xref: /reactos/win32ss/drivers/font/bmfd/font.c (revision c2c66aff)
1 /*
2  * PROJECT:         ReactOS win32 subsystem
3  * LICENSE:         GPL - See COPYING in the top level directory
4  * PURPOSE:         GDI font driver for bitmap fonts
5  * PROGRAMMER:      Timo Kreuzer (timo.kreuzer@reactos.org)
6  */
7 
8 #include "bmfd.h"
9 
10 static
11 BOOLEAN
IsValidPtr(PVOID p,ULONG cjSize,PVOID pStart,PVOID pEnd,ULONG cjAlign)12 IsValidPtr(
13     PVOID p,
14     ULONG cjSize,
15     PVOID pStart,
16     PVOID pEnd,
17     ULONG cjAlign)
18 {
19     if ((ULONG_PTR)p < (ULONG_PTR)pStart ||
20         (ULONG_PTR)p + cjSize >= (ULONG_PTR)pEnd ||
21         (ULONG_PTR)p & (cjAlign -1))
22     {
23         return FALSE;
24     }
25     return TRUE;
26 }
27 
28 static
29 BOOL
FillFaceInfo(PBMFD_FACE pface,PFONTINFO16 pFontInfo)30 FillFaceInfo(
31     PBMFD_FACE pface,
32     PFONTINFO16 pFontInfo)
33 {
34     CHAR ansi[4];
35     WCHAR unicode[4];
36     ULONG written;
37     DWORD dfFlags;
38 
39     pface->pFontInfo = pFontInfo;
40     pface->ulVersion = GETVAL(pFontInfo->dfVersion);
41     pface->cGlyphs = pFontInfo->dfLastChar - pFontInfo->dfFirstChar + 1;
42 
43     /* Convert chars to unicode */
44     ansi[0] = pFontInfo->dfFirstChar;
45     ansi[1] = pFontInfo->dfLastChar;
46     ansi[2] = pFontInfo->dfFirstChar + pFontInfo->dfDefaultChar;
47     ansi[3] = pFontInfo->dfFirstChar + pFontInfo->dfBreakChar;
48     EngMultiByteToUnicodeN(unicode, 4 * sizeof(WCHAR), &written, ansi, 4);
49     pface->wcFirstChar = unicode[0];
50     pface->wcLastChar = unicode[1];
51     pface->wcDefaultChar = unicode[2];
52     pface->wcBreakChar = unicode[3];
53 
54     /* Copy some values */
55     pface->wPixHeight = GETVAL(pFontInfo->dfPixHeight);
56     pface->wPixWidth = GETVAL(pFontInfo->dfPixWidth);
57     pface->wWidthBytes = GETVAL(pFontInfo->dfWidthBytes);
58     pface->wAscent = GETVAL(pFontInfo->dfAscent);
59     pface->wDescent = pface->wPixHeight - pface->wAscent;
60 
61     /* Some version specific members */
62     if (pface->ulVersion >= 0x300)
63     {
64         dfFlags = GETVAL(pFontInfo->dfFlags);
65         pface->wA = GETVAL(pFontInfo->dfAspace);
66         pface->wB = GETVAL(pFontInfo->dfBspace);
67         pface->wC = GETVAL(pFontInfo->dfCspace);
68         pface->pCharTable = pFontInfo->dfCharTable;
69         pface->cjEntrySize = sizeof(GLYPHENTRY30);
70     }
71     else
72     {
73         dfFlags = DFF_1COLOR;
74         pface->wA = 0;
75         pface->wB = 0;
76         pface->wC = 0;
77         pface->pCharTable = &pFontInfo->dfReserved + 1;
78         pface->cjEntrySize = sizeof(GLYPHENTRY20);
79     }
80 
81     pface->flInfo = FM_INFO_MASK;
82 
83     /* If dfWidth is non-null, we have a fixed width font */
84     if (dfFlags & DFF_FIXED || pface->wPixWidth)
85         pface->flInfo |= FM_INFO_CONSTANT_WIDTH;
86 
87     /* Initialize color depth flags */
88     if (dfFlags & DFF_1COLOR)
89         pface->flInfo |= FM_INFO_1BPP;
90     else if (dfFlags & DFF_16COLOR)
91         pface->flInfo |= FM_INFO_4BPP;
92     else if (dfFlags & DFF_256COLOR)
93         pface->flInfo |= FM_INFO_8BPP;
94     else if (dfFlags & DFF_RGBCOLOR)
95         pface->flInfo |= FM_INFO_24BPP;
96 
97     // TODO: walk through all glyphs and veryfy them and calculate max values
98 
99     // FIXME: After this point, the whole font data should be verified!
100 
101     return TRUE;
102 }
103 
104 static
105 PVOID
ParseFntFile(PVOID pvView,ULONG cjView)106 ParseFntFile(
107     PVOID pvView,
108     ULONG cjView)
109 {
110     /* unimplemented */
111     return NULL;
112 }
113 
114 
115 static
116 PVOID
ParseFonFile(PVOID pvView,ULONG cjView)117 ParseFonFile(
118     PVOID pvView,
119     ULONG cjView)
120 {
121     PIMAGE_DOS_HEADER pDosHeader = pvView;
122     PIMAGE_OS2_HEADER pOs2Header;
123     PNE_RESTABLE pResTable;
124     PNE_TYPEINFO pTInfo;
125     PFONTINFO16 pFontInfo;
126     PCHAR pStart, pEnd;
127     PBMFD_FILE pfile = NULL;
128     WORD wShift;
129     ULONG i, cjOffset, cjLength;
130     ULONG type_id, count;
131 
132     /* Initial margins for valid pointers */
133     pStart = pvView;
134     pEnd = pStart + cjView;
135 
136     /* Check for image dos header */
137     if (GETVAL(pDosHeader->e_magic) != IMAGE_DOS_MAGIC)
138     {
139         return NULL;
140     }
141 
142     /* Get pointer to OS2 header and veryfy it is valid */
143     pOs2Header = (PVOID)((PCHAR)pDosHeader + GETVAL(pDosHeader->e_lfanew));
144     pStart += sizeof(IMAGE_DOS_HEADER);
145     if (!IsValidPtr(pOs2Header, sizeof(IMAGE_OS2_HEADER), pStart, pEnd, 4))
146     {
147         DbgPrint("e_lfanew is invalid: 0x%lx\n", pDosHeader->e_lfanew);
148         return NULL;
149     }
150 
151     /* Get pointer to resource table and verify it is valid */
152     pResTable = (PVOID)((PCHAR)pOs2Header + GETVAL(pOs2Header->ne_rsrctab));
153     pStart = (PCHAR)pOs2Header;
154     if (!IsValidPtr(pResTable, sizeof(NE_RESTABLE), pStart, pEnd, 1))
155     {
156         DbgPrint("pTInfo is invalid: 0x%p\n", pResTable);
157         return NULL;
158     }
159 
160     wShift = GETVAL(pResTable->size_shift);
161     pTInfo = pResTable->typeinfo;
162     type_id = GETVAL(pTInfo->type_id);
163 
164     /* Loop the resource table to find a font resource */
165     while (type_id)
166     {
167         /* Get number of nameinfo entries */
168         count = GETVAL(pTInfo->count);
169 
170         /* Look for a font resource */
171         if (type_id == NE_RSCTYPE_FONT && count > 0)
172         {
173             DbgPrint("Found NE_RSCTYPE_FONT\n");
174 
175             /* Allocate an info structure for this font and all faces */
176             cjLength = sizeof(BMFD_FILE) + (count-1) * sizeof(BMFD_FACE);
177             pfile = EngAllocMem(0, cjLength, TAG_FONTINFO);
178             if (!pfile)
179             {
180                 DbgPrint("Not enough memory: %ld\n", cjLength);
181                 return NULL;
182             }
183 
184             pfile->cNumFaces = count;
185 
186             /* Fill all face info structures */
187             for (i = 0; i < count; i++)
188             {
189                 cjOffset = GETVAL(pTInfo->nameinfo[i].offset) << wShift;
190                 cjLength = GETVAL(pTInfo->nameinfo[i].length) << wShift;
191                 pFontInfo = (PVOID)((PCHAR)pDosHeader + cjOffset);
192 
193                 if (!IsValidPtr(pFontInfo, cjLength, pStart, pEnd, 1))
194                 {
195                     DbgPrint("pFontInfo is invalid: 0x%p\n", pFontInfo);
196                     EngFreeMem(pfile);
197                     return NULL;
198                 }
199 
200                 /* Validate FONTINFO and fill face info */
201                 if (!FillFaceInfo(&pfile->aface[i], pFontInfo))
202                 {
203                     DbgPrint("pFontInfo is invalid: 0x%p\n", pFontInfo);
204                     EngFreeMem(pfile);
205                     return NULL;
206                 }
207             }
208 
209             /* Break out of the loop */
210             break;
211         }
212 
213         /* Following pointers must be bigger than this */
214         pStart = (PCHAR)pTInfo;
215 
216         /* Goto next entry in resource table */
217         pTInfo = (PVOID)&pTInfo->nameinfo[count];
218 
219         /* Verify that the new pTInfo pointer is valid */
220         if (!IsValidPtr(pTInfo, sizeof(NE_TYPEINFO), pStart, pEnd, 1))
221         {
222             DbgPrint("pTInfo is invalid: 0x%p\n", pTInfo);
223             return NULL;
224         }
225 
226         type_id = GETVAL(pTInfo->type_id);
227     }
228 
229     return pfile;
230 }
231 
232 /** Public Interface **********************************************************/
233 
234 ULONG_PTR
235 APIENTRY
BmfdLoadFontFile(ULONG cFiles,ULONG_PTR * piFile,PVOID * ppvView,ULONG * pcjView,DESIGNVECTOR * pdv,ULONG ulLangID,ULONG ulFastCheckSum)236 BmfdLoadFontFile(
237     ULONG cFiles,
238     ULONG_PTR *piFile,
239     PVOID *ppvView,
240     ULONG *pcjView,
241     DESIGNVECTOR *pdv,
242     ULONG ulLangID,
243     ULONG ulFastCheckSum)
244 {
245     PBMFD_FILE pfile = NULL;
246     PVOID pvView;
247     ULONG cjView;
248 
249     DbgPrint("BmfdLoadFontFile()\n");
250     __debugbreak();
251 
252     /* Check parameters */
253     if (cFiles != 1)
254     {
255         DbgPrint("Only 1 File is allowed, got %ld!\n", cFiles);
256         return HFF_INVALID;
257     }
258 
259     /* Map the font file */
260     if (!EngMapFontFileFD(*piFile, (PULONG*)&pvView, &cjView))
261     {
262         DbgPrint("Could not map font file!\n", cFiles);
263         return HFF_INVALID;
264     }
265 
266     DbgPrint("mapped font file to %p, site if %ld\n", pvView, cjView);
267 
268     /* Try to parse a .fon file */
269     pfile = ParseFonFile(pvView, cjView);
270 
271     if (!pfile)
272     {
273         /* Could be a .fnt file */
274         pfile = ParseFntFile(pvView, cjView);
275     }
276 
277     /* Check whether we succeeded finding a font */
278     if (!pfile)
279     {
280         DbgPrint("No font data found\n");
281 
282         /* Unmap the file */
283         EngUnmapFontFileFD(*piFile);
284 
285         /* Failure! */
286         return HFF_INVALID;
287     }
288 
289     pfile->iFile = *piFile;
290     pfile->pvView = pvView;
291 
292     /* Success, return the pointer to font info structure */
293     return (ULONG_PTR)pfile;
294 }
295 
296 BOOL
297 APIENTRY
BmfdUnloadFontFile(IN ULONG_PTR iFile)298 BmfdUnloadFontFile(
299     IN ULONG_PTR iFile)
300 {
301     PBMFD_FILE pfile = (PBMFD_FILE)iFile;
302 
303     DbgPrint("BmfdUnloadFontFile()\n");
304 
305     /* Unmap the font file */
306     EngUnmapFontFileFD(pfile->iFile);
307 
308     /* Free the memory that was allocated for the font */
309     EngFreeMem(pfile);
310 
311     return TRUE;
312 }
313 
314 
315 LONG
316 APIENTRY
BmfdQueryFontFile(ULONG_PTR iFile,ULONG ulMode,ULONG cjBuf,ULONG * pulBuf)317 BmfdQueryFontFile(
318     ULONG_PTR iFile,
319     ULONG ulMode,
320     ULONG cjBuf,
321     ULONG *pulBuf)
322 {
323     PBMFD_FILE pfile = (PBMFD_FILE)iFile;
324 
325     DbgPrint("BmfdQueryFontFile()\n");
326 //    __debugbreak();
327 
328     switch (ulMode)
329     {
330         case QFF_DESCRIPTION:
331         {
332             /* We copy the face name of the 1st face */
333             PCHAR pDesc = pfile->aface[0].pszFaceName;
334             ULONG cOutSize;
335             if (pulBuf)
336             {
337                 EngMultiByteToUnicodeN((LPWSTR)pulBuf,
338                                        cjBuf,
339                                        &cOutSize,
340                                        pDesc,
341                                        strnlen(pDesc, LF_FACESIZE));
342             }
343             else
344             {
345                 cOutSize = (strnlen(pDesc, LF_FACESIZE) + 1) * sizeof(WCHAR);
346             }
347             return cOutSize;
348         }
349 
350         case QFF_NUMFACES:
351             /* return the number of faces in the file */
352             return pfile->cNumFaces;
353 
354         default:
355             return FD_ERROR;
356     }
357 }
358 
359 LONG
360 APIENTRY
BmfdQueryFontCaps(ULONG culCaps,ULONG * pulCaps)361 BmfdQueryFontCaps(
362     ULONG culCaps,
363     ULONG *pulCaps)
364 {
365     DbgPrint("BmfdQueryFontCaps()\n");
366 
367     /* We need room for 2 ULONGs */
368     if (culCaps < 2)
369     {
370         return FD_ERROR;
371     }
372 
373     /* We only support 1 bpp */
374     pulCaps[0] = 2;
375     pulCaps[1] = QC_1BIT;
376 
377     return 2;
378 }
379 
380 
381 PVOID
382 APIENTRY
BmfdQueryFontTree(DHPDEV dhpdev,ULONG_PTR iFile,ULONG iFace,ULONG iMode,ULONG_PTR * pid)383 BmfdQueryFontTree(
384     DHPDEV dhpdev,
385     ULONG_PTR iFile,
386     ULONG iFace,
387     ULONG iMode,
388     ULONG_PTR *pid)
389 {
390     PBMFD_FILE pfile = (PBMFD_FILE)iFile;
391     PBMFD_FACE pface;
392     ULONG i, j, cjSize, cGlyphs, cRuns;
393     CHAR ch, chFirst, ach[256];
394     WCHAR wc, awc[256];
395     PFD_GLYPHSET pGlyphSet;
396     WCRUN *pwcrun;
397     HGLYPH * phglyphs;
398 
399     DbgPrint("DrvQueryFontTree(iMode=%ld)\n", iMode);
400 //    __debugbreak();
401 
402     /* Check parameters, we only support QFT_GLYPHSET */
403     if (!iFace || iFace > pfile->cNumFaces || iMode != QFT_GLYPHSET)
404     {
405         DbgPrint("iFace = %ld, cNumFaces = %ld\n", iFace, pfile->cNumFaces);
406         return NULL;
407     }
408 
409     /* Get a pointer to the face data */
410     pface = &pfile->aface[iFace - 1];
411 
412     /* Get the number of characters in the face */
413     cGlyphs = pface->cGlyphs;
414 
415     chFirst = pface->pFontInfo->dfFirstChar;
416 
417     /* Build array of supported chars */
418     for (i = 0; i < cGlyphs; i++)
419     {
420         ach[i] = chFirst + i;
421     }
422 
423     /* Convert the chars to unicode */
424     EngMultiByteToUnicodeN(awc, sizeof(awc), NULL, ach, cGlyphs);
425 
426     /* Sort both arrays in wchar order */
427     for (i = 0; i < cGlyphs - 1; i++)
428     {
429         wc = awc[i];
430         for (j = i + 1; j < cGlyphs; j++)
431         {
432             if (awc[j] < wc)
433             {
434                 awc[i] = awc[j];
435                 awc[j] = wc;
436                 wc = awc[i];
437                 ch = ach[i];
438                 ach[i] = ach[j];
439                 ach[j] = ch;
440             }
441         }
442     }
443 
444     /* Find number of WCRUNs */
445     cRuns = 1;
446     for (i = 1; i < cGlyphs; i++)
447     {
448         if (awc[i] != awc[i - 1] + 1)
449         {
450             cRuns++;
451         }
452     }
453 
454     /* Calculate FD_GLYPHSET size */
455     cjSize = sizeof(FD_GLYPHSET)
456              + (cRuns - 1) * sizeof(WCRUN)
457              + cGlyphs * sizeof(HGLYPH);
458 
459     /* Allocate the FD_GLYPHSET structure */
460     pGlyphSet = EngAllocMem(0, cjSize, TAG_GLYPHSET);
461     if (!pGlyphSet)
462     {
463         return NULL;
464     }
465 
466     /* Initialize FD_GLYPHSET */
467     pGlyphSet->cjThis = cjSize;
468     pGlyphSet->flAccel = 0;
469     pGlyphSet->cGlyphsSupported = cGlyphs;
470     pGlyphSet->cRuns = cRuns;
471 
472     /* Initialize 1st WCRUN */
473     pwcrun = pGlyphSet->awcrun;
474     phglyphs = (PHGLYPH)&pGlyphSet->awcrun[cRuns];
475     pwcrun[0].wcLow = awc[0];
476     pwcrun[0].cGlyphs = 1;
477     pwcrun[0].phg = phglyphs;
478     phglyphs[0] = 0;
479 
480     /* Walk through all supported chars */
481     for (i = 1, j = 0; i < cGlyphs; i++)
482     {
483         /* Use offset to glyph entry as hglyph */
484         phglyphs[i] = (ach[i] - chFirst) * pface->cjEntrySize;
485 
486         /* Check whether we can append the wchar to a run */
487         if (awc[i] == awc[i - 1] + 1)
488         {
489             /* Append to current WCRUN */
490             pwcrun[j].cGlyphs++;
491         }
492         else
493         {
494             /* Add a new WCRUN */
495             j++;
496             pwcrun[j].wcLow = awc[i];
497             pwcrun[j].cGlyphs = 1;
498             pwcrun[j].phg = &phglyphs[i];
499         }
500     }
501 
502     /* Set *pid to the allocated structure for use in BmfdFree */
503     *pid = (ULONG_PTR)pGlyphSet;
504 
505     return pGlyphSet;
506 }
507 
508 PIFIMETRICS
509 APIENTRY
BmfdQueryFont(IN DHPDEV dhpdev,IN ULONG_PTR iFile,IN ULONG iFace,IN ULONG_PTR * pid)510 BmfdQueryFont(
511     IN DHPDEV dhpdev,
512     IN ULONG_PTR iFile,
513     IN ULONG iFace,
514     IN ULONG_PTR *pid)
515 {
516     PBMFD_FILE pfile = (PBMFD_FILE)iFile;
517     PBMFD_FACE pface;
518     PFONTINFO16 pFontInfo;
519     PIFIMETRICS pifi;
520     PBMFD_IFIMETRICS pifiX;
521     PANOSE panose = {0};
522 
523     DbgPrint("BmfdQueryFont()\n");
524 //    __debugbreak();
525 
526     /* Validate parameters */
527     if (iFace > pfile->cNumFaces || !pid)
528     {
529         return NULL;
530     }
531 
532     pface = &pfile->aface[iFace - 1];
533     pFontInfo = pface->pFontInfo;
534 
535     /* Allocate the structure */
536     pifiX = EngAllocMem(FL_ZERO_MEMORY, sizeof(BMFD_IFIMETRICS), TAG_IFIMETRICS);
537     if (!pifiX)
538     {
539         return NULL;
540     }
541 
542     /* Return a pointer to free it later */
543     *pid = (ULONG_PTR)pifiX;
544 
545     /* Fill IFIMETRICS */
546     pifi = &pifiX->ifim;
547     pifi->cjThis = sizeof(BMFD_IFIMETRICS);
548     pifi->cjIfiExtra = 0;
549     pifi->dpwszFamilyName = FIELD_OFFSET(BMFD_IFIMETRICS, wszFamilyName);
550     pifi->dpwszStyleName = FIELD_OFFSET(BMFD_IFIMETRICS, wszFamilyName);
551     pifi->dpwszFaceName = FIELD_OFFSET(BMFD_IFIMETRICS, wszFaceName);
552     pifi->dpwszUniqueName = FIELD_OFFSET(BMFD_IFIMETRICS, wszFaceName);
553     pifi->dpFontSim = 0;
554     pifi->lEmbedId = 0;
555     pifi->lItalicAngle = 0;
556     pifi->lCharBias = 0;
557     pifi->dpCharSets = 0;
558     pifi->jWinCharSet = pFontInfo->dfCharSet;
559     pifi->jWinPitchAndFamily = pFontInfo->dfPitchAndFamily;
560     pifi->usWinWeight = GETVAL(pFontInfo->dfWeight);
561     pifi->flInfo = pface->flInfo;
562     pifi->fsSelection = 0;
563     pifi->fsType = 0;
564     pifi->fwdUnitsPerEm = GETVAL(pFontInfo->dfPixHeight);
565     pifi->fwdLowestPPEm = 0;
566     pifi->fwdWinAscender = GETVAL(pFontInfo->dfAscent);
567     pifi->fwdWinDescender = pifi->fwdUnitsPerEm - pifi->fwdWinAscender;
568     pifi->fwdMacAscender = pifi->fwdWinAscender;
569     pifi->fwdMacDescender = - pifi->fwdWinDescender;
570     pifi->fwdMacLineGap = 0;
571     pifi->fwdTypoAscender = pifi->fwdWinAscender;
572     pifi->fwdTypoDescender = - pifi->fwdWinDescender;
573     pifi->fwdTypoLineGap = 0;
574     pifi->fwdAveCharWidth = GETVAL(pFontInfo->dfAvgWidth);
575     pifi->fwdMaxCharInc =  GETVAL(pFontInfo->dfMaxWidth);
576     pifi->fwdCapHeight = pifi->fwdUnitsPerEm / 2;
577     pifi->fwdXHeight = pifi->fwdUnitsPerEm / 4;
578     pifi->fwdSubscriptXSize = 0;
579     pifi->fwdSubscriptYSize = 0;
580     pifi->fwdSubscriptXOffset = 0;
581     pifi->fwdSubscriptYOffset = 0;
582     pifi->fwdSuperscriptXSize = 0;
583     pifi->fwdSuperscriptYSize = 0;
584     pifi->fwdSuperscriptXOffset = 0;
585     pifi->fwdSuperscriptYOffset = 0;
586     pifi->fwdUnderscoreSize = 01;
587     pifi->fwdUnderscorePosition = -1;
588     pifi->fwdStrikeoutSize = 1;
589     pifi->fwdStrikeoutPosition = pifi->fwdXHeight + 1;
590     pifi->chFirstChar = pFontInfo->dfFirstChar;
591     pifi->chLastChar = pFontInfo->dfLastChar;
592     pifi->chDefaultChar = pFontInfo->dfFirstChar + pFontInfo->dfDefaultChar;
593     pifi->chBreakChar = pFontInfo->dfFirstChar + pFontInfo->dfBreakChar;
594     pifi->wcFirstChar = pface->wcFirstChar;
595     pifi->wcLastChar = pface->wcLastChar;
596     pifi->wcDefaultChar = pface->wcDefaultChar;
597     pifi->wcBreakChar = pface->wcBreakChar;
598     pifi->ptlBaseline.x = 1;
599     pifi->ptlBaseline.y = 0;
600     pifi->ptlAspect.x = pFontInfo->dfVertRes; // CHECKME
601     pifi->ptlAspect.y = pFontInfo->dfHorizRes;
602     pifi->ptlCaret.x = 0;
603     pifi->ptlCaret.y = 1;
604     pifi->rclFontBox.left = 0;
605     pifi->rclFontBox.right = pifi->fwdAveCharWidth;
606     pifi->rclFontBox.top = pifi->fwdWinAscender;
607     pifi->rclFontBox.bottom = - pifi->fwdWinDescender;
608     *(DWORD*)&pifi->achVendId = 0x30303030; // FIXME
609     pifi->cKerningPairs = 0;
610     pifi->ulPanoseCulture = FM_PANOSE_CULTURE_LATIN;
611     pifi->panose = panose;
612 
613     /* Set char sets */
614     pifiX->ajCharSet[0] = pifi->jWinCharSet;
615     pifiX->ajCharSet[1] = DEFAULT_CHARSET;
616 
617     if (pface->flInfo & FM_INFO_CONSTANT_WIDTH)
618         pifi->jWinPitchAndFamily |= FIXED_PITCH;
619 
620 #if 0
621     EngMultiByteToUnicodeN(pifiX->wszFaceName,
622                            LF_FACESIZE * sizeof(WCHAR),
623                            NULL,
624                            pFontInfo->,
625                            strnlen(pDesc, LF_FACESIZE));
626 #endif
627     wcscpy(pifiX->wszFaceName, L"Courier-X");
628     wcscpy(pifiX->wszFamilyName, L"Courier-X");
629 
630     /* Initialize font weight style flags and string */
631     if (pifi->usWinWeight == FW_REGULAR)
632     {
633    //     pifi->fsSelection |= FM_SEL_REGULAR;
634     }
635     else if (pifi->usWinWeight > FW_SEMIBOLD)
636     {
637         pifi->fsSelection |= FM_SEL_BOLD;
638         wcscat(pifiX->wszStyleName, L"Bold ");
639     }
640     else if (pifi->usWinWeight <= FW_LIGHT)
641     {
642         wcscat(pifiX->wszStyleName, L"Light ");
643     }
644 
645     if (pFontInfo->dfItalic)
646     {
647         pifi->fsSelection |= FM_SEL_ITALIC;
648         wcscat(pifiX->wszStyleName, L"Italic ");
649     }
650 
651     if (pFontInfo->dfUnderline)
652     {
653         pifi->fsSelection |= FM_SEL_UNDERSCORE;
654         wcscat(pifiX->wszStyleName, L"Underscore ");
655     }
656 
657     if (pFontInfo->dfStrikeOut)
658     {
659         pifi->fsSelection |= FM_SEL_STRIKEOUT;
660         wcscat(pifiX->wszStyleName, L"Strikeout ");
661     }
662 
663     return pifi;
664 }
665 
666 
667 VOID
668 APIENTRY
BmfdFree(PVOID pv,ULONG_PTR id)669 BmfdFree(
670     PVOID pv,
671     ULONG_PTR id)
672 {
673     DbgPrint("BmfdFree()\n");
674     if (id)
675     {
676         EngFreeMem((PVOID)id);
677     }
678 }
679 
680 
681 VOID
682 APIENTRY
BmfdDestroyFont(IN FONTOBJ * pfo)683 BmfdDestroyFont(
684     IN FONTOBJ *pfo)
685 {
686     /* Free the font realization info */
687     EngFreeMem(pfo->pvProducer);
688     pfo->pvProducer = NULL;
689 }
690