Scale the OUTLINETEXTMETRIC's bounding box with the font size.
[wine/hacks.git] / dlls / gdi / freetype.c
blobad7de4b7c295e5f09d1bb57921cd36e8a5c6b888
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 <stdarg.h>
27 #include <stdlib.h>
28 #include <sys/stat.h>
29 #include <string.h>
30 #include <dirent.h>
31 #include <stdio.h>
32 #include <assert.h>
34 #include "windef.h"
35 #include "winbase.h"
36 #include "winerror.h"
37 #include "winreg.h"
38 #include "wingdi.h"
39 #include "wine/unicode.h"
40 #include "wine/port.h"
41 #include "wine/debug.h"
42 #include "gdi.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(font);
46 #ifdef HAVE_FREETYPE
48 #ifdef HAVE_FREETYPE_FREETYPE_H
49 #include <freetype/freetype.h>
50 #endif
51 #ifdef HAVE_FREETYPE_FTGLYPH_H
52 #include <freetype/ftglyph.h>
53 #endif
54 #ifdef HAVE_FREETYPE_TTTABLES_H
55 #include <freetype/tttables.h>
56 #endif
57 #ifdef HAVE_FREETYPE_FTSNAMES_H
58 #include <freetype/ftsnames.h>
59 #else
60 # ifdef HAVE_FREETYPE_FTNAMES_H
61 # include <freetype/ftnames.h>
62 # endif
63 #endif
64 #ifdef HAVE_FREETYPE_TTNAMEID_H
65 #include <freetype/ttnameid.h>
66 #endif
67 #ifdef HAVE_FREETYPE_FTOUTLN_H
68 #include <freetype/ftoutln.h>
69 #endif
70 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
71 #include <freetype/internal/sfnt.h>
72 #endif
73 #ifdef HAVE_FREETYPE_FTTRIGON_H
74 #include <freetype/fttrigon.h>
75 #endif
77 #ifndef SONAME_LIBFREETYPE
78 #define SONAME_LIBFREETYPE "libfreetype.so"
79 #endif
81 static FT_Library library = 0;
82 typedef struct
84 FT_Int major;
85 FT_Int minor;
86 FT_Int patch;
87 } FT_Version_t;
88 static FT_Version_t FT_Version;
90 static void *ft_handle = NULL;
92 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
93 MAKE_FUNCPTR(FT_Vector_Unit);
94 MAKE_FUNCPTR(FT_Done_Face);
95 MAKE_FUNCPTR(FT_Get_Char_Index);
96 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
97 MAKE_FUNCPTR(FT_Init_FreeType);
98 MAKE_FUNCPTR(FT_Load_Glyph);
99 MAKE_FUNCPTR(FT_Matrix_Multiply);
100 MAKE_FUNCPTR(FT_MulFix);
101 MAKE_FUNCPTR(FT_New_Face);
102 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
103 MAKE_FUNCPTR(FT_Outline_Transform);
104 MAKE_FUNCPTR(FT_Outline_Translate);
105 MAKE_FUNCPTR(FT_Select_Charmap);
106 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
107 MAKE_FUNCPTR(FT_Vector_Transform);
108 static void (*pFT_Library_Version)(FT_Library,FT_Int*,FT_Int*,FT_Int*);
109 static FT_Error (*pFT_Load_Sfnt_Table)(FT_Face,FT_ULong,FT_Long,FT_Byte*,FT_ULong*);
111 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
112 #include <fontconfig/fontconfig.h>
113 MAKE_FUNCPTR(FcConfigGetCurrent);
114 MAKE_FUNCPTR(FcFontList);
115 MAKE_FUNCPTR(FcFontSetDestroy);
116 MAKE_FUNCPTR(FcInit);
117 MAKE_FUNCPTR(FcObjectSetAdd);
118 MAKE_FUNCPTR(FcObjectSetCreate);
119 MAKE_FUNCPTR(FcObjectSetDestroy);
120 MAKE_FUNCPTR(FcPatternCreate);
121 MAKE_FUNCPTR(FcPatternDestroy);
122 MAKE_FUNCPTR(FcPatternGet);
123 #ifndef SONAME_LIBFONTCONFIG
124 #define SONAME_LIBFONTCONFIG "libfontconfig.so"
125 #endif
126 #endif
128 #undef MAKE_FUNCPTR
131 #define GET_BE_WORD(ptr) MAKEWORD( ((BYTE *)(ptr))[1], ((BYTE *)(ptr))[0] )
133 typedef struct tagFace {
134 WCHAR *StyleName;
135 char *file;
136 FT_Long face_index;
137 BOOL Italic;
138 BOOL Bold;
139 FONTSIGNATURE fs;
140 FT_Fixed font_version;
141 struct tagFace *next;
142 struct tagFamily *family;
143 } Face;
145 typedef struct tagFamily {
146 WCHAR *FamilyName;
147 Face *FirstFace;
148 struct tagFamily *next;
149 } Family;
151 typedef struct {
152 GLYPHMETRICS gm;
153 INT adv; /* These three hold to widths of the unrotated chars */
154 INT lsb;
155 INT bbx;
156 BOOL init;
157 } GM;
159 struct tagGdiFont {
160 FT_Face ft_face;
161 XFORM xform;
162 LPWSTR name;
163 int charset;
164 BOOL fake_italic;
165 BOOL fake_bold;
166 INT orientation;
167 GM *gm;
168 DWORD gmsize;
169 HFONT hfont;
170 LONG aveWidth;
171 SHORT yMax;
172 SHORT yMin;
173 OUTLINETEXTMETRICW *potm;
174 FONTSIGNATURE fs;
175 struct tagGdiFont *next;
178 #define INIT_GM_SIZE 128
180 static GdiFont GdiFontList = NULL;
182 static Family *FontList = NULL;
184 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ',
185 'R','o','m','a','n','\0'};
186 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
187 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
189 static const WCHAR defSystem[] = {'A','r','i','a','l','\0'};
190 static const WCHAR SystemW[] = {'S','y','s','t','e','m','\0'};
191 static const WCHAR MSSansSerifW[] = {'M','S',' ','S','a','n','s',' ',
192 'S','e','r','i','f','\0'};
193 static const WCHAR HelvW[] = {'H','e','l','v','\0'};
195 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
196 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
197 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
198 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
199 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
200 'E','u','r','o','p','e','a','n','\0'};
201 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
202 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
203 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
204 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
205 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
206 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
207 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
208 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
209 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
210 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
211 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
213 static const WCHAR *ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
214 WesternW, /*00*/
215 Central_EuropeanW,
216 CyrillicW,
217 GreekW,
218 TurkishW,
219 HebrewW,
220 ArabicW,
221 BalticW,
222 VietnameseW, /*08*/
223 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
224 ThaiW,
225 JapaneseW,
226 CHINESE_GB2312W,
227 HangulW,
228 CHINESE_BIG5W,
229 Hangul_Johab_W,
230 NULL, NULL, /*23*/
231 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
232 SymbolW /*31*/
235 typedef struct {
236 WCHAR *name;
237 INT charset;
238 } NameCs;
240 typedef struct tagFontSubst {
241 NameCs from;
242 NameCs to;
243 struct tagFontSubst *next;
244 } FontSubst;
246 static FontSubst *substlist = NULL;
247 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
250 This function builds an FT_Fixed from a float. It puts the integer part
251 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
252 It fails if the integer part of the float number is greater than SHORT_MAX.
254 static inline FT_Fixed FT_FixedFromFloat(float f)
256 short value = f;
257 unsigned short fract = (f - value) * 0xFFFF;
258 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
262 This function builds an FT_Fixed from a FIXED. It simply put f.value
263 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
265 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
267 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
270 static BOOL AddFontFileToList(const char *file, char *fake_family)
272 FT_Face ft_face;
273 TT_OS2 *pOS2;
274 TT_Header *pHeader;
275 WCHAR *FamilyW, *StyleW;
276 DWORD len;
277 Family *family = FontList;
278 Family **insert = &FontList;
279 Face **insertface, *next;
280 FT_Error err;
281 FT_Long face_index = 0, num_faces;
282 int i;
284 do {
285 char *family_name = fake_family;
287 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
288 if((err = pFT_New_Face(library, file, face_index, &ft_face)) != 0) {
289 WARN("Unable to load font file %s err = %x\n", debugstr_a(file), err);
290 return FALSE;
293 if(!FT_IS_SFNT(ft_face)) { /* for now we'll skip everything but TT/OT */
294 pFT_Done_Face(ft_face);
295 return FALSE;
297 if(!pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2) ||
298 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
299 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head))) {
300 TRACE("Font file %s lacks either an OS2, HHEA or HEAD table.\n"
301 "Skipping this font.\n", debugstr_a(file));
302 pFT_Done_Face(ft_face);
303 return FALSE;
306 if(!ft_face->family_name || !ft_face->style_name) {
307 TRACE("Font file %s lacks either a family or style name\n", debugstr_a(file));
308 pFT_Done_Face(ft_face);
309 return FALSE;
312 if(!family_name)
313 family_name = ft_face->family_name;
315 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
316 FamilyW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
317 MultiByteToWideChar(CP_ACP, 0, family_name, -1, FamilyW, len);
319 while(family) {
320 if(!strcmpW(family->FamilyName, FamilyW))
321 break;
322 insert = &family->next;
323 family = family->next;
325 if(!family) {
326 family = *insert = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
327 family->FamilyName = FamilyW;
328 family->FirstFace = NULL;
329 family->next = NULL;
330 } else {
331 HeapFree(GetProcessHeap(), 0, FamilyW);
334 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
335 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
336 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
338 next = NULL;
339 for(insertface = &family->FirstFace; *insertface;
340 insertface = &(*insertface)->next) {
341 if(!strcmpW((*insertface)->StyleName, StyleW)) {
342 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
343 debugstr_w(family->FamilyName), debugstr_w(StyleW),
344 (*insertface)->font_version, pHeader->Font_Revision);
346 if(fake_family) {
347 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
348 HeapFree(GetProcessHeap(), 0, StyleW);
349 pFT_Done_Face(ft_face);
350 return FALSE;
352 if(pHeader->Font_Revision <= (*insertface)->font_version) {
353 TRACE("Original font is newer so skipping this one\n");
354 HeapFree(GetProcessHeap(), 0, StyleW);
355 pFT_Done_Face(ft_face);
356 return FALSE;
357 } else {
358 TRACE("Replacing original with this one\n");
359 next = (*insertface)->next;
360 HeapFree(GetProcessHeap(), 0, (*insertface)->file);
361 HeapFree(GetProcessHeap(), 0, (*insertface)->StyleName);
362 HeapFree(GetProcessHeap(), 0, *insertface);
363 break;
367 *insertface = HeapAlloc(GetProcessHeap(), 0, sizeof(**insertface));
368 (*insertface)->StyleName = StyleW;
369 (*insertface)->file = HeapAlloc(GetProcessHeap(),0,strlen(file)+1);
370 strcpy((*insertface)->file, file);
371 (*insertface)->face_index = face_index;
372 (*insertface)->next = next;
373 (*insertface)->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
374 (*insertface)->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
375 (*insertface)->font_version = pHeader->Font_Revision;
376 (*insertface)->family = family;
378 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
379 if(pOS2) {
380 (*insertface)->fs.fsCsb[0] = pOS2->ulCodePageRange1;
381 (*insertface)->fs.fsCsb[1] = pOS2->ulCodePageRange2;
382 (*insertface)->fs.fsUsb[0] = pOS2->ulUnicodeRange1;
383 (*insertface)->fs.fsUsb[1] = pOS2->ulUnicodeRange2;
384 (*insertface)->fs.fsUsb[2] = pOS2->ulUnicodeRange3;
385 (*insertface)->fs.fsUsb[3] = pOS2->ulUnicodeRange4;
386 } else {
387 (*insertface)->fs.fsCsb[0] = (*insertface)->fs.fsCsb[1] = 0;
388 (*insertface)->fs.fsUsb[0] = 0;
389 (*insertface)->fs.fsUsb[1] = 0;
390 (*insertface)->fs.fsUsb[2] = 0;
391 (*insertface)->fs.fsUsb[3] = 0;
393 TRACE("fsCsb = %08lx %08lx/%08lx %08lx %08lx %08lx\n",
394 (*insertface)->fs.fsCsb[0], (*insertface)->fs.fsCsb[1],
395 (*insertface)->fs.fsUsb[0], (*insertface)->fs.fsUsb[1],
396 (*insertface)->fs.fsUsb[2], (*insertface)->fs.fsUsb[3]);
398 if((*insertface)->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
399 for(i = 0; i < ft_face->num_charmaps; i++) {
400 switch(ft_face->charmaps[i]->encoding) {
401 case ft_encoding_unicode:
402 case ft_encoding_apple_roman:
403 (*insertface)->fs.fsCsb[0] |= 1;
404 break;
405 case ft_encoding_symbol:
406 (*insertface)->fs.fsCsb[0] |= 1L << 31;
407 break;
408 default:
409 break;
414 if((*insertface)->fs.fsCsb[0] & ~(1L << 31))
415 have_installed_roman_font = TRUE;
417 num_faces = ft_face->num_faces;
418 pFT_Done_Face(ft_face);
419 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
420 debugstr_w(StyleW));
421 } while(num_faces > ++face_index);
422 return TRUE;
425 static void DumpFontList(void)
427 Family *family;
428 Face *face;
430 for(family = FontList; family; family = family->next) {
431 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
432 for(face = family->FirstFace; face; face = face->next) {
433 TRACE("\t%s\n", debugstr_w(face->StyleName));
436 return;
439 static void DumpSubstList(void)
441 FontSubst *psub;
443 for(psub = substlist; psub; psub = psub->next)
444 if(psub->from.charset != -1 || psub->to.charset != -1)
445 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
446 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
447 else
448 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
449 debugstr_w(psub->to.name));
450 return;
453 static LPWSTR strdupW(LPWSTR p)
455 LPWSTR ret;
456 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
457 ret = HeapAlloc(GetProcessHeap(), 0, len);
458 memcpy(ret, p, len);
459 return ret;
462 static void split_subst_info(NameCs *nc, LPSTR str)
464 CHAR *p = strrchr(str, ',');
465 DWORD len;
467 nc->charset = -1;
468 if(p && *(p+1)) {
469 nc->charset = strtol(p+1, NULL, 10);
470 *p = '\0';
472 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
473 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
474 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
477 static void LoadSubstList(void)
479 FontSubst *psub, **ppsub;
480 HKEY hkey;
481 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
482 LPSTR value;
483 LPVOID data;
485 if(substlist) {
486 for(psub = substlist; psub;) {
487 FontSubst *ptmp;
488 HeapFree(GetProcessHeap(), 0, psub->to.name);
489 HeapFree(GetProcessHeap(), 0, psub->from.name);
490 ptmp = psub;
491 psub = psub->next;
492 HeapFree(GetProcessHeap(), 0, ptmp);
494 substlist = NULL;
497 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
498 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
499 &hkey) == ERROR_SUCCESS) {
501 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
502 &valuelen, &datalen, NULL, NULL);
504 valuelen++; /* returned value doesn't include room for '\0' */
505 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
506 data = HeapAlloc(GetProcessHeap(), 0, datalen);
508 dlen = datalen;
509 vlen = valuelen;
510 ppsub = &substlist;
511 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
512 &dlen) == ERROR_SUCCESS) {
513 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
515 *ppsub = HeapAlloc(GetProcessHeap(), 0, sizeof(**ppsub));
516 (*ppsub)->next = NULL;
517 split_subst_info(&((*ppsub)->from), value);
518 split_subst_info(&((*ppsub)->to), data);
520 /* Win 2000 doesn't allow mapping between different charsets
521 or mapping of DEFAULT_CHARSET */
522 if(((*ppsub)->to.charset != (*ppsub)->from.charset) ||
523 (*ppsub)->to.charset == DEFAULT_CHARSET) {
524 HeapFree(GetProcessHeap(), 0, (*ppsub)->to.name);
525 HeapFree(GetProcessHeap(), 0, (*ppsub)->from.name);
526 HeapFree(GetProcessHeap(), 0, *ppsub);
527 *ppsub = NULL;
528 } else {
529 ppsub = &((*ppsub)->next);
531 /* reset dlen and vlen */
532 dlen = datalen;
533 vlen = valuelen;
535 HeapFree(GetProcessHeap(), 0, data);
536 HeapFree(GetProcessHeap(), 0, value);
537 RegCloseKey(hkey);
541 /***********************************************************
542 * The replacement list is a way to map an entire font
543 * family onto another family. For example adding
545 * [HKLM\Software\Wine\Wine\FontReplacements]
546 * "Wingdings"="Winedings"
548 * would enumerate the Winedings font both as Winedings and
549 * Wingdings. However if a real Wingdings font is present the
550 * replacement does not take place.
553 static void LoadReplaceList(void)
555 HKEY hkey;
556 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
557 LPSTR value;
558 LPVOID data;
559 Family *family;
560 Face *face;
561 WCHAR old_nameW[200];
563 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
564 "Software\\Wine\\Wine\\FontReplacements",
565 &hkey) == ERROR_SUCCESS) {
567 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
568 &valuelen, &datalen, NULL, NULL);
570 valuelen++; /* returned value doesn't include room for '\0' */
571 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
572 data = HeapAlloc(GetProcessHeap(), 0, datalen);
574 dlen = datalen;
575 vlen = valuelen;
576 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
577 &dlen) == ERROR_SUCCESS) {
578 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
579 /* "NewName"="Oldname" */
580 if(!MultiByteToWideChar(CP_ACP, 0, data, -1, old_nameW, sizeof(old_nameW)))
581 break;
583 /* Find the old family and hence all of the font files
584 in that family */
585 for(family = FontList; family; family = family->next) {
586 if(!strcmpiW(family->FamilyName, old_nameW)) {
587 for(face = family->FirstFace; face; face = face->next) {
588 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
589 debugstr_w(face->StyleName), value);
590 /* Now add a new entry with the new family name */
591 AddFontFileToList(face->file, value);
593 break;
596 /* reset dlen and vlen */
597 dlen = datalen;
598 vlen = valuelen;
600 HeapFree(GetProcessHeap(), 0, data);
601 HeapFree(GetProcessHeap(), 0, value);
602 RegCloseKey(hkey);
607 static BOOL ReadFontDir(char *dirname)
609 DIR *dir;
610 struct dirent *dent;
611 char path[MAX_PATH];
613 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
615 dir = opendir(dirname);
616 if(!dir) {
617 ERR("Can't open directory %s\n", debugstr_a(dirname));
618 return FALSE;
620 while((dent = readdir(dir)) != NULL) {
621 struct stat statbuf;
623 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
624 continue;
626 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
628 sprintf(path, "%s/%s", dirname, dent->d_name);
630 if(stat(path, &statbuf) == -1)
632 WARN("Can't stat %s\n", debugstr_a(path));
633 continue;
635 if(S_ISDIR(statbuf.st_mode))
636 ReadFontDir(path);
637 else
638 AddFontFileToList(path, NULL);
640 closedir(dir);
641 return TRUE;
644 static void load_fontconfig_fonts(void)
646 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
647 void *fc_handle = NULL;
648 FcConfig *config;
649 FcPattern *pat;
650 FcObjectSet *os;
651 FcFontSet *fontset;
652 FcValue v;
653 int i, len;
654 const char *ext;
656 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
657 if(!fc_handle) {
658 TRACE("Wine cannot find the fontconfig library (%s).\n",
659 SONAME_LIBFONTCONFIG);
660 return;
662 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(fc_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); goto sym_not_found;}
663 LOAD_FUNCPTR(FcConfigGetCurrent);
664 LOAD_FUNCPTR(FcFontList);
665 LOAD_FUNCPTR(FcFontSetDestroy);
666 LOAD_FUNCPTR(FcInit);
667 LOAD_FUNCPTR(FcObjectSetAdd);
668 LOAD_FUNCPTR(FcObjectSetCreate);
669 LOAD_FUNCPTR(FcObjectSetDestroy);
670 LOAD_FUNCPTR(FcPatternCreate);
671 LOAD_FUNCPTR(FcPatternDestroy);
672 LOAD_FUNCPTR(FcPatternGet);
673 #undef LOAD_FUNCPTR
675 if(!pFcInit()) return;
677 config = pFcConfigGetCurrent();
678 pat = pFcPatternCreate();
679 os = pFcObjectSetCreate();
680 pFcObjectSetAdd(os, FC_FILE);
681 fontset = pFcFontList(config, pat, os);
682 if(!fontset) return;
683 for(i = 0; i < fontset->nfont; i++) {
684 if(pFcPatternGet(fontset->fonts[i], FC_FILE, 0, &v) != FcResultMatch)
685 continue;
686 if(v.type != FcTypeString) continue;
687 TRACE("fontconfig: %s\n", v.u.s);
689 /* We're just interested in OT/TT fonts for now, so this hack just
690 picks up the standard extensions to save time loading every other
691 font */
692 len = strlen(v.u.s);
693 if(len < 4) continue;
694 ext = v.u.s + len - 3;
695 if(!strcasecmp(ext, "ttf") || !strcasecmp(ext, "ttc") || !strcasecmp(ext, "otf"))
696 AddFontFileToList(v.u.s, NULL);
698 pFcFontSetDestroy(fontset);
699 pFcObjectSetDestroy(os);
700 pFcPatternDestroy(pat);
701 sym_not_found:
702 #endif
703 return;
705 /*************************************************************
706 * WineEngAddFontResourceEx
709 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
711 if (ft_handle) /* do it only if we have freetype up and running */
713 DWORD len = WideCharToMultiByte(CP_ACP, 0, file, -1, NULL, 0, NULL, NULL);
714 LPSTR fileA = HeapAlloc(GetProcessHeap(), 0, len);
715 char unixname[MAX_PATH];
716 WideCharToMultiByte(CP_ACP, 0, file, -1, fileA, len, NULL, NULL);
718 if(flags)
719 FIXME("Ignoring flags %lx\n", flags);
721 if(wine_get_unix_file_name(fileA, unixname, sizeof(unixname)))
722 AddFontFileToList(unixname, NULL);
723 HeapFree(GetProcessHeap(), 0, fileA);
725 return 1;
728 /*************************************************************
729 * WineEngRemoveFontResourceEx
732 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
734 FIXME(":stub\n");
735 return TRUE;
738 /*************************************************************
739 * WineEngInit
741 * Initialize FreeType library and create a list of available faces
743 BOOL WineEngInit(void)
745 HKEY hkey;
746 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
747 LPSTR value;
748 LPVOID data;
749 char windowsdir[MAX_PATH];
750 char unixname[MAX_PATH];
752 TRACE("\n");
754 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
755 if(!ft_handle) {
756 WINE_MESSAGE(
757 "Wine cannot find the FreeType font library. To enable Wine to\n"
758 "use TrueType fonts please install a version of FreeType greater than\n"
759 "or equal to 2.0.5.\n"
760 "http://www.freetype.org\n");
761 return FALSE;
764 #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;}
766 LOAD_FUNCPTR(FT_Vector_Unit)
767 LOAD_FUNCPTR(FT_Done_Face)
768 LOAD_FUNCPTR(FT_Get_Char_Index)
769 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
770 LOAD_FUNCPTR(FT_Init_FreeType)
771 LOAD_FUNCPTR(FT_Load_Glyph)
772 LOAD_FUNCPTR(FT_Matrix_Multiply)
773 LOAD_FUNCPTR(FT_MulFix)
774 LOAD_FUNCPTR(FT_New_Face)
775 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
776 LOAD_FUNCPTR(FT_Outline_Transform)
777 LOAD_FUNCPTR(FT_Outline_Translate)
778 LOAD_FUNCPTR(FT_Select_Charmap)
779 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
780 LOAD_FUNCPTR(FT_Vector_Transform)
782 #undef LOAD_FUNCPTR
783 /* Don't warn if this one is missing */
784 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
785 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
787 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
788 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
789 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
790 <= 2.0.3 has FT_Sqrt64 */
791 goto sym_not_found;
794 if(pFT_Init_FreeType(&library) != 0) {
795 ERR("Can't init FreeType library\n");
796 wine_dlclose(ft_handle, NULL, 0);
797 ft_handle = NULL;
798 return FALSE;
800 FT_Version.major=FT_Version.minor=FT_Version.patch=-1;
801 if (pFT_Library_Version)
803 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
805 if (FT_Version.major<=0)
807 FT_Version.major=2;
808 FT_Version.minor=0;
809 FT_Version.patch=5;
811 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
813 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
814 GetWindowsDirectoryA(windowsdir, sizeof(windowsdir));
815 strcat(windowsdir, "\\Fonts");
816 if(wine_get_unix_file_name(windowsdir, unixname, sizeof(unixname)))
817 ReadFontDir(unixname);
819 /* now look under HKLM\Software\Microsoft\Windows\CurrentVersion\Fonts
820 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
821 full path as the entry */
822 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
823 "Software\\Microsoft\\Windows\\CurrentVersion\\Fonts",
824 &hkey) == ERROR_SUCCESS) {
825 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
826 &valuelen, &datalen, NULL, NULL);
828 valuelen++; /* returned value doesn't include room for '\0' */
829 value = HeapAlloc(GetProcessHeap(), 0, valuelen);
830 data = HeapAlloc(GetProcessHeap(), 0, datalen);
832 dlen = datalen;
833 vlen = valuelen;
834 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
835 &dlen) == ERROR_SUCCESS) {
836 if(((LPSTR)data)[0] && ((LPSTR)data)[1] == ':')
837 if(wine_get_unix_file_name((LPSTR)data, unixname, sizeof(unixname)))
838 AddFontFileToList(unixname, NULL);
840 /* reset dlen and vlen */
841 dlen = datalen;
842 vlen = valuelen;
844 HeapFree(GetProcessHeap(), 0, data);
845 HeapFree(GetProcessHeap(), 0, value);
846 RegCloseKey(hkey);
849 load_fontconfig_fonts();
851 /* then look in any directories that we've specified in the config file */
852 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
853 "Software\\Wine\\Wine\\Config\\FontDirs",
854 &hkey) == ERROR_SUCCESS) {
856 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
857 &valuelen, &datalen, NULL, NULL);
859 valuelen++; /* returned value doesn't include room for '\0' */
860 value = HeapAlloc(GetProcessHeap(), 0, valuelen);
861 data = HeapAlloc(GetProcessHeap(), 0, datalen);
863 dlen = datalen;
864 vlen = valuelen;
865 i = 0;
866 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
867 &dlen) == ERROR_SUCCESS) {
868 TRACE("Got %s=%s\n", value, (LPSTR)data);
869 ReadFontDir((LPSTR)data);
870 /* reset dlen and vlen */
871 dlen = datalen;
872 vlen = valuelen;
874 HeapFree(GetProcessHeap(), 0, data);
875 HeapFree(GetProcessHeap(), 0, value);
876 RegCloseKey(hkey);
879 DumpFontList();
880 LoadSubstList();
881 DumpSubstList();
882 LoadReplaceList();
883 return TRUE;
884 sym_not_found:
885 WINE_MESSAGE(
886 "Wine cannot find certain functions that it needs inside the FreeType\n"
887 "font library. To enable Wine to use TrueType fonts please upgrade\n"
888 "FreeType to at least version 2.0.5.\n"
889 "http://www.freetype.org\n");
890 wine_dlclose(ft_handle, NULL, 0);
891 ft_handle = NULL;
892 return FALSE;
896 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
898 TT_OS2 *pOS2;
899 LONG ppem;
901 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
903 if(height == 0) height = 16;
905 /* Calc. height of EM square:
907 * For +ve lfHeight we have
908 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
909 * Re-arranging gives:
910 * ppem = units_per_em * lfheight / (winAscent + winDescent)
912 * For -ve lfHeight we have
913 * |lfHeight| = ppem
914 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
915 * with il = winAscent + winDescent - units_per_em]
919 if(height > 0)
920 ppem = ft_face->units_per_EM * height /
921 (pOS2->usWinAscent + pOS2->usWinDescent);
922 else
923 ppem = -height;
925 return ppem;
928 static LONG load_VDMX(GdiFont, LONG);
930 static FT_Face OpenFontFile(GdiFont font, char *file, FT_Long face_index, LONG height)
932 FT_Error err;
933 FT_Face ft_face;
934 LONG ppem;
936 err = pFT_New_Face(library, file, face_index, &ft_face);
937 if(err) {
938 ERR("FT_New_Face rets %d\n", err);
939 return 0;
942 /* set it here, as load_VDMX needs it */
943 font->ft_face = ft_face;
945 /* load the VDMX table if we have one */
946 ppem = load_VDMX(font, height);
947 if(ppem == 0)
948 ppem = calc_ppem_for_height(ft_face, height);
950 pFT_Set_Pixel_Sizes(ft_face, 0, ppem);
952 return ft_face;
956 static int get_nearest_charset(Face *face)
958 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
959 a single face with the requested charset. The idea is to check if
960 the selected font supports the current ANSI codepage, if it does
961 return the corresponding charset, else return the first charset */
963 CHARSETINFO csi;
964 int acp = GetACP(), i;
965 DWORD fs0;
967 if(TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE))
968 if(csi.fs.fsCsb[0] & face->fs.fsCsb[0])
969 return csi.ciCharset;
971 for(i = 0; i < 32; i++) {
972 fs0 = 1L << i;
973 if(face->fs.fsCsb[0] & fs0) {
974 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG))
975 return csi.ciCharset;
976 else
977 FIXME("TCI failing on %lx\n", fs0);
981 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08lx file = %s\n",
982 face->fs.fsCsb[0], face->file);
983 return DEFAULT_CHARSET;
986 static GdiFont alloc_font(void)
988 GdiFont ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
989 ret->gmsize = INIT_GM_SIZE;
990 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
991 ret->gmsize * sizeof(*ret->gm));
992 ret->next = NULL;
993 ret->potm = NULL;
994 ret->xform.eM11 = ret->xform.eM22 = 1.0;
995 return ret;
998 static void free_font(GdiFont font)
1000 if (font->ft_face) pFT_Done_Face(font->ft_face);
1001 if (font->potm) HeapFree(GetProcessHeap(), 0, font->potm);
1002 if (font->name) HeapFree(GetProcessHeap(), 0, font->name);
1003 HeapFree(GetProcessHeap(), 0, font->gm);
1004 HeapFree(GetProcessHeap(), 0, font);
1008 /*************************************************************
1009 * load_VDMX
1011 * load the vdmx entry for the specified height
1014 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
1015 ( ( (FT_ULong)_x4 << 24 ) | \
1016 ( (FT_ULong)_x3 << 16 ) | \
1017 ( (FT_ULong)_x2 << 8 ) | \
1018 (FT_ULong)_x1 )
1020 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
1022 typedef struct {
1023 BYTE bCharSet;
1024 BYTE xRatio;
1025 BYTE yStartRatio;
1026 BYTE yEndRatio;
1027 } Ratios;
1030 static LONG load_VDMX(GdiFont font, LONG height)
1032 BYTE hdr[6], tmp[2], group[4];
1033 BYTE devXRatio, devYRatio;
1034 USHORT numRecs, numRatios;
1035 DWORD offset = -1;
1036 LONG ppem = 0;
1037 int i, result;
1039 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
1041 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
1042 return ppem;
1044 /* FIXME: need the real device aspect ratio */
1045 devXRatio = 1;
1046 devYRatio = 1;
1048 numRecs = GET_BE_WORD(&hdr[2]);
1049 numRatios = GET_BE_WORD(&hdr[4]);
1051 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
1052 for(i = 0; i < numRatios; i++) {
1053 Ratios ratio;
1055 offset = (3 * 2) + (i * sizeof(Ratios));
1056 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
1057 offset = -1;
1059 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
1061 if(ratio.bCharSet != 1)
1062 continue;
1064 if((ratio.xRatio == 0 &&
1065 ratio.yStartRatio == 0 &&
1066 ratio.yEndRatio == 0) ||
1067 (devXRatio == ratio.xRatio &&
1068 devYRatio >= ratio.yStartRatio &&
1069 devYRatio <= ratio.yEndRatio))
1071 offset = (3 * 2) + (numRatios * 4) + (i * 2);
1072 WineEngGetFontData(font, MS_VDMX_TAG, offset, tmp, 2);
1073 offset = GET_BE_WORD(tmp);
1074 break;
1078 if(offset < 0) {
1079 FIXME("No suitable ratio found\n");
1080 return ppem;
1083 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, group, 4) != GDI_ERROR) {
1084 USHORT recs;
1085 BYTE startsz, endsz;
1086 BYTE *vTable;
1088 recs = GET_BE_WORD(group);
1089 startsz = group[2];
1090 endsz = group[3];
1092 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
1094 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
1095 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
1096 if(result == GDI_ERROR) {
1097 FIXME("Failed to retrieve vTable\n");
1098 goto end;
1101 if(height > 0) {
1102 for(i = 0; i < recs; i++) {
1103 SHORT yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1104 SHORT yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1105 ppem = GET_BE_WORD(&vTable[i * 6]);
1107 if(yMax + -yMin == height) {
1108 font->yMax = yMax;
1109 font->yMin = yMin;
1110 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
1111 break;
1113 if(yMax + -yMin > height) {
1114 if(--i < 0) {
1115 ppem = 0;
1116 goto end; /* failed */
1118 font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1119 font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1120 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
1121 break;
1124 if(!font->yMax) {
1125 ppem = 0;
1126 TRACE("ppem not found for height %ld\n", height);
1128 } else {
1129 ppem = -height;
1130 if(ppem < startsz || ppem > endsz)
1131 goto end;
1133 for(i = 0; i < recs; i++) {
1134 USHORT yPelHeight;
1135 yPelHeight = GET_BE_WORD(&vTable[i * 6]);
1137 if(yPelHeight > ppem)
1138 break; /* failed */
1140 if(yPelHeight == ppem) {
1141 font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1142 font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1143 TRACE("ppem %ld found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
1144 break;
1148 end:
1149 HeapFree(GetProcessHeap(), 0, vTable);
1152 return ppem;
1156 /*************************************************************
1157 * WineEngCreateFontInstance
1160 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
1162 GdiFont ret;
1163 Face *face;
1164 Family *family = NULL;
1165 BOOL bd, it;
1166 LOGFONTW lf;
1167 CHARSETINFO csi;
1169 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
1171 TRACE("%s, h=%ld, it=%d, weight=%ld, PandF=%02x, charset=%d orient %ld escapement %ld\n",
1172 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
1173 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
1174 lf.lfEscapement);
1176 /* check the cache first */
1177 for(ret = GdiFontList; ret; ret = ret->next) {
1178 if(ret->hfont == hfont && !memcmp(&ret->xform, &dc->xformWorld2Vport, offsetof(XFORM, eDx))) {
1179 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
1180 return ret;
1184 if(!FontList || !have_installed_roman_font) /* No fonts installed */
1186 TRACE("No fonts installed\n");
1187 return NULL;
1190 ret = alloc_font();
1191 memcpy(&ret->xform, &dc->xformWorld2Vport, sizeof(XFORM));
1193 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
1194 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
1195 original value lfCharSet. Note this is a special case for
1196 Symbol and doesn't happen at least for "Wingdings*" */
1198 if(!strcmpiW(lf.lfFaceName, SymbolW))
1199 lf.lfCharSet = SYMBOL_CHARSET;
1201 if(!TranslateCharsetInfo((DWORD*)(INT)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
1202 switch(lf.lfCharSet) {
1203 case DEFAULT_CHARSET:
1204 csi.fs.fsCsb[0] = 0;
1205 break;
1206 default:
1207 FIXME("Untranslated charset %d\n", lf.lfCharSet);
1208 csi.fs.fsCsb[0] = 0;
1209 break;
1213 if(lf.lfFaceName[0] != '\0') {
1214 FontSubst *psub;
1215 for(psub = substlist; psub; psub = psub->next)
1216 if(!strcmpiW(lf.lfFaceName, psub->from.name) &&
1217 (psub->from.charset == -1 ||
1218 psub->from.charset == lf.lfCharSet))
1219 break;
1220 if(psub) {
1221 TRACE("substituting %s -> %s\n", debugstr_w(lf.lfFaceName),
1222 debugstr_w(psub->to.name));
1223 strcpyW(lf.lfFaceName, psub->to.name);
1226 /* We want a match on name and charset or just name if
1227 charset was DEFAULT_CHARSET. If the latter then
1228 we fixup the returned charset later in get_nearest_charset
1229 where we'll either use the charset of the current ansi codepage
1230 or if that's unavailable the first charset that the font supports.
1232 for(family = FontList; family; family = family->next) {
1233 if(!strcmpiW(family->FamilyName, lf.lfFaceName))
1234 if((csi.fs.fsCsb[0] & family->FirstFace->fs.fsCsb[0]) || !csi.fs.fsCsb[0])
1235 break;
1238 if(!family) { /* do other aliases here */
1239 if(!strcmpiW(lf.lfFaceName, SystemW))
1240 strcpyW(lf.lfFaceName, defSystem);
1241 else if(!strcmpiW(lf.lfFaceName, MSSansSerifW))
1242 strcpyW(lf.lfFaceName, defSans);
1243 else if(!strcmpiW(lf.lfFaceName, HelvW))
1244 strcpyW(lf.lfFaceName, defSans);
1245 else
1246 goto not_found;
1248 for(family = FontList; family; family = family->next) {
1249 if(!strcmpiW(family->FamilyName, lf.lfFaceName))
1250 if((csi.fs.fsCsb[0] & family->FirstFace->fs.fsCsb[0]) || !csi.fs.fsCsb[0])
1251 break;
1256 not_found:
1257 if(!family) {
1258 /* If requested charset was DEFAULT_CHARSET then try using charset
1259 corresponding to the current ansi codepage */
1260 if(!csi.fs.fsCsb[0]) {
1261 INT acp = GetACP();
1262 if(!TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE)) {
1263 FIXME("TCI failed on codepage %d\n", acp);
1264 csi.fs.fsCsb[0] = 0;
1265 } else
1266 lf.lfCharSet = csi.ciCharset;
1269 /* Face families are in the top 4 bits of lfPitchAndFamily,
1270 so mask with 0xF0 before testing */
1272 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
1273 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
1274 strcpyW(lf.lfFaceName, defFixed);
1275 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
1276 strcpyW(lf.lfFaceName, defSerif);
1277 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
1278 strcpyW(lf.lfFaceName, defSans);
1279 else
1280 strcpyW(lf.lfFaceName, defSans);
1281 for(family = FontList; family; family = family->next) {
1282 if(!strcmpiW(family->FamilyName, lf.lfFaceName) &&
1283 (csi.fs.fsCsb[0] & family->FirstFace->fs.fsCsb[0]))
1284 break;
1288 if(!family) {
1289 for(family = FontList; family; family = family->next) {
1290 if(csi.fs.fsCsb[0] & family->FirstFace->fs.fsCsb[0])
1291 break;
1295 if(!family) {
1296 family = FontList;
1297 csi.fs.fsCsb[0] = 0;
1298 FIXME("just using first face for now\n");
1301 it = lf.lfItalic ? 1 : 0;
1302 bd = lf.lfWeight > 550 ? 1 : 0;
1304 for(face = family->FirstFace; face; face = face->next) {
1305 if(!(face->Italic ^ it) && !(face->Bold ^ bd))
1306 break;
1308 if(!face) {
1309 face = family->FirstFace;
1310 if(it && !face->Italic) ret->fake_italic = TRUE;
1311 if(bd && !face->Bold) ret->fake_bold = TRUE;
1314 memcpy(&ret->fs, &face->fs, sizeof(FONTSIGNATURE));
1316 if(csi.fs.fsCsb[0])
1317 ret->charset = lf.lfCharSet;
1318 else
1319 ret->charset = get_nearest_charset(face);
1321 TRACE("Chosen: %s %s\n", debugstr_w(family->FamilyName),
1322 debugstr_w(face->StyleName));
1324 ret->ft_face = OpenFontFile(ret, face->file, face->face_index,
1325 lf.lfHeight < 0 ?
1326 -abs(INTERNAL_YWSTODS(dc,lf.lfHeight)) :
1327 abs(INTERNAL_YWSTODS(dc, lf.lfHeight)));
1328 if (!ret->ft_face)
1330 free_font( ret );
1331 return 0;
1334 if (ret->charset == SYMBOL_CHARSET &&
1335 !pFT_Select_Charmap(ret->ft_face, ft_encoding_symbol)) {
1336 /* No ops */
1338 else if (!pFT_Select_Charmap(ret->ft_face, ft_encoding_unicode)) {
1339 /* No ops */
1341 else {
1342 pFT_Select_Charmap(ret->ft_face, ft_encoding_apple_roman);
1345 ret->orientation = lf.lfOrientation;
1346 ret->name = strdupW(family->FamilyName);
1348 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
1349 ret->hfont = hfont;
1350 ret->aveWidth= lf.lfWidth;
1351 ret->next = GdiFontList;
1352 GdiFontList = ret;
1354 return ret;
1357 static void DumpGdiFontList(void)
1359 GdiFont gdiFont;
1361 TRACE("---------- gdiFont Cache ----------\n");
1362 for(gdiFont = GdiFontList; gdiFont; gdiFont = gdiFont->next) {
1363 LOGFONTW lf;
1364 GetObjectW( gdiFont->hfont, sizeof(lf), &lf );
1365 TRACE("gdiFont=%p hfont=%p (%s)\n",
1366 gdiFont, gdiFont->hfont, debugstr_w(lf.lfFaceName));
1370 /*************************************************************
1371 * WineEngDestroyFontInstance
1373 * free the gdiFont associated with this handle
1376 BOOL WineEngDestroyFontInstance(HFONT handle)
1378 GdiFont gdiFont;
1379 GdiFont gdiPrev = NULL;
1380 BOOL ret = FALSE;
1382 TRACE("destroying hfont=%p\n", handle);
1383 if(TRACE_ON(font))
1384 DumpGdiFontList();
1386 gdiFont = GdiFontList;
1387 while(gdiFont) {
1388 if(gdiFont->hfont == handle) {
1389 if(gdiPrev) {
1390 gdiPrev->next = gdiFont->next;
1391 free_font(gdiFont);
1392 gdiFont = gdiPrev->next;
1393 } else {
1394 GdiFontList = gdiFont->next;
1395 free_font(gdiFont);
1396 gdiFont = GdiFontList;
1398 ret = TRUE;
1399 } else {
1400 gdiPrev = gdiFont;
1401 gdiFont = gdiFont->next;
1404 return ret;
1407 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
1408 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
1410 OUTLINETEXTMETRICW *potm;
1411 UINT size;
1412 GdiFont font = alloc_font();
1414 if (!(font->ft_face = OpenFontFile(font, face->file, face->face_index, 100)))
1416 free_font(font);
1417 return;
1420 font->name = strdupW(face->family->FamilyName);
1422 memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
1424 size = WineEngGetOutlineTextMetrics(font, 0, NULL);
1425 potm = HeapAlloc(GetProcessHeap(), 0, size);
1426 WineEngGetOutlineTextMetrics(font, size, potm);
1428 #define TM potm->otmTextMetrics
1430 pntm->ntmTm.tmHeight = pelf->elfLogFont.lfHeight = TM.tmHeight;
1431 pntm->ntmTm.tmAscent = TM.tmAscent;
1432 pntm->ntmTm.tmDescent = TM.tmDescent;
1433 pntm->ntmTm.tmInternalLeading = TM.tmInternalLeading;
1434 pntm->ntmTm.tmExternalLeading = TM.tmExternalLeading;
1435 pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWidth = TM.tmAveCharWidth;
1436 pntm->ntmTm.tmMaxCharWidth = TM.tmMaxCharWidth;
1437 pntm->ntmTm.tmWeight = pelf->elfLogFont.lfWeight = TM.tmWeight;
1438 pntm->ntmTm.tmOverhang = TM.tmOverhang;
1439 pntm->ntmTm.tmDigitizedAspectX = TM.tmDigitizedAspectX;
1440 pntm->ntmTm.tmDigitizedAspectY = TM.tmDigitizedAspectY;
1441 pntm->ntmTm.tmFirstChar = TM.tmFirstChar;
1442 pntm->ntmTm.tmLastChar = TM.tmLastChar;
1443 pntm->ntmTm.tmDefaultChar = TM.tmDefaultChar;
1444 pntm->ntmTm.tmBreakChar = TM.tmBreakChar;
1445 pntm->ntmTm.tmItalic = pelf->elfLogFont.lfItalic = TM.tmItalic;
1446 pntm->ntmTm.tmUnderlined = pelf->elfLogFont.lfUnderline = TM.tmUnderlined;
1447 pntm->ntmTm.tmStruckOut = pelf->elfLogFont.lfStrikeOut = TM.tmStruckOut;
1448 pntm->ntmTm.tmPitchAndFamily = TM.tmPitchAndFamily;
1449 pelf->elfLogFont.lfPitchAndFamily = (TM.tmPitchAndFamily & 0xf1) + 1;
1450 pntm->ntmTm.tmCharSet = pelf->elfLogFont.lfCharSet = TM.tmCharSet;
1451 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
1452 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
1453 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
1455 pntm->ntmTm.ntmFlags = TM.tmItalic ? NTM_ITALIC : 0;
1456 if(TM.tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD;
1457 if(pntm->ntmTm.ntmFlags == 0) pntm->ntmTm.ntmFlags = NTM_REGULAR;
1459 pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
1460 pntm->ntmTm.ntmCellHeight = 0;
1461 pntm->ntmTm.ntmAvgWidth = 0;
1463 *ptype = TM.tmPitchAndFamily & TMPF_TRUETYPE ? TRUETYPE_FONTTYPE : 0;
1464 if(!(TM.tmPitchAndFamily & TMPF_VECTOR))
1465 *ptype |= RASTER_FONTTYPE;
1467 #undef TM
1468 memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
1470 strncpyW(pelf->elfLogFont.lfFaceName,
1471 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
1472 LF_FACESIZE);
1473 strncpyW(pelf->elfFullName,
1474 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFaceName),
1475 LF_FULLFACESIZE);
1476 strncpyW(pelf->elfStyle,
1477 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
1478 LF_FACESIZE);
1479 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
1481 HeapFree(GetProcessHeap(), 0, potm);
1482 free_font(font);
1483 return;
1486 /*************************************************************
1487 * WineEngEnumFonts
1490 DWORD WineEngEnumFonts(LPLOGFONTW plf, DEVICEFONTENUMPROC proc,
1491 LPARAM lparam)
1493 Family *family;
1494 Face *face;
1495 ENUMLOGFONTEXW elf;
1496 NEWTEXTMETRICEXW ntm;
1497 DWORD type, ret = 1;
1498 FONTSIGNATURE fs;
1499 CHARSETINFO csi;
1500 LOGFONTW lf;
1501 int i;
1503 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
1505 if(plf->lfFaceName[0]) {
1506 FontSubst *psub;
1507 for(psub = substlist; psub; psub = psub->next)
1508 if(!strcmpiW(plf->lfFaceName, psub->from.name) &&
1509 (psub->from.charset == -1 ||
1510 psub->from.charset == plf->lfCharSet))
1511 break;
1512 if(psub) {
1513 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
1514 debugstr_w(psub->to.name));
1515 memcpy(&lf, plf, sizeof(lf));
1516 strcpyW(lf.lfFaceName, psub->to.name);
1517 plf = &lf;
1519 for(family = FontList; family; family = family->next) {
1520 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
1521 for(face = family->FirstFace; face; face = face->next) {
1522 GetEnumStructs(face, &elf, &ntm, &type);
1523 for(i = 0; i < 32; i++) {
1524 if(face->fs.fsCsb[0] & (1L << i)) {
1525 fs.fsCsb[0] = 1L << i;
1526 fs.fsCsb[1] = 0;
1527 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
1528 TCI_SRCFONTSIG))
1529 csi.ciCharset = DEFAULT_CHARSET;
1530 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
1531 if(csi.ciCharset != DEFAULT_CHARSET) {
1532 elf.elfLogFont.lfCharSet =
1533 ntm.ntmTm.tmCharSet = csi.ciCharset;
1534 if(ElfScriptsW[i])
1535 strcpyW(elf.elfScript, ElfScriptsW[i]);
1536 else
1537 FIXME("Unknown elfscript for bit %d\n", i);
1538 TRACE("enuming face %s full %s style %s charset %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
1539 debugstr_w(elf.elfLogFont.lfFaceName),
1540 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
1541 csi.ciCharset, type, debugstr_w(elf.elfScript),
1542 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
1543 ntm.ntmTm.ntmFlags);
1544 ret = proc(&elf, &ntm, type, lparam);
1545 if(!ret) goto end;
1552 } else {
1553 for(family = FontList; family; family = family->next) {
1554 GetEnumStructs(family->FirstFace, &elf, &ntm, &type);
1555 for(i = 0; i < 32; i++) {
1556 if(family->FirstFace->fs.fsCsb[0] & (1L << i)) {
1557 fs.fsCsb[0] = 1L << i;
1558 fs.fsCsb[1] = 0;
1559 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
1560 TCI_SRCFONTSIG))
1561 csi.ciCharset = DEFAULT_CHARSET;
1562 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
1563 if(csi.ciCharset != DEFAULT_CHARSET) {
1564 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
1565 csi.ciCharset;
1566 if(ElfScriptsW[i])
1567 strcpyW(elf.elfScript, ElfScriptsW[i]);
1568 else
1569 FIXME("Unknown elfscript for bit %d\n", i);
1570 TRACE("enuming face %s full %s style %s charset = %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
1571 debugstr_w(elf.elfLogFont.lfFaceName),
1572 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
1573 csi.ciCharset, type, debugstr_w(elf.elfScript),
1574 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
1575 ntm.ntmTm.ntmFlags);
1576 ret = proc(&elf, &ntm, type, lparam);
1577 if(!ret) goto end;
1583 end:
1584 return ret;
1587 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
1589 pt->x.value = vec->x >> 6;
1590 pt->x.fract = (vec->x & 0x3f) << 10;
1591 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
1592 pt->y.value = vec->y >> 6;
1593 pt->y.fract = (vec->y & 0x3f) << 10;
1594 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
1595 return;
1598 static FT_UInt get_glyph_index(GdiFont font, UINT glyph)
1600 if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
1601 glyph = glyph + 0xf000;
1602 return pFT_Get_Char_Index(font->ft_face, glyph);
1605 /*************************************************************
1606 * WineEngGetGlyphIndices
1608 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
1610 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
1611 LPWORD pgi, DWORD flags)
1613 INT i;
1615 for(i = 0; i < count; i++)
1616 pgi[i] = get_glyph_index(font, lpstr[i]);
1618 return count;
1621 /*************************************************************
1622 * WineEngGetGlyphOutline
1624 * Behaves in exactly the same way as the win32 api GetGlyphOutline
1625 * except that the first parameter is the HWINEENGFONT of the font in
1626 * question rather than an HDC.
1629 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
1630 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
1631 const MAT2* lpmat)
1633 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
1634 FT_Face ft_face = font->ft_face;
1635 FT_UInt glyph_index;
1636 DWORD width, height, pitch, needed = 0;
1637 FT_Bitmap ft_bitmap;
1638 FT_Error err;
1639 INT left, right, top = 0, bottom = 0;
1640 FT_Angle angle = 0;
1641 FT_Int load_flags = FT_LOAD_DEFAULT;
1642 float widthRatio = 1.0;
1643 FT_Matrix transMat = identityMat;
1644 BOOL needsTransform = FALSE;
1647 TRACE("%p, %04x, %08x, %p, %08lx, %p, %p\n", font, glyph, format, lpgm,
1648 buflen, buf, lpmat);
1650 if(format & GGO_GLYPH_INDEX) {
1651 glyph_index = glyph;
1652 format &= ~GGO_GLYPH_INDEX;
1653 } else
1654 glyph_index = get_glyph_index(font, glyph);
1656 if(glyph_index >= font->gmsize) {
1657 font->gmsize = (glyph_index / INIT_GM_SIZE + 1) * INIT_GM_SIZE;
1658 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
1659 font->gmsize * sizeof(*font->gm));
1660 } else {
1661 if(format == GGO_METRICS && font->gm[glyph_index].init) {
1662 memcpy(lpgm, &font->gm[glyph_index].gm, sizeof(*lpgm));
1663 return 1; /* FIXME */
1667 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP) || font->aveWidth || lpmat)
1668 load_flags |= FT_LOAD_NO_BITMAP;
1670 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
1672 if(err) {
1673 FIXME("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
1674 return GDI_ERROR;
1677 /* Scaling factor */
1678 if (font->aveWidth && font->potm) {
1679 widthRatio = (float)font->aveWidth * font->xform.eM11 / (float) font->potm->otmTextMetrics.tmAveCharWidth;
1682 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
1683 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
1685 font->gm[glyph_index].adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
1686 font->gm[glyph_index].lsb = left >> 6;
1687 font->gm[glyph_index].bbx = (right - left) >> 6;
1689 /* Scaling transform */
1690 if(font->aveWidth) {
1691 FT_Matrix scaleMat;
1692 scaleMat.xx = FT_FixedFromFloat(widthRatio);
1693 scaleMat.xy = 0;
1694 scaleMat.yx = 0;
1695 scaleMat.yy = (1 << 16);
1697 pFT_Matrix_Multiply(&scaleMat, &transMat);
1698 needsTransform = TRUE;
1701 /* Rotation transform */
1702 if(font->orientation) {
1703 FT_Matrix rotationMat;
1704 FT_Vector vecAngle;
1705 angle = FT_FixedFromFloat((float)font->orientation / 10.0);
1706 pFT_Vector_Unit(&vecAngle, angle);
1707 rotationMat.xx = vecAngle.x;
1708 rotationMat.xy = -vecAngle.y;
1709 rotationMat.yx = -rotationMat.xy;
1710 rotationMat.yy = rotationMat.xx;
1712 pFT_Matrix_Multiply(&rotationMat, &transMat);
1713 needsTransform = TRUE;
1716 /* Extra transformation specified by caller */
1717 if (lpmat) {
1718 FT_Matrix extraMat;
1719 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
1720 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
1721 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
1722 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
1723 pFT_Matrix_Multiply(&extraMat, &transMat);
1724 needsTransform = TRUE;
1727 if(!needsTransform) {
1728 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
1729 bottom = (ft_face->glyph->metrics.horiBearingY -
1730 ft_face->glyph->metrics.height) & -64;
1731 lpgm->gmCellIncX = font->gm[glyph_index].adv;
1732 lpgm->gmCellIncY = 0;
1733 } else {
1734 INT xc, yc;
1735 FT_Vector vec;
1736 for(xc = 0; xc < 2; xc++) {
1737 for(yc = 0; yc < 2; yc++) {
1738 vec.x = (ft_face->glyph->metrics.horiBearingX +
1739 xc * ft_face->glyph->metrics.width);
1740 vec.y = ft_face->glyph->metrics.horiBearingY -
1741 yc * ft_face->glyph->metrics.height;
1742 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
1743 pFT_Vector_Transform(&vec, &transMat);
1744 if(xc == 0 && yc == 0) {
1745 left = right = vec.x;
1746 top = bottom = vec.y;
1747 } else {
1748 if(vec.x < left) left = vec.x;
1749 else if(vec.x > right) right = vec.x;
1750 if(vec.y < bottom) bottom = vec.y;
1751 else if(vec.y > top) top = vec.y;
1755 left = left & -64;
1756 right = (right + 63) & -64;
1757 bottom = bottom & -64;
1758 top = (top + 63) & -64;
1760 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
1761 vec.x = ft_face->glyph->metrics.horiAdvance;
1762 vec.y = 0;
1763 pFT_Vector_Transform(&vec, &transMat);
1764 lpgm->gmCellIncX = (vec.x+63) >> 6;
1765 lpgm->gmCellIncY = -((vec.y+63) >> 6);
1767 lpgm->gmBlackBoxX = (right - left) >> 6;
1768 lpgm->gmBlackBoxY = (top - bottom) >> 6;
1769 lpgm->gmptGlyphOrigin.x = left >> 6;
1770 lpgm->gmptGlyphOrigin.y = top >> 6;
1772 memcpy(&font->gm[glyph_index].gm, lpgm, sizeof(*lpgm));
1773 font->gm[glyph_index].init = TRUE;
1775 if(format == GGO_METRICS)
1776 return 1; /* FIXME */
1778 if (buf && !buflen){
1779 return GDI_ERROR;
1782 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP) {
1783 FIXME("loaded a bitmap\n");
1784 return GDI_ERROR;
1787 switch(format) {
1788 case GGO_BITMAP:
1789 width = lpgm->gmBlackBoxX;
1790 height = lpgm->gmBlackBoxY;
1791 pitch = ((width + 31) >> 5) << 2;
1792 needed = pitch * height;
1794 if(!buf || !buflen) break;
1796 switch(ft_face->glyph->format) {
1797 case ft_glyph_format_bitmap:
1799 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
1800 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
1801 INT h = ft_face->glyph->bitmap.rows;
1802 while(h--) {
1803 memcpy(dst, src, w);
1804 src += ft_face->glyph->bitmap.pitch;
1805 dst += pitch;
1807 break;
1810 case ft_glyph_format_outline:
1811 ft_bitmap.width = width;
1812 ft_bitmap.rows = height;
1813 ft_bitmap.pitch = pitch;
1814 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
1815 ft_bitmap.buffer = buf;
1817 if(needsTransform) {
1818 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
1821 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
1823 /* Note: FreeType will only set 'black' bits for us. */
1824 memset(buf, 0, needed);
1825 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
1826 break;
1828 default:
1829 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
1830 return GDI_ERROR;
1832 break;
1834 case GGO_GRAY2_BITMAP:
1835 case GGO_GRAY4_BITMAP:
1836 case GGO_GRAY8_BITMAP:
1837 case WINE_GGO_GRAY16_BITMAP:
1839 int mult, row, col;
1840 BYTE *start, *ptr;
1842 width = lpgm->gmBlackBoxX;
1843 height = lpgm->gmBlackBoxY;
1844 pitch = (width + 3) / 4 * 4;
1845 needed = pitch * height;
1847 if(!buf || !buflen) break;
1848 ft_bitmap.width = width;
1849 ft_bitmap.rows = height;
1850 ft_bitmap.pitch = pitch;
1851 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
1852 ft_bitmap.buffer = buf;
1854 if(needsTransform) {
1855 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
1858 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
1860 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
1862 if(format == GGO_GRAY2_BITMAP)
1863 mult = 5;
1864 else if(format == GGO_GRAY4_BITMAP)
1865 mult = 17;
1866 else if(format == GGO_GRAY8_BITMAP)
1867 mult = 65;
1868 else if(format == WINE_GGO_GRAY16_BITMAP)
1869 break;
1870 else {
1871 assert(0);
1872 break;
1875 start = buf;
1876 for(row = 0; row < height; row++) {
1877 ptr = start;
1878 for(col = 0; col < width; col++, ptr++) {
1879 *ptr = (*(unsigned int*)ptr * mult + 128) / 256;
1881 start += pitch;
1883 break;
1886 case GGO_NATIVE:
1888 int contour, point = 0, first_pt;
1889 FT_Outline *outline = &ft_face->glyph->outline;
1890 TTPOLYGONHEADER *pph;
1891 TTPOLYCURVE *ppc;
1892 DWORD pph_start, cpfx, type;
1894 if(buflen == 0) buf = NULL;
1896 if (needsTransform && buf) {
1897 pFT_Outline_Transform(outline, &transMat);
1900 for(contour = 0; contour < outline->n_contours; contour++) {
1901 pph_start = needed;
1902 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
1903 first_pt = point;
1904 if(buf) {
1905 pph->dwType = TT_POLYGON_TYPE;
1906 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
1908 needed += sizeof(*pph);
1909 point++;
1910 while(point <= outline->contours[contour]) {
1911 ppc = (TTPOLYCURVE *)((char *)buf + needed);
1912 type = (outline->tags[point] & FT_Curve_Tag_On) ?
1913 TT_PRIM_LINE : TT_PRIM_QSPLINE;
1914 cpfx = 0;
1915 do {
1916 if(buf)
1917 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
1918 cpfx++;
1919 point++;
1920 } while(point <= outline->contours[contour] &&
1921 (outline->tags[point] & FT_Curve_Tag_On) ==
1922 (outline->tags[point-1] & FT_Curve_Tag_On));
1923 /* At the end of a contour Windows adds the start point, but
1924 only for Beziers */
1925 if(point > outline->contours[contour] &&
1926 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
1927 if(buf)
1928 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
1929 cpfx++;
1930 } else if(point <= outline->contours[contour] &&
1931 outline->tags[point] & FT_Curve_Tag_On) {
1932 /* add closing pt for bezier */
1933 if(buf)
1934 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
1935 cpfx++;
1936 point++;
1938 if(buf) {
1939 ppc->wType = type;
1940 ppc->cpfx = cpfx;
1942 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
1944 if(buf)
1945 pph->cb = needed - pph_start;
1947 break;
1949 case GGO_BEZIER:
1951 /* Convert the quadratic Beziers to cubic Beziers.
1952 The parametric eqn for a cubic Bezier is, from PLRM:
1953 r(t) = at^3 + bt^2 + ct + r0
1954 with the control points:
1955 r1 = r0 + c/3
1956 r2 = r1 + (c + b)/3
1957 r3 = r0 + c + b + a
1959 A quadratic Beizer has the form:
1960 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
1962 So equating powers of t leads to:
1963 r1 = 2/3 p1 + 1/3 p0
1964 r2 = 2/3 p1 + 1/3 p2
1965 and of course r0 = p0, r3 = p2
1968 int contour, point = 0, first_pt;
1969 FT_Outline *outline = &ft_face->glyph->outline;
1970 TTPOLYGONHEADER *pph;
1971 TTPOLYCURVE *ppc;
1972 DWORD pph_start, cpfx, type;
1973 FT_Vector cubic_control[4];
1974 if(buflen == 0) buf = NULL;
1976 if (needsTransform && buf) {
1977 pFT_Outline_Transform(outline, &transMat);
1980 for(contour = 0; contour < outline->n_contours; contour++) {
1981 pph_start = needed;
1982 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
1983 first_pt = point;
1984 if(buf) {
1985 pph->dwType = TT_POLYGON_TYPE;
1986 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
1988 needed += sizeof(*pph);
1989 point++;
1990 while(point <= outline->contours[contour]) {
1991 ppc = (TTPOLYCURVE *)((char *)buf + needed);
1992 type = (outline->tags[point] & FT_Curve_Tag_On) ?
1993 TT_PRIM_LINE : TT_PRIM_CSPLINE;
1994 cpfx = 0;
1995 do {
1996 if(type == TT_PRIM_LINE) {
1997 if(buf)
1998 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
1999 cpfx++;
2000 point++;
2001 } else {
2002 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
2003 so cpfx = 3n */
2005 /* FIXME: Possible optimization in endpoint calculation
2006 if there are two consecutive curves */
2007 cubic_control[0] = outline->points[point-1];
2008 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
2009 cubic_control[0].x += outline->points[point].x + 1;
2010 cubic_control[0].y += outline->points[point].y + 1;
2011 cubic_control[0].x >>= 1;
2012 cubic_control[0].y >>= 1;
2014 if(point+1 > outline->contours[contour])
2015 cubic_control[3] = outline->points[first_pt];
2016 else {
2017 cubic_control[3] = outline->points[point+1];
2018 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
2019 cubic_control[3].x += outline->points[point].x + 1;
2020 cubic_control[3].y += outline->points[point].y + 1;
2021 cubic_control[3].x >>= 1;
2022 cubic_control[3].y >>= 1;
2025 /* r1 = 1/3 p0 + 2/3 p1
2026 r2 = 1/3 p2 + 2/3 p1 */
2027 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
2028 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
2029 cubic_control[2] = cubic_control[1];
2030 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
2031 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
2032 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
2033 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
2034 if(buf) {
2035 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
2036 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
2037 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
2039 cpfx += 3;
2040 point++;
2042 } while(point <= outline->contours[contour] &&
2043 (outline->tags[point] & FT_Curve_Tag_On) ==
2044 (outline->tags[point-1] & FT_Curve_Tag_On));
2045 /* At the end of a contour Windows adds the start point,
2046 but only for Beziers and we've already done that.
2048 if(point <= outline->contours[contour] &&
2049 outline->tags[point] & FT_Curve_Tag_On) {
2050 /* This is the closing pt of a bezier, but we've already
2051 added it, so just inc point and carry on */
2052 point++;
2054 if(buf) {
2055 ppc->wType = type;
2056 ppc->cpfx = cpfx;
2058 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2060 if(buf)
2061 pph->cb = needed - pph_start;
2063 break;
2066 default:
2067 FIXME("Unsupported format %d\n", format);
2068 return GDI_ERROR;
2070 return needed;
2073 /*************************************************************
2074 * WineEngGetTextMetrics
2077 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
2079 if(!font->potm) {
2080 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
2081 return FALSE;
2083 if(!font->potm) return FALSE;
2084 memcpy(ptm, &font->potm->otmTextMetrics, sizeof(*ptm));
2086 if (font->aveWidth) {
2087 ptm->tmAveCharWidth = font->aveWidth * font->xform.eM11;
2089 return TRUE;
2093 /*************************************************************
2094 * WineEngGetOutlineTextMetrics
2097 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
2098 OUTLINETEXTMETRICW *potm)
2100 FT_Face ft_face = font->ft_face;
2101 UINT needed, lenfam, lensty, ret;
2102 TT_OS2 *pOS2;
2103 TT_HoriHeader *pHori;
2104 TT_Postscript *pPost;
2105 FT_Fixed x_scale, y_scale;
2106 WCHAR *family_nameW, *style_nameW;
2107 WCHAR spaceW[] = {' ', '\0'};
2108 char *cp;
2110 TRACE("font=%p\n", font);
2112 if(font->potm) {
2113 if(cbSize >= font->potm->otmSize)
2114 memcpy(potm, font->potm, font->potm->otmSize);
2115 return font->potm->otmSize;
2118 needed = sizeof(*potm);
2120 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
2121 family_nameW = strdupW(font->name);
2123 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
2124 * sizeof(WCHAR);
2125 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
2126 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
2127 style_nameW, lensty);
2129 /* These names should be read from the TT name table */
2131 /* length of otmpFamilyName */
2132 needed += lenfam;
2134 /* length of otmpFaceName */
2135 if(!strcasecmp(ft_face->style_name, "regular")) {
2136 needed += lenfam; /* just the family name */
2137 } else {
2138 needed += lenfam + lensty; /* family + " " + style */
2141 /* length of otmpStyleName */
2142 needed += lensty;
2144 /* length of otmpFullName */
2145 needed += lenfam + lensty;
2148 x_scale = ft_face->size->metrics.x_scale;
2149 y_scale = ft_face->size->metrics.y_scale;
2151 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2152 if(!pOS2) {
2153 FIXME("Can't find OS/2 table - not TT font?\n");
2154 ret = 0;
2155 goto end;
2158 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2159 if(!pHori) {
2160 FIXME("Can't find HHEA table - not TT font?\n");
2161 ret = 0;
2162 goto end;
2165 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
2167 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",
2168 pOS2->usWinAscent, pOS2->usWinDescent,
2169 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
2170 ft_face->ascender, ft_face->descender, ft_face->height,
2171 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
2172 ft_face->bbox.yMax, ft_face->bbox.yMin);
2174 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
2175 font->potm->otmSize = needed;
2177 #define TM font->potm->otmTextMetrics
2179 if(font->yMax) {
2180 TM.tmAscent = font->yMax;
2181 TM.tmDescent = -font->yMin;
2182 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
2183 } else {
2184 TM.tmAscent = (pFT_MulFix(pOS2->usWinAscent, y_scale) + 32) >> 6;
2185 TM.tmDescent = (pFT_MulFix(pOS2->usWinDescent, y_scale) + 32) >> 6;
2186 TM.tmInternalLeading = (pFT_MulFix(pOS2->usWinAscent + pOS2->usWinDescent
2187 - ft_face->units_per_EM, y_scale) + 32) >> 6;
2190 TM.tmHeight = TM.tmAscent + TM.tmDescent;
2192 /* MSDN says:
2193 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
2195 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
2196 ((pOS2->usWinAscent + pOS2->usWinDescent) -
2197 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
2199 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
2200 if (TM.tmAveCharWidth == 0) {
2201 TM.tmAveCharWidth = 1;
2203 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
2204 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
2205 TM.tmOverhang = 0;
2206 TM.tmDigitizedAspectX = 300;
2207 TM.tmDigitizedAspectY = 300;
2208 TM.tmFirstChar = pOS2->usFirstCharIndex;
2209 TM.tmLastChar = pOS2->usLastCharIndex;
2210 TM.tmDefaultChar = pOS2->usDefaultChar;
2211 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
2212 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
2213 TM.tmUnderlined = 0; /* entry in OS2 table */
2214 TM.tmStruckOut = 0; /* entry in OS2 table */
2216 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
2217 if(!FT_IS_FIXED_WIDTH(ft_face))
2218 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
2219 else
2220 TM.tmPitchAndFamily = 0;
2222 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
2223 case PAN_FAMILY_SCRIPT:
2224 TM.tmPitchAndFamily |= FF_SCRIPT;
2225 break;
2226 case PAN_FAMILY_DECORATIVE:
2227 case PAN_FAMILY_PICTORIAL:
2228 TM.tmPitchAndFamily |= FF_DECORATIVE;
2229 break;
2230 case PAN_FAMILY_TEXT_DISPLAY:
2231 if(TM.tmPitchAndFamily == 0) /* fixed */
2232 TM.tmPitchAndFamily = FF_MODERN;
2233 else {
2234 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
2235 case PAN_SERIF_NORMAL_SANS:
2236 case PAN_SERIF_OBTUSE_SANS:
2237 case PAN_SERIF_PERP_SANS:
2238 TM.tmPitchAndFamily |= FF_SWISS;
2239 break;
2240 default:
2241 TM.tmPitchAndFamily |= FF_ROMAN;
2244 break;
2245 default:
2246 TM.tmPitchAndFamily |= FF_DONTCARE;
2249 if(FT_IS_SCALABLE(ft_face))
2250 TM.tmPitchAndFamily |= TMPF_VECTOR;
2251 if(FT_IS_SFNT(ft_face))
2252 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
2254 TM.tmCharSet = font->charset;
2255 #undef TM
2257 font->potm->otmFiller = 0;
2258 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
2259 font->potm->otmfsSelection = pOS2->fsSelection;
2260 font->potm->otmfsType = pOS2->fsType;
2261 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
2262 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
2263 font->potm->otmItalicAngle = 0; /* POST table */
2264 font->potm->otmEMSquare = ft_face->units_per_EM;
2265 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
2266 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
2267 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
2268 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
2269 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
2270 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
2271 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
2272 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
2273 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
2274 font->potm->otmMacAscent = 0; /* where do these come from ? */
2275 font->potm->otmMacDescent = 0;
2276 font->potm->otmMacLineGap = 0;
2277 font->potm->otmusMinimumPPEM = 0; /* TT Header */
2278 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
2279 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
2280 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
2281 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
2282 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
2283 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
2284 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
2285 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
2286 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
2287 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
2288 if(!pPost) {
2289 font->potm->otmsUnderscoreSize = 0;
2290 font->potm->otmsUnderscorePosition = 0;
2291 } else {
2292 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
2293 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
2296 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
2297 cp = (char*)font->potm + sizeof(*font->potm);
2298 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
2299 strcpyW((WCHAR*)cp, family_nameW);
2300 cp += lenfam;
2301 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
2302 strcpyW((WCHAR*)cp, style_nameW);
2303 cp += lensty;
2304 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
2305 strcpyW((WCHAR*)cp, family_nameW);
2306 if(strcasecmp(ft_face->style_name, "regular")) {
2307 strcatW((WCHAR*)cp, spaceW);
2308 strcatW((WCHAR*)cp, style_nameW);
2309 cp += lenfam + lensty;
2310 } else
2311 cp += lenfam;
2312 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
2313 strcpyW((WCHAR*)cp, family_nameW);
2314 strcatW((WCHAR*)cp, spaceW);
2315 strcatW((WCHAR*)cp, style_nameW);
2316 ret = needed;
2318 if(potm && needed <= cbSize)
2319 memcpy(potm, font->potm, font->potm->otmSize);
2321 end:
2322 HeapFree(GetProcessHeap(), 0, style_nameW);
2323 HeapFree(GetProcessHeap(), 0, family_nameW);
2325 return ret;
2329 /*************************************************************
2330 * WineEngGetCharWidth
2333 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
2334 LPINT buffer)
2336 UINT c;
2337 GLYPHMETRICS gm;
2338 FT_UInt glyph_index;
2340 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
2342 for(c = firstChar; c <= lastChar; c++) {
2343 glyph_index = get_glyph_index(font, c);
2344 WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
2345 &gm, 0, NULL, NULL);
2346 buffer[c - firstChar] = font->gm[glyph_index].adv;
2348 return TRUE;
2351 /*************************************************************
2352 * WineEngGetTextExtentPoint
2355 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
2356 LPSIZE size)
2358 INT idx;
2359 GLYPHMETRICS gm;
2360 TEXTMETRICW tm;
2361 FT_UInt glyph_index;
2363 TRACE("%p, %s, %d, %p\n", font, debugstr_wn(wstr, count), count,
2364 size);
2366 size->cx = 0;
2367 WineEngGetTextMetrics(font, &tm);
2368 size->cy = tm.tmHeight;
2370 for(idx = 0; idx < count; idx++) {
2371 glyph_index = get_glyph_index(font, wstr[idx]);
2372 WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
2373 &gm, 0, NULL, NULL);
2374 size->cx += font->gm[glyph_index].adv;
2376 TRACE("return %ld,%ld\n", size->cx, size->cy);
2377 return TRUE;
2380 /*************************************************************
2381 * WineEngGetTextExtentPointI
2384 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
2385 LPSIZE size)
2387 INT idx;
2388 GLYPHMETRICS gm;
2389 TEXTMETRICW tm;
2391 TRACE("%p, %p, %d, %p\n", font, indices, count, size);
2393 size->cx = 0;
2394 WineEngGetTextMetrics(font, &tm);
2395 size->cy = tm.tmHeight;
2397 for(idx = 0; idx < count; idx++) {
2398 WineEngGetGlyphOutline(font, indices[idx],
2399 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
2400 NULL);
2401 size->cx += font->gm[indices[idx]].adv;
2403 TRACE("return %ld,%ld\n", size->cx, size->cy);
2404 return TRUE;
2407 /*************************************************************
2408 * WineEngGetFontData
2411 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
2412 DWORD cbData)
2414 FT_Face ft_face = font->ft_face;
2415 DWORD len;
2416 FT_Error err;
2418 TRACE("font=%p, table=%08lx, offset=%08lx, buf=%p, cbData=%lx\n",
2419 font, table, offset, buf, cbData);
2421 if(!FT_IS_SFNT(ft_face))
2422 return GDI_ERROR;
2424 if(!buf || !cbData)
2425 len = 0;
2426 else
2427 len = cbData;
2429 if(table) { /* MS tags differ in endidness from FT ones */
2430 table = table >> 24 | table << 24 |
2431 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
2434 /* If the FT_Load_Sfnt_Table function is there we'll use it */
2435 if(pFT_Load_Sfnt_Table)
2436 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
2437 else { /* Do it the hard way */
2438 TT_Face tt_face = (TT_Face) ft_face;
2439 SFNT_Interface *sfnt;
2440 if (FT_Version.major==2 && FT_Version.minor==0)
2442 /* 2.0.x */
2443 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
2445 else
2447 /* A field was added in the middle of the structure in 2.1.x */
2448 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
2450 err = sfnt->load_any(tt_face, table, offset, buf, &len);
2452 if(err) {
2453 TRACE("Can't find table %08lx.\n", table);
2454 return GDI_ERROR;
2456 return len;
2459 /*************************************************************
2460 * WineEngGetTextFace
2463 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
2465 if(str) {
2466 lstrcpynW(str, font->name, count);
2467 return strlenW(font->name);
2468 } else
2469 return strlenW(font->name) + 1;
2472 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
2474 if (fs) memcpy(fs, &font->fs, sizeof(FONTSIGNATURE));
2475 return font->charset;
2478 #else /* HAVE_FREETYPE */
2480 BOOL WineEngInit(void)
2482 return FALSE;
2484 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
2486 return NULL;
2488 BOOL WineEngDestroyFontInstance(HFONT hfont)
2490 return FALSE;
2493 DWORD WineEngEnumFonts(LPLOGFONTW plf, DEVICEFONTENUMPROC proc, LPARAM lparam)
2495 return 1;
2498 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
2499 LPWORD pgi, DWORD flags)
2501 return GDI_ERROR;
2504 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
2505 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
2506 const MAT2* lpmat)
2508 ERR("called but we don't have FreeType\n");
2509 return GDI_ERROR;
2512 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
2514 ERR("called but we don't have FreeType\n");
2515 return FALSE;
2518 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
2519 OUTLINETEXTMETRICW *potm)
2521 ERR("called but we don't have FreeType\n");
2522 return 0;
2525 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
2526 LPINT buffer)
2528 ERR("called but we don't have FreeType\n");
2529 return FALSE;
2532 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
2533 LPSIZE size)
2535 ERR("called but we don't have FreeType\n");
2536 return FALSE;
2539 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
2540 LPSIZE size)
2542 ERR("called but we don't have FreeType\n");
2543 return FALSE;
2546 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
2547 DWORD cbData)
2549 ERR("called but we don't have FreeType\n");
2550 return GDI_ERROR;
2553 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
2555 ERR("called but we don't have FreeType\n");
2556 return 0;
2559 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2561 FIXME(":stub\n");
2562 return 1;
2565 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2567 FIXME(":stub\n");
2568 return TRUE;
2571 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
2573 FIXME(":stub\n");
2574 return DEFAULT_CHARSET;
2577 #endif /* HAVE_FREETYPE */