Coverage Report

Created: 2023-11-19 07:21

/src/harfbuzz/src/hb-subset-cff-common.hh
Line
Count
Source (jump to first uncovered line)
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
#ifndef HB_SUBSET_CFF_COMMON_HH
28
#define HB_SUBSET_CFF_COMMON_HH
29
30
#include "hb.hh"
31
32
#include "hb-subset-plan.hh"
33
#include "hb-cff-interp-cs-common.hh"
34
35
namespace CFF {
36
37
/* Used for writing a temporary charstring */
38
struct str_encoder_t
39
{
40
  str_encoder_t (str_buff_t &buff_)
41
70.7k
    : buff (buff_) {}
42
43
5.09k
  void reset () { buff.reset (); }
44
45
  void encode_byte (unsigned char b)
46
112k
  {
47
112k
    if (likely ((signed) buff.length < buff.allocated))
48
105k
      buff.arrayZ[buff.length++] = b;
49
6.32k
    else
50
6.32k
      buff.push (b);
51
112k
  }
52
53
  void encode_int (int v)
54
67.0k
  {
55
67.0k
    if ((-1131 <= v) && (v <= 1131))
56
66.6k
    {
57
66.6k
      if ((-107 <= v) && (v <= 107))
58
61.7k
  encode_byte (v + 139);
59
4.86k
      else if (v > 0)
60
2.48k
      {
61
2.48k
  v -= 108;
62
2.48k
  encode_byte ((v >> 8) + OpCode_TwoBytePosInt0);
63
2.48k
  encode_byte (v & 0xFF);
64
2.48k
      }
65
2.37k
      else
66
2.37k
      {
67
2.37k
  v = -v - 108;
68
2.37k
  encode_byte ((v >> 8) + OpCode_TwoByteNegInt0);
69
2.37k
  encode_byte (v & 0xFF);
70
2.37k
      }
71
66.6k
    }
72
452
    else
73
452
    {
74
452
      if (unlikely (v < -32768))
75
0
  v = -32768;
76
452
      else if (unlikely (v > 32767))
77
0
  v = 32767;
78
452
      encode_byte (OpCode_shortint);
79
452
      encode_byte ((v >> 8) & 0xFF);
80
452
      encode_byte (v & 0xFF);
81
452
    }
82
67.0k
  }
83
84
  // Encode number for CharString
85
  void encode_num_cs (const number_t& n)
86
65.0k
  {
87
65.0k
    if (n.in_int_range ())
88
62.2k
    {
89
62.2k
      encode_int (n.to_int ());
90
62.2k
    }
91
2.77k
    else
92
2.77k
    {
93
2.77k
      int32_t v = n.to_fixed ();
94
2.77k
      encode_byte (OpCode_fixedcs);
95
2.77k
      encode_byte ((v >> 24) & 0xFF);
96
2.77k
      encode_byte ((v >> 16) & 0xFF);
97
2.77k
      encode_byte ((v >> 8) & 0xFF);
98
2.77k
      encode_byte (v & 0xFF);
99
2.77k
    }
100
65.0k
  }
101
102
  // Encode number for TopDict / Private
103
  void encode_num_tp (const number_t& n)
104
0
  {
105
0
    if (n.in_int_range ())
106
0
    {
107
      // TODO longint
108
0
      encode_int (n.to_int ());
109
0
    }
110
0
    else
111
0
    {
112
      // Sigh. BCD
113
      // https://learn.microsoft.com/en-us/typography/opentype/spec/cff2#table-5-nibble-definitions
114
0
      double v = n.to_real ();
115
0
      encode_byte (OpCode_BCD);
116
117
      // Based on:
118
      // https://github.com/fonttools/fonttools/blob/97ed3a61cde03e17b8be36f866192fbd56f1d1a7/Lib/fontTools/misc/psCharStrings.py#L265-L294
119
120
0
      char buf[16];
121
      /* FontTools has the following comment:
122
       *
123
       * # Note: 14 decimal digits seems to be the limitation for CFF real numbers
124
       * # in macOS. However, we use 8 here to match the implementation of AFDKO.
125
       *
126
       * We use 8 here to match FontTools X-).
127
       */
128
129
0
      hb_locale_t clocale HB_UNUSED;
130
0
      hb_locale_t oldlocale HB_UNUSED;
131
0
      oldlocale = hb_uselocale (clocale = newlocale (LC_ALL_MASK, "C", NULL));
132
0
      snprintf (buf, sizeof (buf), "%.8G", v);
133
0
      (void) hb_uselocale (((void) freelocale (clocale), oldlocale));
134
135
0
      char *s = buf;
136
0
      if (s[0] == '0' && s[1] == '.')
137
0
  s++;
138
0
      else if (s[0] == '-' && s[1] == '0' && s[2] == '.')
139
0
      {
140
0
  s[1] = '-';
141
0
  s++;
142
0
      }
143
0
      hb_vector_t<char> nibbles;
144
0
      while (*s)
145
0
      {
146
0
  char c = s[0];
147
0
  s++;
148
149
0
  switch (c)
150
0
  {
151
0
    case 'E':
152
0
    {
153
0
      char c2 = *s;
154
0
      if (c2 == '-')
155
0
      {
156
0
        s++;
157
0
        nibbles.push (0x0C); // E-
158
0
        continue;
159
0
      }
160
0
      if (c2 == '+')
161
0
        s++;
162
0
      nibbles.push (0x0B); // E
163
0
      continue;
164
0
    }
165
166
0
    case '.': case ',': // Comma for some European locales in case no uselocale available.
167
0
      nibbles.push (0x0A); // .
168
0
      continue;
169
170
0
    case '-':
171
0
      nibbles.push (0x0E); // .
172
0
      continue;
173
0
  }
174
175
0
  nibbles.push (c - '0');
176
0
      }
177
0
      nibbles.push (0x0F);
178
0
      if (nibbles.length % 2)
179
0
  nibbles.push (0x0F);
180
181
0
      unsigned count = nibbles.length;
182
0
      for (unsigned i = 0; i < count; i += 2)
183
0
        encode_byte ((nibbles[i] << 4) | nibbles[i+1]);
184
0
    }
185
0
  }
Unexecuted instantiation: CFF::str_encoder_t::encode_num_tp(CFF::number_t const&)
Unexecuted instantiation: CFF::str_encoder_t::encode_num_tp(CFF::number_t const&)
186
187
  void encode_op (op_code_t op)
188
22.7k
  {
189
22.7k
    if (Is_OpCode_ESC (op))
190
1.24k
    {
191
1.24k
      encode_byte (OpCode_escape);
192
1.24k
      encode_byte (Unmake_OpCode_ESC (op));
193
1.24k
    }
194
21.5k
    else
195
21.5k
      encode_byte (op);
196
22.7k
  }
197
198
  void copy_str (const unsigned char *str, unsigned length)
199
41.4k
  {
200
41.4k
    assert ((signed) (buff.length + length) <= buff.allocated);
201
0
    hb_memcpy (buff.arrayZ + buff.length, str, length);
202
41.4k
    buff.length += length;
203
41.4k
  }
204
205
5.08k
  bool in_error () const { return buff.in_error (); }
206
207
  protected:
208
209
  str_buff_t &buff;
210
};
211
212
struct cff_sub_table_info_t {
213
  cff_sub_table_info_t ()
214
    : fd_array_link (0),
215
      char_strings_link (0)
216
2.35k
  {
217
2.35k
    fd_select.init ();
218
2.35k
  }
219
220
  table_info_t     fd_select;
221
  objidx_t         fd_array_link;
222
  objidx_t         char_strings_link;
223
};
224
225
template <typename OPSTR=op_str_t>
226
struct cff_top_dict_op_serializer_t : op_serializer_t
227
{
228
  bool serialize (hb_serialize_context_t *c,
229
      const OPSTR &opstr,
230
      const cff_sub_table_info_t &info) const
231
3.27k
  {
232
3.27k
    TRACE_SERIALIZE (this);
233
234
3.27k
    switch (opstr.op)
235
3.27k
    {
236
1.16k
      case OpCode_CharStrings:
237
1.16k
  return_trace (FontDict::serialize_link4_op(c, opstr.op, info.char_strings_link, whence_t::Absolute));
238
239
646
      case OpCode_FDArray:
240
646
  return_trace (FontDict::serialize_link4_op(c, opstr.op, info.fd_array_link, whence_t::Absolute));
241
242
142
      case OpCode_FDSelect:
243
142
  return_trace (FontDict::serialize_link4_op(c, opstr.op, info.fd_select.link, whence_t::Absolute));
244
245
1.32k
      default:
246
1.32k
  return_trace (copy_opstr (c, opstr));
247
3.27k
    }
248
3.27k
    return_trace (true);
249
3.27k
  }
CFF::cff_top_dict_op_serializer_t<CFF::cff1_top_dict_val_t>::serialize(hb_serialize_context_t*, CFF::cff1_top_dict_val_t const&, CFF::cff_sub_table_info_t const&) const
Line
Count
Source
231
1.78k
  {
232
1.78k
    TRACE_SERIALIZE (this);
233
234
1.78k
    switch (opstr.op)
235
1.78k
    {
236
606
      case OpCode_CharStrings:
237
606
  return_trace (FontDict::serialize_link4_op(c, opstr.op, info.char_strings_link, whence_t::Absolute));
238
239
87
      case OpCode_FDArray:
240
87
  return_trace (FontDict::serialize_link4_op(c, opstr.op, info.fd_array_link, whence_t::Absolute));
241
242
94
      case OpCode_FDSelect:
243
94
  return_trace (FontDict::serialize_link4_op(c, opstr.op, info.fd_select.link, whence_t::Absolute));
244
245
994
      default:
246
994
  return_trace (copy_opstr (c, opstr));
247
1.78k
    }
248
0
    return_trace (true);
249
1.78k
  }
CFF::cff_top_dict_op_serializer_t<CFF::op_str_t>::serialize(hb_serialize_context_t*, CFF::op_str_t const&, CFF::cff_sub_table_info_t const&) const
Line
Count
Source
231
1.49k
  {
232
1.49k
    TRACE_SERIALIZE (this);
233
234
1.49k
    switch (opstr.op)
235
1.49k
    {
236
559
      case OpCode_CharStrings:
237
559
  return_trace (FontDict::serialize_link4_op(c, opstr.op, info.char_strings_link, whence_t::Absolute));
238
239
559
      case OpCode_FDArray:
240
559
  return_trace (FontDict::serialize_link4_op(c, opstr.op, info.fd_array_link, whence_t::Absolute));
241
242
48
      case OpCode_FDSelect:
243
48
  return_trace (FontDict::serialize_link4_op(c, opstr.op, info.fd_select.link, whence_t::Absolute));
244
245
330
      default:
246
330
  return_trace (copy_opstr (c, opstr));
247
1.49k
    }
248
0
    return_trace (true);
249
1.49k
  }
250
};
251
252
struct cff_font_dict_op_serializer_t : op_serializer_t
253
{
254
  bool serialize (hb_serialize_context_t *c,
255
      const op_str_t &opstr,
256
      const table_info_t &privateDictInfo) const
257
713
  {
258
713
    TRACE_SERIALIZE (this);
259
260
713
    if (opstr.op == OpCode_Private)
261
703
    {
262
      /* serialize the private dict size & offset as 2-byte & 4-byte integers */
263
703
      return_trace (UnsizedByteStr::serialize_int2 (c, privateDictInfo.size) &&
264
703
        Dict::serialize_link4_op (c, opstr.op, privateDictInfo.link, whence_t::Absolute));
265
703
    }
266
10
    else
267
10
    {
268
10
      unsigned char *d = c->allocate_size<unsigned char> (opstr.length);
269
10
      if (unlikely (!d)) return_trace (false);
270
      /* Faster than hb_memcpy for small strings. */
271
82
      for (unsigned i = 0; i < opstr.length; i++)
272
73
  d[i] = opstr.ptr[i];
273
      //hb_memcpy (d, opstr.ptr, opstr.length);
274
9
    }
275
713
    return_trace (true);
276
713
  }
277
};
278
279
struct flatten_param_t
280
{
281
  str_buff_t     &flatStr;
282
  bool  drop_hints;
283
  const hb_subset_plan_t *plan;
284
};
285
286
template <typename ACC, typename ENV, typename OPSET, op_code_t endchar_op=OpCode_Invalid>
287
struct subr_flattener_t
288
{
289
  subr_flattener_t (const ACC &acc_,
290
        const hb_subset_plan_t *plan_)
291
534
       : acc (acc_), plan (plan_) {}
CFF::subr_flattener_t<OT::cff1::accelerator_subset_t const, CFF::cff1_cs_interp_env_t, cff1_cs_opset_flatten_t, 14u>::subr_flattener_t(OT::cff1::accelerator_subset_t const&, hb_subset_plan_t const*)
Line
Count
Source
291
260
       : acc (acc_), plan (plan_) {}
CFF::subr_flattener_t<OT::cff2::accelerator_subset_t const, CFF::cff2_cs_interp_env_t<CFF::blend_arg_t>, cff2_cs_opset_flatten_t, 65535u>::subr_flattener_t(OT::cff2::accelerator_subset_t const&, hb_subset_plan_t const*)
Line
Count
Source
291
274
       : acc (acc_), plan (plan_) {}
292
293
  bool flatten (str_buff_vec_t &flat_charstrings)
294
534
  {
295
534
    unsigned count = plan->num_output_glyphs ();
296
534
    if (!flat_charstrings.resize_exact (count))
297
3
      return false;
298
1.68k
    for (unsigned int i = 0; i < count; i++)
299
1.46k
    {
300
1.46k
      hb_codepoint_t  glyph;
301
1.46k
      if (!plan->old_gid_for_new_gid (i, &glyph))
302
765
      {
303
  /* add an endchar only charstring for a missing glyph if CFF1 */
304
765
  if (endchar_op != OpCode_Invalid) flat_charstrings[i].push (endchar_op);
305
765
  continue;
306
765
      }
307
701
      const hb_ubytes_t str = (*acc.charStrings)[glyph];
308
701
      unsigned int fd = acc.fdSelect->get_fd (glyph);
309
701
      if (unlikely (fd >= acc.fdCount))
310
7
  return false;
311
312
313
694
      ENV env (str, acc, fd,
314
694
         plan->normalized_coords.arrayZ, plan->normalized_coords.length);
315
694
      cs_interpreter_t<ENV, OPSET, flatten_param_t> interp (env);
316
694
      flatten_param_t  param = {
317
694
        flat_charstrings.arrayZ[i],
318
694
        (bool) (plan->flags & HB_SUBSET_FLAGS_NO_HINTING),
319
694
  plan
320
694
      };
321
694
      if (unlikely (!interp.interpret (param)))
322
307
  return false;
323
694
    }
324
217
    return true;
325
531
  }
CFF::subr_flattener_t<OT::cff1::accelerator_subset_t const, CFF::cff1_cs_interp_env_t, cff1_cs_opset_flatten_t, 14u>::flatten(hb_vector_t<hb_vector_t<unsigned char, false>, false>&)
Line
Count
Source
294
260
  {
295
260
    unsigned count = plan->num_output_glyphs ();
296
260
    if (!flat_charstrings.resize_exact (count))
297
3
      return false;
298
1.07k
    for (unsigned int i = 0; i < count; i++)
299
970
    {
300
970
      hb_codepoint_t  glyph;
301
970
      if (!plan->old_gid_for_new_gid (i, &glyph))
302
602
      {
303
  /* add an endchar only charstring for a missing glyph if CFF1 */
304
602
  if (endchar_op != OpCode_Invalid) flat_charstrings[i].push (endchar_op);
305
602
  continue;
306
602
      }
307
368
      const hb_ubytes_t str = (*acc.charStrings)[glyph];
308
368
      unsigned int fd = acc.fdSelect->get_fd (glyph);
309
368
      if (unlikely (fd >= acc.fdCount))
310
3
  return false;
311
312
313
365
      ENV env (str, acc, fd,
314
365
         plan->normalized_coords.arrayZ, plan->normalized_coords.length);
315
365
      cs_interpreter_t<ENV, OPSET, flatten_param_t> interp (env);
316
365
      flatten_param_t  param = {
317
365
        flat_charstrings.arrayZ[i],
318
365
        (bool) (plan->flags & HB_SUBSET_FLAGS_NO_HINTING),
319
365
  plan
320
365
      };
321
365
      if (unlikely (!interp.interpret (param)))
322
151
  return false;
323
365
    }
324
103
    return true;
325
257
  }
CFF::subr_flattener_t<OT::cff2::accelerator_subset_t const, CFF::cff2_cs_interp_env_t<CFF::blend_arg_t>, cff2_cs_opset_flatten_t, 65535u>::flatten(hb_vector_t<hb_vector_t<unsigned char, false>, false>&)
Line
Count
Source
294
274
  {
295
274
    unsigned count = plan->num_output_glyphs ();
296
274
    if (!flat_charstrings.resize_exact (count))
297
0
      return false;
298
610
    for (unsigned int i = 0; i < count; i++)
299
496
    {
300
496
      hb_codepoint_t  glyph;
301
496
      if (!plan->old_gid_for_new_gid (i, &glyph))
302
163
      {
303
  /* add an endchar only charstring for a missing glyph if CFF1 */
304
163
  if (endchar_op != OpCode_Invalid) flat_charstrings[i].push (endchar_op);
305
163
  continue;
306
163
      }
307
333
      const hb_ubytes_t str = (*acc.charStrings)[glyph];
308
333
      unsigned int fd = acc.fdSelect->get_fd (glyph);
309
333
      if (unlikely (fd >= acc.fdCount))
310
4
  return false;
311
312
313
329
      ENV env (str, acc, fd,
314
329
         plan->normalized_coords.arrayZ, plan->normalized_coords.length);
315
329
      cs_interpreter_t<ENV, OPSET, flatten_param_t> interp (env);
316
329
      flatten_param_t  param = {
317
329
        flat_charstrings.arrayZ[i],
318
329
        (bool) (plan->flags & HB_SUBSET_FLAGS_NO_HINTING),
319
329
  plan
320
329
      };
321
329
      if (unlikely (!interp.interpret (param)))
322
156
  return false;
323
329
    }
324
114
    return true;
325
274
  }
326
327
  const ACC &acc;
328
  const hb_subset_plan_t *plan;
329
};
330
331
struct subr_closures_t
332
{
333
  subr_closures_t (unsigned int fd_count) : global_closure (), local_closures ()
334
1.80k
  {
335
1.80k
    local_closures.resize_exact (fd_count);
336
1.80k
  }
337
338
  void reset ()
339
201
  {
340
201
    global_closure.clear();
341
442
    for (unsigned int i = 0; i < local_closures.length; i++)
342
241
      local_closures[i].clear();
343
201
  }
344
345
1.79k
  bool in_error () const { return local_closures.in_error (); }
346
  hb_set_t  global_closure;
347
  hb_vector_t<hb_set_t> local_closures;
348
};
349
350
struct parsed_cs_op_t : op_str_t
351
{
352
  parsed_cs_op_t (unsigned int subr_num_ = 0) :
353
195k
    subr_num (subr_num_) {}
354
355
201k
  bool is_hinting () const { return hinting_flag; }
356
5.82k
  void set_hinting ()       { hinting_flag = true; }
357
358
  /* The layout of this struct is designed to fit within the
359
   * padding of op_str_t! */
360
361
  protected:
362
  bool    hinting_flag = false;
363
364
  public:
365
  uint16_t subr_num;
366
};
367
368
struct parsed_cs_str_t : parsed_values_t<parsed_cs_op_t>
369
{
370
  parsed_cs_str_t () :
371
    parsed (false),
372
    hint_dropped (false),
373
    has_prefix_ (false),
374
    has_calls_ (false)
375
242k
  {
376
242k
    SUPER::init ();
377
242k
  }
378
379
  void add_op (op_code_t op, const byte_str_ref_t& str_ref)
380
263k
  {
381
263k
    if (!is_parsed ())
382
189k
      SUPER::add_op (op, str_ref);
383
263k
  }
384
385
  void add_call_op (op_code_t op, const byte_str_ref_t& str_ref, unsigned int subr_num)
386
6.90k
  {
387
6.90k
    if (!is_parsed ())
388
6.16k
    {
389
6.16k
      has_calls_ = true;
390
391
      /* Pop the subroutine number. */
392
6.16k
      values.pop ();
393
394
6.16k
      SUPER::add_op (op, str_ref, {subr_num});
395
6.16k
    }
396
6.90k
  }
397
398
  void set_prefix (const number_t &num, op_code_t op = OpCode_Invalid)
399
866
  {
400
866
    has_prefix_ = true;
401
866
    prefix_op_ = op;
402
866
    prefix_num_ = num;
403
866
  }
404
405
  bool at_end (unsigned int pos) const
406
916
  {
407
916
    return ((pos + 1 >= values.length) /* CFF2 */
408
916
  || (values[pos + 1].op == OpCode_return));
409
916
  }
410
411
289k
  bool is_parsed () const { return parsed; }
412
10.6k
  void set_parsed ()      { parsed = true; }
413
414
117
  bool is_hint_dropped () const { return hint_dropped; }
415
137
  void set_hint_dropped ()      { hint_dropped = true; }
416
417
0
  bool is_vsindex_dropped () const { return vsindex_dropped; }
418
1
  void set_vsindex_dropped ()      { vsindex_dropped = true; }
419
420
5.09k
  bool has_prefix () const          { return has_prefix_; }
421
46
  op_code_t prefix_op () const         { return prefix_op_; }
422
42
  const number_t &prefix_num () const { return prefix_num_; }
423
424
618
  bool has_calls () const          { return has_calls_; }
425
426
  void compact ()
427
2.90k
  {
428
2.90k
    unsigned count = values.length;
429
2.90k
    if (!count) return;
430
2.15k
    auto &opstr = values.arrayZ;
431
2.15k
    unsigned j = 0;
432
98.1k
    for (unsigned i = 1; i < count; i++)
433
95.9k
    {
434
      /* See if we can combine op j and op i. */
435
95.9k
      bool combine =
436
95.9k
        (opstr[j].op != OpCode_callsubr && opstr[j].op != OpCode_callgsubr) &&
437
95.9k
        (opstr[i].op != OpCode_callsubr && opstr[i].op != OpCode_callgsubr) &&
438
95.9k
        (opstr[j].is_hinting () == opstr[i].is_hinting ()) &&
439
95.9k
        (opstr[j].ptr + opstr[j].length == opstr[i].ptr) &&
440
95.9k
        (opstr[j].length + opstr[i].length <= 255);
441
442
95.9k
      if (combine)
443
91.2k
      {
444
91.2k
  opstr[j].length += opstr[i].length;
445
91.2k
  opstr[j].op = OpCode_Invalid;
446
91.2k
      }
447
4.72k
      else
448
4.72k
      {
449
4.72k
  opstr[++j] = opstr[i];
450
4.72k
      }
451
95.9k
    }
452
2.15k
    values.shrink (j + 1);
453
2.15k
  }
454
455
  protected:
456
  bool    parsed : 1;
457
  bool    hint_dropped : 1;
458
  bool    vsindex_dropped : 1;
459
  bool    has_prefix_ : 1;
460
  bool    has_calls_ : 1;
461
  op_code_t prefix_op_;
462
  number_t  prefix_num_;
463
464
  private:
465
  typedef parsed_values_t<parsed_cs_op_t> SUPER;
466
};
467
468
struct parsed_cs_str_vec_t : hb_vector_t<parsed_cs_str_t>
469
{
470
  private:
471
  typedef hb_vector_t<parsed_cs_str_t> SUPER;
472
};
473
474
struct cff_subset_accelerator_t
475
{
476
  static cff_subset_accelerator_t* create (
477
      hb_blob_t* original_blob,
478
      const parsed_cs_str_vec_t& parsed_charstrings,
479
      const parsed_cs_str_vec_t& parsed_global_subrs,
480
0
      const hb_vector_t<parsed_cs_str_vec_t>& parsed_local_subrs) {
481
0
    cff_subset_accelerator_t* accel =
482
0
        (cff_subset_accelerator_t*) hb_malloc (sizeof(cff_subset_accelerator_t));
483
0
    if (unlikely (!accel)) return nullptr;
484
0
    new (accel) cff_subset_accelerator_t (original_blob,
485
0
                                          parsed_charstrings,
486
0
                                          parsed_global_subrs,
487
0
                                          parsed_local_subrs);
488
0
    return accel;
489
0
  }
Unexecuted instantiation: CFF::cff_subset_accelerator_t::create(hb_blob_t*, CFF::parsed_cs_str_vec_t const&, CFF::parsed_cs_str_vec_t const&, hb_vector_t<CFF::parsed_cs_str_vec_t, false> const&)
Unexecuted instantiation: CFF::cff_subset_accelerator_t::create(hb_blob_t*, CFF::parsed_cs_str_vec_t const&, CFF::parsed_cs_str_vec_t const&, hb_vector_t<CFF::parsed_cs_str_vec_t, false> const&)
490
491
0
  static void destroy (void* value) {
492
0
    if (!value) return;
493
494
0
    cff_subset_accelerator_t* accel = (cff_subset_accelerator_t*) value;
495
0
    accel->~cff_subset_accelerator_t ();
496
0
    hb_free (accel);
497
0
  }
Unexecuted instantiation: CFF::cff_subset_accelerator_t::destroy(void*)
Unexecuted instantiation: CFF::cff_subset_accelerator_t::destroy(void*)
498
499
  cff_subset_accelerator_t(
500
      hb_blob_t* original_blob_,
501
      const parsed_cs_str_vec_t& parsed_charstrings_,
502
      const parsed_cs_str_vec_t& parsed_global_subrs_,
503
      const hb_vector_t<parsed_cs_str_vec_t>& parsed_local_subrs_)
504
0
  {
505
0
    parsed_charstrings = parsed_charstrings_;
506
0
    parsed_global_subrs = parsed_global_subrs_;
507
0
    parsed_local_subrs = parsed_local_subrs_;
508
0
509
0
    // the parsed charstrings point to memory in the original CFF table so we must hold a reference
510
0
    // to it to keep the memory valid.
511
0
    original_blob = hb_blob_reference (original_blob_);
512
0
  }
513
514
  ~cff_subset_accelerator_t()
515
0
  {
516
0
    hb_blob_destroy (original_blob);
517
0
    auto *mapping = glyph_to_sid_map.get_relaxed ();
518
0
    if (mapping)
519
0
    {
520
0
      mapping->~glyph_to_sid_map_t ();
521
0
      hb_free (mapping);
522
0
    }
523
0
  }
Unexecuted instantiation: CFF::cff_subset_accelerator_t::~cff_subset_accelerator_t()
Unexecuted instantiation: CFF::cff_subset_accelerator_t::~cff_subset_accelerator_t()
524
525
  parsed_cs_str_vec_t parsed_charstrings;
526
  parsed_cs_str_vec_t parsed_global_subrs;
527
  hb_vector_t<parsed_cs_str_vec_t> parsed_local_subrs;
528
  mutable hb_atomic_ptr_t<glyph_to_sid_map_t> glyph_to_sid_map;
529
530
 private:
531
  hb_blob_t* original_blob;
532
};
533
534
struct subr_subset_param_t
535
{
536
  subr_subset_param_t (parsed_cs_str_t *parsed_charstring_,
537
           parsed_cs_str_vec_t *parsed_global_subrs_,
538
           parsed_cs_str_vec_t *parsed_local_subrs_,
539
           hb_set_t *global_closure_,
540
           hb_set_t *local_closure_,
541
           bool drop_hints_) :
542
      current_parsed_str (parsed_charstring_),
543
      parsed_charstring (parsed_charstring_),
544
      parsed_global_subrs (parsed_global_subrs_),
545
      parsed_local_subrs (parsed_local_subrs_),
546
      global_closure (global_closure_),
547
      local_closure (local_closure_),
548
4.36k
      drop_hints (drop_hints_) {}
549
550
  parsed_cs_str_t *get_parsed_str_for_context (call_context_t &context)
551
13.1k
  {
552
13.1k
    switch (context.type)
553
13.1k
    {
554
3.25k
      case CSType_CharString:
555
3.25k
  return parsed_charstring;
556
557
7.19k
      case CSType_LocalSubr:
558
7.19k
  if (likely (context.subr_num < parsed_local_subrs->length))
559
7.19k
    return &(*parsed_local_subrs)[context.subr_num];
560
0
  break;
561
562
2.66k
      case CSType_GlobalSubr:
563
2.66k
  if (likely (context.subr_num < parsed_global_subrs->length))
564
2.66k
    return &(*parsed_global_subrs)[context.subr_num];
565
0
  break;
566
13.1k
    }
567
0
    return nullptr;
568
13.1k
  }
569
570
  template <typename ENV>
571
  void set_current_str (ENV &env, bool calling)
572
12.6k
  {
573
12.6k
    parsed_cs_str_t *parsed_str = get_parsed_str_for_context (env.context);
574
12.6k
    if (unlikely (!parsed_str))
575
0
    {
576
0
      env.set_error ();
577
0
      return;
578
0
    }
579
    /* If the called subroutine is parsed partially but not completely yet,
580
     * it must be because we are calling it recursively.
581
     * Handle it as an error. */
582
12.6k
    if (unlikely (calling && !parsed_str->is_parsed () && (parsed_str->values.length > 0)))
583
193
      env.set_error ();
584
12.4k
    else
585
12.4k
    {
586
12.4k
      if (!parsed_str->is_parsed ())
587
9.17k
        parsed_str->alloc (env.str_ref.total_size ());
588
12.4k
      current_parsed_str = parsed_str;
589
12.4k
    }
590
12.6k
  }
void CFF::subr_subset_param_t::set_current_str<CFF::cff1_cs_interp_env_t>(CFF::cff1_cs_interp_env_t&, bool)
Line
Count
Source
572
4.78k
  {
573
4.78k
    parsed_cs_str_t *parsed_str = get_parsed_str_for_context (env.context);
574
4.78k
    if (unlikely (!parsed_str))
575
0
    {
576
0
      env.set_error ();
577
0
      return;
578
0
    }
579
    /* If the called subroutine is parsed partially but not completely yet,
580
     * it must be because we are calling it recursively.
581
     * Handle it as an error. */
582
4.78k
    if (unlikely (calling && !parsed_str->is_parsed () && (parsed_str->values.length > 0)))
583
97
      env.set_error ();
584
4.68k
    else
585
4.68k
    {
586
4.68k
      if (!parsed_str->is_parsed ())
587
3.18k
        parsed_str->alloc (env.str_ref.total_size ());
588
4.68k
      current_parsed_str = parsed_str;
589
4.68k
    }
590
4.78k
  }
void CFF::subr_subset_param_t::set_current_str<CFF::cff2_cs_interp_env_t<CFF::blend_arg_t> >(CFF::cff2_cs_interp_env_t<CFF::blend_arg_t>&, bool)
Line
Count
Source
572
7.85k
  {
573
7.85k
    parsed_cs_str_t *parsed_str = get_parsed_str_for_context (env.context);
574
7.85k
    if (unlikely (!parsed_str))
575
0
    {
576
0
      env.set_error ();
577
0
      return;
578
0
    }
579
    /* If the called subroutine is parsed partially but not completely yet,
580
     * it must be because we are calling it recursively.
581
     * Handle it as an error. */
582
7.85k
    if (unlikely (calling && !parsed_str->is_parsed () && (parsed_str->values.length > 0)))
583
96
      env.set_error ();
584
7.76k
    else
585
7.76k
    {
586
7.76k
      if (!parsed_str->is_parsed ())
587
5.99k
        parsed_str->alloc (env.str_ref.total_size ());
588
7.76k
      current_parsed_str = parsed_str;
589
7.76k
    }
590
7.85k
  }
591
592
  parsed_cs_str_t *current_parsed_str;
593
594
  parsed_cs_str_t *parsed_charstring;
595
  parsed_cs_str_vec_t *parsed_global_subrs;
596
  parsed_cs_str_vec_t *parsed_local_subrs;
597
  hb_set_t      *global_closure;
598
  hb_set_t      *local_closure;
599
  bool    drop_hints;
600
};
601
602
struct subr_remap_t : hb_inc_bimap_t
603
{
604
  void create (const hb_set_t *closure)
605
4.79k
  {
606
    /* create a remapping of subroutine numbers from old to new.
607
     * no optimization based on usage counts. fonttools doesn't appear doing that either.
608
     */
609
610
4.79k
    alloc (closure->get_population ());
611
4.79k
    for (auto old_num : *closure)
612
2.66k
      add (old_num);
613
614
4.79k
    if (get_population () < 1240)
615
4.79k
      bias = 107;
616
0
    else if (get_population () < 33900)
617
0
      bias = 1131;
618
0
    else
619
0
      bias = 32768;
620
4.79k
  }
621
622
  int biased_num (unsigned int old_num) const
623
3.86k
  {
624
3.86k
    hb_codepoint_t new_num = get (old_num);
625
3.86k
    return (int)new_num - bias;
626
3.86k
  }
627
628
  protected:
629
  int bias;
630
};
631
632
struct subr_remaps_t
633
{
634
  subr_remaps_t (unsigned int fdCount)
635
1.80k
  {
636
1.80k
    local_remaps.resize (fdCount);
637
1.80k
  }
638
639
  bool in_error()
640
1.79k
  {
641
1.79k
    return local_remaps.in_error ();
642
1.79k
  }
643
644
  void create (subr_closures_t& closures)
645
1.00k
  {
646
1.00k
    global_remap.create (&closures.global_closure);
647
4.79k
    for (unsigned int i = 0; i < local_remaps.length; i++)
648
3.79k
      local_remaps.arrayZ[i].create (&closures.local_closures[i]);
649
1.00k
  }
650
651
  subr_remap_t         global_remap;
652
  hb_vector_t<subr_remap_t>  local_remaps;
653
};
654
655
template <typename SUBSETTER, typename SUBRS, typename ACC, typename ENV, typename OPSET, op_code_t endchar_op=OpCode_Invalid>
656
struct subr_subsetter_t
657
{
658
  subr_subsetter_t (ACC &acc_, const hb_subset_plan_t *plan_)
659
      : acc (acc_), plan (plan_), closures(acc_.fdCount),
660
        remaps(acc_.fdCount)
661
1.80k
  {}
CFF::subr_subsetter_t<cff1_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned short, 2u> >, OT::cff1::accelerator_subset_t const, CFF::cff1_cs_interp_env_t, cff1_cs_opset_subr_subset_t, 14u>::subr_subsetter_t(OT::cff1::accelerator_subset_t const&, hb_subset_plan_t const*)
Line
Count
Source
661
1.02k
  {}
CFF::subr_subsetter_t<cff2_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned int, 4u> >, OT::cff2::accelerator_subset_t const, CFF::cff2_cs_interp_env_t<CFF::blend_arg_t>, cff2_cs_opset_subr_subset_t, 65535u>::subr_subsetter_t(OT::cff2::accelerator_subset_t const&, hb_subset_plan_t const*)
Line
Count
Source
661
778
  {}
662
663
  /* Subroutine subsetting with --no-desubroutinize runs in phases:
664
   *
665
   * 1. execute charstrings/subroutines to determine subroutine closures
666
   * 2. parse out all operators and numbers
667
   * 3. mark hint operators and operands for removal if --no-hinting
668
   * 4. re-encode all charstrings and subroutines with new subroutine numbers
669
   *
670
   * Phases #1 and #2 are done at the same time in collect_subrs ().
671
   * Phase #3 walks charstrings/subroutines forward then backward (hence parsing required),
672
   * because we can't tell if a number belongs to a hint op until we see the first moveto.
673
   *
674
   * Assumption: a callsubr/callgsubr operator must immediately follow a (biased) subroutine number
675
   * within the same charstring/subroutine, e.g., not split across a charstring and a subroutine.
676
   */
677
  bool subset (void)
678
1.80k
  {
679
1.80k
    unsigned fd_count = acc.fdCount;
680
1.80k
    const cff_subset_accelerator_t* cff_accelerator = nullptr;
681
1.80k
    if (acc.cff_accelerator) {
682
0
      cff_accelerator = acc.cff_accelerator;
683
0
      fd_count = cff_accelerator->parsed_local_subrs.length;
684
0
    }
685
686
1.80k
    if (cff_accelerator) {
687
      // If we are not dropping hinting then charstrings are not modified so we can
688
      // just use a reference to the cached copies.
689
0
      cached_charstrings.resize_exact (plan->num_output_glyphs ());
690
0
      parsed_global_subrs = &cff_accelerator->parsed_global_subrs;
691
0
      parsed_local_subrs = &cff_accelerator->parsed_local_subrs;
692
1.80k
    } else {
693
1.80k
      parsed_charstrings.resize_exact (plan->num_output_glyphs ());
694
1.80k
      parsed_global_subrs_storage.resize_exact (acc.globalSubrs->count);
695
696
1.80k
      if (unlikely (!parsed_local_subrs_storage.resize (fd_count))) return false;
697
698
6.53k
      for (unsigned int i = 0; i < acc.fdCount; i++)
699
4.73k
      {
700
4.73k
        unsigned count = acc.privateDicts[i].localSubrs->count;
701
4.73k
        parsed_local_subrs_storage[i].resize (count);
702
4.73k
        if (unlikely (parsed_local_subrs_storage[i].in_error ())) return false;
703
4.73k
      }
704
705
1.79k
      parsed_global_subrs = &parsed_global_subrs_storage;
706
1.79k
      parsed_local_subrs = &parsed_local_subrs_storage;
707
1.79k
    }
708
709
1.79k
    if (unlikely (remaps.in_error()
710
1.79k
                  || cached_charstrings.in_error ()
711
1.79k
                  || parsed_charstrings.in_error ()
712
1.79k
                  || parsed_global_subrs->in_error ()
713
1.79k
                  || closures.in_error ())) {
714
9
      return false;
715
9
    }
716
717
    /* phase 1 & 2 */
718
1.78k
    for (auto _ : plan->new_to_old_gid_list)
719
3.69k
    {
720
3.69k
      hb_codepoint_t new_glyph = _.first;
721
3.69k
      hb_codepoint_t old_glyph = _.second;
722
723
3.69k
      const hb_ubytes_t str = (*acc.charStrings)[old_glyph];
724
3.69k
      unsigned int fd = acc.fdSelect->get_fd (old_glyph);
725
3.69k
      if (unlikely (fd >= acc.fdCount))
726
35
        return false;
727
728
3.66k
      if (cff_accelerator)
729
0
      {
730
        // parsed string already exists in accelerator, copy it and move
731
        // on.
732
0
        if (cached_charstrings)
733
0
          cached_charstrings[new_glyph] = &cff_accelerator->parsed_charstrings[old_glyph];
734
0
        else
735
0
          parsed_charstrings[new_glyph] = cff_accelerator->parsed_charstrings[old_glyph];
736
737
0
        continue;
738
0
      }
739
740
3.66k
      ENV env (str, acc, fd);
741
3.66k
      cs_interpreter_t<ENV, OPSET, subr_subset_param_t> interp (env);
742
743
3.66k
      parsed_charstrings[new_glyph].alloc (str.length);
744
3.66k
      subr_subset_param_t  param (&parsed_charstrings[new_glyph],
745
3.66k
                                  &parsed_global_subrs_storage,
746
3.66k
                                  &parsed_local_subrs_storage[fd],
747
3.66k
                                  &closures.global_closure,
748
3.66k
                                  &closures.local_closures[fd],
749
3.66k
                                  plan->flags & HB_SUBSET_FLAGS_NO_HINTING);
750
751
3.66k
      if (unlikely (!interp.interpret (param)))
752
752
        return false;
753
754
      /* complete parsed string esp. copy CFF1 width or CFF2 vsindex to the parsed charstring for encoding */
755
2.90k
      SUBSETTER::complete_parsed_str (interp.env, param, parsed_charstrings[new_glyph]);
756
757
      /* mark hint ops and arguments for drop */
758
2.90k
      if ((plan->flags & HB_SUBSET_FLAGS_NO_HINTING) || plan->inprogress_accelerator)
759
359
      {
760
359
  subr_subset_param_t  param (&parsed_charstrings[new_glyph],
761
359
            &parsed_global_subrs_storage,
762
359
            &parsed_local_subrs_storage[fd],
763
359
            &closures.global_closure,
764
359
            &closures.local_closures[fd],
765
359
            plan->flags & HB_SUBSET_FLAGS_NO_HINTING);
766
767
359
  drop_hints_param_t  drop;
768
359
  if (drop_hints_in_str (parsed_charstrings[new_glyph], param, drop))
769
137
  {
770
137
    parsed_charstrings[new_glyph].set_hint_dropped ();
771
137
    if (drop.vsindex_dropped)
772
1
      parsed_charstrings[new_glyph].set_vsindex_dropped ();
773
137
  }
774
359
      }
775
776
      /* Doing this here one by one instead of compacting all at the end
777
       * has massive peak-memory saving.
778
       *
779
       * The compacting both saves memory and makes further operations
780
       * faster.
781
       */
782
2.90k
      parsed_charstrings[new_glyph].compact ();
783
2.90k
    }
784
785
    /* Since parsed strings were loaded from accelerator, we still need
786
     * to compute the subroutine closures which would have normally happened during
787
     * parsing.
788
     *
789
     * Or if we are dropping hinting, redo closure to get actually used subrs.
790
     */
791
1.00k
    if ((cff_accelerator ||
792
1.00k
  (!cff_accelerator && plan->flags & HB_SUBSET_FLAGS_NO_HINTING)) &&
793
1.00k
        !closure_subroutines(*parsed_global_subrs,
794
201
                             *parsed_local_subrs))
795
0
      return false;
796
797
1.00k
    remaps.create (closures);
798
799
1.00k
    populate_subset_accelerator ();
800
1.00k
    return true;
801
1.00k
  }
CFF::subr_subsetter_t<cff1_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned short, 2u> >, OT::cff1::accelerator_subset_t const, CFF::cff1_cs_interp_env_t, cff1_cs_opset_subr_subset_t, 14u>::subset()
Line
Count
Source
678
1.02k
  {
679
1.02k
    unsigned fd_count = acc.fdCount;
680
1.02k
    const cff_subset_accelerator_t* cff_accelerator = nullptr;
681
1.02k
    if (acc.cff_accelerator) {
682
0
      cff_accelerator = acc.cff_accelerator;
683
0
      fd_count = cff_accelerator->parsed_local_subrs.length;
684
0
    }
685
686
1.02k
    if (cff_accelerator) {
687
      // If we are not dropping hinting then charstrings are not modified so we can
688
      // just use a reference to the cached copies.
689
0
      cached_charstrings.resize_exact (plan->num_output_glyphs ());
690
0
      parsed_global_subrs = &cff_accelerator->parsed_global_subrs;
691
0
      parsed_local_subrs = &cff_accelerator->parsed_local_subrs;
692
1.02k
    } else {
693
1.02k
      parsed_charstrings.resize_exact (plan->num_output_glyphs ());
694
1.02k
      parsed_global_subrs_storage.resize_exact (acc.globalSubrs->count);
695
696
1.02k
      if (unlikely (!parsed_local_subrs_storage.resize (fd_count))) return false;
697
698
4.93k
      for (unsigned int i = 0; i < acc.fdCount; i++)
699
3.91k
      {
700
3.91k
        unsigned count = acc.privateDicts[i].localSubrs->count;
701
3.91k
        parsed_local_subrs_storage[i].resize (count);
702
3.91k
        if (unlikely (parsed_local_subrs_storage[i].in_error ())) return false;
703
3.91k
      }
704
705
1.02k
      parsed_global_subrs = &parsed_global_subrs_storage;
706
1.02k
      parsed_local_subrs = &parsed_local_subrs_storage;
707
1.02k
    }
708
709
1.02k
    if (unlikely (remaps.in_error()
710
1.02k
                  || cached_charstrings.in_error ()
711
1.02k
                  || parsed_charstrings.in_error ()
712
1.02k
                  || parsed_global_subrs->in_error ()
713
1.02k
                  || closures.in_error ())) {
714
6
      return false;
715
6
    }
716
717
    /* phase 1 & 2 */
718
1.01k
    for (auto _ : plan->new_to_old_gid_list)
719
2.01k
    {
720
2.01k
      hb_codepoint_t new_glyph = _.first;
721
2.01k
      hb_codepoint_t old_glyph = _.second;
722
723
2.01k
      const hb_ubytes_t str = (*acc.charStrings)[old_glyph];
724
2.01k
      unsigned int fd = acc.fdSelect->get_fd (old_glyph);
725
2.01k
      if (unlikely (fd >= acc.fdCount))
726
18
        return false;
727
728
1.99k
      if (cff_accelerator)
729
0
      {
730
        // parsed string already exists in accelerator, copy it and move
731
        // on.
732
0
        if (cached_charstrings)
733
0
          cached_charstrings[new_glyph] = &cff_accelerator->parsed_charstrings[old_glyph];
734
0
        else
735
0
          parsed_charstrings[new_glyph] = cff_accelerator->parsed_charstrings[old_glyph];
736
737
0
        continue;
738
0
      }
739
740
1.99k
      ENV env (str, acc, fd);
741
1.99k
      cs_interpreter_t<ENV, OPSET, subr_subset_param_t> interp (env);
742
743
1.99k
      parsed_charstrings[new_glyph].alloc (str.length);
744
1.99k
      subr_subset_param_t  param (&parsed_charstrings[new_glyph],
745
1.99k
                                  &parsed_global_subrs_storage,
746
1.99k
                                  &parsed_local_subrs_storage[fd],
747
1.99k
                                  &closures.global_closure,
748
1.99k
                                  &closures.local_closures[fd],
749
1.99k
                                  plan->flags & HB_SUBSET_FLAGS_NO_HINTING);
750
751
1.99k
      if (unlikely (!interp.interpret (param)))
752
455
        return false;
753
754
      /* complete parsed string esp. copy CFF1 width or CFF2 vsindex to the parsed charstring for encoding */
755
1.53k
      SUBSETTER::complete_parsed_str (interp.env, param, parsed_charstrings[new_glyph]);
756
757
      /* mark hint ops and arguments for drop */
758
1.53k
      if ((plan->flags & HB_SUBSET_FLAGS_NO_HINTING) || plan->inprogress_accelerator)
759
250
      {
760
250
  subr_subset_param_t  param (&parsed_charstrings[new_glyph],
761
250
            &parsed_global_subrs_storage,
762
250
            &parsed_local_subrs_storage[fd],
763
250
            &closures.global_closure,
764
250
            &closures.local_closures[fd],
765
250
            plan->flags & HB_SUBSET_FLAGS_NO_HINTING);
766
767
250
  drop_hints_param_t  drop;
768
250
  if (drop_hints_in_str (parsed_charstrings[new_glyph], param, drop))
769
90
  {
770
90
    parsed_charstrings[new_glyph].set_hint_dropped ();
771
90
    if (drop.vsindex_dropped)
772
0
      parsed_charstrings[new_glyph].set_vsindex_dropped ();
773
90
  }
774
250
      }
775
776
      /* Doing this here one by one instead of compacting all at the end
777
       * has massive peak-memory saving.
778
       *
779
       * The compacting both saves memory and makes further operations
780
       * faster.
781
       */
782
1.53k
      parsed_charstrings[new_glyph].compact ();
783
1.53k
    }
784
785
    /* Since parsed strings were loaded from accelerator, we still need
786
     * to compute the subroutine closures which would have normally happened during
787
     * parsing.
788
     *
789
     * Or if we are dropping hinting, redo closure to get actually used subrs.
790
     */
791
542
    if ((cff_accelerator ||
792
542
  (!cff_accelerator && plan->flags & HB_SUBSET_FLAGS_NO_HINTING)) &&
793
542
        !closure_subroutines(*parsed_global_subrs,
794
117
                             *parsed_local_subrs))
795
0
      return false;
796
797
542
    remaps.create (closures);
798
799
542
    populate_subset_accelerator ();
800
542
    return true;
801
542
  }
CFF::subr_subsetter_t<cff2_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned int, 4u> >, OT::cff2::accelerator_subset_t const, CFF::cff2_cs_interp_env_t<CFF::blend_arg_t>, cff2_cs_opset_subr_subset_t, 65535u>::subset()
Line
Count
Source
678
778
  {
679
778
    unsigned fd_count = acc.fdCount;
680
778
    const cff_subset_accelerator_t* cff_accelerator = nullptr;
681
778
    if (acc.cff_accelerator) {
682
0
      cff_accelerator = acc.cff_accelerator;
683
0
      fd_count = cff_accelerator->parsed_local_subrs.length;
684
0
    }
685
686
778
    if (cff_accelerator) {
687
      // If we are not dropping hinting then charstrings are not modified so we can
688
      // just use a reference to the cached copies.
689
0
      cached_charstrings.resize_exact (plan->num_output_glyphs ());
690
0
      parsed_global_subrs = &cff_accelerator->parsed_global_subrs;
691
0
      parsed_local_subrs = &cff_accelerator->parsed_local_subrs;
692
778
    } else {
693
778
      parsed_charstrings.resize_exact (plan->num_output_glyphs ());
694
778
      parsed_global_subrs_storage.resize_exact (acc.globalSubrs->count);
695
696
778
      if (unlikely (!parsed_local_subrs_storage.resize (fd_count))) return false;
697
698
1.60k
      for (unsigned int i = 0; i < acc.fdCount; i++)
699
825
      {
700
825
        unsigned count = acc.privateDicts[i].localSubrs->count;
701
825
        parsed_local_subrs_storage[i].resize (count);
702
825
        if (unlikely (parsed_local_subrs_storage[i].in_error ())) return false;
703
825
      }
704
705
776
      parsed_global_subrs = &parsed_global_subrs_storage;
706
776
      parsed_local_subrs = &parsed_local_subrs_storage;
707
776
    }
708
709
776
    if (unlikely (remaps.in_error()
710
776
                  || cached_charstrings.in_error ()
711
776
                  || parsed_charstrings.in_error ()
712
776
                  || parsed_global_subrs->in_error ()
713
776
                  || closures.in_error ())) {
714
3
      return false;
715
3
    }
716
717
    /* phase 1 & 2 */
718
773
    for (auto _ : plan->new_to_old_gid_list)
719
1.68k
    {
720
1.68k
      hb_codepoint_t new_glyph = _.first;
721
1.68k
      hb_codepoint_t old_glyph = _.second;
722
723
1.68k
      const hb_ubytes_t str = (*acc.charStrings)[old_glyph];
724
1.68k
      unsigned int fd = acc.fdSelect->get_fd (old_glyph);
725
1.68k
      if (unlikely (fd >= acc.fdCount))
726
17
        return false;
727
728
1.66k
      if (cff_accelerator)
729
0
      {
730
        // parsed string already exists in accelerator, copy it and move
731
        // on.
732
0
        if (cached_charstrings)
733
0
          cached_charstrings[new_glyph] = &cff_accelerator->parsed_charstrings[old_glyph];
734
0
        else
735
0
          parsed_charstrings[new_glyph] = cff_accelerator->parsed_charstrings[old_glyph];
736
737
0
        continue;
738
0
      }
739
740
1.66k
      ENV env (str, acc, fd);
741
1.66k
      cs_interpreter_t<ENV, OPSET, subr_subset_param_t> interp (env);
742
743
1.66k
      parsed_charstrings[new_glyph].alloc (str.length);
744
1.66k
      subr_subset_param_t  param (&parsed_charstrings[new_glyph],
745
1.66k
                                  &parsed_global_subrs_storage,
746
1.66k
                                  &parsed_local_subrs_storage[fd],
747
1.66k
                                  &closures.global_closure,
748
1.66k
                                  &closures.local_closures[fd],
749
1.66k
                                  plan->flags & HB_SUBSET_FLAGS_NO_HINTING);
750
751
1.66k
      if (unlikely (!interp.interpret (param)))
752
297
        return false;
753
754
      /* complete parsed string esp. copy CFF1 width or CFF2 vsindex to the parsed charstring for encoding */
755
1.37k
      SUBSETTER::complete_parsed_str (interp.env, param, parsed_charstrings[new_glyph]);
756
757
      /* mark hint ops and arguments for drop */
758
1.37k
      if ((plan->flags & HB_SUBSET_FLAGS_NO_HINTING) || plan->inprogress_accelerator)
759
109
      {
760
109
  subr_subset_param_t  param (&parsed_charstrings[new_glyph],
761
109
            &parsed_global_subrs_storage,
762
109
            &parsed_local_subrs_storage[fd],
763
109
            &closures.global_closure,
764
109
            &closures.local_closures[fd],
765
109
            plan->flags & HB_SUBSET_FLAGS_NO_HINTING);
766
767
109
  drop_hints_param_t  drop;
768
109
  if (drop_hints_in_str (parsed_charstrings[new_glyph], param, drop))
769
47
  {
770
47
    parsed_charstrings[new_glyph].set_hint_dropped ();
771
47
    if (drop.vsindex_dropped)
772
1
      parsed_charstrings[new_glyph].set_vsindex_dropped ();
773
47
  }
774
109
      }
775
776
      /* Doing this here one by one instead of compacting all at the end
777
       * has massive peak-memory saving.
778
       *
779
       * The compacting both saves memory and makes further operations
780
       * faster.
781
       */
782
1.37k
      parsed_charstrings[new_glyph].compact ();
783
1.37k
    }
784
785
    /* Since parsed strings were loaded from accelerator, we still need
786
     * to compute the subroutine closures which would have normally happened during
787
     * parsing.
788
     *
789
     * Or if we are dropping hinting, redo closure to get actually used subrs.
790
     */
791
459
    if ((cff_accelerator ||
792
459
  (!cff_accelerator && plan->flags & HB_SUBSET_FLAGS_NO_HINTING)) &&
793
459
        !closure_subroutines(*parsed_global_subrs,
794
84
                             *parsed_local_subrs))
795
0
      return false;
796
797
459
    remaps.create (closures);
798
799
459
    populate_subset_accelerator ();
800
459
    return true;
801
459
  }
802
803
  bool encode_charstrings (str_buff_vec_t &buffArray, bool encode_prefix = true) const
804
1.00k
  {
805
1.00k
    unsigned num_glyphs = plan->num_output_glyphs ();
806
1.00k
    if (unlikely (!buffArray.resize_exact (num_glyphs)))
807
3
      return false;
808
998
    hb_codepoint_t last = 0;
809
998
    for (auto _ : plan->new_to_old_gid_list)
810
2.45k
    {
811
2.45k
      hb_codepoint_t gid = _.first;
812
2.45k
      hb_codepoint_t old_glyph = _.second;
813
814
2.45k
      if (endchar_op != OpCode_Invalid)
815
1.54k
        for (; last < gid; last++)
816
256
  {
817
    // Hack to point vector to static string.
818
256
    auto &b = buffArray.arrayZ[last];
819
256
    b.length = 1;
820
256
    b.arrayZ = const_cast<unsigned char *>(endchar_str);
821
256
  }
822
823
2.45k
      last++; // Skip over gid
824
2.45k
      unsigned int  fd = acc.fdSelect->get_fd (old_glyph);
825
2.45k
      if (unlikely (fd >= acc.fdCount))
826
0
  return false;
827
2.45k
      if (unlikely (!encode_str (get_parsed_charstring (gid), fd, buffArray.arrayZ[gid], encode_prefix)))
828
3
  return false;
829
2.45k
    }
830
995
    if (endchar_op != OpCode_Invalid)
831
538
      for (; last < num_glyphs; last++)
832
0
      {
833
  // Hack to point vector to static string.
834
0
  auto &b = buffArray.arrayZ[last];
835
0
  b.length = 1;
836
0
  b.arrayZ = const_cast<unsigned char *>(endchar_str);
837
0
      }
838
839
995
    return true;
840
998
  }
CFF::subr_subsetter_t<cff1_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned short, 2u> >, OT::cff1::accelerator_subset_t const, CFF::cff1_cs_interp_env_t, cff1_cs_opset_subr_subset_t, 14u>::encode_charstrings(hb_vector_t<hb_vector_t<unsigned char, false>, false>&, bool) const
Line
Count
Source
804
542
  {
805
542
    unsigned num_glyphs = plan->num_output_glyphs ();
806
542
    if (unlikely (!buffArray.resize_exact (num_glyphs)))
807
2
      return false;
808
540
    hb_codepoint_t last = 0;
809
540
    for (auto _ : plan->new_to_old_gid_list)
810
1.28k
    {
811
1.28k
      hb_codepoint_t gid = _.first;
812
1.28k
      hb_codepoint_t old_glyph = _.second;
813
814
1.28k
      if (endchar_op != OpCode_Invalid)
815
1.54k
        for (; last < gid; last++)
816
256
  {
817
    // Hack to point vector to static string.
818
256
    auto &b = buffArray.arrayZ[last];
819
256
    b.length = 1;
820
256
    b.arrayZ = const_cast<unsigned char *>(endchar_str);
821
256
  }
822
823
1.28k
      last++; // Skip over gid
824
1.28k
      unsigned int  fd = acc.fdSelect->get_fd (old_glyph);
825
1.28k
      if (unlikely (fd >= acc.fdCount))
826
0
  return false;
827
1.28k
      if (unlikely (!encode_str (get_parsed_charstring (gid), fd, buffArray.arrayZ[gid], encode_prefix)))
828
2
  return false;
829
1.28k
    }
830
538
    if (endchar_op != OpCode_Invalid)
831
538
      for (; last < num_glyphs; last++)
832
0
      {
833
  // Hack to point vector to static string.
834
0
  auto &b = buffArray.arrayZ[last];
835
0
  b.length = 1;
836
0
  b.arrayZ = const_cast<unsigned char *>(endchar_str);
837
0
      }
838
839
538
    return true;
840
540
  }
CFF::subr_subsetter_t<cff2_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned int, 4u> >, OT::cff2::accelerator_subset_t const, CFF::cff2_cs_interp_env_t<CFF::blend_arg_t>, cff2_cs_opset_subr_subset_t, 65535u>::encode_charstrings(hb_vector_t<hb_vector_t<unsigned char, false>, false>&, bool) const
Line
Count
Source
804
459
  {
805
459
    unsigned num_glyphs = plan->num_output_glyphs ();
806
459
    if (unlikely (!buffArray.resize_exact (num_glyphs)))
807
1
      return false;
808
458
    hb_codepoint_t last = 0;
809
458
    for (auto _ : plan->new_to_old_gid_list)
810
1.16k
    {
811
1.16k
      hb_codepoint_t gid = _.first;
812
1.16k
      hb_codepoint_t old_glyph = _.second;
813
814
1.16k
      if (endchar_op != OpCode_Invalid)
815
0
        for (; last < gid; last++)
816
0
  {
817
    // Hack to point vector to static string.
818
0
    auto &b = buffArray.arrayZ[last];
819
0
    b.length = 1;
820
0
    b.arrayZ = const_cast<unsigned char *>(endchar_str);
821
0
  }
822
823
1.16k
      last++; // Skip over gid
824
1.16k
      unsigned int  fd = acc.fdSelect->get_fd (old_glyph);
825
1.16k
      if (unlikely (fd >= acc.fdCount))
826
0
  return false;
827
1.16k
      if (unlikely (!encode_str (get_parsed_charstring (gid), fd, buffArray.arrayZ[gid], encode_prefix)))
828
1
  return false;
829
1.16k
    }
830
457
    if (endchar_op != OpCode_Invalid)
831
0
      for (; last < num_glyphs; last++)
832
0
      {
833
  // Hack to point vector to static string.
834
0
  auto &b = buffArray.arrayZ[last];
835
0
  b.length = 1;
836
0
  b.arrayZ = const_cast<unsigned char *>(endchar_str);
837
0
      }
838
839
457
    return true;
840
458
  }
841
842
  bool encode_subrs (const parsed_cs_str_vec_t &subrs, const subr_remap_t& remap, unsigned int fd, str_buff_vec_t &buffArray) const
843
2.08k
  {
844
2.08k
    unsigned int  count = remap.get_population ();
845
846
2.08k
    if (unlikely (!buffArray.resize_exact (count)))
847
1
      return false;
848
4.72k
    for (unsigned int new_num = 0; new_num < count; new_num++)
849
2.64k
    {
850
2.64k
      hb_codepoint_t old_num = remap.backward (new_num);
851
2.64k
      assert (old_num != CFF_UNDEF_CODE);
852
853
2.64k
      if (unlikely (!encode_str (subrs[old_num], fd, buffArray[new_num])))
854
1
  return false;
855
2.64k
    }
856
2.07k
    return true;
857
2.08k
  }
CFF::subr_subsetter_t<cff1_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned short, 2u> >, OT::cff1::accelerator_subset_t const, CFF::cff1_cs_interp_env_t, cff1_cs_opset_subr_subset_t, 14u>::encode_subrs(CFF::parsed_cs_str_vec_t const&, CFF::subr_remap_t const&, unsigned int, hb_vector_t<hb_vector_t<unsigned char, false>, false>&) const
Line
Count
Source
843
1.12k
  {
844
1.12k
    unsigned int  count = remap.get_population ();
845
846
1.12k
    if (unlikely (!buffArray.resize_exact (count)))
847
0
      return false;
848
2.21k
    for (unsigned int new_num = 0; new_num < count; new_num++)
849
1.09k
    {
850
1.09k
      hb_codepoint_t old_num = remap.backward (new_num);
851
1.09k
      assert (old_num != CFF_UNDEF_CODE);
852
853
1.09k
      if (unlikely (!encode_str (subrs[old_num], fd, buffArray[new_num])))
854
0
  return false;
855
1.09k
    }
856
1.12k
    return true;
857
1.12k
  }
CFF::subr_subsetter_t<cff2_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned int, 4u> >, OT::cff2::accelerator_subset_t const, CFF::cff2_cs_interp_env_t<CFF::blend_arg_t>, cff2_cs_opset_subr_subset_t, 65535u>::encode_subrs(CFF::parsed_cs_str_vec_t const&, CFF::subr_remap_t const&, unsigned int, hb_vector_t<hb_vector_t<unsigned char, false>, false>&) const
Line
Count
Source
843
961
  {
844
961
    unsigned int  count = remap.get_population ();
845
846
961
    if (unlikely (!buffArray.resize_exact (count)))
847
1
      return false;
848
2.50k
    for (unsigned int new_num = 0; new_num < count; new_num++)
849
1.55k
    {
850
1.55k
      hb_codepoint_t old_num = remap.backward (new_num);
851
1.55k
      assert (old_num != CFF_UNDEF_CODE);
852
853
1.55k
      if (unlikely (!encode_str (subrs[old_num], fd, buffArray[new_num])))
854
1
  return false;
855
1.55k
    }
856
959
    return true;
857
960
  }
858
859
  bool encode_globalsubrs (str_buff_vec_t &buffArray)
860
995
  {
861
995
    return encode_subrs (*parsed_global_subrs, remaps.global_remap, 0, buffArray);
862
995
  }
CFF::subr_subsetter_t<cff1_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned short, 2u> >, OT::cff1::accelerator_subset_t const, CFF::cff1_cs_interp_env_t, cff1_cs_opset_subr_subset_t, 14u>::encode_globalsubrs(hb_vector_t<hb_vector_t<unsigned char, false>, false>&)
Line
Count
Source
860
538
  {
861
538
    return encode_subrs (*parsed_global_subrs, remaps.global_remap, 0, buffArray);
862
538
  }
CFF::subr_subsetter_t<cff2_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned int, 4u> >, OT::cff2::accelerator_subset_t const, CFF::cff2_cs_interp_env_t<CFF::blend_arg_t>, cff2_cs_opset_subr_subset_t, 65535u>::encode_globalsubrs(hb_vector_t<hb_vector_t<unsigned char, false>, false>&)
Line
Count
Source
860
457
  {
861
457
    return encode_subrs (*parsed_global_subrs, remaps.global_remap, 0, buffArray);
862
457
  }
863
864
  bool encode_localsubrs (unsigned int fd, str_buff_vec_t &buffArray) const
865
1.08k
  {
866
1.08k
    return encode_subrs ((*parsed_local_subrs)[fd], remaps.local_remaps[fd], fd, buffArray);
867
1.08k
  }
CFF::subr_subsetter_t<cff1_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned short, 2u> >, OT::cff1::accelerator_subset_t const, CFF::cff1_cs_interp_env_t, cff1_cs_opset_subr_subset_t, 14u>::encode_localsubrs(unsigned int, hb_vector_t<hb_vector_t<unsigned char, false>, false>&) const
Line
Count
Source
865
582
  {
866
582
    return encode_subrs ((*parsed_local_subrs)[fd], remaps.local_remaps[fd], fd, buffArray);
867
582
  }
CFF::subr_subsetter_t<cff2_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned int, 4u> >, OT::cff2::accelerator_subset_t const, CFF::cff2_cs_interp_env_t<CFF::blend_arg_t>, cff2_cs_opset_subr_subset_t, 65535u>::encode_localsubrs(unsigned int, hb_vector_t<hb_vector_t<unsigned char, false>, false>&) const
Line
Count
Source
865
504
  {
866
504
    return encode_subrs ((*parsed_local_subrs)[fd], remaps.local_remaps[fd], fd, buffArray);
867
504
  }
868
869
  protected:
870
  struct drop_hints_param_t
871
  {
872
    drop_hints_param_t ()
873
      : seen_moveto (false),
874
  ends_in_hint (false),
875
  all_dropped (false),
876
359
  vsindex_dropped (false) {}
CFF::subr_subsetter_t<cff1_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned short, 2u> >, OT::cff1::accelerator_subset_t const, CFF::cff1_cs_interp_env_t, cff1_cs_opset_subr_subset_t, 14u>::drop_hints_param_t::drop_hints_param_t()
Line
Count
Source
876
250
  vsindex_dropped (false) {}
CFF::subr_subsetter_t<cff2_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned int, 4u> >, OT::cff2::accelerator_subset_t const, CFF::cff2_cs_interp_env_t<CFF::blend_arg_t>, cff2_cs_opset_subr_subset_t, 65535u>::drop_hints_param_t::drop_hints_param_t()
Line
Count
Source
876
109
  vsindex_dropped (false) {}
877
878
    bool  seen_moveto;
879
    bool  ends_in_hint;
880
    bool  all_dropped;
881
    bool  vsindex_dropped;
882
  };
883
884
  bool drop_hints_in_subr (parsed_cs_str_t &str, unsigned int pos,
885
         parsed_cs_str_vec_t &subrs, unsigned int subr_num,
886
         const subr_subset_param_t &param, drop_hints_param_t &drop)
887
707
  {
888
707
    drop.ends_in_hint = false;
889
707
    bool has_hint = drop_hints_in_str (subrs[subr_num], param, drop);
890
891
    /* if this subr ends with a stem hint (i.e., not a number; potential argument for moveto),
892
     * then this entire subroutine must be a hint. drop its call. */
893
707
    if (drop.ends_in_hint)
894
47
    {
895
47
      str.values[pos].set_hinting ();
896
      /* if this subr call is at the end of the parent subr, propagate the flag
897
       * otherwise reset the flag */
898
47
      if (!str.at_end (pos))
899
30
  drop.ends_in_hint = false;
900
47
    }
901
660
    else if (drop.all_dropped)
902
196
    {
903
196
      str.values[pos].set_hinting ();
904
196
    }
905
906
707
    return has_hint;
907
707
  }
CFF::subr_subsetter_t<cff1_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned short, 2u> >, OT::cff1::accelerator_subset_t const, CFF::cff1_cs_interp_env_t, cff1_cs_opset_subr_subset_t, 14u>::drop_hints_in_subr(CFF::parsed_cs_str_t&, unsigned int, CFF::parsed_cs_str_vec_t&, unsigned int, CFF::subr_subset_param_t const&, CFF::subr_subsetter_t<cff1_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned short, 2u> >, OT::cff1::accelerator_subset_t const, CFF::cff1_cs_interp_env_t, cff1_cs_opset_subr_subset_t, 14u>::drop_hints_param_t&)
Line
Count
Source
887
195
  {
888
195
    drop.ends_in_hint = false;
889
195
    bool has_hint = drop_hints_in_str (subrs[subr_num], param, drop);
890
891
    /* if this subr ends with a stem hint (i.e., not a number; potential argument for moveto),
892
     * then this entire subroutine must be a hint. drop its call. */
893
195
    if (drop.ends_in_hint)
894
18
    {
895
18
      str.values[pos].set_hinting ();
896
      /* if this subr call is at the end of the parent subr, propagate the flag
897
       * otherwise reset the flag */
898
18
      if (!str.at_end (pos))
899
10
  drop.ends_in_hint = false;
900
18
    }
901
177
    else if (drop.all_dropped)
902
12
    {
903
12
      str.values[pos].set_hinting ();
904
12
    }
905
906
195
    return has_hint;
907
195
  }
CFF::subr_subsetter_t<cff2_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned int, 4u> >, OT::cff2::accelerator_subset_t const, CFF::cff2_cs_interp_env_t<CFF::blend_arg_t>, cff2_cs_opset_subr_subset_t, 65535u>::drop_hints_in_subr(CFF::parsed_cs_str_t&, unsigned int, CFF::parsed_cs_str_vec_t&, unsigned int, CFF::subr_subset_param_t const&, CFF::subr_subsetter_t<cff2_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned int, 4u> >, OT::cff2::accelerator_subset_t const, CFF::cff2_cs_interp_env_t<CFF::blend_arg_t>, cff2_cs_opset_subr_subset_t, 65535u>::drop_hints_param_t&)
Line
Count
Source
887
512
  {
888
512
    drop.ends_in_hint = false;
889
512
    bool has_hint = drop_hints_in_str (subrs[subr_num], param, drop);
890
891
    /* if this subr ends with a stem hint (i.e., not a number; potential argument for moveto),
892
     * then this entire subroutine must be a hint. drop its call. */
893
512
    if (drop.ends_in_hint)
894
29
    {
895
29
      str.values[pos].set_hinting ();
896
      /* if this subr call is at the end of the parent subr, propagate the flag
897
       * otherwise reset the flag */
898
29
      if (!str.at_end (pos))
899
20
  drop.ends_in_hint = false;
900
29
    }
901
483
    else if (drop.all_dropped)
902
184
    {
903
184
      str.values[pos].set_hinting ();
904
184
    }
905
906
512
    return has_hint;
907
512
  }
908
909
  /* returns true if it sees a hint op before the first moveto */
910
  bool drop_hints_in_str (parsed_cs_str_t &str, const subr_subset_param_t &param, drop_hints_param_t &drop)
911
1.06k
  {
912
1.06k
    bool  seen_hint = false;
913
914
1.06k
    unsigned count = str.values.length;
915
1.06k
    auto *values = str.values.arrayZ;
916
19.6k
    for (unsigned int pos = 0; pos < count; pos++)
917
18.5k
    {
918
18.5k
      bool  has_hint = false;
919
18.5k
      switch (values[pos].op)
920
18.5k
      {
921
537
  case OpCode_callsubr:
922
537
    has_hint = drop_hints_in_subr (str, pos,
923
537
          *param.parsed_local_subrs, values[pos].subr_num,
924
537
          param, drop);
925
537
    break;
926
927
170
  case OpCode_callgsubr:
928
170
    has_hint = drop_hints_in_subr (str, pos,
929
170
          *param.parsed_global_subrs, values[pos].subr_num,
930
170
          param, drop);
931
170
    break;
932
933
378
  case OpCode_rmoveto:
934
519
  case OpCode_hmoveto:
935
624
  case OpCode_vmoveto:
936
624
    drop.seen_moveto = true;
937
624
    break;
938
939
428
  case OpCode_hintmask:
940
572
  case OpCode_cntrmask:
941
572
    if (drop.seen_moveto)
942
400
    {
943
400
      values[pos].set_hinting ();
944
400
      break;
945
400
    }
946
572
    HB_FALLTHROUGH;
947
948
319
  case OpCode_hstemhm:
949
453
  case OpCode_vstemhm:
950
648
  case OpCode_hstem:
951
869
  case OpCode_vstem:
952
869
    has_hint = true;
953
869
    values[pos].set_hinting ();
954
869
    if (str.at_end (pos))
955
37
      drop.ends_in_hint = true;
956
869
    break;
957
958
21
  case OpCode_dotsection:
959
21
    values[pos].set_hinting ();
960
21
    break;
961
962
15.9k
  default:
963
    /* NONE */
964
15.9k
    break;
965
18.5k
      }
966
18.5k
      if (has_hint)
967
983
      {
968
5.27k
  for (int i = pos - 1; i >= 0; i--)
969
5.06k
  {
970
5.06k
    parsed_cs_op_t  &csop = values[(unsigned)i];
971
5.06k
    if (csop.is_hinting ())
972
769
      break;
973
4.29k
    csop.set_hinting ();
974
4.29k
    if (csop.op == OpCode_vsindexcs)
975
1
      drop.vsindex_dropped = true;
976
4.29k
  }
977
983
  seen_hint |= has_hint;
978
983
      }
979
18.5k
    }
980
981
    /* Raise all_dropped flag if all operators except return are dropped from a subr.
982
     * It may happen even after seeing the first moveto if a subr contains
983
     * only (usually one) hintmask operator, then calls to this subr can be dropped.
984
     */
985
1.06k
    drop.all_dropped = true;
986
4.67k
    for (unsigned int pos = 0; pos < count; pos++)
987
4.43k
    {
988
4.43k
      parsed_cs_op_t  &csop = values[pos];
989
4.43k
      if (csop.op == OpCode_return)
990
30
  break;
991
4.40k
      if (!csop.is_hinting ())
992
790
      {
993
790
  drop.all_dropped = false;
994
790
  break;
995
790
      }
996
4.40k
    }
997
998
1.06k
    return seen_hint;
999
1.06k
  }
CFF::subr_subsetter_t<cff1_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned short, 2u> >, OT::cff1::accelerator_subset_t const, CFF::cff1_cs_interp_env_t, cff1_cs_opset_subr_subset_t, 14u>::drop_hints_in_str(CFF::parsed_cs_str_t&, CFF::subr_subset_param_t const&, CFF::subr_subsetter_t<cff1_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned short, 2u> >, OT::cff1::accelerator_subset_t const, CFF::cff1_cs_interp_env_t, cff1_cs_opset_subr_subset_t, 14u>::drop_hints_param_t&)
Line
Count
Source
911
445
  {
912
445
    bool  seen_hint = false;
913
914
445
    unsigned count = str.values.length;
915
445
    auto *values = str.values.arrayZ;
916
8.30k
    for (unsigned int pos = 0; pos < count; pos++)
917
7.85k
    {
918
7.85k
      bool  has_hint = false;
919
7.85k
      switch (values[pos].op)
920
7.85k
      {
921
84
  case OpCode_callsubr:
922
84
    has_hint = drop_hints_in_subr (str, pos,
923
84
          *param.parsed_local_subrs, values[pos].subr_num,
924
84
          param, drop);
925
84
    break;
926
927
111
  case OpCode_callgsubr:
928
111
    has_hint = drop_hints_in_subr (str, pos,
929
111
          *param.parsed_global_subrs, values[pos].subr_num,
930
111
          param, drop);
931
111
    break;
932
933
100
  case OpCode_rmoveto:
934
184
  case OpCode_hmoveto:
935
225
  case OpCode_vmoveto:
936
225
    drop.seen_moveto = true;
937
225
    break;
938
939
218
  case OpCode_hintmask:
940
313
  case OpCode_cntrmask:
941
313
    if (drop.seen_moveto)
942
215
    {
943
215
      values[pos].set_hinting ();
944
215
      break;
945
215
    }
946
313
    HB_FALLTHROUGH;
947
948
145
  case OpCode_hstemhm:
949
201
  case OpCode_vstemhm:
950
336
  case OpCode_hstem:
951
513
  case OpCode_vstem:
952
513
    has_hint = true;
953
513
    values[pos].set_hinting ();
954
513
    if (str.at_end (pos))
955
10
      drop.ends_in_hint = true;
956
513
    break;
957
958
21
  case OpCode_dotsection:
959
21
    values[pos].set_hinting ();
960
21
    break;
961
962
6.68k
  default:
963
    /* NONE */
964
6.68k
    break;
965
7.85k
      }
966
7.85k
      if (has_hint)
967
557
      {
968
3.08k
  for (int i = pos - 1; i >= 0; i--)
969
2.95k
  {
970
2.95k
    parsed_cs_op_t  &csop = values[(unsigned)i];
971
2.95k
    if (csop.is_hinting ())
972
429
      break;
973
2.52k
    csop.set_hinting ();
974
2.52k
    if (csop.op == OpCode_vsindexcs)
975
0
      drop.vsindex_dropped = true;
976
2.52k
  }
977
557
  seen_hint |= has_hint;
978
557
      }
979
7.85k
    }
980
981
    /* Raise all_dropped flag if all operators except return are dropped from a subr.
982
     * It may happen even after seeing the first moveto if a subr contains
983
     * only (usually one) hintmask operator, then calls to this subr can be dropped.
984
     */
985
445
    drop.all_dropped = true;
986
3.15k
    for (unsigned int pos = 0; pos < count; pos++)
987
3.15k
    {
988
3.15k
      parsed_cs_op_t  &csop = values[pos];
989
3.15k
      if (csop.op == OpCode_return)
990
30
  break;
991
3.12k
      if (!csop.is_hinting ())
992
414
      {
993
414
  drop.all_dropped = false;
994
414
  break;
995
414
      }
996
3.12k
    }
997
998
445
    return seen_hint;
999
445
  }
CFF::subr_subsetter_t<cff2_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned int, 4u> >, OT::cff2::accelerator_subset_t const, CFF::cff2_cs_interp_env_t<CFF::blend_arg_t>, cff2_cs_opset_subr_subset_t, 65535u>::drop_hints_in_str(CFF::parsed_cs_str_t&, CFF::subr_subset_param_t const&, CFF::subr_subsetter_t<cff2_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned int, 4u> >, OT::cff2::accelerator_subset_t const, CFF::cff2_cs_interp_env_t<CFF::blend_arg_t>, cff2_cs_opset_subr_subset_t, 65535u>::drop_hints_param_t&)
Line
Count
Source
911
621
  {
912
621
    bool  seen_hint = false;
913
914
621
    unsigned count = str.values.length;
915
621
    auto *values = str.values.arrayZ;
916
11.3k
    for (unsigned int pos = 0; pos < count; pos++)
917
10.7k
    {
918
10.7k
      bool  has_hint = false;
919
10.7k
      switch (values[pos].op)
920
10.7k
      {
921
453
  case OpCode_callsubr:
922
453
    has_hint = drop_hints_in_subr (str, pos,
923
453
          *param.parsed_local_subrs, values[pos].subr_num,
924
453
          param, drop);
925
453
    break;
926
927
59
  case OpCode_callgsubr:
928
59
    has_hint = drop_hints_in_subr (str, pos,
929
59
          *param.parsed_global_subrs, values[pos].subr_num,
930
59
          param, drop);
931
59
    break;
932
933
278
  case OpCode_rmoveto:
934
335
  case OpCode_hmoveto:
935
399
  case OpCode_vmoveto:
936
399
    drop.seen_moveto = true;
937
399
    break;
938
939
210
  case OpCode_hintmask:
940
259
  case OpCode_cntrmask:
941
259
    if (drop.seen_moveto)
942
185
    {
943
185
      values[pos].set_hinting ();
944
185
      break;
945
185
    }
946
259
    HB_FALLTHROUGH;
947
948
174
  case OpCode_hstemhm:
949
252
  case OpCode_vstemhm:
950
312
  case OpCode_hstem:
951
356
  case OpCode_vstem:
952
356
    has_hint = true;
953
356
    values[pos].set_hinting ();
954
356
    if (str.at_end (pos))
955
27
      drop.ends_in_hint = true;
956
356
    break;
957
958
0
  case OpCode_dotsection:
959
0
    values[pos].set_hinting ();
960
0
    break;
961
962
9.25k
  default:
963
    /* NONE */
964
9.25k
    break;
965
10.7k
      }
966
10.7k
      if (has_hint)
967
426
      {
968
2.19k
  for (int i = pos - 1; i >= 0; i--)
969
2.10k
  {
970
2.10k
    parsed_cs_op_t  &csop = values[(unsigned)i];
971
2.10k
    if (csop.is_hinting ())
972
340
      break;
973
1.76k
    csop.set_hinting ();
974
1.76k
    if (csop.op == OpCode_vsindexcs)
975
1
      drop.vsindex_dropped = true;
976
1.76k
  }
977
426
  seen_hint |= has_hint;
978
426
      }
979
10.7k
    }
980
981
    /* Raise all_dropped flag if all operators except return are dropped from a subr.
982
     * It may happen even after seeing the first moveto if a subr contains
983
     * only (usually one) hintmask operator, then calls to this subr can be dropped.
984
     */
985
621
    drop.all_dropped = true;
986
1.52k
    for (unsigned int pos = 0; pos < count; pos++)
987
1.27k
    {
988
1.27k
      parsed_cs_op_t  &csop = values[pos];
989
1.27k
      if (csop.op == OpCode_return)
990
0
  break;
991
1.27k
      if (!csop.is_hinting ())
992
376
      {
993
376
  drop.all_dropped = false;
994
376
  break;
995
376
      }
996
1.27k
    }
997
998
621
    return seen_hint;
999
621
  }
1000
1001
  bool closure_subroutines (const parsed_cs_str_vec_t& global_subrs,
1002
                            const hb_vector_t<parsed_cs_str_vec_t>& local_subrs)
1003
201
  {
1004
201
    closures.reset ();
1005
201
    for (auto _ : plan->new_to_old_gid_list)
1006
345
    {
1007
345
      hb_codepoint_t new_glyph = _.first;
1008
345
      hb_codepoint_t old_glyph = _.second;
1009
345
      unsigned int fd = acc.fdSelect->get_fd (old_glyph);
1010
345
      if (unlikely (fd >= acc.fdCount))
1011
0
        return false;
1012
1013
      // Note: const cast is safe here because the collect_subr_refs_in_str only performs a
1014
      //       closure and does not modify any of the charstrings.
1015
345
      subr_subset_param_t  param (const_cast<parsed_cs_str_t*> (&get_parsed_charstring (new_glyph)),
1016
345
                                  const_cast<parsed_cs_str_vec_t*> (&global_subrs),
1017
345
                                  const_cast<parsed_cs_str_vec_t*> (&local_subrs[fd]),
1018
345
                                  &closures.global_closure,
1019
345
                                  &closures.local_closures[fd],
1020
345
                                  plan->flags & HB_SUBSET_FLAGS_NO_HINTING);
1021
345
      collect_subr_refs_in_str (get_parsed_charstring (new_glyph), param);
1022
345
    }
1023
1024
201
    return true;
1025
201
  }
CFF::subr_subsetter_t<cff1_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned short, 2u> >, OT::cff1::accelerator_subset_t const, CFF::cff1_cs_interp_env_t, cff1_cs_opset_subr_subset_t, 14u>::closure_subroutines(CFF::parsed_cs_str_vec_t const&, hb_vector_t<CFF::parsed_cs_str_vec_t, false> const&)
Line
Count
Source
1003
117
  {
1004
117
    closures.reset ();
1005
117
    for (auto _ : plan->new_to_old_gid_list)
1006
237
    {
1007
237
      hb_codepoint_t new_glyph = _.first;
1008
237
      hb_codepoint_t old_glyph = _.second;
1009
237
      unsigned int fd = acc.fdSelect->get_fd (old_glyph);
1010
237
      if (unlikely (fd >= acc.fdCount))
1011
0
        return false;
1012
1013
      // Note: const cast is safe here because the collect_subr_refs_in_str only performs a
1014
      //       closure and does not modify any of the charstrings.
1015
237
      subr_subset_param_t  param (const_cast<parsed_cs_str_t*> (&get_parsed_charstring (new_glyph)),
1016
237
                                  const_cast<parsed_cs_str_vec_t*> (&global_subrs),
1017
237
                                  const_cast<parsed_cs_str_vec_t*> (&local_subrs[fd]),
1018
237
                                  &closures.global_closure,
1019
237
                                  &closures.local_closures[fd],
1020
237
                                  plan->flags & HB_SUBSET_FLAGS_NO_HINTING);
1021
237
      collect_subr_refs_in_str (get_parsed_charstring (new_glyph), param);
1022
237
    }
1023
1024
117
    return true;
1025
117
  }
CFF::subr_subsetter_t<cff2_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned int, 4u> >, OT::cff2::accelerator_subset_t const, CFF::cff2_cs_interp_env_t<CFF::blend_arg_t>, cff2_cs_opset_subr_subset_t, 65535u>::closure_subroutines(CFF::parsed_cs_str_vec_t const&, hb_vector_t<CFF::parsed_cs_str_vec_t, false> const&)
Line
Count
Source
1003
84
  {
1004
84
    closures.reset ();
1005
84
    for (auto _ : plan->new_to_old_gid_list)
1006
108
    {
1007
108
      hb_codepoint_t new_glyph = _.first;
1008
108
      hb_codepoint_t old_glyph = _.second;
1009
108
      unsigned int fd = acc.fdSelect->get_fd (old_glyph);
1010
108
      if (unlikely (fd >= acc.fdCount))
1011
0
        return false;
1012
1013
      // Note: const cast is safe here because the collect_subr_refs_in_str only performs a
1014
      //       closure and does not modify any of the charstrings.
1015
108
      subr_subset_param_t  param (const_cast<parsed_cs_str_t*> (&get_parsed_charstring (new_glyph)),
1016
108
                                  const_cast<parsed_cs_str_vec_t*> (&global_subrs),
1017
108
                                  const_cast<parsed_cs_str_vec_t*> (&local_subrs[fd]),
1018
108
                                  &closures.global_closure,
1019
108
                                  &closures.local_closures[fd],
1020
108
                                  plan->flags & HB_SUBSET_FLAGS_NO_HINTING);
1021
108
      collect_subr_refs_in_str (get_parsed_charstring (new_glyph), param);
1022
108
    }
1023
1024
84
    return true;
1025
84
  }
1026
1027
  void collect_subr_refs_in_subr (unsigned int subr_num, parsed_cs_str_vec_t &subrs,
1028
          hb_set_t *closure,
1029
          const subr_subset_param_t &param)
1030
359
  {
1031
359
    if (closure->has (subr_num))
1032
86
      return;
1033
273
    closure->add (subr_num);
1034
273
    collect_subr_refs_in_str (subrs[subr_num], param);
1035
273
  }
CFF::subr_subsetter_t<cff1_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned short, 2u> >, OT::cff1::accelerator_subset_t const, CFF::cff1_cs_interp_env_t, cff1_cs_opset_subr_subset_t, 14u>::collect_subr_refs_in_subr(unsigned int, CFF::parsed_cs_str_vec_t&, hb_set_t*, CFF::subr_subset_param_t const&)
Line
Count
Source
1030
135
  {
1031
135
    if (closure->has (subr_num))
1032
34
      return;
1033
101
    closure->add (subr_num);
1034
101
    collect_subr_refs_in_str (subrs[subr_num], param);
1035
101
  }
CFF::subr_subsetter_t<cff2_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned int, 4u> >, OT::cff2::accelerator_subset_t const, CFF::cff2_cs_interp_env_t<CFF::blend_arg_t>, cff2_cs_opset_subr_subset_t, 65535u>::collect_subr_refs_in_subr(unsigned int, CFF::parsed_cs_str_vec_t&, hb_set_t*, CFF::subr_subset_param_t const&)
Line
Count
Source
1030
224
  {
1031
224
    if (closure->has (subr_num))
1032
52
      return;
1033
172
    closure->add (subr_num);
1034
172
    collect_subr_refs_in_str (subrs[subr_num], param);
1035
172
  }
1036
1037
  void collect_subr_refs_in_str (const parsed_cs_str_t &str,
1038
                                 const subr_subset_param_t &param)
1039
618
  {
1040
618
    if (!str.has_calls ())
1041
361
      return;
1042
1043
257
    for (auto &opstr : str.values)
1044
3.24k
    {
1045
3.24k
      if (!param.drop_hints || !opstr.is_hinting ())
1046
2.43k
      {
1047
2.43k
  switch (opstr.op)
1048
2.43k
  {
1049
253
    case OpCode_callsubr:
1050
253
      collect_subr_refs_in_subr (opstr.subr_num, *param.parsed_local_subrs,
1051
253
               param.local_closure, param);
1052
253
      break;
1053
1054
106
    case OpCode_callgsubr:
1055
106
      collect_subr_refs_in_subr (opstr.subr_num, *param.parsed_global_subrs,
1056
106
               param.global_closure, param);
1057
106
      break;
1058
1059
2.07k
    default: break;
1060
2.43k
  }
1061
2.43k
      }
1062
3.24k
    }
1063
257
  }
CFF::subr_subsetter_t<cff1_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned short, 2u> >, OT::cff1::accelerator_subset_t const, CFF::cff1_cs_interp_env_t, cff1_cs_opset_subr_subset_t, 14u>::collect_subr_refs_in_str(CFF::parsed_cs_str_t const&, CFF::subr_subset_param_t const&)
Line
Count
Source
1039
338
  {
1040
338
    if (!str.has_calls ())
1041
200
      return;
1042
1043
138
    for (auto &opstr : str.values)
1044
471
    {
1045
471
      if (!param.drop_hints || !opstr.is_hinting ())
1046
324
      {
1047
324
  switch (opstr.op)
1048
324
  {
1049
64
    case OpCode_callsubr:
1050
64
      collect_subr_refs_in_subr (opstr.subr_num, *param.parsed_local_subrs,
1051
64
               param.local_closure, param);
1052
64
      break;
1053
1054
71
    case OpCode_callgsubr:
1055
71
      collect_subr_refs_in_subr (opstr.subr_num, *param.parsed_global_subrs,
1056
71
               param.global_closure, param);
1057
71
      break;
1058
1059
189
    default: break;
1060
324
  }
1061
324
      }
1062
471
    }
1063
138
  }
CFF::subr_subsetter_t<cff2_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned int, 4u> >, OT::cff2::accelerator_subset_t const, CFF::cff2_cs_interp_env_t<CFF::blend_arg_t>, cff2_cs_opset_subr_subset_t, 65535u>::collect_subr_refs_in_str(CFF::parsed_cs_str_t const&, CFF::subr_subset_param_t const&)
Line
Count
Source
1039
280
  {
1040
280
    if (!str.has_calls ())
1041
161
      return;
1042
1043
119
    for (auto &opstr : str.values)
1044
2.76k
    {
1045
2.76k
      if (!param.drop_hints || !opstr.is_hinting ())
1046
2.11k
      {
1047
2.11k
  switch (opstr.op)
1048
2.11k
  {
1049
189
    case OpCode_callsubr:
1050
189
      collect_subr_refs_in_subr (opstr.subr_num, *param.parsed_local_subrs,
1051
189
               param.local_closure, param);
1052
189
      break;
1053
1054
35
    case OpCode_callgsubr:
1055
35
      collect_subr_refs_in_subr (opstr.subr_num, *param.parsed_global_subrs,
1056
35
               param.global_closure, param);
1057
35
      break;
1058
1059
1.88k
    default: break;
1060
2.11k
  }
1061
2.11k
      }
1062
2.76k
    }
1063
119
  }
1064
1065
  bool encode_str (const parsed_cs_str_t &str, const unsigned int fd, str_buff_t &buff, bool encode_prefix = true) const
1066
5.09k
  {
1067
5.09k
    str_encoder_t  encoder (buff);
1068
5.09k
    encoder.reset ();
1069
5.09k
    bool hinting = !(plan->flags & HB_SUBSET_FLAGS_NO_HINTING);
1070
    /* if a prefix (CFF1 width or CFF2 vsindex) has been removed along with hints,
1071
     * re-insert it at the beginning of charstreing */
1072
5.09k
    if (encode_prefix && str.has_prefix () && !hinting && str.is_hint_dropped ())
1073
42
    {
1074
42
      encoder.encode_num_cs (str.prefix_num ());
1075
42
      if (str.prefix_op () != OpCode_Invalid)
1076
4
  encoder.encode_op (str.prefix_op ());
1077
42
    }
1078
1079
5.09k
    unsigned size = 0;
1080
5.09k
    for (auto &opstr : str.values)
1081
43.0k
    {
1082
43.0k
      size += opstr.length;
1083
43.0k
      if (opstr.op == OpCode_callsubr || opstr.op == OpCode_callgsubr)
1084
4.15k
        size += 3;
1085
43.0k
    }
1086
5.09k
    if (!buff.alloc (buff.length + size, true))
1087
4
      return false;
1088
1089
5.08k
    for (auto &opstr : str.values)
1090
43.0k
    {
1091
43.0k
      if (hinting || !opstr.is_hinting ())
1092
41.4k
      {
1093
41.4k
  switch (opstr.op)
1094
41.4k
  {
1095
2.83k
    case OpCode_callsubr:
1096
2.83k
      encoder.encode_int (remaps.local_remaps[fd].biased_num (opstr.subr_num));
1097
2.83k
      encoder.copy_str (opstr.ptr, opstr.length);
1098
2.83k
      break;
1099
1100
1.02k
    case OpCode_callgsubr:
1101
1.02k
      encoder.encode_int (remaps.global_remap.biased_num (opstr.subr_num));
1102
1.02k
      encoder.copy_str (opstr.ptr, opstr.length);
1103
1.02k
      break;
1104
1105
37.6k
    default:
1106
37.6k
      encoder.copy_str (opstr.ptr, opstr.length);
1107
37.6k
      break;
1108
41.4k
  }
1109
41.4k
      }
1110
43.0k
    }
1111
5.08k
    return !encoder.in_error ();
1112
5.08k
  }
CFF::subr_subsetter_t<cff1_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned short, 2u> >, OT::cff1::accelerator_subset_t const, CFF::cff1_cs_interp_env_t, cff1_cs_opset_subr_subset_t, 14u>::encode_str(CFF::parsed_cs_str_t const&, unsigned int, hb_vector_t<unsigned char, false>&, bool) const
Line
Count
Source
1066
2.37k
  {
1067
2.37k
    str_encoder_t  encoder (buff);
1068
2.37k
    encoder.reset ();
1069
2.37k
    bool hinting = !(plan->flags & HB_SUBSET_FLAGS_NO_HINTING);
1070
    /* if a prefix (CFF1 width or CFF2 vsindex) has been removed along with hints,
1071
     * re-insert it at the beginning of charstreing */
1072
2.37k
    if (encode_prefix && str.has_prefix () && !hinting && str.is_hint_dropped ())
1073
38
    {
1074
38
      encoder.encode_num_cs (str.prefix_num ());
1075
38
      if (str.prefix_op () != OpCode_Invalid)
1076
0
  encoder.encode_op (str.prefix_op ());
1077
38
    }
1078
1079
2.37k
    unsigned size = 0;
1080
2.37k
    for (auto &opstr : str.values)
1081
20.6k
    {
1082
20.6k
      size += opstr.length;
1083
20.6k
      if (opstr.op == OpCode_callsubr || opstr.op == OpCode_callgsubr)
1084
1.50k
        size += 3;
1085
20.6k
    }
1086
2.37k
    if (!buff.alloc (buff.length + size, true))
1087
2
      return false;
1088
1089
2.37k
    for (auto &opstr : str.values)
1090
20.6k
    {
1091
20.6k
      if (hinting || !opstr.is_hinting ())
1092
19.9k
      {
1093
19.9k
  switch (opstr.op)
1094
19.9k
  {
1095
611
    case OpCode_callsubr:
1096
611
      encoder.encode_int (remaps.local_remaps[fd].biased_num (opstr.subr_num));
1097
611
      encoder.copy_str (opstr.ptr, opstr.length);
1098
611
      break;
1099
1100
854
    case OpCode_callgsubr:
1101
854
      encoder.encode_int (remaps.global_remap.biased_num (opstr.subr_num));
1102
854
      encoder.copy_str (opstr.ptr, opstr.length);
1103
854
      break;
1104
1105
18.4k
    default:
1106
18.4k
      encoder.copy_str (opstr.ptr, opstr.length);
1107
18.4k
      break;
1108
19.9k
  }
1109
19.9k
      }
1110
20.6k
    }
1111
2.37k
    return !encoder.in_error ();
1112
2.37k
  }
CFF::subr_subsetter_t<cff2_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned int, 4u> >, OT::cff2::accelerator_subset_t const, CFF::cff2_cs_interp_env_t<CFF::blend_arg_t>, cff2_cs_opset_subr_subset_t, 65535u>::encode_str(CFF::parsed_cs_str_t const&, unsigned int, hb_vector_t<unsigned char, false>&, bool) const
Line
Count
Source
1066
2.71k
  {
1067
2.71k
    str_encoder_t  encoder (buff);
1068
2.71k
    encoder.reset ();
1069
2.71k
    bool hinting = !(plan->flags & HB_SUBSET_FLAGS_NO_HINTING);
1070
    /* if a prefix (CFF1 width or CFF2 vsindex) has been removed along with hints,
1071
     * re-insert it at the beginning of charstreing */
1072
2.71k
    if (encode_prefix && str.has_prefix () && !hinting && str.is_hint_dropped ())
1073
4
    {
1074
4
      encoder.encode_num_cs (str.prefix_num ());
1075
4
      if (str.prefix_op () != OpCode_Invalid)
1076
4
  encoder.encode_op (str.prefix_op ());
1077
4
    }
1078
1079
2.71k
    unsigned size = 0;
1080
2.71k
    for (auto &opstr : str.values)
1081
22.3k
    {
1082
22.3k
      size += opstr.length;
1083
22.3k
      if (opstr.op == OpCode_callsubr || opstr.op == OpCode_callgsubr)
1084
2.65k
        size += 3;
1085
22.3k
    }
1086
2.71k
    if (!buff.alloc (buff.length + size, true))
1087
2
      return false;
1088
1089
2.71k
    for (auto &opstr : str.values)
1090
22.3k
    {
1091
22.3k
      if (hinting || !opstr.is_hinting ())
1092
21.5k
      {
1093
21.5k
  switch (opstr.op)
1094
21.5k
  {
1095
2.22k
    case OpCode_callsubr:
1096
2.22k
      encoder.encode_int (remaps.local_remaps[fd].biased_num (opstr.subr_num));
1097
2.22k
      encoder.copy_str (opstr.ptr, opstr.length);
1098
2.22k
      break;
1099
1100
167
    case OpCode_callgsubr:
1101
167
      encoder.encode_int (remaps.global_remap.biased_num (opstr.subr_num));
1102
167
      encoder.copy_str (opstr.ptr, opstr.length);
1103
167
      break;
1104
1105
19.1k
    default:
1106
19.1k
      encoder.copy_str (opstr.ptr, opstr.length);
1107
19.1k
      break;
1108
21.5k
  }
1109
21.5k
      }
1110
22.3k
    }
1111
2.71k
    return !encoder.in_error ();
1112
2.71k
  }
1113
1114
  void compact_parsed_subrs () const
1115
0
  {
1116
0
    for (auto &cs : parsed_global_subrs_storage)
1117
0
      cs.compact ();
1118
0
    for (auto &vec : parsed_local_subrs_storage)
1119
0
      for (auto &cs : vec)
1120
0
  cs.compact ();
1121
0
  }
Unexecuted instantiation: CFF::subr_subsetter_t<cff1_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned short, 2u> >, OT::cff1::accelerator_subset_t const, CFF::cff1_cs_interp_env_t, cff1_cs_opset_subr_subset_t, 14u>::compact_parsed_subrs() const
Unexecuted instantiation: CFF::subr_subsetter_t<cff2_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned int, 4u> >, OT::cff2::accelerator_subset_t const, CFF::cff2_cs_interp_env_t<CFF::blend_arg_t>, cff2_cs_opset_subr_subset_t, 65535u>::compact_parsed_subrs() const
1122
1123
  void populate_subset_accelerator () const
1124
1.00k
  {
1125
1.00k
    if (!plan->inprogress_accelerator) return;
1126
1127
0
    compact_parsed_subrs ();
1128
1129
0
    acc.cff_accelerator =
1130
0
        cff_subset_accelerator_t::create(acc.blob,
1131
0
                                         parsed_charstrings,
1132
0
                                         parsed_global_subrs_storage,
1133
0
                                         parsed_local_subrs_storage);
1134
0
  }
CFF::subr_subsetter_t<cff1_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned short, 2u> >, OT::cff1::accelerator_subset_t const, CFF::cff1_cs_interp_env_t, cff1_cs_opset_subr_subset_t, 14u>::populate_subset_accelerator() const
Line
Count
Source
1124
542
  {
1125
542
    if (!plan->inprogress_accelerator) return;
1126
1127
0
    compact_parsed_subrs ();
1128
1129
0
    acc.cff_accelerator =
1130
0
        cff_subset_accelerator_t::create(acc.blob,
1131
0
                                         parsed_charstrings,
1132
0
                                         parsed_global_subrs_storage,
1133
0
                                         parsed_local_subrs_storage);
1134
0
  }
CFF::subr_subsetter_t<cff2_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned int, 4u> >, OT::cff2::accelerator_subset_t const, CFF::cff2_cs_interp_env_t<CFF::blend_arg_t>, cff2_cs_opset_subr_subset_t, 65535u>::populate_subset_accelerator() const
Line
Count
Source
1124
459
  {
1125
459
    if (!plan->inprogress_accelerator) return;
1126
1127
0
    compact_parsed_subrs ();
1128
1129
0
    acc.cff_accelerator =
1130
0
        cff_subset_accelerator_t::create(acc.blob,
1131
0
                                         parsed_charstrings,
1132
0
                                         parsed_global_subrs_storage,
1133
0
                                         parsed_local_subrs_storage);
1134
0
  }
1135
1136
  const parsed_cs_str_t& get_parsed_charstring (unsigned i) const
1137
3.14k
  {
1138
3.14k
    if (cached_charstrings) return *(cached_charstrings[i]);
1139
3.14k
    return parsed_charstrings[i];
1140
3.14k
  }
CFF::subr_subsetter_t<cff1_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned short, 2u> >, OT::cff1::accelerator_subset_t const, CFF::cff1_cs_interp_env_t, cff1_cs_opset_subr_subset_t, 14u>::get_parsed_charstring(unsigned int) const
Line
Count
Source
1137
1.75k
  {
1138
1.75k
    if (cached_charstrings) return *(cached_charstrings[i]);
1139
1.75k
    return parsed_charstrings[i];
1140
1.75k
  }
CFF::subr_subsetter_t<cff2_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned int, 4u> >, OT::cff2::accelerator_subset_t const, CFF::cff2_cs_interp_env_t<CFF::blend_arg_t>, cff2_cs_opset_subr_subset_t, 65535u>::get_parsed_charstring(unsigned int) const
Line
Count
Source
1137
1.38k
  {
1138
1.38k
    if (cached_charstrings) return *(cached_charstrings[i]);
1139
1.38k
    return parsed_charstrings[i];
1140
1.38k
  }
1141
1142
  protected:
1143
  const ACC     &acc;
1144
  const hb_subset_plan_t  *plan;
1145
1146
  subr_closures_t   closures;
1147
1148
  hb_vector_t<const parsed_cs_str_t*>     cached_charstrings;
1149
  const parsed_cs_str_vec_t*              parsed_global_subrs;
1150
  const hb_vector_t<parsed_cs_str_vec_t>* parsed_local_subrs;
1151
1152
  subr_remaps_t     remaps;
1153
1154
  private:
1155
1156
  parsed_cs_str_vec_t   parsed_charstrings;
1157
  parsed_cs_str_vec_t   parsed_global_subrs_storage;
1158
  hb_vector_t<parsed_cs_str_vec_t>  parsed_local_subrs_storage;
1159
  typedef typename SUBRS::count_type subr_count_type;
1160
};
1161
1162
} /* namespace CFF */
1163
1164
HB_INTERNAL bool
1165
hb_plan_subset_cff_fdselect (const hb_subset_plan_t *plan,
1166
          unsigned int fdCount,
1167
          const CFF::FDSelect &src, /* IN */
1168
          unsigned int &subset_fd_count /* OUT */,
1169
          unsigned int &subset_fdselect_size /* OUT */,
1170
          unsigned int &subset_fdselect_format /* OUT */,
1171
          hb_vector_t<CFF::code_pair_t> &fdselect_ranges /* OUT */,
1172
          hb_inc_bimap_t &fdmap /* OUT */);
1173
1174
HB_INTERNAL bool
1175
hb_serialize_cff_fdselect (hb_serialize_context_t *c,
1176
        unsigned int num_glyphs,
1177
        const CFF::FDSelect &src,
1178
        unsigned int fd_count,
1179
        unsigned int fdselect_format,
1180
        unsigned int size,
1181
        const hb_vector_t<CFF::code_pair_t> &fdselect_ranges);
1182
1183
#endif /* HB_SUBSET_CFF_COMMON_HH */