[PATCH 3/4] dwrite: Use 8bpp bitmaps in grayscale mode

Nikolay Sivov nsivov at codeweavers.com
Tue Sep 5 05:35:29 CDT 2017


Problem analyzed by Kimmo Myllyvirta

Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---

For https://bugs.winehq.org/show_bug.cgi?id=43319

 dlls/dwrite/dwrite_private.h |   2 +-
 dlls/dwrite/font.c           |  37 +++++++-----
 dlls/dwrite/freetype.c       |   6 +-
 dlls/dwrite/tests/font.c     | 134 ++++++++++++++++++++++++++++++++++++++-----
 4 files changed, 148 insertions(+), 31 deletions(-)

diff --git a/dlls/dwrite/dwrite_private.h b/dlls/dwrite/dwrite_private.h
index 288da2cb43..d12118c258 100644
--- a/dlls/dwrite/dwrite_private.h
+++ b/dlls/dwrite/dwrite_private.h
@@ -273,11 +273,11 @@ struct dwrite_glyphbitmap {
     DWORD simulations;
     FLOAT emsize;
     BOOL nohint;
+    BOOL aliased;
     UINT16 index;
     INT pitch;
     RECT bbox;
     BYTE *buf;
-    DWRITE_TEXTURE_TYPE type;
     DWRITE_MATRIX *m;
 };
 
diff --git a/dlls/dwrite/font.c b/dlls/dwrite/font.c
index 9af46be0db..46dfd30a2a 100644
--- a/dlls/dwrite/font.c
+++ b/dlls/dwrite/font.c
@@ -4872,10 +4872,9 @@ static BOOL is_natural_rendering_mode(DWRITE_RENDERING_MODE1 mode)
     }
 }
 
-static UINT32 get_glyph_bitmap_pitch(DWRITE_TEXTURE_TYPE type, INT width)
+static UINT32 get_glyph_bitmap_pitch(DWRITE_RENDERING_MODE1 rendering_mode, INT width)
 {
-    return type == DWRITE_TEXTURE_CLEARTYPE_3x1 ? (width + 3) / 4 * 4 :
-        ((width + 31) >> 5) << 2;
+    return rendering_mode == DWRITE_RENDERING_MODE1_ALIASED ? ((width + 31) >> 5) << 2 : (width + 3) / 4 * 4;
 }
 
 static void glyphrunanalysis_get_texturebounds(struct dwrite_glyphrunanalysis *analysis, RECT *bounds)
@@ -4912,7 +4911,7 @@ static void glyphrunanalysis_get_texturebounds(struct dwrite_glyphrunanalysis *a
         glyph_bitmap.index = analysis->run.glyphIndices[i];
         freetype_get_glyph_bbox(&glyph_bitmap);
 
-        bitmap_size = get_glyph_bitmap_pitch(analysis->texture_type, bbox->right - bbox->left) *
+        bitmap_size = get_glyph_bitmap_pitch(analysis->rendering_mode, bbox->right - bbox->left) *
             (bbox->bottom - bbox->top);
         if (bitmap_size > analysis->max_glyph_bitmap_size)
             analysis->max_glyph_bitmap_size = bitmap_size;
@@ -4995,7 +4994,7 @@ static HRESULT glyphrunanalysis_render(struct dwrite_glyphrunanalysis *analysis)
     glyph_bitmap.simulations = IDWriteFontFace4_GetSimulations(fontface);
     glyph_bitmap.emsize = analysis->run.fontEmSize;
     glyph_bitmap.nohint = is_natural_rendering_mode(analysis->rendering_mode);
-    glyph_bitmap.type = analysis->texture_type;
+    glyph_bitmap.aliased = analysis->rendering_mode == DWRITE_RENDERING_MODE1_ALIASED;
     if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
         glyph_bitmap.m = &analysis->m;
     if (!(glyph_bitmap.buf = heap_alloc(analysis->max_glyph_bitmap_size))) {
@@ -5019,7 +5018,7 @@ static HRESULT glyphrunanalysis_render(struct dwrite_glyphrunanalysis *analysis)
         width = bbox->right - bbox->left;
         height = bbox->bottom - bbox->top;
 
-        glyph_bitmap.pitch = get_glyph_bitmap_pitch(analysis->texture_type, width);
+        glyph_bitmap.pitch = get_glyph_bitmap_pitch(analysis->rendering_mode, width);
         memset(src, 0, height * glyph_bitmap.pitch);
         is_1bpp = freetype_get_glyph_bitmap(&glyph_bitmap);
 
@@ -5044,18 +5043,27 @@ static HRESULT glyphrunanalysis_render(struct dwrite_glyphrunanalysis *analysis)
                     for (x = 0; x < width; x++)
                         if (src[x / 8] & masks[x % 8])
                             dst[x] = DWRITE_ALPHA_MAX;
-                    src += get_dib_stride(width, 1);
+                    src += glyph_bitmap.pitch;
                     dst += analysis->bounds.right - analysis->bounds.left;
                 }
             }
         }
         else {
-            /* at this point it's DWRITE_TEXTURE_CLEARTYPE_3x1 with 8bpp src bitmap */
-            for (y = 0; y < height; y++) {
-                for (x = 0; x < width; x++)
-                    dst[3*x] = dst[3*x+1] = dst[3*x+2] = src[x] | dst[3*x];
-                src += glyph_bitmap.pitch;
-                dst += (analysis->bounds.right - analysis->bounds.left) * 3;
+            if (analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1) {
+                for (y = 0; y < height; y++) {
+                    for (x = 0; x < width; x++)
+                        dst[3*x] = dst[3*x+1] = dst[3*x+2] = src[x] | dst[3*x];
+                    src += glyph_bitmap.pitch;
+                    dst += (analysis->bounds.right - analysis->bounds.left) * 3;
+                }
+            }
+            else {
+                for (y = 0; y < height; y++) {
+                    for (x = 0; x < width; x++)
+                        dst[x] |= src[x];
+                    src += glyph_bitmap.pitch;
+                    dst += analysis->bounds.right - analysis->bounds.left;
+                }
             }
         }
     }
