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

Behdad Esfahbod behdad at kemper.freedesktop.org
Wed Aug 1 18:51:20 PDT 2012


 src/hb-buffer.cc                     |    2 
 src/hb-common.h                      |   38 ----
 src/hb-fallback-shape.cc             |   23 +-
 src/hb-font-private.hh               |  204 +++++++++++++++++++++++++
 src/hb-font.cc                       |  129 ++--------------
 src/hb-glib.cc                       |    4 
 src/hb-graphite2.cc                  |    6 
 src/hb-icu.cc                        |    4 
 src/hb-old.cc                        |   12 -
 src/hb-ot-layout-common-private.hh   |   12 -
 src/hb-ot-layout-gdef-table.hh       |    2 
 src/hb-ot-layout-gpos-table.hh       |   50 +++---
 src/hb-ot-layout-gsub-table.hh       |   53 +++---
 src/hb-ot-layout-gsubgpos-private.hh |    8 
 src/hb-ot-layout-private.hh          |    4 
 src/hb-ot-layout.cc                  |   29 +++
 src/hb-ot-shape-complex-arabic.cc    |    4 
 src/hb-ot-shape-complex-indic.cc     |    6 
 src/hb-ot-shape-complex-misc.cc      |    2 
 src/hb-ot-shape-normalize.cc         |   43 +++--
 src/hb-ot-shape-private.hh           |    6 
 src/hb-ot-shape.cc                   |   51 +++---
 src/hb-set-private.hh                |   95 +++++++++++
 src/hb-unicode-private.hh            |  193 ++++++++++++++++-------
 src/hb-unicode.cc                    |  282 +++++++++++++++++++----------------
 src/hb-unicode.h                     |  128 +++++++++++++++
 26 files changed, 921 insertions(+), 469 deletions(-)

New commits:
commit 1336ecdf8e4e9879b96b26ecfbf5c9ba6c49e2b9
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Wed Aug 1 21:46:36 2012 -0400

    [GSUB/GPOS] Use Coverage digests as gatekeeper
    
    Gives me a good 10% speedup for the Devanagari test case.  Less so
    for less lookup-intensive tests.
    
    For the Devanagari test case, the false positive rate of the GSUB digest
    is 4%.

diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh
index 3b0b881..34b9723 100644
--- a/src/hb-ot-layout-gpos-table.hh
+++ b/src/hb-ot-layout-gpos-table.hh
@@ -1551,27 +1551,15 @@ struct PosLookup : Lookup
 
     c->buffer->idx = 0;
 
-    /* Fast path for lookups with one coverage only (which is most). */
-    const Coverage *coverage = get_coverage ();
-    if (coverage)
-      while (c->buffer->idx < c->buffer->len)
-      {
-	if ((c->buffer->cur().mask & c->lookup_mask) &&
-	    coverage->get_coverage (c->buffer->cur().codepoint) != NOT_COVERED &&
-	    apply_once (c))
-	  ret = true;
-	else
-	  c->buffer->idx++;
-      }
-    else
-      while (c->buffer->idx < c->buffer->len)
-      {
-	if ((c->buffer->cur().mask & c->lookup_mask) &&
-	    apply_once (c))
-	  ret = true;
-	else
-	  c->buffer->idx++;
-      }
+    while (c->buffer->idx < c->buffer->len)
+    {
+      if ((c->buffer->cur().mask & c->lookup_mask) &&
+	  c->digest->may_have (c->buffer->cur().codepoint) &&
+	  apply_once (c))
+	ret = true;
+      else
+	c->buffer->idx++;
+    }
 
     return ret;
   }
diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh
index ca91a25..182f780 100644
--- a/src/hb-ot-layout-gsub-table.hh
+++ b/src/hb-ot-layout-gsub-table.hh
@@ -1219,28 +1219,15 @@ struct SubstLookup : Lookup
 	c->buffer->clear_output ();
 	c->buffer->idx = 0;
 
-	/* Fast path for lookups with one coverage only (which is most). */
-	const Coverage *coverage = get_coverage ();
-	if (coverage)
-	  while (c->buffer->idx < c->buffer->len)
-	  {
-	    if ((c->buffer->cur().mask & c->lookup_mask) &&
-		coverage->get_coverage (c->buffer->cur().codepoint) != NOT_COVERED &&
-		apply_once (c))
-	      ret = true;
-	    else
-	      c->buffer->next_glyph ();
-	  }
-	else
-	  while (c->buffer->idx < c->buffer->len)
-	  {
-	    if ((c->buffer->cur().mask & c->lookup_mask) &&
-		apply_once (c))
-	      ret = true;
-	    else
-	      c->buffer->next_glyph ();
-
-	  }
+	while (c->buffer->idx < c->buffer->len)
+	{
+	  if ((c->buffer->cur().mask & c->lookup_mask) &&
+	      c->digest->may_have (c->buffer->cur().codepoint) &&
+	      apply_once (c))
+	    ret = true;
+	  else
+	    c->buffer->next_glyph ();
+	}
 	if (ret)
 	  c->buffer->swap_buffers ();
     }
@@ -1250,7 +1237,9 @@ struct SubstLookup : Lookup
 	c->buffer->idx = c->buffer->len - 1;
 	do
 	{
-	  if ((c->buffer->cur().mask & c->lookup_mask) && apply_once (c))
+	  if ((c->buffer->cur().mask & c->lookup_mask) &&
+	      c->digest->may_have (c->buffer->cur().codepoint) &&
+	      apply_once (c))
 	    ret = true;
 	  else
 	    c->buffer->idx--;
diff --git a/src/hb-ot-layout-gsubgpos-private.hh b/src/hb-ot-layout-gsubgpos-private.hh
index 1f20514..7a3f32e 100644
--- a/src/hb-ot-layout-gsubgpos-private.hh
+++ b/src/hb-ot-layout-gsubgpos-private.hh
@@ -31,6 +31,7 @@
 
 #include "hb-buffer-private.hh"
 #include "hb-ot-layout-gdef-table.hh"
+#include "hb-set-private.hh"
 
 
 
@@ -109,12 +110,14 @@ struct hb_apply_context_t
   unsigned int debug_depth;
   const GDEF &gdef;
   bool has_glyph_classes;
+  const hb_set_digest_t *digest;
 
 
   hb_apply_context_t (hb_font_t *font_,
 		      hb_face_t *face_,
 		      hb_buffer_t *buffer_,
-		      hb_mask_t lookup_mask_) :
+		      hb_mask_t lookup_mask_,
+		      const hb_set_digest_t *digest_) :
 			font (font_), face (face_), buffer (buffer_),
 			direction (buffer_->props.direction),
 			lookup_mask (lookup_mask_),
@@ -123,7 +126,8 @@ struct hb_apply_context_t
 			gdef (hb_ot_layout_from_face (face_) &&
 			      !HB_SHAPER_DATA_IS_INVALID (hb_ot_layout_from_face (face_)) ?
 			      *hb_ot_layout_from_face (face_)->gdef : Null(GDEF)),
-			has_glyph_classes (gdef.has_glyph_classes ()) {}
+			has_glyph_classes (gdef.has_glyph_classes ()),
+			digest (digest_) {}
 
   void set_lookup (const Lookup &l) {
     lookup_props = l.get_props ();
diff --git a/src/hb-ot-layout-private.hh b/src/hb-ot-layout-private.hh
index fdbeb5b..d87a138 100644
--- a/src/hb-ot-layout-private.hh
+++ b/src/hb-ot-layout-private.hh
@@ -35,6 +35,7 @@
 
 #include "hb-font-private.hh"
 #include "hb-buffer-private.hh"
+#include "hb-set-private.hh"
 
 
 /* buffer var allocations, used during the GSUB/GPOS processing */
@@ -168,6 +169,9 @@ struct hb_ot_layout_t
   const struct GDEF *gdef;
   const struct GSUB *gsub;
   const struct GPOS *gpos;
+
+  hb_set_digest_t *gsub_digests;
+  hb_set_digest_t *gpos_digests;
 };
 
 
diff --git a/src/hb-ot-layout.cc b/src/hb-ot-layout.cc
index 0d0dfa0..b680d9c 100644
--- a/src/hb-ot-layout.cc
+++ b/src/hb-ot-layout.cc
@@ -58,6 +58,24 @@ _hb_ot_layout_create (hb_face_t *face)
   layout->gpos_blob = Sanitizer<GPOS>::sanitize (hb_face_reference_table (face, HB_OT_TAG_GPOS));
   layout->gpos = Sanitizer<GPOS>::lock_instance (layout->gpos_blob);
 
+  layout->gsub_digests = (hb_set_digest_t *) calloc (layout->gsub->get_lookup_count (), sizeof (hb_set_digest_t));
+  layout->gpos_digests = (hb_set_digest_t *) calloc (layout->gpos->get_lookup_count (), sizeof (hb_set_digest_t));
+
+  if (unlikely ((layout->gsub->get_lookup_count() && !layout->gsub_digests) ||
+		(layout->gpos->get_lookup_count() && !layout->gpos_digests)))
+  {
+    _hb_ot_layout_destroy (layout);
+    return NULL;
+  }
+
+  unsigned int count;
+  count = layout->gsub->get_lookup_count();
+  for (unsigned int i = 0; i < count; i++)
+    layout->gsub->add_coverage (&layout->gsub_digests[i], i);
+  count = layout->gpos->get_lookup_count();
+  for (unsigned int i = 0; i < count; i++)
+    layout->gpos->add_coverage (&layout->gpos_digests[i], i);
+
   return layout;
 }
 
@@ -68,6 +86,9 @@ _hb_ot_layout_destroy (hb_ot_layout_t *layout)
   hb_blob_destroy (layout->gsub_blob);
   hb_blob_destroy (layout->gpos_blob);
 
+  free (layout->gsub_digests);
+  free (layout->gpos_digests);
+
   free (layout);
 }
 
@@ -412,7 +433,7 @@ hb_ot_layout_substitute_lookup (hb_face_t    *face,
 				unsigned int  lookup_index,
 				hb_mask_t     mask)
 {
-  hb_apply_context_t c (NULL, face, buffer, mask);
+  hb_apply_context_t c (NULL, face, buffer, mask, NULL);
   return _get_gsub (face).substitute_lookup (&c, lookup_index);
 }
 
@@ -422,7 +443,7 @@ hb_ot_layout_substitute_lookup_fast (hb_face_t    *face,
 				     unsigned int  lookup_index,
 				     hb_mask_t     mask)
 {
-  hb_apply_context_t c (NULL, face, buffer, mask);
+  hb_apply_context_t c (NULL, face, buffer, mask, &hb_ot_layout_from_face (face)->gsub_digests[lookup_index]);
   return hb_ot_layout_from_face (face)->gsub->substitute_lookup (&c, lookup_index);
 }
 
@@ -463,7 +484,7 @@ hb_ot_layout_position_lookup (hb_font_t    *font,
 			      unsigned int  lookup_index,
 			      hb_mask_t     mask)
 {
-  hb_apply_context_t c (font, font->face, buffer, mask);
+  hb_apply_context_t c (font, font->face, buffer, mask, NULL);
   return _get_gpos (font->face).position_lookup (&c, lookup_index);
 }
 
@@ -473,7 +494,7 @@ hb_ot_layout_position_lookup_fast (hb_font_t    *font,
 				   unsigned int  lookup_index,
 				   hb_mask_t     mask)
 {
-  hb_apply_context_t c (font, font->face, buffer, mask);
+  hb_apply_context_t c (font, font->face, buffer, mask, &hb_ot_layout_from_face (font->face)->gpos_digests[lookup_index]);
   return hb_ot_layout_from_face (font->face)->gpos->position_lookup (&c, lookup_index);
 }
 
commit a878c58a8fc1500986d713b2bcedfeb90a0087b0
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Wed Aug 1 21:18:54 2012 -0400

    [GSUB/GPOS] Add add_coverage()

diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh
index cffbd25..3b0b881 100644
--- a/src/hb-ot-layout-gpos-table.hh
+++ b/src/hb-ot-layout-gpos-table.hh
@@ -1511,6 +1511,20 @@ struct PosLookup : Lookup
     return c;
   }
 
+  template <typename set_t>
+  inline void add_coverage (set_t *glyphs) const
+  {
+    const Coverage *last = NULL;
+    unsigned int count = get_subtable_count ();
+    for (unsigned int i = 0; i < count; i++) {
+      const Coverage *c = &get_subtable (i).get_coverage (get_type ());
+      if (c != last) {
+        c->add_coverage (glyphs);
+        last = c;
+      }
+    }
+  }
+
   inline bool apply_once (hb_apply_context_t *c) const
   {
     unsigned int lookup_type = get_type ();
@@ -1583,6 +1597,10 @@ struct GPOS : GSUBGPOS
   inline const PosLookup& get_lookup (unsigned int i) const
   { return CastR<PosLookup> (GSUBGPOS::get_lookup (i)); }
 
+  template <typename set_t>
+  inline void add_coverage (set_t *glyphs, unsigned int lookup_index) const
+  { get_lookup (lookup_index).add_coverage (glyphs); }
+
   inline bool position_lookup (hb_apply_context_t *c, unsigned int lookup_index) const
   { return get_lookup (lookup_index).apply_string (c); }
 
diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh
index 605ddb5..ca91a25 100644
--- a/src/hb-ot-layout-gsub-table.hh
+++ b/src/hb-ot-layout-gsub-table.hh
@@ -1165,6 +1165,20 @@ struct SubstLookup : Lookup
     return c;
   }
 
