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