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 //#include "hb-ot-post-table.hh"
  40 
  41 
  42 struct hb_ot_face_metrics_accelerator_t
  43 {
  44   unsigned int num_metrics;
  45   unsigned int num_advances;
  46   unsigned int default_advance;
  47   unsigned short ascender;
  48   unsigned short descender;
  49   unsigned short line_gap;
  50 
  51   const OT::_mtx *table;
  52   hb_blob_t *blob;
  53 
  54   inline void init (hb_face_t *face,
  55                     hb_tag_t _hea_tag,
  56                     hb_tag_t _mtx_tag,
  57                     hb_tag_t os2_tag)
  58   {
  59     this->default_advance = face->get_upem ();
  60 
  61     bool got_font_extents = false;
  62     if (os2_tag)
  63     {
  64       hb_blob_t *os2_blob = OT::Sanitizer<OT::os2>::sanitize (face->reference_table (os2_tag));
  65       const OT::os2 *os2 = OT::Sanitizer<OT::os2>::lock_instance (os2_blob);
  66 #define USE_TYPO_METRICS (1u<<7)
  67       if (0 != (os2->fsSelection & USE_TYPO_METRICS))
  68       {
  69         this->ascender = os2->sTypoAscender;
  70         this->descender = os2->sTypoDescender;
  71         this->line_gap = os2->sTypoLineGap;
  72         got_font_extents = (this->ascender | this->descender) != 0;
  73       }
  74       hb_blob_destroy (os2_blob);
  75     }
  76 
  77     hb_blob_t *_hea_blob = OT::Sanitizer<OT::_hea>::sanitize (face->reference_table (_hea_tag));
  78     const OT::_hea *_hea = OT::Sanitizer<OT::_hea>::lock_instance (_hea_blob);
  79     this->num_advances = _hea->numberOfLongMetrics;
  80     if (!got_font_extents)
  81     {
  82       this->ascender = _hea->ascender;
  83       this->descender = _hea->descender;
  84       this->line_gap = _hea->lineGap;
  85     }
  86     hb_blob_destroy (_hea_blob);
  87 
  88     this->blob = OT::Sanitizer<OT::_mtx>::sanitize (face->reference_table (_mtx_tag));
  89 
  90     /* Cap num_metrics() and num_advances() based on table length. */
  91     unsigned int len = hb_blob_get_length (this->blob);
  92     if (unlikely (this->num_advances * 4 > len))
  93       this->num_advances = len / 4;
  94     this->num_metrics = this->num_advances + (len - 4 * this->num_advances) / 2;
  95 
  96     /* We MUST set num_metrics to zero if num_advances is zero.
  97      * Our get_advance() depends on that. */
  98     if (unlikely (!this->num_advances))
  99     {
 100       this->num_metrics = this->num_advances = 0;
 101       hb_blob_destroy (this->blob);
 102       this->blob = hb_blob_get_empty ();
 103     }
 104     this->table = OT::Sanitizer<OT::_mtx>::lock_instance (this->blob);
 105   }
 106 
 107   inline void fini (void)
 108   {
 109     hb_blob_destroy (this->blob);
 110   }
 111 
 112   inline unsigned int get_advance (hb_codepoint_t glyph) const
 113   {
 114     if (unlikely (glyph >= this->num_metrics))
 115     {
 116       /* If this->num_metrics is zero, it means we don't have the metrics table
 117        * for this direction: return default advance.  Otherwise, it means that the
 118        * glyph index is out of bound: return zero. */
 119       if (this->num_metrics)
 120         return 0;
 121       else
 122         return this->default_advance;
 123     }
 124 
 125     if (glyph >= this->num_advances)
 126       glyph = this->num_advances - 1;
 127 
 128     return this->table->longMetric[glyph].advance;
 129   }
 130 };
 131 
 132 struct hb_ot_face_glyf_accelerator_t
 133 {
 134   bool short_offset;
 135   unsigned int num_glyphs;
 136   const OT::loca *loca;
 137   const OT::glyf *glyf;
 138   hb_blob_t *loca_blob;
 139   hb_blob_t *glyf_blob;
 140   unsigned int glyf_len;
 141 
 142   inline void init (hb_face_t *face)
 143   {
 144     hb_blob_t *head_blob = OT::Sanitizer<OT::head>::sanitize (face->reference_table (HB_OT_TAG_head));
 145     const OT::head *head = OT::Sanitizer<OT::head>::lock_instance (head_blob);
 146     if ((unsigned int) head->indexToLocFormat > 1 || head->glyphDataFormat != 0)
 147     {
 148       /* Unknown format.  Leave num_glyphs=0, that takes care of disabling us. */
 149       hb_blob_destroy (head_blob);
 150       return;
 151     }
 152     this->short_offset = 0 == head->indexToLocFormat;
 153     hb_blob_destroy (head_blob);
 154 
 155     this->loca_blob = OT::Sanitizer<OT::loca>::sanitize (face->reference_table (HB_OT_TAG_loca));
 156     this->loca = OT::Sanitizer<OT::loca>::lock_instance (this->loca_blob);
 157     this->glyf_blob = OT::Sanitizer<OT::glyf>::sanitize (face->reference_table (HB_OT_TAG_glyf));
 158     this->glyf = OT::Sanitizer<OT::glyf>::lock_instance (this->glyf_blob);
 159 
 160     this->num_glyphs = MAX (1u, hb_blob_get_length (this->loca_blob) / (this->short_offset ? 2 : 4)) - 1;
 161     this->glyf_len = hb_blob_get_length (this->glyf_blob);
 162   }
 163 
 164   inline void fini (void)
 165   {
 166     hb_blob_destroy (this->loca_blob);
 167     hb_blob_destroy (this->glyf_blob);
 168   }
 169 
 170   inline bool get_extents (hb_codepoint_t glyph,
 171                            hb_glyph_extents_t *extents) const
 172   {
 173     if (unlikely (glyph >= this->num_glyphs))
 174       return false;
 175 
 176     unsigned int start_offset, end_offset;
 177     if (this->short_offset)
 178     {
 179       start_offset = 2 * this->loca->u.shortsZ[glyph];
 180       end_offset   = 2 * this->loca->u.shortsZ[glyph + 1];
 181     }
 182     else
 183     {
 184       start_offset = this->loca->u.longsZ[glyph];
 185       end_offset   = this->loca->u.longsZ[glyph + 1];
 186     }
 187 
 188     if (start_offset > end_offset || end_offset > this->glyf_len)
 189       return false;
 190 
 191     if (end_offset - start_offset < OT::glyfGlyphHeader::static_size)
 192       return true; /* Empty glyph; zero extents. */
 193 
 194     const OT::glyfGlyphHeader &glyph_header = OT::StructAtOffset<OT::glyfGlyphHeader> (this->glyf, start_offset);
 195 
 196     extents->x_bearing = MIN (glyph_header.xMin, glyph_header.xMax);
 197     extents->y_bearing = MAX (glyph_header.yMin, glyph_header.yMax);
 198     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;
 200 
 201     return true;
 202   }
 203 };
 204 
 205 typedef bool (*hb_cmap_get_glyph_func_t) (const void *obj,
 206                                           hb_codepoint_t codepoint,
 207                                           hb_codepoint_t *glyph);
 208 
 209 template <typename Type>
 210 static inline bool get_glyph_from (const void *obj,
 211                                    hb_codepoint_t codepoint,
 212                                    hb_codepoint_t *glyph)
 213 {
 214   const Type *typed_obj = (const Type *) obj;
 215   return typed_obj->get_glyph (codepoint, glyph);
 216 }
 217 
 218 template <typename Type>
 219 static inline bool get_glyph_from_symbol (const void *obj,
 220                                           hb_codepoint_t codepoint,
 221                                           hb_codepoint_t *glyph)
 222 {
 223   const Type *typed_obj = (const Type *) obj;
 224   if (likely (typed_obj->get_glyph (codepoint, glyph)))
 225     return true;
 226 
 227   if (codepoint <= 0x00FFu)
 228   {
 229     /* For symbol-encoded OpenType fonts, we duplicate the
 230      * U+F000..F0FF range at U+0000..U+00FF.  That's what
 231      * Windows seems to do, and that's hinted about at:
 232      * http://www.microsoft.com/typography/otspec/recom.htm
 233      * under "Non-Standard (Symbol) Fonts". */
 234     return typed_obj->get_glyph (0xF000u + codepoint, glyph);
 235   }
 236 
 237   return false;
 238 }
 239 
 240 struct hb_ot_face_cmap_accelerator_t
 241 {
 242   hb_cmap_get_glyph_func_t get_glyph_func;
 243   const void *get_glyph_data;
 244   OT::CmapSubtableFormat4::accelerator_t format4_accel;
 245 
 246   const OT::CmapSubtableFormat14 *uvs_table;
 247   hb_blob_t *blob;
 248 
 249   inline void init (hb_face_t *face)
 250   {
 251     this->blob = OT::Sanitizer<OT::cmap>::sanitize (face->reference_table (HB_OT_TAG_cmap));
 252     const OT::cmap *cmap = OT::Sanitizer<OT::cmap>::lock_instance (this->blob);
 253     const OT::CmapSubtable *subtable = NULL;
 254     const OT::CmapSubtableFormat14 *subtable_uvs = NULL;
 255 
 256     bool symbol = false;
 257     /* 32-bit subtables. */
 258     if (!subtable) subtable = cmap->find_subtable (3, 10);
 259     if (!subtable) subtable = cmap->find_subtable (0, 6);
 260     if (!subtable) subtable = cmap->find_subtable (0, 4);
 261     /* 16-bit subtables. */
 262     if (!subtable) subtable = cmap->find_subtable (3, 1);
 263     if (!subtable) subtable = cmap->find_subtable (0, 3);
 264     if (!subtable) subtable = cmap->find_subtable (0, 2);
 265     if (!subtable) subtable = cmap->find_subtable (0, 1);
 266     if (!subtable) subtable = cmap->find_subtable (0, 0);
 267     if (!subtable)(subtable = cmap->find_subtable (3, 0)) && (symbol = true);
 268     /* Meh. */
 269     if (!subtable) subtable = &OT::Null(OT::CmapSubtable);
 270 
 271     /* UVS subtable. */
 272     if (!subtable_uvs)
 273     {
 274       const OT::CmapSubtable *st = cmap->find_subtable (0, 5);
 275       if (st && st->u.format == 14)
 276         subtable_uvs = &st->u.format14;
 277     }
 278     /* Meh. */
 279     if (!subtable_uvs) subtable_uvs = &OT::Null(OT::CmapSubtableFormat14);
 280 
 281     this->uvs_table = subtable_uvs;
 282 
 283     this->get_glyph_data = subtable;
 284     if (unlikely (symbol))
 285       this->get_glyph_func = get_glyph_from_symbol<OT::CmapSubtable>;
 286     else
 287       switch (subtable->u.format) {
 288       /* Accelerate format 4 and format 12. */
 289       default: this->get_glyph_func = get_glyph_from<OT::CmapSubtable>;         break;
 290       case 12: this->get_glyph_func = get_glyph_from<OT::CmapSubtableFormat12>; break;
 291       case  4:
 292         {
 293           this->format4_accel.init (&subtable->u.format4);
 294           this->get_glyph_data = &this->format4_accel;
 295           this->get_glyph_func = this->format4_accel.get_glyph_func;
 296         }
 297         break;
 298       }
 299   }
 300 
 301   inline void fini (void)
 302   {
 303     hb_blob_destroy (this->blob);
 304   }
 305 
 306   inline bool get_nominal_glyph (hb_codepoint_t  unicode,
 307                                  hb_codepoint_t *glyph) const
 308   {
 309     return this->get_glyph_func (this->get_glyph_data, unicode, glyph);
 310   }
 311 
 312   inline bool get_variation_glyph (hb_codepoint_t  unicode,
 313                                    hb_codepoint_t  variation_selector,
 314                                    hb_codepoint_t *glyph) const
 315   {
 316     switch (this->uvs_table->get_glyph_variant (unicode,
 317                                                 variation_selector,
 318                                                 glyph))
 319     {
 320       case OT::GLYPH_VARIANT_NOT_FOUND:         return false;
 321       case OT::GLYPH_VARIANT_FOUND:             return true;
 322       case OT::GLYPH_VARIANT_USE_DEFAULT:       break;
 323     }
 324 
 325     return get_nominal_glyph (unicode, glyph);
 326   }
 327 };
 328 
 329 template <typename T>
 330 struct hb_lazy_loader_t
 331 {
 332   inline void init (hb_face_t *face_)
 333   {
 334     face = face_;
 335     instance = NULL;
 336   }
 337 
 338   inline void fini (void)
 339   {
 340     if (instance && instance != &OT::Null(T))
 341     {
 342       instance->fini();
 343       free (instance);
 344     }
 345   }
 346 
 347   inline const T* operator-> (void) const
 348   {
 349   retry:
 350     T *p = (T *) hb_atomic_ptr_get (&instance);
 351     if (unlikely (!p))
 352     {
 353       p = (T *) calloc (1, sizeof (T));
 354       if (unlikely (!p))
 355         return &OT::Null(T);
 356       p->init (face);
 357       if (unlikely (!hb_atomic_ptr_cmpexch (const_cast<T **>(&instance), NULL, p)))
 358       {
 359         p->fini ();
 360         goto retry;
 361       }
 362     }
 363     return p;
 364   }
 365 
 366   private:
 367   hb_face_t *face;
 368   T *instance;
 369 };
 370 
 371 struct hb_ot_font_t
 372 {
 373   hb_ot_face_cmap_accelerator_t cmap;
 374   hb_ot_face_metrics_accelerator_t h_metrics;
 375   hb_ot_face_metrics_accelerator_t v_metrics;
 376   hb_lazy_loader_t<hb_ot_face_glyf_accelerator_t> glyf;
 377 };
 378 
 379 
 380 static hb_ot_font_t *
 381 _hb_ot_font_create (hb_face_t *face)
 382 {
 383   hb_ot_font_t *ot_font = (hb_ot_font_t *) calloc (1, sizeof (hb_ot_font_t));
 384 
 385   if (unlikely (!ot_font))
 386     return NULL;
 387 
 388   ot_font->cmap.init (face);
 389   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? */
 391   ot_font->glyf.init (face);
 392 
 393   return ot_font;
 394 }
 395 
 396 static void
 397 _hb_ot_font_destroy (hb_ot_font_t *ot_font)
 398 {
 399   ot_font->cmap.fini ();
 400   ot_font->h_metrics.fini ();
 401   ot_font->v_metrics.fini ();
 402   ot_font->glyf.fini ();
 403 
 404   free (ot_font);
 405 }
 406 
 407 
 408 static hb_bool_t
 409 hb_ot_get_nominal_glyph (hb_font_t *font HB_UNUSED,
 410                          void *font_data,
 411                          hb_codepoint_t unicode,
 412                          hb_codepoint_t *glyph,
 413                          void *user_data HB_UNUSED)
 414 
 415 {
 416   const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
 417   return ot_font->cmap.get_nominal_glyph (unicode, glyph);
 418 }
 419 
 420 static hb_bool_t
 421 hb_ot_get_variation_glyph (hb_font_t *font HB_UNUSED,
 422                            void *font_data,
 423                            hb_codepoint_t unicode,
 424                            hb_codepoint_t variation_selector,
 425                            hb_codepoint_t *glyph,
 426                            void *user_data HB_UNUSED)
 427 {
 428   const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
 429   return ot_font->cmap.get_variation_glyph (unicode, variation_selector, glyph);
 430 }
 431 
 432 static hb_position_t
 433 hb_ot_get_glyph_h_advance (hb_font_t *font HB_UNUSED,
 434                            void *font_data,
 435                            hb_codepoint_t glyph,
 436                            void *user_data HB_UNUSED)
 437 {
 438   const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
 439   return font->em_scale_x (ot_font->h_metrics.get_advance (glyph));
 440 }
 441 
 442 static hb_position_t
 443 hb_ot_get_glyph_v_advance (hb_font_t *font HB_UNUSED,
 444                            void *font_data,
 445                            hb_codepoint_t glyph,
 446                            void *user_data HB_UNUSED)
 447 {
 448   const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
 449   return font->em_scale_y (-(int) ot_font->v_metrics.get_advance (glyph));
 450 }
 451 
 452 static hb_bool_t
 453 hb_ot_get_glyph_extents (hb_font_t *font HB_UNUSED,
 454                          void *font_data,
 455                          hb_codepoint_t glyph,
 456                          hb_glyph_extents_t *extents,
 457                          void *user_data HB_UNUSED)
 458 {
 459   const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
 460   bool ret = ot_font->glyf->get_extents (glyph, extents);
 461   extents->x_bearing = font->em_scale_x (extents->x_bearing);
 462   extents->y_bearing = font->em_scale_y (extents->y_bearing);
 463   extents->width     = font->em_scale_x (extents->width);
 464   extents->height    = font->em_scale_y (extents->height);
 465   return ret;
 466 }
 467 
 468 static hb_bool_t
 469 hb_ot_get_font_h_extents (hb_font_t *font HB_UNUSED,
 470                           void *font_data,
 471                           hb_font_extents_t *metrics,
 472                           void *user_data HB_UNUSED)
 473 {
 474   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);
 476   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);
 478   return true;
 479 }
 480 
 481 static hb_bool_t
 482 hb_ot_get_font_v_extents (hb_font_t *font HB_UNUSED,
 483                           void *font_data,
 484                           hb_font_extents_t *metrics,
 485                           void *user_data HB_UNUSED)
 486 {
 487   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);
 489   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);
 491   return true;
 492 }
 493 
 494 static hb_font_funcs_t *static_ot_funcs = NULL;
 495 
 496 #ifdef HB_USE_ATEXIT
 497 static
 498 void free_static_ot_funcs (void)
 499 {
 500   hb_font_funcs_destroy (static_ot_funcs);
 501 }
 502 #endif
 503 
 504 static hb_font_funcs_t *
 505 _hb_ot_get_font_funcs (void)
 506 {
 507 retry:
 508   hb_font_funcs_t *funcs = (hb_font_funcs_t *) hb_atomic_ptr_get (&static_ot_funcs);
 509 
 510   if (unlikely (!funcs))
 511   {
 512     funcs = hb_font_funcs_create ();
 513 
 514     hb_font_funcs_set_font_h_extents_func (funcs, hb_ot_get_font_h_extents, NULL, NULL);
 515     hb_font_funcs_set_font_v_extents_func (funcs, hb_ot_get_font_v_extents, NULL, NULL);
 516     hb_font_funcs_set_nominal_glyph_func (funcs, hb_ot_get_nominal_glyph, NULL, NULL);
 517     hb_font_funcs_set_variation_glyph_func (funcs, hb_ot_get_variation_glyph, NULL, NULL);
 518     hb_font_funcs_set_glyph_h_advance_func (funcs, hb_ot_get_glyph_h_advance, NULL, NULL);
 519     hb_font_funcs_set_glyph_v_advance_func (funcs, hb_ot_get_glyph_v_advance, NULL, NULL);
 520     //hb_font_funcs_set_glyph_h_origin_func (funcs, hb_ot_get_glyph_h_origin, NULL, NULL);
 521     //hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ot_get_glyph_v_origin, NULL, NULL);
 522     //hb_font_funcs_set_glyph_h_kerning_func (funcs, hb_ot_get_glyph_h_kerning, NULL, NULL); TODO
 523     //hb_font_funcs_set_glyph_v_kerning_func (funcs, hb_ot_get_glyph_v_kerning, NULL, NULL);
 524     hb_font_funcs_set_glyph_extents_func (funcs, hb_ot_get_glyph_extents, NULL, NULL);
 525     //hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ot_get_glyph_contour_point, NULL, NULL); TODO
 526     //hb_font_funcs_set_glyph_name_func (funcs, hb_ot_get_glyph_name, NULL, NULL); TODO
 527     //hb_font_funcs_set_glyph_from_name_func (funcs, hb_ot_get_glyph_from_name, NULL, NULL); TODO
 528 
 529     hb_font_funcs_make_immutable (funcs);
 530 
 531     if (!hb_atomic_ptr_cmpexch (&static_ot_funcs, NULL, funcs)) {
 532       hb_font_funcs_destroy (funcs);
 533       goto retry;
 534     }
 535 
 536 #ifdef HB_USE_ATEXIT
 537     atexit (free_static_ot_funcs); /* First person registers atexit() callback. */
 538 #endif
 539   };
 540 
 541   return funcs;
 542 }
 543 
 544 
 545 /**
 546  * hb_ot_font_set_funcs:
 547  *
 548  * Since: 0.9.28
 549  **/
 550 void
 551 hb_ot_font_set_funcs (hb_font_t *font)
 552 {
 553   hb_ot_font_t *ot_font = _hb_ot_font_create (font->face);
 554   if (unlikely (!ot_font))
 555     return;
 556 
 557   hb_font_set_funcs (font,
 558                      _hb_ot_get_font_funcs (),
 559                      ot_font,
 560                      (hb_destroy_func_t) _hb_ot_font_destroy);
 561 }