xref: /reactos/win32ss/drivers/font/ftfd/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 "ftfd.h"
9 
10 PVOID
HackFixup(PVOID pvView,ULONG cjView)11 HackFixup(
12     PVOID pvView,
13     ULONG cjView)
14 {
15     CHAR *pc;
16 
17     pc = EngAllocMem(0, cjView, 'tmp ');
18     memcpy(pc, pvView, cjView);
19 
20     *pc = 0;
21 
22     return pc;
23 }
24 
25 /** Public Interface **********************************************************/
26 
27 ULONG_PTR
28 APIENTRY
FtfdLoadFontFile(ULONG cFiles,ULONG_PTR * piFile,PVOID * ppvView,ULONG * pcjView,DESIGNVECTOR * pdv,ULONG ulLangID,ULONG ulFastCheckSum)29 FtfdLoadFontFile(
30     ULONG cFiles,
31     ULONG_PTR *piFile,
32     PVOID *ppvView,
33     ULONG *pcjView,
34     DESIGNVECTOR *pdv,
35     ULONG ulLangID,
36     ULONG ulFastCheckSum)
37 {
38     PVOID pvView;
39     ULONG cjView, i;
40     FT_Error fterror;
41     FT_Face ftface;
42     PFTFD_FILE pfile;
43     ULONG cjSize, cNumFaces;
44 
45     DbgPrint("FtfdLoadFontFile()\n");
46 
47     /* Check parameters */
48     if (cFiles != 1)
49     {
50         DbgPrint("Only 1 File is allowed, got %ld!\n", cFiles);
51         return HFF_INVALID;
52     }
53 
54     /* Map the font file */
55     if (!EngMapFontFileFD(*piFile, (PULONG*)&pvView, &cjView))
56     {
57         DbgPrint("Could not map font file!\n");
58         return HFF_INVALID;
59     }
60 
61     // HACK!!!
62     pvView = HackFixup(pvView, cjView);
63 
64     fterror = FT_New_Memory_Face(gftlibrary, pvView, cjView, 0, &ftface);
65     if (fterror)
66     {
67         DbgPrint("No faces found in file\n");
68 
69         /* Unmap the file */
70         EngUnmapFontFileFD(*piFile);
71 
72         /* Failure! */
73         return HFF_INVALID;
74     }
75 
76     /* Get number of faces from the first face */
77     cNumFaces = ftface->num_faces;
78 
79     cjSize = sizeof(FTFD_FILE) + cNumFaces * sizeof(FT_Face);
80     pfile = EngAllocMem(0, cjSize, 'dftF');
81     if (!pfile)
82     {
83         DbgPrint("EngAllocMem() failed.\n");
84 
85         /* Unmap the file */
86         EngUnmapFontFileFD(*piFile);
87 
88         /* Failure! */
89         return HFF_INVALID;
90     }
91 
92     pfile->cNumFaces = cNumFaces;
93     pfile->iFile = *piFile;
94     pfile->pvView = pvView;
95     pfile->cjView = cjView;
96 
97     for (i = 0; i < pfile->cNumFaces; i++)
98     {
99         pfile->aftface[i] = ftface;
100         FT_Select_Charmap(ftface, FT_ENCODING_UNICODE);
101     }
102 
103     DbgPrint("Success! Returning %ld faces\n", cNumFaces);
104 
105     return (ULONG_PTR)pfile;
106 }
107 
108 BOOL
109 APIENTRY
FtfdUnloadFontFile(IN ULONG_PTR iFile)110 FtfdUnloadFontFile(
111     IN ULONG_PTR iFile)
112 {
113     PFTFD_FILE pfile = (PFTFD_FILE)iFile;
114     ULONG i;
115 
116     DbgPrint("FtfdUnloadFontFile()\n");
117 
118     // HACK!!!
119     EngFreeMem(pfile->pvView);
120 
121     /* Cleanup faces */
122     for (i = 0; i < pfile->cNumFaces; i++)
123     {
124         FT_Done_Face(pfile->aftface[i]);
125     }
126 
127     /* Unmap the font file */
128     EngUnmapFontFileFD(pfile->iFile);
129 
130     /* Free the memory that was allocated for the font */
131     EngFreeMem(pfile);
132 
133     return TRUE;
134 }
135 
136 
137 LONG
138 APIENTRY
FtfdQueryFontFile(ULONG_PTR iFile,ULONG ulMode,ULONG cjBuf,ULONG * pulBuf)139 FtfdQueryFontFile(
140     ULONG_PTR iFile,
141     ULONG ulMode,
142     ULONG cjBuf,
143     ULONG *pulBuf)
144 {
145     PFTFD_FILE pfile = (PFTFD_FILE)iFile;
146 
147     DbgPrint("FtfdQueryFontFile(ulMode=%ld)\n", ulMode);
148 //    __debugbreak();
149 
150     switch (ulMode)
151     {
152         case QFF_DESCRIPTION:
153         {
154             return 0;
155         }
156 
157         case QFF_NUMFACES:
158             /* return the number of faces in the file */
159             return pfile->cNumFaces;
160 
161     }
162 
163     return FD_ERROR;
164 }
165 
166 
167 PIFIMETRICS
168 APIENTRY
FtfdQueryFont(IN DHPDEV dhpdev,IN ULONG_PTR iFile,IN ULONG iFace,IN ULONG_PTR * pid)169 FtfdQueryFont(
170     IN DHPDEV dhpdev,
171     IN ULONG_PTR iFile,
172     IN ULONG iFace,
173     IN ULONG_PTR *pid)
174 {
175     PFTFD_FILE pfile = (PFTFD_FILE)iFile;
176     PFTFD_IFIMETRICS pifiX;
177     PIFIMETRICS pifi;
178     FT_Face ftface;
179     FT_Error fterror;
180     ULONG i;
181 
182     DbgPrint("FtfdQueryFont()\n");
183 
184     /* Validate parameters */
185     if (iFace > pfile->cNumFaces || !pid)
186     {
187         DbgPrint("iFace > pfile->cNumFaces || !pid\n");
188         return NULL;
189     }
190 
191     fterror = FT_New_Memory_Face(gftlibrary,
192                                  pfile->pvView,
193                                  pfile->cjView,
194                                  iFace - 1,
195                                  &ftface);
196     if (fterror)
197     {
198         DbgPrint("FT_New_Memory_Face failed\n");
199         return NULL;
200     }
201 
202     /* Allocate the ifi metrics structure */
203     pifiX = EngAllocMem(FL_ZERO_MEMORY, sizeof(FTFD_IFIMETRICS), TAG_IFIMETRICS);
204     if (!pifiX)
205     {
206         DbgPrint("EngAllocMem() failed.\n");
207         FT_Done_Face(ftface);
208         return NULL;
209     }
210 
211     /* Fill IFIMETRICS */
212     pifi = &pifiX->ifim;
213     pifi->cjThis = sizeof(FTFD_IFIMETRICS);
214     pifi->cjIfiExtra = 0;
215 
216     /* Relative offsets */
217     pifi->dpwszFamilyName = FIELD_OFFSET(FTFD_IFIMETRICS, wszFamilyName);
218     pifi->dpwszStyleName = FIELD_OFFSET(FTFD_IFIMETRICS, wszStyleName);
219     pifi->dpwszFaceName = FIELD_OFFSET(FTFD_IFIMETRICS, wszFaceName);
220     pifi->dpwszUniqueName = FIELD_OFFSET(FTFD_IFIMETRICS, wszFaceName);
221     pifi->dpCharSets = FIELD_OFFSET(FTFD_IFIMETRICS, ajCharSet);
222     pifi->dpFontSim = 0;
223 
224     /* Charsets */
225     pifi->jWinCharSet = ANSI_CHARSET;
226     pifiX->ajCharSet[0] = pifi->jWinCharSet;
227     for (i = 1; i < 16; i++)
228     {
229         pifiX->ajCharSet[i] = DEFAULT_CHARSET;
230     }
231 
232     pifi->lEmbedId = 0;
233     pifi->lItalicAngle = 0;
234     pifi->lCharBias = 0;
235     pifi->jWinPitchAndFamily = VARIABLE_PITCH | FF_DONTCARE; // FIXME
236     pifi->usWinWeight = FW_MEDIUM; // FIXME
237     pifi->flInfo = FM_INFO_TECH_TRUETYPE | FM_INFO_ARB_XFORMS |
238                    FM_INFO_1BPP | FM_INFO_4BPP |
239                    FM_INFO_RETURNS_OUTLINES |
240                    FM_INFO_RETURNS_BITMAPS |
241                    FM_INFO_RIGHT_HANDED;
242     pifi->fsSelection = 0;
243     pifi->fsType = 0;
244 
245     /* Font resolution */
246     pifi->fwdUnitsPerEm = ftface->units_per_EM;
247     pifi->fwdLowestPPEm = 8; // FIXME
248 
249     /* Font metrics */
250     pifi->fwdWinAscender = ftface->ascender;
251     pifi->fwdWinDescender = - ftface->descender;
252     pifi->fwdMacAscender = pifi->fwdWinAscender;
253     pifi->fwdMacDescender = - pifi->fwdWinDescender;
254     pifi->fwdMacLineGap = 0;
255     pifi->fwdTypoAscender = pifi->fwdWinAscender;
256     pifi->fwdTypoDescender = 0; // FIXME!!! - pifi->fwdWinDescender;
257     pifi->fwdTypoLineGap = 0;
258     pifi->fwdAveCharWidth = 1085; // FIXME
259     pifi->fwdMaxCharInc =  ftface->max_advance_width;
260     pifi->fwdCapHeight = pifi->fwdUnitsPerEm / 2;
261     pifi->fwdXHeight = pifi->fwdUnitsPerEm / 4;
262     pifi->fwdSubscriptXSize = 0;
263     pifi->fwdSubscriptYSize = 0;
264     pifi->fwdSubscriptXOffset = 0;
265     pifi->fwdSubscriptYOffset = 0;
266     pifi->fwdSuperscriptXSize = 0;
267     pifi->fwdSuperscriptYSize = 0;
268     pifi->fwdSuperscriptXOffset = 0;
269     pifi->fwdSuperscriptYOffset = 0;
270     pifi->fwdUnderscoreSize = 1;
271     pifi->fwdUnderscorePosition = -1;
272     pifi->fwdStrikeoutSize = 1;
273     pifi->fwdStrikeoutPosition = pifi->fwdXHeight + 1;
274 
275     pifi->ptlBaseline.x = 1;
276     pifi->ptlBaseline.y = 0;
277     pifi->ptlAspect.x = 1;
278     pifi->ptlAspect.y = 1;
279     pifi->ptlCaret.x = 0;
280     pifi->ptlCaret.y = 1;
281 
282     /* Set the biggest characters bounding box */
283     pifi->rclFontBox.left = ftface->bbox.xMin;
284     pifi->rclFontBox.right = ftface->bbox.xMax;
285     pifi->rclFontBox.top = ftface->bbox.yMax;
286     pifi->rclFontBox.bottom = ftface->bbox.yMin;
287 
288     /* Special characters */
289     pifi->chFirstChar = 0x1c; // FIXME
290     pifi->chLastChar = 0x79;
291     pifi->chDefaultChar = 0x1d;
292     pifi->chBreakChar = 0x1e;
293     pifi->wcFirstChar = 0x1e;
294     pifi->wcLastChar = 0x79;
295     pifi->wcDefaultChar = 0x1d;
296     pifi->wcBreakChar = 0x1e;
297 
298 
299     *(DWORD*)&pifi->achVendId = 0x30303030; // FIXME
300     pifi->cKerningPairs = 0;
301     pifi->ulPanoseCulture = FM_PANOSE_CULTURE_LATIN;
302 //    pifi->panose = panose;
303 
304     EngMultiByteToUnicodeN(pifiX->wszFamilyName,
305                            LF_FACESIZE,
306                            NULL,
307                            ftface->family_name,
308                            strnlen(ftface->family_name, MAX_PATH));
309 
310     EngMultiByteToUnicodeN(pifiX->wszStyleName,
311                            LF_FACESIZE,
312                            NULL,
313                            ftface->style_name,
314                            strnlen(ftface->style_name, MAX_PATH));
315 
316     EngMultiByteToUnicodeN(pifiX->wszFaceName,
317                            LF_FACESIZE,
318                            NULL,
319                            ftface->family_name,
320                            strnlen(ftface->family_name, MAX_PATH));
321 
322     FT_Done_Face(ftface);
323 
324     DbgPrint("Finished with the ifi: %p\n", pifiX);
325     __debugbreak();
326 
327     return pifi;
328 }
329 
330 
331 LONG
332 APIENTRY
FtfdQueryFontCaps(ULONG culCaps,ULONG * pulCaps)333 FtfdQueryFontCaps(
334     ULONG culCaps,
335     ULONG *pulCaps)
336 {
337     DbgPrint("FtfdQueryFontCaps()\n");
338 
339     /* We need room for 2 ULONGs */
340     if (culCaps < 2)
341     {
342         return FD_ERROR;
343     }
344 
345     /* We only support 1 bpp */
346     pulCaps[0] = 2;
347     pulCaps[1] = QC_1BIT;
348 
349     return 2;
350 }
351 
352 
353 PVOID
354 APIENTRY
FtfdQueryFontTree(DHPDEV dhpdev,ULONG_PTR iFile,ULONG iFace,ULONG iMode,ULONG_PTR * pid)355 FtfdQueryFontTree(
356     DHPDEV dhpdev,
357     ULONG_PTR iFile,
358     ULONG iFace,
359     ULONG iMode,
360     ULONG_PTR *pid)
361 {
362     PFTFD_FILE pfile = (PFTFD_FILE)iFile;
363     FT_Face ftface;
364     FT_Error fterror;
365     FTFD_CHARPAIR *pcp;
366     FD_GLYPHSET *pGlyphSet;
367     FT_ULong charcode;
368     ULONG i, j, cGlyphs, cRuns, cjSize;
369     WCRUN *pwcrun;
370     HGLYPH * phglyphs;
371 
372     DbgPrint("FtfdQueryFontTree()\n");
373 
374     fterror = FT_New_Memory_Face(gftlibrary,
375                                  pfile->pvView,
376                                  pfile->cjView,
377                                  iFace - 1,
378                                  &ftface);
379     if (fterror)
380     {
381         DbgPrint("FT_New_Memory_Face() failed.\n");
382         return NULL;
383     }
384 
385     /* Get initial value for cGlyphs from ftface */
386     cGlyphs = ftface->num_glyphs + 1;
387 
388     /* Allocate a buffer for the char codes and glyph indexes */
389     pcp = EngAllocMem(0, cGlyphs * sizeof(FTFD_CHARPAIR), 'pcp ');
390     if (!pcp)
391     {
392         DbgPrint("EngAllocMem() failed.\n");
393         return NULL;
394     }
395 
396     /* Gather char codes and indexes and count WCRUNs */
397     pcp[0].code = FT_Get_First_Char(ftface, &pcp[0].index);
398     charcode = pcp[0].code;
399     for (i = 1, cRuns = 1; charcode && i < cGlyphs; i++)
400     {
401         charcode = FT_Get_Next_Char(ftface, charcode, &pcp[i].index);
402         DbgPrint("charcode=0x%lx, index=0x%lx\n", charcode, pcp[i].index);
403         pcp[i].code = charcode;
404         if (charcode != pcp[i - 1].code + 1)
405         {
406             cRuns++;
407         }
408     }
409 
410     /* Update cGlyphs to real value */
411     cGlyphs = i - 1;
412 
413     /* Calculate FD_GLYPHSET size */
414     cjSize = sizeof(FD_GLYPHSET)
415              + (cRuns - 1) * sizeof(WCRUN)
416              + cGlyphs * sizeof(HGLYPH);
417 
418     /* Allocate the FD_GLYPHSET structure */
419     pGlyphSet = EngAllocMem(0, cjSize, TAG_GLYPHSET);
420     if (!pGlyphSet)
421     {
422         DbgPrint("EngAllocMem() failed.\n");
423         EngFreeMem(pcp);
424         return NULL;
425     }
426 
427     /* Initialize FD_GLYPHSET */
428     pGlyphSet->cjThis = cjSize;
429     pGlyphSet->flAccel = 0;
430     pGlyphSet->cGlyphsSupported = cGlyphs;
431     pGlyphSet->cRuns = cRuns;
432 
433     /* Initialize 1st WCRUN */
434     pwcrun = pGlyphSet->awcrun;
435     phglyphs = (PHGLYPH)&pGlyphSet->awcrun[cRuns];
436     pwcrun[0].wcLow = pcp[0].code;
437     pwcrun[0].cGlyphs = 1;
438     pwcrun[0].phg = &phglyphs[0];
439     phglyphs[0] = pcp[0].index;
440 
441 DbgPrint("pcp[0].index = 0x%lx\n", pcp[0].index);
442 
443     /* Walk through all supported chars */
444     for (i = 1, j = 0; i < cGlyphs; i++)
445     {
446         /* Use glyph index as HGLYPH */
447         phglyphs[i] = pcp[i].index;
448 
449         /* Check whether we can append the wchar to a run */
450         if (pcp[i].code == pcp[i - 1].code + 1)
451         {
452             /* Append to current WCRUN */
453             pwcrun[j].cGlyphs++;
454         }
455         else
456         {
457             /* Add a new WCRUN */
458             DbgPrint("adding new run\n");
459             j++;
460             pwcrun[j].wcLow = pcp[i].code;
461             pwcrun[j].cGlyphs = 1;
462             pwcrun[j].phg = &phglyphs[i];
463         }
464     }
465 
466     /* Free the temporary buffer */
467     EngFreeMem(pcp);
468 
469     /* Set *pid to the allocated structure for use in FtfdFree */
470     *pid = (ULONG_PTR)pGlyphSet;
471 
472 DbgPrint("pGlyphSet=%p\n", pGlyphSet);
473 __debugbreak();
474 
475     return pGlyphSet;
476 }
477 
478 VOID
479 APIENTRY
FtfdFree(PVOID pv,ULONG_PTR id)480 FtfdFree(
481     PVOID pv,
482     ULONG_PTR id)
483 {
484     DbgPrint("FtfdFree()\n");
485     if (id)
486     {
487         EngFreeMem((PVOID)id);
488     }
489 }
490 
491 
492 
493