[HarfBuzz] harfbuzz: Branch 'master' - 11 commits

Behdad Esfahbod behdad at kemper.freedesktop.org
Wed Oct 31 06:56:00 UTC 2018


 src/hb-aat-layout-common.hh     |  105 +++++++++++++----
 src/hb-aat-layout-kerx-table.hh |   17 +-
 src/hb-aat-layout-morx-table.hh |  243 +++++++++++++++++++++++++---------------
 src/hb-aat-layout.cc            |   49 +++++++-
 src/hb-open-type.hh             |    7 +
 src/hb-ot-face.hh               |    1 
 src/hb-ot-maxp-table.hh         |    2 
 7 files changed, 296 insertions(+), 128 deletions(-)

New commits:
commit 28b68cffe4e5ebf82217ebf439f428431d672af3
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Tue Oct 30 23:33:30 2018 -0700

    [mort] Implement / adjust Contextual substitution

diff --git a/src/hb-aat-layout-morx-table.hh b/src/hb-aat-layout-morx-table.hh
index dba352f9..c3a74835 100644
--- a/src/hb-aat-layout-morx-table.hh
+++ b/src/hb-aat-layout-morx-table.hh
@@ -213,10 +213,13 @@ struct ContextualSubtable
       Reserved		= 0x3FFF,	/* These bits are reserved and should be set to 0. */
     };
 
-    inline driver_context_t (const ContextualSubtable *table) :
+    inline driver_context_t (const ContextualSubtable *table_,
+			     hb_aat_apply_context_t *c_) :
 	ret (false),
+	c (c_),
 	mark_set (false),
 	mark (0),
+	table (table_),
 	subs (table+table->substitutionTables) {}
 
     inline bool is_actionable (StateTableDriver<Types, EntryData> *driver,
@@ -239,30 +242,57 @@ struct ContextualSubtable
       if (buffer->idx == buffer->len && !mark_set)
         return true;
 
-      if (entry->data.markIndex != 0xFFFF)
+      const GlyphID *replacement;
+
+      replacement = nullptr;
+      if (Types::extended)
       {
-	const Lookup<GlyphID> &lookup = subs[entry->data.markIndex];
-	hb_glyph_info_t *info = buffer->info;
-	const GlyphID *replacement = lookup.get_value (info[mark].codepoint, driver->num_glyphs);
-	if (replacement)
+	if (entry->data.markIndex != 0xFFFF)
 	{
-	  buffer->unsafe_to_break (mark, MIN (buffer->idx + 1, buffer->len));
-	  info[mark].codepoint = *replacement;
-	  ret = true;
+	  const Lookup<GlyphID> &lookup = subs[entry->data.markIndex];
+	  replacement = lookup.get_value (buffer->info[mark].codepoint, driver->num_glyphs);
 	}
       }
-      if (entry->data.currentIndex != 0xFFFF)
+      else
+      {
+	unsigned int offset = 2 * (entry->data.markIndex + buffer->info[mark].codepoint);
+	replacement = &StructAtOffset<GlyphID> (table, offset);
+	if ((const void *) replacement < (const void *) subs ||
+	    !replacement->sanitize (&c->sanitizer) ||
+	    !*replacement)
+	  replacement = nullptr;
+      }
+      if (replacement)
+      {
+	buffer->unsafe_to_break (mark, MIN (buffer->idx + 1, buffer->len));
+	buffer->info[mark].codepoint = *replacement;
+	ret = true;
+      }
+
+      replacement = nullptr;
+      unsigned int idx = MIN (buffer->idx, buffer->len - 1);
+      if (Types::extended)
       {
-        unsigned int idx = MIN (buffer->idx, buffer->len - 1);
-	const Lookup<GlyphID> &lookup = subs[entry->data.currentIndex];
-	hb_glyph_info_t *info = buffer->info;
-	const GlyphID *replacement = lookup.get_value (info[idx].codepoint, driver->num_glyphs);
-	if (replacement)
+	if (entry->data.currentIndex != 0xFFFF)
 	{
-	  info[idx].codepoint = *replacement;
-	  ret = true;
+	  const Lookup<GlyphID> &lookup = subs[entry->data.currentIndex];
+	  replacement = lookup.get_value (buffer->info[idx].codepoint, driver->num_glyphs);
 	}
       }
+      else
+      {
+	unsigned int offset = 2 * (entry->data.currentIndex + buffer->info[idx].codepoint);
+	replacement = &StructAtOffset<GlyphID> (table, offset);
+	if ((const void *) replacement < (const void *) subs ||
+	    !replacement->sanitize (&c->sanitizer) ||
+	    !*replacement)
+	  replacement = nullptr;
+      }
+      if (replacement)
+      {
+	buffer->info[idx].codepoint = *replacement;
+	ret = true;
+      }
 
       if (entry->flags & SetMark)
       {
@@ -276,8 +306,10 @@ struct ContextualSubtable
     public:
     bool ret;
     private:
+    hb_aat_apply_context_t *c;
     bool mark_set;
     unsigned int mark;
+    const ContextualSubtable *table;
     const UnsizedOffsetListOf<Lookup<GlyphID>, HBUINT, false> &subs;
   };
 
@@ -285,7 +317,7 @@ struct ContextualSubtable
   {
     TRACE_APPLY (this);
 
-    driver_context_t dc (this);
+    driver_context_t dc (this, c);
 
     StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
     driver.drive (&dc);
@@ -300,6 +332,8 @@ struct ContextualSubtable
     unsigned int num_entries = 0;
     if (unlikely (!machine.sanitize (c, &num_entries))) return_trace (false);
 
+    if (!Types::extended) return_trace (true);
+
     unsigned int num_lookups = 0;
 
     const Entry<EntryData> *entries = machine.get_entries ();
diff --git a/src/hb-open-type.hh b/src/hb-open-type.hh
index e9f99b10..00bd134d 100644
--- a/src/hb-open-type.hh
+++ b/src/hb-open-type.hh
@@ -340,6 +340,9 @@ struct UnsizedArrayOf
   inline const Type& operator [] (unsigned int i) const { return arrayZ[i]; }
   inline Type& operator [] (unsigned int i) { return arrayZ[i]; }
 
+  template <typename T> inline operator  T * (void) { return arrayZ; }
+  template <typename T> inline operator const T * (void) const { return arrayZ; }
+
   inline bool sanitize (hb_sanitize_context_t *c, unsigned int count) const
   {
     TRACE_SANITIZE (this);
@@ -450,6 +453,10 @@ struct ArrayOf
     if (unlikely (i >= len)) return Crap(Type);
     return arrayZ[i];
   }
+
+  template <typename T> inline operator  T * (void) { return arrayZ; }
+  template <typename T> inline operator const T * (void) const { return arrayZ; }
+
   inline unsigned int get_size (void) const
   { return len.static_size + len * Type::static_size; }
 
commit 11dbf0f12926b80d0c308c70a218342280045c23
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Tue Oct 30 21:49:59 2018 -0700

    [mort] More fixes]

diff --git a/src/hb-aat-layout-common.hh b/src/hb-aat-layout-common.hh
index 65e7fd93..33d9e556 100644
--- a/src/hb-aat-layout-common.hh
+++ b/src/hb-aat-layout-common.hh
@@ -430,9 +430,8 @@ struct StateTable
     CLASS_END_OF_LINE = 3,
   };
 
