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 BlendArg : Number 37 { initCFF::BlendArg38 void init () 39 { 40 Number::init (); 41 deltas.init (); 42 } 43 finiCFF::BlendArg44 void fini () 45 { 46 Number::fini (); 47 deltas.fini_deep (); 48 } 49 set_intCFF::BlendArg50 void set_int (int v) { reset_blends (); Number::set_int (v); } set_fixedCFF::BlendArg51 void set_fixed (int32_t v) { reset_blends (); Number::set_fixed (v); } set_realCFF::BlendArg52 void set_real (double v) { reset_blends (); Number::set_real (v); } 53 set_blendsCFF::BlendArg54 void set_blends (unsigned int numValues_, unsigned int valueIndex_, 55 unsigned int numBlends, hb_array_t<const BlendArg> 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::BlendArg64 bool blending () const { return deltas.len > 0; } reset_blendsCFF::BlendArg65 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> deltas; 74 }; 75 76 typedef InterpEnv<BlendArg> BlendInterpEnv; 77 typedef BiasedSubrs<CFF2Subrs> CFF2BiasedSubrs; 78 79 struct CFF2CSInterpEnv : CSInterpEnv<BlendArg, CFF2Subrs> 80 { 81 template <typename ACC> initCFF::CFF2CSInterpEnv82 void init (const ByteStr &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::CFF2CSInterpEnv97 void fini () 98 { 99 scalars.fini (); 100 SUPER::fini (); 101 } 102 fetch_opCFF::CFF2CSInterpEnv103 OpCode fetch_op () 104 { 105 if (this->substr.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::CFF2CSInterpEnv115 const BlendArg& eval_arg (unsigned int i) 116 { 117 BlendArg &arg = argStack[i]; 118 blend_arg (arg); 119 return arg; 120 } 121 pop_argCFF::CFF2CSInterpEnv122 const BlendArg& pop_arg () 123 { 124 BlendArg &arg = argStack.pop (); 125 blend_arg (arg); 126 return arg; 127 } 128 process_blendCFF::CFF2CSInterpEnv129 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::CFF2CSInterpEnv145 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::CFF2CSInterpEnv159 unsigned int get_region_count () const { return region_count; } set_region_countCFF::CFF2CSInterpEnv160 void set_region_count (unsigned int region_count_) { region_count = region_count_; } get_ivsCFF::CFF2CSInterpEnv161 unsigned int get_ivs () const { return ivs; } set_ivsCFF::CFF2CSInterpEnv162 void set_ivs (unsigned int ivs_) { ivs = ivs_; } seen_vsindexCFF::CFF2CSInterpEnv163 bool seen_vsindex () const { return seen_vsindex_; } 164 165 protected: blend_argCFF::CFF2CSInterpEnv166 void blend_arg (BlendArg &arg) 167 { 168 if (do_blend && arg.blending ()) 169 { 170 if (likely (scalars.len == arg.deltas.len)) 171 { 172 double v = arg.to_real (); 173 for (unsigned int i = 0; i < scalars.len; 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 CSInterpEnv<BlendArg, CFF2Subrs> SUPER; 195 }; 196 template <typename OPSET, typename PARAM, typename PATH=PathProcsNull<CFF2CSInterpEnv, PARAM> > 197 struct CFF2CSOpSet : CSOpSet<BlendArg, OPSET, CFF2CSInterpEnv, PARAM, PATH> 198 { process_opCFF::CFF2CSOpSet199 static void process_op (OpCode op, CFF2CSInterpEnv &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::CFF2CSOpSet231 static void process_blend (CFF2CSInterpEnv &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 BlendArg> 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::CFF2CSOpSet256 static void process_vsindex (CFF2CSInterpEnv &env, PARAM& param) 257 { 258 env.process_vsindex (); 259 env.clear_args (); 260 } 261 262 private: 263 typedef CSOpSet<BlendArg, OPSET, CFF2CSInterpEnv, PARAM, PATH> SUPER; 264 }; 265 266 template <typename OPSET, typename PARAM> 267 struct CFF2CSInterpreter : CSInterpreter<CFF2CSInterpEnv, OPSET, PARAM> {}; 268 269 } /* namespace CFF */ 270 271 #endif /* HB_CFF2_INTERP_CS_HH */ 272