ChangeLog: Added support for average width specification when creating a font using CreateFontIndirect. That is, scale the font horizontaly according to the average width value specified by the user in the input LOGFONT. Force the font average width to be at least one. It happened to be zero sometimes for a significantly small x-scale factor between logical and device coordinates, which was causing a division by zero when calculating the width scaling factor in GetGlyphOutline. Description: It implies keeping the average width specified in the LOGFONT inside the GdiFont internal structure. In GetGlyphOutline, scale the output bounding box and the output outline horizontaly with a proper width ratio calculated using the desired width average in logical coordinates, the actual width average for that font in device coordinates and the x-scale factor between logical and device coordinates. Also, in GetTextMetrics, return the user-speficied average width (if so) instead of the actual average width. It behaves that way on Windows. Warren Baird : Warren_Baird@cimmetry.com Dave Belanger diff -ur clean/wine/dlls/gdi/freetype.c wine/dlls/gdi/freetype.c --- clean/wine/dlls/gdi/freetype.c 24 Jan 2003 15:12:16 -0000 1.1.1.3 +++ wine/dlls/gdi/freetype.c 28 Jan 2003 19:04:55 -0000 @@ -143,6 +143,7 @@ GM *gm; DWORD gmsize; HFONT hfont; + LONG aveWidth; SHORT yMax; SHORT yMin; OUTLINETEXTMETRICW *potm; @@ -1105,6 +1106,7 @@ TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont); ret->hfont = hfont; + ret->aveWidth = lf.lfWidth; ret->next = GdiFontList; GdiFontList = ret; @@ -1379,6 +1381,7 @@ INT left, right, top = 0, bottom = 0; FT_Angle angle = 0; FT_Int load_flags = FT_LOAD_DEFAULT; + float widthRatio = 1.0; TRACE("%p, %04x, %08x, %p, %08lx, %p, %p\n", font, glyph, format, lpgm, buflen, buf, lpmat); @@ -1400,8 +1403,9 @@ } } - if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP)) - load_flags |= FT_LOAD_NO_BITMAP; + if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP) || font->aveWidth) + load_flags |= FT_LOAD_NO_BITMAP; + err = pFT_Load_Glyph(ft_face, glyph_index, load_flags); @@ -1409,12 +1413,16 @@ FIXME("FT_Load_Glyph on index %x returns %d\n", glyph_index, err); return GDI_ERROR; } + + // Scaling the bounding box. + if (font->aveWidth && font->potm) { + widthRatio = (float)font->aveWidth * font->xform.eM11 / (float) font->potm->otmTextMetrics.tmAveCharWidth; + } - left = ft_face->glyph->metrics.horiBearingX & -64; - right = ((ft_face->glyph->metrics.horiBearingX + - ft_face->glyph->metrics.width) + 63) & -64; + left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64; + right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) * widthRatio + 63) & -64; - font->gm[glyph_index].adv = (ft_face->glyph->metrics.horiAdvance + 63) >> 6; + font->gm[glyph_index].adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6; font->gm[glyph_index].lsb = left >> 6; font->gm[glyph_index].bbx = (right - left) >> 6; @@ -1432,8 +1440,8 @@ TRACE("angle %ld\n", angle >> 16); for(xc = 0; xc < 2; xc++) { for(yc = 0; yc < 2; yc++) { - vec.x = ft_face->glyph->metrics.horiBearingX + - xc * ft_face->glyph->metrics.width; + vec.x = (ft_face->glyph->metrics.horiBearingX + + xc * ft_face->glyph->metrics.width) * widthRatio; vec.y = ft_face->glyph->metrics.horiBearingY - yc * ft_face->glyph->metrics.height; TRACE("Vec %ld,%ld\n", vec.x, vec.y); @@ -1455,7 +1463,7 @@ top = (top + 63) & -64; TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom); - vec.x = ft_face->glyph->metrics.horiAdvance; + vec.x = ft_face->glyph->metrics.horiAdvance * widthRatio; vec.y = 0; pFT_Vector_Rotate(&vec, angle); lpgm->gmCellIncX = (vec.x+63) >> 6; @@ -1477,6 +1485,19 @@ return GDI_ERROR; } + // Scaling the outline. + if(ft_face->glyph->format == ft_glyph_format_outline && font->aveWidth) { + FT_Matrix scaleMatrix; + unsigned int roundedOffWidthRatio = (unsigned int)widthRatio; + FT_Fixed fixedWidthRatio = (roundedOffWidthRatio << 16) | + (unsigned int)((widthRatio - roundedOffWidthRatio) * 0xFFFF); + scaleMatrix.xx = fixedWidthRatio; + scaleMatrix.xy = 0; + scaleMatrix.yx = 0; + scaleMatrix.yy = (1 << 16); + pFT_Outline_Transform(&ft_face->glyph->outline, &scaleMatrix); + } + switch(format) { case GGO_BITMAP: width = lpgm->gmBlackBoxX; @@ -1776,6 +1797,10 @@ } if(!font->potm) return FALSE; memcpy(ptm, &font->potm->otmTextMetrics, sizeof(*ptm)); + + if (font->aveWidth) { + ptm->tmAveCharWidth = font->aveWidth * font->xform.eM11; + } return TRUE; } @@ -1890,6 +1915,9 @@ (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6); TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6; + if (TM.tmAveCharWidth == 0) { + TM.tmAveCharWidth = 1; + } TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6; TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass; TM.tmOverhang = 0;