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_FTSNAMES_H
40 #include <freetype/ftsnames.h>
42 # ifdef HAVE_FREETYPE_FTNAMES_H
43 # include <freetype/ftnames.h>
46 #ifdef HAVE_FREETYPE_TTNAMEID_H
47 #include <freetype/ttnameid.h>
49 #ifdef HAVE_FREETYPE_FTOUTLN_H
50 #include <freetype/ftoutln.h>
52 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
53 #include <freetype/internal/sfnt.h>
56 static FT_Library library
= 0;
58 typedef struct tagFace
{
66 typedef struct tagFamily
{
69 struct tagFamily
*next
;
77 static Family
*FontList
= NULL
;
79 static BOOL
AddFontFileToList(char *file
)
82 WCHAR
*FamilyW
, *StyleW
;
84 Family
*family
= FontList
;
85 Family
**insert
= &FontList
;
88 TRACE("Loading font file %s\n", debugstr_a(file
));
89 if(FT_New_Face(library
, file
, 0, &ft_face
)) {
90 ERR("Unable to load font file %s\n", debugstr_a(file
));
94 if(!FT_IS_SFNT(ft_face
)) { /* for now we'll skip everything but TT/OT */
95 FT_Done_Face(ft_face
);
99 len
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->family_name
, -1, NULL
, 0);
100 FamilyW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
101 MultiByteToWideChar(CP_ACP
, 0, ft_face
->family_name
, -1, FamilyW
, len
);
104 if(!strcmpW(family
->FamilyName
, FamilyW
))
106 insert
= &family
->next
;
107 family
= family
->next
;
110 family
= *insert
= HeapAlloc(GetProcessHeap(), 0, sizeof(*family
));
111 family
->FamilyName
= FamilyW
;
112 family
->FirstFace
= NULL
;
115 HeapFree(GetProcessHeap(), 0, FamilyW
);
118 len
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0);
119 StyleW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
120 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, StyleW
, len
);
123 for(insertface
= &family
->FirstFace
; *insertface
;
124 insertface
= &(*insertface
)->next
) {
125 if(!strcmpW((*insertface
)->StyleName
, StyleW
)) {
126 ERR("Already loaded font %s %s\n", debugstr_w(family
->FamilyName
),
128 HeapFree(GetProcessHeap(), 0, StyleW
);
129 FT_Done_Face(ft_face
);
133 *insertface
= HeapAlloc(GetProcessHeap(), 0, sizeof(**insertface
));
134 (*insertface
)->StyleName
= StyleW
;
135 (*insertface
)->file
= HeapAlloc(GetProcessHeap(),0,strlen(file
)+1);
136 strcpy((*insertface
)->file
, file
);
137 (*insertface
)->next
= NULL
;
138 (*insertface
)->Italic
= (ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 1 : 0;
139 (*insertface
)->Bold
= (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
) ? 1 : 0;
140 FT_Done_Face(ft_face
);
142 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
),
147 static void DumpFontList(void)
152 for(family
= FontList
; family
; family
= family
->next
) {
153 TRACE("Family: %s\n", debugstr_w(family
->FamilyName
));
154 for(face
= family
->FirstFace
; face
; face
= face
->next
) {
155 TRACE("\t%s\n", debugstr_w(face
->StyleName
));
161 static BOOL
ReadFontDir(char *dirname
)
167 dir
= opendir(dirname
);
169 ERR("Can't open directory %s\n", debugstr_a(dirname
));
172 while((dent
= readdir(dir
)) != NULL
) {
173 if(!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, ".."))
175 sprintf(path
, "%s/%s", dirname
, dent
->d_name
);
176 AddFontFileToList(path
);
181 /*************************************************************
184 * Initialize FreeType library and create a list of available faces
186 BOOL
WineEngInit(void)
189 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
193 if(FT_Init_FreeType(&library
) != 0) {
194 ERR("Can't init FreeType library\n");
198 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
,
199 "Software\\Wine\\Wine\\Config\\FontDirs",
200 &hkey
) != ERROR_SUCCESS
) {
201 TRACE("Can't open FontDirs key in config file\n");
205 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &valuelen
,
206 &datalen
, NULL
, NULL
);
208 valuelen
++; /* returned value doesn't include room for '\0' */
209 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
);
210 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
214 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
215 &dlen
) == ERROR_SUCCESS
) {
216 TRACE("Got %s=%s\n", value
, (LPSTR
)data
);
217 ReadFontDir((LPSTR
)data
);
218 /* reset dlen and vlen */
222 HeapFree(GetProcessHeap(), 0, data
);
223 HeapFree(GetProcessHeap(), 0, value
);
230 static FT_Face
OpenFontFile(char *file
, LONG height
)
237 err
= FT_New_Face(library
, file
, 0, &ft_face
);
239 ERR("FT_New_Face rets %d\n", err
);
243 pOS2
= FT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
245 if(height
== 0) height
= 16;
247 /* Calc. height of EM square:
249 * For +ve lfHeight we have
250 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
251 * Re-arranging gives:
252 * ppem = units_per_em * lfheight / (winAscent + winDescent)
254 * For -ve lfHeight we have
256 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
257 * with il = winAscent + winDescent - units_per_em]
262 ppem
= ft_face
->units_per_EM
* height
/
263 (pOS2
->usWinAscent
+ pOS2
->usWinDescent
);
267 FT_Set_Pixel_Sizes(ft_face
, 0, ppem
);
271 /*************************************************************
272 * WineEngCreateFontInstance
275 GdiFont
WineEngCreateFontInstance(HFONT hfont
)
279 Family
*family
= NULL
;
280 WCHAR FaceName
[LF_FACESIZE
];
282 FONTOBJ
*font
= GDI_GetObjPtr(hfont
, FONT_MAGIC
);
283 LOGFONTW
*plf
= &font
->logfont
;
285 TRACE("%s, h=%ld, it=%d, weight=%ld\n", debugstr_w(plf
->lfFaceName
),
286 plf
->lfHeight
, plf
->lfItalic
, plf
->lfWeight
);
288 ret
= HeapAlloc(GetProcessHeap(), 0, sizeof(*ret
));
291 strcpyW(FaceName
, plf
->lfFaceName
);
293 if(FaceName
[0] != '\0') {
294 for(family
= FontList
; family
; family
= family
->next
) {
295 if(!strcmpiW(family
->FamilyName
, FaceName
))
302 FIXME("just using first face for now\n");
305 it
= plf
->lfItalic
? 1 : 0;
306 bd
= plf
->lfWeight
> 550 ? 1 : 0;
308 for(face
= family
->FirstFace
; face
; face
= face
->next
) {
309 if(!(face
->Italic
^ it
) && !(face
->Bold
^ bd
))
312 if(!face
) face
= family
->FirstFace
;
314 TRACE("Choosen %s %s\n", debugstr_w(family
->FamilyName
),
315 debugstr_w(face
->StyleName
));
317 ret
->ft_face
= OpenFontFile(face
->file
, plf
->lfHeight
);
319 GDI_ReleaseObj(hfont
);
320 TRACE("returning %p\n", ret
);
324 /*************************************************************
328 DWORD
WineEngAddRefFont(GdiFont font
)
333 /*************************************************************
337 DWORD
WineEngDecRefFont(GdiFont font
)
339 DWORD ret
= --font
->ref
;
342 FT_Done_Face(font
->ft_face
);
343 HeapFree(GetProcessHeap(), 0, font
);
348 static void GetEnumStructs(Face
*face
, LPENUMLOGFONTEXW pelf
,
349 LPNEWTEXTMETRICEXW pntm
, LPDWORD ptype
)
351 OUTLINETEXTMETRICW
*potm
;
353 GdiFont font
= HeapAlloc(GetProcessHeap(),0,sizeof(*font
));
356 font
->ft_face
= OpenFontFile(face
->file
, 100);
358 memset(&pelf
->elfLogFont
, 0, sizeof(LOGFONTW
));
360 size
= WineEngGetOutlineTextMetrics(font
, 0, NULL
);
361 potm
= HeapAlloc(GetProcessHeap(), 0, size
);
362 WineEngGetOutlineTextMetrics(font
, size
, potm
);
364 #define TM potm->otmTextMetrics
366 pntm
->ntmTm
.tmHeight
= pelf
->elfLogFont
.lfHeight
= TM
.tmHeight
;
367 pntm
->ntmTm
.tmAscent
= TM
.tmAscent
;
368 pntm
->ntmTm
.tmDescent
= TM
.tmDescent
;
369 pntm
->ntmTm
.tmInternalLeading
= TM
.tmInternalLeading
;
370 pntm
->ntmTm
.tmExternalLeading
= TM
.tmExternalLeading
;
371 pntm
->ntmTm
.tmAveCharWidth
= pelf
->elfLogFont
.lfWeight
= TM
.tmAveCharWidth
;
372 pntm
->ntmTm
.tmMaxCharWidth
= TM
.tmMaxCharWidth
;
373 pntm
->ntmTm
.tmWeight
= pelf
->elfLogFont
.lfWeight
= TM
.tmWeight
;
374 pntm
->ntmTm
.tmOverhang
= TM
.tmOverhang
;
375 pntm
->ntmTm
.tmDigitizedAspectX
= TM
.tmDigitizedAspectX
;
376 pntm
->ntmTm
.tmDigitizedAspectY
= TM
.tmDigitizedAspectY
;
377 pntm
->ntmTm
.tmFirstChar
= TM
.tmFirstChar
;
378 pntm
->ntmTm
.tmLastChar
= TM
.tmLastChar
;
379 pntm
->ntmTm
.tmDefaultChar
= TM
.tmDefaultChar
;
380 pntm
->ntmTm
.tmBreakChar
= TM
.tmBreakChar
;
381 pntm
->ntmTm
.tmItalic
= pelf
->elfLogFont
.lfItalic
= TM
.tmItalic
;
382 pntm
->ntmTm
.tmUnderlined
= pelf
->elfLogFont
.lfUnderline
= TM
.tmUnderlined
;
383 pntm
->ntmTm
.tmStruckOut
= pelf
->elfLogFont
.lfStrikeOut
= TM
.tmStruckOut
;
384 pntm
->ntmTm
.tmPitchAndFamily
= TM
.tmPitchAndFamily
;
385 pelf
->elfLogFont
.lfPitchAndFamily
= (TM
.tmPitchAndFamily
& 0xf1) + 1;
386 pntm
->ntmTm
.tmCharSet
= pelf
->elfLogFont
.lfCharSet
= TM
.tmCharSet
;
388 pntm
->ntmTm
.ntmFlags
= TM
.tmItalic
? NTM_ITALIC
: 0;
389 if(TM
.tmWeight
> 550) pntm
->ntmTm
.ntmFlags
|= NTM_BOLD
;
390 if(pntm
->ntmTm
.ntmFlags
== 0) pntm
->ntmTm
.ntmFlags
= NTM_REGULAR
;
392 pntm
->ntmTm
.ntmSizeEM
= potm
->otmEMSquare
;
393 pntm
->ntmTm
.ntmCellHeight
= 0;
394 pntm
->ntmTm
.ntmAvgWidth
= 0;
396 *ptype
= TM
.tmPitchAndFamily
& TMPF_TRUETYPE
? TRUETYPE_FONTTYPE
: 0;
397 if(!(TM
.tmPitchAndFamily
& TMPF_VECTOR
))
398 *ptype
|= RASTER_FONTTYPE
;
401 memset(&pntm
->ntmFontSig
, 0, sizeof(FONTSIGNATURE
));
403 strncpyW(pelf
->elfLogFont
.lfFaceName
,
404 (WCHAR
*)((char*)potm
+ (ptrdiff_t)potm
->otmpFamilyName
),
406 strncpyW(pelf
->elfFullName
,
407 (WCHAR
*)((char*)potm
+ (ptrdiff_t)potm
->otmpFullName
),
409 strncpyW(pelf
->elfStyle
,
410 (WCHAR
*)((char*)potm
+ (ptrdiff_t)potm
->otmpStyleName
),
412 pelf
->elfScript
[0] = '\0'; /* FIXME */
414 HeapFree(GetProcessHeap(), 0, potm
);
415 WineEngDecRefFont(font
);
419 /*************************************************************
423 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, DEVICEFONTENUMPROC proc
,
429 NEWTEXTMETRICEXW ntm
;
432 TRACE("facename = %s\n", debugstr_w(plf
->lfFaceName
));
433 if(plf
->lfFaceName
[0]) {
434 for(family
= FontList
; family
; family
= family
->next
) {
435 if(!strcmpiW(plf
->lfFaceName
, family
->FamilyName
)) {
436 for(face
= family
->FirstFace
; face
; face
= face
->next
) {
437 GetEnumStructs(face
, &elf
, &ntm
, &type
);
438 TRACE("enuming '%s'\n",
439 debugstr_w(elf
.elfLogFont
.lfFaceName
));
440 ret
= proc(&elf
, &ntm
, type
, lparam
);
446 for(family
= FontList
; family
; family
= family
->next
) {
447 GetEnumStructs(family
->FirstFace
, &elf
, &ntm
, &type
);
448 TRACE("enuming '%s'\n", debugstr_w(elf
.elfLogFont
.lfFaceName
));
449 ret
= proc(&elf
, &ntm
, type
, lparam
);
457 /*************************************************************
458 * WineEngGetGlyphOutline
460 * Behaves in exactly the same way as the win32 api GetGlyphOutline
461 * except that the first parameter is the HWINEENGFONT of the font in
462 * question rather than an HDC.
465 DWORD
WineEngGetGlyphOutline(GdiFont font
, UINT glyph
, UINT format
,
466 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
469 FT_Face ft_face
= font
->ft_face
;
471 DWORD width
, height
, pitch
, needed
;
474 TRACE("%p, %04x, %08x, %p, %08lx, %p, %p\n", font
, glyph
, format
, lpgm
,
477 if(format
& GGO_GLYPH_INDEX
)
480 glyph_index
= FT_Get_Char_Index(ft_face
, glyph
);
482 FT_Load_Glyph(ft_face
, glyph_index
, FT_LOAD_DEFAULT
);
484 lpgm
->gmBlackBoxX
= ft_face
->glyph
->metrics
.width
>> 6;
485 lpgm
->gmBlackBoxY
= ft_face
->glyph
->metrics
.height
>> 6;
486 lpgm
->gmptGlyphOrigin
.x
= ft_face
->glyph
->metrics
.horiBearingX
>> 6;
487 lpgm
->gmptGlyphOrigin
.y
= ft_face
->glyph
->metrics
.horiBearingY
>> 6;
488 lpgm
->gmCellIncX
= ft_face
->glyph
->metrics
.horiAdvance
>> 6;
489 lpgm
->gmCellIncY
= 0;
491 if(format
== GGO_METRICS
)
494 if(ft_face
->glyph
->format
!= ft_glyph_format_outline
) {
495 FIXME("loaded a bitmap\n");
499 if(format
== GGO_BITMAP
) {
500 width
= lpgm
->gmBlackBoxX
;
501 height
= lpgm
->gmBlackBoxY
;
502 pitch
= (width
+ 31) / 32 * 4;
503 needed
= pitch
* height
;
505 if(!buf
|| !buflen
) return needed
;
506 ft_bitmap
.width
= width
;
507 ft_bitmap
.rows
= height
;
508 ft_bitmap
.pitch
= pitch
;
509 ft_bitmap
.pixel_mode
= ft_pixel_mode_mono
;
510 ft_bitmap
.buffer
= buf
;
512 FT_Outline_Translate(&ft_face
->glyph
->outline
,
513 - ft_face
->glyph
->metrics
.horiBearingX
,
514 - (ft_face
->glyph
->metrics
.horiBearingY
-
515 ft_face
->glyph
->metrics
.height
) );
517 FT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
519 FIXME("Unsupported format %d\n", format
);
525 /*************************************************************
526 * WineEngGetTextMetrics
529 BOOL
WineEngGetTextMetrics(GdiFont font
, LPTEXTMETRICW ptm
)
531 FT_Face ft_face
= font
->ft_face
;
533 TT_HoriHeader
*pHori
;
534 FT_Fixed x_scale
, y_scale
;
536 x_scale
= ft_face
->size
->metrics
.x_scale
;
537 y_scale
= ft_face
->size
->metrics
.y_scale
;
539 pOS2
= FT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
541 FIXME("Can't find OS/2 table - not TT font?\n");
545 pHori
= FT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
547 FIXME("Can't find HHEA table - not TT font?\n");
551 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",
552 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
553 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
554 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
555 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
556 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
558 ptm
->tmAscent
= (FT_MulFix(pOS2
->usWinAscent
, y_scale
) + 32) >> 6;
559 ptm
->tmDescent
= (FT_MulFix(pOS2
->usWinDescent
, y_scale
) + 32) >> 6;
560 ptm
->tmHeight
= ptm
->tmAscent
+ ptm
->tmDescent
;
561 ptm
->tmInternalLeading
= (FT_MulFix(pOS2
->usWinAscent
+ pOS2
->usWinDescent
562 - ft_face
->units_per_EM
, y_scale
) + 32) >> 6;
565 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
567 ptm
->tmExternalLeading
= max(0, (FT_MulFix(pHori
->Line_Gap
-
568 ((pOS2
->usWinAscent
+ pOS2
->usWinDescent
) -
569 (pHori
->Ascender
- pHori
->Descender
)), y_scale
) + 32) >> 6);
571 ptm
->tmAveCharWidth
= (FT_MulFix(pOS2
->xAvgCharWidth
, x_scale
) + 32) >> 6;
572 ptm
->tmMaxCharWidth
= (FT_MulFix(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
573 ptm
->tmWeight
= pOS2
->usWeightClass
;
575 ptm
->tmDigitizedAspectX
= 300;
576 ptm
->tmDigitizedAspectY
= 300;
577 ptm
->tmFirstChar
= pOS2
->usFirstCharIndex
;
578 ptm
->tmLastChar
= pOS2
->usLastCharIndex
;
579 ptm
->tmDefaultChar
= pOS2
->usDefaultChar
;
580 ptm
->tmBreakChar
= pOS2
->usBreakChar
;
581 ptm
->tmItalic
= (ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 1 : 0;
582 ptm
->tmUnderlined
= 0; /* entry in OS2 table */
583 ptm
->tmStruckOut
= 0; /* entry in OS2 table */
585 /* Yes this is correct; braindead api */
586 ptm
->tmPitchAndFamily
= FT_IS_FIXED_WIDTH(ft_face
) ? 0 : TMPF_FIXED_PITCH
;
587 if(FT_IS_SCALABLE(ft_face
))
588 ptm
->tmPitchAndFamily
|= TMPF_VECTOR
;
589 if(FT_IS_SFNT(ft_face
))
590 ptm
->tmPitchAndFamily
|= TMPF_TRUETYPE
;
592 ptm
->tmCharSet
= ANSI_CHARSET
;
595 /*************************************************************
596 * WineEngGetOutlineTextMetrics
599 UINT
WineEngGetOutlineTextMetrics(GdiFont font
, UINT cbSize
,
600 OUTLINETEXTMETRICW
*potm
)
602 FT_Face ft_face
= font
->ft_face
;
603 UINT needed
, lenfam
, lensty
, ret
;
605 TT_HoriHeader
*pHori
;
606 FT_Fixed x_scale
, y_scale
;
607 WCHAR
*family_nameW
, *style_nameW
;
608 WCHAR spaceW
[] = {' ', '\0'};
611 needed
= sizeof(*potm
);
613 lenfam
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->family_name
, -1, NULL
, 0)
615 family_nameW
= HeapAlloc(GetProcessHeap(), 0, lenfam
);
616 MultiByteToWideChar(CP_ACP
, 0, ft_face
->family_name
, -1,
617 family_nameW
, lenfam
);
619 lensty
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0)
621 style_nameW
= HeapAlloc(GetProcessHeap(), 0, lensty
);
622 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1,
623 style_nameW
, lensty
);
625 /* These names should be read from the TT name table */
627 /* length of otmpFamilyName */
630 /* length of otmpFaceName */
631 if(!strcasecmp(ft_face
->style_name
, "regular")) {
632 needed
+= lenfam
; /* just the family name */
634 needed
+= lenfam
+ lensty
; /* family + " " + style */
637 /* length of otmpStyleName */
640 /* length of otmpFullName */
641 needed
+= lenfam
+ lensty
;
643 if(needed
> cbSize
) {
648 x_scale
= ft_face
->size
->metrics
.x_scale
;
649 y_scale
= ft_face
->size
->metrics
.y_scale
;
651 pOS2
= FT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
653 FIXME("Can't find OS/2 table - not TT font?\n");
658 pHori
= FT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
660 FIXME("Can't find HHEA table - not TT font?\n");
665 potm
->otmSize
= needed
;
667 WineEngGetTextMetrics(font
, &potm
->otmTextMetrics
);
670 memcpy(&potm
->otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
671 potm
->otmfsSelection
= pOS2
->fsSelection
;
672 potm
->otmfsType
= pOS2
->fsType
;
673 potm
->otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
674 potm
->otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
675 potm
->otmItalicAngle
= 0; /* POST table */
676 potm
->otmEMSquare
= ft_face
->units_per_EM
;
677 potm
->otmAscent
= pOS2
->sTypoAscender
;
678 potm
->otmDescent
= pOS2
->sTypoDescender
;
679 potm
->otmLineGap
= pOS2
->sTypoLineGap
;
680 potm
->otmsCapEmHeight
= pOS2
->sCapHeight
;
681 potm
->otmsXHeight
= pOS2
->sxHeight
;
682 potm
->otmrcFontBox
.left
= ft_face
->bbox
.xMin
;
683 potm
->otmrcFontBox
.right
= ft_face
->bbox
.xMax
;
684 potm
->otmrcFontBox
.top
= ft_face
->bbox
.yMin
;
685 potm
->otmrcFontBox
.bottom
= ft_face
->bbox
.yMax
;
686 potm
->otmMacAscent
= 0; /* where do these come from ? */
687 potm
->otmMacDescent
= 0;
688 potm
->otmMacLineGap
= 0;
689 potm
->otmusMinimumPPEM
= 0; /* TT Header */
690 potm
->otmptSubscriptSize
.x
= pOS2
->ySubscriptXSize
;
691 potm
->otmptSubscriptSize
.y
= pOS2
->ySubscriptYSize
;
692 potm
->otmptSubscriptOffset
.x
= pOS2
->ySubscriptXOffset
;
693 potm
->otmptSubscriptOffset
.y
= pOS2
->ySubscriptYOffset
;
694 potm
->otmptSuperscriptSize
.x
= pOS2
->ySuperscriptXSize
;
695 potm
->otmptSuperscriptSize
.y
= pOS2
->ySuperscriptYSize
;
696 potm
->otmptSuperscriptOffset
.x
= pOS2
->ySuperscriptXOffset
;
697 potm
->otmptSuperscriptOffset
.y
= pOS2
->ySuperscriptYOffset
;
698 potm
->otmsStrikeoutSize
= pOS2
->yStrikeoutSize
;
699 potm
->otmsStrikeoutPosition
= pOS2
->yStrikeoutPosition
;
700 potm
->otmsUnderscoreSize
= 0; /* POST Header */
701 potm
->otmsUnderscorePosition
= 0; /* POST Header */
703 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
704 cp
= (char*)potm
+ sizeof(*potm
);
705 potm
->otmpFamilyName
= (LPSTR
)(cp
- (char*)potm
);
706 strcpyW((WCHAR
*)cp
, family_nameW
);
708 potm
->otmpStyleName
= (LPSTR
)(cp
- (char*)potm
);
709 strcpyW((WCHAR
*)cp
, style_nameW
);
711 potm
->otmpFaceName
= (LPSTR
)(cp
- (char*)potm
);
712 strcpyW((WCHAR
*)cp
, family_nameW
);
713 if(strcasecmp(ft_face
->style_name
, "regular")) {
714 strcatW((WCHAR
*)cp
, spaceW
);
715 strcatW((WCHAR
*)cp
, style_nameW
);
716 cp
+= lenfam
+ lensty
;
719 potm
->otmpFullName
= (LPSTR
)(cp
- (char*)potm
);
720 strcpyW((WCHAR
*)cp
, family_nameW
);
721 strcatW((WCHAR
*)cp
, spaceW
);
722 strcatW((WCHAR
*)cp
, style_nameW
);
726 HeapFree(GetProcessHeap(), 0, style_nameW
);
727 HeapFree(GetProcessHeap(), 0, family_nameW
);
733 /*************************************************************
734 * WineEngGetCharWidth
737 BOOL
WineEngGetCharWidth(GdiFont font
, UINT firstChar
, UINT lastChar
,
742 TRACE("%p, %d, %d, %p\n", font
, firstChar
, lastChar
, buffer
);
744 for(c
= firstChar
; c
<= lastChar
; c
++) {
745 WineEngGetGlyphOutline(font
, c
, GGO_METRICS
, &gm
, 0, NULL
, NULL
);
746 buffer
[c
- firstChar
] = gm
.gmCellIncX
;
751 /*************************************************************
752 * WineEngGetTextExtentPoint
755 BOOL
WineEngGetTextExtentPoint(GdiFont font
, LPCWSTR wstr
, INT count
,
762 TRACE("%p, %s, %d, %p\n", font
, debugstr_wn(wstr
, count
), count
,
766 WineEngGetTextMetrics(font
, &tm
);
767 size
->cy
= tm
.tmHeight
;
769 for(idx
= 0; idx
< count
; idx
++) {
770 WineEngGetGlyphOutline(font
, wstr
[idx
], GGO_METRICS
, &gm
, 0, NULL
,
772 size
->cx
+= gm
.gmCellIncX
;
774 TRACE("return %ld,%ld\n", size
->cx
, size
->cy
);
778 /*************************************************************
782 DWORD
WineEngGetFontData(GdiFont font
, DWORD table
, DWORD offset
, LPVOID buf
,
785 FT_Face ft_face
= font
->ft_face
;
787 SFNT_Interface
*sfnt
;
791 if(!FT_IS_SFNT(ft_face
))
794 tt_face
= (TT_Face
) ft_face
;
795 sfnt
= (SFNT_Interface
*)tt_face
->sfnt
;
802 if(table
) { /* MS tags differ in endidness from FT ones */
803 table
= table
>> 24 | table
<< 24 |
804 (table
>> 8 & 0xff00) | (table
<< 8 & 0xff0000);
807 err
= sfnt
->load_any(tt_face
, table
, offset
, buf
, &len
);
809 ERR("Can't find table %08lx\n", table
);
815 #else /* HAVE_FREETYPE */
817 BOOL
WineEngInit(void)
821 GdiFont
WineEngCreateFontInstance(HFONT hfont
)
825 DWORD
WineEngAddRefFont(GdiFont font
)
827 ERR("called but we don't have FreeType\n");
830 DWORD
WineEngDecRefFont(GdiFont font
)
832 ERR("called but we don't have FreeType\n");
836 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, DEVICEFONTENUMPROC proc
, LPARAM lparam
)
841 DWORD
WineEngGetGlyphOutline(GdiFont font
, UINT glyph
, UINT format
,
842 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
845 ERR("called but we don't have FreeType\n");
849 BOOL
WineEngGetTextMetrics(GdiFont font
, LPTEXTMETRICW ptm
)
851 ERR("called but we don't have FreeType\n");
855 UINT
WineEngGetOutlineTextMetrics(GdiFont font
, UINT cbSize
,
856 OUTLINETEXTMETRICW
*potm
)
858 ERR("called but we don't have FreeType\n");
862 BOOL
WineEngGetCharWidth(GdiFont font
, UINT firstChar
, UINT lastChar
,
865 ERR("called but we don't have FreeType\n");
869 BOOL
WineEngGetTextExtentPoint(GdiFont font
, LPCWSTR wstr
, INT count
,
872 ERR("called but we don't have FreeType\n");
876 DWORD
WineEngGetFontData(GdiFont font
, DWORD table
, DWORD offset
, LPVOID buf
,
879 ERR("called but we don't have FreeType\n");
882 #endif /* HAVE_FREETYPE */