Revert "Imported Upstream version 1.2.7"
[platform/upstream/harfbuzz.git] / src / hb-ot-layout-gpos-table.hh
index bbe390c..d88f787 100644 (file)
@@ -36,17 +36,8 @@ namespace OT {
 
 
 /* buffer **position** var allocations */
-#define attach_chain() var.i16[0] /* glyph to which this attaches to, relative to current glyphs; negative for going back, positive for forward. */
-#define attach_type() var.u8[2] /* attachment type */
-/* Note! if attach_chain() is zero, the value of attach_type() is irrelevant. */
-
-enum attach_type_t {
-  ATTACH_TYPE_NONE     = 0X00,
-
-  /* Each attachment should be either a mark or a cursive; can't be both. */
-  ATTACH_TYPE_MARK     = 0X01,
-  ATTACH_TYPE_CURSIVE  = 0X02,
-};
+#define attach_lookback() var.u16[0] /* number of glyphs to go back to attach this glyph to its base */
+#define cursive_chain() var.i16[1] /* character to which this connects, may be positive or negative */
 
 
 /* Shared Tables: ValueRecord, Anchor Table, and MarkArray */
@@ -190,7 +181,7 @@ struct ValueFormat : USHORT
   inline bool sanitize_value (hb_sanitize_context_t *c, const void *base, const Value *values) const
   {
     TRACE_SANITIZE (this);
-    return_trace (c->check_range (values, get_size ()) && (!has_device () || sanitize_value_devices (c, base, values)));
+    return TRACE_RETURN (c->check_range (values, get_size ()) && (!has_device () || sanitize_value_devices (c, base, values)));
   }
 
   inline bool sanitize_values (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count) const
@@ -198,17 +189,17 @@ struct ValueFormat : USHORT
     TRACE_SANITIZE (this);
     unsigned int len = get_len ();
 
-    if (!c->check_array (values, get_size (), count)) return_trace (false);
+    if (!c->check_array (values, get_size (), count)) return TRACE_RETURN (false);
 
-    if (!has_device ()) return_trace (true);
+    if (!has_device ()) return TRACE_RETURN (true);
 
     for (unsigned int i = 0; i < count; i++) {
       if (!sanitize_value_devices (c, base, values))
-        return_trace (false);
+        return TRACE_RETURN (false);
       values += len;
     }
 
-    return_trace (true);
+    return TRACE_RETURN (true);
   }
 
   /* Just sanitize referenced Device tables.  Doesn't check the values themselves. */
@@ -216,15 +207,15 @@ struct ValueFormat : USHORT
   {
     TRACE_SANITIZE (this);
 
-    if (!has_device ()) return_trace (true);
+    if (!has_device ()) return TRACE_RETURN (true);
 
     for (unsigned int i = 0; i < count; i++) {
       if (!sanitize_value_devices (c, base, values))
-        return_trace (false);
+        return TRACE_RETURN (false);
       values += stride;
     }
 
-    return_trace (true);
+    return TRACE_RETURN (true);
   }
 };
 
@@ -241,7 +232,7 @@ struct AnchorFormat1
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this));
+    return TRACE_RETURN (c->check_struct (this));
   }
 
   protected:
@@ -271,7 +262,7 @@ struct AnchorFormat2
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this));
+    return TRACE_RETURN (c->check_struct (this));
   }
 
   protected:
@@ -300,7 +291,7 @@ struct AnchorFormat3
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this) && xDeviceTable.sanitize (c, this) && yDeviceTable.sanitize (c, this));
+    return TRACE_RETURN (c->check_struct (this) && xDeviceTable.sanitize (c, this) && yDeviceTable.sanitize (c, this));
   }
 
   protected:
@@ -336,12 +327,12 @@ struct Anchor
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    if (!u.format.sanitize (c)) return_trace (false);
+    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
     switch (u.format) {
-    case 1: return_trace (u.format1.sanitize (c));
-    case 2: return_trace (u.format2.sanitize (c));
-    case 3: return_trace (u.format3.sanitize (c));
-    default:return_trace (true);
+    case 1: return TRACE_RETURN (u.format1.sanitize (c));
+    case 2: return TRACE_RETURN (u.format2.sanitize (c));
+    case 3: return TRACE_RETURN (u.format3.sanitize (c));
+    default:return TRACE_RETURN (true);
     }
   }
 
