/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 */ |