Bug 1685225 - Use state bits to determine the color for non-native theme meter chunks...
[gecko.git] / gfx / graphite2 / src / Face.cpp
blob3e106050d7de043b0c8c447b5c9c0d2e222e6cb3
1 /* GRAPHITE2 LICENSING
3 Copyright 2010, 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.
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/Segment.h"
38 #include "inc/NameTable.h"
39 #include "inc/Error.h"
41 using namespace graphite2;
43 namespace
45 enum compression
47 NONE,
48 LZ4
53 Face::Face(const void* appFaceHandle/*non-NULL*/, const gr_face_ops & ops)
54 : m_appFaceHandle(appFaceHandle),
55 m_pFileFace(NULL),
56 m_pGlyphFaceCache(NULL),
57 m_cmap(NULL),
58 m_pNames(NULL),
59 m_logger(NULL),
60 m_error(0), m_errcntxt(0),
61 m_silfs(NULL),
62 m_numSilf(0),
63 m_ascent(0),
64 m_descent(0)
66 memset(&m_ops, 0, sizeof m_ops);
67 memcpy(&m_ops, &ops, min(sizeof m_ops, ops.size));
71 Face::~Face()
73 setLogger(0);
74 delete m_pGlyphFaceCache;
75 delete m_cmap;
76 delete[] m_silfs;
77 #ifndef GRAPHITE2_NFILEFACE
78 delete m_pFileFace;
79 #endif
80 delete m_pNames;
83 float Face::default_glyph_advance(const void* font_ptr, gr_uint16 glyphid)
85 const Font & font = *reinterpret_cast<const Font *>(font_ptr);
87 return font.face().glyphs().glyph(glyphid)->theAdvance().x * font.scale();
90 bool Face::readGlyphs(uint32 faceOptions)
92 Error e;
93 #ifdef GRAPHITE2_TELEMETRY
94 telemetry::category _glyph_cat(tele.glyph);
95 #endif
96 error_context(EC_READGLYPHS);
97 m_pGlyphFaceCache = new GlyphCache(*this, faceOptions);
99 if (e.test(!m_pGlyphFaceCache, E_OUTOFMEM)
100 || e.test(m_pGlyphFaceCache->numGlyphs() == 0, E_NOGLYPHS)
101 || e.test(m_pGlyphFaceCache->unitsPerEm() == 0, E_BADUPEM))
103 return error(e);
106 if (faceOptions & gr_face_cacheCmap)
107 m_cmap = new CachedCmap(*this);
108 else
109 m_cmap = new DirectCmap(*this);
110 if (e.test(!m_cmap, E_OUTOFMEM) || e.test(!*m_cmap, E_BADCMAP))
111 return error(e);
113 if (faceOptions & gr_face_preloadGlyphs)
114 nameTable(); // preload the name table along with the glyphs.
116 return true;
119 bool Face::readGraphite(const Table & silf)
121 #ifdef GRAPHITE2_TELEMETRY
122 telemetry::category _silf_cat(tele.silf);
123 #endif
124 Error e;
125 error_context(EC_READSILF);
126 const byte * p = silf;
127 if (e.test(!p, E_NOSILF) || e.test(silf.size() < 20, E_BADSIZE)) return error(e);
129 const uint32 version = be::read<uint32>(p);
130 if (e.test(version < 0x00020000, E_TOOOLD)) return error(e);
131 if (version >= 0x00030000)
132 be::skip<uint32>(p); // compilerVersion
133 m_numSilf = be::read<uint16>(p);
135 be::skip<uint16>(p); // reserved
137 bool havePasses = false;
138 m_silfs = new Silf[m_numSilf];
139 if (e.test(!m_silfs, E_OUTOFMEM)) return error(e);
140 for (int i = 0; i < m_numSilf; i++)
142 error_context(EC_ASILF + (i << 8));
143 const uint32 offset = be::read<uint32>(p),
144 next = i == m_numSilf - 1 ? uint32(silf.size()) : be::peek<uint32>(p);
145 if (e.test(next > silf.size() || offset >= next, E_BADSIZE))
146 return error(e);
148 if (!m_silfs[i].readGraphite(silf + offset, next - offset, *this, version))
149 return false;
151 if (m_silfs[i].numPasses())
152 havePasses = true;
155 return havePasses;
158 bool Face::readFeatures()
160 return m_Sill.readFace(*this);
163 bool Face::runGraphite(Segment *seg, const Silf *aSilf) const
165 #if !defined GRAPHITE2_NTRACING
166 json * dbgout = logger();
167 if (dbgout)
169 *dbgout << json::object
170 << "id" << objectid(seg)
171 << "passes" << json::array;
173 #endif
175 // if ((seg->dir() & 1) != aSilf->dir())
176 // seg->reverseSlots();
177 if ((seg->dir() & 3) == 3 && aSilf->bidiPass() == 0xFF)
178 seg->doMirror(aSilf->aMirror());
179 bool res = aSilf->runGraphite(seg, 0, aSilf->positionPass(), true);
180 if (res)
182 seg->associateChars(0, seg->charInfoCount());
183 if (aSilf->flags() & 0x20)
184 res &= seg->initCollisions();
185 if (res)
186 res &= aSilf->runGraphite(seg, aSilf->positionPass(), aSilf->numPasses(), false);
189 #if !defined GRAPHITE2_NTRACING
190 if (dbgout)
192 seg->positionSlots(0, 0, 0, seg->currdir());
193 *dbgout << json::item
194 << json::close // Close up the passes array
195 << "outputdir" << (seg->currdir() ? "rtl" : "ltr")
196 << "output" << json::array;
197 for(Slot * s = seg->first(); s; s = s->next())
198 *dbgout << dslot(seg, s);
199 *dbgout << json::close
200 << "advance" << seg->advance()
201 << "chars" << json::array;
202 for(size_t i = 0, n = seg->charInfoCount(); i != n; ++i)
203 *dbgout << json::flat << *seg->charinfo(int(i));
204 *dbgout << json::close // Close up the chars array
205 << json::close; // Close up the segment object
207 #endif
209 return res;
212 void Face::setLogger(FILE * log_file GR_MAYBE_UNUSED)
214 #if !defined GRAPHITE2_NTRACING
215 delete m_logger;
216 m_logger = log_file ? new json(log_file) : 0;
217 #endif
220 const Silf *Face::chooseSilf(uint32 script) const
222 if (m_numSilf == 0)
223 return NULL;
224 else if (m_numSilf == 1 || script == 0)
225 return m_silfs;
226 else // do more work here
227 return m_silfs;
230 uint16 Face::findPseudo(uint32 uid) const
232 return (m_numSilf) ? m_silfs[0].findPseudo(uid) : 0;
235 int32 Face::getGlyphMetric(uint16 gid, uint8 metric) const
237 switch (metrics(metric))
239 case kgmetAscent : return m_ascent;
240 case kgmetDescent : return m_descent;
241 default:
242 if (gid >= glyphs().numGlyphs()) return 0;
243 return glyphs().glyph(gid)->getMetric(metric);
247 void Face::takeFileFace(FileFace* pFileFace GR_MAYBE_UNUSED/*takes ownership*/)
249 #ifndef GRAPHITE2_NFILEFACE
250 if (m_pFileFace==pFileFace)
251 return;
253 delete m_pFileFace;
254 m_pFileFace = pFileFace;
255 #endif
258 NameTable * Face::nameTable() const
260 if (m_pNames) return m_pNames;
261 const Table name(*this, Tag::name);
262 if (name)
263 m_pNames = new NameTable(name, name.size());
264 return m_pNames;
267 uint16 Face::languageForLocale(const char * locale) const
269 nameTable();
270 if (m_pNames)
271 return m_pNames->getLanguageId(locale);
272 return 0;
277 Face::Table::Table(const Face & face, const Tag n, uint32 version) throw()
278 : _f(&face), _sz(0), _compressed(false)
280 _p = static_cast<const byte *>((*_f->m_ops.get_table)(_f->m_appFaceHandle, n, &_sz));
282 if (!TtfUtil::CheckTable(n, _p, _sz))
284 release(); // Make sure we release the table buffer even if the table failed its checks
285 return;
288 if (be::peek<uint32>(_p) >= version)
289 decompress();
292 void Face::Table::release()
294 if (_compressed)
295 free(const_cast<byte *>(_p));
296 else if (_p && _f->m_ops.release_table)
297 (*_f->m_ops.release_table)(_f->m_appFaceHandle, _p);
298 _p = 0; _sz = 0;
301 Face::Table & Face::Table::operator = (const Table && rhs) throw()
303 if (this == &rhs) return *this;
304 release();
305 new (this) Table(std::move(rhs));
306 return *this;
309 Error Face::Table::decompress()
311 Error e;
312 if (e.test(_sz < 5 * sizeof(uint32), E_BADSIZE))
313 return e;
314 byte * uncompressed_table = 0;
315 size_t uncompressed_size = 0;
317 const byte * p = _p;
318 const uint32 version = be::read<uint32>(p); // Table version number.
320 // The scheme is in the top 5 bits of the 1st uint32.
321 const uint32 hdr = be::read<uint32>(p);
322 switch(compression(hdr >> 27))
324 case NONE: return e;
326 case LZ4:
328 uncompressed_size = hdr & 0x07ffffff;
329 uncompressed_table = gralloc<byte>(uncompressed_size);
330 if (!e.test(!uncompressed_table || uncompressed_size < 4, E_OUTOFMEM))
332 memset(uncompressed_table, 0, 4); // make sure version number is initialised
333 // coverity[forward_null : FALSE] - uncompressed_table has been checked so can't be null
334 // coverity[checked_return : FALSE] - we test e later
335 e.test(lz4::decompress(p, _sz - 2*sizeof(uint32), uncompressed_table, uncompressed_size) != signed(uncompressed_size), E_SHRINKERFAILED);
337 break;
340 default:
341 e.error(E_BADSCHEME);
344 // Check the uncompressed version number against the original.
345 if (!e)
346 // coverity[forward_null : FALSE] - uncompressed_table has already been tested so can't be null
347 // coverity[checked_return : FALSE] - we test e later
348 e.test(be::peek<uint32>(uncompressed_table) != version, E_SHRINKERFAILED);
350 // Tell the provider to release the compressed form since were replacing
351 // it anyway.
352 release();
354 if (e)
356 free(uncompressed_table);
357 uncompressed_table = 0;
358 uncompressed_size = 0;
361 _p = uncompressed_table;
362 _sz = uncompressed_size;
363 _compressed = true;
365 return e;