Merge branch 'master' into cff-subset
authorMichiharu Ariza <ariza@adobe.com>
Sat, 6 Oct 2018 21:49:44 +0000 (14:49 -0700)
committerMichiharu Ariza <ariza@adobe.com>
Sat, 6 Oct 2018 21:49:44 +0000 (14:49 -0700)
33 files changed:
TODO
configure.ac
src/hb-aat-layout-common.hh
src/hb-aat-layout-morx-table.hh
src/hb-aat-layout.cc
src/hb-aat-layout.hh
src/hb-face.cc
src/hb-machinery.hh
src/hb-ot-cmap-table.hh
src/hb-ot-post-table.hh
src/hb-ot-shape.cc
src/hb-ot-shape.hh
src/hb-set.hh
src/hb-subset.cc
src/hb-vector.hh
test/shaping/data/text-rendering-tests/DISABLED
test/shaping/data/text-rendering-tests/Makefile.sources
test/shaping/data/text-rendering-tests/extract-tests.py
test/shaping/data/text-rendering-tests/fonts/TestGSUBThree.ttf [new file with mode: 0644]
test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyfive.ttf [new file with mode: 0644]
test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyfour.ttf [new file with mode: 0644]
test/shaping/data/text-rendering-tests/fonts/TestMORXThirtysix.ttf [new file with mode: 0644]
test/shaping/data/text-rendering-tests/fonts/TestMORXThirtythree.ttf [new file with mode: 0644]
test/shaping/data/text-rendering-tests/fonts/TestMORXTwentyfour.ttf [new file with mode: 0644]
test/shaping/data/text-rendering-tests/tests/GSUB-3.tests [new file with mode: 0644]
test/shaping/data/text-rendering-tests/tests/MORX-24.tests [new file with mode: 0644]
test/shaping/data/text-rendering-tests/tests/MORX-32.tests
test/shaping/data/text-rendering-tests/tests/MORX-33.tests [new file with mode: 0644]
test/shaping/data/text-rendering-tests/tests/MORX-34.tests [new file with mode: 0644]
test/shaping/data/text-rendering-tests/tests/MORX-35.tests [new file with mode: 0644]
test/shaping/data/text-rendering-tests/tests/MORX-36.tests [new file with mode: 0644]
test/shaping/run-tests.py
util/view-cairo.hh

diff --git a/TODO b/TODO
index 6dac0be..d2c5812 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,9 +1,3 @@
-General fixes:
-=============
-
-- Implement 'rand' feature.
-
-
 API issues:
 ===========
 
@@ -19,12 +13,10 @@ API additions
 
 - Add hb-cairo glue
 
-- Add sanitize API (and a cached version, that saves result on blob user-data)
+- Add sanitize API.
 
 - BCP 47 language handling / API (language_matches?)
 
-- Add hb_font_create_unscaled()?
-
 - Add query / enumeration API for aalt-like features?
 
 - Add segmentation API
index 4ebb21d..3aa41ff 100644 (file)
@@ -12,6 +12,7 @@ AC_CONFIG_HEADERS([config.h])
 AM_INIT_AUTOMAKE([1.13.0 gnits tar-ustar dist-bzip2 no-dist-gzip -Wall no-define color-tests -Wno-portability])
 AM_SILENT_RULES([yes])
 AX_CODE_COVERAGE
+AC_USE_SYSTEM_EXTENSIONS
 
 # Initialize libtool
 m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
@@ -19,7 +20,6 @@ LT_PREREQ([2.2])
 LT_INIT([disable-static])
 
 # Check for programs
-AC_USE_SYSTEM_EXTENSIONS
 AC_PROG_CC
 AC_PROG_CC_C99
 AM_PROG_CC_C_O