@@ -369,13 +360,13 @@ struct AnchorMatrix
   inline bool sanitize (hb_sanitize_context_t *c, unsigned int cols) const
   {
     TRACE_SANITIZE (this);
-    if (!c->check_struct (this)) return_trace (false);
-    if (unlikely (rows > 0 && cols >= ((unsigned int) -1) / rows)) return_trace (false);
+    if (!c->check_struct (this)) return TRACE_RETURN (false);
+    if (unlikely (rows > 0 && cols >= ((unsigned int) -1) / rows)) return TRACE_RETURN (false);
     unsigned int count = rows * cols;
-    if (!c->check_array (matrixZ, matrixZ[0].static_size, count)) return_trace (false);
+    if (!c->check_array (matrixZ, matrixZ[0].static_size, count)) return TRACE_RETURN (false);
     for (unsigned int i = 0; i < count; i++)
-      if (!matrixZ[i].sanitize (c, this)) return_trace (false);
-    return_trace (true);
+      if (!matrixZ[i].sanitize (c, this)) return TRACE_RETURN (false);
+    return TRACE_RETURN (true);
   }
 
   USHORT       rows;                   /* Number of rows */
@@ -395,7 +386,7 @@ struct MarkRecord
   inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
   {
     TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this) && markAnchor.sanitize (c, base));
+    return TRACE_RETURN (c->check_struct (this) && markAnchor.sanitize (c, base));
   }
 
   protected:
@@ -424,7 +415,7 @@ struct MarkArray : ArrayOf<MarkRecord>      /* Array of MarkRecords--in Coverage orde
     const Anchor& glyph_anchor = anchors.get_anchor (glyph_index, mark_class, class_count, &found);
     /* If this subtable doesn't have an anchor for this base and this class,
      * return false such that the subsequent subtables have a chance at it. */
-    if (unlikely (!found)) return_trace (false);
+    if (unlikely (!found)) return TRACE_RETURN (false);
 
     hb_position_t mark_x, mark_y, base_x, base_y;
 
@@ -434,18 +425,16 @@ struct MarkArray : ArrayOf<MarkRecord>    /* Array of MarkRecords--in Coverage orde
     hb_glyph_position_t &o = buffer->cur_pos();
     o.x_offset = base_x - mark_x;
     o.y_offset = base_y - mark_y;
-    o.attach_type() = ATTACH_TYPE_MARK;
-    o.attach_chain() = (int) glyph_pos - (int) buffer->idx;
-    buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
+    o.attach_lookback() = buffer->idx - glyph_pos;
 
     buffer->idx++;
-    return_trace (true);
+    return TRACE_RETURN (true);
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (ArrayOf<MarkRecord>::sanitize (c, this));
+    return TRACE_RETURN (ArrayOf<MarkRecord>::sanitize (c, this));
   }
 };
 
@@ -470,21 +459,21 @@ struct SinglePosFormat1
     TRACE_APPLY (this);
     hb_buffer_t *buffer = c->buffer;
     unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
-    if (likely (index == NOT_COVERED)) return_trace (false);
+    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
 
     valueFormat.apply_value (c->font, c->direction, this,
                             values, buffer->cur_pos());
 
     buffer->idx++;
-    return_trace (true);
+    return TRACE_RETURN (true);
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this) &&
-                 coverage.sanitize (c, this) &&
-                 valueFormat.sanitize_value (c, this, values));
+    return TRACE_RETURN (c->check_struct (this)
+        && coverage.sanitize (c, this)
+       && valueFormat.sanitize_value (c, this, values));
   }
 
   protected:
@@ -519,24 +508,24 @@ struct SinglePosFormat2
     TRACE_APPLY (this);
     hb_buffer_t *buffer = c->buffer;
     unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
-    if (likely (index == NOT_COVERED)) return_trace (false);
+    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
 
-    if (likely (index >= valueCount)) return_trace (false);
+    if (likely (index >= valueCount)) return TRACE_RETURN (false);
 
     valueFormat.apply_value (c->font, c->direction, this,
                             &values[index * valueFormat.get_len ()],
                             buffer->cur_pos());
 
     buffer->idx++;
-    return_trace (true);
+    return TRACE_RETURN (true);
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this) &&
-                 coverage.sanitize (c, this) &&
-                 valueFormat.sanitize_values (c, this, values, valueCount));
+    return TRACE_RETURN (c->check_struct (this)
+       && coverage.sanitize (c, this)
+       && valueFormat.sanitize_values (c, this, values, valueCount));
   }
 
   protected:
@@ -559,11 +548,11 @@ struct SinglePos
   inline typename context_t::return_t dispatch (context_t *c) const
   {
     TRACE_DISPATCH (this, u.format);
-    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
+    if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
     switch (u.format) {
-    case 1: return_trace (c->dispatch (u.format1));
-    case 2: return_trace (c->dispatch (u.format2));
-    default:return_trace (c->default_return_value ());
+    case 1: return TRACE_RETURN (c->dispatch (u.format1));
+    case 2: return TRACE_RETURN (c->dispatch (u.format2));
+    default:return TRACE_RETURN (c->default_return_value ());
     }
   }
 
@@ -626,7 +615,7 @@ struct PairSet
 
     /* Hand-coded bsearch. */
     if (unlikely (!count))
