dwrite: Implement GetOverhangMetrics().

Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Nikolay Sivov 2017-01-27 00:42:13 +03:00 committed by Alexandre Julliard
parent 0fa152791f
commit 426a5d4a5f
3 changed files with 155 additions and 12 deletions

View File

@ -287,6 +287,7 @@ extern void freetype_get_glyph_bbox(struct dwrite_glyphbitmap*) DECLSPEC_HIDDEN;
extern BOOL freetype_get_glyph_bitmap(struct dwrite_glyphbitmap*) DECLSPEC_HIDDEN;
extern INT freetype_get_charmap_index(IDWriteFontFace4*,BOOL*) DECLSPEC_HIDDEN;
extern INT32 freetype_get_glyph_advance(IDWriteFontFace4*,FLOAT,UINT16,DWRITE_MEASURING_MODE) DECLSPEC_HIDDEN;
extern void freetype_get_design_glyph_bbox(IDWriteFontFace4*,UINT16,UINT16,RECT*) DECLSPEC_HIDDEN;
/* Glyph shaping */
enum SCRIPT_JUSTIFY

View File

@ -639,6 +639,32 @@ void freetype_get_glyph_bbox(struct dwrite_glyphbitmap *bitmap)
SetRect(&bitmap->bbox, bbox.xMin, -bbox.yMax, bbox.xMax, -bbox.yMin);
}
void freetype_get_design_glyph_bbox(IDWriteFontFace4 *fontface, UINT16 unitsperEm, UINT16 glyph, RECT *bbox)
{
FTC_ScalerRec scaler;
FT_Size size;
scaler.face_id = fontface;
scaler.width = unitsperEm;
scaler.height = unitsperEm;
scaler.pixel = 1;
scaler.x_res = 0;
scaler.y_res = 0;
EnterCriticalSection(&freetype_cs);
if (pFTC_Manager_LookupSize(cache_manager, &scaler, &size) == 0) {
if (pFT_Load_Glyph(size->face, glyph, FT_LOAD_NO_SCALE) == 0) {
FT_Glyph_Metrics *metrics = &size->face->glyph->metrics;
bbox->left = metrics->horiBearingX;
bbox->right = bbox->left + metrics->horiAdvance;
bbox->top = -metrics->horiBearingY;
bbox->bottom = bbox->top + metrics->height;
}
}
LeaveCriticalSection(&freetype_cs);
}
static BOOL freetype_get_aliased_glyph_bitmap(struct dwrite_glyphbitmap *bitmap, FT_Glyph glyph)
{
const RECT *bbox = &bitmap->bbox;
@ -889,6 +915,11 @@ void freetype_get_glyph_bbox(struct dwrite_glyphbitmap *bitmap)
memset(&bitmap->bbox, 0, sizeof(bitmap->bbox));
}
void freetype_get_design_glyph_bbox(IDWriteFontFace4 *fontface, UINT16 unitsperEm, UINT16 glyph, RECT *bbox)
{
memset(bbox, 0, sizeof(*bbox));
}
BOOL freetype_get_glyph_bitmap(struct dwrite_glyphbitmap *bitmap)
{
return FALSE;

View File

@ -223,10 +223,12 @@ struct layout_cluster {
};
enum layout_recompute_mask {
RECOMPUTE_CLUSTERS = 1 << 0,
RECOMPUTE_MINIMAL_WIDTH = 1 << 1,
RECOMPUTE_LINES = 1 << 2,
RECOMPUTE_EVERYTHING = 0xffff
RECOMPUTE_CLUSTERS = 1 << 0,
RECOMPUTE_MINIMAL_WIDTH = 1 << 1,
RECOMPUTE_LINES = 1 << 2,
RECOMPUTE_OVERHANGS = 1 << 3,
RECOMPUTE_LINES_AND_OVERHANGS = RECOMPUTE_LINES | RECOMPUTE_OVERHANGS,
RECOMPUTE_EVERYTHING = 0xffff
};
struct dwrite_textlayout {
@ -267,6 +269,7 @@ struct dwrite_textlayout {
UINT32 line_alloc;
DWRITE_TEXT_METRICS1 metrics;
DWRITE_OVERHANG_METRICS overhangs;
DWRITE_MEASURING_MODE measuringmode;
@ -2905,7 +2908,7 @@ static HRESULT WINAPI dwritetextlayout_SetMaxWidth(IDWriteTextLayout3 *iface, FL
This->metrics.layoutWidth = maxWidth;
if (changed)
This->recompute |= RECOMPUTE_LINES;
This->recompute |= RECOMPUTE_LINES_AND_OVERHANGS;
return S_OK;
}
@ -2923,7 +2926,7 @@ static HRESULT WINAPI dwritetextlayout_SetMaxHeight(IDWriteTextLayout3 *iface, F
This->metrics.layoutHeight = maxHeight;
if (changed)
This->recompute |= RECOMPUTE_LINES;
This->recompute |= RECOMPUTE_LINES_AND_OVERHANGS;
return S_OK;
}
@ -3468,11 +3471,119 @@ static HRESULT WINAPI dwritetextlayout_GetMetrics(IDWriteTextLayout3 *iface, DWR
return hr;
}
static HRESULT WINAPI dwritetextlayout_GetOverhangMetrics(IDWriteTextLayout3 *iface, DWRITE_OVERHANG_METRICS *overhangs)
static void scale_glyph_bbox(RECT *bbox, FLOAT emSize, UINT16 units_per_em, D2D_RECT_F *ret)
{
#define SCALE(x) ((FLOAT)x * emSize / (FLOAT)units_per_em)
ret->left = SCALE(bbox->left);
ret->right = SCALE(bbox->right);
ret->top = SCALE(bbox->top);
ret->bottom = SCALE(bbox->bottom);
#undef SCALE
}
static void d2d_rect_offset(D2D_RECT_F *rect, FLOAT x, FLOAT y)
{
rect->left += x;
rect->right += x;
rect->top += y;
rect->bottom += y;
}
static BOOL d2d_rect_is_empty(const D2D_RECT_F *rect)
{
return ((rect->left >= rect->right) || (rect->top >= rect->bottom));
}
static void d2d_rect_union(D2D_RECT_F *dst, const D2D_RECT_F *src)
{
if (d2d_rect_is_empty(dst)) {
if (d2d_rect_is_empty(src)) {
dst->left = dst->right = dst->top = dst->bottom = 0.0f;
return;
}
else
*dst = *src;
}
else {
if (!d2d_rect_is_empty(src)) {
dst->left = min(dst->left, src->left);
dst->right = max(dst->right, src->right);
dst->top = min(dst->top, src->top);
dst->bottom = max(dst->bottom, src->bottom);
}
}
}
static void layout_get_erun_bbox(struct dwrite_textlayout *layout, struct layout_effective_run *run, D2D_RECT_F *bbox)
{
const struct regular_layout_run *regular = &run->run->u.regular;
UINT32 start_glyph = regular->clustermap[run->start];
const DWRITE_GLYPH_RUN *glyph_run = &regular->run;
DWRITE_FONT_METRICS font_metrics;
D2D_POINT_2F origin = { 0 };
UINT32 i;
IDWriteFontFace_GetMetrics(glyph_run->fontFace, &font_metrics);
origin.x = run->origin_x + run->align_dx;
origin.y = run->origin_y;
for (i = 0; i < run->glyphcount; i++) {
D2D_RECT_F glyph_bbox;
RECT design_bbox;
freetype_get_design_glyph_bbox((IDWriteFontFace4 *)glyph_run->fontFace, font_metrics.designUnitsPerEm,
glyph_run->glyphIndices[i + start_glyph], &design_bbox);
scale_glyph_bbox(&design_bbox, glyph_run->fontEmSize, font_metrics.designUnitsPerEm, &glyph_bbox);
d2d_rect_offset(&glyph_bbox, origin.x + glyph_run->glyphOffsets[i + start_glyph].advanceOffset,
origin.y + glyph_run->glyphOffsets[i + start_glyph].ascenderOffset);
d2d_rect_union(bbox, &glyph_bbox);
/* FIXME: take care of vertical/rtl */
origin.x += glyph_run->glyphAdvances[i + start_glyph];
}
}
static HRESULT WINAPI dwritetextlayout_GetOverhangMetrics(IDWriteTextLayout3 *iface,
DWRITE_OVERHANG_METRICS *overhangs)
{
struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
FIXME("(%p)->(%p): stub\n", This, overhangs);
return E_NOTIMPL;
struct layout_effective_run *run;
D2D_RECT_F bbox = { 0 };
HRESULT hr;
TRACE("(%p)->(%p)\n", This, overhangs);
memset(overhangs, 0, sizeof(*overhangs));
if (!(This->recompute & RECOMPUTE_OVERHANGS)) {
*overhangs = This->overhangs;
return S_OK;
}
hr = layout_compute_effective_runs(This);
if (FAILED(hr))
return hr;
LIST_FOR_EACH_ENTRY(run, &This->eruns, struct layout_effective_run, entry) {
D2D_RECT_F run_bbox;
layout_get_erun_bbox(This, run, &run_bbox);
d2d_rect_union(&bbox, &run_bbox);
}
/* FIXME: iterate over inline objects too */
/* deltas from text content metrics */
This->overhangs.left = -bbox.left;
This->overhangs.top = -bbox.top;
This->overhangs.right = bbox.right - This->metrics.layoutWidth;
This->overhangs.bottom = bbox.bottom - This->metrics.layoutHeight;
This->recompute &= ~RECOMPUTE_OVERHANGS;
*overhangs = This->overhangs;
return S_OK;
}
static HRESULT WINAPI dwritetextlayout_GetClusterMetrics(IDWriteTextLayout3 *iface,
@ -3739,7 +3850,7 @@ static HRESULT WINAPI dwritetextlayout3_SetLineSpacing(IDWriteTextLayout3 *iface
return hr;
if (changed)
This->recompute = RECOMPUTE_LINES;
This->recompute |= RECOMPUTE_LINES_AND_OVERHANGS;
return S_OK;
}
@ -3930,7 +4041,7 @@ static HRESULT WINAPI dwritetextformat_layout_SetWordWrapping(IDWriteTextFormat1
return hr;
if (changed)
This->recompute |= RECOMPUTE_LINES;
This->recompute |= RECOMPUTE_LINES_AND_OVERHANGS;
return S_OK;
}
@ -3990,7 +4101,7 @@ static HRESULT WINAPI dwritetextformat_layout_SetTrimming(IDWriteTextFormat1 *if
hr = format_set_trimming(&This->format, trimming, trimming_sign, &changed);
if (changed)
This->recompute |= RECOMPUTE_LINES;
This->recompute |= RECOMPUTE_LINES_AND_OVERHANGS;
return hr;
}