Nikolay Sivov : dwrite: Initial support of cluster metrics computation.
Alexandre Julliard
julliard at wine.codeweavers.com
Tue Jan 20 15:20:10 CST 2015
Module: wine
Branch: master
Commit: 0ee49eb4c882552a0a2ab17e24bd8efe8086d610
URL: http://source.winehq.org/git/wine.git/?a=commit;h=0ee49eb4c882552a0a2ab17e24bd8efe8086d610
Author: Nikolay Sivov <nsivov at codeweavers.com>
Date: Mon Jan 12 00:03:31 2015 +0300
dwrite: Initial support of cluster metrics computation.
---
dlls/dwrite/layout.c | 98 +++++++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 89 insertions(+), 9 deletions(-)
diff --git a/dlls/dwrite/layout.c b/dlls/dwrite/layout.c
index beb97b3..785ded8 100644
--- a/dlls/dwrite/layout.c
+++ b/dlls/dwrite/layout.c
@@ -134,6 +134,9 @@ struct dwrite_textlayout {
DWRITE_LINE_BREAKPOINT *nominal_breakpoints;
DWRITE_LINE_BREAKPOINT *actual_breakpoints;
+ DWRITE_CLUSTER_METRICS *clusters;
+ UINT32 clusters_count;
+
/* gdi-compatible layout specifics */
BOOL gdicompatible;
FLOAT pixels_per_dip;
@@ -206,6 +209,12 @@ 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)
+{
+ return wine_dbg_sprintf("[%u,%u]", run->descr.textPosition, run->descr.textPosition +
+ run->descr.stringLength);
+}
+
static struct layout_run *alloc_layout_run(void)
{
struct layout_run *ret;
@@ -254,7 +263,7 @@ static void free_layout_runs(struct dwrite_textlayout *layout)
}
}
-/* should only be called for ranges with inline objects */
+/* Used to resolve break condition by forcing stronger condition over weaker. */
static inline DWRITE_BREAK_CONDITION override_break_condition(DWRITE_BREAK_CONDITION existingbreak, DWRITE_BREAK_CONDITION newbreak)
{
switch (existingbreak) {
@@ -273,6 +282,7 @@ static inline DWRITE_BREAK_CONDITION override_break_condition(DWRITE_BREAK_CONDI
return existingbreak;
}
+/* Actual breakpoint data gets updated with break condition required by inline object set for range 'cur'. */
static HRESULT layout_update_breakpoints_range(struct dwrite_textlayout *layout, const struct layout_range *cur)
{
DWRITE_BREAK_CONDITION before, after;
@@ -320,14 +330,75 @@ static HRESULT layout_update_breakpoints_range(struct dwrite_textlayout *layout,
static struct layout_range *get_layout_range_by_pos(struct dwrite_textlayout *layout, UINT32 pos);
+static void init_cluster_metrics(const struct layout_run *run, DWRITE_CLUSTER_METRICS *metrics)
+{
+ metrics->width = 0.0;
+ metrics->length = 1;
+ metrics->canWrapLineAfter = FALSE;
+ metrics->isWhitespace = FALSE;
+ metrics->isNewline = FALSE;
+ metrics->isSoftHyphen = FALSE;
+ metrics->isRightToLeft = run->run.bidiLevel & 1;
+ metrics->padding = 0;
+}
+
+/*
+
+ All clusters in a 'run' will be added to 'layout' data, starting at index pointed to by 'cluster'.
+ On return 'cluster' is updated to point to next metrics struct to be filled in on next call.
+
+*/
+static void layout_set_cluster_metrics(struct dwrite_textlayout *layout, const struct layout_run *run, UINT32 *cluster)
+{
+ DWRITE_CLUSTER_METRICS *metrics = &layout->clusters[*cluster];
+ UINT16 glyph;
+ UINT32 i;
+
+ glyph = run->descr.clusterMap[0];
+ init_cluster_metrics(run, metrics);
+
+ for (i = 0; i < run->descr.stringLength; i++) {
+ BOOL newcluster = glyph != run->descr.clusterMap[i];
+
+ /* add new cluster on starting glyph change or simply when run is over */
+ if (newcluster || i == run->descr.stringLength - 1) {
+ UINT8 breakcondition;
+ UINT16 j;
+
+ for (j = glyph; j < run->descr.clusterMap[i]; j++)
+ metrics->width += run->run.glyphAdvances[j];
+
+ /* FIXME: also set isWhitespace, isNewline and isSoftHyphen */
+ breakcondition = newcluster ? layout->nominal_breakpoints[i].breakConditionBefore :
+ layout->nominal_breakpoints[i].breakConditionAfter;
+ metrics->canWrapLineAfter = breakcondition == DWRITE_BREAK_CONDITION_CAN_BREAK ||
+ breakcondition == DWRITE_BREAK_CONDITION_MUST_BREAK;
+
+ /* advance to next cluster */
+ glyph = run->descr.clusterMap[i];
+ *cluster += 1;
+ metrics++;
+ init_cluster_metrics(run, metrics);
+ }
+ else
+ metrics->length++;
+ }
+}
+
static HRESULT layout_compute_runs(struct dwrite_textlayout *layout)
{
IDWriteTextAnalyzer *analyzer;
struct layout_range *range;
struct layout_run *run;
+ UINT32 cluster = 0;
HRESULT hr;
free_layout_runs(layout);
+ heap_free(layout->clusters);
+ layout->clusters_count = 0;
+ layout->clusters = heap_alloc(layout->len*sizeof(DWRITE_CLUSTER_METRICS));
+ if (!layout->clusters)
+ return E_OUTOFMEMORY;
hr = get_textanalyzer(&analyzer);
if (FAILED(hr))
@@ -368,8 +439,7 @@ static HRESULT layout_compute_runs(struct dwrite_textlayout *layout)
hr = IDWriteFontCollection_FindFamilyName(range->collection, range->fontfamily, &index, &exists);
if (FAILED(hr) || !exists) {
- WARN("[%u,%u]: family %s not found in collection %p\n", run->descr.textPosition, run->descr.textPosition+run->descr.stringLength,
- debugstr_w(range->fontfamily), range->collection);
+ WARN("%s: family %s not found in collection %p\n", debugstr_run(run), debugstr_w(range->fontfamily), range->collection);
continue;
}
@@ -380,7 +450,7 @@ static HRESULT layout_compute_runs(struct dwrite_textlayout *layout)
hr = IDWriteFontFamily_GetFirstMatchingFont(family, range->weight, range->stretch, range->style, &font);
IDWriteFontFamily_Release(family);
if (FAILED(hr)) {
- WARN("[%u,%u]: failed to get a matching font\n", run->descr.textPosition, run->descr.textPosition+run->descr.stringLength);
+ WARN("%s: failed to get a matching font\n", debugstr_run(run));
continue;
}
@@ -428,7 +498,7 @@ static HRESULT layout_compute_runs(struct dwrite_textlayout *layout)
if (FAILED(hr)) {
heap_free(text_props);
heap_free(glyph_props);
- WARN("[%u,%u]: shaping failed 0x%08x\n", run->descr.textPosition, run->descr.textPosition+run->descr.stringLength, hr);
+ WARN("%s: shaping failed 0x%08x\n", debugstr_run(run), hr);
continue;
}
@@ -456,12 +526,14 @@ static HRESULT layout_compute_runs(struct dwrite_textlayout *layout)
heap_free(text_props);
heap_free(glyph_props);
if (FAILED(hr))
- WARN("[%u,%u]: failed to get glyph placement info, 0x%08x\n", run->descr.textPosition,
- run->descr.textPosition+run->descr.stringLength, hr);
+ WARN("%s: failed to get glyph placement info, 0x%08x\n", debugstr_run(run), hr);
run->run.glyphAdvances = run->advances;
run->run.glyphOffsets = run->offsets;
+ /* now set cluster metrics */
+ layout_set_cluster_metrics(layout, run, &cluster);
+
continue;
memerr:
@@ -478,6 +550,9 @@ static HRESULT layout_compute_runs(struct dwrite_textlayout *layout)
break;
}
+ if (hr == S_OK)
+ layout->clusters_count = cluster + 1;
+
IDWriteTextAnalyzer_Release(analyzer);
return hr;
}
@@ -1006,6 +1081,7 @@ static ULONG WINAPI dwritetextlayout_Release(IDWriteTextLayout2 *iface)
release_format_data(&This->format);
heap_free(This->nominal_breakpoints);
heap_free(This->actual_breakpoints);
+ heap_free(This->clusters);
heap_free(This->str);
heap_free(This);
}
@@ -2127,6 +2203,8 @@ static HRESULT init_textlayout(const WCHAR *str, UINT32 len, IDWriteTextFormat *
layout->recompute = TRUE;
layout->nominal_breakpoints = NULL;
layout->actual_breakpoints = NULL;
+ layout->clusters_count = 0;
+ layout->clusters = NULL;
list_init(&layout->runs);
list_init(&layout->ranges);
memset(&layout->format, 0, sizeof(layout->format));
@@ -2147,8 +2225,10 @@ static HRESULT init_textlayout(const WCHAR *str, UINT32 len, IDWriteTextFormat *
goto fail;
range = alloc_layout_range(layout, &r);
- if (!range)
- return E_OUTOFMEMORY;
+ if (!range) {
+ hr = E_OUTOFMEMORY;
+ goto fail;
+ }
list_add_head(&layout->ranges, &range->entry);
return S_OK;
More information about the wine-cvs
mailing list