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

Behdad Esfahbod behdad at kemper.freedesktop.org
Fri May 21 06:18:24 PDT 2010


 configure.ac                      |    6 
 contrib/python/lib/harfbuzz.pyx   |  308 ++++++++++++++++++++++++++++++++++++++
 contrib/python/runpy              |    2 
 contrib/python/scripts/hbtestfont |   35 ++++
 contrib/python/setup.py           |   24 ++
 src/Makefile.am                   |   12 +
 src/hb-common.c                   |   41 +++++
 src/hb-common.h                   |    3 
 src/hb-font.cc                    |    2 
 src/hb-font.h                     |    1 
 src/hb-graphite.cc                |  304 +++++++++++++++++++++++++++++++++++++
 src/hb-graphite.h                 |   46 +++++
 src/hb-icu.c                      |   29 +++
 src/hb-open-type-private.hh       |    3 
 src/hb-ot-shape.cc                |   41 +++--
 src/hb-ot-tag.c                   |   33 +++-
 src/hb-ot-tag.h                   |    3 
 src/hb-shape.cc                   |   15 +
 src/hb-unicode.c                  |   19 ++
 src/hb-unicode.h                  |   19 ++
 20 files changed, 931 insertions(+), 15 deletions(-)

New commits:
commit dd47924d88d86b83e7f3ab040de6e7136ac0ca09
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri May 21 14:18:08 2010 +0100

    Fix warnings

