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_CFF1_INTERP_CS_HH
     27 #define HB_CFF1_INTERP_CS_HH
     28 
     29 #include "hb.hh"
     30 #include "hb-cff-interp-cs-common.hh"
     31 
     32 namespace CFF {
     33 
     34 using namespace OT;
     35 
     36 typedef BiasedSubrs<CFF1Subrs>   CFF1BiasedSubrs;
     37 
     38 struct CFF1CSInterpEnv : CSInterpEnv<Number, CFF1Subrs>
     39 {
     40   template <typename ACC>
     41   void init (const ByteStr &str, ACC &acc, unsigned int fd)
     42   {
     43     SUPER::init (str, *acc.globalSubrs, *acc.privateDicts[fd].localSubrs);
     44     processed_width = false;
     45     has_width = false;
     46     arg_start = 0;
     47     in_seac = false;
     48   }
     49 
     50   void fini () { SUPER::fini (); }
     51 
     52   void set_width (bool has_width_)
     53   {
     54     if (likely (!processed_width && (SUPER::argStack.get_count () > 0)))
     55     {
     56       if (has_width_)
     57       {
     58 	width = SUPER::argStack[0];
     59 	has_width = true;
     60 	arg_start = 1;
     61       }
     62     }
     63     processed_width = true;
     64   }
     65 
     66   void clear_args ()
     67   {
     68     arg_start = 0;
     69     SUPER::clear_args ();
     70   }
     71 
     72   void set_in_seac (bool _in_seac) { in_seac = _in_seac; }
     73 
     74   bool	  processed_width;
     75   bool	  has_width;
     76   unsigned int  arg_start;
     77   Number	width;
     78   bool	  in_seac;
     79 
     80   private:
     81   typedef CSInterpEnv<Number, CFF1Subrs> SUPER;
     82 };
     83 
     84 template <typename OPSET, typename PARAM, typename PATH=PathProcsNull<CFF1CSInterpEnv, PARAM> >
     85 struct CFF1CSOpSet : CSOpSet<Number, OPSET, CFF1CSInterpEnv, PARAM, PATH>
     86 {
     87   /* PostScript-originated legacy opcodes (OpCode_add etc) are unsupported */
     88   /* Type 1-originated deprecated opcodes, seac behavior of endchar and dotsection are supported */
     89 
     90   static void process_op (OpCode op, CFF1CSInterpEnv &env, PARAM& param)
     91   {
     92     switch (op) {
     93       case OpCode_dotsection:
     94 	SUPER::flush_args_and_op (op, env, param);
     95 	break;
     96 
     97       case OpCode_endchar:
     98 	OPSET::check_width (op, env, param);
     99 	if (env.argStack.get_count () >= 4)
    100 	{
    101 	  OPSET::process_seac (env, param);
    102 	}
    103 	OPSET::flush_args_and_op (op, env, param);
    104 	env.set_endchar (true);
    105 	break;
    106 
    107       default:
    108 	SUPER::process_op (op, env, param);
    109     }
    110   }
    111 
    112   static void check_width (OpCode op, CFF1CSInterpEnv &env, PARAM& param)
    113   {
    114     if (!env.processed_width)
    115     {
    116       bool  has_width = false;
    117       switch (op)
    118       {
    119 	case OpCode_endchar:
    120 	case OpCode_hstem:
    121 	case OpCode_hstemhm:
    122 	case OpCode_vstem:
    123 	case OpCode_vstemhm:
    124 	case OpCode_hintmask:
    125 	case OpCode_cntrmask:
    126 	  has_width = ((env.argStack.get_count () & 1) != 0);
    127 	  break;
    128 	case OpCode_hmoveto:
    129 	case OpCode_vmoveto:
    130 	  has_width = (env.argStack.get_count () > 1);
    131 	  break;
    132 	case OpCode_rmoveto:
    133 	  has_width = (env.argStack.get_count () > 2);
    134 	  break;
    135 	default:
    136 	  return;
    137       }
    138       env.set_width (has_width);
    139     }
    140   }
    141 
    142   static void process_seac (CFF1CSInterpEnv &env, PARAM& param)
    143   {
    144   }
    145 
    146   static void flush_args (CFF1CSInterpEnv &env, PARAM& param)
    147   {
    148     SUPER::flush_args (env, param);
    149     env.clear_args ();  /* pop off width */
    150   }
    151 
    152   private:
    153   typedef CSOpSet<Number, OPSET, CFF1CSInterpEnv, PARAM, PATH>  SUPER;
    154 };
    155 
    156 template <typename OPSET, typename PARAM>
    157 struct CFF1CSInterpreter : CSInterpreter<CFF1CSInterpEnv, OPSET, PARAM> {};
    158 
    159 } /* namespace CFF */
    160 
    161 #endif /* HB_CFF1_INTERP_CS_HH */
    162