@@ -5223,7 +5231,8 @@ HRESULT create_glyphrunanalysis(const struct glyphrunanalysis_desc *desc, IDWrit
     analysis->ref = 1;
     analysis->rendering_mode = desc->rendering_mode;
 
-    if (desc->rendering_mode == DWRITE_RENDERING_MODE1_ALIASED)
+    if (desc->rendering_mode == DWRITE_RENDERING_MODE1_ALIASED
+            || desc->aa_mode == DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE)
         analysis->texture_type = DWRITE_TEXTURE_ALIASED_1x1;
     else
         analysis->texture_type = DWRITE_TEXTURE_CLEARTYPE_3x1;
diff --git a/dlls/dwrite/freetype.c b/dlls/dwrite/freetype.c
index 571fa24c33..ffdd8a8f1e 100644
--- a/dlls/dwrite/freetype.c
+++ b/dlls/dwrite/freetype.c
@@ -860,10 +860,10 @@ BOOL freetype_get_glyph_bitmap(struct dwrite_glyphbitmap *bitmap)
         else
             glyph_copy = NULL;
 
-        if (bitmap->type == DWRITE_TEXTURE_CLEARTYPE_3x1)
-            ret = freetype_get_aa_glyph_bitmap(bitmap, glyph);
-        else
+        if (bitmap->aliased)
             ret = freetype_get_aliased_glyph_bitmap(bitmap, glyph);
+        else
+            ret = freetype_get_aa_glyph_bitmap(bitmap, glyph);
 
         if (glyph_copy)
             pFT_Done_Glyph(glyph_copy);
diff --git a/dlls/dwrite/tests/font.c b/dlls/dwrite/tests/font.c
index 54dcc75c81..813ce22abf 100644
--- a/dlls/dwrite/tests/font.c
+++ b/dlls/dwrite/tests/font.c
@@ -4732,6 +4732,7 @@ static void test_CreateGlyphRunAnalysis(void)
 
     IDWriteGlyphRunAnalysis *analysis, *analysis2;
     IDWriteRenderingParams *params;
+    IDWriteFactory3 *factory3;
     IDWriteFactory2 *factory2;
     IDWriteFactory *factory;
     DWRITE_GLYPH_RUN run;
@@ -4745,6 +4746,8 @@ static void test_CreateGlyphRunAnalysis(void)
     DWRITE_GLYPH_METRICS metrics;
     DWRITE_FONT_METRICS fm;
     DWRITE_MATRIX m;
+    ULONG size;
+    BYTE *bits;
     ULONG ref;
     int i;
 
@@ -5057,29 +5060,134 @@ static void test_CreateGlyphRunAnalysis(void)
                 0.0f, 0.0f, &analysis);
         ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
 
