/work/workdir/UnpackedTarball/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 | 822k | { |
85 | 822k | clear (); |
86 | 822k | } |
87 | | |
88 | | hb_ot_font_advance_cache_t *acquire_advance_cache () const |
89 | 0 | { |
90 | 0 | retry: |
91 | 0 | auto *cache = advance_cache.get_acquire (); |
92 | 0 | if (!cache) |
93 | 0 | { |
94 | 0 | cache = (hb_ot_font_advance_cache_t *) hb_malloc (sizeof (hb_ot_font_advance_cache_t)); |
95 | 0 | if (!cache) |
96 | 0 | return nullptr; |
97 | 0 | new (cache) hb_ot_font_advance_cache_t; |
98 | 0 | return cache; |
99 | 0 | } |
100 | 0 | if (advance_cache.cmpexch (cache, nullptr)) |
101 | 0 | return cache; |
102 | 0 | else |
103 | 0 | goto retry; |
104 | 0 | } |
105 | | void release_advance_cache (hb_ot_font_advance_cache_t *cache) const |
106 | 0 | { |
107 | 0 | if (!cache) |
108 | 0 | return; |
109 | 0 | if (!advance_cache.cmpexch (nullptr, cache)) |
110 | 0 | hb_free (cache); |
111 | 0 | } |
112 | | void clear_advance_cache () const |
113 | 822k | { |
114 | 822k | retry: |
115 | 822k | auto *cache = advance_cache.get_acquire (); |
116 | 822k | if (!cache) |
117 | 822k | return; |
118 | 0 | if (advance_cache.cmpexch (cache, nullptr)) |
119 | 0 | hb_free (cache); |
120 | 0 | else |
121 | 0 | goto retry; |
122 | 0 | } |
123 | | |
124 | | OT::hb_scalar_cache_t *acquire_varStore_cache (const OT::ItemVariationStore &varStore) const |
125 | 0 | { |
126 | 0 | retry: |
127 | 0 | auto *cache = varStore_cache.get_acquire (); |
128 | 0 | if (!cache) |
129 | 0 | return varStore.create_cache (); |
130 | 0 | if (varStore_cache.cmpexch (cache, nullptr)) |
131 | 0 | return cache; |
132 | 0 | else |
133 | 0 | goto retry; |
134 | 0 | } |
135 | | void release_varStore_cache (OT::hb_scalar_cache_t *cache) const |
136 | 0 | { |
137 | 0 | if (!cache) |
138 | 0 | return; |
139 | 0 | if (!varStore_cache.cmpexch (nullptr, cache)) |
140 | 0 | OT::ItemVariationStore::destroy_cache (cache); |
141 | 0 | } |
142 | | void clear_varStore_cache () const |
143 | 822k | { |
144 | 822k | retry: |
145 | 822k | auto *cache = varStore_cache.get_acquire (); |
146 | 822k | if (!cache) |
147 | 822k | return; |
148 | 0 | if (varStore_cache.cmpexch (cache, nullptr)) |
149 | 0 | OT::ItemVariationStore::destroy_cache (cache); |
150 | 0 | else |
151 | 0 | goto retry; |
152 | 0 | } |
153 | | |
154 | | void clear () const |
155 | 822k | { |
156 | 822k | clear_advance_cache (); |
157 | 822k | clear_varStore_cache (); |
158 | 822k | } |
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 | 411k | { |
169 | 411k | clear (); |
170 | 411k | } |
171 | | |
172 | | hb_ot_font_origin_cache_t *acquire_origin_cache () const |
173 | 1.58M | { |
174 | 1.58M | retry: |
175 | 1.58M | auto *cache = origin_cache.get_acquire (); |
176 | 1.58M | if (!cache) |
177 | 1.10k | { |
178 | 1.10k | cache = (hb_ot_font_origin_cache_t *) hb_malloc (sizeof (hb_ot_font_origin_cache_t)); |
179 | 1.10k | if (!cache) |
180 | 0 | return nullptr; |
181 | 1.10k | new (cache) hb_ot_font_origin_cache_t; |
182 | 1.10k | return cache; |
183 | 1.10k | } |
184 | 1.58M | if (origin_cache.cmpexch (cache, nullptr)) |
185 | 1.58M | return cache; |
186 | 0 | else |
187 | 0 | goto retry; |
188 | 1.58M | } |
189 | | void release_origin_cache (hb_ot_font_origin_cache_t *cache) const |
190 | 1.58M | { |
191 | 1.58M | if (!cache) |
192 | 0 | return; |
193 | 1.58M | if (!origin_cache.cmpexch (nullptr, cache)) |
194 | 0 | hb_free (cache); |
195 | 1.58M | } |
196 | | void clear_origin_cache () const |
197 | 411k | { |
198 | 411k | retry: |
199 | 411k | auto *cache = origin_cache.get_acquire (); |
200 | 411k | if (!cache) |
201 | 410k | return; |
202 | 983 | if (origin_cache.cmpexch (cache, nullptr)) |
203 | 983 | hb_free (cache); |
204 | 0 | else |
205 | 0 | goto retry; |
206 | 983 | } |
207 | | |
208 | | OT::hb_scalar_cache_t *acquire_varStore_cache (const OT::ItemVariationStore &varStore) const |
209 | 0 | { |
210 | 0 | retry: |
211 | 0 | auto *cache = varStore_cache.get_acquire (); |
212 | 0 | if (!cache) |
213 | 0 | 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 | 0 | { |
221 | 0 | if (!cache) |
222 | 0 | return; |
223 | 0 | if (!varStore_cache.cmpexch (nullptr, cache)) |
224 | 0 | OT::ItemVariationStore::destroy_cache (cache); |
225 | 0 | } |
226 | | void clear_varStore_cache () const |
227 | 411k | { |
228 | 411k | retry: |
229 | 411k | auto *cache = varStore_cache.get_acquire (); |
230 | 411k | if (!cache) |
231 | 411k | return; |
232 | 0 | if (varStore_cache.cmpexch (cache, nullptr)) |
233 | 0 | OT::ItemVariationStore::destroy_cache (cache); |
234 | 0 | else |
235 | 0 | goto retry; |
236 | 0 | } |
237 | | |
238 | | void clear () const |
239 | 411k | { |
240 | 411k | clear_origin_cache (); |
241 | 411k | clear_varStore_cache (); |
242 | 411k | } |
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 | 411k | { |
251 | 411k | clear (); |
252 | 411k | } |
253 | | |
254 | | OT::hb_scalar_cache_t *acquire_gvar_cache (const OT::gvar_accelerator_t &gvar) const |
255 | 0 | { |
256 | 0 | retry: |
257 | 0 | auto *cache = gvar_cache.get_acquire (); |
258 | 0 | if (!cache) |
259 | 0 | return gvar.create_cache (); |
260 | 0 | if (gvar_cache.cmpexch (cache, nullptr)) |
261 | 0 | return cache; |
262 | 0 | else |
263 | 0 | goto retry; |
264 | 0 | } |
265 | | void release_gvar_cache (OT::hb_scalar_cache_t *cache) const |
266 | 0 | { |
267 | 0 | if (!cache) |
268 | 0 | return; |
269 | 0 | if (!gvar_cache.cmpexch (nullptr, cache)) |
270 | 0 | OT::gvar_accelerator_t::destroy_cache (cache); |
271 | 0 | } |
272 | | void clear_gvar_cache () const |
273 | 411k | { |
274 | 411k | retry: |
275 | 411k | auto *cache = gvar_cache.get_acquire (); |
276 | 411k | if (!cache) |
277 | 411k | return; |
278 | 0 | if (gvar_cache.cmpexch (cache, nullptr)) |
279 | 0 | OT::gvar_accelerator_t::destroy_cache (cache); |
280 | 0 | else |
281 | 0 | goto retry; |
282 | 0 | } |
283 | | |
284 | | void clear () const |
285 | 411k | { |
286 | 411k | clear_gvar_cache (); |
287 | 411k | } |
288 | | } draw; |
289 | | |
290 | | void check_serial (hb_font_t *font) const |
291 | 0 | { |
292 | 0 | int font_serial = font->serial_coords.get_acquire (); |
293 | 0 | if (cached_serial.get_acquire () != font_serial) |
294 | 0 | { |
295 | | /* These caches are dependent on scale and synthetic settings. |
296 | | * Any change to the font invalidates them. */ |
297 | 0 | v_origin.clear (); |
298 | |
|
299 | 0 | cached_serial.set_release (font_serial); |
300 | 0 | } |
301 | |
|
302 | 0 | int font_serial_coords = font->serial_coords.get_acquire (); |
303 | 0 | if (cached_coords_serial.get_acquire () != font_serial_coords) |
304 | 0 | { |
305 | | /* These caches are independent of scale or synthetic settings. |
306 | | * Just variation changes will invalidate them. */ |
307 | 0 | h.clear (); |
308 | 0 | v.clear (); |
309 | 0 | draw.clear (); |
310 | |
|
311 | 0 | cached_coords_serial.set_release (font_serial_coords); |
312 | 0 | } |
313 | 0 | } |
314 | | }; |
315 | | |
316 | | static hb_ot_font_t * |
317 | | _hb_ot_font_create (hb_font_t *font) |
318 | 412k | { |
319 | 412k | hb_ot_font_t *ot_font = (hb_ot_font_t *) hb_calloc (1, sizeof (hb_ot_font_t)); |
320 | 412k | if (unlikely (!ot_font)) |
321 | 0 | return nullptr; |
322 | | |
323 | 412k | ot_font->ot_face = &font->face->table; |
324 | | |
325 | 412k | return ot_font; |
326 | 412k | } |
327 | | |
328 | | static void |
329 | | _hb_ot_font_destroy (void *font_data) |
330 | 411k | { |
331 | 411k | hb_ot_font_t *ot_font = (hb_ot_font_t *) font_data; |
332 | | |
333 | 411k | ot_font->~hb_ot_font_t (); |
334 | | |
335 | 411k | hb_free (ot_font); |
336 | 411k | } |
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 | 117M | { |
345 | 117M | const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; |
346 | 117M | const hb_ot_face_t *ot_face = ot_font->ot_face; |
347 | 117M | return ot_face->cmap->get_nominal_glyph (unicode, glyph); |
348 | 117M | } |
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 | 29.0M | { |
360 | 29.0M | const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; |
361 | 29.0M | const hb_ot_face_t *ot_face = ot_font->ot_face; |
362 | 29.0M | return ot_face->cmap->get_nominal_glyphs (count, |
363 | 29.0M | first_unicode, unicode_stride, |
364 | 29.0M | first_glyph, glyph_stride); |
365 | 29.0M | } |
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 | 21.3k | { |
375 | 21.3k | const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; |
376 | 21.3k | const hb_ot_face_t *ot_face = ot_font->ot_face; |
377 | 21.3k | return ot_face->cmap->get_variation_glyph (unicode, |
378 | 21.3k | variation_selector, glyph); |
379 | 21.3k | } |
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 | 36.5M | { |
390 | | // Duplicated in v_advances. Ugly. Keep in sync'ish. |
391 | | |
392 | 36.5M | const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; |
393 | 36.5M | const hb_ot_face_t *ot_face = ot_font->ot_face; |
394 | 36.5M | const OT::hmtx_accelerator_t &hmtx = *ot_face->hmtx; |
395 | | |
396 | 36.5M | if (unlikely (!hmtx.has_data ())) |
397 | 0 | { |
398 | 0 | hb_position_t advance = font->face->get_upem () / 2; |
399 | 0 | advance = font->em_scale_x (advance); |
400 | 0 | for (unsigned int i = 0; i < count; i++) |
401 | 0 | { |
402 | 0 | *first_advance = advance; |
403 | 0 | first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride); |
404 | 0 | } |
405 | 0 | return; |
406 | 0 | } |
407 | | |
408 | 36.5M | #ifndef HB_NO_VAR |
409 | 36.5M | if (!font->has_nonzero_coords) |
410 | 36.5M | { |
411 | 36.5M | fallback: |
412 | | #else |
413 | | { |
414 | | #endif |
415 | | // Just plain htmx data. No need to cache. |
416 | 448M | for (unsigned int i = 0; i < count; i++) |
417 | 411M | { |
418 | 411M | *first_advance = font->em_scale_x (hmtx.get_advance_without_var_unscaled (*first_glyph)); |
419 | 411M | first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride); |
420 | 411M | first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride); |
421 | 411M | } |
422 | 36.5M | return; |
423 | 36.5M | } |
424 | | |
425 | 0 | #ifndef HB_NO_VAR |
426 | | /* has_nonzero_coords. */ |
427 | | |
428 | 0 | ot_font->check_serial (font); |
429 | 0 | hb_ot_font_advance_cache_t *advance_cache = ot_font->h.acquire_advance_cache (); |
430 | 0 | if (!advance_cache) |
431 | 0 | { |
432 | | // malloc failure. Just use the fallback non-variable path. |
433 | 0 | goto fallback; |
434 | 0 | } |
435 | | |
436 | | /* If HVAR is present, use it.*/ |
437 | 0 | const OT::HVAR &HVAR = *hmtx.var_table; |
438 | 0 | if (HVAR.has_data ()) |
439 | 0 | { |
440 | 0 | const OT::ItemVariationStore &varStore = &HVAR + HVAR.varStore; |
441 | 0 | OT::hb_scalar_cache_t *varStore_cache = ot_font->h.acquire_varStore_cache (varStore); |
442 | |
|
443 | 0 | for (unsigned int i = 0; i < count; i++) |
444 | 0 | { |
445 | 0 | hb_position_t v; |
446 | 0 | unsigned cv; |
447 | 0 | if (advance_cache->get (*first_glyph, &cv)) |
448 | 0 | v = cv; |
449 | 0 | else |
450 | 0 | { |
451 | 0 | v = hmtx.get_advance_with_var_unscaled (*first_glyph, font, varStore_cache); |
452 | 0 | advance_cache->set (*first_glyph, v); |
453 | 0 | } |
454 | 0 | *first_advance = font->em_scale_x (v); |
455 | 0 | first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride); |
456 | 0 | first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride); |
457 | 0 | } |
458 | |
|
459 | 0 | ot_font->h.release_varStore_cache (varStore_cache); |
460 | 0 | ot_font->h.release_advance_cache (advance_cache); |
461 | 0 | return; |
462 | 0 | } |
463 | | |
464 | 0 | const auto &gvar = *ot_face->gvar; |
465 | 0 | if (gvar.has_data ()) |
466 | 0 | { |
467 | 0 | const auto &glyf = *ot_face->glyf; |
468 | 0 | auto *scratch = glyf.acquire_scratch (); |
469 | 0 | if (unlikely (!scratch)) |
470 | 0 | { |
471 | 0 | ot_font->h.release_advance_cache (advance_cache); |
472 | 0 | goto fallback; |
473 | 0 | } |
474 | 0 | OT::hb_scalar_cache_t *gvar_cache = ot_font->draw.acquire_gvar_cache (gvar); |
475 | |
|
476 | 0 | for (unsigned int i = 0; i < count; i++) |
477 | 0 | { |
478 | 0 | hb_position_t v; |
479 | 0 | unsigned cv; |
480 | 0 | if (advance_cache->get (*first_glyph, &cv)) |
481 | 0 | v = cv; |
482 | 0 | else |
483 | 0 | { |
484 | 0 | v = glyf.get_advance_with_var_unscaled (*first_glyph, font, false, *scratch, gvar_cache); |
485 | 0 | advance_cache->set (*first_glyph, v); |
486 | 0 | } |
487 | 0 | *first_advance = font->em_scale_x (v); |
488 | 0 | first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride); |
489 | 0 | first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride); |
490 | 0 | } |
491 | |
|
492 | 0 | ot_font->draw.release_gvar_cache (gvar_cache); |
493 | 0 | glyf.release_scratch (scratch); |
494 | 0 | ot_font->h.release_advance_cache (advance_cache); |
495 | 0 | return; |
496 | 0 | } |
497 | | |
498 | 0 | ot_font->h.release_advance_cache (advance_cache); |
499 | | // No HVAR or GVAR. Just use the fallback non-variable path. |
500 | 0 | goto fallback; |
501 | 0 | #endif |
502 | 0 | } |
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 | 1.58M | { |
514 | | // Duplicated from h_advances. Ugly. Keep in sync'ish. |
515 | | |
516 | 1.58M | const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; |
517 | 1.58M | const hb_ot_face_t *ot_face = ot_font->ot_face; |
518 | 1.58M | const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx; |
519 | | |
520 | 1.58M | if (unlikely (!vmtx.has_data ())) |
521 | 1.58M | { |
522 | 1.58M | hb_font_extents_t font_extents; |
523 | 1.58M | font->get_h_extents_with_fallback (&font_extents); |
524 | 1.58M | hb_position_t advance = font_extents.descender - font_extents.ascender; |
525 | 4.28M | for (unsigned int i = 0; i < count; i++) |
526 | 2.69M | { |
527 | 2.69M | *first_advance = advance; |
528 | 2.69M | first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride); |
529 | 2.69M | } |
530 | 1.58M | return; |
531 | 1.58M | } |
532 | | |
533 | 0 | #ifndef HB_NO_VAR |
534 | 0 | if (!font->has_nonzero_coords) |
535 | 0 | { |
536 | 0 | fallback: |
537 | | #else |
538 | | { |
539 | | #endif |
540 | | // Just plain vtmx data. No need to cache. |
541 | 0 | for (unsigned int i = 0; i < count; i++) |
542 | 0 | { |
543 | 0 | *first_advance = font->em_scale_y (- (int) vmtx.get_advance_without_var_unscaled (*first_glyph)); |
544 | 0 | first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride); |
545 | 0 | first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride); |
546 | 0 | } |
547 | 0 | return; |
548 | 0 | } |
549 | | |
550 | 0 | #ifndef HB_NO_VAR |
551 | | /* has_nonzero_coords. */ |
552 | | |
553 | 0 | ot_font->check_serial (font); |
554 | 0 | hb_ot_font_advance_cache_t *advance_cache = ot_font->v.acquire_advance_cache (); |
555 | 0 | if (!advance_cache) |
556 | 0 | { |
557 | | // malloc failure. Just use the fallback non-variable path. |
558 | 0 | goto fallback; |
559 | 0 | } |
560 | | |
561 | | /* If VVAR is present, use it.*/ |
562 | 0 | const OT::VVAR &VVAR = *vmtx.var_table; |
563 | 0 | if (VVAR.has_data ()) |
564 | 0 | { |
565 | 0 | const OT::ItemVariationStore &varStore = &VVAR + VVAR.varStore; |
566 | 0 | OT::hb_scalar_cache_t *varStore_cache = ot_font->v.acquire_varStore_cache (varStore); |
567 | |
|
568 | 0 | for (unsigned int i = 0; i < count; i++) |
569 | 0 | { |
570 | 0 | hb_position_t v; |
571 | 0 | unsigned cv; |
572 | 0 | if (advance_cache->get (*first_glyph, &cv)) |
573 | 0 | v = cv; |
574 | 0 | else |
575 | 0 | { |
576 | 0 | v = vmtx.get_advance_with_var_unscaled (*first_glyph, font, varStore_cache); |
577 | 0 | advance_cache->set (*first_glyph, v); |
578 | 0 | } |
579 | 0 | *first_advance = font->em_scale_y (- (int) v); |
580 | 0 | first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride); |
581 | 0 | first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride); |
582 | 0 | } |
583 | |
|
584 | 0 | ot_font->v.release_varStore_cache (varStore_cache); |
585 | 0 | ot_font->v.release_advance_cache (advance_cache); |
586 | 0 | return; |
587 | 0 | } |
588 | | |
589 | 0 | const auto &gvar = *ot_face->gvar; |
590 | 0 | if (gvar.has_data ()) |
591 | 0 | { |
592 | 0 | const auto &glyf = *ot_face->glyf; |
593 | 0 | auto *scratch = glyf.acquire_scratch (); |
594 | 0 | if (unlikely (!scratch)) |
595 | 0 | { |
596 | 0 | ot_font->v.release_advance_cache (advance_cache); |
597 | 0 | goto fallback; |
598 | 0 | } |
599 | 0 | OT::hb_scalar_cache_t *gvar_cache = ot_font->draw.acquire_gvar_cache (gvar); |
600 | |
|
601 | 0 | for (unsigned int i = 0; i < count; i++) |
602 | 0 | { |
603 | 0 | hb_position_t v; |
604 | 0 | unsigned cv; |
605 | 0 | if (advance_cache->get (*first_glyph, &cv)) |
606 | 0 | v = cv; |
607 | 0 | else |
608 | 0 | { |
609 | 0 | v = glyf.get_advance_with_var_unscaled (*first_glyph, font, true, *scratch, gvar_cache); |
610 | 0 | advance_cache->set (*first_glyph, v); |
611 | 0 | } |
612 | 0 | *first_advance = font->em_scale_y (- (int) v); |
613 | 0 | first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride); |
614 | 0 | first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride); |
615 | 0 | } |
616 | |
|
617 | 0 | ot_font->draw.release_gvar_cache (gvar_cache); |
618 | 0 | glyf.release_scratch (scratch); |
619 | 0 | ot_font->v.release_advance_cache (advance_cache); |
620 | 0 | return; |
621 | 0 | } |
622 | | |
623 | 0 | ot_font->v.release_advance_cache (advance_cache); |
624 | | // No VVAR or GVAR. Just use the fallback non-variable path. |
625 | 0 | goto fallback; |
626 | 0 | #endif |
627 | 0 | } |
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 | 1.58M | { |
644 | 1.58M | const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; |
645 | 1.58M | 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 | 1.58M | font->get_glyph_h_advances (count, |
649 | 1.58M | first_glyph, glyph_stride, |
650 | 1.58M | first_x, x_stride); |
651 | 4.28M | for (unsigned i = 0; i < count; i++) |
652 | 2.69M | { |
653 | 2.69M | *first_x /= 2; |
654 | 2.69M | first_x = &StructAtOffsetUnaligned<hb_position_t> (first_x, x_stride); |
655 | 2.69M | } |
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 | 1.58M | 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 | 1.58M | const OT::VORG &VORG = *ot_face->VORG; |
666 | 1.58M | if (origin_cache && VORG.has_data ()) |
667 | 0 | { |
668 | 0 | #ifndef HB_NO_VAR |
669 | 0 | if (!font->has_nonzero_coords) |
670 | 0 | #endif |
671 | 0 | { |
672 | 0 | for (unsigned i = 0; i < count; i++) |
673 | 0 | { |
674 | 0 | hb_position_t origin; |
675 | 0 | unsigned cv; |
676 | 0 | 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 | 0 | else |
679 | 0 | { |
680 | 0 | origin = font->em_scalef_y (VORG.get_y_origin (*first_glyph)); |
681 | 0 | origin_cache->set (*first_glyph, font->y_scale < 0 ? -origin : origin); |
682 | 0 | } |
683 | |
|
684 | 0 | *first_y = origin; |
685 | |
|
686 | 0 | first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride); |
687 | 0 | first_y = &StructAtOffsetUnaligned<hb_position_t> (first_y, y_stride); |
688 | 0 | } |
689 | 0 | } |
690 | 0 | #ifndef HB_NO_VAR |
691 | 0 | else |
692 | 0 | { |
693 | 0 | const OT::VVAR &VVAR = *ot_face->vmtx->var_table; |
694 | 0 | const auto &varStore = &VVAR + VVAR.varStore; |
695 | 0 | auto *varStore_cache = ot_font->v_origin.acquire_varStore_cache (varStore); |
696 | 0 | for (unsigned i = 0; i < count; i++) |
697 | 0 | { |
698 | 0 | hb_position_t origin; |
699 | 0 | unsigned cv; |
700 | 0 | 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 | 0 | else |
703 | 0 | { |
704 | 0 | origin = font->em_scalef_y (VORG.get_y_origin (*first_glyph) + |
705 | 0 | VVAR.get_vorg_delta_unscaled (*first_glyph, |
706 | 0 | font->coords, font->num_coords, |
707 | 0 | varStore_cache)); |
708 | 0 | origin_cache->set (*first_glyph, font->y_scale < 0 ? -origin : origin); |
709 | 0 | } |
710 | |
|
711 | 0 | *first_y = origin; |
712 | |
|
713 | 0 | first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride); |
714 | 0 | first_y = &StructAtOffsetUnaligned<hb_position_t> (first_y, y_stride); |
715 | 0 | } |
716 | 0 | ot_font->v_origin.release_varStore_cache (varStore_cache); |
717 | 0 | } |
718 | 0 | #endif |
719 | 0 | ot_font->v_origin.release_origin_cache (origin_cache); |
720 | 0 | return true; |
721 | 0 | } |
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 | 1.58M | const auto &vmtx = *ot_face->vmtx; |
726 | 1.58M | const auto &glyf = *ot_face->glyf; |
727 | 1.58M | if (origin_cache && vmtx.has_data() && glyf.has_data ()) |
728 | 0 | { |
729 | 0 | auto *scratch = glyf.acquire_scratch (); |
730 | 0 | if (unlikely (!scratch)) |
731 | 0 | { |
732 | 0 | ot_font->v_origin.release_origin_cache (origin_cache); |
733 | 0 | return false; |
734 | 0 | } |
735 | 0 | OT::hb_scalar_cache_t *gvar_cache = font->has_nonzero_coords ? |
736 | 0 | ot_font->draw.acquire_gvar_cache (*ot_face->gvar) : |
737 | 0 | nullptr; |
738 | |
|
739 | 0 | for (unsigned i = 0; i < count; i++) |
740 | 0 | { |
741 | 0 | hb_position_t origin; |
742 | 0 | unsigned cv; |
743 | 0 | 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 | 0 | else |
746 | 0 | { |
747 | 0 | origin = font->em_scalef_y (glyf.get_v_origin_with_var_unscaled (*first_glyph, font, *scratch, gvar_cache)); |
748 | 0 | origin_cache->set (*first_glyph, font->y_scale < 0 ? -origin : origin); |
749 | 0 | } |
750 | |
|
751 | 0 | *first_y = origin; |
752 | |
|
753 | 0 | first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride); |
754 | 0 | first_y = &StructAtOffsetUnaligned<hb_position_t> (first_y, y_stride); |
755 | 0 | } |
756 | |
|
757 | 0 | if (gvar_cache) |
758 | 0 | ot_font->draw.release_gvar_cache (gvar_cache); |
759 | 0 | glyf.release_scratch (scratch); |
760 | 0 | ot_font->v_origin.release_origin_cache (origin_cache); |
761 | 0 | return true; |
762 | 0 | } |
763 | | |
764 | | /* Otherwise, use glyph extents to center the glyph vertically. |
765 | | * If getting glyph extents failed, just use the font ascender. */ |
766 | 1.58M | if (origin_cache && font->has_glyph_extents_func ()) |
767 | 1.58M | { |
768 | 1.58M | hb_font_extents_t font_extents; |
769 | 1.58M | font->get_h_extents_with_fallback (&font_extents); |
770 | 1.58M | hb_position_t font_advance = font_extents.ascender - font_extents.descender; |
771 | | |
772 | 4.28M | for (unsigned i = 0; i < count; i++) |
773 | 2.69M | { |
774 | 2.69M | hb_position_t origin; |
775 | 2.69M | unsigned cv; |
776 | | |
777 | 2.69M | if (origin_cache->get (*first_glyph, &cv)) |
778 | 2.69M | origin = font->y_scale < 0 ? -static_cast<hb_position_t>(cv) : static_cast<hb_position_t>(cv); |
779 | 3.29k | else |
780 | 3.29k | { |
781 | 3.29k | hb_glyph_extents_t extents = {0}; |
782 | 3.29k | if (likely (font->get_glyph_extents (*first_glyph, &extents))) |
783 | 3.29k | origin = extents.y_bearing + ((font_advance - -extents.height) >> 1); |
784 | 0 | else |
785 | 0 | origin = font_extents.ascender; |
786 | | |
787 | 3.29k | origin_cache->set (*first_glyph, font->y_scale < 0 ? -origin : origin); |
788 | 3.29k | } |
789 | | |
790 | 2.69M | *first_y = origin; |
791 | | |
792 | 2.69M | first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride); |
793 | 2.69M | first_y = &StructAtOffsetUnaligned<hb_position_t> (first_y, y_stride); |
794 | 2.69M | } |
795 | 1.58M | } |
796 | | |
797 | 1.58M | ot_font->v_origin.release_origin_cache (origin_cache); |
798 | 1.58M | return true; |
799 | 1.58M | } |
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 | 652k | { |
809 | 652k | const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; |
810 | 652k | const hb_ot_face_t *ot_face = ot_font->ot_face; |
811 | | |
812 | 652k | #if !defined(HB_NO_OT_FONT_BITMAP) && !defined(HB_NO_COLOR) |
813 | 652k | if (ot_face->sbix->get_extents (font, glyph, extents)) return true; |
814 | 652k | if (ot_face->CBDT->get_extents (font, glyph, extents)) return true; |
815 | 652k | #endif |
816 | 652k | #if !defined(HB_NO_COLOR) && !defined(HB_NO_PAINT) |
817 | 652k | if (ot_face->COLR->get_extents (font, glyph, extents)) return true; |
818 | 652k | #endif |
819 | 652k | #ifndef HB_NO_VAR_COMPOSITES |
820 | 652k | if (ot_face->VARC->get_extents (font, glyph, extents)) return true; |
821 | 652k | #endif |
822 | 652k | if (ot_face->glyf->get_extents (font, glyph, extents)) return true; |
823 | 0 | #ifndef HB_NO_OT_FONT_CFF |
824 | 0 | if (ot_face->cff2->get_extents (font, glyph, extents)) return true; |
825 | 0 | if (ot_face->cff1->get_extents (font, glyph, extents)) return true; |
826 | 0 | #endif |
827 | | |
828 | 0 | return false; |
829 | 0 | } |
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 | 0 | { |
839 | 0 | const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; |
840 | 0 | const hb_ot_face_t *ot_face = ot_font->ot_face; |
841 | |
|
842 | 0 | if (ot_face->post->get_glyph_name (glyph, name, size)) return true; |
843 | 0 | #ifndef HB_NO_OT_FONT_CFF |
844 | 0 | if (ot_face->cff1->get_glyph_name (glyph, name, size)) return true; |
845 | 0 | #endif |
846 | 0 | return false; |
847 | 0 | } |
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 | 0 | { |
855 | 0 | const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; |
856 | 0 | const hb_ot_face_t *ot_face = ot_font->ot_face; |
857 | |
|
858 | 0 | if (ot_face->post->get_glyph_from_name (name, len, glyph)) return true; |
859 | 0 | #ifndef HB_NO_OT_FONT_CFF |
860 | 0 | if (ot_face->cff1->get_glyph_from_name (name, len, glyph)) return true; |
861 | 0 | #endif |
862 | 0 | return false; |
863 | 0 | } |
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 | 3.45M | { |
872 | 3.45M | return _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER, &metrics->ascender) && |
873 | 3.45M | _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER, &metrics->descender) && |
874 | 3.45M | _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP, &metrics->line_gap); |
875 | 3.45M | } |
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 | 0 | { |
898 | 0 | const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; |
899 | 0 | hb_draw_session_t draw_session {draw_funcs, draw_data}; |
900 | 0 | bool ret = false; |
901 | |
|
902 | 0 | OT::hb_scalar_cache_t *gvar_cache = nullptr; |
903 | 0 | if (font->num_coords) |
904 | 0 | { |
905 | 0 | ot_font->check_serial (font); |
906 | 0 | gvar_cache = ot_font->draw.acquire_gvar_cache (*ot_font->ot_face->gvar); |
907 | 0 | } |
908 | |
|
909 | 0 | #ifndef HB_NO_VAR_COMPOSITES |
910 | 0 | if (font->face->table.VARC->get_path (font, glyph, draw_session)) { ret = true; goto done; } |
911 | 0 | #endif |
912 | | // Keep the following in synch with VARC::get_path_at() |
913 | 0 | if (font->face->table.glyf->get_path (font, glyph, draw_session, gvar_cache)) { ret = true; goto done; } |
914 | | |
915 | 0 | #ifndef HB_NO_CFF |
916 | 0 | if (font->face->table.cff2->get_path (font, glyph, draw_session)) { ret = true; goto done; } |
917 | 0 | if (font->face->table.cff1->get_path (font, glyph, draw_session)) { ret = true; goto done; } |
918 | 0 | #endif |
919 | | |
920 | 0 | done: |
921 | |
|
922 | 0 | ot_font->draw.release_gvar_cache (gvar_cache); |
923 | |
|
924 | 0 | return ret; |
925 | 0 | } |
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 | 0 | { |
938 | 0 | #ifndef HB_NO_COLOR |
939 | 0 | if (font->face->table.COLR->paint_glyph (font, glyph, paint_funcs, paint_data, palette, foreground)) return true; |
940 | 0 | if (font->face->table.SVG->paint_glyph (font, glyph, paint_funcs, paint_data)) return true; |
941 | 0 | #ifndef HB_NO_OT_FONT_BITMAP |
942 | 0 | if (font->face->table.CBDT->paint_glyph (font, glyph, paint_funcs, paint_data)) return true; |
943 | 0 | if (font->face->table.sbix->paint_glyph (font, glyph, paint_funcs, paint_data)) return true; |
944 | 0 | #endif |
945 | 0 | #endif |
946 | 0 | return false; |
947 | 0 | } |
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 | 28 | { |
956 | 28 | hb_font_funcs_t *funcs = hb_font_funcs_create (); |
957 | | |
958 | 28 | hb_font_funcs_set_nominal_glyph_func (funcs, hb_ot_get_nominal_glyph, nullptr, nullptr); |
959 | 28 | hb_font_funcs_set_nominal_glyphs_func (funcs, hb_ot_get_nominal_glyphs, nullptr, nullptr); |
960 | 28 | hb_font_funcs_set_variation_glyph_func (funcs, hb_ot_get_variation_glyph, nullptr, nullptr); |
961 | | |
962 | 28 | hb_font_funcs_set_font_h_extents_func (funcs, hb_ot_get_font_h_extents, nullptr, nullptr); |
963 | 28 | hb_font_funcs_set_glyph_h_advances_func (funcs, hb_ot_get_glyph_h_advances, nullptr, nullptr); |
964 | | |
965 | 28 | #ifndef HB_NO_VERTICAL |
966 | 28 | hb_font_funcs_set_font_v_extents_func (funcs, hb_ot_get_font_v_extents, nullptr, nullptr); |
967 | 28 | hb_font_funcs_set_glyph_v_advances_func (funcs, hb_ot_get_glyph_v_advances, nullptr, nullptr); |
968 | 28 | hb_font_funcs_set_glyph_v_origins_func (funcs, hb_ot_get_glyph_v_origins, nullptr, nullptr); |
969 | 28 | #endif |
970 | | |
971 | 28 | #ifndef HB_NO_DRAW |
972 | 28 | hb_font_funcs_set_draw_glyph_or_fail_func (funcs, hb_ot_draw_glyph_or_fail, nullptr, nullptr); |
973 | 28 | #endif |
974 | | |
975 | 28 | #ifndef HB_NO_PAINT |
976 | 28 | hb_font_funcs_set_paint_glyph_or_fail_func (funcs, hb_ot_paint_glyph_or_fail, nullptr, nullptr); |
977 | 28 | #endif |
978 | | |
979 | 28 | 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 | 28 | #ifndef HB_NO_OT_FONT_GLYPH_NAMES |
983 | 28 | hb_font_funcs_set_glyph_name_func (funcs, hb_ot_get_glyph_name, nullptr, nullptr); |
984 | 28 | hb_font_funcs_set_glyph_from_name_func (funcs, hb_ot_get_glyph_from_name, nullptr, nullptr); |
985 | 28 | #endif |
986 | | |
987 | 28 | hb_font_funcs_make_immutable (funcs); |
988 | | |
989 | 28 | hb_atexit (free_static_ot_funcs); |
990 | | |
991 | 28 | return funcs; |
992 | 28 | } |
993 | | } static_ot_funcs; |
994 | | |
995 | | static inline |
996 | | void free_static_ot_funcs () |
997 | 28 | { |
998 | 28 | static_ot_funcs.free_instance (); |
999 | 28 | } |
1000 | | |
1001 | | static hb_font_funcs_t * |
1002 | | _hb_ot_get_font_funcs () |
1003 | 412k | { |
1004 | 412k | return static_ot_funcs.get_unconst (); |
1005 | 412k | } |
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 | 412k | { |
1021 | 412k | hb_ot_font_t *ot_font = _hb_ot_font_create (font); |
1022 | 412k | if (unlikely (!ot_font)) |
1023 | 0 | return; |
1024 | | |
1025 | 412k | hb_font_set_funcs (font, |
1026 | 412k | _hb_ot_get_font_funcs (), |
1027 | 412k | ot_font, |
1028 | 412k | _hb_ot_font_destroy); |
1029 | 412k | } |
1030 | | |
1031 | | #endif |