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 { initCFF::blend_arg_t38 void init () 39 { 40 number_t::init (); 41 deltas.init (); 42 } 43 finiCFF::blend_arg_t44 void fini () 45 { 46 number_t::fini (); 47 deltas.fini_deep (); 48 } 49 set_intCFF::blend_arg_t50 void set_int (int v) { reset_blends (); number_t::set_int (v); } set_fixedCFF::blend_arg_t51 void set_fixed (int32_t v) { reset_blends (); number_t::set_fixed (v); } set_realCFF::blend_arg_t52 void set_real (double v) { reset_blends (); number_t::set_real (v); } 53 set_blendsCFF::blend_arg_t54 void set_blends (unsigned int numValues_, unsigned int valueIndex_, 55 unsigned int numBlends, hb_array_t<const blend_arg_t> blends_) 56 { 57 numValues = numValues_; 58 valueIndex = valueIndex_; 59 deltas.resize (numBlends); 60 for (unsigned int i = 0; i < numBlends; i++) 61 deltas[i] = blends_[i]; 62 } 63 blendingCFF::blend_arg_t64 bool blending () const { return deltas.length > 0; } reset_blendsCFF::blend_arg_t65 void reset_blends () 66 { 67 numValues = valueIndex = 0; 68 deltas.resize (0); 69 } 70 71 unsigned int numValues; 72 unsigned int valueIndex; 73 hb_vector_t<number_t> deltas; 74 }; 75 76 typedef interp_env_t<blend_arg_t> BlendInterpEnv; 77 typedef biased_subrs_t<CFF2Subrs> cff2_biased_subrs_t; 78 79 struct cff2_cs_interp_env_t : cs_interp_env_t<blend_arg_t, CFF2Subrs> 80 { 81 template <typename ACC> initCFF::cff2_cs_interp_env_t82 void init (const byte_str_t &str, ACC &acc, unsigned int fd, 83 const int *coords_=nullptr, unsigned int num_coords_=0) 84 { 85 SUPER::init (str, acc.globalSubrs, acc.privateDicts[fd].localSubrs); 86 87 coords = coords_; 88 num_coords = num_coords_; 89 varStore = acc.varStore; 90 seen_blend = false; 91 seen_vsindex_ = false; 92 scalars.init (); 93 do_blend = (coords != nullptr) && num_coords && (varStore != &Null(CFF2VariationStore)); 94 set_ivs (acc.privateDicts[fd].ivs); 95 } 96 finiCFF::cff2_cs_interp_env_t97 void fini () 98 { 99 scalars.fini (); 100 SUPER::fini (); 101 } 102 fetch_opCFF::cff2_cs_interp_env_t103 op_code_t fetch_op () 104 { 105 if (this->str_ref.avail ()) 106 return SUPER::fetch_op (); 107 108 /* make up return or endchar op */ 109 if (this->callStack.is_empty ()) 110 return OpCode_endchar; 111 else 112 return OpCode_return; 113 } 114 eval_argCFF::cff2_cs_interp_env_t115 const blend_arg_t& eval_arg (unsigned int i) 116 { 117 blend_arg_t &arg = argStack[i]; 118 blend_arg (arg); 119 return arg; 120 } 121 pop_argCFF::cff2_cs_interp_env_t122 const blend_arg_t& pop_arg () 123 { 124 blend_arg_t &arg = argStack.pop (); 125 blend_arg (arg); 126 return arg; 127 } 128 process_blendCFF::cff2_cs_interp_env_t129 void process_blend () 130 { 131 if (!seen_blend) 132 { 133 region_count = varStore->varStore.get_region_index_count (get_ivs ()); 134 if (do_blend) 135 { 136 scalars.resize (region_count); 137 varStore->varStore.get_scalars (get_ivs (), 138 (int *)coords, num_coords, 139 &scalars[0], region_count); 140 } 141 seen_blend = true; 142 } 143 } 144 process_vsindexCFF::cff2_cs_interp_env_t145 void process_vsindex () 146 { 147 unsigned int index = argStack.pop_uint (); 148 if (unlikely (seen_vsindex () || seen_blend)) 149 { 150 set_error (); 151 } 152 else 153 { 154 set_ivs (index); 155 } 156 seen_vsindex_ = true; 157 } 158 get_region_countCFF::cff2_cs_interp_env_t159 unsigned int get_region_count () const { return region_count; } set_region_countCFF::cff2_cs_interp_env_t160 void set_region_count (unsigned int region_count_) { region_count = region_count_; } get_ivsCFF::cff2_cs_interp_env_t161 unsigned int get_ivs () const { return ivs; } set_ivsCFF::cff2_cs_interp_env_t162 void set_ivs (unsigned int ivs_) { ivs = ivs_; } seen_vsindexCFF::cff2_cs_interp_env_t163 bool seen_vsindex () const { return seen_vsindex_; } 164 165 protected: blend_argCFF::cff2_cs_interp_env_t166 void blend_arg (blend_arg_t &arg) 167 { 168 if (do_blend && arg.blending ()) 169 { 170 if (likely (scalars.length == arg.deltas.length)) 171 { 172 double v = arg.to_real (); 173 for (unsigned int i = 0; i < scalars.length; i++) 174 { 175 v += (double)scalars[i] * arg.deltas[i].to_real (); 176 } 177 arg.set_real (v); 178 arg.deltas.resize (0); 179 } 180 } 181 } 182 183 protected: 184 const int *coords; 185 unsigned int num_coords; 186 const CFF2VariationStore *varStore; 187 unsigned int region_count; 188 unsigned int ivs; 189 hb_vector_t<float> scalars; 190 bool do_blend; 191 bool seen_vsindex_; 192 bool seen_blend; 193 194 typedef cs_interp_env_t<blend_arg_t, CFF2Subrs> SUPER; 195 }; 196 template <typename OPSET, typename PARAM, typename PATH=path_procs_null_t<cff2_cs_interp_env_t, PARAM>> 197 struct cff2_cs_opset_t : cs_opset_t<blend_arg_t, OPSET, cff2_cs_interp_env_t, PARAM, PATH> 198 { process_opCFF::cff2_cs_opset_t199 static void process_op (op_code_t op, cff2_cs_interp_env_t &env, PARAM& param) 200 { 201 switch (op) { 202 case OpCode_callsubr: 203 case OpCode_callgsubr: 204 /* a subroutine number shoudln't be a blended value */ 205 if (unlikely (env.argStack.peek ().blending ())) 206 { 207 env.set_error (); 208 break; 209 } 210 SUPER::process_op (op, env, param); 211 break; 212 213 case OpCode_blendcs: 214 OPSET::process_blend (env, param); 215 break; 216 217 case OpCode_vsindexcs: 218 if (unlikely (env.argStack.peek ().blending ())) 219 { 220 env.set_error (); 221 break; 222 } 223 OPSET::process_vsindex (env, param); 224 break; 225 226 default: 227 SUPER::process_op (op, env, param); 228 } 229 } 230 process_blendCFF::cff2_cs_opset_t231 static void process_blend (cff2_cs_interp_env_t &env, PARAM& param) 232 { 233 unsigned int n, k; 234 235 env.process_blend (); 236 k = env.get_region_count (); 237 n = env.argStack.pop_uint (); 238 /* copy the blend values into blend array of the default values */ 239 unsigned int start = env.argStack.get_count () - ((k+1) * n); 240 /* let an obvious error case fail, but note CFF2 spec doesn't forbid n==0 */ 241 if (unlikely (start > env.argStack.get_count ())) 242 { 243 env.set_error (); 244 return; 245 } 246 for (unsigned int i = 0; i < n; i++) 247 { 248 const hb_array_t<const blend_arg_t> blends = env.argStack.get_subarray (start + n + (i * k)); 249 env.argStack[start + i].set_blends (n, i, k, blends); 250 } 251 252 /* pop off blend values leaving default values now adorned with blend values */ 253 env.argStack.pop (k * n); 254 } 255 process_vsindexCFF::cff2_cs_opset_t256 static void process_vsindex (cff2_cs_interp_env_t &env, PARAM& param) 257 { 258 env.process_vsindex (); 259 env.clear_args (); 260 } 261 262 private: 263 typedef cs_opset_t<blend_arg_t, OPSET, cff2_cs_interp_env_t, PARAM, PATH> SUPER; 264 }; 265 266 template <typename OPSET, typename PARAM> 267 struct cff2_cs_interpreter_t : cs_interpreter_t<cff2_cs_interp_env_t, OPSET, PARAM> {}; 268 269 } /* namespace CFF */ 270 271 #endif /* HB_CFF2_INTERP_CS_HH */ 272