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.

3456 lines
96 KiB

  1. /******************************module*header*******************************\
  2. * Module Name: textobj.cxx
  3. *
  4. * Supporting routines for text output calls, ExtTextOut etc.
  5. *
  6. * Created: 08-Feb-1991 09:25:14
  7. * Author: Bodin Dresevic [BodinD]
  8. *
  9. * Copyright (c) 1999 Microsoft Corporation
  10. \**************************************************************************/
  11. #include "precomp.hxx"
  12. #define XFORMNULL (EXFORMOBJ *) NULL
  13. VOID vGenWidths
  14. (
  15. FIX *pfxD1,
  16. FIX *pfxD2,
  17. EFLOAT& efRA,
  18. EFLOAT& efRB,
  19. FIX fxWidth,
  20. FIX fxTop,
  21. FIX fxBottom,
  22. FIX fxMaxAscent
  23. );
  24. #define SO_ACCEL_FLAGS (SO_FLAG_DEFAULT_PLACEMENT | SO_MAXEXT_EQUAL_BM_SIDE \
  25. | SO_CHAR_INC_EQUAL_BM_BASE | SO_ZERO_BEARINGS)
  26. BOOL bAdjusBaseLine(RFONTOBJ &rfoBase, RFONTOBJ &rfoLink, POINTL *pptlAdjustBaseLine);
  27. /******************************Member*Function*****************************\
  28. * ESTROBJ::vInit
  29. *
  30. * Constructor for ESTROBJ. Performs the following operations:
  31. *
  32. * 1) Initialize the STROBJ fields for the driver.
  33. * 2) Compute all character positions.
  34. * 3) Compute the TextBox.
  35. * 4) In the simplest cases, computes rectangles for underline and
  36. * strikeout.
  37. *
  38. * The TextBox is a parallelogram in device coordinates, whose sides are
  39. * parallel to the transformed sides of a character cell, and which bounds
  40. * all the character cells. A and C spacings are taken into account to
  41. * assure that it is a proper bound.
  42. *
  43. * We record the TextBox in an unusual notation. If a line is constructed
  44. * through the character origin of the first character in the string and in
  45. * the direction of the ascent, then what we record as the "left" and
  46. * "right" of the TextBox are really the distances from this line to each
  47. * of those edges of the parallelogram, in device coordinates. Likewise,
  48. * the "top" and "bottom" are the distances from the baseline of the first
  49. * character. This completely determines the parallelogram, and is
  50. * surprisingly easy to compute. ExtTextOut later turns this data into the
  51. * actual parallelogram, whereas the TextExtent functions turn this data
  52. * into scalar extents.
  53. *
  54. * History:
  55. * Fri 13-Mar-1992 00:47:05 -by- Charles Whitmer [chuckwh]
  56. * Rewrote from the ground up.
  57. *
  58. * 21-Jan-1991 -by- Bodin Dresevic [BodinD]
  59. * Wrote it.
  60. \**************************************************************************/
  61. VOID ESTROBJ::vInit
  62. (
  63. PWSZ pwsz,
  64. LONG cwc,
  65. XDCOBJ& dco,
  66. RFONTOBJ& rfo,
  67. EXFORMOBJ& xo,
  68. LONG *pdx,
  69. BOOL bPdy,
  70. LONG lEsc,
  71. LONG lExtra,
  72. LONG lBreakExtra,
  73. LONG cBreak,
  74. FIX xRef,
  75. FIX yRef ,
  76. FLONG flControl,
  77. LONG *pdxOut,
  78. PVOID pvBuffer,
  79. DWORD CodePage
  80. )
  81. {
  82. EGLYPHPOS *pg;
  83. GLYPHDATA *pgd;
  84. UINT ii;
  85. EFLOAT efScaleX = xo.efM11();
  86. cGlyphs = cwc;
  87. prfo = &rfo;
  88. flTO = 0L;
  89. flAccel = bPdy ? SO_DXDY : 0L;
  90. // we don't want to substitute the symbol font
  91. // if its glyph set has been extended
  92. {
  93. PFE *ppfe = rfo.ppfe();
  94. ASSERTGDI(ppfe->pfdg, "ESTROBJ::vInit invalid ppfe->pfdg \n");
  95. if (ppfe->pfdg->flAccel & GS_EXTENDED)
  96. {
  97. ASSERTGDI(ppfe->pifi->jWinCharSet == SYMBOL_CHARSET,
  98. "ESTROBJ::vInit(): GS_EXTENDED set for on SYMBOL_CHARSET fonts\n");
  99. flAccel |= SO_DO_NOT_SUBSTITUTE_DEVICE_FONT;
  100. }
  101. }
  102. ulCharInc = 0L;
  103. cgposCopied = 0;
  104. cgposPositionsEnumerated = 0;
  105. cExtraRects = 0;
  106. pgp = NULL;
  107. pgpos = NULL;
  108. pwszOrg = pwsz;
  109. dwCodePage = CodePage;
  110. xExtra = 0; // will be computed later if needed
  111. xBreakExtra = 0; // will be computed later if needed
  112. // fix the string if in GLYPH_INDEX mode, waste of time to be win95 compatible
  113. if (rfo.prfnt->flType & RFONT_TYPE_HGLYPH)
  114. {
  115. flAccel |= SO_GLYPHINDEX_TEXTOUT;
  116. rfo.vFixUpGlyphIndices((USHORT *)pwsz, cwc);
  117. }
  118. // Remember if the printer driver wants 28.4 char positions.
  119. PDEVOBJ po(rfo.hdevConsumer());
  120. if (po.bCapsHighResText())
  121. flTO |= TO_HIGHRESTEXT;
  122. // Locate the GLYPHPOS array. Use the buffer given, if there is one. We
  123. // need one more GLYPHPOS structure than there are glyphs. The concatenation
  124. // point is computed in the last one.
  125. if (pvBuffer)
  126. {
  127. pg = (EGLYPHPOS *) pvBuffer;
  128. }
  129. else
  130. {
  131. pg = (EGLYPHPOS *) PVALLOCTEMPBUFFER(SIZEOF_STROBJ_BUFFER(cwc));
  132. if (pg == (PGLYPHPOS) NULL)
  133. return;
  134. // Note that the memory has been allocated.
  135. flTO |= TO_MEM_ALLOCATED;
  136. }
  137. pgpos = pg; // Make sure our cached value is in the structure.
  138. // In Win 3.1 compatibility mode, we always assume that escapement is
  139. // the same as orientation, except for vector fonts. Make it explicitly so.
  140. if (rfo.iGraphicsMode() == GM_COMPATIBLE)
  141. {
  142. if (!(rfo.prfnt->flInfo & FM_INFO_TECH_STROKE))
  143. lEsc = rfo.ulOrientation();
  144. }
  145. // Offset the reference point for TA_TOP and TA_BOTTOM. Our GLYPHPOS
  146. // structures always contain positions along the baseline. The TA_BASELINE
  147. // case is therefore already correct.
  148. switch (flControl & (TA_TOP | TA_BASELINE | TA_BOTTOM))
  149. {
  150. case TA_TOP:
  151. xRef -= rfo.ptfxMaxAscent().x;
  152. yRef -= rfo.ptfxMaxAscent().y;
  153. break;
  154. case TA_BOTTOM:
  155. xRef -= rfo.ptfxMaxDescent().x;
  156. yRef -= rfo.ptfxMaxDescent().y;
  157. break;
  158. }
  159. /**************************************************************************\
  160. * [Win 3.1 compatibility issue]
  161. *
  162. * Adjust pdx array if there is a non-zero lExtra.
  163. *
  164. * This is only done under compatibility mode and only when using non-vector
  165. * fonts on a non-display device.
  166. \**************************************************************************/
  167. if ( lExtra
  168. && (pdx != (LONG *) NULL)
  169. && (rfo.iGraphicsMode() == GM_COMPATIBLE)
  170. && (!(rfo.prfnt->flInfo & FM_INFO_TECH_STROKE))
  171. && po.bDisplayPDEV() )
  172. {
  173. LONG *pdxAdj = pdx;
  174. LONG *pdxEnd;
  175. if (!bPdy)
  176. {
  177. pdxEnd = pdx + cwc;
  178. for (;pdxAdj < pdxEnd; pdxAdj += 1)
  179. *pdxAdj += lExtra;
  180. }
  181. else
  182. {
  183. pdxEnd = pdx + 2*cwc;
  184. for (;pdxAdj < pdxEnd; pdxAdj += 2)
  185. *pdxAdj += lExtra;
  186. }
  187. }
  188. /**************************************************************************\
  189. * Handle all horizontal special cases.
  190. \**************************************************************************/
  191. if (
  192. ((lEsc | rfo.ulOrientation()) == 0)
  193. && xo.bScale()
  194. && !xo.efM22().bIsNegative() // Otherwise the ascent goes down.
  195. && !efScaleX.bIsNegative() // Otherwise A and C spaces get confused.
  196. )
  197. {
  198. /**********************************************************************\
  199. * We provide several special routines to calculate the character
  200. * positions and TextBox. Each routine is responsible for calculating:
  201. *
  202. * 1) Each position
  203. * 2) Bounding coordinates.
  204. * 3) The ptfxUpdate vector.
  205. * 4) The flAccel flags.
  206. \**********************************************************************/
  207. if (pdx != NULL)
  208. {
  209. // Case H1: A PDX array is provided.
  210. if (!bPdy)
  211. {
  212. vCharPos_H1(
  213. dco,
  214. rfo,xRef,yRef,pdx,efScaleX);
  215. }
  216. else
  217. {
  218. if (flControl & (TSIM_UNDERLINE1 | TSIM_STRIKEOUT))
  219. {
  220. // In H4 case we want to force individual character underlining
  221. // as we do for esc!=orientation case,
  222. if (!rfo.bCalcEscapement(xo,lEsc))
  223. return;
  224. flTO |= TO_ESC_NOT_ORIENT;
  225. }
  226. vCharPos_H4(
  227. dco,
  228. rfo,xRef,yRef,pdx, efScaleX,xo.efM22());
  229. }
  230. }
  231. else if (rfo.lCharInc() && ((lExtra | lBreakExtra) == 0))
  232. {
  233. // Case H2: Characters have constant integer width.
  234. vCharPos_H2(dco,rfo,xRef,yRef,efScaleX);
  235. }
  236. else
  237. {
  238. // Case H3: The general case.
  239. vCharPos_H3(dco,rfo,xRef,yRef,lExtra,lBreakExtra,cBreak,efScaleX);
  240. }
  241. /**********************************************************************\
  242. * Horizontal special cases done!
  243. *
  244. * It remains only to finish the alignment.
  245. \**********************************************************************/
  246. // Offset all the relevant points if our alignment is RIGHT or CENTER.
  247. // Also correct the CP update vector.
  248. ptfxEscapement.x = ptfxUpdate.x; // Remember this for underlining.
  249. ptfxEscapement.y = ptfxUpdate.y;
  250. if (flControl & (TA_RIGHT | TA_CENTER))
  251. {
  252. FIX dx = ptfxUpdate.x;
  253. if ((flControl & TA_CENTER) == TA_CENTER)
  254. {
  255. dx /= 2;
  256. ptfxUpdate.x = 0; // Don't update CP.
  257. }
  258. else
  259. {
  260. ptfxUpdate.x = -ptfxUpdate.x; // Reverse the CP update.
  261. }
  262. pg = pgpos;
  263. dx = FXTOL(dx + 8); // Convert to LONG for pgp adjusts
  264. xRef = ((pg++)->ptl.x -= dx); // Always adjust the first one.
  265. xRef = LTOFX(xRef); // Convert back to FIX for later
  266. if (ulCharInc == 0)
  267. {
  268. for (ii=0; ii<(ULONG) cwc-1; ii++)
  269. (pg++)->ptl.x -= dx;
  270. }
  271. }
  272. // Fill in a pdxOut array.
  273. if (pdxOut != (LONG *) NULL)
  274. {
  275. EFLOAT efDtoW = rfo.efDtoWBase();
  276. if (ulCharInc && !bLinkedGlyphs())
  277. {
  278. FIX dx, xSum;
  279. dx = lCvt(efDtoW,LTOFX(ulCharInc));
  280. xSum = 0;
  281. for (ii=0; ii<(ULONG) cwc; ii++)
  282. {
  283. xSum += dx;
  284. *pdxOut++ = xSum;
  285. }
  286. }
  287. else
  288. {
  289. pg = pgpos + 1; // skip the first element
  290. for (ii=0; ii<(ULONG) cwc-1; ii++,pg++)
  291. *pdxOut++ = lCvt(efDtoW,LTOFX(pg->ptl.x) - xRef);
  292. // Unfortunately, to be consistent with the rounding we've done
  293. // in the above cases, we can't simply compute this last one
  294. // as: *pdxOut = lCvt(efDtoW,ptfxUpdate.x):
  295. *pdxOut = lCvt(efDtoW, ((ptfxUpdate.x + xRef) & ~0xf) - xRef);
  296. }
  297. }
  298. ptfxRef.x = LTOFX(pgpos->ptl.x);
  299. ptfxRef.y = LTOFX(pgpos->ptl.y);
  300. }
  301. /**************************************************************************\
  302. * Handle the harder cases, i.e general orientations and transforms are
  303. * allowed.
  304. \**************************************************************************/
  305. else
  306. {
  307. if (!bPdy)
  308. {
  309. if (lEsc == (LONG)rfo.ulOrientation())
  310. {
  311. if (pdx != NULL)
  312. {
  313. // Case G1: A PDX array is provided. Escapement == Orientation.
  314. vCharPos_G1(dco,rfo,xRef,yRef,pdx,pdxOut);
  315. }
  316. else // (pdx == NULL)
  317. {
  318. // Case G2: No PDX array. Escapement == Orientation.
  319. vCharPos_G2(dco,rfo,xRef,yRef,lExtra,lBreakExtra,cBreak,pdxOut);
  320. }
  321. }
  322. else // lEsc!=rfo.ulOrientation()
  323. {
  324. // Case G3: Escapement != Orientation.
  325. // Make sure escapement vectors and data are up to date.
  326. if (!rfo.bCalcEscapement(xo,lEsc))
  327. return;
  328. flTO |= TO_ESC_NOT_ORIENT;
  329. flAccel |= SO_ESC_NOT_ORIENT;
  330. vCharPos_G3
  331. (
  332. dco,
  333. rfo,
  334. xRef,yRef,
  335. lExtra,lBreakExtra,cBreak,
  336. pdx,
  337. pdxOut
  338. );
  339. }
  340. }
  341. else // pdy case
  342. {
  343. // Make sure escapement vectors and data are up to date.
  344. if (!rfo.bCalcEscapement(xo,lEsc))
  345. return;
  346. flTO |= TO_ESC_NOT_ORIENT;
  347. vCharPos_G4
  348. (
  349. dco,
  350. rfo,
  351. xRef,
  352. yRef,
  353. pdx
  354. );
  355. }
  356. /**********************************************************************\
  357. * General special cases done!
  358. *
  359. * It remains only to finish the alignment.
  360. \**********************************************************************/
  361. // Offset all the relevant points if our alignment is RIGHT or CENTER.
  362. // Also correct the CP update vector.
  363. ptfxEscapement = ptfxUpdate; // Remember this for underlining.
  364. if (flControl & (TA_RIGHT | TA_CENTER))
  365. {
  366. FIX dx = ptfxUpdate.x;
  367. FIX dy = ptfxUpdate.y;
  368. if ((flControl & TA_CENTER) == TA_CENTER)
  369. {
  370. dx /= 2;
  371. dy /= 2;
  372. ptfxUpdate.x = 0; // No CP update.
  373. ptfxUpdate.y = 0;
  374. }
  375. else
  376. {
  377. ptfxUpdate.x = -ptfxUpdate.x; // Reverse the CP update.
  378. ptfxUpdate.y = -ptfxUpdate.y;
  379. }
  380. pg = pgpos;
  381. for (ii=0; ii<(ULONG)cwc; ii++)
  382. {
  383. pg->ptl.x -= dx;
  384. pg->ptl.y -= dy;
  385. pg++;
  386. }
  387. xRef -= dx;
  388. yRef -= dy;
  389. }
  390. // Convert the FIX coordinates to LONG for low res devices.
  391. pg = pgpos;
  392. ptfxRef.x = xRef;
  393. ptfxRef.y = yRef;
  394. for (ii=0; ii<(ULONG)cwc; ii++,pg++)
  395. {
  396. pg->ptl.x = FXTOL(pg->ptl.x + 8);
  397. pg->ptl.y = FXTOL(pg->ptl.y + 8);
  398. }
  399. }
  400. // Fill in the underline and strikeout rectangles. The horizontal cases
  401. // are the only ones that can use the extra rectangles of DrvTextOut to
  402. // draw the lines quickly. We'll use a PATHOBJ (in a separate optional
  403. // method) for the complex cases.
  404. if (flControl & (TSIM_UNDERLINE1 | TSIM_STRIKEOUT))
  405. {
  406. flTO |= flControl & (TSIM_UNDERLINE1 | TSIM_STRIKEOUT);
  407. if (((lEsc | rfo.ulOrientation() | bPdy) == 0) && xo.bScale())
  408. {
  409. ERECTL *prcl = (ERECTL *) &arclExtra[cExtraRects];
  410. // Round off the starting point and update width to pels.
  411. LONG x = FXTOL(xRef+8);
  412. LONG y = FXTOL(yRef+8);
  413. LONG dx = FXTOL(ptfxEscapement.x+8);
  414. if (flControl & TSIM_UNDERLINE1)
  415. {
  416. prcl->right = (prcl->left = x + rfo.ptlUnderline1().x) + dx;
  417. prcl->bottom = (prcl->top = y + rfo.ptlUnderline1().y)
  418. + rfo.ptlULThickness().y;
  419. prcl->vOrder();
  420. cExtraRects++;
  421. prcl++;
  422. }
  423. if (flControl & TSIM_STRIKEOUT)
  424. {
  425. prcl->right = (prcl->left = x + rfo.ptlStrikeOut().x) + dx;
  426. prcl->bottom = (prcl->top = y + rfo.ptlStrikeOut().y)
  427. + rfo.ptlSOThickness().y;
  428. prcl->vOrder();
  429. cExtraRects++;
  430. prcl++;
  431. }
  432. // Put a NULL rectangle at the end of the list.
  433. prcl->left = 0;
  434. prcl->right = 0;
  435. prcl->bottom = 0;
  436. prcl->top = 0;
  437. }
  438. }
  439. if ( rfo.prfnt->fobj.flFontType & RASTER_FONTTYPE )
  440. {
  441. flTO |= TO_BITMAPS;
  442. }
  443. else
  444. {
  445. flTO &= ~TO_BITMAPS;
  446. }
  447. }
  448. /******************************Member*Function*****************************\
  449. * ESTROBJ::vInitSimple
  450. *
  451. * Constructor for ESTROBJ. Performs the following operations:
  452. *
  453. * 1) Initialize the STROBJ fields for the driver.
  454. * 2) Compute all character positions.
  455. * 3) Compute the TextBox.
  456. * 4) Stores the TextBox in the ESTROBJ. <--- Note!
  457. *
  458. * The is the special case code for the console, so we ignore transforms
  459. * and other fancy options.
  460. *
  461. * Note that you don't need to call bOpaqueArea to get rclBkGround
  462. * initialized. This is a difference from the normal vInit.
  463. *
  464. * History:
  465. * Thu 17-Sep-1992 17:32:10 -by- Charles Whitmer [chuckwh]
  466. * Took the vInit code and simplified it for the special console case.
  467. \**************************************************************************/
  468. VOID ESTROBJ::vInitSimple
  469. (
  470. PWSZ pwsz,
  471. LONG cwc,
  472. XDCOBJ& dco,
  473. RFONTOBJ& rfo,
  474. LONG xRef,
  475. LONG yRef,
  476. PVOID pvBuffer
  477. )
  478. {
  479. // Characters have constant integer width. We will also ignore the A and C spaces.
  480. EGLYPHPOS *pg;
  481. cGlyphs = cwc;
  482. prfo = &rfo;
  483. cgposCopied = 0;
  484. pgp = NULL;
  485. pwszOrg = pwsz;
  486. ASSERTGDI(cwc > 0, "Count of glyphs must be greater than zero");
  487. // Locate the GLYPHPOS array. Try to use the default one on the stack. We
  488. // need one more GLYPHPOS structure than there are glyphs. The concatenation
  489. // point is computed in the last one.
  490. if (pvBuffer)
  491. {
  492. pg = (EGLYPHPOS *) pvBuffer;
  493. }
  494. else
  495. {
  496. pg = (EGLYPHPOS *) PVALLOCTEMPBUFFER(SIZEOF_STROBJ_BUFFER(cwc));
  497. if (pg == (PGLYPHPOS) NULL)
  498. return;
  499. // Note that the memory has been allocated.
  500. flTO |= TO_MEM_ALLOCATED;
  501. }
  502. pgpos = pg; // Make sure our cached value is in the structure.
  503. // Compute device driver accelerator flags.
  504. flAccel = SO_HORIZONTAL | (rfo.flRealizedType() & SO_ACCEL_FLAGS);
  505. BOOL bAccel;
  506. if (!rfo.bGetGlyphMetricsPlus(cwc, pg, pwsz, &bAccel, &dco, this))
  507. return;
  508. if ( bAccel )
  509. {
  510. flTO |= TO_ALL_PTRS_VALID;
  511. pgp = pgpos;
  512. }
  513. // We leave these variables uninitialized in this simple case.
  514. // BE CAREFUL!
  515. // cExtraRects = 0;
  516. // ptfxUpdate.x = dx;
  517. // ptfxUpdate.y = 0;
  518. // ptfxEscapement = ptfxUpdate;
  519. // ptfxRef.x = xRef;
  520. // ptfxRef.y = yRef;
  521. // Offset the reference point for TA_TOP. Our GLYPHPOS structures always contain
  522. // positions along the baseline.
  523. // We assume that displays never set the GCAPS_HIGHRESTEXT bit.
  524. pg->ptl.x = xRef;
  525. pg->ptl.y = yRef + rfo.lMaxAscent();
  526. // Set the width accelerator. When the device driver sees ulCharInc
  527. // non-zero, it must not expect any more x coordinates.
  528. ulCharInc = rfo.lCharInc();
  529. #ifdef FE_SB
  530. // If this is a SBCS linked to a DBCS font the font is really "binary pitch" and we
  531. // should ignore ulCharInc. In the case of a DBCS TT font, the font is also really
  532. // "binary pitch" and the TT driver will set ulCharInc to 0. In either case use
  533. // the individual glyph metrics to lay out glyphs. This is slightly slower than
  534. // the fixed pitch optimization but not enough to be significant.
  535. if( bLinkedGlyphs() || (ulCharInc == 0) )
  536. {
  537. FIX xA , xLeft , xRight;
  538. UINT ii;
  539. ulCharInc = 0;
  540. // Calculate the left bound using only the first glyph.
  541. xLeft = pg->pgd()->fxA;
  542. // Handle the remaining glyphs in this batch.
  543. xA = 0; // Distance along the escapement (x) in device coords.
  544. for (ii=1; ii<(unsigned) cwc; ii++)
  545. {
  546. // Compute the next position.
  547. xA += pg->pgd()->fxD;
  548. pg++;
  549. pg->ptl.x = xRef + FXTOL(8 + xA);
  550. pg->ptl.y = yRef + rfo.lMaxAscent();
  551. }
  552. // Calculate the right bound. This is easier than the general case since
  553. // there's no extra spacing.
  554. xRight = xA + pg->pgd()->fxAB;
  555. // Compute the bounding rectangle.
  556. rclBkGround.left = xRef + FXTOL(xLeft);
  557. rclBkGround.right = xRef + FXTOLCEILING(xRight);
  558. rclBkGround.top = yRef;
  559. rclBkGround.bottom = yRef + rfo.lMaxHeight();
  560. }
  561. else
  562. {
  563. #endif
  564. // Compute the bounding rectangle.
  565. rclBkGround.left = xRef;
  566. rclBkGround.right = xRef + cwc * ulCharInc;
  567. rclBkGround.top = yRef;
  568. rclBkGround.bottom = yRef + rfo.lMaxHeight();
  569. }
  570. // color filtering causes spill on each side for cleartype
  571. if (rfo.pfo()->flFontType & FO_CLEARTYPE_X)
  572. {
  573. rclBkGround.left -= 1;
  574. rclBkGround.right += 1;
  575. }
  576. flTO |= TO_VALID;
  577. }
  578. /******************************Public*Routine******************************\
  579. *
  580. * Routine Name: "ESTROBJ::vCorrectBackGround"
  581. *
  582. * Routine Description:
  583. *
  584. * If a glyph lies outside the background rectangle
  585. * the background rectangle is expanded to contain
  586. * the errant glyph. This is a hack routine to fix
  587. * some anomalies found when rendering texts at
  588. * arbitrary angles.
  589. *
  590. * Arguments:
  591. *
  592. * pfo a pointer to the associated FONTOBJ
  593. * This is used to inform us if the
  594. * font contains bitmaps
  595. *
  596. * Return Value: TRUE if string is consistent FALSE if not.
  597. *
  598. \**************************************************************************/
  599. #if DBG
  600. void ESTROBJ::vCorrectBackGroundError(GLYPHPOS *pgp)
  601. {
  602. GLYPHBITS *pgb = pgp->pgdf->pgb;
  603. char *psz = "vCorrectBackGround: Glyph found outside background rectangle";
  604. DbgPrint("\n");
  605. DbgPrint("\n");
  606. DbgPrint("%s\n", psz);
  607. DbgPrint("STROJB* = %-#x\n", this);
  608. DbgPrint(
  609. "rclBkGround = %d %d %d %d\n",
  610. rclBkGround.left,
  611. rclBkGround.top,
  612. rclBkGround.right,
  613. rclBkGround.bottom
  614. );
  615. DbgPrint("pgp = %-#x\n", pgp);
  616. DbgPrint(" hg = %-#x\n", pgp->hg);
  617. DbgPrint(" ptl = %d %d\n", pgp->ptl.x, pgp->ptl.y);
  618. DbgPrint(" pgb = %-#x\n", pgb);
  619. DbgPrint(" ptlOrigin = %d %d\n", pgb->ptlOrigin.x, pgb->ptlOrigin.y);
  620. DbgPrint(" sizlBitmap = %d %d\n", pgb->sizlBitmap.cx, pgb->sizlBitmap.cy);
  621. DbgPrint("\n");
  622. RIP("Stopping for debugging\n");
  623. }
  624. void ESTROBJ::vCorrectBackGround()
  625. {
  626. LONG l; // place holder for glyph bitmap coord
  627. GLYPHPOS *pgp, *pgp_;
  628. GLYPHBITS *pgb;
  629. if (
  630. ((flAccel & SO_FLAG_DEFAULT_PLACEMENT) == 0 ) &&
  631. ( flTO & TO_BITMAPS ) &&
  632. ( pgpos )
  633. )
  634. {
  635. pgp_ = pgpos + cGlyphs;
  636. for ( pgp = pgpos ; pgp < pgp_ ; pgp++ ) {
  637. if ( pgb = pgp->pgdf->pgb )
  638. {
  639. l = pgp->ptl.x + pgb->ptlOrigin.x;
  640. if ( l < rclBkGround.left )
  641. {
  642. vCorrectBackGroundError( pgp );
  643. rclBkGround.left = l;
  644. }
  645. l += pgb->sizlBitmap.cx;
  646. if ( l > rclBkGround.right )
  647. {
  648. vCorrectBackGroundError( pgp );
  649. rclBkGround.right = l;
  650. }
  651. l = pgp->ptl.y + pgb->ptlOrigin.y;
  652. if ( l < rclBkGround.top )
  653. {
  654. vCorrectBackGroundError( pgp );
  655. rclBkGround.top = l;
  656. }
  657. l += pgb->sizlBitmap.cy;
  658. if ( l > rclBkGround.bottom )
  659. {
  660. vCorrectBackGroundError( pgp );
  661. rclBkGround.bottom = l;
  662. }
  663. }
  664. }
  665. }
  666. }
  667. #endif
  668. /******************************Public*Routine******************************\
  669. * ESTROBJ::vCharPos_G3 (rfo,x,y,lExtra,lBreakExtra,cBreak,pdx,pdxOut)
  670. *
  671. * Computes character positions in the case where escapement does not equal
  672. * orientation. This is pretty tricky. We have to make up vertical
  673. * spacings. Also, the character positions we record in the GLYPHPOS
  674. * structure all have to be adjusted because for general escapements the
  675. * concatenation point is not the same as the character origin.
  676. *
  677. * The following fields of the ESTROBJ are filled in:
  678. *
  679. * 1) Each x,y position.
  680. * 2) Bounding coordinates in rcfx.
  681. * 3) The ptfxUpdate vector.
  682. *
  683. * History:
  684. * Sun 22-Mar-1992 23:31:55 -by- Charles Whitmer [chuckwh]
  685. * Wrote it.
  686. \**************************************************************************/
  687. VOID ESTROBJ::vCharPos_G3
  688. (
  689. XDCOBJ& dco,
  690. RFONTOBJ& rfo,
  691. FIX xRef,
  692. FIX yRef,
  693. LONG lExtra,
  694. LONG lBreakExtra,
  695. LONG cBreak,
  696. LONG *pdx,
  697. LONG *pdxOut
  698. )
  699. {
  700. // In this case, we keep track of how far we have traveled along the
  701. // escapement vector in device coordinates. We need scales to project
  702. // this distance onto the base and ascent, as well as a unit escapement
  703. // vector to find the position.
  704. POINTFL pteEsc = rfo.pteUnitEsc(); // Unit escapement vector.
  705. EFLOAT efScaleX = rfo.efEscToBase(); // Project escapement to baseline.
  706. EFLOAT efScaleY = rfo.efEscToAscent(); // Project escapement to ascent.
  707. // Compute logical to device transforms.
  708. EFLOAT efWtoDEsc = rfo.efWtoDEsc(); // Forward transform for pdx.
  709. EFLOAT efDtoWEsc = rfo.efDtoWEsc(); // Back transform for pdxOut.
  710. // Compute extra spacing for the non-pdx case.
  711. FIX fxD1,fxD2; // Pre- and Post-center character widths.
  712. FIX fxAscent = rfo.fxMaxAscent(); // Cache locally.
  713. HGLYPH hgBreak;
  714. if (pdx == (LONG *) NULL)
  715. {
  716. // Calculate the lExtra and lBreakExtra spacing.
  717. xExtra = 0;
  718. xBreakExtra = 0;
  719. hgBreak = 0;
  720. if (lExtra)
  721. {
  722. xExtra = lCvt(rfo.efWtoDEsc(),lExtra);
  723. }
  724. if (lBreakExtra && cBreak)
  725. {
  726. xBreakExtra = lCvt(rfo.efWtoDEsc(),lBreakExtra) / cBreak;
  727. // Windows won't let us back up over a break.
  728. vGenWidths
  729. (
  730. &fxD1, // Pre-center spacing
  731. &fxD2, // Post-center spacing
  732. efScaleY, // Ascent projection
  733. efScaleX, // Baseline projection
  734. rfo.fxBreak(), // Character width
  735. fxAscent, // Ink box top
  736. 0, // Ink box bottom
  737. fxAscent // Maximum Ascent
  738. );
  739. if (fxD1 + fxD2 + xBreakExtra + xExtra < 0)
  740. xBreakExtra = -(fxD1 + fxD2 + xExtra);
  741. hgBreak = rfo.hgBreak();
  742. }
  743. }
  744. // Make some local pointers.
  745. EGLYPHPOS *pg = pgpos;
  746. GLYPHDATA *pgd;
  747. WCHAR *pwsz = pwszOrg;
  748. // Set the first character position.
  749. pg->ptl.x = xRef;
  750. pg->ptl.y = yRef;
  751. // Set up for character loop.
  752. LONG xSum; // Keep pdx sum here.
  753. FIX xA,xB; // Baseline coordinates.
  754. FIX yA,yB; // Ascent coordinates.
  755. FIX sA; // Position on the escapement vector.
  756. RECTFX rcfxBounds; // Accumulate bounds here.
  757. UINT ii;
  758. FIX fxDescent = rfo.fxMaxDescent(); // Cache locally.
  759. rcfxBounds.xLeft = LONG_MAX; // Start with an empty TextBox.
  760. rcfxBounds.xRight = LONG_MIN;
  761. rcfxBounds.yTop = LONG_MIN;
  762. rcfxBounds.yBottom = LONG_MAX;
  763. ASSERTGDI(cGlyphs > 0, "G3, cGlyphs == 0\n");
  764. // We keep the current concatenation point in sA. Note that this is NOT
  765. // where the character origin will be placed.
  766. sA = 0;
  767. xSum = 0;
  768. BOOL bAccel;
  769. if (!rfo.bGetGlyphMetricsPlus(cGlyphs, pg, pwsz, &bAccel, &dco, this))
  770. return;
  771. if (bAccel)
  772. {
  773. flTO |= TO_ALL_PTRS_VALID;
  774. pgp = pgpos;
  775. }
  776. BOOL bZeroBearing = ( rfo.flRealizedType() & SO_ZERO_BEARINGS ) && !bLinkedGlyphs();
  777. for (ii=0; ii<cGlyphs; ii++)
  778. {
  779. pgd = pg->pgd();
  780. // Using the GenWidths function, determine where the
  781. // character center should be placed.
  782. vGenWidths
  783. (
  784. &fxD1, // Pre-center spacing
  785. &fxD2, // Post-center spacing
  786. efScaleY, // Ascent projection
  787. efScaleX, // Baseline projection
  788. pgd->fxD, // Character width
  789. pgd->fxInkTop, // Ink box top
  790. pgd->fxInkBottom, // Ink box bottom
  791. fxAscent // Maximum Ascent
  792. );
  793. sA += fxD1; // Advance to the character center.
  794. // Update ascent bounds.
  795. yA = lCvt(efScaleY,sA); // Project onto ascent.
  796. yB = yA + fxDescent;
  797. if (yB < rcfxBounds.yBottom)
  798. rcfxBounds.yBottom = yB;
  799. yB = yA + fxAscent;
  800. if (yB > rcfxBounds.yTop)
  801. rcfxBounds.yTop = yB;
  802. ASSERTGDI(!rfo.bSmallMetrics(),"ESTROBJ__vCharPos_G3: Small Metrics in cache\n");
  803. // Project the center position onto the baseline and
  804. // move back to the character origin.
  805. xA = lCvt(efScaleX,sA) - pgd->fxD / 2;
  806. // Update the width bounds. Fudge a quarter pel on each side for
  807. // roundoff.
  808. if( bZeroBearing )
  809. {
  810. xB = xA - 4;
  811. if (xB < rcfxBounds.xLeft)
  812. rcfxBounds.xLeft = xB;
  813. xB = xA + pgd->fxD + 4;
  814. if (xB > rcfxBounds.xRight)
  815. rcfxBounds.xRight = xB;
  816. }
  817. else
  818. {
  819. xB = xA + pgd->fxA - 4;
  820. if (xB < rcfxBounds.xLeft)
  821. rcfxBounds.xLeft = xB;
  822. xB = xA + pgd->fxAB + 4;
  823. if (xB > rcfxBounds.xRight)
  824. rcfxBounds.xRight = xB;
  825. }
  826. // Save the adjusted character origin.
  827. pg->ptl.x
  828. = xRef + lCvt(pteEsc.x,sA) - pgd->ptqD.x.u.HighPart / 2;
  829. pg->ptl.y
  830. = yRef + lCvt(pteEsc.y,sA) - pgd->ptqD.y.u.HighPart / 2;
  831. // Advance to the next concatenation point.
  832. if (pdx != (LONG *) NULL)
  833. {
  834. xSum += *pdx++;
  835. sA = lCvt(efWtoDEsc,xSum);
  836. if (pdxOut != (LONG *) NULL)
  837. *pdxOut++ = xSum;
  838. }
  839. else
  840. {
  841. sA += fxD2 + xExtra;
  842. if (xBreakExtra && (pg->hg == hgBreak))
  843. {
  844. sA += xBreakExtra;
  845. }
  846. // Record the concatenation point for GetTextExtentEx. This
  847. // would be very difficult to reconstruct at a later time.
  848. if (pdxOut != (LONG *) NULL)
  849. *pdxOut++ = lCvt(efDtoWEsc,sA);
  850. }
  851. pg++;
  852. }
  853. ptfxUpdate.x = lCvt(pteEsc.x,sA);
  854. ptfxUpdate.y = lCvt(pteEsc.y,sA);
  855. rcfx = rcfxBounds;
  856. flTO |= TO_VALID;
  857. }
  858. /******************************Public*Routine******************************\
  859. * ESTROBJ::vCharPos_G2 (rfo,xRef,yRef,lExtra,lBreakExtra,cBreak,pdxOut)
  860. *
  861. * Computes character positions in the case where no pdx array is provided
  862. * and escapement equals orientation.
  863. *
  864. * The following fields of the ESTROBJ are filled in:
  865. *
  866. * 1) Each x,y position.
  867. * 2) Bounding coordinates in rcfx.
  868. * 3) The ptfxUpdate vector.
  869. * 4) The fxExtent.
  870. *
  871. * History:
  872. * Sun 22-Mar-1992 23:31:55 -by- Charles Whitmer [chuckwh]
  873. * Wrote it.
  874. \**************************************************************************/
  875. VOID ESTROBJ::vCharPos_G2
  876. (
  877. XDCOBJ& dco,
  878. RFONTOBJ& rfo,
  879. FIX xRef,
  880. FIX yRef,
  881. LONG lExtra,
  882. LONG lBreakExtra,
  883. LONG cBreak,
  884. LONG *pdxOut
  885. )
  886. {
  887. // Calculate the lExtra and lBreakExtra spacing.
  888. HGLYPH hgBreak = 0;
  889. EPOINTQF ptqExtra; // Accurate spacing along the escapement.
  890. EPOINTQF ptqBreakExtra;
  891. if (lExtra)
  892. {
  893. xExtra = lCvt(rfo.efWtoDBase(),lExtra);
  894. ptqExtra = rfo.pteUnitBase();
  895. ptqExtra *= (LONG) xExtra;
  896. }
  897. if (lBreakExtra && cBreak)
  898. {
  899. xBreakExtra = lCvt(rfo.efWtoDBase(),lBreakExtra) / cBreak;
  900. // Windows won't let us back up over a break.
  901. if (rfo.fxBreak() + xBreakExtra + xExtra < 0)
  902. xBreakExtra = -(rfo.fxBreak() + xExtra);
  903. ptqBreakExtra = rfo.pteUnitBase();
  904. ptqBreakExtra *= (LONG) xBreakExtra;
  905. hgBreak = rfo.hgBreak();
  906. }
  907. // Prepare for a pdxOut.
  908. EFLOAT efDtoW = rfo.efDtoWBase();
  909. // Make some local pointers.
  910. EGLYPHPOS *pg = pgpos;
  911. GLYPHDATA *pgd;
  912. WCHAR *pwsz = pwszOrg;
  913. // Set the first character position.
  914. pg->ptl.x = xRef;
  915. pg->ptl.y = yRef;
  916. // Set up for character loop.
  917. FIX xA,xB;
  918. FIX xLeft,xRight; // Accumulate bounds here.
  919. UINT ii;
  920. EPOINTQF ptq; // Record the current position here.
  921. ptq.y = ptq.x = (LONGLONG) LONG_MAX + 1;
  922. xLeft = 0; // Start with an empty TextBox.
  923. xRight = 0;
  924. xA = 0; // Distance along the escapement (x) in device coords.
  925. BOOL bAccel;
  926. if (!rfo.bGetGlyphMetricsPlus(cGlyphs,pg, pwsz, &bAccel,&dco,this))
  927. return;
  928. if (bAccel)
  929. {
  930. flTO |= TO_ALL_PTRS_VALID;
  931. pgp = pgpos;
  932. }
  933. ASSERTGDI(!rfo.bSmallMetrics(),"ESTROBJ__vCharPos_G2: Small Metrics in cache\n");
  934. BOOL bZeroBearing = ( rfo.flRealizedType() & SO_ZERO_BEARINGS ) && !bLinkedGlyphs();
  935. ii = cGlyphs;
  936. while (TRUE)
  937. {
  938. // Update the bounds.
  939. if( bZeroBearing )
  940. {
  941. pgd = pg->pgd();
  942. if (xA < xLeft)
  943. xLeft = xA;
  944. xB = xA + pgd->fxD;
  945. if (xB > xRight)
  946. xRight = xB;
  947. }
  948. else
  949. {
  950. pgd = pg->pgd();
  951. xB = xA + pgd->fxA;
  952. if (xB < xLeft)
  953. xLeft = xB;
  954. xB = xA + pgd->fxAB;
  955. if (xB > xRight)
  956. xRight = xB;
  957. }
  958. // Move to the next position.
  959. xA += pgd->fxD;
  960. ptq += pgd->ptqD;
  961. if ( (xExtra) && (xExtra + pgd->fxD > 0) )
  962. {
  963. xA += xExtra;
  964. ptq += ptqExtra;
  965. }
  966. if (xBreakExtra && (pg->hg == hgBreak))
  967. {
  968. xA += xBreakExtra;
  969. ptq += ptqBreakExtra;
  970. }
  971. // Handle a pdxOut.
  972. if (pdxOut != (LONG *) NULL)
  973. *pdxOut++ = lCvt(efDtoW,xA);
  974. if (--ii == 0)
  975. break;
  976. // Save the next position.
  977. pg++;
  978. pg->ptl.x = xRef + (LONG) (ptq.x >> 32);
  979. pg->ptl.y = yRef + (LONG) (ptq.y >> 32);
  980. }
  981. fxExtent = xA;
  982. ptfxUpdate.x = (LONG) (ptq.x >> 32);
  983. ptfxUpdate.y = (LONG) (ptq.y >> 32);
  984. // Expand the text box out to the concatenation point. This allows us to
  985. // continue on with another opaqued string with no visible gap in the
  986. // opaquing.
  987. if (xA > xRight)
  988. xRight = xA;
  989. else if (xA < xLeft)
  990. xLeft = xA; // possible if lExtra < 0
  991. rcfx.xLeft = xLeft;
  992. rcfx.xRight = xRight;
  993. rcfx.yTop = rfo.fxMaxAscent();
  994. rcfx.yBottom = rfo.fxMaxDescent();
  995. flTO |= TO_VALID;
  996. }
  997. /******************************Public*Routine******************************\
  998. * ESTROBJ::vCharPos_G1 (rfo,xRef,yRef,pdx,pdxOut)
  999. *
  1000. * Computes character positions in the case where a pdx array is provided
  1001. * and escapement equals orientation.
  1002. *
  1003. * The following fields of the ESTROBJ are filled in:
  1004. *
  1005. * 1) Each x,y position.
  1006. * 2) Bounding coordinates in rcfx.
  1007. * 3) The ptfxUpdate vector.
  1008. *
  1009. * History:
  1010. * Sun 22-Mar-1992 18:48:19 -by- Charles Whitmer [chuckwh]
  1011. * Wrote it.
  1012. \**************************************************************************/
  1013. VOID ESTROBJ::vCharPos_G1
  1014. (
  1015. XDCOBJ& dco,
  1016. RFONTOBJ& rfo,
  1017. FIX xRef,
  1018. FIX yRef,
  1019. LONG *pdx,
  1020. LONG *pdxOut
  1021. )
  1022. {
  1023. ASSERTGDI(!rfo.bSmallMetrics(),"ESTROBJ__vCharPos_G1: Small Metrics in cache\n");
  1024. // Our X scale is measured along the escapement direction. We cache a
  1025. // local copy of the unit escapement vector.
  1026. EFLOAT efScaleX = rfo.efWtoDBase();
  1027. POINTFL pteEsc = rfo.pteUnitBase();
  1028. // Make some local pointers.
  1029. EGLYPHPOS *pg = pgpos;
  1030. GLYPHDATA *pgd;
  1031. WCHAR *pwsz = pwszOrg;
  1032. // Set the first character position.
  1033. pg->ptl.x = xRef;
  1034. pg->ptl.y = yRef;
  1035. // Set up for character loop.
  1036. FIX xA,xB;
  1037. LONG xSum;
  1038. FIX xLeft,xRight; // Accumulate bounds here.
  1039. UINT ii;
  1040. xLeft = 0; // Start with an empty TextBox.
  1041. xRight = 0;
  1042. xA = 0; // Distance along the escapement (x) in device coords.
  1043. // To avoid roundoff errors, we accumulate the DX widths in logical
  1044. // coordinates and transform the sums.
  1045. xSum = 0;
  1046. BOOL bAccel;
  1047. if (!rfo.bGetGlyphMetricsPlus(cGlyphs, pg, pwsz, &bAccel,&dco,this))
  1048. return;
  1049. if (bAccel)
  1050. {
  1051. flTO |= TO_ALL_PTRS_VALID;
  1052. pgp = pgpos;
  1053. }
  1054. BOOL bZeroBearing = (rfo.flRealizedType() & SO_ZERO_BEARINGS) && !bLinkedGlyphs();
  1055. ii = cGlyphs;
  1056. while (TRUE)
  1057. {
  1058. // Update the bounds.
  1059. if( bZeroBearing )
  1060. {
  1061. pgd = pg->pgd();
  1062. if (xA < xLeft)
  1063. xLeft = xA;
  1064. xB = xA + pgd->fxD;
  1065. if (xB > xRight)
  1066. xRight = xB;
  1067. }
  1068. else
  1069. {
  1070. pgd = pg->pgd();
  1071. xB = xA + pgd->fxA;
  1072. if (xB < xLeft)
  1073. xLeft = xB;
  1074. xB = xA + pgd->fxAB;
  1075. if (xB > xRight)
  1076. xRight = xB;
  1077. }
  1078. // Add the next offset.
  1079. xSum += *pdx++;
  1080. if (pdxOut != (LONG *) NULL)
  1081. *pdxOut++ = xSum;
  1082. // Scale the new offset.
  1083. xA = lCvt(efScaleX,xSum);
  1084. if (--ii == 0)
  1085. break;
  1086. // Save the next position.
  1087. pg++;
  1088. pg->ptl.x = xRef + lCvt(pteEsc.x,xA);
  1089. pg->ptl.y = yRef + lCvt(pteEsc.y,xA);
  1090. }
  1091. // Expand the text box out to the concatenation point. This allows us to
  1092. // continue on with another opaqued string with no visible gap in the
  1093. // opaquing.
  1094. if (xA > xRight)
  1095. xRight = xA;
  1096. ptfxUpdate.x = lCvt(pteEsc.x,xA);
  1097. ptfxUpdate.y = lCvt(pteEsc.y,xA);
  1098. rcfx.xLeft = xLeft;
  1099. rcfx.xRight = xRight;
  1100. rcfx.yTop = rfo.fxMaxAscent();
  1101. rcfx.yBottom = rfo.fxMaxDescent();
  1102. flTO |= TO_VALID;
  1103. }
  1104. /******************************Public*Routine******************************\
  1105. * ESTROBJ::vCharPos_H1 (rfo,xRef,yRef,pdx,efScale)
  1106. *
  1107. * Computes character positions in the simple horizontal case when a pdx
  1108. * array is provided. We use the ABC spacing info for the TextBox.
  1109. *
  1110. * The following fields of the ESTROBJ are filled in:
  1111. *
  1112. * 1) Each x,y position.
  1113. * 2) Bounding coordinates in rcfx.
  1114. * 3) The ptfxUpdate vector.
  1115. * 4) The flAccel flags.
  1116. *
  1117. * History:
  1118. * Sun 22-Mar-1992 18:48:19 -by- Charles Whitmer [chuckwh]
  1119. * Wrote it.
  1120. \**************************************************************************/
  1121. VOID ESTROBJ::vCharPos_H1
  1122. (
  1123. XDCOBJ& dco,
  1124. RFONTOBJ& rfo,
  1125. FIX xRef,
  1126. FIX yRef,
  1127. LONG *pdx,
  1128. EFLOAT efScale
  1129. )
  1130. {
  1131. // Make some local pointers.
  1132. EGLYPHPOS *pg = pgpos;
  1133. GLYPHDATA *pgd;
  1134. WCHAR *pwsz = pwszOrg;
  1135. // Compute device driver accelerator flags.
  1136. flAccel |= SO_HORIZONTAL
  1137. | (rfo.flRealizedType() & SO_MAXEXT_EQUAL_BM_SIDE);
  1138. // The transform is pretty simple, we're going to handle it ourselves.
  1139. // Accelerate on a really simple transform.
  1140. BOOL bUnity = efScale.bIs16();
  1141. BOOL bAccel;
  1142. if (!rfo.bGetGlyphMetricsPlus(cGlyphs, pg, pwsz, &bAccel,&dco,this))
  1143. return;
  1144. if (bAccel)
  1145. {
  1146. flTO |= TO_ALL_PTRS_VALID;
  1147. pgp = pgpos;
  1148. }
  1149. // Set up for character loop.
  1150. FIX xA,xB;
  1151. LONG xSum;
  1152. FIX xLeft,xRight; // Accumulate bounds here.
  1153. UINT ii;
  1154. xLeft = 0; // Start with an empty TextBox.
  1155. xRight = 0;
  1156. // To avoid roundoff errors, we accumulate the DX widths in logical
  1157. // coordinates and transform the sums.
  1158. xSum = 0; // Distance along the escapement in logical coords.
  1159. xA = 0; // Distance along the escapement (x) in device coords.
  1160. // Set the first character position:
  1161. yRef = FXTOL(yRef + 8); // Convert y to LONG coordinate
  1162. xRef += 8; // Add in rounding offset for later
  1163. // converting x to LONG coordinate
  1164. pg->ptl.x = FXTOL(xRef);
  1165. pg->ptl.y = yRef;
  1166. if((rfo.flRealizedType() & SO_ZERO_BEARINGS) && !bLinkedGlyphs())
  1167. {
  1168. ii = cGlyphs;
  1169. while (TRUE)
  1170. {
  1171. // Update the bounds.
  1172. pgd = pg->pgd();
  1173. if (xA < xLeft)
  1174. xLeft = xA;
  1175. xB = xA + pgd->fxD;
  1176. if (xB > xRight)
  1177. xRight = xB;
  1178. // Add the next offset.
  1179. xSum += *pdx++;
  1180. // Scale the new offset.
  1181. xA = bUnity ? LTOFX(xSum) : lCvt(efScale,xSum);
  1182. if (--ii == 0)
  1183. break;
  1184. // Save the next position.
  1185. pg++;
  1186. pg->ptl.y = yRef;
  1187. pg->ptl.x = FXTOL(xA + xRef);
  1188. }
  1189. }
  1190. else
  1191. {
  1192. ii = cGlyphs;
  1193. while (TRUE)
  1194. {
  1195. // Update the bounds.
  1196. pgd = pg->pgd();
  1197. xB = xA + pgd->fxA;
  1198. if (xB < xLeft)
  1199. xLeft = xB;
  1200. xB = xA + pgd->fxAB;
  1201. if (xB > xRight)
  1202. xRight = xB;
  1203. // Add the next offset.
  1204. xSum += *pdx++;
  1205. // Scale the new offset.
  1206. xA = bUnity ? LTOFX(xSum) : lCvt(efScale,xSum);
  1207. if (--ii == 0)
  1208. break;
  1209. // Save the next position.
  1210. pg++;
  1211. pg->ptl.y = yRef;
  1212. pg->ptl.x = FXTOL(xA + xRef);
  1213. }
  1214. }
  1215. // Expand the text box out to the concatenation point. This allows us to
  1216. // continue on with another opaqued string with no visible gap in the
  1217. // opaquing.
  1218. if (xA > xRight)
  1219. xRight = xA;
  1220. ptfxUpdate.x = xA;
  1221. ptfxUpdate.y = 0;
  1222. rcfx.xLeft = xLeft;
  1223. rcfx.xRight = xRight;
  1224. if (dco.pdc->bYisUp())
  1225. {
  1226. rcfx.yTop = -rfo.fxMaxDescent();
  1227. rcfx.yBottom = -rfo.fxMaxAscent();
  1228. }
  1229. else
  1230. {
  1231. rcfx.yTop = rfo.fxMaxAscent();
  1232. rcfx.yBottom = rfo.fxMaxDescent();
  1233. }
  1234. flTO |= TO_VALID;
  1235. }
  1236. /******************************Public*Routine******************************\
  1237. * ESTROBJ::vCharPos_H2()
  1238. *
  1239. * Computes character positions in the simple horizontal case when
  1240. * characters have constant integer width.
  1241. *
  1242. * The following fields of the ESTROBJ are filled in:
  1243. *
  1244. * 1) Each x,y position.
  1245. * 2) Bounding coordinates in rcfx.
  1246. * 3) The ptfxUpdate vector.
  1247. * 4) The flAccel flags.
  1248. * 5) The fxExtent.
  1249. *
  1250. * History:
  1251. * Sun 22-Mar-1992 18:48:19 -by- Charles Whitmer [chuckwh]
  1252. * Wrote it.
  1253. \**************************************************************************/
  1254. VOID ESTROBJ::vCharPos_H2
  1255. (
  1256. XDCOBJ& dco,
  1257. RFONTOBJ& rfo,
  1258. FIX xRef,
  1259. FIX yRef
  1260. ,EFLOAT efScale
  1261. )
  1262. {
  1263. // In this case we will also assume that the A and C spaces are
  1264. // constants.
  1265. //
  1266. // NOTE: this is actually wrong assumption for tt fixed pitch fonts
  1267. // however, we will set ZERO_BEARINGS flag when we want to lie
  1268. // about this to the engine. [bodind]
  1269. LONG dx;
  1270. // Make some local pointers.
  1271. EGLYPHPOS *pg = pgpos;
  1272. GLYPHDATA *pgd;
  1273. WCHAR *pwsz = pwszOrg;
  1274. // Set the first character position. This is the only y position
  1275. // we'll fill in.
  1276. pg->ptl.x = FXTOL(xRef + 8);
  1277. pg->ptl.y = FXTOL(yRef + 8);
  1278. // Compute device driver accelerator flags.
  1279. flAccel |= SO_HORIZONTAL | (rfo.flRealizedType() & SO_ACCEL_FLAGS);
  1280. // Set the width accelerator. When the device driver sees ulCharInc
  1281. // non-zero, it must not expect any more x coordinates.
  1282. ulCharInc = rfo.lCharInc();
  1283. dx = LTOFX(cGlyphs * ulCharInc);
  1284. fxExtent = dx;
  1285. BOOL bAccel;
  1286. if (!rfo.bGetGlyphMetricsPlus(cGlyphs, pg, pwsz, &bAccel,&dco,this))
  1287. return;
  1288. #ifdef FE_SB
  1289. // if there are linked glyphs we can't count on this optimization
  1290. if(bLinkedGlyphs())
  1291. {
  1292. ASSERTGDI((dco.pdc->lTextExtra()|dco.pdc->lBreakExtra()) == 0,
  1293. "vCharPos_H3 lTextExtra or lBreakExtra non zero\n");
  1294. vCharPos_H3(dco,rfo,xRef,yRef,0,0,dco.pdc->cBreak(),efScale,&bAccel);
  1295. return;
  1296. }
  1297. #endif
  1298. if (bAccel)
  1299. {
  1300. flTO |= TO_ALL_PTRS_VALID;
  1301. pgp = pgpos;
  1302. }
  1303. pgd = pg->pgd();
  1304. if (flAccel & SO_ZERO_BEARINGS)
  1305. {
  1306. rcfx.xLeft = 0;
  1307. rcfx.xRight = dx;
  1308. }
  1309. else
  1310. {
  1311. //
  1312. // Old Comment from bodind might point out possible work item:
  1313. // these lines of code rely on the const a,c spaces
  1314. // assumption which is only true for simulated italic
  1315. // fonts [bodind]
  1316. rcfx.xLeft = pgd->fxA;
  1317. rcfx.xRight = dx - LTOFX(ulCharInc) + pgd->fxAB;
  1318. }
  1319. if (dco.pdc->bYisUp())
  1320. {
  1321. rcfx.yTop = -rfo.fxMaxDescent();
  1322. rcfx.yBottom = -rfo.fxMaxAscent();
  1323. }
  1324. else
  1325. {
  1326. rcfx.yTop = rfo.fxMaxAscent();
  1327. rcfx.yBottom = rfo.fxMaxDescent();
  1328. }
  1329. ptfxUpdate.x = dx;
  1330. ptfxUpdate.y = 0;
  1331. flTO |= TO_VALID;
  1332. }
  1333. /******************************Public*Routine******************************\
  1334. * ESTROBJ::vCharPos_H3 (rfo,xRef,yRef,lExtra,lBreakExtra,cBreak,efScale)
  1335. *
  1336. * Computes character positions in the simple horizontal case when no pdx
  1337. * array is provided and the character widths are not constant.
  1338. *
  1339. * The following fields of the ESTROBJ are filled in:
  1340. *
  1341. * 1) Each x,y position.
  1342. * 2) Bounding coordinates in rcfx.
  1343. * 3) The ptfxUpdate vector.
  1344. * 4) The flAccel flags.
  1345. * 5) The fxExtent.
  1346. *
  1347. * History:
  1348. * Sun 22-Mar-1992 18:48:19 -by- Charles Whitmer [chuckwh]
  1349. * Wrote it.
  1350. \**************************************************************************/
  1351. VOID ESTROBJ::vCharPos_H3
  1352. (
  1353. XDCOBJ& dco,
  1354. RFONTOBJ& rfo,
  1355. FIX xRef,
  1356. FIX yRef,
  1357. LONG lExtra,
  1358. LONG lBreakExtra,
  1359. LONG cBreak,
  1360. EFLOAT efScale,
  1361. PBOOL pbAccel
  1362. )
  1363. {
  1364. // Calculate the lExtra and lBreakExtra spacing.
  1365. HGLYPH hgBreak = 0;
  1366. if ((lExtra | lBreakExtra) == 0)
  1367. {
  1368. // Will use only character increments given to us with the font
  1369. flAccel |= SO_HORIZONTAL | (rfo.flRealizedType() & SO_ACCEL_FLAGS);
  1370. }
  1371. else
  1372. {
  1373. flAccel |= SO_HORIZONTAL
  1374. | (rfo.flRealizedType() & SO_MAXEXT_EQUAL_BM_SIDE);
  1375. if (lExtra)
  1376. {
  1377. xExtra = lCvt(efScale,lExtra);
  1378. if (xExtra > 0)
  1379. flAccel |= SO_CHARACTER_EXTRA;
  1380. }
  1381. if (lBreakExtra && cBreak)
  1382. {
  1383. xBreakExtra = lCvt(efScale,lBreakExtra) / cBreak;
  1384. // Windows won't let us back up over a break.
  1385. if (rfo.fxBreak() + xBreakExtra + xExtra < 0)
  1386. xBreakExtra = -(rfo.fxBreak() + xExtra);
  1387. hgBreak = rfo.hgBreak();
  1388. flAccel |= SO_BREAK_EXTRA;
  1389. }
  1390. }
  1391. // Make some local pointers.
  1392. EGLYPHPOS *pg = pgpos;
  1393. GLYPHDATA *pgd;
  1394. WCHAR *pwsz = pwszOrg;
  1395. // Set up for FIX to LONG conversion.
  1396. xRef += 8;
  1397. yRef = FXTOL(yRef + 8);
  1398. // Set the first character position.
  1399. pg->ptl.x = FXTOL(xRef);
  1400. pg->ptl.y = yRef;
  1401. // Set up for character loop.
  1402. FIX xA,xB;
  1403. FIX xLeft,xRight; // Accumulate bounds here.
  1404. UINT ii;
  1405. xLeft = 0; // Start with an empty TextBox.
  1406. xRight = 0;
  1407. xA = 0; // Distance along the escapement (x) in device coords.
  1408. BOOL bAccel;
  1409. // If pbAccel is NULL it means we have encountered the case where we were
  1410. // going to do a fixed pitch optimization of the base font but encountered
  1411. // linked characters which weren't fixed pitch. In this case we have
  1412. // already called bGetGlyphMetricsPlus and will signal this by passing
  1413. // in a pointer to bAccel
  1414. if( pbAccel == (BOOL*) NULL )
  1415. {
  1416. if (!rfo.bGetGlyphMetricsPlus(cGlyphs, pg, pwsz, &bAccel, &dco, this))
  1417. return;
  1418. }
  1419. else
  1420. {
  1421. bAccel = *pbAccel;
  1422. }
  1423. if (bAccel)
  1424. {
  1425. flTO |= TO_ALL_PTRS_VALID;
  1426. pgp = pgpos;
  1427. }
  1428. // if there are linked glyphs then SO_ZERO_BEARINGS and SO_CHAR_INC_EQUAL_BM_BASE
  1429. // will be turned off in the ESTROBJ::bPartitionInit
  1430. if (((flAccel & (SO_ZERO_BEARINGS | SO_CHAR_INC_EQUAL_BM_BASE))
  1431. == (SO_ZERO_BEARINGS | SO_CHAR_INC_EQUAL_BM_BASE)) &&
  1432. (xExtra >= 0) &&
  1433. (xBreakExtra == 0))
  1434. {
  1435. // This handles the case when the glyphs won't overlap, thus simplifying
  1436. // the computation of the bounding box.
  1437. ii = cGlyphs;
  1438. while (TRUE)
  1439. {
  1440. pgd = pg->pgd();
  1441. // Move to the next position.
  1442. xA += pgd->fxD + xExtra;
  1443. if (--ii == 0)
  1444. break;
  1445. // Save the next position.
  1446. pg++;
  1447. pg->ptl.x = FXTOL(xA + xRef);
  1448. pg->ptl.y = yRef;
  1449. }
  1450. // Expand the text box out to the concatenation point. This allows us to
  1451. // continue on with another opaqued string with no visible gap in the
  1452. // opaquing.
  1453. xLeft = 0;
  1454. xRight = xA;
  1455. }
  1456. else
  1457. {
  1458. // This handles the general case.
  1459. ii = cGlyphs;
  1460. while (TRUE)
  1461. {
  1462. // Update the bounds.
  1463. pgd = pg->pgd();
  1464. xB = xA + pgd->fxA;
  1465. if (xB < xLeft)
  1466. xLeft = xB;
  1467. xB = xA + pgd->fxAB;
  1468. if (xB > xRight)
  1469. xRight = xB;
  1470. // Move to the next position.
  1471. xA += pgd->fxD;
  1472. // don't let xExtra backup past the origin of the previous glyph
  1473. if( ( xExtra ) && (pgd->fxD + xExtra > 0) )
  1474. {
  1475. xA += xExtra;
  1476. }
  1477. if (pg->hg == hgBreak)
  1478. xA += xBreakExtra;
  1479. if (--ii == 0)
  1480. break;
  1481. // Save the next position.
  1482. pg++;
  1483. pg->ptl.x = FXTOL(xA + xRef);
  1484. pg->ptl.y = yRef;
  1485. }
  1486. // Expand the text box out to the concatenation point. This allows us to
  1487. // continue on with another opaqued string with no visible gap in the
  1488. // opaquing.
  1489. if (xA > xRight)
  1490. xRight = xA;
  1491. }
  1492. fxExtent = xA;
  1493. ptfxUpdate.x = xA;
  1494. ptfxUpdate.y = 0;
  1495. rcfx.xLeft = xLeft;
  1496. rcfx.xRight = xRight;
  1497. if (dco.pdc->bYisUp())
  1498. {
  1499. rcfx.yTop = -rfo.fxMaxDescent();
  1500. rcfx.yBottom = -rfo.fxMaxAscent();
  1501. }
  1502. else
  1503. {
  1504. rcfx.yTop = rfo.fxMaxAscent();
  1505. rcfx.yBottom = rfo.fxMaxDescent();
  1506. }
  1507. flTO |= TO_VALID;
  1508. }
  1509. /******************************Public*Routine******************************\
  1510. * ESTROBJ::bOpaqueArea (pptfx,prcl)
  1511. *
  1512. * Computes the opaquing area for the text.
  1513. *
  1514. * In the complex case, i.e. non-horizontal case, the TextBox is written as
  1515. * a parallelogram into pptfx. A bounding rectangle is computed in prcl.
  1516. * TRUE is returned.
  1517. *
  1518. * In the simple case, the opaque area is also the bounds and is returned
  1519. * only in prcl. FALSE is returned.
  1520. *
  1521. * History:
  1522. * Fri 13-Mar-1992 19:52:00 -by- Charles Whitmer [chuckwh]
  1523. * Wrote it.
  1524. \**************************************************************************/
  1525. BOOL ESTROBJ::bOpaqueArea(POINTFIX *pptfx,RECTL *prcl)
  1526. {
  1527. // Handle the simplest case.
  1528. if (flAccel & SO_HORIZONTAL)
  1529. {
  1530. // The opaque area is a simple rectangle. We do the rounding in a
  1531. // particular order so that if the whole string is displaced by a
  1532. // fraction of a pel in any direction, the TextBox will not change size,
  1533. // and will move exactly with the characters.
  1534. LONG x = FXTOL(ptfxRef.x + 8);
  1535. prcl->left = x + FXTOL(rcfx.xLeft);
  1536. prcl->right = x + FXTOLCEILING(rcfx.xRight);
  1537. // Making the background rectangle compatible with WFW
  1538. //
  1539. // The problem surfaced with Dbase for Windows where one found
  1540. // that a console window would not be repainted correctly. The
  1541. // problem was that the Borland coders relied on the fact that WFW
  1542. // vga drivers make the background rectangle for text equal to the
  1543. // rectangle returned in GetTextExtent(). Using this they would
  1544. // erase blank lines by printing lines with a lot of blanks. Of
  1545. // course this is an extremely bad thing to do but it got the
  1546. // job done, all be it slowly. Now the interesting part: Under
  1547. // WFW the background rectangle for emboldend (via simulation)
  1548. // text has a horizontal extend equal to one greater than the sum
  1549. // of character widths. NT is compatible with this. However,
  1550. // under NT 3.5 Gdi calculated the horizontal extent of the
  1551. // background rectangle equal to the sum of the character widths
  1552. // (at least for simple fonts e.g. MS Sans Serif) because this
  1553. // was guaranteed to cover all of the bits of the glyphy. Thus,
  1554. // for the case of emboldened text, NT had BackGround.x =
  1555. // GetTextExtent.x - 1 where WFW had BackGround.x =
  1556. // GetTextExtent.x. So if the text is simulated bold we bump the
  1557. // horizontal extent of the background rectangle by 1.
  1558. if (
  1559. (prfo->prfnt->fobj.flFontType & FO_SIM_BOLD) &&
  1560. (prfo->prfnt->flInfo & (FM_INFO_TECH_BITMAP | FM_INFO_TECH_STROKE))
  1561. )
  1562. {
  1563. prcl->right++;
  1564. // The line of code that follows this comment is a
  1565. // hack to compensate for a bug in many of the video
  1566. // drivers shipped with 3.5. This started with the
  1567. // S3 driver which is the prototype of all of the NT
  1568. // video driver shipped from Microsoft. The S3
  1569. // driver has the following line of code in textout.c:
  1570. //
  1571. // bTextPerfectFit = (pstro->flAccel &
  1572. // (SO_ZERO_BEARINGS | SO_FLAG_DEFAULT_PLACEMENT |
  1573. // SO_MAXEXT_EQUAL_BM_SIDE |
  1574. // SO_CHAR_INC_EQUAL_BM_BASE)) == (SO_ZERO_BEARINGS |
  1575. // SO_FLAG_DEFAULT_PLACEMENT |
  1576. // SO_MAXEXT_EQUAL_BM_SIDE |
  1577. // SO_CHAR_INC_EQUAL_BM_BASE);
  1578. //
  1579. // it says that if flAccel sets all of the following
  1580. // bits {SO_ZERO_BEARINGS, SO_FLAG_DEFAULT_PLACEMENT,
  1581. // SO_MAXEXT_EQUAL_BM_SIDE, SO_CHAR_INC_EQUAL_BM_BASE}
  1582. // then the S3 driver will assume that the text
  1583. // passed down from the driver is "perfect". The S3
  1584. // driver assumes that if a STROBJ is perfect, then
  1585. // it just has to lay down the text. This conclusion
  1586. // applys to the background rectangle as well. That
  1587. // is, the S3 driver assume that if this magic set of
  1588. // bits is set, then it can safely ignore the
  1589. // background rectangle safe in the knowlege that it
  1590. // will be taken care of in the process of laying
  1591. // down the glyphs. Unfortunately, this assumption of
  1592. // perfection is not correct now that I have bumped
  1593. // up the background rectangle by one. What is a
  1594. // coder to do? Well I have decided to make the text
  1595. // not so perfect by erasing one of the bits. This
  1596. // will have a couple of result. First it correct the
  1597. // bug as demonstrated by Dbase for Windows. Second
  1598. // it will slow down the case of emboldened text.
  1599. // How important is this? I don't know. We usually
  1600. // base our performance decisions on WinBench tests.
  1601. // If this hack has a noticeable impact then we may
  1602. // have to rethink this strategy.
  1603. //
  1604. // Ref. Bug No. 25102 "T1 DBaseWin X86 Command ..."
  1605. //
  1606. // Wed 07-Dec-1994 08:25:21 by Kirk Olynyk [kirko]
  1607. flAccel &= ~SO_ZERO_BEARINGS;
  1608. }
  1609. LONG y = FXTOL(ptfxRef.y + 8);
  1610. prcl->top = y - FXTOLCEILING(rcfx.yTop);
  1611. prcl->bottom = y - FXTOL(rcfx.yBottom);
  1612. return(FALSE);
  1613. }
  1614. // An inverting transform or an escapement could get us here.
  1615. EPOINTFL *ppteBase = &prfo->pteUnitBase();
  1616. EPOINTFL *ppteAscent = &prfo->pteUnitAscent();
  1617. if (ppteBase->y.bIsZero() && ppteAscent->x.bIsZero())
  1618. {
  1619. LONG x = FXTOL(ptfxRef.x + 8);
  1620. if (ppteBase->x.bIsNegative())
  1621. {
  1622. prcl->left = x - FXTOLCEILING(rcfx.xRight);
  1623. prcl->right = x - FXTOL(rcfx.xLeft);
  1624. }
  1625. else
  1626. {
  1627. prcl->left = x + FXTOL(rcfx.xLeft);
  1628. prcl->right = x + FXTOLCEILING(rcfx.xRight);
  1629. }
  1630. LONG y = FXTOL(ptfxRef.y + 8);
  1631. if (ppteAscent->y.bIsNegative())
  1632. {
  1633. prcl->top = y - FXTOLCEILING(rcfx.yTop);
  1634. prcl->bottom = y - FXTOL(rcfx.yBottom);
  1635. }
  1636. else
  1637. {
  1638. prcl->top = y + FXTOL(rcfx.yBottom);
  1639. prcl->bottom = y + FXTOLCEILING(rcfx.yTop);
  1640. }
  1641. // fudge an extra pixel, do not have a better solution for a space
  1642. // character at the beginning or at the end of string written horizontally
  1643. // It should not be necessary to do any of
  1644. //
  1645. // prcl->top--;
  1646. // prcl->bottom++;
  1647. //
  1648. // because space character is positioned at the baseline, so it should not
  1649. // stick out at the top or at the bottom
  1650. //
  1651. // Also it should not be neccessary to do
  1652. //
  1653. // prcl->left--;
  1654. //
  1655. // because we always ADD a cx = 1 for the space character to the
  1656. // origin of the space character
  1657. prcl->right++;
  1658. return(FALSE);
  1659. }
  1660. // A 90 degree rotation could get us here.
  1661. if (ppteBase->x.bIsZero() && ppteAscent->y.bIsZero())
  1662. {
  1663. LONG x = FXTOL(ptfxRef.x + 8);
  1664. if (ppteAscent->x.bIsNegative())
  1665. {
  1666. prcl->left = x - FXTOLCEILING(rcfx.yTop);
  1667. prcl->right = x - FXTOL(rcfx.yBottom);
  1668. }
  1669. else
  1670. {
  1671. prcl->left = x + FXTOL(rcfx.yBottom);
  1672. prcl->right = x + FXTOLCEILING(rcfx.yTop);
  1673. }
  1674. LONG y = FXTOL(ptfxRef.y + 8);
  1675. if (ppteBase->y.bIsNegative())
  1676. {
  1677. prcl->top = y - FXTOLCEILING(rcfx.xRight);
  1678. prcl->bottom = y - FXTOL(rcfx.xLeft);
  1679. }
  1680. else
  1681. {
  1682. prcl->top = y + FXTOL(rcfx.xLeft);
  1683. prcl->bottom = y + FXTOLCEILING(rcfx.xRight);
  1684. }
  1685. // fudge an extra pixel, do not have a better solution for a space
  1686. // character at the beginning or at the end of string written vertically.
  1687. // It should not be necessary to do any of
  1688. //
  1689. // prcl->right++;
  1690. // prcl->left--;
  1691. //
  1692. // because space character is positioned at the baseline, so it should not
  1693. // stick out left or right.
  1694. //
  1695. // Also it should not be neccessary to do
  1696. //
  1697. // prcl->top--;
  1698. //
  1699. // because we always ADD a cy = 1 for the space character to the
  1700. // origin of the space character
  1701. prcl->bottom++;
  1702. return(FALSE);
  1703. }
  1704. // The opaque area is a parallelogram. We multiply the orientation and
  1705. // ascent unit vectors by the computed bounding widths to get the
  1706. // displacements from the reference point.
  1707. POINTFIX ptfxLeft,ptfxRight,ptfxTop,ptfxBottom;
  1708. ptfxLeft.x = lCvt(ppteBase->x,rcfx.xLeft);
  1709. ptfxLeft.y = lCvt(ppteBase->y,rcfx.xLeft);
  1710. ptfxRight.x = lCvt(ppteBase->x,rcfx.xRight);
  1711. ptfxRight.y = lCvt(ppteBase->y,rcfx.xRight);
  1712. ptfxTop.x = lCvt(ppteAscent->x,rcfx.yTop);
  1713. ptfxTop.y = lCvt(ppteAscent->y,rcfx.yTop);
  1714. ptfxBottom.x = lCvt(ppteAscent->x,rcfx.yBottom);
  1715. ptfxBottom.y = lCvt(ppteAscent->y,rcfx.yBottom);
  1716. pptfx[0].x = ptfxRef.x + ptfxLeft.x + ptfxTop.x;
  1717. pptfx[1].x = ptfxRef.x + ptfxRight.x + ptfxTop.x;
  1718. pptfx[2].x = ptfxRef.x + ptfxRight.x + ptfxBottom.x;
  1719. pptfx[3].x = ptfxRef.x + ptfxLeft.x + ptfxBottom.x;
  1720. pptfx[0].y = ptfxRef.y + ptfxLeft.y + ptfxTop.y;
  1721. pptfx[1].y = ptfxRef.y + ptfxRight.y + ptfxTop.y;
  1722. pptfx[2].y = ptfxRef.y + ptfxRight.y + ptfxBottom.y;
  1723. pptfx[3].y = ptfxRef.y + ptfxLeft.y + ptfxBottom.y;
  1724. // Bound the parallelogram. (Using Black Magic.)
  1725. int ii;
  1726. ii = (pptfx[1].x > pptfx[0].x)
  1727. == (pptfx[1].x > pptfx[2].x);
  1728. prcl->left = pptfx[ii].x;
  1729. prcl->right = pptfx[ii+2].x;
  1730. ii = (pptfx[1].y > pptfx[0].y)
  1731. == (pptfx[1].y > pptfx[2].y);
  1732. prcl->top = pptfx[ii].y;
  1733. prcl->bottom = pptfx[ii+2].y;
  1734. ((ERECTL *) prcl)->vOrder();
  1735. prcl->left = FXTOL(prcl->left) - 2; // to be safe, 1 not enough [bodind]
  1736. prcl->top = FXTOL(prcl->top) - 2; // to be safe, 1 not enough [bodind]
  1737. prcl->right = FXTOLCEILING(prcl->right) + 2; // to be safe, 1 not enough [bodind]
  1738. prcl->bottom = FXTOLCEILING(prcl->bottom) + 2; // to be safe, 1 not enough [bodind]
  1739. #if 0
  1740. vCorrectBackGround();
  1741. #endif
  1742. return(TRUE);
  1743. }
  1744. /******************************Public*Routine******************************\
  1745. * ESTROBJ::bTextExtent (psize)
  1746. *
  1747. * Simply transforms the TextBox extents back to logical coordinates.
  1748. *
  1749. * History:
  1750. * Wed 31-Mar-1993 03:15:04 -by- Charles Whitmer [chuckwh]
  1751. * Removed the overhang hack since the RFONTOBJ version of this function is
  1752. * the Windows compatible one. Made it return an advance width based
  1753. * extent when (escapement==orientation). Otherwise, the bounding box is
  1754. * the only sensible definition.
  1755. *
  1756. * Thu 24-Sep-1992 18:36:14 -by- Charles Whitmer [chuckwh]
  1757. * Added the compatibility hack.
  1758. *
  1759. * Sat 14-Mar-1992 22:08:21 -by- Charles Whitmer [chuckwh]
  1760. * Wrote it.
  1761. \**************************************************************************/
  1762. BOOL ESTROBJ::bTextExtent(RFONTOBJ& rfo,LONG lEsc,PSIZE pSize)
  1763. {
  1764. if (flTO & TO_ESC_NOT_ORIENT)
  1765. {
  1766. pSize->cx = lCvt(prfo->efDtoWBase(),rcfx.xRight-rcfx.xLeft);
  1767. pSize->cy = lCvt(prfo->efDtoWAscent(),rcfx.yTop-rcfx.yBottom);
  1768. }
  1769. else
  1770. {
  1771. // Computes a more Windows compatible extent. This is only possible
  1772. // when (escapement==orientation) and no pdx vector was provided.
  1773. // The field fxExtent is only defined in these cases! We neglect adding
  1774. // in the overhang, since only GetTextExtentEx, a Win32 function, can
  1775. // get here.
  1776. pSize->cx = lCvt(prfo->efDtoWBase(),fxExtent);
  1777. pSize->cy = lCvt(prfo->efDtoWAscent(),prfo->lMaxHeight() << 4);
  1778. }
  1779. #ifdef FE_SB
  1780. if( gbDBCSCodePage && // Only in DBCS system locale
  1781. (rfo.iGraphicsMode() == GM_COMPATIBLE) && // We are in COMPATIBLE mode
  1782. !(rfo.flInfo() & FM_INFO_ARB_XFORMS) && // Driver can't do arbitrary rotations
  1783. !(rfo.flInfo() & FM_INFO_TECH_STROKE) && // Not a vector driver
  1784. (rfo.flInfo() & FM_INFO_90DEGREE_ROTATIONS) && // Driver does 90 deg. rotations
  1785. (lEsc == 900L || lEsc == 2700L) // Current font Escapement is 900 or 2700
  1786. )
  1787. {
  1788. LONG lSwap = pSize->cx;
  1789. pSize->cx = pSize->cy;
  1790. pSize->cy = lSwap;
  1791. }
  1792. #endif FE_SB
  1793. return(TRUE);
  1794. }
  1795. /******************************Public*Routine******************************\
  1796. * bTextToPath (po)
  1797. *
  1798. * Draws the outlines of all the glyphs in the string into the given path.
  1799. *
  1800. * History:
  1801. * Wed 17-Jun-1992 15:43:22 -by- Charles Whitmer [chuckwh]
  1802. * Wrote it.
  1803. \**************************************************************************/
  1804. BOOL ESTROBJ::bTextToPath(EPATHOBJ& po, XDCOBJ& dco, BOOL bNeedUnflattened)
  1805. {
  1806. BOOL ReturnValue;
  1807. if (bLinkedGlyphs())
  1808. {
  1809. ReturnValue = bLinkedTextToPath(po, dco, bNeedUnflattened);
  1810. }
  1811. else
  1812. {
  1813. ReturnValue = bTextToPathWorkhorse(po, bNeedUnflattened);
  1814. }
  1815. return(ReturnValue);
  1816. }
  1817. BOOL ESTROBJ::bTextToPathWorkhorse(EPATHOBJ& po, BOOL bNeedUnflattened)
  1818. {
  1819. ULONG ii, iFound;
  1820. ULONG cLeft, cGot;
  1821. POINTFIX ptfxOffset;
  1822. EGLYPHPOS *pg;
  1823. FIX dx;
  1824. BOOL bMore;
  1825. cLeft = 0;
  1826. vEnumStart();
  1827. do
  1828. {
  1829. bMore = STROBJ_bEnum(this, &iFound, (GLYPHPOS**)&pg);
  1830. if (iFound == 0 || pg == 0)
  1831. {
  1832. break;
  1833. }
  1834. if (ulCharInc)
  1835. {
  1836. ASSERTGDI(flAccel & SO_HORIZONTAL, "bTextToPath,text not horizontal\n");
  1837. ptfxOffset.x = pg->ptl.x;
  1838. ptfxOffset.y = pg->ptl.y;
  1839. if (!(flTO & TO_HIGHRESTEXT))
  1840. {
  1841. ptfxOffset.x <<=4;
  1842. ptfxOffset.y <<=4;
  1843. }
  1844. dx = (FIX)(ulCharInc << 4);
  1845. ptfxOffset.x -= dx;
  1846. }
  1847. else
  1848. {
  1849. dx = 0;
  1850. }
  1851. for (cGot = cLeft = iFound; cLeft; cLeft -= cGot)
  1852. {
  1853. //
  1854. // If the paths in the cache have been flattened we will need to
  1855. // call directly to the driver to get unflatttened paths [gerritv].
  1856. //
  1857. if ( bNeedUnflattened )
  1858. {
  1859. if (!prfo->bInsertPathLookaside(pg,FALSE))
  1860. {
  1861. break;
  1862. }
  1863. cGot = 1;
  1864. }
  1865. else if (!(flTO & TO_ALL_PTRS_VALID))
  1866. {
  1867. if ((cGot = prfo->cGetGlyphData(cLeft,pg)) == 0)
  1868. {
  1869. break;
  1870. }
  1871. }
  1872. for (ii = 0; ii < cGot; ii++, pg++)
  1873. {
  1874. if (dx)
  1875. {
  1876. ptfxOffset.x += dx;
  1877. }
  1878. else
  1879. {
  1880. ptfxOffset.x = pg->ptl.x;
  1881. ptfxOffset.y = pg->ptl.y;
  1882. if (!(flTO & TO_HIGHRESTEXT))
  1883. {
  1884. ptfxOffset.x <<=4;
  1885. ptfxOffset.y <<=4;
  1886. }
  1887. }
  1888. if (!po.bAppend((EPATHOBJ *) pg->pgdf->ppo, &ptfxOffset))
  1889. {
  1890. if (bNeedUnflattened)
  1891. pg->pgdf = NULL;
  1892. break;
  1893. }
  1894. if (bNeedUnflattened)
  1895. pg->pgdf = NULL;
  1896. }
  1897. if (ii < cGot)
  1898. {
  1899. break;
  1900. }
  1901. }
  1902. if (cLeft)
  1903. {
  1904. break;
  1905. }
  1906. } while (bMore);
  1907. if (bNeedUnflattened)
  1908. {
  1909. flTO = (flTO & ~TO_ALL_PTRS_VALID);
  1910. }
  1911. return(cLeft == 0);
  1912. }
  1913. /******************************Public*Routine******************************\
  1914. *
  1915. * Routine Name:
  1916. *
  1917. * ESTROBJ::bLinkedTextToPath
  1918. *
  1919. * Routine Description:
  1920. *
  1921. * Renders a text in the form of a path for the case where font linking
  1922. * is in place.
  1923. *
  1924. * Arguments:
  1925. *
  1926. * po - a referece to an EPATHOBJ. This will receive the text path.
  1927. *
  1928. * bNeedUnflattened - a variable that indicates that whether the path
  1929. * should be unflattened. If it needs to be unflattened we must
  1930. * go back to the font driver to get the glyph path in its original
  1931. * form before being flattend.
  1932. *
  1933. * Called by:
  1934. *
  1935. * ESTROBJ::bTextToPath
  1936. *
  1937. * Return Value:
  1938. *
  1939. \**************************************************************************/
  1940. BOOL ESTROBJ::bLinkedTextToPath(EPATHOBJ& po, XDCOBJ& dco, BOOL bNeedUnflattened)
  1941. {
  1942. RFONTOBJ *prfoSave;
  1943. WCHAR *pwszSave, *pwcTmp, *pwcSource;
  1944. LONG *plPart, *plPartLast, lFontLast, lFont, lInflatedMax = 0;
  1945. ULONG count;
  1946. prfoSave = prfo;
  1947. pgp = 0; // forces enumeration
  1948. flAccel = 0;
  1949. ulCharInc = 0;
  1950. pwszSave = pwszOrg;
  1951. plPartLast = plPartition + cGlyphs; // useful
  1952. lFontLast = EUDCTYPE_FACENAME + (LONG) prfo->uiNumFaceNameLinks();
  1953. for (lFont = EUDCTYPE_BASEFONT; lFont < lFontLast ; lFont++)
  1954. {
  1955. RFONTTMPOBJ rfoLink;
  1956. RFONTOBJ *prfoLink;
  1957. // (re)initialize prfo, because it could be pointing to an old
  1958. // or invalid rfoLink from a previous iteration.
  1959. prfo = prfoSave;
  1960. if (lFont == EUDCTYPE_BASEFONT)
  1961. {
  1962. prfoLink = prfo;
  1963. }
  1964. else
  1965. {
  1966. RFONT *prfnt;
  1967. switch (lFont)
  1968. {
  1969. case EUDCTYPE_SYSTEM_TT_FONT:
  1970. if(cTTSysGlyphs == 0)
  1971. {
  1972. continue;
  1973. }
  1974. prfnt = prfo->prfntSystemTT();
  1975. break;
  1976. case EUDCTYPE_SYSTEM_WIDE:
  1977. if(cSysGlyphs == 0)
  1978. {
  1979. continue;
  1980. }
  1981. prfnt = prfo->prfntSysEUDC();
  1982. break;
  1983. case EUDCTYPE_DEFAULT:
  1984. if(cDefGlyphs == 0)
  1985. {
  1986. continue;
  1987. }
  1988. prfnt = prfo->prfntDefEUDC();
  1989. break;
  1990. default:
  1991. if(cFaceNameGlyphsGet(lFont - EUDCTYPE_FACENAME) == 0)
  1992. {
  1993. continue;
  1994. }
  1995. prfnt = prfo->prfntFaceName(lFont - EUDCTYPE_FACENAME);
  1996. break;
  1997. }
  1998. if (prfnt == 0)
  1999. {
  2000. RIP("prfnt == 0\n");
  2001. return(FALSE);
  2002. }
  2003. rfoLink.vInit(prfnt);
  2004. prfoLink = (RFONTOBJ*) &rfoLink;
  2005. }
  2006. plPart = plPartition;
  2007. pwcTmp = pwcPartition;
  2008. pwcSource = pwszSave;
  2009. count = 0;
  2010. for ( ; plPart < plPartLast; plPart++, pwcSource++)
  2011. {
  2012. if (*plPart == lFont)
  2013. {
  2014. *pwcTmp++ = *pwcSource;
  2015. count++;
  2016. }
  2017. }
  2018. if (count)
  2019. {
  2020. cGlyphs = count;
  2021. pwszOrg = pwcPartition;
  2022. prfo = prfoLink;
  2023. vFontSet(lFont);
  2024. if (lFont != EUDCTYPE_BASEFONT)
  2025. {
  2026. POINTL ptlAdjustBaseLine;
  2027. if (bAdjusBaseLine(*prfo, rfoLink, &ptlAdjustBaseLine))
  2028. {
  2029. ptlBaseLineAdjustSet(ptlAdjustBaseLine);
  2030. }
  2031. }
  2032. if (!bTextToPathWorkhorse(po))
  2033. {
  2034. pwszOrg = pwszSave;
  2035. prfo = prfoSave;
  2036. return(FALSE);
  2037. }
  2038. }
  2039. }
  2040. pwszOrg = pwszSave;
  2041. prfo = prfoSave;
  2042. return(TRUE);
  2043. }
  2044. /******************************Public*Routine******************************\
  2045. * bAddPgmToPath (po,x,y,dx1,dy1,dx2,dy2)
  2046. *
  2047. * Performs the often repeated adding of a parallelogram to a path.
  2048. *
  2049. * Tue 07-Apr-1992 00:17:57 -by- Charles Whitmer [chuckwh]
  2050. * Wrote it.
  2051. \**************************************************************************/
  2052. BOOL bAddPgmToPath(EPATHOBJ& po,FIX x,FIX y,FIX dx1,FIX dy1,FIX dx2,FIX dy2)
  2053. {
  2054. POINTFIX aptfx[4];
  2055. aptfx[0].x = x;
  2056. aptfx[0].y = y;
  2057. aptfx[1].x = x + dx1;
  2058. aptfx[1].y = y + dy1;
  2059. aptfx[2].x = x + dx1 + dx2;
  2060. aptfx[2].y = y + dy1 + dy2;
  2061. aptfx[3].x = x + dx2;
  2062. aptfx[3].y = y + dy2;
  2063. return(po.bAddPolygon(XFORMNULL,(POINTL *) aptfx,4));
  2064. }
  2065. /******************************Public*Routine******************************\
  2066. * bExtraRectsToPath (po)
  2067. *
  2068. * Draws all the underlines and strikeouts into a path, suitable for
  2069. * filling.
  2070. *
  2071. * History:
  2072. * Tue 07-Apr-1992 00:44:00 -by- Charles Whitmer [chuckwh]
  2073. * Wrote it.
  2074. \**************************************************************************/
  2075. BOOL ESTROBJ::bExtraRectsToPath(EPATHOBJ& po, BOOL bNeedUnflattend)
  2076. {
  2077. FIX x;
  2078. FIX y;
  2079. // Get local copies of the offsets and thicknesses.
  2080. POINTFIX ptfxUL;
  2081. POINTFIX ptfxULThick;
  2082. ptfxUL.x = LTOFX(prfo->ptlUnderline1().x);
  2083. ptfxUL.y = LTOFX(prfo->ptlUnderline1().y);
  2084. ptfxULThick.x = LTOFX(prfo->ptlULThickness().x);
  2085. ptfxULThick.y = LTOFX(prfo->ptlULThickness().y);
  2086. POINTFIX ptfxSO;
  2087. POINTFIX ptfxSOThick;
  2088. ptfxSO.x = LTOFX(prfo->ptlStrikeOut().x);
  2089. ptfxSO.y = LTOFX(prfo->ptlStrikeOut().y);
  2090. ptfxSOThick.x = LTOFX(prfo->ptlSOThickness().x);
  2091. ptfxSOThick.y = LTOFX(prfo->ptlSOThickness().y);
  2092. // Underlines and strikeouts are continuous and parallel the escapement
  2093. // vector, if escapement equals orientation.
  2094. if (!(flTO & TO_ESC_NOT_ORIENT))
  2095. {
  2096. // Round off the starting point.
  2097. x = (ptfxRef.x + 8) & -16;
  2098. y = (ptfxRef.y + 8) & -16;
  2099. if (flTO & TSIM_UNDERLINE1)
  2100. {
  2101. if (!bAddPgmToPath
  2102. (
  2103. po,
  2104. x + ptfxUL.x,
  2105. y + ptfxUL.y,
  2106. ptfxEscapement.x,
  2107. ptfxEscapement.y,
  2108. ptfxULThick.x,
  2109. ptfxULThick.y
  2110. )
  2111. )
  2112. return(FALSE);
  2113. }
  2114. if (flTO & TSIM_STRIKEOUT)
  2115. {
  2116. if (!bAddPgmToPath
  2117. (
  2118. po,
  2119. x + ptfxSO.x,
  2120. y + ptfxSO.y,
  2121. ptfxEscapement.x,
  2122. ptfxEscapement.y,
  2123. ptfxSOThick.x,
  2124. ptfxSOThick.y
  2125. )
  2126. )
  2127. return(FALSE);
  2128. }
  2129. return(TRUE);
  2130. }
  2131. // Otherwise underlines and strikeouts apply to each character.
  2132. UINT ii;
  2133. ULONG cLeft;
  2134. ULONG cGot;
  2135. EGLYPHPOS *pg = pgpos;
  2136. WCHAR *pwsz = pwszOrg;
  2137. for (cGot=cLeft=cGlyphs; cLeft; cLeft-=cGot)
  2138. {
  2139. if (bNeedUnflattend)
  2140. {
  2141. if ((cGot = prfo->cGetGlyphDataLookaside(cLeft, pg)) == 0)
  2142. return (FALSE);
  2143. }
  2144. else if (!(flTO & TO_ALL_PTRS_VALID))
  2145. {
  2146. if ((cGot = prfo->cGetGlyphData(cLeft,pg)) == 0)
  2147. return(FALSE);
  2148. }
  2149. pwsz += cGot;
  2150. EPOINTFL *ppteBase = &prfo->pteUnitBase();
  2151. POINTFIX ptfxA;
  2152. POINTFIX ptfxB;
  2153. for (ii=0; ii<cGot; ii++,pg++)
  2154. {
  2155. x = pg->ptl.x;
  2156. y = pg->ptl.y;
  2157. // If pg->ptl contains LONG's, we must convert them to FIX's.
  2158. if (!(flTO & TO_HIGHRESTEXT))
  2159. {
  2160. x <<=4;
  2161. y <<=4;
  2162. }
  2163. ptfxA.x = lCvt(ppteBase->x,pg->pgd()->fxA);
  2164. ptfxA.y = lCvt(ppteBase->y,pg->pgd()->fxA);
  2165. ptfxB.x = lCvt(ppteBase->x,(pg->pgd()->fxAB - pg->pgd()->fxA));
  2166. ptfxB.y = lCvt(ppteBase->y,(pg->pgd()->fxAB - pg->pgd()->fxA));
  2167. if (flTO & TSIM_UNDERLINE1)
  2168. {
  2169. if (!bAddPgmToPath
  2170. (
  2171. po,
  2172. x + ptfxUL.x + ptfxA.x,
  2173. y + ptfxUL.y + ptfxA.y,
  2174. ptfxB.x,
  2175. ptfxB.y,
  2176. ptfxULThick.x,
  2177. ptfxULThick.y
  2178. )
  2179. )
  2180. return(FALSE);
  2181. }
  2182. if (flTO & TSIM_STRIKEOUT)
  2183. {
  2184. if (!bAddPgmToPath
  2185. (
  2186. po,
  2187. x + ptfxSO.x + ptfxA.x,
  2188. y + ptfxSO.y + ptfxA.y,
  2189. ptfxB.x,
  2190. ptfxB.y,
  2191. ptfxSOThick.x,
  2192. ptfxSOThick.y
  2193. )
  2194. )
  2195. return(FALSE);
  2196. }
  2197. }
  2198. }
  2199. return(TRUE);
  2200. }
  2201. /******************************Public*Routine******************************\
  2202. * VOID STROBJ_vEnumStart (pstro)
  2203. *
  2204. * Initialize the string enumerator.
  2205. *
  2206. * History
  2207. * Tue 17-Mar-1992 10:33:09 -by- Charles Whitmer [chuckwh]
  2208. * Simplified it.
  2209. *
  2210. * Fri 25-Jan-1991 -by- Bodin Dresevic [BodinD]
  2211. * Wrote it.
  2212. \**************************************************************************/
  2213. extern "C" VOID STROBJ_vEnumStart(STROBJ *pso)
  2214. {
  2215. ((ESTROBJ *)pso)->vEnumStart();
  2216. }
  2217. /******************************Public*Routine******************************\
  2218. * BOOL STROBJ_bEnum
  2219. *
  2220. * The glyph enumerator.
  2221. *
  2222. * History:
  2223. * Tue 17-Mar-1992 10:35:05 -by- Charles Whitmer [chuckwh]
  2224. * Simplified it and gave it the quick exit. Also let drivers call here
  2225. * direct.
  2226. *
  2227. * 02-Oct-1991 -by- Bodin Dresevic [BodinD]
  2228. * Wrote it.
  2229. \**************************************************************************/
  2230. BOOL STROBJ_bEnumLinked(ESTROBJ *peso, ULONG *pc,PGLYPHPOS *ppgpos);
  2231. extern "C" BOOL STROBJ_bEnum(STROBJ *pso, ULONG *pc, PGLYPHPOS *ppgpos)
  2232. {
  2233. // Quick exit.
  2234. #ifdef FE_SB
  2235. if(((ESTROBJ*)pso)->flTO & (TO_PARTITION_INIT|TO_SYS_PARTITION))
  2236. {
  2237. return(STROBJ_bEnumLinked( (ESTROBJ*) pso, pc, ppgpos ));
  2238. }
  2239. #endif
  2240. if (((ESTROBJ*)pso)->flTO & TO_ALL_PTRS_VALID)
  2241. {
  2242. *pc = ((ESTROBJ*)pso)->cGlyphs;
  2243. *ppgpos = ((ESTROBJ*)pso)->pgpos;
  2244. return(FALSE);
  2245. }
  2246. // compute the number of wc's in the string for which the GLYPHPOS strucs
  2247. // have not yet been written to the driver's buffer
  2248. ULONG cgposYetToCopy = ((ESTROBJ*)pso)->cGlyphs - ((ESTROBJ*)pso)->cgposCopied;
  2249. if (cgposYetToCopy == 0)
  2250. {
  2251. *pc = 0;
  2252. return(FALSE);
  2253. }
  2254. GLYPHPOS *pgp = ((ESTROBJ*)pso)->pgpos + ((ESTROBJ*)pso)->cgposCopied;
  2255. ULONG cgposActual; // # of chars enumerated during this call to strobj
  2256. if ( ((ESTROBJ*)pso)->prfo == NULL) // check for journaling
  2257. {
  2258. WARNING("ESTROBJ::bEnum(), bitmap font, prfo == NULL\n");
  2259. *pc = 0;
  2260. return(FALSE);
  2261. }
  2262. cgposActual =((ESTROBJ*)pso)->prfo->cGetGlyphData(cgposYetToCopy,pgp);
  2263. if (cgposActual == 0)
  2264. {
  2265. *pc = 0;
  2266. return(FALSE);
  2267. }
  2268. // The first glyph in a batch should always have the position info.
  2269. if (((ESTROBJ*)pso)->cgposCopied && ((ESTROBJ*)pso)->ulCharInc)
  2270. {
  2271. if (((ESTROBJ*)pso)->flTO & TO_HIGHRESTEXT)
  2272. {
  2273. pgp->ptl.x = ((ESTROBJ*)pso)->pgpos->ptl.x +
  2274. ((((ESTROBJ*)pso)->cgposCopied * ((ESTROBJ*)pso)->ulCharInc) << 4);
  2275. }
  2276. else
  2277. {
  2278. pgp->ptl.x = ((ESTROBJ*)pso)->pgpos->ptl.x +
  2279. ((ESTROBJ*)pso)->cgposCopied * ((ESTROBJ*)pso)->ulCharInc;
  2280. }
  2281. pgp->ptl.y = ((ESTROBJ*)pso)->pgpos->ptl.y;
  2282. }
  2283. ((ESTROBJ*)pso)->cgposCopied += cgposActual; // update enumeration state
  2284. *pc = cgposActual;
  2285. *ppgpos = pgp;
  2286. return(((ESTROBJ*)pso)->cgposCopied < ((ESTROBJ*)pso)->cGlyphs); // TRUE => more to come.
  2287. }
  2288. /******************************Public*Routine******************************\
  2289. * vGenWidths
  2290. *
  2291. * Computes the advance widths for escapement not equal to orientation.
  2292. * The theory is pretty simple. We construct an 'egg' whose upper and
  2293. * lower outlines are half ellipses with sizes determined by the top and
  2294. * bottom of the ink box. The escapement vector always goes through the
  2295. * center of the character baseline. We call that point (halfway between
  2296. * the normal concatenation points of the glyph) the 'center'. We advance
  2297. * the current position from where the escapement vector first pierces the
  2298. * egg to the center, and then from the center to where the vector exits
  2299. * the egg. These are the D1 and D2 returned widths from this routine.
  2300. *
  2301. * Mon 07-Jun-1993 12:27:22 -by- Charles Whitmer [chuckwh]
  2302. * Wrote it long ago. My apologies for the undocumented math.
  2303. \**************************************************************************/
  2304. VOID vGenWidths
  2305. (
  2306. FIX *pfxD1, // First part of advance width. (Returned.)
  2307. FIX *pfxD2, // Second part of advance width. (Returned.)
  2308. EFLOAT& efRA, // Projection ratio of escapement onto Ascent.
  2309. EFLOAT& efRB, // Projection ratio of escapement onto Baseline.
  2310. FIX fxWidth, // Normal width.
  2311. FIX fxTop, // Top of ink box.
  2312. FIX fxBottom, // Bottom of ink box.
  2313. FIX fxMaxAscent
  2314. )
  2315. {
  2316. EFLOAT efA,efB,efOne;
  2317. FIX fxTemp;
  2318. // Worry about the width being zero. This can occur in a Unicode font.
  2319. // Never advance in this case, since the character is some kind of
  2320. // overpainting glyph.
  2321. if (fxWidth == 0)
  2322. {
  2323. *pfxD2 = 0;
  2324. *pfxD1 = 0;
  2325. return;
  2326. }
  2327. // For escapement along the baseline, we return the normal width, separated
  2328. // into two parts.
  2329. if (efRA.bIsZero())
  2330. {
  2331. *pfxD1 = fxWidth / 2;
  2332. *pfxD2 = fxWidth - *pfxD1;
  2333. return;
  2334. }
  2335. if (fxBottom == fxTop) // Probably a break character.
  2336. {
  2337. fxBottom = -(fxMaxAscent / 4);
  2338. fxTop = fxMaxAscent/2 + fxBottom;
  2339. }
  2340. if (fxBottom >= 0)
  2341. fxBottom = 0;
  2342. if (fxTop <= 0)
  2343. fxTop = 0;
  2344. if (efRA.bIsNegative())
  2345. {
  2346. fxTemp = fxBottom;
  2347. fxBottom = -fxTop;
  2348. fxTop = -fxTemp;
  2349. }
  2350. // Provide a little extra spacing in addition to the ink box.
  2351. fxTop += fxMaxAscent / 16;
  2352. if ( fxTop == 0 )
  2353. {
  2354. WARNING1("vGenWidths: fxTop == 0 .. setting to +1\n");
  2355. fxTop = 1;
  2356. }
  2357. fxBottom -= fxMaxAscent / 16;
  2358. if ( fxBottom == 0 )
  2359. {
  2360. WARNING1("vGenWidths: fxBottom == 0 .. setting to -1\n");
  2361. fxBottom = -1;
  2362. }
  2363. // For escapement in the ascent direction, we return a width that will
  2364. // traverse the ink box. Note that the general code below would give the
  2365. // same result, only take longer!
  2366. if (efRB.bIsZero())
  2367. {
  2368. *pfxD2 = fxTop;
  2369. *pfxD1 = -fxBottom;
  2370. return;
  2371. }
  2372. // Compute the displacements.
  2373. ASSERTGDI(fxWidth, "fxWidth == 0\n");
  2374. efB = fxWidth; // Converts to EFLOAT.
  2375. efB.vDivBy2();
  2376. efB.eqDiv(efRB,efB);
  2377. efB.eqMul(efB,efB);
  2378. efA = fxBottom;
  2379. efA.eqDiv(efRA,efA);
  2380. efA.eqMul(efA,efA);
  2381. efA.eqAdd(efA,efB);
  2382. efA.eqSqrt(efA);
  2383. efOne.vSetToOne();
  2384. efA.eqDiv(efOne,efA);
  2385. efA.bEfToL(*pfxD1);
  2386. efA = fxTop;
  2387. efA.eqDiv(efRA,efA);
  2388. efA.eqMul(efA,efA);
  2389. efA.eqAdd(efA,efB);
  2390. efA.eqSqrt(efA);
  2391. efA.eqDiv(efOne,efA);
  2392. efA.bEfToL(*pfxD2);
  2393. return;
  2394. }
  2395. /******************************Public*Routine******************************\
  2396. *
  2397. * VOID ESTROBJ::vCharPos_H4, pdxdy case for zero esc and orientation
  2398. *
  2399. * History:
  2400. * 18-Sep-1996 -by- Bodin Dresevic [BodinD]
  2401. * Wrote it.
  2402. \**************************************************************************/
  2403. VOID ESTROBJ::vCharPos_H4
  2404. (
  2405. XDCOBJ& dco,
  2406. RFONTOBJ& rfo,
  2407. FIX xRef,
  2408. FIX yRef,
  2409. LONG *pdxdy,
  2410. EFLOAT efXScale,
  2411. EFLOAT efYScale
  2412. )
  2413. {
  2414. // Make some local pointers.
  2415. EGLYPHPOS *pg = pgpos;
  2416. GLYPHDATA *pgd;
  2417. WCHAR *pwsz = pwszOrg;
  2418. POINTL *pDxDy = (POINTL *)pdxdy;
  2419. // The transform is pretty simple, we're going to handle it ourselves.
  2420. // Accelerate on a really simple transforms.
  2421. BOOL bUnityX = efXScale.bIs16();
  2422. BOOL bUnityY = efYScale.bIs16();
  2423. BOOL bAccel;
  2424. if (!rfo.bGetGlyphMetricsPlus(cGlyphs, pg, pwsz, &bAccel,&dco,this))
  2425. return;
  2426. if (bAccel)
  2427. {
  2428. flTO |= TO_ALL_PTRS_VALID;
  2429. pgp = pgpos;
  2430. }
  2431. // Set up for character loop.
  2432. FIX xA,xB;
  2433. FIX yT,yB;
  2434. LONG xSum, ySum;
  2435. FIX xLeft,xRight, yTop, yBottom; // Accumulate bounds here.
  2436. UINT ii;
  2437. FIX fxAscent, fxDescent;
  2438. if (dco.pdc->bYisUp())
  2439. {
  2440. fxAscent = -rfo.fxMaxDescent();
  2441. fxDescent = -rfo.fxMaxAscent();
  2442. }
  2443. else
  2444. {
  2445. fxAscent = rfo.fxMaxAscent();
  2446. fxDescent = rfo.fxMaxDescent();
  2447. }
  2448. xLeft = 0; // Start with an empty TextBox.
  2449. xRight = 0;
  2450. yTop = 0;
  2451. yBottom = 0;
  2452. // To avoid roundoff errors, we accumulate the DX widths in logical
  2453. // coordinates and transform the sums.
  2454. xSum = 0; // Distance along the escapement in logical coords.
  2455. ySum = 0; // Distance along the ascender in logical coords.
  2456. xA = 0; // Distance along the escapement (x) in device coords.
  2457. yT = 0; // Distance along the ascender (y) in device coords
  2458. // Set the first character position:
  2459. yRef += 8; // Add in rounding offset for later
  2460. xRef += 8; // converting x and y to LONG coordinates
  2461. pg->ptl.x = FXTOL(xRef);
  2462. pg->ptl.y = FXTOL(yRef);
  2463. ii = cGlyphs;
  2464. while (TRUE)
  2465. {
  2466. // Update the bounds.
  2467. pgd = pg->pgd();
  2468. xB = xA + pgd->fxA;
  2469. if (xB < xLeft)
  2470. xLeft = xB;
  2471. xB = xA + pgd->fxAB;
  2472. if (xB > xRight)
  2473. xRight = xB;
  2474. // make top and bottom independent of glyphs, ie replace glyph in the
  2475. // string by another one, want to get the same top and bottom, possibly
  2476. // different left and right.
  2477. // (this is similar to how all other H? cases work)
  2478. yB = yT + fxAscent;
  2479. if (yB > yTop)
  2480. yTop = yB;
  2481. yB = yT + fxDescent;
  2482. if (yB < yBottom)
  2483. yBottom = yB;
  2484. // Add the next offset.
  2485. xSum += pDxDy->x;
  2486. ySum += pDxDy->y;
  2487. pDxDy++;
  2488. // Scale the new offset.
  2489. xA = bUnityX ? LTOFX(xSum) : lCvt(efXScale,xSum);
  2490. yT = bUnityY ? LTOFX(ySum) : lCvt(efYScale,ySum);
  2491. if (--ii == 0)
  2492. break;
  2493. // Save the next position.
  2494. pg++;
  2495. pg->ptl.x = FXTOL(xA + xRef);
  2496. pg->ptl.y = FXTOL(-yT + yRef); // y goes down, not opposite from ascender
  2497. }
  2498. // Expand the text box out to the concatenation point. This allows us to
  2499. // continue on with another opaqued string with no visible gap in the
  2500. // opaquing.
  2501. if (xA > xRight)
  2502. xRight = xA;
  2503. ptfxUpdate.x = xA;
  2504. ptfxUpdate.y = -yT;
  2505. rcfx.xLeft = xLeft;
  2506. rcfx.xRight = xRight;
  2507. if (dco.pdc->bYisUp())
  2508. {
  2509. rcfx.yTop = -yBottom;
  2510. rcfx.yBottom = -yTop;
  2511. }
  2512. else
  2513. {
  2514. rcfx.yTop = yTop;
  2515. rcfx.yBottom = yBottom;
  2516. }
  2517. flTO |= TO_VALID;
  2518. }
  2519. /******************************Public*Routine******************************\
  2520. *
  2521. * VOID ESTROBJ::vCharPos_G4
  2522. *
  2523. * handles pdy case with esc != orientation
  2524. *
  2525. * History:
  2526. * 17-Sep-1996 -by- Bodin Dresevic [BodinD]
  2527. * Wrote it.
  2528. \**************************************************************************/
  2529. VOID ESTROBJ::vCharPos_G4
  2530. (
  2531. XDCOBJ& dco,
  2532. RFONTOBJ& rfo,
  2533. FIX xRef,
  2534. FIX yRef,
  2535. LONG *pdxdy
  2536. )
  2537. {
  2538. // In this case, we keep track of how far we have traveled along the
  2539. // escapement vector in device coordinates. We need scales to project
  2540. // this distance onto the base and ascent, as well as a unit escapement
  2541. // vector to find the position.
  2542. POINTFL pteEsc = rfo.pteUnitEsc(); // Unit escapement vector.
  2543. POINTFL pteAsc = rfo.pteUnitAscent(); // Unit ascender vector.
  2544. EFLOAT efScaleX = rfo.efEscToBase(); // Project escapement to baseline.
  2545. EFLOAT efScaleY = rfo.efEscToAscent(); // Project escapement to ascent.
  2546. // Compute logical to device transforms.
  2547. EFLOAT efWtoDEsc = rfo.efWtoDEsc(); // Forward transform for pdx.
  2548. EFLOAT efWtoDAsc = rfo.efWtoDAscent(); // Forward transform for pdy
  2549. BOOL bUnityEsc = efWtoDEsc.bIs16();
  2550. BOOL bUnityAsc = efWtoDAsc.bIs16();
  2551. // Compute extra spacing for the non-pdx case.
  2552. FIX fxD1,fxD2; // Pre- and Post-center character widths.
  2553. FIX fxAscent = rfo.fxMaxAscent(); // Cache locally.
  2554. FIX fxDescent = rfo.fxMaxDescent(); // Cache locally.
  2555. ASSERTGDI(pdxdy, "G4 text out case: pdxdy is null\n");
  2556. ASSERTGDI(cGlyphs > 0, "G4, cGlyphs == 0\n");
  2557. // Make some local pointers.
  2558. EGLYPHPOS *pg = pgpos;
  2559. GLYPHDATA *pgd;
  2560. WCHAR *pwsz = pwszOrg;
  2561. // Set the first character position.
  2562. pg->ptl.x = xRef;
  2563. pg->ptl.y = yRef;
  2564. // Set up for character loop.
  2565. LONG xSum; // Keep pdx sum here.
  2566. LONG ySum; // Keep pdy sum here.
  2567. FIX xA,xB; // Baseline coordinates.
  2568. FIX yA,yB; // Ascent coordinates.
  2569. FIX sA; // Position on the escapement vector.
  2570. FIX sT; // Position on the ascender vector.
  2571. RECTFX rcfxBounds; // Accumulate bounds here.
  2572. UINT ii;
  2573. POINTL *pDxDy = (POINTL *)pdxdy;
  2574. rcfxBounds.xLeft = LONG_MAX; // Start with an empty TextBox.
  2575. rcfxBounds.xRight = LONG_MIN;
  2576. rcfxBounds.yTop = LONG_MIN;
  2577. rcfxBounds.yBottom = LONG_MAX;
  2578. // We keep the current concatenation point in sA. Note that this is NOT
  2579. // where the character origin will be placed.
  2580. sA = sT = 0;
  2581. xSum = ySum = 0;
  2582. BOOL bAccel;
  2583. if (!rfo.bGetGlyphMetricsPlus(cGlyphs, pg, pwsz, &bAccel, &dco, this))
  2584. return;
  2585. if (bAccel)
  2586. {
  2587. flTO |= TO_ALL_PTRS_VALID;
  2588. pgp = pgpos;
  2589. }
  2590. for (ii=0; ii<cGlyphs; ii++, pg++, pDxDy++)
  2591. {
  2592. pgd = pg->pgd();
  2593. // Using the GenWidths function, determine where the
  2594. // character center should be placed.
  2595. vGenWidths
  2596. (
  2597. &fxD1, // Pre-center spacing
  2598. &fxD2, // Post-center spacing
  2599. efScaleY, // Ascent projection
  2600. efScaleX, // Baseline projection
  2601. pgd->fxD, // Character width
  2602. pgd->fxInkTop, // Ink box top
  2603. pgd->fxInkBottom, // Ink box bottom
  2604. fxAscent // Maximum Ascent
  2605. );
  2606. sA += fxD1; // Advance to the character center.
  2607. // Update ascent bounds.
  2608. yA = lCvt(efScaleY,sA) + sT; // Project onto ascent.
  2609. yB = yA + fxDescent;
  2610. if (yB < rcfxBounds.yBottom)
  2611. rcfxBounds.yBottom = yB;
  2612. yB = yA + fxAscent;
  2613. if (yB > rcfxBounds.yTop)
  2614. rcfxBounds.yTop = yB;
  2615. ASSERTGDI(!rfo.bSmallMetrics(),"ESTROBJ__vCharPos_G3: Small Metrics in cache\n");
  2616. // Project the center position onto the baseline and
  2617. // move back to the character origin.
  2618. xA = lCvt(efScaleX,sA) - pgd->fxD / 2;
  2619. // Update the width bounds. Fudge a quarter pel on each side for
  2620. // roundoff.
  2621. xB = xA + pgd->fxA - 4;
  2622. if (xB < rcfxBounds.xLeft)
  2623. rcfxBounds.xLeft = xB;
  2624. xB = xA + pgd->fxAB + 4;
  2625. if (xB > rcfxBounds.xRight)
  2626. rcfxBounds.xRight = xB;
  2627. // Save the adjusted character origin.
  2628. pg->ptl.x
  2629. = xRef + lCvt(pteEsc.x,sA) + lCvt(pteAsc.x,sT) - pgd->ptqD.x.u.HighPart / 2;
  2630. pg->ptl.y
  2631. = yRef + lCvt(pteEsc.y,sA) + lCvt(pteAsc.y,sT) - pgd->ptqD.y.u.HighPart / 2;
  2632. // Advance to the next concatenation point.
  2633. xSum += pDxDy->x;
  2634. ySum += pDxDy->y;
  2635. sA = bUnityEsc ? LTOFX(xSum) : lCvt(efWtoDEsc,xSum);
  2636. sT = bUnityAsc ? LTOFX(ySum) : lCvt(efWtoDAsc,ySum);
  2637. }
  2638. // ptfxUpdate, continue where the last glyph is written:
  2639. ptfxUpdate.x = lCvt(pteEsc.x,sA) + lCvt(pteAsc.x,sT);
  2640. ptfxUpdate.y = lCvt(pteEsc.y,sA) + lCvt(pteAsc.y,sT);
  2641. rcfx = rcfxBounds;
  2642. flTO |= TO_VALID;
  2643. }
  2644. /******************************Public*Routine******************************\
  2645. * STROBJ_bGetAdvanceWidthsLinked(
  2646. *
  2647. * returns the widths for the batch of glyphs from the current font
  2648. *
  2649. * Warnings: assumes that the glyph has been partitioned properly
  2650. *
  2651. * History:
  2652. * 27-Jan-1998 -by- Bodin Dresevic [BodinD]
  2653. * Wrote it.
  2654. \**************************************************************************/
  2655. BOOL STROBJ_bGetAdvanceWidthsLinked(
  2656. ESTROBJ * peso,
  2657. ULONG iFirst,
  2658. ULONG cBatch,
  2659. POINTQF *pptqD
  2660. )
  2661. {
  2662. // Quick exit.
  2663. BOOL bRet = FALSE;
  2664. ULONG iG, iLast;
  2665. iG = 0;
  2666. iLast = iFirst + cBatch;
  2667. if (iLast <= peso->cGlyphs)
  2668. {
  2669. bRet = TRUE;
  2670. for(iG = 0, peso->plNext = peso->plPartition, peso->pgpNext = peso->pgpos;
  2671. iG < iLast;
  2672. (peso->pgpNext)++, (peso->plNext)++)
  2673. {
  2674. if (*(peso->plNext) == peso->lCurrentFont)
  2675. {
  2676. if (iG >= iFirst)
  2677. {
  2678. EGLYPHPOS *pg = (EGLYPHPOS *)peso->pgpNext;
  2679. if (peso->prfo->bSmallMetrics())
  2680. {
  2681. pptqD->x.u.HighPart = pg->pgd()->fxD;
  2682. pptqD->x.u.LowPart = 0;
  2683. pptqD->y.u.HighPart = 0;
  2684. pptqD->y.u.LowPart = 0;
  2685. }
  2686. else
  2687. {
  2688. *pptqD = pg->pgd()->ptqD;
  2689. }
  2690. // get to the next adv. width
  2691. pptqD++;
  2692. }
  2693. // increment iG, count of glyphs from this font
  2694. iG++;
  2695. }
  2696. }
  2697. }
  2698. return bRet;
  2699. }
  2700. /******************************Public*Routine******************************\
  2701. *
  2702. *
  2703. * Effects: accelerator for the printer drivers, they need to know how to
  2704. * update current position, so they need advance vectors of glyphs
  2705. * in this string.
  2706. *
  2707. * Warnings: I think this will not work for linked fonts
  2708. * On the other hand printer driver never get called with STROBJ
  2709. * for linked string, so this should be ok.
  2710. *
  2711. * History:
  2712. * 09-Jan-1998 -by- Bodin Dresevic [BodinD]
  2713. * Wrote it.
  2714. \**************************************************************************/
  2715. extern "C" BOOL APIENTRY STROBJ_bGetAdvanceWidths(
  2716. STROBJ *pso, ULONG iFirst, ULONG cBatch,POINTQF *pptqD
  2717. )
  2718. {
  2719. // We know that all the widths are in the cache, computed already
  2720. // just need to copy them down
  2721. if(((ESTROBJ*)pso)->flTO & (TO_PARTITION_INIT|TO_SYS_PARTITION))
  2722. {
  2723. return STROBJ_bGetAdvanceWidthsLinked((ESTROBJ*)pso,iFirst,cBatch,pptqD);
  2724. }
  2725. BOOL bRet = FALSE;
  2726. if ((iFirst + cBatch) <= ((ESTROBJ*)pso)->cGlyphs)
  2727. {
  2728. EGLYPHPOS *pg = &((ESTROBJ*)pso)->pgpos[iFirst];
  2729. EGLYPHPOS *pgEnd = pg + cBatch;
  2730. bRet = TRUE;
  2731. if (((ESTROBJ*)pso)->prfo->bSmallMetrics())
  2732. {
  2733. for ( ; pg < pgEnd; pg++, pptqD++)
  2734. {
  2735. pptqD->x.u.HighPart = pg->pgd()->fxD;
  2736. pptqD->x.u.LowPart = 0;
  2737. pptqD->y.u.HighPart = 0;
  2738. pptqD->y.u.LowPart = 0;
  2739. }
  2740. }
  2741. else
  2742. {
  2743. for ( ; pg < pgEnd; pg++)
  2744. {
  2745. *pptqD++ = pg->pgd()->ptqD;
  2746. }
  2747. }
  2748. }
  2749. return bRet;
  2750. }
  2751. /******************************Public*Routine******************************\
  2752. *
  2753. * BOOL STROBJ_bEnumPositionsOnlyLinked
  2754. *
  2755. * Enumerates positions only in paralel with STROBJ_bEnumLinked in misceudc.cxx
  2756. *
  2757. * History:
  2758. * 20-Jan-1998 -by- Bodin Dresevic [BodinD]
  2759. * Wrote it.
  2760. \**************************************************************************/
  2761. BOOL STROBJ_bEnumPositionsOnlyLinked(ESTROBJ *peso, ULONG *pc,PGLYPHPOS *ppgpos)
  2762. {
  2763. // Quick exit.
  2764. if( peso->cgposPositionsEnumerated == 0 )
  2765. {
  2766. for( peso->plNext = peso->plPartition, peso->pgpNext = peso->pgpos;
  2767. *(peso->plNext) != peso->lCurrentFont;
  2768. (peso->pgpNext)++, (peso->plNext)++ );
  2769. {
  2770. }
  2771. }
  2772. else
  2773. {
  2774. if (peso->cgposPositionsEnumerated == peso->cGlyphs)
  2775. {
  2776. // no more glyphs so just return
  2777. *pc = 0;
  2778. return(FALSE);
  2779. }
  2780. else
  2781. {
  2782. // find next glyph
  2783. for( (peso->plNext)++, (peso->pgpNext)++;
  2784. *(peso->plNext) != (peso->lCurrentFont);
  2785. (peso->pgpNext)++, (peso->plNext)++ );
  2786. {
  2787. }
  2788. }
  2789. }
  2790. peso->cgposPositionsEnumerated += 1; // update enumeration state
  2791. *pc = 1;
  2792. *ppgpos = peso->pgpNext;
  2793. return(peso->cgposPositionsEnumerated < peso->cGlyphs); // TRUE => more to come.
  2794. }
  2795. BOOL APIENTRY STROBJ_bEnumPositionsOnly(
  2796. STROBJ *pso,
  2797. ULONG *pc,
  2798. PGLYPHPOS *ppgpos
  2799. )
  2800. {
  2801. // Quick exit.
  2802. if(((ESTROBJ*)pso)->flTO & (TO_PARTITION_INIT|TO_SYS_PARTITION))
  2803. {
  2804. return STROBJ_bEnumPositionsOnlyLinked((ESTROBJ*)pso, pc, ppgpos);
  2805. }
  2806. // if not linked all positions are guaranteed to be in the cache:
  2807. *pc = ((ESTROBJ*)pso)->cGlyphs;
  2808. *ppgpos = ((ESTROBJ*)pso)->pgpos;
  2809. return(FALSE); // no more
  2810. }