|
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 "graphite2/Font.h" |
|
28 #include "inc/Face.h" |
|
29 #include "inc/FileFace.h" |
|
30 #include "inc/GlyphCache.h" |
|
31 #include "inc/CachedFace.h" |
|
32 #include "inc/CmapCache.h" |
|
33 #include "inc/Silf.h" |
|
34 #include "inc/json.h" |
|
35 |
|
36 using namespace graphite2; |
|
37 |
|
38 #if !defined GRAPHITE2_NTRACING |
|
39 extern json *global_log; |
|
40 #endif |
|
41 |
|
42 namespace |
|
43 { |
|
44 bool load_face(Face & face, unsigned int options) |
|
45 { |
|
46 #ifdef GRAPHITE2_TELEMETRY |
|
47 telemetry::category _misc_cat(face.tele.misc); |
|
48 #endif |
|
49 Face::Table silf(face, Tag::Silf); |
|
50 if (silf) options &= ~gr_face_dumbRendering; |
|
51 else if (!(options & gr_face_dumbRendering)) |
|
52 return false; |
|
53 |
|
54 if (!face.readGlyphs(options)) |
|
55 return false; |
|
56 |
|
57 if (silf) |
|
58 { |
|
59 if (!face.readFeatures() || !face.readGraphite(silf)) |
|
60 { |
|
61 #if !defined GRAPHITE2_NTRACING |
|
62 if (global_log) |
|
63 { |
|
64 *global_log << json::object |
|
65 << "type" << "fontload" |
|
66 << "failure" << face.error() |
|
67 << "context" << face.error_context() |
|
68 << json::close; |
|
69 } |
|
70 #endif |
|
71 return false; |
|
72 } |
|
73 else |
|
74 return true; |
|
75 } |
|
76 else |
|
77 return options & gr_face_dumbRendering; |
|
78 } |
|
79 } |
|
80 |
|
81 extern "C" { |
|
82 |
|
83 gr_face* gr_make_face_with_ops(const void* appFaceHandle/*non-NULL*/, const gr_face_ops *ops, unsigned int faceOptions) |
|
84 //the appFaceHandle must stay alive all the time when the gr_face is alive. When finished with the gr_face, call destroy_face |
|
85 { |
|
86 if (ops == 0) return 0; |
|
87 |
|
88 Face *res = new Face(appFaceHandle, *ops); |
|
89 if (res && load_face(*res, faceOptions)) |
|
90 return static_cast<gr_face *>(res); |
|
91 |
|
92 delete res; |
|
93 return 0; |
|
94 } |
|
95 |
|
96 gr_face* gr_make_face(const void* appFaceHandle/*non-NULL*/, gr_get_table_fn tablefn, unsigned int faceOptions) |
|
97 { |
|
98 const gr_face_ops ops = {sizeof(gr_face_ops), tablefn, NULL}; |
|
99 return gr_make_face_with_ops(appFaceHandle, &ops, faceOptions); |
|
100 } |
|
101 |
|
102 #ifndef GRAPHITE2_NSEGCACHE |
|
103 gr_face* gr_make_face_with_seg_cache_and_ops(const void* appFaceHandle/*non-NULL*/, const gr_face_ops *ops, unsigned int cacheSize, unsigned int faceOptions) |
|
104 //the appFaceHandle must stay alive all the time when the GrFace is alive. When finished with the GrFace, call destroy_face |
|
105 { |
|
106 if (ops == 0) return 0; |
|
107 |
|
108 CachedFace *res = new CachedFace(appFaceHandle, *ops); |
|
109 if (res && load_face(*res, faceOptions) |
|
110 && res->setupCache(cacheSize)) |
|
111 return static_cast<gr_face *>(static_cast<Face *>(res)); |
|
112 |
|
113 delete res; |
|
114 return 0; |
|
115 } |
|
116 |
|
117 gr_face* gr_make_face_with_seg_cache(const void* appFaceHandle/*non-NULL*/, gr_get_table_fn getTable, unsigned int cacheSize, unsigned int faceOptions) |
|
118 { |
|
119 const gr_face_ops ops = {sizeof(gr_face_ops), getTable, NULL}; |
|
120 return gr_make_face_with_seg_cache_and_ops(appFaceHandle, &ops, cacheSize, faceOptions); |
|
121 } |
|
122 #endif |
|
123 |
|
124 gr_uint32 gr_str_to_tag(const char *str) |
|
125 { |
|
126 uint32 res = 0; |
|
127 int i = strlen(str); |
|
128 if (i > 4) i = 4; |
|
129 while (--i >= 0) |
|
130 res = (res >> 8) + (str[i] << 24); |
|
131 return res; |
|
132 } |
|
133 |
|
134 void gr_tag_to_str(gr_uint32 tag, char *str) |
|
135 { |
|
136 int i = 4; |
|
137 while (--i >= 0) |
|
138 { |
|
139 str[i] = tag & 0xFF; |
|
140 tag >>= 8; |
|
141 } |
|
142 } |
|
143 |
|
144 inline |
|
145 uint32 zeropad(const uint32 x) |
|
146 { |
|
147 if (x == 0x20202020) return 0; |
|
148 if ((x & 0x00FFFFFF) == 0x00202020) return x & 0xFF000000; |
|
149 if ((x & 0x0000FFFF) == 0x00002020) return x & 0xFFFF0000; |
|
150 if ((x & 0x000000FF) == 0x00000020) return x & 0xFFFFFF00; |
|
151 return x; |
|
152 } |
|
153 |
|
154 gr_feature_val* gr_face_featureval_for_lang(const gr_face* pFace, gr_uint32 langname/*0 means clone default*/) //clones the features. if none for language, clones the default |
|
155 { |
|
156 assert(pFace); |
|
157 langname = zeropad(langname); |
|
158 return static_cast<gr_feature_val *>(pFace->theSill().cloneFeatures(langname)); |
|
159 } |
|
160 |
|
161 |
|
162 const gr_feature_ref* gr_face_find_fref(const gr_face* pFace, gr_uint32 featId) //When finished with the FeatureRef, call destroy_FeatureRef |
|
163 { |
|
164 assert(pFace); |
|
165 featId = zeropad(featId); |
|
166 const FeatureRef* pRef = pFace->featureById(featId); |
|
167 return static_cast<const gr_feature_ref*>(pRef); |
|
168 } |
|
169 |
|
170 unsigned short gr_face_n_fref(const gr_face* pFace) |
|
171 { |
|
172 assert(pFace); |
|
173 return pFace->numFeatures(); |
|
174 } |
|
175 |
|
176 const gr_feature_ref* gr_face_fref(const gr_face* pFace, gr_uint16 i) //When finished with the FeatureRef, call destroy_FeatureRef |
|
177 { |
|
178 assert(pFace); |
|
179 const FeatureRef* pRef = pFace->feature(i); |
|
180 return static_cast<const gr_feature_ref*>(pRef); |
|
181 } |
|
182 |
|
183 unsigned short gr_face_n_languages(const gr_face* pFace) |
|
184 { |
|
185 assert(pFace); |
|
186 return pFace->theSill().numLanguages(); |
|
187 } |
|
188 |
|
189 gr_uint32 gr_face_lang_by_index(const gr_face* pFace, gr_uint16 i) |
|
190 { |
|
191 assert(pFace); |
|
192 return pFace->theSill().getLangName(i); |
|
193 } |
|
194 |
|
195 |
|
196 void gr_face_destroy(gr_face *face) |
|
197 { |
|
198 delete face; |
|
199 } |
|
200 |
|
201 |
|
202 gr_uint16 gr_face_name_lang_for_locale(gr_face *face, const char * locale) |
|
203 { |
|
204 if (face) |
|
205 { |
|
206 return face->languageForLocale(locale); |
|
207 } |
|
208 return 0; |
|
209 } |
|
210 |
|
211 unsigned short gr_face_n_glyphs(const gr_face* pFace) |
|
212 { |
|
213 return pFace->glyphs().numGlyphs(); |
|
214 } |
|
215 |
|
216 const gr_faceinfo *gr_face_info(const gr_face *pFace, gr_uint32 script) |
|
217 { |
|
218 if (!pFace) return 0; |
|
219 const Silf *silf = pFace->chooseSilf(script); |
|
220 if (silf) return silf->silfInfo(); |
|
221 return 0; |
|
222 } |
|
223 |
|
224 int gr_face_is_char_supported(const gr_face* pFace, gr_uint32 usv, gr_uint32 script) |
|
225 { |
|
226 const Cmap & cmap = pFace->cmap(); |
|
227 gr_uint16 gid = cmap[usv]; |
|
228 if (!gid) |
|
229 { |
|
230 const Silf * silf = pFace->chooseSilf(script); |
|
231 gid = silf->findPseudo(usv); |
|
232 } |
|
233 return (gid != 0); |
|
234 } |
|
235 |
|
236 #ifndef GRAPHITE2_NFILEFACE |
|
237 gr_face* gr_make_file_face(const char *filename, unsigned int faceOptions) |
|
238 { |
|
239 FileFace* pFileFace = new FileFace(filename); |
|
240 if (*pFileFace) |
|
241 { |
|
242 gr_face* pRes = gr_make_face_with_ops(pFileFace, &FileFace::ops, faceOptions); |
|
243 if (pRes) |
|
244 { |
|
245 pRes->takeFileFace(pFileFace); //takes ownership |
|
246 return pRes; |
|
247 } |
|
248 } |
|
249 |
|
250 //error when loading |
|
251 |
|
252 delete pFileFace; |
|
253 return NULL; |
|
254 } |
|
255 |
|
256 #ifndef GRAPHITE2_NSEGCACHE |
|
257 gr_face* gr_make_file_face_with_seg_cache(const char* filename, unsigned int segCacheMaxSize, unsigned int faceOptions) //returns NULL on failure. //TBD better error handling |
|
258 //when finished with, call destroy_face |
|
259 { |
|
260 FileFace* pFileFace = new FileFace(filename); |
|
261 if (*pFileFace) |
|
262 { |
|
263 gr_face * pRes = gr_make_face_with_seg_cache_and_ops(pFileFace, &FileFace::ops, segCacheMaxSize, faceOptions); |
|
264 if (pRes) |
|
265 { |
|
266 pRes->takeFileFace(pFileFace); //takes ownership |
|
267 return pRes; |
|
268 } |
|
269 } |
|
270 |
|
271 //error when loading |
|
272 |
|
273 delete pFileFace; |
|
274 return NULL; |
|
275 } |
|
276 #endif |
|
277 #endif //!GRAPHITE2_NFILEFACE |
|
278 |
|
279 |
|
280 } // extern "C" |
|
281 |
|
282 |