index b0faa1d..c6b519d 100644 (file)
@@ -546,8 +546,6 @@ struct StateTableDriver
   template <typename context_t>
   inline void drive (context_t *c)
   {
-    hb_glyph_info_t *info = buffer->info;
-
     if (!c->in_place)
       buffer->clear_output ();
 
@@ -556,7 +554,7 @@ struct StateTableDriver
     for (buffer->idx = 0;;)
     {
       unsigned int klass = buffer->idx < buffer->len ?
-                          machine.get_class (info[buffer->idx].codepoint, num_glyphs) :
+                          machine.get_class (buffer->info[buffer->idx].codepoint, num_glyphs) :
                           (unsigned) StateTable<EntryData>::CLASS_END_OF_TEXT;
       const Entry<EntryData> *entry = machine.get_entryZ (state, klass);
       if (unlikely (!entry))
index c58e674..e986903 100644 (file)
@@ -592,6 +592,7 @@ struct InsertionSubtable
                             hb_aat_apply_context_t *c_) :
        ret (false),
        c (c_),
+       mark_set (false),
        mark (0),
        insertionAction (table+table->insertionAction) {}
 
@@ -607,7 +608,7 @@ struct InsertionSubtable
       hb_buffer_t *buffer = driver->buffer;
       unsigned int flags = entry->flags;
 
-      if (entry->data.markedInsertIndex != 0xFFFF)
+      if (entry->data.markedInsertIndex != 0xFFFF && mark_set)
       {
        unsigned int count = (flags & MarkedInsertCount);
        unsigned int start = entry->data.markedInsertIndex;
@@ -668,7 +669,10 @@ struct InsertionSubtable
       }
 
       if (flags & SetMark)
+      {
+       mark_set = true;
        mark = buffer->out_len;
+      }
 
       return true;
     }
@@ -677,6 +681,7 @@ struct InsertionSubtable
     bool ret;
     private:
     hb_aat_apply_context_t *c;
+    bool mark_set;
     unsigned int mark;
     const UnsizedArrayOf<GlyphID> &insertionAction;
   };
@@ -942,6 +947,8 @@ struct morx
 {
   static const hb_tag_t tableTag = HB_AAT_TAG_morx;
 
+  inline bool has_data (void) const { return version != 0; }
+
   inline void apply (hb_aat_apply_context_t *c) const
   {
     if (unlikely (!c->buffer->successful)) return;
index a5e36a4..faf418d 100644 (file)
@@ -55,6 +55,12 @@ _get_morx (hb_face_t *face, hb_blob_t **blob = nullptr)
   return morx;
 }
 
+hb_bool_t
+hb_aat_layout_has_substitution (hb_face_t *face)
+{
+  return _get_morx (face).has_data ();
+}
+
 void
 hb_aat_layout_substitute (hb_font_t *font, hb_buffer_t *buffer)
 {
index ac9c535..553832f 100644 (file)
@@ -33,6 +33,8 @@
 #include "hb-buffer.hh"
 #include "hb-open-type.hh"
 
+HB_INTERNAL hb_bool_t
+hb_aat_layout_has_substitution (hb_face_t *face);
 
 HB_INTERNAL void
 hb_aat_layout_substitute (hb_font_t *font, hb_buffer_t *buffer);
index 3916a4e..bba1ee3 100644 (file)
@@ -634,7 +634,7 @@ _hb_face_builder_data_reference_blob (hb_face_builder_data_t *data)
   unsigned int face_length = table_count * 16 + 12;
 
   for (unsigned int i = 0; i < table_count; i++)
-    face_length += hb_ceil_to_4 (hb_blob_get_length (data->tables.arrayZ[i].blob));
+    face_length += hb_ceil_to_4 (hb_blob_get_length (data->tables[i].blob));
 
   char *buf = (char *) malloc (face_length);
   if (unlikely (!buf))
index f80cfdb..9c73df2 100644 (file)
@@ -591,7 +591,7 @@ struct Supplier
   }
   inline Supplier (const hb_vector_t<Type> *v)
   {
-    head = v->arrayZ;
+    head = v->arrayZ();
     len = v->len;
     stride = sizeof (Type);
   }
index 3f5fa01..52b4db6 100644 (file)
@@ -495,7 +495,7 @@ struct CmapSubtableLongSegmented
   {
     TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (*this))) return_trace (false);
-    Supplier<CmapSubtableLongGroup> supplier (group_data.arrayZ, group_data.len);
+    Supplier<CmapSubtableLongGroup> supplier (group_data.arrayZ(), group_data.len);
     if (unlikely (!groups.serialize (c, supplier, group_data.len))) return_trace (false);
     return true;
   }
index f81de37..bd049f9 100644 (file)
@@ -242,7 +242,7 @@ struct post
 
       if (index >= index_to_offset.len)
        return hb_bytes_t ();
