From c626528a91505292487a4a3b72721122dd68f951 Mon Sep 17 00:00:00 2001 From: Dmitry Timoshkov Date: Fri, 11 May 2012 19:20:31 +0900 Subject: [PATCH] gdiplus: Use OUTLINETEXTMETRIC instead of LOGFONT to store GpFont metrics. --- dlls/gdiplus/font.c | 207 +++++++++++++++------------------ dlls/gdiplus/gdiplus_private.h | 7 +- 2 files changed, 99 insertions(+), 115 deletions(-) diff --git a/dlls/gdiplus/font.c b/dlls/gdiplus/font.c index 5b57ec6c47b..b08323ef2db 100644 --- a/dlls/gdiplus/font.c +++ b/dlls/gdiplus/font.c @@ -39,37 +39,44 @@ static const REAL inch_per_point = 1.0/72.0; static GpFontCollection installedFontCollection = {0}; -static inline REAL get_dpi (void) +static inline LONG get_dpi(void) { - REAL dpi; - GpGraphics *graphics; + LONG dpi; HDC hdc = GetDC(0); - GdipCreateFromHDC (hdc, &graphics); - GdipGetDpiX(graphics, &dpi); - GdipDeleteGraphics(graphics); + dpi = GetDeviceCaps(hdc, LOGPIXELSY); ReleaseDC (0, hdc); return dpi; } -static inline REAL point_to_pixel (REAL point) +static LONG em_size_to_pixel(REAL em_size, Unit unit, LONG dpi) { - return point * get_dpi() * inch_per_point; -} + switch (unit) + { + default: + FIXME("Unhandled unit type: %d\n", unit); + return 0; -static inline REAL inch_to_pixel (REAL inch) -{ - return inch * get_dpi(); -} - -static inline REAL document_to_pixel (REAL doc) -{ - return doc * (get_dpi() / 300.0); /* Per MSDN */ -} - -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 +103,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); + memset(&lfw, 0, sizeof(lfw)); + + stat = GdipGetFamilyName(fontFamily, lfw.lfFaceName, LANG_NEUTRAL); if (stat != Ok) return stat; + + lfw.lfHeight = -em_size_to_pixel(emSize, unit, get_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); + + if (!ret) return NotTrueTypeFont; + *font = GdipAlloc(sizeof(GpFont)); - - otm = &fontFamily->otm; - lfw = &((*font)->lfw); - ZeroMemory(&(*lfw), 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); - - 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 = (*font)->pixel_size * -1; - - lfw->lfWeight = style & FontStyleBold ? FW_BOLD : FW_REGULAR; - lfw->lfItalic = style & FontStyleItalic; - lfw->lfUnderline = style & FontStyleUnderline; - lfw->lfStrikeOut = style & FontStyleStrikeout; + 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,43 +163,31 @@ 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); - - (*font)->lfw.lfHeight = -(textmet.tmHeight-textmet.tmInternalLeading); - (*font)->lfw.lfWeight = textmet.tmWeight; - (*font)->lfw.lfCharSet = textmet.tmCharSet; - - (*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; - + otm.otmSize = sizeof(otm); + ret = GetOutlineTextMetricsW(hdc, otm.otmSize, &otm); SelectObject(hdc, oldfont); DeleteObject(hfont); + if (!ret) return NotTrueTypeFont; + + *font = GdipAlloc(sizeof(GpFont)); + if (!*font) return OutOfMemory; + + (*font)->unit = UnitWorld; + (*font)->emSize = otm.otmTextMetrics.tmAscent; + (*font)->otm = otm; + stat = GdipCreateFontFamilyFromName(logfont->lfFaceName, NULL, &(*font)->family); if (stat != Ok) { @@ -333,7 +306,7 @@ GpStatus WINGDIPAPI GdipGetFontSize(GpFont *font, REAL *size) 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; } @@ -358,15 +331,15 @@ GpStatus WINGDIPAPI GdipGetFontStyle(GpFont *font, INT *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; @@ -390,7 +363,7 @@ GpStatus WINGDIPAPI GdipGetFontUnit(GpFont *font, Unit *unit) 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 +403,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; } @@ -549,7 +536,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; } @@ -664,13 +651,13 @@ GpStatus WINGDIPAPI GdipCloneFontFamily(GpFontFamily* FontFamily, GpFontFamily** { 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); diff --git a/dlls/gdiplus/gdiplus_private.h b/dlls/gdiplus/gdiplus_private.h index 3676358264d..5267d74cb9f 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; };