blob: 915b10cf39a9243ddd91ae81b119e24b409b02c5 [file] [log] [blame]
Michiharu Arizacef75ea2018-08-17 13:13:18 -07001/*
Michiharu Ariza0dfa5842018-11-12 08:47:07 -08002 * Copyright © 2018 Adobe Inc.
Michiharu Arizacef75ea2018-08-17 13:13:18 -07003 *
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
Michiharu Ariza8af96902018-08-29 13:26:17 -070029#include "hb.hh"
30#include "hb-cff-interp-cs-common.hh"
Michiharu Arizacef75ea2018-08-17 13:13:18 -070031
32namespace CFF {
33
34using namespace OT;
35
Michiharu Ariza29f0b6b2018-12-22 07:47:04 -080036struct blend_arg_t : number_t
Michiharu Arizaf2d299b2018-09-04 10:25:21 -070037{
Michiharu Ariza29f0b6b2018-12-22 07:47:04 -080038 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); }
Behdad Esfahbodcb320d22023-07-27 10:43:07 -060040 void set_real (double v) { reset_blends (); number_t::set_real (v); }
Michiharu Arizaf2d299b2018-09-04 10:25:21 -070041
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +033042 void set_blends (unsigned int numValues_, unsigned int valueIndex_,
Behdad Esfahbod70d97d02022-11-26 15:16:11 -070043 hb_array_t<const blend_arg_t> blends_)
Michiharu Arizaf2d299b2018-09-04 10:25:21 -070044 {
45 numValues = numValues_;
46 valueIndex = valueIndex_;
Behdad Esfahbod70d97d02022-11-26 15:16:11 -070047 unsigned numBlends = blends_.length;
Behdad Esfahbod8f2345c2023-01-02 18:08:45 -070048 if (unlikely (!deltas.resize_exact (numBlends)))
Behdad Esfahbod4167e932022-11-26 15:14:52 -070049 return;
Michiharu Arizaf2d299b2018-09-04 10:25:21 -070050 for (unsigned int i = 0; i < numBlends; i++)
Behdad Esfahbod4167e932022-11-26 15:14:52 -070051 deltas.arrayZ[i] = blends_.arrayZ[i];
Michiharu Arizaf2d299b2018-09-04 10:25:21 -070052 }
53
Behdad Esfahbod474a1202018-12-21 18:46:51 -050054 bool blending () const { return deltas.length > 0; }
Ebrahim Byagowie4120082018-12-17 21:31:01 +033055 void reset_blends ()
Michiharu Arizaf2d299b2018-09-04 10:25:21 -070056 {
57 numValues = valueIndex = 0;
Behdad Esfahbodb1c4cb02023-01-01 18:41:19 -070058 deltas.shrink (0);
Michiharu Arizaf2d299b2018-09-04 10:25:21 -070059 }
60
61 unsigned int numValues;
62 unsigned int valueIndex;
Michiharu Ariza29f0b6b2018-12-22 07:47:04 -080063 hb_vector_t<number_t> deltas;
Michiharu Arizaf2d299b2018-09-04 10:25:21 -070064};
65
Michiharu Ariza29f0b6b2018-12-22 07:47:04 -080066typedef biased_subrs_t<CFF2Subrs> cff2_biased_subrs_t;
Michiharu Arizaf2d299b2018-09-04 10:25:21 -070067
Behdad Esfahbod0a424102022-05-10 12:05:19 -060068template <typename ELEM>
69struct cff2_cs_interp_env_t : cs_interp_env_t<ELEM, CFF2Subrs>
Michiharu Arizacef75ea2018-08-17 13:13:18 -070070{
Michiharu Arizaf2d299b2018-09-04 10:25:21 -070071 template <typename ACC>
Behdad Esfahbodbff78e62022-05-10 16:33:37 -060072 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)
Michiharu Arizacef75ea2018-08-17 13:13:18 -070075 {
Michiharu Arizab51418f2018-10-08 15:05:36 -070076 coords = coords_;
Michiharu Arizadf964a02018-10-08 15:38:05 -070077 num_coords = num_coords_;
78 varStore = acc.varStore;
Michiharu Arizab51418f2018-10-08 15:05:36 -070079 seen_blend = false;
Michiharu Ariza0996c0f2018-11-07 14:48:37 -080080 seen_vsindex_ = false;
Michiharu Arizab51418f2018-10-08 15:05:36 -070081 scalars.init ();
Ebrahim Byagowi2be859d2020-04-20 23:48:23 +043082 do_blend = num_coords && coords && varStore->size;
Michiharu Arizab51418f2018-10-08 15:05:36 -070083 set_ivs (acc.privateDicts[fd].ivs);
84 }
85
Ebrahim Byagowie4120082018-12-17 21:31:01 +033086 void fini ()
Michiharu Arizab51418f2018-10-08 15:05:36 -070087 {
88 scalars.fini ();
89 SUPER::fini ();
Michiharu Arizacef75ea2018-08-17 13:13:18 -070090 }
91
Michiharu Ariza29f0b6b2018-12-22 07:47:04 -080092 op_code_t fetch_op ()
Michiharu Arizacef75ea2018-08-17 13:13:18 -070093 {
Michiharu Ariza29f0b6b2018-12-22 07:47:04 -080094 if (this->str_ref.avail ())
Michiharu Ariza7d99a6c2018-10-12 02:16:07 -070095 return SUPER::fetch_op ();
Michiharu Arizacef75ea2018-08-17 13:13:18 -070096
97 /* make up return or endchar op */
Michiharu Ariza7d99a6c2018-10-12 02:16:07 -070098 if (this->callStack.is_empty ())
99 return OpCode_endchar;
Michiharu Arizacef75ea2018-08-17 13:13:18 -0700100 else
Michiharu Ariza7d99a6c2018-10-12 02:16:07 -0700101 return OpCode_return;
Michiharu Arizacef75ea2018-08-17 13:13:18 -0700102 }
103
Behdad Esfahbod0a424102022-05-10 12:05:19 -0600104 const ELEM& eval_arg (unsigned int i)
Michiharu Arizab51418f2018-10-08 15:05:36 -0700105 {
Behdad Esfahbod0a424102022-05-10 12:05:19 -0600106 return SUPER::argStack[i];
Michiharu Arizab51418f2018-10-08 15:05:36 -0700107 }
108
Behdad Esfahbod0a424102022-05-10 12:05:19 -0600109 const ELEM& pop_arg ()
Michiharu Arizab51418f2018-10-08 15:05:36 -0700110 {
Behdad Esfahbod0a424102022-05-10 12:05:19 -0600111 return SUPER::argStack.pop ();
Michiharu Arizab51418f2018-10-08 15:05:36 -0700112 }
113
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330114 void process_blend ()
Michiharu Arizab51418f2018-10-08 15:05:36 -0700115 {
116 if (!seen_blend)
117 {
118 region_count = varStore->varStore.get_region_index_count (get_ivs ());
119 if (do_blend)
120 {
Behdad Esfahbod8f2345c2023-01-02 18:08:45 -0700121 if (unlikely (!scalars.resize_exact (region_count)))
Behdad Esfahbod0a424102022-05-10 12:05:19 -0600122 SUPER::set_error ();
Ebrahim Byagowiefd716d2020-07-31 08:58:53 +0430123 else
Behdad Esfahbodff1fe252021-07-28 18:02:52 -0600124 varStore->varStore.get_region_scalars (get_ivs (), coords, num_coords,
125 &scalars[0], region_count);
Michiharu Arizab51418f2018-10-08 15:05:36 -0700126 }
127 seen_blend = true;
128 }
129 }
130
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330131 void process_vsindex ()
Michiharu Ariza9fd08cc2018-08-29 18:18:18 -0700132 {
Behdad Esfahbod0a424102022-05-10 12:05:19 -0600133 unsigned int index = SUPER::argStack.pop_uint ();
Michiharu Ariza0996c0f2018-11-07 14:48:37 -0800134 if (unlikely (seen_vsindex () || seen_blend))
Michiharu Arizab51418f2018-10-08 15:05:36 -0700135 {
Behdad Esfahbod0a424102022-05-10 12:05:19 -0600136 SUPER::set_error ();
Michiharu Arizab51418f2018-10-08 15:05:36 -0700137 }
Michiharu Ariza0996c0f2018-11-07 14:48:37 -0800138 else
139 {
140 set_ivs (index);
141 }
142 seen_vsindex_ = true;
Michiharu Ariza9fd08cc2018-08-29 18:18:18 -0700143 }
144
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330145 unsigned int get_region_count () const { return region_count; }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330146 void set_region_count (unsigned int region_count_) { region_count = region_count_; }
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330147 unsigned int get_ivs () const { return ivs; }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330148 void set_ivs (unsigned int ivs_) { ivs = ivs_; }
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330149 bool seen_vsindex () const { return seen_vsindex_; }
Michiharu Arizacef75ea2018-08-17 13:13:18 -0700150
Behdad Esfahbodcb320d22023-07-27 10:43:07 -0600151 double blend_deltas (hb_array_t<const ELEM> deltas) const
Michiharu Arizab51418f2018-10-08 15:05:36 -0700152 {
Behdad Esfahbodcb320d22023-07-27 10:43:07 -0600153 double v = 0;
Behdad Esfahbod0a424102022-05-10 12:05:19 -0600154 if (do_blend)
Michiharu Arizab51418f2018-10-08 15:05:36 -0700155 {
Behdad Esfahbod0a424102022-05-10 12:05:19 -0600156 if (likely (scalars.length == deltas.length))
Michiharu Arizab51418f2018-10-08 15:05:36 -0700157 {
Behdad Esfahbodf159bf02022-11-26 15:11:32 -0700158 unsigned count = scalars.length;
159 for (unsigned i = 0; i < count; i++)
Behdad Esfahbodcb320d22023-07-27 10:43:07 -0600160 v += (double) scalars.arrayZ[i] * deltas.arrayZ[i].to_real ();
Michiharu Arizab51418f2018-10-08 15:05:36 -0700161 }
162 }
Behdad Esfahbod0a424102022-05-10 12:05:19 -0600163 return v;
Michiharu Arizab51418f2018-10-08 15:05:36 -0700164 }
165
Behdad Esfahbod76879c52023-01-06 11:47:04 -0700166 bool have_coords () const { return num_coords; }
167
168 protected:
Michiharu Arizab51418f2018-10-08 15:05:36 -0700169 const int *coords;
170 unsigned int num_coords;
Behdad Esfahbod825df6d2018-11-30 23:04:59 -0500171 const CFF2VariationStore *varStore;
Michiharu Arizaf2d299b2018-09-04 10:25:21 -0700172 unsigned int region_count;
Michiharu Arizab51418f2018-10-08 15:05:36 -0700173 unsigned int ivs;
174 hb_vector_t<float> scalars;
Behdad Esfahbod825df6d2018-11-30 23:04:59 -0500175 bool do_blend;
176 bool seen_vsindex_;
177 bool seen_blend;
Michiharu Arizafcf17782018-08-31 16:28:47 -0700178
Behdad Esfahbod0a424102022-05-10 12:05:19 -0600179 typedef cs_interp_env_t<ELEM, CFF2Subrs> SUPER;
Michiharu Arizacef75ea2018-08-17 13:13:18 -0700180};
Behdad Esfahbod0a424102022-05-10 12:05:19 -0600181template <typename OPSET, typename PARAM, typename ELEM, typename PATH=path_procs_null_t<cff2_cs_interp_env_t<ELEM>, PARAM>>
182struct cff2_cs_opset_t : cs_opset_t<ELEM, OPSET, cff2_cs_interp_env_t<ELEM>, PARAM, PATH>
Michiharu Arizacef75ea2018-08-17 13:13:18 -0700183{
Behdad Esfahbod0a424102022-05-10 12:05:19 -0600184 static void process_op (op_code_t op, cff2_cs_interp_env_t<ELEM> &env, PARAM& param)
Michiharu Arizacef75ea2018-08-17 13:13:18 -0700185 {
186 switch (op) {
Michiharu Arizaf2d299b2018-09-04 10:25:21 -0700187 case OpCode_callsubr:
188 case OpCode_callgsubr:
luz paze2e30502022-01-16 07:00:53 -0500189 /* a subroutine number shouldn't be a blended value */
Behdad Esfahbod0a424102022-05-10 12:05:19 -0600190#if 0
Behdad Esfahbod825df6d2018-11-30 23:04:59 -0500191 if (unlikely (env.argStack.peek ().blending ()))
192 {
193 env.set_error ();
194 break;
195 }
Behdad Esfahbod0a424102022-05-10 12:05:19 -0600196#endif
Behdad Esfahbod825df6d2018-11-30 23:04:59 -0500197 SUPER::process_op (op, env, param);
198 break;
Michiharu Arizacef75ea2018-08-17 13:13:18 -0700199
200 case OpCode_blendcs:
Behdad Esfahbod825df6d2018-11-30 23:04:59 -0500201 OPSET::process_blend (env, param);
202 break;
Michiharu Ariza9fd08cc2018-08-29 18:18:18 -0700203
Michiharu Arizacef75ea2018-08-17 13:13:18 -0700204 case OpCode_vsindexcs:
Behdad Esfahbod0a424102022-05-10 12:05:19 -0600205#if 0
Behdad Esfahbod825df6d2018-11-30 23:04:59 -0500206 if (unlikely (env.argStack.peek ().blending ()))
207 {
208 env.set_error ();
209 break;
210 }
Behdad Esfahbod0a424102022-05-10 12:05:19 -0600211#endif
Behdad Esfahbod825df6d2018-11-30 23:04:59 -0500212 OPSET::process_vsindex (env, param);
213 break;
Michiharu Ariza9fd08cc2018-08-29 18:18:18 -0700214
Michiharu Arizacef75ea2018-08-17 13:13:18 -0700215 default:
Behdad Esfahbod825df6d2018-11-30 23:04:59 -0500216 SUPER::process_op (op, env, param);
Michiharu Arizacef75ea2018-08-17 13:13:18 -0700217 }
Michiharu Arizacef75ea2018-08-17 13:13:18 -0700218 }
Michiharu Ariza9fd08cc2018-08-29 18:18:18 -0700219
Behdad Esfahbod0a424102022-05-10 12:05:19 -0600220 template <typename T = ELEM,
221 hb_enable_if (hb_is_same (T, blend_arg_t))>
222 static void process_arg_blend (cff2_cs_interp_env_t<ELEM> &env,
223 ELEM &arg,
224 const hb_array_t<const ELEM> blends,
225 unsigned n, unsigned i)
226 {
Behdad Esfahbod76879c52023-01-06 11:47:04 -0700227 if (env.have_coords ())
Behdad Esfahbod4867e0b2023-01-06 11:39:13 -0700228 arg.set_int (round (arg.to_real () + env.blend_deltas (blends)));
229 else
230 arg.set_blends (n, i, blends);
Behdad Esfahbod0a424102022-05-10 12:05:19 -0600231 }
232 template <typename T = ELEM,
233 hb_enable_if (!hb_is_same (T, blend_arg_t))>
234 static void process_arg_blend (cff2_cs_interp_env_t<ELEM> &env,
235 ELEM &arg,
236 const hb_array_t<const ELEM> blends,
237 unsigned n, unsigned i)
238 {
Behdad Esfahbod576b36a2023-01-06 11:40:21 -0700239 arg.set_real (arg.to_real () + env.blend_deltas (blends));
Behdad Esfahbod0a424102022-05-10 12:05:19 -0600240 }
241
242 static void process_blend (cff2_cs_interp_env_t<ELEM> &env, PARAM& param)
Michiharu Ariza9fd08cc2018-08-29 18:18:18 -0700243 {
Michiharu Arizaf2d299b2018-09-04 10:25:21 -0700244 unsigned int n, k;
245
Michiharu Arizab51418f2018-10-08 15:05:36 -0700246 env.process_blend ();
Michiharu Arizaf2d299b2018-09-04 10:25:21 -0700247 k = env.get_region_count ();
Michiharu Ariza7d99a6c2018-10-12 02:16:07 -0700248 n = env.argStack.pop_uint ();
Michiharu Ariza59345cd2018-12-06 13:36:26 -0800249 /* copy the blend values into blend array of the default values */
250 unsigned int start = env.argStack.get_count () - ((k+1) * n);
251 /* let an obvious error case fail, but note CFF2 spec doesn't forbid n==0 */
252 if (unlikely (start > env.argStack.get_count ()))
Michiharu Ariza14d29a12018-12-05 21:33:29 -0800253 {
254 env.set_error ();
255 return;
256 }
Michiharu Arizaf2d299b2018-09-04 10:25:21 -0700257 for (unsigned int i = 0; i < n; i++)
Michiharu Ariza59345cd2018-12-06 13:36:26 -0800258 {
Behdad Esfahbod0a424102022-05-10 12:05:19 -0600259 const hb_array_t<const ELEM> blends = env.argStack.sub_array (start + n + (i * k), k);
260 process_arg_blend (env, env.argStack[start + i], blends, n, i);
Michiharu Ariza59345cd2018-12-06 13:36:26 -0800261 }
Michiharu Arizaf2d299b2018-09-04 10:25:21 -0700262
263 /* pop off blend values leaving default values now adorned with blend values */
Michiharu Arizac0c85b82018-09-17 11:14:56 -0700264 env.argStack.pop (k * n);
Michiharu Ariza9fd08cc2018-08-29 18:18:18 -0700265 }
266
Behdad Esfahbod0a424102022-05-10 12:05:19 -0600267 static void process_vsindex (cff2_cs_interp_env_t<ELEM> &env, PARAM& param)
Michiharu Ariza9fd08cc2018-08-29 18:18:18 -0700268 {
Michiharu Ariza968168b2018-08-31 13:28:16 -0700269 env.process_vsindex ();
Michiharu Arizaae8fd0d2018-11-07 09:16:12 -0800270 env.clear_args ();
Michiharu Ariza9fd08cc2018-08-29 18:18:18 -0700271 }
Michiharu Arizafcf17782018-08-31 16:28:47 -0700272
273 private:
Behdad Esfahbod0a424102022-05-10 12:05:19 -0600274 typedef cs_opset_t<ELEM, OPSET, cff2_cs_interp_env_t<ELEM>, PARAM, PATH> SUPER;
Michiharu Arizacef75ea2018-08-17 13:13:18 -0700275};
276
Behdad Esfahbod0a424102022-05-10 12:05:19 -0600277template <typename OPSET, typename PARAM, typename ELEM>
Behdad Esfahbodbff78e62022-05-10 16:33:37 -0600278using cff2_cs_interpreter_t = cs_interpreter_t<cff2_cs_interp_env_t<ELEM>, OPSET, PARAM>;
Michiharu Arizacef75ea2018-08-17 13:13:18 -0700279
280} /* namespace CFF */
281
282#endif /* HB_CFF2_INTERP_CS_HH */