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-private.hh" |
30 | |
31 | #include "hb-face-private.hh" |
32 | #include "hb-open-file-private.hh" |
33 | #include "hb-ot-head-table.hh" |
34 | #include "hb-ot-maxp-table.hh" |
35 | |
36 | |
37 | /* |
38 | * hb_face_t |
39 | */ |
40 | |
41 | const hb_face_t _hb_face_nil = { |
42 | HB_OBJECT_HEADER_STATIC, |
43 | |
44 | .immutable: true, /* immutable */ |
45 | |
46 | .reference_table_func: nullptr, /* reference_table_func */ |
47 | .user_data: nullptr, /* user_data */ |
48 | .destroy: nullptr, /* destroy */ |
49 | |
50 | .index: 0, /* index */ |
51 | .upem: 1000, /* upem */ |
52 | .num_glyphs: 0, /* num_glyphs */ |
53 | |
54 | .shaper_data: { |
55 | #define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INVALID, |
56 | #include "hb-shaper-list.hh" |
57 | #undef HB_SHAPER_IMPLEMENT |
58 | }, |
59 | |
60 | .shape_plans: nullptr, /* shape_plans */ |
61 | }; |
62 | |
63 | |
64 | /** |
65 | * hb_face_create_for_tables: |
66 | * @reference_table_func: (closure user_data) (destroy destroy) (scope notified): |
67 | * @user_data: |
68 | * @destroy: |
69 | * |
70 | * |
71 | * |
72 | * Return value: (transfer full) |
73 | * |
74 | * Since: 0.9.2 |
75 | **/ |
76 | hb_face_t * |
77 | hb_face_create_for_tables (hb_reference_table_func_t reference_table_func, |
78 | void *user_data, |
79 | hb_destroy_func_t destroy) |
80 | { |
81 | hb_face_t *face; |
82 | |
83 | if (!reference_table_func || !(face = hb_object_create<hb_face_t> ())) { |
84 | if (destroy) |
85 | destroy (user_data); |
86 | return hb_face_get_empty (); |
87 | } |
88 | |
89 | face->reference_table_func = reference_table_func; |
90 | face->user_data = user_data; |
91 | face->destroy = destroy; |
92 | |
93 | face->upem = 0; |
94 | face->num_glyphs = (unsigned int) -1; |
95 | |
96 | return face; |
97 | } |
98 | |
99 | |
100 | typedef struct hb_face_for_data_closure_t { |
101 | hb_blob_t *blob; |
102 | unsigned int index; |
103 | } hb_face_for_data_closure_t; |
104 | |
105 | static hb_face_for_data_closure_t * |
106 | _hb_face_for_data_closure_create (hb_blob_t *blob, unsigned int index) |
107 | { |
108 | hb_face_for_data_closure_t *closure; |
109 | |
110 | closure = (hb_face_for_data_closure_t *) calloc (nmemb: 1, size: sizeof (hb_face_for_data_closure_t)); |
111 | if (unlikely (!closure)) |
112 | return nullptr; |
113 | |
114 | closure->blob = blob; |
115 | closure->index = index; |
116 | |
117 | return closure; |
118 | } |
119 | |
120 | static void |
121 | _hb_face_for_data_closure_destroy (void *data) |
122 | { |
123 | hb_face_for_data_closure_t *closure = (hb_face_for_data_closure_t *) data; |
124 | |
125 | hb_blob_destroy (blob: closure->blob); |
126 | free (ptr: closure); |
127 | } |
128 | |
129 | static hb_blob_t * |
130 | _hb_face_for_data_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data) |
131 | { |
132 | hb_face_for_data_closure_t *data = (hb_face_for_data_closure_t *) user_data; |
133 | |
134 | if (tag == HB_TAG_NONE) |
135 | return hb_blob_reference (blob: data->blob); |
136 | |
137 | const OT::OpenTypeFontFile &ot_file = *OT::Sanitizer<OT::OpenTypeFontFile>::lock_instance (blob: data->blob); |
138 | const OT::OpenTypeFontFace &ot_face = ot_file.get_face (i: data->index); |
139 | |
140 | const OT::OpenTypeTable &table = ot_face.get_table_by_tag (tag); |
141 | |
142 | hb_blob_t *blob = hb_blob_create_sub_blob (parent: data->blob, offset: table.offset, length: table.length); |
143 | |
144 | return blob; |
145 | } |
146 | |
147 | /** |
148 | * hb_face_create: (Xconstructor) |
149 | * @blob: |
150 | * @index: |
151 | * |
152 | * |
153 | * |
154 | * Return value: (transfer full): |
155 | * |
156 | * Since: 0.9.2 |
157 | **/ |
158 | hb_face_t * |
159 | hb_face_create (hb_blob_t *blob, |
160 | unsigned int index) |
161 | { |
162 | hb_face_t *face; |
163 | |
164 | if (unlikely (!blob)) |
165 | blob = hb_blob_get_empty (); |
166 | |
167 | hb_face_for_data_closure_t *closure = _hb_face_for_data_closure_create (blob: OT::Sanitizer<OT::OpenTypeFontFile>::sanitize (blob: hb_blob_reference (blob)), index); |
168 | |
169 | if (unlikely (!closure)) |
170 | return hb_face_get_empty (); |
171 | |
172 | face = hb_face_create_for_tables (reference_table_func: _hb_face_for_data_reference_table, |
173 | user_data: closure, |
174 | destroy: _hb_face_for_data_closure_destroy); |
175 | |
176 | face->index = index; |
177 | |
178 | return face; |
179 | } |
180 | |
181 | /** |
182 | * hb_face_get_empty: |
183 | * |
184 | * |
185 | * |
186 | * Return value: (transfer full) |
187 | * |
188 | * Since: 0.9.2 |
189 | **/ |
190 | hb_face_t * |
191 | hb_face_get_empty (void) |
192 | { |
193 | return const_cast<hb_face_t *> (&_hb_face_nil); |
194 | } |
195 | |
196 | |
197 | /** |
198 | * hb_face_reference: (skip) |
199 | * @face: a face. |
200 | * |
201 | * |
202 | * |
203 | * Return value: |
204 | * |
205 | * Since: 0.9.2 |
206 | **/ |
207 | hb_face_t * |
208 | hb_face_reference (hb_face_t *face) |
209 | { |
210 | return hb_object_reference (obj: face); |
211 | } |
212 | |
213 | /** |
214 | * hb_face_destroy: (skip) |
215 | * @face: a face. |
216 | * |
217 | * |
218 | * |
219 | * Since: 0.9.2 |
220 | **/ |
221 | void |
222 | hb_face_destroy (hb_face_t *face) |
223 | { |
224 | if (!hb_object_destroy (obj: face)) return; |
225 | |
226 | for (hb_face_t::plan_node_t *node = face->shape_plans; node; ) |
227 | { |
228 | hb_face_t::plan_node_t *next = node->next; |
229 | hb_shape_plan_destroy (shape_plan: node->shape_plan); |
230 | free (ptr: node); |
231 | node = next; |
232 | } |
233 | |
234 | #define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_DESTROY(shaper, face); |
235 | #include "hb-shaper-list.hh" |
236 | #undef HB_SHAPER_IMPLEMENT |
237 | |
238 | if (face->destroy) |
239 | face->destroy (face->user_data); |
240 | |
241 | free (ptr: face); |
242 | } |
243 | |
244 | /** |
245 | * hb_face_set_user_data: (skip) |
246 | * @face: a face. |
247 | * @key: |
248 | * @data: |
249 | * @destroy: |
250 | * @replace: |
251 | * |
252 | * |
253 | * |
254 | * Return value: |
255 | * |
256 | * Since: 0.9.2 |
257 | **/ |
258 | hb_bool_t |
259 | hb_face_set_user_data (hb_face_t *face, |
260 | hb_user_data_key_t *key, |
261 | void * data, |
262 | hb_destroy_func_t destroy, |
263 | hb_bool_t replace) |
264 | { |
265 | return hb_object_set_user_data (obj: face, key, data, destroy, replace); |
266 | } |
267 | |
268 | /** |
269 | * hb_face_get_user_data: (skip) |
270 | * @face: a face. |
271 | * @key: |
272 | * |
273 | * |
274 | * |
275 | * Return value: (transfer none): |
276 | * |
277 | * Since: 0.9.2 |
278 | **/ |
279 | void * |
280 | hb_face_get_user_data (hb_face_t *face, |
281 | hb_user_data_key_t *key) |
282 | { |
283 | return hb_object_get_user_data (obj: face, key); |
284 | } |
285 | |
286 | /** |
287 | * hb_face_make_immutable: |
288 | * @face: a face. |
289 | * |
290 | * |
291 | * |
292 | * Since: 0.9.2 |
293 | **/ |
294 | void |
295 | hb_face_make_immutable (hb_face_t *face) |
296 | { |
297 | if (unlikely (hb_object_is_inert (face))) |
298 | return; |
299 | |
300 | face->immutable = true; |
301 | } |
302 | |
303 | /** |
304 | * hb_face_is_immutable: |
305 | * @face: a face. |
306 | * |
307 | * |
308 | * |
309 | * Return value: |
310 | * |
311 | * Since: 0.9.2 |
312 | **/ |
313 | hb_bool_t |
314 | hb_face_is_immutable (hb_face_t *face) |
315 | { |
316 | return face->immutable; |
317 | } |
318 | |
319 | |
320 | /** |
321 | * hb_face_reference_table: |
322 | * @face: a face. |
323 | * @tag: |
324 | * |
325 | * |
326 | * |
327 | * Return value: (transfer full): |
328 | * |
329 | * Since: 0.9.2 |
330 | **/ |
331 | hb_blob_t * |
332 | hb_face_reference_table (hb_face_t *face, |
333 | hb_tag_t tag) |
334 | { |
335 | return face->reference_table (tag); |
336 | } |
337 | |
338 | /** |
339 | * hb_face_reference_blob: |
340 | * @face: a face. |
341 | * |
342 | * |
343 | * |
344 | * Return value: (transfer full): |
345 | * |
346 | * Since: 0.9.2 |
347 | **/ |
348 | hb_blob_t * |
349 | hb_face_reference_blob (hb_face_t *face) |
350 | { |
351 | return face->reference_table (HB_TAG_NONE); |
352 | } |
353 | |
354 | /** |
355 | * hb_face_set_index: |
356 | * @face: a face. |
357 | * @index: |
358 | * |
359 | * |
360 | * |
361 | * Since: 0.9.2 |
362 | **/ |
363 | void |
364 | hb_face_set_index (hb_face_t *face, |
365 | unsigned int index) |
366 | { |
367 | if (face->immutable) |
368 | return; |
369 | |
370 | face->index = index; |
371 | } |
372 | |
373 | /** |
374 | * hb_face_get_index: |
375 | * @face: a face. |
376 | * |
377 | * |
378 | * |
379 | * Return value: |
380 | * |
381 | * Since: 0.9.2 |
382 | **/ |
383 | unsigned int |
384 | hb_face_get_index (hb_face_t *face) |
385 | { |
386 | return face->index; |
387 | } |
388 | |
389 | /** |
390 | * hb_face_set_upem: |
391 | * @face: a face. |
392 | * @upem: |
393 | * |
394 | * |
395 | * |
396 | * Since: 0.9.2 |
397 | **/ |
398 | void |
399 | hb_face_set_upem (hb_face_t *face, |
400 | unsigned int upem) |
401 | { |
402 | if (face->immutable) |
403 | return; |
404 | |
405 | face->upem = upem; |
406 | } |
407 | |
408 | /** |
409 | * hb_face_get_upem: |
410 | * @face: a face. |
411 | * |
412 | * |
413 | * |
414 | * Return value: |
415 | * |
416 | * Since: 0.9.2 |
417 | **/ |
418 | unsigned int |
419 | hb_face_get_upem (hb_face_t *face) |
420 | { |
421 | return face->get_upem (); |
422 | } |
423 | |
424 | void |
425 | hb_face_t::load_upem (void) const |
426 | { |
427 | hb_blob_t *head_blob = OT::Sanitizer<OT::head>::sanitize (blob: reference_table (HB_OT_TAG_head)); |
428 | const OT::head *head_table = OT::Sanitizer<OT::head>::lock_instance (blob: head_blob); |
429 | upem = head_table->get_upem (); |
430 | hb_blob_destroy (blob: head_blob); |
431 | } |
432 | |
433 | /** |
434 | * hb_face_set_glyph_count: |
435 | * @face: a face. |
436 | * @glyph_count: |
437 | * |
438 | * |
439 | * |
440 | * Since: 0.9.7 |
441 | **/ |
442 | void |
443 | hb_face_set_glyph_count (hb_face_t *face, |
444 | unsigned int glyph_count) |
445 | { |
446 | if (face->immutable) |
447 | return; |
448 | |
449 | face->num_glyphs = glyph_count; |
450 | } |
451 | |
452 | /** |
453 | * hb_face_get_glyph_count: |
454 | * @face: a face. |
455 | * |
456 | * |
457 | * |
458 | * Return value: |
459 | * |
460 | * Since: 0.9.7 |
461 | **/ |
462 | unsigned int |
463 | hb_face_get_glyph_count (hb_face_t *face) |
464 | { |
465 | return face->get_num_glyphs (); |
466 | } |
467 | |
468 | void |
469 | hb_face_t::load_num_glyphs (void) const |
470 | { |
471 | hb_blob_t *maxp_blob = OT::Sanitizer<OT::maxp>::sanitize (blob: reference_table (HB_OT_TAG_maxp)); |
472 | const OT::maxp *maxp_table = OT::Sanitizer<OT::maxp>::lock_instance (blob: maxp_blob); |
473 | num_glyphs = maxp_table->get_num_glyphs (); |
474 | hb_blob_destroy (blob: maxp_blob); |
475 | } |
476 | |
477 | /** |
478 | * hb_face_get_table_tags: |
479 | * @face: a face. |
480 | * |
481 | * Retrieves table tags for a face, if possible. |
482 | * |
483 | * Return value: total number of tables, or 0 if not possible to list. |
484 | * |
485 | * Since: 1.6.0 |
486 | **/ |
487 | unsigned int |
488 | hb_face_get_table_tags (hb_face_t *face, |
489 | unsigned int start_offset, |
490 | unsigned int *table_count, /* IN/OUT */ |
491 | hb_tag_t *table_tags /* OUT */) |
492 | { |
493 | if (face->destroy != _hb_face_for_data_closure_destroy) |
494 | { |
495 | if (table_count) |
496 | *table_count = 0; |
497 | return 0; |
498 | } |
499 | |
500 | hb_face_for_data_closure_t *data = (hb_face_for_data_closure_t *) face->user_data; |
501 | |
502 | const OT::OpenTypeFontFile &ot_file = *OT::Sanitizer<OT::OpenTypeFontFile>::lock_instance (blob: data->blob); |
503 | const OT::OpenTypeFontFace &ot_face = ot_file.get_face (i: data->index); |
504 | |
505 | return ot_face.get_table_tags (start_offset, table_count, table_tags); |
506 | } |
507 | |