[PATCH 1/4] dwrite: Use transformed glyph origins in glyph run analysis

Nikolay Sivov nsivov at codeweavers.com
Tue Apr 4 05:13:17 CDT 2017


Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
 dlls/dwrite/font.c | 207 +++++++++++++++++------------------------------------
 1 file changed, 64 insertions(+), 143 deletions(-)

diff --git a/dlls/dwrite/font.c b/dlls/dwrite/font.c
index 4e35ceab2e..27f5040252 100644
--- a/dlls/dwrite/font.c
+++ b/dlls/dwrite/font.c
@@ -172,10 +172,7 @@ struct dwrite_glyphrunanalysis {
     DWRITE_MATRIX m;
     FLOAT ppdip;
     UINT16 *glyphs;
-    D2D_POINT_2F origin;
-    D2D_POINT_2F *advances;
-    D2D_POINT_2F *advanceoffsets;
-    D2D_POINT_2F *ascenderoffsets;
+    D2D_POINT_2F *origins;
 
     UINT8 flags;
     RECT bounds;
@@ -4775,9 +4772,7 @@ static ULONG WINAPI glyphrunanalysis_Release(IDWriteGlyphRunAnalysis *iface)
         if (This->run.fontFace)
             IDWriteFontFace_Release(This->run.fontFace);
         heap_free(This->glyphs);
-        heap_free(This->advances);
-        heap_free(This->advanceoffsets);
-        heap_free(This->ascenderoffsets);
+        heap_free(This->origins);
         heap_free(This->bitmap);
         heap_free(This);
     }
