tor-browser

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

hb-subset-table.hh (6944B)


      1 /*
      2 * Copyright © 2018  Google, Inc.
      3 *
      4 *  This is part of HarfBuzz, a text shaping library.
      5 *
      6 * Permission is hereby granted, without written agreement and without
      7 * license or royalty fees, to use, copy, modify, and distribute this
      8 * software and its documentation for any purpose, provided that the
      9 * above copyright notice and the following two paragraphs appear in
     10 * all copies of this software.
     11 *
     12 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
     13 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
     14 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
     15 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
     16 * DAMAGE.
     17 *
     18 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
     19 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
     20 * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
     21 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
     22 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
     23 *
     24 * Google Author(s): Garret Rieger, Roderick Sheeter
     25 */
     26 
     27 #ifndef HB_SUBSET_TABLE_HH
     28 #define HB_SUBSET_TABLE_HH
     29 
     30 
     31 #include "hb.hh"
     32 
     33 #include "hb-subset.hh"
     34 #include "hb-repacker.hh"
     35 
     36 
     37 template<typename TableType>
     38 static bool
     39 _hb_subset_table_try (const TableType *table,
     40 	      hb_vector_t<char>* buf,
     41 	      hb_subset_context_t* c /* OUT */)
     42 {
     43  c->serializer->start_serialize ();
     44  if (c->serializer->in_error ()) return false;
     45 
     46  bool needed = table->subset (c);
     47  if (!c->serializer->ran_out_of_room ())
     48  {
     49    c->serializer->end_serialize ();
     50    return needed;
     51  }
     52 
     53  unsigned buf_size = buf->allocated;
     54  buf_size = buf_size * 2 + 16;
     55 
     56 
     57 
     58 
     59  DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c ran out of room; reallocating to %u bytes.",
     60             HB_UNTAG (c->table_tag), buf_size);
     61 
     62  if (unlikely (buf_size > c->source_blob->length * 256 ||
     63 	!buf->alloc_exact (buf_size)))
     64  {
     65    DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c failed to reallocate %u bytes.",
     66               HB_UNTAG (c->table_tag), buf_size);
     67    return needed;
     68  }
     69 
     70  c->serializer->reset (buf->arrayZ, buf->allocated);
     71  return _hb_subset_table_try (table, buf, c);
     72 }
     73 
     74 static HB_UNUSED unsigned
     75 _hb_subset_estimate_table_size (hb_subset_plan_t *plan,
     76 			unsigned table_len,
     77 			hb_tag_t table_tag)
     78 {
     79  unsigned src_glyphs = plan->source->get_num_glyphs ();
     80  unsigned dst_glyphs = plan->glyphset ()->get_population ();
     81 
     82  unsigned bulk = 8192;
     83  /* Tables that we want to allocate same space as the source table. For GSUB/GPOS it's
     84   * because those are expensive to subset, so giving them more room is fine. */
     85  bool same_size = table_tag == HB_TAG('G','S','U','B') ||
     86 	   table_tag == HB_TAG('G','P','O','S') ||
     87 	   table_tag == HB_TAG('G','D','E','F') ||
     88 	   table_tag == HB_TAG('n','a','m','e');
     89 
     90  if (plan->flags & HB_SUBSET_FLAGS_RETAIN_GIDS)
     91  {
     92    if (table_tag == HB_TAG('C','F','F',' '))
     93    {
     94      /* Add some extra room for the CFF charset. */
     95      bulk += src_glyphs * 16;
     96    }
     97    else if (table_tag == HB_TAG('C','F','F','2'))
     98    {
     99      /* Just extra CharString offsets. */
    100      bulk += src_glyphs * 4;
    101    }
    102  }
    103 
    104  if (unlikely (!src_glyphs) || same_size)
    105    return bulk + table_len;
    106 
    107  return bulk + (unsigned) (table_len * sqrt ((double) dst_glyphs / src_glyphs));
    108 }
    109 
    110 /*
    111 * Repack the serialization buffer if any offset overflows exist.
    112 */
    113 static HB_UNUSED hb_blob_t*
    114 _hb_subset_repack (hb_tag_t tag, const hb_serialize_context_t& c)
    115 {
    116  if (!c.offset_overflow ())
    117    return c.copy_blob ();
    118 
    119  hb_blob_t* result = hb_resolve_overflows (c.object_graph (), tag);
    120 
    121  if (unlikely (!result))
    122  {
    123    DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c offset overflow resolution failed.",
    124               HB_UNTAG (tag));
    125    return nullptr;
    126  }
    127 
    128  return result;
    129 }
    130 
    131 template <typename T>
    132 static HB_UNUSED auto _hb_do_destroy (T &t, hb_priority<1>) HB_RETURN (void, t.destroy ())
    133 
    134 template <typename T>
    135 static HB_UNUSED void _hb_do_destroy (T &t, hb_priority<0>) {}
    136 
    137 template<typename TableType>
    138 static bool
    139 _hb_subset_table (hb_subset_plan_t *plan, hb_vector_t<char> &buf)
    140 {
    141  auto &&source_blob = plan->source_table<TableType> ();
    142  auto *table = source_blob.get ();
    143 
    144  hb_tag_t tag = TableType::tableTag;
    145  hb_blob_t *blob = source_blob.get_blob();
    146  if (unlikely (!blob || !blob->data))
    147  {
    148    DEBUG_MSG (SUBSET, nullptr,
    149               "OT::%c%c%c%c::subset sanitize failed on source table.", HB_UNTAG (tag));
    150    _hb_do_destroy (source_blob, hb_prioritize);
    151    return false;
    152  }
    153 
    154  unsigned buf_size = _hb_subset_estimate_table_size (plan, blob->length, TableType::tableTag);
    155  DEBUG_MSG (SUBSET, nullptr,
    156             "OT::%c%c%c%c initial estimated table size: %u bytes.", HB_UNTAG (tag), buf_size);
    157  if (unlikely (!buf.alloc (buf_size)))
    158  {
    159    DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c failed to allocate %u bytes.", HB_UNTAG (tag), buf_size);
    160    _hb_do_destroy (source_blob, hb_prioritize);
    161    return false;
    162  }
    163 
    164  bool needed = false;
    165  hb_serialize_context_t serializer (buf.arrayZ, buf.allocated);
    166  {
    167    hb_subset_context_t c (blob, plan, &serializer, tag);
    168    needed = _hb_subset_table_try (table, &buf, &c);
    169  }
    170  _hb_do_destroy (source_blob, hb_prioritize);
    171 
    172  if (serializer.in_error () && !serializer.only_offset_overflow ())
    173  {
    174    DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c::subset FAILED!", HB_UNTAG (tag));
    175    return false;
    176  }
    177 
    178  if (!needed)
    179  {
    180    DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c::subset table subsetted to empty.", HB_UNTAG (tag));
    181    return true;
    182  }
    183 
    184  bool result = false;
    185  hb_blob_t *dest_blob = _hb_subset_repack (tag, serializer);
    186  if (dest_blob)
    187  {
    188    DEBUG_MSG (SUBSET, nullptr,
    189               "OT::%c%c%c%c final subset table size: %u bytes.",
    190               HB_UNTAG (tag), dest_blob->length);
    191    result = plan->add_table (tag, dest_blob);
    192    hb_blob_destroy (dest_blob);
    193  }
    194 
    195  DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c::subset %s",
    196             HB_UNTAG (tag), result ? "success" : "FAILED!");
    197  return result;
    198 }
    199 
    200 static HB_UNUSED bool
    201 _hb_subset_table_passthrough (hb_subset_plan_t *plan, hb_tag_t tag)
    202 {
    203  hb_blob_t *source_table = hb_face_reference_table (plan->source, tag);
    204  bool result = plan->add_table (tag, source_table);
    205  hb_blob_destroy (source_table);
    206  return result;
    207 }
    208 
    209 
    210 HB_INTERNAL bool _hb_subset_table_layout	(hb_subset_plan_t *plan, hb_vector_t<char> &buf, hb_tag_t tag, bool *success);
    211 HB_INTERNAL bool _hb_subset_table_var		(hb_subset_plan_t *plan, hb_vector_t<char> &buf, hb_tag_t tag, bool *success);
    212 HB_INTERNAL bool _hb_subset_table_cff		(hb_subset_plan_t *plan, hb_vector_t<char> &buf, hb_tag_t tag, bool *success);
    213 HB_INTERNAL bool _hb_subset_table_color		(hb_subset_plan_t *plan, hb_vector_t<char> &buf, hb_tag_t tag, bool *success);
    214 HB_INTERNAL bool _hb_subset_table_other		(hb_subset_plan_t *plan, hb_vector_t<char> &buf, hb_tag_t tag, bool *success);
    215 
    216 
    217 #endif /* HB_SUBSET_TABLE_HH */