-      unsigned int offset = index_to_offset.arrayZ[index];
+      unsigned int offset = index_to_offset[index];
 
       const uint8_t *data = pool + offset;
       unsigned int name_length = *data;
index 748af96..453d995 100644 (file)
@@ -63,9 +63,14 @@ hb_ot_shape_planner_t::compile (hb_ot_shape_plan_t &plan,
   plan.kerning_requested = !!plan.kern_mask;
   plan.has_gpos_mark = !!plan.map.get_1_mask (HB_TAG ('m','a','r','k'));
 
+  plan.apply_morx = !hb_ot_layout_has_substitution (face) &&
+                    hb_aat_layout_has_substitution (face);
+
   bool disable_gpos = plan.shaper->gpos_tag &&
                      plan.shaper->gpos_tag != plan.map.chosen_script[1];
-  plan.fallback_positioning = disable_gpos || !hb_ot_layout_has_positioning (face);
+  plan.apply_gpos = !disable_gpos && hb_ot_layout_has_positioning (face);
+
+  plan.fallback_positioning = !plan.apply_gpos;
   plan.fallback_glyph_classes = !hb_ot_layout_has_glyph_classes (face);
 }
 
@@ -127,9 +132,13 @@ hb_ot_shape_collect_features (hb_ot_shape_planner_t          *planner,
   /* Random! */
   map->enable_feature (HB_TAG ('r','a','n','d'), F_RANDOM, HB_OT_MAP_MAX_VALUE);
 
+  map->enable_feature (HB_TAG('H','A','R','F'));
+
   if (planner->shaper->collect_features)
     planner->shaper->collect_features (planner);
 
+  map->enable_feature (HB_TAG('B','U','Z','Z'));
+
   for (unsigned int i = 0; i < ARRAY_LENGTH (common_features); i++)
     map->add_feature (common_features[i]);
 
@@ -217,7 +226,13 @@ _hb_ot_shaper_shape_plan_data_create (hb_shape_plan_t    *shape_plan,
 
   hb_ot_shape_planner_t planner (shape_plan);
 
-  planner.shaper = hb_ot_shape_complex_categorize (&planner);
+  /* Ugly that we have to do this here...
+   * If we are going to apply morx, choose default shaper. */
+  if (!hb_ot_layout_has_substitution (planner.face) &&
+       hb_aat_layout_has_substitution (planner.face))
+    planner.shaper = &_hb_ot_complex_shaper_default;
+  else
+    planner.shaper = hb_ot_shape_complex_categorize (&planner);
 
   hb_ot_shape_collect_features (&planner, &shape_plan->props,
                                user_features, num_user_features);
@@ -661,10 +676,10 @@ hb_ot_substitute_complex (hb_ot_shape_context_t *c)
   if (c->plan->fallback_glyph_classes)
     hb_synthesize_glyph_classes (c);
 
-  c->plan->substitute (c->font, buffer);
-
-  if (0) /* XXX Call morx instead. */
+  if (unlikely (c->plan->apply_morx))
     hb_aat_layout_substitute (c->font, c->buffer);
+  else
+    c->plan->substitute (c->font, buffer);
 }
 
 static inline void
@@ -784,7 +799,7 @@ hb_ot_position_complex (hb_ot_shape_context_t *c)
       break;
   }
 
-  if (likely (!c->plan->fallback_positioning))
+  if (c->plan->apply_gpos)
     c->plan->position (c->font, c->buffer);
 
   switch (c->plan->shaper->zero_width_marks)
index 88c72dc..23c385a 100644 (file)
@@ -49,6 +49,11 @@ struct hb_ot_shape_plan_t
   bool fallback_positioning : 1;
   bool fallback_glyph_classes : 1;
 
+  bool apply_morx : 1;
+
+  bool apply_gpos : 1;
+
+
   inline void collect_lookups (hb_tag_t table_tag, hb_set_t *lookups) const
   {
     unsigned int table_index;
index 353403e..7ca3297 100644 (file)
@@ -368,8 +368,8 @@ struct hb_set_t
     if (!resize (count))
       return;
     population = other->population;
-    memcpy (pages.arrayZ, other->pages.arrayZ, count * sizeof (pages.arrayZ[0]));
-    memcpy (page_map.arrayZ, other->page_map.arrayZ, count * sizeof (page_map.arrayZ[0]));
+    memcpy (pages.arrayZ(), other->pages.arrayZ(), count * sizeof (pages.arrayZ()[0]));
+    memcpy (page_map.arrayZ(), other->page_map.arrayZ(), count * sizeof (page_map.arrayZ()[0]));
   }
 
   inline bool is_equal (const hb_set_t *other) const
