[HarfBuzz] harfbuzz-ng: Branch 'master' - 6 commits

Behdad Esfahbod behdad at kemper.freedesktop.org
Fri Jul 22 17:23:44 PDT 2011


 src/hb-buffer-private.hh             |  110 ++----
 src/hb-buffer.cc                     |  605 +++++++++++++++++------------------
 src/hb-ot-layout-gpos-private.hh     |   88 ++---
 src/hb-ot-layout-gsub-private.hh     |   58 +--
 src/hb-ot-layout-gsubgpos-private.hh |   50 +-
 src/hb-ot-shape-normalize.cc         |  216 ++++++++++--
 src/hb-ot-shape-private.hh           |   10 
 src/hb-ot-shape.cc                   |   36 --
 8 files changed, 646 insertions(+), 527 deletions(-)

New commits:
commit 5389ff4dbc46c76c9483e3c95f22524b60e21166
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Jul 22 20:22:49 2011 -0400

    Implement the Unicode Canonical Composition algorithm
    
    Fallback normalization is complete and working now!

diff --git a/src/hb-ot-shape-normalize.cc b/src/hb-ot-shape-normalize.cc
index 66afaa6..6f8abb8 100644
--- a/src/hb-ot-shape-normalize.cc
+++ b/src/hb-ot-shape-normalize.cc
@@ -154,11 +154,16 @@ _hb_ot_shape_normalize (hb_ot_shape_context_t *c)
   bool has_multichar_clusters = FALSE;
   unsigned int count;
 
-  buffer->clear_output ();
+  /* We do a farily straightforward yet custom normalization process in three
+   * separate rounds: decompose, reorder, recompose (if desired).  Currently
+   * this makes two buffer swaps.  We can make it faster by moving the last
+   * two rounds into the inner loop for the first round, but it's more readable
+   * this way. */
 
 
   /* First round, decompose */
 
+  buffer->clear_output ();
   count = buffer->len;
   for (buffer->idx = 0; buffer->idx < count;)
   {
@@ -180,7 +185,10 @@ _hb_ot_shape_normalize (hb_ot_shape_context_t *c)
   /* Technically speaking, two characters with ccc=0 may combine.  But all
    * those cases are in languages that the indic module handles (which expects
    * decomposed), or in Hangul jamo, which again, we want decomposed anyway.
-   * So we don't bother combining across cluster boundaries. */
+   * So we don't bother combining across cluster boundaries.
+   *
+   * TODO: Am I right about Hangul?  If I am, we should add a Hangul module
+   * that requests decomposed. */
 
   if (!has_multichar_clusters)
     return; /* Done! */
@@ -231,12 +239,47 @@ _hb_ot_shape_normalize (hb_ot_shape_context_t *c)
   }
 
 
+  if (!recompose)
+    return;
+
   /* Third round, recompose */
 
-  if (recompose) {
+  /* As noted in the comment earlier, we don't try to combine
+   * ccc=0 chars with their previous Starter. */
 
+  buffer->clear_output ();
+  count = buffer->len;
+  unsigned int starter = 0;
+  buffer->next_glyph ();
+  while (buffer->idx < count)
+  {
+    if (buffer->info[buffer->idx].combining_class() == 0) {
+      starter = buffer->out_len;
+      buffer->next_glyph ();
+      continue;
+    }
+
+    hb_codepoint_t composed, glyph;
+    if ((buffer->out_info[buffer->out_len - 1].combining_class() >=
+	 buffer->info[buffer->idx].combining_class()) ||
+	!hb_unicode_compose (c->buffer->unicode,
+			     buffer->out_info[starter].codepoint,
+			     buffer->info[buffer->idx].codepoint,
+			     &composed) ||
+	!hb_font_get_glyph (c->font, composed, 0, &glyph))
+    {
+      /* Blocked, or doesn't compose. */
+      buffer->next_glyph ();
+      continue;
+    }
+
+    /* Composes. Modify starter and carry on. */
+    buffer->out_info[starter].codepoint = composed;
+    hb_glyph_info_set_unicode_props (&buffer->out_info[starter], buffer->unicode);
 
+    buffer->skip_glyph ();
   }
+  buffer->swap_buffers ();
 
 }
 
commit dcdc51cdc0ba9d9fb75f84dd5fa7a49aa0b24ea0
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Jul 22 17:14:46 2011 -0400

    Handle singleton decompositions

diff --git a/src/hb-ot-shape-normalize.cc b/src/hb-ot-shape-normalize.cc
index 040371f..66afaa6 100644
--- a/src/hb-ot-shape-normalize.cc
+++ b/src/hb-ot-shape-normalize.cc
@@ -72,26 +72,28 @@ decompose (hb_ot_shape_context_t *c,
   hb_codepoint_t a, b, glyph;
 
   if (!hb_unicode_decompose (c->buffer->unicode, ab, &a, &b) ||
-      !hb_font_get_glyph (c->font, b, 0, &glyph))
+      (b && !hb_font_get_glyph (c->font, b, 0, &glyph)))
     return FALSE;
 
-  /* XXX handle singleton decompositions */
   bool has_a = hb_font_get_glyph (c->font, a, 0, &glyph);
   if (shortest && has_a) {
     /* Output a and b */
     c->buffer->output_glyph (a);
-    c->buffer->output_glyph (b);
+    if (b)
+      c->buffer->output_glyph (b);
     return TRUE;
   }
 
   if (decompose (c, shortest, a)) {
-    c->buffer->output_glyph (b);
+    if (b)
+      c->buffer->output_glyph (b);
     return TRUE;
   }
 
   if (has_a) {
     c->buffer->output_glyph (a);
-    c->buffer->output_glyph (b);
+    if (b)
+      c->buffer->output_glyph (b);
     return TRUE;
   }
 
commit 34c22f816808d061a980cffca12de03beb437fa0
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Jul 22 17:04:20 2011 -0400

    Implement Unicode Canonical Reordering Algorithm

diff --git a/src/hb-ot-shape-normalize.cc b/src/hb-ot-shape-normalize.cc
index c1baacb..040371f 100644
--- a/src/hb-ot-shape-normalize.cc
+++ b/src/hb-ot-shape-normalize.cc
@@ -98,17 +98,20 @@ decompose (hb_ot_shape_context_t *c,
   return FALSE;
 }
 
-static void
+static bool
 decompose_current_glyph (hb_ot_shape_context_t *c,
 			 bool shortest)
 {
-  if (decompose (c, shortest, c->buffer->info[c->buffer->idx].codepoint))
+  if (decompose (c, shortest, c->buffer->info[c->buffer->idx].codepoint)) {
     c->buffer->skip_glyph ();
-  else
+    return TRUE;
+  } else {
     c->buffer->next_glyph ();
+    return FALSE;
+  }
 }
 