-        /* Natural mode, grayscale antialiased. */
+        /* Win8 does not accept default grid fitting mode. */
         hr = IDWriteFactory2_CreateGlyphRunAnalysis(factory2, &run, NULL, DWRITE_RENDERING_MODE_NATURAL,
                 DWRITE_MEASURING_MODE_NATURAL, DWRITE_GRID_FIT_MODE_DEFAULT, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE,
                 0.0f,  0.0f, &analysis);
-        ok(hr == S_OK || broken(hr == E_INVALIDARG) /* Win8 */, "Failed to create glyph run analysis, hr %#x.\n", hr);
+        ok(hr == S_OK || broken(hr == E_INVALIDARG) /* Win8 */, "Failed to create analysis, hr %#x.\n", hr);
+        if (hr == S_OK)
+            IDWriteGlyphRunAnalysis_Release(analysis);
 
-        if (hr == S_OK) {
-            hr = IDWriteFactory_CreateCustomRenderingParams(factory, 0.1f, 0.0f, 1.0f, DWRITE_PIXEL_GEOMETRY_FLAT,
-                    DWRITE_RENDERING_MODE_NATURAL, &params);
-            ok(hr == S_OK, "Failed to create custom parameters, hr %#x.\n", hr);
+        /* Natural mode, grayscale antialiased. */
+        hr = IDWriteFactory2_CreateGlyphRunAnalysis(factory2, &run, NULL, DWRITE_RENDERING_MODE_NATURAL,
+                DWRITE_MEASURING_MODE_NATURAL, DWRITE_GRID_FIT_MODE_DISABLED, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE,
+                0.0f,  0.0f, &analysis);
+        ok(hr == S_OK, "Failed to create analysis, hr %#x.\n", hr);
 
-            hr = IDWriteGlyphRunAnalysis_GetAlphaBlendParams(analysis, params, &gamma, &contrast, &cleartype_level);
-            ok(hr == S_OK, "Failed to get alpha blend params, hr %#x.\n", hr);
-        todo_wine
-            ok(cleartype_level == 0.0f, "Unexpected cleartype level %f.\n", cleartype_level);
+        SetRect(&rect, 0, 1, 0, 1);
+        hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &rect);
+        ok(hr == S_OK, "Failed to get texture bounds, hr %#x.\n", hr);
+        ok(IsRectEmpty(&rect), "Expected empty bbox.\n");
 
-            IDWriteRenderingParams_Release(params);
-            IDWriteGlyphRunAnalysis_Release(analysis);
-        }
+        SetRectEmpty(&rect);
+        hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect);
+        ok(hr == S_OK, "Failed to get texture bounds, hr %#x.\n", hr);
+        ok(!IsRectEmpty(&rect), "Unexpected empty bbox.\n");
+
+        size = (rect.right - rect.left) * (rect.bottom - rect.top);
+        bits = HeapAlloc(GetProcessHeap(), 0, size);
+
+        hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect, bits, size);
+        ok(hr == S_OK, "Failed to get alpha texture, hr %#x.\n", hr);
+
+        hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect, bits, size - 1);
+        ok(hr == E_NOT_SUFFICIENT_BUFFER, "Unexpected hr %#x.\n", hr);
+
+        hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &rect, bits, size);
+        ok(hr == DWRITE_E_UNSUPPORTEDOPERATION, "Unexpected hr %#x.\n", hr);
+
+        hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &rect, bits, size - 1);
+    todo_wine
+        ok(hr == DWRITE_E_UNSUPPORTEDOPERATION, "Unexpected hr %#x.\n", hr);
+
+        HeapFree(GetProcessHeap(), 0, bits);
+
+        hr = IDWriteFactory_CreateCustomRenderingParams(factory, 0.1f, 0.0f, 1.0f, DWRITE_PIXEL_GEOMETRY_FLAT,
+                DWRITE_RENDERING_MODE_NATURAL, &params);
+        ok(hr == S_OK, "Failed to create custom parameters, hr %#x.\n", hr);
+
+        hr = IDWriteGlyphRunAnalysis_GetAlphaBlendParams(analysis, params, &gamma, &contrast, &cleartype_level);
+        ok(hr == S_OK, "Failed to get alpha blend params, hr %#x.\n", hr);
+    todo_wine
+        ok(cleartype_level == 0.0f, "Unexpected cleartype level %f.\n", cleartype_level);
+
+        IDWriteRenderingParams_Release(params);
+        IDWriteGlyphRunAnalysis_Release(analysis);
 
         IDWriteFactory2_Release(factory2);
     }
 
