/work/workdir/UnpackedTarball/graphite/src/FeatureMap.cpp
Line | Count | Source (jump to first uncovered line) |
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 | | |
29 | | #include "inc/Main.h" |
30 | | #include "inc/bits.h" |
31 | | #include "inc/Endian.h" |
32 | | #include "inc/FeatureMap.h" |
33 | | #include "inc/FeatureVal.h" |
34 | | #include "graphite2/Font.h" |
35 | | #include "inc/TtfUtil.h" |
36 | | #include <cstdlib> |
37 | | #include "inc/Face.h" |
38 | | |
39 | | |
40 | | using namespace graphite2; |
41 | | |
42 | | namespace |
43 | | { |
44 | | static int cmpNameAndFeatures(const void *ap, const void *bp) |
45 | 0 | { |
46 | 0 | const NameAndFeatureRef & a = *static_cast<const NameAndFeatureRef *>(ap), |
47 | 0 | & b = *static_cast<const NameAndFeatureRef *>(bp); |
48 | 0 | return (a < b ? -1 : (b < a ? 1 : 0)); |
49 | 0 | } |
50 | | |
51 | | const size_t FEAT_HEADER = sizeof(uint32) + 2*sizeof(uint16) + sizeof(uint32), |
52 | | FEATURE_SIZE = sizeof(uint32) |
53 | | + 2*sizeof(uint16) |
54 | | + sizeof(uint32) |
55 | | + 2*sizeof(uint16), |
56 | | FEATURE_SETTING_SIZE = sizeof(int16) + sizeof(uint16); |
57 | | |
58 | | uint16 readFeatureSettings(const byte * p, FeatureSetting * s, size_t num_settings) |
59 | 0 | { |
60 | 0 | uint16 max_val = 0; |
61 | 0 | for (FeatureSetting * const end = s + num_settings; s != end; ++s) |
62 | 0 | { |
63 | 0 | const int16 value = be::read<int16>(p); |
64 | 0 | ::new (s) FeatureSetting(value, be::read<uint16>(p)); |
65 | 0 | if (uint16(value) > max_val) max_val = value; |
66 | 0 | } |
67 | |
|
68 | 0 | return max_val; |
69 | 0 | } |
70 | | } |
71 | | |
72 | | FeatureRef::FeatureRef(const Face & face, |
73 | | unsigned short & bits_offset, uint32 max_val, |
74 | | uint32 name, uint16 uiName, flags_t flags, |
75 | | FeatureSetting *settings, uint16 num_set) throw() |
76 | 0 | : m_face(&face), |
77 | 0 | m_nameValues(settings), |
78 | 0 | m_mask(mask_over_val(max_val)), |
79 | 0 | m_max(max_val), |
80 | 0 | m_id(name), |
81 | 0 | m_nameid(uiName), |
82 | 0 | m_numSet(num_set), |
83 | 0 | m_flags(flags) |
84 | 0 | { |
85 | 0 | const uint8 need_bits = bit_set_count(m_mask); |
86 | 0 | m_index = (bits_offset + need_bits) / SIZEOF_CHUNK; |
87 | 0 | if (m_index > bits_offset / SIZEOF_CHUNK) |
88 | 0 | bits_offset = m_index*SIZEOF_CHUNK; |
89 | 0 | m_bits = bits_offset % SIZEOF_CHUNK; |
90 | 0 | bits_offset += need_bits; |
91 | 0 | m_mask <<= m_bits; |
92 | 0 | } |
93 | | |
94 | | FeatureRef::~FeatureRef() throw() |
95 | 0 | { |
96 | 0 | free(m_nameValues); |
97 | 0 | } |
98 | | |
99 | | bool FeatureMap::readFeats(const Face & face) |
100 | 0 | { |
101 | 0 | const Face::Table feat(face, TtfUtil::Tag::Feat); |
102 | 0 | const byte * p = feat; |
103 | 0 | if (!p) return true; |
104 | 0 | if (feat.size() < FEAT_HEADER) return false; |
105 | | |
106 | 0 | const byte *const feat_start = p, |
107 | 0 | *const feat_end = p + feat.size(); |
108 | |
|
109 | 0 | const uint32 version = be::read<uint32>(p); |
110 | 0 | m_numFeats = be::read<uint16>(p); |
111 | 0 | be::skip<uint16>(p); |
112 | 0 | be::skip<uint32>(p); |
113 | | |
114 | | // Sanity checks |
115 | 0 | if (m_numFeats == 0) return true; |
116 | 0 | if (version < 0x00010000 || |
117 | 0 | p + m_numFeats*FEATURE_SIZE > feat_end) |
118 | 0 | { //defensive |
119 | 0 | m_numFeats = 0; |
120 | 0 | return false; |
121 | 0 | } |
122 | | |
123 | 0 | m_feats = new FeatureRef [m_numFeats]; |
124 | 0 | uint16 * const defVals = gralloc<uint16>(m_numFeats); |
125 | 0 | if (!defVals || !m_feats) return false; |
126 | 0 | unsigned short bits = 0; //to cause overflow on first Feature |
127 | |
|
128 | 0 | for (int i = 0, ie = m_numFeats; i != ie; i++) |
129 | 0 | { |
130 | 0 | const uint32 label = version < 0x00020000 ? be::read<uint16>(p) : be::read<uint32>(p); |
131 | 0 | const uint16 num_settings = be::read<uint16>(p); |
132 | 0 | if (version >= 0x00020000) |
133 | 0 | be::skip<uint16>(p); |
134 | 0 | const uint32 settings_offset = be::read<uint32>(p); |
135 | 0 | const uint16 flags = be::read<uint16>(p), |
136 | 0 | uiName = be::read<uint16>(p); |
137 | |
|
138 | 0 | if (settings_offset > size_t(feat_end - feat_start) |
139 | 0 | || settings_offset + num_settings * FEATURE_SETTING_SIZE > size_t(feat_end - feat_start)) |
140 | 0 | { |
141 | 0 | free(defVals); |
142 | 0 | return false; |
143 | 0 | } |
144 | | |
145 | 0 | FeatureSetting *uiSet; |
146 | 0 | uint32 maxVal; |
147 | 0 | if (num_settings != 0) |
148 | 0 | { |
149 | 0 | uiSet = gralloc<FeatureSetting>(num_settings); |
150 | 0 | if (!uiSet) |
151 | 0 | { |
152 | 0 | free(defVals); |
153 | 0 | return false; |
154 | 0 | } |
155 | 0 | maxVal = readFeatureSettings(feat_start + settings_offset, uiSet, num_settings); |
156 | 0 | defVals[i] = uiSet[0].value(); |
157 | 0 | } |
158 | 0 | else |
159 | 0 | { |
160 | 0 | uiSet = 0; |
161 | 0 | maxVal = 0xffffffff; |
162 | 0 | defVals[i] = 0; |
163 | 0 | } |
164 | | |
165 | 0 | ::new (m_feats + i) FeatureRef (face, bits, maxVal, |
166 | 0 | label, uiName, |
167 | 0 | FeatureRef::flags_t(flags), |
168 | 0 | uiSet, num_settings); |
169 | 0 | } |
170 | 0 | new (&m_defaultFeatures) Features(bits/(sizeof(uint32)*8) + 1, *this); |
171 | 0 | m_pNamedFeats = new NameAndFeatureRef[m_numFeats]; |
172 | 0 | if (!m_pNamedFeats) |
173 | 0 | { |
174 | 0 | free(defVals); |
175 | 0 | return false; |
176 | 0 | } |
177 | 0 | for (int i = 0; i < m_numFeats; ++i) |
178 | 0 | { |
179 | 0 | m_feats[i].applyValToFeature(defVals[i], m_defaultFeatures); |
180 | 0 | m_pNamedFeats[i] = m_feats[i]; |
181 | 0 | } |
182 | |
|
183 | 0 | free(defVals); |
184 | |
|
185 | 0 | qsort(m_pNamedFeats, m_numFeats, sizeof(NameAndFeatureRef), &cmpNameAndFeatures); |
186 | |
|
187 | 0 | return true; |
188 | 0 | } |
189 | | |
190 | | bool SillMap::readFace(const Face & face) |
191 | 0 | { |
192 | 0 | if (!m_FeatureMap.readFeats(face)) return false; |
193 | 0 | if (!readSill(face)) return false; |
194 | 0 | return true; |
195 | 0 | } |
196 | | |
197 | | |
198 | | bool SillMap::readSill(const Face & face) |
199 | 0 | { |
200 | 0 | const Face::Table sill(face, TtfUtil::Tag::Sill); |
201 | 0 | const byte *p = sill; |
202 | |
|
203 | 0 | if (!p) return true; |
204 | 0 | if (sill.size() < 12) return false; |
205 | 0 | if (be::read<uint32>(p) != 0x00010000UL) return false; |
206 | 0 | m_numLanguages = be::read<uint16>(p); |
207 | 0 | m_langFeats = new LangFeaturePair[m_numLanguages]; |
208 | 0 | if (!m_langFeats || !m_FeatureMap.m_numFeats) { m_numLanguages = 0; return true; } //defensive |
209 | | |
210 | 0 | p += 6; // skip the fast search |
211 | 0 | if (sill.size() < m_numLanguages * 8U + 12) return false; |
212 | | |
213 | 0 | for (int i = 0; i < m_numLanguages; i++) |
214 | 0 | { |
215 | 0 | uint32 langid = be::read<uint32>(p); |
216 | 0 | uint16 numSettings = be::read<uint16>(p); |
217 | 0 | uint16 offset = be::read<uint16>(p); |
218 | 0 | if (offset + 8U * numSettings > sill.size() && numSettings > 0) return false; |
219 | 0 | Features* feats = new Features(m_FeatureMap.m_defaultFeatures); |
220 | 0 | if (!feats) return false; |
221 | 0 | const byte *pLSet = sill + offset; |
222 | | |
223 | | // Apply langauge specific settings |
224 | 0 | for (int j = 0; j < numSettings; j++) |
225 | 0 | { |
226 | 0 | uint32 name = be::read<uint32>(pLSet); |
227 | 0 | uint16 val = be::read<uint16>(pLSet); |
228 | 0 | pLSet += 2; |
229 | 0 | const FeatureRef* pRef = m_FeatureMap.findFeatureRef(name); |
230 | 0 | if (pRef) pRef->applyValToFeature(val, *feats); |
231 | 0 | } |
232 | | // Add the language id feature which is always feature id 1 |
233 | 0 | const FeatureRef* pRef = m_FeatureMap.findFeatureRef(1); |
234 | 0 | if (pRef) pRef->applyValToFeature(langid, *feats); |
235 | |
|
236 | 0 | m_langFeats[i].m_lang = langid; |
237 | 0 | m_langFeats[i].m_pFeatures = feats; |
238 | 0 | } |
239 | 0 | return true; |
240 | 0 | } |
241 | | |
242 | | |
243 | | Features* SillMap::cloneFeatures(uint32 langname/*0 means default*/) const |
244 | 0 | { |
245 | 0 | if (langname) |
246 | 0 | { |
247 | | // the number of languages in a font is usually small e.g. 8 in Doulos |
248 | | // so this loop is not very expensive |
249 | 0 | for (uint16 i = 0; i < m_numLanguages; i++) |
250 | 0 | { |
251 | 0 | if (m_langFeats[i].m_lang == langname) |
252 | 0 | return new Features(*m_langFeats[i].m_pFeatures); |
253 | 0 | } |
254 | 0 | } |
255 | 0 | return new Features (m_FeatureMap.m_defaultFeatures); |
256 | 0 | } |
257 | | |
258 | | |
259 | | |
260 | | const FeatureRef *FeatureMap::findFeatureRef(uint32 name) const |
261 | 0 | { |
262 | 0 | NameAndFeatureRef *it; |
263 | |
|
264 | 0 | for (it = m_pNamedFeats; it < m_pNamedFeats + m_numFeats; ++it) |
265 | 0 | if (it->m_name == name) |
266 | 0 | return it->m_pFRef; |
267 | 0 | return NULL; |
268 | 0 | } |
269 | | |
270 | | bool FeatureRef::applyValToFeature(uint32 val, Features & pDest) const |
271 | 0 | { |
272 | 0 | if (val>maxVal() || !m_face) |
273 | 0 | return false; |
274 | 0 | if (pDest.m_pMap==NULL) |
275 | 0 | pDest.m_pMap = &m_face->theSill().theFeatureMap(); |
276 | 0 | else |
277 | 0 | if (pDest.m_pMap!=&m_face->theSill().theFeatureMap()) |
278 | 0 | return false; //incompatible |
279 | 0 | if (m_index >= pDest.size()) |
280 | 0 | pDest.resize(m_index+1); |
281 | 0 | pDest[m_index] &= ~m_mask; |
282 | 0 | pDest[m_index] |= (uint32(val) << m_bits); |
283 | 0 | return true; |
284 | 0 | } |
285 | | |
286 | | uint32 FeatureRef::getFeatureVal(const Features& feats) const |
287 | 0 | { |
288 | 0 | if (m_index < feats.size() && m_face |
289 | 0 | && &m_face->theSill().theFeatureMap()==feats.m_pMap) |
290 | 0 | return (feats[m_index] & m_mask) >> m_bits; |
291 | 0 | else |
292 | 0 | return 0; |
293 | 0 | } |