tor-browser

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

Face.cpp (10330B)


      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 <cstring>
     28 #include "graphite2/Segment.h"
     29 #include "inc/CmapCache.h"
     30 #include "inc/debug.h"
     31 #include "inc/Decompressor.h"
     32 #include "inc/Endian.h"
     33 #include "inc/Face.h"
     34 #include "inc/FileFace.h"
     35 #include "inc/GlyphFace.h"
     36 #include "inc/json.h"
     37 #include "inc/Segment.h"
     38 #include "inc/NameTable.h"
     39 #include "inc/Error.h"
     40 
     41 using namespace graphite2;
     42 
     43 namespace
     44 {
     45 enum compression
     46 {
     47    NONE,
     48    LZ4
     49 };
     50 
     51 }
     52 
     53 Face::Face(const void* appFaceHandle/*non-NULL*/, const gr_face_ops & ops)
     54 : m_appFaceHandle(appFaceHandle),
     55  m_pFileFace(NULL),
     56  m_pGlyphFaceCache(NULL),
     57  m_cmap(NULL),
     58  m_pNames(NULL),
     59  m_logger(NULL),
     60  m_error(0), m_errcntxt(0),
     61  m_silfs(NULL),
     62  m_numSilf(0),
     63  m_ascent(0),
     64  m_descent(0)
     65 {
     66    memset(&m_ops, 0, sizeof m_ops);
     67    memcpy(&m_ops, &ops, min(sizeof m_ops, ops.size));
     68 }
     69 
     70 
     71 Face::~Face()
     72 {
     73    setLogger(0);
     74    delete m_pGlyphFaceCache;
     75    delete m_cmap;
     76    delete[] m_silfs;
     77 #ifndef GRAPHITE2_NFILEFACE
     78    delete m_pFileFace;
     79 #endif
     80    delete m_pNames;
     81 }
     82 
     83 float Face::default_glyph_advance(const void* font_ptr, gr_uint16 glyphid)
     84 {
     85    const Font & font = *reinterpret_cast<const Font *>(font_ptr);
     86 
     87    return font.face().glyphs().glyph(glyphid)->theAdvance().x * font.scale();
     88 }
     89 
     90 bool Face::readGlyphs(uint32 faceOptions)
     91 {
     92    Error e;
     93 #ifdef GRAPHITE2_TELEMETRY
     94    telemetry::category _glyph_cat(tele.glyph);
     95 #endif
     96    error_context(EC_READGLYPHS);
     97    m_pGlyphFaceCache = new GlyphCache(*this, faceOptions);
     98 
     99    if (e.test(!m_pGlyphFaceCache, E_OUTOFMEM)
    100        || e.test(m_pGlyphFaceCache->numGlyphs() == 0, E_NOGLYPHS)
    101        || e.test(m_pGlyphFaceCache->unitsPerEm() == 0, E_BADUPEM))
    102    {
    103        return error(e);
    104    }
    105 
    106    if (faceOptions & gr_face_cacheCmap)
    107        m_cmap = new CachedCmap(*this);
    108    else
    109        m_cmap = new DirectCmap(*this);
    110    if (e.test(!m_cmap, E_OUTOFMEM) || e.test(!*m_cmap, E_BADCMAP))
    111        return error(e);
    112 
    113    if (faceOptions & gr_face_preloadGlyphs)
    114        nameTable();        // preload the name table along with the glyphs.
    115 
    116    return true;
    117 }
    118 
    119 bool Face::readGraphite(const Table & silf)
    120 {
    121 #ifdef GRAPHITE2_TELEMETRY
    122    telemetry::category _silf_cat(tele.silf);
    123 #endif
    124    Error e;
    125    error_context(EC_READSILF);
    126    const byte * p = silf;
    127    if (e.test(!p, E_NOSILF) || e.test(silf.size() < 20, E_BADSIZE)) return error(e);
    128 
    129    const uint32 version = be::read<uint32>(p);
    130    if (e.test(version < 0x00020000, E_TOOOLD)) return error(e);
    131    if (version >= 0x00030000)
    132        be::skip<uint32>(p);        // compilerVersion
    133    m_numSilf = be::read<uint16>(p);
    134 
    135    be::skip<uint16>(p);            // reserved
    136 
    137    bool havePasses = false;
    138    m_silfs = new Silf[m_numSilf];
    139    if (e.test(!m_silfs, E_OUTOFMEM)) return error(e);
    140    for (int i = 0; i < m_numSilf; i++)
    141    {
    142        error_context(EC_ASILF + (i << 8));
    143        const uint32 offset = be::read<uint32>(p),
    144                     next   = i == m_numSilf - 1 ? uint32(silf.size()) : be::peek<uint32>(p);
    145        if (e.test(next > silf.size() || offset >= next, E_BADSIZE))
    146            return error(e);
    147 
    148        if (!m_silfs[i].readGraphite(silf + offset, next - offset, *this, version))
    149            return false;
    150 
    151        if (m_silfs[i].numPasses())
    152            havePasses = true;
    153    }
    154 
    155    return havePasses;
    156 }
    157 
    158 bool Face::readFeatures()
    159 {
    160    return m_Sill.readFace(*this);
    161 }
    162 
    163 bool Face::runGraphite(Segment *seg, const Silf *aSilf) const
    164 {
    165 #if !defined GRAPHITE2_NTRACING
    166    json * dbgout = logger();
    167    if (dbgout)
    168    {
    169        *dbgout << json::object
    170                    << "id"         << objectid(seg)
    171                    << "passes"     << json::array;
    172    }
    173 #endif
    174 
    175 //    if ((seg->dir() & 1) != aSilf->dir())
    176 //        seg->reverseSlots();
    177    if ((seg->dir() & 3) == 3 && aSilf->bidiPass() == 0xFF)
    178        seg->doMirror(aSilf->aMirror());
    179    bool res = aSilf->runGraphite(seg, 0, aSilf->positionPass(), true);
    180    if (res)
    181    {
    182        seg->associateChars(0, seg->charInfoCount());
    183        if (aSilf->flags() & 0x20)
    184            res &= seg->initCollisions();
    185        if (res)
    186            res &= aSilf->runGraphite(seg, aSilf->positionPass(), aSilf->numPasses(), false);
    187    }
    188 
    189 #if !defined GRAPHITE2_NTRACING
    190    if (dbgout)
    191 {
    192        seg->positionSlots(0, 0, 0, seg->currdir());
    193        *dbgout             << json::item
    194                            << json::close // Close up the passes array
    195                << "outputdir" << (seg->currdir() ? "rtl" : "ltr")
    196                << "output" << json::array;
    197        for(Slot * s = seg->first(); s; s = s->next())
    198            *dbgout     << dslot(seg, s);
    199        *dbgout         << json::close
    200                << "advance" << seg->advance()
    201                << "chars"   << json::array;
    202        for(size_t i = 0, n = seg->charInfoCount(); i != n; ++i)
    203            *dbgout     << json::flat << *seg->charinfo(int(i));
    204        *dbgout         << json::close  // Close up the chars array
    205                    << json::close;     // Close up the segment object
    206    }
    207 #endif
    208 
    209    return res;
    210 }
    211 
    212 void Face::setLogger(FILE * log_file GR_MAYBE_UNUSED)
    213 {
    214 #if !defined GRAPHITE2_NTRACING
    215    delete m_logger;
    216    m_logger = log_file ? new json(log_file) : 0;
    217 #endif
    218 }
    219 
    220 const Silf *Face::chooseSilf(uint32 script) const
    221 {
    222    if (m_numSilf == 0)
    223        return NULL;
    224    else if (m_numSilf == 1 || script == 0)
    225        return m_silfs;
    226    else // do more work here
    227        return m_silfs;
    228 }
    229 
    230 uint16 Face::findPseudo(uint32 uid) const
    231 {
    232    return (m_numSilf) ? m_silfs[0].findPseudo(uid) : 0;
    233 }
    234 
    235 int32 Face::getGlyphMetric(uint16 gid, uint8 metric) const
    236 {
    237    switch (metrics(metric))
    238    {
    239        case kgmetAscent : return m_ascent;
    240        case kgmetDescent : return m_descent;
    241        default:
    242            if (gid >= glyphs().numGlyphs()) return 0;
    243            return glyphs().glyph(gid)->getMetric(metric);
    244    }
    245 }
    246 
    247 void Face::takeFileFace(FileFace* pFileFace GR_MAYBE_UNUSED/*takes ownership*/)
    248 {
    249 #ifndef GRAPHITE2_NFILEFACE
    250    if (m_pFileFace==pFileFace)
    251      return;
    252 
    253    delete m_pFileFace;
    254    m_pFileFace = pFileFace;
    255 #endif
    256 }
    257 
    258 NameTable * Face::nameTable() const
    259 {
    260    if (m_pNames) return m_pNames;
    261    const Table name(*this, Tag::name);
    262    if (name)
    263        m_pNames = new NameTable(name, name.size());
    264    return m_pNames;
    265 }
    266 
    267 uint16 Face::languageForLocale(const char * locale) const
    268 {
    269    nameTable();
    270    if (m_pNames)
    271        return m_pNames->getLanguageId(locale);
    272    return 0;
    273 }
    274 
    275 
    276 
    277 Face::Table::Table(const Face & face, const Tag n, uint32 version) throw()
    278 : _f(&face), _sz(0), _compressed(false)
    279 {
    280    _p = static_cast<const byte *>((*_f->m_ops.get_table)(_f->m_appFaceHandle, n, &_sz));
    281 
    282    if (!TtfUtil::CheckTable(n, _p, _sz))
    283    {
    284        release();     // Make sure we release the table buffer even if the table failed its checks
    285        return;
    286    }
    287 
    288    if (be::peek<uint32>(_p) >= version)
    289        decompress();
    290 }
    291 
    292 void Face::Table::release()
    293 {
    294    if (_compressed)
    295        free(const_cast<byte *>(_p));
    296    else if (_p && _f->m_ops.release_table)
    297        (*_f->m_ops.release_table)(_f->m_appFaceHandle, _p);
    298    _p = 0; _sz = 0;
    299 }
    300 
    301 Face::Table & Face::Table::operator = (const Table && rhs) throw()
    302 {
    303    if (this == &rhs)   return *this;
    304    release();
    305    new (this) Table(std::move(rhs));
    306    return *this;
    307 }
    308 
    309 Error Face::Table::decompress()
    310 {
    311    Error e;
    312    if (e.test(_sz < 5 * sizeof(uint32), E_BADSIZE))
    313        return e;
    314    byte * uncompressed_table = 0;
    315    size_t uncompressed_size = 0;
    316 
    317    const byte * p = _p;
    318    const uint32 version = be::read<uint32>(p);    // Table version number.
    319 
    320    // The scheme is in the top 5 bits of the 1st uint32.
    321    const uint32 hdr = be::read<uint32>(p);
    322    switch(compression(hdr >> 27))
    323    {
    324    case NONE: return e;
    325 
    326    case LZ4:
    327    {
    328        uncompressed_size  = hdr & 0x07ffffff;
    329        uncompressed_table = gralloc<byte>(uncompressed_size);
    330        if (!e.test(!uncompressed_table || uncompressed_size < 4, E_OUTOFMEM))
    331        {
    332            memset(uncompressed_table, 0, 4);   // make sure version number is initialised
    333            // coverity[forward_null : FALSE] - uncompressed_table has been checked so can't be null
    334            // coverity[checked_return : FALSE] - we test e later
    335            e.test(lz4::decompress(p, _sz - 2*sizeof(uint32), uncompressed_table, uncompressed_size) != signed(uncompressed_size), E_SHRINKERFAILED);
    336        }
    337        break;
    338    }
    339 
    340    default:
    341        e.error(E_BADSCHEME);
    342    };
    343 
    344    // Check the uncompressed version number against the original.
    345    if (!e)
    346        // coverity[forward_null : FALSE] - uncompressed_table has already been tested so can't be null
    347        // coverity[checked_return : FALSE] - we test e later
    348        e.test(be::peek<uint32>(uncompressed_table) != version, E_SHRINKERFAILED);
    349 
    350    // Tell the provider to release the compressed form since were replacing
    351    //   it anyway.
    352    release();
    353 
    354    if (e)
    355    {
    356        free(uncompressed_table);
    357        uncompressed_table = 0;
    358        uncompressed_size  = 0;
    359    }
    360 
    361    _p = uncompressed_table;
    362    _sz = uncompressed_size;
    363    _compressed = true;
    364 
    365    return e;
    366 }