dwrite: Add cluster metrics entry for inline objects too.

This commit is contained in:
Nikolay Sivov 2015-04-04 14:05:52 +03:00 committed by Alexandre Julliard
parent 547fcead1f
commit b16432f2c2
2 changed files with 115 additions and 69 deletions

View File

@ -110,8 +110,17 @@ struct layout_range {
WCHAR *fontfamily;
};
struct layout_run {
struct list entry;
enum layout_run_kind {
LAYOUT_RUN_REGULAR,
LAYOUT_RUN_INLINE
};
struct inline_object_run {
IDWriteInlineObject *object;
UINT16 length;
};
struct regular_layout_run {
DWRITE_GLYPH_RUN_DESCRIPTION descr;
DWRITE_GLYPH_RUN run;
DWRITE_SCRIPT_ANALYSIS sa;
@ -121,6 +130,15 @@ struct layout_run {
DWRITE_GLYPH_OFFSET *offsets;
};
struct layout_run {
struct list entry;
enum layout_run_kind kind;
union {
struct inline_object_run object;
struct regular_layout_run regular;
} u;
};
enum layout_recompute_mask {
RECOMPUTE_NOMINAL_RUNS = 1 << 0,
RECOMPUTE_MINIMAL_WIDTH = 1 << 1,
@ -223,7 +241,7 @@ static inline struct dwrite_typography *impl_from_IDWriteTypography(IDWriteTypog
return CONTAINING_RECORD(iface, struct dwrite_typography, IDWriteTypography_iface);
}
static inline const char *debugstr_run(const struct layout_run *run)
static inline const char *debugstr_run(const struct regular_layout_run *run)
{
return wine_dbg_sprintf("[%u,%u]", run->descr.textPosition, run->descr.textPosition +
run->descr.stringLength);
@ -247,35 +265,19 @@ static HRESULT set_fontfallback_for_format(struct dwrite_textformat_data *format
return S_OK;
}
static struct layout_run *alloc_layout_run(void)
static struct layout_run *alloc_layout_run(enum layout_run_kind kind)
{
struct layout_run *ret;
ret = heap_alloc(sizeof(*ret));
if (!ret) return NULL;
ret->descr.localeName = NULL;
ret->descr.string = NULL;
ret->descr.stringLength = 0;
ret->descr.clusterMap = NULL;
ret->descr.textPosition = 0;
ret->run.fontFace = NULL;
ret->run.fontEmSize = 0.0;
ret->run.glyphCount = 0;
ret->run.glyphIndices = NULL;
ret->run.glyphAdvances = NULL;
ret->run.glyphOffsets = NULL;
ret->run.isSideways = FALSE;
ret->run.bidiLevel = 0;
ret->sa.script = Script_Unknown;
ret->sa.shapes = DWRITE_SCRIPT_SHAPES_DEFAULT;
ret->glyphs = NULL;
ret->clustermap = NULL;
ret->advances = NULL;
ret->offsets = NULL;
memset(ret, 0, sizeof(*ret));
ret->kind = kind;
if (kind == LAYOUT_RUN_REGULAR) {
ret->u.regular.sa.script = Script_Unknown;
ret->u.regular.sa.shapes = DWRITE_SCRIPT_SHAPES_DEFAULT;
}
return ret;
}
@ -285,12 +287,14 @@ static void free_layout_runs(struct dwrite_textlayout *layout)
struct layout_run *cur, *cur2;
LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->runs, struct layout_run, entry) {
list_remove(&cur->entry);
if (cur->run.fontFace)
IDWriteFontFace_Release(cur->run.fontFace);
heap_free(cur->glyphs);
heap_free(cur->clustermap);
heap_free(cur->advances);
heap_free(cur->offsets);
if (cur->kind == LAYOUT_RUN_REGULAR) {
if (cur->u.regular.run.fontFace)
IDWriteFontFace_Release(cur->u.regular.run.fontFace);
heap_free(cur->u.regular.glyphs);
heap_free(cur->u.regular.clustermap);
heap_free(cur->u.regular.advances);
heap_free(cur->u.regular.offsets);
}
heap_free(cur);
}
}
@ -369,7 +373,7 @@ static inline DWRITE_LINE_BREAKPOINT get_effective_breakpoint(const struct dwrit
return layout->nominal_breakpoints[pos];
}
static inline void init_cluster_metrics(const struct dwrite_textlayout *layout, const struct layout_run *run,
static inline void init_cluster_metrics(const struct dwrite_textlayout *layout, const struct regular_layout_run *run,
UINT16 start_glyph, UINT16 stop_glyph, UINT32 stop_position, DWRITE_CLUSTER_METRICS *metrics)
{
UINT8 breakcondition;
@ -402,7 +406,7 @@ static inline void init_cluster_metrics(const struct dwrite_textlayout *layout,
codepoint initially.
*/
static void layout_set_cluster_metrics(struct dwrite_textlayout *layout, const struct layout_run *run, UINT32 *cluster)
static void layout_set_cluster_metrics(struct dwrite_textlayout *layout, const struct regular_layout_run *run, UINT32 *cluster)
{
DWRITE_CLUSTER_METRICS *metrics = &layout->clusters[*cluster];
UINT32 i, start = 0;
@ -433,7 +437,7 @@ static HRESULT layout_compute_runs(struct dwrite_textlayout *layout)
{
IDWriteTextAnalyzer *analyzer;
struct layout_range *range;
struct layout_run *run;
struct layout_run *r;
UINT32 cluster = 0;
HRESULT hr;
@ -454,6 +458,14 @@ static HRESULT layout_compute_runs(struct dwrite_textlayout *layout)
hr = layout_update_breakpoints_range(layout, range);
if (FAILED(hr))
return hr;
r = alloc_layout_run(LAYOUT_RUN_INLINE);
if (!r)
return E_OUTOFMEMORY;
r->u.object.object = range->object;
r->u.object.length = range->range.length;
list_add_tail(&layout->runs, &r->entry);
continue;
}
@ -471,14 +483,43 @@ static HRESULT layout_compute_runs(struct dwrite_textlayout *layout)
}
/* fill run info */
LIST_FOR_EACH_ENTRY(run, &layout->runs, struct layout_run, entry) {
LIST_FOR_EACH_ENTRY(r, &layout->runs, struct layout_run, entry) {
DWRITE_SHAPING_GLYPH_PROPERTIES *glyph_props = NULL;
DWRITE_SHAPING_TEXT_PROPERTIES *text_props = NULL;
struct regular_layout_run *run = &r->u.regular;
IDWriteFontFamily *family;
UINT32 index, max_count;
IDWriteFont *font;
BOOL exists = TRUE;
/* we need to do very little in case of inline objects */
if (r->kind == LAYOUT_RUN_INLINE) {
DWRITE_CLUSTER_METRICS *metrics = &layout->clusters[cluster];
DWRITE_INLINE_OBJECT_METRICS inlinemetrics;
metrics->width = 0.0;
metrics->length = r->u.object.length;
metrics->canWrapLineAfter = FALSE;
metrics->isWhitespace = FALSE;
metrics->isNewline = FALSE;
metrics->isSoftHyphen = FALSE;
metrics->isRightToLeft = FALSE;
metrics->padding = 0;
cluster++;
/* TODO: is it fatal if GetMetrics() fails? */
hr = IDWriteInlineObject_GetMetrics(r->u.object.object, &inlinemetrics);
if (FAILED(hr)) {
FIXME("failed to get inline object metrics, 0x%08x\n", hr);
continue;
}
metrics->width = inlinemetrics.width;
/* FIXME: use resolved breakpoints in this case too */
continue;
}
range = get_layout_range_by_pos(layout, run->descr.textPosition);
hr = IDWriteFontCollection_FindFamilyName(range->collection, range->fontfamily, &index, &exists);
@ -575,7 +616,6 @@ static HRESULT layout_compute_runs(struct dwrite_textlayout *layout)
run->run.glyphAdvances = run->advances;
run->run.glyphOffsets = run->offsets;
/* now set cluster metrics */
layout_set_cluster_metrics(layout, run, &cluster);
continue;
@ -636,8 +676,11 @@ static HRESULT layout_compute(struct dwrite_textlayout *layout)
struct layout_run *cur;
LIST_FOR_EACH_ENTRY(cur, &layout->runs, struct layout_run, entry) {
TRACE("run [%u,%u], len %u, bidilevel %u\n", cur->descr.textPosition, cur->descr.textPosition+cur->descr.stringLength-1,
cur->descr.stringLength, cur->run.bidiLevel);
if (cur->kind == LAYOUT_RUN_INLINE)
TRACE("run inline object %p, len %u\n", cur->u.object.object, cur->u.object.length);
else
TRACE("run [%u,%u], len %u, bidilevel %u\n", cur->u.regular.descr.textPosition, cur->u.regular.descr.textPosition +
cur->u.regular.descr.stringLength-1, cur->u.regular.descr.stringLength, cur->u.regular.run.bidiLevel);
}
}
@ -2394,15 +2437,15 @@ static HRESULT WINAPI dwritetextlayout_sink_SetScriptAnalysis(IDWriteTextAnalysi
TRACE("%u %u script=%d\n", position, length, sa->script);
run = alloc_layout_run();
run = alloc_layout_run(LAYOUT_RUN_REGULAR);
if (!run)
return E_OUTOFMEMORY;
run->descr.string = &layout->str[position];
run->descr.stringLength = length;
run->descr.textPosition = position;
run->sa = *sa;
list_add_head(&layout->runs, &run->entry);
run->u.regular.descr.string = &layout->str[position];
run->u.regular.descr.stringLength = length;
run->u.regular.descr.textPosition = position;
run->u.regular.sa = *sa;
list_add_tail(&layout->runs, &run->entry);
return S_OK;
}
@ -2422,11 +2465,15 @@ static HRESULT WINAPI dwritetextlayout_sink_SetBidiLevel(IDWriteTextAnalysisSink
UINT32 length, UINT8 explicitLevel, UINT8 resolvedLevel)
{
struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSink(iface);
struct layout_run *cur;
struct layout_run *cur_run;
LIST_FOR_EACH_ENTRY(cur, &layout->runs, struct layout_run, entry) {
LIST_FOR_EACH_ENTRY(cur_run, &layout->runs, struct layout_run, entry) {
struct regular_layout_run *cur = &cur_run->u.regular;
struct layout_run *run, *run2;
if (cur_run->kind == LAYOUT_RUN_INLINE)
continue;
/* FIXME: levels are reported in a natural forward direction, so start loop from a run we ended on */
if (position < cur->descr.textPosition || position > cur->descr.textPosition + cur->descr.stringLength)
continue;
@ -2446,32 +2493,32 @@ static HRESULT WINAPI dwritetextlayout_sink_SetBidiLevel(IDWriteTextAnalysisSink
}
/* now starting point is in a run, so it splits it */
run = alloc_layout_run();
run = alloc_layout_run(LAYOUT_RUN_REGULAR);
if (!run)
return E_OUTOFMEMORY;
*run = *cur;
run->descr.textPosition = position;
run->descr.stringLength = cur->descr.stringLength - position + cur->descr.textPosition;
run->descr.string = &layout->str[position];
run->run.bidiLevel = resolvedLevel;
*run = *cur_run;
run->u.regular.descr.textPosition = position;
run->u.regular.descr.stringLength = cur->descr.stringLength - position + cur->descr.textPosition;
run->u.regular.descr.string = &layout->str[position];
run->u.regular.run.bidiLevel = resolvedLevel;
cur->descr.stringLength -= position - cur->descr.textPosition;
list_add_after(&cur->entry, &run->entry);
list_add_after(&cur_run->entry, &run->entry);
if (position + length == run->descr.textPosition + run->descr.stringLength)
if (position + length == run->u.regular.descr.textPosition + run->u.regular.descr.stringLength)
break;
/* split second time */
run2 = alloc_layout_run();
run2 = alloc_layout_run(LAYOUT_RUN_REGULAR);
if (!run2)
return E_OUTOFMEMORY;
*run2 = *cur;
run2->descr.textPosition = run->descr.textPosition + run->descr.stringLength;
run2->descr.stringLength = cur->descr.textPosition + cur->descr.stringLength - position - length;
run2->descr.string = &layout->str[run2->descr.textPosition];
run->descr.stringLength -= run2->descr.stringLength;
*run2 = *cur_run;
run2->u.regular.descr.textPosition = run->u.regular.descr.textPosition + run->u.regular.descr.stringLength;
run2->u.regular.descr.stringLength = cur->descr.textPosition + cur->descr.stringLength - position - length;
run2->u.regular.descr.string = &layout->str[run2->u.regular.descr.textPosition];
run->u.regular.descr.stringLength -= run2->u.regular.descr.stringLength;
list_add_after(&run->entry, &run2->entry);
break;
@ -2782,7 +2829,8 @@ static HRESULT WINAPI dwritetrimmingsign_GetMetrics(IDWriteInlineObject *iface,
{
struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
FIXME("(%p)->(%p): stub\n", This, metrics);
return E_NOTIMPL;
memset(metrics, 0, sizeof(*metrics));
return S_OK;
}
static HRESULT WINAPI dwritetrimmingsign_GetOverhangMetrics(IDWriteInlineObject *iface, DWRITE_OVERHANG_METRICS *overhangs)

View File

@ -1038,23 +1038,21 @@ static void test_GetClusterMetrics(void)
count = 0;
hr = IDWriteTextLayout_GetClusterMetrics(layout, NULL, 0, &count);
ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
todo_wine
ok(count == 3, "got %u\n", count);
count = 0;
memset(&metrics, 0, sizeof(metrics));
hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics, 1, &count);
ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
todo_wine {
ok(count == 3, "got %u\n", count);
ok(metrics[0].length == 2, "got %u\n", metrics[0].length);
}
hr = IDWriteInlineObject_GetMetrics(trimm, &inline_metrics);
todo_wine {
ok(hr == S_OK, "got 0x%08x\n", hr);
ok(inline_metrics.width == metrics[0].width, "got %.2f, expected %.2f\n", inline_metrics.width,
metrics[0].width);
}
todo_wine
ok(inline_metrics.width > 0.0 && inline_metrics.width == metrics[0].width, "got %.2f, expected %.2f\n",
inline_metrics.width, metrics[0].width);
IDWriteInlineObject_Release(trimm);
IDWriteTextLayout_Release(layout);
IDWriteTextFormat_Release(format);