Leaked source code of windows server 2003
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.

2263 lines
68 KiB

  1. /**************************************************************************\
  2. *
  3. * Copyright (c) 1998 Microsoft Corporation
  4. *
  5. * Abstract:
  6. *
  7. * Engine text out routines.
  8. *
  9. * Revision History:
  10. *
  11. * 3/25/1999 cameronb
  12. * Created it.
  13. *
  14. \**************************************************************************/
  15. #include "precomp.hpp"
  16. struct GlyphScanBuf
  17. {
  18. INT left;
  19. INT top;
  20. INT bottom;
  21. INT widthInBytes;
  22. DpRegion::Visibility visibility;
  23. };
  24. const BYTE GRAYSCALE_LEVEL = 16;
  25. /**************************************************************************\
  26. *
  27. * Function Description:
  28. *
  29. * Draws text at a position.
  30. *
  31. * Arguments:
  32. *
  33. * [IN] context - the context (matrix and clipping)
  34. * [IN] surface - the surface to fill
  35. * [IN] drawBounds - the surface bounds
  36. * [IN] text - the typeset text to be drawn
  37. * [IN] font - the font to use
  38. * [IN] fgBrush - the brush to use for the text
  39. * [IN] bgBrush - the brush to use for the background (default = NULL)
  40. *
  41. * Return Value:
  42. *
  43. * GpStatus - Ok or failure status
  44. *
  45. * Created:
  46. *
  47. * 3/25/1999 cameronb
  48. *
  49. \**************************************************************************/
  50. GpStatus
  51. DpDriver::DrawGlyphs
  52. (
  53. DrawGlyphData *drawGlyphData
  54. )
  55. {
  56. GpStatus status = GenericError;
  57. HDC hdc = NULL;
  58. ASSERT(!drawGlyphData->glyphPathPos);
  59. // Choose appropriate brush behaviour
  60. switch(drawGlyphData->brush->Type)
  61. {
  62. case BrushTypeSolidColor:
  63. INT angle; // Passed from GetTextOutputHdc to GdiText
  64. if (!(drawGlyphData->flags & DG_NOGDI))
  65. {
  66. hdc = drawGlyphData->context->GetTextOutputHdc(
  67. drawGlyphData->faceRealization,
  68. drawGlyphData->brush->SolidColor,
  69. drawGlyphData->surface,
  70. &angle
  71. );
  72. }
  73. if (hdc)
  74. {
  75. BOOL isClip;
  76. BOOL usePathClipping = FALSE;
  77. SetupClipping(hdc, drawGlyphData->context,
  78. drawGlyphData->drawBounds, isClip,
  79. usePathClipping, FALSE);
  80. status = GdiText(
  81. hdc,
  82. angle,
  83. drawGlyphData->glyphs,
  84. drawGlyphData->glyphOrigins,
  85. drawGlyphData->glyphCount,
  86. drawGlyphData->rightToLeft
  87. );
  88. RestoreClipping(hdc, isClip, usePathClipping);
  89. drawGlyphData->context->ReleaseTextOutputHdc(hdc);
  90. }
  91. else
  92. {
  93. status = SolidText(
  94. drawGlyphData->context,
  95. drawGlyphData->surface,
  96. drawGlyphData->drawBounds,
  97. drawGlyphData->brush->SolidColor,
  98. drawGlyphData->glyphPos,
  99. drawGlyphData->count,
  100. drawGlyphData->faceRealization->RealizationMethod(),
  101. drawGlyphData->rightToLeft
  102. );
  103. }
  104. break;
  105. // case BrushRectGrad:
  106. // case BrushRadialGrad:
  107. case BrushTypeTextureFill:
  108. case BrushTypeHatchFill:
  109. // case BrushTriangleGrad:
  110. case BrushTypePathGradient:
  111. case BrushTypeLinearGradient:
  112. status = BrushText(
  113. drawGlyphData->context,
  114. drawGlyphData->surface,
  115. drawGlyphData->drawBounds,
  116. drawGlyphData->brush,
  117. drawGlyphData->glyphPos,
  118. drawGlyphData->count,
  119. drawGlyphData->faceRealization->RealizationMethod()
  120. );
  121. break;
  122. default:
  123. status = GenericError;
  124. break;
  125. }
  126. return status;
  127. }
  128. static GpStatus
  129. OutputSolidNormalText (
  130. DpContext* context,
  131. DpDriver *driver,
  132. DpBitmap* surface,
  133. const GpRect* drawBounds,
  134. GpColor color,
  135. const GpGlyphPos *glyphPos,
  136. INT count
  137. )
  138. {
  139. DpScanBuffer scan(
  140. surface->Scan,
  141. driver,
  142. context,
  143. surface,
  144. (color.IsOpaque() &&
  145. (!context->AntiAliasMode)));
  146. if (!scan.IsValid())
  147. {
  148. return(GenericError);
  149. }
  150. FPUStateSaver fpuState;
  151. ARGB argb = color.GetPremultipliedValue();
  152. DpOutputSolidColorSpan outputSolid(argb, &scan);
  153. DpClipRegion * clipRegion = NULL;
  154. if (context->VisibleClip.GetRectVisibility(
  155. drawBounds->X, drawBounds->Y,
  156. drawBounds->GetRight(), drawBounds->GetBottom()) !=
  157. DpRegion::TotallyVisible)
  158. {
  159. clipRegion = &(context->VisibleClip);
  160. clipRegion->InitClipping(&outputSolid, drawBounds->Y);
  161. }
  162. for (int i = 0; i < count; i++)
  163. {
  164. INT left = glyphPos[i].GetLeft();
  165. INT top = glyphPos[i].GetTop();
  166. #if 0
  167. printf("Drawing glyph at [%d,%d]\n", left, top);
  168. #endif
  169. INT widthInPixels = glyphPos[i].GetWidth();
  170. INT right = left + widthInPixels;
  171. INT height = glyphPos[i].GetHeight();
  172. INT bottom = top + height;
  173. INT widthInBytes = (widthInPixels + 7) / 8;
  174. const BYTE* mask = glyphPos[i].GetBits();
  175. if (widthInPixels == 0 || height == 0)
  176. continue;
  177. ASSERT(mask != NULL);
  178. if (clipRegion != NULL)
  179. {
  180. // Clipping
  181. GpRect clippedRect;
  182. DpRegion::Visibility visibility =
  183. clipRegion->GetRectVisibility(
  184. left, top, right, bottom, &clippedRect
  185. );
  186. if (visibility == DpRegion::Invisible)
  187. continue;
  188. for (INT y = top, my = 0; y < bottom && my < height; y++, my++)
  189. {
  190. const BYTE* maskPtr = mask + my * widthInBytes;
  191. BYTE bit = 0x80;
  192. BYTE nextPixel = (*(maskPtr) & bit) ? 255 : 0;
  193. INT runStart = 0;
  194. for (INT mx = 0; mx < widthInPixels; mx++)
  195. {
  196. BYTE pixel = nextPixel;
  197. bit = (bit == 0x01) ? 0x80 : bit >> 1;
  198. nextPixel = (mx == widthInPixels - 1)
  199. ? 0
  200. : ( (*(maskPtr + (mx + 1) / 8) & bit) ? 255 : 0);
  201. if (pixel != nextPixel)
  202. {
  203. if (pixel)
  204. {
  205. // Draw this run
  206. INT runLength = mx - runStart + 1;
  207. INT from = left + runStart;
  208. if (visibility == DpRegion::TotallyVisible)
  209. {
  210. // Draw the entire run
  211. FillMemoryInt32( scan.NextBuffer(from, y, runLength),
  212. runLength, argb);
  213. }
  214. else
  215. {
  216. // Clip the run
  217. INT to = from + runLength; // reference needed
  218. clipRegion->OutputSpan(y, from, to);
  219. }
  220. };
  221. if (nextPixel)
  222. {
  223. // Start a new run
  224. runStart = mx + 1;
  225. }
  226. }
  227. }
  228. }
  229. }
  230. else
  231. {
  232. // No clipping
  233. for (INT y = top, my = 0; y < bottom && my < height; y++, my++)
  234. {
  235. const BYTE* maskPtr = mask + my * widthInBytes;
  236. BYTE bit = 0x80;
  237. INT runLength = 0;
  238. INT runStart;
  239. for (INT mx = 0; mx < widthInPixels; mx++)
  240. {
  241. BOOL pixelOn = *(maskPtr + mx / 8) & bit;
  242. if (pixelOn)
  243. {
  244. if (runLength == 0)
  245. {
  246. // Start a new run
  247. runStart = mx;
  248. }
  249. runLength++;
  250. }
  251. if
  252. (
  253. runLength > 0 && !pixelOn
  254. ||
  255. runLength > 0 && mx == widthInPixels - 1
  256. )
  257. {
  258. // Finish this run and draw it
  259. FillMemoryInt32(
  260. scan.NextBuffer(left + runStart, y, runLength),
  261. runLength, argb
  262. );
  263. runLength = 0;
  264. };
  265. bit = (bit == 0x01) ? 0x80 : bit >> 1;
  266. }
  267. }
  268. }
  269. }
  270. if (clipRegion != NULL)
  271. {
  272. clipRegion->EndClipping();
  273. }
  274. return(Ok);
  275. }
  276. static inline
  277. VOID GetGlyphDimensions(
  278. const GpGlyphPos & glyphPos,
  279. INT * left,
  280. INT * top,
  281. INT * widthInPixels,
  282. INT * right,
  283. INT * height,
  284. INT * bottom
  285. )
  286. {
  287. *left = glyphPos.GetLeft();
  288. *top = glyphPos.GetTop();
  289. *widthInPixels = glyphPos.GetWidth();
  290. *right = *left + *widthInPixels;
  291. *height = glyphPos.GetHeight();
  292. *bottom = *top + *height;
  293. } // GetGlyphDimensions
  294. template <typename MASKTYPE>
  295. class DpOutputOptimizedSpan : public DpOutputSpan
  296. {
  297. public:
  298. typedef MASKTYPE SCANMASKTYPE;
  299. DpOutputOptimizedSpan(DpScanBuffer * scan)
  300. : Scan(scan)
  301. {}
  302. virtual BOOL IsValid() const
  303. {
  304. return TRUE;
  305. }
  306. void SetMaskAndLeft(const MASKTYPE * maskPtr, INT left)
  307. {
  308. ASSERT(maskPtr != 0);
  309. MaskPtr = maskPtr;
  310. Left = left;
  311. }
  312. protected:
  313. DpScanBuffer * Scan;
  314. INT Left;
  315. const MASKTYPE *MaskPtr;
  316. };
  317. template <class OUTPUT_SPAN>
  318. static GpStatus
  319. OutputTextOptimized(
  320. DpContext* context,
  321. const GpRect* drawBounds,
  322. const GpGlyphPos *glyphPos,
  323. INT count,
  324. OUTPUT_SPAN & outputSpan
  325. )
  326. {
  327. ASSERT(context->CompositingMode == CompositingModeSourceOver);
  328. DpClipRegion * clipRegion = &(context->VisibleClip);
  329. clipRegion->InitClipping(&outputSpan, drawBounds->Y);
  330. // measure bounding box for all glyphs
  331. INT minX = INT_MAX, maxX = INT_MIN, minY = INT_MAX, maxY = INT_MIN;
  332. for (INT i = 0; i < count; ++i)
  333. {
  334. INT left, top, widthInPixels, right, height, bottom;
  335. GetGlyphDimensions(glyphPos[i], &left, &top, &widthInPixels, &right, &height, &bottom);
  336. if (widthInPixels == 0 ||
  337. height == 0 ||
  338. clipRegion->GetRectVisibility(left, top, right, bottom) ==
  339. DpRegion::Invisible)
  340. continue;
  341. if (left < minX) minX = left;
  342. if (top < minY) minY = top;
  343. if (right > maxX) maxX = right;
  344. if (bottom > maxY) maxY = bottom;
  345. }
  346. ASSERT(drawBounds->GetLeft() <= minX);
  347. ASSERT(drawBounds->GetTop() <= minY);
  348. ASSERT(drawBounds->GetRight() >= maxX);
  349. ASSERT(drawBounds->GetBottom() >= maxY);
  350. if (minX >= maxX || minY >= maxY)
  351. return Ok;
  352. AutoArray<OUTPUT_SPAN::SCANMASKTYPE> scanLine(new OUTPUT_SPAN::SCANMASKTYPE[maxX - minX]);
  353. if (!scanLine)
  354. return OutOfMemory;
  355. outputSpan.SetMaskAndLeft(scanLine.Get(), minX);
  356. for (INT line = minY; line < maxY; ++line)
  357. {
  358. GpMemset(scanLine.Get(), 0, (maxX - minX) * sizeof(OUTPUT_SPAN::SCANMASKTYPE));
  359. for (INT i = 0; i < count; ++i)
  360. {
  361. INT left, top, widthInPixels, right, height, bottom;
  362. GetGlyphDimensions(glyphPos[i], &left, &top, &widthInPixels, &right, &height, &bottom);
  363. if (widthInPixels == 0 ||
  364. height == 0 ||
  365. top > line ||
  366. line >= bottom ||
  367. clipRegion->GetRectVisibility(left, top, right, bottom) ==
  368. DpRegion::Invisible)
  369. continue; // is the last check necessary? [mleonov]
  370. // now, render glyph into the horizontal merge buffer
  371. outputSpan.RenderGlyph(
  372. glyphPos[i].GetBits(),
  373. &scanLine[left-minX],
  374. widthInPixels,
  375. line - top
  376. );
  377. }
  378. // now, clip and render scan line
  379. clipRegion->OutputSpan(line, minX, maxX);
  380. }
  381. clipRegion->EndClipping();
  382. return Ok;
  383. } // OutputTextOptimized
  384. class DpOutputSolidColorOptimizedSpan : public DpOutputOptimizedSpan<ARGB>
  385. {
  386. typedef DpOutputOptimizedSpan<ARGB> super;
  387. public:
  388. DpOutputSolidColorOptimizedSpan(DpScanBuffer * scan, ARGB argb)
  389. : super(scan), Argb(argb)
  390. {}
  391. virtual GpStatus OutputSpan(INT y, INT xMin, INT xMax)
  392. {
  393. INT width = xMax - xMin;
  394. const ARGB * maskPtr = MaskPtr + xMin - Left;
  395. ARGB * buf = Scan->NextBuffer(xMin, y, width);
  396. GpMemcpy(buf, maskPtr, width * sizeof(ARGB));
  397. return Ok;
  398. }
  399. void RenderGlyph(const BYTE * glyphBits,
  400. SCANMASKTYPE * dst,
  401. INT widthInPixels,
  402. INT y)
  403. {
  404. const INT widthInBytes = (widthInPixels + 7) / 8;
  405. const BYTE * mask = glyphBits + widthInBytes * y;
  406. for (INT pos = 0; pos < widthInPixels; ++dst, ++pos)
  407. {
  408. if (!*dst && (mask[pos>>3] & (0x80 >> (pos & 7))))
  409. *dst = Argb;
  410. }
  411. } // RenderGlyph
  412. protected:
  413. const ARGB Argb;
  414. }; // class DpOutputSolidColorOptimizedSpan
  415. static GpStatus
  416. OutputSolidNormalTextOptimized(
  417. DpContext* context,
  418. DpDriver *driver,
  419. DpBitmap* surface,
  420. const GpRect* drawBounds,
  421. const GpColor & color,
  422. const GpGlyphPos *glyphPos,
  423. INT count
  424. )
  425. {
  426. DpScanBuffer scan(surface->Scan, driver, context, surface);
  427. if (!scan.IsValid())
  428. return GenericError;
  429. DpOutputSolidColorOptimizedSpan outputSolid(&scan, color.GetPremultipliedValue());
  430. return OutputTextOptimized(context, drawBounds, glyphPos, count, outputSolid);
  431. } // OutputSolidNormalTextOptimized
  432. class DpOutputClearTypeOptimizedSpan : public DpOutputOptimizedSpan<BYTE>
  433. {
  434. typedef DpOutputOptimizedSpan<BYTE> super;
  435. public:
  436. DpOutputClearTypeOptimizedSpan(DpScanBuffer * scan)
  437. : super(scan)
  438. {}
  439. void RenderGlyph(const BYTE * glyphBits,
  440. SCANMASKTYPE * dst,
  441. INT widthInPixels,
  442. INT y)
  443. {
  444. const BYTE * mask = glyphBits + widthInPixels * y;
  445. for (INT pos = 0; pos < widthInPixels; ++pos, ++dst)
  446. {
  447. const BYTE src = mask[pos];
  448. ASSERT(0 <= *dst && *dst <= CT_LOOKUP - 1);
  449. ASSERT(0 <= src && src <= CT_LOOKUP - 1);
  450. if (*dst == 0)
  451. {
  452. *dst = src;
  453. }
  454. else if (src != 0)
  455. {
  456. // merge ClearType data
  457. ULONG kR = (ULONG)Globals::gaOutTable[*dst].kR + (ULONG)Globals::gaOutTable[src].kR;
  458. ULONG kG = (ULONG)Globals::gaOutTable[*dst].kG + (ULONG)Globals::gaOutTable[src].kG;
  459. ULONG kB = (ULONG)Globals::gaOutTable[*dst].kB + (ULONG)Globals::gaOutTable[src].kB;
  460. if (kR > CT_SAMPLE_F) {kR = CT_SAMPLE_F;}
  461. if (kG > CT_SAMPLE_F) {kG = CT_SAMPLE_F;}
  462. if (kB > CT_SAMPLE_F) {kB = CT_SAMPLE_F;}
  463. *dst = Globals::FilteredCTLut[kB + 7 * kG + 49 * kR];
  464. }
  465. }
  466. } // RenderGlyph
  467. }; // class DpOutputClearTypeOptimizedSpan
  468. class DpOutputClearTypeSolidOptimizedSpan : public DpOutputClearTypeOptimizedSpan
  469. {
  470. typedef DpOutputClearTypeOptimizedSpan super;
  471. public:
  472. DpOutputClearTypeSolidOptimizedSpan(DpScanBuffer * scan)
  473. : super(scan)
  474. {}
  475. virtual GpStatus OutputSpan(INT y, INT xMin, INT xMax)
  476. {
  477. const INT width = xMax - xMin;
  478. const BYTE * maskPtr = MaskPtr + xMin - Left;
  479. Scan->NextBuffer(xMin, y, width);
  480. BYTE * buf = reinterpret_cast<BYTE *>(Scan->GetCurrentCTBuffer());
  481. for (INT i = 0; i < width; ++i)
  482. {
  483. ASSERT(0 <= *maskPtr && *maskPtr <= CT_LOOKUP - 1);
  484. *buf = *maskPtr;
  485. ++buf;
  486. ++maskPtr;
  487. }
  488. return Ok;
  489. }
  490. }; // class DpOutputClearTypeSolidOptimizedSpan
  491. class DpOutputClearTypeBrushOptimizedSpan : public DpOutputClearTypeOptimizedSpan
  492. {
  493. typedef DpOutputClearTypeOptimizedSpan super;
  494. public:
  495. DpOutputClearTypeBrushOptimizedSpan(DpScanBuffer * scan, DpOutputSpan * output)
  496. : super(scan), Output(output)
  497. {}
  498. virtual GpStatus OutputSpan(INT y, INT xMin, INT xMax)
  499. {
  500. GpStatus status = Output->OutputSpan(y, xMin, xMax);
  501. if (status != Ok)
  502. return status;
  503. const INT width = xMax - xMin;
  504. const BYTE * maskPtr = MaskPtr + xMin - Left;
  505. BYTE * buf = reinterpret_cast<BYTE *>(Scan->GetCurrentCTBuffer());
  506. for (INT i = 0; i < width; ++i)
  507. {
  508. ASSERT(0 <= *maskPtr && *maskPtr <= CT_LOOKUP - 1);
  509. *buf = *maskPtr;
  510. ++buf;
  511. ++maskPtr;
  512. }
  513. return Ok;
  514. }
  515. protected:
  516. DpOutputSpan * Output;
  517. }; // class DpOutputClearTypeBrushOptimizedSpan
  518. static GpStatus
  519. OutputBrushClearTypeText(
  520. DpContext* context,
  521. DpDriver *driver,
  522. DpBitmap* surface,
  523. const GpRect* drawBounds,
  524. const DpBrush * brush,
  525. const GpGlyphPos *glyphPos,
  526. INT count
  527. )
  528. {
  529. DpScanBuffer scan(
  530. surface->Scan,
  531. driver,
  532. context,
  533. surface,
  534. FALSE,
  535. EpScanTypeCT);
  536. if (!scan.IsValid())
  537. {
  538. return GenericError;
  539. }
  540. AutoPointer<DpOutputSpan> output(DpOutputSpan::Create(brush, &scan, context));
  541. if (!output)
  542. return OutOfMemory;
  543. DpOutputClearTypeBrushOptimizedSpan outputCTSpan(&scan, output.Get());
  544. return OutputTextOptimized(context, drawBounds, glyphPos, count, outputCTSpan);
  545. } // OutputBrushClearTypeText
  546. static GpStatus
  547. OutputSolidClearTypeText(
  548. DpContext* context,
  549. DpDriver *driver,
  550. DpBitmap* surface,
  551. const GpRect* drawBounds,
  552. GpColor color,
  553. const GpGlyphPos *glyphPos,
  554. INT count
  555. )
  556. {
  557. DpScanBuffer scan(
  558. surface->Scan,
  559. driver,
  560. context,
  561. surface,
  562. FALSE,
  563. EpScanTypeCTSolidFill,
  564. PixelFormat32bppPARGB,
  565. PixelFormat32bppPARGB,
  566. color.GetValue());
  567. if (!scan.IsValid())
  568. {
  569. return GenericError;
  570. }
  571. DpOutputClearTypeSolidOptimizedSpan outputCTSpan(&scan);
  572. return OutputTextOptimized(context, drawBounds, glyphPos, count, outputCTSpan);
  573. } // OutputSolidClearTypeText
  574. class DpOutputAntiAliasSolidColorOptimizedSpan : public DpOutputOptimizedSpan<BYTE>
  575. {
  576. typedef DpOutputOptimizedSpan<BYTE> super;
  577. public:
  578. DpOutputAntiAliasSolidColorOptimizedSpan(DpScanBuffer * scan, const GpColor & color, ULONG gammaValue)
  579. : super(scan)
  580. {
  581. TextGammaTable.CreateTextColorGammaTable(&color, gammaValue, GRAYSCALE_LEVEL);
  582. }
  583. virtual GpStatus OutputSpan(INT y, INT xMin, INT xMax)
  584. {
  585. INT width = xMax - xMin;
  586. const BYTE * maskPtr = MaskPtr + xMin - Left;
  587. ARGB * buf = Scan->NextBuffer(xMin, y, width);
  588. for (ARGB * cur = buf; cur < buf + width; ++cur, ++maskPtr)
  589. {
  590. if (*maskPtr)
  591. *cur = TextGammaTable.argb[*maskPtr];
  592. else
  593. *cur = 0;
  594. }
  595. return Ok;
  596. }
  597. protected:
  598. TextColorGammaTable TextGammaTable;
  599. BYTE MergeGrayscale(BYTE src, BYTE dst)
  600. {
  601. return max(src, dst);
  602. /* how do we correctly merge overlapping antialiased glyphs?
  603. we need to know if subpixels come from the same glyph
  604. UINT res = src + dst;
  605. if (res >= GsLevel)
  606. return GsLevel - 1;
  607. return (BYTE)res;
  608. */
  609. } // MergeGrayscale
  610. }; // class DpOutputAntiAliasSolidColorOptimizedSpan
  611. class DpOutputAntiAliasSolid8BPPOptimizedSpan : public DpOutputAntiAliasSolidColorOptimizedSpan
  612. {
  613. typedef DpOutputAntiAliasSolidColorOptimizedSpan super;
  614. public:
  615. DpOutputAntiAliasSolid8BPPOptimizedSpan(DpScanBuffer * scan, const GpColor & color, ULONG gammaValue)
  616. : super(scan, color, gammaValue)
  617. {}
  618. void RenderGlyph(const BYTE * glyphBits,
  619. SCANMASKTYPE * dst,
  620. INT widthInPixels,
  621. INT y)
  622. {
  623. const BYTE * mask = glyphBits + widthInPixels * y;
  624. for (INT pos = 0; pos < widthInPixels; ++pos, ++dst)
  625. {
  626. *dst = MergeGrayscale(*dst, mask[pos]);
  627. }
  628. } // RenderGlyph
  629. }; // class DpOutputAntiAliasSolid8BPPOptimizedSpan
  630. class DpOutputAntiAliasSolid4BPPOptimizedSpan : public DpOutputAntiAliasSolidColorOptimizedSpan
  631. {
  632. typedef DpOutputAntiAliasSolidColorOptimizedSpan super;
  633. public:
  634. DpOutputAntiAliasSolid4BPPOptimizedSpan(DpScanBuffer * scan, const GpColor & color, ULONG gammaValue)
  635. : super(scan, color, gammaValue)
  636. {}
  637. void RenderGlyph(const BYTE * glyphBits,
  638. SCANMASKTYPE * dst,
  639. INT widthInPixels,
  640. INT y)
  641. {
  642. const INT widthInBytes = (widthInPixels + 1) / 2;
  643. const BYTE * mask = glyphBits + widthInBytes * y;
  644. for (INT pos = 0; pos < widthInPixels; ++dst, ++pos)
  645. {
  646. BYTE value = mask[pos / 2];
  647. value >>= 4 * ((pos + 1) & 1);
  648. value &= 0x0F;
  649. *dst = MergeGrayscale(*dst, value);
  650. }
  651. } // RenderGlyph
  652. }; // class DpOutputAntiAliasSolid4BPPOptimizedSpan
  653. static GpStatus
  654. OutputSolidAntiAliasText8BPPOptimized(
  655. DpContext* context,
  656. DpDriver * driver,
  657. DpBitmap* surface,
  658. const GpRect* drawBounds,
  659. GpColor color,
  660. const GpGlyphPos *glyphPos,
  661. INT count
  662. )
  663. {
  664. DpScanBuffer scan(surface->Scan, driver, context, surface);
  665. if (!scan.IsValid())
  666. return GenericError;
  667. DpOutputAntiAliasSolid8BPPOptimizedSpan outputAASolid(&scan, color, context->TextContrast);
  668. return OutputTextOptimized(context, drawBounds, glyphPos, count, outputAASolid);
  669. } // OutputSolidAntiAliasText8BPPOptimized
  670. static GpStatus
  671. OutputSolidAntiAliasText4BPPOptimized(
  672. DpContext* context,
  673. DpDriver * driver,
  674. DpBitmap* surface,
  675. const GpRect* drawBounds,
  676. GpColor color,
  677. const GpGlyphPos *glyphPos,
  678. INT count
  679. )
  680. {
  681. DpScanBuffer scan(surface->Scan, driver, context, surface);
  682. if (!scan.IsValid())
  683. return GenericError;
  684. DpOutputAntiAliasSolid4BPPOptimizedSpan outputAASolid(&scan, color, context->TextContrast);
  685. return OutputTextOptimized(context, drawBounds, glyphPos, count, outputAASolid);
  686. } // OutputSolidAntiAliasText4BPPOptimized
  687. static GpStatus
  688. OutputSolidAntiAliasText8BPP (
  689. DpContext* context,
  690. DpDriver * driver,
  691. DpBitmap* surface,
  692. const GpRect* drawBounds,
  693. GpColor color,
  694. const GpGlyphPos *glyphPos,
  695. INT count
  696. )
  697. {
  698. INT i;
  699. DpScanBuffer scan(
  700. surface->Scan,
  701. driver,
  702. context,
  703. surface,
  704. FALSE);
  705. if (!scan.IsValid())
  706. {
  707. return(GenericError);
  708. }
  709. FPUStateSaver fpuState;
  710. DpOutputAntiAliasSolidColorSpan outputAASolid(color, &scan, context->TextContrast, GRAYSCALE_LEVEL);
  711. DpClipRegion * clipRegion = NULL;
  712. if (context->VisibleClip.GetRectVisibility(
  713. drawBounds->X, drawBounds->Y,
  714. drawBounds->GetRight(), drawBounds->GetBottom()) !=
  715. DpRegion::TotallyVisible)
  716. {
  717. clipRegion = &(context->VisibleClip);
  718. clipRegion->InitClipping(&outputAASolid, drawBounds->Y);
  719. }
  720. //////////////////////////////////////////////////////////////////////////////
  721. for (i = 0; i < count; i++)
  722. {
  723. INT left = glyphPos[i].GetLeft();
  724. INT top = glyphPos[i].GetTop();
  725. INT widthInPixels = glyphPos[i].GetWidth();
  726. INT right = left + widthInPixels;
  727. INT height = glyphPos[i].GetHeight();
  728. INT bottom = top + height;
  729. if (widthInPixels == 0 || height == 0)
  730. continue;
  731. INT widthInBytes = widthInPixels;
  732. const BYTE* mask = glyphPos[i].GetBits();
  733. ASSERT(mask != NULL);
  734. if (clipRegion != NULL)
  735. {
  736. // Clipping
  737. GpRect clippedRect;
  738. DpRegion::Visibility visibility =
  739. clipRegion->GetRectVisibility(
  740. left, top, right, bottom, &clippedRect
  741. );
  742. if (visibility == DpRegion::Invisible)
  743. continue;
  744. for (INT y = top, my = 0; y < bottom && my < height; y++, my++)
  745. {
  746. const BYTE* maskPtr = mask + my * widthInBytes;
  747. BYTE grayscaleValue = *maskPtr;
  748. INT runStart = 0;
  749. for (INT mx = 0; mx <= widthInPixels; mx++)
  750. {
  751. BYTE nextgrayscaleValue;
  752. if (mx == widthInPixels)
  753. {
  754. nextgrayscaleValue = 0;
  755. }
  756. else
  757. {
  758. nextgrayscaleValue = *maskPtr;
  759. maskPtr++;
  760. }
  761. if (grayscaleValue != nextgrayscaleValue)
  762. {
  763. if (grayscaleValue != 0)
  764. {
  765. // Draw this run
  766. INT runLength = mx - runStart;
  767. INT from = left + runStart;
  768. if (visibility == DpRegion::TotallyVisible)
  769. {
  770. // Draw the entire run
  771. FillMemoryInt32( scan.NextBuffer(from, y, runLength), runLength,
  772. outputAASolid.GetAASolidColor((ULONG) grayscaleValue));
  773. }
  774. else
  775. {
  776. // Clip the run
  777. INT to = from + runLength; // reference needed
  778. outputAASolid.GetAASolidColor((ULONG) grayscaleValue);
  779. clipRegion->OutputSpan(y, from, to);
  780. }
  781. // Start a new run
  782. runStart = mx;
  783. grayscaleValue = nextgrayscaleValue;
  784. }
  785. else
  786. {
  787. // Start a new run
  788. runStart = mx;
  789. grayscaleValue = nextgrayscaleValue;
  790. }
  791. }
  792. }
  793. }
  794. }
  795. else
  796. {
  797. ARGB * buf;
  798. // No clipping
  799. for (INT y = top, my = 0; y < bottom && my < height; y++, my++)
  800. {
  801. // Get the first byte in the scan line
  802. const BYTE* maskPtr = mask + my * widthInBytes;
  803. buf = scan.NextBuffer(left, y, widthInPixels);
  804. for (INT mx = 0; mx < widthInPixels; mx++)
  805. {
  806. *buf++ = outputAASolid.GetAASolidColor((ULONG) *maskPtr);
  807. maskPtr++;
  808. }
  809. }
  810. }
  811. }
  812. if (clipRegion != NULL)
  813. {
  814. clipRegion->EndClipping();
  815. }
  816. return(Ok);
  817. }
  818. static GpStatus
  819. OutputSolidAntiAliasText4BPP (
  820. DpContext* context,
  821. DpDriver * driver,
  822. DpBitmap* surface,
  823. const GpRect* drawBounds,
  824. GpColor color,
  825. const GpGlyphPos *glyphPos,
  826. INT count
  827. )
  828. {
  829. INT i;
  830. DpScanBuffer scan(
  831. surface->Scan,
  832. driver,
  833. context,
  834. surface,
  835. FALSE);
  836. if (!scan.IsValid())
  837. {
  838. return(GenericError);
  839. }
  840. FPUStateSaver fpuState;
  841. DpOutputAntiAliasSolidColorSpan outputAASolid(color, &scan, context->TextContrast, GRAYSCALE_LEVEL);
  842. DpClipRegion * clipRegion = NULL;
  843. if (context->VisibleClip.GetRectVisibility(
  844. drawBounds->X, drawBounds->Y,
  845. drawBounds->GetRight(), drawBounds->GetBottom()) !=
  846. DpRegion::TotallyVisible)
  847. {
  848. clipRegion = &(context->VisibleClip);
  849. clipRegion->InitClipping(&outputAASolid, drawBounds->Y);
  850. }
  851. //////////////////////////////////////////////////////////////////////////////
  852. for (i = 0; i < count; i++)
  853. {
  854. INT left = glyphPos[i].GetLeft();
  855. INT top = glyphPos[i].GetTop();
  856. INT widthInPixels = glyphPos[i].GetWidth();
  857. INT right = left + widthInPixels;
  858. INT height = glyphPos[i].GetHeight();
  859. INT bottom = top + height;
  860. if (widthInPixels == 0 || height == 0)
  861. continue;
  862. INT widthInBytes = ((widthInPixels + 1) / 2);
  863. const BYTE* mask = glyphPos[i].GetBits();
  864. ASSERT(mask != NULL);
  865. if (clipRegion != NULL)
  866. {
  867. // Clipping
  868. GpRect clippedRect;
  869. DpRegion::Visibility visibility =
  870. clipRegion->GetRectVisibility(
  871. left, top, right, bottom, &clippedRect
  872. );
  873. if (visibility == DpRegion::Invisible)
  874. continue;
  875. for (INT y = top, my = 0; y < bottom && my < height; y++, my++)
  876. {
  877. const BYTE* maskPtr = mask + my * widthInBytes;
  878. BYTE grayscaleValue = *maskPtr >> 4;
  879. INT runStart = 0;
  880. for (INT mx = 0; mx <= widthInPixels; mx++)
  881. {
  882. BYTE nextgrayscaleValue;
  883. if (mx == widthInPixels)
  884. {
  885. nextgrayscaleValue = 0;
  886. }
  887. else
  888. {
  889. if (mx % 2)
  890. {
  891. nextgrayscaleValue = *maskPtr & 0x0F;
  892. maskPtr++;
  893. }
  894. else
  895. {
  896. nextgrayscaleValue = *maskPtr >> 4;
  897. }
  898. }
  899. if (grayscaleValue != nextgrayscaleValue)
  900. {
  901. if (grayscaleValue != 0)
  902. {
  903. // Draw this run
  904. INT runLength = mx - runStart;
  905. INT from = left + runStart;
  906. if (visibility == DpRegion::TotallyVisible)
  907. {
  908. // Draw the entire run
  909. FillMemoryInt32( scan.NextBuffer(from, y, runLength), runLength,
  910. outputAASolid.GetAASolidColor((ULONG) grayscaleValue));
  911. }
  912. else
  913. {
  914. // Clip the run
  915. INT to = from + runLength; // reference needed
  916. outputAASolid.GetAASolidColor((ULONG) grayscaleValue);
  917. clipRegion->OutputSpan(y, from, to);
  918. }
  919. // Start a new run
  920. runStart = mx;
  921. grayscaleValue = nextgrayscaleValue;
  922. }
  923. else
  924. {
  925. // Start a new run
  926. runStart = mx;
  927. grayscaleValue = nextgrayscaleValue;
  928. }
  929. }
  930. }
  931. }
  932. }
  933. else
  934. {
  935. ARGB * buf;
  936. // No clipping
  937. for (INT y = top, my = 0; y < bottom && my < height; y++, my++)
  938. {
  939. // Get the first byte in the scan line
  940. const BYTE* maskPtr = mask + my * widthInBytes;
  941. buf = scan.NextBuffer(left, y, widthInPixels);
  942. for (INT mx = 0; mx < widthInPixels; mx++)
  943. {
  944. if (!(mx % 2))
  945. *buf++ = outputAASolid.GetAASolidColor((ULONG) (*maskPtr >> 4));
  946. else
  947. {
  948. *buf++ = outputAASolid.GetAASolidColor((ULONG) (*maskPtr & 0x0F));
  949. maskPtr++;
  950. }
  951. }
  952. }
  953. }
  954. }
  955. if (clipRegion != NULL)
  956. {
  957. clipRegion->EndClipping();
  958. }
  959. return(Ok);
  960. }
  961. /**************************************************************************\
  962. *
  963. * Function Description:
  964. *
  965. * Engine version of routine to draw solid text.
  966. *
  967. * Arguments:
  968. *
  969. * [IN] - DDI parameters.
  970. *
  971. * Return Value:
  972. *
  973. * TRUE if successful.
  974. *
  975. * History:
  976. *
  977. * 4/4/1999 cameronb
  978. * Created it.
  979. *
  980. \**************************************************************************/
  981. GpStatus
  982. DpDriver::SolidText(
  983. DpContext* context,
  984. DpBitmap* surface,
  985. const GpRect* drawBounds,
  986. GpColor color,
  987. const GpGlyphPos *glyphPos,
  988. INT count,
  989. TextRenderingHint textMode,
  990. BOOL rightToLeft
  991. )
  992. {
  993. ASSERT (textMode != TextRenderingHintSystemDefault);
  994. switch(textMode)
  995. {
  996. case TextRenderingHintSingleBitPerPixelGridFit:
  997. case TextRenderingHintSingleBitPerPixel:
  998. if (context->CompositingMode == CompositingModeSourceCopy)
  999. return OutputSolidNormalText(context, this, surface, drawBounds, color, glyphPos, count);
  1000. // we are allowed to output transparent pixels
  1001. // version with minimized number of scan records
  1002. return OutputSolidNormalTextOptimized(context, this, surface, drawBounds, color, glyphPos, count);
  1003. case TextRenderingHintAntiAlias:
  1004. if (context->CompositingMode == CompositingModeSourceCopy)
  1005. return OutputSolidAntiAliasText8BPP(context, this, surface, drawBounds, color, glyphPos, count);
  1006. return OutputSolidAntiAliasText8BPPOptimized(context, this, surface, drawBounds, color, glyphPos, count);
  1007. case TextRenderingHintAntiAliasGridFit:
  1008. if (context->CompositingMode == CompositingModeSourceCopy)
  1009. return OutputSolidAntiAliasText4BPP(context, this, surface, drawBounds, color, glyphPos, count);
  1010. return OutputSolidAntiAliasText4BPPOptimized(context, this, surface, drawBounds, color, glyphPos, count);
  1011. case TextRenderingHintClearTypeGridFit:
  1012. return OutputSolidClearTypeText(context, this, surface, drawBounds, color, glyphPos, count);
  1013. default:
  1014. break;
  1015. }
  1016. return Ok;
  1017. }
  1018. /**************************************************************************\
  1019. *
  1020. * Function Description:
  1021. *
  1022. * Engine version of routine to draw text based on a brush.
  1023. *
  1024. * Arguments:
  1025. *
  1026. * [IN] - DDI parameters.
  1027. *
  1028. * Return Value:
  1029. *
  1030. * TRUE if successful.
  1031. *
  1032. * History:
  1033. * 5-1-2000 YungT rewrite it.
  1034. * 2/7/2000 YungT modify it.
  1035. * 4/14/1999 cameronb
  1036. * Created it.
  1037. *
  1038. \**************************************************************************/
  1039. static GpStatus
  1040. OutputBrushNormalText(
  1041. DpContext* context,
  1042. DpDriver * driver,
  1043. DpBitmap* surface,
  1044. const GpRect* drawBounds,
  1045. const DpBrush* brush,
  1046. const GpGlyphPos* glyphPos,
  1047. INT count
  1048. )
  1049. {
  1050. DpScanBuffer scan(
  1051. surface->Scan,
  1052. driver,
  1053. context,
  1054. surface,
  1055. FALSE); // (color64.IsOpaque() &&
  1056. // (!context->AntiAliasMode)));
  1057. // !!! If you fix this, you'll get a perf improvement for
  1058. // text that has no transparency.
  1059. if (!scan.IsValid())
  1060. {
  1061. return(GenericError);
  1062. }
  1063. FPUStateSaver fpuState;
  1064. DpOutputSpan* output = DpOutputSpan::Create(brush, &scan, context);
  1065. if (output != NULL)
  1066. {
  1067. INT i;
  1068. INT my;
  1069. GlyphScanBuf glyphScanBuf[256], *pglyphScanBuf;
  1070. DpClipRegion* clipRegion = NULL;
  1071. INT topY = drawBounds->Y;
  1072. INT bottomY = drawBounds->GetBottom();
  1073. // Allocate enough space for glyph scan buffer
  1074. if (count < 256)
  1075. {
  1076. pglyphScanBuf = &glyphScanBuf[0];
  1077. }
  1078. else
  1079. {
  1080. pglyphScanBuf = (GlyphScanBuf *) GpMalloc(count * sizeof(GlyphScanBuf));
  1081. if (!pglyphScanBuf)
  1082. return (OutOfMemory);
  1083. }
  1084. if (context->VisibleClip.GetRectVisibility(drawBounds->X, topY, drawBounds->GetRight(),
  1085. bottomY) != DpRegion::TotallyVisible)
  1086. {
  1087. clipRegion = &(context->VisibleClip);
  1088. clipRegion->InitClipping(output, drawBounds->Y);
  1089. }
  1090. // Scan evrey Glyph and get the Visibility
  1091. // Also we cache some data we will need to for later computation
  1092. for (i = 0; i < count; i++)
  1093. {
  1094. GpRect clippedRect;
  1095. pglyphScanBuf[i].left = glyphPos[i].GetLeft();
  1096. pglyphScanBuf[i].top = glyphPos[i].GetTop();
  1097. pglyphScanBuf[i].widthInBytes = (glyphPos[i].GetWidth() + 7) / 8;
  1098. pglyphScanBuf[i].bottom = pglyphScanBuf[i].top + glyphPos[i].GetHeight();
  1099. // Set the glyph as invisible if it is empty.
  1100. if (glyphPos[i].GetWidth() == 0 || glyphPos[i].GetHeight() == 0)
  1101. pglyphScanBuf[i].visibility = DpRegion::Invisible;
  1102. else if (clipRegion != NULL)
  1103. pglyphScanBuf[i].visibility = clipRegion->GetRectVisibility(pglyphScanBuf[i].left,
  1104. pglyphScanBuf[i].top,
  1105. pglyphScanBuf[i].left + glyphPos[i].GetWidth(),
  1106. pglyphScanBuf[i].bottom, &clippedRect);
  1107. else
  1108. pglyphScanBuf[i].visibility = DpRegion::TotallyVisible;
  1109. }
  1110. // Start to scan from top of bounding box to bottom
  1111. for (int y = topY; y < bottomY; y++)
  1112. {
  1113. for (i = 0; i < count; i++)
  1114. {
  1115. const BYTE* maskPtr;
  1116. INT runLength, runStart;
  1117. INT from, to;
  1118. BYTE thisBit;
  1119. BYTE nextPixel;
  1120. BYTE pixel;
  1121. // Invisible glyph
  1122. if (pglyphScanBuf[i].visibility == DpRegion::Invisible)
  1123. {
  1124. continue;
  1125. }
  1126. // check the scan line with y.top and y.bottom
  1127. if (y < pglyphScanBuf[i].top || y >= pglyphScanBuf[i].bottom)
  1128. continue;
  1129. if (pglyphScanBuf[i].visibility != DpRegion::TotallyVisible)
  1130. {
  1131. // Get the relateive y-scan line for each glyph
  1132. my = y - pglyphScanBuf[i].top;
  1133. // Get the address of glyph bits
  1134. maskPtr = glyphPos[i].GetBits();
  1135. ASSERT(maskPtr != NULL);
  1136. maskPtr += my * pglyphScanBuf[i].widthInBytes;
  1137. thisBit = 0x80;
  1138. nextPixel = (*(maskPtr) & thisBit) ? 255 : 0;
  1139. runStart = 0;
  1140. for (INT mx = 0; mx < glyphPos[i].GetWidth(); mx++)
  1141. {
  1142. pixel = nextPixel;
  1143. thisBit = (thisBit == 0x01) ? 0x80 : thisBit >> 1;
  1144. nextPixel = (mx == glyphPos[i].GetWidth() - 1) ? 0 : ( (*(maskPtr + (mx + 1) / 8) & thisBit) ? 255 : 0);
  1145. if (pixel != nextPixel)
  1146. {
  1147. if (pixel)
  1148. {
  1149. // Draw this run
  1150. runLength = mx - runStart + 1;
  1151. // Clip the run
  1152. from = pglyphScanBuf[i].left + runStart;
  1153. to = from + runLength;
  1154. clipRegion->OutputSpan(y, from, to);
  1155. }
  1156. if (nextPixel)
  1157. {
  1158. // Start a new run
  1159. runStart = mx + 1;
  1160. }
  1161. }
  1162. }
  1163. }
  1164. else
  1165. {
  1166. my = y - pglyphScanBuf[i].top;
  1167. maskPtr = glyphPos[i].GetBits();
  1168. ASSERT(maskPtr != NULL);
  1169. maskPtr += my * pglyphScanBuf[i].widthInBytes;
  1170. thisBit = 0x80;
  1171. runLength = 0;
  1172. for (INT mx = 0; mx < glyphPos[i].GetWidth(); mx++)
  1173. {
  1174. BOOL pixelOn = *(maskPtr + mx / 8) & thisBit;
  1175. if (pixelOn)
  1176. {
  1177. if (runLength == 0)
  1178. {
  1179. // Start a new run
  1180. runStart = mx;
  1181. }
  1182. runLength++;
  1183. }
  1184. if (runLength > 0 && !pixelOn || runLength > 0 && mx == glyphPos[i].GetWidth() - 1)
  1185. {
  1186. // Finish this run and draw it
  1187. from = pglyphScanBuf[i].left + runStart;
  1188. to = from + runLength;
  1189. output->OutputSpan(y, from, to);
  1190. runLength = 0;
  1191. };
  1192. thisBit = (thisBit == 0x01) ? 0x80 : thisBit >> 1;
  1193. }
  1194. }
  1195. }
  1196. } // next scan line
  1197. if (clipRegion != NULL)
  1198. {
  1199. clipRegion->EndClipping();
  1200. }
  1201. delete output;
  1202. if (pglyphScanBuf != &glyphScanBuf[0])
  1203. GpFree(pglyphScanBuf);
  1204. }
  1205. return(Ok);
  1206. }
  1207. /**************************************************************************\
  1208. *
  1209. * Function Description:
  1210. *
  1211. * Antialias version of routine to draw text based on a brush.
  1212. *
  1213. * Arguments:
  1214. *
  1215. * [IN] - same as DDI parameters.
  1216. *
  1217. * Return Value:
  1218. *
  1219. * Ok if successful.
  1220. *
  1221. * History:
  1222. *
  1223. * 2/20/00 YungT
  1224. * Created it.
  1225. *
  1226. \**************************************************************************/
  1227. static GpStatus
  1228. OutputBrushAntiAliasText8BPP(
  1229. DpContext* context,
  1230. DpDriver * driver,
  1231. DpBitmap* surface,
  1232. const GpRect* drawBounds,
  1233. const DpBrush* brush,
  1234. const GpGlyphPos* glyphPos,
  1235. INT count
  1236. )
  1237. {
  1238. DpScanBuffer scan(
  1239. surface->Scan,
  1240. driver,
  1241. context,
  1242. surface,
  1243. FALSE); // (color64.IsOpaque() &&
  1244. // (!context->AntiAliasMode)));
  1245. // !!! If you fix this, you'll get a perf improvement for
  1246. // text that has no transparency.
  1247. if (!scan.IsValid())
  1248. {
  1249. return(GenericError);
  1250. }
  1251. DpOutputSpan* output = DpOutputSpan::Create(brush, &scan, context);
  1252. DpOutputAntiAliasBrushOutputSpan aaBrushSpan;
  1253. if (output != NULL)
  1254. {
  1255. INT i;
  1256. TextColorGammaTable textContrastTable;
  1257. textContrastTable.CreateTextColorGammaTable((GpColor *) NULL, context->TextContrast, GRAYSCALE_LEVEL);
  1258. DpClipRegion* clipRegion = NULL;
  1259. if (context->VisibleClip.GetRectVisibility( drawBounds->X, drawBounds->Y,
  1260. drawBounds->GetRight(), drawBounds->GetBottom()) !=
  1261. DpRegion::TotallyVisible)
  1262. {
  1263. aaBrushSpan.Init(output);
  1264. clipRegion = &(context->VisibleClip);
  1265. clipRegion->InitClipping(&aaBrushSpan, drawBounds->Y);
  1266. }
  1267. for (i = 0; i < count; i++)
  1268. {
  1269. INT left = glyphPos[i].GetLeft();
  1270. INT top = glyphPos[i].GetTop();
  1271. INT widthInPixels = glyphPos[i].GetWidth();
  1272. INT right = left + widthInPixels;
  1273. INT height = glyphPos[i].GetHeight();
  1274. INT bottom = top + height;
  1275. if (widthInPixels == 0 || height == 0)
  1276. continue;
  1277. INT widthInBytes = widthInPixels;
  1278. const BYTE* mask = glyphPos[i].GetBits();
  1279. ASSERT(mask != NULL);
  1280. if (clipRegion != NULL)
  1281. {
  1282. GpRect clippedRect;
  1283. DpRegion::Visibility visibility =
  1284. clipRegion->GetRectVisibility(left, top, right, bottom, &clippedRect);
  1285. if (visibility == DpRegion::Invisible)
  1286. continue;
  1287. for (INT y = top, my = 0; y < bottom && my < height; y++, my++)
  1288. {
  1289. const BYTE* maskPtr = mask + my * widthInBytes;
  1290. BYTE grayscaleValue = *maskPtr;
  1291. INT runStart = 0;
  1292. for (INT mx = 0; mx <= widthInPixels; mx++)
  1293. {
  1294. BYTE nextgrayscaleValue;
  1295. if (mx == widthInPixels)
  1296. {
  1297. nextgrayscaleValue = 0;
  1298. }
  1299. else
  1300. {
  1301. nextgrayscaleValue = *maskPtr;
  1302. maskPtr++;
  1303. }
  1304. if (grayscaleValue != nextgrayscaleValue)
  1305. {
  1306. if (grayscaleValue != 0)
  1307. {
  1308. // Draw this run
  1309. INT runLength = mx - runStart;
  1310. INT from = left + runStart;
  1311. if (visibility == DpRegion::TotallyVisible)
  1312. {
  1313. // Clip the run
  1314. INT to = from + runLength; // reference needed
  1315. output->OutputSpan(y, from, to);
  1316. ARGB *buffer;
  1317. buffer = output->GetScanBuffer()->GetCurrentBuffer();
  1318. for (INT j = from; j < to; j++)
  1319. {
  1320. *buffer++ = GpColor::MultiplyCoverage(*buffer,
  1321. textContrastTable.GetGammaTableIndexValue(grayscaleValue, GRAYSCALE_LEVEL));
  1322. }
  1323. }
  1324. else
  1325. {
  1326. // Clip the run
  1327. INT to = from + runLength; // reference needed
  1328. aaBrushSpan.SetCoverage(textContrastTable.GetGammaTableIndexValue(grayscaleValue, GRAYSCALE_LEVEL));
  1329. clipRegion->OutputSpan(y, from, to);
  1330. }
  1331. // Start a new run
  1332. runStart = mx;
  1333. grayscaleValue = nextgrayscaleValue;
  1334. }
  1335. else
  1336. {
  1337. // Start a new run
  1338. runStart = mx;
  1339. grayscaleValue = nextgrayscaleValue;
  1340. }
  1341. }
  1342. }
  1343. }
  1344. }
  1345. else
  1346. {
  1347. for (INT y = top, my = 0; y < bottom && my < height; y++, my++)
  1348. {
  1349. const BYTE* maskPtr = mask + my * widthInBytes;
  1350. BYTE grayscaleValue = *maskPtr;
  1351. INT runStart = 0;
  1352. for (INT mx = 0; mx <= widthInPixels; mx++)
  1353. {
  1354. BYTE nextgrayscaleValue;
  1355. if (mx == widthInPixels)
  1356. {
  1357. nextgrayscaleValue = 0;
  1358. }
  1359. else
  1360. {
  1361. nextgrayscaleValue = *maskPtr;
  1362. maskPtr++;
  1363. }
  1364. if (grayscaleValue != nextgrayscaleValue)
  1365. {
  1366. if (grayscaleValue != 0)
  1367. {
  1368. // Draw this run
  1369. INT runLength = mx - runStart;
  1370. INT from = left + runStart;
  1371. // Clip the run
  1372. INT to = from + runLength; // reference needed
  1373. output->OutputSpan(y, from, to);
  1374. ARGB *buffer;
  1375. buffer = output->GetScanBuffer()->GetCurrentBuffer();
  1376. for (INT j = from; j < to; j++)
  1377. {
  1378. *buffer++ = GpColor::MultiplyCoverage(*buffer,
  1379. textContrastTable.GetGammaTableIndexValue(grayscaleValue, GRAYSCALE_LEVEL));
  1380. }
  1381. // Start a new run
  1382. runStart = mx;
  1383. grayscaleValue = nextgrayscaleValue;
  1384. }
  1385. else
  1386. {
  1387. // Start a new run
  1388. runStart = mx;
  1389. grayscaleValue = nextgrayscaleValue;
  1390. }
  1391. }
  1392. }
  1393. }
  1394. }
  1395. }
  1396. if (clipRegion != NULL)
  1397. {
  1398. clipRegion->EndClipping();
  1399. }
  1400. delete output;
  1401. }
  1402. return(Ok);
  1403. }
  1404. /**************************************************************************\
  1405. *
  1406. * Function Description:
  1407. *
  1408. * Antialias version of routine to draw text based on a brush.
  1409. *
  1410. * Arguments:
  1411. *
  1412. * [IN] - same as DDI parameters.
  1413. *
  1414. * Return Value:
  1415. *
  1416. * Ok if successful.
  1417. *
  1418. * History:
  1419. *
  1420. * 1/28/00 YungT
  1421. * Created it.
  1422. *
  1423. \**************************************************************************/
  1424. static GpStatus
  1425. OutputBrushAntiAliasText4BPP(
  1426. DpContext* context,
  1427. DpDriver * driver,
  1428. DpBitmap* surface,
  1429. const GpRect* drawBounds,
  1430. const DpBrush* brush,
  1431. const GpGlyphPos* glyphPos,
  1432. INT count
  1433. )
  1434. {
  1435. DpScanBuffer scan(
  1436. surface->Scan,
  1437. driver,
  1438. context,
  1439. surface,
  1440. FALSE); // (color64.IsOpaque() &&
  1441. // (!context->AntiAliasMode)));
  1442. // !!! If you fix this, you'll get a perf improvement for
  1443. // text that has no transparency.
  1444. if (!scan.IsValid())
  1445. {
  1446. return(GenericError);
  1447. }
  1448. DpOutputSpan* output = DpOutputSpan::Create(brush, &scan, context);
  1449. DpOutputAntiAliasBrushOutputSpan aaBrushSpan;
  1450. if (output != NULL)
  1451. {
  1452. INT i;
  1453. TextColorGammaTable textContrastTable;
  1454. textContrastTable.CreateTextColorGammaTable((GpColor *) NULL, context->TextContrast, GRAYSCALE_LEVEL);
  1455. DpClipRegion* clipRegion = NULL;
  1456. if (context->VisibleClip.GetRectVisibility( drawBounds->X, drawBounds->Y,
  1457. drawBounds->GetRight(), drawBounds->GetBottom()) !=
  1458. DpRegion::TotallyVisible)
  1459. {
  1460. aaBrushSpan.Init(output);
  1461. clipRegion = &(context->VisibleClip);
  1462. clipRegion->InitClipping(&aaBrushSpan, drawBounds->Y);
  1463. }
  1464. for (i = 0; i < count; i++)
  1465. {
  1466. INT left = glyphPos[i].GetLeft();
  1467. INT top = glyphPos[i].GetTop();
  1468. INT widthInPixels = glyphPos[i].GetWidth();
  1469. INT right = left + widthInPixels;
  1470. INT height = glyphPos[i].GetHeight();
  1471. INT bottom = top + height;
  1472. if (widthInPixels == 0 || height == 0)
  1473. continue;
  1474. INT widthInBytes = ((widthInPixels + 1) / 2);
  1475. const BYTE* mask = glyphPos[i].GetBits();
  1476. ASSERT(mask != NULL);
  1477. if (clipRegion != NULL)
  1478. {
  1479. GpRect clippedRect;
  1480. DpRegion::Visibility visibility =
  1481. clipRegion->GetRectVisibility(left, top, right, bottom, &clippedRect);
  1482. if (visibility == DpRegion::Invisible)
  1483. continue;
  1484. for (INT y = top, my = 0; y < bottom && my < height; y++, my++)
  1485. {
  1486. const BYTE* maskPtr = mask + my * widthInBytes;
  1487. BYTE grayscaleValue = *maskPtr >> 4;
  1488. INT runStart = 0;
  1489. for (INT mx = 0; mx <= widthInPixels; mx++)
  1490. {
  1491. BYTE nextgrayscaleValue;
  1492. if (mx == widthInPixels)
  1493. {
  1494. nextgrayscaleValue = 0;
  1495. }
  1496. else
  1497. {
  1498. if (mx % 2)
  1499. {
  1500. nextgrayscaleValue = *maskPtr & 0x0F;
  1501. maskPtr++;
  1502. }
  1503. else
  1504. {
  1505. nextgrayscaleValue = *maskPtr >> 4;
  1506. }
  1507. }
  1508. if (grayscaleValue != nextgrayscaleValue)
  1509. {
  1510. if (grayscaleValue != 0)
  1511. {
  1512. // Draw this run
  1513. INT runLength = mx - runStart;
  1514. INT from = left + runStart;
  1515. if (visibility == DpRegion::TotallyVisible)
  1516. {
  1517. // Clip the run
  1518. INT to = from + runLength; // reference needed
  1519. output->OutputSpan(y, from, to);
  1520. ARGB *buffer;
  1521. buffer = output->GetScanBuffer()->GetCurrentBuffer();
  1522. for (INT j = from; j < to; j++)
  1523. {
  1524. *buffer++ = GpColor::MultiplyCoverage(*buffer,
  1525. textContrastTable.GetGammaTableIndexValue(grayscaleValue, GRAYSCALE_LEVEL));
  1526. }
  1527. }
  1528. else
  1529. {
  1530. // Clip the run
  1531. INT to = from + runLength; // reference needed
  1532. aaBrushSpan.SetCoverage(textContrastTable.GetGammaTableIndexValue(grayscaleValue, GRAYSCALE_LEVEL));
  1533. clipRegion->OutputSpan(y, from, to);
  1534. }
  1535. // Start a new run
  1536. runStart = mx;
  1537. grayscaleValue = nextgrayscaleValue;
  1538. }
  1539. else
  1540. {
  1541. // Start a new run
  1542. runStart = mx;
  1543. grayscaleValue = nextgrayscaleValue;
  1544. }
  1545. }
  1546. }
  1547. }
  1548. }
  1549. else
  1550. {
  1551. for (INT y = top, my = 0; y < bottom && my < height; y++, my++)
  1552. {
  1553. const BYTE* maskPtr = mask + my * widthInBytes;
  1554. BYTE grayscaleValue = *maskPtr >> 4;
  1555. INT runStart = 0;
  1556. for (INT mx = 0; mx <= widthInPixels; mx++)
  1557. {
  1558. BYTE nextgrayscaleValue;
  1559. if (mx == widthInPixels)
  1560. {
  1561. nextgrayscaleValue = 0;
  1562. }
  1563. else
  1564. {
  1565. if (mx % 2)
  1566. {
  1567. nextgrayscaleValue = *maskPtr & 0x0F;
  1568. maskPtr++;
  1569. }
  1570. else
  1571. {
  1572. nextgrayscaleValue = *maskPtr >> 4;
  1573. }
  1574. }
  1575. if (grayscaleValue != nextgrayscaleValue)
  1576. {
  1577. if (grayscaleValue != 0)
  1578. {
  1579. // Draw this run
  1580. INT runLength = mx - runStart;
  1581. INT from = left + runStart;
  1582. // Clip the run
  1583. INT to = from + runLength; // reference needed
  1584. output->OutputSpan(y, from, to);
  1585. ARGB *buffer;
  1586. buffer = output->GetScanBuffer()->GetCurrentBuffer();
  1587. for (INT j = from; j < to; j++)
  1588. {
  1589. *buffer++ = GpColor::MultiplyCoverage(*buffer,
  1590. textContrastTable.GetGammaTableIndexValue(grayscaleValue, GRAYSCALE_LEVEL));
  1591. }
  1592. // Start a new run
  1593. runStart = mx;
  1594. grayscaleValue = nextgrayscaleValue;
  1595. }
  1596. else
  1597. {
  1598. // Start a new run
  1599. runStart = mx;
  1600. grayscaleValue = nextgrayscaleValue;
  1601. }
  1602. }
  1603. }
  1604. }
  1605. }
  1606. }
  1607. if (clipRegion != NULL)
  1608. {
  1609. clipRegion->EndClipping();
  1610. }
  1611. delete output;
  1612. }
  1613. return(Ok);
  1614. }
  1615. /**************************************************************************\
  1616. *
  1617. * Function Description:
  1618. *
  1619. * Engine version of routine to draw solid text.
  1620. *
  1621. * Arguments:
  1622. *
  1623. * [IN] - DDI parameters.
  1624. *
  1625. * Return Value:
  1626. *
  1627. * TRUE if successful.
  1628. *
  1629. * History:
  1630. * 1/24/2000 YungT modified it
  1631. * 4/4/1999 cameronb
  1632. * Created it.
  1633. *
  1634. \**************************************************************************/
  1635. GpStatus
  1636. DpDriver::BrushText(
  1637. DpContext* context,
  1638. DpBitmap* surface,
  1639. const GpRect* drawBounds,
  1640. const DpBrush* brush,
  1641. const GpGlyphPos *glyphPos,
  1642. INT count,
  1643. TextRenderingHint textMode
  1644. )
  1645. {
  1646. ASSERT (textMode != TextRenderingHintSystemDefault);
  1647. switch(textMode)
  1648. {
  1649. case TextRenderingHintSingleBitPerPixelGridFit:
  1650. case TextRenderingHintSingleBitPerPixel:
  1651. return OutputBrushNormalText(context, this, surface, drawBounds, brush, glyphPos, count);
  1652. case TextRenderingHintAntiAlias:
  1653. return OutputBrushAntiAliasText8BPP(context, this, surface, drawBounds, brush, glyphPos, count);
  1654. case TextRenderingHintAntiAliasGridFit:
  1655. return OutputBrushAntiAliasText4BPP(context, this, surface, drawBounds, brush, glyphPos, count);
  1656. // version 2 :
  1657. // case TextRenderingHintClearType:
  1658. case TextRenderingHintClearTypeGridFit:
  1659. return OutputBrushClearTypeText(context, this, surface, drawBounds, brush, glyphPos, count);
  1660. default:
  1661. break;
  1662. }
  1663. return Ok;
  1664. }
  1665. ///// GdiText - Draw glyph on downlevel DC
  1666. //
  1667. // !!! Optimize to use lpdx
  1668. // NOTE:
  1669. // Here we explicitly call ExtTextOutW because we calling it with
  1670. // ETO_GLYPH_INDEX. It will be fine even if we are running on Windows 9x
  1671. // because internally it calls ExtTextOutA.
  1672. // We didn't use Global::ExtTextOutFunction because we don't want to call
  1673. // ExtTextOutA with ETO_GLYPH_INDEX while recording to a Meta file under
  1674. // Windows 9x. And in that case Windows 9x fails to record it.
  1675. // The code in Windows 9x is recording glyph indexes only if we are spooling
  1676. // only otherwise it will not record.
  1677. GpStatus
  1678. DpDriver::GdiText(
  1679. HDC hdc,
  1680. INT angle, // Tenths of a degree
  1681. const UINT16 *glyphs,
  1682. const PointF *glyphOrigins,
  1683. INT glyphCount,
  1684. BOOL rightToLeft,
  1685. UINT16 blankGlyph
  1686. )
  1687. {
  1688. UINT16 lastTwoGlyphs[2];
  1689. if ( glyphCount > 1
  1690. && angle == 0)
  1691. {
  1692. // Try to optimise for horizintal text. (We don't try for vertical
  1693. // text since GDI and GDI+ rotation semantics are not compatible)
  1694. INT i=1;
  1695. while ( i < glyphCount
  1696. && abs(GpRound(glyphOrigins[i].Y - glyphOrigins[i-1].Y)) == 0)
  1697. {
  1698. i++;
  1699. }
  1700. if (i == glyphCount)
  1701. {
  1702. // All text is at the same dy
  1703. AutoArray<INT> advances(new INT[glyphCount]);
  1704. if (!advances)
  1705. {
  1706. return OutOfMemory;
  1707. }
  1708. if (rightToLeft && !Globals::IsNt && glyphCount>1)
  1709. {
  1710. // Windows 9x doesn't work with the negative advanced widths
  1711. AutoArray<UINT16> bidiGlyphs(new UINT16[glyphCount]);
  1712. if (!bidiGlyphs)
  1713. {
  1714. return OutOfMemory;
  1715. }
  1716. for (i=0; i<glyphCount-1; i++)
  1717. {
  1718. bidiGlyphs[i] = glyphs[glyphCount - i - 1];
  1719. advances[i] = GpRound(glyphOrigins[glyphCount- i - 2].X - glyphOrigins[glyphCount- i - 1].X);
  1720. }
  1721. bidiGlyphs[glyphCount-1] = glyphs[0];
  1722. advances[glyphCount-1] = 0;
  1723. if (blankGlyph > 0 && (glyphCount & 1))
  1724. {
  1725. if (!ExtTextOutW(
  1726. hdc,
  1727. GpRound(glyphOrigins[glyphCount - 1].X),
  1728. GpRound(glyphOrigins[glyphCount - 1].Y),
  1729. ETO_GLYPH_INDEX,
  1730. NULL,
  1731. (PWSTR)bidiGlyphs.Get(),
  1732. glyphCount-1,
  1733. advances.Get()
  1734. )) {
  1735. return Win32Error;
  1736. }
  1737. lastTwoGlyphs[0] = bidiGlyphs[glyphCount-1];
  1738. lastTwoGlyphs[1] = blankGlyph;
  1739. if (!ExtTextOutW(
  1740. hdc,
  1741. GpRound(glyphOrigins[0].X),
  1742. GpRound(glyphOrigins[0].Y),
  1743. ETO_GLYPH_INDEX,
  1744. NULL,
  1745. (PWSTR)lastTwoGlyphs,
  1746. 2,
  1747. NULL
  1748. )) {
  1749. return Win32Error;
  1750. }
  1751. }
  1752. else
  1753. {
  1754. if (!ExtTextOutW(
  1755. hdc,
  1756. GpRound(glyphOrigins[glyphCount - 1].X),
  1757. GpRound(glyphOrigins[glyphCount - 1].Y),
  1758. ETO_GLYPH_INDEX,
  1759. NULL,
  1760. (PWSTR)bidiGlyphs.Get(),
  1761. glyphCount,
  1762. advances.Get()
  1763. )) {
  1764. return Win32Error;
  1765. }
  1766. }
  1767. return Ok;
  1768. }
  1769. INT offset = GpRound(glyphOrigins[0].X);
  1770. for (i=0; i<glyphCount-1; i++)
  1771. {
  1772. advances[i] = GpRound(glyphOrigins[i+1].X) - offset;
  1773. offset += advances[i];
  1774. }
  1775. advances[glyphCount-1] = 0;
  1776. if (blankGlyph > 0 && (glyphCount & 1))
  1777. {
  1778. if (!ExtTextOutW(
  1779. hdc,
  1780. GpRound(glyphOrigins[0].X),
  1781. GpRound(glyphOrigins[0].Y),
  1782. ETO_GLYPH_INDEX,
  1783. NULL,
  1784. (PWSTR)glyphs,
  1785. glyphCount-1,
  1786. advances.Get()
  1787. )) {
  1788. return Win32Error;
  1789. }
  1790. lastTwoGlyphs[0] = glyphs[glyphCount-1];
  1791. lastTwoGlyphs[1] = blankGlyph;
  1792. if (!ExtTextOutW(
  1793. hdc,
  1794. GpRound(glyphOrigins[glyphCount-1].X),
  1795. GpRound(glyphOrigins[glyphCount-1].Y),
  1796. ETO_GLYPH_INDEX,
  1797. NULL,
  1798. (PWSTR)lastTwoGlyphs,
  1799. 2,
  1800. NULL
  1801. )) {
  1802. return Win32Error;
  1803. }
  1804. }
  1805. else
  1806. {
  1807. if (!ExtTextOutW(
  1808. hdc,
  1809. GpRound(glyphOrigins[0].X),
  1810. GpRound(glyphOrigins[0].Y),
  1811. ETO_GLYPH_INDEX,
  1812. NULL,
  1813. (PWSTR)glyphs,
  1814. glyphCount,
  1815. advances.Get()
  1816. )) {
  1817. return Win32Error;
  1818. }
  1819. }
  1820. return Ok;
  1821. }
  1822. }
  1823. if (blankGlyph > 0)
  1824. {
  1825. lastTwoGlyphs[1] = blankGlyph;
  1826. for (INT i=0; i<glyphCount; i++)
  1827. {
  1828. if (glyphs[i] != 0xffff) // 0xffff is never displayed
  1829. {
  1830. lastTwoGlyphs[0] = glyphs[i];
  1831. if (!ExtTextOutW(
  1832. hdc,
  1833. GpRound(glyphOrigins[i].X),
  1834. GpRound(glyphOrigins[i].Y),
  1835. ETO_GLYPH_INDEX,
  1836. NULL,
  1837. (PWSTR)lastTwoGlyphs,
  1838. 2,
  1839. NULL
  1840. )) {
  1841. return Win32Error;
  1842. }
  1843. }
  1844. }
  1845. }
  1846. else
  1847. {
  1848. // Failed to optimise ...
  1849. for (INT i=0; i<glyphCount; i++)
  1850. {
  1851. if (glyphs[i] != 0xffff) // 0xffff is never displayed
  1852. {
  1853. if (!ExtTextOutW(
  1854. hdc,
  1855. GpRound(glyphOrigins[i].X),
  1856. GpRound(glyphOrigins[i].Y),
  1857. ETO_GLYPH_INDEX,
  1858. NULL,
  1859. (PWSTR)glyphs+i,
  1860. 1,
  1861. NULL
  1862. )) {
  1863. return Win32Error;
  1864. }
  1865. }
  1866. }
  1867. }
  1868. return Ok;
  1869. }