diff --git a/dlls/gdi32/freetype.c b/dlls/gdi32/freetype.c index 40cf0801ec8..b977b0d1fa2 100644 --- a/dlls/gdi32/freetype.c +++ b/dlls/gdi32/freetype.c @@ -5821,6 +5821,7 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format, BOOL needsTransform = FALSE; BOOL tategaki = (font->GSUB_Table != NULL); UINT original_index; + FT_Fixed avgAdvance = 0; TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm, buflen, buf, lpmat); @@ -5957,10 +5958,26 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format, return GDI_ERROR; } + if(FT_IS_SCALABLE(incoming_font->ft_face)) { + TEXTMETRICW tm; + if (get_text_metrics(incoming_font, &tm) && + !(tm.tmPitchAndFamily & TMPF_FIXED_PITCH)) { + avgAdvance = pFT_MulFix(incoming_font->ntmAvgWidth, + incoming_font->ft_face->size->metrics.x_scale); + if (avgAdvance && (ft_face->glyph->metrics.horiAdvance+63) >> 6 == (avgAdvance*2+63) >> 6) + TRACE("Fixed-pitch full-width character detected\n"); + else + avgAdvance = 0; /* cancel this feature */ + } + } + if(!needsTransform) { left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64; right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64; - adv = (INT)(ft_face->glyph->metrics.horiAdvance + 63) >> 6; + if (!avgAdvance) + adv = (INT)(ft_face->glyph->metrics.horiAdvance + 63) >> 6; + else + adv = (INT)((avgAdvance + 32) >> 6) * 2; top = (ft_face->glyph->metrics.horiBearingY + 63) & -64; bottom = (ft_face->glyph->metrics.horiBearingY - @@ -6001,13 +6018,27 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format, vec.x = ft_face->glyph->metrics.horiAdvance; vec.y = 0; pFT_Vector_Transform(&vec, &transMat); - lpgm->gmCellIncX = (vec.x+63) >> 6; lpgm->gmCellIncY = -((vec.y+63) >> 6); + if (!avgAdvance || vec.y) + lpgm->gmCellIncX = (vec.x+63) >> 6; + else { + vec.x = avgAdvance; + vec.y = 0; + pFT_Vector_Transform(&vec, &transMat); + lpgm->gmCellIncX = ((vec.x+32) >> 6) * 2; + } vec.x = ft_face->glyph->metrics.horiAdvance; vec.y = 0; pFT_Vector_Transform(&vec, &transMatUnrotated); - adv = (vec.x+63) >> 6; + if (!avgAdvance || vec.y) + adv = (vec.x+63) >> 6; + else { + vec.x = avgAdvance; + vec.y = 0; + pFT_Vector_Transform(&vec, &transMatUnrotated); + adv = ((vec.x+32) >> 6) * 2; + } } lpgm->gmBlackBoxX = (right - left) >> 6; diff --git a/dlls/gdi32/tests/font.c b/dlls/gdi32/tests/font.c index f234b620bc2..943f584271a 100644 --- a/dlls/gdi32/tests/font.c +++ b/dlls/gdi32/tests/font.c @@ -3552,6 +3552,38 @@ todo_wine DeleteDC(hdc); } +static int CALLBACK create_fixed_pitch_font_proc(const LOGFONT *lpelfe, + const TEXTMETRIC *lpntme, + DWORD FontType, LPARAM lParam) +{ + const NEWTEXTMETRICEX *lpntmex = (const NEWTEXTMETRICEX *)lpntme; + CHARSETINFO csi; + LOGFONT lf = *lpelfe; + HFONT hfont; + + /* skip bitmap, proportional or vertical font */ + if ((FontType & TRUETYPE_FONTTYPE) == 0 || + (lf.lfPitchAndFamily & 0xf) != FIXED_PITCH || + lf.lfFaceName[0] == '@') + return 1; + + /* skip linked font */ + if (!TranslateCharsetInfo((DWORD*)(INT_PTR)lpelfe->lfCharSet, &csi, TCI_SRCCHARSET) || + (lpntmex->ntmFontSig.fsCsb[0] & csi.fs.fsCsb[0]) == 0) + return 1; + + /* test with an odd height */ + lf.lfHeight = -19; + lf.lfWidth = 0; + hfont = CreateFontIndirect(&lf); + if (hfont) + { + *(HFONT *)lParam = hfont; + return 0; + } + return 1; +} + static void test_GetGlyphOutline(void) { HDC hdc; @@ -3640,6 +3672,8 @@ static void test_GetGlyphOutline(void) for (i = 0; i < sizeof c / sizeof c[0]; ++i) { + static const MAT2 rotate_mat = {{0, 0}, {0, -1}, {0, 1}, {0, 0}}; + lf.lfFaceName[0] = '\0'; lf.lfCharSet = c[i].cs; lf.lfPitchAndFamily = 0; @@ -3670,6 +3704,60 @@ static void test_GetGlyphOutline(void) ret2 = GetGlyphOutlineW(hdc, c[i].w, GGO_BITMAP, &gm2, 0, NULL, &mat); ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0, "%d %d\n", ret, ret2); + if (EnumFontFamiliesEx(hdc, &lf, create_fixed_pitch_font_proc, (LPARAM)&hfont, 0)) + { + skip("Fixed-pitch TrueType font for charset %u is not available\n", c[i].cs); + continue; + } + DeleteObject(SelectObject(hdc, hfont)); + if (c[i].a <= 0xff) + { + DeleteObject(SelectObject(hdc, old_hfont)); + continue; + } + + ret = GetObject(hfont, sizeof lf, &lf); + ok(ret > 0, "GetObject error %u\n", GetLastError()); + + ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat); + ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError()); + ret = GetGlyphOutlineA(hdc, c[i].a, GGO_METRICS, &gm2, 0, NULL, &mat); + ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError()); + trace("Tests with height=%d,half=%d,full=%d,face=%s,charset=%d\n", + -lf.lfHeight, gm.gmCellIncX, gm2.gmCellIncX, lf.lfFaceName, lf.lfCharSet); + ok(gm2.gmCellIncX == gm.gmCellIncX * 2 || broken(gm2.gmCellIncX == -lf.lfHeight), + "expected %d, got %d (%s:%d)\n", + gm.gmCellIncX * 2, gm2.gmCellIncX, lf.lfFaceName, lf.lfCharSet); + + ret = GetGlyphOutlineA(hdc, c[i].a, GGO_METRICS, &gm2, 0, NULL, &rotate_mat); + ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError()); + ok(gm2.gmCellIncY == -lf.lfHeight, + "expected %d, got %d (%s:%d)\n", + -lf.lfHeight, gm2.gmCellIncY, lf.lfFaceName, lf.lfCharSet); + + lf.lfItalic = TRUE; + hfont = CreateFontIndirect(&lf); + ok(hfont != NULL, "CreateFontIndirect error %u\n", GetLastError()); + DeleteObject(SelectObject(hdc, hfont)); + ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat); + ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError()); + ret = GetGlyphOutlineA(hdc, c[i].a, GGO_METRICS, &gm2, 0, NULL, &mat); + ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError()); + ok(gm2.gmCellIncX == gm.gmCellIncX * 2 || broken(gm2.gmCellIncX == -lf.lfHeight), + "expected %d, got %d (%s:%d)\n", + gm.gmCellIncX * 2, gm2.gmCellIncX, lf.lfFaceName, lf.lfCharSet); + + lf.lfItalic = FALSE; + lf.lfEscapement = lf.lfOrientation = 2700; + hfont = CreateFontIndirect(&lf); + ok(hfont != NULL, "CreateFontIndirect error %u\n", GetLastError()); + DeleteObject(SelectObject(hdc, hfont)); + ret = GetGlyphOutlineA(hdc, c[i].a, GGO_METRICS, &gm2, 0, NULL, &mat); + ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError()); + ok(gm2.gmCellIncY == -lf.lfHeight, + "expected %d, got %d (%s:%d)\n", + -lf.lfHeight, gm2.gmCellIncY, lf.lfFaceName, lf.lfCharSet); + hfont = SelectObject(hdc, old_hfont); DeleteObject(hfont); }