/* * Copyright © 2018 Adobe Inc. * * This is part of HarfBuzz, a text shaping library. * * Permission is hereby granted, without written agreement and without * license or royalty fees, to use, copy, modify, and distribute this * software and its documentation for any purpose, provided that the * above copyright notice and the following two paragraphs appear in * all copies of this software. * * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. * * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. * * Adobe Author(s): Michiharu Ariza */ #ifndef HB_CFF_INTERP_DICT_COMMON_HH #define HB_CFF_INTERP_DICT_COMMON_HH #include "hb-cff-interp-common.hh" #include namespace CFF { using namespace OT; /* an opstr and the parsed out dict value(s) */ struct DictVal : OpStr { inline void init (void) { single_val.set_int (0); } inline void fini (void) { } Number single_val; }; typedef DictVal NumDictVal; template struct DictValues : ParsedValues {}; template struct TopDictValues : DictValues { inline void init (void) { DictValues::init (); charStringsOffset = 0; FDArrayOffset = 0; } inline void fini (void) { DictValues::fini (); } inline unsigned int calculate_serialized_op_size (const OPSTR& opstr) const { switch (opstr.op) { case OpCode_CharStrings: case OpCode_FDArray: return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (opstr.op); default: return opstr.str.len; } } unsigned int charStringsOffset; unsigned int FDArrayOffset; }; struct DictOpSet : OpSet { static inline void process_op (OpCode op, InterpEnv& env) { switch (op) { case OpCode_longintdict: /* 5-byte integer */ env.argStack.push_longint_from_substr (env.substr); break; case OpCode_BCD: /* real number */ env.argStack.push_real (parse_bcd (env.substr)); break; default: OpSet::process_op (op, env); break; } } static inline float parse_bcd (SubByteStr& substr) { float v = 0.0f; bool neg = false; double int_part = 0; long frac_part = 0; unsigned int frac_count = 0; bool exp_neg = false; unsigned int exp_part = 0; enum Part { INT_PART=0, FRAC_PART, EXP_PART } part = INT_PART; enum Nibble { DECIMAL=10, EXP_POS, EXP_NEG, RESERVED, NEG, END }; double value = 0.0; unsigned char byte = 0; for (unsigned int i = 0;; i++) { char d; if ((i & 1) == 0) { if (!substr.avail ()) { substr.set_error (); return 0.0f; } byte = substr[0]; substr.inc (); d = byte >> 4; } else d = byte & 0x0F; switch (d) { case RESERVED: substr.set_error (); return v; case END: value = (double)(neg? -int_part: int_part); if (frac_count > 0) value += (frac_part / pow (10.0, (double)frac_count)); if (exp_part != 0) { if (exp_neg) value /= pow (10.0, (double)exp_part); else value *= pow (10.0, (double)exp_part); } return (float)value; case NEG: if (i != 0) { substr.set_error (); return 0.0f; } neg = true; break; case DECIMAL: if (part != INT_PART) { substr.set_error (); return v; } part = FRAC_PART; break; case EXP_NEG: exp_neg = true; HB_FALLTHROUGH; case EXP_POS: if (part == EXP_PART) { substr.set_error (); return v; } part = EXP_PART; break; default: switch (part) { default: case INT_PART: int_part = (int_part * 10) + d; break; case FRAC_PART: frac_part = (frac_part * 10) + d; frac_count++; break; case EXP_PART: exp_part = (exp_part * 10) + d; break; } } } return v; } static inline bool is_hint_op (OpCode op) { switch (op) { case OpCode_BlueValues: case OpCode_OtherBlues: case OpCode_FamilyBlues: case OpCode_FamilyOtherBlues: case OpCode_StemSnapH: case OpCode_StemSnapV: case OpCode_StdHW: case OpCode_StdVW: case OpCode_BlueScale: case OpCode_BlueShift: case OpCode_BlueFuzz: case OpCode_ForceBold: case OpCode_LanguageGroup: case OpCode_ExpansionFactor: return true; default: return false; } } }; template struct TopDictOpSet : DictOpSet { static inline void process_op (OpCode op, InterpEnv& env, TopDictValues & dictval) { switch (op) { case OpCode_CharStrings: dictval.charStringsOffset = env.argStack.pop_uint (); env.clear_args (); break; case OpCode_FDArray: dictval.FDArrayOffset = env.argStack.pop_uint (); env.clear_args (); break; case OpCode_FontMatrix: env.clear_args (); break; default: DictOpSet::process_op (op, env); break; } } }; template struct DictInterpreter : Interpreter { inline bool interpret (PARAM& param) { param.init (); while (SUPER::env.substr.avail ()) { OPSET::process_op (SUPER::env.fetch_op (), SUPER::env, param); if (unlikely (SUPER::env.in_error ())) return false; } return true; } private: typedef Interpreter SUPER; }; } /* namespace CFF */ #endif /* HB_CFF_INTERP_DICT_COMMON_HH */