+    if (IDWriteFactory_QueryInterface(factory, &IID_IDWriteFactory3, (void **)&factory3) == S_OK) {
+
+        /* Invalid antialias mode. */
+        hr = IDWriteFactory3_CreateGlyphRunAnalysis(factory3, &run, NULL, DWRITE_RENDERING_MODE1_ALIASED,
+                DWRITE_MEASURING_MODE_NATURAL, DWRITE_GRID_FIT_MODE_DEFAULT, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE + 1,
+                0.0f, 0.0f, &analysis);
+        ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
+
+        /* Invalid grid fit mode. */
+        hr = IDWriteFactory3_CreateGlyphRunAnalysis(factory3, &run, NULL, DWRITE_RENDERING_MODE1_ALIASED,
+                DWRITE_MEASURING_MODE_NATURAL, DWRITE_GRID_FIT_MODE_ENABLED + 1, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE,
+                0.0f, 0.0f, &analysis);
+        ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
+
+        /* Invalid rendering mode. */
+        hr = IDWriteFactory3_CreateGlyphRunAnalysis(factory3, &run, NULL, DWRITE_RENDERING_MODE1_OUTLINE,
+                DWRITE_MEASURING_MODE_NATURAL, DWRITE_GRID_FIT_MODE_ENABLED, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE,
+                0.0f, 0.0f, &analysis);
+        ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
+
+        /* Invalid measuring mode. */
+        hr = IDWriteFactory3_CreateGlyphRunAnalysis(factory3, &run, NULL, DWRITE_RENDERING_MODE1_ALIASED,
+                DWRITE_MEASURING_MODE_GDI_NATURAL + 1, DWRITE_GRID_FIT_MODE_ENABLED,
+                DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE, 0.0f, 0.0f, &analysis);
+        ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
+
+        hr = IDWriteFactory3_CreateGlyphRunAnalysis(factory3, &run, NULL, DWRITE_RENDERING_MODE1_NATURAL,
+                DWRITE_MEASURING_MODE_NATURAL, DWRITE_GRID_FIT_MODE_DEFAULT, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE,
+                0.0f,  0.0f, &analysis);
+        ok(hr == S_OK, "Failed to create analysis, hr %#x.\n", hr);
+        IDWriteGlyphRunAnalysis_Release(analysis);
+
+        /* Natural mode, grayscale antialiased. */
+        hr = IDWriteFactory3_CreateGlyphRunAnalysis(factory3, &run, NULL, DWRITE_RENDERING_MODE1_NATURAL,
+                DWRITE_MEASURING_MODE_NATURAL, DWRITE_GRID_FIT_MODE_DISABLED, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE,
+                0.0f,  0.0f, &analysis);
+        ok(hr == S_OK, "Failed to create analysis, hr %#x.\n", hr);
+
+        SetRect(&rect, 0, 1, 0, 1);
+        hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &rect);
+        ok(hr == S_OK, "Failed to get texture bounds, hr %#x.\n", hr);
+        ok(IsRectEmpty(&rect), "Expected empty bbox.\n");
+
+        SetRectEmpty(&rect);
+        hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect);
+        ok(hr == S_OK, "Failed to get texture bounds, hr %#x.\n", hr);
+        ok(!IsRectEmpty(&rect), "Unexpected empty bbox.\n");
+
+        size = (rect.right - rect.left) * (rect.bottom - rect.top);
+        bits = HeapAlloc(GetProcessHeap(), 0, size);
+
+        hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect, bits, size);
+        ok(hr == S_OK, "Failed to get alpha texture, hr %#x.\n", hr);
+
+        hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect, bits, size - 1);
+        ok(hr == E_NOT_SUFFICIENT_BUFFER, "Unexpected hr %#x.\n", hr);
+
+        hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &rect, bits, size);
+        ok(hr == DWRITE_E_UNSUPPORTEDOPERATION, "Unexpected hr %#x.\n", hr);
+
+        hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &rect, bits, size - 1);
+    todo_wine
+        ok(hr == DWRITE_E_UNSUPPORTEDOPERATION, "Unexpected hr %#x.\n", hr);
+
+        HeapFree(GetProcessHeap(), 0, bits);
+
+        IDWriteGlyphRunAnalysis_Release(analysis);
+
+        IDWriteFactory3_Release(factory3);
+    }
+
     IDWriteFontFace_Release(face);
     ref = IDWriteFactory_Release(factory);
     ok(ref == 0, "factory not released, %u\n", ref);
-- 
2.14.1




More information about the wine-patches mailing list