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.

1258 lines
38 KiB

  1. /**************************************************************************\
  2. *
  3. * Copyright (c) 1999-2000 Microsoft Corporation
  4. *
  5. * Module Name:
  6. *
  7. * GraphicsText.cpp
  8. *
  9. * Abstract:
  10. *
  11. * Text layout and display, Text measurement, Unicode to glyph mapping
  12. *
  13. * Notes:
  14. *
  15. * Provides support to allow apps to work with Unicode in logical order,
  16. * hides the mapping from Unicode to glyphs.
  17. *
  18. * Created:
  19. *
  20. * 06/01/99 dbrown
  21. *
  22. \**************************************************************************/
  23. #include "precomp.hpp"
  24. const DOUBLE PI = 3.1415926535897932384626433832795;
  25. ///// Coordinate systems
  26. //
  27. // The following coordinate systems are used:
  28. //
  29. // World coordinates (REAL) - the coordinate system used by client
  30. // applications and passed to most Graphics APIs (for example
  31. // DrawLine). Text is always purely vertical or purely horizontal in
  32. // world coordinates. Fonts constructed with emSize specified in
  33. // alternate units are first converted to world units by calling
  34. // GetScaleForAlternatePageUnit.
  35. //
  36. // Device coordinates (REAL) - Coordinates used on the device surface.
  37. // World coordinates are transformed to device coordinates using the
  38. // Graphics.Context.WorldToDevice.Transform function. REAL device
  39. // coordinates may have non-integral values when addressing sub-pixels.
  40. //
  41. // Font nominal coordinates (INT) - (aka deign units) coordinates used to
  42. // define a scalable font independant of scaled size.
  43. // GpFontFace.GetDesignEmHeight is the emSize of a font in nominal units.
  44. // Nominal coordinates are always a pure scale factor of world units with
  45. // no shear. For horizontal text there there is no rotation between
  46. // nominal and world coordinates. For vertical text, most non Far East
  47. // script characters are rotated by 90 degrees.
  48. //
  49. // Ideal coordinates (INT) - world coordinates mapped to integers by
  50. // a pure scale factor for use in Line Services, OpenType services and
  51. // Uniscribe shaping engine interfaces. The scale factor is usually
  52. // 2048 divided by the emSize of the default font in a text imager.
  53. ///// Transforms
  54. //
  55. // WorldToDevice - stored in a Graphics. May include scaling,
  56. // shearing and/or translation.
  57. //
  58. // WorldToIdeal - stored in a text imager while the imager is attached
  59. // to a Graphics. A pure scale factor, usually 2048 divided by the emSize
  60. // of the imager default font.
  61. //
  62. // FontTransform - stored in a FaceRealization. Maps font nominal units
  63. // to device coordinates, May include scaling, shearing and rotation, but
  64. // not translation.
  65. ///// Common buffer parameters
  66. //
  67. // glyphAdvance - per-glyph advance widths stored in ideal units measured
  68. // along the text baseline.
  69. //
  70. // glyphOffset - combining character offsets stored in ideal units
  71. // measured along and perpendicular to the baseline. The glyphOffset
  72. // buffer is required by Line Services, OpenType services and the
  73. // complex script shaping engines, but may somethimes be bypassed for
  74. // simple scripts.
  75. //
  76. // glyphOrigins - per glyph device coordinates of the glyph origin (the
  77. // initial point on the baseline of the glyhps advance vector).
  78. // Represented as PointF. Non integer values represent sub pixel
  79. // positions.
  80. ///// Glyph positioning functions
  81. //
  82. //
  83. // DrawPlacedGlyphs - Builds glyphPos array and passes it to the device driver.
  84. // ALL text device output output eventually comes through here.
  85. //
  86. // GetDeviceGlyphOriginsNominal
  87. // Used when there's no hinting to be accounted for.
  88. // Places glyph on device using nominal metrics passed in glyphAdvances
  89. // and glyphOffsets.
  90. //
  91. // GetDeviceGlyphOriginsAdjusted
  92. // Used to adjust for the difference between nominal and hinted metrics
  93. // Generates glyph origins in device units, and adjusts the width of spaces
  94. // to achieve the totalRequiredIdealAdvance parameter.
  95. // !!! Need to add support for kashida and inter-glyph justification.
  96. //
  97. // GetRealizedGlyphPlacement
  98. // Used to obtain hinted advance metrics along the baseline.
  99. // !!! Needs to be updated to call complex script shaping engines.
  100. //
  101. // GetFontTransformForAlternateResolution
  102. // Used during XMF playback.
  103. // Generates a font transform to match a font that was recorded at
  104. // a different resolution.
  105. //
  106. // MeasureGlyphsAtAlternateResolution
  107. // Used during XMF playback.
  108. // Measures glyphs passed to DrawDriverString as if they were to be rendered
  109. // at the original XMF recording resolution.
  110. /**************************************************************************\
  111. *
  112. * GpGraphics::DrawString
  113. *
  114. * Draw plain, marked up or formatted text in a rectangle
  115. *
  116. * Arguments:
  117. *
  118. *
  119. * Return Value:
  120. *
  121. * GDIPlus status
  122. *
  123. * Created:
  124. *
  125. * 06/25/99 dbrown
  126. *
  127. \**************************************************************************/
  128. GpStatus
  129. GpGraphics::DrawString(
  130. const WCHAR *string,
  131. INT length,
  132. const GpFont *font,
  133. const RectF *layoutRect,
  134. const GpStringFormat *format,
  135. const GpBrush *brush
  136. )
  137. {
  138. ASSERT(string && font && brush);
  139. GpStatus status = CheckTextMode();
  140. if (status != Ok)
  141. {
  142. if (IsRecording())
  143. SetValid(FALSE); // Prevent any more recording
  144. return status;
  145. }
  146. // Check that the clipping rectangle, if any, is visible, at least in part.
  147. if ( !IsRecording() // Metafile clipping happens at playback
  148. && layoutRect->Width
  149. && layoutRect->Height
  150. && ( !format
  151. || !(format->GetFormatFlags() & StringFormatFlagsNoClip)))
  152. {
  153. if ( layoutRect->Width < 0
  154. || layoutRect->Height < 0)
  155. {
  156. // Client has requested clipping to an empty rectangle, nothing
  157. // will display.
  158. return Ok;
  159. }
  160. // If client clipping rectangle is outside the visible clipping region -- were done.
  161. GpRectF deviceClipRectFloat;
  162. GpRect deviceClipRectPixel;
  163. GpMatrix worldToDevice;
  164. TransformBounds(
  165. &Context->WorldToDevice,
  166. layoutRect->X,
  167. layoutRect->Y,
  168. layoutRect->X + layoutRect->Width,
  169. layoutRect->Y + layoutRect->Height,
  170. &deviceClipRectFloat
  171. );
  172. status = BoundsFToRect(&deviceClipRectFloat, &deviceClipRectPixel);
  173. if(status != Ok)
  174. {
  175. return status;
  176. }
  177. if (IsTotallyClipped(&deviceClipRectPixel))
  178. {
  179. // Since nothing will be visible, we need do no more.
  180. return Ok;
  181. }
  182. }
  183. REAL emSize = font->GetEmSize() * GetScaleForAlternatePageUnit(font->GetUnit());
  184. if (IsRecording())
  185. {
  186. // Record Gdiplus metafile record
  187. // first measure the text bounding rectangle
  188. RectF boundingBox;
  189. status = MeasureString(
  190. string,
  191. length,
  192. font,
  193. layoutRect,
  194. format,
  195. &boundingBox,
  196. NULL,
  197. NULL);
  198. if (status != Ok)
  199. {
  200. SetValid(FALSE); // Prevent any more recording
  201. return status;
  202. }
  203. GpRectF bounds;
  204. TransformBounds(&(Context->WorldToDevice), boundingBox.X, boundingBox.Y,
  205. boundingBox.GetRight(), boundingBox.GetBottom(), &bounds);
  206. status = Metafile->RecordDrawString(
  207. &bounds,
  208. string,
  209. length,
  210. font,
  211. layoutRect,
  212. format,
  213. brush
  214. );
  215. if (status != Ok)
  216. {
  217. SetValid(FALSE); // Prevent any more recording
  218. return status;
  219. }
  220. if (!DownLevel)
  221. {
  222. return Ok;
  223. }
  224. // else we need to record down-level GDI EMF records as well
  225. // Since we have recorded all the parameters to DrawString,
  226. // we don't need to do anything more. For the downlevel case,
  227. // we need to record the DrawString call as a sequence of
  228. // ExtTextOut calls.
  229. }
  230. else
  231. {
  232. // Not recording a metafile, so it is safe to try using the fast text imager.
  233. FastTextImager fastImager;
  234. status = fastImager.Initialize(
  235. this,
  236. string,
  237. length,
  238. *layoutRect,
  239. font->GetFamily(),
  240. font->GetStyle(),
  241. emSize,
  242. format,
  243. brush
  244. );
  245. if (status == Ok)
  246. {
  247. status = fastImager.DrawString();
  248. }
  249. // If the fast text imager couldn't handle this case, it returns
  250. // NotImplemented, and we continue into the full text imager.
  251. // Otherwise it either completed successfully or hit an error
  252. // that we need to report.
  253. if (status != NotImplemented)
  254. {
  255. return status;
  256. }
  257. }
  258. // Draw text with the full text imager
  259. GpTextImager *imager;
  260. status = newTextImager( // Always creates a fulltextimager.
  261. string,
  262. length,
  263. layoutRect->Width,
  264. layoutRect->Height,
  265. font->GetFamily(),
  266. font->GetStyle(),
  267. emSize,
  268. format,
  269. brush,
  270. &imager,
  271. TRUE // Fast way to set NoChange flag to allow simple imager
  272. );
  273. IF_NOT_OK_WARN_AND_RETURN(status);
  274. imager->GetMetaFileRecordingFlag() = IsRecording();
  275. EmfPlusDisabler disableEmfPlus(&Metafile);
  276. status = imager->Draw(this, &PointF(layoutRect->X, layoutRect->Y));
  277. delete imager;
  278. return status;
  279. }
  280. /**************************************************************************\
  281. *
  282. * GpGraphics::MeasureString
  283. *
  284. * Measure plain, marked up or formatted text in a rectangle
  285. *
  286. * Arguments:
  287. *
  288. *
  289. * Return Value:
  290. *
  291. * GDIPlus status
  292. *
  293. * Created:
  294. *
  295. * 10/26/99 dbrown
  296. *
  297. \**************************************************************************/
  298. GpStatus
  299. GpGraphics::MeasureString(
  300. const WCHAR *string,
  301. INT length,
  302. const GpFont *font,
  303. const RectF *layoutRect,
  304. const GpStringFormat *format,
  305. RectF *boundingBox,
  306. INT *codepointsFitted,
  307. INT *linesFilled
  308. )
  309. {
  310. CalculateTextRenderingHintInternal();
  311. ASSERT(string && font && boundingBox);
  312. if (!string || !font || !boundingBox)
  313. {
  314. return InvalidParameter;
  315. }
  316. GpStatus status;
  317. REAL emSize = font->GetEmSize() * GetScaleForAlternatePageUnit(font->GetUnit());
  318. if (!IsRecording())
  319. {
  320. // Try using the fast imager
  321. FastTextImager fastImager;
  322. status = fastImager.Initialize(
  323. this,
  324. string,
  325. length,
  326. *layoutRect,
  327. font->GetFamily(),
  328. font->GetStyle(),
  329. emSize,
  330. format,
  331. NULL
  332. );
  333. if (status == Ok)
  334. {
  335. status = fastImager.MeasureString(
  336. boundingBox,
  337. codepointsFitted,
  338. linesFilled
  339. );
  340. }
  341. // If the fast text imager couldn't handle this case, it returns
  342. // NotImplemented, and we continue into the full text imager.
  343. // Otherwise it either completed successfully or hit an error
  344. // that we need to report.
  345. if (status != NotImplemented)
  346. {
  347. return status;
  348. }
  349. }
  350. // Measure text with the full text imager
  351. GpTextImager *imager;
  352. status = newTextImager(
  353. string,
  354. length,
  355. layoutRect->Width,
  356. layoutRect->Height,
  357. font->GetFamily(),
  358. font->GetStyle(),
  359. emSize,
  360. format,
  361. NULL,
  362. &imager,
  363. TRUE // Enable use of simple formatter when no format passed
  364. );
  365. IF_NOT_OK_WARN_AND_RETURN(status);
  366. *boundingBox = *layoutRect;
  367. REAL nearGlyphEdge;
  368. REAL farGlyphEdge;
  369. REAL textDepth;
  370. status = imager->Measure( // Returned edges exclude overhang
  371. this,
  372. &nearGlyphEdge,
  373. &farGlyphEdge,
  374. &textDepth,
  375. codepointsFitted,
  376. linesFilled
  377. );
  378. // Generate bounding box (excluding overhang) from near and far glyph edges
  379. if (status == Ok)
  380. {
  381. // Fix up near/far glyph edges for empty box
  382. if (nearGlyphEdge > farGlyphEdge)
  383. {
  384. nearGlyphEdge = 0;
  385. farGlyphEdge = 0;
  386. }
  387. if ( format
  388. && format->GetFormatFlags() & StringFormatFlagsDirectionVertical)
  389. {
  390. boundingBox->Y = layoutRect->Y + nearGlyphEdge;
  391. boundingBox->Height = farGlyphEdge - nearGlyphEdge;
  392. if (format)
  393. {
  394. StringAlignment lineAlign = format->GetLineAlign();
  395. REAL leadingOffset = 0.0; // positive offset to the leading side edge of the textbox
  396. if (lineAlign == StringAlignmentCenter)
  397. {
  398. leadingOffset = (boundingBox->Width - textDepth)/2;
  399. }
  400. else if (lineAlign == StringAlignmentFar)
  401. {
  402. leadingOffset = boundingBox->Width - textDepth;
  403. }
  404. if (format->GetFormatFlags() & StringFormatFlagsDirectionRightToLeft)
  405. {
  406. boundingBox->X += (boundingBox->Width - textDepth - leadingOffset);
  407. }
  408. else
  409. {
  410. boundingBox->X += leadingOffset;
  411. }
  412. }
  413. boundingBox->Width = textDepth;
  414. }
  415. else
  416. {
  417. boundingBox->X = layoutRect->X + nearGlyphEdge;
  418. boundingBox->Width = farGlyphEdge - nearGlyphEdge;
  419. if (format)
  420. {
  421. StringAlignment lineAlign = format->GetLineAlign();
  422. if (lineAlign == StringAlignmentCenter)
  423. {
  424. boundingBox->Y += (boundingBox->Height - textDepth) / 2;
  425. }
  426. else if (lineAlign == StringAlignmentFar)
  427. {
  428. boundingBox->Y += boundingBox->Height - textDepth;
  429. }
  430. }
  431. boundingBox->Height = textDepth;
  432. }
  433. if (!format
  434. || !(format->GetFormatFlags() & StringFormatFlagsNoClip))
  435. {
  436. // Make sure display bounding box never exceeds layout rectangle
  437. // in case of clipping.
  438. if ( layoutRect->Width > 0.0
  439. && boundingBox->Width > layoutRect->Width)
  440. {
  441. boundingBox->Width = layoutRect->Width;
  442. boundingBox->X = layoutRect->X;
  443. }
  444. if ( layoutRect->Height > 0.0
  445. && boundingBox->Height > layoutRect->Height)
  446. {
  447. boundingBox->Height = layoutRect->Height;
  448. boundingBox->Y = layoutRect->Y;
  449. }
  450. }
  451. }
  452. delete imager;
  453. return status;
  454. }
  455. /**************************************************************************\
  456. *
  457. * GpGraphics::MeasureCharacterRanges
  458. *
  459. * Produce a bounding regions of all given character ranges in stringformat
  460. *
  461. * Arguments:
  462. *
  463. *
  464. * Return Value:
  465. *
  466. * GDIPlus status
  467. *
  468. * Created:
  469. *
  470. * 10-9-2000 wchao
  471. *
  472. \**************************************************************************/
  473. GpStatus
  474. GpGraphics::MeasureCharacterRanges(
  475. const WCHAR *string,
  476. INT length,
  477. const GpFont *font,
  478. const RectF &layoutRect,
  479. const GpStringFormat *format,
  480. INT regionCount,
  481. GpRegion **regions
  482. )
  483. {
  484. CalculateTextRenderingHintInternal();
  485. ASSERT(format && string && font && regions);
  486. INT rangeCount = format->GetMeasurableCharacterRanges();
  487. if (regionCount < rangeCount)
  488. {
  489. return InvalidParameter;
  490. }
  491. INT stringLength;
  492. if (length == -1)
  493. {
  494. stringLength = 0;
  495. while (string[stringLength])
  496. {
  497. stringLength++;
  498. }
  499. }
  500. else
  501. {
  502. stringLength = length;
  503. }
  504. GpStatus status;
  505. REAL emSize = font->GetEmSize() * GetScaleForAlternatePageUnit(font->GetUnit());
  506. GpTextImager *imager;
  507. status = newTextImager(
  508. string,
  509. stringLength,
  510. layoutRect.Width,
  511. layoutRect.Height,
  512. font->GetFamily(),
  513. font->GetStyle(),
  514. emSize,
  515. format,
  516. NULL,
  517. &imager,
  518. TRUE // Enable use of simple formatter when no format passed
  519. );
  520. IF_NOT_OK_WARN_AND_RETURN(status);
  521. imager->GetMetaFileRecordingFlag() = IsRecording();
  522. PointF imagerOrigin(layoutRect.X , layoutRect.Y);
  523. status = imager->MeasureRanges(
  524. this,
  525. &imagerOrigin,
  526. regions
  527. );
  528. delete imager;
  529. return status;
  530. }
  531. ///// DrawPlacedGlyphs - Draw glyphs with arbitrary transform at device coordinates
  532. //
  533. //
  534. GpStatus
  535. GpGraphics::DrawPlacedGlyphs(
  536. const GpFaceRealization *faceRealization,
  537. const GpBrush *brush,
  538. INT flags, // For DG_NOGDI
  539. const WCHAR *string,
  540. UINT stringLength,
  541. BOOL rightToLeft,
  542. const UINT16 *glyphs,
  543. const UINT16 *glyphMap,
  544. const PointF *glyphOrigins,
  545. INT glyphCount,
  546. ItemScript Script,
  547. BOOL sideways // e.g. FE characters in vertical text
  548. )
  549. {
  550. IF_NOT_OK_WARN_AND_RETURN(faceRealization->GetStatus());
  551. INT i;
  552. BOOL bNeedPath = FALSE;
  553. GpFaceRealization cloneFaceRealization;
  554. GpGlyphPos *glyphPositions = NULL;
  555. GpGlyphPos *glyphPathPositions = NULL;
  556. // Display glyphs for Bits. Handle as many as possible in one go.
  557. INT glyphStart = 0; // start of this display run
  558. INT glyphsProcessed; // Number of glyphs processed by this GetGlyphPos call
  559. INT glyphPositionCount; // Number of glyphPositions generated by this GetGlyphPos call
  560. // Display glyphs for path. Handle as many as possible in one go.
  561. INT glyphPathStart = 0; // start of this display run
  562. INT glyphsPathProcessed, glyphsPathProcessedTemp; // Number of glyphs processed by this GetGlyphPos call
  563. INT glyphPathPositionCount, glyphPathPositionCountTemp; // Number of glyphPositions generated by this GetGlyphPos call
  564. GpStatus status = Ok;
  565. if (!glyphOrigins)
  566. {
  567. ASSERT(glyphOrigins);
  568. return GenericError;
  569. }
  570. // For sideways text, we have been passed glyph origins at the
  571. // top baseline, but we need to pass leftside baseline origins
  572. // to DrvDrawGlyphs for the benefit of metafiles and GDI positioning.
  573. AutoBuffer<PointF, 16> adjustedGlyphOrigins;
  574. const PointF *leftsideGlyphOrigins = glyphOrigins;
  575. if (sideways && Driver != Globals::MetaDriver)
  576. {
  577. adjustedGlyphOrigins.SetSize(glyphCount);
  578. if (!adjustedGlyphOrigins)
  579. {
  580. status = OutOfMemory;
  581. goto error;
  582. }
  583. status = faceRealization->GetGlyphStringVerticalOriginOffsets(
  584. glyphs,
  585. glyphCount,
  586. adjustedGlyphOrigins.Get()
  587. );
  588. if (status != Ok)
  589. {
  590. goto error;
  591. }
  592. for (INT i=0; i<glyphCount; i++)
  593. {
  594. adjustedGlyphOrigins[i].X = glyphOrigins[i].X - adjustedGlyphOrigins[i].X;
  595. adjustedGlyphOrigins[i].Y = glyphOrigins[i].Y - adjustedGlyphOrigins[i].Y;
  596. }
  597. leftsideGlyphOrigins = adjustedGlyphOrigins.Get();
  598. }
  599. glyphPositions = new GpGlyphPos[glyphCount];
  600. if (!glyphPositions)
  601. {
  602. status = OutOfMemory;
  603. goto error;
  604. }
  605. ASSERT(!faceRealization->IsPathFont() || Driver == Globals::MetaDriver);
  606. if (Driver == Globals::MetaDriver)
  607. {
  608. INT minX = MAXLONG;
  609. INT minY = MAXLONG;
  610. INT maxX = MINLONG;
  611. INT maxY = MINLONG;
  612. INT glyphPositionCountTemp = 0;
  613. while (glyphStart < glyphCount)
  614. {
  615. glyphPositionCount = faceRealization->GetGlyphPos(
  616. glyphCount - glyphStart,
  617. glyphs + glyphStart,
  618. glyphPositions + glyphStart,
  619. glyphOrigins + glyphStart,
  620. &glyphsProcessed,
  621. sideways
  622. );
  623. if (glyphPositionCount == 0 && ((glyphsProcessed + glyphStart) < glyphCount))
  624. {
  625. status = OutOfMemory;
  626. goto error;
  627. }
  628. for (i = 0; i < glyphPositionCount; i++)
  629. {
  630. INT j = glyphPositionCountTemp + i;
  631. if (glyphPositions[j].GetWidth() != 0 &&
  632. glyphPositions[j].GetHeight() != 0)
  633. {
  634. minX = min(minX, glyphPositions[j].GetLeft());
  635. minY = min(minY, glyphPositions[j].GetTop());
  636. maxX = max(maxX, glyphPositions[j].GetLeft() + glyphPositions[j].GetWidth());
  637. maxY = max(maxY, glyphPositions[j].GetTop() + glyphPositions[j].GetHeight());
  638. }
  639. if (glyphPositions[j].GetTempBits() != NULL)
  640. {
  641. GpFree(glyphPositions[j].GetTempBits());
  642. glyphPositions[j].SetTempBits(0);
  643. }
  644. }
  645. glyphStart += glyphsProcessed;
  646. glyphPositionCountTemp += glyphPositionCount;
  647. }
  648. glyphPositionCount = glyphPositionCountTemp;
  649. if (minX < maxX && minY < maxY)
  650. {
  651. // must grab the devlock before going into the driver.
  652. Devlock devlock(Device);
  653. GpRect drawBounds(minX, minY, maxX-minX, maxY-minY);
  654. REAL edgeGlyphAdvance;
  655. if (rightToLeft)
  656. {
  657. status = faceRealization->GetGlyphStringDeviceAdvanceVector(glyphs,
  658. 1,
  659. FALSE,
  660. &edgeGlyphAdvance);
  661. }
  662. else
  663. {
  664. status = faceRealization->GetGlyphStringDeviceAdvanceVector(&glyphs[glyphCount-1],
  665. 1,
  666. FALSE,
  667. &edgeGlyphAdvance);
  668. }
  669. if (status != Ok)
  670. goto error;
  671. if (sideways)
  672. {
  673. flags |= DG_SIDEWAY;
  674. }
  675. status = DrvDrawGlyphs(
  676. &drawBounds,
  677. glyphPositions,
  678. NULL,
  679. glyphPositionCount,
  680. brush->GetDeviceBrush(),
  681. faceRealization,
  682. glyphs,
  683. glyphMap,
  684. leftsideGlyphOrigins,
  685. glyphCount,
  686. string,
  687. stringLength,
  688. Script,
  689. GpRound(edgeGlyphAdvance),
  690. rightToLeft,
  691. flags
  692. );
  693. if (status != Ok)
  694. goto error;
  695. }
  696. }
  697. else
  698. {
  699. if (IsPrinter())
  700. {
  701. DriverPrint *pdriver = (DriverPrint*) Driver;
  702. if (pdriver->DriverType == DriverPostscript)
  703. {
  704. if (brush->GetBrushType() != BrushTypeSolidColor)
  705. {
  706. // generate bitmap & path in glyphPos
  707. bNeedPath = TRUE;
  708. }
  709. }
  710. }
  711. if (bNeedPath)
  712. {
  713. cloneFaceRealization.CloneFaceRealization(faceRealization, TRUE);
  714. if (!cloneFaceRealization.IsValid())
  715. {
  716. status = OutOfMemory;
  717. goto error;
  718. }
  719. ASSERT(cloneFaceRealization.IsPathFont());
  720. }
  721. if (bNeedPath)
  722. {
  723. glyphPathPositions = new GpGlyphPos[glyphCount];
  724. if (!glyphPathPositions)
  725. {
  726. status = OutOfMemory;
  727. goto error;
  728. }
  729. }
  730. while (glyphStart < glyphCount)
  731. {
  732. glyphPositionCount = faceRealization->GetGlyphPos(
  733. glyphCount - glyphStart,
  734. glyphs + glyphStart,
  735. glyphPositions,
  736. glyphOrigins + glyphStart,
  737. &glyphsProcessed,
  738. sideways
  739. );
  740. // glyphPositionCount = number of entries added to glyphPositions array
  741. // glyphsPositioned = number of glyph indices processed from glyph buffer
  742. if (glyphPositionCount == 0 && ((glyphsProcessed + glyphStart) < glyphCount))
  743. {
  744. status = OutOfMemory;
  745. goto error;
  746. }
  747. glyphsPathProcessed = 0;
  748. glyphPathPositionCount = 0;
  749. while (glyphsPathProcessed < glyphsProcessed)
  750. {
  751. INT minX = MAXLONG;
  752. INT minY = MAXLONG;
  753. INT maxX = MINLONG;
  754. INT maxY = MINLONG;
  755. if (bNeedPath)
  756. {
  757. glyphPathPositionCountTemp = cloneFaceRealization.GetGlyphPos(
  758. glyphsProcessed - glyphsPathProcessed,
  759. glyphs + glyphPathStart + glyphsPathProcessed,
  760. glyphPathPositions,
  761. glyphOrigins + glyphPathStart + glyphsPathProcessed,
  762. &glyphsPathProcessedTemp,
  763. sideways
  764. );
  765. glyphsPathProcessed += glyphsPathProcessedTemp;
  766. if (glyphPathPositionCountTemp == 0 && (glyphsPathProcessed < glyphsProcessed))
  767. {
  768. ASSERT(glyphPathPositionCount != glyphPositionCount);
  769. status = OutOfMemory;
  770. goto error;
  771. }
  772. }
  773. else
  774. {
  775. glyphsPathProcessed = glyphsProcessed;
  776. glyphPathPositionCountTemp = glyphPositionCount;
  777. }
  778. for (i = 0; i < glyphPathPositionCountTemp; i++)
  779. {
  780. INT j = glyphPathPositionCount + i;
  781. if (glyphPositions[j].GetWidth() != 0 &&
  782. glyphPositions[j].GetHeight() != 0)
  783. {
  784. minX = min(minX, glyphPositions[j].GetLeft());
  785. minY = min(minY, glyphPositions[j].GetTop());
  786. maxX = max(maxX, glyphPositions[j].GetLeft() + glyphPositions[j].GetWidth());
  787. maxY = max(maxY, glyphPositions[j].GetTop() + glyphPositions[j].GetHeight());
  788. }
  789. }
  790. if (minX < maxX && minY < maxY)
  791. {
  792. // must grab the devlock before going into the driver.
  793. Devlock devlock(Device);
  794. GpRect drawBounds(minX, minY, maxX-minX, maxY-minY);
  795. REAL edgeGlyphAdvance;
  796. if (rightToLeft)
  797. {
  798. status = faceRealization->GetGlyphStringDeviceAdvanceVector(glyphs,
  799. 1,
  800. FALSE,
  801. &edgeGlyphAdvance);
  802. }
  803. else
  804. {
  805. status = faceRealization->GetGlyphStringDeviceAdvanceVector(&glyphs[glyphCount-1],
  806. 1,
  807. FALSE,
  808. &edgeGlyphAdvance);
  809. }
  810. if (status != Ok)
  811. goto error;
  812. status = DrvDrawGlyphs(
  813. &drawBounds,
  814. &glyphPositions[glyphPathPositionCount],
  815. glyphPathPositions,
  816. glyphPathPositionCountTemp,
  817. brush->GetDeviceBrush(),
  818. faceRealization,
  819. glyphs + glyphPathStart,
  820. glyphMap + glyphPathStart,
  821. leftsideGlyphOrigins + glyphPathStart,
  822. glyphsProcessed,
  823. string,
  824. stringLength,
  825. Script,
  826. GpRound(edgeGlyphAdvance),
  827. rightToLeft,
  828. flags
  829. );
  830. if (status != Ok)
  831. goto error;
  832. }
  833. glyphPathPositionCount += glyphPathPositionCountTemp;
  834. }
  835. ASSERT (glyphsPathProcessed == glyphsProcessed);
  836. ASSERT (glyphPathPositionCount == glyphPositionCount);
  837. // Free any temporary bitmap buffers created by subpixelling
  838. for (i=0; i<glyphPositionCount; i++)
  839. {
  840. if (glyphPositions[i].GetTempBits() != NULL)
  841. {
  842. GpFree(glyphPositions[i].GetTempBits());
  843. glyphPositions[i].SetTempBits(0);
  844. }
  845. }
  846. glyphStart += glyphsProcessed;
  847. glyphPathStart += glyphsPathProcessed;
  848. }
  849. }
  850. error:
  851. // free memory allocated
  852. if (glyphPositions)
  853. delete [] glyphPositions;
  854. if (glyphPathPositions)
  855. delete [] glyphPathPositions;
  856. return status;
  857. }
  858. // GpGraphics::CheckTextMode
  859. // disallow ClearType text for CompositingModeSourceCopy
  860. GpStatus GpGraphics::CheckTextMode()
  861. {
  862. CalculateTextRenderingHintInternal();
  863. if (GetCompositingMode() == CompositingModeSourceCopy &&
  864. GetTextRenderingHintInternal() == TextRenderingHintClearTypeGridFit)
  865. {
  866. ONCE(WARNING(("CompositingModeSourceCopy cannot be used with ClearType text")));
  867. return InvalidParameter;
  868. }
  869. return Ok;
  870. } // GpGraphics::CheckTextMode
  871. void GpGraphics::CalculateTextRenderingHintInternal()
  872. {
  873. // this procedure is meant to be used by internal text routine and will convert TextRenderingHintSystemDefault
  874. // to the current system mode
  875. ASSERT(Context);
  876. TextRenderingHint textMode = Context->TextRenderHint;
  877. if (IsPrinter())
  878. {
  879. textMode = TextRenderingHintSingleBitPerPixelGridFit;
  880. }
  881. else if (textMode == TextRenderingHintSystemDefault)
  882. {
  883. if (Globals::CurrentSystemRenderingHintInvalid)
  884. {
  885. // Get the current text antialiazing mode from the system
  886. DWORD bOldSF, dwOldSFT;
  887. SystemParametersInfoA( SPI_GETFONTSMOOTHING, 0, (PVOID)&bOldSF, 0 );
  888. if (bOldSF)
  889. {
  890. SystemParametersInfoA( SPI_GETFONTSMOOTHINGTYPE, 0, (PVOID)&dwOldSFT, 0 );
  891. if( dwOldSFT & FE_FONTSMOOTHINGCLEARTYPE )
  892. {
  893. Globals::CurrentSystemRenderingHint = TextRenderingHintClearTypeGridFit;
  894. } else
  895. {
  896. Globals::CurrentSystemRenderingHint = TextRenderingHintAntiAliasGridFit;
  897. }
  898. } else
  899. {
  900. Globals::CurrentSystemRenderingHint = TextRenderingHintSingleBitPerPixelGridFit;
  901. }
  902. }
  903. textMode = Globals::CurrentSystemRenderingHint;
  904. }
  905. // Lead and PM decision to disable ClearType on downlevel system, we allow only on Windows NT 5.1 or later
  906. if ((textMode == TextRenderingHintClearTypeGridFit) &&
  907. (!Globals::IsNt ||
  908. (Globals::OsVer.dwMajorVersion < 5) ||
  909. ((Globals::OsVer.dwMajorVersion == 5) && (Globals::OsVer.dwMinorVersion < 1))
  910. )
  911. )
  912. {
  913. textMode = TextRenderingHintSingleBitPerPixelGridFit;
  914. }
  915. if (textMode == TextRenderingHintClearTypeGridFit ||
  916. textMode == TextRenderingHintAntiAlias ||
  917. textMode == TextRenderingHintAntiAliasGridFit)
  918. {
  919. if (Surface &&
  920. GetPixelFormatSize(Surface->PixelFormat) <= 8 &&
  921. Surface->PixelFormat != PixelFormatMulti)
  922. {
  923. // disable AA & ClearType in 256 bit color mode and less
  924. textMode = TextRenderingHintSingleBitPerPixelGridFit;
  925. }
  926. else if (Globals::IsTerminalServer)
  927. {
  928. // disable AA & ClearType for Terminal Server desktop surface
  929. if (Surface && Surface->IsDesktopSurface())
  930. {
  931. textMode = TextRenderingHintSingleBitPerPixelGridFit;
  932. }
  933. }
  934. }
  935. if (textMode == TextRenderingHintClearTypeGridFit)
  936. {
  937. if (Globals::CurrentSystemRenderingHintInvalid)
  938. {
  939. // get ClearType orientation setting from the system
  940. UpdateLCDOrientation();
  941. }
  942. }
  943. Globals::CurrentSystemRenderingHintInvalid = FALSE;
  944. TextRenderingHintInternal = textMode;
  945. } // GpGraphics::CalculateTextRenderingHintInternal
  946. ///// DrawFontStyleLine
  947. //
  948. // Draw underline or strikethrough or both depending on what style is used
  949. // in the font. Given points are in world coordinate.
  950. //
  951. // Make sure the line thickness is at least 1 pixel wide.
  952. GpStatus GpGraphics::DrawFontStyleLine(
  953. const PointF *baselineOrigin, // baseline origin
  954. REAL baselineLength, // baseline length
  955. const GpFontFace *face, // font face
  956. const GpBrush *brush, // brush
  957. BOOL vertical, // vertical text?
  958. REAL emSize, // font EM size in world unit
  959. INT style, // kind of lines to be drawn
  960. const GpMatrix *matrix // additional transform
  961. )
  962. {
  963. REAL fontToWorld = emSize / TOREAL(face->GetDesignEmHeight());
  964. PointF drawingParams[2]; // X is offset from baseline, Y is device pen width
  965. INT count = 0;
  966. GpStatus status = Ok;
  967. if (style & FontStyleUnderline)
  968. {
  969. // underlining metric
  970. const REAL penPos = face->GetDesignUnderscorePosition() * fontToWorld;
  971. REAL penWidth = face->GetDesignUnderscoreSize() * fontToWorld;
  972. penWidth = GetDevicePenWidth(penWidth, matrix);
  973. drawingParams[count].X = penPos;
  974. drawingParams[count++].Y = penWidth;
  975. }
  976. if (style & FontStyleStrikeout)
  977. {
  978. // strikethrough metric
  979. const REAL penPos = face->GetDesignStrikeoutPosition() * fontToWorld;
  980. REAL penWidth = face->GetDesignStrikeoutSize() * fontToWorld;
  981. penWidth = GetDevicePenWidth(penWidth, matrix);
  982. drawingParams[count].X = penPos;
  983. drawingParams[count++].Y = penWidth;
  984. }
  985. for (INT i = 0; i < count; i++)
  986. {
  987. PointF points[2];
  988. points[0] = *baselineOrigin;
  989. if (vertical)
  990. {
  991. points[0].X += drawingParams[i].X; // offset from baseline
  992. points[1].X = points[0].X;
  993. points[1].Y = points[0].Y + baselineLength;
  994. }
  995. else
  996. {
  997. points[0].Y -= drawingParams[i].X; // offset from baseline
  998. points[1].Y = points[0].Y;
  999. points[1].X = points[0].X + baselineLength;
  1000. }
  1001. if (matrix)
  1002. {
  1003. matrix->Transform(points, 2);
  1004. }
  1005. status = DrawLine(
  1006. &GpPen(
  1007. brush,
  1008. drawingParams[i].Y,
  1009. UnitPixel
  1010. ),
  1011. points[0],
  1012. points[1]
  1013. );
  1014. IF_NOT_OK_WARN_AND_RETURN(status);
  1015. }
  1016. return status;
  1017. }
  1018. // fix up pen width for strikeout/underline/hotkey cases
  1019. // to avoid varying line width within the same paragraph
  1020. // return value is in pixel units
  1021. REAL GpGraphics::GetDevicePenWidth(
  1022. REAL widthInWorldUnits,
  1023. const GpMatrix *matrix
  1024. )
  1025. {
  1026. GpMatrix worldToDevice;
  1027. GetWorldToDeviceTransform(&worldToDevice);
  1028. if (matrix)
  1029. {
  1030. worldToDevice.Prepend(*matrix);
  1031. }
  1032. PointF underlineVector(widthInWorldUnits, 0.0f);
  1033. worldToDevice.VectorTransform(&underlineVector);
  1034. REAL penWidth = (REAL)GpRound(VectorLength(underlineVector));
  1035. if (penWidth < 1.0f)
  1036. penWidth = 1.0f;
  1037. return penWidth;
  1038. }
  1039. ///// DriverString APIs
  1040. //
  1041. // Driver string APIs are in engine\text\DriverStringImager.cpp