-static void
+static bool
 decompose_single_char_cluster (hb_ot_shape_context_t *c,
 			       bool will_recompose)
 {
@@ -117,23 +120,27 @@ decompose_single_char_cluster (hb_ot_shape_context_t *c,
   /* If recomposing and font supports this, we're good to go */
   if (will_recompose && hb_font_get_glyph (c->font, c->buffer->info[c->buffer->idx].codepoint, 0, &glyph)) {
     c->buffer->next_glyph ();
-    return;
+    return FALSE;
   }
 
-  decompose_current_glyph (c, will_recompose);
+  return decompose_current_glyph (c, will_recompose);
 }
 
-static void
+static bool
 decompose_multi_char_cluster (hb_ot_shape_context_t *c,
 			      unsigned int end)
 {
+  bool changed = FALSE;
+
   /* TODO Currently if there's a variation-selector we give-up, it's just too hard. */
   for (unsigned int i = c->buffer->idx; i < end; i++)
     if (unlikely (is_variation_selector (c->buffer->info[i].codepoint)))
-      return;
+      return changed;
 
   while (c->buffer->idx < end)
-    decompose_current_glyph (c, FALSE);
+    changed |= decompose_current_glyph (c, FALSE);
+
+  return changed;
 }
 
 void
@@ -141,13 +148,16 @@ _hb_ot_shape_normalize (hb_ot_shape_context_t *c)
 {
   hb_buffer_t *buffer = c->buffer;
   bool recompose = !hb_ot_shape_complex_prefer_decomposed (c->plan->shaper);
+  bool changed = FALSE;
   bool has_multichar_clusters = FALSE;
+  unsigned int count;
 
   buffer->clear_output ();
 
+
   /* First round, decompose */
 
-  unsigned int count = buffer->len;
+  count = buffer->len;
   for (buffer->idx = 0; buffer->idx < count;)
   {
     unsigned int end;
@@ -156,14 +166,15 @@ _hb_ot_shape_normalize (hb_ot_shape_context_t *c)
         break;
 
     if (buffer->idx + 1 == end)
-      decompose_single_char_cluster (c, recompose);
+      changed |= decompose_single_char_cluster (c, recompose);
     else {
-      decompose_multi_char_cluster (c, end);
+      changed |= decompose_multi_char_cluster (c, end);
       has_multichar_clusters = TRUE;
     }
   }
   buffer->swap_buffers ();
 
+
   /* Technically speaking, two characters with ccc=0 may combine.  But all
    * those cases are in languages that the indic module handles (which expects
    * decomposed), or in Hangul jamo, which again, we want decomposed anyway.
@@ -172,14 +183,59 @@ _hb_ot_shape_normalize (hb_ot_shape_context_t *c)
   if (!has_multichar_clusters)
     return; /* Done! */
 
+  if (changed)
+    _hb_set_unicode_props (c->buffer); /* BUFFER: Set general_category and combining_class in var1 */
+
+
   /* Second round, reorder (inplace) */
 
+  count = buffer->len;
+  for (unsigned int i = 0; i < count; i++)
+  {
+    if (buffer->info[i].combining_class() == 0)
+      continue;
+
+    unsigned int end;
+    for (end = i + 1; end < count; end++)
+      if (buffer->info[end].combining_class() == 0)
+        break;
+
+    /* We are going to do a bubble-sort.  Only do this if the
+     * sequence is short.  Doing it on long sequences can result
+     * in an O(n^2) DoS. */
+    if (end - i > 10) {
+      i = end;
+      continue;
+    }
+
+    unsigned int k = end - i - 1;
+    do {
+      hb_glyph_info_t *pinfo = buffer->info + i;
+      unsigned int new_k = 0;
+
+      for (unsigned int j = 0; j < k; j++)
+	if (pinfo[j].combining_class() > pinfo[j+1].combining_class()) {
+	  hb_glyph_info_t t;
+	  t = pinfo[j];
+	  pinfo[j] = pinfo[j + 1];
+	  pinfo[j + 1] = t;
+
+	  new_k = j;
+	}
+      k = new_k;
+    } while (k);
+
+    i = end;
+  }
+
 
   /* Third round, recompose */
+
   if (recompose) {
 
 
   }
+
 }
 
 HB_END_DECLS
diff --git a/src/hb-ot-shape-private.hh b/src/hb-ot-shape-private.hh
index 0946820..17f8273 100644
--- a/src/hb-ot-shape-private.hh
+++ b/src/hb-ot-shape-private.hh
@@ -106,6 +106,8 @@ hb_glyph_info_set_unicode_props (hb_glyph_info_t *info, hb_unicode_funcs_t *unic
   info->combining_class() = hb_unicode_combining_class (unicode, info->codepoint);
 }
 
+HB_INTERNAL void _hb_set_unicode_props (hb_buffer_t *buffer);
+
 HB_INTERNAL void _hb_ot_shape_normalize (hb_ot_shape_context_t *c);
 
 HB_END_DECLS
diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc
index 53015cb..929a662 100644
--- a/src/hb-ot-shape.cc
+++ b/src/hb-ot-shape.cc
@@ -176,8 +176,8 @@ hb_ot_position_complex (hb_ot_shape_context_t *c)
 
 /* Prepare */
 
-static void
-hb_set_unicode_props (hb_buffer_t *buffer)
+void
+_hb_set_unicode_props (hb_buffer_t *buffer)
 {
   unsigned int count = buffer->len;
   for (unsigned int i = 1; i < count; i++)
@@ -355,7 +355,7 @@ hb_ot_shape_execute_internal (hb_ot_shape_context_t *c)
 
   hb_reset_glyph_infos (c->buffer); /* BUFFER: Clear buffer var1 and var2 */
 
-  hb_set_unicode_props (c->buffer); /* BUFFER: Set general_category and combining_class in var1 */
+  _hb_set_unicode_props (c->buffer); /* BUFFER: Set general_category and combining_class in var1 */
 
   hb_form_clusters (c->buffer);
 
commit 4ff0d2d9dfc4f7e4880a4e964ca9872624508ea0
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Jul 22 16:15:32 2011 -0400

    Decomposition works now!

diff --git a/src/hb-ot-shape-normalize.cc b/src/hb-ot-shape-normalize.cc
index 0d44d54..c1baacb 100644
--- a/src/hb-ot-shape-normalize.cc
+++ b/src/hb-ot-shape-normalize.cc
@@ -66,65 +66,74 @@ HB_BEGIN_DECLS
 
 static bool
 decompose (hb_ot_shape_context_t *c,
-	   bool recompose,
+	   bool shortest,
 	   hb_codepoint_t ab)
 {
   hb_codepoint_t a, b, glyph;
-  bool has_this = hb_font_get_glyph (c->font, ab, 0, &glyph);
 
-  /* If recomposing and the single char is supported by the font, we're good. */
-  if (recompose && has_this)
-    return TRUE;
-
-  if (hb_unicode_decompose (c->buffer->unicode, ab, &a, &b) &&
-      hb_font_get_glyph (c->font, b, 0, &glyph) &&
-      decompose (c, recompose, a))
-  {
-    /* Successfully decomposed. */
+  if (!hb_unicode_decompose (c->buffer->unicode, ab, &a, &b) ||
+      !hb_font_get_glyph (c->font, b, 0, &glyph))
+    return FALSE;
 
-    if (recompose) {
-      /* Try composing b with base if not blocked */
+  /* XXX handle singleton decompositions */
+  bool has_a = hb_font_get_glyph (c->font, a, 0, &glyph);
+  if (shortest && has_a) {
+    /* Output a and b */
+    c->buffer->output_glyph (a);
+    c->buffer->output_glyph (b);
+    return TRUE;
+  }
 
-    }
+  if (decompose (c, shortest, a)) {
+    c->buffer->output_glyph (b);
+    return TRUE;
+  }
 
+  if (has_a) {
+    c->buffer->output_glyph (a);
+    c->buffer->output_glyph (b);
     return TRUE;
   }
 
-  return has_this;
+  return FALSE;
 }
 
-static bool
-decompose_single_char_cluster (hb_ot_shape_context_t *c,
-			       bool recompose,
-			       unsigned int i)
+static void
+decompose_current_glyph (hb_ot_shape_context_t *c,
+			 bool shortest)
 {
-//  c->buffer->copy ();
-//  bool ret = decompose (c, recompose, c->buffer->info[i].codepoint);
-//  c->buffer->skip ();
-//  return ret;
-  return FALSE;
+  if (decompose (c, shortest, c->buffer->info[c->buffer->idx].codepoint))
+    c->buffer->skip_glyph ();
+  else
+    c->buffer->next_glyph ();
 }
 
 static void
-handle_single_char_cluster (hb_ot_shape_context_t *c,
-			    bool recompose,
-			    unsigned int i)
+decompose_single_char_cluster (hb_ot_shape_context_t *c,
+			       bool will_recompose)
 {
-  /* Decompose */
-  decompose_single_char_cluster (c, recompose, i);
+  hb_codepoint_t glyph;
+
+  /* If recomposing and font supports this, we're good to go */
+  if (will_recompose && hb_font_get_glyph (c->font, c->buffer->info[c->buffer->idx].codepoint, 0, &glyph)) {
+    c->buffer->next_glyph ();
+    return;
+  }
+
+  decompose_current_glyph (c, will_recompose);
 }
 
 static void
-handle_multi_char_cluster (hb_ot_shape_context_t *c,
-			   bool recompose,
-			   unsigned int start,
-			   unsigned int end)
+decompose_multi_char_cluster (hb_ot_shape_context_t *c,
+			      unsigned int end)
 {
   /* TODO Currently if there's a variation-selector we give-up, it's just too hard. */
-  for (unsigned int i = start; i < end; i++)
+  for (unsigned int i = c->buffer->idx; i < end; i++)
     if (unlikely (is_variation_selector (c->buffer->info[i].codepoint)))
       return;
 
+  while (c->buffer->idx < end)
+    decompose_current_glyph (c, FALSE);
 }
 
 void
@@ -132,27 +141,45 @@ _hb_ot_shape_normalize (hb_ot_shape_context_t *c)
 {
   hb_buffer_t *buffer = c->buffer;
   bool recompose = !hb_ot_shape_complex_prefer_decomposed (c->plan->shaper);
+  bool has_multichar_clusters = FALSE;
 
   buffer->clear_output ();
 
+  /* First round, decompose */
+
   unsigned int count = buffer->len;
   for (buffer->idx = 0; buffer->idx < count;)
   {
-
     unsigned int end;
     for (end = buffer->idx + 1; end < count; end++)
       if (buffer->info[buffer->idx].cluster != buffer->info[end].cluster)
         break;
 
     if (buffer->idx + 1 == end)
-      handle_single_char_cluster (c, recompose, buffer->idx);
-    else
-      handle_multi_char_cluster (c, recompose, buffer->idx, end);
-    while (buffer->idx < end)
-      c->buffer->next_glyph ();
+      decompose_single_char_cluster (c, recompose);
+    else {
+      decompose_multi_char_cluster (c, end);
+      has_multichar_clusters = TRUE;
+    }
   }
-
   buffer->swap_buffers ();
+
+  /* Technically speaking, two characters with ccc=0 may combine.  But all
+   * those cases are in languages that the indic module handles (which expects
+   * decomposed), or in Hangul jamo, which again, we want decomposed anyway.
+   * So we don't bother combining across cluster boundaries. */
+
+  if (!has_multichar_clusters)
+    return; /* Done! */
+
+  /* Second round, reorder (inplace) */
+
+
+  /* Third round, recompose */
+  if (recompose) {
+
+
+  }
 }
 
 HB_END_DECLS
diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc
index 05348d3..53015cb 100644
--- a/src/hb-ot-shape.cc
+++ b/src/hb-ot-shape.cc
@@ -208,7 +208,6 @@ hb_ensure_native_direction (hb_buffer_t *buffer)
   if ((HB_DIRECTION_IS_HORIZONTAL (direction) && direction != hb_script_get_horizontal_direction (buffer->props.script)) ||
       (HB_DIRECTION_IS_VERTICAL   (direction) && direction != HB_DIRECTION_TTB))
   {
-    hb_form_clusters (buffer);
     hb_buffer_reverse_clusters (buffer);
     buffer->props.direction = HB_DIRECTION_REVERSE (buffer->props.direction);
   }
@@ -358,6 +357,8 @@ hb_ot_shape_execute_internal (hb_ot_shape_context_t *c)
 
   hb_set_unicode_props (c->buffer); /* BUFFER: Set general_category and combining_class in var1 */
 
+  hb_form_clusters (c->buffer);
+
   hb_ensure_native_direction (c->buffer);
 
   _hb_ot_shape_normalize (c);
commit 468e9cb25c9bc14781b7013e447d763f93bf76a3
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Jul 22 11:28:07 2011 -0400

    Move buffer methods into the object

diff --git a/src/hb-buffer-private.hh b/src/hb-buffer-private.hh
index 73535d4..f544c82 100644
--- a/src/hb-buffer-private.hh
+++ b/src/hb-buffer-private.hh
@@ -1,6 +1,7 @@
 /*
  * Copyright © 1998-2004  David Turner and Werner Lemberg
  * Copyright © 2004,2007,2009,2010  Red Hat, Inc.
+ * Copyright © 2011  Google, Inc.
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
@@ -23,6 +24,7 @@
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  *
  * Red Hat Author(s): Owen Taylor, Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod
  */
 
 #ifndef HB_BUFFER_PRIVATE_HH
@@ -46,52 +48,6 @@ typedef struct _hb_segment_properties_t {
 } hb_segment_properties_t;
 
 
-HB_INTERNAL void
-_hb_buffer_swap (hb_buffer_t *buffer);
-
-HB_INTERNAL void
-_hb_buffer_clear_output (hb_buffer_t *buffer);
-
-HB_INTERNAL void
-_hb_buffer_clear_positions (hb_buffer_t *buffer);
-
-HB_INTERNAL void
-_hb_buffer_replace_glyphs_be16 (hb_buffer_t *buffer,
-				unsigned int num_in,
-				unsigned int num_out,
-				const uint16_t *glyph_data_be);
-
-HB_INTERNAL void
-_hb_buffer_replace_glyph (hb_buffer_t *buffer,
-			  hb_codepoint_t glyph_index);
-
-HB_INTERNAL void
-_hb_buffer_output_glyph (hb_buffer_t *buffer,
-			 hb_codepoint_t glyph_index);
-
-HB_INTERNAL void
-_hb_buffer_skip_glyph (hb_buffer_t *buffer);
-
-HB_INTERNAL void
-_hb_buffer_next_glyph (hb_buffer_t *buffer);
-
-
-HB_INTERNAL void
-_hb_buffer_reset_masks (hb_buffer_t *buffer,
-			hb_mask_t    mask);
-
-HB_INTERNAL void
-_hb_buffer_add_masks (hb_buffer_t *buffer,
-		      hb_mask_t    mask);
-
-HB_INTERNAL void
-_hb_buffer_set_masks (hb_buffer_t *buffer,
-		      hb_mask_t    value,
-		      hb_mask_t    mask,
-		      unsigned int cluster_start,
-		      unsigned int cluster_end);
-
-
 struct _hb_buffer_t {
   hb_object_header_t header;
 
@@ -106,7 +62,7 @@ struct _hb_buffer_t {
   bool have_output; /* Whether we have an output buffer going on */
   bool have_positions; /* Whether we have positions */
 
-  unsigned int i; /* Cursor into ->info and ->pos arrays */
+  unsigned int idx; /* Cursor into ->info and ->pos arrays */
   unsigned int len; /* Length of ->info and ->pos arrays */
   unsigned int out_len; /* Length of ->out array if have_output */
 
@@ -119,22 +75,37 @@ struct _hb_buffer_t {
 
 
   /* Methods */
+
+  HB_INTERNAL void reset (void);
+
   inline unsigned int backtrack_len (void) const
-  { return this->have_output? this->out_len : this->i; }
+  { return have_output? out_len : idx; }
   inline unsigned int next_serial (void) { return serial++; }
-  inline void swap (void) { _hb_buffer_swap (this); }
-  inline void clear_output (void) { _hb_buffer_clear_output (this); }
-  inline void clear_positions (void) { _hb_buffer_clear_positions (this); }
-  inline void next_glyph (void) { _hb_buffer_next_glyph (this); }
-  inline void replace_glyphs_be16 (unsigned int num_in,
-				   unsigned int num_out,
-				   const uint16_t *glyph_data_be)
-  { _hb_buffer_replace_glyphs_be16 (this, num_in, num_out, glyph_data_be); }
-  inline void replace_glyph (hb_codepoint_t glyph_index)
-  { _hb_buffer_replace_glyph (this, glyph_index); }
-  inline void output_glyph (hb_codepoint_t glyph_index)
-  { _hb_buffer_output_glyph (this, glyph_index); }
-  inline void skip_glyph (void) { _hb_buffer_skip_glyph (this); }
+
+  HB_INTERNAL void add (hb_codepoint_t  codepoint,
+			hb_mask_t       mask,
+			unsigned int    cluster);
+
+  HB_INTERNAL void reverse_range (unsigned int start, unsigned int end);
+  HB_INTERNAL void reverse (void);
+  HB_INTERNAL void reverse_clusters (void);
+
+  HB_INTERNAL void swap_buffers (void);
+  HB_INTERNAL void clear_output (void);
+  HB_INTERNAL void clear_positions (void);
+  HB_INTERNAL void replace_glyphs_be16 (unsigned int num_in,
+					unsigned int num_out,
+					const uint16_t *glyph_data_be);
+  HB_INTERNAL void replace_glyph (hb_codepoint_t glyph_index);
+  /* Makes a copy of the glyph at idx to output and replace glyph_index */
+  HB_INTERNAL void output_glyph (hb_codepoint_t glyph_index);
+  /* Copies glyph at idx to output but doesn't advance idx */
+  HB_INTERNAL void copy_glyph (void);
+  /* Copies glyph at idx to output and advance idx.
+   * If there's no output, just advance idx. */
+  HB_INTERNAL void next_glyph (void);
+  /* Advance idx without copying to output. */
+  inline void skip_glyph (void) { idx++; }
 
   inline void reset_masks (hb_mask_t mask)
   {
@@ -146,11 +117,18 @@ struct _hb_buffer_t {
     for (unsigned int j = 0; j < len; j++)
       info[j].mask |= mask;
   }
-  inline void set_masks (hb_mask_t value,
-			 hb_mask_t mask,
-			 unsigned int cluster_start,
-			 unsigned int cluster_end)
-  { _hb_buffer_set_masks (this, value, mask, cluster_start, cluster_end); }
+  HB_INTERNAL void set_masks (hb_mask_t value,
+			      hb_mask_t mask,
+			      unsigned int cluster_start,
+			      unsigned int cluster_end);
+
+  /* Internal methods */
+  HB_INTERNAL bool enlarge (unsigned int size);
+
+  inline bool ensure (unsigned int size)
+  { return likely (size <= allocated) ? TRUE : enlarge (size); }
+
+  HB_INTERNAL bool make_room_for (unsigned int num_in, unsigned int num_out);
 };
 
 
diff --git a/src/hb-buffer.cc b/src/hb-buffer.cc
index 174d8e8..716f858 100644
--- a/src/hb-buffer.cc
+++ b/src/hb-buffer.cc
@@ -34,7 +34,7 @@
 HB_BEGIN_DECLS
 
 
-static hb_buffer_t _hb_buffer_nil = {
+static hb_buffer_t Xhb_buffer_nil = {
   HB_OBJECT_HEADER_STATIC,
 
   &_hb_unicode_funcs_default,
@@ -57,78 +57,333 @@ static hb_buffer_t _hb_buffer_nil = {
  * As an optimization, both info and out_info may point to the
  * same piece of memory, which is owned by info.  This remains the
  * case as long as out_len doesn't exceed i at any time.
- * In that case, swap() is no-op and the glyph operations operate
+ * In that case, swap_buffers() is no-op and the glyph operations operate
  * mostly in-place.
  *
  * As soon as out_info gets longer than info, out_info is moved over
  * to an alternate buffer (which we reuse the pos buffer for!), and its
  * current contents (out_len entries) are copied to the new place.
- * This should all remain transparent to the user.  swap() then
+ * This should all remain transparent to the user.  swap_buffers() then
  * switches info and out_info.
  */
 
 
-static hb_bool_t
-_hb_buffer_enlarge (hb_buffer_t *buffer, unsigned int size)
+
+/* Internal API */
+
+bool
+hb_buffer_t::enlarge (unsigned int size)
 {
-  if (unlikely (buffer->in_error))
+  if (unlikely (in_error))
     return FALSE;
 
-  unsigned int new_allocated = buffer->allocated;
+  unsigned int new_allocated = allocated;
   hb_glyph_position_t *new_pos = NULL;
   hb_glyph_info_t *new_info = NULL;
-  bool separate_out = buffer->out_info != buffer->info;
+  bool separate_out = out_info != info;
 
-  if (unlikely (_hb_unsigned_int_mul_overflows (size, sizeof (buffer->info[0]))))
+  if (unlikely (_hb_unsigned_int_mul_overflows (size, sizeof (info[0]))))
     goto done;
 
   while (size > new_allocated)
     new_allocated += (new_allocated >> 1) + 32;
 
-  ASSERT_STATIC (sizeof (buffer->info[0]) == sizeof (buffer->pos[0]));
-  if (unlikely (_hb_unsigned_int_mul_overflows (new_allocated, sizeof (buffer->info[0]))))
+  ASSERT_STATIC (sizeof (info[0]) == sizeof (pos[0]));
+  if (unlikely (_hb_unsigned_int_mul_overflows (new_allocated, sizeof (info[0]))))
     goto done;
 
-  new_pos = (hb_glyph_position_t *) realloc (buffer->pos, new_allocated * sizeof (buffer->pos[0]));
-  new_info = (hb_glyph_info_t *) realloc (buffer->info, new_allocated * sizeof (buffer->info[0]));
+  new_pos = (hb_glyph_position_t *) realloc (pos, new_allocated * sizeof (pos[0]));
+  new_info = (hb_glyph_info_t *) realloc (info, new_allocated * sizeof (info[0]));
 
 done:
   if (unlikely (!new_pos || !new_info))
-    buffer->in_error = TRUE;
+    in_error = TRUE;
 
   if (likely (new_pos))
-    buffer->pos = new_pos;
+    pos = new_pos;
 
   if (likely (new_info))
-    buffer->info = new_info;
+    info = new_info;
+
+  out_info = separate_out ? (hb_glyph_info_t *) pos : info;
+  if (likely (!in_error))
+    allocated = new_allocated;
+
+  return likely (!in_error);
+}
+
+bool
+hb_buffer_t::make_room_for (unsigned int num_in,
+			    unsigned int num_out)
+{
+  if (unlikely (!ensure (out_len + num_out))) return FALSE;
+
+  if (out_info == info &&
+      out_len + num_out > idx + num_in)
+  {
+    assert (have_output);
+
+    out_info = (hb_glyph_info_t *) pos;
+    memcpy (out_info, info, out_len * sizeof (out_info[0]));
+  }
+
+  return TRUE;
+}
+
+
+/* HarfBuzz-Internal API */
+
+void
+hb_buffer_t::reset (void)
+{
+  if (unlikely (hb_object_is_inert (this)))
+    return;
+
+  hb_unicode_funcs_destroy (unicode);
+  unicode = Xhb_buffer_nil.unicode;
+
+  props = Xhb_buffer_nil.props;
+
+  in_error = FALSE;
+  have_output = FALSE;
+  have_positions = FALSE;
 
-  buffer->out_info = separate_out ? (hb_glyph_info_t *) buffer->pos : buffer->info;
-  if (likely (!buffer->in_error))
-    buffer->allocated = new_allocated;
+  idx = 0;
+  len = 0;
+  out_len = 0;
 
-  return likely (!buffer->in_error);
+  serial = 0;
+
+  out_info = info;
 }
 
-static inline hb_bool_t
-_hb_buffer_ensure (hb_buffer_t *buffer, unsigned int size)
+void
+hb_buffer_t::add (hb_codepoint_t  codepoint,
+		  hb_mask_t       mask,
+		  unsigned int    cluster)
 {
-  return likely (size <= buffer->allocated) ? TRUE : _hb_buffer_enlarge (buffer, size);
+  hb_glyph_info_t *glyph;
+
+  if (unlikely (!ensure (len + 1))) return;
+
+  glyph = &info[len];
+
+  memset (glyph, 0, sizeof (*glyph));
+  glyph->codepoint = codepoint;
+  glyph->mask = mask;
+  glyph->cluster = cluster;
+
+  len++;
 }
 
-static inline hb_bool_t
-_hb_buffer_ensure_separate (hb_buffer_t *buffer, unsigned int size)
+void
+hb_buffer_t::clear_output (void)
 {
-  if (unlikely (!size || !_hb_buffer_ensure (buffer, size))) return FALSE;
+  if (unlikely (hb_object_is_inert (this)))
+    return;
+
+  have_output = TRUE;
+  have_positions = FALSE;
 
-  if (buffer->out_info == buffer->info)
+  out_len = 0;
+  out_info = info;
+}
+
+void
+hb_buffer_t::clear_positions (void)
+{
+  if (unlikely (hb_object_is_inert (this)))
+    return;
+
+  have_output = FALSE;
+  have_positions = TRUE;
+
+  memset (pos, 0, sizeof (pos[0]) * len);
+}
+
+void
+hb_buffer_t::swap_buffers (void)
+{
+  if (unlikely (in_error)) return;
+
+  assert (have_output);
+
+  if (out_info != info)
   {
-    assert (buffer->have_output);
+    hb_glyph_info_t *tmp_string;
+    tmp_string = info;
+    info = out_info;
+    out_info = tmp_string;
+    pos = (hb_glyph_position_t *) out_info;
+  }
+
+  unsigned int tmp;
+  tmp = len;
+  len = out_len;
+  out_len = tmp;
+
+  idx = 0;
+}
 
-    buffer->out_info = (hb_glyph_info_t *) buffer->pos;
-    memcpy (buffer->out_info, buffer->info, buffer->out_len * sizeof (buffer->out_info[0]));
+void
+hb_buffer_t::replace_glyphs_be16 (unsigned int num_in,
+				  unsigned int num_out,
+				  const uint16_t *glyph_data_be)
+{
+  if (!make_room_for (num_in, num_out)) return;
+
+  hb_glyph_info_t orig_info = info[idx];
+  for (unsigned int i = 1; i < num_in; i++)
+  {
+    hb_glyph_info_t *inf = &info[idx + i];
+    orig_info.cluster = MIN (orig_info.cluster, inf->cluster);
   }
 
-  return TRUE;
+  hb_glyph_info_t *pinfo = &out_info[out_len];
+  for (unsigned int i = 0; i < num_out; i++)
+  {
+    *pinfo = orig_info;
+    pinfo->codepoint = hb_be_uint16 (glyph_data_be[i]);
+    pinfo++;
+  }
+
+  idx  += num_in;
+  out_len += num_out;
+}
+
+void
+hb_buffer_t::output_glyph (hb_codepoint_t glyph_index)
+{
+  if (!make_room_for (0, 1)) return;
+
+  out_info[out_len] = info[idx];
+  out_info[out_len].codepoint = glyph_index;
+
+  out_len++;
+}
+
+void
+hb_buffer_t::copy_glyph (void)
+{
+  if (!make_room_for (0, 1)) return;
+
+  out_info[out_len] = info[idx];
+
+  out_len++;
+}
+
+void
+hb_buffer_t::replace_glyph (hb_codepoint_t glyph_index)
+{
+  out_info[out_len] = info[idx];
+  out_info[out_len].codepoint = glyph_index;
+
+  idx++;
+  out_len++;
+}
+
+void
+hb_buffer_t::next_glyph (void)
+{
+  if (have_output)
+  {
+    if (out_info != info)
+    {
+      if (unlikely (!ensure (out_len + 1))) return;
+      out_info[out_len] = info[idx];
+    }
+    else if (out_len != idx)
+      out_info[out_len] = info[idx];
+
+    out_len++;
+  }
+
+  idx++;
+}
+
+void
+hb_buffer_t::set_masks (hb_mask_t    value,
+			hb_mask_t    mask,
+			unsigned int cluster_start,
+			unsigned int cluster_end)
+{
+  hb_mask_t not_mask = ~mask;
+  value &= mask;
+
+  if (!mask)
+    return;
+
+  if (cluster_start == 0 && cluster_end == (unsigned int)-1) {
+    unsigned int count = len;
+    for (unsigned int i = 0; i < count; i++)
+      info[i].mask = (info[i].mask & not_mask) | value;
+    return;
+  }
+
+  unsigned int count = len;
+  for (unsigned int i = 0; i < count; i++)
+    if (cluster_start <= info[i].cluster && info[i].cluster < cluster_end)
+      info[i].mask = (info[i].mask & not_mask) | value;
+}
+
+void
+hb_buffer_t::reverse_range (unsigned int start,
+			    unsigned int end)
+{
+  unsigned int i, j;
+
+  if (start == end - 1)
+    return;
+
+  for (i = start, j = end - 1; i < j; i++, j--) {
+    hb_glyph_info_t t;
+
+    t = info[i];
+    info[i] = info[j];
+    info[j] = t;
+  }
+
+  if (pos) {
+    for (i = start, j = end - 1; i < j; i++, j--) {
+      hb_glyph_position_t t;
+
+      t = pos[i];
+      pos[i] = pos[j];
+      pos[j] = t;
+    }
+  }
+}
+
+void
+hb_buffer_t::reverse (void)
+{
+  if (unlikely (!len))
+    return;
+
+  reverse_range (0, len);
+}
+
+void
+hb_buffer_t::reverse_clusters (void)
+{
+  unsigned int i, start, count, last_cluster;
+
+  if (unlikely (!len))
+    return;
+
+  reverse ();
+
+  count = len;
+  start = 0;
+  last_cluster = info[0].cluster;
+  for (i = 1; i < count; i++) {
+    if (last_cluster != info[i].cluster) {
+      reverse_range (start, i);
+      start = i;
+      last_cluster = info[i].cluster;
+    }
+  }
+  reverse_range (start, i);
 }
 
 
@@ -140,13 +395,13 @@ hb_buffer_create (unsigned int pre_alloc_size)
   hb_buffer_t *buffer;
 
   if (!(buffer = hb_object_create<hb_buffer_t> ()))
-    return &_hb_buffer_nil;
+    return &Xhb_buffer_nil;
 
-  hb_buffer_reset (buffer);
+  buffer->reset ();
 
-  if (pre_alloc_size && !_hb_buffer_ensure (buffer, pre_alloc_size)) {
+  if (pre_alloc_size && !buffer->ensure (pre_alloc_size)) {
     hb_buffer_destroy (buffer);
-    return &_hb_buffer_nil;
+    return &Xhb_buffer_nil;
   }
 
   return buffer;
@@ -155,7 +410,7 @@ hb_buffer_create (unsigned int pre_alloc_size)
 hb_buffer_t *
 hb_buffer_get_empty (void)
 {
-  return &_hb_buffer_nil;
+  return &Xhb_buffer_nil;
 }
 
 hb_buffer_t *
@@ -202,7 +457,7 @@ hb_buffer_set_unicode_funcs (hb_buffer_t        *buffer,
     return;
 
   if (!unicode)
-    unicode = _hb_buffer_nil.unicode;
+    unicode = Xhb_buffer_nil.unicode;
 
   hb_unicode_funcs_reference (unicode);
   hb_unicode_funcs_destroy (buffer->unicode);
@@ -268,31 +523,13 @@ hb_buffer_get_language (hb_buffer_t *buffer)
 void
 hb_buffer_reset (hb_buffer_t *buffer)
 {
-  if (unlikely (hb_object_is_inert (buffer)))
-    return;
-
-  hb_unicode_funcs_destroy (buffer->unicode);
-  buffer->unicode = _hb_buffer_nil.unicode;
-
-  buffer->props = _hb_buffer_nil.props;
-
-  buffer->in_error = FALSE;
-  buffer->have_output = FALSE;
-  buffer->have_positions = FALSE;
-
-  buffer->i = 0;
-  buffer->len = 0;
-  buffer->out_len = 0;
-
-  buffer->serial = 0;
-
-  buffer->out_info = buffer->info;
+  buffer->reset ();
 }
 
 hb_bool_t
 hb_buffer_pre_allocate (hb_buffer_t *buffer, unsigned int size)
 {
-  return _hb_buffer_ensure (buffer, size);
+  return buffer->ensure (size);
 }
 
 hb_bool_t
@@ -307,207 +544,14 @@ hb_buffer_add (hb_buffer_t    *buffer,
 	       hb_mask_t       mask,
 	       unsigned int    cluster)
 {
-  hb_glyph_info_t *glyph;
-
-  if (unlikely (!_hb_buffer_ensure (buffer, buffer->len + 1))) return;
-
-  glyph = &buffer->info[buffer->len];
-
-  memset (glyph, 0, sizeof (*glyph));
-  glyph->codepoint = codepoint;
-  glyph->mask = mask;
-  glyph->cluster = cluster;
-
-  buffer->len++;
-}
-
-/* HarfBuzz-Internal API */
-
-void
-_hb_buffer_clear_output (hb_buffer_t *buffer)
-{
-  if (unlikely (hb_object_is_inert (buffer)))
-    return;
-
-  buffer->have_output = TRUE;
-  buffer->have_positions = FALSE;
-
-  buffer->out_len = 0;
-  buffer->out_info = buffer->info;
-}
-
-void
-_hb_buffer_clear_positions (hb_buffer_t *buffer)
-{
-  if (unlikely (hb_object_is_inert (buffer)))
-    return;
-
-  buffer->have_output = FALSE;
-  buffer->have_positions = TRUE;
-
-  memset (buffer->pos, 0, sizeof (buffer->pos[0]) * buffer->len);
-}
-
-void
-_hb_buffer_swap (hb_buffer_t *buffer)
-{
-  if (unlikely (buffer->in_error)) return;
-
-  assert (buffer->have_output);
-
-  if (buffer->out_info != buffer->info)
-  {
-    hb_glyph_info_t *tmp_string;
-    tmp_string = buffer->info;
-    buffer->info = buffer->out_info;
-    buffer->out_info = tmp_string;
-    buffer->pos = (hb_glyph_position_t *) buffer->out_info;
-  }
-
-  unsigned int tmp;
-  tmp = buffer->len;
-  buffer->len = buffer->out_len;
-  buffer->out_len = tmp;
-
-  buffer->i = 0;
-}
-
-void
-_hb_buffer_replace_glyphs_be16 (hb_buffer_t *buffer,
-				unsigned int num_in,
-				unsigned int num_out,
-				const uint16_t *glyph_data_be)
-{
-  if (buffer->out_info != buffer->info ||
-      buffer->out_len + num_out > buffer->i + num_in)
-  {
-    if (unlikely (!_hb_buffer_ensure_separate (buffer, buffer->out_len + num_out)))
-      return;
-  }
-
-  hb_glyph_info_t orig_info = buffer->info[buffer->i];
-  for (unsigned int i = 1; i < num_in; i++)
-  {
-    hb_glyph_info_t *info = &buffer->info[buffer->i + i];
-    orig_info.cluster = MIN (orig_info.cluster, info->cluster);
-  }
-
-  for (unsigned int i = 0; i < num_out; i++)
-  {
-    hb_glyph_info_t *info = &buffer->out_info[buffer->out_len + i];
-    *info = orig_info;
-    info->codepoint = hb_be_uint16 (glyph_data_be[i]);
-  }
-
-  buffer->i  += num_in;
-  buffer->out_len += num_out;
-}
-
-void
-_hb_buffer_output_glyph (hb_buffer_t *buffer,
-			 hb_codepoint_t glyph_index)
-{
-  hb_glyph_info_t *info;
-
-  if (buffer->out_info != buffer->info)
-  {
-    if (unlikely (!_hb_buffer_ensure (buffer, buffer->out_len + 1))) return;
-    buffer->out_info[buffer->out_len] = buffer->info[buffer->i];
-  }
-  else if (buffer->out_len != buffer->i)
-    buffer->out_info[buffer->out_len] = buffer->info[buffer->i];
-
-  info = &buffer->out_info[buffer->out_len];
-  info->codepoint = glyph_index;
-
-  buffer->out_len++;
-}
-
-void
-_hb_buffer_replace_glyph (hb_buffer_t *buffer,
-			  hb_codepoint_t glyph_index)
-{
-  _hb_buffer_output_glyph (buffer, glyph_index);
-  _hb_buffer_skip_glyph (buffer);
+  buffer->add (codepoint, mask, cluster);
 }
 
-void
-_hb_buffer_skip_glyph (hb_buffer_t *buffer)
-{
-  buffer->i++;
-}
-
-void
-_hb_buffer_next_glyph (hb_buffer_t *buffer)
-{
-  if (buffer->have_output)
-  {
-    if (buffer->out_info != buffer->info)
-    {
-      if (unlikely (!_hb_buffer_ensure (buffer, buffer->out_len + 1))) return;
-      buffer->out_info[buffer->out_len] = buffer->info[buffer->i];
-    }
-    else if (buffer->out_len != buffer->i)
-      buffer->out_info[buffer->out_len] = buffer->info[buffer->i];
-
-    buffer->out_len++;
-  }
-
-  buffer->i++;
-}
-
-void
-_hb_buffer_reset_masks (hb_buffer_t *buffer,
-			hb_mask_t    mask)
-{
-  unsigned int count = buffer->len;
-  for (unsigned int i = 0; i < count; i++)
-    buffer->info[i].mask = mask;
-}
-
-void
-_hb_buffer_add_masks (hb_buffer_t *buffer,
-		      hb_mask_t    mask)
-{
-  unsigned int count = buffer->len;
-  for (unsigned int i = 0; i < count; i++)
-    buffer->info[i].mask |= mask;
-}
-
-void
-_hb_buffer_set_masks (hb_buffer_t *buffer,
-		      hb_mask_t    value,
-		      hb_mask_t    mask,
-		      unsigned int cluster_start,
-		      unsigned int cluster_end)
-{
-  hb_mask_t not_mask = ~mask;
-  value &= mask;
-
-  if (!mask)
-    return;
-
-  if (cluster_start == 0 && cluster_end == (unsigned int)-1) {
-    unsigned int count = buffer->len;
-    for (unsigned int i = 0; i < count; i++)
-      buffer->info[i].mask = (buffer->info[i].mask & not_mask) | value;
-    return;
-  }
-
-  unsigned int count = buffer->len;
-  for (unsigned int i = 0; i < count; i++)
-    if (cluster_start <= buffer->info[i].cluster && buffer->info[i].cluster < cluster_end)
-      buffer->info[i].mask = (buffer->info[i].mask & not_mask) | value;
-}
-
-
-/* Public API again */
-
 hb_bool_t
 hb_buffer_set_length (hb_buffer_t  *buffer,
 		      unsigned int  length)
 {
-  if (!_hb_buffer_ensure (buffer, length))
+  if (!buffer->ensure (length))
     return FALSE;
 
   /* Wipe the new space */
@@ -544,7 +588,7 @@ hb_buffer_get_glyph_positions (hb_buffer_t  *buffer,
                                unsigned int *length)
 {
   if (!buffer->have_positions)
-    _hb_buffer_clear_positions (buffer);
+    buffer->clear_positions ();
 
   if (length)
     *length = buffer->len;
@@ -552,69 +596,18 @@ hb_buffer_get_glyph_positions (hb_buffer_t  *buffer,
   return (hb_glyph_position_t *) buffer->pos;
 }
 
-
-static inline void
-reverse_range (hb_buffer_t *buffer,
-	       unsigned int start,
-	       unsigned int end)
-{
-  unsigned int i, j;
-
-  if (start == end - 1)
-    return;
-
-  for (i = start, j = end - 1; i < j; i++, j--) {
-    hb_glyph_info_t t;
-
-    t = buffer->info[i];
-    buffer->info[i] = buffer->info[j];
-    buffer->info[j] = t;
-  }
-
-  if (buffer->pos) {
-    for (i = start, j = end - 1; i < j; i++, j--) {
-      hb_glyph_position_t t;
-
-      t = buffer->pos[i];
-      buffer->pos[i] = buffer->pos[j];
-      buffer->pos[j] = t;
-    }
-  }
-}
-
 void
 hb_buffer_reverse (hb_buffer_t *buffer)
 {
-  if (unlikely (!buffer->len))
-    return;
-
-  reverse_range (buffer, 0, buffer->len);
+  buffer->reverse ();
 }
 
 void
 hb_buffer_reverse_clusters (hb_buffer_t *buffer)
 {
-  unsigned int i, start, count, last_cluster;
-
-  if (unlikely (!buffer->len))
-    return;
-
-  hb_buffer_reverse (buffer);
-
-  count = buffer->len;
-  start = 0;
-  last_cluster = buffer->info[0].cluster;
-  for (i = 1; i < count; i++) {
-    if (last_cluster != buffer->info[i].cluster) {
-      reverse_range (buffer, start, i);
-      start = i;
-      last_cluster = buffer->info[i].cluster;
-    }
-  }
-  reverse_range (buffer, start, i);
+  buffer->reverse_clusters ();
 }
 
-
 #define ADD_UTF(T) \
 	HB_STMT_START { \
 	  const T *next = (const T *) text + item_offset; \
diff --git a/src/hb-ot-layout-gpos-private.hh b/src/hb-ot-layout-gpos-private.hh
index 59750ab..b726f77 100644
--- a/src/hb-ot-layout-gpos-private.hh
+++ b/src/hb-ot-layout-gpos-private.hh
@@ -409,15 +409,15 @@ struct MarkArray : ArrayOf<MarkRecord>	/* Array of MarkRecords--in Coverage orde
 
     hb_position_t mark_x, mark_y, base_x, base_y;
 
-    mark_anchor.get_anchor (c->font, c->buffer->info[c->buffer->i].codepoint, &mark_x, &mark_y);
+    mark_anchor.get_anchor (c->font, c->buffer->info[c->buffer->idx].codepoint, &mark_x, &mark_y);
     glyph_anchor.get_anchor (c->font, c->buffer->info[glyph_pos].codepoint, &base_x, &base_y);
 
-    hb_glyph_position_t &o = c->buffer->pos[c->buffer->i];
+    hb_glyph_position_t &o = c->buffer->pos[c->buffer->idx];
     o.x_offset = base_x - mark_x;
     o.y_offset = base_y - mark_y;
-    o.attach_lookback() = c->buffer->i - glyph_pos;
+    o.attach_lookback() = c->buffer->idx - glyph_pos;
 
-    c->buffer->i++;
+    c->buffer->idx++;
     return true;
   }
 
@@ -438,14 +438,14 @@ struct SinglePosFormat1
   inline bool apply (hb_apply_context_t *c) const
   {
     TRACE_APPLY ();
-    unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoint);
+    unsigned int index = (this+coverage) (c->buffer->info[c->buffer->idx].codepoint);
     if (likely (index == NOT_COVERED))
       return false;
 
     valueFormat.apply_value (c->font, c->direction, this,
-			     values, c->buffer->pos[c->buffer->i]);
+			     values, c->buffer->pos[c->buffer->idx]);
 
-    c->buffer->i++;
+    c->buffer->idx++;
     return true;
   }
 
@@ -478,7 +478,7 @@ struct SinglePosFormat2
   inline bool apply (hb_apply_context_t *c) const
   {
     TRACE_APPLY ();
-    unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoint);
+    unsigned int index = (this+coverage) (c->buffer->info[c->buffer->idx].codepoint);
     if (likely (index == NOT_COVERED))
       return false;
 
@@ -487,9 +487,9 @@ struct SinglePosFormat2
 
     valueFormat.apply_value (c->font, c->direction, this,
 			     &values[index * valueFormat.get_len ()],
-			     c->buffer->pos[c->buffer->i]);
+			     c->buffer->pos[c->buffer->idx]);
 
-    c->buffer->i++;
+    c->buffer->idx++;
     return true;
   }
 
@@ -582,12 +582,12 @@ struct PairSet
       if (c->buffer->info[pos].codepoint == record->secondGlyph)
       {
 	valueFormats[0].apply_value (c->font, c->direction, this,
-				     &record->values[0], c->buffer->pos[c->buffer->i]);
+				     &record->values[0], c->buffer->pos[c->buffer->idx]);
 	valueFormats[1].apply_value (c->font, c->direction, this,
 				     &record->values[len1], c->buffer->pos[pos]);
 	if (len2)
 	  pos++;
-	c->buffer->i = pos;
+	c->buffer->idx = pos;
 	return true;
       }
       record = &StructAtOffset<PairValueRecord> (record, record_size);
@@ -630,15 +630,15 @@ struct PairPosFormat1
   inline bool apply (hb_apply_context_t *c) const
   {
     TRACE_APPLY ();
-    unsigned int end = MIN (c->buffer->len, c->buffer->i + c->context_length);
-    if (unlikely (c->buffer->i + 2 > end))
+    unsigned int end = MIN (c->buffer->len, c->buffer->idx + c->context_length);
+    if (unlikely (c->buffer->idx + 2 > end))
       return false;
 
-    unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoint);
+    unsigned int index = (this+coverage) (c->buffer->info[c->buffer->idx].codepoint);
     if (likely (index == NOT_COVERED))
       return false;
 
-    unsigned int j = c->buffer->i + 1;
+    unsigned int j = c->buffer->idx + 1;
     while (_hb_ot_layout_skip_mark (c->face, &c->buffer->info[j], c->lookup_props, NULL))
     {
       if (unlikely (j == end))
@@ -692,15 +692,15 @@ struct PairPosFormat2
   inline bool apply (hb_apply_context_t *c) const
   {
     TRACE_APPLY ();
-    unsigned int end = MIN (c->buffer->len, c->buffer->i + c->context_length);
-    if (unlikely (c->buffer->i + 2 > end))
+    unsigned int end = MIN (c->buffer->len, c->buffer->idx + c->context_length);
+    if (unlikely (c->buffer->idx + 2 > end))
       return false;
 
-    unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoint);
+    unsigned int index = (this+coverage) (c->buffer->info[c->buffer->idx].codepoint);
     if (likely (index == NOT_COVERED))
       return false;
 
-    unsigned int j = c->buffer->i + 1;
+    unsigned int j = c->buffer->idx + 1;
     while (_hb_ot_layout_skip_mark (c->face, &c->buffer->info[j], c->lookup_props, NULL))
     {
       if (unlikely (j == end))
@@ -712,20 +712,20 @@ struct PairPosFormat2
     unsigned int len2 = valueFormat2.get_len ();
     unsigned int record_len = len1 + len2;
 
-    unsigned int klass1 = (this+classDef1) (c->buffer->info[c->buffer->i].codepoint);
+    unsigned int klass1 = (this+classDef1) (c->buffer->info[c->buffer->idx].codepoint);
     unsigned int klass2 = (this+classDef2) (c->buffer->info[j].codepoint);
     if (unlikely (klass1 >= class1Count || klass2 >= class2Count))
       return false;
 
     const Value *v = &values[record_len * (klass1 * class2Count + klass2)];
     valueFormat1.apply_value (c->font, c->direction, this,
-			      v, c->buffer->pos[c->buffer->i]);
+			      v, c->buffer->pos[c->buffer->idx]);
     valueFormat2.apply_value (c->font, c->direction, this,
 			      v + len1, c->buffer->pos[j]);
 
     if (len2)
       j++;
-    c->buffer->i = j;
+    c->buffer->idx = j;
 
     return true;
   }
@@ -847,15 +847,15 @@ struct CursivePosFormat1
     if (c->property & HB_OT_LAYOUT_GLYPH_CLASS_MARK)
       return false;
 
-    unsigned int end = MIN (c->buffer->len, c->buffer->i + c->context_length);
-    if (unlikely (c->buffer->i + 2 > end))
+    unsigned int end = MIN (c->buffer->len, c->buffer->idx + c->context_length);
+    if (unlikely (c->buffer->idx + 2 > end))
       return false;
 
-    const EntryExitRecord &this_record = entryExitRecord[(this+coverage) (c->buffer->info[c->buffer->i].codepoint)];
+    const EntryExitRecord &this_record = entryExitRecord[(this+coverage) (c->buffer->info[c->buffer->idx].codepoint)];
     if (!this_record.exitAnchor)
       return false;
 
-    unsigned int j = c->buffer->i + 1;
+    unsigned int j = c->buffer->idx + 1;
     while (_hb_ot_layout_skip_mark (c->face, &c->buffer->info[j], c->lookup_props, NULL))
     {
       if (unlikely (j == end))
@@ -867,7 +867,7 @@ struct CursivePosFormat1
     if (!next_record.entryAnchor)
       return false;
 
-    unsigned int i = c->buffer->i;
+    unsigned int i = c->buffer->idx;
 
     hb_position_t entry_x, entry_y, exit_x, exit_y;
     (this+this_record.exitAnchor).get_anchor (c->font, c->buffer->info[i].codepoint, &exit_x, &exit_y);
@@ -926,7 +926,7 @@ struct CursivePosFormat1
 	pos[j].x_offset = exit_x - entry_x;
     }
 
-    c->buffer->i = j;
+    c->buffer->idx = j;
     return true;
   }
 
@@ -992,13 +992,13 @@ struct MarkBasePosFormat1
   inline bool apply (hb_apply_context_t *c) const
   {
     TRACE_APPLY ();
-    unsigned int mark_index = (this+markCoverage) (c->buffer->info[c->buffer->i].codepoint);
+    unsigned int mark_index = (this+markCoverage) (c->buffer->info[c->buffer->idx].codepoint);
     if (likely (mark_index == NOT_COVERED))
       return false;
 
     /* now we search backwards for a non-mark glyph */
     unsigned int property;
-    unsigned int j = c->buffer->i;
+    unsigned int j = c->buffer->idx;
     do
     {
       if (unlikely (!j))
@@ -1094,13 +1094,13 @@ struct MarkLigPosFormat1
   inline bool apply (hb_apply_context_t *c) const
   {
     TRACE_APPLY ();
-    unsigned int mark_index = (this+markCoverage) (c->buffer->info[c->buffer->i].codepoint);
+    unsigned int mark_index = (this+markCoverage) (c->buffer->info[c->buffer->idx].codepoint);
     if (likely (mark_index == NOT_COVERED))
       return false;
 
     /* now we search backwards for a non-mark glyph */
     unsigned int property;
-    unsigned int j = c->buffer->i;
+    unsigned int j = c->buffer->idx;
     do
     {
       if (unlikely (!j))
@@ -1128,9 +1128,9 @@ struct MarkLigPosFormat1
      * is identical to the ligature ID of the found ligature.  If yes, we
      * can directly use the component index.  If not, we attach the mark
      * glyph to the last component of the ligature. */
-    if (c->buffer->info[j].lig_id() && c->buffer->info[j].lig_id() == c->buffer->info[c->buffer->i].lig_id() && c->buffer->info[c->buffer->i].lig_comp())
+    if (c->buffer->info[j].lig_id() && c->buffer->info[j].lig_id() == c->buffer->info[c->buffer->idx].lig_id() && c->buffer->info[c->buffer->idx].lig_comp())
     {
-      comp_index = c->buffer->info[c->buffer->i].lig_comp() - 1;
+      comp_index = c->buffer->info[c->buffer->idx].lig_comp() - 1;
       if (comp_index >= comp_count)
 	comp_index = comp_count - 1;
     }
@@ -1213,13 +1213,13 @@ struct MarkMarkPosFormat1
   inline bool apply (hb_apply_context_t *c) const
   {
     TRACE_APPLY ();
-    unsigned int mark1_index = (this+mark1Coverage) (c->buffer->info[c->buffer->i].codepoint);
+    unsigned int mark1_index = (this+mark1Coverage) (c->buffer->info[c->buffer->idx].codepoint);
     if (likely (mark1_index == NOT_COVERED))
       return false;
 
     /* now we search backwards for a suitable mark glyph until a non-mark glyph */
     unsigned int property;
-    unsigned int j = c->buffer->i;
+    unsigned int j = c->buffer->idx;
     do
     {
       if (unlikely (!j))
@@ -1233,8 +1233,8 @@ struct MarkMarkPosFormat1
     /* Two marks match only if they belong to the same base, or same component
      * of the same ligature.  That is, the component numbers must match, and
      * if those are non-zero, the ligid number should also match. */
-    if ((c->buffer->info[j].lig_comp() != c->buffer->info[c->buffer->i].lig_comp()) ||
-	(c->buffer->info[j].lig_comp() && c->buffer->info[j].lig_id() != c->buffer->info[c->buffer->i].lig_id()))
+    if ((c->buffer->info[j].lig_comp() != c->buffer->info[c->buffer->idx].lig_comp()) ||
+	(c->buffer->info[j].lig_comp() && c->buffer->info[j].lig_id() != c->buffer->info[c->buffer->idx].lig_id()))
       return false;
 
     unsigned int mark2_index = (this+mark2Coverage) (c->buffer->info[j].codepoint);
@@ -1448,7 +1448,7 @@ struct PosLookup : Lookup
     c->nesting_level_left = nesting_level_left;
     c->lookup_props = get_props ();
 
-    if (!_hb_ot_layout_check_glyph_property (c->face, &c->buffer->info[c->buffer->i], c->lookup_props, &c->property))
+    if (!_hb_ot_layout_check_glyph_property (c->face, &c->buffer->info[c->buffer->idx], c->lookup_props, &c->property))
       return false;
 
     for (unsigned int i = 0; i < get_subtable_count (); i++)
@@ -1467,14 +1467,14 @@ struct PosLookup : Lookup
     if (unlikely (!buffer->len))
       return false;
 
-    buffer->i = 0;
-    while (buffer->i < buffer->len)
+    buffer->idx = 0;
+    while (buffer->idx < buffer->len)
     {
-      if ((buffer->info[buffer->i].mask & mask) &&
+      if ((buffer->info[buffer->idx].mask & mask) &&
 	  apply_once (font, buffer, mask, NO_CONTEXT, MAX_NESTING_LEVEL))
 	ret = true;
       else
-	buffer->i++;
+	buffer->idx++;
     }
 
     return ret;
diff --git a/src/hb-ot-layout-gsub-private.hh b/src/hb-ot-layout-gsub-private.hh
index 237b7ce..09ebc31 100644
--- a/src/hb-ot-layout-gsub-private.hh
+++ b/src/hb-ot-layout-gsub-private.hh
@@ -43,7 +43,7 @@ struct SingleSubstFormat1
   inline bool apply (hb_apply_context_t *c) const
   {
     TRACE_APPLY ();
-    hb_codepoint_t glyph_id = c->buffer->info[c->buffer->i].codepoint;
+    hb_codepoint_t glyph_id = c->buffer->info[c->buffer->idx].codepoint;
     unsigned int index = (this+coverage) (glyph_id);
     if (likely (index == NOT_COVERED))
       return false;
@@ -80,7 +80,7 @@ struct SingleSubstFormat2
   inline bool apply (hb_apply_context_t *c) const
   {
     TRACE_APPLY ();
-    hb_codepoint_t glyph_id = c->buffer->info[c->buffer->i].codepoint;
+    hb_codepoint_t glyph_id = c->buffer->info[c->buffer->idx].codepoint;
     unsigned int index = (this+coverage) (glyph_id);
     if (likely (index == NOT_COVERED))
       return false;
@@ -188,7 +188,7 @@ struct MultipleSubstFormat1
   {
     TRACE_APPLY ();
 
-    unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoint);
+    unsigned int index = (this+coverage) (c->buffer->info[c->buffer->idx].codepoint);
     if (likely (index == NOT_COVERED))
       return false;
 
@@ -257,8 +257,8 @@ struct AlternateSubstFormat1
   inline bool apply (hb_apply_context_t *c) const
   {
     TRACE_APPLY ();
-    hb_codepoint_t glyph_id = c->buffer->info[c->buffer->i].codepoint;
-    hb_mask_t glyph_mask = c->buffer->info[c->buffer->i].mask;
+    hb_codepoint_t glyph_id = c->buffer->info[c->buffer->idx].codepoint;
+    hb_mask_t glyph_mask = c->buffer->info[c->buffer->idx].mask;
     hb_mask_t lookup_mask = c->lookup_mask;
 
     unsigned int index = (this+coverage) (glyph_id);
@@ -344,14 +344,14 @@ struct Ligature
     TRACE_APPLY ();
     unsigned int i, j;
     unsigned int count = component.len;
-    unsigned int end = MIN (c->buffer->len, c->buffer->i + c->context_length);
-    if (unlikely (count < 2 || c->buffer->i + count > end))
+    unsigned int end = MIN (c->buffer->len, c->buffer->idx + c->context_length);
+    if (unlikely (count < 2 || c->buffer->idx + count > end))
       return false;
 
     bool first_was_mark = (c->property & HB_OT_LAYOUT_GLYPH_CLASS_MARK);
     bool found_non_mark = false;
 
-    for (i = 1, j = c->buffer->i + 1; i < count; i++, j++)
+    for (i = 1, j = c->buffer->idx + 1; i < count; i++, j++)
     {
       unsigned int property;
       while (_hb_ot_layout_skip_mark (c->face, &c->buffer->info[j], c->lookup_props, &property))
@@ -372,10 +372,10 @@ struct Ligature
 
     /* Allocate new ligature id */
     unsigned int lig_id = allocate_lig_id (c->buffer);
-    c->buffer->info[c->buffer->i].lig_comp() = 0;
-    c->buffer->info[c->buffer->i].lig_id() = lig_id;
+    c->buffer->info[c->buffer->idx].lig_comp() = 0;
+    c->buffer->info[c->buffer->idx].lig_id() = lig_id;
 
-    if (j == c->buffer->i + i) /* No input glyphs skipped */
+    if (j == c->buffer->idx + i) /* No input glyphs skipped */
     {
       c->replace_glyphs_be16 (i, 1, (const uint16_t *) &ligGlyph);
     }
@@ -392,15 +392,15 @@ struct Ligature
 
       for (i = 1; i < count; i++)
       {
-	while (_hb_ot_layout_skip_mark (c->face, &c->buffer->info[c->buffer->i], c->lookup_props, NULL))
+	while (_hb_ot_layout_skip_mark (c->face, &c->buffer->info[c->buffer->idx], c->lookup_props, NULL))
 	{
-	  c->buffer->info[c->buffer->i].lig_comp() = i;
-	  c->buffer->info[c->buffer->i].lig_id() = lig_id;
-	  c->replace_glyph (c->buffer->info[c->buffer->i].codepoint);
+	  c->buffer->info[c->buffer->idx].lig_comp() = i;
+	  c->buffer->info[c->buffer->idx].lig_id() = lig_id;
+	  c->replace_glyph (c->buffer->info[c->buffer->idx].codepoint);
 	}
 
 	/* Skip the base glyph */
-	c->buffer->i++;
+	c->buffer->idx++;
       }
     }
 
@@ -471,7 +471,7 @@ struct LigatureSubstFormat1
   inline bool apply (hb_apply_context_t *c) const
   {
     TRACE_APPLY ();
-    hb_codepoint_t glyph_id = c->buffer->info[c->buffer->i].codepoint;
+    hb_codepoint_t glyph_id = c->buffer->info[c->buffer->idx].codepoint;
 
     unsigned int index = (this+coverage) (glyph_id);
     if (likely (index == NOT_COVERED))
@@ -591,7 +591,7 @@ struct ReverseChainSingleSubstFormat1
     if (unlikely (c->context_length != NO_CONTEXT))
       return false; /* No chaining to this type */
 
-    unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoint);
+    unsigned int index = (this+coverage) (c->buffer->info[c->buffer->idx].codepoint);
     if (likely (index == NOT_COVERED))
       return false;
 
@@ -606,8 +606,8 @@ struct ReverseChainSingleSubstFormat1
 			 match_coverage, this,
 			 1))
     {
-      c->buffer->info[c->buffer->i].codepoint = substitute[index];
-      c->buffer->i--; /* Reverse! */
+      c->buffer->info[c->buffer->idx].codepoint = substitute[index];
+      c->buffer->idx--; /* Reverse! */
       return true;
     }
 
@@ -779,7 +779,7 @@ struct SubstLookup : Lookup
     c->nesting_level_left = nesting_level_left;
     c->lookup_props = get_props ();
 
-    if (!_hb_ot_layout_check_glyph_property (c->face, &c->buffer->info[c->buffer->i], c->lookup_props, &c->property))
+    if (!_hb_ot_layout_check_glyph_property (c->face, &c->buffer->info[c->buffer->idx], c->lookup_props, &c->property))
       return false;
 
     if (unlikely (lookup_type == SubstLookupSubTable::Extension))
@@ -817,10 +817,10 @@ struct SubstLookup : Lookup
     {
 	/* in/out forward substitution */
 	buffer->clear_output ();
-	buffer->i = 0;
-	while (buffer->i < buffer->len)
+	buffer->idx = 0;
+	while (buffer->idx < buffer->len)
 	{
-	  if ((buffer->info[buffer->i].mask & mask) &&
+	  if ((buffer->info[buffer->idx].mask & mask) &&
 	      apply_once (face, buffer, mask, NO_CONTEXT, MAX_NESTING_LEVEL))
 	    ret = true;
 	  else
@@ -828,22 +828,22 @@ struct SubstLookup : Lookup
 
 	}
 	if (ret)
-	  buffer->swap ();
+	  buffer->swap_buffers ();
     }
     else
     {
 	/* in-place backward substitution */
-	buffer->i = buffer->len - 1;
+	buffer->idx = buffer->len - 1;
 	do
 	{
-	  if ((buffer->info[buffer->i].mask & mask) &&
+	  if ((buffer->info[buffer->idx].mask & mask) &&
 	      apply_once (face, buffer, mask, NO_CONTEXT, MAX_NESTING_LEVEL))
 	    ret = true;
 	  else
-	    buffer->i--;
+	    buffer->idx--;
 
 	}
-	while ((int) buffer->i >= 0);
+	while ((int) buffer->idx >= 0);
     }
 
     return ret;
diff --git a/src/hb-ot-layout-gsubgpos-private.hh b/src/hb-ot-layout-gsubgpos-private.hh
index 4d6656a..7ccbdf0 100644
--- a/src/hb-ot-layout-gsubgpos-private.hh
+++ b/src/hb-ot-layout-gsubgpos-private.hh
@@ -80,14 +80,14 @@ struct hb_apply_context_t
   inline void guess_glyph_class (unsigned int klass)
   {
     /* XXX if ! has gdef */
-    buffer->info[buffer->i].props_cache() = klass;
+    buffer->info[buffer->idx].props_cache() = klass;
   }
 
   private:
   inline void clear_property (void) const
   {
     /* XXX if has gdef */
-    buffer->info[buffer->i].props_cache() = 0;
+    buffer->info[buffer->idx].props_cache() = 0;
   }
 };
 
@@ -129,11 +129,11 @@ static inline bool match_input (hb_apply_context_t *c,
 				unsigned int *context_length_out)
 {
   unsigned int i, j;
-  unsigned int end = MIN (c->buffer->len, c->buffer->i + c->context_length);
-  if (unlikely (c->buffer->i + count > end))
+  unsigned int end = MIN (c->buffer->len, c->buffer->idx + c->context_length);
+  if (unlikely (c->buffer->idx + count > end))
     return false;
 
-  for (i = 1, j = c->buffer->i + 1; i < count; i++, j++)
+  for (i = 1, j = c->buffer->idx + 1; i < count; i++, j++)
   {
     while (_hb_ot_layout_skip_mark (c->face, &c->buffer->info[j], c->lookup_props, NULL))
     {
@@ -146,7 +146,7 @@ static inline bool match_input (hb_apply_context_t *c,
       return false;
   }
 
-  *context_length_out = j - c->buffer->i;
+  *context_length_out = j - c->buffer->idx;
 
   return true;
 }
@@ -184,11 +184,11 @@ static inline bool match_lookahead (hb_apply_context_t *c,
 				    unsigned int offset)
 {
   unsigned int i, j;
-  unsigned int end = MIN (c->buffer->len, c->buffer->i + c->context_length);
-  if (unlikely (c->buffer->i + offset + count > end))
+  unsigned int end = MIN (c->buffer->len, c->buffer->idx + c->context_length);
+  if (unlikely (c->buffer->idx + offset + count > end))
     return false;
 
-  for (i = 0, j = c->buffer->i + offset; i < count; i++, j++)
+  for (i = 0, j = c->buffer->idx + offset; i < count; i++, j++)
   {
     while (_hb_ot_layout_skip_mark (c->face, &c->buffer->info[j], c->lookup_props, NULL))
     {
@@ -231,8 +231,8 @@ static inline bool apply_lookup (hb_apply_context_t *c,
 				 const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */
 				 apply_lookup_func_t apply_func)
 {
-  unsigned int end = MIN (c->buffer->len, c->buffer->i + c->context_length);
-  if (unlikely (count == 0 || c->buffer->i + count > end))
+  unsigned int end = MIN (c->buffer->len, c->buffer->idx + c->context_length);
+  if (unlikely (count == 0 || c->buffer->idx + count > end))
     return false;
 
   /* TODO We don't support lookupRecord arrays that are not increasing:
@@ -244,9 +244,9 @@ static inline bool apply_lookup (hb_apply_context_t *c,
    */
   for (unsigned int i = 0; i < count; /* NOP */)
   {
-    while (_hb_ot_layout_skip_mark (c->face, &c->buffer->info[c->buffer->i], c->lookup_props, NULL))
+    while (_hb_ot_layout_skip_mark (c->face, &c->buffer->info[c->buffer->idx], c->lookup_props, NULL))
     {
-      if (unlikely (c->buffer->i == end))
+      if (unlikely (c->buffer->idx == end))
 	return true;
       /* No lookup applied for this index */
       c->buffer->next_glyph ();
@@ -254,7 +254,7 @@ static inline bool apply_lookup (hb_apply_context_t *c,
 
     if (lookupCount && i == lookupRecord->sequenceIndex)
     {
-      unsigned int old_pos = c->buffer->i;
+      unsigned int old_pos = c->buffer->idx;
 
       /* Apply a lookup */
       bool done = apply_func (c, lookupRecord->lookupListIndex);
@@ -262,8 +262,8 @@ static inline bool apply_lookup (hb_apply_context_t *c,
       lookupRecord++;
       lookupCount--;
       /* Err, this is wrong if the lookup jumped over some glyphs */
-      i += c->buffer->i - old_pos;
-      if (unlikely (c->buffer->i == end))
+      i += c->buffer->idx - old_pos;
+      if (unlikely (c->buffer->idx == end))
 	return true;
 
       if (!done)
@@ -385,7 +385,7 @@ struct ContextFormat1
   inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
   {
     TRACE_APPLY ();
-    unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoint);
+    unsigned int index = (this+coverage) (c->buffer->info[c->buffer->idx].codepoint);
     if (likely (index == NOT_COVERED))
       return false;
 
@@ -424,12 +424,12 @@ struct ContextFormat2
   inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
   {
     TRACE_APPLY ();
-    unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoint);
+    unsigned int index = (this+coverage) (c->buffer->info[c->buffer->idx].codepoint);
     if (likely (index == NOT_COVERED))
       return false;
 
     const ClassDef &class_def = this+classDef;
-    index = class_def (c->buffer->info[c->buffer->i].codepoint);
+    index = class_def (c->buffer->info[c->buffer->idx].codepoint);
     const RuleSet &rule_set = this+ruleSet[index];
     struct ContextLookupContext lookup_context = {
       {match_class, apply_func},
@@ -469,7 +469,7 @@ struct ContextFormat3
   inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
   {
     TRACE_APPLY ();
-    unsigned int index = (this+coverage[0]) (c->buffer->info[c->buffer->i].codepoint);
+    unsigned int index = (this+coverage[0]) (c->buffer->info[c->buffer->idx].codepoint);
     if (likely (index == NOT_COVERED))
       return false;
 
@@ -565,7 +565,7 @@ static inline bool chain_context_lookup (hb_apply_context_t *c,
 {
   /* First guess */
   if (unlikely (c->buffer->backtrack_len () < backtrackCount ||
-		c->buffer->i + inputCount + lookaheadCount > c->buffer->len ||
+		c->buffer->idx + inputCount + lookaheadCount > c->buffer->len ||
 		inputCount + lookaheadCount > c->context_length))
     return false;
 
@@ -672,7 +672,7 @@ struct ChainContextFormat1
   inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
   {
     TRACE_APPLY ();
-    unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoint);
+    unsigned int index = (this+coverage) (c->buffer->info[c->buffer->idx].codepoint);
     if (likely (index == NOT_COVERED))
       return false;
 
@@ -710,7 +710,7 @@ struct ChainContextFormat2
   inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
   {
     TRACE_APPLY ();
-    unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoint);
+    unsigned int index = (this+coverage) (c->buffer->info[c->buffer->idx].codepoint);
     if (likely (index == NOT_COVERED))
       return false;
 
@@ -718,7 +718,7 @@ struct ChainContextFormat2
     const ClassDef &input_class_def = this+inputClassDef;
     const ClassDef &lookahead_class_def = this+lookaheadClassDef;
 
-    index = input_class_def (c->buffer->info[c->buffer->i].codepoint);
+    index = input_class_def (c->buffer->info[c->buffer->idx].codepoint);
     const ChainRuleSet &rule_set = this+ruleSet[index];
     struct ChainContextLookupContext lookup_context = {
       {match_class, apply_func},
@@ -773,7 +773,7 @@ struct ChainContextFormat3
     TRACE_APPLY ();
     const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
 
-    unsigned int index = (this+input[0]) (c->buffer->info[c->buffer->i].codepoint);
+    unsigned int index = (this+input[0]) (c->buffer->info[c->buffer->idx].codepoint);
     if (likely (index == NOT_COVERED))
       return false;
 
diff --git a/src/hb-ot-shape-normalize.cc b/src/hb-ot-shape-normalize.cc
index 1df2cbe..0d44d54 100644
--- a/src/hb-ot-shape-normalize.cc
+++ b/src/hb-ot-shape-normalize.cc
@@ -136,23 +136,23 @@ _hb_ot_shape_normalize (hb_ot_shape_context_t *c)
   buffer->clear_output ();
 
   unsigned int count = buffer->len;
-  for (buffer->i = 0; buffer->i < count;)
+  for (buffer->idx = 0; buffer->idx < count;)
   {
 
     unsigned int end;
-    for (end = buffer->i + 1; end < count; end++)
-      if (buffer->info[buffer->i].cluster != buffer->info[end].cluster)
+    for (end = buffer->idx + 1; end < count; end++)
+      if (buffer->info[buffer->idx].cluster != buffer->info[end].cluster)
         break;
 
-    if (buffer->i + 1 == end)
-      handle_single_char_cluster (c, recompose, buffer->i);
+    if (buffer->idx + 1 == end)
+      handle_single_char_cluster (c, recompose, buffer->idx);
     else
-      handle_multi_char_cluster (c, recompose, buffer->i, end);
-    while (buffer->i < end)
+      handle_multi_char_cluster (c, recompose, buffer->idx, end);
+    while (buffer->idx < end)
       c->buffer->next_glyph ();
   }
 
-  buffer->swap ();
+  buffer->swap_buffers ();
 }
 
 HB_END_DECLS
diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc
index 0770e3d..05348d3 100644
--- a/src/hb-ot-shape.cc
+++ b/src/hb-ot-shape.cc
@@ -257,21 +257,21 @@ hb_map_glyphs (hb_font_t    *font,
   buffer->clear_output ();
 
   unsigned int count = buffer->len - 1;
-  for (buffer->i = 0; buffer->i < count;) {
-    if (unlikely (is_variation_selector (buffer->info[buffer->i + 1].codepoint))) {
-      hb_font_get_glyph (font, buffer->info[buffer->i].codepoint, buffer->info[buffer->i + 1].codepoint, &glyph);
+  for (buffer->idx = 0; buffer->idx < count;) {
+    if (unlikely (is_variation_selector (buffer->info[buffer->idx + 1].codepoint))) {
+      hb_font_get_glyph (font, buffer->info[buffer->idx].codepoint, buffer->info[buffer->idx + 1].codepoint, &glyph);
       buffer->replace_glyph (glyph);
       buffer->skip_glyph ();
     } else {
-      hb_font_get_glyph (font, buffer->info[buffer->i].codepoint, 0, &glyph);
+      hb_font_get_glyph (font, buffer->info[buffer->idx].codepoint, 0, &glyph);
       buffer->replace_glyph (glyph);
     }
   }
-  if (likely (buffer->i < buffer->len)) {
-    hb_font_get_glyph (font, buffer->info[buffer->i].codepoint, 0, &glyph);
+  if (likely (buffer->idx < buffer->len)) {
+    hb_font_get_glyph (font, buffer->info[buffer->idx].codepoint, 0, &glyph);
     buffer->replace_glyph (glyph);
   }
-  buffer->swap ();
+  buffer->swap_buffers ();
 }
 
 static void
commit 45412523dc295cb5ee12e096bfacb282cc925843
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Jul 22 11:07:05 2011 -0400

    More normalization kick

diff --git a/src/hb-ot-shape-normalize.cc b/src/hb-ot-shape-normalize.cc
index 6832779..1df2cbe 100644
--- a/src/hb-ot-shape-normalize.cc
+++ b/src/hb-ot-shape-normalize.cc
@@ -63,12 +63,34 @@ HB_BEGIN_DECLS
  *     matra for the Indic shaper.
  */
 
+
 static bool
-get_glyph (hb_ot_shape_context_t *c, unsigned int i)
+decompose (hb_ot_shape_context_t *c,
+	   bool recompose,
+	   hb_codepoint_t ab)
 {
-  hb_codepoint_t glyph;
+  hb_codepoint_t a, b, glyph;
+  bool has_this = hb_font_get_glyph (c->font, ab, 0, &glyph);
+
+  /* If recomposing and the single char is supported by the font, we're good. */
+  if (recompose && has_this)
+    return TRUE;
+
+  if (hb_unicode_decompose (c->buffer->unicode, ab, &a, &b) &&
+      hb_font_get_glyph (c->font, b, 0, &glyph) &&
+      decompose (c, recompose, a))
+  {
+    /* Successfully decomposed. */
+
+    if (recompose) {
+      /* Try composing b with base if not blocked */
 
-  return hb_font_get_glyph (c->font, c->buffer->info[i].codepoint, 0, &glyph);
+    }
+
+    return TRUE;
+  }
+
+  return has_this;
 }
 
 static bool
@@ -76,23 +98,23 @@ decompose_single_char_cluster (hb_ot_shape_context_t *c,
 			       bool recompose,
 			       unsigned int i)
 {
+//  c->buffer->copy ();
+//  bool ret = decompose (c, recompose, c->buffer->info[i].codepoint);
+//  c->buffer->skip ();
+//  return ret;
   return FALSE;
 }
 
-static bool
+static void
 handle_single_char_cluster (hb_ot_shape_context_t *c,
 			    bool recompose,
 			    unsigned int i)
 {
-  /* If recomposing and the single char is supported by the font, we're good. */
-  if (recompose && get_glyph (c, i))
-    return FALSE;
-
   /* Decompose */
-  return decompose_single_char_cluster (c, recompose, i);
+  decompose_single_char_cluster (c, recompose, i);
 }
 
-static bool
+static void
 handle_multi_char_cluster (hb_ot_shape_context_t *c,
 			   bool recompose,
 			   unsigned int start,
@@ -101,16 +123,14 @@ handle_multi_char_cluster (hb_ot_shape_context_t *c,
   /* TODO Currently if there's a variation-selector we give-up, it's just too hard. */
   for (unsigned int i = start; i < end; i++)
     if (unlikely (is_variation_selector (c->buffer->info[i].codepoint)))
-      return FALSE;
+      return;
 
-  return FALSE;
 }
 
-bool
+void
 _hb_ot_shape_normalize (hb_ot_shape_context_t *c)
 {
   hb_buffer_t *buffer = c->buffer;
-  bool changed = FALSE;
   bool recompose = !hb_ot_shape_complex_prefer_decomposed (c->plan->shaper);
 
   buffer->clear_output ();
@@ -125,16 +145,14 @@ _hb_ot_shape_normalize (hb_ot_shape_context_t *c)
         break;
 
     if (buffer->i + 1 == end)
-      changed |= handle_single_char_cluster (c, recompose, buffer->i);
+      handle_single_char_cluster (c, recompose, buffer->i);
     else
-      changed |= handle_multi_char_cluster (c, recompose, buffer->i, end);
+      handle_multi_char_cluster (c, recompose, buffer->i, end);
     while (buffer->i < end)
       c->buffer->next_glyph ();
   }
 
   buffer->swap ();
-
-  return changed;
 }
 
 HB_END_DECLS
diff --git a/src/hb-ot-shape-private.hh b/src/hb-ot-shape-private.hh
index 17b3c99..0946820 100644
--- a/src/hb-ot-shape-private.hh
+++ b/src/hb-ot-shape-private.hh
@@ -99,8 +99,14 @@ is_variation_selector (hb_codepoint_t unicode)
 		   (unicode >= 0xE0100 && unicode <= 0xE01EF));  /* VARIATION SELECTOR-17..256 */
 }
 
+static inline void
+hb_glyph_info_set_unicode_props (hb_glyph_info_t *info, hb_unicode_funcs_t *unicode)
+{
+  info->general_category() = hb_unicode_general_category (unicode, info->codepoint);
+  info->combining_class() = hb_unicode_combining_class (unicode, info->codepoint);
+}
 
-HB_INTERNAL bool _hb_ot_shape_normalize (hb_ot_shape_context_t *c);
+HB_INTERNAL void _hb_ot_shape_normalize (hb_ot_shape_context_t *c);
 
 HB_END_DECLS
 
diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc
index d1c495f..0770e3d 100644
--- a/src/hb-ot-shape.cc
+++ b/src/hb-ot-shape.cc
@@ -179,14 +179,9 @@ hb_ot_position_complex (hb_ot_shape_context_t *c)
 static void
 hb_set_unicode_props (hb_buffer_t *buffer)
 {
-  hb_unicode_funcs_t *unicode = buffer->unicode;
-  hb_glyph_info_t *info = buffer->info;
-
   unsigned int count = buffer->len;
-  for (unsigned int i = 1; i < count; i++) {
-    info[i].general_category() = hb_unicode_general_category (unicode, info[i].codepoint);
-    info[i].combining_class() = hb_unicode_combining_class (unicode, info[i].codepoint);
-  }
+  for (unsigned int i = 1; i < count; i++)
+    hb_glyph_info_set_unicode_props (&buffer->info[i], buffer->unicode);
 }
 
 static void
@@ -365,9 +360,7 @@ hb_ot_shape_execute_internal (hb_ot_shape_context_t *c)
 
   hb_ensure_native_direction (c->buffer);
 
-  if (_hb_ot_shape_normalize (c))
-    /* Buffer contents changed, reset unicode_props */
-    hb_set_unicode_props (c->buffer); /* BUFFER: Set general_category and combining_class in var1 */
+  _hb_ot_shape_normalize (c);
 
   hb_ot_shape_setup_masks (c); /* BUFFER: Clobbers var2 */
 



More information about the HarfBuzz mailing list