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 = num_coords && coords && varStore->size; 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 if (unlikely (!scalars.resize (region_count))) 137 set_error (); 138 else 139 varStore->varStore.get_scalars (get_ivs (), coords, num_coords, 140 &scalars[0], region_count); 141 } 142 seen_blend = true; 143 } 144 } 145 process_vsindexCFF::cff2_cs_interp_env_t146 void process_vsindex () 147 { 148 unsigned int index = argStack.pop_uint (); 149 if (unlikely (seen_vsindex () || seen_blend)) 150 { 151 set_error (); 152 } 153 else 154 { 155 set_ivs (index); 156 } 157 seen_vsindex_ = true; 158 } 159 get_region_countCFF::cff2_cs_interp_env_t160 unsigned int get_region_count () const { return region_count; } set_region_countCFF::cff2_cs_interp_env_t161 void set_region_count (unsigned int region_count_) { region_count = region_count_; } get_ivsCFF::cff2_cs_interp_env_t162 unsigned int get_ivs () const { return ivs; } set_ivsCFF::cff2_cs_interp_env_t163 void set_ivs (unsigned int ivs_) { ivs = ivs_; } seen_vsindexCFF::cff2_cs_interp_env_t164 bool seen_vsindex () const { return seen_vsindex_; } 165 166 protected: blend_argCFF::cff2_cs_interp_env_t167 void blend_arg (blend_arg_t &arg) 168 { 169 if (do_blend && arg.blending ()) 170 { 171 if (likely (scalars.length == arg.deltas.length)) 172 { 173 double v = arg.to_real (); 174 for (unsigned int i = 0; i < scalars.length; i++) 175 { 176 v += (double)scalars[i] * arg.deltas[i].to_real (); 177 } 178 arg.set_real (v); 179 arg.deltas.resize (0); 180 } 181 } 182 } 183 184 protected: 185 const int *coords; 186 unsigned int num_coords; 187 const CFF2VariationStore *varStore; 188 unsigned int region_count; 189 unsigned int ivs; 190 hb_vector_t<float> scalars; 191 bool do_blend; 192 bool seen_vsindex_; 193 bool seen_blend; 194 195 typedef cs_interp_env_t<blend_arg_t, CFF2Subrs> SUPER; 196 }; 197 template <typename OPSET, typename PARAM, typename PATH=path_procs_null_t<cff2_cs_interp_env_t, PARAM>> 198 struct cff2_cs_opset_t : cs_opset_t<blend_arg_t, OPSET, cff2_cs_interp_env_t, PARAM, PATH> 199 { process_opCFF::cff2_cs_opset_t200 static void process_op (op_code_t op, cff2_cs_interp_env_t &env, PARAM& param) 201 { 202 switch (op) { 203 case OpCode_callsubr: 204 case OpCode_callgsubr: 205 /* a subroutine number shoudln't be a blended value */ 206 if (unlikely (env.argStack.peek ().blending ())) 207 { 208 env.set_error (); 209 break; 210 } 211 SUPER::process_op (op, env, param); 212 break; 213 214 case OpCode_blendcs: 215 OPSET::process_blend (env, param); 216 break; 217 218 case OpCode_vsindexcs: 219 if (unlikely (env.argStack.peek ().blending ())) 220 { 221 env.set_error (); 222 break; 223 } 224 OPSET::process_vsindex (env, param); 225 break; 226 227 default: 228 SUPER::process_op (op, env, param); 229 } 230 } 231 process_blendCFF::cff2_cs_opset_t232 static void process_blend (cff2_cs_interp_env_t &env, PARAM& param) 233 { 234 unsigned int n, k; 235 236 env.process_blend (); 237 k = env.get_region_count (); 238 n = env.argStack.pop_uint (); 239 /* copy the blend values into blend array of the default values */ 240 unsigned int start = env.argStack.get_count () - ((k+1) * n); 241 /* let an obvious error case fail, but note CFF2 spec doesn't forbid n==0 */ 242 if (unlikely (start > env.argStack.get_count ())) 243 { 244 env.set_error (); 245 return; 246 } 247 for (unsigned int i = 0; i < n; i++) 248 { 249 const hb_array_t<const blend_arg_t> blends = env.argStack.get_subarray (start + n + (i * k)); 250 env.argStack[start + i].set_blends (n, i, k, blends); 251 } 252 253 /* pop off blend values leaving default values now adorned with blend values */ 254 env.argStack.pop (k * n); 255 } 256 process_vsindexCFF::cff2_cs_opset_t257 static void process_vsindex (cff2_cs_interp_env_t &env, PARAM& param) 258 { 259 env.process_vsindex (); 260 env.clear_args (); 261 } 262 263 private: 264 typedef cs_opset_t<blend_arg_t, OPSET, cff2_cs_interp_env_t, PARAM, PATH> SUPER; 265 }; 266 267 template <typename OPSET, typename PARAM> 268 struct cff2_cs_interpreter_t : cs_interpreter_t<cff2_cs_interp_env_t, OPSET, PARAM> {}; 269 270 } /* namespace CFF */ 271 272 #endif /* HB_CFF2_INTERP_CS_HH */ 273