[2/2] gdi32: Add support for emulating bold faces of bitmap fonts. Take 2.

Dmitry Timoshkov dmitry at baikal.ru
Sat Apr 28 03:52:36 CDT 2012


This version of the patch also includes tests and fixes for metrics
of normal and emulated bold bitmaps.
---
 dlls/gdi32/freetype.c   |   35 +++++++++++++++++++-
 dlls/gdi32/tests/font.c |   83 ++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 116 insertions(+), 2 deletions(-)

diff --git a/dlls/gdi32/freetype.c b/dlls/gdi32/freetype.c
index f5a60d0..55c764c 100644
--- a/dlls/gdi32/freetype.c
+++ b/dlls/gdi32/freetype.c
@@ -5672,12 +5672,27 @@ static inline BYTE get_max_level( UINT format )
     return 255;
 }
 
-static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
+static void emulate_bold_glyph(BYTE *buf, int pitch, int height)
+{
+    int x, y;
+    BYTE *p = buf;
+
+    for (y = 0; y < height; y++)
+    {
+        for (x = pitch - 1; x >= 0; x--)
+        {
+            p[x] |= p[x] >> 1;
+            if (x > 0) p[x] |= p[x - 1] << 7;
+        }
+        p += pitch;
+    }
+}
 
 static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
                                LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
                                const MAT2* lpmat)
 {
+    static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
     static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
     FT_Face ft_face = incoming_font->ft_face;
     GdiFont *font = incoming_font;
@@ -5894,6 +5909,13 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
     lpgm->gmptGlyphOrigin.x = left >> 6;
     lpgm->gmptGlyphOrigin.y = top >> 6;
 
+    if (font->fake_bold && !FT_IS_SCALABLE(ft_face) && ft_face->glyph->format == ft_glyph_format_bitmap)
+    {
+        lpgm->gmBlackBoxX += font->potm->otmTextMetrics.tmOverhang;
+        adv += font->potm->otmTextMetrics.tmOverhang;
+        bbx += font->potm->otmTextMetrics.tmOverhang;
+    }
+
     TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
           wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
           lpgm->gmCellIncX, lpgm->gmCellIncY);
@@ -5920,6 +5942,9 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
 	return GDI_ERROR;
     }
 
+    if (font->fake_bold && !FT_IS_SCALABLE(ft_face) && ft_face->glyph->format == ft_glyph_format_bitmap)
+        emulate_bold_glyph(ft_face->glyph->bitmap.buffer, ft_face->glyph->bitmap.pitch, ft_face->glyph->bitmap.rows);
+
     switch(format) {
     case GGO_BITMAP:
         width = lpgm->gmBlackBoxX;
@@ -6428,6 +6453,14 @@ static BOOL get_bitmap_text_metrics(GdiFont *font)
         TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
         TM.tmCharSet = font->charset;
     }
+    if (font->fake_bold && TM.tmWeight == FW_NORMAL)
+    {
+        TM.tmWeight = FW_BOLD;
+        TM.tmAveCharWidth++;
+        TM.tmMaxCharWidth++;
+        TM.tmOverhang++;
+        if (font->aveWidth) font->aveWidth++; /* avoid metrics rescaling */
+    }
 #undef TM
 
     return TRUE;
diff --git a/dlls/gdi32/tests/font.c b/dlls/gdi32/tests/font.c
index b0c6e73..49cb9d0 100644
--- a/dlls/gdi32/tests/font.c
+++ b/dlls/gdi32/tests/font.c
@@ -823,11 +823,14 @@ static void test_bitmap_font_metrics(void)
         /* FIXME: add "Terminal" */
     };
     static const int font_log_pixels[] = { 96, 120 };
+    static const char hello[] = "Hello World!";
+    int normal_width[12], bold_width[12];
+    SIZE normal_size, bold_size;
     HDC hdc;
     LOGFONT lf;
     HFONT hfont, old_hfont;
     TEXTMETRIC tm;
