gfx/graphite2/src/GlyphCache.cpp

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:aa362168cf8c
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
35 using namespace graphite2;
36
37 namespace
38 {
39 // Iterator over version 1 or 2 glat entries which consist of a series of
40 // +-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+
41 // v1 |k|n|v1 |v2 |...|vN | or v2 | k | n |v1 |v2 |...|vN |
42 // +-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+
43 // variable length structures.
44
45 template<typename W>
46 class _glat_iterator : public std::iterator<std::input_iterator_tag, std::pair<sparse::key_type, sparse::mapped_type> >
47 {
48 unsigned short key() const { return be::peek<W>(_e) + _n; }
49 unsigned int run() const { return be::peek<W>(_e+sizeof(W)); }
50 void advance_entry() { _n = 0; _e = _v; be::skip<W>(_v,2); }
51 public:
52 _glat_iterator(const void * glat=0) : _e(reinterpret_cast<const byte *>(glat)), _v(_e+2*sizeof(W)), _n(0) {}
53
54 _glat_iterator<W> & operator ++ () {
55 ++_n; be::skip<uint16>(_v);
56 if (_n == run()) advance_entry();
57 return *this;
58 }
59 _glat_iterator<W> operator ++ (int) { _glat_iterator<W> tmp(*this); operator++(); return tmp; }
60
61 // This is strictly a >= operator. A true == operator could be
62 // implemented that test for overlap but it would be more expensive a
63 // test.
64 bool operator == (const _glat_iterator<W> & rhs) { return _v >= rhs._e; }
65 bool operator != (const _glat_iterator<W> & rhs) { return !operator==(rhs); }
66
67 value_type operator * () const {
68 return value_type(key(), be::peek<uint16>(_v));
69 }
70
71 protected:
72 const byte * _e, * _v;
73 ptrdiff_t _n;
74 };
75
76 typedef _glat_iterator<uint8> glat_iterator;
77 typedef _glat_iterator<uint16> glat2_iterator;
78 }
79
80
81 class GlyphCache::Loader
82 {
83 public:
84 Loader(const Face & face, const bool dumb_font); //return result indicates success. Do not use if failed.
85
86 operator bool () const throw();
87 unsigned short int units_per_em() const throw();
88 unsigned short int num_glyphs() const throw();
89 unsigned short int num_attrs() const throw();
90
91 const GlyphFace * read_glyph(unsigned short gid, GlyphFace &) const throw();
92
93 CLASS_NEW_DELETE;
94 private:
95 Face::Table _head,
96 _hhea,
97 _hmtx,
98 _glyf,
99 _loca,
100 m_pGlat,
101 m_pGloc;
102
103 bool _long_fmt;
104 unsigned short _num_glyphs_graphics, //i.e. boundary box and advance
105 _num_glyphs_attributes,
106 _num_attrs; // number of glyph attributes per glyph
107 };
108
109
110
111 GlyphCache::GlyphCache(const Face & face, const uint32 face_options)
112 : _glyph_loader(new Loader(face, bool(face_options & gr_face_dumbRendering))),
113 _glyphs(_glyph_loader && *_glyph_loader ? grzeroalloc<const GlyphFace *>(_glyph_loader->num_glyphs()) : 0),
114 _num_glyphs(_glyphs ? _glyph_loader->num_glyphs() : 0),
115 _num_attrs(_glyphs ? _glyph_loader->num_attrs() : 0),
116 _upem(_glyphs ? _glyph_loader->units_per_em() : 0)
117 {
118 if ((face_options & gr_face_preloadGlyphs) && _glyph_loader && _glyphs)
119 {
120 GlyphFace * const glyphs = new GlyphFace [_num_glyphs];
121 if (!glyphs)
122 return;
123
124 // The 0 glyph is definately required.
125 _glyphs[0] = _glyph_loader->read_glyph(0, glyphs[0]);
126
127 // glyphs[0] has the same address as the glyphs array just allocated,
128 // thus assigning the &glyphs[0] to _glyphs[0] means _glyphs[0] points
129 // to the entire array.
130 const GlyphFace * loaded = _glyphs[0];
131 for (uint16 gid = 1; loaded && gid != _num_glyphs; ++gid)
132 _glyphs[gid] = loaded = _glyph_loader->read_glyph(gid, glyphs[gid]);
133
134 if (!loaded)
135 {
136 _glyphs[0] = 0;
137 delete [] glyphs;
138 }
139 delete _glyph_loader;
140 _glyph_loader = 0;
141 }
142
143 if (_glyphs && glyph(0) == 0)
144 {
145 free(_glyphs);
146 _glyphs = 0;
147 _num_glyphs = _num_attrs = _upem = 0;
148 }
149 }
150
151
152 GlyphCache::~GlyphCache()
153 {
154 if (_glyphs)
155 {
156 if (_glyph_loader)
157 {
158 const GlyphFace * * g = _glyphs;
159 for(unsigned short n = _num_glyphs; n; --n, ++g)
160 delete *g;
161 }
162 else
163 delete [] _glyphs[0];
164 free(_glyphs);
165 }
166 delete _glyph_loader;
167 }
168
169 const GlyphFace *GlyphCache::glyph(unsigned short glyphid) const //result may be changed by subsequent call with a different glyphid
170 {
171 const GlyphFace * & p = _glyphs[glyphid];
172 if (p == 0 && _glyph_loader)
173 {
174 GlyphFace * g = new GlyphFace();
175 if (g) p = _glyph_loader->read_glyph(glyphid, *g);
176 if (!p)
177 {
178 delete g;
179 return *_glyphs;
180 }
181 }
182 return p;
183 }
184
185
186
187 GlyphCache::Loader::Loader(const Face & face, const bool dumb_font)
188 : _head(face, Tag::head),
189 _hhea(face, Tag::hhea),
190 _hmtx(face, Tag::hmtx),
191 _glyf(face, Tag::glyf),
192 _loca(face, Tag::loca),
193 _long_fmt(false),
194 _num_glyphs_graphics(0),
195 _num_glyphs_attributes(0),
196 _num_attrs(0)
197 {
198 if (!operator bool())
199 return;
200
201 const Face::Table maxp = Face::Table(face, Tag::maxp);
202 if (!maxp) { _head = Face::Table(); return; }
203
204 _num_glyphs_graphics = TtfUtil::GlyphCount(maxp);
205 // This will fail if the number of glyphs is wildly out of range.
206 if (_glyf && TtfUtil::LocaLookup(_num_glyphs_graphics-1, _loca, _loca.size(), _head) == size_t(-1))
207 {
208 _head = Face::Table();
209 return;
210 }
211
212 if (!dumb_font)
213 {
214 if ((m_pGlat = Face::Table(face, Tag::Glat)) == NULL
215 || (m_pGloc = Face::Table(face, Tag::Gloc)) == NULL
216 || m_pGloc.size() < 6)
217 {
218 _head = Face::Table();
219 return;
220 }
221 const byte * p = m_pGloc;
222 const int version = be::read<uint32>(p);
223 const uint16 flags = be::read<uint16>(p);
224 _num_attrs = be::read<uint16>(p);
225 // We can accurately calculate the number of attributed glyphs by
226 // subtracting the length of the attribids array (numAttribs long if present)
227 // and dividing by either 2 or 4 depending on shor or lonf format
228 _long_fmt = flags & 1;
229 _num_glyphs_attributes = (m_pGloc.size()
230 - (p - m_pGloc)
231 - sizeof(uint16)*(flags & 0x2 ? _num_attrs : 0))
232 / (_long_fmt ? sizeof(uint32) : sizeof(uint16)) - 1;
233
234 if (version != 0x00010000
235 || _num_attrs == 0 || _num_attrs > 0x3000 // is this hard limit appropriate?
236 || _num_glyphs_graphics > _num_glyphs_attributes)
237 {
238 _head = Face::Table();
239 return;
240 }
241 }
242 }
243
244 inline
245 GlyphCache::Loader::operator bool () const throw()
246 {
247 return _head && _hhea && _hmtx && !(bool(_glyf) != bool(_loca));
248 }
249
250 inline
251 unsigned short int GlyphCache::Loader::units_per_em() const throw()
252 {
253 return _head ? TtfUtil::DesignUnits(_head) : 0;
254 }
255
256 inline
257 unsigned short int GlyphCache::Loader::num_glyphs() const throw()
258 {
259 return max(_num_glyphs_graphics, _num_glyphs_attributes);
260 }
261
262 inline
263 unsigned short int GlyphCache::Loader::num_attrs() const throw()
264 {
265 return _num_attrs;
266 }
267
268 const GlyphFace * GlyphCache::Loader::read_glyph(unsigned short glyphid, GlyphFace & glyph) const throw()
269 {
270 Rect bbox;
271 Position advance;
272
273 if (glyphid < _num_glyphs_graphics)
274 {
275 int nLsb;
276 unsigned int nAdvWid;
277 if (_glyf)
278 {
279 int xMin, yMin, xMax, yMax;
280 size_t locidx = TtfUtil::LocaLookup(glyphid, _loca, _loca.size(), _head);
281 void *pGlyph = TtfUtil::GlyfLookup(_glyf, locidx, _glyf.size());
282
283 if (pGlyph && TtfUtil::GlyfBox(pGlyph, xMin, yMin, xMax, yMax))
284 bbox = Rect(Position(static_cast<float>(xMin), static_cast<float>(yMin)),
285 Position(static_cast<float>(xMax), static_cast<float>(yMax)));
286 }
287 if (TtfUtil::HorMetrics(glyphid, _hmtx, _hmtx.size(), _hhea, nLsb, nAdvWid))
288 advance = Position(static_cast<float>(nAdvWid), 0);
289 }
290
291 if (glyphid < _num_glyphs_attributes)
292 {
293 const byte * gloc = m_pGloc;
294 size_t glocs = 0, gloce = 0;
295
296 be::skip<uint32>(gloc);
297 be::skip<uint16>(gloc,2);
298 if (_long_fmt)
299 {
300 be::skip<uint32>(gloc, glyphid);
301 glocs = be::read<uint32>(gloc);
302 gloce = be::peek<uint32>(gloc);
303 }
304 else
305 {
306 be::skip<uint16>(gloc, glyphid);
307 glocs = be::read<uint16>(gloc);
308 gloce = be::peek<uint16>(gloc);
309 }
310
311 if (glocs >= m_pGlat.size() || gloce > m_pGlat.size())
312 return 0;
313
314 const uint32 glat_version = be::peek<uint32>(m_pGlat);
315 if (glat_version < 0x00020000)
316 {
317 if (gloce - glocs < 2*sizeof(byte)+sizeof(uint16)
318 || gloce - glocs > _num_attrs*(2*sizeof(byte)+sizeof(uint16)))
319 {
320 return 0;
321 }
322
323 new (&glyph) GlyphFace(bbox, advance, glat_iterator(m_pGlat + glocs), glat_iterator(m_pGlat + gloce));
324 }
325 else
326 {
327 if (gloce - glocs < 3*sizeof(uint16)
328 || gloce - glocs > _num_attrs*3*sizeof(uint16))
329 {
330 return 0;
331 }
332
333 new (&glyph) GlyphFace(bbox, advance, glat2_iterator(m_pGlat + glocs), glat2_iterator(m_pGlat + gloce));
334 }
335
336 if (!glyph.attrs() || glyph.attrs().capacity() > _num_attrs)
337 return 0;
338 }
339
340 return &glyph;
341 }

mercurial