/work/workdir/UnpackedTarball/harfbuzz/src/hb-face.cc
Line | Count | Source |
1 | | /* |
2 | | * Copyright © 2009 Red Hat, Inc. |
3 | | * Copyright © 2012 Google, Inc. |
4 | | * |
5 | | * This is part of HarfBuzz, a text shaping library. |
6 | | * |
7 | | * Permission is hereby granted, without written agreement and without |
8 | | * license or royalty fees, to use, copy, modify, and distribute this |
9 | | * software and its documentation for any purpose, provided that the |
10 | | * above copyright notice and the following two paragraphs appear in |
11 | | * all copies of this software. |
12 | | * |
13 | | * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR |
14 | | * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES |
15 | | * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN |
16 | | * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH |
17 | | * DAMAGE. |
18 | | * |
19 | | * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, |
20 | | * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND |
21 | | * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS |
22 | | * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO |
23 | | * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. |
24 | | * |
25 | | * Red Hat Author(s): Behdad Esfahbod |
26 | | * Google Author(s): Behdad Esfahbod |
27 | | */ |
28 | | |
29 | | #include "hb.hh" |
30 | | |
31 | | #include "hb-face.hh" |
32 | | #include "hb-blob.hh" |
33 | | #include "hb-open-file.hh" |
34 | | #include "hb-ot-face.hh" |
35 | | #include "hb-ot-cmap-table.hh" |
36 | | |
37 | | #ifdef HAVE_FREETYPE |
38 | | #include "hb-ft.h" |
39 | | #endif |
40 | | #ifdef HAVE_CORETEXT |
41 | | #include "hb-coretext.h" |
42 | | #endif |
43 | | #ifdef HAVE_DIRECTWRITE |
44 | | #include "hb-directwrite.h" |
45 | | #endif |
46 | | |
47 | | |
48 | | /** |
49 | | * SECTION:hb-face |
50 | | * @title: hb-face |
51 | | * @short_description: Font face objects |
52 | | * @include: hb.h |
53 | | * |
54 | | * A font face is an object that represents a single face from within a |
55 | | * font family. |
56 | | * |
57 | | * More precisely, a font face represents a single face in a binary font file. |
58 | | * Font faces are typically built from a binary blob and a face index. |
59 | | * Font faces are used to create fonts. |
60 | | * |
61 | | * A font face can be created from a binary blob using hb_face_create(). |
62 | | * The face index is used to select a face from a binary blob that contains |
63 | | * multiple faces. For example, a binary blob that contains both a regular |
64 | | * and a bold face can be used to create two font faces, one for each face |
65 | | * index. |
66 | | **/ |
67 | | |
68 | | |
69 | | /** |
70 | | * hb_face_count: |
71 | | * @blob: a blob. |
72 | | * |
73 | | * Fetches the number of faces in a blob. |
74 | | * |
75 | | * Return value: Number of faces in @blob |
76 | | * |
77 | | * Since: 1.7.7 |
78 | | **/ |
79 | | unsigned int |
80 | | hb_face_count (hb_blob_t *blob) |
81 | 0 | { |
82 | 0 | if (unlikely (!blob)) |
83 | 0 | return 0; |
84 | | |
85 | 0 | hb_sanitize_context_t c (blob); |
86 | |
|
87 | 0 | auto *ot = blob->as<OT::OpenTypeFontFile> (); |
88 | 0 | if (unlikely (!ot->sanitize (&c))) |
89 | 0 | return 0; |
90 | | |
91 | 0 | return ot->get_face_count (); |
92 | 0 | } |
93 | | |
94 | | /* |
95 | | * hb_face_t |
96 | | */ |
97 | | |
98 | | DEFINE_NULL_INSTANCE (hb_face_t) = |
99 | | { |
100 | | HB_OBJECT_HEADER_STATIC, |
101 | | |
102 | | 0, /* index */ |
103 | | 1000, /* upem */ |
104 | | 0, /* num_glyphs */ |
105 | | |
106 | | /* Zero for the rest is fine. */ |
107 | | }; |
108 | | |
109 | | |
110 | | /** |
111 | | * hb_face_create_for_tables: |
112 | | * @reference_table_func: (closure user_data) (destroy destroy) (scope notified): Table-referencing function |
113 | | * @user_data: A pointer to the user data |
114 | | * @destroy: (nullable): A callback to call when @data is not needed anymore |
115 | | * |
116 | | * Variant of hb_face_create(), built for those cases where it is more |
117 | | * convenient to provide data for individual tables instead of the whole font |
118 | | * data. With the caveat that hb_face_get_table_tags() would not work |
119 | | * with faces created this way. You can address that by calling the |
120 | | * hb_face_set_get_table_tags_func() function and setting the appropriate callback. |
121 | | * |
122 | | * Creates a new face object from the specified @user_data and @reference_table_func, |
123 | | * with the @destroy callback. |
124 | | * |
125 | | * Return value: (transfer full): The new face object |
126 | | * |
127 | | * Since: 0.9.2 |
128 | | **/ |
129 | | hb_face_t * |
130 | | hb_face_create_for_tables (hb_reference_table_func_t reference_table_func, |
131 | | void *user_data, |
132 | | hb_destroy_func_t destroy) |
133 | 59 | { |
134 | 59 | hb_face_t *face; |
135 | | |
136 | 59 | if (!reference_table_func || !(face = hb_object_create<hb_face_t> ())) { |
137 | 0 | if (destroy) |
138 | 0 | destroy (user_data); |
139 | 0 | return hb_face_get_empty (); |
140 | 0 | } |
141 | | |
142 | 59 | face->reference_table_func = reference_table_func; |
143 | 59 | face->user_data = user_data; |
144 | 59 | face->destroy = destroy; |
145 | | |
146 | 59 | face->num_glyphs = -1; |
147 | | |
148 | 59 | face->data.init0 (face); |
149 | 59 | face->table.init0 (face); |
150 | | |
151 | 59 | return face; |
152 | 59 | } |
153 | | |
154 | | |
155 | | typedef struct hb_face_for_data_closure_t { |
156 | | hb_blob_t *blob; |
157 | | uint16_t index; |
158 | | } hb_face_for_data_closure_t; |
159 | | |
160 | | static hb_face_for_data_closure_t * |
161 | | _hb_face_for_data_closure_create (hb_blob_t *blob, unsigned int index) |
162 | 59 | { |
163 | 59 | hb_face_for_data_closure_t *closure; |
164 | | |
165 | 59 | closure = (hb_face_for_data_closure_t *) hb_calloc (1, sizeof (hb_face_for_data_closure_t)); |
166 | 59 | if (unlikely (!closure)) |
167 | 0 | return nullptr; |
168 | | |
169 | 59 | closure->blob = blob; |
170 | 59 | closure->index = (uint16_t) (index & 0xFFFFu); |
171 | | |
172 | 59 | return closure; |
173 | 59 | } |
174 | | |
175 | | static void |
176 | | _hb_face_for_data_closure_destroy (void *data) |
177 | 0 | { |
178 | 0 | hb_face_for_data_closure_t *closure = (hb_face_for_data_closure_t *) data; |
179 | |
|
180 | 0 | hb_blob_destroy (closure->blob); |
181 | 0 | hb_free (closure); |
182 | 0 | } |
183 | | |
184 | | static hb_blob_t * |
185 | | _hb_face_for_data_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data) |
186 | 37.2M | { |
187 | 37.2M | hb_face_for_data_closure_t *data = (hb_face_for_data_closure_t *) user_data; |
188 | | |
189 | 37.2M | if (tag == HB_TAG_NONE) |
190 | 0 | return hb_blob_reference (data->blob); |
191 | | |
192 | 37.2M | const OT::OpenTypeFontFile &ot_file = *data->blob->as<OT::OpenTypeFontFile> (); |
193 | 37.2M | unsigned int base_offset; |
194 | 37.2M | const OT::OpenTypeFontFace &ot_face = ot_file.get_face (data->index, &base_offset); |
195 | | |
196 | 37.2M | const OT::OpenTypeTable &table = ot_face.get_table_by_tag (tag); |
197 | | |
198 | 37.2M | hb_blob_t *blob = hb_blob_create_sub_blob (data->blob, base_offset + table.offset, table.length); |
199 | | |
200 | 37.2M | return blob; |
201 | 37.2M | } |
202 | | |
203 | | static unsigned |
204 | | _hb_face_for_data_get_table_tags (const hb_face_t *face HB_UNUSED, |
205 | | unsigned int start_offset, |
206 | | unsigned int *table_count, |
207 | | hb_tag_t *table_tags, |
208 | | void *user_data) |
209 | 0 | { |
210 | 0 | hb_face_for_data_closure_t *data = (hb_face_for_data_closure_t *) user_data; |
211 | |
|
212 | 0 | const OT::OpenTypeFontFile &ot_file = *data->blob->as<OT::OpenTypeFontFile> (); |
213 | 0 | const OT::OpenTypeFontFace &ot_face = ot_file.get_face (data->index); |
214 | |
|
215 | 0 | return ot_face.get_table_tags (start_offset, table_count, table_tags); |
216 | 0 | } |
217 | | |
218 | | |
219 | | /** |
220 | | * hb_face_create: |
221 | | * @blob: #hb_blob_t to work upon |
222 | | * @index: The index of the face within @blob |
223 | | * |
224 | | * Constructs a new face object from the specified blob and |
225 | | * a face index into that blob. |
226 | | * |
227 | | * The face index is used for blobs of file formats such as TTC and |
228 | | * DFont that can contain more than one face. Face indices within |
229 | | * such collections are zero-based. |
230 | | * |
231 | | * <note>Note: If the blob font format is not a collection, @index |
232 | | * is ignored. Otherwise, only the lower 16-bits of @index are used. |
233 | | * The unmodified @index can be accessed via hb_face_get_index().</note> |
234 | | * |
235 | | * <note>Note: The high 16-bits of @index, if non-zero, are used by |
236 | | * hb_font_create() to load named-instances in variable fonts. See |
237 | | * hb_font_create() for details.</note> |
238 | | * |
239 | | * Return value: (transfer full): The new face object |
240 | | * |
241 | | * Since: 0.9.2 |
242 | | **/ |
243 | | hb_face_t * |
244 | | hb_face_create (hb_blob_t *blob, |
245 | | unsigned int index) |
246 | 59 | { |
247 | 59 | hb_face_t *face; |
248 | | |
249 | 59 | if (unlikely (!blob)) |
250 | 0 | blob = hb_blob_get_empty (); |
251 | | |
252 | 59 | blob = hb_sanitize_context_t ().sanitize_blob<OT::OpenTypeFontFile> (hb_blob_reference (blob)); |
253 | | |
254 | 59 | hb_face_for_data_closure_t *closure = _hb_face_for_data_closure_create (blob, index); |
255 | | |
256 | 59 | if (unlikely (!closure)) |
257 | 0 | { |
258 | 0 | hb_blob_destroy (blob); |
259 | 0 | return hb_face_get_empty (); |
260 | 0 | } |
261 | | |
262 | 59 | face = hb_face_create_for_tables (_hb_face_for_data_reference_table, |
263 | 59 | closure, |
264 | 59 | _hb_face_for_data_closure_destroy); |
265 | 59 | hb_face_set_get_table_tags_func (face, |
266 | 59 | _hb_face_for_data_get_table_tags, |
267 | 59 | closure, |
268 | 59 | nullptr); |
269 | | |
270 | 59 | face->index = index; |
271 | | |
272 | 59 | return face; |
273 | 59 | } |
274 | | |
275 | | /** |
276 | | * hb_face_create_or_fail: |
277 | | * @blob: #hb_blob_t to work upon |
278 | | * @index: The index of the face within @blob |
279 | | * |
280 | | * Like hb_face_create(), but returns `NULL` if the blob data |
281 | | * contains no usable font face at the specified index. |
282 | | * |
283 | | * Return value: (transfer full): The new face object, or `NULL` if |
284 | | * no face is found at the specified index. |
285 | | * |
286 | | * Since: 10.1.0 |
287 | | **/ |
288 | | hb_face_t * |
289 | | hb_face_create_or_fail (hb_blob_t *blob, |
290 | | unsigned int index) |
291 | 0 | { |
292 | 0 | unsigned num_faces = hb_face_count (blob); |
293 | 0 | if (index >= num_faces) |
294 | 0 | return nullptr; |
295 | | |
296 | 0 | hb_face_t *face = hb_face_create (blob, index); |
297 | 0 | if (hb_object_is_immutable (face)) |
298 | 0 | return nullptr; |
299 | | |
300 | 0 | return face; |
301 | 0 | } |
302 | | |
303 | | #ifndef HB_NO_OPEN |
304 | | /** |
305 | | * hb_face_create_from_file_or_fail: |
306 | | * @file_name: A font filename |
307 | | * @index: The index of the face within the file |
308 | | * |
309 | | * A thin wrapper around hb_blob_create_from_file_or_fail() |
310 | | * followed by hb_face_create_or_fail(). |
311 | | * |
312 | | * Return value: (transfer full): The new face object, or `NULL` if |
313 | | * no face is found at the specified index or the file cannot be read. |
314 | | * |
315 | | * Since: 10.1.0 |
316 | | **/ |
317 | | HB_EXTERN hb_face_t * |
318 | | hb_face_create_from_file_or_fail (const char *file_name, |
319 | | unsigned int index) |
320 | 0 | { |
321 | 0 | hb_blob_t *blob = hb_blob_create_from_file_or_fail (file_name); |
322 | 0 | if (unlikely (!blob)) |
323 | 0 | return nullptr; |
324 | | |
325 | 0 | hb_face_t *face = hb_face_create_or_fail (blob, index); |
326 | 0 | hb_blob_destroy (blob); |
327 | |
|
328 | 0 | return face; |
329 | 0 | } |
330 | | |
331 | | static const struct supported_face_loaders_t { |
332 | | char name[16]; |
333 | | hb_face_t * (*from_file) (const char *font_file, unsigned face_index); |
334 | | hb_face_t * (*from_blob) (hb_blob_t *blob, unsigned face_index); |
335 | | } supported_face_loaders[] = |
336 | | { |
337 | | {"ot", |
338 | | #ifndef HB_NO_OPEN |
339 | | hb_face_create_from_file_or_fail, |
340 | | #else |
341 | | nullptr, |
342 | | #endif |
343 | | hb_face_create_or_fail |
344 | | }, |
345 | | #ifdef HAVE_FREETYPE |
346 | | {"ft", |
347 | | hb_ft_face_create_from_file_or_fail, |
348 | | hb_ft_face_create_from_blob_or_fail |
349 | | }, |
350 | | #endif |
351 | | #ifdef HAVE_CORETEXT |
352 | | {"coretext", |
353 | | hb_coretext_face_create_from_file_or_fail, |
354 | | hb_coretext_face_create_from_blob_or_fail |
355 | | }, |
356 | | #endif |
357 | | #ifdef HAVE_DIRECTWRITE |
358 | | {"directwrite", |
359 | | hb_directwrite_face_create_from_file_or_fail, |
360 | | hb_directwrite_face_create_from_blob_or_fail |
361 | | }, |
362 | | #endif |
363 | | }; |
364 | | |
365 | | static const char *get_default_loader_name () |
366 | 0 | { |
367 | 0 | static hb_atomic_t<const char *> static_loader_name; |
368 | 0 | const char *loader_name = static_loader_name.get_acquire (); |
369 | 0 | if (!loader_name) |
370 | 0 | { |
371 | 0 | loader_name = getenv ("HB_FACE_LOADER"); |
372 | 0 | if (!loader_name) |
373 | 0 | loader_name = ""; |
374 | 0 | if (!static_loader_name.cmpexch (nullptr, loader_name)) |
375 | 0 | loader_name = static_loader_name.get_acquire (); |
376 | 0 | } |
377 | 0 | return loader_name; |
378 | 0 | } |
379 | | |
380 | | /** |
381 | | * hb_face_create_from_file_or_fail_using: |
382 | | * @file_name: A font filename |
383 | | * @index: The index of the face within the file |
384 | | * @loader_name: (nullable): The name of the loader to use, or `NULL` |
385 | | * |
386 | | * A thin wrapper around the face loader functions registered with HarfBuzz. |
387 | | * If @loader_name is `NULL` or the empty string, the first available loader |
388 | | * is used. |
389 | | * |
390 | | * For example, the FreeType ("ft") loader might be able to load |
391 | | * WOFF and WOFF2 files if FreeType is built with those features, |
392 | | * whereas the OpenType ("ot") loader will not. |
393 | | * |
394 | | * Return value: (transfer full): The new face object, or `NULL` if |
395 | | * the file cannot be read or the loader fails to load the face. |
396 | | * |
397 | | * Since: 11.0.0 |
398 | | **/ |
399 | | hb_face_t * |
400 | | hb_face_create_from_file_or_fail_using (const char *file_name, |
401 | | unsigned int index, |
402 | | const char *loader_name) |
403 | 0 | { |
404 | | // Duplicated in hb_face_create_or_fail_using |
405 | 0 | bool retry = false; |
406 | 0 | if (!loader_name || !*loader_name) |
407 | 0 | { |
408 | 0 | loader_name = get_default_loader_name (); |
409 | 0 | retry = true; |
410 | 0 | } |
411 | 0 | if (loader_name && !*loader_name) loader_name = nullptr; |
412 | |
|
413 | 0 | retry: |
414 | 0 | for (unsigned i = 0; i < ARRAY_LENGTH (supported_face_loaders); i++) |
415 | 0 | { |
416 | 0 | if (!loader_name || (supported_face_loaders[i].from_file && !strcmp (supported_face_loaders[i].name, loader_name))) |
417 | 0 | return supported_face_loaders[i].from_file (file_name, index); |
418 | 0 | } |
419 | | |
420 | 0 | if (retry) |
421 | 0 | { |
422 | 0 | retry = false; |
423 | 0 | loader_name = nullptr; |
424 | 0 | goto retry; |
425 | 0 | } |
426 | | |
427 | 0 | return nullptr; |
428 | 0 | } |
429 | | |
430 | | /** |
431 | | * hb_face_create_or_fail_using: |
432 | | * @blob: #hb_blob_t to work upon |
433 | | * @index: The index of the face within @blob |
434 | | * @loader_name: (nullable): The name of the loader to use, or `NULL` |
435 | | * |
436 | | * A thin wrapper around the face loader functions registered with HarfBuzz. |
437 | | * If @loader_name is `NULL` or the empty string, the first available loader |
438 | | * is used. |
439 | | * |
440 | | * For example, the FreeType ("ft") loader might be able to load |
441 | | * WOFF and WOFF2 files if FreeType is built with those features, |
442 | | * whereas the OpenType ("ot") loader will not. |
443 | | * |
444 | | * Return value: (transfer full): The new face object, or `NULL` if |
445 | | * the loader fails to load the face. |
446 | | * |
447 | | * Since: 11.0.0 |
448 | | **/ |
449 | | hb_face_t * |
450 | | hb_face_create_or_fail_using (hb_blob_t *blob, |
451 | | unsigned int index, |
452 | | const char *loader_name) |
453 | 0 | { |
454 | | // Duplicated in hb_face_create_from_file_or_fail_using |
455 | 0 | bool retry = false; |
456 | 0 | if (!loader_name || !*loader_name) |
457 | 0 | { |
458 | 0 | loader_name = get_default_loader_name (); |
459 | 0 | retry = true; |
460 | 0 | } |
461 | 0 | if (loader_name && !*loader_name) loader_name = nullptr; |
462 | |
|
463 | 0 | retry: |
464 | 0 | for (unsigned i = 0; i < ARRAY_LENGTH (supported_face_loaders); i++) |
465 | 0 | { |
466 | 0 | if (!loader_name || (supported_face_loaders[i].from_blob && !strcmp (supported_face_loaders[i].name, loader_name))) |
467 | 0 | return supported_face_loaders[i].from_blob (blob, index); |
468 | 0 | } |
469 | | |
470 | 0 | if (retry) |
471 | 0 | { |
472 | 0 | retry = false; |
473 | 0 | loader_name = nullptr; |
474 | 0 | goto retry; |
475 | 0 | } |
476 | | |
477 | 0 | return nullptr; |
478 | 0 | } |
479 | | |
480 | | static inline void free_static_face_loader_list (); |
481 | | |
482 | | static const char * const nil_face_loader_list[] = {nullptr}; |
483 | | |
484 | | static struct hb_face_loader_list_lazy_loader_t : hb_lazy_loader_t<const char *, |
485 | | hb_face_loader_list_lazy_loader_t> |
486 | | { |
487 | | static const char ** create () |
488 | 0 | { |
489 | 0 | const char **face_loader_list = (const char **) hb_calloc (1 + ARRAY_LENGTH (supported_face_loaders), sizeof (const char *)); |
490 | 0 | if (unlikely (!face_loader_list)) |
491 | 0 | return nullptr; |
492 | | |
493 | 0 | unsigned i; |
494 | 0 | for (i = 0; i < ARRAY_LENGTH (supported_face_loaders); i++) |
495 | 0 | face_loader_list[i] = supported_face_loaders[i].name; |
496 | 0 | face_loader_list[i] = nullptr; |
497 | |
|
498 | 0 | hb_atexit (free_static_face_loader_list); |
499 | |
|
500 | 0 | return face_loader_list; |
501 | 0 | } |
502 | | static void destroy (const char **l) |
503 | 0 | { hb_free (l); } |
504 | | static const char * const * get_null () |
505 | 0 | { return nil_face_loader_list; } |
506 | | } static_face_loader_list; |
507 | | |
508 | | static inline |
509 | | void free_static_face_loader_list () |
510 | 0 | { |
511 | 0 | static_face_loader_list.free_instance (); |
512 | 0 | } |
513 | | |
514 | | /** |
515 | | * hb_face_list_loaders: |
516 | | * |
517 | | * Retrieves the list of face loaders supported by HarfBuzz. |
518 | | * |
519 | | * Return value: (transfer none) (array zero-terminated=1): a |
520 | | * `NULL`-terminated array of supported face loaders |
521 | | * constant strings. The returned array is owned by HarfBuzz |
522 | | * and should not be modified or freed. |
523 | | * |
524 | | * Since: 11.0.0 |
525 | | **/ |
526 | | const char ** |
527 | | hb_face_list_loaders () |
528 | 0 | { |
529 | 0 | return static_face_loader_list.get_unconst (); |
530 | 0 | } |
531 | | #endif |
532 | | |
533 | | |
534 | | /** |
535 | | * hb_face_get_empty: |
536 | | * |
537 | | * Fetches the singleton empty face object. |
538 | | * |
539 | | * Return value: (transfer full): The empty face object |
540 | | * |
541 | | * Since: 0.9.2 |
542 | | **/ |
543 | | hb_face_t * |
544 | | hb_face_get_empty () |
545 | 0 | { |
546 | 0 | return const_cast<hb_face_t *> (&Null (hb_face_t)); |
547 | 0 | } |
548 | | |
549 | | |
550 | | /** |
551 | | * hb_face_reference: (skip) |
552 | | * @face: A face object |
553 | | * |
554 | | * Increases the reference count on a face object. |
555 | | * |
556 | | * Return value: The @face object |
557 | | * |
558 | | * Since: 0.9.2 |
559 | | **/ |
560 | | hb_face_t * |
561 | | hb_face_reference (hb_face_t *face) |
562 | 213k | { |
563 | 213k | return hb_object_reference (face); |
564 | 213k | } |
565 | | |
566 | | /** |
567 | | * hb_face_destroy: (skip) |
568 | | * @face: A face object |
569 | | * |
570 | | * Decreases the reference count on a face object. When the |
571 | | * reference count reaches zero, the face is destroyed, |
572 | | * freeing all memory. |
573 | | * |
574 | | * Since: 0.9.2 |
575 | | **/ |
576 | | void |
577 | | hb_face_destroy (hb_face_t *face) |
578 | 212k | { |
579 | 212k | if (!hb_object_destroy (face)) return; |
580 | | |
581 | 0 | #ifndef HB_NO_SHAPER |
582 | 0 | for (hb_face_t::plan_node_t *node = face->shape_plans; node; ) |
583 | 0 | { |
584 | 0 | hb_face_t::plan_node_t *next = node->next; |
585 | 0 | hb_shape_plan_destroy (node->shape_plan); |
586 | 0 | hb_free (node); |
587 | 0 | node = next; |
588 | 0 | } |
589 | 0 | #endif |
590 | |
|
591 | 0 | face->data.fini (); |
592 | 0 | face->table.fini (); |
593 | |
|
594 | 0 | if (face->get_table_tags_destroy) |
595 | 0 | face->get_table_tags_destroy (face->get_table_tags_user_data); |
596 | |
|
597 | 0 | if (face->destroy) |
598 | 0 | face->destroy (face->user_data); |
599 | |
|
600 | 0 | hb_free (face); |
601 | 0 | } |
602 | | |
603 | | /** |
604 | | * hb_face_set_user_data: (skip) |
605 | | * @face: A face object |
606 | | * @key: The user-data key to set |
607 | | * @data: A pointer to the user data |
608 | | * @destroy: (nullable): A callback to call when @data is not needed anymore |
609 | | * @replace: Whether to replace an existing data with the same key |
610 | | * |
611 | | * Attaches a user-data key/data pair to the given face object. |
612 | | * |
613 | | * Return value: `true` if success, `false` otherwise |
614 | | * |
615 | | * Since: 0.9.2 |
616 | | **/ |
617 | | hb_bool_t |
618 | | hb_face_set_user_data (hb_face_t *face, |
619 | | hb_user_data_key_t *key, |
620 | | void * data, |
621 | | hb_destroy_func_t destroy, |
622 | | hb_bool_t replace) |
623 | 0 | { |
624 | 0 | return hb_object_set_user_data (face, key, data, destroy, replace); |
625 | 0 | } |
626 | | |
627 | | /** |
628 | | * hb_face_get_user_data: (skip) |
629 | | * @face: A face object |
630 | | * @key: The user-data key to query |
631 | | * |
632 | | * Fetches the user data associated with the specified key, |
633 | | * attached to the specified face object. |
634 | | * |
635 | | * Return value: (transfer none): A pointer to the user data |
636 | | * |
637 | | * Since: 0.9.2 |
638 | | **/ |
639 | | void * |
640 | | hb_face_get_user_data (const hb_face_t *face, |
641 | | hb_user_data_key_t *key) |
642 | 0 | { |
643 | 0 | return hb_object_get_user_data (face, key); |
644 | 0 | } |
645 | | |
646 | | /** |
647 | | * hb_face_make_immutable: |
648 | | * @face: A face object |
649 | | * |
650 | | * Makes the given face object immutable. |
651 | | * |
652 | | * Since: 0.9.2 |
653 | | **/ |
654 | | void |
655 | | hb_face_make_immutable (hb_face_t *face) |
656 | 216k | { |
657 | 216k | if (hb_object_is_immutable (face)) |
658 | 216k | return; |
659 | | |
660 | 59 | hb_object_make_immutable (face); |
661 | 59 | } |
662 | | |
663 | | /** |
664 | | * hb_face_is_immutable: |
665 | | * @face: A face object |
666 | | * |
667 | | * Tests whether the given face object is immutable. |
668 | | * |
669 | | * Return value: `true` is @face is immutable, `false` otherwise |
670 | | * |
671 | | * Since: 0.9.2 |
672 | | **/ |
673 | | hb_bool_t |
674 | | hb_face_is_immutable (hb_face_t *face) |
675 | 0 | { |
676 | 0 | return hb_object_is_immutable (face); |
677 | 0 | } |
678 | | |
679 | | |
680 | | /** |
681 | | * hb_face_reference_table: |
682 | | * @face: A face object |
683 | | * @tag: The #hb_tag_t of the table to query |
684 | | * |
685 | | * Fetches a reference to the specified table within |
686 | | * the specified face. Returns an empty blob if referencing table data is not |
687 | | * possible. |
688 | | * |
689 | | * Return value: (transfer full): A pointer to the @tag table within @face |
690 | | * |
691 | | * Since: 0.9.2 |
692 | | **/ |
693 | | hb_blob_t * |
694 | | hb_face_reference_table (const hb_face_t *face, |
695 | | hb_tag_t tag) |
696 | 8.06M | { |
697 | 8.06M | if (unlikely (tag == HB_TAG_NONE)) |
698 | 0 | return hb_blob_get_empty (); |
699 | | |
700 | 8.06M | return face->reference_table (tag); |
701 | 8.06M | } |
702 | | |
703 | | /** |
704 | | * hb_face_reference_blob: |
705 | | * @face: A face object |
706 | | * |
707 | | * Fetches a pointer to the binary blob that contains the specified face. |
708 | | * If referencing the face data is not possible, this function creates a blob |
709 | | * out of individual table blobs if hb_face_get_table_tags() works with this |
710 | | * face, otherwise it returns an empty blob. |
711 | | * |
712 | | * Return value: (transfer full): A pointer to the blob for @face |
713 | | * |
714 | | * Since: 0.9.2 |
715 | | **/ |
716 | | hb_blob_t * |
717 | | hb_face_reference_blob (hb_face_t *face) |
718 | 0 | { |
719 | 0 | hb_blob_t *blob = face->reference_table (HB_TAG_NONE); |
720 | |
|
721 | 0 | if (blob == hb_blob_get_empty ()) |
722 | 0 | { |
723 | | // If referencing the face blob is not possible (e.g. not implemented by the |
724 | | // font functions), use face builder to create a blob out of individual |
725 | | // table blobs. |
726 | 0 | unsigned total_count = hb_face_get_table_tags (face, 0, nullptr, nullptr); |
727 | 0 | if (total_count) |
728 | 0 | { |
729 | 0 | hb_tag_t tags[64]; |
730 | 0 | unsigned count = ARRAY_LENGTH (tags); |
731 | 0 | hb_face_t* builder = hb_face_builder_create (); |
732 | |
|
733 | 0 | for (unsigned offset = 0; offset < total_count; offset += count) |
734 | 0 | { |
735 | 0 | hb_face_get_table_tags (face, offset, &count, tags); |
736 | 0 | if (unlikely (!count)) |
737 | 0 | break; // Allocation error |
738 | 0 | for (unsigned i = 0; i < count; i++) |
739 | 0 | { |
740 | 0 | if (unlikely (!tags[i])) |
741 | 0 | continue; |
742 | 0 | hb_blob_t *table = hb_face_reference_table (face, tags[i]); |
743 | 0 | hb_face_builder_add_table (builder, tags[i], table); |
744 | 0 | hb_blob_destroy (table); |
745 | 0 | } |
746 | 0 | } |
747 | |
|
748 | 0 | blob = hb_face_reference_blob (builder); |
749 | 0 | hb_face_destroy (builder); |
750 | 0 | } |
751 | 0 | } |
752 | |
|
753 | 0 | return blob; |
754 | 0 | } |
755 | | |
756 | | /** |
757 | | * hb_face_set_index: |
758 | | * @face: A face object |
759 | | * @index: The index to assign |
760 | | * |
761 | | * Assigns the specified face-index to @face. Fails if the |
762 | | * face is immutable. |
763 | | * |
764 | | * <note>Note: changing the index has no effect on the face itself |
765 | | * This only changes the value returned by hb_face_get_index().</note> |
766 | | * |
767 | | * Since: 0.9.2 |
768 | | **/ |
769 | | void |
770 | | hb_face_set_index (hb_face_t *face, |
771 | | unsigned int index) |
772 | 0 | { |
773 | 0 | if (hb_object_is_immutable (face)) |
774 | 0 | return; |
775 | | |
776 | 0 | face->index = index; |
777 | 0 | } |
778 | | |
779 | | /** |
780 | | * hb_face_get_index: |
781 | | * @face: A face object |
782 | | * |
783 | | * Fetches the face-index corresponding to the given face. |
784 | | * |
785 | | * <note>Note: face indices within a collection are zero-based.</note> |
786 | | * |
787 | | * Return value: The index of @face. |
788 | | * |
789 | | * Since: 0.9.2 |
790 | | **/ |
791 | | unsigned int |
792 | | hb_face_get_index (const hb_face_t *face) |
793 | 0 | { |
794 | 0 | return face->index; |
795 | 0 | } |
796 | | |
797 | | /** |
798 | | * hb_face_set_upem: |
799 | | * @face: A face object |
800 | | * @upem: The units-per-em value to assign |
801 | | * |
802 | | * Sets the units-per-em (upem) for a face object to the specified value. |
803 | | * |
804 | | * This API is used in rare circumstances. |
805 | | * |
806 | | * Since: 0.9.2 |
807 | | **/ |
808 | | void |
809 | | hb_face_set_upem (hb_face_t *face, |
810 | | unsigned int upem) |
811 | 0 | { |
812 | 0 | if (hb_object_is_immutable (face)) |
813 | 0 | return; |
814 | | |
815 | 0 | face->upem = upem; |
816 | 0 | } |
817 | | |
818 | | /** |
819 | | * hb_face_get_upem: |
820 | | * @face: A face object |
821 | | * |
822 | | * Fetches the units-per-em (UPEM) value of the specified face object. |
823 | | * |
824 | | * Typical UPEM values for fonts are 1000, or 2048, but any value |
825 | | * in between 16 and 16,384 is allowed for OpenType fonts. |
826 | | * |
827 | | * Return value: The upem value of @face |
828 | | * |
829 | | * Since: 0.9.2 |
830 | | **/ |
831 | | unsigned int |
832 | | hb_face_get_upem (const hb_face_t *face) |
833 | 34.0M | { |
834 | 34.0M | return face->get_upem (); |
835 | 34.0M | } |
836 | | |
837 | | /** |
838 | | * hb_face_set_glyph_count: |
839 | | * @face: A face object |
840 | | * @glyph_count: The glyph-count value to assign |
841 | | * |
842 | | * Sets the glyph count for a face object to the specified value. |
843 | | * |
844 | | * This API is used in rare circumstances. |
845 | | * |
846 | | * Since: 0.9.7 |
847 | | **/ |
848 | | void |
849 | | hb_face_set_glyph_count (hb_face_t *face, |
850 | | unsigned int glyph_count) |
851 | 0 | { |
852 | 0 | if (hb_object_is_immutable (face)) |
853 | 0 | return; |
854 | | |
855 | 0 | face->num_glyphs = glyph_count; |
856 | 0 | } |
857 | | |
858 | | /** |
859 | | * hb_face_get_glyph_count: |
860 | | * @face: A face object |
861 | | * |
862 | | * Fetches the glyph-count value of the specified face object. |
863 | | * |
864 | | * Return value: The glyph-count value of @face |
865 | | * |
866 | | * Since: 0.9.7 |
867 | | **/ |
868 | | unsigned int |
869 | | hb_face_get_glyph_count (const hb_face_t *face) |
870 | 969 | { |
871 | 969 | return face->get_num_glyphs (); |
872 | 969 | } |
873 | | |
874 | | /** |
875 | | * hb_face_set_get_table_tags_func: |
876 | | * @face: A face object |
877 | | * @func: (closure user_data) (destroy destroy) (scope notified): The table-tag-fetching function |
878 | | * @user_data: A pointer to the user data, to be destroyed by @destroy when not needed anymore |
879 | | * @destroy: (nullable): A callback to call when @func is not needed anymore |
880 | | * |
881 | | * Sets the table-tag-fetching function for the specified face object. |
882 | | * |
883 | | * Since: 10.0.0 |
884 | | */ |
885 | | HB_EXTERN void |
886 | | hb_face_set_get_table_tags_func (hb_face_t *face, |
887 | | hb_get_table_tags_func_t func, |
888 | | void *user_data, |
889 | | hb_destroy_func_t destroy) |
890 | 59 | { |
891 | 59 | if (hb_object_is_immutable (face)) |
892 | 0 | { |
893 | 0 | if (destroy) |
894 | 0 | destroy (user_data); |
895 | 0 | return; |
896 | 0 | } |
897 | | |
898 | 59 | if (face->get_table_tags_destroy) |
899 | 0 | face->get_table_tags_destroy (face->get_table_tags_user_data); |
900 | | |
901 | 59 | face->get_table_tags_func = func; |
902 | 59 | face->get_table_tags_user_data = user_data; |
903 | 59 | face->get_table_tags_destroy = destroy; |
904 | 59 | } |
905 | | |
906 | | /** |
907 | | * hb_face_get_table_tags: |
908 | | * @face: A face object |
909 | | * @start_offset: The index of first table tag to retrieve |
910 | | * @table_count: (inout): Input = the maximum number of table tags to return; |
911 | | * Output = the actual number of table tags returned (may be zero) |
912 | | * @table_tags: (out) (array length=table_count): The array of table tags found |
913 | | * |
914 | | * Fetches a list of all table tags for a face, if possible. The list returned will |
915 | | * begin at the offset provided |
916 | | * |
917 | | * Return value: Total number of tables, or zero if it is not possible to list |
918 | | * |
919 | | * Since: 1.6.0 |
920 | | **/ |
921 | | unsigned int |
922 | | hb_face_get_table_tags (const hb_face_t *face, |
923 | | unsigned int start_offset, |
924 | | unsigned int *table_count, /* IN/OUT */ |
925 | | hb_tag_t *table_tags /* OUT */) |
926 | 0 | { |
927 | 0 | if (!face->get_table_tags_func) |
928 | 0 | { |
929 | 0 | if (table_count) |
930 | 0 | *table_count = 0; |
931 | 0 | return 0; |
932 | 0 | } |
933 | | |
934 | 0 | return face->get_table_tags_func (face, start_offset, table_count, table_tags, face->get_table_tags_user_data); |
935 | 0 | } |
936 | | |
937 | | |
938 | | /* |
939 | | * Character set. |
940 | | */ |
941 | | |
942 | | |
943 | | #ifndef HB_NO_FACE_COLLECT_UNICODES |
944 | | /** |
945 | | * hb_face_collect_unicodes: |
946 | | * @face: A face object |
947 | | * @out: (out): The set to add Unicode characters to |
948 | | * |
949 | | * Collects all of the Unicode characters covered by @face and adds |
950 | | * them to the #hb_set_t set @out. |
951 | | * |
952 | | * Since: 1.9.0 |
953 | | */ |
954 | | void |
955 | | hb_face_collect_unicodes (hb_face_t *face, |
956 | | hb_set_t *out) |
957 | 12 | { |
958 | 12 | face->table.cmap->collect_unicodes (out, face->get_num_glyphs ()); |
959 | 12 | } |
960 | | /** |
961 | | * hb_face_collect_nominal_glyph_mapping: |
962 | | * @face: A face object |
963 | | * @mapping: (out): The map to add Unicode-to-glyph mapping to |
964 | | * @unicodes: (nullable) (out): The set to add Unicode characters to, or `NULL` |
965 | | * |
966 | | * Collects the mapping from Unicode characters to nominal glyphs of the @face, |
967 | | * and optionally all of the Unicode characters covered by @face. |
968 | | * |
969 | | * Since: 7.0.0 |
970 | | */ |
971 | | void |
972 | | hb_face_collect_nominal_glyph_mapping (hb_face_t *face, |
973 | | hb_map_t *mapping, |
974 | | hb_set_t *unicodes) |
975 | 0 | { |
976 | 0 | hb_set_t stack_unicodes; |
977 | 0 | if (!unicodes) |
978 | 0 | unicodes = &stack_unicodes; |
979 | 0 | face->table.cmap->collect_mapping (unicodes, mapping, face->get_num_glyphs ()); |
980 | 0 | } |
981 | | /** |
982 | | * hb_face_collect_variation_selectors: |
983 | | * @face: A face object |
984 | | * @out: (out): The set to add Variation Selector characters to |
985 | | * |
986 | | * Collects all Unicode "Variation Selector" characters covered by @face and adds |
987 | | * them to the #hb_set_t set @out. |
988 | | * |
989 | | * Since: 1.9.0 |
990 | | */ |
991 | | void |
992 | | hb_face_collect_variation_selectors (hb_face_t *face, |
993 | | hb_set_t *out) |
994 | 0 | { |
995 | 0 | face->table.cmap->collect_variation_selectors (out); |
996 | 0 | } |
997 | | /** |
998 | | * hb_face_collect_variation_unicodes: |
999 | | * @face: A face object |
1000 | | * @variation_selector: The Variation Selector to query |
1001 | | * @out: (out): The set to add Unicode characters to |
1002 | | * |
1003 | | * Collects all Unicode characters for @variation_selector covered by @face and adds |
1004 | | * them to the #hb_set_t set @out. |
1005 | | * |
1006 | | * Since: 1.9.0 |
1007 | | */ |
1008 | | void |
1009 | | hb_face_collect_variation_unicodes (hb_face_t *face, |
1010 | | hb_codepoint_t variation_selector, |
1011 | | hb_set_t *out) |
1012 | 0 | { |
1013 | 0 | face->table.cmap->collect_variation_unicodes (variation_selector, out); |
1014 | 0 | } |
1015 | | #endif |