Commit 072a9b00 authored by Nikolay Sivov's avatar Nikolay Sivov Committed by Alexandre Julliard

dwrite: Split initial cluster computation by stage.

parent 5a70c58a
......@@ -1832,10 +1832,9 @@ static const struct IDWriteTextAnalyzer2Vtbl textanalyzervtbl = {
static IDWriteTextAnalyzer2 textanalyzer = { &textanalyzervtbl };
HRESULT get_textanalyzer(IDWriteTextAnalyzer **ret)
IDWriteTextAnalyzer *get_text_analyzer(void)
{
*ret = (IDWriteTextAnalyzer*)&textanalyzer;
return S_OK;
return (IDWriteTextAnalyzer *)&textanalyzer;
}
static HRESULT WINAPI dwritenumbersubstitution_QueryInterface(IDWriteNumberSubstitution *iface, REFIID riid, void **obj)
......
......@@ -175,7 +175,7 @@ extern HRESULT clone_localizedstring(IDWriteLocalizedStrings *iface, IDWriteLoca
extern void set_en_localizedstring(IDWriteLocalizedStrings*,const WCHAR*) DECLSPEC_HIDDEN;
extern HRESULT get_system_fontcollection(IDWriteFactory5*,IDWriteFontCollection1**) DECLSPEC_HIDDEN;
extern HRESULT get_eudc_fontcollection(IDWriteFactory5*,IDWriteFontCollection1**) DECLSPEC_HIDDEN;
extern HRESULT get_textanalyzer(IDWriteTextAnalyzer**) DECLSPEC_HIDDEN;
extern IDWriteTextAnalyzer *get_text_analyzer(void) DECLSPEC_HIDDEN;
extern HRESULT create_font_file(IDWriteFontFileLoader *loader, const void *reference_key, UINT32 key_size, IDWriteFontFile **font_file) DECLSPEC_HIDDEN;
extern HRESULT create_localfontfileloader(IDWriteLocalFontFileLoader** iface) DECLSPEC_HIDDEN;
extern HRESULT create_fontface(const struct fontface_desc*,struct list*,IDWriteFontFace4**) DECLSPEC_HIDDEN;
......
......@@ -746,40 +746,21 @@ static void layout_get_font_height(FLOAT emsize, DWRITE_FONT_METRICS *fontmetric
*height = SCALE_FONT_METRIC(fontmetrics->ascent + fontmetrics->descent + fontmetrics->lineGap, emsize, fontmetrics);
}
static HRESULT layout_compute_runs(struct dwrite_textlayout *layout)
static HRESULT layout_itemize(struct dwrite_textlayout *layout)
{
IDWriteFontFallback *fallback;
IDWriteTextAnalyzer *analyzer;
struct layout_range *range;
struct layout_run *r;
UINT32 cluster = 0;
HRESULT hr;
free_layout_eruns(layout);
free_layout_runs(layout);
/* Cluster data arrays are allocated once, assuming one text position per cluster. */
if (!layout->clustermetrics && layout->len) {
layout->clustermetrics = heap_alloc(layout->len*sizeof(*layout->clustermetrics));
layout->clusters = heap_alloc(layout->len*sizeof(*layout->clusters));
if (!layout->clustermetrics || !layout->clusters) {
heap_free(layout->clustermetrics);
heap_free(layout->clusters);
return E_OUTOFMEMORY;
}
}
layout->cluster_count = 0;
HRESULT hr = S_OK;
hr = get_textanalyzer(&analyzer);
if (FAILED(hr))
return hr;
analyzer = get_text_analyzer();
LIST_FOR_EACH_ENTRY(range, &layout->ranges, struct layout_range, h.entry) {
/* we don't care about ranges that don't contain any text */
/* We don't care about ranges that don't contain any text. */
if (range->h.range.startPosition >= layout->len)
break;
/* inline objects override actual text in a range */
/* Inline objects override actual text in range. */
if (range->object) {
hr = layout_update_breakpoints_range(layout, range);
if (FAILED(hr))
......@@ -795,30 +776,49 @@ static HRESULT layout_compute_runs(struct dwrite_textlayout *layout)
continue;
}
/* initial splitting by script */
hr = IDWriteTextAnalyzer_AnalyzeScript(analyzer, (IDWriteTextAnalysisSource*)&layout->IDWriteTextAnalysisSource1_iface,
range->h.range.startPosition, get_clipped_range_length(layout, range), (IDWriteTextAnalysisSink*)&layout->IDWriteTextAnalysisSink1_iface);
/* Initial splitting by script. */
hr = IDWriteTextAnalyzer_AnalyzeScript(analyzer, (IDWriteTextAnalysisSource *)&layout->IDWriteTextAnalysisSource1_iface,
range->h.range.startPosition, get_clipped_range_length(layout, range),
(IDWriteTextAnalysisSink *)&layout->IDWriteTextAnalysisSink1_iface);
if (FAILED(hr))
break;
/* this splits it further */
hr = IDWriteTextAnalyzer_AnalyzeBidi(analyzer, (IDWriteTextAnalysisSource*)&layout->IDWriteTextAnalysisSource1_iface,
range->h.range.startPosition, get_clipped_range_length(layout, range), (IDWriteTextAnalysisSink*)&layout->IDWriteTextAnalysisSink1_iface);
/* Splitting further by bidi levels. */
hr = IDWriteTextAnalyzer_AnalyzeBidi(analyzer, (IDWriteTextAnalysisSource *)&layout->IDWriteTextAnalysisSource1_iface,
range->h.range.startPosition, get_clipped_range_length(layout, range),
(IDWriteTextAnalysisSink *)&layout->IDWriteTextAnalysisSink1_iface);
if (FAILED(hr))
break;
}
return hr;
}
static HRESULT layout_resolve_fonts(struct dwrite_textlayout *layout)
{
IDWriteFontCollection *sys_collection;
IDWriteFontFallback *fallback = NULL;
struct layout_range *range;
struct layout_run *r;
HRESULT hr;
if (FAILED(hr = IDWriteFactory5_GetSystemFontCollection(layout->factory, FALSE,
(IDWriteFontCollection1 **)&sys_collection, FALSE))) {
WARN("Failed to get system collection, hr %#x.\n", hr);
return hr;
}
if (layout->format.fallback) {
fallback = layout->format.fallback;
IDWriteFontFallback_AddRef(fallback);
}
else {
hr = IDWriteFactory5_GetSystemFontFallback(layout->factory, &fallback);
if (FAILED(hr))
return hr;
if (FAILED(hr = IDWriteFactory5_GetSystemFontFallback(layout->factory, &fallback))) {
WARN("Failed to get system fallback, hr %#x.\n", hr);
goto fatal;
}
}
/* resolve run fonts */
LIST_FOR_EACH_ENTRY(r, &layout->runs, struct layout_run, entry) {
struct regular_layout_run *run = &r->u.regular;
IDWriteFont *font;
......@@ -832,28 +832,21 @@ static HRESULT layout_compute_runs(struct dwrite_textlayout *layout)
if (run->sa.shapes == DWRITE_SCRIPT_SHAPES_NO_VISUAL) {
IDWriteFontCollection *collection;
if (range->collection) {
collection = range->collection;
IDWriteFontCollection_AddRef(collection);
}
else
IDWriteFactory5_GetSystemFontCollection(layout->factory, FALSE, (IDWriteFontCollection1 **)&collection, FALSE);
hr = create_matching_font(collection, range->fontfamily, range->weight,
range->style, range->stretch, &font);
collection = range->collection ? range->collection : sys_collection;
IDWriteFontCollection_Release(collection);
if (FAILED(hr)) {
WARN("%s: failed to create a font for non visual run, %s, collection %p\n", debugstr_rundescr(&run->descr),
debugstr_w(range->fontfamily), range->collection);
return hr;
if (FAILED(hr = create_matching_font(collection, range->fontfamily, range->weight, range->style,
range->stretch, &font))) {
WARN("%s: failed to create matching font for non visual run, family %s, collection %p\n",
debugstr_rundescr(&run->descr), debugstr_w(range->fontfamily), range->collection);
break;
}
hr = IDWriteFont_CreateFontFace(font, &run->run.fontFace);
IDWriteFont_Release(font);
if (FAILED(hr))
return hr;
if (FAILED(hr)) {
WARN("Failed to create font face, hr %#x.\n", hr);
break;
}
run->run.fontEmSize = range->fontsize;
continue;
......@@ -868,7 +861,7 @@ static HRESULT layout_compute_runs(struct dwrite_textlayout *layout)
run = &r->u.regular;
hr = IDWriteFontFallback_MapCharacters(fallback,
(IDWriteTextAnalysisSource*)&layout->IDWriteTextAnalysisSource1_iface,
(IDWriteTextAnalysisSource *)&layout->IDWriteTextAnalysisSource1_iface,
run->descr.textPosition,
run->descr.stringLength,
range->collection,
......@@ -880,14 +873,18 @@ static HRESULT layout_compute_runs(struct dwrite_textlayout *layout)
&font,
&scale);
if (FAILED(hr)) {
WARN("%s: failed to map family %s, collection %p\n", debugstr_rundescr(&run->descr), debugstr_w(range->fontfamily), range->collection);
return hr;
WARN("%s: failed to map family %s, collection %p, hr %#x.\n", debugstr_rundescr(&run->descr),
debugstr_w(range->fontfamily), range->collection, hr);
goto fatal;
}
hr = IDWriteFont_CreateFontFace(font, &run->run.fontFace);
IDWriteFont_Release(font);
if (FAILED(hr))
return hr;
if (FAILED(hr)) {
WARN("Failed to create font face, hr %#x.\n", hr);
goto fatal;
}
run->run.fontEmSize = range->fontsize * scale;
if (mapped_length < length) {
......@@ -896,8 +893,10 @@ static HRESULT layout_compute_runs(struct dwrite_textlayout *layout)
/* keep mapped part for current run, add another run for the rest */
nextr = alloc_layout_run(LAYOUT_RUN_REGULAR, 0);
if (!nextr)
return E_OUTOFMEMORY;
if (!nextr) {
hr = E_OUTOFMEMORY;
goto fatal;
}
*nextr = *r;
nextr->start_position = run->descr.textPosition + mapped_length;
......@@ -914,15 +913,150 @@ static HRESULT layout_compute_runs(struct dwrite_textlayout *layout)
}
}
IDWriteFontFallback_Release(fallback);
fatal:
IDWriteFontCollection_Release(sys_collection);
if (fallback)
IDWriteFontFallback_Release(fallback);
return hr;
}
static HRESULT layout_shape_run(struct dwrite_textlayout *layout, struct regular_layout_run *run)
{
DWRITE_SHAPING_GLYPH_PROPERTIES *glyph_props;
DWRITE_SHAPING_TEXT_PROPERTIES *text_props;
IDWriteTextAnalyzer *analyzer;
struct layout_range *range;
UINT32 max_count;
HRESULT hr;
range = get_layout_range_by_pos(layout, run->descr.textPosition);
run->descr.localeName = range->locale;
run->clustermap = heap_alloc(run->descr.stringLength * sizeof(*run->clustermap));
max_count = 3 * run->descr.stringLength / 2 + 16;
run->glyphs = heap_alloc(max_count * sizeof(*run->glyphs));
if (!run->clustermap || !run->glyphs)
return E_OUTOFMEMORY;
text_props = heap_alloc(run->descr.stringLength * sizeof(*text_props));
glyph_props = heap_alloc(max_count * sizeof(*glyph_props));
if (!text_props || !glyph_props) {
heap_free(text_props);
heap_free(glyph_props);
return E_OUTOFMEMORY;
}
analyzer = get_text_analyzer();
for (;;) {
hr = IDWriteTextAnalyzer_GetGlyphs(analyzer, run->descr.string, run->descr.stringLength, run->run.fontFace,
run->run.isSideways, run->run.bidiLevel & 1, &run->sa, run->descr.localeName, NULL /* FIXME */, NULL,
NULL, 0, max_count, run->clustermap, text_props, run->glyphs, glyph_props, &run->glyphcount);
if (hr == E_NOT_SUFFICIENT_BUFFER) {
heap_free(run->glyphs);
heap_free(glyph_props);
max_count = run->glyphcount;
run->glyphs = heap_alloc(max_count * sizeof(*run->glyphs));
glyph_props = heap_alloc(max_count * sizeof(*glyph_props));
if (!run->glyphs || !glyph_props) {
hr = E_OUTOFMEMORY;
break;
}
continue;
}
break;
}
if (FAILED(hr)) {
heap_free(text_props);
heap_free(glyph_props);
WARN("%s: shaping failed, hr %#x.\n", debugstr_rundescr(&run->descr), hr);
return hr;
}
run->run.glyphIndices = run->glyphs;
run->descr.clusterMap = run->clustermap;
run->advances = heap_alloc(run->glyphcount * sizeof(*run->advances));
run->offsets = heap_alloc(run->glyphcount * sizeof(*run->offsets));
if (!run->advances || !run->offsets)
return E_OUTOFMEMORY;
/* Get advances and offsets. */
if (is_layout_gdi_compatible(layout))
hr = IDWriteTextAnalyzer_GetGdiCompatibleGlyphPlacements(analyzer, run->descr.string, run->descr.clusterMap,
text_props, run->descr.stringLength, run->run.glyphIndices, glyph_props, run->glyphcount,
run->run.fontFace, run->run.fontEmSize, layout->ppdip, &layout->transform,
layout->measuringmode == DWRITE_MEASURING_MODE_GDI_NATURAL, run->run.isSideways, run->run.bidiLevel & 1,
&run->sa, run->descr.localeName, NULL, NULL, 0, run->advances, run->offsets);
else
hr = IDWriteTextAnalyzer_GetGlyphPlacements(analyzer, run->descr.string, run->descr.clusterMap, text_props,
run->descr.stringLength, run->run.glyphIndices, glyph_props, run->glyphcount, run->run.fontFace,
run->run.fontEmSize, run->run.isSideways, run->run.bidiLevel & 1, &run->sa, run->descr.localeName,
NULL, NULL, 0, run->advances, run->offsets);
heap_free(text_props);
heap_free(glyph_props);
if (FAILED(hr)) {
memset(run->advances, 0, run->glyphcount * sizeof(*run->advances));
memset(run->offsets, 0, run->glyphcount * sizeof(*run->offsets));
WARN("%s: failed to get glyph placement info, hr %#x.\n", debugstr_rundescr(&run->descr), hr);
}
run->run.glyphAdvances = run->advances;
run->run.glyphOffsets = run->offsets;
/* Special treatment for runs that don't produce visual output, shaping code adds normal glyphs for them,
with valid cluster map and potentially with non-zero advances; layout code exposes those as zero
width clusters. */
if (run->sa.shapes == DWRITE_SCRIPT_SHAPES_NO_VISUAL)
run->run.glyphCount = 0;
else
run->run.glyphCount = run->glyphcount;
return S_OK;
}
static HRESULT layout_compute_runs(struct dwrite_textlayout *layout)
{
struct layout_run *r;
UINT32 cluster = 0;
HRESULT hr;
free_layout_eruns(layout);
free_layout_runs(layout);
/* Cluster data arrays are allocated once, assuming one text position per cluster. */
if (!layout->clustermetrics && layout->len) {
layout->clustermetrics = heap_alloc(layout->len*sizeof(*layout->clustermetrics));
layout->clusters = heap_alloc(layout->len*sizeof(*layout->clusters));
if (!layout->clustermetrics || !layout->clusters) {
heap_free(layout->clustermetrics);
heap_free(layout->clusters);
return E_OUTOFMEMORY;
}
}
layout->cluster_count = 0;
if (FAILED(hr = layout_itemize(layout))) {
WARN("Itemization failed, hr %#x.\n", hr);
return hr;
}
if (FAILED(hr = layout_resolve_fonts(layout))) {
WARN("Failed to resolve layout fonts, hr %#x.\n", hr);
return hr;
}
/* fill run info */
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;
DWRITE_FONT_METRICS fontmetrics = { 0 };
UINT32 max_count;
/* we need to do very little in case of inline objects */
if (r->kind == LAYOUT_RUN_INLINE) {
......@@ -957,104 +1091,14 @@ static HRESULT layout_compute_runs(struct dwrite_textlayout *layout)
continue;
}
range = get_layout_range_by_pos(layout, run->descr.textPosition);
run->descr.localeName = range->locale;
run->clustermap = heap_alloc(run->descr.stringLength*sizeof(UINT16));
max_count = 3*run->descr.stringLength/2 + 16;
run->glyphs = heap_alloc(max_count*sizeof(UINT16));
if (!run->clustermap || !run->glyphs)
goto memerr;
text_props = heap_alloc(run->descr.stringLength*sizeof(DWRITE_SHAPING_TEXT_PROPERTIES));
glyph_props = heap_alloc(max_count*sizeof(DWRITE_SHAPING_GLYPH_PROPERTIES));
if (!text_props || !glyph_props)
goto memerr;
while (1) {
hr = IDWriteTextAnalyzer_GetGlyphs(analyzer, run->descr.string, run->descr.stringLength,
run->run.fontFace, run->run.isSideways, run->run.bidiLevel & 1, &run->sa, run->descr.localeName,
NULL /* FIXME */, NULL, NULL, 0, max_count, run->clustermap, text_props, run->glyphs, glyph_props,
&run->glyphcount);
if (hr == E_NOT_SUFFICIENT_BUFFER) {
heap_free(run->glyphs);
heap_free(glyph_props);
max_count = run->glyphcount;
run->glyphs = heap_alloc(max_count*sizeof(UINT16));
glyph_props = heap_alloc(max_count*sizeof(DWRITE_SHAPING_GLYPH_PROPERTIES));
if (!run->glyphs || !glyph_props)
goto memerr;
continue;
}
break;
}
if (FAILED(hr)) {
heap_free(text_props);
heap_free(glyph_props);
WARN("%s: shaping failed 0x%08x\n", debugstr_rundescr(&run->descr), hr);
continue;
}
run->run.glyphIndices = run->glyphs;
run->descr.clusterMap = run->clustermap;
run->advances = heap_alloc(run->glyphcount*sizeof(FLOAT));
run->offsets = heap_alloc(run->glyphcount*sizeof(DWRITE_GLYPH_OFFSET));
if (!run->advances || !run->offsets)
goto memerr;
/* now set advances and offsets */
if (is_layout_gdi_compatible(layout))
hr = IDWriteTextAnalyzer_GetGdiCompatibleGlyphPlacements(analyzer, run->descr.string, run->descr.clusterMap,
text_props, run->descr.stringLength, run->run.glyphIndices, glyph_props, run->glyphcount,
run->run.fontFace, run->run.fontEmSize, layout->ppdip, &layout->transform,
layout->measuringmode == DWRITE_MEASURING_MODE_GDI_NATURAL, run->run.isSideways,
run->run.bidiLevel & 1, &run->sa, run->descr.localeName, NULL, NULL, 0, run->advances, run->offsets);
else
hr = IDWriteTextAnalyzer_GetGlyphPlacements(analyzer, run->descr.string, run->descr.clusterMap, text_props,
run->descr.stringLength, run->run.glyphIndices, glyph_props, run->glyphcount, run->run.fontFace,
run->run.fontEmSize, run->run.isSideways, run->run.bidiLevel & 1, &run->sa, run->descr.localeName,
NULL, NULL, 0, run->advances, run->offsets);
heap_free(text_props);
heap_free(glyph_props);
if (FAILED(hr))
WARN("%s: failed to get glyph placement info, 0x%08x\n", debugstr_rundescr(&run->descr), hr);
run->run.glyphAdvances = run->advances;
run->run.glyphOffsets = run->offsets;
/* Special treatment for runs that don't produce visual output, shaping code adds normal glyphs for them,
with valid cluster map and potentially with non-zero advances; layout code exposes those as zero width clusters. */
if (run->sa.shapes == DWRITE_SCRIPT_SHAPES_NO_VISUAL)
run->run.glyphCount = 0;
else
run->run.glyphCount = run->glyphcount;
if (FAILED(hr = layout_shape_run(layout, run)))
WARN("%s: shaping failed, hr %#x.\n", debugstr_rundescr(&run->descr), hr);
/* baseline derived from font metrics */
layout_get_font_metrics(layout, run->run.fontFace, run->run.fontEmSize, &fontmetrics);
layout_get_font_height(run->run.fontEmSize, &fontmetrics, &r->baseline, &r->height);
layout_set_cluster_metrics(layout, r, &cluster);
continue;
memerr:
heap_free(text_props);
heap_free(glyph_props);
heap_free(run->clustermap);
heap_free(run->glyphs);
heap_free(run->advances);
heap_free(run->offsets);
run->advances = NULL;
run->offsets = NULL;
run->clustermap = run->glyphs = NULL;
hr = E_OUTOFMEMORY;
break;
}
if (hr == S_OK) {
......@@ -1063,7 +1107,6 @@ static HRESULT layout_compute_runs(struct dwrite_textlayout *layout)
layout->clustermetrics[cluster-1].canWrapLineAfter = 1;
}
IDWriteTextAnalyzer_Release(analyzer);
return hr;
}
......@@ -1077,25 +1120,22 @@ static HRESULT layout_compute(struct dwrite_textlayout *layout)
/* nominal breakpoints are evaluated only once, because string never changes */
if (!layout->nominal_breakpoints) {
IDWriteTextAnalyzer *analyzer;
HRESULT hr;
layout->nominal_breakpoints = heap_alloc(sizeof(DWRITE_LINE_BREAKPOINT)*layout->len);
layout->nominal_breakpoints = heap_alloc(layout->len * sizeof(*layout->nominal_breakpoints));
if (!layout->nominal_breakpoints)
return E_OUTOFMEMORY;
hr = get_textanalyzer(&analyzer);
if (FAILED(hr))
return hr;
analyzer = get_text_analyzer();
hr = IDWriteTextAnalyzer_AnalyzeLineBreakpoints(analyzer, (IDWriteTextAnalysisSource*)&layout->IDWriteTextAnalysisSource1_iface,
0, layout->len, (IDWriteTextAnalysisSink*)&layout->IDWriteTextAnalysisSink1_iface);
IDWriteTextAnalyzer_Release(analyzer);
}
if (layout->actual_breakpoints) {
heap_free(layout->actual_breakpoints);
layout->actual_breakpoints = NULL;
if (FAILED(hr = IDWriteTextAnalyzer_AnalyzeLineBreakpoints(analyzer,
(IDWriteTextAnalysisSource *)&layout->IDWriteTextAnalysisSource1_iface,
0, layout->len, (IDWriteTextAnalysisSink *)&layout->IDWriteTextAnalysisSink1_iface)))
WARN("Line breakpoints analysis failed, hr %#x.\n", hr);
}
heap_free(layout->actual_breakpoints);
layout->actual_breakpoints = NULL;
hr = layout_compute_runs(layout);
if (TRACE_ON(dwrite)) {
......
......@@ -1192,8 +1192,12 @@ static HRESULT WINAPI dwritefactory_CreateEllipsisTrimmingSign(IDWriteFactory5 *
static HRESULT WINAPI dwritefactory_CreateTextAnalyzer(IDWriteFactory5 *iface, IDWriteTextAnalyzer **analyzer)
{
struct dwritefactory *This = impl_from_IDWriteFactory5(iface);
TRACE("(%p)->(%p)\n", This, analyzer);
return get_textanalyzer(analyzer);
*analyzer = get_text_analyzer();
return S_OK;
}
static HRESULT WINAPI dwritefactory_CreateNumberSubstitution(IDWriteFactory5 *iface,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment