Sync with trunk r58740.
[reactos.git] / win32ss / drivers / font / ftfd / font.c
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
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
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
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
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
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
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
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 return NULL;
424 }
425
426 /* Initialize FD_GLYPHSET */
427 pGlyphSet->cjThis = cjSize;
428 pGlyphSet->flAccel = 0;
429 pGlyphSet->cGlyphsSupported = cGlyphs;
430 pGlyphSet->cRuns = cRuns;
431
432 /* Initialize 1st WCRUN */
433 pwcrun = pGlyphSet->awcrun;
434 phglyphs = (PHGLYPH)&pGlyphSet->awcrun[cRuns];
435 pwcrun[0].wcLow = pcp[0].code;
436 pwcrun[0].cGlyphs = 1;
437 pwcrun[0].phg = &phglyphs[0];
438 phglyphs[0] = pcp[0].index;
439
440 DbgPrint("pcp[0].index = 0x%lx\n", pcp[0].index);
441
442 /* Walk through all supported chars */
443 for (i = 1, j = 0; i < cGlyphs; i++)
444 {
445 /* Use glyph index as HGLYPH */
446 phglyphs[i] = pcp[i].index;
447
448 /* Check whether we can append the wchar to a run */
449 if (pcp[i].code == pcp[i - 1].code + 1)
450 {
451 /* Append to current WCRUN */
452 pwcrun[j].cGlyphs++;
453 }
454 else
455 {
456 /* Add a new WCRUN */
457 DbgPrint("adding new run\n");
458 j++;
459 pwcrun[j].wcLow = pcp[i].code;
460 pwcrun[j].cGlyphs = 1;
461 pwcrun[j].phg = &phglyphs[i];
462 }
463 }
464
465 /* Free the temporary buffer */
466 EngFreeMem(pcp);
467
468 /* Set *pid to the allocated structure for use in FtfdFree */
469 *pid = (ULONG_PTR)pGlyphSet;
470
471 DbgPrint("pGlyphSet=%p\n", pGlyphSet);
472 __debugbreak();
473
474 return pGlyphSet;
475 }
476
477 VOID
478 APIENTRY
479 FtfdFree(
480 PVOID pv,
481 ULONG_PTR id)
482 {
483 DbgPrint("FtfdFree()\n");
484 if (id)
485 {
486 EngFreeMem((PVOID)id);
487 }
488 }
489
490
491