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