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.

970 lines
27 KiB

  1. /**************************************************************************\
  2. *
  3. * Copyright (c) 1998 Microsoft Corporation
  4. *
  5. * Abstract:
  6. *
  7. * Handles the driver viewable Context class.
  8. *
  9. * Revision History:
  10. *
  11. * 12/03/1998 andrewgo
  12. * Created it.
  13. *
  14. \**************************************************************************/
  15. #include "precomp.hpp"
  16. LONG DpContext::Uniqueness = 0xfdbc; // Used with save/restore Id's
  17. DpContext::DpContext(
  18. DpContext * prev
  19. )
  20. {
  21. ASSERT(prev != NULL);
  22. Id = InterlockedDecrement(&Uniqueness) << 16;
  23. Next = NULL;
  24. Prev = prev;
  25. // Save bit 15 for a container flag
  26. Id |= ((prev->Id + 1) & 0x00007FFF);
  27. if (Id == 0) // 0 is not a valid ID
  28. {
  29. Id = 0x0dbc0001;
  30. }
  31. AntiAliasMode = prev->AntiAliasMode;
  32. TextRenderHint = prev->TextRenderHint;
  33. TextContrast = prev->TextContrast;
  34. CompositingMode = prev->CompositingMode;
  35. CompositingQuality = prev->CompositingQuality;
  36. FilterType = prev->FilterType;
  37. PixelOffset = prev->PixelOffset;
  38. Hwnd = prev->Hwnd;
  39. Hdc = prev->Hdc;
  40. IsEmfPlusHdc = prev->IsEmfPlusHdc;
  41. IsPrinter = prev->IsPrinter;
  42. IsDisplay = prev->IsDisplay;
  43. SaveDc = prev->SaveDc;
  44. Palette = prev->Palette;
  45. PaletteMap = prev->PaletteMap;
  46. OriginalHFont = NULL;
  47. CurrentHFont = NULL;
  48. Face = NULL;
  49. ContainerDpiX = prev->ContainerDpiX;
  50. ContainerDpiY = prev->ContainerDpiY;
  51. MetafileRasterizationLimitDpi = prev->MetafileRasterizationLimitDpi;
  52. RenderingOriginX = prev->RenderingOriginX;
  53. RenderingOriginY = prev->RenderingOriginY;
  54. GdiLayered = FALSE;
  55. // Does this need to be prev->IcmMode?
  56. IcmMode = IcmModeOff;
  57. // Clipping and Transforms handled elsewhere
  58. }
  59. DpContext::DpContext(
  60. BOOL isDisplay
  61. )
  62. {
  63. Id = InterlockedDecrement(&Uniqueness) << 16;
  64. Next = NULL;
  65. Prev = NULL;
  66. Id |= 0x0dbc;
  67. AntiAliasMode = 0;
  68. TextRenderHint = TextRenderingHintSystemDefault;
  69. TextContrast = DEFAULT_TEXT_CONTRAST;
  70. CompositingMode = CompositingModeSourceOver;
  71. CompositingQuality = CompositingQualityDefault;
  72. FilterType = InterpolationModeDefaultInternal;
  73. PixelOffset = PixelOffsetModeDefault;
  74. Hwnd = NULL;
  75. Hdc = NULL;
  76. IsEmfPlusHdc = FALSE;
  77. IsPrinter = FALSE;
  78. IsDisplay = isDisplay;
  79. SaveDc = 0;
  80. PageUnit = UnitDisplay;
  81. PageScale = 1.0f;
  82. Palette = NULL;
  83. PaletteMap = NULL;
  84. OriginalHFont = NULL;
  85. CurrentHFont = NULL;
  86. Face = NULL;
  87. ContainerDpiX = Globals::DesktopDpiX;
  88. ContainerDpiY = Globals::DesktopDpiY;
  89. GdiLayered = FALSE;
  90. MetafileRasterizationLimitDpi = max(ContainerDpiX, ContainerDpiY);
  91. ASSERT(MetafileRasterizationLimitDpi > 0.0f);
  92. // Set the default rendering origin to the top left corner of the Graphics.
  93. RenderingOriginX = 0;
  94. RenderingOriginY = 0;
  95. // Set the default ICM mode == ICM off.
  96. IcmMode = IcmModeOff;
  97. // Clipping and Transforms handled elsewhere
  98. }
  99. DpContext::~DpContext()
  100. {
  101. delete Next;
  102. Next = NULL;
  103. DeleteCurrentHFont();
  104. if (Prev == NULL)
  105. {
  106. if (PaletteMap != NULL)
  107. {
  108. delete PaletteMap;
  109. PaletteMap = NULL;
  110. }
  111. if (Palette != NULL)
  112. {
  113. GpFree(Palette);
  114. Palette = NULL;
  115. }
  116. }
  117. } // DpContext::~DpContext
  118. /**************************************************************************\
  119. *
  120. * Function Description:
  121. *
  122. * Internal function that retrieves a clean HDC for the specified
  123. * context (if there is one). This is intended to be used for
  124. * internal functions that require a DC (such as when we leverage
  125. * GDI accelerations for rendering).
  126. *
  127. * The DC is cleaned for the minimum amount that we can. That is,
  128. * the caller can expect an MM_TEXT transform, copy ROP, etc.
  129. *
  130. * We explicitly DO NOT clean attributes that we expect any callers
  131. * to change, such as brush color, text color, etc. (And consequently,
  132. * callers are not expected to preserve those values.)
  133. *
  134. * Reset: Transform, ROP mode
  135. *
  136. * NOT reset: Application clipping, stretch blt mode, current brush/pen,
  137. * foreground color, etc.
  138. *
  139. * Return Value:
  140. *
  141. * NULL if no HDC can be retrieved.
  142. *
  143. * History:
  144. *
  145. * 12/04/1998 andrewgo
  146. * Created it.
  147. *
  148. \**************************************************************************/
  149. HDC
  150. DpContext::GetHdc(
  151. DpBitmap *surface
  152. )
  153. {
  154. HDC hdc = NULL;
  155. // Callers MUST pass in the surface:
  156. ASSERT(surface != NULL);
  157. // The first thing we have to do is flush any of our pending drawing
  158. // (because GDI certainly doesn't know how to flush it!)
  159. surface->Flush(FlushIntentionFlush);
  160. if (Hwnd)
  161. {
  162. // The Graphics was derived off an Hwnd. Use GetCleanHdc
  163. // to get a nice clean DC (not a CS_OWNDC).
  164. hdc = ::GetCleanHdc(Hwnd);
  165. if(hdc)
  166. {
  167. // Set the appropriate ICM mode according to the context.
  168. if(IcmMode == IcmModeOn)
  169. {
  170. // Force the ICM mode on.
  171. ::SetICMMode(hdc, ICM_ON);
  172. }
  173. else
  174. {
  175. // There are only 2 IcmMode flags possible. If you've added
  176. // more you need to recode the logic that sets the IcmMode on
  177. // the DC.
  178. ASSERT(IcmMode==IcmModeOff);
  179. ::SetICMMode(hdc, ICM_OFF);
  180. }
  181. }
  182. return hdc;
  183. }
  184. else if (Hdc)
  185. {
  186. // The Graphics was derived from a bitmap, printer, or metafile Hdc.
  187. // First, save the application's HDC state and reset all the state
  188. hdc = Hdc;
  189. if (!SaveDc)
  190. {
  191. SaveDc = ::SaveDC(hdc);
  192. if (!SaveDc)
  193. {
  194. return(NULL);
  195. }
  196. this->CleanTheHdc(hdc);
  197. }
  198. }
  199. else if (surface->Type == DpBitmap::CreationType::GPBITMAP)
  200. {
  201. // The GpBitmap is accessible from the EpScanBitmap. It will
  202. // create an HDC and GDI bitmap appropriate for interop.
  203. EpScanBitmap *scan = static_cast<EpScanBitmap*>(surface->Scan);
  204. hdc = scan->GetBitmap()->GetHdc();
  205. // !!! For some reason, this hdc is NOT clean. So in metaplay.cpp
  206. // !!! I have to call CleanTheHdc on this hdc. I don't think I should
  207. // !!! have to do that, but without it, there is bug #121666.
  208. }
  209. return(hdc);
  210. }
  211. /**************************************************************************\
  212. *
  213. * Function Description:
  214. *
  215. * Internal function that cleans the given HDC.
  216. *
  217. * Reset: Transform, ROP mode
  218. *
  219. * NOT reset: Application clipping, stretch blt mode, current brush/pen,
  220. * foreground color, etc.
  221. *
  222. * Notes:
  223. *
  224. * Application clipping IS reset, contrary to the above - this is bug #99338.
  225. *
  226. * Arguments:
  227. *
  228. * hdc - the HDC to clean
  229. *
  230. * History:
  231. *
  232. * ??/??/???? andrewgo
  233. * Created it.
  234. *
  235. \**************************************************************************/
  236. VOID
  237. DpContext::CleanTheHdc(
  238. HDC hdc
  239. )
  240. {
  241. // Reset the minimum number of DC attributes possible
  242. //
  243. // DON'T GRATUITOUSLY ADD RESETS HERE. Read the function
  244. // comment above, and consider resetting any additional
  245. // DC attributes in the function that calls GetHdc().
  246. //
  247. // NOTE: A possible optimization for bitmap surfaces would
  248. // be to CreateCompatibleDC a new DC, and select
  249. // the bitmap into that.
  250. // Set the appropriate ICM mode.
  251. if(IcmMode == IcmModeOn)
  252. {
  253. // Force the ICM mode on.
  254. ::SetICMMode(hdc, ICM_ON);
  255. }
  256. else
  257. {
  258. // There are only 2 IcmMode flags possible. If you've added
  259. // more you need to recode the logic that sets the IcmMode on
  260. // the DC.
  261. ASSERT(IcmMode==IcmModeOff);
  262. // Force the ICM mode off.
  263. ::SetICMMode(hdc, ICM_OFF);
  264. }
  265. if (!IsEmfPlusHdc)
  266. {
  267. SetMapMode(hdc, MM_TEXT);
  268. SetViewportOrgEx(hdc, 0, 0, NULL);
  269. SetWindowOrgEx(hdc, 0, 0, NULL);
  270. SetROP2(hdc, R2_COPYPEN);
  271. ModifyWorldTransform(hdc, NULL, MWT_IDENTITY);
  272. // If someone does a GpGraphics::GetHdc and sets the clipping,
  273. // we have to be sure to unset it before using the hdc again.
  274. SelectClipRgn(hdc, NULL);
  275. // Do we have to do an EndPath?
  276. }
  277. else // it is an EMF+ HDC
  278. {
  279. // record a minimum of commands in the EMF+ file (if any at all)
  280. BOOL setMapMode = (::GetMapMode(hdc) != MM_TEXT);
  281. POINT point;
  282. point.x = 0;
  283. point.y = 0;
  284. ::GetViewportOrgEx(hdc, &point);
  285. BOOL setViewportOrg = ((point.x != 0) || (point.y != 0));
  286. point.x = 0;
  287. point.y = 0;
  288. ::GetWindowOrgEx(hdc, &point);
  289. BOOL setWindowOrg = ((point.x != 0) || (point.y != 0));
  290. BOOL setROP2 = (::GetROP2(hdc) != R2_COPYPEN);
  291. #if 0 // do NOT turn this on -- see comments below
  292. BOOL setWorldTransform = FALSE;
  293. // The graphics mode is never GM_ADVANCED on Win9x.
  294. // On WinNT it gets set to GM_ADVANCED when we are playing an EMF
  295. // into the hdc. In that case, we don't want to set the transform
  296. // to the identity, because it will override the srcRect->destRect
  297. // transform of the command to play the metafile, which will mess
  298. // up GDI's transform.
  299. // The only other way we could be in GM_ADVANCED mode is if the
  300. // application created the EMF hdc themselves and set it to GM_ADVANCED
  301. // before creating a graphics from the metafile HDC. That case is
  302. // currently NOT supported, and the app shouldn't do that!
  303. // Perhaps we should add code in the constructor to block that case.
  304. // This test always returns FALSE on Win9x.
  305. if (::GetGraphicsMode(hdc) == GM_ADVANCED)
  306. {
  307. XFORM xformIdentity;
  308. xformIdentity.eM11 = 1.0f;
  309. xformIdentity.eM12 = 0.0f;
  310. xformIdentity.eM21 = 0.0f;
  311. xformIdentity.eM22 = 1.0f;
  312. xformIdentity.eDx = 0.0f;
  313. xformIdentity.eDy = 0.0f;
  314. XFORM xform;
  315. xform.eM11 = 0.0;
  316. if (::GetWorldTransform(hdc, &xform))
  317. {
  318. setWorldTransform = (GpMemcmp(&xform, &xformIdentity, sizeof(xform)) != 0);
  319. }
  320. else
  321. {
  322. setWorldTransform = TRUE;
  323. WARNING1("GetWorldTransform failed");
  324. }
  325. }
  326. #endif
  327. RECT clipRect;
  328. HRGN hRgnTmp = ::CreateRectRgn(0, 0, 0, 0);
  329. BOOL setClipping = ((hRgnTmp == NULL) ||
  330. (::GetClipRgn(hdc, hRgnTmp) != 0));
  331. ::DeleteObject(hRgnTmp);
  332. if (setMapMode)
  333. {
  334. ::SetMapMode(hdc, MM_TEXT);
  335. }
  336. if (setViewportOrg)
  337. {
  338. ::SetViewportOrgEx(hdc, 0, 0, NULL);
  339. }
  340. if (setWindowOrg)
  341. {
  342. ::SetWindowOrgEx(hdc, 0, 0, NULL);
  343. }
  344. if (setROP2)
  345. {
  346. ::SetROP2(hdc, R2_COPYPEN);
  347. }
  348. #if 0 // do NOT turn this on -- see comments above
  349. if (setWorldTransform)
  350. {
  351. ::ModifyWorldTransform(hdc, NULL, MWT_IDENTITY);
  352. }
  353. #endif
  354. if (setClipping)
  355. {
  356. ::SelectClipRgn(hdc, NULL);
  357. }
  358. }
  359. }
  360. /**************************************************************************\
  361. *
  362. * Function Description:
  363. *
  364. * Releases the HDC if necessary.
  365. *
  366. * Return Value:
  367. *
  368. * History:
  369. *
  370. * 12/04/1998 andrewgo
  371. * Created it.
  372. *
  373. \**************************************************************************/
  374. VOID
  375. DpContext::ReleaseHdc(
  376. HDC hdc,
  377. DpBitmap *surface
  378. )
  379. {
  380. if (Hwnd)
  381. {
  382. ReleaseDC(Hwnd, hdc);
  383. }
  384. else if (!Hdc && surface &&
  385. (surface->Type == DpBitmap::CreationType::GPBITMAP))
  386. {
  387. // The GpBitmap is accessible from the EpScanBitmap.
  388. EpScanBitmap *scan = static_cast<EpScanBitmap*>(surface->Scan);
  389. scan->GetBitmap()->ReleaseHdc(hdc);
  390. }
  391. }
  392. // ResetHdc() restores the HDC to the state in which it was given to us.
  393. VOID DpContext::ResetHdc(VOID)
  394. {
  395. if (SaveDc)
  396. {
  397. RestoreDC(Hdc, SaveDc);
  398. SaveDc = 0;
  399. }
  400. } // DpContext::ResetHdc
  401. /**************************************************************************\
  402. *
  403. * Function Description:
  404. *
  405. * Retrieves the appropriate transform. Implemented as a routine so that
  406. * we can do lazy evaluation.
  407. *
  408. * Arguments:
  409. *
  410. * [OUT] worldToDevice: world to device matrix.
  411. *
  412. * Return Value:
  413. *
  414. * Ok if the device to world matrix is invertible. If this is not Ok,
  415. * the returned matrix is the identity matrix.
  416. *
  417. * History:
  418. *
  419. * 12/04/1998 andrewgo
  420. * Created it.
  421. *
  422. \**************************************************************************/
  423. GpStatus
  424. DpContext::GetDeviceToWorld(
  425. GpMatrix* deviceToWorld
  426. ) const
  427. {
  428. GpStatus status = Ok;
  429. if(!InverseOk)
  430. {
  431. if(WorldToDevice.IsInvertible())
  432. {
  433. DeviceToWorld = WorldToDevice;
  434. DeviceToWorld.Invert();
  435. InverseOk = TRUE;
  436. }
  437. else
  438. {
  439. DeviceToWorld.Reset(); // reset to identity matrix
  440. status = GenericError;
  441. }
  442. }
  443. *deviceToWorld = DeviceToWorld;
  444. return status;
  445. }
  446. // The units we use for the page transform with UnitDisplay depend
  447. // on whether the graphics is associated with a display screen. If
  448. // it is, then we just use the dpi of the display (which is why we
  449. // call it display units). Otherwise (e.g. a printer), we use
  450. // 100 dpi for display units.
  451. #define GDIP_DISPLAY_DPI 100.0f
  452. /**************************************************************************\
  453. *
  454. * Function Description:
  455. *
  456. * Calculate the page multiplier for going from page units to device units.
  457. * Used to concatenate the page transform with the WorldToPage transform.
  458. *
  459. * Arguments:
  460. *
  461. * NONE
  462. *
  463. * Return Value:
  464. *
  465. * NONE
  466. *
  467. * Created:
  468. *
  469. * 3/8/1999 DCurtis
  470. *
  471. \**************************************************************************/
  472. VOID
  473. DpContext::GetPageMultipliers(
  474. REAL * pageMultiplierX,
  475. REAL * pageMultiplierY,
  476. GpPageUnit unit,
  477. REAL scale
  478. ) const
  479. {
  480. if ((unit == UnitDisplay) && IsDisplay)
  481. {
  482. // The page transform is always the identity if
  483. // we are rendering to a display, and the unit
  484. // is UnitDisplay.
  485. *pageMultiplierX = 1.0f;
  486. *pageMultiplierY = 1.0f;
  487. return;
  488. }
  489. REAL multiplierX;
  490. REAL multiplierY;
  491. switch (unit)
  492. {
  493. default:
  494. ASSERT(0);
  495. // FALLTHRU
  496. // The units we use for the page transform with UnitDisplay depend
  497. // on whether the graphics is associated with a display screen. If
  498. // it is, then we just use the dpi of the display (which is why we
  499. // call it display units). Otherwise (e.g. a printer), we use
  500. // 100 dpi for display units.
  501. case UnitDisplay: // Variable
  502. // since it's not a display, use the default display dpi of 100
  503. multiplierX = ContainerDpiX * scale / GDIP_DISPLAY_DPI;
  504. multiplierY = ContainerDpiY * scale / GDIP_DISPLAY_DPI;
  505. break;
  506. case UnitPixel: // Each unit represents one device pixel.
  507. multiplierX = scale;
  508. multiplierY = scale;
  509. break;
  510. case UnitPoint: // Each unit represents a printer's point,
  511. // or 1/72 inch.
  512. multiplierX = ContainerDpiX * scale / 72.0f;
  513. multiplierY = ContainerDpiY * scale / 72.0f;
  514. break;
  515. case UnitInch: // Each unit represents 1 inch.
  516. multiplierX = ContainerDpiX * scale;
  517. multiplierY = ContainerDpiY * scale;
  518. break;
  519. case UnitDocument: // Each unit represents 1/300 inch.
  520. multiplierX = ContainerDpiX * scale / 300.0f;
  521. multiplierY = ContainerDpiY * scale / 300.0f;
  522. break;
  523. case UnitMillimeter: // Each unit represents 1 millimeter.
  524. // One Millimeter is 0.03937 inches
  525. // One Inch is 25.4 millimeters
  526. multiplierX = ContainerDpiX * scale / 25.4f;
  527. multiplierY = ContainerDpiY * scale / 25.4f;
  528. break;
  529. }
  530. *pageMultiplierX = multiplierX;
  531. *pageMultiplierY = multiplierY;
  532. }
  533. /**************************************************************************\
  534. *
  535. * Function Description:
  536. *
  537. * Prepares the contexts DC for use in an ExtTextOut call for a given
  538. * font face realization and brush.
  539. *
  540. * Arguments:
  541. *
  542. * NONE
  543. *
  544. * Return Value:
  545. *
  546. * non-NULL - prepared hdc
  547. * NULL - faceRealization or brush could not be represented in a DC
  548. *
  549. * Created:
  550. *
  551. * 3/7/2000 DBrown
  552. *
  553. \**************************************************************************/
  554. const DOUBLE PI = 3.1415926535897932384626433832795;
  555. HDC
  556. DpContext::GetTextOutputHdc(
  557. const GpFaceRealization *faceRealization, // In - Font face required
  558. GpColor color, // In - Required GdiPlus brush effect
  559. DpBitmap *surface, // In
  560. INT *angle // Out
  561. )
  562. {
  563. ASSERT(angle);
  564. if (Hwnd)
  565. {
  566. // Since GetHdc will create a new DC each time for Graphics created
  567. // from an hWnd, we can't track the currently selected font, and
  568. // the overhead of selecting the font and reselecting the original
  569. // font everytime would be inefficent. Therefore don't optimise text in
  570. // Graphics created from Hwnds.
  571. return NULL;
  572. }
  573. // GDI can't handle clearTtype or our sort of anti-aliasing
  574. if (faceRealization->RealizationMethod() != TextRenderingHintSingleBitPerPixelGridFit)
  575. {
  576. return NULL;
  577. }
  578. // If it is a private font, then we need to go through with GDI+
  579. if (faceRealization->IsPrivate())
  580. return NULL;
  581. // Check whether GDI can handle the brush and font size
  582. if (!color.IsOpaque())
  583. {
  584. return NULL; // GDI can only handle solid color brushes
  585. }
  586. if (faceRealization->GetFontFace()->IsSymbol())
  587. {
  588. return NULL;
  589. }
  590. // GDI can't handle the simulation.
  591. if (faceRealization->Getprface()->fobj.flFontType & (FO_SIM_BOLD | FO_SIM_ITALIC | FO_SIM_ITALIC_SIDEWAYS))
  592. {
  593. return NULL;
  594. }
  595. if (surface && (surface->Type == DpBitmap::CreationType::GPBITMAP))
  596. return NULL;
  597. // Check whether GDI can handle the glyph transform
  598. PointF scale;
  599. REAL rotateRadians;
  600. REAL shear;
  601. PointF translate;
  602. SplitTransform(
  603. faceRealization->Getprface()->mxForDDI,
  604. scale,
  605. rotateRadians,
  606. shear,
  607. translate);
  608. if ( scale.X / scale.Y < 0.999
  609. || scale.X / scale.Y > 1.0001)
  610. {
  611. return NULL; // Don't pass non 1:1 aspect ratios to GDI
  612. }
  613. if ( shear < -0.0001
  614. || shear > 0.0001)
  615. {
  616. return NULL; // GDI cannot handle shearing
  617. }
  618. // Translate rotation from radians in x-up to tenths of a degree in x-down.
  619. *angle = GpRound(float(3600.0 - (rotateRadians * 1800.0 / PI)));
  620. if (*angle >= 3600)
  621. {
  622. *angle -= 3600;
  623. }
  624. // under platform before NT 5.1 if there is a rotation, we need to render through GDI+
  625. // the main reason is a bug in the TrueType rasterizer that was causing in certain fonts
  626. // text to be rendered unhinted under 90, 180 and 270 degree rotations
  627. if ((*angle != 0) &&
  628. (!Globals::IsNt ||
  629. (Globals::OsVer.dwMajorVersion < 5) ||
  630. ((Globals::OsVer.dwMajorVersion == 5) && (Globals::OsVer.dwMinorVersion < 1)) ) )
  631. return NULL;
  632. // Prepare hdc for ExtTextOut
  633. HDC hdc = GetHdc(surface);
  634. if (!hdc)
  635. return NULL;
  636. INT style = faceRealization->Getprface()->Face->GetFaceStyle();
  637. // Select the font if not already selected by a previous caller
  638. GpStatus status = Ok;
  639. if (CurrentHFont == 0 || Face != faceRealization->Getprface()->Face
  640. || !FontTransform.IsEqual(&faceRealization->Getprface()->mxForDDI)
  641. || Style != style)
  642. {
  643. Face = faceRealization->Getprface()->Face;
  644. FontTransform = faceRealization->Getprface()->mxForDDI;
  645. Style = style;
  646. status = UpdateCurrentHFont(
  647. NONANTIALIASED_QUALITY,
  648. scale,
  649. *angle,
  650. hdc,
  651. FALSE); // Sideway
  652. }
  653. if (status == Ok)
  654. status = SelectCurrentHFont(hdc);
  655. if (status != Ok)
  656. {
  657. ReleaseHdc(hdc);
  658. return NULL;
  659. }
  660. if (GetBkMode(hdc) != TRANSPARENT)
  661. SetBkMode(hdc, TRANSPARENT);
  662. COLORREF colorRef = color.ToCOLORREF();
  663. SetTextColor(hdc, colorRef);
  664. if (GetTextAlign(hdc) != TA_BASELINE)
  665. SetTextAlign(hdc, TA_BASELINE); // !!! may need VTA_BASELINE or VTA_CENTRE for vertical?
  666. return hdc;
  667. }
  668. VOID DpContext::ReleaseTextOutputHdc(HDC hdc)
  669. {
  670. ::SelectObject(hdc, OriginalHFont);
  671. OriginalHFont = NULL;
  672. ReleaseHdc(hdc);
  673. } // DpContext::ReleaseTextOutputHdc
  674. VOID DpContext::DeleteCurrentHFont()
  675. {
  676. ASSERT(OriginalHFont == 0);
  677. if (CurrentHFont)
  678. {
  679. ::DeleteObject(CurrentHFont);
  680. CurrentHFont = 0;
  681. }
  682. } // DpContext::DeleteCurrentHFont
  683. GpStatus DpContext::UpdateCurrentHFont(
  684. BYTE quality,
  685. const PointF & scale,
  686. INT angle,
  687. HDC hdc,
  688. BOOL sideway,
  689. BYTE charSet
  690. )
  691. {
  692. if (charSet == 0xFF)
  693. charSet = Face->GetCharset(hdc);
  694. DeleteCurrentHFont();
  695. const LONG emHeight = GpRound(Face->GetDesignEmHeight() * scale.Y);
  696. const LONG emWidth = 0;
  697. LONG rotateDeciDegrees = angle;
  698. const LONG weight = (Style & FontStyleBold) ? 700 : 400;
  699. const BYTE fItalic = (Style & FontStyleItalic) ? TRUE : FALSE;
  700. if (sideway)
  701. {
  702. rotateDeciDegrees -= 900;
  703. if (rotateDeciDegrees < 0)
  704. {
  705. rotateDeciDegrees += 3600;
  706. }
  707. }
  708. // the GP_IFIMETRICS* Face->pifi is internally created structure
  709. // so we trust it is honestly null-terminated
  710. const WCHAR* pwszFamilyName = (const WCHAR*)( (BYTE*)Face->pifi + Face->pifi->dpwszFamilyName );
  711. int sizeFamilyName = wcslen(pwszFamilyName) + 1; // including terminating null
  712. if (Globals::IsNt) {
  713. LOGFONTW lfw = {
  714. -emHeight,
  715. emWidth,
  716. rotateDeciDegrees,
  717. rotateDeciDegrees,
  718. weight,
  719. fItalic,
  720. 0,
  721. 0,
  722. charSet, // charset
  723. OUT_TT_ONLY_PRECIS,
  724. 0,
  725. quality,
  726. 0,
  727. L""};
  728. if (sideway)
  729. {
  730. if (sizeFamilyName + 1 > LF_FACESIZE)
  731. return GenericError;
  732. lfw.lfFaceName[0] = 0x0040; // @
  733. memcpy(&lfw.lfFaceName[1], pwszFamilyName, sizeFamilyName*sizeof(WCHAR));
  734. }
  735. else
  736. {
  737. if (sizeFamilyName > LF_FACESIZE)
  738. return GenericError;
  739. memcpy(&lfw.lfFaceName[0], pwszFamilyName, sizeFamilyName*sizeof(WCHAR));
  740. }
  741. CurrentHFont = CreateFontIndirectW(&lfw);
  742. }
  743. else
  744. {
  745. // ANSI version for Win9X
  746. LOGFONTA lfa = {
  747. -emHeight,
  748. emWidth,
  749. rotateDeciDegrees,
  750. rotateDeciDegrees,
  751. weight,
  752. fItalic,
  753. 0,
  754. 0,
  755. charSet, // charset
  756. OUT_TT_ONLY_PRECIS,
  757. 0,
  758. quality,
  759. 0,
  760. ""};
  761. if (sideway)
  762. {
  763. if (sizeFamilyName + 1 > LF_FACESIZE)
  764. return GenericError;
  765. lfa.lfFaceName[0] = 0x40; // @
  766. UnicodeToAnsiStr(
  767. pwszFamilyName,
  768. &lfa.lfFaceName[1],
  769. LF_FACESIZE-1
  770. );
  771. }
  772. else
  773. {
  774. if (sizeFamilyName > LF_FACESIZE)
  775. return GenericError;
  776. UnicodeToAnsiStr(
  777. pwszFamilyName,
  778. lfa.lfFaceName,
  779. LF_FACESIZE
  780. );
  781. }
  782. CurrentHFont = CreateFontIndirectA(&lfa);
  783. }
  784. if (CurrentHFont == NULL)
  785. {
  786. return GenericError;
  787. }
  788. return Ok;
  789. } // DpContext::UpdateCurrentHFont
  790. GpStatus DpContext::SelectCurrentHFont(HDC hdc)
  791. {
  792. ASSERT(CurrentHFont != 0 && OriginalHFont == 0);
  793. OriginalHFont = (HFONT)::SelectObject(hdc, CurrentHFont);
  794. if (OriginalHFont == 0)
  795. return GenericError;
  796. return Ok;
  797. } // DpContext::SelectCurrentHFont
  798. // Used only when recording a EMF or EMF+ through GpMetafile class
  799. VOID
  800. DpContext::SetMetafileDownLevelRasterizationLimit(
  801. UINT metafileRasterizationLimitDpi
  802. )
  803. {
  804. if (metafileRasterizationLimitDpi > 0)
  805. {
  806. ASSERT(metafileRasterizationLimitDpi >= 10);
  807. MetafileRasterizationLimitDpi = (REAL)metafileRasterizationLimitDpi;
  808. }
  809. else
  810. {
  811. MetafileRasterizationLimitDpi = max(ContainerDpiX, ContainerDpiY);
  812. ASSERT(MetafileRasterizationLimitDpi >= 10);
  813. }
  814. DpContext * prev = Prev;
  815. // The MetafileRasterizationLimitDpi cannot be different in any
  816. // other saved context of the graphics. Update them all.
  817. while (prev != NULL)
  818. {
  819. prev->MetafileRasterizationLimitDpi = MetafileRasterizationLimitDpi;
  820. prev = prev->Prev;
  821. }
  822. }