index 09f0da9..c988dd5 100644 (file)
@@ -80,7 +80,7 @@ _subset2 (hb_subset_plan_t *plan)
       return false;
     }
   retry:
-    hb_serialize_context_t serializer (buf.arrayZ, buf_size);
+    hb_serialize_context_t serializer (buf.arrayZ(), buf_size);
     hb_subset_context_t c (plan, &serializer);
     result = table->subset (&c);
     if (serializer.ran_out_of_room)
index da548cb..766e5fb 100644 (file)
@@ -35,35 +35,42 @@ template <typename Type, unsigned int StaticSize=8>
 struct hb_vector_t
 {
   unsigned int len;
+  private:
   unsigned int allocated; /* == 0 means allocation failed. */
-  Type *arrayZ;
+  Type *arrayZ_;
   Type static_array[StaticSize];
+  public:
 
   void init (void)
   {
     len = 0;
     allocated = ARRAY_LENGTH (static_array);
-    arrayZ = static_array;
+    arrayZ_ = nullptr;
   }
 
+  inline Type * arrayZ (void)
+  { return arrayZ_ ? arrayZ_ : static_array; }
+  inline const Type * arrayZ (void) const
+  { return arrayZ_ ? arrayZ_ : static_array; }
+
   inline Type& operator [] (unsigned int i)
   {
     if (unlikely (i >= len))
       return Crap (Type);
-    return arrayZ[i];
+    return arrayZ()[i];
   }
   inline const Type& operator [] (unsigned int i) const
   {
     if (unlikely (i >= len))
       return Null(Type);
-    return arrayZ[i];
+    return arrayZ()[i];
   }
 
   inline Type *push (void)
   {
     if (unlikely (!resize (len + 1)))
       return &Crap(Type);
-    return &arrayZ[len - 1];
+    return &arrayZ()[len - 1];
   }
   inline Type *push (const Type& v)
   {
@@ -91,17 +98,17 @@ struct hb_vector_t
 
     Type *new_array = nullptr;
 
-    if (arrayZ == static_array)
+    if (!arrayZ_)
     {
       new_array = (Type *) calloc (new_allocated, sizeof (Type));
       if (new_array)
-        memcpy (new_array, arrayZ, len * sizeof (Type));
+        memcpy (new_array, static_array, len * sizeof (Type));
     }
     else
     {
       bool overflows = (new_allocated < allocated) || hb_unsigned_mul_overflows (new_allocated, sizeof (Type));
       if (likely (!overflows))
-        new_array = (Type *) realloc (arrayZ, new_allocated * sizeof (Type));
+        new_array = (Type *) realloc (arrayZ_, new_allocated * sizeof (Type));
     }
 
     if (unlikely (!new_array))
@@ -110,7 +117,7 @@ struct hb_vector_t
       return false;
     }
 
-    arrayZ = new_array;
+    arrayZ_ = new_array;
     allocated = new_allocated;
 
     return true;
@@ -123,7 +130,7 @@ struct hb_vector_t
       return false;
 
     if (size > len)
-      memset (arrayZ + len, 0, (size - len) * sizeof (*arrayZ));
+      memset (arrayZ() + len, 0, (size - len) * sizeof (*arrayZ()));
 
     len = size;
     return true;
@@ -137,12 +144,13 @@ struct hb_vector_t
 
   inline void remove (unsigned int i)
   {
-     if (unlikely (i >= len))
-       return;
-     memmove (static_cast<void *> (&arrayZ[i]),
-             static_cast<void *> (&arrayZ[i + 1]),
-             (len - i - 1) * sizeof (Type));
-     len--;
+    if (unlikely (i >= len))
+      return;
+    Type *array = arrayZ();
+    memmove (static_cast<void *> (&array[i]),
+            static_cast<void *> (&array[i + 1]),
+            (len - i - 1) * sizeof (Type));
+    len--;
   }
 
   inline void shrink (int size_)
@@ -153,41 +161,55 @@ struct hb_vector_t
   }
 
   template <typename T>
