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