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;
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;
}