Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2814 lines
71 KiB

  1. /*
  2. * @doc INTERNAL
  3. *
  4. * @module - RENDER.CPP |
  5. * CRenderer class
  6. *
  7. * Authors:
  8. * RichEdit 1.0 code: David R. Fulmer
  9. * Christian Fortini (initial conversion to C++)
  10. * Murray Sargent
  11. * Keith Curtis (simplified, cleaned up, added support
  12. * for non-western textflows.)
  13. *
  14. * Copyright (c) 1995-2000 Microsoft Corporation. All rights reserved.
  15. */
  16. #include "_common.h"
  17. #include "_render.h"
  18. #include "_font.h"
  19. #include "_disp.h"
  20. #include "_edit.h"
  21. #include "_select.h"
  22. #include "_objmgr.h"
  23. #include "_coleobj.h"
  24. #include "_layout.h"
  25. // Default colors for background and text on window's host printer
  26. const COLORREF RGB_WHITE = RGB(255, 255, 255);
  27. const COLORREF RGB_BLACK = RGB(0, 0, 0);
  28. const COLORREF RGB_BLUE = RGB(0, 0, 255);
  29. ASSERTDATA
  30. extern const COLORREF g_Colors[];
  31. static HBITMAP g_hbitmapSubtext = 0;
  32. static HBITMAP g_hbitmapExpandedHeading = 0;
  33. static HBITMAP g_hbitmapCollapsedHeading = 0;
  34. static HBITMAP g_hbitmapEmptyHeading = 0;
  35. void ShiftRect(
  36. RECTUV &rc, //@parm rectangle
  37. LONG dup, //@parm shift in u direction
  38. LONG dvp) //@parm shift in v direction
  39. {
  40. rc.left -= dup;
  41. rc.right -= dup;
  42. rc.top -= dvp;
  43. rc.bottom -= dvp;
  44. }
  45. HRESULT InitializeOutlineBitmaps()
  46. {
  47. g_hbitmapSubtext = LoadBitmap(hinstRE, MAKEINTRESOURCE(BITMAP_ID_SUBTEXT));
  48. g_hbitmapExpandedHeading = LoadBitmap(hinstRE, MAKEINTRESOURCE(BITMAP_ID_EXPANDED_HEADING));
  49. g_hbitmapCollapsedHeading = LoadBitmap(hinstRE, MAKEINTRESOURCE(BITMAP_ID_COLLAPSED_HEADING));
  50. g_hbitmapEmptyHeading = LoadBitmap(hinstRE, MAKEINTRESOURCE(BITMAP_ID_EMPTY_HEADING));
  51. if (!g_hbitmapSubtext ||
  52. !g_hbitmapExpandedHeading ||
  53. !g_hbitmapCollapsedHeading ||
  54. !g_hbitmapEmptyHeading)
  55. {
  56. return E_OUTOFMEMORY;
  57. }
  58. return NOERROR;
  59. }
  60. void ReleaseOutlineBitmaps()
  61. {
  62. if (g_hbitmapSubtext)
  63. {
  64. DeleteObject(g_hbitmapSubtext);
  65. DeleteObject(g_hbitmapExpandedHeading);
  66. DeleteObject(g_hbitmapCollapsedHeading);
  67. DeleteObject(g_hbitmapEmptyHeading);
  68. }
  69. }
  70. /*
  71. * CBrush::~CBrush()
  72. */
  73. CBrush::~CBrush()
  74. {
  75. if(_hbrush) // Is NULL if all line borders have 0 width
  76. { // in which case, _hbrushOld is undefined
  77. SelectObject(_pre->GetDC(), _hbrushOld);
  78. DeleteObject(_hbrush);
  79. }
  80. }
  81. /*
  82. * CBrush::Draw(x1, y1, x2, y2, dxpLine, cr, fHideGridLines)
  83. *
  84. * @mfunc
  85. * Draw a line from (x1, y1) to (x2, y2) with the pen width dxpLine
  86. * and color cr.
  87. */
  88. void CBrush::Draw(
  89. LONG u1, //@parm Line starting x coord
  90. LONG v1, //@parm Line starting y coord
  91. LONG u2, //@parm Line ending x coord
  92. LONG v2, //@parm Line ending y coord
  93. LONG dxpLine, //@parm Width of line to draw
  94. COLORREF cr, //@parm Color to use
  95. BOOL fHideGridLines)//@parm If TRUE, hide 0-width gridlines
  96. {
  97. if(!dxpLine)
  98. {
  99. if(fHideGridLines) // Hide 0-width grid lines
  100. return;
  101. cr = RGB(192, 192, 192); // Display 0-width grid lines as 1-pixel
  102. dxpLine = 1; // gray lines as in Word
  103. }
  104. HDC hdc = _pre->GetDC();
  105. if(!_hbrush || _cr != cr)
  106. {
  107. HBRUSH hbrush = CreateSolidBrush(cr);
  108. HBRUSH hbrushOld = (HBRUSH)SelectObject(hdc, hbrush);
  109. if(!_hbrush)
  110. _hbrushOld = hbrushOld; // Save original brush
  111. else
  112. DeleteObject(hbrushOld);
  113. _hbrush = hbrush; // Update CPen state
  114. _cr = cr;
  115. }
  116. RECTUV rcuv; // Convert to rcuv in case of rotation
  117. rcuv.left = u1;
  118. rcuv.top = v1;
  119. if(u1 == u2) // Vertical line
  120. { // (in uv space)
  121. rcuv.right = rcuv.left + dxpLine;
  122. rcuv.bottom = v2;
  123. }
  124. else // Horizontal line
  125. { // (in uv space)
  126. rcuv.right = u2;
  127. rcuv.bottom = rcuv.top + dxpLine;
  128. }
  129. RECT rc; // Convert uv to xy space
  130. _pre->GetPdp()->RectFromRectuv(rc, rcuv);
  131. PatBlt(hdc, rc.left, rc.top, rc.right - rc.left,
  132. rc.bottom - rc.top, PATCOPY);
  133. }
  134. /*
  135. * IsTooSimilar(cr1, cr2)
  136. *
  137. * @mfunc
  138. * Return TRUE if the colors cr1 and cr2 are so similar that they
  139. * are hard to distinguish. Used for deciding to use reverse video
  140. * selection instead of system selection colors.
  141. *
  142. * @rdesc
  143. * TRUE if cr1 is too similar to cr2 to be used for selection
  144. *
  145. * @devnote
  146. * The formula below uses RGB. It might be better to use some other
  147. * color representation such as hue, saturation, and luminosity
  148. */
  149. BOOL IsTooSimilar(
  150. COLORREF cr1, //@parm First color for comparison
  151. COLORREF cr2) //@parm Second color for comparison
  152. {
  153. if((cr1 | cr2) & 0xFF000000) // One color and/or the other
  154. return FALSE; // isn't RGB, so algorithm
  155. // doesn't apply
  156. LONG DeltaR = abs(GetRValue(cr1) - GetRValue(cr2));
  157. LONG DeltaG = abs(GetGValue(cr1) - GetGValue(cr2));
  158. LONG DeltaB = abs(GetBValue(cr1) - GetBValue(cr2));
  159. return DeltaR + DeltaG + DeltaB < 80;
  160. }
  161. /*
  162. * GetShadedColor(crf, crb, iShading)
  163. *
  164. * @mfunc
  165. * Return shaded color given by a mixture of crf and crb as determined
  166. * by iShading. Used for table cell coloration.
  167. *
  168. * @rdesc
  169. * Shaded color
  170. */
  171. COLORREF GetShadedColor(
  172. COLORREF crf,
  173. COLORREF crb,
  174. LONG iShading)
  175. {
  176. if ((crb | crf) & 0xFF000000 || // One or the other isn't an RGB
  177. !iShading) // or no shading:
  178. {
  179. return crb; // just use crb
  180. }
  181. DWORD red = ((300 - iShading)*GetRValue(crb) + iShading*GetRValue(crf))/300;
  182. DWORD green = ((300 - iShading)*GetGValue(crb) + iShading*GetGValue(crf))/300;
  183. DWORD blue = ((300 - iShading)*GetBValue(crb) + iShading*GetBValue(crf))/300;
  184. return RGB(red, green, blue);
  185. }
  186. // CRenderer class
  187. CRenderer::CRenderer (const CDisplay * const pdp) :
  188. CMeasurer (pdp)
  189. {
  190. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CRenderer::CRenderer");
  191. Init();
  192. }
  193. CRenderer::CRenderer (const CDisplay * const pdp, const CRchTxtPtr &rtp) :
  194. CMeasurer (pdp, rtp)
  195. {
  196. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CRenderer::CRenderer");
  197. Init();
  198. }
  199. CRenderer::~CRenderer()
  200. {
  201. if(_hdcBitmap)
  202. {
  203. SelectObject(_hdcBitmap, _hbitmapSave);
  204. DeleteDC(_hdcBitmap);
  205. }
  206. }
  207. /*
  208. * CRenderer::Init()
  209. *
  210. * @mfunc
  211. * Initialize most things to zero
  212. */
  213. void CRenderer::Init()
  214. {
  215. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CRenderer::Init");
  216. _fRenderer = TRUE;
  217. CTxtEdit *ped = GetPed();
  218. _cpAccelerator = ped->GetCpAccelerator();
  219. static const RECTUV zrect = { 0, 0, 0, 0 };
  220. _rcView = zrect;
  221. _rcRender = zrect;
  222. _rc = zrect;
  223. _dupLine = 0;
  224. _dwFlags = 0;
  225. _hdcBitmap = NULL;
  226. _ptCur.u = 0;
  227. _ptCur.v = 0;
  228. _plogpalette = NULL;
  229. CDocInfo *pDocInfo = ped->GetDocInfoNC();
  230. if(pDocInfo)
  231. {
  232. _dxBitmap = _pdp->LXtoDX(pDocInfo->_xExtGoal*pDocInfo->_xScale / 100);
  233. _dyBitmap = _pdp->LYtoDY(pDocInfo->_yExtGoal*pDocInfo->_yScale / 100);
  234. }
  235. _crCurTextColor = CLR_INVALID;
  236. _fRenderSelection = ped->GetSel() && ped->GetSel()->GetShowSelection();
  237. _fErase = !_pdp->IsTransparent();
  238. if(!ped->fInOurHost() || !_pdp->IsPrinter())
  239. {
  240. // If we are displaying to a window, or we are not in the window's
  241. // host, we use the colors specified by the host. For text and
  242. // foreground.
  243. _crBackground = ped->TxGetBackColor();
  244. _crTextColor = ped->TxGetForeColor();
  245. }
  246. else
  247. {
  248. // When the window's host is printing, the default colors are white
  249. // for the background and black for the text.
  250. _crBackground = RGB_WHITE;
  251. _crTextColor = RGB_BLACK;
  252. }
  253. _hdc = _pdp->GetDC();
  254. ::SetBkColor (_hdc, _crBackground);
  255. _crCurBackground = _crBackground;
  256. // For hack around ExtTextOutW OnWin9x EMF problems
  257. _fEnhancedMetafileDC = IsEnhancedMetafileDC(_hdc);
  258. _fDisplayDC = GetDeviceCaps(_hdc, TECHNOLOGY) == DT_RASDISPLAY;
  259. // Set text alignment
  260. // Its much faster to draw using top/left alignment than to draw
  261. // using baseline alignment.
  262. SetTextAlign(_hdc, TA_TOP | TA_LEFT);
  263. SetBkMode(_hdc, TRANSPARENT);
  264. }
  265. /*
  266. * CRenderer::StartRender (&rcView, &rcRender)
  267. *
  268. * @mfunc
  269. * Prepare this renderer for rendering operations
  270. *
  271. * @rdesc
  272. * FALSE if nothing to render, TRUE otherwise
  273. */
  274. BOOL CRenderer::StartRender (
  275. const RECTUV &rcView, //@parm View rectangle
  276. const RECTUV &rcRender) //@parm Rectangle to render
  277. {
  278. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CRenderer::StartRender");
  279. // Set view and rendering rects
  280. _rcView = rcView;
  281. _rcRender = rcRender;
  282. // If this isn't a metafile, we set a flag indicating whether we
  283. // can safely erase the background
  284. if(_pdp->IsMetafile() || !_pdp->IsMain())
  285. {
  286. // Since this isn't the main display or it is a metafile,
  287. // we want to ignore the logic to render selections
  288. _fRenderSelection = FALSE;
  289. if(_fErase) // If control is not transparent,
  290. EraseTextOut(_hdc, &rcRender); // clear display
  291. // This is a metafile or a printer so clear the render rectangle
  292. // and then pretend we are transparent.
  293. _fErase = FALSE;
  294. }
  295. return TRUE;
  296. }
  297. /*
  298. * CRenderer::EraseLine()
  299. *
  300. * @mfunc
  301. * Erase the line
  302. */
  303. void CRenderer::EraseLine()
  304. {
  305. Assert(_fEraseOnFirstDraw);
  306. COLORREF crOld = SetBkColor(_hdc, _crBackground);
  307. EraseTextOut(_hdc, &_rcErase);
  308. SetBkColor(_hdc, crOld);
  309. _fEraseOnFirstDraw = FALSE;
  310. }
  311. /*
  312. * CRenderer::EraseRect(prc, crBack)
  313. *
  314. * @mfunc
  315. * Erase a specific rectangle for special table cell background color
  316. *
  317. * @rdesc
  318. * Old value of _fErase
  319. */
  320. BOOL CRenderer::EraseRect(
  321. const RECTUV *prc, //@parm RECT to erase
  322. COLORREF crBack) //@parm Background color to use
  323. {
  324. SetDefaultBackColor(crBack);
  325. EraseTextOut(_hdc, prc, TRUE);
  326. BOOL fErase = _fErase;
  327. _fErase = FALSE;
  328. return fErase;
  329. }
  330. /*
  331. * CRenderer::IsSimpleBackground()
  332. *
  333. * @mfunc
  334. * Return TRUE if the background is opaque
  335. */
  336. BOOL CRenderer::IsSimpleBackground() const
  337. {
  338. CDocInfo *pDocInfo = GetPed()->GetDocInfoNC();
  339. if (!pDocInfo || pDocInfo->_nFillType != 7 && !IN_RANGE(1, pDocInfo->_nFillType, 3))
  340. return TRUE;
  341. return FALSE;
  342. }
  343. /*
  344. * CRenderer::EraseTextOut(hdc, prc, fSimple)
  345. *
  346. * @mfunc
  347. * Erase a specific area
  348. */
  349. void CRenderer::EraseTextOut(
  350. HDC hdc,
  351. const RECTUV *prc,
  352. BOOL fSimple)
  353. {
  354. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CRenderer::EraseTextOut");
  355. CDocInfo *pDocInfo = GetPed()->GetDocInfoNC();
  356. RECT rc;
  357. _pdp->RectFromRectuv(rc, *prc);
  358. if (fSimple || IsSimpleBackground()) // No special background
  359. {
  360. W32->EraseTextOut(hdc, &rc);
  361. return;
  362. }
  363. // To do background gradients and bitmap fills with rotated coords, need
  364. // to use rc as above and translate calls to _pdp->GetUpScroll() and
  365. // _pdp->GetVpScroll(). For directions other than tflowES get rid of
  366. // screen width and height offsets used in PointFromPointuv(), but keep
  367. // the minus signs.
  368. LONG uScroll = _pdp->GetUpScroll();
  369. LONG vScroll = _pdp->GetVpScroll();
  370. POINT ptScroll = {uScroll, vScroll}; // Default unrotated
  371. TFLOW tflow = _pdp->GetTflow();
  372. switch(tflow)
  373. {
  374. case tflowSW: // Vertical
  375. ptScroll.x = -vScroll;
  376. ptScroll.y = uScroll;
  377. break;
  378. case tflowWN:
  379. ptScroll.x = -uScroll;
  380. ptScroll.y = -vScroll;
  381. break;
  382. case tflowNE:
  383. ptScroll.x = vScroll;
  384. ptScroll.y = -uScroll;
  385. break;
  386. }
  387. if(IN_RANGE(1, pDocInfo->_nFillType, 3))
  388. {
  389. if(!pDocInfo->_hBitmapBack)
  390. return;
  391. if(!_hdcBitmap)
  392. {
  393. // Setup compatible DC to use for background BitBlts for
  394. // the lifetime of this renderer
  395. _hdcBitmap = CreateCompatibleDC(hdc);
  396. if(!_hdcBitmap)
  397. return; // Out of memory
  398. _hbitmapSave = (HBITMAP)SelectObject(_hdcBitmap, pDocInfo->_hBitmapBack);
  399. }
  400. LONG wBitmap = _dxBitmap;
  401. LONG hBitmap = _dyBitmap;
  402. LONG yb = (ptScroll.y + rc.top) % hBitmap;
  403. if(yb < 0)
  404. yb += hBitmap;
  405. LONG h = hBitmap - yb;
  406. LONG y = rc.top;
  407. while(y < rc.bottom)
  408. {
  409. if(y + h > rc.bottom) // Don't overshoot bottom
  410. h = rc.bottom - y;
  411. LONG xb = (ptScroll.x + rc.left) % wBitmap;
  412. if(xb < 0) // xb can be < 0 if ptScroll.x < 0
  413. xb += wBitmap;
  414. LONG w = wBitmap - xb;
  415. LONG x = rc.left;
  416. while(x < rc.right)
  417. {
  418. if(x + w > rc.right) // Don't overshoot right
  419. w = rc.right - x;
  420. BitBlt(hdc, x, y, w, h, _hdcBitmap, xb, yb, SRCCOPY);
  421. x += w;
  422. w = wBitmap;
  423. xb = 0;
  424. }
  425. y += h;
  426. h = hBitmap;
  427. yb = 0;
  428. }
  429. return;
  430. }
  431. // Gradient fill backgrounds
  432. LONG Angle = pDocInfo->_sFillAngle;
  433. COLORREF crb = pDocInfo->_crColor;
  434. COLORREF crf = pDocInfo->_crBackColor;
  435. LONG di = ptScroll.x; // Default vertical values
  436. LONG h = 0;
  437. HPEN hpen = NULL;
  438. HPEN hpenEntry = NULL;
  439. LONG iFirst = rc.left;
  440. LONG iLim = rc.right;
  441. LONG iShading;
  442. switch(Angle)
  443. {
  444. case -45: // Diagonal down
  445. case -135: // Diagonal up
  446. h = rc.bottom - rc.top;
  447. if(Angle == -45)
  448. {
  449. di -= ptScroll.y + rc.top;
  450. iFirst -= h;
  451. h = -h;
  452. }
  453. else
  454. {
  455. di += ptScroll.y + rc.top;
  456. iLim += h;
  457. }
  458. break;
  459. case 0: // Horizontal
  460. iFirst = rc.top;
  461. iLim = rc.bottom;
  462. di = ptScroll.y;
  463. break;
  464. }
  465. if(!crf) // Moderate black a bit (needs work)
  466. crf = RGB(100, 100, 100);
  467. for(LONG i = iFirst; i < iLim; i++)
  468. {
  469. iShading = (di + i) % 600;
  470. if(iShading < 0) // Pattern moves up screen
  471. iShading += 600;
  472. if(iShading > 300)
  473. iShading = 600 - iShading;
  474. iShading = max(iShading, 30);
  475. iShading = min(iShading, 270);
  476. if(hpen)
  477. DeleteObject(hpen);
  478. hpen = CreatePen(PS_SOLID, 0, GetShadedColor(crf, crb, iShading));
  479. if(!hpenEntry)
  480. hpenEntry = (HPEN)SelectObject(hdc, hpen);
  481. else
  482. SelectObject(hdc, hpen);
  483. POINT rgpt[2];
  484. if(Angle) // -90 (vertical) or
  485. { // -135 (diagonal)
  486. if(i > rc.right) // Don't let diagonal overshoot
  487. {
  488. rgpt[0].x = rc.right;
  489. rgpt[0].y = rc.top + (i - rc.right);
  490. }
  491. else
  492. {
  493. rgpt[0].x = i;
  494. rgpt[0].y = rc.top;
  495. }
  496. if(i - h < iFirst) // Don't let diagonal undershoot
  497. {
  498. rgpt[1].x = iFirst - 1;
  499. rgpt[1].y = rc.bottom - (iFirst - 1 - (i - h));
  500. }
  501. else
  502. {
  503. rgpt[1].x = i - h;
  504. rgpt[1].y = rc.bottom;
  505. }
  506. }
  507. else // Horizontal (0 degrees)
  508. {
  509. rgpt[0].x = rc.left;
  510. rgpt[0].y = i;
  511. rgpt[1].x = rc.right;
  512. rgpt[1].y = i;
  513. }
  514. Polyline(hdc, rgpt, 2); // Use Polyline() so as not to
  515. } // break WinCE
  516. if(hpen)
  517. {
  518. DeleteObject(hpen);
  519. SelectObject(hdc, hpenEntry);
  520. }
  521. }
  522. /*
  523. * CRenderer::DrawWrappedObjects(pliFirst, pliLast, cpFisrt, ptFirst, fLeft)
  524. *
  525. * @mfunc
  526. * Draw all wrapped objects in the range on the left or right side.
  527. *
  528. */
  529. void CRenderer::DrawWrappedObjects(CLine *pliFirst, CLine *pliLast, LONG cpFirst, const POINTUV &ptFirst)
  530. {
  531. for (BOOL fLeft = 0; fLeft != 2; fLeft ++) //For left and right sides...
  532. {
  533. CLine *pli = pliFirst;
  534. LONG cp = cpFirst;
  535. POINTUV pt = ptFirst;
  536. //If the first line is part-way through an object, then back up to the beginning.
  537. if (fLeft && pli->_cObjectWrapLeft || !fLeft && pli->_cObjectWrapRight)
  538. {
  539. while (fLeft ? !pli->_fFirstWrapLeft : !pli->_fFirstWrapRight)
  540. {
  541. pli--;
  542. pt.v -= pli->GetHeight();
  543. cp -= pli->_cch;
  544. }
  545. }
  546. for (;pli <= pliLast; cp += pli->_cch, pt.v += pli->GetHeight(), pli++)
  547. {
  548. //Did we find an object which needs to be drawn?
  549. if (fLeft && pli->_fFirstWrapLeft || !fLeft && pli->_fFirstWrapRight)
  550. {
  551. LONG cpObj = FindCpDraw(cp + 1, fLeft ? pli->_cObjectWrapLeft : pli->_cObjectWrapRight, fLeft);
  552. COleObject *pobj = GetObjectFromCp(cpObj);
  553. if (!pobj)
  554. return;
  555. LONG dvpAscent, dvpDescent, dup;
  556. pobj->MeasureObj(_dvpInch, _dupInch, dup, dvpAscent, dvpDescent, 0, GetTflow());
  557. POINTUV ptDraw = pt;
  558. if (!fLeft) //Right align images
  559. ptDraw.u += _pdp->GetDupView() - dup;
  560. RECTUV rc = {_rcRender.left, _rcView.top, _rcRender.right, _rcView.bottom};
  561. pobj->DrawObj(_pdp, _dvpInch, _dupInch, _hdc, &rc, _pdp->IsMetafile(),
  562. &ptDraw, dvpAscent + dvpDescent, 0, GetTflow());
  563. }
  564. }
  565. }
  566. }
  567. /*
  568. * CRenderer::EndRender(pliFirst, pliLast, cpFirst, &ptFirst)
  569. *
  570. * @mfunc
  571. * Any final operations which are to happen after we've drawn
  572. * all of the lines.
  573. */
  574. void CRenderer::EndRender(
  575. CLine * pliFirst,
  576. CLine * pliLast,
  577. LONG cpFirst,
  578. const POINTUV &ptFirst)
  579. {
  580. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CRenderer::EndRender");
  581. AssertSz(_hdc, "CRenderer::EndRender() - No rendering DC");
  582. if(_fErase && _ptCur.v < _rcRender.bottom)
  583. {
  584. RECTUV rc = _rcRender;
  585. rc.top = _ptCur.v;
  586. EraseTextOut(_hdc, &rc);
  587. }
  588. DrawWrappedObjects(pliFirst, pliLast, cpFirst, ptFirst);
  589. }
  590. /*
  591. * CRenderer::NewLine (&li)
  592. *
  593. * @mfunc
  594. * Init this CRenderer for rendering the specified line
  595. */
  596. void CRenderer::NewLine (
  597. const CLine &li)
  598. {
  599. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CRenderer::NewLine");
  600. _li = li;
  601. Assert(GetCp() + _li._cch <= GetTextLength());
  602. _cchLine = li._cch;
  603. _dupLine = _li._dup;
  604. _li._dup = 0;
  605. _ptCur.u = _rcView.left;
  606. if(!_pPF->InTable())
  607. _ptCur.u -= _pdp->GetUpScroll();
  608. _fSelected = _fSelectedPrev = FALSE;
  609. }
  610. /*
  611. * CRenderer::SetupOffscreenDC(dup, dvp)
  612. *
  613. * @mfunc
  614. * Setup renderer for using an offscreen DC
  615. *
  616. * @rdesc
  617. * NULL - an error occurred<nl>
  618. * ~NULL - DC to save
  619. */
  620. HDC CRenderer::SetupOffscreenDC(
  621. LONG& dup, //@parm Offset to u
  622. LONG& dvp, //@parm Offset to v
  623. BOOL fLastLine)
  624. {
  625. // Save render DC
  626. CTxtEdit *ped = GetPed();
  627. BOOL fInOurHost = ped->fInOurHost();
  628. HDC hdcSave = _hdc;
  629. //If we've already erased (can't prevent flicker now!)
  630. //or this is some weird textflow, then don't do offscreens.
  631. if (!_fErase || GetTflow() != tflowES || ped->GetBackgroundType() != -1)
  632. return NULL;
  633. RECTUV rc;
  634. RECT rcBitmap;
  635. rc.left = _rcRender.left;
  636. rc.right = _rcRender.right;
  637. rc.top = _rc.top;
  638. rc.bottom = _rc.bottom;
  639. _pdp->RectFromRectuv(rcBitmap, rc);
  640. if (_osdc.GetDC() == NULL)
  641. {
  642. if (!_osdc.Init(_hdc, rcBitmap.right - rcBitmap.left, rcBitmap.bottom - rcBitmap.top, _crBackground))
  643. return NULL;
  644. HPALETTE hpal = fInOurHost ? ped->TxGetPalette() : (HPALETTE) GetCurrentObject(_hdc, OBJ_PAL);
  645. _osdc.SelectPalette(hpal);
  646. }
  647. else
  648. {
  649. LONG dx, dy;
  650. _osdc.GetDimensions(&dx, &dy);
  651. //REVIEW (keithcu) Simplify?
  652. if (IsUVerticalTflow(GetTflow()))
  653. {
  654. if (dx < rcBitmap.bottom - rcBitmap.top)
  655. {
  656. if (_osdc.Realloc(_rc.bottom - _rc.top + dy / 16, dy)) //Resize the bitmap, plus a little room
  657. return NULL;
  658. }
  659. }
  660. else if (dy < rcBitmap.bottom - rcBitmap.top)
  661. {
  662. if (_osdc.Realloc(dx, _rc.bottom - _rc.top + dy / 16)) //Resize the bitmap, plus a little room
  663. return NULL;
  664. }
  665. }
  666. _hdc = _osdc.GetDC();
  667. _crCurTextColor = CLR_INVALID;
  668. if(_pccs)
  669. {
  670. // There is current a character format for the run so we need to
  671. // get in sync with that since the offscreen DC isn't necessarily
  672. // set to that font.
  673. // Get the character format and set up the font
  674. SetFontAndColor(GetCF());
  675. }
  676. // We are rendering to a transparent background
  677. _fErase = FALSE;
  678. // Clear bitmap
  679. ::SetBkColor(_hdc, _crBackground);
  680. _osdc.FillBitmap(rcBitmap.right - rcBitmap.left, rcBitmap.bottom - rcBitmap.top);
  681. //If the first line, erase to edge of rcRender
  682. if (_rc.top <= _rcView.top)
  683. {
  684. //Clear top of rcRender if necessary
  685. RECTUV rcErase = _rcRender;
  686. rcErase.top = min(_rcView.top, _rcRender.top);
  687. rcErase.bottom = _rc.top;
  688. if (rcErase.bottom > rcErase.top)
  689. EraseTextOut(hdcSave, &rcErase);
  690. }
  691. // Restore background color if necessary
  692. if(_crBackground != _crCurBackground)
  693. ::SetBkColor(_hdc, _crCurBackground);
  694. SetBkMode(_hdc, TRANSPARENT);
  695. // Store v adjustment to use in rendering off-screen bitmap
  696. dvp = _rc.top;
  697. // Store u adjustment to use in rendering off-screen bitmap
  698. dup = _rcRender.left;
  699. // Normalize _rc, _rcView, & _rcRender
  700. ShiftRect( _rc, dup, dvp);
  701. ShiftRect( _rcView, dup, dvp);
  702. ShiftRect(_rcRender, dup, dvp);
  703. // Normalize _ptCur for rendering to off-screen bitmap
  704. _ptCur.u -= dup;
  705. _ptCur.v -= dvp;
  706. return hdcSave;
  707. }
  708. /*
  709. * CRenderer::RenderOffscreenBitmap(hdc, dup, yAdj)
  710. *
  711. * @mfunc
  712. * Render off screen bitmap and restore the state of the render.
  713. */
  714. void CRenderer::RenderOffscreenBitmap(
  715. HDC hdc, //@parm DC to render to
  716. LONG dup, //@parm offset to real u base
  717. LONG dvp) //@parm offset to real v base
  718. {
  719. // Palettes for rendering bitmap
  720. HPALETTE hpalOld = NULL;
  721. HPALETTE hpalNew = NULL;
  722. // Restore pt
  723. _ptCur.u += dup;
  724. _ptCur.v += dvp;
  725. // Restore rect
  726. LONG dupTemp = -dup;
  727. LONG dvpTemp = -dvp;
  728. ShiftRect( _rc, dupTemp, dvpTemp);
  729. ShiftRect( _rcView, dupTemp, dvpTemp);
  730. ShiftRect(_rcRender, dupTemp, dvpTemp);
  731. // Create a palette if one is needed
  732. if(_plogpalette)
  733. W32->ManagePalette(hdc, _plogpalette, hpalOld, hpalNew);
  734. RECTUV rcuv = {dup, dvp, dup + _rcRender.right - _rcRender.left, dvp + _rc.bottom - _rc.top};
  735. RECT rc;
  736. _pdp->RectFromRectuv(rc, rcuv);
  737. // Render bitmap to real DC and restore _ptCur & _rc
  738. _osdc.RenderBitMap(hdc, rc.left, rc.top, _rcRender.right - _rcRender.left, _rc.bottom - _rc.top);
  739. // Restore palette after render if necessary
  740. if(_plogpalette)
  741. {
  742. W32->ManagePalette(hdc, _plogpalette, hpalOld, hpalNew);
  743. CoTaskMemFree(_plogpalette);
  744. _plogpalette = NULL;
  745. }
  746. // Restore HDC to actual render DC
  747. _hdc = hdc;
  748. // Set this flag to what it should be for restored DC
  749. _fErase = TRUE;
  750. _crCurTextColor = CLR_INVALID;
  751. // Reset screen DC font
  752. // Set up font on non-screen DC
  753. // Force color resynch
  754. if(!FormatIsChanged()) // Not on a new block,
  755. SetFontAndColor(GetCF()); // so just set font and color
  756. else
  757. { // On new block,
  758. ResetCachediFormat(); // so reset everything
  759. SetNewFont();
  760. }
  761. }
  762. /*
  763. * CRenderer::RenderLine (&li, fLastLine)
  764. *
  765. * @mfunc
  766. * Render visible part of current line
  767. *
  768. * @rdesc
  769. * TRUE if success, FALSE if failed
  770. *
  771. * @devnote
  772. * Only call this from CLine::RenderLine()
  773. */
  774. BOOL CRenderer::RenderLine (
  775. CLine & li, //@parm Line to render
  776. BOOL fLastLine) //@parm True if last line in layout
  777. {
  778. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CRenderer::RenderLine");
  779. BYTE bUnderlineSave = 0;
  780. LONG cch;
  781. LONG cchChunk;
  782. LONG cchInTextRun;
  783. BOOL fAccelerator = FALSE;
  784. const WCHAR * pstrToRender;
  785. CTempWcharBuf twcb;
  786. WCHAR chPassword = GetPasswordChar();
  787. UpdatePF();
  788. // This is used as a temporary buffer so that we can guarantee that we will
  789. // display an entire format run in one ExtTextOut.
  790. WCHAR * pszTempBuffer = NULL;
  791. NewLine(li); // Init render at start of line
  792. _fLastChunk = FALSE;
  793. _ptCur.u += _li._upStart; // Add in line left indent
  794. // Allow for special rendering at start of line
  795. LONG cpSelMin, cpSelMost;
  796. LONG dup, dvp;
  797. HDC hdcSave = StartLine(li, fLastLine, cpSelMin, cpSelMost, dup, dvp);
  798. cch = _li._cch;
  799. if(chPassword && IsRich())
  800. {
  801. // It is kind of stupid to allow rich text password edit controls.
  802. // However, it does make it that much easier to create a password
  803. // edit control since you don't have to know to change the box to
  804. // plain. Anyway, if there is such a thing, we don't want to put
  805. // out password characters for EOPs in general and the final EOP
  806. // specifically. Therefore, the following ...
  807. if(_pdp->IsMultiLine())
  808. cch -= _li._cchEOP;
  809. else
  810. cch = GetPed()->GetAdjustedTextLength();
  811. }
  812. for(; cch > 0; cch -= cchChunk)
  813. {
  814. // Initial chunk (number of characters to render in a single TextOut)
  815. // is min between CHARFORMAT run length and line length. Start with
  816. // count of characters left in current format run
  817. cchChunk = GetCchLeftRunCF();
  818. AssertSz(cchChunk != 0, "empty CHARFORMAT run");
  819. DWORD dwEffects = GetCF()->_dwEffects;
  820. if(dwEffects & CFE_HIDDEN) // Don't display hidden text
  821. {
  822. Move(cchChunk);
  823. continue;
  824. }
  825. if(GetChar() == NOTACHAR) // Ignore NOTACHAR code
  826. {
  827. Move(1);
  828. continue;
  829. }
  830. // Limit chunk to count of characters we want to display.
  831. cchChunk = min(cch, cchChunk);
  832. // Get count of characters in text run
  833. pstrToRender = _rpTX.GetPch(cchInTextRun);
  834. AssertSz(cchInTextRun > 0, "empty text run");
  835. if (cchInTextRun < cchChunk || chPassword || dwEffects & CFE_ALLCAPS)
  836. {
  837. // The count of contiguous chars in the backing store run is
  838. // less than the count of characters we wish to display or this
  839. // is a password control or we want all caps. We copy the data
  840. // out of the backing store.
  841. if(!pszTempBuffer)
  842. {
  843. // Allocate buffer big enough to handle all future
  844. // requests in this loop.
  845. pszTempBuffer = twcb.GetBuf(cch);
  846. if (!pszTempBuffer)
  847. {
  848. CCallMgr * pcallmgr = GetPed()->GetCallMgr();
  849. if (pcallmgr)
  850. pcallmgr->SetOutOfMemory();
  851. return FALSE; // Fail to allocate memory
  852. }
  853. }
  854. _rpTX.GetText(cchChunk, pszTempBuffer);
  855. pstrToRender = pszTempBuffer; // Point at buffer
  856. if(chPassword)
  857. {
  858. // Fill buffer with password characters
  859. for (int i = 0, j = 0; i < cchChunk; i++)
  860. {
  861. if(!IN_RANGE(0xDC00, pszTempBuffer[i], 0xDFFF))
  862. pszTempBuffer[j++] = chPassword;
  863. }
  864. cch -= cchChunk - j;
  865. Move(cchChunk - j);
  866. cchChunk = j;
  867. }
  868. else if(dwEffects & CFE_ALLCAPS)
  869. CharUpperBuff(pszTempBuffer, cchChunk);
  870. }
  871. if(_cpAccelerator != -1)
  872. {
  873. LONG cpCur = GetCp(); // Get current cp
  874. // Does accelerator character fall in this chunk?
  875. if (cpCur < _cpAccelerator &&
  876. cpCur + cchChunk > _cpAccelerator)
  877. {
  878. // Yes. Reduce chunk to char just before accelerator
  879. cchChunk = _cpAccelerator - cpCur;
  880. }
  881. // Is this character the accelerator?
  882. else if(cpCur == _cpAccelerator)
  883. { // Set chunk size to 1 since only
  884. cchChunk = 1; // want to output underlined char
  885. fAccelerator = TRUE; // Tell downstream routines that
  886. // we're handling accelerator
  887. _cpAccelerator = -1; // Only 1 accelerator per line
  888. }
  889. }
  890. // Reduce chunk to account for selection if we are rendering for a
  891. // display that cares about selections.
  892. if(_fRenderSelection && cpSelMin != cpSelMost)
  893. {
  894. LONG cchSel = cpSelMin - GetCp();
  895. if(cchSel > 0)
  896. cchChunk = min(cchChunk, cchSel);
  897. else if(GetCp() < cpSelMost)
  898. {
  899. cchSel = cpSelMost - GetCp();
  900. if(cchSel >= cch)
  901. _fSelectToEOL = TRUE;
  902. else
  903. cchChunk = min(cchChunk, cchSel);
  904. _fSelected = TRUE; // cpSelMin <= GetCp() < cpSelMost
  905. } // so current run is selected
  906. }
  907. // If start of CCharFormat run, select font and color
  908. if(FormatIsChanged() || _fSelected != _fSelectedPrev)
  909. {
  910. ResetCachediFormat();
  911. _fSelectedPrev = _fSelected;
  912. if(!SetNewFont())
  913. return FALSE; // Failed
  914. }
  915. if(fAccelerator)
  916. {
  917. bUnderlineSave = _bUnderlineType;
  918. SetupUnderline(CFU_UNDERLINE, 0);
  919. }
  920. // Allow for further reduction of the chunk and rendering of
  921. // interleaved rich text elements
  922. if(_li._fHasSpecialChars && RenderChunk(cchChunk, pstrToRender, cch))
  923. {
  924. AssertSz(cchChunk > 0, "CRenderer::RenderLine(): cchChunk == 0");
  925. _fSelected = FALSE;
  926. continue;
  927. }
  928. AssertSz(cchChunk > 0,"CRenderer::RenderLine() - cchChunk == 0");
  929. _fLastChunk = (cchChunk == cch);
  930. RenderText(pstrToRender, cchChunk); // Render the text
  931. if(fAccelerator)
  932. {
  933. _bUnderlineType = bUnderlineSave;
  934. fAccelerator = FALSE; // Turn off special accelerator
  935. } // processing
  936. Move(cchChunk);
  937. // Break if we went past right of render rect.
  938. if(_ptCur.u >= _rcRender.right)
  939. {
  940. cch -= cchChunk;
  941. break;
  942. }
  943. }
  944. EndLine(hdcSave, dup, dvp);
  945. Move(cch);
  946. return TRUE; // Success
  947. }
  948. /*
  949. * CRenderer::EndLine (hdcSave, dup, dvp)
  950. *
  951. * @mfunc
  952. * Finish up rendering of line, drawing table borders, rendering
  953. * offscreen DC, and erasing to right of render rect if necessary.
  954. */
  955. void CRenderer::EndLine(
  956. HDC hdcSave,
  957. LONG dup,
  958. LONG dvp)
  959. {
  960. if(hdcSave)
  961. RenderOffscreenBitmap(hdcSave, dup, dvp);
  962. // Handle setting background color. We need to do this for each line
  963. // because we return the background color to the default after each
  964. // line so that opaquing will work correctly.
  965. if(_crBackground != _crCurBackground)
  966. {
  967. ::SetBkColor(_hdc, _crBackground); // Tell window background color
  968. _crCurBackground = _crBackground;
  969. }
  970. }
  971. /*
  972. * CRenderer::GetColorFromIndex (icr, fForeColor, pPF)
  973. *
  974. * @mfunc
  975. * Returns COLORREF corresponding to color index icr
  976. *
  977. * @rdesc
  978. * Get COLORREF corresponding to color index icr as follows:
  979. * icr = 1 to 16 is g_Colors[icr-1]
  980. * icr = 17 is pCF->_crTextColor
  981. * icr = 18 is pCF->_crBackColor
  982. * else CRenderer autocolor corresponding to fForeColor
  983. */
  984. COLORREF CRenderer::GetColorFromIndex(
  985. LONG icr, //@parm Color index
  986. BOOL fForeColor, //@parm TRUE if foreground color (for autocolor)
  987. const CParaFormat *pPF) const //@parm PF for two custom colors
  988. {
  989. icr &= 0x1F; // Mask off other indices
  990. if(!IN_RANGE(1, icr, 18))
  991. return fForeColor ? _crTextColor : _crBackground; // autocolor
  992. if(IN_RANGE(1, icr, 16)) // One of standard 16 colors
  993. return g_Colors[icr - 1];
  994. // Two custom colors
  995. return (icr == 17) ? pPF->_crCustom1 : pPF->_crCustom2;
  996. }
  997. /*
  998. * CRenderer::GetShadedColorFromIndices (icrf, icrb, iShading, pPF)
  999. *
  1000. * @mfunc
  1001. * Returns COLORREF corresponding to color index icr
  1002. *
  1003. * @rdesc
  1004. * Get COLORREF corresponding to foreground/background indices
  1005. * icrf and icrb according to shading iShading
  1006. */
  1007. COLORREF CRenderer::GetShadedColorFromIndices(
  1008. LONG icrf, //@parm Foreground color index
  1009. LONG icrb, //@parm Background color index
  1010. LONG iShading, //@parm Shading in .01 percent
  1011. const CParaFormat *pPF) const //@parm PF for two custom colors
  1012. {
  1013. Assert(iShading <= 200);
  1014. COLORREF crb = GetColorFromIndex (icrb, FALSE, pPF);
  1015. COLORREF crf = GetColorFromIndex (icrf, TRUE, pPF);
  1016. return GetShadedColor(crf, crb, (iShading*3)/2);
  1017. }
  1018. /*
  1019. * CRenderer::DrawTableBorders (pPF, u, vHeightRow, iDrawBottomLine, dulRow, pPFAbove)
  1020. *
  1021. * @mfunc
  1022. * Draws table borders. If iDrawBottomLine is nonzero, draw bottom line
  1023. * as well as others. If iDrawBottomLine & 1, width of bottom line is
  1024. * included in vHeightRow; else if iDrawBottomLine is nonzero, draw bottom
  1025. * line immediately below the row and return the extra height.
  1026. *
  1027. * @rdesc
  1028. * Extra dvp if extra bottom line is drawn
  1029. */
  1030. LONG CRenderer::DrawTableBorders(
  1031. const CParaFormat *pPF, //@parm PF with cell data
  1032. LONG u, //@parm u position to start table row borders
  1033. LONG vHeightRow, //@parm Height of row
  1034. LONG iDrawBottomLine, //@parm Flags on drawing bottom line
  1035. LONG dulRow, //@parm Length of row
  1036. const CParaFormat *pPFAbove)//@parm PF for row above
  1037. {
  1038. CBrush brush(this);
  1039. LONG cCell = pPF->_bTabCount;
  1040. LONG cCellAbove = 0;
  1041. COLORREF cr;
  1042. LONG dupRow = LUtoDU(dulRow);
  1043. LONG dvp = 0;
  1044. LONG dxlLine;
  1045. LONG dxlLinePrevRight = 0;
  1046. LONG dxpLine;
  1047. BOOL fHideGridlines = GetPed()->fHideGridlines() || !fDisplayDC();
  1048. BOOL fRTLRow = pPF->IsRtl();
  1049. LONG iCell;
  1050. LONG icr;
  1051. const CELLPARMS *prgCellParms = pPF->GetCellParms();
  1052. const CELLPARMS *prgCellParmsAbove = NULL;
  1053. LONG vTop = _ptCur.v;
  1054. LONG vBot = vTop + vHeightRow;
  1055. LONG v = vBot;
  1056. if(pPFAbove)
  1057. {
  1058. prgCellParmsAbove = pPFAbove->GetCellParms();
  1059. cCellAbove = pPFAbove->_bTabCount;
  1060. }
  1061. if(_fErase)
  1062. {
  1063. //Erase left and right edges of table
  1064. LONG cpSelMin, cpSelMost;
  1065. RECTUV rc = {_rcRender.left, vTop, u, vBot};
  1066. EraseTextOut(_hdc, &rc);
  1067. rc.left = u + dupRow;
  1068. rc.right = _rcRender.right;
  1069. EraseTextOut(_hdc, &rc);
  1070. //If first line, erase to edge of rcRender
  1071. if (rc.top <= _rcView.top)
  1072. rc.top = _rcRender.top;
  1073. rc.left = 0;
  1074. rc.bottom = vTop;
  1075. EraseTextOut(_hdc, &rc);
  1076. // Display row selection mark if row is selected
  1077. GetPed()->GetSelRangeForRender(&cpSelMin, &cpSelMost);
  1078. Assert(_rpTX.IsAfterTRD(ENDFIELD));
  1079. if(GetCp() <= cpSelMost && GetCp() > cpSelMin)
  1080. { // Row is selected
  1081. COLORREF crSave = _crBackground;
  1082. LONG dup;
  1083. if(!_pccs)
  1084. _pccs = GetCcs(GetCF());
  1085. if(_pccs && _pccs->Include(' ', dup))
  1086. {
  1087. rc.left = u + dupRow +
  1088. GetPBorderWidth(prgCellParms[cCell-1].GetBrdrWidthRight()/2);
  1089. rc.right = rc.left + dup;
  1090. rc.top = vTop + GetPBorderWidth(prgCellParms->GetBrdrWidthTop());
  1091. rc.top++;
  1092. rc.bottom= vBot;
  1093. if(iDrawBottomLine & 1)
  1094. rc.bottom = vBot - GetPBorderWidth(prgCellParms->GetBrdrWidthBottom());
  1095. SetBkColor(_hdc, GetPed()->TxGetSysColor(COLOR_HIGHLIGHT));
  1096. EraseTextOut(_hdc, &rc, TRUE);
  1097. SetBkColor(_hdc, crSave);
  1098. }
  1099. }
  1100. }
  1101. if(iDrawBottomLine) // Row bottom border
  1102. {
  1103. LONG dxp = GetPBorderWidth(prgCellParms->GetBrdrWidthLeft())/2;
  1104. LONG u1 = u - dxp;
  1105. LONG u2 = u + dupRow;
  1106. dxpLine = GetPBorderWidth(prgCellParms->GetBrdrWidthBottom());
  1107. cr = GetColorFromIndex(prgCellParms->GetColorIndexBottom(), TRUE, pPF);
  1108. if(iDrawBottomLine & 1) // Line width incl in cell height
  1109. { // Don't draw left vertical lines
  1110. v -= dxpLine; // over bottom line
  1111. if(!dxpLine && !fHideGridlines)
  1112. v--; // Overlay cell bottom with gray
  1113. } // gridline
  1114. else // Line width not incl in cell height
  1115. {
  1116. dvp = dxpLine; // Return extra width due to bottom line
  1117. if(!dxpLine && !fHideGridlines)
  1118. dvp = 1;
  1119. vBot += dvp; // Set up outside vertical lines
  1120. }
  1121. brush.Draw(u1, v, u2, v, dxpLine, cr, fHideGridlines);
  1122. }
  1123. LONG uPrev, uCur = u;
  1124. LONG dul = 0;
  1125. LONG dup;
  1126. if(fRTLRow)
  1127. uCur = u + dupRow;
  1128. for(LONG i = cCell; i >= 0; i--)
  1129. {
  1130. // Draw cell side border
  1131. if(i) // Left border
  1132. {
  1133. icr = prgCellParms->GetColorIndexLeft();
  1134. dxlLine = prgCellParms->GetBrdrWidthLeft();
  1135. dxlLine = max(dxlLine, dxlLinePrevRight);
  1136. dxlLinePrevRight = prgCellParms->GetBrdrWidthRight();
  1137. }
  1138. else // Right border
  1139. {
  1140. prgCellParms--;
  1141. icr = prgCellParms->GetColorIndexRight();
  1142. dxlLine = dxlLinePrevRight;
  1143. v = vBot; // Be sure bottom right corner is square
  1144. }
  1145. cr = GetColorFromIndex(icr, TRUE, pPF);
  1146. dxpLine = GetPBorderWidth(dxlLine);
  1147. brush.Draw(uCur - dxpLine/2, vTop, uCur - dxpLine/2, v, dxpLine, cr, fHideGridlines);
  1148. if(i)
  1149. {
  1150. dul += GetCellWidth(prgCellParms->uCell); // Stay logical to
  1151. dup = LUtoDU(dul); // avoid roundoff
  1152. uPrev = uCur;
  1153. uCur = u + dup;
  1154. if(fRTLRow)
  1155. uCur = u + dupRow - dup;
  1156. if(!IsLowCell(prgCellParms->uCell))
  1157. { // Cell top border
  1158. dxlLine = prgCellParms->GetBrdrWidthTop();
  1159. if(prgCellParmsAbove) // Choose thicker of this row's top
  1160. { // & above row's bottom borders
  1161. iCell = prgCellParmsAbove->ICellFromUCell(dul, cCellAbove);
  1162. if(iCell >= 0)
  1163. {
  1164. LONG dxlAbove = prgCellParmsAbove[iCell].GetBrdrWidthBottom();
  1165. dxlLine = max(dxlLine, dxlAbove);
  1166. }
  1167. }
  1168. dxpLine = GetPBorderWidth(dxlLine);
  1169. cr = GetColorFromIndex(prgCellParms->GetColorIndexTop(), TRUE, pPF);
  1170. brush.Draw(uPrev, vTop, uCur, vTop, dxpLine, cr, fHideGridlines);
  1171. }
  1172. prgCellParms++;
  1173. }
  1174. }
  1175. if(prgCellParmsAbove && !pPFAbove->IsRtl())
  1176. { // Draw more top borders if row
  1177. LONG dulAbove = 0; // above extends beyond current
  1178. for(i = cCellAbove; i > 0; i--) // row (LTR rows only for now)
  1179. {
  1180. dulAbove += GetCellWidth(prgCellParmsAbove->uCell);
  1181. if(dulAbove > dul)
  1182. {
  1183. dup = LUtoDU(dulAbove);
  1184. if(i == 1)
  1185. dup += GetPBorderWidth((prgCellParmsAbove->GetBrdrWidthRight()+1)/2);
  1186. uPrev = uCur;
  1187. uCur = u + dup;
  1188. dxpLine = GetPBorderWidth(prgCellParmsAbove->GetBrdrWidthBottom());
  1189. cr = GetColorFromIndex(prgCellParmsAbove->GetColorIndexBottom(), TRUE, pPFAbove);
  1190. brush.Draw(uPrev, vTop, uCur, vTop, dxpLine, cr, fHideGridlines);
  1191. }
  1192. prgCellParmsAbove++;
  1193. }
  1194. }
  1195. return dvp;
  1196. }
  1197. /*
  1198. * CRenderer::UpdatePalette (pobj)
  1199. *
  1200. * @mfunc
  1201. * Stores palette information so that we can render any OLE objects
  1202. * correctly in a bitmap.
  1203. */
  1204. void CRenderer::UpdatePalette(
  1205. COleObject *pobj) //@parm OLE object wrapper.
  1206. {
  1207. #ifndef NOPALETTE
  1208. LOGPALETTE *plogpalette = NULL;
  1209. LOGPALETTE *plogpaletteMerged;
  1210. IViewObject *pviewobj;
  1211. // Get IViewObject interface information so we can build a palette
  1212. // to render the object correctly.
  1213. if (((pobj->GetIUnknown())->QueryInterface(IID_IViewObject,
  1214. (void **) &pviewobj)) != NOERROR)
  1215. {
  1216. // Couldn't get it, so pretend this didn't happen
  1217. return;
  1218. }
  1219. // Get logical palette information from object
  1220. if(pviewobj->GetColorSet(DVASPECT_CONTENT, -1, NULL, NULL,
  1221. NULL, &plogpalette) != NOERROR || !plogpalette)
  1222. {
  1223. // Couldn't get it, so pretend this didn't happen
  1224. goto CleanUp;
  1225. }
  1226. if(!_plogpalette)
  1227. { // No palette entries yet
  1228. _plogpalette = plogpalette; // Just use the one returned
  1229. goto CleanUp;
  1230. }
  1231. // We have had other palette entries. We just reallocate the table
  1232. // and put the newest entry on the end. This is crude, we might
  1233. // sweep the table and actually merge it. However, this code
  1234. // should be executed relatively infrequently and therefore, crude
  1235. // should be good enough.
  1236. // Allocate a new table - Note the " - 1" in the end has to do with
  1237. // the fact that LOGPALETTE is defined to have one entry already.
  1238. AssertSz(_plogpalette->palNumEntries + plogpalette->palNumEntries >= 1,
  1239. "CRenderer::UpdatePalette - invalid palettes to merge");
  1240. plogpaletteMerged = (LOGPALETTE *) CoTaskMemAlloc(sizeof(LOGPALETTE) +
  1241. ((_plogpalette->palNumEntries + plogpalette->palNumEntries - 1) * sizeof(PALETTEENTRY)));
  1242. if(!plogpaletteMerged) // Memory allocation failed
  1243. goto CleanTempPalette; // Just pretend it didn't happen
  1244. // Copy in original table.
  1245. memcpy(&plogpaletteMerged->palPalEntry[0], &_plogpalette->palPalEntry[0],
  1246. _plogpalette->palNumEntries * sizeof(PALETTEENTRY));
  1247. // Put new data at end
  1248. memcpy(&plogpaletteMerged->palPalEntry[_plogpalette->palNumEntries],
  1249. &plogpalette->palPalEntry[0],
  1250. plogpalette->palNumEntries * sizeof(PALETTEENTRY));
  1251. // Set the version number and count
  1252. plogpaletteMerged->palVersion = plogpalette->palVersion;
  1253. plogpaletteMerged->palNumEntries = _plogpalette->palNumEntries
  1254. + plogpalette->palNumEntries;
  1255. // Replace current palette table with merged table
  1256. CoTaskMemFree(_plogpalette);
  1257. _plogpalette = plogpaletteMerged;
  1258. CleanTempPalette:
  1259. CoTaskMemFree(plogpalette);
  1260. CleanUp:
  1261. // Release object we got since we don't need it any more
  1262. pviewobj->Release();
  1263. #endif // NOPALETTE
  1264. }
  1265. /*
  1266. * CRenderer::RenderChunk (&cchChunk, pchRender, cch)
  1267. *
  1268. * @mfunc
  1269. * Method reducing the length of the chunk (number of character
  1270. * rendered in one RenderText) and to render items interleaved in text.
  1271. *
  1272. * @rdesc
  1273. * TRUE if this method actually rendered the chunk,
  1274. * FALSE if it just updated cchChunk and rendering is still needed
  1275. */
  1276. BOOL CRenderer::RenderChunk(
  1277. LONG & cchChunk, //@parm in: chunk cch; out: # chars rendered
  1278. // if return TRUE; else # chars yet to render
  1279. const WCHAR *pchRender, //@parm pchRender render up to cchChunk chars
  1280. LONG cch) //@parm # chars left to render on line
  1281. {
  1282. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CRenderer::RenderChunk");
  1283. LONG cchValid = cchChunk;
  1284. LONG i;
  1285. const WCHAR *pchT;
  1286. // Search for object in chunk
  1287. for(pchT = pchRender, i = 0; i < cchValid && *pchT != WCH_EMBEDDING; i++)
  1288. pchT++;
  1289. if(i == 0)
  1290. {
  1291. // First character is object so display object
  1292. COleObject *pobj = GetObjectFromCp(GetCp());
  1293. if(pobj)
  1294. {
  1295. LONG dvpAscent, dvpDescent, dupObject;
  1296. pobj->MeasureObj(_dvpInch, _dupInch, dupObject, dvpAscent, dvpDescent, _li._dvpDescent, GetTflow());
  1297. if (W32->FUsePalette() && _li._fUseOffscreenDC && _pdp->IsMain())
  1298. {
  1299. // Keep track of palette needed for rendering bitmap
  1300. UpdatePalette(pobj);
  1301. }
  1302. SetClipLeftRight(dupObject);
  1303. pobj->DrawObj(_pdp, _dvpInch, _dupInch, _hdc, &GetClipRect(), _pdp->IsMetafile(), &_ptCur,
  1304. _li._dvpHeight - _li._dvpDescent, _li._dvpDescent, GetTflow());
  1305. _ptCur.u += dupObject;
  1306. _li._dup += dupObject;
  1307. }
  1308. cchChunk = 1;
  1309. // Both tabs and object code need to advance the run pointer past
  1310. // each character processed.
  1311. Move(1);
  1312. return TRUE;
  1313. }
  1314. cchChunk -= cchValid - i; // Limit chunk to char before object
  1315. // Handle other special characters
  1316. LONG cchT = 0;
  1317. for(pchT = pchRender; cchT < cchChunk; pchT++, cchT++)
  1318. {
  1319. switch(*pchT)
  1320. {
  1321. case EURO: //NOTE: (keithcu) Euro's need this special logic only for printing/metafiles
  1322. case TAB:
  1323. case NBSPACE:
  1324. case SOFTHYPHEN:
  1325. case NBHYPHEN:
  1326. case EMSPACE:
  1327. case ENSPACE:
  1328. break;
  1329. default:
  1330. continue;
  1331. }
  1332. break;
  1333. }
  1334. if(!cchT)
  1335. {
  1336. // First char is a tab, render it and any that follow
  1337. if(*pchT == TAB)
  1338. cchChunk = RenderTabs(cchChunk);
  1339. else
  1340. {
  1341. WCHAR chT = *pchT;
  1342. if (*pchT == NBSPACE)
  1343. chT = ' ';
  1344. else if (*pchT == NBHYPHEN || *pchT == SOFTHYPHEN)
  1345. chT = '-';
  1346. if(*pchT != SOFTHYPHEN || cch == 1) // Only render hyphens/blank at EOL
  1347. RenderText(&chT, 1);
  1348. Move(1); // Skip those within line
  1349. cchChunk = 1;
  1350. }
  1351. Assert (cchChunk > 0);
  1352. return TRUE;
  1353. }
  1354. cchChunk = cchT; // Update cchChunk not to incl trailing tabs
  1355. return FALSE;
  1356. }
  1357. /*
  1358. * CRenderer::SetClipRect()
  1359. *
  1360. * @mfunc
  1361. * Helper to set clipping rect for the line
  1362. */
  1363. void CRenderer::SetClipRect()
  1364. {
  1365. _rc = _rcRender;
  1366. _rc.top = _ptCur.v;
  1367. _rc.bottom = _rc.top + _li._dvpHeight;
  1368. _rc.top = max(_rc.top, _rcView.top);
  1369. _rc.bottom = min(_rc.bottom, _rcView.bottom);
  1370. }
  1371. /*
  1372. * CRenderer::SetClipLeftRight (dup)
  1373. *
  1374. * @mfunc
  1375. * Helper to sets left and right of clipping/erase rect.
  1376. *
  1377. * @rdesc
  1378. * Sets _rc left and right
  1379. */
  1380. void CRenderer::SetClipLeftRight(
  1381. LONG dup) //@parm Width of chunk to render
  1382. {
  1383. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CRenderer::SetClipLeftRight");
  1384. //Nominal value
  1385. _rc.left = _ptCur.u;
  1386. _rc.right = _rc.left + dup;
  1387. //Constrain left and right based on rcView, rcRender
  1388. _rc.left = max(_rc.left, _rcRender.left);
  1389. _rc.right = max(_rc.right, _rc.left);
  1390. _rc.right = min(_rc.right, _rcRender.right);
  1391. }
  1392. /*
  1393. * CRenderer::GetConvertMode()
  1394. *
  1395. * @mfunc
  1396. * Return the mode that should really be used in the RenderText call
  1397. */
  1398. CONVERTMODE CRenderer::GetConvertMode()
  1399. {
  1400. CONVERTMODE cm = (CONVERTMODE)_pccs->_bConvertMode;
  1401. // For hack around ExtTextOutW Win95 problems.
  1402. if (cm != CVT_LOWBYTE && W32->OnWin9x() && (_pdp->IsMetafile() || _fEnhancedMetafileDC))
  1403. return CVT_WCTMB;
  1404. if (cm != CVT_LOWBYTE && _pdp->IsMetafile() && !_fEnhancedMetafileDC)
  1405. return CVT_WCTMB; // WMF cant store Unicode so we cant use ExtTextOutW
  1406. return cm;
  1407. }
  1408. /*
  1409. * CRenderer::RenderExtTextOut (ptuv, fuOptions, prc, pwchRun, cch, rgdxp)
  1410. *
  1411. * @mfunc
  1412. * Calls ExtTextOut and handles disabled text. There is duplicate logic in OlsDrawGlyphs, but
  1413. * the params are different so that was simplest way.
  1414. *
  1415. */
  1416. extern ICustomTextOut *g_pcto;
  1417. void CRenderer::RenderExtTextOut(
  1418. POINTUV ptuv,
  1419. UINT fuOptions,
  1420. RECT *prc,
  1421. PCWSTR pch,
  1422. UINT cch,
  1423. const INT *rgdxp)
  1424. {
  1425. CONVERTMODE cm = GetConvertMode();
  1426. if (prc->left >= prc->right || prc->top >= prc->bottom)
  1427. return;
  1428. DWORD dwETOFlags = GetTflow();
  1429. if (_fFEFontOnNonFEWin9x)
  1430. dwETOFlags |= fETOFEFontOnNonFEWin9x;
  1431. if (_pccs->_fCustomTextOut)
  1432. dwETOFlags |= fETOCustomTextOut;
  1433. if(_fDisabled)
  1434. {
  1435. if(_crForeDisabled != _crShadowDisabled)
  1436. {
  1437. // The shadow should be offset by a hairline point, namely
  1438. // 3/4 of a point. Calculate how big this is in device units,
  1439. // but make sure it is at least 1 pixel.
  1440. DWORD offset = MulDiv(3, _dvpInch, 4*72);
  1441. offset = max(offset, 1);
  1442. // Draw shadow
  1443. SetTextColor(_crShadowDisabled);
  1444. POINTUV ptuvT = ptuv;
  1445. ptuvT.u += offset;
  1446. ptuvT.v += offset;
  1447. POINT pt;
  1448. _pdp->PointFromPointuv(pt, ptuvT, TRUE);
  1449. W32->REExtTextOut(cm, _pccs->_wCodePage, _hdc, pt.x, pt.y,
  1450. fuOptions, prc, pch, cch, rgdxp, dwETOFlags);
  1451. // Now set drawing mode to transparent
  1452. fuOptions &= ~ETO_OPAQUE;
  1453. SetBkMode(_hdc, TRANSPARENT);
  1454. }
  1455. SetTextColor(_crForeDisabled);
  1456. }
  1457. POINT pt;
  1458. _pdp->PointFromPointuv(pt, ptuv, TRUE);
  1459. W32->REExtTextOut(cm, _pccs->_wCodePage, _hdc, pt.x, pt.y, fuOptions, prc, pch, cch, rgdxp, dwETOFlags);
  1460. }
  1461. /*
  1462. * CRenderer::RenderText (pch, cch)
  1463. *
  1464. * @mfunc
  1465. * Render text in the current context of this CRenderer
  1466. *
  1467. * @devnote
  1468. * Renders text only: does not do tabs or OLE objects
  1469. */
  1470. void CRenderer::RenderText(
  1471. const WCHAR *pch, //@parm Text to render
  1472. LONG cch) //@parm Length of text to render
  1473. {
  1474. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CRenderer::RenderText");
  1475. LONG dvp, cchT;
  1476. // Variables used for calculating length of underline.
  1477. LONG dupSelPastEOL = 0;
  1478. BOOL fCell = FALSE;
  1479. UINT fuOptions = _pdp->IsMain() ? ETO_CLIPPED : 0;
  1480. LONG dup;
  1481. LONG dupT;
  1482. CTempBuf rgdu;
  1483. //Reset clip rectangle to greater of view/render rectangle
  1484. _rc.left = _rcRender.left;
  1485. _rc.right = _rcRender.right;
  1486. // Trim all nondisplayable linebreaking chars off end
  1487. while(cch && IsASCIIEOP(pch[cch - 1]))
  1488. cch--;
  1489. if(cch && pch[cch-1] == CELL)
  1490. {
  1491. fCell = TRUE;
  1492. cch--;
  1493. }
  1494. int *pdu = (int *)rgdu.GetBuf(cch * sizeof(int));
  1495. // Measure width of text to write so next point to write can be
  1496. // calculated.
  1497. dup = 0;
  1498. for(cchT = 0;
  1499. cchT < cch && dup < _rc.right - _ptCur.u;
  1500. cchT++)
  1501. {
  1502. dupT = 0;
  1503. if (!_pccs->Include(*pch, dupT))
  1504. {
  1505. TRACEERRSZSC("CRenderer::RenderText(): Error filling CCcs", E_FAIL);
  1506. return;
  1507. }
  1508. if (pdu)
  1509. *pdu++ = dupT;
  1510. pch++;
  1511. dup += dupT;
  1512. }
  1513. // Go back to start of chunk
  1514. cch = cchT;
  1515. pch -= cch;
  1516. if (pdu)
  1517. pdu -= cch;
  1518. if(_fLastChunk && _fSelectToEOL && _li._cchEOP)
  1519. {
  1520. // Use the width of the current font's space to highlight
  1521. if(!_pccs->Include(' ', dupT))
  1522. {
  1523. TRACEERRSZSC("CRenderer::RenderText(): Error no length of space", E_FAIL);
  1524. return;
  1525. }
  1526. dupSelPastEOL = dupT;
  1527. dup += dupSelPastEOL;
  1528. _fSelectToEOL = FALSE; // Reset the flag
  1529. }
  1530. _li._dup += dup;
  1531. // Setup for drawing selections via ExtTextOut.
  1532. if(_fSelected || _crBackground != _crCurBackground)
  1533. {
  1534. SetClipLeftRight(dup);
  1535. if(_fSelected && fCell)
  1536. {
  1537. // Needs work, but this is a start. _rcRender has the cell
  1538. // boundaries, so we need to use them on the right calls.
  1539. _rc.right = _rcRender.right;
  1540. }
  1541. fuOptions = ETO_CLIPPED | ETO_OPAQUE;
  1542. }
  1543. dvp = _ptCur.v + _li._dvpHeight - _li._dvpDescent + _pccs->_yDescent - _pccs->_yHeight;
  1544. LONG dvpOffset, dvpAdjust;
  1545. _pccs->GetOffset(GetCF(), _dvpInch, &dvpOffset, &dvpAdjust);
  1546. dvp -= dvpOffset + dvpAdjust;
  1547. POINTUV ptuv = {_ptCur.u, dvp};
  1548. RECT rc;
  1549. _pdp->RectFromRectuv(rc, _rc);
  1550. //For 1 char runs, we may need to swap the character we output.
  1551. WCHAR ch;
  1552. if (cch == 1)
  1553. {
  1554. switch(*pch)
  1555. {
  1556. case EMSPACE:
  1557. case ENSPACE:
  1558. ch = ' ';
  1559. pch = &ch;
  1560. break;
  1561. }
  1562. }
  1563. RenderExtTextOut(ptuv, fuOptions, &rc, pch, cch, pdu);
  1564. // Calculate width to draw for underline/strikeout
  1565. // FUTURE (keithcu) Don't underline trailing spaces?
  1566. if(_bUnderlineType != CFU_UNDERLINENONE || _fStrikeOut)
  1567. {
  1568. LONG dupToDraw = dup - dupSelPastEOL;
  1569. LONG upStart = _ptCur.u;
  1570. LONG upEnd = upStart + dupToDraw;
  1571. upStart = max(upStart, _rcRender.left);
  1572. upEnd = min(upEnd, _rcRender.right);
  1573. dupToDraw = upEnd - upStart;
  1574. if(dupToDraw > 0)
  1575. {
  1576. LONG y = _ptCur.v + _li._dvpHeight - _li._dvpDescent;
  1577. y -= dvpOffset + dvpAdjust;
  1578. // Render underline if required
  1579. if(_bUnderlineType != CFU_UNDERLINENONE)
  1580. RenderUnderline(upStart, y + _pccs->_dyULOffset, dupToDraw, _pccs->_dyULWidth);
  1581. // Render strikeout if required
  1582. if(_fStrikeOut)
  1583. RenderStrikeOut(upStart, y + _pccs->_dySOOffset, dupToDraw, _pccs->_dySOWidth);
  1584. }
  1585. }
  1586. _fSelected = FALSE;
  1587. _ptCur.u += dup; // Update current point
  1588. }
  1589. /*
  1590. * CRenderer::RenderTabs (cchMax)
  1591. *
  1592. * @mfunc
  1593. * Render a span of zero or more tab characters in chunk *this
  1594. *
  1595. * @rdesc
  1596. * number of tabs rendered
  1597. *
  1598. * @devnote
  1599. * *this is advanced by number of tabs rendered
  1600. * MS - tabs should be rendered using opaquing rect of adjacent string
  1601. */
  1602. LONG CRenderer::RenderTabs(
  1603. LONG cchMax) //@parm Max cch to render (cch in chunk)
  1604. {
  1605. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CRenderer::RenderTabs");
  1606. LONG cch = cchMax;
  1607. LONG ch = GetChar();
  1608. LONG chPrev = 0;
  1609. LONG upTab, upTabs;
  1610. for(upTabs = 0; cch && ch == TAB; cch--)
  1611. {
  1612. upTab = MeasureTab(ch);
  1613. _li._dup += upTab; // Advance internal width
  1614. upTabs += upTab; // Accumulate width of tabbed
  1615. Move(1); // region
  1616. chPrev = ch;
  1617. ch = GetChar();
  1618. }
  1619. if(_li._dup > _dupLine)
  1620. {
  1621. upTabs = 0;
  1622. _li._dup = _dupLine;
  1623. }
  1624. if(upTabs)
  1625. {
  1626. LONG dup = 0;
  1627. LONG upGap = 0;
  1628. if(_fSelected && chPrev == CELL && ch != CR && _pPF->InTable())
  1629. {
  1630. LONG cpSelMin, cpSelMost;
  1631. GetPed()->GetSelRangeForRender(&cpSelMin, &cpSelMost);
  1632. if(GetCp() == cpSelMin || GetCp() == cpSelMost)
  1633. {
  1634. upGap = LUtoDU(_pPF->_dxOffset);
  1635. if(GetCp() == cpSelMost)
  1636. {
  1637. dup = upGap;
  1638. upGap = 0;
  1639. }
  1640. }
  1641. }
  1642. SetClipLeftRight(upTabs - dup);
  1643. if(_rc.left < _rc.right) // Something to erase
  1644. {
  1645. if(_fSelected) // Use selection background color
  1646. {
  1647. COLORREF cr = GetPed()->TxGetSysColor(COLOR_HIGHLIGHT);
  1648. if (!UseXOR(cr))
  1649. {
  1650. ::SetBkColor (_hdc, cr);
  1651. _crCurTextColor = GetPed()->TxGetSysColor(COLOR_HIGHLIGHTTEXT);
  1652. }
  1653. else
  1654. {
  1655. const CCharFormat* pCF = GetCF();
  1656. ::SetBkColor (_hdc, (pCF->_dwEffects & CFE_AUTOBACKCOLOR) ?
  1657. _crBackground ^ RGB_WHITE : pCF->_crBackColor ^ RGB_WHITE);
  1658. _crCurTextColor = (pCF->_dwEffects & CFE_AUTOCOLOR) ?
  1659. _crTextColor ^ RGB_WHITE : pCF->_crTextColor ^ RGB_WHITE;
  1660. }
  1661. }
  1662. // Paint background with appropriate color
  1663. if(_fSelected || _crBackground != _crCurBackground)
  1664. EraseTextOut(_hdc, &_rc, TRUE);
  1665. // Render underline if required
  1666. dup = _rc.right - _rc.left;
  1667. LONG vp = _ptCur.v + _li._dvpHeight - _li._dvpDescent;
  1668. LONG dvpOffset, dvpAdjust;
  1669. _pccs->GetOffset(GetCF(), _dvpInch, &dvpOffset, &dvpAdjust);
  1670. vp -= dvpOffset + dvpAdjust;
  1671. if(_bUnderlineType != CFU_UNDERLINENONE)
  1672. RenderUnderline(_rc.left, vp + _pccs->_dyULOffset, dup, _pccs->_dyULWidth);
  1673. // Render strikeout if required
  1674. if(_fStrikeOut)
  1675. RenderStrikeOut(_rc.left, vp + _pccs->_dySOOffset, dup, _pccs->_dySOWidth);
  1676. if(_fSelected) // Restore colors
  1677. ::SetBkColor(_hdc, _crCurBackground);
  1678. }
  1679. _ptCur.u += upTabs; // Update current point
  1680. }
  1681. return cchMax - cch; // Return # tabs rendered
  1682. }
  1683. /*
  1684. * CRenderer::SetNewFont()
  1685. *
  1686. * @mfunc
  1687. * Select appropriate font and color in the _hdc based on the
  1688. * current character format. Also sets the background color
  1689. * and mode.
  1690. *
  1691. * @rdesc
  1692. * TRUE if it succeeds
  1693. *
  1694. * @devnote
  1695. * The calling chain must be protected by a CLock, since this present
  1696. * routine access the global (shared) FontCache facility.
  1697. */
  1698. BOOL CRenderer::SetNewFont()
  1699. {
  1700. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CRenderer::SetNewFont");
  1701. const CCharFormat *pCF = GetCF();
  1702. DWORD dwEffects = pCF->_dwEffects;
  1703. BOOL fDisplay = fDisplayDC();
  1704. // Release previous font in use
  1705. if(_pccs)
  1706. _pccs->Release();
  1707. Assert(_fTarget == FALSE);
  1708. _pccs = GetCcs(pCF);
  1709. if(!_pccs)
  1710. {
  1711. TRACEERRSZSC("CRenderer::SetNewFont(): no CCcs", E_FAIL);
  1712. return FALSE;
  1713. }
  1714. // Select font in _hdc
  1715. AssertSz(_pccs->_hfont, "CRenderer::SetNewFont _pccs->_hfont is NULL");
  1716. SetFontAndColor(pCF);
  1717. // Assume no underlining
  1718. _bUnderlineType = CFU_UNDERLINENONE;
  1719. // We want to draw revision marks and native hyperlinks with underlining,
  1720. // so just fake out our font information.
  1721. if((dwEffects & (CFE_UNDERLINE | CFE_REVISED)) ||
  1722. (dwEffects & (CFE_LINKPROTECTED | CFE_LINK)) == CFE_LINK ||
  1723. fDisplay && GetTmpUnderline(pCF->_sTmpDisplayAttrIdx))
  1724. {
  1725. if (dwEffects & CFE_LINK)
  1726. SetupUnderline(CFU_UNDERLINE, 0);
  1727. else
  1728. {
  1729. BYTE bTmpUnderlineIdx = 0;
  1730. if (fDisplay)
  1731. bTmpUnderlineIdx = GetTmpUnderline(pCF->_sTmpDisplayAttrIdx);
  1732. if (bTmpUnderlineIdx)
  1733. {
  1734. COLORREF crTmpUnderline;
  1735. GetTmpUnderlineColor(pCF->_sTmpDisplayAttrIdx, crTmpUnderline);
  1736. SetupUnderline(bTmpUnderlineIdx, 0, crTmpUnderline);
  1737. }
  1738. else
  1739. SetupUnderline(pCF->_bUnderlineType, pCF->_bUnderlineColor);
  1740. }
  1741. }
  1742. _fStrikeOut = (dwEffects & (CFE_STRIKEOUT | CFE_DELETED)) != 0;
  1743. return TRUE;
  1744. }
  1745. /*
  1746. * CRenderer::SetupUnderline (bULType, bULColorIdx, crULColor)
  1747. *
  1748. * @mfunc
  1749. * Setup internal variables for underlining
  1750. */
  1751. void CRenderer::SetupUnderline(
  1752. BYTE bULType,
  1753. BYTE bULColorIdx,
  1754. COLORREF crULColor)
  1755. {
  1756. _bUnderlineType = bULType;
  1757. _crUnderlineClr = crULColor;
  1758. if (bULColorIdx)
  1759. GetPed()->GetEffectColor(bULColorIdx, &_crUnderlineClr);
  1760. }
  1761. /*
  1762. * CRenderer::UseXOR (cr)
  1763. *
  1764. * @mfunc
  1765. * Return if reverse video selection should be used for the nominal
  1766. * selection color cr. RichEdit 1.0 mode always uses reverse video
  1767. * selection. Else use it if cr is too close to the current window
  1768. * background.
  1769. *
  1770. * @rdesc
  1771. * Return if caller should use reverse video for cr
  1772. */
  1773. BOOL CRenderer::UseXOR(
  1774. COLORREF cr) //@parm Color to compare _crBackground to
  1775. {
  1776. return GetPed()->Get10Mode() ||
  1777. (_crBackground != GetPed()->TxGetSysColor(COLOR_WINDOW) &&
  1778. IsTooSimilar(_crBackground, cr));
  1779. }
  1780. /*
  1781. * CRenderer::SetFontAndColor (pCF)
  1782. *
  1783. * @mfunc
  1784. * Select appropriate font and color in the _hdc based on the
  1785. * current character format. Also sets the background color
  1786. * and mode.
  1787. */
  1788. void CRenderer::SetFontAndColor(
  1789. const CCharFormat *pCF) //@parm Character format for colors
  1790. {
  1791. CTxtEdit *ped = GetPed();
  1792. _fDisabled = FALSE;
  1793. if((pCF->_dwEffects & (CFE_AUTOCOLOR | CFE_DISABLED))
  1794. == (CFE_AUTOCOLOR | CFE_DISABLED))
  1795. {
  1796. _fDisabled = TRUE;
  1797. _crForeDisabled = ped->TxGetSysColor(COLOR_3DSHADOW);
  1798. _crShadowDisabled = ped->TxGetSysColor(COLOR_3DHILIGHT);
  1799. }
  1800. _fFEFontOnNonFEWin9x = FALSE;
  1801. if (IsFECharRep(pCF->_iCharRep) && W32->OnWin9x() && !W32->OnWin9xFE())
  1802. _fFEFontOnNonFEWin9x = TRUE;
  1803. SelectFont(_hdc, _pccs->_hfont);
  1804. // Compute height and descent if not yet done
  1805. if(_li._dvpHeight == -1)
  1806. {
  1807. SHORT dvpAdjustFE = _pccs->AdjustFEHeight(!fUseUIFont() && ped->_pdp->IsMultiLine());
  1808. // Note: this assumes plain text
  1809. // Should be used only for single line control
  1810. _li._dvpHeight = _pccs->_yHeight + (dvpAdjustFE << 1);
  1811. _li._dvpDescent = _pccs->_yDescent + dvpAdjustFE;
  1812. }
  1813. SetTextColor(GetTextColor(pCF)); // Set current text color
  1814. COLORREF cr;
  1815. if(_fSelected) // Set current background color
  1816. {
  1817. cr = GetPed()->TxGetSysColor(COLOR_HIGHLIGHT);
  1818. if (UseXOR(cr))
  1819. {
  1820. // There are 2 cases to be concerned with
  1821. // 1) if the background color is the same as the selection color or
  1822. // 2) if 1.0 Window and the background color is NOT system default
  1823. cr = (pCF->_dwEffects & CFE_AUTOBACKCOLOR) ?
  1824. _crBackground ^ RGB_WHITE : pCF->_crBackColor ^ RGB_WHITE;
  1825. }
  1826. }
  1827. else if(!fDisplayDC() ||
  1828. !(GetTmpBackColor(pCF->_sTmpDisplayAttrIdx, cr))) // Any temp. background color?
  1829. { // No, use regular background color
  1830. if(pCF->_dwEffects & CFE_AUTOBACKCOLOR)
  1831. cr = _crBackground;
  1832. else // Text run has some kind of back color
  1833. cr = pCF->_crBackColor;
  1834. }
  1835. if(cr != _crCurBackground)
  1836. {
  1837. ::SetBkColor(_hdc, cr); // Tell window background color
  1838. _crCurBackground = cr; // Remember current background color
  1839. _fBackgroundColor = _crBackground != cr; // Change render settings so we
  1840. } // won't fill with background color
  1841. }
  1842. /*
  1843. * CRenderer::SetDefaultBackColor (cr)
  1844. *
  1845. * @mfunc
  1846. * Select given background color in the _hdc. Used for setting
  1847. * background color in table cells.
  1848. */
  1849. void CRenderer::SetDefaultBackColor(
  1850. COLORREF cr) //@parm Background color to use
  1851. {
  1852. if(cr == tomAutoColor)
  1853. cr = GetPed()->TxGetBackColor(); // Printer needs work...
  1854. if(_crBackground != cr)
  1855. {
  1856. _crCurBackground = _crBackground = cr;
  1857. ::SetBkColor(_hdc, cr);
  1858. }
  1859. }
  1860. /*
  1861. * CRenderer::SetDefaultTextColor (cr)
  1862. *
  1863. * @mfunc
  1864. * Select given foreground color in the _hdc. Used for setting
  1865. * text color in table cells.
  1866. */
  1867. void CRenderer::SetDefaultTextColor(
  1868. COLORREF cr) //@parm Background color to use
  1869. {
  1870. if(cr == tomAutoColor)
  1871. cr = GetPed()->TxGetForeColor(); // Printer needs work...
  1872. if(_crTextColor != cr)
  1873. {
  1874. _crCurTextColor = _crTextColor = cr;
  1875. ::SetTextColor(_hdc, cr);
  1876. }
  1877. }
  1878. /*
  1879. * CRenderer::SetTextColor (cr)
  1880. *
  1881. * @mfunc
  1882. * Select given text color in the _hdc
  1883. * Used to maintain _crCurTextColor cache
  1884. */
  1885. void CRenderer::SetTextColor(
  1886. COLORREF cr) //@parm color to set in the dc
  1887. {
  1888. if(cr != _crCurTextColor)
  1889. {
  1890. _crCurTextColor = cr;
  1891. ::SetTextColor(_hdc, cr);
  1892. }
  1893. }
  1894. /*
  1895. * CRenderer::GetTextColor(pCF)
  1896. *
  1897. * @mfunc
  1898. * Return text color for pCF. Depends on _bRevAuthor, display tech
  1899. *
  1900. * FUTURE (keithcu) It might be nice to have black or blue selected text be
  1901. * white, but to have all other colors stay their other colors. What do we
  1902. * do if the backcolor is blue??
  1903. *
  1904. * @rdesc
  1905. * text color
  1906. */
  1907. COLORREF CRenderer::GetTextColor(
  1908. const CCharFormat *pCF) //@parm CCharFormat specifying text color
  1909. {
  1910. if(_fSelected)
  1911. {
  1912. // There are 2 cases where XOR for selection is needed
  1913. // 1) if the background is the same as the selection background
  1914. // 2) if 1.0 window and the background isn't the system default window
  1915. // background color
  1916. // if this doesn't match the above case just return the cr
  1917. if (!UseXOR(GetPed()->TxGetSysColor(COLOR_HIGHLIGHT)))
  1918. return GetPed()->TxGetSysColor(COLOR_HIGHLIGHTTEXT);
  1919. // xor the current text color for the selected text color
  1920. return (pCF->_dwEffects & CFE_AUTOCOLOR) ? _crTextColor ^ RGB_WHITE :
  1921. pCF->_crTextColor ^ RGB_WHITE;
  1922. }
  1923. // The following could be generalized to return a different color for
  1924. // links that have been visited for this text instance (need to define
  1925. // extra CCharFormat::_dwEffects internal flag to ID these links)
  1926. if((pCF->_dwEffects & (CFE_LINK | CFE_LINKPROTECTED)) == CFE_LINK)
  1927. {
  1928. // Blue doesnt show up very well against dark backgrounds.
  1929. // In these situations, use the system selected text color.
  1930. COLORREF crBackground = (pCF->_dwEffects & CFE_AUTOBACKCOLOR)
  1931. ? _crBackground : pCF->_crBackColor;
  1932. if (IsTooSimilar(crBackground, RGB_BLACK) || IsTooSimilar(crBackground, RGB_BLUE))
  1933. {
  1934. COLORREF crHighlightText = GetPed()->TxGetSysColor(COLOR_HIGHLIGHTTEXT);
  1935. if (IsTooSimilar(crBackground, crHighlightText))
  1936. {
  1937. // Background is similar to highlight, use window text color
  1938. return GetPed()->TxGetSysColor(COLOR_WINDOWTEXT);
  1939. }
  1940. else
  1941. {
  1942. return crHighlightText;
  1943. }
  1944. }
  1945. // If not high contrast, fall through
  1946. }
  1947. BOOL fDisplay = fDisplayDC();
  1948. #ifndef NODRAFTMODE
  1949. // Use draft mode text color only for displays
  1950. if (GetPed()->_fDraftMode && (!_hdc || fDisplay))
  1951. {
  1952. SHORT iFont;
  1953. SHORT yHeight;
  1954. QWORD qwFontSig;
  1955. COLORREF crColor;
  1956. if (W32->GetDraftModeFontInfo(iFont, yHeight, qwFontSig, crColor))
  1957. return crColor;
  1958. }
  1959. #endif
  1960. // If we did not return the URL color via draft mode or the high contrast check, do it now
  1961. if((pCF->_dwEffects & (CFE_LINK | CFE_LINKPROTECTED)) == CFE_LINK)
  1962. return RGB_BLUE;
  1963. if(pCF->_bRevAuthor) // Rev author
  1964. {
  1965. // Limit color of rev authors to 0 through 7.
  1966. return rgcrRevisions[(pCF->_bRevAuthor - 1) & REVMASK];
  1967. }
  1968. COLORREF cr = (pCF->_dwEffects & CFE_AUTOCOLOR) ? _crTextColor : pCF->_crTextColor;
  1969. COLORREF crTmpTextColor;
  1970. if(fDisplay && GetTmpTextColor(pCF->_sTmpDisplayAttrIdx, crTmpTextColor))
  1971. cr = crTmpTextColor;
  1972. if(cr == RGB_WHITE) // Text is white
  1973. {
  1974. COLORREF crBackground = (pCF->_dwEffects & CFE_AUTOBACKCOLOR)
  1975. ? _crBackground : pCF->_crBackColor;
  1976. COLORREF crTmpBackground;
  1977. if(fDisplay && GetTmpBackColor(pCF->_sTmpDisplayAttrIdx, crTmpBackground))
  1978. crBackground = crTmpBackground;
  1979. if(crBackground != RGB_WHITE)
  1980. {
  1981. // Background color isn't white, so white text is probably
  1982. // visible unless display device is only black/white. So we
  1983. // switch to black text on such devices.
  1984. if (GetDeviceCaps(_hdc, NUMCOLORS) == 2 ||
  1985. GetDeviceCaps(_hdc, TECHNOLOGY) == DT_PLOTTER)
  1986. {
  1987. cr = RGB_BLACK;
  1988. }
  1989. }
  1990. }
  1991. return cr;
  1992. }
  1993. extern BOOL g_OLSBusy;
  1994. /*
  1995. * CRenderer::StartLine(&li, fLastLine, &cpSelMin, &cpSelMost, &dup, &dvp)
  1996. *
  1997. * @mfunc
  1998. * Render possible outline symbol and bullet if at start of line
  1999. *
  2000. * @rdesc
  2001. * hdcSave if using offscreen DC
  2002. */
  2003. HDC CRenderer::StartLine(
  2004. CLine & li, //@parm Line to render
  2005. BOOL fLastLine, //@parm True if last line in layout
  2006. LONG & cpSelMin, //@parm Out parm for current selection cpMin
  2007. LONG & cpSelMost, //@parm Out parm for current selection cpMost
  2008. LONG & dup, //@parm Offset to u
  2009. LONG & dvp) //@parm Offset to v
  2010. {
  2011. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CRenderer::StartLine");
  2012. BOOL fDrawBack = !(GetCF()->_dwEffects & CFE_AUTOBACKCOLOR) && GetPed()->_fExtendBackColor;
  2013. RECTUV rcErase = _rcRender;
  2014. _fEraseOnFirstDraw = FALSE;
  2015. GetPed()->GetSelRangeForRender(&cpSelMin, &cpSelMost);
  2016. if(cpSelMost != cpSelMin && cpSelMost == GetCp())
  2017. _fSelectedPrev = TRUE;
  2018. LONG cpMost = GetCp() + _li._cch;
  2019. COLORREF crPrev = 0xFFFFFFFF;
  2020. BOOL fUseSelColors = FALSE;
  2021. if (cpMost <= cpSelMost && cpMost - 1 >= cpSelMin &&
  2022. _pPF->InTable() && _fRenderSelection)
  2023. {
  2024. CTxtPtr tp(_rpTX);
  2025. tp.SetCp(cpMost);
  2026. if(tp.GetPrevChar() == CELL)
  2027. {
  2028. fUseSelColors = TRUE;
  2029. crPrev = ::SetBkColor(GetDC(), GetPed()->TxGetSysColor(COLOR_HIGHLIGHT));
  2030. }
  2031. }
  2032. SetClipRect();
  2033. HDC hdcSave = NULL;
  2034. dup = dvp = 0;
  2035. if(li._cch > 0 && li._fUseOffscreenDC)
  2036. {
  2037. // Set up an off-screen DC if we can. Note that if this fails,
  2038. // we just use the regular DC which won't look as nice but
  2039. // will at least display something readable.
  2040. hdcSave = SetupOffscreenDC(dup, dvp, fLastLine);
  2041. if(li._fOffscreenOnce)
  2042. li._fUseOffscreenDC = li._fOffscreenOnce = FALSE;
  2043. }
  2044. rcErase.top = _ptCur.v;
  2045. rcErase.bottom = min(rcErase.top + _li._dvpHeight, _rcRender.bottom);
  2046. //If first line, erase to edge of rcRender
  2047. if (rcErase.top <= _rcView.top)
  2048. rcErase.top = _rcRender.top;
  2049. //If last line, erase to bottom edge of rcRender
  2050. if (fLastLine)
  2051. rcErase.bottom = _rcRender.bottom;
  2052. if (_fErase && !fDrawBack)
  2053. {
  2054. if(g_OLSBusy && IsSimpleBackground() && !fUseSelColors)
  2055. {
  2056. _fEraseOnFirstDraw = TRUE;
  2057. _rcErase = rcErase;
  2058. }
  2059. else
  2060. EraseTextOut(GetDC(), &rcErase);
  2061. }
  2062. // Fill line with background color if we are in fExtendBackColor mode
  2063. if (fDrawBack || fUseSelColors)
  2064. {
  2065. // Capture old color so we reset it to what it was when we're finished
  2066. COLORREF crOld = 0;
  2067. if(fDrawBack)
  2068. crOld = ::SetBkColor(GetDC(), GetCF()->_crBackColor);
  2069. EraseTextOut(GetDC(), &_rc);
  2070. // Reset background color to old color
  2071. if(fDrawBack)
  2072. ::SetBkColor(GetDC(), crOld);
  2073. //Erase the remainder of the background area
  2074. if (_fErase)
  2075. {
  2076. RECTUV rcTemp = rcErase;
  2077. //Erase the top part if necessary
  2078. if (rcErase.top < _rc.top)
  2079. {
  2080. rcTemp.bottom = _rc.top;
  2081. EraseTextOut(GetDC(), &rcTemp);
  2082. }
  2083. //Erase the left and right parts if necessary
  2084. rcTemp.top = _rc.top;
  2085. rcTemp.bottom = _rc.bottom;
  2086. if (rcErase.left < _rc.left)
  2087. {
  2088. rcTemp.right = _rc.left;
  2089. EraseTextOut(GetDC(), &rcTemp);
  2090. }
  2091. if (rcErase.right > _rc.right)
  2092. {
  2093. rcTemp.left = _rc.right;
  2094. rcTemp.right = rcErase.right;
  2095. EraseTextOut(GetDC(), &rcTemp);
  2096. }
  2097. }
  2098. }
  2099. if(crPrev != 0xFFFFFFFF)
  2100. ::SetBkColor(GetDC(), crPrev);
  2101. if(IsRich() && _li._fFirstInPara && _pPF)
  2102. {
  2103. if(IsInOutlineView())
  2104. RenderOutlineSymbol();
  2105. if(_pPF->_wNumbering && !fUseLineServices())
  2106. RenderBullet();
  2107. }
  2108. // Reset format if there is special background color for previous line.
  2109. // Otherwise, current line with the same format will not re-paint with the
  2110. // special background color
  2111. if (_fBackgroundColor)
  2112. {
  2113. _iFormat = -10; // Reset to invalid format
  2114. // Assume that there is no special background color for the line
  2115. _fBackgroundColor = FALSE;
  2116. }
  2117. // Handle setting background color. If the current background
  2118. // color is different than the default, we need to set the background
  2119. // to this because the end of line processing reset the color so
  2120. // that opaquing would work.
  2121. if(_crBackground != _crCurBackground)
  2122. {
  2123. // Tell the window the background color
  2124. ::SetBkColor(_hdc, _crCurBackground);
  2125. _fBackgroundColor = TRUE;
  2126. }
  2127. return hdcSave;
  2128. }
  2129. /*
  2130. * CRenderer::EraseToBottom()
  2131. *
  2132. * @mfunc
  2133. * Erase from current display position to bottom of render RECT.
  2134. * Used by tables for last line in a display
  2135. */
  2136. void CRenderer::EraseToBottom()
  2137. {
  2138. if(_ptCur.v < _rcRender.bottom)
  2139. {
  2140. RECTUV rcErase = _rcRender;
  2141. rcErase.top = _ptCur.v;
  2142. EraseTextOut(GetDC(), &rcErase);
  2143. }
  2144. }
  2145. /*
  2146. * CRenderer::RenderOutlineSymbol()
  2147. *
  2148. * @mfunc
  2149. * Render outline symbol for current paragraph
  2150. *
  2151. * @rdesc
  2152. * TRUE if outline symbol rendered
  2153. */
  2154. BOOL CRenderer::RenderOutlineSymbol()
  2155. {
  2156. AssertSz(IsInOutlineView(),
  2157. "CRenderer::RenderOutlineSymbol called when not in outline view");
  2158. HBITMAP hbitmap;
  2159. LONG height;
  2160. LONG width;
  2161. LONG up = _ptCur.u - _li._upStart + LUtoDU(lDefaultTab/2 * _pPF->_bOutlineLevel);
  2162. LONG vp = _ptCur.v;
  2163. if(!g_hbitmapSubtext && InitializeOutlineBitmaps() != NOERROR)
  2164. return FALSE;
  2165. HDC hMemDC = CreateCompatibleDC(_hdc); // REVIEW: performance
  2166. if(!hMemDC)
  2167. return FALSE; //REVIEW: out of memory
  2168. if(_pPF->_bOutlineLevel & 1) // Subtext
  2169. {
  2170. width = BITMAP_WIDTH_SUBTEXT;
  2171. height = BITMAP_HEIGHT_SUBTEXT;
  2172. hbitmap = g_hbitmapSubtext;
  2173. }
  2174. else // Heading
  2175. {
  2176. width = BITMAP_WIDTH_HEADING;
  2177. height = BITMAP_HEIGHT_HEADING;
  2178. hbitmap = g_hbitmapEmptyHeading;
  2179. CPFRunPtr rp(*this); // Check next PF for other
  2180. LONG cch = _li._cch; // outline symbols
  2181. if(_li._cch < rp.GetCchLeft()) // Set cch = count to heading
  2182. { // EOP
  2183. CTxtPtr tp(_rpTX);
  2184. cch = tp.FindEOP(tomForward);
  2185. }
  2186. rp.Move(cch); // Go to next paragraph
  2187. if(rp.IsCollapsed())
  2188. hbitmap = g_hbitmapCollapsedHeading;
  2189. else if(_pPF->_bOutlineLevel < rp.GetOutlineLevel())
  2190. hbitmap = g_hbitmapExpandedHeading;
  2191. }
  2192. if(!hbitmap)
  2193. return FALSE;
  2194. HBITMAP hbitmapDefault = (HBITMAP)SelectObject(hMemDC, hbitmap);
  2195. // REVIEW: what if the background color changes? Also, use a TT font
  2196. // for symbols
  2197. LONG dvpSymbol = _pdp->Zoom(height);
  2198. LONG dvp = _li._dvpHeight - _li._dvpDescent - dvpSymbol;
  2199. if(dvp > 0)
  2200. dvp /= 2;
  2201. else
  2202. dvp = -dvp;
  2203. POINTUV ptuv = {up, vp + dvp};
  2204. POINT pt;
  2205. _pdp->PointFromPointuv(pt, ptuv);
  2206. StretchBlt(_hdc, pt.x, pt.y, _pdp->Zoom(width), dvpSymbol, hMemDC, 0, 0, width, height, SRCCOPY);
  2207. SelectObject(hMemDC, hbitmapDefault);
  2208. DeleteDC(hMemDC);
  2209. return TRUE;
  2210. }
  2211. /*
  2212. * CRenderer::RenderBullet()
  2213. *
  2214. * @mfunc
  2215. * Render bullet at start of line
  2216. *
  2217. * @rdesc
  2218. * TRUE if this method succeeded
  2219. */
  2220. BOOL CRenderer::RenderBullet()
  2221. {
  2222. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CRenderer::RenderBullet");
  2223. AssertSz(_pPF->_wNumbering,
  2224. "CRenderer::RenderBullet called for non-bullet");
  2225. // Width of the bullet character
  2226. LONG dup;
  2227. // FUTURE: Unicode bullet is L'\x2022' We want to migrate to this and
  2228. // other bullets
  2229. LONG cch;
  2230. CCharFormat CF;
  2231. WCHAR szBullet[CCHMAXNUMTOSTR];
  2232. CCcs *pccs = GetCcsBullet(&CF);
  2233. if(!pccs) // Bullet is suppressed because
  2234. return TRUE; // preceding EOP is VT
  2235. if(_pccs)
  2236. _pccs->Release();
  2237. _pccs = pccs;
  2238. // Default to no underline
  2239. _bUnderlineType = CFU_UNDERLINENONE;
  2240. if(_pPF->IsListNumbered() && CF._dwEffects & CFE_UNDERLINE)
  2241. SetupUnderline(CF._bUnderlineType, CF._bUnderlineColor);
  2242. SetFontAndColor(&CF);
  2243. LONG dupLineSave = _dupLine;
  2244. LONG dupOffset = LUtoDU(_pPF->_wNumberingTab ? _pPF->_wNumberingTab : _pPF->_dxOffset);
  2245. LONG upSave = _ptCur.u;
  2246. // Set-up to render bullet in one chunk
  2247. cch = GetBullet(szBullet, _pccs, &dup);
  2248. dupOffset = max(dupOffset, dup);
  2249. _dupLine = dupOffset;
  2250. if(IsInOutlineView())
  2251. dupOffset = _li._upStart - LUtoDU(lDefaultTab/2 * (_pPF->_bOutlineLevel + 1));
  2252. _ptCur.u -= dupOffset;
  2253. switch(_pPF->_wNumberingStyle & 3)
  2254. {
  2255. case tomAlignCenter:
  2256. dup /= 2; // Fall thru to tomAlignRight
  2257. case tomAlignRight:
  2258. _ptCur.u -= dup;
  2259. }
  2260. // Render bullet
  2261. _fLastChunk = TRUE;
  2262. RenderText(szBullet, cch);
  2263. // Restore render vars to continue with remainder of line.
  2264. _ptCur.u = upSave;
  2265. _dupLine = dupLineSave;
  2266. _li._dup = 0;
  2267. // This releases the _pccs that we put in for the bullet
  2268. SetNewFont();
  2269. return TRUE;
  2270. }
  2271. /*
  2272. * CRenderer::DrawLine(ptStart, ptEnd)
  2273. *
  2274. * @mfunc
  2275. * Rotate the points passed and then call the OS.
  2276. */
  2277. void CRenderer::DrawLine(const POINTUV &ptStart, const POINTUV &ptEnd)
  2278. {
  2279. POINT rgpt[2];
  2280. _pdp->PointFromPointuv(rgpt[0], ptStart);
  2281. _pdp->PointFromPointuv(rgpt[1], ptEnd);
  2282. Polyline(_hdc, rgpt, 2);
  2283. }
  2284. /*
  2285. * CRenderer::RenderUnderline(upStart, vpStart, dup, dvp)
  2286. *
  2287. * @mfunc
  2288. * Render underline
  2289. */
  2290. void CRenderer::RenderUnderline(
  2291. LONG upStart, //@parm Horizontal start of underline
  2292. LONG vpStart, //@parm Vertical start of underline
  2293. LONG dup, //@parm Length of underline
  2294. LONG dvp) //@parm Thickness of underline
  2295. {
  2296. BOOL fUseLS = fUseLineServices();
  2297. COLORREF crUnderline = _crUnderlineClr;
  2298. RECTUV rcT, rcIntersection;
  2299. rcT.top = vpStart;
  2300. rcT.bottom = vpStart + dvp;
  2301. rcT.left = upStart;
  2302. rcT.right = upStart + dup;
  2303. if (!IntersectRect((RECT*)&rcIntersection, (RECT*)&_rcRender, (RECT*)&rcT))
  2304. return; // Underline not inside rc, forget it.
  2305. upStart = rcIntersection.left;
  2306. dup = rcIntersection.right - rcIntersection.left;
  2307. vpStart = rcIntersection.top;
  2308. dvp = rcIntersection.bottom - rcIntersection.top;
  2309. if (crUnderline == tomAutoColor || crUnderline == tomUndefined)
  2310. {
  2311. crUnderline = _crCurTextColor;
  2312. }
  2313. if (_bUnderlineType != CFU_INVERT &&
  2314. !IN_RANGE(CFU_UNDERLINEDOTTED, _bUnderlineType, CFU_UNDERLINEWAVE) &&
  2315. !IN_RANGE(CFU_UNDERLINEDOUBLEWAVE, _bUnderlineType, CFU_UNDERLINETHICKLONGDASH))
  2316. {
  2317. // Regular single underline case
  2318. // Calculate where to put underline
  2319. rcT.top = vpStart;
  2320. if (CFU_UNDERLINETHICK == _bUnderlineType)
  2321. {
  2322. if (rcT.top > _rcRender.top + dvp)
  2323. {
  2324. rcT.top -= dvp;
  2325. dvp += dvp;
  2326. }
  2327. }
  2328. // There are some cases were the following can occur - particularly
  2329. // with bullets on Japanese systems.
  2330. if(!fUseLS && rcT.top >= _ptCur.v + _li._dvpHeight)
  2331. rcT.top = _ptCur.v + _li._dvpHeight - dvp;
  2332. rcT.bottom = rcT.top + dvp;
  2333. rcT.left = upStart;
  2334. rcT.right = upStart + dup;
  2335. FillRectWithColor(&rcT, crUnderline);
  2336. return;
  2337. }
  2338. if(_bUnderlineType == CFU_INVERT) // Fake selection.
  2339. { // NOTE, not really
  2340. rcT.top = _ptCur.v; // how we should invert text!!
  2341. rcT.left = upStart; // check out IME invert.
  2342. rcT.bottom = rcT.top + _li._dvpHeight - _li._dvpDescent + _pccs->_yDescent;
  2343. rcT.right = rcT.left + dup;
  2344. RECT rc;
  2345. _pdp->RectFromRectuv(rc, rcT);
  2346. InvertRect(_hdc, &rc);
  2347. return;
  2348. }
  2349. if(IN_RANGE(CFU_UNDERLINEDOTTED, _bUnderlineType, CFU_UNDERLINEWAVE) ||
  2350. IN_RANGE(CFU_UNDERLINEDOUBLEWAVE, _bUnderlineType, CFU_UNDERLINETHICKLONGDASH))
  2351. {
  2352. static const char pen[] = {PS_DOT, PS_DASH, PS_DASHDOT, PS_DASHDOTDOT, PS_SOLID,
  2353. PS_SOLID, PS_SOLID, PS_SOLID, PS_SOLID, PS_DASH, PS_DASH,
  2354. PS_DASHDOT, PS_DASHDOTDOT, PS_DOT, PS_DASHDOT};
  2355. HPEN hPen = CreatePen(pen[_bUnderlineType - CFU_UNDERLINEDOTTED], 1, crUnderline);
  2356. if(hPen)
  2357. {
  2358. HPEN hPenOld = SelectPen(_hdc, hPen);
  2359. LONG upEnd = upStart + dup;
  2360. POINTUV ptStart, ptEnd;
  2361. ptStart.u = upStart;
  2362. ptStart.v = vpStart;
  2363. if((_bUnderlineType == CFU_UNDERLINEWAVE) ||
  2364. (_bUnderlineType == CFU_UNDERLINEDOUBLEWAVE) ||
  2365. (_bUnderlineType == CFU_UNDERLINEHEAVYWAVE))
  2366. {
  2367. LONG dv = 1; // Vertical displacement
  2368. LONG u = upStart + 1; // u coordinate
  2369. upEnd++; // Round up rightmost u
  2370. for( ; u < upEnd; dv = -dv, u += 2)
  2371. {
  2372. ptEnd.u = u;
  2373. ptEnd.v = vpStart + dv;
  2374. DrawLine(ptStart, ptEnd);
  2375. ptStart = ptEnd;
  2376. }
  2377. }
  2378. else
  2379. {
  2380. ptEnd.u = upEnd;
  2381. ptEnd.v = vpStart;
  2382. DrawLine(ptStart, ptEnd);
  2383. }
  2384. if(hPenOld) // Restore original pen.
  2385. SelectPen(_hdc, hPenOld);
  2386. DeleteObject(hPen);
  2387. }
  2388. }
  2389. }
  2390. /*
  2391. * CRenderer::RenderStrikeOut(upStart, vpStart, dup, dvp)
  2392. *
  2393. * @mfunc
  2394. * Render strikeout
  2395. */
  2396. void CRenderer::RenderStrikeOut(
  2397. LONG upStart, //@parm start of strikeout
  2398. LONG vpStart, //@parm start of strikeout
  2399. LONG dup, //@parm Length of strikeout
  2400. LONG dvp) //@parm Thickness of strikeout
  2401. {
  2402. RECTUV rcT, rcIntersection;
  2403. // Calculate where to put strikeout rectangle
  2404. rcT.top = vpStart;
  2405. rcT.bottom = vpStart + dvp;
  2406. rcT.left = upStart;
  2407. rcT.right = upStart + dup;
  2408. if (!IntersectRect((RECT*)&rcIntersection, (RECT*)&_rcRender, (RECT*)&rcT))
  2409. return; // Line not inside rc, forget it.
  2410. FillRectWithColor(&rcIntersection, GetTextColor(GetCF()));
  2411. }
  2412. /*
  2413. * CRenderer::FillRectWithTextColor(prc, cr)
  2414. *
  2415. * @mfunc
  2416. * Fill input rectangle with current color of text
  2417. */
  2418. void CRenderer::FillRectWithColor(
  2419. const RECTUV * prc, //@parm Rectangle to fill with color
  2420. COLORREF cr) //@parm Color to use
  2421. {
  2422. // Create a brush with the text color
  2423. HBRUSH hbrush = CreateSolidBrush(_fDisabled ? _crForeDisabled : cr);
  2424. // Note if the CreateSolidBrush fails we just ignore it since there
  2425. // isn't anything we can do about it anyway.
  2426. if(hbrush)
  2427. {
  2428. // Save old brush
  2429. HBRUSH hbrushOld = (HBRUSH)SelectObject(_hdc, hbrush);
  2430. // Fill rectangle for underline
  2431. RECT rc;
  2432. _pdp->RectFromRectuv(rc, *prc);
  2433. PatBlt(_hdc, rc.left, rc.top, rc.right - rc.left,
  2434. rc.bottom - rc.top, PATCOPY);
  2435. SelectObject(_hdc, hbrushOld); // Put old brush back
  2436. DeleteObject(hbrush); // Free brush we created.
  2437. }
  2438. }