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 <[email protected]> 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 <[email protected]> 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 <[email protected]> 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 <[email protected]> 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 <[email protected]> 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 <[email protected]> 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 <[email protected]> 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 <[email protected]> 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 <[email protected]> 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 <[email protected]> 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='[email protected]', + 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 <[email protected]> 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);
_______________________________________________ HarfBuzz mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/harfbuzz
