Merge pull request #131 from simoncozens/docs

Use gtk-doc to build user's manual as well as reference
diff --git a/docs/usermanual-ch03.xml b/docs/usermanual-ch03.xml
index fd63e74..3a26c55 100644
--- a/docs/usermanual-ch03.xml
+++ b/docs/usermanual-ch03.xml
@@ -56,7 +56,7 @@
       Now we have a brand new Harfbuzz buffer. Let's start filling it
       with text! From Harfbuzz's perspective, a buffer is just a stream
       of Unicode codepoints, but your input string is probably in one of
-      the standard Unicode character encodings (UTF-8, UTF-16, UTF-3 )
+      the standard Unicode character encodings (UTF-8, UTF-16, UTF-32)
     </para>
   </section>
   <section id="setting-buffer-properties">
diff --git a/src/hb-object-private.hh b/src/hb-object-private.hh
index 635d62d..6b73ff9 100644
--- a/src/hb-object-private.hh
+++ b/src/hb-object-private.hh
@@ -47,8 +47,9 @@
 
 /* reference_count */
 
-#define HB_REFERENCE_COUNT_INVALID_VALUE -1
-#define HB_REFERENCE_COUNT_INIT {HB_ATOMIC_INT_INIT(HB_REFERENCE_COUNT_INVALID_VALUE)}
+#define HB_REFERENCE_COUNT_INERT_VALUE -1
+#define HB_REFERENCE_COUNT_POISON_VALUE -0x0000DEAD
+#define HB_REFERENCE_COUNT_INIT {HB_ATOMIC_INT_INIT(HB_REFERENCE_COUNT_INERT_VALUE)}
 
 struct hb_reference_count_t
 {
@@ -58,9 +59,10 @@
   inline int get_unsafe (void) const { return ref_count.get_unsafe (); }
   inline int inc (void) { return ref_count.inc (); }
   inline int dec (void) { return ref_count.dec (); }
-  inline void finish (void) { ref_count.set_unsafe (HB_REFERENCE_COUNT_INVALID_VALUE); }
+  inline void finish (void) { ref_count.set_unsafe (HB_REFERENCE_COUNT_POISON_VALUE); }
 
-  inline bool is_invalid (void) const { return ref_count.get_unsafe () == HB_REFERENCE_COUNT_INVALID_VALUE; }
+  inline bool is_inert (void) const { return ref_count.get_unsafe () == HB_REFERENCE_COUNT_INERT_VALUE; }
+  inline bool is_valid (void) const { return ref_count.get_unsafe () > 0; }
 };
 
 
@@ -142,7 +144,12 @@
 template <typename Type>
 static inline bool hb_object_is_inert (const Type *obj)
 {
-  return unlikely (obj->header.ref_count.is_invalid ());
+  return unlikely (obj->header.ref_count.is_inert ());
+}
+template <typename Type>
+static inline bool hb_object_is_valid (const Type *obj)
+{
+  return likely (obj->header.ref_count.is_valid ());
 }
 template <typename Type>
 static inline Type *hb_object_reference (Type *obj)
@@ -150,6 +157,7 @@
   hb_object_trace (obj, HB_FUNC);
   if (unlikely (!obj || hb_object_is_inert (obj)))
     return obj;
+  assert (hb_object_is_valid (obj));
   obj->header.ref_count.inc ();
   return obj;
 }
@@ -159,6 +167,7 @@
   hb_object_trace (obj, HB_FUNC);
   if (unlikely (!obj || hb_object_is_inert (obj)))
     return false;
+  assert (hb_object_is_valid (obj));
   if (obj->header.ref_count.dec () != 1)
     return false;
 
@@ -175,6 +184,7 @@
 {
   if (unlikely (!obj || hb_object_is_inert (obj)))
     return false;
+  assert (hb_object_is_valid (obj));
   return obj->header.user_data.set (key, data, destroy, replace);
 }
 
@@ -184,6 +194,7 @@
 {
   if (unlikely (!obj || hb_object_is_inert (obj)))
     return NULL;
+  assert (hb_object_is_valid (obj));
   return obj->header.user_data.get (key);
 }
 
diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh
index da9506c..996f8b5 100644
--- a/src/hb-ot-layout-gpos-table.hh
+++ b/src/hb-ot-layout-gpos-table.hh
@@ -883,6 +883,9 @@
   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
@@ -960,20 +963,39 @@
     }
 
     /* Cross-direction adjustment */
