tor-browser

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

GlyphCache.cpp (16340B)


      1 /*  GRAPHITE2 LICENSING
      2 
      3    Copyright 2012, 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 "graphite2/Font.h"
     28 
     29 #include "inc/Main.h"
     30 #include "inc/Face.h"     //for the tags
     31 #include "inc/GlyphCache.h"
     32 #include "inc/GlyphFace.h"
     33 #include "inc/Endian.h"
     34 #include "inc/bits.h"
     35 
     36 using namespace graphite2;
     37 
     38 namespace
     39 {
     40    // Iterator over version 1 or 2 glat entries which consist of a series of
     41    //    +-+-+-+-+-+-+-+-+-+-+                +-+-+-+-+-+-+-+-+-+-+-+-+
     42    // v1 |k|n|v1 |v2 |...|vN |     or    v2   | k | n |v1 |v2 |...|vN |
     43    //    +-+-+-+-+-+-+-+-+-+-+                +-+-+-+-+-+-+-+-+-+-+-+-+
     44    // variable length structures.
     45 
     46    template<typename W>
     47    class _glat_iterator : public std::iterator<std::input_iterator_tag, std::pair<sparse::key_type, sparse::mapped_type> >
     48    {
     49        unsigned short  key() const             { return uint16(be::peek<W>(_e) + _n); }
     50        unsigned int    run() const             { return be::peek<W>(_e+sizeof(W)); }
     51        void            advance_entry()         { _n = 0; _e = _v; be::skip<W>(_v,2); }
     52    public:
     53        _glat_iterator(const void * glat=0) : _e(reinterpret_cast<const byte *>(glat)), _v(_e+2*sizeof(W)), _n(0) {}
     54 
     55        _glat_iterator<W> & operator ++ () {
     56            ++_n; be::skip<uint16>(_v);
     57            if (_n == run()) advance_entry();
     58            return *this;
     59        }
     60        _glat_iterator<W>   operator ++ (int)   { _glat_iterator<W> tmp(*this); operator++(); return tmp; }
     61 
     62        // This is strictly a >= operator. A true == operator could be
     63        // implemented that test for overlap but it would be more expensive a
     64        // test.
     65        bool operator == (const _glat_iterator<W> & rhs) { return _v >= rhs._e - 1; }
     66        bool operator != (const _glat_iterator<W> & rhs) { return !operator==(rhs); }
     67 
     68        value_type          operator * () const {
     69            return value_type(key(), be::peek<uint16>(_v));
     70        }
     71 
     72    protected:
     73        const byte     * _e, * _v;
     74        size_t        _n;
     75    };
     76 
     77    typedef _glat_iterator<uint8>   glat_iterator;
     78    typedef _glat_iterator<uint16>  glat2_iterator;
     79 }
     80 
     81 const SlantBox SlantBox::empty = {0,0,0,0};
     82 
     83 
     84 class GlyphCache::Loader
     85 {
     86 public:
     87    Loader(const Face & face);    //return result indicates success. Do not use if failed.
     88 
     89    operator bool () const throw();
     90    unsigned short int units_per_em() const throw();
     91    unsigned short int num_glyphs() const throw();
     92    unsigned short int num_attrs() const throw();
     93    bool has_boxes() const throw();
     94 
     95    const GlyphFace * read_glyph(unsigned short gid, GlyphFace &, int *numsubs) const throw();
     96    GlyphBox * read_box(uint16 gid, GlyphBox *curr, const GlyphFace & face) const throw();
     97 
     98    CLASS_NEW_DELETE;
     99 private:
    100    Face::Table _head,
    101                _hhea,
    102                _hmtx,
    103                _glyf,
    104                _loca,
    105                m_pGlat,
    106                m_pGloc;
    107 
    108    bool            _long_fmt;
    109    bool            _has_boxes;
    110    unsigned short  _num_glyphs_graphics,        //i.e. boundary box and advance
    111                    _num_glyphs_attributes,
    112                    _num_attrs;                    // number of glyph attributes per glyph
    113 };
    114 
    115 
    116 
    117 GlyphCache::GlyphCache(const Face & face, const uint32 face_options)
    118 : _glyph_loader(new Loader(face)),
    119  _glyphs(_glyph_loader && *_glyph_loader && _glyph_loader->num_glyphs()
    120        ? grzeroalloc<const GlyphFace *>(_glyph_loader->num_glyphs()) : 0),
    121  _boxes(_glyph_loader && _glyph_loader->has_boxes() && _glyph_loader->num_glyphs()
    122        ? grzeroalloc<GlyphBox *>(_glyph_loader->num_glyphs()) : 0),
    123  _num_glyphs(_glyphs ? _glyph_loader->num_glyphs() : 0),
    124  _num_attrs(_glyphs ? _glyph_loader->num_attrs() : 0),
    125  _upem(_glyphs ? _glyph_loader->units_per_em() : 0)
    126 {
    127    if ((face_options & gr_face_preloadGlyphs) && _glyph_loader && _glyphs)
    128    {
    129        int numsubs = 0;
    130        GlyphFace * const glyphs = new GlyphFace [_num_glyphs];
    131        if (!glyphs)
    132            return;
    133 
    134        // The 0 glyph is definately required.
    135        _glyphs[0] = _glyph_loader->read_glyph(0, glyphs[0], &numsubs);
    136 
    137        // glyphs[0] has the same address as the glyphs array just allocated,
    138        //  thus assigning the &glyphs[0] to _glyphs[0] means _glyphs[0] points
    139        //  to the entire array.
    140        const GlyphFace * loaded = _glyphs[0];
    141        for (uint16 gid = 1; loaded && gid != _num_glyphs; ++gid)
    142            _glyphs[gid] = loaded = _glyph_loader->read_glyph(gid, glyphs[gid], &numsubs);
    143 
    144        if (!loaded)
    145        {
    146            _glyphs[0] = 0;
    147            delete [] glyphs;
    148        }
    149        else if (numsubs > 0 && _boxes)
    150        {
    151            GlyphBox * boxes = (GlyphBox *)gralloc<char>(_num_glyphs * sizeof(GlyphBox) + numsubs * 8 * sizeof(float));
    152            GlyphBox * currbox = boxes;
    153 
    154            for (uint16 gid = 0; currbox && gid != _num_glyphs; ++gid)
    155            {
    156                _boxes[gid] = currbox;
    157                currbox = _glyph_loader->read_box(gid, currbox, *_glyphs[gid]);
    158            }
    159            if (!currbox)
    160            {
    161                free(boxes);
    162                _boxes[0] = 0;
    163            }
    164        }
    165        delete _glyph_loader;
    166        _glyph_loader = 0;
    167 // coverity[leaked_storage : FALSE] - calling read_glyph on index 0 saved
    168 // glyphs as _glyphs[0]. Setting _glyph_loader to nullptr here flags that
    169 // the dtor needs to call delete[] on _glyphs[0] to release what was allocated
    170 // as glyphs
    171    }
    172 
    173    if (_glyphs && glyph(0) == 0)
    174    {
    175        free(_glyphs);
    176        _glyphs = 0;
    177        if (_boxes)
    178        {
    179            free(_boxes);
    180            _boxes = 0;
    181        }
    182        _num_glyphs = _num_attrs = _upem = 0;
    183    }
    184 }
    185 
    186 
    187 GlyphCache::~GlyphCache()
    188 {
    189    if (_glyphs)
    190    {
    191        if (_glyph_loader)
    192        {
    193            const GlyphFace *  * g = _glyphs;
    194            for(unsigned short n = _num_glyphs; n; --n, ++g)
    195                delete *g;
    196        }
    197        else
    198            delete [] _glyphs[0];
    199        free(_glyphs);
    200    }
    201    if (_boxes)
    202    {
    203        if (_glyph_loader)
    204        {
    205            GlyphBox *  * g = _boxes;
    206            for (uint16 n = _num_glyphs; n; --n, ++g)
    207                free(*g);
    208        }
    209        else
    210            free(_boxes[0]);
    211        free(_boxes);
    212    }
    213    delete _glyph_loader;
    214 }
    215 
    216 const GlyphFace *GlyphCache::glyph(unsigned short glyphid) const      //result may be changed by subsequent call with a different glyphid
    217 {
    218    if (glyphid >= numGlyphs())
    219        return _glyphs[0];
    220    const GlyphFace * & p = _glyphs[glyphid];
    221    if (p == 0 && _glyph_loader)
    222    {
    223        int numsubs = 0;
    224        GlyphFace * g = new GlyphFace();
    225        if (g)  p = _glyph_loader->read_glyph(glyphid, *g, &numsubs);
    226        if (!p)
    227        {
    228            delete g;
    229            return *_glyphs;
    230        }
    231        if (_boxes)
    232        {
    233            _boxes[glyphid] = (GlyphBox *)gralloc<char>(sizeof(GlyphBox) + 8 * numsubs * sizeof(float));
    234            if (!_glyph_loader->read_box(glyphid, _boxes[glyphid], *_glyphs[glyphid]))
    235            {
    236                free(_boxes[glyphid]);
    237                _boxes[glyphid] = 0;
    238            }
    239        }
    240    }
    241    return p;
    242 }
    243 
    244 
    245 
    246 GlyphCache::Loader::Loader(const Face & face)
    247 : _head(face, Tag::head),
    248  _hhea(face, Tag::hhea),
    249  _hmtx(face, Tag::hmtx),
    250  _glyf(face, Tag::glyf),
    251  _loca(face, Tag::loca),
    252  _long_fmt(false),
    253  _has_boxes(false),
    254  _num_glyphs_graphics(0),
    255  _num_glyphs_attributes(0),
    256  _num_attrs(0)
    257 {
    258    if (!operator bool())
    259        return;
    260 
    261    const Face::Table maxp = Face::Table(face, Tag::maxp);
    262    if (!maxp) { _head = Face::Table(); return; }
    263 
    264    _num_glyphs_graphics = static_cast<unsigned short>(TtfUtil::GlyphCount(maxp));
    265    // This will fail if the number of glyphs is wildly out of range.
    266    if (_glyf && TtfUtil::LocaLookup(_num_glyphs_graphics-1, _loca, _loca.size(), _head) == size_t(-2))
    267    {
    268        _head = Face::Table();
    269        return;
    270    }
    271 
    272    if ((m_pGlat = Face::Table(face, Tag::Glat, 0x00030000)) == NULL
    273        || (m_pGloc = Face::Table(face, Tag::Gloc)) == NULL
    274        || m_pGloc.size() < 8)
    275    {
    276        _head = Face::Table();
    277        return;
    278    }
    279    const byte    * p = m_pGloc;
    280    int       version = be::read<uint32>(p);
    281    const uint16    flags = be::read<uint16>(p);
    282    _num_attrs = be::read<uint16>(p);
    283    // We can accurately calculate the number of attributed glyphs by
    284    //  subtracting the length of the attribids array (numAttribs long if present)
    285    //  and dividing by either 2 or 4 depending on shor or lonf format
    286    _long_fmt              = flags & 1;
    287    ptrdiff_t tmpnumgattrs       = (m_pGloc.size()
    288                               - (p - m_pGloc)
    289                               - sizeof(uint16)*(flags & 0x2 ? _num_attrs : 0))
    290                                   / (_long_fmt ? sizeof(uint32) : sizeof(uint16)) - 1;
    291 
    292    if (version >= 0x00020000 || tmpnumgattrs < 0 || tmpnumgattrs > 65535
    293        || _num_attrs == 0 || _num_attrs > 0x3000  // is this hard limit appropriate?
    294        || _num_glyphs_graphics > tmpnumgattrs
    295        || m_pGlat.size() < 4)
    296    {
    297        _head = Face::Table();
    298        return;
    299    }
    300 
    301    _num_glyphs_attributes = static_cast<unsigned short>(tmpnumgattrs);
    302    p = m_pGlat;
    303    version = be::read<uint32>(p);
    304    if (version >= 0x00040000 || (version >= 0x00030000 && m_pGlat.size() < 8))       // reject Glat tables that are too new
    305    {
    306        _head = Face::Table();
    307        return;
    308    }
    309    else if (version >= 0x00030000)
    310    {
    311        unsigned int glatflags = be::read<uint32>(p);
    312        _has_boxes = glatflags & 1;
    313        // delete this once the compiler is fixed
    314        _has_boxes = true;
    315    }
    316 }
    317 
    318 inline
    319 GlyphCache::Loader::operator bool () const throw()
    320 {
    321    return _head && _hhea && _hmtx && !(bool(_glyf) != bool(_loca));
    322 }
    323 
    324 inline
    325 unsigned short int GlyphCache::Loader::units_per_em() const throw()
    326 {
    327    return _head ? TtfUtil::DesignUnits(_head) : 0;
    328 }
    329 
    330 inline
    331 unsigned short int GlyphCache::Loader::num_glyphs() const throw()
    332 {
    333    return max(_num_glyphs_graphics, _num_glyphs_attributes);
    334 }
    335 
    336 inline
    337 unsigned short int GlyphCache::Loader::num_attrs() const throw()
    338 {
    339    return _num_attrs;
    340 }
    341 
    342 inline
    343 bool GlyphCache::Loader::has_boxes () const throw()
    344 {
    345    return _has_boxes;
    346 }
    347 
    348 const GlyphFace * GlyphCache::Loader::read_glyph(unsigned short glyphid, GlyphFace & glyph, int *numsubs) const throw()
    349 {
    350    Rect        bbox;
    351    Position    advance;
    352 
    353    if (glyphid < _num_glyphs_graphics)
    354    {
    355        int nLsb;
    356        unsigned int nAdvWid;
    357        if (_glyf)
    358        {
    359            int xMin, yMin, xMax, yMax;
    360            size_t locidx = TtfUtil::LocaLookup(glyphid, _loca, _loca.size(), _head);
    361            void *pGlyph = TtfUtil::GlyfLookup(_glyf, locidx, _glyf.size());
    362 
    363            if (pGlyph && TtfUtil::GlyfBox(pGlyph, xMin, yMin, xMax, yMax))
    364            {
    365                if ((xMin > xMax) || (yMin > yMax))
    366                    return 0;
    367                bbox = Rect(Position(static_cast<float>(xMin), static_cast<float>(yMin)),
    368                    Position(static_cast<float>(xMax), static_cast<float>(yMax)));
    369            }
    370        }
    371        if (TtfUtil::HorMetrics(glyphid, _hmtx, _hmtx.size(), _hhea, nLsb, nAdvWid))
    372            advance = Position(static_cast<float>(nAdvWid), 0);
    373    }
    374 
    375    if (glyphid < _num_glyphs_attributes)
    376    {
    377        const byte * gloc = m_pGloc;
    378        size_t      glocs = 0, gloce = 0;
    379 
    380        be::skip<uint32>(gloc);
    381        be::skip<uint16>(gloc,2);
    382        if (_long_fmt)
    383        {
    384            if (8 + glyphid * sizeof(uint32) > m_pGloc.size())
    385                return 0;
    386            be::skip<uint32>(gloc, glyphid);
    387            glocs = be::read<uint32>(gloc);
    388            gloce = be::peek<uint32>(gloc);
    389        }
    390        else
    391        {
    392            if (8 + glyphid * sizeof(uint16) > m_pGloc.size())
    393                return 0;
    394            be::skip<uint16>(gloc, glyphid);
    395            glocs = be::read<uint16>(gloc);
    396            gloce = be::peek<uint16>(gloc);
    397        }
    398 
    399        if (glocs >= m_pGlat.size() - 1 || gloce > m_pGlat.size())
    400            return 0;
    401 
    402        const uint32 glat_version = be::peek<uint32>(m_pGlat);
    403        if (glat_version >= 0x00030000)
    404        {
    405            if (glocs >= gloce)
    406                return 0;
    407            const byte * p = m_pGlat + glocs;
    408            uint16 bmap = be::read<uint16>(p);
    409            int num = bit_set_count((uint32)bmap);
    410            if (numsubs) *numsubs += num;
    411            glocs += 6 + 8 * num;
    412            if (glocs > gloce)
    413                return 0;
    414        }
    415        if (glat_version < 0x00020000)
    416        {
    417            if (gloce - glocs < 2*sizeof(byte)+sizeof(uint16)
    418                || gloce - glocs > _num_attrs*(2*sizeof(byte)+sizeof(uint16)))
    419                    return 0;
    420            new (&glyph) GlyphFace(bbox, advance, glat_iterator(m_pGlat + glocs), glat_iterator(m_pGlat + gloce));
    421        }
    422        else
    423        {
    424            if (gloce - glocs < 3*sizeof(uint16)        // can a glyph have no attributes? why not?
    425                || gloce - glocs > _num_attrs*3*sizeof(uint16)
    426                || glocs > m_pGlat.size() - 2*sizeof(uint16))
    427                    return 0;
    428            new (&glyph) GlyphFace(bbox, advance, glat2_iterator(m_pGlat + glocs), glat2_iterator(m_pGlat + gloce));
    429        }
    430        if (!glyph.attrs() || glyph.attrs().capacity() > _num_attrs)
    431            return 0;
    432    }
    433    return &glyph;
    434 }
    435 
    436 inline float scale_to(uint8 t, float zmin, float zmax)
    437 {
    438    return (zmin + t * (zmax - zmin) / 255);
    439 }
    440 
    441 Rect readbox(Rect &b, uint8 zxmin, uint8 zymin, uint8 zxmax, uint8 zymax)
    442 {
    443    return Rect(Position(scale_to(zxmin, b.bl.x, b.tr.x), scale_to(zymin, b.bl.y, b.tr.y)),
    444                Position(scale_to(zxmax, b.bl.x, b.tr.x), scale_to(zymax, b.bl.y, b.tr.y)));
    445 }
    446 
    447 GlyphBox * GlyphCache::Loader::read_box(uint16 gid, GlyphBox *curr, const GlyphFace & glyph) const throw()
    448 {
    449    if (gid >= _num_glyphs_attributes) return 0;
    450 
    451    const byte * gloc = m_pGloc;
    452    size_t      glocs = 0, gloce = 0;
    453 
    454    be::skip<uint32>(gloc);
    455    be::skip<uint16>(gloc,2);
    456    if (_long_fmt)
    457    {
    458        be::skip<uint32>(gloc, gid);
    459        glocs = be::read<uint32>(gloc);
    460        gloce = be::peek<uint32>(gloc);
    461    }
    462    else
    463    {
    464        be::skip<uint16>(gloc, gid);
    465        glocs = be::read<uint16>(gloc);
    466        gloce = be::peek<uint16>(gloc);
    467    }
    468 
    469    if (gloce > m_pGlat.size() || glocs + 6 >= gloce)
    470        return 0;
    471 
    472    const byte * p = m_pGlat + glocs;
    473    uint16 bmap = be::read<uint16>(p);
    474    int num = bit_set_count((uint32)bmap);
    475 
    476    Rect bbox = glyph.theBBox();
    477    Rect diamax(Position(bbox.bl.x + bbox.bl.y, bbox.bl.x - bbox.tr.y),
    478                Position(bbox.tr.x + bbox.tr.y, bbox.tr.x - bbox.bl.y));
    479    Rect diabound = readbox(diamax, p[0], p[2], p[1], p[3]);
    480    ::new (curr) GlyphBox(num, bmap, &diabound);
    481    be::skip<uint8>(p, 4);
    482    if (glocs + 6 + num * 8 >= gloce)
    483        return 0;
    484 
    485    for (int i = 0; i < num * 2; ++i)
    486    {
    487        Rect box = readbox((i & 1) ? diamax : bbox, p[0], p[2], p[1], p[3]);
    488        curr->addSubBox(i >> 1, i & 1, &box);
    489        be::skip<uint8>(p, 4);
    490    }
    491    return (GlyphBox *)((char *)(curr) + sizeof(GlyphBox) + 2 * num * sizeof(Rect));
    492 }