Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
1 /* GRAPHITE2 LICENSING
3 Copyright 2012, SIL International
4 All rights reserved.
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.
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.
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.
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"
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"
35 using namespace graphite2;
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.
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) {}
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; }
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); }
67 value_type operator * () const {
68 return value_type(key(), be::peek<uint16>(_v));
69 }
71 protected:
72 const byte * _e, * _v;
73 ptrdiff_t _n;
74 };
76 typedef _glat_iterator<uint8> glat_iterator;
77 typedef _glat_iterator<uint16> glat2_iterator;
78 }
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.
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();
91 const GlyphFace * read_glyph(unsigned short gid, GlyphFace &) const throw();
93 CLASS_NEW_DELETE;
94 private:
95 Face::Table _head,
96 _hhea,
97 _hmtx,
98 _glyf,
99 _loca,
100 m_pGlat,
101 m_pGloc;
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 };
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;
124 // The 0 glyph is definately required.
125 _glyphs[0] = _glyph_loader->read_glyph(0, glyphs[0]);
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]);
134 if (!loaded)
135 {
136 _glyphs[0] = 0;
137 delete [] glyphs;
138 }
139 delete _glyph_loader;
140 _glyph_loader = 0;
141 }
143 if (_glyphs && glyph(0) == 0)
144 {
145 free(_glyphs);
146 _glyphs = 0;
147 _num_glyphs = _num_attrs = _upem = 0;
148 }
149 }
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 }
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 }
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;
201 const Face::Table maxp = Face::Table(face, Tag::maxp);
202 if (!maxp) { _head = Face::Table(); return; }
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 }
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;
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 }
244 inline
245 GlyphCache::Loader::operator bool () const throw()
246 {
247 return _head && _hhea && _hmtx && !(bool(_glyf) != bool(_loca));
248 }
250 inline
251 unsigned short int GlyphCache::Loader::units_per_em() const throw()
252 {
253 return _head ? TtfUtil::DesignUnits(_head) : 0;
254 }
256 inline
257 unsigned short int GlyphCache::Loader::num_glyphs() const throw()
258 {
259 return max(_num_glyphs_graphics, _num_glyphs_attributes);
260 }
262 inline
263 unsigned short int GlyphCache::Loader::num_attrs() const throw()
264 {
265 return _num_attrs;
266 }
268 const GlyphFace * GlyphCache::Loader::read_glyph(unsigned short glyphid, GlyphFace & glyph) const throw()
269 {
270 Rect bbox;
271 Position advance;
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());
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 }
291 if (glyphid < _num_glyphs_attributes)
292 {
293 const byte * gloc = m_pGloc;
294 size_t glocs = 0, gloce = 0;
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 }
311 if (glocs >= m_pGlat.size() || gloce > m_pGlat.size())
312 return 0;
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 }
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 }
333 new (&glyph) GlyphFace(bbox, advance, glat2_iterator(m_pGlat + glocs), glat2_iterator(m_pGlat + gloce));
334 }
336 if (!glyph.attrs() || glyph.attrs().capacity() > _num_attrs)
337 return 0;
338 }
340 return &glyph;
341 }