Bug 1335223 - Update Graphite2 to version 1.3.9. r=jfkthame
authorRyan VanderMeulen <ryanvm@gmail.com>
Tue, 31 Jan 2017 12:36:56 -0500
changeset 468863 ac3294db3ea4f3836031d008fc7d787ec3487904
parent 468862 70e19926d22bc7ad68fc64825a869ab65afde184
child 468864 fbe43964eb8d1595bb67fd679da69053de3a2015
push id43551
push userbmo:kgilbert@mozilla.com
push dateTue, 31 Jan 2017 23:27:06 +0000
reviewersjfkthame
bugs1335223
milestone54.0a1
Bug 1335223 - Update Graphite2 to version 1.3.9. r=jfkthame
gfx/graphite2/ChangeLog
gfx/graphite2/README.mozilla
gfx/graphite2/include/graphite2/Font.h
gfx/graphite2/include/graphite2/XmlLog.h
gfx/graphite2/src/Bidi.cpp
gfx/graphite2/src/Collider.cpp
gfx/graphite2/src/Face.cpp
gfx/graphite2/src/GlyphFaceCache.cpp
gfx/graphite2/src/Intervals.cpp
gfx/graphite2/src/MozGrMalloc.h
gfx/graphite2/src/Pass.cpp
gfx/graphite2/src/Rule.cpp
gfx/graphite2/src/Segment.cpp
gfx/graphite2/src/Silf.cpp
gfx/graphite2/src/XmlTraceLog.cpp
gfx/graphite2/src/XmlTraceLogTags.cpp
gfx/graphite2/src/inc/Bidi.h
gfx/graphite2/src/inc/Collider.h
gfx/graphite2/src/inc/GlyphFaceCache.h
gfx/graphite2/src/inc/Pass.h
gfx/graphite2/src/inc/Shrinker.h
gfx/graphite2/src/moz.build
gfx/thebes/gfxFont.cpp
old mode 100644
new mode 100755
--- a/gfx/graphite2/ChangeLog
+++ b/gfx/graphite2/ChangeLog
@@ -1,8 +1,35 @@
+1.3.9
+    . Add Collision COLL_ISSPACE to allow for visible spaces in collision avoidance
+    . Add segment and pass direction information to tracing output
+    . Bug fix rule length testing in 32-bit
+    . Increase slanted margin distances for collision avoidance
+    . Change kerning algorithm to simple outline expansion. Seems to make no visible difference.
+    . Add trace2svg to test tools
+
+1.3.8
+    . Various bug fixes arising from fuzzing
+    . Fix regression that stopped piglatin from working
+    . Make collision avoidance kerning give more regular results
+    . Minor modification to clustering algorithm to handle variable width chars
+
+1.3.7
+    . Bug fixes
+    . Start to deprecate SegCache. This will be going away in a later release.
+
+1.3.6
+    . Bug fixes
+
+1.3.5
+    . Bug fixes
+        . Security bug fix
+        . Fix ARM misalignment problem
+        . Track latest cmake
+
 1.3.4
     . Transition from Mercurial to Git
     . Bug fixes
         . Fix Collision Kerning ignoring some diacritics
         . Handle pass bits 16-31 to speed up fonts with > 16 passes
         . Various minor fuzz bug fixes
         . Make Coverity happy
         . Add GR_FALLTHROUGH macro for clang c++11
--- a/gfx/graphite2/README.mozilla
+++ b/gfx/graphite2/README.mozilla
@@ -1,6 +1,3 @@
-This directory contains the Graphite2 library release 1.3.8 from
-https://github.com/silnrsi/graphite/releases/download/1.3.8/graphite2-minimal-1.3.8.tgz
+This directory contains the Graphite2 library release 1.3.9 from
+https://github.com/silnrsi/graphite/releases/download/1.3.9/graphite2-minimal-1.3.9.tgz
 See gfx/graphite2/moz-gr-update.sh for update procedure.
-
-Cherry-picked post-1.3.8 commit 56157cf9845d13452068c297205f96b946126cc2 to fix
-https://bugzilla.mozilla.org/show_bug.cgi?id=1261135.
--- a/gfx/graphite2/include/graphite2/Font.h
+++ b/gfx/graphite2/include/graphite2/Font.h
@@ -25,17 +25,17 @@
     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   3
