[PATCH 3/3] dwrite: Added support for transform in glyph run analysis

Nikolay Sivov nsivov at codeweavers.com
Mon Nov 2 07:38:43 CST 2015


Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
 dlls/dwrite/dwrite_private.h |  1 +
 dlls/dwrite/font.c           | 28 +++++++++++++++
 dlls/dwrite/freetype.c       | 83 ++++++++++++++++++++++++++++++++++++++++----
 dlls/dwrite/tests/font.c     | 27 ++++++++++++++
 4 files changed, 133 insertions(+), 6 deletions(-)

diff --git a/dlls/dwrite/dwrite_private.h b/dlls/dwrite/dwrite_private.h
index 50c0462..2757b69 100644
--- a/dlls/dwrite/dwrite_private.h
+++ b/dlls/dwrite/dwrite_private.h
@@ -201,6 +201,7 @@ struct dwrite_glyphbitmap {
     RECT bbox;
     BYTE *buf;
     DWRITE_TEXTURE_TYPE type;
+    DWRITE_MATRIX *m;
 };
 
 extern BOOL init_freetype(void) DECLSPEC_HIDDEN;
diff --git a/dlls/dwrite/font.c b/dlls/dwrite/font.c
index d3554a5..c00aeed 100644
--- a/dlls/dwrite/font.c
+++ b/dlls/dwrite/font.c
@@ -4084,6 +4084,8 @@ static void glyphrunanalysis_get_texturebounds(struct dwrite_glyphrunanalysis *a
     glyph_bitmap.emsize = analysis->run.fontEmSize * analysis->ppdip;
     glyph_bitmap.nohint = analysis->rendering_mode == DWRITE_RENDERING_MODE_NATURAL ||
         analysis->rendering_mode == DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
+    if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
+        glyph_bitmap.m = &analysis->m;
 
     for (i = 0; i < analysis->run.glyphCount; i++) {
         const D2D_POINT_2F *advanceoffset = analysis->advanceoffsets ? analysis->advanceoffsets + i : NULL;
@@ -4126,6 +4128,8 @@ static void glyphrunanalysis_get_texturebounds(struct dwrite_glyphrunanalysis *a
 
     /* translate to given run origin */
     OffsetRect(&analysis->bounds, analysis->origin.x, analysis->origin.y);
+    if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
+        OffsetRect(&analysis->bounds, analysis->m.dx, analysis->m.dy);
 
     analysis->flags |= RUNANALYSIS_BOUNDS_READY;
     *bounds = analysis->bounds;
@@ -4198,6 +4202,8 @@ static void glyphrunanalysis_render(struct dwrite_glyphrunanalysis *analysis, DW
     glyph_bitmap.nohint = analysis->rendering_mode == DWRITE_RENDERING_MODE_NATURAL ||
         analysis->rendering_mode == DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
     glyph_bitmap.type = type;
+    if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
+        glyph_bitmap.m = &analysis->m;
     bbox = &glyph_bitmap.bbox;
 
     for (i = 0; i < analysis->run.glyphCount; i++) {
@@ -4252,6 +4258,8 @@ static void glyphrunanalysis_render(struct dwrite_glyphrunanalysis *analysis, DW
         }
 
         OffsetRect(bbox, analysis->origin.x, analysis->origin.y);
+        if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
+            OffsetRect(bbox, analysis->m.dx, analysis->m.dy);
 
         /* blit to analysis bitmap */
         dst = get_pixel_ptr(analysis->bitmap, type, bbox, &analysis->bounds);
@@ -4437,6 +4445,14 @@ static inline void init_2d_vec(D2D_POINT_2F *vec, FLOAT length, BOOL is_vertical
     }
 }
 
+static inline void transform_2d_vec(D2D_POINT_2F *vec, const DWRITE_MATRIX *m)
+{
+    D2D_POINT_2F ret;
+    ret.x = vec->x * m->m11 + vec->y * m->m21;
+    ret.y = vec->x * m->m12 + vec->y * m->m22;
+    *vec = ret;
+}
+
 HRESULT create_glyphrunanalysis(DWRITE_RENDERING_MODE rendering_mode, DWRITE_MEASURING_MODE measuring_mode, DWRITE_GLYPH_RUN const *run,
     FLOAT ppdip, const DWRITE_MATRIX *transform, DWRITE_GRID_FIT_MODE gridfit_mode, DWRITE_TEXT_ANTIALIAS_MODE aa_mode,
     FLOAT originX, FLOAT originY, IDWriteGlyphRunAnalysis **ret)
@@ -4503,11 +4519,16 @@ HRESULT create_glyphrunanalysis(DWRITE_RENDERING_MODE rendering_mode, DWRITE_MEA
     analysis->run.glyphAdvances = NULL;
     analysis->run.glyphOffsets = NULL;
 
+    if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
+        transform_2d_vec(&analysis->origin, &analysis->m);
+
     memcpy(analysis->glyphs, run->glyphIndices, run->glyphCount*sizeof(*run->glyphIndices));
 
     if (run->glyphAdvances) {
         for (i = 0; i < run->glyphCount; i++) {
             init_2d_vec(analysis->advances + i, run->glyphAdvances[i] * ppdip, run->isSideways);
+            if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
+                transform_2d_vec(analysis->advances + i, &analysis->m);
         }
     }
     else {
@@ -4543,6 +4564,9 @@ HRESULT create_glyphrunanalysis(DWRITE_RENDERING_MODE rendering_mode, DWRITE_MEA
             default:
                 ;
             }
+
+            if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
+                transform_2d_vec(analysis->advances + i, &analysis->m);
         }
 
         IDWriteFontFace1_Release(fontface1);
@@ -4552,6 +4576,10 @@ HRESULT create_glyphrunanalysis(DWRITE_RENDERING_MODE rendering_mode, DWRITE_MEA
         for (i = 0; i < run->glyphCount; i++) {
             init_2d_vec(analysis->advanceoffsets + i, run->glyphOffsets[i].advanceOffset * ppdip, run->isSideways);
             init_2d_vec(analysis->ascenderoffsets + i, run->glyphOffsets[i].ascenderOffset * ppdip, !run->isSideways);
+            if (analysis->flags & RUNANALYSIS_USE_TRANSFORM) {
+                transform_2d_vec(analysis->advanceoffsets + i, &analysis->m);
+                transform_2d_vec(analysis->ascenderoffsets + i, &analysis->m);
+            }
         }
     }
 
diff --git a/dlls/dwrite/freetype.c b/dlls/dwrite/freetype.c
index 87ccc7c..543e74c 100644
--- a/dlls/dwrite/freetype.c
+++ b/dlls/dwrite/freetype.c
@@ -65,10 +65,13 @@ typedef struct
 
 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
 MAKE_FUNCPTR(FT_Done_FreeType);
+MAKE_FUNCPTR(FT_Done_Glyph);
 MAKE_FUNCPTR(FT_Get_First_Char);
 MAKE_FUNCPTR(FT_Get_Kerning);
 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
+MAKE_FUNCPTR(FT_Glyph_Copy);
 MAKE_FUNCPTR(FT_Glyph_Get_CBox);
+MAKE_FUNCPTR(FT_Glyph_Transform);
 MAKE_FUNCPTR(FT_Init_FreeType);
 MAKE_FUNCPTR(FT_Library_Version);
 MAKE_FUNCPTR(FT_Load_Glyph);
@@ -148,10 +151,13 @@ BOOL init_freetype(void)
 
 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(ft_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); goto sym_not_found;}
     LOAD_FUNCPTR(FT_Done_FreeType)
+    LOAD_FUNCPTR(FT_Done_Glyph)
     LOAD_FUNCPTR(FT_Get_First_Char)
     LOAD_FUNCPTR(FT_Get_Kerning)
     LOAD_FUNCPTR(FT_Get_Sfnt_Table)
+    LOAD_FUNCPTR(FT_Glyph_Copy)
     LOAD_FUNCPTR(FT_Glyph_Get_CBox)
+    LOAD_FUNCPTR(FT_Glyph_Transform)
     LOAD_FUNCPTR(FT_Init_FreeType)
     LOAD_FUNCPTR(FT_Library_Version)
     LOAD_FUNCPTR(FT_Load_Glyph)
@@ -487,20 +493,61 @@ INT32 freetype_get_kerning_pair_adjustment(IDWriteFontFace2 *fontface, UINT16 le
     return adjustment;
 }
 
+static inline void ft_matrix_from_dwrite_matrix(const DWRITE_MATRIX *m, FT_Matrix *ft_matrix)
+{
+    ft_matrix->xx =  m->m11 * 0x10000;
+    ft_matrix->xy = -m->m21 * 0x10000;
+    ft_matrix->yx = -m->m12 * 0x10000;
+    ft_matrix->yy =  m->m22 * 0x10000;
+}
+
+/* Should be used only while holding 'freetype_cs' */
+static BOOL is_face_scalable(IDWriteFontFace2 *fontface)
+{
+    FT_Face face;
+    if (pFTC_Manager_LookupFace(cache_manager, fontface, &face) == 0)
+        return FT_IS_SCALABLE(face);
+    else
+        return FALSE;
+}
+
 void freetype_get_glyph_bbox(struct dwrite_glyphbitmap *bitmap)
 {
     FTC_ImageTypeRec imagetype;
     FT_BBox bbox = { 0 };
     FT_Glyph glyph;
 
+    EnterCriticalSection(&freetype_cs);
+
+    /* Some fonts provide mostly bitmaps and very few outlines, for example for .notdef,
+       disable transform if that's the case. */
+    if (bitmap->m) {
+        if (!is_face_scalable(bitmap->fontface))
+            bitmap->m = NULL;
+    }
+
     imagetype.face_id = bitmap->fontface;
     imagetype.width = 0;
     imagetype.height = bitmap->emsize;
-    imagetype.flags = FT_LOAD_DEFAULT;
+    imagetype.flags = bitmap->m ? FT_LOAD_NO_BITMAP : FT_LOAD_DEFAULT;
+
+    if (pFTC_ImageCache_Lookup(image_cache, &imagetype, bitmap->index, &glyph, NULL) == 0) {
+        if (bitmap->m) {
+            FT_Glyph glyph_copy;
+
+            if (pFT_Glyph_Copy(glyph, &glyph_copy) == 0) {
+                FT_Matrix ft_matrix;
+
+                ft_matrix_from_dwrite_matrix(bitmap->m, &ft_matrix);
+                pFT_Glyph_Transform(glyph_copy, &ft_matrix, NULL);
+                pFT_Glyph_Get_CBox(glyph_copy, FT_GLYPH_BBOX_PIXELS, &bbox);
+                pFT_Done_Glyph(glyph_copy);
+            }
+        }
+        else
+            pFT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_PIXELS, &bbox);
+    }
 
-    EnterCriticalSection(&freetype_cs);
-    if (pFTC_ImageCache_Lookup(image_cache, &imagetype, bitmap->index, &glyph, NULL) == 0)
-        pFT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_PIXELS, &bbox);
     LeaveCriticalSection(&freetype_cs);
 
     /* flip Y axis */
@@ -607,18 +654,42 @@ BOOL freetype_get_glyph_bitmap(struct dwrite_glyphbitmap *bitmap)
     BOOL ret = FALSE;
     FT_Glyph glyph;
 
+    EnterCriticalSection(&freetype_cs);
+
+    if (bitmap->m) {
+        if (!is_face_scalable(bitmap->fontface))
+            bitmap->m = NULL;
+    }
+
     imagetype.face_id = bitmap->fontface;
     imagetype.width = 0;
     imagetype.height = bitmap->emsize;
-    imagetype.flags = FT_LOAD_DEFAULT;
+    imagetype.flags = bitmap->m ? FT_LOAD_NO_BITMAP : FT_LOAD_DEFAULT;
 
-    EnterCriticalSection(&freetype_cs);
     if (pFTC_ImageCache_Lookup(image_cache, &imagetype, bitmap->index, &glyph, NULL) == 0) {
+        FT_Glyph glyph_copy;
+
+        if (bitmap->m) {
+            if (pFT_Glyph_Copy(glyph, &glyph_copy) == 0) {
+                FT_Matrix ft_matrix;
+
+                ft_matrix_from_dwrite_matrix(bitmap->m, &ft_matrix);
+                pFT_Glyph_Transform(glyph_copy, &ft_matrix, NULL);
+                glyph = glyph_copy;
+            }
+        }
+        else
+            glyph_copy = NULL;
+
         if (bitmap->type == DWRITE_TEXTURE_CLEARTYPE_3x1)
             ret = freetype_get_aa_glyph_bitmap(bitmap, glyph);
         else
             ret = freetype_get_aliased_glyph_bitmap(bitmap, glyph);
+
+        if (glyph_copy)
+            pFT_Done_Glyph(glyph_copy);
     }
+
     LeaveCriticalSection(&freetype_cs);
 
     return ret;
diff --git a/dlls/dwrite/tests/font.c b/dlls/dwrite/tests/font.c
index 8c03977..104e8e6 100644
--- a/dlls/dwrite/tests/font.c
+++ b/dlls/dwrite/tests/font.c
@@ -3507,6 +3507,7 @@ static void test_CreateGlyphRunAnalysis(void)
     DWRITE_GLYPH_OFFSET offsets[2];
     DWRITE_GLYPH_METRICS metrics;
     DWRITE_FONT_METRICS fm;
+    DWRITE_MATRIX m;
     int i;
 
     factory = create_factory();
@@ -3758,6 +3759,32 @@ static void test_CreateGlyphRunAnalysis(void)
     ok((rect.right - rect.left) > 2 * advances[0], "got rect width %d for advance %f\n", rect.right - rect.left, advances[0]);
     IDWriteGlyphRunAnalysis_Release(analysis);
 
+    /* with scaling transform */
+    hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
+        DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
+        0.0, 0.0, &analysis);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+
+    SetRectEmpty(&rect);
+    hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+    ok(!IsRectEmpty(&rect), "got rect width %d\n", rect.right - rect.left);
+    IDWriteGlyphRunAnalysis_Release(analysis);
+
+    memset(&m, 0, sizeof(m));
+    m.m11 = 2.0;
+    m.m22 = 1.0;
+    hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, &m,
+        DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
+        0.0, 0.0, &analysis);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+
+    SetRectEmpty(&rect2);
+    hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect2);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+    ok((rect2.right - rect2.left) > (rect.right - rect.left), "got rect width %d\n", rect2.right - rect2.left);
+    IDWriteGlyphRunAnalysis_Release(analysis);
+
     IDWriteFontFace_Release(face);
     IDWriteFactory_Release(factory);
 }
-- 
2.6.1




More information about the wine-patches mailing list