tor-browser

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

hb-subset-cff-common.cc (6730B)


      1 /*
      2 * Copyright © 2018 Adobe 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 * Adobe Author(s): Michiharu Ariza
     25 */
     26 
     27 #include "hb.hh"
     28 
     29 #ifndef HB_NO_SUBSET_CFF
     30 
     31 #include "hb-ot-cff-common.hh"
     32 #include "hb-ot-cff2-table.hh"
     33 #include "hb-subset-cff-common.hh"
     34 
     35 /* Disable FDSelect format 0 for compatibility with fonttools which doesn't seem choose it.
     36 * Rarely any/much smaller than format 3 anyway. */
     37 #define CFF_SERIALIZE_FDSELECT_0  0
     38 
     39 using namespace CFF;
     40 
     41 
     42 /* Determine an optimal FDSelect format according to a provided plan.
     43 *
     44 * Return value: FDSelect format, size, and ranges for the most compact subset FDSelect
     45 * along with a font index remapping table
     46 */
     47 
     48 bool
     49 hb_plan_subset_cff_fdselect (const hb_subset_plan_t *plan,
     50 		     unsigned int fdCount,
     51 		     const FDSelect &src, /* IN */
     52 		     unsigned int &subset_fd_count /* OUT */,
     53 		     unsigned int &subset_fdselect_size /* OUT */,
     54 		     unsigned int &subset_fdselect_format /* OUT */,
     55 		     hb_vector_t<code_pair_t> &fdselect_ranges /* OUT */,
     56 		     hb_inc_bimap_t &fdmap /* OUT */)
     57 {
     58  subset_fd_count = 0;
     59  subset_fdselect_size = 0;
     60  subset_fdselect_format = 0;
     61  unsigned int num_ranges = 0;
     62 
     63  unsigned int subset_num_glyphs = plan->num_output_glyphs ();
     64  if (subset_num_glyphs == 0)
     65    return true;
     66 
     67  {
     68    /* use hb_set to determine the subset of font dicts */
     69    hb_set_t set;
     70    hb_codepoint_t prev_fd = CFF_UNDEF_CODE;
     71    hb_pair_t<unsigned, hb_codepoint_t> last_range {0, 0};
     72    auto it = hb_iter (plan->new_to_old_gid_list);
     73    auto _ = *it;
     74    for (hb_codepoint_t gid = 0; gid < subset_num_glyphs; gid++)
     75    {
     76      hb_codepoint_t old_glyph;
     77      if (gid == _.first)
     78      {
     79 old_glyph = _.second;
     80 _ = *++it;
     81      }
     82      else
     83      {
     84 /* fonttools retains FDSelect & font dicts for missing glyphs. do the same */
     85 old_glyph = gid;
     86      }
     87      if (old_glyph >= last_range.second)
     88 last_range = src.get_fd_range (old_glyph);
     89      unsigned fd = last_range.first;
     90 
     91      if (fd != prev_fd)
     92      {
     93 set.add (fd);
     94 num_ranges++;
     95 prev_fd = fd;
     96 fdselect_ranges.push (code_pair_t { fd, gid });
     97 
     98 if (gid == old_glyph)
     99   gid = hb_min (_.first - 1, last_range.second - 1);
    100      }
    101    }
    102 
    103    subset_fd_count = set.get_population ();
    104    if (subset_fd_count == fdCount)
    105    {
    106      /* all font dicts belong to the subset. no need to subset FDSelect & FDArray */
    107      fdmap.identity (fdCount);
    108    }
    109    else
    110    {
    111      /* create a fdmap */
    112      fdmap.reset ();
    113 
    114      hb_codepoint_t fd = CFF_UNDEF_CODE;
    115      while (set.next (&fd))
    116 fdmap.add (fd);
    117      if (unlikely (fdmap.get_population () != subset_fd_count))
    118 return false;
    119    }
    120 
    121    /* update each font dict index stored as "code" in fdselect_ranges */
    122    for (unsigned int i = 0; i < fdselect_ranges.length; i++)
    123      fdselect_ranges[i].code = fdmap[fdselect_ranges[i].code];
    124  }
    125 
    126  /* determine which FDSelect format is most compact */
    127  if (subset_fd_count > 0xFF)
    128  {
    129    if (unlikely (src.format != 4))
    130      return false;
    131    subset_fdselect_format = 4;
    132    subset_fdselect_size = FDSelect::min_size + FDSelect4::min_size + FDSelect4_Range::static_size * num_ranges + HBUINT32::static_size;
    133  }
    134  else
    135  {
    136 #if CFF_SERIALIZE_FDSELECT_0
    137    unsigned int format0_size = FDSelect::min_size + FDSelect0::min_size + HBUINT8::static_size * subset_num_glyphs;
    138 #endif
    139    unsigned int format3_size = FDSelect::min_size + FDSelect3::min_size + FDSelect3_Range::static_size * num_ranges + HBUINT16::static_size;
    140 
    141 #if CFF_SERIALIZE_FDSELECT_0
    142    if (format0_size <= format3_size)
    143    {
    144      // subset_fdselect_format = 0;
    145      subset_fdselect_size = format0_size;
    146    }
    147    else
    148 #endif
    149    {
    150      subset_fdselect_format = 3;
    151      subset_fdselect_size = format3_size;
    152    }
    153  }
    154 
    155  return true;
    156 }
    157 
    158 template <typename FDSELECT3_4>
    159 static inline bool
    160 serialize_fdselect_3_4 (hb_serialize_context_t *c,
    161 		const unsigned int num_glyphs,
    162 		const FDSelect &src,
    163 		unsigned int size,
    164 		const hb_vector_t<code_pair_t> &fdselect_ranges)
    165 {
    166  TRACE_SERIALIZE (this);
    167  FDSELECT3_4 *p = c->allocate_size<FDSELECT3_4> (size);
    168  if (unlikely (!p)) return_trace (false);
    169  p->nRanges () = fdselect_ranges.length;
    170  for (unsigned int i = 0; i < fdselect_ranges.length; i++)
    171  {
    172    p->ranges[i].first = fdselect_ranges[i].glyph;
    173    p->ranges[i].fd = fdselect_ranges[i].code;
    174  }
    175  p->sentinel () = num_glyphs;
    176  return_trace (true);
    177 }
    178 
    179 /* Serialize a subset FDSelect format planned above. */
    180 bool
    181 hb_serialize_cff_fdselect (hb_serialize_context_t *c,
    182 		   const unsigned int num_glyphs,
    183 		   const FDSelect &src,
    184 		   unsigned int fd_count,
    185 		   unsigned int fdselect_format,
    186 		   unsigned int size,
    187 		   const hb_vector_t<code_pair_t> &fdselect_ranges)
    188 {
    189  TRACE_SERIALIZE (this);
    190  FDSelect *p = c->allocate_min<FDSelect> ();
    191  if (unlikely (!p)) return_trace (false);
    192  p->format = fdselect_format;
    193  size -= FDSelect::min_size;
    194 
    195  switch (fdselect_format)
    196  {
    197 #if CFF_SERIALIZE_FDSELECT_0
    198  case 0:
    199  {
    200    FDSelect0 *p = c->allocate_size<FDSelect0> (size);
    201    if (unlikely (!p)) return_trace (false);
    202    unsigned int range_index = 0;
    203    unsigned int fd = fdselect_ranges[range_index++].code;
    204    for (unsigned int i = 0; i < num_glyphs; i++)
    205    {
    206      if ((range_index < fdselect_ranges.len) &&
    207   (i >= fdselect_ranges[range_index].glyph))
    208      {
    209 fd = fdselect_ranges[range_index++].code;
    210      }
    211      p->fds[i] = fd;
    212    }
    213    return_trace (true);
    214  }
    215 #endif /* CFF_SERIALIZE_FDSELECT_0 */
    216 
    217  case 3:
    218    return serialize_fdselect_3_4<FDSelect3> (c, num_glyphs, src,
    219 				      size, fdselect_ranges);
    220 
    221  case 4:
    222    return serialize_fdselect_3_4<FDSelect4> (c, num_glyphs, src,
    223 				      size, fdselect_ranges);
    224 
    225  default:
    226    return_trace (false);
    227  }
    228 }
    229 
    230 
    231 #endif