Akihiro Sagawa : gdi32: Ensure a fixed-pitch full-width character has double advance of a half-width character .
Alexandre Julliard
julliard at winehq.org
Thu Feb 7 14:07:24 CST 2013
Module: wine
Branch: master
Commit: 9aa8300f99965d2b66eb7016ff3e44a3d517ba8b
URL: http://source.winehq.org/git/wine.git/?a=commit;h=9aa8300f99965d2b66eb7016ff3e44a3d517ba8b
Author: Akihiro Sagawa <sagawa.aki at gmail.com>
Date: Thu Feb 7 22:13:04 2013 +0900
gdi32: Ensure a fixed-pitch full-width character has double advance of a half-width character.
---
dlls/gdi32/freetype.c | 37 ++++++++++++++++++--
dlls/gdi32/tests/font.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 122 insertions(+), 3 deletions(-)
diff --git a/dlls/gdi32/freetype.c b/dlls/gdi32/freetype.c
index 40cf080..b977b0d 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 f234b62..943f584 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);
}
More information about the wine-cvs
mailing list