[uniscribe/directwrite] Move feature setup to shared file Fixes https://github.com/harfbuzz/harfbuzz/issues/3070
diff --git a/src/hb-directwrite.cc b/src/hb-directwrite.cc index a1e57b0..40cb09b 100644 --- a/src/hb-directwrite.cc +++ b/src/hb-directwrite.cc
@@ -32,6 +32,7 @@ #include "hb-directwrite.h" +#include "hb-ms-feature-ranges.hh" /** * SECTION:hb-directwrite @@ -510,44 +511,6 @@ * shaper */ -struct active_feature_t { - DWRITE_FONT_FEATURE fea; - unsigned int order; - - HB_INTERNAL static int cmp (const void *pa, const void *pb) { - const active_feature_t *a = (const active_feature_t *) pa; - const active_feature_t *b = (const active_feature_t *) pb; - return a->fea.nameTag < b->fea.nameTag ? -1 : a->fea.nameTag > b->fea.nameTag ? 1 : - a->order < b->order ? -1 : a->order > b->order ? 1 : - a->fea.parameter < b->fea.parameter ? -1 : a->fea.parameter > b->fea.parameter ? 1 : - 0; - } - bool operator== (const active_feature_t *f) - { return cmp (this, f) == 0; } -}; - -struct feature_event_t { - unsigned int index; - bool start; - active_feature_t feature; - - HB_INTERNAL static int cmp (const void *pa, const void *pb) - { - const feature_event_t *a = (const feature_event_t *) pa; - const feature_event_t *b = (const feature_event_t *) pb; - return a->index < b->index ? -1 : a->index > b->index ? 1 : - a->start < b->start ? -1 : a->start > b->start ? 1 : - active_feature_t::cmp (&a->feature, &b->feature); - } -}; - -struct range_record_t { - DWRITE_TYPOGRAPHIC_FEATURES features; - unsigned int index_first; /* == start */ - unsigned int index_last; /* == end - 1 */ -}; - - hb_bool_t _hb_directwrite_shape (hb_shape_plan_t *shape_plan, hb_font_t *font, @@ -644,149 +607,24 @@ /* * Set up features. */ - hb_vector_t<DWRITE_FONT_FEATURE> feature_records; - hb_vector_t<range_record_t> range_records; - if (num_features) - { - /* Sort features by start/end events. */ - hb_vector_t<feature_event_t> feature_events; - for (unsigned int i = 0; i < num_features; i++) - { - active_feature_t feature; - feature.fea.nameTag = (DWRITE_FONT_FEATURE_TAG) hb_uint32_swap (features[i].tag); - feature.fea.parameter = features[i].value; - feature.order = i; - - feature_event_t *event; - - event = feature_events.push (); - event->index = features[i].start; - event->start = true; - event->feature = feature; - - event = feature_events.push (); - event->index = features[i].end; - event->start = false; - event->feature = feature; - } - feature_events.qsort (); - /* Add a strategic final event. */ - { - active_feature_t feature; - feature.fea.nameTag = (DWRITE_FONT_FEATURE_TAG) 0; - feature.fea.parameter = 0; - feature.order = num_features + 1; - - feature_event_t *event = feature_events.push (); - event->index = 0; /* This value does magic. */ - event->start = false; - event->feature = feature; - } - - /* Scan events and save features for each range. */ - hb_vector_t<active_feature_t> active_features; - unsigned int last_index = 0; - for (unsigned int i = 0; i < feature_events.length; i++) - { - feature_event_t *event = &feature_events[i]; - - if (event->index != last_index) - { - /* Save a snapshot of active features and the range. */ - range_record_t *range = range_records.push (); - - unsigned int offset = feature_records.length; - - active_features.qsort (); - for (unsigned int j = 0; j < active_features.length; j++) - { - if (!j || active_features[j].fea.nameTag != feature_records[feature_records.length - 1].nameTag) - { - feature_records.push (active_features[j].fea); - } - else - { - /* Overrides value for existing feature. */ - feature_records[feature_records.length - 1].parameter = active_features[j].fea.parameter; - } - } - - /* Will convert to pointer after all is ready, since feature_records.array - * may move as we grow it. */ - range->features.features = reinterpret_cast<DWRITE_FONT_FEATURE *> (offset); - range->features.featureCount = feature_records.length - offset; - range->index_first = last_index; - range->index_last = event->index - 1; - - last_index = event->index; - } - - if (event->start) - { - active_features.push (event->feature); - } - else - { - active_feature_t *feature = active_features.find (&event->feature); - if (feature) - active_features.remove (feature - active_features.arrayZ); - } - } - - if (!range_records.length) /* No active feature found. */ - num_features = 0; - - /* Fixup the pointers. */ - for (unsigned int i = 0; i < range_records.length; i++) - { - range_record_t *range = &range_records[i]; - range->features.features = (DWRITE_FONT_FEATURE *) feature_records + reinterpret_cast<uintptr_t> (range->features.features); - } - } - - hb_vector_t<DWRITE_TYPOGRAPHIC_FEATURES *> range_features; + static_assert ((sizeof (DWRITE_TYPOGRAPHIC_FEATURES) == sizeof (hb_ms_features_t)), ""); + static_assert ((sizeof (DWRITE_FONT_FEATURE) == sizeof (hb_ms_feature_t)), ""); + hb_vector_t<hb_ms_features_t *> range_features; hb_vector_t<uint32_t> range_char_counts; if (num_features) { - range_features.shrink (0); - range_char_counts.shrink (0); - - range_record_t *last_range = &range_records[0]; - for (unsigned int i = 0; i < textLength; i++) - { - range_record_t *range = last_range; - while (log_clusters[i] < range->index_first) - range--; - while (log_clusters[i] > range->index_last) - range++; - if (!range_features.length || - &range->features != range_features[range_features.length - 1]) - { - auto **typoFeatures = range_features.push (); - auto *c = range_char_counts.push (); - if (unlikely (!typoFeatures || !c)) - { - range_features.shrink (0); - range_char_counts.shrink (0); - break; - } - *typoFeatures = &range->features; - *c = 1; - } - else - { - range_char_counts[range_char_counts.length - 1]++; - } - - last_range = range; - } + hb_vector_t<hb_ms_feature_t> feature_records; + hb_vector_t<range_record_t> range_records; + if (hb_ms_setup_features (features, num_features, feature_records, range_records)) + hb_ms_make_feature_ranges (feature_records, + range_records, + 0, + chars_len, + log_clusters, + range_features, + range_char_counts); } - const auto **dwFeatures = (const DWRITE_TYPOGRAPHIC_FEATURES**) range_features.arrayZ; - auto featureRanges = range_features.length; - const auto *featureRangeLengths = range_char_counts.arrayZ; - // - uint16_t* clusterMap; clusterMap = new uint16_t[textLength]; DWRITE_SHAPING_TEXT_PROPERTIES* textProperties; @@ -797,11 +635,23 @@ DWRITE_SHAPING_GLYPH_PROPERTIES* glyphProperties; glyphProperties = new DWRITE_SHAPING_GLYPH_PROPERTIES[maxGlyphCount]; - hr = analyzer->GetGlyphs (textString, textLength, fontFace, false, - isRightToLeft, &runHead->mScript, localeName, - nullptr, dwFeatures, featureRangeLengths, featureRanges, - maxGlyphCount, clusterMap, textProperties, - glyphIndices, glyphProperties, &glyphCount); + hr = analyzer->GetGlyphs (textString, + chars_len, + fontFace, + false, + isRightToLeft, + &runHead->mScript, + localeName, + nullptr, + (const DWRITE_TYPOGRAPHIC_FEATURES**) range_features.arrayZ, + range_char_counts.arrayZ, + range_features.length, + maxGlyphCount, + clusterMap, + textProperties, + glyphIndices, + glyphProperties, + &glyphCount); if (unlikely (hr == HRESULT_FROM_WIN32 (ERROR_INSUFFICIENT_BUFFER))) { @@ -837,12 +687,24 @@ double x_mult = (double) font->x_scale / fontEmSize; double y_mult = (double) font->y_scale / fontEmSize; - hr = analyzer->GetGlyphPlacements (textString, clusterMap, textProperties, - textLength, glyphIndices, glyphProperties, - glyphCount, fontFace, fontEmSize, - false, isRightToLeft, &runHead->mScript, localeName, - dwFeatures, featureRangeLengths, featureRanges, - glyphAdvances, glyphOffsets); + hr = analyzer->GetGlyphPlacements (textString, + clusterMap, + textProperties, + chars_len, + glyphIndices, + glyphProperties, + glyphCount, + fontFace, + fontEmSize, + false, + isRightToLeft, + &runHead->mScript, + localeName, + (const DWRITE_TYPOGRAPHIC_FEATURES**) range_features.arrayZ, + range_char_counts.arrayZ, + range_features.length, + glyphAdvances, + glyphOffsets); if (FAILED (hr)) FAIL ("Analyzer failed to get glyph placements.");