1 /*
   2  * Copyright © 2015  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
  25  */
  26 
  27 #ifndef HB_OT_GLYF_TABLE_HH
  28 #define HB_OT_GLYF_TABLE_HH
  29 
  30 #include "hb-open-type-private.hh"
  31 #include "hb-ot-head-table.hh"
  32 #include "hb-subset-glyf.hh"
  33 #include "hb-subset-plan.hh"
  34 #include "hb-subset-private.hh"
  35 
  36 namespace OT {
  37 
  38 
  39 /*
  40  * loca -- Index to Location
  41  * https://docs.microsoft.com/en-us/typography/opentype/spec/loca
  42  */
  43 #define HB_OT_TAG_loca HB_TAG('l','o','c','a')
  44 
  45 
  46 struct loca
  47 {
  48   friend struct glyf;
  49 
  50   static const hb_tag_t tableTag = HB_OT_TAG_loca;
  51 
  52   inline bool sanitize (hb_sanitize_context_t *c) const
  53   {
  54     TRACE_SANITIZE (this);
  55     return_trace (true);
  56   }
  57 
  58   protected:
  59   HBUINT8               dataZ[VAR];             /* Location data. */
  60   DEFINE_SIZE_ARRAY (0, dataZ);
  61 };
  62 
  63 
  64 /*
  65  * glyf -- TrueType Glyph Data
  66  * https://docs.microsoft.com/en-us/typography/opentype/spec/glyf
  67  */
  68 #define HB_OT_TAG_glyf HB_TAG('g','l','y','f')
  69 
  70 
  71 struct glyf
  72 {
  73   static const hb_tag_t tableTag = HB_OT_TAG_glyf;
  74 
  75   inline bool sanitize (hb_sanitize_context_t *c) const
  76   {
  77     TRACE_SANITIZE (this);
  78     /* We don't check for anything specific here.  The users of the
  79      * struct do all the hard work... */
  80     return_trace (true);
  81   }
  82 
  83   inline bool subset (hb_subset_plan_t *plan) const
  84   {
  85     hb_blob_t *glyf_prime = nullptr;
  86     hb_blob_t *loca_prime = nullptr;
  87 
  88     bool success = true;
  89     bool use_short_loca = false;
  90     if (hb_subset_glyf_and_loca (plan, &use_short_loca, &glyf_prime, &loca_prime)) {
  91       success = success && plan->add_table (HB_OT_TAG_glyf, glyf_prime);
  92       success = success && plan->add_table (HB_OT_TAG_loca, loca_prime);
  93       success = success && _add_head_and_set_loca_version (plan, use_short_loca);
  94     } else {
  95       success = false;
  96     }
  97     hb_blob_destroy (loca_prime);
  98     hb_blob_destroy (glyf_prime);
  99 
 100     return success;
 101   }
 102 
 103   static bool
 104   _add_head_and_set_loca_version (hb_subset_plan_t *plan, bool use_short_loca)
 105   {
 106     hb_blob_t *head_blob = OT::Sanitizer<OT::head>().sanitize (hb_face_reference_table (plan->source, HB_OT_TAG_head));
 107     hb_blob_t *head_prime_blob = hb_blob_copy_writable_or_fail (head_blob);
 108     hb_blob_destroy (head_blob);
 109 
 110     if (unlikely (!head_prime_blob))
 111       return false;
 112 
 113     OT::head *head_prime = (OT::head *) hb_blob_get_data_writable (head_prime_blob, nullptr);
 114     head_prime->indexToLocFormat.set (use_short_loca ? 0 : 1);
 115     bool success = plan->add_table (HB_OT_TAG_head, head_prime_blob);
 116 
 117     hb_blob_destroy (head_prime_blob);
 118     return success;
 119   }
 120 
 121   struct GlyphHeader
 122   {
 123     HBINT16             numberOfContours;       /* If the number of contours is
 124                                                  * greater than or equal to zero,
 125                                                  * this is a simple glyph; if negative,
 126                                                  * this is a composite glyph. */
 127     FWORD               xMin;                   /* Minimum x for coordinate data. */
 128     FWORD               yMin;                   /* Minimum y for coordinate data. */
 129     FWORD               xMax;                   /* Maximum x for coordinate data. */
 130     FWORD               yMax;                   /* Maximum y for coordinate data. */
 131 
 132     DEFINE_SIZE_STATIC (10);
 133   };
 134 
 135   struct CompositeGlyphHeader
 136   {
 137     enum composite_glyph_flag_t {
 138       ARG_1_AND_2_ARE_WORDS =      0x0001,
 139       ARGS_ARE_XY_VALUES =         0x0002,
 140       ROUND_XY_TO_GRID =           0x0004,
 141       WE_HAVE_A_SCALE =            0x0008,
 142       MORE_COMPONENTS =            0x0020,
 143       WE_HAVE_AN_X_AND_Y_SCALE =   0x0040,
 144       WE_HAVE_A_TWO_BY_TWO =       0x0080,
 145       WE_HAVE_INSTRUCTIONS =       0x0100,
 146       USE_MY_METRICS =             0x0200,
 147       OVERLAP_COMPOUND =           0x0400,
 148       SCALED_COMPONENT_OFFSET =    0x0800,
 149       UNSCALED_COMPONENT_OFFSET =  0x1000
 150     };
 151 
 152     HBUINT16 flags;
 153     HBUINT16 glyphIndex;
 154 
 155     inline unsigned int get_size (void) const
 156     {
 157       unsigned int size = min_size;
 158       if (flags & ARG_1_AND_2_ARE_WORDS) {
 159         // arg1 and 2 are int16
 160         size += 4;
 161       } else {
 162         // arg1 and 2 are int8
 163         size += 2;
 164       }
 165       if (flags & WE_HAVE_A_SCALE) {
 166         // One x 16 bit (scale)
 167         size += 2;
 168       } else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) {
 169         // Two x 16 bit (xscale, yscale)
 170         size += 4;
 171       } else if (flags & WE_HAVE_A_TWO_BY_TWO) {
 172         // Four x 16 bit (xscale, scale01, scale10, yscale)
 173         size += 8;
 174       }
 175       return size;
 176     }
 177 
 178     struct Iterator
 179     {
 180       const char *glyph_start;
 181       const char *glyph_end;
 182       const CompositeGlyphHeader *current;
 183 
 184       inline bool move_to_next ()
 185       {
 186         if (current->flags & CompositeGlyphHeader::MORE_COMPONENTS)
 187         {
 188           const CompositeGlyphHeader *possible =
 189             &StructAfter<CompositeGlyphHeader, CompositeGlyphHeader> (*current);
 190           if (!in_range (possible))
 191             return false;
 192           current = possible;
 193           return true;
 194         }
 195         return false;
 196       }
 197 
 198       inline bool in_range (const CompositeGlyphHeader *composite) const
 199       {
 200         return (const char *) composite >= glyph_start
 201           && ((const char *) composite + CompositeGlyphHeader::min_size) <= glyph_end
 202           && ((const char *) composite + composite->get_size()) <= glyph_end;
 203       }
 204     };
 205 
 206     static inline bool get_iterator (const char * glyph_data,
 207                                      unsigned int length,
 208                                      CompositeGlyphHeader::Iterator *iterator /* OUT */)
 209     {
 210       if (length < GlyphHeader::static_size)
 211         return false; /* Empty glyph; zero extents. */
 212 
 213       const GlyphHeader &glyph_header = StructAtOffset<GlyphHeader> (glyph_data, 0);
 214       if (glyph_header.numberOfContours < 0)
 215       {
 216         const CompositeGlyphHeader *possible =
 217           &StructAfter<CompositeGlyphHeader, GlyphHeader> (glyph_header);
 218 
 219         iterator->glyph_start = glyph_data;
 220         iterator->glyph_end = (const char *) glyph_data + length;
 221         if (!iterator->in_range (possible))
 222           return false;
 223         iterator->current = possible;
 224         return true;
 225       }
 226 
 227       return false;
 228     }
 229 
 230     DEFINE_SIZE_MIN (4);
 231   };
 232 
 233   struct accelerator_t
 234   {
 235     inline void init (hb_face_t *face)
 236     {
 237       memset (this, 0, sizeof (accelerator_t));
 238 
 239       hb_blob_t *head_blob = Sanitizer<head>().sanitize (face->reference_table (HB_OT_TAG_head));
 240       const head *head_table = head_blob->as<head> ();
 241       if (head_table == &Null(head) || (unsigned int) head_table->indexToLocFormat > 1 || head_table->glyphDataFormat != 0)
 242       {
 243         /* head table is not present, or in an unknown format.  Leave num_glyphs=0, that takes care of disabling us. */
 244         hb_blob_destroy (head_blob);
 245         return;
 246       }
 247       short_offset = 0 == head_table->indexToLocFormat;
 248       hb_blob_destroy (head_blob);
 249 
 250       loca_blob = Sanitizer<loca>().sanitize (face->reference_table (HB_OT_TAG_loca));
 251       loca_table = loca_blob->as<loca> ();
 252       glyf_blob = Sanitizer<glyf>().sanitize (face->reference_table (HB_OT_TAG_glyf));
 253       glyf_table = glyf_blob->as<glyf> ();
 254 
 255       num_glyphs = MAX (1u, hb_blob_get_length (loca_blob) / (short_offset ? 2 : 4)) - 1;
 256       glyf_len = hb_blob_get_length (glyf_blob);
 257     }
 258 
 259     inline void fini (void)
 260     {
 261       hb_blob_destroy (loca_blob);
 262       hb_blob_destroy (glyf_blob);
 263     }
 264 
 265     /*
 266      * Returns true if the referenced glyph is a valid glyph and a composite glyph.
 267      * If true is returned a pointer to the composite glyph will be written into
 268      * composite.
 269      */
 270     inline bool get_composite (hb_codepoint_t glyph,
 271                                CompositeGlyphHeader::Iterator *composite /* OUT */) const
 272     {
 273       if (this->glyf_table == &Null(glyf) || !num_glyphs)
 274         return false;
 275 
 276       unsigned int start_offset, end_offset;
 277       if (!get_offsets (glyph, &start_offset, &end_offset))
 278         return false; /* glyph not found */
 279 
 280       return CompositeGlyphHeader::get_iterator ((const char*) this->glyf_table + start_offset,
 281                                                  end_offset - start_offset,
 282                                                  composite);
 283     }
 284 
 285     enum simple_glyph_flag_t {
 286       FLAG_X_SHORT = 0x02,
 287       FLAG_Y_SHORT = 0x04,
 288       FLAG_REPEAT = 0x08,
 289       FLAG_X_SAME = 0x10,
 290       FLAG_Y_SAME = 0x20
 291     };
 292 
 293     /* based on FontTools _g_l_y_f.py::trim */
 294     inline bool remove_padding(unsigned int start_offset,
 295                                unsigned int *end_offset) const
 296     {
 297       if (*end_offset - start_offset < GlyphHeader::static_size)
 298         return true;
 299 
 300       const char *glyph = ((const char *) glyf_table) + start_offset;
 301       const char * const glyph_end = glyph + (*end_offset - start_offset);
 302       const GlyphHeader &glyph_header = StructAtOffset<GlyphHeader> (glyph, 0);
 303       int16_t num_contours = (int16_t) glyph_header.numberOfContours;
 304 
 305       if (num_contours < 0)
 306         /* Trimming for composites not implemented.
 307          * If removing hints it falls out of that. */
 308         return true;
 309       else if (num_contours > 0)
 310       {
 311         /* simple glyph w/contours, possibly trimmable */
 312         glyph += GlyphHeader::static_size + 2 * num_contours;
 313 
 314         if (unlikely (glyph + 2 >= glyph_end)) return false;
 315         uint16_t nCoordinates = (uint16_t) StructAtOffset<HBUINT16>(glyph - 2, 0) + 1;
 316         uint16_t nInstructions = (uint16_t) StructAtOffset<HBUINT16>(glyph, 0);
 317 
 318         glyph += 2 + nInstructions;
 319         if (unlikely (glyph + 2 >= glyph_end)) return false;
 320 
 321         unsigned int coordBytes = 0;
 322         unsigned int coordsWithFlags = 0;
 323         while (glyph < glyph_end)
 324         {
 325           uint8_t flag = (uint8_t) *glyph;
 326           glyph++;
 327 
 328           unsigned int repeat = 1;
 329           if (flag & FLAG_REPEAT)
 330           {
 331             if (glyph >= glyph_end)
 332             {
 333               DEBUG_MSG(SUBSET, nullptr, "Bad flag");
 334               return false;
 335             }
 336             repeat = ((uint8_t) *glyph) + 1;
 337             glyph++;
 338           }
 339 
 340           unsigned int xBytes, yBytes;
 341           xBytes = yBytes = 0;
 342           if (flag & FLAG_X_SHORT)
 343             xBytes = 1;
 344           else if ((flag & FLAG_X_SAME) == 0)
 345             xBytes = 2;
 346 
 347           if (flag & FLAG_Y_SHORT)
 348             yBytes = 1;
 349           else if ((flag & FLAG_Y_SAME) == 0)
 350             yBytes = 2;
 351 
 352           coordBytes += (xBytes + yBytes) * repeat;
 353           coordsWithFlags += repeat;
 354           if (coordsWithFlags >= nCoordinates)
 355             break;
 356         }
 357 
 358         if (coordsWithFlags != nCoordinates)
 359         {
 360           DEBUG_MSG(SUBSET, nullptr, "Expect %d coords to have flags, got flags for %d", nCoordinates, coordsWithFlags);
 361           return false;
 362         }
 363         glyph += coordBytes;
 364 
 365         if (glyph < glyph_end)
 366           *end_offset -= glyph_end - glyph;
 367       }
 368       return true;
 369     }
 370 
 371     inline bool get_offsets (hb_codepoint_t  glyph,
 372                              unsigned int   *start_offset /* OUT */,
 373                              unsigned int   *end_offset   /* OUT */) const
 374     {
 375       if (unlikely (glyph >= num_glyphs))
 376         return false;
 377 
 378       if (short_offset)
 379       {
 380         const HBUINT16 *offsets = (const HBUINT16 *) loca_table->dataZ;
 381         *start_offset = 2 * offsets[glyph];
 382         *end_offset   = 2 * offsets[glyph + 1];
 383       }
 384       else
 385       {
 386         const HBUINT32 *offsets = (const HBUINT32 *) loca_table->dataZ;
 387 
 388         *start_offset = offsets[glyph];
 389         *end_offset   = offsets[glyph + 1];
 390       }
 391 
 392       if (*start_offset > *end_offset || *end_offset > glyf_len)
 393         return false;
 394 
 395       return true;
 396     }
 397 
 398     inline bool get_instruction_offsets(unsigned int start_offset,
 399                                         unsigned int end_offset,
 400                                         unsigned int *instruction_start /* OUT */,
 401                                         unsigned int *instruction_end /* OUT */) const
 402     {
 403       if (end_offset - start_offset < GlyphHeader::static_size)
 404       {
 405         *instruction_start = 0;
 406         *instruction_end = 0;
 407         return true; /* Empty glyph; no instructions. */
 408       }
 409       const GlyphHeader &glyph_header = StructAtOffset<GlyphHeader> (glyf_table, start_offset);
 410       int16_t num_contours = (int16_t) glyph_header.numberOfContours;
 411       if (num_contours < 0)
 412       {
 413         CompositeGlyphHeader::Iterator composite_it;
 414         if (unlikely (!CompositeGlyphHeader::get_iterator (
 415             (const char*) this->glyf_table + start_offset,
 416              end_offset - start_offset, &composite_it))) return false;
 417         const CompositeGlyphHeader *last;
 418         do {
 419           last = composite_it.current;
 420         } while (composite_it.move_to_next());
 421 
 422         if ( (uint16_t) last->flags & CompositeGlyphHeader::WE_HAVE_INSTRUCTIONS)
 423           *instruction_start = ((char *) last - (char *) glyf_table->dataZ) + last->get_size();
 424         else
 425           *instruction_start = end_offset;
 426         *instruction_end = end_offset;
 427         if (unlikely (*instruction_start > *instruction_end))
 428         {
 429           DEBUG_MSG(SUBSET, nullptr, "Invalid instruction offset, %d is outside [%d, %d]", *instruction_start, start_offset, end_offset);
 430           return false;
 431         }
 432       }
 433       else
 434       {
 435         unsigned int instruction_length_offset = start_offset + GlyphHeader::static_size + 2 * num_contours;
 436         if (unlikely (instruction_length_offset + 2 > end_offset))
 437         {
 438           DEBUG_MSG(SUBSET, nullptr, "Glyph size is too short, missing field instructionLength.");
 439           return false;
 440         }
 441 
 442         const HBUINT16 &instruction_length = StructAtOffset<HBUINT16> (glyf_table, instruction_length_offset);
 443         unsigned int start = instruction_length_offset + 2;
 444         unsigned int end = start + (uint16_t) instruction_length;
 445         if (unlikely (end > end_offset)) // Out of bounds of the current glyph
 446         {
 447           DEBUG_MSG(SUBSET, nullptr, "The instructions array overruns the glyph's boundaries.");
 448           return false;
 449         }
 450 
 451         *instruction_start = start;
 452         *instruction_end = end;
 453       }
 454       return true;
 455     }
 456 
 457     inline bool get_extents (hb_codepoint_t glyph,
 458                              hb_glyph_extents_t *extents) const
 459     {
 460       unsigned int start_offset, end_offset;
 461       if (!get_offsets (glyph, &start_offset, &end_offset))
 462         return false;
 463 
 464       if (end_offset - start_offset < GlyphHeader::static_size)
 465         return true; /* Empty glyph; zero extents. */
 466 
 467       const GlyphHeader &glyph_header = StructAtOffset<GlyphHeader> (glyf_table, start_offset);
 468 
 469       extents->x_bearing = MIN (glyph_header.xMin, glyph_header.xMax);
 470       extents->y_bearing = MAX (glyph_header.yMin, glyph_header.yMax);
 471       extents->width     = MAX (glyph_header.xMin, glyph_header.xMax) - extents->x_bearing;
 472       extents->height    = MIN (glyph_header.yMin, glyph_header.yMax) - extents->y_bearing;
 473 
 474       return true;
 475     }
 476 
 477     private:
 478     bool short_offset;
 479     unsigned int num_glyphs;
 480     const loca *loca_table;
 481     const glyf *glyf_table;
 482     hb_blob_t *loca_blob;
 483     hb_blob_t *glyf_blob;
 484     unsigned int glyf_len;
 485   };
 486 
 487   protected:
 488   HBUINT8               dataZ[VAR];             /* Glyphs data. */
 489 
 490   DEFINE_SIZE_ARRAY (0, dataZ);
 491 };
 492 
 493 } /* namespace OT */
 494 
 495 
 496 #endif /* HB_OT_GLYF_TABLE_HH */