This patch reflects the metrics changes in the subpixel rendering. The problem that arises from this patch is corrected in the following patches. I will correct the problem and remove the todo_wine again.
Signed-off-by: Byeongsik Jeon bsjeon@hanmail.net --- dlls/gdi32/freetype.c | 156 +++++++++++++++++++++------------------- dlls/gdi32/tests/font.c | 7 ++ 2 files changed, 89 insertions(+), 74 deletions(-)
diff --git a/dlls/gdi32/freetype.c b/dlls/gdi32/freetype.c index d0480333ce..02f7455619 100644 --- a/dlls/gdi32/freetype.c +++ b/dlls/gdi32/freetype.c @@ -6884,23 +6884,18 @@ static FT_Vector get_advance_metric(GdiFont *incoming_font, GdiFont *font, return adv; }
-static FT_BBox compute_gm_abc_metrics( GdiFont *incoming_font, GdiFont *font, - const FT_Glyph_Metrics *metrics, - BOOL tategaki, BOOL vertical_metrics, BOOL needsTransform, - const FT_Matrix *transMat, - const FT_Matrix *transMatTategaki, - const FT_Matrix *transMatUnrotated, - GLYPHMETRICS *gm, ABC *abc ) +static void compute_gm_abc_metrics( GdiFont *incoming_font, GdiFont *font, + FT_BBox bbox, const FT_Glyph_Metrics *metrics, + BOOL tategaki, BOOL vertical_metrics, BOOL needsTransform, + const FT_Matrix *transMat, + const FT_Matrix *transMatTategaki, + const FT_Matrix *transMatUnrotated, + GLYPHMETRICS *gm, ABC *abc ) { - FT_BBox bbox = { 0, 0, 0, 0 }; FT_Vector adv, vec, origin;
if (!needsTransform) { - bbox.xMin = (metrics->horiBearingX) & -64; - bbox.xMax = (metrics->horiBearingX + metrics->width + 63) & -64; - bbox.yMax = (metrics->horiBearingY + 63) & -64; - bbox.yMin = (metrics->horiBearingY - metrics->height) & -64; adv = get_advance_metric( incoming_font, font, metrics, NULL, vertical_metrics ); gm->gmCellIncX = adv.x >> 6; gm->gmCellIncY = 0; @@ -6911,37 +6906,8 @@ static FT_BBox compute_gm_abc_metrics( GdiFont *incoming_font, GdiFont *font, } else { - INT xc, yc; FT_Pos lsb;
- for (xc = 0; xc < 2; xc++) - { - for (yc = 0; yc < 2; yc++) - { - 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, transMatTategaki ); - if (xc == 0 && yc == 0) - { - bbox.xMin = bbox.xMax = vec.x; - bbox.yMin = bbox.yMax = vec.y; - } - else - { - if (vec.x < bbox.xMin) bbox.xMin = vec.x; - else if (vec.x > bbox.xMax) bbox.xMax = vec.x; - if (vec.y < bbox.yMin) bbox.yMin = vec.y; - else if (vec.y > bbox.yMax) bbox.yMax = vec.y; - } - } - } - bbox.xMin = bbox.xMin & -64; - bbox.xMax = (bbox.xMax + 63) & -64; - bbox.yMax = (bbox.yMax + 63) & -64; - bbox.yMin = bbox.yMin & -64; - TRACE( "transformed box: (%ld,%ld - %ld,%ld)\n", bbox.xMin, bbox.yMax, bbox.xMax, bbox.yMin ); - if (tategaki && (font->potm || get_outline_text_metrics( font ))) { if (vertical_metrics) @@ -6997,6 +6963,53 @@ static FT_BBox compute_gm_abc_metrics( GdiFont *incoming_font, GdiFont *font, TRACE( "gm: %u,%u,%s,%d,%d\n", gm->gmBlackBoxX, gm->gmBlackBoxY, wine_dbgstr_point(&gm->gmptGlyphOrigin), gm->gmCellIncX, gm->gmCellIncY ); TRACE( "abc: %d,%u,%d\n", abc->abcA, abc->abcB, abc->abcC ); +} + +static FT_BBox get_transformed_bbox( const FT_Glyph_Metrics *metrics, + BOOL needsTransform, const FT_Matrix *transMatTategaki ) +{ + FT_BBox bbox = { 0, 0, 0, 0 }; + + if (!needsTransform) + { + bbox.xMin = (metrics->horiBearingX) & -64; + bbox.xMax = (metrics->horiBearingX + metrics->width + 63) & -64; + bbox.yMax = (metrics->horiBearingY + 63) & -64; + bbox.yMin = (metrics->horiBearingY - metrics->height) & -64; + } + else + { + FT_Vector vec; + INT xc, yc; + + for (xc = 0; xc < 2; xc++) + { + for (yc = 0; yc < 2; yc++) + { + 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, transMatTategaki ); + if (xc == 0 && yc == 0) + { + bbox.xMin = bbox.xMax = vec.x; + bbox.yMin = bbox.yMax = vec.y; + } + else + { + if (vec.x < bbox.xMin) bbox.xMin = vec.x; + else if (vec.x > bbox.xMax) bbox.xMax = vec.x; + if (vec.y < bbox.yMin) bbox.yMin = vec.y; + else if (vec.y > bbox.yMax) bbox.yMax = vec.y; + } + } + } + bbox.xMin = bbox.xMin & -64; + bbox.xMax = (bbox.xMax + 63) & -64; + bbox.yMax = (bbox.yMax + 63) & -64; + bbox.yMin = bbox.yMin & -64; + TRACE( "transformed box: (%ld,%ld - %ld,%ld)\n", bbox.xMin, bbox.yMax, bbox.xMax, bbox.yMin ); + }
return bbox; } @@ -7198,12 +7211,12 @@ static unsigned int get_bezier_glyph_outline(FT_Outline *outline, unsigned int b return needed; }
-static DWORD get_ggo_glyph_from_outline( FT_GlyphSlot glyph, UINT format, FT_BBox bbox, GLYPHMETRICS *gm, +static DWORD get_ggo_glyph_from_outline( FT_GlyphSlot glyph, UINT format, FT_BBox *bbox, BOOL needsTransform, FT_Matrix *transMatTategaki, DWORD buflen, BYTE *buf ) { - DWORD width = (bbox.xMax - bbox.xMin) >> 6; - DWORD height = (bbox.yMax - bbox.yMin) >> 6; + DWORD width = (bbox->xMax - bbox->xMin) >> 6; + DWORD height = (bbox->yMax - bbox->yMin) >> 6; FT_Outline *outline = &glyph->outline; FT_Bitmap ft_bitmap; DWORD max_level, pitch, needed = 0; @@ -7226,7 +7239,7 @@ static DWORD get_ggo_glyph_from_outline( FT_GlyphSlot glyph, UINT format, FT_BBo
if (needsTransform) pFT_Outline_Transform( outline, transMatTategaki ); - pFT_Outline_Translate( outline, -bbox.xMin, -bbox.yMin ); + pFT_Outline_Translate( outline, -bbox->xMin, -bbox->yMin );
/* Note: FreeType will only set 'black' bits for us. */ memset( buf, 0, needed ); @@ -7252,7 +7265,7 @@ static DWORD get_ggo_glyph_from_outline( FT_GlyphSlot glyph, UINT format, FT_BBo
if (needsTransform) pFT_Outline_Transform( outline, transMatTategaki ); - pFT_Outline_Translate( outline, -bbox.xMin, -bbox.yMin ); + pFT_Outline_Translate( outline, -bbox->xMin, -bbox->yMin );
memset( ft_bitmap.buffer, 0, buflen ); pFT_Outline_Get_Bitmap( library, outline, &ft_bitmap ); @@ -7296,19 +7309,17 @@ static DWORD get_ggo_glyph_from_outline( FT_GlyphSlot glyph, UINT format, FT_BBo
if (render_mode == FT_RENDER_MODE_LCD) { - gm->gmBlackBoxX += 2; - gm->gmptGlyphOrigin.x -= 1; - bbox.xMin -= (1 << 6); + bbox->xMin -= (1 << 6); + bbox->xMax += (1 << 6); } else { - gm->gmBlackBoxY += 2; - gm->gmptGlyphOrigin.y += 1; - bbox.yMax += (1 << 6); + bbox->yMax += (1 << 6); + bbox->yMin -= (1 << 6); }
- width = gm->gmBlackBoxX; - height = gm->gmBlackBoxY; + width = (bbox->xMax - bbox->xMin) >> 6; + height = (bbox->yMax - bbox->yMin) >> 6; pitch = width * 4; needed = pitch * height;
@@ -7336,7 +7347,7 @@ static DWORD get_ggo_glyph_from_outline( FT_GlyphSlot glyph, UINT format, FT_BBo hmul = render_mode == FT_RENDER_MODE_LCD ? 3 : 1; vmul = render_mode == FT_RENDER_MODE_LCD ? 1 : 3;
- x_shift = glyph->bitmap_left - (bbox.xMin >> 6); + x_shift = glyph->bitmap_left - (bbox->xMin >> 6); if (x_shift < 0) { src += hmul * -x_shift; @@ -7348,7 +7359,7 @@ static DWORD get_ggo_glyph_from_outline( FT_GlyphSlot glyph, UINT format, FT_BBo width -= x_shift; }
- y_shift = (bbox.yMax >> 6) - glyph->bitmap_top; + y_shift = (bbox->yMax >> 6) - glyph->bitmap_top; if (y_shift < 0) { src += src_pitch * vmul * -y_shift; @@ -7660,20 +7671,7 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format, /* metrics.width = min( metrics.width, ptm->tmMaxCharWidth << 6 ); */ }
- bbox = compute_gm_abc_metrics( incoming_font, font, &metrics, - tategaki, vertical_metrics, needsTransform, - &transMat, &transMatTategaki, &transMatUnrotated, - &gm, abc ); - - if ((ggo_metrics || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) && - is_identity_MAT2(lpmat)) /* don't cache custom transforms */ - cache_gm_abc_metrics( font, glyph_index, &gm, abc ); - - if (ggo_metrics) - { - *lpgm = gm; - return 1; /* FIXME */ - } + bbox = get_transformed_bbox( &metrics, needsTransform, &transMatTategaki );
switch (ft_face->glyph->format) { @@ -7682,7 +7680,7 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format, buflen, buf ); break; case FT_GLYPH_FORMAT_OUTLINE: - needed = get_ggo_glyph_from_outline( ft_face->glyph, format, bbox, &gm, + needed = get_ggo_glyph_from_outline( ft_face->glyph, format, &bbox, needsTransform, &transMatTategaki, buflen, buf ); break; @@ -7690,10 +7688,20 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format, FIXME("loaded glyph format %x\n", ft_face->glyph->format); return GDI_ERROR; } - if (needed == GDI_ERROR) return GDI_ERROR;
- *lpgm = gm; - return needed; + compute_gm_abc_metrics( incoming_font, font, bbox, &metrics, + tategaki, vertical_metrics, needsTransform, + &transMat, &transMatTategaki, &transMatUnrotated, + &gm, abc ); + + if ((ggo_metrics || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) && + is_identity_MAT2(lpmat)) /* don't cache custom transforms */ + cache_gm_abc_metrics( font, glyph_index, &gm, abc ); + + if (ggo_metrics || needed != GDI_ERROR) + *lpgm = gm; + + return ggo_metrics ? 1 : needed; /* FIXME: GGO_METRICS return value? */ }
static BOOL get_bitmap_text_metrics(GdiFont *font) diff --git a/dlls/gdi32/tests/font.c b/dlls/gdi32/tests/font.c index 67e8941b5e..f8762eca56 100644 --- a/dlls/gdi32/tests/font.c +++ b/dlls/gdi32/tests/font.c @@ -1335,8 +1335,11 @@ static void test_GetCharABCWidths(void) /* 3) compare ABC results */ ok(match_off_by_1(abcw[0].abcA, abc[0].abcA, FALSE), "got %d, expected %d (A)\n", abc[0].abcA, abcw[0].abcA); + todo_wine ok(match_off_by_1(abcw[0].abcB, abc[0].abcB, FALSE), "got %d, expected %d (B)\n", abc[0].abcB, abcw[0].abcB); + ok(match_off_by_n(abcw[0].abcB, abc[0].abcB, 2), + "got %d, expected %d (B)\n", abc[0].abcB, abcw[0].abcB); ok(match_off_by_1(abcw[0].abcC, abc[0].abcC, FALSE), "got %d, expected %d (C)\n", abc[0].abcC, abcw[0].abcC);
@@ -1382,9 +1385,11 @@ static void test_GetCharABCWidths(void) ret = GetCharABCWidthsA(hdc, code, code, abc); ok(ret, "GetCharABCWidthsA should have succeeded at width %d\n", i);
+ todo_wine ok(abc[0].abcA == gm.gmptGlyphOrigin.x, "abcA(%d) and gmptGlyphOrigin.x(%d) values are different at width %d\n", abc[0].abcA, gm.gmptGlyphOrigin.x, i); + todo_wine ok(abc[0].abcB == gm.gmBlackBoxX, "abcB(%d) and gmBlackBoxX(%d) values are different at width %d\n", abc[0].abcB, gm.gmBlackBoxX, i); @@ -6134,8 +6139,10 @@ static void check_vertical_metrics(const char *face) ok(ret != GDI_ERROR, "GetGlyphOutlineW failed\n"); ret = GetCharABCWidthsW(hdc, code, code, &vabc); ok(ret, "GetCharABCWidthsW failed\n"); + todo_wine ok(vabc.abcA == vgm.gmptGlyphOrigin.x, "expected %d, got %d\n", vabc.abcA, vgm.gmptGlyphOrigin.x); + todo_wine ok(vabc.abcB == vgm.gmBlackBoxX, "expected %d, got %d\n", vabc.abcB, vgm.gmBlackBoxX); ok(vabc.abcA + vabc.abcB + vabc.abcC == vgm.gmCellIncX,