2 * FreeType font engine interface
4 * Copyright 2001 Huw D M Davies for CodeWeavers.
6 * This file contains the WineEng* functions.
16 #include "wine/unicode.h"
19 #include "debugtools.h"
26 DEFAULT_DEBUG_CHANNEL(font
);
30 #ifdef HAVE_FREETYPE_FREETYPE_H
31 #include <freetype/freetype.h>
33 #ifdef HAVE_FREETYPE_FTGLYPH_H
34 #include <freetype/ftglyph.h>
36 #ifdef HAVE_FREETYPE_TTTABLES_H
37 #include <freetype/tttables.h>
39 #ifdef HAVE_FREETYPE_FTNAMES_H
40 #include <freetype/ftnames.h>
42 #ifdef HAVE_FREETYPE_FTSNAMES_H
43 #include <freetype/ftsnames.h>
45 #ifdef HAVE_FREETYPE_TTNAMEID_H
46 #include <freetype/ttnameid.h>
48 #ifdef HAVE_FREETYPE_FTOUTLN_H
49 #include <freetype/ftoutln.h>
51 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
52 #include <freetype/internal/sfnt.h>
55 static FT_Library library
= 0;
57 typedef struct tagFace
{
65 typedef struct tagFamily
{
68 struct tagFamily
*next
;
76 static Family
*FontList
= NULL
;
78 static BOOL
AddFontFileToList(char *file
)
81 WCHAR
*FamilyW
, *StyleW
;
83 Family
*family
= FontList
;
84 Family
**insert
= &FontList
;
87 TRACE("Loading font file %s\n", debugstr_a(file
));
88 if(FT_New_Face(library
, file
, 0, &ft_face
)) {
89 ERR("Unable to load font file %s\n", debugstr_a(file
));
93 if(!FT_IS_SFNT(ft_face
)) { /* for now we'll skip everything but TT/OT */
94 FT_Done_Face(ft_face
);
98 len
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->family_name
, -1, NULL
, 0);
99 FamilyW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
100 MultiByteToWideChar(CP_ACP
, 0, ft_face
->family_name
, -1, FamilyW
, len
);
103 if(!strcmpW(family
->FamilyName
, FamilyW
))
105 insert
= &family
->next
;
106 family
= family
->next
;
109 family
= *insert
= HeapAlloc(GetProcessHeap(), 0, sizeof(*family
));
110 family
->FamilyName
= FamilyW
;
111 family
->FirstFace
= NULL
;
114 HeapFree(GetProcessHeap(), 0, FamilyW
);
117 len
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0);
118 StyleW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
119 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, StyleW
, len
);
122 for(insertface
= &family
->FirstFace
; *insertface
;
123 insertface
= &(*insertface
)->next
) {
124 if(!strcmpW((*insertface
)->StyleName
, StyleW
)) {
125 ERR("Already loaded font %s %s\n", debugstr_w(family
->FamilyName
),
127 HeapFree(GetProcessHeap(), 0, StyleW
);
128 FT_Done_Face(ft_face
);
132 *insertface
= HeapAlloc(GetProcessHeap(), 0, sizeof(**insertface
));
133 (*insertface
)->StyleName
= StyleW
;
134 (*insertface
)->file
= HeapAlloc(GetProcessHeap(),0,strlen(file
)+1);
135 strcpy((*insertface
)->file
, file
);
136 (*insertface
)->next
= NULL
;
137 (*insertface
)->Italic
= (ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 1 : 0;
138 (*insertface
)->Bold
= (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
) ? 1 : 0;
139 FT_Done_Face(ft_face
);
141 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
),
146 static void DumpFontList(void)
151 for(family
= FontList
; family
; family
= family
->next
) {
152 TRACE("Family: %s\n", debugstr_w(family
->FamilyName
));
153 for(face
= family
->FirstFace
; face
; face
= face
->next
) {
154 TRACE("\t%s\n", debugstr_w(face
->StyleName
));
160 static BOOL
ReadFontDir(char *dirname
)
166 dir
= opendir(dirname
);
168 ERR("Can't open directory %s\n", debugstr_a(dirname
));
171 while((dent
= readdir(dir
)) != NULL
) {
172 if(!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, ".."))
174 sprintf(path
, "%s/%s", dirname
, dent
->d_name
);
175 AddFontFileToList(path
);
180 /*************************************************************
183 * Initialize FreeType library and create a list of available faces
185 BOOL
WineEngInit(void)
188 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
192 if(FT_Init_FreeType(&library
) != 0) {
193 ERR("Can't init FreeType library\n");
197 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
,
198 "Software\\Wine\\Wine\\Config\\FontDirs",
199 &hkey
) != ERROR_SUCCESS
) {
200 TRACE("Can't open FontDirs key in config file\n");
204 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &valuelen
,
205 &datalen
, NULL
, NULL
);
207 valuelen
++; /* returned value doesn't include room for '\0' */
208 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
);
209 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
213 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
214 &dlen
) == ERROR_SUCCESS
) {
215 TRACE("Got %s=%s\n", value
, (LPSTR
)data
);
216 ReadFontDir((LPSTR
)data
);
217 /* reset dlen and vlen */
221 HeapFree(GetProcessHeap(), 0, data
);
222 HeapFree(GetProcessHeap(), 0, value
);
229 static FT_Face
OpenFontFile(char *file
, LONG height
)
236 err
= FT_New_Face(library
, file
, 0, &ft_face
);
238 ERR("FT_New_Face rets %d\n", err
);
242 pOS2
= FT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
244 if(height
== 0) height
= 16;
246 /* Calc. height of EM square:
248 * For +ve lfHeight we have
249 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
250 * Re-arranging gives:
251 * ppem = units_per_em * lfheight / (winAscent + winDescent)
253 * For -ve lfHeight we have
255 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
256 * with il = winAscent + winDescent - units_per_em]
261 ppem
= ft_face
->units_per_EM
* height
/
262 (pOS2
->usWinAscent
+ pOS2
->usWinDescent
);
266 FT_Set_Pixel_Sizes(ft_face
, 0, ppem
);
270 /*************************************************************
271 * WineEngCreateFontInstance
274 GdiFont
WineEngCreateFontInstance(HFONT hfont
)
278 Family
*family
= NULL
;
279 WCHAR FaceName
[LF_FACESIZE
];
281 FONTOBJ
*font
= GDI_GetObjPtr(hfont
, FONT_MAGIC
);
282 LOGFONTW
*plf
= &font
->logfont
;
284 TRACE("%s, h=%ld, it=%d, weight=%ld\n", debugstr_w(plf
->lfFaceName
),
285 plf
->lfHeight
, plf
->lfItalic
, plf
->lfWeight
);
287 ret
= HeapAlloc(GetProcessHeap(), 0, sizeof(*ret
));
290 strcpyW(FaceName
, plf
->lfFaceName
);
292 if(FaceName
[0] != '\0') {
293 for(family
= FontList
; family
; family
= family
->next
) {
294 if(!strcmpiW(family
->FamilyName
, FaceName
))
301 FIXME("just using first face for now\n");
304 it
= plf
->lfItalic
? 1 : 0;
305 bd
= plf
->lfWeight
> 550 ? 1 : 0;
307 for(face
= family
->FirstFace
; face
; face
= face
->next
) {
308 if(!(face
->Italic
^ it
) && !(face
->Bold
^ bd
))
311 if(!face
) face
= family
->FirstFace
;
313 TRACE("Choosen %s %s\n", debugstr_w(family
->FamilyName
),
314 debugstr_w(face
->StyleName
));
316 ret
->ft_face
= OpenFontFile(face
->file
, plf
->lfHeight
);
318 GDI_ReleaseObj(hfont
);
319 TRACE("returning %p\n", ret
);
323 /*************************************************************
327 DWORD
WineEngAddRefFont(GdiFont font
)
332 /*************************************************************
336 DWORD
WineEngDecRefFont(GdiFont font
)
338 DWORD ret
= --font
->ref
;
341 FT_Done_Face(font
->ft_face
);
342 HeapFree(GetProcessHeap(), 0, font
);
347 static void GetEnumStructs(Face
*face
, LPENUMLOGFONTEXW pelf
,
348 LPNEWTEXTMETRICEXW pntm
, LPDWORD ptype
)
350 OUTLINETEXTMETRICW
*potm
;
352 GdiFont font
= HeapAlloc(GetProcessHeap(),0,sizeof(*font
));
355 font
->ft_face
= OpenFontFile(face
->file
, 100);
357 memset(&pelf
->elfLogFont
, 0, sizeof(LOGFONTW
));
359 size
= WineEngGetOutlineTextMetrics(font
, 0, NULL
);
360 potm
= HeapAlloc(GetProcessHeap(), 0, size
);
361 WineEngGetOutlineTextMetrics(font
, size
, potm
);
363 #define TM potm->otmTextMetrics
365 pntm
->ntmTm
.tmHeight
= pelf
->elfLogFont
.lfHeight
= TM
.tmHeight
;
366 pntm
->ntmTm
.tmAscent
= TM
.tmAscent
;
367 pntm
->ntmTm
.tmDescent
= TM
.tmDescent
;
368 pntm
->ntmTm
.tmInternalLeading
= TM
.tmInternalLeading
;
369 pntm
->ntmTm
.tmExternalLeading
= TM
.tmExternalLeading
;
370 pntm
->ntmTm
.tmAveCharWidth
= pelf
->elfLogFont
.lfWeight
= TM
.tmAveCharWidth
;
371 pntm
->ntmTm
.tmMaxCharWidth
= TM
.tmMaxCharWidth
;
372 pntm
->ntmTm
.tmWeight
= pelf
->elfLogFont
.lfWeight
= TM
.tmWeight
;
373 pntm
->ntmTm
.tmOverhang
= TM
.tmOverhang
;
374 pntm
->ntmTm
.tmDigitizedAspectX
= TM
.tmDigitizedAspectX
;
375 pntm
->ntmTm
.tmDigitizedAspectY
= TM
.tmDigitizedAspectY
;
376 pntm
->ntmTm
.tmFirstChar
= TM
.tmFirstChar
;
377 pntm
->ntmTm
.tmLastChar
= TM
.tmLastChar
;
378 pntm
->ntmTm
.tmDefaultChar
= TM
.tmDefaultChar
;
379 pntm
->ntmTm
.tmBreakChar
= TM
.tmBreakChar
;
380 pntm
->ntmTm
.tmItalic
= pelf
->elfLogFont
.lfItalic
= TM
.tmItalic
;
381 pntm
->ntmTm
.tmUnderlined
= pelf
->elfLogFont
.lfUnderline
= TM
.tmUnderlined
;
382 pntm
->ntmTm
.tmStruckOut
= pelf
->elfLogFont
.lfStrikeOut
= TM
.tmStruckOut
;
383 pntm
->ntmTm
.tmPitchAndFamily
= TM
.tmPitchAndFamily
;
384 pelf
->elfLogFont
.lfPitchAndFamily
= (TM
.tmPitchAndFamily
& 0xf1) + 1;
385 pntm
->ntmTm
.tmCharSet
= pelf
->elfLogFont
.lfCharSet
= TM
.tmCharSet
;
387 pntm
->ntmTm
.ntmFlags
= TM
.tmItalic
? NTM_ITALIC
: 0;
388 if(TM
.tmWeight
> 550) pntm
->ntmTm
.ntmFlags
|= NTM_BOLD
;
389 if(pntm
->ntmTm
.ntmFlags
== 0) pntm
->ntmTm
.ntmFlags
= NTM_REGULAR
;
391 pntm
->ntmTm
.ntmSizeEM
= potm
->otmEMSquare
;
392 pntm
->ntmTm
.ntmCellHeight
= 0;
393 pntm
->ntmTm
.ntmAvgWidth
= 0;
395 *ptype
= TM
.tmPitchAndFamily
& TMPF_TRUETYPE
? TRUETYPE_FONTTYPE
: 0;
396 if(!(TM
.tmPitchAndFamily
& TMPF_VECTOR
))
397 *ptype
|= RASTER_FONTTYPE
;
400 memset(&pntm
->ntmFontSig
, 0, sizeof(FONTSIGNATURE
));
402 strncpyW(pelf
->elfLogFont
.lfFaceName
,
403 (WCHAR
*)((char*)potm
+ (ptrdiff_t)potm
->otmpFamilyName
),
405 strncpyW(pelf
->elfFullName
,
406 (WCHAR
*)((char*)potm
+ (ptrdiff_t)potm
->otmpFullName
),
408 strncpyW(pelf
->elfStyle
,
409 (WCHAR
*)((char*)potm
+ (ptrdiff_t)potm
->otmpStyleName
),
411 pelf
->elfScript
[0] = '\0'; /* FIXME */
413 HeapFree(GetProcessHeap(), 0, potm
);
414 WineEngDecRefFont(font
);
418 /*************************************************************
422 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, DEVICEFONTENUMPROC proc
,
428 NEWTEXTMETRICEXW ntm
;
431 TRACE("facename = %s\n", debugstr_w(plf
->lfFaceName
));
432 if(plf
->lfFaceName
[0]) {
433 for(family
= FontList
; family
; family
= family
->next
) {
434 if(!strcmpiW(plf
->lfFaceName
, family
->FamilyName
)) {
435 for(face
= family
->FirstFace
; face
; face
= face
->next
) {
436 GetEnumStructs(face
, &elf
, &ntm
, &type
);
437 TRACE("enuming '%s'\n",
438 debugstr_w(elf
.elfLogFont
.lfFaceName
));
439 ret
= proc(&elf
, &ntm
, type
, lparam
);
445 for(family
= FontList
; family
; family
= family
->next
) {
446 GetEnumStructs(family
->FirstFace
, &elf
, &ntm
, &type
);
447 TRACE("enuming '%s'\n", debugstr_w(elf
.elfLogFont
.lfFaceName
));
448 ret
= proc(&elf
, &ntm
, type
, lparam
);
456 /*************************************************************
457 * WineEngGetGlyphOutline
459 * Behaves in exactly the same way as the win32 api GetGlyphOutline
460 * except that the first parameter is the HWINEENGFONT of the font in
461 * question rather than an HDC.
464 DWORD
WineEngGetGlyphOutline(GdiFont font
, UINT glyph
, UINT format
,
465 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
468 FT_Face ft_face
= font
->ft_face
;
470 DWORD width
, height
, pitch
, needed
;
473 TRACE("%p, %04x, %08x, %p, %08lx, %p, %p\n", font
, glyph
, format
, lpgm
,
476 if(format
& GGO_GLYPH_INDEX
)
479 glyph_index
= FT_Get_Char_Index(ft_face
, glyph
);
481 FT_Load_Glyph(ft_face
, glyph_index
, FT_LOAD_DEFAULT
);
483 lpgm
->gmBlackBoxX
= ft_face
->glyph
->metrics
.width
>> 6;
484 lpgm
->gmBlackBoxY
= ft_face
->glyph
->metrics
.height
>> 6;
485 lpgm
->gmptGlyphOrigin
.x
= ft_face
->glyph
->metrics
.horiBearingX
>> 6;
486 lpgm
->gmptGlyphOrigin
.y
= ft_face
->glyph
->metrics
.horiBearingY
>> 6;
487 lpgm
->gmCellIncX
= ft_face
->glyph
->metrics
.horiAdvance
>> 6;
488 lpgm
->gmCellIncY
= 0;
490 if(format
== GGO_METRICS
)
493 if(ft_face
->glyph
->format
!= ft_glyph_format_outline
) {
494 FIXME("loaded a bitmap\n");
498 if(format
== GGO_BITMAP
) {
499 width
= lpgm
->gmBlackBoxX
;
500 height
= lpgm
->gmBlackBoxY
;
501 pitch
= (width
+ 31) / 32 * 4;
502 needed
= pitch
* height
;
504 if(!buf
|| !buflen
) return needed
;
505 ft_bitmap
.width
= width
;
506 ft_bitmap
.rows
= height
;
507 ft_bitmap
.pitch
= pitch
;
508 ft_bitmap
.pixel_mode
= ft_pixel_mode_mono
;
509 ft_bitmap
.buffer
= buf
;
511 FT_Outline_Translate(&ft_face
->glyph
->outline
,
512 - ft_face
->glyph
->metrics
.horiBearingX
,
513 - (ft_face
->glyph
->metrics
.horiBearingY
-
514 ft_face
->glyph
->metrics
.height
) );
516 FT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
518 FIXME("Unsupported format %d\n", format
);
524 /*************************************************************
525 * WineEngGetTextMetrics
528 BOOL
WineEngGetTextMetrics(GdiFont font
, LPTEXTMETRICW ptm
)
530 FT_Face ft_face
= font
->ft_face
;
532 TT_HoriHeader
*pHori
;
533 FT_Fixed x_scale
, y_scale
;
535 x_scale
= ft_face
->size
->metrics
.x_scale
;
536 y_scale
= ft_face
->size
->metrics
.y_scale
;
538 pOS2
= FT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
540 FIXME("Can't find OS/2 table - not TT font?\n");
544 pHori
= FT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
546 FIXME("Can't find HHEA table - not TT font?\n");
550 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",
551 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
552 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
553 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
554 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
555 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
557 ptm
->tmAscent
= (FT_MulFix(pOS2
->usWinAscent
, y_scale
) + 32) >> 6;
558 ptm
->tmDescent
= (FT_MulFix(pOS2
->usWinDescent
, y_scale
) + 32) >> 6;
559 ptm
->tmHeight
= ptm
->tmAscent
+ ptm
->tmDescent
;
560 ptm
->tmInternalLeading
= (FT_MulFix(pOS2
->usWinAscent
+ pOS2
->usWinDescent
561 - ft_face
->units_per_EM
, y_scale
) + 32) >> 6;
564 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
566 ptm
->tmExternalLeading
= max(0, (FT_MulFix(pHori
->Line_Gap
-
567 ((pOS2
->usWinAscent
+ pOS2
->usWinDescent
) -
568 (pHori
->Ascender
- pHori
->Descender
)), y_scale
) + 32) >> 6);
570 ptm
->tmAveCharWidth
= (FT_MulFix(pOS2
->xAvgCharWidth
, x_scale
) + 32) >> 6;
571 ptm
->tmMaxCharWidth
= (FT_MulFix(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
572 ptm
->tmWeight
= pOS2
->usWeightClass
;
574 ptm
->tmDigitizedAspectX
= 300;
575 ptm
->tmDigitizedAspectY
= 300;
576 ptm
->tmFirstChar
= pOS2
->usFirstCharIndex
;
577 ptm
->tmLastChar
= pOS2
->usLastCharIndex
;
578 ptm
->tmDefaultChar
= pOS2
->usDefaultChar
;
579 ptm
->tmBreakChar
= pOS2
->usBreakChar
;
580 ptm
->tmItalic
= (ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 1 : 0;
581 ptm
->tmUnderlined
= 0; /* entry in OS2 table */
582 ptm
->tmStruckOut
= 0; /* entry in OS2 table */
584 /* Yes this is correct; braindead api */
585 ptm
->tmPitchAndFamily
= FT_IS_FIXED_WIDTH(ft_face
) ? 0 : TMPF_FIXED_PITCH
;
586 if(FT_IS_SCALABLE(ft_face
))
587 ptm
->tmPitchAndFamily
|= TMPF_VECTOR
;
588 if(FT_IS_SFNT(ft_face
))
589 ptm
->tmPitchAndFamily
|= TMPF_TRUETYPE
;
591 ptm
->tmCharSet
= ANSI_CHARSET
;
594 /*************************************************************
595 * WineEngGetOutlineTextMetrics
598 UINT
WineEngGetOutlineTextMetrics(GdiFont font
, UINT cbSize
,
599 OUTLINETEXTMETRICW
*potm
)
601 FT_Face ft_face
= font
->ft_face
;
602 UINT needed
, lenfam
, lensty
, ret
;
604 TT_HoriHeader
*pHori
;
605 FT_Fixed x_scale
, y_scale
;
606 WCHAR
*family_nameW
, *style_nameW
;
607 WCHAR spaceW
[] = {' ', '\0'};
610 needed
= sizeof(*potm
);
612 lenfam
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->family_name
, -1, NULL
, 0)
614 family_nameW
= HeapAlloc(GetProcessHeap(), 0, lenfam
);
615 MultiByteToWideChar(CP_ACP
, 0, ft_face
->family_name
, -1,
616 family_nameW
, lenfam
);
618 lensty
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0)
620 style_nameW
= HeapAlloc(GetProcessHeap(), 0, lensty
);
621 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1,
622 style_nameW
, lensty
);
624 /* These names should be read from the TT name table */
626 /* length of otmpFamilyName */
629 /* length of otmpFaceName */
630 if(!strcasecmp(ft_face
->style_name
, "regular")) {
631 needed
+= lenfam
; /* just the family name */
633 needed
+= lenfam
+ lensty
; /* family + " " + style */
636 /* length of otmpStyleName */
639 /* length of otmpFullName */
640 needed
+= lenfam
+ lensty
;
642 if(needed
> cbSize
) {
647 x_scale
= ft_face
->size
->metrics
.x_scale
;
648 y_scale
= ft_face
->size
->metrics
.y_scale
;
650 pOS2
= FT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
652 FIXME("Can't find OS/2 table - not TT font?\n");
657 pHori
= FT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
659 FIXME("Can't find HHEA table - not TT font?\n");
664 potm
->otmSize
= needed
;
666 WineEngGetTextMetrics(font
, &potm
->otmTextMetrics
);
669 memcpy(&potm
->otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
670 potm
->otmfsSelection
= pOS2
->fsSelection
;
671 potm
->otmfsType
= pOS2
->fsType
;
672 potm
->otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
673 potm
->otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
674 potm
->otmItalicAngle
= 0; /* POST table */
675 potm
->otmEMSquare
= ft_face
->units_per_EM
;
676 potm
->otmAscent
= pOS2
->sTypoAscender
;
677 potm
->otmDescent
= pOS2
->sTypoDescender
;
678 potm
->otmLineGap
= pOS2
->sTypoLineGap
;
679 potm
->otmsCapEmHeight
= pOS2
->sCapHeight
;
680 potm
->otmsXHeight
= pOS2
->sxHeight
;
681 potm
->otmrcFontBox
.left
= ft_face
->bbox
.xMin
;
682 potm
->otmrcFontBox
.right
= ft_face
->bbox
.xMax
;
683 potm
->otmrcFontBox
.top
= ft_face
->bbox
.yMin
;
684 potm
->otmrcFontBox
.bottom
= ft_face
->bbox
.yMax
;
685 potm
->otmMacAscent
= 0; /* where do these come from ? */
686 potm
->otmMacDescent
= 0;
687 potm
->otmMacLineGap
= 0;
688 potm
->otmusMinimumPPEM
= 0; /* TT Header */
689 potm
->otmptSubscriptSize
.x
= pOS2
->ySubscriptXSize
;
690 potm
->otmptSubscriptSize
.y
= pOS2
->ySubscriptYSize
;
691 potm
->otmptSubscriptOffset
.x
= pOS2
->ySubscriptXOffset
;
692 potm
->otmptSubscriptOffset
.y
= pOS2
->ySubscriptYOffset
;
693 potm
->otmptSuperscriptSize
.x
= pOS2
->ySuperscriptXSize
;
694 potm
->otmptSuperscriptSize
.y
= pOS2
->ySuperscriptYSize
;
695 potm
->otmptSuperscriptOffset
.x
= pOS2
->ySuperscriptXOffset
;
696 potm
->otmptSuperscriptOffset
.y
= pOS2
->ySuperscriptYOffset
;
697 potm
->otmsStrikeoutSize
= pOS2
->yStrikeoutSize
;
698 potm
->otmsStrikeoutPosition
= pOS2
->yStrikeoutPosition
;
699 potm
->otmsUnderscoreSize
= 0; /* POST Header */
700 potm
->otmsUnderscorePosition
= 0; /* POST Header */
702 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
703 cp
= (char*)potm
+ sizeof(*potm
);
704 potm
->otmpFamilyName
= (LPSTR
)(cp
- (char*)potm
);
705 strcpyW((WCHAR
*)cp
, family_nameW
);
707 potm
->otmpStyleName
= (LPSTR
)(cp
- (char*)potm
);
708 strcpyW((WCHAR
*)cp
, style_nameW
);
710 potm
->otmpFaceName
= (LPSTR
)(cp
- (char*)potm
);
711 strcpyW((WCHAR
*)cp
, family_nameW
);
712 if(strcasecmp(ft_face
->style_name
, "regular")) {
713 strcatW((WCHAR
*)cp
, spaceW
);
714 strcatW((WCHAR
*)cp
, style_nameW
);
715 cp
+= lenfam
+ lensty
;
718 potm
->otmpFullName
= (LPSTR
)(cp
- (char*)potm
);
719 strcpyW((WCHAR
*)cp
, family_nameW
);
720 strcatW((WCHAR
*)cp
, spaceW
);
721 strcatW((WCHAR
*)cp
, style_nameW
);
725 HeapFree(GetProcessHeap(), 0, style_nameW
);
726 HeapFree(GetProcessHeap(), 0, family_nameW
);
732 /*************************************************************
733 * WineEngGetCharWidth
736 BOOL
WineEngGetCharWidth(GdiFont font
, UINT firstChar
, UINT lastChar
,
741 TRACE("%p, %d, %d, %p\n", font
, firstChar
, lastChar
, buffer
);
743 for(c
= firstChar
; c
<= lastChar
; c
++) {
744 WineEngGetGlyphOutline(font
, c
, GGO_METRICS
, &gm
, 0, NULL
, NULL
);
745 buffer
[c
- firstChar
] = gm
.gmCellIncX
;
750 /*************************************************************
751 * WineEngGetTextExtentPoint
754 BOOL
WineEngGetTextExtentPoint(GdiFont font
, LPCWSTR wstr
, INT count
,
761 TRACE("%p, %s, %d, %p\n", font
, debugstr_wn(wstr
, count
), count
,
765 WineEngGetTextMetrics(font
, &tm
);
766 size
->cy
= tm
.tmHeight
;
768 for(idx
= 0; idx
< count
; idx
++) {
769 WineEngGetGlyphOutline(font
, wstr
[idx
], GGO_METRICS
, &gm
, 0, NULL
,
771 size
->cx
+= gm
.gmCellIncX
;
773 TRACE("return %ld,%ld\n", size
->cx
, size
->cy
);
777 /*************************************************************
781 DWORD
WineEngGetFontData(GdiFont font
, DWORD table
, DWORD offset
, LPVOID buf
,
784 FT_Face ft_face
= font
->ft_face
;
786 SFNT_Interface
*sfnt
;
790 if(!FT_IS_SFNT(ft_face
))
793 tt_face
= (TT_Face
) ft_face
;
794 sfnt
= (SFNT_Interface
*)tt_face
->sfnt
;
801 if(table
) { /* MS tags differ in endidness from FT ones */
802 table
= table
>> 24 | table
<< 24 |
803 (table
>> 8 & 0xff00) | (table
<< 8 & 0xff0000);
806 err
= sfnt
->load_any(tt_face
, table
, offset
, buf
, &len
);
808 ERR("Can't find table %08lx\n", table
);
814 #else /* HAVE_FREETYPE */
816 BOOL
WineEngInit(void)
820 GdiFont
WineEngCreateFontInstance(HFONT hfont
)
824 DWORD
WineEngAddRefFont(GdiFont font
)
826 ERR("called but we don't have FreeType\n");
829 DWORD
WineEngDecRefFont(GdiFont font
)
831 ERR("called but we don't have FreeType\n");
835 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, DEVICEFONTENUMPROC proc
, LPARAM lparam
)
840 DWORD
WineEngGetGlyphOutline(GdiFont font
, UINT glyph
, UINT format
,
841 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
844 ERR("called but we don't have FreeType\n");
848 BOOL
WineEngGetTextMetrics(GdiFont font
, LPTEXTMETRICW ptm
)
850 ERR("called but we don't have FreeType\n");
854 UINT
WineEngGetOutlineTextMetrics(GdiFont font
, UINT cbSize
,
855 OUTLINETEXTMETRICW
*potm
)
857 ERR("called but we don't have FreeType\n");
861 BOOL
WineEngGetCharWidth(GdiFont font
, UINT firstChar
, UINT lastChar
,
864 ERR("called but we don't have FreeType\n");
868 BOOL
WineEngGetTextExtentPoint(GdiFont font
, LPCWSTR wstr
, INT count
,
871 ERR("called but we don't have FreeType\n");
875 DWORD
WineEngGetFontData(GdiFont font
, DWORD table
, DWORD offset
, LPVOID buf
,
878 ERR("called but we don't have FreeType\n");
881 #endif /* HAVE_FREETYPE */