tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

CompositeGlyph.hh (11667B)


      1 #ifndef OT_GLYF_COMPOSITEGLYPH_HH
      2 #define OT_GLYF_COMPOSITEGLYPH_HH
      3 
      4 
      5 #include "../../hb-open-type.hh"
      6 #include "composite-iter.hh"
      7 
      8 
      9 namespace OT {
     10 namespace glyf_impl {
     11 
     12 
     13 struct CompositeGlyphRecord
     14 {
     15  protected:
     16  enum composite_glyph_flag_t
     17  {
     18    ARG_1_AND_2_ARE_WORDS	= 0x0001,
     19    ARGS_ARE_XY_VALUES		= 0x0002,
     20    ROUND_XY_TO_GRID		= 0x0004,
     21    WE_HAVE_A_SCALE		= 0x0008,
     22    MORE_COMPONENTS		= 0x0020,
     23    WE_HAVE_AN_X_AND_Y_SCALE	= 0x0040,
     24    WE_HAVE_A_TWO_BY_TWO	= 0x0080,
     25    WE_HAVE_INSTRUCTIONS	= 0x0100,
     26    USE_MY_METRICS		= 0x0200,
     27    OVERLAP_COMPOUND		= 0x0400,
     28    SCALED_COMPONENT_OFFSET	= 0x0800,
     29    UNSCALED_COMPONENT_OFFSET	= 0x1000,
     30 #ifndef HB_NO_BEYOND_64K
     31    GID_IS_24BIT		= 0x2000
     32 #endif
     33  };
     34 
     35  public:
     36  unsigned int get_size () const
     37  {
     38    unsigned int size = min_size;
     39    /* glyphIndex is 24bit instead of 16bit */
     40 #ifndef HB_NO_BEYOND_64K
     41    if (flags & GID_IS_24BIT) size += HBGlyphID24::static_size - HBGlyphID16::static_size;
     42 #endif
     43    /* arg1 and 2 are int16 */
     44    if (flags & ARG_1_AND_2_ARE_WORDS) size += 4;
     45    /* arg1 and 2 are int8 */
     46    else size += 2;
     47 
     48    /* One x 16 bit (scale) */
     49    if (flags & WE_HAVE_A_SCALE) size += 2;
     50    /* Two x 16 bit (xscale, yscale) */
     51    else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) size += 4;
     52    /* Four x 16 bit (xscale, scale01, scale10, yscale) */
     53    else if (flags & WE_HAVE_A_TWO_BY_TWO) size += 8;
     54 
     55    return size;
     56  }
     57 
     58  void drop_instructions_flag ()  { flags = (uint16_t) flags & ~WE_HAVE_INSTRUCTIONS; }
     59  void set_overlaps_flag ()
     60  {
     61    flags = (uint16_t) flags | OVERLAP_COMPOUND;
     62  }
     63 
     64  bool has_instructions ()  const { return   flags & WE_HAVE_INSTRUCTIONS; }
     65 
     66  bool has_more ()          const { return   flags & MORE_COMPONENTS; }
     67  bool is_use_my_metrics () const { return   flags & USE_MY_METRICS; }
     68  bool is_anchored ()       const { return !(flags & ARGS_ARE_XY_VALUES); }
     69  void get_anchor_points (unsigned int &point1, unsigned int &point2) const
     70  {
     71    const auto *p = &StructAfter<const HBUINT8> (flags);
     72 #ifndef HB_NO_BEYOND_64K
     73    if (flags & GID_IS_24BIT)
     74      p += HBGlyphID24::static_size;
     75    else
     76 #endif
     77      p += HBGlyphID16::static_size;
     78    if (flags & ARG_1_AND_2_ARE_WORDS)
     79    {
     80      point1 = ((const HBUINT16 *) p)[0];
     81      point2 = ((const HBUINT16 *) p)[1];
     82    }
     83    else
     84    {
     85      point1 = p[0];
     86      point2 = p[1];
     87    }
     88  }
     89 
     90  static void transform (const float (&matrix)[4],
     91 		 hb_array_t<contour_point_t> points)
     92  {
     93    if (matrix[0] != 1.f || matrix[1] != 0.f ||
     94 matrix[2] != 0.f || matrix[3] != 1.f)
     95      for (auto &point : points)
     96        point.transform (matrix);
     97  }
     98 
     99  static void translate (const contour_point_t &trans,
    100 		 hb_array_t<contour_point_t> points)
    101  {
    102    if (HB_OPTIMIZE_SIZE_VAL)
    103    {
    104      if (trans.x != 0.f || trans.y != 0.f)
    105        for (auto &point : points)
    106   point.translate (trans);
    107    }
    108    else
    109    {
    110      if (trans.x != 0.f && trans.y != 0.f)
    111        for (auto &point : points)
    112   point.translate (trans);
    113      else
    114      {
    115 if (trans.x != 0.f)
    116   for (auto &point : points)
    117     point.x += trans.x;
    118 else if (trans.y != 0.f)
    119   for (auto &point : points)
    120     point.y += trans.y;
    121      }
    122    }
    123  }
    124 
    125  void transform_points (hb_array_t<contour_point_t> points,
    126 		 const float (&matrix)[4],
    127 		 const contour_point_t &trans) const
    128  {
    129    if (scaled_offsets ())
    130    {
    131      translate (trans, points);
    132      transform (matrix, points);
    133    }
    134    else
    135    {
    136      transform (matrix, points);
    137      translate (trans, points);
    138    }
    139  }
    140 
    141  bool get_points (contour_point_vector_t &points) const
    142  {
    143    float matrix[4];
    144    contour_point_t trans;
    145    get_transformation (matrix, trans);
    146    if (unlikely (!points.alloc (points.length + 1 + 4))) return false; // For phantom points
    147    points.push (trans);
    148    return true;
    149  }
    150 
    151  unsigned compile_with_point (const contour_point_t &point,
    152                               char *out) const
    153  {
    154    const HBINT8 *p = &StructAfter<const HBINT8> (flags);
    155 #ifndef HB_NO_BEYOND_64K
    156    if (flags & GID_IS_24BIT)
    157      p += HBGlyphID24::static_size;
    158    else
    159 #endif
    160      p += HBGlyphID16::static_size;
    161 
    162    unsigned len = get_size ();
    163    unsigned len_before_val = (const char *)p - (const char *)this;
    164    if (flags & ARG_1_AND_2_ARE_WORDS)
    165    {
    166      // no overflow, copy value
    167      hb_memcpy (out, this, len);
    168 
    169      HBINT16 *o = reinterpret_cast<HBINT16 *> (out + len_before_val);
    170      o[0] = roundf (point.x);
    171      o[1] = roundf (point.y);
    172    }
    173    else
    174    {
    175      int new_x = roundf (point.x);
    176      int new_y = roundf (point.y);
    177      if (new_x <= 127 && new_x >= -128 &&
    178          new_y <= 127 && new_y >= -128)
    179      {
    180        hb_memcpy (out, this, len);
    181        HBINT8 *o = reinterpret_cast<HBINT8 *> (out + len_before_val);
    182        o[0] = new_x;
    183        o[1] = new_y;
    184      }
    185      else
    186      {
    187        // new point value has an int8 overflow
    188        hb_memcpy (out, this, len_before_val);
    189        
    190        //update flags
    191        CompositeGlyphRecord *o = reinterpret_cast<CompositeGlyphRecord *> (out);
    192        o->flags = flags | ARG_1_AND_2_ARE_WORDS;
    193        out += len_before_val;
    194 
    195        HBINT16 new_value;
    196        new_value = new_x;
    197        hb_memcpy (out, &new_value, HBINT16::static_size);
    198        out += HBINT16::static_size;
    199 
    200        new_value = new_y;
    201        hb_memcpy (out, &new_value, HBINT16::static_size);
    202        out += HBINT16::static_size;
    203 
    204        hb_memcpy (out, p+2, len - len_before_val - 2);
    205        len += 2;
    206      }
    207    }
    208    return len;
    209  }
    210 
    211  protected:
    212  bool scaled_offsets () const
    213  { return (flags & (SCALED_COMPONENT_OFFSET | UNSCALED_COMPONENT_OFFSET)) == SCALED_COMPONENT_OFFSET; }
    214 
    215  public:
    216  bool get_transformation (float (&matrix)[4], contour_point_t &trans) const
    217  {
    218    matrix[0] = matrix[3] = 1.f;
    219    matrix[1] = matrix[2] = 0.f;
    220 
    221    const auto *p = &StructAfter<const HBINT8> (flags);
    222 #ifndef HB_NO_BEYOND_64K
    223    if (flags & GID_IS_24BIT)
    224      p += HBGlyphID24::static_size;
    225    else
    226 #endif
    227      p += HBGlyphID16::static_size;
    228    int tx, ty;
    229    if (flags & ARG_1_AND_2_ARE_WORDS)
    230    {
    231      tx = *(const HBINT16 *) p;
    232      p += HBINT16::static_size;
    233      ty = *(const HBINT16 *) p;
    234      p += HBINT16::static_size;
    235    }
    236    else
    237    {
    238      tx = *p++;
    239      ty = *p++;
    240    }
    241    if (is_anchored ()) tx = ty = 0;
    242 
    243    /* set is_end_point flag to true, used by IUP delta optimization */
    244    trans.init ((float) tx, (float) ty, true);
    245 
    246    {
    247      const F2DOT14 *points = (const F2DOT14 *) p;
    248      if (flags & WE_HAVE_A_SCALE)
    249      {
    250 matrix[0] = matrix[3] = points[0].to_float ();
    251 return true;
    252      }
    253      else if (flags & WE_HAVE_AN_X_AND_Y_SCALE)
    254      {
    255 matrix[0] = points[0].to_float ();
    256 matrix[3] = points[1].to_float ();
    257 return true;
    258      }
    259      else if (flags & WE_HAVE_A_TWO_BY_TWO)
    260      {
    261 matrix[0] = points[0].to_float ();
    262 matrix[1] = points[1].to_float ();
    263 matrix[2] = points[2].to_float ();
    264 matrix[3] = points[3].to_float ();
    265 return true;
    266      }
    267    }
    268    return tx || ty;
    269  }
    270 
    271  hb_codepoint_t get_gid () const
    272  {
    273 #ifndef HB_NO_BEYOND_64K
    274    if (flags & GID_IS_24BIT)
    275      return StructAfter<const HBGlyphID24> (flags);
    276    else
    277 #endif
    278      return StructAfter<const HBGlyphID16> (flags);
    279  }
    280  void set_gid (hb_codepoint_t gid)
    281  {
    282 #ifndef HB_NO_BEYOND_64K
    283    if (flags & GID_IS_24BIT)
    284      StructAfter<HBGlyphID24> (flags) = gid;
    285    else
    286 #endif
    287      /* TODO assert? */
    288      StructAfter<HBGlyphID16> (flags) = gid;
    289  }
    290 
    291 #ifndef HB_NO_BEYOND_64K
    292  void lower_gid_24_to_16 ()
    293  {
    294    hb_codepoint_t gid = get_gid ();
    295    if (!(flags & GID_IS_24BIT) || gid > 0xFFFFu)
    296      return;
    297 
    298    /* Lower the flag and move the rest of the struct down. */
    299 
    300    unsigned size = get_size ();
    301    char *end = (char *) this + size;
    302    char *p = &StructAfter<char> (flags);
    303    p += HBGlyphID24::static_size;
    304 
    305    flags = flags & ~GID_IS_24BIT;
    306    set_gid (gid);
    307 
    308    memmove (p - HBGlyphID24::static_size + HBGlyphID16::static_size, p, end - p);
    309  }
    310 #endif
    311 
    312  protected:
    313  HBUINT16	flags;
    314  HBUINT24	pad;
    315  public:
    316  DEFINE_SIZE_MIN (4);
    317 };
    318 
    319 using composite_iter_t = composite_iter_tmpl<CompositeGlyphRecord>;
    320 
    321 struct CompositeGlyph
    322 {
    323  const GlyphHeader &header;
    324  hb_bytes_t bytes;
    325  CompositeGlyph (const GlyphHeader &header_, hb_bytes_t bytes_) :
    326    header (header_), bytes (bytes_) {}
    327 
    328  composite_iter_t iter () const
    329  { return composite_iter_t (bytes, &StructAfter<CompositeGlyphRecord, GlyphHeader> (header)); }
    330 
    331  unsigned int instructions_length (hb_bytes_t bytes) const
    332  {
    333    unsigned int start = bytes.length;
    334    unsigned int end = bytes.length;
    335    const CompositeGlyphRecord *last = nullptr;
    336    for (auto &item : iter ())
    337      last = &item;
    338    if (unlikely (!last)) return 0;
    339 
    340    if (last->has_instructions ())
    341      start = (char *) last - &bytes + last->get_size ();
    342    if (unlikely (start > end)) return 0;
    343    return end - start;
    344  }
    345 
    346  /* Trimming for composites not implemented.
    347   * If removing hints it falls out of that. */
    348  const hb_bytes_t trim_padding () const { return bytes; }
    349 
    350  void drop_hints ()
    351  {
    352    for (const auto &_ : iter ())
    353      const_cast<CompositeGlyphRecord &> (_).drop_instructions_flag ();
    354  }
    355 
    356  /* Chop instructions off the end */
    357  void drop_hints_bytes (hb_bytes_t &dest_start) const
    358  { dest_start = bytes.sub_array (0, bytes.length - instructions_length (bytes)); }
    359 
    360  void set_overlaps_flag ()
    361  {
    362    CompositeGlyphRecord& glyph_chain = const_cast<CompositeGlyphRecord &> (
    363 StructAfter<CompositeGlyphRecord, GlyphHeader> (header));
    364    if (!bytes.check_range(&glyph_chain, CompositeGlyphRecord::min_size))
    365      return;
    366    glyph_chain.set_overlaps_flag ();
    367  }
    368 
    369  bool compile_bytes_with_deltas (const hb_bytes_t &source_bytes,
    370                                  const contour_point_vector_t &points_with_deltas,
    371                                  hb_bytes_t &dest_bytes /* OUT */)
    372  {
    373    if (source_bytes.length <= GlyphHeader::static_size ||
    374        header.numberOfContours != -1)
    375    {
    376      dest_bytes = hb_bytes_t ();
    377      return true;
    378    }
    379 
    380    unsigned source_len = source_bytes.length - GlyphHeader::static_size;
    381 
    382    /* try to allocate more memories than source glyph bytes
    383     * in case that there might be an overflow for int8 value
    384     * and we would need to use int16 instead */
    385    char *o = (char *) hb_calloc (source_len * 2, sizeof (char));
    386    if (unlikely (!o)) return false;
    387 
    388    const CompositeGlyphRecord *c = reinterpret_cast<const CompositeGlyphRecord *> (source_bytes.arrayZ + GlyphHeader::static_size);
    389    auto it = composite_iter_t (hb_bytes_t ((const char *)c, source_len), c);
    390 
    391    char *p = o;
    392    unsigned i = 0, source_comp_len = 0;
    393    for (const auto &component : it)
    394    {
    395      /* last 4 points in points_with_deltas are phantom points and should not be included */
    396      if (i >= points_with_deltas.length - 4) {
    397        hb_free (o);
    398        return false;
    399      }
    400 
    401      unsigned comp_len = component.get_size ();
    402      if (component.is_anchored ())
    403      {
    404        hb_memcpy (p, &component, comp_len);
    405        p += comp_len;
    406      }
    407      else
    408      {
    409        unsigned new_len = component.compile_with_point (points_with_deltas[i], p);
    410        p += new_len;
    411      }
    412      i++;
    413      source_comp_len += comp_len;
    414    }
    415 
    416    //copy instructions if any
    417    if (source_len > source_comp_len)
    418    {
    419      unsigned instr_len = source_len - source_comp_len;
    420      hb_memcpy (p, (const char *)c + source_comp_len, instr_len);
    421      p += instr_len;
    422    }
    423 
    424    unsigned len = p - o;
    425    dest_bytes = hb_bytes_t (o, len);
    426    return true;
    427  }
    428 };
    429 
    430 
    431 } /* namespace glyf_impl */
    432 } /* namespace OT */
    433 
    434 
    435 #endif /* OT_GLYF_COMPOSITEGLYPH_HH */