tor-browser

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

hb-ot-var-common.hh (72816B)


      1 /*
      2 * Copyright © 2021  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 */
     25 
     26 #ifndef HB_OT_VAR_COMMON_HH
     27 #define HB_OT_VAR_COMMON_HH
     28 
     29 #include "hb-ot-layout-common.hh"
     30 #include "hb-alloc-pool.hh"
     31 #include "hb-priority-queue.hh"
     32 #include "hb-subset-instancer-iup.hh"
     33 
     34 
     35 namespace OT {
     36 
     37 using rebase_tent_result_scratch_t = hb_pair_t<rebase_tent_result_t, rebase_tent_result_t>;
     38 
     39 /* https://docs.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats#tuplevariationheader */
     40 struct TupleVariationHeader
     41 {
     42  friend struct tuple_delta_t;
     43  unsigned get_size (unsigned axis_count_times_2) const
     44  {
     45    // This function is super hot in mega-var-fonts with hundreds of masters.
     46    unsigned ti = tupleIndex;
     47    if (unlikely ((ti & (TupleIndex::EmbeddedPeakTuple | TupleIndex::IntermediateRegion))))
     48    {
     49      unsigned count = ((ti & TupleIndex::EmbeddedPeakTuple) != 0) + ((ti & TupleIndex::IntermediateRegion) != 0) * 2;
     50      return min_size + count * axis_count_times_2;
     51    }
     52    return min_size;
     53  }
     54 
     55  unsigned get_data_size () const { return varDataSize; }
     56 
     57  const TupleVariationHeader &get_next (unsigned axis_count_times_2) const
     58  { return StructAtOffset<TupleVariationHeader> (this, get_size (axis_count_times_2)); }
     59 
     60  bool unpack_axis_tuples (unsigned axis_count,
     61                           const hb_array_t<const F2DOT14> shared_tuples,
     62                           const hb_map_t *axes_old_index_tag_map,
     63                           hb_hashmap_t<hb_tag_t, Triple>& axis_tuples /* OUT */) const
     64  {
     65    const F2DOT14 *peak_tuple = nullptr;
     66    if (has_peak ())
     67      peak_tuple = get_peak_tuple (axis_count);
     68    else
     69    {
     70      unsigned int index = get_index ();
     71      if (unlikely ((index + 1) * axis_count > shared_tuples.length))
     72        return false;
     73      peak_tuple = shared_tuples.sub_array (axis_count * index, axis_count).arrayZ;
     74    }
     75 
     76    const F2DOT14 *start_tuple = nullptr;
     77    const F2DOT14 *end_tuple = nullptr;
     78    bool has_interm = has_intermediate ();
     79 
     80    if (has_interm)
     81    {
     82      start_tuple = get_start_tuple (axis_count);
     83      end_tuple = get_end_tuple (axis_count);
     84    }
     85 
     86    for (unsigned i = 0; i < axis_count; i++)
     87    {
     88      float peak = peak_tuple[i].to_float ();
     89      if (peak == 0.f) continue;
     90 
     91      hb_tag_t *axis_tag;
     92      if (!axes_old_index_tag_map->has (i, &axis_tag))
     93        return false;
     94 
     95      float start, end;
     96      if (has_interm)
     97      {
     98        start = start_tuple[i].to_float ();
     99        end = end_tuple[i].to_float ();
    100      }
    101      else
    102      {
    103        start = hb_min (peak, 0.f);
    104        end = hb_max (peak, 0.f);
    105      }
    106      axis_tuples.set (*axis_tag, Triple ((double) start, (double) peak, (double) end));
    107    }
    108 
    109    return true;
    110  }
    111 
    112  HB_ALWAYS_INLINE
    113  double calculate_scalar (hb_array_t<const int> coords, unsigned int coord_count,
    114 		   const hb_array_t<const F2DOT14> shared_tuples,
    115 		   hb_scalar_cache_t *shared_tuple_scalar_cache = nullptr) const
    116  {
    117    unsigned tuple_index = tupleIndex;
    118 
    119    const F2DOT14 *peak_tuple;
    120 
    121    bool has_interm = tuple_index & TupleIndex::IntermediateRegion; // Inlined for performance
    122 
    123    if (unlikely (tuple_index & TupleIndex::EmbeddedPeakTuple)) // Inlined for performance
    124    {
    125      peak_tuple = get_peak_tuple (coord_count);
    126      shared_tuple_scalar_cache = nullptr;
    127    }
    128    else
    129    {
    130      unsigned int index = tuple_index & TupleIndex::TupleIndexMask; // Inlined for performance
    131 
    132      float scalar;
    133      if (shared_tuple_scalar_cache &&
    134   shared_tuple_scalar_cache->get (index, &scalar))
    135      {
    136        if (has_interm && (scalar != 0 && scalar != 1.f))
    137   shared_tuple_scalar_cache = nullptr;
    138 else
    139   return (double) scalar;
    140      }
    141 
    142      if (unlikely ((index + 1) * coord_count > shared_tuples.length))
    143        return 0.0;
    144      peak_tuple = shared_tuples.arrayZ + (coord_count * index);
    145 
    146    }
    147 
    148    const F2DOT14 *start_tuple = nullptr;
    149    const F2DOT14 *end_tuple = nullptr;
    150 
    151    if (has_interm)
    152    {
    153      start_tuple = get_start_tuple (coord_count);
    154      end_tuple = get_end_tuple (coord_count);
    155    }
    156 
    157    double scalar = 1.0;
    158 #ifndef HB_OPTIMIZE_SIZE
    159 #if HB_FAST_NUM_ACCESS
    160    bool skip = coord_count >= 16;
    161 #endif
    162 #endif
    163    for (unsigned int i = 0; i < coord_count; i++)
    164    {
    165 #ifndef HB_OPTIMIZE_SIZE
    166 #if HB_FAST_NUM_ACCESS
    167      if (skip)
    168      {
    169 while (i + 4 <= coord_count && * (HBUINT64LE *) &peak_tuple[i] == 0)
    170   i += 4;
    171 while (i < coord_count && peak_tuple[i].to_int () == 0)
    172   i += 1;
    173 if (i >= coord_count)
    174   break;
    175      }
    176 #endif
    177 #endif
    178 
    179      int peak = peak_tuple[i].to_int ();
    180      if (!peak) continue;
    181 
    182      int v = coords[i];
    183      if (!v) { scalar = 0.0; break; }
    184      if (v == peak) continue;
    185 
    186      if (has_interm)
    187      {
    188 shared_tuple_scalar_cache = nullptr;
    189        int start = start_tuple[i].to_int ();
    190        int end = end_tuple[i].to_int ();
    191        if (unlikely (start > peak || peak > end ||
    192                      (start < 0 && end > 0 && peak))) continue;
    193        if (v < start || v > end) { scalar = 0.0; break; }
    194        if (v < peak)
    195        { if (peak != start) scalar *= (double) (v - start) / (peak - start); }
    196        else
    197        { if (peak != end) scalar *= (double) (end - v) / (end - peak); }
    198      }
    199      else if (v < hb_min (0, peak) || v > hb_max (0, peak)) { scalar = 0.0; break; }
    200      else
    201        scalar *= (double) v / peak;
    202    }
    203    if (shared_tuple_scalar_cache)
    204      shared_tuple_scalar_cache->set (get_index (), scalar);
    205    return scalar;
    206  }
    207 
    208  bool           has_peak () const { return tupleIndex & TupleIndex::EmbeddedPeakTuple; }
    209  bool   has_intermediate () const { return tupleIndex & TupleIndex::IntermediateRegion; }
    210  bool has_private_points () const { return tupleIndex & TupleIndex::PrivatePointNumbers; }
    211  unsigned      get_index () const { return tupleIndex & TupleIndex::TupleIndexMask; }
    212 
    213  protected:
    214  struct TupleIndex : HBUINT16
    215  {
    216    enum Flags {
    217      EmbeddedPeakTuple   = 0x8000u,
    218      IntermediateRegion  = 0x4000u,
    219      PrivatePointNumbers = 0x2000u,
    220      TupleIndexMask      = 0x0FFFu
    221    };
    222 
    223    TupleIndex& operator = (uint16_t i) { HBUINT16::operator= (i); return *this; }
    224    DEFINE_SIZE_STATIC (2);
    225  };
    226 
    227  hb_array_t<const F2DOT14> get_all_tuples (unsigned axis_count) const
    228  { return StructAfter<UnsizedArrayOf<F2DOT14>> (tupleIndex).as_array ((has_peak () + has_intermediate () * 2) * axis_count); }
    229  const F2DOT14* get_all_tuples_base (unsigned axis_count) const
    230  { return StructAfter<UnsizedArrayOf<F2DOT14>> (tupleIndex).arrayZ; }
    231  const F2DOT14* get_peak_tuple (unsigned axis_count) const
    232  { return get_all_tuples_base (axis_count); }
    233  const F2DOT14* get_start_tuple (unsigned axis_count) const
    234  { return get_all_tuples_base (axis_count) + has_peak () * axis_count; }
    235  const F2DOT14* get_end_tuple (unsigned axis_count) const
    236  { return get_all_tuples_base (axis_count) + has_peak () * axis_count + axis_count; }
    237 
    238  HBUINT16      varDataSize;    /* The size in bytes of the serialized
    239                                 * data for this tuple variation table. */
    240  TupleIndex    tupleIndex;     /* A packed field. The high 4 bits are flags (see below).
    241                                   The low 12 bits are an index into a shared tuple
    242                                   records array. */
    243  /* UnsizedArrayOf<F2DOT14> peakTuple - optional */
    244                                /* Peak tuple record for this tuple variation table — optional,
    245                                 * determined by flags in the tupleIndex value.
    246                                 *
    247                                 * Note that this must always be included in the 'cvar' table. */
    248  /* UnsizedArrayOf<F2DOT14> intermediateStartTuple - optional */
    249                                /* Intermediate start tuple record for this tuple variation table — optional,
    250                                   determined by flags in the tupleIndex value. */
    251  /* UnsizedArrayOf<F2DOT14> intermediateEndTuple - optional */
    252                                /* Intermediate end tuple record for this tuple variation table — optional,
    253                                 * determined by flags in the tupleIndex value. */
    254  public:
    255  DEFINE_SIZE_MIN (4);
    256 };
    257 
    258 struct optimize_scratch_t
    259 {
    260  iup_scratch_t iup;
    261  hb_vector_t<bool> opt_indices;
    262  hb_vector_t<int> rounded_x_deltas;
    263  hb_vector_t<int> rounded_y_deltas;
    264  hb_vector_t<float> opt_deltas_x;
    265  hb_vector_t<float> opt_deltas_y;
    266  hb_vector_t<unsigned char> opt_point_data;
    267  hb_vector_t<unsigned char> opt_deltas_data;
    268  hb_vector_t<unsigned char> point_data;
    269  hb_vector_t<unsigned char> deltas_data;
    270  hb_vector_t<int> rounded_deltas;
    271 };
    272 
    273 struct tuple_delta_t
    274 {
    275  static constexpr bool realloc_move = true;  // Watch out when adding new members!
    276 
    277  public:
    278  hb_hashmap_t<hb_tag_t, Triple> axis_tuples;
    279 
    280  /* indices_length = point_count, indice[i] = 1 means point i is referenced */
    281  hb_vector_t<bool> indices;
    282 
    283  hb_vector_t<float> deltas_x;
    284  /* empty for cvar tuples */
    285  hb_vector_t<float> deltas_y;
    286 
    287  /* compiled data: header and deltas
    288   * compiled point data is saved in a hashmap within tuple_variations_t cause
    289   * some point sets might be reused by different tuple variations */
    290  hb_vector_t<unsigned char> compiled_tuple_header;
    291  hb_vector_t<unsigned char> compiled_deltas;
    292 
    293  hb_vector_t<F2DOT14> compiled_peak_coords;
    294  hb_vector_t<F2DOT14> compiled_interm_coords;
    295 
    296  tuple_delta_t (hb_alloc_pool_t *pool = nullptr) {}
    297  tuple_delta_t (const tuple_delta_t& o) = default;
    298  tuple_delta_t& operator = (const tuple_delta_t& o) = default;
    299 
    300  friend void swap (tuple_delta_t& a, tuple_delta_t& b) noexcept
    301  {
    302    hb_swap (a.axis_tuples, b.axis_tuples);
    303    hb_swap (a.indices, b.indices);
    304    hb_swap (a.deltas_x, b.deltas_x);
    305    hb_swap (a.deltas_y, b.deltas_y);
    306    hb_swap (a.compiled_tuple_header, b.compiled_tuple_header);
    307    hb_swap (a.compiled_deltas, b.compiled_deltas);
    308    hb_swap (a.compiled_peak_coords, b.compiled_peak_coords);
    309  }
    310 
    311  tuple_delta_t (tuple_delta_t&& o)  noexcept : tuple_delta_t ()
    312  { hb_swap (*this, o); }
    313 
    314  tuple_delta_t& operator = (tuple_delta_t&& o) noexcept
    315  {
    316    hb_swap (*this, o);
    317    return *this;
    318  }
    319 
    320  void copy_from (const tuple_delta_t& o, hb_alloc_pool_t *pool = nullptr)
    321  {
    322    axis_tuples = o.axis_tuples;
    323    indices.allocate_from_pool (pool, o.indices);
    324    deltas_x.allocate_from_pool (pool, o.deltas_x);
    325    deltas_y.allocate_from_pool (pool, o.deltas_y);
    326    compiled_tuple_header.allocate_from_pool (pool, o.compiled_tuple_header);
    327    compiled_deltas.allocate_from_pool (pool, o.compiled_deltas);
    328    compiled_peak_coords.allocate_from_pool (pool, o.compiled_peak_coords);
    329    compiled_interm_coords.allocate_from_pool (pool, o.compiled_interm_coords);
    330  }
    331 
    332  void remove_axis (hb_tag_t axis_tag)
    333  { axis_tuples.del (axis_tag); }
    334 
    335  bool set_tent (hb_tag_t axis_tag, Triple tent)
    336  { return axis_tuples.set (axis_tag, tent); }
    337 
    338  tuple_delta_t& operator += (const tuple_delta_t& o)
    339  {
    340    unsigned num = indices.length;
    341    for (unsigned i = 0; i < num; i++)
    342    {
    343      if (indices.arrayZ[i])
    344      {
    345        if (o.indices.arrayZ[i])
    346        {
    347          deltas_x[i] += o.deltas_x[i];
    348          if (deltas_y && o.deltas_y)
    349            deltas_y[i] += o.deltas_y[i];
    350        }
    351      }
    352      else
    353      {
    354        if (!o.indices.arrayZ[i]) continue;
    355        indices.arrayZ[i] = true;
    356        deltas_x[i] = o.deltas_x[i];
    357        if (deltas_y && o.deltas_y)
    358          deltas_y[i] = o.deltas_y[i];
    359      }
    360    }
    361    return *this;
    362  }
    363 
    364  tuple_delta_t& operator *= (float scalar)
    365  {
    366    if (scalar == 1.0f)
    367      return *this;
    368 
    369    unsigned num = indices.length;
    370    if (deltas_y)
    371      for (unsigned i = 0; i < num; i++)
    372      {
    373 if (!indices.arrayZ[i]) continue;
    374 deltas_x[i] *= scalar;
    375 deltas_y[i] *= scalar;
    376      }
    377    else
    378      for (unsigned i = 0; i < num; i++)
    379      {
    380 if (!indices.arrayZ[i]) continue;
    381 deltas_x[i] *= scalar;
    382      }
    383    return *this;
    384  }
    385 
    386  void change_tuple_var_axis_limit (hb_tag_t axis_tag, Triple axis_limit,
    387 			    TripleDistances axis_triple_distances,
    388 			    hb_vector_t<tuple_delta_t>& out,
    389 			    rebase_tent_result_scratch_t &scratch,
    390 			    hb_alloc_pool_t *pool = nullptr)
    391  {
    392    // May move *this out.
    393 
    394    out.reset ();
    395    Triple *tent;
    396    if (!axis_tuples.has (axis_tag, &tent))
    397    {
    398      out.push (std::move (*this));
    399      return;
    400    }
    401 
    402    if ((tent->minimum < 0.0 && tent->maximum > 0.0) ||
    403        !(tent->minimum <= tent->middle && tent->middle <= tent->maximum))
    404      return;
    405 
    406    if (tent->middle == 0.0)
    407    {
    408      out.push (std::move (*this));
    409      return;
    410    }
    411 
    412    rebase_tent_result_t &solutions = scratch.first;
    413    rebase_tent (*tent, axis_limit, axis_triple_distances, solutions, scratch.second);
    414    for (unsigned i = 0; i < solutions.length; i++)
    415    {
    416      auto &t = solutions.arrayZ[i];
    417 
    418      tuple_delta_t new_var;
    419      if (i < solutions.length - 1)
    420 new_var.copy_from (*this, pool);
    421      else
    422 new_var = std::move (*this);
    423 
    424      if (t.second == Triple ())
    425        new_var.remove_axis (axis_tag);
    426      else
    427        new_var.set_tent (axis_tag, t.second);
    428 
    429      new_var *= t.first;
    430      out.push (std::move (new_var));
    431    }
    432  }
    433 
    434  bool compile_coords (const hb_map_t& axes_index_map,
    435 	       const hb_map_t& axes_old_index_tag_map,
    436 	       hb_alloc_pool_t *pool= nullptr)
    437  {
    438    unsigned cur_axis_count = axes_index_map.get_population ();
    439    if (pool)
    440    {
    441      if (unlikely (!compiled_peak_coords.allocate_from_pool (pool, cur_axis_count)))
    442 return false;
    443    }
    444    else if (unlikely (!compiled_peak_coords.resize (cur_axis_count)))
    445      return false;
    446 
    447    hb_array_t<F2DOT14> start_coords, end_coords;
    448 
    449    unsigned orig_axis_count = axes_old_index_tag_map.get_population ();
    450    unsigned j = 0;
    451    for (unsigned i = 0; i < orig_axis_count; i++)
    452    {
    453      if (!axes_index_map.has (i))
    454        continue;
    455 
    456      hb_tag_t axis_tag = axes_old_index_tag_map.get (i);
    457      Triple *coords = nullptr;
    458      if (axis_tuples.has (axis_tag, &coords))
    459      {
    460 float min_val = coords->minimum;
    461 float val = coords->middle;
    462 float max_val = coords->maximum;
    463 
    464 compiled_peak_coords.arrayZ[j].set_float (val);
    465 
    466 if (min_val != hb_min (val, 0.f) || max_val != hb_max (val, 0.f))
    467 {
    468   if (!compiled_interm_coords)
    469   {
    470     if (pool)
    471     {
    472       if (unlikely (!compiled_interm_coords.allocate_from_pool (pool, 2 * cur_axis_count)))
    473 	return false;
    474     }
    475     else if (unlikely (!compiled_interm_coords.resize (2 * cur_axis_count)))
    476       return false;
    477     start_coords = compiled_interm_coords.as_array ().sub_array (0, cur_axis_count);
    478     end_coords = compiled_interm_coords.as_array ().sub_array (cur_axis_count);
    479 
    480     for (unsigned k = 0; k < j; k++)
    481     {
    482       signed peak = compiled_peak_coords.arrayZ[k].to_int ();
    483       if (!peak) continue;
    484       start_coords.arrayZ[k].set_int (hb_min (peak, 0));
    485       end_coords.arrayZ[k].set_int (hb_max (peak, 0));
    486     }
    487   }
    488 
    489 }
    490 
    491 if (compiled_interm_coords)
    492 {
    493   start_coords.arrayZ[j].set_float (min_val);
    494   end_coords.arrayZ[j].set_float (max_val);
    495 }
    496      }
    497 
    498      j++;
    499    }
    500 
    501    return !compiled_peak_coords.in_error () && !compiled_interm_coords.in_error ();
    502  }
    503 
    504  /* deltas should be compiled already before we compile tuple
    505   * variation header cause we need to fill in the size of the
    506   * serialized data for this tuple variation */
    507  bool compile_tuple_var_header (const hb_map_t& axes_index_map,
    508                                 unsigned points_data_length,
    509                                 const hb_map_t& axes_old_index_tag_map,
    510                                 const hb_hashmap_t<const hb_vector_t<F2DOT14>*, unsigned>* shared_tuples_idx_map,
    511 			 hb_alloc_pool_t *pool = nullptr)
    512  {
    513    /* compiled_deltas could be empty after iup delta optimization, we can skip
    514     * compiling this tuple and return true */
    515    if (!compiled_deltas) return true;
    516 
    517    unsigned cur_axis_count = axes_index_map.get_population ();
    518    /* allocate enough memory: 1 peak + 2 intermediate coords + fixed header size */
    519    unsigned alloc_len = 3 * cur_axis_count * (F2DOT14::static_size) + 4;
    520    if (unlikely (!compiled_tuple_header.allocate_from_pool (pool, alloc_len, false))) return false;
    521 
    522    unsigned flag = 0;
    523    /* skip the first 4 header bytes: variationDataSize+tupleIndex */
    524    F2DOT14* p = reinterpret_cast<F2DOT14 *> (compiled_tuple_header.begin () + 4);
    525    F2DOT14* end = reinterpret_cast<F2DOT14 *> (compiled_tuple_header.end ());
    526    hb_array_t<F2DOT14> coords (p, end - p);
    527 
    528    if (!shared_tuples_idx_map)
    529      compile_coords (axes_index_map, axes_old_index_tag_map); // non-gvar tuples do not have compiled coords yet
    530 
    531    /* encode peak coords */
    532    unsigned peak_count = 0;
    533    unsigned *shared_tuple_idx;
    534    if (shared_tuples_idx_map &&
    535        shared_tuples_idx_map->has (&compiled_peak_coords, &shared_tuple_idx))
    536    {
    537      flag = *shared_tuple_idx;
    538    }
    539    else
    540    {
    541      peak_count = encode_peak_coords(coords, flag);
    542      if (!peak_count) return false;
    543    }
    544 
    545    /* encode interim coords, it's optional so returned num could be 0 */
    546    unsigned interim_count = encode_interm_coords (coords.sub_array (peak_count), flag);
    547 
    548    /* pointdata length = 0 implies "use shared points" */
    549    if (points_data_length)
    550      flag |= TupleVariationHeader::TupleIndex::PrivatePointNumbers;
    551 
    552    unsigned serialized_data_size = points_data_length + compiled_deltas.length;
    553    TupleVariationHeader *o = reinterpret_cast<TupleVariationHeader *> (compiled_tuple_header.begin ());
    554    o->varDataSize = serialized_data_size;
    555    o->tupleIndex = flag;
    556 
    557    unsigned total_header_len = 4 + (peak_count + interim_count) * (F2DOT14::static_size);
    558    compiled_tuple_header.shrink_back_to_pool (pool, total_header_len);
    559    return true;
    560  }
    561 
    562  unsigned encode_peak_coords (hb_array_t<F2DOT14> peak_coords,
    563                               unsigned& flag) const
    564  {
    565    hb_memcpy (&peak_coords[0], &compiled_peak_coords[0], compiled_peak_coords.length * sizeof (compiled_peak_coords[0]));
    566    flag |= TupleVariationHeader::TupleIndex::EmbeddedPeakTuple;
    567    return compiled_peak_coords.length;
    568  }
    569 
    570  /* if no need to encode intermediate coords, then just return p */
    571  unsigned encode_interm_coords (hb_array_t<F2DOT14> coords,
    572                                 unsigned& flag) const
    573  {
    574    if (compiled_interm_coords)
    575    {
    576      hb_memcpy (&coords[0], &compiled_interm_coords[0], compiled_interm_coords.length * sizeof (compiled_interm_coords[0]));
    577      flag |= TupleVariationHeader::TupleIndex::IntermediateRegion;
    578    }
    579    return compiled_interm_coords.length;
    580  }
    581 
    582  bool compile_deltas (hb_vector_t<int> &rounded_deltas_scratch,
    583 	       hb_alloc_pool_t *pool = nullptr)
    584  { return compile_deltas (indices, deltas_x, deltas_y, compiled_deltas, rounded_deltas_scratch, pool); }
    585 
    586  static bool compile_deltas (hb_array_t<const bool> point_indices,
    587 		      hb_array_t<const float> x_deltas,
    588 		      hb_array_t<const float> y_deltas,
    589 		      hb_vector_t<unsigned char> &compiled_deltas, /* OUT */
    590 		      hb_vector_t<int> &rounded_deltas, /* scratch */
    591 		      hb_alloc_pool_t *pool = nullptr)
    592  {
    593    if (unlikely (!rounded_deltas.resize_dirty  (point_indices.length)))
    594      return false;
    595 
    596    unsigned j = 0;
    597    for (unsigned i = 0; i < point_indices.length; i++)
    598    {
    599      if (!point_indices[i]) continue;
    600      rounded_deltas.arrayZ[j++] = (int) roundf (x_deltas.arrayZ[i]);
    601    }
    602    rounded_deltas.resize (j);
    603 
    604    if (!rounded_deltas) return true;
    605    /* Allocate enough memory: this is the correct bound:
    606     * Worst case scenario is that each delta has to be encoded in 4 bytes, and there
    607     * are runs of 64 items each. Any delta encoded in less than 4 bytes (2, 1, or 0)
    608     * is still smaller than the 4-byte encoding even with their control byte.
    609     * The initial 2 is to handle length==0, for both x and y deltas. */
    610    unsigned alloc_len = 2 + 4 * rounded_deltas.length + (rounded_deltas.length + 63) / 64;
    611    if (y_deltas)
    612      alloc_len *= 2;
    613 
    614    if (unlikely (!compiled_deltas.allocate_from_pool (pool, alloc_len, false))) return false;
    615 
    616    unsigned encoded_len = compile_deltas (compiled_deltas, rounded_deltas);
    617 
    618    if (y_deltas)
    619    {
    620      /* reuse the rounded_deltas vector, check that y_deltas have the same num of deltas as x_deltas */
    621      unsigned j = 0;
    622      for (unsigned idx = 0; idx < point_indices.length; idx++)
    623      {
    624        if (!point_indices[idx]) continue;
    625        int rounded_delta = (int) roundf (y_deltas.arrayZ[idx]);
    626 
    627        if (j >= rounded_deltas.length) return false;
    628 
    629        rounded_deltas[j++] = rounded_delta;
    630      }
    631 
    632      if (j != rounded_deltas.length) return false;
    633      encoded_len += compile_deltas (compiled_deltas.as_array ().sub_array (encoded_len), rounded_deltas);
    634    }
    635    compiled_deltas.shrink_back_to_pool (pool, encoded_len);
    636    return true;
    637  }
    638 
    639  static unsigned compile_deltas (hb_array_t<unsigned char> encoded_bytes,
    640 			  hb_array_t<const int> deltas)
    641  {
    642    return TupleValues::compile_unsafe (deltas, encoded_bytes);
    643  }
    644 
    645  bool calc_inferred_deltas (const contour_point_vector_t& orig_points,
    646 		     hb_vector_t<unsigned> &scratch)
    647  {
    648    unsigned point_count = orig_points.length;
    649    if (point_count != indices.length)
    650      return false;
    651 
    652    unsigned ref_count = 0;
    653 
    654    hb_vector_t<unsigned> &end_points = scratch.reset ();
    655 
    656    for (unsigned i = 0; i < point_count; i++)
    657    {
    658      ref_count += indices.arrayZ[i];
    659      if (orig_points.arrayZ[i].is_end_point)
    660        end_points.push (i);
    661    }
    662    /* all points are referenced, nothing to do */
    663    if (ref_count == point_count)
    664      return true;
    665    if (unlikely (end_points.in_error ())) return false;
    666 
    667    hb_bit_set_t inferred_idxes;
    668    unsigned start_point = 0;
    669    for (unsigned end_point : end_points)
    670    {
    671      /* Check the number of unreferenced points in a contour. If no unref points or no ref points, nothing to do. */
    672      unsigned unref_count = 0;
    673      for (unsigned i = start_point; i < end_point + 1; i++)
    674        unref_count += indices.arrayZ[i];
    675      unref_count = (end_point - start_point + 1) - unref_count;
    676 
    677      unsigned j = start_point;
    678      if (unref_count == 0 || unref_count > end_point - start_point)
    679        goto no_more_gaps;
    680      for (;;)
    681      {
    682        /* Locate the next gap of unreferenced points between two referenced points prev and next.
    683         * Note that a gap may wrap around at left (start_point) and/or at right (end_point).
    684         */
    685        unsigned int prev, next, i;
    686        for (;;)
    687        {
    688          i = j;
    689          j = next_index (i, start_point, end_point);
    690          if (indices.arrayZ[i] && !indices.arrayZ[j]) break;
    691        }
    692        prev = j = i;
    693        for (;;)
    694        {
    695          i = j;
    696          j = next_index (i, start_point, end_point);
    697          if (!indices.arrayZ[i] && indices.arrayZ[j]) break;
    698        }
    699        next = j;
    700       /* Infer deltas for all unref points in the gap between prev and next */
    701        i = prev;
    702        for (;;)
    703        {
    704          i = next_index (i, start_point, end_point);
    705          if (i == next) break;
    706          deltas_x.arrayZ[i] = infer_delta ((double) orig_points.arrayZ[i].x,
    707                                            (double) orig_points.arrayZ[prev].x,
    708                                            (double) orig_points.arrayZ[next].x,
    709                                            (double) deltas_x.arrayZ[prev], (double) deltas_x.arrayZ[next]);
    710          deltas_y.arrayZ[i] = infer_delta ((double) orig_points.arrayZ[i].y,
    711                                            (double) orig_points.arrayZ[prev].y,
    712                                            (double) orig_points.arrayZ[next].y,
    713                                            (double) deltas_y.arrayZ[prev], (double) deltas_y.arrayZ[next]);
    714          inferred_idxes.add (i);
    715          if (--unref_count == 0) goto no_more_gaps;
    716        }
    717      }
    718    no_more_gaps:
    719      start_point = end_point + 1;
    720    }
    721 
    722    for (unsigned i = 0; i < point_count; i++)
    723    {
    724      /* if points are not referenced and deltas are not inferred, set to 0.
    725       * reference all points for gvar */
    726      if ( !indices[i])
    727      {
    728        if (!inferred_idxes.has (i))
    729        {
    730          deltas_x.arrayZ[i] = 0.0;
    731          deltas_y.arrayZ[i] = 0.0;
    732        }
    733        indices[i] = true;
    734      }
    735    }
    736    return true;
    737  }
    738 
    739  bool optimize (const contour_point_vector_t& contour_points,
    740                 bool is_composite,
    741 	 optimize_scratch_t &scratch,
    742                 double tolerance = 0.5 + 1e-10)
    743  {
    744    unsigned count = contour_points.length;
    745    if (deltas_x.length != count ||
    746        deltas_y.length != count)
    747      return false;
    748 
    749    hb_vector_t<bool> &opt_indices = scratch.opt_indices.reset ();
    750    hb_vector_t<int> &rounded_x_deltas = scratch.rounded_x_deltas;
    751    hb_vector_t<int> &rounded_y_deltas = scratch.rounded_y_deltas;
    752 
    753    if (unlikely (!rounded_x_deltas.resize_dirty  (count) ||
    754                  !rounded_y_deltas.resize_dirty  (count)))
    755      return false;
    756 
    757    for (unsigned i = 0; i < count; i++)
    758    {
    759      rounded_x_deltas.arrayZ[i] = (int) roundf (deltas_x.arrayZ[i]);
    760      rounded_y_deltas.arrayZ[i] = (int) roundf (deltas_y.arrayZ[i]);
    761    }
    762 
    763    if (!iup_delta_optimize (contour_points, rounded_x_deltas, rounded_y_deltas, opt_indices, scratch.iup, tolerance))
    764      return false;
    765 
    766    unsigned ref_count = 0;
    767    for (bool ref_flag : opt_indices)
    768       ref_count += ref_flag;
    769 
    770    if (ref_count == count) return true;
    771 
    772    hb_vector_t<float> &opt_deltas_x = scratch.opt_deltas_x.reset ();
    773    hb_vector_t<float> &opt_deltas_y = scratch.opt_deltas_y.reset ();
    774    bool is_comp_glyph_wo_deltas = (is_composite && ref_count == 0);
    775    if (is_comp_glyph_wo_deltas)
    776    {
    777      if (unlikely (!opt_deltas_x.resize (count) ||
    778                    !opt_deltas_y.resize (count)))
    779        return false;
    780 
    781      opt_indices.arrayZ[0] = true;
    782      for (unsigned i = 1; i < count; i++)
    783        opt_indices.arrayZ[i] = false;
    784    }
    785 
    786    hb_vector_t<unsigned char> &opt_point_data = scratch.opt_point_data.reset ();
    787    if (!compile_point_set (opt_indices, opt_point_data))
    788      return false;
    789    hb_vector_t<unsigned char> &opt_deltas_data = scratch.opt_deltas_data.reset ();
    790    if (!compile_deltas (opt_indices,
    791                         is_comp_glyph_wo_deltas ? opt_deltas_x : deltas_x,
    792                         is_comp_glyph_wo_deltas ? opt_deltas_y : deltas_y,
    793                         opt_deltas_data,
    794 		 scratch.rounded_deltas))
    795      return false;
    796 
    797    hb_vector_t<unsigned char> &point_data = scratch.point_data.reset ();
    798    if (!compile_point_set (indices, point_data))
    799      return false;
    800    hb_vector_t<unsigned char> &deltas_data = scratch.deltas_data.reset ();
    801    if (!compile_deltas (indices, deltas_x, deltas_y, deltas_data, scratch.rounded_deltas))
    802      return false;
    803 
    804    if (opt_point_data.length + opt_deltas_data.length < point_data.length + deltas_data.length)
    805    {
    806      indices = std::move (opt_indices);
    807 
    808      if (is_comp_glyph_wo_deltas)
    809      {
    810        deltas_x = std::move (opt_deltas_x);
    811        deltas_y = std::move (opt_deltas_y);
    812      }
    813    }
    814    return !indices.in_error () && !deltas_x.in_error () && !deltas_y.in_error ();
    815  }
    816 
    817  static bool compile_point_set (const hb_vector_t<bool> &point_indices,
    818                                 hb_vector_t<unsigned char>& compiled_points /* OUT */)
    819  {
    820    unsigned num_points = 0;
    821    for (bool i : point_indices)
    822      if (i) num_points++;
    823 
    824    /* when iup optimization is enabled, num of referenced points could be 0 */
    825    if (!num_points) return true;
    826 
    827    unsigned indices_length = point_indices.length;
    828    /* If the points set consists of all points in the glyph, it's encoded with a
    829     * single zero byte */
    830    if (num_points == indices_length)
    831      return compiled_points.resize (1);
    832 
    833    /* allocate enough memories: 2 bytes for count + 3 bytes for each point */
    834    unsigned num_bytes = 2 + 3 *num_points;
    835    if (unlikely (!compiled_points.resize_dirty  (num_bytes)))
    836      return false;
    837 
    838    unsigned pos = 0;
    839    /* binary data starts with the total number of reference points */
    840    if (num_points < 0x80)
    841      compiled_points.arrayZ[pos++] = num_points;
    842    else
    843    {
    844      compiled_points.arrayZ[pos++] = ((num_points >> 8) | 0x80);
    845      compiled_points.arrayZ[pos++] = num_points & 0xFF;
    846    }
    847 
    848    const unsigned max_run_length = 0x7F;
    849    unsigned i = 0;
    850    unsigned last_value = 0;
    851    unsigned num_encoded = 0;
    852    while (i < indices_length && num_encoded < num_points)
    853    {
    854      unsigned run_length = 0;
    855      unsigned header_pos = pos;
    856      compiled_points.arrayZ[pos++] = 0;
    857 
    858      bool use_byte_encoding = false;
    859      bool new_run = true;
    860      while (i < indices_length && num_encoded < num_points &&
    861             run_length <= max_run_length)
    862      {
    863        // find out next referenced point index
    864        while (i < indices_length && !point_indices[i])
    865          i++;
    866 
    867        if (i >= indices_length) break;
    868 
    869        unsigned cur_value = i;
    870        unsigned delta = cur_value - last_value;
    871 
    872        if (new_run)
    873        {
    874          use_byte_encoding = (delta <= 0xFF);
    875          new_run = false;
    876        }
    877 
    878        if (use_byte_encoding && delta > 0xFF)
    879          break;
    880 
    881        if (use_byte_encoding)
    882          compiled_points.arrayZ[pos++] = delta;
    883        else
    884        {
    885          compiled_points.arrayZ[pos++] = delta >> 8;
    886          compiled_points.arrayZ[pos++] = delta & 0xFF;
    887        }
    888        i++;
    889        last_value = cur_value;
    890        run_length++;
    891        num_encoded++;
    892      }
    893 
    894      if (use_byte_encoding)
    895        compiled_points.arrayZ[header_pos] = run_length - 1;
    896      else
    897        compiled_points.arrayZ[header_pos] = (run_length - 1) | 0x80;
    898    }
    899    return compiled_points.resize_dirty  (pos);
    900  }
    901 
    902  static double infer_delta (double target_val, double prev_val, double next_val, double prev_delta, double next_delta)
    903  {
    904    if (prev_val == next_val)
    905      return (prev_delta == next_delta) ? prev_delta : 0.0;
    906    else if (target_val <= hb_min (prev_val, next_val))
    907      return (prev_val < next_val) ? prev_delta : next_delta;
    908    else if (target_val >= hb_max (prev_val, next_val))
    909      return (prev_val > next_val) ? prev_delta : next_delta;
    910 
    911    double r = (target_val - prev_val) / (next_val - prev_val);
    912    return prev_delta + r * (next_delta - prev_delta);
    913  }
    914 
    915  static unsigned int next_index (unsigned int i, unsigned int start, unsigned int end)
    916  { return (i >= end) ? start : (i + 1); }
    917 };
    918 
    919 template <typename OffType = HBUINT16>
    920 struct TupleVariationData
    921 {
    922  bool sanitize (hb_sanitize_context_t *c) const
    923  {
    924    TRACE_SANITIZE (this);
    925    // here check on min_size only, TupleVariationHeader and var data will be
    926    // checked while accessing through iterator.
    927    return_trace (c->check_struct (this));
    928  }
    929 
    930  unsigned get_size (unsigned axis_count_times_2) const
    931  {
    932    unsigned total_size = min_size;
    933    unsigned count = tupleVarCount.get_count ();
    934    const TupleVariationHeader *tuple_var_header = &(get_tuple_var_header());
    935    for (unsigned i = 0; i < count; i++)
    936    {
    937      total_size += tuple_var_header->get_size (axis_count_times_2) + tuple_var_header->get_data_size ();
    938      tuple_var_header = &tuple_var_header->get_next (axis_count_times_2);
    939    }
    940 
    941    return total_size;
    942  }
    943 
    944  const TupleVariationHeader &get_tuple_var_header (void) const
    945  { return StructAfter<TupleVariationHeader> (data); }
    946 
    947  struct tuple_iterator_t;
    948  struct tuple_variations_t
    949  {
    950    hb_vector_t<tuple_delta_t> tuple_vars;
    951 
    952    private:
    953    /* referenced point set->compiled point data map */
    954    hb_hashmap_t<const hb_vector_t<bool>*, hb_vector_t<unsigned char>> point_data_map;
    955    /* referenced point set-> count map, used in finding shared points */
    956    hb_hashmap_t<const hb_vector_t<bool>*, unsigned> point_set_count_map;
    957 
    958    /* empty for non-gvar tuples.
    959     * shared_points_bytes is a pointer to some value in the point_data_map,
    960     * which will be freed during map destruction. Save it for serialization, so
    961     * no need to do find_shared_points () again */
    962    hb_vector_t<unsigned char> *shared_points_bytes = nullptr;
    963 
    964    /* total compiled byte size as TupleVariationData format, initialized to 0 */
    965    unsigned compiled_byte_size = 0;
    966    bool needs_padding = false;
    967 
    968    /* for gvar iup delta optimization: whether this is a composite glyph */
    969    bool is_composite = false;
    970 
    971    public:
    972    tuple_variations_t () = default;
    973    tuple_variations_t (const tuple_variations_t&) = delete;
    974    tuple_variations_t& operator=(const tuple_variations_t&) = delete;
    975    tuple_variations_t (tuple_variations_t&&) = default;
    976    tuple_variations_t& operator=(tuple_variations_t&&) = default;
    977    ~tuple_variations_t () = default;
    978 
    979    explicit operator bool () const { return bool (tuple_vars); }
    980    unsigned get_var_count () const
    981    {
    982      unsigned count = 0;
    983      /* when iup delta opt is enabled, compiled_deltas could be empty and we
    984       * should skip this tuple */
    985      for (auto& tuple: tuple_vars)
    986        if (tuple.compiled_deltas) count++;
    987 
    988      if (shared_points_bytes && shared_points_bytes->length)
    989        count |= TupleVarCount::SharedPointNumbers;
    990      return count;
    991    }
    992 
    993    unsigned get_compiled_byte_size () const
    994    { return compiled_byte_size; }
    995 
    996    bool create_from_tuple_var_data (tuple_iterator_t iterator,
    997                                     unsigned tuple_var_count,
    998                                     unsigned point_count,
    999                                     bool is_gvar,
   1000                                     const hb_map_t *axes_old_index_tag_map,
   1001                                     const hb_vector_t<unsigned> &shared_indices,
   1002                                     const hb_array_t<const F2DOT14> shared_tuples,
   1003 			     hb_alloc_pool_t *pool = nullptr,
   1004                                     bool is_composite_glyph = false)
   1005    {
   1006      hb_vector_t<unsigned> private_indices;
   1007      hb_vector_t<int> deltas_x;
   1008      hb_vector_t<int> deltas_y;
   1009      do
   1010      {
   1011        const HBUINT8 *p = iterator.get_serialized_data ();
   1012        unsigned int length = iterator.current_tuple->get_data_size ();
   1013        if (unlikely (!iterator.var_data_bytes.check_range (p, length)))
   1014          return false;
   1015 
   1016 hb_hashmap_t<hb_tag_t, Triple> axis_tuples;
   1017        if (!iterator.current_tuple->unpack_axis_tuples (iterator.get_axis_count (), shared_tuples, axes_old_index_tag_map, axis_tuples)
   1018            || axis_tuples.is_empty ())
   1019          return false;
   1020 
   1021 private_indices.reset ();
   1022        bool has_private_points = iterator.current_tuple->has_private_points ();
   1023        const HBUINT8 *end = p + length;
   1024        if (has_private_points &&
   1025            !TupleVariationData::decompile_points (p, private_indices, end))
   1026          return false;
   1027 
   1028        const hb_vector_t<unsigned> &indices = has_private_points ? private_indices : shared_indices;
   1029        bool apply_to_all = (indices.length == 0);
   1030        unsigned num_deltas = apply_to_all ? point_count : indices.length;
   1031 
   1032        if (unlikely (!deltas_x.resize_dirty  (num_deltas) ||
   1033                      !TupleVariationData::decompile_deltas (p, deltas_x, end)))
   1034          return false;
   1035 
   1036        if (is_gvar)
   1037        {
   1038          if (unlikely (!deltas_y.resize_dirty  (num_deltas) ||
   1039                        !TupleVariationData::decompile_deltas (p, deltas_y, end)))
   1040            return false;
   1041        }
   1042 
   1043        tuple_delta_t var;
   1044        var.axis_tuples = std::move (axis_tuples);
   1045        if (unlikely (!var.indices.allocate_from_pool (pool, point_count) ||
   1046                      !var.deltas_x.allocate_from_pool (pool, point_count, false)))
   1047          return false;
   1048 
   1049        if (is_gvar && unlikely (!var.deltas_y.allocate_from_pool (pool, point_count, false)))
   1050          return false;
   1051 
   1052        for (unsigned i = 0; i < num_deltas; i++)
   1053        {
   1054          unsigned idx = apply_to_all ? i : indices[i];
   1055          if (idx >= point_count) continue;
   1056          var.indices[idx] = true;
   1057          var.deltas_x[idx] = deltas_x[i];
   1058          if (is_gvar)
   1059            var.deltas_y[idx] = deltas_y[i];
   1060        }
   1061        tuple_vars.push (std::move (var));
   1062      } while (iterator.move_to_next ());
   1063 
   1064      is_composite = is_composite_glyph;
   1065      return true;
   1066    }
   1067 
   1068    bool create_from_item_var_data (const VarData &var_data,
   1069                                    const hb_vector_t<hb_hashmap_t<hb_tag_t, Triple>>& regions,
   1070                                    const hb_map_t& axes_old_index_tag_map,
   1071                                    unsigned& item_count,
   1072                                    const hb_inc_bimap_t* inner_map = nullptr)
   1073    {
   1074      /* NULL offset, to keep original varidx valid, just return */
   1075      if (&var_data == &Null (VarData))
   1076        return true;
   1077 
   1078      unsigned num_regions = var_data.get_region_index_count ();
   1079      if (!tuple_vars.alloc (num_regions)) return false;
   1080 
   1081      item_count = inner_map ? inner_map->get_population () : var_data.get_item_count ();
   1082      if (!item_count) return true;
   1083      unsigned row_size = var_data.get_row_size ();
   1084      const HBUINT8 *delta_bytes = var_data.get_delta_bytes ();
   1085 
   1086      for (unsigned r = 0; r < num_regions; r++)
   1087      {
   1088        /* In VarData, deltas are organized in rows, convert them into
   1089         * column(region) based tuples, resize deltas_x first */
   1090        tuple_delta_t tuple;
   1091        if (!tuple.deltas_x.resize_dirty  (item_count) ||
   1092            !tuple.indices.resize_dirty  (item_count))
   1093          return false;
   1094 
   1095        for (unsigned i = 0; i < item_count; i++)
   1096        {
   1097          tuple.indices.arrayZ[i] = true;
   1098          tuple.deltas_x.arrayZ[i] = var_data.get_item_delta_fast (inner_map ? inner_map->backward (i) : i,
   1099                                                                   r, delta_bytes, row_size);
   1100        }
   1101 
   1102        unsigned region_index = var_data.get_region_index (r);
   1103        if (region_index >= regions.length) return false;
   1104        tuple.axis_tuples = regions.arrayZ[region_index];
   1105 
   1106        tuple_vars.push (std::move (tuple));
   1107      }
   1108      return !tuple_vars.in_error ();
   1109    }
   1110 
   1111    private:
   1112    static int _cmp_axis_tag (const void *pa, const void *pb)
   1113    {
   1114      const hb_tag_t *a = (const hb_tag_t*) pa;
   1115      const hb_tag_t *b = (const hb_tag_t*) pb;
   1116      return (int)(*a) - (int)(*b);
   1117    }
   1118 
   1119    bool change_tuple_variations_axis_limits (const hb_hashmap_t<hb_tag_t, Triple>& normalized_axes_location,
   1120                                              const hb_hashmap_t<hb_tag_t, TripleDistances>& axes_triple_distances,
   1121 				      hb_alloc_pool_t *pool = nullptr)
   1122    {
   1123      /* sort axis_tag/axis_limits, make result deterministic */
   1124      hb_vector_t<hb_tag_t> axis_tags;
   1125      if (!axis_tags.alloc (normalized_axes_location.get_population ()))
   1126        return false;
   1127      for (auto t : normalized_axes_location.keys ())
   1128        axis_tags.push (t);
   1129 
   1130      // Reused vectors for reduced malloc pressure.
   1131      rebase_tent_result_scratch_t scratch;
   1132      hb_vector_t<tuple_delta_t> out;
   1133 
   1134      axis_tags.qsort (_cmp_axis_tag);
   1135      for (auto axis_tag : axis_tags)
   1136      {
   1137        Triple *axis_limit;
   1138        if (!normalized_axes_location.has (axis_tag, &axis_limit))
   1139          return false;
   1140        TripleDistances axis_triple_distances{1.0, 1.0};
   1141        if (axes_triple_distances.has (axis_tag))
   1142          axis_triple_distances = axes_triple_distances.get (axis_tag);
   1143 
   1144        hb_vector_t<tuple_delta_t> new_vars;
   1145        for (tuple_delta_t& var : tuple_vars)
   1146        {
   1147   // This may move var out.
   1148   var.change_tuple_var_axis_limit (axis_tag, *axis_limit, axis_triple_distances, out, scratch, pool);
   1149          if (!out) continue;
   1150 
   1151          unsigned new_len = new_vars.length + out.length;
   1152 
   1153          if (unlikely (!new_vars.alloc (new_len, false)))
   1154            return false;
   1155 
   1156          for (unsigned i = 0; i < out.length; i++)
   1157            new_vars.push (std::move (out[i]));
   1158        }
   1159        tuple_vars = std::move (new_vars);
   1160      }
   1161      return true;
   1162    }
   1163 
   1164    /* merge tuple variations with overlapping tents, if iup delta optimization
   1165     * is enabled, add default deltas to contour_points */
   1166    bool merge_tuple_variations (contour_point_vector_t* contour_points = nullptr)
   1167    {
   1168      hb_vector_t<tuple_delta_t> new_vars;
   1169      // The pre-allocation is essential for address stability of pointers
   1170      // we store in the hashmap.
   1171      if (unlikely (!new_vars.alloc (tuple_vars.length)))
   1172 return false;
   1173      hb_hashmap_t<const hb_hashmap_t<hb_tag_t, Triple>*, unsigned> m;
   1174      for (tuple_delta_t& var : tuple_vars)
   1175      {
   1176        /* if all axes are pinned, drop the tuple variation */
   1177        if (var.axis_tuples.is_empty ())
   1178        {
   1179          /* if iup_delta_optimize is enabled, add deltas to contour coords */
   1180          if (contour_points && !contour_points->add_deltas (var.deltas_x,
   1181                                                             var.deltas_y,
   1182                                                             var.indices))
   1183            return false;
   1184          continue;
   1185        }
   1186 
   1187        unsigned *idx;
   1188        if (m.has (&(var.axis_tuples), &idx))
   1189        {
   1190          new_vars[*idx] += var;
   1191        }
   1192        else
   1193        {
   1194   auto *new_var = new_vars.push ();
   1195   if (unlikely (new_vars.in_error ()))
   1196     return false;
   1197          hb_swap (*new_var, var);
   1198          if (unlikely (!m.set (&(new_var->axis_tuples), new_vars.length - 1)))
   1199            return false;
   1200        }
   1201      }
   1202      m.fini (); // Just in case, since it points into new_vars data.
   1203 	 // Shouldn't be necessary though, since we only move new_vars, not its
   1204 	 // contents.
   1205      tuple_vars = std::move (new_vars);
   1206      return true;
   1207    }
   1208 
   1209    /* compile all point set and store byte data in a point_set->hb_bytes_t hashmap,
   1210     * also update point_set->count map, which will be used in finding shared
   1211     * point set*/
   1212    bool compile_all_point_sets ()
   1213    {
   1214      for (const auto& tuple: tuple_vars)
   1215      {
   1216        const hb_vector_t<bool>* points_set = &(tuple.indices);
   1217        if (point_data_map.has (points_set))
   1218        {
   1219          unsigned *count;
   1220          if (unlikely (!point_set_count_map.has (points_set, &count) ||
   1221                        !point_set_count_map.set (points_set, (*count) + 1)))
   1222            return false;
   1223          continue;
   1224        }
   1225 
   1226        hb_vector_t<unsigned char> compiled_point_data;
   1227        if (!tuple_delta_t::compile_point_set (*points_set, compiled_point_data))
   1228          return false;
   1229 
   1230        if (!point_data_map.set (points_set, std::move (compiled_point_data)) ||
   1231            !point_set_count_map.set (points_set, 1))
   1232          return false;
   1233      }
   1234      return true;
   1235    }
   1236 
   1237    /* find shared points set which saves most bytes */
   1238    void find_shared_points ()
   1239    {
   1240      unsigned max_saved_bytes = 0;
   1241 
   1242      for (const auto& _ : point_data_map.iter_ref ())
   1243      {
   1244        const hb_vector_t<bool>* points_set = _.first;
   1245        unsigned data_length = _.second.length;
   1246        if (!data_length) continue;
   1247        unsigned *count;
   1248        if (unlikely (!point_set_count_map.has (points_set, &count) ||
   1249                      *count <= 1))
   1250        {
   1251          shared_points_bytes = nullptr;
   1252          return;
   1253        }
   1254 
   1255        unsigned saved_bytes = data_length * ((*count) -1);
   1256        if (saved_bytes > max_saved_bytes)
   1257        {
   1258          max_saved_bytes = saved_bytes;
   1259          shared_points_bytes = &(_.second);
   1260        }
   1261      }
   1262    }
   1263 
   1264    bool calc_inferred_deltas (const contour_point_vector_t& contour_points,
   1265 		       hb_vector_t<unsigned> &scratch)
   1266    {
   1267      for (tuple_delta_t& var : tuple_vars)
   1268        if (!var.calc_inferred_deltas (contour_points, scratch))
   1269          return false;
   1270 
   1271      return true;
   1272    }
   1273 
   1274    bool iup_optimize (const contour_point_vector_t& contour_points,
   1275 	       optimize_scratch_t &scratch)
   1276    {
   1277      for (tuple_delta_t& var : tuple_vars)
   1278      {
   1279        if (!var.optimize (contour_points, is_composite, scratch))
   1280          return false;
   1281      }
   1282      return true;
   1283    }
   1284 
   1285    public:
   1286    bool instantiate (const hb_hashmap_t<hb_tag_t, Triple>& normalized_axes_location,
   1287                      const hb_hashmap_t<hb_tag_t, TripleDistances>& axes_triple_distances,
   1288 	      optimize_scratch_t &scratch,
   1289 	      hb_alloc_pool_t *pool = nullptr,
   1290                      contour_point_vector_t* contour_points = nullptr,
   1291                      bool optimize = false)
   1292    {
   1293      if (!tuple_vars) return true;
   1294      if (!change_tuple_variations_axis_limits (normalized_axes_location, axes_triple_distances, pool))
   1295        return false;
   1296      /* compute inferred deltas only for gvar */
   1297      if (contour_points)
   1298      {
   1299 hb_vector_t<unsigned> scratch;
   1300 if (!calc_inferred_deltas (*contour_points, scratch))
   1301   return false;
   1302      }
   1303 
   1304      /* if iup delta opt is on, contour_points can't be null */
   1305      if (optimize && !contour_points)
   1306        return false;
   1307 
   1308      if (!merge_tuple_variations (optimize ? contour_points : nullptr))
   1309        return false;
   1310 
   1311      if (optimize && !iup_optimize (*contour_points, scratch)) return false;
   1312      return !tuple_vars.in_error ();
   1313    }
   1314 
   1315    bool compile_bytes (const hb_map_t& axes_index_map,
   1316                        const hb_map_t& axes_old_index_tag_map,
   1317                        bool use_shared_points,
   1318                        bool is_gvar = false,
   1319                        const hb_hashmap_t<const hb_vector_t<F2DOT14>*, unsigned>* shared_tuples_idx_map = nullptr,
   1320 		hb_alloc_pool_t *pool = nullptr)
   1321    {
   1322      // return true for empty glyph
   1323      if (!tuple_vars)
   1324        return true;
   1325 
   1326      // compile points set and store data in hashmap
   1327      if (!compile_all_point_sets ())
   1328        return false;
   1329 
   1330      /* total compiled byte size as TupleVariationData format, initialized to its
   1331       * min_size: 4 */
   1332      compiled_byte_size += 4;
   1333 
   1334      if (use_shared_points)
   1335      {
   1336        find_shared_points ();
   1337        if (shared_points_bytes)
   1338          compiled_byte_size += shared_points_bytes->length;
   1339      }
   1340      hb_vector_t<int> rounded_deltas_scratch;
   1341      // compile delta and tuple var header for each tuple variation
   1342      for (auto& tuple: tuple_vars)
   1343      {
   1344        const hb_vector_t<bool>* points_set = &(tuple.indices);
   1345        hb_vector_t<unsigned char> *points_data;
   1346        if (unlikely (!point_data_map.has (points_set, &points_data)))
   1347          return false;
   1348 
   1349        /* when iup optimization is enabled, num of referenced points could be 0
   1350         * and thus the compiled points bytes is empty, we should skip compiling
   1351         * this tuple */
   1352        if (!points_data->length)
   1353          continue;
   1354        if (!tuple.compile_deltas (rounded_deltas_scratch, pool))
   1355          return false;
   1356 
   1357        unsigned points_data_length = (points_data != shared_points_bytes) ? points_data->length : 0;
   1358        if (!tuple.compile_tuple_var_header (axes_index_map, points_data_length, axes_old_index_tag_map,
   1359                                             shared_tuples_idx_map,
   1360 				     pool))
   1361          return false;
   1362        compiled_byte_size += tuple.compiled_tuple_header.length + points_data_length + tuple.compiled_deltas.length;
   1363      }
   1364 
   1365      if (is_gvar && (compiled_byte_size % 2))
   1366      {
   1367        needs_padding = true;
   1368        compiled_byte_size += 1;
   1369      }
   1370 
   1371      return true;
   1372    }
   1373 
   1374    bool serialize_var_headers (hb_serialize_context_t *c, unsigned& total_header_len) const
   1375    {
   1376      TRACE_SERIALIZE (this);
   1377      for (const auto& tuple: tuple_vars)
   1378      {
   1379        tuple.compiled_tuple_header.as_array ().copy (c);
   1380        if (c->in_error ()) return_trace (false);
   1381        total_header_len += tuple.compiled_tuple_header.length;
   1382      }
   1383      return_trace (true);
   1384    }
   1385 
   1386    bool serialize_var_data (hb_serialize_context_t *c, bool is_gvar) const
   1387    {
   1388      TRACE_SERIALIZE (this);
   1389      if (is_gvar && shared_points_bytes)
   1390      {
   1391        hb_ubytes_t s (shared_points_bytes->arrayZ, shared_points_bytes->length);
   1392        s.copy (c);
   1393      }
   1394 
   1395      for (const auto& tuple: tuple_vars)
   1396      {
   1397        const hb_vector_t<bool>* points_set = &(tuple.indices);
   1398        hb_vector_t<unsigned char> *point_data;
   1399        if (!point_data_map.has (points_set, &point_data))
   1400          return_trace (false);
   1401 
   1402        if (!is_gvar || point_data != shared_points_bytes)
   1403        {
   1404          hb_ubytes_t s (point_data->arrayZ, point_data->length);
   1405          s.copy (c);
   1406        }
   1407 
   1408        tuple.compiled_deltas.as_array ().copy (c);
   1409        if (c->in_error ()) return_trace (false);
   1410      }
   1411 
   1412      /* padding for gvar */
   1413      if (is_gvar && needs_padding)
   1414      {
   1415        HBUINT8 pad;
   1416        pad = 0;
   1417        if (!c->embed (pad)) return_trace (false);
   1418      }
   1419      return_trace (true);
   1420    }
   1421  };
   1422 
   1423  struct tuple_iterator_t
   1424  {
   1425    unsigned get_axis_count () const { return axis_count; }
   1426 
   1427    void init (hb_bytes_t var_data_bytes_, unsigned int axis_count_, const void *table_base_)
   1428    {
   1429      var_data_bytes = var_data_bytes_;
   1430      var_data = var_data_bytes_.as<TupleVariationData> ();
   1431      tuples_left = var_data->tupleVarCount.get_count ();
   1432      axis_count = axis_count_;
   1433      axis_count_times_2 = axis_count_ * 2;
   1434      current_tuple = &var_data->get_tuple_var_header ();
   1435      data_offset = 0;
   1436      table_base = table_base_;
   1437    }
   1438 
   1439    bool get_shared_indices (hb_vector_t<unsigned int> &shared_indices /* OUT */)
   1440    {
   1441      if (var_data->has_shared_point_numbers ())
   1442      {
   1443        const HBUINT8 *base = &(table_base+var_data->data);
   1444        const HBUINT8 *p = base;
   1445        if (!decompile_points (p, shared_indices, (const HBUINT8 *) (var_data_bytes.arrayZ + var_data_bytes.length))) return false;
   1446        data_offset = p - base;
   1447      }
   1448      return true;
   1449    }
   1450 
   1451    bool is_valid ()
   1452    {
   1453      if (unlikely (tuples_left <= 0))
   1454 return false;
   1455 
   1456      current_tuple_size = TupleVariationHeader::min_size;
   1457      if (unlikely (!var_data_bytes.check_end ((const char *) current_tuple + current_tuple_size)))
   1458 return false;
   1459 
   1460      current_tuple_size = current_tuple->get_size (axis_count_times_2);
   1461      if (unlikely (!var_data_bytes.check_end ((const char *) current_tuple + current_tuple_size)))
   1462 return false;
   1463 
   1464      return true;
   1465    }
   1466 
   1467    HB_ALWAYS_INLINE
   1468    bool move_to_next ()
   1469    {
   1470      data_offset += current_tuple->get_data_size ();
   1471      current_tuple = &StructAtOffset<TupleVariationHeader> (current_tuple, current_tuple_size);
   1472      tuples_left--;
   1473      return is_valid ();
   1474    }
   1475 
   1476    // TODO: Make it return (sanitized) hb_bytes_t
   1477    const HBUINT8 *get_serialized_data () const
   1478    { return &(table_base+var_data->data) + data_offset; }
   1479 
   1480    private:
   1481    signed tuples_left;
   1482    const TupleVariationData *var_data;
   1483    unsigned int axis_count;
   1484    unsigned int axis_count_times_2;
   1485    unsigned int data_offset;
   1486    unsigned int current_tuple_size;
   1487    const void *table_base;
   1488 
   1489    public:
   1490    hb_bytes_t var_data_bytes;
   1491    const TupleVariationHeader *current_tuple;
   1492  };
   1493 
   1494  static bool get_tuple_iterator (hb_bytes_t var_data_bytes, unsigned axis_count,
   1495                                  const void *table_base,
   1496                                  hb_vector_t<unsigned int> &shared_indices /* OUT */,
   1497                                  tuple_iterator_t *iterator /* OUT */)
   1498  {
   1499    iterator->init (var_data_bytes, axis_count, table_base);
   1500    if (!iterator->get_shared_indices (shared_indices))
   1501      return false;
   1502    return iterator->is_valid ();
   1503  }
   1504 
   1505  bool has_shared_point_numbers () const { return tupleVarCount.has_shared_point_numbers (); }
   1506 
   1507  static bool decompile_points (const HBUINT8 *&p /* IN/OUT */,
   1508 			hb_vector_t<unsigned int> &points /* OUT */,
   1509 			const HBUINT8 *end)
   1510  {
   1511    enum packed_point_flag_t
   1512    {
   1513      POINTS_ARE_WORDS     = 0x80,
   1514      POINT_RUN_COUNT_MASK = 0x7F
   1515    };
   1516 
   1517    if (unlikely (p + 1 > end)) return false;
   1518 
   1519    unsigned count = *p++;
   1520    if (count & POINTS_ARE_WORDS)
   1521    {
   1522      if (unlikely (p + 1 > end)) return false;
   1523      count = ((count & POINT_RUN_COUNT_MASK) << 8) | *p++;
   1524    }
   1525    if (unlikely (!points.resize_dirty  (count))) return false;
   1526 
   1527    unsigned n = 0;
   1528    unsigned i = 0;
   1529    while (i < count)
   1530    {
   1531      if (unlikely (p + 1 > end)) return false;
   1532      unsigned control = *p++;
   1533      unsigned run_count = (control & POINT_RUN_COUNT_MASK) + 1;
   1534      unsigned stop = i + run_count;
   1535      if (unlikely (stop > count)) return false;
   1536      if (control & POINTS_ARE_WORDS)
   1537      {
   1538        if (unlikely (p + run_count * HBUINT16::static_size > end)) return false;
   1539        for (; i < stop; i++)
   1540        {
   1541          n += *(const HBUINT16 *)p;
   1542          points.arrayZ[i] = n;
   1543          p += HBUINT16::static_size;
   1544        }
   1545      }
   1546      else
   1547      {
   1548        if (unlikely (p + run_count > end)) return false;
   1549        for (; i < stop; i++)
   1550        {
   1551          n += *p++;
   1552          points.arrayZ[i] = n;
   1553        }
   1554      }
   1555    }
   1556    return true;
   1557  }
   1558 
   1559  template <typename T>
   1560  HB_ALWAYS_INLINE
   1561  static bool decompile_deltas (const HBUINT8 *&p /* IN/OUT */,
   1562 			hb_vector_t<T> &deltas /* IN/OUT */,
   1563 			const HBUINT8 *end,
   1564 			bool consume_all = false,
   1565 			unsigned start = 0)
   1566  {
   1567    return TupleValues::decompile (p, deltas, end, consume_all, start);
   1568  }
   1569 
   1570  bool has_data () const { return tupleVarCount; }
   1571 
   1572  bool decompile_tuple_variations (unsigned point_count,
   1573                                   bool is_gvar,
   1574                                   tuple_iterator_t iterator,
   1575                                   const hb_map_t *axes_old_index_tag_map,
   1576                                   const hb_vector_t<unsigned> &shared_indices,
   1577                                   const hb_array_t<const F2DOT14> shared_tuples,
   1578                                   tuple_variations_t& tuple_variations, /* OUT */
   1579 			   hb_alloc_pool_t *pool = nullptr,
   1580                                   bool is_composite_glyph = false) const
   1581  {
   1582    return tuple_variations.create_from_tuple_var_data (iterator, tupleVarCount,
   1583                                                        point_count, is_gvar,
   1584                                                        axes_old_index_tag_map,
   1585                                                        shared_indices,
   1586                                                        shared_tuples,
   1587 						pool,
   1588                                                        is_composite_glyph);
   1589  }
   1590 
   1591  bool serialize (hb_serialize_context_t *c,
   1592                  bool is_gvar,
   1593                  const tuple_variations_t& tuple_variations) const
   1594  {
   1595    TRACE_SERIALIZE (this);
   1596    /* empty tuple variations, just return and skip serialization. */
   1597    if (!tuple_variations) return_trace (true);
   1598 
   1599    auto *out = c->start_embed (this);
   1600    if (unlikely (!c->extend_min (out))) return_trace (false);
   1601 
   1602    if (!c->check_assign (out->tupleVarCount, tuple_variations.get_var_count (),
   1603                          HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false);
   1604 
   1605    unsigned total_header_len = 0;
   1606 
   1607    if (!tuple_variations.serialize_var_headers (c, total_header_len))
   1608      return_trace (false);
   1609 
   1610    unsigned data_offset = min_size + total_header_len;
   1611    if (!is_gvar) data_offset += 4;
   1612    if (!c->check_assign (out->data, data_offset, HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false);
   1613 
   1614    return tuple_variations.serialize_var_data (c, is_gvar);
   1615  }
   1616 
   1617  protected:
   1618  struct TupleVarCount : HBUINT16
   1619  {
   1620    friend struct tuple_variations_t;
   1621    bool has_shared_point_numbers () const { return ((*this) & SharedPointNumbers); }
   1622    unsigned int get_count () const { return (*this) & CountMask; }
   1623    TupleVarCount& operator = (uint16_t i) { HBUINT16::operator= (i); return *this; }
   1624    explicit operator bool () const { return get_count (); }
   1625 
   1626    protected:
   1627    enum Flags
   1628    {
   1629      SharedPointNumbers= 0x8000u,
   1630      CountMask         = 0x0FFFu
   1631    };
   1632    public:
   1633    DEFINE_SIZE_STATIC (2);
   1634  };
   1635 
   1636  TupleVarCount tupleVarCount;  /* A packed field. The high 4 bits are flags, and the
   1637                                 * low 12 bits are the number of tuple variation tables
   1638                                 * for this glyph. The number of tuple variation tables
   1639                                 * can be any number between 1 and 4095. */
   1640  OffsetTo<HBUINT8, OffType>
   1641                data;           /* Offset from the start of the base table
   1642                                 * to the serialized data. */
   1643  /* TupleVariationHeader tupleVariationHeaders[] *//* Array of tuple variation headers. */
   1644  public:
   1645  DEFINE_SIZE_MIN (2 + OffType::static_size);
   1646 };
   1647 
   1648 // TODO: Move tuple_variations_t to outside of TupleVariationData
   1649 using tuple_variations_t = TupleVariationData<HBUINT16>::tuple_variations_t;
   1650 struct item_variations_t
   1651 {
   1652  using region_t = const hb_hashmap_t<hb_tag_t, Triple>*;
   1653  private:
   1654  /* each subtable is decompiled into a tuple_variations_t, in which all tuples
   1655   * have the same num of deltas (rows) */
   1656  hb_vector_t<tuple_variations_t> vars;
   1657 
   1658  /* num of retained rows for each subtable, there're 2 cases when var_data is empty:
   1659   * 1. retained item_count is zero
   1660   * 2. regions is empty and item_count is non-zero.
   1661   * when converting to tuples, both will be dropped because the tuple is empty,
   1662   * however, we need to retain 2. as all-zero rows to keep original varidx
   1663   * valid, so we need a way to remember the num of rows for each subtable */
   1664  hb_vector_t<unsigned> var_data_num_rows;
   1665 
   1666  /* original region list, decompiled from item varstore, used when rebuilding
   1667   * region list after instantiation */
   1668  hb_vector_t<hb_hashmap_t<hb_tag_t, Triple>> orig_region_list;
   1669 
   1670  /* region list: vector of Regions, maintain the original order for the regions
   1671   * that existed before instantiate (), append the new regions at the end.
   1672   * Regions are stored in each tuple already, save pointers only.
   1673   * When converting back to item varstore, unused regions will be pruned */
   1674  hb_vector_t<region_t> region_list;
   1675 
   1676  /* region -> idx map after instantiation and pruning unused regions */
   1677  hb_hashmap_t<region_t, unsigned> region_map;
   1678 
   1679  /* all delta rows after instantiation */
   1680  hb_vector_t<hb_vector_t<int>> delta_rows;
   1681  /* final optimized vector of encoding objects used to assemble the varstore */
   1682  hb_vector_t<delta_row_encoding_t> encodings;
   1683 
   1684  /* old varidxes -> new var_idxes map */
   1685  hb_map_t varidx_map;
   1686 
   1687  /* has long words */
   1688  bool has_long = false;
   1689 
   1690  public:
   1691  bool has_long_word () const
   1692  { return has_long; }
   1693 
   1694  const hb_vector_t<region_t>& get_region_list () const
   1695  { return region_list; }
   1696 
   1697  const hb_vector_t<delta_row_encoding_t>& get_vardata_encodings () const
   1698  { return encodings; }
   1699 
   1700  const hb_map_t& get_varidx_map () const
   1701  { return varidx_map; }
   1702 
   1703  bool instantiate (const ItemVariationStore& varStore,
   1704                    const hb_subset_plan_t *plan,
   1705                    bool optimize=true,
   1706                    bool use_no_variation_idx=true,
   1707                    const hb_array_t <const hb_inc_bimap_t> inner_maps = hb_array_t<const hb_inc_bimap_t> ())
   1708  {
   1709    if (!create_from_item_varstore (varStore, plan->axes_old_index_tag_map, inner_maps))
   1710      return false;
   1711    if (!instantiate_tuple_vars (plan->axes_location, plan->axes_triple_distances))
   1712      return false;
   1713    return as_item_varstore (optimize, use_no_variation_idx);
   1714  }
   1715 
   1716  /* keep below APIs public only for unit test: test-item-varstore */
   1717  bool create_from_item_varstore (const ItemVariationStore& varStore,
   1718                                  const hb_map_t& axes_old_index_tag_map,
   1719                                  const hb_array_t <const hb_inc_bimap_t> inner_maps = hb_array_t<const hb_inc_bimap_t> ())
   1720  {
   1721    const VarRegionList& regionList = varStore.get_region_list ();
   1722    if (!regionList.get_var_regions (axes_old_index_tag_map, orig_region_list))
   1723      return false;
   1724 
   1725    unsigned num_var_data = varStore.get_sub_table_count ();
   1726    if (inner_maps && inner_maps.length != num_var_data) return false;
   1727    if (!vars.alloc (num_var_data) ||
   1728        !var_data_num_rows.alloc (num_var_data)) return false;
   1729 
   1730    for (unsigned i = 0; i < num_var_data; i++)
   1731    {
   1732      if (inner_maps && !inner_maps.arrayZ[i].get_population ())
   1733          continue;
   1734      tuple_variations_t var_data_tuples;
   1735      unsigned item_count = 0;
   1736      if (!var_data_tuples.create_from_item_var_data (varStore.get_sub_table (i),
   1737                                                      orig_region_list,
   1738                                                      axes_old_index_tag_map,
   1739                                                      item_count,
   1740                                                      inner_maps ? &(inner_maps.arrayZ[i]) : nullptr))
   1741        return false;
   1742 
   1743      var_data_num_rows.push (item_count);
   1744      vars.push (std::move (var_data_tuples));
   1745    }
   1746    return !vars.in_error () && !var_data_num_rows.in_error () && vars.length == var_data_num_rows.length;
   1747  }
   1748 
   1749  bool instantiate_tuple_vars (const hb_hashmap_t<hb_tag_t, Triple>& normalized_axes_location,
   1750                               const hb_hashmap_t<hb_tag_t, TripleDistances>& axes_triple_distances)
   1751  {
   1752    optimize_scratch_t scratch;
   1753    for (tuple_variations_t& tuple_vars : vars)
   1754      if (!tuple_vars.instantiate (normalized_axes_location, axes_triple_distances, scratch))
   1755        return false;
   1756 
   1757    if (!build_region_list ()) return false;
   1758    return true;
   1759  }
   1760 
   1761  bool build_region_list ()
   1762  {
   1763    /* scan all tuples and collect all unique regions, prune unused regions */
   1764    hb_hashmap_t<region_t, unsigned> all_regions;
   1765    hb_hashmap_t<region_t, unsigned> used_regions;
   1766 
   1767    /* use a vector when inserting new regions, make result deterministic */
   1768    hb_vector_t<region_t> all_unique_regions;
   1769    for (const tuple_variations_t& sub_table : vars)
   1770    {
   1771      for (const tuple_delta_t& tuple : sub_table.tuple_vars)
   1772      {
   1773        region_t r = &(tuple.axis_tuples);
   1774        if (!used_regions.has (r))
   1775        {
   1776          bool all_zeros = true;
   1777          for (float d : tuple.deltas_x)
   1778          {
   1779            int delta = (int) roundf (d);
   1780            if (delta != 0)
   1781            {
   1782              all_zeros = false;
   1783              break;
   1784            }
   1785          }
   1786          if (!all_zeros)
   1787          {
   1788            if (!used_regions.set (r, 1))
   1789              return false;
   1790          }
   1791        }
   1792        if (all_regions.has (r))
   1793          continue;
   1794        if (!all_regions.set (r, 1))
   1795          return false;
   1796        all_unique_regions.push (r);
   1797      }
   1798    }
   1799 
   1800    /* regions are empty means no variation data, return true */
   1801    if (!all_regions || !all_unique_regions) return true;
   1802 
   1803    if (!region_list.alloc (all_regions.get_population ()))
   1804      return false;
   1805 
   1806    unsigned idx = 0;
   1807    /* append the original regions that pre-existed */
   1808    for (const auto& r : orig_region_list)
   1809    {
   1810      if (!all_regions.has (&r) || !used_regions.has (&r))
   1811        continue;
   1812 
   1813      region_list.push (&r);
   1814      if (!region_map.set (&r, idx))
   1815        return false;
   1816      all_regions.del (&r);
   1817      idx++;
   1818    }
   1819 
   1820    /* append the new regions at the end */
   1821    for (const auto& r: all_unique_regions)
   1822    {
   1823      if (!all_regions.has (r) || !used_regions.has (r))
   1824        continue;
   1825      region_list.push (r);
   1826      if (!region_map.set (r, idx))
   1827        return false;
   1828      all_regions.del (r);
   1829      idx++;
   1830    }
   1831    return (!region_list.in_error ()) && (!region_map.in_error ());
   1832  }
   1833 
   1834  /* main algorithm ported from fonttools VarStore_optimize() method, optimize
   1835   * varstore by default */
   1836 
   1837  struct combined_gain_idx_tuple_t
   1838  {
   1839    uint64_t encoded;
   1840 
   1841    combined_gain_idx_tuple_t () = default;
   1842    combined_gain_idx_tuple_t (unsigned gain, unsigned i, unsigned j)
   1843        : encoded ((uint64_t (0xFFFFFF - gain) << 40) | (uint64_t (i) << 20) | uint64_t (j))
   1844    {
   1845      assert (gain < 0xFFFFFF);
   1846      assert (i < 0xFFFFFFF && j < 0xFFFFFFF);
   1847    }
   1848 
   1849    bool operator < (const combined_gain_idx_tuple_t& o)
   1850    {
   1851      return encoded < o.encoded;
   1852    }
   1853 
   1854    bool operator <= (const combined_gain_idx_tuple_t& o)
   1855    {
   1856      return encoded <= o.encoded;
   1857    }
   1858 
   1859    unsigned idx_1 () const { return (encoded >> 20) & 0xFFFFF; };
   1860    unsigned idx_2 () const { return encoded & 0xFFFFF; };
   1861  };
   1862 
   1863  bool as_item_varstore (bool optimize=true, bool use_no_variation_idx=true)
   1864  {
   1865    /* return true if no variation data */
   1866    if (!region_list) return true;
   1867    unsigned num_cols = region_list.length;
   1868    /* pre-alloc a 2D vector for all sub_table's VarData rows */
   1869    unsigned total_rows = 0;
   1870    for (unsigned major = 0; major < var_data_num_rows.length; major++)
   1871      total_rows += var_data_num_rows[major];
   1872 
   1873    if (!delta_rows.resize (total_rows)) return false;
   1874    /* init all rows to [0]*num_cols */
   1875    for (unsigned i = 0; i < total_rows; i++)
   1876      if (!(delta_rows[i].resize (num_cols))) return false;
   1877 
   1878    /* old VarIdxes -> full encoding_row mapping */
   1879    hb_hashmap_t<unsigned, const hb_vector_t<int>*> front_mapping;
   1880    unsigned start_row = 0;
   1881    hb_vector_t<delta_row_encoding_t> encoding_objs;
   1882 
   1883    /* delta_rows map, used for filtering out duplicate rows */
   1884    hb_vector_t<const hb_vector_t<int> *> major_rows;
   1885    hb_hashmap_t<const hb_vector_t<int>*, unsigned> delta_rows_map;
   1886    for (unsigned major = 0; major < vars.length; major++)
   1887    {
   1888      /* deltas are stored in tuples(column based), convert them back into items
   1889       * (row based) delta */
   1890      const tuple_variations_t& tuples = vars[major];
   1891      unsigned num_rows = var_data_num_rows[major];
   1892 
   1893      if (!num_rows) continue;
   1894 
   1895      for (const tuple_delta_t& tuple: tuples.tuple_vars)
   1896      {
   1897        if (tuple.deltas_x.length != num_rows)
   1898          return false;
   1899 
   1900        /* skip unused regions */
   1901        unsigned *col_idx;
   1902        if (!region_map.has (&(tuple.axis_tuples), &col_idx))
   1903          continue;
   1904 
   1905        for (unsigned i = 0; i < num_rows; i++)
   1906        {
   1907          int rounded_delta = roundf (tuple.deltas_x[i]);
   1908          delta_rows[start_row + i][*col_idx] += rounded_delta;
   1909          has_long |= rounded_delta < -65536 || rounded_delta > 65535;
   1910        }
   1911      }
   1912 
   1913      major_rows.reset ();
   1914      for (unsigned minor = 0; minor < num_rows; minor++)
   1915      {
   1916 const hb_vector_t<int>& row = delta_rows[start_row + minor];
   1917 if (use_no_variation_idx)
   1918 {
   1919   bool all_zeros = true;
   1920   for (int delta : row)
   1921   {
   1922     if (delta != 0)
   1923     {
   1924       all_zeros = false;
   1925       break;
   1926     }
   1927   }
   1928   if (all_zeros)
   1929     continue;
   1930 }
   1931 
   1932 if (!front_mapping.set ((major<<16) + minor, &row))
   1933   return false;
   1934 
   1935 if (delta_rows_map.has (&row))
   1936   continue;
   1937 
   1938 delta_rows_map.set (&row, 1);
   1939 
   1940 major_rows.push (&row);
   1941      }
   1942 
   1943      if (major_rows)
   1944 encoding_objs.push (delta_row_encoding_t (std::move (major_rows), num_cols));
   1945 
   1946      start_row += num_rows;
   1947    }
   1948 
   1949    /* return directly if no optimization, maintain original VariationIndex so
   1950     * varidx_map would be empty */
   1951    if (!optimize)
   1952    {
   1953      encodings = std::move (encoding_objs);
   1954      return !encodings.in_error ();
   1955    }
   1956 
   1957    /* NOTE: Fonttools instancer always optimizes VarStore from scratch. This
   1958     * is too costly for large fonts. So, instead, we retain the encodings of
   1959     * the original VarStore, and just try to combine them if possible. This
   1960     * is a compromise between optimization and performance and practically
   1961     * works very well. */
   1962 
   1963    // This produces slightly smaller results in some cases.
   1964    encoding_objs.qsort ();
   1965 
   1966    /* main algorithm: repeatedly pick 2 best encodings to combine, and combine them */
   1967    using item_t = hb_priority_queue_t<combined_gain_idx_tuple_t>::item_t;
   1968    hb_vector_t<item_t> queue_items;
   1969    unsigned num_todos = encoding_objs.length;
   1970    for (unsigned i = 0; i < num_todos; i++)
   1971    {
   1972      for (unsigned j = i + 1; j < num_todos; j++)
   1973      {
   1974        int combining_gain = encoding_objs.arrayZ[i].gain_from_merging (encoding_objs.arrayZ[j]);
   1975        if (combining_gain > 0)
   1976          queue_items.push (item_t (combined_gain_idx_tuple_t (combining_gain, i, j), 0));
   1977      }
   1978    }
   1979 
   1980    hb_priority_queue_t<combined_gain_idx_tuple_t> queue (std::move (queue_items));
   1981 
   1982    hb_bit_set_t removed_todo_idxes;
   1983    while (queue)
   1984    {
   1985      auto t = queue.pop_minimum ().first;
   1986      unsigned i = t.idx_1 ();
   1987      unsigned j = t.idx_2 ();
   1988 
   1989      if (removed_todo_idxes.has (i) || removed_todo_idxes.has (j))
   1990        continue;
   1991 
   1992      delta_row_encoding_t& encoding = encoding_objs.arrayZ[i];
   1993      delta_row_encoding_t& other_encoding = encoding_objs.arrayZ[j];
   1994 
   1995      removed_todo_idxes.add (i);
   1996      removed_todo_idxes.add (j);
   1997 
   1998      encoding.merge (other_encoding);
   1999 
   2000      for (unsigned idx = 0; idx < encoding_objs.length; idx++)
   2001      {
   2002        if (removed_todo_idxes.has (idx)) continue;
   2003 
   2004        const delta_row_encoding_t& obj = encoding_objs.arrayZ[idx];
   2005 // In the unlikely event that the same encoding exists already, combine it.
   2006        if (obj.width == encoding.width && obj.chars == encoding.chars)
   2007        {
   2008   // This is straight port from fonttools algorithm. I added this branch there
   2009   // because I thought it can happen. But looks like we never get in here in
   2010   // practice. I'm not confident enough to remove it though; in theory it can
   2011   // happen. I think it's just that our tests are not extensive enough to hit
   2012   // this path.
   2013 
   2014          for (const auto& row : obj.items)
   2015            encoding.add_row (row);
   2016 
   2017          removed_todo_idxes.add (idx);
   2018          continue;
   2019        }
   2020 
   2021        int combined_gain = encoding.gain_from_merging (obj);
   2022        if (combined_gain > 0)
   2023          queue.insert (combined_gain_idx_tuple_t (combined_gain, idx, encoding_objs.length), 0);
   2024      }
   2025 
   2026      auto moved_encoding = std::move (encoding);
   2027      encoding_objs.push (moved_encoding);
   2028    }
   2029 
   2030    int num_final_encodings = (int) encoding_objs.length - (int) removed_todo_idxes.get_population ();
   2031    if (num_final_encodings <= 0) return false;
   2032 
   2033    if (!encodings.alloc (num_final_encodings)) return false;
   2034    for (unsigned i = 0; i < encoding_objs.length; i++)
   2035    {
   2036      if (removed_todo_idxes.has (i)) continue;
   2037      encodings.push (std::move (encoding_objs.arrayZ[i]));
   2038    }
   2039 
   2040    return compile_varidx_map (front_mapping);
   2041  }
   2042 
   2043  private:
   2044  /* compile varidx_map for one VarData subtable (index specified by major) */
   2045  bool compile_varidx_map (const hb_hashmap_t<unsigned, const hb_vector_t<int>*>& front_mapping)
   2046  {
   2047    /* full encoding_row -> new VarIdxes mapping */
   2048    hb_hashmap_t<const hb_vector_t<int>*, unsigned> back_mapping;
   2049 
   2050    for (unsigned major = 0; major < encodings.length; major++)
   2051    {
   2052      delta_row_encoding_t& encoding = encodings[major];
   2053      /* just sanity check, this shouldn't happen */
   2054      if (encoding.is_empty ())
   2055        return false;
   2056 
   2057      unsigned num_rows = encoding.items.length;
   2058 
   2059      /* sort rows, make result deterministic */
   2060      encoding.items.qsort (_cmp_row);
   2061 
   2062      /* compile old to new var_idxes mapping */
   2063      for (unsigned minor = 0; minor < num_rows; minor++)
   2064      {
   2065        unsigned new_varidx = (major << 16) + minor;
   2066        back_mapping.set (encoding.items.arrayZ[minor], new_varidx);
   2067      }
   2068    }
   2069 
   2070    for (auto _ : front_mapping.iter ())
   2071    {
   2072      unsigned old_varidx = _.first;
   2073      unsigned *new_varidx;
   2074      if (back_mapping.has (_.second, &new_varidx))
   2075        varidx_map.set (old_varidx, *new_varidx);
   2076      else
   2077        varidx_map.set (old_varidx, HB_OT_LAYOUT_NO_VARIATIONS_INDEX);
   2078    }
   2079    return !varidx_map.in_error ();
   2080  }
   2081 
   2082  static int _cmp_row (const void *pa, const void *pb)
   2083  {
   2084    /* compare pointers of vectors(const hb_vector_t<int>*) that represent a row */
   2085    const hb_vector_t<int>** a = (const hb_vector_t<int>**) pa;
   2086    const hb_vector_t<int>** b = (const hb_vector_t<int>**) pb;
   2087 
   2088    for (unsigned i = 0; i < (*b)->length; i++)
   2089    {
   2090      int va = (*a)->arrayZ[i];
   2091      int vb = (*b)->arrayZ[i];
   2092      if (va != vb)
   2093        return va < vb ? -1 : 1;
   2094    }
   2095    return 0;
   2096  }
   2097 };
   2098 
   2099 
   2100 } /* namespace OT */
   2101 
   2102 
   2103 #endif /* HB_OT_VAR_COMMON_HH */