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:
parent
111637a3c6
commit
da697572dc
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue