mirror of
https://github.com/reactos/wine.git
synced 2025-02-03 10:43:30 +00:00
dwrite: Report strikethrough ranges to renderer.
This commit is contained in:
parent
e31881a6c9
commit
b8e3fbe0c1
@ -176,6 +176,12 @@ struct layout_effective_inline {
|
||||
BOOL is_rtl;
|
||||
};
|
||||
|
||||
struct layout_strikethrough {
|
||||
struct list entry;
|
||||
const struct layout_effective_run *run;
|
||||
DWRITE_STRIKETHROUGH s;
|
||||
};
|
||||
|
||||
struct layout_cluster {
|
||||
const struct layout_run *run; /* link to nominal run this cluster belongs to */
|
||||
UINT32 position; /* relative to run, first cluster has 0 position */
|
||||
@ -206,6 +212,7 @@ struct dwrite_textlayout {
|
||||
/* lists ready to use by Draw() */
|
||||
struct list eruns;
|
||||
struct list inlineobjects;
|
||||
struct list strikethrough;
|
||||
USHORT recompute;
|
||||
|
||||
DWRITE_LINE_BREAKPOINT *nominal_breakpoints;
|
||||
@ -355,6 +362,7 @@ static void free_layout_eruns(struct dwrite_textlayout *layout)
|
||||
{
|
||||
struct layout_effective_inline *in, *in2;
|
||||
struct layout_effective_run *cur, *cur2;
|
||||
struct layout_strikethrough *s, *s2;
|
||||
|
||||
LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->eruns, struct layout_effective_run, entry) {
|
||||
list_remove(&cur->entry);
|
||||
@ -366,6 +374,11 @@ static void free_layout_eruns(struct dwrite_textlayout *layout)
|
||||
list_remove(&in->entry);
|
||||
heap_free(in);
|
||||
}
|
||||
|
||||
LIST_FOR_EACH_ENTRY_SAFE(s, s2, &layout->strikethrough, struct layout_strikethrough, entry) {
|
||||
list_remove(&s->entry);
|
||||
heap_free(s);
|
||||
}
|
||||
}
|
||||
|
||||
/* Used to resolve break condition by forcing stronger condition over weaker. */
|
||||
@ -808,10 +821,18 @@ static HRESULT layout_compute(struct dwrite_textlayout *layout)
|
||||
return hr;
|
||||
}
|
||||
|
||||
static inline FLOAT get_cluster_range_width(struct dwrite_textlayout *layout, UINT32 start, UINT32 end)
|
||||
{
|
||||
FLOAT width = 0.0;
|
||||
for (; start < end; start++)
|
||||
width += layout->clustermetrics[start].width;
|
||||
return width;
|
||||
}
|
||||
|
||||
/* Effective run is built from consecutive clusters of a single nominal run, 'first_cluster' is 0 based cluster index,
|
||||
'cluster_count' indicates how many clusters to add, including first one. */
|
||||
static HRESULT layout_add_effective_run(struct dwrite_textlayout *layout, const struct layout_run *r, UINT32 first_cluster,
|
||||
UINT32 cluster_count, FLOAT origin_x)
|
||||
UINT32 cluster_count, FLOAT origin_x, BOOL strikethrough)
|
||||
{
|
||||
UINT32 i, start, length, last_cluster;
|
||||
struct layout_effective_run *run;
|
||||
@ -839,9 +860,11 @@ static HRESULT layout_add_effective_run(struct dwrite_textlayout *layout, const
|
||||
if (!run)
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
/* no need to iterate for that */
|
||||
/* No need to iterate for that, use simple fact that:
|
||||
<last cluster position> = first cluster position> + <sum of cluster lengths not including last one> */
|
||||
last_cluster = first_cluster + cluster_count - 1;
|
||||
length = layout->clusters[last_cluster].position + layout->clustermetrics[last_cluster].length;
|
||||
length = layout->clusters[last_cluster].position - layout->clusters[first_cluster].position +
|
||||
layout->clustermetrics[last_cluster].length;
|
||||
|
||||
run->clustermap = heap_alloc(sizeof(UINT16)*length);
|
||||
if (!run->clustermap) {
|
||||
@ -870,6 +893,43 @@ static HRESULT layout_add_effective_run(struct dwrite_textlayout *layout, const
|
||||
run->clustermap[i] = r->u.regular.clustermap[start] - start;
|
||||
|
||||
list_add_tail(&layout->eruns, &run->entry);
|
||||
|
||||
/* Strikethrough style is guaranteed to be consistent within effective run,
|
||||
it's width equals to run width, thikness and offset are derived from
|
||||
font metrics, rest of the values are from layout or run itself */
|
||||
if (strikethrough) {
|
||||
DWRITE_FONT_METRICS metrics = { 0 };
|
||||
struct layout_strikethrough *s;
|
||||
|
||||
s = heap_alloc(sizeof(*s));
|
||||
if (!s)
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
if (layout->gdicompatible) {
|
||||
HRESULT hr = IDWriteFontFace_GetGdiCompatibleMetrics(
|
||||
r->u.regular.run.fontFace,
|
||||
r->u.regular.run.fontEmSize,
|
||||
layout->pixels_per_dip,
|
||||
&layout->transform,
|
||||
&metrics);
|
||||
if (FAILED(hr))
|
||||
WARN("failed to get font metrics, 0x%08x\n", hr);
|
||||
}
|
||||
else
|
||||
IDWriteFontFace_GetMetrics(r->u.regular.run.fontFace, &metrics);
|
||||
|
||||
s->s.width = get_cluster_range_width(layout, first_cluster, first_cluster + cluster_count);
|
||||
s->s.thickness = metrics.strikethroughThickness;
|
||||
s->s.offset = metrics.strikethroughPosition;
|
||||
s->s.readingDirection = layout->format.readingdir;
|
||||
s->s.flowDirection = layout->format.flow;
|
||||
s->s.localeName = r->u.regular.descr.localeName;
|
||||
s->s.measuringMode = DWRITE_MEASURING_MODE_NATURAL; /* FIXME */
|
||||
s->run = run;
|
||||
|
||||
list_add_tail(&layout->strikethrough, &s->entry);
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
@ -895,12 +955,23 @@ static HRESULT layout_set_line_metrics(struct dwrite_textlayout *layout, DWRITE_
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static inline FLOAT get_cluster_range_width(struct dwrite_textlayout *layout, UINT32 start, UINT32 end)
|
||||
static struct layout_range_header *get_layout_range_header_by_pos(struct list *ranges, UINT32 pos)
|
||||
{
|
||||
FLOAT width = 0.0;
|
||||
for (; start < end; start++)
|
||||
width += layout->clustermetrics[start].width;
|
||||
return width;
|
||||
struct layout_range_header *cur;
|
||||
|
||||
LIST_FOR_EACH_ENTRY(cur, ranges, struct layout_range_header, entry) {
|
||||
DWRITE_TEXT_RANGE *r = &cur->range;
|
||||
if (r->startPosition <= pos && pos < r->startPosition + r->length)
|
||||
return cur;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline BOOL layout_get_strikethrough_from_pos(struct dwrite_textlayout *layout, UINT32 pos)
|
||||
{
|
||||
struct layout_range_header *h = get_layout_range_header_by_pos(&layout->strike_ranges, pos);
|
||||
return ((struct layout_range_bool*)h)->value;
|
||||
}
|
||||
|
||||
static HRESULT layout_compute_effective_runs(struct dwrite_textlayout *layout)
|
||||
@ -908,8 +979,9 @@ static HRESULT layout_compute_effective_runs(struct dwrite_textlayout *layout)
|
||||
DWRITE_LINE_METRICS metrics;
|
||||
const struct layout_run *run;
|
||||
FLOAT width, origin_x;
|
||||
UINT32 i, start, line;
|
||||
UINT32 i, start, line, textpos;
|
||||
HRESULT hr;
|
||||
BOOL s[2];
|
||||
|
||||
if (!(layout->recompute & RECOMPUTE_EFFECTIVE_RUNS))
|
||||
return S_OK;
|
||||
@ -923,17 +995,21 @@ static HRESULT layout_compute_effective_runs(struct dwrite_textlayout *layout)
|
||||
line = 0;
|
||||
run = layout->clusters[0].run;
|
||||
memset(&metrics, 0, sizeof(metrics));
|
||||
s[0] = s[1] = layout_get_strikethrough_from_pos(layout, 0);
|
||||
|
||||
for (i = 0, start = 0, width = 0.0; i < layout->cluster_count; i++) {
|
||||
for (i = 0, start = 0, textpos = 0, width = 0.0; i < layout->cluster_count; i++) {
|
||||
BOOL can_wrap_after = layout->clustermetrics[i].canWrapLineAfter;
|
||||
|
||||
s[1] = layout_get_strikethrough_from_pos(layout, textpos);
|
||||
|
||||
/* switched to next nominal run, at this point all previous pending clusters are already
|
||||
checked for layout line overflow, so new effective run will fit in current line */
|
||||
if (run != layout->clusters[i].run) {
|
||||
hr = layout_add_effective_run(layout, run, start, i - start, origin_x);
|
||||
if (run != layout->clusters[i].run || s[0] != s[1]) {
|
||||
hr = layout_add_effective_run(layout, run, start, i - start, origin_x, s[0]);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
origin_x += get_cluster_range_width(layout, start, i);
|
||||
run = layout->clusters[i].run;
|
||||
start = i;
|
||||
}
|
||||
|
||||
@ -945,7 +1021,7 @@ static HRESULT layout_compute_effective_runs(struct dwrite_textlayout *layout)
|
||||
UINT32 strlength = metrics.length, index = i;
|
||||
|
||||
if (i >= start) {
|
||||
hr = layout_add_effective_run(layout, run, start, i - start + 1, origin_x);
|
||||
hr = layout_add_effective_run(layout, run, start, i - start + 1, origin_x, s[0]);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
/* we don't need to update origin for next run as we're going to wrap */
|
||||
@ -988,7 +1064,8 @@ static HRESULT layout_compute_effective_runs(struct dwrite_textlayout *layout)
|
||||
width += layout->clustermetrics[i].width;
|
||||
}
|
||||
|
||||
run = layout->clusters[i].run;
|
||||
s[0] = s[1];
|
||||
textpos += layout->clustermetrics[i].length;
|
||||
}
|
||||
|
||||
layout->line_count = line;
|
||||
@ -1256,19 +1333,6 @@ static struct layout_range *get_layout_range_by_pos(struct dwrite_textlayout *la
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct layout_range_header *get_layout_range_header_by_pos(struct list *ranges, UINT32 pos)
|
||||
{
|
||||
struct layout_range_header *cur;
|
||||
|
||||
LIST_FOR_EACH_ENTRY(cur, ranges, struct layout_range_header, entry) {
|
||||
DWRITE_TEXT_RANGE *r = &cur->range;
|
||||
if (r->startPosition <= pos && pos < r->startPosition + r->length)
|
||||
return cur;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline BOOL set_layout_range_iface_attr(IUnknown **dest, IUnknown *value)
|
||||
{
|
||||
if (*dest == value) return FALSE;
|
||||
@ -2193,6 +2257,7 @@ static HRESULT WINAPI dwritetextlayout_Draw(IDWriteTextLayout2 *iface,
|
||||
struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
|
||||
struct layout_effective_inline *inlineobject;
|
||||
struct layout_effective_run *run;
|
||||
struct layout_strikethrough *s;
|
||||
HRESULT hr;
|
||||
|
||||
TRACE("(%p)->(%p %p %.2f %.2f)\n", This, context, renderer, origin_x, origin_y);
|
||||
@ -2250,7 +2315,16 @@ static HRESULT WINAPI dwritetextlayout_Draw(IDWriteTextLayout2 *iface,
|
||||
}
|
||||
|
||||
/* TODO: 3. Underlines */
|
||||
/* TODO: 4. Strikethrough */
|
||||
|
||||
/* 4. Strikethrough */
|
||||
LIST_FOR_EACH_ENTRY(s, &This->strikethrough, struct layout_strikethrough, entry) {
|
||||
IDWriteTextRenderer_DrawStrikethrough(renderer,
|
||||
context,
|
||||
s->run->origin_x,
|
||||
s->run->origin_y,
|
||||
&s->s,
|
||||
s->run->run->effect);
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
@ -3206,6 +3280,7 @@ static HRESULT init_textlayout(const WCHAR *str, UINT32 len, IDWriteTextFormat *
|
||||
layout->minwidth = 0.0;
|
||||
list_init(&layout->eruns);
|
||||
list_init(&layout->inlineobjects);
|
||||
list_init(&layout->strikethrough);
|
||||
list_init(&layout->runs);
|
||||
list_init(&layout->ranges);
|
||||
list_init(&layout->strike_ranges);
|
||||
|
@ -1156,6 +1156,14 @@ static const struct drawcall_entry draw_seq4[] = {
|
||||
{ DRAW_LAST_KIND }
|
||||
};
|
||||
|
||||
static const struct drawcall_entry draw_seq5[] = {
|
||||
{ DRAW_GLYPHRUN, {'s','t',0} },
|
||||
{ DRAW_GLYPHRUN, {'r','i',0} },
|
||||
{ DRAW_GLYPHRUN, {'n','g',0} },
|
||||
{ DRAW_STRIKETHROUGH },
|
||||
{ DRAW_LAST_KIND }
|
||||
};
|
||||
|
||||
static void test_Draw(void)
|
||||
{
|
||||
static const WCHAR strW[] = {'s','t','r','i','n','g',0};
|
||||
@ -1238,7 +1246,22 @@ static void test_Draw(void)
|
||||
|
||||
hr = IDWriteTextLayout_Draw(layout, NULL, &testrenderer, 0.0, 0.0);
|
||||
ok(hr == S_OK, "got 0x%08x\n", hr);
|
||||
ok_sequence(sequences, RENDERER_ID, draw_seq4, "draw test 4", TRUE);
|
||||
ok_sequence(sequences, RENDERER_ID, draw_seq4, "draw test 4", FALSE);
|
||||
IDWriteTextLayout_Release(layout);
|
||||
|
||||
/* strikethrough somewhere in the middle */
|
||||
hr = IDWriteFactory_CreateTextLayout(factory, strW, 6, format, 500.0, 100.0, &layout);
|
||||
ok(hr == S_OK, "got 0x%08x\n", hr);
|
||||
flush_sequence(sequences, RENDERER_ID);
|
||||
|
||||
range.startPosition = 2;
|
||||
range.length = 2;
|
||||
hr = IDWriteTextLayout_SetStrikethrough(layout, TRUE, range);
|
||||
ok(hr == S_OK, "got 0x%08x\n", hr);
|
||||
|
||||
hr = IDWriteTextLayout_Draw(layout, NULL, &testrenderer, 0.0, 0.0);
|
||||
ok(hr == S_OK, "got 0x%08x\n", hr);
|
||||
ok_sequence(sequences, RENDERER_ID, draw_seq5, "draw test 5", FALSE);
|
||||
IDWriteTextLayout_Release(layout);
|
||||
|
||||
IDWriteTextFormat_Release(format);
|
||||
|
Loading…
x
Reference in New Issue
Block a user