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