dwrite: Store character spacing layout settings.

This commit is contained in:
Nikolay Sivov 2015-06-18 19:52:15 +03:00 committed by Alexandre Julliard
parent e70b50d772
commit b43850a363
2 changed files with 114 additions and 18 deletions

View File

@ -72,7 +72,8 @@ enum layout_range_attr_kind {
LAYOUT_RANGE_ATTR_PAIR_KERNING, LAYOUT_RANGE_ATTR_PAIR_KERNING,
LAYOUT_RANGE_ATTR_FONTCOLL, LAYOUT_RANGE_ATTR_FONTCOLL,
LAYOUT_RANGE_ATTR_LOCALE, LAYOUT_RANGE_ATTR_LOCALE,
LAYOUT_RANGE_ATTR_FONTFAMILY LAYOUT_RANGE_ATTR_FONTFAMILY,
LAYOUT_RANGE_ATTR_SPACING
}; };
struct layout_range_attr_value { struct layout_range_attr_value {
@ -90,13 +91,15 @@ struct layout_range_attr_value {
IDWriteFontCollection *collection; IDWriteFontCollection *collection;
const WCHAR *locale; const WCHAR *locale;
const WCHAR *fontfamily; const WCHAR *fontfamily;
FLOAT spacing[3]; /* in arguments order - leading, trailing, advance */
} u; } u;
}; };
enum layout_range_kind { enum layout_range_kind {
LAYOUT_RANGE_REGULAR, LAYOUT_RANGE_REGULAR,
LAYOUT_RANGE_STRIKETHROUGH, LAYOUT_RANGE_STRIKETHROUGH,
LAYOUT_RANGE_EFFECT LAYOUT_RANGE_EFFECT,
LAYOUT_RANGE_SPACING
}; };
struct layout_range_header { struct layout_range_header {
@ -129,6 +132,13 @@ struct layout_range_effect {
IUnknown *effect; IUnknown *effect;
}; };
struct layout_range_spacing {
struct layout_range_header h;
FLOAT leading;
FLOAT trailing;
FLOAT min_advance;
};
enum layout_run_kind { enum layout_run_kind {
LAYOUT_RUN_REGULAR, LAYOUT_RUN_REGULAR,
LAYOUT_RUN_INLINE LAYOUT_RUN_INLINE
@ -213,6 +223,7 @@ struct dwrite_textlayout {
FLOAT maxheight; FLOAT maxheight;
struct list strike_ranges; struct list strike_ranges;
struct list effects; struct list effects;
struct list spacing;
struct list ranges; struct list ranges;
struct list runs; struct list runs;
/* lists ready to use by Draw() */ /* lists ready to use by Draw() */
@ -1109,6 +1120,7 @@ static HRESULT layout_compute_effective_runs(struct dwrite_textlayout *layout)
static BOOL is_same_layout_attrvalue(struct layout_range_header const *h, enum layout_range_attr_kind attr, struct layout_range_attr_value *value) static BOOL is_same_layout_attrvalue(struct layout_range_header const *h, enum layout_range_attr_kind attr, struct layout_range_attr_value *value)
{ {
struct layout_range_spacing const *range_spacing = (struct layout_range_spacing*)h;
struct layout_range_effect const *range_effect = (struct layout_range_effect*)h; struct layout_range_effect const *range_effect = (struct layout_range_effect*)h;
struct layout_range_bool const *range_bool = (struct layout_range_bool*)h; struct layout_range_bool const *range_bool = (struct layout_range_bool*)h;
struct layout_range const *range = (struct layout_range*)h; struct layout_range const *range = (struct layout_range*)h;
@ -1138,6 +1150,10 @@ static BOOL is_same_layout_attrvalue(struct layout_range_header const *h, enum l
return strcmpW(range->locale, value->u.locale) == 0; return strcmpW(range->locale, value->u.locale) == 0;
case LAYOUT_RANGE_ATTR_FONTFAMILY: case LAYOUT_RANGE_ATTR_FONTFAMILY:
return strcmpW(range->fontfamily, value->u.fontfamily) == 0; return strcmpW(range->fontfamily, value->u.fontfamily) == 0;
case LAYOUT_RANGE_ATTR_SPACING:
return range_spacing->leading == value->u.spacing[0] &&
range_spacing->trailing == value->u.spacing[1] &&
range_spacing->min_advance == value->u.spacing[2];
default: default:
; ;
} }
@ -1176,6 +1192,14 @@ static inline BOOL is_same_layout_attributes(struct layout_range_header const *h
struct layout_range_effect const *right = (struct layout_range_effect const*)hright; struct layout_range_effect const *right = (struct layout_range_effect const*)hright;
return left->effect == right->effect; return left->effect == right->effect;
} }
case LAYOUT_RANGE_SPACING:
{
struct layout_range_spacing const *left = (struct layout_range_spacing const*)hleft;
struct layout_range_spacing const *right = (struct layout_range_spacing const*)hright;
return left->leading == right->leading &&
left->trailing == right->trailing &&
left->min_advance == right->min_advance;
}
default: default:
FIXME("unknown range kind %d\n", hleft->kind); FIXME("unknown range kind %d\n", hleft->kind);
return FALSE; return FALSE;
@ -1246,6 +1270,19 @@ static struct layout_range_header *alloc_layout_range(struct dwrite_textlayout *
h = &range->h; h = &range->h;
break; break;
} }
case LAYOUT_RANGE_SPACING:
{
struct layout_range_spacing *range;
range = heap_alloc(sizeof(*range));
if (!range) return NULL;
range->leading = 0.0;
range->trailing = 0.0;
range->min_advance = 0.0;
h = &range->h;
break;
}
default: default:
FIXME("unknown range kind %d\n", kind); FIXME("unknown range kind %d\n", kind);
return NULL; return NULL;
@ -1304,6 +1341,15 @@ static struct layout_range_header *alloc_layout_range_from(struct layout_range_h
ret = &effect->h; ret = &effect->h;
break; break;
} }
case LAYOUT_RANGE_SPACING:
{
struct layout_range_spacing *spacing = heap_alloc(sizeof(*spacing));
if (!spacing) return NULL;
*spacing = *(struct layout_range_spacing*)h;
ret = &spacing->h;
break;
}
default: default:
FIXME("unknown range kind %d\n", h->kind); FIXME("unknown range kind %d\n", h->kind);
return NULL; return NULL;
@ -1363,6 +1409,11 @@ static void free_layout_ranges_list(struct dwrite_textlayout *layout)
list_remove(&cur->entry); list_remove(&cur->entry);
free_layout_range(cur); free_layout_range(cur);
} }
LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->spacing, struct layout_range_header, entry) {
list_remove(&cur->entry);
free_layout_range(cur);
}
} }
static struct layout_range_header *find_outer_range(struct list *ranges, const DWRITE_TEXT_RANGE *range) static struct layout_range_header *find_outer_range(struct list *ranges, const DWRITE_TEXT_RANGE *range)
@ -1412,6 +1463,7 @@ static inline BOOL set_layout_range_iface_attr(IUnknown **dest, IUnknown *value)
static BOOL set_layout_range_attrval(struct layout_range_header *h, enum layout_range_attr_kind attr, struct layout_range_attr_value *value) static BOOL set_layout_range_attrval(struct layout_range_header *h, enum layout_range_attr_kind attr, struct layout_range_attr_value *value)
{ {
struct layout_range_spacing *dest_spacing = (struct layout_range_spacing*)h;
struct layout_range_effect *dest_effect = (struct layout_range_effect*)h; struct layout_range_effect *dest_effect = (struct layout_range_effect*)h;
struct layout_range_bool *dest_bool = (struct layout_range_bool*)h; struct layout_range_bool *dest_bool = (struct layout_range_bool*)h;
struct layout_range *dest = (struct layout_range*)h; struct layout_range *dest = (struct layout_range*)h;
@ -1468,6 +1520,14 @@ static BOOL set_layout_range_attrval(struct layout_range_header *h, enum layout_
dest->fontfamily = heap_strdupW(value->u.fontfamily); dest->fontfamily = heap_strdupW(value->u.fontfamily);
} }
break; break;
case LAYOUT_RANGE_ATTR_SPACING:
changed = dest_spacing->leading != value->u.spacing[0] ||
dest_spacing->trailing != value->u.spacing[1] ||
dest_spacing->min_advance != value->u.spacing[2];
dest_spacing->leading = value->u.spacing[0];
dest_spacing->trailing = value->u.spacing[1];
dest_spacing->min_advance = value->u.spacing[2];
break;
default: default:
; ;
} }
@ -1520,6 +1580,9 @@ static HRESULT set_layout_range_attr(struct dwrite_textlayout *layout, enum layo
case LAYOUT_RANGE_ATTR_EFFECT: case LAYOUT_RANGE_ATTR_EFFECT:
ranges = &layout->effects; ranges = &layout->effects;
break; break;
case LAYOUT_RANGE_ATTR_SPACING:
ranges = &layout->spacing;
break;
default: default:
FIXME("unknown attr kind %d\n", attr); FIXME("unknown attr kind %d\n", attr);
return E_FAIL; return E_FAIL;
@ -2560,20 +2623,38 @@ static HRESULT WINAPI dwritetextlayout1_GetPairKerning(IDWriteTextLayout2 *iface
return return_range(&range->h, r); return return_range(&range->h, r);
} }
static HRESULT WINAPI dwritetextlayout1_SetCharacterSpacing(IDWriteTextLayout2 *iface, FLOAT leading_spacing, FLOAT trailing_spacing, static HRESULT WINAPI dwritetextlayout1_SetCharacterSpacing(IDWriteTextLayout2 *iface, FLOAT leading, FLOAT trailing,
FLOAT minimum_advance_width, DWRITE_TEXT_RANGE range) FLOAT min_advance, DWRITE_TEXT_RANGE range)
{ {
struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface); struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
FIXME("(%p)->(%f %f %f %s): stub\n", This, leading_spacing, trailing_spacing, minimum_advance_width, debugstr_range(&range)); struct layout_range_attr_value value;
return E_NOTIMPL;
TRACE("(%p)->(%.2f %.2f %.2f %s)\n", This, leading, trailing, min_advance, debugstr_range(&range));
if (min_advance < 0.0)
return E_INVALIDARG;
value.range = range;
value.u.spacing[0] = leading;
value.u.spacing[1] = trailing;
value.u.spacing[2] = min_advance;
return set_layout_range_attr(This, LAYOUT_RANGE_ATTR_SPACING, &value);
} }
static HRESULT WINAPI dwritetextlayout1_GetCharacterSpacing(IDWriteTextLayout2 *iface, UINT32 position, FLOAT* leading_spacing, static HRESULT WINAPI dwritetextlayout1_GetCharacterSpacing(IDWriteTextLayout2 *iface, UINT32 position, FLOAT *leading,
FLOAT* trailing_spacing, FLOAT* minimum_advance_width, DWRITE_TEXT_RANGE *range) FLOAT *trailing, FLOAT *min_advance, DWRITE_TEXT_RANGE *r)
{ {
struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface); struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
FIXME("(%p)->(%u %p %p %p %p): stub\n", This, position, leading_spacing, trailing_spacing, minimum_advance_width, range); struct layout_range_spacing *range;
return E_NOTIMPL;
TRACE("(%p)->(%u %p %p %p %p)\n", This, position, leading, trailing, min_advance, r);
range = (struct layout_range_spacing*)get_layout_range_header_by_pos(&This->spacing, position);
*leading = range->leading;
*trailing = range->trailing;
*min_advance = range->min_advance;
return return_range(&range->h, r);
} }
static HRESULT WINAPI dwritetextlayout2_GetMetrics(IDWriteTextLayout2 *iface, DWRITE_TEXT_METRICS1 *metrics) static HRESULT WINAPI dwritetextlayout2_GetMetrics(IDWriteTextLayout2 *iface, DWRITE_TEXT_METRICS1 *metrics)
@ -3315,7 +3396,7 @@ static HRESULT layout_format_from_textformat(struct dwrite_textlayout *layout, I
static HRESULT init_textlayout(const WCHAR *str, UINT32 len, IDWriteTextFormat *format, FLOAT maxwidth, FLOAT maxheight, struct dwrite_textlayout *layout) static HRESULT init_textlayout(const WCHAR *str, UINT32 len, IDWriteTextFormat *format, FLOAT maxwidth, FLOAT maxheight, struct dwrite_textlayout *layout)
{ {
struct layout_range_header *range, *strike, *effect; struct layout_range_header *range, *strike, *effect, *spacing;
DWRITE_TEXT_RANGE r = { 0, ~0u }; DWRITE_TEXT_RANGE r = { 0, ~0u };
HRESULT hr; HRESULT hr;
@ -3344,6 +3425,7 @@ static HRESULT init_textlayout(const WCHAR *str, UINT32 len, IDWriteTextFormat *
list_init(&layout->ranges); list_init(&layout->ranges);
list_init(&layout->strike_ranges); list_init(&layout->strike_ranges);
list_init(&layout->effects); list_init(&layout->effects);
list_init(&layout->spacing);
memset(&layout->format, 0, sizeof(layout->format)); memset(&layout->format, 0, sizeof(layout->format));
layout->gdicompatible = FALSE; layout->gdicompatible = FALSE;
@ -3364,10 +3446,12 @@ static HRESULT init_textlayout(const WCHAR *str, UINT32 len, IDWriteTextFormat *
range = alloc_layout_range(layout, &r, LAYOUT_RANGE_REGULAR); range = alloc_layout_range(layout, &r, LAYOUT_RANGE_REGULAR);
strike = alloc_layout_range(layout, &r, LAYOUT_RANGE_STRIKETHROUGH); strike = alloc_layout_range(layout, &r, LAYOUT_RANGE_STRIKETHROUGH);
effect = alloc_layout_range(layout, &r, LAYOUT_RANGE_EFFECT); effect = alloc_layout_range(layout, &r, LAYOUT_RANGE_EFFECT);
if (!range || !strike || !effect) { spacing = alloc_layout_range(layout, &r, LAYOUT_RANGE_SPACING);
if (!range || !strike || !effect || !spacing) {
free_layout_range(range); free_layout_range(range);
free_layout_range(strike); free_layout_range(strike);
free_layout_range(effect); free_layout_range(effect);
free_layout_range(spacing);
hr = E_OUTOFMEMORY; hr = E_OUTOFMEMORY;
goto fail; goto fail;
} }
@ -3375,6 +3459,7 @@ static HRESULT init_textlayout(const WCHAR *str, UINT32 len, IDWriteTextFormat *
list_add_head(&layout->ranges, &range->entry); list_add_head(&layout->ranges, &range->entry);
list_add_head(&layout->strike_ranges, &strike->entry); list_add_head(&layout->strike_ranges, &strike->entry);
list_add_head(&layout->effects, &effect->entry); list_add_head(&layout->effects, &effect->entry);
list_add_head(&layout->spacing, &spacing->entry);
return S_OK; return S_OK;
fail: fail:

View File

@ -1536,17 +1536,23 @@ static void test_GetClusterMetrics(void)
DWRITE_TEXT_RANGE r; DWRITE_TEXT_RANGE r;
leading = trailing = min_advance = 2.0; leading = trailing = min_advance = 2.0;
hr = IDWriteTextLayout1_GetCharacterSpacing(layout1, 0, &leading, &trailing, hr = IDWriteTextLayout1_GetCharacterSpacing(layout1, 500, &leading, &trailing,
&min_advance, NULL); &min_advance, &r);
todo_wine {
ok(hr == S_OK, "got 0x%08x\n", hr); ok(hr == S_OK, "got 0x%08x\n", hr);
ok(leading == 0.0 && trailing == 0.0 && min_advance == 0.0, ok(leading == 0.0 && trailing == 0.0 && min_advance == 0.0,
"got %.2f, %.2f, %.2f\n", leading, trailing, min_advance); "got %.2f, %.2f, %.2f\n", leading, trailing, min_advance);
} ok(r.startPosition == 0 && r.length == ~0u, "got %u, %u\n", r.startPosition, r.length);
leading = trailing = min_advance = 2.0;
hr = IDWriteTextLayout1_GetCharacterSpacing(layout1, 0, &leading, &trailing,
&min_advance, NULL);
ok(hr == S_OK, "got 0x%08x\n", hr);
ok(leading == 0.0 && trailing == 0.0 && min_advance == 0.0,
"got %.2f, %.2f, %.2f\n", leading, trailing, min_advance);
r.startPosition = 0; r.startPosition = 0;
r.length = 4; r.length = 4;
hr = IDWriteTextLayout1_SetCharacterSpacing(layout1, 10.0, 15.0, 0.0, r); hr = IDWriteTextLayout1_SetCharacterSpacing(layout1, 10.0, 15.0, 0.0, r);
todo_wine
ok(hr == S_OK, "got 0x%08x\n", hr); ok(hr == S_OK, "got 0x%08x\n", hr);
count = 0; count = 0;
@ -1564,9 +1570,14 @@ todo_wine
r.startPosition = 0; r.startPosition = 0;
r.length = 4; r.length = 4;
hr = IDWriteTextLayout1_SetCharacterSpacing(layout1, 0.0, 0.0, 0.0, r); hr = IDWriteTextLayout1_SetCharacterSpacing(layout1, 0.0, 0.0, 0.0, r);
todo_wine
ok(hr == S_OK, "got 0x%08x\n", hr); ok(hr == S_OK, "got 0x%08x\n", hr);
/* negative advance limit */
r.startPosition = 0;
r.length = 4;
hr = IDWriteTextLayout1_SetCharacterSpacing(layout1, 0.0, 0.0, -10.0, r);
ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
IDWriteTextLayout1_Release(layout1); IDWriteTextLayout1_Release(layout1);
} }
else else