Coverage Report

Created: 2023-12-14 16:39

/src/harfbuzz/src/hb-cff2-interp-cs.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
#ifndef HB_CFF2_INTERP_CS_HH
27
#define HB_CFF2_INTERP_CS_HH
28
29
#include "hb.hh"
30
#include "hb-cff-interp-cs-common.hh"
31
32
namespace CFF {
33
34
using namespace OT;
35
36
struct blend_arg_t : number_t
37
{
38
0
  void set_int (int v) { reset_blends (); number_t::set_int (v); }
39
0
  void set_fixed (int32_t v) { reset_blends (); number_t::set_fixed (v); }
40
0
  void set_real (double v) { reset_blends (); number_t::set_real (v); }
41
42
  void set_blends (unsigned int numValues_, unsigned int valueIndex_,
43
       unsigned int numBlends, hb_array_t<const blend_arg_t> blends_)
44
0
  {
45
0
    numValues = numValues_;
46
0
    valueIndex = valueIndex_;
47
0
    deltas.resize (numBlends);
48
0
    for (unsigned int i = 0; i < numBlends; i++)
49
0
      deltas[i] = blends_[i];
50
0
  }
51
52
0
  bool blending () const { return deltas.length > 0; }
53
  void reset_blends ()
54
0
  {
55
0
    numValues = valueIndex = 0;
56
0
    deltas.resize (0);
57
0
  }
58
59
  unsigned int numValues;
60
  unsigned int valueIndex;
61
  hb_vector_t<number_t> deltas;
62
};
63
64
typedef interp_env_t<blend_arg_t> BlendInterpEnv;
65
typedef biased_subrs_t<CFF2Subrs>   cff2_biased_subrs_t;
66
67
template <typename ELEM>
68
struct cff2_cs_interp_env_t : cs_interp_env_t<ELEM, CFF2Subrs>
69
{
70
  template <typename ACC>
71
  cff2_cs_interp_env_t (const hb_ubytes_t &str, ACC &acc, unsigned int fd,
72
      const int *coords_=nullptr, unsigned int num_coords_=0)
73
    : SUPER (str, acc.globalSubrs, acc.privateDicts[fd].localSubrs)
74
34.1k
  {
75
34.1k
    coords = coords_;
76
34.1k
    num_coords = num_coords_;
77
34.1k
    varStore = acc.varStore;
78
34.1k
    seen_blend = false;
79
34.1k
    seen_vsindex_ = false;
80
34.1k
    scalars.init ();
81
34.1k
    do_blend = num_coords && coords && varStore->size;
82
34.1k
    set_ivs (acc.privateDicts[fd].ivs);
83
34.1k
  }
84
85
  void fini ()
86
  {
87
    scalars.fini ();
88
    SUPER::fini ();
89
  }
90
91
  op_code_t fetch_op ()
92
12.6M
  {
93
12.6M
    if (this->str_ref.avail ())
94
12.4M
      return SUPER::fetch_op ();
95
96
    /* make up return or endchar op */
97
270k
    if (this->callStack.is_empty ())
98
12.3k
      return OpCode_endchar;
99
258k
    else
100
258k
      return OpCode_return;
101
270k
  }
102
103
  const ELEM& eval_arg (unsigned int i)
104
5.90M
  {
105
5.90M
    return SUPER::argStack[i];
106
5.90M
  }
107
108
  const ELEM& pop_arg ()
109
153k
  {
110
153k
    return SUPER::argStack.pop ();
111
153k
  }
112
113
  void process_blend ()
114
391k
  {
115
391k
    if (!seen_blend)
116
30.4k
    {
117
30.4k
      region_count = varStore->varStore.get_region_index_count (get_ivs ());
118
30.4k
      if (do_blend)
119
1.54k
      {
120
1.54k
  if (unlikely (!scalars.resize (region_count)))
121
38
    SUPER::set_error ();
122
1.50k
  else
123
1.50k
    varStore->varStore.get_region_scalars (get_ivs (), coords, num_coords,
124
1.50k
             &scalars[0], region_count);
125
1.54k
      }
126
30.4k
      seen_blend = true;
127
30.4k
    }
128
391k
  }
129
130
  void process_vsindex ()
131
1.93k
  {
132
1.93k
    unsigned int  index = SUPER::argStack.pop_uint ();
133
1.93k
    if (unlikely (seen_vsindex () || seen_blend))
134
843
    {
135
843
     SUPER::set_error ();
136
843
    }
137
1.09k
    else
138
1.09k
    {
139
1.09k
      set_ivs (index);
140
1.09k
    }
141
1.93k
    seen_vsindex_ = true;
142
1.93k
  }
143
144
391k
  unsigned int get_region_count () const { return region_count; }
145
  void   set_region_count (unsigned int region_count_) { region_count = region_count_; }
146
31.9k
  unsigned int get_ivs () const { return ivs; }
147
35.2k
  void   set_ivs (unsigned int ivs_) { ivs = ivs_; }
148
1.93k
  bool   seen_vsindex () const { return seen_vsindex_; }
149
150
  double blend_deltas (hb_array_t<const ELEM> deltas) const
151
1.10M
  {
152
1.10M
    double v = 0;
153
1.10M
    if (do_blend)
154
37.8k
    {
155
37.8k
      if (likely (scalars.length == deltas.length))
156
37.8k
      {
157
97.7k
  for (unsigned int i = 0; i < scalars.length; i++)
158
59.8k
    v += (double) scalars[i] * deltas[i].to_real ();
159
37.8k
      }
160
37.8k
    }
161
1.10M
    return v;
162
1.10M
  }
163
164
  protected:
165
  const int     *coords;
166
  unsigned int  num_coords;
167
  const  CFF2VariationStore *varStore;
168
  unsigned int  region_count;
169
  unsigned int  ivs;
170
  hb_vector_t<float>  scalars;
171
  bool    do_blend;
172
  bool    seen_vsindex_;
173
  bool    seen_blend;
174
175
  typedef cs_interp_env_t<ELEM, CFF2Subrs> SUPER;
176
};
177
template <typename OPSET, typename PARAM, typename ELEM, typename PATH=path_procs_null_t<cff2_cs_interp_env_t<ELEM>, PARAM>>
178
struct cff2_cs_opset_t : cs_opset_t<ELEM, OPSET, cff2_cs_interp_env_t<ELEM>, PARAM, PATH>
179
{
180
  static void process_op (op_code_t op, cff2_cs_interp_env_t<ELEM> &env, PARAM& param)
181
12.6M
  {
182
12.6M
    switch (op) {
183
183k
      case OpCode_callsubr:
184
302k
      case OpCode_callgsubr:
185
  /* a subroutine number shouldn't be a blended value */
186
#if 0
187
  if (unlikely (env.argStack.peek ().blending ()))
188
  {
189
    env.set_error ();
190
    break;
191
  }
192
#endif
193
302k
  SUPER::process_op (op, env, param);
194
302k
  break;
195
196
391k
      case OpCode_blendcs:
197
391k
  OPSET::process_blend (env, param);
198
391k
  break;
199
200
1.93k
      case OpCode_vsindexcs:
201
#if 0
202
  if (unlikely (env.argStack.peek ().blending ()))
203
  {
204
    env.set_error ();
205
    break;
206
  }
207
#endif
208
1.93k
  OPSET::process_vsindex (env, param);
209
1.93k
  break;
210
211
11.9M
      default:
212
11.9M
  SUPER::process_op (op, env, param);
213
12.6M
    }
214
12.6M
  }
CFF::cff2_cs_opset_t<cff2_cs_opset_extents_t, cff2_extents_param_t, CFF::number_t, cff2_path_procs_extents_t>::process_op(unsigned int, CFF::cff2_cs_interp_env_t<CFF::number_t>&, cff2_extents_param_t&)
Line
Count
Source
181
7.91M
  {
182
7.91M
    switch (op) {
183
119k
      case OpCode_callsubr:
184
188k
      case OpCode_callgsubr:
185
  /* a subroutine number shouldn't be a blended value */
186
#if 0
187
  if (unlikely (env.argStack.peek ().blending ()))
188
  {
189
    env.set_error ();
190
    break;
191
  }
192
#endif
193
188k
  SUPER::process_op (op, env, param);
194
188k
  break;
195
196
256k
      case OpCode_blendcs:
197
256k
  OPSET::process_blend (env, param);
198
256k
  break;
199
200
1.36k
      case OpCode_vsindexcs:
201
#if 0
202
  if (unlikely (env.argStack.peek ().blending ()))
203
  {
204
    env.set_error ();
205
    break;
206
  }
207
#endif
208
1.36k
  OPSET::process_vsindex (env, param);
209
1.36k
  break;
210
211
7.47M
      default:
212
7.47M
  SUPER::process_op (op, env, param);
213
7.91M
    }
214
7.91M
  }
CFF::cff2_cs_opset_t<cff2_cs_opset_path_t, cff2_path_param_t, CFF::number_t, cff2_path_procs_path_t>::process_op(unsigned int, CFF::cff2_cs_interp_env_t<CFF::number_t>&, cff2_path_param_t&)
Line
Count
Source
181
4.75M
  {
182
4.75M
    switch (op) {
183
64.4k
      case OpCode_callsubr:
184
114k
      case OpCode_callgsubr:
185
  /* a subroutine number shouldn't be a blended value */
186
#if 0
187
  if (unlikely (env.argStack.peek ().blending ()))
188
  {
189
    env.set_error ();
190
    break;
191
  }
192
#endif
193
114k
  SUPER::process_op (op, env, param);
194
114k
  break;
195
196
135k
      case OpCode_blendcs:
197
135k
  OPSET::process_blend (env, param);
198
135k
  break;
199
200
571
      case OpCode_vsindexcs:
201
#if 0
202
  if (unlikely (env.argStack.peek ().blending ()))
203
  {
204
    env.set_error ();
205
    break;
206
  }
207
#endif
208
571
  OPSET::process_vsindex (env, param);
209
571
  break;
210
211
4.50M
      default:
212
4.50M
  SUPER::process_op (op, env, param);
213
4.75M
    }
214
4.75M
  }
215
216
  template <typename T = ELEM,
217
      hb_enable_if (hb_is_same (T, blend_arg_t))>
218
  static void process_arg_blend (cff2_cs_interp_env_t<ELEM> &env,
219
         ELEM &arg,
220
         const hb_array_t<const ELEM> blends,
221
         unsigned n, unsigned i)
222
  {
223
    arg.set_blends (n, i, blends.length, blends);
224
  }
225
  template <typename T = ELEM,
226
      hb_enable_if (!hb_is_same (T, blend_arg_t))>
227
  static void process_arg_blend (cff2_cs_interp_env_t<ELEM> &env,
228
         ELEM &arg,
229
         const hb_array_t<const ELEM> blends,
230
         unsigned n, unsigned i)
231
1.10M
  {
232
1.10M
    arg.set_real (arg.to_real () + env.blend_deltas (blends));
233
1.10M
  }
void CFF::cff2_cs_opset_t<cff2_cs_opset_extents_t, cff2_extents_param_t, CFF::number_t, cff2_path_procs_extents_t>::process_arg_blend<CFF::number_t, (void*)0>(CFF::cff2_cs_interp_env_t<CFF::number_t>&, CFF::number_t&, hb_array_t<CFF::number_t const>, unsigned int, unsigned int)
Line
Count
Source
231
723k
  {
232
723k
    arg.set_real (arg.to_real () + env.blend_deltas (blends));
233
723k
  }
void CFF::cff2_cs_opset_t<cff2_cs_opset_path_t, cff2_path_param_t, CFF::number_t, cff2_path_procs_path_t>::process_arg_blend<CFF::number_t, (void*)0>(CFF::cff2_cs_interp_env_t<CFF::number_t>&, CFF::number_t&, hb_array_t<CFF::number_t const>, unsigned int, unsigned int)
Line
Count
Source
231
377k
  {
232
377k
    arg.set_real (arg.to_real () + env.blend_deltas (blends));
233
377k
  }
234
235
  static void process_blend (cff2_cs_interp_env_t<ELEM> &env, PARAM& param)
236
391k
  {
237
391k
    unsigned int n, k;
238
239
391k
    env.process_blend ();
240
391k
    k = env.get_region_count ();
241
391k
    n = env.argStack.pop_uint ();
242
    /* copy the blend values into blend array of the default values */
243
391k
    unsigned int start = env.argStack.get_count () - ((k+1) * n);
244
    /* let an obvious error case fail, but note CFF2 spec doesn't forbid n==0 */
245
391k
    if (unlikely (start > env.argStack.get_count ()))
246
4.94k
    {
247
4.94k
      env.set_error ();
248
4.94k
      return;
249
4.94k
    }
250
1.48M
    for (unsigned int i = 0; i < n; i++)
251
1.10M
    {
252
1.10M
      const hb_array_t<const ELEM> blends = env.argStack.sub_array (start + n + (i * k), k);
253
1.10M
      process_arg_blend (env, env.argStack[start + i], blends, n, i);
254
1.10M
    }
255
256
    /* pop off blend values leaving default values now adorned with blend values */
257
386k
    env.argStack.pop (k * n);
258
386k
  }
CFF::cff2_cs_opset_t<cff2_cs_opset_extents_t, cff2_extents_param_t, CFF::number_t, cff2_path_procs_extents_t>::process_blend(CFF::cff2_cs_interp_env_t<CFF::number_t>&, cff2_extents_param_t&)
Line
Count
Source
236
256k
  {
237
256k
    unsigned int n, k;
238
239
256k
    env.process_blend ();
240
256k
    k = env.get_region_count ();
241
256k
    n = env.argStack.pop_uint ();
242
    /* copy the blend values into blend array of the default values */
243
256k
    unsigned int start = env.argStack.get_count () - ((k+1) * n);
244
    /* let an obvious error case fail, but note CFF2 spec doesn't forbid n==0 */
245
256k
    if (unlikely (start > env.argStack.get_count ()))
246
3.37k
    {
247
3.37k
      env.set_error ();
248
3.37k
      return;
249
3.37k
    }
250
977k
    for (unsigned int i = 0; i < n; i++)
251
723k
    {
252
723k
      const hb_array_t<const ELEM> blends = env.argStack.sub_array (start + n + (i * k), k);
253
723k
      process_arg_blend (env, env.argStack[start + i], blends, n, i);
254
723k
    }
255
256
    /* pop off blend values leaving default values now adorned with blend values */
257
253k
    env.argStack.pop (k * n);
258
253k
  }
CFF::cff2_cs_opset_t<cff2_cs_opset_path_t, cff2_path_param_t, CFF::number_t, cff2_path_procs_path_t>::process_blend(CFF::cff2_cs_interp_env_t<CFF::number_t>&, cff2_path_param_t&)
Line
Count
Source
236
135k
  {
237
135k
    unsigned int n, k;
238
239
135k
    env.process_blend ();
240
135k
    k = env.get_region_count ();
241
135k
    n = env.argStack.pop_uint ();
242
    /* copy the blend values into blend array of the default values */
243
135k
    unsigned int start = env.argStack.get_count () - ((k+1) * n);
244
    /* let an obvious error case fail, but note CFF2 spec doesn't forbid n==0 */
245
135k
    if (unlikely (start > env.argStack.get_count ()))
246
1.57k
    {
247
1.57k
      env.set_error ();
248
1.57k
      return;
249
1.57k
    }
250
511k
    for (unsigned int i = 0; i < n; i++)
251
377k
    {
252
377k
      const hb_array_t<const ELEM> blends = env.argStack.sub_array (start + n + (i * k), k);
253
377k
      process_arg_blend (env, env.argStack[start + i], blends, n, i);
254
377k
    }
255
256
    /* pop off blend values leaving default values now adorned with blend values */
257
133k
    env.argStack.pop (k * n);
258
133k
  }
259
260
  static void process_vsindex (cff2_cs_interp_env_t<ELEM> &env, PARAM& param)
261
1.93k
  {
262
1.93k
    env.process_vsindex ();
263
1.93k
    env.clear_args ();
264
1.93k
  }
CFF::cff2_cs_opset_t<cff2_cs_opset_extents_t, cff2_extents_param_t, CFF::number_t, cff2_path_procs_extents_t>::process_vsindex(CFF::cff2_cs_interp_env_t<CFF::number_t>&, cff2_extents_param_t&)
Line
Count
Source
261
1.36k
  {
262
1.36k
    env.process_vsindex ();
263
1.36k
    env.clear_args ();
264
1.36k
  }
CFF::cff2_cs_opset_t<cff2_cs_opset_path_t, cff2_path_param_t, CFF::number_t, cff2_path_procs_path_t>::process_vsindex(CFF::cff2_cs_interp_env_t<CFF::number_t>&, cff2_path_param_t&)
Line
Count
Source
261
571
  {
262
571
    env.process_vsindex ();
263
571
    env.clear_args ();
264
571
  }
265
266
  private:
267
  typedef cs_opset_t<ELEM, OPSET, cff2_cs_interp_env_t<ELEM>, PARAM, PATH>  SUPER;
268
};
269
270
template <typename OPSET, typename PARAM, typename ELEM>
271
using cff2_cs_interpreter_t = cs_interpreter_t<cff2_cs_interp_env_t<ELEM>, OPSET, PARAM>;
272
273
} /* namespace CFF */
274
275
#endif /* HB_CFF2_INTERP_CS_HH */