| |
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/Endian.h" |
| |
32 #include "inc/Face.h" |
| |
33 #include "inc/FileFace.h" |
| |
34 #include "inc/GlyphFace.h" |
| |
35 #include "inc/json.h" |
| |
36 #include "inc/SegCacheStore.h" |
| |
37 #include "inc/Segment.h" |
| |
38 #include "inc/NameTable.h" |
| |
39 #include "inc/Error.h" |
| |
40 |
| |
41 using namespace graphite2; |
| |
42 |
| |
43 Face::Face(const void* appFaceHandle/*non-NULL*/, const gr_face_ops & ops) |
| |
44 : m_appFaceHandle(appFaceHandle), |
| |
45 m_pFileFace(NULL), |
| |
46 m_pGlyphFaceCache(NULL), |
| |
47 m_cmap(NULL), |
| |
48 m_pNames(NULL), |
| |
49 m_logger(NULL), |
| |
50 m_error(0), m_errcntxt(0), |
| |
51 m_silfs(NULL), |
| |
52 m_numSilf(0), |
| |
53 m_ascent(0), |
| |
54 m_descent(0) |
| |
55 { |
| |
56 memset(&m_ops, 0, sizeof m_ops); |
| |
57 memcpy(&m_ops, &ops, min(sizeof m_ops, ops.size)); |
| |
58 } |
| |
59 |
| |
60 |
| |
61 Face::~Face() |
| |
62 { |
| |
63 setLogger(0); |
| |
64 delete m_pGlyphFaceCache; |
| |
65 delete m_cmap; |
| |
66 delete[] m_silfs; |
| |
67 #ifndef GRAPHITE2_NFILEFACE |
| |
68 delete m_pFileFace; |
| |
69 #endif |
| |
70 delete m_pNames; |
| |
71 } |
| |
72 |
| |
73 float Face::default_glyph_advance(const void* font_ptr, gr_uint16 glyphid) |
| |
74 { |
| |
75 const Font & font = *reinterpret_cast<const Font *>(font_ptr); |
| |
76 |
| |
77 return font.face().glyphs().glyph(glyphid)->theAdvance().x * font.scale(); |
| |
78 } |
| |
79 |
| |
80 bool Face::readGlyphs(uint32 faceOptions) |
| |
81 { |
| |
82 Error e; |
| |
83 #ifdef GRAPHITE2_TELEMETRY |
| |
84 telemetry::category _glyph_cat(tele.glyph); |
| |
85 #endif |
| |
86 error_context(EC_READGLYPHS); |
| |
87 if (faceOptions & gr_face_cacheCmap) |
| |
88 m_cmap = new CachedCmap(*this); |
| |
89 else |
| |
90 m_cmap = new DirectCmap(*this); |
| |
91 |
| |
92 m_pGlyphFaceCache = new GlyphCache(*this, faceOptions); |
| |
93 if (e.test(!m_pGlyphFaceCache, E_OUTOFMEM) |
| |
94 || e.test(m_pGlyphFaceCache->numGlyphs() == 0, E_NOGLYPHS) |
| |
95 || e.test(m_pGlyphFaceCache->unitsPerEm() == 0, E_BADUPEM) |
| |
96 || e.test(!m_cmap, E_OUTOFMEM) || e.test(!*m_cmap, E_BADCMAP)) |
| |
97 { |
| |
98 return error(e); |
| |
99 } |
| |
100 |
| |
101 if (faceOptions & gr_face_preloadGlyphs) |
| |
102 nameTable(); // preload the name table along with the glyphs. |
| |
103 |
| |
104 return true; |
| |
105 } |
| |
106 |
| |
107 bool Face::readGraphite(const Table & silf) |
| |
108 { |
| |
109 #ifdef GRAPHITE2_TELEMETRY |
| |
110 telemetry::category _silf_cat(tele.silf); |
| |
111 #endif |
| |
112 Error e; |
| |
113 error_context(EC_READSILF); |
| |
114 const byte * p = silf; |
| |
115 if (e.test(!p, E_NOSILF)) return error(e); |
| |
116 |
| |
117 const uint32 version = be::read<uint32>(p); |
| |
118 if (e.test(version < 0x00020000, E_TOOOLD)) return error(e); |
| |
119 if (version >= 0x00030000) |
| |
120 be::skip<uint32>(p); // compilerVersion |
| |
121 m_numSilf = be::read<uint16>(p); |
| |
122 be::skip<uint16>(p); // reserved |
| |
123 |
| |
124 bool havePasses = false; |
| |
125 m_silfs = new Silf[m_numSilf]; |
| |
126 for (int i = 0; i < m_numSilf; i++) |
| |
127 { |
| |
128 error_context(EC_ASILF + (i << 8)); |
| |
129 const uint32 offset = be::read<uint32>(p), |
| |
130 next = i == m_numSilf - 1 ? silf.size() : be::peek<uint32>(p); |
| |
131 if (e.test(next > silf.size() || offset >= next, E_BADSIZE)) |
| |
132 return error(e); |
| |
133 |
| |
134 if (!m_silfs[i].readGraphite(silf + offset, next - offset, *this, version)) |
| |
135 return false; |
| |
136 |
| |
137 if (m_silfs[i].numPasses()) |
| |
138 havePasses = true; |
| |
139 } |
| |
140 |
| |
141 return havePasses; |
| |
142 } |
| |
143 |
| |
144 bool Face::readFeatures() |
| |
145 { |
| |
146 return m_Sill.readFace(*this); |
| |
147 } |
| |
148 |
| |
149 bool Face::runGraphite(Segment *seg, const Silf *aSilf) const |
| |
150 { |
| |
151 #if !defined GRAPHITE2_NTRACING |
| |
152 json * dbgout = logger(); |
| |
153 if (dbgout) |
| |
154 { |
| |
155 *dbgout << json::object |
| |
156 << "id" << objectid(seg) |
| |
157 << "passes" << json::array; |
| |
158 } |
| |
159 #endif |
| |
160 |
| |
161 bool res = aSilf->runGraphite(seg, 0, aSilf->justificationPass(), true); |
| |
162 if (res) |
| |
163 res = aSilf->runGraphite(seg, aSilf->positionPass(), aSilf->numPasses(), false); |
| |
164 |
| |
165 #if !defined GRAPHITE2_NTRACING |
| |
166 if (dbgout) |
| |
167 { |
| |
168 *dbgout << json::item |
| |
169 << json::close // Close up the passes array |
| |
170 << "output" << json::array; |
| |
171 for(Slot * s = seg->first(); s; s = s->next()) |
| |
172 *dbgout << dslot(seg, s); |
| |
173 seg->finalise(0); // Call this here to fix up charinfo back indexes. |
| |
174 *dbgout << json::close |
| |
175 << "advance" << seg->advance() |
| |
176 << "chars" << json::array; |
| |
177 for(size_t i = 0, n = seg->charInfoCount(); i != n; ++i) |
| |
178 *dbgout << json::flat << *seg->charinfo(i); |
| |
179 *dbgout << json::close // Close up the chars array |
| |
180 << json::close; // Close up the segment object |
| |
181 } |
| |
182 #endif |
| |
183 |
| |
184 return res; |
| |
185 } |
| |
186 |
| |
187 void Face::setLogger(FILE * log_file GR_MAYBE_UNUSED) |
| |
188 { |
| |
189 #if !defined GRAPHITE2_NTRACING |
| |
190 delete m_logger; |
| |
191 m_logger = log_file ? new json(log_file) : 0; |
| |
192 #endif |
| |
193 } |
| |
194 |
| |
195 const Silf *Face::chooseSilf(uint32 script) const |
| |
196 { |
| |
197 if (m_numSilf == 0) |
| |
198 return NULL; |
| |
199 else if (m_numSilf == 1 || script == 0) |
| |
200 return m_silfs; |
| |
201 else // do more work here |
| |
202 return m_silfs; |
| |
203 } |
| |
204 |
| |
205 uint16 Face::findPseudo(uint32 uid) const |
| |
206 { |
| |
207 return (m_numSilf) ? m_silfs[0].findPseudo(uid) : 0; |
| |
208 } |
| |
209 |
| |
210 uint16 Face::getGlyphMetric(uint16 gid, uint8 metric) const |
| |
211 { |
| |
212 switch (metrics(metric)) |
| |
213 { |
| |
214 case kgmetAscent : return m_ascent; |
| |
215 case kgmetDescent : return m_descent; |
| |
216 default: return glyphs().glyph(gid)->getMetric(metric); |
| |
217 } |
| |
218 } |
| |
219 |
| |
220 void Face::takeFileFace(FileFace* pFileFace GR_MAYBE_UNUSED/*takes ownership*/) |
| |
221 { |
| |
222 #ifndef GRAPHITE2_NFILEFACE |
| |
223 if (m_pFileFace==pFileFace) |
| |
224 return; |
| |
225 |
| |
226 delete m_pFileFace; |
| |
227 m_pFileFace = pFileFace; |
| |
228 #endif |
| |
229 } |
| |
230 |
| |
231 NameTable * Face::nameTable() const |
| |
232 { |
| |
233 if (m_pNames) return m_pNames; |
| |
234 const Table name(*this, Tag::name); |
| |
235 if (name) |
| |
236 m_pNames = new NameTable(name, name.size()); |
| |
237 return m_pNames; |
| |
238 } |
| |
239 |
| |
240 uint16 Face::languageForLocale(const char * locale) const |
| |
241 { |
| |
242 nameTable(); |
| |
243 if (m_pNames) |
| |
244 return m_pNames->getLanguageId(locale); |
| |
245 return 0; |
| |
246 } |
| |
247 |
| |
248 Face::Table::Table(const Face & face, const Tag n) throw() |
| |
249 : _f(&face) |
| |
250 { |
| |
251 size_t sz = 0; |
| |
252 _p = reinterpret_cast<const byte *>((*_f->m_ops.get_table)(_f->m_appFaceHandle, n, &sz)); |
| |
253 _sz = uint32(sz); |
| |
254 if (!TtfUtil::CheckTable(n, _p, _sz)) |
| |
255 { |
| |
256 this->~Table(); // Make sure we release the table buffer even if the table filed it's checks |
| |
257 _p = 0; _sz = 0; |
| |
258 } |
| |
259 } |
| |
260 |
| |
261 Face::Table & Face::Table::operator = (const Table & rhs) throw() |
| |
262 { |
| |
263 if (_p == rhs._p) return *this; |
| |
264 |
| |
265 this->~Table(); |
| |
266 new (this) Table(rhs); |
| |
267 return *this; |
| |
268 } |
| |
269 |