+  template <typename set_t>
+  inline void add_coverage (set_t *glyphs) const
+  {
+    const Coverage *last = NULL;
+    unsigned int count = get_subtable_count ();
+    for (unsigned int i = 0; i < count; i++) {
+      const Coverage *c = &get_subtable (i).get_coverage (get_type ());
+      if (c != last) {
+        c->add_coverage (glyphs);
+        last = c;
+      }
+    }
+  }
+
   inline bool would_apply (hb_would_apply_context_t *c) const
   {
     unsigned int lookup_type = get_type ();
@@ -1284,6 +1298,10 @@ struct GSUB : GSUBGPOS
   inline const SubstLookup& get_lookup (unsigned int i) const
   { return CastR<SubstLookup> (GSUBGPOS::get_lookup (i)); }
 
+  template <typename set_t>
+  inline void add_coverage (set_t *glyphs, unsigned int lookup_index) const
+  { get_lookup (lookup_index).add_coverage (glyphs); }
+
   inline bool would_substitute_lookup (hb_would_apply_context_t *c, unsigned int lookup_index) const
   { return get_lookup (lookup_index).would_apply (c); }
 
commit 60a3035ac5ec8227e4cc0e6708732bb139c9e0b8
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Wed Aug 1 21:06:27 2012 -0400

    Add hb_set_digest_t
    
    Implement two set digests, and one that combines the two.

diff --git a/src/hb-set-private.hh b/src/hb-set-private.hh
index 3b3f7fe..537319a 100644
--- a/src/hb-set-private.hh
+++ b/src/hb-set-private.hh
@@ -32,6 +32,101 @@
 #include "hb-object-private.hh"
 
 
+struct hb_set_digest_common_bits_t
+{
+  ASSERT_POD ();
+
+  typedef uint16_t mask_t;
+
+  inline void init (void) {
+    mask = ~0;
+    value = (mask_t) -1;
+  }
+
+  inline void add (hb_codepoint_t g) {
+    if (unlikely (value == (mask_t) -1)) {
+      value = g;
+      return;
+    }
+
+    mask ^= (g & mask) ^ value;
+    value &= mask;
+  }
+
+  inline void add_range (hb_codepoint_t a, hb_codepoint_t b) {
+    /* TODO Speedup. */
+    for (unsigned int i = a; i < b + 1; i++)
+      add (i);
+  }
+
+  inline bool may_have (hb_codepoint_t g) const {
+    return (g & mask) == value;
+  }
+
+  private:
+  mask_t mask;
+  mask_t value;
+};
+
+struct hb_set_digest_lowest_bits_t
+{
+  ASSERT_POD ();
+
+  typedef uint32_t mask_t;
+
+  inline void init (void) {
+    mask = 0;
+  }
+
+  inline void add (hb_codepoint_t g) {
+    mask |= mask_for (g);
+  }
+
+  inline void add_range (hb_codepoint_t a, hb_codepoint_t b) {
+    /* TODO Speedup. */
+    for (unsigned int i = a; i < b + 1; i++)
+      add (i);
+  }
+
+  inline bool may_have (hb_codepoint_t g) const {
+    return !!(mask & mask_for (g));
+  }
+
+  private:
+
+  mask_t mask_for (hb_codepoint_t g) const { return 1 << (g & (sizeof (mask_t) * 8 - 1)); }
+  mask_t mask;
+};
+
+struct hb_set_digest_t
+{
+  ASSERT_POD ();
+
+  inline void init (void) {
+    digest1.init ();
+    digest2.init ();
+  }
+
+  inline void add (hb_codepoint_t g) {
+    digest1.add (g);
+    digest2.add (g);
+  }
+
+  inline void add_range (hb_codepoint_t a, hb_codepoint_t b) {
+    digest1.add_range (a, b);
+    digest2.add_range (a, b);
+  }
+
+  inline bool may_have (hb_codepoint_t g) const {
+    return digest1.may_have (g) && digest2.may_have (g);
+  }
+
+  private:
+  hb_set_digest_common_bits_t digest1;
+  hb_set_digest_lowest_bits_t digest2;
+};
+
+
 /* TODO Make this faster and memmory efficient. */
 
 struct hb_set_t
commit c8accf1dd2d92cc4f714393eb0ea46f69bb182a6
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Wed Aug 1 21:05:57 2012 -0400

    [OT] Templatize Coverage::add_coverage()

diff --git a/src/hb-ot-layout-common-private.hh b/src/hb-ot-layout-common-private.hh
index db42894..fad813f 100644
--- a/src/hb-ot-layout-common-private.hh
+++ b/src/hb-ot-layout-common-private.hh
@@ -134,7 +134,8 @@ struct RangeRecord
     return glyphs->intersects (start, end);
   }
 
-  inline void add_coverage (hb_set_t *glyphs) const {
+  template <typename set_t>
+  inline void add_coverage (set_t *glyphs) const {
     glyphs->add_range (start, end);
   }
 
@@ -361,7 +362,8 @@ struct CoverageFormat1
     return glyphs->has (glyphArray[index]);
   }
 
-  inline void add_coverage (hb_set_t *glyphs) const {
+  template <typename set_t>
+  inline void add_coverage (set_t *glyphs) const {
     unsigned int count = glyphArray.len;
     for (unsigned int i = 0; i < count; i++)
       glyphs->add (glyphArray[i]);
@@ -422,7 +424,8 @@ struct CoverageFormat2
     return false;
   }
 
-  inline void add_coverage (hb_set_t *glyphs) const {
+  template <typename set_t>
+  inline void add_coverage (set_t *glyphs) const {
     unsigned int count = rangeRecord.len;
     for (unsigned int i = 0; i < count; i++)
       rangeRecord[i].add_coverage (glyphs);
@@ -505,7 +508,8 @@ struct Coverage
     }
   }
 
-  inline void add_coverage (hb_set_t *glyphs) const {
+  template <typename set_t>
+  inline void add_coverage (set_t *glyphs) const {
     switch (u.format) {
     case 1: u.format1.add_coverage (glyphs); break;
     case 2: u.format2.add_coverage (glyphs); break;
commit 8fbfda920e0b3bb4ab7afb732826026964b79be9
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Wed Aug 1 19:03:46 2012 -0400

    Inline font getters

diff --git a/src/hb-fallback-shape.cc b/src/hb-fallback-shape.cc
index ad7c88c..529e5d3 100644
--- a/src/hb-fallback-shape.cc
+++ b/src/hb-fallback-shape.cc
@@ -95,9 +95,8 @@ _hb_fallback_shape (hb_shape_plan_t    *shape_plan,
 		    const hb_feature_t *features HB_UNUSED,
 		    unsigned int        num_features HB_UNUSED)
 {
-  /* TODO Save the space character in the font? */
   hb_codepoint_t space;
-  hb_font_get_glyph (font, ' ', 0, &space);
+  font->get_glyph (' ', 0, &space);
 
   buffer->guess_properties ();
   buffer->clear_positions ();
@@ -112,15 +111,15 @@ _hb_fallback_shape (hb_shape_plan_t    *shape_plan,
       buffer->pos[i].y_advance = 0;
       continue;
     }
-    hb_font_get_glyph (font, buffer->info[i].codepoint, 0, &buffer->info[i].codepoint);
-    hb_font_get_glyph_advance_for_direction (font, buffer->info[i].codepoint,
-					     buffer->props.direction,
-					     &buffer->pos[i].x_advance,
-					     &buffer->pos[i].y_advance);
-    hb_font_subtract_glyph_origin_for_direction (font, buffer->info[i].codepoint,
-						 buffer->props.direction,
-						 &buffer->pos[i].x_offset,
-						 &buffer->pos[i].y_offset);
+    font->get_glyph (buffer->info[i].codepoint, 0, &buffer->info[i].codepoint);
+    font->get_glyph_advance_for_direction (buffer->info[i].codepoint,
+					   buffer->props.direction,
+					   &buffer->pos[i].x_advance,
+					   &buffer->pos[i].y_advance);
+    font->subtract_glyph_origin_for_direction (buffer->info[i].codepoint,
+					       buffer->props.direction,
+					       &buffer->pos[i].x_offset,
+					       &buffer->pos[i].y_offset);
   }
 
   if (HB_DIRECTION_IS_BACKWARD (buffer->props.direction))
diff --git a/src/hb-font-private.hh b/src/hb-font-private.hh
index 892fd7c..56c5913 100644
--- a/src/hb-font-private.hh
+++ b/src/hb-font-private.hh
@@ -174,6 +174,210 @@ struct hb_font_t {
   }
 
 
+  /* Public getters */
+
+  inline hb_bool_t get_glyph (hb_codepoint_t unicode, hb_codepoint_t variation_selector,
+			      hb_codepoint_t *glyph)
+  {
+    *glyph = 0;
+    return klass->get.glyph (this, user_data,
+			     unicode, variation_selector, glyph,
+			     klass->user_data.glyph);
+  }
+
+  inline hb_position_t get_glyph_h_advance (hb_codepoint_t glyph)
+  {
+    return klass->get.glyph_h_advance (this, user_data,
+				       glyph,
+				       klass->user_data.glyph_h_advance);
+  }
+
+  inline hb_position_t get_glyph_v_advance (hb_codepoint_t glyph)
+  {
+    return klass->get.glyph_v_advance (this, user_data,
+				       glyph,
+				       klass->user_data.glyph_v_advance);
+  }
+
+  inline hb_bool_t get_glyph_h_origin (hb_codepoint_t glyph,
+				       hb_position_t *x, hb_position_t *y)
+  {
+    *x = *y = 0;
+    return klass->get.glyph_h_origin (this, user_data,
+				      glyph, x, y,
+				      klass->user_data.glyph_h_origin);
+  }
+
+  inline hb_bool_t get_glyph_v_origin (hb_codepoint_t glyph,
+				       hb_position_t *x, hb_position_t *y)
+  {
+    *x = *y = 0;
+    return klass->get.glyph_v_origin (this, user_data,
+				      glyph, x, y,
+				      klass->user_data.glyph_v_origin);
+  }
+
+  inline hb_position_t get_glyph_h_kerning (hb_codepoint_t left_glyph, hb_codepoint_t right_glyph)
+  {
+    return klass->get.glyph_h_kerning (this, user_data,
+				       left_glyph, right_glyph,
+				       klass->user_data.glyph_h_kerning);
+  }
+
+  inline hb_position_t get_glyph_v_kerning (hb_codepoint_t left_glyph, hb_codepoint_t right_glyph)
+  {
+    return klass->get.glyph_v_kerning (this, user_data,
+				       left_glyph, right_glyph,
+				       klass->user_data.glyph_v_kerning);
+  }
+
+  inline hb_bool_t get_glyph_extents (hb_codepoint_t glyph,
+				      hb_glyph_extents_t *extents)
+  {
+    memset (extents, 0, sizeof (*extents));
+    return klass->get.glyph_extents (this, user_data,
+				     glyph,
+				     extents,
+				     klass->user_data.glyph_extents);
+  }
+
+  inline hb_bool_t get_glyph_contour_point (hb_codepoint_t glyph, unsigned int point_index,
+					    hb_position_t *x, hb_position_t *y)
+  {
+    *x = *y = 0;
+    return klass->get.glyph_contour_point (this, user_data,
+					   glyph, point_index,
+					   x, y,
+					   klass->user_data.glyph_contour_point);
+  }
+
+  inline hb_bool_t get_glyph_name (hb_codepoint_t glyph,
+				   char *name, unsigned int size)
+  {
+    return klass->get.glyph_name (this, user_data,
+				  glyph,
+				  name, size,
+				  klass->user_data.glyph_name);
+  }
+
+  inline hb_bool_t get_glyph_from_name (const char *name, int len, /* -1 means nul-terminated */
+					hb_codepoint_t *glyph)
+  {
+    return klass->get.glyph_from_name (this, user_data,
+				       name, len,
+				       glyph,
+				       klass->user_data.glyph_from_name);
+  }
+
+
+  /* A bit higher-level, and with fallback */
+
+  inline void get_glyph_advance_for_direction (hb_codepoint_t glyph,
+					       hb_direction_t direction,
+					       hb_position_t *x, hb_position_t *y)
+  {
+    if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) {
+      *x = get_glyph_h_advance (glyph);
+      *y = 0;
+    } else {
+      *x = 0;
+      *y = get_glyph_v_advance (glyph);
+    }
+  }
+
+  /* Internal only */
+  inline void guess_v_origin_minus_h_origin (hb_codepoint_t glyph,
+					     hb_position_t *x, hb_position_t *y)
+  {
+    *x = get_glyph_h_advance (glyph) / 2;
+
+    /* TODO use font_metics.ascent */
+    *y = y_scale;
+  }
+
+  inline void get_glyph_origin_for_direction (hb_codepoint_t glyph,
+					      hb_direction_t direction,
+					      hb_position_t *x, hb_position_t *y)
+  {
+    if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) {
+      hb_bool_t ret = get_glyph_h_origin (glyph, x, y);
+      if (!ret && (ret = get_glyph_v_origin (glyph, x, y))) {
+	hb_position_t dx, dy;
+	guess_v_origin_minus_h_origin (glyph, &dx, &dy);
+	*x -= dx; *y -= dy;
+      }
+    } else {
+      hb_bool_t ret = get_glyph_v_origin (glyph, x, y);
+      if (!ret && (ret = get_glyph_h_origin (glyph, x, y))) {
+	hb_position_t dx, dy;
+	guess_v_origin_minus_h_origin (glyph, &dx, &dy);
+	*x += dx; *y += dy;
+      }
+    }
+  }
+
+  inline void add_glyph_origin_for_direction (hb_codepoint_t glyph,
+					      hb_direction_t direction,
+					      hb_position_t *x, hb_position_t *y)
+  {
+    hb_position_t origin_x, origin_y;
+
+    get_glyph_origin_for_direction (glyph, direction, &origin_x, &origin_y);
+
+    *x += origin_x;
+    *y += origin_y;
+  }
+
+  inline void subtract_glyph_origin_for_direction (hb_codepoint_t glyph,
+						   hb_direction_t direction,
+						   hb_position_t *x, hb_position_t *y)
+  {
+    hb_position_t origin_x, origin_y;
+
+    get_glyph_origin_for_direction (glyph, direction, &origin_x, &origin_y);
+
+    *x -= origin_x;
+    *y -= origin_y;
+  }
+
+  inline void get_glyph_kerning_for_direction (hb_codepoint_t first_glyph, hb_codepoint_t second_glyph,
+					       hb_direction_t direction,
+					       hb_position_t *x, hb_position_t *y)
+  {
+    if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) {
+      *x = get_glyph_h_kerning (first_glyph, second_glyph);
+      *y = 0;
+    } else {
+      *x = 0;
+      *y = get_glyph_v_kerning (first_glyph, second_glyph);
+    }
+  }
+
+  inline hb_bool_t get_glyph_extents_for_origin (hb_codepoint_t glyph,
+						 hb_direction_t direction,
+						 hb_glyph_extents_t *extents)
+  {
+    hb_bool_t ret = get_glyph_extents (glyph, extents);
+
+    if (ret)
+      subtract_glyph_origin_for_direction (glyph, direction, &extents->x_bearing, &extents->y_bearing);
+
+    return ret;
+  }
+
+  inline hb_bool_t get_glyph_contour_point_for_origin (hb_codepoint_t glyph, unsigned int point_index,
+						       hb_direction_t direction,
+						       hb_position_t *x, hb_position_t *y)
+  {
+    hb_bool_t ret = get_glyph_contour_point (glyph, point_index, x, y);
+
+    if (ret)
+      subtract_glyph_origin_for_direction (glyph, direction, x, y);
+
+    return ret;
+  }
+
+
   private:
   inline hb_position_t em_scale (int16_t v, int scale) { return v * (int64_t) scale / hb_face_get_upem (this->face); }
 };
