Home | History | Annotate | Download | only in src
      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 
     41 struct 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 
    131 struct 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 
    204 typedef bool (*hb_cmap_get_glyph_func_t) (const void *obj,
    205 					  hb_codepoint_t codepoint,
    206 					  hb_codepoint_t *glyph);
    207 
    208 template <typename Type>
    209 static 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 
    217 struct 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 
    303 struct 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 
    312 static 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 
    328 static 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 
    340 static hb_bool_t
    341 hb_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 
    352 static hb_bool_t
    353 hb_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 
    364 static hb_position_t
    365 hb_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 
    374 static hb_position_t
    375 hb_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 
    384 static hb_bool_t
    385 hb_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 
    400 static hb_bool_t
    401 hb_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 
    413 static hb_bool_t
    414 hb_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 
    426 static hb_font_funcs_t *static_ot_funcs = NULL;
    427 
    428 #ifdef HB_USE_ATEXIT
    429 static
    430 void free_static_ot_funcs (void)
    431 {
    432   hb_font_funcs_destroy (static_ot_funcs);
    433 }
    434 #endif
    435 
    436 static hb_font_funcs_t *
    437 _hb_ot_get_font_funcs (void)
    438 {
    439 retry:
    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  **/
    482 void
    483 hb_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