-  inline unsigned int row_stride (void) const { return nClasses * sizeof (HBUSHORT); }
   inline unsigned int new_state (unsigned int newState) const
-  { return newState / (Types::extended ? 1 : row_stride ()); }
+  { return Types::extended ? newState : (newState - stateArrayTable) / nClasses; }
 
   inline unsigned int get_class (hb_codepoint_t glyph_id, unsigned int num_glyphs) const
   {
@@ -524,7 +523,7 @@ struct StateTable
 		entryTable;	/* Offset to the entry array. */
 
   public:
-  DEFINE_SIZE_STATIC (16);
+  DEFINE_SIZE_STATIC (4 * sizeof (HBUINT));
 };
 
 struct ClassTable
commit e1552af95b6c17571f7ee58ebac92f48d93c8f98
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Tue Oct 30 21:09:05 2018 -0700

    [maxp] Minor

diff --git a/src/hb-ot-maxp-table.hh b/src/hb-ot-maxp-table.hh
index 648f232d..198dd251 100644
--- a/src/hb-ot-maxp-table.hh
+++ b/src/hb-ot-maxp-table.hh
@@ -92,7 +92,7 @@ struct maxp
     if (version.major == 1)
     {
       const maxpV1Tail &v1 = StructAfter<maxpV1Tail> (*this);
-      return v1.sanitize (c);
+      return_trace (v1.sanitize (c));
     }
     return_trace (likely (version.major == 0 && version.minor == 0x5000u));
   }
commit 0cf282a32e5b0fe1fec454ff293ffe04b33f1112
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Tue Oct 30 20:51:44 2018 -0700

    [mort] Grind some more

diff --git a/src/hb-aat-layout-common.hh b/src/hb-aat-layout-common.hh
index c9d5cfe9..65e7fd93 100644
--- a/src/hb-aat-layout-common.hh
+++ b/src/hb-aat-layout-common.hh
@@ -430,6 +430,10 @@ struct StateTable
     CLASS_END_OF_LINE = 3,
   };
 
+  inline unsigned int row_stride (void) const { return nClasses * sizeof (HBUSHORT); }
+  inline unsigned int new_state (unsigned int newState) const
+  { return newState / (Types::extended ? 1 : row_stride ()); }
+
   inline unsigned int get_class (hb_codepoint_t glyph_id, unsigned int num_glyphs) const
   {
     if (unlikely (glyph_id == DELETED_GLYPH)) return CLASS_DELETED_GLYPH;
@@ -495,7 +499,10 @@ struct StateTable
       { /* Sweep new entries. */
 	const Entry<Extra> *stop = &entries[num_entries];
 	for (const Entry<Extra> *p = &entries[entry]; p < stop; p++)
-	  num_states = MAX<unsigned int> (num_states, p->newState + 1);
+	{
+	  unsigned int newState = new_state (p->newState);
+	  num_states = MAX<unsigned int> (num_states, newState + 1);
+	}
 	entry = num_entries;
       }
     }
@@ -620,17 +627,17 @@ struct StateTableDriver
       }
 
       if (unlikely (!c->transition (this, entry)))
-        break;
+	break;
 
       last_was_dont_advance = (entry->flags & context_t::DontAdvance) && buffer->max_ops-- > 0;
 
-      state = entry->newState;
+      state = machine.new_state (entry->newState);
 
       if (buffer->idx == buffer->len)
-        break;
+	break;
 
       if (!last_was_dont_advance)
-        buffer->next_glyph ();
+	buffer->next_glyph ();
     }
 
     if (!c->in_place)
commit 90667b31bc3e61e68e27966e4781aba456c6b93b
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Tue Oct 30 20:15:28 2018 -0700

    [mort] Hook up more

diff --git a/src/hb-aat-layout.cc b/src/hb-aat-layout.cc
index 2b4f5783..b6bdb0be 100644
--- a/src/hb-aat-layout.cc
+++ b/src/hb-aat-layout.cc
@@ -207,7 +207,19 @@ void
 hb_aat_layout_compile_map (const hb_aat_map_builder_t *mapper,
 			   hb_aat_map_t *map)
 {
-  _get_morx (mapper->face).compile_flags (mapper, map);
+  const AAT::morx& morx = _get_morx (mapper->face, nullptr);
+  if (morx.has_data ())
+  {
+    morx.compile_flags (mapper, map);
+    return;
+  }
+
+  const AAT::mort& mort = _get_mort (mapper->face, nullptr);
+  if (mort.has_data ())
+  {
+    mort.compile_flags (mapper, map);
+    return;
+  }
 }
 
 
commit 9346b1f158dfd7d25ed0057b40aaa6980a85ea17
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Tue Oct 30 20:04:13 2018 -0700

    [morx] Remove stale comment