diff --git a/src/hb-font.cc b/src/hb-font.cc
index 83c349e..48bfaab 100644
--- a/src/hb-font.cc
+++ b/src/hb-font.cc
@@ -336,33 +336,28 @@ HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
 #undef HB_FONT_FUNC_IMPLEMENT
 
 
+/* Public getters */
+
 hb_bool_t
 hb_font_get_glyph (hb_font_t *font,
 		   hb_codepoint_t unicode, hb_codepoint_t variation_selector,
 		   hb_codepoint_t *glyph)
 {
-  *glyph = 0;
-  return font->klass->get.glyph (font, font->user_data,
-				 unicode, variation_selector, glyph,
-				 font->klass->user_data.glyph);
+  return font->get_glyph (unicode, variation_selector, glyph);
 }
 
 hb_position_t
 hb_font_get_glyph_h_advance (hb_font_t *font,
 			     hb_codepoint_t glyph)
 {
-  return font->klass->get.glyph_h_advance (font, font->user_data,
-					   glyph,
-					   font->klass->user_data.glyph_h_advance);
+  return font->get_glyph_h_advance (glyph);
 }
 
 hb_position_t
 hb_font_get_glyph_v_advance (hb_font_t *font,
 			     hb_codepoint_t glyph)
 {
-  return font->klass->get.glyph_v_advance (font, font->user_data,
-					   glyph,
-					   font->klass->user_data.glyph_v_advance);
+  return font->get_glyph_v_advance (glyph);
 }
 
 hb_bool_t
@@ -370,10 +365,7 @@ hb_font_get_glyph_h_origin (hb_font_t *font,
 			    hb_codepoint_t glyph,
 			    hb_position_t *x, hb_position_t *y)
 {
-  *x = *y = 0;
-  return font->klass->get.glyph_h_origin (font, font->user_data,
-					   glyph, x, y,
-					   font->klass->user_data.glyph_h_origin);
+  return font->get_glyph_h_origin (glyph, x, y);
 }
 
 hb_bool_t
@@ -381,28 +373,21 @@ hb_font_get_glyph_v_origin (hb_font_t *font,
 			    hb_codepoint_t glyph,
 			    hb_position_t *x, hb_position_t *y)
 {
-  *x = *y = 0;
-  return font->klass->get.glyph_v_origin (font, font->user_data,
-					   glyph, x, y,
-					   font->klass->user_data.glyph_v_origin);
+  return font->get_glyph_v_origin (glyph, x, y);
 }
 
 hb_position_t
 hb_font_get_glyph_h_kerning (hb_font_t *font,
 			     hb_codepoint_t left_glyph, hb_codepoint_t right_glyph)
 {
-  return font->klass->get.glyph_h_kerning (font, font->user_data,
-					   left_glyph, right_glyph,
-					   font->klass->user_data.glyph_h_kerning);
+  return font->get_glyph_h_kerning (left_glyph, right_glyph);
 }
 
 hb_position_t
 hb_font_get_glyph_v_kerning (hb_font_t *font,
 			     hb_codepoint_t left_glyph, hb_codepoint_t right_glyph)
 {
-  return font->klass->get.glyph_v_kerning (font, font->user_data,
-				     left_glyph, right_glyph,
-				     font->klass->user_data.glyph_v_kerning);
+  return font->get_glyph_v_kerning (left_glyph, right_glyph);
 }
 
 hb_bool_t
@@ -410,11 +395,7 @@ hb_font_get_glyph_extents (hb_font_t *font,
 			   hb_codepoint_t glyph,
 			   hb_glyph_extents_t *extents)
 {
-  memset (extents, 0, sizeof (*extents));
-  return font->klass->get.glyph_extents (font, font->user_data,
-					 glyph,
-					 extents,
-					 font->klass->user_data.glyph_extents);
+  return font->get_glyph_extents (glyph, extents);
 }
 
 hb_bool_t
@@ -422,11 +403,7 @@ hb_font_get_glyph_contour_point (hb_font_t *font,
 				 hb_codepoint_t glyph, unsigned int point_index,
 				 hb_position_t *x, hb_position_t *y)
 {
-  *x = *y = 0;
-  return font->klass->get.glyph_contour_point (font, font->user_data,
-					       glyph, point_index,
-					       x, y,
-					       font->klass->user_data.glyph_contour_point);
+  return font->get_glyph_contour_point (glyph, point_index, x, y);
 }
 
 hb_bool_t
@@ -434,10 +411,7 @@ hb_font_get_glyph_name (hb_font_t *font,
 			hb_codepoint_t glyph,
 			char *name, unsigned int size)
 {
-  return font->klass->get.glyph_name (font, font->user_data,
-				      glyph,
-				      name, size,
-				      font->klass->user_data.glyph_name);
+  return font->get_glyph_name (glyph, name, size);
 }
 
 hb_bool_t
@@ -445,10 +419,7 @@ hb_font_get_glyph_from_name (hb_font_t *font,
 			     const char *name, int len, /* -1 means nul-terminated */
 			     hb_codepoint_t *glyph)
 {
-  return font->klass->get.glyph_from_name (font, font->user_data,
-					   name, len,
-					   glyph,
-					   font->klass->user_data.glyph_from_name);
+  return font->get_glyph_from_name (name, len, glyph);
 }
 
 
@@ -460,48 +431,16 @@ hb_font_get_glyph_advance_for_direction (hb_font_t *font,
 					 hb_direction_t direction,
 					 hb_position_t *x, hb_position_t *y)
 {
-  if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) {
-    *x = hb_font_get_glyph_h_advance (font, glyph);
-    *y = 0;
-  } else {
-    *x = 0;
-    *y = hb_font_get_glyph_v_advance (font, glyph);
-  }
-}
-
-static void
-guess_v_origin_minus_h_origin (hb_font_t *font,
-			       hb_codepoint_t glyph,
-			       hb_position_t *x, hb_position_t *y)
-{
-  *x = hb_font_get_glyph_h_advance (font, glyph) / 2;
-
-  /* TODO use font_metics.ascent */
-  *y = font->y_scale;
+  return font->get_glyph_advance_for_direction (glyph, direction, x, y);
 }
 
-
 void
 hb_font_get_glyph_origin_for_direction (hb_font_t *font,
 					hb_codepoint_t glyph,
 					hb_direction_t direction,
 					hb_position_t *x, hb_position_t *y)
 {
-  if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) {
-    hb_bool_t ret = hb_font_get_glyph_h_origin (font, glyph, x, y);
-    if (!ret && (ret = hb_font_get_glyph_v_origin (font, glyph, x, y))) {
-      hb_position_t dx, dy;
-      guess_v_origin_minus_h_origin (font, glyph, &dx, &dy);
-      *x -= dx; *y -= dy;
-    }
-  } else {
-    hb_bool_t ret = hb_font_get_glyph_v_origin (font, glyph, x, y);
-    if (!ret && (ret = hb_font_get_glyph_h_origin (font, glyph, x, y))) {
-      hb_position_t dx, dy;
-      guess_v_origin_minus_h_origin (font, glyph, &dx, &dy);
-      *x += dx; *y += dy;
-    }
-  }
+  return font->get_glyph_origin_for_direction (glyph, direction, x, y);
 }
 
 void
@@ -510,12 +449,7 @@ hb_font_add_glyph_origin_for_direction (hb_font_t *font,
 					hb_direction_t direction,
 					hb_position_t *x, hb_position_t *y)
 {
-  hb_position_t origin_x, origin_y;
-
-  hb_font_get_glyph_origin_for_direction (font, glyph, direction, &origin_x, &origin_y);
-
-  *x += origin_x;
-  *y += origin_y;
+  return font->add_glyph_origin_for_direction (glyph, direction, x, y);
 }
 
 void
@@ -524,12 +458,7 @@ hb_font_subtract_glyph_origin_for_direction (hb_font_t *font,
 					     hb_direction_t direction,
 					     hb_position_t *x, hb_position_t *y)
 {
-  hb_position_t origin_x, origin_y;
-
-  hb_font_get_glyph_origin_for_direction (font, glyph, direction, &origin_x, &origin_y);
-
-  *x -= origin_x;
-  *y -= origin_y;
+  return font->subtract_glyph_origin_for_direction (glyph, direction, x, y);
 }
 
 void
@@ -538,13 +467,7 @@ hb_font_get_glyph_kerning_for_direction (hb_font_t *font,
 					 hb_direction_t direction,
 					 hb_position_t *x, hb_position_t *y)
 {
-  if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) {
-    *x = hb_font_get_glyph_h_kerning (font, first_glyph, second_glyph);
-    *y = 0;
-  } else {
-    *x = 0;
-    *y = hb_font_get_glyph_v_kerning (font, first_glyph, second_glyph);
-  }
+  return font->get_glyph_kerning_for_direction (first_glyph, second_glyph, direction, x, y);
 }
 
 hb_bool_t
@@ -553,12 +476,7 @@ hb_font_get_glyph_extents_for_origin (hb_font_t *font,
 				      hb_direction_t direction,
 				      hb_glyph_extents_t *extents)
 {
-  hb_bool_t ret = hb_font_get_glyph_extents (font, glyph, extents);
-
-  if (ret)
-    hb_font_subtract_glyph_origin_for_direction (font, glyph, direction, &extents->x_bearing, &extents->y_bearing);
-
-  return ret;
+  return font->get_glyph_extents_for_origin (glyph, direction, extents);
 }
 
 hb_bool_t
@@ -567,12 +485,7 @@ hb_font_get_glyph_contour_point_for_origin (hb_font_t *font,
 					    hb_direction_t direction,
 					    hb_position_t *x, hb_position_t *y)
 {
-  hb_bool_t ret = hb_font_get_glyph_contour_point (font, glyph, point_index, x, y);
-
-  if (ret)
-    hb_font_subtract_glyph_origin_for_direction (font, glyph, direction, x, y);
-
-  return ret;
+  return font->get_glyph_contour_point_for_origin (glyph, point_index, direction, x, y);
 }
 
 
@@ -1058,5 +971,3 @@ hb_font_get_ppem (hb_font_t *font,
   if (x_ppem) *x_ppem = font->x_ppem;
   if (y_ppem) *y_ppem = font->y_ppem;
 }
-
-
diff --git a/src/hb-graphite2.cc b/src/hb-graphite2.cc
index 3fa9f79..c14eea5 100644
--- a/src/hb-graphite2.cc
+++ b/src/hb-graphite2.cc
@@ -108,7 +108,7 @@ static const void *hb_gr_get_table (const void *data, unsigned int tag, size_t *
 
 static float hb_gr_get_advance (const void *hb_font, unsigned short gid)
 {
-  return hb_font_get_glyph_h_advance ((hb_font_t *) hb_font, gid);
+  return ((hb_font_t *) font)->get_glyph_h_advance (gid);
 }
 
 static void _hb_gr_face_data_destroy (void *data)
@@ -191,9 +191,7 @@ _hb_gr_font_get_data (hb_font_t *font)
   }
 
   data->grface = _hb_gr_face_get_data (font->face)->grface;
