| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright © 2011,2014 Google, Inc. | 2 * Copyright © 2011,2014 Google, Inc. |
| 3 * | 3 * |
| 4 * This is part of HarfBuzz, a text shaping library. | 4 * This is part of HarfBuzz, a text shaping library. |
| 5 * | 5 * |
| 6 * Permission is hereby granted, without written agreement and without | 6 * Permission is hereby granted, without written agreement and without |
| 7 * license or royalty fees, to use, copy, modify, and distribute this | 7 * license or royalty fees, to use, copy, modify, and distribute this |
| 8 * software and its documentation for any purpose, provided that the | 8 * software and its documentation for any purpose, provided that the |
| 9 * above copyright notice and the following two paragraphs appear in | 9 * above copyright notice and the following two paragraphs appear in |
| 10 * all copies of this software. | 10 * all copies of this software. |
| (...skipping 13 matching lines...) Expand all Loading... |
| 24 * Google Author(s): Behdad Esfahbod, Roozbeh Pournader | 24 * Google Author(s): Behdad Esfahbod, Roozbeh Pournader |
| 25 */ | 25 */ |
| 26 | 26 |
| 27 #include "hb-private.hh" | 27 #include "hb-private.hh" |
| 28 | 28 |
| 29 #include "hb-ot.h" | 29 #include "hb-ot.h" |
| 30 | 30 |
| 31 #include "hb-font-private.hh" | 31 #include "hb-font-private.hh" |
| 32 | 32 |
| 33 #include "hb-ot-cmap-table.hh" | 33 #include "hb-ot-cmap-table.hh" |
| 34 #include "hb-ot-cbdt-table.hh" |
| 34 #include "hb-ot-glyf-table.hh" | 35 #include "hb-ot-glyf-table.hh" |
| 35 #include "hb-ot-head-table.hh" | 36 #include "hb-ot-head-table.hh" |
| 36 #include "hb-ot-hhea-table.hh" | 37 #include "hb-ot-hhea-table.hh" |
| 37 #include "hb-ot-hmtx-table.hh" | 38 #include "hb-ot-hmtx-table.hh" |
| 38 #include "hb-ot-os2-table.hh" | 39 #include "hb-ot-os2-table.hh" |
| 39 //#include "hb-ot-post-table.hh" | 40 //#include "hb-ot-post-table.hh" |
| 40 | 41 |
| 41 | 42 |
| 42 struct hb_ot_face_metrics_accelerator_t | 43 struct hb_ot_face_metrics_accelerator_t |
| 43 { | 44 { |
| 44 unsigned int num_metrics; | 45 unsigned int num_metrics; |
| 45 unsigned int num_advances; | 46 unsigned int num_advances; |
| 46 unsigned int default_advance; | 47 unsigned int default_advance; |
| 47 unsigned short ascender; | 48 unsigned short ascender; |
| 48 unsigned short descender; | 49 unsigned short descender; |
| 49 unsigned short line_gap; | 50 unsigned short line_gap; |
| 51 bool has_font_extents; |
| 50 | 52 |
| 51 const OT::_mtx *table; | 53 const OT::_mtx *table; |
| 52 hb_blob_t *blob; | 54 hb_blob_t *blob; |
| 53 | 55 |
| 54 inline void init (hb_face_t *face, | 56 inline void init (hb_face_t *face, |
| 55 hb_tag_t _hea_tag, | 57 hb_tag_t _hea_tag, |
| 56 hb_tag_t _mtx_tag, | 58 hb_tag_t _mtx_tag, |
| 57 » » hb_tag_t os2_tag) | 59 » » hb_tag_t os2_tag, |
| 60 » » unsigned int default_advance = 0) |
| 58 { | 61 { |
| 59 this->default_advance = face->get_upem (); | 62 this->default_advance = default_advance ? default_advance : face->get_upem (
); |
| 60 | 63 |
| 61 bool got_font_extents = false; | 64 bool got_font_extents = false; |
| 62 if (os2_tag) | 65 if (os2_tag) |
| 63 { | 66 { |
| 64 hb_blob_t *os2_blob = OT::Sanitizer<OT::os2>::sanitize (face->reference_ta
ble (os2_tag)); | 67 hb_blob_t *os2_blob = OT::Sanitizer<OT::os2>::sanitize (face->reference_ta
ble (os2_tag)); |
| 65 const OT::os2 *os2 = OT::Sanitizer<OT::os2>::lock_instance (os2_blob); | 68 const OT::os2 *os2 = OT::Sanitizer<OT::os2>::lock_instance (os2_blob); |
| 66 #define USE_TYPO_METRICS (1u<<7) | 69 #define USE_TYPO_METRICS (1u<<7) |
| 67 if (0 != (os2->fsSelection & USE_TYPO_METRICS)) | 70 if (0 != (os2->fsSelection & USE_TYPO_METRICS)) |
| 68 { | 71 { |
| 69 this->ascender = os2->sTypoAscender; | 72 this->ascender = os2->sTypoAscender; |
| 70 this->descender = os2->sTypoDescender; | 73 this->descender = os2->sTypoDescender; |
| 71 this->line_gap = os2->sTypoLineGap; | 74 this->line_gap = os2->sTypoLineGap; |
| 72 got_font_extents = (this->ascender | this->descender) != 0; | 75 got_font_extents = (this->ascender | this->descender) != 0; |
| 73 } | 76 } |
| 74 hb_blob_destroy (os2_blob); | 77 hb_blob_destroy (os2_blob); |
| 75 } | 78 } |
| 76 | 79 |
| 77 hb_blob_t *_hea_blob = OT::Sanitizer<OT::_hea>::sanitize (face->reference_ta
ble (_hea_tag)); | 80 hb_blob_t *_hea_blob = OT::Sanitizer<OT::_hea>::sanitize (face->reference_ta
ble (_hea_tag)); |
| 78 const OT::_hea *_hea = OT::Sanitizer<OT::_hea>::lock_instance (_hea_blob); | 81 const OT::_hea *_hea = OT::Sanitizer<OT::_hea>::lock_instance (_hea_blob); |
| 79 this->num_advances = _hea->numberOfLongMetrics; | 82 this->num_advances = _hea->numberOfLongMetrics; |
| 80 if (!got_font_extents) | 83 if (!got_font_extents) |
| 81 { | 84 { |
| 82 this->ascender = _hea->ascender; | 85 this->ascender = _hea->ascender; |
| 83 this->descender = _hea->descender; | 86 this->descender = _hea->descender; |
| 84 this->line_gap = _hea->lineGap; | 87 this->line_gap = _hea->lineGap; |
| 88 got_font_extents = (this->ascender | this->descender) != 0; |
| 85 } | 89 } |
| 86 hb_blob_destroy (_hea_blob); | 90 hb_blob_destroy (_hea_blob); |
| 87 | 91 |
| 92 this->has_font_extents = got_font_extents; |
| 93 |
| 88 this->blob = OT::Sanitizer<OT::_mtx>::sanitize (face->reference_table (_mtx_
tag)); | 94 this->blob = OT::Sanitizer<OT::_mtx>::sanitize (face->reference_table (_mtx_
tag)); |
| 89 | 95 |
| 90 /* Cap num_metrics() and num_advances() based on table length. */ | 96 /* Cap num_metrics() and num_advances() based on table length. */ |
| 91 unsigned int len = hb_blob_get_length (this->blob); | 97 unsigned int len = hb_blob_get_length (this->blob); |
| 92 if (unlikely (this->num_advances * 4 > len)) | 98 if (unlikely (this->num_advances * 4 > len)) |
| 93 this->num_advances = len / 4; | 99 this->num_advances = len / 4; |
| 94 this->num_metrics = this->num_advances + (len - 4 * this->num_advances) / 2; | 100 this->num_metrics = this->num_advances + (len - 4 * this->num_advances) / 2; |
| 95 | 101 |
| 96 /* We MUST set num_metrics to zero if num_advances is zero. | 102 /* We MUST set num_metrics to zero if num_advances is zero. |
| 97 * Our get_advance() depends on that. */ | 103 * Our get_advance() depends on that. */ |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 195 | 201 |
| 196 extents->x_bearing = MIN (glyph_header.xMin, glyph_header.xMax); | 202 extents->x_bearing = MIN (glyph_header.xMin, glyph_header.xMax); |
| 197 extents->y_bearing = MAX (glyph_header.yMin, glyph_header.yMax); | 203 extents->y_bearing = MAX (glyph_header.yMin, glyph_header.yMax); |
| 198 extents->width = MAX (glyph_header.xMin, glyph_header.xMax) - extents->x
_bearing; | 204 extents->width = MAX (glyph_header.xMin, glyph_header.xMax) - extents->x
_bearing; |
| 199 extents->height = MIN (glyph_header.yMin, glyph_header.yMax) - extents->y
_bearing; | 205 extents->height = MIN (glyph_header.yMin, glyph_header.yMax) - extents->y
_bearing; |
| 200 | 206 |
| 201 return true; | 207 return true; |
| 202 } | 208 } |
| 203 }; | 209 }; |
| 204 | 210 |
| 211 struct hb_ot_face_cbdt_accelerator_t |
| 212 { |
| 213 hb_blob_t *cblc_blob; |
| 214 hb_blob_t *cbdt_blob; |
| 215 const OT::CBLC *cblc; |
| 216 const OT::CBDT *cbdt; |
| 217 |
| 218 unsigned int cbdt_len; |
| 219 float upem; |
| 220 |
| 221 inline void init (hb_face_t *face) |
| 222 { |
| 223 upem = face->get_upem(); |
| 224 |
| 225 cblc_blob = OT::Sanitizer<OT::CBLC>::sanitize (face->reference_table (HB_OT_
TAG_CBLC)); |
| 226 cbdt_blob = OT::Sanitizer<OT::CBDT>::sanitize (face->reference_table (HB_OT_
TAG_CBDT)); |
| 227 cbdt_len = hb_blob_get_length (cbdt_blob); |
| 228 |
| 229 if (hb_blob_get_length (cblc_blob) == 0) { |
| 230 cblc = NULL; |
| 231 cbdt = NULL; |
| 232 return; /* Not a bitmap font. */ |
| 233 } |
| 234 cblc = OT::Sanitizer<OT::CBLC>::lock_instance (cblc_blob); |
| 235 cbdt = OT::Sanitizer<OT::CBDT>::lock_instance (cbdt_blob); |
| 236 |
| 237 } |
| 238 |
| 239 inline void fini (void) |
| 240 { |
| 241 hb_blob_destroy (this->cblc_blob); |
| 242 hb_blob_destroy (this->cbdt_blob); |
| 243 } |
| 244 |
| 245 inline bool get_extents (hb_codepoint_t glyph, hb_glyph_extents_t *extents) co
nst |
| 246 { |
| 247 unsigned int x_ppem = upem, y_ppem = upem; /* TODO Use font ppem if availabl
e. */ |
| 248 |
| 249 if (cblc == NULL) |
| 250 return false; // Not a color bitmap font. |
| 251 |
| 252 const OT::IndexSubtableRecord *subtable_record = this->cblc->find_table(glyp
h, &x_ppem, &y_ppem); |
| 253 if (subtable_record == NULL) |
| 254 return false; |
| 255 |
| 256 if (subtable_record->get_extents (extents)) |
| 257 return true; |
| 258 |
| 259 unsigned int image_offset = 0, image_length = 0, image_format = 0; |
| 260 if (!subtable_record->get_image_data (glyph, &image_offset, &image_length, &
image_format)) |
| 261 return false; |
| 262 |
| 263 { |
| 264 /* TODO Move the following into CBDT struct when adding more formats. */ |
| 265 |
| 266 if (unlikely (image_offset > cbdt_len || cbdt_len - image_offset < image_l
ength)) |
| 267 return false; |
| 268 |
| 269 switch (image_format) |
| 270 { |
| 271 case 17: { |
| 272 if (unlikely (image_length < OT::GlyphBitmapDataFormat17::min_size)) |
| 273 return false; |
| 274 |
| 275 const OT::GlyphBitmapDataFormat17& glyphFormat17 = |
| 276 OT::StructAtOffset<OT::GlyphBitmapDataFormat17> (this->cbdt, image
_offset); |
| 277 glyphFormat17.glyphMetrics.get_extents (extents); |
| 278 } |
| 279 break; |
| 280 default: |
| 281 // TODO: Support other image formats. |
| 282 return false; |
| 283 } |
| 284 } |
| 285 |
| 286 /* Convert to the font units. */ |
| 287 extents->x_bearing *= upem / (float) x_ppem; |
| 288 extents->y_bearing *= upem / (float) y_ppem; |
| 289 extents->width *= upem / (float) x_ppem; |
| 290 extents->height *= upem / (float) y_ppem; |
| 291 |
| 292 return true; |
| 293 } |
| 294 }; |
| 295 |
| 205 typedef bool (*hb_cmap_get_glyph_func_t) (const void *obj, | 296 typedef bool (*hb_cmap_get_glyph_func_t) (const void *obj, |
| 206 hb_codepoint_t codepoint, | 297 hb_codepoint_t codepoint, |
| 207 hb_codepoint_t *glyph); | 298 hb_codepoint_t *glyph); |
| 208 | 299 |
| 209 template <typename Type> | 300 template <typename Type> |
| 210 static inline bool get_glyph_from (const void *obj, | 301 static inline bool get_glyph_from (const void *obj, |
| 211 hb_codepoint_t codepoint, | 302 hb_codepoint_t codepoint, |
| 212 hb_codepoint_t *glyph) | 303 hb_codepoint_t *glyph) |
| 213 { | 304 { |
| 214 const Type *typed_obj = (const Type *) obj; | 305 const Type *typed_obj = (const Type *) obj; |
| (...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 367 hb_face_t *face; | 458 hb_face_t *face; |
| 368 T *instance; | 459 T *instance; |
| 369 }; | 460 }; |
| 370 | 461 |
| 371 struct hb_ot_font_t | 462 struct hb_ot_font_t |
| 372 { | 463 { |
| 373 hb_ot_face_cmap_accelerator_t cmap; | 464 hb_ot_face_cmap_accelerator_t cmap; |
| 374 hb_ot_face_metrics_accelerator_t h_metrics; | 465 hb_ot_face_metrics_accelerator_t h_metrics; |
| 375 hb_ot_face_metrics_accelerator_t v_metrics; | 466 hb_ot_face_metrics_accelerator_t v_metrics; |
| 376 hb_lazy_loader_t<hb_ot_face_glyf_accelerator_t> glyf; | 467 hb_lazy_loader_t<hb_ot_face_glyf_accelerator_t> glyf; |
| 468 hb_lazy_loader_t<hb_ot_face_cbdt_accelerator_t> cbdt; |
| 377 }; | 469 }; |
| 378 | 470 |
| 379 | 471 |
| 380 static hb_ot_font_t * | 472 static hb_ot_font_t * |
| 381 _hb_ot_font_create (hb_face_t *face) | 473 _hb_ot_font_create (hb_face_t *face) |
| 382 { | 474 { |
| 383 hb_ot_font_t *ot_font = (hb_ot_font_t *) calloc (1, sizeof (hb_ot_font_t)); | 475 hb_ot_font_t *ot_font = (hb_ot_font_t *) calloc (1, sizeof (hb_ot_font_t)); |
| 384 | 476 |
| 385 if (unlikely (!ot_font)) | 477 if (unlikely (!ot_font)) |
| 386 return NULL; | 478 return NULL; |
| 387 | 479 |
| 388 ot_font->cmap.init (face); | 480 ot_font->cmap.init (face); |
| 389 ot_font->h_metrics.init (face, HB_OT_TAG_hhea, HB_OT_TAG_hmtx, HB_OT_TAG_os2); | 481 ot_font->h_metrics.init (face, HB_OT_TAG_hhea, HB_OT_TAG_hmtx, HB_OT_TAG_os2); |
| 390 ot_font->v_metrics.init (face, HB_OT_TAG_vhea, HB_OT_TAG_vmtx, HB_TAG_NONE); /
* TODO Can we do this lazily? */ | 482 ot_font->v_metrics.init (face, HB_OT_TAG_vhea, HB_OT_TAG_vmtx, HB_TAG_NONE, |
| 483 » » » ot_font->h_metrics.ascender - ot_font->h_metrics.desc
ender); /* TODO Can we do this lazily? */ |
| 391 ot_font->glyf.init (face); | 484 ot_font->glyf.init (face); |
| 485 ot_font->cbdt.init (face); |
| 392 | 486 |
| 393 return ot_font; | 487 return ot_font; |
| 394 } | 488 } |
| 395 | 489 |
| 396 static void | 490 static void |
| 397 _hb_ot_font_destroy (hb_ot_font_t *ot_font) | 491 _hb_ot_font_destroy (hb_ot_font_t *ot_font) |
| 398 { | 492 { |
| 399 ot_font->cmap.fini (); | 493 ot_font->cmap.fini (); |
| 400 ot_font->h_metrics.fini (); | 494 ot_font->h_metrics.fini (); |
| 401 ot_font->v_metrics.fini (); | 495 ot_font->v_metrics.fini (); |
| 402 ot_font->glyf.fini (); | 496 ot_font->glyf.fini (); |
| 497 ot_font->cbdt.fini (); |
| 403 | 498 |
| 404 free (ot_font); | 499 free (ot_font); |
| 405 } | 500 } |
| 406 | 501 |
| 407 | 502 |
| 408 static hb_bool_t | 503 static hb_bool_t |
| 409 hb_ot_get_nominal_glyph (hb_font_t *font HB_UNUSED, | 504 hb_ot_get_nominal_glyph (hb_font_t *font HB_UNUSED, |
| 410 void *font_data, | 505 void *font_data, |
| 411 hb_codepoint_t unicode, | 506 hb_codepoint_t unicode, |
| 412 hb_codepoint_t *glyph, | 507 hb_codepoint_t *glyph, |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 451 | 546 |
| 452 static hb_bool_t | 547 static hb_bool_t |
| 453 hb_ot_get_glyph_extents (hb_font_t *font HB_UNUSED, | 548 hb_ot_get_glyph_extents (hb_font_t *font HB_UNUSED, |
| 454 void *font_data, | 549 void *font_data, |
| 455 hb_codepoint_t glyph, | 550 hb_codepoint_t glyph, |
| 456 hb_glyph_extents_t *extents, | 551 hb_glyph_extents_t *extents, |
| 457 void *user_data HB_UNUSED) | 552 void *user_data HB_UNUSED) |
| 458 { | 553 { |
| 459 const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; | 554 const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; |
| 460 bool ret = ot_font->glyf->get_extents (glyph, extents); | 555 bool ret = ot_font->glyf->get_extents (glyph, extents); |
| 556 if (!ret) |
| 557 ret = ot_font->cbdt->get_extents (glyph, extents); |
| 461 extents->x_bearing = font->em_scale_x (extents->x_bearing); | 558 extents->x_bearing = font->em_scale_x (extents->x_bearing); |
| 462 extents->y_bearing = font->em_scale_y (extents->y_bearing); | 559 extents->y_bearing = font->em_scale_y (extents->y_bearing); |
| 463 extents->width = font->em_scale_x (extents->width); | 560 extents->width = font->em_scale_x (extents->width); |
| 464 extents->height = font->em_scale_y (extents->height); | 561 extents->height = font->em_scale_y (extents->height); |
| 465 return ret; | 562 return ret; |
| 466 } | 563 } |
| 467 | 564 |
| 468 static hb_bool_t | 565 static hb_bool_t |
| 469 hb_ot_get_font_h_extents (hb_font_t *font HB_UNUSED, | 566 hb_ot_get_font_h_extents (hb_font_t *font HB_UNUSED, |
| 470 void *font_data, | 567 void *font_data, |
| 471 hb_font_extents_t *metrics, | 568 hb_font_extents_t *metrics, |
| 472 void *user_data HB_UNUSED) | 569 void *user_data HB_UNUSED) |
| 473 { | 570 { |
| 474 const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; | 571 const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; |
| 475 metrics->ascender = font->em_scale_y (ot_font->h_metrics.ascender); | 572 metrics->ascender = font->em_scale_y (ot_font->h_metrics.ascender); |
| 476 metrics->descender = font->em_scale_y (ot_font->h_metrics.descender); | 573 metrics->descender = font->em_scale_y (ot_font->h_metrics.descender); |
| 477 metrics->line_gap = font->em_scale_y (ot_font->h_metrics.line_gap); | 574 metrics->line_gap = font->em_scale_y (ot_font->h_metrics.line_gap); |
| 478 return true; | 575 return ot_font->h_metrics.has_font_extents; |
| 479 } | 576 } |
| 480 | 577 |
| 481 static hb_bool_t | 578 static hb_bool_t |
| 482 hb_ot_get_font_v_extents (hb_font_t *font HB_UNUSED, | 579 hb_ot_get_font_v_extents (hb_font_t *font HB_UNUSED, |
| 483 void *font_data, | 580 void *font_data, |
| 484 hb_font_extents_t *metrics, | 581 hb_font_extents_t *metrics, |
| 485 void *user_data HB_UNUSED) | 582 void *user_data HB_UNUSED) |
| 486 { | 583 { |
| 487 const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; | 584 const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; |
| 488 metrics->ascender = font->em_scale_x (ot_font->v_metrics.ascender); | 585 metrics->ascender = font->em_scale_x (ot_font->v_metrics.ascender); |
| 489 metrics->descender = font->em_scale_x (ot_font->v_metrics.descender); | 586 metrics->descender = font->em_scale_x (ot_font->v_metrics.descender); |
| 490 metrics->line_gap = font->em_scale_x (ot_font->v_metrics.line_gap); | 587 metrics->line_gap = font->em_scale_x (ot_font->v_metrics.line_gap); |
| 491 return true; | 588 return ot_font->v_metrics.has_font_extents; |
| 492 } | 589 } |
| 493 | 590 |
| 494 static hb_font_funcs_t *static_ot_funcs = NULL; | 591 static hb_font_funcs_t *static_ot_funcs = NULL; |
| 495 | 592 |
| 496 #ifdef HB_USE_ATEXIT | 593 #ifdef HB_USE_ATEXIT |
| 497 static | 594 static |
| 498 void free_static_ot_funcs (void) | 595 void free_static_ot_funcs (void) |
| 499 { | 596 { |
| 500 hb_font_funcs_destroy (static_ot_funcs); | 597 hb_font_funcs_destroy (static_ot_funcs); |
| 501 } | 598 } |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 552 { | 649 { |
| 553 hb_ot_font_t *ot_font = _hb_ot_font_create (font->face); | 650 hb_ot_font_t *ot_font = _hb_ot_font_create (font->face); |
| 554 if (unlikely (!ot_font)) | 651 if (unlikely (!ot_font)) |
| 555 return; | 652 return; |
| 556 | 653 |
| 557 hb_font_set_funcs (font, | 654 hb_font_set_funcs (font, |
| 558 _hb_ot_get_font_funcs (), | 655 _hb_ot_get_font_funcs (), |
| 559 ot_font, | 656 ot_font, |
| 560 (hb_destroy_func_t) _hb_ot_font_destroy); | 657 (hb_destroy_func_t) _hb_ot_font_destroy); |
| 561 } | 658 } |
| OLD | NEW |