tor-browser

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

ValueFormat.hh (15834B)


      1 #ifndef OT_LAYOUT_GPOS_VALUEFORMAT_HH
      2 #define OT_LAYOUT_GPOS_VALUEFORMAT_HH
      3 
      4 #include "../../../hb-ot-layout-gsubgpos.hh"
      5 
      6 namespace OT {
      7 namespace Layout {
      8 namespace GPOS_impl {
      9 
     10 typedef HBUINT16 Value;
     11 
     12 struct ValueBase {}; // Dummy base class tag for OffsetTo<Value> bases.
     13 
     14 typedef UnsizedArrayOf<Value> ValueRecord;
     15 
     16 struct ValueFormat : HBUINT16
     17 {
     18  enum Flags {
     19    xPlacement  = 0x0001u,      /* Includes horizontal adjustment for placement */
     20    yPlacement  = 0x0002u,      /* Includes vertical adjustment for placement */
     21    xAdvance    = 0x0004u,      /* Includes horizontal adjustment for advance */
     22    yAdvance    = 0x0008u,      /* Includes vertical adjustment for advance */
     23    xPlaDevice  = 0x0010u,      /* Includes horizontal Device table for placement */
     24    yPlaDevice  = 0x0020u,      /* Includes vertical Device table for placement */
     25    xAdvDevice  = 0x0040u,      /* Includes horizontal Device table for advance */
     26    yAdvDevice  = 0x0080u,      /* Includes vertical Device table for advance */
     27    ignored     = 0x0F00u,      /* Was used in TrueType Open for MM fonts */
     28    reserved    = 0xF000u,      /* For future use */
     29 
     30    devices     = 0x00F0u       /* Mask for having any Device table */
     31  };
     32 
     33 /* All fields are options.  Only those available advance the value pointer. */
     34 #if 0
     35  HBINT16               xPlacement;     /* Horizontal adjustment for
     36                                         * placement--in design units */
     37  HBINT16               yPlacement;     /* Vertical adjustment for
     38                                         * placement--in design units */
     39  HBINT16               xAdvance;       /* Horizontal adjustment for
     40                                         * advance--in design units (only used
     41                                         * for horizontal writing) */
     42  HBINT16               yAdvance;       /* Vertical adjustment for advance--in
     43                                         * design units (only used for vertical
     44                                         * writing) */
     45  Offset16To<Device>    xPlaDevice;     /* Offset to Device table for
     46                                         * horizontal placement--measured from
     47                                         * beginning of PosTable (may be NULL) */
     48  Offset16To<Device>    yPlaDevice;     /* Offset to Device table for vertical
     49                                         * placement--measured from beginning
     50                                         * of PosTable (may be NULL) */
     51  Offset16To<Device>    xAdvDevice;     /* Offset to Device table for
     52                                         * horizontal advance--measured from
     53                                         * beginning of PosTable (may be NULL) */
     54  Offset16To<Device>    yAdvDevice;     /* Offset to Device table for vertical
     55                                         * advance--measured from beginning of
     56                                         * PosTable (may be NULL) */
     57 #endif
     58 
     59  NumType& operator = (uint16_t i) { v = i; return *this; }
     60 
     61  // Note: spec says skip 2 bytes per bit in the valueformat. But reports
     62  // from Microsoft developers indicate that only the fields that are
     63  // currently defined are counted. We don't expect any new fields to
     64  // be added to ValueFormat. As such, we use the faster hb_popcount8
     65  // that only processes the lowest 8 bits.
     66  unsigned int get_len () const  { return hb_popcount8 ((uint8_t) *this); }
     67  unsigned int get_size () const { return get_len () * Value::static_size; }
     68 
     69  hb_vector_t<unsigned> get_device_table_indices () const {
     70    unsigned i = 0;
     71    hb_vector_t<unsigned> result;
     72    unsigned format = *this;
     73 
     74    if (format & xPlacement) i++;
     75    if (format & yPlacement) i++;
     76    if (format & xAdvance)   i++;
     77    if (format & yAdvance)   i++;
     78 
     79    if (format & xPlaDevice) result.push (i++);
     80    if (format & yPlaDevice) result.push (i++);
     81    if (format & xAdvDevice) result.push (i++);
     82    if (format & yAdvDevice) result.push (i++);
     83 
     84    return result;
     85  }
     86 
     87  bool apply_value (hb_ot_apply_context_t *c,
     88                    const ValueBase       *base,
     89                    const Value           *values,
     90                    hb_glyph_position_t   &glyph_pos) const
     91  {
     92    bool ret = false;
     93    unsigned int format = *this;
     94    if (!format) return ret;
     95 
     96    hb_font_t *font = c->font;
     97    bool horizontal =
     98 #ifndef HB_NO_VERTICAL
     99      HB_DIRECTION_IS_HORIZONTAL (c->direction)
    100 #else
    101      true
    102 #endif
    103      ;
    104 
    105    if (format & xPlacement) glyph_pos.x_offset  += font->em_scale_x (get_short (values++, &ret));
    106    if (format & yPlacement) glyph_pos.y_offset  += font->em_scale_y (get_short (values++, &ret));
    107    if (format & xAdvance) {
    108      if (likely (horizontal)) glyph_pos.x_advance += font->em_scale_x (get_short (values, &ret));
    109      values++;
    110    }
    111    /* y_advance values grow downward but font-space grows upward, hence negation */
    112    if (format & yAdvance) {
    113      if (unlikely (!horizontal)) glyph_pos.y_advance -= font->em_scale_y (get_short (values, &ret));
    114      values++;
    115    }
    116 
    117    if (!has_device ()) return ret;
    118 
    119    bool use_x_device = font->x_ppem || font->has_nonzero_coords;
    120    bool use_y_device = font->y_ppem || font->has_nonzero_coords;
    121 
    122    if (!use_x_device && !use_y_device) return ret;
    123 
    124    const ItemVariationStore &store = c->var_store;
    125    auto *cache = c->var_store_cache;
    126 
    127    /* pixel -> fractional pixel */
    128    if (format & xPlaDevice)
    129    {
    130      if (use_x_device) glyph_pos.x_offset  += get_device (values, &ret, base, c->sanitizer).get_x_delta (font, store, cache);
    131      values++;
    132    }
    133    if (format & yPlaDevice)
    134    {
    135      if (use_y_device) glyph_pos.y_offset  += get_device (values, &ret, base, c->sanitizer).get_y_delta (font, store, cache);
    136      values++;
    137    }
    138    if (format & xAdvDevice)
    139    {
    140      if (horizontal && use_x_device) glyph_pos.x_advance += get_device (values, &ret, base, c->sanitizer).get_x_delta (font, store, cache);
    141      values++;
    142    }
    143    if (format & yAdvDevice)
    144    {
    145      /* y_advance values grow downward but font-space grows upward, hence negation */
    146      if (!horizontal && use_y_device) glyph_pos.y_advance -= get_device (values, &ret, base, c->sanitizer).get_y_delta (font, store, cache);
    147      values++;
    148    }
    149    return ret;
    150  }
    151 
    152  unsigned int get_effective_format (const Value *values, bool strip_hints, bool strip_empty, const ValueBase *base,
    153                                     const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *varidx_delta_map) const
    154  {
    155    unsigned int format = *this;
    156    for (unsigned flag = xPlacement; flag <= yAdvDevice; flag = flag << 1) {
    157      if (format & flag)
    158      {
    159        if (strip_hints && flag >= xPlaDevice)
    160        {
    161          format = format & ~flag;
    162          values++;
    163          continue;
    164        }
    165        if (varidx_delta_map && flag >= xPlaDevice)
    166        {
    167          update_var_flag (values++, (Flags) flag, &format, base, varidx_delta_map);
    168          continue;
    169        }
    170        /* do not strip empty when instancing, cause we don't know whether the new
    171         * default value is 0 or not */
    172        if (strip_empty) should_drop (*values, (Flags) flag, &format);
    173        values++;
    174      }
    175    }
    176 
    177    return format;
    178  }
    179 
    180  template<typename Iterator,
    181      hb_requires (hb_is_iterator (Iterator))>
    182  unsigned int get_effective_format (Iterator it, bool strip_hints, bool strip_empty, const ValueBase *base,
    183                                     const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *varidx_delta_map) const {
    184    unsigned int new_format = 0;
    185 
    186    for (const hb_array_t<const Value>& values : it)
    187      new_format = new_format | get_effective_format (&values, strip_hints, strip_empty, base, varidx_delta_map);
    188 
    189    return new_format;
    190  }
    191 
    192  void copy_values (hb_serialize_context_t *c,
    193                    unsigned int new_format,
    194                    const ValueBase *base,
    195                    const Value *values,
    196                    const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map) const
    197  {
    198    unsigned int format = *this;
    199    if (!format) return;
    200 
    201    HBINT16 *x_placement = nullptr, *y_placement = nullptr, *x_adv = nullptr, *y_adv = nullptr;
    202    if (format & xPlacement) x_placement = copy_value (c, new_format, xPlacement, *values++);
    203    if (format & yPlacement) y_placement = copy_value (c, new_format, yPlacement, *values++);
    204    if (format & xAdvance)   x_adv = copy_value (c, new_format, xAdvance, *values++);
    205    if (format & yAdvance)   y_adv = copy_value (c, new_format, yAdvance, *values++);
    206 
    207    if (!has_device ())
    208      return;
    209 
    210    if (format & xPlaDevice)
    211    {
    212      add_delta_to_value (x_placement, base, values, layout_variation_idx_delta_map);
    213      copy_device (c, base, values++, layout_variation_idx_delta_map, new_format, xPlaDevice);
    214    }
    215 
    216    if (format & yPlaDevice)
    217    {
    218      add_delta_to_value (y_placement, base, values, layout_variation_idx_delta_map);
    219      copy_device (c, base, values++, layout_variation_idx_delta_map, new_format, yPlaDevice);
    220    }
    221 
    222    if (format & xAdvDevice)
    223    {
    224      add_delta_to_value (x_adv, base, values, layout_variation_idx_delta_map);
    225      copy_device (c, base, values++, layout_variation_idx_delta_map, new_format, xAdvDevice);
    226    }
    227 
    228    if (format & yAdvDevice)
    229    {
    230      add_delta_to_value (y_adv, base, values, layout_variation_idx_delta_map);
    231      copy_device (c, base, values++, layout_variation_idx_delta_map, new_format, yAdvDevice);
    232    }
    233  }
    234 
    235  HBINT16* copy_value (hb_serialize_context_t *c,
    236                       unsigned int new_format,
    237                       Flags flag,
    238                       Value value) const
    239  {
    240    // Filter by new format.
    241    if (!(new_format & flag)) return nullptr;
    242    return reinterpret_cast<HBINT16 *> (c->copy (value));
    243  }
    244 
    245  void collect_variation_indices (hb_collect_variation_indices_context_t *c,
    246                                  const ValueBase *base,
    247                                  const hb_array_t<const Value>& values) const
    248  {
    249    unsigned format = *this;
    250    unsigned i = 0;
    251    if (format & xPlacement) i++;
    252    if (format & yPlacement) i++;
    253    if (format & xAdvance) i++;
    254    if (format & yAdvance) i++;
    255    if (format & xPlaDevice)
    256    {
    257      (base + get_device (&(values[i]))).collect_variation_indices (c);
    258      i++;
    259    }
    260 
    261    if (format & ValueFormat::yPlaDevice)
    262    {
    263      (base + get_device (&(values[i]))).collect_variation_indices (c);
    264      i++;
    265    }
    266 
    267    if (format & ValueFormat::xAdvDevice)
    268    {
    269      (base + get_device (&(values[i]))).collect_variation_indices (c);
    270      i++;
    271    }
    272 
    273    if (format & ValueFormat::yAdvDevice)
    274    {
    275      (base + get_device (&(values[i]))).collect_variation_indices (c);
    276      i++;
    277    }
    278  }
    279 
    280  private:
    281  bool sanitize_value_devices (hb_sanitize_context_t *c, const ValueBase *base, const Value *values) const
    282  {
    283    unsigned int format = *this;
    284 
    285    if (format & xPlacement) values++;
    286    if (format & yPlacement) values++;
    287    if (format & xAdvance)   values++;
    288    if (format & yAdvance)   values++;
    289 
    290    if ((format & xPlaDevice) && !get_device (values++).sanitize (c, base)) return false;
    291    if ((format & yPlaDevice) && !get_device (values++).sanitize (c, base)) return false;
    292    if ((format & xAdvDevice) && !get_device (values++).sanitize (c, base)) return false;
    293    if ((format & yAdvDevice) && !get_device (values++).sanitize (c, base)) return false;
    294 
    295    return true;
    296  }
    297 
    298  static inline Offset16To<Device, ValueBase>& get_device (Value* value)
    299  {
    300    return *static_cast<Offset16To<Device, ValueBase> *> (value);
    301  }
    302  static inline const Offset16To<Device, ValueBase>& get_device (const Value* value)
    303  {
    304    return *static_cast<const Offset16To<Device, ValueBase> *> (value);
    305  }
    306  static inline const Device& get_device (const Value* value,
    307 				  bool *worked,
    308 				  const ValueBase *base,
    309 				  hb_sanitize_context_t &c)
    310  {
    311    if (worked) *worked |= bool (*value);
    312    auto &offset = *static_cast<const Offset16To<Device> *> (value);
    313 
    314    if (unlikely (!offset.sanitize (&c, base)))
    315      return Null(Device);
    316    hb_barrier ();
    317 
    318    return base + offset;
    319  }
    320 
    321  void add_delta_to_value (HBINT16 *value,
    322                           const ValueBase *base,
    323                           const Value *src_value,
    324                           const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map) const
    325  {
    326    if (!value) return;
    327    unsigned varidx = (base + get_device (src_value)).get_variation_index ();
    328    hb_pair_t<unsigned, int> *varidx_delta;
    329    if (!layout_variation_idx_delta_map->has (varidx, &varidx_delta)) return;
    330 
    331    *value += hb_second (*varidx_delta);
    332  }
    333 
    334  bool copy_device (hb_serialize_context_t *c,
    335                    const ValueBase *base,
    336                    const Value *src_value,
    337                    const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map,
    338                    unsigned int new_format, Flags flag) const
    339  {
    340    // Filter by new format.
    341    if (!(new_format & flag)) return true;
    342 
    343    Value       *dst_value = c->copy (*src_value);
    344 
    345    if (!dst_value) return false;
    346    if (*dst_value == 0) return true;
    347 
    348    *dst_value = 0;
    349    c->push ();
    350    if ((base + get_device (src_value)).copy (c, layout_variation_idx_delta_map))
    351    {
    352      c->add_link (*dst_value, c->pop_pack ());
    353      return true;
    354    }
    355    else
    356    {
    357      c->pop_discard ();
    358      return false;
    359    }
    360  }
    361 
    362  static inline const HBINT16& get_short (const Value* value, bool *worked=nullptr)
    363  {
    364    if (worked) *worked |= bool (*value);
    365    return *reinterpret_cast<const HBINT16 *> (value);
    366  }
    367 
    368  public:
    369 
    370  bool has_device () const
    371  {
    372    unsigned int format = *this;
    373    return (format & devices) != 0;
    374  }
    375 
    376  bool sanitize_value (hb_sanitize_context_t *c, const ValueBase *base, const Value *values) const
    377  {
    378    TRACE_SANITIZE (this);
    379 
    380    if (unlikely (!c->check_range (values, get_size ()))) return_trace (false);
    381 
    382    if (c->lazy_some_gpos)
    383      return_trace (true);
    384 
    385    return_trace (!has_device () || sanitize_value_devices (c, base, values));
    386  }
    387 
    388  bool sanitize_values (hb_sanitize_context_t *c, const ValueBase *base, const Value *values, unsigned int count) const
    389  {
    390    TRACE_SANITIZE (this);
    391    unsigned size = get_size ();
    392 
    393    if (!c->check_range (values, count, size)) return_trace (false);
    394 
    395    if (c->lazy_some_gpos)
    396      return_trace (true);
    397 
    398    hb_barrier ();
    399    return_trace (sanitize_values_stride_unsafe (c, base, values, count, size));
    400  }
    401 
    402  /* Just sanitize referenced Device tables.  Doesn't check the values themselves. */
    403  bool sanitize_values_stride_unsafe (hb_sanitize_context_t *c, const ValueBase *base, const Value *values, unsigned int count, unsigned int stride) const
    404  {
    405    TRACE_SANITIZE (this);
    406 
    407    if (!has_device ()) return_trace (true);
    408 
    409    for (unsigned int i = 0; i < count; i++) {
    410      if (!sanitize_value_devices (c, base, values))
    411        return_trace (false);
    412      values = &StructAtOffset<const Value> (values, stride);
    413    }
    414 
    415    return_trace (true);
    416  }
    417 
    418 private:
    419 
    420  void should_drop (Value value, Flags flag, unsigned int* format) const
    421  {
    422    if (value) return;
    423    *format = *format & ~flag;
    424  }
    425 
    426  void update_var_flag (const Value* value, Flags flag,
    427                        unsigned int* format, const ValueBase *base,
    428                        const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *varidx_delta_map) const
    429  {
    430    if (*value)
    431    {
    432      unsigned varidx = (base + get_device (value)).get_variation_index ();
    433      hb_pair_t<unsigned, int> *varidx_delta;
    434      if (varidx_delta_map->has (varidx, &varidx_delta) &&
    435          varidx_delta->first != HB_OT_LAYOUT_NO_VARIATIONS_INDEX)
    436        return;
    437    }
    438    *format = *format & ~flag;
    439  }
    440 };
    441 
    442 }
    443 }
    444 }
    445 
    446 #endif  // #ifndef OT_LAYOUT_GPOS_VALUEFORMAT_HH