Signed-off-by: Byeongsik Jeon bsjeon@hanmail.net --- v3: Huw's comments are applied.
Thank you.
'Vertical' transform position issue: Vertical transform must be separated from the rotation transform and applied before the scale transform. This is an issue at lfWidth != 0. I'll post related patch later.
[v2 PATCH 4/7] is included in this patch. [v2 PATCH 7/7] has been cancelled. It's not an improvement.
dlls/gdi32/freetype.c | 284 +++++++++++++++++++++--------------------- 1 file changed, 144 insertions(+), 140 deletions(-)
diff --git a/dlls/gdi32/freetype.c b/dlls/gdi32/freetype.c index de62425173..c1a3a548eb 100644 --- a/dlls/gdi32/freetype.c +++ b/dlls/gdi32/freetype.c @@ -241,6 +241,14 @@ MAKE_FUNCPTR(FcPatternGetString); #define WINE_FONT_DIR "fonts" #endif
+/* get_glyph_outline() glyph transform matrices index */ +enum +{ + matrix_hori, + matrix_vert, + matrix_unrotated +}; + /* This is basically a copy of FT_Bitmap_Size with an extra element added */ typedef struct { FT_Short height; @@ -6588,6 +6596,111 @@ static inline FT_Vector normalize_vector(FT_Vector *vec) return out; }
+static BOOL get_transform_matrices( GdiFont *font, BOOL vertical, const MAT2 *user_transform, + FT_Matrix matrices[3] ) +{ + static const FT_Matrix identity_mat = { (1 << 16), 0, 0, (1 << 16) }; + BOOL needs_transform = FALSE; + double width_ratio; + int i; + + matrices[matrix_unrotated] = identity_mat; + + /* Scaling factor */ + if (font->aveWidth) + { + TEXTMETRICW tm; + get_text_metrics( font, &tm ); + + width_ratio = (double)font->aveWidth; + width_ratio /= (double)font->potm->otmTextMetrics.tmAveCharWidth; + } + else + width_ratio = font->scale_y; + + /* Scaling transform */ + if (width_ratio != 1.0 || font->scale_y != 1.0) + { + FT_Matrix scale_mat; + scale_mat.xx = FT_FixedFromFloat( width_ratio ); + scale_mat.xy = 0; + scale_mat.yx = 0; + scale_mat.yy = FT_FixedFromFloat( font->scale_y ); + + pFT_Matrix_Multiply( &scale_mat, &matrices[matrix_unrotated] ); + needs_transform = TRUE; + } + + /* Slant transform */ + if (font->fake_italic) + { + FT_Matrix slant_mat; + slant_mat.xx = (1 << 16); + slant_mat.xy = (1 << 16) >> 2; + slant_mat.yx = 0; + slant_mat.yy = (1 << 16); + + pFT_Matrix_Multiply( &slant_mat, &matrices[matrix_unrotated] ); + needs_transform = TRUE; + } + + /* Rotation transform */ + matrices[matrix_hori] = matrices[matrix_unrotated]; + if (font->orientation % 3600) + { + FT_Matrix rotation_mat; + FT_Vector angle; + + pFT_Vector_Unit( &angle, MulDiv( 1 << 16, font->orientation, 10 ) ); + rotation_mat.xx = angle.x; + rotation_mat.xy = -angle.y; + rotation_mat.yx = angle.y; + rotation_mat.yy = angle.x; + pFT_Matrix_Multiply( &rotation_mat, &matrices[matrix_hori] ); + needs_transform = TRUE; + } + + /* Vertical transform */ + matrices[matrix_vert] = matrices[matrix_hori]; + if (vertical) + { + FT_Matrix vertical_mat = { 0, -(1 << 16), 1 << 16, 0 }; /* 90 degrees rotation */ + + pFT_Matrix_Multiply( &vertical_mat, &matrices[matrix_vert] ); + needs_transform = TRUE; + } + + /* World transform */ + if (!is_identity_FMAT2( &font->font_desc.matrix )) + { + FT_Matrix world_mat; + world_mat.xx = FT_FixedFromFloat( font->font_desc.matrix.eM11 ); + world_mat.xy = -FT_FixedFromFloat( font->font_desc.matrix.eM21 ); + world_mat.yx = -FT_FixedFromFloat( font->font_desc.matrix.eM12 ); + world_mat.yy = FT_FixedFromFloat( font->font_desc.matrix.eM22 ); + + for (i = 0; i < 3; i++) + pFT_Matrix_Multiply( &world_mat, &matrices[i] ); + needs_transform = TRUE; + } + + /* Extra transformation specified by caller */ + if (!is_identity_MAT2( user_transform )) + { + FT_Matrix user_mat; + user_mat.xx = FT_FixedFromFIXED( user_transform->eM11 ); + user_mat.xy = FT_FixedFromFIXED( user_transform->eM21 ); + user_mat.yx = FT_FixedFromFIXED( user_transform->eM12 ); + user_mat.yy = FT_FixedFromFIXED( user_transform->eM22 ); + + for (i = 0; i < 3; i++) + pFT_Matrix_Multiply( &user_mat, &matrices[i] ); + needs_transform = TRUE; + } + + return needs_transform; +} + static BOOL get_bold_glyph_outline(FT_GlyphSlot glyph, LONG ppem, FT_Glyph_Metrics *metrics) { FT_Error err; @@ -6629,7 +6742,7 @@ static inline BYTE get_max_level( UINT format )
extern const unsigned short vertical_orientation_table[] DECLSPEC_HIDDEN;
-static BOOL check_unicode_tategaki(WCHAR uchar) +static BOOL check_unicode_vertical_orientation( WCHAR uchar ) { unsigned short orientation = vertical_orientation_table[vertical_orientation_table[vertical_orientation_table[uchar >> 8]+((uchar >> 4) & 0x0f)]+ (uchar & 0xf)];
@@ -6934,7 +7047,6 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format, LPGLYPHMETRICS lpgm, ABC *abc, DWORD buflen, LPVOID buf, const MAT2* lpmat) { - static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)}; GLYPHMETRICS gm; FT_Face ft_face = incoming_font->ft_face; GdiFont *font = incoming_font; @@ -6946,14 +7058,10 @@ 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); - double widthRatio = 1.0; - FT_Matrix transMat = identityMat; - FT_Matrix transMatUnrotated; - FT_Matrix transMatTategaki; - BOOL needsTransform = FALSE; - BOOL tategaki = (font->name[0] == '@'); + FT_Matrix matrices[3]; + BOOL needs_transform = FALSE; + BOOL vertical = (font->name[0] == '@'); BOOL vertical_metrics; UINT original_index;
@@ -6974,7 +7082,7 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format, glyph_index = glyph; original_index = glyph_index; format &= ~GGO_GLYPH_INDEX; - /* TODO: Window also turns off tategaki for glyphs passed in by index + /* TODO: Window also turns off vertical for glyphs passed in by index if their unicode code points fall outside of the range that is rotated. */ } else { @@ -6982,8 +7090,8 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format, 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); + if (!vert && vertical) + vertical = check_unicode_vertical_orientation( glyph ); }
format &= ~GGO_UNHINTED; @@ -7008,121 +7116,15 @@ 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; - } + needs_transform = get_transform_matrices( font, vertical, lpmat, matrices );
- vertical_metrics = (tategaki && FT_HAS_VERTICAL(ft_face)); + vertical_metrics = (vertical && FT_HAS_VERTICAL(ft_face)); /* there is a freetype bug where vertical metrics are only properly scaled and correct in 2.4.0 or greater */ if ((vertical_metrics) && (FT_Version.major < 2 || (FT_Version.major == 2 && FT_Version.minor < 4))) vertical_metrics = FALSE;
- if (needsTransform || format != GGO_BITMAP) load_flags |= FT_LOAD_NO_BITMAP; + if (needs_transform || format != GGO_BITMAP) load_flags |= FT_LOAD_NO_BITMAP; if (vertical_metrics) load_flags |= FT_LOAD_VERTICAL_LAYOUT;
err = pFT_Load_Glyph(ft_face, glyph_index, load_flags); @@ -7153,7 +7155,7 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format, /* metrics.width = min( metrics.width, ptm->tmMaxCharWidth << 6 ); */ }
- if(!needsTransform) { + if (!needs_transform) { left = (INT)(metrics.horiBearingX) & -64; right = (INT)((metrics.horiBearingX + metrics.width) + 63) & -64; top = (metrics.horiBearingY + 63) & -64; @@ -7177,7 +7179,7 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format, 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); + pFT_Vector_Transform( &vec, &matrices[matrix_vert] ); if(xc == 0 && yc == 0) { left = right = vec.x; top = bottom = vec.y; @@ -7194,7 +7196,7 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format, bottom = bottom & -64; top = (top + 63) & -64;
- if (tategaki && (font->potm || get_outline_text_metrics(font))) + if (vertical && (font->potm || get_outline_text_metrics(font))) { if (vertical_metrics) lsb = metrics.horiBearingY + metrics.vertBearingY; @@ -7203,7 +7205,7 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format, 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); + pFT_Vector_Transform( &vec, &matrices[matrix_hori] ); origin_x = (vec.x + left) & -64; origin_y = (vec.y + top + 63) & -64; lsb -= metrics.horiBearingY; @@ -7216,24 +7218,26 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format, }
TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom); - adv = get_advance_metric(incoming_font, font, &metrics, &transMat, vertical_metrics); + adv = get_advance_metric( incoming_font, font, &metrics, &matrices[matrix_hori], + vertical_metrics); gm.gmCellIncX = adv.x >> 6; gm.gmCellIncY = adv.y >> 6;
- adv = get_advance_metric(incoming_font, font, &metrics, &transMatUnrotated, vertical_metrics); + adv = get_advance_metric( incoming_font, font, &metrics, &matrices[matrix_unrotated], + vertical_metrics); adv.x = pFT_Vector_Length(&adv); adv.y = 0;
vec.x = lsb; vec.y = 0; - pFT_Vector_Transform(&vec, &transMatUnrotated); + pFT_Vector_Transform( &vec, &matrices[matrix_unrotated] ); 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.x = lsb + (vertical ? metrics.height : metrics.width); vec.y = 0; - pFT_Vector_Transform(&vec, &transMatUnrotated); + pFT_Vector_Transform( &vec, &matrices[matrix_unrotated] ); abc->abcB = ((pFT_Vector_Length(&vec) + 63) >> 6) - abc->abcA; }
@@ -7312,8 +7316,8 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format, ft_bitmap.pixel_mode = ft_pixel_mode_mono; ft_bitmap.buffer = buf;
- if(needsTransform) - pFT_Outline_Transform(&ft_face->glyph->outline, &transMatTategaki); + if (needs_transform) + pFT_Outline_Transform( &ft_face->glyph->outline, &matrices[matrix_vert] );
pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
@@ -7373,8 +7377,8 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format, ft_bitmap.pixel_mode = ft_pixel_mode_grays; ft_bitmap.buffer = buf;
- if(needsTransform) - pFT_Outline_Transform(&ft_face->glyph->outline, &transMatTategaki); + if (needs_transform) + pFT_Outline_Transform( &ft_face->glyph->outline, &matrices[matrix_vert] );
pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
@@ -7488,8 +7492,8 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format, memset(buf, 0, buflen); dst = buf;
- if ( needsTransform ) - pFT_Outline_Transform (&ft_face->glyph->outline, &transMatTategaki); + if (needs_transform) + pFT_Outline_Transform( &ft_face->glyph->outline, &matrices[matrix_vert] );
#ifdef FT_LCD_FILTER_H if ( pFT_Library_SetLcdFilter ) @@ -7574,8 +7578,8 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
if(buflen == 0) buf = NULL;
- if (needsTransform && buf) - pFT_Outline_Transform(outline, &transMatTategaki); + if (needs_transform && buf) + pFT_Outline_Transform( outline, &matrices[matrix_vert] );
needed = get_native_glyph_outline(outline, buflen, NULL);
@@ -7592,8 +7596,8 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format, FT_Outline *outline = &ft_face->glyph->outline; if(buflen == 0) buf = NULL;
- if (needsTransform && buf) - pFT_Outline_Transform(outline, &transMat); + if (needs_transform && buf) + pFT_Outline_Transform( outline, &matrices[matrix_vert] );
needed = get_bezier_glyph_outline(outline, buflen, NULL);