Commit 1e8f554e authored by Nikolay Sivov's avatar Nikolay Sivov Committed by Alexandre Julliard

dwrite: Initial support for line trimming signs.

parent 82d73733
...@@ -193,8 +193,9 @@ struct layout_effective_run { ...@@ -193,8 +193,9 @@ struct layout_effective_run {
struct layout_effective_inline { struct layout_effective_inline {
struct list entry; struct list entry;
const struct layout_run *run; /* nominal run this one is based on */ IDWriteInlineObject *object; /* inline object, set explicitly or added when trimming a line */
IUnknown *effect; /* original reference is kept only at range level */ IUnknown *effect; /* original reference is kept only at range level */
FLOAT baseline;
FLOAT origin_x; /* left X position */ FLOAT origin_x; /* left X position */
FLOAT origin_y; /* left top corner Y position */ FLOAT origin_y; /* left top corner Y position */
FLOAT align_dx; /* adjustment from text alignment */ FLOAT align_dx; /* adjustment from text alignment */
...@@ -1205,11 +1206,12 @@ static HRESULT layout_add_effective_run(struct dwrite_textlayout *layout, const ...@@ -1205,11 +1206,12 @@ static HRESULT layout_add_effective_run(struct dwrite_textlayout *layout, const
if (!inlineobject) if (!inlineobject)
return E_OUTOFMEMORY; return E_OUTOFMEMORY;
inlineobject->run = r; inlineobject->object = r->u.object.object;
inlineobject->width = get_cluster_range_width(layout, first_cluster, first_cluster + cluster_count); inlineobject->width = get_cluster_range_width(layout, first_cluster, first_cluster + cluster_count);
inlineobject->origin_x = is_rtl ? origin_x - inlineobject->width : origin_x; inlineobject->origin_x = is_rtl ? origin_x - inlineobject->width : origin_x;
inlineobject->origin_y = 0.0f; /* set after line is built */ inlineobject->origin_y = 0.0f; /* set after line is built */
inlineobject->align_dx = 0.0f; inlineobject->align_dx = 0.0f;
inlineobject->baseline = r->baseline;
/* It's not clear how these two are set, possibly directionality /* It's not clear how these two are set, possibly directionality
is derived from surrounding text (replaced text could have is derived from surrounding text (replaced text could have
...@@ -1585,7 +1587,7 @@ static void layout_apply_par_alignment(struct dwrite_textlayout *layout) ...@@ -1585,7 +1587,7 @@ static void layout_apply_par_alignment(struct dwrite_textlayout *layout)
} }
while (inrun && inrun->line == line) { while (inrun && inrun->line == line) {
inrun->origin_y = origin_y - inrun->run->baseline; inrun->origin_y = origin_y - inrun->baseline;
inrun = layout_get_next_inline_run(layout, inrun); inrun = layout_get_next_inline_run(layout, inrun);
} }
} }
...@@ -1722,10 +1724,12 @@ static void layout_add_line(struct dwrite_textlayout *layout, UINT32 first_clust ...@@ -1722,10 +1724,12 @@ static void layout_add_line(struct dwrite_textlayout *layout, UINT32 first_clust
{ {
BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT; BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
struct layout_final_splitting_params params, prev_params; struct layout_final_splitting_params params, prev_params;
UINT32 strlength, index, start, pos = *textpos; DWRITE_INLINE_OBJECT_METRICS sign_metrics = { 0 };
UINT32 line = layout->metrics.lineCount, i; UINT32 line = layout->metrics.lineCount, i;
DWRITE_LINE_METRICS1 metrics = { 0 }; DWRITE_LINE_METRICS1 metrics = { 0 };
UINT32 index, start, pos = *textpos;
FLOAT descent, trailingspacewidth; FLOAT descent, trailingspacewidth;
BOOL append_trimming_run = FALSE;
const struct layout_run *run; const struct layout_run *run;
FLOAT width, origin_x; FLOAT width, origin_x;
HRESULT hr; HRESULT hr;
...@@ -1766,6 +1770,26 @@ static void layout_add_line(struct dwrite_textlayout *layout, UINT32 first_clust ...@@ -1766,6 +1770,26 @@ static void layout_add_line(struct dwrite_textlayout *layout, UINT32 first_clust
/* Does not include trailing space width */ /* Does not include trailing space width */
width = get_cluster_range_width(layout, first_cluster, last_cluster + 1); width = get_cluster_range_width(layout, first_cluster, last_cluster + 1);
/* Append trimming run if necessary */
if (width > layout->metrics.layoutWidth && layout->format.trimmingsign != NULL &&
layout->format.trimming.granularity != DWRITE_TRIMMING_GRANULARITY_NONE) {
FLOAT trimmed_width = width;
hr = IDWriteInlineObject_GetMetrics(layout->format.trimmingsign, &sign_metrics);
if (SUCCEEDED(hr)) {
while (last_cluster > first_cluster) {
if (trimmed_width + sign_metrics.width <= layout->metrics.layoutWidth)
break;
trimmed_width -= layout->clustermetrics[last_cluster--].width;
}
append_trimming_run = TRUE;
}
else
WARN("Failed to get trimming sign metrics, lines won't be trimmed, hr %#x.\n", hr);
width = trimmed_width + sign_metrics.width;
}
layout_splitting_params_from_pos(layout, pos, &params); layout_splitting_params_from_pos(layout, pos, &params);
prev_params = params; prev_params = params;
run = layout->clusters[first_cluster].run; run = layout->clusters[first_cluster].run;
...@@ -1795,24 +1819,39 @@ static void layout_add_line(struct dwrite_textlayout *layout, UINT32 first_clust ...@@ -1795,24 +1819,39 @@ static void layout_add_line(struct dwrite_textlayout *layout, UINT32 first_clust
if (FAILED(hr)) if (FAILED(hr))
return; return;
if (append_trimming_run) {
struct layout_effective_inline *trimming_sign;
trimming_sign = heap_alloc(sizeof(*trimming_sign));
if (!trimming_sign)
return;
trimming_sign->object = layout->format.trimmingsign;
trimming_sign->width = sign_metrics.width;
origin_x += is_rtl ? -get_cluster_range_width(layout, start, i) : get_cluster_range_width(layout, start, i);
trimming_sign->origin_x = is_rtl ? origin_x - trimming_sign->width : origin_x;
trimming_sign->origin_y = 0.0f; /* set after line is built */
trimming_sign->align_dx = 0.0f;
trimming_sign->baseline = sign_metrics.baseline;
trimming_sign->is_sideways = FALSE;
trimming_sign->is_rtl = FALSE;
trimming_sign->line = line;
trimming_sign->effect = NULL; /* FIXME */
list_add_tail(&layout->inlineobjects, &trimming_sign->entry);
}
/* Look for max baseline and descent for this line */ /* Look for max baseline and descent for this line */
strlength = metrics.length - metrics.trailingWhitespaceLength; for (index = first_cluster, metrics.baseline = 0.0f, descent = 0.0f; index <= last_cluster; index++) {
index = last_cluster;
metrics.baseline = 0.0f;
descent = 0.0f;
while (strlength) {
DWRITE_CLUSTER_METRICS *cluster = &layout->clustermetrics[index];
const struct layout_run *cur = layout->clusters[index].run; const struct layout_run *cur = layout->clusters[index].run;
FLOAT cur_descent = cur->height - cur->baseline; FLOAT cur_descent = cur->height - cur->baseline;
if (cur->baseline > metrics.baseline) if (cur->baseline > metrics.baseline)
metrics.baseline = cur->baseline; metrics.baseline = cur->baseline;
if (cur_descent > descent) if (cur_descent > descent)
descent = cur_descent; descent = cur_descent;
strlength -= cluster->length;
index--;
} }
layout->metrics.width = max(width, layout->metrics.width); layout->metrics.width = max(width, layout->metrics.width);
...@@ -1820,7 +1859,7 @@ static void layout_add_line(struct dwrite_textlayout *layout, UINT32 first_clust ...@@ -1820,7 +1859,7 @@ static void layout_add_line(struct dwrite_textlayout *layout, UINT32 first_clust
layout->metrics.widthIncludingTrailingWhitespace); layout->metrics.widthIncludingTrailingWhitespace);
metrics.height = descent + metrics.baseline; metrics.height = descent + metrics.baseline;
metrics.isTrimmed = width > layout->metrics.layoutWidth; metrics.isTrimmed = append_trimming_run || width > layout->metrics.layoutWidth;
layout_set_line_metrics(layout, &metrics); layout_set_line_metrics(layout, &metrics);
*textpos += metrics.length; *textpos += metrics.length;
...@@ -1937,10 +1976,11 @@ static HRESULT layout_compute_effective_runs(struct dwrite_textlayout *layout) ...@@ -1937,10 +1976,11 @@ static HRESULT layout_compute_effective_runs(struct dwrite_textlayout *layout)
/* Same for inline runs */ /* Same for inline runs */
while (inrun && inrun->line == line) { while (inrun && inrun->line == line) {
inrun->origin_y = origin_y - inrun->run->baseline; inrun->origin_y = origin_y - inrun->baseline;
inrun = layout_get_next_inline_run(layout, inrun); inrun = layout_get_next_inline_run(layout, inrun);
} }
} }
/* Use last line origin y + line descent as total content height */ /* Use last line origin y + line descent as total content height */
line--; line--;
layout->metrics.height = origin_y + layout->lines[line].height - layout->lines[line].baseline; layout->metrics.height = origin_y + layout->lines[line].height - layout->lines[line].baseline;
...@@ -3360,7 +3400,7 @@ static HRESULT WINAPI dwritetextlayout_Draw(IDWriteTextLayout3 *iface, ...@@ -3360,7 +3400,7 @@ static HRESULT WINAPI dwritetextlayout_Draw(IDWriteTextLayout3 *iface,
context, context,
inlineobject->origin_x + inlineobject->align_dx + origin_x, inlineobject->origin_x + inlineobject->align_dx + origin_x,
SNAP_COORD(inlineobject->origin_y + origin_y), SNAP_COORD(inlineobject->origin_y + origin_y),
inlineobject->run->u.object.object, inlineobject->object,
inlineobject->is_sideways, inlineobject->is_sideways,
inlineobject->is_rtl, inlineobject->is_rtl,
inlineobject->effect); inlineobject->effect);
...@@ -4728,12 +4768,17 @@ static HRESULT WINAPI dwritetrimmingsign_Draw(IDWriteInlineObject *iface, void * ...@@ -4728,12 +4768,17 @@ static HRESULT WINAPI dwritetrimmingsign_Draw(IDWriteInlineObject *iface, void *
{ {
struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface); struct dwrite_trimmingsign *This = impl_from_IDWriteInlineObject(iface);
DWRITE_TEXT_RANGE range = { 0, ~0u }; DWRITE_TEXT_RANGE range = { 0, ~0u };
DWRITE_TEXT_METRICS metrics;
DWRITE_LINE_METRICS line;
UINT32 line_count;
HRESULT hr; HRESULT hr;
TRACE("(%p)->(%p %p %.2f %.2f %d %d %p)\n", This, context, renderer, originX, originY, is_sideways, is_rtl, effect); TRACE("(%p)->(%p %p %.2f %.2f %d %d %p)\n", This, context, renderer, originX, originY, is_sideways, is_rtl, effect);
IDWriteTextLayout_SetDrawingEffect(This->layout, effect, range); IDWriteTextLayout_SetDrawingEffect(This->layout, effect, range);
hr = IDWriteTextLayout_Draw(This->layout, context, renderer, originX, originY); IDWriteTextLayout_GetLineMetrics(This->layout, &line, 1, &line_count);
IDWriteTextLayout_GetMetrics(This->layout, &metrics);
hr = IDWriteTextLayout_Draw(This->layout, context, renderer, originX, originY - line.baseline);
IDWriteTextLayout_SetDrawingEffect(This->layout, NULL, range); IDWriteTextLayout_SetDrawingEffect(This->layout, NULL, range);
return hr; return hr;
} }
...@@ -4844,6 +4889,7 @@ HRESULT create_trimmingsign(IDWriteFactory4 *factory, IDWriteTextFormat *format, ...@@ -4844,6 +4889,7 @@ HRESULT create_trimmingsign(IDWriteFactory4 *factory, IDWriteTextFormat *format,
} }
IDWriteTextLayout_SetWordWrapping(This->layout, DWRITE_WORD_WRAPPING_NO_WRAP); IDWriteTextLayout_SetWordWrapping(This->layout, DWRITE_WORD_WRAPPING_NO_WRAP);
IDWriteTextLayout_SetParagraphAlignment(This->layout, DWRITE_PARAGRAPH_ALIGNMENT_NEAR);
*sign = &This->IDWriteInlineObject_iface; *sign = &This->IDWriteInlineObject_iface;
return S_OK; return S_OK;
......
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