From: Dmitry Timoshkov Subject: [4/5] gdiplus: Fix internal font metrics handling. Take 2. Message-Id: <20120508192956.200b4490.dmitry@baikal.ru> Date: Tue, 8 May 2012 19:29:56 +0900 Deriving GpFont from GpFontFamily was sent separately to simplify a bit the patch. --- dlls/gdiplus/font.c | 454 +++++++++++++++++++++++++--------------- dlls/gdiplus/gdiplus_private.h | 10 +- dlls/gdiplus/graphics.c | 14 +- dlls/gdiplus/graphicspath.c | 5 +- 4 files changed, 307 insertions(+), 176 deletions(-) diff --git a/dlls/gdiplus/font.c b/dlls/gdiplus/font.c index a07333a..bf6a598 100644 --- a/dlls/gdiplus/font.c +++ b/dlls/gdiplus/font.c @@ -34,42 +34,121 @@ WINE_DEFAULT_DEBUG_CHANNEL (gdiplus); #include "gdiplus.h" #include "gdiplus_private.h" +/* PANOSE is 10 bytes in size, need to pack the structure properly */ +#include "pshpack2.h" +typedef struct +{ + USHORT version; + SHORT xAvgCharWidth; + USHORT usWeightClass; + USHORT usWidthClass; + SHORT fsType; + SHORT ySubscriptXSize; + SHORT ySubscriptYSize; + SHORT ySubscriptXOffset; + SHORT ySubscriptYOffset; + SHORT ySuperscriptXSize; + SHORT ySuperscriptYSize; + SHORT ySuperscriptXOffset; + SHORT ySuperscriptYOffset; + SHORT yStrikeoutSize; + SHORT yStrikeoutPosition; + SHORT sFamilyClass; + PANOSE panose; + ULONG ulUnicodeRange1; + ULONG ulUnicodeRange2; + ULONG ulUnicodeRange3; + ULONG ulUnicodeRange4; + CHAR achVendID[4]; + USHORT fsSelection; + USHORT usFirstCharIndex; + USHORT usLastCharIndex; + /* According to the Apple spec, original version didn't have the below fields, + * version numbers were taken from the OpenType spec. + */ + /* version 0 (TrueType 1.5) */ + USHORT sTypoAscender; + USHORT sTypoDescender; + USHORT sTypoLineGap; + USHORT usWinAscent; + USHORT usWinDescent; + /* version 1 (TrueType 1.66) */ + ULONG ulCodePageRange1; + ULONG ulCodePageRange2; + /* version 2 (OpenType 1.2) */ + SHORT sxHeight; + SHORT sCapHeight; + USHORT usDefaultChar; + USHORT usBreakChar; + USHORT usMaxContext; +} TT_OS2_V2; + +typedef struct +{ + ULONG Version; + SHORT Ascender; + SHORT Descender; + SHORT LineGap; + USHORT advanceWidthMax; + SHORT minLeftSideBearing; + SHORT minRightSideBearing; + SHORT xMaxExtent; + SHORT caretSlopeRise; + SHORT caretSlopeRun; + SHORT caretOffset; + SHORT reserved[4]; + SHORT metricDataFormat; + USHORT numberOfHMetrics; +} TT_HHEA; +#include "poppack.h" + +#ifdef WORDS_BIGENDIAN +#define GET_BE_WORD(x) (x) +#define GET_BE_DWORD(x) (x) +#else +#define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x)) +#define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x))); +#endif + +#define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \ + ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \ + ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24)) +#define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2') +#define MS_HHEA_TAG MS_MAKE_TAG('h','h','e','a') + static const REAL mm_per_inch = 25.4; static const REAL inch_per_point = 1.0/72.0; static GpFontCollection installedFontCollection = {0}; -static inline REAL get_dpi (void) -{ - REAL dpi; - GpGraphics *graphics; - HDC hdc = GetDC(0); - GdipCreateFromHDC (hdc, &graphics); - GdipGetDpiX(graphics, &dpi); - GdipDeleteGraphics(graphics); - ReleaseDC (0, hdc); - - return dpi; -} - -static inline REAL point_to_pixel (REAL point) -{ - return point * get_dpi() * inch_per_point; -} - -static inline REAL inch_to_pixel (REAL inch) -{ - return inch * get_dpi(); -} - -static inline REAL document_to_pixel (REAL doc) +static LONG em_size_to_pixel(REAL em_size, Unit unit, LONG dpi) { - return doc * (get_dpi() / 300.0); /* Per MSDN */ -} + switch (unit) + { + default: + FIXME("Unhandled unit type: %d\n", unit); + return 0; -static inline REAL mm_to_pixel (REAL mm) -{ - return mm * (get_dpi() / mm_per_inch); + case UnitPixel: + case UnitWorld: + /* FIXME: Figure out when World != Pixel */ + return em_size; + case UnitDisplay: + FIXME("Unknown behavior for UnitDisplay! Please report!\n"); + /* FIXME: Figure out how this works... + * MSDN says that if "DISPLAY" is a monitor, then pixel should be + * used. That's not what I got. Tests on Windows revealed no output, + * and the tests in tests/font crash windows */ + return 0; + case UnitPoint: + return em_size * dpi * inch_per_point; + case UnitInch: + return em_size * dpi; + case UnitDocument: + return em_size * dpi / 300.0; /* Per MSDN */ + case UnitMillimeter: + return em_size * dpi / mm_per_inch; + } } /******************************************************************************* @@ -96,68 +175,46 @@ static inline REAL mm_to_pixel (REAL mm) GpStatus WINGDIPAPI GdipCreateFont(GDIPCONST GpFontFamily *fontFamily, REAL emSize, INT style, Unit unit, GpFont **font) { - WCHAR facename[LF_FACESIZE]; - LOGFONTW* lfw; - const OUTLINETEXTMETRICW *otm; + HFONT hfont; + OUTLINETEXTMETRICW otm; + LOGFONTW lfw; + HDC hdc; GpStatus stat; + int ret; - if (!fontFamily || !font) + if (!fontFamily || !font || emSize < 0.0) return InvalidParameter; TRACE("%p (%s), %f, %d, %d, %p\n", fontFamily, debugstr_w(fontFamily->FamilyName), emSize, style, unit, font); - stat = GdipGetFamilyName (fontFamily, facename, 0); - if (stat != Ok) return stat; - *font = GdipAlloc(sizeof(GpFont)); - - otm = &fontFamily->otm; - lfw = &((*font)->lfw); - ZeroMemory(&(*lfw), sizeof(*lfw)); + memset(&lfw, 0, sizeof(lfw)); - lfw->lfWeight = otm->otmTextMetrics.tmWeight; - lfw->lfItalic = otm->otmTextMetrics.tmItalic; - lfw->lfUnderline = otm->otmTextMetrics.tmUnderlined; - lfw->lfStrikeOut = otm->otmTextMetrics.tmStruckOut; - lfw->lfCharSet = otm->otmTextMetrics.tmCharSet; - lfw->lfPitchAndFamily = otm->otmTextMetrics.tmPitchAndFamily; - lstrcpynW(lfw->lfFaceName, facename, LF_FACESIZE); + stat = GdipGetFamilyName(fontFamily, lfw.lfFaceName, LANG_NEUTRAL); + if (stat != Ok) return stat; - switch (unit) - { - case UnitWorld: - /* FIXME: Figure out when World != Pixel */ - (*font)->pixel_size = emSize; break; - case UnitDisplay: - FIXME("Unknown behavior for UnitDisplay! Please report!\n"); - /* FIXME: Figure out how this works... - * MSDN says that if "DISPLAY" is a monitor, then pixel should be - * used. That's not what I got. Tests on Windows revealed no output, - * and the tests in tests/font crash windows */ - (*font)->pixel_size = 0; break; - case UnitPixel: - (*font)->pixel_size = emSize; break; - case UnitPoint: - (*font)->pixel_size = point_to_pixel(emSize); break; - case UnitInch: - (*font)->pixel_size = inch_to_pixel(emSize); break; - case UnitDocument: - (*font)->pixel_size = document_to_pixel(emSize); break; - case UnitMillimeter: - (*font)->pixel_size = mm_to_pixel(emSize); break; - } + lfw.lfHeight = -em_size_to_pixel(emSize, unit, fontFamily->dpi); + lfw.lfWeight = style & FontStyleBold ? FW_BOLD : FW_REGULAR; + lfw.lfItalic = style & FontStyleItalic; + lfw.lfUnderline = style & FontStyleUnderline; + lfw.lfStrikeOut = style & FontStyleStrikeout; + + hfont = CreateFontIndirectW(&lfw); + hdc = CreateCompatibleDC(0); + SelectObject(hdc, hfont); + otm.otmSize = sizeof(otm); + ret = GetOutlineTextMetricsW(hdc, otm.otmSize, &otm); + DeleteDC(hdc); + DeleteObject(hfont); - lfw->lfHeight = (*font)->pixel_size * -1; + if (!ret) return NotTrueTypeFont; - lfw->lfWeight = style & FontStyleBold ? FW_BOLD : FW_REGULAR; - lfw->lfItalic = style & FontStyleItalic; - lfw->lfUnderline = style & FontStyleUnderline; - lfw->lfStrikeOut = style & FontStyleStrikeout; + *font = GdipAlloc(sizeof(GpFont)); + if (!*font) return OutOfMemory; (*font)->unit = unit; (*font)->emSize = emSize; - (*font)->height = otm->otmEMSquare; - (*font)->line_spacing = otm->otmTextMetrics.tmAscent + otm->otmTextMetrics.tmDescent + otm->otmTextMetrics.tmExternalLeading; + (*font)->otm = otm; stat = GdipCloneFontFamily((GpFontFamily *)fontFamily, &(*font)->family); if (stat != Ok) @@ -178,42 +235,30 @@ GpStatus WINGDIPAPI GdipCreateFontFromLogfontW(HDC hdc, GDIPCONST LOGFONTW *logfont, GpFont **font) { HFONT hfont, oldfont; - TEXTMETRICW textmet; + OUTLINETEXTMETRICW otm; GpStatus stat; + int ret; TRACE("(%p, %p, %p)\n", hdc, logfont, font); - if(!logfont || !font) + if (!hdc || !logfont || !font) return InvalidParameter; - if (logfont->lfFaceName[0] == 0) - return NotTrueTypeFont; - - *font = GdipAlloc(sizeof(GpFont)); - if(!*font) return OutOfMemory; - - memcpy((*font)->lfw.lfFaceName, logfont->lfFaceName, LF_FACESIZE * - sizeof(WCHAR)); - (*font)->lfw.lfHeight = logfont->lfHeight; - (*font)->lfw.lfItalic = logfont->lfItalic; - (*font)->lfw.lfUnderline = logfont->lfUnderline; - (*font)->lfw.lfStrikeOut = logfont->lfStrikeOut; - - hfont = CreateFontIndirectW(&(*font)->lfw); + hfont = CreateFontIndirectW(logfont); oldfont = SelectObject(hdc, hfont); - GetTextMetricsW(hdc, &textmet); + otm.otmSize = sizeof(otm); + ret = GetOutlineTextMetricsW(hdc, otm.otmSize, &otm); + SelectObject(hdc, oldfont); + DeleteObject(hfont); - (*font)->lfw.lfHeight = -(textmet.tmHeight-textmet.tmInternalLeading); - (*font)->lfw.lfWeight = textmet.tmWeight; - (*font)->lfw.lfCharSet = textmet.tmCharSet; + if (!ret) return NotTrueTypeFont; - (*font)->pixel_size = (*font)->emSize = textmet.tmHeight; - (*font)->unit = UnitPixel; - (*font)->height = 1; /* FIXME: need NEWTEXTMETRIC.ntmSizeEM here */ - (*font)->line_spacing = textmet.tmAscent + textmet.tmDescent + textmet.tmExternalLeading; + *font = GdipAlloc(sizeof(GpFont)); + if (!*font) return OutOfMemory; - SelectObject(hdc, oldfont); - DeleteObject(hfont); + (*font)->unit = UnitWorld; + (*font)->emSize = otm.otmTextMetrics.tmAscent; + (*font)->otm = otm; stat = GdipCreateFontFamilyFromName(logfont->lfFaceName, NULL, &(*font)->family); if (stat != Ok) @@ -304,7 +349,7 @@ GpStatus WINGDIPAPI GdipGetFamily(GpFont *font, GpFontFamily **family) { TRACE("%p %p\n", font, family); - if (!(font && family)) + if (!font || !family) return InvalidParameter; return GdipCloneFontFamily(font->family, family); @@ -330,10 +375,10 @@ GpStatus WINGDIPAPI GdipGetFontSize(GpFont *font, REAL *size) { TRACE("(%p, %p)\n", font, size); - if (!(font && size)) return InvalidParameter; + if (!font || !size) return InvalidParameter; *size = font->emSize; - TRACE("%s,%d => %f\n", debugstr_w(font->lfw.lfFaceName), font->lfw.lfHeight, *size); + TRACE("%s,%d => %f\n", debugstr_w(font->family->FamilyName), font->otm.otmTextMetrics.tmHeight, *size); return Ok; } @@ -355,18 +400,18 @@ GpStatus WINGDIPAPI GdipGetFontStyle(GpFont *font, INT *style) { TRACE("%p %p\n", font, style); - if (!(font && style)) + if (!font || !style) return InvalidParameter; - if (font->lfw.lfWeight > FW_REGULAR) + if (font->otm.otmTextMetrics.tmWeight > FW_REGULAR) *style = FontStyleBold; else *style = FontStyleRegular; - if (font->lfw.lfItalic) + if (font->otm.otmTextMetrics.tmItalic) *style |= FontStyleItalic; - if (font->lfw.lfUnderline) + if (font->otm.otmTextMetrics.tmUnderlined) *style |= FontStyleUnderline; - if (font->lfw.lfStrikeOut) + if (font->otm.otmTextMetrics.tmStruckOut) *style |= FontStyleStrikeout; return Ok; @@ -387,10 +432,10 @@ GpStatus WINGDIPAPI GdipGetFontUnit(GpFont *font, Unit *unit) { TRACE("(%p, %p)\n", font, unit); - if (!(font && unit)) return InvalidParameter; + if (!font || !unit) return InvalidParameter; *unit = font->unit; - TRACE("%s,%d => %d\n", debugstr_w(font->lfw.lfFaceName), font->lfw.lfHeight, *unit); + TRACE("%s,%d => %d\n", debugstr_w(font->family->FamilyName), font->otm.otmTextMetrics.tmHeight, *unit); return Ok; } @@ -430,8 +475,22 @@ GpStatus WINGDIPAPI GdipGetLogFontW(GpFont *font, GpGraphics *graphics, if(!font || !graphics || !lfw) return InvalidParameter; - *lfw = font->lfw; - TRACE("=> %s,%d\n", debugstr_w(font->lfw.lfFaceName), font->lfw.lfHeight); + lfw->lfHeight = -font->otm.otmTextMetrics.tmAscent; + lfw->lfWidth = 0; + lfw->lfEscapement = 0; + lfw->lfOrientation = 0; + lfw->lfWeight = font->otm.otmTextMetrics.tmWeight; + lfw->lfItalic = font->otm.otmTextMetrics.tmItalic ? 1 : 0; + lfw->lfUnderline = font->otm.otmTextMetrics.tmUnderlined ? 1 : 0; + lfw->lfStrikeOut = font->otm.otmTextMetrics.tmStruckOut ? 1 : 0; + lfw->lfCharSet = font->otm.otmTextMetrics.tmCharSet; + lfw->lfOutPrecision = OUT_DEFAULT_PRECIS; + lfw->lfClipPrecision = CLIP_DEFAULT_PRECIS; + lfw->lfQuality = DEFAULT_QUALITY; + lfw->lfPitchAndFamily = 0; + strcpyW(lfw->lfFaceName, font->family->FamilyName); + + TRACE("=> %s,%d\n", debugstr_w(lfw->lfFaceName), lfw->lfHeight); return Ok; } @@ -479,12 +538,15 @@ GpStatus WINGDIPAPI GdipGetFontHeight(GDIPCONST GpFont *font, TRACE("%p %p %p\n", font, graphics, height); - stat = GdipGetDpiY((GpGraphics*)graphics, &dpi); - - if (stat == Ok) - stat = GdipGetFontHeightGivenDPI(font, dpi, height); + if (graphics) + { + stat = GdipGetDpiY((GpGraphics*)graphics, &dpi); + if (stat != Ok) return stat; + } + else + dpi = font->family->dpi; - return stat; + return GdipGetFontHeightGivenDPI(font, dpi, height); } /******************************************************************************* @@ -504,14 +566,26 @@ GpStatus WINGDIPAPI GdipGetFontHeight(GDIPCONST GpFont *font, */ GpStatus WINGDIPAPI GdipGetFontHeightGivenDPI(GDIPCONST GpFont *font, REAL dpi, REAL *height) { - REAL font_height; + GpStatus stat; + INT style; + UINT16 line_spacing, em_height; + REAL font_height, font_size; + + if (!font || !height) return InvalidParameter; TRACE("%p (%s), %f, %p\n", font, - debugstr_w(font->lfw.lfFaceName), dpi, height); + debugstr_w(font->family->FamilyName), dpi, height); - if (!(font && height)) return InvalidParameter; + stat = GdipGetFontSize((GpFont *)font, &font_size); + if (stat != Ok) return stat; + stat = GdipGetFontStyle((GpFont *)font, &style); + if (stat != Ok) return stat; + stat = GdipGetLineSpacing(font->family, style, &line_spacing); + if (stat != Ok) return stat; + stat = GdipGetEmHeight(font->family, style, &em_height); + if (stat != Ok) return stat; - font_height = font->line_spacing * (font->emSize / font->height); + font_height = (REAL)line_spacing * font_size / (REAL)em_height; switch (font->unit) { @@ -537,7 +611,7 @@ GpStatus WINGDIPAPI GdipGetFontHeightGivenDPI(GDIPCONST GpFont *font, REAL dpi, } TRACE("%s,%d(unit %d) => %f\n", - debugstr_w(font->lfw.lfFaceName), font->lfw.lfHeight, font->unit, *height); + debugstr_w(font->family->FamilyName), font->otm.otmTextMetrics.tmHeight, font->unit, *height); return Ok; } @@ -551,35 +625,84 @@ GpStatus WINGDIPAPI GdipGetFontHeightGivenDPI(GDIPCONST GpFont *font, REAL dpi, static INT CALLBACK is_font_installed_proc(const LOGFONTW *elf, const TEXTMETRICW *ntm, DWORD type, LPARAM lParam) { - if (!ntm || type == RASTER_FONTTYPE) - { + if (type != TRUETYPE_FONTTYPE) return 1; - } *(LOGFONTW *)lParam = *elf; return 0; } -static BOOL find_installed_font(const WCHAR *name, OUTLINETEXTMETRICW *otm) +struct font_metrics +{ + UINT16 em_height, ascent, descent, line_spacing; /* in font units */ + int dpi; +}; + +static BOOL get_font_metrics(HDC hdc, struct font_metrics *fm) +{ + OUTLINETEXTMETRICW otm; + TT_OS2_V2 tt_os2; + TT_HHEA tt_hori; + LONG size; + UINT16 line_gap; + + otm.otmSize = sizeof(otm); + if (!GetOutlineTextMetricsW(hdc, otm.otmSize, &otm)) return FALSE; + + fm->em_height = otm.otmEMSquare; + fm->dpi = GetDeviceCaps(hdc, LOGPIXELSY); + + memset(&tt_hori, 0, sizeof(tt_hori)); + if (GetFontData(hdc, MS_HHEA_TAG, 0, &tt_hori, sizeof(tt_hori)) != GDI_ERROR) + { + fm->ascent = GET_BE_WORD(tt_hori.Ascender); + fm->descent = -GET_BE_WORD(tt_hori.Descender); + TRACE("hhea: ascent %d, descent %d\n", fm->ascent, fm->descent); + line_gap = GET_BE_WORD(tt_hori.LineGap); + fm->line_spacing = fm->ascent + fm->descent + line_gap; + TRACE("line_gap %u, line_spacing %u\n", line_gap, fm->line_spacing); + if (fm->ascent + fm->descent != 0) return TRUE; + } + + size = GetFontData(hdc, MS_OS2_TAG, 0, NULL, 0); + if (size == GDI_ERROR) return FALSE; + + if (size > sizeof(tt_os2)) size = sizeof(tt_os2); + + memset(&tt_os2, 0, sizeof(tt_os2)); + if (GetFontData(hdc, MS_OS2_TAG, 0, &tt_os2, size) != size) return FALSE; + + fm->ascent = GET_BE_WORD(tt_os2.usWinAscent); + fm->descent = GET_BE_WORD(tt_os2.usWinDescent); + TRACE("usWinAscent %u, usWinDescent %u\n", fm->ascent, fm->descent); + if (fm->ascent + fm->descent == 0) + { + fm->ascent = GET_BE_WORD(tt_os2.sTypoAscender); + fm->descent = GET_BE_WORD(tt_os2.sTypoDescender); + TRACE("sTypoAscender %u, sTypoDescender %u\n", fm->ascent, fm->descent); + } + line_gap = GET_BE_WORD(tt_os2.sTypoLineGap); + fm->line_spacing = fm->ascent + fm->descent + line_gap; + TRACE("line_gap %u, line_spacing %u\n", line_gap, fm->line_spacing); + return TRUE; +} + +static GpStatus find_installed_font(const WCHAR *name, struct font_metrics *fm) { LOGFONTW lf; HDC hdc = CreateCompatibleDC(0); - BOOL ret = FALSE; + GpStatus ret = FontFamilyNotFound; if(!EnumFontFamiliesW(hdc, name, is_font_installed_proc, (LPARAM)&lf)) { - HFONT hfont; + HFONT hfont, old_font; - lf.lfHeight = -2048; hfont = CreateFontIndirectW(&lf); - hfont = SelectObject(hdc, hfont); - - otm->otmSize = sizeof(*otm); - if (GetOutlineTextMetricsW(hdc, otm->otmSize, otm)) - ret = TRUE; - - DeleteObject(SelectObject(hdc, hfont)); + old_font = SelectObject(hdc, hfont); + ret = get_font_metrics(hdc, fm) ? Ok : NotTrueTypeFont; + SelectObject(hdc, old_font); + DeleteObject(hfont); } DeleteDC(hdc); @@ -610,24 +733,29 @@ GpStatus WINGDIPAPI GdipCreateFontFamilyFromName(GDIPCONST WCHAR *name, GpFontCollection *fontCollection, GpFontFamily **FontFamily) { + GpStatus stat; GpFontFamily* ffamily; - OUTLINETEXTMETRICW otm; + struct font_metrics fm; TRACE("%s, %p %p\n", debugstr_w(name), fontCollection, FontFamily); - if (!(name && FontFamily)) + if (!name || !FontFamily) return InvalidParameter; if (fontCollection) FIXME("No support for FontCollections yet!\n"); - if (!find_installed_font(name, &otm)) - return FontFamilyNotFound; + stat = find_installed_font(name, &fm); + if (stat != Ok) return stat; ffamily = GdipAlloc(sizeof (GpFontFamily)); if (!ffamily) return OutOfMemory; - ffamily->otm = otm; lstrcpynW(ffamily->FamilyName, name, LF_FACESIZE); + ffamily->em_height = fm.em_height; + ffamily->ascent = fm.ascent; + ffamily->descent = fm.descent; + ffamily->line_spacing = fm.line_spacing; + ffamily->dpi = fm.dpi; *FontFamily = ffamily; @@ -650,15 +778,15 @@ GpStatus WINGDIPAPI GdipCreateFontFamilyFromName(GDIPCONST WCHAR *name, */ GpStatus WINGDIPAPI GdipCloneFontFamily(GpFontFamily* FontFamily, GpFontFamily** clonedFontFamily) { - if (!(FontFamily && clonedFontFamily)) return InvalidParameter; + if (!FontFamily || !clonedFontFamily) return InvalidParameter; - TRACE("stub: %p (%s), %p\n", FontFamily, + TRACE("%p (%s), %p\n", FontFamily, debugstr_w(FontFamily->FamilyName), clonedFontFamily); *clonedFontFamily = GdipAlloc(sizeof(GpFontFamily)); if (!*clonedFontFamily) return OutOfMemory; - (*clonedFontFamily)->otm = FontFamily->otm; + **clonedFontFamily = *FontFamily; lstrcpyW((*clonedFontFamily)->FamilyName, FontFamily->FamilyName); TRACE("<-- %p\n", *clonedFontFamily); @@ -729,10 +857,10 @@ GpStatus WINGDIPAPI GdipDeleteFontFamily(GpFontFamily *FontFamily) GpStatus WINGDIPAPI GdipGetCellAscent(GDIPCONST GpFontFamily *family, INT style, UINT16* CellAscent) { - if (!(family && CellAscent)) return InvalidParameter; + if (!family || !CellAscent) return InvalidParameter; - *CellAscent = family->otm.otmTextMetrics.tmAscent; - TRACE("%d => %u\n", family->otm.otmTextMetrics.tmHeight, *CellAscent); + *CellAscent = family->ascent; + TRACE("%s => %u\n", debugstr_w(family->FamilyName), *CellAscent); return Ok; } @@ -742,10 +870,10 @@ GpStatus WINGDIPAPI GdipGetCellDescent(GDIPCONST GpFontFamily *family, { TRACE("(%p, %d, %p)\n", family, style, CellDescent); - if (!(family && CellDescent)) return InvalidParameter; + if (!family || !CellDescent) return InvalidParameter; - *CellDescent = family->otm.otmTextMetrics.tmDescent; - TRACE("%d => %u\n", family->otm.otmTextMetrics.tmHeight, *CellDescent); + *CellDescent = family->descent; + TRACE("%s => %u\n", debugstr_w(family->FamilyName), *CellDescent); return Ok; } @@ -766,12 +894,12 @@ GpStatus WINGDIPAPI GdipGetCellDescent(GDIPCONST GpFontFamily *family, */ GpStatus WINGDIPAPI GdipGetEmHeight(GDIPCONST GpFontFamily *family, INT style, UINT16* EmHeight) { - if (!(family && EmHeight)) return InvalidParameter; + if (!family || !EmHeight) return InvalidParameter; TRACE("%p (%s), %d, %p\n", family, debugstr_w(family->FamilyName), style, EmHeight); - *EmHeight = family->otm.otmEMSquare; - TRACE("%d => %u\n", family->otm.otmTextMetrics.tmHeight, *EmHeight); + *EmHeight = family->em_height; + TRACE("%s => %u\n", debugstr_w(family->FamilyName), *EmHeight); return Ok; } @@ -796,13 +924,13 @@ GpStatus WINGDIPAPI GdipGetLineSpacing(GDIPCONST GpFontFamily *family, { TRACE("%p, %d, %p\n", family, style, LineSpacing); - if (!(family && LineSpacing)) + if (!family || !LineSpacing) return InvalidParameter; if (style) FIXME("ignoring style\n"); - *LineSpacing = family->otm.otmTextMetrics.tmAscent + family->otm.otmTextMetrics.tmDescent + family->otm.otmTextMetrics.tmExternalLeading; - TRACE("%d => %u\n", family->otm.otmTextMetrics.tmHeight, *LineSpacing); + *LineSpacing = family->line_spacing; + TRACE("%s => %u\n", debugstr_w(family->FamilyName), *LineSpacing); return Ok; } @@ -829,7 +957,7 @@ GpStatus WINGDIPAPI GdipIsStyleAvailable(GDIPCONST GpFontFamily* family, TRACE("%p %d %p\n", family, style, IsStyleAvailable); - if (!(family && IsStyleAvailable)) + if (!family || !IsStyleAvailable) return InvalidParameter; *IsStyleAvailable = FALSE; @@ -987,7 +1115,7 @@ GpStatus WINGDIPAPI GdipPrivateAddFontFile(GpFontCollection* fontCollection, { FIXME("stub: %p, %s\n", fontCollection, debugstr_w(filename)); - if (!(fontCollection && filename)) + if (!fontCollection || !filename) return InvalidParameter; return NotImplemented; @@ -1156,7 +1284,7 @@ GpStatus WINGDIPAPI GdipGetFontCollectionFamilyCount( { TRACE("%p, %p\n", fontCollection, numFound); - if (!(fontCollection && numFound)) + if (!fontCollection || !numFound) return InvalidParameter; *numFound = fontCollection->count; @@ -1175,7 +1303,7 @@ GpStatus WINGDIPAPI GdipGetFontCollectionFamilyList( TRACE("%p, %d, %p, %p\n", fontCollection, numSought, gpfamilies, numFound); - if (!(fontCollection && gpfamilies && numFound)) + if (!fontCollection || !gpfamilies || !numFound) return InvalidParameter; memset(gpfamilies, 0, sizeof(*gpfamilies) * numSought); diff --git a/dlls/gdiplus/gdiplus_private.h b/dlls/gdiplus/gdiplus_private.h index 3676358..1adfe09 100644 --- a/dlls/gdiplus/gdiplus_private.h +++ b/dlls/gdiplus/gdiplus_private.h @@ -347,11 +347,8 @@ struct GpImageAttributes{ struct GpFont{ GpFontFamily *family; - LOGFONTW lfw; - REAL emSize; - REAL pixel_size; - UINT height; - LONG line_spacing; + OUTLINETEXTMETRICW otm; + REAL emSize; /* in font units */ Unit unit; }; @@ -378,8 +375,9 @@ struct GpFontCollection{ }; struct GpFontFamily{ - OUTLINETEXTMETRICW otm; WCHAR FamilyName[LF_FACESIZE]; + UINT16 em_height, ascent, descent, line_spacing; /* in font units */ + int dpi; }; /* internal use */ diff --git a/dlls/gdiplus/graphics.c b/dlls/gdiplus/graphics.c index a5e3eb2..b674035 100644 --- a/dlls/gdiplus/graphics.c +++ b/dlls/gdiplus/graphics.c @@ -2136,15 +2136,13 @@ void get_font_hfont(GpGraphics *graphics, GDIPCONST GpFont *font, HFONT *hfont) rel_height = sqrt((pt[2].Y-pt[0].Y)*(pt[2].Y-pt[0].Y)+ (pt[2].X-pt[0].X)*(pt[2].X-pt[0].X)); - lfw = font->lfw; - lfw.lfHeight = roundr(-font->pixel_size * rel_height); + GdipGetLogFontW((GpFont *)font, graphics, &lfw); + lfw.lfHeight = roundr(lfw.lfHeight * rel_height); unscaled_font = CreateFontIndirectW(&lfw); SelectObject(hdc, unscaled_font); GetTextMetricsW(hdc, &textmet); - lfw = font->lfw; - lfw.lfHeight = roundr(-font->pixel_size * rel_height); lfw.lfWidth = roundr(textmet.tmAveCharWidth * rel_width / rel_height); lfw.lfEscapement = lfw.lfOrientation = roundr((angle / M_PI) * 1800.0); @@ -4919,6 +4917,7 @@ GpStatus WINGDIPAPI GdipMeasureCharacterRanges(GpGraphics* graphics, { GpStatus stat; int i; + LOGFONTW lfw; HFONT oldfont; struct measure_ranges_args args; HDC hdc, temp_hdc=NULL; @@ -4926,12 +4925,15 @@ GpStatus WINGDIPAPI GdipMeasureCharacterRanges(GpGraphics* graphics, TRACE("(%p %s %d %p %s %p %d %p)\n", graphics, debugstr_w(string), length, font, debugstr_rectf(layoutRect), stringFormat, regionCount, regions); - if (!(graphics && string && font && layoutRect && stringFormat && regions)) + if (!graphics || !string || !font || !layoutRect || !stringFormat || !regions) return InvalidParameter; if (regionCount < stringFormat->range_count) return InvalidParameter; + stat = GdipGetLogFontW((GpFont *)font, graphics, &lfw); + if (stat != Ok) return stat; + if(!graphics->hdc) { hdc = temp_hdc = CreateCompatibleDC(0); @@ -4943,7 +4945,7 @@ GpStatus WINGDIPAPI GdipMeasureCharacterRanges(GpGraphics* graphics, if (stringFormat->attr) TRACE("may be ignoring some format flags: attr %x\n", stringFormat->attr); - oldfont = SelectObject(hdc, CreateFontIndirectW(&font->lfw)); + oldfont = SelectObject(hdc, CreateFontIndirectW(&lfw)); for (i=0; irange_count; i++) { diff --git a/dlls/gdiplus/graphicspath.c b/dlls/gdiplus/graphicspath.c index d37512e..5da53b2 100644 --- a/dlls/gdiplus/graphicspath.c +++ b/dlls/gdiplus/graphicspath.c @@ -942,6 +942,7 @@ GpStatus WINGDIPAPI GdipAddPathString(GpPath* path, GDIPCONST WCHAR* string, INT { GpFont *font; GpStatus status; + LOGFONTW lfw; HANDLE hfont; HDC dc; GpPath *backup; @@ -956,7 +957,9 @@ GpStatus WINGDIPAPI GdipAddPathString(GpPath* path, GDIPCONST WCHAR* string, INT if (status != Ok) return status; - hfont = CreateFontIndirectW(&font->lfw); + status = GdipGetLogFontW((GpFont *)font, NULL, &lfw); + if (status != Ok) return status; + hfont = CreateFontIndirectW(&lfw); if (!hfont) { WARN("Failed to create font\n"); -- 1.7.10.1