[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.");