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.

4322 lines
150 KiB

  1. /******************************Module*Header*******************************\
  2. * Module Name: pftobj.cxx *
  3. * *
  4. * Non-inline methods for physical font table objects. *
  5. * *
  6. * Created: 30-Oct-1990 09:32:48 *
  7. * Author: Gilman Wong [gilmanw] *
  8. * *
  9. * Tue 09-Aug-1994 10:04:09 by Kirk Olynyk [kirko] *
  10. * Prior to build ### there was only a single font table on which all *
  11. * fonts, be they public (engine) or device, where attached. I have *
  12. * changed the font architecture so that there will be two font tables. *
  13. * One for public fonts and the other font device fonts. The public font *
  14. * table will be string based. That is, the fonts were added to this *
  15. * using GreAddFontResourceW() with the name of the associated font file. *
  16. * The name of the font file and path will be hashed and the font files *
  17. * will hang off of the collision list. The number of hash buckets is *
  18. * set at boot time. *
  19. * *
  20. * The device font table will be for device fonts (suprise). *
  21. * In this case the fonts will be placed in hash collisions *
  22. * lists depending upon the value of their hdev. *
  23. * *
  24. * Copyright (c) 1994-1999 Microsoft Corporation *
  25. * *
  26. \**************************************************************************/
  27. #include "precomp.hxx"
  28. extern "C" BOOL bInitFontTables();
  29. extern "C" void vQueryRegistryForNumberOfBuckets(unsigned *, unsigned *);
  30. #pragma alloc_text(INIT, bInitFontTables)
  31. #pragma alloc_text(INIT, vQueryRegistryForNumberOfBuckets)
  32. #define CPRIVATEBUCKETS 20
  33. PFT *gpPFTPublic; // global public font table (for font drivers)
  34. PFT *gpPFTDevice; // global device font table (for printers)
  35. PFT *gpPFTPrivate = PPFTNULL; // global public talbe for private fonts, init as NULL
  36. #ifdef LANGPACK
  37. UINT PFFOBJ::uGlobalUniqueness = 0;
  38. #endif
  39. LARGE_INTEGER PFTOBJ::FontChangeTime; // time of most recent addition or
  40. // removal of a font file
  41. // Definitions for local functions used to remove font files from system.
  42. static RFONT* prfntKillList(PFFOBJ &);
  43. static BOOL bKillRFONTList(PFFOBJ &, RFONT *);
  44. static UINT iHash(const WCHAR *, UINT);
  45. /******************************Public*Routine******************************\
  46. * pAllocateAndInitializePFT *
  47. * *
  48. * Allocates and initializes a font table with cBuckets *
  49. * This allows the public (engine) font table and the device *
  50. * font table to share the same code. *
  51. * *
  52. * input: cBuckets = number of members in allocated PFF* table *
  53. * output: address of new PFT *
  54. * *
  55. * Notes: *
  56. * *
  57. * it is not necessary to check for error in the creation *
  58. * of the hash tables because the system will still work *
  59. * *
  60. * error: return 0 *
  61. * *
  62. * History: *
  63. * Fri 05-Aug-1994 07:41:50 by Kirk Olynyk [kirko] *
  64. * Wrote it. *
  65. \**************************************************************************/
  66. PFT *pAllocateAndInitializePFT(unsigned cBuckets)
  67. {
  68. PFT *pPFT;
  69. register ULONGSIZE_T size = offsetof(PFT, apPFF) + cBuckets * sizeof(PFF*);
  70. if (pPFT = (PFT*) PALLOCMEM(size, 'tfpG'))
  71. {
  72. pPFT->cBuckets = cBuckets;
  73. pPFT->cFiles = 0;
  74. }
  75. return(pPFT);
  76. }
  77. // strings used to identify values stored in the registry
  78. static CONST PWSZ pwszP0 = L"NumberOfPublicFontFilesAtLastLogOff";
  79. static CONST PWSZ pwszP1 = L"NumberOfPublicFontFilesSetByUser";
  80. static CONST PWSZ pwszD0 = L"NumberOfDeviceFontFilesAtLastLogOff";
  81. static CONST PWSZ pwszD1 = L"NumberOfDeviceFontFilesSetByUser";
  82. static CONST PWSZ pwszFC =
  83. L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\FontCache";
  84. // Define some default values in case the registry numbers are bogus
  85. #define MIN_PUBLIC_BUCKETS 100
  86. #define MAX_PUBLIC_BUCKETS 10000
  87. #define MIN_DRIVER_BUCKETS 5
  88. #define MAX_DRIVER_BUCKETS 100
  89. // PIR :== Put In Range
  90. #define PIR(x,a,b) ((x)<(a)?(a):((x)>(b)?(b):(x)))
  91. /******************************Public*Routine******************************\
  92. * vQueryRegistryForNumberOfBuckets
  93. *
  94. * Gets from the registry the number of buckets needed for the public
  95. * and driver font tables.
  96. *
  97. * History:
  98. * Mon 26-Sep-1994 09:59:52 by Kirk Olynyk [kirko]
  99. * Wrote it.
  100. \**************************************************************************/
  101. extern "C" void vQueryRegistryForNumberOfBuckets(
  102. unsigned *puPublic // recieves # buckets for Public fonts
  103. , unsigned *puDevice // recieves # buckets for Device fonts
  104. )
  105. {
  106. RTL_QUERY_REGISTRY_TABLE QueryTable[5];
  107. HANDLE hDevMode;
  108. DWORD Status;
  109. ULONG cPublicBucketsSys = 0;
  110. ULONG cPublicBucketsUser = 0;
  111. ULONG cDeviceBucketsSys = 0;
  112. ULONG cDeviceBucketsUser = 0;
  113. //
  114. // Initialize registry query table.
  115. //
  116. QueryTable[0].QueryRoutine = NULL;
  117. QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
  118. QueryTable[0].Name = L"NumberOfPublicFontFilesAtLastLogOff";
  119. QueryTable[0].EntryContext = &cPublicBucketsSys;
  120. QueryTable[0].DefaultType = REG_NONE;
  121. QueryTable[0].DefaultData = NULL;
  122. QueryTable[0].DefaultLength = 0;
  123. QueryTable[1].QueryRoutine = NULL;
  124. QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
  125. QueryTable[1].Name = L"NumberOfPublicFontFilesSetByUser";
  126. QueryTable[1].EntryContext = &cPublicBucketsUser;
  127. QueryTable[1].DefaultType = REG_NONE;
  128. QueryTable[1].DefaultData = NULL;
  129. QueryTable[1].DefaultLength = 0;
  130. QueryTable[2].QueryRoutine = NULL;
  131. QueryTable[2].Flags = RTL_QUERY_REGISTRY_DIRECT;
  132. QueryTable[2].Name = L"NumberOfDeviceFontFilesAtLastLogOff";
  133. QueryTable[2].EntryContext = &cDeviceBucketsSys;
  134. QueryTable[2].DefaultType = REG_NONE;
  135. QueryTable[2].DefaultData = NULL;
  136. QueryTable[2].DefaultLength = 0;
  137. QueryTable[3].QueryRoutine = NULL;
  138. QueryTable[3].Flags = RTL_QUERY_REGISTRY_DIRECT;
  139. QueryTable[3].Name = L"NumberOfDeviceFontFilesSetByUser";
  140. QueryTable[3].EntryContext = &cDeviceBucketsUser;
  141. QueryTable[3].DefaultType = REG_NONE;
  142. QueryTable[3].DefaultData = NULL;
  143. QueryTable[3].DefaultLength = 0;
  144. QueryTable[4].QueryRoutine = NULL;
  145. QueryTable[4].Flags = 0;
  146. QueryTable[4].Name = NULL;
  147. //
  148. // If the open was succesdsful, then query the registry for the
  149. // specified printer.
  150. //
  151. Status = RtlQueryRegistryValues(RTL_REGISTRY_WINDOWS_NT,
  152. L"FontCache",
  153. &QueryTable[0],
  154. NULL,
  155. NULL);
  156. if (!NT_SUCCESS(Status))
  157. {
  158. WARNING1("vQueryRegistryForNumberOfBuckets failure\n");
  159. }
  160. else
  161. {
  162. if (!cPublicBucketsUser)
  163. {
  164. cPublicBucketsUser = cPublicBucketsSys;
  165. }
  166. if (!cDeviceBucketsUser)
  167. {
  168. cDeviceBucketsUser = cDeviceBucketsSys;
  169. }
  170. }
  171. *puPublic = PIR(cPublicBucketsUser, MIN_PUBLIC_BUCKETS, MAX_PUBLIC_BUCKETS);
  172. *puDevice = PIR(cDeviceBucketsUser, MIN_DRIVER_BUCKETS, MAX_DRIVER_BUCKETS);
  173. }
  174. /******************************Public*Routine******************************\
  175. * BOOL bInitFontTables *
  176. * *
  177. * Create the global public PFT and driver PFT *
  178. * *
  179. * Create the public PFT semaphore to serialize access to both the *
  180. * public and driver font tables and their releated PFF's and PFE's *
  181. * Access to the RFONT's (realized font instances) are regulated *
  182. * by a separate semaphore. *
  183. * *
  184. * History: *
  185. * Fri 05-Aug-1994 07:07:27 by Kirk Olynyk [kirko] *
  186. * Made it allocate both the public and driver font tables. Both *
  187. * allocations and initializations are done by a common routine. *
  188. * 21-Jan-1991 -by- Gilman Wong [gilmanw] *
  189. * Wrote it. *
  190. \**************************************************************************/
  191. extern "C" BOOL bInitFontTables()
  192. {
  193. unsigned cPublicBuckets;
  194. unsigned cDeviceBuckets;
  195. register BOOL bRet = FALSE;
  196. vQueryRegistryForNumberOfBuckets(&cPublicBuckets, &cDeviceBuckets);
  197. if (
  198. bRet = (
  199. (gpPFTPublic = pAllocateAndInitializePFT(cPublicBuckets))
  200. && (gpPFTDevice = pAllocateAndInitializePFT(cDeviceBuckets))
  201. && (ghsemPublicPFT = GreCreateSemaphore())
  202. && (ghsemGlyphSet = GreCreateSemaphore())
  203. && (ghsemPrintKView = GreCreateSemaphore()))
  204. )
  205. {
  206. FHMEMOBJ fhmo1(&gpPFTPublic->pfhFace , FHT_FACE , cPublicBuckets);
  207. FHMEMOBJ fhmo2(&gpPFTPublic->pfhFamily, FHT_FAMILY, cPublicBuckets);
  208. FHMEMOBJ fhmo3(&gpPFTPublic->pfhUFI, FHT_UFI, cPublicBuckets);
  209. }
  210. #if DBG
  211. if (!bRet)
  212. {
  213. if (!gpPFTPublic) WARNING("gpPFTPublic == 0\n");
  214. if (!gpPFTDevice) WARNING("gpPFTDevice == 0\n");
  215. if (!ghsemPublicPFT) WARNING("ghsemPublicPFT == 0\n");
  216. }
  217. #endif
  218. return(bRet);
  219. }
  220. /******************************Public*Routine******************************\
  221. * BOOL bInitPrivatePFT *
  222. * *
  223. * Create the global private PFT *
  224. * *
  225. * Create the semaphore for the private PFT to serialize access *
  226. * to the private PFT and its releated PFF's and PFE's *
  227. * Access to the RFONT's (realized font instances) are regulated *
  228. * by a separate semaphore. *
  229. * *
  230. * History: *
  231. * 10-Aug-1996 -by- Xudong Wu [TessieW] *
  232. * Wrote it. *
  233. \**************************************************************************/
  234. BOOL bInitPrivatePFT()
  235. {
  236. register BOOL bRet = FALSE;
  237. SEMOBJ sem(ghsemPublicPFT);
  238. if (gpPFTPrivate)
  239. return TRUE;
  240. if ( bRet = ((gpPFTPrivate = pAllocateAndInitializePFT(CPRIVATEBUCKETS)) != PPFTNULL ) )
  241. {
  242. FHMEMOBJ fhmo1(&gpPFTPrivate->pfhFace , FHT_FACE , CPRIVATEBUCKETS);
  243. FHMEMOBJ fhmo2(&gpPFTPrivate->pfhFamily, FHT_FAMILY, CPRIVATEBUCKETS);
  244. FHMEMOBJ fhmo3(&gpPFTPrivate->pfhUFI, FHT_UFI, CPRIVATEBUCKETS);
  245. }
  246. #if DBG
  247. if (!bRet)
  248. {
  249. if (!gpPFTPrivate) WARNING("gpPFTPrivate== 0\n");
  250. }
  251. #endif
  252. return(bRet);
  253. }
  254. /******************************Public*Routine******************************\
  255. * VOID vCleanupPrivateFonts() *
  256. * *
  257. * Clean up the PFF for the dying process pid *
  258. * *
  259. * History: *
  260. * 01-Oct-1996 -by- Xudong Wu [TessieW] *
  261. * Wrote it. *
  262. \**************************************************************************/
  263. VOID vCleanupPrivateFonts()
  264. {
  265. ULONG i;
  266. PFF *pPFF, **ppPFF, **ppPFFHead;
  267. // We have seen some stress failures on the Hydra system
  268. // that ghsemPublicPFT was not even initialized
  269. if (ghsemPublicPFT)
  270. {
  271. GreAcquireSemaphoreEx(ghsemPublicPFT, SEMORDER_PUBLICPFT, NULL);
  272. PUBLIC_PFTOBJ pftop(gpPFTPrivate);
  273. if (pftop.bValid())
  274. {
  275. //fonts loaded as private
  276. ppPFFHead = gpPFTPrivate->apPFF;
  277. for (i=0; i < CPRIVATEBUCKETS; i++)
  278. {
  279. ppPFF = ppPFFHead;
  280. pPFF = *ppPFFHead;
  281. while ( pPFF )
  282. {
  283. PFF *pPFFNextVictim = pPFF->pPFFNext;
  284. // bUnloadWorkhorse should release ghsemPublicPFT
  285. if ( pftop.bUnloadWorkhorse(pPFF, ppPFF, ghsemPublicPFT, FRW_PVT_CLEANUP) )
  286. {
  287. GreQuerySystemTime( &PFTOBJ::FontChangeTime );
  288. }
  289. pPFF = pPFFNextVictim;
  290. GreAcquireSemaphoreEx(ghsemPublicPFT, SEMORDER_PUBLICPFT, NULL);
  291. }
  292. ppPFFHead++;
  293. }
  294. }
  295. GreReleaseSemaphoreEx(ghsemPublicPFT);
  296. }
  297. }
  298. /******************************Public*Routine******************************\
  299. * BOOL PFTOBJ::bDelete() *
  300. * *
  301. * Destroy the PFT physical font table object. *
  302. * *
  303. * If this method succeeds the pointer to the public font table is *
  304. * set to 0 and then this method returns TRUE. If the table contains *
  305. * any files, then this method will fail and return FALSE. *
  306. * *
  307. * History: *
  308. * 30-Oct-1990 -by- Gilman Wong [gilmanw] *
  309. * Wrote it. *
  310. \**************************************************************************/
  311. BOOL PFTOBJ::bDelete()
  312. {
  313. if (pPFT->cFiles == 0)
  314. {
  315. VFREEMEM(pPFT);
  316. pPFT = 0;
  317. }
  318. else
  319. {
  320. WARNING("gdisrv!bDeletePFTOBJ(): cFiles != 0");
  321. }
  322. return(!pPFT);
  323. }
  324. /******************************Public*Routine******************************\
  325. * PFTOBJ::chpfeIncrPFF *
  326. * *
  327. * If this was an attempt to load a font that was embeded and the *
  328. * client ID didn't match that in the *.fot file FALSE will be *
  329. * return via pbEmbedStatus ortherwise TRUE is returned. *
  330. * *
  331. * If found, the load count of the PFF is incremented. *
  332. * *
  333. * Note: *
  334. * Caller should be holding the ghsemPublicPFT *
  335. * semaphore when calling this routine in order *
  336. * to access the table and load count. *
  337. * *
  338. * Returns: *
  339. * Number of PFEs in the PFF, 0 if PFF not found. *
  340. * *
  341. * History: *
  342. * Fri 05-Aug-1994 13:37:11 by Kirk Olynyk [kirko] *
  343. * The PFF has been found up front and is guaranteed to exist. *
  344. * I have removed the check to see if it is a device font. This check *
  345. * is now redundant because you can tell if it is a device font by the *
  346. * table that you are on. If device fonts cannot be loaded via *
  347. * AddFontResouce, then this function should not be called for a *
  348. * device font. *
  349. * 28-Jun-1991 -by- Gilman Wong [gilmanw] *
  350. * Wrote it. *
  351. \**************************************************************************/
  352. COUNT PFTOBJ::chpfeIncrPFF(
  353. PFF *pPFF, // address of PFF to be, incremented
  354. BOOL *pbEmbedStatus, // tried to load an embeded font illegally
  355. ULONG flEmbed,
  356. PEUDCLOAD pEudcLoadData // PFE's in file if EUDC
  357. )
  358. {
  359. // Caller should be holding ghsemPublicPFT semaphore!
  360. BOOL bEUDC = ( pEudcLoadData != NULL );
  361. COUNT cRet = 0;
  362. PFFOBJ pffo(pPFF);
  363. if (!pffo.bValid())
  364. {
  365. RIP("Invalid PFFOBJ\n");
  366. }
  367. else
  368. {
  369. if ((bEUDC && pffo.bEUDC()) || (!bEUDC && !pffo.bEUDC()) )
  370. {
  371. *pbEmbedStatus = !bIsPrivatePFT() || pffo.bAddPvtData(flEmbed);
  372. if(*pbEmbedStatus)
  373. {
  374. if(bEUDC)
  375. {
  376. if((pEudcLoadData->LinkedFace == NULL) &&
  377. (pffo.cFonts() > 2))
  378. {
  379. // EUDC font file can have at most two fonts (one regular
  380. // and one @) unless the user specifies a face name.
  381. // we return failure by setting embed status to false
  382. *pbEmbedStatus = FALSE;
  383. // return non-zero so calling function returns right away
  384. return(1);
  385. }
  386. pffo.vGetEUDC(pEudcLoadData);
  387. }
  388. if (!bIsPrivatePFT())
  389. {
  390. pffo.vLoadIncr(flEmbed);
  391. }
  392. cRet = pffo.cFonts();
  393. }
  394. else
  395. {
  396. cRet = ~cRet;
  397. ASSERTGDI(cRet,
  398. "cRet should be non zero so calling function"
  399. " will return right away\n");
  400. }
  401. }
  402. }
  403. return(cRet);
  404. }
  405. /******************************Public*Routine******************************\
  406. * PFTOBJ::pPFFGet *
  407. * *
  408. * Note: *
  409. * Caller should be holding the ghsemPublicPFT semaphore when *
  410. * this method calling this in order to guarantee a stable font *
  411. * table. *
  412. * Note that since all the strings in the table are in upper case *
  413. * and the input string must be upper case, we are allowed to *
  414. * compare strings with the faster case sensitive compare *
  415. * wcscmp(). *
  416. * *
  417. * Returns: *
  418. * PPFF of the PFF if found, (PPFF) NULL if the PFF not found. *
  419. * *
  420. * History: *
  421. * Thu 04-Aug-1994 08:18:27 by Kirk Olynyk [kirko] *
  422. * Modified to make the public font table hash based *
  423. * 06-May-1992 -by- Gilman Wong [gilmanw] *
  424. * Wrote it. *
  425. \**************************************************************************/
  426. PPFF PUBLIC_PFTOBJ::pPFFGet (
  427. PWSZ pwszPathname // address of upper case string
  428. , ULONG cwc
  429. , ULONG cFiles
  430. , DESIGNVECTOR *pdv
  431. , ULONG cjDV
  432. , PFF ***pppPFF // write address of bucket here
  433. , BOOL bEUDC // be true if EUDC
  434. )
  435. {
  436. PFF *pPFF, **ppPFF;
  437. // it is enough to hash on the first file only, no need to include the
  438. // second and or third file to the hashing routine [bodind]
  439. ppPFF = pPFT->apPFF + iHash(pwszPathname,pPFT->cBuckets);
  440. if (pppPFF)
  441. {
  442. *pppPFF = ppPFF;
  443. }
  444. pPFF = *ppPFF;
  445. while(pPFF)
  446. {
  447. if
  448. ((bEUDC == ((pPFF->flState & PFF_STATE_EUDC_FONT) != 0)) &&
  449. (cwc == pPFF->cwc) && (cFiles == pPFF->cFiles) &&
  450. !memcmp(pPFF->pwszPathname_, pwszPathname, cwc * sizeof(WCHAR)) &&
  451. (cjDV == pPFF->cjDV_) &&
  452. (!cjDV || !memcmp(pdv, pPFF->pdv_, pPFF->cjDV_))
  453. )
  454. {
  455. break;
  456. }
  457. pPFF = pPFF->pPFFNext;
  458. }
  459. return(pPFF);
  460. }
  461. /**********************Public*Routine***************************\
  462. * PFTOBJ::pPFFGetMM *
  463. * *
  464. * Note: *
  465. * Caller should be holding the ghsemPublicPFT semaphore *
  466. * when this method calling this in order to guarantee *
  467. * a stable font table. Also this should only be called *
  468. * when we remove the memory fonts. *
  469. * *
  470. * We check the PFF_STATE_MEMORY_FONT flag, the ulCheckSum *
  471. * and the process ID *
  472. * *
  473. * Returns: *
  474. * PPFF of the PFF if found, (PPFF) NULL if not found. *
  475. * *
  476. * History: *
  477. * 12-Jun-1997 -by- Xudong Wu [TessieW] *
  478. * Wrote it. *
  479. \***************************************************************/
  480. PPFF PUBLIC_PFTOBJ::pPFFGetMM
  481. (
  482. ULONG ulCheckSum,
  483. PFF ***pppPFF
  484. )
  485. {
  486. BOOL bFind = FALSE;
  487. PFF *pPFF, **ppPFFHead;
  488. int i;
  489. ASSERTGDI(pPFT == gpPFTPrivate, "pPFFGetMM(): it is not private PFT table\n");
  490. ppPFFHead = gpPFTPrivate->apPFF;
  491. for (i=0; i < CPRIVATEBUCKETS; i++)
  492. {
  493. pPFF = *ppPFFHead;
  494. while (pPFF)
  495. {
  496. if ((pPFF->flState & PFF_STATE_MEMORY_FONT) && (pPFF->ulCheckSum == ulCheckSum))
  497. {
  498. PFFOBJ pffo(pPFF);
  499. if (pffo.pPvtDataMatch())
  500. {
  501. bFind = TRUE;
  502. break;
  503. }
  504. }
  505. pPFF = pPFF->pPFFNext;
  506. }
  507. if (bFind)
  508. {
  509. break;
  510. }
  511. ppPFFHead++;
  512. }
  513. if (bFind && pppPFF)
  514. {
  515. *pppPFF = ppPFFHead;
  516. }
  517. return(pPFF);
  518. }
  519. /******************************Public*Routine******************************\
  520. * PFTOBJ::pPFFGet *
  521. * *
  522. * This function searches for the PFF that contains the device fonts for *
  523. * the PDEV specified by the HPDEV passed in. *
  524. * *
  525. * Note: *
  526. * Caller should be holding the ghsemPublicPFT semaphore *
  527. * when calling this in order to have access to the font tables. *
  528. * *
  529. * Returns: *
  530. * pointer to the PFF if found. 0 returned on error. *
  531. * *
  532. * History: *
  533. * Fri 05-Aug-1994 13:39:04 by Kirk Olynyk [kirko] *
  534. * Changed this to a hash based search. *
  535. * 06-May-1992 -by- Gilman Wong [gilmanw] *
  536. * Wrote it. *
  537. \**************************************************************************/
  538. #define iHashHPDEV(hdev, c) (((ULONG_PTR) hdev >> 4) % c)
  539. PPFF DEVICE_PFTOBJ::pPFFGet(
  540. HDEV hdev
  541. , PFF ***pppPFF // write address of bucket here
  542. )
  543. {
  544. PFF *pPFF, **ppPFF;
  545. ppPFF = pPFT->apPFF + iHashHPDEV(hdev, pPFT->cBuckets);
  546. pPFF = *ppPFF;
  547. if (pppPFF)
  548. {
  549. *pppPFF = ppPFF;
  550. }
  551. while (pPFF)
  552. {
  553. PFFOBJ pffo(pPFF);
  554. if (!pffo.bValid())
  555. {
  556. RIP("PFTOBJ::PPFFGet(HPDEV) encountered invalid PFFOBJ\n");
  557. }
  558. else if (hdev == pffo.hdev())
  559. {
  560. break;
  561. }
  562. pPFF = pPFF->pPFFNext;
  563. }
  564. return(pPFF);
  565. }
  566. /******************************Public*Routine******************************\
  567. *
  568. * bLoadAFont, wrapper for one file only
  569. *
  570. *
  571. * History:
  572. * 28-Mar-1996 -by- Bodin Dresevic [BodinD]
  573. * Wrote it.
  574. \**************************************************************************/
  575. BOOL PUBLIC_PFTOBJ::bLoadAFont(
  576. PWSZ pwszPathname, // font file pathname
  577. PULONG pcFonts, // number of fonts faces loaded
  578. FLONG fl, // permanent
  579. PPFF *pPPFF,
  580. PEUDCLOAD pEudcLoadData
  581. )
  582. {
  583. WCHAR awcUcPathName[MAX_PATH + 1];
  584. ULONG cwc = wcslen(pwszPathname) + 1;
  585. cCapString(awcUcPathName, pwszPathname, cwc);
  586. return bLoadFonts(awcUcPathName, cwc, 1, // pwsz, cwc, cFiles
  587. NULL, 0, // pdv, cjDV
  588. pcFonts,fl, pPPFF
  589. , 0
  590. , FALSE
  591. , pEudcLoadData
  592. );
  593. }
  594. /************************Public*Routine*******************************\
  595. *
  596. * VOID vLoadFontFileView()
  597. *
  598. * Note: we need to grab semaphore ghsemDriverMgmt before the function
  599. * call and release the semaphore afterwards.
  600. *
  601. * History:
  602. * 03-June-1997 -by- Xudong Wu [Tessiew]
  603. * Wrote it.
  604. \*********************************************************************/
  605. VOID vLoadFontFileView
  606. (
  607. PWSZ pwszPathname, // font file pathname
  608. ULONG cwc, // cwc in PathName
  609. FONTFILEVIEW **apfv,
  610. ULONG cFiles,
  611. PVOID *apvView,
  612. ULONG *acjView,
  613. DESIGNVECTOR *pdv,
  614. ULONG cjDV,
  615. HFF *phffNew,
  616. PPDEV *pppDevList,
  617. PFNTCHECKSUM pFntCheckSum
  618. )
  619. {
  620. GDIFunctionID(vLoadFontFileView);
  621. HFF hffNew = HFF_INVALID;
  622. PPDEV ppDevList = gppdevList, ppDevTmp;
  623. ULONG lflag;
  624. PPDEV ppDevCache = NULL;
  625. BOOL bCached = FALSE;
  626. pFntCheckSum->ulCheckSum = 0;
  627. pFntCheckSum->ulFastCheckSum = 0;
  628. pFntCheckSum->ulCheckSum = LookUpFNTCacheTable( cwc, pwszPathname, &pFntCheckSum->ulFastCheckSum,
  629. apfv, cFiles, &ppDevList, pdv, cjDV);
  630. if (pFntCheckSum->ulCheckSum && ppDevList)
  631. {
  632. PDEVOBJ pdo((HDEV)ppDevList);
  633. ASSERTGDI (pdo.bFontDriver(), " Something wrong in font ppDev cache \n" );
  634. // In case something wrong in font driver.
  635. if (pdo.bFontDriver())
  636. {
  637. // make a reference to the font driver under the protection
  638. // of the semaphore. This will guarantee that the font
  639. // driver will not be unloaded unexpectedly. After that
  640. pdo.vReferencePdev();
  641. GreReleaseSemaphoreEx(ghsemDriverMgmt);
  642. // Attempt to load the font file.
  643. // It is acceptable to release the lock at this point because
  644. // we know this font driver has at least one reference to it.
  645. // We also do not care if other font drivers are added or removed
  646. // from the list while we are scanning it ...
  647. // We are assuming that DrvLoadFontFile will call EngMapFontFile
  648. // and EngUnmapFontFile in balanced pairs upon the view.
  649. // we are trying to add the font using the cached info. If this failed
  650. // we will try to add it later without using the cached info, in case there
  651. // is a problem with boot cache. (Defensive programming).
  652. hffNew = pdo.LoadFontFile( cFiles,
  653. (ULONG_PTR *) apfv,
  654. apvView,
  655. acjView,
  656. pdv,
  657. (ULONG) gusLanguageID,
  658. pFntCheckSum->ulFastCheckSum
  659. );
  660. if (hffNew == HFF_INVALID)
  661. {
  662. hffNew = pdo.LoadFontFile( cFiles,
  663. (ULONG_PTR *) apfv,
  664. apvView,
  665. acjView,
  666. pdv,
  667. (ULONG) gusLanguageID,
  668. 0
  669. );
  670. }
  671. if (hffNew != HFF_INVALID)
  672. {
  673. bCached = TRUE;
  674. }
  675. else
  676. {
  677. // We did not load the font file properly
  678. // Release the reference and go on.
  679. pdo.vUnreferencePdev();
  680. }
  681. // Grab the lock again here (so we exit the loop properly)
  682. GreAcquireSemaphoreEx(ghsemDriverMgmt, SEMORDER_DRIVERMGMT, NULL);
  683. }
  684. }
  685. if (!bCached)
  686. {
  687. ppDevList = gppdevList;
  688. do
  689. {
  690. PDEVOBJ pdo((HDEV)ppDevList);
  691. ppDevTmp = NULL;
  692. if ( pdo.bFontDriver() )
  693. {
  694. // make a reference to the font driver under the protection
  695. // of the semaphore. This will guarantee that the font
  696. // driver will not be unloaded unexpectedly. After that
  697. pdo.vReferencePdev();
  698. GreReleaseSemaphoreEx(ghsemDriverMgmt);
  699. // Attempt to load the font file.
  700. // It is acceptable to release the lock at this point because
  701. // we know this font driver has at least one reference to it.
  702. // We also do not care if other font drivers are added or removed
  703. // from the list while we are scanning it ...
  704. // We are assuming that DrvLoadFontFile will call EngMapFontFile
  705. // and EngUnmapFontFile in balanced pairs upon the view.
  706. hffNew = pdo.LoadFontFile( cFiles,
  707. (ULONG_PTR *) apfv,
  708. apvView,
  709. acjView,
  710. pdv,
  711. (ULONG) gusLanguageID,
  712. pFntCheckSum->ulFastCheckSum
  713. );
  714. // Grab the lock again here (so we exit the loop properly)
  715. GreAcquireSemaphoreEx(ghsemDriverMgmt, SEMORDER_DRIVERMGMT, NULL);
  716. if (hffNew != HFF_INVALID)
  717. {
  718. PutFntCacheDrv(pFntCheckSum->ulFastCheckSum, ppDevList);
  719. break;
  720. }
  721. else
  722. {
  723. // We did not load the font file properly
  724. // Release the reference and go on.
  725. ppDevTmp = ppDevList->ppdevNext;
  726. pdo.vUnreferencePdev();
  727. }
  728. }
  729. ppDevList = ppDevTmp ? ppDevTmp : ppDevList->ppdevNext;
  730. } while (ppDevList);
  731. }
  732. *pppDevList = ppDevList;
  733. *phffNew = hffNew;
  734. }
  735. /******************************Public*Routine******************************\
  736. * BOOL PUBLIC_PFTOBJ::bLoadFonts *
  737. * *
  738. * The bLoadFont function searches for an IFI font driver which can load *
  739. * the requested font file. If a driver is found, a new Pysical Font *
  740. * File object is created and is used to load the font file. *
  741. * *
  742. * Note that if the font file has already been loaded (i.e., a PFF object *
  743. * already exists for it), the ref count in the PFF is incremented without *
  744. * reloading the file. *
  745. * *
  746. * If pppfeEUDC != NULL then we are loading an EUDC font file. This has *
  747. * the restriction the font file has only one face or two if the other is *
  748. * an @face. If either of these aren't true the call fails. Also, an EUDC *
  749. * font wont be enumerated. Finally the PFE will be returned for the one *
  750. * font in the EUDC font file via pppfeEUDC. *
  751. * *
  752. * Returns FALSE on failure. *
  753. * *
  754. * History: *
  755. * Thu 28-Mar-1996 -by- Bodin Dresevic [BodinD]
  756. * update: added multiple file support
  757. * Thu 04-Aug-1994 08:04:03 by Kirk Olynyk [kirko] *
  758. * Made the font table hash based. *
  759. * 06-Nov-1990 -by- Gilman Wong [gilmanw] *
  760. * Wrote it. *
  761. \**************************************************************************/
  762. BOOL PUBLIC_PFTOBJ::bLoadFonts(
  763. PWSZ pwszPathname, // font file pathname
  764. ULONG cwc, // cwc in PathName
  765. ULONG cFiles, // number of distinct files in path
  766. DESIGNVECTOR *pdv,
  767. ULONG cjDV,
  768. PULONG pcFonts, // number of fonts faces loaded
  769. FLONG fl, // permanent
  770. PPFF *pPPFF,
  771. FLONG flEmbed,
  772. BOOL bSkip, // skip the check if the font is already loaded
  773. PEUDCLOAD pEudcLoadData // returns PFE for EUDC font file
  774. )
  775. {
  776. GDIFunctionID(PUBLIC_PFTOBJ::bLoadFonts);
  777. COUNT cFonts; // count of fonts in font file
  778. BOOL bRet = FALSE; // assume failuer
  779. PFF *pPFF; // convenient pointer2
  780. PFF **ppPFF; // address of bucket
  781. BOOL bEUDC = ( pEudcLoadData != NULL );
  782. PPFE *pppfeEUDC = ((bEUDC) ? pEudcLoadData->pppfeData : NULL);
  783. FNTCHECKSUM fntCheckSum;
  784. PFF *pPFFTemp = NULL;
  785. BOOL bClone = FALSE;
  786. if (!pwszPathname)
  787. {
  788. RIP("pwszPathname != 0\n");
  789. return(bRet);
  790. }
  791. // we have seen AV caused by uninitialized gpsemPublicPFT
  792. // on Hydra systems
  793. // hydra -- we might remove this in Beta3
  794. //if (!ghsemPublicPFT)
  795. //{
  796. // return bRet;
  797. //}
  798. // if (already_loaded) increment_ref_count_then_exit_immediately
  799. if (!bSkip)
  800. {
  801. SEMOBJ so(ghsemPublicPFT);
  802. *pcFonts = 0;
  803. if ((*pPPFF = pPFFGet((PWSZ) pwszPathname, cwc, cFiles, pdv, cjDV, &ppPFF, bEUDC)) &&
  804. (*pcFonts = chpfeIncrPFF(*pPPFF, &bRet, flEmbed, pEudcLoadData)))
  805. {
  806. return(bRet);
  807. }
  808. else if (pPFFTemp = pPFFGet((PWSZ) pwszPathname, cwc, cFiles, pdv, cjDV, &ppPFF, !bEUDC))
  809. {
  810. if (pPFFTemp->pPFFClone == (PFF *) NULL)
  811. bClone = TRUE;
  812. }
  813. }
  814. // Grab the head of the font driver list under semaphore and find
  815. // the first font driver in the list that loads the font
  816. //
  817. // Release the semaphore so we can go and see if the
  818. // driver supports the font. If it does, then keep
  819. // the reference count and exit. Otherwise, grab the
  820. // semaphore again, release the reference count and
  821. // find the next driver in the list.
  822. // alloc temp memory, this could be done on the stack if it were not
  823. // for the fact that we do not know ahead the upper bound on cFiles
  824. if (!bClone)
  825. {
  826. HFF hffNew = HFF_INVALID; // IFI handle to font file
  827. MALLOCOBJ moViews(cFiles * (sizeof(PVOID) + sizeof(ULONG)));
  828. if (!moViews.bValid())
  829. return FALSE;
  830. PVOID *apvView = (PVOID *)moViews.pv();
  831. ULONG *acjView = (ULONG *)&apvView[cFiles];
  832. FONTFILEVIEW **apfv;
  833. // apfv - pointer to a block of memory that begins with an array
  834. // of cFiles pointers to FONTFILEVIEW structures followed
  835. // by a corretly aligned FONTFILEVIEW structure
  836. unsigned offset;
  837. // offset - offset of FONTFILEVIEW structure from the beginning
  838. // of the block of memory pointed to by apfv. This is equal to the
  839. // offset of the nearest double following the array of pointers.
  840. // In C, a double is maximally aligned.
  841. offset = ALIGN8(cFiles * sizeof(void*));
  842. apfv = (FONTFILEVIEW**) PALLOCMEM(offset + cFiles*sizeof(FONTFILEVIEW),'vffG');
  843. if (apfv == NULL)
  844. {
  845. WARNING("Out of memory\n");
  846. return(FALSE);
  847. }
  848. // pfv - pointer to FONTFILEVIEW structure following the array of
  849. // cFiles pointers.
  850. FONTFILEVIEW *pfv = (FONTFILEVIEW*)(((char*) apfv) + offset);
  851. // init the data for all files;
  852. PWSZ pwszTmp = pwszPathname;
  853. ULONG iFile;
  854. for (iFile = 0; iFile < cFiles; iFile++)
  855. {
  856. apfv[iFile] = &pfv[iFile];
  857. apfv[iFile]->pwszPath = pwszTmp;
  858. if (!EngMapFontFileFDInternal((ULONG_PTR)apfv[iFile], (PULONG*)&apvView[iFile], &acjView[iFile], FALSE))
  859. {
  860. WARNING("EngMapFontFile failed\n");
  861. // clean up, unmap all of those mapped so far
  862. for (ULONG jFile = 0; jFile < iFile; jFile++)
  863. EngUnmapFontFileFD((ULONG_PTR)apfv[jFile]);
  864. VFREEMEM(apfv);
  865. return(FALSE);
  866. }
  867. // get to the next file in the multiple path
  868. while (*pwszTmp++)
  869. ;
  870. }
  871. PPDEV ppDevList;
  872. // order of grabbing semaphores important
  873. GreAcquireSemaphoreEx(ghsemDriverMgmt, SEMORDER_DRIVERMGMT, NULL);
  874. vLoadFontFileView(pwszPathname, cwc, apfv, cFiles, apvView, acjView, pdv, cjDV, &hffNew, &ppDevList, &fntCheckSum);
  875. PDEVOBJ pdo((HDEV)ppDevList);
  876. GreReleaseSemaphoreEx(ghsemDriverMgmt);
  877. ASSERTGDI(bRet==FALSE,"bRet != FALSE\n");
  878. if (hffNew != HFF_INVALID)
  879. {
  880. // cFonts = number of faces in the file
  881. cFonts = pdo.QueryFontFile( hffNew,
  882. QFF_NUMFACES,
  883. 0,
  884. NULL);
  885. if (cFonts && cFonts != FD_ERROR)
  886. {
  887. // EUDC font file can have at most two fonts. If it
  888. // has two fonts then one of the face names must begin
  889. // with the '@' character. We check the number of fonts
  890. // here but we do not check the characters of the
  891. // face names.
  892. if (bEUDC && (pEudcLoadData->LinkedFace == NULL) && (cFonts > 2))
  893. {
  894. WARNING("EUDC font file has more than two faces.");
  895. return(bRet);
  896. }
  897. *pcFonts = cFonts;
  898. // Create new PFF with table big enough to accomodate
  899. // the new fonts and pathname.
  900. PFFCLEANUP *pPFFC = 0;
  901. PFFMEMOBJ pffmo(cFonts,
  902. pwszPathname,cwc, cFiles, pdv, cjDV,
  903. hffNew,pdo.hdev(),0,pPFT,fl,flEmbed,&fntCheckSum, apfv, NULL
  904. );
  905. if (pffmo.bValid())
  906. {
  907. // Tell the PFF user object to load its table of
  908. // HPFE's for each font in file.
  909. if (!pffmo.bLoadFontFileTable(pwszPathname,
  910. cFonts,
  911. (HANDLE) 0,
  912. NULL, //PFE_UFIMATCH bit for remote printing
  913. pEudcLoadData
  914. ))
  915. {
  916. *pcFonts = 0;
  917. }
  918. else
  919. {
  920. // Font load has succeeded. If some other process hasn't
  921. // already snuck in and added it while the ghsemPublicPFT
  922. // semaphore was released, add the new PFF to the PFT.
  923. // Stabilize font table before searching or modifying it.
  924. SEMOBJ so2(ghsemPublicPFT);
  925. // Is PFF already in table? We check this by
  926. // assuming that it already is and attempt to
  927. // increment the load count. If it succeeds, its
  928. // there. If it fails, it not there and we can add
  929. // our new PFF to the PFT.
  930. #ifdef LANGPACK
  931. // do this under the public font table semaphore to
  932. // serialize access to the
  933. pffmo.vSetUniqueness();
  934. #endif
  935. if((*pPPFF = pPFFGet(pwszPathname, cwc, cFiles, pdv, cjDV, &ppPFF, bEUDC)) &&
  936. (cFonts = chpfeIncrPFF(*pPPFF,&bRet,flEmbed,pEudcLoadData)))
  937. {
  938. // Some other process got in and put it in before we
  939. // could. chpfeIncrPFF has already incremented the
  940. // count for us. We only need to delete the PFF that
  941. // we made which will occur automatically if
  942. // bRet = FALSE
  943. *pcFonts = cFonts;
  944. }
  945. else
  946. {
  947. // Not already in the table, so we really are going
  948. // to add it to the PFT.
  949. *pPPFF = pffmo.pPFFGet();
  950. if(pffmo.bAddHash(bEUDC))
  951. {
  952. // add entry to head of a doubly linked collision
  953. // list
  954. pPFT->cFiles++;
  955. if (*ppPFF)
  956. {
  957. (*ppPFF)->pPFFPrev = *pPPFF;
  958. }
  959. (*pPPFF)->pPFFNext = *ppPFF;
  960. (*pPPFF)->pPFFPrev = 0;
  961. *ppPFF = *pPPFF;
  962. pffmo.vKeepIt();
  963. // need to reset the file paths pointers
  964. pwszTmp = pffmo.pwszPathname();
  965. for (iFile = 0; iFile < cFiles; iFile++)
  966. {
  967. apfv[iFile]->pwszPath = pwszTmp;
  968. // get to the next file in the multiple path
  969. while (*pwszTmp++)
  970. ;
  971. }
  972. bRet = TRUE;
  973. }
  974. else
  975. {
  976. WARNING("pffmo.bAddHash() failed\n");
  977. *pcFonts = 0;
  978. pffmo.vRemoveHash();
  979. }
  980. }
  981. }
  982. if (!bRet)
  983. {
  984. // must unmap the files before calling pPFFC_Delete()
  985. // because this function will delete apfv memory so that unmap
  986. // will fail
  987. for (iFile = 0; iFile < cFiles; iFile++)
  988. {
  989. EngUnmapFontFileFD((ULONG_PTR)apfv[iFile]);
  990. }
  991. pffmo.vPFFC_DeleteAndCleanup(); // new code
  992. return bRet;
  993. }
  994. }
  995. }
  996. }
  997. // If you get to here then the font driver recognized the font. Since
  998. // we cannot be sure that the font will be used immediately, we will
  999. // unmap font font file and free the memory containing the image of the
  1000. // font file.
  1001. for ( iFile = 0; iFile < cFiles; iFile++ )
  1002. {
  1003. EngUnmapFontFileFD( (ULONG_PTR) apfv[iFile] );
  1004. }
  1005. if (!bRet)
  1006. {
  1007. VFREEMEM(apfv);
  1008. }
  1009. return(bRet);
  1010. }
  1011. else
  1012. {
  1013. PFFCLEANUP *pPFFC = 0;
  1014. // Clone the hffNew and make a new PFF object
  1015. PFFMEMOBJ pffmo(pPFFTemp, fl, flEmbed, pPFT);
  1016. bRet = FALSE;
  1017. cFonts = pPFFTemp->cFonts;
  1018. if (pffmo.bValid())
  1019. {
  1020. // Tell the PFF user object to load its table of
  1021. // HPFE's for each font in file.
  1022. if (!pffmo.bLoadFontFileTable(pwszPathname, cFonts, (HANDLE) 0, NULL, pEudcLoadData))
  1023. {
  1024. *pcFonts = 0;
  1025. }
  1026. else
  1027. {
  1028. // Font load has succeeded. If some other process hasn't
  1029. // already snuck in and added it while the ghsemPublicPFT
  1030. // semaphore was released, add the new PFF to the PFT.
  1031. // Stabilize font table before searching or modifying it.
  1032. SEMOBJ so2(ghsemPublicPFT);
  1033. // Is PFF already in table? We check this by
  1034. // assuming that it already is and attempt to
  1035. // increment the load count. If it succeeds, its
  1036. // there. If it fails, it not there and we can add
  1037. // our new PFF to the PFT.
  1038. #ifdef LANGPACK
  1039. // do this under the public font table semaphore to
  1040. // serialize access to the
  1041. pffmo.vSetUniqueness();
  1042. #endif
  1043. if((*pPPFF = pPFFGet(pwszPathname, cwc, cFiles, pdv, cjDV, &ppPFF, bEUDC)) &&
  1044. (cFonts = chpfeIncrPFF(*pPPFF,&bRet,flEmbed,pEudcLoadData)))
  1045. {
  1046. // Some other process got in and put it in before we
  1047. // could. chpfeIncrPFF has already incremented the
  1048. // count for us. We only need to delete the PFF that
  1049. // we made which will occur automatically if
  1050. // bRet = FALSE
  1051. *pcFonts = cFonts;
  1052. }
  1053. else
  1054. {
  1055. // Not already in the table, so we really are going
  1056. // to add it to the PFT.
  1057. *pPPFF = pffmo.pPFFGet();
  1058. if(pffmo.bAddHash(bEUDC))
  1059. {
  1060. // add entry to head of a doubly linked collision
  1061. // list
  1062. pPFT->cFiles++;
  1063. if (*ppPFF)
  1064. {
  1065. (*ppPFF)->pPFFPrev = *pPPFF;
  1066. }
  1067. (*pPPFF)->pPFFNext = *ppPFF;
  1068. (*pPPFF)->pPFFPrev = 0;
  1069. *ppPFF = *pPPFF;
  1070. pffmo.vKeepIt();
  1071. bRet = TRUE;
  1072. }
  1073. else
  1074. {
  1075. WARNING("pffmo.bAddHash() failed\n");
  1076. *pcFonts = 0;
  1077. pffmo.vRemoveHash();
  1078. }
  1079. }
  1080. }
  1081. if (!bRet)
  1082. {
  1083. // must unmap the files before calling pPFFC_Delete()
  1084. // because this function will delete apfv memory so that unmap
  1085. // will fail
  1086. pffmo.vPFFC_DeleteAndCleanup(); // new code
  1087. }
  1088. }
  1089. return(bRet);
  1090. }
  1091. }
  1092. /******************************Public*Routine******************************\
  1093. * BOOL PUBLIC_PFTOBJ::bLoadRemoteFonts
  1094. *
  1095. * Warning:
  1096. *
  1097. * This routine or any of the routines that it calls must
  1098. * call EngMapFontFile and EngUnmapFontFile in pairs.
  1099. *
  1100. * History:
  1101. * Thu 02-Feb-1995 2:04:06 by Gerrit van Wingerden [gerritv]
  1102. * Wrote it.
  1103. \**************************************************************************/
  1104. #define QUICK_VIEWS 4
  1105. ULONG PUBLIC_PFTOBJ::ulRemoteUnique = 0;
  1106. BOOL PUBLIC_PFTOBJ::bLoadRemoteFonts(
  1107. XDCOBJ &dco,
  1108. PFONTFILEVIEW *ppfv, // points to a pre mapped view of the font
  1109. // EngMapFontFile must NOT be called
  1110. // before sending it to the font driver
  1111. // EngUnmapFontFile must be called at
  1112. // the end of this routine for possible
  1113. // error cleanup
  1114. UINT cNumFonts, // number of files needed to represent this font
  1115. DESIGNVECTOR *pdv, // dv for the mm instance
  1116. PUNIVERSAL_FONT_ID pufi
  1117. )
  1118. {
  1119. COUNT cFonts; // count of fonts in font file
  1120. BOOL bRet = FALSE; // assume failure
  1121. HFF hffNew = HFF_INVALID; // IFI handle to font file
  1122. ULONG cjDV = (pdv ? SIZEOFDV(pdv->dvNumAxes) : 0);
  1123. FNTCHECKSUM fntCheckSum;
  1124. PVOID pvQuickBuffer[QUICK_VIEWS], *ppvViews;
  1125. ULONG pcjQuickBuffer[QUICK_VIEWS], *pcjViews;
  1126. if(cNumFonts > QUICK_VIEWS)
  1127. {
  1128. if(!(ppvViews = (VOID**) PALLOCMEM((sizeof(void*)+sizeof(ULONG*))*cNumFonts,
  1129. 'vffG')))
  1130. {
  1131. WARNING("bLoadRemoteFonts unable to allocate memory\n");
  1132. // need to free ppfv if this function (bLoadRemoteFonts) fails
  1133. if (ppfv)
  1134. {
  1135. VFREEMEM (ppfv);
  1136. }
  1137. return(FALSE);
  1138. }
  1139. pcjViews = (ULONG*) &ppvViews[QUICK_VIEWS];
  1140. }
  1141. else
  1142. {
  1143. ppvViews = pvQuickBuffer;
  1144. pcjViews = pcjQuickBuffer;
  1145. }
  1146. UINT i;
  1147. for(i = 0; i < cNumFonts; i++)
  1148. {
  1149. ppvViews[i] = ppfv[i]->fv.pvViewFD;
  1150. pcjViews[i] = ppfv[i]->fv.cjView;
  1151. }
  1152. PPDEV ppDevList;
  1153. // order of grabbing semaphores important
  1154. GreAcquireSemaphoreEx(ghsemDriverMgmt, SEMORDER_DRIVERMGMT, NULL);
  1155. vLoadFontFileView(NULL, 0, ppfv, cNumFonts, ppvViews, pcjViews, pdv, cjDV, &hffNew, &ppDevList, &fntCheckSum);
  1156. PDEVOBJ pdo((HDEV)ppDevList);
  1157. GreReleaseSemaphoreEx(ghsemDriverMgmt);
  1158. if(ppvViews != pvQuickBuffer)
  1159. {
  1160. VFREEMEM(ppvViews);
  1161. }
  1162. ASSERTGDI(bRet==FALSE,"bRet != FALSE\n");
  1163. if (hffNew != HFF_INVALID)
  1164. {
  1165. //
  1166. // cFonts = number of faces in the file
  1167. //
  1168. cFonts = pdo.QueryFontFile( hffNew, QFF_NUMFACES, 0, NULL);
  1169. if (cFonts && cFonts != FD_ERROR)
  1170. {
  1171. WCHAR awc[30];
  1172. // Create a (hopefully) unique file name for
  1173. // the remote font of the form "REMOTE nnnnnnnn"
  1174. swprintf(
  1175. awc,
  1176. L"REMOTE-%u",
  1177. ulGetNewUniqueness(PUBLIC_PFTOBJ::ulRemoteUnique));
  1178. ULONG cwc = wcslen(awc) + 1;
  1179. // Create new PFF with table big enough to accomodate
  1180. // the new fonts and pathname.
  1181. PFFCLEANUP *pPFFC = 0;
  1182. PFFMEMOBJ
  1183. pffmo (cFonts,
  1184. awc, cwc, cNumFonts, // pwsz, cwc, cFiles
  1185. pdv, cjDV, // pdv, cjDV,
  1186. hffNew,
  1187. pdo.hdev(),
  1188. 0,
  1189. pPFT,
  1190. PFF_STATE_DCREMOTE_FONT,
  1191. FR_NOT_ENUM, // never enum fonts that are temporarily
  1192. &fntCheckSum,
  1193. ppfv, // loaded on printer server until print job is done
  1194. pufi); // use this ufi instead of calculate from the ppfv for remote printing
  1195. if (pffmo.bValid())
  1196. {
  1197. // Tell the PFF user object to load its table of
  1198. // HPFE's for each font in file.
  1199. if ( pffmo.bLoadFontFileTable(awc,
  1200. cFonts,
  1201. dco.hdc(),
  1202. pufi, // fonts can be mapped only by bFoundForcedMatch() calls
  1203. NULL // for remote printing.
  1204. ))
  1205. {
  1206. // Stabilize font table before searching or modifying it.
  1207. SEMOBJ so2(ghsemPublicPFT);
  1208. if(bRet = pffmo.bAddHash(FALSE))
  1209. {
  1210. PFF **ppPFF, *pPFF;
  1211. pPFF = pPFFGet(awc, cwc, cNumFonts, pdv, cjDV, &ppPFF);
  1212. if (pPFF)
  1213. {
  1214. #if DBG
  1215. KdPrint(("\"%ws\" has been found on the font table\n"));
  1216. KdBreakPoint();
  1217. #endif
  1218. bRet = FALSE;
  1219. }
  1220. else
  1221. {
  1222. pPFF = pffmo.pPFFGet();
  1223. if( bRet = dco.bAddRemoteFont( pPFF ) )
  1224. {
  1225. pPFT->cFiles++;
  1226. // place the pointer to this new remote
  1227. // PFF at the head of the public PFT.
  1228. if (*ppPFF) // head of list exist?
  1229. { // yes make it follow new PFF
  1230. (*ppPFF)->pPFFPrev = pPFF;
  1231. }
  1232. pPFF->pPFFNext = *ppPFF;
  1233. pPFF->pPFFPrev = 0; // new PFF is first in list
  1234. *ppPFF = pPFF;
  1235. pffmo.vKeepIt();
  1236. }
  1237. }
  1238. }
  1239. else
  1240. {
  1241. pffmo.vRemoveHash();
  1242. }
  1243. // Here we should add it to our HDC's font table.
  1244. }
  1245. // call this if the above addition to the HDC's font table
  1246. // fails
  1247. if (!bRet)
  1248. {
  1249. pffmo.vPFFC_DeleteAndCleanup(); // new code
  1250. }
  1251. }
  1252. }
  1253. }
  1254. return(bRet);
  1255. }
  1256. /******************************Public*Routine******************************\
  1257. * PFTOBJ::bLoadDeviceFonts
  1258. *
  1259. * This function loads the device fonts of the device identified by the pair
  1260. * (pldo, hdev) into the public table. There are cFonts number of device
  1261. * fonts.
  1262. *
  1263. * The function will enlarge the PFT and create a PFF to contain the new fonts.
  1264. * The actual work of loading each device font into the tables is carrided
  1265. * out by PFF::bLoadDeviceFontTable().
  1266. *
  1267. * Note:
  1268. * All the device fonts of a particular physical device are grouped together
  1269. * as if they were in a single file and are placed all within a single PFF,
  1270. * with each font represented by a single PFE.
  1271. *
  1272. * Note:
  1273. * The function does not bother to check if the device fonts already are
  1274. * in the tree.*
  1275. *
  1276. * Returns:
  1277. * TRUE if successful, FALSE if an error occurs.
  1278. *
  1279. * History:
  1280. * Mon 15-Aug-1994 11:57:14 by Kirk Olynyk [kirko]
  1281. * Modified it for the new hashing scheme (not the same thing as font name
  1282. * hashing, which remains unchanged).
  1283. * 18-Mar-1991 -by- Gilman Wong [gilmanw]
  1284. * Wrote it.
  1285. \**************************************************************************/
  1286. BOOL
  1287. DEVICE_PFTOBJ::bLoadFonts(
  1288. PPDEVOBJ ppdo
  1289. )
  1290. {
  1291. PFF *pPFF, **ppPFF;
  1292. BOOL bRet = FALSE;
  1293. FNTCHECKSUM fntCheckSum;
  1294. {
  1295. SEMOBJ so(ghsemPublicPFT);
  1296. if (pPFFGet(ppdo->hdev(), &ppPFF))
  1297. {
  1298. bRet = TRUE;
  1299. }
  1300. }
  1301. if (!bRet)
  1302. {
  1303. //
  1304. // create new PFF with table big enough to accomodate the
  1305. // new device fonts
  1306. //
  1307. // the 'dhpdev' is used only for drivers that are font producers,
  1308. // and consequently are not affected by dynamic mode changing.
  1309. // We have to call 'dhpdevNotDynamic' to avoid an assert
  1310. //
  1311. fntCheckSum.ulFastCheckSum = 0;
  1312. fntCheckSum.ulCheckSum = 0;
  1313. PFFMEMOBJ pffmo(ppdo->cFonts(),
  1314. NULL,0,0, // no path, no files,
  1315. NULL, 0, // no pdv, cjDV,
  1316. HFF_INVALID,
  1317. ppdo->hdev(),
  1318. ppdo->dhpdevNotDynamic(),
  1319. pPFT,
  1320. 0,
  1321. 0, // flEmbed
  1322. &fntCheckSum, // pointer to PFNTCHECKSUM, on return fill in slow check sum
  1323. NULL, // no views of the mapped font files
  1324. NULL // pufi
  1325. );
  1326. if (pffmo.bValid())
  1327. {
  1328. if (!pffmo.bLoadDeviceFontTable(ppdo))
  1329. {
  1330. WARNING("pffmo.bLoadDeviceFontTable() failed\n");
  1331. }
  1332. else
  1333. {
  1334. SEMOBJ so(ghsemPublicPFT);
  1335. // if (!font_is_loaded_already) add_font_to_table;
  1336. if (!(pPFF = pPFFGet(ppdo->hdev(), &ppPFF)))
  1337. {
  1338. if (!pffmo.bAddHash(FALSE))
  1339. {
  1340. WARNING("gdisrv!bLoadDeviceFontsPFTOBJ()"
  1341. ": failed to add to font hash\n");
  1342. pffmo.vRemoveHash();
  1343. }
  1344. else
  1345. {
  1346. // Add file to font table
  1347. // Insert PFF at the head of the linked list
  1348. // pointed to by ppPFF
  1349. pPFF = pffmo.pPFF; // convenient pointer.
  1350. pPFT->cFiles += 1; // Increment total number
  1351. // of files in table.
  1352. if (*ppPFF) // Is there a PFF at the head
  1353. // of the linked list?
  1354. (*ppPFF)->pPFFPrev = pPFF; // Yes, put this new
  1355. pPFF->pPFFNext = *ppPFF; // PFF in front of old.
  1356. pPFF->pPFFPrev = 0; // Nothing before new font.
  1357. *ppPFF = pPFF; // Reset pointer to head of list.
  1358. pffmo.vKeepIt(); // Prevent ~PFFMEMOBJ from
  1359. // freeing memory.
  1360. bRet = TRUE;
  1361. }
  1362. }
  1363. }
  1364. if (!bRet)
  1365. {
  1366. pffmo.vPFFC_DeleteAndCleanup(); // new code
  1367. }
  1368. }
  1369. }
  1370. return(bRet);
  1371. }
  1372. #if 0
  1373. typedef struct _FONT_STRUCT_DATA {
  1374. ULONG fontDataSize;
  1375. ULONG fontMaxDataSize;
  1376. ULONG cRegistryFonts;
  1377. ULONG cMaxRegistryFonts;
  1378. ULONG cHashBuckets;
  1379. PBYTE pFont;
  1380. } FONT_STRUCT_DATA, *PFONT_STRUCT_DATA;
  1381. extern "C"
  1382. NTSTATUS
  1383. QueryRegistryFontListRoutine
  1384. (
  1385. PWSTR ValueName,
  1386. ULONG ValueType,
  1387. PVOID ValueData,
  1388. ULONG ValueLength,
  1389. PVOID Context,
  1390. PVOID EntryContext
  1391. )
  1392. {
  1393. PFONT_STRUCT_DATA pFontStructData = (PFONT_STRUCT_DATA) Context;
  1394. ULONG Length;
  1395. if ( (pFontStructData->fontDataSize + ValueLength >
  1396. pFontStructData->fontMaxDataSize) ||
  1397. (pFontStructData->cRegistryFonts >= pFontStructData->cMaxRegistryFonts) ||
  1398. (pFontStructData->cRegistryFonts >= pFontStructData->cHashBuckets) )
  1399. {
  1400. //
  1401. // The buffer is too small - reallocate it (leave lots of place to
  1402. // build the hash table at the end
  1403. //
  1404. PBYTE pjBuffer;
  1405. ULONG i;
  1406. ULONG oldMaxSize = pFontStructData->fontMaxDataSize;
  1407. pFontStructData->fontMaxDataSize += 0x100;
  1408. pFontStructData->cMaxRegistryFonts += 10;
  1409. pFontStructData->cHashBuckets = pFontStructData->cMaxRegistryFonts * 2;
  1410. pjBuffer = (PBYTE) PALLOCMEM(pFontStructData->fontMaxDataSize +
  1411. pFontStructData->cMaxRegistryFonts *
  1412. sizeof(PBYTE) +
  1413. pFontStructData->cHashBuckets *
  1414. sizeof(REGHASHBKT) * 2, 'gerG');
  1415. //
  1416. // The buffer has three sections
  1417. // 1) the first part of the buffer contains all the NULL terminated
  1418. // strings of the font files.
  1419. // 2) an array of pointers to these strings.
  1420. // 3) space for the hash table
  1421. //
  1422. // When copying the buffer, 1) can just be moved, 2) has to be adjusted
  1423. // and 3) is not touched - has to be zero initialized
  1424. //
  1425. if (pjBuffer)
  1426. {
  1427. //
  1428. // If we have an old one, move it to the new one, and then
  1429. // always reset the pointer.
  1430. //
  1431. if (pFontStructData->fontDataSize)
  1432. {
  1433. //
  1434. // Adjust the pointers - requires doing arithmetic on the
  1435. // pointers themselves !
  1436. //
  1437. for (i=0; i < pFontStructData->cRegistryFonts; i++)
  1438. {
  1439. *( ((PULONG)(pjBuffer +
  1440. pFontStructData->fontMaxDataSize)) + i ) =
  1441. *( ((PULONG)(pFontStructData->pFont + oldMaxSize)) + i )
  1442. + pjBuffer - pFontStructData->pFont;
  1443. }
  1444. //
  1445. // Copy all the data to the new Buffer
  1446. //
  1447. RtlMoveMemory(pjBuffer,
  1448. pFontStructData->pFont,
  1449. pFontStructData->fontDataSize);
  1450. VFREEMEM(pFontStructData->pFont);
  1451. }
  1452. pFontStructData->pFont = pjBuffer;
  1453. }
  1454. else
  1455. {
  1456. //
  1457. // we do not have enough memory - return failiure
  1458. //
  1459. return STATUS_NO_MEMORY;
  1460. }
  1461. }
  1462. Length = cCapString((PWSTR) (pFontStructData->pFont +
  1463. pFontStructData->fontDataSize),
  1464. (const WCHAR*) ValueData,
  1465. ValueLength / 2);
  1466. ASSERTGDI(Length * 2 + 2 == ValueLength,
  1467. "QueryRegistryFontListRoutine CapString problem\n");
  1468. * ( ((PBYTE *)(pFontStructData->pFont + pFontStructData->fontMaxDataSize)) +
  1469. pFontStructData->cRegistryFonts) =
  1470. pFontStructData->pFont + pFontStructData->fontDataSize;
  1471. pFontStructData->fontDataSize += ValueLength;
  1472. pFontStructData->cRegistryFonts += 1;
  1473. return STATUS_SUCCESS;
  1474. }
  1475. #endif
  1476. /******************************Public*Routine******************************\
  1477. *
  1478. * BOOL PFTOBJ::bUnloadAllButPermanentFonts
  1479. *
  1480. * If bUnloadPermanent == FALSE (default):
  1481. *
  1482. * Called at log-off time to force unloading off all but permanent
  1483. * fonts Permanent fonts are defined as either console fonts or
  1484. * fonts from Gre_Initialize section of win.ini (i.e. registry).
  1485. * Fonts from the "Fonts" section in win.ini (registry) are also
  1486. * permanent if they are on the local hard drive. If they are
  1487. * remote they will get reloaded at the log on time. This should
  1488. * be done after the net connections from the user profile are
  1489. * restored so that the font can get reloaded.
  1490. *
  1491. * If bUnloadPermanent == TRUE:
  1492. *
  1493. * All fonts in table are unloaded. Only used for MultiUserGreCleanupAllFonts
  1494. * (i.e, MultiUserGreCleanup or Hydra processing).
  1495. *
  1496. * History:
  1497. * 30-Nov-1993 -by- Bodin Dresevic [BodinD]
  1498. * Wrote it.
  1499. \**************************************************************************/
  1500. typedef struct _FONTVICTIM
  1501. {
  1502. PFF *pPFFVictim;
  1503. RFONT *prfntVictims;
  1504. } FONTVICTIM;
  1505. FONTVICTIM gFntVict[64];
  1506. BOOL PFTOBJ::bUnloadAllButPermanentFonts (BOOL bUnloadPermanent)
  1507. {
  1508. // pointer to the array of cFonts victim structures. Only as
  1509. // many entries of this array will be initialized as there are
  1510. // non-permanent fonts in the pft. These fonts will be deleted
  1511. // outside of the pft semaphore.
  1512. FONTVICTIM *pvict, *pvictCur;
  1513. COUNT cFile, cFonts;
  1514. PFF *pPFF;
  1515. BOOL bAlloc = FALSE;
  1516. // Look for the PFF to unload.
  1517. {
  1518. // Stablize table while we scan it for victims.
  1519. SEMOBJ so(ghsemPublicPFT);
  1520. // alloc mem for the array of font victims
  1521. // It is essential that this memory is zero initialized
  1522. // This must be done under semaphore, otherwise cFonts might change;
  1523. cFonts = pPFT->cFiles;
  1524. if (cFonts == 0)
  1525. {
  1526. // gpPFTDevice initialized but no device font loaded.
  1527. // Seen this on Hydra.
  1528. return TRUE;
  1529. }
  1530. if ( cFonts > 64)
  1531. {
  1532. if (!(pvict = (FONTVICTIM *)PALLOCNOZ(cFonts * sizeof(FONTVICTIM),'ivfG')))
  1533. {
  1534. WARNING(
  1535. "PFTOBJ::bUnloadAllButPermanentFonts failure\n"
  1536. "Failed to allocate memeory for font victim list\n");
  1537. return FALSE;
  1538. }
  1539. bAlloc = TRUE;
  1540. }
  1541. else
  1542. {
  1543. pvict = &gFntVict[0];
  1544. }
  1545. pvictCur = pvict;
  1546. // Caution with this code: pPFT->cFiles changes in the loop
  1547. // This loop does two things:
  1548. // a) stores the pPFFVictim information in the pvict array
  1549. // for the fonts that are going to be unloaded outside
  1550. // the semaphore.
  1551. // b) contracts the pft table to contain only the permanent
  1552. // fonts upon the exit of the loop
  1553. for (
  1554. PFF **ppPFF = pPFT->apPFF
  1555. ; ppPFF < pPFT->apPFF + pPFT->cBuckets
  1556. ; ppPFF++
  1557. )
  1558. {
  1559. for (pPFF = *ppPFF; pPFF; pPFF = pPFF->pPFFNext)
  1560. {
  1561. // Create a PFF user object. There shouldn't be any invalid
  1562. // handles in the PFT.
  1563. PFFOBJ pffo(pPFF);
  1564. ASSERTGDI(pffo.bValid(),
  1565. "gdisrv!bUnloadFontPFTOBJ(file): bad PPFF in public PFT\n");
  1566. // Is it a font driver loaded file? And if so, is this not a
  1567. // permanent file (listed in Gre_Initialize or loaded by
  1568. // console or local font from "fonts" section of the registry)
  1569. // We also leave alone fonts loaded temporarily for printing
  1570. if (bUnloadPermanent || !(pffo.bPermanent() || pffo.bDCRemote()))
  1571. {
  1572. ASSERTGDI(!pffo.bDCRemote(), "bUnloadAllButPermanentFonts: "
  1573. "EMF spooler playback fonts still present!\n");
  1574. // Tell PFF to decrement its load count and ask it if is
  1575. // ready to die. If it returns TRUE, we will need to delete
  1576. // (outside of semaphore since PFF deletion may cause driver
  1577. // to be called).
  1578. // we force the load count to zero. We are forcing the unload
  1579. // of this font
  1580. pffo.vSet_cLoaded((COUNT)0); // not loaded any more,
  1581. // avoid asserts
  1582. pffo.vSet_cNotEnum((COUNT)0);
  1583. pffo.vKill();
  1584. {
  1585. // unlink the PFF from the collision list
  1586. if (*ppPFF == pPFF)
  1587. {
  1588. // The hash bucket contains a pointer to the first
  1589. // PFF in the collision list. If it turns out that
  1590. // the victim is this first in the list, then the
  1591. // address storred in the hash bucket must be changed
  1592. *ppPFF = pPFF->pPFFNext;
  1593. }
  1594. if (pPFF->pPFFNext)
  1595. {
  1596. pPFF->pPFFNext->pPFFPrev = pPFF->pPFFPrev;
  1597. }
  1598. if (pPFF->pPFFPrev)
  1599. {
  1600. pPFF->pPFFPrev->pPFFNext = pPFF->pPFFNext;
  1601. }
  1602. }
  1603. // Save handle of victim.
  1604. pvictCur->pPFFVictim = pffo.pPFFGet();
  1605. // Remove PFF and PFEs from hash tables. Fonts in this
  1606. // font file will no longer be enumerated or mapped to.
  1607. pffo.vRemoveHash();
  1608. pPFT->cFiles--;
  1609. // Construct a "kill" list of RFONTs.
  1610. pvictCur->prfntVictims = prfntKillList(pffo);
  1611. // point to the next entry in pvictCur array
  1612. pvictCur++;
  1613. }
  1614. else
  1615. {
  1616. // this is a permanent or a device font, leave them in
  1617. // set init to 1 for the next logon session
  1618. if (pffo.bPermanent() && !(pPFF->flState & PFF_STATE_EUDC_FONT))
  1619. {
  1620. if ( pffo.cLoaded() )
  1621. {
  1622. pffo.vSet_cLoaded((COUNT)1);
  1623. pffo.vSet_cNotEnum((COUNT)0);
  1624. }
  1625. else
  1626. {
  1627. pffo.vSet_cLoaded((COUNT)0);
  1628. pffo.vSet_cNotEnum((COUNT)1);
  1629. }
  1630. }
  1631. }
  1632. }
  1633. } // end of the for loop
  1634. // at this time if any font were in the private font table, the process
  1635. // cleanup should have removed them (this is logoff time!), therefore there
  1636. // is nothing we need to do about private font table
  1637. #if DBG
  1638. PUBLIC_PFTOBJ pftop(gpPFTPrivate);
  1639. ASSERTGDI((gpPFTPrivate == NULL) || (pftop.cFiles() == 0),
  1640. "some private fonts still around at logoff time\n");
  1641. #endif
  1642. }
  1643. // Delete the victims that were found:
  1644. // Overload cFonts to mean cFontsToBeDeleted:
  1645. // Sundown truncation
  1646. ASSERT4GB((ULONGLONG)(pvictCur - pvict));
  1647. cFonts = (ULONG)(pvictCur - pvict);
  1648. for (cFile = 0; cFile < cFonts; cFile++)
  1649. {
  1650. ASSERTGDI(
  1651. pvict[cFile].pPFFVictim != (PPFF) NULL,
  1652. "GreRemoveAllButPermanentFonts, pPFFVictim IS null\n"
  1653. );
  1654. PFFOBJ pffoVictim(pvict[cFile].pPFFVictim);
  1655. ASSERTGDI(pffoVictim.bValid(),
  1656. "gdisrv!bUnloadFontPFTOBJ(device): PFF victim bad\n");
  1657. // If we need to kill any RFONT victims, now is the time to do it.
  1658. // bKillRFONTList() can handle NULL prfntVictims case.
  1659. // Note that we do not check the return, we go on to the
  1660. // next font [bodind]
  1661. bKillRFONTList(pffoVictim, pvict[cFile].prfntVictims);
  1662. }
  1663. // release memory
  1664. if (bAlloc)
  1665. VFREEMEM(pvict);
  1666. // We didn't delete anything, but we're ok as long as we found the right
  1667. // PFF. PFF still referenced (either load count or RFONT count) and will
  1668. // be deleted later.
  1669. return(TRUE);
  1670. }
  1671. /******************************Public*Routine******************************\
  1672. * bUnloadWorkhorse
  1673. *
  1674. * History:
  1675. * Mon 15-Aug-1994 14:10:53 by Kirk Olynyk [kirko]
  1676. * Wrote it.
  1677. \**************************************************************************/
  1678. BOOL PFTOBJ::bUnloadWorkhorse(
  1679. PFF *pPFF,
  1680. PFF **ppPFFHead, // bucket address
  1681. HSEMAPHORE hsem, // if the pointer is not zero,
  1682. // then this must be a pointer
  1683. // to the public font table
  1684. // semaphore and must be released
  1685. // before this procedure returns
  1686. ULONG flEmbed // Embedding/private flag
  1687. )
  1688. {
  1689. GDIFunctionID(PFTOBJ::bUnloadWorkhorse);
  1690. PFF *pPFFVictim = 0; // Pointer to PFF to be deleted, only
  1691. // non zero when found and deleted
  1692. BOOL bFoundPFF = FALSE; // signals PFF was found (does not
  1693. // indicate deletion status);
  1694. static const PSZ pszReleaseSem = "PFTOBJ::bUnloadWorkhorse()"
  1695. " releasing gpPFTPublic";
  1696. TRACE_FONT((
  1697. "Entering PFTOBJ::bUnloadWorkhorse\n"
  1698. "\tpPFF=%-#x\n"
  1699. "\tppPFFHead=%-#x\n",
  1700. "\thsem=%-#x\n",
  1701. pPFF, ppPFFHead, hsem
  1702. ));
  1703. ASSERTGDI(!hsem || hsem==ghsemPublicPFT, "hsem!=ghsemPublicPFT\n");
  1704. if ( pPFF )
  1705. {
  1706. PFFOBJ pffo(pPFF);
  1707. ASSERTGDI(pffo.bValid(), "bad PPFF in public PFT\n");
  1708. PVTDATA *pPvtData = NULL;
  1709. if ((!bIsPrivatePFT()) || (pPvtData = pffo.pPvtDataMatch()))
  1710. {
  1711. // Tell PFF to decrement its load count and ask it if is
  1712. // ready to die. If it returns TRUE, we will need to
  1713. // delete (outside of semaphore since PFF deletion may
  1714. // cause driver to be called).
  1715. bFoundPFF = TRUE;
  1716. BOOL bWrongFlags = FALSE;
  1717. if ( pffo.bDeleteLoadRef(flEmbed, pPvtData, &bWrongFlags) )
  1718. {
  1719. // Remove PFF and PFEs from hash tables. Fonts in this
  1720. // font file will no longer be enumerated or mapped to.
  1721. pffo.vRemoveHash();
  1722. // now remove it from the font table hash
  1723. pPFFVictim = pPFF;
  1724. // If ppPFFHead is NULL then it means that we are
  1725. // unloading a font that has been added to the DC
  1726. // as a remote font and the this must be the public
  1727. // font table
  1728. PFF **ppPFF = ppPFFHead;
  1729. if( ppPFF == 0 )
  1730. {
  1731. PUBLIC_PFTOBJ *pTemp;
  1732. PFF *pPFF_Found;
  1733. ASSERTGDI(pPFF->pPFT==gpPFTPublic || pPFF->pPFT==gpPFTPrivate,"PFF not in public font table\n");
  1734. pTemp = (PUBLIC_PFTOBJ*) this;
  1735. pPFF_Found = pTemp->pPFFGet(pPFF->pwszPathname_,
  1736. pPFF->cwc,
  1737. pPFF->cFiles,
  1738. pPFF->pdv_,
  1739. pPFF->cjDV_,
  1740. &ppPFF
  1741. );
  1742. ASSERTGDI(pPFF==pPFF_Found,"Could not find remote PFF in the font table\n");
  1743. }
  1744. if (*ppPFF == pPFF)
  1745. {
  1746. *ppPFF = pPFF->pPFFNext;
  1747. }
  1748. if (pPFF->pPFFNext)
  1749. {
  1750. (pPFF->pPFFNext)->pPFFPrev = pPFF->pPFFPrev;
  1751. }
  1752. if (pPFF->pPFFPrev)
  1753. {
  1754. (pPFF->pPFFPrev)->pPFFNext = pPFF->pPFFNext;
  1755. }
  1756. pPFT->cFiles--;
  1757. }
  1758. else
  1759. {
  1760. // Set the return value as FALSE for private/embedded fonts
  1761. if (bIsPrivatePFT() && bWrongFlags)
  1762. {
  1763. bFoundPFF = FALSE;
  1764. }
  1765. }
  1766. }
  1767. if ( pPFFVictim )
  1768. {
  1769. PFFOBJ pffoVictim(pPFFVictim);
  1770. if ( !pffoVictim.bValid() )
  1771. {
  1772. RIP("pffoVictim is not valid\n");
  1773. bFoundPFF = 0;
  1774. }
  1775. else
  1776. {
  1777. if ( hsem )
  1778. {
  1779. // The victim has been removed from the table
  1780. // so the semaphore for the table may be safely
  1781. // released. It is necessary to do this because
  1782. // bKillRFONTList() calls RFONTOBJ::bDeleteRFONT()
  1783. // which in turn locks the display. If we do
  1784. // not release the font table semaphore before
  1785. // the device lock, we will have deadlock.
  1786. TRACE_FONT(("%ws\n", pszReleaseSem));
  1787. GreReleaseSemaphoreEx(hsem);
  1788. hsem = 0;
  1789. }
  1790. bFoundPFF = bKillRFONTList( pffoVictim, prfntKillList( pffoVictim ));
  1791. }
  1792. }
  1793. // We didn't delete anything, but we're ok as long as we found
  1794. // the right PFF. PFF still referenced (either load count or
  1795. // RFONT count) and will be deleted later.
  1796. }
  1797. // Make sure the semampore is released before the procedure ends
  1798. if( hsem )
  1799. {
  1800. TRACE_FONT(("%ws\n", pszReleaseSem));
  1801. GreReleaseSemaphoreEx(hsem);
  1802. }
  1803. TRACE_FONT(("Exiting PFTOBJ::bUnloadWorkhorse\n"
  1804. "\treturn value = %d\n", bFoundPFF));
  1805. return( bFoundPFF );
  1806. }
  1807. /****************************************************************************
  1808. * INT PFTOBJ::QueryFonts( PUNIVERSAL_FONT_ID, ULONG, PLARGE_INTEGER )
  1809. *
  1810. * History:
  1811. * 5/24/1995 by Gerrit van Wingerden [gerritv]
  1812. * Wrote it.
  1813. *****************************************************************************/
  1814. INT PUBLIC_PFTOBJ::QueryFonts(
  1815. PUNIVERSAL_FONT_ID pufi,
  1816. ULONG nBufferSize,
  1817. PLARGE_INTEGER pTimeStamp
  1818. )
  1819. {
  1820. ULONG cFonts = 0;
  1821. *pTimeStamp = PFTOBJ::FontChangeTime;
  1822. // if we aren't supplied with a buffer just return the time stamp and number
  1823. // of fonts
  1824. if( ( pufi == NULL ) || ( nBufferSize == 0 ) )
  1825. {
  1826. return(pPFT->cFiles + (UFI_TYPE1_RASTERIZER(&gufiLocalType1Rasterizer) ? 1 : 0));
  1827. }
  1828. PFF *pPFF;
  1829. SEMOBJ so(ghsemPublicPFT);
  1830. // Fill the first position with the identifier for the local rasterizer if one
  1831. // exists. This must be the first UFI in the list if it exists.
  1832. if(UFI_TYPE1_RASTERIZER(&gufiLocalType1Rasterizer))
  1833. {
  1834. pufi[cFonts++] = gufiLocalType1Rasterizer;
  1835. }
  1836. for (
  1837. PFF **ppPFF = pPFT->apPFF
  1838. ; (ppPFF < pPFT->apPFF + pPFT->cBuckets) && (cFonts < nBufferSize)
  1839. ; ppPFF++
  1840. )
  1841. {
  1842. for (pPFF = *ppPFF; (pPFF) && (cFonts<nBufferSize); pPFF = pPFF->pPFFNext)
  1843. {
  1844. // Create a PFF user object. There shouldn't be any invalid
  1845. // handles in the PFT.
  1846. PFFOBJ pffo(pPFF);
  1847. ASSERTGDI(pffo.bValid(),
  1848. "gdisrv!bUnloadFontPFTOBJ(file): bad PPFF in public PFT\n");
  1849. // be sure not to include remote fonts in list
  1850. if (!pffo.bDCRemote())
  1851. {
  1852. // Set the Index to 1. This value can be anything since we will only
  1853. // be using the UFI's passed back to determine if font file match.
  1854. // We could just pass back checksums but we may need to expand the
  1855. // UFI structure to include more than checksum's which is why I'm
  1856. // using UFI's.
  1857. pufi[cFonts].Index = 1;
  1858. pufi[cFonts++].CheckSum = pffo.ulCheckSum();
  1859. }
  1860. }
  1861. }
  1862. return(cFonts);
  1863. }
  1864. /******************************Public*Routine******************************\
  1865. * prfntKillList
  1866. *
  1867. * Scans the display PDEV list looking for inactive RFONTs that realized
  1868. * from the given PFF. These RFONTs are put into a linked list (using the
  1869. * PDEV RFONTLINKs) that is returned as the function return.
  1870. *
  1871. * The function is quite aggressinve in its definition of an inactive RFONT.
  1872. * In addition to looking for victims on the inactive list of each PDEV,
  1873. * the function also scans the DC list off each PDEV for RFONTs that are
  1874. * selected into currently unused DCs.
  1875. *
  1876. * We're not worried about being aggressive with non-display PDEVs. The
  1877. * PDEV cleanup code will destroy extraneous RFONTs directly using the PDEV's
  1878. * RFONT list(s).
  1879. *
  1880. * The reason we are building a list of RFONT victims rather than killing
  1881. * them immediately is because we are holding the ghsemPublicPFT semaphore
  1882. * when this function is called.
  1883. *
  1884. * Returns:
  1885. * Pointer to the kill list, NULL if the list is empty.
  1886. *
  1887. * History:
  1888. * 11-Mar-1993 -by- Gilman Wong [gilmanw]
  1889. * Wrote it.
  1890. \**************************************************************************/
  1891. static
  1892. RFONT *prfntKillList(PFFOBJ &pffoVictim)
  1893. {
  1894. TRACE_FONT((
  1895. "Entering prfntKillList\n\tpffoVictim.pPFF = %-#x\n",pffoVictim.pPFF));
  1896. RFONT *prfntDeadMeat = PRFNTNULL;
  1897. // Must hold this semaphore to be sure that the display
  1898. // PDEV list is stable.
  1899. SEMOBJ so1(ghsemDriverMgmt);
  1900. // Must hold this semaphore so we can manipulate the RFONT links and
  1901. // RFONT::cSelected.
  1902. SEMOBJ so2(ghsemRFONTList);
  1903. TRACE_FONT(("Acquiring ghsemRFONTList\n"));
  1904. // Must hold this mutex so that no one else tries to come in and lock
  1905. // a DC while we're scanning the DC lists off the PDEVs.
  1906. //
  1907. // Since we're holding this mutex, we must be extremely careful not
  1908. // to create any user objects that will try to regrab the mutex.
  1909. // That is bad bad bad bad.
  1910. MLOCKFAST mlf;
  1911. TRACE_FONT(("Acquiring handle management semaphore\n"));
  1912. PDEV *pPDEV = gppdevList;
  1913. // Scan through the list of display PDEVs.
  1914. while (pPDEV != NULL)
  1915. {
  1916. if (pPDEV->fl & PDEV_DISPLAY)
  1917. {
  1918. // Scan the RFONT active list for candidates made inactive by our
  1919. // scan of the DC list.
  1920. RFONT *prfntCandidate;
  1921. for ( prfntCandidate = pPDEV->prfntActive;
  1922. prfntCandidate != PRFNTNULL;
  1923. )
  1924. {
  1925. RFONTTMPOBJ rfo(prfntCandidate);
  1926. // We have to grab the next pointer before we (possibly)
  1927. // remove the current RFONT from the list.
  1928. prfntCandidate = prfntCandidate->rflPDEV.prfntNext;
  1929. // If this is an interesting RFONT (i.e., uses our PFF),
  1930. // then take it out of the list.
  1931. if ( (rfo.pPFF() == pffoVictim.pPFFGet()) && !rfo.bActive() )
  1932. {
  1933. RFONT *prfntHead = pffoVictim.prfntList();
  1934. rfo.vRemove(&prfntHead, PFF_LIST);
  1935. pffoVictim.prfntList(prfntHead);
  1936. rfo.vRemove(&pPDEV->prfntActive, PDEV_LIST);
  1937. rfo.vInsert(&prfntDeadMeat, PDEV_LIST);
  1938. }
  1939. }
  1940. // Scan the RFONT inactive list for candidates.
  1941. for (prfntCandidate = pPDEV->prfntInactive;
  1942. prfntCandidate != PRFNTNULL;
  1943. )
  1944. {
  1945. RFONTTMPOBJ rfo(prfntCandidate);
  1946. // We have to grab the next pointer before we (possibly)
  1947. // remove the current RFONT from the list.
  1948. prfntCandidate = prfntCandidate->rflPDEV.prfntNext;
  1949. // If this is an interesting RFONT (i.e., uses our PFF),
  1950. // then take it out of the list.
  1951. if ( rfo.pPFF() == pffoVictim.pPFFGet() )
  1952. {
  1953. RFONT *prfntHead = pffoVictim.prfntList();
  1954. rfo.vRemove(&prfntHead, PFF_LIST);
  1955. pffoVictim.prfntList(prfntHead);
  1956. rfo.vRemove(&pPDEV->prfntInactive, PDEV_LIST);
  1957. rfo.vInsert(&prfntDeadMeat, PDEV_LIST);
  1958. // Since we've removed a font from the inactive list, we
  1959. // need to update the count in the PDEV.
  1960. pPDEV->cInactive -= 1;
  1961. }
  1962. }
  1963. }
  1964. pPDEV = pPDEV->ppdevNext;
  1965. }
  1966. TRACE_FONT(("Releasing handle management semaphore\n"));
  1967. TRACE_FONT(("Releasing ghsemRFONTList\n"));
  1968. TRACE_FONT(("Releasing ghsemDriverMgmt\n"));
  1969. TRACE_FONT(("Exiting prfntKillList\n\treturn value=%-#x\n", prfntDeadMeat));
  1970. return(prfntDeadMeat);
  1971. }
  1972. /******************************Public*Routine******************************\
  1973. * bKillRFONTList
  1974. *
  1975. * Runs down a linked list (that is linked via the PDEV RFONTLINK's) and
  1976. * deletes each RFONT on it. Hold no global semaphores while calling this
  1977. * because we may call out to a driver.
  1978. *
  1979. * History:
  1980. * 11-Mar-1993 -by- Gilman Wong [gilmanw]
  1981. * Wrote it.
  1982. \**************************************************************************/
  1983. static
  1984. BOOL bKillRFONTList(PFFOBJ &pffoVictim, RFONT *prfntVictims)
  1985. {
  1986. // If kill list is NULL, it is already OK to delete the PFF.
  1987. // However, we will have to do the work in here rather than let
  1988. // RFONTOBJ::bDeleteRFONTRef() do the work for us.
  1989. BOOL bRet;
  1990. TRACE_FONT((
  1991. "Entering bKillRFONTList\n"
  1992. "\t*pffoVictim.pPFF=%-#x\n"
  1993. "\tprfntVictims=%-#x\n"
  1994. , pffoVictim.pPFF, prfntVictims
  1995. ));
  1996. if (prfntVictims == (PRFONT) NULL)
  1997. {
  1998. BOOL bCleanUp = FALSE;
  1999. PFFCLEANUP pffc;
  2000. {
  2001. // Need semaphore to access cRFONT.
  2002. SEMOBJ so(ghsemPublicPFT);
  2003. // If no more RFONTs for this PFF, OK to delete.
  2004. // Load count is implied to be zero
  2005. // (only time we call this function).
  2006. // For private/embedded fonts, pPvtDataHead needs to be NULL too.
  2007. ASSERTGDI( (pffoVictim.cLoaded() == 0 && pffoVictim.cNotEnum() == 0 && pffoVictim.pPvtDataHeadGet() == NULL),
  2008. "gdisrv!bKillRFONTList(): PFF load count not zero\n");
  2009. if (pffoVictim.cRFONT() == 0)
  2010. {
  2011. // It is now safe to delete the PFF.
  2012. pffoVictim.vPFFC_Delete(&pffc);
  2013. bCleanUp = TRUE;
  2014. }
  2015. }
  2016. // Call the driver outside of the semaphore.
  2017. if (bCleanUp)
  2018. {
  2019. vCleanupFontFile(&pffc); // function can handle NULL case
  2020. }
  2021. bRet = TRUE;
  2022. }
  2023. else
  2024. {
  2025. // Otherwise, we will delete the RFONTs in the kill list. If and when
  2026. // the last RFONT dies, RFONTOBJ::bDeleteRFONTRef() will delete the PFF.
  2027. PRFONT prfnt;
  2028. while ( (prfnt = prfntVictims) != (PRFONT) NULL )
  2029. {
  2030. prfntVictims = prfntVictims->rflPDEV.prfntNext;
  2031. RFONTTMPOBJ rflo(prfnt);
  2032. ASSERTGDI(!rflo.bActive(),
  2033. "gdisrv!bKillRFONTList(): RFONT still active\n");
  2034. PDEVOBJ pdo(rflo.hdevConsumer());
  2035. ASSERTGDI(pdo.bValid(), "gdisrv!bKillRFONTList(): invalid HPDEV\n");
  2036. rflo.bDeleteRFONT((PDEVOBJ *) NULL, (PFFOBJ *) NULL);
  2037. bRet = pffoVictim.bDeleteRFONTRef();
  2038. }
  2039. }
  2040. TRACE_FONT(("Exiting bKillRFONTList\n\treturn value = %d\n", bRet));
  2041. return(bRet);
  2042. }
  2043. /******************************Public*Routine******************************\
  2044. * cCapString (pwcDst,pwcSrc,cMax) *
  2045. * *
  2046. * A useful routine to capitalize a string. This is adapted to our name *
  2047. * strings that show up in logical fonts. They may or may not have NULL *
  2048. * terminators, but they always fit in a given width. *
  2049. * *
  2050. * We assume that we may overwrite the last character in the buffer if *
  2051. * there is no terminator! (That's what the code was doing when I got *
  2052. * to it.) *
  2053. * *
  2054. * Returns: The length, in characters, of the resultant string. *
  2055. * *
  2056. * History: *
  2057. * Sun 13-Dec-1992 17:22:25 -by- Charles Whitmer [chuckwh] *
  2058. * Wrote it. *
  2059. \**************************************************************************/
  2060. LONG cCapString(WCHAR *pwcDst, const WCHAR *pwcSrc,INT cMax)
  2061. {
  2062. UNICODE_STRING csSrc,csDst;
  2063. const WCHAR *pwc,*pwcEnd;
  2064. INT cLen;
  2065. // Count the length of the given string, but note that we can be given a
  2066. // string with cMax characters and no terminator!
  2067. // In that case, we truncate the last character and replace it with NULL.
  2068. pwc = pwcSrc;
  2069. pwcEnd = pwc + cMax - 1;
  2070. while (pwc<pwcEnd && *pwc)
  2071. pwc++;
  2072. // Sundown: cMax is int, pwcEnd = cMax -1, safe to truncate
  2073. cLen = (int)(pwc - pwcSrc); // cLen <= cMax-1, always.
  2074. if (cLen)
  2075. {
  2076. // Initialize the counted string structures.
  2077. csSrc.Length = (USHORT)(cLen * sizeof(WCHAR)); // Measured in bytes!
  2078. csSrc.Buffer = const_cast<WCHAR *>(pwcSrc);
  2079. csSrc.MaximumLength = (USHORT)(cMax * sizeof(WCHAR));
  2080. csDst.Buffer = pwcDst;
  2081. csDst.MaximumLength = (USHORT)(cMax * sizeof(WCHAR));
  2082. // Convert the string.
  2083. RtlUpcaseUnicodeString(&csDst,&csSrc,FALSE);
  2084. }
  2085. // NULL terminate the result.
  2086. pwcDst[cLen] = 0;
  2087. return(cLen);
  2088. }
  2089. /******************************Member*Function*****************************\
  2090. * UINT iHash *
  2091. * *
  2092. * A case dependent hashing routine for Unicode strings. *
  2093. * *
  2094. * Input: *
  2095. * *
  2096. * pwsz pointer to the string to be hashed *
  2097. * c number to be mod'ed against at the end *
  2098. * *
  2099. * Reutrns: *
  2100. * *
  2101. * a 'random' number in the range 0,1,...,c-1 *
  2102. * *
  2103. * Note: All strings must be capitalized! *
  2104. * *
  2105. * History: *
  2106. * Wed 07-Sep-1994 08:12:22 by Kirk Olynyk [kirko] *
  2107. * Since chuck is gone the mice are free to play. So I have replaced *
  2108. * it with my own variety. Tests show that this one is better. Of *
  2109. * course, once I have gone someone will replace mine. By the way, *
  2110. * just adding the letters and adding produces bad distributions. *
  2111. * Tue 15-Dec-1992 03:13:15 -by- Charles Whitmer [chuckwh] *
  2112. * Wrote it. It looks crazy, but I claim there's a theory behind it. *
  2113. \**************************************************************************/
  2114. static
  2115. UINT iHash(const WCHAR * pwsz, UINT c)
  2116. {
  2117. unsigned i = 0;
  2118. while (*pwsz)
  2119. {
  2120. // use the lower byte since that is where most of the
  2121. // interesting stuff happens
  2122. i += 256*i + (UCHAR) *pwsz++;
  2123. }
  2124. return(i % c);
  2125. }
  2126. /******************************Member*Function*****************************\
  2127. * FHOBJ::vInit *
  2128. * *
  2129. * History: *
  2130. * Mon 14-Dec-1992 18:38:35 -by- Charles Whitmer [chuckwh] *
  2131. * Compressed the table to contain only pointers to buckets. *
  2132. * *
  2133. * Tue 14-Apr-1992 13:48:53 by Kirk Olynyk [kirko] *
  2134. * Wrote it. *
  2135. \**************************************************************************/
  2136. VOID FHOBJ::vInit(FONTHASHTYPE fht_,UINT c)
  2137. {
  2138. pfh->id = FONTHASH_ID;
  2139. pfh->fht = fht_;
  2140. pfh->cBuckets = c;
  2141. // Currently, none of the buckets are in use
  2142. pfh->cUsed = 0;
  2143. pfh->cCollisions = 0;
  2144. RtlZeroMemory(pfh->apbkt,sizeof(*(pfh->apbkt)) * pfh->cBuckets);
  2145. // Setup head and tail pointers to the doubly linked list of
  2146. // buckets. This list is maintained in load order. The ordinal
  2147. // of a bucket is the load time of the earliest loaded PFE in a
  2148. // bucket's list.
  2149. pfh->pbktFirst = (HASHBUCKET *) NULL;
  2150. pfh->pbktLast = (HASHBUCKET *) NULL;
  2151. }
  2152. /******************************Member*Function*****************************\
  2153. * FHOBJ::vFree *
  2154. * *
  2155. * History: *
  2156. * Tue 15-Dec-1992 00:53:39 -by- Charles Whitmer [chuckwh] *
  2157. * Deletes remaining hash buckets. *
  2158. * *
  2159. * Tue 14-Apr-1992 13:48:56 by Kirk Olynyk [kirko] *
  2160. * Wrote it. *
  2161. \**************************************************************************/
  2162. VOID FHOBJ::vFree()
  2163. {
  2164. HASHBUCKET *pbkt,*pbktNext;
  2165. if (pfh)
  2166. {
  2167. // Unfortunately, we get called here while a string of PFE's may be
  2168. // hanging on. One of the PFTOBJ::bUnloadFont calls kills the PFE's
  2169. // separately.
  2170. // We still need to free the small pfel bloks that
  2171. // define enumeration links
  2172. // Clean up any hash buckets.
  2173. for (UINT ii=0; ii<pfh->cBuckets; ii++)
  2174. {
  2175. for
  2176. (
  2177. pbkt = pfh->apbkt[ii];
  2178. pbkt != (HASHBUCKET *) NULL;
  2179. pbkt = pbktNext
  2180. )
  2181. {
  2182. pbktNext = pbkt->pbktCollision;
  2183. // now free the small linking blocks:
  2184. {
  2185. PFELINK *ppfel = pbkt->ppfelEnumHead;
  2186. PFELINK *ppfelNext;
  2187. for ( ; ppfel ; ppfel = ppfelNext)
  2188. {
  2189. ppfelNext = ppfel->ppfelNext;
  2190. VFREEMEM(ppfel);
  2191. #if DBG
  2192. if (ppfelNext == NULL)
  2193. {
  2194. ASSERTGDI(ppfel == pbkt->ppfelEnumTail,
  2195. "FHOBJ::vFree(), problem with ppfelEnumTail\n");
  2196. }
  2197. #endif
  2198. }
  2199. }
  2200. VFREEMEM(pbkt);
  2201. }
  2202. }
  2203. // Free the table itself.
  2204. VFREEMEM(pfh);
  2205. }
  2206. pfh = 0;
  2207. *ppfh = 0;
  2208. }
  2209. /******************************Member*Function*****************************\
  2210. * FHOBJ::pbktSearch (pwsz,pi) *
  2211. * *
  2212. * Tries to locate a HASHBUCKET for the given string. If found, a pointer *
  2213. * is returned, else NULL. If pi is non-NULL, the hash index is returned *
  2214. * in either case. *
  2215. * *
  2216. * History: *
  2217. * Mon 14-Dec-1992 21:11:14 -by- Charles Whitmer [chuckwh] *
  2218. * Wrote it. Differs from KirkO's old iSearch in that it assumes that all *
  2219. * strings are capitalized, and the hash table is full of pointers to *
  2220. * HASHBUCKETs instead of HASHBUCKETs. *
  2221. \**************************************************************************/
  2222. HASHBUCKET *FHOBJ::pbktSearch(const WCHAR * pwsz,UINT *pi,PUNIVERSAL_FONT_ID pufi, BOOL bEquiv)
  2223. {
  2224. UINT i;
  2225. HASHBUCKET *pbkt;
  2226. // If we are requested to look only for equivalency buckets, and we find it,
  2227. // we shall return it.
  2228. // If we are asked to look for any kind of bucket, and we found equivalency
  2229. // bucket first in the linked list, we shall continue to search the linked
  2230. // list until we possibly find a non-equivalency bucket. If found both
  2231. // equivalency and non-equivalency bucket, we return non-equivalency bucket.
  2232. // If we find a non-equivalency bucket, we shall just return.
  2233. HASHBUCKET *pbktEquiv = NULL;
  2234. // Locate the hash entry.
  2235. if( pwsz == NULL )
  2236. {
  2237. if( pufi == NULL )
  2238. {
  2239. return NULL;
  2240. }
  2241. i = UFI_HASH_VALUE(pufi) % pfh->cBuckets;
  2242. }
  2243. else
  2244. {
  2245. i = iHash(pwsz,pfh->cBuckets);
  2246. }
  2247. // Return the index for those who care.
  2248. if (pi != (UINT *) NULL)
  2249. *pi = i;
  2250. // Try to find an existing bucket that matches exactly.
  2251. for
  2252. (
  2253. pbkt = pfh->apbkt[i];
  2254. pbkt != (HASHBUCKET *) NULL;
  2255. pbkt = pbkt->pbktCollision
  2256. )
  2257. {
  2258. if( pufi != NULL )
  2259. {
  2260. if( UFI_SAME_FILE(&pbkt->u.ufi,pufi) )
  2261. {
  2262. return(pbkt);
  2263. }
  2264. }
  2265. else
  2266. {
  2267. if (!bEquiv || (pbkt->fl & HB_EQUIV_FAMILY))
  2268. {
  2269. const WCHAR *pwcA,*pwcB;
  2270. for (pwcA=pwsz,pwcB=pbkt->u.wcCapName; *pwcA==*pwcB; pwcA++,pwcB++)
  2271. {
  2272. if (*pwcA == 0)
  2273. {
  2274. if (bEquiv)
  2275. {
  2276. return(pbkt);
  2277. }
  2278. else
  2279. {
  2280. if (pbkt->fl & HB_EQUIV_FAMILY)
  2281. {
  2282. pbktEquiv = pbkt;
  2283. break;
  2284. }
  2285. else
  2286. {
  2287. return(pbkt);
  2288. }
  2289. }
  2290. }
  2291. }
  2292. }
  2293. }
  2294. }
  2295. return(pbktEquiv);
  2296. }
  2297. /******************************Public*Routine******************************\
  2298. *
  2299. * BOOL FHOBJ::bAddPFELink
  2300. *
  2301. * History:
  2302. * 02-Jul-1997 -by- Bodin Dresevic [BodinD]
  2303. * Wrote it.
  2304. \**************************************************************************/
  2305. BOOL FHOBJ::bAddPFELink(
  2306. HASHBUCKET *pbkt, // pointer to bucket with this family name/ufi (if found)
  2307. UINT iBucket, // index into hash table for this pfe
  2308. WCHAR *pwcCap, // capitalized family name
  2309. PFEOBJ& pfeoNew, // pfe for which we are adding the link
  2310. BOOL bEquiv // create equiv or non-equivalency bucket
  2311. )
  2312. {
  2313. PFELINK *ppfel = NULL;
  2314. if (ppfel = (PFELINK *)PALLOCMEM(sizeof(PFELINK), 'knlG'))
  2315. {
  2316. ppfel->ppfelNext = NULL; // we have just added it;
  2317. ppfel->ppfe = pfeoNew.ppfeGet();
  2318. // we will create a new bucket if the bucket with this face name does not exist
  2319. // or if we are attempting to create a non-equivalency bucket and we have only
  2320. // found an equivalency name bucket with this family name.
  2321. if ((pbkt == (HASHBUCKET *) NULL) || (!bEquiv && (pbkt->fl & HB_EQUIV_FAMILY)))
  2322. {
  2323. pbkt = (HASHBUCKET *) PALLOCMEM(sizeof(HASHBUCKET), 'bahG');
  2324. if (pbkt == (HASHBUCKET *) NULL)
  2325. {
  2326. VFREEMEM(ppfel);
  2327. return(FALSE);
  2328. }
  2329. // Link the PFE into the empty lists.
  2330. pbkt->ppfelEnumHead = pbkt->ppfelEnumTail = ppfel;
  2331. // Set up the linked list pointers. We always add new buckets at the
  2332. // tail of the load order linked list.
  2333. if ( pfh->pbktFirst == (HASHBUCKET *) NULL )
  2334. {
  2335. // Special case: this is the first bucket to be put on the list.
  2336. pfh->pbktFirst = pbkt;
  2337. pfh->pbktLast = pbkt;
  2338. pbkt->pbktPrev = (HASHBUCKET *) NULL;
  2339. pbkt->pbktNext = (HASHBUCKET *) NULL;
  2340. }
  2341. else
  2342. {
  2343. pbkt->pbktPrev = pfh->pbktLast;
  2344. pbkt->pbktNext = (HASHBUCKET *) NULL;
  2345. pfh->pbktLast->pbktNext = pbkt;
  2346. pfh->pbktLast = pbkt;
  2347. }
  2348. // Record the time stamp of the bucket. Its time stamp is the
  2349. // time stamp of its oldest (or first) PFE. Since this is a new
  2350. // bucket, the time stamp is automatically that of pfeoNew.
  2351. pbkt->ulTime = pfeoNew.ulTimeStamp();
  2352. // Finish up.
  2353. pbkt->fl = bEquiv ? HB_EQUIV_FAMILY : 0;
  2354. pbkt->cTrueType = (pfeoNew.flFontType() & TRUETYPE_FONTTYPE) ? 1 : 0;
  2355. pbkt->cRaster = (pfeoNew.flFontType() & RASTER_FONTTYPE) ? 1 : 0;
  2356. // Copy in the string.
  2357. if( fht() == FHT_UFI )
  2358. {
  2359. pfeoNew.vUFI( &(pbkt->u.ufi) );
  2360. }
  2361. else
  2362. {
  2363. for (INT ii=0; ii<LF_FACESIZE; ii++)
  2364. pbkt->u.wcCapName[ii] = pwcCap[ii];
  2365. }
  2366. // link the bucket into the hash table.
  2367. pbkt->pbktCollision = pfh->apbkt[iBucket];
  2368. if (pbkt->pbktCollision != (HASHBUCKET *) NULL)
  2369. pfh->cCollisions++;
  2370. pfh->apbkt[iBucket] = pbkt;
  2371. pfh->cUsed++;
  2372. }
  2373. else
  2374. {
  2375. // In the following we have found an existing HASHBUCKET.
  2376. // We can assume that its lists are non-empty.
  2377. // Insert into the font enumeration list. The new PFE is inserted at
  2378. // the tail because we want to preserve the order in which fonts are
  2379. // added to the system (Windows 3.1 compatibility).
  2380. // Append new PFELINK to old tail and fixup the tail pointer
  2381. pbkt->ppfelEnumTail->ppfelNext = ppfel;
  2382. pbkt->ppfelEnumTail = ppfel;
  2383. // Track the number of TrueType fonts.
  2384. if (pfeoNew.flFontType() & TRUETYPE_FONTTYPE)
  2385. pbkt->cTrueType++;
  2386. // Track the number of Raster fonts.
  2387. if (pfeoNew.flFontType() & RASTER_FONTTYPE)
  2388. pbkt->cRaster++;
  2389. }
  2390. }
  2391. return (ppfel != NULL);
  2392. }
  2393. /******************************Member*Function*****************************\
  2394. * FHOBJ::bInsert *
  2395. * *
  2396. * Insert a new PFE into the font hash table. *
  2397. * *
  2398. * History: *
  2399. * Mon 14-Dec-1992 22:51:22 -by- Charles Whitmer [chuckwh] *
  2400. * Moved HASHBUCKETs out of the hash table. We now create them as needed. *
  2401. * *
  2402. * 06-Aug-1992 00:43:37 by Gilman Wong [gilmanw] *
  2403. * Added support for font enumeration list. *
  2404. * *
  2405. * Tue 14-Apr-1992 13:49:24 by Kirk Olynyk [kirko] *
  2406. * Wrote it. *
  2407. \**************************************************************************/
  2408. BOOL FHOBJ::bInsert(PFEOBJ& pfeoNew)
  2409. {
  2410. // Capitalize the given string. We will always match on the capitalized
  2411. // string.
  2412. WCHAR wcCap[LF_FACESIZE];
  2413. HASHBUCKET *pbkt;
  2414. UINT iBucket;
  2415. // Insert into facename hash only if the typographic face name
  2416. // is different from the typeographic family name. Case insensitive
  2417. // since searching in the font hash table is case insensitive.
  2418. if ((fht() == FHT_FACE) &&
  2419. !_wcsicmp(pfeoNew.pwszFaceName(),pfeoNew.pwszFamilyName()))
  2420. {
  2421. return TRUE; // nothing to do.
  2422. }
  2423. if( fht() == FHT_UFI )
  2424. {
  2425. UNIVERSAL_FONT_ID ufi;
  2426. pfeoNew.vUFI( &ufi );
  2427. pbkt = pbktSearch(NULL,&iBucket,&ufi);
  2428. }
  2429. else
  2430. {
  2431. cCapString(wcCap,pwszName(pfeoNew),LF_FACESIZE);
  2432. // Locate the hashbucket.
  2433. pbkt = pbktSearch(wcCap,&iBucket);
  2434. }
  2435. // link the pfe into appropriate lists:
  2436. if (!bAddPFELink(pbkt, iBucket, wcCap, pfeoNew, FALSE))
  2437. return FALSE;
  2438. // Do we need to add equivalence buckets for this pfe to the hash table?
  2439. // This way the same pfe may show up in linked lists hanging off several buckets.
  2440. if ( pfeoNew.bEquivNames() && (fht() == FHT_FAMILY) )
  2441. {
  2442. HASHBUCKET *pbktEquiv;
  2443. PWSZ pwszEquivName = pwszName(pfeoNew);
  2444. // Skip to first equiv name.
  2445. while (*pwszEquivName++);
  2446. // Process each equiv. name until we hit the list terminator (NULL).
  2447. while (*pwszEquivName)
  2448. {
  2449. // Capitalize the name.
  2450. cCapString(wcCap,pwszEquivName,LF_FACESIZE);
  2451. // Locate the hashbucket. We only search for equiv buckets
  2452. pbktEquiv = pbktSearch(wcCap,&iBucket, NULL, TRUE);
  2453. if (!bAddPFELink(pbktEquiv, iBucket, wcCap, pfeoNew, TRUE))
  2454. return FALSE;
  2455. // Skip to next name.
  2456. while (*pwszEquivName++);
  2457. }
  2458. }
  2459. return(TRUE);
  2460. }
  2461. /******************************Public*Routine******************************\
  2462. *
  2463. * VOID FHOBJ::vDeletePFELink(HASHBUCKET *phbkt, PFEOBJ& pfeoV)
  2464. *
  2465. * Delete pfe from the linked list hanging off the bucket and possibly
  2466. * also remove the bucket itself, after removing the last pfe from the llist
  2467. *
  2468. * History:
  2469. * 27-Jun-1997 -by- Bodin Dresevic [BodinD]
  2470. * Wrote it.
  2471. \**************************************************************************/
  2472. VOID FHOBJ::vDeletePFELink(HASHBUCKET *phbkt, UINT iBucket, PFEOBJ& pfeoV)
  2473. {
  2474. // Capitalize the search string.
  2475. PFELINK *ppfel, *ppfelV = NULL;
  2476. #if DBG
  2477. BOOL bFoundVictim; // used only for debugging
  2478. #endif
  2479. // Does the list exist? It is possible that on the facename list this PFE
  2480. // may not exist. The set of PFEs in the facename list is a subset of the
  2481. // set of PFEs in the family name list.
  2482. // Return if there is no list.
  2483. if (phbkt == (HASHBUCKET *) NULL)
  2484. {
  2485. // ASSERTGDI(fht() == FHT_FACE, "trying to remove nonexisting pfe\n");
  2486. return;
  2487. }
  2488. // ----------------------------------
  2489. // Remove from font enumeration list.
  2490. // ----------------------------------
  2491. // Check for special case: victim is at the head of list.
  2492. if (phbkt->ppfelEnumHead->ppfe == pfeoV.ppfeGet())
  2493. {
  2494. // remember the pointer, we shall have to free the mem;
  2495. ppfelV = phbkt->ppfelEnumHead;
  2496. // Victim found, new head of list.
  2497. phbkt->ppfelEnumHead = phbkt->ppfelEnumHead->ppfelNext;
  2498. // Tail check. List may now be empty, so we may need to adjust tail.
  2499. if (phbkt->ppfelEnumHead == NULL)
  2500. {
  2501. phbkt->ppfelEnumTail = NULL;
  2502. }
  2503. }
  2504. else
  2505. {
  2506. // If we're here, victim is either in the middle or end of the list.
  2507. ppfel = phbkt->ppfelEnumHead;
  2508. #if DBG
  2509. bFoundVictim = FALSE;
  2510. #endif
  2511. // Search loop; look for victim on the linked list.
  2512. while (ppfel->ppfelNext)
  2513. {
  2514. if (ppfel->ppfelNext->ppfe == pfeoV.ppfeGet())
  2515. {
  2516. // Victim found.
  2517. ppfelV = ppfel->ppfelNext;
  2518. ppfel->ppfelNext = ppfelV->ppfelNext;
  2519. #if DBG
  2520. bFoundVictim = TRUE;
  2521. #endif
  2522. // Tail check. If victim is also the tail, we need a new tail.
  2523. if (ppfelV->ppfelNext == NULL)
  2524. {
  2525. ASSERTGDI(phbkt->ppfelEnumTail == ppfelV, "ppfelEnumTail problem");
  2526. phbkt->ppfelEnumTail = ppfel;
  2527. }
  2528. // Get out of search loop.
  2529. break;
  2530. }
  2531. ppfel = ppfel->ppfelNext;
  2532. }
  2533. // PFE must exist somewhere on the list.
  2534. // We saw the case where PFE doesn't exist in the list on Hydra
  2535. // Somehow pffmo.bAddHash failed in bLoadFonts which caused the
  2536. // pffmo.vRemoveHash was called right after.
  2537. }
  2538. if (ppfelV)
  2539. {
  2540. // free the link itself
  2541. VFREEMEM(ppfelV);
  2542. //
  2543. // Track the number of TrueType fonts.
  2544. //
  2545. if (pfeoV.flFontType() & TRUETYPE_FONTTYPE)
  2546. {
  2547. phbkt->cTrueType--;
  2548. }
  2549. //
  2550. // Track the number of Raster fonts.
  2551. //
  2552. if (pfeoV.flFontType() & RASTER_FONTTYPE)
  2553. {
  2554. phbkt->cRaster--;
  2555. }
  2556. //
  2557. // If the bucket has no PFE's attached, delete it.
  2558. //
  2559. if (phbkt->ppfelEnumHead == NULL)
  2560. {
  2561. //
  2562. // We have to remove the HASHBUCKET from the load order linked list.
  2563. //
  2564. if ( phbkt->pbktPrev )
  2565. {
  2566. phbkt->pbktPrev->pbktNext = phbkt->pbktNext;
  2567. }
  2568. else
  2569. {
  2570. pfh->pbktFirst = phbkt->pbktNext; // new head of list
  2571. }
  2572. if ( phbkt->pbktNext )
  2573. {
  2574. phbkt->pbktNext->pbktPrev = phbkt->pbktPrev;
  2575. }
  2576. else
  2577. {
  2578. pfh->pbktLast = phbkt->pbktPrev; // new tail of list
  2579. }
  2580. // We also have to remove the HASHBUCKET from the collision list.
  2581. for
  2582. (
  2583. HASHBUCKET **ppbkt = &pfh->apbkt[iBucket];
  2584. *ppbkt != phbkt;
  2585. ppbkt = &((*ppbkt)->pbktCollision)
  2586. )
  2587. {}
  2588. *ppbkt = phbkt->pbktCollision;
  2589. // Reduce the counts in the hash table.
  2590. pfh->cUsed--;
  2591. if (pfh->apbkt[iBucket])
  2592. {
  2593. pfh->cCollisions--;
  2594. }
  2595. // Delete the HASHBUCKET.
  2596. VFREEMEM(phbkt);
  2597. }
  2598. else
  2599. {
  2600. // If we haven't deleted the bucket,
  2601. // check to see if its time stamp should be changed.
  2602. // The time stamp of a bucket is the time stamp of its oldest
  2603. // PFE. Since the font enumeration PFE list is also maintained
  2604. // in load order, the bucket time stamp is equivalent to the time
  2605. // stamp of the first bucket in its font enumeration list.
  2606. if ( phbkt->ulTime == phbkt->ppfelEnumHead->ppfe->ulTimeStamp )
  2607. {
  2608. // If the time stamps are equal, the head of the list was not
  2609. // deleted. Therefore, the position of this bucket in the
  2610. // load order list has not changed and we are done.
  2611. return;
  2612. }
  2613. // Update the time stamp.
  2614. phbkt->ulTime = phbkt->ppfelEnumHead->ppfe->ulTimeStamp;
  2615. // The bucket can only get younger if the head of the list is removed.
  2616. // Therefore we need only probe forward for the new position of the
  2617. // hash bucket.
  2618. // We will stop the scan when we are pointing at the bucket that
  2619. // precedes the new position.
  2620. for ( HASHBUCKET *pbktProbe = phbkt;
  2621. (pbktProbe->pbktNext != (HASHBUCKET *) NULL)
  2622. && (pbktProbe->pbktNext->ulTime < phbkt->ulTime);
  2623. pbktProbe = pbktProbe->pbktNext
  2624. );
  2625. // If we found a new position and it isn't the one we already occupy,
  2626. // move the bucket.
  2627. if (pbktProbe != phbkt)
  2628. {
  2629. // Remove the bucket from its current position.
  2630. if (phbkt->pbktPrev )
  2631. {
  2632. phbkt->pbktPrev->pbktNext = phbkt->pbktNext;
  2633. }
  2634. else
  2635. {
  2636. pfh->pbktFirst = phbkt->pbktNext; // new head of list
  2637. }
  2638. if (phbkt->pbktNext )
  2639. {
  2640. phbkt->pbktNext->pbktPrev = phbkt->pbktPrev;
  2641. }
  2642. // It is not necessary to handle the case of a new tail
  2643. // because if this were the current tail, we would not be
  2644. // attempting to move it.
  2645. // Insert at its new position. Remember: pbktProbe is pointing to
  2646. // the bucket that should precede this one.
  2647. phbkt->pbktPrev = pbktProbe;
  2648. phbkt->pbktNext = pbktProbe->pbktNext;
  2649. pbktProbe->pbktNext = phbkt;
  2650. if (phbkt->pbktNext )
  2651. {
  2652. phbkt->pbktNext->pbktPrev = phbkt;
  2653. }
  2654. else
  2655. {
  2656. pfh->pbktLast = phbkt; // new tail for the list
  2657. }
  2658. }
  2659. }
  2660. }
  2661. }
  2662. /******************************Member*Function*****************************\
  2663. * FHOBJ::vDelete *
  2664. * *
  2665. * Removes a PFE from all the lists hanging off the hash table. *
  2666. * *
  2667. * History: *
  2668. *
  2669. * Fri 27-Jun-1997 -by- Bodin Dresevic [BodinD]
  2670. * update:
  2671. * Added removing pfe's from equivalency buckets, I think this was missing
  2672. *
  2673. * Mon 14-Dec-1992 23:39:28 -by- Charles Whitmer [chuckwh] *
  2674. * Changed to search for buckets. Made it delete the bucket at the end, *
  2675. * instead of reconstructing the whole table. *
  2676. * *
  2677. * 06-Aug-1992 00:43:37 by Gilman Wong [gilmanw] *
  2678. * New deletion algorithm. Also, added support for font enumeration list. *
  2679. * *
  2680. * Tue 14-Apr-1992 13:49:05 by Kirk Olynyk [kirko] *
  2681. * Wrote it. *
  2682. \**************************************************************************/
  2683. VOID FHOBJ::vDelete(PFEOBJ& pfeoV)
  2684. {
  2685. // Capitalize the search string.
  2686. WCHAR wcCapName[LF_FACESIZE];
  2687. UINT iBucket;
  2688. HASHBUCKET *phbkt;
  2689. // Delete from facename hash only if the typographic face name
  2690. // is different from the typeographic family name. Case insensitive
  2691. // since searching in the font hash table is case insensitive.
  2692. if ((fht() == FHT_FACE) &&
  2693. !_wcsicmp(pfeoV.pwszFaceName(),pfeoV.pwszFamilyName()))
  2694. {
  2695. return; // nothing to do.
  2696. }
  2697. if( fht() == FHT_UFI )
  2698. {
  2699. UNIVERSAL_FONT_ID ufi;
  2700. pfeoV.vUFI( &ufi );
  2701. phbkt = pbktSearch(NULL,&iBucket,&ufi);
  2702. }
  2703. else
  2704. {
  2705. cCapString(wcCapName,pwszName(pfeoV),LF_FACESIZE);
  2706. // Determine hash position in the table.
  2707. phbkt = pbktSearch(wcCapName,&iBucket);
  2708. }
  2709. vDeletePFELink(phbkt,iBucket,pfeoV);
  2710. // this pfe may need to be deleted from the lists hanging off of
  2711. // equivalency buckets:
  2712. if (pfeoV.bEquivNames() && (fht() == FHT_FAMILY))
  2713. {
  2714. HASHBUCKET *pbktEquiv;
  2715. PWSZ pwszEquivName = pwszName(pfeoV);
  2716. // Skip to first equiv name.
  2717. while (*pwszEquivName++);
  2718. // Process each equiv. name until we hit the list terminator (NULL).
  2719. while (*pwszEquivName)
  2720. {
  2721. // Capitalize the name.
  2722. cCapString(wcCapName,pwszEquivName,LF_FACESIZE);
  2723. // Locate the hashbucket. Only search for equivalency buckets
  2724. pbktEquiv = pbktSearch(wcCapName,&iBucket, NULL, TRUE);
  2725. vDeletePFELink(pbktEquiv,iBucket,pfeoV);
  2726. // Skip to next name.
  2727. while (*pwszEquivName++);
  2728. }
  2729. }
  2730. }
  2731. /******************************Public*Routine******************************\
  2732. * ENUMFONTSTYLE efsCompute(BOOL *abFoundStyle, PFEOBJ &pfeo)
  2733. *
  2734. * Computes a font enumeration style category for the given pfeo.
  2735. *
  2736. * An array of flags, abFoundStyle, is passed in. There is a flag
  2737. * for each style classification returned by PFEOBJ::efsCompute().
  2738. *
  2739. * These flags are set as PFEs for each category are found.
  2740. * Once a category is filled, then all subsequent fonts of the
  2741. * same category are marked as either EFSTYLE_OTHER (if facename
  2742. * is different than family name, thereby allowing us to use it
  2743. * to distinguish from other fonts of this family) or EFSTYLE_SKIP
  2744. * (if facename is the same as the family name).
  2745. *
  2746. * This is to support Win 3.1 EnumFonts() behavior which can only
  2747. * discriminate 4 different styles for each family of fonts.
  2748. *
  2749. * History:
  2750. * 07-Aug-1992 -by- Gilman Wong [gilmanw]
  2751. * Wrote it.
  2752. \**************************************************************************/
  2753. ENUMFONTSTYLE efstyCompute(BOOL *abFoundStyle, PFEOBJ &pfeo)
  2754. {
  2755. ENUMFONTSTYLE efsty = pfeo.efstyCompute();
  2756. if ( !abFoundStyle[efsty] )
  2757. {
  2758. abFoundStyle[efsty] = TRUE;
  2759. }
  2760. else
  2761. {
  2762. if ( _wcsicmp(pfeo.pwszFamilyName(), pfeo.pwszFaceName()) )
  2763. {
  2764. efsty = EFSTYLE_OTHER;
  2765. }
  2766. else
  2767. {
  2768. efsty = EFSTYLE_SKIP;
  2769. }
  2770. }
  2771. return efsty;
  2772. }
  2773. /******************************Member*Function*****************************\
  2774. * BOOL FHOBJ::bScanLists *
  2775. * *
  2776. * This implements the behavior of EnumFonts() and EnumFontFamilies() when *
  2777. * a NULL name is passed in. If the bComputeStyles flag is TRUE, the *
  2778. * EnumFonts() behavior of enumerating some fonts by their facename (rather *
  2779. * than family name) is used. *
  2780. * *
  2781. * This function puts HPFEs from the hash table and lists into the EFSOBJ. *
  2782. * If bComputeStyles is FALSE, only the font enumeration list heads from *
  2783. * each bucket are added to the EFSOBJ. *
  2784. * *
  2785. * If bComputeStyles is TRUE, then each list is scanned and a style *
  2786. * classification (EFSTYLE) is computed. Fonts classified as EFSTYLE_OTHER *
  2787. * are also added to the EFSOBJ. *
  2788. * *
  2789. * Return: *
  2790. * Returns FALSE if an error occurs; TRUE otherwise. *
  2791. * *
  2792. * History: *
  2793. * 15-Jan-1993 -by- Gilman Wong [gilmanw] *
  2794. * Changed to use the linked list that preserves PFE load order for outer *
  2795. * loop. *
  2796. * *
  2797. * Mon 14-Dec-1992 23:50:10 -by- Charles Whitmer [chuckwh] *
  2798. * Changed outer loop logic for new hashing. *
  2799. * *
  2800. * 07-Aug-1992 -by- Gilman Wong [gilmanw] *
  2801. * Wrote it. *
  2802. \**************************************************************************/
  2803. BOOL FHOBJ::bScanLists (
  2804. EFSOBJ *pefso, // fill this EFSOBJ
  2805. ULONG iEnumType, // Enum Fonts, Families or FamiliesEx
  2806. EFFILTER_INFO *peffi // filtering information
  2807. )
  2808. {
  2809. HASHBUCKET *phbkt;
  2810. // better C++ code generation if you always return a variable
  2811. BOOL bRet = FALSE;
  2812. FLONG flAdd = 0;
  2813. PFELINK *ppfel;
  2814. if (iEnumType == TYPE_ENUMFONTFAMILIES)
  2815. flAdd |= FL_ENUMFAMILIES;
  2816. if (iEnumType == TYPE_ENUMFONTFAMILIESEX)
  2817. flAdd |= FL_ENUMFAMILIESEX;
  2818. // Scan through the hash table using the load ordered linked list.
  2819. for (phbkt = pfh->pbktFirst;
  2820. phbkt != (HASHBUCKET *) NULL;
  2821. phbkt = phbkt->pbktNext
  2822. )
  2823. {
  2824. // If the list exists, need to scan it. We skip over equiv. name
  2825. // HASHBUCKETs. These are here only to allow the mapper to alias
  2826. // printer font names to other "equivlaent" names. We do not
  2827. // enumerate them.
  2828. if (
  2829. phbkt->ppfelEnumHead
  2830. && !(phbkt->fl & HB_EQUIV_FAMILY)
  2831. )
  2832. {
  2833. ppfel = phbkt->ppfelEnumHead;
  2834. PFEOBJ pfeo(ppfel->ppfe);
  2835. ASSERTGDI (
  2836. pfeo.bValid(),
  2837. "gdisrv!bScanListsFHOBJ(NULL): bad HPFE handle\n"
  2838. );
  2839. // This flag is used only if bComputeStyles is TRUE (i.e.,
  2840. // processing an EnumFonts() request). We use this to track
  2841. // whether or not the first suitable font in the list is found
  2842. // yet. The first font PLUS fonts that are EFSTYLE_OTHER
  2843. // are put in the enumeration.
  2844. BOOL bFoundFirst = FALSE;
  2845. // These flags are set as PFEs for each category are found.
  2846. // Once a category is filled, then all subsequent fonts of the
  2847. // same category are marked as either EFSTYLE_OTHER (if facename
  2848. // is different than family name, thereby allowing us to use it
  2849. // to distinguish from other fonts of this family) or EFSTYLE_SKIP
  2850. // (if facename is the same as the family name).
  2851. //
  2852. // This is to support Win 3.1 EnumFonts() behavior which can only
  2853. // discriminate 4 different styles for each family of fonts.
  2854. BOOL abFoundStyle[EFSTYLE_MAX];
  2855. RtlZeroMemory((PVOID) abFoundStyle, EFSTYLE_MAX * sizeof(BOOL));
  2856. // Windows 3.1 compatibility
  2857. //
  2858. // When NULL is passed into EnumFonts or EnumFontFamilies,
  2859. // raster fonts are not enumerated if a TrueType font of the same
  2860. // name exists. We can emulate this behavior by turning on
  2861. // the "TrueType duplicate" filter (the same one used by the
  2862. // (GACF_TTIGNORERASTERDUPE app compatibility flag) for the NULL case.
  2863. peffi->bTrueTypeDupeFilter = TRUE;
  2864. // Win3.1 App compatibility flag GACF_TTIGNORERASTERDUPE. Need
  2865. // to copy count of TrueType from bucket into EFFILTER_INFO, peffi.
  2866. peffi->cTrueType = phbkt->cTrueType;
  2867. // Scan the list for candidates.
  2868. do
  2869. {
  2870. pfeo.ppfeSet(ppfel); // "relock" ppfe;
  2871. // Skip this PFE if it needs to be filtered out.
  2872. if ( pfeo.bFilteredOut(peffi) )
  2873. continue;
  2874. // EnumFonts() or EnumFontFamilies() processing (bComputeStyles
  2875. // is TRUE for EnumFonts()).
  2876. if (iEnumType != TYPE_ENUMFONTS)
  2877. {
  2878. // EnumFontFamilies --
  2879. // Need only the first one on the list.
  2880. if (!pefso->bAdd(pfeo.ppfeGet(),EFSTYLE_REGULAR,flAdd,peffi->lfCharSetFilter))
  2881. {
  2882. // Error return. bAdd() will set error code.
  2883. WARNING(
  2884. "gdisrv!bScanListsFHOBJ(NULL): "
  2885. "abandon enum, cannot grow list\n"
  2886. );
  2887. return bRet;
  2888. }
  2889. // Break out of the do..while loop.
  2890. //
  2891. break;
  2892. }
  2893. else
  2894. {
  2895. // Compute the style category for this PFE.
  2896. ENUMFONTSTYLE efsty = efstyCompute(abFoundStyle, pfeo);
  2897. // EnumFonts --
  2898. // If style is EFSTYLE_OTHER, this font falls into an already
  2899. // occupied category but it has a facename that allow it to be
  2900. // distinguished from other fonts of this family. So it
  2901. // should be added.
  2902. //
  2903. if ( !bFoundFirst || (efsty == EFSTYLE_OTHER) )
  2904. {
  2905. if (!pefso->bAdd(pfeo.ppfeGet(),efsty))
  2906. {
  2907. // Error return. bAdd() will set error code.
  2908. WARNING(
  2909. "gdisrv!bScanListsFHOBJ(NULL): "
  2910. "abandon enum, cannot grow list\n");
  2911. return bRet;
  2912. }
  2913. //
  2914. // First one has been found. From now on, we will only
  2915. // take EFSTYLE_OTHER fonts.
  2916. //
  2917. bFoundFirst = TRUE;
  2918. }
  2919. }
  2920. } while (ppfel = ppfel->ppfelNext);
  2921. }
  2922. }
  2923. // Success.
  2924. bRet = TRUE;
  2925. return bRet;
  2926. }
  2927. /******************************Member*Function*****************************\
  2928. * BOOL FHOBJ::bScanLists *
  2929. * *
  2930. * This implements the behavior of EnumFonts() and EnumFontFamilies() when *
  2931. * a non-NULL name is passed in. If the bComputeStyles flag is TRUE, the *
  2932. * EnumFonts() behavior of enumerating some fonts by their facename (rather *
  2933. * than family name) is used. *
  2934. * *
  2935. * This function puts HPFEs from the hash table and lists into the EFSOBJ. *
  2936. * If bComputeStyles is FALSE, the entire font enumeration list is added *
  2937. * to the EFSOBJ. *
  2938. * *
  2939. * If bComputeStyles is TRUE, then each list is scanned and a style *
  2940. * classification (EFSTYLE) is computed. Fonts classified as EFSTYLE_OTHER *
  2941. * are excluded from the EFSOBJ. (These fonts are enumerated by their *
  2942. * facename rather than their family name). *
  2943. * *
  2944. * Return: *
  2945. * Returns FALSE if an error occurs; TRUE otherwise. *
  2946. * *
  2947. * History: *
  2948. * Mon 14-Dec-1992 23:54:37 -by- Charles Whitmer [chuckwh] *
  2949. * Modified hash lookup. *
  2950. * *
  2951. * 07-Aug-1992 -by- Gilman Wong [gilmanw] *
  2952. * Wrote it. *
  2953. \**************************************************************************/
  2954. BOOL FHOBJ::bScanLists
  2955. (
  2956. EFSOBJ *pefso, // fill this EFSOBJ
  2957. PWSZ pwszName, // search on this name
  2958. ULONG iEnumType, // Enum Fonts, Families or FamiliesEx
  2959. EFFILTER_INFO *peffi // filtering information
  2960. )
  2961. {
  2962. WCHAR wcCapName[LF_FACESIZE];
  2963. BOOL bRet = FALSE; // for better code generation
  2964. FLONG flAdd = 0;
  2965. PFELINK *ppfel;
  2966. if (iEnumType == TYPE_ENUMFONTFAMILIESEX)
  2967. flAdd |= FL_ENUMFAMILIESEX;
  2968. // Capitalize the search name.
  2969. cCapString(wcCapName,pwszName,LF_FACESIZE);
  2970. // Search for head of the list.
  2971. HASHBUCKET *pbkt = pbktSearch(wcCapName,(UINT *) NULL);
  2972. // If the list exists, need to scan it. Unless this is an equiv. name
  2973. // HASHBUCKET. These are here only to allow the mapper to alias
  2974. // printer font names to other "equivlaent" names. We do not
  2975. // enumerate them.
  2976. if (pbkt)
  2977. {
  2978. ppfel = pbkt->ppfelEnumHead;
  2979. PFEOBJ pfeo(ppfel->ppfe);
  2980. ASSERTGDI (
  2981. pfeo.bValid(),
  2982. "gdisrv!bScanListsFHOBJ(): bad HPFE handle\n"
  2983. );
  2984. // These flags are set as PFEs for each category are found.
  2985. // Once a category is filled, then all subsequent fonts of the
  2986. // same category are marked as either EFSTYLE_OTHER (if facename
  2987. // is different than family name, thereby allowing us to use it
  2988. // to distinguish from other fonts of this family) or EFSTYLE_SKIP
  2989. // (if facename is the same as the family name).
  2990. //
  2991. // This is to support Win 3.1 EnumFonts() behavior which can only
  2992. // discriminate 4 different styles for each family of fonts.
  2993. BOOL abFoundStyle[EFSTYLE_MAX];
  2994. RtlZeroMemory((PVOID) abFoundStyle, EFSTYLE_MAX * sizeof(BOOL));
  2995. ENUMFONTSTYLE efsty = EFSTYLE_REGULAR;
  2996. //
  2997. // Win3.1 App compatibility flag GACF_TTIGNORERASTERDUPE. Need
  2998. // to copy count of TrueType from bucket into EFFILTER_INFO, peffi.
  2999. //
  3000. peffi->cTrueType = pbkt->cTrueType;
  3001. //
  3002. // Scan the list for candidates.
  3003. //
  3004. do
  3005. {
  3006. pfeo.ppfeSet(ppfel); // "relock" ppfe;
  3007. // Skip this PFE if it needs to be filtered out.
  3008. if ( pfeo.bFilteredOut(peffi) )
  3009. continue;
  3010. // If servicing an EnumFonts() call (bComputeStyles is TRUE),
  3011. // then some fonts may be excluded. EnumFontFamilies, however,
  3012. // wants the entire list.
  3013. if (iEnumType == TYPE_ENUMFONTS)
  3014. {
  3015. //
  3016. // Compute the style category for this PFE.
  3017. //
  3018. efsty = efstyCompute(abFoundStyle, pfeo);
  3019. // EnumFonts --
  3020. // If style is EFSTYLE_OTHER, this font falls into an
  3021. // already occupied category but it has a facename that allows
  3022. // it to be distinguished from other fonts of this family.
  3023. // So it will be excluded from this enumeration. (It will
  3024. // be enumerated by its facename).
  3025. if ( efsty == EFSTYLE_OTHER )
  3026. continue;
  3027. }
  3028. // Add the font to the enumeration.
  3029. if (!pefso->bAdd(pfeo.ppfeGet(),efsty,flAdd, peffi->lfCharSetFilter))
  3030. {
  3031. // Error return. bAdd() will set error code.
  3032. WARNING(
  3033. "gdisrv!bScanListsFHOBJ(): "
  3034. "abandon enum, cannot grow list\n");
  3035. return bRet;
  3036. }
  3037. } while (ppfel = ppfel->ppfelNext);
  3038. }
  3039. // Success.
  3040. bRet = TRUE;
  3041. return bRet;
  3042. }
  3043. /******************************Member*Function*****************************\
  3044. * FHMEMOBJ::FHMEMOBJ *
  3045. * *
  3046. * Allocates memory for a font hash table. *
  3047. * *
  3048. * History: *
  3049. * Tue 14-Apr-1992 14:44:35 by Kirk Olynyk [kirko] *
  3050. * Wrote it. *
  3051. \**************************************************************************/
  3052. FHMEMOBJ::FHMEMOBJ(FONTHASH **ppfhNew, FONTHASHTYPE fht_, UINT c)
  3053. {
  3054. ppfh = ppfhNew;
  3055. *ppfh = (FONTHASH*)
  3056. PALLOCMEM (offsetof(FONTHASH,apbkt) + sizeof(*(pfh->apbkt)) * c, 'sahG');
  3057. pfh = *ppfh;
  3058. if (pfh != (FONTHASH*) NULL)
  3059. {
  3060. vInit(fht_,c);
  3061. }
  3062. }
  3063. #if DBG
  3064. /******************************Public*Routine******************************\
  3065. * VOID PFTOBJ::vDump ()
  3066. *
  3067. * Debugging code.
  3068. *
  3069. * History:
  3070. * 25-Feb-1991 -by- Gilman Wong [gilmanw]
  3071. * Wrote it.
  3072. \**************************************************************************/
  3073. VOID PFTOBJ::vPrint()
  3074. {
  3075. PFF *pPFF, **ppPFF;
  3076. int i;
  3077. DbgPrint("\nContents of PFT, PPFT = 0x%p\n", pPFT);
  3078. DbgPrint("pfhFamily = %-#p\n", pPFT->pfhFamily);
  3079. DbgPrint("pfhFace = %-#p\n", pPFT->pfhFace);
  3080. DbgPrint("pfhUFI = %-#p\n", pPFT->pfhUFI);
  3081. DbgPrint("cBuckets = %ld\n", pPFT->cBuckets);
  3082. DbgPrint("cFiles = %ld\n", pPFT->cFiles);
  3083. DbgPrint("PPFF table\n");
  3084. for (
  3085. ppPFF = pPFT->apPFF,i=0
  3086. ; ppPFF < pPFT->apPFF + pPFT->cBuckets
  3087. ; ppPFF++,i++)
  3088. {
  3089. if (pPFF = *ppPFF)
  3090. {
  3091. DbgPrint("\tPFT->apPFF[%d]\n",i);
  3092. while (pPFF)
  3093. {
  3094. if (!pPFF->hdev)
  3095. {
  3096. DbgPrint("%p\t\"%ws\" %u\n"
  3097. , pPFF
  3098. , pPFF->pwszPathname_
  3099. , pPFF->sizeofThis
  3100. );
  3101. }
  3102. else
  3103. {
  3104. DbgPrint("%p\t%p %u\n"
  3105. , pPFF
  3106. , pPFF->hdev
  3107. , pPFF->sizeofThis
  3108. );
  3109. }
  3110. pPFF = pPFF->pPFFNext;
  3111. }
  3112. }
  3113. }
  3114. DbgPrint("\n");
  3115. }
  3116. /******************************Member*Function*****************************\
  3117. * FHOBJ::vPrint
  3118. *
  3119. * History:
  3120. * Tue 14-Apr-1992 13:49:51 by Kirk Olynyk [kirko]
  3121. * Wrote it.
  3122. \**************************************************************************/
  3123. VOID FHOBJ::vPrint(VPRINT print)
  3124. {
  3125. UINT i;
  3126. HASHBUCKET *pbkt;
  3127. PFELINK *ppfel;
  3128. print(" FHOBJ::vPrint()\n\n");
  3129. print(" ppfh = %-#8lx\n",ppfh);
  3130. print(" pfh = %-#8lx\n",pfh);
  3131. print(
  3132. " pfh->id = %c%c%c%c\n",
  3133. ((char*) (&pfh->id))[0],
  3134. ((char*) (&pfh->id))[1],
  3135. ((char*) (&pfh->id))[2],
  3136. ((char*) (&pfh->id))[3]
  3137. );
  3138. print(
  3139. " fht = %s\n",
  3140. pfh->fht == FHT_FAMILY ? "FHT_FAMILY" :
  3141. (pfh->fht == FHT_FACE ? "FHT_FACE" :
  3142. (pfh->fht == FHT_UFI ? "FHT_UFI" : "BOGUS VALUE" ))
  3143. );
  3144. print(" cBuckets = %d\n",pfh->cBuckets);
  3145. print(" cUsed = %d\n",pfh->cUsed);
  3146. print(" cCollisions = %d\n",pfh->cCollisions);
  3147. for (i = 0; i < pfh->cBuckets; i++)
  3148. {
  3149. for
  3150. (
  3151. pbkt = pfh->apbkt[i];
  3152. pbkt != (HASHBUCKET *) NULL;
  3153. pbkt = pbkt->pbktCollision
  3154. )
  3155. {
  3156. print(" ahbkt[%04d] \"%ws\"\n",i,pbkt->u.wcCapName);
  3157. }
  3158. }
  3159. print(
  3160. "\n\n hpfe %s\n\n",
  3161. pfh->fht ? "FamilyName" : "FaceName"
  3162. );
  3163. for (i = 0; i < pfh->cBuckets; i++)
  3164. {
  3165. BOOL bFirst;
  3166. for
  3167. (
  3168. pbkt = pfh->apbkt[i];
  3169. pbkt != (HASHBUCKET *) NULL;
  3170. pbkt = pbkt->pbktCollision
  3171. )
  3172. {
  3173. ppfel = pbkt->ppfelEnumHead;
  3174. bFirst = TRUE;
  3175. while (ppfel)
  3176. {
  3177. PFEOBJ pfeo(ppfel->ppfe);
  3178. if (bFirst)
  3179. {
  3180. print(" %-#8x \"%ws\"\n",ppfel->ppfe,pwszName(pfeo));
  3181. bFirst = FALSE;
  3182. }
  3183. else
  3184. {
  3185. print(" %-#8x\n",ppfel->ppfe);
  3186. }
  3187. ppfel = ppfel->ppfelNext;
  3188. }
  3189. }
  3190. }
  3191. print("\n\n");
  3192. }
  3193. #endif
  3194. /******************************Public*Routine******************************\
  3195. *
  3196. * Routine Name:
  3197. *
  3198. * GetLanguageID
  3199. *
  3200. * Routine Description:
  3201. *
  3202. * This routines returns the default language ID. Normally, we would call
  3203. * GetLocaleInfoW to get this information but that API is not available in
  3204. * kernel mode. Since GetLocaleInfoW gets it from the registry we'll do the
  3205. * same.
  3206. *
  3207. * Arguments: none
  3208. *
  3209. * Called by:
  3210. *
  3211. * Return Value:
  3212. *
  3213. * The default language ID. If the call fails it will just return 409
  3214. * for English.
  3215. *
  3216. \**************************************************************************/
  3217. USHORT GetLanguageID()
  3218. {
  3219. NTSTATUS NtStatus;
  3220. USHORT Result = 0x409;
  3221. HANDLE RegistryKeyHandle;
  3222. OBJECT_ATTRIBUTES ObjectAttributes;
  3223. UNICODE_STRING UnicodeString;
  3224. PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation;
  3225. #define NLS_TABLE_KEY \
  3226. L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Nls\\Language"
  3227. RtlInitUnicodeString(&UnicodeString, NLS_TABLE_KEY);
  3228. InitializeObjectAttributes(&ObjectAttributes,
  3229. &UnicodeString,
  3230. OBJ_CASE_INSENSITIVE,
  3231. NULL,
  3232. NULL);
  3233. NtStatus = ZwOpenKey(&RegistryKeyHandle, GENERIC_READ, &ObjectAttributes);
  3234. if(NT_SUCCESS(NtStatus))
  3235. {
  3236. PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation;
  3237. ULONG BufferSize = sizeof(WCHAR) * MAX_PATH +
  3238. sizeof(KEY_VALUE_FULL_INFORMATION);
  3239. KeyValueInformation = (PKEY_VALUE_PARTIAL_INFORMATION) PALLOCMEM(BufferSize,'dilG');
  3240. if(KeyValueInformation)
  3241. {
  3242. ULONG ValueReturnedLength;
  3243. RtlInitUnicodeString(&UnicodeString,L"Default");
  3244. NtStatus = ZwQueryValueKey(RegistryKeyHandle,
  3245. &UnicodeString,
  3246. KeyValuePartialInformation,
  3247. KeyValueInformation,
  3248. BufferSize,
  3249. &BufferSize);
  3250. if(NT_SUCCESS(NtStatus))
  3251. {
  3252. ULONG Temp;
  3253. RtlInitUnicodeString(&UnicodeString,
  3254. (PCWSTR) &(KeyValueInformation->Data[0]));
  3255. RtlUnicodeStringToInteger(&UnicodeString, 16, &Temp);
  3256. Result = (USHORT) Temp;
  3257. }
  3258. else
  3259. {
  3260. WARNING("GetLanguageID failed to read registry\n");
  3261. }
  3262. VFREEMEM(KeyValueInformation);
  3263. }
  3264. else
  3265. {
  3266. WARNING("GetLanguageID out of memory\n");
  3267. }
  3268. ZwCloseKey(RegistryKeyHandle);
  3269. }
  3270. else
  3271. {
  3272. WARNING("GetLanguageID failed to open NLS key\n");
  3273. }
  3274. return(Result);
  3275. }
  3276. BOOL PFTOBJ::bUnloadEUDCFont(PWSZ pwszPathname)
  3277. {
  3278. PFF *pPFF, **ppPFF;
  3279. WCHAR szUcPathName[MAX_PATH + 1];
  3280. BOOL bRet = FALSE;
  3281. cCapString(szUcPathName,
  3282. pwszPathname,
  3283. wcslen(pwszPathname)+1);
  3284. PUBLIC_PFTOBJ pfto; // access the public font table
  3285. GreAcquireSemaphoreEx(ghsemPublicPFT, SEMORDER_PUBLICPFT, NULL); // This is a very high granularity
  3286. // and will prevent text output
  3287. pPFF = pfto.pPFFGet(szUcPathName, wcslen(szUcPathName) + 1, 1,
  3288. NULL, 0, // pdv, cjDV
  3289. &ppPFF,TRUE);
  3290. if (pPFF)
  3291. {
  3292. // bUnloadWorkhorse() guarantees that the public font table
  3293. // semaphore will be released before it returns
  3294. bRet = pfto.bUnloadWorkhorse(pPFF, ppPFF, ghsemPublicPFT, 0);
  3295. }
  3296. else
  3297. {
  3298. GreReleaseSemaphoreEx(ghsemPublicPFT);
  3299. }
  3300. return( bRet );
  3301. }
  3302. /******************************Public*Routine******************************\
  3303. * HANDLE PUBLIC_PFTOBJ::hLoadMemFonts *
  3304. * ** * *
  3305. * Returns zero on failure. *
  3306. * *
  3307. * History: *
  3308. * 20-May-1997 -by- Xudong Wu [TessieW} *
  3309. * Wrote it. *
  3310. \**************************************************************************/
  3311. ULONG PUBLIC_PFTOBJ::ulMemoryUnique = 0;
  3312. HANDLE PUBLIC_PFTOBJ::hLoadMemFonts
  3313. (
  3314. PFONTFILEVIEW *ppfv, // font file image
  3315. DESIGNVECTOR *pdv,
  3316. ULONG cjDV,
  3317. ULONG *pcFonts
  3318. )
  3319. {
  3320. BOOL bOK = FALSE;
  3321. HANDLE hMMFont = 0;
  3322. ULONG cFonts;
  3323. FNTCHECKSUM fntCheckSum;
  3324. PVOID ppvViews[1];
  3325. ULONG pcjViews[1];
  3326. ppvViews[0] = ppfv[0]->fv.pvViewFD;
  3327. pcjViews[0] = ppfv[0]->fv.cjView;
  3328. HFF hffNew = HFF_INVALID;
  3329. PPDEV ppDevList;
  3330. // order of grabbing semaphores important
  3331. GreAcquireSemaphoreEx(ghsemDriverMgmt, SEMORDER_DRIVERMGMT, NULL);
  3332. vLoadFontFileView(NULL, 0, ppfv, 1, ppvViews, pcjViews, pdv, cjDV, &hffNew ,&ppDevList, &fntCheckSum);
  3333. PDEVOBJ pdo((HDEV)ppDevList);
  3334. GreReleaseSemaphoreEx(ghsemDriverMgmt);
  3335. if (hffNew != HFF_INVALID)
  3336. {
  3337. cFonts = pdo.QueryFontFile( hffNew, QFF_NUMFACES, 0, NULL);
  3338. if (cFonts && cFonts != FD_ERROR)
  3339. {
  3340. WCHAR awc[30];
  3341. *pcFonts = cFonts;
  3342. // create a unique file name for the memory font
  3343. // in the form of "Memory NNN"
  3344. swprintf(awc, L"MEMORY-%u", ulGetNewUniqueness(PUBLIC_PFTOBJ::ulMemoryUnique));
  3345. ULONG cwc = wcslen(awc) + 1;
  3346. PFFCLEANUP *pPFFC = 0;
  3347. PFFMEMOBJ
  3348. pffmo(cFonts,
  3349. awc, cwc, 1,
  3350. pdv, cjDV,
  3351. hffNew, pdo.hdev(),
  3352. 0, pPFT,
  3353. PFF_STATE_MEMORY_FONT,
  3354. FR_PRIVATE | FR_NOT_ENUM, //always use FR_PRIVATE | FR_NOT_ENUM for memory fonts
  3355. &fntCheckSum,
  3356. ppfv,
  3357. NULL); // pufi
  3358. if (pffmo.bValid())
  3359. {
  3360. if (pffmo.bLoadFontFileTable(awc, cFonts, (HANDLE)0, NULL, NULL))
  3361. {
  3362. SEMOBJ so2(ghsemPublicPFT);
  3363. if(bOK = pffmo.bAddHash(FALSE))
  3364. {
  3365. PFF **ppPFF, *pPFF;
  3366. pPFF = pPFFGet(awc, cwc, 1, pdv, cjDV, &ppPFF);
  3367. if (pPFF)
  3368. {
  3369. KdPrint(("bLoadMemFonts(): \"%ws\" has been found on the font table\n"));
  3370. KdBreakPoint();
  3371. bOK = FALSE;
  3372. }
  3373. else
  3374. {
  3375. pPFF = pffmo.pPFFGet();
  3376. pPFT->cFiles++;
  3377. //place this new pff at the head of the hash bucket list
  3378. if (*ppPFF)
  3379. {
  3380. (*ppPFF)->pPFFPrev = pPFF;
  3381. }
  3382. pPFF->pPFFNext = *ppPFF;
  3383. pPFF->pPFFPrev = 0;
  3384. *ppPFF = pPFF;
  3385. pffmo.vKeepIt();
  3386. //Sundown: hMMFont is not a real handle but the checksum
  3387. hMMFont = (HANDLE)(ULONG_PTR)pPFF->ulCheckSum;
  3388. }
  3389. }
  3390. else
  3391. {
  3392. pffmo.vRemoveHash();
  3393. }
  3394. }
  3395. if (!bOK)
  3396. {
  3397. pffmo.vPFFC_DeleteAndCleanup(); // new code (not so new anymore)
  3398. bOK = TRUE;
  3399. }
  3400. }
  3401. }
  3402. }
  3403. if (!bOK)
  3404. {
  3405. VFREEMEM(ppfv);
  3406. }
  3407. return hMMFont;
  3408. }
  3409. ULONG PUBLIC_PFTOBJ::GetEmbedFonts()
  3410. {
  3411. ULONG i, cEmbedFonts = 0;
  3412. PFF *pPFF, **ppPFF;
  3413. PVTDATA *pPvtData;
  3414. DWORD pid, tid;
  3415. if (!bIsPrivatePFT())
  3416. return 0;
  3417. pid = (DWORD) W32GetCurrentPID();
  3418. tid = (DWORD) W32GetCurrentTID();
  3419. SEMOBJ so(ghsemPublicPFT);
  3420. for (i = 0; i < CPRIVATEBUCKETS; i++)
  3421. {
  3422. ppPFF = &pPFT->apPFF[i];
  3423. if (ppPFF)
  3424. {
  3425. pPFF = *ppPFF;
  3426. while (pPFF)
  3427. {
  3428. pPvtData = pPFF->pPvtDataHead;
  3429. while (pPvtData)
  3430. {
  3431. if (pPvtData->fl & FRW_EMB_TID)
  3432. {
  3433. if (pPvtData->dwID == tid)
  3434. cEmbedFonts++;
  3435. }
  3436. else
  3437. {
  3438. if (pPvtData->dwID == pid)
  3439. cEmbedFonts++;
  3440. }
  3441. pPvtData = pPvtData->pPvtDataNext;
  3442. }
  3443. pPFF = pPFF->pPFFNext;
  3444. }
  3445. }
  3446. }
  3447. return cEmbedFonts;
  3448. }
  3449. BOOL PUBLIC_PFTOBJ::VerifyFontID(VOID *fontID)
  3450. {
  3451. ULONG i;
  3452. PFF *pPFF, **ppPFF;
  3453. BOOL bRet = FALSE;
  3454. if (!bIsPrivatePFT())
  3455. return FALSE;
  3456. SEMOBJ so(ghsemPublicPFT);
  3457. for (i = 0; (i < CPRIVATEBUCKETS && !bRet); i++)
  3458. {
  3459. ppPFF = &pPFT->apPFF[i];
  3460. if (ppPFF)
  3461. {
  3462. pPFF = *ppPFF;
  3463. while (pPFF)
  3464. {
  3465. if ((PFF *)fontID == pPFF) // PFF match
  3466. {
  3467. return TRUE;
  3468. }
  3469. pPFF = pPFF->pPFFNext;
  3470. }
  3471. }
  3472. }
  3473. return bRet;
  3474. }
  3475. BOOL PUBLIC_PFTOBJ::ChangeGhostFont(VOID *fontID, BOOL bLoad)
  3476. {
  3477. ULONG i;
  3478. PFF *pPFF, **ppPFF;
  3479. PVTDATA *pPvtData;
  3480. DWORD pid, tid;
  3481. BOOL bRet = FALSE;
  3482. if (!bIsPrivatePFT())
  3483. return FALSE;
  3484. pid = (DWORD) W32GetCurrentPID();
  3485. tid = (DWORD) W32GetCurrentTID();
  3486. SEMOBJ so(ghsemPublicPFT);
  3487. for (i = 0; (i < CPRIVATEBUCKETS && !bRet); i++)
  3488. {
  3489. ppPFF = &pPFT->apPFF[i];
  3490. if (ppPFF)
  3491. {
  3492. pPFF = *ppPFF;
  3493. while (pPFF)
  3494. {
  3495. if ((PFF *)fontID == pPFF) // PFF match
  3496. {
  3497. pPvtData = pPFF->pPvtDataHead;
  3498. while(pPvtData)
  3499. {
  3500. if (((pPvtData->fl & FRW_EMB_TID) && (pPvtData->dwID == tid)) ||
  3501. ((!(pPvtData->fl & FRW_EMB_TID)) && (pPvtData->dwID == pid)))
  3502. {
  3503. if (bLoad)
  3504. {
  3505. pPvtData->cNotEnum++;
  3506. pPvtData->fl |= FR_PRINT_EMB_FONT;
  3507. bRet = TRUE;
  3508. }
  3509. else
  3510. {
  3511. if (pPvtData->cNotEnum)
  3512. {
  3513. pPvtData->cNotEnum--;
  3514. pPvtData->fl &= ~FR_PRINT_EMB_FONT;
  3515. }
  3516. }
  3517. break;
  3518. }
  3519. pPvtData = pPvtData->pPvtDataNext;
  3520. }
  3521. }
  3522. if (bRet)
  3523. break;
  3524. pPFF = pPFF->pPFFNext;
  3525. }
  3526. }
  3527. }
  3528. return bRet;
  3529. }