Home | History | Annotate | Download | only in src
      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 DictVal : OpStr
     39 {
     40   void init () { single_val.set_int (0); }
     41   void fini () {}
     42 
     43   Number	      single_val;
     44 };
     45 
     46 typedef DictVal NumDictVal;
     47 
     48 template <typename VAL> struct DictValues : ParsedValues<VAL> {};
     49 
     50 template <typename OPSTR=OpStr>
     51 struct TopDictValues : DictValues<OPSTR>
     52 {
     53   void init ()
     54   {
     55     DictValues<OPSTR>::init ();
     56     charStringsOffset = 0;
     57     FDArrayOffset = 0;
     58   }
     59   void fini () { DictValues<OPSTR>::fini (); }
     60 
     61   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.len;
     71     }
     72   }
     73 
     74   unsigned int  charStringsOffset;
     75   unsigned int  FDArrayOffset;
     76 };
     77 
     78 struct DictOpSet : OpSet<Number>
     79 {
     80   static void process_op (OpCode op, InterpEnv<Number>& env)
     81   {
     82     switch (op) {
     83       case OpCode_longintdict:  /* 5-byte integer */
     84 	env.argStack.push_longint_from_substr (env.substr);
     85 	break;
     86 
     87       case OpCode_BCD:  /* real number */
     88 	env.argStack.push_real (parse_bcd (env.substr));
     89 	break;
     90 
     91       default:
     92 	OpSet<Number>::process_op (op, env);
     93 	break;
     94     }
     95   }
     96 
     97   static double parse_bcd (SubByteStr& substr)
     98   {
     99     bool    neg = false;
    100     double  int_part = 0;
    101     uint64_t frac_part = 0;
    102     uint32_t  frac_count = 0;
    103     bool    exp_neg = false;
    104     uint32_t  exp_part = 0;
    105     bool    exp_overflow = false;
    106     enum Part { INT_PART=0, FRAC_PART, EXP_PART } part = INT_PART;
    107     enum Nibble { DECIMAL=10, EXP_POS, EXP_NEG, RESERVED, NEG, END };
    108     const uint64_t MAX_FRACT = 0xFFFFFFFFFFFFFull; /* 1^52-1 */
    109     const uint32_t MAX_EXP = 0x7FFu; /* 1^11-1 */
    110 
    111     double  value = 0.0;
    112     unsigned char byte = 0;
    113     for (uint32_t i = 0;; i++)
    114     {
    115       char d;
    116       if ((i & 1) == 0)
    117       {
    118 	if (!substr.avail ())
    119 	{
    120 	  substr.set_error ();
    121 	  return 0.0;
    122 	}
    123 	byte = substr[0];
    124 	substr.inc ();
    125 	d = byte >> 4;
    126       }
    127       else
    128 	d = byte & 0x0F;
    129 
    130       switch (d)
    131       {
    132 	case RESERVED:
    133 	  substr.set_error ();
    134 	  return value;
    135 
    136 	case END:
    137 	  value = (double)(neg? -int_part: int_part);
    138 	  if (frac_count > 0)
    139 	  {
    140 	    double frac = (frac_part / pow (10.0, (double)frac_count));
    141 	    if (neg) frac = -frac;
    142 	    value += frac;
    143 	  }
    144 	  if (unlikely (exp_overflow))
    145 	  {
    146 	    if (value == 0.0)
    147 	      return value;
    148 	    if (exp_neg)
    149 	      return neg? -DBL_MIN: DBL_MIN;
    150 	    else
    151 	      return neg? -DBL_MAX: DBL_MAX;
    152 	  }
    153 	  if (exp_part != 0)
    154 	  {
    155 	    if (exp_neg)
    156 	      value /= pow (10.0, (double)exp_part);
    157 	    else
    158 	      value *= pow (10.0, (double)exp_part);
    159 	  }
    160 	  return value;
    161 
    162 	case NEG:
    163 	  if (i != 0)
    164 	  {
    165 	    substr.set_error ();
    166 	    return 0.0;
    167 	  }
    168 	  neg = true;
    169 	  break;
    170 
    171 	case DECIMAL:
    172 	  if (part != INT_PART)
    173 	  {
    174 	    substr.set_error ();
    175 	    return value;
    176 	  }
    177 	  part = FRAC_PART;
    178 	  break;
    179 
    180 	case EXP_NEG:
    181 	  exp_neg = true;
    182 	  HB_FALLTHROUGH;
    183 
    184 	case EXP_POS:
    185 	  if (part == EXP_PART)
    186 	  {
    187 	    substr.set_error ();
    188 	    return value;
    189 	  }
    190 	  part = EXP_PART;
    191 	  break;
    192 
    193 	default:
    194 	  switch (part) {
    195 	    default:
    196 	    case INT_PART:
    197 	      int_part = (int_part * 10) + d;
    198 	      break;
    199 
    200 	    case FRAC_PART:
    201 	      if (likely (frac_part <= MAX_FRACT / 10))
    202 	      {
    203 		frac_part = (frac_part * 10) + (unsigned)d;
    204 		frac_count++;
    205 	      }
    206 	      break;
    207 
    208 	    case EXP_PART:
    209 	      if (likely (exp_part * 10 + d <= MAX_EXP))
    210 	      {
    211 	      	exp_part = (exp_part * 10) + d;
    212 	      }
    213 	      else
    214 	      	exp_overflow = true;
    215 	      break;
    216 	  }
    217       }
    218     }
    219 
    220     return value;
    221   }
    222 
    223   static bool is_hint_op (OpCode op)
    224   {
    225     switch (op)
    226     {
    227       case OpCode_BlueValues:
    228       case OpCode_OtherBlues:
    229       case OpCode_FamilyBlues:
    230       case OpCode_FamilyOtherBlues:
    231       case OpCode_StemSnapH:
    232       case OpCode_StemSnapV:
    233       case OpCode_StdHW:
    234       case OpCode_StdVW:
    235       case OpCode_BlueScale:
    236       case OpCode_BlueShift:
    237       case OpCode_BlueFuzz:
    238       case OpCode_ForceBold:
    239       case OpCode_LanguageGroup:
    240       case OpCode_ExpansionFactor:
    241 	return true;
    242       default:
    243 	return false;
    244     }
    245   }
    246 };
    247 
    248 template <typename VAL=OpStr>
    249 struct TopDictOpSet : DictOpSet
    250 {
    251   static void process_op (OpCode op, InterpEnv<Number>& env, TopDictValues<VAL> & dictval)
    252   {
    253     switch (op) {
    254       case OpCode_CharStrings:
    255 	dictval.charStringsOffset = env.argStack.pop_uint ();
    256 	env.clear_args ();
    257 	break;
    258       case OpCode_FDArray:
    259 	dictval.FDArrayOffset = env.argStack.pop_uint ();
    260 	env.clear_args ();
    261 	break;
    262       case OpCode_FontMatrix:
    263 	env.clear_args ();
    264 	break;
    265       default:
    266 	DictOpSet::process_op (op, env);
    267 	break;
    268     }
    269   }
    270 };
    271 
    272 template <typename OPSET, typename PARAM, typename ENV=NumInterpEnv>
    273 struct DictInterpreter : Interpreter<ENV>
    274 {
    275   bool interpret (PARAM& param)
    276   {
    277     param.init ();
    278     while (SUPER::env.substr.avail ())
    279     {
    280       OPSET::process_op (SUPER::env.fetch_op (), SUPER::env, param);
    281       if (unlikely (SUPER::env.in_error ()))
    282 	return false;
    283     }
    284 
    285     return true;
    286   }
    287 
    288   private:
    289   typedef Interpreter<ENV> SUPER;
    290 };
    291 
    292 } /* namespace CFF */
    293 
    294 #endif /* HB_CFF_INTERP_DICT_COMMON_HH */
    295