Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/dwrite/analyzer.c | 209 ++++++++++++++++------------------- dlls/dwrite/tests/analyzer.c | 158 +++++++++++++++++++------- 2 files changed, 215 insertions(+), 152 deletions(-)
diff --git a/dlls/dwrite/analyzer.c b/dlls/dwrite/analyzer.c index a1d9f25ad1..7ee3675d2e 100644 --- a/dlls/dwrite/analyzer.c +++ b/dlls/dwrite/analyzer.c @@ -1397,124 +1397,121 @@ static inline FLOAT get_cluster_advance(const FLOAT *advances, UINT32 start, UIN return advance; }
-static void apply_single_glyph_spacing(FLOAT leading_spacing, FLOAT trailing_spacing, - FLOAT min_advance_width, UINT32 g, FLOAT const *advances, DWRITE_GLYPH_OFFSET const *offsets, - DWRITE_SHAPING_GLYPH_PROPERTIES const *props, FLOAT *modified_advances, DWRITE_GLYPH_OFFSET *modified_offsets) +static HRESULT apply_cluster_spacing(float leading_spacing, float trailing_spacing, float min_advance_width, + unsigned int start, unsigned int end, float const *advances, DWRITE_GLYPH_OFFSET const *offsets, + DWRITE_SHAPING_GLYPH_PROPERTIES const *glyph_props, float *modified_advances, + DWRITE_GLYPH_OFFSET *modified_offsets) { BOOL reduced = leading_spacing < 0.0f || trailing_spacing < 0.0f; - FLOAT advance = advances[g]; - FLOAT origin = 0.0f; + unsigned int first_spacing, last_spacing, i; + float advance, origin = 0.0f, *deltas; + BOOL is_spacing_cluster = FALSE;
- if (props[g].isZeroWidthSpace) { - modified_advances[g] = advances[g]; - modified_offsets[g] = offsets[g]; - return; - } + if (modified_advances != advances) + memcpy(&modified_advances[start], &advances[start], (end - start + 1) * sizeof(*advances)); + if (modified_offsets != offsets) + memcpy(&modified_offsets[start], &offsets[start], (end - start + 1) * sizeof(*offsets));
- /* first apply negative spacing and check if we hit minimum width */ - if (leading_spacing < 0.0f) { - advance += leading_spacing; - origin -= leading_spacing; + for (first_spacing = start; first_spacing <= end; ++first_spacing) + { + if ((is_spacing_cluster = !glyph_props[first_spacing].isZeroWidthSpace)) + break; } - if (trailing_spacing < 0.0f) - advance += trailing_spacing;
- if (advance < min_advance_width) { - FLOAT half = (min_advance_width - advance) / 2.0f; - - if (!reduced) - origin -= half; - else if (leading_spacing < 0.0f && trailing_spacing < 0.0f) - origin -= half; - else if (leading_spacing < 0.0f) - origin -= min_advance_width - advance; + /* Nothing to adjust if there is no spacing glyphs. */ + if (!is_spacing_cluster) + return S_OK;
- advance = min_advance_width; + for (last_spacing = end; last_spacing >= start; --last_spacing) + { + if (!glyph_props[last_spacing].isZeroWidthSpace) + break; }
- /* now apply positive spacing adjustments */ - if (leading_spacing > 0.0f) { - advance += leading_spacing; - origin -= leading_spacing; - } - if (trailing_spacing > 0.0f) - advance += trailing_spacing; + deltas = heap_alloc((end - start + 1) * sizeof(*deltas)); + if (!deltas) + return E_OUTOFMEMORY;
- modified_advances[g] = advance; - modified_offsets[g].advanceOffset = offsets[g].advanceOffset - origin; - /* ascender is never touched, it's orthogonal to reading direction and is not - affected by advance adjustments */ - modified_offsets[g].ascenderOffset = offsets[g].ascenderOffset; -} + /* Cluster advance, note that properties are ignored. */ + origin = offsets[start].advanceOffset; + for (i = start, advance = 0.0f; i <= end; ++i) + { + float cur = advance + offsets[i].advanceOffset;
-static void apply_cluster_spacing(FLOAT leading_spacing, FLOAT trailing_spacing, FLOAT min_advance_width, - UINT32 start, UINT32 end, FLOAT const *advances, DWRITE_GLYPH_OFFSET const *offsets, - FLOAT *modified_advances, DWRITE_GLYPH_OFFSET *modified_offsets) -{ - BOOL reduced = leading_spacing < 0.0f || trailing_spacing < 0.0f; - FLOAT advance = get_cluster_advance(advances, start, end); - FLOAT origin = 0.0f; - UINT16 g; + deltas[i - start] = cur - origin;
- modified_advances[start] = advances[start]; - modified_advances[end-1] = advances[end-1]; + advance += advances[i]; + origin = cur; + }
- /* first apply negative spacing and check if we hit minimum width */ - if (leading_spacing < 0.0f) { + /* Negative spacing. */ + if (leading_spacing < 0.0f) + { advance += leading_spacing; - modified_advances[start] += leading_spacing; - origin -= leading_spacing; + modified_advances[first_spacing] += leading_spacing; + modified_offsets[first_spacing].advanceOffset += leading_spacing; } - if (trailing_spacing < 0.0f) { + + if (trailing_spacing < 0.0f) + { advance += trailing_spacing; - modified_advances[end-1] += trailing_spacing; + modified_advances[last_spacing] += trailing_spacing; }
+ /* Minimal advance. */ advance = min_advance_width - advance; if (advance > 0.0f) { - /* additional spacing is only applied to leading and trailing glyph */ - FLOAT half = advance / 2.0f; + /* Additional spacing is only applied to leading and trailing spacing glyphs. */ + float half = advance / 2.0f;
- if (!reduced) { - origin -= half; - modified_advances[start] += half; - modified_advances[end-1] += half; + if (!reduced) + { + modified_advances[first_spacing] += half; + modified_advances[last_spacing] += half; + modified_offsets[first_spacing].advanceOffset += half; } - else if (leading_spacing < 0.0f && trailing_spacing < 0.0f) { - origin -= half; - modified_advances[start] += half; - modified_advances[end-1] += half; + else if (leading_spacing < 0.0f && trailing_spacing < 0.0f) + { + modified_advances[first_spacing] += half; + modified_advances[last_spacing] += half; + modified_offsets[first_spacing].advanceOffset += half; } - else if (leading_spacing < 0.0f) { - origin -= advance; - modified_advances[start] += advance; + else if (leading_spacing < 0.0f) + { + modified_advances[first_spacing] += advance; + modified_offsets[first_spacing].advanceOffset += advance; } else - modified_advances[end-1] += advance; + modified_advances[last_spacing] += advance; }
- /* now apply positive spacing adjustments */ - if (leading_spacing > 0.0f) { - modified_advances[start] += leading_spacing; - origin -= leading_spacing; + /* Positive spacing. */ + if (leading_spacing > 0.0f) + { + modified_advances[first_spacing] += leading_spacing; + modified_offsets[first_spacing].advanceOffset += leading_spacing; } + if (trailing_spacing > 0.0f) - modified_advances[end-1] += trailing_spacing; + modified_advances[last_spacing] += trailing_spacing;
- for (g = start; g < end; g++) { - if (g == start) { - modified_offsets[g].advanceOffset = offsets[g].advanceOffset - origin; - modified_offsets[g].ascenderOffset = offsets[g].ascenderOffset; - } - else if (g == end - 1) - /* trailing glyph offset is not adjusted */ - modified_offsets[g] = offsets[g]; - else { - /* for all glyphs within a cluster use original advances and offsets */ - modified_advances[g] = advances[g]; - modified_offsets[g] = offsets[g]; - } + /* Update offsets to preserve original relative positions within cluster. */ + for (i = first_spacing; i > start; --i) + { + unsigned int cur = i - 1; + modified_offsets[cur].advanceOffset = modified_advances[cur] + modified_offsets[i].advanceOffset - + deltas[i - start]; + } + + for (i = first_spacing + 1; i <= end; ++i) + { + modified_offsets[i].advanceOffset = deltas[i - start] + modified_offsets[i - 1].advanceOffset - + modified_advances[i - 1]; } + + heap_free(deltas); + + return S_OK; }
static inline UINT32 get_cluster_length(UINT16 const *clustermap, UINT32 start, UINT32 text_len) @@ -1562,16 +1559,13 @@ static inline UINT32 get_cluster_length(UINT16 const *clustermap, UINT32 start,
It's known that isZeroWidthSpace property keeps initial advance from changing.
- TODO: test other properties; make isZeroWidthSpace work properly for clusters - with more than one glyph. - */ static HRESULT WINAPI dwritetextanalyzer1_ApplyCharacterSpacing(IDWriteTextAnalyzer2 *iface, FLOAT leading_spacing, FLOAT trailing_spacing, FLOAT min_advance_width, UINT32 len, UINT32 glyph_count, UINT16 const *clustermap, FLOAT const *advances, DWRITE_GLYPH_OFFSET const *offsets, DWRITE_SHAPING_GLYPH_PROPERTIES const *props, FLOAT *modified_advances, DWRITE_GLYPH_OFFSET *modified_offsets) { - UINT16 start; + unsigned int i;
TRACE("(%.2f %.2f %.2f %u %u %p %p %p %p %p %p)\n", leading_spacing, trailing_spacing, min_advance_width, len, glyph_count, clustermap, advances, offsets, props, modified_advances, modified_offsets); @@ -1582,33 +1576,18 @@ static HRESULT WINAPI dwritetextanalyzer1_ApplyCharacterSpacing(IDWriteTextAnaly return E_INVALIDARG; }
- /* minimum advance is not applied if no adjustments were made */ - if (leading_spacing == 0.0f && trailing_spacing == 0.0f) { - memmove(modified_advances, advances, glyph_count*sizeof(*advances)); - memmove(modified_offsets, offsets, glyph_count*sizeof(*offsets)); - return S_OK; - } - - for (start = 0; start < len;) { - UINT32 length = get_cluster_length(clustermap, start, len); - - if (length == 1) { - UINT32 g = clustermap[start]; - - apply_single_glyph_spacing(leading_spacing, trailing_spacing, min_advance_width, - g, advances, offsets, props, modified_advances, modified_offsets); - } - else { - UINT32 g_start, g_end; + for (i = 0; i < len;) + { + unsigned int length = get_cluster_length(clustermap, i, len); + unsigned int start, end;
- g_start = clustermap[start]; - g_end = (start + length < len) ? clustermap[start + length] : glyph_count; + start = clustermap[i]; + end = i + length < len ? clustermap[i + length] : glyph_count;
- apply_cluster_spacing(leading_spacing, trailing_spacing, min_advance_width, - g_start, g_end, advances, offsets, modified_advances, modified_offsets); - } + apply_cluster_spacing(leading_spacing, trailing_spacing, min_advance_width, start, end - 1, advances, + offsets, props, modified_advances, modified_offsets);
- start += length; + i += length; }
return S_OK; diff --git a/dlls/dwrite/tests/analyzer.c b/dlls/dwrite/tests/analyzer.c index 77369a7ef9..251887f508 100644 --- a/dlls/dwrite/tests/analyzer.c +++ b/dlls/dwrite/tests/analyzer.c @@ -1738,7 +1738,17 @@ struct spacing_test { DWRITE_SHAPING_GLYPH_PROPERTIES props[3]; };
-static const struct spacing_test spacing_tests[] = { +static const struct spacing_test spacing_tests[] = +{ +/* Default spacing glyph properties. */ +#define P_S { 0 } +/* isZeroWidthSpace */ +#define P_Z { 0, 0, 0, 1, 0 } +/* isDiacritic */ +#define P_D { 0, 0, 1, 0, 0 } +/* isDiacritic + isZeroWidthSpace, that's how diacritics are shaped. */ +#define P_D_Z { 0, 0, 1, 1, 0 } + { 0.0, 0.0, 0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 11.0 }, { 2.0, 3.0 } }, /* 0 */ { 0.0, 0.0, 2.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 11.0 }, { 2.0, 3.0 } }, { 1.0, 0.0, 0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 11.0, 12.0 }, { 3.0, 4.0 } }, @@ -1756,9 +1766,9 @@ static const struct spacing_test spacing_tests[] = { { 1.0, -10.0, -5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 0.0, 0.0 }, { 2.0, 3.0 } }, { -10.0, 1.0, 5.0, { 8.0, 11.0 }, { 2.0, 3.0 }, { 6.0, 6.0 }, { -1.0, -3.0 } }, /* 15 */ /* cluster of more than 1 glyph */ - { 0.0, 0.0, 0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 11.0 }, { 2.0, 3.0 }, TRUE }, - { 1.0, 0.0, 0.0, { 10.0, 11.0 }, { 2.0, 3.5 }, { 11.0, 11.0 }, { 3.0, 3.5 }, TRUE }, - { 1.0, 1.0, 0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 11.0, 12.0 }, { 3.0, 3.0 }, TRUE }, + { 0.0f, 0.0f, 0.0f, { 10.0f, 11.0f }, { 2.0f, 3.0f }, { 10.0f, 11.0f }, { 2.0f, 3.0f }, TRUE }, + { 1.0f, 0.0f, 0.0f, { 10.0f, 11.0f }, { 2.0f, 3.5f }, { 11.0f, 11.0f }, { 3.0f, 3.5f }, TRUE }, + { 1.0f, 1.0f, 0.0f, { 10.0f, 11.0f }, { 2.0f, 3.0f }, { 11.0f, 12.0f }, { 3.0f, 3.0f }, TRUE }, { 1.0, -1.0, 0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 11.0, 10.0 }, { 3.0, 3.0 }, TRUE }, { 0.0, -10.0, 0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 1.0 }, { 2.0, 3.0 }, TRUE }, /* 20 */ { 0.0, -10.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 1.0 }, { 2.0, 3.0 }, TRUE }, @@ -1770,35 +1780,106 @@ static const struct spacing_test spacing_tests[] = { { 1.0, -10.0, 5.0, { 2.0, 1.0, 10.0 }, { 2.0, 3.0, 4.0 }, { 3.0, 1.0, 2.0 }, { 3.0, 3.0, 4.0 }, TRUE }, { -10.0, -10.0, 5.0, { 11.0, 1.0, 11.0 }, { 2.0, 3.0, 4.0 }, { 2.0, 1.0, 2.0 }, { -7.0, 3.0, 4.0 }, TRUE }, /* isZeroWidthSpace set */ - { 1.0, 0.0, 0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 12.0 }, { 2.0, 4.0 }, FALSE, { { 0, 0, 0, 1, 0 }, { 0 } } }, - { 1.0, 1.0, 0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 13.0 }, { 2.0, 4.0 }, FALSE, { { 0, 0, 0, 1, 0 }, { 0 } } }, /* 30 */ - { 1.0, -1.0, 0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 11.0 }, { 3.0, 3.0 }, FALSE, { { 0 }, { 0, 0, 0, 1, 0 } } }, - { 0.0, -10.0, 0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 1.0 }, { 2.0, 3.0 }, FALSE, { { 0, 0, 0, 1, 0 }, { 0 } } }, - { -5.0, -4.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 5.0, 11.0 }, { -1.0, 3.0 }, FALSE, { { 0 }, { 0, 0, 0, 1, 0 } } }, - { -5.0, -5.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 11.0 }, { 2.0, 3.0 }, FALSE, { { 0, 0, 0, 1, 0 }, { 0, 0, 0, 1, 0 }} }, - { 2.0, 0.0, 5.0, { 1.0, 2.0 }, { 2.0, 3.0 }, { 7.0, 2.0 }, { 6.0, 3.0 }, FALSE, { { 0 }, { 0, 0, 0, 1, 0 } } }, /* 35 */ - { 2.0, 1.0, 5.0, { 1.0, 2.0 }, { 2.0, 3.0 }, { 8.0, 2.0 }, { 6.0, 3.0 }, FALSE, { { 0 }, { 0, 0, 0, 1, 0 } } }, - { 2.0, -10.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 11.0 }, { 2.0, 3.0 }, FALSE, { { 0, 0, 0, 1, 0 }, { 0, 0, 0, 1, 0 } } }, - { 1.0, -10.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 6.0, 11.0 }, { 3.0, 3.0 }, FALSE, { { 0 }, { 0, 0, 0, 1, 0 } } }, - { -10.0, 1.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 11.0 }, { 2.0, 3.0 }, FALSE, { { 0, 0, 0, 1, 0 }, { 0, 0, 0, 1, 0 } } }, - { 0.0, -10.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 5.0, 11.0 }, { 2.0, 3.0 }, FALSE, { { 0 }, { 0, 0, 0, 1, 0 } } }, /* 40 */ - { 1.0, -10.0, -5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 0.0, 0.0 }, { 2.0, 3.0 }, FALSE, { { 0, 0, 0, 1, 0 }, { 0 } } }, - { -10.0, 1.0, 5.0, { 8.0, 11.0 }, { 2.0, 3.0 }, { 6.0, 11.0 }, { -1.0, 3.0 }, FALSE, { { 0 }, { 0, 0, 0, 1, 0 } } }, + { 1.0, 0.0, 0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 12.0 }, { 2.0, 4.0 }, FALSE, { P_Z, P_S } }, + { 1.0, 1.0, 0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 13.0 }, { 2.0, 4.0 }, FALSE, { P_Z, P_S } }, /* 30 */ + { 1.0, -1.0, 0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 11.0 }, { 3.0, 3.0 }, FALSE, { P_S, P_Z } }, + { 0.0, -10.0, 0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 1.0 }, { 2.0, 3.0 }, FALSE, { P_Z, P_S } }, + { -5.0, -4.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 5.0, 11.0 }, { -1.0, 3.0 }, FALSE, { P_S, P_Z } }, + { -5.0, -5.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 11.0 }, { 2.0, 3.0 }, FALSE, { P_Z, P_Z } }, + { 2.0, 0.0, 5.0, { 1.0, 2.0 }, { 2.0, 3.0 }, { 7.0, 2.0 }, { 6.0, 3.0 }, FALSE, { P_S, P_Z } }, /* 35 */ + { 2.0, 1.0, 5.0, { 1.0, 2.0 }, { 2.0, 3.0 }, { 8.0, 2.0 }, { 6.0, 3.0 }, FALSE, { P_S, P_Z } }, + { 2.0, -10.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 11.0 }, { 2.0, 3.0 }, FALSE, { P_Z, P_Z } }, + { 1.0, -10.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 6.0, 11.0 }, { 3.0, 3.0 }, FALSE, { P_S, P_Z } }, + { -10.0, 1.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 11.0 }, { 2.0, 3.0 }, FALSE, { P_Z, P_Z } }, + { 0.0, -10.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 5.0, 11.0 }, { 2.0, 3.0 }, FALSE, { P_S, P_Z } }, /* 40 */ + { 1.0, -10.0, -5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 0.0, 0.0 }, { 2.0, 3.0 }, FALSE, { P_Z, P_S } }, + { -10.0, 1.0, 5.0, { 8.0, 11.0 }, { 2.0, 3.0 }, { 6.0, 11.0 }, { -1.0, 3.0 }, FALSE, { P_S, P_Z } }, /* isDiacritic */ - { 1.0, 0.0, 0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 11.0, 12.0 }, { 3.0, 4.0 }, FALSE, { { 0, 0, 1, 0, 0 }, { 0 } } }, - { 1.0, 1.0, 0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 12.0, 13.0 }, { 3.0, 4.0 }, FALSE, { { 0, 0, 1, 0, 0 }, { 0 } } }, - { 1.0, -1.0, 0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 11.0 }, { 3.0, 4.0 }, FALSE, { { 0 }, { 0, 0, 1, 0, 0 } } }, /* 45 */ - { 0.0, -10.0, 0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 0.0, 1.0 }, { 2.0, 3.0 }, FALSE, { { 0, 0, 1, 0, 0 }, { 0 } } }, - { -5.0, -4.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 5.0, 5.0 }, { -1.0, -0.5 }, FALSE, { { 0 }, { 0, 0, 1, 0, 0 } } }, - { -5.0, -5.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 5.0, 5.0 }, { -0.5, 0.0 }, FALSE, { { 0, 0, 1, 0, 0 }, { 0, 0, 1, 0, 0 }} }, - { 2.0, 0.0, 5.0, { 1.0, 2.0 }, { 2.0, 3.0 }, { 7.0, 7.0 }, { 6.0, 6.5 }, FALSE, { { 0 }, { 0, 0, 1, 0, 0 } } }, - { 2.0, 1.0, 5.0, { 1.0, 2.0 }, { 2.0, 3.0 }, { 8.0, 8.0 }, { 6.0, 6.5 }, FALSE, { { 0 }, { 0, 0, 1, 0, 0 } } }, /* 50 */ - { 2.0, -10.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 7.0, 7.0 }, { 4.0, 5.0 }, FALSE, { { 0, 0, 1, 0, 0 }, { 0, 0, 1, 0, 0 } } }, - { 1.0, -10.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 6.0, 11.0 }, { 3.0, 3.0 }, FALSE, { { 0 }, { 0, 0, 0, 1, 0 } } }, - { -10.0, 1.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 6.0, 6.0 }, { -3.0, -3.0 }, FALSE, { { 0, 0, 1, 0, 0 }, { 0, 0, 1, 0, 0 } } }, - { 0.0, -10.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 5.0, 5.0 }, { 2.0, 3.0 }, FALSE, { { 0 }, { 0, 0, 1, 0, 0 } } }, - { 1.0, -10.0, -5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 0.0, 0.0 }, { 2.0, 3.0 }, FALSE, { { 0, 0, 1, 0, 0 }, { 0 } } }, /* 55 */ - { -10.0, 1.0, 5.0, { 8.0, 11.0 }, { 2.0, 3.0 }, { 6.0, 6.0 }, { -1.0, -3.0 }, FALSE, { { 0 }, { 0, 0, 1, 0, 0 } } }, + { 1.0, 0.0, 0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 11.0, 12.0 }, { 3.0, 4.0 }, FALSE, { P_D, P_S } }, + { 1.0, 1.0, 0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 12.0, 13.0 }, { 3.0, 4.0 }, FALSE, { P_D, P_S } }, + { 1.0, -1.0, 0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 11.0 }, { 3.0, 4.0 }, FALSE, { P_S, P_D } }, /* 45 */ + { 0.0, -10.0, 0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 0.0, 1.0 }, { 2.0, 3.0 }, FALSE, { P_D, P_S } }, + { -5.0, -4.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 5.0, 5.0 }, { -1.0, -0.5 }, FALSE, { P_S, P_D } }, + { -5.0, -5.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 5.0, 5.0 }, { -0.5, 0.0 }, FALSE, { P_D, P_D } }, + { 2.0, 0.0, 5.0, { 1.0, 2.0 }, { 2.0, 3.0 }, { 7.0, 7.0 }, { 6.0, 6.5 }, FALSE, { P_S, P_D } }, + { 2.0, 1.0, 5.0, { 1.0, 2.0 }, { 2.0, 3.0 }, { 8.0, 8.0 }, { 6.0, 6.5 }, FALSE, { P_S, P_D } }, /* 50 */ + { 2.0, -10.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 7.0, 7.0 }, { 4.0, 5.0 }, FALSE, { P_D, P_D } }, + { 1.0, -10.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 6.0, 6.0 }, { 3.0, 4.0 }, FALSE, { P_S, P_D } }, + { -10.0, 1.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 6.0, 6.0 }, { -3.0, -3.0 }, FALSE, { P_D, P_D } }, + { 0.0, -10.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 5.0, 5.0 }, { 2.0, 3.0 }, FALSE, { P_S, P_D } }, + { 1.0, -10.0, -5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 0.0, 0.0 }, { 2.0, 3.0 }, FALSE, { P_D, P_S } }, /* 55 */ + { -10.0, 1.0, 5.0, { 8.0, 11.0 }, { 2.0, 3.0 }, { 6.0, 6.0 }, { -1.0, -3.0 }, FALSE, { P_S, P_D } }, + /* isZeroWidthSpace in a cluster */ + { 1.0, 0.0, 0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 12.0 }, { 3.0, 4.0 }, TRUE, { P_Z, P_S } }, + { 1.0, 1.0, 0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 13.0 }, { 3.0, 4.0 }, TRUE, { P_Z, P_S } }, + { 1.0, -1.0, 0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 11.0 }, { 3.0, 4.0 }, TRUE, { P_S, P_Z } }, + { 0.0, -10.0, 0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 1.0 }, { 2.0, 3.0 }, TRUE, { P_Z, P_S } }, /* 60 */ + { -5.0, -4.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 1.0, 11.0 }, { -3.0, 7.0 }, TRUE, { P_S, P_Z } }, + { -5.0, -5.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 11.0 }, { 2.0, 3.0 }, TRUE, { P_Z, P_Z } }, + { 0.0, 0.0, 5.0, { 1.0, 2.0 }, { 2.0, 3.0 }, { 3.0, 2.0 }, { 3.0, 2.0 }, TRUE, { P_S, P_Z } }, + { 0.0, 0.0, 5.0, { 1.0, 2.0, 1.0 }, { 2.0, 3.0, 5.0 }, { 1.5, 2.0, 1.5 }, { 2.5, 3.0, 5.0 }, TRUE, { P_S, P_Z, P_S } }, + { 0.0, 0.0, 5.0, { 1.0, 2.0, 1.0 }, { 2.0, 3.0, 5.0 }, { 1.5, 2.5, 1.0 }, { 2.5, 3.0, 4.5 }, TRUE, { P_S, P_S, P_Z } }, + { 0.0, 0.0, 5.0, { 1.0, 2.0, 1.0 }, { 2.0, 3.0, 5.0 }, { 2.0, 2.0, 1.0 }, { 2.5, 2.5, 4.5 }, TRUE, { P_S, P_Z, P_Z } }, + { 0.0, 0.0, 5.0, { 1.0, 2.0, 1.0 }, { 2.0, 3.0, 5.0 }, { 1.0, 2.0, 1.0 }, { 2.0, 3.0, 5.0 }, TRUE, { P_Z, P_Z, P_Z } }, + { 2.0, 1.0, 1.0, { 1.0, 2.0, 3.0 }, { 2.0, 3.0, 4.0 }, { 3.0, 2.0, 4.0 }, { 4.0, 3.0, 4.0 }, TRUE, { P_S, P_Z, P_S } }, + { 0.0, 0.0, 5.0, { 1.0, 2.0 }, { 2.0, 3.0 }, { 3.0, 2.0 }, { 3.0, 2.0 }, TRUE, { P_S, P_Z } }, + { 0.0, 0.0, 5.0, { 1.0, 2.0, 6.0 }, { 2.0, 3.0, 4.0 }, { 1.0, 2.0, 6.0 }, { 2.0, 3.0, 4.0 }, TRUE, { P_S, P_Z, P_S } }, + { 2.0, -10.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 11.0 }, { 2.0, 3.0 }, TRUE, { P_Z, P_Z } }, /* 65 */ + { 1.0, -10.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 1.0, 11.0 }, { 3.0, 13.0 }, TRUE, { P_S, P_Z } }, + { -10.0, 1.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 11.0 }, { 2.0, 3.0 }, TRUE, { P_Z, P_Z } }, + { 0.0, -10.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 0.0, 11.0 }, { 2.0, 13.0 }, TRUE, { P_S, P_Z } }, + { 1.0, -10.0, -5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 0.0, 0.0 }, { 2.0, 3.0 }, TRUE, { P_Z, P_S } }, + { -10.0, 1.0, 5.0, { 8.0, 11.0 }, { 2.0, 3.0 }, { -1.0, 11.0 }, { -8.0, 2.0 }, TRUE, { P_S, P_Z } }, /* 70 */ + /* isDiacritic in a cluster */ + { 1.0, 0.0, 0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 11.0, 11.0 }, { 3.0, 3.0 }, TRUE, { P_D, P_S } }, + { 1.0, 1.0, 0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 11.0, 12.0 }, { 3.0, 3.0 }, TRUE, { P_D, P_S } }, + { 1.0, -1.0, 0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 11.0, 10.0 }, { 3.0, 3.0 }, TRUE, { P_S, P_D } }, + { 0.0, -10.0, 0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 1.0 }, { 2.0, 3.0 }, TRUE, { P_D, P_S } }, + { -5.0, -4.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 5.0, 7.0 }, { -3.0, 3.0 }, TRUE, { P_S, P_D } }, /* 75 */ + { -5.0, -5.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 5.0, 6.0 }, { -3.0, 3.0 }, TRUE, { P_D, P_D } }, + { 2.0, 0.0, 5.0, { 1.0, 2.0 }, { 2.0, 3.0 }, { 4.0, 3.0 }, { 5.0, 3.0 }, TRUE, { P_S, P_D } }, + { 2.0, 1.0, 5.0, { 1.0, 2.0 }, { 2.0, 3.0 }, { 4.0, 4.0 }, { 5.0, 3.0 }, TRUE, { P_S, P_D } }, + { 2.0, -10.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 12.0, 1.0 }, { 4.0, 3.0 }, TRUE, { P_D, P_D } }, + { 1.0, -10.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 11.0, 1.0 }, { 3.0, 3.0 }, TRUE, { P_S, P_D } }, /* 80 */ + { -10.0, 1.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 0.0, 12.0 }, { -8.0, 3.0 }, TRUE, { P_D, P_D } }, + { 0.0, -10.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 1.0 }, { 2.0, 3.0 }, TRUE, { P_S, P_D } }, + { 1.0, -10.0, -5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 0.0, 0.0 }, { 2.0, 3.0 }, TRUE, { P_D, P_S } }, + { -10.0, 1.0, 5.0, { 8.0, 11.0 }, { 2.0, 3.0 }, { -2.0, 12.0 }, { -8.0, 3.0 }, TRUE, { P_S, P_D } }, + /* isZeroWidthSpace + isDiacritic */ + { 1.0, 0.0, 0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 12.0 }, { 2.0, 4.0 }, FALSE, { P_D_Z, P_S } }, /* 85 */ + { 1.0, 1.0, 0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 13.0 }, { 2.0, 4.0 }, FALSE, { P_D_Z, P_S } }, + { 1.0, -1.0, 0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 11.0 }, { 3.0, 3.0 }, FALSE, { P_S, P_D_Z } }, + { 0.0, -10.0, 0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 1.0 }, { 2.0, 3.0 }, FALSE, { P_D_Z, P_S } }, + { -5.0, -4.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 5.0, 11.0 }, { -1.0, 3.0 }, FALSE, { P_S, P_D_Z } }, + { -5.0, -5.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 11.0 }, { 2.0, 3.0 }, FALSE, { P_D_Z, P_D_Z } }, /* 90 */ + { 2.0, 0.0, 5.0, { 1.0, 2.0 }, { 2.0, 3.0 }, { 7.0, 2.0 }, { 6.0, 3.0 }, FALSE, { P_S, P_D_Z } }, + { 2.0, 1.0, 5.0, { 1.0, 2.0 }, { 2.0, 3.0 }, { 8.0, 2.0 }, { 6.0, 3.0 }, FALSE, { P_S, P_D_Z } }, + { 2.0, -10.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 11.0 }, { 2.0, 3.0 }, FALSE, { P_D_Z, P_D_Z } }, + { 1.0, -10.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 6.0, 11.0 }, { 3.0, 3.0 }, FALSE, { P_S, P_D_Z } }, + { -10.0, 1.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 11.0 }, { 2.0, 3.0 }, FALSE, { P_D_Z, P_D_Z } }, /* 95 */ + { 0.0, -10.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 5.0, 11.0 }, { 2.0, 3.0 }, FALSE, { P_S, P_D_Z } }, + { 1.0, -10.0, -5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 0.0, 0.0 }, { 2.0, 3.0 }, FALSE, { P_D_Z, P_S } }, + { -10.0, 1.0, 5.0, { 8.0, 11.0 }, { 2.0, 3.0 }, { 6.0, 11.0 }, { -1.0, 3.0 }, FALSE, { P_S, P_D_Z } }, + /* isZeroWidthSpace + isDiacritic in a cluster */ + { 1.0, 0.0, 0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 12.0 }, { 3.0, 4.0 }, TRUE, { P_D_Z, P_S } }, + { 1.0, 1.0, 0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 13.0 }, { 3.0, 4.0 }, TRUE, { P_D_Z, P_S } }, /* 100 */ + { 1.0, -1.0, 0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 11.0 }, { 3.0, 4.0 }, TRUE, { P_S, P_D_Z } }, + { 0.0, -10.0, 0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 1.0 }, { 2.0, 3.0 }, TRUE, { P_D_Z, P_S } }, + { -5.0, -4.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 1.0, 11.0 }, { -3.0, 7.0 }, TRUE, { P_S, P_D_Z } }, + { -5.0, -5.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 11.0 }, { 2.0, 3.0 }, TRUE, { P_D_Z, P_D_Z } }, + { 2.0, 0.0, 5.0, { 1.0, 2.0 }, { 2.0, 3.0 }, { 5.0, 2.0 }, { 5.0, 2.0 }, TRUE, { P_S, P_D_Z } }, /* 105 */ + { 2.0, 1.0, 5.0, { 1.0, 2.0 }, { 2.0, 3.0 }, { 6.0, 2.0 }, { 5.0, 1.0 }, TRUE, { P_S, P_D_Z } }, + { 2.0, -10.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 11.0 }, { 2.0, 3.0 }, TRUE, { P_D_Z, P_D_Z } }, + { 1.0, -10.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 1.0, 11.0 }, { 3.0, 13.0 }, TRUE, { P_S, P_D_Z } }, + { -10.0, 1.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 11.0 }, { 2.0, 3.0 }, TRUE, { P_D_Z, P_D_Z } }, + { 0.0, -10.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 0.0, 11.0 }, { 2.0, 13.0 }, TRUE, { P_S, P_D_Z } }, /* 110 */ + { 1.0, -10.0, -5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 0.0, 0.0 }, { 2.0, 3.0 }, TRUE, { P_D_Z, P_S } }, + { -10.0, 1.0, 5.0, { 8.0, 11.0 }, { 2.0, 3.0 }, { -1.0, 11.0 }, { -8.0, 2.0 }, TRUE, { P_S, P_D_Z } }, + +#undef P_S +#undef P_D +#undef P_Z +#undef P_D_Z };
static void test_ApplyCharacterSpacing(void) @@ -1835,20 +1916,23 @@ static void test_ApplyCharacterSpacing(void) offsets[1].ascenderOffset = 32.0; offsets[2].ascenderOffset = 31.0;
+ advances[0] = advances[1] = 123.45f; + memcpy(props, ptr->props, sizeof(props)); glyph_count = ptr->advances[2] > 0.0 ? 3 : 2; - if (ptr->single_cluster) { + if (ptr->single_cluster) + { clustermap[0] = 0; clustermap[1] = 0; + props[0].isClusterStart = 1; } - else { + else + { /* trivial case with one glyph per cluster */ clustermap[0] = 0; clustermap[1] = 1; + props[0].isClusterStart = props[1].isClusterStart = 1; }
- advances[0] = advances[1] = 123.45; - memcpy(props, ptr->props, sizeof(props)); - hr = IDWriteTextAnalyzer1_ApplyCharacterSpacing(analyzer1, ptr->leading, ptr->trailing,
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/dwrite/tests/font.c | 89 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 87 insertions(+), 2 deletions(-)
diff --git a/dlls/dwrite/tests/font.c b/dlls/dwrite/tests/font.c index 3f4128986c..3e736c82b7 100644 --- a/dlls/dwrite/tests/font.c +++ b/dlls/dwrite/tests/font.c @@ -8038,17 +8038,73 @@ static void test_HasKerningPairs(void) ok(ref == 0, "factory not released, %u\n", ref); }
+static void get_expected_glyph_origins(D2D1_POINT_2F baseline_origin, const DWRITE_GLYPH_RUN *run, + D2D1_POINT_2F *origins) +{ + unsigned int i; + + if (run->bidiLevel & 1) + { + DWRITE_GLYPH_METRICS glyph_metrics[2]; + DWRITE_FONT_METRICS metrics; + float advance; + HRESULT hr; + + hr = IDWriteFontFace_GetDesignGlyphMetrics(run->fontFace, run->glyphIndices, run->glyphCount, glyph_metrics, FALSE); + ok(hr == S_OK, "Failed to get glyph metrics, hr %#x.\n", hr); + + IDWriteFontFace_GetMetrics(run->fontFace, &metrics); + + advance = run->fontEmSize * glyph_metrics[0].advanceWidth / metrics.designUnitsPerEm; + + baseline_origin.x -= advance; + + for (i = 0; i < run->glyphCount; ++i) + { + origins[i].x = baseline_origin.x - run->glyphOffsets[i].advanceOffset; + origins[i].y = baseline_origin.y - run->glyphOffsets[i].ascenderOffset; + + baseline_origin.x -= run->glyphAdvances[i]; + } + } + else + { + for (i = 0; i < run->glyphCount; ++i) + { + origins[i].x = baseline_origin.x + run->glyphOffsets[i].advanceOffset; + origins[i].y = baseline_origin.y - run->glyphOffsets[i].ascenderOffset; + + baseline_origin.x += run->glyphAdvances[i]; + } + } +} + static void test_ComputeGlyphOrigins(void) { + static const struct origins_test + { + D2D1_POINT_2F baseline_origin; + float advances[2]; + DWRITE_GLYPH_OFFSET offsets[2]; + unsigned int bidi_level; + } + origins_tests[] = + { + { { 123.0f, 321.0f }, { 10.0f, 20.0f }, { { 0 } } }, + { { 123.0f, 321.0f }, { 10.0f, 20.0f }, { { 0.3f, 0.5f }, { -0.1f, 0.9f } } }, + { { 123.0f, 321.0f }, { 10.0f, 20.0f }, { { 0 } }, 1 }, + }; IDWriteFactory4 *factory; DWRITE_GLYPH_RUN run; HRESULT hr; - D2D1_POINT_2F origins[2]; + D2D1_POINT_2F origins[2], expected_origins[2]; D2D1_POINT_2F baseline_origin; - UINT16 glyphs[2]; + UINT16 glyphs[2] = { 0 }; FLOAT advances[2]; DWRITE_MATRIX m; ULONG ref; + unsigned int i, j; + IDWriteFontFace *fontface;
factory = create_factory_iid(&IID_IDWriteFactory4); if (!factory) { @@ -8056,6 +8112,35 @@ static void test_ComputeGlyphOrigins(void) return; }
+ fontface = create_fontface((IDWriteFactory *)factory); + + for (i = 0; i < ARRAY_SIZE(origins_tests); ++i) + { + run.fontFace = fontface; + run.fontEmSize = 32.0f; + run.glyphCount = 2; + run.glyphIndices = glyphs; + run.glyphAdvances = origins_tests[i].advances; + run.glyphOffsets = origins_tests[i].offsets; + run.isSideways = FALSE; + run.bidiLevel = origins_tests[i].bidi_level; + + get_expected_glyph_origins(origins_tests[i].baseline_origin, &run, expected_origins); + + memset(origins, 0, sizeof(origins)); + hr = IDWriteFactory4_ComputeGlyphOrigins_(factory, &run, origins_tests[i].baseline_origin, origins); + ok(hr == S_OK, "%u: failed to compute glyph origins, hr %#x.\n", i, hr); + for (j = 0; j < run.glyphCount; ++j) + { + todo_wine_if(run.bidiLevel & 1) + ok(!memcmp(&origins[j], &expected_origins[j], sizeof(origins[j])), + "%u: unexpected origin[%u] (%f, %f) - (%f, %f).\n", i, j, origins[j].x, origins[j].y, + expected_origins[j].x, expected_origins[j].y); + } + } + + IDWriteFontFace_Release(fontface); + advances[0] = 10.0f; advances[1] = 20.0f;
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/dwrite/dwrite_private.h | 11 ++- dlls/dwrite/font.c | 36 +++----- dlls/dwrite/opentype.c | 159 +++++++++++++++++++++++------------ 3 files changed, 127 insertions(+), 79 deletions(-)
diff --git a/dlls/dwrite/dwrite_private.h b/dlls/dwrite/dwrite_private.h index 6ee59cfd02..52e7a18708 100644 --- a/dlls/dwrite/dwrite_private.h +++ b/dlls/dwrite/dwrite_private.h @@ -208,9 +208,18 @@ struct file_stream_desc { UINT32 face_index; };
+struct dwrite_fonttable +{ + const BYTE *data; + void *context; + UINT32 size; + BOOL exists; +}; + extern HRESULT opentype_analyze_font(IDWriteFontFileStream*,BOOL*,DWRITE_FONT_FILE_TYPE*,DWRITE_FONT_FACE_TYPE*,UINT32*) DECLSPEC_HIDDEN; extern HRESULT opentype_get_font_table(struct file_stream_desc*,UINT32,const void**,void**,UINT32*,BOOL*) DECLSPEC_HIDDEN; -extern HRESULT opentype_cmap_get_unicode_ranges(void*,UINT32,DWRITE_UNICODE_RANGE*,UINT32*) DECLSPEC_HIDDEN; +extern HRESULT opentype_cmap_get_unicode_ranges(const struct dwrite_fonttable *table, unsigned int max_count, + DWRITE_UNICODE_RANGE *ranges, unsigned int *count) DECLSPEC_HIDDEN; extern void opentype_get_font_properties(struct file_stream_desc*,struct dwrite_font_props*) DECLSPEC_HIDDEN; extern void opentype_get_font_metrics(struct file_stream_desc*,DWRITE_FONT_METRICS1*,DWRITE_CARET_METRICS*) DECLSPEC_HIDDEN; extern HRESULT opentype_get_font_info_strings(const void*,DWRITE_INFORMATIONAL_STRING_ID,IDWriteLocalizedStrings**) DECLSPEC_HIDDEN; diff --git a/dlls/dwrite/font.c b/dlls/dwrite/font.c index 735c7c7180..5c287ea653 100644 --- a/dlls/dwrite/font.c +++ b/dlls/dwrite/font.c @@ -149,13 +149,6 @@ struct dwrite_font { struct dwrite_fontfamily *family; };
-struct dwrite_fonttable { - void *data; - void *context; - UINT32 size; - BOOL exists; -}; - enum runanalysis_flags { RUNANALYSIS_BOUNDS_READY = 1 << 0, RUNANALYSIS_BITMAP_READY = 1 << 1, @@ -345,7 +338,7 @@ static HRESULT set_cached_glyph_metrics(struct dwrite_fontface *fontface, UINT16 return S_OK; }
-static void* get_fontface_table(IDWriteFontFace4 *fontface, UINT32 tag, struct dwrite_fonttable *table) +static const void* get_fontface_table(IDWriteFontFace4 *fontface, UINT32 tag, struct dwrite_fonttable *table) { HRESULT hr;
@@ -381,29 +374,24 @@ static FLOAT get_font_prop_vec_dotproduct(const struct dwrite_font_propvec *left return left->stretch * right->stretch + left->style * right->style + left->weight * right->weight; }
-static inline void* get_fontface_cmap(struct dwrite_fontface *fontface) -{ - return get_fontface_table(&fontface->IDWriteFontFace4_iface, MS_CMAP_TAG, &fontface->cmap); -} - -static inline void* get_fontface_vdmx(struct dwrite_fontface *fontface) +static const void* get_fontface_vdmx(struct dwrite_fontface *fontface) { return get_fontface_table(&fontface->IDWriteFontFace4_iface, MS_VDMX_TAG, &fontface->vdmx); }
-static inline void* get_fontface_gasp(struct dwrite_fontface *fontface, UINT32 *size) +static const void* get_fontface_gasp(struct dwrite_fontface *fontface, UINT32 *size) { - void *ptr = get_fontface_table(&fontface->IDWriteFontFace4_iface, MS_GASP_TAG, &fontface->gasp); + const void *ptr = get_fontface_table(&fontface->IDWriteFontFace4_iface, MS_GASP_TAG, &fontface->gasp); *size = fontface->gasp.size; return ptr; }
-static inline void* get_fontface_cpal(struct dwrite_fontface *fontface) +static const void* get_fontface_cpal(struct dwrite_fontface *fontface) { return get_fontface_table(&fontface->IDWriteFontFace4_iface, MS_CPAL_TAG, &fontface->cpal); }
-static inline void* get_fontface_colr(struct dwrite_fontface *fontface) +static const void* get_fontface_colr(struct dwrite_fontface *fontface) { return get_fontface_table(&fontface->IDWriteFontFace4_iface, MS_COLR_TAG, &fontface->colr); } @@ -730,9 +718,10 @@ static HRESULT WINAPI dwritefontface_GetRecommendedRenderingMode(IDWriteFontFace FLOAT ppdip, DWRITE_MEASURING_MODE measuring, IDWriteRenderingParams *params, DWRITE_RENDERING_MODE *mode) { struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface); - WORD gasp, *ptr; + const WORD *ptr; UINT32 size; FLOAT ppem; + WORD gasp;
TRACE("(%p)->(%.2f %.2f %d %p %p)\n", This, emSize, ppdip, measuring, params, mode);
@@ -910,7 +899,8 @@ static HRESULT WINAPI dwritefontface1_GetUnicodeRanges(IDWriteFontFace4 *iface, if (max_count && !ranges) return E_INVALIDARG;
- return opentype_cmap_get_unicode_ranges(get_fontface_cmap(This), max_count, ranges, count); + get_fontface_table(iface, MS_CMAP_TAG, &This->cmap); + return opentype_cmap_get_unicode_ranges(&This->cmap, max_count, ranges, count); }
static BOOL WINAPI dwritefontface1_IsMonospacedFont(IDWriteFontFace4 *iface) @@ -1108,8 +1098,9 @@ static HRESULT WINAPI dwritefontface2_GetRecommendedRenderingMode(IDWriteFontFac { struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface); FLOAT emthreshold; - WORD gasp, *ptr; + const WORD *ptr; UINT32 size; + WORD gasp;
TRACE("(%p)->(%.2f %.2f %.2f %p %d %d %d %p %p %p)\n", This, emSize, dpiX, dpiY, m, is_sideways, threshold, measuringmode, params, renderingmode, gridfitmode); @@ -1239,8 +1230,9 @@ static HRESULT WINAPI dwritefontface3_GetRecommendedRenderingMode(IDWriteFontFac { struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface); FLOAT emthreshold; - WORD gasp, *ptr; + const WORD *ptr; UINT32 size; + WORD gasp;
TRACE("(%p)->(%.2f %.2f %.2f %p %d %d %d %p %p %p)\n", This, emSize, dpiX, dpiY, m, is_sideways, threshold, measuring_mode, params, rendering_mode, gridfit_mode); diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c index db7dabcd56..0e0de8730e 100644 --- a/dlls/dwrite/opentype.c +++ b/dlls/dwrite/opentype.c @@ -82,16 +82,18 @@ typedef struct { DWORD length; } TT_TableRecord;
-typedef struct { +struct cmap_encoding_record +{ WORD platformID; WORD encodingID; DWORD offset; -} CMAP_EncodingRecord; +};
-typedef struct { +struct cmap_header +{ WORD version; - WORD numTables; - CMAP_EncodingRecord tables[1]; + WORD num_tables; + struct cmap_encoding_record tables[1]; } CMAP_Header;
typedef struct { @@ -100,25 +102,27 @@ typedef struct { DWORD startGlyphID; } CMAP_SegmentedCoverage_group;
-typedef struct { +struct cmap_segmented_coverage +{ WORD format; WORD reserved; DWORD length; DWORD language; - DWORD nGroups; + DWORD num_groups; CMAP_SegmentedCoverage_group groups[1]; -} CMAP_SegmentedCoverage; +};
-typedef struct { +struct cmap_segment_mapping +{ WORD format; WORD length; WORD language; - WORD segCountX2; - WORD searchRange; - WORD entrySelector; - WORD rangeShift; - WORD endCode[1]; -} CMAP_SegmentMapping_0; + WORD seg_count_x2; + WORD search_range; + WORD entry_selector; + WORD range_shift; + WORD end_code[1]; +};
enum OPENTYPE_CMAP_TABLE_FORMAT { @@ -874,6 +878,26 @@ struct COLR_LayerRecord USHORT paletteIndex; };
+static const void *table_read_ensure(const struct dwrite_fonttable *table, unsigned int offset, unsigned int size) +{ + if (size > table->size || offset > table->size - size) + return NULL; + + return table->data + offset; +} + +static WORD table_read_be_word(const struct dwrite_fonttable *table, unsigned int offset) +{ + const WORD *ptr = table_read_ensure(table, offset, sizeof(*ptr)); + return ptr ? GET_BE_WORD(*ptr) : 0; +} + +static DWORD table_read_be_dword(const struct dwrite_fonttable *table, unsigned int offset) +{ + const DWORD *ptr = table_read_ensure(table, offset, sizeof(*ptr)); + return ptr ? GET_BE_DWORD(*ptr) : 0; +} + BOOL is_face_type_supported(DWRITE_FONT_FACE_TYPE type) { return (type == DWRITE_FONT_FACE_TYPE_CFF) || @@ -1137,92 +1161,115 @@ HRESULT opentype_get_font_table(struct file_stream_desc *stream_desc, UINT32 tag * CMAP **********/
-static UINT32 opentype_cmap_get_unicode_ranges_count(const CMAP_Header *CMAP_Table) +static unsigned int opentype_cmap_get_unicode_ranges_count(const struct dwrite_fonttable *cmap) { - UINT32 count = 0; - int i; + unsigned int i, num_tables, count = 0; + const struct cmap_header *header;
- for (i = 0; i < GET_BE_WORD(CMAP_Table->numTables); i++) { - WORD type; - WORD *table; + num_tables = table_read_be_word(cmap, FIELD_OFFSET(struct cmap_header, num_tables)); + header = table_read_ensure(cmap, 0, FIELD_OFFSET(struct cmap_header, tables[num_tables]));
- if (GET_BE_WORD(CMAP_Table->tables[i].platformID) != 3) + if (!header) + return 0; + + for (i = 0; i < num_tables; ++i) + { + unsigned int format, offset; + + if (GET_BE_WORD(header->tables[i].platformID) != 3) continue;
- table = (WORD*)(((BYTE*)CMAP_Table) + GET_BE_DWORD(CMAP_Table->tables[i].offset)); - type = GET_BE_WORD(*table); - TRACE("table type %i\n", type); + offset = GET_BE_DWORD(header->tables[i].offset); + format = table_read_be_word(cmap, offset);
- switch (type) + switch (format) { case OPENTYPE_CMAP_TABLE_SEGMENT_MAPPING: { - CMAP_SegmentMapping_0 *format = (CMAP_SegmentMapping_0*)table; - count += GET_BE_WORD(format->segCountX2)/2; + count += table_read_be_word(cmap, offset + FIELD_OFFSET(struct cmap_segment_mapping, seg_count_x2)) / 2; break; } case OPENTYPE_CMAP_TABLE_SEGMENTED_COVERAGE: { - CMAP_SegmentedCoverage *format = (CMAP_SegmentedCoverage*)table; - count += GET_BE_DWORD(format->nGroups); + count += table_read_be_dword(cmap, offset + FIELD_OFFSET(struct cmap_segmented_coverage, num_groups)); break; } default: - FIXME("table type %i unhandled.\n", type); + FIXME("table format %u is not supported.\n", format); } }
return count; }
-HRESULT opentype_cmap_get_unicode_ranges(void *data, UINT32 max_count, DWRITE_UNICODE_RANGE *ranges, UINT32 *count) +HRESULT opentype_cmap_get_unicode_ranges(const struct dwrite_fonttable *cmap, unsigned int max_count, + DWRITE_UNICODE_RANGE *ranges, unsigned int *count) { - CMAP_Header *CMAP_Table = data; - int i, k = 0; + unsigned int i, num_tables, k = 0; + const struct cmap_header *header;
- if (!CMAP_Table) + if (!cmap->exists) return E_FAIL;
- *count = opentype_cmap_get_unicode_ranges_count(CMAP_Table); + *count = opentype_cmap_get_unicode_ranges_count(cmap); + + num_tables = table_read_be_word(cmap, FIELD_OFFSET(struct cmap_header, num_tables)); + header = table_read_ensure(cmap, 0, FIELD_OFFSET(struct cmap_header, tables[num_tables]));
- for (i = 0; i < GET_BE_WORD(CMAP_Table->numTables) && k < max_count; i++) + if (!header) + return S_OK; + + for (i = 0; i < num_tables && k < max_count; ++i) { - WORD type; - WORD *table; - int j; + unsigned int j, offset, format;
- if (GET_BE_WORD(CMAP_Table->tables[i].platformID) != 3) + if (GET_BE_WORD(header->tables[i].platformID) != 3) continue;
- table = (WORD*)(((BYTE*)CMAP_Table) + GET_BE_DWORD(CMAP_Table->tables[i].offset)); - type = GET_BE_WORD(*table); - TRACE("table type %i\n", type); + offset = GET_BE_DWORD(header->tables[i].offset);
- switch (type) + format = table_read_be_word(cmap, offset); + switch (format) { case OPENTYPE_CMAP_TABLE_SEGMENT_MAPPING: { - CMAP_SegmentMapping_0 *format = (CMAP_SegmentMapping_0*)table; - UINT16 segment_count = GET_BE_WORD(format->segCountX2)/2; - UINT16 *startCode = (WORD*)((BYTE*)format + sizeof(CMAP_SegmentMapping_0) + (sizeof(WORD) * segment_count)); + unsigned int segment_count = table_read_be_word(cmap, offset + + FIELD_OFFSET(struct cmap_segment_mapping, seg_count_x2)) / 2; + const UINT16 *start_code = table_read_ensure(cmap, offset, + FIELD_OFFSET(struct cmap_segment_mapping, end_code[segment_count]) + + 2 /* reservedPad */ + + 2 * segment_count /* start code array */); + const UINT16 *end_code = table_read_ensure(cmap, offset, + FIELD_OFFSET(struct cmap_segment_mapping, end_code[segment_count])); + + if (!start_code || !end_code) + continue;
- for (j = 0; j < segment_count && GET_BE_WORD(format->endCode[j]) < 0xffff && k < max_count; j++, k++) { - ranges[k].first = GET_BE_WORD(startCode[j]); - ranges[k].last = GET_BE_WORD(format->endCode[j]); + for (j = 0; j < segment_count && GET_BE_WORD(end_code[j]) != 0xffff && k < max_count; ++j, ++k) + { + ranges[k].first = GET_BE_WORD(start_code[j]); + ranges[k].last = GET_BE_WORD(end_code[j]); } break; } case OPENTYPE_CMAP_TABLE_SEGMENTED_COVERAGE: { - CMAP_SegmentedCoverage *format = (CMAP_SegmentedCoverage*)table; - for (j = 0; j < GET_BE_DWORD(format->nGroups) && k < max_count; j++, k++) { - ranges[k].first = GET_BE_DWORD(format->groups[j].startCharCode); - ranges[k].last = GET_BE_DWORD(format->groups[j].endCharCode); + unsigned int num_groups = table_read_be_dword(cmap, offset + + FIELD_OFFSET(struct cmap_segmented_coverage, num_groups)); + const struct cmap_segmented_coverage *coverage; + + coverage = table_read_ensure(cmap, offset, + FIELD_OFFSET(struct cmap_segmented_coverage, groups[num_groups])); + + for (j = 0; j < num_groups && k < max_count; j++, k++) + { + ranges[k].first = GET_BE_DWORD(coverage->groups[j].startCharCode); + ranges[k].last = GET_BE_DWORD(coverage->groups[j].endCharCode); } break; } default: - FIXME("table type %i unhandled.\n", type); + FIXME("table format %u unhandled.\n", format); } }
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/dwrite/dwrite_private.h | 2 +- dlls/dwrite/font.c | 42 ++++++++++++++--------------------- dlls/dwrite/opentype.c | 43 +++++++++++++++++++++++++++--------- 3 files changed, 50 insertions(+), 37 deletions(-)
diff --git a/dlls/dwrite/dwrite_private.h b/dlls/dwrite/dwrite_private.h index 52e7a18708..9f8c941428 100644 --- a/dlls/dwrite/dwrite_private.h +++ b/dlls/dwrite/dwrite_private.h @@ -254,7 +254,7 @@ enum gasp_flags { GASP_SYMMETRIC_SMOOTHING = 0x0008, };
-extern WORD opentype_get_gasp_flags(const WORD*,UINT32,INT) DECLSPEC_HIDDEN; +extern unsigned int opentype_get_gasp_flags(const struct dwrite_fonttable *gasp, float emsize) DECLSPEC_HIDDEN;
/* BiDi helpers */ extern HRESULT bidi_computelevels(const WCHAR*,UINT32,UINT8,UINT8*,UINT8*) DECLSPEC_HIDDEN; diff --git a/dlls/dwrite/font.c b/dlls/dwrite/font.c index 5c287ea653..5c0b2a4310 100644 --- a/dlls/dwrite/font.c +++ b/dlls/dwrite/font.c @@ -379,11 +379,10 @@ static const void* get_fontface_vdmx(struct dwrite_fontface *fontface) return get_fontface_table(&fontface->IDWriteFontFace4_iface, MS_VDMX_TAG, &fontface->vdmx); }
-static const void* get_fontface_gasp(struct dwrite_fontface *fontface, UINT32 *size) +static const struct dwrite_fonttable *get_fontface_gasp(struct dwrite_fontface *fontface) { - const void *ptr = get_fontface_table(&fontface->IDWriteFontFace4_iface, MS_GASP_TAG, &fontface->gasp); - *size = fontface->gasp.size; - return ptr; + get_fontface_table(&fontface->IDWriteFontFace4_iface, MS_GASP_TAG, &fontface->gasp); + return &fontface->gasp; }
static const void* get_fontface_cpal(struct dwrite_fontface *fontface) @@ -687,7 +686,7 @@ static HRESULT WINAPI dwritefontface_GetGlyphRunOutline(IDWriteFontFace4 *iface, }
static DWRITE_RENDERING_MODE fontface_renderingmode_from_measuringmode(DWRITE_MEASURING_MODE measuring, - FLOAT ppem, WORD gasp) + float ppem, unsigned int gasp) { DWRITE_RENDERING_MODE mode = DWRITE_RENDERING_MODE_DEFAULT;
@@ -718,10 +717,8 @@ static HRESULT WINAPI dwritefontface_GetRecommendedRenderingMode(IDWriteFontFace FLOAT ppdip, DWRITE_MEASURING_MODE measuring, IDWriteRenderingParams *params, DWRITE_RENDERING_MODE *mode) { struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface); - const WORD *ptr; - UINT32 size; + unsigned int flags; FLOAT ppem; - WORD gasp;
TRACE("(%p)->(%.2f %.2f %d %p %p)\n", This, emSize, ppdip, measuring, params, mode);
@@ -741,9 +738,8 @@ static HRESULT WINAPI dwritefontface_GetRecommendedRenderingMode(IDWriteFontFace return S_OK; }
- ptr = get_fontface_gasp(This, &size); - gasp = opentype_get_gasp_flags(ptr, size, ppem); - *mode = fontface_renderingmode_from_measuringmode(measuring, ppem, gasp); + flags = opentype_get_gasp_flags(get_fontface_gasp(This), ppem); + *mode = fontface_renderingmode_from_measuringmode(measuring, ppem, flags); return S_OK; }
@@ -1097,10 +1093,8 @@ static HRESULT WINAPI dwritefontface2_GetRecommendedRenderingMode(IDWriteFontFac DWRITE_GRID_FIT_MODE *gridfitmode) { struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface); + unsigned int flags; FLOAT emthreshold; - const WORD *ptr; - UINT32 size; - WORD gasp;
TRACE("(%p)->(%.2f %.2f %.2f %p %d %d %d %p %p %p)\n", This, emSize, dpiX, dpiY, m, is_sideways, threshold, measuringmode, params, renderingmode, gridfitmode); @@ -1131,14 +1125,13 @@ static HRESULT WINAPI dwritefontface2_GetRecommendedRenderingMode(IDWriteFontFac
emthreshold = threshold == DWRITE_OUTLINE_THRESHOLD_ANTIALIASED ? RECOMMENDED_OUTLINE_AA_THRESHOLD : RECOMMENDED_OUTLINE_A_THRESHOLD;
- ptr = get_fontface_gasp(This, &size); - gasp = opentype_get_gasp_flags(ptr, size, emSize); + flags = opentype_get_gasp_flags(get_fontface_gasp(This), emSize);
if (*renderingmode == DWRITE_RENDERING_MODE_DEFAULT) { if (emSize >= emthreshold) *renderingmode = DWRITE_RENDERING_MODE_OUTLINE; else - *renderingmode = fontface_renderingmode_from_measuringmode(measuringmode, emSize, gasp); + *renderingmode = fontface_renderingmode_from_measuringmode(measuringmode, emSize, flags); }
if (*gridfitmode == DWRITE_GRID_FIT_MODE_DEFAULT) { @@ -1147,7 +1140,8 @@ static HRESULT WINAPI dwritefontface2_GetRecommendedRenderingMode(IDWriteFontFac else if (measuringmode == DWRITE_MEASURING_MODE_GDI_CLASSIC || measuringmode == DWRITE_MEASURING_MODE_GDI_NATURAL) *gridfitmode = DWRITE_GRID_FIT_MODE_ENABLED; else - *gridfitmode = (gasp & (GASP_GRIDFIT|GASP_SYMMETRIC_GRIDFIT)) ? DWRITE_GRID_FIT_MODE_ENABLED : DWRITE_GRID_FIT_MODE_DISABLED; + *gridfitmode = flags & (GASP_GRIDFIT|GASP_SYMMETRIC_GRIDFIT) ? + DWRITE_GRID_FIT_MODE_ENABLED : DWRITE_GRID_FIT_MODE_DISABLED; }
return S_OK; @@ -1229,10 +1223,8 @@ static HRESULT WINAPI dwritefontface3_GetRecommendedRenderingMode(IDWriteFontFac IDWriteRenderingParams *params, DWRITE_RENDERING_MODE1 *rendering_mode, DWRITE_GRID_FIT_MODE *gridfit_mode) { struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface); + unsigned int flags; FLOAT emthreshold; - const WORD *ptr; - UINT32 size; - WORD gasp;
TRACE("(%p)->(%.2f %.2f %.2f %p %d %d %d %p %p %p)\n", This, emSize, dpiX, dpiY, m, is_sideways, threshold, measuring_mode, params, rendering_mode, gridfit_mode); @@ -1263,14 +1255,13 @@ static HRESULT WINAPI dwritefontface3_GetRecommendedRenderingMode(IDWriteFontFac
emthreshold = threshold == DWRITE_OUTLINE_THRESHOLD_ANTIALIASED ? RECOMMENDED_OUTLINE_AA_THRESHOLD : RECOMMENDED_OUTLINE_A_THRESHOLD;
- ptr = get_fontface_gasp(This, &size); - gasp = opentype_get_gasp_flags(ptr, size, emSize); + flags = opentype_get_gasp_flags(get_fontface_gasp(This), emSize);
if (*rendering_mode == DWRITE_RENDERING_MODE1_DEFAULT) { if (emSize >= emthreshold) *rendering_mode = DWRITE_RENDERING_MODE1_OUTLINE; else - *rendering_mode = fontface_renderingmode_from_measuringmode(measuring_mode, emSize, gasp); + *rendering_mode = fontface_renderingmode_from_measuringmode(measuring_mode, emSize, flags); }
if (*gridfit_mode == DWRITE_GRID_FIT_MODE_DEFAULT) { @@ -1279,7 +1270,8 @@ static HRESULT WINAPI dwritefontface3_GetRecommendedRenderingMode(IDWriteFontFac else if (measuring_mode == DWRITE_MEASURING_MODE_GDI_CLASSIC || measuring_mode == DWRITE_MEASURING_MODE_GDI_NATURAL) *gridfit_mode = DWRITE_GRID_FIT_MODE_ENABLED; else - *gridfit_mode = (gasp & (GASP_GRIDFIT|GASP_SYMMETRIC_GRIDFIT)) ? DWRITE_GRID_FIT_MODE_ENABLED : DWRITE_GRID_FIT_MODE_DISABLED; + *gridfit_mode = flags & (GASP_GRIDFIT|GASP_SYMMETRIC_GRIDFIT) ? + DWRITE_GRID_FIT_MODE_ENABLED : DWRITE_GRID_FIT_MODE_DISABLED; }
return S_OK; diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c index 0e0de8730e..291b41b131 100644 --- a/dlls/dwrite/opentype.c +++ b/dlls/dwrite/opentype.c @@ -292,6 +292,20 @@ typedef struct { BYTE bitDepth; BYTE flags; } CBLCBitmapSizeTable; + +struct gasp_range +{ + WORD max_ppem; + WORD flags; +}; + +struct gasp_header +{ + WORD version; + WORD num_ranges; + struct gasp_range ranges[1]; +}; + #include "poppack.h"
enum OS2_FSSELECTION { @@ -1959,25 +1973,32 @@ BOOL opentype_get_vdmx_size(const void *data, INT emsize, UINT16 *ascent, UINT16 return FALSE; }
-WORD opentype_get_gasp_flags(const WORD *ptr, UINT32 size, INT emsize) +unsigned int opentype_get_gasp_flags(const struct dwrite_fonttable *gasp, float emsize) { - WORD num_recs, version; + unsigned int version, num_ranges, i; + const struct gasp_header *table; WORD flags = 0;
- if (!ptr) + if (!gasp->exists) return 0;
- version = GET_BE_WORD( *ptr++ ); - num_recs = GET_BE_WORD( *ptr++ ); - if (version > 1 || size < (num_recs * 2 + 2) * sizeof(WORD)) { - ERR("unsupported gasp table: ver %d size %d recs %d\n", version, size, num_recs); + num_ranges = table_read_be_word(gasp, FIELD_OFFSET(struct gasp_header, num_ranges)); + + table = table_read_ensure(gasp, 0, FIELD_OFFSET(struct gasp_header, ranges[num_ranges])); + if (!table) + return 0; + + version = GET_BE_WORD(table->version); + if (version > 1) + { + ERR("Unsupported gasp table format version %u.\n", version); goto done; }
- while (num_recs--) { - flags = GET_BE_WORD( *(ptr + 1) ); - if (emsize <= GET_BE_WORD( *ptr )) break; - ptr += 2; + for (i = 0; i < num_ranges; ++i) + { + flags = GET_BE_WORD(table->ranges[i].flags); + if (emsize <= GET_BE_WORD(table->ranges[i].max_ppem)) break; }
done:
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/dwrite/dwrite_private.h | 7 ++-- dlls/dwrite/font.c | 5 +-- dlls/dwrite/opentype.c | 67 ++++++++++++++++++------------------ 3 files changed, 41 insertions(+), 38 deletions(-)
diff --git a/dlls/dwrite/dwrite_private.h b/dlls/dwrite/dwrite_private.h index 9f8c941428..6eac1f4f33 100644 --- a/dlls/dwrite/dwrite_private.h +++ b/dlls/dwrite/dwrite_private.h @@ -227,9 +227,10 @@ extern HRESULT opentype_get_font_familyname(struct file_stream_desc*,IDWriteLoca extern HRESULT opentype_get_font_facename(struct file_stream_desc*,WCHAR*,IDWriteLocalizedStrings**) DECLSPEC_HIDDEN; extern HRESULT opentype_get_typographic_features(IDWriteFontFace*,UINT32,UINT32,UINT32,UINT32*,DWRITE_FONT_FEATURE_TAG*) DECLSPEC_HIDDEN; extern BOOL opentype_get_vdmx_size(const void*,INT,UINT16*,UINT16*) DECLSPEC_HIDDEN; -extern UINT32 opentype_get_cpal_palettecount(const void*) DECLSPEC_HIDDEN; -extern UINT32 opentype_get_cpal_paletteentrycount(const void*) DECLSPEC_HIDDEN; -extern HRESULT opentype_get_cpal_entries(const void*,UINT32,UINT32,UINT32,DWRITE_COLOR_F*) DECLSPEC_HIDDEN; +extern unsigned int opentype_get_cpal_palettecount(const struct dwrite_fonttable *table) DECLSPEC_HIDDEN; +extern unsigned int opentype_get_cpal_paletteentrycount(const struct dwrite_fonttable *table) DECLSPEC_HIDDEN; +extern HRESULT opentype_get_cpal_entries(const struct dwrite_fonttable *table, unsigned int palette, + unsigned int first_entry_index, unsigned int entry_count, DWRITE_COLOR_F *entries) DECLSPEC_HIDDEN; extern BOOL opentype_has_vertical_variants(IDWriteFontFace4*) DECLSPEC_HIDDEN; extern UINT32 opentype_get_glyph_image_formats(IDWriteFontFace4*) DECLSPEC_HIDDEN; extern DWRITE_CONTAINER_TYPE opentype_analyze_container_type(void const *, UINT32) DECLSPEC_HIDDEN; diff --git a/dlls/dwrite/font.c b/dlls/dwrite/font.c index 5c0b2a4310..2c51674b0a 100644 --- a/dlls/dwrite/font.c +++ b/dlls/dwrite/font.c @@ -385,9 +385,10 @@ static const struct dwrite_fonttable *get_fontface_gasp(struct dwrite_fontface * return &fontface->gasp; }
-static const void* get_fontface_cpal(struct dwrite_fontface *fontface) +static const struct dwrite_fonttable *get_fontface_cpal(struct dwrite_fontface *fontface) { - return get_fontface_table(&fontface->IDWriteFontFace4_iface, MS_CPAL_TAG, &fontface->cpal); + get_fontface_table(&fontface->IDWriteFontFace4_iface, MS_CPAL_TAG, &fontface->cpal); + return &fontface->cpal; }
static const void* get_fontface_colr(struct dwrite_fontface *fontface) diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c index 291b41b131..647ac99597 100644 --- a/dlls/dwrite/opentype.c +++ b/dlls/dwrite/opentype.c @@ -843,25 +843,17 @@ static const UINT16 dwriteid_to_opentypeid[DWRITE_INFORMATIONAL_STRING_POSTSCRIP };
/* CPAL table */ -struct CPAL_Header_0 +struct cpal_header_0 { USHORT version; - USHORT numPaletteEntries; - USHORT numPalette; - USHORT numColorRecords; - ULONG offsetFirstColorRecord; - USHORT colorRecordIndices[1]; + USHORT num_palette_entries; + USHORT num_palettes; + USHORT num_color_records; + ULONG offset_first_color_record; + USHORT color_record_indices[1]; };
-/* for version == 1, this comes after full CPAL_Header_0 */ -struct CPAL_SubHeader_1 -{ - ULONG offsetPaletteTypeArray; - ULONG offsetPaletteLabelArray; - ULONG offsetPaletteEntryLabelArray; -}; - -struct CPAL_ColorRecord +struct cpal_color_record { BYTE blue; BYTE green; @@ -2005,37 +1997,46 @@ done: return flags; }
-UINT32 opentype_get_cpal_palettecount(const void *cpal) +unsigned int opentype_get_cpal_palettecount(const struct dwrite_fonttable *cpal) { - const struct CPAL_Header_0 *header = (const struct CPAL_Header_0*)cpal; - return header ? GET_BE_WORD(header->numPalette) : 0; + return table_read_be_word(cpal, FIELD_OFFSET(struct cpal_header_0, num_palettes)); }
-UINT32 opentype_get_cpal_paletteentrycount(const void *cpal) +unsigned int opentype_get_cpal_paletteentrycount(const struct dwrite_fonttable *cpal) { - const struct CPAL_Header_0 *header = (const struct CPAL_Header_0*)cpal; - return header ? GET_BE_WORD(header->numPaletteEntries) : 0; + return table_read_be_word(cpal, FIELD_OFFSET(struct cpal_header_0, num_palette_entries)); }
-HRESULT opentype_get_cpal_entries(const void *cpal, UINT32 palette, UINT32 first_entry_index, UINT32 entry_count, - DWRITE_COLOR_F *entries) +HRESULT opentype_get_cpal_entries(const struct dwrite_fonttable *cpal, unsigned int palette, + unsigned int first_entry_index, unsigned int entry_count, DWRITE_COLOR_F *entries) { - const struct CPAL_Header_0 *header = (const struct CPAL_Header_0*)cpal; - const struct CPAL_ColorRecord *records; - UINT32 palettecount, entrycount, i; + unsigned int num_palettes, num_palette_entries, i; + const struct cpal_color_record *records; + const struct cpal_header_0 *header; + + header = table_read_ensure(cpal, 0, sizeof(*header)); + + if (!cpal->exists || !header) + return DWRITE_E_NOCOLOR;
- if (!header) return DWRITE_E_NOCOLOR; + num_palettes = GET_BE_WORD(header->num_palettes); + if (palette >= num_palettes) + return DWRITE_E_NOCOLOR;
- palettecount = GET_BE_WORD(header->numPalette); - if (palette >= palettecount) + header = table_read_ensure(cpal, 0, FIELD_OFFSET(struct cpal_header_0, color_record_indices[palette])); + if (!header) return DWRITE_E_NOCOLOR;
- entrycount = GET_BE_WORD(header->numPaletteEntries); - if (first_entry_index + entry_count > entrycount) + num_palette_entries = GET_BE_WORD(header->num_palette_entries); + if (first_entry_index + entry_count > num_palette_entries) return E_INVALIDARG;
- records = (const struct CPAL_ColorRecord*)((BYTE*)cpal + GET_BE_DWORD(header->offsetFirstColorRecord)); - first_entry_index += GET_BE_WORD(header->colorRecordIndices[palette]); + records = table_read_ensure(cpal, GET_BE_DWORD(header->offset_first_color_record), + sizeof(*records) * GET_BE_WORD(header->num_color_records)); + if (!records) + return DWRITE_E_NOCOLOR; + + first_entry_index += GET_BE_WORD(header->color_record_indices[palette]);
for (i = 0; i < entry_count; i++) { entries[i].u1.r = records[first_entry_index + i].red / 255.0f;