diff --git a/src/hb-graphite.cc b/src/hb-graphite.cc
index ba1169a..f1af2c3 100644
--- a/src/hb-graphite.cc
+++ b/src/hb-graphite.cc
@@ -51,7 +51,6 @@ class GrBufferTextSrc : public gr::ITextSource
 public:
   GrBufferTextSrc(hb_buffer_t *buff, hb_feature_t *feats, unsigned int num_features)
   {
-    int i;
     hb_feature_t *aFeat = feats;
     featureSetting *aNewFeat;
 
@@ -59,7 +58,7 @@ public:
     features = new featureSetting[num_features];
     nFeatures = num_features;
     aNewFeat = features;
-    for (i = 0; i < num_features; i++, aFeat++, aNewFeat++)
+    for (unsigned int i = 0; i < num_features; i++, aFeat++, aNewFeat++)
     {
         aNewFeat->id = aFeat->tag;
         aNewFeat->value = aFeat->value;
@@ -70,12 +69,10 @@ public:
   virtual size_t getLength() { return buffer->len; };
   virtual size_t fetch(gr::toffset ichMin, size_t cch, gr::utf32 * prgchBuffer)
   {
-    int i;
-
     assert(cch <= buffer->len);
     if (cch > buffer->len)
       return 0;
-    for (i = ichMin; i < ichMin + cch; i++)
+    for (unsigned int i = ichMin; i < ichMin + cch; i++)
       prgchBuffer[i - ichMin] = buffer->info[i].codepoint;
     return (cch - ichMin);
   };
@@ -107,9 +104,8 @@ public:
   { return std::pair<gr::toffset, gr::toffset>(0, buffer->len); };
   virtual size_t getFontFeatures(gr::toffset ich, gr::FeatureSetting * prgfset)
   {
-    int i;
     featureSetting *aFeat = features;
-    for (i = 0; i < nFeatures; i++, aFeat++, prgfset++)
+    for (unsigned int i = 0; i < nFeatures; i++, aFeat++, prgfset++)
     {
       prgfset->id = aFeat->id;
       prgfset->value = aFeat->value;
@@ -268,7 +264,7 @@ hb_graphite_shape (hb_font_t    *font,
   hb_buffer_ensure(buffer, numGlyphs);
   pSegment.getUniscribeClusters(firsts, numChars, NULL, flags, numGlyphs, NULL);
   glyph_range = pSegment.glyphs();
-  for (pGlyph = glyph_infos, iGlyph = glyph_range.first; iGlyph != glyph_range.second;
+  for (pGlyph = glyph_infos, iGlyph = glyph_range.first; iGlyph < glyph_range.second;
         iGlyph++, pGlyph++)
   { *pGlyph = iGlyph->glyphID(); }
 
@@ -289,7 +285,7 @@ hb_graphite_shape (hb_font_t    *font,
 
   float curradvx = 0., curradvy = 0.;
   for (pPosition = hb_buffer_get_glyph_positions(buffer), iGlyph = glyph_range.first;
-        iGlyph != glyph_range.second; pPosition++, iGlyph++)
+        iGlyph < glyph_range.second; pPosition++, iGlyph++)
   {
     pPosition->x_offset = iGlyph->origin() - curradvx;
     pPosition->y_offset = iGlyph->yOffset() - curradvy;
commit 305ba8671553cd955c20a54db622666c0bb02532
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri May 21 14:02:20 2010 +0100

    Import Graphite shaping backend by Martin Hosken

diff --git a/configure.ac b/configure.ac
index 0cc01b7..721c912 100644
--- a/configure.ac
+++ b/configure.ac
@@ -33,6 +33,12 @@ if $have_icu; then
 fi
 AM_CONDITIONAL(HAVE_ICU, $have_icu)
 
+PKG_CHECK_MODULES(GRAPHITE, silgraphite, have_graphite=true, have_graphite=false)
+if $have_graphite; then
+    AC_DEFINE(HAVE_GRAPHITE, 1, [Have Graphite library])
+fi
+AM_CONDITIONAL(HAVE_GRAPHITE, $have_graphite)
+
 PKG_CHECK_MODULES(FREETYPE, freetype2, have_freetype=true, have_freetype=false)
 if $have_freetype; then
 	AC_DEFINE(HAVE_FREETYPE, 1, [Have FreeType 2 library])
diff --git a/src/Makefile.am b/src/Makefile.am
index 70cbfd8..0ed02e1 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -89,6 +89,17 @@ HBHEADERS += \
 	$(NULL)
 endif
 
+if HAVE_GRAPHITE
+HBCFLAGS += $(GRAPHITE_CFLAGS)
+HBLIBS   += $(GRAPHITE_LIBS)
+HBSOURCES += \
+	hb-graphite.cc \
+	$(NULL)
+HBHEADERS += \
+	hb-graphite.h \
+	$(NULL)
+endif
+
 CXXLINK = $(LINK)
 libharfbuzz_la_SOURCES = $(HBSOURCES) $(HBHEADERS)
 libharfbuzz_la_CPPFLAGS = $(HBCFLAGS)
diff --git a/src/hb-graphite.cc b/src/hb-graphite.cc
new file mode 100644
index 0000000..ba1169a
--- /dev/null
+++ b/src/hb-graphite.cc
@@ -0,0 +1,308 @@
+/*
+ * Copyright (C) 2009, Martin Hosken
+ * Copyright (C) 2009, SIL International
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#include <graphite/GrClient.h>
+#include <graphite/ITextSource.h>
+#include <graphite/GrData.h>
+#include <graphite/GrConstants.h>
+#include <graphite/Segment.h>
+#include "hb-buffer-private.hh"
+#include "hb-font-private.hh"
+#include "hb-graphite.h"
+#include <map>
+
+namespace TtfUtil
+{
+extern int FontAscent(const void *pOS2);
+extern int FontDescent(const void *pOS2);
+extern int DesignUnits(const void *pHead);
+extern bool FontOs2Style(const void *pOS2, bool &fBold, bool &fItalic);
+}
+
+typedef struct _featureSetting {
+    unsigned int id;
+    int value;
+} featureSetting;
+
+class GrBufferTextSrc : public gr::ITextSource
+{
+public:
+  GrBufferTextSrc(hb_buffer_t *buff, hb_feature_t *feats, unsigned int num_features)
+  {
+    int i;
+    hb_feature_t *aFeat = feats;
+    featureSetting *aNewFeat;
+
+    buffer = hb_buffer_reference(buff);
+    features = new featureSetting[num_features];
+    nFeatures = num_features;
+    aNewFeat = features;
+    for (i = 0; i < num_features; i++, aFeat++, aNewFeat++)
+    {
+        aNewFeat->id = aFeat->tag;
+        aNewFeat->value = aFeat->value;
+    }
+  };
+  ~GrBufferTextSrc() { hb_buffer_destroy(buffer); delete[] features; };
+  virtual gr::UtfType utfEncodingForm() { return gr::kutf32; };
+  virtual size_t getLength() { return buffer->len; };
+  virtual size_t fetch(gr::toffset ichMin, size_t cch, gr::utf32 * prgchBuffer)
+  {
+    int i;
+
+    assert(cch <= buffer->len);
+    if (cch > buffer->len)
+      return 0;
+    for (i = ichMin; i < ichMin + cch; i++)
+      prgchBuffer[i - ichMin] = buffer->info[i].codepoint;
+    return (cch - ichMin);
+  };
+  virtual size_t fetch(gr::toffset ichMin, size_t cch, gr::utf16 * prgchBuffer) { return 0 ;};
+  virtual size_t fetch(gr::toffset ichMin, size_t cch, gr::utf8 * prgchBuffer) { return 0; };
+  virtual bool getRightToLeft(gr::toffset ich)
+  { return hb_buffer_get_direction(buffer) == HB_DIRECTION_RTL; };
+  virtual unsigned int getDirectionDepth(gr::toffset ich)
+  { return hb_buffer_get_direction(buffer) == HB_DIRECTION_RTL ? 1 : 0; };
+  virtual float getVerticalOffset(gr::toffset ich) { return 0; };
+  virtual gr::isocode getLanguage(gr::toffset ich)
+  {
+    gr::isocode aLang;
+    char *p = (char *)(buffer->language);
+    int i;
+    for (i = 0; i < 4; i++)
+    {
+      if (p != NULL)
+        aLang.rgch[i] = *p;
+      else
+        aLang.rgch[i] = 0;
+      if (p && *p)
+        p++;
+    }
+    return aLang;
+  }
+
+  virtual std::pair<gr::toffset, gr::toffset> propertyRange(gr::toffset ich)
+  { return std::pair<gr::toffset, gr::toffset>(0, buffer->len); };
+  virtual size_t getFontFeatures(gr::toffset ich, gr::FeatureSetting * prgfset)
+  {
+    int i;
+    featureSetting *aFeat = features;
+    for (i = 0; i < nFeatures; i++, aFeat++, prgfset++)
+    {
+      prgfset->id = aFeat->id;
+      prgfset->value = aFeat->value;
+    }
+    return nFeatures;
+  }
+  virtual bool sameSegment(gr::toffset ich1, gr::toffset ich2) {return true; };
+
+private:
+  hb_buffer_t   *buffer;
+  featureSetting   *features;
+  unsigned int nFeatures;
+};
+
+class GrHbFont : public gr::Font
+{
+public:
+  GrHbFont(hb_font_t *font, hb_face_t *face) : gr::Font()
+  { m_font = hb_font_reference(font); m_face = hb_face_reference(face); initfont(); };
+  ~GrHbFont()
+  {
+    std::map<hb_tag_t,hb_blob_t *>::iterator p = m_blobs.begin();
+    while (p != m_blobs.end())
+    { hb_blob_destroy((p++)->second); }
+    hb_font_destroy(m_font);
+    hb_face_destroy(m_face);
+  };
+  GrHbFont (const GrHbFont &font) : gr::Font(font)
+  {
+    *this = font;
+    m_blobs = std::map<hb_tag_t, hb_blob_t *>(font.m_blobs);
+    std::map<hb_tag_t,hb_blob_t *>::iterator p=m_blobs.begin();
+    while (p != m_blobs.end()) { hb_blob_reference((*p++).second); }
+    hb_font_reference(m_font);
+    hb_face_reference(m_face);
+  };
+  virtual GrHbFont *copyThis() { return new GrHbFont(*this); };
+  virtual bool bold() { return m_bold; };
+  virtual bool italic() { return m_italic; };
+  virtual float ascent() { float asc; getFontMetrics(&asc, NULL, NULL); return asc; };
+  virtual float descent() { float desc; getFontMetrics(NULL, &desc, NULL); return desc; };
+  virtual float height()
+  { float asc, desc; getFontMetrics(&asc, &desc, NULL); return (asc + desc); };
+  virtual unsigned int getDPIx() { return m_font->x_ppem; };
+  virtual unsigned int getDPIy() { return m_font->y_ppem; };
+  virtual const void *getTable(gr::fontTableId32 tableID, size_t *pcbsize)
+  {
+    hb_blob_t *blob;
+    std::map<hb_tag_t,hb_blob_t *>::iterator p=m_blobs.find((hb_tag_t)tableID);
+    if (p == m_blobs.end())
+    {
+      blob = hb_face_get_table(m_face, (hb_tag_t)tableID);
+      m_blobs[(hb_tag_t)tableID] = blob;
+    }
+    else
+    { blob = p->second; }
+
+    const char *res = hb_blob_lock(blob);
+    if (pcbsize)
+      *pcbsize = hb_blob_get_length(blob);
+    hb_blob_unlock(blob);
+    return (const void *)res;
+  }
+
+  virtual void getFontMetrics(float *pAscent, float *pDescent, float *pEmSquare)
+  {
+    if (pAscent) *pAscent = 1. * m_ascent * m_font->y_ppem / m_emsquare;
+    if (pDescent) *pDescent = 1. * m_descent * m_font->y_ppem / m_emsquare;
+    if (pEmSquare) *pEmSquare = m_font->x_scale;
+  }
+  virtual void getGlyphPoint(gr::gid16 glyphID, unsigned int pointNum, gr::Point &pointReturn)
+  {
+    hb_position_t x, y;
+    hb_font_get_contour_point(m_font, m_face, pointNum, glyphID, &x, &y);
+    pointReturn.x = (float)x;
+    pointReturn.y = (float)y;
+  }
+
+  virtual void getGlyphMetrics(gr::gid16 glyphID, gr::Rect &boundingBox, gr::Point &advances)
+  {
+    hb_glyph_metrics_t metrics;
+    hb_font_get_glyph_metrics(m_font, m_face, glyphID, &metrics);
+    boundingBox.top = (metrics.y_offset + metrics.height);
+    boundingBox.bottom = metrics.y_offset;
+    boundingBox.left = metrics.x_offset;
+    boundingBox.right = (metrics.x_offset + metrics.width);
+    advances.x = metrics.x_advance;
+    advances.y = metrics.y_advance;
+//    fprintf (stderr, "%d: (%d, %d, %d, %d)+(%d, %d)\n", glyphID, metrics.x_offset, metrics.y_offset, metrics.width, metrics.height, metrics.x_advance, metrics.y_advance);
+  }
+
+private:
+  void initfont();
+
+  hb_font_t *m_font;
+  hb_face_t *m_face;
+  float m_ascent;
+  float m_descent;
+  float m_emsquare;
+  bool m_bold;
+  bool m_italic;
+  std::map<hb_tag_t, hb_blob_t *> m_blobs;
+};
+
+void GrHbFont::initfont()
+{
+  const void *pOS2 = getTable(gr::kttiOs2, NULL);
+  const void *pHead = getTable(gr::kttiHead, NULL);
+  TtfUtil::FontOs2Style(pOS2, m_bold, m_italic);
+  m_ascent = static_cast<float>(TtfUtil::FontAscent(pOS2));
+  m_descent = static_cast<float>(TtfUtil::FontDescent(pOS2));
+  m_emsquare = static_cast<float>(TtfUtil::DesignUnits(pHead));
+}
+
+void
+hb_graphite_shape (hb_font_t    *font,
+		   hb_face_t    *face,
+		   hb_buffer_t  *buffer,
+		   hb_feature_t *features,
+		   unsigned int  num_features)
+{
+  /* create text source */
+  GrBufferTextSrc   textSrc(buffer, features, num_features);
+
+  /* create grfont */
+  GrHbFont          grfont(font, face);
+
+  /* create segment */
+  int *firsts;
+  bool *flags;
+  int numChars;
+  int numGlyphs;
+  gr::LayoutEnvironment layout;
+  std::pair<gr::GlyphIterator, gr::GlyphIterator>glyph_range;
+  gr::GlyphIterator iGlyph;
+  hb_codepoint_t *glyph_infos, *pGlyph;
+  hb_glyph_position_t *pPosition;
+  int cGlyph = 0;
+  int cChar = 0;
+
+  layout.setStartOfLine(0);
+  layout.setEndOfLine(0);
+  layout.setDumbFallback(true);
+  layout.setJustifier(NULL);
+  layout.setRightToLeft(false);
+
+  gr::RangeSegment pSegment(&grfont, &textSrc, &layout, (gr::toffset)0,
+        static_cast<gr::toffset>(buffer->len), (gr::Segment *)NULL);
+
+  /* fill in buffer from segment */
+  _hb_buffer_clear_output(buffer);
+  pSegment.getUniscribeClusters(NULL, 0, &numChars, NULL, 0, &numGlyphs);
+  firsts = new int[numChars];
+  flags = new bool[numGlyphs];
+  glyph_infos = new hb_codepoint_t[numGlyphs];
+  hb_buffer_ensure(buffer, numGlyphs);
+  pSegment.getUniscribeClusters(firsts, numChars, NULL, flags, numGlyphs, NULL);
+  glyph_range = pSegment.glyphs();
+  for (pGlyph = glyph_infos, iGlyph = glyph_range.first; iGlyph != glyph_range.second;
+        iGlyph++, pGlyph++)
+  { *pGlyph = iGlyph->glyphID(); }
+
+  while (cGlyph < numGlyphs)
+  {
+    if (flags[cGlyph])
+    {
+        int oldcChar = cChar++;
+        int oldcGlyph = cGlyph++;
+        while (cChar < numChars && firsts[cChar] == firsts[oldcChar]) cChar++;
+        while (cGlyph < numGlyphs && !flags[cGlyph]) cGlyph++;
+        _hb_buffer_add_output_glyphs(buffer, cChar - oldcChar, cGlyph - oldcGlyph,
+                glyph_infos + oldcGlyph, 0xFFFF, 0xFFFF);
+    }
+    else
+    { cGlyph++; }   /* This should never happen */
+  }
+
+  float curradvx = 0., curradvy = 0.;
+  for (pPosition = hb_buffer_get_glyph_positions(buffer), iGlyph = glyph_range.first;
+        iGlyph != glyph_range.second; pPosition++, iGlyph++)
+  {
+    pPosition->x_offset = iGlyph->origin() - curradvx;
+    pPosition->y_offset = iGlyph->yOffset() - curradvy;
+    pPosition->x_advance = pPosition->x_offset + iGlyph->advanceWidth();
+    pPosition->y_advance = pPosition->y_offset + iGlyph->advanceHeight();
+//    if (pPosition->x_advance < 0)
+//        pPosition->x_advance = 0;
+    curradvx += pPosition->x_advance;
+    curradvy += pPosition->y_advance;
+//    fprintf(stderr, "%d@(%f, %f)+(%f, %f)\n", iGlyph->glyphID(), iGlyph->origin(), iGlyph->yOffset(), iGlyph->advanceWidth(), iGlyph->advanceHeight());
+  }
+
+  delete[] glyph_infos;
+  delete[] firsts;
+  delete[] flags;
+}
diff --git a/src/hb-graphite.h b/src/hb-graphite.h
new file mode 100644
index 0000000..ac9ca27
--- /dev/null
+++ b/src/hb-graphite.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2009, Martin Hosken
+ * Copyright (C) 2009, SIL International
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Red Hat Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_GRAPHITE_H
+#define HB_GRAPHITE_H
+
+#include "hb-shape.h"
+
+
+HB_BEGIN_DECLS
+
+#define HB_GRAPHITE_TAG_Silf HB_TAG('S','i','l','f')
+
+void hb_graphite_shape (hb_font_t    *font,
+			hb_face_t    *face,
+			hb_buffer_t  *buffer,
+			hb_feature_t *features,
+			unsigned int  num_features);
+
+HB_END_DECLS
+
+#endif /* HB_GRAPHITE_H */
diff --git a/src/hb-shape.cc b/src/hb-shape.cc
index b77677c..a53f3ea 100644
--- a/src/hb-shape.cc
+++ b/src/hb-shape.cc
@@ -32,6 +32,9 @@
 
 #include "hb-ot-shape-private.hh"
 
+#ifdef HAVE_GRAPHITE
+#include "hb-graphite.h"
+#endif
 
 /* Prepare */
 
@@ -220,6 +223,18 @@ hb_shape (hb_font_t    *font,
   hb_direction_t original_direction;
   hb_bool_t substitute_fallback, position_fallback;
 
+#ifdef HAVE_GRAPHITE
+  hb_blob_t *silf_blob;
+  silf_blob = hb_face_get_table (face, HB_GRAPHITE_TAG_Silf);
+  if (hb_blob_get_length(silf_blob))
+  {
+    hb_graphite_shape(font, face, buffer, features, num_features);
+    hb_blob_destroy(silf_blob);
+    return;
+  }
+  hb_blob_destroy(silf_blob);
+#endif
+
   hb_form_clusters (buffer);
 
   hb_substitute_default (font, face, buffer, features, num_features);
commit 3ba6818ba9be950e46902f0239f2451ec0e65d44
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri May 21 13:51:29 2010 +0100

    Update the Python module

diff --git a/contrib/python/lib/harfbuzz.pyx b/contrib/python/lib/harfbuzz.pyx
index 1f254ff..2a97c6c 100644
--- a/contrib/python/lib/harfbuzz.pyx
+++ b/contrib/python/lib/harfbuzz.pyx
@@ -7,7 +7,7 @@ cdef extern from "ft2build.h" :
     pass
 
 cdef extern from "freetype/freetype.h" :
-    ctypedef void *FT_Library 
+    ctypedef void *FT_Library
     ctypedef void *FT_Face
     ctypedef int FT_Error
 
@@ -27,6 +27,7 @@ cdef extern from "hb-common.h" :
     ctypedef long hb_position_t
     ctypedef unsigned long hb_mask_t
     ctypedef unsigned long hb_tag_t
+    hb_tag_t hb_tag_from_string (char *s)
     ctypedef void (*hb_destroy_func_t) (void *user_data)
 
 cdef extern from "hb-unicode.h" :
@@ -113,6 +114,22 @@ cdef extern from "hb-unicode.h" :
         HB_SCRIPT_CARIAN,
         HB_SCRIPT_LYCIAN,
         HB_SCRIPT_LYDIAN
+# Unicode-5.2
+        HB_SCRIPT_AVESTAN
+        HB_SCRIPT_BAMUM
+        HB_SCRIPT_EGYPTIAN_HIEROGLYPHS
+        HB_SCRIPT_IMPERIAL_ARAMAIC
+        HB_SCRIPT_INSCRIPTIONAL_PAHLAVI
+        HB_SCRIPT_INSCRIPTIONAL_PARTHIAN
+        HB_SCRIPT_JAVANESE
+        HB_SCRIPT_KAITHI
+        HB_SCRIPT_LISU
+        HB_SCRIPT_MEITEI_MAYEK
+        HB_SCRIPT_OLD_SOUTH_ARABIAN
+        HB_SCRIPT_OLD_TURKIC
+        HB_SCRIPT_SAMARITAN
+        HB_SCRIPT_TAI_THAM
+        HB_SCRIPT_TAI_VIET
 
 cdef extern from "hb-language.h" :
     ctypedef void *hb_language_t
@@ -120,7 +137,7 @@ cdef extern from "hb-language.h" :
     char * hb_language_to_string(hb_language_t language)
 
 cdef extern from "hb-ot-tag.h" :
-    hb_script_t hb_ot_string_to_script (char *sname)
+    hb_script_t hb_ot_tag_to_script (char *sname)
 
 cdef extern from "hb-buffer.h" :
     ctypedef struct hb_buffer_t :
@@ -178,7 +195,6 @@ cdef extern from "hb-font.h" :
     void hb_face_destroy(hb_face_t *face)
     void hb_font_destroy(hb_font_t *font)
     hb_blob_t * hb_face_get_table(hb_face_t *face, hb_tag_t tag)
-    void hb_font_set_tracecallback(hb_font_t *font, void (*cb)(char *type, int index, hb_buffer_t *))
 
 
 cdef extern from "hb-shape.h" :
@@ -208,10 +224,6 @@ class glyphinfo :
         if self.internal : res += "/i=" + str(self.internal)
         return res
 
-gcb = None
-cdef void hb_python_trace(char *aType, int i, hb_buffer_t *aBuffer) :
-    gcb(aType, i)
-
 cdef class buffer :
     cdef hb_buffer_t *buffer
 
@@ -260,10 +272,8 @@ cdef class ft :
     cdef FT_Face face
     cdef hb_face_t *hbface
     cdef hb_font_t *hbfont
-    cdef object tracefn
 
-    def __init__(self, char *fname, size, trace = None) :
-        global gcb
+    def __init__(self, char *fname, size) :
         cdef FT_Library engine
         FT_Init_FreeType(&engine)
         self.engine = engine
@@ -273,13 +283,6 @@ cdef class ft :
         self.face = face
         self.hbface = hb_ft_face_create(face, <void (*)(void *)>hb_face_destroy)
         self.hbfont = hb_ft_font_create(face, <void (*)(void *)>hb_font_destroy)
-        if trace :
-            self.tracefn = trace
-            gcb = self.trace
-            hb_font_set_tracecallback(self.hbfont, hb_python_trace)
-
-    def trace(self, aType, index) :
-        self.tracefn(self, aType, index)
 
     def __del__(self) :
         cdef FT_Library engine
@@ -295,8 +298,7 @@ cdef class ft :
         feats = <hb_feature_t *>malloc(sizeof(hb_feature_t) * len(features))
         aFeat = feats
         for k,v in features.items() :
-            k = k + "    "
-            aFeat.tag = (ord(k[0]) << 24) + (ord(k[1]) << 16) + (ord(k[2]) << 8) + ord(k[3])
+            aFeat.tag = hb_tag_from_string (k)
             aFeat.value = int(v)
             aFeat.start = 0
             aFeat.end = -1
commit 83f34677bcbc6bb194940407b0fcb23575650e3d
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri May 21 13:43:49 2010 +0100

    Add hb_tag_from_string()

diff --git a/src/Makefile.am b/src/Makefile.am
index fb82f0e..70cbfd8 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -14,6 +14,7 @@ HBSOURCES =  \
 	hb-blob-private.h \
 	hb-buffer.cc \
 	hb-buffer-private.hh \
+	hb-common.c \
 	hb-font.cc \
 	hb-font-private.hh \
 	hb-object-private.h \
diff --git a/src/hb-common.c b/src/hb-common.c
new file mode 100644
index 0000000..d205fc8
--- /dev/null
+++ b/src/hb-common.c
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2010  Red Hat, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Red Hat Author(s): Behdad Esfahbod
+ */
+
+#include "hb-private.h"
+
+hb_tag_t
+hb_tag_from_string (const char *s)
+{
+  char tag[4];
+  unsigned int i;
+
+  for (i = 0; i < 4 && s[i]; i++)
+    tag[i] = s[i];
+  for (; i < 4; i++)
+    tag[i] = ' ';
+
+  return HB_TAG_STR (tag);
+}
diff --git a/src/hb-common.h b/src/hb-common.h
index 594d358..74d8512 100644
--- a/src/hb-common.h
+++ b/src/hb-common.h
@@ -65,6 +65,9 @@ typedef uint32_t hb_tag_t;
 				((const char *) s)[3]))
 #define HB_TAG_NONE HB_TAG(0,0,0,0)
 
+hb_tag_t hb_tag_from_string (const char *s);
+
+
 typedef uint32_t hb_codepoint_t;
 typedef int32_t hb_position_t;
 typedef uint32_t hb_mask_t;
commit 4a9a5c0b06e8aa5d15327242609a7c766d3e0e94
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri May 21 13:33:46 2010 +0100

    Don't allocate bits for features not available

diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc
index 84f3432..8e5d6d8 100644
--- a/src/hb-ot-shape.cc
+++ b/src/hb-ot-shape.cc
@@ -125,6 +125,11 @@ setup_lookups (hb_face_t    *face,
   unsigned int global_values = 0;
   for (i = 0; i < num_features; i++)
   {
+    if (!hb_ot_layout_language_find_feature (face, table_tag, script_index, language_index,
+					     features[i].tag,
+					     &feature_index))
+      continue;
+
     unsigned int bits_needed = _hb_bit_storage (features[i].value);
     if (!bits_needed)
       continue;
@@ -132,10 +137,7 @@ setup_lookups (hb_face_t    *face,
     unsigned int value = features[i].value << last_bit_used;
     last_bit_used += bits_needed;
 
-    if (hb_ot_layout_language_find_feature (face, table_tag, script_index, language_index,
-					    features[i].tag,
-					    &feature_index))
-      add_feature (face, table_tag, feature_index, mask, lookups, num_lookups, room_lookups);
+    add_feature (face, table_tag, feature_index, mask, lookups, num_lookups, room_lookups);
 
     if (features[i].start == 0 && features[i].end == (unsigned int)-1)
       global_values |= value;
commit e53d77142ac4ecbe38ab3235491fa93cb7ff16ab
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri May 21 13:32:38 2010 +0100

    Speed up feature mask setting
    
    Patch from Jonathan Kew.

diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc
index 6a8c7ec..84f3432 100644
--- a/src/hb-ot-shape.cc
+++ b/src/hb-ot-shape.cc
@@ -122,6 +122,7 @@ setup_lookups (hb_face_t    *face,
     buffer->info[i].mask = 1;
 
   unsigned int last_bit_used = 1;
+  unsigned int global_values = 0;
   for (i = 0; i < num_features; i++)
   {
     unsigned int bits_needed = _hb_bit_storage (features[i].value);
@@ -136,15 +137,33 @@ setup_lookups (hb_face_t    *face,
 					    &feature_index))
       add_feature (face, table_tag, feature_index, mask, lookups, num_lookups, room_lookups);
 
-    /* Turn mask on in the buffer, the über-slow way! */
-    unsigned int count = buffer->len;
-    for (unsigned int j = 0; j < count; j++) {
-        unsigned int cluster = buffer->info[j].cluster;
-	if (features[i].start <= cluster && cluster < features[i].end)
-	  buffer->info[j].mask |= value;
+    if (features[i].start == 0 && features[i].end == (unsigned int)-1)
+      global_values |= value;
+    else
+    {
+      unsigned int start = features[i].start, end = features[i].end;
+      unsigned int a = 0, b = buffer->len;
+      while (a < b)
+      {
+        unsigned int h = a + ((b - a) / 2);
+        if (buffer->info[h].cluster < start)
+          a = h + 1;
+        else
+          b = h;
+      }
+      unsigned int count = buffer->len;
+      for (unsigned int j = a; j < count && buffer->info[j].cluster < end; j++)
+        buffer->info[j].mask |= value;
     }
   }
 
+  if (global_values)
+  {
+    unsigned int count = buffer->len;
+    for (unsigned int j = 0; j < count; j++)
+      buffer->info[j].mask |= global_values;
+  }
+
   qsort (lookups, *num_lookups, sizeof (lookups[0]), cmp_lookups);
 
   if (*num_lookups)
commit 4fa67f34ecc65056ce60a572213fbdae66e0423b
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri May 21 13:29:12 2010 +0100

    Add Unicode 5.2 scripts

diff --git a/src/hb-icu.c b/src/hb-icu.c
index 8e4ef94..2d1ef85 100644
--- a/src/hb-icu.c
+++ b/src/hb-icu.c
@@ -31,6 +31,7 @@
 
 #include "hb-unicode-private.h"
 
+#include <unicode/uversion.h>
 #include <unicode/uchar.h>
 #include <unicode/uscript.h>
 
@@ -110,9 +111,12 @@ hb_icu_get_script (hb_codepoint_t unicode)
   UScriptCode scriptCode = uscript_getScript(unicode, &status);
   switch ((int) scriptCode)
   {
+#define CHECK_ICU_VERSION(major, minor) \
+	U_ICU_VERSION_MAJOR_NUM > (major) || (U_ICU_VERSION_MAJOR_NUM == (major) && U_ICU_VERSION_MINOR_NUM >= (minor))
 #define MATCH_SCRIPT(C) case USCRIPT_##C: return HB_SCRIPT_##C
+#define MATCH_SCRIPT2(C1, C2) case USCRIPT_##C1: return HB_SCRIPT_##C2
   MATCH_SCRIPT (INVALID_CODE);
-  MATCH_SCRIPT (COMMON);   /* Zyyy */
+  MATCH_SCRIPT (COMMON);             /* Zyyy */
   MATCH_SCRIPT (INHERITED);          /* Qaai */
   MATCH_SCRIPT (ARABIC);             /* Arab */
   MATCH_SCRIPT (ARMENIAN);           /* Armn */
@@ -198,6 +202,29 @@ hb_icu_get_script (hb_codepoint_t unicode)
   MATCH_SCRIPT (CARIAN);             /* Cari */
   MATCH_SCRIPT (LYCIAN);             /* Lyci */
   MATCH_SCRIPT (LYDIAN);             /* Lydi */
+
+  /* Unicode-5.2 additions */
+  MATCH_SCRIPT (AVESTAN);                /* Avst */
+#if CHECK_ICU_VERSION (4, 4)
+  MATCH_SCRIPT (BAMUM);                  /* Bamu */
+#endif
+  MATCH_SCRIPT (EGYPTIAN_HIEROGLYPHS);   /* Egyp */
+  MATCH_SCRIPT (IMPERIAL_ARAMAIC);       /* Armi */
+  MATCH_SCRIPT (INSCRIPTIONAL_PAHLAVI);  /* Phli */
+  MATCH_SCRIPT (INSCRIPTIONAL_PARTHIAN); /* Prti */
+  MATCH_SCRIPT (JAVANESE);               /* Java */
+  MATCH_SCRIPT (KAITHI);                 /* Kthi */
+  MATCH_SCRIPT2(LANNA, TAI_THAM);        /* Lana */
+#if CHECK_ICU_VERSION (4, 4)
+  MATCH_SCRIPT (LISU);                   /* Lisu */
+#endif
+  MATCH_SCRIPT (MEITEI_MAYEK);           /* Mtei */
+#if CHECK_ICU_VERSION (4, 4)
+  MATCH_SCRIPT (OLD_SOUTH_ARABIAN);      /* Sarb */
+#endif
+  MATCH_SCRIPT2(ORKHON, OLD_TURKIC);     /* Orkh */
+  MATCH_SCRIPT (SAMARITAN);              /* Samr */
+  MATCH_SCRIPT (TAI_VIET);               /* Tavt */
   }
   return HB_SCRIPT_UNKNOWN;
 }
diff --git a/src/hb-ot-tag.c b/src/hb-ot-tag.c
index a77fef8..d1d42f5 100644
--- a/src/hb-ot-tag.c
+++ b/src/hb-ot-tag.c
@@ -120,7 +120,24 @@ static const hb_tag_t ot_scripts[][3] = {
   {HB_TAG('v','a','i',' ')},	/* HB_SCRIPT_VAI */
   {HB_TAG('c','a','r','i')},	/* HB_SCRIPT_CARIAN */
   {HB_TAG('l','y','c','i')},	/* HB_SCRIPT_LYCIAN */
-  {HB_TAG('l','y','d','i')} 	/* HB_SCRIPT_LYDIAN */
+  {HB_TAG('l','y','d','i')},	/* HB_SCRIPT_LYDIAN */
+
+  /* Unicode-5.2 additions */
+  {HB_TAG('D','F','L','T')},	/* HB_SCRIPT_AVESTAN */
+  {HB_TAG('D','F','L','T')},	/* HB_SCRIPT_BAMUM */
+  {HB_TAG('D','F','L','T')},	/* HB_SCRIPT_EGYPTIAN_HIEROGLYPHS */
+  {HB_TAG('D','F','L','T')},	/* HB_SCRIPT_IMPERIAL_ARAMAIC */
+  {HB_TAG('D','F','L','T')},	/* HB_SCRIPT_INSCRIPTIONAL_PAHLAVI */
+  {HB_TAG('D','F','L','T')},	/* HB_SCRIPT_INSCRIPTIONAL_PARTHIAN */
+  {HB_TAG('j','a','v','a')},	/* HB_SCRIPT_JAVANESE */
+  {HB_TAG('D','F','L','T')},	/* HB_SCRIPT_KAITHI */
+  {HB_TAG('D','F','L','T')},	/* HB_SCRIPT_LISU */
+  {HB_TAG('D','F','L','T')},	/* HB_SCRIPT_MEITEI_MAYEK */
+  {HB_TAG('D','F','L','T')},	/* HB_SCRIPT_OLD_SOUTH_ARABIAN */
+  {HB_TAG('D','F','L','T')},	/* HB_SCRIPT_OLD_TURKIC */
+  {HB_TAG('D','F','L','T')},	/* HB_SCRIPT_SAMARITAN */
+  {HB_TAG('D','F','L','T')},	/* HB_SCRIPT_TAI_THAM */
+  {HB_TAG('D','F','L','T')} 	/* HB_SCRIPT_TAI_VIET */
 };
 
 const hb_tag_t *
@@ -140,7 +157,7 @@ hb_ot_tag_to_script (hb_tag_t tag)
   int i;
 
   for (i = 0; i < ARRAY_LENGTH (ot_scripts); i++) {
-    hb_tag_t *p = ot_scripts[i];
+    const hb_tag_t *p = ot_scripts[i];
     while (*p)
       if (tag == *p)
         return i;
diff --git a/src/hb-unicode.c b/src/hb-unicode.c
index 7970a79..1813940 100644
--- a/src/hb-unicode.c
+++ b/src/hb-unicode.c
@@ -286,7 +286,24 @@ const hb_direction_t horiz_dir[] =
   LTR,	/* Vaii */
   LTR,	/* Cari */
   LTR,	/* Lyci */
-  LTR	/* Lydi */
+  LTR,	/* Lydi */
+
+  /* Unicode-5.2 additions */
+  RTL,	/* Avst */
+  LTR,	/* Bamu */
+  LTR,	/* Egyp */
+  RTL,	/* Armi */
+  RTL,	/* Phli */
+  RTL,	/* Prti */
+  LTR,	/* Java */
+  LTR,	/* Kthi */
+  LTR,	/* Lisu */
+  LTR,	/* Mtei */
+  RTL,	/* Sarb */
+  RTL,	/* Orkh */
+  RTL,	/* Samr */
+  LTR,	/* Lana */
+  LTR 	/* Tavt */
 };
 #undef LTR
 #undef RTL
diff --git a/src/hb-unicode.h b/src/hb-unicode.h
index dc70bd1..2f4f69b 100644
--- a/src/hb-unicode.h
+++ b/src/hb-unicode.h
@@ -155,7 +155,24 @@ typedef enum
   HB_SCRIPT_VAI,                /* Vaii */
   HB_SCRIPT_CARIAN,             /* Cari */
   HB_SCRIPT_LYCIAN,             /* Lyci */
-  HB_SCRIPT_LYDIAN              /* Lydi */
+  HB_SCRIPT_LYDIAN,             /* Lydi */
+
+  /* Unicode-5.2 additions */
+  HB_SCRIPT_AVESTAN,                /* Avst */
+  HB_SCRIPT_BAMUM,                  /* Bamu */
+  HB_SCRIPT_EGYPTIAN_HIEROGLYPHS,   /* Egyp */
+  HB_SCRIPT_IMPERIAL_ARAMAIC,       /* Armi */
+  HB_SCRIPT_INSCRIPTIONAL_PAHLAVI,  /* Phli */
+  HB_SCRIPT_INSCRIPTIONAL_PARTHIAN, /* Prti */
+  HB_SCRIPT_JAVANESE,               /* Java */
+  HB_SCRIPT_KAITHI,                 /* Kthi */
+  HB_SCRIPT_LISU,                   /* Lisu */
+  HB_SCRIPT_MEITEI_MAYEK,           /* Mtei */
+  HB_SCRIPT_OLD_SOUTH_ARABIAN,      /* Sarb */
+  HB_SCRIPT_OLD_TURKIC,             /* Orkh */
+  HB_SCRIPT_SAMARITAN,              /* Samr */
+  HB_SCRIPT_TAI_THAM,               /* Lana */
+  HB_SCRIPT_TAI_VIET                /* Tavt */
 } hb_script_t;
 
 
commit ee1b322100a6bd575b999904592abbd9fed5587f
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri May 21 12:55:57 2010 +0100

    Fix feature mask setting

diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc
index 509ce7d..6a8c7ec 100644
--- a/src/hb-ot-shape.cc
+++ b/src/hb-ot-shape.cc
@@ -138,10 +138,10 @@ setup_lookups (hb_face_t    *face,
 
     /* Turn mask on in the buffer, the über-slow way! */
     unsigned int count = buffer->len;
-    for (unsigned int i = 0; i < count; i++) {
-        unsigned int cluster = buffer->info[i].cluster;
+    for (unsigned int j = 0; j < count; j++) {
+        unsigned int cluster = buffer->info[j].cluster;
 	if (features[i].start <= cluster && cluster < features[i].end)
-	  buffer->info[i].mask |= value;
+	  buffer->info[j].mask |= value;
     }
   }
 
commit b490fa343322f1b5abaf880abc073287c1f34132
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri May 21 11:15:07 2010 +0100

    Add hb_ot_tag_to_script()

diff --git a/src/hb-ot-tag.c b/src/hb-ot-tag.c
index fc4889b..a77fef8 100644
--- a/src/hb-ot-tag.c
+++ b/src/hb-ot-tag.c
@@ -134,6 +134,20 @@ hb_ot_tags_from_script (hb_script_t script)
   return ot_scripts[script];
 }
 
+hb_script_t
+hb_ot_tag_to_script (hb_tag_t tag)
+{
+  int i;
+
+  for (i = 0; i < ARRAY_LENGTH (ot_scripts); i++) {
+    hb_tag_t *p = ot_scripts[i];
+    while (*p)
+      if (tag == *p)
+        return i;
+  }
+
+  return HB_SCRIPT_UNKNOWN;
+}
 
 typedef struct {
   char language[6];
diff --git a/src/hb-ot-tag.h b/src/hb-ot-tag.h
index 2dab2e8..6d15d4e 100644
--- a/src/hb-ot-tag.h
+++ b/src/hb-ot-tag.h
@@ -38,6 +38,9 @@ HB_BEGIN_DECLS
 const hb_tag_t *
 hb_ot_tags_from_script (hb_script_t script);
 
+hb_script_t
+hb_ot_tag_to_script (hb_tag_t tag);
+
 hb_tag_t
 hb_ot_tag_from_language (hb_language_t language);
 
commit 50355309047765558ef8f5d60aefed42a7f954cc
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri May 21 10:33:23 2010 +0100

    Add Python wrapper from Martin Hosken

diff --git a/contrib/python/lib/harfbuzz.pyx b/contrib/python/lib/harfbuzz.pyx
new file mode 100644
index 0000000..1f254ff
--- /dev/null
+++ b/contrib/python/lib/harfbuzz.pyx
@@ -0,0 +1,306 @@
+cdef extern from "stdlib.h":
+    ctypedef int size_t
+    void *malloc(size_t size)
+    void free(void* ptr)
+
+cdef extern from "ft2build.h" :
+    pass
+
+cdef extern from "freetype/freetype.h" :
+    ctypedef void *FT_Library 
+    ctypedef void *FT_Face
+    ctypedef int FT_Error
+
+    FT_Error FT_Init_FreeType (FT_Library *alib)
+    FT_Error FT_Done_FreeType (FT_Library alib)
+    FT_Error FT_Done_Face (FT_Face alib)
+    FT_Error FT_New_Face( FT_Library library, char *path, unsigned long index, FT_Face *aface)
+    FT_Error FT_Set_Char_Size (FT_Face aFace, unsigned int size_x, unsigned int size_y, unsigned int res_x, unsigned int res_y)
+
+cdef extern from "hb-common.h" :
+    cdef enum hb_direction_t :
+        HB_DIRECTION_LTR
+        HB_DIRECTION_RTL
+        HB_DIRECTION_TTB
+        HB_DIRECTION_BTT
+    ctypedef unsigned long hb_codepoint_t
+    ctypedef long hb_position_t
+    ctypedef unsigned long hb_mask_t
+    ctypedef unsigned long hb_tag_t
+    ctypedef void (*hb_destroy_func_t) (void *user_data)
+
+cdef extern from "hb-unicode.h" :
+# there must be a better way of syncing this list with the true source
+    ctypedef enum hb_script_t :
+        HB_SCRIPT_INVALID_CODE = -1,
+        HB_SCRIPT_COMMON = 0,
+        HB_SCRIPT_INHERITED,
+        HB_SCRIPT_ARABIC,
+        HB_SCRIPT_ARMENIAN,
+        HB_SCRIPT_BENGALI,
+        HB_SCRIPT_BOPOMOFO,
+        HB_SCRIPT_CHEROKEE,
+        HB_SCRIPT_DESERET,
+        HB_SCRIPT_DEVANAGARI,
+        HB_SCRIPT_ETHIOPIC,
+        HB_SCRIPT_GEORGIAN,
+        HB_SCRIPT_GOTHIC,
+        HB_SCRIPT_GREEK,
+        HB_SCRIPT_GUJARATI,
+        HB_SCRIPT_GURMUKHI,
+        HB_SCRIPT_HAN,
+        HB_SCRIPT_HANGUL,
+        HB_SCRIPT_HEBREW,
+        HB_SCRIPT_HIRAGANA,
+        HB_SCRIPT_KANNADA,
+        HB_SCRIPT_KATAKANA,
+        HB_SCRIPT_KHMER,
+        HB_SCRIPT_LAO,
+        HB_SCRIPT_LATIN,
+        HB_SCRIPT_MALAYALAM,
+        HB_SCRIPT_MONGOLIAN,
+        HB_SCRIPT_MYANMAR,
+        HB_SCRIPT_OGHAM,
+        HB_SCRIPT_OLD_ITALIC,
+        HB_SCRIPT_ORIYA,
+        HB_SCRIPT_RUNIC,
+        HB_SCRIPT_SINHALA,
+        HB_SCRIPT_SYRIAC,
+        HB_SCRIPT_TAMIL,
+        HB_SCRIPT_TELUGU,
+        HB_SCRIPT_THAANA,
+        HB_SCRIPT_THAI,
+        HB_SCRIPT_TIBETAN,
+        HB_SCRIPT_CANADIAN_ABORIGINAL,
+        HB_SCRIPT_YI,
+        HB_SCRIPT_TAGALOG,
+        HB_SCRIPT_HANUNDO,
+        HB_SCRIPT_BUHID,
+        HB_SCRIPT_TAGBANWA,
+# Unicode 4.0
+        HB_SCRIPT_BRAILLE,
+        HB_SCRIPT_CYPRIOT,
+        HB_SCRIPT_LIMBU,
+        HB_SCRIPT_OSMANYA,
+        HB_SCRIPT_SHAVIAN,
+        HB_SCRIPT_LINEAR_B,
+        HB_SCRIPT_TAI_LE,
+        HB_SCRIPT_UGARITIC,
+# Unicode 4.1
+        HB_SCRIPT_NEW_TAI_LUE,
+        HB_SCRIPT_BUGINESE,
+        HB_SCRIPT_GLAGOLITIC,
+        HB_SCRIPT_TIFINAGH,
+        HB_SCRIPT_SYLOTI_NAGRI,
+        HB_SCRIPT_OLD_PERSIAN,
+        HB_SCRIPT_KHAROSHTHI,
+# Unicode 5.0
+        HB_SCRIPT_UNKNOWN,
+        HB_SCRIPT_BALINESE,
+        HB_SCRIPT_CUNEIFORM,
+        HB_SCRIPT_PHOENICIAN,
+        HB_SCRIPT_PHAGS_PA,
+        HB_SCRIPT_NKO,
+# Unicode 5.1
+        HB_SCRIPT_KAYAH_LI,
+        HB_SCRIPT_LEPCHA,
+        HB_SCRIPT_REJANG,
+        HB_SCRIPT_SUNDANESE,
+        HB_SCRIPT_SAURASHTRA,
+        HB_SCRIPT_CHAM,
+        HB_SCRIPT_OL_CHIKI,
+        HB_SCRIPT_VAI,
+        HB_SCRIPT_CARIAN,
+        HB_SCRIPT_LYCIAN,
+        HB_SCRIPT_LYDIAN
+
+cdef extern from "hb-language.h" :
+    ctypedef void *hb_language_t
+    hb_language_t hb_language_from_string(char *str)
+    char * hb_language_to_string(hb_language_t language)
+
+cdef extern from "hb-ot-tag.h" :
+    hb_script_t hb_ot_string_to_script (char *sname)
+
+cdef extern from "hb-buffer.h" :
+    ctypedef struct hb_buffer_t :
+        pass
+
+    ctypedef struct hb_glyph_info_t :
+        hb_codepoint_t codepoint
+        hb_mask_t mask
+        unsigned long cluster
+
+    ctypedef struct hb_glyph_position_t :
+        hb_position_t x_advance
+        hb_position_t y_advance
+        hb_position_t x_offset
+        hb_position_t y_offset
+        unsigned long internal
+
+    hb_buffer_t *hb_buffer_create(unsigned int size)
+    hb_buffer_t *hb_buffer_reference(hb_buffer_t *buffer)
+    unsigned int hb_buffer_get_reference_count(hb_buffer_t *buffer)
+    void hb_buffer_destroy(hb_buffer_t *buffer)
+    void hb_buffer_set_direction(hb_buffer_t *buffer, hb_direction_t direction)
+    hb_direction_t hb_buffer_get_direction(hb_buffer_t *buffer)
+    void hb_buffer_set_script(hb_buffer_t *buffer, hb_script_t script)
+    hb_script_t hb_buffer_get_script(hb_buffer_t *buffer)
+    void hb_buffer_set_language(hb_buffer_t *buffer, hb_language_t language)
+    hb_language_t hb_buffer_get_language(hb_buffer_t *buffer)
+    void hb_buffer_clear(hb_buffer_t *)
+    void hb_buffer_clear_positions(hb_buffer_t *buffer)
+    void hb_buffer_ensure(hb_buffer_t *buffer, unsigned int size)
+    void hb_buffer_reverse(hb_buffer_t *buffer)
+    void hb_buffer_reverse_clusters(hb_buffer_t *buffer)
+    void hb_buffer_add_glyph(hb_buffer_t *buffer, hb_codepoint_t codepoint, hb_mask_t mask, unsigned int cluster)
+    void hb_buffer_add_utf8(hb_buffer_t *buffer, char *text, unsigned int text_length, unsigned int item_offset, unsigned int item_length)
+    unsigned int hb_buffer_get_length(hb_buffer_t *buffer)
+    hb_glyph_info_t *hb_buffer_get_glyph_infos(hb_buffer_t *buffer)
+    hb_glyph_position_t *hb_buffer_get_glyph_positions(hb_buffer_t *buffer)
+
+cdef extern from "hb-blob.h" :
+    cdef struct hb_blob_t :
+        pass
+# do I need blob functions here?
+
+cdef extern from "hb-font.h" :
+    ctypedef struct hb_face_t :
+        pass
+    ctypedef struct hb_font_t :
+        pass
+
+    ctypedef hb_blob_t * (*hb_get_table_func_t) (hb_tag_t tag, void *user_data)
+    hb_face_t * hb_face_create_for_data(hb_blob_t *blob, unsigned int index)
+    hb_face_t * hb_face_create_for_tables(hb_get_table_func_t get_table, hb_destroy_func_t destroy, void *user_data)
+    hb_face_t * hb_face_reference(hb_face_t *face)
+    unsigned int hb_face_get_reference_count(hb_face_t *face)
+    void hb_face_destroy(hb_face_t *face)
+    void hb_font_destroy(hb_font_t *font)
+    hb_blob_t * hb_face_get_table(hb_face_t *face, hb_tag_t tag)
+    void hb_font_set_tracecallback(hb_font_t *font, void (*cb)(char *type, int index, hb_buffer_t *))
+
+
+cdef extern from "hb-shape.h" :
+    ctypedef struct hb_feature_t :
+        int tag
+        unsigned int value
+        unsigned int start
+        unsigned int end
+
+    void hb_shape (hb_font_t *font, hb_face_t *face, hb_buffer_t *buffer, hb_feature_t *features, unsigned int num_features)
+
+cdef extern from "hb-ft.h" :
+    hb_face_t *hb_ft_face_create (FT_Face ft_face, hb_destroy_func_t destroy)
+    hb_font_t *hb_ft_font_create (FT_Face ft_face, hb_destroy_func_t destroy)
+
+class glyphinfo :
+ 
+    def __init__(self, gid, cluster, advance, offset, internal = 0) :
+        self.gid = gid
+        self.cluster = cluster
+        self.advance = advance
+        self.offset = offset
+        self.internal = internal
+
+    def __repr__(self) :
+        res = "{0:d}>{1:d}@({2:.2f},{3:.2f})+({4:.2f},{5:.2f})".format(self.gid, self.cluster, self.offset[0], self.offset[1], self.advance[0], self.advance[1])
+        if self.internal : res += "/i=" + str(self.internal)
+        return res
+
+gcb = None
+cdef void hb_python_trace(char *aType, int i, hb_buffer_t *aBuffer) :
+    gcb(aType, i)
+
+cdef class buffer :
+    cdef hb_buffer_t *buffer
+
+    def __init__(self, char *text, unsigned int length) :
+        """Note text must be a utf-8 string and length is number of chars"""
+        self.buffer = hb_buffer_create(length)
+        hb_buffer_add_utf8(self.buffer, text, length, 0, len(text))
+
+    def set_scriptlang(self, char *script, char *lang) :
+        cdef hb_language_t language
+        cdef hb_script_t scriptnum
+
+        language = hb_language_from_string(lang)
+        scriptnum = hb_ot_string_to_script(script)
+        hb_buffer_set_script(self.buffer, scriptnum)
+        hb_buffer_set_language(self.buffer, language)
+
+    def get_info(self, scale = 1) :
+        cdef hb_glyph_info_t *infos
+        cdef hb_glyph_position_t *positions
+        cdef unsigned int num
+        cdef unsigned int i
+        res = []
+
+        num = hb_buffer_get_length(self.buffer)
+        infos = hb_buffer_get_glyph_infos(self.buffer)
+        positions = hb_buffer_get_glyph_positions(self.buffer)
+        for 0 <= i < num :
+            temp = glyphinfo(infos[i].codepoint, infos[i].cluster, (positions[i].x_advance / scale, positions[i].y_advance / scale), (positions[i].x_offset / scale, positions[i].y_offset / scale), positions[i].internal)
+            res.append(temp)
+        return res
+
+    def get_settings(self) :
+        cdef hb_script_t script
+        cdef hb_language_t lang
+
+        script = hb_buffer_get_script(self.buffer)
+        lang = hb_buffer_get_language(self.buffer)
+        return {'script' : script, 'language' : hb_language_to_string(lang)}
+
+    def __del__(self) :
+        hb_buffer_destroy(self.buffer)
+
+cdef class ft :
+    cdef FT_Library engine
+    cdef FT_Face face
+    cdef hb_face_t *hbface
+    cdef hb_font_t *hbfont
+    cdef object tracefn
+
+    def __init__(self, char *fname, size, trace = None) :
+        global gcb
+        cdef FT_Library engine
+        FT_Init_FreeType(&engine)
+        self.engine = engine
+        cdef FT_Face face
+        FT_New_Face(engine, fname, 0, &face)
+        FT_Set_Char_Size(face, size << 6, size << 6, 144, 144)
+        self.face = face
+        self.hbface = hb_ft_face_create(face, <void (*)(void *)>hb_face_destroy)
+        self.hbfont = hb_ft_font_create(face, <void (*)(void *)>hb_font_destroy)
+        if trace :
+            self.tracefn = trace
+            gcb = self.trace
+            hb_font_set_tracecallback(self.hbfont, hb_python_trace)
+
+    def trace(self, aType, index) :
+        self.tracefn(self, aType, index)
+
+    def __del__(self) :
+        cdef FT_Library engine
+        engine = self.engine
+        cdef FT_Face face
+        face = self.face
+        FT_Done_Face(face)
+        FT_Done_FreeType(engine)
+
+    def shape(self, buffer aBuffer, features = {}) :
+        cdef hb_feature_t *feats
+        cdef hb_feature_t *aFeat
+        feats = <hb_feature_t *>malloc(sizeof(hb_feature_t) * len(features))
+        aFeat = feats
+        for k,v in features.items() :
+            k = k + "    "
+            aFeat.tag = (ord(k[0]) << 24) + (ord(k[1]) << 16) + (ord(k[2]) << 8) + ord(k[3])
+            aFeat.value = int(v)
+            aFeat.start = 0
+            aFeat.end = -1
+            aFeat += 1
+        hb_shape(self.hbfont, self.hbface, aBuffer.buffer, feats, len(features))
+
+
diff --git a/contrib/python/runpy b/contrib/python/runpy
new file mode 100755
index 0000000..b39db1b
--- /dev/null
+++ b/contrib/python/runpy
@@ -0,0 +1,2 @@
+#!/bin/sh
+LD_LIBRARY_PATH=../../src/.libs PYTHONPATH=build/lib.`python -c 'import distutils.util, sys; print distutils.util.get_platform()+"-"+str(sys.version_info[0])+"."+str(sys.version_info[1])'` "$@"
diff --git a/contrib/python/scripts/hbtestfont b/contrib/python/scripts/hbtestfont
new file mode 100755
index 0000000..4d1134d
--- /dev/null
+++ b/contrib/python/scripts/hbtestfont
@@ -0,0 +1,35 @@
+#!/usr/bin/python
+
+import harfbuzz, optparse
+
+buffer = None
+
+def tracefn(ft, aType, index) :
+    print aType + "(" + str(index) + "): " + str(buffer.get_info())
+
+usage = '''usage: %prog [options] fontfile "codepoints"
+    Generates output of glyphs and positions. Each entry is of the form:
+        glyphid>cluster@(offsetx,offsety)+(advancex,advancey)
+
+    codepoints is a space separated list of hex values of Unicode codepoints'''
+p = optparse.OptionParser(usage=usage)
+p.add_option('-s', '--size', default=12, type="int", help="point size")
+p.add_option('-l', '--lang', help="language code")
+p.add_option('-c', '--script', help="script code")
+p.add_option('-f', '--feature', action='append', help="define a feature key=val")
+p.add_option('-d', '--debug', action='store_true', help="Output trace info")
+(opts, args) = p.parse_args()
+
+ft = harfbuzz.ft(args[0], opts.size, trace = tracefn if opts.debug else None)
+text = "".join(unichr(int(c, 16)) for c in args[1].split(" "))
+bytes = text.encode('utf_8')
+buffer = harfbuzz.buffer(bytes, len(text))
+if (opts.lang or opts.script) : buffer.set_scriptlang(opts.script if opts.script else "", opts.lang if opts.lang else "")
+features = {}
+if opts.feature :
+    for f in opts.feature :
+        k, v = f.split("=")
+        features[k] = v
+ft.shape(buffer, features = features)
+res = buffer.get_info(64)       # scale for 26.6
+print res
diff --git a/contrib/python/setup.py b/contrib/python/setup.py
new file mode 100755
index 0000000..ef2412b
--- /dev/null
+++ b/contrib/python/setup.py
@@ -0,0 +1,24 @@
+#!/usr/bin/python
+
+from distutils.core import setup
+from glob import glob
+from Pyrex.Distutils.extension import Extension
+from Pyrex.Distutils import build_ext
+
+setup(name='harfbuzz',
+    version='0.0.1',
+    description='Harfbuzz compatibility layer',
+    long_description='Harfbuzz python integration modules and supporting scripts',
+    maintainer='Martin Hosken',
+    maintainer_email='martin_hosken at sil.org',
+    packages=['harfbuzz'],
+    ext_modules = [
+        Extension("harfbuzz", ["lib/harfbuzz.pyx"], libraries=["harfbuzz"], library_dirs=["../../src/.libs"], include_dirs=["/usr/include/freetype2", "../../src"])
+        ],
+    cmdclass = {'build_ext' : build_ext},
+    scripts = glob('scripts/*'),
+    license = 'LGPL',
+    platforms = ['Linux', 'Win32', 'Mac OS X'],
+    package_dir = {'harfbuzz' : 'lib'}
+)
+
commit 280af1bddb958ff97cf7ce12fe7ec2b6352e61d0
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Thu May 20 18:33:35 2010 +0100

    Let hb_face_get_table() return NULL if table not found

diff --git a/src/hb-font.cc b/src/hb-font.cc
index 93787c0..a55deb3 100644
--- a/src/hb-font.cc
+++ b/src/hb-font.cc
@@ -364,7 +364,7 @@ hb_face_get_table (hb_face_t *face,
 
   blob = face->get_table (tag, face->user_data);
 
-  return likely (blob) ? blob : &_hb_blob_nil;
+  return blob;
 }
 
 
diff --git a/src/hb-font.h b/src/hb-font.h
index 433d31a..89324fa 100644
--- a/src/hb-font.h
+++ b/src/hb-font.h
@@ -60,6 +60,7 @@ hb_face_get_reference_count (hb_face_t *face);
 void
 hb_face_destroy (hb_face_t *face);
 
+/* Returns NULL if not found */
 hb_blob_t *
 hb_face_get_table (hb_face_t *face,
 		   hb_tag_t   tag);
diff --git a/src/hb-open-type-private.hh b/src/hb-open-type-private.hh
index 2ab639c..d2fbb21 100644
--- a/src/hb-open-type-private.hh
+++ b/src/hb-open-type-private.hh
@@ -283,6 +283,9 @@ struct Sanitizer
 
     /* TODO is_sane() stuff */
 
+    if (!blob)
+      return hb_blob_create_empty ();
+
   retry:
     if (HB_DEBUG_SANITIZE)
       fprintf (stderr, "Sanitizer %p start %s\n", blob, HB_FUNC);



More information about the HarfBuzz mailing list