-#define GR2_VERSION_BUGFIX  8
+#define GR2_VERSION_BUGFIX  9
 
 #ifdef __cplusplus
 extern "C"
 {
 #endif
 
 typedef struct gr_face          gr_face;
 typedef struct gr_font          gr_font;
deleted file mode 100644
--- a/gfx/graphite2/include/graphite2/XmlLog.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*  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
deleted file mode 100644
--- a/gfx/graphite2/src/Bidi.cpp
+++ /dev/null
@@ -1,826 +0,0 @@
-/*  GRAPHITE2 LICENSING
-
-    Copyright 2011, 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 "inc/Main.h"
-#include "inc/Slot.h"
-#include "inc/Segment.h"
-#include "inc/Bidi.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
-        EUS        =  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
-        CUS        =  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
-        LRI        = 17,   // LRI isolate
-        RLI        = 18,   // RLI isolate
-        FSI        = 19,   // FSI isolate
-        PDI        = 20,   // pop isolate
-        OPP        = 21,   // opening paired parenthesis
-        CPP        = 22,   // closing paired parenthesis
-
-        ON = N
-};
-
-enum DirMask {
-        WSflag = int8(1 << 7),     // keep track of WS for eos handling
-        WSMask = int8(~(1 << 7))
-};
-
-inline uint8    BaseClass(Slot *s)   { return s->getBidiClass() & WSMask; }
-
-unsigned int bidi_class_map[] = { 0, 1, 2, 5, 4, 8, 9, 3, 7, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0 };
-// Algorithms based on Unicode reference standard code. Thanks Asmus Freitag.
-
-void resolveWeak(Slot *start, int sos, int eos);
-void resolveNeutrals(Slot *s, int baseLevel, int sos, int eos);
-void processParens(Slot *s, Segment *seg, uint8 aMirror, int level, BracketPairStack &stack);
-
-inline int calc_base_level(Slot *s)
-{
-    int count = 0;
-    for ( ; s; s = s->next())
-    {
-        int cls = s->getBidiClass();
-        if (count)
-        {
-            switch(cls)
-            {
-            case LRI :
-            case RLI :
-            case FSI :
-                ++count;
-                break;
-            case PDI :
-                --count;
-            }
-        }
-        else
-        {
-            switch(cls)
-            {
-            case L :
-                return 0;
-            case R :
-            case AL :
-                return 1;
-            case LRI :
-            case RLI :
-            case FSI :
-                ++count;
-            }
-        }
-    }
-    return 0;
-}
-
-// inline or not?
-void do_resolves(Slot *start, int level, int sos, int eos, int &bmask, Segment *seg, uint8 aMirror, BracketPairStack &stack)
-{
-    if (bmask & 0x1F1178)
-        resolveWeak(start, sos, eos);
-    if (bmask & 0x200000)
-        processParens(start, seg, aMirror, level, stack);
-    if (bmask & 0x7E0361)
-        resolveNeutrals(start, level, sos, eos);
-    bmask = 0;
-}
-
-enum maxs
-{
-    MAX_LEVEL = 125,
-};
-
-// returns where we are up to in processing
-Slot *process_bidi(Slot *start, int level, int prelevel, int &nextLevel, int dirover, int isol, int &cisol, int &isolerr, int &embederr, int init, Segment *seg, uint8 aMirror, BracketPairStack &bstack)
-{
-    int bmask = 0;
-    Slot *s = start;
-    Slot *slast = start;
-    Slot *scurr = 0;
-    Slot *stemp;
-    int lnextLevel = nextLevel;
-    int newLevel;
-    int empty = 1;
-    for ( ; s; s = s ? s->next() : s)
-    {
-        int cls = s->getBidiClass();
-        bmask |= (1 << cls);
-        s->setBidiLevel(level);
-        // we keep s->prev() pointing backwards for PDI repeating
-        
-        switch (cls)
-        {
-        case BN :
-            if (slast == s) slast = s->next();      // ignore if at front of text
-            continue;
-        case LRE :
-        case LRO :
-        case RLE :
-        case RLO :
-            switch (cls)
-            {
-            case LRE :
-            case LRO :
-                newLevel = level + (level & 1 ? 1 : 2);
-                break;
-            case RLE :
-            case RLO :
-                newLevel = level + (level & 1 ? 2 : 1);
-                break;
-            }
-            s->setBidiClass(BN);
-            if (isolerr || newLevel > MAX_LEVEL || embederr)
-            {
-                if (!isolerr) ++embederr;
-                break;
-            }
-            stemp = scurr;
-            if (scurr)
-                scurr->prev(0);         // don't include control in string
-            lnextLevel = newLevel;
-            scurr = s;
-            s->setBidiLevel(newLevel); // to make it vanish
-            // recurse for the new subsequence. A sequence only contains text at the same level
-            s = process_bidi(s->next(), newLevel, level, lnextLevel, cls < LRE, 0, cisol, isolerr, embederr, 0, seg, aMirror, bstack);
-            // s points at PDF or end of sequence
-            // try to keep extending the run and not process it until we have to
-            if (lnextLevel != level || !s)      // if the subsequence really had something in it, or we are at the end of the run
-            {
-                if (slast != scurr)             // process the run now, don't try to extend it
-                {
-                    // process text preceeding embedding
-                    do_resolves(slast, level, (prelevel > level ? prelevel : level) & 1, lnextLevel & 1, bmask, seg, aMirror, bstack);
-                    empty = 0;
-                    nextLevel = level;
-                }
-                else if (lnextLevel != level)   // the subsequence had something
-                {
-                    empty = 0;                  // so we aren't empty either
-                    nextLevel = lnextLevel;     // but since we really are empty, pass back our level from the subsequence
-                }
-                if (s)                          // if still more to process
-                {
-                    prelevel = lnextLevel;      // future text starts out with sos of the higher subsequence
-                    lnextLevel = level;         // and eos is our level
-                }
-                slast = s ? s->next() : s;
-            }
-            else if (stemp)
-                stemp->prev(s);
-            break;
-
-        case PDF :
-            s->setBidiClass(BN);
-            s->prev(0);                         // unstitch us since we skip final stitching code when we return
-            if (isol || isolerr || init)        // boundary error conditions
-                break;
-            if (embederr)
-            {
-                --embederr;
-                break;
-            }
-            if (slast != s)
-            {
-                scurr->prev(0);     // if slast, then scurr. Terminate before here
-                do_resolves(slast, level, level & 1, level & 1, bmask, seg, aMirror, bstack);
-                empty = 0;
-            }
-            if (empty)
-            {
-                nextLevel = prelevel;       // no contents? set our level to that of parent
-                s->setBidiLevel(prelevel);
-            }
-            return s;
-
-        case FSI :
-        case LRI :
-        case RLI :
-            switch (cls)
-            {
-            case FSI :
-                if (calc_base_level(s->next()))
-                    newLevel = level + (level & 1 ? 2 : 1);
-                else
-                    newLevel = level + (level & 1 ? 1 : 2);
-                break;
-            case LRI :
-                newLevel = level + (level & 1 ? 1 : 2);
-                break;
-            case RLI :
-                newLevel = level + (level & 1 ? 2 : 1);
-                break;
-            }
-            if (newLevel > MAX_LEVEL || isolerr)
-            {
-                ++isolerr;
-                s->setBidiClass(ON | WSflag);
-                break;
-            }
-            ++cisol;
-            if (scurr) scurr->prev(s);
-            scurr = s;  // include FSI
-            lnextLevel = newLevel;
-            // recurse for the new sub sequence
-            s = process_bidi(s->next(), newLevel, newLevel, lnextLevel, 0, 1, cisol, isolerr, embederr, 0, seg, aMirror, bstack);
-            // s points at PDI
-            if (s)
-            {
-                bmask |= 1 << BaseClass(s);     // include the PDI in the mask
-                s->setBidiLevel(level);         // reset its level to our level
-            }
-            lnextLevel = level;
-            break;
-
-        case PDI :
-            if (isolerr)
-            {
-                --isolerr;
-                s->setBidiClass(ON | WSflag);
-                break;
-            }
-            if (init || !cisol)
-            {
-                s->setBidiClass(ON | WSflag);
-                break;
-            }
-            embederr = 0;
-            if (!isol)                  // we are in an embedded subsequence, we have to return through all those
-            {
-                if (empty)              // if empty, reset the level to tell embedded parent
-                    nextLevel = prelevel;
-                return s->prev();       // keep working up the stack pointing at this PDI until we get to an isolate entry
-            }
-            else                        // we are terminating an isolate sequence
-            {
-                if (slast != s)         // process any remaining content in this subseqence
-                {
-                    scurr->prev(0);
-                    do_resolves(slast, level, prelevel & 1, level & 1, bmask, seg, aMirror, bstack);
-                }
-                --cisol;                // pop the isol sequence from the stack
-                return s;
-            }
-
-        default :
-            if (dirover)
-                s->setBidiClass((level & 1 ? R : L) | (WSflag * (cls == WS)));
-        }
-        if (s) s->prev(0);      // unstitch us
-        if (scurr)              // stitch in text for processing
-            scurr->prev(s);
-        scurr = s;              // add us to text to process
-    }
-    if (slast != s)
-    {
-        do_resolves(slast, level, (level > prelevel ? level : prelevel) & 1, lnextLevel & 1, bmask, seg, aMirror, bstack);
-        empty = 0;
-    }
-    if (empty || isol)
-        nextLevel = prelevel;
-    return s;
-}
-
-// === 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
-} ;
-
-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; }
-
-// 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
-};
-
-// ->prev() here means ->next()
-void SetDeferredRunClass(Slot *s, Slot *sRun, int nval)
-{
-    if (!sRun || s == sRun) return;
-    for (Slot *p = sRun; p != s; p = p->prev())
-        if (p->getBidiClass() == WS) p->setBidiClass(nval | WSflag);
-        else if (BaseClass(p) != BN) p->setBidiClass(nval | (p->getBidiClass() & WSflag));
-}
-
-void SetThisDeferredRunClass(Slot *s, Slot *sRun, int nval)
-{
-    if (!sRun) return;
-    for (Slot *p = sRun, *e = s->prev(); p != e; p = p->prev())
-        if (p->getBidiClass() == WS) p->setBidiClass(nval | WSflag);
-        else if (BaseClass(p) != BN) p->setBidiClass(nval | (p->getBidiClass() & WSflag));
-}
-
-void resolveWeak(Slot *start, int sos, int eos)
-{
-    int state = (sos & 1) ? xr : xl;
-    int cls;
-    Slot *s = start;
-    Slot *sRun = NULL;
-    Slot *sLast = s;
-
-    for ( ; s; s = s->prev())
-    {
-        sLast = s;
-        cls = BaseClass(s);
-        switch (cls)
-        {
-        case BN :
-            if (s == start) start = s->prev();  // skip initial BNs for NSM resolving
-            continue;
-        case LRI :
-        case RLI :
-        case FSI :
-        case PDI :
-            {
-                Slot *snext = s->prev();
-                if (snext && snext->getBidiClass() == NSM)
-                    snext->setBidiClass(ON);
-                s->setBidiClass(ON | WSflag);
-            }
-            break;
-
-        case NSM :
-            if (s == start)
-            {
-                cls = EmbeddingDirection(sos);
-                s->setBidiClass(cls);
-            }
-            break;
-        }
-        
-        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;
-        state = stateWeak[state][bidi_class_map[cls]];
-    }
-
-    cls = EmbeddingDirection(eos);
-    int clsRun = GetDeferredType(actionWeak[state][bidi_class_map[cls]]);
-    if (clsRun != XX)
-        SetThisDeferredRunClass(sLast, sRun, clsRun);
-}
-
-void processParens(Slot *s, Segment *seg, uint8 aMirror, int level, BracketPairStack &stack)
-{
-    uint8 mask = 0;
-    int8 lastDir = -1;
-    BracketPair *p;
-    for ( ; s; s = s->prev())       // walk the sequence
-    {
-        uint16 ogid = seg->glyphAttr(s->gid(), aMirror) || s->gid();
-        int cls = BaseClass(s);
-        
-        switch(cls)
-        {
-        case OPP :
-            stack.orin(mask);
-            stack.push(ogid, s, lastDir, lastDir != CPP);
-            mask = 0;
-            lastDir = OPP;
-            break;
-        case CPP :
-            stack.orin(mask);
-            p = stack.scan(s->gid());
-            if (!p) break;
-            mask = 0;
-            stack.close(p, s);
-            lastDir = CPP;
-            break;
-        case L :
-            lastDir = L;
-            mask |= 1;
-            break;
-        case R :
-        case AL :
-        case AN :
-        case EN :
-            lastDir = R;
-            mask |= 2;
-        }
-    }
-    if (stack.size())
-    {
-        for (p = stack.start(); p; p =p->next())      // walk the stack
-        {
-            if (p->close() && p->mask())
-            {
-                int dir = (level & 1) + 1;
-                if (p->mask() & dir)
-                { }
-                else if (p->mask() & (1 << (~level & 1)))  // if inside has strong other embedding
-                {
-                    int ldir = p->before();
-                    if ((p->before() == OPP || p->before() == CPP) && p->prev())
-                    {
-                        for (BracketPair *q = p->prev(); q; q = q->prev())
-                        {
-                            ldir = q->open()->getBidiClass();
-                            if (ldir < 3) break;
-                            ldir = q->before();
-                            if (ldir < 3) break;
-                        }
-                        if (ldir > 2) ldir = 0;
-                    }
-                    if (ldir > 0 && (ldir - 1) != (level & 1))     // is dir given opp. to level dir (ldir == R or L)
-                        dir = (~level & 1) + 1;
-                }
-                p->open()->setBidiClass(dir);
-                p->close()->setBidiClass(dir);
-            }
-        }
-        stack.clear();
-    }
-}
-
-int GetDeferredNeutrals(int action, int level)
-{
-        action = (action >> 4) & 0xF;
-        if (action == (En >> 4))
-            return EmbeddingDirection(level);
-        else
-            return action;
-}
-
-int GetResolvedNeutrals(int action)
-{
-        return action & 0xF;
-}
-
-// 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, 0, 0, 0, 0, 0, 0, 0 };
-
-const int actionNeutrals[][5] =
-{
-// cls= N,   L,  R, AN, EN,        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] =
-{
-// cls= N,  L,  R,      AN,     EN              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(Slot *s, int baseLevel, int sos, int eos)
-{
-    int state = (sos & 1) ? r : l;
-    int cls;
-    Slot *sRun = NULL;
-    Slot *sLast = s;
-    int level = baseLevel;
-
-    for ( ; s; s = s->prev())
-    {
-        sLast = s;
-        cls = BaseClass(s);
-        switch (cls)
-        {
-        case BN :
-            continue;
-        case LRI :
-        case RLI :
-        case FSI :
-            s->setBidiClass(BN | WSflag);
-            continue;
-
-        default :
-            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);
-            if (!sRun && (action & In))
-                sRun = s;
-            state = stateNeutrals[state][neutral_class_map[cls]];
-        }
-    }
-    cls = EmbeddingDirection(eos);
-    int clsRun = GetDeferredNeutrals(actionNeutrals[state][neutral_class_map[cls]], level);
-    if (clsRun != N)
-        SetThisDeferredRunClass(sLast, sRun, clsRun);
-}
-
-const int addLevel[][4] =
-{
-        //  cls = L,    R,      AN,     EN         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;
-    int level = rtl;
-    Slot *slast = 0;
-    for ( ; s; s = s->next())
-    {
-        int cls = BaseClass(s);
-        s->prev(slast);         // restitch the prev() side of the doubly linked list
-        slast = s;
-        if (cls == AN)
-            cls = AL;   // use AL value as the index for AN, no property change
-        if (cls < 5 && cls > 0)
-        {
-            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, Slot *s)
-{
-    for ( ; s; s = s->prev())
-    {
-        int8 cls = s->getBidiClass();
-        if (cls == WS || (cls & WSflag))
-            s->setBidiLevel(baseLevel);
-        else if (cls != BN)
-            break;
-    }
-}
-
-
-/*
-Stitch two spans together to make another span (with ends tied together).
-If the level is odd then swap the order of the two spans
-*/
-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;
-}
-
-/*
-Given the first slot in a run of slots with the same bidi level, turn the run
-into it's own little doubly linked list ring (a span) with the two ends joined together.
-If the run is rtl then reverse its direction.
-Returns the first slot after the span
-*/
-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->getBidiClass() == BN); 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->getBidiClass() == BN); cs = cs->next())
-            re = cs;
-        r->prev(re);
-        re->next(r);
-    }
-    if (cs) cs->prev(0);
-    return r;
-}
-
-inline int getlevel(const Slot *cs, const int level)
-{
-    while (cs && cs->getBidiClass() == BN)
-    { cs = cs->next(); }
-    if (cs)
-        return cs->getBidiLevel();
-    else
-        return level;
-}
-
-Slot *resolveOrder(Slot * & cs, const bool reordered, const int level)
-{
-    Slot * r = 0;
-    int ls;
-    while (cs && level <= (ls = getlevel(cs, level) - reordered))
-    {
-        r = join(level, r, level < ls
-                                ? resolveOrder(/* updates */cs, reordered, level+1) // find span of heighest level
-                                : span(/* updates */cs, level & 1));
-    }
-    return r;
-}
--- a/gfx/graphite2/src/Collider.cpp
+++ b/gfx/graphite2/src/Collider.cpp
@@ -301,16 +301,17 @@ bool ShiftCollider::mergeSlot(Segment *s
         const float ts = tx + ty;
         const SlantBox &sb = gc.getBoundingSlantBox(gid);
         const unsigned short tgid = _target->gid();
         const BBox &tbb = gc.getBoundingBBox(tgid);
         const SlantBox &tsb = gc.getBoundingSlantBox(tgid);
         float seq_above_wt = cslot->seqAboveWt();
         float seq_below_wt = cslot->seqBelowWt();
         float seq_valign_wt = cslot->seqValignWt();
+        float lmargin = _margin;
         // if isAfter, invert orderFlags for diagonal orders.
         if (isAfter)
         {
             // invert appropriate bits
             orderFlags ^= (sameClass ? 0x3F : 0x3);
             // consider 2 bits at a time, non overlapping. If both bits set, clear them
             orderFlags = orderFlags ^ ((((orderFlags >> 1) & orderFlags) & 0x15) * 3);
         }
@@ -329,51 +330,55 @@ bool ShiftCollider::mergeSlot(Segment *s
                     vmax = min(min(bb.xa - tbb.xi + sx, sb.da - tsb.di + ty + sd), sb.sa - tsb.si - ty + ss);
                     otmin = tbb.yi + ty;
                     otmax = tbb.ya + ty;
                     omin = bb.yi + sy;
                     omax = bb.ya + sy;
                     torg = _currOffset.x;
                     cmin = _limit.bl.x + torg;
                     cmax = _limit.tr.x - tbb.xi + tbb.xa + torg;
+                    lmargin = _margin;
                     break;
                 case 1 :	// y direction
                     vmin = max(max(bb.yi - tbb.ya + sy, tsb.di - sb.da + tx - sd), sb.si - tsb.sa - tx + ss);
                     vmax = min(min(bb.ya - tbb.yi + sy, tsb.da - sb.di + tx - sd), sb.sa - tsb.si - tx + ss);
                     otmin = tbb.xi + tx;
                     otmax = tbb.xa + tx;
                     omin = bb.xi + sx;
                     omax = bb.xa + sx;
                     torg = _currOffset.y;
                     cmin = _limit.bl.y + torg;
                     cmax = _limit.tr.y - tbb.yi + tbb.ya + torg;
+                    lmargin = _margin;
                     break;
                 case 2 :    // sum - moving along the positively-sloped vector, so the boundaries are the
                             // negatively-sloped boundaries.
                     vmin = max(max(sb.si - tsb.sa + ss, 2 * (bb.yi - tbb.ya + sy) + td), 2 * (bb.xi - tbb.xa + sx) - td);
                     vmax = min(min(sb.sa - tsb.si + ss, 2 * (bb.ya - tbb.yi + sy) + td), 2 * (bb.xa - tbb.xi + sx) - td);
                     otmin = tsb.di + td;
                     otmax = tsb.da + td;
                     omin = sb.di + sd;
                     omax = sb.da + sd;
                     torg = _currOffset.x + _currOffset.y;
                     cmin = _limit.bl.x + _limit.bl.y + torg;
                     cmax = _limit.tr.x + _limit.tr.y - tsb.si + tsb.sa + torg;
+                    lmargin = _margin / ISQRT2;
                     break;
                 case 3 :    // diff - moving along the negatively-sloped vector, so the boundaries are the
                             // positively-sloped boundaries.
                     vmin = max(max(sb.di - tsb.da + sd, 2 * (bb.xi - tbb.xa + sx) - ts), -2 * (bb.ya - tbb.yi + sy) + ts);
                     vmax = min(min(sb.da - tsb.di + sd, 2 * (bb.xa - tbb.xi + sx) - ts), -2 * (bb.yi - tbb.ya + sy) + ts);
                     otmin = tsb.si + ts;
                     otmax = tsb.sa + ts;
                     omin = sb.si + ss;
                     omax = sb.sa + ss;
                     torg = _currOffset.x - _currOffset.y;
                     cmin = _limit.bl.x - _limit.tr.y + torg;
                     cmax = _limit.tr.x - _limit.bl.y - tsb.di + tsb.da + torg;
+                    lmargin = _margin / ISQRT2;
                     break;
                 default :
                     continue;
             }
             
 #if !defined GRAPHITE2_NTRACING
             if (dbgout)
                 dbgout->setenv(1, reinterpret_cast<void *>(-1));
@@ -465,17 +470,17 @@ bool ShiftCollider::mergeSlot(Segment *s
                         removeBox(Rect(Position(bb.xa - tbb.xi + sx, bb.yi - tbb.ya + sy),
                                         Position(xpinf, bb.ya - tbb.yi + sy)), tbb, tsb, org, i);
                         break;
                     default :
                         break;
                 }
             }
 
