Wine-bug: https://bugs.winehq.org/show_bug.cgi?id=46512 Signed-off-by: Byeongsik Jeon bsjeon@hanmail.net --- [PATCH 1,2,3,5] does not actually change. Each additional function can be further refactored, but at this point, it has kept the existing code. In my personal git branch, I am modifying other issues, and this structural change seems appropriate.
[PATCH 4,7] are a relatively minor issue correction.
[PATCH 6,8-12] are an additional patches associated with Wine-bug#46512.
dlls/gdi32/freetype.c | 235 ++++++++++++++++++++++-------------------- 1 file changed, 126 insertions(+), 109 deletions(-)
diff --git a/dlls/gdi32/freetype.c b/dlls/gdi32/freetype.c index 999b921b9d..4ae6cdd29f 100644 --- a/dlls/gdi32/freetype.c +++ b/dlls/gdi32/freetype.c @@ -6598,6 +6598,130 @@ static inline FT_Vector normalize_vector(FT_Vector *vec) return out; }
+static BOOL get_transform_matrix( GdiFont *font, BOOL tategaki, const MAT2 *lpmat, + FT_Matrix *transMat, FT_Matrix *transMatTategaki, + FT_Matrix *transMatUnrotated ) +{ + double widthRatio; + BOOL needsTransform = FALSE; + + /* Scaling factor */ + if (font->aveWidth) + { + TEXTMETRICW tm; + + get_text_metrics(font, &tm); + + widthRatio = (double)font->aveWidth; + widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth; + } + else + widthRatio = font->scale_y; + + /* Scaling transform */ + if (widthRatio != 1.0 || font->scale_y != 1.0) + { + FT_Matrix scaleMat; + scaleMat.xx = FT_FixedFromFloat( widthRatio ); + scaleMat.xy = 0; + scaleMat.yx = 0; + scaleMat.yy = FT_FixedFromFloat( font->scale_y ); + + pFT_Matrix_Multiply( &scaleMat, transMat ); + needsTransform = TRUE; + } + + /* Slant transform */ + if (font->fake_italic) + { + FT_Matrix slantMat; + slantMat.xx = (1 << 16); + slantMat.xy = (1 << 16) >> 2; + slantMat.yx = 0; + slantMat.yy = (1 << 16); + + pFT_Matrix_Multiply( &slantMat, transMat ); + needsTransform = TRUE; + } + + /* Rotation transform */ + *transMatUnrotated = *transMat; + *transMatTategaki = *transMat; + if (font->orientation || tategaki) + { + FT_Matrix rotationMat; + FT_Matrix taterotationMat; + FT_Vector vecAngle; + FT_Angle angle; + + double orient = font->orientation / 10.0; + double tate_orient = 0.f; + + if (tategaki) + tate_orient = ((font->orientation + 900) % 3600) / 10.0; + else + tate_orient = font->orientation / 10.0; + + if (orient) + { + angle = FT_FixedFromFloat( orient ); + pFT_Vector_Unit( &vecAngle, angle ); + rotationMat.xx = vecAngle.x; + rotationMat.xy = -vecAngle.y; + rotationMat.yx = -rotationMat.xy; + rotationMat.yy = rotationMat.xx; + + pFT_Matrix_Multiply( &rotationMat, transMat ); + } + + if (tate_orient) + { + angle = FT_FixedFromFloat( tate_orient ); + pFT_Vector_Unit( &vecAngle, angle ); + taterotationMat.xx = vecAngle.x; + taterotationMat.xy = -vecAngle.y; + taterotationMat.yx = -taterotationMat.xy; + taterotationMat.yy = taterotationMat.xx; + + pFT_Matrix_Multiply( &taterotationMat, transMatTategaki ); + } + + needsTransform = TRUE; + } + + /* World transform */ + if (!is_identity_FMAT2( &font->font_desc.matrix )) + { + FT_Matrix worldMat; + worldMat.xx = FT_FixedFromFloat( font->font_desc.matrix.eM11 ); + worldMat.xy = -FT_FixedFromFloat( font->font_desc.matrix.eM21 ); + worldMat.yx = -FT_FixedFromFloat( font->font_desc.matrix.eM12 ); + worldMat.yy = FT_FixedFromFloat( font->font_desc.matrix.eM22 ); + + pFT_Matrix_Multiply( &worldMat, transMat ); + pFT_Matrix_Multiply( &worldMat, transMatUnrotated ); + pFT_Matrix_Multiply( &worldMat, transMatTategaki ); + needsTransform = TRUE; + } + + /* Extra transformation specified by caller */ + if (!is_identity_MAT2( lpmat )) + { + FT_Matrix extraMat; + extraMat.xx = FT_FixedFromFIXED( lpmat->eM11 ); + extraMat.xy = FT_FixedFromFIXED( lpmat->eM21 ); + extraMat.yx = FT_FixedFromFIXED( lpmat->eM12 ); + extraMat.yy = FT_FixedFromFIXED( lpmat->eM22 ); + + pFT_Matrix_Multiply( &extraMat, transMat ); + pFT_Matrix_Multiply( &extraMat, transMatUnrotated ); + pFT_Matrix_Multiply( &extraMat, transMatTategaki ); + needsTransform = TRUE; + } + + return needsTransform; +} + static BOOL get_bold_glyph_outline(FT_GlyphSlot glyph, LONG ppem, FT_Glyph_Metrics *metrics) { FT_Error err; @@ -6953,9 +7077,7 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format, INT left, right, top = 0, bottom = 0; FT_Vector adv; INT origin_x = 0, origin_y = 0; - FT_Angle angle = 0; FT_Int load_flags = get_load_flags(format, incoming_font); - double widthRatio = 1.0; FT_Matrix transMat = identityMat; FT_Matrix transMatUnrotated; FT_Matrix transMatTategaki; @@ -7015,113 +7137,8 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format, if (!font->gm[original_index / GM_BLOCK_SIZE]) font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
- /* Scaling factor */ - if (font->aveWidth) - { - TEXTMETRICW tm; - - get_text_metrics(font, &tm); - - widthRatio = (double)font->aveWidth; - widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth; - } - else - widthRatio = font->scale_y; - - /* Scaling transform */ - if (widthRatio != 1.0 || font->scale_y != 1.0) - { - FT_Matrix scaleMat; - scaleMat.xx = FT_FixedFromFloat(widthRatio); - scaleMat.xy = 0; - scaleMat.yx = 0; - scaleMat.yy = FT_FixedFromFloat(font->scale_y); - - pFT_Matrix_Multiply(&scaleMat, &transMat); - needsTransform = TRUE; - } - - /* Slant transform */ - if (font->fake_italic) { - FT_Matrix slantMat; - - slantMat.xx = (1 << 16); - slantMat.xy = ((1 << 16) >> 2); - slantMat.yx = 0; - slantMat.yy = (1 << 16); - pFT_Matrix_Multiply(&slantMat, &transMat); - needsTransform = TRUE; - } - - /* Rotation transform */ - transMatUnrotated = transMat; - transMatTategaki = transMat; - if(font->orientation || tategaki) { - FT_Matrix rotationMat; - FT_Matrix taterotationMat; - FT_Vector vecAngle; - - double orient = font->orientation / 10.0; - double tate_orient = 0.f; - - if (tategaki) - tate_orient = ((font->orientation+900)%3600)/10.0; - else - tate_orient = font->orientation/10.0; - - if (orient) - { - angle = FT_FixedFromFloat(orient); - pFT_Vector_Unit(&vecAngle, angle); - rotationMat.xx = vecAngle.x; - rotationMat.xy = -vecAngle.y; - rotationMat.yx = -rotationMat.xy; - rotationMat.yy = rotationMat.xx; - - pFT_Matrix_Multiply(&rotationMat, &transMat); - } - - if (tate_orient) - { - angle = FT_FixedFromFloat(tate_orient); - pFT_Vector_Unit(&vecAngle, angle); - taterotationMat.xx = vecAngle.x; - taterotationMat.xy = -vecAngle.y; - taterotationMat.yx = -taterotationMat.xy; - taterotationMat.yy = taterotationMat.xx; - pFT_Matrix_Multiply(&taterotationMat, &transMatTategaki); - } - - needsTransform = TRUE; - } - - /* World transform */ - if (!is_identity_FMAT2(&font->font_desc.matrix)) - { - FT_Matrix worldMat; - worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11); - worldMat.xy = -FT_FixedFromFloat(font->font_desc.matrix.eM21); - worldMat.yx = -FT_FixedFromFloat(font->font_desc.matrix.eM12); - worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22); - pFT_Matrix_Multiply(&worldMat, &transMat); - pFT_Matrix_Multiply(&worldMat, &transMatUnrotated); - pFT_Matrix_Multiply(&worldMat, &transMatTategaki); - needsTransform = TRUE; - } - - /* Extra transformation specified by caller */ - if (!is_identity_MAT2(lpmat)) - { - FT_Matrix extraMat; - extraMat.xx = FT_FixedFromFIXED(lpmat->eM11); - extraMat.xy = FT_FixedFromFIXED(lpmat->eM21); - extraMat.yx = FT_FixedFromFIXED(lpmat->eM12); - extraMat.yy = FT_FixedFromFIXED(lpmat->eM22); - pFT_Matrix_Multiply(&extraMat, &transMat); - pFT_Matrix_Multiply(&extraMat, &transMatUnrotated); - pFT_Matrix_Multiply(&extraMat, &transMatTategaki); - needsTransform = TRUE; - } + needsTransform = get_transform_matrix( font, tategaki, lpmat, + &transMat, &transMatTategaki, &transMatUnrotated );
vertical_metrics = (tategaki && FT_HAS_VERTICAL(ft_face)); /* there is a freetype bug where vertical metrics are only
Signed-off-by: Byeongsik Jeon bsjeon@hanmail.net --- dlls/gdi32/freetype.c | 81 ++++++++++++++++++++++++++++--------------- 1 file changed, 54 insertions(+), 27 deletions(-)
diff --git a/dlls/gdi32/freetype.c b/dlls/gdi32/freetype.c index 4ae6cdd29f..5159d18be5 100644 --- a/dlls/gdi32/freetype.c +++ b/dlls/gdi32/freetype.c @@ -4707,6 +4707,56 @@ static void free_font(GdiFont *font) HeapFree(GetProcessHeap(), 0, font); }
+/* TODO: ggo format support */ +static GM *get_cached_gm_abc_metrics( GdiFont *font, UINT index, + GLYPHMETRICS *gm, ABC *abc ) +{ + UINT block = index / GM_BLOCK_SIZE; + UINT entry = index % GM_BLOCK_SIZE; + GM *ret = NULL; + + if (block < font->gmsize && font->gm[block] && font->gm[block][entry].init) + { + *gm = font->gm[block][entry].gm; + *abc = font->gm[block][entry].abc; + ret = &font->gm[block][entry]; + + TRACE( "cached gm: %u,%u,%s,%d,%d\n", gm->gmBlackBoxX, gm->gmBlackBoxY, + wine_dbgstr_point( &gm->gmptGlyphOrigin ), + gm->gmCellIncX, gm->gmCellIncY ); + TRACE( "cached abc: %d,%u,%d\n", abc->abcA, abc->abcB, abc->abcC ); + } + + return ret; +} + +static void cache_gm_abc_metrics( GdiFont *font, UINT index, + const GLYPHMETRICS *gm, const ABC *abc ) +{ + UINT block = index / GM_BLOCK_SIZE; + UINT entry = index % GM_BLOCK_SIZE; + + if (block >= font->gmsize) + { + GM **ptr = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, + font->gm, (block + 1) * sizeof(GM*) ); + if (!ptr) return; + + font->gmsize = block + 1; + font->gm = ptr; + } + + if (!font->gm[block]) + { + font->gm[block] = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof(GM) * GM_BLOCK_SIZE ); + if (!font->gm[block]) return; + } + + font->gm[block][entry].gm = *gm; + font->gm[block][entry].abc = *abc; + font->gm[block][entry].init = TRUE; +}
static DWORD get_font_data( GdiFont *font, DWORD table, DWORD offset, LPVOID buf, DWORD cbData) { @@ -7084,7 +7134,6 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format, BOOL needsTransform = FALSE; BOOL tategaki = (font->name[0] == '@'); BOOL vertical_metrics; - UINT original_index;
TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm, buflen, buf, lpmat); @@ -7101,7 +7150,6 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format, TRACE("translate glyph index %04x -> %04x\n", glyph, glyph_index); } else glyph_index = glyph; - original_index = glyph_index; format &= ~GGO_GLYPH_INDEX; /* TODO: Window also turns off tategaki for glyphs passed in by index if their unicode code points fall outside of the range that is @@ -7110,32 +7158,15 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format, BOOL vert; get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index, &vert); ft_face = font->ft_face; - original_index = glyph_index; if (!vert && tategaki) tategaki = check_unicode_tategaki(glyph); }
format &= ~GGO_UNHINTED;
- if(original_index >= font->gmsize * GM_BLOCK_SIZE) { - font->gmsize = (original_index / GM_BLOCK_SIZE + 1); - font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm, - font->gmsize * sizeof(GM*)); - } else { - if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL && - FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat)) - { - *lpgm = FONT_GM(font,original_index)->gm; - *abc = FONT_GM(font,original_index)->abc; - TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY, - wine_dbgstr_point(&lpgm->gmptGlyphOrigin), - lpgm->gmCellIncX, lpgm->gmCellIncY); - return 1; /* FIXME */ - } - } - - if (!font->gm[original_index / GM_BLOCK_SIZE]) - font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE); + if (format == GGO_METRICS && is_identity_MAT2(lpmat) && + get_cached_gm_abc_metrics( font, glyph_index, lpgm, abc )) + return 1; /* FIXME */
needsTransform = get_transform_matrix( font, tategaki, lpmat, &transMat, &transMatTategaki, &transMatUnrotated ); @@ -7276,11 +7307,7 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) && is_identity_MAT2(lpmat)) /* don't cache custom transforms */ - { - FONT_GM(font,original_index)->gm = gm; - FONT_GM(font,original_index)->abc = *abc; - FONT_GM(font,original_index)->init = TRUE; - } + cache_gm_abc_metrics( font, glyph_index, &gm, abc );
if(format == GGO_METRICS) {
Hi,
While running your changed tests on Windows, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=46862
Your paranoid android.
=== debian9 (build log) ===
error: patch failed: dlls/gdi32/freetype.c:6953 error: patch failed: dlls/gdi32/freetype.c:7110 Task: Patch failed to apply
=== debian9 (build log) ===
error: patch failed: dlls/gdi32/freetype.c:6953 error: patch failed: dlls/gdi32/freetype.c:7110 Task: Patch failed to apply
Signed-off-by: Byeongsik Jeon bsjeon@hanmail.net --- dlls/gdi32/freetype.c | 238 +++++++++++++++++++++++------------------- 1 file changed, 132 insertions(+), 106 deletions(-)
diff --git a/dlls/gdi32/freetype.c b/dlls/gdi32/freetype.c index 5159d18be5..41bab77a83 100644 --- a/dlls/gdi32/freetype.c +++ b/dlls/gdi32/freetype.c @@ -6884,6 +6884,123 @@ 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 ) +{ + 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; + origin.x = bbox.xMin; + origin.y = bbox.yMax; + abc->abcA = origin.x >> 6; + abc->abcB = (metrics->width + 63) >> 6; + } + 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) + lsb = metrics->horiBearingY + metrics->vertBearingY; + else + lsb = metrics->vertAdvance + (font->potm->otmDescent << 6); + vec.x = lsb; + vec.y = font->potm->otmDescent << 6; + TRACE( "Vec %ld,%ld\n", vec.x>>6, vec.y>>6 ); + pFT_Vector_Transform( &vec, transMat ); + origin.x = (vec.x + bbox.xMin) & -64; + origin.y = (vec.y + bbox.yMax + 63) & -64; + lsb -= metrics->horiBearingY; + } + else + { + origin.x = bbox.xMin; + origin.y = bbox.yMax; + lsb = metrics->horiBearingX; + } + + adv = get_advance_metric( incoming_font, font, metrics, transMat, vertical_metrics ); + gm->gmCellIncX = adv.x >> 6; + gm->gmCellIncY = adv.y >> 6; + + adv = get_advance_metric( incoming_font, font, metrics, transMatUnrotated, vertical_metrics ); + adv.x = pFT_Vector_Length( &adv ); + adv.y = 0; + + vec.x = lsb; + vec.y = 0; + pFT_Vector_Transform( &vec, transMatUnrotated ); + if (lsb > 0) abc->abcA = pFT_Vector_Length( &vec ) >> 6; + else abc->abcA = -((pFT_Vector_Length( &vec ) + 63) >> 6); + + /* We use lsb again to avoid rounding errors */ + vec.x = lsb + (tategaki ? metrics->height : metrics->width); + vec.y = 0; + pFT_Vector_Transform( &vec, transMatUnrotated ); + abc->abcB = ((pFT_Vector_Length( &vec ) + 63) >> 6) - abc->abcA; + } + + if (!abc->abcB) abc->abcB = 1; + abc->abcC = (adv.x >> 6) - abc->abcA - abc->abcB; + + gm->gmptGlyphOrigin.x = origin.x >> 6; + gm->gmptGlyphOrigin.y = origin.y >> 6; + gm->gmBlackBoxX = (bbox.xMax - bbox.xMin) >> 6; + gm->gmBlackBoxY = (bbox.yMax - bbox.yMin) >> 6; + if (!gm->gmBlackBoxX) gm->gmBlackBoxX = 1; + if (!gm->gmBlackBoxY) gm->gmBlackBoxY = 1; + + 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 ); + + return bbox; +} + static unsigned int get_native_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf) { TTPOLYGONHEADER *pph; @@ -7124,9 +7241,7 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format, DWORD width, height, pitch, needed = 0; FT_Bitmap ft_bitmap; FT_Error err; - INT left, right, top = 0, bottom = 0; - FT_Vector adv; - INT origin_x = 0, origin_y = 0; + FT_BBox bbox; FT_Int load_flags = get_load_flags(format, incoming_font); FT_Matrix transMat = identityMat; FT_Matrix transMatUnrotated; @@ -7199,8 +7314,8 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format, 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) ); + INT top = min( metrics.horiBearingY, ptm->tmAscent << 6 ); + INT bottom = max( metrics.horiBearingY - metrics.height, -(ptm->tmDescent << 6) ); metrics.horiBearingY = top; metrics.height = top - bottom;
@@ -7208,102 +7323,13 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format, /* metrics.width = min( metrics.width, ptm->tmMaxCharWidth << 6 ); */ }
- if(!needsTransform) { - left = (INT)(metrics.horiBearingX) & -64; - right = (INT)((metrics.horiBearingX + metrics.width) + 63) & -64; - top = (metrics.horiBearingY + 63) & -64; - bottom = (metrics.horiBearingY - metrics.height) & -64; - adv = get_advance_metric(incoming_font, font, &metrics, NULL, vertical_metrics); - gm.gmCellIncX = adv.x >> 6; - gm.gmCellIncY = 0; - origin_x = left; - origin_y = top; - abc->abcA = origin_x >> 6; - abc->abcB = (metrics.width + 63) >> 6; - } else { - INT xc, yc; - FT_Vector vec; - FT_Pos lsb; - - left = right = 0; - - 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) { - left = right = vec.x; - top = bottom = vec.y; - } else { - if(vec.x < left) left = vec.x; - else if(vec.x > right) right = vec.x; - if(vec.y < bottom) bottom = vec.y; - else if(vec.y > top) top = vec.y; - } - } - } - left = left & -64; - right = (right + 63) & -64; - bottom = bottom & -64; - top = (top + 63) & -64; - - if (tategaki && (font->potm || get_outline_text_metrics(font))) - { - if (vertical_metrics) - lsb = metrics.horiBearingY + metrics.vertBearingY; - else - lsb = metrics.vertAdvance + (font->potm->otmDescent << 6); - vec.x = lsb; - vec.y = font->potm->otmDescent << 6; - TRACE ("Vec %ld,%ld\n", vec.x>>6, vec.y>>6); - pFT_Vector_Transform(&vec, &transMat); - origin_x = (vec.x + left) & -64; - origin_y = (vec.y + top + 63) & -64; - lsb -= metrics.horiBearingY; - } - else - { - origin_x = left; - origin_y = top; - lsb = metrics.horiBearingX; - } - - TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom); - adv = get_advance_metric(incoming_font, font, &metrics, &transMat, vertical_metrics); - gm.gmCellIncX = adv.x >> 6; - gm.gmCellIncY = adv.y >> 6; - - adv = get_advance_metric(incoming_font, font, &metrics, &transMatUnrotated, vertical_metrics); - adv.x = pFT_Vector_Length(&adv); - adv.y = 0; - - vec.x = lsb; - vec.y = 0; - pFT_Vector_Transform(&vec, &transMatUnrotated); - if(lsb > 0) abc->abcA = pFT_Vector_Length(&vec) >> 6; - else abc->abcA = -((pFT_Vector_Length(&vec) + 63) >> 6); - - /* We use lsb again to avoid rounding errors */ - vec.x = lsb + (tategaki ? metrics.height : metrics.width); - vec.y = 0; - pFT_Vector_Transform(&vec, &transMatUnrotated); - abc->abcB = ((pFT_Vector_Length(&vec) + 63) >> 6) - abc->abcA; - } - - width = (right - left) >> 6; - height = (top - bottom) >> 6; - gm.gmBlackBoxX = width ? width : 1; - gm.gmBlackBoxY = height ? height : 1; - gm.gmptGlyphOrigin.x = origin_x >> 6; - gm.gmptGlyphOrigin.y = origin_y >> 6; - if (!abc->abcB) abc->abcB = 1; - abc->abcC = (adv.x >> 6) - abc->abcA - abc->abcB; + bbox = compute_gm_abc_metrics( incoming_font, font, &metrics, + tategaki, vertical_metrics, needsTransform, + &transMat, &transMatTategaki, &transMatUnrotated, + &gm, abc );
- TRACE("%u,%u,%s,%d,%d\n", gm.gmBlackBoxX, gm.gmBlackBoxY, - wine_dbgstr_point(&gm.gmptGlyphOrigin), - gm.gmCellIncX, gm.gmCellIncY); + width = (bbox.xMax - bbox.xMin) >> 6; + height = (bbox.yMax - bbox.yMin) >> 6;
if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) && is_identity_MAT2(lpmat)) /* don't cache custom transforms */ @@ -7366,7 +7392,7 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format, if(needsTransform) pFT_Outline_Transform(&ft_face->glyph->outline, &transMatTategaki);
- pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom ); + pFT_Outline_Translate(&ft_face->glyph->outline, -bbox.xMin, -bbox.yMin );
/* Note: FreeType will only set 'black' bits for us. */ memset(buf, 0, needed); @@ -7427,7 +7453,7 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format, if(needsTransform) pFT_Outline_Transform(&ft_face->glyph->outline, &transMatTategaki);
- pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom ); + pFT_Outline_Translate(&ft_face->glyph->outline, -bbox.xMin, -bbox.yMin );
memset(ft_bitmap.buffer, 0, buflen);
@@ -7518,13 +7544,13 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format, { gm.gmBlackBoxX += 2; gm.gmptGlyphOrigin.x -= 1; - left -= (1 << 6); + bbox.xMin -= (1 << 6); } else { gm.gmBlackBoxY += 2; gm.gmptGlyphOrigin.y += 1; - top += (1 << 6); + bbox.yMax += (1 << 6); }
width = gm.gmBlackBoxX; @@ -7566,7 +7592,7 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format, vmul = 3; }
- x_shift = ft_face->glyph->bitmap_left - (left >> 6); + x_shift = ft_face->glyph->bitmap_left - (bbox.xMin >> 6); if ( x_shift < 0 ) { src += hmul * -x_shift; @@ -7578,7 +7604,7 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format, width -= x_shift; }
- y_shift = (top >> 6) - ft_face->glyph->bitmap_top; + y_shift = (bbox.yMax >> 6) - ft_face->glyph->bitmap_top; if ( y_shift < 0 ) { src += src_pitch * vmul * -y_shift;
Hi,
While running your changed tests on Windows, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=46863
Your paranoid android.
=== debian9 (build log) ===
error: patch failed: dlls/gdi32/freetype.c:6953 error: patch failed: dlls/gdi32/freetype.c:7110 error: patch failed: dlls/gdi32/freetype.c:7124 Task: Patch failed to apply
=== debian9 (build log) ===
error: patch failed: dlls/gdi32/freetype.c:6953 error: patch failed: dlls/gdi32/freetype.c:7110 error: patch failed: dlls/gdi32/freetype.c:7124 Task: Patch failed to apply
Signed-off-by: Byeongsik Jeon bsjeon@hanmail.net --- dlls/gdi32/freetype.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlls/gdi32/freetype.c b/dlls/gdi32/freetype.c index 41bab77a83..c42f4287dd 100644 --- a/dlls/gdi32/freetype.c +++ b/dlls/gdi32/freetype.c @@ -7670,7 +7670,7 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format, if(buflen == 0) buf = NULL;
if (needsTransform && buf) - pFT_Outline_Transform(outline, &transMat); + pFT_Outline_Transform(outline, &transMatTategaki);
needed = get_bezier_glyph_outline(outline, buflen, NULL);
Hi,
While running your changed tests on Windows, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=46864
Your paranoid android.
=== debian9 (build log) ===
error: patch failed: dlls/gdi32/freetype.c:6953 error: patch failed: dlls/gdi32/freetype.c:7110 error: patch failed: dlls/gdi32/freetype.c:7124 Task: Patch failed to apply
=== debian9 (build log) ===
error: patch failed: dlls/gdi32/freetype.c:6953 error: patch failed: dlls/gdi32/freetype.c:7110 error: patch failed: dlls/gdi32/freetype.c:7124 Task: Patch failed to apply
Signed-off-by: Byeongsik Jeon bsjeon@hanmail.net --- dlls/gdi32/freetype.c | 697 +++++++++++++++++++++--------------------- 1 file changed, 350 insertions(+), 347 deletions(-)
diff --git a/dlls/gdi32/freetype.c b/dlls/gdi32/freetype.c index c42f4287dd..292a39909e 100644 --- a/dlls/gdi32/freetype.c +++ b/dlls/gdi32/freetype.c @@ -7001,7 +7001,7 @@ static FT_BBox compute_gm_abc_metrics( GdiFont *incoming_font, GdiFont *font, return bbox; }
-static unsigned int get_native_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf) +static unsigned int get_native_glyph_outline(FT_Outline *outline, unsigned int buflen, BYTE *buf) { TTPOLYGONHEADER *pph; TTPOLYCURVE *ppc; @@ -7074,7 +7074,7 @@ static unsigned int get_native_glyph_outline(FT_Outline *outline, unsigned int b return needed; }
-static unsigned int get_bezier_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf) +static unsigned int get_bezier_glyph_outline(FT_Outline *outline, unsigned int buflen, BYTE *buf) { /* Convert the quadratic Beziers to cubic Beziers. The parametric eqn for a cubic Bezier is, from PLRM: @@ -7198,6 +7198,344 @@ 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, + BOOL needsTransform, FT_Matrix *transMatTategaki, + DWORD buflen, BYTE *buf ) +{ + 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; + + switch (format) + { + case GGO_BITMAP: + pitch = ((width + 31) >> 5) << 2; + needed = pitch * height; + + if (!buf || !buflen) break; + if (!needed) return GDI_ERROR; /* empty glyph */ + if (needed > buflen) return GDI_ERROR; + + ft_bitmap.width = width; + ft_bitmap.rows = height; + ft_bitmap.pitch = pitch; + ft_bitmap.pixel_mode = FT_PIXEL_MODE_MONO; + ft_bitmap.buffer = buf; + + if (needsTransform) + pFT_Outline_Transform( outline, transMatTategaki ); + pFT_Outline_Translate( outline, -bbox.xMin, -bbox.yMin ); + + /* Note: FreeType will only set 'black' bits for us. */ + memset( buf, 0, needed ); + pFT_Outline_Get_Bitmap( library, outline, &ft_bitmap ); + break; + + case GGO_GRAY2_BITMAP: + case GGO_GRAY4_BITMAP: + case GGO_GRAY8_BITMAP: + case WINE_GGO_GRAY16_BITMAP: + pitch = (width + 3) / 4 * 4; + needed = pitch * height; + + if (!buf || !buflen) break; + if (!needed) return GDI_ERROR; /* empty glyph */ + if (needed > buflen) return GDI_ERROR; + + ft_bitmap.width = width; + ft_bitmap.rows = height; + ft_bitmap.pitch = pitch; + ft_bitmap.pixel_mode = FT_PIXEL_MODE_GRAY; + ft_bitmap.buffer = buf; + + if (needsTransform) + pFT_Outline_Transform( outline, transMatTategaki ); + pFT_Outline_Translate( outline, -bbox.xMin, -bbox.yMin ); + + memset( ft_bitmap.buffer, 0, buflen ); + pFT_Outline_Get_Bitmap( library, outline, &ft_bitmap ); + + max_level = get_max_level( format ); + if (max_level != 255) + { + BYTE *start, *ptr; + UINT row, col; + + for (row = 0, start = buf; row < height; row++) + { + for (col = 0, ptr = start; col < width; col++, ptr++) + *ptr = (((int)*ptr) * (max_level + 1)) / 256; + start += pitch; + } + } + break; + + case WINE_GGO_HRGB_BITMAP: + case WINE_GGO_HBGR_BITMAP: + case WINE_GGO_VRGB_BITMAP: + case WINE_GGO_VBGR_BITMAP: + { + BYTE *src; + unsigned int *dst; + INT x, rgb_interval, hmul, vmul; + INT src_pitch, src_width, src_height, x_shift, y_shift; + const INT *sub_order; + const INT rgb_order[3] = { 0, 1, 2 }; + const INT bgr_order[3] = { 2, 1, 0 }; + FT_Render_Mode render_mode = + (format == WINE_GGO_HRGB_BITMAP || + format == WINE_GGO_HBGR_BITMAP) ? FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V; + + if (!width || !height) /* empty glyph */ + { + if (!buf || !buflen) break; + return GDI_ERROR; + } + + if (render_mode == FT_RENDER_MODE_LCD) + { + gm->gmBlackBoxX += 2; + gm->gmptGlyphOrigin.x -= 1; + bbox.xMin -= (1 << 6); + } + else + { + gm->gmBlackBoxY += 2; + gm->gmptGlyphOrigin.y += 1; + bbox.yMax += (1 << 6); + } + + width = gm->gmBlackBoxX; + height = gm->gmBlackBoxY; + pitch = width * 4; + needed = pitch * height; + + if (!buf || !buflen) break; + if (needed > buflen) return GDI_ERROR; + + memset( buf, 0, buflen ); + dst = (unsigned int *)buf; + + if (needsTransform) + pFT_Outline_Transform( outline, transMatTategaki ); + +#ifdef FT_LCD_FILTER_H + if (pFT_Library_SetLcdFilter) + pFT_Library_SetLcdFilter( library, FT_LCD_FILTER_DEFAULT ); +#endif + pFT_Render_Glyph( glyph, render_mode ); + + src = glyph->bitmap.buffer; + src_pitch = glyph->bitmap.pitch; + src_width = glyph->bitmap.width; + src_height = glyph->bitmap.rows; + + rgb_interval = render_mode == FT_RENDER_MODE_LCD ? 1 : src_pitch; + 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); + if (x_shift < 0) + { + src += hmul * -x_shift; + src_width -= hmul * -x_shift; + } + else if (x_shift > 0) + { + dst += x_shift; + width -= x_shift; + } + + y_shift = (bbox.yMax >> 6) - glyph->bitmap_top; + if (y_shift < 0) + { + src += src_pitch * vmul * -y_shift; + src_height -= vmul * -y_shift; + } + else if (y_shift > 0) + { + dst += y_shift * (pitch / sizeof(*dst)); + height -= y_shift; + } + + width = min( width, src_width / hmul ); + height = min( height, src_height / vmul ); + + sub_order = (format == WINE_GGO_HRGB_BITMAP || + format == WINE_GGO_VRGB_BITMAP) ? rgb_order : bgr_order; + + while (height--) + { + for (x = 0; x < width; x++) + { + dst[x] = ((unsigned int)src[hmul * x + rgb_interval * sub_order[0]] << 16) | + ((unsigned int)src[hmul * x + rgb_interval * sub_order[1]] << 8) | + ((unsigned int)src[hmul * x + rgb_interval * sub_order[2]]); + } + src += src_pitch * vmul; + dst += pitch / sizeof(*dst); + } + break; + } + case GGO_NATIVE: + if (buflen == 0) buf = NULL; + + if (needsTransform && buf) + pFT_Outline_Transform( outline, transMatTategaki ); + + needed = get_native_glyph_outline( outline, buflen, NULL ); + + if (!buf || !buflen) break; + if (needed > buflen) return GDI_ERROR; + + get_native_glyph_outline( outline, buflen, buf ); + break; + + case GGO_BEZIER: + if (buflen == 0) buf = NULL; + + if (needsTransform && buf) + pFT_Outline_Transform( outline, transMatTategaki ); + + needed = get_bezier_glyph_outline( outline, buflen, NULL ); + + if (!buf || !buflen) break; + if (needed > buflen) return GDI_ERROR; + + get_bezier_glyph_outline( outline, buflen, buf ); + break; + + default: + FIXME("Unsupported format %d\n", format); + return GDI_ERROR; + } + + return needed; +} + +static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01}; + +static DWORD get_ggo_glyph_from_bitmap( FT_GlyphSlot glyph, UINT format, FT_BBox bbox, + GdiFont *font, + DWORD buflen, BYTE *buf ) +{ + BYTE *src, *dst; + DWORD width = (bbox.xMax - bbox.xMin) >> 6; + DWORD height = (bbox.yMax - bbox.yMin) >> 6; + DWORD max_level, pitch, needed = 0; + INT x, w, h; + + switch (format) + { + case GGO_BITMAP: + pitch = ((width + 31) >> 5) << 2; + needed = pitch * height; + + if (!buf || !buflen) break; + if (!needed) return GDI_ERROR; /* empty glyph */ + if (needed > buflen) return GDI_ERROR; + + src = glyph->bitmap.buffer; + dst = buf; + w = min( pitch, (glyph->bitmap.width + 7) >> 3 ); + h = min( height, glyph->bitmap.rows ); + while (h--) + { + if (!font->fake_bold) + memcpy( dst, src, w ); + else + { + dst[0] = 0; + for (x = 0; x < w; x++) + { + dst[x] = (dst[x] & 0x80) | (src[x] >> 1) | src[x]; + if (x + 1 < pitch) + dst[x + 1] = (src[x] & 0x01) << 7; + } + } + src += glyph->bitmap.pitch; + dst += pitch; + } + break; + + case GGO_GRAY2_BITMAP: + case GGO_GRAY4_BITMAP: + case GGO_GRAY8_BITMAP: + case WINE_GGO_GRAY16_BITMAP: + pitch = (width + 3) / 4 * 4; + needed = pitch * height; + + if(!buf || !buflen) break; + if (!needed) return GDI_ERROR; /* empty glyph */ + if (needed > buflen) return GDI_ERROR; + + src = glyph->bitmap.buffer; + dst = buf; + memset( buf, 0, buflen ); + max_level = get_max_level( format ); + h = min( height, glyph->bitmap.rows ); + while (h--) + { + for (x = 0; x < pitch && x < glyph->bitmap.width; x++) + { + if (src[x / 8] & masks[x % 8]) + { + dst[x] = max_level; + if (font->fake_bold && x + 1 < pitch) + dst[x+1] = max_level; + } + } + src += glyph->bitmap.pitch; + dst += pitch; + } + break; + + case WINE_GGO_HRGB_BITMAP: + case WINE_GGO_HBGR_BITMAP: + case WINE_GGO_VRGB_BITMAP: + case WINE_GGO_VBGR_BITMAP: + pitch = width * 4; + needed = pitch * height; + + if (!buf || !buflen) break; + if (!needed) return GDI_ERROR; /* empty glyph */ + if (needed > buflen) return GDI_ERROR; + + src = glyph->bitmap.buffer; + dst = buf; + memset(buf, 0, buflen); + h = min( height, glyph->bitmap.rows ); + while (h--) + { + for (x = 0; x < width && x < glyph->bitmap.width; x++) + { + if (src[x / 8] & masks[x % 8]) + { + ((unsigned int *)dst)[x] = ~0u; + if (font->fake_bold && x + 1 < width) + ((unsigned int *)dst)[x + 1] = ~0u; + } + } + src += glyph->bitmap.pitch; + dst += pitch; + } + break; + + case GGO_NATIVE: + case GGO_BEZIER: + TRACE("loaded a bitmap\n"); + return GDI_ERROR; + + default: + FIXME("Unsupported format %d\n", format); + return GDI_ERROR; + } + + return needed; +} + static FT_Int get_load_flags( UINT format, GdiFont *font ) { BOOL natural_width; @@ -7226,8 +7564,6 @@ static FT_Int get_load_flags( UINT format, GdiFont *font ) return load_flags; }
-static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01}; - static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format, LPGLYPHMETRICS lpgm, ABC *abc, DWORD buflen, LPVOID buf, const MAT2* lpmat) @@ -7238,8 +7574,7 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format, GdiFont *font = incoming_font; FT_Glyph_Metrics metrics; FT_UInt glyph_index; - DWORD width, height, pitch, needed = 0; - FT_Bitmap ft_bitmap; + DWORD needed = 0; FT_Error err; FT_BBox bbox; FT_Int load_flags = get_load_flags(format, incoming_font); @@ -7328,9 +7663,6 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format, &transMat, &transMatTategaki, &transMatUnrotated, &gm, abc );
- width = (bbox.xMax - bbox.xMin) >> 6; - height = (bbox.yMax - bbox.yMin) >> 6; - if ((format == 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 ); @@ -7341,352 +7673,23 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format, return 1; /* FIXME */ }
- if(ft_face->glyph->format != ft_glyph_format_outline && - (format == GGO_NATIVE || format == GGO_BEZIER)) + switch (ft_face->glyph->format) { - TRACE("loaded a bitmap\n"); - return GDI_ERROR; - } - - switch(format) { - case GGO_BITMAP: - pitch = ((width + 31) >> 5) << 2; - needed = pitch * height; - - if(!buf || !buflen) break; - if (!needed) return GDI_ERROR; /* empty glyph */ - if (needed > buflen) - return GDI_ERROR; - - switch(ft_face->glyph->format) { - case ft_glyph_format_bitmap: - { - BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf; - INT w = min( pitch, (ft_face->glyph->bitmap.width + 7) >> 3 ); - INT h = min( height, ft_face->glyph->bitmap.rows ); - while(h--) { - if (!font->fake_bold) - memcpy(dst, src, w); - else { - INT x; - dst[0] = 0; - for (x = 0; x < w; x++) { - dst[x ] = (dst[x] & 0x80) | (src[x] >> 1) | src[x]; - if (x+1 < pitch) - dst[x+1] = (src[x] & 0x01) << 7; - } - } - src += ft_face->glyph->bitmap.pitch; - dst += pitch; - } - break; - } - - case ft_glyph_format_outline: - ft_bitmap.width = width; - ft_bitmap.rows = height; - ft_bitmap.pitch = pitch; - ft_bitmap.pixel_mode = ft_pixel_mode_mono; - ft_bitmap.buffer = buf; - - if(needsTransform) - pFT_Outline_Transform(&ft_face->glyph->outline, &transMatTategaki); - - pFT_Outline_Translate(&ft_face->glyph->outline, -bbox.xMin, -bbox.yMin ); - - /* Note: FreeType will only set 'black' bits for us. */ - memset(buf, 0, needed); - pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap); - break; - - default: - FIXME("loaded glyph format %x\n", ft_face->glyph->format); - return GDI_ERROR; - } - break; - - case GGO_GRAY2_BITMAP: - case GGO_GRAY4_BITMAP: - case GGO_GRAY8_BITMAP: - case WINE_GGO_GRAY16_BITMAP: - { - unsigned int max_level, row, col; - BYTE *start, *ptr; - - pitch = (width + 3) / 4 * 4; - needed = pitch * height; - - if(!buf || !buflen) break; - if (!needed) return GDI_ERROR; /* empty glyph */ - if (needed > buflen) - return GDI_ERROR; - - max_level = get_max_level( format ); - - switch(ft_face->glyph->format) { - case ft_glyph_format_bitmap: - { - BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf; - INT h = min( height, ft_face->glyph->bitmap.rows ); - INT x; - memset( buf, 0, needed ); - while(h--) { - for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++) { - if (src[x / 8] & masks[x % 8]) { - dst[x] = max_level; - if (font->fake_bold && x+1 < pitch) dst[x+1] = max_level; - } - } - src += ft_face->glyph->bitmap.pitch; - dst += pitch; - } - break; - } - case ft_glyph_format_outline: - { - ft_bitmap.width = width; - ft_bitmap.rows = height; - ft_bitmap.pitch = pitch; - ft_bitmap.pixel_mode = ft_pixel_mode_grays; - ft_bitmap.buffer = buf; - - if(needsTransform) - pFT_Outline_Transform(&ft_face->glyph->outline, &transMatTategaki); - - pFT_Outline_Translate(&ft_face->glyph->outline, -bbox.xMin, -bbox.yMin ); - - memset(ft_bitmap.buffer, 0, buflen); - - pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap); - - if (max_level != 255) - { - for (row = 0, start = buf; row < height; row++) - { - for (col = 0, ptr = start; col < width; col++, ptr++) - *ptr = (((int)*ptr) * (max_level + 1)) / 256; - start += pitch; - } - } - break; - } - - default: - FIXME("loaded glyph format %x\n", ft_face->glyph->format); - return GDI_ERROR; - } - break; - } - - case WINE_GGO_HRGB_BITMAP: - case WINE_GGO_HBGR_BITMAP: - case WINE_GGO_VRGB_BITMAP: - case WINE_GGO_VBGR_BITMAP: - { - switch (ft_face->glyph->format) - { case FT_GLYPH_FORMAT_BITMAP: - { - BYTE *src, *dst; - INT src_pitch, x; - - pitch = width * 4; - needed = pitch * height; - - if (!buf || !buflen) break; - if (!needed) return GDI_ERROR; /* empty glyph */ - if (needed > buflen) - return GDI_ERROR; - - memset(buf, 0, buflen); - dst = buf; - src = ft_face->glyph->bitmap.buffer; - src_pitch = ft_face->glyph->bitmap.pitch; - - height = min( height, ft_face->glyph->bitmap.rows ); - while ( height-- ) - { - for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++) - { - if ( src[x / 8] & masks[x % 8] ) - { - ((unsigned int *)dst)[x] = ~0u; - if (font->fake_bold && x+1 < width) ((unsigned int *)dst)[x+1] = ~0u; - } - } - src += src_pitch; - dst += pitch; - } - + needed = get_ggo_glyph_from_bitmap( ft_face->glyph, format, bbox, font, + buflen, buf ); break; - } - case FT_GLYPH_FORMAT_OUTLINE: - { - unsigned int *dst; - BYTE *src; - INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul; - INT x_shift, y_shift; - const INT *sub_order; - const INT rgb_order[3] = { 0, 1, 2 }; - const INT bgr_order[3] = { 2, 1, 0 }; - FT_Render_Mode render_mode = - (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)? - FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V; - - if (!width || !height) - { - if (!buf || !buflen) break; - return GDI_ERROR; - } - - if ( render_mode == FT_RENDER_MODE_LCD) - { - gm.gmBlackBoxX += 2; - gm.gmptGlyphOrigin.x -= 1; - bbox.xMin -= (1 << 6); - } - else - { - gm.gmBlackBoxY += 2; - gm.gmptGlyphOrigin.y += 1; - bbox.yMax += (1 << 6); - } - - width = gm.gmBlackBoxX; - height = gm.gmBlackBoxY; - pitch = width * 4; - needed = pitch * height; - - if (!buf || !buflen) break; - if (needed > buflen) - return GDI_ERROR; - - memset(buf, 0, buflen); - dst = buf; - - if ( needsTransform ) - pFT_Outline_Transform (&ft_face->glyph->outline, &transMatTategaki); - -#ifdef FT_LCD_FILTER_H - if ( pFT_Library_SetLcdFilter ) - pFT_Library_SetLcdFilter( library, FT_LCD_FILTER_DEFAULT ); -#endif - pFT_Render_Glyph (ft_face->glyph, render_mode); - - src = ft_face->glyph->bitmap.buffer; - src_pitch = ft_face->glyph->bitmap.pitch; - src_width = ft_face->glyph->bitmap.width; - src_height = ft_face->glyph->bitmap.rows; - - if ( render_mode == FT_RENDER_MODE_LCD) - { - rgb_interval = 1; - hmul = 3; - vmul = 1; - } - else - { - rgb_interval = src_pitch; - hmul = 1; - vmul = 3; - } - - x_shift = ft_face->glyph->bitmap_left - (bbox.xMin >> 6); - if ( x_shift < 0 ) - { - src += hmul * -x_shift; - src_width -= hmul * -x_shift; - } - else if ( x_shift > 0 ) - { - dst += x_shift; - width -= x_shift; - } - - y_shift = (bbox.yMax >> 6) - ft_face->glyph->bitmap_top; - if ( y_shift < 0 ) - { - src += src_pitch * vmul * -y_shift; - src_height -= vmul * -y_shift; - } - else if ( y_shift > 0 ) - { - dst += y_shift * ( pitch / sizeof(*dst) ); - height -= y_shift; - } - - width = min( width, src_width / hmul ); - height = min( height, src_height / vmul ); - - sub_order = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP)? - rgb_order : bgr_order; - - while ( height-- ) - { - for ( x = 0; x < width; x++ ) - { - dst[x] = ((unsigned int)src[hmul * x + rgb_interval * sub_order[0]] << 16) | - ((unsigned int)src[hmul * x + rgb_interval * sub_order[1]] << 8) | - ((unsigned int)src[hmul * x + rgb_interval * sub_order[2]]); - } - src += src_pitch * vmul; - dst += pitch / sizeof(*dst); - } - + needed = get_ggo_glyph_from_outline( ft_face->glyph, format, bbox, &gm, + needsTransform, &transMatTategaki, + buflen, buf ); break; - } - default: - FIXME ("loaded glyph format %x\n", ft_face->glyph->format); - return GDI_ERROR; - } - - break; - } - - case GGO_NATIVE: - { - FT_Outline *outline = &ft_face->glyph->outline; - - if(buflen == 0) buf = NULL; - - if (needsTransform && buf) - pFT_Outline_Transform(outline, &transMatTategaki); - - needed = get_native_glyph_outline(outline, buflen, NULL); - - if (!buf || !buflen) - break; - if (needed > buflen) - return GDI_ERROR; - - get_native_glyph_outline(outline, buflen, buf); - break; - } - case GGO_BEZIER: - { - FT_Outline *outline = &ft_face->glyph->outline; - if(buflen == 0) buf = NULL; - - if (needsTransform && buf) - pFT_Outline_Transform(outline, &transMatTategaki); - - needed = get_bezier_glyph_outline(outline, buflen, NULL); - - if (!buf || !buflen) - break; - if (needed > buflen) + FIXME("loaded glyph format %x\n", ft_face->glyph->format); return GDI_ERROR; - - get_bezier_glyph_outline(outline, buflen, buf); - break; - } - - default: - FIXME("Unsupported format %d\n", format); - return GDI_ERROR; } + if (needed == GDI_ERROR) return GDI_ERROR; + *lpgm = gm; return needed; }
Hi,
While running your changed tests on Windows, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=46865
Your paranoid android.
=== debian9 (build log) ===
error: patch failed: dlls/gdi32/freetype.c:6953 error: patch failed: dlls/gdi32/freetype.c:7110 error: patch failed: dlls/gdi32/freetype.c:7124 error: patch failed: dlls/gdi32/freetype.c:7001 Task: Patch failed to apply
=== debian9 (build log) ===
error: patch failed: dlls/gdi32/freetype.c:6953 error: patch failed: dlls/gdi32/freetype.c:7110 error: patch failed: dlls/gdi32/freetype.c:7124 error: patch failed: dlls/gdi32/freetype.c:7001 Task: Patch failed to apply
Signed-off-by: Byeongsik Jeon bsjeon@hanmail.net --- If we look at the behavior of GGO_METRICS, the setting of lfQuality is applied.
GGO_METIRCS is zero. So it's impossible to do 'GGO_METRICS | GGO_BITMAP', 'GGO_METRICS | GGO_GRAY4_BITMAP', etc.
dlls/gdi32/freetype.c | 45 +++++++++++++++++++++++++++-------------- dlls/gdi32/tests/font.c | 1 + include/wingdi.h | 2 ++ 3 files changed, 33 insertions(+), 15 deletions(-)
diff --git a/dlls/gdi32/freetype.c b/dlls/gdi32/freetype.c index 292a39909e..0759a68412 100644 --- a/dlls/gdi32/freetype.c +++ b/dlls/gdi32/freetype.c @@ -7546,7 +7546,8 @@ static FT_Int get_load_flags( UINT format, GdiFont *font )
natural_width = font->font_desc.lf.lfQuality == CLEARTYPE_NATURAL_QUALITY;
- switch (format & ~GGO_GLYPH_INDEX) + format &= ~(GGO_GLYPH_INDEX | WINE_GGO_METRICS); + switch (format) { case WINE_GGO_HRGB_BITMAP: case WINE_GGO_HBGR_BITMAP: @@ -7584,6 +7585,7 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format, BOOL needsTransform = FALSE; BOOL tategaki = (font->name[0] == '@'); BOOL vertical_metrics; + BOOL ggo_metrics = format & WINE_GGO_METRICS;
TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm, buflen, buf, lpmat); @@ -7612,9 +7614,9 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format, tategaki = check_unicode_tategaki(glyph); }
- format &= ~GGO_UNHINTED; + format &= ~(WINE_GGO_METRICS | GGO_UNHINTED);
- if (format == GGO_METRICS && is_identity_MAT2(lpmat) && + if (ggo_metrics && is_identity_MAT2(lpmat) && get_cached_gm_abc_metrics( font, glyph_index, lpgm, abc )) return 1; /* FIXME */
@@ -7663,11 +7665,11 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format, &transMat, &transMatTategaki, &transMatUnrotated, &gm, abc );
- if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) && + 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(format == GGO_METRICS) + if (ggo_metrics) { *lpgm = gm; return 1; /* FIXME */ @@ -8230,7 +8232,11 @@ static DWORD freetype_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
GDI_CheckNotLock(); EnterCriticalSection( &freetype_cs ); + + if (GGO_METRICS == (format & ~(GGO_UNHINTED | GGO_GLYPH_INDEX))) + format |= get_physdev_dc( dev )->aa_flags | WINE_GGO_METRICS; ret = get_glyph_outline( physdev->font, glyph, format, lpgm, &abc, buflen, buf, lpmat ); + LeaveCriticalSection( &freetype_cs ); return ret; } @@ -8386,7 +8392,7 @@ done: static BOOL freetype_GetCharWidth( PHYSDEV dev, UINT firstChar, UINT lastChar, LPINT buffer ) { static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} }; - UINT c; + UINT c, format; GLYPHMETRICS gm; ABC abc; struct freetype_physdev *physdev = get_freetype_dev( dev ); @@ -8401,10 +8407,14 @@ static BOOL freetype_GetCharWidth( PHYSDEV dev, UINT firstChar, UINT lastChar, L
GDI_CheckNotLock(); EnterCriticalSection( &freetype_cs ); - for(c = firstChar; c <= lastChar; c++) { - get_glyph_outline( physdev->font, c, GGO_METRICS, &gm, &abc, 0, NULL, &identity ); + + format = get_physdev_dc( dev )->aa_flags | WINE_GGO_METRICS; + for (c = firstChar; c <= lastChar; c++) + { + get_glyph_outline( physdev->font, c, format, &gm, &abc, 0, NULL, &identity ); buffer[c - firstChar] = abc.abcA + abc.abcB + abc.abcC; } + LeaveCriticalSection( &freetype_cs ); return TRUE; } @@ -8415,7 +8425,7 @@ static BOOL freetype_GetCharWidth( PHYSDEV dev, UINT firstChar, UINT lastChar, L static BOOL freetype_GetCharABCWidths( PHYSDEV dev, UINT firstChar, UINT lastChar, LPABC buffer ) { static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} }; - UINT c; + UINT c, format; GLYPHMETRICS gm; struct freetype_physdev *physdev = get_freetype_dev( dev );
@@ -8430,8 +8440,9 @@ static BOOL freetype_GetCharABCWidths( PHYSDEV dev, UINT firstChar, UINT lastCha GDI_CheckNotLock(); EnterCriticalSection( &freetype_cs );
+ format = get_physdev_dc( dev )->aa_flags | WINE_GGO_METRICS; for(c = firstChar; c <= lastChar; c++, buffer++) - get_glyph_outline( physdev->font, c, GGO_METRICS, &gm, buffer, 0, NULL, &identity ); + get_glyph_outline( physdev->font, c, format, &gm, buffer, 0, NULL, &identity );
LeaveCriticalSection( &freetype_cs ); return TRUE; @@ -8443,7 +8454,7 @@ static BOOL freetype_GetCharABCWidths( PHYSDEV dev, UINT firstChar, UINT lastCha static BOOL freetype_GetCharABCWidthsI( PHYSDEV dev, UINT firstChar, UINT count, LPWORD pgi, LPABC buffer ) { static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} }; - UINT c; + UINT c, format; GLYPHMETRICS gm; struct freetype_physdev *physdev = get_freetype_dev( dev );
@@ -8459,8 +8470,9 @@ static BOOL freetype_GetCharABCWidthsI( PHYSDEV dev, UINT firstChar, UINT count, GDI_CheckNotLock(); EnterCriticalSection( &freetype_cs );
+ format = get_physdev_dc( dev )->aa_flags | WINE_GGO_METRICS | GGO_GLYPH_INDEX; for(c = 0; c < count; c++, buffer++) - get_glyph_outline( physdev->font, pgi ? pgi[c] : firstChar + c, GGO_METRICS | GGO_GLYPH_INDEX, + get_glyph_outline( physdev->font, pgi ? pgi[c] : firstChar + c, format, &gm, buffer, 0, NULL, &identity );
LeaveCriticalSection( &freetype_cs ); @@ -8474,6 +8486,7 @@ static BOOL freetype_GetTextExtentExPoint( PHYSDEV dev, LPCWSTR wstr, INT count, { static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} }; INT idx, pos; + UINT format; ABC abc; GLYPHMETRICS gm; struct freetype_physdev *physdev = get_freetype_dev( dev ); @@ -8489,9 +8502,10 @@ static BOOL freetype_GetTextExtentExPoint( PHYSDEV dev, LPCWSTR wstr, INT count, GDI_CheckNotLock(); EnterCriticalSection( &freetype_cs );
+ format = get_physdev_dc( dev )->aa_flags | WINE_GGO_METRICS; for (idx = pos = 0; idx < count; idx++) { - get_glyph_outline( physdev->font, wstr[idx], GGO_METRICS, &gm, &abc, 0, NULL, &identity ); + get_glyph_outline( physdev->font, wstr[idx], format, &gm, &abc, 0, NULL, &identity ); pos += abc.abcA + abc.abcB + abc.abcC; dxs[idx] = pos; } @@ -8507,6 +8521,7 @@ static BOOL freetype_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, IN { static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} }; INT idx, pos; + UINT format; ABC abc; GLYPHMETRICS gm; struct freetype_physdev *physdev = get_freetype_dev( dev ); @@ -8522,10 +8537,10 @@ static BOOL freetype_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, IN GDI_CheckNotLock(); EnterCriticalSection( &freetype_cs );
+ format = get_physdev_dc( dev )->aa_flags | WINE_GGO_METRICS | GGO_GLYPH_INDEX; for (idx = pos = 0; idx < count; idx++) { - get_glyph_outline( physdev->font, indices[idx], GGO_METRICS | GGO_GLYPH_INDEX, - &gm, &abc, 0, NULL, &identity ); + get_glyph_outline( physdev->font, indices[idx], format, &gm, &abc, 0, NULL, &identity ); pos += abc.abcA + abc.abcB + abc.abcC; dxs[idx] = pos; } diff --git a/dlls/gdi32/tests/font.c b/dlls/gdi32/tests/font.c index 67e8941b5e..6e7ac1e8e5 100644 --- a/dlls/gdi32/tests/font.c +++ b/dlls/gdi32/tests/font.c @@ -4839,6 +4839,7 @@ static void test_GetGlyphOutline(void) ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError()); trace("Tests with height=%d,avg=%d,full=%d,face=%s,charset=%d\n", -lf.lfHeight, tm.tmAveCharWidth, gm2.gmCellIncX, lf.lfFaceName, lf.lfCharSet); + todo_wine ok(gm2.gmCellIncX == tm.tmAveCharWidth * 2 || broken(gm2.gmCellIncX == -lf.lfHeight), "expected %d, got %d (%s:%d)\n", tm.tmAveCharWidth * 2, gm2.gmCellIncX, lf.lfFaceName, lf.lfCharSet); diff --git a/include/wingdi.h b/include/wingdi.h index 1851654194..8a7453e92c 100644 --- a/include/wingdi.h +++ b/include/wingdi.h @@ -1337,6 +1337,8 @@ typedef struct #define WINE_GGO_HBGR_BITMAP 0x12 #define WINE_GGO_VRGB_BITMAP 0x13 #define WINE_GGO_VBGR_BITMAP 0x14 + +#define WINE_GGO_METRICS 0x40 #endif
typedef struct
Hi,
While running your changed tests on Windows, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=46866
Your paranoid android.
=== build (build log) ===
error: patch failed: dlls/gdi32/freetype.c:6953 error: patch failed: dlls/gdi32/freetype.c:7110 error: patch failed: dlls/gdi32/freetype.c:7124 error: patch failed: dlls/gdi32/freetype.c:7001 error: patch failed: dlls/gdi32/freetype.c:7546 Task: Patch failed to apply
=== debian9 (build log) ===
error: patch failed: dlls/gdi32/freetype.c:6953 error: patch failed: dlls/gdi32/freetype.c:7110 error: patch failed: dlls/gdi32/freetype.c:7124 error: patch failed: dlls/gdi32/freetype.c:7001 error: patch failed: dlls/gdi32/freetype.c:7546 Task: Patch failed to apply
=== debian9 (build log) ===
error: patch failed: dlls/gdi32/freetype.c:6953 error: patch failed: dlls/gdi32/freetype.c:7110 error: patch failed: dlls/gdi32/freetype.c:7124 error: patch failed: dlls/gdi32/freetype.c:7001 error: patch failed: dlls/gdi32/freetype.c:7546 Task: Patch failed to apply
The previous patch causes this hidden problem to be revealed. MS Korean dual-width fonts(ex. GulimChe), the advance width ratio of these fonts is not 1:2.
Signed-off-by: Byeongsik Jeon bsjeon@hanmail.net --- dlls/gdi32/freetype.c | 4 ++-- dlls/gdi32/tests/font.c | 1 - 2 files changed, 2 insertions(+), 3 deletions(-)
diff --git a/dlls/gdi32/freetype.c b/dlls/gdi32/freetype.c index 0759a68412..d0480333ce 100644 --- a/dlls/gdi32/freetype.c +++ b/dlls/gdi32/freetype.c @@ -6850,8 +6850,8 @@ static FT_Vector get_advance_metric(GdiFont *incoming_font, GdiFont *font, incoming_font->ft_face->units_per_EM); avg_advance = pFT_MulFix(incoming_font->ntmAvgWidth, em_scale); fixed_pitch_full = (avg_advance > 0 && - (base_advance + 63) >> 6 == - pFT_MulFix(incoming_font->ntmAvgWidth*2, em_scale)); + (base_advance + 63) >> 6 != + pFT_MulFix(incoming_font->ntmAvgWidth, em_scale)); if (fixed_pitch_full && !transMat) adv.x = (avg_advance * 2) << 6; } diff --git a/dlls/gdi32/tests/font.c b/dlls/gdi32/tests/font.c index 6e7ac1e8e5..67e8941b5e 100644 --- a/dlls/gdi32/tests/font.c +++ b/dlls/gdi32/tests/font.c @@ -4839,7 +4839,6 @@ static void test_GetGlyphOutline(void) ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError()); trace("Tests with height=%d,avg=%d,full=%d,face=%s,charset=%d\n", -lf.lfHeight, tm.tmAveCharWidth, gm2.gmCellIncX, lf.lfFaceName, lf.lfCharSet); - todo_wine ok(gm2.gmCellIncX == tm.tmAveCharWidth * 2 || broken(gm2.gmCellIncX == -lf.lfHeight), "expected %d, got %d (%s:%d)\n", tm.tmAveCharWidth * 2, gm2.gmCellIncX, lf.lfFaceName, lf.lfCharSet);
Hi,
While running your changed tests on Windows, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=46867
Your paranoid android.
=== build (build log) ===
error: patch failed: dlls/gdi32/freetype.c:6953 error: patch failed: dlls/gdi32/freetype.c:7110 error: patch failed: dlls/gdi32/freetype.c:7124 error: patch failed: dlls/gdi32/freetype.c:7001 error: patch failed: dlls/gdi32/freetype.c:7546 Task: Patch failed to apply
=== debian9 (build log) ===
error: patch failed: dlls/gdi32/freetype.c:6953 error: patch failed: dlls/gdi32/freetype.c:7110 error: patch failed: dlls/gdi32/freetype.c:7124 error: patch failed: dlls/gdi32/freetype.c:7001 error: patch failed: dlls/gdi32/freetype.c:7546 Task: Patch failed to apply
=== debian9 (build log) ===
error: patch failed: dlls/gdi32/freetype.c:6953 error: patch failed: dlls/gdi32/freetype.c:7110 error: patch failed: dlls/gdi32/freetype.c:7124 error: patch failed: dlls/gdi32/freetype.c:7001 error: patch failed: dlls/gdi32/freetype.c:7546 Task: Patch failed to apply
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,
Hi,
While running your changed tests on Windows, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=46868
Your paranoid android.
=== build (build log) ===
error: patch failed: dlls/gdi32/freetype.c:6953 error: patch failed: dlls/gdi32/freetype.c:7110 error: patch failed: dlls/gdi32/freetype.c:7124 error: patch failed: dlls/gdi32/freetype.c:7001 error: patch failed: dlls/gdi32/freetype.c:7546 error: patch failed: dlls/gdi32/freetype.c:6884 Task: Patch failed to apply
=== debian9 (build log) ===
error: patch failed: dlls/gdi32/freetype.c:6953 error: patch failed: dlls/gdi32/freetype.c:7110 error: patch failed: dlls/gdi32/freetype.c:7124 error: patch failed: dlls/gdi32/freetype.c:7001 error: patch failed: dlls/gdi32/freetype.c:7546 error: patch failed: dlls/gdi32/freetype.c:6884 Task: Patch failed to apply
=== debian9 (build log) ===
error: patch failed: dlls/gdi32/freetype.c:6953 error: patch failed: dlls/gdi32/freetype.c:7110 error: patch failed: dlls/gdi32/freetype.c:7124 error: patch failed: dlls/gdi32/freetype.c:7001 error: patch failed: dlls/gdi32/freetype.c:7546 error: patch failed: dlls/gdi32/freetype.c:6884 Task: Patch failed to apply
If the glyph does not rotate, you do not have to recalculate abcA, abcB. In particular, the added subpixel metrics becomes a problem.
Signed-off-by: Byeongsik Jeon bsjeon@hanmail.net --- dlls/gdi32/freetype.c | 25 ++++++++++++++++--------- dlls/gdi32/tests/font.c | 2 -- 2 files changed, 16 insertions(+), 11 deletions(-)
diff --git a/dlls/gdi32/freetype.c b/dlls/gdi32/freetype.c index 02f7455619..96e414c5d6 100644 --- a/dlls/gdi32/freetype.c +++ b/dlls/gdi32/freetype.c @@ -6894,15 +6894,25 @@ static void compute_gm_abc_metrics( GdiFont *incoming_font, GdiFont *font, { FT_Vector adv, vec, origin;
- if (!needsTransform) + if (!memcmp( transMat, transMatUnrotated, sizeof(FT_Matrix) ) && !tategaki ) { - adv = get_advance_metric( incoming_font, font, metrics, NULL, vertical_metrics ); - gm->gmCellIncX = adv.x >> 6; - gm->gmCellIncY = 0; + if (!needsTransform) + { + adv = get_advance_metric( incoming_font, font, metrics, NULL, vertical_metrics ); + gm->gmCellIncX = adv.x >> 6; + gm->gmCellIncY = 0; + } + else + { + adv = get_advance_metric( incoming_font, font, metrics, transMat, vertical_metrics ); + gm->gmCellIncX = adv.x >> 6; + gm->gmCellIncY = adv.y >> 6; + } + origin.x = bbox.xMin; origin.y = bbox.yMax; abc->abcA = origin.x >> 6; - abc->abcB = (metrics->width + 63) >> 6; + abc->abcB = (bbox.xMax - bbox.xMin) >> 6; } else { @@ -6934,8 +6944,6 @@ static void compute_gm_abc_metrics( GdiFont *incoming_font, GdiFont *font, gm->gmCellIncY = adv.y >> 6;
adv = get_advance_metric( incoming_font, font, metrics, transMatUnrotated, vertical_metrics ); - adv.x = pFT_Vector_Length( &adv ); - adv.y = 0;
vec.x = lsb; vec.y = 0; @@ -6949,9 +6957,8 @@ static void compute_gm_abc_metrics( GdiFont *incoming_font, GdiFont *font, pFT_Vector_Transform( &vec, transMatUnrotated ); abc->abcB = ((pFT_Vector_Length( &vec ) + 63) >> 6) - abc->abcA; } - if (!abc->abcB) abc->abcB = 1; - abc->abcC = (adv.x >> 6) - abc->abcA - abc->abcB; + abc->abcC = (pFT_Vector_Length( &adv ) >> 6) - abc->abcA - abc->abcB;
gm->gmptGlyphOrigin.x = origin.x >> 6; gm->gmptGlyphOrigin.y = origin.y >> 6; diff --git a/dlls/gdi32/tests/font.c b/dlls/gdi32/tests/font.c index f8762eca56..88b19c0482 100644 --- a/dlls/gdi32/tests/font.c +++ b/dlls/gdi32/tests/font.c @@ -1385,11 +1385,9 @@ 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);
Hi,
While running your changed tests on Windows, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=46869
Your paranoid android.
=== build (build log) ===
error: patch failed: dlls/gdi32/freetype.c:6953 error: patch failed: dlls/gdi32/freetype.c:7110 error: patch failed: dlls/gdi32/freetype.c:7124 error: patch failed: dlls/gdi32/freetype.c:7001 error: patch failed: dlls/gdi32/freetype.c:7546 error: patch failed: dlls/gdi32/freetype.c:6884 error: patch failed: dlls/gdi32/freetype.c:6894 Task: Patch failed to apply
=== debian9 (build log) ===
error: patch failed: dlls/gdi32/freetype.c:6953 error: patch failed: dlls/gdi32/freetype.c:7110 error: patch failed: dlls/gdi32/freetype.c:7124 error: patch failed: dlls/gdi32/freetype.c:7001 error: patch failed: dlls/gdi32/freetype.c:7546 error: patch failed: dlls/gdi32/freetype.c:6884 error: patch failed: dlls/gdi32/freetype.c:6894 Task: Patch failed to apply
=== debian9 (build log) ===
error: patch failed: dlls/gdi32/freetype.c:6953 error: patch failed: dlls/gdi32/freetype.c:7110 error: patch failed: dlls/gdi32/freetype.c:7124 error: patch failed: dlls/gdi32/freetype.c:7001 error: patch failed: dlls/gdi32/freetype.c:7546 error: patch failed: dlls/gdi32/freetype.c:6884 error: patch failed: dlls/gdi32/freetype.c:6894 Task: Patch failed to apply
Signed-off-by: Byeongsik Jeon bsjeon@hanmail.net --- The problem with the tategaki glyph is also an issue like [PATCH 9].
dlls/gdi32/freetype.c | 49 +++++++++++++++++++---------------------- dlls/gdi32/tests/font.c | 2 -- 2 files changed, 23 insertions(+), 28 deletions(-)
diff --git a/dlls/gdi32/freetype.c b/dlls/gdi32/freetype.c index 96e414c5d6..8c5eb11e66 100644 --- a/dlls/gdi32/freetype.c +++ b/dlls/gdi32/freetype.c @@ -6893,8 +6893,30 @@ static void compute_gm_abc_metrics( GdiFont *incoming_font, GdiFont *font, GLYPHMETRICS *gm, ABC *abc ) { FT_Vector adv, vec, origin; + FT_Pos lsb;
- if (!memcmp( transMat, transMatUnrotated, sizeof(FT_Matrix) ) && !tategaki ) + if (tategaki && (font->potm || get_outline_text_metrics( font ))) + { + if (vertical_metrics) + lsb = metrics->horiBearingY + metrics->vertBearingY; + else + lsb = metrics->vertAdvance + (font->potm->otmDescent << 6); + vec.x = lsb; + vec.y = font->potm->otmDescent << 6; + TRACE( "Vec %ld,%ld\n", vec.x >> 6, vec.y >> 6 ); + pFT_Vector_Transform( &vec, transMat ); + origin.x = (vec.x + bbox.xMin) & -64; + origin.y = (vec.y + bbox.yMax + 63) & -64; + lsb -= metrics->horiBearingY; + } + else + { + origin.x = bbox.xMin; + origin.y = bbox.yMax; + lsb = metrics->horiBearingX; + } + + if (!memcmp( transMat, transMatUnrotated, sizeof(FT_Matrix) )) { if (!needsTransform) { @@ -6909,36 +6931,11 @@ static void compute_gm_abc_metrics( GdiFont *incoming_font, GdiFont *font, gm->gmCellIncY = adv.y >> 6; }
- origin.x = bbox.xMin; - origin.y = bbox.yMax; abc->abcA = origin.x >> 6; abc->abcB = (bbox.xMax - bbox.xMin) >> 6; } else { - FT_Pos lsb; - - if (tategaki && (font->potm || get_outline_text_metrics( font ))) - { - if (vertical_metrics) - lsb = metrics->horiBearingY + metrics->vertBearingY; - else - lsb = metrics->vertAdvance + (font->potm->otmDescent << 6); - vec.x = lsb; - vec.y = font->potm->otmDescent << 6; - TRACE( "Vec %ld,%ld\n", vec.x>>6, vec.y>>6 ); - pFT_Vector_Transform( &vec, transMat ); - origin.x = (vec.x + bbox.xMin) & -64; - origin.y = (vec.y + bbox.yMax + 63) & -64; - lsb -= metrics->horiBearingY; - } - else - { - origin.x = bbox.xMin; - origin.y = bbox.yMax; - lsb = metrics->horiBearingX; - } - adv = get_advance_metric( incoming_font, font, metrics, transMat, vertical_metrics ); gm->gmCellIncX = adv.x >> 6; gm->gmCellIncY = adv.y >> 6; diff --git a/dlls/gdi32/tests/font.c b/dlls/gdi32/tests/font.c index 88b19c0482..72957688de 100644 --- a/dlls/gdi32/tests/font.c +++ b/dlls/gdi32/tests/font.c @@ -6137,10 +6137,8 @@ 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,
Hi,
While running your changed tests on Windows, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=46870
Your paranoid android.
=== build (build log) ===
error: patch failed: dlls/gdi32/freetype.c:6953 error: patch failed: dlls/gdi32/freetype.c:7110 error: patch failed: dlls/gdi32/freetype.c:7124 error: patch failed: dlls/gdi32/freetype.c:7001 error: patch failed: dlls/gdi32/freetype.c:7546 error: patch failed: dlls/gdi32/freetype.c:6884 error: patch failed: dlls/gdi32/freetype.c:6894 error: patch failed: dlls/gdi32/freetype.c:6893 Task: Patch failed to apply
=== debian9 (build log) ===
error: patch failed: dlls/gdi32/freetype.c:6953 error: patch failed: dlls/gdi32/freetype.c:7110 error: patch failed: dlls/gdi32/freetype.c:7124 error: patch failed: dlls/gdi32/freetype.c:7001 error: patch failed: dlls/gdi32/freetype.c:7546 error: patch failed: dlls/gdi32/freetype.c:6884 error: patch failed: dlls/gdi32/freetype.c:6894 error: patch failed: dlls/gdi32/freetype.c:6893 Task: Patch failed to apply
=== debian9 (build log) ===
error: patch failed: dlls/gdi32/freetype.c:6953 error: patch failed: dlls/gdi32/freetype.c:7110 error: patch failed: dlls/gdi32/freetype.c:7124 error: patch failed: dlls/gdi32/freetype.c:7001 error: patch failed: dlls/gdi32/freetype.c:7546 error: patch failed: dlls/gdi32/freetype.c:6884 error: patch failed: dlls/gdi32/freetype.c:6894 error: patch failed: dlls/gdi32/freetype.c:6893 Task: Patch failed to apply
Signed-off-by: Byeongsik Jeon bsjeon@hanmail.net --- Since previous patches have modified the glyph metrics consistency problem, we can caching the glyph metrics by GGO format.
dlls/gdi32/freetype.c | 137 +++++++++++++++++++++++++++++------------- 1 file changed, 96 insertions(+), 41 deletions(-)
diff --git a/dlls/gdi32/freetype.c b/dlls/gdi32/freetype.c index 8c5eb11e66..d3d9e391f7 100644 --- a/dlls/gdi32/freetype.c +++ b/dlls/gdi32/freetype.c @@ -306,6 +306,17 @@ typedef struct tagFamily { struct list *replacement; } Family;
+enum GM_type +{ + GM_TYPE_MONO, + GM_TYPE_GRAY, + GM_TYPE_LCD, + GM_TYPE_LCD_V, + GM_TYPE_OUTLINE, + GM_TYPE_NONE +}; +#define GM_NBTYPES GM_TYPE_NONE + typedef struct { GLYPHMETRICS gm; ABC abc; /* metrics of the unrotated char */ @@ -404,8 +415,8 @@ struct tagGdiFont { struct list entry; struct list unused_entry; unsigned int refcount; - GM **gm; - DWORD gmsize; + GM **gm[GM_NBTYPES]; + DWORD gmsize[GM_NBTYPES]; OUTLINETEXTMETRICW *potm; DWORD total_kern_pairs; KERNINGPAIR *kern_pairs; @@ -4665,11 +4676,16 @@ static int get_nearest_charset(const WCHAR *family_name, Face *face, int *cp)
static GdiFont *alloc_font(void) { + DWORD type; + GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret)); ret->refcount = 1; - ret->gmsize = 1; - ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*)); - ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE); + for (type = 0; type < GM_NBTYPES; type++) + { + ret->gmsize[type] = 1; + ret->gm[type] = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM *) ); + ret->gm[type][0] = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE ); + } ret->potm = NULL; ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0; ret->total_kern_pairs = (DWORD)-1; @@ -4682,7 +4698,7 @@ static GdiFont *alloc_font(void) static void free_font(GdiFont *font) { CHILD_FONT *child, *child_next; - DWORD i; + DWORD type, block;
LIST_FOR_EACH_ENTRY_SAFE( child, child_next, &font->child_fonts, CHILD_FONT, entry ) { @@ -4700,26 +4716,62 @@ static void free_font(GdiFont *font) HeapFree(GetProcessHeap(), 0, font->kern_pairs); HeapFree(GetProcessHeap(), 0, font->potm); HeapFree(GetProcessHeap(), 0, font->name); - for (i = 0; i < font->gmsize; i++) - HeapFree(GetProcessHeap(),0,font->gm[i]); - HeapFree(GetProcessHeap(), 0, font->gm); + + for (type = 0; type < GM_NBTYPES; type++) + { + for (block = 0; block < font->gmsize[type]; block++) + HeapFree( GetProcessHeap(), 0, font->gm[type][block] ); + HeapFree( GetProcessHeap(), 0, font->gm[type] ); + } + HeapFree(GetProcessHeap(), 0, font->GSUB_Table); HeapFree(GetProcessHeap(), 0, font); }
-/* TODO: ggo format support */ -static GM *get_cached_gm_abc_metrics( GdiFont *font, UINT index, +static UINT get_GM_type( UINT format ) +{ + switch (format) + { + case GGO_BITMAP: + return GM_TYPE_MONO; + + case GGO_GRAY2_BITMAP: + case GGO_GRAY4_BITMAP: + case GGO_GRAY8_BITMAP: + return GM_TYPE_GRAY; + + case WINE_GGO_HRGB_BITMAP: + case WINE_GGO_HBGR_BITMAP: + return GM_TYPE_LCD; + + case WINE_GGO_VRGB_BITMAP: + case WINE_GGO_VBGR_BITMAP: + return GM_TYPE_LCD_V; + + case GGO_NATIVE: + case GGO_BEZIER: + return GM_TYPE_OUTLINE; + + default: + return GM_TYPE_NONE; + } +} + +static GM *get_cached_gm_abc_metrics( GdiFont *font, UINT index, UINT format, GLYPHMETRICS *gm, ABC *abc ) { + UINT type = get_GM_type( format ); UINT block = index / GM_BLOCK_SIZE; UINT entry = index % GM_BLOCK_SIZE; GM *ret = NULL;
- if (block < font->gmsize && font->gm[block] && font->gm[block][entry].init) + if (type == GM_TYPE_NONE) return NULL; + + if (block < font->gmsize[type] && font->gm[type][block] && font->gm[type][block][entry].init) { - *gm = font->gm[block][entry].gm; - *abc = font->gm[block][entry].abc; - ret = &font->gm[block][entry]; + *gm = font->gm[type][block][entry].gm; + *abc = font->gm[type][block][entry].abc; + ret = &font->gm[type][block][entry];
TRACE( "cached gm: %u,%u,%s,%d,%d\n", gm->gmBlackBoxX, gm->gmBlackBoxY, wine_dbgstr_point( &gm->gmptGlyphOrigin ), @@ -4730,32 +4782,37 @@ static GM *get_cached_gm_abc_metrics( GdiFont *font, UINT index, return ret; }
-static void cache_gm_abc_metrics( GdiFont *font, UINT index, +static void cache_gm_abc_metrics( GdiFont *font, UINT index, UINT format, const GLYPHMETRICS *gm, const ABC *abc ) { + UINT type = get_GM_type( format ); UINT block = index / GM_BLOCK_SIZE; UINT entry = index % GM_BLOCK_SIZE;
- if (block >= font->gmsize) + if (type == GM_TYPE_NONE) return; + + if (block >= font->gmsize[type]) { GM **ptr = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, - font->gm, (block + 1) * sizeof(GM*) ); + font->gm[type], (block + 1) * sizeof(GM*) ); if (!ptr) return;
- font->gmsize = block + 1; - font->gm = ptr; + font->gmsize[type] = block + 1; + font->gm[type] = ptr; }
- if (!font->gm[block]) + if (!font->gm[type][block]) { - font->gm[block] = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof(GM) * GM_BLOCK_SIZE ); - if (!font->gm[block]) return; + font->gm[type][block] = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof(GM) * GM_BLOCK_SIZE ); + if (!font->gm[type][block]) return; }
- font->gm[block][entry].gm = *gm; - font->gm[block][entry].abc = *abc; - font->gm[block][entry].init = TRUE; + if (font->gm[type][block][entry].init) return; + + font->gm[type][block][entry].gm = *gm; + font->gm[type][block][entry].abc = *abc; + font->gm[type][block][entry].init = TRUE; }
static DWORD get_font_data( GdiFont *font, DWORD table, DWORD offset, LPVOID buf, DWORD cbData) @@ -7551,17 +7608,13 @@ static DWORD get_ggo_glyph_from_bitmap( FT_GlyphSlot glyph, UINT format, FT_BBox return needed; }
-static FT_Int get_load_flags( UINT format, GdiFont *font ) +static FT_Int get_load_flags( UINT format, BOOL ggo_unhinted, BOOL natural_width ) { - BOOL natural_width; FT_Int load_flags = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
- if (format & GGO_UNHINTED) + if (ggo_unhinted) return load_flags | FT_LOAD_NO_HINTING;
- natural_width = font->font_desc.lf.lfQuality == CLEARTYPE_NATURAL_QUALITY; - - format &= ~(GGO_GLYPH_INDEX | WINE_GGO_METRICS); switch (format) { case WINE_GGO_HRGB_BITMAP: @@ -7593,7 +7646,7 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format, DWORD needed = 0; FT_Error err; FT_BBox bbox; - FT_Int load_flags = get_load_flags(format, incoming_font); + FT_Int load_flags; FT_Matrix transMat = identityMat; FT_Matrix transMatUnrotated; FT_Matrix transMatTategaki; @@ -7601,6 +7654,9 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format, BOOL tategaki = (font->name[0] == '@'); BOOL vertical_metrics; BOOL ggo_metrics = format & WINE_GGO_METRICS; + BOOL ggo_unhinted = format & GGO_UNHINTED; + BOOL natural_width = incoming_font->font_desc.lf.lfQuality == CLEARTYPE_NATURAL_QUALITY; + BOOL can_use_cache = is_identity_MAT2(lpmat) && !(ggo_unhinted || natural_width);
TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm, buflen, buf, lpmat); @@ -7617,7 +7673,6 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format, TRACE("translate glyph index %04x -> %04x\n", glyph, glyph_index); } else glyph_index = glyph; - format &= ~GGO_GLYPH_INDEX; /* TODO: Window also turns off tategaki for glyphs passed in by index if their unicode code points fall outside of the range that is rotated. */ @@ -7629,10 +7684,10 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format, tategaki = check_unicode_tategaki(glyph); }
- format &= ~(WINE_GGO_METRICS | GGO_UNHINTED); + format &= ~(WINE_GGO_METRICS | GGO_UNHINTED | GGO_GLYPH_INDEX);
- if (ggo_metrics && is_identity_MAT2(lpmat) && - get_cached_gm_abc_metrics( font, glyph_index, lpgm, abc )) + if (ggo_metrics && can_use_cache && + get_cached_gm_abc_metrics( font, glyph_index, format, lpgm, abc )) return 1; /* FIXME */
needsTransform = get_transform_matrix( font, tategaki, lpmat, @@ -7644,6 +7699,7 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format, if (vertical_metrics && FT_SimpleVersion < FT_VERSION_VALUE(2, 4 ,0)) vertical_metrics = FALSE;
+ load_flags = get_load_flags( format, ggo_unhinted, natural_width ); if (needsTransform || format != GGO_BITMAP) load_flags |= FT_LOAD_NO_BITMAP; if (vertical_metrics) load_flags |= FT_LOAD_VERTICAL_LAYOUT;
@@ -7698,9 +7754,8 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format, &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 (can_use_cache && needed != GDI_ERROR) + cache_gm_abc_metrics( font, glyph_index, format, &gm, abc );
if (ggo_metrics || needed != GDI_ERROR) *lpgm = gm;
Hi,
While running your changed tests on Windows, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=46871
Your paranoid android.
=== debian9 (build log) ===
error: patch failed: dlls/gdi32/freetype.c:6953 error: patch failed: dlls/gdi32/freetype.c:7110 error: patch failed: dlls/gdi32/freetype.c:7124 error: patch failed: dlls/gdi32/freetype.c:7001 error: patch failed: dlls/gdi32/freetype.c:7546 error: patch failed: dlls/gdi32/freetype.c:6884 error: patch failed: dlls/gdi32/freetype.c:6894 error: patch failed: dlls/gdi32/freetype.c:6893 error: patch failed: dlls/gdi32/freetype.c:4700 Task: Patch failed to apply
=== debian9 (build log) ===
error: patch failed: dlls/gdi32/freetype.c:6953 error: patch failed: dlls/gdi32/freetype.c:7110 error: patch failed: dlls/gdi32/freetype.c:7124 error: patch failed: dlls/gdi32/freetype.c:7001 error: patch failed: dlls/gdi32/freetype.c:7546 error: patch failed: dlls/gdi32/freetype.c:6884 error: patch failed: dlls/gdi32/freetype.c:6894 error: patch failed: dlls/gdi32/freetype.c:6893 error: patch failed: dlls/gdi32/freetype.c:4700 Task: Patch failed to apply
https://docs.microsoft.com/en-us/windows/desktop/api/wingdi/ns-wingdi-taglog...
The following situations do not support ClearType antialiasing:
The font has tuned embedded bitmaps, for any font sizes that contain the embedded bitmaps. For example, this occurs commonly in East Asian fonts.
Wine-bug: https://bugs.winehq.org/show_bug.cgi?id=28009 Signed-off-by: Byeongsik Jeon bsjeon@hanmail.net --- [1] This patch affects the WineTahoma rendering. This is a normal operation. Instead of loading the embedded bitmap, the metrics returns to normal.
[2] This is a different topic from the use of get_gasp_flags in freetype_SelectFont. This determines whether to load the embedded bitmap.
This issue has been an issue for a long time in the Windows CJK legacy builtin fonts. For some wrong programs, these fonts are programmed under the assumption that they are rendered as bitmap. Ex. Space Funeral.
[3] If the font with embedded bitmap has gasp DO_GRAY bits set, does not use the bitmap. Ex. Calibri.
dlls/gdi32/freetype.c | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-)
diff --git a/dlls/gdi32/freetype.c b/dlls/gdi32/freetype.c index d3d9e391f7..45709a0a92 100644 --- a/dlls/gdi32/freetype.c +++ b/dlls/gdi32/freetype.c @@ -7608,6 +7608,38 @@ static DWORD get_ggo_glyph_from_bitmap( FT_GlyphSlot glyph, UINT format, FT_BBox return needed; }
+static FT_Int get_embedded_bitmap_load_flags( UINT format, GdiFont *font, BOOL needsTransform ) +{ + FT_Int load_flags = 0; + WORD gasp_flags; + + if ( needsTransform ) + return FT_LOAD_NO_BITMAP; + + switch (format) + { + case GGO_BITMAP: + break; + case GGO_GRAY2_BITMAP: + case GGO_GRAY4_BITMAP: + case GGO_GRAY8_BITMAP: + case GGO_NATIVE: + case GGO_BEZIER: + load_flags = FT_LOAD_NO_BITMAP; + break; + case WINE_GGO_GRAY16_BITMAP: + case WINE_GGO_HRGB_BITMAP: + case WINE_GGO_HBGR_BITMAP: + case WINE_GGO_VRGB_BITMAP: + case WINE_GGO_VBGR_BITMAP: + if (get_gasp_flags( font, &gasp_flags ) && (gasp_flags & GASP_DOGRAY)) + load_flags = FT_LOAD_NO_BITMAP; + break; + } + + return load_flags; +} + static FT_Int get_load_flags( UINT format, BOOL ggo_unhinted, BOOL natural_width ) { FT_Int load_flags = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH; @@ -7700,7 +7732,7 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format, vertical_metrics = FALSE;
load_flags = get_load_flags( format, ggo_unhinted, natural_width ); - if (needsTransform || format != GGO_BITMAP) load_flags |= FT_LOAD_NO_BITMAP; + load_flags |= get_embedded_bitmap_load_flags( format, font, needsTransform ); if (vertical_metrics) load_flags |= FT_LOAD_VERTICAL_LAYOUT;
err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
Hi,
While running your changed tests on Windows, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=46872
Your paranoid android.
=== debian9 (build log) ===
error: patch failed: dlls/gdi32/freetype.c:6953 error: patch failed: dlls/gdi32/freetype.c:7110 error: patch failed: dlls/gdi32/freetype.c:7124 error: patch failed: dlls/gdi32/freetype.c:7001 error: patch failed: dlls/gdi32/freetype.c:7546 error: patch failed: dlls/gdi32/freetype.c:6884 error: patch failed: dlls/gdi32/freetype.c:6894 error: patch failed: dlls/gdi32/freetype.c:6893 error: patch failed: dlls/gdi32/freetype.c:4700 error: patch failed: dlls/gdi32/freetype.c:7608 Task: Patch failed to apply
=== debian9 (build log) ===
error: patch failed: dlls/gdi32/freetype.c:6953 error: patch failed: dlls/gdi32/freetype.c:7110 error: patch failed: dlls/gdi32/freetype.c:7124 error: patch failed: dlls/gdi32/freetype.c:7001 error: patch failed: dlls/gdi32/freetype.c:7546 error: patch failed: dlls/gdi32/freetype.c:6884 error: patch failed: dlls/gdi32/freetype.c:6894 error: patch failed: dlls/gdi32/freetype.c:6893 error: patch failed: dlls/gdi32/freetype.c:4700 error: patch failed: dlls/gdi32/freetype.c:7608 Task: Patch failed to apply
Hi,
While running your changed tests on Windows, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=46861
Your paranoid android.
=== debian9 (build log) ===
error: patch failed: dlls/gdi32/freetype.c:6953 Task: Patch failed to apply
=== debian9 (build log) ===
error: patch failed: dlls/gdi32/freetype.c:6953 Task: Patch failed to apply
This is a problem that has arisen because my previous three patches have not yet been applied.
Should I send the whole patch with previous patches?
Marvin wrote:
Hi,
While running your changed tests on Windows, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=46861
Your paranoid android.
=== debian9 (build log) ===
error: patch failed: dlls/gdi32/freetype.c:6953 Task: Patch failed to apply
=== debian9 (build log) ===
error: patch failed: dlls/gdi32/freetype.c:6953 Task: Patch failed to apply
On Tue, Jan 29, 2019 at 06:51:59PM +0900, Byeongsik Jeon wrote:
This is a problem that has arisen because my previous three patches have not yet been applied.
Should I send the whole patch with previous patches?
Please don't send a patch-set that relies on earlier, uncommitted patches. Since the total number of patches is now 15, I suggest sending prehaps 6 or 7 at first to avoid spamming the list.
In a quick look at your first set, I'd suggest swapping [2/3] and [3/3] (and possibly moving them before [1/3]).
Thanks, Huw.