[PATCH v2 3/7] gdi32: Add helper functions to compute the glyph metrics.

Byeongsik Jeon bsjeon at hanmail.net
Tue Jan 29 11:12:37 CST 2019


Signed-off-by: Byeongsik Jeon <bsjeon at hanmail.net>
---
 dlls/gdi32/freetype.c | 250 ++++++++++++++++++++++++------------------
 1 file changed, 145 insertions(+), 105 deletions(-)

diff --git a/dlls/gdi32/freetype.c b/dlls/gdi32/freetype.c
index 7e07b22409..f996df62fe 100644
--- a/dlls/gdi32/freetype.c
+++ b/dlls/gdi32/freetype.c
@@ -6873,6 +6873,135 @@ static FT_Vector get_advance_metric(GdiFont *incoming_font, GdiFont *font,
     return adv;
 }
 
+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;
+}
+
+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_Vector adv, vec, origin;
+
+    if (!needsTransform)
+    {
+        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
+    {
+        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;
+
+        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 );
+}
+
 static unsigned int get_native_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
 {
     TTPOLYGONHEADER *pph;
@@ -7116,9 +7245,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);
     FT_Matrix transMat = identityMat;
     FT_Matrix transMatUnrotated;
@@ -7191,8 +7318,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;
 
@@ -7200,102 +7327,15 @@ 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;
-        }
+    bbox = get_transformed_bbox( &metrics, needsTransform, &transMatTategaki );
 
-	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;
+    compute_gm_abc_metrics( incoming_font, font, bbox, &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 */
@@ -7358,7 +7398,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);
@@ -7419,7 +7459,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);
 
@@ -7510,13 +7550,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;
@@ -7558,7 +7598,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;
@@ -7570,7 +7610,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;
-- 
2.20.1




More information about the wine-devel mailing list