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_CFF_INTERP_DICT_COMMON_HH 27 #define HB_CFF_INTERP_DICT_COMMON_HH 28 29 #include "hb-cff-interp-common.hh" 30 #include <math.h> 31 #include <float.h> 32 33 namespace CFF { 34 35 using namespace OT; 36 37 /* an opstr and the parsed out dict value(s) */ 38 struct dict_val_t : op_str_t 39 { initCFF::dict_val_t40 void init () { single_val.set_int (0); } finiCFF::dict_val_t41 void fini () {} 42 43 number_t single_val; 44 }; 45 46 typedef dict_val_t num_dict_val_t; 47 48 template <typename VAL> struct dict_values_t : parsed_values_t<VAL> {}; 49 50 template <typename OPSTR=op_str_t> 51 struct top_dict_values_t : dict_values_t<OPSTR> 52 { initCFF::top_dict_values_t53 void init () 54 { 55 dict_values_t<OPSTR>::init (); 56 charStringsOffset = 0; 57 FDArrayOffset = 0; 58 } finiCFF::top_dict_values_t59 void fini () { dict_values_t<OPSTR>::fini (); } 60 calculate_serialized_op_sizeCFF::top_dict_values_t61 unsigned int calculate_serialized_op_size (const OPSTR& opstr) const 62 { 63 switch (opstr.op) 64 { 65 case OpCode_CharStrings: 66 case OpCode_FDArray: 67 return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (opstr.op); 68 69 default: 70 return opstr.str.length; 71 } 72 } 73 74 unsigned int charStringsOffset; 75 unsigned int FDArrayOffset; 76 }; 77 78 struct dict_opset_t : opset_t<number_t> 79 { process_opCFF::dict_opset_t80 static void process_op (op_code_t op, interp_env_t<number_t>& env) 81 { 82 switch (op) { 83 case OpCode_longintdict: /* 5-byte integer */ 84 env.argStack.push_longint_from_substr (env.str_ref); 85 break; 86 87 case OpCode_BCD: /* real number */ 88 env.argStack.push_real (parse_bcd (env.str_ref)); 89 break; 90 91 default: 92 opset_t<number_t>::process_op (op, env); 93 break; 94 } 95 } 96 97 /* Turns CFF's BCD format into strtod understandable string */ parse_bcdCFF::dict_opset_t98 static double parse_bcd (byte_str_ref_t& str_ref) 99 { 100 if (unlikely (str_ref.in_error ())) return .0; 101 102 enum Nibble { DECIMAL=10, EXP_POS, EXP_NEG, RESERVED, NEG, END }; 103 104 char buf[32]; 105 unsigned char byte = 0; 106 for (unsigned i = 0, count = 0; count < ARRAY_LENGTH (buf); ++i, ++count) 107 { 108 unsigned nibble; 109 if (!(i & 1)) 110 { 111 if (unlikely (!str_ref.avail ())) break; 112 113 byte = str_ref[0]; 114 str_ref.inc (); 115 nibble = byte >> 4; 116 } 117 else 118 nibble = byte & 0x0F; 119 120 if (unlikely (nibble == RESERVED)) break; 121 else if (nibble == END) 122 { 123 const char *p = buf; 124 double pv; 125 if (unlikely (!hb_parse_double (&p, p + count, &pv, true/* whole buffer */))) 126 break; 127 return pv; 128 } 129 else 130 { 131 buf[count] = "0123456789.EE?-?"[nibble]; 132 if (nibble == EXP_NEG) 133 { 134 ++count; 135 if (unlikely (count == ARRAY_LENGTH (buf))) break; 136 buf[count] = '-'; 137 } 138 } 139 } 140 141 str_ref.set_error (); 142 return .0; 143 } 144 is_hint_opCFF::dict_opset_t145 static bool is_hint_op (op_code_t op) 146 { 147 switch (op) 148 { 149 case OpCode_BlueValues: 150 case OpCode_OtherBlues: 151 case OpCode_FamilyBlues: 152 case OpCode_FamilyOtherBlues: 153 case OpCode_StemSnapH: 154 case OpCode_StemSnapV: 155 case OpCode_StdHW: 156 case OpCode_StdVW: 157 case OpCode_BlueScale: 158 case OpCode_BlueShift: 159 case OpCode_BlueFuzz: 160 case OpCode_ForceBold: 161 case OpCode_LanguageGroup: 162 case OpCode_ExpansionFactor: 163 return true; 164 default: 165 return false; 166 } 167 } 168 }; 169 170 template <typename VAL=op_str_t> 171 struct top_dict_opset_t : dict_opset_t 172 { process_opCFF::top_dict_opset_t173 static void process_op (op_code_t op, interp_env_t<number_t>& env, top_dict_values_t<VAL> & dictval) 174 { 175 switch (op) { 176 case OpCode_CharStrings: 177 dictval.charStringsOffset = env.argStack.pop_uint (); 178 env.clear_args (); 179 break; 180 case OpCode_FDArray: 181 dictval.FDArrayOffset = env.argStack.pop_uint (); 182 env.clear_args (); 183 break; 184 case OpCode_FontMatrix: 185 env.clear_args (); 186 break; 187 default: 188 dict_opset_t::process_op (op, env); 189 break; 190 } 191 } 192 }; 193 194 template <typename OPSET, typename PARAM, typename ENV=num_interp_env_t> 195 struct dict_interpreter_t : interpreter_t<ENV> 196 { interpretCFF::dict_interpreter_t197 bool interpret (PARAM& param) 198 { 199 param.init (); 200 while (SUPER::env.str_ref.avail ()) 201 { 202 OPSET::process_op (SUPER::env.fetch_op (), SUPER::env, param); 203 if (unlikely (SUPER::env.in_error ())) 204 return false; 205 } 206 207 return true; 208 } 209 210 private: 211 typedef interpreter_t<ENV> SUPER; 212 }; 213 214 } /* namespace CFF */ 215 216 #endif /* HB_CFF_INTERP_DICT_COMMON_HH */ 217