comparison mupdf-source/thirdparty/harfbuzz/src/hb-cff2-interp-cs.hh @ 2:b50eed0cc0ef upstream

ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4. The directory name has changed: no version number in the expanded directory now.
author Franz Glasner <fzglas.hg@dom66.de>
date Mon, 15 Sep 2025 11:43:07 +0200
parents
children
comparison
equal deleted inserted replaced
1:1d09e1dec1d9 2:b50eed0cc0ef
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 void set_int (int v) { reset_blends (); number_t::set_int (v); }
39 void set_fixed (int32_t v) { reset_blends (); number_t::set_fixed (v); }
40 void set_real (double v) { reset_blends (); number_t::set_real (v); }
41
42 void set_blends (unsigned int numValues_, unsigned int valueIndex_,
43 hb_array_t<const blend_arg_t> blends_)
44 {
45 numValues = numValues_;
46 valueIndex = valueIndex_;
47 unsigned numBlends = blends_.length;
48 if (unlikely (!deltas.resize (numBlends)))
49 return;
50 for (unsigned int i = 0; i < numBlends; i++)
51 deltas.arrayZ[i] = blends_.arrayZ[i];
52 }
53
54 bool blending () const { return deltas.length > 0; }
55 void reset_blends ()
56 {
57 numValues = valueIndex = 0;
58 deltas.resize (0);
59 }
60
61 unsigned int numValues;
62 unsigned int valueIndex;
63 hb_vector_t<number_t> deltas;
64 };
65
66 typedef biased_subrs_t<CFF2Subrs> cff2_biased_subrs_t;
67
68 template <typename ELEM>
69 struct cff2_cs_interp_env_t : cs_interp_env_t<ELEM, CFF2Subrs>
70 {
71 template <typename ACC>
72 cff2_cs_interp_env_t (const hb_ubytes_t &str, ACC &acc, unsigned int fd,
73 const int *coords_=nullptr, unsigned int num_coords_=0)
74 : SUPER (str, acc.globalSubrs, acc.privateDicts[fd].localSubrs)
75 {
76 coords = coords_;
77 num_coords = num_coords_;
78 varStore = acc.varStore;
79 seen_blend = false;
80 seen_vsindex_ = false;
81 scalars.init ();
82 do_blend = num_coords && coords && varStore->size;
83 set_ivs (acc.privateDicts[fd].ivs);
84 }
85
86 void fini ()
87 {
88 scalars.fini ();
89 SUPER::fini ();
90 }
91
92 op_code_t fetch_op ()
93 {
94 if (this->str_ref.avail ())
95 return SUPER::fetch_op ();
96
97 /* make up return or endchar op */
98 if (this->callStack.is_empty ())
99 return OpCode_endchar;
100 else
101 return OpCode_return;
102 }
103
104 const ELEM& eval_arg (unsigned int i)
105 {
106 return SUPER::argStack[i];
107 }
108
109 const ELEM& pop_arg ()
110 {
111 return SUPER::argStack.pop ();
112 }
113
114 void process_blend ()
115 {
116 if (!seen_blend)
117 {
118 region_count = varStore->varStore.get_region_index_count (get_ivs ());
119 if (do_blend)
120 {
121 if (unlikely (!scalars.resize (region_count)))
122 SUPER::set_error ();
123 else
124 varStore->varStore.get_region_scalars (get_ivs (), coords, num_coords,
125 &scalars[0], region_count);
126 }
127 seen_blend = true;
128 }
129 }
130
131 void process_vsindex ()
132 {
133 unsigned int index = SUPER::argStack.pop_uint ();
134 if (unlikely (seen_vsindex () || seen_blend))
135 {
136 SUPER::set_error ();
137 }
138 else
139 {
140 set_ivs (index);
141 }
142 seen_vsindex_ = true;
143 }
144
145 unsigned int get_region_count () const { return region_count; }
146 void set_region_count (unsigned int region_count_) { region_count = region_count_; }
147 unsigned int get_ivs () const { return ivs; }
148 void set_ivs (unsigned int ivs_) { ivs = ivs_; }
149 bool seen_vsindex () const { return seen_vsindex_; }
150
151 double blend_deltas (hb_array_t<const ELEM> deltas) const
152 {
153 double v = 0;
154 if (do_blend)
155 {
156 if (likely (scalars.length == deltas.length))
157 {
158 unsigned count = scalars.length;
159 for (unsigned i = 0; i < count; i++)
160 v += (double) scalars.arrayZ[i] * deltas.arrayZ[i].to_real ();
161 }
162 }
163 return v;
164 }
165
166 protected:
167 const int *coords;
168 unsigned int num_coords;
169 const CFF2VariationStore *varStore;
170 unsigned int region_count;
171 unsigned int ivs;
172 hb_vector_t<float> scalars;
173 bool do_blend;
174 bool seen_vsindex_;
175 bool seen_blend;
176
177 typedef cs_interp_env_t<ELEM, CFF2Subrs> SUPER;
178 };
179 template <typename OPSET, typename PARAM, typename ELEM, typename PATH=path_procs_null_t<cff2_cs_interp_env_t<ELEM>, PARAM>>
180 struct cff2_cs_opset_t : cs_opset_t<ELEM, OPSET, cff2_cs_interp_env_t<ELEM>, PARAM, PATH>
181 {
182 static void process_op (op_code_t op, cff2_cs_interp_env_t<ELEM> &env, PARAM& param)
183 {
184 switch (op) {
185 case OpCode_callsubr:
186 case OpCode_callgsubr:
187 /* a subroutine number shouldn't be a blended value */
188 #if 0
189 if (unlikely (env.argStack.peek ().blending ()))
190 {
191 env.set_error ();
192 break;
193 }
194 #endif
195 SUPER::process_op (op, env, param);
196 break;
197
198 case OpCode_blendcs:
199 OPSET::process_blend (env, param);
200 break;
201
202 case OpCode_vsindexcs:
203 #if 0
204 if (unlikely (env.argStack.peek ().blending ()))
205 {
206 env.set_error ();
207 break;
208 }
209 #endif
210 OPSET::process_vsindex (env, param);
211 break;
212
213 default:
214 SUPER::process_op (op, env, param);
215 }
216 }
217
218 template <typename T = ELEM,
219 hb_enable_if (hb_is_same (T, blend_arg_t))>
220 static void process_arg_blend (cff2_cs_interp_env_t<ELEM> &env,
221 ELEM &arg,
222 const hb_array_t<const ELEM> blends,
223 unsigned n, unsigned i)
224 {
225 arg.set_blends (n, i, blends);
226 }
227 template <typename T = ELEM,
228 hb_enable_if (!hb_is_same (T, blend_arg_t))>
229 static void process_arg_blend (cff2_cs_interp_env_t<ELEM> &env,
230 ELEM &arg,
231 const hb_array_t<const ELEM> blends,
232 unsigned n, unsigned i)
233 {
234 arg.set_real (arg.to_real () + env.blend_deltas (blends));
235 }
236
237 static void process_blend (cff2_cs_interp_env_t<ELEM> &env, PARAM& param)
238 {
239 unsigned int n, k;
240
241 env.process_blend ();
242 k = env.get_region_count ();
243 n = env.argStack.pop_uint ();
244 /* copy the blend values into blend array of the default values */
245 unsigned int start = env.argStack.get_count () - ((k+1) * n);
246 /* let an obvious error case fail, but note CFF2 spec doesn't forbid n==0 */
247 if (unlikely (start > env.argStack.get_count ()))
248 {
249 env.set_error ();
250 return;
251 }
252 for (unsigned int i = 0; i < n; i++)
253 {
254 const hb_array_t<const ELEM> blends = env.argStack.sub_array (start + n + (i * k), k);
255 process_arg_blend (env, env.argStack[start + i], blends, n, i);
256 }
257
258 /* pop off blend values leaving default values now adorned with blend values */
259 env.argStack.pop (k * n);
260 }
261
262 static void process_vsindex (cff2_cs_interp_env_t<ELEM> &env, PARAM& param)
263 {
264 env.process_vsindex ();
265 env.clear_args ();
266 }
267
268 private:
269 typedef cs_opset_t<ELEM, OPSET, cff2_cs_interp_env_t<ELEM>, PARAM, PATH> SUPER;
270 };
271
272 template <typename OPSET, typename PARAM, typename ELEM>
273 using cff2_cs_interpreter_t = cs_interpreter_t<cff2_cs_interp_env_t<ELEM>, OPSET, PARAM>;
274
275 } /* namespace CFF */
276
277 #endif /* HB_CFF2_INTERP_CS_HH */