gfx/graphite2/src/Silf.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /*  GRAPHITE2 LICENSING
     3     Copyright 2010, SIL International
     4     All rights reserved.
     6     This library is free software; you can redistribute it and/or modify
     7     it under the terms of the GNU Lesser General Public License as published
     8     by the Free Software Foundation; either version 2.1 of License, or
     9     (at your option) any later version.
    11     This program is distributed in the hope that it will be useful,
    12     but WITHOUT ANY WARRANTY; without even the implied warranty of
    13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    14     Lesser General Public License for more details.
    16     You should also have received a copy of the GNU Lesser General Public
    17     License along with this library in the file named "LICENSE".
    18     If not, write to the Free Software Foundation, 51 Franklin Street, 
    19     Suite 500, Boston, MA 02110-1335, USA or visit their web page on the 
    20     internet at http://www.fsf.org/licenses/lgpl.html.
    22 Alternatively, the contents of this file may be used under the terms of the
    23 Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
    24 License, as published by the Free Software Foundation, either version 2
    25 of the License or (at your option) any later version.
    26 */
    27 #include <cstdlib>
    28 #include "graphite2/Segment.h"
    29 #include "inc/debug.h"
    30 #include "inc/Endian.h"
    31 #include "inc/Silf.h"
    32 #include "inc/Segment.h"
    33 #include "inc/Rule.h"
    34 #include "inc/Error.h"
    37 using namespace graphite2;
    39 namespace { static const uint32 ERROROFFSET = 0xFFFFFFFF; }
    41 Silf::Silf() throw()
    42 : m_passes(0),
    43   m_pseudos(0),
    44   m_classOffsets(0),
    45   m_classData(0),
    46   m_justs(0),
    47   m_numPasses(0),
    48   m_numJusts(0),
    49   m_sPass(0),
    50   m_pPass(0),
    51   m_jPass(0),
    52   m_bPass(0),
    53   m_flags(0),
    54   m_aPseudo(0),
    55   m_aBreak(0),
    56   m_aUser(0),
    57   m_aBidi(0),
    58   m_aMirror(0),
    59   m_aPassBits(0),
    60   m_iMaxComp(0),
    61   m_aLig(0),
    62   m_numPseudo(0),
    63   m_nClass(0),
    64   m_nLinear(0),
    65   m_gEndLine(0)
    66 {
    67     memset(&m_silfinfo, 0, sizeof m_silfinfo);
    68 }
    70 Silf::~Silf() throw()
    71 {
    72     releaseBuffers();
    73 }
    75 void Silf::releaseBuffers() throw()
    76 {
    77     delete [] m_passes;
    78     delete [] m_pseudos;
    79     free(m_classOffsets);
    80     free(m_classData);
    81     free(m_justs);
    82     m_passes= 0;
    83     m_pseudos = 0;
    84     m_classOffsets = 0;
    85     m_classData = 0;
    86     m_justs = 0;
    87 }
    90 bool Silf::readGraphite(const byte * const silf_start, size_t lSilf, Face& face, uint32 version)
    91 {
    92     const byte * p = silf_start,
    93                * const silf_end = p + lSilf;
    94     Error e;
    96     if (version >= 0x00030000)
    97     {
    98         if (e.test(lSilf < 28, E_BADSIZE)) { releaseBuffers(); return face.error(e); }
    99         be::skip<int32>(p);    // ruleVersion
   100         be::skip<uint16>(p,2); // passOffset & pseudosOffset
   101     }
   102     else if (e.test(lSilf < 20, E_BADSIZE)) { releaseBuffers(); return face.error(e); }
   103     const uint16 maxGlyph = be::read<uint16>(p);
   104     m_silfinfo.extra_ascent = be::read<uint16>(p);
   105     m_silfinfo.extra_descent = be::read<uint16>(p);
   106     m_numPasses = be::read<uint8>(p);
   107     m_sPass     = be::read<uint8>(p);
   108     m_pPass     = be::read<uint8>(p);
   109     m_jPass     = be::read<uint8>(p);
   110     m_bPass     = be::read<uint8>(p);
   111     m_flags     = be::read<uint8>(p);
   112     be::skip<uint8>(p,2); //  max{Pre,Post}Context.
   113     m_aPseudo   = be::read<uint8>(p);
   114     m_aBreak    = be::read<uint8>(p);
   115     m_aBidi     = be::read<uint8>(p);
   116     m_aMirror   = be::read<uint8>(p);
   117     m_aPassBits = be::read<uint8>(p);
   119     // Read Justification levels.
   120     m_numJusts  = be::read<uint8>(p);
   121     if (e.test(maxGlyph >= face.glyphs().numGlyphs(), E_BADMAXGLYPH)
   122         || e.test(p + m_numJusts * 8 >= silf_end, E_BADNUMJUSTS))
   123     {
   124         releaseBuffers(); return face.error(e);
   125     }
   127     if (m_numJusts)
   128     {
   129         m_justs = gralloc<Justinfo>(m_numJusts);
   130         if (e.test(!m_justs, E_OUTOFMEM)) return face.error(e);
   132         for (uint8 i = 0; i < m_numJusts; i++)
   133         {
   134             ::new(m_justs + i) Justinfo(p[0], p[1], p[2], p[3]);
   135             be::skip<byte>(p,8);
   136         }
   137     }
   139     if (e.test(p + sizeof(uint16) + sizeof(uint8)*8 >= silf_end, E_BADENDJUSTS)) { releaseBuffers(); return face.error(e); }
   140     m_aLig      = be::read<uint16>(p);
   141     m_aUser     = be::read<uint8>(p);
   142     m_iMaxComp  = be::read<uint8>(p);
   143     be::skip<byte>(p,5);                        // direction and 4 reserved bytes
   144     be::skip<uint16>(p, be::read<uint8>(p));    // don't need critical features yet
   145     be::skip<byte>(p);                          // reserved
   146     if (e.test(p >= silf_end, E_BADCRITFEATURES))   { releaseBuffers(); return face.error(e); }
   147     be::skip<uint32>(p, be::read<uint8>(p));    // don't use scriptTag array.
   148     if (e.test(p + sizeof(uint16) + sizeof(uint32) >= silf_end, E_BADSCRIPTTAGS)) { releaseBuffers(); return face.error(e); }
   149     m_gEndLine  = be::read<uint16>(p);          // lbGID
   150     const byte * o_passes = p,
   151                * const passes_start = silf_start + be::read<uint32>(p);
   153     const size_t num_attrs = face.glyphs().numAttrs();
   154     if (e.test(m_aPseudo   >= num_attrs, E_BADAPSEUDO)
   155         || e.test(m_aBreak >= num_attrs, E_BADABREAK)
   156         || e.test(m_aBidi  >= num_attrs, E_BADABIDI)
   157         || e.test(m_aMirror>= num_attrs, E_BADAMIRROR)
   158         || e.test(m_numPasses > 128, E_BADNUMPASSES) || e.test(passes_start >= silf_end, E_BADPASSESSTART)
   159         || e.test(m_pPass < m_sPass, E_BADPASSBOUND) || e.test(m_pPass > m_numPasses, E_BADPPASS) || e.test(m_sPass > m_numPasses, E_BADSPASS)
   160         || e.test(m_jPass < m_pPass, E_BADJPASSBOUND) || e.test(m_jPass > m_numPasses, E_BADJPASS)
   161         || e.test((m_bPass != 0xFF && (m_bPass < m_jPass || m_bPass > m_numPasses)), E_BADBPASS)
   162         || e.test(m_aLig > 127, E_BADALIG))
   163     {
   164         releaseBuffers();
   165         return face.error(e);
   166     }
   167     be::skip<uint32>(p, m_numPasses);
   168     if (e.test(p + sizeof(uint16) >= passes_start, E_BADPASSESSTART)) { releaseBuffers(); return face.error(e); }
   169     m_numPseudo = be::read<uint16>(p);
   170     be::skip<uint16>(p, 3); // searchPseudo, pseudoSelector, pseudoShift
   171     if (e.test(p + m_numPseudo*(sizeof(uint32) + sizeof(uint16)) >= passes_start, E_BADNUMPSEUDO))
   172     {
   173         releaseBuffers(); return face.error(e);
   174     }
   175     m_pseudos = new Pseudo[m_numPseudo];
   176     for (int i = 0; i < m_numPseudo; i++)
   177     {
   178         m_pseudos[i].uid = be::read<uint32>(p);
   179         m_pseudos[i].gid = be::read<uint16>(p);
   180     }
   182     const size_t clen = readClassMap(p, passes_start - p, version, e);
   183     if (e || e.test(p + clen > passes_start, E_BADPASSESSTART)) { releaseBuffers(); return face.error(e); }
   185     m_passes = new Pass[m_numPasses];
   186     for (size_t i = 0; i < m_numPasses; ++i)
   187     {
   188         const byte * const pass_start = silf_start + be::read<uint32>(o_passes),
   189                    * const pass_end = silf_start + be::peek<uint32>(o_passes);
   190         face.error_context((face.error_context() & 0xFF00) + EC_ASILF + (i << 16));
   191         if (e.test(pass_start > pass_end, E_BADPASSSTART) || e.test(pass_end > silf_end, E_BADPASSEND)) {
   192             releaseBuffers(); return face.error(e);
   193         }
   195         m_passes[i].init(this);
   196         if (!m_passes[i].readPass(pass_start, pass_end - pass_start, pass_start - silf_start, face, e))
   197         {
   198             releaseBuffers();
   199             return false;
   200         }
   201     }
   203     // fill in gr_faceinfo
   204     m_silfinfo.upem = face.glyphs().unitsPerEm();
   205     m_silfinfo.has_bidi_pass = (m_bPass != 0xFF);
   206     m_silfinfo.justifies = (m_numJusts != 0) || (m_jPass < m_pPass);
   207     m_silfinfo.line_ends = (m_flags & 1);
   208     m_silfinfo.space_contextuals = gr_faceinfo::gr_space_contextuals((m_flags >> 2) & 0x7);
   209     return true;
   210 }
   212 template<typename T> inline uint32 Silf::readClassOffsets(const byte *&p, size_t data_len, Error &e)
   213 {
   214     const T cls_off = 2*sizeof(uint16) + sizeof(T)*(m_nClass+1);
   215     const size_t max_off = (be::peek<T>(p + sizeof(T)*m_nClass) - cls_off)/sizeof(uint16);
   216     // Check that the last+1 offset is less than or equal to the class map length.
   217     if (e.test(be::peek<T>(p) != cls_off, E_MISALIGNEDCLASSES) 
   218             || e.test(max_off > (data_len - cls_off)/sizeof(uint16), E_HIGHCLASSOFFSET))
   219         return ERROROFFSET;
   221     // Read in all the offsets.
   222     m_classOffsets = gralloc<uint32>(m_nClass+1);
   223     if (e.test(!m_classOffsets, E_OUTOFMEM)) return ERROROFFSET;
   224     for (uint32 * o = m_classOffsets, * const o_end = o + m_nClass + 1; o != o_end; ++o)
   225     {
   226         *o = (be::read<T>(p) - cls_off)/sizeof(uint16);
   227         if (e.test(*o > max_off, E_HIGHCLASSOFFSET))
   228             return ERROROFFSET;
   229     }
   230     return max_off;
   231 }
   233 size_t Silf::readClassMap(const byte *p, size_t data_len, uint32 version, Error &e)
   234 {
   235     if (e.test(data_len < sizeof(uint16)*2, E_BADCLASSSIZE)) return ERROROFFSET;
   237     m_nClass  = be::read<uint16>(p);
   238     m_nLinear = be::read<uint16>(p);
   240     // Check that numLinear < numClass,
   241     // that there is at least enough data for numClasses offsets.
   242     if (e.test(m_nLinear > m_nClass, E_TOOMANYLINEAR)
   243      || e.test((m_nClass + 1) * (version >= 0x00040000 ? sizeof(uint32) : sizeof(uint16)) > (data_len - 4), E_CLASSESTOOBIG))
   244         return ERROROFFSET;
   246     uint32 max_off;
   247     if (version >= 0x00040000)
   248         max_off = readClassOffsets<uint32>(p, data_len, e);
   249     else
   250         max_off = readClassOffsets<uint16>(p, data_len, e);
   252     if (max_off == ERROROFFSET) return ERROROFFSET;
   254     // Check the linear offsets are sane, these must be monotonically increasing.
   255     for (const uint32 *o = m_classOffsets, * const o_end = o + m_nLinear; o != o_end; ++o)
   256         if (e.test(o[0] > o[1], E_BADCLASSOFFSET))
   257             return ERROROFFSET;
   259     // Fortunately the class data is all uint16s so we can decode these now
   260     m_classData = gralloc<uint16>(max_off);
   261     if (e.test(!m_classData, E_OUTOFMEM)) return ERROROFFSET;
   262     for (uint16 *d = m_classData, * const d_end = d + max_off; d != d_end; ++d)
   263         *d = be::read<uint16>(p);
   265     // Check the lookup class invariants for each non-linear class
   266     for (const uint32 *o = m_classOffsets + m_nLinear, * const o_end = m_classOffsets + m_nClass; o != o_end; ++o)
   267     {
   268         const uint16 * lookup = m_classData + *o;
   269         if (e.test(*o > max_off - 4, E_HIGHCLASSOFFSET)                        // LookupClass doesn't stretch over max_off
   270          || e.test(lookup[0] == 0                                                   // A LookupClass with no looks is a suspicious thing ...
   271                     || lookup[0] > (max_off - *o - 4)/2                             // numIDs lookup pairs fits within (start of LookupClass' lookups array, max_off]
   272                     || lookup[3] != lookup[0] - lookup[1], E_BADCLASSLOOKUPINFO))   // rangeShift:   numIDs  - searchRange
   273             return ERROROFFSET;
   274     }
   276     return max_off;
   277 }
   279 uint16 Silf::findPseudo(uint32 uid) const
   280 {
   281     for (int i = 0; i < m_numPseudo; i++)
   282         if (m_pseudos[i].uid == uid) return m_pseudos[i].gid;
   283     return 0;
   284 }
   286 uint16 Silf::findClassIndex(uint16 cid, uint16 gid) const
   287 {
   288     if (cid > m_nClass) return -1;
   290     const uint16 * cls = m_classData + m_classOffsets[cid];
   291     if (cid < m_nLinear)        // output class being used for input, shouldn't happen
   292     {
   293         for (unsigned int i = 0, n = m_classOffsets[cid + 1]; i < n; ++i, ++cls)
   294             if (*cls == gid) return i;
   295         return -1;
   296     }
   297     else
   298     {
   299         const uint16 *  min = cls + 4,      // lookups array
   300                      *  max = min + cls[0]*2; // lookups aray is numIDs (cls[0]) uint16 pairs long
   301         do
   302         {
   303             const uint16 * p = min + (-2 & ((max-min)/2));
   304             if  (p[0] > gid)    max = p;
   305             else                min = p;
   306         }
   307         while (max - min > 2);
   308         return min[0] == gid ? min[1] : -1;
   309     }
   310 }
   312 uint16 Silf::getClassGlyph(uint16 cid, unsigned int index) const
   313 {
   314     if (cid > m_nClass) return 0;
   316     uint32 loc = m_classOffsets[cid];
   317     if (cid < m_nLinear)
   318     {
   319         if (index < m_classOffsets[cid + 1] - loc)
   320             return m_classData[index + loc];
   321     }
   322     else        // input class being used for output. Shouldn't happen
   323     {
   324         for (unsigned int i = loc + 4; i < m_classOffsets[cid + 1]; i += 2)
   325             if (m_classData[i + 1] == index) return m_classData[i];
   326     }
   327     return 0;
   328 }
   331 bool Silf::runGraphite(Segment *seg, uint8 firstPass, uint8 lastPass, int dobidi) const
   332 {
   333     assert(seg != 0);
   334     SlotMap            map(*seg);
   335     FiniteStateMachine fsm(map, seg->getFace()->logger());
   336     vm::Machine        m(map);
   337     unsigned int       initSize = seg->slotCount();
   338     uint8              lbidi = m_bPass;
   339 #if !defined GRAPHITE2_NTRACING
   340     json * const dbgout = seg->getFace()->logger();
   341 #endif
   343     if (lastPass == 0)
   344     {
   345         if (firstPass == lastPass && lbidi == 0xFF)
   346             return true;
   347         lastPass = m_numPasses;
   348     }
   349     if (firstPass <= lbidi && lastPass >= lbidi && dobidi)
   350         lastPass++;
   351     else
   352         lbidi = 0xFF;
   354     for (size_t i = firstPass; i < lastPass; ++i)
   355     {
   356         // bidi and mirroring
   357         if (i == lbidi)
   358         {
   359 #if !defined GRAPHITE2_NTRACING
   360             if (dbgout)
   361             {
   362                 *dbgout << json::item << json::object
   363                             << "id"     << -1
   364                             << "slots"  << json::array;
   365                 seg->positionSlots(0);
   366                 for(Slot * s = seg->first(); s; s = s->next())
   367                     *dbgout     << dslot(seg, s);
   368                 *dbgout         << json::close
   369                             << "rules"  << json::array << json::close
   370                             << json::close;
   371             }
   372 #endif
   374             if (!(seg->dir() & 2))
   375                 seg->bidiPass(m_aBidi, seg->dir() & 1, m_aMirror);
   376             else if (m_aMirror)
   377             {
   378                 Slot * s;
   379                 for (s = seg->first(); s; s = s->next())
   380                 {
   381                     unsigned short g = seg->glyphAttr(s->gid(), m_aMirror);
   382                     if (g && (!(seg->dir() & 4) || !seg->glyphAttr(s->gid(), m_aMirror + 1)))
   383                         s->setGlyph(seg, g);
   384                 }
   385             }
   386         --i;
   387         --lastPass;
   388         lbidi = 0xFF;
   389         continue;
   390         }
   392 #if !defined GRAPHITE2_NTRACING
   393         if (dbgout)
   394         {
   395             *dbgout << json::item << json::object
   396                         << "id"     << i+1
   397                         << "slots"  << json::array;
   398             seg->positionSlots(0);
   399             for(Slot * s = seg->first(); s; s = s->next())
   400                 *dbgout     << dslot(seg, s);
   401             *dbgout         << json::close;
   402         }
   403 #endif
   405         // test whether to reorder, prepare for positioning
   406         if (i >= 32 || (seg->passBits() & (1 << i)) == 0)
   407             m_passes[i].runGraphite(m, fsm);
   408         // only subsitution passes can change segment length, cached subsegments are short for their text
   409         if (m.status() != vm::Machine::finished
   410             || (i < m_pPass && (seg->slotCount() > initSize * MAX_SEG_GROWTH_FACTOR
   411             || (seg->slotCount() && seg->slotCount() * MAX_SEG_GROWTH_FACTOR < initSize))))
   412             return false;
   413     }
   414     return true;
   415 }

mercurial