-  inline Type *find (T v) {
+  inline Type *find (T v)
+  {
+    Type *array = arrayZ();
     for (unsigned int i = 0; i < len; i++)
-      if (arrayZ[i] == v)
-       return &arrayZ[i];
+      if (array[i] == v)
+       return &array[i];
     return nullptr;
   }
   template <typename T>
-  inline const Type *find (T v) const {
+  inline const Type *find (T v) const
+  {
+    const Type *array = arrayZ();
     for (unsigned int i = 0; i < len; i++)
-      if (arrayZ[i] == v)
-       return &arrayZ[i];
+      if (array[i] == v)
+       return &array[i];
     return nullptr;
   }
 
   inline void qsort (int (*cmp)(const void*, const void*))
   {
-    ::qsort (arrayZ, len, sizeof (Type), cmp);
+    ::qsort (arrayZ(), len, sizeof (Type), cmp);
   }
 
   inline void qsort (void)
   {
-    ::qsort (arrayZ, len, sizeof (Type), Type::cmp);
+    ::qsort (arrayZ(), len, sizeof (Type), Type::cmp);
   }
 
   inline void qsort (unsigned int start, unsigned int end)
   {
-    ::qsort (arrayZ + start, end - start, sizeof (Type), Type::cmp);
+    ::qsort (arrayZ() + start, end - start, sizeof (Type), Type::cmp);
   }
 
   template <typename T>
   inline Type *lsearch (const T &x)
   {
+    Type *array = arrayZ();
     for (unsigned int i = 0; i < len; i++)
-      if (0 == this->arrayZ[i].cmp (&x))
-       return &arrayZ[i];
+      if (0 == array[i].cmp (&x))
+       return &array[i];
+    return nullptr;
+  }
+  template <typename T>
+  inline const Type *lsearch (const T &x) const
+  {
+    const Type *array = arrayZ();
+    for (unsigned int i = 0; i < len; i++)
+      if (0 == array[i].cmp (&x))
+       return &array[i];
     return nullptr;
   }
 
@@ -195,22 +217,23 @@ struct hb_vector_t
   inline Type *bsearch (const T &x)
   {
     unsigned int i;
-    return bfind (x, &i) ? &arrayZ[i] : nullptr;
+    return bfind (x, &i) ? &arrayZ()[i] : nullptr;
   }
   template <typename T>
   inline const Type *bsearch (const T &x) const
   {
     unsigned int i;
-    return bfind (x, &i) ? &arrayZ[i] : nullptr;
+    return bfind (x, &i) ? &arrayZ()[i] : nullptr;
   }
   template <typename T>
   inline bool bfind (const T &x, unsigned int *i) const
   {
     int min = 0, max = (int) this->len - 1;
+    const Type *array = this->arrayZ();
     while (min <= max)
     {
       int mid = (min + max) / 2;
-      int c = this->arrayZ[mid].cmp (&x);
+      int c = array[mid].cmp (&x);
       if (c < 0)
         max = mid - 1;
       else if (c > 0)
@@ -221,17 +244,26 @@ struct hb_vector_t
        return true;
       }
     }
-    if (max < 0 || (max < (int) this->len && this->arrayZ[max].cmp (&x) > 0))
+    if (max < 0 || (max < (int) this->len && array[max].cmp (&x) > 0))
       max++;
     *i = max;
     return false;
   }
 
+  inline void fini_deep (void)
+  {
+    Type *array = arrayZ();
+    unsigned int count = len;
+    for (unsigned int i = 0; i < count; i++)
+      array[i].fini ();
+    fini ();
+  }
+
   inline void fini (void)
   {
-    if (arrayZ != static_array)
-      free (arrayZ);
-    arrayZ = nullptr;
+    if (arrayZ_)
+      free (arrayZ_);
+    arrayZ_ = nullptr;
     allocated = len = 0;
   }
 };
index 1ce62e0..4e8b1cf 100644 (file)
@@ -1,38 +1,9 @@
+# https://github.com/harfbuzz/harfbuzz/issues/1224
+tests/MORX-35.tests
+
 # Non-Unicode cmap
 tests/CMAP-3.tests
 
