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