@@ -4807,9 +4802,7 @@ static UINT32 get_glyph_bitmap_pitch(DWRITE_TEXTURE_TYPE type, INT width)
 static void glyphrunanalysis_get_texturebounds(struct dwrite_glyphrunanalysis *analysis, RECT *bounds)
 {
     struct dwrite_glyphbitmap glyph_bitmap;
-    IDWriteFontFace4 *fontface3;
-    D2D_POINT_2F origin;
-    BOOL is_rtl;
+    IDWriteFontFace4 *fontface;
     HRESULT hr;
     UINT32 i;
 
@@ -4821,27 +4814,18 @@ static void glyphrunanalysis_get_texturebounds(struct dwrite_glyphrunanalysis *a
     if (analysis->run.isSideways)
         FIXME("sideways runs are not supported.\n");
 
-    hr = IDWriteFontFace_QueryInterface(analysis->run.fontFace, &IID_IDWriteFontFace4, (void**)&fontface3);
+    hr = IDWriteFontFace_QueryInterface(analysis->run.fontFace, &IID_IDWriteFontFace4, (void **)&fontface);
     if (FAILED(hr))
         WARN("failed to get IDWriteFontFace4, 0x%08x\n", hr);
 
-    /* Start with empty bounds at (0,0) origin, returned bounds are not translated back to (0,0), e.g. for
-       RTL run negative left bound is returned, same goes for vertical direction - top bound will be negative
-       for any non-zero glyph ascender */
-    origin.x = origin.y = 0.0f;
-    is_rtl = analysis->run.bidiLevel & 1;
-
     memset(&glyph_bitmap, 0, sizeof(glyph_bitmap));
-    glyph_bitmap.fontface = fontface3;
+    glyph_bitmap.fontface = fontface;
     glyph_bitmap.emsize = analysis->run.fontEmSize * analysis->ppdip;
     glyph_bitmap.nohint = is_natural_rendering_mode(analysis->rendering_mode);
     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;
-        const D2D_POINT_2F *ascenderoffset = analysis->ascenderoffsets ? analysis->ascenderoffsets + i : NULL;
-        const D2D_POINT_2F *advance = analysis->advances + i;
         RECT *bbox = &glyph_bitmap.bbox;
         UINT32 bitmap_size;
 
@@ -4853,25 +4837,11 @@ static void glyphrunanalysis_get_texturebounds(struct dwrite_glyphrunanalysis *a
         if (bitmap_size > analysis->max_glyph_bitmap_size)
             analysis->max_glyph_bitmap_size = bitmap_size;
 
-        if (is_rtl)
-            OffsetRect(bbox, origin.x + advance->x, origin.y + advance->y);
-        else
-            OffsetRect(bbox, origin.x, origin.y);
-
-        if (advanceoffset)
-            OffsetRect(bbox, advanceoffset->x + ascenderoffset->x, advanceoffset->y + ascenderoffset->y);
-
+        OffsetRect(bbox, analysis->origins[i].x, analysis->origins[i].y);
         UnionRect(&analysis->bounds, &analysis->bounds, bbox);
-        origin.x += advance->x;
-        origin.y += advance->y;
     }
 
-    IDWriteFontFace4_Release(fontface3);
-
-    /* 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);
+    IDWriteFontFace4_Release(fontface);
 
     analysis->flags |= RUNANALYSIS_BOUNDS_READY;
     *bounds = analysis->bounds;
@@ -4919,7 +4889,6 @@ static HRESULT glyphrunanalysis_render(struct dwrite_glyphrunanalysis *analysis)
     IDWriteFontFace4 *fontface;
     D2D_POINT_2F origin;
     UINT32 i, size;
-    BOOL is_rtl;
     HRESULT hr;
     RECT *bbox;
 
@@ -4940,7 +4909,6 @@ static HRESULT glyphrunanalysis_render(struct dwrite_glyphrunanalysis *analysis)
     }
 
     origin.x = origin.y = 0.0f;
-    is_rtl = analysis->run.bidiLevel & 1;
 
     memset(&glyph_bitmap, 0, sizeof(glyph_bitmap));
     glyph_bitmap.fontface = fontface;
@@ -4957,9 +4925,6 @@ static HRESULT glyphrunanalysis_render(struct dwrite_glyphrunanalysis *analysis)
     bbox = &glyph_bitmap.bbox;
 
     for (i = 0; i < analysis->run.glyphCount; i++) {
-        const D2D_POINT_2F *advanceoffset = analysis->advanceoffsets ? analysis->advanceoffsets + i : NULL;
-        const D2D_POINT_2F *ascenderoffset = analysis->ascenderoffsets ? analysis->ascenderoffsets + i : NULL;
-        const D2D_POINT_2F *advance = analysis->advances + i;
         BYTE *src = glyph_bitmap.buf, *dst;
         int x, y, width, height;
         BOOL is_1bpp;
@@ -4967,11 +4932,8 @@ static HRESULT glyphrunanalysis_render(struct dwrite_glyphrunanalysis *analysis)
         glyph_bitmap.index = analysis->run.glyphIndices[i];
         freetype_get_glyph_bbox(&glyph_bitmap);
 
-        if (IsRectEmpty(bbox)) {
-            origin.x += advance->x;
-            origin.y += advance->y;
+        if (IsRectEmpty(bbox))
             continue;
-        }
 
         width = bbox->right - bbox->left;
         height = bbox->bottom - bbox->top;
@@ -4980,17 +4942,7 @@ static HRESULT glyphrunanalysis_render(struct dwrite_glyphrunanalysis *analysis)
         memset(src, 0, height * glyph_bitmap.pitch);
         is_1bpp = freetype_get_glyph_bitmap(&glyph_bitmap);
 
-        if (is_rtl)
-            OffsetRect(bbox, origin.x + advance->x, origin.y + advance->y);
-        else
-            OffsetRect(bbox, origin.x, origin.y);
-
-        if (advanceoffset)
-            OffsetRect(bbox, advanceoffset->x + ascenderoffset->x, advanceoffset->y + ascenderoffset->y);
-
-        OffsetRect(bbox, analysis->origin.x, analysis->origin.y);
-        if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
-            OffsetRect(bbox, analysis->m.dx, analysis->m.dy);
+        OffsetRect(bbox, analysis->origins[i].x, analysis->origins[i].y);
 
         /* blit to analysis bitmap */
         dst = get_pixel_ptr(analysis->bitmap, analysis->texture_type, bbox, &analysis->bounds);
@@ -5025,9 +4977,6 @@ static HRESULT glyphrunanalysis_render(struct dwrite_glyphrunanalysis *analysis)
                 dst += (analysis->bounds.right - analysis->bounds.left) * 3;
             }
         }
-
-        origin.x += advance->x;
-        origin.y += advance->y;
     }
     heap_free(glyph_bitmap.buf);
 
@@ -5037,15 +4986,11 @@ static HRESULT glyphrunanalysis_render(struct dwrite_glyphrunanalysis *analysis)
 
     /* we don't need this anymore */
     heap_free(analysis->glyphs);
-    heap_free(analysis->advances);
-    heap_free(analysis->advanceoffsets);
-    heap_free(analysis->ascenderoffsets);
+    heap_free(analysis->origins);
     IDWriteFontFace_Release(analysis->run.fontFace);
 
     analysis->glyphs = NULL;
-    analysis->advances = NULL;
-    analysis->advanceoffsets = NULL;
-    analysis->ascenderoffsets = NULL;
+    analysis->origins = NULL;
     analysis->run.glyphIndices = NULL;
     analysis->run.fontFace = NULL;
 
@@ -5154,29 +5099,20 @@ static const struct IDWriteGlyphRunAnalysisVtbl glyphrunanalysisvtbl = {
     glyphrunanalysis_GetAlphaBlendParams
 };
 
