[PATCH v3 1/5] gdi32: Add a helper function to get the transform matrices.

Byeongsik Jeon bsjeon at hanmail.net
Thu Feb 7 06:41:32 CST 2019


Signed-off-by: Byeongsik Jeon <bsjeon at 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);
 
-- 
2.20.1




More information about the wine-devel mailing list