1/* 2 * Copyright © 2011,2014 Google, Inc. 3 * 4 * This is part of HarfBuzz, a text shaping library. 5 * 6 * Permission is hereby granted, without written agreement and without 7 * license or royalty fees, to use, copy, modify, and distribute this 8 * software and its documentation for any purpose, provided that the 9 * above copyright notice and the following two paragraphs appear in 10 * all copies of this software. 11 * 12 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 13 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 14 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 15 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 16 * DAMAGE. 17 * 18 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 19 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 21 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 22 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 23 * 24 * Google Author(s): Behdad Esfahbod, Roozbeh Pournader 25 */ 26 27#include "hb-private.hh" 28 29#include "hb-ot.h" 30 31#include "hb-font-private.hh" 32 33#include "hb-ot-cmap-table.hh" 34#include "hb-ot-glyf-table.hh" 35#include "hb-ot-head-table.hh" 36#include "hb-ot-hhea-table.hh" 37#include "hb-ot-hmtx-table.hh" 38#include "hb-ot-os2-table.hh" 39 40 41struct hb_ot_face_metrics_accelerator_t 42{ 43 unsigned int num_metrics; 44 unsigned int num_advances; 45 unsigned int default_advance; 46 unsigned short ascender; 47 unsigned short descender; 48 unsigned short line_gap; 49 50 const OT::_mtx *table; 51 hb_blob_t *blob; 52 53 inline void init (hb_face_t *face, 54 hb_tag_t _hea_tag, 55 hb_tag_t _mtx_tag, 56 hb_tag_t os2_tag) 57 { 58 this->default_advance = face->get_upem (); 59 60 bool got_font_extents = false; 61 if (os2_tag) 62 { 63 hb_blob_t *os2_blob = OT::Sanitizer<OT::os2>::sanitize (face->reference_table (os2_tag)); 64 const OT::os2 *os2 = OT::Sanitizer<OT::os2>::lock_instance (os2_blob); 65#define USE_TYPO_METRICS (1u<<7) 66 if (0 != (os2->fsSelection & USE_TYPO_METRICS)) 67 { 68 this->ascender = os2->sTypoAscender; 69 this->descender = os2->sTypoDescender; 70 this->line_gap = os2->sTypoLineGap; 71 got_font_extents = (this->ascender | this->descender) != 0; 72 } 73 hb_blob_destroy (os2_blob); 74 } 75 76 hb_blob_t *_hea_blob = OT::Sanitizer<OT::_hea>::sanitize (face->reference_table (_hea_tag)); 77 const OT::_hea *_hea = OT::Sanitizer<OT::_hea>::lock_instance (_hea_blob); 78 this->num_advances = _hea->numberOfLongMetrics; 79 if (!got_font_extents) 80 { 81 this->ascender = _hea->ascender; 82 this->descender = _hea->descender; 83 this->line_gap = _hea->lineGap; 84 } 85 hb_blob_destroy (_hea_blob); 86 87 this->blob = OT::Sanitizer<OT::_mtx>::sanitize (face->reference_table (_mtx_tag)); 88 89 /* Cap num_metrics() and num_advances() based on table length. */ 90 unsigned int len = hb_blob_get_length (this->blob); 91 if (unlikely (this->num_advances * 4 > len)) 92 this->num_advances = len / 4; 93 this->num_metrics = this->num_advances + (len - 4 * this->num_advances) / 2; 94 95 /* We MUST set num_metrics to zero if num_advances is zero. 96 * Our get_advance() depends on that. */ 97 if (unlikely (!this->num_advances)) 98 { 99 this->num_metrics = this->num_advances = 0; 100 hb_blob_destroy (this->blob); 101 this->blob = hb_blob_get_empty (); 102 } 103 this->table = OT::Sanitizer<OT::_mtx>::lock_instance (this->blob); 104 } 105 106 inline void fini (void) 107 { 108 hb_blob_destroy (this->blob); 109 } 110 111 inline unsigned int get_advance (hb_codepoint_t glyph) const 112 { 113 if (unlikely (glyph >= this->num_metrics)) 114 { 115 /* If this->num_metrics is zero, it means we don't have the metrics table 116 * for this direction: return default advance. Otherwise, it means that the 117 * glyph index is out of bound: return zero. */ 118 if (this->num_metrics) 119 return 0; 120 else 121 return this->default_advance; 122 } 123 124 if (glyph >= this->num_advances) 125 glyph = this->num_advances - 1; 126 127 return this->table->longMetric[glyph].advance; 128 } 129}; 130 131struct hb_ot_face_glyf_accelerator_t 132{ 133 bool short_offset; 134 unsigned int num_glyphs; 135 const OT::loca *loca; 136 const OT::glyf *glyf; 137 hb_blob_t *loca_blob; 138 hb_blob_t *glyf_blob; 139 unsigned int glyf_len; 140 141 inline void init (hb_face_t *face) 142 { 143 hb_blob_t *head_blob = OT::Sanitizer<OT::head>::sanitize (face->reference_table (HB_OT_TAG_head)); 144 const OT::head *head = OT::Sanitizer<OT::head>::lock_instance (head_blob); 145 if ((unsigned int) head->indexToLocFormat > 1 || head->glyphDataFormat != 0) 146 { 147 /* Unknown format. Leave num_glyphs=0, that takes care of disabling us. */ 148 hb_blob_destroy (head_blob); 149 return; 150 } 151 this->short_offset = 0 == head->indexToLocFormat; 152 hb_blob_destroy (head_blob); 153 154 this->loca_blob = OT::Sanitizer<OT::loca>::sanitize (face->reference_table (HB_OT_TAG_loca)); 155 this->loca = OT::Sanitizer<OT::loca>::lock_instance (this->loca_blob); 156 this->glyf_blob = OT::Sanitizer<OT::glyf>::sanitize (face->reference_table (HB_OT_TAG_glyf)); 157 this->glyf = OT::Sanitizer<OT::glyf>::lock_instance (this->glyf_blob); 158 159 this->num_glyphs = MAX (1u, hb_blob_get_length (this->loca_blob) / (this->short_offset ? 2 : 4)) - 1; 160 this->glyf_len = hb_blob_get_length (this->glyf_blob); 161 } 162 163 inline void fini (void) 164 { 165 hb_blob_destroy (this->loca_blob); 166 hb_blob_destroy (this->glyf_blob); 167 } 168 169 inline bool get_extents (hb_codepoint_t glyph, 170 hb_glyph_extents_t *extents) const 171 { 172 if (unlikely (glyph >= this->num_glyphs)) 173 return false; 174 175 unsigned int start_offset, end_offset; 176 if (this->short_offset) 177 { 178 start_offset = 2 * this->loca->u.shortsZ[glyph]; 179 end_offset = 2 * this->loca->u.shortsZ[glyph + 1]; 180 } 181 else 182 { 183 start_offset = this->loca->u.longsZ[glyph]; 184 end_offset = this->loca->u.longsZ[glyph + 1]; 185 } 186 187 if (start_offset > end_offset || end_offset > this->glyf_len) 188 return false; 189 190 if (end_offset - start_offset < OT::glyfGlyphHeader::static_size) 191 return true; /* Empty glyph; zero extents. */ 192 193 const OT::glyfGlyphHeader &glyph_header = OT::StructAtOffset<OT::glyfGlyphHeader> (this->glyf, start_offset); 194 195 extents->x_bearing = MIN (glyph_header.xMin, glyph_header.xMax); 196 extents->y_bearing = MAX (glyph_header.yMin, glyph_header.yMax); 197 extents->width = MAX (glyph_header.xMin, glyph_header.xMax) - extents->x_bearing; 198 extents->height = MIN (glyph_header.yMin, glyph_header.yMax) - extents->y_bearing; 199 200 return true; 201 } 202}; 203 204typedef bool (*hb_cmap_get_glyph_func_t) (const void *obj, 205 hb_codepoint_t codepoint, 206 hb_codepoint_t *glyph); 207 208template <typename Type> 209static inline bool get_glyph_from (const void *obj, 210 hb_codepoint_t codepoint, 211 hb_codepoint_t *glyph) 212{ 213 const Type *typed_obj = (const Type *) obj; 214 return typed_obj->get_glyph (codepoint, glyph); 215} 216 217struct hb_ot_face_cmap_accelerator_t 218{ 219 hb_cmap_get_glyph_func_t get_glyph_func; 220 const void *get_glyph_data; 221 OT::CmapSubtableFormat4::accelerator_t format4_accel; 222 223 const OT::CmapSubtableFormat14 *uvs_table; 224 hb_blob_t *blob; 225 226 inline void init (hb_face_t *face) 227 { 228 this->blob = OT::Sanitizer<OT::cmap>::sanitize (face->reference_table (HB_OT_TAG_cmap)); 229 const OT::cmap *cmap = OT::Sanitizer<OT::cmap>::lock_instance (this->blob); 230 const OT::CmapSubtable *subtable = NULL; 231 const OT::CmapSubtableFormat14 *subtable_uvs = NULL; 232 233 /* 32-bit subtables. */ 234 if (!subtable) subtable = cmap->find_subtable (3, 10); 235 if (!subtable) subtable = cmap->find_subtable (0, 6); 236 if (!subtable) subtable = cmap->find_subtable (0, 4); 237 /* 16-bit subtables. */ 238 if (!subtable) subtable = cmap->find_subtable (3, 1); 239 if (!subtable) subtable = cmap->find_subtable (0, 3); 240 if (!subtable) subtable = cmap->find_subtable (0, 2); 241 if (!subtable) subtable = cmap->find_subtable (0, 1); 242 if (!subtable) subtable = cmap->find_subtable (0, 0); 243 if (!subtable) subtable = cmap->find_subtable (3, 0); 244 /* Meh. */ 245 if (!subtable) subtable = &OT::Null(OT::CmapSubtable); 246 247 /* UVS subtable. */ 248 if (!subtable_uvs) 249 { 250 const OT::CmapSubtable *st = cmap->find_subtable (0, 5); 251 if (st && st->u.format == 14) 252 subtable_uvs = &st->u.format14; 253 } 254 /* Meh. */ 255 if (!subtable_uvs) subtable_uvs = &OT::Null(OT::CmapSubtableFormat14); 256 257 this->uvs_table = subtable_uvs; 258 259 this->get_glyph_data = subtable; 260 switch (subtable->u.format) { 261 /* Accelerate format 4 and format 12. */ 262 default: this->get_glyph_func = get_glyph_from<OT::CmapSubtable>; break; 263 case 12: this->get_glyph_func = get_glyph_from<OT::CmapSubtableFormat12>; break; 264 case 4: 265 { 266 this->format4_accel.init (&subtable->u.format4); 267 this->get_glyph_data = &this->format4_accel; 268 this->get_glyph_func = this->format4_accel.get_glyph_func; 269 } 270 break; 271 } 272 } 273 274 inline void fini (void) 275 { 276 hb_blob_destroy (this->blob); 277 } 278 279 inline bool get_nominal_glyph (hb_codepoint_t unicode, 280 hb_codepoint_t *glyph) const 281 { 282 return this->get_glyph_func (this->get_glyph_data, unicode, glyph); 283 } 284 285 inline bool get_variation_glyph (hb_codepoint_t unicode, 286 hb_codepoint_t variation_selector, 287 hb_codepoint_t *glyph) const 288 { 289 switch (this->uvs_table->get_glyph_variant (unicode, 290 variation_selector, 291 glyph)) 292 { 293 case OT::GLYPH_VARIANT_NOT_FOUND: return false; 294 case OT::GLYPH_VARIANT_FOUND: return true; 295 case OT::GLYPH_VARIANT_USE_DEFAULT: break; 296 } 297 298 return get_nominal_glyph (unicode, glyph); 299 } 300}; 301 302 303struct hb_ot_font_t 304{ 305 hb_ot_face_cmap_accelerator_t cmap; 306 hb_ot_face_metrics_accelerator_t h_metrics; 307 hb_ot_face_metrics_accelerator_t v_metrics; 308 hb_ot_face_glyf_accelerator_t glyf; 309}; 310 311 312static hb_ot_font_t * 313_hb_ot_font_create (hb_face_t *face) 314{ 315 hb_ot_font_t *ot_font = (hb_ot_font_t *) calloc (1, sizeof (hb_ot_font_t)); 316 317 if (unlikely (!ot_font)) 318 return NULL; 319 320 ot_font->cmap.init (face); 321 ot_font->h_metrics.init (face, HB_OT_TAG_hhea, HB_OT_TAG_hmtx, HB_OT_TAG_os2); 322 ot_font->v_metrics.init (face, HB_OT_TAG_vhea, HB_OT_TAG_vmtx, HB_TAG_NONE); /* TODO Can we do this lazily? */ 323 ot_font->glyf.init (face); 324 325 return ot_font; 326} 327 328static void 329_hb_ot_font_destroy (hb_ot_font_t *ot_font) 330{ 331 ot_font->cmap.fini (); 332 ot_font->h_metrics.fini (); 333 ot_font->v_metrics.fini (); 334 ot_font->glyf.fini (); 335 336 free (ot_font); 337} 338 339 340static hb_bool_t 341hb_ot_get_nominal_glyph (hb_font_t *font HB_UNUSED, 342 void *font_data, 343 hb_codepoint_t unicode, 344 hb_codepoint_t *glyph, 345 void *user_data HB_UNUSED) 346 347{ 348 const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; 349 return ot_font->cmap.get_nominal_glyph (unicode, glyph); 350} 351 352static hb_bool_t 353hb_ot_get_variation_glyph (hb_font_t *font HB_UNUSED, 354 void *font_data, 355 hb_codepoint_t unicode, 356 hb_codepoint_t variation_selector, 357 hb_codepoint_t *glyph, 358 void *user_data HB_UNUSED) 359{ 360 const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; 361 return ot_font->cmap.get_variation_glyph (unicode, variation_selector, glyph); 362} 363 364static hb_position_t 365hb_ot_get_glyph_h_advance (hb_font_t *font HB_UNUSED, 366 void *font_data, 367 hb_codepoint_t glyph, 368 void *user_data HB_UNUSED) 369{ 370 const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; 371 return font->em_scale_x (ot_font->h_metrics.get_advance (glyph)); 372} 373 374static hb_position_t 375hb_ot_get_glyph_v_advance (hb_font_t *font HB_UNUSED, 376 void *font_data, 377 hb_codepoint_t glyph, 378 void *user_data HB_UNUSED) 379{ 380 const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; 381 return font->em_scale_y (-(int) ot_font->v_metrics.get_advance (glyph)); 382} 383 384static hb_bool_t 385hb_ot_get_glyph_extents (hb_font_t *font HB_UNUSED, 386 void *font_data, 387 hb_codepoint_t glyph, 388 hb_glyph_extents_t *extents, 389 void *user_data HB_UNUSED) 390{ 391 const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; 392 bool ret = ot_font->glyf.get_extents (glyph, extents); 393 extents->x_bearing = font->em_scale_x (extents->x_bearing); 394 extents->y_bearing = font->em_scale_y (extents->y_bearing); 395 extents->width = font->em_scale_x (extents->width); 396 extents->height = font->em_scale_y (extents->height); 397 return ret; 398} 399 400static hb_bool_t 401hb_ot_get_font_h_extents (hb_font_t *font HB_UNUSED, 402 void *font_data, 403 hb_font_extents_t *metrics, 404 void *user_data HB_UNUSED) 405{ 406 const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; 407 metrics->ascender = font->em_scale_y (ot_font->h_metrics.ascender); 408 metrics->descender = font->em_scale_y (ot_font->h_metrics.descender); 409 metrics->line_gap = font->em_scale_y (ot_font->h_metrics.line_gap); 410 return true; 411} 412 413static hb_bool_t 414hb_ot_get_font_v_extents (hb_font_t *font HB_UNUSED, 415 void *font_data, 416 hb_font_extents_t *metrics, 417 void *user_data HB_UNUSED) 418{ 419 const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; 420 metrics->ascender = font->em_scale_x (ot_font->v_metrics.ascender); 421 metrics->descender = font->em_scale_x (ot_font->v_metrics.descender); 422 metrics->line_gap = font->em_scale_x (ot_font->v_metrics.line_gap); 423 return true; 424} 425 426static hb_font_funcs_t *static_ot_funcs = NULL; 427 428#ifdef HB_USE_ATEXIT 429static 430void free_static_ot_funcs (void) 431{ 432 hb_font_funcs_destroy (static_ot_funcs); 433} 434#endif 435 436static hb_font_funcs_t * 437_hb_ot_get_font_funcs (void) 438{ 439retry: 440 hb_font_funcs_t *funcs = (hb_font_funcs_t *) hb_atomic_ptr_get (&static_ot_funcs); 441 442 if (unlikely (!funcs)) 443 { 444 funcs = hb_font_funcs_create (); 445 446 hb_font_funcs_set_font_h_extents_func (funcs, hb_ot_get_font_h_extents, NULL, NULL); 447 hb_font_funcs_set_font_v_extents_func (funcs, hb_ot_get_font_v_extents, NULL, NULL); 448 hb_font_funcs_set_nominal_glyph_func (funcs, hb_ot_get_nominal_glyph, NULL, NULL); 449 hb_font_funcs_set_variation_glyph_func (funcs, hb_ot_get_variation_glyph, NULL, NULL); 450 hb_font_funcs_set_glyph_h_advance_func (funcs, hb_ot_get_glyph_h_advance, NULL, NULL); 451 hb_font_funcs_set_glyph_v_advance_func (funcs, hb_ot_get_glyph_v_advance, NULL, NULL); 452 //hb_font_funcs_set_glyph_h_origin_func (funcs, hb_ot_get_glyph_h_origin, NULL, NULL); 453 //hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ot_get_glyph_v_origin, NULL, NULL); 454 //hb_font_funcs_set_glyph_h_kerning_func (funcs, hb_ot_get_glyph_h_kerning, NULL, NULL); TODO 455 //hb_font_funcs_set_glyph_v_kerning_func (funcs, hb_ot_get_glyph_v_kerning, NULL, NULL); 456 hb_font_funcs_set_glyph_extents_func (funcs, hb_ot_get_glyph_extents, NULL, NULL); 457 //hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ot_get_glyph_contour_point, NULL, NULL); TODO 458 //hb_font_funcs_set_glyph_name_func (funcs, hb_ot_get_glyph_name, NULL, NULL); TODO 459 //hb_font_funcs_set_glyph_from_name_func (funcs, hb_ot_get_glyph_from_name, NULL, NULL); TODO 460 461 hb_font_funcs_make_immutable (funcs); 462 463 if (!hb_atomic_ptr_cmpexch (&static_ot_funcs, NULL, funcs)) { 464 hb_font_funcs_destroy (funcs); 465 goto retry; 466 } 467 468#ifdef HB_USE_ATEXIT 469 atexit (free_static_ot_funcs); /* First person registers atexit() callback. */ 470#endif 471 }; 472 473 return funcs; 474} 475 476 477/** 478 * hb_ot_font_set_funcs: 479 * 480 * Since: 0.9.28 481 **/ 482void 483hb_ot_font_set_funcs (hb_font_t *font) 484{ 485 hb_ot_font_t *ot_font = _hb_ot_font_create (font->face); 486 if (unlikely (!ot_font)) 487 return; 488 489 hb_font_set_funcs (font, 490 _hb_ot_get_font_funcs (), 491 ot_font, 492 (hb_destroy_func_t) _hb_ot_font_destroy); 493} 494