Line data Source code
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 :
54 0 : 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 0 : m_descent(0)
66 : {
67 0 : memset(&m_ops, 0, sizeof m_ops);
68 0 : memcpy(&m_ops, &ops, min(sizeof m_ops, ops.size));
69 0 : }
70 :
71 :
72 0 : Face::~Face()
73 : {
74 0 : setLogger(0);
75 0 : delete m_pGlyphFaceCache;
76 0 : delete m_cmap;
77 0 : delete[] m_silfs;
78 : #ifndef GRAPHITE2_NFILEFACE
79 : delete m_pFileFace;
80 : #endif
81 0 : delete m_pNames;
82 0 : }
83 :
84 0 : float Face::default_glyph_advance(const void* font_ptr, gr_uint16 glyphid)
85 : {
86 0 : const Font & font = *reinterpret_cast<const Font *>(font_ptr);
87 :
88 0 : return font.face().glyphs().glyph(glyphid)->theAdvance().x * font.scale();
89 : }
90 :
91 0 : bool Face::readGlyphs(uint32 faceOptions)
92 : {
93 0 : Error e;
94 : #ifdef GRAPHITE2_TELEMETRY
95 : telemetry::category _glyph_cat(tele.glyph);
96 : #endif
97 0 : error_context(EC_READGLYPHS);
98 0 : m_pGlyphFaceCache = new GlyphCache(*this, faceOptions);
99 :
100 0 : if (e.test(!m_pGlyphFaceCache, E_OUTOFMEM)
101 0 : || e.test(m_pGlyphFaceCache->numGlyphs() == 0, E_NOGLYPHS)
102 0 : || e.test(m_pGlyphFaceCache->unitsPerEm() == 0, E_BADUPEM))
103 : {
104 0 : return error(e);
105 : }
106 :
107 0 : if (faceOptions & gr_face_cacheCmap)
108 0 : m_cmap = new CachedCmap(*this);
109 : else
110 0 : m_cmap = new DirectCmap(*this);
111 0 : if (e.test(!m_cmap, E_OUTOFMEM) || e.test(!*m_cmap, E_BADCMAP))
112 0 : return error(e);
113 :
114 0 : if (faceOptions & gr_face_preloadGlyphs)
115 0 : nameTable(); // preload the name table along with the glyphs.
116 :
117 0 : return true;
118 : }
119 :
120 0 : bool Face::readGraphite(const Table & silf)
121 : {
122 : #ifdef GRAPHITE2_TELEMETRY
123 : telemetry::category _silf_cat(tele.silf);
124 : #endif
125 0 : Error e;
126 0 : error_context(EC_READSILF);
127 0 : const byte * p = silf;
128 0 : if (e.test(!p, E_NOSILF) || e.test(silf.size() < 20, E_BADSIZE)) return error(e);
129 :
130 0 : const uint32 version = be::read<uint32>(p);
131 0 : if (e.test(version < 0x00020000, E_TOOOLD)) return error(e);
132 0 : if (version >= 0x00030000)
133 0 : be::skip<uint32>(p); // compilerVersion
134 0 : m_numSilf = be::read<uint16>(p);
135 :
136 0 : be::skip<uint16>(p); // reserved
137 :
138 0 : bool havePasses = false;
139 0 : m_silfs = new Silf[m_numSilf];
140 0 : if (e.test(!m_silfs, E_OUTOFMEM)) return error(e);
141 0 : for (int i = 0; i < m_numSilf; i++)
142 : {
143 0 : error_context(EC_ASILF + (i << 8));
144 0 : const uint32 offset = be::read<uint32>(p),
145 0 : next = i == m_numSilf - 1 ? silf.size() : be::peek<uint32>(p);
146 0 : if (e.test(next > silf.size() || offset >= next, E_BADSIZE))
147 0 : return error(e);
148 :
149 0 : if (!m_silfs[i].readGraphite(silf + offset, next - offset, *this, version))
150 0 : return false;
151 :
152 0 : if (m_silfs[i].numPasses())
153 0 : havePasses = true;
154 : }
155 :
156 0 : return havePasses;
157 : }
158 :
159 0 : bool Face::readFeatures()
160 : {
161 0 : return m_Sill.readFace(*this);
162 : }
163 :
164 0 : 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 0 : if ((seg->dir() & 3) == 3 && aSilf->bidiPass() == 0xFF)
179 0 : seg->doMirror(aSilf->aMirror());
180 0 : bool res = aSilf->runGraphite(seg, 0, aSilf->positionPass(), true);
181 0 : if (res)
182 : {
183 0 : seg->associateChars(0, seg->charInfoCount());
184 0 : if (aSilf->flags() & 0x20)
185 0 : res &= seg->initCollisions();
186 0 : if (res)
187 0 : 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 0 : return res;
211 : }
212 :
213 0 : 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 0 : }
220 :
221 0 : const Silf *Face::chooseSilf(uint32 script) const
222 : {
223 0 : if (m_numSilf == 0)
224 0 : return NULL;
225 0 : else if (m_numSilf == 1 || script == 0)
226 0 : return m_silfs;
227 : else // do more work here
228 0 : return m_silfs;
229 : }
230 :
231 0 : uint16 Face::findPseudo(uint32 uid) const
232 : {
233 0 : return (m_numSilf) ? m_silfs[0].findPseudo(uid) : 0;
234 : }
235 :
236 0 : int32 Face::getGlyphMetric(uint16 gid, uint8 metric) const
237 : {
238 0 : switch (metrics(metric))
239 : {
240 0 : case kgmetAscent : return m_ascent;
241 0 : case kgmetDescent : return m_descent;
242 : default:
243 0 : if (gid >= glyphs().numGlyphs()) return 0;
244 0 : return glyphs().glyph(gid)->getMetric(metric);
245 : }
246 : }
247 :
248 0 : 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 0 : }
258 :
259 0 : NameTable * Face::nameTable() const
260 : {
261 0 : if (m_pNames) return m_pNames;
262 0 : const Table name(*this, Tag::name);
263 0 : if (name)
264 0 : m_pNames = new NameTable(name, name.size());
265 0 : return m_pNames;
266 : }
267 :
268 0 : uint16 Face::languageForLocale(const char * locale) const
269 : {
270 0 : nameTable();
271 0 : if (m_pNames)
272 0 : return m_pNames->getLanguageId(locale);
273 0 : return 0;
274 : }
275 :
276 :
277 :
278 0 : Face::Table::Table(const Face & face, const Tag n, uint32 version) throw()
279 0 : : _f(&face), _compressed(false)
280 : {
281 0 : size_t sz = 0;
282 0 : _p = static_cast<const byte *>((*_f->m_ops.get_table)(_f->m_appFaceHandle, n, &sz));
283 0 : _sz = uint32(sz);
284 :
285 0 : if (!TtfUtil::CheckTable(n, _p, _sz))
286 : {
287 0 : releaseBuffers(); // Make sure we release the table buffer even if the table failed it's checks
288 0 : return;
289 : }
290 :
291 0 : if (be::peek<uint32>(_p) >= version)
292 0 : decompress();
293 : }
294 :
295 0 : void Face::Table::releaseBuffers()
296 : {
297 0 : if (_compressed)
298 0 : free(const_cast<byte *>(_p));
299 0 : else if (_p && _f->m_ops.release_table)
300 0 : (*_f->m_ops.release_table)(_f->m_appFaceHandle, _p);
301 0 : _p = 0; _sz = 0;
302 0 : }
303 :
304 0 : Face::Table & Face::Table::operator = (const Table & rhs) throw()
305 : {
306 0 : if (_p == rhs._p) return *this;
307 :
308 0 : this->~Table();
309 0 : new (this) Table(rhs);
310 0 : return *this;
311 : }
312 :
313 0 : Error Face::Table::decompress()
314 : {
315 0 : Error e;
316 0 : if (e.test(_sz < 5 * sizeof(uint32), E_BADSIZE))
317 0 : return e;
318 0 : byte * uncompressed_table = 0;
319 0 : size_t uncompressed_size = 0;
320 :
321 0 : const byte * p = _p;
322 0 : 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 0 : const uint32 hdr = be::read<uint32>(p);
326 0 : switch(compression(hdr >> 27))
327 : {
328 0 : case NONE: return e;
329 :
330 : case LZ4:
331 : {
332 0 : uncompressed_size = hdr & 0x07ffffff;
333 0 : uncompressed_table = gralloc<byte>(uncompressed_size);
334 0 : if (!e.test(!uncompressed_table || uncompressed_size < 4, E_OUTOFMEM))
335 : {
336 0 : 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 0 : e.test(lz4::decompress(p, _sz - 2*sizeof(uint32), uncompressed_table, uncompressed_size) != signed(uncompressed_size), E_SHRINKERFAILED);
340 : }
341 0 : break;
342 : }
343 :
344 : default:
345 0 : e.error(E_BADSCHEME);
346 : };
347 :
348 : // Check the uncompressed version number against the original.
349 0 : 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 0 : 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 0 : releaseBuffers();
357 :
358 0 : if (e)
359 : {
360 0 : free(uncompressed_table);
361 0 : uncompressed_table = 0;
362 0 : uncompressed_size = 0;
363 : }
364 :
365 0 : _p = uncompressed_table;
366 0 : _sz = uncompressed_size;
367 0 : _compressed = true;
368 :
369 0 : return e;
370 : }
|