-      return_trace (false);
+      return TRACE_RETURN (false);
     hb_codepoint_t x = buffer->info[pos].codepoint;
     int min = 0, max = (int) count - 1;
     while (min <= max)
@@ -647,11 +636,11 @@ struct PairSet
        if (len2)
          pos++;
        buffer->idx = pos;
-       return_trace (true);
+       return TRACE_RETURN (true);
       }
     }
 
-    return_trace (false);
+    return TRACE_RETURN (false);
   }
 
   struct sanitize_closure_t {
@@ -665,12 +654,12 @@ struct PairSet
   {
     TRACE_SANITIZE (this);
     if (!(c->check_struct (this)
-       && c->check_array (arrayZ, USHORT::static_size * closure->stride, len))) return_trace (false);
+       && c->check_array (arrayZ, USHORT::static_size * closure->stride, len))) return TRACE_RETURN (false);
 
     unsigned int count = len;
     const PairValueRecord *record = CastP<PairValueRecord> (arrayZ);
-    return_trace (closure->valueFormats[0].sanitize_values_stride_unsafe (c, closure->base, &record->values[0], count, closure->stride) &&
-                 closure->valueFormats[1].sanitize_values_stride_unsafe (c, closure->base, &record->values[closure->len1], count, closure->stride));
+    return TRACE_RETURN (closure->valueFormats[0].sanitize_values_stride_unsafe (c, closure->base, &record->values[0], count, closure->stride)
+                     && closure->valueFormats[1].sanitize_values_stride_unsafe (c, closure->base, &record->values[closure->len1], count, closure->stride));
   }
 
   protected:
@@ -702,21 +691,19 @@ struct PairPosFormat1
     TRACE_APPLY (this);
     hb_buffer_t *buffer = c->buffer;
     unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
-    if (likely (index == NOT_COVERED)) return_trace (false);
+    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
 
     hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
     skippy_iter.reset (buffer->idx, 1);
-    if (!skippy_iter.next ()) return_trace (false);
+    if (!skippy_iter.next ()) return TRACE_RETURN (false);
 
-    return_trace ((this+pairSet[index]).apply (c, &valueFormat1, skippy_iter.idx));
+    return TRACE_RETURN ((this+pairSet[index]).apply (c, &valueFormat1, skippy_iter.idx));
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
 
-    if (!c->check_struct (this)) return_trace (false);
-
     unsigned int len1 = valueFormat1.get_len ();
     unsigned int len2 = valueFormat2.get_len ();
     PairSet::sanitize_closure_t closure = {
@@ -726,7 +713,7 @@ struct PairPosFormat1
       1 + len1 + len2
     };
 
-    return_trace (coverage.sanitize (c, this) && pairSet.sanitize (c, this, &closure));
+    return TRACE_RETURN (c->check_struct (this) && coverage.sanitize (c, this) && pairSet.sanitize (c, this, &closure));
   }
 
   protected:
@@ -752,7 +739,7 @@ struct PairPosFormat2
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
     TRACE_COLLECT_GLYPHS (this);
-    (this+coverage).add_coverage (c->input);
+    /* (this+coverage).add_coverage (c->input); // Don't need this. */
 
     unsigned int count1 = class1Count;
     const ClassDef &klass1 = this+classDef1;
@@ -775,11 +762,11 @@ struct PairPosFormat2
     TRACE_APPLY (this);
     hb_buffer_t *buffer = c->buffer;
     unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
-    if (likely (index == NOT_COVERED)) return_trace (false);
+    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
 
     hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
     skippy_iter.reset (buffer->idx, 1);
-    if (!skippy_iter.next ()) return_trace (false);
+    if (!skippy_iter.next ()) return TRACE_RETURN (false);
 
     unsigned int len1 = valueFormat1.get_len ();
     unsigned int len2 = valueFormat2.get_len ();
@@ -787,7 +774,7 @@ struct PairPosFormat2
 
     unsigned int klass1 = (this+classDef1).get_class (buffer->cur().codepoint);
     unsigned int klass2 = (this+classDef2).get_class (buffer->info[skippy_iter.idx].codepoint);
-    if (unlikely (klass1 >= class1Count || klass2 >= class2Count)) return_trace (false);
+    if (unlikely (klass1 >= class1Count || klass2 >= class2Count)) return TRACE_RETURN (false);
 
     const Value *v = &values[record_len * (klass1 * class2Count + klass2)];
     valueFormat1.apply_value (c->font, c->direction, this,
@@ -799,7 +786,7 @@ struct PairPosFormat2
     if (len2)
       buffer->idx++;
 
-    return_trace (true);
+    return TRACE_RETURN (true);
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
@@ -808,16 +795,16 @@ struct PairPosFormat2
     if (!(c->check_struct (this)
        && coverage.sanitize (c, this)
        && classDef1.sanitize (c, this)
-       && classDef2.sanitize (c, this))) return_trace (false);
+       && classDef2.sanitize (c, this))) return TRACE_RETURN (false);
 
     unsigned int len1 = valueFormat1.get_len ();
     unsigned int len2 = valueFormat2.get_len ();
     unsigned int stride = len1 + len2;
     unsigned int record_size = valueFormat1.get_size () + valueFormat2.get_size ();
     unsigned int count = (unsigned int) class1Count * (unsigned int) class2Count;
