1 /* GRAPHITE2 LICENSING
2
3 Copyright 2010, 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 <cstring>
28 #include "graphite2/Segment.h"
29 #include "inc/CmapCache.h"
30 #include "inc/debug.h"
31 #include "inc/Decompressor.h"
32 #include "inc/Endian.h"
33 #include "inc/Face.h"
34 #include "inc/FileFace.h"
35 #include "inc/GlyphFace.h"
36 #include "inc/json.h"
37 #include "inc/SegCacheStore.h"
38 #include "inc/Segment.h"
39 #include "inc/NameTable.h"
40 #include "inc/Error.h"
41
42 using namespace graphite2;
43
44 namespace
45 {
46 enum compression
47 {
48 NONE,
49 LZ4
50 };
51
52 }
53
Face(const void * appFaceHandle,const gr_face_ops & ops)54 Face::Face(const void* appFaceHandle/*non-NULL*/, const gr_face_ops & ops)
55 : m_appFaceHandle(appFaceHandle),
56 m_pFileFace(NULL),
57 m_pGlyphFaceCache(NULL),
58 m_cmap(NULL),
59 m_pNames(NULL),
60 m_logger(NULL),
61 m_error(0), m_errcntxt(0),
62 m_silfs(NULL),
63 m_numSilf(0),
64 m_ascent(0),
65 m_descent(0)
66 {
67 memset(&m_ops, 0, sizeof m_ops);
68 memcpy(&m_ops, &ops, min(sizeof m_ops, ops.size));
69 }
70
71
~Face()72 Face::~Face()
73 {
74 setLogger(0);
75 delete m_pGlyphFaceCache;
76 delete m_cmap;
77 delete[] m_silfs;
78 #ifndef GRAPHITE2_NFILEFACE
79 delete m_pFileFace;
80 #endif
81 delete m_pNames;
82 }
83
default_glyph_advance(const void * font_ptr,gr_uint16 glyphid)84 float Face::default_glyph_advance(const void* font_ptr, gr_uint16 glyphid)
85 {
86 const Font & font = *reinterpret_cast<const Font *>(font_ptr);
87
88 return font.face().glyphs().glyph(glyphid)->theAdvance().x * font.scale();
89 }
90
readGlyphs(uint32 faceOptions)91 bool Face::readGlyphs(uint32 faceOptions)
92 {
93 Error e;
94 #ifdef GRAPHITE2_TELEMETRY
95 telemetry::category _glyph_cat(tele.glyph);
96 #endif
97 error_context(EC_READGLYPHS);
98 m_pGlyphFaceCache = new GlyphCache(*this, faceOptions);
99
100 if (e.test(!m_pGlyphFaceCache, E_OUTOFMEM)
101 || e.test(m_pGlyphFaceCache->numGlyphs() == 0, E_NOGLYPHS)
102 || e.test(m_pGlyphFaceCache->unitsPerEm() == 0, E_BADUPEM))
103 {
104 return error(e);
105 }
106
107 if (faceOptions & gr_face_cacheCmap)
108 m_cmap = new CachedCmap(*this);
109 else
110 m_cmap = new DirectCmap(*this);
111 if (e.test(!m_cmap, E_OUTOFMEM) || e.test(!*m_cmap, E_BADCMAP))
112 return error(e);
113
114 if (faceOptions & gr_face_preloadGlyphs)
115 nameTable(); // preload the name table along with the glyphs.
116
117 return true;
118 }
119
readGraphite(const Table & silf)120 bool Face::readGraphite(const Table & silf)
121 {
122 #ifdef GRAPHITE2_TELEMETRY
123 telemetry::category _silf_cat(tele.silf);
124 #endif
125 Error e;
126 error_context(EC_READSILF);
127 const byte * p = silf;
128 if (e.test(!p, E_NOSILF) || e.test(silf.size() < 20, E_BADSIZE)) return error(e);
129
130 const uint32 version = be::read<uint32>(p);
131 if (e.test(version < 0x00020000, E_TOOOLD)) return error(e);
132 if (version >= 0x00030000)
133 be::skip<uint32>(p); // compilerVersion
134 m_numSilf = be::read<uint16>(p);
135
136 be::skip<uint16>(p); // reserved
137
138 bool havePasses = false;
139 m_silfs = new Silf[m_numSilf];
140 if (e.test(!m_silfs, E_OUTOFMEM)) return error(e);
141 for (int i = 0; i < m_numSilf; i++)
142 {
143 error_context(EC_ASILF + (i << 8));
144 const uint32 offset = be::read<uint32>(p),
145 next = i == m_numSilf - 1 ? silf.size() : be::peek<uint32>(p);
146 if (e.test(next > silf.size() || offset >= next, E_BADSIZE))
147 return error(e);
148
149 if (!m_silfs[i].readGraphite(silf + offset, next - offset, *this, version))
150 return false;
151
152 if (m_silfs[i].numPasses())
153 havePasses = true;
154 }
155
156 return havePasses;
157 }
158
readFeatures()159 bool Face::readFeatures()
160 {
161 return m_Sill.readFace(*this);
162 }
163
runGraphite(Segment * seg,const Silf * aSilf) const164 bool Face::runGraphite(Segment *seg, const Silf *aSilf) const
165 {
166 #if !defined GRAPHITE2_NTRACING
167 json * dbgout = logger();
168 if (dbgout)
169 {
170 *dbgout << json::object
171 << "id" << objectid(seg)
172 << "passes" << json::array;
173 }
174 #endif
175
176 // if ((seg->dir() & 1) != aSilf->dir())
177 // seg->reverseSlots();
178 if ((seg->dir() & 3) == 3 && aSilf->bidiPass() == 0xFF)
179 seg->doMirror(aSilf->aMirror());
180 bool res = aSilf->runGraphite(seg, 0, aSilf->positionPass(), true);
181 if (res)
182 {
183 seg->associateChars(0, seg->charInfoCount());
184 if (aSilf->flags() & 0x20)
185 res &= seg->initCollisions();
186 if (res)
187 res &= aSilf->runGraphite(seg, aSilf->positionPass(), aSilf->numPasses(), false);
188 }
189
190 #if !defined GRAPHITE2_NTRACING
191 if (dbgout)
192 {
193 seg->positionSlots(0, 0, 0, seg->currdir());
194 *dbgout << json::item
195 << json::close // Close up the passes array
196 << "outputdir" << (seg->currdir() ? "rtl" : "ltr")
197 << "output" << json::array;
198 for(Slot * s = seg->first(); s; s = s->next())
199 *dbgout << dslot(seg, s);
200 *dbgout << json::close
201 << "advance" << seg->advance()
202 << "chars" << json::array;
203 for(size_t i = 0, n = seg->charInfoCount(); i != n; ++i)
204 *dbgout << json::flat << *seg->charinfo(i);
205 *dbgout << json::close // Close up the chars array
206 << json::close; // Close up the segment object
207 }
208 #endif
209
210 return res;
211 }
212
setLogger(FILE * log_file GR_MAYBE_UNUSED)213 void Face::setLogger(FILE * log_file GR_MAYBE_UNUSED)
214 {
215 #if !defined GRAPHITE2_NTRACING
216 delete m_logger;
217 m_logger = log_file ? new json(log_file) : 0;
218 #endif
219 }
220
chooseSilf(uint32 script) const221 const Silf *Face::chooseSilf(uint32 script) const
222 {
223 if (m_numSilf == 0)
224 return NULL;
225 else if (m_numSilf == 1 || script == 0)
226 return m_silfs;
227 else // do more work here
228 return m_silfs;
229 }
230
findPseudo(uint32 uid) const231 uint16 Face::findPseudo(uint32 uid) const
232 {
233 return (m_numSilf) ? m_silfs[0].findPseudo(uid) : 0;
234 }
235
getGlyphMetric(uint16 gid,uint8 metric) const236 int32 Face::getGlyphMetric(uint16 gid, uint8 metric) const
237 {
238 switch (metrics(metric))
239 {
240 case kgmetAscent : return m_ascent;
241 case kgmetDescent : return m_descent;
242 default:
243 if (gid >= glyphs().numGlyphs()) return 0;
244 return glyphs().glyph(gid)->getMetric(metric);
245 }
246 }
247
takeFileFace(FileFace * pFileFace GR_MAYBE_UNUSED)248 void Face::takeFileFace(FileFace* pFileFace GR_MAYBE_UNUSED/*takes ownership*/)
249 {
250 #ifndef GRAPHITE2_NFILEFACE
251 if (m_pFileFace==pFileFace)
252 return;
253
254 delete m_pFileFace;
255 m_pFileFace = pFileFace;
256 #endif
257 }
258
nameTable() const259 NameTable * Face::nameTable() const
260 {
261 if (m_pNames) return m_pNames;
262 const Table name(*this, Tag::name);
263 if (name)
264 m_pNames = new NameTable(name, name.size());
265 return m_pNames;
266 }
267
languageForLocale(const char * locale) const268 uint16 Face::languageForLocale(const char * locale) const
269 {
270 nameTable();
271 if (m_pNames)
272 return m_pNames->getLanguageId(locale);
273 return 0;
274 }
275
276
277
Table(const Face & face,const Tag n,uint32 version)278 Face::Table::Table(const Face & face, const Tag n, uint32 version) throw()
279 : _f(&face), _compressed(false)
280 {
281 size_t sz = 0;
282 _p = static_cast<const byte *>((*_f->m_ops.get_table)(_f->m_appFaceHandle, n, &sz));
283 _sz = uint32(sz);
284
285 if (!TtfUtil::CheckTable(n, _p, _sz))
286 {
287 releaseBuffers(); // Make sure we release the table buffer even if the table failed it's checks
288 return;
289 }
290
291 if (be::peek<uint32>(_p) >= version)
292 decompress();
293 }
294
releaseBuffers()295 void Face::Table::releaseBuffers()
296 {
297 if (_compressed)
298 free(const_cast<byte *>(_p));
299 else if (_p && _f->m_ops.release_table)
300 (*_f->m_ops.release_table)(_f->m_appFaceHandle, _p);
301 _p = 0; _sz = 0;
302 }
303
operator =(const Table & rhs)304 Face::Table & Face::Table::operator = (const Table & rhs) throw()
305 {
306 if (_p == rhs._p) return *this;
307
308 this->~Table();
309 new (this) Table(rhs);
310 return *this;
311 }
312
decompress()313 Error Face::Table::decompress()
314 {
315 Error e;
316 if (e.test(_sz < 5 * sizeof(uint32), E_BADSIZE))
317 return e;
318 byte * uncompressed_table = 0;
319 size_t uncompressed_size = 0;
320
321 const byte * p = _p;
322 const uint32 version = be::read<uint32>(p); // Table version number.
323
324 // The scheme is in the top 5 bits of the 1st uint32.
325 const uint32 hdr = be::read<uint32>(p);
326 switch(compression(hdr >> 27))
327 {
328 case NONE: return e;
329
330 case LZ4:
331 {
332 uncompressed_size = hdr & 0x07ffffff;
333 uncompressed_table = gralloc<byte>(uncompressed_size);
334 if (!e.test(!uncompressed_table || uncompressed_size < 4, E_OUTOFMEM))
335 {
336 memset(uncompressed_table, 0, 4); // make sure version number is initialised
337 // coverity[forward_null : FALSE] - uncompressed_table has been checked so can't be null
338 // coverity[checked_return : FALSE] - we test e later
339 e.test(lz4::decompress(p, _sz - 2*sizeof(uint32), uncompressed_table, uncompressed_size) != signed(uncompressed_size), E_SHRINKERFAILED);
340 }
341 break;
342 }
343
344 default:
345 e.error(E_BADSCHEME);
346 };
347
348 // Check the uncompressed version number against the original.
349 if (!e)
350 // coverity[forward_null : FALSE] - uncompressed_table has already been tested so can't be null
351 // coverity[checked_return : FALSE] - we test e later
352 e.test(be::peek<uint32>(uncompressed_table) != version, E_SHRINKERFAILED);
353
354 // Tell the provider to release the compressed form since were replacing
355 // it anyway.
356 releaseBuffers();
357
358 if (e)
359 {
360 free(uncompressed_table);
361 uncompressed_table = 0;
362 uncompressed_size = 0;
363 }
364
365 _p = uncompressed_table;
366 _sz = uncompressed_size;
367 _compressed = true;
368
369 return e;
370 }
371