Coverage Report

Created: 2025-07-07 10:01

/work/workdir/UnpackedTarball/graphite/src/GlyphCache.cpp
Line
Count
Source (jump to first uncovered line)
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
0
        unsigned short  key() const             { return uint16(be::peek<W>(_e) + _n); }
Unexecuted instantiation: GlyphCache.cpp:(anonymous namespace)::_glat_iterator<unsigned char>::key() const
Unexecuted instantiation: GlyphCache.cpp:(anonymous namespace)::_glat_iterator<unsigned short>::key() const
50
0
        unsigned int    run() const             { return be::peek<W>(_e+sizeof(W)); }
Unexecuted instantiation: GlyphCache.cpp:(anonymous namespace)::_glat_iterator<unsigned char>::run() const
Unexecuted instantiation: GlyphCache.cpp:(anonymous namespace)::_glat_iterator<unsigned short>::run() const
51
0
        void            advance_entry()         { _n = 0; _e = _v; be::skip<W>(_v,2); }
Unexecuted instantiation: GlyphCache.cpp:(anonymous namespace)::_glat_iterator<unsigned char>::advance_entry()
Unexecuted instantiation: GlyphCache.cpp:(anonymous namespace)::_glat_iterator<unsigned short>::advance_entry()
52
    public:
53
0
        _glat_iterator(const void * glat=0) : _e(reinterpret_cast<const byte *>(glat)), _v(_e+2*sizeof(W)), _n(0) {}
Unexecuted instantiation: GlyphCache.cpp:(anonymous namespace)::_glat_iterator<unsigned char>::_glat_iterator(void const*)
Unexecuted instantiation: GlyphCache.cpp:(anonymous namespace)::_glat_iterator<unsigned short>::_glat_iterator(void const*)
54
55
0
        _glat_iterator<W> & operator ++ () {
56
0
            ++_n; be::skip<uint16>(_v);
57
0
            if (_n == run()) advance_entry();
58
0
            return *this;
59
0
        }
Unexecuted instantiation: GlyphCache.cpp:(anonymous namespace)::_glat_iterator<unsigned char>::operator++()
Unexecuted instantiation: GlyphCache.cpp:(anonymous namespace)::_glat_iterator<unsigned short>::operator++()
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
0
        bool operator == (const _glat_iterator<W> & rhs) { return _v >= rhs._e - 1; }
Unexecuted instantiation: GlyphCache.cpp:(anonymous namespace)::_glat_iterator<unsigned char>::operator==((anonymous namespace)::_glat_iterator<unsigned char> const&)
Unexecuted instantiation: GlyphCache.cpp:(anonymous namespace)::_glat_iterator<unsigned short>::operator==((anonymous namespace)::_glat_iterator<unsigned short> const&)
66
0
        bool operator != (const _glat_iterator<W> & rhs) { return !operator==(rhs); }
Unexecuted instantiation: GlyphCache.cpp:(anonymous namespace)::_glat_iterator<unsigned char>::operator!=((anonymous namespace)::_glat_iterator<unsigned char> const&)
Unexecuted instantiation: GlyphCache.cpp:(anonymous namespace)::_glat_iterator<unsigned short>::operator!=((anonymous namespace)::_glat_iterator<unsigned short> const&)
67
68
0
        value_type          operator * () const {
69
0
            return value_type(key(), be::peek<uint16>(_v));
70
0
        }
Unexecuted instantiation: GlyphCache.cpp:(anonymous namespace)::_glat_iterator<unsigned char>::operator*() const
Unexecuted instantiation: GlyphCache.cpp:(anonymous namespace)::_glat_iterator<unsigned short>::operator*() const
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
0
: _glyph_loader(new Loader(face)),
119
0
  _glyphs(_glyph_loader && *_glyph_loader && _glyph_loader->num_glyphs()
120
0
        ? grzeroalloc<const GlyphFace *>(_glyph_loader->num_glyphs()) : 0),