-static inline void init_2d_vec(D2D_POINT_2F *vec, FLOAT length, BOOL is_vertical)
-{
-    if (is_vertical) {
-        vec->x = 0.0f;
-        vec->y = length;
-    }
-    else {
-        vec->x = length;
-        vec->y = 0.0f;
-    }
-}
-
-static inline void transform_2d_vec(D2D_POINT_2F *vec, const DWRITE_MATRIX *m)
+static inline void transform_point(D2D_POINT_2F *point, 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;
+    ret.x = point->x * m->m11 + point->y * m->m21 + m->dx;
+    ret.y = point->x * m->m12 + point->y * m->m22 + m->dy;
+    *point = ret;
 }
 
 HRESULT create_glyphrunanalysis(const struct glyphrunanalysis_desc *desc, IDWriteGlyphRunAnalysis **ret)
 {
     struct dwrite_glyphrunanalysis *analysis;
+    DWRITE_FONT_METRICS metrics;
+    IDWriteFontFace1 *fontface1;
+    D2D_POINT_2F origin;
     FLOAT rtl_factor;
     UINT32 i;
 
@@ -5205,32 +5141,18 @@ HRESULT create_glyphrunanalysis(const struct glyphrunanalysis_desc *desc, IDWrit
     analysis->bitmap = NULL;
     analysis->max_glyph_bitmap_size = 0;
     analysis->ppdip = desc->ppdip;
-    analysis->origin.x = desc->origin_x * desc->ppdip;
-    analysis->origin.y = desc->origin_y * desc->ppdip;
     SetRectEmpty(&analysis->bounds);
     analysis->run = *desc->run;
     IDWriteFontFace_AddRef(analysis->run.fontFace);
-    analysis->glyphs = heap_alloc(desc->run->glyphCount*sizeof(*desc->run->glyphIndices));
-    analysis->advances = heap_alloc(desc->run->glyphCount*sizeof(*analysis->advances));
-    if (desc->run->glyphOffsets) {
-        analysis->advanceoffsets = heap_alloc(desc->run->glyphCount*sizeof(*analysis->advanceoffsets));
-        analysis->ascenderoffsets = heap_alloc(desc->run->glyphCount*sizeof(*analysis->ascenderoffsets));
-    }
-    else {
-        analysis->advanceoffsets = NULL;
-        analysis->ascenderoffsets = NULL;
-    }
+    analysis->glyphs = heap_alloc(desc->run->glyphCount * sizeof(*analysis->glyphs));
+    analysis->origins = heap_alloc(desc->run->glyphCount * sizeof(*analysis->origins));
 
-    if (!analysis->glyphs || !analysis->advances || ((!analysis->advanceoffsets || !analysis->ascenderoffsets) && desc->run->glyphOffsets)) {
+    if (!analysis->glyphs || !analysis->origins) {
         heap_free(analysis->glyphs);
-        heap_free(analysis->advances);
-        heap_free(analysis->advanceoffsets);
-        heap_free(analysis->ascenderoffsets);
+        heap_free(analysis->origins);
 
         analysis->glyphs = NULL;
-        analysis->advances = NULL;
-        analysis->advanceoffsets = NULL;
-        analysis->ascenderoffsets = NULL;
+        analysis->origins = NULL;
 
         IDWriteGlyphRunAnalysis_Release(&analysis->IDWriteGlyphRunAnalysis_iface);
         return E_OUTOFMEMORY;
@@ -5250,71 +5172,70 @@ HRESULT create_glyphrunanalysis(const struct glyphrunanalysis_desc *desc, IDWrit
 
     rtl_factor = desc->run->bidiLevel & 1 ? -1.0f : 1.0f;
 
-    if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
-        transform_2d_vec(&analysis->origin, &analysis->m);
-
     memcpy(analysis->glyphs, desc->run->glyphIndices, desc->run->glyphCount*sizeof(*desc->run->glyphIndices));
 
-    if (desc->run->glyphAdvances) {
-        for (i = 0; i < desc->run->glyphCount; i++) {
-            init_2d_vec(analysis->advances + i, rtl_factor * desc->run->glyphAdvances[i] * desc->ppdip, desc->run->isSideways);
-            if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
-                transform_2d_vec(analysis->advances + i, &analysis->m);
-        }
-    }
-    else {
-        DWRITE_FONT_METRICS metrics;
-        IDWriteFontFace1 *fontface1;
+    IDWriteFontFace_GetMetrics(desc->run->fontFace, &metrics);
+    IDWriteFontFace_QueryInterface(desc->run->fontFace, &IID_IDWriteFontFace1, (void **)&fontface1);
 
-        IDWriteFontFace_GetMetrics(desc->run->fontFace, &metrics);
-        IDWriteFontFace_QueryInterface(desc->run->fontFace, &IID_IDWriteFontFace1, (void**)&fontface1);
+    origin.x = desc->origin_x * desc->ppdip;
+    origin.y = desc->origin_y * desc->ppdip;
+    for (i = 0; i < desc->run->glyphCount; i++) {
+        FLOAT advance;
 
-        for (i = 0; i < desc->run->glyphCount; i++) {
-            HRESULT hr;
+        /* Use nominal advances if not provided by caller. */
+        if (desc->run->glyphAdvances)
+            advance = rtl_factor * desc->run->glyphAdvances[i] * desc->ppdip;
+        else {
             INT32 a;
 
+            advance = 0.0f;
             switch (desc->measuring_mode)
             {
             case DWRITE_MEASURING_MODE_NATURAL:
-                hr = IDWriteFontFace1_GetDesignGlyphAdvances(fontface1, 1, desc->run->glyphIndices + i, &a, desc->run->isSideways);
-                if (FAILED(hr))
-                    a = 0;
-                init_2d_vec(analysis->advances + i, rtl_factor * get_scaled_advance_width(a, desc->run->fontEmSize, &metrics) * desc->ppdip,
-                    desc->run->isSideways);
+                if (SUCCEEDED(IDWriteFontFace1_GetDesignGlyphAdvances(fontface1, 1, desc->run->glyphIndices + i, &a,
+                        desc->run->isSideways)))
+                    advance = rtl_factor * get_scaled_advance_width(a, desc->run->fontEmSize, &metrics) * desc->ppdip;
                 break;
             case DWRITE_MEASURING_MODE_GDI_CLASSIC:
             case DWRITE_MEASURING_MODE_GDI_NATURAL:
-                hr = IDWriteFontFace1_GetGdiCompatibleGlyphAdvances(fontface1, desc->run->fontEmSize, desc->ppdip, desc->transform,
-                    desc->measuring_mode == DWRITE_MEASURING_MODE_GDI_NATURAL, desc->run->isSideways, 1, desc->run->glyphIndices + i, &a);
-                if (FAILED(hr))
-                    init_2d_vec(analysis->advances + i, 0.0f, FALSE);
-                else
-                    init_2d_vec(analysis->advances + i, rtl_factor * floorf(a * desc->run->fontEmSize * desc->ppdip / metrics.designUnitsPerEm + 0.5f),
-                        desc->run->isSideways);
+                if (SUCCEEDED(IDWriteFontFace1_GetGdiCompatibleGlyphAdvances(fontface1, desc->run->fontEmSize,
+                        desc->ppdip, desc->transform, desc->measuring_mode == DWRITE_MEASURING_MODE_GDI_NATURAL,
+                        desc->run->isSideways, 1, desc->run->glyphIndices + i, &a)))
+                    advance = rtl_factor * floorf(a * desc->run->fontEmSize * desc->ppdip / metrics.designUnitsPerEm + 0.5f);
                 break;
             default:
                 ;
             }
-
-            if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
-                transform_2d_vec(analysis->advances + i, &analysis->m);
         }
 
-        IDWriteFontFace1_Release(fontface1);
-    }
+        analysis->origins[i] = origin;
+
+        /* Offsets are optional, appled to pre-transformed origin. */
+        if (desc->run->glyphOffsets) {
+            FLOAT advanceoffset = rtl_factor * desc->run->glyphOffsets[i].advanceOffset * desc->ppdip;
+            FLOAT ascenderoffset = -desc->run->glyphOffsets[i].ascenderOffset * desc->ppdip;
 
-    if (desc->run->glyphOffsets) {
-        for (i = 0; i < desc->run->glyphCount; i++) {
-            init_2d_vec(analysis->advanceoffsets + i, rtl_factor * desc->run->glyphOffsets[i].advanceOffset * desc->ppdip, desc->run->isSideways);
-            /* Positive ascender offset moves glyph up. Keep it orthogonal to advance direction. */
-            init_2d_vec(analysis->ascenderoffsets + i, -desc->run->glyphOffsets[i].ascenderOffset * desc->ppdip, !desc->run->isSideways);
-            if (analysis->flags & RUNANALYSIS_USE_TRANSFORM) {
-                transform_2d_vec(analysis->advanceoffsets + i, &analysis->m);
-                transform_2d_vec(analysis->ascenderoffsets + i, &analysis->m);
+            if (desc->run->isSideways) {
+                analysis->origins[i].x += ascenderoffset;
+                analysis->origins[i].y += advanceoffset;
+            }
+            else {
+                analysis->origins[i].x += advanceoffset;
+                analysis->origins[i].y += ascenderoffset;
             }
         }
+
+        if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
+            transform_point(analysis->origins + i, &analysis->m);
+
+        if (desc->run->isSideways)
+            origin.y += advance;
+        else
+            origin.x += advance;
     }
 
+    IDWriteFontFace1_Release(fontface1);
+
     *ret = &analysis->IDWriteGlyphRunAnalysis_iface;
     return S_OK;
 }
-- 
2.11.0




More information about the wine-patches mailing list