-    return_trace (c->check_array (values, record_size, count) &&
-                 valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], count, stride) &&
-                 valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride));
+    return TRACE_RETURN (c->check_array (values, record_size, count) &&
+                        valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], count, stride) &&
+                        valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride));
   }
 
   protected:
@@ -856,11 +843,11 @@ struct PairPos
   inline typename context_t::return_t dispatch (context_t *c) const
   {
     TRACE_DISPATCH (this, u.format);
-    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
+    if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
     switch (u.format) {
-    case 1: return_trace (c->dispatch (u.format1));
-    case 2: return_trace (c->dispatch (u.format2));
-    default:return_trace (c->default_return_value ());
+    case 1: return TRACE_RETURN (c->dispatch (u.format1));
+    case 2: return TRACE_RETURN (c->dispatch (u.format2));
+    default:return TRACE_RETURN (c->default_return_value ());
     }
   }
 
@@ -880,7 +867,7 @@ struct EntryExitRecord
   inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
   {
     TRACE_SANITIZE (this);
-    return_trace (entryAnchor.sanitize (c, base) && exitAnchor.sanitize (c, base));
+    return TRACE_RETURN (entryAnchor.sanitize (c, base) && exitAnchor.sanitize (c, base));
   }
 
   protected:
@@ -896,9 +883,6 @@ struct EntryExitRecord
   DEFINE_SIZE_STATIC (4);
 };
 
-static void
-reverse_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction, unsigned int new_parent);
-
 struct CursivePosFormat1
 {
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
@@ -917,15 +901,18 @@ struct CursivePosFormat1
     TRACE_APPLY (this);
     hb_buffer_t *buffer = c->buffer;
 
+    /* We don't handle mark glyphs here. */
+    if (unlikely (_hb_glyph_info_is_mark (&buffer->cur()))) return TRACE_RETURN (false);
+
     const EntryExitRecord &this_record = entryExitRecord[(this+coverage).get_coverage  (buffer->cur().codepoint)];
-    if (!this_record.exitAnchor) return_trace (false);
+    if (!this_record.exitAnchor) return TRACE_RETURN (false);
 
     hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
     skippy_iter.reset (buffer->idx, 1);
-    if (!skippy_iter.next ()) return_trace (false);
+    if (!skippy_iter.next ()) return TRACE_RETURN (false);
 
     const EntryExitRecord &next_record = entryExitRecord[(this+coverage).get_coverage  (buffer->info[skippy_iter.idx].codepoint)];
-    if (!next_record.entryAnchor) return_trace (false);
+    if (!next_record.entryAnchor) return TRACE_RETURN (false);
 
     unsigned int i = buffer->idx;
     unsigned int j = skippy_iter.idx;
@@ -973,49 +960,28 @@ struct CursivePosFormat1
     }
 
     /* Cross-direction adjustment */
-
-    /* We attach child to parent (think graph theory and rooted trees whereas
-     * the root stays on baseline and each node aligns itself against its
-     * parent.
-     *
-     * Optimize things for the case of RightToLeft, as that's most common in
-     * Arabinc. */
-    unsigned int child  = i;
-    unsigned int parent = j;
-    hb_position_t x_offset = entry_x - exit_x;
-    hb_position_t y_offset = entry_y - exit_y;
-    if  (!(c->lookup_props & LookupFlag::RightToLeft))
-    {
-      unsigned int k = child;
-      child = parent;
-      parent = k;
-      x_offset = -x_offset;
-      y_offset = -y_offset;
+    if  (c->lookup_props & LookupFlag::RightToLeft) {
+      pos[i].cursive_chain() = j - i;
+      if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction)))
+       pos[i].y_offset = entry_y - exit_y;
+      else
+       pos[i].x_offset = entry_x - exit_x;
+    } else {
+      pos[j].cursive_chain() = i - j;
+      if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction)))
+       pos[j].y_offset = exit_y - entry_y;
+      else
+       pos[j].x_offset = exit_x - entry_x;
     }
 
-    /* If child was already connected to someone else, walk through its old
-     * chain and reverse the link direction, such that the whole tree of its
-     * previous connection now attaches to new parent.  Watch out for case
-     * where new parent is on the path from old chain...
-     */
-    reverse_cursive_minor_offset (pos, child, c->direction, parent);
-
-    pos[child].attach_type() = ATTACH_TYPE_CURSIVE;
-    pos[child].attach_chain() = (int) parent - (int) child;
-    buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
-    if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction)))
-      pos[child].y_offset = y_offset;
-    else
-      pos[child].x_offset = x_offset;
-
     buffer->idx = j;
