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
38/**
39 * hb_face_count: Get number of faces on the blob
40 * @blob:
41 *
42 *
43 *
44 * Return value: Number of faces on the blob
45 *
46 * Since: 1.7.7
47 **/
48unsigned int
49hb_face_count (hb_blob_t *blob)
50{
51 if (unlikely (!blob))
52 return 0;
53
54 /* TODO We shouldn't be sanitizing blob. Port to run sanitizer and return if not sane. */
55 /* Make API signature const after. */
56 hb_blob_t *sanitized = hb_sanitize_context_t ().sanitize_blob<OT::OpenTypeFontFile> (hb_blob_reference (blob));
57 const OT::OpenTypeFontFile& ot = *sanitized->as<OT::OpenTypeFontFile> ();
58 unsigned int ret = ot.get_face_count ();
59 hb_blob_destroy (sanitized);
60
61 return ret;
62}
63
64/*
65 * hb_face_t
66 */
67
68DEFINE_NULL_INSTANCE (hb_face_t) =
69{
70 HB_OBJECT_HEADER_STATIC,
71
72 true, /* immutable */
73
74 nullptr, /* reference_table_func */
75 nullptr, /* user_data */
76 nullptr, /* destroy */
77
78 0, /* index */
79 1000, /* upem */
80 0, /* num_glyphs */
81
82 {
83#define HB_SHAPER_IMPLEMENT(shaper) HB_ATOMIC_PTR_INIT (HB_SHAPER_DATA_INVALID),
84#include "hb-shaper-list.hh"
85#undef HB_SHAPER_IMPLEMENT
86 },
87
88 HB_ATOMIC_PTR_INIT (nullptr), /* shape_plans */
89};
90
91
92/**
93 * hb_face_create_for_tables:
94 * @reference_table_func: (closure user_data) (destroy destroy) (scope notified):
95 * @user_data:
96 * @destroy:
97 *
98 *
99 *
100 * Return value: (transfer full)
101 *
102 * Since: 0.9.2
103 **/
104hb_face_t *
105hb_face_create_for_tables (hb_reference_table_func_t reference_table_func,
106 void *user_data,
107 hb_destroy_func_t destroy)
108{
109 hb_face_t *face;
110
111 if (!reference_table_func || !(face = hb_object_create<hb_face_t> ())) {
112 if (destroy)
113 destroy (user_data);
114 return hb_face_get_empty ();
115 }
116
117 face->reference_table_func = reference_table_func;
118 face->user_data = user_data;
119 face->destroy = destroy;
120
121 face->upem = 0;
122 face->num_glyphs = (unsigned int) -1;
123
124 return face;
125}
126
127
128typedef struct hb_face_for_data_closure_t {
129 hb_blob_t *blob;
130 unsigned int index;
131} hb_face_for_data_closure_t;
132
133static hb_face_for_data_closure_t *
134_hb_face_for_data_closure_create (hb_blob_t *blob, unsigned int index)
135{
136 hb_face_for_data_closure_t *closure;
137
138 closure = (hb_face_for_data_closure_t *) calloc (1, sizeof (hb_face_for_data_closure_t));
139 if (unlikely (!closure))
140 return nullptr;
141
142 closure->blob = blob;
143 closure->index = index;
144
145 return closure;
146}
147
148static void
149_hb_face_for_data_closure_destroy (void *data)
150{
151 hb_face_for_data_closure_t *closure = (hb_face_for_data_closure_t *) data;
152
153 hb_blob_destroy (closure->blob);
154 free (closure);
155}
156
157static hb_blob_t *
158_hb_face_for_data_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
159{
160 hb_face_for_data_closure_t *data = (hb_face_for_data_closure_t *) user_data;
161
162 if (tag == HB_TAG_NONE)
163 return hb_blob_reference (data->blob);
164
165 const OT::OpenTypeFontFile &ot_file = *data->blob->as<OT::OpenTypeFontFile> ();
166 const OT::OpenTypeFontFace &ot_face = ot_file.get_face (data->index);
167
168 const OT::OpenTypeTable &table = ot_face.get_table_by_tag (tag);
169
170 hb_blob_t *blob = hb_blob_create_sub_blob (data->blob, table.offset, table.length);
171
172 return blob;
173}
174
175/**
176 * hb_face_create: (Xconstructor)
177 * @blob:
178 * @index:
179 *
180 *
181 *
182 * Return value: (transfer full):
183 *
184 * Since: 0.9.2
185 **/
186hb_face_t *
187hb_face_create (hb_blob_t *blob,
188 unsigned int index)
189{
190 hb_face_t *face;
191
192 if (unlikely (!blob))
193 blob = hb_blob_get_empty ();
194
195 hb_face_for_data_closure_t *closure = _hb_face_for_data_closure_create (hb_sanitize_context_t ().sanitize_blob<OT::OpenTypeFontFile> (hb_blob_reference (blob)), index);
196
197 if (unlikely (!closure))
198 return hb_face_get_empty ();
199
200 face = hb_face_create_for_tables (_hb_face_for_data_reference_table,
201 closure,
202 _hb_face_for_data_closure_destroy);
203
204 face->index = index;
205
206 return face;
207}
208
209/**
210 * hb_face_get_empty:
211 *
212 *
213 *
214 * Return value: (transfer full)
215 *
216 * Since: 0.9.2
217 **/
218hb_face_t *
219hb_face_get_empty (void)
220{
221 return const_cast<hb_face_t *> (&Null(hb_face_t));
222}
223
224
225/**
226 * hb_face_reference: (skip)
227 * @face: a face.
228 *
229 *
230 *
231 * Return value:
232 *
233 * Since: 0.9.2
234 **/
235hb_face_t *
236hb_face_reference (hb_face_t *face)
237{
238 return hb_object_reference (face);
239}
240
241/**
242 * hb_face_destroy: (skip)
243 * @face: a face.
244 *
245 *
246 *
247 * Since: 0.9.2
248 **/
249void
250hb_face_destroy (hb_face_t *face)
251{
252 if (!hb_object_destroy (face)) return;
253
254 for (hb_face_t::plan_node_t *node = face->shape_plans.get (); node; )
255 {
256 hb_face_t::plan_node_t *next = node->next;
257 hb_shape_plan_destroy (node->shape_plan);
258 free (node);
259 node = next;
260 }
261
262#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_DESTROY(shaper, face);
263#include "hb-shaper-list.hh"
264#undef HB_SHAPER_IMPLEMENT
265
266 if (face->destroy)
267 face->destroy (face->user_data);
268
269 free (face);
270}
271
272/**
273 * hb_face_set_user_data: (skip)
274 * @face: a face.
275 * @key:
276 * @data:
277 * @destroy:
278 * @replace:
279 *
280 *
281 *
282 * Return value:
283 *
284 * Since: 0.9.2
285 **/
286hb_bool_t
287hb_face_set_user_data (hb_face_t *face,
288 hb_user_data_key_t *key,
289 void * data,
290 hb_destroy_func_t destroy,
291 hb_bool_t replace)
292{
293 return hb_object_set_user_data (face, key, data, destroy, replace);
294}
295
296/**
297 * hb_face_get_user_data: (skip)
298 * @face: a face.
299 * @key:
300 *
301 *
302 *
303 * Return value: (transfer none):
304 *
305 * Since: 0.9.2
306 **/
307void *
308hb_face_get_user_data (const hb_face_t *face,
309 hb_user_data_key_t *key)
310{
311 return hb_object_get_user_data (face, key);
312}
313
314/**
315 * hb_face_make_immutable:
316 * @face: a face.
317 *
318 *
319 *
320 * Since: 0.9.2
321 **/
322void
323hb_face_make_immutable (hb_face_t *face)
324{
325 if (unlikely (hb_object_is_inert (face)))
326 return;
327
328 face->immutable = true;
329}
330
331/**
332 * hb_face_is_immutable:
333 * @face: a face.
334 *
335 *
336 *
337 * Return value:
338 *
339 * Since: 0.9.2
340 **/
341hb_bool_t
342hb_face_is_immutable (const hb_face_t *face)
343{
344 return face->immutable;
345}
346
347
348/**
349 * hb_face_reference_table:
350 * @face: a face.
351 * @tag:
352 *
353 *
354 *
355 * Return value: (transfer full):
356 *
357 * Since: 0.9.2
358 **/
359hb_blob_t *
360hb_face_reference_table (const hb_face_t *face,
361 hb_tag_t tag)
362{
363 return face->reference_table (tag);
364}
365
366/**
367 * hb_face_reference_blob:
368 * @face: a face.
369 *
370 *
371 *
372 * Return value: (transfer full):
373 *
374 * Since: 0.9.2
375 **/
376hb_blob_t *
377hb_face_reference_blob (hb_face_t *face)
378{
379 return face->reference_table (HB_TAG_NONE);
380}
381
382/**
383 * hb_face_set_index:
384 * @face: a face.
385 * @index:
386 *
387 *
388 *
389 * Since: 0.9.2
390 **/
391void
392hb_face_set_index (hb_face_t *face,
393 unsigned int index)
394{
395 if (face->immutable)
396 return;
397
398 face->index = index;
399}
400
401/**
402 * hb_face_get_index:
403 * @face: a face.
404 *
405 *
406 *
407 * Return value:
408 *
409 * Since: 0.9.2
410 **/
411unsigned int
412hb_face_get_index (const hb_face_t *face)
413{
414 return face->index;
415}
416
417/**
418 * hb_face_set_upem:
419 * @face: a face.
420 * @upem:
421 *
422 *
423 *
424 * Since: 0.9.2
425 **/
426void
427hb_face_set_upem (hb_face_t *face,
428 unsigned int upem)
429{
430 if (face->immutable)
431 return;
432
433 face->upem = upem;
434}
435
436/**
437 * hb_face_get_upem:
438 * @face: a face.
439 *
440 *
441 *
442 * Return value:
443 *
444 * Since: 0.9.2
445 **/
446unsigned int
447hb_face_get_upem (const hb_face_t *face)
448{
449 return face->get_upem ();
450}
451
452/**
453 * hb_face_set_glyph_count:
454 * @face: a face.
455 * @glyph_count:
456 *
457 *
458 *
459 * Since: 0.9.7
460 **/
461void
462hb_face_set_glyph_count (hb_face_t *face,
463 unsigned int glyph_count)
464{
465 if (face->immutable)
466 return;
467
468 face->num_glyphs = glyph_count;
469}
470
471/**
472 * hb_face_get_glyph_count:
473 * @face: a face.
474 *
475 *
476 *
477 * Return value:
478 *
479 * Since: 0.9.7
480 **/
481unsigned int
482hb_face_get_glyph_count (const hb_face_t *face)
483{
484 return face->get_num_glyphs ();
485}
486
487/**
488 * hb_face_get_table_tags:
489 * @face: a face.
490 *
491 * Retrieves table tags for a face, if possible.
492 *
493 * Return value: total number of tables, or 0 if not possible to list.
494 *
495 * Since: 1.6.0
496 **/
497unsigned int
498hb_face_get_table_tags (const hb_face_t *face,
499 unsigned int start_offset,
500 unsigned int *table_count, /* IN/OUT */
501 hb_tag_t *table_tags /* OUT */)
502{
503 if (face->destroy != (hb_destroy_func_t) _hb_face_for_data_closure_destroy)
504 {
505 if (table_count)
506 *table_count = 0;
507 return 0;
508 }
509
510 hb_face_for_data_closure_t *data = (hb_face_for_data_closure_t *) face->user_data;
511
512 const OT::OpenTypeFontFile &ot_file = *data->blob->as<OT::OpenTypeFontFile> ();
513 const OT::OpenTypeFontFace &ot_face = ot_file.get_face (data->index);
514
515 return ot_face.get_table_tags (start_offset, table_count, table_tags);
516}
517
518
519/*
520 * Character set.
521 */
522
523
524/**
525 * hb_face_collect_unicodes:
526 * @face: font face.
527 * @out: set to add Unicode characters covered by @face to.
528 *
529 * Since: 1.9.0
530 */
531void
532hb_face_collect_unicodes (hb_face_t *face,
533 hb_set_t *out)
534{
535 if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return;
536 hb_ot_face_data (face)->cmap->collect_unicodes (out);
537}
538
539/**
540 * hb_face_collect_variation_selectors:
541 * @face: font face.
542 * @out: set to add Variation Selector characters covered by @face to.
543 *
544 *
545 *
546 * Since: 1.9.0
547 */
548void
549hb_face_collect_variation_selectors (hb_face_t *face,
550 hb_set_t *out)
551{
552 if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return;
553 hb_ot_face_data (face)->cmap->collect_variation_selectors (out);
554}
555
556/**
557 * hb_face_collect_variation_unicodes:
558 * @face: font face.
559 * @out: set to add Unicode characters for @variation_selector covered by @face to.
560 *
561 *
562 *
563 * Since: 1.9.0
564 */
565void
566hb_face_collect_variation_unicodes (hb_face_t *face,
567 hb_codepoint_t variation_selector,
568 hb_set_t *out)
569{
570 if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return;
571 hb_ot_face_data (face)->cmap->collect_variation_unicodes (variation_selector, out);
572}
573
574
575
576/*
577 * face-builder: A face that has add_table().
578 */
579
580struct hb_face_builder_data_t
581{
582 struct table_entry_t
583 {
584 inline int cmp (const hb_tag_t *t) const
585 {
586 if (*t < tag) return -1;
587 if (*t > tag) return -1;
588 return 0;
589 }
590
591 hb_tag_t tag;
592 hb_blob_t *blob;
593 };
594
595 hb_vector_t<table_entry_t, 32> tables;
596};
597
598static hb_face_builder_data_t *
599_hb_face_builder_data_create (void)
600{
601 hb_face_builder_data_t *data = (hb_face_builder_data_t *) calloc (1, sizeof (hb_face_builder_data_t));
602 if (unlikely (!data))
603 return nullptr;
604
605 data->tables.init ();
606
607 return data;
608}
609
610static void
611_hb_face_builder_data_destroy (void *user_data)
612{
613 hb_face_builder_data_t *data = (hb_face_builder_data_t *) user_data;
614
615 for (unsigned int i = 0; i < data->tables.len; i++)
616 hb_blob_destroy (data->tables[i].blob);
617
618 data->tables.fini ();
619
620 free (data);
621}
622
623static hb_blob_t *
624_hb_face_builder_data_reference_blob (hb_face_builder_data_t *data)
625{
626
627 unsigned int table_count = data->tables.len;
628 unsigned int face_length = table_count * 16 + 12;
629
630 for (unsigned int i = 0; i < table_count; i++)
631 face_length += hb_ceil_to_4 (hb_blob_get_length (data->tables.arrayZ[i].blob));
632
633 char *buf = (char *) malloc (face_length);
634 if (unlikely (!buf))
635 return nullptr;
636
637 hb_serialize_context_t c (buf, face_length);
638 OT::OpenTypeFontFile *f = c.start_serialize<OT::OpenTypeFontFile> ();
639
640 bool is_cff = data->tables.lsearch (HB_TAG ('C','F','F',' ')) || data->tables.lsearch (HB_TAG ('C','F','F','2'));
641 hb_tag_t sfnt_tag = is_cff ? OT::OpenTypeFontFile::CFFTag : OT::OpenTypeFontFile::TrueTypeTag;
642
643 Supplier<hb_tag_t> tags_supplier (&data->tables[0].tag, table_count, sizeof (data->tables[0]));
644 Supplier<hb_blob_t *> blobs_supplier (&data->tables[0].blob, table_count, sizeof (data->tables[0]));
645 bool ret = f->serialize_single (&c,
646 sfnt_tag,
647 tags_supplier,
648 blobs_supplier,
649 table_count);
650
651 c.end_serialize ();
652
653 if (unlikely (!ret))
654 {
655 free (buf);
656 return nullptr;
657 }
658
659 return hb_blob_create (buf, face_length, HB_MEMORY_MODE_WRITABLE, buf, free);
660}
661
662static hb_blob_t *
663_hb_face_builder_reference_table (hb_face_t *face, hb_tag_t tag, void *user_data)
664{
665 hb_face_builder_data_t *data = (hb_face_builder_data_t *) user_data;
666
667 if (!tag)
668 return _hb_face_builder_data_reference_blob (data);
669
670 hb_face_builder_data_t::table_entry_t *entry = data->tables.lsearch (tag);
671 if (entry)
672 return hb_blob_reference (entry->blob);
673
674 return nullptr;
675}
676
677
678/**
679 * hb_face_builder_create:
680 *
681 * Creates a #hb_face_t that can be used with hb_face_builder_add_table().
682 * After tables are added to the face, it can be compiled to a binary
683 * font file by calling hb_face_reference_blob().
684 *
685 * Return value: (transfer full) New face.
686 *
687 * Since: 1.9.0
688 **/
689hb_face_t *
690hb_face_builder_create (void)
691{
692 hb_face_builder_data_t *data = _hb_face_builder_data_create ();
693 if (unlikely (!data)) return hb_face_get_empty ();
694
695 return hb_face_create_for_tables (_hb_face_builder_reference_table,
696 data,
697 _hb_face_builder_data_destroy);
698}
699
700/**
701 * hb_face_builder_add_table:
702 *
703 * Add table for @tag with data provided by @blob to the face. @face must
704 * be created using hb_face_builder_create().
705 *
706 * Since: 1.9.0
707 **/
708hb_bool_t
709hb_face_builder_add_table (hb_face_t *face, hb_tag_t tag, hb_blob_t *blob)
710{
711 if (unlikely (face->destroy != (hb_destroy_func_t) _hb_face_builder_data_destroy))
712 return false;
713
714 hb_face_builder_data_t *data = (hb_face_builder_data_t *) face->user_data;
715 hb_face_builder_data_t::table_entry_t *entry = data->tables.push ();
716
717 entry->tag = tag;
718 entry->blob = hb_blob_reference (blob);
719
720 return true;
721}
722