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

Huw Davies huw at codeweavers.com
Wed Feb 6 03:51:45 CST 2019


On Wed, Jan 30, 2019 at 02:12:37AM +0900, Byeongsik Jeon wrote:
> 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 )

Again, needs_transform.  Let's pass the entries matrices array here for simpicity.

> +{
> +    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 );

Add a space after comma.

> +                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 );

Again, spaces after commas.

> +    }
> +
> +    return bbox;
> +}
> +
> +static void compute_gm_abc_metrics( GdiFont *incoming_font, GdiFont *font,

I think compute_metrics should be fine.

> +                                    FT_BBox bbox, const FT_Glyph_Metrics *metrics,
> +                                    BOOL tategaki, BOOL vertical_metrics, BOOL needsTransform,

takegaki -> vertical
> +                                    const FT_Matrix *transMat,
> +                                    const FT_Matrix *transMatTategaki,
> +                                    const FT_Matrix *transMatUnrotated,

These three become the array.

> +                                    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 );

Use the same format here as in get_cached_metrics.

> +}
> +
>  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