Make it easy to use something other than wrc to compile resources.
[wine.git] / dlls / gdi / freetype.c
blobf2ad20d17175e12d4a606874a83b37d08667a7d6
1 /*
2 * FreeType font engine interface
4 * Copyright 2001 Huw D M Davies for CodeWeavers.
6 * This file contains the WineEng* functions.
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include "config.h"
26 #include "windef.h"
27 #include "winerror.h"
28 #include "winreg.h"
29 #include "wingdi.h"
30 #include "wine/unicode.h"
31 #include "wine/port.h"
32 #include "wine/debug.h"
33 #include "gdi.h"
35 #include <stdlib.h>
36 #include <sys/stat.h>
37 #include <string.h>
38 #include <dirent.h>
39 #include <stdio.h>
40 #include <assert.h>
42 WINE_DEFAULT_DEBUG_CHANNEL(font);
44 #ifdef HAVE_FREETYPE
46 #ifdef HAVE_FREETYPE_FREETYPE_H
47 #include <freetype/freetype.h>
48 #endif
49 #ifdef HAVE_FREETYPE_FTGLYPH_H
50 #include <freetype/ftglyph.h>
51 #endif
52 #ifdef HAVE_FREETYPE_TTTABLES_H
53 #include <freetype/tttables.h>
54 #endif
55 #ifdef HAVE_FREETYPE_FTSNAMES_H
56 #include <freetype/ftsnames.h>
57 #else
58 # ifdef HAVE_FREETYPE_FTNAMES_H
59 # include <freetype/ftnames.h>
60 # endif
61 #endif
62 #ifdef HAVE_FREETYPE_TTNAMEID_H
63 #include <freetype/ttnameid.h>
64 #endif
65 #ifdef HAVE_FREETYPE_FTOUTLN_H
66 #include <freetype/ftoutln.h>
67 #endif
68 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
69 #include <freetype/internal/sfnt.h>
70 #endif
71 #ifdef HAVE_FREETYPE_FTTRIGON_H
72 #include <freetype/fttrigon.h>
73 #endif
75 #ifndef SONAME_LIBFREETYPE
76 #define SONAME_LIBFREETYPE "libfreetype.so"
77 #endif
79 static FT_Library library = 0;
80 typedef struct
82 FT_Int major;
83 FT_Int minor;
84 FT_Int patch;
85 } FT_Version_t;
86 static FT_Version_t FT_Version;
88 static void *ft_handle = NULL;
90 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
91 MAKE_FUNCPTR(FT_Cos);
92 MAKE_FUNCPTR(FT_Done_Face);
93 MAKE_FUNCPTR(FT_Get_Char_Index);
94 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
95 MAKE_FUNCPTR(FT_Init_FreeType);
96 MAKE_FUNCPTR(FT_Load_Glyph);
97 MAKE_FUNCPTR(FT_MulFix);
98 MAKE_FUNCPTR(FT_New_Face);
99 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
100 MAKE_FUNCPTR(FT_Outline_Transform);
101 MAKE_FUNCPTR(FT_Outline_Translate);
102 MAKE_FUNCPTR(FT_Select_Charmap);
103 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
104 MAKE_FUNCPTR(FT_Sin);
105 MAKE_FUNCPTR(FT_Vector_Rotate);
106 #undef MAKE_FUNCPTR
107 static void (*pFT_Library_Version)(FT_Library,FT_Int*,FT_Int*,FT_Int*);
109 #define GET_BE_WORD(ptr) MAKEWORD( ((BYTE *)(ptr))[1], ((BYTE *)(ptr))[0] )
111 typedef struct tagFace {
112 WCHAR *StyleName;
113 char *file;
114 FT_Long face_index;
115 BOOL Italic;
116 BOOL Bold;
117 DWORD fsCsb[2]; /* codepage bitfield from FONTSIGNATURE */
118 struct tagFace *next;
119 } Face;
121 typedef struct tagFamily {
122 WCHAR *FamilyName;
123 Face *FirstFace;
124 struct tagFamily *next;
125 } Family;
127 typedef struct {
128 GLYPHMETRICS gm;
129 INT adv; /* These three hold to widths of the unrotated chars */
130 INT lsb;
131 INT bbx;
132 BOOL init;
133 } GM;
135 struct tagGdiFont {
136 FT_Face ft_face;
137 XFORM xform;
138 LPWSTR name;
139 int charset;
140 BOOL fake_italic;
141 BOOL fake_bold;
142 INT orientation;
143 GM *gm;
144 DWORD gmsize;
145 HFONT hfont;
146 SHORT yMax;
147 SHORT yMin;
148 OUTLINETEXTMETRICW *potm;
149 struct tagGdiFont *next;
152 #define INIT_GM_SIZE 128
154 static GdiFont GdiFontList = NULL;
156 static Family *FontList = NULL;
158 static WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ',
159 'R','o','m','a','n','\0'};
160 static WCHAR defSans[] = {'A','r','i','a','l','\0'};
161 static WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
163 static WCHAR defSystem[] = {'A','r','i','a','l','\0'};
164 static WCHAR SystemW[] = {'S','y','s','t','e','m','\0'};
165 static WCHAR MSSansSerifW[] = {'M','S',' ','S','a','n','s',' ',
166 'S','e','r','i','f','\0'};
167 static WCHAR HelvW[] = {'H','e','l','v','\0'};
169 static WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
170 static WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
171 static WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
172 static WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
173 static WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
174 'E','u','r','o','p','e','a','n','\0'};
175 static WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
176 static WCHAR GreekW[] = {'G','r','e','e','k','\0'};
177 static WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
178 static WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
179 static WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
180 static WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
181 static WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
182 static WCHAR ThaiW[] = {'T','h','a','i','\0'};
183 static WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
184 static WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
185 static WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
187 static WCHAR *ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
188 WesternW, /*00*/
189 Central_EuropeanW,
190 CyrillicW,
191 GreekW,
192 TurkishW,
193 HebrewW,
194 ArabicW,
195 BalticW,
196 VietnameseW, /*08*/
197 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
198 ThaiW,
199 JapaneseW,
200 CHINESE_GB2312W,
201 HangulW,
202 CHINESE_BIG5W,
203 Hangul_Johab_W,
204 NULL, NULL, /*23*/
205 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
206 SymbolW /*31*/
209 typedef struct {
210 WCHAR *name;
211 INT charset;
212 } NameCs;
214 typedef struct tagFontSubst {
215 NameCs from;
216 NameCs to;
217 struct tagFontSubst *next;
218 } FontSubst;
220 static FontSubst *substlist = NULL;
222 static BOOL AddFontFileToList(char *file)
224 FT_Face ft_face;
225 TT_OS2 *pOS2;
226 WCHAR *FamilyW, *StyleW;
227 DWORD len;
228 Family *family = FontList;
229 Family **insert = &FontList;
230 Face **insertface;
231 FT_Error err;
232 FT_Long face_index = 0, num_faces;
233 int i;
235 do {
236 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
237 if((err = pFT_New_Face(library, file, face_index, &ft_face)) != 0) {
238 WARN("Unable to load font file %s err = %x\n", debugstr_a(file), err);
239 return FALSE;
242 if(!FT_IS_SFNT(ft_face)) { /* for now we'll skip everything but TT/OT */
243 pFT_Done_Face(ft_face);
244 return FALSE;
246 if(!pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2) ||
247 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea)) {
248 TRACE("Font file %s lacks either an OS2 or HHEA table.\n"
249 "Skipping this font.\n", debugstr_a(file));
250 pFT_Done_Face(ft_face);
251 return FALSE;
254 len = MultiByteToWideChar(CP_ACP, 0, ft_face->family_name, -1, NULL, 0);
255 FamilyW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
256 MultiByteToWideChar(CP_ACP, 0, ft_face->family_name, -1, FamilyW, len);
258 while(family) {
259 if(!strcmpW(family->FamilyName, FamilyW))
260 break;
261 insert = &family->next;
262 family = family->next;
264 if(!family) {
265 family = *insert = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
266 family->FamilyName = FamilyW;
267 family->FirstFace = NULL;
268 family->next = NULL;
269 } else {
270 HeapFree(GetProcessHeap(), 0, FamilyW);
273 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
274 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
275 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
277 for(insertface = &family->FirstFace; *insertface;
278 insertface = &(*insertface)->next) {
279 if(!strcmpW((*insertface)->StyleName, StyleW)) {
280 TRACE("Already loaded font %s %s\n", debugstr_w(family->FamilyName),
281 debugstr_w(StyleW));
282 HeapFree(GetProcessHeap(), 0, StyleW);
283 pFT_Done_Face(ft_face);
284 return FALSE;
287 *insertface = HeapAlloc(GetProcessHeap(), 0, sizeof(**insertface));
288 (*insertface)->StyleName = StyleW;
289 (*insertface)->file = HeapAlloc(GetProcessHeap(),0,strlen(file)+1);
290 strcpy((*insertface)->file, file);
291 (*insertface)->face_index = face_index;
292 (*insertface)->next = NULL;
293 (*insertface)->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
294 (*insertface)->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
296 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
297 if(pOS2) {
298 (*insertface)->fsCsb[0] = pOS2->ulCodePageRange1;
299 (*insertface)->fsCsb[1] = pOS2->ulCodePageRange2;
300 } else {
301 (*insertface)->fsCsb[0] = (*insertface)->fsCsb[1] = 0;
303 TRACE("fsCsb = %08lx %08lx\n", (*insertface)->fsCsb[0], (*insertface)->fsCsb[1]);
305 if((*insertface)->fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
306 for(i = 0; i < ft_face->num_charmaps &&
307 !(*insertface)->fsCsb[0]; i++) {
308 switch(ft_face->charmaps[i]->encoding) {
309 case ft_encoding_unicode:
310 (*insertface)->fsCsb[0] = 1;
311 break;
312 case ft_encoding_symbol:
313 (*insertface)->fsCsb[0] = 1L << 31;
314 break;
315 default:
316 break;
320 num_faces = ft_face->num_faces;
321 pFT_Done_Face(ft_face);
322 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
323 debugstr_w(StyleW));
324 } while(num_faces > ++face_index);
325 return TRUE;
328 static void DumpFontList(void)
330 Family *family;
331 Face *face;
333 for(family = FontList; family; family = family->next) {
334 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
335 for(face = family->FirstFace; face; face = face->next) {
336 TRACE("\t%s\n", debugstr_w(face->StyleName));
339 return;
342 static void DumpSubstList(void)
344 FontSubst *psub;
346 for(psub = substlist; psub; psub = psub->next)
347 if(psub->from.charset != -1 || psub->to.charset != -1)
348 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
349 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
350 else
351 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
352 debugstr_w(psub->to.name));
353 return;
356 static LPWSTR strdupW(LPWSTR p)
358 LPWSTR ret;
359 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
360 ret = HeapAlloc(GetProcessHeap(), 0, len);
361 memcpy(ret, p, len);
362 return ret;
365 static void split_subst_info(NameCs *nc, LPSTR str)
367 CHAR *p = strrchr(str, ',');
368 DWORD len;
370 nc->charset = -1;
371 if(p && *(p+1)) {
372 nc->charset = strtol(p+1, NULL, 10);
373 *p = '\0';
375 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
376 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
377 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
380 static void LoadSubstList(void)
382 FontSubst *psub, **ppsub;
383 HKEY hkey;
384 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
385 LPSTR value;
386 LPVOID data;
388 if(substlist) {
389 for(psub = substlist; psub;) {
390 FontSubst *ptmp;
391 HeapFree(GetProcessHeap(), 0, psub->to.name);
392 HeapFree(GetProcessHeap(), 0, psub->from.name);
393 ptmp = psub;
394 psub = psub->next;
395 HeapFree(GetProcessHeap(), 0, ptmp);
397 substlist = NULL;
400 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
401 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
402 &hkey) == ERROR_SUCCESS) {
404 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
405 &valuelen, &datalen, NULL, NULL);
407 valuelen++; /* returned value doesn't include room for '\0' */
408 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
409 data = HeapAlloc(GetProcessHeap(), 0, datalen);
411 dlen = datalen;
412 vlen = valuelen;
413 ppsub = &substlist;
414 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
415 &dlen) == ERROR_SUCCESS) {
416 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
418 *ppsub = HeapAlloc(GetProcessHeap(), 0, sizeof(**ppsub));
419 (*ppsub)->next = NULL;
420 split_subst_info(&((*ppsub)->from), value);
421 split_subst_info(&((*ppsub)->to), data);
423 /* Win 2000 doesn't allow mapping between different charsets
424 or mapping of DEFAULT_CHARSET */
425 if(((*ppsub)->to.charset != (*ppsub)->from.charset) ||
426 (*ppsub)->to.charset == DEFAULT_CHARSET) {
427 HeapFree(GetProcessHeap(), 0, (*ppsub)->to.name);
428 HeapFree(GetProcessHeap(), 0, (*ppsub)->from.name);
429 HeapFree(GetProcessHeap(), 0, *ppsub);
430 *ppsub = NULL;
431 } else {
432 ppsub = &((*ppsub)->next);
434 /* reset dlen and vlen */
435 dlen = datalen;
436 vlen = valuelen;
438 HeapFree(GetProcessHeap(), 0, data);
439 HeapFree(GetProcessHeap(), 0, value);
440 RegCloseKey(hkey);
444 static BOOL ReadFontDir(char *dirname)
446 DIR *dir;
447 struct dirent *dent;
448 char path[MAX_PATH];
450 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
452 dir = opendir(dirname);
453 if(!dir) {
454 ERR("Can't open directory %s\n", debugstr_a(dirname));
455 return FALSE;
457 while((dent = readdir(dir)) != NULL) {
458 struct stat statbuf;
460 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
461 continue;
463 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
465 sprintf(path, "%s/%s", dirname, dent->d_name);
467 if(stat(path, &statbuf) == -1)
469 WARN("Can't stat %s\n", debugstr_a(path));
470 continue;
472 if(S_ISDIR(statbuf.st_mode))
473 ReadFontDir(path);
474 else
475 AddFontFileToList(path);
477 closedir(dir);
478 return TRUE;
481 /*************************************************************
482 * WineEngAddFontResourceEx
485 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
487 if (ft_handle) /* do it only if we have freetype up and running */
489 DWORD len = WideCharToMultiByte(CP_ACP, 0, file, -1, NULL, 0, NULL, NULL);
490 LPSTR fileA = HeapAlloc(GetProcessHeap(), 0, len);
491 char unixname[MAX_PATH];
492 WideCharToMultiByte(CP_ACP, 0, file, -1, fileA, len, NULL, NULL);
494 if(flags)
495 FIXME("Ignoring flags %lx\n", flags);
497 if(wine_get_unix_file_name(fileA, unixname, sizeof(unixname)))
498 AddFontFileToList(unixname);
499 HeapFree(GetProcessHeap(), 0, fileA);
501 return 1;
504 /*************************************************************
505 * WineEngRemoveFontResourceEx
508 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
510 FIXME(":stub\n");
511 return TRUE;
514 /*************************************************************
515 * WineEngInit
517 * Initialize FreeType library and create a list of available faces
519 BOOL WineEngInit(void)
521 HKEY hkey;
522 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
523 LPSTR value;
524 LPVOID data;
525 char windowsdir[MAX_PATH];
526 char unixname[MAX_PATH];
528 TRACE("\n");
530 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
531 if(!ft_handle) {
532 WINE_MESSAGE(
533 "Wine cannot find the FreeType font library. To enable Wine to\n"
534 "use TrueType fonts please install a version of FreeType greater than\n"
535 "or equal to 2.0.5.\n"
536 "http://www.freetype.org\n");
537 return FALSE;
540 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(ft_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); goto sym_not_found;}
542 LOAD_FUNCPTR(FT_Cos)
543 LOAD_FUNCPTR(FT_Done_Face)
544 LOAD_FUNCPTR(FT_Get_Char_Index)
545 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
546 LOAD_FUNCPTR(FT_Init_FreeType)
547 LOAD_FUNCPTR(FT_Load_Glyph)
548 LOAD_FUNCPTR(FT_MulFix)
549 LOAD_FUNCPTR(FT_New_Face)
550 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
551 LOAD_FUNCPTR(FT_Outline_Transform)
552 LOAD_FUNCPTR(FT_Outline_Translate)
553 LOAD_FUNCPTR(FT_Select_Charmap)
554 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
555 LOAD_FUNCPTR(FT_Sin)
556 LOAD_FUNCPTR(FT_Vector_Rotate)
558 #undef LOAD_FUNCPTR
559 /* Don't warn if this one is missing */
560 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
562 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
563 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
564 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
565 <= 2.0.3 has FT_Sqrt64 */
566 goto sym_not_found;
569 if(pFT_Init_FreeType(&library) != 0) {
570 ERR("Can't init FreeType library\n");
571 wine_dlclose(ft_handle, NULL, 0);
572 ft_handle = NULL;
573 return FALSE;
575 FT_Version.major=FT_Version.minor=FT_Version.patch=-1;
576 if (pFT_Library_Version)
578 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
580 if (FT_Version.major<=0)
582 FT_Version.major=2;
583 FT_Version.minor=0;
584 FT_Version.patch=5;
586 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
588 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
589 GetWindowsDirectoryA(windowsdir, sizeof(windowsdir));
590 strcat(windowsdir, "\\Fonts");
591 if(wine_get_unix_file_name(windowsdir, unixname, sizeof(unixname)))
592 ReadFontDir(unixname);
594 /* now look under HKLM\Software\Microsoft\Windows\CurrentVersion\Fonts
595 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
596 full path as the entry */
597 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
598 "Software\\Microsoft\\Windows\\CurrentVersion\\Fonts",
599 &hkey) == ERROR_SUCCESS) {
600 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
601 &valuelen, &datalen, NULL, NULL);
603 valuelen++; /* returned value doesn't include room for '\0' */
604 value = HeapAlloc(GetProcessHeap(), 0, valuelen);
605 data = HeapAlloc(GetProcessHeap(), 0, datalen);
607 dlen = datalen;
608 vlen = valuelen;
609 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
610 &dlen) == ERROR_SUCCESS) {
611 if(((LPSTR)data)[0] && ((LPSTR)data)[1] == ':')
612 if(wine_get_unix_file_name((LPSTR)data, unixname, sizeof(unixname)))
613 AddFontFileToList(unixname);
615 /* reset dlen and vlen */
616 dlen = datalen;
617 vlen = valuelen;
619 HeapFree(GetProcessHeap(), 0, data);
620 HeapFree(GetProcessHeap(), 0, value);
621 RegCloseKey(hkey);
625 /* then look in any directories that we've specified in the config file */
626 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
627 "Software\\Wine\\Wine\\Config\\FontDirs",
628 &hkey) == ERROR_SUCCESS) {
630 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
631 &valuelen, &datalen, NULL, NULL);
633 valuelen++; /* returned value doesn't include room for '\0' */
634 value = HeapAlloc(GetProcessHeap(), 0, valuelen);
635 data = HeapAlloc(GetProcessHeap(), 0, datalen);
637 dlen = datalen;
638 vlen = valuelen;
639 i = 0;
640 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
641 &dlen) == ERROR_SUCCESS) {
642 TRACE("Got %s=%s\n", value, (LPSTR)data);
643 ReadFontDir((LPSTR)data);
644 /* reset dlen and vlen */
645 dlen = datalen;
646 vlen = valuelen;
648 HeapFree(GetProcessHeap(), 0, data);
649 HeapFree(GetProcessHeap(), 0, value);
650 RegCloseKey(hkey);
653 DumpFontList();
654 LoadSubstList();
655 DumpSubstList();
656 return TRUE;
657 sym_not_found:
658 WINE_MESSAGE(
659 "Wine cannot find certain functions that it needs inside the FreeType\n"
660 "font library. To enable Wine to use TrueType fonts please upgrade\n"
661 "FreeType to at least version 2.0.5.\n"
662 "http://www.freetype.org\n");
663 wine_dlclose(ft_handle, NULL, 0);
664 ft_handle = NULL;
665 return FALSE;
669 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
671 TT_OS2 *pOS2;
672 LONG ppem;
674 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
676 if(height == 0) height = 16;
678 /* Calc. height of EM square:
680 * For +ve lfHeight we have
681 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
682 * Re-arranging gives:
683 * ppem = units_per_em * lfheight / (winAscent + winDescent)
685 * For -ve lfHeight we have
686 * |lfHeight| = ppem
687 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
688 * with il = winAscent + winDescent - units_per_em]
692 if(height > 0)
693 ppem = ft_face->units_per_EM * height /
694 (pOS2->usWinAscent + pOS2->usWinDescent);
695 else
696 ppem = -height;
698 return ppem;
701 static LONG load_VDMX(GdiFont, LONG);
703 static FT_Face OpenFontFile(GdiFont font, char *file, FT_Long face_index, LONG height)
705 FT_Error err;
706 FT_Face ft_face;
707 LONG ppem;
709 err = pFT_New_Face(library, file, face_index, &ft_face);
710 if(err) {
711 ERR("FT_New_Face rets %d\n", err);
712 return 0;
715 /* set it here, as load_VDMX needs it */
716 font->ft_face = ft_face;
718 /* load the VDMX table if we have one */
719 ppem = load_VDMX(font, height);
720 if(ppem == 0)
721 ppem = calc_ppem_for_height(ft_face, height);
723 pFT_Set_Pixel_Sizes(ft_face, 0, ppem);
725 return ft_face;
729 static int get_nearest_charset(Face *face)
731 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
732 a single face with the requested charset. The idea is to check if
733 the selected font supports the current ANSI codepage, if it does
734 return the corresponding charset, else return the first charset */
736 CHARSETINFO csi;
737 int acp = GetACP(), i;
738 DWORD fs0;
740 if(TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE))
741 if(csi.fs.fsCsb[0] & face->fsCsb[0])
742 return csi.ciCharset;
744 for(i = 0; i < 32; i++) {
745 fs0 = 1L << i;
746 if(face->fsCsb[0] & fs0) {
747 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG))
748 return csi.ciCharset;
749 else
750 FIXME("TCI failing on %lx\n", fs0);
754 FIXME("returning DEFAULT_CHARSET face->fsCsb[0] = %08lx file = %s\n",
755 face->fsCsb[0], face->file);
756 return DEFAULT_CHARSET;
759 static GdiFont alloc_font(void)
761 GdiFont ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
762 ret->gmsize = INIT_GM_SIZE;
763 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
764 ret->gmsize * sizeof(*ret->gm));
765 ret->next = NULL;
766 ret->potm = NULL;
767 ret->xform.eM11 = ret->xform.eM22 = 1.0;
768 return ret;
771 static void free_font(GdiFont font)
773 if (font->ft_face) pFT_Done_Face(font->ft_face);
774 if (font->potm) HeapFree(GetProcessHeap(), 0, font->potm);
775 if (font->name) HeapFree(GetProcessHeap(), 0, font->name);
776 HeapFree(GetProcessHeap(), 0, font->gm);
777 HeapFree(GetProcessHeap(), 0, font);
781 /*************************************************************
782 * load_VDMX
784 * load the vdmx entry for the specified height
787 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
788 ( ( (FT_ULong)_x4 << 24 ) | \
789 ( (FT_ULong)_x3 << 16 ) | \
790 ( (FT_ULong)_x2 << 8 ) | \
791 (FT_ULong)_x1 )
793 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
795 typedef struct {
796 BYTE bCharSet;
797 BYTE xRatio;
798 BYTE yStartRatio;
799 BYTE yEndRatio;
800 } Ratios;
803 static LONG load_VDMX(GdiFont font, LONG height)
805 BYTE hdr[6], tmp[2], group[4];
806 BYTE devXRatio, devYRatio;
807 USHORT numRecs, numRatios;
808 DWORD offset = -1;
809 LONG ppem = 0;
810 int i, result;
812 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
814 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
815 return ppem;
817 /* FIXME: need the real device aspect ratio */
818 devXRatio = 1;
819 devYRatio = 1;
821 numRecs = GET_BE_WORD(&hdr[2]);
822 numRatios = GET_BE_WORD(&hdr[4]);
824 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
825 for(i = 0; i < numRatios; i++) {
826 Ratios ratio;
828 offset = (3 * 2) + (i * sizeof(Ratios));
829 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
830 offset = -1;
832 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
834 if(ratio.bCharSet != 1)
835 continue;
837 if((ratio.xRatio == 0 &&
838 ratio.yStartRatio == 0 &&
839 ratio.yEndRatio == 0) ||
840 (devXRatio == ratio.xRatio &&
841 devYRatio >= ratio.yStartRatio &&
842 devYRatio <= ratio.yEndRatio))
844 offset = (3 * 2) + (numRatios * 4) + (i * 2);
845 WineEngGetFontData(font, MS_VDMX_TAG, offset, tmp, 2);
846 offset = GET_BE_WORD(tmp);
847 break;
851 if(offset < 0) {
852 FIXME("No suitable ratio found\n");
853 return ppem;
856 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, group, 4) != GDI_ERROR) {
857 USHORT recs;
858 BYTE startsz, endsz;
859 BYTE *vTable;
861 recs = GET_BE_WORD(group);
862 startsz = group[2];
863 endsz = group[3];
865 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
867 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
868 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
869 if(result == GDI_ERROR) {
870 FIXME("Failed to retrieve vTable\n");
871 goto end;
874 if(height > 0) {
875 for(i = 0; i < recs; i++) {
876 SHORT yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
877 SHORT yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
878 ppem = GET_BE_WORD(&vTable[i * 6]);
880 if(yMax + -yMin == height) {
881 font->yMax = yMax;
882 font->yMin = yMin;
883 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
884 break;
886 if(yMax + -yMin > height) {
887 if(--i < 0) {
888 ppem = 0;
889 goto end; /* failed */
891 font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
892 font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
893 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
894 break;
897 if(!font->yMax) {
898 ppem = 0;
899 TRACE("ppem not found for height %ld\n", height);
901 } else {
902 ppem = -height;
903 if(ppem < startsz || ppem > endsz)
904 goto end;
906 for(i = 0; i < recs; i++) {
907 USHORT yPelHeight;
908 yPelHeight = GET_BE_WORD(&vTable[i * 6]);
910 if(yPelHeight > ppem)
911 break; /* failed */
913 if(yPelHeight == ppem) {
914 font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
915 font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
916 TRACE("ppem %ld found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
917 break;
921 end:
922 HeapFree(GetProcessHeap(), 0, vTable);
925 return ppem;
929 /*************************************************************
930 * WineEngCreateFontInstance
933 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
935 GdiFont ret;
936 Face *face;
937 Family *family = NULL;
938 BOOL bd, it;
939 LOGFONTW lf;
940 CHARSETINFO csi;
942 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
944 TRACE("%s, h=%ld, it=%d, weight=%ld, PandF=%02x, charset=%d orient %ld escapement %ld\n",
945 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
946 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
947 lf.lfEscapement);
949 /* check the cache first */
950 for(ret = GdiFontList; ret; ret = ret->next) {
951 if(ret->hfont == hfont && !memcmp(&ret->xform, &dc->xformWorld2Vport, offsetof(XFORM, eDx))) {
952 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
953 return ret;
957 if(!FontList) /* No fonts installed */
959 TRACE("No fonts installed\n");
960 return NULL;
963 ret = alloc_font();
964 memcpy(&ret->xform, &dc->xformWorld2Vport, sizeof(XFORM));
966 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
967 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
968 original value lfCharSet. Note this is a special case for
969 Symbol and doesn't happen at least for "Wingdings*" */
971 if(!strcmpiW(lf.lfFaceName, SymbolW))
972 lf.lfCharSet = SYMBOL_CHARSET;
974 if(!TranslateCharsetInfo((DWORD*)(INT)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
975 switch(lf.lfCharSet) {
976 case DEFAULT_CHARSET:
977 csi.fs.fsCsb[0] = 0;
978 break;
979 default:
980 FIXME("Untranslated charset %d\n", lf.lfCharSet);
981 csi.fs.fsCsb[0] = 0;
982 break;
986 if(lf.lfFaceName[0] != '\0') {
987 FontSubst *psub;
988 for(psub = substlist; psub; psub = psub->next)
989 if(!strcmpiW(lf.lfFaceName, psub->from.name) &&
990 (psub->from.charset == -1 ||
991 psub->from.charset == lf.lfCharSet))
992 break;
993 if(psub) {
994 TRACE("substituting %s -> %s\n", debugstr_w(lf.lfFaceName),
995 debugstr_w(psub->to.name));
996 strcpyW(lf.lfFaceName, psub->to.name);
999 /* We want a match on name and charset or just name if
1000 charset was DEFAULT_CHARSET. If the latter then
1001 we fixup the returned charset later in get_nearest_charset
1002 where we'll either use the charset of the current ansi codepage
1003 or if that's unavailable the first charset that the font supports.
1005 for(family = FontList; family; family = family->next) {
1006 if(!strcmpiW(family->FamilyName, lf.lfFaceName))
1007 if((csi.fs.fsCsb[0] & family->FirstFace->fsCsb[0]) || !csi.fs.fsCsb[0])
1008 break;
1011 if(!family) { /* do other aliases here */
1012 if(!strcmpiW(lf.lfFaceName, SystemW))
1013 strcpyW(lf.lfFaceName, defSystem);
1014 else if(!strcmpiW(lf.lfFaceName, MSSansSerifW))
1015 strcpyW(lf.lfFaceName, defSans);
1016 else if(!strcmpiW(lf.lfFaceName, HelvW))
1017 strcpyW(lf.lfFaceName, defSans);
1018 else
1019 goto not_found;
1021 for(family = FontList; family; family = family->next) {
1022 if(!strcmpiW(family->FamilyName, lf.lfFaceName))
1023 if((csi.fs.fsCsb[0] & family->FirstFace->fsCsb[0]) || !csi.fs.fsCsb[0])
1024 break;
1029 not_found:
1030 if(!family) {
1031 /* If requested charset was DEFAULT_CHARSET then try using charset
1032 corresponding to the current ansi codepage */
1033 if(!csi.fs.fsCsb[0]) {
1034 INT acp = GetACP();
1035 if(!TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE)) {
1036 FIXME("TCI failed on codepage %d\n", acp);
1037 csi.fs.fsCsb[0] = 0;
1038 } else
1039 lf.lfCharSet = csi.ciCharset;
1041 if(lf.lfPitchAndFamily & FIXED_PITCH ||
1042 lf.lfPitchAndFamily & FF_MODERN)
1043 strcpyW(lf.lfFaceName, defFixed);
1044 else if(lf.lfPitchAndFamily & FF_ROMAN)
1045 strcpyW(lf.lfFaceName, defSerif);
1046 else if(lf.lfPitchAndFamily & FF_SWISS)
1047 strcpyW(lf.lfFaceName, defSans);
1048 else
1049 strcpyW(lf.lfFaceName, defSans);
1050 for(family = FontList; family; family = family->next) {
1051 if(!strcmpiW(family->FamilyName, lf.lfFaceName) &&
1052 (csi.fs.fsCsb[0] & family->FirstFace->fsCsb[0]))
1053 break;
1057 if(!family) {
1058 for(family = FontList; family; family = family->next) {
1059 if(csi.fs.fsCsb[0] & family->FirstFace->fsCsb[0])
1060 break;
1064 if(!family) {
1065 family = FontList;
1066 csi.fs.fsCsb[0] = 0;
1067 FIXME("just using first face for now\n");
1070 it = lf.lfItalic ? 1 : 0;
1071 bd = lf.lfWeight > 550 ? 1 : 0;
1073 for(face = family->FirstFace; face; face = face->next) {
1074 if(!(face->Italic ^ it) && !(face->Bold ^ bd))
1075 break;
1077 if(!face) {
1078 face = family->FirstFace;
1079 if(it && !face->Italic) ret->fake_italic = TRUE;
1080 if(bd && !face->Bold) ret->fake_bold = TRUE;
1083 if(csi.fs.fsCsb[0])
1084 ret->charset = lf.lfCharSet;
1085 else
1086 ret->charset = get_nearest_charset(face);
1088 TRACE("Chosen: %s %s\n", debugstr_w(family->FamilyName),
1089 debugstr_w(face->StyleName));
1091 ret->ft_face = OpenFontFile(ret, face->file, face->face_index,
1092 lf.lfHeight < 0 ?
1093 -abs(INTERNAL_YWSTODS(dc,lf.lfHeight)) :
1094 abs(INTERNAL_YWSTODS(dc, lf.lfHeight)));
1095 if (!ret->ft_face)
1097 free_font( ret );
1098 return 0;
1101 if(ret->charset == SYMBOL_CHARSET)
1102 pFT_Select_Charmap(ret->ft_face, ft_encoding_symbol);
1103 ret->orientation = lf.lfOrientation;
1104 ret->name = strdupW(family->FamilyName);
1106 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
1107 ret->hfont = hfont;
1108 ret->next = GdiFontList;
1109 GdiFontList = ret;
1111 return ret;
1114 static void DumpGdiFontList(void)
1116 GdiFont gdiFont;
1118 TRACE("---------- gdiFont Cache ----------\n");
1119 for(gdiFont = GdiFontList; gdiFont; gdiFont = gdiFont->next) {
1120 LOGFONTW lf;
1121 GetObjectW( gdiFont->hfont, sizeof(lf), &lf );
1122 TRACE("gdiFont=%p hfont=%p (%s)\n",
1123 gdiFont, gdiFont->hfont, debugstr_w(lf.lfFaceName));
1127 /*************************************************************
1128 * WineEngDestroyFontInstance
1130 * free the gdiFont associated with this handle
1133 BOOL WineEngDestroyFontInstance(HFONT handle)
1135 GdiFont gdiFont;
1136 GdiFont gdiPrev = NULL;
1137 BOOL ret = FALSE;
1139 TRACE("destroying hfont=%p\n", handle);
1140 if(TRACE_ON(font))
1141 DumpGdiFontList();
1143 gdiFont = GdiFontList;
1144 while(gdiFont) {
1145 if(gdiFont->hfont == handle) {
1146 if(gdiPrev) {
1147 gdiPrev->next = gdiFont->next;
1148 free_font(gdiFont);
1149 gdiFont = gdiPrev->next;
1150 } else {
1151 GdiFontList = gdiFont->next;
1152 free_font(gdiFont);
1153 gdiFont = GdiFontList;
1155 ret = TRUE;
1156 } else {
1157 gdiPrev = gdiFont;
1158 gdiFont = gdiFont->next;
1161 return ret;
1164 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
1165 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
1167 OUTLINETEXTMETRICW *potm;
1168 UINT size;
1169 GdiFont font = alloc_font();
1171 if (!(font->ft_face = OpenFontFile(font, face->file, face->face_index, 100)))
1173 free_font(font);
1174 return;
1177 memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
1179 size = WineEngGetOutlineTextMetrics(font, 0, NULL);
1180 potm = HeapAlloc(GetProcessHeap(), 0, size);
1181 WineEngGetOutlineTextMetrics(font, size, potm);
1183 #define TM potm->otmTextMetrics
1185 pntm->ntmTm.tmHeight = pelf->elfLogFont.lfHeight = TM.tmHeight;
1186 pntm->ntmTm.tmAscent = TM.tmAscent;
1187 pntm->ntmTm.tmDescent = TM.tmDescent;
1188 pntm->ntmTm.tmInternalLeading = TM.tmInternalLeading;
1189 pntm->ntmTm.tmExternalLeading = TM.tmExternalLeading;
1190 pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWidth = TM.tmAveCharWidth;
1191 pntm->ntmTm.tmMaxCharWidth = TM.tmMaxCharWidth;
1192 pntm->ntmTm.tmWeight = pelf->elfLogFont.lfWeight = TM.tmWeight;
1193 pntm->ntmTm.tmOverhang = TM.tmOverhang;
1194 pntm->ntmTm.tmDigitizedAspectX = TM.tmDigitizedAspectX;
1195 pntm->ntmTm.tmDigitizedAspectY = TM.tmDigitizedAspectY;
1196 pntm->ntmTm.tmFirstChar = TM.tmFirstChar;
1197 pntm->ntmTm.tmLastChar = TM.tmLastChar;
1198 pntm->ntmTm.tmDefaultChar = TM.tmDefaultChar;
1199 pntm->ntmTm.tmBreakChar = TM.tmBreakChar;
1200 pntm->ntmTm.tmItalic = pelf->elfLogFont.lfItalic = TM.tmItalic;
1201 pntm->ntmTm.tmUnderlined = pelf->elfLogFont.lfUnderline = TM.tmUnderlined;
1202 pntm->ntmTm.tmStruckOut = pelf->elfLogFont.lfStrikeOut = TM.tmStruckOut;
1203 pntm->ntmTm.tmPitchAndFamily = TM.tmPitchAndFamily;
1204 pelf->elfLogFont.lfPitchAndFamily = (TM.tmPitchAndFamily & 0xf1) + 1;
1205 pntm->ntmTm.tmCharSet = pelf->elfLogFont.lfCharSet = TM.tmCharSet;
1206 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
1207 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
1208 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
1210 pntm->ntmTm.ntmFlags = TM.tmItalic ? NTM_ITALIC : 0;
1211 if(TM.tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD;
1212 if(pntm->ntmTm.ntmFlags == 0) pntm->ntmTm.ntmFlags = NTM_REGULAR;
1214 pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
1215 pntm->ntmTm.ntmCellHeight = 0;
1216 pntm->ntmTm.ntmAvgWidth = 0;
1218 *ptype = TM.tmPitchAndFamily & TMPF_TRUETYPE ? TRUETYPE_FONTTYPE : 0;
1219 if(!(TM.tmPitchAndFamily & TMPF_VECTOR))
1220 *ptype |= RASTER_FONTTYPE;
1222 #undef TM
1223 memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
1225 strncpyW(pelf->elfLogFont.lfFaceName,
1226 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
1227 LF_FACESIZE);
1228 strncpyW(pelf->elfFullName,
1229 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFaceName),
1230 LF_FULLFACESIZE);
1231 strncpyW(pelf->elfStyle,
1232 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
1233 LF_FACESIZE);
1234 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
1236 HeapFree(GetProcessHeap(), 0, potm);
1237 free_font(font);
1238 return;
1241 /*************************************************************
1242 * WineEngEnumFonts
1245 DWORD WineEngEnumFonts(LPLOGFONTW plf, DEVICEFONTENUMPROC proc,
1246 LPARAM lparam)
1248 Family *family;
1249 Face *face;
1250 ENUMLOGFONTEXW elf;
1251 NEWTEXTMETRICEXW ntm;
1252 DWORD type, ret = 1;
1253 FONTSIGNATURE fs;
1254 CHARSETINFO csi;
1255 int i;
1257 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
1259 if(plf->lfFaceName[0]) {
1260 for(family = FontList; family; family = family->next) {
1261 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
1262 for(face = family->FirstFace; face; face = face->next) {
1263 GetEnumStructs(face, &elf, &ntm, &type);
1264 for(i = 0; i < 32; i++) {
1265 if(face->fsCsb[0] & (1L << i)) {
1266 fs.fsCsb[0] = 1L << i;
1267 fs.fsCsb[1] = 0;
1268 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
1269 TCI_SRCFONTSIG))
1270 csi.ciCharset = DEFAULT_CHARSET;
1271 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
1272 if(csi.ciCharset != DEFAULT_CHARSET) {
1273 elf.elfLogFont.lfCharSet =
1274 ntm.ntmTm.tmCharSet = csi.ciCharset;
1275 if(ElfScriptsW[i])
1276 strcpyW(elf.elfScript, ElfScriptsW[i]);
1277 else
1278 FIXME("Unknown elfscript for bit %d\n", i);
1279 TRACE("enuming face %s full %s style %s charset %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
1280 debugstr_w(elf.elfLogFont.lfFaceName),
1281 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
1282 csi.ciCharset, type, debugstr_w(elf.elfScript),
1283 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
1284 ntm.ntmTm.ntmFlags);
1285 ret = proc(&elf, &ntm, type, lparam);
1286 if(!ret) goto end;
1293 } else {
1294 for(family = FontList; family; family = family->next) {
1295 GetEnumStructs(family->FirstFace, &elf, &ntm, &type);
1296 for(i = 0; i < 32; i++) {
1297 if(family->FirstFace->fsCsb[0] & (1L << i)) {
1298 fs.fsCsb[0] = 1L << i;
1299 fs.fsCsb[1] = 0;
1300 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
1301 TCI_SRCFONTSIG))
1302 csi.ciCharset = DEFAULT_CHARSET;
1303 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
1304 if(csi.ciCharset != DEFAULT_CHARSET) {
1305 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
1306 csi.ciCharset;
1307 if(ElfScriptsW[i])
1308 strcpyW(elf.elfScript, ElfScriptsW[i]);
1309 else
1310 FIXME("Unknown elfscript for bit %d\n", i);
1311 TRACE("enuming face %s full %s style %s charset = %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
1312 debugstr_w(elf.elfLogFont.lfFaceName),
1313 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
1314 csi.ciCharset, type, debugstr_w(elf.elfScript),
1315 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
1316 ntm.ntmTm.ntmFlags);
1317 ret = proc(&elf, &ntm, type, lparam);
1318 if(!ret) goto end;
1324 end:
1325 return ret;
1328 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
1330 pt->x.value = vec->x >> 6;
1331 pt->x.fract = (vec->x & 0x3f) << 10;
1332 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
1333 pt->y.value = vec->y >> 6;
1334 pt->y.fract = (vec->y & 0x3f) << 10;
1335 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
1336 return;
1339 static FT_UInt get_glyph_index(GdiFont font, UINT glyph)
1341 if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
1342 glyph = glyph + 0xf000;
1343 return pFT_Get_Char_Index(font->ft_face, glyph);
1346 /*************************************************************
1347 * WineEngGetGlyphIndices
1349 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
1351 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
1352 LPWORD pgi, DWORD flags)
1354 INT i;
1356 for(i = 0; i < count; i++)
1357 pgi[i] = get_glyph_index(font, lpstr[i]);
1359 return count;
1362 /*************************************************************
1363 * WineEngGetGlyphOutline
1365 * Behaves in exactly the same way as the win32 api GetGlyphOutline
1366 * except that the first parameter is the HWINEENGFONT of the font in
1367 * question rather than an HDC.
1370 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
1371 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
1372 const MAT2* lpmat)
1374 FT_Face ft_face = font->ft_face;
1375 FT_UInt glyph_index;
1376 DWORD width, height, pitch, needed = 0;
1377 FT_Bitmap ft_bitmap;
1378 FT_Error err;
1379 INT left, right, top = 0, bottom = 0;
1380 FT_Angle angle = 0;
1381 FT_Int load_flags = FT_LOAD_DEFAULT;
1383 TRACE("%p, %04x, %08x, %p, %08lx, %p, %p\n", font, glyph, format, lpgm,
1384 buflen, buf, lpmat);
1386 if(format & GGO_GLYPH_INDEX) {
1387 glyph_index = glyph;
1388 format &= ~GGO_GLYPH_INDEX;
1389 } else
1390 glyph_index = get_glyph_index(font, glyph);
1392 if(glyph_index >= font->gmsize) {
1393 font->gmsize = (glyph_index / INIT_GM_SIZE + 1) * INIT_GM_SIZE;
1394 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
1395 font->gmsize * sizeof(*font->gm));
1396 } else {
1397 if(format == GGO_METRICS && font->gm[glyph_index].init) {
1398 memcpy(lpgm, &font->gm[glyph_index].gm, sizeof(*lpgm));
1399 return 1; /* FIXME */
1403 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP))
1404 load_flags |= FT_LOAD_NO_BITMAP;
1406 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
1408 if(err) {
1409 FIXME("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
1410 return GDI_ERROR;
1413 left = ft_face->glyph->metrics.horiBearingX & -64;
1414 right = ((ft_face->glyph->metrics.horiBearingX +
1415 ft_face->glyph->metrics.width) + 63) & -64;
1417 font->gm[glyph_index].adv = (ft_face->glyph->metrics.horiAdvance + 63) >> 6;
1418 font->gm[glyph_index].lsb = left >> 6;
1419 font->gm[glyph_index].bbx = (right - left) >> 6;
1421 if(font->orientation == 0) {
1422 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
1423 bottom = (ft_face->glyph->metrics.horiBearingY -
1424 ft_face->glyph->metrics.height) & -64;
1425 lpgm->gmCellIncX = font->gm[glyph_index].adv;
1426 lpgm->gmCellIncY = 0;
1427 } else {
1428 INT xc, yc;
1429 FT_Vector vec;
1430 angle = font->orientation / 10 << 16;
1431 angle |= ((font->orientation % 10) * (1 << 16)) / 10;
1432 TRACE("angle %ld\n", angle >> 16);
1433 for(xc = 0; xc < 2; xc++) {
1434 for(yc = 0; yc < 2; yc++) {
1435 vec.x = ft_face->glyph->metrics.horiBearingX +
1436 xc * ft_face->glyph->metrics.width;
1437 vec.y = ft_face->glyph->metrics.horiBearingY -
1438 yc * ft_face->glyph->metrics.height;
1439 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
1440 pFT_Vector_Rotate(&vec, angle);
1441 if(xc == 0 && yc == 0) {
1442 left = right = vec.x;
1443 top = bottom = vec.y;
1444 } else {
1445 if(vec.x < left) left = vec.x;
1446 else if(vec.x > right) right = vec.x;
1447 if(vec.y < bottom) bottom = vec.y;
1448 else if(vec.y > top) top = vec.y;
1452 left = left & -64;
1453 right = (right + 63) & -64;
1454 bottom = bottom & -64;
1455 top = (top + 63) & -64;
1457 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
1458 vec.x = ft_face->glyph->metrics.horiAdvance;
1459 vec.y = 0;
1460 pFT_Vector_Rotate(&vec, angle);
1461 lpgm->gmCellIncX = (vec.x+63) >> 6;
1462 lpgm->gmCellIncY = -(vec.y+63) >> 6;
1464 lpgm->gmBlackBoxX = (right - left) >> 6;
1465 lpgm->gmBlackBoxY = (top - bottom) >> 6;
1466 lpgm->gmptGlyphOrigin.x = left >> 6;
1467 lpgm->gmptGlyphOrigin.y = top >> 6;
1469 memcpy(&font->gm[glyph_index].gm, lpgm, sizeof(*lpgm));
1470 font->gm[glyph_index].init = TRUE;
1472 if(format == GGO_METRICS)
1473 return 1; /* FIXME */
1475 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP) {
1476 FIXME("loaded a bitmap\n");
1477 return GDI_ERROR;
1480 switch(format) {
1481 case GGO_BITMAP:
1482 width = lpgm->gmBlackBoxX;
1483 height = lpgm->gmBlackBoxY;
1484 pitch = (width + 31) / 32 * 4;
1485 needed = pitch * height;
1487 if(!buf || !buflen) break;
1489 switch(ft_face->glyph->format) {
1490 case ft_glyph_format_bitmap:
1492 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
1493 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
1494 INT h = ft_face->glyph->bitmap.rows;
1495 while(h--) {
1496 memcpy(dst, src, w);
1497 src += ft_face->glyph->bitmap.pitch;
1498 dst += pitch;
1500 break;
1503 case ft_glyph_format_outline:
1504 ft_bitmap.width = width;
1505 ft_bitmap.rows = height;
1506 ft_bitmap.pitch = pitch;
1507 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
1508 ft_bitmap.buffer = buf;
1510 if(font->orientation) {
1511 FT_Matrix matrix;
1512 matrix.xx = matrix.yy = pFT_Cos(angle);
1513 matrix.xy = -pFT_Sin(angle);
1514 matrix.yx = -matrix.xy;
1516 pFT_Outline_Transform(&ft_face->glyph->outline, &matrix);
1519 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
1521 /* Note: FreeType will only set 'black' bits for us. */
1522 memset(buf, 0, needed);
1523 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
1524 break;
1526 default:
1527 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
1528 return GDI_ERROR;
1530 break;
1532 case GGO_GRAY2_BITMAP:
1533 case GGO_GRAY4_BITMAP:
1534 case GGO_GRAY8_BITMAP:
1535 case WINE_GGO_GRAY16_BITMAP:
1537 int mult, row, col;
1538 BYTE *start, *ptr;
1540 width = lpgm->gmBlackBoxX;
1541 height = lpgm->gmBlackBoxY;
1542 pitch = (width + 3) / 4 * 4;
1543 needed = pitch * height;
1545 if(!buf || !buflen) break;
1546 ft_bitmap.width = width;
1547 ft_bitmap.rows = height;
1548 ft_bitmap.pitch = pitch;
1549 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
1550 ft_bitmap.buffer = buf;
1552 if(font->orientation) {
1553 FT_Matrix matrix;
1554 matrix.xx = matrix.yy = pFT_Cos(angle);
1555 matrix.xy = -pFT_Sin(angle);
1556 matrix.yx = -matrix.xy;
1557 pFT_Outline_Transform(&ft_face->glyph->outline, &matrix);
1560 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
1562 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
1564 if(format == GGO_GRAY2_BITMAP)
1565 mult = 5;
1566 else if(format == GGO_GRAY4_BITMAP)
1567 mult = 17;
1568 else if(format == GGO_GRAY8_BITMAP)
1569 mult = 65;
1570 else if(format == WINE_GGO_GRAY16_BITMAP)
1571 break;
1572 else {
1573 assert(0);
1574 break;
1577 start = buf;
1578 for(row = 0; row < height; row++) {
1579 ptr = start;
1580 for(col = 0; col < width; col++, ptr++) {
1581 *ptr = (*(unsigned int*)ptr * mult + 128) / 256;
1583 start += pitch;
1585 break;
1588 case GGO_NATIVE:
1590 int contour, point = 0, first_pt;
1591 FT_Outline *outline = &ft_face->glyph->outline;
1592 TTPOLYGONHEADER *pph;
1593 TTPOLYCURVE *ppc;
1594 DWORD pph_start, cpfx, type;
1596 if(buflen == 0) buf = NULL;
1598 for(contour = 0; contour < outline->n_contours; contour++) {
1599 pph_start = needed;
1600 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
1601 first_pt = point;
1602 if(buf) {
1603 pph->dwType = TT_POLYGON_TYPE;
1604 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
1606 needed += sizeof(*pph);
1607 point++;
1608 while(point <= outline->contours[contour]) {
1609 ppc = (TTPOLYCURVE *)((char *)buf + needed);
1610 type = (outline->tags[point] & FT_Curve_Tag_On) ?
1611 TT_PRIM_LINE : TT_PRIM_QSPLINE;
1612 cpfx = 0;
1613 do {
1614 if(buf)
1615 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
1616 cpfx++;
1617 point++;
1618 } while(point <= outline->contours[contour] &&
1619 (outline->tags[point] & FT_Curve_Tag_On) ==
1620 (outline->tags[point-1] & FT_Curve_Tag_On));
1621 /* At the end of a contour Windows adds the start point, but
1622 only for Beziers */
1623 if(point > outline->contours[contour] &&
1624 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
1625 if(buf)
1626 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
1627 cpfx++;
1628 } else if(point <= outline->contours[contour] &&
1629 outline->tags[point] & FT_Curve_Tag_On) {
1630 /* add closing pt for bezier */
1631 if(buf)
1632 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
1633 cpfx++;
1634 point++;
1636 if(buf) {
1637 ppc->wType = type;
1638 ppc->cpfx = cpfx;
1640 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
1642 if(buf)
1643 pph->cb = needed - pph_start;
1645 break;
1647 case GGO_BEZIER:
1649 /* Convert the quadratic Beziers to cubic Beziers.
1650 The parametric eqn for a cubic Bezier is, from PLRM:
1651 r(t) = at^3 + bt^2 + ct + r0
1652 with the control points:
1653 r1 = r0 + c/3
1654 r2 = r1 + (c + b)/3
1655 r3 = r0 + c + b + a
1657 A quadratic Beizer has the form:
1658 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
1660 So equating powers of t leads to:
1661 r1 = 2/3 p1 + 1/3 p0
1662 r2 = 2/3 p1 + 1/3 p2
1663 and of course r0 = p0, r3 = p2
1666 int contour, point = 0, first_pt;
1667 FT_Outline *outline = &ft_face->glyph->outline;
1668 TTPOLYGONHEADER *pph;
1669 TTPOLYCURVE *ppc;
1670 DWORD pph_start, cpfx, type;
1671 FT_Vector cubic_control[4];
1672 if(buflen == 0) buf = NULL;
1674 for(contour = 0; contour < outline->n_contours; contour++) {
1675 pph_start = needed;
1676 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
1677 first_pt = point;
1678 if(buf) {
1679 pph->dwType = TT_POLYGON_TYPE;
1680 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
1682 needed += sizeof(*pph);
1683 point++;
1684 while(point <= outline->contours[contour]) {
1685 ppc = (TTPOLYCURVE *)((char *)buf + needed);
1686 type = (outline->tags[point] & FT_Curve_Tag_On) ?
1687 TT_PRIM_LINE : TT_PRIM_CSPLINE;
1688 cpfx = 0;
1689 do {
1690 if(type == TT_PRIM_LINE) {
1691 if(buf)
1692 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
1693 cpfx++;
1694 point++;
1695 } else {
1696 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
1697 so cpfx = 3n */
1699 /* FIXME: Possible optimization in endpoint calculation
1700 if there are two consecutive curves */
1701 cubic_control[0] = outline->points[point-1];
1702 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
1703 cubic_control[0].x += outline->points[point].x + 1;
1704 cubic_control[0].y += outline->points[point].y + 1;
1705 cubic_control[0].x >>= 1;
1706 cubic_control[0].y >>= 1;
1708 if(point+1 > outline->contours[contour])
1709 cubic_control[3] = outline->points[first_pt];
1710 else {
1711 cubic_control[3] = outline->points[point+1];
1712 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
1713 cubic_control[3].x += outline->points[point].x + 1;
1714 cubic_control[3].y += outline->points[point].y + 1;
1715 cubic_control[3].x >>= 1;
1716 cubic_control[3].y >>= 1;
1719 /* r1 = 1/3 p0 + 2/3 p1
1720 r2 = 1/3 p2 + 2/3 p1 */
1721 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
1722 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
1723 cubic_control[2] = cubic_control[1];
1724 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
1725 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
1726 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
1727 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
1728 if(buf) {
1729 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
1730 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
1731 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
1733 cpfx += 3;
1734 point++;
1736 } while(point <= outline->contours[contour] &&
1737 (outline->tags[point] & FT_Curve_Tag_On) ==
1738 (outline->tags[point-1] & FT_Curve_Tag_On));
1739 /* At the end of a contour Windows adds the start point,
1740 but only for Beziers and we've already done that.
1742 if(point <= outline->contours[contour] &&
1743 outline->tags[point] & FT_Curve_Tag_On) {
1744 /* This is the closing pt of a bezier, but we've already
1745 added it, so just inc point and carry on */
1746 point++;
1748 if(buf) {
1749 ppc->wType = type;
1750 ppc->cpfx = cpfx;
1752 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
1754 if(buf)
1755 pph->cb = needed - pph_start;
1757 break;
1760 default:
1761 FIXME("Unsupported format %d\n", format);
1762 return GDI_ERROR;
1764 return needed;
1767 /*************************************************************
1768 * WineEngGetTextMetrics
1771 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
1773 if(!font->potm) {
1774 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
1775 return FALSE;
1777 if(!font->potm) return FALSE;
1778 memcpy(ptm, &font->potm->otmTextMetrics, sizeof(*ptm));
1779 return TRUE;
1783 /*************************************************************
1784 * WineEngGetOutlineTextMetrics
1787 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
1788 OUTLINETEXTMETRICW *potm)
1790 FT_Face ft_face = font->ft_face;
1791 UINT needed, lenfam, lensty, ret;
1792 TT_OS2 *pOS2;
1793 TT_HoriHeader *pHori;
1794 TT_Postscript *pPost;
1795 FT_Fixed x_scale, y_scale;
1796 WCHAR *family_nameW, *style_nameW;
1797 WCHAR spaceW[] = {' ', '\0'};
1798 char *cp;
1800 TRACE("font=%p\n", font);
1802 if(font->potm) {
1803 if(cbSize >= font->potm->otmSize)
1804 memcpy(potm, font->potm, font->potm->otmSize);
1805 return font->potm->otmSize;
1808 needed = sizeof(*potm);
1810 lenfam = MultiByteToWideChar(CP_ACP, 0, ft_face->family_name, -1, NULL, 0)
1811 * sizeof(WCHAR);
1812 family_nameW = HeapAlloc(GetProcessHeap(), 0, lenfam);
1813 MultiByteToWideChar(CP_ACP, 0, ft_face->family_name, -1,
1814 family_nameW, lenfam);
1816 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
1817 * sizeof(WCHAR);
1818 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
1819 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
1820 style_nameW, lensty);
1822 /* These names should be read from the TT name table */
1824 /* length of otmpFamilyName */
1825 needed += lenfam;
1827 /* length of otmpFaceName */
1828 if(!strcasecmp(ft_face->style_name, "regular")) {
1829 needed += lenfam; /* just the family name */
1830 } else {
1831 needed += lenfam + lensty; /* family + " " + style */
1834 /* length of otmpStyleName */
1835 needed += lensty;
1837 /* length of otmpFullName */
1838 needed += lenfam + lensty;
1841 x_scale = ft_face->size->metrics.x_scale;
1842 y_scale = ft_face->size->metrics.y_scale;
1844 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1845 if(!pOS2) {
1846 FIXME("Can't find OS/2 table - not TT font?\n");
1847 ret = 0;
1848 goto end;
1851 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
1852 if(!pHori) {
1853 FIXME("Can't find HHEA table - not TT font?\n");
1854 ret = 0;
1855 goto end;
1858 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
1860 TRACE("OS/2 winA = %d winD = %d typoA = %d typoD = %d typoLG = %d FT_Face a = %d, d = %d, h = %d: HORZ a = %d, d = %d lg = %d maxY = %ld minY = %ld\n",
1861 pOS2->usWinAscent, pOS2->usWinDescent,
1862 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
1863 ft_face->ascender, ft_face->descender, ft_face->height,
1864 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
1865 ft_face->bbox.yMax, ft_face->bbox.yMin);
1867 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
1868 font->potm->otmSize = needed;
1870 #define TM font->potm->otmTextMetrics
1872 if(font->yMax) {
1873 TM.tmAscent = font->yMax;
1874 TM.tmDescent = -font->yMin;
1875 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
1876 } else {
1877 TM.tmAscent = (pFT_MulFix(pOS2->usWinAscent, y_scale) + 32) >> 6;
1878 TM.tmDescent = (pFT_MulFix(pOS2->usWinDescent, y_scale) + 32) >> 6;
1879 TM.tmInternalLeading = (pFT_MulFix(pOS2->usWinAscent + pOS2->usWinDescent
1880 - ft_face->units_per_EM, y_scale) + 32) >> 6;
1883 TM.tmHeight = TM.tmAscent + TM.tmDescent;
1885 /* MSDN says:
1886 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
1888 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
1889 ((pOS2->usWinAscent + pOS2->usWinDescent) -
1890 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
1892 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
1893 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
1894 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
1895 TM.tmOverhang = 0;
1896 TM.tmDigitizedAspectX = 300;
1897 TM.tmDigitizedAspectY = 300;
1898 TM.tmFirstChar = pOS2->usFirstCharIndex;
1899 TM.tmLastChar = pOS2->usLastCharIndex;
1900 TM.tmDefaultChar = pOS2->usDefaultChar;
1901 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
1902 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
1903 TM.tmUnderlined = 0; /* entry in OS2 table */
1904 TM.tmStruckOut = 0; /* entry in OS2 table */
1906 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
1907 if(!FT_IS_FIXED_WIDTH(ft_face))
1908 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
1909 else
1910 TM.tmPitchAndFamily = 0;
1912 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
1913 case PAN_FAMILY_SCRIPT:
1914 TM.tmPitchAndFamily |= FF_SCRIPT;
1915 break;
1916 case PAN_FAMILY_DECORATIVE:
1917 case PAN_FAMILY_PICTORIAL:
1918 TM.tmPitchAndFamily |= FF_DECORATIVE;
1919 break;
1920 case PAN_FAMILY_TEXT_DISPLAY:
1921 if(TM.tmPitchAndFamily == 0) /* fixed */
1922 TM.tmPitchAndFamily = FF_MODERN;
1923 else {
1924 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
1925 case PAN_SERIF_NORMAL_SANS:
1926 case PAN_SERIF_OBTUSE_SANS:
1927 case PAN_SERIF_PERP_SANS:
1928 TM.tmPitchAndFamily |= FF_SWISS;
1929 break;
1930 default:
1931 TM.tmPitchAndFamily |= FF_ROMAN;
1934 break;
1935 default:
1936 TM.tmPitchAndFamily |= FF_DONTCARE;
1939 if(FT_IS_SCALABLE(ft_face))
1940 TM.tmPitchAndFamily |= TMPF_VECTOR;
1941 if(FT_IS_SFNT(ft_face))
1942 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
1944 TM.tmCharSet = font->charset;
1945 #undef TM
1947 font->potm->otmFiller = 0;
1948 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
1949 font->potm->otmfsSelection = pOS2->fsSelection;
1950 font->potm->otmfsType = pOS2->fsType;
1951 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
1952 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
1953 font->potm->otmItalicAngle = 0; /* POST table */
1954 font->potm->otmEMSquare = ft_face->units_per_EM;
1955 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
1956 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
1957 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
1958 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
1959 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
1960 font->potm->otmrcFontBox.left = ft_face->bbox.xMin;
1961 font->potm->otmrcFontBox.right = ft_face->bbox.xMax;
1962 font->potm->otmrcFontBox.top = ft_face->bbox.yMin;
1963 font->potm->otmrcFontBox.bottom = ft_face->bbox.yMax;
1964 font->potm->otmMacAscent = 0; /* where do these come from ? */
1965 font->potm->otmMacDescent = 0;
1966 font->potm->otmMacLineGap = 0;
1967 font->potm->otmusMinimumPPEM = 0; /* TT Header */
1968 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
1969 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
1970 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
1971 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
1972 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
1973 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
1974 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
1975 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
1976 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
1977 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
1978 if(!pPost) {
1979 font->potm->otmsUnderscoreSize = 0;
1980 font->potm->otmsUnderscorePosition = 0;
1981 } else {
1982 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
1983 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
1986 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
1987 cp = (char*)font->potm + sizeof(*font->potm);
1988 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
1989 strcpyW((WCHAR*)cp, family_nameW);
1990 cp += lenfam;
1991 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
1992 strcpyW((WCHAR*)cp, style_nameW);
1993 cp += lensty;
1994 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
1995 strcpyW((WCHAR*)cp, family_nameW);
1996 if(strcasecmp(ft_face->style_name, "regular")) {
1997 strcatW((WCHAR*)cp, spaceW);
1998 strcatW((WCHAR*)cp, style_nameW);
1999 cp += lenfam + lensty;
2000 } else
2001 cp += lenfam;
2002 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
2003 strcpyW((WCHAR*)cp, family_nameW);
2004 strcatW((WCHAR*)cp, spaceW);
2005 strcatW((WCHAR*)cp, style_nameW);
2006 ret = needed;
2008 if(needed <= cbSize)
2009 memcpy(potm, font->potm, font->potm->otmSize);
2011 end:
2012 HeapFree(GetProcessHeap(), 0, style_nameW);
2013 HeapFree(GetProcessHeap(), 0, family_nameW);
2015 return ret;
2019 /*************************************************************
2020 * WineEngGetCharWidth
2023 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
2024 LPINT buffer)
2026 UINT c;
2027 GLYPHMETRICS gm;
2028 FT_UInt glyph_index;
2030 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
2032 for(c = firstChar; c <= lastChar; c++) {
2033 WineEngGetGlyphOutline(font, c, GGO_METRICS, &gm, 0, NULL, NULL);
2034 glyph_index = get_glyph_index(font, c);
2035 buffer[c - firstChar] = font->gm[glyph_index].adv;
2037 return TRUE;
2040 /*************************************************************
2041 * WineEngGetTextExtentPoint
2044 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
2045 LPSIZE size)
2047 INT idx;
2048 GLYPHMETRICS gm;
2049 TEXTMETRICW tm;
2050 FT_UInt glyph_index;
2052 TRACE("%p, %s, %d, %p\n", font, debugstr_wn(wstr, count), count,
2053 size);
2055 size->cx = 0;
2056 WineEngGetTextMetrics(font, &tm);
2057 size->cy = tm.tmHeight;
2059 for(idx = 0; idx < count; idx++) {
2060 WineEngGetGlyphOutline(font, wstr[idx], GGO_METRICS, &gm, 0, NULL,
2061 NULL);
2062 glyph_index = get_glyph_index(font, wstr[idx]);
2063 size->cx += font->gm[glyph_index].adv;
2065 TRACE("return %ld,%ld\n", size->cx, size->cy);
2066 return TRUE;
2069 /*************************************************************
2070 * WineEngGetTextExtentPointI
2073 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
2074 LPSIZE size)
2076 INT idx;
2077 GLYPHMETRICS gm;
2078 TEXTMETRICW tm;
2080 TRACE("%p, %p, %d, %p\n", font, indices, count, size);
2082 size->cx = 0;
2083 WineEngGetTextMetrics(font, &tm);
2084 size->cy = tm.tmHeight;
2086 for(idx = 0; idx < count; idx++) {
2087 WineEngGetGlyphOutline(font, indices[idx],
2088 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
2089 NULL);
2090 size->cx += font->gm[indices[idx]].adv;
2092 TRACE("return %ld,%ld\n", size->cx, size->cy);
2093 return TRUE;
2096 /*************************************************************
2097 * WineEngGetFontData
2100 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
2101 DWORD cbData)
2103 FT_Face ft_face = font->ft_face;
2104 TT_Face tt_face;
2105 SFNT_Interface *sfnt;
2106 DWORD len;
2107 FT_Error err;
2109 TRACE("font=%p, table=%08lx, offset=%08lx, buf=%p, cbData=%lx\n",
2110 font, table, offset, buf, cbData);
2112 if(!FT_IS_SFNT(ft_face))
2113 return GDI_ERROR;
2115 tt_face = (TT_Face) ft_face;
2116 if (FT_Version.major==2 && FT_Version.minor==0)
2118 /* 2.0.x */
2119 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
2121 else
2123 /* A field was added in the middle of the structure in 2.1.x */
2124 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
2127 if(!buf || !cbData)
2128 len = 0;
2129 else
2130 len = cbData;
2132 if(table) { /* MS tags differ in endidness from FT ones */
2133 table = table >> 24 | table << 24 |
2134 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
2137 err = sfnt->load_any(tt_face, table, offset, buf, &len);
2138 if(err) {
2139 TRACE("Can't find table %08lx.\n", table);
2140 return GDI_ERROR;
2142 return len;
2145 /*************************************************************
2146 * WineEngGetTextFace
2149 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
2151 if(str) {
2152 lstrcpynW(str, font->name, count);
2153 return strlenW(font->name);
2154 } else
2155 return strlenW(font->name) + 1;
2159 #else /* HAVE_FREETYPE */
2161 BOOL WineEngInit(void)
2163 return FALSE;
2165 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
2167 return NULL;
2169 BOOL WineEngDestroyFontInstance(HFONT hfont)
2171 return FALSE;
2174 DWORD WineEngEnumFonts(LPLOGFONTW plf, DEVICEFONTENUMPROC proc, LPARAM lparam)
2176 return 1;
2179 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
2180 LPWORD pgi, DWORD flags)
2182 return GDI_ERROR;
2185 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
2186 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
2187 const MAT2* lpmat)
2189 ERR("called but we don't have FreeType\n");
2190 return GDI_ERROR;
2193 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
2195 ERR("called but we don't have FreeType\n");
2196 return FALSE;
2199 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
2200 OUTLINETEXTMETRICW *potm)
2202 ERR("called but we don't have FreeType\n");
2203 return 0;
2206 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
2207 LPINT buffer)
2209 ERR("called but we don't have FreeType\n");
2210 return FALSE;
2213 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
2214 LPSIZE size)
2216 ERR("called but we don't have FreeType\n");
2217 return FALSE;
2220 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
2221 LPSIZE size)
2223 ERR("called but we don't have FreeType\n");
2224 return FALSE;
2227 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
2228 DWORD cbData)
2230 ERR("called but we don't have FreeType\n");
2231 return GDI_ERROR;
2234 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
2236 ERR("called but we don't have FreeType\n");
2237 return 0;
2240 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2242 FIXME(":stub\n");
2243 return 1;
2246 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2248 FIXME(":stub\n");
2249 return TRUE;
2251 #endif /* HAVE_FREETYPE */