-# Not hooked up
-tests/MORX-1.tests
-tests/MORX-2.tests
-tests/MORX-3.tests
-tests/MORX-4.tests
-tests/MORX-5.tests
-tests/MORX-6.tests
-tests/MORX-7.tests
-tests/MORX-8.tests
-tests/MORX-9.tests
-tests/MORX-10.tests
-tests/MORX-11.tests
-tests/MORX-12.tests
-tests/MORX-13.tests
-tests/MORX-14.tests
-tests/MORX-16.tests
-tests/MORX-17.tests
-tests/MORX-18.tests
-tests/MORX-19.tests
-tests/MORX-20.tests
-tests/MORX-21.tests
-tests/MORX-22.tests
-tests/MORX-23.tests
-tests/MORX-25.tests
-tests/MORX-26.tests
-tests/MORX-27.tests
-tests/MORX-28.tests
-tests/MORX-29.tests
-tests/MORX-30.tests
-tests/MORX-31.tests
-tests/MORX-32.tests
-
 # Rounding differences
 tests/SHARAN-1.tests
 tests/SHBALI-1.tests
index 5c8cd03..29d064b 100644 (file)
@@ -15,6 +15,7 @@ TESTS = \
        tests/GPOS-5.tests \
        tests/GSUB-1.tests \
        tests/GSUB-2.tests \
+       tests/GSUB-3.tests \
        tests/GVAR-1.tests \
        tests/GVAR-2.tests \
        tests/GVAR-3.tests \
@@ -28,12 +29,6 @@ TESTS = \
        tests/HVAR-2.tests \
        tests/KERN-1.tests \
        tests/KERN-2.tests \
-       tests/SHBALI-3.tests \
-       tests/SHKNDA-1.tests \
-       $(NULL)
-
-DISBALED_TESTS = \
-       tests/CMAP-3.tests \
        tests/MORX-10.tests \
        tests/MORX-11.tests \
        tests/MORX-12.tests \
@@ -48,6 +43,7 @@ DISBALED_TESTS = \
        tests/MORX-21.tests \
        tests/MORX-22.tests \
        tests/MORX-23.tests \
+       tests/MORX-24.tests \
        tests/MORX-25.tests \
        tests/MORX-26.tests \
        tests/MORX-27.tests \
@@ -57,6 +53,9 @@ DISBALED_TESTS = \
        tests/MORX-30.tests \
        tests/MORX-31.tests \
        tests/MORX-32.tests \
+       tests/MORX-33.tests \
+       tests/MORX-34.tests \
+       tests/MORX-36.tests \
        tests/MORX-3.tests \
        tests/MORX-4.tests \
        tests/MORX-5.tests \
@@ -64,6 +63,13 @@ DISBALED_TESTS = \
        tests/MORX-7.tests \
        tests/MORX-8.tests \
        tests/MORX-9.tests \
+       tests/SHBALI-3.tests \
+       tests/SHKNDA-1.tests \
+       $(NULL)
+
+DISBALED_TESTS = \
+       tests/MORX-35.tests \
+       tests/CMAP-3.tests \
        tests/SHARAN-1.tests \
        tests/SHBALI-1.tests \
        tests/SHBALI-2.tests \
index 36963e5..27d5686 100755 (executable)
@@ -28,12 +28,13 @@ def glyphstr(glyphs):
 
 html = ET.fromstring(sys.stdin.read())
 found = False
+
 for elt in html.findall(".//*[@class='expected'][@ft:id]", namespaces):
        found = True
        name = elt.get(ns('ft:id'))
        text = elt.get(ns('ft:render'))
        font = elt.get(ns('ft:font'))
-       vars = elt.get(ns('ft:var'), '').replace(':', '=').replace(';', ',')
+       variations = elt.get(ns('ft:var'), '').replace(':', '=').replace(';', ',')
        glyphs = []
        for use in elt.findall(".//use"):
                x = int(use.get('x'))
@@ -43,8 +44,19 @@ for elt in html.findall(".//*[@class='expected'][@ft:id]", namespaces):
                glyphname = '.'.join(href[1:].split('/')[1].split('.')[1:])
                glyphs.append((glyphname, x, y))
        opts = '--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft'