-    return_trace (true);
+    return TRACE_RETURN (true);
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (coverage.sanitize (c, this) && entryExitRecord.sanitize (c, this));
+    return TRACE_RETURN (coverage.sanitize (c, this) && entryExitRecord.sanitize (c, this));
   }
 
   protected:
@@ -1036,10 +1002,10 @@ struct CursivePos
   inline typename context_t::return_t dispatch (context_t *c) const
   {
     TRACE_DISPATCH (this, u.format);
-    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
+    if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
     switch (u.format) {
-    case 1: return_trace (c->dispatch (u.format1));
-    default:return_trace (c->default_return_value ());
+    case 1: return TRACE_RETURN (c->dispatch (u.format1));
+    default:return TRACE_RETURN (c->default_return_value ());
     }
   }
 
@@ -1075,36 +1041,33 @@ struct MarkBasePosFormat1
     TRACE_APPLY (this);
     hb_buffer_t *buffer = c->buffer;
     unsigned int mark_index = (this+markCoverage).get_coverage  (buffer->cur().codepoint);
-    if (likely (mark_index == NOT_COVERED)) return_trace (false);
+    if (likely (mark_index == NOT_COVERED)) return TRACE_RETURN (false);
 
-    /* Now we search backwards for a non-mark glyph */
+    /* now we search backwards for a non-mark glyph */
     hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
     skippy_iter.reset (buffer->idx, 1);
     skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
     do {
-      if (!skippy_iter.prev ()) return_trace (false);
+      if (!skippy_iter.prev ()) return TRACE_RETURN (false);
       /* We only want to attach to the first of a MultipleSubst sequence.  Reject others. */
       if (0 == _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx])) break;
       skippy_iter.reject ();
     } while (1);
 
     /* Checking that matched glyph is actually a base glyph by GDEF is too strong; disabled */
-    //if (!_hb_glyph_info_is_base_glyph (&buffer->info[skippy_iter.idx])) { return_trace (false); }
+    if (!_hb_glyph_info_is_base_glyph (&buffer->info[skippy_iter.idx])) { /*return TRACE_RETURN (false);*/ }
 
     unsigned int base_index = (this+baseCoverage).get_coverage  (buffer->info[skippy_iter.idx].codepoint);
-    if (base_index == NOT_COVERED) return_trace (false);
+    if (base_index == NOT_COVERED) return TRACE_RETURN (false);
 
-    return_trace ((this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, skippy_iter.idx));
+    return TRACE_RETURN ((this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, skippy_iter.idx));
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this) &&
-                 markCoverage.sanitize (c, this) &&
-                 baseCoverage.sanitize (c, this) &&
-                 markArray.sanitize (c, this) &&
-                 baseArray.sanitize (c, this, (unsigned int) classCount));
+    return TRACE_RETURN (c->check_struct (this) && markCoverage.sanitize (c, this) && baseCoverage.sanitize (c, this) &&
+                        markArray.sanitize (c, this) && baseArray.sanitize (c, this, (unsigned int) classCount));
   }
 
   protected:
@@ -1132,10 +1095,10 @@ struct MarkBasePos
   inline typename context_t::return_t dispatch (context_t *c) const
   {
     TRACE_DISPATCH (this, u.format);
-    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
+    if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
     switch (u.format) {
-    case 1: return_trace (c->dispatch (u.format1));
-    default:return_trace (c->default_return_value ());
+    case 1: return TRACE_RETURN (c->dispatch (u.format1));
+    default:return TRACE_RETURN (c->default_return_value ());
     }
   }
 
@@ -1176,27 +1139,27 @@ struct MarkLigPosFormat1
     TRACE_APPLY (this);
     hb_buffer_t *buffer = c->buffer;
     unsigned int mark_index = (this+markCoverage).get_coverage  (buffer->cur().codepoint);
-    if (likely (mark_index == NOT_COVERED)) return_trace (false);
+    if (likely (mark_index == NOT_COVERED)) return TRACE_RETURN (false);
 
-    /* Now we search backwards for a non-mark glyph */
+    /* now we search backwards for a non-mark glyph */
     hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
     skippy_iter.reset (buffer->idx, 1);
     skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
-    if (!skippy_iter.prev ()) return_trace (false);
+    if (!skippy_iter.prev ()) return TRACE_RETURN (false);
 
     /* Checking that matched glyph is actually a ligature by GDEF is too strong; disabled */
-    //if (!_hb_glyph_info_is_ligature (&buffer->info[skippy_iter.idx])) { return_trace (false); }
+    if (!_hb_glyph_info_is_ligature (&buffer->info[skippy_iter.idx])) { /*return TRACE_RETURN (false);*/ }
 
     unsigned int j = skippy_iter.idx;
     unsigned int lig_index = (this+ligatureCoverage).get_coverage  (buffer->info[j].codepoint);
