From da697572dca0663fd010cc78db342328757f54ea Mon Sep 17 00:00:00 2001 From: Nikolay Sivov Date: Tue, 4 Apr 2017 13:13:17 +0300 Subject: [PATCH] dwrite: Use transformed glyph origins in glyph run analysis. Signed-off-by: Nikolay Sivov Signed-off-by: Alexandre Julliard --- 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 4e35ceab2e2..27f50402520 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; - 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); + /* 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->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; }