diff --git a/src/hb-aat-layout-morx-table.hh b/src/hb-aat-layout-morx-table.hh
index 6d6ef708..dba352f9 100644
--- a/src/hb-aat-layout-morx-table.hh
+++ b/src/hb-aat-layout-morx-table.hh
@@ -865,8 +865,6 @@ struct Chain
   {
     hb_mask_t flags = defaultFlags;
     {
-      /* Compute applicable flags.  TODO Should move this to planning
-       * stage and take user-requested features into account. */
       unsigned int count = featureCount;
       for (unsigned i = 0; i < count; i++)
       {
commit f864ef215e1354a1e5a3c8796afafba761404e08
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Tue Oct 30 19:42:21 2018 -0700

    [mort] More massaging towards mort

diff --git a/src/hb-aat-layout-morx-table.hh b/src/hb-aat-layout-morx-table.hh
index a2dd45a0..6d6ef708 100644
--- a/src/hb-aat-layout-morx-table.hh
+++ b/src/hb-aat-layout-morx-table.hh
@@ -782,28 +782,29 @@ struct Feature
 template <typename Types>
 struct ChainSubtable
 {
+  typedef typename Types::HBUINT HBUINT;
+
   template <typename T>
   friend struct Chain;
 
   inline unsigned int get_size (void) const { return length; }
-  inline unsigned int get_type (void) const { return coverage & SubtableType; }
+  inline unsigned int get_type (void) const { return coverage & 0xFF; }
+  inline unsigned int get_coverage (void) const { return coverage >> (sizeof (HBUINT) * 8 - 8); }
 
   enum Coverage
   {
-    Vertical		= 0x80000000,	/* If set, this subtable will only be applied
-					 * to vertical text. If clear, this subtable
-					 * will only be applied to horizontal text. */
-    Backwards		= 0x40000000,	/* If set, this subtable will process glyphs
-					 * in descending order. If clear, it will
-					 * process the glyphs in ascending order. */
-    AllDirections	= 0x20000000,	/* If set, this subtable will be applied to
-					 * both horizontal and vertical text (i.e.
-					 * the state of bit 0x80000000 is ignored). */
-    Logical		= 0x10000000,	/* If set, this subtable will process glyphs
-					 * in logical order (or reverse logical order,
-					 * depending on the value of bit 0x80000000). */
-    Reserved		= 0x0FFFFF00,	/* Reserved, set to zero. */
-    SubtableType	= 0x000000FF,	/* Subtable type; see following table. */
+    Vertical		= 0x80,	/* If set, this subtable will only be applied
+				 * to vertical text. If clear, this subtable
+				 * will only be applied to horizontal text. */
+    Backwards		= 0x40,	/* If set, this subtable will process glyphs
+				 * in descending order. If clear, it will
+				 * process the glyphs in ascending order. */
+    AllDirections	= 0x20,	/* If set, this subtable will be applied to
+				 * both horizontal and vertical text (i.e.
+				 * the state of bit 0x80000000 is ignored). */
+    Logical		= 0x10,	/* If set, this subtable will process glyphs
+				 * in logical order (or reverse logical order,
+				 * depending on the value of bit 0x80000000). */
   };
   enum Type
   {
@@ -841,8 +842,8 @@ struct ChainSubtable
   }
 
   protected:
-  HBUINT32	length;		/* Total subtable length, including this header. */
-  HBUINT32	coverage;	/* Coverage flags and subtable type. */
+  HBUINT	length;		/* Total subtable length, including this header. */
+  HBUINT	coverage;	/* Coverage flags and subtable type. */
   HBUINT32	subFeatureFlags;/* The 32-bit mask identifying which subtable this is. */
   union {
   RearrangementSubtable<Types>	rearrangement;
@@ -852,7 +853,7 @@ struct ChainSubtable
   InsertionSubtable<Types>	insertion;
   } u;
   public:
-  DEFINE_SIZE_MIN (2 * sizeof (HBUINT32) + 4);
+  DEFINE_SIZE_MIN (2 * sizeof (HBUINT) + 4);
 };
 
 template <typename Types>
@@ -895,9 +896,9 @@ struct Chain
       if (!(subtable->subFeatureFlags & flags))
         goto skip;
 
-      if (!(subtable->coverage & ChainSubtable<Types>::AllDirections) &&
+      if (!(subtable->get_coverage() & ChainSubtable<Types>::AllDirections) &&
 	  HB_DIRECTION_IS_VERTICAL (c->buffer->props.direction) !=
-	  bool (subtable->coverage & ChainSubtable<Types>::Vertical))
+	  bool (subtable->get_coverage() & ChainSubtable<Types>::Vertical))
         goto skip;
 
       /* Buffer contents is always in logical direction.  Determine if
@@ -927,9 +928,9 @@ struct Chain
 				(the order opposite that of the characters, which
 				may be right-to-left or left-to-right).
        */
-      reverse = subtable->coverage & ChainSubtable<Types>::Logical ?
-		bool (subtable->coverage & ChainSubtable<Types>::Backwards) :
-		bool (subtable->coverage & ChainSubtable<Types>::Backwards) !=
+      reverse = subtable->get_coverage () & ChainSubtable<Types>::Logical ?
+		bool (subtable->get_coverage () & ChainSubtable<Types>::Backwards) :
+		bool (subtable->get_coverage () & ChainSubtable<Types>::Backwards) !=
 		HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction);
 
       if (!c->buffer->message (c->font, "start chain subtable %d", c->lookup_index))
@@ -981,8 +982,8 @@ struct Chain
   }
 
   protected:
-  HBUINT	defaultFlags;	/* The default specification for subtables. */
-  HBUINT	length;		/* Total byte count, including this header. */
+  HBUINT32	defaultFlags;	/* The default specification for subtables. */
+  HBUINT32	length;		/* Total byte count, including this header. */
   HBUINT	featureCount;	/* Number of feature subtable entries. */
   HBUINT	subtableCount;	/* The number of subtables in the chain. */
 
@@ -991,7 +992,7 @@ struct Chain
 /*subtableGlyphCoverageArray*/	/* Only if version >= 3. We don't use. */
 
   public:
-  DEFINE_SIZE_MIN (2 * sizeof (HBUINT) + 4);
+  DEFINE_SIZE_MIN (8 + 2 * sizeof (HBUINT));
 };
 
 
commit 2d9467340b1498ccc0cd47bf915b84ab12dfa025
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Tue Oct 30 19:33:31 2018 -0700

    [mort] Fix version check in sanitize

diff --git a/src/hb-aat-layout-morx-table.hh b/src/hb-aat-layout-morx-table.hh
index e619d9e9..a2dd45a0 100644
--- a/src/hb-aat-layout-morx-table.hh
+++ b/src/hb-aat-layout-morx-table.hh
@@ -1052,8 +1052,7 @@ struct mortmorx
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    if (!version.sanitize (c) || version < 2 ||
-	!chainCount.sanitize (c))
+    if (!version.sanitize (c) || !version || !chainCount.sanitize (c))
       return_trace (false);
 
     const Chain<Types> *chain = &firstChain;
@@ -1070,7 +1069,7 @@ struct mortmorx
 
   protected:
   HBUINT16	version;	/* Version number of the glyph metamorphosis table.
-				 * 2 or 3. */
+				 * 1, 2, or 3. */
   HBUINT16	unused;		/* Set to 0. */
   HBUINT32	chainCount;	/* Number of metamorphosis chains contained in this
 				 * table. */
commit c2527a1bc2b493473f06ea6ae79f0a87b722c4d3
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Tue Oct 30 19:26:16 2018 -0700

    [mort] Make it compile / hook it up
    
    Untested.

diff --git a/src/hb-aat-layout-common.hh b/src/hb-aat-layout-common.hh
index 7327cc5b..c9d5cfe9 100644
--- a/src/hb-aat-layout-common.hh
+++ b/src/hb-aat-layout-common.hh
@@ -433,8 +433,7 @@ struct StateTable
   inline unsigned int get_class (hb_codepoint_t glyph_id, unsigned int num_glyphs) const
   {
     if (unlikely (glyph_id == DELETED_GLYPH)) return CLASS_DELETED_GLYPH;
-    const HBUINT16 *v = (this+classTable).get_value (glyph_id, num_glyphs);
-    return v ? (unsigned) *v : (unsigned) CLASS_OUT_OF_BOUNDS;
+    return (this+classTable).get_class (glyph_id, num_glyphs);
   }
 
   inline const Entry<Extra> *get_entries () const