-       if vars:
-               opts = opts + ' --variations=%s' % vars
+       if variations:
+               opts = opts + ' --variations=%s' % variations
        print ("../fonts/%s:%s:%s:%s" % (font, opts, unistr(text), glyphstr(glyphs)))
 
+for elt in html.findall(".//*[@class='should-not-crash'][@ft:id]", namespaces):
+       found = True
+       name = elt.get(ns('ft:id'))
+       text = elt.get(ns('ft:render'))
+       font = elt.get(ns('ft:font'))
+       variations = elt.get(ns('ft:var'), '').replace(':', '=').replace(';', ',')
+       opts = ''
+       if variations:
+               opts = '--variations=%s' % variations
+       print ("../fonts/%s:%s:%s:*" % (font, opts, unistr(text)))
+
 sys.exit(0 if found else 1)
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestGSUBThree.ttf b/test/shaping/data/text-rendering-tests/fonts/TestGSUBThree.ttf
new file mode 100644 (file)
index 0000000..8fce4ac
Binary files /dev/null and b/test/shaping/data/text-rendering-tests/fonts/TestGSUBThree.ttf differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyfive.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyfive.ttf
new file mode 100644 (file)
index 0000000..f157063
Binary files /dev/null and b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyfive.ttf differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyfour.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyfour.ttf
new file mode 100644 (file)
index 0000000..a70dadc
Binary files /dev/null and b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyfour.ttf differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtysix.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtysix.ttf
new file mode 100644 (file)
index 0000000..6676e52
Binary files /dev/null and b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtysix.ttf differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtythree.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtythree.ttf
new file mode 100644 (file)
index 0000000..5cab73e
Binary files /dev/null and b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtythree.ttf differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentyfour.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentyfour.ttf
new file mode 100644 (file)
index 0000000..271dddb
Binary files /dev/null and b/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentyfour.ttf differ
diff --git a/test/shaping/data/text-rendering-tests/tests/GSUB-3.tests b/test/shaping/data/text-rendering-tests/tests/GSUB-3.tests
new file mode 100644 (file)
index 0000000..c2f7e6e
--- /dev/null
@@ -0,0 +1 @@
+../fonts/TestGSUBThree.ttf::U+006C,U+006F,U+006C:*
diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-24.tests b/test/shaping/data/text-rendering-tests/tests/MORX-24.tests
new file mode 100644 (file)
index 0000000..79a3d7b
--- /dev/null
@@ -0,0 +1 @@
+../fonts/TestMORXTwentyfour.ttf::U+0041,U+0042,U+0043,U+0044,U+0045:*
index 6f3ae88..87c1152 100644 (file)
@@ -1,4 +1,4 @@
-../fonts/TestMORXThirtytwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041:[I|N@830,0|S@1660,0|A@2490,0]
-../fonts/TestMORXThirtytwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0058,U+0041,U+0059:[I|N@830,0|S@1660,0|X@2490,0|A@2854,0|Y@3684,0]
-../fonts/TestMORXThirtytwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0042:[B|I@830,0|N@1660,0|S@2490,0]
-../fonts/TestMORXThirtytwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0058,U+0042,U+0059:[X|I@364,0|N@1194,0|S@2024,0|B@2854,0|Y@3684,0]
+../fonts/TestMORXThirtytwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041:[A]
+../fonts/TestMORXThirtytwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0058,U+0041,U+0059:[X|A@364,0|Y@1194,0]
+../fonts/TestMORXThirtytwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0042:[B]
+../fonts/TestMORXThirtytwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0058,U+0042,U+0059:[X|B@364,0|Y@1194,0]
diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-33.tests b/test/shaping/data/text-rendering-tests/tests/MORX-33.tests
new file mode 100644 (file)
index 0000000..17d080a
--- /dev/null
@@ -0,0 +1,3 @@
+../fonts/TestMORXThirtythree.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0068,U+0061:[h|a@618,0|h@1179,0|a@1797,0]
+../fonts/TestMORXThirtythree.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0068,U+0061,U+0068,U+0061:[h|a@618,0|h@1179,0|a@1797,0|h@2358,0|a@2976,0|h@3537,0|a@4155,0]
+../fonts/TestMORXThirtythree.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0061,U+0068:[a|h@561,0]
diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-34.tests b/test/shaping/data/text-rendering-tests/tests/MORX-34.tests
new file mode 100644 (file)
index 0000000..8c309df
--- /dev/null
@@ -0,0 +1 @@
+../fonts/TestMORXThirtyfour.ttf::U+0068,U+0061:*
diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-35.tests b/test/shaping/data/text-rendering-tests/tests/MORX-35.tests
new file mode 100644 (file)
index 0000000..1061034
--- /dev/null
@@ -0,0 +1,2 @@
+../fonts/TestMORXThirtyfive.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041:[A|B@639,0|C@1265,0]
+../fonts/TestMORXThirtyfive.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0058,U+0041,U+0059:[X|A@586,0|B@1225,0|C@1851,0|E@2447,0|Y@3003,0]
diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-36.tests b/test/shaping/data/text-rendering-tests/tests/MORX-36.tests
new file mode 100644 (file)
index 0000000..6b2340e
--- /dev/null
@@ -0,0 +1 @@
+../fonts/TestMORXThirtysix.ttf::U+0041:*
index ffe622a..0b27872 100755 (executable)
@@ -19,8 +19,6 @@ if not args or sys.argv[1].find('hb-shape') == -1 or not os.path.exists (sys.arg
        sys.exit (1)
 hb_shape, args = args[0], args[1:]
 
-extra_options = "--verify"
-
 fails = 0
 
 reference = False
@@ -48,6 +46,11 @@ for filename in args:
                cwd = os.path.dirname(filename)
                fontfile = os.path.normpath (os.path.join (cwd, fontfile))
 
+               extra_options = ["--shaper=ot"]
+               glyphs_expected = glyphs_expected.strip()
+               if glyphs_expected != '*':
+                       extra_options.append("--verify")
+
                if line.startswith ("#"):
                        if not reference:
                                print ("# %s %s --unicodes %s" % (hb_shape, fontfile, unicodes))
@@ -55,19 +58,19 @@ for filename in args:
 
                if not reference:
                        print ("%s %s %s %s --unicodes %s" %
-                                        (hb_shape, fontfile, extra_options, options, unicodes))
+                                        (hb_shape, fontfile, ' '.join(extra_options), options, unicodes))
 
                glyphs1, returncode = cmd ([hb_shape, "--font-funcs=ft",
-                       fontfile, extra_options, "--unicodes",
+                       fontfile] + extra_options + ["--unicodes",
                        unicodes] + (options.split (' ') if options else []))
 
                if returncode:
