dwrite: Use transformed glyph origins in glyph run analysis.

Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Nikolay Sivov 2017-04-04 13:13:17 +03:00 committed by Alexandre Julliard
parent 111637a3c6
commit da697572dc
1 changed files with 64 additions and 143 deletions

View File

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