|
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 |