-    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;
+
+    /* 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 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].cursive_chain() = parent - child;
+    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_RETURN (true);
   }
@@ -1483,6 +1505,30 @@
 
 
 static void
+reverse_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction, unsigned int new_parent)
+{
+  unsigned int j = pos[i].cursive_chain();
+  if (likely (!j))
+    return;
+
+  j += i;
+
+  pos[i].cursive_chain() = 0;
+
+  /* Stop if we see new parent in the chain. */
+  if (j == new_parent)
+    return;
+
+  reverse_cursive_minor_offset (pos, j, direction, new_parent);
+
+  if (HB_DIRECTION_IS_HORIZONTAL (direction))
+    pos[j].y_offset = -pos[i].y_offset;
+  else
+    pos[j].x_offset = -pos[i].x_offset;
+
+  pos[j].cursive_chain() = i - j;
+}
+static void
 fix_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction)
 {
   unsigned int j = pos[i].cursive_chain();
diff --git a/test/api/test-object.c b/test/api/test-object.c
index 4ea6f7c..02b9760 100644
--- a/test/api/test-object.c
+++ b/test/api/test-object.c
@@ -357,10 +357,6 @@
       g_assert (o->get_user_data (obj, &key[0]));
 
       o->destroy (obj);
-      o->destroy (obj);
-      o->destroy (obj);
-      o->destroy (obj);
-      o->destroy (obj);
 
       g_assert (data[0].freed);
     }
diff --git a/test/shaping/Makefile.am b/test/shaping/Makefile.am
index bab3b47..69779b1 100644
--- a/test/shaping/Makefile.am
+++ b/test/shaping/Makefile.am
@@ -40,6 +40,7 @@
 	tests/arabic-feature-order.tests \
 	tests/cluster.tests \
 	tests/context-matching.tests \
+	tests/cursive-positioning.tests \
 	tests/default-ignorables.tests \
 	tests/hangul-jamo.tests \
 	tests/indic-joiner-candrabindu.tests \
diff --git a/test/shaping/fonts/sha1sum/298c9e1d955f10f6f72c6915c3c6ff9bf9695cec.ttf b/test/shaping/fonts/sha1sum/298c9e1d955f10f6f72c6915c3c6ff9bf9695cec.ttf
new file mode 100644
index 0000000..0d677a8
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/298c9e1d955f10f6f72c6915c3c6ff9bf9695cec.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/MANIFEST b/test/shaping/fonts/sha1sum/MANIFEST
index 072911f..1e78f0a 100644
--- a/test/shaping/fonts/sha1sum/MANIFEST
+++ b/test/shaping/fonts/sha1sum/MANIFEST
@@ -2,6 +2,7 @@
 191826b9643e3f124d865d617ae609db6a2ce203.ttf
 226bc2deab3846f1a682085f70c67d0421014144.ttf
 270b89df543a7e48e206a2d830c0e10e5265c630.ttf
+298c9e1d955f10f6f72c6915c3c6ff9bf9695cec.ttf
 37033cc5cf37bb223d7355153016b6ccece93b28.ttf
 4cce528e99f600ed9c25a2b69e32eb94a03b4ae8.ttf
 5028afb650b1bb718ed2131e872fbcce57828fff.ttf
@@ -15,6 +16,7 @@
 a919b33197965846f21074b24e30250d67277bce.ttf
 bb29ce50df2bdba2d10726427c6b7609bf460e04.ttf
 bb9473d2403488714043bcfb946c9f78b86ad627.ttf
+c4e48b0886ef460f532fb49f00047ec92c432ec0.ttf
 d629e7fedc0b350222d7987345fe61613fa3929a.ttf
 df768b9c257e0c9c35786c47cae15c46571d56be.ttf
 e207635780b42f898d58654b65098763e340f5c7.ttf
diff --git a/test/shaping/fonts/sha1sum/c4e48b0886ef460f532fb49f00047ec92c432ec0.ttf b/test/shaping/fonts/sha1sum/c4e48b0886ef460f532fb49f00047ec92c432ec0.ttf
new file mode 100644
index 0000000..99cda16
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/c4e48b0886ef460f532fb49f00047ec92c432ec0.ttf
Binary files differ
diff --git a/test/shaping/tests/MANIFEST b/test/shaping/tests/MANIFEST
index 0d97806..b4ee18e 100644
--- a/test/shaping/tests/MANIFEST
+++ b/test/shaping/tests/MANIFEST
@@ -2,6 +2,7 @@
 arabic-feature-order.tests
 cluster.tests
 context-matching.tests
+cursive-positioning.tests
 default-ignorables.tests
 hangul-jamo.tests
 indic-joiner-candrabindu.tests
diff --git a/test/shaping/tests/cursive-positioning.tests b/test/shaping/tests/cursive-positioning.tests
new file mode 100644
index 0000000..b61d0c1
--- /dev/null
+++ b/test/shaping/tests/cursive-positioning.tests
@@ -0,0 +1,2 @@
+fonts/sha1sum/c4e48b0886ef460f532fb49f00047ec92c432ec0.ttf::U+0643,U+0645,U+0645,U+062B,U+0644:[gid8=4+738|gid5=3@441,1197+0|gid6=3@0,432+405|gid9=2@0,477+452|gid9=1@0,977+452|gid10=0@20,1577+207]
+fonts/sha1sum/298c9e1d955f10f6f72c6915c3c6ff9bf9695cec.ttf::U+0643,U+0645,U+0645,U+062B,U+0644:[gid8=4+738|gid5=3@441,1197+0|gid6=3@0,432+405|gid9=2@0,477+500|gid9=1@0,577+452|gid10=0@20,1177+207]