-            if (vmax < cmin - _margin || vmin > cmax + _margin || omax < otmin - _margin || omin > otmax + _margin)
+            if (vmax < cmin - lmargin || vmin > cmax + lmargin || omax < otmin - lmargin || omin > otmax + lmargin)
                 continue;
 
             // Process sub-boxes that are defined for this glyph.
             // We only need to do this if there was in fact a collision with the main octabox.
             uint8 numsub = gc.numSubBounds(gid);
             if (numsub > 0)
             {
                 bool anyhits = false;
@@ -504,49 +509,49 @@ bool ShiftCollider::mergeSlot(Segment *s
                             break;
                         case 3 :    // diff
                             vmin = max(max(ssb.di-tsb.da+sd, 2*(sbb.xi-tbb.xa+sx)-ts), -2*(sbb.ya-tbb.yi+sy)+ts);
                             vmax = min(min(ssb.da-tsb.di+sd, 2*(sbb.xa-tbb.xi+sx)-ts), -2*(sbb.yi-tbb.ya+sy)+ts);
                             omin = ssb.si + ss;
                             omax = ssb.sa + ss;
                             break;
                     }
-                    if (vmax < cmin - _margin || vmin > cmax + _margin || omax < otmin - _margin || omin > otmax + _margin)
+                    if (vmax < cmin - lmargin || vmin > cmax + lmargin || omax < otmin - lmargin || omin > otmax + lmargin)
                         continue;
 
 #if !defined GRAPHITE2_NTRACING
                     if (dbgout)
                         dbgout->setenv(1, reinterpret_cast<void *>(j));
 #endif
                     if (omin > otmax)
-                        _ranges[i].weightedAxis(i, vmin - _margin, vmax + _margin, 0, 0, 0, 0, 0,
-                                                sqr(_margin - omin + otmax) * _marginWt, false);
+                        _ranges[i].weightedAxis(i, vmin - lmargin, vmax + lmargin, 0, 0, 0, 0, 0,
+                                                sqr(lmargin - omin + otmax) * _marginWt, false);
                     else if (omax < otmin)
-                        _ranges[i].weightedAxis(i, vmin - _margin, vmax + _margin, 0, 0, 0, 0, 0,
-                                                sqr(_margin - otmin + omax) * _marginWt, false);
+                        _ranges[i].weightedAxis(i, vmin - lmargin, vmax + lmargin, 0, 0, 0, 0, 0,
+                                                sqr(lmargin - otmin + omax) * _marginWt, false);
                     else
                         _ranges[i].exclude_with_margins(vmin, vmax, i);
                     anyhits = true;
                 }
                 if (anyhits)
                     isCol = true;
             }
             else // no sub-boxes
             {
 #if !defined GRAPHITE2_NTRACING
                     if (dbgout)
                         dbgout->setenv(1, reinterpret_cast<void *>(-1));
 #endif
                 isCol = true;
                 if (omin > otmax)
-                    _ranges[i].weightedAxis(i, vmin - _margin, vmax + _margin, 0, 0, 0, 0, 0,
-                                            sqr(_margin - omin + otmax) * _marginWt, false);
+                    _ranges[i].weightedAxis(i, vmin - lmargin, vmax + lmargin, 0, 0, 0, 0, 0,
+                                            sqr(lmargin - omin + otmax) * _marginWt, false);
                 else if (omax < otmin)
-                    _ranges[i].weightedAxis(i, vmin - _margin, vmax + _margin, 0, 0, 0, 0, 0,
-                                            sqr(_margin - otmin + omax) * _marginWt, false);
+                    _ranges[i].weightedAxis(i, vmin - lmargin, vmax + lmargin, 0, 0, 0, 0, 0,
+                                            sqr(lmargin - otmin + omax) * _marginWt, false);
                 else
                     _ranges[i].exclude_with_margins(vmin, vmax, i);
 
             }
         }
     }
     bool res = true;
     if (cslot->exclGlyph() > 0 && gc.check(cslot->exclGlyph()) && !isExclusion)
