/src/harfbuzz/src/hb-ot-font.cc
Line | Count | Source |
1 | | /* |
2 | | * Copyright © 2011,2014 Google, Inc. |
3 | | * |
4 | | * This is part of HarfBuzz, a text shaping library. |
5 | | * |
6 | | * Permission is hereby granted, without written agreement and without |
7 | | * license or royalty fees, to use, copy, modify, and distribute this |
8 | | * software and its documentation for any purpose, provided that the |
9 | | * above copyright notice and the following two paragraphs appear in |
10 | | * all copies of this software. |
11 | | * |
12 | | * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR |
13 | | * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES |
14 | | * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN |
15 | | * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH |
16 | | * DAMAGE. |
17 | | * |
18 | | * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, |
19 | | * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND |
20 | | * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS |
21 | | * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO |
22 | | * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. |
23 | | * |
24 | | * Google Author(s): Behdad Esfahbod, Roozbeh Pournader |
25 | | */ |
26 | | |
27 | | #include "hb.hh" |
28 | | |
29 | | #ifndef HB_NO_OT_FONT |
30 | | |
31 | | #include "hb-ot.h" |
32 | | |
33 | | #include "hb-cache.hh" |
34 | | #include "hb-font.hh" |
35 | | #include "hb-machinery.hh" |
36 | | #include "hb-ot-face.hh" |
37 | | |
38 | | #include "hb-ot-cmap-table.hh" |
39 | | #include "hb-ot-glyf-table.hh" |
40 | | #include "hb-ot-var-gvar-table.hh" |
41 | | #include "hb-ot-cff2-table.hh" |
42 | | #include "hb-ot-cff1-table.hh" |
43 | | #include "hb-ot-hmtx-table.hh" |
44 | | #include "hb-ot-post-table.hh" |
45 | | #include "hb-ot-stat-table.hh" |
46 | | #include "hb-ot-var-varc-table.hh" |
47 | | #include "hb-ot-vorg-table.hh" |
48 | | #include "OT/Color/CBDT/CBDT.hh" |
49 | | #include "OT/Color/COLR/COLR.hh" |
50 | | #include "OT/Color/sbix/sbix.hh" |
51 | | #include "OT/Color/svg/svg.hh" |
52 | | |
53 | | |
54 | | /** |
55 | | * SECTION:hb-ot-font |
56 | | * @title: hb-ot-font |
57 | | * @short_description: OpenType font implementation |
58 | | * @include: hb-ot.h |
59 | | * |
60 | | * Functions for using OpenType fonts with hb_shape(). Note that fonts returned |
61 | | * by hb_font_create() default to using these functions, so most clients would |
62 | | * never need to call these functions directly. |
63 | | **/ |
64 | | |
65 | | using hb_ot_font_advance_cache_t = hb_cache_t<24, 16>; |
66 | | static_assert (sizeof (hb_ot_font_advance_cache_t) == 1024, ""); |
67 | | |
68 | | using hb_ot_font_origin_cache_t = hb_cache_t<20, 20>; |
69 | | static_assert (sizeof (hb_ot_font_origin_cache_t) == 1024, ""); |
70 | | |
71 | | struct hb_ot_font_t |
72 | | { |
73 | | const hb_ot_face_t *ot_face; |
74 | | |
75 | | mutable hb_atomic_t<int> cached_serial; |
76 | | mutable hb_atomic_t<int> cached_coords_serial; |
77 | | |
78 | | struct direction_cache_t |
79 | | { |
80 | | mutable hb_atomic_t<hb_ot_font_advance_cache_t *> advance_cache; |
81 | | mutable hb_atomic_t<OT::hb_scalar_cache_t *> varStore_cache; |
82 | | |
83 | | ~direction_cache_t () |
84 | 85.5k | { |
85 | 85.5k | clear (); |
86 | 85.5k | } |
87 | | |
88 | | hb_ot_font_advance_cache_t *acquire_advance_cache () const |
89 | 6.54k | { |
90 | 6.54k | retry: |
91 | 6.54k | auto *cache = advance_cache.get_acquire (); |
92 | 6.54k | if (!cache) |
93 | 1.39k | { |
94 | 1.39k | cache = (hb_ot_font_advance_cache_t *) hb_malloc (sizeof (hb_ot_font_advance_cache_t)); |
95 | 1.39k | if (!cache) |
96 | 86 | return nullptr; |
97 | 1.30k | new (cache) hb_ot_font_advance_cache_t; |
98 | 1.30k | return cache; |
99 | 1.39k | } |
100 | 5.15k | if (advance_cache.cmpexch (cache, nullptr)) |
101 | 5.15k | return cache; |
102 | 0 | else |
103 | 0 | goto retry; |
104 | 5.15k | } |
105 | | void release_advance_cache (hb_ot_font_advance_cache_t *cache) const |
106 | 6.45k | { |
107 | 6.45k | if (!cache) |
108 | 0 | return; |
109 | 6.45k | if (!advance_cache.cmpexch (nullptr, cache)) |
110 | 0 | hb_free (cache); |
111 | 6.45k | } |
112 | | void clear_advance_cache () const |
113 | 91.1k | { |
114 | 91.1k | retry: |
115 | 91.1k | auto *cache = advance_cache.get_acquire (); |
116 | 91.1k | if (!cache) |
117 | 89.8k | return; |
118 | 1.30k | if (advance_cache.cmpexch (cache, nullptr)) |
119 | 1.30k | hb_free (cache); |
120 | 0 | else |
121 | 0 | goto retry; |
122 | 1.30k | } |
123 | | |
124 | | OT::hb_scalar_cache_t *acquire_varStore_cache (const OT::ItemVariationStore &varStore) const |
125 | 945 | { |
126 | 945 | retry: |
127 | 945 | auto *cache = varStore_cache.get_acquire (); |
128 | 945 | if (!cache) |
129 | 221 | return varStore.create_cache (); |
130 | 724 | if (varStore_cache.cmpexch (cache, nullptr)) |
131 | 724 | return cache; |
132 | 0 | else |
133 | 0 | goto retry; |
134 | 724 | } |
135 | | void release_varStore_cache (OT::hb_scalar_cache_t *cache) const |
136 | 945 | { |
137 | 945 | if (!cache) |
138 | 0 | return; |
139 | 945 | if (!varStore_cache.cmpexch (nullptr, cache)) |
140 | 0 | OT::ItemVariationStore::destroy_cache (cache); |
141 | 945 | } |
142 | | void clear_varStore_cache () const |
143 | 91.1k | { |
144 | 91.1k | retry: |
145 | 91.1k | auto *cache = varStore_cache.get_acquire (); |
146 | 91.1k | if (!cache) |
147 | 90.8k | return; |
148 | 221 | if (varStore_cache.cmpexch (cache, nullptr)) |
149 | 221 | OT::ItemVariationStore::destroy_cache (cache); |
150 | 0 | else |
151 | 0 | goto retry; |
152 | 221 | } |
153 | | |
154 | | void clear () const |
155 | 91.1k | { |
156 | 91.1k | clear_advance_cache (); |
157 | 91.1k | clear_varStore_cache (); |
158 | 91.1k | } |
159 | | |
160 | | } h, v; |
161 | | |
162 | | struct origin_cache_t |
163 | | { |
164 | | mutable hb_atomic_t<hb_ot_font_origin_cache_t *> origin_cache; |
165 | | mutable hb_atomic_t<OT::hb_scalar_cache_t *> varStore_cache; |
166 | | |
167 | | ~origin_cache_t () |
168 | 42.7k | { |
169 | 42.7k | clear (); |
170 | 42.7k | } |
171 | | |
172 | | hb_ot_font_origin_cache_t *acquire_origin_cache () const |
173 | 42.7k | { |
174 | 42.7k | retry: |
175 | 42.7k | auto *cache = origin_cache.get_acquire (); |
176 | 42.7k | if (!cache) |
177 | 42.7k | { |
178 | 42.7k | cache = (hb_ot_font_origin_cache_t *) hb_malloc (sizeof (hb_ot_font_origin_cache_t)); |
179 | 42.7k | if (!cache) |
180 | 528 | return nullptr; |
181 | 42.2k | new (cache) hb_ot_font_origin_cache_t; |
182 | 42.2k | return cache; |
183 | 42.7k | } |
184 | 0 | if (origin_cache.cmpexch (cache, nullptr)) |
185 | 0 | return cache; |
186 | 0 | else |
187 | 0 | goto retry; |
188 | 0 | } |
189 | | void release_origin_cache (hb_ot_font_origin_cache_t *cache) const |
190 | 42.7k | { |
191 | 42.7k | if (!cache) |
192 | 528 | return; |
193 | 42.2k | if (!origin_cache.cmpexch (nullptr, cache)) |
194 | 0 | hb_free (cache); |
195 | 42.2k | } |
196 | | void clear_origin_cache () const |
197 | 45.5k | { |
198 | 45.5k | retry: |
199 | 45.5k | auto *cache = origin_cache.get_acquire (); |
200 | 45.5k | if (!cache) |
201 | 3.29k | return; |
202 | 42.2k | if (origin_cache.cmpexch (cache, nullptr)) |
203 | 42.2k | hb_free (cache); |
204 | 0 | else |
205 | 0 | goto retry; |
206 | 42.2k | } |
207 | | |
208 | | OT::hb_scalar_cache_t *acquire_varStore_cache (const OT::ItemVariationStore &varStore) const |
209 | 91 | { |
210 | 91 | retry: |
211 | 91 | auto *cache = varStore_cache.get_acquire (); |
212 | 91 | if (!cache) |
213 | 91 | return varStore.create_cache (); |
214 | 0 | if (varStore_cache.cmpexch (cache, nullptr)) |
215 | 0 | return cache; |
216 | 0 | else |
217 | 0 | goto retry; |
218 | 0 | } |
219 | | void release_varStore_cache (OT::hb_scalar_cache_t *cache) const |
220 | 91 | { |
221 | 91 | if (!cache) |
222 | 0 | return; |
223 | 91 | if (!varStore_cache.cmpexch (nullptr, cache)) |
224 | 0 | OT::ItemVariationStore::destroy_cache (cache); |
225 | 91 | } |
226 | | void clear_varStore_cache () const |
227 | 45.5k | { |
228 | 45.5k | retry: |
229 | 45.5k | auto *cache = varStore_cache.get_acquire (); |
230 | 45.5k | if (!cache) |
231 | 45.4k | return; |
232 | 91 | if (varStore_cache.cmpexch (cache, nullptr)) |
233 | 91 | OT::ItemVariationStore::destroy_cache (cache); |
234 | 0 | else |
235 | 0 | goto retry; |
236 | 91 | } |
237 | | |
238 | | void clear () const |
239 | 45.5k | { |
240 | 45.5k | clear_origin_cache (); |
241 | 45.5k | clear_varStore_cache (); |
242 | 45.5k | } |
243 | | } v_origin; |
244 | | |
245 | | struct draw_cache_t |
246 | | { |
247 | | mutable hb_atomic_t<OT::hb_scalar_cache_t *> gvar_cache; |
248 | | |
249 | | ~draw_cache_t () |
250 | 42.7k | { |
251 | 42.7k | clear (); |
252 | 42.7k | } |
253 | | |
254 | | OT::hb_scalar_cache_t *acquire_gvar_cache (const OT::gvar_accelerator_t &gvar) const |
255 | 18.2k | { |
256 | 18.2k | retry: |
257 | 18.2k | auto *cache = gvar_cache.get_acquire (); |
258 | 18.2k | if (!cache) |
259 | 2.76k | return gvar.create_cache (); |
260 | 15.5k | if (gvar_cache.cmpexch (cache, nullptr)) |
261 | 15.5k | return cache; |
262 | 0 | else |
263 | 0 | goto retry; |
264 | 15.5k | } |
265 | | void release_gvar_cache (OT::hb_scalar_cache_t *cache) const |
266 | 742k | { |
267 | 742k | if (!cache) |
268 | 724k | return; |
269 | 18.2k | if (!gvar_cache.cmpexch (nullptr, cache)) |
270 | 0 | OT::gvar_accelerator_t::destroy_cache (cache); |
271 | 18.2k | } |
272 | | void clear_gvar_cache () const |
273 | 45.5k | { |
274 | 45.5k | retry: |
275 | 45.5k | auto *cache = gvar_cache.get_acquire (); |
276 | 45.5k | if (!cache) |
277 | 42.7k | return; |
278 | 2.76k | if (gvar_cache.cmpexch (cache, nullptr)) |
279 | 2.76k | OT::gvar_accelerator_t::destroy_cache (cache); |
280 | 0 | else |
281 | 0 | goto retry; |
282 | 2.76k | } |
283 | | |
284 | | void clear () const |
285 | 45.5k | { |
286 | 45.5k | clear_gvar_cache (); |
287 | 45.5k | } |
288 | | } draw; |
289 | | |
290 | | void check_serial (hb_font_t *font) const |
291 | 21.5k | { |
292 | 21.5k | int font_serial = font->serial_coords.get_acquire (); |
293 | 21.5k | if (cached_serial.get_acquire () != font_serial) |
294 | 2.76k | { |
295 | | /* These caches are dependent on scale and synthetic settings. |
296 | | * Any change to the font invalidates them. */ |
297 | 2.76k | v_origin.clear (); |
298 | | |
299 | 2.76k | cached_serial.set_release (font_serial); |
300 | 2.76k | } |
301 | | |
302 | 21.5k | int font_serial_coords = font->serial_coords.get_acquire (); |
303 | 21.5k | if (cached_coords_serial.get_acquire () != font_serial_coords) |
304 | 2.76k | { |
305 | | /* These caches are independent of scale or synthetic settings. |
306 | | * Just variation changes will invalidate them. */ |
307 | 2.76k | h.clear (); |
308 | 2.76k | v.clear (); |
309 | 2.76k | draw.clear (); |
310 | | |
311 | 2.76k | cached_coords_serial.set_release (font_serial_coords); |
312 | 2.76k | } |
313 | 21.5k | } |
314 | | }; |
315 | | |
316 | | static hb_ot_font_t * |
317 | | _hb_ot_font_create (hb_font_t *font) |
318 | 43.3k | { |
319 | 43.3k | hb_ot_font_t *ot_font = (hb_ot_font_t *) hb_calloc (1, sizeof (hb_ot_font_t)); |
320 | 43.3k | if (unlikely (!ot_font)) |
321 | 578 | return nullptr; |
322 | | |
323 | 42.7k | ot_font->ot_face = &font->face->table; |
324 | | |
325 | 42.7k | return ot_font; |
326 | 43.3k | } |
327 | | |
328 | | static void |
329 | | _hb_ot_font_destroy (void *font_data) |
330 | 42.7k | { |
331 | 42.7k | hb_ot_font_t *ot_font = (hb_ot_font_t *) font_data; |
332 | | |
333 | 42.7k | ot_font->~hb_ot_font_t (); |
334 | | |
335 | 42.7k | hb_free (ot_font); |
336 | 42.7k | } |
337 | | |
338 | | static hb_bool_t |
339 | | hb_ot_get_nominal_glyph (hb_font_t *font HB_UNUSED, |
340 | | void *font_data, |
341 | | hb_codepoint_t unicode, |
342 | | hb_codepoint_t *glyph, |
343 | | void *user_data HB_UNUSED) |
344 | 2.26M | { |
345 | 2.26M | const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; |
346 | 2.26M | const hb_ot_face_t *ot_face = ot_font->ot_face; |
347 | 2.26M | return ot_face->cmap->get_nominal_glyph (unicode, glyph); |
348 | 2.26M | } |
349 | | |
350 | | static unsigned int |
351 | | hb_ot_get_nominal_glyphs (hb_font_t *font HB_UNUSED, |
352 | | void *font_data, |
353 | | unsigned int count, |
354 | | const hb_codepoint_t *first_unicode, |
355 | | unsigned int unicode_stride, |
356 | | hb_codepoint_t *first_glyph, |
357 | | unsigned int glyph_stride, |
358 | | void *user_data HB_UNUSED) |
359 | 130k | { |
360 | 130k | const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; |
361 | 130k | const hb_ot_face_t *ot_face = ot_font->ot_face; |
362 | 130k | return ot_face->cmap->get_nominal_glyphs (count, |
363 | 130k | first_unicode, unicode_stride, |
364 | 130k | first_glyph, glyph_stride); |
365 | 130k | } |
366 | | |
367 | | static hb_bool_t |
368 | | hb_ot_get_variation_glyph (hb_font_t *font HB_UNUSED, |
369 | | void *font_data, |
370 | | hb_codepoint_t unicode, |
371 | | hb_codepoint_t variation_selector, |
372 | | hb_codepoint_t *glyph, |
373 | | void *user_data HB_UNUSED) |
374 | 44.8k | { |
375 | 44.8k | const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; |
376 | 44.8k | const hb_ot_face_t *ot_face = ot_font->ot_face; |
377 | 44.8k | return ot_face->cmap->get_variation_glyph (unicode, |
378 | 44.8k | variation_selector, glyph); |
379 | 44.8k | } |
380 | | |
381 | | static void |
382 | | hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data, |
383 | | unsigned count, |
384 | | const hb_codepoint_t *first_glyph, |
385 | | unsigned glyph_stride, |
386 | | hb_position_t *first_advance, |
387 | | unsigned advance_stride, |
388 | | void *user_data HB_UNUSED) |
389 | 260k | { |
390 | | // Duplicated in v_advances. Ugly. Keep in sync'ish. |
391 | | |
392 | 260k | const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; |
393 | 260k | const hb_ot_face_t *ot_face = ot_font->ot_face; |
394 | 260k | const OT::hmtx_accelerator_t &hmtx = *ot_face->hmtx; |
395 | | |
396 | 260k | if (unlikely (!hmtx.has_data ())) |
397 | 247k | { |
398 | 247k | hb_position_t advance = font->face->get_upem () / 2; |
399 | 247k | advance = font->em_scale_x (advance); |
400 | 60.6M | for (unsigned int i = 0; i < count; i++) |
401 | 60.3M | { |
402 | 60.3M | *first_advance = advance; |
403 | 60.3M | first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride); |
404 | 60.3M | } |
405 | 247k | return; |
406 | 247k | } |
407 | | |
408 | 12.5k | #ifndef HB_NO_VAR |
409 | 12.5k | if (!font->has_nonzero_coords) |
410 | 6.29k | { |
411 | 8.73k | fallback: |
412 | | #else |
413 | | { |
414 | | #endif |
415 | | // Just plain htmx data. No need to cache. |
416 | 1.35M | for (unsigned int i = 0; i < count; i++) |
417 | 1.34M | { |
418 | 1.34M | *first_advance = font->em_scale_x (hmtx.get_advance_without_var_unscaled (*first_glyph)); |
419 | 1.34M | first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride); |
420 | 1.34M | first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride); |
421 | 1.34M | } |
422 | 8.73k | return; |
423 | 6.29k | } |
424 | | |
425 | 6.23k | #ifndef HB_NO_VAR |
426 | | /* has_nonzero_coords. */ |
427 | | |
428 | 6.23k | ot_font->check_serial (font); |
429 | 6.23k | hb_ot_font_advance_cache_t *advance_cache = ot_font->h.acquire_advance_cache (); |
430 | 6.23k | if (!advance_cache) |
431 | 82 | { |
432 | | // malloc failure. Just use the fallback non-variable path. |
433 | 82 | goto fallback; |
434 | 82 | } |
435 | | |
436 | | /* If HVAR is present, use it.*/ |
437 | 6.15k | const OT::HVAR &HVAR = *hmtx.var_table; |
438 | 6.15k | if (HVAR.has_data ()) |
439 | 879 | { |
440 | 879 | const OT::ItemVariationStore &varStore = &HVAR + HVAR.varStore; |
441 | 879 | OT::hb_scalar_cache_t *varStore_cache = ot_font->h.acquire_varStore_cache (varStore); |
442 | | |
443 | 6.34k | for (unsigned int i = 0; i < count; i++) |
444 | 5.46k | { |
445 | 5.46k | hb_position_t v; |
446 | 5.46k | unsigned cv; |
447 | 5.46k | if (advance_cache->get (*first_glyph, &cv)) |
448 | 3.60k | v = cv; |
449 | 1.86k | else |
450 | 1.86k | { |
451 | 1.86k | v = hmtx.get_advance_with_var_unscaled (*first_glyph, font, varStore_cache); |
452 | 1.86k | advance_cache->set (*first_glyph, v); |
453 | 1.86k | } |
454 | 5.46k | *first_advance = font->em_scale_x (v); |
455 | 5.46k | first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride); |
456 | 5.46k | first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride); |
457 | 5.46k | } |
458 | | |
459 | 879 | ot_font->h.release_varStore_cache (varStore_cache); |
460 | 879 | ot_font->h.release_advance_cache (advance_cache); |
461 | 879 | return; |
462 | 879 | } |
463 | | |
464 | 5.27k | const auto &gvar = *ot_face->gvar; |
465 | 5.27k | if (gvar.has_data ()) |
466 | 2.98k | { |
467 | 2.98k | const auto &glyf = *ot_face->glyf; |
468 | 2.98k | auto *scratch = glyf.acquire_scratch (); |
469 | 2.98k | if (unlikely (!scratch)) |
470 | 65 | { |
471 | 65 | ot_font->h.release_advance_cache (advance_cache); |
472 | 65 | goto fallback; |
473 | 65 | } |
474 | 2.91k | OT::hb_scalar_cache_t *gvar_cache = ot_font->draw.acquire_gvar_cache (gvar); |
475 | | |
476 | 20.4k | for (unsigned int i = 0; i < count; i++) |
477 | 17.5k | { |
478 | 17.5k | hb_position_t v; |
479 | 17.5k | unsigned cv; |
480 | 17.5k | if (advance_cache->get (*first_glyph, &cv)) |
481 | 11.6k | v = cv; |
482 | 5.94k | else |
483 | 5.94k | { |
484 | 5.94k | v = glyf.get_advance_with_var_unscaled (*first_glyph, font, false, *scratch, gvar_cache); |
485 | 5.94k | advance_cache->set (*first_glyph, v); |
486 | 5.94k | } |
487 | 17.5k | *first_advance = font->em_scale_x (v); |
488 | 17.5k | first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride); |
489 | 17.5k | first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride); |
490 | 17.5k | } |
491 | | |
492 | 2.91k | ot_font->draw.release_gvar_cache (gvar_cache); |
493 | 2.91k | glyf.release_scratch (scratch); |
494 | 2.91k | ot_font->h.release_advance_cache (advance_cache); |
495 | 2.91k | return; |
496 | 2.98k | } |
497 | | |
498 | 2.29k | ot_font->h.release_advance_cache (advance_cache); |
499 | | // No HVAR or GVAR. Just use the fallback non-variable path. |
500 | 2.29k | goto fallback; |
501 | 5.27k | #endif |
502 | 5.27k | } |
503 | | |
504 | | #ifndef HB_NO_VERTICAL |
505 | | static void |
506 | | hb_ot_get_glyph_v_advances (hb_font_t* font, void* font_data, |
507 | | unsigned count, |
508 | | const hb_codepoint_t *first_glyph, |
509 | | unsigned glyph_stride, |
510 | | hb_position_t *first_advance, |
511 | | unsigned advance_stride, |
512 | | void *user_data HB_UNUSED) |
513 | 42.7k | { |
514 | | // Duplicated from h_advances. Ugly. Keep in sync'ish. |
515 | | |
516 | 42.7k | const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; |
517 | 42.7k | const hb_ot_face_t *ot_face = ot_font->ot_face; |
518 | 42.7k | const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx; |
519 | | |
520 | 42.7k | if (unlikely (!vmtx.has_data ())) |
521 | 42.3k | { |
522 | 42.3k | hb_font_extents_t font_extents; |
523 | 42.3k | font->get_h_extents_with_fallback (&font_extents); |
524 | 42.3k | hb_position_t advance = font_extents.descender - font_extents.ascender; |
525 | 84.7k | for (unsigned int i = 0; i < count; i++) |
526 | 42.3k | { |
527 | 42.3k | *first_advance = advance; |
528 | 42.3k | first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride); |
529 | 42.3k | } |
530 | 42.3k | return; |
531 | 42.3k | } |
532 | | |
533 | 388 | #ifndef HB_NO_VAR |
534 | 388 | if (!font->has_nonzero_coords) |
535 | 83 | { |
536 | 152 | fallback: |
537 | | #else |
538 | | { |
539 | | #endif |
540 | | // Just plain vtmx data. No need to cache. |
541 | 304 | for (unsigned int i = 0; i < count; i++) |
542 | 152 | { |
543 | 152 | *first_advance = font->em_scale_y (- (int) vmtx.get_advance_without_var_unscaled (*first_glyph)); |
544 | 152 | first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride); |
545 | 152 | first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride); |
546 | 152 | } |
547 | 152 | return; |
548 | 83 | } |
549 | | |
550 | 305 | #ifndef HB_NO_VAR |
551 | | /* has_nonzero_coords. */ |
552 | | |
553 | 305 | ot_font->check_serial (font); |
554 | 305 | hb_ot_font_advance_cache_t *advance_cache = ot_font->v.acquire_advance_cache (); |
555 | 305 | if (!advance_cache) |
556 | 4 | { |
557 | | // malloc failure. Just use the fallback non-variable path. |
558 | 4 | goto fallback; |
559 | 4 | } |
560 | | |
561 | | /* If VVAR is present, use it.*/ |
562 | 301 | const OT::VVAR &VVAR = *vmtx.var_table; |
563 | 301 | if (VVAR.has_data ()) |
564 | 66 | { |
565 | 66 | const OT::ItemVariationStore &varStore = &VVAR + VVAR.varStore; |
566 | 66 | OT::hb_scalar_cache_t *varStore_cache = ot_font->v.acquire_varStore_cache (varStore); |
567 | | |
568 | 132 | for (unsigned int i = 0; i < count; i++) |
569 | 66 | { |
570 | 66 | hb_position_t v; |
571 | 66 | unsigned cv; |
572 | 66 | if (advance_cache->get (*first_glyph, &cv)) |
573 | 0 | v = cv; |
574 | 66 | else |
575 | 66 | { |
576 | 66 | v = vmtx.get_advance_with_var_unscaled (*first_glyph, font, varStore_cache); |
577 | 66 | advance_cache->set (*first_glyph, v); |
578 | 66 | } |
579 | 66 | *first_advance = font->em_scale_y (- (int) v); |
580 | 66 | first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride); |
581 | 66 | first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride); |
582 | 66 | } |
583 | | |
584 | 66 | ot_font->v.release_varStore_cache (varStore_cache); |
585 | 66 | ot_font->v.release_advance_cache (advance_cache); |
586 | 66 | return; |
587 | 66 | } |
588 | | |
589 | 235 | const auto &gvar = *ot_face->gvar; |
590 | 235 | if (gvar.has_data ()) |
591 | 174 | { |
592 | 174 | const auto &glyf = *ot_face->glyf; |
593 | 174 | auto *scratch = glyf.acquire_scratch (); |
594 | 174 | if (unlikely (!scratch)) |
595 | 4 | { |
596 | 4 | ot_font->v.release_advance_cache (advance_cache); |
597 | 4 | goto fallback; |
598 | 4 | } |
599 | 170 | OT::hb_scalar_cache_t *gvar_cache = ot_font->draw.acquire_gvar_cache (gvar); |
600 | | |
601 | 340 | for (unsigned int i = 0; i < count; i++) |
602 | 170 | { |
603 | 170 | hb_position_t v; |
604 | 170 | unsigned cv; |
605 | 170 | if (advance_cache->get (*first_glyph, &cv)) |
606 | 0 | v = cv; |
607 | 170 | else |
608 | 170 | { |
609 | 170 | v = glyf.get_advance_with_var_unscaled (*first_glyph, font, true, *scratch, gvar_cache); |
610 | 170 | advance_cache->set (*first_glyph, v); |
611 | 170 | } |
612 | 170 | *first_advance = font->em_scale_y (- (int) v); |
613 | 170 | first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride); |
614 | 170 | first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride); |
615 | 170 | } |
616 | | |
617 | 170 | ot_font->draw.release_gvar_cache (gvar_cache); |
618 | 170 | glyf.release_scratch (scratch); |
619 | 170 | ot_font->v.release_advance_cache (advance_cache); |
620 | 170 | return; |
621 | 174 | } |
622 | | |
623 | 61 | ot_font->v.release_advance_cache (advance_cache); |
624 | | // No VVAR or GVAR. Just use the fallback non-variable path. |
625 | 61 | goto fallback; |
626 | 235 | #endif |
627 | 235 | } |
628 | | #endif |
629 | | |
630 | | #ifndef HB_NO_VERTICAL |
631 | | HB_HOT |
632 | | static hb_bool_t |
633 | | hb_ot_get_glyph_v_origins (hb_font_t *font, |
634 | | void *font_data, |
635 | | unsigned int count, |
636 | | const hb_codepoint_t *first_glyph, |
637 | | unsigned glyph_stride, |
638 | | hb_position_t *first_x, |
639 | | unsigned x_stride, |
640 | | hb_position_t *first_y, |
641 | | unsigned y_stride, |
642 | | void *user_data HB_UNUSED) |
643 | 42.7k | { |
644 | 42.7k | const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; |
645 | 42.7k | const hb_ot_face_t *ot_face = ot_font->ot_face; |
646 | | |
647 | | /* First, set all the x values to half the advance width. */ |
648 | 42.7k | font->get_glyph_h_advances (count, |
649 | 42.7k | first_glyph, glyph_stride, |
650 | 42.7k | first_x, x_stride); |
651 | 85.5k | for (unsigned i = 0; i < count; i++) |
652 | 42.7k | { |
653 | 42.7k | *first_x /= 2; |
654 | 42.7k | first_x = &StructAtOffsetUnaligned<hb_position_t> (first_x, x_stride); |
655 | 42.7k | } |
656 | | |
657 | | /* The vertical origin business is messy... |
658 | | * |
659 | | * We allocate the cache, then have various code paths that use the cache. |
660 | | * Each one is responsible to free it before returning. |
661 | | */ |
662 | 42.7k | hb_ot_font_origin_cache_t *origin_cache = ot_font->v_origin.acquire_origin_cache (); |
663 | | |
664 | | /* If there is VORG, always use it. It uses VVAR for variations if necessary. */ |
665 | 42.7k | const OT::VORG &VORG = *ot_face->VORG; |
666 | 42.7k | if (origin_cache && VORG.has_data ()) |
667 | 178 | { |
668 | 178 | #ifndef HB_NO_VAR |
669 | 178 | if (!font->has_nonzero_coords) |
670 | 87 | #endif |
671 | 87 | { |
672 | 174 | for (unsigned i = 0; i < count; i++) |
673 | 87 | { |
674 | 87 | hb_position_t origin; |
675 | 87 | unsigned cv; |
676 | 87 | if (origin_cache->get (*first_glyph, &cv)) |
677 | 0 | origin = font->y_scale < 0 ? -static_cast<hb_position_t>(cv) : static_cast<hb_position_t>(cv); |
678 | 87 | else |
679 | 87 | { |
680 | 87 | origin = font->em_scalef_y (VORG.get_y_origin (*first_glyph)); |
681 | 87 | origin_cache->set (*first_glyph, font->y_scale < 0 ? -origin : origin); |
682 | 87 | } |
683 | | |
684 | 87 | *first_y = origin; |
685 | | |
686 | 87 | first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride); |
687 | 87 | first_y = &StructAtOffsetUnaligned<hb_position_t> (first_y, y_stride); |
688 | 87 | } |
689 | 87 | } |
690 | 91 | #ifndef HB_NO_VAR |
691 | 91 | else |
692 | 91 | { |
693 | 91 | const OT::VVAR &VVAR = *ot_face->vmtx->var_table; |
694 | 91 | const auto &varStore = &VVAR + VVAR.varStore; |
695 | 91 | auto *varStore_cache = ot_font->v_origin.acquire_varStore_cache (varStore); |
696 | 182 | for (unsigned i = 0; i < count; i++) |
697 | 91 | { |
698 | 91 | hb_position_t origin; |
699 | 91 | unsigned cv; |
700 | 91 | if (origin_cache->get (*first_glyph, &cv)) |
701 | 0 | origin = font->y_scale < 0 ? -static_cast<hb_position_t>(cv) : static_cast<hb_position_t>(cv); |
702 | 91 | else |
703 | 91 | { |
704 | 91 | origin = font->em_scalef_y (VORG.get_y_origin (*first_glyph) + |
705 | 91 | VVAR.get_vorg_delta_unscaled (*first_glyph, |
706 | 91 | font->coords, font->num_coords, |
707 | 91 | varStore_cache)); |
708 | 91 | origin_cache->set (*first_glyph, font->y_scale < 0 ? -origin : origin); |
709 | 91 | } |
710 | | |
711 | 91 | *first_y = origin; |
712 | | |
713 | 91 | first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride); |
714 | 91 | first_y = &StructAtOffsetUnaligned<hb_position_t> (first_y, y_stride); |
715 | 91 | } |
716 | 91 | ot_font->v_origin.release_varStore_cache (varStore_cache); |
717 | 91 | } |
718 | 178 | #endif |
719 | 178 | ot_font->v_origin.release_origin_cache (origin_cache); |
720 | 178 | return true; |
721 | 178 | } |
722 | | |
723 | | /* If and only if `vmtx` is present and it's a `glyf` font, |
724 | | * we use the top phantom point, deduced from vmtx,glyf[,gvar]. */ |
725 | 42.6k | const auto &vmtx = *ot_face->vmtx; |
726 | 42.6k | const auto &glyf = *ot_face->glyf; |
727 | 42.6k | if (origin_cache && vmtx.has_data() && glyf.has_data ()) |
728 | 244 | { |
729 | 244 | auto *scratch = glyf.acquire_scratch (); |
730 | 244 | if (unlikely (!scratch)) |
731 | 3 | { |
732 | 3 | ot_font->v_origin.release_origin_cache (origin_cache); |
733 | 3 | return false; |
734 | 3 | } |
735 | 241 | OT::hb_scalar_cache_t *gvar_cache = font->has_nonzero_coords ? |
736 | 203 | ot_font->draw.acquire_gvar_cache (*ot_face->gvar) : |
737 | 241 | nullptr; |
738 | | |
739 | 482 | for (unsigned i = 0; i < count; i++) |
740 | 241 | { |
741 | 241 | hb_position_t origin; |
742 | 241 | unsigned cv; |
743 | 241 | if (origin_cache->get (*first_glyph, &cv)) |
744 | 0 | origin = font->y_scale < 0 ? -static_cast<hb_position_t>(cv) : static_cast<hb_position_t>(cv); |
745 | 241 | else |
746 | 241 | { |
747 | 241 | origin = font->em_scalef_y (glyf.get_v_origin_with_var_unscaled (*first_glyph, font, *scratch, gvar_cache)); |
748 | 241 | origin_cache->set (*first_glyph, font->y_scale < 0 ? -origin : origin); |
749 | 241 | } |
750 | | |
751 | 241 | *first_y = origin; |
752 | | |
753 | 241 | first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride); |
754 | 241 | first_y = &StructAtOffsetUnaligned<hb_position_t> (first_y, y_stride); |
755 | 241 | } |
756 | | |
757 | 241 | if (gvar_cache) |
758 | 203 | ot_font->draw.release_gvar_cache (gvar_cache); |
759 | 241 | glyf.release_scratch (scratch); |
760 | 241 | ot_font->v_origin.release_origin_cache (origin_cache); |
761 | 241 | return true; |
762 | 244 | } |
763 | | |
764 | | /* Otherwise, use glyph extents to center the glyph vertically. |
765 | | * If getting glyph extents failed, just use the font ascender. */ |
766 | 42.3k | if (origin_cache && font->has_glyph_extents_func ()) |
767 | 41.8k | { |
768 | 41.8k | hb_font_extents_t font_extents; |
769 | 41.8k | font->get_h_extents_with_fallback (&font_extents); |
770 | 41.8k | hb_position_t font_advance = font_extents.ascender - font_extents.descender; |
771 | | |
772 | 83.6k | for (unsigned i = 0; i < count; i++) |
773 | 41.8k | { |
774 | 41.8k | hb_position_t origin; |
775 | 41.8k | unsigned cv; |
776 | | |
777 | 41.8k | if (origin_cache->get (*first_glyph, &cv)) |
778 | 0 | origin = font->y_scale < 0 ? -static_cast<hb_position_t>(cv) : static_cast<hb_position_t>(cv); |
779 | 41.8k | else |
780 | 41.8k | { |
781 | 41.8k | hb_glyph_extents_t extents = {0}; |
782 | 41.8k | if (likely (font->get_glyph_extents (*first_glyph, &extents))) |
783 | 2.36k | origin = extents.y_bearing + ((font_advance - -extents.height) >> 1); |
784 | 39.4k | else |
785 | 39.4k | origin = font_extents.ascender; |
786 | | |
787 | 41.8k | origin_cache->set (*first_glyph, font->y_scale < 0 ? -origin : origin); |
788 | 41.8k | } |
789 | | |
790 | 41.8k | *first_y = origin; |
791 | | |
792 | 41.8k | first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride); |
793 | 41.8k | first_y = &StructAtOffsetUnaligned<hb_position_t> (first_y, y_stride); |
794 | 41.8k | } |
795 | 41.8k | } |
796 | | |
797 | 42.3k | ot_font->v_origin.release_origin_cache (origin_cache); |
798 | 42.3k | return true; |
799 | 42.6k | } |
800 | | #endif |
801 | | |
802 | | static hb_bool_t |
803 | | hb_ot_get_glyph_extents (hb_font_t *font, |
804 | | void *font_data, |
805 | | hb_codepoint_t glyph, |
806 | | hb_glyph_extents_t *extents, |
807 | | void *user_data HB_UNUSED) |
808 | 1.22M | { |
809 | 1.22M | const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; |
810 | 1.22M | const hb_ot_face_t *ot_face = ot_font->ot_face; |
811 | | |
812 | 1.22M | #if !defined(HB_NO_OT_FONT_BITMAP) && !defined(HB_NO_COLOR) |
813 | 1.22M | if (ot_face->sbix->get_extents (font, glyph, extents)) return true; |
814 | 1.22M | if (ot_face->CBDT->get_extents (font, glyph, extents)) return true; |
815 | 1.22M | #endif |
816 | 1.22M | #if !defined(HB_NO_COLOR) && !defined(HB_NO_PAINT) |
817 | 1.22M | if (ot_face->COLR->get_extents (font, glyph, extents)) return true; |
818 | 1.21M | #endif |
819 | 1.21M | #ifndef HB_NO_VAR_COMPOSITES |
820 | 1.21M | if (ot_face->VARC->get_extents (font, glyph, extents)) return true; |
821 | 1.21M | #endif |
822 | 1.21M | if (ot_face->glyf->get_extents (font, glyph, extents)) return true; |
823 | 1.15M | #ifndef HB_NO_OT_FONT_CFF |
824 | 1.15M | if (ot_face->cff2->get_extents (font, glyph, extents)) return true; |
825 | 1.15M | if (ot_face->cff1->get_extents (font, glyph, extents)) return true; |
826 | 1.15M | #endif |
827 | | |
828 | 1.15M | return false; |
829 | 1.15M | } |
830 | | |
831 | | #ifndef HB_NO_OT_FONT_GLYPH_NAMES |
832 | | static hb_bool_t |
833 | | hb_ot_get_glyph_name (hb_font_t *font HB_UNUSED, |
834 | | void *font_data, |
835 | | hb_codepoint_t glyph, |
836 | | char *name, unsigned int size, |
837 | | void *user_data HB_UNUSED) |
838 | 42.7k | { |
839 | 42.7k | const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; |
840 | 42.7k | const hb_ot_face_t *ot_face = ot_font->ot_face; |
841 | | |
842 | 42.7k | if (ot_face->post->get_glyph_name (glyph, name, size)) return true; |
843 | 42.4k | #ifndef HB_NO_OT_FONT_CFF |
844 | 42.4k | if (ot_face->cff1->get_glyph_name (glyph, name, size)) return true; |
845 | 41.4k | #endif |
846 | 41.4k | return false; |
847 | 42.4k | } |
848 | | static hb_bool_t |
849 | | hb_ot_get_glyph_from_name (hb_font_t *font HB_UNUSED, |
850 | | void *font_data, |
851 | | const char *name, int len, |
852 | | hb_codepoint_t *glyph, |
853 | | void *user_data HB_UNUSED) |
854 | 42.7k | { |
855 | 42.7k | const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; |
856 | 42.7k | const hb_ot_face_t *ot_face = ot_font->ot_face; |
857 | | |
858 | 42.7k | if (ot_face->post->get_glyph_from_name (name, len, glyph)) return true; |
859 | 42.7k | #ifndef HB_NO_OT_FONT_CFF |
860 | 42.7k | if (ot_face->cff1->get_glyph_from_name (name, len, glyph)) return true; |
861 | 42.6k | #endif |
862 | 42.6k | return false; |
863 | 42.7k | } |
864 | | #endif |
865 | | |
866 | | static hb_bool_t |
867 | | hb_ot_get_font_h_extents (hb_font_t *font, |
868 | | void *font_data HB_UNUSED, |
869 | | hb_font_extents_t *metrics, |
870 | | void *user_data HB_UNUSED) |
871 | 84.2k | { |
872 | 84.2k | return _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER, &metrics->ascender) && |
873 | 4.36k | _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER, &metrics->descender) && |
874 | 4.36k | _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP, &metrics->line_gap); |
875 | 84.2k | } |
876 | | |
877 | | #ifndef HB_NO_VERTICAL |
878 | | static hb_bool_t |
879 | | hb_ot_get_font_v_extents (hb_font_t *font, |
880 | | void *font_data HB_UNUSED, |
881 | | hb_font_extents_t *metrics, |
882 | | void *user_data HB_UNUSED) |
883 | 0 | { |
884 | 0 | return _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_VERTICAL_ASCENDER, &metrics->ascender) && |
885 | 0 | _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_VERTICAL_DESCENDER, &metrics->descender) && |
886 | 0 | _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_VERTICAL_LINE_GAP, &metrics->line_gap); |
887 | 0 | } |
888 | | #endif |
889 | | |
890 | | #ifndef HB_NO_DRAW |
891 | | static hb_bool_t |
892 | | hb_ot_draw_glyph_or_fail (hb_font_t *font, |
893 | | void *font_data HB_UNUSED, |
894 | | hb_codepoint_t glyph, |
895 | | hb_draw_funcs_t *draw_funcs, void *draw_data, |
896 | | void *user_data) |
897 | 739k | { |
898 | 739k | const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; |
899 | 739k | hb_draw_session_t draw_session {draw_funcs, draw_data}; |
900 | 739k | bool ret = false; |
901 | | |
902 | 739k | OT::hb_scalar_cache_t *gvar_cache = nullptr; |
903 | 739k | if (font->num_coords) |
904 | 15.0k | { |
905 | 15.0k | ot_font->check_serial (font); |
906 | 15.0k | gvar_cache = ot_font->draw.acquire_gvar_cache (*ot_font->ot_face->gvar); |
907 | 15.0k | } |
908 | | |
909 | 739k | #ifndef HB_NO_VAR_COMPOSITES |
910 | 739k | if (font->face->table.VARC->get_path (font, glyph, draw_session)) { ret = true; goto done; } |
911 | 738k | #endif |
912 | | // Keep the following in synch with VARC::get_path_at() |
913 | 738k | if (font->face->table.glyf->get_path (font, glyph, draw_session, gvar_cache)) { ret = true; goto done; } |
914 | | |
915 | 734k | #ifndef HB_NO_CFF |
916 | 734k | if (font->face->table.cff2->get_path (font, glyph, draw_session)) { ret = true; goto done; } |
917 | 734k | if (font->face->table.cff1->get_path (font, glyph, draw_session)) { ret = true; goto done; } |
918 | 734k | #endif |
919 | | |
920 | 739k | done: |
921 | | |
922 | 739k | ot_font->draw.release_gvar_cache (gvar_cache); |
923 | | |
924 | 739k | return ret; |
925 | 734k | } |
926 | | #endif |
927 | | |
928 | | #ifndef HB_NO_PAINT |
929 | | static hb_bool_t |
930 | | hb_ot_paint_glyph_or_fail (hb_font_t *font, |
931 | | void *font_data, |
932 | | hb_codepoint_t glyph, |
933 | | hb_paint_funcs_t *paint_funcs, void *paint_data, |
934 | | unsigned int palette, |
935 | | hb_color_t foreground, |
936 | | void *user_data) |
937 | 550k | { |
938 | 550k | #ifndef HB_NO_COLOR |
939 | 550k | if (font->face->table.COLR->paint_glyph (font, glyph, paint_funcs, paint_data, palette, foreground)) return true; |
940 | 550k | if (font->face->table.SVG->paint_glyph (font, glyph, paint_funcs, paint_data)) return true; |
941 | 550k | #ifndef HB_NO_OT_FONT_BITMAP |
942 | 550k | if (font->face->table.CBDT->paint_glyph (font, glyph, paint_funcs, paint_data)) return true; |
943 | 550k | if (font->face->table.sbix->paint_glyph (font, glyph, paint_funcs, paint_data)) return true; |
944 | 550k | #endif |
945 | 550k | #endif |
946 | 550k | return false; |
947 | 550k | } |
948 | | #endif |
949 | | |
950 | | static inline void free_static_ot_funcs (); |
951 | | |
952 | | static struct hb_ot_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ot_font_funcs_lazy_loader_t> |
953 | | { |
954 | | static hb_font_funcs_t *create () |
955 | 1 | { |
956 | 1 | hb_font_funcs_t *funcs = hb_font_funcs_create (); |
957 | | |
958 | 1 | hb_font_funcs_set_nominal_glyph_func (funcs, hb_ot_get_nominal_glyph, nullptr, nullptr); |
959 | 1 | hb_font_funcs_set_nominal_glyphs_func (funcs, hb_ot_get_nominal_glyphs, nullptr, nullptr); |
960 | 1 | hb_font_funcs_set_variation_glyph_func (funcs, hb_ot_get_variation_glyph, nullptr, nullptr); |
961 | | |
962 | 1 | hb_font_funcs_set_font_h_extents_func (funcs, hb_ot_get_font_h_extents, nullptr, nullptr); |
963 | 1 | hb_font_funcs_set_glyph_h_advances_func (funcs, hb_ot_get_glyph_h_advances, nullptr, nullptr); |
964 | | |
965 | 1 | #ifndef HB_NO_VERTICAL |
966 | 1 | hb_font_funcs_set_font_v_extents_func (funcs, hb_ot_get_font_v_extents, nullptr, nullptr); |
967 | 1 | hb_font_funcs_set_glyph_v_advances_func (funcs, hb_ot_get_glyph_v_advances, nullptr, nullptr); |
968 | 1 | hb_font_funcs_set_glyph_v_origins_func (funcs, hb_ot_get_glyph_v_origins, nullptr, nullptr); |
969 | 1 | #endif |
970 | | |
971 | 1 | #ifndef HB_NO_DRAW |
972 | 1 | hb_font_funcs_set_draw_glyph_or_fail_func (funcs, hb_ot_draw_glyph_or_fail, nullptr, nullptr); |
973 | 1 | #endif |
974 | | |
975 | 1 | #ifndef HB_NO_PAINT |
976 | 1 | hb_font_funcs_set_paint_glyph_or_fail_func (funcs, hb_ot_paint_glyph_or_fail, nullptr, nullptr); |
977 | 1 | #endif |
978 | | |
979 | 1 | hb_font_funcs_set_glyph_extents_func (funcs, hb_ot_get_glyph_extents, nullptr, nullptr); |
980 | | //hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ot_get_glyph_contour_point, nullptr, nullptr); |
981 | | |
982 | 1 | #ifndef HB_NO_OT_FONT_GLYPH_NAMES |
983 | 1 | hb_font_funcs_set_glyph_name_func (funcs, hb_ot_get_glyph_name, nullptr, nullptr); |
984 | 1 | hb_font_funcs_set_glyph_from_name_func (funcs, hb_ot_get_glyph_from_name, nullptr, nullptr); |
985 | 1 | #endif |
986 | | |
987 | 1 | hb_font_funcs_make_immutable (funcs); |
988 | | |
989 | 1 | hb_atexit (free_static_ot_funcs); |
990 | | |
991 | 1 | return funcs; |
992 | 1 | } |
993 | | } static_ot_funcs; |
994 | | |
995 | | static inline |
996 | | void free_static_ot_funcs () |
997 | 1 | { |
998 | 1 | static_ot_funcs.free_instance (); |
999 | 1 | } |
1000 | | |
1001 | | static hb_font_funcs_t * |
1002 | | _hb_ot_get_font_funcs () |
1003 | 42.7k | { |
1004 | 42.7k | return static_ot_funcs.get_unconst (); |
1005 | 42.7k | } |
1006 | | |
1007 | | |
1008 | | /** |
1009 | | * hb_ot_font_set_funcs: |
1010 | | * @font: #hb_font_t to work upon |
1011 | | * |
1012 | | * Sets the font functions to use when working with @font to |
1013 | | * the HarfBuzz's native implementation. This is the default |
1014 | | * for fonts newly created. |
1015 | | * |
1016 | | * Since: 0.9.28 |
1017 | | **/ |
1018 | | void |
1019 | | hb_ot_font_set_funcs (hb_font_t *font) |
1020 | 43.3k | { |
1021 | 43.3k | hb_ot_font_t *ot_font = _hb_ot_font_create (font); |
1022 | 43.3k | if (unlikely (!ot_font)) |
1023 | 578 | return; |
1024 | | |
1025 | 42.7k | hb_font_set_funcs (font, |
1026 | 42.7k | _hb_ot_get_font_funcs (), |
1027 | 42.7k | ot_font, |
1028 | 42.7k | _hb_ot_font_destroy); |
1029 | 42.7k | } |
1030 | | |
1031 | | #endif |