dwrite: Fix cluster width and length calculation.

This commit is contained in:
Nikolay Sivov 2015-04-03 11:38:23 +03:00 committed by Alexandre Julliard
parent 52df833a72
commit 0c116d7736
2 changed files with 65 additions and 39 deletions

View File

@ -362,14 +362,34 @@ 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)
static inline DWRITE_LINE_BREAKPOINT get_effective_breakpoint(const struct dwrite_textlayout *layout, UINT32 pos)
{
if (layout->actual_breakpoints)
return layout->actual_breakpoints[pos];
return layout->nominal_breakpoints[pos];
}
static inline void init_cluster_metrics(const struct dwrite_textlayout *layout, const struct layout_run *run,
UINT16 start_glyph, UINT16 stop_glyph, UINT32 stop_position, DWRITE_CLUSTER_METRICS *metrics)
{
UINT8 breakcondition;
UINT16 j;
metrics->width = 0.0;
metrics->length = 1;
metrics->canWrapLineAfter = FALSE;
metrics->isWhitespace = FALSE;
metrics->isNewline = FALSE;
metrics->isSoftHyphen = FALSE;
for (j = start_glyph; j < stop_glyph; j++)
metrics->width += run->run.glyphAdvances[j];
metrics->length = 0;
if (stop_glyph == run->run.glyphCount)
breakcondition = get_effective_breakpoint(layout, stop_position).breakConditionAfter;
else
breakcondition = get_effective_breakpoint(layout, stop_position).breakConditionBefore;
metrics->canWrapLineAfter = breakcondition == DWRITE_BREAK_CONDITION_CAN_BREAK ||
breakcondition == DWRITE_BREAK_CONDITION_MUST_BREAK;
metrics->isWhitespace = FALSE; /* FIXME */
metrics->isNewline = FALSE; /* FIXME */
metrics->isSoftHyphen = FALSE; /* FIXME */
metrics->isRightToLeft = run->run.bidiLevel & 1;
metrics->padding = 0;
}
@ -378,42 +398,34 @@ static void init_cluster_metrics(const struct layout_run *run, DWRITE_CLUSTER_ME
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.
Note that there's no need to reallocate anything at this point as we allocate one cluster per
codepoint initially.
*/
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);
UINT32 i, start = 0;
for (i = 0; i < run->descr.stringLength; i++) {
BOOL newcluster = glyph != run->descr.clusterMap[i];
BOOL end = i == run->descr.stringLength - 1;
/* add new cluster on starting glyph change or simply when run is over */
if (newcluster || i == run->descr.stringLength - 1) {
UINT8 breakcondition;
UINT16 j;
if (run->descr.clusterMap[start] != run->descr.clusterMap[i]) {
init_cluster_metrics(layout, run, run->descr.clusterMap[start], run->descr.clusterMap[i], i, metrics);
metrics->length = i - start;
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);
start = i;
}
if (end) {
init_cluster_metrics(layout, run, run->descr.clusterMap[start], run->run.glyphCount, i, metrics);
metrics->length = i - start + 1;
*cluster += 1;
return;
}
else
metrics->length++;
}
}
@ -583,7 +595,7 @@ static HRESULT layout_compute_runs(struct dwrite_textlayout *layout)
}
if (hr == S_OK)
layout->clusters_count = cluster + 1;
layout->clusters_count = cluster;
IDWriteTextAnalyzer_Release(analyzer);
return hr;
@ -613,6 +625,10 @@ static HRESULT layout_compute(struct dwrite_textlayout *layout)
0, layout->len, &layout->IDWriteTextAnalysisSink_iface);
IDWriteTextAnalyzer_Release(analyzer);
}
if (layout->actual_breakpoints) {
heap_free(layout->actual_breakpoints);
layout->actual_breakpoints = NULL;
}
hr = layout_compute_runs(layout);

View File

@ -993,13 +993,13 @@ static void test_GetClusterMetrics(void)
{
static const WCHAR strW[] = {'a','b','c','d',0};
DWRITE_INLINE_OBJECT_METRICS inline_metrics;
DWRITE_CLUSTER_METRICS metrics;
DWRITE_CLUSTER_METRICS metrics[4];
IDWriteInlineObject *trimm;
IDWriteTextFormat *format;
IDWriteTextLayout *layout;
DWRITE_TEXT_RANGE range;
IDWriteFactory *factory;
UINT32 count;
UINT32 count, i;
HRESULT hr;
factory = create_factory();
@ -1016,6 +1016,16 @@ static void test_GetClusterMetrics(void)
ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
ok(count == 4, "got %u\n", count);
/* check every cluster width */
count = 0;
hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics, sizeof(metrics)/sizeof(metrics[0]), &count);
ok(hr == S_OK, "got 0x%08x\n", hr);
ok(count == 4, "got %u\n", count);
for (i = 0; i < count; i++) {
ok(metrics[i].width > 0.0, "%u: got width %.2f\n", i, metrics[i].width);
ok(metrics[i].length == 1, "%u: got length %u\n", i, metrics[i].length);
}
hr = IDWriteFactory_CreateEllipsisTrimmingSign(factory, format, &trimm);
ok(hr == S_OK, "got 0x%08x\n", hr);
@ -1033,17 +1043,17 @@ todo_wine
count = 0;
memset(&metrics, 0, sizeof(metrics));
hr = IDWriteTextLayout_GetClusterMetrics(layout, &metrics, 1, &count);
hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics, 1, &count);
ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
todo_wine
todo_wine {
ok(count == 3, "got %u\n", count);
ok(metrics.length == 2, "got %u\n", metrics.length);
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.width, "got %.2f, expected %.2f\n", inline_metrics.width,
metrics.width);
ok(inline_metrics.width == metrics[0].width, "got %.2f, expected %.2f\n", inline_metrics.width,
metrics[0].width);
}
IDWriteInlineObject_Release(trimm);
IDWriteTextLayout_Release(layout);