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 () {} finiCFF::dict_val_t39 void fini () {} 40 }; 41 42 typedef dict_val_t num_dict_val_t; 43 44 template <typename VAL> struct dict_values_t : parsed_values_t<VAL> {}; 45 46 template <typename OPSTR=op_str_t> 47 struct top_dict_values_t : dict_values_t<OPSTR> 48 { initCFF::top_dict_values_t49 void init () 50 { 51 dict_values_t<OPSTR>::init (); 52 charStringsOffset = 0; 53 FDArrayOffset = 0; 54 } finiCFF::top_dict_values_t55 void fini () { dict_values_t<OPSTR>::fini (); } 56 57 int charStringsOffset; 58 int FDArrayOffset; 59 }; 60 61 struct dict_opset_t : opset_t<number_t> 62 { process_opCFF::dict_opset_t63 static void process_op (op_code_t op, interp_env_t<number_t>& env) 64 { 65 switch (op) { 66 case OpCode_longintdict: /* 5-byte integer */ 67 env.argStack.push_longint_from_substr (env.str_ref); 68 break; 69 70 case OpCode_BCD: /* real number */ 71 env.argStack.push_real (parse_bcd (env.str_ref)); 72 break; 73 74 default: 75 opset_t<number_t>::process_op (op, env); 76 break; 77 } 78 } 79 80 /* Turns CFF's BCD format into strtod understandable string */ parse_bcdCFF::dict_opset_t81 static double parse_bcd (byte_str_ref_t& str_ref) 82 { 83 if (unlikely (str_ref.in_error ())) return .0; 84 85 enum Nibble { DECIMAL=10, EXP_POS, EXP_NEG, RESERVED, NEG, END }; 86 87 char buf[32] = {0}; 88 unsigned char byte = 0; 89 for (unsigned i = 0, count = 0; count < ARRAY_LENGTH (buf); ++i, ++count) 90 { 91 unsigned nibble; 92 if (!(i & 1)) 93 { 94 if (unlikely (!str_ref.avail ())) break; 95 96 byte = str_ref[0]; 97 str_ref.inc (); 98 nibble = byte >> 4; 99 } 100 else 101 nibble = byte & 0x0F; 102 103 if (unlikely (nibble == RESERVED)) break; 104 else if (nibble == END) 105 { 106 const char *p = buf; 107 double pv; 108 if (unlikely (!hb_parse_double (&p, p + count, &pv, true/* whole buffer */))) 109 break; 110 return pv; 111 } 112 else 113 { 114 buf[count] = "0123456789.EE?-?"[nibble]; 115 if (nibble == EXP_NEG) 116 { 117 ++count; 118 if (unlikely (count == ARRAY_LENGTH (buf))) break; 119 buf[count] = '-'; 120 } 121 } 122 } 123 124 str_ref.set_error (); 125 return .0; 126 } 127 is_hint_opCFF::dict_opset_t128 static bool is_hint_op (op_code_t op) 129 { 130 switch (op) 131 { 132 case OpCode_BlueValues: 133 case OpCode_OtherBlues: 134 case OpCode_FamilyBlues: 135 case OpCode_FamilyOtherBlues: 136 case OpCode_StemSnapH: 137 case OpCode_StemSnapV: 138 case OpCode_StdHW: 139 case OpCode_StdVW: 140 case OpCode_BlueScale: 141 case OpCode_BlueShift: 142 case OpCode_BlueFuzz: 143 case OpCode_ForceBold: 144 case OpCode_LanguageGroup: 145 case OpCode_ExpansionFactor: 146 return true; 147 default: 148 return false; 149 } 150 } 151 }; 152 153 template <typename VAL=op_str_t> 154 struct top_dict_opset_t : dict_opset_t 155 { process_opCFF::top_dict_opset_t156 static void process_op (op_code_t op, interp_env_t<number_t>& env, top_dict_values_t<VAL> & dictval) 157 { 158 switch (op) { 159 case OpCode_CharStrings: 160 dictval.charStringsOffset = env.argStack.pop_int (); 161 env.clear_args (); 162 break; 163 case OpCode_FDArray: 164 dictval.FDArrayOffset = env.argStack.pop_int (); 165 env.clear_args (); 166 break; 167 case OpCode_FontMatrix: 168 env.clear_args (); 169 break; 170 default: 171 dict_opset_t::process_op (op, env); 172 break; 173 } 174 } 175 }; 176 177 template <typename OPSET, typename PARAM, typename ENV=num_interp_env_t> 178 struct dict_interpreter_t : interpreter_t<ENV> 179 { dict_interpreter_tCFF::dict_interpreter_t180 dict_interpreter_t (ENV& env_) : interpreter_t<ENV> (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