-    if (lig_index == NOT_COVERED) return_trace (false);
+    if (lig_index == NOT_COVERED) return TRACE_RETURN (false);
 
     const LigatureArray& lig_array = this+ligatureArray;
     const LigatureAttach& lig_attach = lig_array[lig_index];
 
     /* Find component to attach to */
     unsigned int comp_count = lig_attach.rows;
-    if (unlikely (!comp_count)) return_trace (false);
+    if (unlikely (!comp_count)) return TRACE_RETURN (false);
 
     /* We must now check whether the ligature ID of the current mark glyph
      * is identical to the ligature ID of the found ligature.  If yes, we
@@ -1211,17 +1174,14 @@ struct MarkLigPosFormat1
     else
       comp_index = comp_count - 1;
 
-    return_trace ((this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, j));
+    return TRACE_RETURN ((this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, j));
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this) &&
-                 markCoverage.sanitize (c, this) &&
-                 ligatureCoverage.sanitize (c, this) &&
-                 markArray.sanitize (c, this) &&
-                 ligatureArray.sanitize (c, this, (unsigned int) classCount));
+    return TRACE_RETURN (c->check_struct (this) && markCoverage.sanitize (c, this) && ligatureCoverage.sanitize (c, this) &&
+                        markArray.sanitize (c, this) && ligatureArray.sanitize (c, this, (unsigned int) classCount));
   }
 
   protected:
@@ -1250,10 +1210,10 @@ struct MarkLigPos
   inline typename context_t::return_t dispatch (context_t *c) const
   {
     TRACE_DISPATCH (this, u.format);
-    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
+    if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
     switch (u.format) {
-    case 1: return_trace (c->dispatch (u.format1));
-    default:return_trace (c->default_return_value ());
+    case 1: return TRACE_RETURN (c->dispatch (u.format1));
+    default:return TRACE_RETURN (c->default_return_value ());
     }
   }
 
@@ -1289,15 +1249,15 @@ struct MarkMarkPosFormat1
     TRACE_APPLY (this);
     hb_buffer_t *buffer = c->buffer;
     unsigned int mark1_index = (this+mark1Coverage).get_coverage  (buffer->cur().codepoint);
-    if (likely (mark1_index == NOT_COVERED)) return_trace (false);
+    if (likely (mark1_index == NOT_COVERED)) return TRACE_RETURN (false);
 
     /* now we search backwards for a suitable mark glyph until a non-mark glyph */
     hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
     skippy_iter.reset (buffer->idx, 1);
     skippy_iter.set_lookup_props (c->lookup_props & ~LookupFlag::IgnoreFlags);
-    if (!skippy_iter.prev ()) return_trace (false);
+    if (!skippy_iter.prev ()) return TRACE_RETURN (false);
 
-    if (!_hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx])) { return_trace (false); }
+    if (!_hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx])) { return TRACE_RETURN (false); }
 
     unsigned int j = skippy_iter.idx;
 
@@ -1319,23 +1279,21 @@ struct MarkMarkPosFormat1
     }
 
     /* Didn't match. */
-    return_trace (false);
+    return TRACE_RETURN (false);
 
     good:
     unsigned int mark2_index = (this+mark2Coverage).get_coverage  (buffer->info[j].codepoint);
-    if (mark2_index == NOT_COVERED) return_trace (false);
+    if (mark2_index == NOT_COVERED) return TRACE_RETURN (false);
 
-    return_trace ((this+mark1Array).apply (c, mark1_index, mark2_index, this+mark2Array, classCount, j));
+    return TRACE_RETURN ((this+mark1Array).apply (c, mark1_index, mark2_index, this+mark2Array, classCount, j));
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this) &&
-                 mark1Coverage.sanitize (c, this) &&
-                 mark2Coverage.sanitize (c, this) &&
-                 mark1Array.sanitize (c, this) &&
-                 mark2Array.sanitize (c, this, (unsigned int) classCount));
+    return TRACE_RETURN (c->check_struct (this) && mark1Coverage.sanitize (c, this) &&
+                        mark2Coverage.sanitize (c, this) && mark1Array.sanitize (c, this)
+                        && mark2Array.sanitize (c, this, (unsigned int) classCount));
   }
 
   protected:
@@ -1365,10 +1323,10 @@ struct MarkMarkPos
   inline typename context_t::return_t dispatch (context_t *c) const
   {
     TRACE_DISPATCH (this, u.format);
-    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
+    if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
     switch (u.format) {
-    case 1: return_trace (c->dispatch (u.format1));
-    default:return_trace (c->default_return_value ());
+    case 1: return TRACE_RETURN (c->dispatch (u.format1));
+    default:return TRACE_RETURN (c->default_return_value ());
     }
   }
 
