1// SPDX-License-Identifier: MIT OR MPL-2.0 OR LGPL-2.1-or-later OR GPL-2.0-or-later
2// Copyright 2010, SIL International, All rights reserved.
3
4#include "graphite2/Font.h"
5#include "inc/Face.h"
6#include "inc/FileFace.h"
7#include "inc/GlyphCache.h"
8#include "inc/CmapCache.h"
9#include "inc/Silf.h"
10#include "inc/json.h"
11
12using namespace graphite2;
13
14#if !defined GRAPHITE2_NTRACING
15extern json *global_log;
16#endif
17
18namespace
19{
20 bool load_face(Face & face, unsigned int options)
21 {
22#ifdef GRAPHITE2_TELEMETRY
23 telemetry::category _misc_cat(face.tele.misc);
24#endif
25 Face::Table silf(face, Tag::Silf, 0x00050000);
26 if (!silf)
27 return false;
28
29 if (!face.readGlyphs(options))
30 return false;
31
32 if (silf)
33 {
34 if (!face.readFeatures() || !face.readGraphite(silf))
35 {
36#if !defined GRAPHITE2_NTRACING
37 if (global_log)
38 {
39 *global_log << json::object
40 << "type" << "fontload"
41 << "failure" << face.error()
42 << "context" << face.error_context()
43 << json::close;
44 }
45#endif
46 return false;
47 }
48 else
49 return true;
50 }
51 else
52 return false;
53 }
54
55 inline
56 uint32 zeropad(const uint32 x)
57 {
58 if (x == 0x20202020) return 0;
59 if ((x & 0x00FFFFFF) == 0x00202020) return x & 0xFF000000;
60 if ((x & 0x0000FFFF) == 0x00002020) return x & 0xFFFF0000;
61 if ((x & 0x000000FF) == 0x00000020) return x & 0xFFFFFF00;
62 return x;
63 }
64}
65
66extern "C" {
67
68gr_face* gr_make_face_with_ops(const void* appFaceHandle/*non-NULL*/, const gr_face_ops *ops, unsigned int faceOptions)
69 //the appFaceHandle must stay alive all the time when the gr_face is alive. When finished with the gr_face, call destroy_face
70{
71 if (ops == 0) return 0;
72
73 Face *res = new Face(appFaceHandle, *ops);
74 if (res && load_face(*res, faceOptions))
75 return static_cast<gr_face *>(res);
76
77 delete res;
78 return 0;
79}
80
81gr_face* gr_make_face(const void* appFaceHandle/*non-NULL*/, gr_get_table_fn tablefn, unsigned int faceOptions)
82{
83 const gr_face_ops ops = {sizeof(gr_face_ops), tablefn, NULL};
84 return gr_make_face_with_ops(appFaceHandle, &ops, faceOptions);
85}
86
87
88gr_face* gr_make_face_with_seg_cache_and_ops(const void* appFaceHandle/*non-NULL*/, const gr_face_ops *ops, unsigned int , unsigned int faceOptions)
89{
90 return gr_make_face_with_ops(appFaceHandle, ops, faceOptions);
91}
92
93gr_face* gr_make_face_with_seg_cache(const void* appFaceHandle/*non-NULL*/, gr_get_table_fn tablefn, unsigned int, unsigned int faceOptions)
94{
95 const gr_face_ops ops = {sizeof(gr_face_ops), tablefn, NULL};
96 return gr_make_face_with_ops(appFaceHandle, &ops, faceOptions);
97}
98
99gr_uint32 gr_str_to_tag(const char *str)
100{
101 uint32 res = 0;
102 switch(max(strlen(str),size_t(4)))
103 {
104 case 4: res |= str[3]; GR_FALLTHROUGH;
105 case 3: res |= str[2] << 8; GR_FALLTHROUGH;
106 case 2: res |= str[1] << 16; GR_FALLTHROUGH;
107 case 1: res |= str[0] << 24; GR_FALLTHROUGH;
108 default: break;
109 }
110 return res;
111}
112
113void gr_tag_to_str(gr_uint32 tag, char *str)
114{
115 if (!str) return;
116
117 *str++ = char(tag >> 24);
118 *str++ = char(tag >> 16);
119 *str++ = char(tag >> 8);
120 *str++ = char(tag);
121 *str = '\0';
122}
123
124gr_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
125{
126 assert(pFace);
127 langname = zeropad(langname);
128 return static_cast<gr_feature_val *>(pFace->theSill().cloneFeatures(langname));
129}
130
131
132const gr_feature_ref* gr_face_find_fref(const gr_face* pFace, gr_uint32 featId) //When finished with the FeatureRef, call destroy_FeatureRef
133{
134 assert(pFace);
135 featId = zeropad(featId);
136 const FeatureRef* pRef = pFace->featureById(featId);
137 return static_cast<const gr_feature_ref*>(pRef);
138}
139
140unsigned short gr_face_n_fref(const gr_face* pFace)
141{
142 assert(pFace);
143 int res = 0;
144 for (int i = 0; i < pFace->numFeatures(); ++i)
145 if (!(pFace->feature(i)->getFlags() & FeatureRef::HIDDEN))
146 ++res;
147 return res;
148}
149
150const gr_feature_ref* gr_face_fref(const gr_face* pFace, gr_uint16 i) //When finished with the FeatureRef, call destroy_FeatureRef
151{
152 assert(pFace);
153 int count = 0;
154 for (int j = 0; j < pFace->numFeatures(); ++j)
155 {
156 const FeatureRef* pRef = pFace->feature(j);
157 if (!(pRef->getFlags() & FeatureRef::HIDDEN))
158 if (count++ == i)
159 return static_cast<const gr_feature_ref*>(pRef);
160 }
161 return 0;
162}
163
164unsigned short gr_face_n_languages(const gr_face* pFace)
165{
166 assert(pFace);
167 return pFace->theSill().numLanguages();
168}
169
170gr_uint32 gr_face_lang_by_index(const gr_face* pFace, gr_uint16 i)
171{
172 assert(pFace);
173 return pFace->theSill().getLangName(i);
174}
175
176
177void gr_face_destroy(gr_face *face)
178{
179 delete static_cast<Face*>(face);
180}
181
182
183gr_uint16 gr_face_name_lang_for_locale(gr_face *face, const char * locale)
184{
185 if (face)
186 {
187 return face->languageForLocale(locale);
188 }
189 return 0;
190}
191
192unsigned short gr_face_n_glyphs(const gr_face* pFace)
193{
194 return pFace->glyphs().numGlyphs();
195}
196
197const gr_faceinfo *gr_face_info(const gr_face *pFace, gr_uint32 script)
198{
199 if (!pFace) return 0;
200 const Silf *silf = pFace->chooseSilf(script);
201 if (silf) return silf->silfInfo();
202 return 0;
203}
204
205int gr_face_is_char_supported(const gr_face* pFace, gr_uint32 usv, gr_uint32 script)
206{
207 const Cmap & cmap = pFace->cmap();
208 gr_uint16 gid = cmap[usv];
209 if (!gid)
210 {
211 const Silf * silf = pFace->chooseSilf(script);
212 gid = silf->findPseudo(usv);
213 }
214 return (gid != 0);
215}
216
217#ifndef GRAPHITE2_NFILEFACE
218gr_face* gr_make_file_face(const char *filename, unsigned int faceOptions)
219{
220 FileFace* pFileFace = new FileFace(filename);
221 if (*pFileFace)
222 {
223 gr_face* pRes = gr_make_face_with_ops(pFileFace, &FileFace::ops, faceOptions);
224 if (pRes)
225 {
226 pRes->takeFileFace(pFileFace); //takes ownership
227 return pRes;
228 }
229 }
230
231 //error when loading
232
233 delete pFileFace;
234 return NULL;
235}
236
237gr_face* gr_make_file_face_with_seg_cache(const char* filename, unsigned int, unsigned int faceOptions) //returns NULL on failure. //TBD better error handling
238 //when finished with, call destroy_face
239{
240 return gr_make_file_face(filename, faceOptions);
241}
242#endif //!GRAPHITE2_NFILEFACE
243
244} // extern "C"
245