Module: wine Branch: master Commit: 21dbe1c949af569daf0a4db4eef45e40fc780f0b URL: http://source.winehq.org/git/wine.git/?a=commit;h=21dbe1c949af569daf0a4db4ee...
Author: Sam Edwards CFSworks@gmail.com Date: Tue Apr 30 01:20:57 2013 -0600
gdi32: Clip font glyphs to fit within text metrics.
---
dlls/gdi32/freetype.c | 41 ++++++++++++++++++-------- dlls/gdi32/tests/font.c | 41 +++++++++++++++++++++++++++ dlls/gdi32/tests/wine_test.sfd | 60 +++++++++++++++++++++++++++++++++------ dlls/gdi32/tests/wine_test.ttf | Bin 1652 -> 1760 bytes 4 files changed, 119 insertions(+), 23 deletions(-)
diff --git a/dlls/gdi32/freetype.c b/dlls/gdi32/freetype.c index 30ab574..c30a358 100644 --- a/dlls/gdi32/freetype.c +++ b/dlls/gdi32/freetype.c @@ -538,6 +538,7 @@ static BOOL use_default_fallback = FALSE;
static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph); static BOOL get_outline_text_metrics(GdiFont *font); +static BOOL get_bitmap_text_metrics(GdiFont *font); static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm); static void remove_face_from_cache( Face *face );
@@ -5868,6 +5869,7 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format, static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)}; FT_Face ft_face = incoming_font->ft_face; GdiFont *font = incoming_font; + FT_Glyph_Metrics metrics; FT_UInt glyph_index; DWORD width, height, pitch, needed = 0; FT_Bitmap ft_bitmap; @@ -6019,6 +6021,22 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format, return GDI_ERROR; }
+ /* Some poorly-created fonts contain glyphs that exceed the boundaries set + * by the text metrics. The proper behavior is to clip the glyph metrics to + * fit within the maximums specified in the text metrics. */ + metrics = ft_face->glyph->metrics; + if(incoming_font->potm || get_outline_text_metrics(incoming_font) || + get_bitmap_text_metrics(incoming_font)) { + TEXTMETRICW *ptm = &incoming_font->potm->otmTextMetrics; + top = min( metrics.horiBearingY, ptm->tmAscent << 6 ); + bottom = max( metrics.horiBearingY - metrics.height, -(ptm->tmDescent << 6) ); + metrics.horiBearingY = top; + metrics.height = top - bottom; + + /* TODO: Are we supposed to clip the width as well...? */ + /* metrics.width = min( metrics.width, ptm->tmMaxCharWidth << 6 ); */ + } + if(FT_IS_SCALABLE(incoming_font->ft_face)) { TEXTMETRICW tm; if (get_text_metrics(incoming_font, &tm) && @@ -6026,7 +6044,7 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format, em_scale = MulDiv(incoming_font->ppem, 1 << 16, incoming_font->ft_face->units_per_EM); avgAdvance = pFT_MulFix(incoming_font->ntmAvgWidth, em_scale); if (avgAdvance && - (ft_face->glyph->metrics.horiAdvance+63) >> 6 == pFT_MulFix(incoming_font->ntmAvgWidth*2, em_scale)) + (metrics.horiAdvance+63) >> 6 == pFT_MulFix(incoming_font->ntmAvgWidth*2, em_scale)) TRACE("Fixed-pitch full-width character detected\n"); else avgAdvance = 0; /* cancel this feature */ @@ -6034,16 +6052,15 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format, }
if(!needsTransform) { - left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64; - right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64; + left = (INT)(metrics.horiBearingX) & -64; + right = (INT)((metrics.horiBearingX + metrics.width) + 63) & -64; if (!avgAdvance) - adv = (INT)(ft_face->glyph->metrics.horiAdvance + 63) >> 6; + adv = (INT)(metrics.horiAdvance + 63) >> 6; else adv = (INT)avgAdvance * 2;
- top = (ft_face->glyph->metrics.horiBearingY + 63) & -64; - bottom = (ft_face->glyph->metrics.horiBearingY - - ft_face->glyph->metrics.height) & -64; + top = (metrics.horiBearingY + 63) & -64; + bottom = (metrics.horiBearingY - metrics.height) & -64; lpgm->gmCellIncX = adv; lpgm->gmCellIncY = 0; } else { @@ -6054,10 +6071,8 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
for(xc = 0; xc < 2; xc++) { for(yc = 0; yc < 2; yc++) { - vec.x = (ft_face->glyph->metrics.horiBearingX + - xc * ft_face->glyph->metrics.width); - vec.y = ft_face->glyph->metrics.horiBearingY - - yc * ft_face->glyph->metrics.height; + vec.x = metrics.horiBearingX + xc * metrics.width; + vec.y = metrics.horiBearingY - yc * metrics.height; TRACE("Vec %ld,%ld\n", vec.x, vec.y); pFT_Vector_Transform(&vec, &transMat); if(xc == 0 && yc == 0) { @@ -6077,7 +6092,7 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format, top = (top + 63) & -64;
TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom); - vec.x = ft_face->glyph->metrics.horiAdvance; + vec.x = metrics.horiAdvance; vec.y = 0; pFT_Vector_Transform(&vec, &transMat); lpgm->gmCellIncY = -((vec.y+63) >> 6); @@ -6090,7 +6105,7 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format, lpgm->gmCellIncX = pFT_MulFix(vec.x, em_scale) * 2; }
- vec.x = ft_face->glyph->metrics.horiAdvance; + vec.x = metrics.horiAdvance; vec.y = 0; pFT_Vector_Transform(&vec, &transMatUnrotated); if (!avgAdvance || vec.y) diff --git a/dlls/gdi32/tests/font.c b/dlls/gdi32/tests/font.c index e5e7ff9..bc4e614 100644 --- a/dlls/gdi32/tests/font.c +++ b/dlls/gdi32/tests/font.c @@ -4561,6 +4561,46 @@ static void test_GetGlyphOutline_empty_contour(void) ReleaseDC(NULL, hdc); }
+static void test_GetGlyphOutline_metric_clipping(void) +{ + HDC hdc; + LOGFONTA lf; + HFONT hfont, hfont_prev; + GLYPHMETRICS gm; + TEXTMETRICA tm; + DWORD ret; + + memset(&lf, 0, sizeof(lf)); + lf.lfHeight = 72; + lstrcpyA(lf.lfFaceName, "wine_test"); + + SetLastError(0xdeadbeef); + hfont = CreateFontIndirectA(&lf); + ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError()); + + hdc = GetDC(NULL); + + hfont_prev = SelectObject(hdc, hfont); + ok(hfont_prev != NULL, "SelectObject failed\n"); + + SetLastError(0xdeadbeef); + ret = GetTextMetrics(hdc, &tm); + ok(ret, "GetTextMetrics error %u\n", GetLastError()); + + GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat); + ok(gm.gmptGlyphOrigin.y <= tm.tmAscent, + "Glyph top(%d) exceeds ascent(%d)\n", + gm.gmptGlyphOrigin.y, tm.tmAscent); + GetGlyphOutlineA(hdc, 'D', GGO_METRICS, &gm, 0, NULL, &mat); + ok(gm.gmptGlyphOrigin.y - gm.gmBlackBoxY >= -tm.tmDescent, + "Glyph bottom(%d) exceeds descent(%d)\n", + gm.gmptGlyphOrigin.y - gm.gmBlackBoxY, -tm.tmDescent); + + SelectObject(hdc, hfont_prev); + DeleteObject(hfont); + ReleaseDC(NULL, hdc); +} + static void test_CreateScalableFontResource(void) { char ttf_name[MAX_PATH]; @@ -4643,6 +4683,7 @@ static void test_CreateScalableFontResource(void) ok(ret, "font wine_test should be enumerated\n");
test_GetGlyphOutline_empty_contour(); + test_GetGlyphOutline_metric_clipping();
ret = pRemoveFontResourceExA(fot_name, FR_PRIVATE, 0); ok(!ret, "RemoveFontResourceEx() with not matching flags should fail\n"); diff --git a/dlls/gdi32/tests/wine_test.sfd b/dlls/gdi32/tests/wine_test.sfd index 5adf7cf..4c19377 100644 --- a/dlls/gdi32/tests/wine_test.sfd +++ b/dlls/gdi32/tests/wine_test.sfd @@ -20,7 +20,7 @@ OS2Version: 2 OS2_WeightWidthSlopeOnly: 0 OS2_UseTypoMetrics: 1 CreationTime: 1288336343 -ModificationTime: 1352483620 +ModificationTime: 1366465321 PfmFamily: 17 TTFWeight: 500 TTFWidth: 5 @@ -32,10 +32,10 @@ OS2TypoAOffset: 1 OS2TypoDescent: 0 OS2TypoDOffset: 1 OS2TypoLinegap: 184 -OS2WinAscent: 0 -OS2WinAOffset: 1 -OS2WinDescent: 0 -OS2WinDOffset: 1 +OS2WinAscent: 1638 +OS2WinAOffset: 0 +OS2WinDescent: 410 +OS2WinDOffset: 0 HheadAscent: 0 HheadAOffset: 1 HheadDescent: 0 @@ -78,15 +78,17 @@ ShortTable: maxp 16 0 EndShort LangName: 1033 "" "" "" "Wine : wine_test : 4-11-2010" -GaspTable: 1 65535 2 +GaspTable: 1 65535 2 0 Encoding: UnicodeBmp UnicodeInterp: none NameList: Adobe Glyph List DisplaySize: -24 AntiAlias: 1 FitToEm: 1 -WinInfo: 65 65 19 -BeginChars: 65539 5 +WinInfo: 48 16 4 +BeginPrivate: 0 +EndPrivate +BeginChars: 65539 7
StartChar: .notdef Encoding: 65536 -1 0 @@ -178,10 +180,10 @@ LayerCount: 2 EndChar
StartChar: dieresis -Encoding: 168 168 0 +Encoding: 168 168 4 Width: 1000 VWidth: 0 -Flags: HW +Flags: W LayerCount: 2 Fore SplineSet @@ -201,5 +203,43 @@ SplineSet 310.707 834.805 310.707 834.805 254.492 773.213 c 1,12,13 EndSplineSet EndChar + +StartChar: A +Encoding: 65 65 5 +Width: 1000 +VWidth: 0 +Flags: WO +LayerCount: 2 +Fore +SplineSet +459 1258 m 29,0,-1 + 462 1639 l 5,1,-1 + 389 1638 l 5,2,-1 + 492 1815 l 5,3,-1 + 609 1638.5 l 5,4,-1 + 531 1637.5 l 5,5,-1 + 523 1258 l 5,6,-1 + 459 1258 l 29,0,-1 +EndSplineSet +EndChar + +StartChar: D +Encoding: 68 68 6 +Width: 1000 +VWidth: 0 +Flags: WO +LayerCount: 2 +Fore +SplineSet +461 -30.7998 m 29,0,-1 + 464 -411.8 l 5,1,-1 + 391 -410.8 l 5,2,-1 + 494 -587.8 l 5,3,-1 + 611 -411.3 l 5,4,-1 + 533 -410.3 l 5,5,-1 + 525 -30.7998 l 5,6,-1 + 461 -30.7998 l 29,0,-1 +EndSplineSet +EndChar EndChars EndSplineFont diff --git a/dlls/gdi32/tests/wine_test.ttf b/dlls/gdi32/tests/wine_test.ttf index 1e546eb..0868802 100644 Binary files a/dlls/gdi32/tests/wine_test.ttf and b/dlls/gdi32/tests/wine_test.ttf differ