summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--gnu-system.am1
-rw-r--r--gnu/packages/gnuzilla.scm3
-rw-r--r--gnu/packages/patches/icecat-update-graphite2-pt2.patch861
3 files changed, 864 insertions, 1 deletions
diff --git a/gnu-system.am b/gnu-system.am
index 526e991beb..61ee02fdb4 100644
--- a/gnu-system.am
+++ b/gnu-system.am
@@ -525,6 +525,7 @@ dist_patch_DATA =						\
   gnu/packages/patches/hydra-disable-darcs-test.patch		\
   gnu/packages/patches/icecat-avoid-bundled-includes.patch	\
   gnu/packages/patches/icecat-update-graphite2.patch		\
+  gnu/packages/patches/icecat-update-graphite2-pt2.patch	\
   gnu/packages/patches/icecat-re-enable-DHE-cipher-suites.patch	\
   gnu/packages/patches/icu4c-CVE-2014-6585.patch		\
   gnu/packages/patches/icu4c-CVE-2015-1270.patch		\
diff --git a/gnu/packages/gnuzilla.scm b/gnu/packages/gnuzilla.scm
index ec97491cd7..1a2057a343 100644
--- a/gnu/packages/gnuzilla.scm
+++ b/gnu/packages/gnuzilla.scm
@@ -290,7 +290,8 @@ standards.")
       (patches (map search-patch
                     '("icecat-avoid-bundled-includes.patch"
                       "icecat-re-enable-DHE-cipher-suites.patch"
-                      "icecat-update-graphite2.patch")))
+                      "icecat-update-graphite2.patch"
+                      "icecat-update-graphite2-pt2.patch")))
       (modules '((guix build utils)))
       (snippet
        '(begin
diff --git a/gnu/packages/patches/icecat-update-graphite2-pt2.patch b/gnu/packages/patches/icecat-update-graphite2-pt2.patch
new file mode 100644
index 0000000000..8acde75d6c
--- /dev/null
+++ b/gnu/packages/patches/icecat-update-graphite2-pt2.patch
@@ -0,0 +1,861 @@
+Copied from upstream:
+https://hg.mozilla.org/releases/mozilla-esr38/raw-rev/ec9cff7bb543
+
+# HG changeset patch
+# User Jonathan Kew <jkew@mozilla.com>
+# Date 1456760339 0
+# Node ID ec9cff7bb5439b2b4c1249ff9376d07a80172c27
+# Parent  6f4d5130238790fa5810c76ffeb9eccc65efa8c9
+Bug 1248876 - Update graphite2 to upstream release 1.3.6. r=jrmuizel a=sledru
+
+diff --git a/gfx/graphite2/README.mozilla b/gfx/graphite2/README.mozilla
+--- a/gfx/graphite2/README.mozilla
++++ b/gfx/graphite2/README.mozilla
+@@ -1,7 +1,3 @@
+-This directory contains the Graphite2 library release 1.3.5 from
+-https://github.com/silnrsi/graphite/releases/download/1.3.5/graphite2-minimal-1.3.5.tgz
++This directory contains the Graphite2 library release 1.3.6 from
++https://github.com/silnrsi/graphite/releases/download/1.3.6/graphite-minimal-1.3.6.tgz
+ See gfx/graphite2/moz-gr-update.sh for update procedure.
+-
+-Also includes two post-1.3.5 fixes:
+-a8b3ac2aed0eb132cd80efe7de88f8153e73c829
+-e569e28d83491fedb31b9220493f3c07f6ec6d80
+diff --git a/gfx/graphite2/include/graphite2/Font.h b/gfx/graphite2/include/graphite2/Font.h
+--- 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  5
++#define GR2_VERSION_BUGFIX  6
+ 
+ #ifdef __cplusplus
+ extern "C"
+ {
+ #endif
+ 
+ typedef struct gr_face          gr_face;
+ typedef struct gr_font          gr_font;
+diff --git a/gfx/graphite2/moz-gr-update.sh b/gfx/graphite2/moz-gr-update.sh
+--- a/gfx/graphite2/moz-gr-update.sh
++++ b/gfx/graphite2/moz-gr-update.sh
+@@ -14,17 +14,17 @@
+ RELEASE=$1
+ 
+ if [ "x$RELEASE" == "x" ]
+ then
+     echo "Must provide the version number to be used."
+     exit 1
+ fi
+ 
+-TARBALL="https://github.com/silnrsi/graphite/releases/download/$RELEASE/graphite2-minimal-$RELEASE.tgz"
++TARBALL="https://github.com/silnrsi/graphite/releases/download/$RELEASE/graphite-minimal-$RELEASE.tgz"
+ 
+ foo=`basename $0`
+ TMPFILE=`mktemp -t ${foo}` || exit 1
+ 
+ curl -L "$TARBALL" -o "$TMPFILE"
+ tar -x -z -C gfx/graphite2/ --strip-components 1 -f "$TMPFILE" || exit 1
+ rm "$TMPFILE"
+ 
+diff --git a/gfx/graphite2/src/CmapCache.cpp b/gfx/graphite2/src/CmapCache.cpp
+--- a/gfx/graphite2/src/CmapCache.cpp
++++ b/gfx/graphite2/src/CmapCache.cpp
+@@ -33,43 +33,43 @@ of the License or (at your option) any l
+ 
+ 
+ using namespace graphite2;
+ 
+ const void * bmp_subtable(const Face::Table & cmap)
+ {
+     const void * stbl;
+     if (!cmap.size()) return 0;
+-    if (TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 3, 1, cmap.size()), cmap.size())
+-     || TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 3, cmap.size()), cmap.size())
+-     || TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 2, cmap.size()), cmap.size())
+-     || TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 1, cmap.size()), cmap.size())
+-     || TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 0, cmap.size()), cmap.size()))
++    if (TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 3, 1, cmap.size()), cmap + cmap.size())
++     || TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 3, cmap.size()), cmap + cmap.size())
++     || TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 2, cmap.size()), cmap + cmap.size())
++     || TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 1, cmap.size()), cmap + cmap.size())
++     || TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 0, cmap.size()), cmap + cmap.size()))
+         return stbl;
+     return 0;
+ }
+ 
+ const void * smp_subtable(const Face::Table & cmap)
+ {
+     const void * stbl;
+     if (!cmap.size()) return 0;
+-    if (TtfUtil::CheckCmapSubtable12(stbl = TtfUtil::FindCmapSubtable(cmap, 3, 10, cmap.size()), cmap.size())
+-     || TtfUtil::CheckCmapSubtable12(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 4, cmap.size()), cmap.size()))
++    if (TtfUtil::CheckCmapSubtable12(stbl = TtfUtil::FindCmapSubtable(cmap, 3, 10, cmap.size()), cmap + cmap.size())
++     || TtfUtil::CheckCmapSubtable12(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 4, cmap.size()), cmap + cmap.size()))
+         return stbl;
+     return 0;
+ }
+ 
+ template <unsigned int (*NextCodePoint)(const void *, unsigned int, int *),
+           uint16 (*LookupCodePoint)(const void *, unsigned int, int)>
+ bool cache_subtable(uint16 * blocks[], const void * cst, const unsigned int limit)
+ {
+     int rangeKey = 0;
+     uint32          codePoint = NextCodePoint(cst, 0, &rangeKey),
+                     prevCodePoint = 0;
+-    while (codePoint != limit)
++    while (codePoint < limit)
+     {
+         unsigned int block = codePoint >> 8;
+         if (!blocks[block])
+         {
+             blocks[block] = grzeroalloc<uint16>(0x100);
+             if (!blocks[block])
+                 return false;
+         }
+diff --git a/gfx/graphite2/src/Code.cpp b/gfx/graphite2/src/Code.cpp
+--- a/gfx/graphite2/src/Code.cpp
++++ b/gfx/graphite2/src/Code.cpp
+@@ -79,18 +79,19 @@ struct context
+ 
+ 
+ class Machine::Code::decoder
+ {
+ public:
+     struct limits;
+     struct analysis
+     {
++        static const int NUMCONTEXTS = 256;
+         uint8     slotref;
+-        context   contexts[256];
++        context   contexts[NUMCONTEXTS];
+         byte      max_ref;
+         
+         analysis() : slotref(0), max_ref(0) {};
+         void set_ref(int index, bool incinsert=false) throw();
+         void set_noref(int index) throw();
+         void set_changed(int index) throw();
+ 
+     };
+@@ -363,29 +364,33 @@ opcode Machine::Code::decoder::fetch_opc
+             break;
+         case ATTR_SET :
+         case ATTR_ADD :
+         case ATTR_SUB :
+         case ATTR_SET_SLOT :
+             if (--_stack_depth < 0)
+                 failure(underfull_stack);
+             valid_upto(gr_slatMax, bc[0]);
++            if (attrCode(bc[0]) == gr_slatUserDefn)     // use IATTR for user attributes
++                failure(out_of_range_data);
+             test_context();
+             break;
+         case IATTR_SET_SLOT :
+             if (--_stack_depth < 0)
+                 failure(underfull_stack);
+             if (valid_upto(gr_slatMax, bc[0]))
+                 valid_upto(_max.attrid[bc[0]], bc[1]);
+             test_context();
+             break;
+         case PUSH_SLOT_ATTR :
+             ++_stack_depth;
+             valid_upto(gr_slatMax, bc[0]);
+             valid_upto(_rule_length, _pre_context + int8(bc[1]));
++            if (attrCode(bc[0]) == gr_slatUserDefn)     // use IATTR for user attributes
++                failure(out_of_range_data);
+             break;
+         case PUSH_GLYPH_ATTR_OBS :
+             ++_stack_depth;
+             valid_upto(_max.glyf_attrs, bc[0]);
+             valid_upto(_rule_length, _pre_context + int8(bc[1]));
+             break;
+         case PUSH_GLYPH_METRIC :
+             ++_stack_depth;
+@@ -656,24 +661,24 @@ bool Machine::Code::decoder::validate_op
+         return false;
+     }
+     return true;
+ }
+ 
+ 
+ bool Machine::Code::decoder::valid_upto(const uint16 limit, const uint16 x) const throw()
+ {
+-    const bool t = x < limit;
++    const bool t = (limit != 0) && (x < limit);
+     if (!t) failure(out_of_range_data);
+     return t;
+ }
+ 
+ bool Machine::Code::decoder::test_context() const throw()
+ {
+-    if (_pre_context >= _rule_length)
++    if (_pre_context >= _rule_length || _analysis.slotref >= analysis::NUMCONTEXTS - 1)
+     {
+         failure(out_of_range_data);
+         return false;
+     }
+     return true;
+ }
+ 
+ inline 
+@@ -681,34 +686,34 @@ void Machine::Code::failure(const status
+     release_buffers();
+     _status = s;
+ }
+ 
+ 
+ inline
+ void Machine::Code::decoder::analysis::set_ref(int index, bool incinsert) throw() {
+     if (incinsert && contexts[slotref].flags.inserted) --index;
+-    if (index + slotref < 0) return;
++    if (index + slotref < 0 || index + slotref >= NUMCONTEXTS) return;
+     contexts[index + slotref].flags.referenced = true;
+     if ((index > 0 || !contexts[index + slotref].flags.inserted) && index + slotref > max_ref) max_ref = index + slotref;
+ }
+ 
+ 
+ inline
+ void Machine::Code::decoder::analysis::set_noref(int index) throw() {
+     if (contexts[slotref].flags.inserted) --index;
+-    if (index + slotref < 0) return;
++    if (index + slotref < 0 || index + slotref >= NUMCONTEXTS) return;
+     if ((index > 0 || !contexts[index + slotref].flags.inserted) && index + slotref > max_ref) max_ref = index + slotref;
+ }
+ 
+ 
+ inline
+ void Machine::Code::decoder::analysis::set_changed(int index) throw() {
+     if (contexts[slotref].flags.inserted) --index;
+-    if (index + slotref < 0) return;
++    if (index + slotref < 0 || index + slotref >= NUMCONTEXTS) return;
+     contexts[index + slotref].flags.changed = true;
+     if ((index > 0 || !contexts[index + slotref].flags.inserted) && index + slotref > max_ref) max_ref = index + slotref;
+ }
+ 
+ 
+ void Machine::Code::release_buffers() throw()
+ {
+     if (_own)
+diff --git a/gfx/graphite2/src/GlyphCache.cpp b/gfx/graphite2/src/GlyphCache.cpp
+--- a/gfx/graphite2/src/GlyphCache.cpp
++++ b/gfx/graphite2/src/GlyphCache.cpp
+@@ -260,17 +260,17 @@ GlyphCache::Loader::Loader(const Face & 
+         _head = Face::Table();
+         return;
+     }
+ 
+     if (!dumb_font)
+     {
+         if ((m_pGlat = Face::Table(face, Tag::Glat, 0x00030000)) == NULL
+             || (m_pGloc = Face::Table(face, Tag::Gloc)) == NULL
+-            || m_pGloc.size() < 6)
++            || m_pGloc.size() < 8)
+         {
+             _head = Face::Table();
+             return;
+         }
+         const byte    * p = m_pGloc;
+         int       version = be::read<uint32>(p);
+         const uint16    flags = be::read<uint16>(p);
+         _num_attrs = be::read<uint16>(p);
+diff --git a/gfx/graphite2/src/Pass.cpp b/gfx/graphite2/src/Pass.cpp
+--- a/gfx/graphite2/src/Pass.cpp
++++ b/gfx/graphite2/src/Pass.cpp
+@@ -233,17 +233,17 @@ bool Pass::readRules(const byte * rule_m
+     m_codes = new Code [m_numRules*2];
+     const size_t prog_pool_sz = vm::Machine::Code::estimateCodeDataOut(ac_end - ac_data + rc_end - rc_data);
+     m_progs = gralloc<byte>(prog_pool_sz);
+     byte * prog_pool_free = m_progs,
+          * prog_pool_end  = m_progs + prog_pool_sz;
+     if (e.test(!(m_rules && m_codes && m_progs), E_OUTOFMEM)) return face.error(e);
+ 
+     Rule * r = m_rules + m_numRules - 1;
+-    for (size_t n = m_numRules; n; --n, --r, ac_end = ac_begin, rc_end = rc_begin)
++    for (size_t n = m_numRules; r >= m_rules; --n, --r, ac_end = ac_begin, rc_end = rc_begin)
+     {
+         face.error_context((face.error_context() & 0xFFFF00) + EC_ARULE + ((n - 1) << 24));
+         r->preContext = *--precontext;
+         r->sort       = be::peek<uint16>(--sort_key);
+ #ifndef NDEBUG
+         r->rule_idx   = n - 1;
+ #endif
+         if (r->sort > 63 || r->preContext >= r->sort || r->preContext > m_maxPreCtxt || r->preContext < m_minPreCtxt)
+@@ -405,16 +405,17 @@ bool Pass::runGraphite(vm::Machine & m, 
+         json::closer rules_array_closer(fsm.dbgout);
+ #endif
+ 
+         m.slotMap().highwater(currHigh);
+         int lc = m_iMaxLoop;
+         do
+         {
+             findNDoRule(s, m, fsm);
++            if (m.status() != Machine::finished) return false;
+             if (s && (s == m.slotMap().highwater() || m.slotMap().highpassed() || --lc == 0)) {
+                 if (!lc)
+                     s = m.slotMap().highwater();
+                 lc = m_iMaxLoop;
+                 if (s)
+                     m.slotMap().highwater(s->next());
+             }
+         } while (s);
+@@ -495,17 +496,22 @@ void Pass::findNDoRule(Slot * & slot, Ma
+ {
+     assert(slot);
+ 
+     if (runFSM(fsm, slot))
+     {
+         // Search for the first rule which passes the constraint
+         const RuleEntry *        r = fsm.rules.begin(),
+                         * const re = fsm.rules.end();
+-        while (r != re && !testConstraint(*r->rule, m)) ++r;
++        while (r != re && !testConstraint(*r->rule, m))
++        {
++            ++r;
++            if (m.status() != Machine::finished)
++                return;
++        }
+ 
+ #if !defined GRAPHITE2_NTRACING
+         if (fsm.dbgout)
+         {
+             if (fsm.rules.size() != 0)
+             {
+                 *fsm.dbgout << json::item << json::object;
+                 dumpRuleEventConsidered(fsm, *r);
+@@ -530,16 +536,17 @@ void Pass::findNDoRule(Slot * & slot, Ma
+             }
+         }
+         else
+ #endif
+         {
+             if (r != re)
+             {
+                 const int adv = doAction(r->rule->action, slot, m);
++                if (m.status() != Machine::finished) return;
+                 if (r->rule->action->deletes()) fsm.slots.collectGarbage(slot);
+                 adjustSlot(adv, slot, fsm.slots);
+                 return;
+             }
+         }
+     }
+ 
+     slot = slot->next();
+diff --git a/gfx/graphite2/src/Segment.cpp b/gfx/graphite2/src/Segment.cpp
+--- a/gfx/graphite2/src/Segment.cpp
++++ b/gfx/graphite2/src/Segment.cpp
+@@ -205,18 +205,23 @@ Slot *Segment::newSlot()
+ void Segment::freeSlot(Slot *aSlot)
+ {
+     if (m_last == aSlot) m_last = aSlot->prev();
+     if (m_first == aSlot) m_first = aSlot->next();
+     if (aSlot->attachedTo())
+         aSlot->attachedTo()->removeChild(aSlot);
+     while (aSlot->firstChild())
+     {
+-        aSlot->firstChild()->attachTo(NULL);
+-        aSlot->removeChild(aSlot->firstChild());
++        if (aSlot->firstChild()->attachedTo() == aSlot)
++        {
++            aSlot->firstChild()->attachTo(NULL);
++            aSlot->removeChild(aSlot->firstChild());
++        }
++        else
++            aSlot->firstChild(NULL);
+     }
+     // reset the slot incase it is reused
+     ::new (aSlot) Slot(aSlot->userAttrs());
+     memset(aSlot->userAttrs(), 0, m_silf->numUser() * sizeof(int16));
+     // Update generation counter for debug
+ #if !defined GRAPHITE2_NTRACING
+     if (m_face->logger())
+         ++aSlot->userAttrs()[m_silf->numUser()];
+diff --git a/gfx/graphite2/src/Slot.cpp b/gfx/graphite2/src/Slot.cpp
+--- a/gfx/graphite2/src/Slot.cpp
++++ b/gfx/graphite2/src/Slot.cpp
+@@ -192,16 +192,18 @@ int32 Slot::clusterMetric(const Segment 
+ #define SLOTGETCOLATTR(x) { SlotCollision *c = seg->collisionInfo(this); return c ? int(c-> x) : 0; }
+ 
+ int Slot::getAttr(const Segment *seg, attrCode ind, uint8 subindex) const
+ {
+     if (ind == gr_slatUserDefnV1)
+     {
+         ind = gr_slatUserDefn;
+         subindex = 0;
++        if (seg->numAttrs() == 0)
++            return 0;
+     }
+     else if (ind >= gr_slatJStretch && ind < gr_slatJStretch + 20 && ind != gr_slatJWidth)
+     {
+         int indx = ind - gr_slatJStretch;
+         return getJustify(seg, indx / 5, indx % 5);
+     }
+ 
+     switch (ind)
+@@ -269,16 +271,18 @@ int Slot::getAttr(const Segment *seg, at
+         break; }
+ 
+ void Slot::setAttr(Segment *seg, attrCode ind, uint8 subindex, int16 value, const SlotMap & map)
+ {
+     if (ind == gr_slatUserDefnV1)
+     {
+         ind = gr_slatUserDefn;
+         subindex = 0;
++        if (seg->numAttrs() == 0)
++            return;
+     }
+     else if (ind >= gr_slatJStretch && ind < gr_slatJStretch + 20 && ind != gr_slatJWidth)
+     {
+         int indx = ind - gr_slatJStretch;
+         return setJustify(seg, indx / 5, indx % 5, value);
+     }
+ 
+     switch (ind)
+@@ -416,32 +420,32 @@ bool Slot::sibling(Slot *ap)
+ }
+ 
+ bool Slot::removeChild(Slot *ap)
+ {
+     if (this == ap || !m_child) return false;
+     else if (ap == m_child)
+     {
+         Slot *nSibling = m_child->nextSibling();
+-        m_child->sibling(NULL);
++        m_child->removeSibling(nSibling);
+         m_child = nSibling;
+         return true;
+     }
+     else
+         return m_child->removeSibling(ap);
+     return true;
+ }
+ 
+ bool Slot::removeSibling(Slot *ap)
+ {
+     if (this == ap || !m_sibling) return false;
+     else if (ap == m_sibling)
+     {
+         m_sibling = m_sibling->nextSibling();
+-        ap->sibling(NULL);
++        if (m_sibling) ap->removeSibling(m_sibling);
+         return true;
+     }
+     else
+         return m_sibling->removeSibling(ap);
+     return true;
+ }
+ 
+ void Slot::setGlyph(Segment *seg, uint16 glyphid, const GlyphFace * theGlyph)
+diff --git a/gfx/graphite2/src/TtfUtil.cpp b/gfx/graphite2/src/TtfUtil.cpp
+--- a/gfx/graphite2/src/TtfUtil.cpp
++++ b/gfx/graphite2/src/TtfUtil.cpp
+@@ -884,18 +884,19 @@ const void * FindCmapSubtable(const void
+     }
+ 
+     return 0;
+ }
+ 
+ /*----------------------------------------------------------------------------------------------
+     Check the Microsoft Unicode subtable for expected values
+ ----------------------------------------------------------------------------------------------*/
+-bool CheckCmapSubtable4(const void * pCmapSubtable4, size_t table_len /*, unsigned int maxgid*/)
++bool CheckCmapSubtable4(const void * pCmapSubtable4, const void * pCmapEnd /*, unsigned int maxgid*/)
+ {
++    size_t table_len = (const byte *)pCmapEnd - (const byte *)pCmapSubtable4;
+     if (!pCmapSubtable4) return false;
+     const Sfnt::CmapSubTable * pTable = reinterpret_cast<const Sfnt::CmapSubTable *>(pCmapSubtable4);
+     // Bob H say some freeware TT fonts have version 1 (eg, CALIGULA.TTF) 
+     // so don't check subtable version. 21 Mar 2002 spec changes version to language.
+     if (be::swap(pTable->format) != 4) return false;
+     const Sfnt::CmapSubTableFormat4 * pTable4 = reinterpret_cast<const Sfnt::CmapSubTableFormat4 *>(pCmapSubtable4);
+     uint16 length = be::swap(pTable4->length);
+     if (length > table_len)
+@@ -1044,17 +1045,17 @@ unsigned int CmapSubtable4NextCodepoint(
+             *pRangeKey = nRange - 1;
+         return 0xFFFF;
+     }
+ 
+     int iRange = (pRangeKey) ? *pRangeKey : 0;
+     // Just in case we have a bad key:
+     while (iRange > 0 && be::peek<uint16>(pStartCode + iRange) > nUnicodePrev)
+         iRange--;
+-    while (be::peek<uint16>(pTable->end_code + iRange) < nUnicodePrev)
++    while (iRange < nRange - 1 && be::peek<uint16>(pTable->end_code + iRange) < nUnicodePrev)
+         iRange++;
+ 
+     // Now iRange is the range containing nUnicodePrev.
+     unsigned int nStartCode = be::peek<uint16>(pStartCode + iRange);
+     unsigned int nEndCode = be::peek<uint16>(pTable->end_code + iRange);
+ 
+     if (nStartCode > nUnicodePrev)
+         // Oops, nUnicodePrev is not in the cmap! Adjust so we get a reasonable
+@@ -1069,36 +1070,37 @@ unsigned int CmapSubtable4NextCodepoint(
+         return nUnicodePrev + 1;
+     }
+ 
+     // Otherwise the next codepoint is the first one in the next range.
+     // There is guaranteed to be a next range because there must be one that
+     // ends with 0xFFFF.
+     if (pRangeKey)
+         *pRangeKey = iRange + 1;
+-    return be::peek<uint16>(pStartCode + iRange + 1);
++    return (iRange + 1 >= nRange) ? 0xFFFF : be::peek<uint16>(pStartCode + iRange + 1);
+ }
+ 
+ /*----------------------------------------------------------------------------------------------
+     Check the Microsoft UCS-4 subtable for expected values.
+ ----------------------------------------------------------------------------------------------*/
+-bool CheckCmapSubtable12(const void *pCmapSubtable12, size_t table_len /*, unsigned int maxgid*/)
++bool CheckCmapSubtable12(const void *pCmapSubtable12, const void *pCmapEnd /*, unsigned int maxgid*/)
+ {
++    size_t table_len = (const byte *)pCmapEnd - (const byte *)pCmapSubtable12;
+     if (!pCmapSubtable12)  return false;
+     const Sfnt::CmapSubTable * pTable = reinterpret_cast<const Sfnt::CmapSubTable *>(pCmapSubtable12);
+     if (be::swap(pTable->format) != 12)
+         return false;
+     const Sfnt::CmapSubTableFormat12 * pTable12 = reinterpret_cast<const Sfnt::CmapSubTableFormat12 *>(pCmapSubtable12);
+     uint32 length = be::swap(pTable12->length);
+     if (length > table_len)
+         return false;
+     if (length < sizeof(Sfnt::CmapSubTableFormat12))
+         return false;
+     uint32 num_groups = be::swap(pTable12->num_groups);
+-    if (length != (sizeof(Sfnt::CmapSubTableFormat12) + (num_groups - 1) * sizeof(uint32) * 3))
++    if (num_groups > 0x10000000 || length != (sizeof(Sfnt::CmapSubTableFormat12) + (num_groups - 1) * sizeof(uint32) * 3))
+         return false;
+ #if 0
+     for (unsigned int i = 0; i < num_groups; ++i)
+     {
+         if (be::swap(pTable12->group[i].end_char_code)  - be::swap(pTable12->group[i].start_char_code) + be::swap(pTable12->group[i].start_glyph_id) > maxgid)
+             return false;
+         if (i > 0 && be::swap(pTable12->group[i].start_char_code) <= be::swap(pTable12->group[i-1].end_char_code))
+             return false;
+@@ -1161,17 +1163,17 @@ unsigned int CmapSubtable12NextCodepoint
+             *pRangeKey = nRange;
+         return 0x10FFFF;
+     }
+ 
+     int iRange = (pRangeKey) ? *pRangeKey : 0;
+     // Just in case we have a bad key:
+     while (iRange > 0 && be::swap(pTable->group[iRange].start_char_code) > nUnicodePrev)
+         iRange--;
+-    while (be::swap(pTable->group[iRange].end_char_code) < nUnicodePrev)
++    while (iRange < nRange - 1 && be::swap(pTable->group[iRange].end_char_code) < nUnicodePrev)
+         iRange++;
+ 
+     // Now iRange is the range containing nUnicodePrev.
+ 
+     unsigned int nStartCode = be::swap(pTable->group[iRange].start_char_code);
+     unsigned int nEndCode = be::swap(pTable->group[iRange].end_char_code);
+ 
+     if (nStartCode > nUnicodePrev)
+diff --git a/gfx/graphite2/src/call_machine.cpp b/gfx/graphite2/src/call_machine.cpp
+--- a/gfx/graphite2/src/call_machine.cpp
++++ b/gfx/graphite2/src/call_machine.cpp
+@@ -67,32 +67,34 @@ using namespace vm;
+ struct regbank  {
+     slotref         is;
+     slotref *       map;
+     SlotMap       & smap;
+     slotref * const map_base;
+     const instr * & ip;
+     uint8           direction;
+     int8            flags;
++    Machine::status_t & status;
+ };
+ 
+ typedef bool        (* ip_t)(registers);
+ 
+ // Pull in the opcode definitions
+ // We pull these into a private namespace so these otherwise common names dont
+ // pollute the toplevel namespace.
+ namespace {
+ #define smap    reg.smap
+ #define seg     smap.segment
+ #define is      reg.is
+ #define ip      reg.ip
+ #define map     reg.map
+ #define mapb    reg.map_base
+ #define flags   reg.flags
+ #define dir     reg.direction
++#define status  reg.status
+ 
+ #include "inc/opcodes.h"
+ 
+ #undef smap
+ #undef seg
+ #undef is
+ #undef ip
+ #undef map
+@@ -108,17 +110,17 @@ Machine::stack_t  Machine::run(const ins
+ {
+     assert(program != 0);
+ 
+     // Declare virtual machine registers
+     const instr   * ip = program-1;
+     const byte    * dp = data;
+     stack_t       * sp = _stack + Machine::STACK_GUARD,
+             * const sb = sp;
+-    regbank         reg = {*map, map, _map, _map.begin()+_map.context(), ip, _map.dir(), 0};
++    regbank         reg = {*map, map, _map, _map.begin()+_map.context(), ip, _map.dir(), 0, _status};
+ 
+     // Run the program        
+     while ((reinterpret_cast<ip_t>(*++ip))(dp, sp, sb, reg)) {}
+     const stack_t ret = sp == _stack+STACK_GUARD+1 ? *sp-- : 0;
+ 
+     check_final_stack(sp);
+     map = reg.map;
+     *map = reg.is;
+diff --git a/gfx/graphite2/src/direct_machine.cpp b/gfx/graphite2/src/direct_machine.cpp
+--- a/gfx/graphite2/src/direct_machine.cpp
++++ b/gfx/graphite2/src/direct_machine.cpp
+@@ -57,36 +57,37 @@ using namespace vm;
+ namespace {
+ 
+ const void * direct_run(const bool          get_table_mode,
+                         const instr       * program,
+                         const byte        * data,
+                         Machine::stack_t  * stack,
+                         slotref         * & __map,
+                         uint8                _dir,
++                        Machine::status_t & status,
+                         SlotMap           * __smap=0)
+ {
+     // We need to define and return to opcode table from within this function 
+     // other inorder to take the addresses of the instruction bodies.
+     #include "inc/opcode_table.h"
+     if (get_table_mode)
+         return opcode_table;
+ 
+     // Declare virtual machine registers
+-    const instr       * ip = program;
+-    const byte        * dp = data;
+-    Machine::stack_t  * sp = stack + Machine::STACK_GUARD,
+-                * const sb = sp;
+-    SlotMap         & smap = *__smap;
+-    Segment          & seg = smap.segment;
+-    slotref             is = *__map,
+-                     * map = __map,
+-              * const mapb = smap.begin()+smap.context();
+-    uint8            dir = _dir;
+-    int8             flags = 0;
++    const instr           * ip = program;
++    const byte            * dp = data;
++    Machine::stack_t      * sp = stack + Machine::STACK_GUARD,
++                    * const sb = sp;
++    SlotMap             & smap = *__smap;
++    Segment              & seg = smap.segment;
++    slotref                 is = *__map,
++                         * map = __map,
++                  * const mapb = smap.begin()+smap.context();
++    uint8                  dir = _dir;
++    int8                 flags = 0;
+     
+     // start the program
+     goto **ip;
+ 
+     // Pull in the opcode definitions
+     #include "inc/opcodes.h"
+     
+     end:
+@@ -95,25 +96,26 @@ const void * direct_run(const bool      
+     return sp;
+ }
+ 
+ }
+ 
+ const opcode_t * Machine::getOpcodeTable() throw()
+ {
+     slotref * dummy;
+-    return static_cast<const opcode_t *>(direct_run(true, 0, 0, 0, dummy, 0));
++    Machine::status_t dumstat = Machine::finished;
++    return static_cast<const opcode_t *>(direct_run(true, 0, 0, 0, dummy, 0, dumstat));
+ }
+ 
+ 
+ Machine::stack_t  Machine::run(const instr   * program,
+                                const byte    * data,
+                                slotref     * & is)
+ {
+     assert(program != 0);
+     
+     const stack_t *sp = static_cast<const stack_t *>(
+-                direct_run(false, program, data, _stack, is, _map.dir(), &_map));
++                direct_run(false, program, data, _stack, is, _map.dir(), _status, &_map));
+     const stack_t ret = sp == _stack+STACK_GUARD+1 ? *sp-- : 0;
+     check_final_stack(sp);
+     return ret;
+ }
+ 
+diff --git a/gfx/graphite2/src/inc/Code.h b/gfx/graphite2/src/inc/Code.h
+--- a/gfx/graphite2/src/inc/Code.h
++++ b/gfx/graphite2/src/inc/Code.h
+@@ -109,17 +109,17 @@ public:
+     int32 run(Machine &m, slotref * & map) const;
+     
+     CLASS_NEW_DELETE;
+ };
+ 
+ inline
+ size_t  Machine::Code::estimateCodeDataOut(size_t n_bc)
+ {
+-    return n_bc * (sizeof(instr)+sizeof(byte));
++    return (n_bc + 1) * (sizeof(instr)+sizeof(byte));
+ }
+ 
+ 
+ inline Machine::Code::Code() throw()
+ : _code(0), _data(0), _data_size(0), _instr_count(0), _max_ref(0),
+   _status(loaded), _constraint(false), _modify(false), _delete(false),
+   _own(false)
+ {
+diff --git a/gfx/graphite2/src/inc/Machine.h b/gfx/graphite2/src/inc/Machine.h
+--- a/gfx/graphite2/src/inc/Machine.h
++++ b/gfx/graphite2/src/inc/Machine.h
+@@ -135,17 +135,18 @@ public:
+ 
+     class Code;
+ 
+     enum status_t {
+         finished = 0,
+         stack_underflow,
+         stack_not_empty,
+         stack_overflow,
+-        slot_offset_out_bounds
++        slot_offset_out_bounds,
++        died_early
+     };
+ 
+     Machine(SlotMap &) throw();
+     static const opcode_t *   getOpcodeTable() throw();
+ 
+     CLASS_NEW_DELETE;
+ 
+     SlotMap   & slotMap() const throw();
+diff --git a/gfx/graphite2/src/inc/TtfUtil.h b/gfx/graphite2/src/inc/TtfUtil.h
+--- a/gfx/graphite2/src/inc/TtfUtil.h
++++ b/gfx/graphite2/src/inc/TtfUtil.h
+@@ -132,21 +132,21 @@ public:
+     int GetLangsForNames(const void * pName, int nPlatformId, int nEncodingId,
+         int *nameIdList, int cNameIds, short *langIdList);
+     void SwapWString(void * pWStr, size_t nSize = 0); // throw (std::invalid_argument);
+ #endif
+ 
+     ////////////////////////////////// cmap lookup tools 
+     const void * FindCmapSubtable(const void * pCmap, int nPlatformId = 3, 
+         int nEncodingId = 1, size_t length = 0);
+-    bool CheckCmapSubtable4(const void * pCmap31, size_t table_len /*, unsigned int maxgid*/);
++    bool CheckCmapSubtable4(const void * pCmap31, const void * pCmapEnd /*, unsigned int maxgid*/);
+     gid16 CmapSubtable4Lookup(const void * pCmapSubtabel4, unsigned int nUnicodeId, int rangeKey = 0);
+     unsigned int CmapSubtable4NextCodepoint(const void *pCmap31, unsigned int nUnicodeId,
+         int * pRangeKey = 0);
+-    bool CheckCmapSubtable12(const void *pCmap310, size_t table_len /*, unsigned int maxgid*/);
++    bool CheckCmapSubtable12(const void *pCmap310, const void * pCmapEnd /*, unsigned int maxgid*/);
+     gid16 CmapSubtable12Lookup(const void * pCmap310, unsigned int uUnicodeId, int rangeKey = 0);
+     unsigned int CmapSubtable12NextCodepoint(const void *pCmap310, unsigned int nUnicodeId,
+         int * pRangeKey = 0);
+ 
+     ///////////////////////////////// horizontal metric data for a glyph
+     bool HorMetrics(gid16 nGlyphId, const void * pHmtx, size_t lHmtxSize, 
+         const void * pHhea, int & nLsb, unsigned int & nAdvWid);
+ 
+diff --git a/gfx/graphite2/src/inc/opcodes.h b/gfx/graphite2/src/inc/opcodes.h
+--- a/gfx/graphite2/src/inc/opcodes.h
++++ b/gfx/graphite2/src/inc/opcodes.h
+@@ -71,17 +71,17 @@ of the License or (at your option) any l
+ #define use_params(n)       dp += n
+ 
+ #define declare_params(n)   const byte * param = dp; \
+                             use_params(n);
+ 
+ #define push(n)             { *++sp = n; }
+ #define pop()               (*sp--)
+ #define slotat(x)           (map[(x)])
+-#define DIE                 { is=seg.last(); EXIT(1); }
++#define DIE                 { is=seg.last(); status = Machine::died_early; EXIT(1); }
+ #define POSITIONED          1
+ 
+ STARTOP(nop)
+     do {} while (0);
+ ENDOP
+ 
+ STARTOP(push_byte)
+     declare_params(1);
+@@ -387,30 +387,30 @@ STARTOP(attr_set)
+ ENDOP
+ 
+ STARTOP(attr_add)
+     declare_params(1);
+     const attrCode      slat = attrCode(uint8(*param));
+     const          int  val  = int(pop());
+     if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0)
+     {
+-        seg.positionSlots(0, *smap.begin(), *(smap.end()-1), dir);
++        seg.positionSlots(0, *smap.begin(), *(smap.end()-1), seg.currdir());
+         flags |= POSITIONED;
+     }
+     int res = is->getAttr(&seg, slat, 0);
+     is->setAttr(&seg, slat, 0, val + res, smap);
+ ENDOP
+ 
+ STARTOP(attr_sub)
+     declare_params(1);
+     const attrCode      slat = attrCode(uint8(*param));
+     const          int  val  = int(pop());
+     if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0)
+     {
+-        seg.positionSlots(0, *smap.begin(), *(smap.end()-1), dir);
++        seg.positionSlots(0, *smap.begin(), *(smap.end()-1), seg.currdir());
+         flags |= POSITIONED;
+     }
+     int res = is->getAttr(&seg, slat, 0);
+     is->setAttr(&seg, slat, 0, res - val, smap);
+ ENDOP
+ 
+ STARTOP(attr_set_slot)
+     declare_params(1);
+@@ -429,17 +429,17 @@ STARTOP(iattr_set_slot)
+ ENDOP
+ 
+ STARTOP(push_slot_attr)
+     declare_params(2);
+     const attrCode      slat     = attrCode(uint8(param[0]));
+     const int           slot_ref = int8(param[1]);
+     if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0)
+     {
+-        seg.positionSlots(0, *smap.begin(), *(smap.end()-1), dir);
++        seg.positionSlots(0, *smap.begin(), *(smap.end()-1), seg.currdir());
+         flags |= POSITIONED;
+     }
+     slotref slot = slotat(slot_ref);
+     if (slot)
+     {
+         int res = slot->getAttr(&seg, slat, 0);
+         push(res);
+     }
+@@ -505,17 +505,17 @@ ENDOP
+ 
+ STARTOP(push_islot_attr)
+     declare_params(3);
+     const attrCode  slat     = attrCode(uint8(param[0]));
+     const int           slot_ref = int8(param[1]),
+                         idx      = uint8(param[2]);
+     if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0)
+     {
+-        seg.positionSlots(0, *smap.begin(), *(smap.end()-1), dir);
++        seg.positionSlots(0, *smap.begin(), *(smap.end()-1), seg.currdir());
+         flags |= POSITIONED;
+     }
+     slotref slot = slotat(slot_ref);
+     if (slot)
+     {
+         int res = slot->getAttr(&seg, slat, idx);
+         push(res);
+     }
+