@@ -446,7 +445,7 @@ struct StateTable
   {
     if (unlikely (klass >= nClasses)) return nullptr;
 
-    const HBUINT16 *states = (this+stateArrayTable).arrayZ;
+    const HBUSHORT *states = (this+stateArrayTable).arrayZ;
     const Entry<Extra> *entries = (this+entryTable).arrayZ;
 
     unsigned int entry = states[state * nClasses + klass];
@@ -461,7 +460,7 @@ struct StateTable
     if (unlikely (!(c->check_struct (this) &&
 		    classTable.sanitize (c, this)))) return_trace (false);
 
-    const HBUINT16 *states = (this+stateArrayTable).arrayZ;
+    const HBUSHORT *states = (this+stateArrayTable).arrayZ;
     const Entry<Extra> *entries = (this+entryTable).arrayZ;
 
     unsigned int num_classes = nClasses;
@@ -483,8 +482,8 @@ struct StateTable
       if ((c->max_ops -= num_states - state) < 0)
 	return_trace (false);
       { /* Sweep new states. */
-	const HBUINT16 *stop = &states[num_states * num_classes];
-	for (const HBUINT16 *p = &states[state * num_classes]; p < stop; p++)
+	const HBUSHORT *stop = &states[num_states * num_classes];
+	for (const HBUSHORT *p = &states[state * num_classes]; p < stop; p++)
 	  num_entries = MAX<unsigned int> (num_entries, *p + 1);
 	state = num_states;
       }
diff --git a/src/hb-aat-layout-morx-table.hh b/src/hb-aat-layout-morx-table.hh
index 99627d3a..e619d9e9 100644
--- a/src/hb-aat-layout-morx-table.hh
+++ b/src/hb-aat-layout-morx-table.hh
@@ -278,7 +278,7 @@ struct ContextualSubtable
     private:
     bool mark_set;
     unsigned int mark;
-    const UnsizedOffsetListOf<Lookup<GlyphID>, HBUINT32, false> &subs;
+    const UnsizedOffsetListOf<Lookup<GlyphID>, HBUINT, false> &subs;
   };
 
   inline bool apply (hb_aat_apply_context_t *c) const
diff --git a/src/hb-aat-layout.cc b/src/hb-aat-layout.cc
index 59157c21..2b4f5783 100644
--- a/src/hb-aat-layout.cc
+++ b/src/hb-aat-layout.cc
@@ -133,20 +133,20 @@ hb_aat_layout_find_feature_mapping (hb_tag_t tag)
  * mort/morx/kerx/trak
  */
 