@@ -1416,18 +1374,19 @@ struct PosLookupSubTable
   inline typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const
   {
     TRACE_DISPATCH (this, lookup_type);
-    if (unlikely (!c->may_dispatch (this, &u.sub_format))) return_trace (c->no_dispatch_return_value ());
+    /* The sub_format passed to may_dispatch is unnecessary but harmless. */
+    if (unlikely (!c->may_dispatch (this, &u.sub_format))) TRACE_RETURN (c->default_return_value ());
     switch (lookup_type) {
-    case Single:               return_trace (u.single.dispatch (c));
-    case Pair:                 return_trace (u.pair.dispatch (c));
-    case Cursive:              return_trace (u.cursive.dispatch (c));
-    case MarkBase:             return_trace (u.markBase.dispatch (c));
-    case MarkLig:              return_trace (u.markLig.dispatch (c));
-    case MarkMark:             return_trace (u.markMark.dispatch (c));
-    case Context:              return_trace (u.context.dispatch (c));
-    case ChainContext:         return_trace (u.chainContext.dispatch (c));
-    case Extension:            return_trace (u.extension.dispatch (c));
-    default:                   return_trace (c->default_return_value ());
+    case Single:               return TRACE_RETURN (u.single.dispatch (c));
+    case Pair:                 return TRACE_RETURN (u.pair.dispatch (c));
+    case Cursive:              return TRACE_RETURN (u.cursive.dispatch (c));
+    case MarkBase:             return TRACE_RETURN (u.markBase.dispatch (c));
+    case MarkLig:              return TRACE_RETURN (u.markLig.dispatch (c));
+    case MarkMark:             return TRACE_RETURN (u.markMark.dispatch (c));
+    case Context:              return TRACE_RETURN (u.context.dispatch (c));
+    case ChainContext:         return TRACE_RETURN (u.chainContext.dispatch (c));
+    case Extension:            return TRACE_RETURN (u.extension.dispatch (c));
+    default:                   return TRACE_RETURN (c->default_return_value ());
     }
   }
 
@@ -1462,13 +1421,13 @@ struct PosLookup : Lookup
   inline bool apply (hb_apply_context_t *c) const
   {
     TRACE_APPLY (this);
-    return_trace (dispatch (c));
+    return TRACE_RETURN (dispatch (c));
   }
 
   inline hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
     TRACE_COLLECT_GLYPHS (this);
-    return_trace (dispatch (c));
+    return TRACE_RETURN (dispatch (c));
   }
 
   template <typename set_t>
@@ -1490,8 +1449,9 @@ struct PosLookup : Lookup
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    if (unlikely (!Lookup::sanitize (c))) return_trace (false);
-    return_trace (dispatch (c));
+    if (unlikely (!Lookup::sanitize (c))) return TRACE_RETURN (false);
+    const OffsetArrayOf<PosLookupSubTable> &list = get_subtables<PosLookupSubTable> ();
+    return TRACE_RETURN (dispatch (c));
   }
 };
 
@@ -1509,15 +1469,14 @@ struct GPOS : GSUBGPOS
   { return CastR<PosLookup> (GSUBGPOS::get_lookup (i)); }
 
   static inline void position_start (hb_font_t *font, hb_buffer_t *buffer);
-  static inline void position_finish_advances (hb_font_t *font, hb_buffer_t *buffer);
-  static inline void position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer);
+  static inline void position_finish (hb_font_t *font, hb_buffer_t *buffer);
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    if (unlikely (!GSUBGPOS::sanitize (c))) return_trace (false);
+    if (unlikely (!GSUBGPOS::sanitize (c))) return TRACE_RETURN (false);
     const OffsetTo<PosLookupList> &list = CastR<OffsetTo<PosLookupList> > (lookupList);
-    return_trace (list.sanitize (c, this));
+    return TRACE_RETURN (list.sanitize (c, this));
   }
   public:
   DEFINE_SIZE_STATIC (10);
@@ -1525,89 +1484,59 @@ struct GPOS : GSUBGPOS
 
 
 static void
-reverse_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction, unsigned int new_parent)
+fix_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction)
 {
-  int chain = pos[i].attach_chain(), type = pos[i].attach_type();
-  if (likely (!chain || 0 == (type & ATTACH_TYPE_CURSIVE)))
+  unsigned int j = pos[i].cursive_chain();
+  if (likely (!j))
     return;
 
-  pos[i].attach_chain() = 0;
-
-  unsigned int j = (int) i + chain;
+  j += i;
 
-  /* Stop if we see new parent in the chain. */
-  if (j == new_parent)
-    return;
+  pos[i].cursive_chain() = 0;
 
-  reverse_cursive_minor_offset (pos, j, direction, new_parent);
+  fix_cursive_minor_offset (pos, j, direction);
 
   if (HB_DIRECTION_IS_HORIZONTAL (direction))
-    pos[j].y_offset = -pos[i].y_offset;
+    pos[i].y_offset += pos[j].y_offset;
   else
-    pos[j].x_offset = -pos[i].x_offset;
-
-  pos[j].attach_chain() = -chain;
-  pos[j].attach_type() = type;
+    pos[i].x_offset += pos[j].x_offset;
 }