-  int scale;
-  hb_font_get_scale (font, &scale, NULL);
-  data->grfont = gr_make_font_with_advance_fn (scale, font, &hb_gr_get_advance, data->grface);
+  data->grfont = gr_make_font_with_advance_fn (font->x_scale, font, &hb_gr_get_advance, data->grface);
 
 
   if (unlikely (!hb_font_set_user_data (font, &hb_gr_data_key, data,
diff --git a/src/hb-old.cc b/src/hb-old.cc
index dffc206..1d5544b 100644
--- a/src/hb-old.cc
+++ b/src/hb-old.cc
@@ -90,13 +90,13 @@ hb_old_convertStringToGlyphIndices (HB_Font old_font,
   {
     hb_codepoint_t u;
 
-    /* TODO Handle UTF-16.  Ugh */
+    /* XXX Handle UTF-16.  Ugh */
     u = string[i];
 
     if (rightToLeft)
       u = hb_unicode_funcs_get_default ()->mirroring (u);
 
-    hb_font_get_glyph (font, u, 0, &u); /* TODO Variation selectors */
+    font->get_glyph (u, 0, &u); /* TODO Variation selectors */
 
     glyphs[i] = u;
   }
@@ -115,7 +115,7 @@ hb_old_getGlyphAdvances (HB_Font old_font,
   hb_font_t *font = (hb_font_t *) old_font->userData;
 
   for (unsigned int i = 0; i < numGlyphs; i++)
-    advances[i] = hb_font_get_glyph_h_advance (font, glyphs[i]);
+    advances[i] = font->get_glyph_h_advance (glyphs[i]);
 }
 
 static HB_Bool
@@ -147,13 +147,13 @@ hb_old_getGlyphMetrics (HB_Font old_font,
 
   hb_glyph_extents_t extents;
 
-  hb_font_get_glyph_extents (font, glyph, &extents);
+  font->get_glyph_extents (glyph, &extents);
 
   metrics->x       = extents.x_bearing;
   metrics->y       = extents.y_bearing;
   metrics->width   = extents.width;
   metrics->height  = -extents.height;
-  metrics->xOffset = hb_font_get_glyph_h_advance (font, glyph);
+  metrics->xOffset = font->get_glyph_h_advance (glyph);
   metrics->yOffset = 0;
 }
 
diff --git a/src/hb-ot-layout-gdef-table.hh b/src/hb-ot-layout-gdef-table.hh
index 54149d7..cebbe68 100644
--- a/src/hb-ot-layout-gdef-table.hh
+++ b/src/hb-ot-layout-gdef-table.hh
@@ -119,7 +119,7 @@ struct CaretValueFormat2
   inline hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction, hb_codepoint_t glyph_id) const
   {
     hb_position_t x, y;
-    if (hb_font_get_glyph_contour_point_for_origin (font, glyph_id, caretValuePoint, direction, &x, &y))
+    if (font->get_glyph_contour_point_for_origin (glyph_id, caretValuePoint, direction, &x, &y))
       return HB_DIRECTION_IS_HORIZONTAL (direction) ? x : y;
     else
       return 0;
diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh
index 2e8a389..cffbd25 100644
--- a/src/hb-ot-layout-gpos-table.hh
+++ b/src/hb-ot-layout-gpos-table.hh
@@ -247,7 +247,7 @@ struct AnchorFormat2
       hb_bool_t ret = false;
 
       if (x_ppem || y_ppem)
-	ret = hb_font_get_glyph_contour_point_for_origin (font, glyph_id, anchorPoint, HB_DIRECTION_LTR, &cx, &cy);
+	ret = font->get_glyph_contour_point_for_origin (glyph_id, anchorPoint, HB_DIRECTION_LTR, &cx, &cy);
       *x = x_ppem && ret ? cx : font->em_scale_x (xCoordinate);
       *y = y_ppem && ret ? cy : font->em_scale_y (yCoordinate);
   }
diff --git a/src/hb-ot-shape-complex-arabic.cc b/src/hb-ot-shape-complex-arabic.cc
index 39b25c3..4ce09a8 100644
--- a/src/hb-ot-shape-complex-arabic.cc
+++ b/src/hb-ot-shape-complex-arabic.cc
@@ -211,7 +211,7 @@ arabic_fallback_shape (hb_font_t *font, hb_buffer_t *buffer)
   for (unsigned int i = 0; i < count; i++) {
     hb_codepoint_t u = buffer->info[i].codepoint;
     hb_codepoint_t shaped = get_arabic_shape (u, buffer->info[i].arabic_shaping_action());
-    if (shaped != u && hb_font_get_glyph (font, shaped, 0, &glyph))
+    if (shaped != u && font->get_glyph (shaped, 0, &glyph))
       buffer->info[i].codepoint = shaped;
   }
 
@@ -220,7 +220,7 @@ arabic_fallback_shape (hb_font_t *font, hb_buffer_t *buffer)
   for (buffer->idx = 0; buffer->idx + 1 < count;) {
     hb_codepoint_t ligature = get_ligature (buffer->cur().codepoint,
 					    buffer->cur(+1).codepoint);
-    if (likely (!ligature) || !(hb_font_get_glyph (font, ligature, 0, &glyph))) {
+    if (likely (!ligature) || !(font->get_glyph (ligature, 0, &glyph))) {
       buffer->next_glyph ();
       continue;
     }
diff --git a/src/hb-ot-shape-complex-indic.cc b/src/hb-ot-shape-complex-indic.cc
index 15af692..255e00e 100644
--- a/src/hb-ot-shape-complex-indic.cc
+++ b/src/hb-ot-shape-complex-indic.cc
@@ -130,10 +130,10 @@ consonant_position (hb_codepoint_t     u,
   hb_codepoint_t glyphs[2];
 
   unsigned int virama_pos = IS_OLD_INDIC_TAG (map->get_chosen_script (0)) ? 1 : 0;
-  hb_font_get_glyph (font, virama, 0, &glyphs[virama_pos]);
-  hb_font_get_glyph (font, u,      0, &glyphs[1-virama_pos]);
+  font->get_glyph (virama, 0, &glyphs[virama_pos]);
+  font->get_glyph (u,      0, &glyphs[1-virama_pos]);
 
-  hb_face_t *face = hb_font_get_face (font);
+  hb_face_t *face = font->face;
   if (would_substitute (glyphs, ARRAY_LENGTH (glyphs), HB_TAG('p','r','e','f'), map, face)) return POS_BELOW_C;
   if (would_substitute (glyphs, ARRAY_LENGTH (glyphs), HB_TAG('b','l','w','f'), map, face)) return POS_BELOW_C;
   if (would_substitute (glyphs, ARRAY_LENGTH (glyphs), HB_TAG('p','s','t','f'), map, face)) return POS_POST_C;
diff --git a/src/hb-ot-shape-normalize.cc b/src/hb-ot-shape-normalize.cc
index fbfe88b..bc1df54 100644
--- a/src/hb-ot-shape-normalize.cc
+++ b/src/hb-ot-shape-normalize.cc
@@ -96,10 +96,10 @@ decompose (hb_font_t *font, hb_buffer_t *buffer,
   hb_codepoint_t a, b, glyph;
 
   if (!buffer->unicode->decompose (ab, &a, &b) ||
-      (b && !hb_font_get_glyph (font, b, 0, &glyph)))
+      (b && !font->get_glyph (b, 0, &glyph)))
     return false;
 
-  bool has_a = hb_font_get_glyph (font, a, 0, &glyph);
+  bool has_a = font->get_glyph (a, 0, &glyph);
   if (shortest && has_a) {
     /* Output a and b */
     output_glyph (buffer, a);
@@ -137,7 +137,7 @@ decompose_compatibility (hb_font_t *font, hb_buffer_t *buffer,
 
   hb_codepoint_t glyph;
   for (i = 0; i < len; i++)
-    if (!hb_font_get_glyph (font, decomposed[i], 0, &glyph))
+    if (!font->get_glyph (decomposed[i], 0, &glyph))
       return false;
 
   for (i = 0; i < len; i++)
@@ -153,11 +153,11 @@ decompose_current_character (hb_font_t *font, hb_buffer_t *buffer,
   hb_codepoint_t glyph;
 
   /* Kind of a cute waterfall here... */
-  if (shortest && hb_font_get_glyph (font, buffer->cur().codepoint, 0, &glyph))
+  if (shortest && font->get_glyph (buffer->cur().codepoint, 0, &glyph))
     buffer->next_glyph ();
   else if (decompose (font, buffer, shortest, buffer->cur().codepoint))
     buffer->skip_glyph ();
-  else if (!shortest && hb_font_get_glyph (font, buffer->cur().codepoint, 0, &glyph))
+  else if (!shortest && font->get_glyph (buffer->cur().codepoint, 0, &glyph))
     buffer->next_glyph ();
   else if (decompose_compatibility (font, buffer, buffer->cur().codepoint))
     buffer->skip_glyph ();
@@ -285,7 +285,7 @@ _hb_ot_shape_normalize (hb_font_t *font, hb_buffer_t *buffer,
 				  buffer->cur().codepoint,
 				  &composed) &&
 	/* And the font has glyph for the composite. */
-	hb_font_get_glyph (font, composed, 0, &glyph))
+	font->get_glyph (composed, 0, &glyph))
     {
       /* Composes. */
       buffer->next_glyph (); /* Copy to out-buffer. */
diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc
index e254f56..755999b 100644
--- a/src/hb-ot-shape.cc
+++ b/src/hb-ot-shape.cc
@@ -328,15 +328,15 @@ hb_map_glyphs (hb_font_t    *font,
   unsigned int count = buffer->len - 1;
   for (buffer->idx = 0; buffer->idx < count;) {
     if (unlikely (buffer->unicode->is_variation_selector (buffer->cur(+1).codepoint))) {
-      hb_font_get_glyph (font, buffer->cur().codepoint, buffer->cur(+1).codepoint, &glyph);
+      font->get_glyph (buffer->cur().codepoint, buffer->cur(+1).codepoint, &glyph);
       buffer->replace_glyphs (2, 1, &glyph);
     } else {
-      hb_font_get_glyph (font, buffer->cur().codepoint, 0, &glyph);
+      font->get_glyph (buffer->cur().codepoint, 0, &glyph);
       buffer->replace_glyph (glyph);
     }
   }
   if (likely (buffer->idx < buffer->len)) {
-    hb_font_get_glyph (font, buffer->cur().codepoint, 0, &glyph);
+    font->get_glyph (buffer->cur().codepoint, 0, &glyph);
     buffer->replace_glyph (glyph);
   }
   buffer->swap_buffers ();
@@ -390,14 +390,14 @@ hb_position_default (hb_ot_shape_context_t *c)
 
   unsigned int count = c->buffer->len;
   for (unsigned int i = 0; i < count; i++) {
-    hb_font_get_glyph_advance_for_direction (c->font, c->buffer->info[i].codepoint,
-					     c->buffer->props.direction,
-					     &c->buffer->pos[i].x_advance,
-					     &c->buffer->pos[i].y_advance);
-    hb_font_subtract_glyph_origin_for_direction (c->font, c->buffer->info[i].codepoint,
-						 c->buffer->props.direction,
-						 &c->buffer->pos[i].x_offset,
-						 &c->buffer->pos[i].y_offset);
+    c->font->get_glyph_advance_for_direction (c->buffer->info[i].codepoint,
+					      c->buffer->props.direction,
+					      &c->buffer->pos[i].x_advance,
+					      &c->buffer->pos[i].y_advance);
+    c->font->subtract_glyph_origin_for_direction (c->buffer->info[i].codepoint,
+						  c->buffer->props.direction,
+						  &c->buffer->pos[i].x_offset,
+						  &c->buffer->pos[i].y_offset);
   }
 }
 
@@ -423,19 +423,19 @@ hb_ot_position_complex (hb_ot_shape_context_t *c)
 
     unsigned int count = c->buffer->len;
     for (unsigned int i = 0; i < count; i++) {
-      hb_font_add_glyph_origin_for_direction (c->font, c->buffer->info[i].codepoint,
-					      HB_DIRECTION_LTR,
-					      &c->buffer->pos[i].x_offset,
-					      &c->buffer->pos[i].y_offset);
+      c->font->add_glyph_origin_for_direction (c->buffer->info[i].codepoint,
+					       HB_DIRECTION_LTR,
+					       &c->buffer->pos[i].x_offset,
+					       &c->buffer->pos[i].y_offset);
     }
 
     c->plan->map.position (c->font, c->buffer);
 
     for (unsigned int i = 0; i < count; i++) {
-      hb_font_subtract_glyph_origin_for_direction (c->font, c->buffer->info[i].codepoint,
-						   HB_DIRECTION_LTR,
-						   &c->buffer->pos[i].x_offset,
-						   &c->buffer->pos[i].y_offset);
+      c->font->subtract_glyph_origin_for_direction (c->buffer->info[i].codepoint,
+						    HB_DIRECTION_LTR,
+						    &c->buffer->pos[i].x_offset,
+						    &c->buffer->pos[i].y_offset);
     }
 
     c->applied_position_complex = true;
@@ -460,10 +460,9 @@ hb_truetype_kern (hb_ot_shape_context_t *c)
   unsigned int count = c->buffer->len;
   for (unsigned int i = 1; i < count; i++) {
     hb_position_t x_kern, y_kern, kern1, kern2;
-    hb_font_get_glyph_kerning_for_direction (c->font,
-					     c->buffer->info[i - 1].codepoint, c->buffer->info[i].codepoint,
-					     c->buffer->props.direction,
-					     &x_kern, &y_kern);
+    c->font->get_glyph_kerning_for_direction (c->buffer->info[i - 1].codepoint, c->buffer->info[i].codepoint,
+					      c->buffer->props.direction,
+					      &x_kern, &y_kern);
 
     kern1 = x_kern >> 1;
     kern2 = x_kern - kern1;
@@ -489,7 +488,7 @@ static void
 hb_hide_zerowidth (hb_ot_shape_context_t *c)
 {
   hb_codepoint_t space;
-  if (!hb_font_get_glyph (c->font, ' ', 0, &space))
+  if (!c->font->get_glyph (' ', 0, &space))
     return; /* No point! */
 
   unsigned int count = c->buffer->len;
commit 6adf417bc15d4524e280b284e3accd1ae647662e
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Wed Aug 1 18:07:42 2012 -0400

    Use a lookup table for modified_combining_class

diff --git a/src/hb-unicode-private.hh b/src/hb-unicode-private.hh
index 14d8131..5c5fff9 100644
--- a/src/hb-unicode-private.hh
+++ b/src/hb-unicode-private.hh
@@ -1,7 +1,7 @@
 /*
  * Copyright © 2009  Red Hat, Inc.
  * Copyright © 2011  Codethink Limited
- * Copyright © 2010,2011  Google, Inc.
+ * Copyright © 2010,2011,2012  Google, Inc.
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
@@ -37,6 +37,7 @@
 #include "hb-object-private.hh"
 
 
+extern HB_INTERNAL const uint8_t _hb_modified_combining_class[256];
 
 /*
  * hb_unicode_funcs_t
@@ -143,8 +144,11 @@ HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE
   }
 
 
-  HB_INTERNAL unsigned int
-  modified_combining_class (hb_codepoint_t unicode);
+  unsigned int
+  modified_combining_class (hb_codepoint_t unicode)
+  {
+    return _hb_modified_combining_class[combining_class (unicode)];
+  }
 
   inline hb_bool_t
   is_variation_selector (hb_codepoint_t unicode)
diff --git a/src/hb-unicode.cc b/src/hb-unicode.cc
index b1bd147..f4eae0d 100644
--- a/src/hb-unicode.cc
+++ b/src/hb-unicode.cc
@@ -1,7 +1,7 @@
 /*
  * Copyright © 2009  Red Hat, Inc.
- * Copyright © 2011 Codethink Limited
- * Copyright © 2010,2011  Google, Inc.
+ * Copyright © 2011  Codethink Limited
+ * Copyright © 2010,2011,2012  Google, Inc.
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
@@ -287,69 +287,148 @@ hb_unicode_decompose_compatibility (hb_unicode_funcs_t *ufuncs,
 }
 
 
-unsigned int
-hb_unicode_funcs_t::modified_combining_class (hb_codepoint_t unicode)
+const uint8_t
+_hb_modified_combining_class[256] =
 {
-  int c = combining_class (unicode);
-
-  if (unlikely (hb_in_range<int> (c, 27, 33)))
-  {
-    /* Modify the combining-class to suit Arabic better.  See:
-     * http://unicode.org/faq/normalization.html#8
-     * http://unicode.org/faq/normalization.html#9
-     */
-    c = c == 33 ? 27 : c + 1;
-  }
-  else if (unlikely (hb_in_range<int> (c, 10, 26)))
-  {
-    /* The equivalent fix for Hebrew is more complex.
-     *
-     * We permute the "fixed-position" classes 10-26 into the order
-     * described in the SBL Hebrew manual:
-     *
-     * http://www.sbl-site.org/Fonts/SBLHebrewUserManual1.5x.pdf
-     *
-     * (as recommended by:
-     *  http://forum.fontlab.com/archive-old-microsoft-volt-group/vista-and-diacritic-ordering-t6751.0.html)
-     *
-     * More details here:
-     * https://bugzilla.mozilla.org/show_bug.cgi?id=662055
-     */
-    static const int permuted_hebrew_classes[26 - 10 + 1] = {
-      /* 10 sheva */        22,
-      /* 11 hataf segol */  15,
-      /* 12 hataf patah */  16,
-      /* 13 hataf qamats */ 17,
-      /* 14 hiriq */        23,
-      /* 15 tsere */        18,
-      /* 16 segol */        19,
-      /* 17 patah */        20,
-      /* 18 qamats */       21,
-      /* 19 holam */        14,
-      /* 20 qubuts */       24,
-      /* 21 dagesh */       12,
-      /* 22 meteg */        25,
-      /* 23 rafe */         13,
-      /* 24 shin dot */     10,
-      /* 25 sin dot */      11,
-      /* 26 point varika */ 26,
-    };
-    c = permuted_hebrew_classes[c - 10];
-  }
-  else if (unlikely (unicode == 0x0E3A)) /* THAI VOWEL SIGN PHINTHU */
-  {
-    /* Assign 104, so it reorders after the THAI ccc=103 marks.
-     * Uniscribe does this. */
-    c = 104;
-  }
-  else if (unlikely (hb_in_range<hb_codepoint_t> (unicode, 0x0C55, 0x0C56)))
-  {
-    /* Telugu length marks.
-     * These are the only matras in the main Indic script range that have
-     * a non-zero ccc.  That makes them reorder with the Halant that is
-     * ccc=9.  Just zero them, we don't need them in our Indic shaper. */
-    c = 0;
-  }
-
-  return c;
-}
+  0, /* HB_UNICODE_COMBINING_CLASS_NOT_REORDERED */
+  1, /* HB_UNICODE_COMBINING_CLASS_OVERLAY */
+  2, 3, 4, 5, 6,
+  7, /* HB_UNICODE_COMBINING_CLASS_NUKTA */
+  8, /* HB_UNICODE_COMBINING_CLASS_KANA_VOICING */
+  9, /* HB_UNICODE_COMBINING_CLASS_VIRAMA */
+
+  /* Hebrew */
+
+  /*
+   * We permute the "fixed-position" classes 10-26 into the order
+   * described in the SBL Hebrew manual:
+   *
+   * http://www.sbl-site.org/Fonts/SBLHebrewUserManual1.5x.pdf
+   *
+   * (as recommended by:
+   *  http://forum.fontlab.com/archive-old-microsoft-volt-group/vista-and-diacritic-ordering-t6751.0.html)
+   *
+   * More details here:
+   * https://bugzilla.mozilla.org/show_bug.cgi?id=662055
+   */
+  22, /* HB_UNICODE_COMBINING_CLASS_CCC10 sheva */
+  15, /* HB_UNICODE_COMBINING_CLASS_CCC11 hataf segol */
+  16, /* HB_UNICODE_COMBINING_CLASS_CCC12 hataf patah*/
+  17, /* HB_UNICODE_COMBINING_CLASS_CCC13 hataf qamats */
+  23, /* HB_UNICODE_COMBINING_CLASS_CCC14 hiriq */
+  18, /* HB_UNICODE_COMBINING_CLASS_CCC15 tsere */
+  19, /* HB_UNICODE_COMBINING_CLASS_CCC16 segol */
+  20, /* HB_UNICODE_COMBINING_CLASS_CCC17 patah */
+  21, /* HB_UNICODE_COMBINING_CLASS_CCC18 qamats */
+  14, /* HB_UNICODE_COMBINING_CLASS_CCC19 holam */
+  24, /* HB_UNICODE_COMBINING_CLASS_CCC20 qubuts */
+  12, /* HB_UNICODE_COMBINING_CLASS_CCC21 dagesh */
+  25, /* HB_UNICODE_COMBINING_CLASS_CCC22 meteg */
+  13, /* HB_UNICODE_COMBINING_CLASS_CCC23 rafe */
+  10, /* HB_UNICODE_COMBINING_CLASS_CCC24 shin dot */
+  11, /* HB_UNICODE_COMBINING_CLASS_CCC25 sin dot */
+
+  26, /* HB_UNICODE_COMBINING_CLASS_CCC26 */
+
+  /* Arabic */
+
+  /*
+   * Modify to move Shadda (ccc=33) before other marks.  See:
+   * http://unicode.org/faq/normalization.html#8
+   * http://unicode.org/faq/normalization.html#9
+   */
+  28, /* HB_UNICODE_COMBINING_CLASS_CCC27 */
+  29, /* HB_UNICODE_COMBINING_CLASS_CCC28 */
+  30, /* HB_UNICODE_COMBINING_CLASS_CCC29 */
+  31, /* HB_UNICODE_COMBINING_CLASS_CCC30 */
+  32, /* HB_UNICODE_COMBINING_CLASS_CCC31 */
+  33, /* HB_UNICODE_COMBINING_CLASS_CCC32 */
+  27, /* HB_UNICODE_COMBINING_CLASS_CCC33 shadda */
+
+  34, /* HB_UNICODE_COMBINING_CLASS_CCC34 */
+  35, /* HB_UNICODE_COMBINING_CLASS_CCC35 */
+
+  /* Syriac */
+  36, /* HB_UNICODE_COMBINING_CLASS_CCC36 */
+
+  37, 38, 39,
+  40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
+  60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+  80, 81, 82, 83,
+
+  /* Telugu */
+
+  /*
+   * Modify Telugu length marks (ccc=84, ccc=91).
+   * These are the only matras in the main Indic scripts range that have
+   * a non-zero ccc.  That makes them reorder with the Halant that is
+   * ccc=9.  Just zero them, we don't need them in our Indic shaper.
+   */
+  0, /* HB_UNICODE_COMBINING_CLASS_CCC84 */
+  85, 86, 87, 88, 89, 90,
+  0, /* HB_UNICODE_COMBINING_CLASS_CCC91 */
+  92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102,
+
+  /* Thai */
+
+  /*
+   * Modify U+0E38 and U+0E39 (ccc=104) to be reordered before U+0E3A (ccc=9).
+   * Uniscribe does this too.
+   */
+  3, /* HB_UNICODE_COMBINING_CLASS_CCC103 */
+
+  104, 105, 106,
+  107, /* HB_UNICODE_COMBINING_CLASS_CCC107 */
+  108, 109, 110, 111, 112, 113, 114, 115, 116, 117,
+
+  /* Lao */
+  118, /* HB_UNICODE_COMBINING_CLASS_CCC118 */
+  119, 120, 121,
+  122, /* HB_UNICODE_COMBINING_CLASS_CCC122 */
+  123, 124, 125, 126, 127, 128,
+
+  /* Tibetan */
+  129, /* HB_UNICODE_COMBINING_CLASS_CCC129 */
+  130, /* HB_UNICODE_COMBINING_CLASS_CCC130 */
+  131,
+  132, /* HB_UNICODE_COMBINING_CLASS_CCC133 */
+  133, 134, 135, 136, 137, 138, 139,
+
+
+  140, 141, 142, 143, 144, 145, 146, 147, 148, 149,
+  150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
+  160, 161, 162, 163, 164, 165, 166, 167, 168, 169,
+  170, 171, 172, 173, 174, 175, 176, 177, 178, 179,
+  180, 181, 182, 183, 184, 185, 186, 187, 188, 189,
+  190, 191, 192, 193, 194, 195, 196, 197, 198, 199,
+
+  200, /* HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW_LEFT */
+  201,
+  202, /* HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW */
+  203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213,
+  214, /* HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE */
+  215,
+  216, /* HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE_RIGHT */
+  217,
+  218, /* HB_UNICODE_COMBINING_CLASS_BELOW_LEFT */
+  219,
+  220, /* HB_UNICODE_COMBINING_CLASS_BELOW */
+  221,
+  222, /* HB_UNICODE_COMBINING_CLASS_BELOW_RIGHT */
+  223,
+  224, /* HB_UNICODE_COMBINING_CLASS_LEFT */
+  225,
+  226, /* HB_UNICODE_COMBINING_CLASS_RIGHT */
+  227,
+  228, /* HB_UNICODE_COMBINING_CLASS_ABOVE_LEFT */
+  229,
+  230, /* HB_UNICODE_COMBINING_CLASS_ABOVE */
+  231,
+  232, /* HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT */
+  233, /* HB_UNICODE_COMBINING_CLASS_DOUBLE_BELOW */
+  234, /* HB_UNICODE_COMBINING_CLASS_DOUBLE_ABOVE */
+  235, 236, 237, 238, 239,
+  240, /* HB_UNICODE_COMBINING_CLASS_IOTA_SUBSCRIPT */
+  241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254,
+  255, /* HB_UNICODE_COMBINING_CLASS_INVALID */
+};
diff --git a/src/hb-unicode.h b/src/hb-unicode.h
index 47084da..2e10d98 100644
--- a/src/hb-unicode.h
+++ b/src/hb-unicode.h
@@ -79,6 +79,10 @@ typedef enum
 
 /* hb_unicode_combining_class_t */
 
+/* Note: newer versions of Unicode may add new values.  Clients should be ready to handle
+ * any value in the 0..254 range being returned from hb_unicode_combining_class().
+ */
+
 /* Unicode Character Database property: Canonical_Combining_Class (ccc) */
 typedef enum
 {
commit 208f70f0553d73d2908b21b9552298029482a8b9
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Wed Aug 1 17:13:10 2012 -0400

    Inline Unicode callbacks internally

diff --git a/src/hb-buffer.cc b/src/hb-buffer.cc
index b9623e8..db4edce 100644
--- a/src/hb-buffer.cc
+++ b/src/hb-buffer.cc
@@ -456,7 +456,7 @@ hb_buffer_t::guess_properties (void)
   /* If script is set to INVALID, guess from buffer contents */
   if (props.script == HB_SCRIPT_INVALID) {
     for (unsigned int i = 0; i < len; i++) {
-      hb_script_t script = hb_unicode_script (unicode, info[i].codepoint);
+      hb_script_t script = unicode->script (info[i].codepoint);
       if (likely (script != HB_SCRIPT_COMMON &&
 		  script != HB_SCRIPT_INHERITED &&
 		  script != HB_SCRIPT_UNKNOWN)) {
diff --git a/src/hb-fallback-shape.cc b/src/hb-fallback-shape.cc
index 52b46b1..ad7c88c 100644
--- a/src/hb-fallback-shape.cc
+++ b/src/hb-fallback-shape.cc
@@ -106,7 +106,7 @@ _hb_fallback_shape (hb_shape_plan_t    *shape_plan,
 
   for (unsigned int i = 0; i < count; i++)
   {
-    if (_hb_unicode_is_zero_width (buffer->info[i].codepoint)) {
+    if (buffer->unicode->is_zero_width (buffer->info[i].codepoint)) {
       buffer->info[i].codepoint = space;
       buffer->pos[i].x_advance = 0;
       buffer->pos[i].y_advance = 0;
diff --git a/src/hb-old.cc b/src/hb-old.cc
index 9d1a005..dffc206 100644
--- a/src/hb-old.cc
+++ b/src/hb-old.cc
@@ -94,7 +94,7 @@ hb_old_convertStringToGlyphIndices (HB_Font old_font,
     u = string[i];
 
     if (rightToLeft)
-      u = hb_unicode_mirroring (hb_unicode_funcs_get_default (), u);
+      u = hb_unicode_funcs_get_default ()->mirroring (u);
 
     hb_font_get_glyph (font, u, 0, &u); /* TODO Variation selectors */
 
diff --git a/src/hb-ot-shape-complex-misc.cc b/src/hb-ot-shape-complex-misc.cc
index a9dda94..06b873a 100644
--- a/src/hb-ot-shape-complex-misc.cc
+++ b/src/hb-ot-shape-complex-misc.cc
@@ -124,7 +124,7 @@ setup_masks_thai (const hb_ot_complex_shaper_t *shaper,
    *
    * Uniscribe also does so below-marks reordering.  Namely, it positions U+0E3A
    * after U+0E38 and U+0E39.  We do that by modifying the ccc for U+0E3A.
-   * See _hb_unicode_modified_combining_class ().  Lao does NOT have a U+0E3A
+   * See unicode->modified_combining_class ().  Lao does NOT have a U+0E3A
    * equivalent.
    */
 
diff --git a/src/hb-ot-shape-normalize.cc b/src/hb-ot-shape-normalize.cc
index 17a9ac8..fbfe88b 100644
--- a/src/hb-ot-shape-normalize.cc
+++ b/src/hb-ot-shape-normalize.cc
@@ -95,7 +95,7 @@ decompose (hb_font_t *font, hb_buffer_t *buffer,
 {
   hb_codepoint_t a, b, glyph;
 
-  if (!hb_unicode_decompose (buffer->unicode, ab, &a, &b) ||
+  if (!buffer->unicode->decompose (ab, &a, &b) ||
       (b && !hb_font_get_glyph (font, b, 0, &glyph)))
     return false;
 
@@ -131,7 +131,7 @@ decompose_compatibility (hb_font_t *font, hb_buffer_t *buffer,
   unsigned int len, i;
   hb_codepoint_t decomposed[HB_UNICODE_MAX_DECOMPOSITION_LEN];
 
-  len = hb_unicode_decompose_compatibility (buffer->unicode, u, decomposed);
+  len = buffer->unicode->decompose_compatibility (u, decomposed);
   if (!len)
     return false;
 
@@ -171,7 +171,7 @@ decompose_multi_char_cluster (hb_font_t *font, hb_buffer_t *buffer,
 {
   /* TODO Currently if there's a variation-selector we give-up, it's just too hard. */
   for (unsigned int i = buffer->idx; i < end; i++)
-    if (unlikely (_hb_unicode_is_variation_selector (buffer->info[i].codepoint))) {
+    if (unlikely (buffer->unicode->is_variation_selector (buffer->info[i].codepoint))) {
       while (buffer->idx < end)
 	buffer->next_glyph ();
       return;
@@ -281,10 +281,9 @@ _hb_ot_shape_normalize (hb_font_t *font, hb_buffer_t *buffer,
 	(starter == buffer->out_len - 1 ||
 	 _hb_glyph_info_get_modified_combining_class (&buffer->prev()) < _hb_glyph_info_get_modified_combining_class (&buffer->cur())) &&
 	/* And compose. */
-	hb_unicode_compose (buffer->unicode,
-			    buffer->out_info[starter].codepoint,
-			    buffer->cur().codepoint,
-			    &composed) &&
+	buffer->unicode->compose (buffer->out_info[starter].codepoint,
+				  buffer->cur().codepoint,
+				  &composed) &&
 	/* And the font has glyph for the composite. */
 	hb_font_get_glyph (font, composed, 0, &glyph))
     {
diff --git a/src/hb-ot-shape-private.hh b/src/hb-ot-shape-private.hh
index 30c7808..fd45e2d 100644
--- a/src/hb-ot-shape-private.hh
+++ b/src/hb-ot-shape-private.hh
@@ -43,9 +43,9 @@ struct hb_ot_shape_plan_t
 inline void
 _hb_glyph_info_set_unicode_props (hb_glyph_info_t *info, hb_unicode_funcs_t *unicode)
 {
-  info->unicode_props0() = ((unsigned int) hb_unicode_general_category (unicode, info->codepoint)) |
-			   (_hb_unicode_is_zero_width (info->codepoint) ? 0x80 : 0);
-  info->unicode_props1() = _hb_unicode_modified_combining_class (unicode, info->codepoint);
+  info->unicode_props0() = ((unsigned int) unicode->general_category (info->codepoint)) |
+			   (unicode->is_zero_width (info->codepoint) ? 0x80 : 0);
+  info->unicode_props1() = unicode->modified_combining_class (info->codepoint);
 }
 
 inline hb_unicode_general_category_t
diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc
index 11bc74f..e254f56 100644
--- a/src/hb-ot-shape.cc
+++ b/src/hb-ot-shape.cc
@@ -306,7 +306,7 @@ hb_mirror_chars (hb_ot_shape_context_t *c)
 
   unsigned int count = c->buffer->len;
   for (unsigned int i = 0; i < count; i++) {
-    hb_codepoint_t codepoint = hb_unicode_mirroring (unicode, c->buffer->info[i].codepoint);
+    hb_codepoint_t codepoint = unicode->mirroring (c->buffer->info[i].codepoint);
     if (likely (codepoint == c->buffer->info[i].codepoint))
       c->buffer->info[i].mask |= rtlm_mask; /* XXX this should be moved to before setting user-feature masks */
     else
@@ -327,7 +327,7 @@ hb_map_glyphs (hb_font_t    *font,
 
   unsigned int count = buffer->len - 1;
   for (buffer->idx = 0; buffer->idx < count;) {
-    if (unlikely (_hb_unicode_is_variation_selector (buffer->cur(+1).codepoint))) {
+    if (unlikely (buffer->unicode->is_variation_selector (buffer->cur(+1).codepoint))) {
       hb_font_get_glyph (font, buffer->cur().codepoint, buffer->cur(+1).codepoint, &glyph);
       buffer->replace_glyphs (2, 1, &glyph);
     } else {
diff --git a/src/hb-unicode-private.hh b/src/hb-unicode-private.hh
index 9185392..14d8131 100644
--- a/src/hb-unicode-private.hh
+++ b/src/hb-unicode-private.hh
@@ -143,6 +143,62 @@ HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE
   }
 
 
+  HB_INTERNAL unsigned int
+  modified_combining_class (hb_codepoint_t unicode);
+
+  inline hb_bool_t
+  is_variation_selector (hb_codepoint_t unicode)
+  {
+    return unlikely (hb_in_ranges<hb_codepoint_t> (unicode,
+						   0x180B, 0x180D, /* MONGOLIAN FREE VARIATION SELECTOR ONE..THREE */
+						   0xFE00, 0xFE0F, /* VARIATION SELECTOR-1..16 */
+						   0xE0100, 0xE01EF));  /* VARIATION SELECTOR-17..256 */
+  }
+
+  /* Zero-Width invisible characters:
+   *
+   *  00AD  SOFT HYPHEN
+   *  034F  COMBINING GRAPHEME JOINER
+   *
+   *  180E  MONGOLIAN VOWEL SEPARATOR
+   *
+   *  200B  ZERO WIDTH SPACE
+   *  200C  ZERO WIDTH NON-JOINER
+   *  200D  ZERO WIDTH JOINER
+   *  200E  LEFT-TO-RIGHT MARK
+   *  200F  RIGHT-TO-LEFT MARK
+   *
+   *  2028  LINE SEPARATOR
+   *
+   *  202A  LEFT-TO-RIGHT EMBEDDING
+   *  202B  RIGHT-TO-LEFT EMBEDDING
+   *  202C  POP DIRECTIONAL FORMATTING
+   *  202D  LEFT-TO-RIGHT OVERRIDE
+   *  202E  RIGHT-TO-LEFT OVERRIDE
+   *
+   *  2060  WORD JOINER
+   *  2061  FUNCTION APPLICATION
+   *  2062  INVISIBLE TIMES
+   *  2063  INVISIBLE SEPARATOR
+   *
+   *  FEFF  ZERO WIDTH NO-BREAK SPACE
+   */
+  inline hb_bool_t
+  is_zero_width (hb_codepoint_t ch)
+  {
+    return ((ch & ~0x007F) == 0x2000 && (hb_in_ranges<hb_codepoint_t> (ch,
+								       0x200B, 0x200F,
+								       0x202A, 0x202E,
+								       0x2060, 0x2064) ||
+					 (ch == 0x2028))) ||
+	    unlikely (ch == 0x0009 ||
+		      ch == 0x00AD ||
+		      ch == 0x034F ||
+		      ch == 0x180E ||
+		      ch == 0xFEFF);
+  }
+
+
   struct {
 #define HB_UNICODE_FUNC_IMPLEMENT(name) hb_unicode_##name##_func_t name;
     HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS
@@ -176,60 +232,4 @@ extern HB_INTERNAL const hb_unicode_funcs_t _hb_unicode_funcs_nil;
 #endif
 
 
-HB_INTERNAL unsigned int
-_hb_unicode_modified_combining_class (hb_unicode_funcs_t *ufuncs,
-				      hb_codepoint_t      unicode);
-
-static inline hb_bool_t
-_hb_unicode_is_variation_selector (hb_codepoint_t unicode)
-{
-  return unlikely (hb_in_ranges<hb_codepoint_t> (unicode,
-						 0x180B, 0x180D, /* MONGOLIAN FREE VARIATION SELECTOR ONE..THREE */
-						 0xFE00, 0xFE0F, /* VARIATION SELECTOR-1..16 */
-						 0xE0100, 0xE01EF));  /* VARIATION SELECTOR-17..256 */
-}
-
-/* Zero-Width invisible characters:
- *
- *  00AD  SOFT HYPHEN
- *  034F  COMBINING GRAPHEME JOINER
- *
- *  180E  MONGOLIAN VOWEL SEPARATOR
- *
- *  200B  ZERO WIDTH SPACE
- *  200C  ZERO WIDTH NON-JOINER
- *  200D  ZERO WIDTH JOINER
- *  200E  LEFT-TO-RIGHT MARK
- *  200F  RIGHT-TO-LEFT MARK
- *
- *  2028  LINE SEPARATOR
- *
- *  202A  LEFT-TO-RIGHT EMBEDDING
- *  202B  RIGHT-TO-LEFT EMBEDDING
- *  202C  POP DIRECTIONAL FORMATTING
- *  202D  LEFT-TO-RIGHT OVERRIDE
- *  202E  RIGHT-TO-LEFT OVERRIDE
- *
- *  2060  WORD JOINER
- *  2061  FUNCTION APPLICATION
- *  2062  INVISIBLE TIMES
- *  2063  INVISIBLE SEPARATOR
- *
- *  FEFF  ZERO WIDTH NO-BREAK SPACE
- */
-static inline hb_bool_t
-_hb_unicode_is_zero_width (hb_codepoint_t ch)
-{
-  return ((ch & ~0x007F) == 0x2000 && (hb_in_ranges<hb_codepoint_t> (ch,
-								     0x200B, 0x200F,
-								     0x202A, 0x202E,
-								     0x2060, 0x2064) ||
-				       (ch == 0x2028))) ||
-	  unlikely (ch == 0x0009 ||
-		    ch == 0x00AD ||
-		    ch == 0x034F ||
-		    ch == 0x180E ||
-		    ch == 0xFEFF);
-}
-
 #endif /* HB_UNICODE_PRIVATE_HH */
diff --git a/src/hb-unicode.cc b/src/hb-unicode.cc
index a94ea16..b1bd147 100644
--- a/src/hb-unicode.cc
+++ b/src/hb-unicode.cc
@@ -288,10 +288,9 @@ hb_unicode_decompose_compatibility (hb_unicode_funcs_t *ufuncs,
 
 
 unsigned int
-_hb_unicode_modified_combining_class (hb_unicode_funcs_t *ufuncs,
-				      hb_codepoint_t      unicode)
+hb_unicode_funcs_t::modified_combining_class (hb_codepoint_t unicode)
 {
-  int c = hb_unicode_combining_class (ufuncs, unicode);
+  int c = combining_class (unicode);
 
   if (unlikely (hb_in_range<int> (c, 27, 33)))
   {
commit 7470315a3e782aa6192bbe64f7a3944266fb1521
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Wed Aug 1 17:01:59 2012 -0400

    Move unicode accessors around

diff --git a/src/hb-unicode-private.hh b/src/hb-unicode-private.hh
index 6ec0a76..9185392 100644
--- a/src/hb-unicode-private.hh
+++ b/src/hb-unicode-private.hh
@@ -70,7 +70,78 @@ struct hb_unicode_funcs_t {
 
   bool immutable;
 
-  /* Don't access these directly.  Call hb_unicode_*() instead. */
+#define HB_UNICODE_FUNC_IMPLEMENT(return_type, name) \
+  inline return_type name (hb_codepoint_t unicode) { return func.name (this, unicode, user_data.name); }
+HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE
+#undef HB_UNICODE_FUNC_IMPLEMENT
+
+  inline hb_bool_t compose (hb_codepoint_t a, hb_codepoint_t b,
+			    hb_codepoint_t *ab)
+  {
+    *ab = 0;
+    /* XXX, this belongs to indic normalizer. */
+    if ((FLAG (general_category (a)) &
+	 (FLAG (HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK) |
+	  FLAG (HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK) |
+	  FLAG (HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK))))
+      return false;
+    /* XXX, add composition-exclusion exceptions to Indic shaper. */
+    if (a == 0x09AF && b == 0x09BC) { *ab = 0x09DF; return true; }
+    return func.compose (this, a, b, ab, user_data.compose);
+  }
+
+  inline hb_bool_t decompose (hb_codepoint_t ab,
+			      hb_codepoint_t *a, hb_codepoint_t *b)
+  {
+    /* XXX FIXME, move these to complex shapers and propagage to normalizer.*/
+    switch (ab) {
+      case 0x0AC9  : return false;
+
+      case 0x0931  : return false;
+      case 0x0B94  : return false;
+
+      /* These ones have Unicode decompositions, but we do it
+       * this way to be close to what Uniscribe does. */
+      case 0x0DDA  : *a = 0x0DD9; *b= 0x0DDA; return true;
+      case 0x0DDC  : *a = 0x0DD9; *b= 0x0DDC; return true;
+      case 0x0DDD  : *a = 0x0DD9; *b= 0x0DDD; return true;
+      case 0x0DDE  : *a = 0x0DD9; *b= 0x0DDE; return true;
+
+      case 0x0F77  : *a = 0x0FB2; *b= 0x0F81; return true;
+      case 0x0F79  : *a = 0x0FB3; *b= 0x0F81; return true;
+      case 0x17BE  : *a = 0x17C1; *b= 0x17BE; return true;
+      case 0x17BF  : *a = 0x17C1; *b= 0x17BF; return true;
+      case 0x17C0  : *a = 0x17C1; *b= 0x17C0; return true;
+      case 0x17C4  : *a = 0x17C1; *b= 0x17C4; return true;
+      case 0x17C5  : *a = 0x17C1; *b= 0x17C5; return true;
+      case 0x1925  : *a = 0x1920; *b= 0x1923; return true;
+      case 0x1926  : *a = 0x1920; *b= 0x1924; return true;
+      case 0x1B3C  : *a = 0x1B42; *b= 0x1B3C; return true;
+      case 0x1112E  : *a = 0x11127; *b= 0x11131; return true;
+      case 0x1112F  : *a = 0x11127; *b= 0x11132; return true;
+#if 0
+      case 0x0B57  : *a = 0xno decomp, -> RIGHT; return true;
+      case 0x1C29  : *a = 0xno decomp, -> LEFT; return true;
+      case 0xA9C0  : *a = 0xno decomp, -> RIGHT; return true;
+      case 0x111BF  : *a = 0xno decomp, -> ABOVE; return true;
+#endif
+    }
+    *a = ab; *b = 0;
+    return func.decompose (this, ab, a, b, user_data.decompose);
+  }
+
+  inline unsigned int decompose_compatibility (hb_codepoint_t  u,
+					       hb_codepoint_t *decomposed)
+  {
+    unsigned int ret = func.decompose_compatibility (this, u, decomposed, user_data.decompose_compatibility);
+    if (ret == 1 && u == decomposed[0]) {
+      decomposed[0] = 0;
+      return 0;
+    }
+    decomposed[ret] = 0;
+    return ret;
+  }
+
 
   struct {
 #define HB_UNICODE_FUNC_IMPLEMENT(name) hb_unicode_##name##_func_t name;
diff --git a/src/hb-unicode.cc b/src/hb-unicode.cc
index 288edf7..a94ea16 100644
--- a/src/hb-unicode.cc
+++ b/src/hb-unicode.cc
@@ -245,7 +245,7 @@ hb_unicode_funcs_set_##name##_func (hb_unicode_funcs_t		   *ufuncs,	\
   }										\
 }
 
-    HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS
+HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS
 #undef HB_UNICODE_FUNC_IMPLEMENT
 
 
@@ -255,9 +255,9 @@ return_type									\
 hb_unicode_##name (hb_unicode_funcs_t *ufuncs,					\
 		   hb_codepoint_t      unicode)					\
 {										\
-  return ufuncs->func.name (ufuncs, unicode, ufuncs->user_data.name);		\
+  return ufuncs->name (unicode);						\
 }
-    HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE
+HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE
 #undef HB_UNICODE_FUNC_IMPLEMENT
 
 hb_bool_t
@@ -266,16 +266,7 @@ hb_unicode_compose (hb_unicode_funcs_t *ufuncs,
 		    hb_codepoint_t      b,
 		    hb_codepoint_t     *ab)
 {
-  *ab = 0;
-  /* XXX, this belongs to indic normalizer. */
-  if ((FLAG (hb_unicode_general_category (ufuncs, a)) &
-       (FLAG (HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK) |
-        FLAG (HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK) |
-        FLAG (HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK))))
-    return false;
-  /* XXX, add composition-exclusion exceptions to Indic shaper. */
-  if (a == 0x09AF && b == 0x09BC) { *ab = 0x09DF; return true; }
-  return ufuncs->func.compose (ufuncs, a, b, ab, ufuncs->user_data.compose);
+  return ufuncs->compose (a, b, ab);
 }
 
 hb_bool_t
@@ -284,41 +275,7 @@ hb_unicode_decompose (hb_unicode_funcs_t *ufuncs,
 		      hb_codepoint_t     *a,
 		      hb_codepoint_t     *b)
 {
-  /* XXX FIXME, move these to complex shapers and propagage to normalizer.*/
-  switch (ab) {
-    case 0x0AC9  : return false;
-
-    case 0x0931  : return false;
-    case 0x0B94  : return false;
-
-    /* These ones have Unicode decompositions, but we do it
-     * this way to be close to what Uniscribe does. */
-    case 0x0DDA  : *a = 0x0DD9; *b= 0x0DDA; return true;
-    case 0x0DDC  : *a = 0x0DD9; *b= 0x0DDC; return true;
-    case 0x0DDD  : *a = 0x0DD9; *b= 0x0DDD; return true;
-    case 0x0DDE  : *a = 0x0DD9; *b= 0x0DDE; return true;
-
-    case 0x0F77  : *a = 0x0FB2; *b= 0x0F81; return true;
-    case 0x0F79  : *a = 0x0FB3; *b= 0x0F81; return true;
-    case 0x17BE  : *a = 0x17C1; *b= 0x17BE; return true;
-    case 0x17BF  : *a = 0x17C1; *b= 0x17BF; return true;
-    case 0x17C0  : *a = 0x17C1; *b= 0x17C0; return true;
-    case 0x17C4  : *a = 0x17C1; *b= 0x17C4; return true;
-    case 0x17C5  : *a = 0x17C1; *b= 0x17C5; return true;
-    case 0x1925  : *a = 0x1920; *b= 0x1923; return true;
-    case 0x1926  : *a = 0x1920; *b= 0x1924; return true;
-    case 0x1B3C  : *a = 0x1B42; *b= 0x1B3C; return true;
-    case 0x1112E  : *a = 0x11127; *b= 0x11131; return true;
-    case 0x1112F  : *a = 0x11127; *b= 0x11132; return true;
-#if 0
-    case 0x0B57  : *a = 0xno decomp, -> RIGHT; return true;
-    case 0x1C29  : *a = 0xno decomp, -> LEFT; return true;
-    case 0xA9C0  : *a = 0xno decomp, -> RIGHT; return true;
-    case 0x111BF  : *a = 0xno decomp, -> ABOVE; return true;
-#endif
-  }
-  *a = ab; *b = 0;
-  return ufuncs->func.decompose (ufuncs, ab, a, b, ufuncs->user_data.decompose);
+  return ufuncs->decompose (ab, a, b);
 }
 
 unsigned int
@@ -326,17 +283,7 @@ hb_unicode_decompose_compatibility (hb_unicode_funcs_t *ufuncs,
 				    hb_codepoint_t      u,
 				    hb_codepoint_t     *decomposed)
 {
-  unsigned int ret = ufuncs->func.decompose_compatibility (ufuncs, u,
-							   decomposed,
-							   ufuncs->user_data.decompose_compatibility);
-  if (ret == 1 && u == decomposed[0]) {
-    decomposed[0] = 0;
-    return 0;
-  }
-
-  decomposed[ret] = 0;
-
-  return ret;
+  return ufuncs->decompose_compatibility (u, decomposed);
 }
 
 
commit 21fdcee00125b6e1c09f0bed3064d16ccd3a7a5d
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Wed Aug 1 16:23:44 2012 -0400

    Add hb_unicode_combining_class_t

diff --git a/src/hb-common.h b/src/hb-common.h
index 1728db7..6f2a709 100644
--- a/src/hb-common.h
+++ b/src/hb-common.h
@@ -141,47 +141,11 @@ hb_language_t
 hb_language_get_default (void);
 
 
-/* hb_unicode_general_category_t */
-
-typedef enum
-{
-  HB_UNICODE_GENERAL_CATEGORY_CONTROL,			/* Cc */
-  HB_UNICODE_GENERAL_CATEGORY_FORMAT,			/* Cf */
-  HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED,		/* Cn */
-  HB_UNICODE_GENERAL_CATEGORY_PRIVATE_USE,		/* Co */
-  HB_UNICODE_GENERAL_CATEGORY_SURROGATE,		/* Cs */
-  HB_UNICODE_GENERAL_CATEGORY_LOWERCASE_LETTER,		/* Ll */
-  HB_UNICODE_GENERAL_CATEGORY_MODIFIER_LETTER,		/* Lm */
-  HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER,		/* Lo */
-  HB_UNICODE_GENERAL_CATEGORY_TITLECASE_LETTER,		/* Lt */
-  HB_UNICODE_GENERAL_CATEGORY_UPPERCASE_LETTER,		/* Lu */
-  HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK,		/* Mc */
-  HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK,		/* Me */
-  HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK,		/* Mn */
-  HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER,		/* Nd */
-  HB_UNICODE_GENERAL_CATEGORY_LETTER_NUMBER,		/* Nl */
-  HB_UNICODE_GENERAL_CATEGORY_OTHER_NUMBER,		/* No */
-  HB_UNICODE_GENERAL_CATEGORY_CONNECT_PUNCTUATION,	/* Pc */
-  HB_UNICODE_GENERAL_CATEGORY_DASH_PUNCTUATION,		/* Pd */
-  HB_UNICODE_GENERAL_CATEGORY_CLOSE_PUNCTUATION,	/* Pe */
-  HB_UNICODE_GENERAL_CATEGORY_FINAL_PUNCTUATION,	/* Pf */
-  HB_UNICODE_GENERAL_CATEGORY_INITIAL_PUNCTUATION,	/* Pi */
-  HB_UNICODE_GENERAL_CATEGORY_OTHER_PUNCTUATION,	/* Po */
-  HB_UNICODE_GENERAL_CATEGORY_OPEN_PUNCTUATION,		/* Ps */
-  HB_UNICODE_GENERAL_CATEGORY_CURRENCY_SYMBOL,		/* Sc */
-  HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL,		/* Sk */
-  HB_UNICODE_GENERAL_CATEGORY_MATH_SYMBOL,		/* Sm */
-  HB_UNICODE_GENERAL_CATEGORY_OTHER_SYMBOL,		/* So */
-  HB_UNICODE_GENERAL_CATEGORY_LINE_SEPARATOR,		/* Zl */
-  HB_UNICODE_GENERAL_CATEGORY_PARAGRAPH_SEPARATOR,	/* Zp */
-  HB_UNICODE_GENERAL_CATEGORY_SPACE_SEPARATOR		/* Zs */
-} hb_unicode_general_category_t;
-
-
 /* hb_script_t */
 
 /* http://unicode.org/iso15924/ */
 /* http://goo.gl/x9ilM */
+/* Unicode Character Database property: Script (sc) */
 typedef enum
 {
   /* Unicode-1.1 additions */
diff --git a/src/hb-glib.cc b/src/hb-glib.cc
index 5246363..fe2368a 100644
--- a/src/hb-glib.cc
+++ b/src/hb-glib.cc
@@ -192,13 +192,13 @@ hb_glib_script_from_script (hb_script_t script)
 }
 
 
-static unsigned int
+static hb_unicode_combining_class_t
 hb_glib_unicode_combining_class (hb_unicode_funcs_t *ufuncs HB_UNUSED,
 				 hb_codepoint_t      unicode,
 				 void               *user_data HB_UNUSED)
 
 {
-  return g_unichar_combining_class (unicode);
+  return (hb_unicode_combining_class_t) g_unichar_combining_class (unicode);
 }
 
 static unsigned int
diff --git a/src/hb-icu.cc b/src/hb-icu.cc
index dce6103..4694e31 100644
--- a/src/hb-icu.cc
+++ b/src/hb-icu.cc
@@ -63,13 +63,13 @@ hb_icu_script_from_script (hb_script_t script)
 }
 
 
-static unsigned int
+static hb_unicode_combining_class_t
 hb_icu_unicode_combining_class (hb_unicode_funcs_t *ufuncs HB_UNUSED,
 				hb_codepoint_t      unicode,
 				void               *user_data HB_UNUSED)
 
 {
-  return u_getCombiningClass (unicode);
+  return (hb_unicode_combining_class_t) u_getCombiningClass (unicode);
 }
 
 static unsigned int
diff --git a/src/hb-unicode-private.hh b/src/hb-unicode-private.hh
index ba791eb..6ec0a76 100644
--- a/src/hb-unicode-private.hh
+++ b/src/hb-unicode-private.hh
@@ -55,7 +55,7 @@
 
 /* Simple callbacks are those taking a hb_codepoint_t and returning a hb_codepoint_t */
 #define HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE \
-  HB_UNICODE_FUNC_IMPLEMENT (unsigned int, combining_class) \
+  HB_UNICODE_FUNC_IMPLEMENT (hb_unicode_combining_class_t, combining_class) \
   HB_UNICODE_FUNC_IMPLEMENT (unsigned int, eastasian_width) \
   HB_UNICODE_FUNC_IMPLEMENT (hb_unicode_general_category_t, general_category) \
   HB_UNICODE_FUNC_IMPLEMENT (hb_codepoint_t, mirroring) \
diff --git a/src/hb-unicode.cc b/src/hb-unicode.cc
index f300fed..288edf7 100644
--- a/src/hb-unicode.cc
+++ b/src/hb-unicode.cc
@@ -38,12 +38,12 @@
  * hb_unicode_funcs_t
  */
 
-static unsigned int
+static hb_unicode_combining_class_t
 hb_unicode_combining_class_nil (hb_unicode_funcs_t *ufuncs    HB_UNUSED,
 				hb_codepoint_t      unicode   HB_UNUSED,
 				void               *user_data HB_UNUSED)
 {
-  return 0;
+  return HB_UNICODE_COMBINING_CLASS_NOT_REORDERED;
 }
 
 static unsigned int
@@ -354,11 +354,11 @@ _hb_unicode_modified_combining_class (hb_unicode_funcs_t *ufuncs,
      */
     c = c == 33 ? 27 : c + 1;
   }
-  else if (unlikely (hb_in_range<int> (c, 10, 25)))
+  else if (unlikely (hb_in_range<int> (c, 10, 26)))
   {
     /* The equivalent fix for Hebrew is more complex.
      *
-     * We permute the "fixed-position" classes 10-25 into the order
+     * We permute the "fixed-position" classes 10-26 into the order
      * described in the SBL Hebrew manual:
      *
      * http://www.sbl-site.org/Fonts/SBLHebrewUserManual1.5x.pdf
@@ -369,7 +369,7 @@ _hb_unicode_modified_combining_class (hb_unicode_funcs_t *ufuncs,
      * More details here:
      * https://bugzilla.mozilla.org/show_bug.cgi?id=662055
      */
-    static const int permuted_hebrew_classes[25 - 10 + 1] = {
+    static const int permuted_hebrew_classes[26 - 10 + 1] = {
       /* 10 sheva */        22,
       /* 11 hataf segol */  15,
       /* 12 hataf patah */  16,
@@ -386,6 +386,7 @@ _hb_unicode_modified_combining_class (hb_unicode_funcs_t *ufuncs,
       /* 23 rafe */         13,
       /* 24 shin dot */     10,
       /* 25 sin dot */      11,
+      /* 26 point varika */ 26,
     };
     c = permuted_hebrew_classes[c - 10];
   }
diff --git a/src/hb-unicode.h b/src/hb-unicode.h
index 2af2d67..47084da 100644
--- a/src/hb-unicode.h
+++ b/src/hb-unicode.h
@@ -40,6 +40,126 @@
 HB_BEGIN_DECLS
 
 
+/* hb_unicode_general_category_t */
+
+/* Unicode Character Database property: General_Category (gc) */
+typedef enum
+{
+  HB_UNICODE_GENERAL_CATEGORY_CONTROL,			/* Cc */
+  HB_UNICODE_GENERAL_CATEGORY_FORMAT,			/* Cf */
+  HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED,		/* Cn */
+  HB_UNICODE_GENERAL_CATEGORY_PRIVATE_USE,		/* Co */
+  HB_UNICODE_GENERAL_CATEGORY_SURROGATE,		/* Cs */
+  HB_UNICODE_GENERAL_CATEGORY_LOWERCASE_LETTER,		/* Ll */
+  HB_UNICODE_GENERAL_CATEGORY_MODIFIER_LETTER,		/* Lm */
+  HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER,		/* Lo */
+  HB_UNICODE_GENERAL_CATEGORY_TITLECASE_LETTER,		/* Lt */
+  HB_UNICODE_GENERAL_CATEGORY_UPPERCASE_LETTER,		/* Lu */
+  HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK,		/* Mc */
+  HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK,		/* Me */
+  HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK,		/* Mn */
+  HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER,		/* Nd */
+  HB_UNICODE_GENERAL_CATEGORY_LETTER_NUMBER,		/* Nl */
+  HB_UNICODE_GENERAL_CATEGORY_OTHER_NUMBER,		/* No */
+  HB_UNICODE_GENERAL_CATEGORY_CONNECT_PUNCTUATION,	/* Pc */
+  HB_UNICODE_GENERAL_CATEGORY_DASH_PUNCTUATION,		/* Pd */
+  HB_UNICODE_GENERAL_CATEGORY_CLOSE_PUNCTUATION,	/* Pe */
+  HB_UNICODE_GENERAL_CATEGORY_FINAL_PUNCTUATION,	/* Pf */
+  HB_UNICODE_GENERAL_CATEGORY_INITIAL_PUNCTUATION,	/* Pi */
+  HB_UNICODE_GENERAL_CATEGORY_OTHER_PUNCTUATION,	/* Po */
+  HB_UNICODE_GENERAL_CATEGORY_OPEN_PUNCTUATION,		/* Ps */
+  HB_UNICODE_GENERAL_CATEGORY_CURRENCY_SYMBOL,		/* Sc */
+  HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL,		/* Sk */
+  HB_UNICODE_GENERAL_CATEGORY_MATH_SYMBOL,		/* Sm */
+  HB_UNICODE_GENERAL_CATEGORY_OTHER_SYMBOL,		/* So */
+  HB_UNICODE_GENERAL_CATEGORY_LINE_SEPARATOR,		/* Zl */
+  HB_UNICODE_GENERAL_CATEGORY_PARAGRAPH_SEPARATOR,	/* Zp */
+  HB_UNICODE_GENERAL_CATEGORY_SPACE_SEPARATOR		/* Zs */
+} hb_unicode_general_category_t;
+
+/* hb_unicode_combining_class_t */
+
+/* Unicode Character Database property: Canonical_Combining_Class (ccc) */
+typedef enum
+{
+  HB_UNICODE_COMBINING_CLASS_NOT_REORDERED	= 0,
+  HB_UNICODE_COMBINING_CLASS_OVERLAY		= 1,
+  HB_UNICODE_COMBINING_CLASS_NUKTA		= 7,
+  HB_UNICODE_COMBINING_CLASS_KANA_VOICING	= 8,
+  HB_UNICODE_COMBINING_CLASS_VIRAMA		= 9,
+
+  /* Hebrew */
+  HB_UNICODE_COMBINING_CLASS_CCC10	=  10,
+  HB_UNICODE_COMBINING_CLASS_CCC11	=  11,
+  HB_UNICODE_COMBINING_CLASS_CCC12	=  12,
+  HB_UNICODE_COMBINING_CLASS_CCC13	=  13,
+  HB_UNICODE_COMBINING_CLASS_CCC14	=  14,
+  HB_UNICODE_COMBINING_CLASS_CCC15	=  15,
+  HB_UNICODE_COMBINING_CLASS_CCC16	=  16,
+  HB_UNICODE_COMBINING_CLASS_CCC17	=  17,
+  HB_UNICODE_COMBINING_CLASS_CCC18	=  18,
+  HB_UNICODE_COMBINING_CLASS_CCC19	=  19,
+  HB_UNICODE_COMBINING_CLASS_CCC20	=  20,
+  HB_UNICODE_COMBINING_CLASS_CCC21	=  21,
+  HB_UNICODE_COMBINING_CLASS_CCC22	=  22,
+  HB_UNICODE_COMBINING_CLASS_CCC23	=  23,
+  HB_UNICODE_COMBINING_CLASS_CCC24	=  24,
+  HB_UNICODE_COMBINING_CLASS_CCC25	=  25,
+  HB_UNICODE_COMBINING_CLASS_CCC26	=  26,
+
+  /* Arabic */
+  HB_UNICODE_COMBINING_CLASS_CCC27	=  27,
+  HB_UNICODE_COMBINING_CLASS_CCC28	=  28,
+  HB_UNICODE_COMBINING_CLASS_CCC29	=  29,
+  HB_UNICODE_COMBINING_CLASS_CCC30	=  30,
+  HB_UNICODE_COMBINING_CLASS_CCC31	=  31,
+  HB_UNICODE_COMBINING_CLASS_CCC32	=  32,
+  HB_UNICODE_COMBINING_CLASS_CCC33	=  33,
+  HB_UNICODE_COMBINING_CLASS_CCC34	=  34,
+  HB_UNICODE_COMBINING_CLASS_CCC35	=  35,
+
+  /* Syriac */
+  HB_UNICODE_COMBINING_CLASS_CCC36	=  36,
+
+  /* Telugu */
+  HB_UNICODE_COMBINING_CLASS_CCC84	=  84,
+  HB_UNICODE_COMBINING_CLASS_CCC91	=  91,
+
+  /* Thai */
+  HB_UNICODE_COMBINING_CLASS_CCC103	= 103,
+  HB_UNICODE_COMBINING_CLASS_CCC107	= 107,
+
+  /* Lao */
+  HB_UNICODE_COMBINING_CLASS_CCC118	= 118,
+  HB_UNICODE_COMBINING_CLASS_CCC122	= 122,
+
+  /* Tibetan */
+  HB_UNICODE_COMBINING_CLASS_CCC129	= 129,
+  HB_UNICODE_COMBINING_CLASS_CCC130	= 130,
+  HB_UNICODE_COMBINING_CLASS_CCC133	= 132,
+
+
+  HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW_LEFT	= 200,
+  HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW		= 202,
+  HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE		= 214,
+  HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE_RIGHT	= 216,
+  HB_UNICODE_COMBINING_CLASS_BELOW_LEFT			= 218,
+  HB_UNICODE_COMBINING_CLASS_BELOW			= 220,
+  HB_UNICODE_COMBINING_CLASS_BELOW_RIGHT		= 222,
+  HB_UNICODE_COMBINING_CLASS_LEFT			= 224,
+  HB_UNICODE_COMBINING_CLASS_RIGHT			= 226,
+  HB_UNICODE_COMBINING_CLASS_ABOVE_LEFT			= 228,
+  HB_UNICODE_COMBINING_CLASS_ABOVE			= 230,
+  HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT		= 232,
+  HB_UNICODE_COMBINING_CLASS_DOUBLE_BELOW		= 233,
+  HB_UNICODE_COMBINING_CLASS_DOUBLE_ABOVE		= 234,
+
+  HB_UNICODE_COMBINING_CLASS_IOTA_SUBSCRIPT		= 240,
+
+  HB_UNICODE_COMBINING_CLASS_INVALID	= 255
+} hb_unicode_combining_class_t;
+
+
 /*
  * hb_unicode_funcs_t
  */
@@ -95,7 +215,7 @@ hb_unicode_funcs_get_parent (hb_unicode_funcs_t *ufuncs);
 
 /* typedefs */
 
-typedef unsigned int			(*hb_unicode_combining_class_func_t)	(hb_unicode_funcs_t *ufuncs,
+typedef hb_unicode_combining_class_t	(*hb_unicode_combining_class_func_t)	(hb_unicode_funcs_t *ufuncs,
 										 hb_codepoint_t      unicode,
 										 void               *user_data);
 typedef unsigned int			(*hb_unicode_eastasian_width_func_t)	(hb_unicode_funcs_t *ufuncs,
@@ -192,7 +312,7 @@ hb_unicode_funcs_set_decompose_compatibility_func (hb_unicode_funcs_t *ufuncs,
 
 /* accessors */
 
-unsigned int
+hb_unicode_combining_class_t
 hb_unicode_combining_class (hb_unicode_funcs_t *ufuncs,
 			    hb_codepoint_t unicode);
 
commit 84186a64004e5dcd2ce98b564d0e0a09aa5d68b2
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Wed Aug 1 13:32:39 2012 -0400

    Add commentary on the compatibility decomposition in the normalizer

diff --git a/src/hb-ot-shape-normalize.cc b/src/hb-ot-shape-normalize.cc
index 46c89ec..17a9ac8 100644
--- a/src/hb-ot-shape-normalize.cc
+++ b/src/hb-ot-shape-normalize.cc
@@ -63,10 +63,22 @@
  *
  *   - When a font does not support a character but supports its decomposition,
  *     well, use the decomposition (preferring the canonical decomposition, but
- *     falling back to the compatibility decomposition if necessary).
+ *     falling back to the compatibility decomposition if necessary).  The
+ *     compatibility decomposition is really nice to have, for characters like
+ *     ellipsis, or various-sized space characters.
  *
- *   - The Indic shaper requests decomposed output.  This will handle splitting
- *     matra for the Indic shaper.
+ *   - The complex shapers can customize the compose and decompose functions to
+ *     offload some of their requirements to the normalizer.  For example, the
+ *     Indic shaper may want to disallow recomposing of two matras.
+ *
+ *   - We try compatibility decomposition if decomposing through canonical
+ *     decomposition alone failed to find a sequence that the font supports.
+ *     We don't try compatibility decomposition recursively during the canonical
+ *     decomposition phase.  This has minimal impact.  There are only a handful
+ *     of Greek letter that have canonical decompositions that include characters
+ *     with compatibility decomposition.  Those can be found using this command:
+ *
+ *     egrep  "`echo -n ';('; grep ';<' UnicodeData.txt | cut -d';' -f1 | tr '\n' '|'; echo ') '`" UnicodeData.txt
  */
 
 static void



More information about the HarfBuzz mailing list