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.

872 lines
22 KiB

  1. /**************************************************************************\
  2. *
  3. * Copyright (c) 1999 Microsoft Corporation
  4. *
  5. * Abstract:
  6. *
  7. * Font table operations
  8. *
  9. * Revision History:
  10. *
  11. * 23/06/1999 cameronb
  12. * Created it.
  13. *
  14. \**************************************************************************/
  15. #include "precomp.hpp"
  16. /**************************************************************************\
  17. Windows 9x compatibility:
  18. const WCHAR* strW;
  19. if (Globals::IsNT)
  20. {
  21. FunctionW(strW);
  22. }
  23. else
  24. {
  25. AnsiStrFromUnicode strA(strW);
  26. FunctionA(strA);
  27. }
  28. \**************************************************************************/
  29. /**************************************************************************\
  30. *
  31. * Function Description:
  32. *
  33. * Constructs a GpFontTable object
  34. *
  35. * Arguments:
  36. *
  37. * none
  38. *
  39. * Returns:
  40. *
  41. * nothing
  42. *
  43. * History:
  44. *
  45. * 23/06/1999 cameronb
  46. * Created it.
  47. *
  48. \**************************************************************************/
  49. GpFontTable::GpFontTable() : NumFilesLoaded(0), NumHashEntries(61), Table(NULL), EnumList(NULL)
  50. {
  51. Table = new GpFontFile *[NumHashEntries];
  52. if (Table != NULL)
  53. {
  54. GpMemset(Table, 0, sizeof(GpFontFile *) * NumHashEntries);
  55. EnumList = new GpFontFamilyList();
  56. }
  57. bPrivate = FALSE;
  58. bFontFilesLoaded = FALSE;
  59. }
  60. /**************************************************************************\
  61. *
  62. * Function Description:
  63. *
  64. * Destroys a GpFontTable object
  65. *
  66. * Arguments:
  67. *
  68. * none
  69. *
  70. * Returns:
  71. *
  72. * nothing
  73. *
  74. * History:
  75. *
  76. * 23/06/1999 cameronb
  77. * Created it.
  78. *
  79. \**************************************************************************/
  80. GpFontTable::~GpFontTable()
  81. {
  82. if (EnumList)
  83. {
  84. delete EnumList;
  85. }
  86. if (Table)
  87. {
  88. for (UINT h = 0; h < NumHashEntries; h++)
  89. {
  90. if (Table[h] != NULL)
  91. {
  92. UnloadFontFiles(Table[h]);
  93. }
  94. }
  95. delete [] Table;
  96. }
  97. }
  98. BOOL GpFontTable::UnloadFontFiles(GpFontFile* fontFile)
  99. {
  100. if (fontFile->GetNext() != NULL)
  101. {
  102. UnloadFontFiles(fontFile->GetNext());
  103. }
  104. CacheFaceRealization *prface = fontFile->prfaceList;
  105. while(prface)
  106. {
  107. GpFaceRealizationTMP rface(prface);
  108. // specially for the case of font added and removed from a private font collection, we need to remove it from the
  109. // last recently used list
  110. Globals::FontCacheLastRecentlyUsedList->RemoveFace(prface);
  111. prface = (prface->NextCacheFaceRealization == fontFile->prfaceList) ? NULL : prface->NextCacheFaceRealization;
  112. rface.DeleteRealizedFace();
  113. }
  114. ttfdSemUnloadFontFile(fontFile->hff);
  115. // Free objects allocated by text support
  116. for (UINT i=0; i<fontFile->GetNumEntries(); i++)
  117. {
  118. fontFile->GetFontFace(i)->FreeImagerTables();
  119. }
  120. if (fontFile->pfv != NULL)
  121. {
  122. if (fontFile->pfv->pwszPath == NULL) // memory image
  123. GpFree(fontFile->pfv->pvView);
  124. GpFree(fontFile->pfv);
  125. }
  126. GpFree(fontFile);
  127. return TRUE;
  128. }
  129. /**************************************************************************\
  130. *
  131. * Function Description:
  132. *
  133. * Load all the fonts from cache or the registry to the font table
  134. *
  135. *
  136. * History:
  137. *
  138. * 11/12/1999 yungt created it.
  139. *
  140. \**************************************************************************/
  141. void GpFontTable::LoadAllFonts(const WCHAR *familyName)
  142. {
  143. InitFontFileCache();
  144. if (GetFontFileCacheState() & FONT_CACHE_LOOKUP_MODE)
  145. {
  146. // Do the fast way to load all the fonts, we will be no need to touch any registry
  147. // and font file.
  148. LoadAllFontsFromCache(FontFileCacheReadRegistry());
  149. }
  150. else
  151. {
  152. // We do need to load the fonts from registry also we need to
  153. if (GetFontFileCacheState() & FONT_CACHE_CREATE_MODE)
  154. {
  155. LoadAllFontsFromRegistry(TRUE);
  156. }
  157. else
  158. {
  159. LoadAllFontsFromRegistry(FALSE);
  160. }
  161. }
  162. vCloseFontFileCache();
  163. }
  164. /**************************************************************************\
  165. *
  166. * Function Description:
  167. *
  168. * Adds a font from the font table
  169. *
  170. * Arguments:
  171. *
  172. * str: name of font to be added
  173. *
  174. * Returns:
  175. *
  176. * GpFontFile *: It will not be NULL if succeeded
  177. *
  178. * History:
  179. *
  180. * 28/06/YungT cameronb
  181. * Created it.
  182. *
  183. \**************************************************************************/
  184. GpFontFile * GpFontTable::AddFontFile(WCHAR* fileName)
  185. {
  186. // This rountine is called from GpFontFamily which we have load the family from cache
  187. // We need to load the font file now if it is being used.
  188. GpFontFile* fontFile = NULL;
  189. UINT hash = HashIt(fileName);
  190. {
  191. fontFile = GetFontFile(fileName, hash);
  192. if (fontFile != NULL)
  193. {
  194. // font exists in the table
  195. fontFile->cLoaded++;
  196. }
  197. else
  198. {
  199. if ((fontFile = LoadFontFile(fileName)) == NULL)
  200. {
  201. return NULL;
  202. }
  203. // Add to the head of the appropriate hash list (hash bucket)
  204. fontFile->SetPrev(NULL);
  205. fontFile->SetNext(Table[hash]);
  206. if (Table[hash] != NULL)
  207. Table[hash]->SetPrev(fontFile);
  208. Table[hash] = fontFile;
  209. // loop over pfe's, init the data:
  210. GpFontFace * face = (GpFontFace *)fontFile->aulData;
  211. for (ULONG iFont = 0; iFont < fontFile->cFonts; iFont++)
  212. {
  213. face[iFont].SetPrivate(bPrivate);
  214. }
  215. // Add to the emuneration list
  216. NumFilesLoaded++;
  217. }
  218. }
  219. return fontFile;
  220. }
  221. /**************************************************************************\
  222. *
  223. * Function Description:
  224. *
  225. * Adds a font from the font table
  226. *
  227. * Arguments:
  228. *
  229. * str: name of font to be added
  230. *
  231. * Returns:
  232. *
  233. * BOOL: indicating success
  234. *
  235. * History:
  236. *
  237. * 23/06/1999 cameronb
  238. * Created it.
  239. *
  240. \**************************************************************************/
  241. GpStatus GpFontTable::AddFontFile(const WCHAR* fileName,
  242. GpFontCollection *fontCollection)
  243. {
  244. WCHAR awcPath[MAX_PATH];
  245. GpStatus status = Ok;
  246. if (!MakePathName(awcPath, const_cast<WCHAR *>(fileName)))
  247. return FileNotFound;
  248. // Determine whether font is already in the table
  249. UnicodeStringToUpper (awcPath, awcPath);
  250. UINT hash = HashIt(awcPath);
  251. {
  252. GpFontFile* fontFile = GetFontFile(awcPath, hash);
  253. if (fontFile != NULL)
  254. {
  255. // font exists in the table
  256. fontFile->cLoaded++;
  257. }
  258. else
  259. {
  260. if ((fontFile = LoadFontFile(awcPath)) == NULL)
  261. {
  262. return FileNotFound;
  263. }
  264. // Add to the head of the appropriate hash list (hash bucket)
  265. fontFile->SetPrev(NULL);
  266. fontFile->SetNext(Table[hash]);
  267. if (Table[hash] != NULL)
  268. Table[hash]->SetPrev(fontFile);
  269. Table[hash] = fontFile;
  270. // loop over pfe's, init the data:
  271. GpFontFace * face = (GpFontFace *)fontFile->aulData;
  272. for (ULONG iFont = 0; iFont < fontFile->cFonts; iFont++)
  273. {
  274. face[iFont].SetPrivate(bPrivate);
  275. }
  276. // Add to the emuneration list
  277. if (!EnumList->AddFont(fontFile, fontCollection))
  278. return OutOfMemory;
  279. NumFilesLoaded++;
  280. }
  281. }
  282. return Ok;
  283. }
  284. /************************************************************\
  285. *
  286. * Function Description:
  287. *
  288. * Adds a font from the memory image
  289. *
  290. *
  291. * History:
  292. *
  293. * Nov/09/1999 Xudong Wu [tessiew]
  294. * Created it.
  295. *
  296. \************************************************************/
  297. ULONG GpFontTable::MemImageUnique = 0;
  298. GpStatus GpFontTable::AddFontMemImage(
  299. const BYTE* fontMemoryImage,
  300. INT fontImageSize,
  301. GpFontCollection *fontCollection
  302. )
  303. {
  304. WCHAR awcPath[MAX_PATH];
  305. UINT hash;
  306. GpFontFile *fontFile;
  307. // generate a "MEMORY xxx" style file name
  308. wsprintfW(awcPath, L"MEMORY-%u", GetNewMemImageUniqueness(GpFontTable::MemImageUnique));
  309. UnicodeStringToUpper (awcPath, awcPath);
  310. hash = HashIt(awcPath);
  311. fontFile = LoadFontMemImage(awcPath, const_cast<BYTE *>(fontMemoryImage), fontImageSize);
  312. if (fontFile == NULL) // unable to load font
  313. {
  314. return FileNotFound;
  315. }
  316. // Add to the head of the appropriate hash list (hash bucket)
  317. fontFile->SetNext(Table[hash]);
  318. if (Table[hash] != NULL)
  319. Table[hash]->SetPrev(fontFile);
  320. Table[hash] = fontFile;
  321. // Add to the emuneration list
  322. if (!EnumList->AddFont(fontFile, fontCollection))
  323. return OutOfMemory;
  324. NumFilesLoaded++;
  325. return Ok;
  326. }
  327. /**************************************************************************\
  328. *
  329. * Function Description:
  330. *
  331. * Searched the font table for the any font
  332. *
  333. * Arguments:
  334. *
  335. *
  336. * Returns:
  337. *
  338. * GpFontFamily *: pointer to font file if found, else NULL
  339. *
  340. * History:
  341. *
  342. * 7/15/2000 YungT
  343. * Created it.
  344. *
  345. \**************************************************************************/
  346. GpFontFamily* GpFontTable::GetAnyFamily()
  347. {
  348. return EnumList->GetAnyFamily();
  349. }
  350. /**************************************************************************\
  351. *
  352. * Function Description:
  353. *
  354. * Searched the font table for the specified font
  355. *
  356. * Arguments:
  357. *
  358. * fileName: name of font to be removed
  359. * hash: its hash value
  360. *
  361. * Returns:
  362. *
  363. * GpFontFile*: pointer to font file if found, else NULL
  364. *
  365. * History:
  366. *
  367. * 23/06/1999 cameronb
  368. * Created it.
  369. *
  370. \**************************************************************************/
  371. GpFontFamily* GpFontTable::GetFontFamily(const WCHAR* familyName)
  372. {
  373. return EnumList->GetFamily(familyName);
  374. }
  375. /**************************************************************************\
  376. *
  377. * Function Description:
  378. *
  379. * Removes a font from the font table.
  380. *
  381. * Note: If the ref count of any of the PFEs in the font file is greater
  382. * than zero, then we do not delete the font file entry in the font table.
  383. * However, the bRemoved flag is set in this function. So, in the case when
  384. * a ref count decrement could cause a font file to be removed, the caller
  385. * should first test bRemoved before calling this function.
  386. *
  387. * History:
  388. *
  389. * Nov/28/1999 Xudong Wu [tessiew]
  390. * Created it.
  391. *
  392. \**************************************************************************/
  393. GpStatus GpFontTable::RemoveFontFile(const WCHAR* fontFileName)
  394. {
  395. WCHAR awcPath[MAX_PATH];
  396. GpFontFile *fontFile = NULL;
  397. if (!MakePathName(awcPath, const_cast<WCHAR *>(fontFileName)))
  398. return GenericError;
  399. UnicodeStringToUpper (awcPath, awcPath);
  400. UINT hash = HashIt(awcPath);
  401. GpFontFile *ff = Table[hash];
  402. while(ff && !fontFile)
  403. {
  404. if ( UnicodeStringCompare(awcPath, ff->pwszPathname_) == 0 )
  405. {
  406. fontFile = ff;
  407. }
  408. ff = ff->GetNext();
  409. }
  410. if (fontFile)
  411. {
  412. fontFile->bRemoved = TRUE;
  413. if (fontFile->cLoaded)
  414. {
  415. fontFile->cLoaded--;
  416. }
  417. // see if any of the PFEs have a ref count on them
  418. BOOL bFontFamilyRef = TRUE;
  419. for (UINT iFont = 0; iFont < fontFile->cFonts; iFont++)
  420. {
  421. GpFontFace *pfe = &(((GpFontFace *) &(fontFile->aulData))[iFont]);
  422. if (pfe->cGpFontFamilyRef > 0)
  423. {
  424. bFontFamilyRef = FALSE;
  425. }
  426. }
  427. // ASSERT: if there are no references by any FontFamily to
  428. // any of the PFEs in this object (via GpFontFamily objects),
  429. // then bFontFamilyRef is TRUE. bFontFamilyRef is FALSE otherwise.
  430. if (fontFile->cLoaded == 0 &&
  431. bFontFamilyRef &&
  432. fontFile->prfaceList == NULL)
  433. {
  434. // set the Face pointers of the corresponding FontFamily objects
  435. // to NULL and attempt to remove each font family in the file
  436. for (UINT iFont = 0; iFont < fontFile->cFonts; iFont++)
  437. {
  438. GpFontFamily *gpFontFamily = GetFontFamily(fontFile->GetFamilyName(iFont));
  439. if (gpFontFamily)
  440. {
  441. for (UINT iFace = 0; iFace < NumFontFaces; iFace++)
  442. {
  443. if (gpFontFamily->GetFaceAbsolute(iFace) ==
  444. (&(((GpFontFace *) (&(fontFile->aulData))) [iFont])))
  445. {
  446. gpFontFamily->SetFaceAndFile(iFace, NULL, NULL);
  447. }
  448. }
  449. EnumList->RemoveFontFamily(gpFontFamily);
  450. }
  451. }
  452. // remove GpFontFile from the FontTable
  453. NumFilesLoaded--;
  454. if (fontFile->GetPrev())
  455. fontFile->GetPrev()->SetNext(fontFile->GetNext());
  456. if (fontFile->GetNext())
  457. fontFile->GetNext()->SetPrev(fontFile->GetPrev());
  458. if (fontFile == Table[hash])
  459. Table[hash] = fontFile->GetNext();
  460. ttfdSemUnloadFontFile(fontFile->hff);
  461. // Free objects allocated by text support
  462. for (ULONG i=0; i<fontFile->GetNumEntries(); i++)
  463. {
  464. fontFile->GetFontFace(i)->FreeImagerTables();
  465. }
  466. if (fontFile->pfv != NULL)
  467. {
  468. if (fontFile->pfv->pwszPath == NULL) // memory image
  469. GpFree(fontFile->pfv->pvView);
  470. GpFree(fontFile->pfv);
  471. }
  472. GpFree(fontFile);
  473. return Ok;
  474. }
  475. }
  476. else
  477. {
  478. // couldn't find the font file in the hash table
  479. return GenericError;
  480. }
  481. return Ok;
  482. }
  483. /**************************************************************************\
  484. *
  485. * Function Description:
  486. *
  487. * Counts the number of enumerable fonts in the table
  488. *
  489. * Arguments:
  490. *
  491. *
  492. *
  493. * Returns:
  494. *
  495. * Number of enumerable fonts
  496. *
  497. * History:
  498. *
  499. * 12/07/1999 cameronb
  500. * Created it.
  501. *
  502. \**************************************************************************/
  503. INT GpFontTable::EnumerableFonts(GpGraphics* graphics)
  504. {
  505. return EnumList->Enumerable(graphics);
  506. }
  507. /**************************************************************************\
  508. *
  509. * Function Description:
  510. *
  511. * Enumerates fonts.
  512. *
  513. * First call EnumerableFonts() to determine the number to expect.
  514. *
  515. * Arguments:
  516. *
  517. *
  518. *
  519. * Returns:
  520. *
  521. * Status of the enumeration operation
  522. *
  523. * History:
  524. *
  525. * 12/07/1999 cameronb
  526. * Created it.
  527. *
  528. \**************************************************************************/
  529. GpStatus GpFontTable::EnumerateFonts(
  530. INT numSought,
  531. GpFontFamily* gpfamilies[],
  532. INT& numFound,
  533. GpGraphics* graphics
  534. )
  535. {
  536. GpStatus status = EnumList->Enumerate(numSought, gpfamilies, numFound, graphics);
  537. #if FONTTABLE_DBG
  538. TERSE(("Enumerated font list:"));
  539. EnumList->Dump();
  540. TERSE(("Done."));
  541. #endif
  542. return status;
  543. }
  544. /**************************************************************************\
  545. *
  546. * Function Description:
  547. *
  548. * Returns a pseudorandom hash value for a given string
  549. *
  550. * Arguments:
  551. *
  552. * str: string to be hashed
  553. *
  554. * Returns:
  555. *
  556. * UINT: hash value for str
  557. *
  558. * Note: All strings must be capitalized! *
  559. * *
  560. * History:
  561. *
  562. * 23/06/1999 cameronb
  563. * Created it.
  564. * History: *
  565. * Wed 07-Sep-1994 08:12:22 by Kirk Olynyk [kirko] *
  566. * Since chuck is gone the mice are free to play. So I have replaced *
  567. * it with my own variety. Tests show that this one is better. Of *
  568. * course, once I have gone someone will replace mine. By the way, *
  569. * just adding the letters and adding produces bad distributions. *
  570. * Tue 15-Dec-1992 03:13:15 -by- Charles Whitmer [chuckwh] *
  571. * Wrote it. It looks crazy, but I claim there's a theory behind it. *
  572. *
  573. \**************************************************************************/
  574. UINT GpFontTable::HashIt(const WCHAR* str) const
  575. {
  576. UINT result = 0;
  577. //ASSERT(NumHashEntries != 0);
  578. while (*str)
  579. {
  580. // use the lower byte since that is where most of the
  581. // interesting stuff happens
  582. //result += 256 * result + (UCHAR)towupper(*str++);
  583. result += 256 * result + (UCHAR)*str++;
  584. }
  585. return result % NumHashEntries;
  586. }
  587. GpFontFile* GpFontTable::GetFontFile(const WCHAR* fileName) const
  588. {
  589. WCHAR fileNameCopy[MAX_PATH];
  590. UnicodeStringToUpper (fileNameCopy, const_cast<WCHAR *>(fileName));
  591. UINT hash = HashIt(fileNameCopy);
  592. return GetFontFile(fileNameCopy, hash);
  593. }
  594. GpFontFile* GpFontTable::GetFontFile(const WCHAR* fileName, UINT hash) const
  595. {
  596. for (GpFontFile* ff = Table[hash]; ff != NULL; ff = ff->GetNext())
  597. if (UnicodeStringCompareCI(fileName, ff->GetPathName()) == 0)
  598. {
  599. return ff;
  600. }
  601. return NULL;
  602. }
  603. /**************************************************************************\
  604. *
  605. * Function Description:
  606. *
  607. * Adds fonts from the cache file to the font table
  608. *
  609. * Arguments:
  610. *
  611. * Returns:
  612. *
  613. * nothing
  614. *
  615. * History:
  616. *
  617. * 6/21/2000 YungT
  618. * Created it.
  619. *
  620. \**************************************************************************/
  621. void GpFontTable::LoadAllFontsFromCache(BOOL bLoadFromRegistry)
  622. {
  623. if (!EnumList->BuildFamilyListFromCache(bLoadFromRegistry))
  624. {
  625. LoadAllFontsFromRegistry(FALSE);
  626. }
  627. else
  628. {
  629. bFontFilesLoaded = TRUE;
  630. }
  631. return ;
  632. }
  633. /**************************************************************************\
  634. *
  635. * Function Description:
  636. *
  637. * Adds fonts from the registry to the font table
  638. *
  639. * Arguments:
  640. *
  641. * numExpected: number of fonts expected in the registry. This includes
  642. * *.FON files which the TT font driver will not load.
  643. *
  644. * Returns:
  645. *
  646. * nothing
  647. *
  648. * History:
  649. *
  650. * 23/06/1999 cameronb
  651. * Created it.
  652. *
  653. \**************************************************************************/
  654. void GpFontTable::LoadAllFontsFromRegistry(BOOL bUpdateCache)
  655. {
  656. ULONG numExpected;
  657. // Open the key
  658. HKEY hkey;
  659. LONG error = (Globals::IsNt) ? RegOpenKeyExW(HKEY_LOCAL_MACHINE, Globals::FontsKeyW, 0, KEY_QUERY_VALUE, &hkey)
  660. : RegOpenKeyExA(HKEY_LOCAL_MACHINE, Globals::FontsKeyA, 0, KEY_QUERY_VALUE, &hkey);
  661. if (error == ERROR_SUCCESS)
  662. {
  663. // Must read from the registry in Ascii format for some unfathomable reason
  664. CHAR label[MAX_PATH];
  665. BYTE data[MAX_PATH];
  666. WCHAR labelW[MAX_PATH];
  667. WCHAR fileNameW[MAX_PATH];
  668. // Loop through fonts in registry
  669. // Note:
  670. // Don't make (error != ERROR_NO_MORE_ITEMS) the sole
  671. // terminating condition for this loop. The last entry
  672. // may produce a different type of error.
  673. ULONG index = 0;
  674. ULONG registrySize = 0;
  675. error = RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, &numExpected, NULL, NULL, NULL, NULL);
  676. if (error != ERROR_SUCCESS)
  677. {
  678. numExpected = NumHashEntries << 3;
  679. error = ERROR_SUCCESS;
  680. }
  681. /* we need to add the font Marlett separately since it's hidden and not listed in the registry */
  682. if (AddFontFile(L"Marlett.ttf", NULL) != Ok)
  683. {
  684. VERBOSE(("Error loading font Marlett.ttf.\n"))
  685. }
  686. while (index < numExpected && error != ERROR_NO_MORE_ITEMS)
  687. {
  688. DWORD regType = 0;
  689. DWORD labelSize = MAX_PATH;
  690. DWORD dataSize = MAX_PATH;
  691. DWORD dataSizeW = MAX_PATH * sizeof(WCHAR);
  692. if (Globals::IsNt)
  693. error = RegEnumValueW(hkey, index, labelW, &labelSize, NULL, &regType, (PBYTE) fileNameW, &dataSizeW );
  694. else
  695. error = RegEnumValueA(hkey, index, label, &labelSize, NULL, &regType, data, &dataSize);
  696. if (error == ERROR_NO_MORE_ITEMS)
  697. break;
  698. else if (error != ERROR_SUCCESS)
  699. {
  700. index ++;
  701. //ASSERT
  702. VERBOSE(("Bad RegEnumValueA %d for %s.", error, data))
  703. continue;
  704. }
  705. if (!Globals::IsNt)
  706. {
  707. memset(fileNameW, 0, MAX_PATH * sizeof(WCHAR));
  708. MultiByteToWideChar(CP_ACP, 0, (CHAR*)data, -1, fileNameW, MAX_PATH);
  709. registrySize += dataSize;
  710. }
  711. if (AddFontFile(fileNameW, NULL) != Ok)
  712. {
  713. VERBOSE(("Error loading font %ws.\n", fileNameW))
  714. }
  715. index ++;
  716. }
  717. if (NumFilesLoaded)
  718. {
  719. // loaded all the fonts from reg
  720. if (bUpdateCache)
  721. EnumList->UpdateFamilyListToCache(FontFileCacheReadRegistry(), hkey, registrySize, numExpected);
  722. bFontFilesLoaded = TRUE;
  723. }
  724. RegCloseKey(hkey);
  725. }
  726. }