1 /* -*- c-basic-offset:2; tab-width:2; indent-tabs-mode:nil -*- */
2
3 #include <otf.h>
4 #include <pobl/bl_debug.h>
5 #include <pobl/bl_mem.h>
6 #ifdef USE_WIN32GUI
7 #include <windows.h>
8 #endif
9 #ifdef USE_BEOS
10 #include <fontconfig/fontconfig.h>
11 #endif
12
13 #if defined(USE_WIN32GUI) || defined(USE_QUARTZ) || defined(USE_BEOS)
14
15 static struct {
16 char *name;
17 OTF *otf;
18 u_int ref_count;
19
20 } *otfs;
21 static u_int num_otfs;
22
get_cached_otf(const char * name)23 static OTF *get_cached_otf(const char *name) {
24 u_int count;
25
26 for (count = 0; count < num_otfs; count++) {
27 if (strcmp(otfs[count].name, name) == 0) {
28 otfs[count].ref_count++;
29
30 return otfs[count].otf;
31 }
32 }
33
34 return NULL;
35 }
36
add_otf_to_cache(const char * name,OTF * otf)37 static void add_otf_to_cache(const char *name, OTF *otf) {
38 void *p;
39
40 if ((p = realloc(otfs, sizeof(*otfs) * (num_otfs + 1)))) {
41 otfs = p;
42 otfs[num_otfs].otf = otf;
43 otfs[num_otfs].name = strdup(name);
44 otfs[num_otfs++].ref_count = 1;
45 }
46 }
47
remove_otf_from_cache(OTF * otf)48 static void remove_otf_from_cache(OTF *otf) {
49 u_int count;
50
51 for (count = 0; count < num_otfs; count++) {
52 if (otfs[count].otf == otf) {
53 if (--otfs[count].ref_count == 0) {
54 free(otfs[count].name);
55 OTF_close(otfs[count].otf);
56 otfs[count] = otfs[--num_otfs];
57
58 return;
59 }
60 }
61 }
62 }
63
64 #if defined(USE_WIN32GUI)
65
66 #ifdef NO_DYNAMIC_LOAD_OTL
67 static
68 #endif
otl_open(void * obj)69 void *otl_open(void *obj) {
70 /* obj == HDC */
71
72 HDC hdc = obj;
73 HFONT hfont;
74 LOGFONTA logfont;
75 OTF* otf;
76 FT_Library ftlib;
77 u_char buf[4];
78 void *font_data;
79 u_int size;
80 int is_ttc;
81 FT_Face face;
82
83 if ((hfont = GetCurrentObject(hdc, OBJ_FONT)) == NULL ||
84 GetObjectA(hfont, sizeof(logfont), &logfont) == 0) {
85 return NULL;
86 }
87
88 if ((otf = get_cached_otf(logfont.lfFaceName))) {
89 return otf;
90 }
91
92 #define TTC_TAG ('t' << 0) + ('t' << 8) + ('c' << 16) + ('f' << 24)
93
94 if (GetFontData(hdc, TTC_TAG, 0, &buf, 1) == 1) {
95 is_ttc = 1;
96 size = GetFontData(hdc, TTC_TAG, 0, NULL, 0);
97 } else {
98 is_ttc = 0;
99 size = GetFontData(hdc, 0, 0, NULL, 0);
100 }
101
102 if (!(font_data = malloc(size))) {
103 return NULL;
104 }
105
106 if (is_ttc) {
107 GetFontData(hdc, TTC_TAG, 0, font_data, size);
108 } else {
109 GetFontData(hdc, 0, 0, font_data, size);
110 }
111
112 if (FT_Init_FreeType(&ftlib) != 0) {
113 free(font_data);
114
115 return NULL;
116 }
117
118 if (FT_New_Memory_Face(ftlib, font_data, size, 0, &face) != 0) {
119 otf = NULL;
120 } else {
121 if ((otf = OTF_open_ft_face(face))) {
122 if (OTF_get_table(otf, "GSUB") != 0 || OTF_get_table(otf, "cmap") != 0) {
123 OTF_close(otf);
124 otf = NULL;
125 } else {
126 add_otf_to_cache(logfont.lfFaceName, otf);
127 }
128 }
129
130 FT_Done_Face(face);
131 }
132
133 free(font_data);
134 FT_Done_FreeType(ftlib);
135
136 return otf;
137 }
138
139 #elif defined(USE_QUARTZ)
140
141 #ifdef NO_DYNAMIC_LOAD_OTL
142 static
143 #endif
otl_open(void * obj)144 void *otl_open(void *obj) {
145 /* obj == string (Font path) */
146
147 OTF* otf;
148
149 if ((otf = get_cached_otf(obj))) {
150 return otf;
151 }
152
153 if ((otf = OTF_open(obj))) {
154 if (OTF_check_table(otf, "GSUB") != 0 || OTF_check_table(otf, "cmap") != 0) {
155 OTF_close(otf);
156 otf = NULL;
157 }
158 }
159
160 if (otf) {
161 add_otf_to_cache(obj, otf);
162 }
163
164 return otf;
165 }
166
167 #else /* USE_BEOS */
168
169 #ifdef NO_DYNAMIC_LOAD_OTL
170 static
171 #endif
otl_open(void * obj)172 void *otl_open(void *obj) {
173 /* obj == string (Font Family) */
174
175 char *family = obj;
176 OTF *otf;
177 FT_Library ftlib;
178 FcPattern *pattern;
179 FcPattern *match;
180 FcResult result;
181 FcValue val;
182 FT_Face face;
183
184 if ((otf = get_cached_otf(family))) {
185 return otf;
186 }
187
188 if (FT_Init_FreeType(&ftlib) != 0) {
189 return NULL;
190 }
191
192 if ((pattern = FcPatternCreate()) == NULL) {
193 return NULL;
194 }
195
196 FcPatternAddString(pattern, FC_FAMILY, family);
197 match = FcFontMatch(NULL, pattern, &result);
198 FcPatternDestroy(pattern);
199
200 if (match == NULL) {
201 return NULL;
202 }
203
204 FcPatternGet(match, FC_FILE, 0, &val);
205 if (FT_New_Face(ftlib, val.u.s, 0, &face)) {
206 otf = NULL;
207 } else {
208 if ((otf = OTF_open_ft_face(face))) {
209 if (OTF_get_table(otf, "GSUB") != 0 || OTF_get_table(otf, "cmap") != 0) {
210 OTF_close(otf);
211 otf = NULL;
212 } else {
213 add_otf_to_cache(family, otf);
214 }
215 }
216
217 FT_Done_Face(face);
218 }
219
220 FcPatternDestroy(match);
221 FT_Done_FreeType(ftlib);
222
223 return otf;
224 }
225
226 #endif
227
228 #else /* USE_XLIB, USE_FRAMEBUFFER, USE_SDL2, USE_WAYLAND */
229
230 static struct {
231 FT_Face face;
232 OTF *otf;
233 u_int ref_count;
234
235 } *otfs;
236 static u_int num_otfs;
237
get_cached_otf(FT_Face face)238 static OTF *get_cached_otf(FT_Face face) {
239 u_int count;
240
241 for (count = 0; count < num_otfs; count++) {
242 if (otfs[count].face == face) {
243 otfs[count].ref_count++;
244
245 return otfs[count].otf;
246 }
247 }
248
249 return NULL;
250 }
251
add_otf_to_cache(FT_Face face,OTF * otf)252 static void add_otf_to_cache(FT_Face face, OTF *otf) {
253 void *p;
254
255 if ((p = realloc(otfs, sizeof(*otfs) * (num_otfs + 1)))) {
256 otfs = p;
257 otfs[num_otfs].otf = otf;
258 otfs[num_otfs].face = face;
259 otfs[num_otfs++].ref_count = 1;
260 }
261 }
262
remove_otf_from_cache(OTF * otf)263 static void remove_otf_from_cache(OTF *otf) {
264 u_int count;
265
266 for (count = 0; count < num_otfs; count++) {
267 if (otfs[count].otf == otf) {
268 if (--otfs[count].ref_count == 0) {
269 OTF_close(otfs[count].otf);
270 otfs[count] = otfs[--num_otfs];
271
272 return;
273 }
274 }
275 }
276 }
277
278 #ifdef NO_DYNAMIC_LOAD_OTL
279 static
280 #endif
otl_open(void * obj)281 void *otl_open(void *obj) {
282 /* obj == FT_Face */
283
284 OTF* otf;
285
286 if ((otf = get_cached_otf(obj))) {
287 return otf;
288 }
289
290 if ((otf = OTF_open_ft_face(obj))) {
291 if (OTF_check_table(otf, "GSUB") != 0 || OTF_check_table(otf, "cmap") != 0) {
292 OTF_close(otf);
293 otf = NULL;
294 }
295 }
296
297 add_otf_to_cache(obj, otf);
298
299 return otf;
300 }
301
302 #endif
303
304 #ifdef NO_DYNAMIC_LOAD_OTL
305 static
306 #endif
otl_close(void * otf)307 void otl_close(void *otf) {
308 remove_otf_from_cache(otf);
309 }
310
311 /*
312 * shape_glyphs != NULL && noshape_glyphs != NULL && src != NULL:
313 * noshape_glyphs -> shape_glyphs (called from vt_ot_layout.c)
314 * shape_glyphs == NULL: src -> noshape_glyphs (called from vt_ot_layout.c)
315 * cmaped == NULL: src -> shape_glyphs (Not used for now)
316 *
317 * num_shape_glyphs should be greater than src_len.
318 */
319 #ifdef NO_DYNAMIC_LOAD_OTL
320 static
321 #endif
otl_convert_text_to_glyphs(void * otf,u_int32_t * shape_glyphs,u_int num_shape_glyphs,int8_t * xoffsets,int8_t * yoffsets,u_int8_t * advances,u_int32_t * noshape_glyphs,u_int32_t * src,u_int src_len,const char * script,const char * features,u_int fontsize)322 u_int otl_convert_text_to_glyphs(void *otf, u_int32_t *shape_glyphs, u_int num_shape_glyphs,
323 int8_t *xoffsets, int8_t *yoffsets, u_int8_t *advances,
324 u_int32_t *noshape_glyphs, u_int32_t *src, u_int src_len,
325 const char *script, const char *features, u_int fontsize) {
326 static OTF_Glyph *glyphs;
327 OTF_GlyphString otfstr;
328 u_int count;
329
330 otfstr.size = otfstr.used = src_len;
331
332 /* Avoid bl_mem memory management */
333 #undef realloc
334 if (!(otfstr.glyphs = realloc(glyphs, otfstr.size * sizeof(*otfstr.glyphs)))) {
335 return 0;
336 }
337 #ifdef BL_DEBUG
338 #define realloc(ptr, size) bl_mem_realloc(ptr, size, __FILE__, __LINE__, __FUNCTION__)
339 #endif
340
341 glyphs = otfstr.glyphs;
342 memset(otfstr.glyphs, 0, otfstr.size * sizeof(*otfstr.glyphs));
343
344 if (shape_glyphs == NULL || noshape_glyphs == NULL) {
345 for (count = 0; count < src_len; count++) {
346 otfstr.glyphs[count].c = src[count];
347 }
348
349 OTF_drive_cmap(otf, &otfstr);
350
351 if (shape_glyphs == NULL) {
352 for (count = 0; count < otfstr.used; count++) {
353 noshape_glyphs[count] = otfstr.glyphs[count].glyph_id;
354 }
355
356 return otfstr.used;
357 }
358 } else {
359 for (count = 0; count < src_len; count++) {
360 otfstr.glyphs[count].glyph_id = noshape_glyphs[count];
361 }
362 }
363
364 OTF_drive_gdef(otf, &otfstr);
365 OTF_drive_gsub(otf, &otfstr, script, NULL, features);
366
367 if (otfstr.used > num_shape_glyphs) {
368 otfstr.used = num_shape_glyphs;
369 }
370
371 if (xoffsets /* && yoffsets && advances */) {
372 #if 0
373 OTF_drive_gpos2(otf, &otfstr, script, NULL, features);
374
375 for (count = 0; count < otfstr.used; count++) {
376 bl_debug_printf("glyph %x: pos type %d ", src[count], otfstr.glyphs[count].glyph_id,
377 otfstr.glyphs[count].positioning_type);
378 switch(otfstr.glyphs[count].positioning_type) {
379 case 0:
380 bl_msg_printf("from %d to %d", otfstr.glyphs[count].f.index.from,
381 otfstr.glyphs[count].f.index.to);
382 break;
383 case 1:
384 case 2:
385 bl_msg_printf("x %d y %d a %d", otfstr.glyphs[count].f.f1.value->XPlacement,
386 otfstr.glyphs[count].f.f1.value->YPlacement,
387 otfstr.glyphs[count].f.f1.value->XAdvance);
388 break;
389 }
390 bl_msg_printf("\n");
391 }
392 #endif
393
394 memset(xoffsets, 0, num_shape_glyphs * sizeof(*xoffsets));
395 memset(yoffsets, 0, num_shape_glyphs * sizeof(*yoffsets));
396 /* 0xff: dummy code which gets OTL_IS_COMB() to be false */
397 memset(advances, 0xff, num_shape_glyphs * sizeof(*advances));
398 }
399
400 for (count = 0; count < otfstr.used; count++) {
401 shape_glyphs[count] = otfstr.glyphs[count].glyph_id;
402 }
403
404 return otfstr.used;
405 }
406