-// static inline const AAT::mort&
-// _get_mort (hb_face_t *face, hb_blob_t **blob = nullptr)
-// {
-//   if (unlikely (!hb_ot_shaper_face_data_ensure (face)))
-//   {
-//     if (blob)
-//       *blob = hb_blob_get_empty ();
-//     return Null(AAT::mort);
-//   }
-//   const AAT::morx& mort = *(hb_ot_face_data (face)->mort.get ());
-//   if (blob)
-//     *blob = hb_ot_face_data (face)->mort.get_blob ();
-//   return mort;
-// }
+static inline const AAT::mort&
+_get_mort (hb_face_t *face, hb_blob_t **blob = nullptr)
+{
+  if (unlikely (!hb_ot_shaper_face_data_ensure (face)))
+  {
+    if (blob)
+      *blob = hb_blob_get_empty ();
+    return Null(AAT::mort);
+  }
+  const AAT::mort& mort = *(hb_ot_face_data (face)->mort.get ());
+  if (blob)
+    *blob = hb_ot_face_data (face)->mort.get_blob ();
+  return mort;
+}
 static inline const AAT::morx&
 _get_morx (hb_face_t *face, hb_blob_t **blob = nullptr)
 {
@@ -214,7 +214,8 @@ hb_aat_layout_compile_map (const hb_aat_map_builder_t *mapper,
 hb_bool_t
 hb_aat_layout_has_substitution (hb_face_t *face)
 {
-  return _get_morx (face).has_data ();
+  return _get_morx (face).has_data () ||
+	 _get_mort (face).has_data ();
 }
 
 void
@@ -223,10 +224,22 @@ hb_aat_layout_substitute (hb_ot_shape_plan_t *plan,
 			  hb_buffer_t *buffer)
 {
   hb_blob_t *blob;
+
   const AAT::morx& morx = _get_morx (font->face, &blob);
+  if (morx.has_data ())
+  {
+    AAT::hb_aat_apply_context_t c (plan, font, buffer, blob);
+    morx.apply (&c);
+    return;
+  }
 
-  AAT::hb_aat_apply_context_t c (plan, font, buffer, blob);
-  morx.apply (&c);
+  const AAT::mort& mort = _get_mort (font->face, &blob);
+  if (mort.has_data ())
+  {
+    AAT::hb_aat_apply_context_t c (plan, font, buffer, blob);
+    mort.apply (&c);
+    return;
+  }
 }
 
 
commit 933babdc075c27fbcc1b726c3c9b2aa67338c6ad
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Tue Oct 30 19:22:43 2018 -0700

    [mort] Fixup on previous commit

diff --git a/src/hb-aat-layout-morx-table.hh b/src/hb-aat-layout-morx-table.hh
index 336d0e35..99627d3a 100644
--- a/src/hb-aat-layout-morx-table.hh
+++ b/src/hb-aat-layout-morx-table.hh
@@ -73,12 +73,12 @@ struct RearrangementSubtable
 	ret (false),
 	start (0), end (0) {}
 
-    inline bool is_actionable (StateTableDriver<MorxTypes, EntryData> *driver HB_UNUSED,
+    inline bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED,
 			       const Entry<EntryData> *entry)
     {
       return (entry->flags & Verb) && start < end;
     }
-    inline bool transition (StateTableDriver<MorxTypes, EntryData> *driver,
+    inline bool transition (StateTableDriver<Types, EntryData> *driver,
 			    const Entry<EntryData> *entry)
     {
       hb_buffer_t *buffer = driver->buffer;
@@ -169,7 +169,7 @@ struct RearrangementSubtable
 
     driver_context_t dc (this);
 
-    StateTableDriver<MorxTypes, EntryData> driver (machine, c->buffer, c->face);
+    StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
     driver.drive (&dc);
 
     return_trace (dc.ret);
@@ -219,7 +219,7 @@ struct ContextualSubtable
 	mark (0),
 	subs (table+table->substitutionTables) {}
 
-    inline bool is_actionable (StateTableDriver<MorxTypes, EntryData> *driver,
+    inline bool is_actionable (StateTableDriver<Types, EntryData> *driver,
 			       const Entry<EntryData> *entry)
     {
       hb_buffer_t *buffer = driver->buffer;
@@ -229,7 +229,7 @@ struct ContextualSubtable
 
       return entry->data.markIndex != 0xFFFF || entry->data.currentIndex != 0xFFFF;
     }
-    inline bool transition (StateTableDriver<MorxTypes, EntryData> *driver,
+    inline bool transition (StateTableDriver<Types, EntryData> *driver,
 			    const Entry<EntryData> *entry)
     {
       hb_buffer_t *buffer = driver->buffer;
@@ -287,7 +287,7 @@ struct ContextualSubtable
 
     driver_context_t dc (this);
 
-    StateTableDriver<MorxTypes, EntryData> driver (machine, c->buffer, c->face);
+    StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
     driver.drive (&dc);
 
     return_trace (dc.ret);
@@ -373,12 +373,12 @@ struct LigatureSubtable
 	ligature (table+table->ligature),
 	match_length (0) {}
 
-    inline bool is_actionable (StateTableDriver<MorxTypes, EntryData> *driver HB_UNUSED,
+    inline bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED,
 			       const Entry<EntryData> *entry)
     {
       return entry->flags & PerformAction;
     }
-    inline bool transition (StateTableDriver<MorxTypes, EntryData> *driver,
+    inline bool transition (StateTableDriver<Types, EntryData> *driver,
 			    const Entry<EntryData> *entry)
     {
       hb_buffer_t *buffer = driver->buffer;
@@ -492,7 +492,7 @@ struct LigatureSubtable
 
     driver_context_t dc (this, c);
 
-    StateTableDriver<MorxTypes, EntryData> driver (machine, c->buffer, c->face);
+    StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
     driver.drive (&dc);
 
     return_trace (dc.ret);
@@ -636,13 +636,13 @@ struct InsertionSubtable
 	mark (0),
 	insertionAction (table+table->insertionAction) {}
 
-    inline bool is_actionable (StateTableDriver<MorxTypes, EntryData> *driver HB_UNUSED,
+    inline bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED,
 			       const Entry<EntryData> *entry)
     {
       return (entry->flags & (CurrentInsertCount | MarkedInsertCount)) &&
 	     (entry->data.currentInsertIndex != 0xFFFF ||entry->data.markedInsertIndex != 0xFFFF);
     }
-    inline bool transition (StateTableDriver<MorxTypes, EntryData> *driver,
+    inline bool transition (StateTableDriver<Types, EntryData> *driver,
 			    const Entry<EntryData> *entry)
     {
       hb_buffer_t *buffer = driver->buffer;
@@ -734,7 +734,7 @@ struct InsertionSubtable
 
     driver_context_t dc (this, c);
 
-    StateTableDriver<MorxTypes, EntryData> driver (machine, c->buffer, c->face);
+    StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
     driver.drive (&dc);
 
     return_trace (dc.ret);
commit b053cabacd99ff69144a1459fe02ffd574c2416c
Author: Ebrahim Byagowi <ebrahim at gnu.org>
Date:   Tue Oct 30 18:41:34 2018 +0330

    [mort] Bring back mort generalizations
    
    Started by reverting https://github.com/harfbuzz/harfbuzz/commit/1f1c85a5
    
    Just a starting point, if we agree even mort can come back.

diff --git a/src/hb-aat-layout-common.hh b/src/hb-aat-layout-common.hh
index ce40abd5..7327cc5b 100644
--- a/src/hb-aat-layout-common.hh
+++ b/src/hb-aat-layout-common.hh
@@ -410,9 +410,13 @@ struct Entry<void>
   DEFINE_SIZE_STATIC (4);
 };
 
-template <typename Extra>
+template <typename Types, typename Extra>
 struct StateTable
 {
+  typedef typename Types::HBUINT HBUINT;
+  typedef typename Types::HBUSHORT HBUSHORT;
+  typedef typename Types::ClassType ClassType;
+
   enum State
   {
     STATE_START_OF_TEXT = 0,
@@ -504,23 +508,73 @@ struct StateTable
   }
 
   protected:
-  HBUINT32	nClasses;	/* Number of classes, which is the number of indices
+  HBUINT	nClasses;	/* Number of classes, which is the number of indices
 				 * in a single line in the state array. */
-  LOffsetTo<Lookup<HBUINT16>, false>
+  OffsetTo<ClassType, HBUINT, false>
 		classTable;	/* Offset to the class table. */
-  LOffsetTo<UnsizedArrayOf<HBUINT16>, false>
+  OffsetTo<UnsizedArrayOf<HBUSHORT>, HBUINT, false>
 		stateArrayTable;/* Offset to the state array. */
-  LOffsetTo<UnsizedArrayOf<Entry<Extra> >, false>
+  OffsetTo<UnsizedArrayOf<Entry<Extra> >, HBUINT, false>
 		entryTable;	/* Offset to the entry array. */
 
   public:
   DEFINE_SIZE_STATIC (16);
 };
 
-template <typename EntryData>
+struct ClassTable
+{
+  inline unsigned int get_class (hb_codepoint_t glyph_id) const
+  {
+    return firstGlyph <= glyph_id && glyph_id - firstGlyph < glyphCount ? classArrayZ[glyph_id - firstGlyph] : 1;
+  }
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) && classArrayZ.sanitize (c, glyphCount));
+  }
+  protected:
+  GlyphID	firstGlyph;	/* First glyph index included in the trimmed array. */
+  HBUINT16	glyphCount;	/* Total number of glyphs (equivalent to the last
+				 * glyph minus the value of firstGlyph plus 1). */
+  UnsizedArrayOf<HBUINT8>
+		classArrayZ;	/* The class codes (indexed by glyph index minus
+				 * firstGlyph). */
+  public:
+  DEFINE_SIZE_ARRAY (4, classArrayZ);
+};
+
+struct MortTypes
+{
+  static const bool extended = false;
+  typedef HBUINT16 HBUINT;
+  typedef HBUINT8 HBUSHORT;
+  struct ClassType : ClassTable
+  {
+    inline unsigned int get_class (hb_codepoint_t glyph_id, unsigned int num_glyphs HB_UNUSED) const
+    {
+      return ClassTable::get_class (glyph_id);
+    }
+  };
+};
+struct MorxTypes
+{
+  static const bool extended = true;
+  typedef HBUINT32 HBUINT;
+  typedef HBUINT16 HBUSHORT;
+  struct ClassType : Lookup<HBUINT16>
+  {
+    inline unsigned int get_class (hb_codepoint_t glyph_id, unsigned int num_glyphs) const
+    {
+      const HBUINT16 *v = get_value (glyph_id, num_glyphs);
+      return v ? *v : 1;
+    }
+  };
+};
+
+template <typename Types, typename EntryData>
 struct StateTableDriver
 {
-  inline StateTableDriver (const StateTable<EntryData> &machine_,
+  inline StateTableDriver (const StateTable<Types, EntryData> &machine_,
 			   hb_buffer_t *buffer_,
 			   hb_face_t *face_) :
 	      machine (machine_),
@@ -533,13 +587,13 @@ struct StateTableDriver
     if (!c->in_place)
       buffer->clear_output ();
 
-    unsigned int state = StateTable<EntryData>::STATE_START_OF_TEXT;
+    unsigned int state = StateTable<Types, EntryData>::STATE_START_OF_TEXT;
     bool last_was_dont_advance = false;
     for (buffer->idx = 0; buffer->successful;)
     {
       unsigned int klass = buffer->idx < buffer->len ?
 			   machine.get_class (buffer->info[buffer->idx].codepoint, num_glyphs) :
-			   (unsigned) StateTable<EntryData>::CLASS_END_OF_TEXT;
+			   (unsigned) StateTable<Types, EntryData>::CLASS_END_OF_TEXT;
       const Entry<EntryData> *entry = machine.get_entryZ (state, klass);
       if (unlikely (!entry))
 	break;
@@ -553,7 +607,7 @@ struct StateTableDriver
 	/* If there's no action and we're just epsilon-transitioning to state 0,
 	 * safe to break. */
 	if (c->is_actionable (this, entry) ||
-	    !(entry->newState == StateTable<EntryData>::STATE_START_OF_TEXT &&
+	    !(entry->newState == StateTable<Types, EntryData>::STATE_START_OF_TEXT &&
 	      entry->flags == context_t::DontAdvance))
 	  buffer->unsafe_to_break_from_outbuffer (buffer->backtrack_len () - 1, buffer->idx + 1);
       }
@@ -590,7 +644,7 @@ struct StateTableDriver
   }
 
   public:
-  const StateTable<EntryData> &machine;
+  const StateTable<Types, EntryData> &machine;
   hb_buffer_t *buffer;
   unsigned int num_glyphs;
 };
diff --git a/src/hb-aat-layout-kerx-table.hh b/src/hb-aat-layout-kerx-table.hh
index a8831250..94e0a9b6 100644
--- a/src/hb-aat-layout-kerx-table.hh
+++ b/src/hb-aat-layout-kerx-table.hh
@@ -163,12 +163,12 @@ struct KerxSubTableFormat1
 	kernAction (&table->machine + table->kernAction),
 	depth (0) {}
 
-    inline bool is_actionable (StateTableDriver<EntryData> *driver HB_UNUSED,
+    inline bool is_actionable (StateTableDriver<MorxTypes, EntryData> *driver HB_UNUSED,
 			       const Entry<EntryData> *entry)
     {
       return entry->data.kernActionIndex != 0xFFFF;
     }
-    inline bool transition (StateTableDriver<EntryData> *driver,
+    inline bool transition (StateTableDriver<MorxTypes, EntryData> *driver,
 			    const Entry<EntryData> *entry)
     {
       hb_buffer_t *buffer = driver->buffer;
@@ -239,7 +239,7 @@ struct KerxSubTableFormat1
 
     driver_context_t dc (this, c);
 
-    StateTableDriver<EntryData> driver (machine, c->buffer, c->font->face);
+    StateTableDriver<MorxTypes, EntryData> driver (machine, c->buffer, c->font->face);
     driver.drive (&dc);
 
     return_trace (true);
@@ -255,7 +255,7 @@ struct KerxSubTableFormat1
 
   protected:
   KerxSubTableHeader				header;
-  StateTable<EntryData>				machine;
+  StateTable<MorxTypes, EntryData>				machine;
   LOffsetTo<UnsizedArrayOf<FWORD>, false>	kernAction;
   public:
   DEFINE_SIZE_STATIC (32);
@@ -365,12 +365,12 @@ struct KerxSubTableFormat4
 	mark_set (false),
 	mark (0) {}
 
-    inline bool is_actionable (StateTableDriver<EntryData> *driver HB_UNUSED,
+    inline bool is_actionable (StateTableDriver<MorxTypes, EntryData> *driver HB_UNUSED,
 			       const Entry<EntryData> *entry)
     {
       return entry->data.ankrActionIndex != 0xFFFF;
     }
-    inline bool transition (StateTableDriver<EntryData> *driver,
+    inline bool transition (StateTableDriver<MorxTypes, EntryData> *driver,
 			    const Entry<EntryData> *entry)
     {
       hb_buffer_t *buffer = driver->buffer;
@@ -473,7 +473,7 @@ struct KerxSubTableFormat4
 
     driver_context_t dc (this, c);
 
-    StateTableDriver<EntryData> driver (machine, c->buffer, c->font->face);
+    StateTableDriver<MorxTypes, EntryData> driver (machine, c->buffer, c->font->face);
     driver.drive (&dc);
 
     return_trace (true);
@@ -489,7 +489,8 @@ struct KerxSubTableFormat4
 
   protected:
   KerxSubTableHeader	header;
-  StateTable<EntryData>	machine;
+  StateTable<MorxTypes, EntryData>
+			machine;
   HBUINT32		flags;
   public:
   DEFINE_SIZE_STATIC (32);
diff --git a/src/hb-aat-layout-morx-table.hh b/src/hb-aat-layout-morx-table.hh
index a5620910..336d0e35 100644
--- a/src/hb-aat-layout-morx-table.hh
+++ b/src/hb-aat-layout-morx-table.hh
@@ -35,17 +35,21 @@
 /*
  * morx -- Extended Glyph Metamorphosis
  * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6morx.html
+ * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6mort.html
  */
 #define HB_AAT_TAG_morx HB_TAG('m','o','r','x')
+#define HB_AAT_TAG_mort HB_TAG('m','o','r','t')
 
 
 namespace AAT {
 
 using namespace OT;
 
-
+template <typename Types>
 struct RearrangementSubtable
 {
+  typedef typename Types::HBUINT HBUINT;
+
   typedef void EntryData;
 
   struct driver_context_t
@@ -69,12 +73,12 @@ struct RearrangementSubtable
 	ret (false),
 	start (0), end (0) {}
 
-    inline bool is_actionable (StateTableDriver<EntryData> *driver HB_UNUSED,
+    inline bool is_actionable (StateTableDriver<MorxTypes, EntryData> *driver HB_UNUSED,
 			       const Entry<EntryData> *entry)
     {
       return (entry->flags & Verb) && start < end;
     }
-    inline bool transition (StateTableDriver<EntryData> *driver,
+    inline bool transition (StateTableDriver<MorxTypes, EntryData> *driver,
 			    const Entry<EntryData> *entry)
     {
       hb_buffer_t *buffer = driver->buffer;
@@ -165,7 +169,7 @@ struct RearrangementSubtable
 
     driver_context_t dc (this);
 
-    StateTableDriver<EntryData> driver (machine, c->buffer, c->face);
+    StateTableDriver<MorxTypes, EntryData> driver (machine, c->buffer, c->face);
     driver.drive (&dc);
 
     return_trace (dc.ret);
@@ -178,13 +182,16 @@ struct RearrangementSubtable
   }
 
   protected:
-  StateTable<EntryData>	machine;
+  StateTable<Types, EntryData>	machine;
   public:
   DEFINE_SIZE_STATIC (16);
 };
 
+template <typename Types>
 struct ContextualSubtable
 {
+  typedef typename Types::HBUINT HBUINT;
+
   struct EntryData
   {
     HBUINT16	markIndex;	/* Index of the substitution table for the
@@ -212,7 +219,7 @@ struct ContextualSubtable
 	mark (0),
 	subs (table+table->substitutionTables) {}
 
-    inline bool is_actionable (StateTableDriver<EntryData> *driver,
+    inline bool is_actionable (StateTableDriver<MorxTypes, EntryData> *driver,
 			       const Entry<EntryData> *entry)
     {
       hb_buffer_t *buffer = driver->buffer;
@@ -222,7 +229,7 @@ struct ContextualSubtable
 
       return entry->data.markIndex != 0xFFFF || entry->data.currentIndex != 0xFFFF;
     }
-    inline bool transition (StateTableDriver<EntryData> *driver,
+    inline bool transition (StateTableDriver<MorxTypes, EntryData> *driver,
 			    const Entry<EntryData> *entry)
     {
       hb_buffer_t *buffer = driver->buffer;
@@ -280,7 +287,7 @@ struct ContextualSubtable
 
     driver_context_t dc (this);
 
-    StateTableDriver<EntryData> driver (machine, c->buffer, c->face);
+    StateTableDriver<MorxTypes, EntryData> driver (machine, c->buffer, c->face);
     driver.drive (&dc);
 
     return_trace (dc.ret);
@@ -310,16 +317,19 @@ struct ContextualSubtable
   }
 
   protected:
-  StateTable<EntryData>
+  StateTable<Types, EntryData>
 		machine;
-  LOffsetTo<UnsizedOffsetListOf<Lookup<GlyphID>, HBUINT32, false>, false>
+  OffsetTo<UnsizedOffsetListOf<Lookup<GlyphID>, HBUINT, false>, HBUINT, false>
 		substitutionTables;
   public:
   DEFINE_SIZE_STATIC (20);
 };
 
+template <typename Types>
 struct LigatureSubtable
 {
+  typedef typename Types::HBUINT HBUINT;
+
   struct EntryData
   {
     HBUINT16	ligActionIndex;	/* Index to the first ligActionTable entry
@@ -363,12 +373,12 @@ struct LigatureSubtable
 	ligature (table+table->ligature),
 	match_length (0) {}
 
-    inline bool is_actionable (StateTableDriver<EntryData> *driver HB_UNUSED,
+    inline bool is_actionable (StateTableDriver<MorxTypes, EntryData> *driver HB_UNUSED,
 			       const Entry<EntryData> *entry)
     {
       return entry->flags & PerformAction;
     }
-    inline bool transition (StateTableDriver<EntryData> *driver,
+    inline bool transition (StateTableDriver<MorxTypes, EntryData> *driver,
 			    const Entry<EntryData> *entry)
     {
       hb_buffer_t *buffer = driver->buffer;
@@ -482,7 +492,7 @@ struct LigatureSubtable
 
     driver_context_t dc (this, c);
 
-    StateTableDriver<EntryData> driver (machine, c->buffer, c->face);
+    StateTableDriver<MorxTypes, EntryData> driver (machine, c->buffer, c->face);
     driver.drive (&dc);
 
     return_trace (dc.ret);
@@ -497,18 +507,19 @@ struct LigatureSubtable
   }
 
   protected:
-  StateTable<EntryData>
+  StateTable<Types, EntryData>
 		machine;
-  LOffsetTo<UnsizedArrayOf<HBUINT32>, false>
+  OffsetTo<UnsizedArrayOf<HBUINT32>, HBUINT, false>
 		ligAction;	/* Offset to the ligature action table. */
-  LOffsetTo<UnsizedArrayOf<HBUINT16>, false>
+  OffsetTo<UnsizedArrayOf<HBUINT16>, HBUINT, false>
 		component;	/* Offset to the component table. */
-  LOffsetTo<UnsizedArrayOf<GlyphID>, false>
+  OffsetTo<UnsizedArrayOf<GlyphID>, HBUINT, false>
 		ligature;	/* Offset to the actual ligature lists. */
   public:
   DEFINE_SIZE_STATIC (28);
 };
 
+template <typename Types>
 struct NoncontextualSubtable
 {
   inline bool apply (hb_aat_apply_context_t *c) const
@@ -545,8 +556,11 @@ struct NoncontextualSubtable
   DEFINE_SIZE_MIN (2);
 };
 
+template <typename Types>
 struct InsertionSubtable
 {
+  typedef typename Types::HBUINT HBUINT;
+
   struct EntryData
   {
     HBUINT16	currentInsertIndex;	/* Zero-based index into the insertion glyph table.
@@ -622,13 +636,13 @@ struct InsertionSubtable
 	mark (0),
 	insertionAction (table+table->insertionAction) {}
 
-    inline bool is_actionable (StateTableDriver<EntryData> *driver HB_UNUSED,
+    inline bool is_actionable (StateTableDriver<MorxTypes, EntryData> *driver HB_UNUSED,
 			       const Entry<EntryData> *entry)
     {
       return (entry->flags & (CurrentInsertCount | MarkedInsertCount)) &&
 	     (entry->data.currentInsertIndex != 0xFFFF ||entry->data.markedInsertIndex != 0xFFFF);
     }
-    inline bool transition (StateTableDriver<EntryData> *driver,
+    inline bool transition (StateTableDriver<MorxTypes, EntryData> *driver,
 			    const Entry<EntryData> *entry)
     {
       hb_buffer_t *buffer = driver->buffer;
@@ -720,7 +734,7 @@ struct InsertionSubtable
 
     driver_context_t dc (this, c);
 
-    StateTableDriver<EntryData> driver (machine, c->buffer, c->face);
+    StateTableDriver<MorxTypes, EntryData> driver (machine, c->buffer, c->face);
     driver.drive (&dc);
 
     return_trace (dc.ret);
@@ -735,9 +749,9 @@ struct InsertionSubtable
   }
 
   protected:
-  StateTable<EntryData>
+  StateTable<Types, EntryData>
 		machine;
-  LOffsetTo<UnsizedArrayOf<GlyphID>, false>
+  OffsetTo<UnsizedArrayOf<GlyphID>, HBUINT, false>
 		insertionAction;	/* Byte offset from stateHeader to the start of
 					 * the insertion glyph table. */
   public:
@@ -765,9 +779,10 @@ struct Feature
   DEFINE_SIZE_STATIC (12);
 };
 
-
+template <typename Types>
 struct ChainSubtable
 {
+  template <typename T>
   friend struct Chain;
 
   inline unsigned int get_size (void) const { return length; }
@@ -830,18 +845,21 @@ struct ChainSubtable
   HBUINT32	coverage;	/* Coverage flags and subtable type. */
   HBUINT32	subFeatureFlags;/* The 32-bit mask identifying which subtable this is. */
   union {
-  RearrangementSubtable		rearrangement;
-  ContextualSubtable		contextual;
-  LigatureSubtable		ligature;
-  NoncontextualSubtable		noncontextual;
-  InsertionSubtable		insertion;
+  RearrangementSubtable<Types>	rearrangement;
+  ContextualSubtable<Types>	contextual;
+  LigatureSubtable<Types>	ligature;
+  NoncontextualSubtable<Types>	noncontextual;
+  InsertionSubtable<Types>	insertion;
   } u;
   public:
-  DEFINE_SIZE_MIN (12);
+  DEFINE_SIZE_MIN (2 * sizeof (HBUINT32) + 4);
 };
 
+template <typename Types>
 struct Chain
 {
+  typedef typename Types::HBUINT HBUINT;
+
   inline hb_mask_t compile_flags (const hb_aat_map_builder_t *map) const
   {
     hb_mask_t flags = defaultFlags;
@@ -868,7 +886,7 @@ struct Chain
   inline void apply (hb_aat_apply_context_t *c,
 		     hb_mask_t flags) const
   {
-    const ChainSubtable *subtable = &StructAtOffset<ChainSubtable> (&featureZ, featureZ[0].static_size * featureCount);
+    const ChainSubtable<Types> *subtable = &StructAtOffset<ChainSubtable<Types> > (&featureZ, featureZ[0].static_size * featureCount);
     unsigned int count = subtableCount;
     for (unsigned int i = 0; i < count; i++)
     {
@@ -877,9 +895,9 @@ struct Chain
       if (!(subtable->subFeatureFlags & flags))
         goto skip;
 
-      if (!(subtable->coverage & ChainSubtable::AllDirections) &&
+      if (!(subtable->coverage & ChainSubtable<Types>::AllDirections) &&
 	  HB_DIRECTION_IS_VERTICAL (c->buffer->props.direction) !=
-	  bool (subtable->coverage & ChainSubtable::Vertical))
+	  bool (subtable->coverage & ChainSubtable<Types>::Vertical))
         goto skip;
 
       /* Buffer contents is always in logical direction.  Determine if
@@ -909,9 +927,9 @@ struct Chain
 				(the order opposite that of the characters, which
 				may be right-to-left or left-to-right).
        */
-      reverse = subtable->coverage & ChainSubtable::Logical ?
-		bool (subtable->coverage & ChainSubtable::Backwards) :
-		bool (subtable->coverage & ChainSubtable::Backwards) !=
+      reverse = subtable->coverage & ChainSubtable<Types>::Logical ?
+		bool (subtable->coverage & ChainSubtable<Types>::Backwards) :
+		bool (subtable->coverage & ChainSubtable<Types>::Backwards) !=
 		HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction);
 
       if (!c->buffer->message (c->font, "start chain subtable %d", c->lookup_index))
@@ -932,7 +950,7 @@ struct Chain
       if (unlikely (!c->buffer->successful)) return;
 
     skip:
-      subtable = &StructAfter<ChainSubtable> (*subtable);
+      subtable = &StructAfter<ChainSubtable<Types> > (*subtable);
       c->set_lookup_index (c->lookup_index + 1);
     }
   }
@@ -950,38 +968,39 @@ struct Chain
     if (!c->check_array (featureZ.arrayZ, featureCount))
       return_trace (false);
 
-    const ChainSubtable *subtable = &StructAtOffset<ChainSubtable> (&featureZ, featureZ[0].static_size * featureCount);
+    const ChainSubtable<Types> *subtable = &StructAtOffset<ChainSubtable<Types> > (&featureZ, featureZ[0].static_size * featureCount);
     unsigned int count = subtableCount;
     for (unsigned int i = 0; i < count; i++)
     {
       if (!subtable->sanitize (c))
 	return_trace (false);
-      subtable = &StructAfter<ChainSubtable> (*subtable);
+      subtable = &StructAfter<ChainSubtable<Types> > (*subtable);
     }
 
     return_trace (true);
   }
 
   protected:
-  HBUINT32	defaultFlags;	/* The default specification for subtables. */
-  HBUINT32	length;		/* Total byte count, including this header. */
-  HBUINT32	featureCount;	/* Number of feature subtable entries. */
-  HBUINT32	subtableCount;	/* The number of subtables in the chain. */
+  HBUINT	defaultFlags;	/* The default specification for subtables. */
+  HBUINT	length;		/* Total byte count, including this header. */
+  HBUINT	featureCount;	/* Number of feature subtable entries. */
+  HBUINT	subtableCount;	/* The number of subtables in the chain. */
 
   UnsizedArrayOf<Feature>	featureZ;	/* Features. */
 /*ChainSubtable	firstSubtable;*//* Subtables. */
 /*subtableGlyphCoverageArray*/	/* Only if version >= 3. We don't use. */
 
   public:
-  DEFINE_SIZE_MIN (16);
+  DEFINE_SIZE_MIN (2 * sizeof (HBUINT) + 4);
 };
 
 
 /*
- * The 'morx' Table
+ * The 'mort'/'morx' Table
  */
 
-struct morx
+template <typename Types>
+struct mortmorx
 {
   static const hb_tag_t tableTag = HB_AAT_TAG_morx;
 
@@ -990,12 +1009,12 @@ struct morx
   inline void compile_flags (const hb_aat_map_builder_t *mapper,
 			     hb_aat_map_t *map) const
   {
-    const Chain *chain = &firstChain;
+    const Chain<Types> *chain = &firstChain;
     unsigned int count = chainCount;
     for (unsigned int i = 0; i < count; i++)
     {
       map->chain_flags.push (chain->compile_flags (mapper));
-      chain = &StructAfter<Chain> (*chain);
+      chain = &StructAfter<Chain<Types> > (*chain);
     }
   }
 
@@ -1019,13 +1038,13 @@ struct morx
   {
     if (unlikely (!c->buffer->successful)) return;
     c->set_lookup_index (0);
-    const Chain *chain = &firstChain;
+    const Chain<Types> *chain = &firstChain;
     unsigned int count = chainCount;
     for (unsigned int i = 0; i < count; i++)
     {
       chain->apply (c, c->plan->aat_map.chain_flags[i]);
       if (unlikely (!c->buffer->successful)) return;
-      chain = &StructAfter<Chain> (*chain);
+      chain = &StructAfter<Chain<Types> > (*chain);
     }
     remove_deleted_glyphs (c->buffer);
   }
@@ -1037,13 +1056,13 @@ struct morx
 	!chainCount.sanitize (c))
       return_trace (false);
 
-    const Chain *chain = &firstChain;
+    const Chain<Types> *chain = &firstChain;
     unsigned int count = chainCount;
     for (unsigned int i = 0; i < count; i++)
     {
       if (!chain->sanitize (c, version))
 	return_trace (false);
-      chain = &StructAfter<Chain> (*chain);
+      chain = &StructAfter<Chain<Types> > (*chain);
     }
 
     return_trace (true);
@@ -1055,12 +1074,22 @@ struct morx
   HBUINT16	unused;		/* Set to 0. */
   HBUINT32	chainCount;	/* Number of metamorphosis chains contained in this
 				 * table. */
-  Chain		firstChain;	/* Chains. */
+  Chain<Types>	firstChain;	/* Chains. */
 
   public:
   DEFINE_SIZE_MIN (8);
 };
 
+struct morx : mortmorx<MorxTypes>
+{
+  static const hb_tag_t tableTag	= HB_AAT_TAG_morx;
+};
+struct mort : mortmorx<MortTypes>
+{
+  static const hb_tag_t tableTag	= HB_AAT_TAG_mort;
+};
+
+
 } /* namespace AAT */
 
 
diff --git a/src/hb-aat-layout.cc b/src/hb-aat-layout.cc
index ec053938..59157c21 100644
--- a/src/hb-aat-layout.cc
+++ b/src/hb-aat-layout.cc
@@ -130,9 +130,23 @@ hb_aat_layout_find_feature_mapping (hb_tag_t tag)
 
 
 /*
- * morx/kerx/trak
+ * mort/morx/kerx/trak
  */
 
+// static inline const AAT::mort&
+// _get_mort (hb_face_t *face, hb_blob_t **blob = nullptr)
+// {
+//   if (unlikely (!hb_ot_shaper_face_data_ensure (face)))
+//   {
+//     if (blob)
+//       *blob = hb_blob_get_empty ();
+//     return Null(AAT::mort);
+//   }
+//   const AAT::morx& mort = *(hb_ot_face_data (face)->mort.get ());
+//   if (blob)
+//     *blob = hb_ot_face_data (face)->mort.get_blob ();
+//   return mort;
+// }
 static inline const AAT::morx&
 _get_morx (hb_face_t *face, hb_blob_t **blob = nullptr)
 {
diff --git a/src/hb-ot-face.hh b/src/hb-ot-face.hh
index f3b7945b..6e629eb4 100644
--- a/src/hb-ot-face.hh
+++ b/src/hb-ot-face.hh
@@ -52,6 +52,7 @@
     HB_OT_TABLE(OT, BASE) \
     /* AAT shaping. */ \
     HB_OT_TABLE(AAT, morx) \
+    HB_OT_TABLE(AAT, mort) \
     HB_OT_TABLE(AAT, kerx) \
     HB_OT_TABLE(AAT, ankr) \
     HB_OT_TABLE(AAT, trak) \


More information about the HarfBuzz mailing list