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.

4302 lines
146 KiB

  1. /******************************Module*Header*******************************\
  2. * Module Name: textgdi.cxx
  3. *
  4. * Text APIs for NT graphics engine
  5. *
  6. * Created: 18-Dec-1990 10:09:19
  7. * Author: Donald Sidoroff [donalds]
  8. *
  9. * Copyright (c) 1990-1999 Microsoft Corporation
  10. \**************************************************************************/
  11. #include "precomp.hxx"
  12. EFLOAT efCos(EFLOAT x);
  13. EFLOAT efSin(EFLOAT x);
  14. extern PBRUSH gpbrText;
  15. extern PBRUSH gpbrBackground;
  16. #define XFORMNULL (EXFORMOBJ *) NULL
  17. // This is a tiny class just to make sure we don't forget to free up any
  18. // objects before leaving ExtTextOut.
  19. class TXTCLEANUP
  20. {
  21. XDCOBJ *pdco;
  22. public:
  23. TXTCLEANUP() {pdco=(DCOBJ *) NULL;}
  24. ~TXTCLEANUP() {if (pdco != (DCOBJ *) NULL) vMopUp();}
  25. VOID vSet(XDCOBJ& dco) {pdco = &dco;}
  26. VOID vMopUp();
  27. };
  28. VOID TXTCLEANUP::vMopUp()
  29. {
  30. RGNOBJ ro(pdco->pdc->prgnAPI());
  31. ro.bDeleteRGNOBJ();
  32. pdco->pdc->prgnAPI(NULL);
  33. }
  34. // Helper routine to draw a device coordinate RECTL into a path.
  35. BOOL bAddRectToPath(EPATHOBJ& po,RECTL *prcl)
  36. {
  37. POINTFIX aptfx[4];
  38. aptfx[3].x = aptfx[0].x = LTOFX(prcl->left);
  39. aptfx[1].y = aptfx[0].y = LTOFX(prcl->top);
  40. aptfx[2].x = aptfx[1].x = LTOFX(prcl->right);
  41. aptfx[3].y = aptfx[2].y = LTOFX(prcl->bottom);
  42. return(po.bAddPolygon(XFORMNULL,(POINTL *) aptfx,4));
  43. }
  44. /******************************Public*Routine******************************\
  45. * GreExtTextOutRect: Wrapper for common GreExtTextOutW code. This routine just
  46. * acquires locks then calls GreExtTextOutWLocked
  47. *
  48. * Arguments:
  49. *
  50. * Same as ExtTextOutRect
  51. *
  52. * Return Value:
  53. *
  54. * BOOL States
  55. *
  56. * History:
  57. *
  58. * 30-Oct-1995 - Initial version of wrapper
  59. *
  60. \**************************************************************************/
  61. BOOL
  62. GreExtTextOutRect(
  63. HDC hdc,
  64. LPRECT prcl
  65. )
  66. {
  67. BOOL bRet = FALSE;
  68. //
  69. // call GreExtTextOutW
  70. //
  71. XDCOBJ dcoDst(hdc);
  72. //
  73. // Validate the destination DC.
  74. //
  75. if (dcoDst.bValid())
  76. {
  77. DEVLOCKOBJ dlo;
  78. if (dlo.bLock(dcoDst))
  79. {
  80. if ((!dcoDst.bDisplay() || dcoDst.bRedirection()) || UserScreenAccessCheck())
  81. {
  82. bRet = ExtTextOutRect(
  83. dcoDst,
  84. prcl);
  85. }
  86. else
  87. {
  88. SAVE_ERROR_CODE(ERROR_ACCESS_DENIED);
  89. }
  90. }
  91. else
  92. {
  93. bRet = dcoDst.bFullScreen();
  94. }
  95. dcoDst.vUnlock();
  96. }
  97. return(bRet);
  98. }
  99. /******************************Public*Routine******************************\
  100. * ExtTextOutRect
  101. *
  102. * Called when just a Rectangle is passed. Over-used by Winbench4.0 the
  103. * perf app we aim to please.
  104. *
  105. * History:
  106. * 02-Nov-1993 -by- Patrick Haluptzok patrickh
  107. * Wrote it.
  108. \**************************************************************************/
  109. BOOL
  110. ExtTextOutRect(
  111. XDCOBJ &dcoDst,
  112. LPRECT prcl
  113. )
  114. {
  115. // Assume failure.
  116. BOOL bReturn;
  117. // Validate the destination DC.
  118. if (dcoDst.bValid())
  119. {
  120. ASSERTGDI(prcl != NULL, "This API must be past a valid rect");
  121. EXFORMOBJ xoDst(dcoDst, WORLD_TO_DEVICE);
  122. if (!xoDst.bRotation())
  123. {
  124. ERECTL erclDst(prcl->left, prcl->top, prcl->right, prcl->bottom);
  125. xoDst.bXform(erclDst);
  126. erclDst.vOrder();
  127. if (!erclDst.bEmpty())
  128. {
  129. // Accumulate bounds. We can do this before knowing if the operation is
  130. // successful because bounds can be loose.
  131. if (dcoDst.fjAccum())
  132. dcoDst.vAccumulate(erclDst);
  133. // Check surface is included in DC.
  134. SURFACE *pSurfDst = dcoDst.pSurface();
  135. if (pSurfDst != NULL)
  136. {
  137. // With a fixed DC origin we can change the destination to SCREEN coordinates.
  138. erclDst += dcoDst.eptlOrigin();
  139. ECLIPOBJ *pco = NULL;
  140. // This is a pretty knarly expression to save a return in here.
  141. // Basically pco can be NULL if the rect is completely in the
  142. // cached rect in the DC or if we set up a clip object that isn't empty.
  143. if (((erclDst.left >= dcoDst.prclClip()->left) &&
  144. (erclDst.right <= dcoDst.prclClip()->right) &&
  145. (erclDst.top >= dcoDst.prclClip()->top) &&
  146. (erclDst.bottom <= dcoDst.prclClip()->bottom)) ||
  147. (pco = dcoDst.pco(),
  148. pco->vSetup(dcoDst.prgnEffRao(), erclDst,CLIP_NOFORCETRIV),
  149. erclDst = pco->erclExclude(),
  150. (!erclDst.bEmpty())))
  151. {
  152. // Set up the brush if necessary.
  153. EBRUSHOBJ *pbo = dcoDst.peboBackground();
  154. if (dcoDst.bDirtyBrush(DIRTY_BACKGROUND))
  155. {
  156. dcoDst.vCleanBrush(DIRTY_BACKGROUND);
  157. XEPALOBJ palDst(pSurfDst->ppal());
  158. XEPALOBJ palDstDC(dcoDst.ppal());
  159. pbo->vInitBrush(dcoDst.pdc,
  160. gpbrBackground,
  161. palDstDC,
  162. palDst,
  163. pSurfDst,
  164. (dcoDst.flGraphicsCaps() & GCAPS_ARBRUSHOPAQUE) ? TRUE : FALSE);
  165. }
  166. DEVEXCLUDEOBJ dxo(dcoDst,&erclDst,pco);
  167. // Inc the target surface uniqueness
  168. INC_SURF_UNIQ(pSurfDst);
  169. // Dispatch the call.
  170. bReturn = (*(pSurfDst->pfnBitBlt()))
  171. (pSurfDst->pSurfobj(),
  172. (SURFOBJ *) NULL,
  173. (SURFOBJ *) NULL,
  174. pco,
  175. NULL,
  176. &erclDst,
  177. (POINTL *) NULL,
  178. (POINTL *) NULL,
  179. pbo,
  180. &dcoDst.pdc->ptlFillOrigin(),
  181. 0x0000f0f0);
  182. }
  183. else
  184. {
  185. bReturn = TRUE;
  186. }
  187. }
  188. else
  189. {
  190. bReturn = TRUE;
  191. }
  192. }
  193. else
  194. {
  195. bReturn = TRUE;
  196. }
  197. }
  198. else
  199. {
  200. // There is rotation involved - send it off to ExtTextOutW to handle it.
  201. bReturn = GreExtTextOutWLocked(dcoDst, 0, 0, ETO_OPAQUE,
  202. prcl, (LPWSTR) NULL, 0, NULL, dcoDst.pdc->jBkMode(), NULL, 0);
  203. }
  204. }
  205. else
  206. {
  207. WARNING1("ERROR TextOutRect called on invalid DC\n");
  208. bReturn = FALSE;
  209. }
  210. return(bReturn);
  211. }
  212. /******************************Public*Routine******************************\
  213. * BOOL GrePolyTextOut
  214. *
  215. * Write text with lots of random spacing and alignment options.
  216. *
  217. * Arguments:
  218. *
  219. * hdc - handle to DC
  220. * lpto - Ptr to array of polytext structures
  221. * nStrings - number of polytext structures
  222. *
  223. * Return Value:
  224. *
  225. * History:
  226. * Tue 09-Nov-1993 -by- Patrick Haluptzok [patrickh]
  227. * For code size we'll call ExtTextOutW. After the RFONT and brushes are
  228. * realized, the RaoRegion is setup etc, future calls to ExtTextOutW
  229. * will be very cheap. Plus ExtTextOut will be in the working set where a
  230. * huge GrePolyTextOut won't be. It is still a savings by avoiding kernel
  231. * transitions
  232. *
  233. \**************************************************************************/
  234. BOOL GrePolyTextOutW(
  235. HDC hdc,
  236. POLYTEXTW *lpto,
  237. UINT nStrings,
  238. DWORD dwCodePage
  239. )
  240. {
  241. BYTE CaptureBuffer[TEXT_CAPTURE_BUFFER_SIZE];
  242. BOOL bRet = TRUE;
  243. //
  244. // call GreExtTextOutW
  245. //
  246. XDCOBJ dcoDst(hdc);
  247. //
  248. // Validate the destination DC.
  249. //
  250. if (dcoDst.bValid())
  251. {
  252. DEVLOCKOBJ dlo;
  253. if (dlo.bLock(dcoDst))
  254. {
  255. for (POLYTEXTW *ppt = lpto; ppt < lpto+nStrings; ppt += 1)
  256. {
  257. //
  258. // Try to use stack buffer
  259. //
  260. PVOID pStrObjBuffer = NULL;
  261. ULONG cjStrObj = SIZEOF_STROBJ_BUFFER(ppt->n);
  262. if (TEXT_CAPTURE_BUFFER_SIZE >= cjStrObj)
  263. {
  264. pStrObjBuffer = CaptureBuffer;
  265. }
  266. if (!GreExtTextOutWLocked(
  267. dcoDst,
  268. ppt->x,
  269. ppt->y,
  270. ppt->uiFlags,
  271. &(ppt->rcl),
  272. (LPWSTR) ppt->lpstr,
  273. ppt->n,
  274. ppt->pdx,
  275. dcoDst.pdc->jBkMode(),
  276. pStrObjBuffer,
  277. dwCodePage))
  278. {
  279. WARNING1("GrePolyTextOutW failed a call to GreExtTextOutW\n");
  280. bRet = FALSE;
  281. break;
  282. }
  283. }
  284. }
  285. else
  286. {
  287. bRet = dcoDst.bFullScreen();
  288. }
  289. dcoDst.vUnlock();
  290. }
  291. else
  292. {
  293. WARNING1("GrePolyTextOutW: can not lock dc \n");
  294. SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
  295. bRet = FALSE;
  296. }
  297. return(bRet);
  298. }
  299. /******************************Public*Routine******************************\
  300. * GreExtTextOutW: Wrapper for common GreExtTextOutW code. This routine just
  301. * acquires locks then calls GreExtTextOutWLocked
  302. *
  303. * Arguments:
  304. *
  305. * Same as GreExtTextOutW
  306. *
  307. * Return Value:
  308. *
  309. * BOOL States
  310. *
  311. * History:
  312. *
  313. * 30-Oct-1995 - Initial version of wrapper
  314. *
  315. \**************************************************************************/
  316. // for user/kernel consumption only
  317. BOOL GreExtTextOutW(
  318. HDC hdc,
  319. int x,
  320. int y,
  321. UINT flOpts,
  322. CONST RECT *prcl,
  323. LPCWSTR pwsz,
  324. UINT cwc,
  325. CONST INT *pdx
  326. )
  327. {
  328. return GreExtTextOutWInternal(
  329. hdc,
  330. x,
  331. y,
  332. flOpts,
  333. (LPRECT)prcl,
  334. (LPWSTR)pwsz,
  335. (int) cwc,
  336. (LPINT)pdx,
  337. NULL,
  338. 0
  339. );
  340. }
  341. BOOL GreExtTextOutWInternal(
  342. HDC hdc,
  343. int x,
  344. int y,
  345. UINT flOpts,
  346. LPRECT prcl,
  347. LPWSTR pwsz,
  348. int cwc,
  349. LPINT pdx,
  350. PVOID pvBuffer,
  351. DWORD dwCodePage
  352. )
  353. {
  354. BOOL bRet = FALSE;
  355. //
  356. // call GreExtTextOutW
  357. //
  358. XDCOBJ dcoDst(hdc);
  359. //
  360. // Validate the destination DC.
  361. //
  362. if (dcoDst.bValid())
  363. {
  364. DEVLOCKOBJ dlo;
  365. if (dlo.bLock(dcoDst))
  366. {
  367. bRet = GreExtTextOutWLocked(
  368. dcoDst,
  369. x,
  370. y,
  371. flOpts,
  372. prcl,
  373. pwsz,
  374. cwc,
  375. pdx,
  376. dcoDst.pdc->jBkMode(),
  377. pvBuffer,
  378. dwCodePage);
  379. }
  380. else
  381. {
  382. bRet = dcoDst.bFullScreen();
  383. }
  384. dcoDst.vUnlock();
  385. }
  386. return(bRet);
  387. }
  388. /******************************Public*Routine******************************\
  389. * GreBatchTextOut: Set propper DC flags and attributes, then call textout
  390. * pr textoutrect.
  391. *
  392. * Arguments:
  393. *
  394. * dcoDst Locked DCOBJ
  395. * xoDst XFORMOBJ
  396. * pbText Batched textout entry
  397. *
  398. * Return Value:
  399. *
  400. * Status
  401. *
  402. * 14-Oct-1995 -by- Mark Enstrom [marke]
  403. *
  404. \**************************************************************************/
  405. #define ETO_NULL_PRCL 0x80000000
  406. BOOL
  407. GreBatchTextOut(
  408. XDCOBJ &dcoDst,
  409. PBATCHTEXTOUT pbText,
  410. ULONG cjBatchLength // cannot trust the Length field in pbText
  411. // because it is accessible to user-mode
  412. )
  413. {
  414. //
  415. // set foreground and background color in DC
  416. // and restore after call (if needed)
  417. //
  418. BYTE CaptureBuffer[TEXT_CAPTURE_BUFFER_SIZE];
  419. COLORREF crSaveText = (COLORREF)-1;
  420. COLORREF crSaveBack = (COLORREF)-1;
  421. HANDLE hlfntNewSave = NULL;
  422. UINT flTextAlignSave = -1;
  423. POINTL ptlViewportOrgSave;
  424. PVOID pStrObjBuffer = NULL;
  425. ULONG ulSaveText, ulSaveBack;
  426. if (pbText->Type == BatchTypeTextOutRect)
  427. {
  428. ASSERTGDI(((PBATCHTEXTOUTRECT)pbText)->fl & ETO_OPAQUE, "GreBatchTextOut, flags\n");
  429. crSaveBack = dcoDst.pdc->crBackClr();
  430. ulSaveBack = dcoDst.pdc->ulBackClr();
  431. if (crSaveBack != ((PBATCHTEXTOUTRECT)pbText)->BackColor)
  432. {
  433. dcoDst.pdc->crBackClr(((PBATCHTEXTOUTRECT)pbText)->BackColor);
  434. dcoDst.pdc->ulBackClr(((PBATCHTEXTOUTRECT)pbText)->ulBackColor);
  435. dcoDst.ulDirtyAdd(DIRTY_FILL|DIRTY_LINE|DIRTY_BACKGROUND);
  436. }
  437. ptlViewportOrgSave = dcoDst.pdc->ptlViewportOrg();
  438. if ((ptlViewportOrgSave.x != ((PBATCHTEXTOUTRECT)pbText)->ptlViewportOrg.x) ||
  439. (ptlViewportOrgSave.y != ((PBATCHTEXTOUTRECT)pbText)->ptlViewportOrg.y))
  440. {
  441. dcoDst.pdc->lViewportOrgX(((PBATCHTEXTOUTRECT)pbText)->ptlViewportOrg.x);
  442. dcoDst.pdc->lViewportOrgY(((PBATCHTEXTOUTRECT)pbText)->ptlViewportOrg.y);
  443. dcoDst.pdc->flSet_flXform(
  444. PAGE_XLATE_CHANGED |
  445. DEVICE_TO_WORLD_INVALID);
  446. }
  447. ExtTextOutRect(dcoDst,(LPRECT)&((PBATCHTEXTOUTRECT)pbText)->rcl);
  448. if (dcoDst.pdc->crBackClr() != crSaveBack)
  449. {
  450. dcoDst.pdc->crBackClr(crSaveBack);
  451. dcoDst.pdc->ulBackClr(ulSaveBack);
  452. dcoDst.ulDirtyAdd(DIRTY_FILL|DIRTY_LINE|DIRTY_BACKGROUND);
  453. }
  454. if ((ptlViewportOrgSave.x != dcoDst.pdc->lViewportOrgX()) ||
  455. (ptlViewportOrgSave.y != dcoDst.pdc->lViewportOrgY()))
  456. {
  457. dcoDst.pdc->lViewportOrgX(ptlViewportOrgSave.x);
  458. dcoDst.pdc->lViewportOrgY(ptlViewportOrgSave.y);
  459. dcoDst.pdc->flSet_flXform(
  460. PAGE_XLATE_CHANGED |
  461. DEVICE_TO_WORLD_INVALID);
  462. }
  463. }
  464. else
  465. {
  466. RECT newRect;
  467. LPRECT prcl;
  468. LPINT pdx = NULL;
  469. //
  470. // Capture the buffer length parameters from the TEB batch.
  471. // They can be overwritten by user-mode, so are not to be
  472. // trusted.
  473. //
  474. ULONG fl = pbText->fl;
  475. ULONG cChar = pbText->cChar;
  476. ULONG PdxOffset = pbText->PdxOffset;
  477. //
  478. // Check that char data will not overflow the data buffer.
  479. //
  480. ULONG cjBuf = cjBatchLength - offsetof(BATCHTEXTOUT, ulBuffer);
  481. if (cChar > (cjBuf / sizeof(WCHAR)))
  482. {
  483. WARNING("GreBatchTextOut: batch overflow char\n");
  484. return FALSE;
  485. }
  486. //
  487. // Check that optional pdx data will not overflow the data buffer.
  488. //
  489. if (PdxOffset != 0)
  490. {
  491. ULONG cjPdxPerChar;
  492. //
  493. // The pdx array must have cChar number of horizontal
  494. // deltas and, if the optional ETO_PDY flag is set, cChar
  495. // number of vertical deltas.
  496. //
  497. cjPdxPerChar = sizeof(INT);
  498. if (fl & ETO_PDY)
  499. cjPdxPerChar *= 2;
  500. //
  501. // Is the start and end of the pdx array in range?
  502. //
  503. if ((PdxOffset > cjBuf) ||
  504. (cChar > ((cjBuf - PdxOffset) / cjPdxPerChar)))
  505. {
  506. WARNING("GreBatchTextOut: batch overflow pdx\n");
  507. return FALSE;
  508. }
  509. //
  510. // Since we know that the pdx array is in range, go ahead
  511. // and set pdx.
  512. //
  513. pdx = (LPINT)((PUCHAR)&pbText->ulBuffer[0] + PdxOffset);
  514. }
  515. //
  516. // Set foreground and background text colors.
  517. //
  518. crSaveText = dcoDst.pdc->crTextClr();
  519. ulSaveText = dcoDst.pdc->ulTextClr();
  520. if (crSaveText != pbText->TextColor)
  521. {
  522. dcoDst.pdc->crTextClr(pbText->TextColor);
  523. dcoDst.pdc->ulTextClr(pbText->ulTextColor);
  524. dcoDst.ulDirtyAdd(DIRTY_FILL|DIRTY_LINE|DIRTY_TEXT);
  525. }
  526. crSaveBack = dcoDst.pdc->crBackClr();
  527. ulSaveBack = dcoDst.pdc->ulBackClr();
  528. if (crSaveBack != pbText->BackColor)
  529. {
  530. dcoDst.pdc->crBackClr(pbText->BackColor);
  531. dcoDst.pdc->ulBackClr(pbText->ulBackColor);
  532. dcoDst.ulDirtyAdd(DIRTY_FILL|DIRTY_LINE|DIRTY_BACKGROUND);
  533. }
  534. if (dcoDst.pdc->hlfntNew() != pbText->hlfntNew)
  535. {
  536. hlfntNewSave = dcoDst.pdc->hlfntNew();
  537. dcoDst.pdc->hlfntNew((HLFONT)pbText->hlfntNew);
  538. dcoDst.ulDirtyAdd(DIRTY_CHARSET);
  539. dcoDst.ulDirtySub(SLOW_WIDTHS);
  540. }
  541. if (dcoDst.pdc->flTextAlign() != pbText->flTextAlign)
  542. {
  543. flTextAlignSave = dcoDst.pdc->flTextAlign();
  544. dcoDst.pdc->flTextAlign(pbText->flTextAlign);
  545. }
  546. ptlViewportOrgSave = dcoDst.pdc->ptlViewportOrg();
  547. if ((ptlViewportOrgSave.x != pbText->ptlViewportOrg.x) ||
  548. (ptlViewportOrgSave.y != pbText->ptlViewportOrg.y))
  549. {
  550. dcoDst.pdc->lViewportOrgX(pbText->ptlViewportOrg.x);
  551. dcoDst.pdc->lViewportOrgY(pbText->ptlViewportOrg.y);
  552. dcoDst.pdc->flSet_flXform(
  553. PAGE_XLATE_CHANGED |
  554. DEVICE_TO_WORLD_INVALID);
  555. }
  556. if (fl & ETO_NULL_PRCL)
  557. {
  558. prcl = NULL;
  559. fl &= ~ETO_NULL_PRCL;
  560. }
  561. else
  562. {
  563. __try
  564. {
  565. newRect = ProbeAndReadStructure((LPRECT)&pbText->rcl,RECT);
  566. prcl = &newRect;
  567. }
  568. __except(EXCEPTION_EXECUTE_HANDLER)
  569. {
  570. WARNINGX(119);
  571. return FALSE;
  572. }
  573. }
  574. //
  575. // try to use stack based temp buffer
  576. //
  577. ULONG cjStrObj = SIZEOF_STROBJ_BUFFER(cChar);
  578. if (TEXT_CAPTURE_BUFFER_SIZE >= cjStrObj)
  579. {
  580. pStrObjBuffer = &CaptureBuffer[0];
  581. }
  582. GreExtTextOutWLocked(
  583. dcoDst,
  584. pbText->x,
  585. pbText->y,
  586. fl,
  587. prcl,
  588. (LPWSTR)&pbText->ulBuffer[0],
  589. cChar,
  590. pdx,
  591. pbText->BackMode,
  592. pStrObjBuffer,
  593. pbText->dwCodePage);
  594. //
  595. // Restore the foreground and background text colors.
  596. //
  597. if (dcoDst.pdc->crTextClr() != crSaveText)
  598. {
  599. dcoDst.pdc->crTextClr(crSaveText);
  600. dcoDst.pdc->ulTextClr(ulSaveText);
  601. dcoDst.ulDirtyAdd(DIRTY_FILL|DIRTY_LINE|DIRTY_TEXT);
  602. }
  603. if (dcoDst.pdc->crBackClr() != crSaveBack)
  604. {
  605. dcoDst.pdc->crBackClr(crSaveBack);
  606. dcoDst.pdc->ulBackClr(ulSaveBack);
  607. dcoDst.ulDirtyAdd(DIRTY_FILL|DIRTY_LINE|DIRTY_BACKGROUND);
  608. }
  609. if (hlfntNewSave != NULL)
  610. {
  611. dcoDst.pdc->hlfntNew(((HLFONT)hlfntNewSave));
  612. dcoDst.ulDirtyAdd(DIRTY_CHARSET);
  613. dcoDst.ulDirtySub(SLOW_WIDTHS);
  614. }
  615. if (flTextAlignSave != -1)
  616. {
  617. dcoDst.pdc->flTextAlign(flTextAlignSave);
  618. }
  619. if ((ptlViewportOrgSave.x != dcoDst.pdc->lViewportOrgX()) ||
  620. (ptlViewportOrgSave.y != dcoDst.pdc->lViewportOrgY()))
  621. {
  622. dcoDst.pdc->lViewportOrgX(ptlViewportOrgSave.x);
  623. dcoDst.pdc->lViewportOrgY(ptlViewportOrgSave.y);
  624. dcoDst.pdc->flSet_flXform(
  625. PAGE_XLATE_CHANGED |
  626. DEVICE_TO_WORLD_INVALID);
  627. }
  628. }
  629. return(TRUE);
  630. }
  631. /******************************Public*Routine******************************\
  632. * BOOL GreExtTextOutW (hdc,x,y,flOpts,prcl,pwsz,cwc,pdx,pvBuffer)
  633. *
  634. * Write text with lots of random spacing and alignment options.
  635. *
  636. * Below are the string length distributions from running the Winstone 95
  637. * scenarios for Excel and Winword, courtesy of KirkO:
  638. *
  639. * [Excel]
  640. * ------ OPAQUE ------- ----- TRANSPARENT ---
  641. * string length pdx == 0 pdx != 0 pdx == 0 pdx != 0
  642. * ------------- ---------- ---------- ---------- ----------
  643. * 0--9 3799 0 15323 9143
  644. * 10--19 695 0 1651 983
  645. * 20--29 527 0 196 22
  646. * 30--39 200 0 289 53
  647. * 40--49 12 0 3 0
  648. * 50--59 96 0 12 0
  649. * 60--69 10 0 4 0
  650. * 70--79 3 0 0 0
  651. * 80--89 0 0 0 0
  652. * 90--99 0 0 49 16
  653. * 100--109 11 0 0 0
  654. *
  655. * [Winword]
  656. *
  657. * ------ OPAQUE ------- ----- TRANSPARENT ---
  658. * string length pdx == 0 pdx != 0 pdx == 0 pdx != 0
  659. * ------------- ---------- ---------- ---------- ----------
  660. * 0--9 1875 9 3350 0
  661. * 10--19 878 17 324 0
  662. * 20--29 254 17 25 0
  663. * 30--39 93 6 28 2
  664. * 40--49 146 30 18 12
  665. * 50--59 34 16 3 14
  666. * 60--69 20 13 8 7
  667. * 70--79 128 73 13 18
  668. * 80--89 53 139 6 23
  669. * 90--99 41 903 9 127
  670. * 100--109 92 1878 3 217
  671. * 110--119 5 23 0 0
  672. *
  673. * History:
  674. * Fri 05-Nov-1993 -by- Patrick Haluptzok [patrickh]
  675. * Make smaller and faster.
  676. *
  677. * Sat 14-Mar-1992 06:08:26 -by- Charles Whitmer [chuckwh]
  678. * Rewrote it.
  679. *
  680. * Thu 03-Jan-1991 -by- Bodin Dresevic [BodinD]
  681. * Wrote it.
  682. \**************************************************************************/
  683. #define TS_DRAW_TEXT 0x0001
  684. #define TS_DRAW_OPAQUE_PGM 0x0002
  685. #define TS_DRAW_COMPLEX_UNDERLINES 0x0004
  686. #define TS_DRAW_OPAQUE_RECT 0x0008
  687. #define TS_DRAW_BACKGROUND_PGM 0x0010
  688. #define TS_DRAW_VECTOR_FONT 0x0020
  689. #define TS_DRAW_OUTLINE_FONT 0x0040
  690. #define TS_START_WITH_SUCCESS 0x0080
  691. // Due to the massiveness of this function we will use 2 space tabs.
  692. #if DBG // statistics
  693. typedef struct _TSTATENTRY {
  694. int c; // number observed
  695. } TSTATENTRY;
  696. typedef struct _TSTAT {
  697. TSTATENTRY NO; // pdx == 0, opaque
  698. TSTATENTRY DO; // pdx != 0, opaque
  699. TSTATENTRY NT; // pdx == 0, transparent
  700. TSTATENTRY DT; // pdx != 0, transparent
  701. } TSTAT;
  702. #define MAX_CHAR_COUNT 200 // observe for 0,1,..200,201 and above
  703. typedef struct _TEXTSTATS {
  704. int cchMax; // = MAX_CHAR_COUNT
  705. TSTAT ats[MAX_CHAR_COUNT+2];
  706. } TEXTSTATS;
  707. TEXTSTATS gTS = {MAX_CHAR_COUNT};
  708. #define TS_START 1
  709. #define TS_CONTINUE 2
  710. #define TS_VERBOSE 4
  711. #define TS_STOP 8
  712. FLONG gflTS = 0; // flags that control text statistics
  713. #endif // statistics
  714. BOOL GreExtTextOutWLocked(
  715. XDCOBJ &dco, // Locked DC
  716. int x, // Initial x position
  717. int y, // Initial y position
  718. UINT flOpts, // Options
  719. LPRECT prcl, // Clipping rectangle
  720. LPWSTR pwsz, // Unicode character array
  721. int cwc, // Count of characters
  722. LPINT pdx, // Character spacing
  723. ULONG ulBkMode, // Current background mode
  724. PVOID pvBuffer, // If non-NULL, contains a buffer for storing
  725. // the STROBJ, so that we don't need to
  726. // allocate one on the fly. Must be at
  727. // least SIZEOF_STROBJ_BUFFER(cwc) bytes in
  728. // size.
  729. // If NULL, we will try to use the global
  730. // STROBJ buffer, otherwise we will allocate
  731. // on the fly.
  732. DWORD dwCodePage // Code page for current textout
  733. )
  734. {
  735. // flState gets set with BITS for things we need to draw.
  736. // We also use this for the return value, setting it to 0 if an error occurs.
  737. BOOL bIsVectorFont = FALSE;
  738. BOOL bPathFont = FALSE;
  739. FLONG flState = TS_START_WITH_SUCCESS;
  740. BOOL flType = ((flOpts & ETO_GLYPH_INDEX) ? RFONT_TYPE_HGLYPH : RFONT_TYPE_UNICODE);
  741. // Win95 comaptibility: If in path bracket and ETO_CLIPPED is set, then fail call
  742. if ( dco.pdc->bActive() && ( flOpts & ETO_CLIPPED ) )
  743. {
  744. EngSetLastError( ERROR_INVALID_PARAMETER );
  745. return( FALSE );
  746. }
  747. if (dco.bDisplay() && !dco.bRedirection() && !UserScreenAccessCheck())
  748. {
  749. SAVE_ERROR_CODE(ERROR_ACCESS_DENIED);
  750. return( FALSE );
  751. }
  752. // ignore RTOLREADING flag,
  753. // only does something if lpk dlls are loaded under win95
  754. BOOL bPdy = flOpts & ETO_PDY;
  755. flOpts &= ~(ETO_PDY | ETO_GLYPH_INDEX | ETO_RTLREADING | ETO_IGNORELANGUAGE | ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN);
  756. if (!prcl)
  757. {
  758. flOpts &= ~(ETO_CLIPPED | ETO_OPAQUE); // ignore flags if no rect, win95 compat
  759. }
  760. else if ((prcl->left == prcl->right) || (prcl->top == prcl->bottom))
  761. {
  762. prcl->left = prcl->right = x;
  763. prcl->top = prcl->bottom = y;
  764. // now prcl is guaranteed to be within text rect
  765. if ((flOpts & (ETO_OPAQUE|ETO_CLIPPED)) == ETO_OPAQUE)
  766. {
  767. prcl = NULL; // since it is empty, we may as well ignore it
  768. flOpts &= ~ETO_OPAQUE; // ignore flag if no rect
  769. }
  770. }
  771. PFN_DrvTextOut pfnTextOut;
  772. MIX mix = R2_COPYPEN + 256*R2_COPYPEN; // default mix sent to TextOut routines
  773. // Lock the DC and set the new attributes.
  774. if (dco.bValid())
  775. {
  776. #if DBG // statistics
  777. if (gflTS & TS_START) {
  778. KdPrint((
  779. "\n"
  780. "***************************************\n"
  781. "*** BEGIN GreExtTextOutW statistics ***\n"
  782. "***************************************\n"
  783. "\n"
  784. ));
  785. RtlZeroMemory(gTS.ats, sizeof(TSTAT)*(gTS.cchMax+2));
  786. gflTS ^= TS_START;
  787. gflTS |= TS_CONTINUE;
  788. }
  789. if (gflTS & TS_CONTINUE) {
  790. TSTATENTRY *ptse;
  791. char *psz;
  792. TSTAT *pts;
  793. pts = gTS.ats + min(cwc,gTS.cchMax+1);
  794. ptse = 0;
  795. switch (ulBkMode)
  796. {
  797. case OPAQUE:
  798. ptse = (pdx) ? &(pts->DO) : &(pts->NO);
  799. psz = "OPAQUE";
  800. break;
  801. case TRANSPARENT:
  802. ptse = (pdx) ? &(pts->DT) : &(pts->NT);
  803. psz = "TRANSP";
  804. break;
  805. default:
  806. KdPrint(("jBkMode = UNKNOWN\n"));
  807. break;
  808. }
  809. if (ptse) {
  810. ptse->c += 1;
  811. if (gflTS & TS_VERBOSE)
  812. KdPrint((
  813. "%10d %10d %s %s"
  814. , min(cwc,gTS.cchMax+1)
  815. , ptse->c
  816. , psz
  817. , (pdx) ? "(pdx)" : ""
  818. ));
  819. }
  820. }
  821. if (gflTS & TS_STOP) {
  822. KdPrint((
  823. "\n"
  824. "*************************************\n"
  825. "*** END GreExtTextOutW statistics ***\n"
  826. "*************************************\n"
  827. "\n"
  828. ));
  829. gflTS = 0;
  830. }
  831. #endif // statistics
  832. // Check the validity of the flags.
  833. if
  834. (
  835. ((flOpts == 0) || ((prcl != (RECT *) NULL) && ((flOpts & ~(ETO_CLIPPED | ETO_OPAQUE)) == 0)))
  836. &&
  837. !(dco.pdc->bActive() && (flOpts & ETO_CLIPPED)) // no clipping in a path
  838. )
  839. {
  840. FLONG flControl = 0; // Set to 0 in case cwc is 0
  841. ERECTL rclExclude(0,0,0,0);
  842. // Lock the Rao region if we are drawing on a display surface. The Rao region
  843. // might otherwise change asynchronously. The DEVLOCKOBJ also makes sure that
  844. // the VisRgn is up to date, calling the window manager if necessary to
  845. // recompute it. This is needed if want to compute positions in screen coords.
  846. // No DEVLOCK is needed if we are in path accumulation mode.
  847. POINTL ptlOrigin; // The window origin.
  848. POINTFIX ptfxOrigin; // Same thing in FIX.
  849. if (dco.pdc->bActive())
  850. {
  851. ptlOrigin.x = 0;
  852. ptlOrigin.y = 0;
  853. }
  854. else
  855. {
  856. ptlOrigin = dco.eptlOrigin();
  857. }
  858. ptfxOrigin.x = LTOFX(ptlOrigin.x);
  859. ptfxOrigin.y = LTOFX(ptlOrigin.y);
  860. // Get the transform from the DC.
  861. EXFORMOBJ xo(dco, WORLD_TO_DEVICE);
  862. // Transform the input rectangle. In the simple case the result is in
  863. // rclInput. In the general case a parallelogram is in ptfxInput[4], and
  864. // bounds for the parallelogram are in rclInput.
  865. ERECTL rclInput;
  866. POINTFIX ptfxInput[4];
  867. // this must go after the DCOBJ, so that the DCOBJ still exists at cleanup
  868. TXTCLEANUP clean; // Mops up before exit.
  869. if (prcl != (RECT *) NULL)
  870. {
  871. if (flOpts & ETO_OPAQUE)
  872. {
  873. flState |= TS_DRAW_OPAQUE_RECT;
  874. }
  875. // The intent of the following bTranslationsOnly and bScale cases is to provide
  876. // faster inline versions of the same code that would be executed by xo.bXform(prcl).
  877. // We must be completely compatible with the normal xform code because apps expect
  878. // to opaque and clip to the same rectangles as a PatBlt would cover. So, if you
  879. // intend to modify the behavior of this code, make sure you change PatBlt and
  880. // BitBlt as well! (I.e. just don't do it.) [chuckwh]
  881. if (xo.bTranslationsOnly())
  882. {
  883. rclInput.left = prcl->left + ptlOrigin.x + FXTOL(xo.fxDx() + 8);
  884. rclInput.right = prcl->right + ptlOrigin.x + FXTOL(xo.fxDx() + 8);
  885. rclInput.top = prcl->top + ptlOrigin.y + FXTOL(xo.fxDy() + 8);
  886. rclInput.bottom = prcl->bottom + ptlOrigin.y + FXTOL(xo.fxDy() + 8);
  887. }
  888. else if (xo.bScale()) // Simple scaling.
  889. {
  890. rclInput.left = FXTOL(xo.fxFastX(prcl->left) + 8) + ptlOrigin.x;
  891. rclInput.right = FXTOL(xo.fxFastX(prcl->right) + 8) + ptlOrigin.x;
  892. rclInput.top = FXTOL(xo.fxFastY(prcl->top) + 8) + ptlOrigin.y;
  893. rclInput.bottom = FXTOL(xo.fxFastY(prcl->bottom) + 8) + ptlOrigin.y;
  894. }
  895. else // General case.
  896. {
  897. //
  898. // Construct three vertices of the input rectangle, in drawing order.
  899. //
  900. ptfxInput[0].x = prcl->left;
  901. ptfxInput[0].y = prcl->bottom;
  902. ptfxInput[1].x = prcl->left;
  903. ptfxInput[1].y = prcl->top;
  904. ptfxInput[2].x = prcl->right;
  905. ptfxInput[2].y = prcl->top;
  906. // Transform the vertices.
  907. xo.bXform((POINTL *) ptfxInput,ptfxInput,3);
  908. // We construct the fourth vertex ourselves to avoid excess transform
  909. // work and roundoff errors.
  910. ptfxInput[3].x = ptfxInput[0].x + ptfxInput[2].x - ptfxInput[1].x;
  911. ptfxInput[3].y = ptfxInput[0].y + ptfxInput[2].y - ptfxInput[1].y;
  912. // Bound the parallelogram. (Using Black Magic.)
  913. // DChinn: At this point, we know that EITHER points 0 and 2 OR
  914. // points 1 and 3 are the extreme x coordinates (left and right).
  915. // Similarly, EITHER points 0 and 2 OR points 1 and 3 are the extreme y
  916. // coordinates.
  917. //
  918. // ASSERT: it is possible that at this point, prcl is inverted
  919. // (i.e., left > right or top > bottom). If this is true, then
  920. // ptfxInput[] will have its points ordered counterclockwise rather
  921. // than clockwise.
  922. int ii;
  923. ii = (ptfxInput[1].x > ptfxInput[0].x)
  924. == (ptfxInput[1].x > ptfxInput[2].x);
  925. // Rounding direction depends on whether the parallelogram is inverted or not.
  926. if (ptfxInput[ii].x <= ptfxInput[ii+2].x)
  927. {
  928. rclInput.left = ptlOrigin.x + FXTOL(ptfxInput[ii].x);
  929. rclInput.right = ptlOrigin.x + FXTOLCEILING(ptfxInput[ii+2].x);
  930. }
  931. else
  932. {
  933. rclInput.left = ptlOrigin.x + FXTOLCEILING(ptfxInput[ii].x);
  934. rclInput.right = ptlOrigin.x + FXTOL(ptfxInput[ii+2].x);
  935. }
  936. ii = (ptfxInput[1].y > ptfxInput[0].y)
  937. == (ptfxInput[1].y > ptfxInput[2].y);
  938. // Rounding direction depends on whether the parallelogram is inverted or not.
  939. if (ptfxInput[ii].y <= ptfxInput[ii+2].y)
  940. {
  941. rclInput.top = ptlOrigin.y + FXTOL(ptfxInput[ii].y);
  942. rclInput.bottom = ptlOrigin.y + FXTOLCEILING(ptfxInput[ii+2].y);
  943. }
  944. else
  945. {
  946. rclInput.top = ptlOrigin.y + FXTOLCEILING(ptfxInput[ii].y);
  947. rclInput.bottom = ptlOrigin.y + FXTOL(ptfxInput[ii+2].y);
  948. }
  949. // Take care of a complex clipping request now. We'll set things up
  950. // so that the clipping will just happen automatically, and then clear
  951. // the clipping flag. This simplifies the rest of the code.
  952. if (flOpts & ETO_CLIPPED)
  953. {
  954. // Allocate a path. We know we're not already in a path bracket
  955. // since clipping requests in path brackets were rejected above.
  956. // Draw the parallelogram into it.
  957. PATHMEMOBJ po;
  958. if (po.bValid() && po.bAddPolygon(XFORMNULL,(POINTL *)&ptfxInput[0],4))
  959. {
  960. //
  961. // Construct a region from the path.
  962. //
  963. RECTL Bounds, *pBounds;
  964. // Only the top and bottom are used for clipping and
  965. // they have to be initialized as FIX.
  966. Bounds.top = LTOFX(dco.erclClip().top - ptlOrigin.y);
  967. Bounds.bottom = LTOFX(dco.erclClip().bottom - ptlOrigin.y);
  968. pBounds = &Bounds;
  969. RGNMEMOBJ rmo(po, ALTERNATE, pBounds);
  970. if (rmo.bValid())
  971. {
  972. // Stuff the region handle into the DC. This is a nifty trick
  973. // (courtesy of DonaldS) that uses this region in the next
  974. // calculation of the clipping pipeline. We'll clear the prgnAPI
  975. // after we're through.
  976. dco.pdc->prgnAPI(rmo.prgnGet());
  977. // Clipping is now transparent, so forget about it.
  978. clean.vSet(dco); // This frees the region on exit.
  979. if (dco.pdc->prgnRao() != (REGION *)NULL)
  980. {
  981. dco.pdc->vReleaseRao();
  982. }
  983. if (dco.pdc->bCompute())
  984. {
  985. flOpts &= ~ETO_CLIPPED;
  986. }
  987. // Now that we have a complex clip area, we can opaque with a
  988. // simple BitBlt. So we don't need to set TS_DRAW_OPAQUE_PGM.
  989. }
  990. }
  991. //
  992. // Well if we have succeeded we will have erased the ETO_CLIPPED flag.
  993. // Otherwise we failed and need to return FALSE. We can't return here
  994. // without generating tons of destructors so we set flState and a few
  995. // other fields to 0 so we bop down and return FALSE.
  996. //
  997. if (flOpts & ETO_CLIPPED)
  998. {
  999. flOpts = 0;
  1000. flState = 0;
  1001. cwc = 0;
  1002. }
  1003. }
  1004. else if (flOpts & ETO_OPAQUE)
  1005. {
  1006. flState &= ~TS_DRAW_OPAQUE_RECT;
  1007. flState |= TS_DRAW_OPAQUE_PGM;
  1008. // Since we're actually going to use it, offset the parallelogram
  1009. // to screen coordinates. use unrolled loop
  1010. EPOINTFIX *pptfx = (EPOINTFIX *) &ptfxInput[0];
  1011. *pptfx++ += ptfxOrigin;
  1012. *pptfx++ += ptfxOrigin;
  1013. *pptfx++ += ptfxOrigin;
  1014. *pptfx += ptfxOrigin;
  1015. }
  1016. }
  1017. // If it a mirrored DC then shift the rect one pixel to the right
  1018. // This will give the effect of including the right edge of the rect and exclude the left edge.
  1019. if (MIRRORED_DC(dco.pdc)) {
  1020. ++rclInput.left;
  1021. ++rclInput.right;
  1022. }
  1023. // Force the rectangle to be well ordered.
  1024. rclInput.vOrder();
  1025. // Add any opaquing into the exclusion area.
  1026. if (flState &
  1027. (TS_DRAW_OPAQUE_RECT | TS_DRAW_OPAQUE_PGM))
  1028. {
  1029. rclExclude += rclInput;
  1030. }
  1031. }
  1032. POINTFIX aptfxBackground[4]; // The TextBox.
  1033. BOOL bComplexBackground; // TRUE if the TextBox is a parallelogram.
  1034. RECTL *prclBackground = NULL; // Bkgnd rectangle passed to DrvTextOut.
  1035. RECTL *prclExtraRects = NULL; // Extra rectangles passed to DrvTextOut.
  1036. RFONTOBJ rfo;
  1037. ESTROBJ to;
  1038. if (cwc)
  1039. {
  1040. //
  1041. // Locate the font cache. Demand PATHOBJ's if we are in a path bracket.
  1042. //
  1043. rfo.vInit(dco, dco.pdc->bActive() ? TRUE : FALSE, flType);
  1044. if (rfo.bValid())
  1045. {
  1046. bPathFont = rfo.bPathFont();
  1047. bIsVectorFont = rfo.bPathFont() && !rfo.bReturnsOutlines();
  1048. // The recording of the simulation flags and escapement must come AFTER
  1049. // the rfont constructor since they're cached values that are copied from
  1050. // the LFONT only when the font is realized.
  1051. flControl = (dco.pdc->flTextAlign() & TA_MASK)
  1052. | dco.pdc->flSimulationFlags();
  1053. // Get the reference point.
  1054. EPOINTFIX ptfx;
  1055. if (flControl & TA_UPDATECP)
  1056. {
  1057. if (dco.pdc->bValidPtfxCurrent())
  1058. {
  1059. // Mark that we'll be updating the DC's CP in device coords only:
  1060. dco.pdc->vInvalidatePtlCurrent();
  1061. ptfx.x = dco.ptfxCurrent().x + ptfxOrigin.x;
  1062. ptfx.y = dco.ptfxCurrent().y + ptfxOrigin.y;
  1063. }
  1064. else
  1065. {
  1066. // DC's CP is in logical coords; we have to transform it to device
  1067. // space and mark that we'll be updating the CP in device space:
  1068. dco.pdc->vValidatePtfxCurrent();
  1069. dco.pdc->vInvalidatePtlCurrent();
  1070. if (xo.bTranslationsOnly())
  1071. {
  1072. ptfx.x = LTOFX(dco.ptlCurrent().x) + xo.fxDx();
  1073. ptfx.y = LTOFX(dco.ptlCurrent().y) + xo.fxDy();
  1074. }
  1075. else if (xo.bScale())
  1076. {
  1077. ptfx.x = xo.fxFastX(dco.ptlCurrent().x);
  1078. ptfx.y = xo.fxFastY(dco.ptlCurrent().y);
  1079. }
  1080. else
  1081. {
  1082. xo.bXform((POINTL *) &dco.ptlCurrent(), &ptfx, 1);
  1083. }
  1084. dco.ptfxCurrent() = ptfx;
  1085. ptfx += ptfxOrigin;
  1086. }
  1087. }
  1088. else
  1089. {
  1090. //
  1091. // The reference point is passed in. Transform it to device coords.
  1092. //
  1093. if (xo.bTranslationsOnly())
  1094. {
  1095. ptfx.x = LTOFX(x) + xo.fxDx() + ptfxOrigin.x;
  1096. ptfx.y = LTOFX(y) + xo.fxDy() + ptfxOrigin.y;
  1097. }
  1098. else if (xo.bScale())
  1099. {
  1100. ptfx.x = xo.fxFastX(x) + ptfxOrigin.x;
  1101. ptfx.y = xo.fxFastY(y) + ptfxOrigin.y;
  1102. }
  1103. else
  1104. {
  1105. ptfx.x = x;
  1106. ptfx.y = y;
  1107. xo.bXform((POINTL *) &ptfx,&ptfx,1);
  1108. ptfx += ptfxOrigin;
  1109. }
  1110. }
  1111. // The STROBJ will now compute the text alignment, character positions,
  1112. // and TextBox.
  1113. to.vInit
  1114. (
  1115. pwsz,
  1116. cwc,
  1117. dco,
  1118. rfo,
  1119. xo,
  1120. (LONG *) pdx,
  1121. bPdy,
  1122. dco.pdc->lEscapement(), // Only read this after RFONTOBJ!
  1123. dco.pdc->lTextExtra(),
  1124. dco.pdc->lBreakExtra(),
  1125. dco.pdc->cBreak(),
  1126. ptfx.x,ptfx.y,
  1127. flControl,
  1128. (LONG *) NULL,
  1129. pvBuffer,
  1130. dwCodePage
  1131. );
  1132. if (to.bValid())
  1133. {
  1134. // Compute the bounding box and the background opaquing area. The
  1135. // parallelogram aptfxBackground is only computed when it's complex.
  1136. bComplexBackground = to.bOpaqueArea(aptfxBackground,
  1137. &to.rclBkGround);
  1138. // This hack, due to filtering needs to be put in textgdi.cxx
  1139. // filtering leeks color one pixel to the left and one pixel to the right
  1140. // The trouble with it is that is it going to add a pixel on each side
  1141. // to the text background when text is painted in the OPAQUE mode.
  1142. if (rfo.pfo()->flFontType & FO_CLEARTYPE_X)
  1143. {
  1144. to.rclBkGround.left--;
  1145. to.rclBkGround.right++;
  1146. }
  1147. if (to.bLinkedGlyphs())
  1148. {
  1149. to.vEudcOpaqueArea(aptfxBackground, bComplexBackground);
  1150. }
  1151. // Accumulate the touched area to the exclusion rect.
  1152. rclExclude += to.rclBkGround;
  1153. // Make notes of exactly what drawing needs to be done.
  1154. if (ulBkMode == OPAQUE)
  1155. {
  1156. if (bComplexBackground)
  1157. {
  1158. flState |= TS_DRAW_BACKGROUND_PGM;
  1159. }
  1160. else
  1161. {
  1162. prclBackground = &to.rclBkGround; // No TS_ bit since this gets
  1163. } // passed directly to DrvTextOut.
  1164. }
  1165. // In a few bizarre cases the STROBJ can have an empty text rectangle
  1166. // we don't want to call DrvTextOut in those case but still need
  1167. // to worry about the opaque rectangle.
  1168. BOOL bEmptyTextRectangle = ((ERECTL *)&(to.rclBkGround))->bEmpty();
  1169. // Attempt to combine the rectangles. Even in transparent mode we should
  1170. // attempt to send an opaquing rectangle to DrvTextOut in prclBackground.
  1171. if ((flState & TS_DRAW_OPAQUE_RECT) &&
  1172. (rclInput.bContain(to.rclBkGround)) &&
  1173. (!bEmptyTextRectangle) )
  1174. {
  1175. prclBackground = &rclInput;
  1176. flState &= ~TS_DRAW_OPAQUE_RECT;
  1177. }
  1178. if ( ((prclBackground != NULL ) && !((ERECTL *)prclBackground)->bEmpty() ) ||
  1179. ((prclBackground == NULL) && !bEmptyTextRectangle) )
  1180. {
  1181. flState |= TS_DRAW_TEXT;
  1182. }
  1183. if (flControl & (TSIM_UNDERLINE1 | TSIM_STRIKEOUT))
  1184. {
  1185. if ((prclExtraRects = to.prclExtraRects()) == NULL)
  1186. {
  1187. flState |= TS_DRAW_COMPLEX_UNDERLINES;
  1188. }
  1189. else // include extra rectangles into the touched area:
  1190. {
  1191. ERECTL *eprcl = (ERECTL *) prclExtraRects;
  1192. for (; !eprcl->bEmpty(); eprcl++)
  1193. {
  1194. rclExclude += *eprcl;
  1195. }
  1196. }
  1197. }
  1198. // Accelerate the clipping case when it's irrelevant. (I'm concerned
  1199. // that a spreadsheet might tell us to clip to a cell, even though the
  1200. // string lies completely within.)
  1201. if (flOpts & ETO_CLIPPED)
  1202. {
  1203. if (rclInput.bContain(rclExclude))
  1204. {
  1205. flOpts &= ~ETO_CLIPPED;
  1206. }
  1207. else
  1208. {
  1209. rclExclude *= rclInput;
  1210. }
  1211. }
  1212. }
  1213. else // if (to.bValid())
  1214. {
  1215. flState = 0;
  1216. }
  1217. }
  1218. else // if (rfo.bValid())
  1219. {
  1220. flState = 0;
  1221. }
  1222. } // if (cwc)
  1223. if (flControl & TA_UPDATECP)
  1224. {
  1225. dco.ptfxCurrent().x += to.ptfxAdvance().x;
  1226. dco.ptfxCurrent().y += to.ptfxAdvance().y;
  1227. }
  1228. //
  1229. // Draw the text into a path if we're in a path bracket.
  1230. //
  1231. if (dco.pdc->bActive())
  1232. {
  1233. //
  1234. // We fail this call if we are asked to CLIP while in a path bracket.
  1235. //
  1236. if (flOpts & ETO_CLIPPED)
  1237. {
  1238. flState = 0;
  1239. }
  1240. XEPATHOBJ po(dco);
  1241. if (po.bValid())
  1242. {
  1243. // Draw the various background shapes.
  1244. if (flState & TS_DRAW_OPAQUE_RECT)
  1245. {
  1246. if (!bAddRectToPath(po,&rclInput))
  1247. {
  1248. flState = 0;
  1249. }
  1250. }
  1251. if (flState & TS_DRAW_OPAQUE_PGM)
  1252. {
  1253. if (!po.bAddPolygon(XFORMNULL,(POINTL *) &ptfxInput[0],4))
  1254. {
  1255. flState = 0;
  1256. }
  1257. }
  1258. if (flState & TS_DRAW_BACKGROUND_PGM)
  1259. {
  1260. if (!po.bAddPolygon(XFORMNULL,(POINTL *) aptfxBackground,4))
  1261. {
  1262. flState = 0;
  1263. }
  1264. }
  1265. BOOL bNeedUnflattend = FALSE;
  1266. //
  1267. // Draw the background rect, text, and extra rectangles.
  1268. //
  1269. if (flState & TS_DRAW_TEXT)
  1270. {
  1271. //
  1272. // Draw a background rectangle.
  1273. //
  1274. if ((prclBackground == (RECTL *) NULL) ||
  1275. bAddRectToPath(po,prclBackground))
  1276. {
  1277. //
  1278. // Draw the text.
  1279. //
  1280. bNeedUnflattend =
  1281. ( dco.flGraphicsCaps() & GCAPS_BEZIERS ) ? FALSE : TRUE;
  1282. if (!to.bTextToPath(po, dco, bNeedUnflattend))
  1283. {
  1284. flState = 0;
  1285. }
  1286. else
  1287. {
  1288. //
  1289. // Draw extra rectangles.
  1290. //
  1291. if (prclExtraRects != (ERECTL *) NULL)
  1292. {
  1293. ERECTL *eprcl = (ERECTL *) prclExtraRects;
  1294. for (; !eprcl->bEmpty(); eprcl++)
  1295. {
  1296. if (!bAddRectToPath(po,eprcl))
  1297. {
  1298. flState = 0;
  1299. break;
  1300. }
  1301. }
  1302. }
  1303. }
  1304. } // if ((prclBackground==0)||bAddRectToPath(po,prclBackground))
  1305. } // if (flState & TS_DRAW_TEXT)
  1306. //
  1307. // Handle complex cases of strikeout and underlines.
  1308. //
  1309. if (flState & TS_DRAW_COMPLEX_UNDERLINES)
  1310. {
  1311. if (!to.bExtraRectsToPath(po, bNeedUnflattend))
  1312. {
  1313. flState = 0;
  1314. }
  1315. }
  1316. } // if (po.bValid())
  1317. }
  1318. else // if (dco.pdc->bActive())
  1319. {
  1320. //
  1321. // If there's nothing to do, get out now.
  1322. //
  1323. if (!rclExclude.bEmpty())
  1324. {
  1325. // Accumulate bounds. We can do this before knowing if the operation is
  1326. // successful because bounds can be loose.
  1327. if (dco.fjAccum())
  1328. {
  1329. // Use a temporary exclusion rect in device coordinates.
  1330. ERECTL rclExcludeDev;
  1331. rclExcludeDev.left = rclExclude.left - ptlOrigin.x;
  1332. rclExcludeDev.right = rclExclude.right - ptlOrigin.x;
  1333. rclExcludeDev.top = rclExclude.top - ptlOrigin.y;
  1334. rclExcludeDev.bottom = rclExclude.bottom - ptlOrigin.y;
  1335. dco.vAccumulate(*((ERECTL *) &rclExcludeDev));
  1336. }
  1337. // Compute the clipping complexity and maybe reduce the exclusion rectangle.
  1338. // It appears that a 10pt script font (on a screen DC) can be outside of
  1339. // the bounds of the background rectangle. We have a situation where
  1340. // an app creates a memory DC exactly the size of the bouding rectangle
  1341. // and then draws a vector font to it. We compute the cliping to be
  1342. // trivial since we think the vector string fits completely inside
  1343. // the bounds of the DC and blow up later in the code. Rather than tweak
  1344. // the vector font driver at this point in the game I am going to force
  1345. // cliping to be set for vector fonts. Later on we should figure out
  1346. // why this is happening and fix the vector font driver. [gerritv]
  1347. // Under some xform, the text might be "stretched" to some extent length
  1348. // and it will go to the bSimpleFill path code. Force clipping for this
  1349. // case, otherwise we might hit the AV since recl's generated from the
  1350. // pathobj might be a pixel off than the clip rclBounds <seen in stress>.
  1351. ECLIPOBJ co(dco.prgnEffRao(),rclExclude,
  1352. bPathFont || (flOpts & ETO_CLIPPED) ? CLIP_FORCE :
  1353. CLIP_NOFORCE);
  1354. rclExclude = co.erclExclude();
  1355. // Check the destination which is reduced by clipping.
  1356. if (!co.erclExclude().bEmpty())
  1357. {
  1358. SURFACE *pSurf = dco.pSurface();
  1359. if (pSurf != NULL)
  1360. {
  1361. PDEVOBJ pdo(pSurf->hdev());
  1362. XEPALOBJ palDest(pSurf->ppal());
  1363. XEPALOBJ palDestDC(dco.ppal());
  1364. // Get the foreground and opaque brushes
  1365. FLONG flCaps = dco.flGraphicsCaps();
  1366. EBRUSHOBJ *peboText = dco.peboText();
  1367. EBRUSHOBJ *peboBackground = dco.peboBackground();
  1368. BOOL bDitherText = FALSE;
  1369. if ( flCaps & GCAPS_ARBRUSHTEXT )
  1370. {
  1371. // Even if a printer driver sets GCAPS_ARBRUSHTEXT, we
  1372. // can't allow vector fonts to be dithered.
  1373. bDitherText = !bIsVectorFont;
  1374. // We always dirty the text brush if ARBRUSHTEXT is set to
  1375. // catch the cases where we transition between vector and
  1376. // non-vector fonts but keep the same brush -- if we didn't
  1377. // do this, we might try to use a cached, dithered brush
  1378. // after switching from a TrueType font to a vector font.
  1379. dco.ulDirtyAdd(DIRTY_TEXT);
  1380. // Get through the are-you-really-dirty check in vInitBrush:
  1381. peboText->vInvalidateUniqueness();
  1382. }
  1383. if ( dco.bDirtyBrush(DIRTY_TEXT|DIRTY_BACKGROUND) )
  1384. {
  1385. if ( dco.bDirtyBrush(DIRTY_TEXT) )
  1386. {
  1387. peboText->vInitBrush(dco.pdc,
  1388. gpbrText,
  1389. palDestDC,
  1390. palDest,
  1391. pSurf,
  1392. bDitherText);
  1393. }
  1394. if ( dco.bDirtyBrush(DIRTY_BACKGROUND) )
  1395. {
  1396. peboBackground->vInitBrush(dco.pdc,
  1397. gpbrBackground,
  1398. palDestDC, palDest, pSurf,
  1399. (flCaps & GCAPS_ARBRUSHOPAQUE) ? TRUE : FALSE);
  1400. }
  1401. dco.vCleanBrush(DIRTY_TEXT|DIRTY_BACKGROUND);
  1402. }
  1403. // exclude the pointer
  1404. DEVEXCLUDEOBJ dxo(dco,&co.erclExclude(),&co);
  1405. //
  1406. // Draw background shapes that are too complex for DrvTextOut.
  1407. //
  1408. POINTL *pptlBO = &dco.pdc->ptlFillOrigin();
  1409. // There's an extra layer of conditional here so that simple text can just
  1410. // jump over it all.
  1411. if (flState &
  1412. (TS_DRAW_OPAQUE_RECT | TS_DRAW_OPAQUE_PGM | TS_DRAW_BACKGROUND_PGM))
  1413. {
  1414. if ((flState & TS_DRAW_OPAQUE_RECT) && !rclInput.bEmpty())
  1415. {
  1416. // intersect the dest rect with the clip rect and set it in co
  1417. // we can only get away with touching co.rclBounds after
  1418. // the ECLIPOBJ constructor because of two reasons:
  1419. // a) the target rectangle passed to bitblt is contained in the
  1420. // original bounds set by ECLIPOBJ, being the intersection
  1421. // of the origianal bounds with THE intended target rectangle.
  1422. // b) clipping complexity may have changed when we changed
  1423. // co.erclExclude, but it only could have gotten simpler,
  1424. // so at worst in those rare situations we would not go
  1425. // through the optimal code path.
  1426. // By changing clipping bounds we accomplish that no intersection
  1427. // of the target rectangle with clipping region rectangle is emtpy
  1428. // relieving the driver of extra work [bodind]
  1429. co.erclExclude().left = max(rclExclude.left,rclInput.left);
  1430. co.erclExclude().right = min(rclExclude.right,rclInput.right);
  1431. co.erclExclude().top = max(rclExclude.top,rclInput.top);
  1432. co.erclExclude().bottom = min(rclExclude.bottom,rclInput.bottom);
  1433. // if not clipped, Just paint the rectangle.
  1434. if ((co.erclExclude().left < co.erclExclude().right) &&
  1435. (co.erclExclude().top < co.erclExclude().bottom))
  1436. {
  1437. // Inc target surface uniqueness
  1438. INC_SURF_UNIQ(pSurf);
  1439. TextOutBitBlt(pSurf,
  1440. rfo,
  1441. (SURFOBJ *) NULL,
  1442. (SURFOBJ *) NULL,
  1443. &co,
  1444. NULL,
  1445. &co.rclBounds,
  1446. (POINTL *) NULL,
  1447. (POINTL *) NULL,
  1448. (BRUSHOBJ *)peboBackground,
  1449. pptlBO,
  1450. 0x0000f0f0);
  1451. }
  1452. co.erclExclude() = rclExclude;
  1453. }
  1454. if (flState & (TS_DRAW_OPAQUE_PGM | TS_DRAW_BACKGROUND_PGM))
  1455. {
  1456. PATHMEMOBJ po;
  1457. if (po.bValid())
  1458. {
  1459. if (flState & TS_DRAW_OPAQUE_PGM)
  1460. {
  1461. if (!po.bAddPolygon(XFORMNULL,(POINTL *) &ptfxInput[0],4))
  1462. {
  1463. flState = 0;
  1464. }
  1465. }
  1466. if (flState & TS_DRAW_BACKGROUND_PGM)
  1467. {
  1468. if (!po.bAddPolygon(XFORMNULL,(POINTL *) aptfxBackground,4))
  1469. {
  1470. flState = 0;
  1471. }
  1472. }
  1473. if (flState & (TS_DRAW_OPAQUE_PGM | TS_DRAW_BACKGROUND_PGM))
  1474. {
  1475. if (!po.bTextOutSimpleFill(dco,
  1476. rfo,
  1477. &pdo,
  1478. pSurf,
  1479. &co,
  1480. (BRUSHOBJ *)peboBackground,
  1481. pptlBO,
  1482. (R2_COPYPEN << 8) | R2_COPYPEN,
  1483. WINDING))
  1484. {
  1485. flState = 0;
  1486. }
  1487. } // if (flState & (TS_DRAW_OPAQUE_PGM | TS_DRAW_BACKGROUND_PGM))
  1488. } // if (po.bValid())
  1489. } // if (flState & (TS_DRAW_OPAQUE_PGM | TS_DRAW_BACKGROUND_PGM))
  1490. } // if (flState & (TS_DRAW_OPAQUE_RECT | TS_DRAW_OPAQUE_PGM | TS_DRAW_BACKGROUND_PGM))
  1491. //
  1492. // Draw the background rect, text, and extra rectangles.
  1493. //
  1494. if (flState & TS_DRAW_TEXT)
  1495. {
  1496. ERECTL *prclSimExtra = NULL;
  1497. // Prepare for a vector font simulation. Note that we'll also need to
  1498. // simulate the background and extra rectangles.
  1499. if (bPathFont)
  1500. {
  1501. flCaps &= ~(GCAPS_OPAQUERECT);
  1502. flState |= (rfo.bReturnsOutlines()) ? TS_DRAW_OUTLINE_FONT:TS_DRAW_VECTOR_FONT;
  1503. }
  1504. // Simulate a background rectangle.
  1505. if ((prclBackground != (RECTL *) NULL) &&
  1506. !(flCaps & GCAPS_OPAQUERECT))
  1507. {
  1508. // intersect the dest rect with the clip rect and set it in co
  1509. // we can only get away with touching co.rclBounds after
  1510. // the ECLIPOBJ constructor because of two reasons:
  1511. // a) the target rectangle passed to bitblt is contained in the
  1512. // original bounds set by ECLIPOBJ, being the intersection
  1513. // of the origianal bounds with THE intended target rectangle.
  1514. // b) clipping complexity may have changed when we changed
  1515. // co.erclExclude, but it only could have gotten simpler,
  1516. // so at worst in those rare situations we would not go
  1517. // through the optimal code path.
  1518. // By changing clipping bounds we accomplish that no intersection
  1519. // of the target rectangle with clipping region rectangle is emtpy
  1520. // relieving the driver of extra work [bodind]
  1521. co.erclExclude().left = max(rclExclude.left,prclBackground->left);
  1522. co.erclExclude().right = min(rclExclude.right,prclBackground->right);
  1523. co.erclExclude().top = max(rclExclude.top,prclBackground->top);
  1524. co.erclExclude().bottom = min(rclExclude.bottom,prclBackground->bottom);
  1525. // if not clipped, Just paint the rectangle.
  1526. if ((co.erclExclude().left < co.erclExclude().right) &&
  1527. (co.erclExclude().top < co.erclExclude().bottom))
  1528. {
  1529. // Inc target surface uniqueness
  1530. INC_SURF_UNIQ(pSurf);
  1531. TextOutBitBlt(pSurf,
  1532. rfo,
  1533. (SURFOBJ *) NULL,
  1534. (SURFOBJ *) NULL,
  1535. &co,
  1536. NULL,
  1537. &co.rclBounds,
  1538. (POINTL *) NULL,
  1539. (POINTL *) NULL,
  1540. (BRUSHOBJ *)peboBackground,
  1541. pptlBO,
  1542. 0x0000f0f0);
  1543. }
  1544. co.erclExclude() = rclExclude;
  1545. prclBackground = NULL;
  1546. }
  1547. // Prepare for the extra rectangle simulation.
  1548. // For TTY drivers, we need to pass prclExtraRects
  1549. // to the DrvTextOut call.
  1550. if ((prclExtraRects != (ERECTL *) NULL) &&
  1551. (pdo.ulTechnology() != DT_CHARSTREAM))
  1552. {
  1553. prclSimExtra = (ERECTL *) prclExtraRects;
  1554. prclExtraRects = NULL;
  1555. }
  1556. // Draw the text.
  1557. if (flState & TS_DRAW_VECTOR_FONT)
  1558. {
  1559. #ifdef FE_SB
  1560. if( to.bLinkedGlyphs() )
  1561. {
  1562. if( ! bProxyDrvTextOut
  1563. (
  1564. dco,
  1565. pSurf,
  1566. to,
  1567. co,
  1568. (RECTL*) NULL,
  1569. (RECTL*) NULL,
  1570. (BRUSHOBJ*) peboText,
  1571. (BRUSHOBJ*) peboBackground,
  1572. pptlBO,
  1573. rfo,
  1574. &pdo,
  1575. dco.flGraphicsCaps(),
  1576. &rclExclude
  1577. ))
  1578. {
  1579. flState = 0;
  1580. }
  1581. }
  1582. else
  1583. {
  1584. #endif
  1585. PATHMEMOBJ po;
  1586. if ((!po.bValid()) ||
  1587. (!to.bTextToPath(po, dco)) ||
  1588. (!po.bTextOutSimpleStroke1(dco,
  1589. rfo,
  1590. &pdo,
  1591. pSurf,
  1592. &co,
  1593. (BRUSHOBJ *)peboText,
  1594. pptlBO,
  1595. (R2_COPYPEN | (R2_COPYPEN << 8)))))
  1596. {
  1597. flState = 0;
  1598. }
  1599. }
  1600. }
  1601. else // if (flState & TS_DRAW_VECTOR_FONT)
  1602. {
  1603. if (pSurf->pdcoAA)
  1604. {
  1605. RIP("pdcoAA != 0\n");
  1606. pSurf->pdcoAA = 0; // let the free build run
  1607. }
  1608. pfnTextOut = pSurf->pfnTextOut();
  1609. // If the pointer to the TextOut function points to SpTextOut then
  1610. // we know that AntiAliased text can be handled and we can skip
  1611. // the funny business in the else clause
  1612. if (pfnTextOut == SpTextOut)
  1613. {
  1614. if (rfo.prfnt->fobj.flFontType & (FO_GRAY16 | FO_CLEARTYPE_X))
  1615. {
  1616. pSurf->pdcoAA = &dco;
  1617. }
  1618. }
  1619. else
  1620. {
  1621. if
  1622. (
  1623. (rfo.prfnt->fobj.flFontType & FO_GRAY16) &&
  1624. (!(dco.flGraphicsCaps() & GCAPS_GRAY16) ||
  1625. (rfo.prfnt->fobj.flFontType & FO_CLEARTYPE_X))
  1626. )
  1627. {
  1628. // Inform SpTextOut that this call came from GreExtTextOutW
  1629. // for the purpose of rendering anti aliased text on a device
  1630. // that does not support it. Remember to set this to zero
  1631. // before releasing the surface to other users.
  1632. if (pfnTextOut != EngTextOut)
  1633. pSurf->pdcoAA = &dco;
  1634. pfnTextOut = SpTextOut;
  1635. }
  1636. } // if (pfnTextOut == SpTextOut) else
  1637. if (flState & TS_DRAW_OUTLINE_FONT)
  1638. {
  1639. #ifdef FE_SB
  1640. if( to.bLinkedGlyphs() )
  1641. {
  1642. if( ! bProxyDrvTextOut
  1643. (
  1644. dco,
  1645. pSurf,
  1646. to,
  1647. co,
  1648. (RECTL*) NULL,
  1649. (RECTL*) NULL,
  1650. (BRUSHOBJ*) peboText,
  1651. (BRUSHOBJ*) peboBackground,
  1652. pptlBO,
  1653. rfo,
  1654. &pdo,
  1655. dco.flGraphicsCaps(),
  1656. &rclExclude
  1657. ))
  1658. {
  1659. flState = 0;
  1660. }
  1661. }
  1662. else
  1663. {
  1664. #endif
  1665. PATHMEMOBJ po;
  1666. if ((!po.bValid()) ||
  1667. (!to.bTextToPath(po, dco)) ||
  1668. ( ( po.cCurves > 1 ) &&
  1669. !po.bTextOutSimpleFill(dco,
  1670. rfo,
  1671. &pdo,
  1672. pSurf,
  1673. &co,
  1674. (BRUSHOBJ *)peboText,
  1675. pptlBO,
  1676. (R2_COPYPEN | (R2_COPYPEN << 8)),
  1677. WINDING)))
  1678. {
  1679. flState = 0;
  1680. }
  1681. }
  1682. }
  1683. else // if (flState & TS_DRAW_OUTLINE_FONT)
  1684. {
  1685. if (flState & TS_DRAW_COMPLEX_UNDERLINES)
  1686. {
  1687. INC_SURF_UNIQ(pSurf);
  1688. // Unfortunately, many drivers destroy the coordinates in our
  1689. // GLYPHPOS array. This means that any complex underlining has
  1690. // to be calculated now.
  1691. PATHMEMOBJ po;
  1692. if ((!po.bValid()) ||
  1693. (!to.bExtraRectsToPath(po)) ||
  1694. #ifdef FE_SB
  1695. ((to.bLinkedGlyphs() ) ?
  1696. (!bProxyDrvTextOut
  1697. (
  1698. dco,
  1699. pSurf,
  1700. to,
  1701. co,
  1702. prclExtraRects,
  1703. prclBackground,
  1704. peboText,
  1705. peboBackground,
  1706. pptlBO,
  1707. rfo,
  1708. (PDEVOBJ *) NULL,
  1709. (FLONG) 0L,
  1710. &rclExclude
  1711. )) :
  1712. #endif
  1713. (!((*pfnTextOut)
  1714. (pSurf->pSurfobj(),
  1715. (STROBJ *) &to,
  1716. rfo.pfo(),
  1717. &co,
  1718. prclExtraRects,
  1719. prclBackground,
  1720. (BRUSHOBJ *)peboText,
  1721. (BRUSHOBJ *)peboBackground,
  1722. pptlBO,
  1723. mix)))
  1724. ) ||
  1725. (!po.bTextOutSimpleFill(dco,
  1726. rfo,
  1727. &pdo,
  1728. pSurf,
  1729. &co,
  1730. (BRUSHOBJ *)peboText,
  1731. pptlBO,
  1732. (R2_COPYPEN | (R2_COPYPEN << 8)),
  1733. WINDING)))
  1734. {
  1735. flState = 0;
  1736. }
  1737. flState &= ~TS_DRAW_COMPLEX_UNDERLINES;
  1738. } // if (flState & TS_DRAW_COMPLEX_UNDERLINES)
  1739. else
  1740. {
  1741. // Inc target surface uniqueness
  1742. INC_SURF_UNIQ(pSurf);
  1743. #ifdef FE_SB
  1744. if( to.bLinkedGlyphs() )
  1745. {
  1746. if( !bProxyDrvTextOut
  1747. (
  1748. dco,
  1749. pSurf,
  1750. to,
  1751. co,
  1752. prclExtraRects,
  1753. prclBackground,
  1754. peboText,
  1755. peboBackground,
  1756. pptlBO,
  1757. rfo,
  1758. &pdo,
  1759. (FLONG) 0,
  1760. &rclExclude
  1761. ))
  1762. {
  1763. flState = 0;
  1764. }
  1765. }
  1766. else
  1767. {
  1768. #endif
  1769. rfo.PreTextOut(dco);
  1770. if (!(*pfnTextOut)(pSurf->pSurfobj(),
  1771. (STROBJ *) &to,
  1772. rfo.pfo(),
  1773. &co,
  1774. prclExtraRects,
  1775. prclBackground,
  1776. (BRUSHOBJ *)peboText,
  1777. (BRUSHOBJ *)peboBackground,
  1778. pptlBO,
  1779. mix))
  1780. {
  1781. flState = 0;
  1782. }
  1783. rfo.PostTextOut(dco);
  1784. }
  1785. } // if (flState & TS_DRAW_COMPLEX_UNDERLINES) else
  1786. } // if (flState & TS_DRAW_OUTLINE_FONT) else
  1787. ASSERTGDI(pSurf != NULL, "pSurf null after EngTextOut");
  1788. /* we have seen pSurf being null with privates binaries */
  1789. if (pSurf != NULL)
  1790. pSurf->pdcoAA = 0; // clear AA state;
  1791. } // if (flState & TS_DRAW_VECTOR_FONT) else
  1792. // Simulate extra rectangles.
  1793. if (prclSimExtra != (ERECTL *) NULL)
  1794. {
  1795. ERECTL erclOrg;
  1796. erclOrg = co.erclExclude();
  1797. // Inc target surface uniqueness
  1798. INC_SURF_UNIQ(pSurf);
  1799. for (; !prclSimExtra->bEmpty(); prclSimExtra++)
  1800. {
  1801. // intersect the dest rect with the clip rect and set it in co
  1802. co.erclExclude().left = max(erclOrg.left,prclSimExtra->left);
  1803. co.erclExclude().right = min(erclOrg.right,prclSimExtra->right);
  1804. if (co.erclExclude().left >= co.erclExclude().right)
  1805. continue;
  1806. co.erclExclude().top = max(erclOrg.top,prclSimExtra->top);
  1807. co.erclExclude().bottom = min(erclOrg.bottom,prclSimExtra->bottom);
  1808. if (co.erclExclude().top >= co.erclExclude().bottom)
  1809. {
  1810. continue;
  1811. }
  1812. //
  1813. // not completely clipped, do the bitblt
  1814. //
  1815. TextOutBitBlt(pSurf,
  1816. rfo,
  1817. (SURFOBJ *) NULL,
  1818. (SURFOBJ *) NULL,
  1819. &co,
  1820. NULL,
  1821. &co.rclBounds,
  1822. (POINTL *) NULL,
  1823. (POINTL *) NULL,
  1824. (BRUSHOBJ *)peboText,
  1825. pptlBO,
  1826. 0x0000f0f0);
  1827. }
  1828. co.erclExclude() = erclOrg;
  1829. } // if (prclSimExtra != (ERECTL *) NULL)
  1830. } // if (flState & TS_DRAW_TEXT)
  1831. //
  1832. // Handle complex cases of strikeout and underlines.
  1833. //
  1834. if (flState & TS_DRAW_COMPLEX_UNDERLINES)
  1835. {
  1836. PATHMEMOBJ po;
  1837. if (po.bValid())
  1838. {
  1839. if (!to.bExtraRectsToPath(po) ||
  1840. !po.bTextOutSimpleFill(dco,
  1841. rfo,
  1842. &pdo,
  1843. pSurf,
  1844. &co,
  1845. (BRUSHOBJ *)peboText,
  1846. pptlBO,
  1847. (R2_COPYPEN | (R2_COPYPEN << 8)),
  1848. WINDING))
  1849. {
  1850. flState = 0;
  1851. }
  1852. }
  1853. else // if (po.bValid())
  1854. {
  1855. flState = 0;
  1856. }
  1857. } // if (flState & TS_DRAW_COMPLEX_UNDERLINES)
  1858. } // if (pSurf != NULL)
  1859. } // if (!co.erclExclude().bEmpty())
  1860. } // if (!rclExclude.bEmpty())
  1861. } // else if (dco.pdc->bActive())
  1862. }
  1863. else // if (((flOpts == 0) ||
  1864. // ((prcl != (RECT *) NULL) &&
  1865. // ((flOpts & ~(ETO_CLIPPED | ETO_OPAQUE)) == 0)))
  1866. // && !(dco.pdc->bActive() && (flOpts & ETO_CLIPPED)))
  1867. {
  1868. WARNING1("Invalid flags for ExtTextOut.\n");
  1869. flState = 0;
  1870. }
  1871. }
  1872. else
  1873. {
  1874. flState = 0;
  1875. }
  1876. //
  1877. // flState is filled with all the stuff we need to do.
  1878. // If it is 0 we failed.
  1879. //
  1880. // return(flState /* != 0 */);
  1881. return(flState != 0);
  1882. }
  1883. /******************************Public*Routine******************************\
  1884. * BOOL GreGetTextExtentW
  1885. *
  1886. * Computes the size of the text box in logical coordinates. The text box
  1887. * has sides which are parallel to the baseline of the text and its ascent
  1888. * direction. The height is measured in the ascent direction. The width
  1889. * is measured in the baseline direction. This definition does not change
  1890. * for transformed text.
  1891. *
  1892. * History:
  1893. * Sat 14-Mar-1992 05:39:04 -by- Charles Whitmer [chuckwh]
  1894. * Wrote it.
  1895. \**************************************************************************/
  1896. #define PDXNULL (LONG *) NULL
  1897. BOOL GreGetTextExtentW(
  1898. HDC hdc, // device context
  1899. LPWSTR pwsz, // pointer to a UNICODE text string
  1900. int cwc, // Count of chars.
  1901. PSIZE pSize, // address to return the dimensions of the string to
  1902. UINT fl // internal flags
  1903. )
  1904. {
  1905. BOOL bRet = FALSE;
  1906. if (cwc == 0)
  1907. {
  1908. //
  1909. // Nothing to do, but we do not fail.
  1910. //
  1911. pSize->cx = 0;
  1912. pSize->cy = 0;
  1913. bRet = TRUE;
  1914. }
  1915. else
  1916. {
  1917. //
  1918. // Lock the DC and set the new attributes.
  1919. //
  1920. DCOBJ dco(hdc);
  1921. if (dco.bValid())
  1922. {
  1923. RFONTOBJ rfo(dco,FALSE, (fl & GGTE_GLYPH_INDEX) ? RFONT_TYPE_HGLYPH : RFONT_TYPE_UNICODE);
  1924. if (rfo.bValid())
  1925. {
  1926. // fix up glyph indices for bitmap fonts
  1927. if (rfo.prfnt->flType & RFONT_TYPE_HGLYPH)
  1928. rfo.vFixUpGlyphIndices((USHORT *)pwsz, cwc);
  1929. // If we have (escapement != orientation) we return the extents of the
  1930. // bounding parallelogram. This is not Windows compatible, but then
  1931. // Windows can't draw it either.
  1932. LONG lEsc = dco.pdc->lEscapement(); // Only read this after RFONTOBJ!
  1933. if ((lEsc != (LONG)rfo.ulOrientation()) &&
  1934. ((rfo.iGraphicsMode() != GM_COMPATIBLE) ||
  1935. (rfo.prfnt->flInfo & FM_INFO_TECH_STROKE)))
  1936. {
  1937. //
  1938. // Get the transform from the DC.
  1939. //
  1940. EXFORMOBJ xo(dco,WORLD_TO_DEVICE);
  1941. //
  1942. // The STROBJ will now compute the text alignment, character positions,
  1943. // and TextBox.
  1944. //
  1945. ESTROBJ to(pwsz,
  1946. cwc,
  1947. dco,
  1948. rfo,
  1949. xo,
  1950. PDXNULL,FALSE,
  1951. lEsc,
  1952. dco.pdc->lTextExtra(),
  1953. dco.pdc->lBreakExtra(),
  1954. dco.pdc->cBreak(),
  1955. 0,
  1956. 0,
  1957. 0,
  1958. PDXNULL);
  1959. if (to.bValid())
  1960. {
  1961. //
  1962. // Transform the TextBox to logical coordinates.
  1963. //
  1964. bRet = to.bTextExtent(rfo,lEsc,pSize);
  1965. }
  1966. }
  1967. else
  1968. {
  1969. //
  1970. // At this point we have (escapement == orientation) so we can just run
  1971. // some pretty trivial code.
  1972. //
  1973. bRet = rfo.bTextExtent(dco,
  1974. pwsz,
  1975. cwc,
  1976. lEsc,
  1977. dco.pdc->lTextExtra(),
  1978. dco.pdc->lBreakExtra(),
  1979. dco.pdc->cBreak(),
  1980. fl,
  1981. pSize);
  1982. //
  1983. // finally if this is compatible mode and a vector font, do win31
  1984. // crazyness about text extent: "rotate" cx and cy by esc vector.
  1985. // This is totally crazy, and is different from what win31 is doing
  1986. // for tt, but it turns out that quatro pro for windows has figured
  1987. // this out and that they use this "feature" [bodind]
  1988. //
  1989. if (bRet &&
  1990. lEsc &&
  1991. (dco.pdc->iGraphicsMode() == GM_COMPATIBLE) &&
  1992. !dco.pdc->bUseMetaPtoD() &&
  1993. (rfo.prfnt->flInfo & FM_INFO_TECH_STROKE))
  1994. {
  1995. EVECTORFL evfl((LONG)pSize->cx, (LONG)pSize->cy);
  1996. EFLOATEXT efAngle = lEsc;
  1997. efAngle /= (LONG)10;
  1998. MATRIX mx;
  1999. mx.efM11 = efCos(efAngle);
  2000. mx.efM11.vAbs();
  2001. mx.efM22 = mx.efM11;
  2002. mx.efM12 = efSin(efAngle);
  2003. mx.efM12.vAbs();
  2004. mx.efM21 = mx.efM12;
  2005. mx.efDx.vSetToZero();
  2006. mx.efDy.vSetToZero();
  2007. EXFORMOBJ xoExt(&mx,COMPUTE_FLAGS | XFORM_FORMAT_LTOL);
  2008. if ((bRet = xoExt.bXform(evfl)) != FALSE)
  2009. {
  2010. evfl.x.vAbs();
  2011. evfl.y.vAbs();
  2012. bRet = evfl.bToPOINTL(*(POINTL *)pSize);
  2013. }
  2014. }
  2015. }
  2016. }
  2017. else
  2018. {
  2019. WARNING("gdisrv!GreGetTextExtentW(): could not lock HRFONT\n");
  2020. }
  2021. }
  2022. }
  2023. return(bRet);
  2024. }
  2025. /******************************Public*Routine******************************\
  2026. * RFONTOBJ::bTextExtent (pwsz,lExtra,lBreakExtra,cBreak,cc,fl,psizl) *
  2027. * *
  2028. * A quick function to compute text extents on the server side. Only *
  2029. * handles the case where (escapement==orientation). Call the ESTROBJ *
  2030. * version for the other very hard case. *
  2031. * *
  2032. * Thu 14-Jan-1993 04:00:57 -by- Charles Whitmer [chuckwh] *
  2033. * Wrote it. OK, so it's a blatant ripoff of my bComputeTextExtent from *
  2034. * the client side. Fine. *
  2035. \**************************************************************************/
  2036. #define CTE_BATCH 82
  2037. BOOL RFONTOBJ::bTextExtent(
  2038. XDCOBJ &dco,
  2039. LPWSTR pwsz,
  2040. int cc,
  2041. LONG lEsc,
  2042. LONG lExtra,
  2043. LONG lBreakExtra,
  2044. LONG cBreak,
  2045. UINT fl,
  2046. SIZE *psizl
  2047. )
  2048. {
  2049. LONG fxBasicExtent;
  2050. int ii, cNoBackup;
  2051. FIX fxCharExtra = 0;
  2052. FIX fxBreakExtra;
  2053. FIX fxExtra = 0;
  2054. GLYPHPOS agpos[CTE_BATCH]; // Default set of GLYPHPOS structures.
  2055. // Compute the basic extent. Batch the glyphs through our array.
  2056. if (lExtra)
  2057. {
  2058. fxCharExtra = lCvt(efWtoDBase(),lExtra);
  2059. cNoBackup = 0;
  2060. }
  2061. #ifndef FE_SB
  2062. if(lCharInc() == 0)
  2063. #endif
  2064. {
  2065. fxBasicExtent = 0;
  2066. // NOTE PERF: This is the loop that PaulB would like to optimize with a
  2067. // special cache access function. Why create the GLYPHPOS
  2068. // array? [chuckwh]
  2069. int cBatch;
  2070. int cLeft = cc;
  2071. WCHAR *pwc = pwsz;
  2072. while (cLeft)
  2073. {
  2074. cBatch = cLeft;
  2075. if (cBatch > CTE_BATCH)
  2076. cBatch = CTE_BATCH;
  2077. // Get the glyph data.
  2078. if (!bGetGlyphMetrics(cBatch,agpos,pwc,&dco))
  2079. return(FALSE);
  2080. // Sum the advance widths.
  2081. for (ii=0; ii<cBatch; ii++)
  2082. {
  2083. fxBasicExtent += ((EGLYPHPOS *) &agpos[ii])->pgd()->fxD;
  2084. // the layout code won't allow lExtra to backup a character behind
  2085. // its origin so keep track of the number of times this happens
  2086. if( ( fxCharExtra < 0 ) &&
  2087. ( ((EGLYPHPOS *) &agpos[ii])->pgd()->fxD + fxCharExtra <= 0 ) )
  2088. {
  2089. cNoBackup += 1;
  2090. }
  2091. }
  2092. cLeft -= cBatch;
  2093. pwc += cBatch;
  2094. }
  2095. }
  2096. // Adjust for CharExtra.
  2097. if (lExtra)
  2098. {
  2099. PDEVOBJ pdo(prfnt->hdevConsumer);
  2100. ASSERTGDI(pdo.bValid(), "bTextExtentRFONTOBJ(): PDEVOBJ constructor failed\n");
  2101. if ( (fl & GGTE_WIN3_EXTENT) && pdo.bDisplayPDEV()
  2102. && (!(prfnt->flInfo & FM_INFO_TECH_STROKE)) )
  2103. fxExtra = fxCharExtra * ((lExtra > 0) ? cc : (cc - 1));
  2104. else
  2105. fxExtra = fxCharExtra * ( cc - cNoBackup );
  2106. }
  2107. // Adjust for lBreakExtra.
  2108. if (lBreakExtra && cBreak)
  2109. {
  2110. // Track down the break character.
  2111. PFEOBJ pfeo(ppfe());
  2112. IFIOBJ ifio(pfeo.pifi());
  2113. // Compute the extra space in device units.
  2114. fxBreakExtra = lCvt(efWtoDBase(),lBreakExtra) / cBreak;
  2115. // Windows won't let us back up over a break. Set up the BreakExtra
  2116. // to just cancel out what we've already got.
  2117. if (fxBreakExtra + fxBreak() + fxCharExtra < 0)
  2118. fxBreakExtra = -(fxBreak() + fxCharExtra);
  2119. // Add it up for all breaks.
  2120. WCHAR wcBreak = (fl & GGTE_GLYPH_INDEX)?
  2121. (WCHAR)hgBreak():ifio.wcBreakChar();
  2122. WCHAR *pwc = pwsz;
  2123. for (ii=0; ii<cc; ii++)
  2124. {
  2125. if (*pwc++ == wcBreak)
  2126. fxExtra += fxBreakExtra;
  2127. }
  2128. }
  2129. // Add in the extra stuff.
  2130. fxBasicExtent += fxExtra;
  2131. // Add in the overhang for font simulations.
  2132. if (fl & GGTE_WIN3_EXTENT)
  2133. fxBasicExtent += lOverhang() << 4;
  2134. // Transform the result to logical coordinates.
  2135. if (efDtoWBase_31().bIs1Over16())
  2136. psizl->cx = (fxBasicExtent + 8) >> 4;
  2137. else
  2138. psizl->cx = lCvt(efDtoWBase_31(),fxBasicExtent);
  2139. if (efDtoWAscent_31().bIs1Over16())
  2140. psizl->cy = lMaxHeight();
  2141. else
  2142. psizl->cy = lCvt(efDtoWAscent_31(),lMaxHeight() << 4);
  2143. #ifdef FE_SB
  2144. if( gbDBCSCodePage && // Only in DBCS system locale
  2145. (iGraphicsMode() == GM_COMPATIBLE) && // We are in COMPAPIBLE mode
  2146. !(flInfo() & FM_INFO_ARB_XFORMS) && // The driver couldnt do arbitrary rotations
  2147. !(flInfo() & FM_INFO_TECH_STROKE) && // The driver is not vector driver
  2148. (flInfo() & FM_INFO_90DEGREE_ROTATIONS) && // Driver does 90 degree rotations
  2149. (lEsc == 900L || lEsc == 2700L) // Current font Escapemant is 900 or 2700
  2150. )
  2151. {
  2152. LONG lSwap = psizl->cx;
  2153. psizl->cx = psizl->cy;
  2154. psizl->cy = lSwap;
  2155. }
  2156. #endif
  2157. return(TRUE);
  2158. }
  2159. /******************************Public*Routine******************************\
  2160. * GreSetTextJustification (hdc,lBreakExtra,cBreak) *
  2161. * *
  2162. * Sets the amount of extra spacing we'd like to add for each break (space) *
  2163. * character to (lBreakExtra/cBreak) in logical coordinates. *
  2164. * *
  2165. * History: *
  2166. * Fri 13-Mar-1992 02:25:12 -by- Charles Whitmer [chuckwh] *
  2167. * Wrote it. *
  2168. \**************************************************************************/
  2169. BOOL APIENTRY
  2170. NtGdiSetTextJustification(
  2171. HDC hdc,
  2172. int lBreakExtra, // Space in logical units to be added to the line.
  2173. int cBreak // Number of break chars in the line.
  2174. )
  2175. {
  2176. BOOL bRet;
  2177. DCOBJ dco(hdc);
  2178. if ((bRet = dco.bValid()) != FALSE)
  2179. {
  2180. dco.pdc->lBreakExtra(lBreakExtra);
  2181. dco.pdc->cBreak(cBreak);
  2182. }
  2183. return(bRet);
  2184. }
  2185. /******************************Public*Routine******************************\
  2186. * BOOL GreGetTextExtentExW *
  2187. * *
  2188. * Determines the number of characters in the input string that fit into *
  2189. * the given max width (with the widths computed along the escapement *
  2190. * vector). The partial widths (the distance from the string origin to *
  2191. * a given character with the width of that character included) for each of *
  2192. * character. *
  2193. * *
  2194. * Returns: *
  2195. * TRUE if successful, FALSE otherwise. *
  2196. * *
  2197. * History: *
  2198. * Sat 14-Mar-1992 06:03:32 -by- Charles Whitmer [chuckwh] *
  2199. * Rewrote with new ESTROBJ technology. *
  2200. * *
  2201. * 06-Jan-1992 -by- Gilman Wong [gilmanw] *
  2202. * Wrote it. *
  2203. \**************************************************************************/
  2204. BOOL GreGetTextExtentExW(
  2205. HDC hdc, // device context
  2206. LPWSTR pwsz, // pointer to a UNICODE text string
  2207. COUNT cwc, // count of WCHARs in the string
  2208. ULONG dxMax, // maximum width to return
  2209. COUNT *pcChars, // number of chars that fit in dxMax
  2210. PULONG pdxOut, // offset of each character from string origin
  2211. LPSIZE pSize, // return height and width of string
  2212. FLONG fl
  2213. )
  2214. {
  2215. BOOL bRet = FALSE;
  2216. PVOID pv;
  2217. #ifdef DUMPCALL
  2218. DbgPrint("\nGreGetTextExtentExW(" );
  2219. DbgPrint("\n HDC hdc = %-#8lx\n", hdc );
  2220. DbgPrint("\n LPWSTR pwsz = %-#8lx -> \"%ws\"\n", pwsz ,pwsz );
  2221. DbgPrint("\n COUNT cwc = %d\n", cwc );
  2222. DbgPrint("\n ULONG dxMax = %-#8lx\n", dxMax );
  2223. DbgPrint("\n COUNT *pcChars = %-#8lx\n", pcChars);
  2224. DbgPrint("\n PULONG pdxOut = %-#8lx\n", pdxOut );
  2225. DbgPrint("\n LPSIZE pSize = %-#8lx\n", pSize );
  2226. DbgPrint("\n )\n" );
  2227. #endif
  2228. // Parameter validation.
  2229. if ( ((pwsz == (LPWSTR) NULL) && (cwc != 0))
  2230. || (pSize == (LPSIZE) NULL) )
  2231. {
  2232. WARNING("gdisrv!GreGetTextExtentExW(): invalid parameter\n");
  2233. SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
  2234. return (FALSE);
  2235. }
  2236. // Early out.
  2237. if (cwc == 0L) // Nothing to do, but we do not fail.
  2238. {
  2239. if ( pcChars != (COUNT *) NULL )
  2240. {
  2241. *pcChars = 0;
  2242. }
  2243. return(TRUE);
  2244. }
  2245. // Lock the DC and set the new attributes.
  2246. DCOBJ dco(hdc);
  2247. if (!dco.bValid())
  2248. {
  2249. WARNING("gdisrv!GreGetTextExtentExW(): invalid HDC\n");
  2250. SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
  2251. }
  2252. else
  2253. {
  2254. // Get the transform.
  2255. EXFORMOBJ xo(dco, WORLD_TO_DEVICE);
  2256. // Realize font and get the simulation flags and escapement.
  2257. RFONTOBJ rfo(dco, FALSE, (fl & GTEEX_GLYPH_INDEX) ? RFONT_TYPE_HGLYPH : RFONT_TYPE_UNICODE);
  2258. if (!rfo.bValid())
  2259. {
  2260. WARNING("gdisrv!GreGetTextExtentExW(): could not lock HRFONT\n");
  2261. }
  2262. else
  2263. {
  2264. if (rfo.prfnt->flType & RFONT_TYPE_HGLYPH)
  2265. rfo.vFixUpGlyphIndices((USHORT *)pwsz, cwc);
  2266. // If there is no pdxOut buffer provided, but we still need one to compute the
  2267. // number of characters that fit (pcChars not NULL), then we will have to
  2268. // allocate one of our own.
  2269. #define DXOUTLEN 40
  2270. ULONG dxOut[DXOUTLEN];
  2271. PULONG pdxAlloc = NULL;
  2272. if ((pdxOut == (PULONG) NULL) && (pcChars != (COUNT *) NULL))
  2273. {
  2274. if (cwc <= DXOUTLEN)
  2275. {
  2276. pdxOut = &dxOut[0];
  2277. }
  2278. else
  2279. {
  2280. if ((pdxAlloc = (PULONG) PALLOCMEM(cwc * sizeof(ULONG), 'txtG')) == (PULONG) NULL)
  2281. {
  2282. WARNING("gdisrv!GreGetTextExtentExW(): could not alloc temp buffer\n");
  2283. SAVE_ERROR_CODE(ERROR_NOT_ENOUGH_MEMORY);
  2284. }
  2285. pdxOut = pdxAlloc;
  2286. }
  2287. }
  2288. // The STROBJ will now compute the text alignment, character positions,
  2289. // and TextBox.
  2290. ESTROBJ to(
  2291. pwsz,cwc,
  2292. dco,
  2293. rfo,
  2294. xo,PDXNULL,FALSE, // xo, PDXNULL, bPdy = FALSE
  2295. dco.pdc->lEscapement(),
  2296. dco.pdc->lTextExtra(),
  2297. dco.pdc->lBreakExtra(),
  2298. dco.pdc->cBreak(),
  2299. 0,0,0,(LONG *) pdxOut
  2300. );
  2301. if (to.bValid())
  2302. {
  2303. // Transform the TextExtent to logical coordinates. Because this is a
  2304. // new NT function, we need not worry about the extent compatibility hack.
  2305. if (to.bTextExtent(rfo,0L,pSize))
  2306. {
  2307. // Count number of characters that fit in the max. width.
  2308. // If pcChars is NULL, we skip this and ignore the dxMax limit.
  2309. if (pcChars && pdxOut)
  2310. {
  2311. ULONG c;
  2312. for (c=0; c<cwc && *pdxOut<=dxMax; c++,pdxOut++)
  2313. {}
  2314. *pcChars = c;
  2315. }
  2316. bRet = TRUE;
  2317. }
  2318. }
  2319. // Free temp buffer.
  2320. if (pdxAlloc)
  2321. VFREEMEM(pdxAlloc);
  2322. }
  2323. }
  2324. return(bRet);
  2325. }
  2326. /******************************Public*Routine******************************\
  2327. * BOOL GreConsoleTextOut
  2328. *
  2329. * Write text with no spacing and alignment options, thereby saving a ton
  2330. * of time.
  2331. *
  2332. * History:
  2333. * Fri 12-Nov-1993 -by- Patrick Haluptzok [patrickh]
  2334. * Smaller and Faster
  2335. *
  2336. * Wed 16-Sep-1992 17:36:17 -by- Charles Whitmer [chuckwh]
  2337. * Duplicated GrePolyTextOut, and then deleted the unneeded code.
  2338. \**************************************************************************/
  2339. extern "C" BOOL GreConsoleTextOut(
  2340. HDC hdc,
  2341. POLYTEXTW *lpto, // Ptr to array of polytext structures
  2342. UINT nStrings, // number of polytext structures
  2343. RECTL *prclBounds
  2344. )
  2345. {
  2346. // make sure CSR is calling us
  2347. if (PsGetCurrentProcess() != gpepCSRSS)
  2348. return(FALSE);
  2349. //
  2350. // Assume we will succeed, set Failure if we don't
  2351. //
  2352. BOOL bRet = TRUE;
  2353. //
  2354. // Lock the DC.
  2355. //
  2356. DCOBJ dco(hdc);
  2357. if (dco.bValid())
  2358. {
  2359. //
  2360. // Accumulate bounds. We can do this before knowing if
  2361. // the operation is successful because bounds can be loose.
  2362. //
  2363. if (dco.bAccum())
  2364. dco.erclBounds() |= *prclBounds;
  2365. //
  2366. // Lock the Rao region.
  2367. //
  2368. DEVLOCKOBJ dlo;
  2369. if (dlo.bLock(dco))
  2370. {
  2371. //
  2372. // Locate the font realization.
  2373. //
  2374. RFONTOBJ rfo;
  2375. rfo.vInit(dco,FALSE);
  2376. if (rfo.bValid() && !rfo.bPathFont())
  2377. {
  2378. POINTL ptlOrigin;
  2379. ptlOrigin = dco.eptlOrigin();
  2380. SURFACE *pSurf = dco.pSurface();
  2381. XEPALOBJ palDest(pSurf->ppal());
  2382. XEPALOBJ palDestDC(dco.ppal());
  2383. POINTL *pptlBO = &dco.pdc->ptlFillOrigin();
  2384. EBRUSHOBJ *peboText = dco.peboText();
  2385. EBRUSHOBJ *peboBackground = dco.peboBackground();
  2386. BOOL bDitherText = FALSE;
  2387. if ( dco.flGraphicsCaps() & GCAPS_ARBRUSHTEXT )
  2388. {
  2389. // Even if a printer driver sets GCAPS_ARBRUSHTEXT, we
  2390. // can't allow vector fonts to be dithered.
  2391. bDitherText = (!rfo.bPathFont() || rfo.bReturnsOutlines());
  2392. // We always dirty the text brush if ARBRUSHTEXT is set to
  2393. // catch the cases where we transition between vector and
  2394. // non-vector fonts but keep the same brush -- if we didn't
  2395. // do this, we might try to use a cached, dithered brush
  2396. // after switching from a TrueType font to a vector font.
  2397. dco.ulDirtyAdd(DIRTY_TEXT);
  2398. // Get through the are-you-really-dirty check in vInitBrush:
  2399. peboText->vInvalidateUniqueness();
  2400. }
  2401. if ( dco.bDirtyBrush(DIRTY_TEXT|DIRTY_BACKGROUND) )
  2402. {
  2403. if ( dco.bDirtyBrush(DIRTY_TEXT) )
  2404. {
  2405. peboText->vInitBrush(dco.pdc,
  2406. gpbrText,
  2407. palDestDC, palDest,
  2408. pSurf,
  2409. bDitherText);
  2410. }
  2411. if ( dco.bDirtyBrush(DIRTY_BACKGROUND) )
  2412. {
  2413. peboBackground->vInitBrush(
  2414. dco.pdc,
  2415. gpbrBackground,
  2416. palDestDC, palDest, pSurf,
  2417. (dco.flGraphicsCaps() & GCAPS_ARBRUSHOPAQUE) ?
  2418. TRUE : FALSE);
  2419. }
  2420. dco.vCleanBrush(DIRTY_TEXT|DIRTY_BACKGROUND);
  2421. }
  2422. //
  2423. // Compute the clipping complexity and maybe reduce the exclusion
  2424. // rectangle. The bounding rectangle must be converted to Screen
  2425. // coordinates.
  2426. //
  2427. ERECTL rclExclude;
  2428. rclExclude.left = prclBounds->left + ptlOrigin.x;
  2429. rclExclude.right = prclBounds->right + ptlOrigin.x;
  2430. rclExclude.top = prclBounds->top + ptlOrigin.y;
  2431. rclExclude.bottom = prclBounds->bottom + ptlOrigin.y;
  2432. ECLIPOBJ co(
  2433. dco.prgnEffRao(),
  2434. rclExclude,
  2435. (rfo.prfnt->fobj.flFontType & FO_CLEARTYPE_X) ? CLIP_FORCE : CLIP_NOFORCE
  2436. );
  2437. rclExclude = co.erclExclude();
  2438. //
  2439. // Check the destination which is reduced by clipping.
  2440. //
  2441. if (!rclExclude.bEmpty())
  2442. {
  2443. DEVEXCLUDEOBJ dxo(dco,&rclExclude,&co);
  2444. //
  2445. // We now begin the 'Big Loop'. We will pass thru this loop once for
  2446. // each entry in the array of PolyText structures. Increment the
  2447. // pSurface once before we enter. We assume success from here on out
  2448. // unless we hit a failure.
  2449. //
  2450. INC_SURF_UNIQ(pSurf);
  2451. PFN_DrvBitBlt pfnBitBlt = pSurf->pfnBitBlt();
  2452. PFN_DrvTextOut pfnTextOut;
  2453. if
  2454. (
  2455. ((rfo.prfnt->fobj.flFontType & FO_GRAY16) && !(dco.flGraphicsCaps() & GCAPS_GRAY16)) ||
  2456. (rfo.prfnt->fobj.flFontType & FO_CLEARTYPE_X)
  2457. )
  2458. {
  2459. pfnTextOut = SpTextOut;
  2460. pSurf->pdcoAA = &dco; // make sure this is needed
  2461. }
  2462. else
  2463. {
  2464. pfnTextOut = pSurf->pfnTextOut();
  2465. }
  2466. ERECTL rclInput;
  2467. for (POLYTEXTW *ppt = lpto; ppt < lpto + nStrings; ppt += 1)
  2468. {
  2469. //
  2470. // Process the rectangle in prcl.
  2471. //
  2472. rclInput.left = ppt->rcl.left + ptlOrigin.x;
  2473. rclInput.right = ppt->rcl.right + ptlOrigin.x;
  2474. rclInput.top = ppt->rcl.top + ptlOrigin.y;
  2475. rclInput.bottom = ppt->rcl.bottom + ptlOrigin.y;
  2476. //
  2477. // Process the string.
  2478. //
  2479. if (ppt->n)
  2480. {
  2481. //
  2482. // The STROBJ will now compute the text alignment,
  2483. // character positions, and TextBox.
  2484. //
  2485. ESTROBJ to;
  2486. to.vInitSimple(
  2487. (PWSZ) ppt->lpstr,
  2488. ppt->n,
  2489. dco,
  2490. rfo,ppt->x+ptlOrigin.x,
  2491. ppt->y+ptlOrigin.y,NULL);
  2492. if (to.bValid())
  2493. {
  2494. // Draw the text.
  2495. #ifdef FE_SB
  2496. if( to.bLinkedGlyphs() )
  2497. {
  2498. // If there are linked glyphs, then the bounds of the
  2499. // glyphs (to.rclBkGround) might exceed the bounds of the
  2500. // clipping object (co.rclBounds). If so, then we need
  2501. // to increase the complexity of the clipping object from
  2502. // DC_TRIVIAL to DC_RECT.
  2503. if ((co.iDComplexity == DC_TRIVIAL) &&
  2504. ((to.rclBkGround.left < co.rclBounds.left) ||
  2505. (to.rclBkGround.right > co.rclBounds.right) ||
  2506. (to.rclBkGround.top < co.rclBounds.top) ||
  2507. (to.rclBkGround.bottom > co.rclBounds.bottom)))
  2508. {
  2509. co.iDComplexity = DC_RECT;
  2510. }
  2511. bProxyDrvTextOut
  2512. (
  2513. dco,
  2514. pSurf,
  2515. to,
  2516. co,
  2517. (RECTL *) NULL,
  2518. &rclInput,
  2519. peboText,
  2520. peboBackground,
  2521. pptlBO,
  2522. rfo,
  2523. (PDEVOBJ*)NULL,
  2524. (FLONG) 0L,
  2525. &rclExclude
  2526. );
  2527. }
  2528. else
  2529. {
  2530. #endif
  2531. (*pfnTextOut)(pSurf->pSurfobj(),
  2532. (STROBJ *) &to,
  2533. rfo.pfo(),
  2534. &co,
  2535. (RECTL *) NULL,
  2536. &rclInput,
  2537. peboText,
  2538. peboBackground,
  2539. pptlBO,
  2540. (R2_COPYPEN | (R2_COPYPEN << 8)));
  2541. }
  2542. }
  2543. else
  2544. {
  2545. bRet = FALSE;
  2546. break;
  2547. }
  2548. }
  2549. else
  2550. {
  2551. // intersect the dest rect with the clip rect and set it in co
  2552. // we can only get away with touching co.rclBounds after
  2553. // the ECLIPOBJ constructor because of two reasons:
  2554. // a) the target rectangle passed to bitblt is contained in the
  2555. // original bounds set by ECLIPOBJ, being the intersection
  2556. // of the origianal bounds with THE intended target rectangle.
  2557. // b) clipping complexity may have changed when we changed
  2558. // co.erclExclude, but it only could have gotten simpler,
  2559. // so at worst in those rare situations we would not go
  2560. // through the optimal code path.
  2561. // By changing clipping bounds we accomplish that no intersection
  2562. // of the target rectangle with clipping region rectangle is emtpy
  2563. // relieving the driver of extra work [bodind]
  2564. co.erclExclude().left = max(rclExclude.left,rclInput.left);
  2565. co.erclExclude().right = min(rclExclude.right,rclInput.right);
  2566. co.erclExclude().top = max(rclExclude.top,rclInput.top);
  2567. co.erclExclude().bottom = min(rclExclude.bottom,rclInput.bottom);
  2568. // if not clipped, Just paint the rectangle.
  2569. if ((co.erclExclude().left < co.erclExclude().right) &&
  2570. (co.erclExclude().top < co.erclExclude().bottom))
  2571. {
  2572. (*pfnBitBlt)(pSurf->pSurfobj(),
  2573. (SURFOBJ *) NULL,
  2574. (SURFOBJ *) NULL,
  2575. &co,
  2576. NULL,
  2577. &co.rclBounds,
  2578. (POINTL *) NULL,
  2579. (POINTL *) NULL,
  2580. (BRUSHOBJ *)peboBackground,
  2581. pptlBO,
  2582. 0x0000f0f0);
  2583. }
  2584. co.erclExclude() = rclExclude;
  2585. }
  2586. }
  2587. pSurf->pdcoAA = NULL;
  2588. }
  2589. }
  2590. else
  2591. {
  2592. WARNING("gdisrv!GreExtTextOutW(): could not lock HRFONT\n");
  2593. bRet = FALSE;
  2594. }
  2595. }
  2596. else
  2597. {
  2598. bRet = dco.bFullScreen();
  2599. }
  2600. }
  2601. else
  2602. {
  2603. bRet = FALSE;
  2604. WARNING("Invalid DC passed to GreConsoleTextOut\n");
  2605. }
  2606. return(bRet);
  2607. }
  2608. /******************************Public*Routine******************************\
  2609. * DWORD GreSetTextAlign (hdc,flOpts) *
  2610. * *
  2611. * Set the text alignment flags in the DC. *
  2612. * *
  2613. * History: *
  2614. * *
  2615. * Tue 28-Dec-1993 -by- Patrick Haluptzok [patrickh] *
  2616. * smaller and faster *
  2617. * *
  2618. * 18-Dec-1990 -by- Donald Sidoroff [donalds] *
  2619. * Wrote it. *
  2620. \**************************************************************************/
  2621. UINT APIENTRY GreSetTextAlign(HDC hdc,UINT flOpts)
  2622. {
  2623. ULONG ulReturn = 0;
  2624. XDCOBJ dco( hdc );
  2625. if(!dco.bValid())
  2626. {
  2627. WARNING("Invalid DC or offset passed to GreSetTextAlign\n");
  2628. }
  2629. else
  2630. {
  2631. ulReturn = (UINT)dco.pdc->lTextAlign();
  2632. dco.pdc->lTextAlign(flOpts);
  2633. if (MIRRORED_DC(dco.pdc) && ((flOpts & TA_CENTER) != TA_CENTER)) {
  2634. flOpts = flOpts ^ TA_RIGHT;
  2635. }
  2636. dco.pdc->flTextAlign(flOpts & (TA_UPDATECP | TA_CENTER | TA_BASELINE));
  2637. dco.vUnlockFast();
  2638. }
  2639. return((UINT)ulReturn);
  2640. }
  2641. /******************************Public*Routine******************************\
  2642. * int GreSetTextCharacterExtra (hdc,lExtra) *
  2643. * *
  2644. * Sets the amount of intercharcter spacing for TextOut. *
  2645. * *
  2646. * History: *
  2647. * Tue 28-Dec-1993 -by- Patrick Haluptzok [patrickh] *
  2648. * smaller and faster *
  2649. * *
  2650. * Tue 08-Jan-1991 -by- Bodin Dresevic [BodinD] *
  2651. * Update: bug, used to return lExtra instead of lOld, transform stuff *
  2652. * deleted since it will be done at the TextOut time. *
  2653. * *
  2654. * 18-Dec-1990 -by- Donald Sidoroff [donalds] *
  2655. * Wrote it. *
  2656. \**************************************************************************/
  2657. int APIENTRY GreSetTextCharacterExtra(HDC hdc,int lExtra)
  2658. {
  2659. ULONG ulOld = 0x80000000;
  2660. XDCOBJ dco( hdc );
  2661. if(!dco.bValid())
  2662. {
  2663. WARNING("Invalid DC or offset passed to GreSetTextCharacterExtra\n");
  2664. }
  2665. else
  2666. {
  2667. ulOld = dco.pdc->lTextExtra();
  2668. dco.pdc->lTextExtra(lExtra);
  2669. dco.vUnlockFast();
  2670. }
  2671. return(ulOld);
  2672. }
  2673. /******************************Public*Routine******************************\
  2674. * int GreGetTextCharacterExtra (hdc) *
  2675. * *
  2676. * Gets the amount of intercharcter spacing for TextOut. *
  2677. * *
  2678. * 29-Jun-1995 -by- Fritz Sands [fritzs] *
  2679. * Wrote it. *
  2680. \**************************************************************************/
  2681. int APIENTRY GreGetTextCharacterExtra(HDC hdc)
  2682. {
  2683. ULONG ulOld = 0;
  2684. XDCOBJ dco( hdc );
  2685. if(!dco.bValid())
  2686. {
  2687. WARNING("Invalid DC or offset passed to GreGetTextCharacterExtra\n");
  2688. }
  2689. else
  2690. {
  2691. ulOld = dco.pdc->lTextExtra();
  2692. dco.vUnlockFast();
  2693. }
  2694. return(ulOld);
  2695. }
  2696. /******************************Public*Routine******************************\
  2697. *
  2698. * CalcJustInArray
  2699. *
  2700. * Effects: mimics win95 asm code, except that their code does not have
  2701. * if (b_lpDx) clause, for all of their arrays are 16 bit.
  2702. *
  2703. * if GCP_JUSTIFYIN flag is set, the lpDx array on input contains
  2704. * justifying priorities.
  2705. * For latin this means the lpDx array will contain
  2706. * 0's or 1's where 0 means that the glyph at this position can not be
  2707. * used for spacing while 1 means that the glyph at this position should
  2708. * be used for spacing. If GCP_JUSTIFYIN is NOT set, than space chars ' ',
  2709. * in the input string are used to do justification.
  2710. *
  2711. * History:
  2712. * 21-Jul-1995 -by- Bodin Dresevic [BodinD]
  2713. * Wrote it.
  2714. \**************************************************************************/
  2715. DWORD nCalcJustInArray(
  2716. UINT **ppJustIn, // place to store the pointer to array
  2717. WCHAR Glyph, // glyph to find
  2718. VOID *pvIn, // input array
  2719. BOOL b_lpDx, // input array is lpDx or pwc
  2720. UINT cGlyphs // length of the input array
  2721. )
  2722. {
  2723. WCHAR *pwc, *pwcEnd;
  2724. int *pDx, *pDxEnd;
  2725. int iGlyph;
  2726. COUNT nJustIn = 0;
  2727. UINT *piInit;
  2728. // look for Glyph in the string
  2729. if (b_lpDx)
  2730. {
  2731. iGlyph = (int)Glyph;
  2732. pDxEnd = (int*)pvIn + cGlyphs;
  2733. for (pDx = (int*)pvIn; pDx < pDxEnd; pDx++)
  2734. {
  2735. if (*pDx == iGlyph)
  2736. nJustIn++;
  2737. }
  2738. }
  2739. else
  2740. {
  2741. pwcEnd = (WCHAR*)pvIn + cGlyphs;
  2742. for (pwc = (WCHAR*)pvIn; pwc < pwcEnd; pwc++)
  2743. {
  2744. if (*pwc == Glyph)
  2745. nJustIn++;
  2746. }
  2747. }
  2748. if ((nJustIn == 0) || // did not find any Glyphs in the string
  2749. !(piInit = (UINT *)PALLOCMEM(nJustIn * sizeof(UINT), 'ylgG')))
  2750. {
  2751. *ppJustIn = NULL;
  2752. return 0;
  2753. }
  2754. // store locations where Glyph's are found in the input array
  2755. UINT *pi = piInit;
  2756. if (b_lpDx)
  2757. {
  2758. for (pDx = (int*)pvIn; pDx < pDxEnd; pDx++)
  2759. {
  2760. if (*pDx == iGlyph)
  2761. {
  2762. //Sundown: safe to truncate since pDxEnd = pvIn + cGlyphs
  2763. *pi++ = (UINT)(pDx - (int*)pvIn);
  2764. }
  2765. }
  2766. }
  2767. else
  2768. {
  2769. for (pwc = (WCHAR*)pvIn; pwc < pwcEnd; pwc++)
  2770. {
  2771. if (*pwc == Glyph)
  2772. {
  2773. //Sundown: same as above
  2774. *pi++ = (UINT)(pwc - (WCHAR*)pvIn);
  2775. }
  2776. }
  2777. }
  2778. // return the pointer with array of locations of uiGlyphs
  2779. *ppJustIn = piInit;
  2780. return nJustIn;
  2781. }
  2782. /******************************Public*Routine******************************\
  2783. *
  2784. * VOID RFONTOBJ::vFixUpGlyphIndices(USHORT *pgi, UINT cgi)
  2785. *
  2786. * Effects: Windows 95 returns glyph indices for bitmap fonts that are the
  2787. * same as ansi values. On NT glyph handles are zero based, so
  2788. * we need to add chFirstChar to NT handles to get win95 indices
  2789. * which is what we do in GetGlyphIndicesA/W and GetCharacterPlacement.
  2790. * Conversely, when those indices are passed to us through
  2791. * text routines we have to subtract chFirstChar from indices to
  2792. * produce NT handles. This is what this routine does:
  2793. *
  2794. * History:
  2795. * 04-Mar-1997 -by- Bodin Dresevic [BodinD]
  2796. * Wrote it.
  2797. \**************************************************************************/
  2798. VOID RFONTOBJ::vFixUpGlyphIndices(USHORT *pgi, UINT cgi)
  2799. {
  2800. USHORT usFirst = prfnt->ppfe->pifi->chFirstChar;
  2801. ASSERTGDI(prfnt->flType & RFONT_TYPE_HGLYPH, "vFixUpGlyphIndices\n");
  2802. ASSERTGDI(prfnt->ppfe->pfdg, "RFONTOBJ::vFixUpGlyphIndices invalid ppfe->pfdg \n");
  2803. if ((prfnt->ppfe->pfdg->flAccel & GS_8BIT_HANDLES) && usFirst)
  2804. {
  2805. // win95 does not return true glyph indicies but ansi
  2806. // values for raster, vector, ps fonts
  2807. for (USHORT *pgiEnd = pgi + cgi; pgi < pgiEnd; pgi++)
  2808. *pgi -= usFirst;
  2809. }
  2810. }
  2811. /******************************Public*Routine******************************\
  2812. *
  2813. * GreGetGlyphIndicesW (
  2814. *
  2815. * Effects: designed to emulate win95 behavior
  2816. *
  2817. * Warnings:
  2818. *
  2819. * History:
  2820. * 25-Jul-1995 -by- Bodin Dresevic [BodinD]
  2821. * Wrote it.
  2822. \**************************************************************************/
  2823. DWORD GreGetGlyphIndicesW (
  2824. HDC hdc,
  2825. WCHAR *pwc,
  2826. DWORD cwc,
  2827. USHORT *pgi,
  2828. DWORD iMode,
  2829. BOOL bSubset
  2830. )
  2831. {
  2832. DWORD dwRet = GDI_ERROR;
  2833. HGLYPH *phg, *phgInit;
  2834. USHORT *pgiEnd = pgi + cwc;
  2835. XDCOBJ dco(hdc); // Lock the DC.
  2836. if (dco.bValid()) // Check if it's good.
  2837. {
  2838. // Locate the RFONT.
  2839. // It might be better to set the type to RFONT_TYPE_HGLYPH
  2840. // in anticipation of ETO_GLYPH_INDEX ExtTextOut calls
  2841. RFONTOBJ rfo(dco, FALSE, RFONT_TYPE_UNICODE);
  2842. if (rfo.bValid())
  2843. {
  2844. USHORT usFirst = rfo.prfnt->ppfe->pifi->chFirstChar;
  2845. // if cwc == 0 all we are care for is the # of distinct glyph indices
  2846. if (cwc==0)
  2847. {
  2848. ASSERTGDI(iMode == 0, "GreGetGlyphIndicesW parameters bogus\n");
  2849. if (rfo.prfnt->ppfe->pifi->cjIfiExtra > offsetof(IFIEXTRA,cig))
  2850. {
  2851. dwRet = ((IFIEXTRA *)(rfo.prfnt->ppfe->pifi + 1))->cig;
  2852. }
  2853. else
  2854. {
  2855. dwRet = 0;
  2856. }
  2857. }
  2858. else
  2859. {
  2860. // if we ever switch to 16 bit HGLYPHS in ddi, this alloc will no
  2861. // longer be necessary [bodind]
  2862. if (phgInit = (phg = (HGLYPH *)PALLOCMEM(cwc * sizeof(HGLYPH), 'ylgG')))
  2863. {
  2864. rfo.vXlatGlyphArray(pwc, cwc, phg, iMode, bSubset);
  2865. // separate loops for faster processing:
  2866. ASSERTGDI(rfo.prfnt->ppfe->pfdg, "GreGetGlyphIndicesW invalid ppfe->pfdg \n");
  2867. if (rfo.prfnt->ppfe->pfdg->flAccel & (GS_8BIT_HANDLES|GS_16BIT_HANDLES))
  2868. {
  2869. if ((rfo.prfnt->ppfe->pfdg->flAccel & GS_8BIT_HANDLES) && usFirst)
  2870. {
  2871. // win95 does not return true glyph indicies but ansi
  2872. // values for raster, vector, ps fonts
  2873. for ( ; pgi < pgiEnd; pgi++, pwc++, phg++)
  2874. *pgi = (USHORT)*phg + usFirst;
  2875. }
  2876. else
  2877. {
  2878. for ( ; pgi < pgiEnd; pgi++, pwc++, phg++)
  2879. *pgi = (USHORT)*phg;
  2880. }
  2881. dwRet = cwc; // can not fail any more
  2882. }
  2883. else
  2884. {
  2885. dwRet = GDI_ERROR;
  2886. }
  2887. VFREEMEM(phgInit);
  2888. }
  2889. }
  2890. }
  2891. dco.vUnlockFast();
  2892. }
  2893. return dwRet;
  2894. }
  2895. /******************************Public*Routine******************************\
  2896. *
  2897. * DWORD GreGetCharacterPlacementW
  2898. *
  2899. *
  2900. *
  2901. * History:
  2902. * 06-Jan-1995 -by- Bodin Dresevic [BodinD]
  2903. * Wrote it.
  2904. \**************************************************************************/
  2905. DWORD GreGetCharacterPlacementW(
  2906. HDC hdc,
  2907. LPWSTR pwsz,
  2908. DWORD nCountIn,
  2909. DWORD nMaxExtent,
  2910. LPGCP_RESULTSW pResults,
  2911. DWORD dwFlags
  2912. )
  2913. {
  2914. SIZE size;
  2915. GCP_RESULTSW gcpw;
  2916. DWORD nCount = nCountIn;
  2917. DWORD dwWidthType = 0;
  2918. int *pDx = NULL;
  2919. UINT *pJustIn = NULL;
  2920. DWORD dwJustInOff = 0; // used by calc routine for spacing
  2921. DWORD nJustIn = 0;
  2922. ULONG nKern = 0;
  2923. KERNINGPAIR *pKern = NULL;
  2924. KERNINGPAIR *pKernSave = NULL; // esential initialization
  2925. int nExtentLeft = 0;
  2926. int nExtentRem = 0;
  2927. WORD *pwc,*pwcEnd;
  2928. DWORD i, j;
  2929. // init size
  2930. size.cx = size.cy = 0;
  2931. // we will only be implementing the simple version of this api,
  2932. // that is for now we will not be calling LPK dlls
  2933. if (!pResults)
  2934. {
  2935. if (!GreGetTextExtentW(hdc, (LPWSTR)pwsz, (int)nCount, &size, GGTE_WIN3_EXTENT))
  2936. {
  2937. WARNING("GreGetCharacterPlacementW, GreGetTextExtentW failed\n");
  2938. return 0;
  2939. }
  2940. // now do unthinkable win95 stuff, chop off 32 bit values to 16 bits
  2941. return (DWORD)((USHORT)size.cx) | (DWORD)(size.cy << 16);
  2942. }
  2943. // main code starts here. We are following win95 code as closely as possible.
  2944. // Copy pResults to the stack, for faster access I presume.
  2945. gcpw = *pResults;
  2946. // take nCount to be the smaller of the nCounts and nGlyphs
  2947. if (nCount > gcpw.nGlyphs)
  2948. nCount = gcpw.nGlyphs;
  2949. // Calc pJustIn array if any
  2950. if (dwFlags & GCP_JUSTIFY) // if have this
  2951. dwFlags |= GCP_MAXEXTENT; // then must also have this
  2952. if ((dwFlags & GCP_JUSTIFYIN) && gcpw.lpDx)
  2953. {
  2954. // if this flag is set, the lpDx array on input contains
  2955. // justifying priorities so we can not continue if lpDx is not present.
  2956. // For latin this means the lpDx array will contain
  2957. // 0's or 1's where 0 means that the glyph at this position can not be
  2958. // used for spacing while 1 means that the glyph at this position should
  2959. // be used for spacing. If GCP_JUSTIFYIN is NOT set, than space chars ' ',
  2960. // in the string are used to do justification.
  2961. // Now that we have everything in place we can call CalcJustInArray
  2962. // to compute the array in pJustIn
  2963. nJustIn = nCalcJustInArray(&pJustIn, 1,
  2964. (VOID *)gcpw.lpDx, TRUE ,gcpw.nGlyphs);
  2965. if (!nJustIn)
  2966. {
  2967. // if this computation fails must pretend that this flag is not set
  2968. dwFlags &= ~GCP_JUSTIFYIN;
  2969. }
  2970. }
  2971. else
  2972. {
  2973. // either GCP_JUSTIFYIN not set or lpDx is NULL input,
  2974. // in either case can kill the bit
  2975. dwFlags &= ~GCP_JUSTIFYIN;
  2976. }
  2977. // we could have either the lpDx, lpCaretPos or neither or both. Take this
  2978. // into account and call GetTextExtentEx
  2979. // we could or could not be asking for a maximum. If we are, put it in the
  2980. // local version of the results structure.
  2981. if (gcpw.lpDx)
  2982. dwWidthType += 1; // bogus way of doing it, i.e. win95 way
  2983. if (gcpw.lpCaretPos)
  2984. dwWidthType += 2; // bogus way of doing it, i.e. win95 way
  2985. // dwWidthType can be 0,1,2,3
  2986. pDx = gcpw.lpDx;
  2987. if (dwWidthType == 2) // CaretPos only
  2988. pDx = gcpw.lpCaretPos; // reset the array pointer
  2989. // Check if the count should be reduced even further
  2990. COUNT *pnCount = NULL;
  2991. if (dwFlags & GCP_MAXEXTENT)
  2992. {
  2993. pnCount = (COUNT*)&nCount;
  2994. }
  2995. // now call GetTextExtentEx
  2996. if (!GreGetTextExtentExW(
  2997. hdc, // device context
  2998. (LPWSTR)pwsz, // pointer to a UNICODE text string
  2999. nCount, // count of WCHARs in the string
  3000. (ULONG)nMaxExtent, // maximum width to return
  3001. pnCount, // number of chars that fit in dxMax
  3002. (PULONG)pDx, // offset of each character from string origin
  3003. &size,0))
  3004. {
  3005. if (pJustIn)
  3006. VFREEMEM(pJustIn);
  3007. return 0;
  3008. }
  3009. // these few lines of code do not exist in Win95, presumably because
  3010. // their internal version of GetTextExtentExW does not return positions
  3011. // of glyphs (relative to the first glyph) but character increments along
  3012. // baseline.
  3013. if (pDx && (nCount > 0))
  3014. {
  3015. for (int * pDxEnd = &pDx[nCount - 1]; pDxEnd > pDx; pDxEnd--)
  3016. {
  3017. *pDxEnd -= pDxEnd[-1];
  3018. }
  3019. }
  3020. if ((dwFlags & GCP_MAXEXTENT) && (nCount == 0))
  3021. {
  3022. if (pJustIn)
  3023. VFREEMEM(pJustIn);
  3024. return (DWORD)((USHORT)size.cx) | (DWORD)(size.cy << 16);
  3025. }
  3026. // Kerning:
  3027. // It only makes sense to do kerning if there are more than 2 glyphs
  3028. if ((dwFlags & GCP_USEKERNING) && (dwWidthType != 0) && (nCount >= 2))
  3029. {
  3030. // Get the number of kerning pairs, if zero done
  3031. if (nKern = GreGetKerningPairs(hdc,0,NULL))
  3032. {
  3033. if (pKernSave = (KERNINGPAIR*)PALLOCMEM(nKern * sizeof(KERNINGPAIR), 'txtG'))
  3034. {
  3035. // consistency check for GetKerningPairs:
  3036. if (GreGetKerningPairs(hdc,nKern,pKernSave) != nKern)
  3037. {
  3038. // something is gone wrong, out of here
  3039. if (pJustIn)
  3040. VFREEMEM(pJustIn);
  3041. if (pKernSave)
  3042. VFREEMEM(pKernSave);
  3043. return 0;
  3044. }
  3045. KERNINGPAIR *pKernEnd = pKernSave + nKern;
  3046. for (pKern = pKernSave; pKern < pKernEnd; pKern++)
  3047. {
  3048. // now go over the sting and find all the instances of
  3049. // THIS kerning pair in the string:
  3050. register WORD wcFirst = pKern->wFirst;
  3051. // note that this is the loop for trying the wcFirst
  3052. // so that the end condition is &pwsz[nCount - 2],
  3053. // wcSecond could go up to &pwsz[nCount - 1],
  3054. // Either I do not understand Win95 code or they have
  3055. // a bug in that they could fault on trying to access the
  3056. // the second glyph in a pair in the input string
  3057. pwcEnd = (WORD*)pwsz + (nCount - 1);
  3058. for (pwc = (WORD *)pwsz; pwc < pwcEnd; pwc++)
  3059. {
  3060. if ((wcFirst == pwc[0]) && (pwc[1] == pKern->wSecond))
  3061. {
  3062. // found a kerning pair in the string,
  3063. // we need to modify the pDx vector for the second
  3064. // glyph in the kerning pair
  3065. pDx[pwc - (WORD *)pwsz] += pKern->iKernAmount;
  3066. // also adjust the return value accordingly:
  3067. size.cx += pKern->iKernAmount;
  3068. }
  3069. }
  3070. } // on to the next pair
  3071. // done with kerning pairs can free the memory
  3072. VFREEMEM(pKernSave);
  3073. // if we have kerned positive amounts, then the string could well
  3074. // have gone over the preset limit. If so, reduce the number of
  3075. // characters we found [win95 comment]
  3076. if (dwFlags & GCP_MAXEXTENT)
  3077. {
  3078. while (((DWORD)size.cx > nMaxExtent) && (nCount > 0))
  3079. {
  3080. // point to the last glyph in the string
  3081. size.cx -= pDx[nCount - 1];
  3082. nCount -= 1;
  3083. }
  3084. // see if there are any glyphs left to process
  3085. if (nCount == 0)
  3086. {
  3087. if (pJustIn)
  3088. VFREEMEM(pJustIn);
  3089. pResults->nGlyphs = nCount;
  3090. pResults->nMaxFit = (int)nCount;
  3091. return 0;
  3092. }
  3093. }
  3094. } // no memory
  3095. } // no kern pairs
  3096. }
  3097. // Justification, check flags and the presence of array
  3098. if ((dwFlags & GCP_JUSTIFY) && dwWidthType && (nCount > 0))
  3099. {
  3100. int *pDxEnd = &pDx[nCount - 1]; // must have nCount > 0 for this
  3101. // check trailing spaces, adjust nCount further to remove trailing spaces
  3102. for
  3103. (
  3104. pwcEnd = (WORD*)&pwsz[nCount-1];
  3105. (pwcEnd >= (WORD*)pwsz) && (*pwcEnd == L' ');
  3106. nCount--, pwcEnd--, pDxEnd--
  3107. )
  3108. {
  3109. size.cx -= *pDxEnd;
  3110. }
  3111. if (nCount == 0)
  3112. {
  3113. if (pJustIn)
  3114. VFREEMEM(pJustIn);
  3115. pResults->nGlyphs = nCount;
  3116. pResults->nMaxFit = (int)nCount;
  3117. return 0;
  3118. }
  3119. // See if we need to justify.
  3120. // Can not justify one character, need at least two...
  3121. nExtentLeft = (int)nMaxExtent - (int)size.cx;
  3122. if ((nExtentLeft >= 0) && (nCount >= 2))
  3123. {
  3124. // ... yes, we do need to justify
  3125. // if GCP_JUSTIFYIN was set, pJustIn and nJustIn have
  3126. // already been set.
  3127. if (!nJustIn) // try to use ' ' as a "spacer glyph"
  3128. {
  3129. nJustIn = nCalcJustInArray(&pJustIn,L' ',
  3130. (VOID *)pwsz, FALSE, nCount);
  3131. }
  3132. if (nJustIn)
  3133. {
  3134. // Make sure that the array doesn't say to
  3135. // space a character beyond the new nCount.
  3136. j = nCount - 1; // convert count to index of the last glyph
  3137. int ii;
  3138. for (ii = (int)(nJustIn - 1); ii >= 0; ii--)
  3139. {
  3140. if ((UINT)j >= pJustIn[ii])
  3141. break;
  3142. }
  3143. // pJustIn array is zero based, to get the effective number
  3144. // of "spacers" in the array must add 1 to the index of the last "spacer" in the array
  3145. i = (DWORD)ii + 1;
  3146. // run a sort of primitive DDA a'la DavidMS
  3147. nExtentRem = (int) (((DWORD)nExtentLeft) % i);
  3148. nExtentLeft /= i;
  3149. for (j = 0; j < i; j++, nExtentRem--)
  3150. {
  3151. int dxCor = nExtentLeft;
  3152. if (nExtentRem > 0)
  3153. dxCor += 1;
  3154. pDx[pJustIn[j]] += dxCor;
  3155. }
  3156. }
  3157. else
  3158. {
  3159. // no spaces. justify by expanding every character evenly.
  3160. while (nExtentLeft > 0)
  3161. {
  3162. // Note the end condition: nCount - 1, rather
  3163. // than usual nCount; This is because there is no point
  3164. // in adding spaces to the last glyph in the string
  3165. j = nCount - 1;
  3166. for (i = 0; i < j; i++)
  3167. {
  3168. pDx[i] += 1;
  3169. if (!(--nExtentLeft))
  3170. break;
  3171. }
  3172. }
  3173. }
  3174. }
  3175. #if DBG
  3176. else
  3177. {
  3178. if (nCount < 2)
  3179. RIP("GetCharacterPlacement, justification wrong\n");
  3180. }
  3181. #endif
  3182. // we now have exactly this:
  3183. size.cx = (LONG)nMaxExtent;
  3184. }
  3185. // fill other width array, that is CaretPos
  3186. if (dwWidthType == 3) // both lpDx and lpCaretPos are non NULL
  3187. RtlCopyMemory(gcpw.lpCaretPos, gcpw.lpDx, nCount * sizeof(int));
  3188. // caret positioning is from the start of the string,
  3189. // not the previous character.
  3190. if (gcpw.lpCaretPos)
  3191. {
  3192. int iCaretPos = 0, iDx = 0;
  3193. for (i = 0; i < nCount; i++)
  3194. {
  3195. iDx = gcpw.lpCaretPos[i];
  3196. gcpw.lpCaretPos[i] = iCaretPos;
  3197. iCaretPos += iDx;
  3198. }
  3199. }
  3200. // Fix Output String
  3201. if (gcpw.lpOutString)
  3202. RtlCopyMemory(gcpw.lpOutString, pwsz, nCount * sizeof(WCHAR));
  3203. // Classification
  3204. if (gcpw.lpClass)
  3205. RtlFillMemory(gcpw.lpClass, nCount, GCPCLASS_LATIN);
  3206. // Ordering
  3207. if (gcpw.lpOrder)
  3208. {
  3209. for (i = 0; i < nCount; i++)
  3210. {
  3211. gcpw.lpOrder[i] = i;
  3212. }
  3213. }
  3214. // Get lpGlyphs
  3215. if (gcpw.lpGlyphs)
  3216. {
  3217. if (GreGetGlyphIndicesW(
  3218. hdc,(WCHAR*)pwsz,nCount,
  3219. (USHORT*)gcpw.lpGlyphs,0, FALSE) == GDI_ERROR)
  3220. {
  3221. nCount = 0;
  3222. size.cx = size.cy = 0;
  3223. }
  3224. }
  3225. // Finally fix counters in the returned structure
  3226. if (pJustIn)
  3227. VFREEMEM(pJustIn);
  3228. pResults->nGlyphs = nCount;
  3229. pResults->nMaxFit = nCount;
  3230. return (DWORD)((USHORT)size.cx) | (DWORD)(size.cy << 16);
  3231. }
  3232. /**************************************************************************\
  3233. * NtGdiGetWidthTable
  3234. *
  3235. * Gets a table of character advance widths for a font. Returns SHORTs
  3236. * over the C/S interface to save space. (Note that 99+% of all requests
  3237. * will be happy with this limitation.)
  3238. *
  3239. * We will try real hard to get widths for the "special" characters at the
  3240. * start of the array. Other widths are returned only when they are not
  3241. * expensive. (Expensive is True Type rasterizing a glyph, for example.)
  3242. * The value NO_WIDTH is returned for those expensive glyphs.
  3243. *
  3244. * We return GDI_ERROR (0xFFFFFFFF) in case of an error. TRUE indicates
  3245. * that all widths were easy.
  3246. *
  3247. * History:
  3248. * Tue 13-Jun-1995 22:24:49 by Gerrit van Wingerden [gerritv]
  3249. * Moved to kernel mode
  3250. *
  3251. * Mon 11-Jan-1993 22:24:39 -by- Charles Whitmer [chuckwh]
  3252. * Wrote it. Sorry about the wierd structure, I'm trying to get good tail
  3253. * merging.
  3254. \**************************************************************************/
  3255. BOOL APIENTRY NtGdiGetWidthTable
  3256. (
  3257. HDC hdc, // Device context
  3258. ULONG cSpecial,
  3259. WCHAR *pwc, // Pointer to a UNICODE text codepoints.
  3260. ULONG cwc, // Count of chars.
  3261. USHORT *psWidth, // Width table (returned).
  3262. WIDTHDATA *pwd, // Useful font data (returned).
  3263. FLONG *pflInfo // Font info flags.
  3264. )
  3265. {
  3266. ULONG ii;
  3267. BOOL bRet = (BOOL) GDI_ERROR;
  3268. XDCOBJ dco(hdc); // Lock the DC.
  3269. if (dco.bValid()) // Check if it's good.
  3270. {
  3271. WIDTHDATA wd;
  3272. FLONG flInfo;
  3273. USHORT *psWidthTmp = NULL;
  3274. WCHAR *pwcTmp;
  3275. if (!BALLOC_OVERFLOW2(cwc, USHORT, WCHAR))
  3276. {
  3277. psWidthTmp = (USHORT*) AllocFreeTmpBuffer(cwc*(sizeof(USHORT)+sizeof(WCHAR)));
  3278. }
  3279. if( psWidthTmp )
  3280. {
  3281. pwcTmp = (WCHAR*) (psWidthTmp + cwc);
  3282. __try
  3283. {
  3284. ProbeForRead(pwc,sizeof(WCHAR)*cwc,sizeof(WORD));
  3285. RtlCopyMemory(pwcTmp,pwc,cwc*sizeof(WCHAR));
  3286. }
  3287. __except(EXCEPTION_EXECUTE_HANDLER)
  3288. {
  3289. cwc = 0;
  3290. }
  3291. }
  3292. else
  3293. {
  3294. WARNING("NtGdiGetWidthTable unable to allocate memory\n");
  3295. cwc = 0;
  3296. }
  3297. if (cwc)
  3298. {
  3299. // Locate the RFONT.
  3300. RFONTOBJ rfo(dco,FALSE);
  3301. if (rfo.bValid())
  3302. {
  3303. // Grab the flInfo flags.
  3304. flInfo = rfo.flInfo();
  3305. if (rfo.cxMax() < 0xFFF)
  3306. {
  3307. // Check for a simple case. We still have to fill the table
  3308. // because some one may want it.
  3309. if (rfo.lCharInc())
  3310. {
  3311. USHORT *psWidth1 = psWidthTmp;
  3312. LONG fxInc = rfo.lCharInc() << 4;
  3313. for (ii=0; ii<cwc; ii++)
  3314. *psWidth1++ = (USHORT) fxInc;
  3315. bRet = TRUE;
  3316. }
  3317. else
  3318. {
  3319. bRet = rfo.bGetWidthTable(dco,cSpecial,pwcTmp,cwc,psWidthTmp);
  3320. }
  3321. // If things are going well, get the WIDTHDATA.
  3322. if (bRet != GDI_ERROR)
  3323. {
  3324. if (!rfo.bGetWidthData(&wd,dco))
  3325. bRet = (BOOL) GDI_ERROR;
  3326. }
  3327. }
  3328. }
  3329. else
  3330. {
  3331. WARNING("gdisrv!GreGetWidthTable(): could not lock HRFONT\n");
  3332. }
  3333. }
  3334. if( bRet != GDI_ERROR )
  3335. {
  3336. __try
  3337. {
  3338. ProbeForWrite(psWidth,sizeof(USHORT)*cwc,sizeof(USHORT));
  3339. RtlCopyMemory(psWidth,psWidthTmp,cwc*sizeof(USHORT));
  3340. if( pwd )
  3341. {
  3342. ProbeForWrite(pwd,sizeof(WIDTHDATA),sizeof(DWORD));
  3343. RtlCopyMemory(pwd,&wd,sizeof(WIDTHDATA));
  3344. }
  3345. ProbeForWrite(pflInfo,sizeof(FLONG),sizeof(DWORD));
  3346. RtlCopyMemory(pflInfo,&flInfo,sizeof(FLONG));
  3347. }
  3348. __except(EXCEPTION_EXECUTE_HANDLER)
  3349. {
  3350. bRet = GDI_ERROR;
  3351. }
  3352. }
  3353. if (psWidthTmp)
  3354. {
  3355. FreeTmpBuffer( psWidthTmp );
  3356. }
  3357. dco.vUnlockFast();
  3358. }
  3359. return(bRet);
  3360. }
  3361. /******************************Public*Routine******************************\
  3362. * iGetPublicWidthTable()
  3363. *
  3364. *
  3365. * History:
  3366. * 28-Feb-1996 -by- Eric Kutter [erick]
  3367. * Wrote it.
  3368. \**************************************************************************/
  3369. EFLOAT_S ef_16 = EFLOAT_16;
  3370. EFLOAT_S ef_1_16 = EFLOAT_1Over16;
  3371. int iGetPublicWidthTable(
  3372. HDC hdc)
  3373. {
  3374. ULONG ii = MAX_PUBLIC_CFONT; // this means failure
  3375. BOOL bRet = FALSE;
  3376. HLFONT hf;
  3377. XDCOBJ dco(hdc); // Lock the DC.
  3378. if (dco.bValid()) // Check if it's good.
  3379. {
  3380. // only want to support no transforms
  3381. if ((dco.pdc->ulMapMode() == MM_TEXT) && (dco.ulDirty() & DISPLAY_DC))
  3382. {
  3383. // Get the hfont and check if it is public
  3384. hf = dco.pdc->hlfntNew();
  3385. if ((hf != NULL) &&
  3386. GreGetObjectOwner((HOBJ)hf,LFONT_TYPE) == OBJECT_OWNER_PUBLIC)
  3387. {
  3388. RFONTOBJ rfo(dco,FALSE);
  3389. if (rfo.bValid() && (rfo.cxMax() < 0xFFF))
  3390. {
  3391. // lets see if we can find an available cpf
  3392. for (ii = 0; ii < MAX_PUBLIC_CFONT; ++ii)
  3393. {
  3394. if (gpGdiSharedMemory->acfPublic[ii].hf == 0)
  3395. break;
  3396. if (gpGdiSharedMemory->acfPublic[ii].hf == (HFONT)hf)
  3397. {
  3398. WARNING("iGetPublicWidthTable - font already in public list\n");
  3399. ii = MAX_PUBLIC_CFONT;
  3400. }
  3401. }
  3402. if (ii < MAX_PUBLIC_CFONT)
  3403. {
  3404. PCFONT pcf = &gpGdiSharedMemory->acfPublic[ii];
  3405. pcf->timeStamp = gpGdiSharedMemory->timeStamp;
  3406. // Grab the flInfo flags.
  3407. pcf->flInfo = rfo.flInfo();
  3408. // Check for a simple case. We still have to fill the table
  3409. // because some one may want it.
  3410. if (rfo.lCharInc())
  3411. {
  3412. USHORT usInc = (USHORT)(rfo.lCharInc() << 4);
  3413. for (ii=0; ii<256; ii++)
  3414. pcf->sWidth[ii] = usInc;
  3415. bRet = TRUE;
  3416. }
  3417. else
  3418. {
  3419. WCHAR wch[256];
  3420. LFONTOBJ lfo(hf);
  3421. if (lfo.bValid())
  3422. {
  3423. if (IS_ANY_DBCS_CHARSET(lfo.plfw()->lfCharSet))
  3424. {
  3425. ULONG uiCodePage = ulCharsetToCodePage((UINT)lfo.plfw()->lfCharSet);
  3426. for (ii = 0; ii < 256; ++ii)
  3427. {
  3428. UCHAR j = (UCHAR) ii;
  3429. EngMultiByteToWideChar(uiCodePage,
  3430. &wch[ii],
  3431. sizeof(WCHAR),
  3432. (LPSTR)&j,
  3433. 1);
  3434. }
  3435. }
  3436. else
  3437. {
  3438. UCHAR ach[256];
  3439. ULONG BytesReturned;
  3440. for (ii = 0; ii < 256; ++ii)
  3441. ach[ii] = (UCHAR)ii;
  3442. RtlMultiByteToUnicodeN(wch,
  3443. sizeof(wch),
  3444. &BytesReturned,
  3445. (PCHAR)ach,
  3446. sizeof(ach));
  3447. }
  3448. bRet = rfo.bGetWidthTable(dco,256,wch,256,pcf->sWidth);
  3449. if (bRet == GDI_ERROR)
  3450. bRet = FALSE;
  3451. }
  3452. }
  3453. // If things are going well, get the WIDTHDATA , metrics and
  3454. // RealizationInfo
  3455. DCOBJ dcof(hdc);
  3456. if (bRet &&
  3457. rfo.bGetWidthData(&pcf->wd,dco) &&
  3458. #ifdef LANGPACK
  3459. rfo.GetRealizationInfo(&pcf->ri) &&
  3460. #endif
  3461. bGetTextMetrics(rfo, dcof, &pcf->tmw)
  3462. )
  3463. {
  3464. pcf->fl = CFONT_COMPLETE |
  3465. CFONT_CACHED_METRICS |
  3466. CFONT_CACHED_WIDTHS |
  3467. #ifdef LANGPACK
  3468. CFONT_CACHED_RI |
  3469. #endif
  3470. CFONT_PUBLIC;
  3471. // since we are always MM_TEXT, the xform is identity
  3472. pcf->efM11 = ef_16;
  3473. pcf->efM22 = ef_16;
  3474. pcf->efDtoWBaseline = ef_1_16;
  3475. pcf->efDtoWAscent = ef_1_16;
  3476. pcf->hf = (HFONT)hf;
  3477. pcf->hdc = 0;
  3478. pcf->cRef = 0;
  3479. pcf->lHeight = FXTOL((LONG) pcf->wd.sHeight);
  3480. }
  3481. else
  3482. {
  3483. // if got error... we should retuen MAX_PUBLIC_CFONT..
  3484. // At this point "ii" is not equal to MAX_PUBLIC_CFONT, it
  3485. // points first free entry of cache table...
  3486. // Just force set it to error..
  3487. ii = MAX_PUBLIC_CFONT;
  3488. }
  3489. }
  3490. }
  3491. else
  3492. {
  3493. WARNING("gdisrv!GreGetWidthTable(): could not lock HRFONT\n");
  3494. }
  3495. }
  3496. }
  3497. dco.vUnlockFast();
  3498. }
  3499. return(ii);
  3500. }
  3501. /******************************Public*Routine******************************\
  3502. * NtGdiSetupPublicCFONT()
  3503. *
  3504. * Modify the cached public cfont.
  3505. *
  3506. * if HDC is non-null, textmetrics must be set
  3507. * if HF is non-null, cached ave width must be set
  3508. *
  3509. * returns index of cfont modified
  3510. *
  3511. * History:
  3512. * 23-Feb-1996 -by- Eric Kutter [erick]
  3513. * Wrote it.
  3514. \**************************************************************************/
  3515. int APIENTRY NtGdiSetupPublicCFONT(
  3516. HDC hdc,
  3517. HFONT hf,
  3518. ULONG ulAve)
  3519. {
  3520. int ii = MAX_PUBLIC_CFONT;
  3521. // get metrics and widths if necesary
  3522. if (hdc)
  3523. {
  3524. ii = iGetPublicWidthTable(hdc);
  3525. }
  3526. // now see if we need to fill in the ave width
  3527. if (hf)
  3528. {
  3529. // if we havn't found it yet, find it
  3530. if (ii == MAX_PUBLIC_CFONT)
  3531. {
  3532. for (ii = 0; ii < MAX_PUBLIC_CFONT; ++ii)
  3533. {
  3534. if (gpGdiSharedMemory->acfPublic[ii].hf == hf)
  3535. break;
  3536. }
  3537. }
  3538. if (ii < MAX_PUBLIC_CFONT)
  3539. {
  3540. gpGdiSharedMemory->acfPublic[ii].ulAveWidth = ulAve;
  3541. gpGdiSharedMemory->acfPublic[ii].fl |= CFONT_CACHED_AVE;
  3542. }
  3543. }
  3544. return(ii);
  3545. }
  3546. UINT APIENTRY GreGetTextAlign(HDC hdc)
  3547. {
  3548. XDCOBJ dco( hdc );
  3549. if(dco.bValid())
  3550. {
  3551. UINT uTextAlign = dco.pdc->lTextAlign();
  3552. dco.vUnlockFast();
  3553. return uTextAlign;
  3554. }
  3555. else
  3556. {
  3557. WARNING("GreGetTextAlign: invalid DC\n");
  3558. return(0);
  3559. }
  3560. }