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