121
0
  _boxes(_glyph_loader && _glyph_loader->has_boxes() && _glyph_loader->num_glyphs()
122
0
        ? grzeroalloc<GlyphBox *>(_glyph_loader->num_glyphs()) : 0),
123
0
  _num_glyphs(_glyphs ? _glyph_loader->num_glyphs() : 0),
124
0
  _num_attrs(_glyphs ? _glyph_loader->num_attrs() : 0),
125
0
  _upem(_glyphs ? _glyph_loader->units_per_em() : 0)
126
0
{
127
0
    if ((face_options & gr_face_preloadGlyphs) && _glyph_loader && _glyphs)
128
0
    {
129
0
        int numsubs = 0;
130
0
        GlyphFace * const glyphs = new GlyphFace [_num_glyphs];
131
0
        if (!glyphs)
132
0
            return;
133
134
        // The 0 glyph is definately required.
135
0
        _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
0
        const GlyphFace * loaded = _glyphs[0];
141
0
        for (uint16 gid = 1; loaded && gid != _num_glyphs; ++gid)
142
0
            _glyphs[gid] = loaded = _glyph_loader->read_glyph(gid, glyphs[gid], &numsubs);
143
144
0
        if (!loaded)
145
0
        {
146
0
            _glyphs[0] = 0;
147
0
            delete [] glyphs;
148
0
        }
149
0
        else if (numsubs > 0 && _boxes)
150
0
        {
151
0
            GlyphBox * boxes = (GlyphBox *)gralloc<char>(_num_glyphs * sizeof(GlyphBox) + numsubs * 8 * sizeof(float));
152
0
            GlyphBox * currbox = boxes;
153
154
0
            for (uint16 gid = 0; currbox && gid != _num_glyphs; ++gid)
155
0
            {
156
0
                _boxes[gid] = currbox;
157
0
                currbox = _glyph_loader->read_box(gid, currbox, *_glyphs[gid]);
158
0
            }
159
0
            if (!currbox)
160
0
            {
161
0
                free(boxes);
162
0
                _boxes[0] = 0;
163
0
            }
164
0
        }
165
0
        delete _glyph_loader;
166
0
        _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
0
    }
172
173
0
    if (_glyphs && glyph(0) == 0)
174
0
    {
175
0
        free(_glyphs);
176
0
        _glyphs = 0;
177
0
        if (_boxes)
178
0
        {
179
0
            free(_boxes);
180
0
            _boxes = 0;
181
0
        }
182
0
        _num_glyphs = _num_attrs = _upem = 0;
183
0
    }
184
0
}
185
186
187
GlyphCache::~GlyphCache()
188
0
{
189
0
    if (_glyphs)
190
0
    {
191
0
        if (_glyph_loader)
192
0
        {
193
0
            const GlyphFace *  * g = _glyphs;
194
0
            for(unsigned short n = _num_glyphs; n; --n, ++g)
195
0
                delete *g;
196
0
        }
197
0
        else
198
0
            delete [] _glyphs[0];
199
0
        free(_glyphs);
200
0
    }
201
0
    if (_boxes)
202
0
    {
203
0
        if (_glyph_loader)
204
0
        {
205
0
            GlyphBox *  * g = _boxes;
206
0
            for (uint16 n = _num_glyphs; n; --n, ++g)
207
0
                free(*g);
208
0
        }
209
0
        else
210
0
            free(_boxes[0]);
211
0
        free(_boxes);
212
0
    }
213
0
    delete _glyph_loader;
214
0
}
215
216
const GlyphFace *GlyphCache::glyph(unsigned short glyphid) const      //result may be changed by subsequent call with a different glyphid
217
0
{
218
0
    if (glyphid >= numGlyphs())
219
0
        return _glyphs[0];
220
0
    const GlyphFace * & p = _glyphs[glyphid];
221
0
    if (p == 0 && _glyph_loader)
222
0
    {
223
0
        int numsubs = 0;
224
0
        GlyphFace * g = new GlyphFace();
225
0
        if (g)  p = _glyph_loader->read_glyph(glyphid, *g, &numsubs);
226
0
        if (!p)
227
0
        {
228
0
            delete g;
229
0
            return *_glyphs;
230
0
        }
231
0
        if (_boxes)
232
0
        {
233
0
            _boxes[glyphid] = (GlyphBox *)gralloc<char>(sizeof(GlyphBox) + 8 * numsubs * sizeof(float));
234
0
            if (!_glyph_loader->read_box(glyphid, _boxes[glyphid], *_glyphs[glyphid]))
235
0
            {
236
0
                free(_boxes[glyphid]);
237
0
                _boxes[glyphid] = 0;
238
0
            }
239
0
        }
240
0
    }
241
0
    return p;
242
0
}
243
244
245
246
GlyphCache::Loader::Loader(const Face & face)
247
0
: _head(face, Tag::head),
248
0
  _hhea(face, Tag::hhea),