@@ -747,69 +752,69 @@ static float localmin(float al, float au
 {
     if (bl > al)
     { if (bu > au) return bl > x ? bl : x; }
     else if (au > bu) return al > x ? al : x;
     return x;        
 }
 
 // Return the given edge of the glyph at height y, taking any slant box into account.
-static float get_edge(Segment *seg, const Slot *s, const Position &shift, float y, float width, bool isRight)
+static float get_edge(Segment *seg, const Slot *s, const Position &shift, float y, float width, float margin, bool isRight)
 {
     const GlyphCache &gc = seg->getFace()->glyphs();
     unsigned short gid = s->gid();
     float sx = s->origin().x + shift.x;
     float sy = s->origin().y + shift.y;
     uint8 numsub = gc.numSubBounds(gid);
     float res = isRight ? (float)-1e38 : (float)1e38;
 
     if (numsub > 0)
     {
         for (int i = 0; i < numsub; ++i)
         {
             const BBox &sbb = gc.getSubBoundingBBox(gid, i);
             const SlantBox &ssb = gc.getSubBoundingSlantBox(gid, i);
-            if (sy + sbb.yi > y + width / 2 || sy + sbb.ya < y - width / 2)
+            if (sy + sbb.yi - margin > y + width / 2 || sy + sbb.ya + margin < y - width / 2)
                 continue;
             if (isRight)
             {
-                float x = sx + sbb.xa;
+                float x = sx + sbb.xa + margin;
                 if (x > res)
                 {
-                    float td = sx - sy + ssb.da + y;
-                    float ts = sx + sy + ssb.sa - y;
+                    float td = sx - sy + ssb.da + margin + y;
+                    float ts = sx + sy + ssb.sa + margin - y;
                     x = localmax(td - width / 2, td + width / 2,  ts - width / 2, ts + width / 2, x);
                     if (x > res)
                         res = x;
                 }
             }
             else
             {
-                float x = sx + sbb.xi;
+                float x = sx + sbb.xi - margin;
                 if (x < res)
                 {
-                    float td = sx - sy + ssb.di + y;
-                    float ts = sx + sy + ssb.si - y;
+                    float td = sx - sy + ssb.di - margin + y;
+                    float ts = sx + sy + ssb.si - margin - y;
                     x = localmin(td - width / 2, td + width / 2, ts - width / 2, ts + width / 2, x);
                     if (x < res)
                         res = x;
                 }
             }
         }
     }
     else
     {
         const BBox &bb = gc.getBoundingBBox(gid);
         const SlantBox &sb = gc.getBoundingSlantBox(gid);
         float td = sx - sy + y;
         float ts = sx + sy - y;
         if (isRight)
-            res = localmax(td + sb.da - width / 2, td + sb.da + width / 2, ts + sb.sa - width / 2, ts + sb.sa + width / 2, sx + bb.xa);
+            res = localmax(td + sb.da - width / 2, td + sb.da + width / 2, ts + sb.sa - width / 2, ts + sb.sa + width / 2, sx + bb.xa) + margin;
         else
-            res = localmin(td + sb.di - width / 2, td + sb.di + width / 2, ts + sb.si - width / 2, ts + sb.si + width / 2, sx + bb.xi);
+            res = localmin(td + sb.di - width / 2, td + sb.di + width / 2, ts + sb.si - width / 2, ts + sb.si + width / 2, sx + bb.xi) - margin;
     }
     return res;
 }
 
 
 bool KernCollider::initSlot(Segment *seg, Slot *aSlot, const Rect &limit, float margin,
     const Position &currShift, const Position &offsetPrev, int dir,
     float ymin, float ymax, GR_MAYBE_UNUSED json * const dbgout)
@@ -860,16 +865,17 @@ bool KernCollider::initSlot(Segment *seg
             if (numSlices > (int)_edges.size())
                 _edges.insert(_edges.end(), numSlices - _edges.size(), (dir & 1) ? 1e38f : -1e38f);
             else if (numSlices < (int)_edges.size())   // this shouldn't fire since we always grow the range
             {
                 while ((int)_edges.size() > numSlices)
                     _edges.pop_back();
             }
         }
+        goto done;
     }
     numSlices = _edges.size();
 
 #if !defined GRAPHITE2_NTRACING
     // Debugging
     _seg = seg;
     _slotNear.clear();
     _slotNear.insert(_slotNear.begin(), numSlices, NULL);
@@ -891,36 +897,37 @@ bool KernCollider::initSlot(Segment *seg
         int smin = max(0, int((bs.yi + toffset) / _sliceWidth));
         int smax = min(numSlices - 1, int((bs.ya + toffset) / _sliceWidth + 1));
         for (int i = smin; i <= smax; ++i)
         {
             float t;
             float y = _miny - 1 + (i + .5f) * _sliceWidth; // vertical center of slice
             if ((dir & 1) && x < _edges[i])
             {
-                t = get_edge(seg, s, c->shift(), y, _sliceWidth, false);
+                t = get_edge(seg, s, c->shift(), y, _sliceWidth, margin, false);
                 if (t < _edges[i])
                 {
                     _edges[i] = t;
                     if (t < _xbound)
                         _xbound = t;
                 }
             }
             else if (!(dir & 1) && x > _edges[i])
             {
-                t = get_edge(seg, s, c->shift(), y, _sliceWidth, true);
+                t = get_edge(seg, s, c->shift(), y, _sliceWidth, margin, true);
                 if (t > _edges[i])
                 {
                     _edges[i] = t;
                     if (t > _xbound)
                         _xbound = t;
                 }
             }
         }
     }
+    done:
     _mingap = (float)1e38;
     _target = aSlot;
     _margin = margin;
     _currShift = currShift;
     return true;
 }   // end of KernCollider::initSlot
 
 
