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 }