bug 631479 (part 1) - import graphite2 code from http://projects.palaso.org/projects/graphitedev/repository/revisions/853 (release 1.0.3 plus bugfixes). r=jdaggett
authorJonathan Kew <jfkthame@gmail.com>
Fri, 09 Dec 2011 22:32:28 +0000
changeset 82402 0973ce3ecd5d
parent 82401 f5d0e8d72b9b
child 82403 c25e81047a9e
push id21592
push userbmo@edmorley.co.uk
push dateSun, 11 Dec 2011 04:01:06 +0000
treeherdermozilla-central@f5578fdc50ef [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjdaggett
bugs631479
milestone11.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
bug 631479 (part 1) - import graphite2 code from http://projects.palaso.org/projects/graphitedev/repository/revisions/853 (release 1.0.3 plus bugfixes). r=jdaggett
gfx/graphite2/include/graphite2/Font.h
gfx/graphite2/include/graphite2/Segment.h
gfx/graphite2/include/graphite2/Types.h
gfx/graphite2/include/graphite2/XmlLog.h
gfx/graphite2/src/Bidi.cpp
gfx/graphite2/src/CMakeLists.txt
gfx/graphite2/src/CachedFace.cpp
gfx/graphite2/src/CachedFace.h
gfx/graphite2/src/CharInfo.h
gfx/graphite2/src/CmapCache.cpp
gfx/graphite2/src/CmapCache.h
gfx/graphite2/src/Code.cpp
gfx/graphite2/src/Code.h
gfx/graphite2/src/Endian.h
gfx/graphite2/src/Face.cpp
gfx/graphite2/src/Face.h
gfx/graphite2/src/FeatureMap.cpp
gfx/graphite2/src/FeatureMap.h
gfx/graphite2/src/FeatureVal.h
gfx/graphite2/src/Font.cpp
gfx/graphite2/src/Font.h
gfx/graphite2/src/GlyphFace.cpp
gfx/graphite2/src/GlyphFace.h
gfx/graphite2/src/GlyphFaceCache.cpp
gfx/graphite2/src/GlyphFaceCache.h
gfx/graphite2/src/List.h
gfx/graphite2/src/Machine.h
gfx/graphite2/src/Main.h
gfx/graphite2/src/NameTable.cpp
gfx/graphite2/src/NameTable.h
gfx/graphite2/src/Pass.cpp
gfx/graphite2/src/Pass.h
gfx/graphite2/src/Position.h
gfx/graphite2/src/Rule.cpp
gfx/graphite2/src/Rule.h
gfx/graphite2/src/SegCache.cpp
gfx/graphite2/src/SegCache.h
gfx/graphite2/src/SegCacheEntry.cpp
gfx/graphite2/src/SegCacheEntry.h
gfx/graphite2/src/SegCacheStore.cpp
gfx/graphite2/src/SegCacheStore.h
gfx/graphite2/src/Segment.cpp
gfx/graphite2/src/Segment.h
gfx/graphite2/src/Silf.cpp
gfx/graphite2/src/Silf.h
gfx/graphite2/src/Slot.cpp
gfx/graphite2/src/Slot.h
gfx/graphite2/src/Sparse.cpp
gfx/graphite2/src/Sparse.h
gfx/graphite2/src/TtfTypes.h
gfx/graphite2/src/TtfUtil.cpp
gfx/graphite2/src/TtfUtil.h
gfx/graphite2/src/UtfCodec.cpp
gfx/graphite2/src/UtfCodec.h
gfx/graphite2/src/XmlTraceLog.cpp
gfx/graphite2/src/XmlTraceLog.h
gfx/graphite2/src/XmlTraceLogTags.cpp
gfx/graphite2/src/XmlTraceLogTags.h
gfx/graphite2/src/call_machine.cpp
gfx/graphite2/src/direct_machine.cpp
gfx/graphite2/src/files.mk
gfx/graphite2/src/gr_char_info.cpp
gfx/graphite2/src/gr_face.cpp
gfx/graphite2/src/gr_features.cpp
gfx/graphite2/src/gr_font.cpp
gfx/graphite2/src/gr_logging.cpp
gfx/graphite2/src/gr_segment.cpp
gfx/graphite2/src/gr_slot.cpp
gfx/graphite2/src/locale2lcid.h
gfx/graphite2/src/opcode_table.h
gfx/graphite2/src/opcodes.h
gfx/graphite2/src/processUTF.h
new file mode 100644
--- /dev/null
+++ b/gfx/graphite2/include/graphite2/Font.h
@@ -0,0 +1,269 @@
+/*  GRAPHITE2 LICENSING
+
+    Copyright 2010, SIL International
+    All rights reserved.
+
+    This library is free software; you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published
+    by the Free Software Foundation; either version 2.1 of License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should also have received a copy of the GNU Lesser General Public
+    License along with this library in the file named "LICENSE".
+    If not, write to the Free Software Foundation, 51 Franklin Street,
+    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
+    internet at http://www.fsf.org/licenses/lgpl.html.
+
+    Alternatively, the contents of this file may be used under the terms
+    of the Mozilla Public License (http://mozilla.org/MPL) or the GNU
+    General Public License, as published by the Free Software Foundation,
+    either version 2 of the License or (at your option) any later version.
+*/
+#pragma once
+
+#include "graphite2/Types.h"
+
+#define GR2_VERSION_MAJOR   1
+#define GR2_VERSION_MINOR   0
+#define GR2_VERSION_BUGFIX  1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+typedef struct gr_face          gr_face;
+typedef struct gr_font          gr_font;
+typedef struct gr_feature_ref   gr_feature_ref;
+typedef struct gr_feature_val   gr_feature_val;
+
+/**
+* Returns version information on this engine
+*/
+GR2_API void gr_engine_version(int *nMajor, int *nMinor, int *nBugFix);
+
+/**
+* The Face Options allow the application to require that certain tables are
+* read during face construction. This may be of concern if the appFaceHandle
+* used in the gr_get_table_fn may change.
+* The values can be combined 
+*/
+enum gr_face_options {
+    /** No preload, no cmap caching, fail if the graphite tables are invalid */
+    gr_face_default = 0,
+    /** Dumb rendering will be enabled if the graphite tables are invalid */
+    gr_face_dumbRendering = 1,
+    /** preload glyphs at construction time */
+    gr_face_preloadGlyphs = 2,
+    /** Cache the lookup from code point to glyph ID at construction time */
+    gr_face_cacheCmap = 4,
+    /** Preload everything */
+    gr_face_preloadAll = 6
+};
+
+/** type describing function to retrieve font table information
+  *
+  * @return a pointer to the table in memory. The pointed to memory must exist as
+  *          long as the gr_face which makes the call.
+  * @param appFaceHandle is the unique information passed to gr_make_face()
+  * @param name is a 32bit tag to the table name.
+  * @param len returned by this function to say how long the table is in memory.
+  */
+typedef const void *(*gr_get_table_fn)(const void* appFaceHandle, unsigned int name, size_t *len);
+
+/** Create a gr_face object given application information and a getTable function
+  *
+  * @return gr_face or NULL if the font fails to load for some reason.
+  * @param appFaceHandle This is application specific information that is passed to the getTable
+  *                      function. The appFaceHandle must stay alive as long as the gr_face is alive.
+  * @param getTable  This function is called whenever graphite needs access to a table of data
+  *                  in the font.
+  * @param faceOptions   Bitfield describing various options. See enum gr_face_options for details.
+  */
+GR2_API gr_face* gr_make_face(const void* appFaceHandle/*non-NULL*/, gr_get_table_fn getTable, unsigned int faceOptions);
+
+#ifndef DISABLE_SEGCACHE
+/** Create a gr_face object given application information, with subsegmental caching support
+  *
+  * @return gr_face or NULL if the font fails to load.
+  * @param appFaceHandle is a pointer to application specific information that is passed to getTable.
+  *                      This may not be NULL and must stay alive as long as the gr_face is alive.
+  * @param getTable  The function graphite calls to access font table data
+  * @param segCacheMaxSize   How large the segment cache is.
+  * @param faceOptions   Bitfield of values from enum gr_face_options
+  */
+GR2_API gr_face* gr_make_face_with_seg_cache(const void* appFaceHandle, gr_get_table_fn getTable, unsigned int segCacheMaxSize, unsigned int faceOptions);
+#endif
+
+/** Convert a tag in a string into a gr_uint32
+  *
+  * @return gr_uint32 tag, zero padded
+  * @param str a nul terminated string of which at most the first 4 characters are read
+  */
+GR2_API gr_uint32 gr_str_to_tag(const char *str);
+
+/** Convert a gr_uint32 tag into a string
+  *
+  * @param tag contains the tag to convert
+  * @param str is a pointer to a char array of at least size 4 bytes. The first 4 bytes of this array
+  *            will be overwritten by this function. No nul is appended.
+  */
+GR2_API void gr_tag_to_str(gr_uint32 tag, char *str);
+
+/** Get feature values for a given language or default
+  *
+  * @return a copy of the default feature values for a given language. The application must call
+  *          gr_featureval_destroy() to free this object when done.
+  * @param pFace The font face to get feature values from
+  * @param langname The language tag to get feature values for. If there is no such language or
+  *                  langname is 0, the default feature values for the font are returned.
+  *                  langname is right 0 padded and assumes lowercase. Thus the en langauge
+  *                  would be 0x656E0000. Langname may also be space padded, thus 0x656E2020.
+  */
+GR2_API gr_feature_val* gr_face_featureval_for_lang(const gr_face* pFace, gr_uint32 langname);
+
+/** Get feature reference for a given feature id from a face
+  *
+  * @return a feature reference corresponding to the given id. This data is part of the gr_face and
+  *          will be freed when the face is destroyed.
+  * @param pFace Font face to get information on.
+  * @param featId    Feature id tag to get reference to.
+  */
+GR2_API const gr_feature_ref* gr_face_find_fref(const gr_face* pFace, gr_uint32 featId);
+
+/** Returns number of feature references in a face **/
+GR2_API gr_uint16 gr_face_n_fref(const gr_face* pFace);
+
+/** Returns feature reference at given index in face **/
+GR2_API const gr_feature_ref* gr_face_fref(const gr_face* pFace, gr_uint16 i);
+
+/** Return number of languages the face knows about **/
+GR2_API unsigned short gr_face_n_languages(const gr_face* pFace);
+
+/** Returns a language id corresponding to a language of given index in the face **/
+GR2_API gr_uint32 gr_face_lang_by_index(const gr_face* pFace, gr_uint16 i);
+
+/** Destroy the given face and free its memory **/
+GR2_API void gr_face_destroy(gr_face *face);
+
+/** Returns the number of glyphs in the face **/
+GR2_API unsigned short gr_face_n_glyphs(const gr_face* pFace);
+
+#ifndef DISABLE_FILE_FACE
+/** Create gr_face from a font file
+  *
+  * @return gr_face that accesses a font file directly. Returns NULL on failure.
+  * @param filename Full path and filename to font file
+  * @param faceOptions Bitfile from enum gr_face_options to control face options.
+  */
+GR2_API gr_face* gr_make_file_face(const char *filename, unsigned int faceOptions);
+
+#ifndef DISABLE_SEGCACHE
+/** Create gr_face from a font file, with subsegment caching support.
+  *
+  * @return gr_face that accesses a font file directly. Returns NULL on failure.
+  * @param filename Full path and filename to font file
+  * @param segCacheMaxSize Specifies how big to make the cache in segments.
+  * @param faceOptions   Bitfield from enum gr_face_options to control face options.
+  */
+GR2_API gr_face* gr_make_file_face_with_seg_cache(const char *filename, unsigned int segCacheMaxSize, unsigned int faceOptions);
+#endif
+#endif      // !DISABLE_FILE_FACE
+
+/** Create a font from a face
+  *
+  * @return gr_font Call font_destroy to free this font
+  * @param ppm Resolution of the font in pixels per em
+  * @param face Face this font corresponds to. This must stay alive as long as the font is alive.
+  */
+GR2_API gr_font* gr_make_font(float ppm, const gr_face *face);
+
+/** query function to find the hinted advance width of a glyph **/
+typedef float (*gr_advance_fn)(const void* appFontHandle, gr_uint16 glyphid);
+
+/** Creates a font with hinted advance width query function
+  *
+  * @return gr_font to be destroyed via font_destroy
+  * @param ppm size of font in pixels per em
+  * @param appFontHandle font specific information that must stay alive as long as the font does
+  * @param advance function to call with appFontHandle and glyphid to get horizontal advance in pixels.
+  * @param face the face this font corresponds to. Must stay alive as long as the font does.
+  */
+GR2_API gr_font* gr_make_font_with_advance_fn(float ppm, const void* appFontHandle, gr_advance_fn advance, const gr_face *face);
+
+/** Free a font **/
+GR2_API void gr_font_destroy(gr_font *font);
+
+/** get a feature value
+  *
+  * @return value of specific feature or 0 if any problems.
+  * @param pfeatureref   gr_feature_ref to the feature
+  * @param feats gr_feature_val containing all the values
+  */
+GR2_API gr_uint16 gr_fref_feature_value(const gr_feature_ref* pfeatureref, const gr_feature_val* feats);
+
+/** set a feature value
+  *
+  * @return false if there were any problems (value out of range, etc.)
+  * @param pfeatureref   gr_feature_ref to the feature
+  * @param val   value to set the feature to
+  * @param pDest the gr_feature_val containing all the values for all the features
+  */
+GR2_API int gr_fref_set_feature_value(const gr_feature_ref* pfeatureref, gr_uint16 val, gr_feature_val* pDest);
+
+/** Returns the id tag for a gr_feature_ref **/
+GR2_API gr_uint32 gr_fref_id(const gr_feature_ref* pfeatureref);
+
+/** Returns number of values a feature may take, given a gr_feature_ref **/
+GR2_API gr_uint16 gr_fref_n_values(const gr_feature_ref* pfeatureref);
+
+/** Returns the value associated with a particular value in a feature
+  *
+  * @return value
+  * @param pfeatureref gr_feature_ref of the feature of interest
+  * @param settingno   Index up to the return value of gr_fref_n_values() of the value
+  */
+GR2_API gr_int16 gr_fref_value(const gr_feature_ref* pfeatureref, gr_uint16 settingno);   
+
+/** Returns a string of the UI name of a feature
+  *
+  * @return string of the UI name, in the encoding form requested. Call gr_label_destroy() after use.
+  * @param pfeatureref   gr_feature_ref of the feature
+  * @param langId    This is a pointer since the face may not support a string in the requested
+  *                  language. The actual language of the string is returned in langId
+  * @param utf   Encoding form for the string
+  * @param length    Used to return the length of the string returned in bytes.
+  */
+GR2_API void* gr_fref_label(const gr_feature_ref* pfeatureref, gr_uint16 *langId, enum gr_encform utf, gr_uint32 *length);
+
+/** Return a UI string for a possible value of a feature
+  *
+  * @return string of the UI name, in the encoding form requested. nul terminated. Call gr_label_destroy()
+  *          after use.
+  * @param pfeatureref   gr_feature_ref of the feature
+  * @param settingno     Value setting index
+  * @param langId        This is a pointer to the requested language. The requested language id is
+  *                      replaced by the actual language id of the string returned.
+  * @param utf   Encoding form for the string
+  * @param length    Returns the length of the string returned in bytes.
+  */
+GR2_API void* gr_fref_value_label(const gr_feature_ref* pfeatureref, gr_uint16 settingno/*rather than a value*/, gr_uint16 *langId, enum gr_encform utf, gr_uint32 *length);
+
+/** Destroy a previously returned label string **/
+GR2_API void gr_label_destroy(void * label);
+
+/** Copies a gr_feature_val **/
+GR2_API gr_feature_val* gr_featureval_clone(const gr_feature_val* pfeatures);
+
+/** Destroys a gr_feature_val **/
+GR2_API void gr_featureval_destroy(gr_feature_val *pfeatures);
+
+#ifdef __cplusplus
+}
+#endif
+
new file mode 100644
--- /dev/null
+++ b/gfx/graphite2/include/graphite2/Segment.h
@@ -0,0 +1,393 @@
+/*  GRAPHITE2 LICENSING
+
+    Copyright 2010, SIL International
+    All rights reserved.
+
+    This library is free software; you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published
+    by the Free Software Foundation; either version 2.1 of License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should also have received a copy of the GNU Lesser General Public
+    License along with this library in the file named "LICENSE".
+    If not, write to the Free Software Foundation, 51 Franklin Street,
+    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
+    internet at http://www.fsf.org/licenses/lgpl.html.
+
+    Alternatively, the contents of this file may be used under the terms
+    of the Mozilla Public License (http://mozilla.org/MPL) or the GNU
+    General Public License, as published by the Free Software Foundation,
+    either version 2 of the License or (at your option) any later version.
+*/
+#pragma once
+
+#include "graphite2/Types.h"
+#include "graphite2/Font.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+enum gr_break_weight {
+    gr_breakNone = 0,
+    /* after break weights */
+    gr_breakWhitespace = 10,
+    gr_breakWord = 15,
+    gr_breakIntra = 20,
+    gr_breakLetter = 30,
+    gr_breakClip = 40,
+    /* before break weights */
+    gr_breakBeforeWhitespace = -10,
+    gr_breakBeforeWord = -15,
+    gr_breakBeforeIntra = -20,
+    gr_breakBeforeLetter = -30,
+    gr_breakBeforeClip = -40
+};
+
+enum gr_justFlags {
+    /// Indicates that the start of the slot list is not at the start of a line
+    gr_justStartInline = 1,
+    /// Indicates that the end of the slot list is not at the end of a line
+    gr_justEndInline = 2
+};
+
+/** Used for looking up slot attributes. Most are already available in other functions **/
+enum gr_attrCode {
+    /// adjusted glyph advance in x direction in design units
+    gr_slatAdvX = 0,        
+    /// adjusted glyph advance in y direction (usually 0) in design units
+    gr_slatAdvY,            
+    /// returns 0. Deprecated.
+    gr_slatAttTo,           
+    /// This slot attaches to its parent at the given design units in the x direction
+    gr_slatAttX,            
+    /// This slot attaches to its parent at the given design units in the y direction
+    gr_slatAttY,            
+    /// This slot attaches to its parent at the given glyph point (not implemented)
+    gr_slatAttGpt,          
+    /// x-direction adjustment from the given glyph point (not implemented)
+    gr_slatAttXOff,         
+    /// y-direction adjustment from the given glyph point (not implemented)
+    gr_slatAttYOff,         
+    /// Where on this glyph should align with the attachment point on the parent glyph in the x-direction.
+    gr_slatAttWithX,        
+    /// Where on this glyph should align with the attachment point on the parent glyph in the y-direction
+    gr_slatAttWithY,        
+    /// Which glyph point on this glyph should align with the attachment point on the parent glyph (not implemented).
+    gr_slatWithGpt,         
+    /// Adjustment to gr_slatWithGpt in x-direction (not implemented)
+    gr_slatAttWithXOff,     
+    /// Adjustment to gr_slatWithGpt in y-direction (not implemented)
+    gr_slatAttWithYOff,     
+    /// Attach at given nesting level (not implemented)
+    gr_slatAttLevel,        
+    /// Line break breakweight for this glyph
+    gr_slatBreak,           
+    /// Ligature component reference (not implemented)
+    gr_slatCompRef,         
+    /// bidi directionality of this glyph (not implemented)
+    gr_slatDir,             
+    /// Whether insertion is allowed before this glyph
+    gr_slatInsert,          
+    /// Final positioned position of this glyph relative to its parent in x-direction in pixels
+    gr_slatPosX,            
+    /// Final positioned position of this glyph relative to its parent in y-direction in pixels
+    gr_slatPosY,            
+    /// Amount to shift glyph by in x-direction design units
+    gr_slatShiftX,          
+    /// Amount to shift glyph by in y-direction design units
+    gr_slatShiftY,          
+    /// attribute user1
+    gr_slatUserDefnV1,      
+    /// not implemented
+    gr_slatMeasureSol,      
+    /// not implemented
+    gr_slatMeasureEol,      
+    /// Amount this slot can stretch (not implemented)
+    gr_slatJStretch,        
+    /// Amount this slot can shrink (not implemented)
+    gr_slatJShrink,         
+    /// Granularity by which this slot can stretch or shrink (not implemented)
+    gr_slatJStep,           
+    /// Justification weight for this glyph (not implemented)
+    gr_slatJWeight,         
+    /// Amount this slot mush shrink or stretch in design units
+    gr_slatJWidth,          
+    /// User defined attribute, see subattr for user attr number
+    gr_slatUserDefn = gr_slatJStretch + 30,
+                            
+    /// not implemented
+    gr_slatMax,             
+    /// not implemented
+    gr_slatNoEffect = gr_slatMax + 1    
+};
+
+enum gr_bidirtl {
+    /// Underlying paragraph direction is RTL
+    gr_rtl = 1,
+    /// Set this to not run the bidi pass internally, even if the font asks for it.
+    /// This presumes that the segment is in a single direction.
+    gr_nobidi = 2,
+    /// Disable auto mirroring for rtl text
+    gr_nomirror = 4
+};
+
+typedef struct gr_char_info     gr_char_info;
+typedef struct gr_segment       gr_segment;
+typedef struct gr_slot          gr_slot;
+
+/** Returns Unicode character for a charinfo.
+  * 
+  * @param p Pointer to charinfo to return information on.
+  */
+GR2_API unsigned int gr_cinfo_unicode_char(const gr_char_info* p/*not NULL*/);
+
+/** Returns breakweight for a charinfo.
+  * 
+  * @return Breakweight is a number between -50 and 50 indicating the cost of a
+  * break before or after this character.
+  * @param p Pointer to charinfo to return information on.
+  */
+GR2_API int gr_cinfo_break_weight(const gr_char_info* p/*not NULL*/);
+
+/** Returns the slot index that after this character is after in the slot stream
+  *
+  * @return after slot index between 0 and gr_seg_n_slots()
+  * @param p Pointer to charinfo to return information on.
+  */
+GR2_API int gr_cinfo_after(const gr_char_info* p/*not NULL*/);
+
+/** Returns the slot index that before this character is before in the slot stream
+  *
+  * @return before slot index between 0 and gr_seg_n_slots()
+  * @param p Pointer to charinfo to return information on.
+  */
+GR2_API int gr_cinfo_before(const gr_char_info* p/*not NULL*/);
+
+/** Returns the code unit index of this character in the input string
+  *
+  * @return code unit index between 0 and the end of the string
+  * @param p Pointer to charinfo to return information on.
+  */
+GR2_API size_t gr_cinfo_base(const gr_char_info* p/*not NULL*/);
+
+/** Returns the number of unicode characters in a string.
+  *
+  * @return number of characters in the string
+  * @param enc Specifies the type of data in the string: utf8, utf16, utf32
+  * @param buffer_begin The start of the string
+  * @param buffer_end Measure up to the first nul or when end is reached, whichever is earliest.
+  *            This parameter may be NULL.
+  * @param pError If there is a structural fault in the string, the location is returned
+  *               in this variable. If no error occurs, pError will contain NULL. NULL
+  *               may be passed for pError if no such information is required.
+  */
+GR2_API size_t gr_count_unicode_characters(enum gr_encform enc, const void* buffer_begin, const void* buffer_end, const void** pError);
+
+/** Creates and returns a segment.
+  *
+  * @return a segment that needs seg_destroy called on it. May return NULL if bad problems
+  *     in segment processing.
+  * @param font Gives the size of the font in pixels per em for final positioning. If
+  *             NULL, positions are returned in design units, i.e. at a ppm of the upem
+  *             of the face.
+  * @param face The face containing all the non-size dependent information.
+  * @param script This is a tag containing a script identifier that is used to choose
+  *               which graphite table within the font to use. Maybe 0. Tag may be 4 chars
+  *               NULL padded in LSBs or space padded in LSBs.
+  * @param pFeats Pointer to a feature values to be used for the segment. Only one
+  *               feature values may be used for a segment. If NULL the default features
+  *               for the font will be used.
+  * @param enc Specifies what encoding form the string is in (utf8, utf16, utf32)
+  * @param pStart Start of the string
+  * @param nChars Number of unicode characters to process in the string. The string will
+  *               be processed either up to the first NULL or until nChars have been
+  *               processed. nChars is also used to initialise the internal memory
+  *               allocations of the segment. So it is wise not to make nChars too much
+  *               greater than the actual number of characters being processed.
+  * @param dir Specifies whether the segment is processed right to left (1) or left to
+  *            right (0) and whether to run the internal bidi pass, if a font requests it.
+  *            See enum gr_bidirtl for details.
+  */
+GR2_API gr_segment* gr_make_seg(const gr_font* font, const gr_face* face, gr_uint32 script, const gr_feature_val* pFeats, enum gr_encform enc, const void* pStart, size_t nChars, int dir);
+
+/** Destroys a segment, freeing the memory.
+  *
+  * @param p The segment to destroy
+  */
+GR2_API void gr_seg_destroy(gr_segment* p);
+
+/** Returns the advance for the whole segment.
+  *
+  * Returns the width of the segment up to the next glyph origin after the segment
+  */
+GR2_API float gr_seg_advance_X(const gr_segment* pSeg/*not NULL*/);
+
+/** Returns the height advance for the segment. **/
+GR2_API float gr_seg_advance_Y(const gr_segment* pSeg/*not NULL*/);
+
+/** Returns the number of gr_char_infos in the segment. **/
+GR2_API unsigned int gr_seg_n_cinfo(const gr_segment* pSeg/*not NULL*/);
+
+/** Returns a gr_char_info at a given index in the segment. **/
+GR2_API const gr_char_info* gr_seg_cinfo(const gr_segment* pSeg/*not NULL*/, unsigned int index/*must be <number_of_CharInfo*/);
+
+/** Returns the number of glyph gr_slots in the segment. **/
+GR2_API unsigned int gr_seg_n_slots(const gr_segment* pSeg/*not NULL*/);      //one slot per glyph
+
+/** Returns the first gr_slot in the segment.
+  *
+  * The first slot in a segment has a gr_slot_prev_in_segment() of NULL. Slots are owned
+  * by their segment and are destroyed along with the segment.
+  */
+GR2_API const gr_slot* gr_seg_first_slot(gr_segment* pSeg/*not NULL*/);    //may give a base slot or a slot which is attached to another
+
+/** Returns the last gr_slot in the segment.
+  *
+  * The last slot in a segment has a gr_slot_next_in_segment() of NULL
+  */
+GR2_API const gr_slot* gr_seg_last_slot(gr_segment* pSeg/*not NULL*/);    //may give a base slot or a slot which is attached to another
+
+/** Justifies a linked list of slots for a line to a given width
+  *
+  * Passed a pointer to the start of a linked list of slots corresponding to a line, as
+  * set up by gr_slot_linebreak_before, this function will position the glyphs in the line
+  * to take up the given width. It is possible to specify a subrange within the line to process.
+  * This allows skipping of line initial or final whitespace, for example. While this will ensure
+  * that the subrange fits width, the line will still be positioned with the first glyph of the
+  * line at 0. So the resulting positions may be beyond width.
+  * @param pSeg     Pointer to the segment
+  * @param pStart   Pointer to the start of the line linked list (including skipped characters)
+  * @param pFont    Font to use for positioning
+  * @param width    Width in pixels in which to fit the line
+  * @param flags    Indicates line ending types. Default is linked list is a full line
+  * @param pFirst   If not NULL, the first slot in the list to be considered part of the line (so can skip)
+  * @param pLast    If not NULL, the last slot to process in the line (allow say trailing whitespace to be skipped)
+  */
+GR2_API void gr_seg_justify(gr_segment* pSeg/*not NULL*/, gr_slot* pStart/*not NULL*/, const gr_font *pFont, double width, enum gr_justFlags flags, gr_slot* pFirst, gr_slot* pLast);
+
+/** Returns the next slot along in the segment.
+  *
+  * Slots are held in a linked list. This returns the next in the linked list. The slot
+  * may or may not be attached to another slot. Returns NULL at the end of the segment.
+  */
+GR2_API const gr_slot* gr_slot_next_in_segment(const gr_slot* p);
+
+/** Returns the previous slot along in the segment.
+  *
+  * Slots are held in a doubly linked list. This returns the previos slot in the linked
+  * list. This slot may or may not be attached to it. Returns NULL at the start of the
+  * segment.
+  */
+GR2_API const gr_slot* gr_slot_prev_in_segment(const gr_slot* p);
+
+/** Returns the attachment parent slot of this slot.
+  *
+  * Attached slots form a tree. This returns the parent of this slot in that tree. A
+  * base glyph which is not attached to another glyph, always returns NULL.
+  */
+GR2_API const gr_slot* gr_slot_attached_to(const gr_slot* p);
+
+/** Returns the first slot attached to this slot.
+  *
+  * Attached slots form a singly linked list from the parent. This returns the first
+  * slot in that list. Note that this is a reference to another slot that is also in
+  * the main segment doubly linked list.
+  *
+  * if gr_slot_first_attachment(p) != NULL then gr_slot_attached_to(gr_slot_first_attachment(p)) == p.
+  */
+GR2_API const gr_slot* gr_slot_first_attachment(const gr_slot* p);
+
+/** Returns the next slot attached to our attachment parent.
+  *
+  * This returns the next slot in the singly linked list of slots attached to this
+  * slot's parent. If there are no more such slots, NULL is returned. If there is
+  * no parent, i.e. the passed slot is a base, then the next base in graphical order
+  * (ltr even for rtl text) is returned.
+  *
+  * if gr_slot_next_sibling_attachment(p) != NULL then gr_slot_attached_to(gr_slot_next_sibling_attachment(p)) == gr_slot_attached_to(p).
+  */
+GR2_API const gr_slot* gr_slot_next_sibling_attachment(const gr_slot* p);
+
+
+/** Returns glyph id of the slot
+  *
+  * Each slot has a glyphid which is rendered at the position given by the slot. This
+  * glyphid is the real glyph to be rendered and never a pseudo glyph.
+  */
+GR2_API unsigned short gr_slot_gid(const gr_slot* p);
+
+/** Returns X offset of glyph from start of segment **/
+GR2_API float gr_slot_origin_X(const gr_slot* p);
+
+/** Returns Y offset of glyph from start of segment **/
+GR2_API float gr_slot_origin_Y(const gr_slot* p);
+
+/** Returns the glyph advance for this glyph as adjusted for kerning
+  *
+  * @param p    Slot to give results for
+  * @param face gr_face of the glyphs. May be NULL if unhinted advances used
+  * @param font gr_font to scale for pixel results. If NULL returns design units advance. If not NULL then returns pixel advance based on hinted or scaled glyph advances in the font. face must be passed for hinted advances to be used.
+  */
+GR2_API float gr_slot_advance_X(const gr_slot* p, const gr_face* face, const gr_font *font);
+
+/** Returns the vertical advance for the glyph in the slot adjusted for kerning
+  *
+  * Returns design units unless font is not NULL in which case the pixel value is returned scaled for the given font
+  */
+GR2_API float gr_slot_advance_Y(const gr_slot* p, const gr_face* face, const gr_font *font);
+
+/** Returns the gr_char_info index before us
+  *
+  * Returns the index of the gr_char_info that a cursor before this slot, would put
+  * an underlying cursor before.
+  */
+GR2_API int gr_slot_before(const gr_slot* p/*not NULL*/);
+
+/** Returns the gr_char_info index after us
+  *
+  * Returns the index of the gr_char_info that a cursor after this slot would put an
+  * underlying cursor after.
+  */
+GR2_API int gr_slot_after(const gr_slot* p/*not NULL*/);
+
+/** Returns the index of this slot in the segment
+  *
+  * Returns the index given to this slot during final positioning. This corresponds to the value returned br gr_cinfo_before()
+  * and gr_cinfo_after()
+  */
+GR2_API unsigned int gr_slot_index(const gr_slot* p/*not NULL*/);
+
+/** Return a slot attribute value
+  *
+  * Given a slot and an attribute along with a possible subattribute, return the
+  * corresponding value in the slot. See enum gr_attrCode for details of each attribute.
+  */
+GR2_API int gr_slot_attr(const gr_slot* p/*not NULL*/, const gr_segment* pSeg/*not NULL*/, enum gr_attrCode index, gr_uint8 subindex); //tbd - do we need to expose this?
+
+/** Returns whether text may be inserted before this glyph [check this isn't inverted] **/
+GR2_API int gr_slot_can_insert_before(const gr_slot* p);
+
+/** Returns the original gr_char_info index this slot refers to.
+  *
+  * Each Slot has a gr_char_info that it originates from. This is that gr_char_info. The index is passed to gr_seg_cinfo(). This
+  * information is useful for testing.
+  */
+GR2_API int gr_slot_original(const gr_slot* p/*not NULL*/);
+
+/** Breaks a segment into lines.
+  *
+  * Breaks the slot linked list at the given point in the linked list. It is up
+  * to the application to keep track of the first slot on each line.
+  */
+GR2_API void gr_slot_linebreak_before(gr_slot *p/*not NULL*/);
+
+#ifdef __cplusplus
+}
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/graphite2/include/graphite2/Types.h
@@ -0,0 +1,67 @@
+/*  GRAPHITE2 LICENSING
+
+    Copyright 2010, SIL International
+    All rights reserved.
+
+    This library is free software; you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published
+    by the Free Software Foundation; either version 2.1 of License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should also have received a copy of the GNU Lesser General Public
+    License along with this library in the file named "LICENSE".
+    If not, write to the Free Software Foundation, 51 Franklin Street,
+    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
+    internet at http://www.fsf.org/licenses/lgpl.html.
+
+    Alternatively, the contents of this file may be used under the terms
+    of the Mozilla Public License (http://mozilla.org/MPL) or the GNU
+    General Public License, as published by the Free Software Foundation,
+    either version 2 of the License or (at your option) any later version.
+*/
+#pragma once
+
+#include <stddef.h>
+
+typedef unsigned char   gr_uint8;
+typedef gr_uint8        gr_byte;
+typedef signed char     gr_int8;
+typedef unsigned short  gr_uint16;
+typedef short           gr_int16;
+typedef unsigned int    gr_uint32;
+typedef int             gr_int32;
+
+enum gr_encform {
+  gr_utf8 = 1/*sizeof(uint8)*/, gr_utf16 = 2/*sizeof(uint16)*/, gr_utf32 = 4/*sizeof(uint32)*/
+};
+
+// Definitions for library publicly exported symbols
+#if defined _WIN32 || defined __CYGWIN__
+  #ifdef GR2_EXPORTING
+    #ifdef __GNUC__
+      #define GR2_API    __attribute__((dllexport))
+    #else
+      #define GR2_API    __declspec(dllexport)
+    #endif
+  #else
+    #ifdef __GNUC__
+      #define GR2_API    __attribute__((dllimport))
+    #else
+      #define GR2_API    __declspec(dllimport)
+    #endif
+  #endif
+  #define GR2_LOCAL
+#else
+  #if __GNUC__ >= 4
+    #define GR2_API      __attribute__ ((visibility("default")))
+    #define GR2_LOCAL       __attribute__ ((visibility("hidden")))
+  #else
+    #define GR2_API
+    #define GR2_LOCAL
+  #endif
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/graphite2/include/graphite2/XmlLog.h
@@ -0,0 +1,55 @@
+/*  GRAPHITE2 LICENSING
+
+    Copyright 2010, SIL International
+    All rights reserved.
+
+    This library is free software; you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published
+    by the Free Software Foundation; either version 2.1 of License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should also have received a copy of the GNU Lesser General Public
+    License along with this library in the file named "LICENSE".
+    If not, write to the Free Software Foundation, 51 Franklin Street,
+    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
+    internet at http://www.fsf.org/licenses/lgpl.html.
+
+    Alternatively, the contents of this file may be used under the terms
+    of the Mozilla Public License (http://mozilla.org/MPL) or the GNU
+    General Public License, as published by the Free Software Foundation,
+    either version 2 of the License or (at your option) any later version.
+*/
+#pragma once
+
+#include <graphite2/Types.h>
+#include <stdio.h>
+
+typedef enum {
+    GRLOG_NONE = 0x0,
+    GRLOG_FACE = 0x01,
+    GRLOG_SEGMENT = 0x02,
+    GRLOG_PASS = 0x04,
+    GRLOG_CACHE = 0x08,
+    
+    GRLOG_OPCODE = 0x80,
+    GRLOG_ALL = 0xFF
+} GrLogMask;
+
+// If startGraphiteLogging returns true, logging is enabled and the FILE handle
+// will be closed by graphite when stopGraphiteLogging is called.
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+GR2_API bool graphite_start_logging(FILE * logFile, GrLogMask mask);		//may not do anthing if disabled in the implementation of the engine.
+GR2_API void graphite_stop_logging();
+
+#ifdef __cplusplus
+}
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/graphite2/src/Bidi.cpp
@@ -0,0 +1,576 @@
+/*  GRAPHITE2 LICENSING
+
+    Copyright 2010, SIL International
+    All rights reserved.
+
+    This library is free software; you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published
+    by the Free Software Foundation; either version 2.1 of License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should also have received a copy of the GNU Lesser General Public
+    License along with this library in the file named "LICENSE".
+    If not, write to the Free Software Foundation, 51 Franklin Street,
+    suite 500, Boston, MA 02110-1335, USA or visit their web page on the 
+    internet at http://www.fsf.org/licenses/lgpl.html.
+
+Alternatively, the contents of this file may be used under the terms of the
+Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
+License, as published by the Free Software Foundation, either version 2
+of the License or (at your option) any later version.
+*/
+#include "Main.h"
+#include "Slot.h"
+#include "Segment.h"
+
+using namespace graphite2;
+
+enum DirCode {  // Hungarian: dirc
+        Unk        = -1,
+        N          =  0,   // other neutrals (default) - ON
+        L          =  1,   // left-to-right, strong - L
+        R          =  2,   // right-to-left, strong - R
+        AL         =  3,   // Arabic letter, right-to-left, strong, AR
+        EN         =  4,   // European number, left-to-right, weak - EN
+        ES         =  5,   // European separator, left-to-right, weak - ES
+        ET         =  6,   // European number terminator, left-to-right, weak - ET
+        AN         =  7,   // Arabic number, left-to-right, weak - AN
+        CS         =  8,   // Common number separator, left-to-right, weak - CS
+        WS         =  9,   // white space, neutral - WS
+        BN         = 10,   // boundary neutral - BN
+
+        LRO        = 11,   // LTR override
+        RLO        = 12,   // RTL override
+        LRE        = 13,   // LTR embedding
+        RLE        = 14,   // RTL embedding
+        PDF        = 15,   // pop directional format
+        NSM        = 16,   // non-space mark
+
+        ON = N
+};
+
+enum DirMask {
+    Nmask = 1,
+    Lmask = 2,
+    Rmask = 4,
+    ALmask = 8,
+    ENmask = 0x10,
+    ESmask = 0x20,
+    ETmask = 0x40,
+    ANmask = 0x80,
+    CSmask = 0x100,
+    WSmask = 0x200,
+    BNmask = 0x400,
+    LROmask = 0x800,
+    RLOmask = 0x1000,
+    LREmask = 0x2000,
+    RLEmask = 0x4000,
+    PDFmask = 0x8000,
+    NSMmask = 0x10000
+};
+
+unsigned int bidi_class_map[] = { 0, 1, 2, 5, 4, 8, 9, 3, 7, 0, 0, 0, 0, 0, 0, 0, 6 };
+// Algorithms based on Unicode reference standard code. Thanks Asmus Freitag.
+#define MAX_LEVEL 61
+
+Slot *resolveExplicit(int level, int dir, Slot *s, int nNest = 0)
+{
+    int nLastValid = nNest;
+    Slot *res = NULL;
+    for ( ; s && !res; s = s->next())
+    {
+        int cls = s->getBidiClass();
+        switch(cls)
+        {
+        case LRO:
+        case LRE:
+            nNest++;
+            if (level & 1)
+                s->setBidiLevel(level + 1);
+            else
+                s->setBidiLevel(level + 2);
+            if (s->getBidiLevel() > MAX_LEVEL)
+                s->setBidiLevel(level);
+            else
+            {
+                s = resolveExplicit(s->getBidiLevel(), (cls == LRE ? N : L), s->next(), nNest);
+                nNest--;
+                if (s) continue; else break;
+            }
+            cls = BN;
+            s->setBidiClass(cls);
+            break;
+
+        case RLO:
+        case RLE:
+            nNest++;
+            if (level & 1)
+                s->setBidiLevel(level + 2);
+            else
+                s->setBidiLevel(level + 1);
+            if (s->getBidiLevel() > MAX_LEVEL)
+                s->setBidiLevel(level);
+            else
+            {
+                s = resolveExplicit(s->getBidiLevel(), (cls == RLE ? N : R), s->next(), nNest);
+                nNest--;
+                if (s) continue; else break;
+            }
+            cls = BN;
+            s->setBidiClass(cls);
+            break;
+
+        case PDF:
+            cls = BN;
+            s->setBidiClass(cls);
+            if (nNest)
+            {
+                if (nLastValid < nNest)
+                    --nNest;
+                else
+                    res = s;
+            }
+            break;
+        }
+
+        if (dir != N)
+            cls = dir;
+        if (s)
+        {
+            s->setBidiLevel(level);
+            if (s->getBidiClass() != BN)
+                s->setBidiClass(cls);
+        }
+        else
+            break;
+    }
+    return res;
+}
+
+// === RESOLVE WEAK TYPES ================================================
+
+enum bidi_state // possible states
+{
+        xa,             //      arabic letter
+        xr,             //      right leter
+        xl,             //      left letter
+
+        ao,             //      arabic lett. foll by ON
+        ro,             //      right lett. foll by ON
+        lo,             //      left lett. foll by ON
+
+        rt,             //      ET following R
+        lt,             //      ET following L
+
+        cn,             //      EN, AN following AL
+        ra,             //      arabic number foll R
+        re,             //      european number foll R
+        la,             //      arabic number foll L
+        le,             //      european number foll L
+
+        ac,             //      CS following cn
+        rc,             //      CS following ra
+        rs,             //      CS,ES following re
+        lc,             //      CS following la
+        ls,             //      CS,ES following le
+
+        ret,            //      ET following re
+        let,            //      ET following le
+} ;
+
+enum bidi_state_mask
+{
+    xamask = 1,
+    xrmask = 2,
+    xlmask = 4,
+    aomask = 8,
+    romask = 0x10,
+    lomask = 0x20,
+    rtmask = 0x40,
+    ltmask = 0x80,
+    cnmask = 0x100,
+    ramask = 0x200,
+    remask = 0x400,
+    lamask = 0x800,
+    lemask = 0x1000,
+    acmask = 0x2000,
+    rcmask = 0x4000,
+    rsmask = 0x8000,
+    lcmask = 0x10000,
+    lsmask = 0x20000,
+    retmask = 0x40000,
+    letmask = 0x80000
+};
+
+const bidi_state stateWeak[][10] =
+{
+        //      N,  L,  R,  AN, EN, AL,NSM, CS, ES, ET,
+{ /*xa*/        ao, xl, xr, cn, cn, xa, xa, ao, ao, ao, /* arabic letter          */ },
+{ /*xr*/        ro, xl, xr, ra, re, xa, xr, ro, ro, rt, /* right letter           */ },
+{ /*xl*/        lo, xl, xr, la, le, xa, xl, lo, lo, lt, /* left letter            */ },
+
+{ /*ao*/        ao, xl, xr, cn, cn, xa, ao, ao, ao, ao, /* arabic lett. foll by ON*/ },
+{ /*ro*/        ro, xl, xr, ra, re, xa, ro, ro, ro, rt, /* right lett. foll by ON */ },
+{ /*lo*/        lo, xl, xr, la, le, xa, lo, lo, lo, lt, /* left lett. foll by ON  */ },
+
+{ /*rt*/        ro, xl, xr, ra, re, xa, rt, ro, ro, rt, /* ET following R         */ },
+{ /*lt*/        lo, xl, xr, la, le, xa, lt, lo, lo, lt, /* ET following L         */ },
+
+{ /*cn*/        ao, xl, xr, cn, cn, xa, cn, ac, ao, ao, /* EN, AN following AL    */ },
+{ /*ra*/        ro, xl, xr, ra, re, xa, ra, rc, ro, rt, /* arabic number foll R   */ },
+{ /*re*/        ro, xl, xr, ra, re, xa, re, rs, rs,ret, /* european number foll R */ },
+{ /*la*/        lo, xl, xr, la, le, xa, la, lc, lo, lt, /* arabic number foll L   */ },
+{ /*le*/        lo, xl, xr, la, le, xa, le, ls, ls,let, /* european number foll L */ },
+
+{ /*ac*/        ao, xl, xr, cn, cn, xa, ao, ao, ao, ao, /* CS following cn        */ },
+{ /*rc*/        ro, xl, xr, ra, re, xa, ro, ro, ro, rt, /* CS following ra        */ },
+{ /*rs*/        ro, xl, xr, ra, re, xa, ro, ro, ro, rt, /* CS,ES following re     */ },
+{ /*lc*/        lo, xl, xr, la, le, xa, lo, lo, lo, lt, /* CS following la        */ },
+{ /*ls*/        lo, xl, xr, la, le, xa, lo, lo, lo, lt, /* CS,ES following le     */ },
+
+{ /*ret*/ ro, xl, xr, ra, re, xa,ret, ro, ro,ret, /* ET following re              */ },
+{ /*let*/ lo, xl, xr, la, le, xa,let, lo, lo,let, /* ET following le              */ },
+
+
+};
+
+enum bidi_action // possible actions
+{
+        // primitives
+        IX = 0x100,                     // increment
+        XX = 0xF,                       // no-op
+
+        // actions
+        xxx = (XX << 4) + XX,           // no-op
+        xIx = IX + xxx,                         // increment run
+        xxN = (XX << 4) + ON,           // set current to N
+        xxE = (XX << 4) + EN,           // set current to EN
+        xxA = (XX << 4) + AN,           // set current to AN
+        xxR = (XX << 4) + R,            // set current to R
+        xxL = (XX << 4) + L,            // set current to L
+        Nxx = (ON << 4) + 0xF,          // set run to neutral
+        Axx = (AN << 4) + 0xF,          // set run to AN
+        ExE = (EN << 4) + EN,           // set run to EN, set current to EN
+        NIx = (ON << 4) + 0xF + IX,     // set run to N, increment
+        NxN = (ON << 4) + ON,           // set run to N, set current to N
+        NxR = (ON << 4) + R,            // set run to N, set current to R
+        NxE = (ON << 4) + EN,           // set run to N, set current to EN
+
+        AxA = (AN << 4) + AN,           // set run to AN, set current to AN
+        NxL = (ON << 4) + L,            // set run to N, set current to L
+        LxL = (L << 4) + L,             // set run to L, set current to L
+};
+
+
+const bidi_action actionWeak[][10] =
+{
+          //   N,.. L,   R,  AN,  EN,  AL, NSM,  CS,..ES,  ET,
+{ /*xa*/ xxx, xxx, xxx, xxx, xxA, xxR, xxR, xxN, xxN, xxN, /* arabic letter             */ },
+{ /*xr*/ xxx, xxx, xxx, xxx, xxE, xxR, xxR, xxN, xxN, xIx, /* right leter               */ },
+{ /*xl*/ xxx, xxx, xxx, xxx, xxL, xxR, xxL, xxN, xxN, xIx, /* left letter               */ },
+
+{ /*ao*/ xxx, xxx, xxx, xxx, xxA, xxR, xxN, xxN, xxN, xxN, /* arabic lett. foll by ON   */ },
+{ /*ro*/ xxx, xxx, xxx, xxx, xxE, xxR, xxN, xxN, xxN, xIx, /* right lett. foll by ON    */ },
+{ /*lo*/ xxx, xxx, xxx, xxx, xxL, xxR, xxN, xxN, xxN, xIx, /* left lett. foll by ON     */ },
+
+{ /*rt*/ Nxx, Nxx, Nxx, Nxx, ExE, NxR, xIx, NxN, NxN, xIx, /* ET following R            */ },
+{ /*lt*/ Nxx, Nxx, Nxx, Nxx, LxL, NxR, xIx, NxN, NxN, xIx, /* ET following L            */ },
+
+{ /*cn*/ xxx, xxx, xxx, xxx, xxA, xxR, xxA, xIx, xxN, xxN, /* EN, AN following  AL      */ },
+{ /*ra*/ xxx, xxx, xxx, xxx, xxE, xxR, xxA, xIx, xxN, xIx, /* arabic number foll R      */ },
+{ /*re*/ xxx, xxx, xxx, xxx, xxE, xxR, xxE, xIx, xIx, xxE, /* european number foll R    */ },
+{ /*la*/ xxx, xxx, xxx, xxx, xxL, xxR, xxA, xIx, xxN, xIx, /* arabic number foll L      */ },
+{ /*le*/ xxx, xxx, xxx, xxx, xxL, xxR, xxL, xIx, xIx, xxL, /* european number foll L    */ },
+
+{ /*ac*/ Nxx, Nxx, Nxx, Axx, AxA, NxR, NxN, NxN, NxN, NxN, /* CS following cn           */ },
+{ /*rc*/ Nxx, Nxx, Nxx, Axx, NxE, NxR, NxN, NxN, NxN, NIx, /* CS following ra           */ },
+{ /*rs*/ Nxx, Nxx, Nxx, Nxx, ExE, NxR, NxN, NxN, NxN, NIx, /* CS,ES following re        */ },
+{ /*lc*/ Nxx, Nxx, Nxx, Axx, NxL, NxR, NxN, NxN, NxN, NIx, /* CS following la           */ },
+{ /*ls*/ Nxx, Nxx, Nxx, Nxx, LxL, NxR, NxN, NxN, NxN, NIx, /* CS,ES following le        */ },
+
+{ /*ret*/xxx, xxx, xxx, xxx, xxE, xxR, xxE, xxN, xxN, xxE, /* ET following re           */ },
+{ /*let*/xxx, xxx, xxx, xxx, xxL, xxR, xxL, xxN, xxN, xxL, /* ET following le           */ },
+};
+
+inline uint8    GetDeferredType(bidi_action a)          { return (a >> 4) & 0xF; }
+inline uint8    GetResolvedType(bidi_action a)          { return a & 0xF; }
+inline DirCode  EmbeddingDirection(int l)               { return l & 1 ? R : L; }
+inline bool     IsDeferredState(bidi_state a)           { return (1 << a) & (rtmask | ltmask | acmask | rcmask | rsmask | lcmask | lsmask); }
+inline bool     IsModifiedClass(DirCode a)              { return (1 << a) & (ALmask | NSMmask | ESmask | CSmask | ETmask | ENmask); }
+
+void SetDeferredRunClass(Slot *s, Slot *sRun, int nval)
+{
+    if (!sRun || s == sRun) return;
+    for (Slot *p = s->prev(); p != sRun; p = p->prev())
+        p->setBidiClass(nval);
+}
+
+void resolveWeak(int baseLevel, Slot *s)
+{
+    int state = (baseLevel & 1) ? xr : xl;
+    int cls;
+    int level = baseLevel;
+    Slot *sRun = NULL;
+    Slot *sLast = s;
+
+    for ( ; s; s = s->next())
+    {
+        sLast = s;
+        cls = s->getBidiClass();
+        if (cls == BN)
+        {
+            s->setBidiLevel(level);
+            if (!s->next() && level != baseLevel)
+                s->setBidiClass(EmbeddingDirection(level));
+            else if (s->next() && level != s->next()->getBidiLevel() && s->next()->getBidiClass() != BN)
+            {
+                int newLevel = s->next()->getBidiLevel();
+                if (level > newLevel)
+                    newLevel = level;
+                s->setBidiLevel(newLevel);
+                s->setBidiClass(EmbeddingDirection(newLevel));
+                level  = s->next()->getBidiLevel();
+            }
+            else
+                continue;
+        }
+
+        bidi_action action = actionWeak[state][bidi_class_map[cls]];
+        int clsRun = GetDeferredType(action);
+        if (clsRun != XX)
+        {
+            SetDeferredRunClass(s, sRun, clsRun);
+            sRun = NULL;
+        }
+        int clsNew = GetResolvedType(action);
+        if (clsNew != XX)
+            s->setBidiClass(clsNew);
+        if (!sRun && (IX & action))
+            sRun = s->prev();
+        state = stateWeak[state][bidi_class_map[cls]];
+    }
+
+    cls = EmbeddingDirection(level);
+    int clsRun = GetDeferredType(actionWeak[state][bidi_class_map[cls]]);
+    if (clsRun != XX)
+        SetDeferredRunClass(sLast, sRun, clsRun);
+}
+
+// Neutrals
+enum neutral_action
+{
+        // action to resolve previous input
+        nL = L,         // resolve EN to L
+        En = 3 << 4,    // resolve neutrals run to embedding level direction
+        Rn = R << 4,    // resolve neutrals run to strong right
+        Ln = L << 4,    // resolved neutrals run to strong left
+        In = (1<<8),    // increment count of deferred neutrals
+        LnL = (1<<4)+L, // set run and EN to L
+};
+
+int GetDeferredNeutrals(int action, int level)
+{
+        action = (action >> 4) & 0xF;
+        if (action == (En >> 4))
+            return EmbeddingDirection(level);
+        else
+            return action;
+}
+
+int GetResolvedNeutrals(int action)
+{
+        action = action & 0xF;
+        if (action == In)
+            return 0;
+        else
+            return action;
+}
+
+// state values
+enum neutral_state
+{
+        // new temporary class
+        r,  // R and characters resolved to R
+        l,  // L and characters resolved to L
+        rn, // N preceded by right
+        ln, // N preceded by left
+        a,  // AN preceded by left (the abbrev 'la' is used up above)
+        na, // N preceeded by a
+} ;
+
+const uint8 neutral_class_map[] = { 0, 1, 2, 0, 4, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+const int actionNeutrals[][5] =
+{
+//      N,      L,      R, AN, EN, = cls
+                                // state =
+{       In,  0,  0,  0,  0, },  // r    right
+{       In,  0,  0,  0,  L, },  // l    left
+
+{       In, En, Rn, Rn, Rn, },  // rn   N preceded by right
+{       In, Ln, En, En, LnL, }, // ln   N preceded by left
+
+{       In,  0,  0,  0,  L, },  // a   AN preceded by left
+{       In, En, Rn, Rn, En, },  // na   N  preceded by a
+} ;
+
+const int stateNeutrals[][5] =
+{
+//       N, L,  R,      AN, EN = cls
+                                                // state =
+{       rn, l,  r,      r,      r, },           // r   right
+{       ln, l,  r,      a,      l, },           // l   left
+
+{       rn, l,  r,      r,      r, },           // rn  N preceded by right
+{       ln, l,  r,      a,      l, },           // ln  N preceded by left
+
+{       na, l,  r,      a,      l, },           // a  AN preceded by left
+{       na, l,  r,      a,      l, },           // na  N preceded by la
+} ;
+
+void resolveNeutrals(int baseLevel, Slot *s)
+{
+    int state = baseLevel ? r : l;
+    int cls;
+    Slot *sRun = NULL;
+    Slot *sLast = s;
+    int level = baseLevel;
+
+    for ( ; s; s = s->next())
+    {
+        sLast = s;
+        cls = s->getBidiClass();
+        if (cls == BN)
+        {
+            if (sRun)
+                sRun = sRun->prev();
+            continue;
+        }
+
+        int action = actionNeutrals[state][neutral_class_map[cls]];
+        int clsRun = GetDeferredNeutrals(action, level);
+        if (clsRun != N)
+        {
+            SetDeferredRunClass(s, sRun, clsRun);
+            sRun = NULL;
+        }
+        int clsNew = GetResolvedNeutrals(action);
+        if (clsNew != N)
+            s->setBidiClass(clsNew);
+        state = stateNeutrals[state][neutral_class_map[cls]];
+        level = s->getBidiLevel();
+    }
+    cls = EmbeddingDirection(level);
+    int clsRun = GetDeferredNeutrals(actionNeutrals[state][neutral_class_map[cls]], level);
+    if (clsRun != N)
+        SetDeferredRunClass(sLast, sRun, clsRun);
+}
+
+const int addLevel[][4] =
+{
+                //    L,  R,    AN, EN = cls
+                                                // level =
+/* even */      { 0,    1,      2,      2, },   // EVEN
+/* odd  */      { 1,    0,      1,      1, },   // ODD
+
+};
+
+void resolveImplicit(Slot *s, Segment *seg, uint8 aMirror)
+{
+    bool rtl = seg->dir() & 1;
+    for ( ; s; s = s->next())
+    {
+        int cls = s->getBidiClass();
+        if (cls == BN)
+            continue;
+        else if (cls == AN)
+            cls = AL;
+        if (cls < 5 && cls > 0)
+        {
+            int level = s->getBidiLevel();
+            level += addLevel[level & 1][cls - 1];
+            s->setBidiLevel(level);
+            if (aMirror)
+            {
+                int hasChar = seg->glyphAttr(s->gid(), aMirror + 1);
+                if ( ((level & 1) && (!(seg->dir() & 4) || !hasChar)) 
+                  || ((rtl ^ (level & 1)) && (seg->dir() & 4) && hasChar) )
+                {
+                    unsigned short g = seg->glyphAttr(s->gid(), aMirror);
+                    if (g) s->setGlyph(seg, g);
+                }
+            }
+        }
+    }
+}
+
+void resolveWhitespace(int baseLevel, Segment *seg, uint8 aBidi, Slot *s)
+{
+    for ( ; s; s = s->prev())
+    {
+        int cls = seg->glyphAttr(s->gid(), aBidi);
+        if (cls == WS)
+            s->setBidiLevel(baseLevel);
+        else
+            break;
+    }
+}
+
+
+inline
+Slot * join(int level, Slot * a, Slot * b)
+{
+    if (!a) return b;
+    if (level & 1)  { Slot * const t = a; a = b; b = t; }
+    Slot * const t = b->prev();
+    a->prev()->next(b); b->prev(a->prev()); // splice middle
+    t->next(a); a->prev(t);                 // splice ends
+    return a;
+}
+
+
+Slot * span(Slot * & cs, const bool rtl)
+{
+    Slot * r = cs, * re = cs; cs = cs->next();
+    if (rtl)
+    {
+        Slot * t = r->next(); r->next(r->prev()); r->prev(t);
+        for (int l = r->getBidiLevel(); cs && l == cs->getBidiLevel(); cs = cs->prev())
+        {
+            re = cs;
+            t = cs->next(); cs->next(cs->prev()); cs->prev(t);
+        }
+        r->next(re);
+        re->prev(r);
+        r = re;
+    }
+    else
+    {
+        for (int l = r->getBidiLevel(); cs && l == cs->getBidiLevel(); cs = cs->next())
+            re = cs;
+        r->prev(re);
+        re->next(r);
+    }
+    if (cs) cs->prev(0);
+    return r;
+}
+
+
+Slot *resolveOrder(Slot * & cs, const bool reordered, const int level)
+{
+    Slot * r = 0;
+    int ls;
+    while (cs && level <= (ls = cs->getBidiLevel() - reordered))
+    {
+        r = join(level, r, level >= ls
+                                ? span(cs, level & 1)
+                                : resolveOrder(cs, reordered, level+1));
+    }
+    return r;
+}
+
new file mode 100644
--- /dev/null
+++ b/gfx/graphite2/src/CMakeLists.txt
@@ -0,0 +1,121 @@
+#    GRAPHITE2 LICENSING
+#
+#    Copyright 2010, SIL International
+#    All rights reserved.
+#
+#    This library is free software; you can redistribute it and/or modify
+#    it under the terms of the GNU Lesser General Public License as published
+#    by the Free Software Foundation; either version 2.1 of License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#    Lesser General Public License for more details.
+#
+#    You should also have received a copy of the GNU Lesser General Public
+#    License along with this library in the file named "LICENSE".
+#    If not, write to the Free Software Foundation, 51 Franklin Street, 
+#    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the 
+#    internet at http://www.fsf.org/licenses/lgpl.html.
+
+CMAKE_MINIMUM_REQUIRED(VERSION 2.8.0 FATAL_ERROR)
+project(graphite2_core)
+cmake_policy(SET CMP0012 NEW)
+INCLUDE(CheckCXXSourceCompiles)
+
+set(GRAPHITE_API_MAJOR 2)
+set(GRAPHITE_API_MINOR 0)
+set(GRAPHITE_API_AGE 0)
+set(GRAPHITE_SO_VERSION ${GRAPHITE_API_MAJOR}.${GRAPHITE_API_MINOR}.${GRAPHITE_API_AGE})
+
+include(TestBigEndian)
+
+include_directories(${PROJECT_SOURCE_DIR})
+
+if (DISABLE_SEGCACHE)
+    add_definitions(-DDISABLE_SEGCACHE)
+endif (DISABLE_SEGCACHE)
+
+if (DISABLE_FILEFACE)
+    add_definitions(-DDISABLE_FILE_FACE)
+endif (DISABLE_FILEFACE)
+
+if (NOT DISABLE_TRACING)
+    set(TRACE_HEADERS ../include/graphite2/XmlLog.h)
+    if (ENABLE_DEEP_TRACING)
+        add_definitions(-DENABLE_DEEP_TRACING)
+    endif (ENABLE_DEEP_TRACING)
+endif (NOT DISABLE_TRACING)
+
+set(GRAPHITE_HEADERS 
+    ../include/graphite2/Font.h
+    ../include/graphite2/Segment.h
+    ../include/graphite2/Types.h
+    ${TRACE_HEADERS}
+    )
+
+file(GLOB PRIVATE_HEADERS *.h) 
+
+add_library(graphite2 SHARED
+    ${VM_MACHINE_TYPE}_machine.cpp
+    gr_char_info.cpp
+    gr_features.cpp
+    gr_face.cpp
+    gr_font.cpp
+    gr_logging.cpp
+    gr_segment.cpp
+    gr_slot.cpp
+    Bidi.cpp
+    CachedFace.cpp
+    CmapCache.cpp
+    Code.cpp
+    Face.cpp
+    FeatureMap.cpp
+    Font.cpp
+    GlyphFace.cpp
+    GlyphFaceCache.cpp
+    NameTable.cpp
+    Pass.cpp
+    SegCache.cpp
+    SegCacheEntry.cpp
+    SegCacheStore.cpp
+    Segment.cpp
+    Silf.cpp
+    Slot.cpp
+    Sparse.cpp
+    TtfUtil.cpp
+    UtfCodec.cpp
+    XmlTraceLog.cpp
+    XmlTraceLogTags.cpp)
+
+set_target_properties(graphite2 PROPERTIES  PUBLIC_HEADER "${GRAPHITE_HEADERS}"
+                                            SOVERSION ${GRAPHITE_SO_VERSION}
+                                            LT_VERSION_CURRENT ${GRAPHITE_API_MAJOR}
+                                            LT_VERSION_REVISION ${GRAPHITE_API_MINOR}
+                                            LT_VERSION_AGE ${GRAPHITE_API_AGE})
+
+if  (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
+    add_definitions(-Wall -Wno-unknown-pragmas -Wparentheses -Wextra -Wendif-labels
+     -Wshadow -Wno-ctor-dtor-privacy -Wno-non-virtual-dtor -fdiagnostics-show-option
+     -fno-rtti -fno-exceptions -nodefaultlibs
+     -fvisibility=hidden -fvisibility-inlines-hidden -fno-stack-protector)
+    set_target_properties(graphite2 PROPERTIES LINK_FLAGS "-nodefaultlibs" LINKER_LANGUAGE C)
+    if (${CMAKE_CXX_COMPILER} MATCHES  ".*mingw.*")
+        target_link_libraries(graphite2 "-lkernel32 -lmsvcr90 -lmingw32 -lgcc -luser32")
+    else (${CMAKE_CXX_COMPILER} MATCHES  ".*mingw.*")
+        target_link_libraries(graphite2 "-lc -lgcc")
+        include(Graphite)
+        nolib_test(stdc++ $<TARGET_SONAME_FILE:graphite2>)
+    endif (${CMAKE_CXX_COMPILER} MATCHES  ".*mingw.*")
+    set(CMAKE_CXX_IMPLICIT_LINK_LIBRARIES "")
+    CREATE_LIBTOOL_FILE(graphite2 "/lib${LIB_SUFFIX}")
+endif (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
+
+if  (${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
+    add_definitions(-D_SCL_SECURE_NO_WARNINGS -D_CRT_SECURE_NO_WARNINGS -DUNICODE -DGR2_EXPORTING)
+endif (${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
+
+
+install(TARGETS graphite2 EXPORT graphite2 LIBRARY DESTINATION lib${LIB_SUFFIX} ARCHIVE DESTINATION lib${LIB_SUFFIX} PUBLIC_HEADER DESTINATION include/graphite2 RUNTIME DESTINATION bin)
+install(EXPORT graphite2 DESTINATION share/graphite2 NAMESPACE gr2_)
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/gfx/graphite2/src/CachedFace.cpp
@@ -0,0 +1,160 @@
+/*  GRAPHITE2 LICENSING
+
+    Copyright 2010, SIL International
+    All rights reserved.
+
+    This library is free software; you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published
+    by the Free Software Foundation; either version 2.1 of License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should also have received a copy of the GNU Lesser General Public
+    License along with this library in the file named "LICENSE".
+    If not, write to the Free Software Foundation, 51 Franklin Street,
+    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
+    internet at http://www.fsf.org/licenses/lgpl.html.
+
+Alternatively, the contents of this file may be used under the terms of the
+Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
+License, as published by the Free Software Foundation, either version 2
+of the License or (at your option) any later version.
+*/
+
+#ifndef DISABLE_SEGCACHE
+
+#include <graphite2/Segment.h>
+#include "CachedFace.h"
+#include "SegCacheStore.h"
+
+
+using namespace graphite2;
+
+CachedFace::CachedFace(const void* appFaceHandle/*non-NULL*/, gr_get_table_fn getTable2)
+: Face(appFaceHandle, getTable2), m_cacheStore(0) 
+{
+}
+
+CachedFace::~CachedFace()
+{
+    delete m_cacheStore;
+}
+
+bool CachedFace::setupCache(unsigned int cacheSize)
+{
+    m_cacheStore = new SegCacheStore(this, m_numSilf, cacheSize);
+    return (m_cacheStore != NULL);
+}
+
+
+bool CachedFace::runGraphite(Segment *seg, const Silf *pSilf) const
+{
+    assert(pSilf);
+    pSilf->runGraphite(seg, 0, pSilf->substitutionPass());
+
+    SegCache * segCache = NULL;
+    unsigned int silfIndex = 0;
+
+    for (unsigned int i = 0; i < m_numSilf; i++)
+    {
+        if (&(m_silfs[i]) == pSilf)
+        {
+            break;
+        }
+    }
+    assert(silfIndex < m_numSilf);
+    assert(m_cacheStore);
+    segCache = m_cacheStore->getOrCreate(silfIndex, seg->getFeatures(0));
+    // find where the segment can be broken
+    Slot * subSegStartSlot = seg->first();
+    Slot * subSegEndSlot = subSegStartSlot;
+    uint16 cmapGlyphs[eMaxSpliceSize];
+    int subSegStart = 0;
+    bool spaceOnly = true;
+    for (unsigned int i = 0; i < seg->charInfoCount(); i++)
+    {
+        if (i - subSegStart < eMaxSpliceSize)
+        {
+            cmapGlyphs[i-subSegStart] = subSegEndSlot->gid();
+        }
+        if (!m_cacheStore->isSpaceGlyph(subSegEndSlot->gid()))
+        {
+            spaceOnly = false;
+        }
+        // at this stage the character to slot mapping is still 1 to 1
+        int breakWeight = seg->charinfo(i)->breakWeight();
+        int nextBreakWeight = (i + 1 < seg->charInfoCount())?
+            seg->charinfo(i+1)->breakWeight() : 0;
+        if (((breakWeight > 0) &&
+             (breakWeight <= gr_breakWord)) ||
+            (i + 1 == seg->charInfoCount()) ||
+             m_cacheStore->isSpaceGlyph(subSegEndSlot->gid()) ||
+            ((i + 1 < seg->charInfoCount()) &&
+             (((nextBreakWeight < 0) &&
+              (nextBreakWeight >= gr_breakBeforeWord)) ||
+              (subSegEndSlot->next() && m_cacheStore->isSpaceGlyph(subSegEndSlot->next()->gid())))))
+        {
+            // record the next slot before any splicing
+            Slot * nextSlot = subSegEndSlot->next();
+            if (spaceOnly)
+            {
+                // spaces should be left untouched by graphite rules in any sane font
+            }
+            else
+            {
+                // found a break position, check for a cache of the sub sequence
+                const SegCacheEntry * entry = (segCache)?
+                    segCache->find(cmapGlyphs, i - subSegStart + 1) : NULL;
+                // TODO disable cache for words at start/end of line with contextuals
+#ifndef DISABLE_TRACING
+                if (XmlTraceLog::get().active())
+                {
+                    XmlTraceLog::get().openElement(ElementSubSeg);
+                    XmlTraceLog::get().addAttribute(AttrFirstId, subSegStart);
+                    XmlTraceLog::get().addAttribute(AttrLastId, i);
+                }
+#endif
+                if (!entry)
+                {
+                    unsigned int length = i - subSegStart + 1;
+                    SegmentScopeState scopeState = seg->setScope(subSegStartSlot, subSegEndSlot, length);
+                    pSilf->runGraphite(seg, pSilf->substitutionPass(), pSilf->numPasses());
+                    //entry =runGraphiteOnSubSeg(segCache, seg, cmapGlyphs,
+                    //                           subSegStartSlot, subSegEndSlot,
+                    //                           subSegStart, i - subSegStart + 1);
+                    if ((length < eMaxSpliceSize) && segCache)
+                        entry = segCache->cache(m_cacheStore, cmapGlyphs, length, seg, subSegStart);
+                    seg->removeScope(scopeState);
+                }
+                else
+                {
+                    //seg->splice(subSegStart, i - subSegStart + 1, subSegStartSlot, subSegEndSlot, entry);
+                    seg->splice(subSegStart, i - subSegStart + 1, subSegStartSlot, subSegEndSlot,
+                        entry->first(), entry->glyphLength());
+                }
+#ifndef DISABLE_TRACING
+                if (XmlTraceLog::get().active())
+                {
+                    XmlTraceLog::get().closeElement(ElementSubSeg);
+                }
+#endif
+            }
+            subSegEndSlot = nextSlot;
+            subSegStartSlot = nextSlot;
+            subSegStart = i + 1;
+            spaceOnly = true;
+        }
+        else
+        {
+            subSegEndSlot = subSegEndSlot->next();
+        }
+    }
+    return true;
+}
+
+#endif
+
new file mode 100644
--- /dev/null
+++ b/gfx/graphite2/src/CachedFace.h
@@ -0,0 +1,52 @@
+/*  GRAPHITE2 LICENSING
+
+    Copyright 2010, SIL International
+    All rights reserved.
+
+    This library is free software; you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published
+    by the Free Software Foundation; either version 2.1 of License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should also have received a copy of the GNU Lesser General Public
+    License along with this library in the file named "LICENSE".
+    If not, write to the Free Software Foundation, 51 Franklin Street,
+    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
+    internet at http://www.fsf.org/licenses/lgpl.html.
+
+Alternatively, the contents of this file may be used under the terms of the
+Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
+License, as published by the Free Software Foundation, either version 2
+of the License or (at your option) any later version.
+*/
+#pragma once
+
+#ifndef DISABLE_SEGCACHE
+
+#include "Face.h"
+
+namespace graphite2 {
+
+class SegCacheStore;
+
+class CachedFace : public Face
+{
+public:
+    CachedFace(const void* appFaceHandle/*non-NULL*/, gr_get_table_fn getTable2);
+    bool setupCache(unsigned int cacheSize);
+    virtual ~CachedFace();
+    virtual bool runGraphite(Segment *seg, const Silf *silf) const;
+    SegCacheStore * cacheStore() { return m_cacheStore; }
+private:
+    SegCacheStore * m_cacheStore;
+};
+
+} // namespace graphite2
+
+#endif
+
new file mode 100644
--- /dev/null
+++ b/gfx/graphite2/src/CharInfo.h
@@ -0,0 +1,64 @@
+/*  GRAPHITE2 LICENSING
+
+    Copyright 2010, SIL International
+    All rights reserved.
+
+    This library is free software; you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published
+    by the Free Software Foundation; either version 2.1 of License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should also have received a copy of the GNU Lesser General Public
+    License along with this library in the file named "LICENSE".
+    If not, write to the Free Software Foundation, 51 Franklin Street, 
+    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the 
+    internet at http://www.fsf.org/licenses/lgpl.html.
+
+Alternatively, the contents of this file may be used under the terms of the
+Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
+License, as published by the Free Software Foundation, either version 2
+of the License or (at your option) any later version.
+*/
+#pragma once
+#include "Main.h"
+
+
+namespace graphite2 {
+
+class CharInfo
+{
+
+public:
+    CharInfo() : m_before(-1), m_after(0) {}
+    void init(int cid) { m_char = cid; }
+    unsigned int unicodeChar() const { return m_char; }
+    void feats(int offset) { m_featureid = offset; }
+    int fid() const { return m_featureid; }
+    int breakWeight() const { return m_break; }
+    void breakWeight(int val) { m_break = val; }
+    int after() const { return m_after; }
+    void after(int val) { m_after = val; }
+    int before() const { return m_before; }
+    void before(int val) { m_before = val; }
+    size_t base() const { return m_base; }
+    void base(size_t offset) { m_base = offset; }
+
+    CLASS_NEW_DELETE
+private:
+    int m_char;     // Unicode character from character stream
+    int m_before;   // slot index before us, comes before
+    int m_after;    // slot index after us, comes after
+    size_t  m_base; // offset into input string corresponding to this charinfo
+    uint8 m_featureid;	// index into features list in the segment
+    int8 m_break;	// breakweight coming from lb table
+};
+
+} // namespace graphite2
+
+struct gr_char_info : public graphite2::CharInfo {};
+
new file mode 100644
--- /dev/null
+++ b/gfx/graphite2/src/CmapCache.cpp
@@ -0,0 +1,141 @@
+/*  GRAPHITE2 LICENSING
+
+    Copyright 2010, SIL International
+    All rights reserved.
+
+    This library is free software; you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published
+    by the Free Software Foundation; either version 2.1 of License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should also have received a copy of the GNU Lesser General Public
+    License along with this library in the file named "LICENSE".
+    If not, write to the Free Software Foundation, 51 Franklin Street,
+    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
+    internet at http://www.fsf.org/licenses/lgpl.html.
+
+Alternatively, the contents of this file may be used under the terms of the
+Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
+License, as published by the Free Software Foundation, either version 2
+of the License or (at your option) any later version.
+*/
+
+#include "Main.h"
+#include "CmapCache.h"
+#include "TtfTypes.h"
+#include "TtfUtil.h"
+
+
+using namespace graphite2;
+
+CmapCache::CmapCache(const void* cmapTable, size_t length)
+{
+    const void * table31 = TtfUtil::FindCmapSubtable(cmapTable, 3, 1, length);
+    const void * table310 = TtfUtil::FindCmapSubtable(cmapTable, 3, 10, length);
+    m_isBmpOnly = (!table310);
+    int rangeKey = 0;
+    uint32 	codePoint = 0,
+    		prevCodePoint = 0;
+    if (table310 && TtfUtil::CheckCmap310Subtable(table310))
+    {
+        m_blocks = grzeroalloc<uint16*>(0x1100);
+        if (!m_blocks) return;
+        codePoint =  TtfUtil::Cmap310NextCodepoint(table310, codePoint, &rangeKey);
+        while (codePoint != 0x10FFFF)
+        {
+            unsigned int block = (codePoint & 0xFFFF00) >> 8;
+            if (!m_blocks[block])
+            {
+                m_blocks[block] = grzeroalloc<uint16>(0x100);
+                if (!m_blocks[block])
+                    return;
+            }
+            m_blocks[block][codePoint & 0xFF] = TtfUtil::Cmap310Lookup(table310, codePoint, rangeKey);
+            // prevent infinite loop
+            if (codePoint <= prevCodePoint)
+                codePoint = prevCodePoint + 1;
+            prevCodePoint = codePoint;
+            codePoint =  TtfUtil::Cmap310NextCodepoint(table310, codePoint, &rangeKey);
+        }
+    }
+    else
+    {
+        m_blocks = grzeroalloc<uint16*>(0x100);
+        if (!m_blocks) return;
+    }
+    if (table31 && TtfUtil::CheckCmap31Subtable(table31))
+    {
+        codePoint = 0;
+        rangeKey = 0;
+        codePoint =  TtfUtil::Cmap31NextCodepoint(table31, codePoint, &rangeKey);
+        while (codePoint != 0xFFFF)
+        {
+            unsigned int block = (codePoint & 0xFFFF00) >> 8;
+            if (!m_blocks[block])
+            {
+                m_blocks[block] = grzeroalloc<uint16>(0x100);
+                if (!m_blocks[block])
+                    return;
+            }
+            m_blocks[block][codePoint & 0xFF] = TtfUtil::Cmap31Lookup(table31, codePoint, rangeKey);
+            // prevent infinite loop
+            if (codePoint <= prevCodePoint)
+                codePoint = prevCodePoint + 1;
+            prevCodePoint = codePoint;
+            codePoint =  TtfUtil::Cmap31NextCodepoint(table31, codePoint, &rangeKey);
+        }
+    }
+}
+
+CmapCache::~CmapCache() throw()
+{
+    unsigned int numBlocks = (m_isBmpOnly)? 0x100 : 0x1100;
+    for (unsigned int i = 0; i < numBlocks; i++)
+    	free(m_blocks[i]);
+    free(m_blocks);
+}
+
+uint16 CmapCache::operator [] (const uint32 usv) const throw()
+{
+    if ((m_isBmpOnly && usv > 0xFFFF) || (usv > 0x10FFFF))
+        return 0;
+    const uint32 block = 0xFFFF & (usv >> 8);
+    if (m_blocks[block])
+        return m_blocks[block][usv & 0xFF];
+    return 0;
+};
+
+CmapCache::operator bool() const throw()
+{
+	return m_blocks;
+}
+
+
+DirectCmap::DirectCmap(const void* cmap, size_t length)
+{
+    _ctable = TtfUtil::FindCmapSubtable(cmap, 3, 1, length);
+    if (!_ctable || !TtfUtil::CheckCmap31Subtable(_ctable))
+    {
+        _ctable =  0;
+        return;
+    }
+    _stable = TtfUtil::FindCmapSubtable(cmap, 3, 10, length);
+    if (_stable && !TtfUtil::CheckCmap310Subtable(_stable))
+    	_stable = 0;
+}
+
+uint16 DirectCmap::operator [] (const uint32 usv) const throw()
+{
+    return usv > 0xFFFF ? (_stable ? TtfUtil::Cmap310Lookup(_stable, usv) : 0) : TtfUtil::Cmap31Lookup(_ctable, usv);
+}
+
+DirectCmap::operator bool () const throw()
+{
+	return _ctable;
+}
+
new file mode 100644
--- /dev/null
+++ b/gfx/graphite2/src/CmapCache.h
@@ -0,0 +1,73 @@
+/*  GRAPHITE2 LICENSING
+
+    Copyright 2010, SIL International
+    All rights reserved.
+
+    This library is free software; you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published
+    by the Free Software Foundation; either version 2.1 of License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should also have received a copy of the GNU Lesser General Public
+    License along with this library in the file named "LICENSE".
+    If not, write to the Free Software Foundation, 51 Franklin Street,
+    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
+    internet at http://www.fsf.org/licenses/lgpl.html.
+
+Alternatively, the contents of this file may be used under the terms of the
+Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
+License, as published by the Free Software Foundation, either version 2
+of the License or (at your option) any later version.
+*/
+#pragma once
+
+#include <Main.h>
+
+namespace graphite2 {
+
+class Face;
+
+class Cmap
+{
+public:
+	virtual ~Cmap() throw() {}
+
+	virtual uint16 operator [] (const uint32) const throw() { return 0; }
+
+	virtual operator bool () const throw() { return false; }
+
+	CLASS_NEW_DELETE;
+};
+
+class DirectCmap : public Cmap
+{
+public:
+	DirectCmap(const void* cmap, size_t length);
+	virtual uint16 operator [] (const uint32 usv) const throw();
+	virtual operator bool () const throw();
+
+    CLASS_NEW_DELETE;
+private:
+    const void *_stable,
+    		   *_ctable;
+};
+
+class CmapCache : public Cmap
+{
+public:
+	CmapCache(const void * cmapTable, size_t length);
+	virtual ~CmapCache() throw();
+	virtual uint16 operator [] (const uint32 usv) const throw();
+	virtual operator bool () const throw();
+    CLASS_NEW_DELETE;
+private:
+    bool m_isBmpOnly;
+    uint16 ** m_blocks;
+};
+
+} // namespace graphite2
new file mode 100644
--- /dev/null
+++ b/gfx/graphite2/src/Code.cpp
@@ -0,0 +1,628 @@
+/*  GRAPHITE2 LICENSING
+
+    Copyright 2010, SIL International
+    All rights reserved.
+
+    This library is free software; you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published
+    by the Free Software Foundation; either version 2.1 of License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should also have received a copy of the GNU Lesser General Public
+    License along with this library in the file named "LICENSE".
+    If not, write to the Free Software Foundation, 51 Franklin Street, 
+    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the 
+    internet at http://www.fsf.org/licenses/lgpl.html.
+
+Alternatively, the contents of this file may be used under the terms of the
+Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
+License, as published by the Free Software Foundation, either version 2
+of the License or (at your option) any later version.
+*/
+// This class represents loaded graphite stack machine code.  It performs 
+// basic sanity checks, on the incoming code to prevent more obvious problems
+// from crashing graphite.
+// Author: Tim Eves
+
+#include <cassert>
+#include <cstdlib>
+#include <cstring>
+#include "graphite2/Segment.h"
+#include "Code.h"
+#include "Machine.h"
+#include "Silf.h"
+#include "Face.h"
+#include "Rule.h"
+#include "XmlTraceLog.h"
+
+#include <cstdio>
+
+#ifdef DISABLE_TRACING
+#ifdef __GNUC__
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+#endif
+
+
+using namespace graphite2;
+using namespace vm;
+
+namespace {
+
+inline bool is_return(const instr i) {
+    const opcode_t * opmap = Machine::getOpcodeTable();
+    const instr pop_ret  = *opmap[POP_RET].impl,
+                ret_zero = *opmap[RET_ZERO].impl,
+                ret_true = *opmap[RET_TRUE].impl;
+    return i == pop_ret || i == ret_zero || i == ret_true;
+}
+
+void emit_trace_message(opcode, const byte *const, const opcode_t &);
+
+struct context
+{
+    context(uint8 ref=0) : codeRef(ref) {flags.changed=false; flags.referenced=false; flags.inserted=false;}
+    struct { 
+        uint8   changed:1,
+                referenced:1,
+                inserted:1;
+    } flags;
+    uint8       codeRef;
+};
+
+} // end namespace
+
+
+class Machine::Code::decoder
+{
+public:
+    struct limits;
+    struct analysis
+    {
+        uint8     slotref;
+        context   contexts[256];
+        byte      max_ref;
+        
+        analysis() : slotref(0), max_ref(0) {};
+        void set_ref(int index) throw();
+        void set_changed(int index) throw();
+
+    };
+    
+    decoder(const limits & lims, Code &code) throw();
+    
+    bool        load(const byte * bc_begin, const byte * bc_end);
+    void        apply_analysis(instr * const code, instr * code_end);
+    byte        max_ref() { return _analysis.max_ref; }
+    int         pre_context() const { return _pre_context; }
+    
+private:
+    opcode      fetch_opcode(const byte * bc);
+    void        analyse_opcode(const opcode, const int8 * const dp) throw();
+    bool        emit_opcode(opcode opc, const byte * & bc);
+    bool 		validate_opcode(const opcode opc, const byte * const bc);
+    bool        valid_upto(const uint16 limit, const uint16 x) const throw();
+    void        failure(const status_t s) const throw() { _code.failure(s); }
+    
+    Code              & _code;
+    int                 _pre_context;
+    uint16              _rule_length;
+    instr             * _instr;
+    byte              * _data;
+    const limits      & _max;
+    analysis            _analysis;
+};
+
+
+struct Machine::Code::decoder::limits
+{
+  const byte * const bytecode;
+  const uint8        pre_context;
+  const uint16       rule_length,
+                     classes,
+                     glyf_attrs,
+                     features;
+  const byte         attrid[gr_slatMax];
+};
+   
+inline Machine::Code::decoder::decoder(const limits & lims, Code &code) throw()
+: _code(code),
+  _pre_context(code._constraint ? 0 : lims.pre_context), 
+  _rule_length(code._constraint ? 1 : lims.rule_length), 
+  _instr(code._code), _data(code._data), _max(lims)
+{ }
+    
+
+
+Machine::Code::Code(bool is_constraint, const byte * bytecode_begin, const byte * const bytecode_end,
+           uint8 pre_context, uint16 rule_length, const Silf & silf, const Face & face)
+ :  _code(0), _data_size(0), _instr_count(0), _status(loaded),
+    _constraint(is_constraint), _modify(false), _delete(false), _own(true)
+{
+    assert(bytecode_begin != 0);
+    if (bytecode_begin == bytecode_end)
+    {
+      ::new (this) Code();
+      return;
+    }
+    assert(bytecode_end > bytecode_begin);
+    const opcode_t *    op_to_fn = Machine::getOpcodeTable();
+    
+    // Allocate code and dat target buffers, these sizes are a worst case 
+    // estimate.  Once we know their real sizes the we'll shrink them.
+    _code = static_cast<instr *>(malloc((bytecode_end - bytecode_begin)
+                                             * sizeof(instr)));
+    _data = static_cast<byte *>(malloc((bytecode_end - bytecode_begin)
+                                             * sizeof(byte)));
+    
+    if (!_code || !_data) {
+        failure(alloc_failed);
+        return;
+    }
+    
+    const decoder::limits lims = {
+        bytecode_end,
+        pre_context,
+        rule_length,
+        silf.numClasses(),
+        face.getGlyphFaceCache()->numAttrs(),
+        face.numFeatures(), 
+        {1,1,1,1,1,1,1,1, 
+         1,1,1,1,1,1,1,255,
+         1,1,1,1,1,1,1,1, 
+         1,1,1,1,1,1,0,0, 
+         0,0,0,0,0,0,0,0, 
+         0,0,0,0,0,0,0,0, 
+         0,0,0,0,0,0,0, silf.numUser()}
+    };
+    
+    decoder dec(lims, *this);
+    if(!dec.load(bytecode_begin, bytecode_end))
+       return;
+    
+    // Is this an empty program?
+    if (_instr_count == 0)
+    {
+      release_buffers();
+      ::new (this) Code();
+      return;
+    }
+    
+    // When we reach the end check we've terminated it correctly
+    if (!is_return(_code[_instr_count-1])) {
+        failure(missing_return);
+        return;
+    }
+
+    assert((_constraint && immutable()) || !_constraint);
+    dec.apply_analysis(_code, _code + _instr_count);
+    _max_ref = dec.max_ref();
+    
+    // Now we know exactly how much code and data the program really needs
+    // realloc the buffers to exactly the right size so we don't waste any 
+    // memory.
+    assert((bytecode_end - bytecode_begin) >= ptrdiff_t(_instr_count));
+    assert((bytecode_end - bytecode_begin) >= ptrdiff_t(_data_size));
+    _code = static_cast<instr *>(realloc(_code, (_instr_count+1)*sizeof(instr)));
+    _data = static_cast<byte *>(realloc(_data, _data_size*sizeof(byte)));
+    
+    // Make this RET_ZERO, we should never reach this but just in case ...
+    _code[_instr_count] = op_to_fn[RET_ZERO].impl[_constraint];
+
+    if (!_code)
+        failure(alloc_failed);
+}
+
+Machine::Code::~Code() throw ()
+{
+    if (_own)
+        release_buffers();
+}
+
+
+bool Machine::Code::decoder::load(const byte * bc, const byte * bc_end)
+{
+    while (bc < bc_end)
+    {
+        const opcode opc = fetch_opcode(bc++);
+        if (opc == vm::MAX_OPCODE)
+            return false;
+        
+        analyse_opcode(opc, reinterpret_cast<const int8 *>(bc));
+        
+        if (!emit_opcode(opc, bc))
+            return false;
+    }
+    
+    return bool(_code);
+}
+
+// Validation check and fixups.
+//
+
+opcode Machine::Code::decoder::fetch_opcode(const byte * bc)
+{
+    const opcode opc = opcode(*bc++);
+
+    // Do some basic sanity checks based on what we know about the opcode
+    if (!validate_opcode(opc, bc))	return MAX_OPCODE;
+
+    // And check it's arguments as far as possible
+    switch (opc)
+    {
+        case NOP :
+        case PUSH_BYTE :
+        case PUSH_BYTEU :
+        case PUSH_SHORT :
+        case PUSH_SHORTU :
+        case PUSH_LONG :
+        case ADD :
+        case SUB :
+        case MUL :
+        case DIV :
+        case MIN_ :
+        case MAX_ :
+        case NEG :
+        case TRUNC8 :
+        case TRUNC16 :
+        case COND :
+        case AND :
+        case OR :
+        case NOT :
+        case EQUAL :
+        case NOT_EQ :
+        case LESS :
+        case GTR :
+        case LESS_EQ :
+        case GTR_EQ :
+            break;
+        case NEXT :
+        case NEXT_N :           // runtime checked
+        case COPY_NEXT :
+            ++_pre_context;
+            break;
+        case PUT_GLYPH_8BIT_OBS :
+            valid_upto(_max.classes, bc[0]);
+            break;
+        case PUT_SUBS_8BIT_OBS :
+            valid_upto(_rule_length, _pre_context + int8(bc[0]));
+            valid_upto(_max.classes, bc[1]);
+            valid_upto(_max.classes, bc[2]);
+            break;
+        case PUT_COPY :
+            valid_upto(_rule_length, _pre_context + int8(bc[0]));
+            break;
+        case INSERT :
+            --_pre_context;
+            break;
+        case DELETE :
+            break;
+        case ASSOC :
+            for (uint8 num = bc[0]; num; --num)
+                valid_upto(_rule_length, _pre_context + int8(bc[num]));
+            break;
+        case CNTXT_ITEM :
+            valid_upto(_max.rule_length, _max.pre_context + int8(bc[0]));
+            if (bc + 2 + bc[1] >= _max.bytecode)  failure(jump_past_end);
+            break;
+        case ATTR_SET :
+        case ATTR_ADD :
+        case ATTR_SUB :
+        case ATTR_SET_SLOT :
+        	valid_upto(gr_slatMax, bc[0]);
+            break;
+        case IATTR_SET_SLOT :
+            if (valid_upto(gr_slatMax, bc[0]))
+            	valid_upto(_max.attrid[bc[0]], bc[1]);
+            break;
+        case PUSH_SLOT_ATTR :
+            valid_upto(gr_slatMax, bc[0]);
+            valid_upto(_rule_length, _pre_context + int8(bc[1]));
+            break;
+        case PUSH_GLYPH_ATTR_OBS :
+            valid_upto(_max.glyf_attrs, bc[0]);
+            valid_upto(_rule_length, _pre_context + int8(bc[1]));
+            break;
+        case PUSH_GLYPH_METRIC :
+            valid_upto(kgmetDescent, bc[0]);
+            valid_upto(_rule_length, _pre_context + int8(bc[1]));
+            // level: dp[2] no check necessary
+            break;
+        case PUSH_FEAT :
+            valid_upto(_max.features, bc[0]);
+            valid_upto(_rule_length, _pre_context + int8(bc[1]));
+            break;
+        case PUSH_ATT_TO_GATTR_OBS :
+            valid_upto(_max.glyf_attrs, bc[0]);
+            valid_upto(_rule_length, _pre_context + int8(bc[1]));
+            break;
+        case PUSH_ATT_TO_GLYPH_METRIC :
+            valid_upto(kgmetDescent, bc[0]);
+            valid_upto(_rule_length, _pre_context + int8(bc[1]));
+            // level: dp[2] no check necessary
+            break;
+        case PUSH_ISLOT_ATTR :
+            if (valid_upto(gr_slatMax, bc[0]))
+            {
+            	valid_upto(_rule_length, _pre_context + int8(bc[1]));
+            	valid_upto(_max.attrid[bc[0]], bc[2]);
+            }
+            break;
+        case PUSH_IGLYPH_ATTR :// not implemented
+        case POP_RET :
+        case RET_ZERO :
+        case RET_TRUE :
+            break;
+        case IATTR_SET :
+        case IATTR_ADD :
+        case IATTR_SUB :
+            if (valid_upto(gr_slatMax, bc[0]))
+            	valid_upto(_max.attrid[bc[0]], bc[1]);
+            break;
+        case PUSH_PROC_STATE :  // dummy: dp[0] no check necessary
+        case PUSH_VERSION :
+            break;
+        case PUT_SUBS :
+            valid_upto(_rule_length, _pre_context + int8(bc[0]));
+            valid_upto(_max.classes, uint16(bc[1]<< 8) | bc[2]);
+            valid_upto(_max.classes, uint16(bc[3]<< 8) | bc[4]);
+            break;
+        case PUT_SUBS2 :        // not implemented
+        case PUT_SUBS3 :        // not implemented
+            break;
+        case PUT_GLYPH :
+            valid_upto(_max.classes, uint16(bc[0]<< 8) | bc[1]);
+            break;
+        case PUSH_GLYPH_ATTR :
+        case PUSH_ATT_TO_GLYPH_ATTR :
+            valid_upto(_max.glyf_attrs, uint16(bc[0]<< 8) | bc[1]);
+            valid_upto(_rule_length, _pre_context + int8(bc[2]));
+            break;
+        default:
+            failure(invalid_opcode);
+            break;
+    }
+
+    return bool(_code) ? opc : MAX_OPCODE;
+}
+
+
+void Machine::Code::decoder::analyse_opcode(const opcode opc, const int8  * arg) throw()
+{
+  if (_code._constraint) return;
+  
+  switch (opc)
+  {
+    case DELETE :
+      _code._delete = true;
+      break;
+    case PUT_GLYPH_8BIT_OBS :
+    case PUT_GLYPH :
+      _code._modify = true;
+      _analysis.set_changed(_analysis.slotref);
+      break;
+    case NEXT :
+    case COPY_NEXT :
+      if (!_analysis.contexts[_analysis.slotref].flags.inserted)
+        ++_analysis.slotref;
+      _analysis.contexts[_analysis.slotref] = context(_code._instr_count+1);
+      if (_analysis.slotref > _analysis.max_ref) _analysis.max_ref = _analysis.slotref;
+      break;
+    case INSERT :
+      _analysis.contexts[_analysis.slotref].flags.inserted = true;
+      _code._modify = true;
+      break;
+    case PUT_SUBS_8BIT_OBS :    // slotref on 1st parameter
+    case PUT_SUBS : 
+      _code._modify = true;
+      _analysis.set_changed(_analysis.slotref);
+      // no break here;
+    case PUT_COPY :
+    {
+      if (arg[0] != 0) { _analysis.set_changed(_analysis.slotref); _code._modify = true; }
+      if (arg[0] <= 0 && -arg[0] <= _analysis.slotref - _analysis.contexts[_analysis.slotref].flags.inserted)
+        _analysis.set_ref(_analysis.slotref + arg[0] - _analysis.contexts[_analysis.slotref].flags.inserted);
+      else if (_analysis.slotref + arg[0] > _analysis.max_ref) _analysis.max_ref = _analysis.slotref + arg[0];
+      break;
+    }
+    case PUSH_ATT_TO_GATTR_OBS :
+        if (_code._constraint) return;
+    case PUSH_GLYPH_ATTR_OBS :
+    case PUSH_SLOT_ATTR :       // slotref on 2nd parameter
+    case PUSH_GLYPH_METRIC :
+    case PUSH_ATT_TO_GLYPH_METRIC :
+    case PUSH_ISLOT_ATTR :
+    case PUSH_FEAT :
+      if (arg[1] <= 0 && -arg[1] <= _analysis.slotref - _analysis.contexts[_analysis.slotref].flags.inserted)
+        _analysis.set_ref(_analysis.slotref + arg[1] - _analysis.contexts[_analysis.slotref].flags.inserted);
+      else if (_analysis.slotref + arg[1] > _analysis.max_ref) _analysis.max_ref = _analysis.slotref + arg[1];
+      break;
+    case PUSH_ATT_TO_GLYPH_ATTR :
+        if (_code._constraint) return;
+    case PUSH_GLYPH_ATTR :
+      if (arg[2] <= 0 && -arg[2] <= _analysis.slotref - _analysis.contexts[_analysis.slotref].flags.inserted)
+        _analysis.set_ref(_analysis.slotref + arg[2] - _analysis.contexts[_analysis.slotref].flags.inserted);
+      else if (_analysis.slotref + arg[2] > _analysis.max_ref) _analysis.max_ref = _analysis.slotref + arg[2];
+      break;
+    case ASSOC :                // slotrefs in varargs
+      break;
+    default:
+        break;
+  }
+}
+
+
+bool Machine::Code::decoder::emit_opcode(opcode opc, const byte * & bc)
+{
+    const opcode_t * op_to_fn = Machine::getOpcodeTable();
+    const opcode_t & op       = op_to_fn[opc];
+    if (op.impl[_code._constraint] == 0)
+    {
+        failure(unimplemented_opcode_used);
+        return false;
+    }
+
+    const size_t     param_sz = op.param_sz == VARARGS ? bc[0] + 1 : op.param_sz;
+
+    // Add this instruction
+    *_instr++ = op.impl[_code._constraint]; 
+    ++_code._instr_count;
+    emit_trace_message(opc, bc, op);
+
+    // Grab the parameters
+    if (param_sz) {
+        memmove(_data, bc, param_sz * sizeof(byte));
+        bc         += param_sz;
+        _data         += param_sz;
+        _code._data_size += param_sz;
+    }
+    
+    // recursively decode a context item so we can split the skip into 
+    // instruction and data portions.
+    if (opc == CNTXT_ITEM)
+    {
+        assert(_pre_context == 0);
+        _pre_context = _max.pre_context + int8(_data[-2]);
+        _rule_length = _max.rule_length;
+
+        const size_t ctxt_start = _code._instr_count;
+        byte & instr_skip = _data[-1];
+        byte & data_skip  = *_data++;
+        ++_code._data_size;
+
+        if (load(bc, bc + instr_skip))
+        {
+            bc += instr_skip;
+            data_skip  = instr_skip - (_code._instr_count - ctxt_start);
+            instr_skip = _code._instr_count - ctxt_start;
+
+            _rule_length = 1;
+            _pre_context = 0;
+        }
+    }
+    
+    return bool(_code);
+}
+
+
+
+namespace {
+
+inline void emit_trace_message(opcode opc, const byte *const params, 
+                        const opcode_t &op)
+{
+#ifndef DISABLE_TRACING
+    if (XmlTraceLog::get().active())
+    {
+        XmlTraceLog::get().openElement(ElementAction);
+        XmlTraceLog::get().addAttribute(AttrActionCode, opc);
+        XmlTraceLog::get().addAttribute(AttrAction, op.name);
+        for (size_t p = 0; p < 8 && p < op.param_sz; ++p)
+        {
+            XmlTraceLog::get().addAttribute(
+                                XmlTraceLogAttribute(Attr0 + p),
+                                params[p]);
+        }
+        XmlTraceLog::get().closeElement(ElementAction);
+    }
+#endif
+}
+
+} // end of namespace
+
+
+void Machine::Code::decoder::apply_analysis(instr * const code, instr * code_end)
+{
+    // insert TEMP_COPY commands for slots that need them (that change and are referenced later)
+    int tempcount = 0;
+    if (_code._constraint) return;
+
+    const instr temp_copy = Machine::getOpcodeTable()[TEMP_COPY].impl[0];
+    for (const context * c = _analysis.contexts, * const ce = c + _analysis.slotref; c != ce; ++c)
+    {
+        if (!c->flags.referenced || !c->flags.changed) continue;
+        
+        instr * const tip = code + c->codeRef + tempcount;        
+        memmove(tip+1, tip, (code_end - tip) * sizeof(instr));
+        *tip = temp_copy;
+        ++code_end;
+        ++tempcount;
+    }
+    
+    _code._instr_count = code_end - code;
+}
+
+
+inline
+bool Machine::Code::decoder::validate_opcode(const opcode opc, const byte * const bc)
+{
+	if (opc >= MAX_OPCODE)
+	{
+		failure(invalid_opcode);
+		return false;
+	}
+	const opcode_t & op = Machine::getOpcodeTable()[opc];
+	const size_t param_sz = op.param_sz == VARARGS ? bc[0] + 1 : op.param_sz;
+	if (bc + param_sz > _max.bytecode)
+	{
+		failure(arguments_exhausted);
+		return false;
+	}
+	return true;
+}
+
+
+bool Machine::Code::decoder::valid_upto(const uint16 limit, const uint16 x) const throw()
+{
+	const bool t = x < limit;
+    if (!t)	failure(out_of_range_data);
+    return t;
+}
+
+inline 
+void Machine::Code::failure(const status_t s) throw() {
+    release_buffers();
+    _status = s;
+}
+
+inline
+void Machine::Code::decoder::analysis::set_ref(const int index) throw() {
+    contexts[index].flags.referenced = true;
+    if (index > max_ref) max_ref = index;
+}
+
+inline
+void Machine::Code::decoder::analysis::set_changed(const int index) throw() {
+    contexts[index].flags.changed = true;
+    if (index > max_ref) max_ref = index;
+}
+
+void Machine::Code::release_buffers() throw()
+{
+    free(_code);
+    free(_data);
+    _code = 0;
+    _data = 0;
+    _own  = false;
+}
+
+int32 Machine::Code::run(Machine & m, slotref * & map) const
+{
+    assert(_own);
+    assert(*this);          // Check we are actually runnable
+
+    if (m.slotMap().size() <= _max_ref + m.slotMap().context())
+    {
+        m._status = Machine::slot_offset_out_bounds;
+//        return (m.slotMap().end() - map);
+        return 1;
+    }
+
+    return  m.run(_code, _data, map);
+}
+
new file mode 100644
--- /dev/null
+++ b/gfx/graphite2/src/Code.h
@@ -0,0 +1,172 @@
+/*  GRAPHITE2 LICENSING
+
+    Copyright 2010, SIL International
+    All rights reserved.
+
+    This library is free software; you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published
+    by the Free Software Foundation; either version 2.1 of License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should also have received a copy of the GNU Lesser General Public
+    License along with this library in the file named "LICENSE".
+    If not, write to the Free Software Foundation, 51 Franklin Street, 
+    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the 
+    internet at http://www.fsf.org/licenses/lgpl.html.
+
+Alternatively, the contents of this file may be used under the terms of the
+Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
+License, as published by the Free Software Foundation, either version 2
+of the License or (at your option) any later version.
+*/
+// This class represents loaded graphite stack machine code.  It performs 
+// basic sanity checks, on the incoming code to prevent more obvious problems
+// from crashing graphite.
+// Author: Tim Eves
+
+#pragma once
+
+#include <cassert>
+#include <graphite2/Types.h>
+#include "Main.h"
+#include "Machine.h"
+
+namespace graphite2 {
+
+class Silf;
+class Face;
+
+namespace vm {
+
+class Machine::Code
+{
+public:
+    enum status_t 
+    {
+        loaded,
+        alloc_failed, 
+        invalid_opcode, 
+        unimplemented_opcode_used,
+        out_of_range_data,
+        jump_past_end,
+        arguments_exhausted,
+        missing_return
+    };
+
+private:
+    class decoder;
+
+    instr *     _code;
+    byte  *     _data;
+    size_t      _data_size,
+                _instr_count;
+    byte        _max_ref;
+    mutable status_t _status;
+    bool        _constraint,
+                _modify,
+                _delete;
+    mutable bool _own;
+
+    void release_buffers() throw ();
+    void failure(const status_t) throw();
+
+public:
+    Code() throw();
+    Code(bool is_constraint, const byte * bytecode_begin, const byte * const bytecode_end,
+         uint8 pre_context, uint16 rule_length, const Silf &, const Face &);
+    Code(const Machine::Code &) throw();
+    ~Code() throw();
+    
+    Code & operator=(const Code &rhs) throw();
+    operator bool () const throw();
+    status_t      status() const throw();
+    bool          constraint() const throw();
+    size_t        dataSize() const throw();
+    size_t        instructionCount() const throw();
+    bool          immutable() const throw();
+    bool          deletes() const throw();
+    size_t        maxRef() const throw();
+
+    int32 run(Machine &m, slotref * & map) const;
+    
+    CLASS_NEW_DELETE;
+};
+
+inline Machine::Code::Code() throw()
+: _code(0), _data(0), _data_size(0), _instr_count(0), _max_ref(0),
+  _status(loaded), _own(false) {
+}
+
+inline Machine::Code::Code(const Machine::Code &obj) throw ()
+ :  _code(obj._code), 
+    _data(obj._data), 
+    _data_size(obj._data_size), 
+    _instr_count(obj._instr_count),
+    _max_ref(obj._max_ref),
+    _status(obj._status), 
+    _constraint(obj._constraint),
+    _modify(obj._modify),
+    _delete(obj._delete),
+    _own(obj._own) 
+{
+    obj._own = false;
+}
+
+inline Machine::Code & Machine::Code::operator=(const Machine::Code &rhs) throw() {
+    if (_instr_count > 0)
+        release_buffers();
+    _code        = rhs._code; 
+    _data        = rhs._data;
+    _data_size   = rhs._data_size; 
+    _instr_count = rhs._instr_count;
+    _status      = rhs._status; 
+    _constraint  = rhs._constraint;
+    _modify      = rhs._modify;
+    _delete      = rhs._delete;
+    _own         = rhs._own; 
+    rhs._own = false;
+    return *this;
+}
+
+inline Machine::Code::operator bool () const throw () {
+    return _code && status() == loaded;
+}
+
+inline Machine::Code::status_t Machine::Code::status() const throw() {
+    return _status;
+}
+
+inline bool Machine::Code::constraint() const throw() {
+    return _constraint;
+}
+
+inline size_t Machine::Code::dataSize() const throw() {
+    return _data_size;
+}
+
+inline size_t Machine::Code::instructionCount() const throw() {
+    return _instr_count;
+}
+
+inline bool Machine::Code::immutable() const throw()
+{
+  return !(_delete || _modify);
+}
+
+inline bool Machine::Code::deletes() const throw()
+{
+  return _delete;
+}
+
+inline size_t Machine::Code::maxRef() const throw()
+{
+	return _max_ref;
+}
+
+} // namespace vm
+} // namespace graphite2
new file mode 100644
--- /dev/null
+++ b/gfx/graphite2/src/Endian.h
@@ -0,0 +1,103 @@
+/*-----------------------------------------------------------------------------
+Copyright (C) 2011 SIL International
+Responsibility: Tim Eves
+
+    This library is free software; you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published
+    by the Free Software Foundation; either version 2.1 of License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should also have received a copy of the GNU Lesser General Public
+    License along with this library in the file named "LICENSE".
+    If not, write to the Free Software Foundation, 51 Franklin Street,
+    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
+    internet at http://www.fsf.org/licenses/lgpl.html.
+
+Alternatively, the contents of this file may be used under the terms of the
+Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
+License, as published by the Free Software Foundation, either version 2
+of the License or (at your option) any later version.
+
+Description:
+A set of fast template based decoders for decoding values of any C integer
+type up to long int size laid out with most significant byte first or least
+significant byte first (aka big endian or little endian).  These are CPU
+byte order agnostic and will function the same regardless of the CPUs native
+byte order.
+Being template based means if the either le or be class is not used then
+template code of unused functions will not be instantiated by the compiler
+and thus shouldn't cause any overhead.
+-----------------------------------------------------------------------------*/
+
+class be
+{
+	template<int S>
+	inline static unsigned long int _peek(const unsigned char * p) {
+		return _peek<S/2>(p) << (S/2)*8 | _peek<S/2>(p+S/2);
+	}
+public:
+	template<typename T>
+	inline static T peek(const unsigned char * p) { 
+		return T(_peek<sizeof(T)>(p));
+	}
+
+	template<typename T>
+	inline static T read(const unsigned char * &p) {
+		const T r = T(_peek<sizeof(T)>(p)); 
+		p += sizeof r;
+		return r;
+	}
+	
+	template<typename T>
+	inline static T swap(const T x) {
+		return T(_peek<sizeof(T)>(reinterpret_cast<const unsigned char *>(&x)));
+	}
+
+	template<typename T>
+	inline static void skip(const unsigned char * &p, size_t n=1) {
+		p += sizeof(T)*n;
+	}
+};
+
+template<>
+inline unsigned long int be::_peek<1>(const unsigned char * p) { return *p; }
+
+
+class le 
+{
+	template<int S>
+	inline static unsigned long int _peek(const unsigned char * p) {
+		return _peek<S/2>(p) | _peek<S/2>(p+S/2)  << (S/2)*8;
+	}
+public:
+	template<typename T>
+	inline static T peek(const unsigned char * p) { 
+		return T(_peek<sizeof(T)>(p));
+	}
+
+	template<typename T>
+	inline static T read(const unsigned char * &p) {
+		const T r = T(_peek<sizeof(T)>(p)); 
+		p += sizeof r;
+		return r;
+	}
+	
+	template<typename T>
+	inline static T swap(const T x) {
+		return T(_peek<sizeof(T)>(reinterpret_cast<const unsigned char *>(&x)));
+	}
+
+	template<typename T>
+	inline static void skip(const unsigned char * &p, size_t n=1) {
+		p += sizeof(T)*n;
+	}
+};
+
+template<>
+inline unsigned long int le::_peek<1>(const unsigned char * p) { return *p; }
+
new file mode 100644
--- /dev/null
+++ b/gfx/graphite2/src/Face.cpp
@@ -0,0 +1,296 @@
+/*  GRAPHITE2 LICENSING
+
+    Copyright 2010, SIL International
+    All rights reserved.
+
+    This library is free software; you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published
+    by the Free Software Foundation; either version 2.1 of License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should also have received a copy of the GNU Lesser General Public
+    License along with this library in the file named "LICENSE".
+    If not, write to the Free Software Foundation, 51 Franklin Street, 
+    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the 
+    internet at http://www.fsf.org/licenses/lgpl.html.
+
+Alternatively, the contents of this file may be used under the terms of the
+Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
+License, as published by the Free Software Foundation, either version 2
+of the License or (at your option) any later version.
+*/
+#include <cstring>
+#include "graphite2/Segment.h"
+#include "Face.h"
+#include "Endian.h"
+#include "Segment.h"
+#include "CmapCache.h"
+#include "NameTable.h"
+#include "SegCacheStore.h"
+#include "XmlTraceLog.h"
+
+
+using namespace graphite2;
+
+Face::~Face()
+{
+    delete m_pGlyphFaceCache;
+    delete m_cmap;
+    delete[] m_silfs;
+    m_pGlyphFaceCache = NULL;
+    m_cmap = NULL;
+    m_silfs = NULL;
+    delete m_pFileFace;
+    delete m_pNames;
+    m_pFileFace = NULL;
+}
+
+
+bool Face::readGlyphs(uint32 faceOptions)
+{
+    GlyphFaceCacheHeader hdr;
+    if (!hdr.initialize(*this, faceOptions & gr_face_dumbRendering)) return false;
+
+    m_pGlyphFaceCache = GlyphFaceCache::makeCache(hdr);
+    if (!m_pGlyphFaceCache) return false;
+
+    size_t length = 0;
+    const byte * table = getTable(Tag::cmap, &length);
+    if (!table) return false;
+
+    if (faceOptions & gr_face_cacheCmap)
+    	m_cmap = new CmapCache(table, length);
+    else
+    	m_cmap = new DirectCmap(table, length);
+
+    if (!m_cmap || !*m_cmap) return false;
+
+    if (faceOptions & gr_face_preloadGlyphs)
+    {
+        m_pGlyphFaceCache->loadAllGlyphs();
+        nameTable();        // preload the name table along with the glyphs, heh.
+    }
+    m_upem = TtfUtil::DesignUnits(m_pGlyphFaceCache->m_pHead);
+    if (!m_upem) return false;
+    // m_glyphidx = new unsigned short[m_numGlyphs];        // only need this if doing occasional glyph reads
+    
+    return true;
+}
+
+bool Face::readGraphite()
+{
+    const byte *pSilf;
+    size_t lSilf;
+    if ((pSilf = getTable(Tag::Silf, &lSilf)) == NULL) return false;
+    uint32 version;
+#ifndef DISABLE_TRACING
+    uint32 compilerVersion = 0; // wasn't set before GTF version 3
+#endif
+    uint32 offset32Pos = 2;
+    version = be::peek<uint32>(pSilf);
+    if (version < 0x00020000) return false;
+    if (version >= 0x00030000)
+    {
+#ifndef DISABLE_TRACING
+        compilerVersion = be::swap<uint32>(((uint32 *)pSilf)[1]);
+#endif
+        m_numSilf = be::swap<uint16>(((uint16 *)pSilf)[4]);
+        offset32Pos = 3;
+    }
+    else
+        m_numSilf = be::swap<uint16>(((uint16 *)pSilf)[2]);
+
+#ifndef DISABLE_TRACING
+        if (XmlTraceLog::get().active())
+        {
+            XmlTraceLog::get().openElement(ElementSilf);
+            XmlTraceLog::get().addAttribute(AttrMajor, version >> 16);
+            XmlTraceLog::get().addAttribute(AttrMinor, version & 0xFFFF);
+            XmlTraceLog::get().addAttribute(AttrCompilerMajor, compilerVersion >> 16);
+            XmlTraceLog::get().addAttribute(AttrCompilerMinor, compilerVersion & 0xFFFF);
+            XmlTraceLog::get().addAttribute(AttrNum, m_numSilf);
+            if (m_numSilf == 0)
+                XmlTraceLog::get().warning("No Silf subtables!");
+        }
+#endif
+    bool havePasses = false;
+    m_silfs = new Silf[m_numSilf];
+    for (int i = 0; i < m_numSilf; i++)
+    {
+        const uint32 offset = be::swap<uint32>(((uint32 *)pSilf)[offset32Pos + i]);
+        uint32 next;
+        if (i == m_numSilf - 1)
+            next = lSilf;
+        else
+            next = be::swap<uint32>(((uint32 *)pSilf)[offset32Pos + 1 + i]);
+        if (offset > lSilf || next > lSilf)
+        {
+#ifndef DISABLE_TRACING
+            XmlTraceLog::get().error("Invalid table %d offset %d length %u", i, offset, lSilf);
+            XmlTraceLog::get().closeElement(ElementSilf);
+#endif
+            return false;
+        }
+        if (!m_silfs[i].readGraphite((void *)((char *)pSilf + offset), next - offset, *this, version))
+        {
+#ifndef DISABLE_TRACING
+            if (XmlTraceLog::get().active())
+            {
+                XmlTraceLog::get().error("Error reading Graphite subtable %d", i);
+                XmlTraceLog::get().closeElement(ElementSilfSub); // for convenience
+                XmlTraceLog::get().closeElement(ElementSilf);
+            }
+#endif
+            return false;
+        }
+        if (m_silfs[i].numPasses())
+            havePasses = true;
+    }
+
+#ifndef DISABLE_TRACING
+    XmlTraceLog::get().closeElement(ElementSilf);
+#endif
+    return havePasses;
+}
+
+bool Face::runGraphite(Segment *seg, const Silf *aSilf) const
+{
+    return aSilf->runGraphite(seg, 0, aSilf->numPasses());
+}
+
+const Silf *Face::chooseSilf(uint32 script) const
+{
+    if (m_numSilf == 0)
+        return NULL;
+    else if (m_numSilf == 1 || script == 0)
+        return m_silfs;
+    else // do more work here
+        return m_silfs;
+}
+
+uint16 Face::getGlyphMetric(uint16 gid, uint8 metric) const
+{
+    switch (metrics(metric))
+    {
+        case kgmetAscent : return m_ascent;
+        case kgmetDescent : return m_descent;
+        default: return m_pGlyphFaceCache->glyph(gid)->getMetric(metric);
+    }
+}
+
+void Face::takeFileFace(FileFace* pFileFace/*takes ownership*/)
+{
+    if (m_pFileFace==pFileFace)
+      return;
+    
+    delete m_pFileFace;
+    m_pFileFace = pFileFace;
+}
+
+NameTable * Face::nameTable() const
+{
+    if (m_pNames) return m_pNames;
+    size_t tableLength = 0;
+    const byte * table = getTable(Tag::name, &tableLength);
+    if (table)
+        m_pNames = new NameTable(table, tableLength);
+    return m_pNames;
+}
+
+uint16 Face::languageForLocale(const char * locale) const
+{
+    nameTable();
+    if (m_pNames)
+        return m_pNames->getLanguageId(locale);
+    return 0;
+}
+
+
+#ifndef DISABLE_FILE_FACE
+
+FileFace::FileFace(const char *filename) :
+    m_pHeader(NULL),
+    m_pTableDir(NULL)
+{
+    if (!(m_pfile = fopen(filename, "rb"))) return;
+    if (fseek(m_pfile, 0, SEEK_END)) return;
+    m_lfile = ftell(m_pfile);
+    if (fseek(m_pfile, 0, SEEK_SET)) return;
+    size_t lOffset, lSize;
+    if (!TtfUtil::GetHeaderInfo(lOffset, lSize)) return;
+    m_pHeader = (TtfUtil::Sfnt::OffsetSubTable*)gralloc<char>(lSize);
+    if (fseek(m_pfile, lOffset, SEEK_SET)) return;
+    if (fread(m_pHeader, 1, lSize, m_pfile) != lSize) return;
+    if (!TtfUtil::CheckHeader(m_pHeader)) return;
+    if (!TtfUtil::GetTableDirInfo(m_pHeader, lOffset, lSize)) return;
+    m_pTableDir = (TtfUtil::Sfnt::OffsetSubTable::Entry*)gralloc<char>(lSize);
+    if (fseek(m_pfile, lOffset, SEEK_SET)) return;
+    if (fread(m_pTableDir, 1, lSize, m_pfile) != lSize) return;
+}
+
+FileFace::~FileFace()
+{
+    free(m_pTableDir);
+    free(m_pHeader);
+    if (m_pfile)
+        fclose(m_pfile);
+    m_pTableDir = NULL;
+    m_pfile = NULL;
+    m_pHeader = NULL;
+}
+
+
+const void *FileFace::table_fn(const void* appFaceHandle, unsigned int name, size_t *len)
+{
+    const FileFace* ttfFaceHandle = (const FileFace*)appFaceHandle;
+    TableCacheItem * tci = ttfFaceHandle->m_tables;
+
+    switch (name)
+    {
+		case Tag::Feat:	tci += 0; break;
+		case Tag::Glat:	tci += 1; break;
+		case Tag::Gloc:	tci += 2; break;
+		case Tag::OS_2:	tci += 3; break;
+		case Tag::Sile:	tci += 4; break;
+		case Tag::Silf:	tci += 5; break;
+		case Tag::Sill:	tci += 6; break;
+    	case Tag::cmap:	tci += 7; break;
+    	case Tag::glyf:	tci += 8; break;
+    	case Tag::hdmx:	tci += 9; break;
+    	case Tag::head:	tci += 10; break;
+    	case Tag::hhea:	tci += 11; break;
+    	case Tag::hmtx:	tci += 12; break;
+    	case Tag::kern:	tci += 13; break;
+    	case Tag::loca:	tci += 14; break;
+    	case Tag::maxp:	tci += 15; break;
+    	case Tag::name:	tci += 16; break;
+    	case Tag::post:	tci += 17; break;
+    	default:					tci = 0; break;
+    }
+
+    assert(tci); // don't expect any other table types
+    if (!tci) return NULL;
+    if (tci->data() == NULL)
+    {
+        char *tptr;
+        size_t tlen, lOffset;
+        if (!TtfUtil::GetTableInfo(name, ttfFaceHandle->m_pHeader, ttfFaceHandle->m_pTableDir, lOffset, tlen)) return NULL;
+        if (fseek(ttfFaceHandle->m_pfile, lOffset, SEEK_SET)) return NULL;
+        if (lOffset + tlen > ttfFaceHandle->m_lfile) return NULL;
+        tptr = gralloc<char>(tlen);
+        if (fread(tptr, 1, tlen, ttfFaceHandle->m_pfile) != tlen) 
+        {
+            free(tptr);
+            return NULL;
+        }
+        tci->set(tptr, tlen);
+    }
+    if (len) *len = tci->size();
+    return tci->data();
+}
+#endif                  //!DISABLE_FILE_FACE
new file mode 100644
--- /dev/null
+++ b/gfx/graphite2/src/Face.h
@@ -0,0 +1,176 @@
+/*  GRAPHITE2 LICENSING
+
+    Copyright 2010, SIL International
+    All rights reserved.
+
+    This library is free software; you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published
+    by the Free Software Foundation; either version 2.1 of License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should also have received a copy of the GNU Lesser General Public
+    License along with this library in the file named "LICENSE".
+    If not, write to the Free Software Foundation, 51 Franklin Street, 
+    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the 
+    internet at http://www.fsf.org/licenses/lgpl.html.
+
+Alternatively, the contents of this file may be used under the terms of the
+Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
+License, as published by the Free Software Foundation, either version 2
+of the License or (at your option) any later version.
+*/
+#pragma once
+
+#include "Main.h"
+#include "GlyphFace.h"
+#include "Silf.h"
+#include "TtfUtil.h"
+#include "Main.h"
+#include "graphite2/Font.h"
+#include "FeatureMap.h"
+#include "GlyphFaceCache.h"
+
+#ifndef DISABLE_FILE_FACE
+#include <cstdio>
+#include <cassert>
+#include "TtfTypes.h"
+#endif      //!DISABLE_FILE_FACE
+
+namespace graphite2 {
+
+class Segment;
+class FeatureVal;
+class NameTable;
+class Cmap;
+
+using TtfUtil::Tag;
+
+// These are the actual tags, as distinct from the consecutive IDs in TtfUtil.h
+
+#ifndef DISABLE_FILE_FACE
+class TableCacheItem
+{
+public:
+    TableCacheItem(char * theData, size_t theSize) : m_data(theData), m_size(theSize) {}
+    TableCacheItem() : m_data(0), m_size(0) {}
+    ~TableCacheItem()
+    {
+        if (m_size) free(m_data);
+    }
+    void set(char * theData, size_t theSize) { m_data = theData; m_size = theSize; }
+    const void * data() const { return m_data; }
+    size_t size() const { return m_size; }
+private:
+    char * m_data;
+    size_t m_size;
+};
+#endif      //!DISABLE_FILE_FACE
+
+
+
+
+class FileFace
+{
+#ifndef DISABLE_FILE_FACE
+public:
+    static const void *table_fn(const void* appFaceHandle, unsigned int name, size_t *len);
+  
+    FileFace(const char *filename);
+    ~FileFace();
+//    virtual const void *getTable(unsigned int name, size_t *len) const;
+    bool isValid() const { return m_pfile && m_pHeader && m_pTableDir; }
+
+    CLASS_NEW_DELETE
+public:     //for local convenience    
+    FILE* m_pfile;
+    unsigned int m_lfile;
+    mutable TableCacheItem m_tables[18];
+    TtfUtil::Sfnt::OffsetSubTable* m_pHeader;
+    TtfUtil::Sfnt::OffsetSubTable::Entry* m_pTableDir;       //[] number of elements is determined by m_pHeader->num_tables
+#endif      //!DISABLE_FILE_FACE
+   
+private:        //defensive
+    FileFace(const FileFace&);
+    FileFace& operator=(const FileFace&);
+};
+
+class Face
+{
+public:
+    const byte *getTable(const Tag name, size_t  * len = 0) const {
+    	size_t tbl_len=0;
+    	const byte * const tbl = reinterpret_cast<const byte *>((*m_getTable)(m_appFaceHandle, name, &tbl_len));
+    	if (len) *len = tbl_len;
+    	return TtfUtil::CheckTable(name, tbl, tbl_len) ? tbl : 0;
+    }
+    float advance(unsigned short id) const { return m_pGlyphFaceCache->glyph(id)->theAdvance().x; }
+    const Silf *silf(int i) const { return ((i < m_numSilf) ? m_silfs + i : (const Silf *)NULL); }
+    virtual bool runGraphite(Segment *seg, const Silf *silf) const;
+    uint16 findPseudo(uint32 uid) const { return (m_numSilf) ? m_silfs[0].findPseudo(uid) : 0; }
+
+public:
+    Face(const void* appFaceHandle/*non-NULL*/, gr_get_table_fn getTable2) : 
+        m_appFaceHandle(appFaceHandle), m_getTable(getTable2), m_pGlyphFaceCache(NULL),
+        m_cmap(NULL), m_numSilf(0), m_silfs(NULL), m_pFileFace(NULL),
+        m_pNames(NULL) {}
+    virtual ~Face();
+public:
+    float getAdvance(unsigned short glyphid, float scale) const { return advance(glyphid) * scale; }
+    const Rect &theBBoxTemporary(uint16 gid) const { return m_pGlyphFaceCache->glyph(gid)->theBBox(); }   //warning value may become invalid when another glyph is accessed
+    unsigned short upem() const { return m_upem; }
+    uint16 glyphAttr(uint16 gid, uint8 gattr) const { return m_pGlyphFaceCache->glyphAttr(gid, gattr); }
+
+private:
+    friend class Font;
+    unsigned short numGlyphs() const { return m_pGlyphFaceCache->m_nGlyphs; }
+
+public:
+    bool readGlyphs(uint32 faceOptions);
+    bool readGraphite();
+    bool readFeatures() { return m_Sill.readFace(*this); }
+    const Silf *chooseSilf(uint32 script) const;
+    const SillMap& theSill() const { return m_Sill; }
+    uint16 numFeatures() const { return m_Sill.m_FeatureMap.numFeats(); }
+    const FeatureRef *featureById(uint32 id) const { return m_Sill.m_FeatureMap.findFeatureRef(id); }
+    const FeatureRef *feature(uint16 index) const { return m_Sill.m_FeatureMap.feature(index); }
+    uint16 getGlyphMetric(uint16 gid, uint8 metric) const;
+
+    const GlyphFaceCache* getGlyphFaceCache() const { return m_pGlyphFaceCache; }      //never NULL
+    void takeFileFace(FileFace* pFileFace/*takes ownership*/);
+    Cmap & cmap() const { return *m_cmap; };
+    NameTable * nameTable() const;
+    uint16 languageForLocale(const char * locale) const;
+
+    CLASS_NEW_DELETE
+private:
+    const void* m_appFaceHandle/*non-NULL*/;
+    gr_get_table_fn m_getTable;
+    uint16 m_ascent;
+    uint16 m_descent;
+    // unsigned short *m_glyphidx;     // index for each glyph id in the font
+    // unsigned short m_readglyphs;    // how many glyphs have we in m_glyphs?
+    // unsigned short m_capacity;      // how big is m_glyphs
+    mutable GlyphFaceCache* m_pGlyphFaceCache;      //owned - never NULL
+    mutable Cmap * m_cmap; // cmap cache if available
+    unsigned short m_upem;          // design units per em
+protected:
+    unsigned short m_numSilf;       // number of silf subtables in the silf table
+    Silf *m_silfs;                   // silf subtables.
+private:
+    SillMap m_Sill;
+    FileFace* m_pFileFace;      //owned
+    mutable NameTable* m_pNames;
+    
+private:        //defensive on m_pGlyphFaceCache, m_pFileFace and m_silfs
+    Face(const Face&);
+    Face& operator=(const Face&);
+};
+
+} // namespace graphite2
+
+struct gr_face : public graphite2::Face {};
new file mode 100644
--- /dev/null
+++ b/gfx/graphite2/src/FeatureMap.cpp
@@ -0,0 +1,288 @@
+/*  GRAPHITE2 LICENSING
+
+    Copyright 2010, SIL International
+    All rights reserved.
+
+    This library is free software; you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published
+    by the Free Software Foundation; either version 2.1 of License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should also have received a copy of the GNU Lesser General Public
+    License along with this library in the file named "LICENSE".
+    If not, write to the Free Software Foundation, 51 Franklin Street, 
+    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the 
+    internet at http://www.fsf.org/licenses/lgpl.html.
+
+Alternatively, the contents of this file may be used under the terms of the
+Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
+License, as published by the Free Software Foundation, either version 2
+of the License or (at your option) any later version.
+*/
+#include <cstring>
+
+#include "Main.h"
+#include "Endian.h"
+#include "FeatureMap.h"
+#include "FeatureVal.h"
+#include "graphite2/Font.h"
+#include "XmlTraceLog.h"
+#include "TtfUtil.h"
+#include <cstdlib>
+#include "Face.h"
+
+
+using namespace graphite2;
+
+static int cmpNameAndFeatures(const void *a, const void *b) { return (*(NameAndFeatureRef *)a < *(NameAndFeatureRef *)b 
+                                                                        ? -1 : (*(NameAndFeatureRef *)b < *(NameAndFeatureRef *)a 
+                                                                                    ? 1 : 0)); }
+
+bool FeatureMap::readFeats(const Face & face)
+{
+    size_t lFeat;
+    const byte *pFeat = face.getTable(TtfUtil::Tag::Feat, &lFeat);
+    const byte *pOrig = pFeat;
+    uint16 *defVals=0;
+    uint32 version;
+    if (!pFeat) return true;
+    if (lFeat < 12) return false;
+
+    version = be::read<uint32>(pFeat);
+    if (version < 0x00010000) return false;
+    m_numFeats = be::read<uint16>(pFeat);
+    be::skip<uint16>(pFeat);
+    be::skip<uint32>(pFeat);
+    if (m_numFeats * 16U + 12 > lFeat) { m_numFeats = 0; return false; }		//defensive
+    if (!m_numFeats) return true;
+    m_feats = new FeatureRef[m_numFeats];
+    defVals = gralloc<uint16>(m_numFeats);
+    byte currIndex = 0;
+    byte currBits = 0;     //to cause overflow on first Feature
+
+#ifndef DISABLE_TRACING
+    if (XmlTraceLog::get().active())
+    {
+        XmlTraceLog::get().openElement(ElementFeatures);
+        XmlTraceLog::get().addAttribute(AttrMajor, version >> 16);
+        XmlTraceLog::get().addAttribute(AttrMinor, version & 0xFFFF);
+        XmlTraceLog::get().addAttribute(AttrNum, m_numFeats);
+    }
+#endif
+    for (int i = 0, ie = m_numFeats; i != ie; i++)
+    {
+        uint32 name;
+        if (version < 0x00020000)
+            name = be::read<uint16>(pFeat);
+        else
+            name = be::read<uint32>(pFeat);
+        uint16 numSet = be::read<uint16>(pFeat);
+
+        uint32 offset;
+        if (version < 0x00020000)
+            offset = be::read<uint32>(pFeat);
+        else
+        {
+            be::skip<uint16>(pFeat);
+            offset = be::read<uint32>(pFeat);
+        }
+        if (offset > lFeat)
+        {
+            free(defVals);
+            return false;
+        }
+        uint16 flags = be::read<uint16>(pFeat);
+        uint16 uiName = be::read<uint16>(pFeat);
+        const byte *pSet = pOrig + offset;
+        uint16 maxVal = 0;
+
+#ifndef DISABLE_TRACING
+        if (XmlTraceLog::get().active())
+        {
+            XmlTraceLog::get().openElement(ElementFeature);
+            XmlTraceLog::get().addAttribute(AttrIndex, i);
+            XmlTraceLog::get().addAttribute(AttrNum, name);
+            XmlTraceLog::get().addAttribute(AttrFlags, flags);
+            XmlTraceLog::get().addAttribute(AttrLabel, uiName);
+        }
+#endif
+
+        if (numSet == 0)
+        {
+            --m_numFeats;
+#ifndef DISABLE_TRACING
+            XmlTraceLog::get().closeElement(ElementFeature);
+#endif
+            continue;
+        }
+
+        if (offset + numSet * 4 > lFeat) return false;
+        FeatureSetting *uiSet = gralloc<FeatureSetting>(numSet);
+        for (int j = 0; j < numSet; j++)
+        {
+            int16 val = be::read<int16>(pSet);
+            if (val > maxVal) maxVal = val;
+            if (j == 0) defVals[i] = val;
+            uint16 label = be::read<uint16>(pSet);
+            new (uiSet + j) FeatureSetting(label, val);
+#ifndef DISABLE_TRACING
+            if (XmlTraceLog::get().active())
+            {
+                XmlTraceLog::get().openElement(ElementFeatureSetting);
+                XmlTraceLog::get().addAttribute(AttrIndex, j);
+                XmlTraceLog::get().addAttribute(AttrValue, val);
+                XmlTraceLog::get().addAttribute(AttrLabel, label);
+                if (j == 0) XmlTraceLog::get().addAttribute(AttrDefault, defVals[i]);
+                XmlTraceLog::get().closeElement(ElementFeatureSetting);
+            }
+#endif
+        }
+        uint32 mask = 1;
+        byte bits = 0;
+        for (bits = 0; bits < 32; bits++, mask <<= 1)
+        {
+            if (mask > maxVal)
+            {
+                if (bits + currBits > 32)
+                {
+                    currIndex++;
+                    currBits = 0;
+                    mask = 2;
+                }
+                ::new (m_feats + i) FeatureRef (currBits, currIndex,
+                                               (mask - 1) << currBits, flags,
+                                               name, uiName, numSet, uiSet, &face);
+                currBits += bits;
+                break;
+            }
+        }
+#ifndef DISABLE_TRACING
+    XmlTraceLog::get().closeElement(ElementFeature);
+#endif
+    }
+    m_defaultFeatures = new Features(currIndex + 1, *this);
+    m_pNamedFeats = new NameAndFeatureRef[m_numFeats];
+    for (int i = 0; i < m_numFeats; i++)
+    {
+    	m_feats[i].applyValToFeature(defVals[i], *m_defaultFeatures);
+        m_pNamedFeats[i] = m_feats+i;
+    }
+    
+    free(defVals);
+
+    qsort(m_pNamedFeats, m_numFeats, sizeof(NameAndFeatureRef), &cmpNameAndFeatures);
+
+#ifndef DISABLE_TRACING
+    XmlTraceLog::get().closeElement(ElementFeatures);
+#endif
+
+    return true;
+}
+
+bool SillMap::readFace(const Face & face)
+{
+    if (!m_FeatureMap.readFeats(face)) return false;
+    if (!readSill(face)) return false;
+    return true;
+}
+
+
+bool SillMap::readSill(const Face & face)
+{
+    size_t lSill;
+    const byte *pSill = face.getTable(TtfUtil::Tag::Sill, &lSill);
+    const byte *pBase = pSill;
+
+    if (!pSill) return true;
+    if (lSill < 12) return false;
+    if (be::read<uint32>(pSill) != 0x00010000UL) return false;
+    m_numLanguages = be::read<uint16>(pSill);
+    m_langFeats = new LangFeaturePair[m_numLanguages];
+    if (!m_langFeats || !m_FeatureMap.m_numFeats) { m_numLanguages = 0; return true; }        //defensive
+
+    pSill += 6;     // skip the fast search
+    if (lSill < m_numLanguages * 8U + 12) return false;
+
+    for (int i = 0; i < m_numLanguages; i++)
+    {
+        uint32 langid = be::read<uint32>(pSill);
+        uint16 numSettings = be::read<uint16>(pSill);
+        uint16 offset = be::read<uint16>(pSill);
+        if (offset + 8U * numSettings > lSill && numSettings > 0) return false;
+        Features* feats = new Features(*m_FeatureMap.m_defaultFeatures);
+        const byte *pLSet = pBase + offset;
+
+        for (int j = 0; j < numSettings; j++)
+        {
+            uint32 name = be::read<uint32>(pLSet);
+            uint16 val = be::read<uint16>(pLSet);
+            pLSet += 2;
+            const FeatureRef* pRef = m_FeatureMap.findFeatureRef(name);
+            if (pRef)
+                pRef->applyValToFeature(val, *feats);
+        }
+        //std::pair<uint32, Features *>kvalue = std::pair<uint32, Features *>(langid, feats);
+        //m_langMap.insert(kvalue);
+        m_langFeats[i].m_lang = langid;
+        m_langFeats[i].m_pFeatures = feats;
+    }
+    return true;
+}
+
+
+Features* SillMap::cloneFeatures(uint32 langname/*0 means default*/) const
+{
+    if (langname)
+    {
+        // the number of languages in a font is usually small e.g. 8 in Doulos
+        // so this loop is not very expensive
+        for (uint16 i = 0; i < m_numLanguages; i++)
+        {
+            if (m_langFeats[i].m_lang == langname)
+                return new Features(*m_langFeats[i].m_pFeatures);
+        }
+    }
+    return new Features (*m_FeatureMap.m_defaultFeatures);
+}
+
+
+
+const FeatureRef *FeatureMap::findFeatureRef(uint32 name) const
+{
+    NameAndFeatureRef *it;
+    
+    for (it = m_pNamedFeats; it < m_pNamedFeats + m_numFeats; ++it)
+        if (it->m_name == name)
+            return it->m_pFRef;
+    return NULL;
+}
+
+bool FeatureRef::applyValToFeature(uint16 val, Features & pDest) const 
+{ 
+    if (val>m_max || !m_pFace)
+      return false;
+    if (pDest.m_pMap==NULL)
+      pDest.m_pMap = &m_pFace->theSill().theFeatureMap();
+    else
+      if (pDest.m_pMap!=&m_pFace->theSill().theFeatureMap())
+        return false;       //incompatible
+    pDest.reserve(m_index);
+    pDest[m_index] &= ~m_mask;
+    pDest[m_index] |= (uint32(val) << m_bits);
+    return true;
+}
+
+uint16 FeatureRef::getFeatureVal(const Features& feats) const
+{ 
+  if (m_index < feats.size() && &m_pFace->theSill().theFeatureMap()==feats.m_pMap) 
+    return (feats[m_index] & m_mask) >> m_bits; 
+  else
+    return 0;
+}
+
+
new file mode 100644
--- /dev/null
+++ b/gfx/graphite2/src/FeatureMap.h
@@ -0,0 +1,202 @@
+/*  GRAPHITE2 LICENSING
+
+    Copyright 2010, SIL International
+    All rights reserved.
+
+    This library is free software; you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published
+    by the Free Software Foundation; either version 2.1 of License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should also have received a copy of the GNU Lesser General Public
+    License along with this library in the file named "LICENSE".
+    If not, write to the Free Software Foundation, 51 Franklin Street, 
+    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the 
+    internet at http://www.fsf.org/licenses/lgpl.html.
+
+Alternatively, the contents of this file may be used under the terms of the
+Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
+License, as published by the Free Software Foundation, either version 2
+of the License or (at your option) any later version.
+*/
+#pragma once
+// #include <cstring>
+// #include "graphite2/Types.h"
+#include "graphite2/Font.h"
+#include "Main.h"
+#include "FeatureVal.h"
+
+namespace graphite2 {
+
+// Forward declarations for implmentation types
+class FeatureMap;
+class Face;
+
+
+class FeatureSetting
+{
+public:
+    FeatureSetting(uint16 labelId, int16 theValue) : m_label(labelId), m_value(theValue) {};
+    FeatureSetting(const FeatureSetting & fs) : m_label(fs.m_label), m_value(fs.m_value) {};
+    uint16 label() const { return m_label; }
+    int16 value() const { return m_value; }
+    
+    CLASS_NEW_DELETE;
+private:
+    uint16 m_label;
+    int16 m_value;
+};
+
+class FeatureRef
+{
+public:
+    FeatureRef() :
+        m_nameValues(NULL), m_pFace(NULL)
+      {}
+    FeatureRef(byte bits, byte index, uint32 mask, uint16 flags,
+               uint32 name, uint16 uiName, uint16 numSet,
+               FeatureSetting *uiNames, const Face* pFace/*not NULL*/) throw()
+      : m_mask(mask), m_id(name), m_max((uint16)(mask >> bits)), m_bits(bits), m_index(index),
+      m_nameid(uiName), m_nameValues(uiNames), m_pFace(pFace), m_flags(flags),
+      m_numSet(numSet)
+      {}
+    FeatureRef(const FeatureRef & toCopy)
+        : m_mask(toCopy.m_mask), m_id(toCopy.m_id), m_max(toCopy.m_max),
+        m_bits(toCopy.m_bits), m_index(toCopy.m_index),
+        m_nameid(toCopy.m_nameid),
+        m_nameValues((toCopy.m_nameValues)? gralloc<FeatureSetting>(toCopy.m_numSet) : NULL),
+        m_pFace(toCopy.m_pFace), m_flags(toCopy.m_flags),
+        m_numSet(toCopy.m_numSet)
+    {
+        // most of the time these name values aren't used, so NULL might be acceptable
+        if (toCopy.m_nameValues)
+        {
+            memcpy(m_nameValues, toCopy.m_nameValues, sizeof(FeatureSetting) * m_numSet);
+        }
+    }
+    ~FeatureRef() {
+        free(m_nameValues);
+        m_nameValues = NULL;
+    }
+    bool applyValToFeature(uint16 val, Features& pDest) const; //defined in GrFaceImp.h
+    void maskFeature(Features & pDest) const {
+	if (m_index < pDest.size()) 				//defensive
+	    pDest[m_index] |= m_mask; 
+    }
+
+    uint16 getFeatureVal(const Features& feats) const; //defined in GrFaceImp.h
+
+    uint32 getId() const { return m_id; }
+    uint16 getNameId() const { return m_nameid; }
+    uint16 getNumSettings() const { return m_numSet; }
+    uint16 getSettingName(uint16 index) const { return m_nameValues[index].label(); }
+    int16 getSettingValue(uint16 index) const { return m_nameValues[index].value(); }
+    uint16 maxVal() const { return m_max; }
+    const Face* getFace() const { return m_pFace;}
+    const FeatureMap* getFeatureMap() const;// { return m_pFace;}
+
+    CLASS_NEW_DELETE;
+private:
+    uint32 m_mask;              // bit mask to get the value from the vector
+    uint32 m_id;                // feature identifier/name
+    uint16 m_max;               // max value the value can take
+    byte m_bits;                // how many bits to shift the value into place
+    byte m_index;               // index into the array to find the ulong to mask
+    uint16 m_nameid;            // Name table id for feature name
+    FeatureSetting *m_nameValues;       // array of name table ids for feature values
+    const Face* m_pFace;   //not NULL
+    uint16 m_flags;             // feature flags (unused at the moment but read from the font)
+    uint16 m_numSet;            // number of values (number of entries in m_nameValues)
+
+private:        //unimplemented
+    FeatureRef& operator=(const FeatureRef&);
+};
+
+
+class NameAndFeatureRef
+{
+  public:
+    NameAndFeatureRef() : m_pFRef(NULL) {}
+    NameAndFeatureRef(uint32 name) : m_name(name) {}
+    NameAndFeatureRef(const FeatureRef* p/*not NULL*/) : m_name(p->getId()), m_pFRef(p) {}
+
+    bool operator<(const NameAndFeatureRef& rhs) const //orders by m_name
+        {   return m_name<rhs.m_name; }
+
+    CLASS_NEW_DELETE
+ 
+    uint32 m_name;
+    const FeatureRef* m_pFRef;
+};
+
+class FeatureMap
+{
+public:
+    FeatureMap() : m_numFeats(0), m_feats(NULL), m_pNamedFeats(NULL),
+        m_defaultFeatures(NULL) {}
+    ~FeatureMap() { delete[] m_feats; delete[] m_pNamedFeats; delete m_defaultFeatures; }
+
+    bool readFeats(const Face & face);
+    const FeatureRef *findFeatureRef(uint32 name) const;
+    FeatureRef *feature(uint16 index) const { return m_feats + index; }
+    //GrFeatureRef *featureRef(byte index) { return index < m_numFeats ? m_feats + index : NULL; }
+    const FeatureRef *featureRef(byte index) const { return index < m_numFeats ? m_feats + index : NULL; }
+    FeatureVal* cloneFeatures(uint32 langname/*0 means default*/) const;      //call destroy_Features when done.
+    uint16 numFeats() const { return m_numFeats; };
+    CLASS_NEW_DELETE
+private:
+friend class SillMap;
+    uint16 m_numFeats;
+
+    FeatureRef *m_feats;
+    NameAndFeatureRef* m_pNamedFeats;   //owned
+    FeatureVal* m_defaultFeatures;        //owned
+    
+private:		//defensive on m_feats, m_pNamedFeats, and m_defaultFeatures
+    FeatureMap(const FeatureMap&);
+    FeatureMap& operator=(const FeatureMap&);
+};
+
+
+class SillMap
+{
+private:
+    class LangFeaturePair
+    {
+    public:
+        LangFeaturePair() : m_pFeatures(NULL) {}
+        ~LangFeaturePair() { delete m_pFeatures; }
+        
+        uint32 m_lang;
+        Features* m_pFeatures;      //owns
+        CLASS_NEW_DELETE
+    };
+public:
+    SillMap() : m_langFeats(NULL), m_numLanguages(0) {}
+    ~SillMap() { delete[] m_langFeats; }
+    bool readFace(const Face & face);
+    bool readSill(const Face & face);
+    FeatureVal* cloneFeatures(uint32 langname/*0 means default*/) const;      //call destroy_Features when done.
+    uint16 numLanguages() const { return m_numLanguages; };
+    uint32 getLangName(uint16 index) const { return (index < m_numLanguages)? m_langFeats[index].m_lang : 0; };
+
+    const FeatureMap & theFeatureMap() const { return m_FeatureMap; };
+private:
+friend class Face;
+    FeatureMap m_FeatureMap;        //of face
+    LangFeaturePair * m_langFeats;
+    uint16 m_numLanguages;
+
+private:        //defensive on m_langFeats
+    SillMap(const SillMap&);
+    SillMap& operator=(const SillMap&);
+};
+
+} // namespace graphite2
+
+struct gr_feature_ref : public graphite2::FeatureRef {};
new file mode 100644
--- /dev/null
+++ b/gfx/graphite2/src/FeatureVal.h
@@ -0,0 +1,75 @@
+/*  GRAPHITE2 LICENSING
+
+    Copyright 2010, SIL International
+    All rights reserved.
+
+    This library is free software; you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published
+    by the Free Software Foundation; either version 2.1 of License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should also have received a copy of the GNU Lesser General Public
+    License along with this library in the file named "LICENSE".
+    If not, write to the Free Software Foundation, 51 Franklin Street, 
+    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the 
+    internet at http://www.fsf.org/licenses/lgpl.html.
+
+Alternatively, the contents of this file may be used under the terms of the
+Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
+License, as published by the Free Software Foundation, either version 2
+of the License or (at your option) any later version.
+*/
+#pragma once
+#include <cstring>
+#include <cassert>
+#include "Main.h"
+#include "List.h"
+
+namespace graphite2 {
+
+class FeatureRef;
+class FeatureMap;
+
+class FeatureVal : public Vector<uint32>
+{
+public:
+    uint32 maskedOr(const FeatureVal &other, const FeatureVal &mask) {
+        uint32 len = size() ;
+        if (other.size()<len) len = other.size();		//defensive
+        if (mask.size()<len) len = mask.size();		//defensive
+        for (uint32 i = 0; i < len; i++)
+            if (mask[i]) operator[](i) = (operator[](i) & ~mask[i]) | (other[i] & mask[i]);
+        return len;
+    }
+
+    FeatureVal() : m_pMap(0) { }
+    FeatureVal(int num, const FeatureMap & pMap) : Vector<uint32>(num), m_pMap(&pMap) {}
+    FeatureVal(const FeatureVal & rhs) : Vector<uint32>(rhs), m_pMap(rhs.m_pMap) {}
+
+    bool operator ==(const FeatureVal & b) const
+    {
+        size_t n = size();
+        if (n != b.size())      return false;
+        
+        for(const_iterator l = begin(), r = b.begin(); n && *l == *r; --n, ++l, ++r);
+        
+        return n == 0;
+    }
+
+    CLASS_NEW_DELETE
+private:
+    friend class FeatureRef;		//so that FeatureRefs can manipulate m_vec directly
+    const FeatureMap* m_pMap;
+};
+
+typedef FeatureVal Features;
+
+} // namespace graphite2
+
+
+struct gr_feature_val : public graphite2::FeatureVal {};
new file mode 100644
--- /dev/null
+++ b/gfx/graphite2/src/Font.cpp
@@ -0,0 +1,80 @@
+/*  GRAPHITE2 LICENSING
+
+    Copyright 2010, SIL International
+    All rights reserved.
+
+    This library is free software; you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published
+    by the Free Software Foundation; either version 2.1 of License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should also have received a copy of the GNU Lesser General Public
+    License along with this library in the file named "LICENSE".
+    If not, write to the Free Software Foundation, 51 Franklin Street, 
+    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the 
+    internet at http://www.fsf.org/licenses/lgpl.html.
+
+Alternatively, the contents of this file may be used under the terms of the
+Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
+License, as published by the Free Software Foundation, either version 2
+of the License or (at your option) any later version.
+*/
+#include "Font.h"
+
+
+using namespace graphite2;
+
+Font::Font(float ppm, const Face *face/*needed for scaling*/) :
+    m_scale(ppm / face->upem())
+{
+    size_t nGlyphs=face->numGlyphs();
+    m_advances = gralloc<float>(nGlyphs);
+    if (m_advances)
+    {
+        float *advp = m_advances;
+        for (size_t i = 0; i < nGlyphs; i++)
+        { *advp++ = INVALID_ADVANCE; }
+    }
+}
+
+
+/*virtual*/ Font::~Font()
+{
+	free(m_advances);
+}
+
+
+SimpleFont::SimpleFont(float ppm/*pixels per em*/, const Face *face) :
+  Font(ppm, face),
+  m_face(face)
+{
+}
+  
+  
+/*virtual*/ float SimpleFont::computeAdvance(unsigned short glyphid) const
+{
+    return m_face->getAdvance(glyphid, m_scale);
+}
+
+
+
+HintedFont::HintedFont(float ppm/*pixels per em*/, const void* appFontHandle/*non-NULL*/, gr_advance_fn advance2, const Face *face/*needed for scaling*/) :
+    Font(ppm, face), 
+    m_appFontHandle(appFontHandle),
+    m_advance(advance2)
+{
+}
+
+
+/*virtual*/ float HintedFont::computeAdvance(unsigned short glyphid) const
+{
+    return (*m_advance)(m_appFontHandle, glyphid);
+}
+
+
+
new file mode 100644
--- /dev/null
+++ b/gfx/graphite2/src/Font.h
@@ -0,0 +1,93 @@
+/*  GRAPHITE2 LICENSING
+
+    Copyright 2010, SIL International
+    All rights reserved.
+
+    This library is free software; you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published
+    by the Free Software Foundation; either version 2.1 of License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should also have received a copy of the GNU Lesser General Public
+    License along with this library in the file named "LICENSE".
+    If not, write to the Free Software Foundation, 51 Franklin Street, 
+    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the 
+    internet at http://www.fsf.org/licenses/lgpl.html.
+
+Alternatively, the contents of this file may be used under the terms of the
+Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
+License, as published by the Free Software Foundation, either version 2
+of the License or (at your option) any later version.
+*/
+#pragma once
+#include <cassert>
+#include "graphite2/Font.h"
+#include "Main.h"
+#include "Face.h"
+
+namespace graphite2 {
+
+#define INVALID_ADVANCE -1e38f		// can't be a static const because non-integral
+
+class Font
+{
+public:
+    Font(float ppm, const Face *face/*needed for scaling*/);
+    virtual ~Font();
+
+    float advance(unsigned short glyphid) const {
+        if (m_advances[glyphid] == INVALID_ADVANCE)
+            m_advances[glyphid] = computeAdvance(glyphid);
+        return m_advances[glyphid];
+    }
+//    Position scale(const Position& p) const { return Position(m_scale * p.x, m_scale * p.y); }
+//    float scale(float p) const { return m_scale * p; }
+    float scale() const { return m_scale; }
+    virtual bool isHinted() const { return false; }
+
+    CLASS_NEW_DELETE
+private:
+    virtual float computeAdvance(unsigned short /*glyphid*/) const { assert(false); return .0f; };
+    
+protected:
+    float m_scale;      // scales from design units to ppm
+    float *m_advances;  // One advance per glyph in pixels. Nan if not defined
+    
+private:			//defensive on m_advances
+    Font(const Font&);
+    Font& operator=(const Font&);
+};
+
+
+class SimpleFont : public Font      //has no external hints - gets advance information from the face
+{
+public:
+    SimpleFont(float ppm/*pixels per em*/, const Face *face);
+private:
+    virtual float computeAdvance(unsigned short glyphid) const;
+private:
+    const Face *m_face;   // GrFace to get the rest of the info from
+};
+
+
+class HintedFont : public Font
+{
+public:
+    HintedFont(float ppm/*pixels per em*/, const void* appFontHandle/*non-NULL*/, gr_advance_fn advance, const Face *face/*needed for scaling*/);
+    virtual bool isHinted() const { return true; }
+private:
+    virtual float computeAdvance(unsigned short glyphid) const;
+
+private:
+    const void* m_appFontHandle/*non-NULL*/;
+    gr_advance_fn m_advance;
+};
+
+} // namespace graphite2
+
+struct gr_font : public graphite2::Font {};
new file mode 100644
--- /dev/null
+++ b/gfx/graphite2/src/GlyphFace.cpp
@@ -0,0 +1,255 @@
+/*  GRAPHITE2 LICENSING
+
+    Copyright 2010, SIL International
+    All rights reserved.
+
+    This library is free software; you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published
+    by the Free Software Foundation; either version 2.1 of License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should also have received a copy of the GNU Lesser General Public
+    License along with this library in the file named "LICENSE".
+    If not, write to the Free Software Foundation, 51 Franklin Street, 
+    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the 
+    internet at http://www.fsf.org/licenses/lgpl.html.
+
+Alternatively, the contents of this file may be used under the terms of the
+Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
+License, as published by the Free Software Foundation, either version 2
+of the License or (at your option) any later version.
+*/
+#include <iterator>
+#include "GlyphFace.h"
+#include "XmlTraceLog.h"
+#include "GlyphFaceCache.h"
+#include "TtfUtil.h"
+#include "Endian.h"
+
+
+using namespace graphite2;
+
+namespace
+{
+	struct glyph_attr { uint16 id, value; };
+
+	class glat_iterator : public std::iterator<std::input_iterator_tag, glyph_attr>
+	{
+	public:
+		glat_iterator(const void * glat=0) : _p(reinterpret_cast<const byte *>(glat)), _n(0) {}
+
+		glat_iterator & operator ++ () 		{ ++_v.id; --_n; _p += sizeof(uint16); if (_n == -1) { _p -= 2; _v.id = *_p++; _n = *_p++; } return *this; }
+		glat_iterator   operator ++ (int) 	{ glat_iterator tmp(*this); operator++(); return tmp; }
+
+		bool operator == (const glat_iterator & rhs) { return _p >= rhs._p || _p + _n*sizeof(uint16) > rhs._p; }
+		bool operator != (const glat_iterator & rhs) { return !operator==(rhs); }
+
+		value_type 			operator * () const {
+			if (_n==0) { _v.id = *_p++; _n = *_p++; }
+			_v.value = be::peek<uint16>(_p);
+			return _v;
+		}
+		const value_type *	operator ->() const { operator * (); return &_v; }
+
+	protected:
+		mutable const byte * _p;
+		mutable value_type  _v;
+		mutable int 		_n;
+	};
+
+	class glat2_iterator : public glat_iterator
+	{
+	public:
+		glat2_iterator(const void * glat) : glat_iterator(glat) {}
+
+		glat_iterator & operator ++ () 		{ ++_v.id; --_n; _p += sizeof(uint16); if (_n == -1) { _p -= sizeof(uint16)*2; _v.id = be::read<uint16>(_p); _n = be::read<uint16>(_p); } return *this; }
+		glat_iterator   operator ++ (int) 	{ glat_iterator tmp(*this); operator++(); return tmp; }
+
+		value_type 			operator * () const {
+			if (_n==0) { _v.id = be::read<uint16>(_p); _n = be::read<uint16>(_p); }
+			_v.value = be::peek<uint16>(_p);
+			return _v;
+		}
+		const value_type *	operator ->() const { operator * (); return &_v; }
+	};
+}
+
+GlyphFace::GlyphFace(const GlyphFaceCacheHeader& hdr, unsigned short glyphid)
+{
+    if (glyphid < hdr.m_nGlyphsWithGraphics)
+    {
+        int nLsb, xMin, yMin, xMax, yMax;
+        unsigned int nAdvWid;
+        size_t locidx = TtfUtil::LocaLookup(glyphid, hdr.m_pLoca, hdr.m_lLoca, hdr.m_pHead);
+        void *pGlyph = TtfUtil::GlyfLookup(hdr.m_pGlyf, locidx, hdr.m_lGlyf);
+        if (TtfUtil::HorMetrics(glyphid, hdr.m_pHmtx, hdr.m_lHmtx, hdr.m_pHHea, nLsb, nAdvWid))
+            m_advance = Position(static_cast<float>(nAdvWid), 0);
+        else
+            m_advance = Position();
+        if (pGlyph && TtfUtil::GlyfBox(pGlyph, xMin, yMin, xMax, yMax))
+            m_bbox = Rect(Position(static_cast<float>(xMin), static_cast<float>(yMin)),
+//                    Position(static_cast<float>(xMax - xMin), static_cast<float>(yMax - yMin)));
+                Position(static_cast<float>(xMax), static_cast<float>(yMax)));
+        else
+            m_bbox = Rect();
+    }
+    else
+    {
+        m_advance = Position();
+        m_bbox = Rect();
+    }
+#ifndef DISABLE_TRACING
+    if (XmlTraceLog::get().active())
+    {
+        XmlTraceLog::get().openElement(ElementGlyphFace);
+        XmlTraceLog::get().addAttribute(AttrGlyphId, glyphid);
+        XmlTraceLog::get().addAttribute(AttrAdvanceX, m_advance.x);
+        XmlTraceLog::get().addAttribute(AttrAdvanceY, m_advance.y);
+    }
+#endif
+    if (glyphid < hdr.m_nGlyphsWithAttributes)
+    {
+        size_t glocs, gloce;
+        if (hdr.m_locFlagsUse32Bit)
+        {
+            glocs = be::swap<uint32>(((uint32 *)hdr.m_pGloc)[2+glyphid]);
+            gloce = be::swap<uint32>(((uint32 *)hdr.m_pGloc)[3+glyphid]);
+        }
+        else
+        {
+            glocs = be::swap<uint16>(((uint16 *)hdr.m_pGloc)[4+glyphid]);
+            gloce = be::swap<uint16>(((uint16 *)hdr.m_pGloc)[5+glyphid]);
+        }
+        if (glocs < hdr.m_lGlat && gloce <= hdr.m_lGlat)
+        {
+//            m_attrs = grzeroalloc<uint16>(hdr.m_numAttrs);
+//            readAttrs(hdr.m_pGlat + glocs, hdr.m_pGlat + gloce, m_attrs, hdr.m_numAttrs, hdr.m_fGlat);
+        	if (hdr.m_fGlat < 0x00020000)
+        	{
+        		if (gloce - glocs < 2*sizeof(byte)+sizeof(uint16)
+        		 || gloce - glocs > hdr.m_numAttrs*(2*sizeof(byte)+sizeof(uint16)))
+        			return;
+
+        		new (&m_attrs) sparse(glat_iterator(hdr.m_pGlat + glocs), glat_iterator(hdr.m_pGlat + gloce));
+        	}
+        	else
+        	{
+        		if (gloce - glocs < 3*sizeof(uint16)
+        		 || gloce - glocs > hdr.m_numAttrs*3*sizeof(uint16))
+        			return;
+
+        		new (&m_attrs) sparse(glat2_iterator(hdr.m_pGlat + glocs), glat2_iterator(hdr.m_pGlat + gloce));
+        	}
+
+        	if (m_attrs.size() > hdr.m_numAttrs)
+        	{
+        		m_attrs.~sparse();
+        		new (&m_attrs) sparse();
+        	}
+        }
+    }
+#ifndef DISABLE_TRACING
+    XmlTraceLog::get().closeElement(ElementGlyphFace);
+#endif
+}
+
+
+//void GlyphFace::readAttrs(const byte *glat, const byte * const glat_end, uint16 * attrs, size_t num, uint32 format)
+//{
+//	glat_iterator::value_type v;
+//
+//	if (format < 0x00020000)
+//	{
+//		for (glat_iterator i = glat, end = glat_end; i != end; ++i)
+//		{
+//			v = *i;
+//			if (v.id >= num) break;
+//			attrs[v.id] = v.value;
+//		}
+//	}
+//	else
+//	{
+//		for (glat2_iterator i = glat, end = glat_end; i != end; ++i)
+//		{
+//			v = *i;
+//			if (v.id >= num) break;
+//			attrs[v.id] = v.value;
+//		}
+//	}
+//
+//	if (v.id >= num) {
+//#ifndef DISABLE_TRACING
+//		XmlTraceLog::get().warning("Invalid glat entry: attr id %d max id %d", v.id, num);
+//#endif
+//	}
+//
+//	const byte * 		glat 		= static_cast<const byte *>(pGlat) + start,
+//			   * const 	glat_end 	= glat + end - start;
+
+
+//	while (glat < glat_end)
+//	{
+//		uint16 * attr, * attr_end;
+//
+//		if (format < 0x00020000)
+//		{
+//			attr = attrs + *glat++; attr_end = attr + *glat++;
+//		}
+//		else
+//		{
+//			attr = attrs + be::read<uint16>(glat); attr_end = attr + be::read<uint16>(glat);
+//		}
+//
+//		if (attr_end > attrs + num)
+//		{
+//#ifndef DISABLE_TRACING
+//			XmlTraceLog::get().warning("Invalid glat entry: attr id %d count %d", *attr, attr_end - attr);
+//#endif
+//			return;
+//		}
+//		while (attr != attr_end)
+//		{
+//			*attr++ = be::read<uint16>(glat);
+//			logAttr(attrs, attr-1);
+//		}
+//	}
+//}
+
+
+inline
+void GlyphFace::logAttr(GR_MAYBE_UNUSED const uint16 attrs[], GR_MAYBE_UNUSED const uint16 * attr)
+{
+#ifndef DISABLE_TRACING
+	if (XmlTraceLog::get().active())
+	{
+		XmlTraceLog::get().openElement(ElementAttr);
+		XmlTraceLog::get().addAttribute(AttrAttrId, attr - attrs);
+		XmlTraceLog::get().addAttribute(AttrAttrVal, *attr);
+		XmlTraceLog::get().closeElement(ElementAttr);
+	}
+#endif
+}
+
+
+uint16 GlyphFace::getMetric(uint8 metric) const
+{
+    switch (metrics(metric))
+    {
+        case kgmetLsb : return static_cast<uint16>(m_bbox.bl.x);
+        case kgmetRsb : return static_cast<uint16>(m_advance.x - m_bbox.tr.x);
+        case kgmetBbTop : return static_cast<uint16>(m_bbox.tr.y);
+        case kgmetBbBottom : return static_cast<uint16>(m_bbox.bl.y);
+        case kgmetBbLeft : return static_cast<uint16>(m_bbox.bl.x);
+        case kgmetBbRight : return static_cast<uint16>(m_bbox.tr.x);
+        case kgmetBbHeight: return static_cast<uint16>(m_bbox.tr.y - m_bbox.bl.y);
+        case kgmetBbWidth : return static_cast<uint16>(m_bbox.tr.x - m_bbox.bl.x);
+        case kgmetAdvWidth : return static_cast<uint16>(m_advance.x);
+        case kgmetAdvHeight : return static_cast<uint16>(m_advance.y);
+        default : return 0;
+    }
+}
new file mode 100644
--- /dev/null
+++ b/gfx/graphite2/src/GlyphFace.h
@@ -0,0 +1,100 @@
+/*  GRAPHITE2 LICENSING
+
+    Copyright 2010, SIL International
+    All rights reserved.
+
+    This library is free software; you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published
+    by the Free Software Foundation; either version 2.1 of License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should also have received a copy of the GNU Lesser General Public
+    License along with this library in the file named "LICENSE".
+    If not, write to the Free Software Foundation, 51 Franklin Street, 
+    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the 
+    internet at http://www.fsf.org/licenses/lgpl.html.
+
+Alternatively, the contents of this file may be used under the terms of the
+Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
+License, as published by the Free Software Foundation, either version 2
+of the License or (at your option) any later version.
+*/
+#pragma once
+
+#include "Main.h"
+#include "XmlTraceLog.h"
+#include "Main.h"
+#include "Position.h"
+#include "Sparse.h"
+
+namespace graphite2 {
+
+enum metrics {
+    kgmetLsb = 0, kgmetRsb,
+    kgmetBbTop, kgmetBbBottom, kgmetBbLeft, kgmetBbRight,
+    kgmetBbHeight, kgmetBbWidth,
+    kgmetAdvWidth, kgmetAdvHeight,
+    kgmetAscent, kgmetDescent
+};
+
+class Rect
+{
+public :
+    Rect() {}
+    Rect(const Position& botLeft, const Position& topRight): bl(botLeft), tr(topRight) {}
+    Rect widen(const Rect& other) { return Rect(Position(bl.x > other.bl.x ? other.bl.x : bl.x, bl.y > other.bl.y ? other.bl.y : bl.y), Position(tr.x > other.tr.x ? tr.x : other.tr.x, tr.y > other.tr.y ? tr.y : other.tr.y)); }
+    Rect operator + (const Position &a) const { return Rect(Position(bl.x + a.x, bl.y + a.y), Position(tr.x + a.x, tr.y + a.y)); }
+    Rect operator * (float m) const { return Rect(Position(bl.x, bl.y) * m, Position(tr.x, tr.y) * m); }
+
+    Position bl;
+    Position tr;
+};
+
+class XmlTraceLog;
+class GlyphFaceCacheHeader;
+
+class GlyphFace
+{
+private:
+friend class GlyphFaceCache;
+    GlyphFace(const GlyphFaceCacheHeader& hdr, unsigned short glyphid);
+    ~GlyphFace() throw();
+
+public:
+
+    const Position    & theAdvance() const;
+    const Rect &theBBox() const { return m_bbox; }
+    uint16  getAttr(uint8 index) const { 
+        if (m_attrs)
+            return m_attrs[index];
+#ifdef ENABLE_DEEP_TRACING
+        XmlTraceLog::get().warning("No attributes for glyph attr %d", index);
+#endif
+        return 0;
+    }
+    uint16  getMetric(uint8 metric) const;
+
+private:
+//    static void readAttrs(const byte *glat, const byte * const glat_end, uint16 * attrs, size_t num, uint32 format);       //only called from constructor
+    static void logAttr(const uint16 attrs[], const uint16 * attr);
+
+private:
+    Rect     m_bbox;        // bounding box metrics in design units
+    Position m_advance;     // Advance width and height in design units
+    sparse   m_attrs;
+};
+
+
+inline GlyphFace::~GlyphFace() throw() {
+}
+
+inline const Position & GlyphFace::theAdvance() const { 
+    return m_advance;
+}
+
+} // namespace graphite2
new file mode 100644
--- /dev/null
+++ b/gfx/graphite2/src/GlyphFaceCache.cpp
@@ -0,0 +1,147 @@
+/*  GRAPHITE2 LICENSING
+
+    Copyright 2010, SIL International
+    All rights reserved.
+
+    This library is free software; you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published
+    by the Free Software Foundation; either version 2.1 of License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should also have received a copy of the GNU Lesser General Public
+    License along with this library in the file named "LICENSE".
+    If not, write to the Free Software Foundation, 51 Franklin Street, 
+    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the 
+    internet at http://www.fsf.org/licenses/lgpl.html.
+
+Alternatively, the contents of this file may be used under the terms of the
+Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
+License, as published by the Free Software Foundation, either version 2
+of the License or (at your option) any later version.
+*/
+#include "GlyphFaceCache.h"
+#include "graphite2/Font.h"
+#include "Face.h"     //for the tags
+#include "Endian.h"
+
+using namespace graphite2;
+
+/*virtual*/ bool GlyphFaceCacheHeader::initialize(const Face & face, const bool dumb_font)    //return result indicates success. Do not use if failed.
+{
+    if ((m_pLoca = face.getTable(Tag::loca, &m_lLoca)) == NULL) return false;
+    if ((m_pHead = face.getTable(Tag::head)) == NULL) return false;
+    if ((m_pGlyf = face.getTable(Tag::glyf, &m_lGlyf)) == NULL) return false;
+    if ((m_pHmtx = face.getTable(Tag::hmtx, &m_lHmtx)) == NULL) return false;
+    if ((m_pHHea = face.getTable(Tag::hhea)) == NULL) return false;
+
+    const void* pMaxp = face.getTable(Tag::maxp);
+    if (pMaxp == NULL) return false;
+    m_nGlyphs = m_nGlyphsWithGraphics = (unsigned short)TtfUtil::GlyphCount(pMaxp);
+    
+    if (!dumb_font)
+    {
+		if ((m_pGlat = face.getTable(Tag::Glat, &m_lGlat)) == NULL) return false;
+		m_fGlat = be::peek<uint32>(m_pGlat);
+		size_t lGloc;
+		if ((m_pGloc = face.getTable(Tag::Gloc, &lGloc)) == NULL) return false;
+		if (lGloc < 6) return false;
+		int version = be::peek<uint32>(m_pGloc);
+		if (version != 0x00010000) return false;
+
+		m_numAttrs = be::swap<uint16>(((uint16 *)m_pGloc)[3]);
+		if (m_numAttrs > 0x1000) return false;                  // is this hard limit appropriate?
+
+		unsigned short locFlags = be::swap<uint16>(((uint16 *)m_pGloc)[2]);
+		if (locFlags & 1)
+		{
+			m_locFlagsUse32Bit = true;
+			m_nGlyphsWithAttributes = (unsigned short)((lGloc - 12) / 4);
+		}
+		else
+		{
+			m_locFlagsUse32Bit = false;
+			m_nGlyphsWithAttributes = (unsigned short)((lGloc - 10) / 2);
+		}
+
+		if (m_nGlyphsWithAttributes > m_nGlyphs)
+	        m_nGlyphs = m_nGlyphsWithAttributes;
+    }
+
+    return true;
+}
+
+GlyphFaceCache* GlyphFaceCache::makeCache(const GlyphFaceCacheHeader& hdr)
+{
+    return new (hdr) GlyphFaceCache(hdr);
+}
+
+GlyphFaceCache::GlyphFaceCache(const GlyphFaceCacheHeader& hdr)
+:   GlyphFaceCacheHeader(hdr)
+{
+    unsigned int nGlyphs = numGlyphs();
+    
+    for (unsigned int i = 0; i < nGlyphs; i++)
+    {
+         *glyphPtrDirect(i) = NULL;
+    }
+}
+
+GlyphFaceCache::~GlyphFaceCache()
+{
+    unsigned int nGlyphs = numGlyphs();
+    int deltaPointers = (*glyphPtrDirect(nGlyphs-1u) - *glyphPtrDirect(0u));
+    if ((nGlyphs > 0u) && (deltaPointers == static_cast<int>(nGlyphs - 1)))
+    {
+        for (unsigned int i=0 ; i<nGlyphs; ++i)
+        {
+            GlyphFace *p = *glyphPtrDirect(i);
+            assert (p);
+            p->~GlyphFace();
+        }
+        free (*glyphPtrDirect(0));
+    }
+    else
+    {
+        for (unsigned int i=0 ; i<nGlyphs; ++i)
+        {
+            GlyphFace *p = *glyphPtrDirect(i);
+            if (p)
+            {
+                p->~GlyphFace();
+                free(p);
+            }
+        }
+    }
+}
+
+void GlyphFaceCache::loadAllGlyphs()
+{
+    unsigned int nGlyphs = numGlyphs();
+//    size_t sparse_size = 0;
+    GlyphFace * glyphs = gralloc<GlyphFace>(nGlyphs);
+    for (unsigned short glyphid = 0; glyphid < nGlyphs; glyphid++)
+    {
+        GlyphFace **p = glyphPtrDirect(glyphid);
+        *p = &(glyphs[glyphid]);
+        new(*p) GlyphFace(*this, glyphid);
+//        sparse_size += (*p)->m_attrs._sizeof();
+    }
+//    const size_t flat_size = nGlyphs*(sizeof(uint16*) + sizeof(uint16)*numAttrs());
+//    assert(sparse_size <= flat_size);
+}
+
+/*virtual*/ const GlyphFace *GlyphFaceCache::glyph(unsigned short glyphid) const      //result may be changed by subsequent call with a different glyphid
+{ 
+    GlyphFace **p = glyphPtrDirect(glyphid);
+    if (*p)
+        return *p;
+
+    *p = (GlyphFace*)malloc(sizeof(GlyphFace));
+    new(*p) GlyphFace(*this, glyphid);
+    return *p;
+}
new file mode 100644
--- /dev/null
+++ b/gfx/graphite2/src/GlyphFaceCache.h
@@ -0,0 +1,103 @@
+/*  GRAPHITE2 LICENSING
+
+    Copyright 2010, SIL International
+    All rights reserved.
+
+    This library is free software; you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published
+    by the Free Software Foundation; either version 2.1 of License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should also have received a copy of the GNU Lesser General Public
+    License along with this library in the file named "LICENSE".
+    If not, write to the Free Software Foundation, 51 Franklin Street, 
+    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the 
+    internet at http://www.fsf.org/licenses/lgpl.html.
+
+Alternatively, the contents of this file may be used under the terms of the
+Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
+License, as published by the Free Software Foundation, either version 2
+of the License or (at your option) any later version.
+*/
+#pragma once
+
+#include "GlyphFace.h"
+#include "graphite2/Font.h"
+
+namespace graphite2 {
+
+class Segment;
+class Face;
+class FeatureVal;
+
+
+class GlyphFaceCacheHeader
+{
+public:
+    bool initialize(const Face & face, const bool dumb_font);    //return result indicates success. Do not use if failed.
+    unsigned short numGlyphs() const { return m_nGlyphs; }
+    unsigned short numAttrs() const { return m_numAttrs; }
+
+private:
+friend class Face;
+friend class GlyphFace;
+    const byte* m_pHead,
+    		  * m_pHHea,
+    		  * m_pHmtx,
+    		  * m_pGlat,
+    		  * m_pGloc,
+    		  * m_pGlyf,
+    		  * m_pLoca;
+    size_t		m_lHmtx,
+    			m_lGlat,
+    			m_lGlyf,
+    			m_lLoca;
+
+    uint32			m_fGlat;
+    unsigned short 	m_numAttrs,					// number of glyph attributes per glyph
+    				m_nGlyphsWithGraphics,		//i.e. boundary box and advance
+    				m_nGlyphsWithAttributes,
+    				m_nGlyphs;					// number of glyphs in the font. Max of the above 2.
+    bool 			m_locFlagsUse32Bit;
+};
+
+class GlyphFaceCache : public GlyphFaceCacheHeader
+{
+public:
+    static GlyphFaceCache* makeCache(const GlyphFaceCacheHeader& hdr /*, EGlyphCacheStrategy requested */);
+
+    GlyphFaceCache(const GlyphFaceCacheHeader& hdr);
+    ~GlyphFaceCache();
+
+    const GlyphFace *glyphSafe(unsigned short glyphid) const { return glyphid<numGlyphs()?glyph(glyphid):NULL; }
+    uint16 glyphAttr(uint16 gid, uint8 gattr) const { if (gattr>=numAttrs()) return 0; const GlyphFace*p=glyphSafe(gid); return p?p->getAttr(gattr):0; }
+
+    void * operator new (size_t s, const GlyphFaceCacheHeader& hdr)
+    {
+        return malloc(s + sizeof(GlyphFace*)*hdr.numGlyphs());
+    }
+    // delete in case an exception is thrown in constructor
+    void operator delete(void* p, const GlyphFaceCacheHeader& ) throw()
+    {
+        free(p);
+    }
+
+    const GlyphFace *glyph(unsigned short glyphid) const;      //result may be changed by subsequent call with a different glyphid
+    void loadAllGlyphs();
+
+    CLASS_NEW_DELETE
+    
+private:
+    GlyphFace **glyphPtrDirect(unsigned short glyphid) const { return (GlyphFace **)((const char*)(this)+sizeof(GlyphFaceCache)+sizeof(GlyphFace*)*glyphid);}
+
+private:      //defensive
+    GlyphFaceCache(const GlyphFaceCache&);
+    GlyphFaceCache& operator=(const GlyphFaceCache&);
+};
+
+} // namespace graphite2
new file mode 100644
--- /dev/null
+++ b/gfx/graphite2/src/List.h
@@ -0,0 +1,154 @@
+/*  GRAPHITE2 LICENSING
+
+    Copyright 2010, SIL International
+    All rights reserved.
+
+    This library is free software; you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published
+    by the Free Software Foundation; either version 2.1 of License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should also have received a copy of the GNU Lesser General Public
+    License along with this library in the file named "LICENSE".
+    If not, write to the Free Software Foundation, 51 Franklin Street, 
+    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the 
+    internet at http://www.fsf.org/licenses/lgpl.html.
+
+Alternatively, the contents of this file may be used under the terms of the
+Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
+License, as published by the Free Software Foundation, either version 2
+of the License or (at your option) any later version.
+*/
+
+// designed to have a limited subset of the std::vector api
+#pragma once
+
+#include <cassert>
+#include <cstring>
+#include <cstdlib>
+#include <new>
+
+
+namespace graphite2 {
+
+template <typename T> 
+inline
+ptrdiff_t distance(T* first, T* last) { return last-first; }
+
+
+template <typename T> 
+class Vector
+{
+    T * m_first, *m_last, *m_end;
+public:
+    typedef       T &   reference;
+    typedef const T &   const_reference;
+    typedef       T *   iterator;
+    typedef const T *   const_iterator;
+
+    Vector() : m_first(0), m_last(0), m_end(0) {}
+    Vector(size_t n, const T& value = T())      : m_first(0), m_last(0), m_end(0) { insert(begin(), n, value); }
+    Vector(const Vector<T> &rhs)                : m_first(0), m_last(0), m_end(0) { insert(begin(), rhs.begin(), rhs.end()); }
+    template <typename I> 
+    Vector(I first, const I last)               : m_first(0), m_last(0), m_end(0) { insert(begin(), first, last); }
+    ~Vector() { clear(); free(m_first); }
+    
+    iterator            begin()         { return m_first; }
+    const_iterator      begin() const   { return m_first; }
+
+    iterator            end()           { return m_last; }
+    const_iterator      end() const     { return m_last; }
+    
+    bool                empty() const   { return m_first == m_last; }
+    size_t              size() const    { return m_last - m_first; }
+    size_t              capacity() const{ return m_end - m_first; }
+    
+    void                reserve(size_t n);
+    
+    reference           front()         { assert(size() > 0); return *begin(); }
+    const_reference     front() const   { assert(size() > 0); return *begin(); }
+    reference           back()          { assert(size() > 0); return *(end()-1); }
+    const_reference     back() const    { assert(size() > 0); return *(end()-1); }
+    
+    Vector<T>         & operator = (const Vector<T> & rhs) { assign(rhs.begin(), rhs.end()); return *this; }
+    reference           operator [] (size_t n)          { assert(size() > n); return m_first[n]; }
+    const_reference     operator [] (size_t n) const    { assert(size() > n); return m_first[n]; }
+    
+    void                assign(size_t n, const T& u)    { clear(); insert(begin(), n, u); }
+    void                assign(const_iterator first, const_iterator last)      { clear(); insert(begin(), first, last); }
+    iterator            insert(iterator p, const T & x) { p = _insert_default(p, 1); *p = x; return p; }
+    void                insert(iterator p, size_t n, const T & x);
+    void                insert(iterator p, const_iterator first, const_iterator last);
+    void                pop_back()              { assert(size() > 0); --m_last; }
+    void                push_back(const T &v)   { if (m_last == m_end) reserve(size()+1); new (m_last++) T(v); }
+
+    void                clear()                 { erase(begin(), end()); }
+    iterator            erase(iterator p)       { return erase(p, p+1); }
+    iterator            erase(iterator first, iterator last);
+
+private:
+    iterator            _insert_default(iterator p, size_t n);
+};
+    
+template <typename T>
+inline 
+void Vector<T>::reserve(size_t n)
+{
+    if (n > capacity()) 
+    {
+        const ptrdiff_t sz = size();
+        m_first = static_cast<T*>(realloc(m_first, n*sizeof(T)));
+        m_last  = m_first + sz;
+        m_end   = m_first + n;
+    }
+}
+
+template<typename T> 
+inline 
+typename Vector<T>::iterator Vector<T>::_insert_default(iterator p, size_t n)
+{
+    assert(begin() <= p && p <= end());
+    const ptrdiff_t i = p - begin();
+    reserve((size() + n + 7) >> 3 << 3);
+    p = begin() + i;
+    // Move tail if there is one
+    if (p != end()) memmove(p + n, p, distance(p,end())*sizeof(T));
+    m_last += n;
+    return p;
+}
+
+template<typename T> 
+inline 
+void Vector<T>::insert(iterator p, size_t n, const T & x)
+{
+    p = _insert_default(p, n);
+    // Copy in elements
+    for (; n; --n, ++p) { new (p) T(x); }
+}
+
+template<typename T>
+inline 
+void Vector<T>::insert(iterator p, const_iterator first, const_iterator last)
+{
+    p = _insert_default(p, distance(first, last));
+    // Copy in elements
+    for (;first != last; ++first, ++p) { new (p) T(*first); }
+}
+
+template<typename T>
+inline
+typename Vector<T>::iterator Vector<T>::erase(iterator first, iterator last)
+{
+    for (iterator e = first; e != last; ++e) e->~T();
+    const size_t sz = distance(first, last);
+    if (m_last != last) memmove(first, last, distance(last,end())*sizeof(T));
+    m_last -= sz;
+    return first;
+}
+
+} // namespace graphite2
new file mode 100644
--- /dev/null
+++ b/gfx/graphite2/src/Machine.h
@@ -0,0 +1,197 @@
+/*  GRAPHITE2 LICENSING
+
+    Copyright 2010, SIL International
+    All rights reserved.
+
+    This library is free software; you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published
+    by the Free Software Foundation; either version 2.1 of License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should also have received a copy of the GNU Lesser General Public
+    License along with this library in the file named "LICENSE".
+    If not, write to the Free Software Foundation, 51 Franklin Street, 
+    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the 
+    internet at http://www.fsf.org/licenses/lgpl.html.
+
+Alternatively, the contents of this file may be used under the terms of the
+Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
+License, as published by the Free Software Foundation, either version 2
+of the License or (at your option) any later version.
+*/
+// This general interpreter interface.
+// Author: Tim Eves
+
+// Build one of direct_machine.cpp or call_machine.cpp to implement this 
+// interface.
+
+#pragma once
+#include <cstring>
+#include <graphite2/Types.h>
+#include "Main.h"
+
+#if defined(__GNUC__)
+#define     HOT             __attribute__((hot))
+#if defined(__x86_64)
+#define     REGPARM(n)      __attribute__((hot, regparm(n)))
+#else
+#define     REGPARM(n)
+#endif
+#else
+#define     HOT
+#define     REGPARM(n)
+#endif
+
+namespace graphite2 {
+
+// Forward declarations
+class Segment;
+class Slot;
+class SlotMap;
+
+
+namespace vm 
+{
+
+
+typedef void * instr;
+typedef Slot * slotref;
+
+enum {VARARGS = 0xff, MAX_NAME_LEN=32};
+
+enum opcode {
+    NOP = 0,
+
+    PUSH_BYTE,      PUSH_BYTEU,     PUSH_SHORT,     PUSH_SHORTU,    PUSH_LONG,
+
+    ADD,            SUB,            MUL,            DIV,
+    MIN_,           MAX_,
+    NEG,
+    TRUNC8,         TRUNC16,
+
+    COND,
+
+    AND,            OR,             NOT,
+    EQUAL,          NOT_EQ,
+    LESS,           GTR,            LESS_EQ,        GTR_EQ,
+
+    NEXT,           NEXT_N,         COPY_NEXT,
+    PUT_GLYPH_8BIT_OBS,              PUT_SUBS_8BIT_OBS,   PUT_COPY,
+    INSERT,         DELETE,
+    ASSOC,
+    CNTXT_ITEM,
+
+    ATTR_SET,       ATTR_ADD,       ATTR_SUB,
+    ATTR_SET_SLOT,
+    IATTR_SET_SLOT,
+    PUSH_SLOT_ATTR,                 PUSH_GLYPH_ATTR_OBS,
+    PUSH_GLYPH_METRIC,              PUSH_FEAT,
+    PUSH_ATT_TO_GATTR_OBS,          PUSH_ATT_TO_GLYPH_METRIC,
+    PUSH_ISLOT_ATTR,
+
+    PUSH_IGLYPH_ATTR,    // not implemented
+
+    POP_RET,                        RET_ZERO,           RET_TRUE,
+    IATTR_SET,                      IATTR_ADD,          IATTR_SUB,
+    PUSH_PROC_STATE,                PUSH_VERSION,
+    PUT_SUBS,                       PUT_SUBS2,          PUT_SUBS3,
+    PUT_GLYPH,                      PUSH_GLYPH_ATTR,    PUSH_ATT_TO_GLYPH_ATTR,
+    MAX_OPCODE,
+    // private opcodes for internal use only, comes after all other on disk opcodes
+    TEMP_COPY = MAX_OPCODE
+};
+
+struct opcode_t 
+{
+    instr           impl[2];
+    uint8           param_sz;
+    char            name[MAX_NAME_LEN];
+};
+
+
+class Machine
+{
+public:
+    typedef int32  stack_t;
+    static size_t const STACK_ORDER  = 10,
+                        STACK_MAX    = 1 << STACK_ORDER,
+                        STACK_GUARD  = 2;
+
+    class Code;
+
+    enum status_t {
+        finished = 0,
+        stack_underflow,
+        stack_not_empty,
+        stack_overflow,
+        slot_offset_out_bounds
+    };
+
+    Machine(SlotMap &) throw();
+    static const opcode_t *   getOpcodeTable() throw();
+
+    CLASS_NEW_DELETE;
+
+    SlotMap   & slotMap() const throw();
+    status_t	status() const throw();
+    operator bool () const throw();
+
+private:
+    void    check_final_stack(const stack_t * const sp);
+    stack_t run(const instr * program, const byte * data,
+                slotref * & map) HOT;
+
+    SlotMap       & _map;
+    stack_t         _stack[STACK_MAX + 2*STACK_GUARD];
+    status_t		_status;
+};
+
+inline Machine::Machine(SlotMap & map) throw()
+: _map(map), _status(finished)
+{
+	memset(_stack, 0, STACK_GUARD);
+}
+
+inline SlotMap& Machine::slotMap() const throw()
+{
+    return _map;
+}
+
+inline Machine::status_t Machine::status() const throw()
+{
+    return _status;
+}
+
+inline void Machine::check_final_stack(const int32 * const sp)
+{
+    stack_t const * const base  = _stack + STACK_GUARD,
+                  * const limit = base + STACK_MAX;
+    if      (sp <  base)    _status = stack_underflow;       // This should be impossible now.
+    else if (sp >= limit)   _status = stack_overflow;        // So should this.
+    else if (sp != base)    _status = stack_not_empty;
+    else                    _status = finished;
+}
+
+} // namespace vm
+} // namespace graphite2
+
+#ifdef ENABLE_DEEP_TRACING
+#define STARTTRACE(name,is) if (XmlTraceLog::get().active()) { \
+                                XmlTraceLog::get().openElement(ElementOpCode); \
+                                XmlTraceLog::get().addAttribute(AttrName, # name); \
+                                XmlTraceLog::get().addAttribute(AttrIndex, unsigned(map - smap.begin())); \
+                            }
+
+#define ENDTRACE            XmlTraceLog::get().closeElement(ElementOpCode)
+#else // ENABLE_DEEP_TRACING
+#define STARTTRACE(name,is)
+#define ENDTRACE
+#endif // ENABLE_DEEP_TRACING
+
+
+
new file mode 100644
--- /dev/null
+++ b/gfx/graphite2/src/Main.h
@@ -0,0 +1,75 @@
+/*  GRAPHITE2 LICENSING
+
+    Copyright 2010, SIL International
+    All rights reserved.
+
+    This library is free software; you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published
+    by the Free Software Foundation; either version 2.1 of License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should also have received a copy of the GNU Lesser General Public
+    License along with this library in the file named "LICENSE".
+    If not, write to the Free Software Foundation, 51 Franklin Street, 
+    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the 
+    internet at http://www.fsf.org/licenses/lgpl.html.
+
+Alternatively, the contents of this file may be used under the terms of the
+Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
+License, as published by the Free Software Foundation, either version 2
+of the License or (at your option) any later version.
+*/
+#pragma once
+
+#include <cstdlib>
+#include "graphite2/Types.h"
+
+#ifdef GR2_CUSTOM_HEADER
+#include GR2_CUSTOM_HEADER
+#endif
+
+namespace graphite2 {
+
+typedef gr_uint8        uint8;
+typedef gr_uint8        byte;
+typedef gr_uint16       uint16;
+typedef gr_uint32       uint32;
+typedef gr_int8         int8;
+typedef gr_int16        int16;
+typedef gr_int32        int32;
+typedef size_t          uintptr;
+
+// typesafe wrapper around malloc for simple types
+// use free(pointer) to deallocate
+template <typename T> T * gralloc(size_t n)
+{
+    return reinterpret_cast<T*>(malloc(sizeof(T) * n));
+}
+
+template <typename T> T * grzeroalloc(size_t n)
+{
+    return reinterpret_cast<T*>(calloc(n, sizeof(T)));
+}
+
+} // namespace graphite2
+
+#define CLASS_NEW_DELETE \
+    void * operator new   (size_t size){ return malloc(size);} \
+    void * operator new   (size_t, void * p) throw() { return p; } \
+    void * operator new[] (size_t size) {return malloc(size);} \
+    void * operator new[] (size_t, void * p) throw() { return p; } \
+    void operator delete   (void * p) throw() { free(p);} \
+    void operator delete   (void *, void *) throw() {} \
+    void operator delete[] (void * p)throw() { free(p); } \
+    void operator delete[] (void *, void *) throw() {}
+
+#ifdef __GNUC__
+#define GR_MAYBE_UNUSED __attribute__((unused))
+#else
+#define GR_MAYBE_UNUSED
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/graphite2/src/NameTable.cpp
@@ -0,0 +1,223 @@
+/*  GRAPHITE2 LICENSING
+
+    Copyright 2010, SIL International
+    All rights reserved.
+
+    This library is free software; you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published
+    by the Free Software Foundation; either version 2.1 of License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should also have received a copy of the GNU Lesser General Public
+    License along with this library in the file named "LICENSE".
+    If not, write to the Free Software Foundation, 51 Franklin Street,
+    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
+    internet at http://www.fsf.org/licenses/lgpl.html.
+
+Alternatively, the contents of this file may be used under the terms of the
+Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
+License, as published by the Free Software Foundation, either version 2
+of the License or (at your option) any later version.
+*/
+#include "Main.h"
+#include "Endian.h"
+
+#include "NameTable.h"
+#include "UtfCodec.h"
+
+using namespace graphite2;
+
+NameTable::NameTable(const void* data, size_t length, uint16 platformId, uint16 encodingID)
+    :
+    m_platformId(0), m_encodingId(0), m_languageCount(0),
+    m_platformOffset(0), m_platformLastRecord(0), m_nameDataLength(0),
+    m_table(0), m_nameData(NULL)
+{
+    void *pdata = malloc(length);
+    if (!pdata) return;
+    memcpy(pdata, data, length);
+    m_table = reinterpret_cast<const TtfUtil::Sfnt::FontNames*>(pdata);
+
+    if ((length > sizeof(TtfUtil::Sfnt::FontNames)) &&
+        (length > sizeof(TtfUtil::Sfnt::FontNames) +
+         sizeof(TtfUtil::Sfnt::NameRecord) * ( be::swap<uint16>(m_table->count) - 1)))
+    {
+        uint16 offset = be::swap<uint16>(m_table->string_offset);
+        m_nameData = reinterpret_cast<const uint8*>(pdata) + offset;
+        setPlatformEncoding(platformId, encodingID);
+        m_nameDataLength = length - offset;
+    }
+    else
+    {
+        free(const_cast<TtfUtil::Sfnt::FontNames*>(m_table));
+        m_table = NULL;
+    }
+}
+
+uint16 NameTable::setPlatformEncoding(uint16 platformId, uint16 encodingID)
+{
+    if (!m_nameData) return 0;
+    uint16 i = 0;
+    uint16 count = be::swap<uint16>(m_table->count);
+    for (; i < count; i++)
+    {
+        if (be::swap<uint16>(m_table->name_record[i].platform_id) == platformId &&
+            be::swap<uint16>(m_table->name_record[i].platform_specific_id) == encodingID)
+        {
+            m_platformOffset = i;
+            break;
+        }
+    }
+    while ((++i < count) &&
+           (be::swap<uint16>(m_table->name_record[i].platform_id) == platformId) &&
+           (be::swap<uint16>(m_table->name_record[i].platform_specific_id) == encodingID))
+    {
+        m_platformLastRecord = i;
+    }
+    m_encodingId = encodingID;
+    m_platformId = platformId;
+    return 0;
+}
+
+void* NameTable::getName(uint16& languageId, uint16 nameId, gr_encform enc, uint32& length)
+{
+    uint16 anyLang = 0;
+    uint16 enUSLang = 0;
+    uint16 bestLang = 0;
+    if (!m_table)
+    {
+        languageId = 0;
+        length = 0;
+        return NULL;
+    }
+    for (uint16 i = m_platformOffset; i <= m_platformLastRecord; i++)
+    {
+        if (be::swap<uint16>(m_table->name_record[i].name_id) == nameId)
+        {
+            uint16 langId = be::swap<uint16>(m_table->name_record[i].language_id);
+            if (langId == languageId)
+            {
+                bestLang = i;
+                break;
+            }
+            // MS language tags have the language in the lower byte, region in the higher
+            else if ((langId & 0xFF) == (languageId & 0xFF))
+            {
+                bestLang = i;
+            }
+            else if (langId == 0x409)
+            {
+                enUSLang = i;
+            }
+            else
+            {
+                anyLang = i;
+            }
+        }
+    }
+    if (!bestLang)
+    {
+        if (enUSLang) bestLang = enUSLang;
+        else
+        {
+            bestLang = anyLang;
+            if (!anyLang)
+            {
+                languageId = 0;
+                length = 0;
+                return NULL;
+            }
+        }
+    }
+    const TtfUtil::Sfnt::NameRecord & nameRecord = m_table->name_record[bestLang];
+    languageId = be::swap<uint16>(nameRecord.language_id);
+    uint16 utf16Length = be::swap<uint16>(nameRecord.length);
+    uint16 offset = be::swap<uint16>(nameRecord.offset);
+    if(offset + utf16Length > m_nameDataLength)
+    {
+        languageId = 0;
+        length = 0;
+        return NULL;
+    }
+    utf16Length >>= 1; // in utf16 units
+    utf16::codeunit_t * utf16Name = gralloc<utf16::codeunit_t>(utf16Length);
+    const uint8* pName = m_nameData + offset;
+    for (size_t i = 0; i < utf16Length; i++)
+    {
+        utf16Name[i] = be::read<uint16>(pName);
+    }
+    switch (enc)
+    {
+    case gr_utf8:
+    {
+    	utf8::codeunit_t* uniBuffer = gralloc<utf8::codeunit_t>(3 * utf16Length + 1);
+        utf8::iterator d = uniBuffer;
+        for (utf16::const_iterator s = utf16Name, e = utf16Name + utf16Length; s != e; ++s, ++d)
+        	*d = *s;
+        length = d - uniBuffer;
+        uniBuffer[length] = 0;
+        return uniBuffer;
+    }
+    case gr_utf16:
+    	length = utf16Length;
+    	return utf16Name;
+    case gr_utf32:
+    {
+    	utf32::codeunit_t * uniBuffer = gralloc<utf32::codeunit_t>(utf16Length  + 1);
+		utf32::iterator d = uniBuffer;
+		for (utf16::const_iterator s = utf16Name, e = utf16Name + utf16Length; s != e; ++s, ++d)
+			*d = *s;
+		length = d - uniBuffer;
+		uniBuffer[length] = 0;
+		return uniBuffer;
+    }
+    }
+    length = 0;
+    return NULL;
+}
+
+uint16 NameTable::getLanguageId(const char * bcp47Locale)
+{
+    size_t localeLength = strlen(bcp47Locale);
+    uint16 localeId = m_locale2Lang.getMsId(bcp47Locale);
+    if (m_table && (be::swap<uint16>(m_table->format) == 1))
+    {
+        const uint8 * pLangEntries = reinterpret_cast<const uint8*>(m_table) +
+            sizeof(TtfUtil::Sfnt::FontNames)
+            + sizeof(TtfUtil::Sfnt::NameRecord) * ( be::swap<uint16>(m_table->count) - 1);
+        uint16 numLangEntries = be::read<uint16>(pLangEntries);
+        const TtfUtil::Sfnt::LangTagRecord * langTag =
+            reinterpret_cast<const TtfUtil::Sfnt::LangTagRecord*>(pLangEntries);
+        if (pLangEntries + numLangEntries * sizeof(TtfUtil::Sfnt::LangTagRecord) <= m_nameData)
+        {
+            for (uint16 i = 0; i < numLangEntries; i++)
+            {
+                uint16 offset = be::swap<uint16>(langTag[i].offset);
+                uint16 length = be::swap<uint16>(langTag[i].length);
+                if ((offset + length <= m_nameDataLength) && (length == 2 * localeLength))
+                {
+                    const uint8* pName = m_nameData + offset;
+                    bool match = true;
+                    for (size_t j = 0; j < localeLength; j++)
+                    {
+                        uint16 code = be::read<uint16>(pName);
+                        if ((code > 0x7F) || (code != bcp47Locale[j]))
+                        {
+                            match = false;
+                            break;
+                        }
+                    }
+                    if (match)
+                        return 0x8000 + i;
+                }
+            }
+        }
+    }
+    return localeId;
+}
+
new file mode 100644
--- /dev/null
+++ b/gfx/graphite2/src/NameTable.h
@@ -0,0 +1,62 @@
+/*  GRAPHITE2 LICENSING
+
+    Copyright 2010, SIL International
+    All rights reserved.
+
+    This library is free software; you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published
+    by the Free Software Foundation; either version 2.1 of License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should also have received a copy of the GNU Lesser General Public
+    License along with this library in the file named "LICENSE".
+    If not, write to the Free Software Foundation, 51 Franklin Street,
+    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
+    internet at http://www.fsf.org/licenses/lgpl.html.
+
+Alternatively, the contents of this file may be used under the terms of the
+Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
+License, as published by the Free Software Foundation, either version 2
+of the License or (at your option) any later version.
+*/
+#pragma once
+
+#include <graphite2/Segment.h>
+#include "TtfTypes.h"
+#include "locale2lcid.h"
+
+namespace graphite2 {
+
+class NameTable
+{
+public:
+    NameTable(const void * data, size_t length, uint16 platfromId=3, uint16 encodingID = 1);
+    ~NameTable() { free(const_cast<TtfUtil::Sfnt::FontNames *>(m_table)); }
+    enum eNameFallback {
+        eNoFallback = 0,
+        eEnUSFallbackOnly = 1,
+        eEnOrAnyFallback = 2
+    };
+    uint16 setPlatformEncoding(uint16 platfromId=3, uint16 encodingID = 1);
+    void * getName(uint16 & languageId, uint16 nameId, gr_encform enc, uint32 & length);
+    uint16 getLanguageId(const char * bcp47Locale);
+
+    CLASS_NEW_DELETE
+private:
+    uint16 m_platformId;
+    uint16 m_encodingId;
+    uint16 m_languageCount;
+    uint16 m_platformOffset; // offset of first NameRecord with for platform 3, encoding 1
+    uint16 m_platformLastRecord;
+    uint16 m_nameDataLength;
+    const TtfUtil::Sfnt::FontNames * m_table;
+    const uint8 * m_nameData;
+    Locale2Lang m_locale2Lang;
+};
+
+} // namespace graphite2
new file mode 100644
--- /dev/null
+++ b/gfx/graphite2/src/Pass.cpp
@@ -0,0 +1,608 @@
+/*  GRAPHITE2 LICENSING
+
+    Copyright 2010, SIL International
+    All rights reserved.
+
+    This library is free software; you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published
+    by the Free Software Foundation; either version 2.1 of License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should also have received a copy of the GNU Lesser General Public
+    License along with this library in the file named "LICENSE".
+    If not, write to the Free Software Foundation, 51 Franklin Street,
+    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
+    internet at http://www.fsf.org/licenses/lgpl.html.
+
+Alternatively, the contents of this file may be used under the terms of the
+Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
+License, as published by the Free Software Foundation, either version 2
+of the License or (at your option) any later version.
+*/
+#include "Main.h"
+#include "Endian.h"
+#include "Pass.h"
+#include <cstring>
+#include <cstdlib>
+#include <cassert>
+#include "Segment.h"
+#include "Code.h"
+#include "Rule.h"
+#include "XmlTraceLog.h"
+
+using namespace graphite2;
+using vm::Machine;
+typedef Machine::Code  Code;
+
+
+Pass::Pass()
+        :
+        m_silf(0),
+        m_cols(0),
+        m_rules(0),
+        m_ruleMap(0),
+        m_startStates(0),
+        m_sTable(0),
+        m_states(0)
+{
+}
+
+Pass::~Pass()
+{
+    free(m_cols);
+    free(m_startStates);
+    free(m_sTable);
+    free(m_states);
+    free(m_ruleMap);
+
+    delete [] m_rules;
+}
+
+bool Pass::readPass(void *pass, size_t pass_length, size_t subtable_base, const Face & face)
+{
+    const byte *                p = reinterpret_cast<const byte *>(pass),
+               * const pass_start = p,
+               * const pass_end   = p + pass_length;
+    size_t numRanges;
+
+    if (pass_length < 40) return false; 
+    // Read in basic values
+    m_immutable = (*p++) & 0x1U;
+    m_iMaxLoop = *p++;
+    p++; // skip maxContext
+    p += sizeof(byte);     // skip maxBackup
+    m_numRules = be::read<uint16>(p);
+    p += sizeof(uint16);   // not sure why we would want this
+    const byte * const pcCode = pass_start + be::read<uint32>(p) - subtable_base,
+               * const rcCode = pass_start + be::read<uint32>(p) - subtable_base,
+               * const aCode  = pass_start + be::read<uint32>(p) - subtable_base;
+    p += sizeof(uint32);
+    m_sRows = be::read<uint16>(p);
+    m_sTransition = be::read<uint16>(p);
+    m_sSuccess = be::read<uint16>(p);
+    m_sColumns = be::read<uint16>(p);
+    numRanges = be::read<uint16>(p);
+    p += sizeof(uint16)   // skip searchRange
+         +  sizeof(uint16)   // skip entrySelector
+         +  sizeof(uint16);  // skip rangeShift
+#ifndef DISABLE_TRACING
+    XmlTraceLog::get().addAttribute(AttrFlags,          m_immutable);
+    XmlTraceLog::get().addAttribute(AttrMaxRuleLoop,    m_iMaxLoop);
+    XmlTraceLog::get().addAttribute(AttrNumRules,       m_numRules);
+    XmlTraceLog::get().addAttribute(AttrNumRows,        m_sRows);
+    XmlTraceLog::get().addAttribute(AttrNumTransition,  m_sTransition);
+    XmlTraceLog::get().addAttribute(AttrNumSuccess,     m_sSuccess);
+    XmlTraceLog::get().addAttribute(AttrNumColumns,     m_sColumns);
+    XmlTraceLog::get().addAttribute(AttrNumRanges,      numRanges);
+#endif
+    assert(p - pass_start == 40);
+    // Perform some sanity checks.
+    if (   m_sTransition > m_sRows
+            || m_sSuccess > m_sRows
+            || m_sSuccess + m_sTransition < m_sRows)
+        return false;
+
+    if (p + numRanges * 6 - 4 > pass_end) return false;
+    m_numGlyphs = be::swap<uint16>(*(uint16 *)(p + numRanges * 6 - 4)) + 1;
+    // Caculate the start of vairous arrays.
+    const uint16 * const ranges = reinterpret_cast<const uint16 *>(p);
+    p += numRanges*sizeof(uint16)*3;
+    const uint16 * const o_rule_map = reinterpret_cast<const uint16 *>(p);
+    p += (m_sSuccess + 1)*sizeof(uint16);
+
+    // More sanity checks
+    if (   reinterpret_cast<const byte *>(o_rule_map) > pass_end
+            || p > pass_end)
+        return false;
+    const size_t numEntries = be::swap<uint16>(o_rule_map[m_sSuccess]);
+    const uint16 * const   rule_map = reinterpret_cast<const uint16 *>(p);
+    p += numEntries*sizeof(uint16);
+
+    if (p > pass_end) return false;
+    m_minPreCtxt = *p++;
+    m_maxPreCtxt = *p++;
+    const int16 * const start_states = reinterpret_cast<const int16 *>(p);
+    p += (m_maxPreCtxt - m_minPreCtxt + 1)*sizeof(int16);
+    const uint16 * const sort_keys = reinterpret_cast<const uint16 *>(p);
+    p += m_numRules*sizeof(uint16);
+    const byte * const precontext = p;
+    p += m_numRules;
+    p += sizeof(byte);     // skip reserved byte
+
+    if (p > pass_end) return false;
+    const size_t pass_constraint_len = be::read<uint16>(p);
+    const uint16 * const o_constraint = reinterpret_cast<const uint16 *>(p);
+    p += (m_numRules + 1)*sizeof(uint16);
+    const uint16 * const o_actions = reinterpret_cast<const uint16 *>(p);
+    p += (m_numRules + 1)*sizeof(uint16);
+    const int16 * const states = reinterpret_cast<const int16 *>(p);
+    p += m_sTransition*m_sColumns*sizeof(int16);
+    p += sizeof(byte);          // skip reserved byte
+    if (p != pcCode || p >= pass_end) return false;
+    p += pass_constraint_len;
+    if (p != rcCode || p >= pass_end) return false;
+    p += be::swap<uint16>(o_constraint[m_numRules]);
+    if (p != aCode || p >= pass_end) return false;
+    if (size_t(rcCode - pcCode) != pass_constraint_len) return false;
+
+    // Load the pass constraint if there is one.
+    if (pass_constraint_len)
+    {
+        m_cPConstraint = vm::Machine::Code(true, pcCode, pcCode + pass_constraint_len, 
+                                  precontext[0], be::swap<uint16>(sort_keys[0]), *m_silf, face);
+        if (!m_cPConstraint) return false;
+    }
+    if (!readRanges(ranges, numRanges)) return false;
+    if (!readRules(rule_map, numEntries,  precontext, sort_keys,
+                   o_constraint, rcCode, o_actions, aCode, face)) return false;
+    return readStates(start_states, states, o_rule_map);
+}
+
+
+bool Pass::readRules(const uint16 * rule_map, const size_t num_entries,
+                     const byte *precontext, const uint16 * sort_key,
+                     const uint16 * o_constraint, const byte *rc_data,
+                     const uint16 * o_action,     const byte * ac_data,
+                     const Face & face)
+{
+    const byte * const ac_data_end = ac_data + be::swap<uint16>(o_action[m_numRules]);
+    const byte * const rc_data_end = rc_data + be::swap<uint16>(o_constraint[m_numRules]);
+
+    if (!(m_rules = new Rule [m_numRules])) return false;
+    precontext += m_numRules;
+    sort_key   += m_numRules;
+    o_constraint += m_numRules;
+    o_action += m_numRules;
+
+    // Load rules.
+    const byte * ac_begin = 0, * rc_begin = 0,
+               * ac_end = ac_data + be::swap<uint16>(*o_action),
+               * rc_end = rc_data + be::swap<uint16>(*o_constraint);
+    Rule * r = m_rules + m_numRules - 1;
+    for (size_t n = m_numRules; n; --n, --r, ac_end = ac_begin, rc_end = rc_begin)
+    {
+        r->preContext = *--precontext;
+        r->sort       = be::swap<uint16>(*--sort_key);
+#ifndef NDEBUG
+        r->rule_idx   = n - 1;
+#endif
+        if (r->sort > 63 || r->preContext >= r->sort || r->preContext > m_maxPreCtxt || r->preContext < m_minPreCtxt)
+            return false;
+        ac_begin      = ac_data + be::swap<uint16>(*--o_action);
+        rc_begin      = *--o_constraint ? rc_data + be::swap<uint16>(*o_constraint) : rc_end;
+
+        if (ac_begin > ac_end || ac_begin > ac_data_end || ac_end > ac_data_end
+                || rc_begin > rc_end || rc_begin > rc_data_end || rc_end > rc_data_end)
+            return false;
+        r->action     = new vm::Machine::Code(false, ac_begin, ac_end, r->preContext, r->sort, *m_silf, face);
+        r->constraint = new vm::Machine::Code(true,  rc_begin, rc_end, r->preContext, r->sort, *m_silf, face);
+
+        if (!r->action || !r->constraint
+                || r->action->status() != Code::loaded
+                || r->constraint->status() != Code::loaded
+                || !r->constraint->immutable())
+            return false;
+
+        logRule(r, sort_key);
+    }
+
+    // Load the rule entries map
+    RuleEntry * re = m_ruleMap = gralloc<RuleEntry>(num_entries);
+    for (size_t n = num_entries; n; --n, ++re)
+    {
+        const ptrdiff_t rn = be::swap<uint16>(*rule_map++);
+        if (rn >= m_numRules)  return false;
+        re->rule = m_rules + rn;
+    }
+
+    return true;
+}
+
+static int cmpRuleEntry(const void *a, const void *b) { return (*(RuleEntry *)a < *(RuleEntry *)b ? -1 :
+                                                                (*(RuleEntry *)b < *(RuleEntry *)a ? 1 : 0)); }
+
+bool Pass::readStates(const int16 * starts, const int16 *states, const uint16 * o_rule_map)
+{
+    m_startStates = gralloc<State *>(m_maxPreCtxt - m_minPreCtxt + 1);
+    m_states      = gralloc<State>(m_sRows);
+    m_sTable      = gralloc<State *>(m_sTransition * m_sColumns);
+
+    if (!m_startStates || !m_states || !m_sTable) return false;
+    // load start states
+    for (State * * s = m_startStates,
+            * * const s_end = s + m_maxPreCtxt - m_minPreCtxt + 1; s != s_end; ++s)
+    {
+        *s = m_states + be::swap<uint16>(*starts++);
+        if (*s < m_states || *s >= m_states + m_sRows) return false; // true;
+    }
+
+    // load state transition table.
+    for (State * * t = m_sTable,
+               * * const t_end = t + m_sTransition*m_sColumns; t != t_end; ++t)
+    {
+        *t = m_states + be::swap<uint16>(*states++);
+        if (*t < m_states || *t >= m_states + m_sRows) return false;
+    }
+
+    State * s = m_states,
+          * const transitions_end = m_states + m_sTransition,
+          * const success_begin = m_states + m_sRows - m_sSuccess;
+    const RuleEntry * rule_map_end = m_ruleMap + be::swap<uint16>(o_rule_map[m_sSuccess]);
+    for (size_t n = m_sRows; n; --n, ++s)
+    {
+        s->transitions = s < transitions_end ? m_sTable + (s-m_states)*m_sColumns : 0;
+        RuleEntry * const begin = s < success_begin ? 0 : m_ruleMap + be::swap<uint16>(*o_rule_map++),
+                  * const end   = s < success_begin ? 0 : m_ruleMap + be::swap<uint16>(*o_rule_map);
+
+        if (begin >= rule_map_end || end > rule_map_end || begin > end)
+            return false;
+#ifndef NDEBUG
+        s->index = (s - m_states);
+#endif
+        s->rules = begin;
+        s->rules_end = (end - begin <= FiniteStateMachine::MAX_RULES)? end :
+            begin + FiniteStateMachine::MAX_RULES;
+        qsort(begin, end - begin, sizeof(RuleEntry), &cmpRuleEntry);
+    }
+
+    logStates();
+    return true;
+}
+
+
+void Pass::logRule(GR_MAYBE_UNUSED const Rule * r, GR_MAYBE_UNUSED const uint16 * sort_key) const
+{
+#ifndef DISABLE_TRACING
+    if (!XmlTraceLog::get().active()) return;
+
+    const size_t lid = r - m_rules;
+    if (r->constraint)
+    {
+        XmlTraceLog::get().openElement(ElementConstraint);
+        XmlTraceLog::get().addAttribute(AttrIndex, lid);
+        XmlTraceLog::get().closeElement(ElementConstraint);
+    }
+    else
+    {
+        XmlTraceLog::get().openElement(ElementRule);
+        XmlTraceLog::get().addAttribute(AttrIndex, lid);
+        XmlTraceLog::get().addAttribute(AttrSortKey, be::swap<uint16>(sort_key[lid]));
+        XmlTraceLog::get().addAttribute(AttrPrecontext, r->preContext);
+        XmlTraceLog::get().closeElement(ElementRule);
+    }
+#endif
+}
+
+void Pass::logStates() const
+{
+#ifndef DISABLE_TRACING
+    if (XmlTraceLog::get().active())
+    {
+        for (int i = 0; i != (m_maxPreCtxt - m_minPreCtxt + 1); ++i)
+        {
+            XmlTraceLog::get().openElement(ElementStartState);
+            XmlTraceLog::get().addAttribute(AttrContextLen, i + m_minPreCtxt);
+            XmlTraceLog::get().addAttribute(AttrState, size_t(m_startStates[i] - m_states));
+            XmlTraceLog::get().closeElement(ElementStartState);
+        }
+
+        for (uint16 i = 0; i != m_sSuccess; ++i)
+        {
+            XmlTraceLog::get().openElement(ElementRuleMap);
+            XmlTraceLog::get().addAttribute(AttrSuccessId, i);
+            for (const RuleEntry *j = m_states[i].rules, *const j_end = m_states[i].rules_end; j != j_end; ++j)
+            {
+                XmlTraceLog::get().openElement(ElementRule);
+                XmlTraceLog::get().addAttribute(AttrRuleId, size_t(j->rule - m_rules));
+                XmlTraceLog::get().closeElement(ElementRule);
+            }
+            XmlTraceLog::get().closeElement(ElementRuleMap);
+        }
+
+        XmlTraceLog::get().openElement(ElementStateTransitions);
+        for (size_t iRow = 0; iRow < m_sTransition; iRow++)
+        {
+            XmlTraceLog::get().openElement(ElementRow);
+            XmlTraceLog::get().addAttribute(AttrIndex, iRow);
+            const State * const * const row = m_sTable + iRow * m_sColumns;
+            for (int i = 0; i != m_sColumns; ++i)
+            {
+                XmlTraceLog::get().openElement(ElementData);
+                XmlTraceLog::get().addAttribute(AttrIndex, i);
+                XmlTraceLog::get().addAttribute(AttrValue, size_t(row[i] - m_states));
+                XmlTraceLog::get().closeElement(ElementData);
+            }
+            XmlTraceLog::get().closeElement(ElementRow);
+        }
+        XmlTraceLog::get().closeElement(ElementStateTransitions);
+    }
+#endif
+}
+
+bool Pass::readRanges(const uint16 *ranges, size_t num_ranges)
+{
+    m_cols = gralloc<uint16>(m_numGlyphs);
+    memset(m_cols, 0xFF, m_numGlyphs * sizeof(uint16));
+    for (size_t n = num_ranges; n; --n)
+    {
+        const uint16 first = be::swap<uint16>(*ranges++),
+                     last  = be::swap<uint16>(*ranges++),
+                     col   = be::swap<uint16>(*ranges++);
+        uint16 *p;
+
+        if (first > last || last >= m_numGlyphs || col >= m_sColumns)
+            return false;
+
+        for (p = m_cols + first; p <= m_cols + last; )
+            *p++ = col;
+#ifndef DISABLE_TRACING
+        if (XmlTraceLog::get().active())
+        {
+            XmlTraceLog::get().openElement(ElementRange);
+            XmlTraceLog::get().addAttribute(AttrFirstId, first);
+            XmlTraceLog::get().addAttribute(AttrLastId, last);
+            XmlTraceLog::get().addAttribute(AttrColId, col);
+            XmlTraceLog::get().closeElement(ElementRange);
+        }
+#endif
+    }
+    return true;
+}
+
+void Pass::runGraphite(Machine & m, FiniteStateMachine & fsm) const
+{
+    Slot *s = m.slotMap().segment.first();
+    if (!s || !testPassConstraint(m)) return;
+    Slot *currHigh = s->next();
+    
+    m.slotMap().highwater(currHigh);
+    int lc = m_iMaxLoop;
+    do
+    {
+        findNDoRule(s, m, fsm);
+        if (s && (m.slotMap().highpassed() || s == m.slotMap().highwater() || --lc == 0)) {
+        	if (!lc)
+        		s = m.slotMap().highwater();
+        	lc = m_iMaxLoop;
+            if (s)
+            	m.slotMap().highwater(s->next());
+        }
+    } while (s);
+}
+
+inline uint16 Pass::glyphToCol(const uint16 gid) const
+{
+    return gid < m_numGlyphs ? m_cols[gid] : 0xffffU;
+}
+
+bool Pass::runFSM(FiniteStateMachine& fsm, Slot * slot) const
+{
+    int context = 0;
+    for (; context != m_maxPreCtxt && slot->prev(); ++context, slot = slot->prev());
+    if (context < m_minPreCtxt)
+        return false;
+
+    fsm.setContext(context);
+    const State * state = m_startStates[m_maxPreCtxt - context];
+    do
+    {
+        fsm.slots.pushSlot(slot);
+        if (fsm.slots.size() >= SlotMap::MAX_SLOTS) return false;
+        const uint16 col = glyphToCol(slot->gid());
+        if (col == 0xffffU || !state->is_transition()) return true;
+
+        state = state->transitions[col];
+        if (state->is_success())
+            fsm.rules.accumulate_rules(*state);
+
+#ifdef ENABLE_DEEP_TRACING
+        if (col >= m_sColumns && col != 65535)
+        {
+            XmlTraceLog::get().error("Invalid column %d ID %d for slot %d",
+                                     col, slot->gid(), slot);
+        }
+#endif
+
+        slot = slot->next();
+    } while (state != m_states && slot);
+
+    fsm.slots.pushSlot(slot);
+    return true;
+}
+
+void Pass::findNDoRule(Slot * & slot, Machine &m, FiniteStateMachine & fsm) const
+{
+    assert(slot);
+
+    if (runFSM(fsm, slot))
+    {
+        // Search for the first rule which passes the constraint
+        const RuleEntry *        r = fsm.rules.begin(),
+                        * const re = fsm.rules.end();
+        for (; r != re && !testConstraint(*r->rule, m); ++r);
+
+        if (r != re)
+        {
+#ifdef ENABLE_DEEP_TRACING
+            if (XmlTraceLog::get().active())
+            {
+                XmlTraceLog::get().openElement(ElementDoRule);
+                XmlTraceLog::get().addAttribute(AttrNum, size_t(r->rule - m_rules));
+                XmlTraceLog::get().addAttribute(AttrIndex, int(slot - fsm.slots.segment.first()));
+            }
+#endif
+            doAction(r->rule->action, slot, m);
+#ifdef ENABLE_DEEP_TRACING
+            if (XmlTraceLog::get().active())
+            {
+                XmlTraceLog::get().openElement(ElementPassResult);
+                XmlTraceLog::get().addAttribute(AttrResult, int(slot - fsm.slots.segment.first()));
+                const Slot * s = fsm.slots.segment.first();
+                while (s)
+                {
+                    XmlTraceLog::get().openElement(ElementSlot);
+                    XmlTraceLog::get().addAttribute(AttrGlyphId, s->gid());
+                    XmlTraceLog::get().addAttribute(AttrX, s->origin().x);
+                    XmlTraceLog::get().addAttribute(AttrY, s->origin().y);
+                    XmlTraceLog::get().addAttribute(AttrBefore, s->before());
+                    XmlTraceLog::get().addAttribute(AttrAfter, s->after());
+                    XmlTraceLog::get().closeElement(ElementSlot);
+                    s = s->next();
+                }
+                XmlTraceLog::get().closeElement(ElementPassResult);
+                XmlTraceLog::get().closeElement(ElementDoRule);
+            }
+#endif
+            return;
+        }
+    }
+
+    slot = slot->next();
+}
+
+
+inline
+bool Pass::testPassConstraint(Machine & m) const
+{
+    if (!m_cPConstraint) return true;
+
+    assert(m_cPConstraint.constraint());
+
+    vm::slotref * map = m.slotMap().begin();
+    *map = m.slotMap().segment.first();
+    const uint32 ret = m_cPConstraint.run(m, map);
+
+    return ret || m.status() != Machine::finished;
+}
+
+
+bool Pass::testConstraint(const Rule &r, Machine & m) const
+{
+    if (r.sort - r.preContext > (int)m.slotMap().size() - m.slotMap().context())    return false;
+    if (m.slotMap().context() - r.preContext < 0) return false;
+    if (!*r.constraint)                 return true;
+    assert(r.constraint->constraint());
+
+#ifdef ENABLE_DEEP_TRACING
+    if (XmlTraceLog::get().active())
+    {
+        XmlTraceLog::get().openElement(ElementTestRule);
+        XmlTraceLog::get().addAttribute(AttrNum, size_t(&r - m_rules));
+    }
+#endif
+    vm::slotref * map = m.slotMap().begin() + m.slotMap().context() - r.preContext;
+    for (int n = r.sort; n && map; --n, ++map)
+    {
+	if (!*map) continue;
+        const int32 ret = r.constraint->run(m, map);
+        if (!ret || m.status() != Machine::finished)
+        {
+#ifdef ENABLE_DEEP_TRACING
+            if (XmlTraceLog::get().active())
+            {
+                XmlTraceLog::get().closeElement(ElementTestRule);
+            }
+#endif
+            return false;
+        }
+    }
+
+#ifdef ENABLE_DEEP_TRACING
+    if (XmlTraceLog::get().active())
+    {
+        XmlTraceLog::get().closeElement(ElementTestRule);
+    }
+#endif
+
+    return true;
+}
+
+
+void Pass::doAction(const Code *codeptr, Slot * & slot_out, vm::Machine & m) const
+{
+    assert(codeptr);
+    if (!*codeptr) return;
+    SlotMap   & smap = m.slotMap();
+    vm::slotref * map = &smap[smap.context()];
+    smap.highpassed(false);
+
+    Segment & seg = smap.segment;
+    int glyph_diff = -static_cast<int>(seg.slotCount());
+    int32 ret = codeptr->run(m, map);
+    glyph_diff += seg.slotCount();
+    if (codeptr->deletes())
+    {
+        for (Slot **s = smap.begin(), *const * const se = smap.end()-1; s != se; ++s)
+        {
+            Slot * & slot = *s;
+            if (slot->isDeleted() || slot->isCopied())
+            {
+            	if (slot == smap.highwater())
+            		smap.highwater(slot->next());
+            	seg.freeSlot(slot);
+            }
+        }
+    }
+
+    slot_out = *map;
+    if (ret < 0)
+    {
+        if (!slot_out)
+        {
+            slot_out = seg.last();
+            ++ret;
+            if (smap.highpassed() && !smap.highwater())
+            	smap.highpassed(false);
+        }
+        while (++ret <= 0 && slot_out)
+        {
+            slot_out = slot_out->prev();
+            if (smap.highpassed() && smap.highwater() == slot_out)
+            	smap.highpassed(false);
+        }
+    }
+    else if (ret > 0)
+    {
+        if (!slot_out)
+        {
+            slot_out = seg.first();
+            --ret;
+        }
+        while (--ret >= 0 && slot_out)
+        {
+            slot_out = slot_out->next();
+            if (slot_out == smap.highwater() && slot_out)
+                smap.highpassed(true);
+        }
+    }
+    if (m.status() != Machine::finished)
+    {
+    	slot_out = NULL;
+    	m.slotMap().highwater(0);
+    }
+}
new file mode 100644
--- /dev/null
+++ b/gfx/graphite2/src/Pass.h
@@ -0,0 +1,96 @@
+/*  GRAPHITE2 LICENSING
+
+    Copyright 2010, SIL International
+    All rights reserved.
+
+    This library is free software; you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published
+    by the Free Software Foundation; either version 2.1 of License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should also have received a copy of the GNU Lesser General Public
+    License along with this library in the file named "LICENSE".
+    If not, write to the Free Software Foundation, 51 Franklin Street, 
+    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the 
+    internet at http://www.fsf.org/licenses/lgpl.html.
+
+Alternatively, the contents of this file may be used under the terms of the
+Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
+License, as published by the Free Software Foundation, either version 2
+of the License or (at your option) any later version.
+*/
+#pragma once
+
+#include <cstdlib>
+#include "Code.h"
+
+namespace graphite2 {
+
+class Segment;
+class Face;
+class Silf;
+struct Rule;
+struct RuleEntry;
+struct State;
+class FiniteStateMachine;
+
+class Pass
+{   
+public:
+    Pass();
+    ~Pass();
+    
+    bool readPass(void* pPass, size_t pass_length, size_t subtable_base, const Face & face);
+    void runGraphite(vm::Machine & m, FiniteStateMachine & fsm) const;
+    void init(Silf *silf) { m_silf = silf; }
+
+    CLASS_NEW_DELETE
+private:
+    void   findNDoRule(Slot* & iSlot, vm::Machine &, FiniteStateMachine& fsm) const;
+    void   doAction(const vm::Machine::Code* codeptr, Slot * & slot_out, vm::Machine &) const;
+    bool   testPassConstraint(vm::Machine & m) const;
+    bool   testConstraint(const Rule & r, vm::Machine &) const;
+    bool   readFSM(const byte* p, const byte*const pass_start, const size_t max_offset);
+    bool   readRules(const uint16 * rule_map, const size_t num_entries, 
+                     const byte *precontext, const uint16 * sort_key,
+                     const uint16 * o_constraint, const byte *constraint_data, 
+                     const uint16 * o_action, const byte * action_data,
+                     const Face &);
+    void   logRule(const Rule * r, const uint16 * sort_key) const;
+    bool   readStates(const int16 * starts, const int16 * states, const uint16 * o_rule_map);
+    void   logStates() const;
+    bool   readRanges(const uint16* ranges, size_t num_ranges);
+    uint16 glyphToCol(const uint16 gid) const;
+    bool   runFSM(FiniteStateMachine & fsm, Slot * slot) const;
+    
+    const Silf* m_silf;
+    uint16    * m_cols;
+    Rule      * m_rules; // rules
+    RuleEntry * m_ruleMap;
+    State *   * m_startStates; // prectxt length
+    State *   * m_sTable;
+    State     * m_states;
+    
+    bool   m_immutable;
+    byte   m_iMaxLoop;
+    uint16 m_numGlyphs;
+    uint16 m_numRules;
+    uint16 m_sRows;
+    uint16 m_sTransition;
+    uint16 m_sSuccess;
+    uint16 m_sColumns;
+    byte m_minPreCtxt;
+    byte m_maxPreCtxt;
+    vm::Machine::Code m_cPConstraint;
+    
+private:		//defensive
+    Pass(const Pass&);
+    Pass& operator=(const Pass&);
+};
+
+} // namespace graphite2
new file mode 100644
--- /dev/null
+++ b/gfx/graphite2/src/Position.h
@@ -0,0 +1,46 @@
+/*  GRAPHITE2 LICENSING
+
+    Copyright 2010, SIL International
+    All rights reserved.
+
+    This library is free software; you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published
+    by the Free Software Foundation; either version 2.1 of License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should also have received a copy of the GNU Lesser General Public
+    License along with this library in the file named "LICENSE".
+    If not, write to the Free Software Foundation, 51 Franklin Street, 
+    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the 
+    internet at http://www.fsf.org/licenses/lgpl.html.
+
+Alternatively, the contents of this file may be used under the terms of the
+Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
+License, as published by the Free Software Foundation, either version 2
+of the License or (at your option) any later version.
+*/
+#pragma once
+
+namespace graphite2 {
+
+class Position
+{
+public:
+    Position() : x(0), y(0) { }
+    Position(float inx, float iny) { x = inx; y = iny; }
+    Position operator + (const Position& a) const { return Position(x + a.x, y + a.y); }
+    Position operator - (const Position& a) const { return Position(x - a.x, y - a.y); }
+    Position operator * (const float m) const { return Position(x * m, y * m); }
+    Position &operator += (const Position &a) { x += a.x; y += a.y; return *this; }
+    Position &operator *= (const float m) { x *= m; y *= m; return *this; }
+
+    float x;
+    float y;
+};
+
+} // namespace graphite2
new file mode 100644
--- /dev/null
+++ b/gfx/graphite2/src/Rule.cpp
@@ -0,0 +1,29 @@
+/*  GRAPHITE2 LICENSING
+
+    Copyright 2010, SIL International
+    All rights reserved.
+
+    This library is free software; you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published
+    by the Free Software Foundation; either version 2.1 of License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should also have received a copy of the GNU Lesser General Public
+    License along with this library in the file named "LICENSE".
+    If not, write to the Free Software Foundation, 51 Franklin Street, 
+    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the 
+    internet at http://www.fsf.org/licenses/lgpl.html.
+
+Alternatively, the contents of this file may be used under the terms of the
+Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
+License, as published by the Free Software Foundation, either version 2
+of the License or (at your option) any later version.
+*/
+
+#include "Rule.h"
+
new file mode 100644
--- /dev/null
+++ b/gfx/graphite2/src/Rule.h
@@ -0,0 +1,275 @@
+/*  GRAPHITE2 LICENSING
+
+    Copyright 2010, SIL International
+    All rights reserved.
+
+    This library is free software; you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published
+    by the Free Software Foundation; either version 2.1 of License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should also have received a copy of the GNU Lesser General Public
+    License along with this library in the file named "LICENSE".
+    If not, write to the Free Software Foundation, 51 Franklin Street, 
+    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the 
+    internet at http://www.fsf.org/licenses/lgpl.html.
+
+Alternatively, the contents of this file may be used under the terms of the
+Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
+License, as published by the Free Software Foundation, either version 2
+of the License or (at your option) any later version.
+*/
+
+#pragma once
+
+#include "Code.h"
+
+namespace graphite2 {
+
+struct Rule {
+  const vm::Machine::Code * constraint, 
+                 * action;
+  unsigned short   sort;
+  byte             preContext;
+#ifndef NDEBUG
+  uint16           rule_idx;
+#endif
+
+  Rule() : constraint(0), action(0) {}
+  ~Rule();
+
+  CLASS_NEW_DELETE;
+};
+
+inline Rule::~Rule()
+{
+  delete constraint;
+  delete action;
+}
+
+
+struct RuleEntry
+{
+  const Rule   * rule;
+
+  inline bool operator < (const RuleEntry &r) const
+  { 
+    const unsigned short lsort = rule->sort, rsort = r.rule->sort; 
+    return lsort > rsort || (lsort == rsort && rule < r.rule);
+  }
+  
+  inline bool operator == (const RuleEntry &r) const
+  {
+    return rule == r.rule;
+  }
+};
+
+
+struct State
+{
+  const RuleEntry     * rules,
+                      * rules_end;
+  const State * const * transitions;
+  
+  size_t size() const;
+  bool   is_success() const;
+  bool   is_transition() const;
+#ifndef NDEBUG
+    uint32 index;
+#endif
+};
+
+inline size_t State::size() const 
+{
+  return rules_end - rules;
+}
+
+inline bool State::is_success() const
+{
+  return (rules != NULL);
+}
+
+inline bool State::is_transition() const
+{
+  return (transitions != NULL);
+}
+
+
+class SlotMap
+{
+public:
+  enum {MAX_SLOTS=64};
+  SlotMap(Segment & seg);
+  
+  Slot       * * begin();
+  Slot       * * end();
+  size_t         size() const;
+  unsigned short context() const;
+  void           setContext(unsigned short);
+  
+  Slot * const & operator[](int n) const;
+  Slot       * & operator [] (int);
+  void           pushSlot(Slot * const slot);
+  Slot         * highwater() { return m_highwater; }
+  void           highwater(Slot *s) { m_highwater = s; }
+  bool			 highpassed() const { return m_highpassed; }
+  void			 highpassed(bool v) { m_highpassed = v; }
+
+  Segment &    segment;
+private:
+  Slot         * m_slot_map[MAX_SLOTS+1];
+  unsigned short m_size;
+  unsigned short m_precontext;
+  Slot         * m_highwater;
+  bool			 m_highpassed;
+};
+
+
+class FiniteStateMachine
+{
+public:
+  enum {MAX_RULES=128};
+
+private:
+  class Rules
+  {
+  public:
+      Rules();
+      void              clear();
+      const RuleEntry * begin() const;
+      const RuleEntry * end() const;
+      size_t            size() const;
+      
+      void accumulate_rules(const State &state);
+
+  private:
+      RuleEntry * m_begin, 
+                * m_end,
+                  m_rules[MAX_RULES*2];
+  };
+
+public:
+  FiniteStateMachine(SlotMap & map);
+  void      setContext(short unsigned int);
+  Rules     rules;
+  SlotMap   & slots;
+};
+
+inline FiniteStateMachine::FiniteStateMachine(SlotMap& map)
+: slots(map)
+{
+}
+
+inline void FiniteStateMachine::setContext(short unsigned int ctxt)
+{
+  rules.clear();
+  slots.setContext(ctxt);
+}
+
+inline FiniteStateMachine::Rules::Rules()
+  : m_begin(m_rules)
+{
+  m_end = m_begin;
+}
+
+inline void FiniteStateMachine::Rules::clear() 
+{
+  m_end = m_begin;
+}
+
+inline const RuleEntry * FiniteStateMachine::Rules::begin() const
+{
+  return m_begin;
+}
+
+inline const RuleEntry * FiniteStateMachine::Rules::end() const
+{
+  return m_end;
+}
+
+inline size_t FiniteStateMachine::Rules::size() const
+{
+  return m_end - m_begin;
+}
+
+inline void FiniteStateMachine::Rules::accumulate_rules(const State &state)
+{
+  // Only bother if there are rules in the State object.
+  if (state.size() == 0) return;
+  
+  // Merge the new sorted rules list into the current sorted result set.
+  const RuleEntry * lre = begin(), * rre = state.rules;
+  RuleEntry * out = m_rules + (m_begin == m_rules)*MAX_RULES;    
+  const RuleEntry * lrend = out + MAX_RULES;
+  m_begin = out; 
+  while (lre != end() && out != lrend)
+  {
+    if (*lre < *rre)      *out++ = *lre++;
+    else if (*rre < *lre) { *out++ = *rre++; }
+    else                { *out++ = *lre++; ++rre; }
+
+    if (rre == state.rules_end) 
+    { 
+      while (lre != end() && out != lrend) { *out++ = *lre++; }
+      m_end = out;
+      return;
+    }
+  }
+  while (rre != state.rules_end && out != lrend) { *out++ = *rre++; }
+  m_end = out;
+}
+
+inline SlotMap::SlotMap(Segment & seg)
+: segment(seg), m_size(0), m_precontext(0)
+{
+    m_slot_map[0] = 0;
+}
+
+inline Slot * * SlotMap::begin()
+{
+  return &m_slot_map[1]; // allow map to go 1 before slot_map when inserting
+                         // at start of segment.
+}
+
+inline Slot * * SlotMap::end()
+{
+  return m_slot_map + m_size + 1;
+}
+
+inline size_t SlotMap::size() const
+{
+  return m_size;
+}
+
+inline short unsigned int SlotMap::context() const
+{
+  return m_precontext;
+}
+
+inline void SlotMap::setContext(short unsigned int ctxt)
+{
+  m_size = 0;
+  m_precontext = ctxt;
+}
+
+inline void SlotMap::pushSlot(Slot*const slot)
+{
+  m_slot_map[m_size++ + 1] = slot;
+}
+
+inline Slot * const & SlotMap::operator[](int n) const
+{
+  return m_slot_map[n + 1];
+}
+
+inline Slot * & SlotMap::operator[](int n)
+{
+  return m_slot_map[n + 1];
+}
+
+} // namespace graphite2
new file mode 100644
--- /dev/null
+++ b/gfx/graphite2/src/SegCache.cpp
@@ -0,0 +1,240 @@
+/*  GRAPHITE2 LICENSING
+
+    Copyright 2010, SIL International
+    All rights reserved.
+
+    This library is free software; you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published
+    by the Free Software Foundation; either version 2.1 of License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should also have received a copy of the GNU Lesser General Public
+    License along with this library in the file named "LICENSE".
+    If not, write to the Free Software Foundation, 51 Franklin Street,
+    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
+    internet at http://www.fsf.org/licenses/lgpl.html.
+
+Alternatively, the contents of this file may be used under the terms of the
+Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
+License, as published by the Free Software Foundation, either version 2
+of the License or (at your option) any later version.
+*/
+
+#include "Main.h"
+#include "TtfTypes.h"
+#include "TtfUtil.h"
+#include "SegCache.h"
+#include "SegCacheEntry.h"
+#include "SegCacheStore.h"
+#include "CmapCache.h"
+
+
+using namespace graphite2;
+
+#ifndef DISABLE_SEGCACHE
+
+SegCache::SegCache(const SegCacheStore * store, const Features & feats)
+    :
+    m_prefixLength(ePrefixLength),
+    m_maxCachedSegLength(eMaxSpliceSize),
+    m_segmentCount(0),
+    m_features(feats),
+    m_totalAccessCount(0l), m_totalMisses(0l),
+    m_purgeFactor(1.0f / (ePurgeFactor * store->maxSegmentCount()))
+{
+    m_prefixes.raw = grzeroalloc<void*>(store->maxCmapGid() + 2);
+    m_prefixes.range[SEG_CACHE_MIN_INDEX] = SEG_CACHE_UNSET_INDEX;
+    m_prefixes.range[SEG_CACHE_MAX_INDEX] = SEG_CACHE_UNSET_INDEX;
+}
+
+void SegCache::freeLevel(SegCacheStore * store, SegCachePrefixArray prefixes, size_t level)
+{
+    for (size_t i = 0; i < store->maxCmapGid(); i++)
+    {
+        if (prefixes.array[i].raw)
+        {
+            if (level + 1 < ePrefixLength)
+                freeLevel(store, prefixes.array[i], level + 1);
+            else
+            {
+                SegCachePrefixEntry * prefixEntry = prefixes.prefixEntries[i];
+                delete prefixEntry;
+            }
+        }
+    }
+    free(prefixes.raw);
+}
+
+void SegCache::clear(SegCacheStore * store)
+{
+    #ifndef DISABLE_TRACING
+    if (XmlTraceLog::get().active())
+    {
+        XmlTraceLog::get().openElement(ElementSegCache);
+        XmlTraceLog::get().addAttribute(AttrNum, m_segmentCount);
+        XmlTraceLog::get().addAttribute(AttrAccessCount, m_totalAccessCount);
+        XmlTraceLog::get().addAttribute(AttrMisses, m_totalMisses);
+    }
+#endif
+    freeLevel(store, m_prefixes, 0);
+#ifndef DISABLE_TRACING
+    if (XmlTraceLog::get().active())
+    {
+        XmlTraceLog::get().closeElement(ElementSegCache);
+    }
+#endif
+    m_prefixes.raw = NULL;
+}
+
+SegCache::~SegCache()
+{
+    assert(m_prefixes.raw == NULL);
+}
+
+SegCacheEntry* SegCache::cache(SegCacheStore * store, const uint16* cmapGlyphs, size_t length, Segment * seg, size_t charOffset)
+{
+    uint16 pos = 0;
+    if (!length) return NULL;
+    assert(length < m_maxCachedSegLength);
+    SegCachePrefixArray pArray = m_prefixes;
+    while (pos + 1 < m_prefixLength)
+    {
+        uint16 gid = (pos < length)? cmapGlyphs[pos] : 0;
+        if (!pArray.array[gid].raw)
+        {
+            pArray.array[gid].raw = grzeroalloc<void*>(store->maxCmapGid() + 2);
+            if (!pArray.array[gid].raw)
+                return NULL; // malloc failed
+            if (pArray.range[SEG_CACHE_MIN_INDEX] == SEG_CACHE_UNSET_INDEX)
+            {
+                pArray.range[SEG_CACHE_MIN_INDEX] = gid;
+                pArray.range[SEG_CACHE_MAX_INDEX] = gid;
+            }
+            else
+            {
+                if (gid < pArray.range[SEG_CACHE_MIN_INDEX])
+                    pArray.range[SEG_CACHE_MIN_INDEX] = gid;
+                else if (gid > pArray.range[SEG_CACHE_MAX_INDEX])
+                    pArray.range[SEG_CACHE_MAX_INDEX] = gid;
+            }
+        }
+        pArray = pArray.array[gid];
+        ++pos;
+    }
+    uint16 gid = (pos < length)? cmapGlyphs[pos] : 0;
+    SegCachePrefixEntry * prefixEntry = pArray.prefixEntries[gid];
+    if (!prefixEntry)
+    {
+        prefixEntry = new SegCachePrefixEntry();
+        pArray.prefixEntries[gid] = prefixEntry;
+        if (pArray.range[SEG_CACHE_MIN_INDEX] == SEG_CACHE_UNSET_INDEX)
+        {
+            pArray.range[SEG_CACHE_MIN_INDEX] = gid;
+            pArray.range[SEG_CACHE_MAX_INDEX] = gid;
+        }
+        else
+        {
+            if (gid < pArray.range[SEG_CACHE_MIN_INDEX])
+                pArray.range[SEG_CACHE_MIN_INDEX] = gid;
+            else if (gid > pArray.range[SEG_CACHE_MAX_INDEX])
+                pArray.range[SEG_CACHE_MAX_INDEX] = gid;
+        }
+    }
+    if (!prefixEntry) return NULL;
+    // if the cache is full run a purge - this is slow, since it walks the tree
+    if (m_segmentCount + 1 > store->maxSegmentCount())
+    {
+        purge(store);
+        assert(m_segmentCount < store->maxSegmentCount());
+    }
+    SegCacheEntry * pEntry = prefixEntry->cache(cmapGlyphs, length, seg, charOffset, m_totalAccessCount);
+    if (pEntry) ++m_segmentCount;
+    return pEntry;
+}
+
+void SegCache::purge(SegCacheStore * store)
+{
+    unsigned long long minAccessCount = m_totalAccessCount * m_purgeFactor + 1;
+    if (minAccessCount < 2) minAccessCount = 2;
+    unsigned long long oldAccessTime = m_totalAccessCount - store->maxSegmentCount() / eAgeFactor;
+    purgeLevel(store, m_prefixes, 0, minAccessCount, oldAccessTime);
+}
+
+void SegCache::purgeLevel(SegCacheStore * store, SegCachePrefixArray prefixes, size_t level,
+                          unsigned long long minAccessCount, unsigned long long oldAccessTime)
+{
+    if (prefixes.range[SEG_CACHE_MIN_INDEX] == SEG_CACHE_UNSET_INDEX) return;
+    size_t maxGlyphCached = prefixes.range[SEG_CACHE_MAX_INDEX];
+    for (size_t i = prefixes.range[SEG_CACHE_MIN_INDEX]; i <= maxGlyphCached; i++)
+    {
+        if (prefixes.array[i].raw)
+        {
+            if (level + 1 < ePrefixLength)
+                purgeLevel(store, prefixes.array[i], level + 1, minAccessCount, oldAccessTime);
+            else
+            {
+                SegCachePrefixEntry * prefixEntry = prefixes.prefixEntries[i];
+                m_segmentCount -= prefixEntry->purge(minAccessCount,
+                    oldAccessTime, m_totalAccessCount);
+            }
+        }
+    }
+}
+
+uint32 SegCachePrefixEntry::purge(unsigned long long minAccessCount,
+                                              unsigned long long oldAccessTime,
+                                              unsigned long long currentTime)
+{
+    // ignore the purge request if another has been done recently
+    //if (m_lastPurge > oldAccessTime)
+    //    return 0;
+
+    uint32 totalPurged = 0;
+    // real length is length + 1 in this loop
+    for (uint16 length = 0; length < eMaxSpliceSize; length++)
+    {
+        if (m_entryCounts[length] == 0)
+            continue;
+        uint16 purgeCount = 0;
+        uint16 newIndex = 0;
+        for (uint16 j = 0; j < m_entryCounts[length]; j++)
+        {
+            SegCacheEntry & tempEntry = m_entries[length][j];
+            // purge entries with a low access count which haven't been
+            // accessed recently
+            if (tempEntry.accessCount() <= minAccessCount &&
+                tempEntry.lastAccess() <= oldAccessTime)
+            {
+                tempEntry.clear();
+                ++purgeCount;
+            }
+            else
+            {
+                m_entries[length][newIndex++] = m_entries[length][j];
+            }
+        }
+        if (purgeCount == m_entryCounts[length])
+        {
+            assert(newIndex == 0);
+            m_entryCounts[length] = 0;
+            m_entryBSIndex[length] = 0;
+            free(m_entries[length]);
+            m_entries[length] = NULL;
+        }
+        else if (purgeCount > 0)
+        {
+            assert(m_entryCounts[length] == newIndex + purgeCount);
+            m_entryCounts[length] = newIndex;
+        }
+        totalPurged += purgeCount;
+    }
+    m_lastPurge = currentTime;
+    return totalPurged;
+}
+
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/graphite2/src/SegCache.h
@@ -0,0 +1,314 @@
+/*  GRAPHITE2 LICENSING
+
+    Copyright 2010, SIL International
+    All rights reserved.
+
+    This library is free software; you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published
+    by the Free Software Foundation; either version 2.1 of License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should also have received a copy of the GNU Lesser General Public
+    License along with this library in the file named "LICENSE".
+    If not, write to the Free Software Foundation, 51 Franklin Street,
+    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
+    internet at http://www.fsf.org/licenses/lgpl.html.
+
+Alternatively, the contents of this file may be used under the terms of the
+Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
+License, as published by the Free Software Foundation, either version 2
+of the License or (at your option) any later version.
+*/
+#pragma once
+
+#ifndef DISABLE_SEGCACHE
+
+#include <graphite2/Segment.h>
+#include "Main.h"
+#include "Slot.h"
+#include "FeatureVal.h"
+#include "SegCacheEntry.h"
+#include "Segment.h"
+
+namespace graphite2 {
+
+class SegCache;
+class SegCacheEntry;
+class SegCacheStore;
+
+/**
+ * SegPrefixEntry stores lists of word/syllable segments
+ * with one list for each word length. The prefix size should be chosen so that
+ * these list sizes stay small since they will be searched iteratively.
+ */
+class SegCachePrefixEntry
+{
+public:
+    SegCachePrefixEntry() { memset(this, 0, sizeof(SegCachePrefixEntry)); }
+    ~SegCachePrefixEntry()
+    {
+        for (size_t j = 0; j < eMaxSpliceSize; j++)
+        {
+            if (m_entryCounts[j])
+            {
+                assert(m_entries[j]);
+                for (size_t k = 0; k < m_entryCounts[j]; k++)
+                {
+                    m_entries[j][k].log(j);
+                    m_entries[j][k].clear();
+                }
+                free(m_entries[j]);
+            }
+        }
+    }
+    const SegCacheEntry * find(const uint16 * cmapGlyphs, size_t length) const
+    {
+        if (length <= ePrefixLength)
+        {
+            assert(m_entryCounts[length-1] <= 1);
+            if (m_entries[length-1])
+                return m_entries[length-1];
+            return NULL;
+        }
+        SegCacheEntry * entry = NULL;
+        findPosition(cmapGlyphs, length, &entry);
+        return entry;
+    }
+    SegCacheEntry * cache(const uint16* cmapGlyphs, size_t length, Segment * seg, size_t charOffset, unsigned long long totalAccessCount)
+    {
+        size_t listSize = m_entryBSIndex[length-1]? (m_entryBSIndex[length-1] << 1) - 1 : 0;
+        SegCacheEntry * newEntries = NULL;
+        if (m_entryCounts[length-1] + 1u > listSize)
+        {
+            if (m_entryCounts[length-1] == 0)
+            {
+                listSize = 1;
+            }
+            else
+            {
+                // the problem comes when you get incremental numeric ids in a large doc
+                if (listSize >= eMaxSuffixCount)
+                    return NULL;
+                listSize = (m_entryBSIndex[length-1] << 2) - 1;
+            }
+            newEntries = gralloc<SegCacheEntry>(listSize);
+            if (!newEntries)
+            {
+                return NULL;
+            }
+        }        
+
+        uint16 insertPos = 0;
+        if (m_entryCounts[length-1] > 0)
+        {
+            insertPos = findPosition(cmapGlyphs, length, NULL);
+            if (!newEntries)
+            {
+                // same buffer, shift entries up
+                memmove(m_entries[length-1] + insertPos + 1, m_entries[length-1] + insertPos,
+                    sizeof(SegCacheEntry) * (m_entryCounts[length-1] - insertPos));
+            }
+            else
+            {
+                memcpy(newEntries, m_entries[length-1], sizeof(SegCacheEntry) * (insertPos));
+                memcpy(newEntries + insertPos + 1, m_entries[length-1] + insertPos,
+                   sizeof(SegCacheEntry) * (m_entryCounts[length-1] - insertPos));
+                
+                free(m_entries[length-1]);
+                m_entries[length-1] = newEntries;
+                assert (m_entryBSIndex[length-1]);
+                m_entryBSIndex[length-1] <<= 1;
+            }
+        } 
+        else
+        {
+            m_entryBSIndex[length-1] = 1;
+            m_entries[length-1] = newEntries;
+        }
+        m_entryCounts[length-1] += 1;
+        new (m_entries[length-1] + insertPos)
+            SegCacheEntry(cmapGlyphs, length, seg, charOffset, totalAccessCount);
+        return m_entries[length-1]  + insertPos;
+    }
+    uint32 purge(unsigned long long minAccessCount, unsigned long long oldAccessTime,
+        unsigned long long currentTime);
+    CLASS_NEW_DELETE
+private:
+    uint16 findPosition(const uint16 * cmapGlyphs, uint16 length, SegCacheEntry ** entry) const
+    {
+        int dir = 0;
+        if (m_entryCounts[length-1] == 0)
+        {
+            if (entry) *entry = NULL;
+            return 0;
+        }
+        else if (m_entryCounts[length-1] == 1)
+        {
+            // optimize single entry case
+            for (int i = ePrefixLength; i < length; i++)
+            {
+                if (cmapGlyphs[i] > m_entries[length-1][0].m_unicode[i])
+                {
+                    return 1;
+                }
+                else if (cmapGlyphs[i] < m_entries[length-1][0].m_unicode[i])
+                {
+                    return 0;
+                }
+            }
+            if (entry)
+                *entry = m_entries[length-1];
+            return 0;
+        }
+        uint16 searchIndex = m_entryBSIndex[length-1] - 1;
+        uint16 stepSize = m_entryBSIndex[length-1] >> 1;
+        size_t prevIndex = searchIndex;
+        do
+        {
+            dir = 0;
+            if (searchIndex >= m_entryCounts[length-1])
+            {
+                dir = -1;
+                searchIndex -= stepSize;
+                stepSize >>= 1;
+            }
+            else
+            {
+                for (int i = ePrefixLength; i < length; i++)
+                {
+                    if (cmapGlyphs[i] > m_entries[length-1][searchIndex].m_unicode[i])
+                    {
+                        dir = 1;
+                        searchIndex += stepSize;
+                        stepSize >>= 1;
+                        break;
+                    }
+                    else if (cmapGlyphs[i] < m_entries[length-1][searchIndex].m_unicode[i])
+                    {
+                        dir = -1;
+                        searchIndex -= stepSize;
+                        stepSize >>= 1;
+                        break;
+                    }
+                }
+            }
+            if (prevIndex == searchIndex)
+                break;
+            prevIndex = searchIndex;
+        } while (dir != 0);
+        if (entry)
+        {
+            if (dir == 0)
+                *entry = m_entries[length-1] + searchIndex;
+            else
+                *entry = NULL;
+        }
+        else
+        {
+            // if entry is null, then this is for inserting a new value, which
+            // shouldn't already be in the cache
+            assert(dir != 0);
+            if (dir > 0)
+                ++searchIndex;
+        }
+        return searchIndex;
+    }
+    /** m_entries is a null terminated list of entries */
+    uint16 m_entryCounts[eMaxSpliceSize];
+    uint16 m_entryBSIndex[eMaxSpliceSize];
+    SegCacheEntry * m_entries[eMaxSpliceSize];
+    unsigned long long m_lastPurge;
+};
+
+union SegCachePrefixArray;
+
+#define SEG_CACHE_MIN_INDEX (store->maxCmapGid())
+#define SEG_CACHE_MAX_INDEX (store->maxCmapGid()+1u)
+#define SEG_CACHE_UNSET_INDEX (store->maxCmapGid()+2u)
+
+union SegCachePrefixArray
+{
+    void ** raw;
+    SegCachePrefixArray * array;
+    SegCachePrefixEntry ** prefixEntries;
+    uintptr * range;
+};
+
+class SegCache
+{
+public:
+    SegCache(const SegCacheStore * store, const Features& features);
+    ~SegCache();
+
+    const SegCacheEntry * find(const uint16 * cmapGlyphs, size_t length) const;
+    SegCacheEntry * cache(SegCacheStore * store, const uint16 * cmapGlyphs, size_t length, Segment * seg, size_t charOffset);
+    void purge(SegCacheStore * store);
+
+    long long totalAccessCount() const { return m_totalAccessCount; }
+    size_t segmentCount() const { return m_segmentCount; }
+    const Features & features() const { return m_features; }
+    void clear(SegCacheStore * store);
+
+    CLASS_NEW_DELETE
+private:
+    void freeLevel(SegCacheStore * store, SegCachePrefixArray prefixes, size_t level);
+    void purgeLevel(SegCacheStore * store, SegCachePrefixArray prefixes, size_t level,
+                    unsigned long long minAccessCount, unsigned long long oldAccessTime);
+
+    uint16 m_prefixLength;
+    uint16 m_maxCachedSegLength;
+    size_t m_segmentCount;
+    SegCachePrefixArray m_prefixes;
+    Features m_features;
+    mutable unsigned long long m_totalAccessCount;
+    mutable unsigned long long m_totalMisses;
+    float m_purgeFactor;
+};
+
+inline const SegCacheEntry * SegCache::find(const uint16 * cmapGlyphs, size_t length) const
+{
+    uint16 pos = 0;
+    if (!length || length > eMaxSpliceSize) return NULL;
+    SegCachePrefixArray pEntry = m_prefixes.array[cmapGlyphs[0]];
+    while (++pos < m_prefixLength - 1)
+    {
+        if (!pEntry.raw)
+        {
+            ++m_totalMisses;
+            return NULL;
+        }
+        pEntry = pEntry.array[(pos < length)? cmapGlyphs[pos] : 0];
+    }
+    if (!pEntry.raw)
+    {
+        ++m_totalMisses;
+        return NULL;
+    }
+    SegCachePrefixEntry * prefixEntry = pEntry.prefixEntries[(pos < length)? cmapGlyphs[pos] : 0];
+    if (!prefixEntry)
+    {
+        ++m_totalMisses;
+        return NULL;
+    }
+    const SegCacheEntry * entry = prefixEntry->find(cmapGlyphs, length);
+    if (entry)
+    {
+        ++m_totalAccessCount;
+        entry->accessed(m_totalAccessCount);
+    }
+    else
+    {
+        ++m_totalMisses;
+    }   
+    return entry;
+}
+    
+} // namespace graphite2
+
+#endif
+
new file mode 100644
--- /dev/null
+++ b/gfx/graphite2/src/SegCacheEntry.cpp
@@ -0,0 +1,171 @@
+/*  GRAPHITE2 LICENSING
+
+    Copyright 2010, SIL International
+    All rights reserved.
+
+    This library is free software; you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published
+    by the Free Software Foundation; either version 2.1 of License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should also have received a copy of the GNU Lesser General Public
+    License along with this library in the file named "LICENSE".
+    If not, write to the Free Software Foundation, 51 Franklin Street,
+    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
+    internet at http://www.fsf.org/licenses/lgpl.html.
+
+Alternatively, the contents of this file may be used under the terms of the
+Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
+License, as published by the Free Software Foundation, either version 2
+of the License or (at your option) any later version.
+*/
+
+#ifndef DISABLE_SEGCACHE
+
+#include "Main.h"
+#include "Slot.h"
+#include "Segment.h"
+#include "SegCache.h"
+#include "SegCacheEntry.h"
+
+
+using namespace graphite2;
+
+SegCacheEntry::SegCacheEntry(const uint16* cmapGlyphs, size_t length, Segment * seg, size_t charOffset, long long cacheTime)
+    : m_glyphLength(0), m_unicode(gralloc<uint16>(length)), m_glyph(NULL),
+    m_attr(NULL),
+    m_accessCount(0), m_lastAccess(cacheTime)
+{
+    for (uint16 i = 0; i < length; i++)
+    {
+        m_unicode[i] = cmapGlyphs[i];
+    }
+    size_t glyphCount = seg->slotCount();
+    const Slot * slot = seg->first();
+    m_glyph = new Slot[glyphCount];
+    m_attr = gralloc<uint16>(glyphCount * seg->numAttrs());
+    m_glyphLength = glyphCount;
+    Slot * slotCopy = m_glyph;
+    m_glyph->prev(NULL);
+    struct Index2Slot {
+        Index2Slot(uint16 i, const Slot * s) : m_i(i), m_slot(s) {};
+        Index2Slot() : m_i(0), m_slot(NULL) {};
+        uint16 m_i;
+        const Slot * m_slot;
+    };
+    struct Index2Slot parentGlyphs[eMaxSpliceSize];
+    struct Index2Slot childGlyphs[eMaxSpliceSize];
+    uint16 numParents = 0;
+    uint16 numChildren = 0;
+    uint16 pos = 0;
+    while (slot)
+    {
+        slotCopy->userAttrs(m_attr + pos * seg->numAttrs());
+        slotCopy->set(*slot, -static_cast<int32>(charOffset), seg->numAttrs());
+        if (slot->firstChild())
+        {
+            new(parentGlyphs + numParents) Index2Slot( pos, slot );
+            ++numParents;
+        }
+        if (slot->attachedTo())
+        {
+            new(childGlyphs + numChildren) Index2Slot( pos, slot );
+            ++numChildren;
+        }
+        slot = slot->next();
+        ++slotCopy;
+        ++pos;
+        if (slot)
+        {
+            slotCopy->prev(slotCopy-1);
+            (slotCopy-1)->next(slotCopy);
+        }
+    }
+    // loop over the attached children finding their siblings and parents
+    for (int16 i = 0; i < numChildren; i++)
+    {
+        if (childGlyphs[i].m_slot->nextSibling())
+        {
+            for (int16 j = i; j < numChildren; j++)
+            {
+                if (childGlyphs[i].m_slot->nextSibling() == childGlyphs[j].m_slot)
+                {
+                    m_glyph[childGlyphs[i].m_i].sibling(m_glyph + childGlyphs[j].m_i);
+                    break;
+                }
+            }
+            if (!m_glyph[childGlyphs[i].m_i].nextSibling())
+            {
+                // search backwards
+                for (int16 j = i-1; j >= 0; j--)
+                {
+                    if (childGlyphs[i].m_slot->nextSibling() == childGlyphs[j].m_slot)
+                    {
+                        m_glyph[childGlyphs[i].m_i].sibling(m_glyph + childGlyphs[j].m_i);
+                        break;
+                    }
+                }
+            }
+        }
+        // now find the parent glyph
+        for (int16 j = 0; j < numParents; j++)
+        {
+            if (childGlyphs[i].m_slot->attachedTo() == parentGlyphs[j].m_slot)
+            {
+                m_glyph[childGlyphs[i].m_i].attachTo(m_glyph + parentGlyphs[j].m_i);
+                if (parentGlyphs[j].m_slot->firstChild() == childGlyphs[i].m_slot)
+                {
+                    m_glyph[parentGlyphs[j].m_i].child(m_glyph + childGlyphs[i].m_i);
+                }
+            }
+        }
+    }
+}
+
+void SegCacheEntry::log(GR_MAYBE_UNUSED size_t unicodeLength) const
+{
+#ifndef DISABLE_TRACING
+    if (XmlTraceLog::get().active())
+    {
+        XmlTraceLog::get().openElement(ElementSegCacheEntry);
+        XmlTraceLog::get().addAttribute(AttrAccessCount, m_accessCount);
+        XmlTraceLog::get().addAttribute(AttrLastAccess, m_lastAccess);
+        for (size_t i = 0; i < unicodeLength; i++)
+        {
+            XmlTraceLog::get().openElement(ElementText);
+            XmlTraceLog::get().addAttribute(AttrGlyphId, m_unicode[i]);
+            XmlTraceLog::get().closeElement(ElementText);
+        }
+        for (size_t i = 0; i < m_glyphLength; i++)
+        {
+            XmlTraceLog::get().openElement(ElementGlyph);
+            XmlTraceLog::get().addAttribute(AttrGlyphId, m_glyph[i].gid());
+            XmlTraceLog::get().addAttribute(AttrX, m_glyph[i].origin().x);
+            XmlTraceLog::get().addAttribute(AttrY, m_glyph[i].origin().y);
+            XmlTraceLog::get().addAttribute(AttrBefore, m_glyph[i].before());
+            XmlTraceLog::get().addAttribute(AttrAfter, m_glyph[i].after());
+            XmlTraceLog::get().closeElement(ElementGlyph);
+        }
+        XmlTraceLog::get().closeElement(ElementSegCacheEntry);
+    }
+#endif
+}
+
+void SegCacheEntry::clear()
+{
+    free(m_unicode);
+    free(m_attr);
+    delete [] m_glyph;
+    m_unicode = NULL;
+    m_glyph = NULL;
+    m_glyphLength = 0;
+    m_attr = NULL;
+}
+
+#endif
+
new file mode 100644
--- /dev/null
+++ b/gfx/graphite2/src/SegCacheEntry.h
@@ -0,0 +1,116 @@
+/*  GRAPHITE2 LICENSING
+
+    Copyright 2010, SIL International
+    All rights reserved.
+
+    This library is free software; you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published
+    by the Free Software Foundation; either version 2.1 of License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should also have received a copy of the GNU Lesser General Public
+    License along with this library in the file named "LICENSE".
+    If not, write to the Free Software Foundation, 51 Franklin Street,
+    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
+    internet at http://www.fsf.org/licenses/lgpl.html.
+
+Alternatively, the contents of this file may be used under the terms of the
+Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
+License, as published by the Free Software Foundation, either version 2
+of the License or (at your option) any later version.
+*/
+#pragma once
+
+#ifndef DISABLE_SEGCACHE
+
+#include "Main.h"
+
+namespace graphite2 {
+
+class Segment;
+class Slot;
+class SegCacheEntry;
+class SegCachePrefixEntry;
+
+enum SegCacheParameters {
+    /** number of characters used in initial prefix tree */
+    ePrefixLength = 2,
+    /** Segments more recent than maxSegmentCount() / eAgeFactor are kept */
+    eAgeFactor = 4,
+    /** Segments are purged according to the formular:
+     * accessCount < (totalAccesses)/(ePurgeFactor * maxSegments) */
+    ePurgeFactor = 5,
+    /** Maximum number of Segments to store which have the same
+     * prefix. Needed to prevent unique identifiers flooding the cache */
+    eMaxSuffixCount = 15
+
+};
+
+class SegCacheCharInfo
+{
+public:
+    uint16 m_unicode;
+    uint16 m_before;
+    uint16 m_after;
+};
+
+/**
+ * SegCacheEntry stores the result of running the engine for specific unicode
+ * code points in the typical mid-line situation.
+ */
+class SegCacheEntry
+{
+    friend class SegCachePrefixEntry;
+public:
+    SegCacheEntry() :
+        m_glyphLength(0), m_unicode(NULL), m_glyph(NULL), m_attr(NULL),
+        m_accessCount(0), m_lastAccess(0)
+    {}
+    SegCacheEntry(const uint16 * cmapGlyphs, size_t length, Segment * seg, size_t charOffset, long long cacheTime);
+    ~SegCacheEntry() { clear(); };
+    void clear();
+    size_t glyphLength() const { return m_glyphLength; }
+    const Slot * first() const { return m_glyph; }
+    const Slot * last() const { return m_glyph + (m_glyphLength - 1); }
+
+    void log(size_t unicodeLength) const;
+    /** Total number of times this entry has been accessed since creation */
+    unsigned long long accessCount() const { return m_accessCount; }
+    /** "time" of last access where "time" is measured in accesses to the cache owning this entry */
+    void accessed(unsigned long long cacheTime) const
+    {
+        m_lastAccess = cacheTime; ++m_accessCount;
+    };
+
+    int compareRank(const SegCacheEntry & entry) const
+    {
+        if (m_accessCount > entry.m_accessCount) return 1;
+        else if (m_accessCount < entry.m_accessCount) return 1;
+        else if (m_lastAccess > entry.m_lastAccess) return 1;
+        else if (m_lastAccess < entry.m_lastAccess) return -1;
+        return 0;
+    }
+    unsigned long long lastAccess() const { return m_lastAccess; };
+
+    CLASS_NEW_DELETE;
+private:
+
+    size_t m_glyphLength;
+    /** glyph ids resulting from cmap mapping from unicode to glyph before substitution
+     * the length of this array is determined by the position in the SegCachePrefixEntry */
+    uint16 * m_unicode;
+    /** slots after shapping and positioning */
+    Slot * m_glyph;
+    uint16 * m_attr;
+    mutable unsigned long long m_accessCount;
+    mutable unsigned long long m_lastAccess;
+};
+
+} // namespace graphite2
+
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/graphite2/src/SegCacheStore.cpp
@@ -0,0 +1,49 @@
+/*  GRAPHITE2 LICENSING
+
+    Copyright 2010, SIL International
+    All rights reserved.
+
+    This library is free software; you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published
+    by the Free Software Foundation; either version 2.1 of License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should also have received a copy of the GNU Lesser General Public
+    License along with this library in the file named "LICENSE".
+    If not, write to the Free Software Foundation, 51 Franklin Street,
+    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
+    internet at http://www.fsf.org/licenses/lgpl.html.
+
+Alternatively, the contents of this file may be used under the terms of the
+Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
+License, as published by the Free Software Foundation, either version 2
+of the License or (at your option) any later version.
+*/
+
+#ifndef DISABLE_SEGCACHE
+
+#include "SegCacheStore.h"
+#include "Face.h"
+
+
+using namespace graphite2;
+
+SegCacheStore::SegCacheStore(const Face *face, unsigned int numSilf, size_t maxSegments)
+ : m_caches(new SilfSegCache[numSilf]), m_numSilf(numSilf), m_maxSegments(maxSegments),
+   m_maxCmapGid(0)
+{
+    assert(face);
+    assert(face->getGlyphFaceCache());
+    m_maxCmapGid = face->getGlyphFaceCache()->numGlyphs();
+
+    m_spaceGid = face->cmap()[0x20];
+    m_zwspGid = face->cmap()[0x200B];
+}
+
+#endif
+
new file mode 100644
--- /dev/null
+++ b/gfx/graphite2/src/SegCacheStore.h
@@ -0,0 +1,121 @@
+/*  GRAPHITE2 LICENSING
+
+    Copyright 2010, SIL International
+    All rights reserved.
+
+    This library is free software; you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published
+    by the Free Software Foundation; either version 2.1 of License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should also have received a copy of the GNU Lesser General Public
+    License along with this library in the file named "LICENSE".
+    If not, write to the Free Software Foundation, 51 Franklin Street,
+    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
+    internet at http://www.fsf.org/licenses/lgpl.html.
+
+Alternatively, the contents of this file may be used under the terms of the
+Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
+License, as published by the Free Software Foundation, either version 2
+of the License or (at your option) any later version.
+*/
+#pragma once
+
+#ifndef DISABLE_SEGCACHE
+
+#include "Main.h"
+#include "CmapCache.h"
+#include "SegCache.h"
+
+namespace graphite2 {
+
+class SegCache;
+class Face;
+
+class SilfSegCache
+{
+public:
+    SilfSegCache() : m_caches(NULL), m_cacheCount(0) {};
+    ~SilfSegCache()
+    {
+        assert(m_caches == NULL);
+    }
+    void clear(SegCacheStore * cacheStore)
+    {
+        for (size_t i = 0; i < m_cacheCount; i++)
+        {
+            m_caches[i]->clear(cacheStore);
+            delete m_caches[i];
+        }
+        free(m_caches);
+        m_caches = NULL;
+        m_cacheCount = 0;
+    }
+    SegCache * getOrCreate(SegCacheStore * cacheStore, const Features & features)
+    {
+        for (size_t i = 0; i < m_cacheCount; i++)
+        {
+            if (m_caches[i]->features() == features)
+                return m_caches[i];
+        }
+        SegCache ** newData = gralloc<SegCache*>(m_cacheCount+1);
+        if (newData)
+        {
+            if (m_cacheCount > 0)
+            {
+                memcpy(newData, m_caches, sizeof(SegCache*) * m_cacheCount);
+                free(m_caches);
+            }
+            m_caches = newData;
+            m_caches[m_cacheCount] = new SegCache(cacheStore, features);
+            m_cacheCount++;
+            return m_caches[m_cacheCount - 1];
+        }
+        return NULL;
+    }
+    CLASS_NEW_DELETE
+private:
+    SegCache ** m_caches;
+    size_t m_cacheCount;
+};
+
+class SegCacheStore
+{
+public:
+    SegCacheStore(const Face *face, unsigned int numSilf, size_t maxSegments);
+    ~SegCacheStore()
+    {
+        for (size_t i = 0; i < m_numSilf; i++)
+        {
+            m_caches[i].clear(this);
+        }
+        delete [] m_caches;
+        m_caches = NULL;
+    }
+    SegCache * getOrCreate(unsigned int i, const Features & features)
+    {
+        return m_caches[i].getOrCreate(this, features);
+    }
+    bool isSpaceGlyph(uint16 gid) const { return (gid == m_spaceGid) || (gid == m_zwspGid); }
+    uint16 maxCmapGid() const { return m_maxCmapGid; }
+    uint32 maxSegmentCount() const { return m_maxSegments; };
+
+    CLASS_NEW_DELETE
+private:
+    SilfSegCache * m_caches;
+    uint8 m_numSilf;
+    uint32 m_maxSegments;
+    uint16 m_maxCmapGid;
+    uint16 m_spaceGid;
+    uint16 m_zwspGid;
+};
+
+} // namespace graphite2
+
+#endif
+
new file mode 100644
--- /dev/null
+++ b/gfx/graphite2/src/Segment.cpp
@@ -0,0 +1,563 @@
+/*  GRAPHITE2 LICENSING
+
+    Copyright 2010, SIL International
+    All rights reserved.
+
+    This library is free software; you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published
+    by the Free Software Foundation; either version 2.1 of License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should also have received a copy of the GNU Lesser General Public
+    License along with this library in the file named "LICENSE".
+    If not, write to the Free Software Foundation, 51 Franklin Street, 
+    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the 
+    internet at http://www.fsf.org/licenses/lgpl.html.
+
+Alternatively, the contents of this file may be used under the terms of the
+Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
+License, as published by the Free Software Foundation, either version 2
+of the License or (at your option) any later version.
+*/
+#include "UtfCodec.h"
+#include <cstring>
+#include <cstdlib>
+
+#include "Segment.h"
+#include "graphite2/Font.h"
+#include "CharInfo.h"
+#include "Slot.h"
+#include "Main.h"
+#include "XmlTraceLog.h"
+#include "CmapCache.h"
+#include "graphite2/Segment.h"
+
+
+using namespace graphite2;
+
+Segment::Segment(unsigned int numchars, const Face* face, uint32 script, int textDir) :
+        m_freeSlots(NULL),
+        m_first(NULL),
+        m_last(NULL),
+        m_numGlyphs(numchars),
+        m_numCharinfo(numchars),
+        m_defaultOriginal(0),
+        m_charinfo(new CharInfo[numchars]),
+        m_face(face),
+        m_silf(face->chooseSilf(script)),
+        m_bbox(Rect(Position(0, 0), Position(0, 0))),
+        m_dir(textDir)
+{
+    unsigned int i, j;
+    m_bufSize = numchars + 10;
+    freeSlot(newSlot());
+    for (i = 0, j = 1; j < numchars; i++, j <<= 1) {}
+    if (!i) i = 1;
+    m_bufSize = i;                  // log2(numchars)
+}
+
+Segment::~Segment()
+{
+    for (SlotRope::iterator i = m_slots.begin(); i != m_slots.end(); ++i)
+        free(*i);
+    for (AttributeRope::iterator j = m_userAttrs.begin(); j != m_userAttrs.end(); ++j)
+        free(*j);
+    delete[] m_charinfo;
+}
+
+#ifndef DISABLE_SEGCACHE
+SegmentScopeState Segment::setScope(Slot * firstSlot, Slot * lastSlot, size_t subLength)
+{
+    SegmentScopeState state;
+    state.numGlyphsOutsideScope = m_numGlyphs - subLength;
+    state.realFirstSlot = m_first;
+    state.slotBeforeScope = firstSlot->prev();
+    state.slotAfterScope = lastSlot->next();
+    state.realLastSlot = m_last;
+    firstSlot->prev(NULL);
+    lastSlot->next(NULL);
+    assert(m_defaultOriginal == 0);
+    m_defaultOriginal = firstSlot->original();
+    m_numGlyphs = subLength;
+    m_first = firstSlot;
+    m_last = lastSlot;
+    return state;
+}
+
+void Segment::removeScope(SegmentScopeState & state)
+{
+    m_numGlyphs = state.numGlyphsOutsideScope + m_numGlyphs;
+    if (state.slotBeforeScope)
+    {
+        state.slotBeforeScope->next(m_first);
+        m_first->prev(state.slotBeforeScope);
+        m_first = state.realFirstSlot;
+    }
+    if (state.slotAfterScope)
+    {
+        state.slotAfterScope->prev(m_last);
+        m_last->next(state.slotAfterScope);
+        m_last = state.realLastSlot;
+    }
+    m_defaultOriginal = 0;
+}
+
+
+void Segment::append(const Segment &other)
+{
+    Rect bbox = other.m_bbox + m_advance;
+
+    m_slots.insert(m_slots.end(), other.m_slots.begin(), other.m_slots.end());
+    CharInfo* pNewCharInfo = new CharInfo[m_numCharinfo+other.m_numCharinfo];		//since CharInfo has no constructor, this doesn't do much
+    for (unsigned int i=0 ; i<m_numCharinfo ; ++i)
+	pNewCharInfo[i] = m_charinfo[i];
+    m_last->next(other.m_first);
+    other.m_last->prev(m_last);
+    m_userAttrs.insert(m_userAttrs.end(), other.m_userAttrs.begin(), other.m_userAttrs.end());
+    
+    delete[] m_charinfo;
+    m_charinfo = pNewCharInfo;
+    pNewCharInfo += m_numCharinfo ;
+    for (unsigned int i=0 ; i<m_numCharinfo ; ++i)
+        pNewCharInfo[i] = other.m_charinfo[i];
+ 
+    m_numCharinfo += other.m_numCharinfo;
+    m_numGlyphs += other.m_numGlyphs;
+    m_advance = m_advance + other.m_advance;
+    m_bbox = m_bbox.widen(bbox);
+}
+#endif // DISABLE_SEGCACHE
+
+void Segment::appendSlot(int id, int cid, int gid, int iFeats, size_t coffset)
+{
+    Slot *aSlot = newSlot();
+    
+    m_charinfo[id].init(cid);
+    m_charinfo[id].feats(iFeats);
+    m_charinfo[id].base(coffset);
+    const GlyphFace * theGlyph = m_face->getGlyphFaceCache()->glyphSafe(gid);
+    if (theGlyph)
+    {
+        m_charinfo[id].breakWeight(theGlyph->getAttr(m_silf->aBreak()));
+    }
+    else
+    {
+        m_charinfo[id].breakWeight(0);
+    }
+    
+    aSlot->child(NULL);
+    aSlot->setGlyph(this, gid, theGlyph);
+    aSlot->originate(id);
+    aSlot->before(id);
+    aSlot->after(id);
+    if (m_last) m_last->next(aSlot);
+    aSlot->prev(m_last);
+    m_last = aSlot;
+    if (!m_first) m_first = aSlot;
+}
+
+Slot *Segment::newSlot()
+{
+    if (!m_freeSlots)
+    {
+        int numUser = m_silf->numUser();
+        Slot *newSlots = grzeroalloc<Slot>(m_bufSize);
+        uint16 *newAttrs = grzeroalloc<uint16>(numUser * m_bufSize);
+        newSlots[0].userAttrs(newAttrs);
+        for (size_t i = 1; i < m_bufSize - 1; i++)
+        {
+            newSlots[i].next(newSlots + i + 1);
+            newSlots[i].userAttrs(newAttrs + i * numUser);
+        }
+        newSlots[m_bufSize - 1].userAttrs(newAttrs + (m_bufSize - 1) * numUser);
+        newSlots[m_bufSize - 1].next(NULL);
+        m_slots.push_back(newSlots);
+        m_userAttrs.push_back(newAttrs);
+        m_freeSlots = (m_bufSize > 1)? newSlots + 1 : NULL;
+        return newSlots;
+    }
+    Slot *res = m_freeSlots;
+    m_freeSlots = m_freeSlots->next();
+    res->next(NULL);
+    return res;
+}
+
+void Segment::freeSlot(Slot *aSlot)
+{
+    if (m_last == aSlot) m_last = aSlot->prev();
+    if (m_first == aSlot) m_first = aSlot->next();
+    // reset the slot incase it is reused
+    ::new (aSlot) Slot;
+    memset(aSlot->userAttrs(), 0, m_silf->numUser() * sizeof(uint16));
+    // update next pointer
+    if (!m_freeSlots)
+        aSlot->next(NULL);
+    else
+        aSlot->next(m_freeSlots);
+    m_freeSlots = aSlot;
+}
+
+#ifndef DISABLE_SEGCACHE
+void Segment::splice(size_t offset, size_t length, Slot * startSlot,
+                       Slot * endSlot, const Slot * firstSpliceSlot,
+                       size_t numGlyphs)
+{
+    const Slot * replacement = firstSpliceSlot;
+    Slot * slot = startSlot;
+    extendLength(numGlyphs - length);
+    // insert extra slots if needed
+    while (numGlyphs > length)
+    {
+        Slot * extra = newSlot();
+        extra->prev(endSlot);
+        extra->next(endSlot->next());
+        endSlot->next(extra);
+        if (extra->next())
+            extra->next()->prev(extra);
+        if (m_last == endSlot)
+            m_last = extra;
+        endSlot = extra;
+        ++length;
+    }
+    // remove any extra
+    if (numGlyphs < length)
+    {
+        Slot * afterSplice = endSlot->next();
+        do
+        {
+            endSlot = endSlot->prev();
+            freeSlot(endSlot->next());
+            --length;
+        } while (numGlyphs < length);
+        endSlot->next(afterSplice);
+        if (afterSplice)
+            afterSplice->prev(endSlot);
+    }
+    assert(numGlyphs == length);
+    // keep a record of consecutive slots wrt start of splice to minimize
+    // iterative next/prev calls
+    Slot * slotArray[eMaxSpliceSize];
+    uint16 slotPosition = 0;
+    for (uint16 i = 0; i < numGlyphs; i++)
+    {
+        if (slotPosition <= i)
+        {
+            slotArray[i] = slot;
+            slotPosition = i;
+        }
+        slot->set(*replacement, offset, m_silf->numUser());
+        if (replacement->attachedTo())
+        {
+            uint16 parentPos = replacement->attachedTo() - firstSpliceSlot;
+            while (slotPosition < parentPos)
+            {
+                slotArray[slotPosition+1] = slotArray[slotPosition]->next();
+                ++slotPosition;
+            }
+            slot->attachTo(slotArray[parentPos]);
+        }
+        if (replacement->nextSibling())
+        {
+            uint16 pos = replacement->nextSibling() - firstSpliceSlot;
+            while (slotPosition < pos)
+            {
+                slotArray[slotPosition+1] = slotArray[slotPosition]->next();
+                ++slotPosition;
+            }
+            slot->sibling(slotArray[pos]);
+        }
+        if (replacement->firstChild())
+        {
+            uint16 pos = replacement->firstChild() - firstSpliceSlot;
+            while (slotPosition < pos)
+            {
+                slotArray[slotPosition+1] = slotArray[slotPosition]->next();
+                ++slotPosition;
+            }
+            slot->child(slotArray[pos]);
+        }
+        slot = slot->next();
+        replacement = replacement->next();
+    }
+}
+#endif // DISABLE_SEGCACHE
+        
+void Segment::positionSlots(const Font *font, Slot *iStart, Slot *iEnd)
+{
+    Position currpos(0., 0.);
+    Slot *s, *ls = NULL;
+    int iSlot = 0;
+    float cMin = 0.;
+    float clusterMin = 0.;
+    Rect bbox;
+
+    if (!iStart) iStart = m_first;
+    if (!iEnd) iEnd = m_last;
+    
+    if (m_dir & 1)
+    {
+        for (s = iEnd, iSlot = m_numGlyphs - 1; s && s != iStart->prev(); s = s->prev(), --iSlot)
+        {
+            int j = s->before();
+            if (j >= 0)
+            {
+                for ( ; j <= s->after(); j++)
+                {
+                    CharInfo *c = charinfo(j);
+                    if (c->before() == -1 || iSlot < c->before()) c->before(iSlot);
+                    if (c->after() < iSlot) c->after(iSlot);
+                }
+            }
+            s->index(iSlot);
+
+            if (s->isBase())
+            {
+                clusterMin = currpos.x;
+                currpos = s->finalise(this, font, &currpos, &bbox, &cMin, 0, &clusterMin);
+                if (ls)
+                    ls->sibling(s);
+                ls = s;
+            }
+        }
+    }
+    else
+    {
+        for (s = iStart, iSlot = 0; s && s != iEnd->next(); s = s->next(), ++iSlot)
+        {
+            int j = s->before();
+            if (j >= 0)
+            {
+                for ( ; j <= s->after(); j++)
+                {
+                    CharInfo *c = charinfo(j);
+                    if (c->before() == -1 || iSlot < c->before()) c->before(iSlot);
+                    if (c->after() < iSlot) c->after(iSlot);
+                }
+            }
+            s->index(iSlot);
+
+            if (s->isBase())
+            {
+                clusterMin = currpos.x;
+                currpos = s->finalise(this, font, &currpos, &bbox, &cMin, 0, &clusterMin);
+                if (ls)
+                    ls->sibling(s);
+                ls = s;
+            }
+        }
+    }
+    if (iStart == m_first && iEnd == m_last) m_advance = currpos;
+}
+
+#ifndef DISABLE_TRACING
+void Segment::logSegment(gr_encform enc, const void* pStart, size_t nChars) const
+{
+    if (XmlTraceLog::get().active())
+    {
+        if (pStart)
+        {
+            XmlTraceLog::get().openElement(ElementText);
+            XmlTraceLog::get().addAttribute(AttrEncoding, enc);
+            XmlTraceLog::get().addAttribute(AttrLength, nChars);
+            switch (enc)
+            {
+            case gr_utf8:
+                XmlTraceLog::get().writeText(
+                    reinterpret_cast<const char *>(pStart));
+                break;
+            case gr_utf16:
+                for (size_t j = 0; j < nChars; ++j)
+                {
+                    uint32 code = reinterpret_cast<const uint16 *>(pStart)[j];
+                    if (code >= 0xD800 && code <= 0xDBFF) // high surrogate
+                    {
+                        j++;
+                        // append low surrogate
+                        code = (code << 16) + reinterpret_cast<const uint16 *>(pStart)[j];
+                    }
+                    else if (code >= 0xDC00 && code <= 0xDFFF)
+                    {
+                        XmlTraceLog::get().warning("Unexpected low surrogate %x at %d", code, j);
+                    }
+                    XmlTraceLog::get().writeUnicode(code);
+                }
+                break;
+            case gr_utf32:
+                for (size_t j = 0; j < nChars; ++j)
+                {
+                    XmlTraceLog::get().writeUnicode(
+                        reinterpret_cast<const uint32 *>(pStart)[j]);
+                }
+                break;
+            }
+            XmlTraceLog::get().closeElement(ElementText);
+        }
+        logSegment();
+    }
+}
+
+void Segment::logSegment() const
+{
+    if (XmlTraceLog::get().active())
+    {
+        XmlTraceLog::get().openElement(ElementSegment);
+        XmlTraceLog::get().addAttribute(AttrLength, slotCount());
+        XmlTraceLog::get().addAttribute(AttrAdvanceX, advance().x);
+        XmlTraceLog::get().addAttribute(AttrAdvanceY, advance().y);
+        for (Slot *i = m_first; i; i = i->next())
+        {
+            XmlTraceLog::get().openElement(ElementSlot);
+            XmlTraceLog::get().addAttribute(AttrGlyphId, i->gid());
+            XmlTraceLog::get().addAttribute(AttrX, i->origin().x);
+            XmlTraceLog::get().addAttribute(AttrY, i->origin().y);
+            XmlTraceLog::get().addAttribute(AttrBefore, i->before());
+            XmlTraceLog::get().addAttribute(AttrAfter, i->after());
+            XmlTraceLog::get().closeElement(ElementSlot);
+        }
+        XmlTraceLog::get().closeElement(ElementSegment);
+    }
+}
+
+#endif
+
+template <typename utf_iter>
+inline void process_utf_data(Segment & seg, const Face & face, const int fid, utf_iter c, size_t n_chars)
+{
+	const Cmap    & cmap = face.cmap();
+	int slotid = 0;
+
+	const typename utf_iter::codeunit_type * const base = c;
+	for (; n_chars; --n_chars, ++c, ++slotid)
+	{
+		const uint32 usv = *c;
+		uint16 gid = cmap[usv];
+		if (!gid)	gid = face.findPseudo(usv);
+		seg.appendSlot(slotid, usv, gid, fid, c - base);
+	}
+}
+
+void Segment::read_text(const Face *face, const Features* pFeats/*must not be NULL*/, gr_encform enc, const void* pStart, size_t nChars)
+{
+	assert(face);
+	assert(pFeats);
+
+	switch (enc)
+	{
+	case gr_utf8:	process_utf_data(*this, *face, addFeatures(*pFeats), utf8::const_iterator(pStart), nChars); break;
+	case gr_utf16:	process_utf_data(*this, *face, addFeatures(*pFeats), utf16::const_iterator(pStart), nChars); break;
+	case gr_utf32:	process_utf_data(*this, *face, addFeatures(*pFeats), utf32::const_iterator(pStart), nChars); break;
+	}
+}
+
+void Segment::prepare_pos(const Font * /*font*/)
+{
+    // copy key changeable metrics into slot (if any);
+}
+
+void Segment::finalise(const Font *font)
+{
+    positionSlots(font);
+}
+
+void Segment::justify(Slot *pSlot, const Font *font, float width, GR_MAYBE_UNUSED justFlags flags, Slot *pFirst, Slot *pLast)
+{
+    Slot *pEnd = pSlot;
+    Slot *s, *end;
+    int numBase = 0;
+    float currWidth = 0.;
+    float scale = font ? font->scale() : 1.0;
+    float base;
+
+    if (!pFirst) pFirst = pSlot;
+    base = pFirst->origin().x / scale;
+    width = width / scale;
+    end = pLast ? pLast->next() : NULL;
+
+    for (s = pFirst; s != end; s=s->next())
+    {
+        float w = s->origin().x / scale + s->advance() - base;
+        if (w > currWidth) currWidth = w;
+        pEnd = s;
+        if (!s->attachedTo())       // what about trailing whitespace?
+            numBase++;
+    }
+    if (pLast)
+        while (s)
+        {
+            pEnd = s;
+            s = s->next();
+        }
+    else
+        pLast = pEnd;
+        
+    if (!numBase) return;
+
+    Slot *oldFirst = m_first;
+    Slot *oldLast = m_last;
+    // add line end contextuals to linked list
+    m_first = pSlot;
+    m_last = pEnd;
+    // process the various silf justification stuff returning updated currwidth
+
+    // now fallback to spreading the remaining space among all the bases
+    float nShift = (width - currWidth) / (numBase - 1);
+    for (s = pFirst->nextSibling(); s != end; s = s->nextSibling())
+        s->just(nShift + s->just());
+    positionSlots(font, pSlot, pEnd);
+
+    m_first = oldFirst;
+    m_last = oldLast;
+    // dump line end contextual markers
+}
+
+Slot *resolveExplicit(int level, int dir, Slot *s, int nNest = 0);
+void resolveWeak(int baseLevel, Slot *s);
+void resolveNeutrals(int baseLevel, Slot *s);
+void resolveImplicit(Slot *s, Segment *seg, uint8 aMirror);
+void resolveWhitespace(int baseLevel, Segment *seg, uint8 aBidi, Slot *s);
+Slot *resolveOrder(Slot * & s, const bool reordered, const int level = 0);
+
+void Segment::bidiPass(uint8 aBidi, int paradir, uint8 aMirror)
+{
+	if (slotCount() == 0)
+		return;
+
+    Slot *s;
+    int baseLevel = paradir ? 1 : 0;
+    unsigned int bmask = 0;
+    for (s = first(); s; s = s->next())
+    {
+        unsigned int bAttr = glyphAttr(s->gid(), aBidi);
+        s->setBidiClass((bAttr <= 16) * bAttr);
+        bmask |= (1 << s->getBidiClass());
+        s->setBidiLevel(baseLevel);
+    }
+    if (bmask & (paradir ? 0x92 : 0x9C))
+    {
+        if (bmask & 0xF800)
+            resolveExplicit(baseLevel, 0, first(), 0);
+        if (bmask & 0x10178)
+            resolveWeak(baseLevel, first());
+        if (bmask & 0x161)
+            resolveNeutrals(baseLevel, first());
+        resolveImplicit(first(), this, aMirror);
+        resolveWhitespace(baseLevel, this, aBidi, last());
+        s = resolveOrder(s = first(), baseLevel);
+        first(s); last(s->prev());
+        s->prev()->next(0); s->prev(0);
+    }
+    else if (!(dir() & 4) && baseLevel && aMirror)
+    {
+        for (s = first(); s; s = s->next())
+        {
+            unsigned short g = glyphAttr(s->gid(), aMirror);
+            if (g) s->setGlyph(this, g);
+        }
+    }
+}
+
new file mode 100644
--- /dev/null
+++ b/gfx/graphite2/src/Segment.h
@@ -0,0 +1,171 @@
+/*  GRAPHITE2 LICENSING
+
+    Copyright 2010, SIL International
+    All rights reserved.
+
+    This library is free software; you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published
+    by the Free Software Foundation; either version 2.1 of License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should also have received a copy of the GNU Lesser General Public
+    License along with this library in the file named "LICENSE".
+    If not, write to the Free Software Foundation, 51 Franklin Street, 
+    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the 
+    internet at http://www.fsf.org/licenses/lgpl.html.
+
+Alternatively, the contents of this file may be used under the terms of the
+Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
+License, as published by the Free Software Foundation, either version 2
+of the License or (at your option) any later version.
+*/
+#pragma once
+
+#include "Main.h"
+
+#include <cassert>
+
+#include "Slot.h"
+#include "CharInfo.h"
+#include "FeatureVal.h"
+#include "XmlTraceLog.h"
+#include "Silf.h"
+
+#include "List.h"
+
+#define MAX_SEG_GROWTH_FACTOR  256
+
+namespace graphite2 {
+
+typedef Vector<Features>        FeatureList;
+typedef Vector<Slot *>          SlotRope;
+typedef Vector<uint16 *>        AttributeRope;
+
+#ifndef DISABLE_SEGCACHE
+class SegmentScopeState;
+#endif
+class Segment;
+
+enum SpliceParam {
+/** sub-Segments longer than this are not cached
+ * (in Unicode code points) */
+    eMaxSpliceSize = 16
+};
+
+enum justFlags {
+    gr_justStartInline = 1,
+    gr_justEndInline = 2
+};
+
+class SegmentScopeState
+{
+private:
+    friend class Segment;
+    Slot * realFirstSlot;
+    Slot * slotBeforeScope;
+    Slot * slotAfterScope;
+    Slot * realLastSlot;
+    size_t numGlyphsOutsideScope;
+};
+
+class Segment
+{
+public:
+    unsigned int slotCount() const { return m_numGlyphs; }      //one slot per glyph
+    void extendLength(int num) { m_numGlyphs += num; }
+    Position advance() const { return m_advance; }
+    bool runGraphite() { if (m_silf) return m_face->runGraphite(this, m_silf); else return true;};
+    void chooseSilf(uint32 script) { m_silf = m_face->chooseSilf(script); }
+    const Silf *silf() const { return m_silf; }
+    unsigned int charInfoCount() const { return m_numCharinfo; }
+    const CharInfo *charinfo(unsigned int index) const { return index < m_numCharinfo ? m_charinfo + index : NULL; }
+    CharInfo *charinfo(unsigned int index) { return index < m_numCharinfo ? m_charinfo + index : NULL; }
+    int8 dir() const { return m_dir; }
+
+    Segment(unsigned int numchars, const Face* face, uint32 script, int dir);
+    ~Segment();
+#ifndef DISABLE_SEGCACHE
+    SegmentScopeState setScope(Slot * firstSlot, Slot * lastSlot, size_t subLength);
+    void removeScope(SegmentScopeState & state);
+    void append(const Segment &other);
+    void splice(size_t offset, size_t length, Slot * startSlot, Slot * endSlot, 
+                const Slot * firstSpliceSlot, size_t numGlyphs);
+#endif
+    Slot *first() { return m_first; }
+    void first(Slot *p) { m_first = p; }
+    Slot *last() { return m_last; }
+    void last(Slot *p) { m_last = p; }
+    void appendSlot(int i, int cid, int gid, int fid, size_t coffset);
+    Slot *newSlot();
+    void freeSlot(Slot *);
+    void positionSlots(const Font *font, Slot *iStart = NULL, Slot *iEnd = NULL);
+    uint16 getClassGlyph(uint16 cid, uint16 offset) const { return m_silf->getClassGlyph(cid, offset); }
+    uint16 findClassIndex(uint16 cid, uint16 gid) const { return m_silf->findClassIndex(cid, gid); }
+    int addFeatures(const Features& feats) { m_feats.push_back(feats); return m_feats.size() - 1; }
+    uint16 getFeature(int index, uint8 findex) const { const FeatureRef* pFR=m_face->theSill().theFeatureMap().featureRef(findex); if (!pFR) return 0; else return pFR->getFeatureVal(m_feats[index]); }
+    void dir(int8 val) { m_dir = val; }
+    uint16 glyphAttr(uint16 gid, uint8 gattr) const { return m_face->glyphAttr(gid, gattr); }
+    uint16 getGlyphMetric(Slot *iSlot, uint8 metric, uint8 attrLevel) const {
+        if (attrLevel > 0)
+        {
+            Slot *is = findRoot(iSlot);
+            return is->clusterMetric(this, metric, attrLevel);
+        }
+        else
+            return m_face->getGlyphMetric(iSlot->gid(), metric);
+    }
+    float glyphAdvance(uint16 gid) const { return m_face->getAdvance(gid, 1.0); }
+    const Rect &theGlyphBBoxTemporary(uint16 gid) const { return m_face->theBBoxTemporary(gid); }   //warning value may become invalid when another glyph is accessed
+    Slot *findRoot(Slot *is) const { return is->attachTo() ? findRoot(is->attachTo()) : is; }
+    int numAttrs() { return m_silf->numUser(); }
+    int defaultOriginal() const { return m_defaultOriginal; }
+    const Face * getFace() const { return m_face; }
+    const Features & getFeatures(unsigned int /*charIndex*/) { assert(m_feats.size() == 1); return m_feats[0]; }
+    void bidiPass(uint8 aBidi, int paradir, uint8 aMirror);
+
+    CLASS_NEW_DELETE
+
+#ifndef DISABLE_TRACING
+    void logSegment(gr_encform enc, const void* pStart, size_t nChars) const;
+    void logSegment() const;
+#endif
+
+public:       //only used by: GrSegment* makeAndInitialize(const GrFont *font, const GrFace *face, uint32 script, const FeaturesHandle& pFeats/*must not be IsNull*/, encform enc, const void* pStart, size_t nChars, int dir);
+    void read_text(const Face *face, const Features* pFeats/*must not be NULL*/, gr_encform enc, const void*pStart, size_t nChars);
+    void prepare_pos(const Font *font);
+    void finalise(const Font *font);
+    void justify(Slot *pSlot, const Font *font, float width, enum justFlags flags, Slot *pFirst, Slot *pLast);
+  
+private:
+    SlotRope m_slots;           // std::vector of slot buffers
+    Slot *m_freeSlots;          // linked list of free slots
+    Slot *m_first;              // first slot in segment
+    Slot *m_last;               // last slot in segment
+    unsigned int m_bufSize;     // how big a buffer to create when need more slots
+    unsigned int m_numGlyphs;
+    unsigned int m_numCharinfo; // size of the array and number of input characters
+    int m_defaultOriginal;      // CharInfo index used if all slots have been deleted
+    AttributeRope m_userAttrs;  // std::vector of userAttrs buffers
+    CharInfo *m_charinfo;       // character info, one per input character
+
+    const Face *m_face;       // GrFace
+    const Silf *m_silf;
+    Position m_advance;         // whole segment advance
+    Rect m_bbox;                // ink box of the segment
+    int8 m_dir;
+    FeatureList m_feats;	// feature settings referenced by charinfos in this segment
+
+private:		//defensive on m_charinfo
+    Segment(const Segment&);
+    Segment& operator=(const Segment&);
+};
+
+} // namespace graphite2
+
+struct gr_segment : public graphite2::Segment {};
+
new file mode 100644
--- /dev/null
+++ b/gfx/graphite2/src/Silf.cpp
@@ -0,0 +1,430 @@
+/*  GRAPHITE2 LICENSING
+
+    Copyright 2010, SIL International
+    All rights reserved.
+
+    This library is free software; you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published
+    by the Free Software Foundation; either version 2.1 of License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should also have received a copy of the GNU Lesser General Public
+    License along with this library in the file named "LICENSE".
+    If not, write to the Free Software Foundation, 51 Franklin Street, 
+    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the 
+    internet at http://www.fsf.org/licenses/lgpl.html.
+
+Alternatively, the contents of this file may be used under the terms of the
+Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
+License, as published by the Free Software Foundation, either version 2
+of the License or (at your option) any later version.
+*/
+#include <cstdlib>
+#include "graphite2/Segment.h"
+#include "Endian.h"
+#include "Silf.h"
+#include "XmlTraceLog.h"
+#include "Segment.h"
+#include "Rule.h"
+
+
+using namespace graphite2;
+
+Silf::Silf() throw()
+: m_passes(0), m_pseudos(0), m_classOffsets(0), m_classData(0), m_justs(0),
+  m_numPasses(0), m_sPass(0), m_pPass(0), m_jPass(0), m_bPass(0), m_flags(0),
+  m_aBreak(0), m_aUser(0), m_iMaxComp(0),
+  m_aLig(0), m_numPseudo(0), m_nClass(0), m_nLinear(0)
+{
+}
+
+Silf::~Silf() throw()
+{
+    releaseBuffers();
+}
+
+void Silf::releaseBuffers() throw()
+{
+    delete [] m_passes;
+    delete [] m_pseudos;
+    free(m_classOffsets);
+    free(m_classData);
+    free(m_justs);
+    m_passes= 0;
+    m_pseudos = 0;
+    m_classOffsets = 0;
+    m_classData = 0;
+    m_justs = 0;
+}
+
+
+bool Silf::readGraphite(void* pSilf, size_t lSilf, const Face& face, uint32 version)
+{
+    const byte *p = (byte *)pSilf;
+    const byte * const eSilf = p + lSilf;
+    uint32 *pPasses;
+#ifndef DISABLE_TRACING
+    XmlTraceLog::get().openElement(ElementSilfSub);
+#endif
+    if (version >= 0x00030000)
+    {
+#ifndef DISABLE_TRACING
+        if (XmlTraceLog::get().active())
+        {
+            XmlTraceLog::get().addAttribute(AttrMajor, be::peek<uint16>(p));
+            XmlTraceLog::get().addAttribute(AttrMinor, be::peek<uint16>(p+sizeof(uint16)));
+        }
+#endif
+        if (lSilf < 27) { releaseBuffers(); return false; }
+        p += 8;
+    }
+    else if (lSilf < 19) { releaseBuffers(); return false; }
+    p += 2;     // maxGlyphID
+    p += 4;     // extra ascent/descent
+    m_numPasses = uint8(*p++);
+#ifndef DISABLE_TRACING
+    XmlTraceLog::get().addAttribute(AttrNumPasses, m_numPasses);
+#endif
+    if (m_numPasses > 128)
+        return false;
+    m_passes = new Pass[m_numPasses];
+    m_sPass = uint8(*p++);
+#ifndef DISABLE_TRACING
+    XmlTraceLog::get().addAttribute(AttrSubPass, m_sPass);
+#endif
+    m_pPass = uint8(*p++);
+#ifndef DISABLE_TRACING
+    XmlTraceLog::get().addAttribute(AttrPosPass, m_pPass);
+#endif
+    if (m_pPass < m_sPass) {
+        releaseBuffers();
+        return false;
+    }
+    m_jPass = uint8(*p++);
+#ifndef DISABLE_TRACING
+    XmlTraceLog::get().addAttribute(AttrJustPass, m_jPass);
+#endif
+    if (m_jPass < m_pPass) {
+        releaseBuffers();
+        return false;
+    }
+    m_bPass = uint8(*p++);     // when do we reorder?
+#ifndef DISABLE_TRACING
+    XmlTraceLog::get().addAttribute(AttrBidiPass, m_bPass);
+#endif
+    if (m_bPass != 0xFF && (m_bPass < m_jPass || m_bPass > m_numPasses)) {
+        releaseBuffers();
+        return false;
+    }
+    m_flags = uint8(*p++);
+    p += 2;     // ignore line end contextuals for now
+    m_aPseudo = uint8(*p++);
+    m_aBreak = uint8(*p++);
+#ifndef DISABLE_TRACING
+    XmlTraceLog::get().addAttribute(AttrBreakWeight, m_aBreak);
+    XmlTraceLog::get().addAttribute(AttrDirectionality, *p);
+#endif
+    m_aBidi = uint8(*p++);
+    m_aMirror = uint8(*p++);
+    p += 1;     // skip reserved stuff
+#ifndef DISABLE_TRACING
+    XmlTraceLog::get().addAttribute(AttrNumJustLevels, *p);
+#endif
+    m_numJusts = uint8(*p++);
+    m_justs = gralloc<Justinfo>(m_numJusts);
+    for (uint8 i = 0; i < m_numJusts; i++)
+    {
+        ::new(m_justs + i) Justinfo(p[0], p[1], p[2], p[3]);
+        p += 8;
+    }
+//    p += uint8(*p) * 8 + 1;     // ignore justification for now
+    if (p + 9 >= eSilf) { releaseBuffers(); return false; }
+    m_aLig = be::read<uint16>(p);
+#ifndef DISABLE_TRACING
+    XmlTraceLog::get().addAttribute(AttrLigComp, *p);
+#endif
+    if (m_aLig > 127) {
+        releaseBuffers();
+        return false;
+    }
+    m_aUser = uint8(*p++);
+#ifndef DISABLE_TRACING
+    XmlTraceLog::get().addAttribute(AttrUserDefn, m_aUser);
+#endif
+    m_iMaxComp = uint8(*p++);
+#ifndef DISABLE_TRACING
+    XmlTraceLog::get().addAttribute(AttrNumLigComp, m_iMaxComp);
+#endif
+    p += 5;     // skip direction and reserved
+#ifndef DISABLE_TRACING
+    XmlTraceLog::get().addAttribute(AttrNumCritFeatures, *p);
+#endif
+    p += uint8(*p) * 2 + 1;        // don't need critical features yet
+    p++;        // reserved
+    if (p >= eSilf) 
+    {
+        releaseBuffers();
+        return false;
+    }
+#ifndef DISABLE_TRACING
+    XmlTraceLog::get().addAttribute(AttrNumScripts, *p);
+#endif
+    p += uint8(*p) * 4 + 1;        // skip scripts
+    p += 2;     // skip lbGID
+    
+    if (p + 4 * (m_numPasses + 1) + 6 >= eSilf) 
+    {
+        releaseBuffers(); 
+        return false;
+    }
+    pPasses = (uint32 *)p;
+    p += 4 * (m_numPasses + 1);
+    m_numPseudo = be::read<uint16>(p);
+#ifndef DISABLE_TRACING
+    XmlTraceLog::get().addAttribute(AttrNumPseudo, m_numPseudo);
+#endif
+    p += 6;
+    if (p + m_numPseudo * 6 >= eSilf) 
+    {
+        releaseBuffers();
+        return false;
+    }
+    m_pseudos = new Pseudo[m_numPseudo];
+    for (int i = 0; i < m_numPseudo; i++)
+    {
+        m_pseudos[i].uid = be::read<uint32>(p);
+        m_pseudos[i].gid = be::read<uint16>(p);
+#ifndef DISABLE_TRACING
+        XmlTraceLog::get().openElement(ElementPseudo);
+        XmlTraceLog::get().addAttribute(AttrIndex, i);
+        XmlTraceLog::get().addAttribute(AttrGlyphId, m_pseudos[i].uid);
+        XmlTraceLog::get().writeUnicode(m_pseudos[i].uid);
+        XmlTraceLog::get().closeElement(ElementPseudo);
+#endif
+    }
+    if (p >= eSilf) 
+    {
+        releaseBuffers();
+        return false;
+    }
+
+    int clen = readClassMap(p, be::swap<uint32>(*pPasses) - (p - (byte *)pSilf), version);
+    if (clen < 0) {
+        releaseBuffers();
+        return false;
+    }
+    p += clen;
+
+    for (size_t i = 0; i < m_numPasses; ++i)
+    {
+        uint32 pOffset = be::swap<uint32>(pPasses[i]);
+        uint32 pEnd = be::swap<uint32>(pPasses[i + 1]);
+        if ((uint8 *)pSilf + pEnd > eSilf || pOffset > pEnd)
+        {
+            releaseBuffers();
+            return false;
+        }
+        m_passes[i].init(this);
+#ifndef DISABLE_TRACING
+        if (XmlTraceLog::get().active())
+        {
+            XmlTraceLog::get().openElement(ElementPass);
+            XmlTraceLog::get().addAttribute(AttrPassId, i);
+        }
+#endif
+        if (!m_passes[i].readPass((char *)pSilf + pOffset, pEnd - pOffset, pOffset, face))
+        {
+#ifndef DISABLE_TRACING
+            XmlTraceLog::get().closeElement(ElementPass);
+#endif
+            {
+        releaseBuffers();
+        return false;
+            }
+        }
+#ifndef DISABLE_TRACING
+        XmlTraceLog::get().closeElement(ElementPass);
+#endif
+    }
+#ifndef DISABLE_TRACING
+    XmlTraceLog::get().closeElement(ElementSilfSub);
+#endif
+    return true;
+}
+
+template<typename T> inline uint32 Silf::readClassOffsets(const byte *&p, size_t data_len)
+{
+	const T cls_off = 2*sizeof(uint16) + sizeof(T)*(m_nClass+1);
+	const uint32 max_off = (be::peek<T>(p + sizeof(T)*m_nClass) - cls_off)/sizeof(uint16);
+	// Check that the last+1 offset is less than or equal to the class map length.
+	if (be::peek<T>(p) != cls_off || max_off > (data_len - cls_off)/sizeof(uint16))
+		return -1;
+
+	// Read in all the offsets.
+	m_classOffsets = gralloc<uint32>(m_nClass+1);
+	for (uint32 * o = m_classOffsets, * const o_end = o + m_nClass + 1; o != o_end; ++o)
+	{
+		*o = (be::read<T>(p) - cls_off)/sizeof(uint16);
+		if (*o > max_off)
+			return 0;
+	}
+    return max_off;
+}
+
+size_t Silf::readClassMap(const byte *p, size_t data_len, uint32 version)
+{
+	if (data_len < sizeof(uint16)*2)	return -1;
+
+	m_nClass  = be::read<uint16>(p);
+	m_nLinear = be::read<uint16>(p);
+
+	// Check that numLinear < numClass,
+	// that there is at least enough data for numClasses offsets.
+	if (m_nLinear > m_nClass
+	 || (m_nClass + 1) * (version >= 0x00040000 ? sizeof(uint32) : sizeof(uint16))> (data_len - 4))
+		return -1;
+
+    
+    uint32 max_off;
+    if (version >= 0x00040000)
+        max_off = readClassOffsets<uint32>(p, data_len);
+    else
+        max_off = readClassOffsets<uint16>(p, data_len);
+
+    if (max_off == 0) return -1;
+
+	// Check the linear offsets are sane, these must be monotonically increasing.
+	for (const uint32 *o = m_classOffsets, * const o_end = o + m_nLinear; o != o_end; ++o)
+		if (o[0] > o[1])
+			return -1;
+
+	// Fortunately the class data is all uint16s so we can decode these now
+    m_classData = gralloc<uint16>(max_off);
+    for (uint16 *d = m_classData, * const d_end = d + max_off; d != d_end; ++d)
+        *d = be::read<uint16>(p);
+
+	// Check the lookup class invariants for each non-linear class
+	for (const uint32 *o = m_classOffsets + m_nLinear, * const o_end = m_classOffsets + m_nClass; o != o_end; ++o)
+	{
+		const uint16 * lookup = m_classData + *o;
+		if (lookup[0] == 0							// A LookupClass with no looks is a suspicious thing ...
+		 || lookup[0] > (max_off - *o - 4)/2  	    // numIDs lookup pairs fits within (start of LookupClass' lookups array, max_off]
+		 || lookup[3] != lookup[0] - lookup[1])		// rangeShift:	 numIDs  - searchRange
+			return -1;
+	}
+
+	return max_off;
+}
+
+uint16 Silf::findPseudo(uint32 uid) const
+{
+    for (int i = 0; i < m_numPseudo; i++)
+        if (m_pseudos[i].uid == uid) return m_pseudos[i].gid;
+    return 0;
+}
+
+uint16 Silf::findClassIndex(uint16 cid, uint16 gid) const
+{
+    if (cid > m_nClass) return -1;
+
+    const uint16 * cls = m_classData + m_classOffsets[cid];
+    if (cid < m_nLinear)        // output class being used for input, shouldn't happen
+    {
+        for (unsigned int i = 0, n = m_classOffsets[cid + 1]; i < n; ++i, ++cls)
+            if (*cls == gid) return i;
+        return -1;
+    }
+    else
+    {
+    	const uint16 *	min = cls + 4,		// lookups array
+    				 * 	max = min + cls[0]*2; // lookups aray is numIDs (cls[0]) uint16 pairs long
+    	do
+        {
+        	const uint16 * p = min + (-2U & ((max-min)/2));
+        	if 	(p[0] > gid)	max = p;
+        	else 				min = p;
+        }
+        while (max - min > 2);
+        return min[0] == gid ? min[1] : -1;
+    }
+}
+
+uint16 Silf::getClassGlyph(uint16 cid, unsigned int index) const
+{
+    if (cid > m_nClass) return 0;
+
+    uint32 loc = m_classOffsets[cid];
+    if (cid < m_nLinear)
+    {
+        if (index < m_classOffsets[cid + 1] - loc)
+            return m_classData[index + loc];
+    }
+    else        // input class being used for output. Shouldn't happen
+    {
+        for (unsigned int i = loc + 4; i < m_classOffsets[cid + 1]; i += 2)
+            if (m_classData[i + 1] == index) return m_classData[i];
+    }
+    return 0;
+}
+
+bool Silf::runGraphite(Segment *seg, uint8 firstPass, uint8 lastPass) const
+{
+    assert(seg != 0);
+    SlotMap            map(*seg);
+    FiniteStateMachine fsm(map);
+    vm::Machine        m(map);
+    unsigned int       initSize = seg->slotCount();
+
+    if (lastPass == 0)
+    {
+        if (firstPass == lastPass)
+            return true;
+        lastPass = m_numPasses;
+    }
+
+    for (size_t i = firstPass; i < lastPass; ++i)
+    {
+#ifndef DISABLE_TRACING
+        if (XmlTraceLog::get().active())
+        {
+	        XmlTraceLog::get().openElement(ElementRunPass);
+	        XmlTraceLog::get().addAttribute(AttrNum, i);
+        }
+#endif
+
+        // bidi and mirroring
+        if (i == m_bPass && !(seg->dir() & 2))
+            seg->bidiPass(m_aBidi, seg->dir() & 1, m_aMirror);
+        else if (i == m_bPass && m_aMirror)
+        {
+            Slot * s;
+            for (s = seg->first(); s; s = s->next())
+            {
+                unsigned short g = seg->glyphAttr(s->gid(), m_aMirror);
+                if (g && (!(seg->dir() & 4) || !seg->glyphAttr(s->gid(), m_aMirror + 1)))
+                    s->setGlyph(seg, g);
+            }
+        }
+
+        // test whether to reorder, prepare for positioning
+        m_passes[i].runGraphite(m, fsm);
+#ifndef DISABLE_TRACING
+            seg->logSegment();
+        if (XmlTraceLog::get().active())
+        {
+            XmlTraceLog::get().closeElement(ElementRunPass);
+        }
+#endif
+        // only subsitution passes can change segment length, cached subsegments are short for their text
+        if (m.status() != vm::Machine::finished
+        	|| (i < m_pPass && (seg->slotCount() > initSize * MAX_SEG_GROWTH_FACTOR
+                               || (seg->slotCount() && seg->slotCount() * MAX_SEG_GROWTH_FACTOR < initSize))))
+            return false;
+    }
+    return true;
+}
new file mode 100644
--- /dev/null
+++ b/gfx/graphite2/src/Silf.h
@@ -0,0 +1,114 @@
+/*  GRAPHITE2 LICENSING
+
+    Copyright 2010, SIL International
+    All rights reserved.
+
+    This library is free software; you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published
+    by the Free Software Foundation; either version 2.1 of License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should also have received a copy of the GNU Lesser General Public
+    License along with this library in the file named "LICENSE".
+    If not, write to the Free Software Foundation, 51 Franklin Street, 
+    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the 
+    internet at http://www.fsf.org/licenses/lgpl.html.
+
+Alternatively, the contents of this file may be used under the terms of the
+Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
+License, as published by the Free Software Foundation, either version 2
+of the License or (at your option) any later version.
+*/
+#pragma once
+
+#include "Main.h"
+
+#include "Pass.h"
+
+namespace graphite2 {
+
+class Face;
+class Segment;
+class FeatureVal;
+class VMScratch;
+
+class Pseudo
+{
+public:
+    uint32 uid;
+    uint32 gid;
+    CLASS_NEW_DELETE
+};
+
+class Justinfo
+{
+public:
+    Justinfo(uint8 stretch, uint8 shrink, uint8 step, uint8 weight) :
+        m_astretch(stretch), m_ashrink(shrink), m_astep(step),
+        m_aweight(weight) {};
+private:
+    uint8   m_astretch;
+    uint8   m_ashrink;
+    uint8   m_astep;
+    uint8   m_aweight;
+};
+
+class Silf
+{
+public:
+    Silf() throw();
+    ~Silf() throw();
+    
+    bool readGraphite(void *pSilf, size_t lSilf, const Face &face, uint32 version);
+    bool runGraphite(Segment *seg, uint8 firstPass=0, uint8 lastPass=0) const;
+    uint16 findClassIndex(uint16 cid, uint16 gid) const;
+    uint16 getClassGlyph(uint16 cid, unsigned int index) const;
+    uint16 findPseudo(uint32 uid) const;
+    uint8 numUser() const { return m_aUser; }
+    uint8 aPseudo() const { return m_aPseudo; }
+    uint8 aBreak() const { return m_aBreak; }
+    uint8 aMirror() const {return m_aMirror; }
+    uint8 substitutionPass() const { return m_sPass; }
+    uint8 positionPass() const { return m_pPass; }
+    uint8 justificationPass() const { return m_jPass; }
+    uint8 bidiPass() const { return m_bPass; }
+    uint8 numPasses() const { return m_numPasses; }
+    uint8 maxCompPerLig() const { return m_iMaxComp; }
+    uint16 numClasses() const { return m_nClass; }
+
+    CLASS_NEW_DELETE
+
+private:
+    size_t readClassMap(const byte *p, size_t data_len, uint32 version);
+    template<typename T> inline uint32 readClassOffsets(const byte *&p, size_t data_len);
+
+    Pass          * m_passes;
+    Pseudo        * m_pseudos;
+    uint32        * m_classOffsets;
+    uint16        * m_classData;
+    Justinfo      * m_justs;
+    uint8           m_numPasses;
+    uint8           m_numJusts;
+    uint8           m_sPass, m_pPass, m_jPass, m_bPass,
+                    m_flags;
+
+    uint8   m_aPseudo, m_aBreak, m_aUser, m_aBidi, m_aMirror,
+            m_iMaxComp;
+    uint16  m_aLig,
+            m_numPseudo,
+            m_nClass,
+            m_nLinear;
+    
+    void releaseBuffers() throw();
+    
+private:			//defensive
+    Silf(const Silf&);
+    Silf& operator=(const Silf&);
+};
+
+} // namespace graphite2
new file mode 100644
--- /dev/null
+++ b/gfx/graphite2/src/Slot.cpp
@@ -0,0 +1,355 @@
+/*  GRAPHITE2 LICENSING
+
+    Copyright 2010, SIL International
+    All rights reserved.
+
+    This library is free software; you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published
+    by the Free Software Foundation; either version 2.1 of License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should also have received a copy of the GNU Lesser General Public
+    License along with this library in the file named "LICENSE".
+    If not, write to the Free Software Foundation, 51 Franklin Street, 
+    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the 
+    internet at http://www.fsf.org/licenses/lgpl.html.
+
+Alternatively, the contents of this file may be used under the terms of the
+Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
+License, as published by the Free Software Foundation, either version 2
+of the License or (at your option) any later version.
+*/
+#include "Segment.h"
+#include "Slot.h"
+#include "CharInfo.h"
+#include "Rule.h"
+
+
+using namespace graphite2;
+
+Slot::Slot() :
+    m_next(NULL), m_prev(NULL),
+    m_glyphid(0), m_realglyphid(0), m_original(0), m_before(0), m_after(0),
+    m_parent(NULL), m_child(NULL), m_sibling(NULL),
+    m_position(0, 0), m_shift(0, 0), m_advance(-1, -1),
+    m_attach(0, 0), m_with(0, 0), m_just(0.),
+    m_flags(0), m_attLevel(0)
+    // Do not set m_userAttr since it is set *before* new is called since this
+    // is used as a positional new to reset the GrSlot
+{
+}
+
+// take care, this does not copy any of the GrSlot pointer fields
+void Slot::set(const Slot & orig, int charOffset, uint8 numUserAttr)
+{
+    // leave m_next and m_prev unchanged
+    m_glyphid = orig.m_glyphid;
+    m_realglyphid = orig.m_realglyphid;
+    m_original = orig.m_original + charOffset;
+    m_before = orig.m_before + charOffset;
+    m_after = orig.m_after + charOffset;
+    m_parent = NULL;
+    m_child = NULL;
+    m_sibling = NULL;
+    m_position = orig.m_position;
+    m_shift = orig.m_shift;
+    m_advance = orig.m_advance;
+    m_attach = orig.m_attach;
+    m_with = orig.m_with;
+    m_flags = orig.m_flags;
+    m_attLevel = orig.m_attLevel;
+    assert(!orig.m_userAttr || m_userAttr);
+    if (m_userAttr && orig.m_userAttr)
+    {
+        memcpy(m_userAttr, orig.m_userAttr, numUserAttr * sizeof(*m_userAttr));
+    }
+}
+
+void Slot::update(int /*numGrSlots*/, int numCharInfo, Position &relpos)
+{
+    m_before += numCharInfo;
+    m_after += numCharInfo;
+    m_position = m_position + relpos;
+}
+
+Position Slot::finalise(const Segment *seg, const Font *font, Position *base, Rect *bbox, float *cMin, uint8 attrLevel, float * clusterMin)
+{
+    if (attrLevel && m_attLevel > attrLevel) return Position(0, 0);
+    float scale = 1.0;
+    Position shift = m_shift + Position(m_just, 0);
+    float tAdvance = m_advance.x + m_just;
+    const GlyphFace * glyphFace = seg->getFace()->getGlyphFaceCache()->glyphSafe(glyph());
+    if (font)
+    {
+        scale = font->scale();
+        shift *= scale;
+        if (font->isHinted())
+        {
+            if (glyphFace)
+                tAdvance = (m_advance.x - glyphFace->theAdvance().x) * scale + font->advance(m_glyphid);
+            else
+                tAdvance = (m_advance.x - seg->glyphAdvance(glyph())) * scale + font->advance(m_glyphid);
+        }
+        else
+            tAdvance *= scale;
+    }    
+    Position res;
+
+    m_position = *base + shift;
+    if (!m_parent)
+    {
+        res = *base + Position(tAdvance, m_advance.y * scale);
+        *cMin = 0.;
+        *clusterMin = base->x;
+    }
+    else
+    {
+        float tAdv;
+        m_position += (m_attach - m_with) * scale;
+        tAdv = tAdvance > 0.f ? m_position.x + tAdvance - shift.x : 0.f;
+        res = Position(tAdv, 0);
+        if (m_position.x < *clusterMin) *clusterMin = m_position.x;
+    }
+
+    if (glyphFace)
+    {
+        Rect ourBbox = glyphFace->theBBox() * scale + m_position;
+        *bbox = bbox->widen(ourBbox);
+    }
+    //Rect ourBbox = seg->theGlyphBBoxTemporary(glyph()) * scale + m_position;
+    //bbox->widen(ourBbox);
+
+    if (m_parent && m_position.x < *cMin) *cMin = m_position.x;
+
+    if (m_child && m_child != this && m_child->attachedTo() == this)
+    {
+        Position tRes = m_child->finalise(seg, font, &m_position, bbox, cMin, attrLevel, clusterMin);
+        if (tRes.x > res.x) res = tRes;
+    }
+
+    if (m_parent && m_sibling && m_sibling != this && m_sibling->attachedTo() == m_parent)
+    {
+        Position tRes = m_sibling->finalise(seg, font, base, bbox, cMin, attrLevel, clusterMin);
+        if (tRes.x > res.x) res = tRes;
+    }
+    
+    if (!m_parent)
+    {
+        if (*cMin < 0)
+        {
+            Position adj = Position(-*cMin, 0.);
+            res += adj;
+            m_position += adj;
+            if (m_child) m_child->floodShift(adj);
+        }
+        else if ((seg->dir() & 1) && (*clusterMin < base->x))
+        {
+            Position adj = Position(base->x - *clusterMin, 0.);
+            res += adj;
+            m_position += adj;
+            if (m_child) m_child->floodShift(adj);
+        }
+    }
+    return res;
+}
+
+uint32 Slot::clusterMetric(const Segment *seg, uint8 metric, uint8 attrLevel)
+{
+    Position base;
+    Rect bbox = seg->theGlyphBBoxTemporary(gid());
+    float cMin = 0.;
+    float clusterMin = 0.;
+    Position res = finalise(seg, NULL, &base, &bbox, &cMin, attrLevel, &clusterMin);
+
+    switch (metrics(metric))
+    {
+    case kgmetLsb :
+        return static_cast<uint32>(bbox.bl.x);
+    case kgmetRsb :
+        return static_cast<uint32>(res.x - bbox.tr.x);
+    case kgmetBbTop :
+        return static_cast<uint32>(bbox.tr.y);
+    case kgmetBbBottom :
+        return static_cast<uint32>(bbox.bl.y);
+    case kgmetBbLeft :
+        return static_cast<uint32>(bbox.bl.x);
+    case kgmetBbRight :
+        return static_cast<uint32>(bbox.tr.x);
+    case kgmetBbWidth :
+        return static_cast<uint32>(bbox.tr.x - bbox.bl.x);
+    case kgmetBbHeight :
+        return static_cast<uint32>(bbox.tr.y - bbox.bl.y);
+    case kgmetAdvWidth :
+        return static_cast<uint32>(res.x);
+    case kgmetAdvHeight :
+        return static_cast<uint32>(res.y);
+    default :
+        return 0;
+    }
+}
+
+int Slot::getAttr(const Segment *seg, attrCode ind, uint8 subindex) const
+{
+    if (!this) return 0;
+    if (ind == gr_slatUserDefnV1)
+    {
+        ind = gr_slatUserDefn;
+        subindex = 0;
+    }
+    switch (ind)
+    {
+    case gr_slatAdvX :		return int(m_advance.x);
+    case gr_slatAdvY :		return int(m_advance.y);
+    case gr_slatAttTo :		return 0;
+    case gr_slatAttX :		return int(m_attach.x);
+    case gr_slatAttY :  	return int(m_attach.y);
+    case gr_slatAttXOff :
+    case gr_slatAttYOff :	return 0;
+    case gr_slatAttWithX :  return int(m_with.x);
+    case gr_slatAttWithY :  return int(m_with.y);
+    case gr_slatAttWithXOff:
+    case gr_slatAttWithYOff:return 0;
+    case gr_slatAttLevel :	return m_attLevel;
+    case gr_slatBreak :		return seg->charinfo(m_original)->breakWeight();
+    case gr_slatCompRef : 	return 0;
+    case gr_slatDir :		return seg->dir();
+    case gr_slatInsert :	return isInsertBefore();
+    case gr_slatPosX :		return int(m_position.x); // but need to calculate it
+    case gr_slatPosY :		return int(m_position.y);
+    case gr_slatShiftX :	return int(m_shift.x);
+    case gr_slatShiftY :	return int(m_shift.y);
+    case gr_slatMeasureSol:	return -1; // err what's this?
+    case gr_slatMeasureEol: return -1;
+    case gr_slatJStretch :
+    case gr_slatJShrink :
+    case gr_slatJStep :
+    case gr_slatJWeight :	return 0;
+    case gr_slatJWidth :	return m_just;
+    case gr_slatUserDefn :	return m_userAttr[subindex];
+    default :				return 0;
+    }
+}
+
+void Slot::setAttr(Segment *seg, attrCode ind, uint8 subindex, int16 value, const SlotMap & map)
+{
+    if (!this) return;
+    if (ind == gr_slatUserDefnV1)
+    {
+        ind = gr_slatUserDefn;
+        subindex = 0;
+    }
+    switch (ind)
+    {
+    case gr_slatAdvX :	m_advance.x = value; break;
+    case gr_slatAdvY :	m_advance.y = value; break;
+    case gr_slatAttTo :
+    {
+        const uint16 idx = uint16(value);
+        if (idx < map.size() && map[idx])
+        {
+            Slot *other = map[idx];
+            if (other != this && other->child(this))
+            {
+                attachTo(other);
+                m_attach = Position(seg->glyphAdvance(other->gid()), 0);
+            }
+        }
+        else
+        {
+#ifndef DISABLE_TRACING
+            XmlTraceLog::get().warning("invalid slatAttTo %d", value);
+#endif
+        }
+        break;
+    }
+    case gr_slatAttX :			m_attach.x = value; break;
+    case gr_slatAttY :			m_attach.y = value; break;
+    case gr_slatAttXOff :
+    case gr_slatAttYOff :		break;
+    case gr_slatAttWithX :		m_with.x = value; break;
+    case gr_slatAttWithY :		m_with.y = value; break;
+    case gr_slatAttWithXOff :
+    case gr_slatAttWithYOff :	break;
+    case gr_slatAttLevel :
+        m_attLevel = byte(value);
+        break;
+    case gr_slatBreak :
+        seg->charinfo(m_original)->breakWeight(value);
+        break;
+    case gr_slatCompRef :	break;      // not sure what to do here
+    case gr_slatDir :		break;  // read only
+    case gr_slatInsert :
+        markInsertBefore(value? true : false);
+        break;
+    case gr_slatPosX :		break; // can't set these here
+    case gr_slatPosY :		break;
+    case gr_slatShiftX :	m_shift.x = value; break;
+    case gr_slatShiftY :    m_shift.y = value; break;
+    case gr_slatMeasureSol :	break;
+    case gr_slatMeasureEol :	break;
+    case gr_slatJStretch :      break;  // handle these later
+    case gr_slatJShrink :       break;
+    case gr_slatJStep :         break;
+    case gr_slatJWeight :       break;
+    case gr_slatJWidth :	m_just = value; break;
+    case gr_slatUserDefn :  m_userAttr[subindex] = value; break;
+    default :
+    	break;
+    }
+}
+
+bool Slot::child(Slot *ap)
+{
+    if (this == ap) return false;
+    else if (ap == m_child) return true;
+    else if (!m_child)
+        m_child = ap;
+    else
+        return m_child->sibling(ap);
+    return true;
+}
+
+bool Slot::sibling(Slot *ap)
+{
+    if (this == ap) return false;
+    else if (ap == m_sibling) return true;
+    else if (!m_sibling || !ap)
+        m_sibling = ap;
+    else
+        return m_sibling->sibling(ap);
+    return true;
+}
+
+void Slot::setGlyph(Segment *seg, uint16 glyphid, const GlyphFace * theGlyph)
+{
+    m_glyphid = glyphid;
+    if (!theGlyph)
+    {
+        theGlyph = seg->getFace()->getGlyphFaceCache()->glyphSafe(glyphid);
+        if (!theGlyph)
+        {
+            m_realglyphid = 0;
+            m_advance = Position(0.,0.);
+            return;
+        }
+    }
+    m_realglyphid = theGlyph->getAttr(seg->silf()->aPseudo());
+    if (m_realglyphid)
+    {
+        const GlyphFace *aGlyph = seg->getFace()->getGlyphFaceCache()->glyphSafe(m_realglyphid);
+        if (aGlyph) theGlyph = aGlyph;
+    }
+    m_advance = Position(theGlyph->theAdvance().x, 0.);
+}
+
+void Slot::floodShift(Position adj)
+{
+    m_position += adj;
+    if (m_child) m_child->floodShift(adj);
+    if (m_sibling) m_sibling->floodShift(adj);
+}
new file mode 100644
--- /dev/null
+++ b/gfx/graphite2/src/Slot.h
@@ -0,0 +1,134 @@
+/*  GRAPHITE2 LICENSING
+
+    Copyright 2010, SIL International
+    All rights reserved.
+
+    This library is free software; you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published
+    by the Free Software Foundation; either version 2.1 of License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should also have received a copy of the GNU Lesser General Public
+    License along with this library in the file named "LICENSE".
+    If not, write to the Free Software Foundation, 51 Franklin Street, 
+    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the 
+    internet at http://www.fsf.org/licenses/lgpl.html.
+
+Alternatively, the contents of this file may be used under the terms of the
+Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
+License, as published by the Free Software Foundation, either version 2
+of the License or (at your option) any later version.
+*/
+#pragma once
+
+#include "graphite2/Types.h"
+#include "graphite2/Segment.h"
+#include "Main.h"
+#include "Font.h"
+
+
+#define SLOT_DELETED    1
+#define SLOT_INSERT	2
+#define SLOT_COPIED     4
+#define SLOT_POSITIONED 8
+
+namespace graphite2 {
+
+typedef gr_attrCode attrCode;
+
+class Segment;
+
+class Slot
+{
+public:
+    unsigned short gid() const { return m_glyphid; }
+    Position origin() const { return m_position; }
+    float advance() const { return m_advance.x; }
+    Position advancePos() const { return m_advance; }
+    int before() const { return m_before; }
+    int after() const { return m_after; }
+    uint32 index() const { return m_index; }
+    void index(uint32 val) { m_index = val; }
+
+    Slot();
+    void set(const Slot & slot, int charOffset, uint8 numUserAttr);
+    Slot *next() const { return m_next; }
+    void next(Slot *s) { m_next = s; }
+    Slot *prev() const { return m_prev; }
+    void prev(Slot *s) { m_prev = s; }
+    uint16 glyph() const { return m_realglyphid ? m_realglyphid : m_glyphid; }
+    void setGlyph(Segment *seg, uint16 glyphid, const GlyphFace * theGlyph = NULL);
+    void setRealGid(uint16 realGid) { m_realglyphid = realGid; }
+    void adjKern(const Position &pos) { m_shift = m_shift + pos; m_advance = m_advance + pos; }
+    void origin(const Position &pos) { m_position = pos + m_shift; }
+    void originate(int ind) { m_original = ind; }
+    int original() const { return m_original; }
+    void before(int ind) { m_before = ind; }
+    void after(int ind) { m_after = ind; }
+    bool isBase() const { return (!m_parent); }
+    void update(int numSlots, int numCharInfo, Position &relpos);
+    Position finalise(const Segment* seg, const Font* font, Position* base, Rect* bbox, float* cMin, uint8 attrLevel, float *clusterMin);
+    bool isDeleted() const { return (m_flags & SLOT_DELETED) ? true : false; }
+    void markDeleted(bool state) { if (state) m_flags |= SLOT_DELETED; else m_flags &= ~SLOT_DELETED; }
+    bool isCopied() const { return (m_flags & SLOT_COPIED) ? true : false; }
+    void markCopied(bool state) { if (state) m_flags |= SLOT_COPIED; else m_flags &= ~SLOT_COPIED; }
+    bool isPositioned() const { return (m_flags & SLOT_POSITIONED) ? true : false; }
+    void markPositioned(bool state) { if (state) m_flags |= SLOT_POSITIONED; else m_flags &= ~SLOT_POSITIONED; }
+    bool isInsertBefore() const { return !(m_flags & SLOT_INSERT); }
+    uint8 getBidiLevel() const { return m_bidiLevel; }
+    void setBidiLevel(uint8 level) { m_bidiLevel = level; }
+    uint8 getBidiClass() const { return m_bidiCls; }
+    void setBidiClass(uint8 cls) { m_bidiCls = cls; }
+    uint16 *userAttrs() { return m_userAttr; }
+    void userAttrs(uint16 *p) { m_userAttr = p; }
+    void markInsertBefore(bool state) { if (!state) m_flags |= SLOT_INSERT; else m_flags &= ~SLOT_INSERT; }
+    void setAttr(Segment* seg, attrCode ind, uint8 subindex, int16 val, const SlotMap & map);
+    int getAttr(const Segment *seg, attrCode ind, uint8 subindex) const;
+    void attachTo(Slot *ap) { m_parent = ap; }
+    Slot *attachedTo() const { return m_parent; }
+    Slot* firstChild() const { return m_child; }
+    bool child(Slot *ap);
+    Slot* nextSibling() const { return m_sibling; }
+    bool sibling(Slot *ap);
+    Slot *attachTo() const { return m_parent; }
+    uint32 clusterMetric(const Segment* seg, uint8 metric, uint8 attrLevel);
+    void positionShift(Position a) { m_position += a; }
+    void floodShift(Position adj);
+    float just() { return m_just; }
+    void just(float j) { m_just = j; }
+
+    CLASS_NEW_DELETE
+
+private:
+    Slot *m_next;           // linked list of slots
+    Slot *m_prev;
+    unsigned short m_glyphid;        // glyph id
+    uint16 m_realglyphid;
+    uint32 m_original;	    // charinfo that originated this slot (e.g. for feature values)
+    uint32 m_before;        // charinfo index of before association
+    uint32 m_after;         // charinfo index of after association
+    uint32 m_index;         // slot index given to this slot during finalising
+    Slot *m_parent;         // index to parent we are attached to
+    Slot *m_child;          // index to first child slot that attaches to us
+    Slot *m_sibling;        // index to next child that attaches to our parent
+    Position m_position;    // absolute position of glyph
+    Position m_shift;       // .shift slot attribute
+    Position m_advance;     // .advance slot attribute
+    Position m_attach;      // attachment point on us
+    Position m_with;	    // attachment point position on parent
+    float    m_just;        // justification adjustment
+    uint8    m_flags;       // holds bit flags
+    byte     m_attLevel;    // attachment level
+    byte     m_bidiCls;     // bidirectional class
+    byte     m_bidiLevel;   // bidirectional level
+    uint16  *m_userAttr;     // pointer to user attributes
+};
+
+} // namespace graphite2
+
+struct gr_slot : public graphite2::Slot {};
new file mode 100644
--- /dev/null
+++ b/gfx/graphite2/src/Sparse.cpp
@@ -0,0 +1,72 @@
+/*  GRAPHITE2 LICENSING
+
+    Copyright 2010, SIL International
+    All rights reserved.
+
+    This library is free software; you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published
+    by the Free Software Foundation; either version 2.1 of License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should also have received a copy of the GNU Lesser General Public
+    License along with this library in the file named "LICENSE".
+    If not, write to the Free Software Foundation, 51 Franklin Street,
+    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
+    internet at http://www.fsf.org/licenses/lgpl.html.
+
+Alternatively, the contents of this file may be used under the terms of the
+Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
+License, as published by the Free Software Foundation, either version 2
+of the License or (at your option) any later version.
+*/
+
+#include "Sparse.h"
+
+using namespace graphite2;
+
+namespace
+{
+	template<typename T>
+	inline unsigned int bit_set_count(T v)
+	{
+		v = v - ((v >> 1) & T(~T(0)/3));                           // temp
+		v = (v & T(~T(0)/15*3)) + ((v >> 2) & T(~T(0)/15*3));      // temp
+		v = (v + (v >> 4)) & T(~T(0)/255*15);                      // temp
+		return (T)(v * T(~T(0)/255)) >> (sizeof(T)-1)*8;           // count
+	}
+}
+
+
+sparse::~sparse() throw()
+{
+	free(m_array.values);
+}
+
+
+sparse::value sparse::operator [] (int k) const throw()
+{
+	bool g = k < m_nchunks*SIZEOF_CHUNK;	// This will be 0 is were out of bounds
+	k *= g;									// Force k to 0 if out of bounds making the map look up safe
+	const chunk & 		c = m_array.map[k/SIZEOF_CHUNK];
+	const mask_t 		m = c.mask >> (SIZEOF_CHUNK - 1 - (k%SIZEOF_CHUNK));
+	g *= m & 1;			// Extend the guard value to consider the residency bit
+
+	return g*m_array.values[c.offset + g*bit_set_count(m >> 1)];
+}
+