+
 static void
-propagate_attachment_offsets (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction)
+fix_mark_attachment (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction)
 {
-  /* Adjusts offsets of attached glyphs (both cursive and mark) to accumulate
-   * offset of glyph they are attached to. */
-  int chain = pos[i].attach_chain(), type = pos[i].attach_type();
-  if (likely (!chain))
+  if (likely (!(pos[i].attach_lookback())))
     return;
 
-  unsigned int j = (int) i + chain;
-
-  pos[i].attach_chain() = 0;
+  unsigned int j = i - pos[i].attach_lookback();
 
-  propagate_attachment_offsets (pos, j, direction);
+  pos[i].x_offset += pos[j].x_offset;
+  pos[i].y_offset += pos[j].y_offset;
 
-  assert (!!(type & ATTACH_TYPE_MARK) ^ !!(type & ATTACH_TYPE_CURSIVE));
-
-  if (type & ATTACH_TYPE_CURSIVE)
-  {
-    if (HB_DIRECTION_IS_HORIZONTAL (direction))
-      pos[i].y_offset += pos[j].y_offset;
-    else
-      pos[i].x_offset += pos[j].x_offset;
-  }
-  else /*if (type & ATTACH_TYPE_MARK)*/
-  {
-    pos[i].x_offset += pos[j].x_offset;
-    pos[i].y_offset += pos[j].y_offset;
-
-    assert (j < i);
-    if (HB_DIRECTION_IS_FORWARD (direction))
-      for (unsigned int k = j; k < i; k++) {
-       pos[i].x_offset -= pos[k].x_advance;
-       pos[i].y_offset -= pos[k].y_advance;
-      }
-    else
-      for (unsigned int k = j + 1; k < i + 1; k++) {
-       pos[i].x_offset += pos[k].x_advance;
-       pos[i].y_offset += pos[k].y_advance;
-      }
-  }
+  if (HB_DIRECTION_IS_FORWARD (direction))
+    for (unsigned int k = j; k < i; k++) {
+      pos[i].x_offset -= pos[k].x_advance;
+      pos[i].y_offset -= pos[k].y_advance;
+    }
+  else
+    for (unsigned int k = j + 1; k < i + 1; k++) {
+      pos[i].x_offset += pos[k].x_advance;
+      pos[i].y_offset += pos[k].y_advance;
+    }
 }
 
 void
 GPOS::position_start (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
 {
+  buffer->clear_positions ();
+
   unsigned int count = buffer->len;
   for (unsigned int i = 0; i < count; i++)
-    buffer->pos[i].attach_chain() = buffer->pos[i].attach_type() = 0;
+    buffer->pos[i].attach_lookback() = buffer->pos[i].cursive_chain() = 0;
 }
 
 void
-GPOS::position_finish_advances (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
-{
-  //_hb_buffer_assert_gsubgpos_vars (buffer);
-}
-
-void
-GPOS::position_finish_offsets (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
+GPOS::position_finish (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
 {
   _hb_buffer_assert_gsubgpos_vars (buffer);
 
@@ -1615,10 +1544,13 @@ GPOS::position_finish_offsets (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
   hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, &len);
   hb_direction_t direction = buffer->props.direction;
 
+  /* Handle cursive connections */
+  for (unsigned int i = 0; i < len; i++)
+    fix_cursive_minor_offset (pos, i, direction);
+
   /* Handle attachments */
-  if (buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT)
-    for (unsigned int i = 0; i < len; i++)
-      propagate_attachment_offsets (pos, i, direction);
+  for (unsigned int i = 0; i < len; i++)
+    fix_mark_attachment (pos, i, direction);
 }
 
 
@@ -1637,18 +1569,15 @@ template <typename context_t>
   const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->gpos);
   const PosLookup &l = gpos.get_lookup (lookup_index);
   unsigned int saved_lookup_props = c->lookup_props;
-  unsigned int saved_lookup_index = c->lookup_index;
-  c->set_lookup_index (lookup_index);
-  c->set_lookup_props (l.get_props ());
+  c->set_lookup (l);
   bool ret = l.dispatch (c);
-  c->set_lookup_index (saved_lookup_index);
   c->set_lookup_props (saved_lookup_props);
   return ret;
 }
 
 
-#undef attach_chain
-#undef attach_type
+#undef attach_lookback
+#undef cursive_chain
 
 
 } /* namespace OT */