tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

Silf.cpp (16478B)


      1 /*  GRAPHITE2 LICENSING
      2 
      3    Copyright 2010, SIL International
      4    All rights reserved.
      5 
      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.
     10 
     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.
     15 
     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.
     21 
     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"
     35 
     36 
     37 using namespace graphite2;
     38 
     39 namespace { static const uint32 ERROROFFSET = 0xFFFFFFFF; }
     40 
     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_dir(0),
     55  m_aPseudo(0),
     56  m_aBreak(0),
     57  m_aUser(0),
     58  m_aBidi(0),
     59  m_aMirror(0),
     60  m_aPassBits(0),
     61  m_iMaxComp(0),
     62  m_aCollision(0),
     63  m_aLig(0),
     64  m_numPseudo(0),
     65  m_nClass(0),
     66  m_nLinear(0),
     67  m_gEndLine(0)
     68 {
     69    memset(&m_silfinfo, 0, sizeof m_silfinfo);
     70 }
     71 
     72 Silf::~Silf() throw()
     73 {
     74    releaseBuffers();
     75 }
     76 
     77 void Silf::releaseBuffers() throw()
     78 {
     79    delete [] m_passes;
     80    delete [] m_pseudos;
     81    free(m_classOffsets);
     82    free(m_classData);
     83    free(m_justs);
     84    m_passes= 0;
     85    m_pseudos = 0;
     86    m_classOffsets = 0;
     87    m_classData = 0;
     88    m_justs = 0;
     89 }
     90 
     91 
     92 bool Silf::readGraphite(const byte * const silf_start, size_t lSilf, Face& face, uint32 version)
     93 {
     94    const byte * p = silf_start,
     95               * const silf_end = p + lSilf;
     96    Error e;
     97 
     98    if (e.test(version >= 0x00060000, E_BADSILFVERSION))
     99    {
    100        releaseBuffers(); return face.error(e);
    101    }
    102    if (version >= 0x00030000)
    103    {
    104        if (e.test(lSilf < 28, E_BADSIZE)) { releaseBuffers(); return face.error(e); }
    105        be::skip<int32>(p);    // ruleVersion
    106        be::skip<uint16>(p,2); // passOffset & pseudosOffset
    107    }
    108    else if (e.test(lSilf < 20, E_BADSIZE)) { releaseBuffers(); return face.error(e); }
    109    const uint16 maxGlyph = be::read<uint16>(p);
    110    m_silfinfo.extra_ascent = be::read<uint16>(p);
    111    m_silfinfo.extra_descent = be::read<uint16>(p);
    112    m_numPasses = be::read<uint8>(p);
    113    m_sPass     = be::read<uint8>(p);
    114    m_pPass     = be::read<uint8>(p);
    115    m_jPass     = be::read<uint8>(p);
    116    m_bPass     = be::read<uint8>(p);
    117    m_flags     = be::read<uint8>(p);
    118    be::skip<uint8>(p,2); //  max{Pre,Post}Context.
    119    m_aPseudo   = be::read<uint8>(p);
    120    m_aBreak    = be::read<uint8>(p);
    121    m_aBidi     = be::read<uint8>(p);
    122    m_aMirror   = be::read<uint8>(p);
    123    m_aPassBits = be::read<uint8>(p);
    124 
    125    // Read Justification levels.
    126    m_numJusts  = be::read<uint8>(p);
    127    if (e.test(maxGlyph >= face.glyphs().numGlyphs(), E_BADMAXGLYPH)
    128        || e.test(p + m_numJusts * 8 >= silf_end, E_BADNUMJUSTS))
    129    {
    130        releaseBuffers(); return face.error(e);
    131    }
    132 
    133    if (m_numJusts)
    134    {
    135        m_justs = gralloc<Justinfo>(m_numJusts);
    136        if (e.test(!m_justs, E_OUTOFMEM)) return face.error(e);
    137 
    138        for (uint8 i = 0; i < m_numJusts; i++)
    139        {
    140            ::new(m_justs + i) Justinfo(p[0], p[1], p[2], p[3]);
    141            be::skip<byte>(p,8);
    142        }
    143    }
    144 
    145    if (e.test(p + sizeof(uint16) + sizeof(uint8)*8 >= silf_end, E_BADENDJUSTS)) { releaseBuffers(); return face.error(e); }
    146    m_aLig       = be::read<uint16>(p);
    147    m_aUser      = be::read<uint8>(p);
    148    m_iMaxComp   = be::read<uint8>(p);
    149    m_dir        = be::read<uint8>(p) - 1;
    150    m_aCollision = be::read<uint8>(p);
    151    be::skip<byte>(p,3);
    152    be::skip<uint16>(p, be::read<uint8>(p));    // don't need critical features yet
    153    be::skip<byte>(p);                          // reserved
    154    if (e.test(p >= silf_end, E_BADCRITFEATURES))   { releaseBuffers(); return face.error(e); }
    155    be::skip<uint32>(p, be::read<uint8>(p));    // don't use scriptTag array.
    156    if (e.test(p + sizeof(uint16) + sizeof(uint32) >= silf_end, E_BADSCRIPTTAGS)) { releaseBuffers(); return face.error(e); }
    157    m_gEndLine  = be::read<uint16>(p);          // lbGID
    158    const byte * o_passes = p;
    159    uint32 passes_start = be::read<uint32>(p);
    160 
    161    const size_t num_attrs = face.glyphs().numAttrs();
    162    if (e.test(m_aPseudo   >= num_attrs, E_BADAPSEUDO)
    163        || e.test(m_aBreak >= num_attrs, E_BADABREAK)
    164        || e.test(m_aBidi  >= num_attrs, E_BADABIDI)
    165        || e.test(m_aMirror>= num_attrs, E_BADAMIRROR)
    166        || e.test(m_aCollision && m_aCollision >= num_attrs - 5, E_BADACOLLISION)
    167        || e.test(m_numPasses > 128, E_BADNUMPASSES) || e.test(passes_start >= lSilf, E_BADPASSESSTART)
    168        || e.test(m_pPass < m_sPass, E_BADPASSBOUND) || e.test(m_pPass > m_numPasses, E_BADPPASS) || e.test(m_sPass > m_numPasses, E_BADSPASS)
    169        || e.test(m_jPass < m_pPass, E_BADJPASSBOUND) || e.test(m_jPass > m_numPasses, E_BADJPASS)
    170        || e.test((m_bPass != 0xFF && (m_bPass < m_jPass || m_bPass > m_numPasses)), E_BADBPASS)
    171        || e.test(m_aLig > 127, E_BADALIG))
    172    {
    173        releaseBuffers();
    174        return face.error(e);
    175    }
    176    be::skip<uint32>(p, m_numPasses);
    177    if (e.test(unsigned(p - silf_start) + sizeof(uint16) >= passes_start, E_BADPASSESSTART)) { releaseBuffers(); return face.error(e); }
    178    m_numPseudo = be::read<uint16>(p);
    179    be::skip<uint16>(p, 3); // searchPseudo, pseudoSelector, pseudoShift
    180    m_pseudos = new Pseudo[m_numPseudo];
    181    if (e.test(unsigned(p - silf_start) + m_numPseudo*(sizeof(uint32) + sizeof(uint16)) >= passes_start, E_BADNUMPSEUDO)
    182        || e.test(!m_pseudos, E_OUTOFMEM))
    183    {
    184        releaseBuffers(); return face.error(e);
    185    }
    186    for (int i = 0; i < m_numPseudo; i++)
    187    {
    188        m_pseudos[i].uid = be::read<uint32>(p);
    189        m_pseudos[i].gid = be::read<uint16>(p);
    190    }
    191 
    192    const size_t clen = readClassMap(p, passes_start + silf_start - p, version, e);
    193    m_passes = new Pass[m_numPasses];
    194    if (e || e.test(clen > unsigned(passes_start + silf_start - p), E_BADPASSESSTART)
    195          || e.test(!m_passes, E_OUTOFMEM))
    196    { releaseBuffers(); return face.error(e); }
    197 
    198    for (size_t i = 0; i < m_numPasses; ++i)
    199    {
    200        uint32 pass_start = be::read<uint32>(o_passes);
    201        uint32 pass_end = be::peek<uint32>(o_passes);
    202        face.error_context((face.error_context() & 0xFF00) + EC_ASILF + unsigned(i << 16));
    203        if (e.test(pass_start > pass_end, E_BADPASSSTART)
    204                || e.test(pass_start < passes_start, E_BADPASSSTART)
    205                || e.test(pass_end > lSilf, E_BADPASSEND)) {
    206            releaseBuffers(); return face.error(e);
    207        }
    208 
    209        enum passtype pt = PASS_TYPE_UNKNOWN;
    210        if (i >= m_jPass) pt = PASS_TYPE_JUSTIFICATION;
    211        else if (i >= m_pPass) pt = PASS_TYPE_POSITIONING;
    212        else if (i >= m_sPass) pt = PASS_TYPE_SUBSTITUTE;
    213        else pt = PASS_TYPE_LINEBREAK;
    214 
    215        m_passes[i].init(this);
    216        if (!m_passes[i].readPass(silf_start + pass_start, pass_end - pass_start, pass_start, face, pt,
    217            version, e))
    218        {
    219            releaseBuffers();
    220            return false;
    221        }
    222    }
    223 
    224    // fill in gr_faceinfo
    225    m_silfinfo.upem = face.glyphs().unitsPerEm();
    226    m_silfinfo.has_bidi_pass = (m_bPass != 0xFF);
    227    m_silfinfo.justifies = (m_numJusts != 0) || (m_jPass < m_pPass);
    228    m_silfinfo.line_ends = (m_flags & 1);
    229    m_silfinfo.space_contextuals = gr_faceinfo::gr_space_contextuals((m_flags >> 2) & 0x7);
    230    return true;
    231 }
    232 
    233 template<typename T> inline uint32 Silf::readClassOffsets(const byte *&p, size_t data_len, Error &e)
    234 {
    235    const T cls_off = 2*sizeof(uint16) + sizeof(T)*(m_nClass+1);
    236    const uint32 max_off = (be::peek<T>(p + sizeof(T)*m_nClass) - cls_off)/sizeof(uint16);
    237    // Check that the last+1 offset is less than or equal to the class map length.
    238    if (e.test(be::peek<T>(p) != cls_off, E_MISALIGNEDCLASSES)
    239            || e.test(max_off > (data_len - cls_off)/sizeof(uint16), E_HIGHCLASSOFFSET))
    240        return ERROROFFSET;
    241 
    242    // Read in all the offsets.
    243    m_classOffsets = gralloc<uint32>(m_nClass+1);
    244    if (e.test(!m_classOffsets, E_OUTOFMEM)) return ERROROFFSET;
    245    for (uint32 * o = m_classOffsets, * const o_end = o + m_nClass + 1; o != o_end; ++o)
    246    {
    247        *o = (be::read<T>(p) - cls_off)/sizeof(uint16);
    248        if (e.test(*o > max_off, E_HIGHCLASSOFFSET))
    249            return ERROROFFSET;
    250    }
    251    return max_off;
    252 }
    253 
    254 size_t Silf::readClassMap(const byte *p, size_t data_len, uint32 version, Error &e)
    255 {
    256    if (e.test(data_len < sizeof(uint16)*2, E_BADCLASSSIZE)) return ERROROFFSET;
    257 
    258    m_nClass  = be::read<uint16>(p);
    259    m_nLinear = be::read<uint16>(p);
    260 
    261    // Check that numLinear < numClass,
    262    // that there is at least enough data for numClasses offsets.
    263    if (e.test(m_nLinear > m_nClass, E_TOOMANYLINEAR)
    264     || e.test((m_nClass + 1) * (version >= 0x00040000 ? sizeof(uint32) : sizeof(uint16)) > (data_len - 4), E_CLASSESTOOBIG))
    265        return ERROROFFSET;
    266 
    267    uint32 max_off;
    268    if (version >= 0x00040000)
    269        max_off = readClassOffsets<uint32>(p, data_len, e);
    270    else
    271        max_off = readClassOffsets<uint16>(p, data_len, e);
    272 
    273    if (max_off == ERROROFFSET) return ERROROFFSET;
    274 
    275    if (e.test((int)max_off < m_nLinear + (m_nClass - m_nLinear) * 6, E_CLASSESTOOBIG))
    276        return ERROROFFSET;
    277 
    278    // Check the linear offsets are sane, these must be monotonically increasing.
    279    assert(m_nClass >= m_nLinear);
    280    for (const uint32 *o = m_classOffsets, * const o_end = o + m_nLinear; o != o_end; ++o)
    281        if (e.test(o[0] > o[1], E_BADCLASSOFFSET))
    282            return ERROROFFSET;
    283 
    284    // Fortunately the class data is all uint16s so we can decode these now
    285    m_classData = gralloc<uint16>(max_off);
    286    if (e.test(!m_classData, E_OUTOFMEM)) return ERROROFFSET;
    287    for (uint16 *d = m_classData, * const d_end = d + max_off; d != d_end; ++d)
    288        *d = be::read<uint16>(p);
    289 
    290    // Check the lookup class invariants for each non-linear class
    291    for (const uint32 *o = m_classOffsets + m_nLinear, * const o_end = m_classOffsets + m_nClass; o != o_end; ++o)
    292    {
    293        const uint16 * lookup = m_classData + *o;
    294        if (e.test(*o + 4 > max_off, E_HIGHCLASSOFFSET)                        // LookupClass doesn't stretch over max_off
    295         || e.test(lookup[0] == 0                                                   // A LookupClass with no looks is a suspicious thing ...
    296                    || lookup[0] * 2 + *o + 4 > max_off                             // numIDs lookup pairs fits within (start of LookupClass' lookups array, max_off]
    297                    || lookup[3] + lookup[1] != lookup[0], E_BADCLASSLOOKUPINFO)    // rangeShift:   numIDs  - searchRange
    298         || e.test(((o[1] - *o) & 1) != 0, ERROROFFSET))                         // glyphs are in pairs so difference must be even.
    299            return ERROROFFSET;
    300    }
    301 
    302    return max_off;
    303 }
    304 
    305 uint16 Silf::findPseudo(uint32 uid) const
    306 {
    307    for (int i = 0; i < m_numPseudo; i++)
    308        if (m_pseudos[i].uid == uid) return m_pseudos[i].gid;
    309    return 0;
    310 }
    311 
    312 uint16 Silf::findClassIndex(uint16 cid, uint16 gid) const
    313 {
    314    if (cid > m_nClass) return -1;
    315 
    316    const uint16 * cls = m_classData + m_classOffsets[cid];
    317    if (cid < m_nLinear)        // output class being used for input, shouldn't happen
    318    {
    319        for (unsigned int i = 0, n = m_classOffsets[cid + 1] - m_classOffsets[cid]; i < n; ++i, ++cls)
    320            if (*cls == gid) return i;
    321        return -1;
    322    }
    323    else
    324    {
    325        const uint16 *  min = cls + 4,      // lookups array
    326                     *  max = min + cls[0]*2; // lookups aray is numIDs (cls[0]) uint16 pairs long
    327        do
    328        {
    329            const uint16 * p = min + (-2 & ((max-min)/2));
    330            if  (p[0] > gid)    max = p;
    331            else                min = p;
    332        }
    333        while (max - min > 2);
    334        return min[0] == gid ? min[1] : -1;
    335    }
    336 }
    337 
    338 uint16 Silf::getClassGlyph(uint16 cid, unsigned int index) const
    339 {
    340    if (cid > m_nClass) return 0;
    341 
    342    uint32 loc = m_classOffsets[cid];
    343    if (cid < m_nLinear)
    344    {
    345        if (index < m_classOffsets[cid + 1] - loc)
    346            return m_classData[index + loc];
    347    }
    348    else        // input class being used for output. Shouldn't happen
    349    {
    350        for (unsigned int i = loc + 4; i < m_classOffsets[cid + 1]; i += 2)
    351            if (m_classData[i + 1] == index) return m_classData[i];
    352    }
    353    return 0;
    354 }
    355 
    356 
    357 bool Silf::runGraphite(Segment *seg, uint8 firstPass, uint8 lastPass, int dobidi) const
    358 {
    359    assert(seg != 0);
    360    size_t             maxSize = seg->slotCount() * MAX_SEG_GROWTH_FACTOR;
    361    SlotMap            map(*seg, m_dir, maxSize);
    362    FiniteStateMachine fsm(map, seg->getFace()->logger());
    363    vm::Machine        m(map);
    364    uint8              lbidi = m_bPass;
    365 #if !defined GRAPHITE2_NTRACING
    366    json * const dbgout = seg->getFace()->logger();
    367 #endif
    368 
    369    if (lastPass == 0)
    370    {
    371        if (firstPass == lastPass && lbidi == 0xFF)
    372            return true;
    373        lastPass = m_numPasses;
    374    }
    375    if ((firstPass < lbidi || (dobidi && firstPass == lbidi)) && (lastPass >= lbidi || (dobidi && lastPass + 1 == lbidi)))
    376        lastPass++;
    377    else
    378        lbidi = 0xFF;
    379 
    380    for (size_t i = firstPass; i < lastPass; ++i)
    381    {
    382        // bidi and mirroring
    383        if (i == lbidi)
    384        {
    385 #if !defined GRAPHITE2_NTRACING
    386            if (dbgout)
    387            {
    388                *dbgout << json::item << json::object
    389 //							<< "pindex" << i   // for debugging
    390                            << "id"     << -1
    391                            << "slotsdir" << (seg->currdir() ? "rtl" : "ltr")
    392                            << "passdir" << (m_dir & 1 ? "rtl" : "ltr")
    393                            << "slots"  << json::array;
    394                seg->positionSlots(0, 0, 0, seg->currdir());
    395                for(Slot * s = seg->first(); s; s = s->next())
    396                    *dbgout     << dslot(seg, s);
    397                *dbgout         << json::close
    398                            << "rules"  << json::array << json::close
    399                            << json::close;
    400            }
    401 #endif
    402            if (seg->currdir() != (m_dir & 1))
    403                seg->reverseSlots();
    404            if (m_aMirror && (seg->dir() & 3) == 3)
    405                seg->doMirror(m_aMirror);
    406        --i;
    407        lbidi = lastPass;
    408        --lastPass;
    409        continue;
    410        }
    411 
    412 #if !defined GRAPHITE2_NTRACING
    413        if (dbgout)
    414        {
    415            *dbgout << json::item << json::object
    416 //						<< "pindex" << i   // for debugging
    417                        << "id"     << i+1
    418                        << "slotsdir" << (seg->currdir() ? "rtl" : "ltr")
    419                        << "passdir" << ((m_dir & 1) ^ m_passes[i].reverseDir() ? "rtl" : "ltr")
    420                        << "slots"  << json::array;
    421            seg->positionSlots(0, 0, 0, seg->currdir());
    422            for(Slot * s = seg->first(); s; s = s->next())
    423                *dbgout     << dslot(seg, s);
    424            *dbgout         << json::close;
    425        }
    426 #endif
    427 
    428        // test whether to reorder, prepare for positioning
    429        bool reverse = (lbidi == 0xFF) && (seg->currdir() != ((m_dir & 1) ^ m_passes[i].reverseDir()));
    430        if ((i >= 32 || (seg->passBits() & (1 << i)) == 0 || m_passes[i].collisionLoops())
    431                && !m_passes[i].runGraphite(m, fsm, reverse))
    432            return false;
    433        // only subsitution passes can change segment length, cached subsegments are short for their text
    434        if (m.status() != vm::Machine::finished
    435            || (seg->slotCount() && seg->slotCount() > maxSize))
    436            return false;
    437    }
    438    return true;
    439 }