gfx/graphite2/src/GlyphCache.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/graphite2/src/GlyphCache.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,341 @@
     1.4 +/*  GRAPHITE2 LICENSING
     1.5 +
     1.6 +    Copyright 2012, SIL International
     1.7 +    All rights reserved.
     1.8 +
     1.9 +    This library is free software; you can redistribute it and/or modify
    1.10 +    it under the terms of the GNU Lesser General Public License as published
    1.11 +    by the Free Software Foundation; either version 2.1 of License, or
    1.12 +    (at your option) any later version.
    1.13 +
    1.14 +    This program is distributed in the hope that it will be useful,
    1.15 +    but WITHOUT ANY WARRANTY; without even the implied warranty of
    1.16 +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    1.17 +    Lesser General Public License for more details.
    1.18 +
    1.19 +    You should also have received a copy of the GNU Lesser General Public
    1.20 +    License along with this library in the file named "LICENSE".
    1.21 +    If not, write to the Free Software Foundation, 51 Franklin Street, 
    1.22 +    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the 
    1.23 +    internet at http://www.fsf.org/licenses/lgpl.html.
    1.24 +
    1.25 +Alternatively, the contents of this file may be used under the terms of the
    1.26 +Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
    1.27 +License, as published by the Free Software Foundation, either version 2
    1.28 +of the License or (at your option) any later version.
    1.29 +*/
    1.30 +#include "graphite2/Font.h"
    1.31 +
    1.32 +#include "inc/Main.h"
    1.33 +#include "inc/Face.h"     //for the tags
    1.34 +#include "inc/GlyphCache.h"
    1.35 +#include "inc/GlyphFace.h"
    1.36 +#include "inc/Endian.h"
    1.37 +
    1.38 +using namespace graphite2;
    1.39 +
    1.40 +namespace
    1.41 +{
    1.42 +    // Iterator over version 1 or 2 glat entries which consist of a series of
    1.43 +    //    +-+-+-+-+-+-+-+-+-+-+                +-+-+-+-+-+-+-+-+-+-+-+-+
    1.44 +    // v1 |k|n|v1 |v2 |...|vN |     or    v2   | k | n |v1 |v2 |...|vN |
    1.45 +    //    +-+-+-+-+-+-+-+-+-+-+                +-+-+-+-+-+-+-+-+-+-+-+-+
    1.46 +    // variable length structures.
    1.47 +
    1.48 +    template<typename W>
    1.49 +    class _glat_iterator : public std::iterator<std::input_iterator_tag, std::pair<sparse::key_type, sparse::mapped_type> >
    1.50 +    {
    1.51 +        unsigned short  key() const             { return be::peek<W>(_e) + _n; }
    1.52 +        unsigned int    run() const             { return be::peek<W>(_e+sizeof(W)); }
    1.53 +        void            advance_entry()         { _n = 0; _e = _v; be::skip<W>(_v,2); }
    1.54 +    public:
    1.55 +        _glat_iterator(const void * glat=0) : _e(reinterpret_cast<const byte *>(glat)), _v(_e+2*sizeof(W)), _n(0) {}
    1.56 +
    1.57 +        _glat_iterator<W> & operator ++ () {
    1.58 +            ++_n; be::skip<uint16>(_v);
    1.59 +            if (_n == run()) advance_entry();
    1.60 +            return *this;
    1.61 +        }
    1.62 +        _glat_iterator<W>   operator ++ (int)   { _glat_iterator<W> tmp(*this); operator++(); return tmp; }
    1.63 +
    1.64 +        // This is strictly a >= operator. A true == operator could be
    1.65 +        // implemented that test for overlap but it would be more expensive a
    1.66 +        // test.
    1.67 +        bool operator == (const _glat_iterator<W> & rhs) { return _v >= rhs._e; }
    1.68 +        bool operator != (const _glat_iterator<W> & rhs) { return !operator==(rhs); }
    1.69 +
    1.70 +        value_type          operator * () const {
    1.71 +            return value_type(key(), be::peek<uint16>(_v));
    1.72 +        }
    1.73 +
    1.74 +    protected:
    1.75 +        const byte     * _e, * _v;
    1.76 +        ptrdiff_t        _n;
    1.77 +    };
    1.78 +
    1.79 +    typedef _glat_iterator<uint8>   glat_iterator;
    1.80 +    typedef _glat_iterator<uint16>  glat2_iterator;
    1.81 +}
    1.82 +
    1.83 +
    1.84 +class GlyphCache::Loader
    1.85 +{
    1.86 +public:
    1.87 +    Loader(const Face & face, const bool dumb_font);    //return result indicates success. Do not use if failed.
    1.88 +
    1.89 +    operator bool () const throw();
    1.90 +    unsigned short int units_per_em() const throw();
    1.91 +    unsigned short int num_glyphs() const throw();
    1.92 +    unsigned short int num_attrs() const throw();
    1.93 +
    1.94 +    const GlyphFace * read_glyph(unsigned short gid, GlyphFace &) const throw();
    1.95 +
    1.96 +    CLASS_NEW_DELETE;
    1.97 +private:
    1.98 +    Face::Table _head,
    1.99 +                _hhea,
   1.100 +                _hmtx,
   1.101 +                _glyf,
   1.102 +                _loca,
   1.103 +                m_pGlat,
   1.104 +                m_pGloc;
   1.105 +
   1.106 +    bool            _long_fmt;
   1.107 +    unsigned short  _num_glyphs_graphics,        //i.e. boundary box and advance
   1.108 +                    _num_glyphs_attributes,
   1.109 +                    _num_attrs;                    // number of glyph attributes per glyph
   1.110 +};
   1.111 +
   1.112 +
   1.113 +
   1.114 +GlyphCache::GlyphCache(const Face & face, const uint32 face_options)
   1.115 +: _glyph_loader(new Loader(face, bool(face_options & gr_face_dumbRendering))),
   1.116 +  _glyphs(_glyph_loader && *_glyph_loader ? grzeroalloc<const GlyphFace *>(_glyph_loader->num_glyphs()) : 0),
   1.117 +  _num_glyphs(_glyphs ? _glyph_loader->num_glyphs() : 0),
   1.118 +  _num_attrs(_glyphs ? _glyph_loader->num_attrs() : 0),
   1.119 +  _upem(_glyphs ? _glyph_loader->units_per_em() : 0)
   1.120 +{
   1.121 +    if ((face_options & gr_face_preloadGlyphs) && _glyph_loader && _glyphs)
   1.122 +    {
   1.123 +        GlyphFace * const glyphs = new GlyphFace [_num_glyphs];
   1.124 +        if (!glyphs)
   1.125 +            return;
   1.126 +
   1.127 +        // The 0 glyph is definately required.
   1.128 +        _glyphs[0] = _glyph_loader->read_glyph(0, glyphs[0]);
   1.129 +
   1.130 +        // glyphs[0] has the same address as the glyphs array just allocated,
   1.131 +        //  thus assigning the &glyphs[0] to _glyphs[0] means _glyphs[0] points
   1.132 +        //  to the entire array.
   1.133 +        const GlyphFace * loaded = _glyphs[0];
   1.134 +        for (uint16 gid = 1; loaded && gid != _num_glyphs; ++gid)
   1.135 +            _glyphs[gid] = loaded = _glyph_loader->read_glyph(gid, glyphs[gid]);
   1.136 +
   1.137 +        if (!loaded)
   1.138 +        {
   1.139 +            _glyphs[0] = 0;
   1.140 +            delete [] glyphs;
   1.141 +        }
   1.142 +        delete _glyph_loader;
   1.143 +        _glyph_loader = 0;
   1.144 +    }
   1.145 +
   1.146 +    if (_glyphs && glyph(0) == 0)
   1.147 +    {
   1.148 +        free(_glyphs);
   1.149 +        _glyphs = 0;
   1.150 +        _num_glyphs = _num_attrs = _upem = 0;
   1.151 +    }
   1.152 +}
   1.153 +
   1.154 +
   1.155 +GlyphCache::~GlyphCache()
   1.156 +{
   1.157 +    if (_glyphs)
   1.158 +    {
   1.159 +        if (_glyph_loader)
   1.160 +        {
   1.161 +            const GlyphFace *  * g = _glyphs;
   1.162 +            for(unsigned short n = _num_glyphs; n; --n, ++g)
   1.163 +                delete *g;
   1.164 +        }
   1.165 +        else
   1.166 +            delete [] _glyphs[0];
   1.167 +        free(_glyphs);
   1.168 +    }
   1.169 +    delete _glyph_loader;
   1.170 +}
   1.171 +
   1.172 +const GlyphFace *GlyphCache::glyph(unsigned short glyphid) const      //result may be changed by subsequent call with a different glyphid
   1.173 +{ 
   1.174 +    const GlyphFace * & p = _glyphs[glyphid];
   1.175 +    if (p == 0 && _glyph_loader)
   1.176 +    {
   1.177 +        GlyphFace * g = new GlyphFace();
   1.178 +        if (g)  p = _glyph_loader->read_glyph(glyphid, *g);
   1.179 +        if (!p)
   1.180 +        {
   1.181 +            delete g;
   1.182 +            return *_glyphs;
   1.183 +        }
   1.184 +    }
   1.185 +    return p;
   1.186 +}
   1.187 +
   1.188 +
   1.189 +
   1.190 +GlyphCache::Loader::Loader(const Face & face, const bool dumb_font)
   1.191 +: _head(face, Tag::head),
   1.192 +  _hhea(face, Tag::hhea),
   1.193 +  _hmtx(face, Tag::hmtx),
   1.194 +  _glyf(face, Tag::glyf),
   1.195 +  _loca(face, Tag::loca),
   1.196 +  _long_fmt(false),
   1.197 +  _num_glyphs_graphics(0),
   1.198 +  _num_glyphs_attributes(0),
   1.199 +  _num_attrs(0)
   1.200 +{
   1.201 +    if (!operator bool())
   1.202 +        return;
   1.203 +
   1.204 +    const Face::Table maxp = Face::Table(face, Tag::maxp);
   1.205 +    if (!maxp) { _head = Face::Table(); return; }
   1.206 +
   1.207 +    _num_glyphs_graphics = TtfUtil::GlyphCount(maxp);
   1.208 +    // This will fail if the number of glyphs is wildly out of range.
   1.209 +    if (_glyf && TtfUtil::LocaLookup(_num_glyphs_graphics-1, _loca, _loca.size(), _head) == size_t(-1))
   1.210 +    {
   1.211 +        _head = Face::Table();
   1.212 +        return;
   1.213 +    }
   1.214 +
   1.215 +    if (!dumb_font)
   1.216 +    {
   1.217 +        if ((m_pGlat = Face::Table(face, Tag::Glat)) == NULL
   1.218 +            || (m_pGloc = Face::Table(face, Tag::Gloc)) == NULL
   1.219 +            || m_pGloc.size() < 6)
   1.220 +        {
   1.221 +            _head = Face::Table();
   1.222 +            return;
   1.223 +        }
   1.224 +        const byte    * p = m_pGloc;
   1.225 +        const int       version = be::read<uint32>(p);
   1.226 +        const uint16    flags = be::read<uint16>(p);
   1.227 +        _num_attrs = be::read<uint16>(p);
   1.228 +        // We can accurately calculate the number of attributed glyphs by
   1.229 +        //  subtracting the length of the attribids array (numAttribs long if present)
   1.230 +        //  and dividing by either 2 or 4 depending on shor or lonf format
   1.231 +        _long_fmt              = flags & 1;
   1.232 +        _num_glyphs_attributes = (m_pGloc.size()
   1.233 +                                   - (p - m_pGloc)
   1.234 +                                   - sizeof(uint16)*(flags & 0x2 ? _num_attrs : 0))
   1.235 +                                       / (_long_fmt ? sizeof(uint32) : sizeof(uint16)) - 1;
   1.236 +
   1.237 +        if (version != 0x00010000
   1.238 +            || _num_attrs == 0 || _num_attrs > 0x3000  // is this hard limit appropriate?
   1.239 +            || _num_glyphs_graphics > _num_glyphs_attributes)
   1.240 +        {
   1.241 +            _head = Face::Table();
   1.242 +            return;
   1.243 +        }
   1.244 +    }
   1.245 +}
   1.246 +
   1.247 +inline
   1.248 +GlyphCache::Loader::operator bool () const throw()
   1.249 +{
   1.250 +    return _head && _hhea && _hmtx && !(bool(_glyf) != bool(_loca));
   1.251 +}
   1.252 +
   1.253 +inline
   1.254 +unsigned short int GlyphCache::Loader::units_per_em() const throw()
   1.255 +{
   1.256 +    return _head ? TtfUtil::DesignUnits(_head) : 0;
   1.257 +}
   1.258 +
   1.259 +inline
   1.260 +unsigned short int GlyphCache::Loader::num_glyphs() const throw()
   1.261 +{
   1.262 +    return max(_num_glyphs_graphics, _num_glyphs_attributes);
   1.263 +}
   1.264 +
   1.265 +inline
   1.266 +unsigned short int GlyphCache::Loader::num_attrs() const throw()
   1.267 +{
   1.268 +    return _num_attrs;
   1.269 +}
   1.270 +
   1.271 +const GlyphFace * GlyphCache::Loader::read_glyph(unsigned short glyphid, GlyphFace & glyph) const throw()
   1.272 +{
   1.273 +    Rect        bbox;
   1.274 +    Position    advance;
   1.275 +
   1.276 +    if (glyphid < _num_glyphs_graphics)
   1.277 +    {
   1.278 +        int nLsb;
   1.279 +        unsigned int nAdvWid;
   1.280 +        if (_glyf)
   1.281 +        {
   1.282 +            int xMin, yMin, xMax, yMax;
   1.283 +            size_t locidx = TtfUtil::LocaLookup(glyphid, _loca, _loca.size(), _head);
   1.284 +            void *pGlyph = TtfUtil::GlyfLookup(_glyf, locidx, _glyf.size());
   1.285 +
   1.286 +            if (pGlyph && TtfUtil::GlyfBox(pGlyph, xMin, yMin, xMax, yMax))
   1.287 +                bbox = Rect(Position(static_cast<float>(xMin), static_cast<float>(yMin)),
   1.288 +                    Position(static_cast<float>(xMax), static_cast<float>(yMax)));
   1.289 +        }
   1.290 +        if (TtfUtil::HorMetrics(glyphid, _hmtx, _hmtx.size(), _hhea, nLsb, nAdvWid))
   1.291 +            advance = Position(static_cast<float>(nAdvWid), 0);
   1.292 +    }
   1.293 +
   1.294 +    if (glyphid < _num_glyphs_attributes)
   1.295 +    {
   1.296 +        const byte * gloc = m_pGloc;
   1.297 +        size_t      glocs = 0, gloce = 0;
   1.298 +
   1.299 +        be::skip<uint32>(gloc);
   1.300 +        be::skip<uint16>(gloc,2);
   1.301 +        if (_long_fmt)
   1.302 +        {
   1.303 +            be::skip<uint32>(gloc, glyphid);
   1.304 +            glocs = be::read<uint32>(gloc);
   1.305 +            gloce = be::peek<uint32>(gloc);
   1.306 +        }
   1.307 +        else
   1.308 +        {
   1.309 +            be::skip<uint16>(gloc, glyphid);
   1.310 +            glocs = be::read<uint16>(gloc);
   1.311 +            gloce = be::peek<uint16>(gloc);
   1.312 +        }
   1.313 +
   1.314 +        if (glocs >= m_pGlat.size() || gloce > m_pGlat.size())
   1.315 +            return 0;
   1.316 +
   1.317 +        const uint32 glat_version = be::peek<uint32>(m_pGlat);
   1.318 +        if (glat_version < 0x00020000)
   1.319 +        {
   1.320 +            if (gloce - glocs < 2*sizeof(byte)+sizeof(uint16)
   1.321 +                || gloce - glocs > _num_attrs*(2*sizeof(byte)+sizeof(uint16)))
   1.322 +            {
   1.323 +                return 0;
   1.324 +            }
   1.325 +
   1.326 +            new (&glyph) GlyphFace(bbox, advance, glat_iterator(m_pGlat + glocs), glat_iterator(m_pGlat + gloce));
   1.327 +        }
   1.328 +        else
   1.329 +        {
   1.330 +            if (gloce - glocs < 3*sizeof(uint16)
   1.331 +                || gloce - glocs > _num_attrs*3*sizeof(uint16))
   1.332 +            {
   1.333 +                return 0;
   1.334 +            }
   1.335 +
   1.336 +            new (&glyph) GlyphFace(bbox, advance, glat2_iterator(m_pGlat + glocs), glat2_iterator(m_pGlat + gloce));
   1.337 +        }
   1.338 +
   1.339 +        if (!glyph.attrs() || glyph.attrs().capacity() > _num_attrs)
   1.340 +            return 0;
   1.341 +    }
   1.342 +
   1.343 +    return &glyph;
   1.344 +}

mercurial