gdi32: Ensure a fixed-pitch full-width character has double advance of a half-width character.

This commit is contained in:
Akihiro Sagawa 2013-02-07 22:13:04 +09:00 committed by Alexandre Julliard
parent 68d72f4792
commit 9aa8300f99
2 changed files with 122 additions and 3 deletions

View File

@ -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;

View File

@ -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);
}