Nikolay Sivov : dwrite/layout: Pass user features to shaping calls.
Alexandre Julliard
julliard at winehq.org
Wed Feb 17 16:23:33 CST 2021
Module: wine
Branch: master
Commit: aa1bd1e0a09d60e05f132e7c42ada904176f3a72
URL: https://source.winehq.org/git/wine.git/?a=commit;h=aa1bd1e0a09d60e05f132e7c42ada904176f3a72
Author: Nikolay Sivov <nsivov at codeweavers.com>
Date: Wed Feb 17 13:33:24 2021 +0300
dwrite/layout: Pass user features to shaping calls.
Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>
---
dlls/dwrite/layout.c | 178 ++++++++++++++++++++++++++++++++++++++++++---------
1 file changed, 147 insertions(+), 31 deletions(-)
diff --git a/dlls/dwrite/layout.c b/dlls/dwrite/layout.c
index 12a2ce1726c..b2e16447334 100644
--- a/dlls/dwrite/layout.c
+++ b/dlls/dwrite/layout.c
@@ -648,7 +648,33 @@ static HRESULT layout_update_breakpoints_range(struct dwrite_textlayout *layout,
return S_OK;
}
-static struct layout_range *get_layout_range_by_pos(struct dwrite_textlayout *layout, UINT32 pos);
+static struct layout_range *get_layout_range_by_pos(struct dwrite_textlayout *layout, UINT32 pos)
+{
+ struct layout_range *cur;
+
+ LIST_FOR_EACH_ENTRY(cur, &layout->ranges, struct layout_range, h.entry)
+ {
+ DWRITE_TEXT_RANGE *r = &cur->h.range;
+ if (r->startPosition <= pos && pos < r->startPosition + r->length)
+ return cur;
+ }
+
+ 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 DWRITE_LINE_BREAKPOINT get_effective_breakpoint(const struct dwrite_textlayout *layout, UINT32 pos)
{
@@ -940,14 +966,123 @@ struct shaping_context
struct regular_layout_run *run;
DWRITE_SHAPING_GLYPH_PROPERTIES *glyph_props;
DWRITE_SHAPING_TEXT_PROPERTIES *text_props;
+
+ struct
+ {
+ DWRITE_TYPOGRAPHIC_FEATURES **features;
+ unsigned int *range_lengths;
+ unsigned int range_count;
+ } user_features;
};
+static void layout_shape_clear_user_features_context(struct shaping_context *context)
+{
+ unsigned int i;
+
+ for (i = 0; i < context->user_features.range_count; ++i)
+ {
+ heap_free(context->user_features.features[i]->features);
+ heap_free(context->user_features.features[i]);
+ }
+ heap_free(context->user_features.features);
+ memset(&context->user_features, 0, sizeof(context->user_features));
+}
+
static void layout_shape_clear_context(struct shaping_context *context)
{
+ layout_shape_clear_user_features_context(context);
heap_free(context->glyph_props);
heap_free(context->text_props);
}
+static HRESULT layout_shape_add_empty_user_features_range(struct shaping_context *context, unsigned int length)
+{
+ DWRITE_TYPOGRAPHIC_FEATURES *features;
+ unsigned int r = context->user_features.range_count;
+
+ if (!(context->user_features.features[r] = heap_alloc_zero(sizeof(*features))))
+ return E_OUTOFMEMORY;
+
+ context->user_features.range_lengths[r] = length;
+ context->user_features.range_count++;
+
+ return S_OK;
+}
+
+static HRESULT layout_shape_get_user_features(struct dwrite_textlayout *layout, struct shaping_context *context)
+{
+ unsigned int i, f, start = 0, r, covered_length = 0, length, feature_count;
+ struct regular_layout_run *run = context->run;
+ DWRITE_TYPOGRAPHIC_FEATURES *features;
+ struct layout_range_iface *range;
+ IDWriteTypography *typography;
+ HRESULT hr = E_OUTOFMEMORY;
+
+ range = (struct layout_range_iface *)get_layout_range_header_by_pos(&layout->typographies, 0);
+ if (range->h.range.length >= run->descr.stringLength && !range->iface)
+ return S_OK;
+
+ if (!(context->user_features.features = heap_calloc(run->descr.stringLength, sizeof(*context->user_features.features))))
+ goto failed;
+ if (!(context->user_features.range_lengths = heap_calloc(run->descr.stringLength, sizeof(*context->user_features.range_lengths))))
+ goto failed;
+
+ for (i = run->descr.textPosition; i < run->descr.textPosition + run->descr.stringLength; ++i)
+ {
+ range = (struct layout_range_iface *)get_layout_range_header_by_pos(&layout->typographies, i);
+ if (!range || !range->iface) continue;
+
+ typography = (IDWriteTypography *)range->iface;
+ feature_count = IDWriteTypography_GetFontFeatureCount(typography);
+ if (!feature_count)
+ {
+ i = range->h.range.length - i + 1;
+ continue;
+ }
+
+ if (start != i)
+ {
+ if (FAILED(hr = layout_shape_add_empty_user_features_range(context, i - start))) goto failed;
+ covered_length += i - start;
+ start += range->h.range.length;
+ }
+
+ r = context->user_features.range_count;
+ if (!(features = context->user_features.features[r] = heap_alloc(sizeof(*features))))
+ goto failed;
+
+ context->user_features.range_lengths[r] = length = min(run->descr.textPosition + run->descr.stringLength,
+ range->h.range.startPosition + range->h.range.length) - i;
+ features->featureCount = feature_count;
+ if (!(features->features = heap_calloc(feature_count, sizeof(*features->features))))
+ goto failed;
+
+ for (f = 0; f < feature_count; ++f)
+ {
+ IDWriteTypography_GetFontFeature(typography, f, &features->features[f]);
+ }
+
+ i += length;
+ covered_length += length;
+ context->user_features.range_count++;
+ }
+
+ if (context->user_features.range_count && covered_length < run->descr.stringLength)
+ {
+ if (FAILED(hr = layout_shape_add_empty_user_features_range(context, run->descr.stringLength - covered_length)))
+ goto failed;
+ }
+
+ hr = S_OK;
+
+failed:
+
+ if (!context->user_features.range_count || FAILED(hr))
+ layout_shape_clear_user_features_context(context);
+
+ return hr;
+}
+
static HRESULT layout_shape_get_glyphs(struct dwrite_textlayout *layout, struct shaping_context *context)
{
struct regular_layout_run *run = context->run;
@@ -969,11 +1104,16 @@ static HRESULT layout_shape_get_glyphs(struct dwrite_textlayout *layout, struct
if (!context->text_props || !context->glyph_props)
return E_OUTOFMEMORY;
+ if (FAILED(hr = layout_shape_get_user_features(layout, context)))
+ return hr;
+
for (;;)
{
hr = IDWriteTextAnalyzer_GetGlyphs(context->analyzer, run->descr.string, run->descr.stringLength, run->run.fontFace,
- run->run.isSideways, run->run.bidiLevel & 1, &run->sa, run->descr.localeName, NULL /* FIXME */, NULL,
- NULL, 0, max_count, run->clustermap, context->text_props, run->glyphs, context->glyph_props, &run->glyphcount);
+ run->run.isSideways, run->run.bidiLevel & 1, &run->sa, run->descr.localeName, NULL /* FIXME */,
+ (const DWRITE_TYPOGRAPHIC_FEATURES **)context->user_features.features, context->user_features.range_lengths,
+ context->user_features.range_count, max_count, run->clustermap, context->text_props, run->glyphs,
+ context->glyph_props, &run->glyphcount);
if (hr == E_NOT_SUFFICIENT_BUFFER)
{
heap_free(run->glyphs);
@@ -1020,12 +1160,14 @@ static HRESULT layout_shape_get_positions(struct dwrite_textlayout *layout, stru
context->text_props, run->descr.stringLength, run->run.glyphIndices, context->glyph_props, run->glyphcount,
run->run.fontFace, run->run.fontEmSize, layout->ppdip, &layout->transform,
layout->measuringmode == DWRITE_MEASURING_MODE_GDI_NATURAL, run->run.isSideways, run->run.bidiLevel & 1,
- &run->sa, run->descr.localeName, NULL, NULL, 0, run->advances, run->offsets);
+ &run->sa, run->descr.localeName, (const DWRITE_TYPOGRAPHIC_FEATURES **)context->user_features.features,
+ context->user_features.range_lengths, context->user_features.range_count, run->advances, run->offsets);
else
hr = IDWriteTextAnalyzer_GetGlyphPlacements(context->analyzer, run->descr.string, run->descr.clusterMap,
context->text_props, run->descr.stringLength, run->run.glyphIndices, context->glyph_props, run->glyphcount,
run->run.fontFace, run->run.fontEmSize, run->run.isSideways, run->run.bidiLevel & 1, &run->sa,
- run->descr.localeName, NULL, NULL, 0, run->advances, run->offsets);
+ run->descr.localeName, (const DWRITE_TYPOGRAPHIC_FEATURES **)context->user_features.features,
+ context->user_features.range_lengths, context->user_features.range_count, run->advances, run->offsets);
if (FAILED(hr))
{
@@ -1204,19 +1346,6 @@ static inline FLOAT get_cluster_range_width(struct dwrite_textlayout *layout, UI
return width;
}
-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 IUnknown *layout_get_effect_from_pos(struct dwrite_textlayout *layout, UINT32 pos)
{
struct layout_range_header *h = get_layout_range_header_by_pos(&layout->effects, pos);
@@ -2483,19 +2612,6 @@ static struct layout_range_header *find_outer_range(struct list *ranges, const D
return NULL;
}
-static struct layout_range *get_layout_range_by_pos(struct dwrite_textlayout *layout, UINT32 pos)
-{
- struct layout_range *cur;
-
- LIST_FOR_EACH_ENTRY(cur, &layout->ranges, struct layout_range, h.entry) {
- DWRITE_TEXT_RANGE *r = &cur->h.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;
More information about the wine-cvs
mailing list