-                       print ("hb-shape --font-funcs=ft failed.") # file=sys.stderr
+                       print ("ERROR: hb-shape --font-funcs=ft failed.") # file=sys.stderr
                        fails = fails + 1
                        #continue
 
                glyphs2, returncode = cmd ([hb_shape, "--font-funcs=ot",
-                       fontfile, extra_options, "--unicodes",
+                       fontfile] + extra_options + ["--unicodes",
                        unicodes] + (options.split (' ') if options else []))
 
                if returncode:
@@ -75,7 +78,7 @@ for filename in args:
                        fails = fails + 1
                        #continue
 
-               if glyphs1 != glyphs2:
+               if glyphs1 != glyphs2 and glyphs_expected != '*':
                        print ("FT funcs: " + glyphs1) # file=sys.stderr
                        print ("OT funcs: " + glyphs2) # file=sys.stderr
                        fails = fails + 1
@@ -84,7 +87,7 @@ for filename in args:
                        print (":".join ([fontfile, options, unicodes, glyphs1]))
                        continue
 
-               if glyphs1.strip() != glyphs_expected.strip() and glyphs_expected.strip() != '*':
+               if glyphs1.strip() != glyphs_expected and glyphs_expected != '*':
                        print ("Actual:   " + glyphs1) # file=sys.stderr
                        print ("Expected: " + glyphs_expected) # file=sys.stderr
                        fails = fails + 1
index 677f74b..5be3523 100644 (file)
@@ -46,7 +46,7 @@ struct view_cairo_t
   void init (hb_buffer_t *buffer, const font_options_t *font_opts)
   {
     lines = g_array_new (false, false, sizeof (helper_cairo_line_t));
-    scale_bits = -font_opts->subpixel_bits;
+    scale_bits = - (int) font_opts->subpixel_bits;
   }
   void new_line (void)
   {