Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
michael@0 | 1 | /* GRAPHITE2 LICENSING |
michael@0 | 2 | |
michael@0 | 3 | Copyright 2010, SIL International |
michael@0 | 4 | All rights reserved. |
michael@0 | 5 | |
michael@0 | 6 | This library is free software; you can redistribute it and/or modify |
michael@0 | 7 | it under the terms of the GNU Lesser General Public License as published |
michael@0 | 8 | by the Free Software Foundation; either version 2.1 of License, or |
michael@0 | 9 | (at your option) any later version. |
michael@0 | 10 | |
michael@0 | 11 | This program is distributed in the hope that it will be useful, |
michael@0 | 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
michael@0 | 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
michael@0 | 14 | Lesser General Public License for more details. |
michael@0 | 15 | |
michael@0 | 16 | You should also have received a copy of the GNU Lesser General Public |
michael@0 | 17 | License along with this library in the file named "LICENSE". |
michael@0 | 18 | If not, write to the Free Software Foundation, 51 Franklin Street, |
michael@0 | 19 | Suite 500, Boston, MA 02110-1335, USA or visit their web page on the |
michael@0 | 20 | internet at http://www.fsf.org/licenses/lgpl.html. |
michael@0 | 21 | |
michael@0 | 22 | Alternatively, the contents of this file may be used under the terms of the |
michael@0 | 23 | Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public |
michael@0 | 24 | License, as published by the Free Software Foundation, either version 2 |
michael@0 | 25 | of the License or (at your option) any later version. |
michael@0 | 26 | */ |
michael@0 | 27 | #include "graphite2/Font.h" |
michael@0 | 28 | #include "inc/Face.h" |
michael@0 | 29 | #include "inc/FileFace.h" |
michael@0 | 30 | #include "inc/GlyphCache.h" |
michael@0 | 31 | #include "inc/CachedFace.h" |
michael@0 | 32 | #include "inc/CmapCache.h" |
michael@0 | 33 | #include "inc/Silf.h" |
michael@0 | 34 | #include "inc/json.h" |
michael@0 | 35 | |
michael@0 | 36 | using namespace graphite2; |
michael@0 | 37 | |
michael@0 | 38 | #if !defined GRAPHITE2_NTRACING |
michael@0 | 39 | extern json *global_log; |
michael@0 | 40 | #endif |
michael@0 | 41 | |
michael@0 | 42 | namespace |
michael@0 | 43 | { |
michael@0 | 44 | bool load_face(Face & face, unsigned int options) |
michael@0 | 45 | { |
michael@0 | 46 | #ifdef GRAPHITE2_TELEMETRY |
michael@0 | 47 | telemetry::category _misc_cat(face.tele.misc); |
michael@0 | 48 | #endif |
michael@0 | 49 | Face::Table silf(face, Tag::Silf); |
michael@0 | 50 | if (silf) options &= ~gr_face_dumbRendering; |
michael@0 | 51 | else if (!(options & gr_face_dumbRendering)) |
michael@0 | 52 | return false; |
michael@0 | 53 | |
michael@0 | 54 | if (!face.readGlyphs(options)) |
michael@0 | 55 | return false; |
michael@0 | 56 | |
michael@0 | 57 | if (silf) |
michael@0 | 58 | { |
michael@0 | 59 | if (!face.readFeatures() || !face.readGraphite(silf)) |
michael@0 | 60 | { |
michael@0 | 61 | #if !defined GRAPHITE2_NTRACING |
michael@0 | 62 | if (global_log) |
michael@0 | 63 | { |
michael@0 | 64 | *global_log << json::object |
michael@0 | 65 | << "type" << "fontload" |
michael@0 | 66 | << "failure" << face.error() |
michael@0 | 67 | << "context" << face.error_context() |
michael@0 | 68 | << json::close; |
michael@0 | 69 | } |
michael@0 | 70 | #endif |
michael@0 | 71 | return false; |
michael@0 | 72 | } |
michael@0 | 73 | else |
michael@0 | 74 | return true; |
michael@0 | 75 | } |
michael@0 | 76 | else |
michael@0 | 77 | return options & gr_face_dumbRendering; |
michael@0 | 78 | } |
michael@0 | 79 | } |
michael@0 | 80 | |
michael@0 | 81 | extern "C" { |
michael@0 | 82 | |
michael@0 | 83 | gr_face* gr_make_face_with_ops(const void* appFaceHandle/*non-NULL*/, const gr_face_ops *ops, unsigned int faceOptions) |
michael@0 | 84 | //the appFaceHandle must stay alive all the time when the gr_face is alive. When finished with the gr_face, call destroy_face |
michael@0 | 85 | { |
michael@0 | 86 | if (ops == 0) return 0; |
michael@0 | 87 | |
michael@0 | 88 | Face *res = new Face(appFaceHandle, *ops); |
michael@0 | 89 | if (res && load_face(*res, faceOptions)) |
michael@0 | 90 | return static_cast<gr_face *>(res); |
michael@0 | 91 | |
michael@0 | 92 | delete res; |
michael@0 | 93 | return 0; |
michael@0 | 94 | } |
michael@0 | 95 | |
michael@0 | 96 | gr_face* gr_make_face(const void* appFaceHandle/*non-NULL*/, gr_get_table_fn tablefn, unsigned int faceOptions) |
michael@0 | 97 | { |
michael@0 | 98 | const gr_face_ops ops = {sizeof(gr_face_ops), tablefn, NULL}; |
michael@0 | 99 | return gr_make_face_with_ops(appFaceHandle, &ops, faceOptions); |
michael@0 | 100 | } |
michael@0 | 101 | |
michael@0 | 102 | #ifndef GRAPHITE2_NSEGCACHE |
michael@0 | 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) |
michael@0 | 104 | //the appFaceHandle must stay alive all the time when the GrFace is alive. When finished with the GrFace, call destroy_face |
michael@0 | 105 | { |
michael@0 | 106 | if (ops == 0) return 0; |
michael@0 | 107 | |
michael@0 | 108 | CachedFace *res = new CachedFace(appFaceHandle, *ops); |
michael@0 | 109 | if (res && load_face(*res, faceOptions) |
michael@0 | 110 | && res->setupCache(cacheSize)) |
michael@0 | 111 | return static_cast<gr_face *>(static_cast<Face *>(res)); |
michael@0 | 112 | |
michael@0 | 113 | delete res; |
michael@0 | 114 | return 0; |
michael@0 | 115 | } |
michael@0 | 116 | |
michael@0 | 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) |
michael@0 | 118 | { |
michael@0 | 119 | const gr_face_ops ops = {sizeof(gr_face_ops), getTable, NULL}; |
michael@0 | 120 | return gr_make_face_with_seg_cache_and_ops(appFaceHandle, &ops, cacheSize, faceOptions); |
michael@0 | 121 | } |
michael@0 | 122 | #endif |
michael@0 | 123 | |
michael@0 | 124 | gr_uint32 gr_str_to_tag(const char *str) |
michael@0 | 125 | { |
michael@0 | 126 | uint32 res = 0; |
michael@0 | 127 | int i = strlen(str); |
michael@0 | 128 | if (i > 4) i = 4; |
michael@0 | 129 | while (--i >= 0) |
michael@0 | 130 | res = (res >> 8) + (str[i] << 24); |
michael@0 | 131 | return res; |
michael@0 | 132 | } |
michael@0 | 133 | |
michael@0 | 134 | void gr_tag_to_str(gr_uint32 tag, char *str) |
michael@0 | 135 | { |
michael@0 | 136 | int i = 4; |
michael@0 | 137 | while (--i >= 0) |
michael@0 | 138 | { |
michael@0 | 139 | str[i] = tag & 0xFF; |
michael@0 | 140 | tag >>= 8; |
michael@0 | 141 | } |
michael@0 | 142 | } |
michael@0 | 143 | |
michael@0 | 144 | inline |
michael@0 | 145 | uint32 zeropad(const uint32 x) |
michael@0 | 146 | { |
michael@0 | 147 | if (x == 0x20202020) return 0; |
michael@0 | 148 | if ((x & 0x00FFFFFF) == 0x00202020) return x & 0xFF000000; |
michael@0 | 149 | if ((x & 0x0000FFFF) == 0x00002020) return x & 0xFFFF0000; |
michael@0 | 150 | if ((x & 0x000000FF) == 0x00000020) return x & 0xFFFFFF00; |
michael@0 | 151 | return x; |
michael@0 | 152 | } |
michael@0 | 153 | |
michael@0 | 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 |
michael@0 | 155 | { |
michael@0 | 156 | assert(pFace); |
michael@0 | 157 | langname = zeropad(langname); |
michael@0 | 158 | return static_cast<gr_feature_val *>(pFace->theSill().cloneFeatures(langname)); |
michael@0 | 159 | } |
michael@0 | 160 | |
michael@0 | 161 | |
michael@0 | 162 | const gr_feature_ref* gr_face_find_fref(const gr_face* pFace, gr_uint32 featId) //When finished with the FeatureRef, call destroy_FeatureRef |
michael@0 | 163 | { |
michael@0 | 164 | assert(pFace); |
michael@0 | 165 | featId = zeropad(featId); |
michael@0 | 166 | const FeatureRef* pRef = pFace->featureById(featId); |
michael@0 | 167 | return static_cast<const gr_feature_ref*>(pRef); |
michael@0 | 168 | } |
michael@0 | 169 | |
michael@0 | 170 | unsigned short gr_face_n_fref(const gr_face* pFace) |
michael@0 | 171 | { |
michael@0 | 172 | assert(pFace); |
michael@0 | 173 | return pFace->numFeatures(); |
michael@0 | 174 | } |
michael@0 | 175 | |
michael@0 | 176 | const gr_feature_ref* gr_face_fref(const gr_face* pFace, gr_uint16 i) //When finished with the FeatureRef, call destroy_FeatureRef |
michael@0 | 177 | { |
michael@0 | 178 | assert(pFace); |
michael@0 | 179 | const FeatureRef* pRef = pFace->feature(i); |
michael@0 | 180 | return static_cast<const gr_feature_ref*>(pRef); |
michael@0 | 181 | } |
michael@0 | 182 | |
michael@0 | 183 | unsigned short gr_face_n_languages(const gr_face* pFace) |
michael@0 | 184 | { |
michael@0 | 185 | assert(pFace); |
michael@0 | 186 | return pFace->theSill().numLanguages(); |
michael@0 | 187 | } |
michael@0 | 188 | |
michael@0 | 189 | gr_uint32 gr_face_lang_by_index(const gr_face* pFace, gr_uint16 i) |
michael@0 | 190 | { |
michael@0 | 191 | assert(pFace); |
michael@0 | 192 | return pFace->theSill().getLangName(i); |
michael@0 | 193 | } |
michael@0 | 194 | |
michael@0 | 195 | |
michael@0 | 196 | void gr_face_destroy(gr_face *face) |
michael@0 | 197 | { |
michael@0 | 198 | delete face; |
michael@0 | 199 | } |
michael@0 | 200 | |
michael@0 | 201 | |
michael@0 | 202 | gr_uint16 gr_face_name_lang_for_locale(gr_face *face, const char * locale) |
michael@0 | 203 | { |
michael@0 | 204 | if (face) |
michael@0 | 205 | { |
michael@0 | 206 | return face->languageForLocale(locale); |
michael@0 | 207 | } |
michael@0 | 208 | return 0; |
michael@0 | 209 | } |
michael@0 | 210 | |
michael@0 | 211 | unsigned short gr_face_n_glyphs(const gr_face* pFace) |
michael@0 | 212 | { |
michael@0 | 213 | return pFace->glyphs().numGlyphs(); |
michael@0 | 214 | } |
michael@0 | 215 | |
michael@0 | 216 | const gr_faceinfo *gr_face_info(const gr_face *pFace, gr_uint32 script) |
michael@0 | 217 | { |
michael@0 | 218 | if (!pFace) return 0; |
michael@0 | 219 | const Silf *silf = pFace->chooseSilf(script); |
michael@0 | 220 | if (silf) return silf->silfInfo(); |
michael@0 | 221 | return 0; |
michael@0 | 222 | } |
michael@0 | 223 | |
michael@0 | 224 | int gr_face_is_char_supported(const gr_face* pFace, gr_uint32 usv, gr_uint32 script) |
michael@0 | 225 | { |
michael@0 | 226 | const Cmap & cmap = pFace->cmap(); |
michael@0 | 227 | gr_uint16 gid = cmap[usv]; |
michael@0 | 228 | if (!gid) |
michael@0 | 229 | { |
michael@0 | 230 | const Silf * silf = pFace->chooseSilf(script); |
michael@0 | 231 | gid = silf->findPseudo(usv); |
michael@0 | 232 | } |
michael@0 | 233 | return (gid != 0); |
michael@0 | 234 | } |
michael@0 | 235 | |
michael@0 | 236 | #ifndef GRAPHITE2_NFILEFACE |
michael@0 | 237 | gr_face* gr_make_file_face(const char *filename, unsigned int faceOptions) |
michael@0 | 238 | { |
michael@0 | 239 | FileFace* pFileFace = new FileFace(filename); |
michael@0 | 240 | if (*pFileFace) |
michael@0 | 241 | { |
michael@0 | 242 | gr_face* pRes = gr_make_face_with_ops(pFileFace, &FileFace::ops, faceOptions); |
michael@0 | 243 | if (pRes) |
michael@0 | 244 | { |
michael@0 | 245 | pRes->takeFileFace(pFileFace); //takes ownership |
michael@0 | 246 | return pRes; |
michael@0 | 247 | } |
michael@0 | 248 | } |
michael@0 | 249 | |
michael@0 | 250 | //error when loading |
michael@0 | 251 | |
michael@0 | 252 | delete pFileFace; |
michael@0 | 253 | return NULL; |
michael@0 | 254 | } |
michael@0 | 255 | |
michael@0 | 256 | #ifndef GRAPHITE2_NSEGCACHE |
michael@0 | 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 |
michael@0 | 258 | //when finished with, call destroy_face |
michael@0 | 259 | { |
michael@0 | 260 | FileFace* pFileFace = new FileFace(filename); |
michael@0 | 261 | if (*pFileFace) |
michael@0 | 262 | { |
michael@0 | 263 | gr_face * pRes = gr_make_face_with_seg_cache_and_ops(pFileFace, &FileFace::ops, segCacheMaxSize, faceOptions); |
michael@0 | 264 | if (pRes) |
michael@0 | 265 | { |
michael@0 | 266 | pRes->takeFileFace(pFileFace); //takes ownership |
michael@0 | 267 | return pRes; |
michael@0 | 268 | } |
michael@0 | 269 | } |
michael@0 | 270 | |
michael@0 | 271 | //error when loading |
michael@0 | 272 | |
michael@0 | 273 | delete pFileFace; |
michael@0 | 274 | return NULL; |
michael@0 | 275 | } |
michael@0 | 276 | #endif |
michael@0 | 277 | #endif //!GRAPHITE2_NFILEFACE |
michael@0 | 278 | |
michael@0 | 279 | |
michael@0 | 280 | } // extern "C" |
michael@0 | 281 | |
michael@0 | 282 |