-    INT ret, i, expected_cs, screen_log_pixels, diff, font_res;
+    INT ret, i, n, expected_cs, screen_log_pixels, diff, font_res;
     WORD system_lang_id;
     char face_name[LF_FACESIZE];
     CHARSETINFO csi;
@@ -964,6 +967,17 @@ static void test_bitmap_font_metrics(void)
                        that make the max width bigger */
                     if(strcmp(lf.lfFaceName, "System") || lf.lfCharSet != ANSI_CHARSET)
                         ok(tm.tmMaxCharWidth == fd[i].max_char_width, "%s(%d): tm.tmMaxCharWidth %d != %d\n", fd[i].face_name, height, tm.tmMaxCharWidth, fd[i].max_char_width);
+                    ok(tm.tmOverhang == 0, "%s(%d): tm.tmOverhang %d != 0\n", fd[i].face_name, height, tm.tmOverhang);
+
+                    SetLastError(0xdeadbeef);
+                    ret = GetTextExtentPoint32(hdc, hello, lstrlen(hello), &normal_size);
+                    ok(ret, "GetTextExtentPoint error %u\n", GetLastError());
+                    trace("normal size %dx%d\n", normal_size.cx, normal_size.cy);
+
+                    assert(sizeof(normal_width)/sizeof(normal_width[0]) >= sizeof(hello)-1);
+                    memset(normal_width, 0, sizeof(normal_width));
+                    for (n = 0; n < lstrlen(hello); n++)
+                        GetCharWidth32(hdc, hello[n], hello[n], &normal_width[n]);
                 }
                 else
                     skip("Skipping font metrics test for system langid 0x%x\n",
@@ -971,6 +985,73 @@ static void test_bitmap_font_metrics(void)
             }
             SelectObject(hdc, old_hfont);
             DeleteObject(hfont);