249
0
  _hmtx(face, Tag::hmtx),
250
0
  _glyf(face, Tag::glyf),
251
0
  _loca(face, Tag::loca),
252
0
  _long_fmt(false),
253
0
  _has_boxes(false),
254
0
  _num_glyphs_graphics(0),
255
0
  _num_glyphs_attributes(0),
256
0
  _num_attrs(0)
257
0
{
258
0
    if (!operator bool())
259
0
        return;
260
261
0
    const Face::Table maxp = Face::Table(face, Tag::maxp);
262
0
    if (!maxp) { _head = Face::Table(); return; }
263
264
0
    _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
0
    if (_glyf && TtfUtil::LocaLookup(_num_glyphs_graphics-1, _loca, _loca.size(), _head) == size_t(-2))
267
0
    {
268
0
        _head = Face::Table();
269
0
        return;
270
0
    }
271
272
0
    if ((m_pGlat = Face::Table(face, Tag::Glat, 0x00030000)) == NULL
273
0
        || (m_pGloc = Face::Table(face, Tag::Gloc)) == NULL
274
0
        || m_pGloc.size() < 8)
275
0
    {
276
0
        _head = Face::Table();
277
0
        return;
278
0
    }
279
0
    const byte    * p = m_pGloc;
280
0
    int       version = be::read<uint32>(p);
281
0
    const uint16    flags = be::read<uint16>(p);
282
0
    _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
0
    _long_fmt              = flags & 1;
287
0
    ptrdiff_t tmpnumgattrs       = (m_pGloc.size()
288
0
                               - (p - m_pGloc)
289
0
                               - sizeof(uint16)*(flags & 0x2 ? _num_attrs : 0))
290
0
                                   / (_long_fmt ? sizeof(uint32) : sizeof(uint16)) - 1;
291
292
0
    if (version >= 0x00020000 || tmpnumgattrs < 0 || tmpnumgattrs > 65535
293
0
        || _num_attrs == 0 || _num_attrs > 0x3000  // is this hard limit appropriate?
294
0
        || _num_glyphs_graphics > tmpnumgattrs
295
0
        || m_pGlat.size() < 4)
296
0
    {
297
0
        _head = Face::Table();
298
0
        return;
299
0
    }
300
301
0
    _num_glyphs_attributes = static_cast<unsigned short>(tmpnumgattrs);
302
0
    p = m_pGlat;
303
0
    version = be::read<uint32>(p);
304
0
    if (version >= 0x00040000 || (version >= 0x00030000 && m_pGlat.size() < 8))       // reject Glat tables that are too new
305
0
    {
306
0
        _head = Face::Table();
307
0
        return;
308
0
    }
309
0
    else if (version >= 0x00030000)
310
0
    {
311
0
        unsigned int glatflags = be::read<uint32>(p);
312
0
        _has_boxes = glatflags & 1;
313
        // delete this once the compiler is fixed
314
0
        _has_boxes = true;
315
0
    }
316
0
}
317
318
inline
319
GlyphCache::Loader::operator bool () const throw()
320
0
{
321
0
    return _head && _hhea && _hmtx && !(bool(_glyf) != bool(_loca));
322
0
}
323
324
inline
325
unsigned short int GlyphCache::Loader::units_per_em() const throw()
326
0
{
327
0
    return _head ? TtfUtil::DesignUnits(_head) : 0;
328
0
}
329
330
inline
331
unsigned short int GlyphCache::Loader::num_glyphs() const throw()
332
0
{
333
0
    return max(_num_glyphs_graphics, _num_glyphs_attributes);
334
0
}
335
336
inline
337
unsigned short int GlyphCache::Loader::num_attrs() const throw()
338
0
{
339
0
    return _num_attrs;
340
0
}
341
342
inline
343
bool GlyphCache::Loader::has_boxes () const throw()
344
0
{
345
0
    return _has_boxes;
346
0
}
347
348
const GlyphFace * GlyphCache::Loader::read_glyph(unsigned short glyphid, GlyphFace & glyph, int *numsubs) const throw()
349
0
{
350
0
    Rect        bbox;
351
0
    Position    advance;
352
353
0
    if (glyphid < _num_glyphs_graphics)
354
0
    {
355
0
        int nLsb;
356
0
        unsigned int nAdvWid;
357
0
        if (_glyf)
358
0
        {
359
0
            int xMin, yMin, xMax, yMax;
360
0
            size_t locidx = TtfUtil::LocaLookup(glyphid, _loca, _loca.size(), _head);
361
0
            void *pGlyph = TtfUtil::GlyfLookup(_glyf, locidx, _glyf.size());
362
363
0
            if (pGlyph && TtfUtil::GlyfBox(pGlyph, xMin, yMin, xMax, yMax))
364
0
            {
365
0
                if ((xMin > xMax) || (yMin > yMax))
366
0
                    return 0;
367
0
                bbox = Rect(Position(static_cast<float>(xMin), static_cast<float>(yMin)),
368
0
                    Position(static_cast<float>(xMax), static_cast<float>(yMax)));
369
0
            }
370
0
        }
371
0
        if (TtfUtil::HorMetrics(glyphid, _hmtx, _hmtx.size(), _hhea, nLsb, nAdvWid))
372
0
            advance = Position(static_cast<float>(nAdvWid), 0);
373
0
    }
374
375
0
    if (glyphid < _num_glyphs_attributes)
376
0
    {
377
0
        const byte * gloc = m_pGloc;
378
0
        size_t      glocs = 0, gloce = 0;
379
380
0
        be::skip<uint32>(gloc);
381
0
        be::skip<uint16>(gloc,2);
382
0
        if (_long_fmt)
383
0
        {
384
0
            if (8 + glyphid * sizeof(uint32) > m_pGloc.size())
385
0
                return 0;
386
0
            be::skip<uint32>(gloc, glyphid);
387
0
            glocs = be::read<uint32>(gloc);
388
0
            gloce = be::peek<uint32>(gloc);
389
0
        }
390
0
        else
391
0
        {
392
0
            if (8 + glyphid * sizeof(uint16) > m_pGloc.size())
393
0
                return 0;
394
0
            be::skip<uint16>(gloc, glyphid);
395
0
            glocs = be::read<uint16>(gloc);
396
0
            gloce = be::peek<uint16>(gloc);
397
0
        }
398
399
0
        if (glocs >= m_pGlat.size() - 1 || gloce > m_pGlat.size())
400
0
            return 0;
401
402
0
        const uint32 glat_version = be::peek<uint32>(m_pGlat);
403
0
        if (glat_version >= 0x00030000)
404
0
        {
405
0
            if (glocs >= gloce)
406
0
                return 0;
407
0
            const byte * p = m_pGlat + glocs;
408
0
            uint16 bmap = be::read<uint16>(p);
409
0
            int num = bit_set_count((uint32)bmap);
410
0
            if (numsubs) *numsubs += num;
411
0
            glocs += 6 + 8 * num;
412
0
            if (glocs > gloce)
413
0
                return 0;
414
0
        }
415
0
        if (glat_version < 0x00020000)
416
0
        {
417
0
            if (gloce - glocs < 2*sizeof(byte)+sizeof(uint16)
418
0
                || gloce - glocs > _num_attrs*(2*sizeof(byte)+sizeof(uint16)))
419
0
                    return 0;
420
0
            new (&glyph) GlyphFace(bbox, advance, glat_iterator(m_pGlat + glocs), glat_iterator(m_pGlat + gloce));
421
0
        }
422
0
        else
423
0
        {
424
0
            if (gloce - glocs < 3*sizeof(uint16)        // can a glyph have no attributes? why not?
425
0
                || gloce - glocs > _num_attrs*3*sizeof(uint16)
426
0
                || glocs > m_pGlat.size() - 2*sizeof(uint16))
427
0
                    return 0;
428
0
            new (&glyph) GlyphFace(bbox, advance, glat2_iterator(m_pGlat + glocs), glat2_iterator(m_pGlat + gloce));
429
0
        }
430
0
        if (!glyph.attrs() || glyph.attrs().capacity() > _num_attrs)
431
0
            return 0;
432
0
    }
433
0
    return &glyph;
434
0
}
435
436
inline float scale_to(uint8 t, float zmin, float zmax)
437
0
{
438
0
    return (zmin + t * (zmax - zmin) / 255);
439
0
}
440
441
Rect readbox(Rect &b, uint8 zxmin, uint8 zymin, uint8 zxmax, uint8 zymax)
442
0
{
443
0
    return Rect(Position(scale_to(zxmin, b.bl.x, b.tr.x), scale_to(zymin, b.bl.y, b.tr.y)),
444
0
                Position(scale_to(zxmax, b.bl.x, b.tr.x), scale_to(zymax, b.bl.y, b.tr.y)));
445
0
}
446
447
GlyphBox * GlyphCache::Loader::read_box(uint16 gid, GlyphBox *curr, const GlyphFace & glyph) const throw()
448
0
{
449
0
    if (gid >= _num_glyphs_attributes) return 0;
450
451
0
    const byte * gloc = m_pGloc;
452
0
    size_t      glocs = 0, gloce = 0;
453
454
0
    be::skip<uint32>(gloc);
455
0
    be::skip<uint16>(gloc,2);
456
0
    if (_long_fmt)
457
0
    {
458
0
        be::skip<uint32>(gloc, gid);
459
0
        glocs = be::read<uint32>(gloc);
460
0
        gloce = be::peek<uint32>(gloc);
461
0
    }
462
0
    else
463
0
    {
464
0
        be::skip<uint16>(gloc, gid);
465
0
        glocs = be::read<uint16>(gloc);
466
0
        gloce = be::peek<uint16>(gloc);
467
0
    }
468
469
0
    if (gloce > m_pGlat.size() || glocs + 6 >= gloce)
470
0
        return 0;
471
472
0
    const byte * p = m_pGlat + glocs;
473
0
    uint16 bmap = be::read<uint16>(p);
474
0
    int num = bit_set_count((uint32)bmap);
475
476
0
    Rect bbox = glyph.theBBox();
477
0
    Rect diamax(Position(bbox.bl.x + bbox.bl.y, bbox.bl.x - bbox.tr.y),
478
0
                Position(bbox.tr.x + bbox.tr.y, bbox.tr.x - bbox.bl.y));
479
0
    Rect diabound = readbox(diamax, p[0], p[2], p[1], p[3]);
480
0
    ::new (curr) GlyphBox(num, bmap, &diabound);
481
0
    be::skip<uint8>(p, 4);
482
0
    if (glocs + 6 + num * 8 >= gloce)
483
0
        return 0;
484
485
0
    for (int i = 0; i < num * 2; ++i)
486
0
    {
487
0
        Rect box = readbox((i & 1) ? diamax : bbox, p[0], p[2], p[1], p[3]);
488
0
        curr->addSubBox(i >> 1, i & 1, &box);
489
0
        be::skip<uint8>(p, 4);
490
0
    }
491
0
    return (GlyphBox *)((char *)(curr) + sizeof(GlyphBox) + 2 * num * sizeof(Rect));
492
0
}