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.

2245 lines
63 KiB

  1. #include "precomp.hpp"
  2. #define PATH_HEIGHT_THRESHOLD 800
  3. #define PAGE_SIZE (8*1024)
  4. #define ROUND_TO_PAGE(x) (((x)+PAGE_SIZE-1)&~(PAGE_SIZE-1))
  5. #define CJMININCREMENT 0x2000
  6. #define CJMAX (16 * 0x2000)
  7. #define FONT_GRAYSCALE_OR_CT_OR_MONOUNHINTED (FO_GRAYSCALE | FO_SUBPIXEL_4 | FO_CLEARTYPE_GRID | FO_CLEARTYPE | FO_MONO_UNHINTED | FO_COMPATIBLE_WIDTH)
  8. // we want number divisible by 8 containing about 75 glyphs,
  9. // almost an upper limit on number of glyphs in the metrics cache
  10. // when running winstone memory constrained scenario
  11. #define GD_INC (76 * sizeof(GpGlyphData) * 2)
  12. // GD_INC amounts to 1520 == 000005f0H, far less than a page.
  13. // according to Kirk's statistics, very few realizations cache more
  14. // than 60 glyphs, so we shall start with a block which contains about
  15. // 60 glyphs
  16. #define C_GLYPHS_IN_BLOCK 64
  17. ULONG ulClearTypeFilter(GLYPHBITS *GlyphBits, ULONG cjBuf, CacheFaceRealization *prface);
  18. BOOL SetFontXform(
  19. const GpGraphics *pdc,
  20. const GpFontFace *pfe,
  21. REAL height,
  22. Unit unit,
  23. FD_XFORM *pfdx,
  24. BOOL needPaths,
  25. const GpMatrix *pmx
  26. )
  27. {
  28. REAL EmHt, scale;
  29. REAL DpiX, DpiY;
  30. if (needPaths && unit != UnitWorld)
  31. return FALSE;
  32. EmHt = pfe->GetDesignEmHeight();
  33. if (!needPaths)
  34. {
  35. DpiX = pdc->GetDpiX();
  36. DpiY = pdc->GetDpiY();
  37. // UnitDisplay is device dependent and cannot be used as a font unit
  38. ASSERT(unit != UnitDisplay);
  39. if (unit != UnitWorld && unit != UnitPixel)
  40. {
  41. height *= DpiY;
  42. switch (unit)
  43. {
  44. case UnitPoint:
  45. height /= 72.0;
  46. break;
  47. case UnitDocument:
  48. height /= 300.0;
  49. break;
  50. case UnitMillimeter:
  51. height *= 10.0;
  52. height /= 254.0;
  53. break;
  54. default:
  55. return FALSE;
  56. }
  57. }
  58. }
  59. scale = height / EmHt;
  60. GpMatrix tempMatrix(scale, 0, 0, scale, 0, 0);
  61. GpMatrix wtodMatrix;
  62. REAL m[6];
  63. if (pmx)
  64. tempMatrix.Append(*pmx);
  65. if (!needPaths)
  66. {
  67. pdc->GetWorldToDeviceTransform(&wtodMatrix);
  68. tempMatrix.Append(wtodMatrix);
  69. }
  70. tempMatrix.GetMatrix(m);
  71. pfdx->eXX = m[0];
  72. pfdx->eXY = m[1];
  73. pfdx->eYX = m[2];
  74. pfdx->eYY = m[3];
  75. // Adjust for the non-square resolution
  76. if (!needPaths)
  77. {
  78. if (DpiY != DpiX)
  79. {
  80. DpiX /= DpiY;
  81. pfdx->eXX *= DpiX;
  82. pfdx->eYX *= DpiX;
  83. }
  84. }
  85. return TRUE;
  86. }
  87. //////////////////////////////////////////////////////////////////////////////
  88. GpFaceRealization::GpFaceRealization(
  89. const GpFontFace *face,
  90. INT style,
  91. const GpMatrix *matrix,
  92. const SizeF dpi,
  93. TextRenderingHint textMode,
  94. BOOL bPath,
  95. BOOL bCompatibleWidth, /* we want ClearType compatible width when we come from DrawDriverString */
  96. BOOL bSideways /* for far east vertical writing, run of glyph layed out sideways,
  97. used to do the italic simulation in the right direction */
  98. ) :
  99. prface (NULL),
  100. Style (style),
  101. Status (GenericError),
  102. LimitSubpixel (FALSE)
  103. {
  104. if (bInit(face, style, matrix, dpi, textMode, bPath, bCompatibleWidth, bSideways))
  105. {
  106. vGetCache();
  107. Status = Ok;
  108. }
  109. }
  110. void GpFaceRealization::CloneFaceRealization(
  111. const GpFaceRealization * pfaceRealization,
  112. BOOL bPath
  113. )
  114. {
  115. BOOL bOK = FALSE;
  116. SizeF dpi;
  117. // Adjust for the non-square resolution
  118. // Now we will not do it but eventually we will need to do it.
  119. prface = NULL;
  120. if (FindRealizedFace(pfaceRealization->pfdx(), pfaceRealization->GetFontFace(),
  121. bPath, pfaceRealization->prface->fobj.flFontType))
  122. bOK = TRUE;
  123. dpi.Width = (REAL) pfaceRealization->prface->fobj.sizLogResPpi.cx;
  124. dpi.Height = (REAL) pfaceRealization->prface->fobj.sizLogResPpi.cy;
  125. if (!bOK && Realize(dpi, pfaceRealization->GetFontFace(), pfaceRealization->GetStyle(),
  126. pfaceRealization->pfdx(), pfaceRealization->prface->fobj.flFontType, bPath))
  127. {
  128. prface->Face->pff->cRealizedFace +=1;
  129. bOK = TRUE;
  130. }
  131. if (bOK)
  132. {
  133. vGetCache();
  134. Status = Ok;
  135. }
  136. }
  137. BOOL GpFaceRealization::bInit(
  138. const GpFontFace * pface,
  139. INT style,
  140. const GpMatrix * matrix,
  141. SizeF dpi,
  142. TextRenderingHint textMode,
  143. BOOL bPath,
  144. BOOL bCompatibleWidth, /* we want ClearType compatible width when we come from DrawDriverString */
  145. BOOL bSideways /* for far east vertical writing, run of glyph layed out sideways,
  146. used to do the italic simulation in the right direction */
  147. )
  148. {
  149. // It is a new version of face realization
  150. REAL m[6];
  151. FD_XFORM fdxTmp;
  152. BOOL canSimulate = TRUE;
  153. ULONG fl = FO_EM_HEIGHT;
  154. ULONG flSim = 0;
  155. matrix->GetMatrix(m);
  156. fdxTmp.eXX = m[0];
  157. fdxTmp.eXY = m[1];
  158. fdxTmp.eYX = m[2];
  159. fdxTmp.eYY = m[3];
  160. // Adjust for the non-square resolution
  161. // Now we will not do it but eventually we will need to do it.
  162. prface = NULL;
  163. // TextRenderingHintSystemDefault should already been converted through GetTextRenderingHintInternal
  164. ASSERT (textMode != TextRenderingHintSystemDefault);
  165. if (textMode == TextRenderingHintSingleBitPerPixel)
  166. fl |= FO_MONO_UNHINTED;
  167. else if (textMode == TextRenderingHintAntiAliasGridFit)
  168. fl |= FO_GRAYSCALE;
  169. else if (textMode == TextRenderingHintAntiAlias)
  170. fl |= FO_GRAYSCALE | FO_SUBPIXEL_4;
  171. else if (textMode == TextRenderingHintClearTypeGridFit)
  172. {
  173. fl |= FO_GRAYSCALE | FO_CLEARTYPE_GRID;
  174. if (bCompatibleWidth)
  175. fl |= FO_COMPATIBLE_WIDTH;
  176. }
  177. // version 2 :
  178. // else if (textMode == TextRenderingHintClearType)
  179. // fl |= FO_GRAYSCALE | FO_CLEARTYPE;
  180. if ( style & FontStyleBold
  181. && !(pface->GetFaceStyle() & FontStyleBold))
  182. {
  183. if (pface->SimBold())
  184. {
  185. fl |= FO_SIM_BOLD;
  186. }
  187. else
  188. {
  189. return FALSE; // Bold required but cannot be simulated
  190. }
  191. }
  192. if ( style & FontStyleItalic
  193. && !(pface->GetFaceStyle() & FontStyleItalic))
  194. {
  195. if (pface->SimItalic())
  196. {
  197. if (bSideways)
  198. {
  199. fl |= FO_SIM_ITALIC_SIDEWAYS;
  200. }
  201. else
  202. {
  203. fl |= FO_SIM_ITALIC;
  204. }
  205. }
  206. else
  207. {
  208. return FALSE; // Italic required but cannot be simulated
  209. }
  210. }
  211. if (FindRealizedFace(&fdxTmp, pface, bPath, fl))
  212. return TRUE;
  213. if (Realize(dpi, pface, style, &fdxTmp, fl, bPath))
  214. {
  215. pface->pff->cRealizedFace +=1;
  216. return TRUE;
  217. }
  218. return FALSE;
  219. }
  220. // Destructor -- Unlocks the CacheFaceRealization
  221. GpFaceRealization::~GpFaceRealization ()
  222. {
  223. if (prface != (CacheFaceRealization *) NULL )
  224. {
  225. vReleaseCache();
  226. }
  227. }
  228. GpFaceRealization::ReuseRealizedFace()
  229. {
  230. if (prface != (CacheFaceRealization *) NULL )
  231. {
  232. // free glyphbit cache
  233. GlyphBitsBlock *pbblfree, *pbbl = prface->FirstGlyphBitsBlock;
  234. while(pbbl)
  235. {
  236. pbblfree = pbbl;
  237. pbbl = pbbl->NextGlyphBitsBlock;
  238. GpFree((PVOID)pbblfree);
  239. }
  240. // free glyphdata cache
  241. GlyphDataBlock *pdblfree, *pdbl = prface->FirstGlyphDataBlock;
  242. while (pdbl)
  243. {
  244. pdblfree = pdbl;
  245. pdbl = pdbl->NextGlyphDataBlock;
  246. GpFree((PVOID)pdblfree);
  247. }
  248. GpFree(prface->GlyphDataArray);
  249. vDestroyRealizedFace(); /* release the FontContext Memory */
  250. }
  251. return TRUE;
  252. }
  253. GpFaceRealization::DeleteRealizedFace()
  254. {
  255. if (prface != (CacheFaceRealization *) NULL )
  256. {
  257. ReuseRealizedFace();
  258. GpFree(prface);
  259. }
  260. return TRUE;
  261. }
  262. static inline
  263. BOOL SwitchToPath(FLONG flFontType, const FD_DEVICEMETRICS & deviceMetrics)
  264. {
  265. BOOL fResult = FALSE;
  266. INT pathThreshold = PATH_HEIGHT_THRESHOLD;
  267. if (flFontType & FO_CLEARTYPE_GRID)
  268. pathThreshold /= 8;
  269. else if (flFontType & FO_GRAYSCALE)
  270. pathThreshold /= 4;
  271. // Note: This function need quite a bit of reworking so that it takes
  272. // the rotation of the font into account when determining the transition
  273. // point between bitmap/CT and path. Currently the size where we switch
  274. // rendering modes is based on the maximum dimension of the bounding
  275. // box of the largest rotated character. Also note that if a single
  276. // glyph in the font is significantly offset from the rest of the
  277. // glyphs in the font, the deviceMetrics will indicate a much larger
  278. // required bitmap than we would normally use. This switch to path really
  279. // needs to be strictly based on the ascent of the font above the
  280. // baseline, independent of the rotation or the maximum bounding
  281. // rectangle for the rendered glyphs.
  282. if (flFontType & FO_CLEARTYPE_GRID)
  283. {
  284. // Cleartype should not take width of the bitmap into account.
  285. // For rotated text, we will cache larger bitmaps for ClearType
  286. // than for other rendering modes, but this will allow us to more
  287. // closely match the behavior of ClearType in notepad.
  288. fResult =
  289. (deviceMetrics.yMax - deviceMetrics.yMin) > pathThreshold;
  290. }
  291. else
  292. {
  293. fResult =
  294. (deviceMetrics.xMax - deviceMetrics.xMin) > pathThreshold ||
  295. (deviceMetrics.yMax - deviceMetrics.yMin) > pathThreshold;
  296. }
  297. return fResult;
  298. } // SwitchToPath
  299. BOOL GpFaceRealization::FindRealizedFace(
  300. FD_XFORM *fdx,
  301. const GpFontFace *fontFace,
  302. BOOL needPaths,
  303. FLONG fl
  304. ) const
  305. {
  306. FLONG fltemp1 = fl & FONT_GRAYSCALE_OR_CT_OR_MONOUNHINTED;
  307. FLONG fltemp2 = fl & (FO_SIM_BOLD | FO_SIM_ITALIC | FO_SIM_ITALIC_SIDEWAYS);
  308. for (prface = fontFace->pff->prfaceList;
  309. prface != NULL;
  310. prface = (prface->NextCacheFaceRealization == fontFace->pff->prfaceList) ? NULL : prface->NextCacheFaceRealization)
  311. {
  312. if (prface->Face == fontFace)
  313. {
  314. if ((prface->ForcedPath || (needPaths == IsPathFont())) &&
  315. MatchFDXForm(fdx))
  316. {
  317. if (IsPathFont())
  318. {
  319. // if for given text rendering hint we can't switch to path
  320. // skip this realization (unless someone really wants path)
  321. if (!needPaths && !SwitchToPath(fl, prface->DeviceMetrics))
  322. continue;
  323. }
  324. else
  325. {
  326. // FO_NOGRAY16 means that for this transform, grayscale was turned off following the "gasp" table
  327. // see vSetGrayState__FONTCONTEXT in TrueType driver
  328. FLONG fltemp = fltemp1;
  329. if (prface->fobj.flFontType & FO_NOGRAY16)
  330. fltemp &= ~FO_GRAYSCALE;
  331. if (prface->fobj.flFontType & FO_NOCLEARTYPE)
  332. {
  333. if (fltemp & FO_CLEARTYPE_GRID)
  334. fltemp &= ~(FO_CLEARTYPE_GRID | FO_GRAYSCALE | FO_COMPATIBLE_WIDTH);
  335. }
  336. if ((prface->fobj.flFontType & FONT_GRAYSCALE_OR_CT_OR_MONOUNHINTED) != fltemp)
  337. {
  338. continue;
  339. }
  340. }
  341. if ((prface->fobj.flFontType & (FO_SIM_BOLD | FO_SIM_ITALIC | FO_SIM_ITALIC_SIDEWAYS)) != fltemp2)
  342. continue;
  343. // We need to update the recently used list here!
  344. Globals::FontCacheLastRecentlyUsedList->RemoveFace(prface);
  345. Globals::FontCacheLastRecentlyUsedList->AddMostRecent(prface);
  346. return TRUE;
  347. }
  348. }
  349. }
  350. prface = NULL;
  351. return FALSE;
  352. }
  353. BOOL GpFaceRealization::bGetDEVICEMETRICS()
  354. {
  355. if (ttfdSemQueryFontData(
  356. &prface->fobj,
  357. QFD_MAXEXTENTS,
  358. HGLYPH_INVALID,
  359. (GLYPHDATA *) NULL,
  360. &prface->DeviceMetrics) == FD_ERROR)
  361. {
  362. // The QFD_MAXEXTENTS mode is required of all drivers.
  363. // However must allow for the possibility of this call to fail.
  364. // This could happen if the
  365. // font file is on the net and the net connection dies, and the font
  366. // driver needs the font file to produce device metrics [bodind]
  367. return FALSE;
  368. }
  369. if (prface->fobj.flFontType & FO_CLEARTYPE_GRID)
  370. {
  371. // need to compute the filtering correction for CLEAR_TYPE:
  372. // x filtering adds a pixel on each side of the glyph
  373. prface->MaxGlyphByteCount = CJ_CTGD(
  374. prface->DeviceMetrics.cxMax + 2,
  375. prface->DeviceMetrics.cyMax
  376. );
  377. }
  378. else
  379. {
  380. prface->MaxGlyphByteCount = prface->DeviceMetrics.cjGlyphMax; // used to get via QFD_MAXGLYPHBITMAP
  381. }
  382. // Everythings OK.
  383. return TRUE;
  384. }
  385. VOID GpFaceRealization::vDestroyRealizedFace()
  386. {
  387. ttfdSemDestroyFont(&prface->fobj);
  388. }
  389. BOOL GpFaceRealization::Realize(
  390. SizeF dpi,
  391. const GpFontFace *pfe,
  392. INT style, // style - which may require simulation
  393. PFD_XFORM pfdx, // font xform (Notional to Device)
  394. FLONG fl, // these two really modify the xform
  395. BOOL bNeedPaths
  396. )
  397. {
  398. BOOL result = FALSE;
  399. // prface is a member variable pointing to the embedded CacheFaceRealization
  400. if (Globals::FontCacheLastRecentlyUsedList->GetCount() >= MAXRECENTLYUSEDCOUNT)
  401. {
  402. prface = Globals::FontCacheLastRecentlyUsedList->ReuseLeastRecent();
  403. ASSERT(prface);
  404. }
  405. else
  406. {
  407. prface = (CacheFaceRealization *)GpMalloc(sizeof(CacheFaceRealization));
  408. }
  409. if (!prface)
  410. return FALSE;
  411. // Copy the font transform passed in.
  412. prface->fobj.fdx = *pfdx;
  413. // Initialize the DDI callback EXFORMOBJ.
  414. GpMatrix tmpMatrix(pfdx->eXX, pfdx->eXY, pfdx->eYX, pfdx->eYY, 0, 0);
  415. prface->mxForDDI = tmpMatrix;
  416. // Initialize the FONTOBJ inherited by the embedded CacheFaceRealization
  417. // Save identifiers to the source of the font (physical font).
  418. prface->Face = pfe;
  419. // GetDpiX() and GetDpiY() return REALs
  420. prface->fobj.sizLogResPpi.cx = GpRound(dpi.Width);
  421. prface->fobj.sizLogResPpi.cy = GpRound(dpi.Height);
  422. prface->fobj.ulPointSize = 0;
  423. prface->fobj.flFontType = fl | FO_TYPE_TRUETYPE; // fl contains simulation flag(s)
  424. prface->fobj.pvProducer = (PVOID) NULL; // the true type driver will init this field
  425. prface->fobj.iFace = prface->Face->iFont;
  426. prface->fobj.iFile = prface->Face->pff->hff;
  427. // Get the device metrics info
  428. if (!bGetDEVICEMETRICS())
  429. {
  430. vDestroyRealizedFace(); // kill the driver realization
  431. GpFree(prface);
  432. prface = NULL;
  433. return result; // return FALSE
  434. }
  435. prface->CacheType = bNeedPaths ? CachePath : CacheBits;
  436. prface->ForcedPath = FALSE;
  437. if (!bNeedPaths)
  438. {
  439. // We force drawing with a path if size is to large
  440. if (SwitchToPath(prface->fobj.flFontType, prface->DeviceMetrics))
  441. {
  442. prface->CacheType = CachePath;
  443. prface->ForcedPath = TRUE;
  444. }
  445. }
  446. // If you force the path mode then turn off antialiasing
  447. if (IsPathFont())
  448. {
  449. prface->fobj.flFontType &= ~FONT_GRAYSCALE_OR_CT_OR_MONOUNHINTED;
  450. prface->realizationMethod = TextRenderingHintSingleBitPerPixelGridFit;
  451. prface->QueryFontDataMode = QFD_GLYPHANDOUTLINE;
  452. }
  453. else
  454. {
  455. if (prface->fobj.flFontType & FO_GRAYSCALE)
  456. {
  457. // version 2 :
  458. // if (prface->fobj.flFontType & FO_CLEARTYPE)
  459. // {
  460. // prface->realizationMethod = TextRenderingHintClearType;
  461. // prface->QueryFontDataMode = QFD_CT;
  462. // }
  463. if (prface->fobj.flFontType & FO_CLEARTYPE_GRID)
  464. {
  465. prface->realizationMethod = TextRenderingHintClearTypeGridFit;
  466. prface->QueryFontDataMode = QFD_CT_GRID;
  467. }
  468. else if (prface->fobj.flFontType & FO_SUBPIXEL_4)
  469. {
  470. prface->CacheType = CacheAABits;
  471. prface->realizationMethod = TextRenderingHintAntiAlias;
  472. prface->QueryFontDataMode = QFD_TT_GRAY4_BITMAP;
  473. }
  474. else
  475. {
  476. prface->realizationMethod = TextRenderingHintAntiAliasGridFit;
  477. prface->QueryFontDataMode = QFD_TT_GRAY4_BITMAP;
  478. }
  479. }
  480. else
  481. {
  482. if (prface->fobj.flFontType & FO_MONO_UNHINTED)
  483. {
  484. prface->realizationMethod = TextRenderingHintSingleBitPerPixel;
  485. prface->QueryFontDataMode = QFD_GLYPHANDBITMAP_SUBPIXEL;
  486. }
  487. else
  488. {
  489. prface->realizationMethod = TextRenderingHintSingleBitPerPixelGridFit;
  490. prface->QueryFontDataMode = QFD_GLYPHANDBITMAP;
  491. }
  492. }
  493. }
  494. if (!bInitCache())
  495. {
  496. vDestroyRealizedFace(); // kill the driver realization
  497. GpFree(prface);
  498. prface = NULL;
  499. return result; // return FALSE
  500. }
  501. // Made it this far, so everything is OK
  502. result = TRUE;
  503. Globals::FontCacheLastRecentlyUsedList->AddMostRecent(prface);
  504. vInsert(&prface->Face->pff->prfaceList);
  505. return result;
  506. }
  507. VOID GpFaceRealization::vInsert(CacheFaceRealization **pprfaceHead)
  508. {
  509. if (*pprfaceHead != NULL)
  510. {
  511. prface->NextCacheFaceRealization = *pprfaceHead;
  512. prface->PreviousCacheFaceRealization = (*pprfaceHead)->PreviousCacheFaceRealization;
  513. prface->PreviousCacheFaceRealization->NextCacheFaceRealization = prface;
  514. (*pprfaceHead)->PreviousCacheFaceRealization = prface;
  515. }
  516. else
  517. {
  518. prface->NextCacheFaceRealization = prface;
  519. prface->PreviousCacheFaceRealization = prface;
  520. }
  521. *pprfaceHead = prface;
  522. }
  523. BOOL GpFaceRealization::bInitCache() const
  524. {
  525. BOOL result = TRUE; // unless proven otherwise
  526. // Set the pointer to null. vDeleteCache will free memory from
  527. // any non-null pointers. This simplifies cleanup, since bRealize
  528. // ensures that vDeleteCache is called if this routine fails.
  529. // metrics portion
  530. prface->FirstGlyphDataBlock = NULL;
  531. prface->GlyphDataBlockUnderConstruction = NULL;
  532. prface->NextFreeGlyphDataIndex = 0;
  533. // glyphbits portion
  534. prface->FirstGlyphBitsBlock = NULL;
  535. prface->GlyphBitsBlockUnderConstruction = NULL;
  536. prface->SizeGlyphBitsBlockUnderConstruction = 0;
  537. prface->UsedBytesGlyphBitsBlockUnderConstruction = 0;
  538. // aux mem portion
  539. prface->LookasideGlyphData = NULL;
  540. prface->LookasideByteCount = 0;
  541. prface->GlyphDataArray = NULL; // to be allocated later, big allocation
  542. prface->NextCacheFaceRealization = NULL;
  543. prface->PreviousCacheFaceRealization = NULL;
  544. // First, figure out how big the max glyph will be
  545. // Default is zero - glyphdata size is not counted!
  546. ULONG cjGlyphMaxX2;
  547. if (IsPathFont())
  548. {
  549. cjGlyphMaxX2 = CJMAX;
  550. }
  551. else
  552. {
  553. cjGlyphMaxX2 = 2 * prface->MaxGlyphByteCount;
  554. }
  555. // if we can't even get one glyph in a maximum size cache, don't cache
  556. // Note that we need room for the default glyph and one other glyph
  557. prface->NoCache = FALSE;
  558. if (cjGlyphMaxX2 > CJMAX)
  559. {
  560. // Glyph exceeds maximum cache memory size, so we will revert to
  561. // caching just the metrics. This will speed up things like
  562. // GetCharWidths, and stuff that just *has* to have the glyphs
  563. // will use the lookaside stuff (previously called BigGlyph)
  564. /* we don't support NoCache and Path */
  565. ASSERT(!IsPathFont())
  566. prface->NoCache = TRUE;
  567. }
  568. // set up the cache semaphore.
  569. // InitializeCriticalSection(&prface->FaceRealizationCritSection);
  570. return result;
  571. }
  572. BOOL GpFaceRealization::AllocateCache() const
  573. {
  574. BOOL result = TRUE; // unless proven otherwise
  575. ULONG cGlyphsTotal = 0;
  576. cGlyphsTotal = GetGlyphsSupported();
  577. if (!cGlyphsTotal)
  578. return FALSE;
  579. // The distribution of metics per realized font w/ Winstone97 is:
  580. //
  581. // 43% <= 0 Metrics
  582. // 50% <= 6 Metrics
  583. // 76% <= 32 Metrics
  584. // 99% <= 216 Metrics
  585. // 100% <= 249 Metrics
  586. //
  587. // allocate memory for the glyphDataArray :
  588. if ((prface->GlyphDataArray = (GpGlyphData **) GpMalloc(cGlyphsTotal * sizeof(GpGlyphData*))) == NULL)
  589. {
  590. return FALSE;
  591. }
  592. // init all glyphdata pointers to zero
  593. memset(prface->GlyphDataArray, 0, sizeof(GpGlyphData*) * cGlyphsTotal);
  594. // Allocate memory for the first GpGlyphData block
  595. if ((prface->GlyphDataBlockUnderConstruction = (GlyphDataBlock *)GpMalloc(sizeof(GlyphDataBlock))) == NULL)
  596. {
  597. return FALSE;
  598. }
  599. prface->FirstGlyphDataBlock = prface->GlyphDataBlockUnderConstruction;
  600. prface->FirstGlyphDataBlock->NextGlyphDataBlock = NULL;
  601. prface->NextFreeGlyphDataIndex = 0;
  602. // we shall re-interpret cjMax to mean the max number of bytes in
  603. // glyphbits portion of the cache per 1K of glyphs in the font.
  604. // That is for larger fonts we shall allow more glyphbits
  605. // memory per realization than for ordinary US fonts. This will be
  606. // particularly important for FE fonts. This same code will work fine
  607. // in their case too:
  608. ULONG cjBytes = 16 * prface->MaxGlyphByteCount;
  609. ULONG AllocationSize = ROUND_TO_PAGE(cjBytes);
  610. if (AllocationSize == 0)
  611. prface->cBlocksMax = 1;
  612. else
  613. {
  614. prface->cBlocksMax =
  615. (CJMAX * ((cGlyphsTotal + 1024 - 1)/1024)) /
  616. AllocationSize;
  617. /* at least one block */
  618. if (prface->cBlocksMax == 0)
  619. prface->cBlocksMax = 1;
  620. }
  621. prface->cBlocks = 0;
  622. return result;
  623. }
  624. //// ConvertGLYPHDATAToGpGlyphMetrics
  625. //
  626. // Populate GpGlyphMetrics field of GpGlyphData from font driver GLYPHDATA
  627. VOID GpFaceRealization::ConvertGLYPHDATAToGpGlyphMetrics(
  628. IN INT glyphIndex,
  629. IN GLYPHDATA *pgd,
  630. OUT GpGlyphData *pgpgd
  631. ) const
  632. {
  633. // horizontal metrics:
  634. pgpgd->GlyphMetrics[0].AdvanceWidth = pgd->fxD;
  635. pgpgd->GlyphMetrics[0].LeadingSidebearing = pgd->fxA;
  636. pgpgd->GlyphMetrics[0].TrailingSidebearing = pgd->fxD - pgd->fxAB;
  637. pgpgd->GlyphMetrics[0].Origin = PointF(0,0);
  638. // vertical metrics:
  639. pgpgd->GlyphMetrics[1].AdvanceWidth = pgd->fxD_Sideways;
  640. pgpgd->GlyphMetrics[1].LeadingSidebearing = pgd->fxA_Sideways;
  641. pgpgd->GlyphMetrics[1].TrailingSidebearing = pgd->fxD_Sideways - pgd->fxAB_Sideways;
  642. pgpgd->GlyphMetrics[1].Origin.X = pgd->VerticalOrigin_X / 16.0f;
  643. pgpgd->GlyphMetrics[1].Origin.Y = pgd->VerticalOrigin_Y / 16.0f;
  644. pgpgd->GlyphBits = NULL;
  645. }
  646. GpStatus GpFaceRealization::IsMetricsCached
  647. (
  648. UINT16 glyphIndex,
  649. ULONG *pcjNeeded
  650. ) const
  651. {
  652. ULONG cjNeeded = 0;
  653. if (prface->GlyphDataArray == NULL)
  654. if (!AllocateCache())
  655. return OutOfMemory;
  656. if (glyphIndex >= prface->Face->NumGlyphs)
  657. return InvalidParameter;
  658. if (!prface->GlyphDataArray[glyphIndex])
  659. {
  660. GLYPHDATA gd;
  661. // Verify enough room in metrics cache area, grow if needed.
  662. // Note that failure to fit a glyphdata is a hard error, get out now.
  663. if (!CheckMetricsCache())
  664. {
  665. return GenericError;
  666. }
  667. // Call font driver to get the metrics.
  668. cjNeeded = ttfdSemQueryFontData(
  669. &prface->fobj,
  670. prface->QueryFontDataMode,
  671. (HGLYPH)glyphIndex,
  672. &gd,
  673. NULL
  674. );
  675. if (cjNeeded == FD_ERROR)
  676. {
  677. return GenericError;
  678. }
  679. gd.gdf.pgb = NULL;
  680. if (prface->fobj.flFontType & FO_CLEARTYPE_GRID)
  681. {
  682. ULONG cx = (ULONG)(gd.rclInk.right - gd.rclInk.left);
  683. ULONG cy = (ULONG)(gd.rclInk.bottom - gd.rclInk.top);
  684. ASSERT(cjNeeded <= CJ_CTGD(cx+2,cy));
  685. cjNeeded = CJ_CTGD(cx+2,cy);
  686. }
  687. prface->GlyphDataArray[glyphIndex] = &prface->GlyphDataBlockUnderConstruction->GlyphDataArray[prface->NextFreeGlyphDataIndex];
  688. // Populate GpGlyphMetrics field of GpGlyphData from font driver GLYPHDATA
  689. ConvertGLYPHDATAToGpGlyphMetrics(glyphIndex, &gd, prface->GlyphDataArray[glyphIndex]);
  690. prface->NextFreeGlyphDataIndex ++;
  691. }
  692. if (pcjNeeded)
  693. {
  694. *pcjNeeded = cjNeeded;
  695. }
  696. ASSERT(prface->GlyphDataArray[glyphIndex])
  697. return Ok;
  698. }
  699. BOOL GpFaceRealization::InsertGlyphPath(
  700. UINT16 glyphIndex,
  701. BOOL bFlushOk
  702. ) const
  703. {
  704. // Call font driver to get the metrics.
  705. GpGlyphPath *fontPath;
  706. GLYPHDATA gd;
  707. GpPath path;
  708. ASSERT(IsPathFont());
  709. ASSERT(prface->GlyphDataArray[glyphIndex]);
  710. if (prface->GlyphDataArray[glyphIndex]->GlyphPath)
  711. return TRUE;
  712. ULONG cjNeeded = ttfdSemQueryFontData(
  713. &prface->fobj,
  714. prface->QueryFontDataMode,
  715. (HGLYPH)glyphIndex,
  716. &gd,
  717. (PVOID)&path
  718. );
  719. if ( cjNeeded == FD_ERROR )
  720. return FALSE;
  721. if (!path.IsValid())
  722. return FALSE;
  723. cjNeeded = sizeof(GpGlyphPath) +
  724. path.GetPointCount() * (sizeof(GpPointF) + sizeof(BYTE));
  725. cjNeeded = ALIGN(void*, cjNeeded);
  726. /* a GpGlyphPath* need to be aligned to the next valid pointer address */
  727. ALIGN(void*, prface->UsedBytesGlyphBitsBlockUnderConstruction);
  728. VOID *GlyphBits;
  729. while ((GlyphBits = (GLYPHBITS *)pgbCheckGlyphCache(cjNeeded)) == NULL)
  730. {
  731. if ( !bFlushOk )
  732. return FALSE;
  733. //TRACE_INSERT(("InsertGlyphBits: Flushing the cache\n"));
  734. FlushCache();
  735. bFlushOk = FALSE;
  736. }
  737. fontPath = (GpGlyphPath*)GlyphBits;
  738. if (fontPath->CopyPath(&path) != Ok)
  739. return FALSE;
  740. prface->GlyphDataArray[glyphIndex]->GlyphPath = fontPath;
  741. prface->UsedBytesGlyphBitsBlockUnderConstruction += cjNeeded;
  742. return TRUE;
  743. }
  744. BOOL GpFaceRealization::InsertGlyphBits(
  745. UINT16 glyphIndex,
  746. ULONG cjNeeded,
  747. BOOL bFlushOk
  748. ) const
  749. {
  750. if (prface->NoCache)
  751. {
  752. return FALSE;
  753. }
  754. ASSERT(!IsPathFont());
  755. ASSERT(prface->GlyphDataArray[glyphIndex]);
  756. if (prface->GlyphDataArray[glyphIndex]->GlyphBits)
  757. return TRUE;
  758. // Look to see if there is room in the glyphbits cache
  759. // Grow the glyphbits cache if neccessary, but don't flush the cache
  760. GLYPHDATA gd;
  761. // If max glyph will fit, assume max glyph
  762. // otherwise, call up and ask how big
  763. if ( (prface->MaxGlyphByteCount < (SIZE_T)(prface->SizeGlyphBitsBlockUnderConstruction - prface->UsedBytesGlyphBitsBlockUnderConstruction)) )
  764. {
  765. cjNeeded = prface->MaxGlyphByteCount;
  766. }
  767. else
  768. {
  769. if (!cjNeeded)
  770. {
  771. cjNeeded = ttfdSemQueryFontData(
  772. &prface->fobj,
  773. prface->QueryFontDataMode,
  774. glyphIndex,
  775. &gd,
  776. NULL
  777. );
  778. if ( cjNeeded == FD_ERROR )
  779. return FALSE;
  780. if (prface->fobj.flFontType & FO_CLEARTYPE_GRID)
  781. {
  782. ULONG cx = (ULONG)(gd.rclInk.right - gd.rclInk.left);
  783. ULONG cy = (ULONG)(gd.rclInk.bottom - gd.rclInk.top);
  784. ASSERT(cjNeeded <= CJ_CTGD(cx+2,cy));
  785. cjNeeded = CJ_CTGD(cx+2,cy);
  786. }
  787. }
  788. }
  789. // Now, we try to fit the bits in. If they fit, fine.
  790. // If not, and we can flush the cache, we flush it and try again.
  791. // If we couldn't flush, or we flushed and still fail, just return.
  792. GLYPHBITS *GlyphBits;
  793. //TRACE_INSERT(("InsertGlyphBits: attempting to insert bits at: 0x%lx\n", prface->UsedBytesGlyphBitsBlockUnderConstruction));
  794. while ((GlyphBits = (GLYPHBITS *)pgbCheckGlyphCache(cjNeeded)) == NULL)
  795. {
  796. if ( !bFlushOk )
  797. return FALSE;
  798. //TRACE_INSERT(("InsertGlyphBits: Flushing the cache\n"));
  799. FlushCache();
  800. bFlushOk = FALSE;
  801. }
  802. // Call font driver to get glyph bits.
  803. cjNeeded = ttfdSemQueryFontData(
  804. &prface->fobj,
  805. prface->QueryFontDataMode,
  806. glyphIndex,
  807. &gd,
  808. (VOID *)GlyphBits
  809. );
  810. if ( cjNeeded == FD_ERROR )
  811. return FALSE;
  812. ASSERT(cjNeeded <= prface->MaxGlyphByteCount);
  813. if (prface->fobj.flFontType & FO_CLEARTYPE_GRID)
  814. {
  815. ULONG cx = (ULONG)(gd.rclInk.right - gd.rclInk.left);
  816. ULONG cy = (ULONG)(gd.rclInk.bottom - gd.rclInk.top);
  817. ASSERT(cjNeeded <= CJ_CTGD(cx+2,cy));
  818. cjNeeded = CJ_CTGD(cx+2,cy);
  819. ASSERT(cjNeeded <= prface->MaxGlyphByteCount);
  820. if (GlyphBits)
  821. {
  822. cjNeeded = ulClearTypeFilter(GlyphBits, cjNeeded, prface);
  823. }
  824. }
  825. // Only the glyph bits we need.
  826. prface->GlyphDataArray[glyphIndex]->GlyphBits = GlyphBits;
  827. // Adjust the cache next pointers as needed.
  828. prface->UsedBytesGlyphBitsBlockUnderConstruction += cjNeeded;
  829. return TRUE;
  830. }
  831. //// GetGlyphDataLookaside
  832. //
  833. // Returns glyph data for a single glyph, using the lookaside buffer
  834. // instead of the cache.
  835. GpGlyphData *GpFaceRealization::GetGlyphDataLookaside(
  836. UINT16 glyphIndex
  837. ) const
  838. {
  839. if (!IsPathFont())
  840. {
  841. // Make sure the lookaside buffer has enough room for the bitmap
  842. ULONG cjMaxBitmap = prface->MaxGlyphByteCount + sizeof(GpGlyphData);
  843. // Allocate the buffer and save its size if existing buffer isn't big enough
  844. if (prface->LookasideByteCount < cjMaxBitmap)
  845. {
  846. if (prface->LookasideGlyphData != NULL)
  847. {
  848. GpFree(prface->LookasideGlyphData);
  849. }
  850. prface->LookasideGlyphData = (GpGlyphData *)GpMalloc(cjMaxBitmap);
  851. if (prface->LookasideGlyphData == NULL)
  852. return NULL;
  853. prface->LookasideByteCount = cjMaxBitmap;
  854. }
  855. GpGlyphData *pgd = prface->LookasideGlyphData;
  856. GLYPHBITS *glyphBits = (GLYPHBITS *)(pgd + 1);
  857. GLYPHDATA gd;
  858. ULONG cjNeeded = ttfdSemQueryFontData(
  859. &prface->fobj,
  860. prface->QueryFontDataMode,
  861. glyphIndex,
  862. &gd,
  863. glyphBits
  864. );
  865. if (cjNeeded == FD_ERROR)
  866. return NULL;
  867. ASSERT(cjNeeded <= prface->MaxGlyphByteCount);
  868. if (prface->fobj.flFontType & FO_CLEARTYPE_GRID)
  869. {
  870. ULONG cx = (ULONG)(gd.rclInk.right - gd.rclInk.left);
  871. ULONG cy = (ULONG)(gd.rclInk.bottom - gd.rclInk.top);
  872. ASSERT(cjNeeded <= CJ_CTGD(cx+2,cy));
  873. cjNeeded = CJ_CTGD(cx+2,cy);
  874. ASSERT(cjNeeded <= prface->MaxGlyphByteCount);
  875. if (glyphBits)
  876. {
  877. cjNeeded = ulClearTypeFilter(glyphBits, cjNeeded, prface);
  878. }
  879. }
  880. // Populate GpGlyphMetrics field of GpGlyphData from font driver GLYPHDATA
  881. ConvertGLYPHDATAToGpGlyphMetrics(glyphIndex, &gd, pgd);
  882. // Set the returned value
  883. pgd->GlyphBits = glyphBits;
  884. return pgd;
  885. }
  886. else
  887. {
  888. // For glyph path
  889. // Call font driver to get the metrics.
  890. GLYPHDATA gd;
  891. GpPath path;
  892. // Verify enough room in metrics cache area, grow if needed.
  893. // Note that failure to fit a glyphdata is a hard error, get out now.
  894. ULONG cjNeeded = ttfdSemQueryFontData(
  895. &prface->fobj,
  896. prface->QueryFontDataMode,
  897. (HGLYPH)glyphIndex,
  898. &gd,
  899. (PVOID)&path
  900. );
  901. if ( cjNeeded == FD_ERROR )
  902. return NULL;
  903. if (!path.IsValid())
  904. return NULL;
  905. cjNeeded = sizeof(GpGlyphData) + sizeof(GpGlyphPath) + path.GetPointCount() * (sizeof(GpPointF) + sizeof(BYTE));
  906. cjNeeded = ALIGN(void*, cjNeeded);
  907. // Make sure the lookaside buffer is allocated
  908. if ( ( prface->LookasideByteCount < cjNeeded ) &&
  909. ( prface->LookasideGlyphData != NULL ))
  910. {
  911. GpFree((PVOID) prface->LookasideGlyphData);
  912. prface->LookasideGlyphData = NULL;
  913. prface->LookasideByteCount = 0;
  914. }
  915. if ( prface->LookasideGlyphData == NULL )
  916. {
  917. prface->LookasideGlyphData = (GpGlyphData *)GpMalloc(cjNeeded);
  918. if ( prface->LookasideGlyphData == NULL )
  919. return NULL;
  920. prface->LookasideByteCount = cjNeeded;
  921. }
  922. GpGlyphData * pgd = prface->LookasideGlyphData;
  923. GpGlyphPath * fontPath = (GpGlyphPath *)(pgd + 1);
  924. // Populate GpGlyphMetrics field of GpGlyphData from font driver GLYPHDATA
  925. ConvertGLYPHDATAToGpGlyphMetrics(glyphIndex, &gd, pgd);
  926. if (fontPath->CopyPath(&path) != Ok)
  927. return FALSE;
  928. // Set the returned value
  929. pgd->GlyphPath = fontPath;
  930. return pgd;
  931. }
  932. }
  933. BOOL GpFaceRealization::CheckMetricsCache() const
  934. {
  935. // Verify enough room in metrics cache area, grow if needed.
  936. if (prface->NextFreeGlyphDataIndex >= GLYPHDATABLOCKCOUNT)
  937. {
  938. GlyphDataBlock *NewGlyphDataBlock;
  939. // allocate a new block of GpGlyphData structs
  940. if ((NewGlyphDataBlock = (GlyphDataBlock *)GpMalloc(sizeof(GlyphDataBlock))) == NULL)
  941. {
  942. return FALSE;
  943. }
  944. NewGlyphDataBlock->NextGlyphDataBlock = NULL;
  945. prface->GlyphDataBlockUnderConstruction->NextGlyphDataBlock = NewGlyphDataBlock;
  946. prface->GlyphDataBlockUnderConstruction = NewGlyphDataBlock;
  947. prface->NextFreeGlyphDataIndex = 0;
  948. }
  949. return TRUE;
  950. }
  951. PVOID GpFaceRealization::pgbCheckGlyphCache(SIZE_T cjNeeded) const
  952. {
  953. if ((prface->UsedBytesGlyphBitsBlockUnderConstruction + cjNeeded) > prface->SizeGlyphBitsBlockUnderConstruction)
  954. {
  955. ULONG cjBlockSize;
  956. ASSERT (!(prface->NoCache));
  957. if (IsPathFont())
  958. {
  959. // this seems to work and this is what we did before DavidFie changes
  960. // for PATHOBJ case
  961. cjBlockSize = CJMAX;
  962. }
  963. else
  964. {
  965. ULONG cjBytes = 16 * prface->MaxGlyphByteCount;
  966. cjBlockSize = ROUND_TO_PAGE(cjBytes);
  967. if (prface->FirstGlyphBitsBlock == NULL)
  968. {
  969. // first block designed to contain 16 glyphs
  970. cjBlockSize = cjBytes;
  971. }
  972. }
  973. if ( !(prface->NoCache)
  974. && (prface->cBlocks < prface->cBlocksMax)
  975. && ((offsetof(GlyphBitsBlock,Bits) + cjNeeded) <= cjBlockSize))
  976. {
  977. // The only reason we need the last check is the PATHOBJ case
  978. // where cjNeeded may actually not fit in the block of SizeGlyphBitsBlock bytes.
  979. // This is because we have no way of knowing how big the paths
  980. // are going to be (especailly after doing bFlatten) and our
  981. // prface->MaxGlyphByteCount is just a good guess in this case.
  982. // We are going to append another block at the end of the list
  983. GlyphBitsBlock *newGlyphBitsBlock = (GlyphBitsBlock *) GpMalloc(cjBlockSize);
  984. if (!newGlyphBitsBlock)
  985. {
  986. return NULL;
  987. }
  988. // we have just allocated another block, update cBlocks:
  989. prface->cBlocks += 1;
  990. // append this block to the end of the list
  991. newGlyphBitsBlock->NextGlyphBitsBlock = NULL;
  992. if (prface->GlyphBitsBlockUnderConstruction != NULL)
  993. prface->GlyphBitsBlockUnderConstruction->NextGlyphBitsBlock = newGlyphBitsBlock;
  994. prface->GlyphBitsBlockUnderConstruction = newGlyphBitsBlock;
  995. if (!prface->FirstGlyphBitsBlock) // first block ever for this rfont
  996. {
  997. prface->FirstGlyphBitsBlock = newGlyphBitsBlock;
  998. }
  999. prface->GlyphBitsBlockUnderConstruction->SizeGlyphBitsBlock = cjBlockSize;
  1000. prface->SizeGlyphBitsBlockUnderConstruction = cjBlockSize;
  1001. prface->UsedBytesGlyphBitsBlockUnderConstruction = offsetof(GlyphBitsBlock,Bits);
  1002. ALIGN(void*, prface->UsedBytesGlyphBitsBlockUnderConstruction);
  1003. }
  1004. else
  1005. {
  1006. // tough luck, we are not allowed to add more blocks
  1007. return NULL;
  1008. }
  1009. }
  1010. return (BYTE *)prface->GlyphBitsBlockUnderConstruction + prface->UsedBytesGlyphBitsBlockUnderConstruction;
  1011. }
  1012. VOID GpFaceRealization::FlushCache() const
  1013. {
  1014. // all the pointers to glyphs bits will be invalidated and we will start
  1015. // filling the glyphbits cache all over again. Therefore, we set the current
  1016. // block to be the same as base block and pgbN to the first available field in
  1017. // in the Current block.
  1018. // Note that vFlushCache is allways called after pgbCheckGlyphCache has failed.
  1019. // pgbCheckGlyphCache could fail for one of the two following reasons:
  1020. //
  1021. // a) (pc->cBlocks == pc->cBlocksMax) && (no room in the last block)
  1022. // b) (pc->cBlocks < pc->cBlocksMax) &&
  1023. // (failed to alloc mem for the new bitblock).
  1024. //
  1025. // In the latter case we do not want to flush glyphbits cache.
  1026. // Instead we shall try to allocate one more time a bit later.
  1027. if (prface->FirstGlyphBitsBlock && (prface->cBlocks == prface->cBlocksMax))
  1028. {
  1029. prface->GlyphBitsBlockUnderConstruction = prface->FirstGlyphBitsBlock;
  1030. prface->UsedBytesGlyphBitsBlockUnderConstruction = offsetof(GlyphBitsBlock,Bits);
  1031. ALIGN(void*, prface->UsedBytesGlyphBitsBlockUnderConstruction);
  1032. // we do not want to use the last 8 bytes in the BITBLOCK. Some drivers
  1033. // read the last dword (or quadword) past the end of the GLYPHBITS.
  1034. // If there is a GLYPHBITS at the very and of the BITBLOCK AND the
  1035. // allocation happens to be at the end of the page the read will AV.
  1036. prface->SizeGlyphBitsBlockUnderConstruction = prface->GlyphBitsBlockUnderConstruction->SizeGlyphBitsBlock;
  1037. }
  1038. // now go and invalidate the glyphbit pointers in the glyphdata cache
  1039. for
  1040. (
  1041. GlyphDataBlock *pdbl = prface->FirstGlyphDataBlock;
  1042. pdbl != (GlyphDataBlock*)NULL;
  1043. pdbl = pdbl->NextGlyphDataBlock
  1044. )
  1045. {
  1046. UINT i;
  1047. for (i = 0; i < GLYPHDATABLOCKCOUNT; i++)
  1048. {
  1049. pdbl->GlyphDataArray[i].GlyphBits = NULL;
  1050. }
  1051. }
  1052. }
  1053. //// CheckGlyphStringMetricsCached
  1054. //
  1055. // Ensures that glyph metric information for all the glyphs in the
  1056. // given glyph string are already cached.
  1057. GpStatus GpFaceRealization::CheckGlyphStringMetricsCached(
  1058. const UINT16 *glyphs,
  1059. INT glyphCount
  1060. ) const
  1061. {
  1062. ASSERT(glyphCount >= 0);
  1063. // Create glyph data array if none yet exists
  1064. if (prface->GlyphDataArray == NULL)
  1065. {
  1066. if (!AllocateCache())
  1067. {
  1068. return OutOfMemory;
  1069. }
  1070. }
  1071. GpGlyphData **glyphData = prface->GlyphDataArray;
  1072. // Check each glyph
  1073. INT glyphIndexLimit = prface->Face->NumGlyphs;
  1074. INT i=0;
  1075. while (i < glyphCount)
  1076. {
  1077. // Loop quickly through glyphs that are already cached
  1078. while ( i < glyphCount
  1079. && ( glyphs[i] == EMPTY_GLYPH_FFFF
  1080. || ( glyphs[i] < glyphIndexLimit
  1081. && glyphData[glyphs[i]] != NULL)))
  1082. {
  1083. i++;
  1084. }
  1085. // Use IsMetricsCached for glyphs not already cached
  1086. if (i < glyphCount)
  1087. {
  1088. GpStatus status = IsMetricsCached(glyphs[i], NULL);
  1089. if (status != Ok)
  1090. {
  1091. return status;
  1092. }
  1093. }
  1094. }
  1095. return Ok;
  1096. }
  1097. //// GetGlyphStringIdealAdvanceVector
  1098. //
  1099. // Returns the realized advance vector scaled to ideal units.
  1100. GpStatus GpFaceRealization::GetGlyphStringIdealAdvanceVector(
  1101. const UINT16 *glyphs,
  1102. INT glyphCount,
  1103. REAL deviceToIdeal,
  1104. BOOL vertical,
  1105. INT *idealAdvances
  1106. ) const
  1107. {
  1108. GpStatus status = CheckGlyphStringMetricsCached(glyphs, glyphCount);
  1109. IF_NOT_OK_WARN_AND_RETURN(status);
  1110. vertical = vertical ? 1 : 0; // Prepare vertical flag for use as index
  1111. // Provide advance width for each glyph
  1112. for (INT i=0; i<glyphCount; i++)
  1113. {
  1114. if (glyphs[i] == EMPTY_GLYPH_FFFF)
  1115. {
  1116. idealAdvances[i] = 0;
  1117. }
  1118. else
  1119. {
  1120. idealAdvances[i] = GpRound(
  1121. prface->GlyphDataArray[glyphs[i]]->GlyphMetrics[vertical].AdvanceWidth
  1122. * deviceToIdeal
  1123. / 16
  1124. );
  1125. }
  1126. }
  1127. return Ok;
  1128. }
  1129. //// GetGlyphStringDeviceAdvanceVector
  1130. //
  1131. // Returns the realized advance vector in device units
  1132. GpStatus GpFaceRealization::GetGlyphStringDeviceAdvanceVector(
  1133. const UINT16 *glyphs,
  1134. INT glyphCount,
  1135. BOOL vertical,
  1136. REAL *deviceAdvances
  1137. ) const
  1138. {
  1139. GpStatus status = CheckGlyphStringMetricsCached(glyphs, glyphCount);
  1140. IF_NOT_OK_WARN_AND_RETURN(status);
  1141. vertical = vertical ? 1 : 0; // Prepare vertical flag for use as index
  1142. // Provide advance width for each glyph
  1143. for (INT i=0; i<glyphCount; i++)
  1144. {
  1145. if (glyphs[i] == EMPTY_GLYPH_FFFF)
  1146. {
  1147. deviceAdvances[i] = 0;
  1148. }
  1149. else
  1150. {
  1151. deviceAdvances[i] = TOREAL(prface->GlyphDataArray[glyphs[i]]->GlyphMetrics[vertical].AdvanceWidth) / 16;
  1152. }
  1153. }
  1154. return Ok;
  1155. }
  1156. // INT 28.4 variant
  1157. GpStatus GpFaceRealization::GetGlyphStringDeviceAdvanceVector(
  1158. const UINT16 *glyphs,
  1159. INT glyphCount,
  1160. BOOL vertical,
  1161. INT *deviceAdvances
  1162. ) const
  1163. {
  1164. GpStatus status = CheckGlyphStringMetricsCached(glyphs, glyphCount);
  1165. IF_NOT_OK_WARN_AND_RETURN(status);
  1166. GpGlyphData **glyphDataArray = prface->GlyphDataArray;
  1167. vertical = vertical ? 1 : 0; // Prepare vertical flag for use as index
  1168. // Provide advance width for each glyph
  1169. for (INT i=0; i<glyphCount; i++)
  1170. {
  1171. if (glyphs[i] == EMPTY_GLYPH_FFFF)
  1172. {
  1173. deviceAdvances[i] = 0;
  1174. }
  1175. else
  1176. {
  1177. deviceAdvances[i] = glyphDataArray[glyphs[i]]
  1178. ->GlyphMetrics[vertical]
  1179. .AdvanceWidth;
  1180. }
  1181. }
  1182. return Ok;
  1183. }
  1184. GpStatus GpFaceRealization::GetGlyphStringVerticalOriginOffsets(
  1185. const UINT16 *glyphs,
  1186. INT glyphCount,
  1187. PointF *offsets
  1188. ) const
  1189. {
  1190. GpStatus status = CheckGlyphStringMetricsCached(glyphs, glyphCount);
  1191. IF_NOT_OK_WARN_AND_RETURN(status);
  1192. GpGlyphData **glyphDataArray = prface->GlyphDataArray;
  1193. for (INT i=0; i<glyphCount; i++)
  1194. {
  1195. if (glyphs[i] == EMPTY_GLYPH_FFFF)
  1196. {
  1197. offsets[i] = PointF(0,0);
  1198. }
  1199. else
  1200. {
  1201. offsets[i] = glyphDataArray[glyphs[i]]->GlyphMetrics[1].Origin;
  1202. }
  1203. }
  1204. return Ok;
  1205. }
  1206. //// GetGlyphStringSidebearings
  1207. //
  1208. // Sidebearings - the sidebearings returned are the largest distances
  1209. // over the ends of the string. i.e. if the first glyph has no negative A
  1210. // width, but the second glyph has a negative A width large enough to reach
  1211. // back over the whole of the first glyph, we return that part of the 2nd
  1212. // glyphs A width that overhangs the left end of the line.
  1213. // This situation is common with scripts that make extensive use of
  1214. // combining characters.
  1215. GpStatus GpFaceRealization::GetGlyphStringSidebearings(
  1216. const UINT16 *glyphs,
  1217. INT glyphCount,
  1218. BOOL vertical,
  1219. BOOL reverse, // For example right-to-left
  1220. INT *leadingSidebearing, // 28.4
  1221. INT *trailingSidebearing // 28.4
  1222. ) const
  1223. {
  1224. GpStatus status = CheckGlyphStringMetricsCached(glyphs, glyphCount);
  1225. IF_NOT_OK_WARN_AND_RETURN(status);
  1226. GpGlyphData **glyphDataArray = prface->GlyphDataArray;
  1227. INT orientation = vertical ? 1 : 0; // Prepare vertical flag for use as index
  1228. INT maxSupportedSidebearing28p4 = (prface->DeviceMetrics.yMax-prface->DeviceMetrics.yMin) * 2 * 16;
  1229. if (leadingSidebearing)
  1230. {
  1231. // Determine largest overhang to left of string of any glyph
  1232. // in the string.
  1233. //
  1234. // We assume that no overhang exceeds approx 2 ems.
  1235. //
  1236. // NOTE: If you make a change to for leadingsizdebeating, also fix
  1237. // trailingsidebearing below.
  1238. INT offset28p4 = 0;
  1239. INT sidebearing28p4 = maxSupportedSidebearing28p4;
  1240. INT i = 0;
  1241. while ( i < glyphCount
  1242. && offset28p4 < maxSupportedSidebearing28p4)
  1243. {
  1244. INT glyphSidebearing28p4;
  1245. if (reverse)
  1246. {
  1247. glyphSidebearing28p4 = glyphDataArray[glyphs[i]]
  1248. ->GlyphMetrics[orientation]
  1249. .TrailingSidebearing;
  1250. }
  1251. else
  1252. {
  1253. glyphSidebearing28p4 = glyphDataArray[glyphs[i]]
  1254. ->GlyphMetrics[orientation]
  1255. .LeadingSidebearing;
  1256. }
  1257. if (glyphSidebearing28p4 + offset28p4 < sidebearing28p4)
  1258. {
  1259. sidebearing28p4 = glyphSidebearing28p4+offset28p4;
  1260. }
  1261. offset28p4 += glyphDataArray[glyphs[i]]
  1262. ->GlyphMetrics[orientation]
  1263. .AdvanceWidth;
  1264. i++;
  1265. }
  1266. *leadingSidebearing = sidebearing28p4;
  1267. }
  1268. if (trailingSidebearing)
  1269. {
  1270. INT offset28p4 = 0;
  1271. INT sidebearing28p4 = maxSupportedSidebearing28p4;
  1272. INT i = glyphCount-1;
  1273. while ( i >= 0
  1274. && offset28p4 < maxSupportedSidebearing28p4)
  1275. {
  1276. INT glyphSidebearing28p4;
  1277. if (reverse)
  1278. {
  1279. glyphSidebearing28p4 = glyphDataArray[glyphs[i]]
  1280. ->GlyphMetrics[orientation]
  1281. .LeadingSidebearing;
  1282. }
  1283. else
  1284. {
  1285. glyphSidebearing28p4 = glyphDataArray[glyphs[i]]
  1286. ->GlyphMetrics[orientation]
  1287. .TrailingSidebearing;
  1288. }
  1289. if (glyphSidebearing28p4 + offset28p4 < sidebearing28p4)
  1290. {
  1291. sidebearing28p4 = glyphSidebearing28p4+offset28p4;
  1292. }
  1293. offset28p4 += glyphDataArray[glyphs[i]]
  1294. ->GlyphMetrics[orientation]
  1295. .AdvanceWidth;
  1296. i--;
  1297. }
  1298. *trailingSidebearing = sidebearing28p4;
  1299. }
  1300. return Ok;
  1301. }
  1302. GpStatus
  1303. GpFaceRealization::GetGlyphPath(
  1304. const UINT16 glyphIndice,
  1305. GpGlyphPath **pFontPath,
  1306. PointF *sidewaysOffset
  1307. ) const
  1308. {
  1309. VOID *glyphBuffer, *glyphBits;
  1310. GpStatus status;
  1311. if ((status = IsMetricsCached(glyphIndice, NULL)) != Ok)
  1312. {
  1313. return status;
  1314. }
  1315. if (!InsertGlyphPath(glyphIndice, TRUE))
  1316. return GenericError;
  1317. *pFontPath = prface->GlyphDataArray[glyphIndice]->GlyphPath;
  1318. if (sidewaysOffset)
  1319. {
  1320. // Return sideways offset as REAL
  1321. *sidewaysOffset = prface->GlyphDataArray[glyphIndice]->GlyphMetrics[1].Origin;
  1322. }
  1323. return Ok;
  1324. }
  1325. INT GpFaceRealization::GetGlyphPos(
  1326. const INT cGlyphs, // How many glyphs Client want to request
  1327. const UINT16 *glyphs, // An array of glyph index
  1328. GpGlyphPos *pgpos, // An array of GLYPHPOS
  1329. const PointF *glyphOrigins, // X,Y positions for sub-pixel calculation
  1330. INT *cParsed, // How many glyphs we parsed
  1331. BOOL sideways // e.g. FE characters in vertical text
  1332. ) const
  1333. {
  1334. INT cgpos = 0;
  1335. BOOL noCache = prface->NoCache;
  1336. BOOL pathFont = IsPathFont();
  1337. *cParsed = 0;
  1338. INT glyphLimit = noCache ? 1 : cGlyphs;
  1339. if (prface->CacheType == CacheAABits)
  1340. {
  1341. /* we could be in noCache mode with a surrogate sequence, doing one glyph at a time
  1342. and with glyphs[0] == EMPTY_GLYPH_FFFF */
  1343. for (INT i=0; (i < cGlyphs) && (cgpos < glyphLimit); i++)
  1344. {
  1345. if (glyphs[i] != EMPTY_GLYPH_FFFF)
  1346. {
  1347. INT x = GpRound(TOREAL(glyphOrigins[i].X * 16.0));
  1348. INT y = GpRound(TOREAL(glyphOrigins[i].Y * 16.0));
  1349. if (!GetAAGlyphDataCached(glyphs[i], pgpos+cgpos, i==0, x, y, sideways))
  1350. {
  1351. break;
  1352. }
  1353. cgpos++;
  1354. }
  1355. (*cParsed)++;
  1356. }
  1357. }
  1358. else
  1359. {
  1360. ASSERT(prface->realizationMethod != TextRenderingHintAntiAlias);
  1361. /* we could be in noCache mode with a surrogate sequence, doing one glyph at a time
  1362. and with glyphs[0] == EMPTY_GLYPH_FFFF */
  1363. for (INT i=0; (i < cGlyphs) && (cgpos < glyphLimit); i++)
  1364. {
  1365. if (glyphs[i] != EMPTY_GLYPH_FFFF)
  1366. {
  1367. INT x = GpRound(TOREAL(glyphOrigins[i].X * 16.0));
  1368. INT y = GpRound(TOREAL(glyphOrigins[i].Y * 16.0));
  1369. GpGlyphData *pgd = NULL;
  1370. if (noCache)
  1371. {
  1372. pgd = GetGlyphDataLookaside(glyphs[i]);
  1373. }
  1374. else
  1375. {
  1376. pgd = GetGlyphDataCached(glyphs[i], i==0);
  1377. }
  1378. if (!pgd || !pgd->GlyphBits)
  1379. {
  1380. // No more glyph data available. (Cache may be full)
  1381. break;
  1382. }
  1383. if (pathFont)
  1384. {
  1385. INT left = (x+8) >> 4;
  1386. INT top = (y+8) >> 4;
  1387. if (sideways)
  1388. {
  1389. left -= GpRound(pgd->GlyphMetrics[1].Origin.X);
  1390. top -= GpRound(pgd->GlyphMetrics[1].Origin.Y);
  1391. }
  1392. pgpos[cgpos].SetLeft (left);
  1393. pgpos[cgpos].SetTop (top);
  1394. pgpos[cgpos].SetWidth (1);
  1395. pgpos[cgpos].SetHeight(1);
  1396. pgpos[cgpos].SetPath(pgd->GlyphPath);
  1397. }
  1398. else
  1399. {
  1400. if (sideways)
  1401. {
  1402. pgpos[cgpos].SetLeft(pgd->GlyphBits->ptlSidewaysOrigin.x + ((x + 8)>>4));
  1403. pgpos[cgpos].SetTop (pgd->GlyphBits->ptlSidewaysOrigin.y + ((y + 8)>>4));
  1404. }
  1405. else
  1406. {
  1407. pgpos[cgpos].SetLeft(pgd->GlyphBits->ptlUprightOrigin.x + ((x + 8)>>4));
  1408. pgpos[cgpos].SetTop (pgd->GlyphBits->ptlUprightOrigin.y + ((y + 8)>>4));
  1409. }
  1410. pgpos[cgpos].SetWidth (pgd->GlyphBits->sizlBitmap.cx);
  1411. pgpos[cgpos].SetHeight(pgd->GlyphBits->sizlBitmap.cy);
  1412. pgpos[cgpos].SetBits(pgd->GlyphBits->aj);
  1413. }
  1414. cgpos++;
  1415. }
  1416. (*cParsed)++;
  1417. }
  1418. }
  1419. return cgpos;
  1420. }
  1421. // Serch the glyph data from cache array.
  1422. GpGlyphData *
  1423. GpFaceRealization::GetGlyphDataCached(
  1424. UINT16 glyphIndex,
  1425. BOOL allowFlush
  1426. ) const
  1427. {
  1428. VOID *glyphBuffer, *glyphBits;
  1429. ULONG cjNeeded = 0;
  1430. GpStatus status;
  1431. if ((status = IsMetricsCached(glyphIndex, &cjNeeded)) != Ok)
  1432. {
  1433. return NULL;
  1434. }
  1435. if (IsPathFont())
  1436. {
  1437. if (!InsertGlyphPath(glyphIndex, allowFlush))
  1438. return NULL;
  1439. }
  1440. else
  1441. {
  1442. if (!InsertGlyphBits(glyphIndex, cjNeeded, allowFlush))
  1443. return NULL;
  1444. }
  1445. ASSERT(prface->GlyphDataArray[glyphIndex]);
  1446. if (!prface->GlyphDataArray[glyphIndex])
  1447. return NULL;
  1448. return prface->GlyphDataArray[glyphIndex];
  1449. }
  1450. BOOL
  1451. GpFaceRealization::GetAAGlyphDataCached(
  1452. UINT16 glyphIndex,
  1453. GpGlyphPos * pgpos,
  1454. BOOL bFlushOk,
  1455. INT x,
  1456. INT y,
  1457. BOOL sideways // e.g. FE characters in vertical text
  1458. ) const
  1459. {
  1460. const GpFaceRealization * pfaceRealization = this;
  1461. UINT xsubPos = ((UINT) (((x+1) & 0x0000000F) >> 1));
  1462. // we need to be carefull that y axis is downwards
  1463. UINT ysubPos = ((UINT) (7 - (((y+1) & 0x0000000F) >> 1)));
  1464. // limit the subpixel position to 1/4 of a pixel to have only a maximum of 16 different bitmaps to cache
  1465. xsubPos = xsubPos & 0x6;
  1466. ysubPos = ysubPos & 0x6;
  1467. if (LimitSubpixel)
  1468. {
  1469. // Now limit the subpixel position further so that large font sizes do
  1470. // not generate all 16 subpixel glyphs!
  1471. if ((prface->DeviceMetrics.yMax-prface->DeviceMetrics.yMin) > 50)
  1472. {
  1473. // Force to 4 possible values...
  1474. xsubPos &= 0x4;
  1475. ysubPos &= 0x4;
  1476. if ((prface->DeviceMetrics.yMax-prface->DeviceMetrics.yMin) > 100)
  1477. {
  1478. // Force to 1 possible value...
  1479. xsubPos = 0x4;
  1480. ysubPos = 0x4;
  1481. }
  1482. }
  1483. }
  1484. ASSERT(!pfaceRealization->IsPathFont())
  1485. // Look to see if there is room in the glyphbits cache
  1486. // Grow the glyphbits cache if neccessary, but don't flush the cache
  1487. ULONG subPosX;
  1488. if (xsubPos <= 7)
  1489. subPosX = xsubPos << 13;
  1490. else
  1491. subPosX = 0;
  1492. ULONG subPosY;
  1493. if (ysubPos)
  1494. subPosY = ysubPos << 13;
  1495. else
  1496. subPosY = 0;
  1497. // If max glyph will fit, assume max glyph
  1498. // otherwise, call up and ask how big
  1499. ASSERT (pfaceRealization->QueryFontDataMode() == QFD_TT_GRAY4_BITMAP ||
  1500. pfaceRealization->QueryFontDataMode() == QFD_GLYPHANDBITMAP_SUBPIXEL);
  1501. if (IsMetricsCached(glyphIndex, 0) != Ok)
  1502. return FALSE;
  1503. GpGlyphData * glyphData = prface->GlyphDataArray[glyphIndex];
  1504. ASSERT(glyphData);
  1505. // check if we already have a bitmap for this subposition
  1506. for (GpGlyphAABits * cur = glyphData->GlyphAABits; cur != 0; cur = cur->Next)
  1507. {
  1508. if (cur->X == subPosX && cur->Y == subPosY)
  1509. break;
  1510. }
  1511. GLYPHBITS * pgb = 0;
  1512. if (cur)
  1513. pgb = reinterpret_cast<GLYPHBITS *>(&cur->Bits);
  1514. else
  1515. {
  1516. ULONG cjNeeded = ttfdSemQueryFontDataSubPos(
  1517. &prface->fobj,
  1518. prface->QueryFontDataMode,
  1519. glyphIndex,
  1520. 0,
  1521. NULL,
  1522. subPosX,
  1523. subPosY
  1524. );
  1525. if (cjNeeded == FD_ERROR)
  1526. return FALSE;
  1527. ASSERT(cjNeeded != 0);
  1528. cjNeeded += offsetof(GpGlyphAABits, Bits);
  1529. if (prface->NoCache)
  1530. {
  1531. if (prface->LookasideByteCount < cjNeeded)
  1532. {
  1533. GpFree(prface->LookasideGlyphData);
  1534. prface->LookasideGlyphData = (GpGlyphData *)GpMalloc(cjNeeded);
  1535. if (!prface->LookasideGlyphData)
  1536. return FALSE;
  1537. prface->LookasideByteCount = cjNeeded;
  1538. }
  1539. cur = reinterpret_cast<GpGlyphAABits *>(prface->LookasideGlyphData);
  1540. }
  1541. else
  1542. {
  1543. // Now, we try to fit the bits in. If they fit, fine.
  1544. // If not, and we can flush the cache, we flush it and try again.
  1545. // If we couldn't flush, or we flushed and still fail, just return.
  1546. cjNeeded = ALIGN(void*, cjNeeded);
  1547. // a GpGlyphAABits * needs to be aligned to the next valid pointer address
  1548. ALIGN(void*, prface->UsedBytesGlyphBitsBlockUnderConstruction);
  1549. while ((cur = (GpGlyphAABits *)pgbCheckGlyphCache(cjNeeded)) == NULL)
  1550. {
  1551. if ( !bFlushOk )
  1552. return FALSE;
  1553. FlushCache();
  1554. bFlushOk = FALSE;
  1555. }
  1556. prface->UsedBytesGlyphBitsBlockUnderConstruction += cjNeeded;
  1557. }
  1558. pgb = reinterpret_cast<GLYPHBITS *>(&cur->Bits);
  1559. cjNeeded = ttfdSemQueryFontDataSubPos(
  1560. pfaceRealization->pfo(),
  1561. pfaceRealization->QueryFontDataMode(),
  1562. glyphIndex,
  1563. 0,
  1564. pgb,
  1565. subPosX,
  1566. subPosY
  1567. );
  1568. if (cjNeeded == FD_ERROR)
  1569. return FALSE;
  1570. cur->X = subPosX;
  1571. cur->Y = subPosY;
  1572. if (!prface->NoCache)
  1573. cur->Next = glyphData->GlyphAABits, glyphData->GlyphAABits = cur;
  1574. }
  1575. // the pixel origin is computed by rouding the real origin minus the subpixel position
  1576. // to get to the placement of the origin of the bitmap, we add to that origin
  1577. // we cast (xsubPos << 1) and (ysubPos << 1) to INT to avoid
  1578. // converting possibly negative x and y to UINTs
  1579. if (sideways)
  1580. {
  1581. pgpos->SetLeft (pgb->ptlSidewaysOrigin.x + ((x - (INT)(xsubPos << 1) + 8 ) >> 4));
  1582. // we need to be careful that the y axis go downwards
  1583. pgpos->SetTop (pgb->ptlSidewaysOrigin.y + ((y + (INT)(ysubPos << 1) + 8) >> 4));
  1584. }
  1585. else
  1586. {
  1587. pgpos->SetLeft (pgb->ptlUprightOrigin.x + ((x - (INT)(xsubPos << 1) + 8 ) >> 4));
  1588. // we need to be careful that the y axis go downwards
  1589. pgpos->SetTop (pgb->ptlUprightOrigin.y + ((y + (INT)(ysubPos << 1) + 8) >> 4));
  1590. }
  1591. pgpos->SetWidth (pgb->sizlBitmap.cx);
  1592. pgpos->SetHeight(pgb->sizlBitmap.cy);
  1593. pgpos->SetBits(pgb->aj);
  1594. return TRUE;
  1595. } // GpFaceRealization::GetAAGlyphDataCached
  1596. GpCacheFaceRealizationList::~GpCacheFaceRealizationList()
  1597. {
  1598. // elements in that list get released when the font table get released
  1599. ASSERT(count == 0);
  1600. }
  1601. void GpCacheFaceRealizationList::AddMostRecent(CacheFaceRealization *prface)
  1602. {
  1603. count ++;
  1604. if (head != NULL)
  1605. {
  1606. prface->NextRecentCacheFaceRealization = head;
  1607. prface->PreviousRecentCacheFaceRealization = head->PreviousRecentCacheFaceRealization;
  1608. prface->PreviousRecentCacheFaceRealization->NextRecentCacheFaceRealization = prface;
  1609. head->PreviousRecentCacheFaceRealization = prface;
  1610. }
  1611. else
  1612. {
  1613. prface->NextRecentCacheFaceRealization = prface;
  1614. prface->PreviousRecentCacheFaceRealization = prface;
  1615. }
  1616. head = prface;
  1617. }
  1618. void GpCacheFaceRealizationList::RemoveFace(CacheFaceRealization *prface)
  1619. {
  1620. if ((prface->PreviousRecentCacheFaceRealization != NULL) && (prface->NextRecentCacheFaceRealization != NULL))
  1621. {
  1622. if (prface->PreviousRecentCacheFaceRealization == prface)
  1623. {
  1624. head = NULL;
  1625. }
  1626. else
  1627. {
  1628. prface->PreviousRecentCacheFaceRealization->NextRecentCacheFaceRealization = prface->NextRecentCacheFaceRealization;
  1629. prface->NextRecentCacheFaceRealization->PreviousRecentCacheFaceRealization = prface->PreviousRecentCacheFaceRealization;
  1630. if (head == prface)
  1631. {
  1632. head = prface->NextRecentCacheFaceRealization;
  1633. }
  1634. }
  1635. prface->PreviousRecentCacheFaceRealization = NULL;
  1636. prface->NextRecentCacheFaceRealization = NULL;
  1637. count --;
  1638. ASSERT(count >= 0);
  1639. }
  1640. }
  1641. CacheFaceRealization *GpCacheFaceRealizationList::ReuseLeastRecent (void)
  1642. {
  1643. CacheFaceRealization *prface = NULL;
  1644. CacheFaceRealization *prfaceList;
  1645. if (head != NULL)
  1646. {
  1647. prface = head->PreviousRecentCacheFaceRealization;
  1648. }
  1649. ASSERT(prface);
  1650. // remove prface from GpCacheFaceRealizationList
  1651. if (head == prface)
  1652. {
  1653. ASSERT(count == 1);
  1654. head = NULL;
  1655. }
  1656. else
  1657. {
  1658. prface->PreviousRecentCacheFaceRealization->NextRecentCacheFaceRealization = head;
  1659. head->PreviousRecentCacheFaceRealization = prface->PreviousRecentCacheFaceRealization;
  1660. }
  1661. count--;
  1662. if (prface != NULL)
  1663. {
  1664. GpFaceRealizationTMP rface(prface);
  1665. rface.ReuseRealizedFace();
  1666. // remove the face from the face list
  1667. prfaceList = prface->Face->pff->prfaceList;
  1668. ASSERT(prfaceList);
  1669. if ((prfaceList == prface) && (prfaceList->NextCacheFaceRealization == prface))
  1670. {
  1671. // there is only oine face in the faceList for that font face
  1672. prface->Face->pff->prfaceList = NULL;
  1673. } else
  1674. {
  1675. if (prfaceList == prface)
  1676. {
  1677. // set the beginning of the list to the next one
  1678. prface->Face->pff->prfaceList = prfaceList->NextCacheFaceRealization;
  1679. }
  1680. // update the pointers in the faceList
  1681. prface->PreviousCacheFaceRealization->NextCacheFaceRealization = prface->NextCacheFaceRealization;
  1682. prface->NextCacheFaceRealization->PreviousCacheFaceRealization = prface->PreviousCacheFaceRealization;
  1683. }
  1684. }
  1685. return prface;
  1686. }