@@ -941,69 +948,62 @@ bool KernCollider::mergeSlot(Segment *se
         return false;
 
     const float sy = slot->origin().y + currShift.y;
     int smin = max(1, int((bb.bl.y + (1 - _miny + sy)) / _sliceWidth + 1)) - 1;
     int smax = min((int)_edges.size() - 2, int((bb.tr.y + (1 - _miny + sy)) / _sliceWidth + 1)) + 1;
     if (smin > smax)
         return false;
     bool collides = false;
-    float below = smin > 0 ? _edges[smin-1] * rtl : 1e38f;
-    float here = _edges[smin] * rtl;
-    float above = smin < (int)_edges.size() - 1 ? _edges[smin+1] * rtl : 1e38f;
 
     for (int i = smin; i <= smax; ++i)
     {
         float t;
+        float here = _edges[i] * rtl;
         float y = (float)(_miny - 1 + (i + .5f) * _sliceWidth);  // vertical center of slice
-        if (    (x > here - _mingap - currSpace)
-             || (x > below - _mingap - currSpace)
-             || (x > above - _mingap - currSpace))
+        if (    (x > here - _mingap - currSpace) )
         {
             // 2 * currSpace to account for the space that is already separating them and the space we want to add
-            float m = get_edge(seg, slot, currShift, y, _sliceWidth, rtl > 0) * rtl + 2 * currSpace;
-            // Check slices above and below (if any).
-            t = min(min(here, below), above) - m;
+            float m = get_edge(seg, slot, currShift, y, _sliceWidth, 0., rtl > 0) * rtl + 2 * currSpace;
+            t = here - m;
             // _mingap is positive to shrink
             if (t < _mingap)
             {
                 _mingap = t;
                 collides = true;
             }
 #if !defined GRAPHITE2_NTRACING
             // Debugging - remember the closest neighboring edge for this slice.
             if (m > rtl * _nearEdges[i])
             {
                 _slotNear[i] = slot;
                 _nearEdges[i] = m * rtl;
             }
 #endif
         }
-        below = here; here = above;
-        above = i < (int)_edges.size() - 2 ? _edges[i+2] * rtl : 1e38f;
     }
     return collides;   // note that true is not a necessarily reliable value
     
 }   // end of KernCollider::mergeSlot
 
 
 // Return the amount to kern by.
 Position KernCollider::resolve(GR_MAYBE_UNUSED Segment *seg, GR_MAYBE_UNUSED Slot *slot,
-        int dir, float margin, GR_MAYBE_UNUSED json * const dbgout)
+        int dir, GR_MAYBE_UNUSED json * const dbgout)
 {
-    float resultNeeded = (1 - 2 * (dir & 1)) * (_mingap - margin);
+    float resultNeeded = (1 - 2 * (dir & 1)) * _mingap;
+    // float resultNeeded = (1 - 2 * (dir & 1)) * (_mingap - margin);
     float result = min(_limit.tr.x - _offsetPrev.x, max(resultNeeded, _limit.bl.x - _offsetPrev.x));
 
 #if !defined GRAPHITE2_NTRACING
     if (dbgout)
     {
         *dbgout << json::object // slot
                 << "slot" << objectid(dslot(seg, _target))
 				<< "gid" << _target->gid()
-                << "margin" << _margin
                 << "limit" << _limit
                 << "miny" << _miny
                 << "maxy" << _maxy
                 << "slicewidth" << _sliceWidth
                 << "target" << json::object
                     << "origin" << _target->origin()
                     //<< "currShift" << _currShift
                     << "offsetPrev" << _offsetPrev
@@ -1088,8 +1088,12 @@ void SlotCollision::initFromSlot(Segment
 float SlotCollision::getKern(int dir) const
 {
     if ((_flags & SlotCollision::COLL_KERN) != 0)
         return float(_shift.x * ((dir & 1) ? -1 : 1));
     else
     	return 0;
 }
 
+bool SlotCollision::ignore() const
+{
+	return ((flags() & SlotCollision::COLL_IGNORE) || (flags() & SlotCollision::COLL_ISSPACE));
+}
--- a/gfx/graphite2/src/Face.cpp
+++ b/gfx/graphite2/src/Face.cpp
@@ -185,19 +185,20 @@ bool Face::runGraphite(Segment *seg, con
             res &= seg->initCollisions();
         if (res)
             res &= aSilf->runGraphite(seg, aSilf->positionPass(), aSilf->numPasses(), false);
     }
 
 #if !defined GRAPHITE2_NTRACING
     if (dbgout)
 {
-        seg->positionSlots(0, 0, 0, aSilf->dir());
+        seg->positionSlots(0, 0, 0, seg->currdir());
         *dbgout             << json::item
                             << json::close // Close up the passes array
+                << "outputdir" << (seg->currdir() ? "rtl" : "ltr")
                 << "output" << json::array;
         for(Slot * s = seg->first(); s; s = s->next())
             *dbgout     << dslot(seg, s);
         *dbgout         << json::close
                 << "advance" << seg->advance()
                 << "chars"   << json::array;
         for(size_t i = 0, n = seg->charInfoCount(); i != n; ++i)
             *dbgout     << json::flat << *seg->charinfo(i);
deleted file mode 100644
--- a/gfx/graphite2/src/GlyphFaceCache.cpp
+++ /dev/null
@@ -1,149 +0,0 @@
-/*  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 "inc/GlyphFaceCache.h"
-#include "graphite2/Font.h"
-#include "inc/Face.h"     //for the tags
-#include "inc/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 (TtfUtil::LocaLookup(m_nGlyphs-1, m_pLoca, m_lLoca, m_pHead) == size_t(-1))
-    	return false; // This will fail if m_nGlyphs is wildly out of range.
-
-    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::read<uint32>(m_pGloc);
-		if (version != 0x00010000) return false;
-
-		const uint16 locFlags = be::read<uint16>(m_pGloc);
-		m_numAttrs = be::read<uint16>(m_pGloc);
-		if (m_numAttrs > 0x1000) return false;                  // is this hard limit appropriate?
-
-		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;
-}
--- a/gfx/graphite2/src/Intervals.cpp
+++ b/gfx/graphite2/src/Intervals.cpp
@@ -54,31 +54,36 @@ inline
 Zones::Exclusion & Zones::Exclusion::operator += (Exclusion const & rhs) {
     c += rhs.c; sm += rhs.sm; smx += rhs.smx; open = false;
     return *this;
 }
 
 inline
 uint8 Zones::Exclusion::outcode(float val) const {
     float p = val;
-    return ((p >= xm) << 1) | (p < x);
+    //float d = std::numeric_limits<float>::epsilon();
+    float d = 0.;
+    return ((p - xm >= d) << 1) | (x - p > d);
 }
 
 void Zones::exclude_with_margins(float xmin, float xmax, int axis) {
     remove(xmin, xmax);
     weightedAxis(axis, xmin-_margin_len, xmin, 0, 0, _margin_weight, xmin-_margin_len, 0, 0, false);
     weightedAxis(axis, xmax, xmax+_margin_len, 0, 0, _margin_weight, xmax+_margin_len, 0, 0, false);
 }
 
 namespace
 {
 
 inline
 bool separated(float a, float b) {
     return a != b;
+    //int exp;
+    //float res = frexpf(fabs(a - b), &exp);
+    //return (*(unsigned int *)(&res) > 4);
     //return std::fabs(a-b) > std::numeric_limits<float>::epsilon(); // std::epsilon may not work. but 0.5 fails exising 64 bit tests
     //return std::fabs(a-b) > 0.5f;
 }
 
 }
 
 void Zones::insert(Exclusion e)
 {
old mode 100644
new mode 100755
--- a/gfx/graphite2/src/Pass.cpp
+++ b/gfx/graphite2/src/Pass.cpp
@@ -518,17 +518,17 @@ void Pass::findNDoRule(Slot * & slot, Ma
         {
             if (fsm.rules.size() != 0)
             {
                 *fsm.dbgout << json::item << json::object;
                 dumpRuleEventConsidered(fsm, *r);
                 if (r != re)
                 {
                     const int adv = doAction(r->rule->action, slot, m);
-                    dumpRuleEventOutput(fsm, m, *r->rule, slot);
+                    dumpRuleEventOutput(fsm, *r->rule, slot);
                     if (r->rule->action->deletes()) fsm.slots.collectGarbage(slot);
                     adjustSlot(adv, slot, fsm.slots);
                     *fsm.dbgout << "cursor" << objectid(dslot(&fsm.slots.segment, slot))
                             << json::close; // Close RuelEvent object
 
                     return;
                 }
                 else
@@ -574,17 +574,17 @@ void Pass::dumpRuleEventConsidered(const
                         << "start" << objectid(dslot(&fsm.slots.segment, input_slot(fsm.slots, -r->rule->preContext)))
                         << "length" << r->rule->sort
                         << json::close  // close "input"
                     << json::close; // close Rule object
     }
 }
 
 
-void Pass::dumpRuleEventOutput(const FiniteStateMachine & fsm, Machine & m, const Rule & r, Slot * const last_slot) const
+void Pass::dumpRuleEventOutput(const FiniteStateMachine & fsm, const Rule & r, Slot * const last_slot) const
 {
     *fsm.dbgout     << json::item << json::flat << json::object
                         << "id"     << &r - m_rules
                         << "failed" << false
                         << "input" << json::flat << json::object
                             << "start" << objectid(dslot(&fsm.slots.segment, input_slot(fsm.slots, 0)))
                             << "length" << r.sort - r.preContext
                             << json::close // close "input"
@@ -592,17 +592,17 @@ void Pass::dumpRuleEventOutput(const Fin
                 << json::close // close considered array
                 << "output" << json::object
                     << "range" << json::flat << json::object
                         << "start"  << objectid(dslot(&fsm.slots.segment, input_slot(fsm.slots, 0)))
                         << "end"    << objectid(dslot(&fsm.slots.segment, last_slot))
                     << json::close // close "input"
                     << "slots"  << json::array;
     const Position rsb_prepos = last_slot ? last_slot->origin() : fsm.slots.segment.advance();
-    fsm.slots.segment.positionSlots(0, 0, 0, m.slotMap().dir());
+    fsm.slots.segment.positionSlots(0, 0, 0, fsm.slots.segment.currdir());
 
     for(Slot * slot = output_slot(fsm.slots, 0); slot != last_slot; slot = slot->next())
         *fsm.dbgout     << dslot(&fsm.slots.segment, slot);
     *fsm.dbgout         << json::close  // close "slots"
                     << "postshift"  << (last_slot ? last_slot->origin() : fsm.slots.segment.advance()) - rsb_prepos
                 << json::close;         // close "output" object
 
 }
@@ -874,18 +874,21 @@ bool Pass::collisionKern(Segment *seg, i
 
     for (Slot *s = seg->first(); s; s = s->next())
     {
         if (!gc.check(s->gid()))
             return false;
         const SlotCollision * c = seg->collisionInfo(s);
         const Rect &bbox = seg->theGlyphBBoxTemporary(s->gid());
         float y = s->origin().y + c->shift().y;
-        ymax = max(y + bbox.tr.y, ymax);
-        ymin = min(y + bbox.bl.y, ymin);
+        if (!(c->flags() & SlotCollision::COLL_ISSPACE))
+        {
+            ymax = max(y + bbox.tr.y, ymax);
+            ymin = min(y + bbox.bl.y, ymin);
+        }
         if (start && (c->flags() & (SlotCollision::COLL_KERN | SlotCollision::COLL_FIX))
                         == (SlotCollision::COLL_KERN | SlotCollision::COLL_FIX))
             resolveKern(seg, s, start, dir, ymin, ymax, dbgout);
         if (c->flags() & SlotCollision::COLL_END)
             start = NULL;
         if (c->flags() & SlotCollision::COLL_START)
             start = s;
     }
@@ -957,18 +960,18 @@ bool Pass::resolveCollisions(Segment *se
         base = base->attachedTo();
     Position zero(0., 0.);
     
     // Look for collisions with the neighboring glyphs.
     for (nbor = start; nbor; nbor = isRev ? nbor->prev() : nbor->next())
     {
         SlotCollision *cNbor = seg->collisionInfo(nbor);
         bool sameCluster = nbor->isChildOf(base);
-        if (nbor != slotFix         // don't process if this is the slot of interest
-                      && !(cNbor->flags() & SlotCollision::COLL_IGNORE)    // don't process if ignoring
+        if (nbor != slotFix         						// don't process if this is the slot of interest
+                      && !(cNbor->ignore())    				// don't process if ignoring
                       && (nbor == base || sameCluster       // process if in the same cluster as slotFix
                             || !inKernCluster(seg, nbor)    // or this cluster is not to be kerned
                             || (rtl ^ ignoreForKern))       // or it comes before(ltr) or after(rtl)
                       && (!isRev    // if processing forwards then good to merge otherwise only:
                             || !(cNbor->flags() & SlotCollision::COLL_FIX)     // merge in immovable stuff
                             || ((cNbor->flags() & SlotCollision::COLL_KERN) && !sameCluster)     // ignore other kernable clusters
                             || (cNbor->flags() & SlotCollision::COLL_ISCOL))   // test against other collided glyphs
                       && !coll.mergeSlot(seg, nbor, cNbor->shift(), !ignoreForKern, sameCluster, collides, false, dbgout))
@@ -1047,31 +1050,31 @@ float Pass::resolveKern(Segment *seg, Sl
     for (nbor = slotFix->next(); nbor; nbor = nbor->next())
     {
         if (nbor->isChildOf(base))
             continue;
         if (!gc.check(nbor->gid()))
             return 0.;
         const Rect &bb = seg->theGlyphBBoxTemporary(nbor->gid());
         SlotCollision *cNbor = seg->collisionInfo(nbor);
-        if (bb.bl.y == 0.f && bb.tr.y == 0.f)
+        if ((bb.bl.y == 0.f && bb.tr.y == 0.f) || (cNbor->flags() & SlotCollision::COLL_ISSPACE))
         {
             if (m_kernColls == InWord)
                 break;
             // Add space for a space glyph.
             currSpace += nbor->advance();
             ++space_count;
         }
         else
         {
             space_count = 0; 
             float y = nbor->origin().y + cNbor->shift().y;
             ymax = max(y + bb.tr.y, ymax);
             ymin = min(y + bb.bl.y, ymin);
-            if (nbor != slotFix && !(cNbor->flags() & SlotCollision::COLL_IGNORE))
+            if (nbor != slotFix && !cNbor->ignore())
             {
                 seenEnd = true;
                 if (!isInit)
                 {
                     if (!coll.initSlot(seg, slotFix, cFix->limit(), cFix->margin(),
                                     cFix->shift(), cFix->offset(), dir, ymin, ymax, dbgout))
                         return 0.;
                     isInit = true;
@@ -1084,17 +1087,17 @@ float Pass::resolveKern(Segment *seg, Sl
             if (seenEnd && space_count < 2)
                 break;
             else
                 seenEnd = true;
         }
     }
     if (collides)
     {
-        Position mv = coll.resolve(seg, slotFix, dir, cFix->margin(), dbgout);
+        Position mv = coll.resolve(seg, slotFix, dir, dbgout);
         coll.shift(mv, dir);
         Position delta = slotFix->advancePos() + mv - cFix->shift();
         slotFix->advance(delta);
         cFix->setShift(mv);
         return mv.x;
     }
     return 0.;
 }
deleted file mode 100644
--- a/gfx/graphite2/src/Rule.cpp
+++ /dev/null
@@ -1,31 +0,0 @@
-/*  GRAPHITE2 LICENSING
-
-    Copyright 2011, 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 "inc/Rule.h"
-#include "inc/Segment.h"
-
-using namespace graphite2;
--- a/gfx/graphite2/src/Segment.cpp
+++ b/gfx/graphite2/src/Segment.cpp
@@ -407,18 +407,19 @@ void Segment::linkClusters(Slot *s, Slot
     }
 }
 
 Position Segment::positionSlots(const Font *font, Slot * iStart, Slot * iEnd, bool isRtl, bool isFinal)
 {
     Position currpos(0., 0.);
     float clusterMin = 0.;
     Rect bbox;
+    bool reorder = (currdir() != isRtl);
 
-    if (currdir() != isRtl)
+    if (reorder)
     {
         Slot *temp;
         reverseSlots();
         temp = iStart;
         iStart = iEnd;
         iEnd = temp;
     }
     if (!iStart)    iStart = m_first;
@@ -438,16 +439,18 @@ Position Segment::positionSlots(const Fo
     else
     {
         for (Slot * s = iStart, * const end = iEnd->next(); s && s != end; s = s->next())
         {
             if (s->isBase())
                 currpos = s->finalise(this, font, currpos, bbox, 0, clusterMin = currpos.x, isRtl, isFinal);
         }
     }
+    if (reorder)
+        reverseSlots();
     return currpos;
 }
 
 
 void Segment::associateChars(int offset, int numChars)
 {
     int i = 0, j = 0;
     CharInfo *c, *cend;
--- a/gfx/graphite2/src/Silf.cpp
+++ b/gfx/graphite2/src/Silf.cpp
@@ -379,19 +379,22 @@ bool Silf::runGraphite(Segment *seg, uin
     {
         // bidi and mirroring
         if (i == lbidi)
         {
 #if !defined GRAPHITE2_NTRACING
             if (dbgout)
             {
                 *dbgout << json::item << json::object
+//							<< "pindex" << i   // for debugging
                             << "id"     << -1
+                            << "slotsdir" << (seg->currdir() ? "rtl" : "ltr")
+                            << "passdir" << (m_dir & 1 ? "rtl" : "ltr")
                             << "slots"  << json::array;
-                seg->positionSlots(0, 0, 0, m_dir);
+                seg->positionSlots(0, 0, 0, seg->currdir());
                 for(Slot * s = seg->first(); s; s = s->next())
                     *dbgout     << dslot(seg, s);
                 *dbgout         << json::close
                             << "rules"  << json::array << json::close
                             << json::close;
             }
 #endif
             if (seg->currdir() != (m_dir & 1))
@@ -403,19 +406,22 @@ bool Silf::runGraphite(Segment *seg, uin
         --lastPass;
         continue;
         }
 
 #if !defined GRAPHITE2_NTRACING
         if (dbgout)
         {
             *dbgout << json::item << json::object
+//						<< "pindex" << i   // for debugging
                         << "id"     << i+1
+                        << "slotsdir" << (seg->currdir() ? "rtl" : "ltr")
+                        << "passdir" << ((m_dir & 1) ^ m_passes[i].reverseDir() ? "rtl" : "ltr")
                         << "slots"  << json::array;
-            seg->positionSlots(0, 0, 0, m_dir);
+            seg->positionSlots(0, 0, 0, seg->currdir());
             for(Slot * s = seg->first(); s; s = s->next())
                 *dbgout     << dslot(seg, s);
             *dbgout         << json::close;
         }
 #endif
 
         // test whether to reorder, prepare for positioning
         bool reverse = (lbidi == 0xFF) && (seg->currdir() != ((m_dir & 1) ^ m_passes[i].reverseDir()));
deleted file mode 100644
--- a/gfx/graphite2/src/XmlTraceLog.cpp
+++ /dev/null
@@ -1,219 +0,0 @@
-/*  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 <cstdarg>
-#include "Main.h"
-#include "XmlTraceLog.h"
-
-
-using namespace graphite2;
-
-#ifndef DISABLE_TRACING
-
-/*static*/ XmlTraceLog XmlTraceLog::sm_NullLog(NULL, NULL, GRLOG_NONE);
-XmlTraceLog * XmlTraceLog::sLog = &sm_NullLog;
-
-XmlTraceLog::XmlTraceLog(FILE * file, const char * ns, GrLogMask logMask)
-                         : m_file(file), m_depth(0), m_mask(logMask)
-{
-    if (!m_file) return;
-    int deep = 0;
-#ifdef ENABLE_DEEP_TRACING
-    deep = 1;
-#endif
-    fprintf(m_file, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<%s xmlns=\"%s\" mask=\"%x\" deep=\"%d\">",
-            xmlTraceLogElements[ElementTopLevel].mName, ns, logMask, deep);
-    m_elementStack[m_depth++] = ElementTopLevel;
-    m_elementEmpty = true;
-    m_inElement = false;
-    m_lastNodeText = false;
-}
-
-XmlTraceLog::~XmlTraceLog()
-{
-    if (m_file && m_file != stdout && m_file != stderr)
-    {
-        assert(m_depth == 1);
-        while (m_depth > 0)
-        {
-            closeElement(m_elementStack[m_depth-1]);
-        }
-        fclose(m_file);
-        m_file = NULL;
-    }
-}
-
-void XmlTraceLog::addSingleElement(XmlTraceLogElement eId, const int value)
-{
-    if (!m_file) return;
-    if (m_inElement)
-    {
-        if (xmlTraceLogElements[m_elementStack[m_depth-1]].mFlags & m_mask)
-            fprintf(m_file, ">");
-    }
-    if (xmlTraceLogElements[eId].mFlags & m_mask)
-    {
-        if (!m_lastNodeText)
-        {
-            fprintf(m_file, "\n");
-            for (size_t i = 0; i < m_depth; i++)
-            {
-                fprintf(m_file, " ");
-            }
-        }
-        fprintf(m_file, "<%s val=\"%d\"/>", xmlTraceLogElements[eId].mName, value);
-    }
-    m_inElement = false;
-    m_lastNodeText = false;
-}
-    
-void XmlTraceLog::writeElementArray(XmlTraceLogElement eId, XmlTraceLogAttribute aId, int16 values [], size_t length)
-{
-    if (!m_file) return;
-    if (xmlTraceLogElements[eId].mFlags & m_mask)
-    {
-        if(m_inElement && xmlTraceLogElements[m_elementStack[m_depth-1]].mFlags & m_mask)
-        {
-            fprintf(m_file, ">");
-            m_inElement = false;
-        }
-        // line break after 5 columns
-        for (size_t i = 0; i < length; i++)
-        {
-            if (i % 5 == 0)
-            {
-                fprintf(m_file, "\n");
-                for (size_t j = 0; j < m_depth; j++)
-                {
-                    fprintf(m_file, " ");
-                }
-            }
-            fprintf(m_file, "<%s index=\"%d\" %s=\"%d\"/>", xmlTraceLogElements[eId].mName, int(i),
-                xmlTraceLogAttributes[aId], (int)values[i]);
-        }
-    }
-}
-
-void XmlTraceLog::writeText(const char * utf8)
-{
-    if (!m_file) return;
-    if (m_inElement)
-    {
-        if (xmlTraceLogElements[m_elementStack[m_depth-1]].mFlags & m_mask)
-        {
-            fprintf(m_file, ">");
-        }
-        m_inElement = false;
-    }
-    if (xmlTraceLogElements[m_elementStack[m_depth-1]].mFlags & m_mask)
-    {
-        escapeIfNeeded(utf8);
-    }
-    m_lastNodeText = true;
-}
-
-void XmlTraceLog::writeUnicode(const uint32 code)
-{
-    if (!m_file) return;
-    if (m_inElement)
-    {
-        if (xmlTraceLogElements[m_elementStack[m_depth-1]].mFlags & m_mask)
-        {
-            fprintf(m_file, ">");
-        }
-        m_inElement = false;
-    }
-    if (xmlTraceLogElements[m_elementStack[m_depth-1]].mFlags & m_mask)
-    {
-        fprintf(m_file, "&#x%02x;", code);
-    }
-    m_lastNodeText = true;
-}
-
-void XmlTraceLog::escapeIfNeeded(const char * data)
-{
-    size_t length = strlen(data);
-    for (size_t i = 0; i < length; i++)
-    {
-        switch (data[i])
-        {
-            case '<':
-                fprintf(m_file, "&lt;");
-                break;
-            case '>':
-                fprintf(m_file, "&gt;");
-                break;
-            case '&':
-                fprintf(m_file, "&amp;");
-                break;
-            case '"':
-                fprintf(m_file, "&#34;");
-                break;
-            default:
-                fprintf(m_file, "%c", data[i]);
-        }
-    }
-}
-
-static const int MAX_MSG_LEN = 1024;
-
-void XmlTraceLog::error(const char * msg, ...)
-{
-    if (!m_file) return;
-    openElement(ElementError);
-    va_list args;
-    va_start(args, msg);
-    char buffer[MAX_MSG_LEN];
-#ifndef NDEBUG
-    int len =
-#endif
-        vsnprintf(buffer, MAX_MSG_LEN, msg, args);
-    assert(len + 1 < MAX_MSG_LEN);
-    writeText(buffer);
-    va_end(args);
-    closeElement(ElementError);
-}
-
-void XmlTraceLog::warning(const char * msg, ...)
-{
-    if (!m_file) return;
-    openElement(ElementWarning);
-    va_list args;
-    va_start(args, msg);
-    char buffer[MAX_MSG_LEN];
-#ifndef NDEBUG
-    int len =
-#endif
-        vsnprintf(buffer, MAX_MSG_LEN, msg, args);
-    assert(len + 1 < MAX_MSG_LEN);
-    writeText(buffer);
-    va_end(args);
-    closeElement(ElementWarning);
-}
-
-#endif		//!DISABLE_TRACING
deleted file mode 100644
--- a/gfx/graphite2/src/XmlTraceLogTags.cpp
+++ /dev/null
@@ -1,169 +0,0 @@
-/*  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 "XmlTraceLogTags.h"
-
-
-using namespace graphite2;
-
-#ifndef DISABLE_TRACING
-
-
-// start this at same line number as in XmlTraceLogTags.h
-const XmlTraceLogTag graphite2::xmlTraceLogElements[NumElements] = {
-    XmlTraceLogTag("Graphite2Log", GRLOG_ALL),
-    XmlTraceLogTag("Face", GRLOG_FACE | GRLOG_PASS),
-    XmlTraceLogTag("Glyphs", GRLOG_FACE),
-    XmlTraceLogTag("GlyphFace", GRLOG_FACE),
-    XmlTraceLogTag("Attr", GRLOG_FACE),
-    XmlTraceLogTag("Silf", GRLOG_FACE | GRLOG_PASS),
-    XmlTraceLogTag("SilfSub", GRLOG_FACE | GRLOG_PASS),
-    XmlTraceLogTag("Pass", GRLOG_FACE | GRLOG_PASS),
-    XmlTraceLogTag("Pseudo", GRLOG_FACE | GRLOG_PASS),
-    XmlTraceLogTag("ClassMap", GRLOG_FACE | GRLOG_PASS),
-    XmlTraceLogTag("LookupClass", GRLOG_FACE | GRLOG_PASS),
-    XmlTraceLogTag("Lookup", GRLOG_FACE | GRLOG_PASS),
-    XmlTraceLogTag("Range", GRLOG_PASS),
-    XmlTraceLogTag("RuleMap", GRLOG_PASS),
-    XmlTraceLogTag("Rule", GRLOG_PASS),
-    XmlTraceLogTag("StartState", GRLOG_PASS),
-    XmlTraceLogTag("StateTransitions", GRLOG_PASS),
-    XmlTraceLogTag("TR", GRLOG_PASS),
-    XmlTraceLogTag("TD", GRLOG_PASS),
-    XmlTraceLogTag("Constraint", GRLOG_PASS),
-    XmlTraceLogTag("Constraints", GRLOG_PASS),
-    XmlTraceLogTag("Actions", GRLOG_PASS),
-    XmlTraceLogTag("Action", GRLOG_PASS),
-    XmlTraceLogTag("Features", GRLOG_PASS),
-    XmlTraceLogTag("Feature", GRLOG_PASS),
-    XmlTraceLogTag("FeatureSetting", GRLOG_PASS),
-    XmlTraceLogTag("Segment", GRLOG_SEGMENT),
-    XmlTraceLogTag("Slot", GRLOG_SEGMENT),
-    XmlTraceLogTag("Text", GRLOG_SEGMENT),
-    XmlTraceLogTag("OpCode", GRLOG_OPCODE),
-    XmlTraceLogTag("TestRule", GRLOG_OPCODE),
-    XmlTraceLogTag("DoRule", GRLOG_OPCODE),
-    XmlTraceLogTag("RunPass", GRLOG_OPCODE),
-    XmlTraceLogTag("Params", GRLOG_OPCODE),
-    XmlTraceLogTag("Push", GRLOG_OPCODE),
-    XmlTraceLogTag("SubSeg", GRLOG_SEGMENT),
-    XmlTraceLogTag("SegCache", GRLOG_CACHE),
-    XmlTraceLogTag("SegCacheEntry", GRLOG_CACHE),
-    XmlTraceLogTag("Glyph", GRLOG_CACHE),
-    XmlTraceLogTag("PassResult", GRLOG_OPCODE),
-
-    XmlTraceLogTag("Error", GRLOG_ALL),
-    XmlTraceLogTag("Warning", GRLOG_ALL)
-    // Nothing corresponds to NumElements
-};
-
-
-
-// start this at same line number as in XmlTraceLogTags.h
-const char * graphite2::xmlTraceLogAttributes[NumAttributes] = {
-    "index",
-    "version",
-    "major",
-    "minor",
-    "num",
-    "glyphId",
-    "advance",
-    "advanceX",
-    "advanceY",
-    "attrId",
-    "attrVal",
-    "compilerMajor",
-    "compilerMinor",
-    "numPasses",//AttrNumPasses,
-    "subPass",//AttrSubPass,
-    "posPass",//AttrPosPass,
-    "justPass",//AttrJustPass,
-    "bidiPass",//AttrBidiPass,
-    "preContext",//AttrPreContext,
-    "postContext",//AttrPostContext,
-    "pseudoGlyph",//AttrPseudoGlyph,
-    "breakWeight",//AttrBreakWeight,
-    "directionality",//AttrDirectionality,
-    "numJustLevels",//AttrNumJustLevels,
-    "numLigCompAttr",//AttrLigComp,
-    "numUserDefinedAttr",//AttrUserDefn,
-    "maxNumLigComp",//AttrNumLigComp,
-    "numCriticalFeatures",//AttrNumCritFeatures,
-    "numScripts",//AttrNumScripts
-    "lineBreakglyph",//,AttrLBGlyph,
-    "numPseudo",
-    "numClasses",
-    "numLinear",
-    "passId",//AttrPassId,
-    "flags",//AttrFlags,
-    "maxRuleLoop",//AttrMaxRuleLoop,
-    "maxRuleContext",//AttrMaxRuleContext,
-    "maxBackup",//AttrMaxBackup,
-    "numRules",//AttrNumRules,
-    "numRows",//AttrNumRows,
-    "numTransitionStates",//AttrNumTransition,
-    "numSuccessStates",//AttrNumSuccess,
-    "numColumns",//AttrNumColumns,
-    "numRanges",//AttrNumRanges,
-    "minPrecontext",//AttrMinPrecontext,
-    "maxPrecontext",//AttrMaxPrecontext,
-    "firstId",
-    "lastId",
-    "colId",
-    "successId",
-    "ruleId",
-    "contextLength",
-    "state",
-    "value",
-    "sortKey",
-    "precontext",
-    "action",
-    "actionCode",
-    "arg1",
-    "arg2",
-    "arg3",
-    "arg4",
-    "arg5",
-    "arg6",
-    "arg7",
-    "arg8",
-    "label",
-    "length",
-    "x",
-    "y",
-    "before",
-    "after",
-    "encoding",
-    "name",
-    "result",
-    "default",
-    "accessCount",
-    "lastAccess",
-    "misses"
-};
-
-#endif
deleted file mode 100644
--- a/gfx/graphite2/src/inc/Bidi.h
+++ /dev/null
@@ -1,126 +0,0 @@
-/*  GRAPHITE2 LICENSING
-
-    Copyright 2013, 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 BracketPair
-{
-public:
-    BracketPair(uint16 g, Slot *s, uint8 b, BracketPair *p, BracketPair *l) : _open(s), _close(0), _parent(p), _next(0), _prev(l), _gid(g), _mask(0), _before(b) {};
-    uint16 gid() const { return _gid; }
-    Slot *open() const { return _open; }
-    Slot *close() const { return _close; }
-    uint8 mask() const { return _mask; }
-    int8 before() const { return _before; }
-    BracketPair *parent() const { return _parent; }
-    void close(Slot *s) { _close = s; }
-    BracketPair *next() const { return _next; }
-    BracketPair *prev() const { return _prev; }
-    void next(BracketPair *n) { _next = n; }
-    void orin(uint8 m) { _mask |= m; }
-private:
-    Slot        *   _open;          // Slot of opening paren
-    Slot        *   _close;         // Slot of closing paren
-    BracketPair *   _parent;        // pair this pair is in or NULL
-    BracketPair *   _next;          // next pair along the string
-    BracketPair *   _prev;          // pair that closed last before we opened
-    uint16          _gid;           // gid of closing paren
-    uint8           _mask;          // bitmap (2 bits) of directions within the pair
-    int8            _before;        // most recent strong type (L, R, OPP, CPP)
-};
-
-class BracketPairStack
-{
-public:
-    BracketPairStack(int s) : _stack(grzeroalloc<BracketPair>(s)), _ip(_stack - 1), _top(0), _last(0), _lastclose(0), _size(s) {}
-    ~BracketPairStack() { free(_stack); }
-
-public:
-    BracketPair *scan(uint16 gid);
-    void close(BracketPair *tos, Slot *s);
-    BracketPair *push(uint16 gid, Slot *pos, uint8 before, int prevopen);
-    void orin(uint8 mask);
-    void clear() { _ip = _stack - 1; _top = 0; _last = 0; _lastclose = 0; }
-    int size() const { return _size; }
-    BracketPair *start() const { return _stack; }
-
-    CLASS_NEW_DELETE
-
-private:
-
-    BracketPair *_stack;        // start of storage
-    BracketPair *_ip;           // where to add the next pair
-    BracketPair *_top;          // current parent
-    BracketPair *_last;         // end of next() chain
-    BracketPair *_lastclose;    // last pair to close
-    int          _size;         // capacity
-};
-
-inline BracketPair *BracketPairStack::scan(uint16 gid)
-{
-    BracketPair *res = _top;
-    while (res >= _stack)
-    {
-        if (res->gid() == gid)
-            return res;
-        res = res->parent();
-    }
-    return 0;
-}
-
-inline void BracketPairStack::close(BracketPair *tos, Slot *s) 
-{
-    for ( ; _last && _last != tos && !_last->close(); _last = _last->parent())
-    { }
-    tos->close(s);
-    _last->next(NULL);
-    _lastclose = tos;
-    _top = tos->parent();
-}
-
-inline BracketPair *BracketPairStack::push(uint16 gid, Slot *pos, uint8 before, int prevopen)
-{
-    if (++_ip - _stack < _size && _stack)
-    {
-        ::new (_ip) BracketPair(gid, pos, before, _top, prevopen ? _last : _lastclose);
-        if (_last) _last->next(_ip);
-        _last = _ip;
-    }
-    _top = _ip;
-    return _ip;
-}
-
-inline void BracketPairStack::orin(uint8 mask)
-{
-    BracketPair *t = _top;
-    for ( ; t; t = t->parent())
-        t->orin(mask);
-}
-
-}
--- a/gfx/graphite2/src/inc/Collider.h
+++ b/gfx/graphite2/src/inc/Collider.h
@@ -49,17 +49,18 @@ public:
     //  COLL_TESTONLY = 0,  // default - test other glyphs for collision with this one, but don't move this one
         COLL_FIX = 1,       // fix collisions involving this glyph
         COLL_IGNORE = 2,    // ignore this glyph altogether
         COLL_START = 4,     // start of range of possible collisions
         COLL_END = 8,       // end of range of possible collisions
         COLL_KERN = 16,     // collisions with this glyph are fixed by adding kerning space after it
         COLL_ISCOL = 32,    // this glyph has a collision
         COLL_KNOWN = 64,    // we've figured out what's happening with this glyph
-        COLL_TEMPLOCK = 128,    // Lock glyphs that have been given priority positioning
+        COLL_ISSPACE = 128,		// treat this glyph as a space with regard to kerning
+        COLL_TEMPLOCK = 256,    // Lock glyphs that have been given priority positioning
         ////COLL_JUMPABLE = 128,    // moving glyphs may jump this stationary glyph in any direction - DELETE
         ////COLL_OVERLAP = 256,    // use maxoverlap to restrict - DELETE
     };
     
     // Behavior for the collision.order attribute. To GDL this is an enum, to us it's a bitfield, with only 1 bit set
     // Allows for easier inversion.
     enum {
         SEQ_ORDER_LEFTDOWN = 1,
@@ -88,16 +89,17 @@ public:
     SLOTCOLSETINTPROP(seqAboveXoff, setSeqAboveXoff)
     SLOTCOLSETUINTPROP(seqAboveWt, setSeqAboveWt)
     SLOTCOLSETINTPROP(seqBelowXlim, setSeqBelowXlim)
     SLOTCOLSETUINTPROP(seqBelowWt, setSeqBelowWt)
     SLOTCOLSETUINTPROP(seqValignHt, setSeqValignHt)
     SLOTCOLSETUINTPROP(seqValignWt, setSeqValignWt)
 
     float getKern(int dir) const;
+    bool ignore() const;
     
 private:
     Rect        _limit;
     Position    _shift;     // adjustment within the given pass
     Position    _offset;    // total adjustment for collisions
     Position    _exclOffset;
     uint16		_margin;
     uint16		_marginWt;
@@ -186,17 +188,17 @@ class KernCollider
 {
 public:
     KernCollider(json *dbg);
     ~KernCollider() throw() { };
     bool initSlot(Segment *seg, Slot *aSlot, const Rect &constraint, float margin,
             const Position &currShift, const Position &offsetPrev, int dir,
             float ymin, float ymax, json * const dbgout);
     bool mergeSlot(Segment *seg, Slot *slot, const Position &currShift, float currSpace, int dir, json * const dbgout);
-    Position resolve(Segment *seg, Slot *slot, int dir, float margin, json * const dbgout);
+    Position resolve(Segment *seg, Slot *slot, int dir, json * const dbgout);
     void shift(const Position &mv, int dir);
 
     CLASS_NEW_DELETE;
 
 private:
     Slot *  _target;        // the glyph to fix
     Rect    _limit;
     float   _margin;
deleted file mode 100644
--- a/gfx/graphite2/src/inc/GlyphFaceCache.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/*  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 "inc/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
--- a/gfx/graphite2/src/inc/Pass.h
+++ b/gfx/graphite2/src/inc/Pass.h
@@ -69,17 +69,17 @@ private:
                      const uint16 * o_constraint, const byte *constraint_data, 
                      const uint16 * o_action, const byte * action_data,
                      Face &, enum passtype pt, Error &e);
     bool    readStates(const byte * starts, const byte * states, const byte * o_rule_map, Face &, Error &e);
     bool    readRanges(const byte * ranges, size_t num_ranges, Error &e);
     uint16  glyphToCol(const uint16 gid) const;
     bool    runFSM(FiniteStateMachine & fsm, Slot * slot) const;
     void    dumpRuleEventConsidered(const FiniteStateMachine & fsm, const RuleEntry & re) const;
-    void    dumpRuleEventOutput(const FiniteStateMachine & fsm, vm::Machine & m, const Rule & r, Slot * os) const;
+    void    dumpRuleEventOutput(const FiniteStateMachine & fsm, const Rule & r, Slot * os) const;
     void    adjustSlot(int delta, Slot * & slot_out, SlotMap &) const;
     bool    collisionShift(Segment *seg, int dir, json * const dbgout) const;
     bool    collisionKern(Segment *seg, int dir, json * const dbgout) const;
     bool    collisionFinish(Segment *seg, GR_MAYBE_UNUSED json * const dbgout) const;
     bool    resolveCollisions(Segment *seg, Slot *slot, Slot *start, ShiftCollider &coll, bool isRev,
                      int dir, bool &moved, bool &hasCol, json * const dbgout) const;
     float   resolveKern(Segment *seg, Slot *slot, Slot *start, int dir,
                      float &ymin, float &ymax, json *const dbgout) const;
deleted file mode 100644
--- a/gfx/graphite2/src/inc/Shrinker.h
+++ /dev/null
@@ -1,119 +0,0 @@
-/*  Copyright (c) 2012, Siyuan Fu <fusiyuan2010@gmail.com>
-    Copyright (c) 2015, SIL International
-    All rights reserved.
-    
-    Redistribution and use in source and binary forms, with or without
-    modification, are permitted provided that the following conditions are met:
-    
-    1. Redistributions of source code must retain the above copyright notice,
-       this list of conditions and the following disclaimer.
-    
-    2. Redistributions in binary form must reproduce the above copyright
-       notice, this list of conditions and the following disclaimer in the
-       documentation and/or other materials provided with the distribution.
-    
-    3. Neither the name of the copyright holder nor the names of its
-       contributors may be used to endorse or promote products derived from
-       this software without specific prior written permission.
-    
-    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
-    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
-    ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 
-    LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
-    CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
-    SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
-    INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
-    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
-    ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
-    POSSIBILITY OF SUCH DAMAGE.
-*/
-
-#pragma once
-
-#include <cassert>
-#include <cstddef>
-#include <cstring>
-
-#include <iterator>
-
-//the code from LZ4
-#if (GCC_VERSION >= 302) || (__INTEL_COMPILER >= 800) || defined(__clang__)
-# define expect(expr,value)    (__builtin_expect ((expr),(value)) )
-#else
-# define expect(expr,value)    (expr)
-#endif
-#define likely(expr)     expect((expr) != 0, 1)
-#define unlikely(expr)   expect((expr) != 0, 0)
-////////////////////
-
-
-namespace
-{
-
-#if defined(_MSC_VER)
-typedef unsigned __int8 u8;
-typedef unsigned __int16 u16;
-typedef unsigned __int32 u32;
-typedef unsigned __int64 u64;
-#else
-#include <stdint.h>
-typedef uint8_t u8;
-typedef uint16_t u16;
-typedef uint32_t u32;
-typedef uint64_t u64;
-#endif
-
-ptrdiff_t const     MINMATCH  = 4;
-
-template<int S>
-inline 
-void unaligned_copy(void * d, void const * s) {
-  ::memcpy(d, s, S);
-}
-
-inline
-u8 * memcpy_nooverlap(u8 * d, u8 const * s, size_t n) {
-    size_t const WS = sizeof(unsigned long);
-    u8 const * e = s + n;
-    do 
-    {
-        unaligned_copy<WS>(d, s);
-        d += WS;
-        s += WS;
-    }
-    while (s < e);
-    d-=(s-e);
-    
-    return d;
-}
-
-
-inline
-u8 * memcpy_nooverlap_surpass(u8 * d, u8 const * s, size_t n) {
-    size_t const WS = sizeof(unsigned long);
-    size_t wn = n/WS;
-    while (wn--) 
-    {
-        unaligned_copy<WS>(d, s);
-        d += WS;
-        s += WS;
-    }
-    n &= WS-1;
-    while (n--) {*d++ = *s++; }
-    
-    return d;
-}
-
-
-inline 
-u8 * memcpy_(u8 * d, u8 const * s, size_t n) {
-    if (likely(d>s+sizeof(unsigned long)))
-        return memcpy_nooverlap(d,s,n);
-    else while (n--) *d++ = *s++;
-    return d;
-}
-
-} // end of anonymous namespace
-
-
old mode 100644
new mode 100755
--- a/gfx/graphite2/src/moz.build
+++ b/gfx/graphite2/src/moz.build
@@ -18,17 +18,16 @@ if CONFIG['GNU_CC']:
     ]
 else:
     UNIFIED_SOURCES += [
         'call_machine.cpp'
     ]
 
 # This should contain all of the _SOURCES from files.mk, except *_machine.cpp
 UNIFIED_SOURCES += [
-    'Bidi.cpp',
     'CachedFace.cpp',
     'CmapCache.cpp',
     'Code.cpp',
     'Collider.cpp',
     'Decompressor.cpp',
     'Face.cpp',
     'FeatureMap.cpp',
     'FileFace.cpp',
--- a/gfx/thebes/gfxFont.cpp
+++ b/gfx/thebes/gfxFont.cpp
@@ -42,17 +42,16 @@
 #include "gfx2DGlue.h"
 
 #include "GreekCasing.h"
 
 #include "cairo.h"
 
 #include "harfbuzz/hb.h"
 #include "harfbuzz/hb-ot.h"
-#include "graphite2/Font.h"
 
 #include <algorithm>
 #include <limits>
 #include <cmath>
 
 using namespace mozilla;
 using namespace mozilla::gfx;
 using namespace mozilla::unicode;