+
+            lf.lfWeight = FW_BOLD;
+            hfont = create_font(lf.lfFaceName, &lf);
+            old_hfont = SelectObject(hdc, hfont);
+            bRet = GetTextMetrics(hdc, &tm);
+            ok(bRet, "GetTextMetrics error %d\n", GetLastError());
+            if (fd[i].dpi == tm.tmDigitizedAspectX)
+            {
+                trace("matched %s, height %d charset %x dpi %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
+                if (fd[i].skip_lang_id == 0 || system_lang_id != fd[i].skip_lang_id)
+                {
+                    if (fd[i].weight == FW_NORMAL)
+                        ok(tm.tmWeight == FW_BOLD, "%s(%d): tm.tmWeight %d != FW_BOLD\n", fd[i].face_name, height, tm.tmWeight);
+                    else
+                        ok(tm.tmWeight == fd[i].weight, "%s(%d): tm.tmWeight %d != %d\n", fd[i].face_name, height, tm.tmWeight, fd[i].weight);
+                    if (fd[i].height & FH_SCALE)
+                        ok(tm.tmHeight == fd[i].scaled_height, "%s(%d): tm.tmHeight %d != %d\n", fd[i].face_name, height, tm.tmHeight, fd[i].scaled_height);
+                    else
+                        ok(tm.tmHeight == fd[i].height, "%s(%d): tm.tmHeight %d != %d\n", fd[i].face_name, fd[i].height, tm.tmHeight, fd[i].height);
+                    ok(tm.tmAscent == fd[i].ascent, "%s(%d): tm.tmAscent %d != %d\n", fd[i].face_name, height, tm.tmAscent, fd[i].ascent);
+                    ok(tm.tmDescent == fd[i].descent, "%s(%d): tm.tmDescent %d != %d\n", fd[i].face_name, height, tm.tmDescent, fd[i].descent);
+                    ok(tm.tmInternalLeading == fd[i].int_leading, "%s(%d): tm.tmInternalLeading %d != %d\n", fd[i].face_name, height, tm.tmInternalLeading, fd[i].int_leading);
+                    ok(tm.tmExternalLeading == fd[i].ext_leading, "%s(%d): tm.tmExternalLeading %d != %d\n", fd[i].face_name, height, tm.tmExternalLeading, fd[i].ext_leading);
+                    if (fd[i].weight == FW_NORMAL)
+                    {
+                        ok(tm.tmAveCharWidth == fd[i].ave_char_width + 1, "%s(%d): tm.tmAveCharWidth %d != %d\n", fd[i].face_name, height, tm.tmAveCharWidth, fd[i].ave_char_width + 1);
+                        /* Don't run the max char width test on System/ANSI_CHARSET.  We have extra characters in our font
+                           that make the max width bigger */
+                        if (strcmp(lf.lfFaceName, "System") || lf.lfCharSet != ANSI_CHARSET)
+                            ok(tm.tmMaxCharWidth == fd[i].max_char_width + 1, "%s(%d): tm.tmMaxCharWidth %d != %d\n", fd[i].face_name, height, tm.tmMaxCharWidth, fd[i].max_char_width + 1);
+                        ok(tm.tmOverhang == 1, "%s(%d): tm.tmOverhang %d != 1\n", fd[i].face_name, height, tm.tmOverhang);
+                    }
+                    else
+                    {
+                        ok(tm.tmAveCharWidth == fd[i].ave_char_width, "%s(%d): tm.tmAveCharWidth %d != %d\n", fd[i].face_name, height, tm.tmAveCharWidth, fd[i].ave_char_width);
+                        /* Don't run the max char width test on System/ANSI_CHARSET.  We have extra characters in our font
+                           that make the max width bigger */
+                        if (strcmp(lf.lfFaceName, "System") || lf.lfCharSet != ANSI_CHARSET)
+                            ok(tm.tmMaxCharWidth == fd[i].max_char_width, "%s(%d): tm.tmMaxCharWidth %d != %d\n", fd[i].face_name, height, tm.tmMaxCharWidth, fd[i].max_char_width);
+                        ok(tm.tmOverhang == 0, "%s(%d): tm.tmOverhang %d != 0\n", fd[i].face_name, height, tm.tmOverhang);
+                    }
+
+                    SetLastError(0xdeadbeef);
+                    ret = GetTextExtentPoint32(hdc, hello, lstrlen(hello), &bold_size);
+                    ok(ret, "GetTextExtentPoint error %u\n", GetLastError());
+                    trace("bold size %dx%d\n", bold_size.cx, bold_size.cy);
+
+                    ok(normal_size.cy == bold_size.cy, "normal cy %d != bold cy %d\n", normal_size.cy, bold_size.cy);
+                    ret = normal_size.cx + tm.tmOverhang * lstrlen(hello);
+                    if (strcmp(lf.lfFaceName, "Small Fonts") != 0) /* it's broken under Vista */
+                        ok(bold_size.cx == ret, "expected cx %d, got %d\n", ret, bold_size.cx);
+
+                    assert(sizeof(bold_width)/sizeof(bold_width[0]) >= sizeof(hello)-1);
+                    memset(bold_width, 0, sizeof(bold_width));
+                    for (n = 0; n < lstrlen(hello); n++)
+                    {
+                        GetCharWidth32(hdc, hello[n], hello[n], &bold_width[n]);
+                        ok(bold_width[n] == normal_width[n] + tm.tmOverhang,
+                           "%c: bold_width %d != normal_width %d + overhang %d\n",
+                           hello[n], bold_width[n], normal_width[n], tm.tmOverhang);
+                    }
+                }
+                else
+                    skip("Skipping font metrics test for system langid 0x%x\n", system_lang_id);
+            }
+            SelectObject(hdc, old_hfont);
+            DeleteObject(hfont);
         }
     }
 
-- 
1.7.9.4




More information about the wine-patches mailing list