Merge branch 'master' into cff-subset
authorMichiharu Ariza <ariza@adobe.com>
Wed, 29 Aug 2018 20:26:17 +0000 (13:26 -0700)
committerMichiharu Ariza <ariza@adobe.com>
Wed, 29 Aug 2018 20:26:17 +0000 (13:26 -0700)
Renamed cff "private" source/headers without the suffix

18 files changed:
1  2 
src/Makefile.sources
src/hb-cff-interp-common.hh
src/hb-cff-interp-cs-common.hh
src/hb-cff-interp-dict-common.hh
src/hb-cff1-interp-cs.hh
src/hb-cff2-interp-cs.hh
src/hb-null.hh
src/hb-ot-cff-common.hh
src/hb-ot-cff1-table.hh
src/hb-ot-cff2-table.hh
src/hb-ot-font.cc
src/hb-subset-cff-common.cc
src/hb-subset-cff-common.hh
src/hb-subset-cff1.cc
src/hb-subset-cff1.hh
src/hb-subset-cff2.cc
src/hb-subset-cff2.hh
src/hb-subset.cc

@@@ -152,11 -151,6 +153,12 @@@ HB_OT_sources = 
        hb-ot-var-fvar-table.hh \
        hb-ot-var-hvar-table.hh \
        hb-ot-var-mvar-table.hh \
-       hb-cff-interp-common-private.hh \
-       hb-cff-interp-cs-common-private.hh \
++      hb-ot-cff-common.hh \
++      hb-cff-interp-common.hh \
++      hb-cff-interp-cs-common.hh \
 +      hb-cff1-interp-cs.hh \
 +      hb-cff2-interp-cs.hh \
-       hb-cff-interp-dict-common-private.hh \
++      hb-cff-interp-dict-common.hh \
        $(NULL)
  
  HB_OT_RAGEL_GENERATED_sources = \
@@@ -215,22 -209,16 +217,25 @@@ HB_ICU_headers = hb-icu.
  HB_SUBSET_sources = \
        hb-static.cc \
        hb-subset.cc \
+       hb-subset.hh \
        hb-subset-glyf.cc \
-   hb-subset-cff1.cc \
-   hb-subset-cff2.cc \
-       hb-subset-cff-common-private.cc \
+       hb-subset-glyf.hh \
++      hb-subset-cff1.cc \
++      hb-subset-cff2.cc \
++      hb-subset-cff-common.cc \
        hb-subset-input.cc \
        hb-subset-plan.cc \
+       hb-subset-plan.hh \
        $(NULL)
  
  HB_SUBSET_headers = \
        hb-subset.h \
-   hb-subset-cff1.hh \
-   hb-subset-cff2.hh \
-       hb-subset-cff-common-private.hh \
 +      hb-subset-glyf.hh \
-       hb-subset-private.hh \
++      hb-subset-cff1.hh \
++      hb-subset-cff2.hh \
++      hb-subset-cff-common.hh \
 +      hb-subset-plan.hh \
++      hb-subset.hh \
        $(NULL)
  
  HB_GOBJECT_DIST_sources = hb-gobject-structs.cc
index 79add12,0000000..79add12
mode 100644,000000..100644
--- /dev/null
index a8fd8ba,0000000..a1ab472
mode 100644,000000..100644
--- /dev/null
@@@ -1,323 -1,0 +1,323 @@@
- #include "hb-private.hh"
- #include "hb-cff-interp-common-private.hh"
 +/*
 + * Copyright © 2018 Adobe Systems Incorporated.
 + *
 + *  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_CS_COMMON_PRIVATE_HH
 +#define HB_CFF_INTERP_CS_COMMON_PRIVATE_HH
 +
++#include "hb.hh"
++#include "hb-cff-interp-common.hh"
 +
 +namespace CFF {
 +
 +using namespace OT;
 +
 +/* call stack */
 +struct CallStack : Stack<SubByteStr, 10> {};
 +
 +template <typename SUBRS>
 +struct BiasedSubrs
 +{
 +  inline void init (const SUBRS &subrs_)
 +  {
 +    subrs = &subrs_;
 +    unsigned int  nSubrs = subrs_.count;
 +    if (nSubrs < 1240)
 +      bias = 107;
 +    else if (nSubrs < 33900)
 +      bias = 1131;
 +    else
 +      bias = 32768;
 +  }
 +
 +  inline void fini (void) {}
 +
 +  const SUBRS   *subrs;
 +  unsigned int  bias;
 +};
 +
 +template <typename SUBRS>
 +struct CSInterpEnv : InterpEnv
 +{
 +  inline void init (const ByteStr &str, const SUBRS &globalSubrs_, const SUBRS &localSubrs_)
 +  {
 +    InterpEnv::init (str);
 +
 +    stack_cleared = false;
 +    seen_moveto = true;
 +    seen_hintmask = false;
 +    hstem_count = 0;
 +    vstem_count = 0;
 +    callStack.init ();
 +    globalSubrs.init (globalSubrs_);
 +    localSubrs.init (localSubrs_);
 +  }
 +  inline void fini (void)
 +  {
 +    InterpEnv::fini ();
 +
 +    callStack.fini ();
 +    globalSubrs.fini ();
 +    localSubrs.fini ();
 +  }
 +
 +  inline bool popSubrNum (const BiasedSubrs<SUBRS>& biasedSubrs, unsigned int &subr_num)
 +  {
 +    int n;
 +    if (unlikely ((!callStack.check_overflow (1) ||
 +                   !argStack.check_pop_int (n))))
 +      return false;
 +    n += biasedSubrs.bias;
 +    if (unlikely ((n < 0) || (n >= biasedSubrs.subrs->count)))
 +      return false;
 +
 +    subr_num = (unsigned int)n;
 +    return true;
 +  }
 +
 +  inline bool callSubr (const BiasedSubrs<SUBRS>& biasedSubrs)
 +  {
 +    unsigned int subr_num;
 +
 +    if (unlikely (!popSubrNum (biasedSubrs, subr_num)))
 +      return false;
 +    callStack.push (substr);
 +    substr = (*biasedSubrs.subrs)[subr_num];
 +
 +    return true;
 +  }
 +
 +  inline bool returnFromSubr (void)
 +  {
 +    if (unlikely (!callStack.check_underflow ()))
 +      return false;
 +
 +    substr = callStack.pop ();
 +    return true;
 +  }
 +
 +  inline void determine_hintmask_size (void)
 +  {
 +    if (!seen_hintmask)
 +    {
 +      vstem_count += argStack.size / 2;
 +      hintmask_size = (hstem_count + vstem_count + 7) >> 3;
 +      seen_hintmask = true;
 +    }
 +  }
 +
 +  inline void clear_stack (void)
 +  {
 +    stack_cleared = true;
 +    argStack.clear ();
 +  }
 +
 +  inline void set_endchar (bool endchar_flag_) { endchar_flag = endchar_flag_; }
 +  inline bool is_endchar (void) const { return endchar_flag; }
 +  inline bool is_stack_cleared (void) const { return stack_cleared; }
 +
 +  public:
 +  bool          endchar_flag;
 +  bool          stack_cleared;
 +  bool          seen_moveto;
 +  bool          seen_hintmask;
 +
 +  unsigned int  hstem_count;
 +  unsigned int  vstem_count;
 +  unsigned int  hintmask_size;
 +  CallStack            callStack;
 +  BiasedSubrs<SUBRS>   globalSubrs;
 +  BiasedSubrs<SUBRS>   localSubrs;
 +};
 +
 +template <typename OPSET, typename ENV, typename PARAM>
 +struct CSOpSet : OpSet
 +{
 +  static inline bool process_op (OpCode op, ENV &env, PARAM& param)
 +  {  
 +    switch (op) {
 +
 +      case OpCode_return:
 +        return env.returnFromSubr ();
 +      case OpCode_endchar:
 +        env.set_endchar (true);
 +        return true;
 +
 +      case OpCode_fixedcs:
 +        return env.argStack.push_fixed_from_substr (env.substr);
 +
 +      case OpCode_callsubr:
 +        return env.callSubr (env.localSubrs);
 +      
 +      case OpCode_callgsubr:
 +        return env.callSubr (env.globalSubrs);
 +
 +      case OpCode_hstem:
 +      case OpCode_hstemhm:
 +        OPSET::process_hstem (env, param);
 +        break;
 +      case OpCode_vstem:
 +      case OpCode_vstemhm:
 +        OPSET::process_vstem (env, param);
 +        break;
 +      case OpCode_hintmask:
 +      case OpCode_cntrmask:
 +        env.determine_hintmask_size ();
 +        OPSET::flush_stack (env, param);
 +        if (unlikely (!env.substr.avail (env.hintmask_size)))
 +          return false;
 +        env.substr.inc (env.hintmask_size);
 +        break;
 +      
 +      case OpCode_vmoveto:
 +      case OpCode_rlineto:
 +      case OpCode_hlineto:
 +      case OpCode_vlineto:
 +      case OpCode_rmoveto:
 +      case OpCode_hmoveto:
 +        OPSET::process_moveto (env, param);
 +        break;
 +      case OpCode_rrcurveto:
 +      case OpCode_rcurveline:
 +      case OpCode_rlinecurve:
 +      case OpCode_vvcurveto:
 +      case OpCode_hhcurveto:
 +      case OpCode_vhcurveto:
 +      case OpCode_hvcurveto:
 +      case OpCode_hflex:
 +      case OpCode_flex:
 +      case OpCode_hflex1:
 +      case OpCode_flex1:
 +        OPSET::flush_stack (env, param);
 +        break;
 +
 +      default:
 +        return OpSet::process_op (op, env);
 +    }
 +    return true;
 +  }
 +
 +  static inline void process_hstem (ENV &env, PARAM& param)
 +  {
 +    env.hstem_count += env.argStack.size / 2;
 +    OPSET::flush_stack (env, param);
 +  }
 +
 +  static inline void process_vstem (ENV &env, PARAM& param)
 +  {
 +    env.vstem_count += env.argStack.size / 2;
 +    OPSET::flush_stack (env, param);
 +  }
 +
 +  static inline void process_moveto (ENV &env, PARAM& param)
 +  {
 +    if (!env.seen_moveto)
 +    {
 +      env.determine_hintmask_size ();
 +      env.seen_moveto = true;
 +    }
 +    OPSET::flush_stack (env, param);
 +  }
 +
 +  static inline void flush_stack (ENV &env, PARAM& param)
 +  {
 +    env.clear_stack ();
 +  }
 +
 +  /* numeric / logical / arithmetic operators */
 +  static inline bool is_arg_op (OpCode op)
 +  {
 +    switch (op)
 +    {
 +      case OpCode_shortint:
 +      case OpCode_TwoBytePosInt0: case OpCode_TwoBytePosInt1:
 +      case OpCode_TwoBytePosInt2: case OpCode_TwoBytePosInt3:
 +      case OpCode_TwoByteNegInt0: case OpCode_TwoByteNegInt1:
 +      case OpCode_TwoByteNegInt2: case OpCode_TwoByteNegInt3:
 +      case OpCode_fixedcs:
 +      case OpCode_and:
 +      case OpCode_or:
 +      case OpCode_not:
 +      case OpCode_abs:
 +      case OpCode_add:
 +      case OpCode_sub:
 +      case OpCode_div:
 +      case OpCode_neg:
 +      case OpCode_eq:
 +      case OpCode_drop:
 +      case OpCode_put:
 +      case OpCode_get:
 +      case OpCode_ifelse:
 +      case OpCode_random:
 +      case OpCode_mul:
 +      case OpCode_sqrt:
 +      case OpCode_dup:
 +      case OpCode_exch:
 +      case OpCode_index:
 +      case OpCode_roll:
 +        return true;
 +      default:
 +        return (OpCode_OneByteIntFirst <= op) && (op <= OpCode_OneByteIntLast);
 +    }
 +  }
 +
 +  static inline bool is_subr_op (OpCode op)
 +  {
 +    switch (op)
 +    {
 +      case OpCode_callsubr:
 +      case OpCode_callgsubr:
 +      case OpCode_return:
 +        return true;
 +      default:
 +        return false;
 +    }
 +  }
 +};
 +
 +template <typename ENV, typename OPSET, typename PARAM>
 +struct CSInterpreter : Interpreter<ENV>
 +{
 +  inline bool interpret (PARAM& param)
 +  {
 +    param.init ();
 +    Interpreter<ENV> &super = *this;
 +    super.env.set_endchar (false);
 +
 +    for (;;) {
 +      OpCode op;
 +      if (unlikely (!super.env.fetch_op (op) ||
 +                    !OPSET::process_op (op, super.env, param)))
 +        return false;
 +      if (super.env.is_endchar ())
 +        break;
 +    }
 +    
 +    return true;
 +  }
 +};
 +
 +} /* namespace CFF */
 +
 +#endif /* HB_CFF_INTERP_CS_COMMON_PRIVATE_HH */
index 1a61132,0000000..6557290
mode 100644,000000..100644
--- /dev/null
@@@ -1,208 -1,0 +1,208 @@@
- #include "hb-cff-interp-common-private.hh"
 +/*
 + * Copyright © 2018 Adobe Systems Incorporated.
 + *
 + *  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_PRIVATE_HH
 +#define HB_CFF_INTERP_DICT_COMMON_PRIVATE_HH
 +
++#include "hb-cff-interp-common.hh"
 +
 +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);
 +    multi_val.init ();
 +  }
 +
 +  inline void fini (void)
 +  {
 +    multi_val.fini ();
 +  }
 +
 +  Number              single_val;
 +  hb_vector_t<Number> multi_val;
 +};
 +
 +template <typename VAL>
 +struct DictValues
 +{
 +  inline void init (void)
 +  {
 +    opStart = 0;
 +    values.init ();
 +  }
 +
 +  inline void fini (void)
 +  {
 +    values.fini ();
 +  }
 +
 +  inline void pushVal (OpCode op, const SubByteStr& substr)
 +  {
 +    VAL *val = values.push ();
 +    val->op = op;
 +    val->str = ByteStr (substr.str, opStart, substr.offset - opStart);
 +    opStart = substr.offset;
 +  }
 +
 +  inline void pushVal (OpCode op, const SubByteStr& substr, const VAL &v)
 +  {
 +    VAL *val = values.push (v);
 +    val->op = op;
 +    val->str = ByteStr (substr.str, opStart, substr.offset - opStart);
 +    opStart = substr.offset;
 +  }
 +
 +  unsigned int       opStart;
 +  hb_vector_t<VAL>   values;
 +};
 +
 +struct TopDictValues : DictValues<OpStr>
 +{
 +  inline void init (void)
 +  {
 +    DictValues<OpStr>::init ();
 +    charStringsOffset = 0;
 +    FDArrayOffset = 0;
 +  }
 +
 +  inline void fini (void)
 +  {
 +    DictValues<OpStr>::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 bool process_op (OpCode op, InterpEnv& env)
 +  {
 +    switch (op) {
 +      case OpCode_longintdict:  /* 5-byte integer */
 +        return env.argStack.push_longint_from_substr (env.substr);
 +      case OpCode_BCD:  /* real number */
 +        float v;
 +        if (unlikely (!env.argStack.check_overflow (1) || !parse_bcd (env.substr, v)))
 +          return false;
 +        env.argStack.push_real (v);
 +        return true;
 +
 +      default:
 +        return OpSet::process_op (op, env);
 +    }
 +
 +    return true;
 +  }
 +
 +  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;
 +    }
 +  }
 +};
 +
 +struct TopDictOpSet : DictOpSet
 +{
 +  static inline bool process_op (OpCode op, InterpEnv& env, TopDictValues& dictval)
 +  {
 +    switch (op) {
 +      case OpCode_CharStrings:
 +        if (unlikely (!env.argStack.check_pop_uint (dictval.charStringsOffset)))
 +          return false;
 +        env.argStack.clear ();
 +        break;
 +      case OpCode_FDArray:
 +        if (unlikely (!env.argStack.check_pop_uint (dictval.FDArrayOffset)))
 +          return false;
 +        env.argStack.clear ();
 +        break;
 +      default:
 +        return DictOpSet::process_op (op, env);
 +    }
 +
 +    return true;
 +  }
 +};
 +
 +template <typename OPSET, typename PARAM>
 +struct DictInterpreter : Interpreter<InterpEnv>
 +{
 +  inline bool interpret (PARAM& param)
 +  {
 +    param.init ();
 +    Interpreter<InterpEnv>  &super = *this;
 +    do
 +    {
 +      OpCode op;
 +      if (unlikely (!super.env.fetch_op (op) ||
 +                    !OPSET::process_op (op, super.env, param)))
 +        return false;
 +    } while (super.env.substr.avail ());
 +    
 +    return true;
 +  }
 +};
 +
 +} /* namespace CFF */
 +
 +#endif /* HB_CFF_INTERP_DICT_COMMON_PRIVATE_HH */
index ba93454,0000000..858623c
mode 100644,000000..100644
--- /dev/null
@@@ -1,212 -1,0 +1,212 @@@
- #include "hb-private.hh"
- #include "hb-cff-interp-cs-common-private.hh"
 +/*
 + * Copyright © 2018 Adobe Systems Incorporated.
 + *
 + *  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_CFF1_INTERP_CS_HH
 +#define HB_CFF1_INTERP_CS_HH
 +
++#include "hb.hh"
++#include "hb-cff-interp-cs-common.hh"
 +
 +namespace CFF {
 +
 +using namespace OT;
 +
 +struct CFF1CSInterpEnv : CSInterpEnv<CFF1Subrs>
 +{
 +  inline void init (const ByteStr &str, const CFF1Subrs &globalSubrs, const CFF1Subrs &localSubrs)
 +  {
 +    CSInterpEnv<CFF1Subrs>::init (str, globalSubrs, localSubrs);
 +    processed_width = false;
 +    has_width = false;
 +    for (unsigned int i = 0; i < kTransientArraySize; i++)
 +      transient_array[i].set_int (0);
 +  }
 +
 +  bool check_transient_array_index (unsigned int i) const
 +  { return i < kTransientArraySize; }
 +
 +  inline void check_width (void)
 +  {
 +    if (!processed_width)
 +    {
 +      if ((this->argStack.size & 1) != 0)
 +      {
 +        width = this->argStack.elements[0];
 +        has_width = true;
 +      }
 +      processed_width = true;
 +    }
 +  }
 +
 +  bool          processed_width;
 +  bool          has_width;
 +  Number        width;
 +
 +  static const unsigned int kTransientArraySize = 32;
 +  Number  transient_array[kTransientArraySize];
 +};
 +
 +template <typename OPSET, typename PARAM>
 +struct CFF1CSOpSet : CSOpSet<OPSET, CFF1CSInterpEnv, PARAM>
 +{
 +  static inline bool process_op (OpCode op, CFF1CSInterpEnv &env, PARAM& param)
 +  {
 +    Number  n1, n2;
 +
 +    switch (op) {
 +
 +      case OpCode_and:
 +        if (unlikely (!env.argStack.check_pop_num2 (n1, n2))) return false;
 +        env.argStack.push_int ((n1.to_real() != 0.0f) && (n2.to_real() != 0.0f));
 +        break;
 +      case OpCode_or:
 +        if (unlikely (!env.argStack.check_pop_num2 (n1, n2))) return false;
 +        env.argStack.push_int ((n1.to_real() != 0.0f) || (n2.to_real() != 0.0f));
 +        break;
 +      case OpCode_not:
 +        if (unlikely (!env.argStack.check_pop_num (n1))) return false;
 +        env.argStack.push_int (n1.to_real() == 0.0f);
 +        break;
 +      case OpCode_abs:
 +        if (unlikely (!env.argStack.check_pop_num (n1)))  return false;
 +        env.argStack.push_real (fabs(n1.to_real ()));
 +        break;
 +      case OpCode_add:
 +        if (unlikely (!env.argStack.check_pop_num2 (n1, n2))) return false;
 +        env.argStack.push_real (n1.to_real() + n2.to_real());
 +        break;
 +      case OpCode_sub:
 +        if (unlikely (!env.argStack.check_pop_num2 (n1, n2))) return false;
 +        env.argStack.push_real (n1.to_real() - n2.to_real());
 +        break;
 +      case OpCode_div:
 +        if (unlikely (!env.argStack.check_pop_num2 (n1, n2))) return false;
 +        if (unlikely (n2.to_real() == 0.0f))
 +          env.argStack.push_int (0);
 +        else
 +          env.argStack.push_real (n1.to_real() / n2.to_real());
 +        break;
 +      case OpCode_neg:
 +        if (unlikely (!env.argStack.check_pop_num (n1))) return false;
 +        env.argStack.push_real (-n1.to_real ());
 +        break;
 +      case OpCode_eq:
 +        if (unlikely (!env.argStack.check_pop_num2 (n1, n2))) return false;
 +        env.argStack.push_int (n1.to_real() == n2.to_real());
 +        break;
 +      case OpCode_drop:
 +        if (unlikely (!env.argStack.check_pop_num (n1))) return false;
 +        break;
 +      case OpCode_put:
 +        if (unlikely (!env.argStack.check_pop_num2 (n1, n2) ||
 +                      !env.check_transient_array_index (n2.to_int ()))) return false;
 +        env.transient_array[n2.to_int ()] = n1;
 +        break;
 +      case OpCode_get:
 +        if (unlikely (!env.argStack.check_pop_num (n1) ||
 +                      !env.check_transient_array_index (n1.to_int ()))) return false;
 +        env.argStack.push (env.transient_array[n1.to_int ()]);
 +        break;
 +      case OpCode_ifelse:
 +        {
 +          if (unlikely (!env.argStack.check_pop_num2 (n1, n2))) return false;
 +          bool  test = n1.to_real () <= n2.to_real ();
 +          if (unlikely (!env.argStack.check_pop_num2 (n1, n2))) return false;
 +          env.argStack.push (test? n1: n2);
 +        }
 +        break;
 +      case OpCode_random:
 +          if (unlikely (!env.argStack.check_overflow (1))) return false;
 +          env.argStack.push_int (1);  /* we can't deal with random behavior; make it constant */
 +      case OpCode_mul:
 +        if (unlikely (!env.argStack.check_pop_num2 (n1, n2))) return false;
 +        env.argStack.push_real (n1.to_real() * n2.to_real());
 +        break;
 +      case OpCode_sqrt:
 +        if (unlikely (!env.argStack.check_pop_num (n1))) return false;
 +        env.argStack.push_real ((float)sqrt (n1.to_real ()));
 +        break;
 +      case OpCode_dup:
 +        if (unlikely (!env.argStack.check_pop_num (n1))) return false;
 +        env.argStack.push (n1);
 +        env.argStack.push (n1);
 +        break;
 +      case OpCode_exch:
 +        if (unlikely (!env.argStack.check_pop_num2 (n1, n2))) return false;
 +        env.argStack.push (n2);
 +        env.argStack.push (n1);
 +        break;
 +      case OpCode_index:
 +        {
 +          if (unlikely (!env.argStack.check_pop_num (n1))) return false;
 +          int i = n1.to_int ();
 +          if (i < 0) i = 0;
 +          if (unlikely (i >= env.argStack.size || !env.argStack.check_overflow (1))) return false;
 +          env.argStack.push (env.argStack.elements[env.argStack.size - i - 1]);
 +        }
 +        break;
 +      case OpCode_roll:
 +        {
 +          if (unlikely (!env.argStack.check_pop_num2 (n1, n2))) return false;
 +          int n = n1.to_int ();
 +          int j = n2.to_int ();
 +          if (unlikely (n < 0 || n > env.argStack.size)) return false;
 +          if (likely (n > 0))
 +          {
 +            if (j < 0)
 +              j = n - (-j % n);
 +            j %= n;
 +            unsigned int top = env.argStack.size - 1;
 +            unsigned int bot = top - n + 1;
 +            env.argStack.reverse_range (top - j + 1, top);
 +            env.argStack.reverse_range (bot, top - j);
 +            env.argStack.reverse_range (bot, top);
 +          }
 +        }
 +        break;
 +      default:
 +        if (unlikely (!SUPER::process_op (op, env, param)))
 +          return false;
 +        break;
 +    }
 +    return true;
 +  }
 +
 +  static inline void flush_stack (CFF1CSInterpEnv &env, PARAM& param)
 +  {
 +    env.check_width ();
 +    SUPER::flush_stack (env, param);
 +  }
 +
 +  private:
 +  typedef CSOpSet<OPSET, CFF1CSInterpEnv, PARAM>  SUPER;
 +};
 +
 +template <typename OPSET, typename PARAM>
 +struct CFF1CSInterpreter : CSInterpreter<CFF1CSInterpEnv, OPSET, PARAM> {};
 +
 +} /* namespace CFF */
 +
 +#endif /* HB_CFF1_INTERP_CS_HH */
index 96e209b,0000000..aaff5ac
mode 100644,000000..100644
--- /dev/null
@@@ -1,97 -1,0 +1,97 @@@
- #include "hb-private.hh"
- #include "hb-cff-interp-cs-common-private.hh"
 +/*
 + * Copyright © 2018 Adobe Systems Incorporated.
 + *
 + *  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_CFF2_INTERP_CS_HH
 +#define HB_CFF2_INTERP_CS_HH
 +
++#include "hb.hh"
++#include "hb-cff-interp-cs-common.hh"
 +
 +namespace CFF {
 +
 +using namespace OT;
 +
 +struct CFF2CSInterpEnv : CSInterpEnv<CFF2Subrs>
 +{
 +  inline void init (const ByteStr &str, const CFF2Subrs &globalSubrs_, const CFF2Subrs &localSubrs_)
 +  {
 +    CSInterpEnv<CFF2Subrs>::init (str, globalSubrs_, localSubrs_);
 +    ivs = 0;
 +  }
 +
 +  inline bool fetch_op (OpCode &op)
 +  {
 +    if (unlikely (this->substr.avail ()))
 +      return CSInterpEnv<CFF2Subrs>::fetch_op (op);
 +
 +    /* make up return or endchar op */
 +    if (this->callStack.check_underflow ())
 +      op = OpCode_return;
 +    else
 +      op = OpCode_endchar;
 +    return true;
 +  }
 +
 +  inline unsigned int get_ivs (void) const { return ivs; }
 +  inline void         set_ivs (unsigned int ivs_) { ivs = ivs_; }
 +
 +  protected:
 +  unsigned int  ivs;
 +};
 +
 +template <typename OPSET, typename PARAM>
 +struct CFF2CSOpSet : CSOpSet<OPSET, CFF2CSInterpEnv, PARAM>
 +{
 +  static inline bool process_op (OpCode op, CFF2CSInterpEnv &env, PARAM& param)
 +  {
 +    switch (op) {
 +
 +      case OpCode_blendcs:
 +        //env.flush_stack (); // XXX: TODO
 +        break;
 +      case OpCode_vsindexcs:
 +        {
 +          unsigned int ivs;
 +          if (unlikely (!env.argStack.check_pop_uint (ivs))) return false;
 +          env.set_ivs (ivs);
 +          //env.flush_stack ();
 +        }
 +        break;
 +      default:
 +        typedef CSOpSet<OPSET, CFF2CSInterpEnv, PARAM>  SUPER;
 +        if (unlikely (!SUPER::process_op (op, env, param)))
 +          return false;
 +        break;
 +    }
 +    return true;
 +  }
 +};
 +
 +template <typename OPSET, typename PARAM>
 +struct CFF2CSInterpreter : CSInterpreter<CFF2CSInterpEnv, OPSET, PARAM> {};
 +
 +} /* namespace CFF */
 +
 +#endif /* HB_CFF2_INTERP_CS_HH */
diff --cc src/hb-null.hh
Simple merge
index 09bcc22,0000000..b5ab0e7
mode 100644,000000..100644
--- /dev/null
@@@ -1,623 -1,0 +1,623 @@@
- #include "hb-open-type-private.hh"
- #include "hb-ot-layout-common-private.hh"
- #include "hb-cff-interp-dict-common-private.hh"
 +/*
 + * Copyright © 2018 Adobe Systems Incorporated.
 + *
 + *  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_OT_CFF_COMMON_PRIVATE_HH
 +#define HB_OT_CFF_COMMON_PRIVATE_HH
 +
++#include "hb-open-type.hh"
++#include "hb-ot-layout-common.hh"
++#include "hb-cff-interp-dict-common.hh"
 +#include "hb-subset-plan.hh"
 +
 +namespace CFF {
 +
 +using namespace OT;
 +
 +/* utility macro */
 +template<typename Type>
 +static inline const Type& StructAtOffsetOrNull(const void *P, unsigned int offset)
 +{ return offset? (* reinterpret_cast<const Type*> ((const char *) P + offset)): Null(Type); }
 +
 +inline unsigned int calcOffSize(unsigned int offset)
 +{
 +  unsigned int size = 1;
 +  while ((offset & ~0xFF) != 0)
 +  {
 +    size++;
 +    offset >>= 8;
 +  }
 +  assert (size <= 4);
 +  return size;
 +}
 +
 +/* CFF INDEX */
 +template <typename COUNT>
 +struct CFFIndex
 +{
 +  inline bool sanitize (hb_sanitize_context_t *c) const
 +  {
 +    TRACE_SANITIZE (this);
 +    return_trace (likely ((count.sanitize (c) && count == 0) || /* empty INDEX */
 +                          (c->check_struct (this) && offSize >= 1 && offSize <= 4 &&
 +                           c->check_array (offsets, offSize, count + 1) &&
 +                           c->check_array (data_base (), 1, max_offset () - 1))));
 +  }
 +
 +  inline static unsigned int calculate_offset_array_size (unsigned int offSize, unsigned int count)
 +  { return offSize * (count + 1); }
 +
 +  inline unsigned int offset_array_size (void) const
 +  { return calculate_offset_array_size (offSize, count); }
 +
 +  inline static unsigned int calculate_serialized_size (unsigned int offSize, unsigned int count, unsigned int dataSize)
 +  { return min_size + calculate_offset_array_size (offSize, count) + dataSize; }
 +
 +  inline bool serialize (hb_serialize_context_t *c, const CFFIndex &src)
 +  {
 +    TRACE_SERIALIZE (this);
 +    unsigned int size = src.get_size ();
 +    CFFIndex *dest = c->allocate_size<CFFIndex> (size);
 +    if (unlikely (dest == nullptr)) return_trace (false);
 +    memcpy (dest, &src, size);
 +    return_trace (true);
 +  }
 +
 +  inline bool serialize (hb_serialize_context_t *c,
 +                         unsigned int offSize_,
 +                         const hb_vector_t<ByteStr> &byteArray)
 +  {
 +    TRACE_SERIALIZE (this);
 +    /* serialize CFFIndex header */
 +    if (unlikely (!c->extend_min (*this))) return_trace (false);
 +    this->count.set (byteArray.len);
 +    this->offSize.set (offSize_);
 +    if (!unlikely (c->allocate_size<HBUINT8> (offSize_ * (byteArray.len + 1))))
 +      return_trace (false);
 +  
 +    /* serialize indices */
 +    unsigned int  offset = 1;
 +    unsigned int  i = 0;
 +    for (; i < byteArray.len; i++)
 +    {
 +      set_offset_at (i, offset);
 +      offset += byteArray[i].get_size ();
 +    }
 +    set_offset_at (i, offset);
 +
 +    /* serialize data */
 +    for (unsigned int i = 0; i < byteArray.len; i++)
 +    {
 +      ByteStr  *dest = c->start_embed<ByteStr> ();
 +      if (unlikely (dest == nullptr ||
 +                    !dest->serialize (c, byteArray[i])))
 +        return_trace (false);
 +    }
 +    return_trace (true);
 +  }
 +
 +  inline void set_offset_at (unsigned int index, unsigned int offset)
 +  {
 +    HBUINT8 *p = offsets + offSize * index + offSize;
 +    unsigned int size = offSize;
 +    for (; size; size--)
 +    {
 +      --p;
 +      p->set (offset & 0xFF);
 +      offset >>= 8;
 +    }
 +  }
 +
 +  inline const unsigned int offset_at (unsigned int index) const
 +  {
 +    assert (index <= count);
 +    const HBUINT8 *p = offsets + offSize * index;
 +    unsigned int size = offSize;
 +    unsigned int offset = 0;
 +    for (; size; size--)
 +      offset = (offset << 8) + *p++;
 +    return offset;
 +  }
 +
 +  inline const unsigned int length_at (unsigned int index) const
 +  { return offset_at (index + 1) - offset_at (index); }
 +
 +  inline const char *data_base (void) const
 +  { return (const char *)this + min_size + offset_array_size (); }
 +
 +  inline unsigned int data_size (void) const
 +  { return HBINT8::static_size; };
 +
 +  ByteStr operator [] (unsigned int index) const
 +  {
 +    if (likely (index < count))
 +      return ByteStr (data_base () + offset_at (index) - 1, offset_at (index + 1) - offset_at (index));
 +    else
 +      return Null(ByteStr);
 +  }
 +
 +  inline unsigned int get_size (void) const
 +  {
 +    if (this != &Null(CFFIndex))
 +    {
 +      if (count > 0)
 +        return min_size + offset_array_size () + (offset_at (count) - 1);
 +      else
 +        return count.static_size;  /* empty CFFIndex contains count only */
 +    }
 +    else
 +      return 0;
 +  }
 +
 +  protected:
 +  inline unsigned int max_offset (void) const
 +  {
 +    unsigned int max = 0;
 +    for (unsigned int i = 0; i <= count; i++)
 +    {
 +      unsigned int off = offset_at (i);
 +      if (off > max) max = off;
 +    }
 +    return max;
 +  }
 +
 +  public:
 +  COUNT     count;        /* Number of object data. Note there are (count+1) offsets */
 +  HBUINT8   offSize;      /* The byte size of each offset in the offsets array. */
 +  HBUINT8   offsets[VAR]; /* The array of (count + 1) offsets into objects array (1-base). */
 +  /* HBUINT8 data[VAR];      Object data */
 +  public:
 +  DEFINE_SIZE_ARRAY (COUNT::static_size + HBUINT8::static_size, offsets);
 +};
 +
 +template <typename COUNT, typename TYPE>
 +struct IndexOf : CFFIndex<COUNT>
 +{
 +  inline const ByteStr operator [] (unsigned int index) const
 +  {
 +    if (likely (index < CFFIndex<COUNT>::count))
 +      return ByteStr (CFFIndex<COUNT>::data_base () + CFFIndex<COUNT>::offset_at (index) - 1, CFFIndex<COUNT>::length_at (index));
 +    return Null(ByteStr);
 +  }
 +
 +  template <typename DATA, typename PARAM1, typename PARAM2>
 +  inline bool serialize (hb_serialize_context_t *c,
 +                         unsigned int offSize_,
 +                         const hb_vector_t<DATA> &dataArray,
 +                         const hb_vector_t<unsigned int> &dataSizeArray,
 +                         const PARAM1 &param1,
 +                         const PARAM2 &param2)
 +  {
 +    TRACE_SERIALIZE (this);
 +    /* serialize CFFIndex header */
 +    if (unlikely (!c->extend_min (*this))) return_trace (false);
 +    this->count.set (dataArray.len);
 +    this->offSize.set (offSize_);
 +    if (!unlikely (c->allocate_size<HBUINT8> (offSize_ * (dataArray.len + 1))))
 +      return_trace (false);
 +  
 +    /* serialize indices */
 +    unsigned int  offset = 1;
 +    unsigned int  i = 0;
 +    for (; i < dataArray.len; i++)
 +    {
 +      CFFIndex<COUNT>::set_offset_at (i, offset);
 +      offset += dataSizeArray[i];
 +    }
 +    CFFIndex<COUNT>::set_offset_at (i, offset);
 +
 +    /* serialize data */
 +    for (unsigned int i = 0; i < dataArray.len; i++)
 +    {
 +      TYPE  *dest = c->start_embed<TYPE> ();
 +      if (unlikely (dest == nullptr ||
 +                    !dest->serialize (c, dataArray[i], param1, param2)))
 +        return_trace (false);
 +    }
 +    return_trace (true);
 +  }
 +
 +  /* in parallel to above */
 +  template <typename DATA, typename PARAM>
 +  inline static unsigned int calculate_serialized_size (unsigned int &offSize_ /* OUT */,
 +                                                        const hb_vector_t<DATA> &dataArray,
 +                                                        hb_vector_t<unsigned int> &dataSizeArray, /* OUT */
 +                                                        const PARAM &param)
 +  {
 +    /* determine offset size */
 +    unsigned int  totalDataSize = 0;
 +    for (unsigned int i = 0; i < dataArray.len; i++)
 +    {
 +      unsigned int dataSize = TYPE::calculate_serialized_size (dataArray[i], param);
 +      dataSizeArray[i] = dataSize;
 +      totalDataSize += dataSize;
 +    }
 +    offSize_ = calcOffSize (totalDataSize);
 +
 +    return CFFIndex<COUNT>::calculate_serialized_size (offSize_, dataArray.len, totalDataSize);
 +  }
 +};
 +
 +/* Top Dict, Font Dict, Private Dict */
 +struct Dict : UnsizedByteStr
 +{
 +  template <typename DICTVAL, typename OP_SERIALIZER, typename PARAM>
 +  inline bool serialize (hb_serialize_context_t *c,
 +                        const DICTVAL &dictval,
 +                        OP_SERIALIZER& opszr,
 +                        PARAM& param)
 +  {
 +    TRACE_SERIALIZE (this);
 +    for (unsigned int i = 0; i < dictval.values.len; i++)
 +    {
 +      if (unlikely (!opszr.serialize (c, dictval.values[i], param)))
 +        return_trace (false);
 +    }
 +    return_trace (true);
 +  }
 +
 +  /* in parallel to above */
 +  template <typename DICTVAL, typename OP_SERIALIZER>
 +  inline static unsigned int calculate_serialized_size (const DICTVAL &dictval,
 +                                                        OP_SERIALIZER& opszr)
 +  {
 +    unsigned int size = 0;
 +    for (unsigned int i = 0; i < dictval.values.len; i++)
 +      size += opszr.calculate_serialized_size (dictval.values[i]);
 +    return size;
 +  }
 +
 +  template <typename INTTYPE, int minVal, int maxVal>
 +  inline static bool serialize_offset_op (hb_serialize_context_t *c, OpCode op, int value, OpCode intOp)
 +  {
 +    if (value == 0)
 +      return true;
 +    // XXX: not sure why but LLVM fails to compile the following 'unlikely' macro invocation
 +    if (/*unlikely*/ (!serialize_int<INTTYPE, minVal, maxVal> (c, intOp, value)))
 +      return false;
 +
 +    TRACE_SERIALIZE (this);
 +    /* serialize the opcode */
 +    HBUINT8 *p = c->allocate_size<HBUINT8> (OpCode_Size (op));
 +    if (unlikely (p == nullptr)) return_trace (false);
 +    if (Is_OpCode_ESC (op))
 +    {
 +      p->set (OpCode_escape);
 +      op = Unmake_OpCode_ESC (op);
 +      p++;
 +    }
 +    p->set (op);
 +    return_trace (true);
 +  }
 +
 +  inline static bool serialize_offset4_op (hb_serialize_context_t *c, OpCode op, int value)
 +  { return serialize_offset_op<HBUINT32, 0, 0x7FFFFFFF> (c, op, value, OpCode_longintdict); }
 +
 +  inline static bool serialize_offset2_op (hb_serialize_context_t *c, OpCode op, int value)
 +  { return serialize_offset_op<HBUINT16, 0, 0x7FFF> (c, op, value, OpCode_shortint); }
 +};
 +
 +struct TopDict : Dict {};
 +struct FontDict : Dict {};
 +struct PrivateDict : Dict {};
 +
 +struct TableInfo
 +{
 +  void init (void) { offSize = offset = size = 0; }
 +
 +  unsigned int    offset;
 +  unsigned int    size;
 +  unsigned int    offSize;
 +};
 +
 +/* font dict index remap table from fullset FDArray to subset FDArray.
 + * set to HB_SET_VALUE_INVALID if excluded from subset */
 +struct FDMap : hb_vector_t<hb_codepoint_t>
 +{
 +  inline void init (void)
 +  { hb_vector_t<hb_codepoint_t>::init (); }
 +
 +  inline void fini (void)
 +  { hb_vector_t<hb_codepoint_t>::fini (); }
 +
 +  inline bool fullset (void) const
 +  {
 +    for (unsigned int i = 0; i < len; i++)
 +      if (hb_vector_t<hb_codepoint_t>::operator[] (i) == HB_SET_VALUE_INVALID)
 +        return false;
 +    return true;
 +  }
 +
 +  inline bool excludes (hb_codepoint_t fd) const
 +  { return (fd < len) && ((*this)[fd] == HB_SET_VALUE_INVALID); }
 +
 +  inline hb_codepoint_t operator[] (hb_codepoint_t i) const
 +  {
 +    if (fullset ())
 +      return i;
 +    else
 +      return hb_vector_t<hb_codepoint_t>::operator[] (i);
 +  }
 +
 +  inline hb_codepoint_t &operator[] (hb_codepoint_t i)
 +  {
 +    assert (i < len);
 +    return hb_vector_t<hb_codepoint_t>::operator[] (i);
 +  }
 +};
 +
 +template <typename COUNT>
 +struct FDArray : IndexOf<COUNT, FontDict>
 +{
 +  template <typename DICTVAL, typename OP_SERIALIZER>
 +  inline bool serialize (hb_serialize_context_t *c,
 +                        unsigned int offSize_,
 +                        const hb_vector_t<DICTVAL> &fontDicts,
 +                        unsigned int fdCount,
 +                        const FDMap &fdmap,
 +                        OP_SERIALIZER& opszr,
 +                        const hb_vector_t<TableInfo> &privateInfos)
 +  {
 +    TRACE_SERIALIZE (this);
 +    if (unlikely (!c->extend_min (*this))) return_trace (false);
 +    this->count.set (fdCount);
 +    this->offSize.set (offSize_);
 +    if (!unlikely (c->allocate_size<HBUINT8> (offSize_ * (fdCount + 1))))
 +      return_trace (false);
 +    
 +    /* serialize font dict offsets */
 +    unsigned int  offset = 1;
 +    unsigned int  fid = 0;
 +    for (unsigned i = 0; i < fontDicts.len; i++)
 +      if (!fdmap.excludes (i))
 +      {
 +        IndexOf<COUNT, FontDict>::set_offset_at (fid++, offset);
 +        offset += FontDict::calculate_serialized_size (fontDicts[i], opszr);
 +      }
 +    IndexOf<COUNT, FontDict>::set_offset_at (fid, offset);
 +
 +    /* serialize font dicts */
 +    for (unsigned int i = 0; i < fontDicts.len; i++)
 +      if (!fdmap.excludes (i))
 +      {
 +        FontDict *dict = c->start_embed<FontDict> ();
 +        if (unlikely (!dict->serialize (c, fontDicts[i], opszr, privateInfos[fdmap[i]])))
 +          return_trace (false);
 +      }
 +    return_trace (true);
 +  }
 +  
 +  /* in parallel to above */
 +  template <typename OP_SERIALIZER, typename DICTVAL>
 +  inline static unsigned int calculate_serialized_size (unsigned int &offSize_ /* OUT */,
 +                                                        const hb_vector_t<DICTVAL> &fontDicts,
 +                                                        unsigned int fdCount,
 +                                                        const FDMap &fdmap,
 +                                                        OP_SERIALIZER& opszr)
 +  {
 +    unsigned int dictsSize = 0;
 +    for (unsigned int i = 0; i < fontDicts.len; i++)
 +      if (!fdmap.excludes (i))
 +        dictsSize += FontDict::calculate_serialized_size (fontDicts[i], opszr);
 +
 +    offSize_ = calcOffSize (dictsSize + 1);
 +    return CFFIndex<COUNT>::calculate_serialized_size (offSize_, fdCount, dictsSize);
 +  }
 +};
 +
 +/* FDSelect */
 +struct FDSelect0 {
 +  inline bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const
 +  {
 +    TRACE_SANITIZE (this);
 +    if (unlikely (!(c->check_struct (this))))
 +      return_trace (false);
 +    for (unsigned int i = 0; i < c->get_num_glyphs (); i++)
 +      if (unlikely (!fds[i].sanitize (c)))
 +        return_trace (false);
 +
 +    return_trace (true);
 +  }
 +
 +  inline hb_codepoint_t get_fd (hb_codepoint_t glyph) const
 +  {
 +    return (hb_codepoint_t)fds[glyph];
 +  }
 +
 +  inline unsigned int get_size (unsigned int num_glyphs) const
 +  { return HBUINT8::static_size * num_glyphs; }
 +
 +  HBUINT8     fds[VAR];
 +
 +  DEFINE_SIZE_MIN (1);
 +};
 +
 +template <typename GID_TYPE, typename FD_TYPE>
 +struct FDSelect3_4_Range {
 +  inline bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const
 +  {
 +    TRACE_SANITIZE (this);
 +    return_trace (likely (c->check_struct (this) && (first < c->get_num_glyphs ()) && (fd < fdcount)));
 +  }
 +
 +  GID_TYPE    first;
 +  FD_TYPE     fd;
 +
 +  DEFINE_SIZE_STATIC (GID_TYPE::static_size + FD_TYPE::static_size);
 +};
 +
 +template <typename GID_TYPE, typename FD_TYPE>
 +struct FDSelect3_4 {
 +  inline unsigned int get_size (void) const
 +  { return GID_TYPE::static_size * 2 + FDSelect3_4_Range<GID_TYPE, FD_TYPE>::static_size * nRanges; }
 +
 +  inline bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const
 +  {
 +    TRACE_SANITIZE (this);
 +    if (unlikely (!(c->check_struct (this) && (nRanges > 0) && (ranges[0].first == 0))))
 +      return_trace (false);
 +
 +    for (unsigned int i = 0; i < nRanges; i++)
 +    {
 +      if (unlikely (!ranges[i].sanitize (c, fdcount)))
 +        return_trace (false);
 +      if ((0 < i) && unlikely (ranges[i - 1].first >= ranges[i].first))
 +        return_trace (false);
 +    }
 +    if (unlikely (!sentinel().sanitize (c) || (sentinel() != c->get_num_glyphs ())))
 +      return_trace (false);
 +
 +    return_trace (true);
 +  }
 +
 +  inline hb_codepoint_t get_fd (hb_codepoint_t glyph) const
 +  {
 +    for (unsigned int i = 1; i < nRanges; i++)
 +      if (glyph < ranges[i].first)
 +        return (hb_codepoint_t)ranges[i - 1].fd;
 +
 +    assert (false);
 +  }
 +
 +  inline GID_TYPE &sentinel (void)  { return StructAfter<GID_TYPE> (ranges[nRanges - 1]); }
 +  inline const GID_TYPE &sentinel (void) const  { return StructAfter<GID_TYPE> (ranges[nRanges - 1]); }
 +
 +  GID_TYPE         nRanges;
 +  FDSelect3_4_Range<GID_TYPE, FD_TYPE>  ranges[VAR];
 +  /* GID_TYPE sentinel */
 +
 +  DEFINE_SIZE_ARRAY (GID_TYPE::static_size * 2, ranges);
 +};
 +
 +typedef FDSelect3_4<HBUINT16, HBUINT8> FDSelect3;
 +typedef FDSelect3_4_Range<HBUINT16, HBUINT8> FDSelect3_Range;
 +
 +struct FDSelect {
 +  inline bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const
 +  {
 +    TRACE_SANITIZE (this);
 +
 +    return_trace (likely (c->check_struct (this) && (format == 0 || format == 3) &&
 +                          (format == 0)?
 +                          u.format0.sanitize (c, fdcount):
 +                          u.format3.sanitize (c, fdcount)));
 +  }
 +
 +  inline bool serialize (hb_serialize_context_t *c, const FDSelect &src, unsigned int num_glyphs)
 +  {
 +    TRACE_SERIALIZE (this);
 +    unsigned int size = src.get_size (num_glyphs);
 +    FDSelect *dest = c->allocate_size<FDSelect> (size);
 +    if (unlikely (dest == nullptr)) return_trace (false);
 +    memcpy (dest, &src, size);
 +    return_trace (true);
 +  }
 +
 +  inline unsigned int calculate_serialized_size (unsigned int num_glyphs) const
 +  { return get_size (num_glyphs); }
 +
 +  inline unsigned int get_size (unsigned int num_glyphs) const
 +  {
 +    unsigned int size = format.static_size;
 +    if (format == 0)
 +      size += u.format0.get_size (num_glyphs);
 +    else
 +      size += u.format3.get_size ();
 +    return size;
 +  }
 +
 +  inline hb_codepoint_t get_fd (hb_codepoint_t glyph) const
 +  {
 +    if (this == &Null(FDSelect))
 +      return 0;
 +    if (format == 0)
 +      return u.format0.get_fd (glyph);
 +    else
 +      return u.format3.get_fd (glyph);
 +  }
 +
 +  HBUINT8       format;
 +  union {
 +    FDSelect0   format0;
 +    FDSelect3   format3;
 +  } u;
 +
 +  DEFINE_SIZE_MIN (1);
 +};
 +
 +template <typename COUNT>
 +struct Subrs : CFFIndex<COUNT>
 +{
 +  inline bool serialize (hb_serialize_context_t *c, const Subrs<COUNT> &subrs, unsigned int offSize, const hb_set_t *set, const ByteStr& nullStr = ByteStr())
 +  {
 +    TRACE_SERIALIZE (this);
 +    if (&subrs == &Null(Subrs<COUNT>))
 +      return_trace (true);
 +    if ((subrs.count == 0) || (set == nullptr) || (hb_set_is_empty (set)))
 +    {
 +      if (!unlikely (c->allocate_size<COUNT> (COUNT::static_size)))
 +        return_trace (false);
 +      CFFIndex<COUNT>::count.set (0);
 +      return_trace (true);
 +    }
 +    
 +    hb_vector_t<ByteStr> bytesArray;
 +    bytesArray.init ();
 +    if (!bytesArray.resize (subrs.count))
 +      return_trace (false);
 +    for (hb_codepoint_t i = 0; i < subrs.count; i++)
 +      bytesArray[i] = (hb_set_has (set, i))? subrs[i]: nullStr;
 +
 +    bool result = CFFIndex<COUNT>::serialize (c, offSize, bytesArray);
 +    bytesArray.fini ();
 +    return_trace (result);
 +  }
 +  
 +  /* in parallel to above */
 +  inline unsigned int calculate_serialized_size (unsigned int &offSize /*OUT*/, const hb_set_t *set, unsigned int nullStrSize = 0) const
 +  {
 +    if (this == &Null(Subrs<COUNT>))
 +      return 0;
 +    unsigned int  count_ = CFFIndex<COUNT>::count;
 +    offSize = 0;
 +    if ((count_ == 0) || (hb_set_get_population (set) == 0))
 +      return COUNT::static_size;
 +
 +    unsigned int dataSize = 0;
 +    for (hb_codepoint_t i = 0; i < count_; i++)
 +    {
 +      if (hb_set_has (set, i))
 +        dataSize += (*this)[i].len;
 +      else
 +        dataSize += nullStrSize;
 +    }
 +    offSize = calcOffSize(dataSize);
 +    return CFFIndex<COUNT>::calculate_serialized_size (offSize, count_, dataSize);
 +  }
 +};
 +
 +} /* namespace CFF */
 +
 +#endif /* HB_OT_CFF_COMMON_PRIVATE_HH */
 +
index f2a255c,0000000..dd42a47
mode 100644,000000..100644
--- /dev/null
@@@ -1,898 -1,0 +1,898 @@@
- #include "hb-ot-cff-common-private.hh"
 +/*
 + * Copyright © 2018 Adobe Systems Incorporated.
 + *
 + *  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_OT_CFF1_TABLE_HH
 +#define HB_OT_CFF1_TABLE_HH
 +
++#include "hb-ot-cff-common.hh"
 +#include "hb-subset-cff1.hh"
 +
 +namespace CFF {
 +
 +/*
 + * CFF -- Compact Font Format (CFF)
 + * http://www.adobe.com/content/dam/acom/en/devnet/font/pdfs/5176.CFF.pdf
 + */
 +#define HB_OT_TAG_cff1 HB_TAG('C','F','F',' ')
 +
 +typedef CFFIndex<HBUINT16>  CFF1Index;
 +template <typename Type> struct CFF1IndexOf : IndexOf<HBUINT16, Type> {};
 +
 +typedef CFFIndex<HBUINT16>  CFF1Index;
 +typedef CFF1Index         CFF1CharStrings;
 +typedef FDArray<HBUINT16> CFF1FDArray;
 +typedef Subrs<HBUINT16>   CFF1Subrs;
 +
 +struct CFF1FDSelect : FDSelect {};
 +
 +/* Encoding */
 +struct Encoding0 {
 +  inline bool sanitize (hb_sanitize_context_t *c) const
 +  {
 +    TRACE_SANITIZE (this);
 +    return_trace (c->check_struct (this) && codes[nCodes - 1].sanitize (c));
 +  }
 +
 +  inline bool get_code (hb_codepoint_t glyph, hb_codepoint_t &code) const
 +  {
 +    if (glyph < nCodes)
 +    {
 +      code = (hb_codepoint_t)codes[glyph];
 +      return true;
 +    }
 +    else
 +      return false;
 +  }
 +
 +  inline unsigned int get_size (void) const
 +  { return HBUINT8::static_size * (nCodes + 1); }
 +
 +  HBUINT8     nCodes;
 +  HBUINT8     codes[VAR];
 +
 +  DEFINE_SIZE_ARRAY(1, codes);
 +};
 +
 +struct Encoding1_Range {
 +  inline bool sanitize (hb_sanitize_context_t *c) const
 +  {
 +    TRACE_SANITIZE (this);
 +    return_trace (c->check_struct (this));
 +  }
 +
 +  HBUINT8   first;
 +  HBUINT8   nLeft;
 +
 +  DEFINE_SIZE_STATIC (2);
 +};
 +
 +struct Encoding1 {
 +  inline unsigned int get_size (void) const
 +  { return HBUINT8::static_size + Encoding1_Range::static_size * nRanges; }
 +
 +  inline bool sanitize (hb_sanitize_context_t *c) const
 +  {
 +    TRACE_SANITIZE (this);
 +    return_trace (c->check_struct (this) && ((nRanges == 0) || (ranges[nRanges - 1]).sanitize (c)));
 +  }
 +
 +  inline bool get_code (hb_codepoint_t glyph, hb_codepoint_t &code) const
 +  {
 +    for (unsigned int i = 0; i < nRanges; i++)
 +    {
 +      if (glyph <= ranges[i].nLeft)
 +      {
 +        code = (hb_codepoint_t)ranges[i].first + glyph;
 +        return true;
 +      }
 +      glyph -= (ranges[i].nLeft + 1);
 +    }
 +  
 +    return false;
 +  }
 +
 +  HBUINT8           nRanges;
 +  Encoding1_Range   ranges[VAR];
 +
 +  DEFINE_SIZE_ARRAY (1, ranges);
 +};
 +
 +struct EncSupplement {
 +  inline bool sanitize (hb_sanitize_context_t *c) const
 +  {
 +    TRACE_SANITIZE (this);
 +    return_trace (c->check_struct (this));
 +  }
 +
 +  HBUINT8   code;
 +  HBUINT16  glyph;
 +
 +  DEFINE_SIZE_STATIC (3);
 +};
 +
 +struct CFF1SuppEncData {
 +  inline bool sanitize (hb_sanitize_context_t *c) const
 +  {
 +    TRACE_SANITIZE (this);
 +    return_trace (c->check_struct (this) && ((nSups == 0) || (supps[nSups - 1]).sanitize (c)));
 +  }
 +
 +  inline bool get_code (hb_codepoint_t glyph, hb_codepoint_t &code) const
 +  {
 +    for (unsigned int i = 0; i < nSups; i++)
 +      if (glyph == supps[i].glyph)
 +      {
 +        code = supps[i].code;
 +        return true;
 +      }
 +  
 +    return false;
 +  }
 +
 +  inline unsigned int get_size (void) const
 +  { return HBUINT8::static_size + EncSupplement::static_size * nSups; }
 +
 +  HBUINT8         nSups;
 +  EncSupplement   supps[VAR];
 +
 +  DEFINE_SIZE_ARRAY (1, supps);
 +};
 +
 +struct Encoding {
 +  inline bool sanitize (hb_sanitize_context_t *c) const
 +  {
 +    TRACE_SANITIZE (this);
 +
 +    if (unlikely (!c->check_struct (this)))
 +      return_trace (false);
 +    unsigned int fmt = format & 0x7F;
 +    if (unlikely (fmt > 1))
 +      return_trace (false);
 +    if (unlikely (!((fmt == 0)? u.format0.sanitize (c): u.format1.sanitize (c))))
 +      return_trace (false);
 +    return_trace (((format & 0x80) == 0) || suppEncData ().sanitize (c));
 +  }
 +
 +  inline bool serialize (hb_serialize_context_t *c, const Encoding &src, unsigned int num_glyphs)
 +  {
 +    TRACE_SERIALIZE (this);
 +    unsigned int size = src.get_size ();
 +    Encoding *dest = c->allocate_size<Encoding> (size);
 +    if (unlikely (dest == nullptr)) return_trace (false);
 +    memcpy (dest, &src, size);
 +    return_trace (true);
 +  }
 +
 +  inline unsigned int calculate_serialized_size (void) const
 +  { return get_size (); } // XXX: TODO
 +
 +  inline unsigned int get_size (void) const
 +  {
 +    unsigned int size = min_size;
 +    if ((format & 0x7F) == 0)
 +      size += u.format0.get_size ();
 +    else
 +      size += u.format1.get_size ();
 +    if ((format & 0x80) != 0)
 +      size += suppEncData ().get_size ();
 +    return size;
 +  }
 +
 +  inline bool get_code (hb_codepoint_t glyph, hb_codepoint_t &code) const
 +  {
 +    // XXX: TODO
 +    return false;
 +  }
 +
 +  inline const CFF1SuppEncData &suppEncData (void) const
 +  {
 +    if ((format & 0x7F) == 0)
 +      return StructAfter<CFF1SuppEncData> (u.format0.codes[u.format0.nCodes-1]);
 +    else
 +      return StructAfter<CFF1SuppEncData> (u.format1.ranges[u.format1.nRanges-1]);
 +  }
 +
 +  HBUINT8       format;
 +  union {
 +    Encoding0   format0;
 +    Encoding1   format1;
 +  } u;
 +  /* CFF1SuppEncData  suppEncData; */
 +
 +  DEFINE_SIZE_MIN (1);
 +};
 +
 +/* Charset */
 +struct Charset0 {
 +  inline bool sanitize (hb_sanitize_context_t *c, unsigned int num_glyphs) const
 +  {
 +    TRACE_SANITIZE (this);
 +    return_trace (c->check_struct (this) && sids[num_glyphs - 1].sanitize (c));
 +  }
 +
 +  inline unsigned int get_sid (hb_codepoint_t glyph)
 +  {
 +    if (glyph == 0)
 +      return 0;
 +    else
 +      return sids[glyph - 1];
 +  }
 +
 +  inline unsigned int get_size (unsigned int num_glyphs) const
 +  {
 +    assert (num_glyphs > 0);
 +    return HBUINT16::static_size * (num_glyphs - 1);
 +  }
 +
 +  HBUINT16  sids[VAR];
 +
 +  DEFINE_SIZE_ARRAY(0, sids);
 +};
 +
 +template <typename TYPE>
 +struct Charset_Range {
 +  inline bool sanitize (hb_sanitize_context_t *c) const
 +  {
 +    TRACE_SANITIZE (this);
 +    return_trace (c->check_struct (this));
 +  }
 +
 +  HBUINT8   first;
 +  TYPE      nLeft;
 +
 +  DEFINE_SIZE_STATIC (1 + TYPE::static_size);
 +};
 +
 +template <typename TYPE>
 +struct Charset1_2 {
 +  inline bool sanitize (hb_sanitize_context_t *c) const
 +  {
 +    TRACE_SANITIZE (this);
 +    return_trace (c->check_struct (this) && ((nRanges == 0) || (ranges[nRanges - 1]).sanitize (c)));
 +  }
 +
 +  inline bool get_sid (hb_codepoint_t glyph, unsigned int &sid) const
 +  {
 +    for (unsigned int i = 0; i < nRanges; i++)
 +    {
 +      if (glyph <= ranges[i].nLeft)
 +      {
 +        sid = (hb_codepoint_t)ranges[i].first + glyph;
 +        return true;
 +      }
 +      glyph -= (ranges[i].nLeft + 1);
 +    }
 +  
 +    return false;
 +  }
 +
 +  inline unsigned int get_size (void) const
 +  { return HBUINT8::static_size + Charset_Range<TYPE>::static_size * nRanges; }
 +
 +  HBUINT8               nRanges;
 +  Charset_Range<TYPE>   ranges[VAR];
 +
 +  DEFINE_SIZE_ARRAY (1, ranges);
 +};
 +
 +struct Charset {
 +  inline bool sanitize (hb_sanitize_context_t *c) const
 +  {
 +    TRACE_SANITIZE (this);
 +
 +    if (unlikely (!c->check_struct (this)))
 +      return_trace (false);
 +    if (format == 0)
 +      return_trace (u.format0.sanitize (c, c->get_num_glyphs ()));
 +    else if (format == 1)
 +      return_trace (u.format1.sanitize (c));
 +    else if (likely (format == 2))
 +      return_trace (u.format2.sanitize (c));
 +    else
 +      return_trace (false);
 +  }
 +
 +  inline bool serialize (hb_serialize_context_t *c, const Charset &src, unsigned int num_glyphs)
 +  {
 +    TRACE_SERIALIZE (this);
 +    unsigned int size = src.get_size (num_glyphs);
 +    Charset *dest = c->allocate_size<Charset> (size);
 +    if (unlikely (dest == nullptr)) return_trace (false);
 +    memcpy (dest, &src, size);
 +    return_trace (true);
 +  }
 +
 +  inline unsigned int calculate_serialized_size (unsigned int num_glyphs) const
 +  { return get_size (num_glyphs); } // XXX: TODO
 +
 +  inline unsigned int get_size (unsigned int num_glyphs) const
 +  {
 +    unsigned int size = min_size;
 +    if (format == 0)
 +      size += u.format0.get_size (num_glyphs);
 +    else if (format == 1)
 +      size += u.format1.get_size ();
 +    else
 +      size += u.format2.get_size ();
 +    return size;
 +  }
 +
 +  inline bool get_sid (hb_codepoint_t glyph, unsigned int &sid) const
 +  {
 +    // XXX: TODO
 +    return false;
 +  }
 +
 +  HBUINT8       format;
 +  union {
 +    Charset0              format0;
 +    Charset1_2<HBUINT8>   format1;
 +    Charset1_2<HBUINT16>  format2;
 +  } u;
 +
 +  DEFINE_SIZE_MIN (1);
 +};
 +
 +struct CFF1TopDictValues : TopDictValues
 +{
 +  inline void init (void)
 +  {
 +    TopDictValues::init ();
 +
 +    ros[0] = ros[1] = ros[2] = 0;
 +    cidCount = 8720;
 +    EncodingOffset = 0;
 +    CharsetOffset = 0;
 +    FDSelectOffset = 0;
 +    privateDictInfo.init ();
 +  }
 +
 +  inline void fini (void)
 +  {
 +    TopDictValues::fini ();
 +  }
 +
 +  inline bool is_CID (void) const
 +  { return ros[0] != 0; }
 +
 +  inline unsigned int calculate_serialized_size (void) const
 +  {
 +    unsigned int size = 0;
 +    for (unsigned int i = 0; i < values.len; i++)
 +    {
 +      OpCode op = values[i].op;
 +      switch (op)
 +      {
 +        case OpCode_FDSelect:
 +          size += OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (op);
 +          break;
 +        default:
 +          size += TopDictValues::calculate_serialized_op_size (values[i]);
 +          break;
 +      }
 +    }
 +    return size;
 +  }
 +
 +  unsigned int              ros[3]; /* registry, ordering, supplement */
 +  unsigned int              cidCount;
 +
 +  enum EncodingID { StandardEncoding = 0, ExpertEncoding = 1 };
 +  unsigned int  EncodingOffset;
 +  unsigned int  CharsetOffset;
 +  unsigned int  FDSelectOffset;
 +  TableInfo     privateDictInfo;
 +};
 +
 +struct CFF1TopDictOpSet : TopDictOpSet
 +{
 +  static inline bool process_op (OpCode op, InterpEnv& env, CFF1TopDictValues& dictval)
 +  {
 +  
 +    switch (op) {
 +      case OpCode_version:
 +      case OpCode_Notice:
 +      case OpCode_Copyright:
 +      case OpCode_FullName:
 +      case OpCode_FamilyName:
 +      case OpCode_Weight:
 +      case OpCode_isFixedPitch:
 +      case OpCode_ItalicAngle:
 +      case OpCode_UnderlinePosition:
 +      case OpCode_UnderlineThickness:
 +      case OpCode_PaintType:
 +      case OpCode_CharstringType:
 +      case OpCode_UniqueID:
 +      case OpCode_StrokeWidth:
 +      case OpCode_SyntheticBase:
 +      case OpCode_PostScript:
 +      case OpCode_BaseFontName:
 +      case OpCode_CIDFontVersion:
 +      case OpCode_CIDFontRevision:
 +      case OpCode_CIDFontType:
 +      case OpCode_UIDBase:
 +      case OpCode_FontBBox:
 +      case OpCode_XUID:
 +      case OpCode_BaseFontBlend:
 +        env.argStack.clear ();
 +        break;
 +        
 +      case OpCode_CIDCount:
 +        if (unlikely (!env.argStack.check_pop_uint (dictval.cidCount)))
 +          return false;
 +        env.argStack.clear ();
 +        break;
 +
 +      case OpCode_ROS:
 +        if (unlikely (!env.argStack.check_pop_uint (dictval.ros[2]) ||
 +                      !env.argStack.check_pop_uint (dictval.ros[1]) ||
 +                      !env.argStack.check_pop_uint (dictval.ros[0])))
 +          return false;
 +        env.argStack.clear ();
 +        break;
 +
 +      case OpCode_Encoding:
 +        if (unlikely (!env.argStack.check_pop_uint (dictval.EncodingOffset)))
 +          return false;
 +        env.argStack.clear ();
 +        break;
 +
 +      case OpCode_charset:
 +        if (unlikely (!env.argStack.check_pop_uint (dictval.CharsetOffset)))
 +          return false;
 +        env.argStack.clear ();
 +        break;
 +
 +      case OpCode_FDSelect:
 +        if (unlikely (!env.argStack.check_pop_uint (dictval.FDSelectOffset)))
 +          return false;
 +        env.argStack.clear ();
 +        break;
 +    
 +      case OpCode_Private:
 +        if (unlikely (!env.argStack.check_pop_uint (dictval.privateDictInfo.offset)))
 +          return false;
 +        if (unlikely (!env.argStack.check_pop_uint (dictval.privateDictInfo.size)))
 +          return false;
 +        env.argStack.clear ();
 +        break;
 +    
 +      default:
 +        if (unlikely (!TopDictOpSet::process_op (op, env, dictval)))
 +          return false;
 +        /* Record this operand below if stack is empty, otherwise done */
 +        if (!env.argStack.is_empty ()) return true;
 +        break;
 +    }
 +
 +    dictval.pushVal (op, env.substr);
 +    return true;
 +  }
 +};
 +
 +struct CFF1FontDictValues : DictValues<OpStr>
 +{
 +  inline void init (void)
 +  {
 +    DictValues<OpStr>::init ();
 +    privateDictInfo.init ();
 +  }
 +
 +  inline void fini (void)
 +  {
 +    DictValues<OpStr>::fini ();
 +  }
 +
 +  TableInfo   privateDictInfo;
 +};
 +
 +struct CFF1FontDictOpSet : DictOpSet
 +{
 +  static inline bool process_op (OpCode op, InterpEnv& env, CFF1FontDictValues& dictval)
 +  {
 +    switch (op) {
 +      case OpCode_FontName:
 +      case OpCode_FontMatrix:
 +      case OpCode_PaintType:
 +        env.argStack.clear ();
 +        break;
 +      case OpCode_Private:
 +        if (unlikely (!env.argStack.check_pop_uint (dictval.privateDictInfo.offset)))
 +          return false;
 +        if (unlikely (!env.argStack.check_pop_uint (dictval.privateDictInfo.size)))
 +          return false;
 +        env.argStack.clear ();
 +        break;
 +    
 +      default:
 +        if (unlikely (!DictOpSet::process_op (op, env)))
 +          return false;
 +        if (!env.argStack.is_empty ()) return true;
 +        break;
 +    }
 +
 +    dictval.pushVal (op, env.substr);
 +    return true;
 +  }
 +};
 +
 +template <typename VAL>
 +struct CFF1PrivateDictValues_Base : DictValues<VAL>
 +{
 +  inline void init (void)
 +  {
 +    DictValues<VAL>::init ();
 +    subrsOffset = 0;
 +    localSubrs = &Null(CFF1Subrs);
 +  }
 +
 +  inline void fini (void)
 +  {
 +    DictValues<VAL>::fini ();
 +  }
 +
 +  inline unsigned int calculate_serialized_size (void) const
 +  {
 +    unsigned int size = 0;
 +    for (unsigned int i = 0; i < DictValues<VAL>::values.len; i++)
 +      if (DictValues<VAL>::values[i].op == OpCode_Subrs)
 +        size += OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_Subrs);
 +      else
 +        size += DictValues<VAL>::values[i].str.len;
 +    return size;
 +  }
 +
 +  unsigned int      subrsOffset;
 +  const CFF1Subrs    *localSubrs;
 +};
 +
 +typedef CFF1PrivateDictValues_Base<OpStr> CFF1PrivateDictValues_Subset;
 +typedef CFF1PrivateDictValues_Base<DictVal> CFF1PrivateDictValues;
 +
 +struct CFF1PrivateDictOpSet : DictOpSet
 +{
 +  static inline bool process_op (OpCode op, InterpEnv& env, CFF1PrivateDictValues& dictval)
 +  {
 +    DictVal val;
 +    val.init ();
 +
 +    switch (op) {
 +      case OpCode_BlueValues:
 +      case OpCode_OtherBlues:
 +      case OpCode_FamilyBlues:
 +      case OpCode_FamilyOtherBlues:
 +      case OpCode_StemSnapH:
 +      case OpCode_StemSnapV:
 +        if (unlikely (!env.argStack.check_pop_delta (val.multi_val)))
 +          return false;
 +        break;
 +      case OpCode_StdHW:
 +      case OpCode_StdVW:
 +      case OpCode_BlueScale:
 +      case OpCode_BlueShift:
 +      case OpCode_BlueFuzz:
 +      case OpCode_ForceBold:
 +      case OpCode_LanguageGroup:
 +      case OpCode_ExpansionFactor:
 +      case OpCode_initialRandomSeed:
 +      case OpCode_defaultWidthX:
 +      case OpCode_nominalWidthX:
 +        if (unlikely (!env.argStack.check_pop_num (val.single_val)))
 +          return false;
 +        env.argStack.clear ();
 +        break;
 +      case OpCode_Subrs:
 +        if (unlikely (!env.argStack.check_pop_uint (dictval.subrsOffset)))
 +          return false;
 +        env.argStack.clear ();
 +        break;
 +
 +      default:
 +        if (unlikely (!DictOpSet::process_op (op, env)))
 +          return false;
 +        if (!env.argStack.is_empty ()) return true;
 +        break;
 +    }
 +
 +    dictval.pushVal (op, env.substr, val);
 +    return true;
 +  }
 +};
 +
 +struct CFF1PrivateDictOpSet_Subset : DictOpSet
 +{
 +  static inline bool process_op (OpCode op, InterpEnv& env, CFF1PrivateDictValues_Subset& dictval)
 +  {
 +    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:
 +      case OpCode_initialRandomSeed:
 +      case OpCode_defaultWidthX:
 +      case OpCode_nominalWidthX:
 +        env.argStack.clear ();
 +        break;
 +
 +      case OpCode_Subrs:
 +        if (unlikely (!env.argStack.check_pop_uint (dictval.subrsOffset)))
 +          return false;
 +        env.argStack.clear ();
 +        break;
 +
 +      default:
 +        if (unlikely (!DictOpSet::process_op (op, env)))
 +          return false;
 +        if (!env.argStack.is_empty ()) return true;
 +        break;
 +    }
 +
 +    dictval.pushVal (op, env.substr);
 +    return true;
 +  }
 +};
 +
 +typedef DictInterpreter<CFF1TopDictOpSet, CFF1TopDictValues> CFF1TopDict_Interpreter;
 +typedef DictInterpreter<CFF1FontDictOpSet, CFF1FontDictValues> CFF1FontDict_Interpreter;
 +typedef DictInterpreter<CFF1PrivateDictOpSet, CFF1PrivateDictValues> CFF1PrivateDict_Interpreter;
 +
 +typedef CFF1Index CFF1NameIndex;
 +typedef CFF1IndexOf<TopDict> CFF1TopDictIndex;
 +typedef CFF1Index CFF1StringIndex;
 +
 +}; /* namespace CFF */
 +
 +namespace OT {
 +
 +using namespace CFF;
 +
 +struct cff1
 +{
 +  static const hb_tag_t tableTag        = HB_OT_TAG_cff1;
 +
 +  inline bool sanitize (hb_sanitize_context_t *c) const
 +  {
 +    TRACE_SANITIZE (this);
 +    return_trace (c->check_struct (this) &&
 +                  likely (version.major == 1));
 +  }
 +
 +  template <typename PrivOpSet, typename PrivDictVal>
 +  struct accelerator_templ_t
 +  {
 +    inline void init (hb_face_t *face)
 +    {
 +      topDicts.init ();
 +      topDicts.resize (1);
 +      topDicts[0].init ();
 +      fontDicts.init ();
 +      privateDicts.init ();
 +      
 +      this->blob = sc.reference_table<cff1> (face);
 +
 +      /* setup for run-time santization */
 +      sc.init (this->blob);
 +      sc.start_processing ();
 +      
 +      const OT::cff1 *cff = this->blob->template as<OT::cff1> ();
 +
 +      if (cff == &Null(OT::cff1))
 +      { fini (); return; }
 +
 +      nameIndex = &cff->nameIndex (cff);
 +      if ((nameIndex == &Null (CFF1NameIndex)) || !nameIndex->sanitize (&sc))
 +      { fini (); return; }
 +
 +      topDictIndex = &StructAtOffset<CFF1TopDictIndex> (nameIndex, nameIndex->get_size ());
 +      if ((topDictIndex == &Null (CFF1TopDictIndex)) || !topDictIndex->sanitize (&sc) || (topDictIndex->count == 0))
 +      { fini (); return; }
 +
 +      { /* parse top dict */
 +        const ByteStr topDictStr = (*topDictIndex)[0];
 +        if (unlikely (!topDictStr.sanitize (&sc))) { fini (); return; }
 +        CFF1TopDict_Interpreter top_interp;
 +        top_interp.env.init (topDictStr);
 +        if (unlikely (!top_interp.interpret (topDicts[0]))) { fini (); return; }
 +      }
 +      
 +      encoding = &Null(Encoding);
 +      charset = &StructAtOffsetOrNull<Charset> (cff, topDicts[0].CharsetOffset);
 +
 +      fdCount = 1;
 +      if (is_CID ())
 +      {
 +        fdArray = &StructAtOffsetOrNull<CFF1FDArray> (cff, topDicts[0].FDArrayOffset);
 +        fdSelect = &StructAtOffsetOrNull<CFF1FDSelect> (cff, topDicts[0].FDSelectOffset);
 +        if (unlikely ((fdArray == &Null(CFF1FDArray)) || !fdArray->sanitize (&sc) ||
 +            (fdSelect == &Null(CFF1FDSelect)) || !fdSelect->sanitize (&sc, fdArray->count)))
 +        { fini (); return; }
 +
 +        fdCount = fdArray->count;
 +      }
 +      else
 +      {
 +        fdArray = &Null(CFF1FDArray);
 +        fdSelect = &Null(CFF1FDSelect);
 +        if (topDicts[0].EncodingOffset != CFF1TopDictValues::StandardEncoding &&
 +            topDicts[0].EncodingOffset != CFF1TopDictValues::ExpertEncoding)
 +        {
 +          encoding = &StructAtOffsetOrNull<Encoding> (cff, topDicts[0].EncodingOffset);
 +          if ((encoding == &Null (Encoding)) || !encoding->sanitize (&sc))
 +          { fini (); return; }
 +        }
 +      }
 +
 +      stringIndex = &StructAtOffset<CFF1StringIndex> (topDictIndex, topDictIndex->get_size ());
 +      if ((stringIndex == &Null (CFF1StringIndex)) || !stringIndex->sanitize (&sc))
 +      { fini (); return; }
 +
 +      globalSubrs = &StructAtOffset<CFF1Subrs> (stringIndex, stringIndex->get_size ());
 +      if ((globalSubrs != &Null (CFF1Subrs)) && !stringIndex->sanitize (&sc))
 +      { fini (); return; }
 +
 +      charStrings = &StructAtOffsetOrNull<CFF1CharStrings> (cff, topDicts[0].charStringsOffset);
 +
 +      if ((charStrings == &Null(CFF1CharStrings)) || unlikely (!charStrings->sanitize (&sc)))
 +      { fini (); return; }
 +
 +      num_glyphs = charStrings->count;
 +      if (num_glyphs != sc.get_num_glyphs ())
 +      { fini (); return; }
 +
 +      privateDicts.resize (fdCount);
 +      for (unsigned int i = 0; i < fdCount; i++)
 +        privateDicts[i].init ();
 +
 +      // parse CID font dicts and gather private dicts
 +      if (is_CID ())
 +      {
 +        for (unsigned int i = 0; i < fdCount; i++)
 +        {
 +          ByteStr fontDictStr = (*fdArray)[i];
 +          if (unlikely (!fontDictStr.sanitize (&sc))) { fini (); return; }
 +          CFF1FontDictValues  *font;
 +          CFF1FontDict_Interpreter font_interp;
 +          font_interp.env.init (fontDictStr);
 +          font = fontDicts.push ();
 +          if (unlikely (!font_interp.interpret (*font))) { fini (); return; }
 +          PrivDictVal  *priv = &privateDicts[i];
 +          const ByteStr privDictStr (StructAtOffset<UnsizedByteStr> (cff, font->privateDictInfo.offset), font->privateDictInfo.size);
 +          if (unlikely (!privDictStr.sanitize (&sc))) { fini (); return; }
 +          DictInterpreter<PrivOpSet, PrivDictVal> priv_interp;
 +          priv_interp.env.init (privDictStr);
 +          if (unlikely (!priv_interp.interpret (*priv))) { fini (); return; }
 +
 +          priv->localSubrs = &StructAtOffsetOrNull<CFF1Subrs> (privDictStr.str, priv->subrsOffset);
 +          if (priv->localSubrs != &Null(CFF1Subrs) &&
 +              unlikely (!priv->localSubrs->sanitize (&sc)))
 +          { fini (); return; }
 +        }
 +      }
 +      else  /* non-CID */
 +      {
 +        CFF1TopDictValues  *font = &topDicts[0];
 +        PrivDictVal  *priv = &privateDicts[0];
 +        
 +        const ByteStr privDictStr (StructAtOffset<UnsizedByteStr> (cff, font->privateDictInfo.offset), font->privateDictInfo.size);
 +        if (unlikely (!privDictStr.sanitize (&sc))) { fini (); return; }
 +        DictInterpreter<PrivOpSet, PrivDictVal> priv_interp;
 +        priv_interp.env.init (privDictStr);
 +        if (unlikely (!priv_interp.interpret (*priv))) { fini (); return; }
 +
 +        priv->localSubrs = &StructAtOffsetOrNull<CFF1Subrs> (privDictStr.str, priv->subrsOffset);
 +        if (priv->localSubrs != &Null(CFF1Subrs) &&
 +            unlikely (!priv->localSubrs->sanitize (&sc)))
 +        { fini (); return; }
 +      }
 +    }
 +
 +    inline void fini (void)
 +    {
 +      sc.end_processing ();
 +      topDicts[0].fini ();
 +      topDicts.fini ();
 +      fontDicts.fini ();
 +      privateDicts.fini ();
 +      hb_blob_destroy (blob);
 +      blob = nullptr;
 +    }
 +
 +    inline bool is_valid (void) const { return blob != nullptr; }
 +    inline bool is_CID (void) const { return topDicts[0].is_CID (); }
 +
 +    inline bool get_extents (hb_codepoint_t glyph,
 +           hb_glyph_extents_t *extents) const
 +    {
 +      // XXX: TODO
 +      if (glyph >= num_glyphs)
 +        return false;
 +      
 +      return true;
 +    }
 +
 +    protected:
 +    hb_blob_t               *blob;
 +    hb_sanitize_context_t   sc;
 +
 +    public:
 +    const CFF1NameIndex     *nameIndex;
 +    const CFF1TopDictIndex  *topDictIndex;
 +    const CFF1StringIndex   *stringIndex;
 +    const Encoding          *encoding;
 +    const Charset           *charset;
 +    const CFF1Subrs         *globalSubrs;
 +    const CFF1CharStrings   *charStrings;
 +    const CFF1FDArray       *fdArray;
 +    const CFF1FDSelect      *fdSelect;
 +    unsigned int            fdCount;
 +
 +    hb_vector_t<CFF1TopDictValues>    topDicts;
 +    hb_vector_t<CFF1FontDictValues>   fontDicts;
 +    hb_vector_t<PrivDictVal>          privateDicts;
 +
 +    unsigned int            num_glyphs;
 +  };
 +
 +  typedef accelerator_templ_t<CFF1PrivateDictOpSet, CFF1PrivateDictValues> accelerator_t;
 +  typedef accelerator_templ_t<CFF1PrivateDictOpSet_Subset, CFF1PrivateDictValues_Subset> accelerator_subset_t;
 +
 +  inline bool subset (hb_subset_plan_t *plan) const
 +  {
 +    hb_blob_t *cff_prime = nullptr;
 +
 +    bool success = true;
 +    if (hb_subset_cff1 (plan, &cff_prime)) {
 +      success = success && plan->add_table (HB_OT_TAG_cff1, cff_prime);
 +    } else {
 +      success = false;
 +    }
 +    hb_blob_destroy (cff_prime);
 +
 +    return success;
 +  }
 +
 +  public:
 +  FixedVersion<HBUINT8> version;          /* Version of CFF table. set to 0x0100u */
 +  OffsetTo<CFF1NameIndex, HBUINT8> nameIndex; /* headerSize = Offset to Name INDEX. */
 +  HBUINT8               offSize;          /* offset size (unused?) */
 +
 +  public:
 +  DEFINE_SIZE_STATIC (4);
 +};
 +
 +} /* namespace OT */
 +
 +#endif /* HB_OT_CFF1_TABLE_HH */
index da4acf4,0000000..bf0a97d
mode 100644,000000..100644
--- /dev/null
@@@ -1,542 -1,0 +1,542 @@@
- #include "hb-ot-cff-common-private.hh"
 +/*
 + * Copyright © 2018 Adobe Systems Incorporated.
 + *
 + *  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_OT_CFF2_TABLE_HH
 +#define HB_OT_CFF2_TABLE_HH
 +
++#include "hb-ot-cff-common.hh"
 +#include "hb-subset-cff2.hh"
 +
 +namespace CFF {
 +
 +/*
 + * CFF2 -- Compact Font Format (CFF) Version 2
 + * https://docs.microsoft.com/en-us/typography/opentype/spec/cff2
 + */
 +#define HB_OT_TAG_cff2 HB_TAG('C','F','F','2')
 +
 +typedef CFFIndex<HBUINT32>  CFF2Index;
 +template <typename Type> struct CFF2IndexOf : IndexOf<HBUINT32, Type> {};
 +
 +typedef CFF2Index         CFF2CharStrings;
 +typedef FDArray<HBUINT32> CFF2FDArray;
 +typedef Subrs<HBUINT32>   CFF2Subrs;
 +
 +typedef FDSelect3_4<HBUINT32, HBUINT16> FDSelect4;
 +typedef FDSelect3_4_Range<HBUINT32, HBUINT16> FDSelect4_Range;
 +
 +struct CFF2FDSelect
 +{
 +  inline bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const
 +  {
 +    TRACE_SANITIZE (this);
 +
 +    return_trace (likely (c->check_struct (this) && (format == 0 || format == 3 || format == 4) &&
 +                          (format == 0)?
 +                          u.format0.sanitize (c, fdcount):
 +                            ((format == 3)?
 +                            u.format3.sanitize (c, fdcount):
 +                            u.format4.sanitize (c, fdcount))));
 +  }
 +
 +  inline bool serialize (hb_serialize_context_t *c, const CFF2FDSelect &src, unsigned int num_glyphs)
 +  {
 +    TRACE_SERIALIZE (this);
 +    unsigned int size = src.get_size (num_glyphs);
 +    CFF2FDSelect *dest = c->allocate_size<CFF2FDSelect> (size);
 +    if (unlikely (dest == nullptr)) return_trace (false);
 +    memcpy (dest, &src, size);
 +    return_trace (true);
 +  }
 +
 +  inline unsigned int calculate_serialized_size (unsigned int num_glyphs) const
 +  { return get_size (num_glyphs); }
 +
 +  inline unsigned int get_size (unsigned int num_glyphs) const
 +  {
 +    unsigned int size = format.static_size;
 +    if (format == 0)
 +      size += u.format0.get_size (num_glyphs);
 +    else if (format == 3)
 +      size += u.format3.get_size ();
 +    else
 +      size += u.format4.get_size ();
 +    return size;
 +  }
 +
 +  inline hb_codepoint_t get_fd (hb_codepoint_t glyph) const
 +  {
 +    if (this == &Null(CFF2FDSelect))
 +      return 0;
 +    if (format == 0)
 +      return u.format0.get_fd (glyph);
 +    else if (format == 3)
 +      return u.format3.get_fd (glyph);
 +    else
 +      return u.format4.get_fd (glyph);
 +  }
 +
 +  HBUINT8       format;
 +  union {
 +    FDSelect0   format0;
 +    FDSelect3   format3;
 +    FDSelect4   format4;
 +  } u;
 +
 +  DEFINE_SIZE_MIN (2);
 +};
 +
 +struct CFF2VariationStore
 +{
 +  inline bool sanitize (hb_sanitize_context_t *c) const
 +  {
 +    TRACE_SANITIZE (this);
 +    return_trace (likely (c->check_struct (this)) && varStore.sanitize (c));
 +  }
 +
 +  inline bool serialize (hb_serialize_context_t *c, const CFF2VariationStore *varStore)
 +  {
 +    TRACE_SERIALIZE (this);
 +    unsigned int size_ = varStore->get_size ();
 +    CFF2VariationStore *dest = c->allocate_size<CFF2VariationStore> (size_);
 +    if (unlikely (dest == nullptr)) return_trace (false);
 +    memcpy (dest, varStore, size_);
 +    return_trace (true);
 +  }
 +
 +  inline unsigned int get_size (void) const { return HBUINT16::static_size + size; }
 +
 +  HBUINT16        size;
 +  VariationStore  varStore;
 +
 +  DEFINE_SIZE_MIN (2 + VariationStore::min_size);
 +};
 +
 +struct CFF2TopDictValues : TopDictValues
 +{
 +  inline void init (void)
 +  {
 +    TopDictValues::init ();
 +    vstoreOffset = 0;
 +    FDSelectOffset = 0;
 +  }
 +
 +  inline void fini (void)
 +  {
 +    TopDictValues::fini ();
 +  }
 +
 +  inline unsigned int calculate_serialized_size (void) const
 +  {
 +    unsigned int size = 0;
 +    for (unsigned int i = 0; i < values.len; i++)
 +    {
 +      OpCode op = values[i].op;
 +      switch (op)
 +      {
 +        case OpCode_vstore:
 +        case OpCode_FDSelect:
 +          size += OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (op);
 +          break;
 +        default:
 +          size += TopDictValues::calculate_serialized_op_size (values[i]);
 +          break;
 +      }
 +    }
 +    return size;
 +  }
 +
 +  unsigned int  vstoreOffset;
 +  unsigned int  FDSelectOffset;
 +};
 +
 +struct CFF2TopDictOpSet : TopDictOpSet
 +{
 +  static inline bool process_op (OpCode op, InterpEnv& env, CFF2TopDictValues& dictval)
 +  {
 +    switch (op) {
 +      case OpCode_FontMatrix:
 +        {
 +          DictVal val;
 +          val.init ();
 +          dictval.pushVal (op, env.substr);
 +          env.argStack.clear ();
 +        }
 +        break;
 +
 +      case OpCode_vstore:
 +        if (unlikely (!env.argStack.check_pop_uint (dictval.vstoreOffset)))
 +          return false;
 +        env.argStack.clear ();
 +        break;
 +      case OpCode_FDSelect:
 +        if (unlikely (!env.argStack.check_pop_uint (dictval.FDSelectOffset)))
 +          return false;
 +        env.argStack.clear ();
 +        break;
 +    
 +      default:
 +        if (unlikely (!TopDictOpSet::process_op (op, env, dictval)))
 +          return false;
 +        /* Record this operand below if stack is empty, otherwise done */
 +        if (!env.argStack.is_empty ()) return true;
 +    }
 +
 +    dictval.pushVal (op, env.substr);
 +    return true;
 +  }
 +};
 +
 +struct CFF2FontDictValues : DictValues<OpStr>
 +{
 +  inline void init (void)
 +  {
 +    DictValues<OpStr>::init ();
 +    privateDictInfo.init ();
 +  }
 +
 +  inline void fini (void)
 +  {
 +    DictValues<OpStr>::fini ();
 +  }
 +
 +  TableInfo    privateDictInfo;
 +};
 +
 +struct CFF2FontDictOpSet : DictOpSet
 +{
 +  static inline bool process_op (OpCode op, InterpEnv& env, CFF2FontDictValues& dictval)
 +  {
 +    switch (op) {
 +      case OpCode_Private:
 +        if (unlikely (!env.argStack.check_pop_uint (dictval.privateDictInfo.offset)))
 +          return false;
 +        if (unlikely (!env.argStack.check_pop_uint (dictval.privateDictInfo.size)))
 +          return false;
 +        env.argStack.clear ();
 +        break;
 +    
 +      default:
 +        if (unlikely (!DictOpSet::process_op (op, env)))
 +          return false;
 +        if (!env.argStack.is_empty ())
 +          return true;
 +    }
 +
 +    dictval.pushVal (op, env.substr);
 +    return true;
 +  }
 +};
 +
 +template <typename VAL>
 +struct CFF2PrivateDictValues_Base : DictValues<VAL>
 +{
 +  inline void init (void)
 +  {
 +    DictValues<VAL>::init ();
 +    subrsOffset = 0;
 +    localSubrs = &Null(CFF2Subrs);
 +  }
 +
 +  inline void fini (void)
 +  {
 +    DictValues<VAL>::fini ();
 +  }
 +
 +  inline unsigned int calculate_serialized_size (void) const
 +  {
 +    unsigned int size = 0;
 +    for (unsigned int i = 0; i < DictValues<VAL>::values.len; i++)
 +      if (DictValues<VAL>::values[i].op == OpCode_Subrs)
 +        size += OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_Subrs);
 +      else
 +        size += DictValues<VAL>::values[i].str.len;
 +    return size;
 +  }
 +
 +  unsigned int      subrsOffset;
 +  const CFF2Subrs   *localSubrs;
 +};
 +
 +typedef CFF2PrivateDictValues_Base<OpStr> CFF2PrivateDictValues_Subset;
 +typedef CFF2PrivateDictValues_Base<DictVal> CFF2PrivateDictValues;
 +
 +struct CFF2PrivateDictOpSet : DictOpSet
 +{
 +  static inline bool process_op (OpCode op, InterpEnv& env, CFF2PrivateDictValues& dictval)
 +  {
 +    DictVal val;
 +    val.init ();
 +
 +    switch (op) {
 +      case OpCode_StdHW:
 +      case OpCode_StdVW:
 +      case OpCode_BlueScale:
 +      case OpCode_BlueShift:
 +      case OpCode_BlueFuzz:
 +      case OpCode_ExpansionFactor:
 +      case OpCode_LanguageGroup:
 +        if (unlikely (!env.argStack.check_pop_num (val.single_val)))
 +          return false;
 +        env.argStack.clear ();
 +        break;
 +      case OpCode_BlueValues:
 +      case OpCode_OtherBlues:
 +      case OpCode_FamilyBlues:
 +      case OpCode_FamilyOtherBlues:
 +      case OpCode_StemSnapH:
 +      case OpCode_StemSnapV:
 +        if (unlikely (!env.argStack.check_pop_delta (val.multi_val)))
 +          return false;
 +        env.argStack.clear ();
 +        break;
 +      case OpCode_Subrs:
 +        if (unlikely (!env.argStack.check_pop_uint (dictval.subrsOffset)))
 +          return false;
 +        env.argStack.clear ();
 +        break;
 +      case OpCode_vsindexdict:
 +      case OpCode_blenddict:
 +        // XXX: TODO
 +        return true;
 +
 +      default:
 +        if (unlikely (!DictOpSet::process_op (op, env)))
 +          return false;
 +        if (!env.argStack.is_empty ()) return true;
 +        break;
 +    }
 +
 +    dictval.pushVal (op, env.substr, val);
 +    return true;
 +  }
 +};
 +
 +struct CFF2PrivateDictOpSet_Subset : DictOpSet
 +{
 +  static inline bool process_op (OpCode op, InterpEnv& env, CFF2PrivateDictValues_Subset& dictval)
 +  {
 +    switch (op) {
 +      case OpCode_BlueValues:
 +      case OpCode_OtherBlues:
 +      case OpCode_FamilyBlues:
 +      case OpCode_FamilyOtherBlues:
 +      case OpCode_StdHW:
 +      case OpCode_StdVW:
 +      case OpCode_BlueScale:
 +      case OpCode_BlueShift:
 +      case OpCode_BlueFuzz:
 +      case OpCode_StemSnapH:
 +      case OpCode_StemSnapV:
 +      case OpCode_LanguageGroup:
 +      case OpCode_ExpansionFactor:
 +        env.argStack.clear ();
 +        break;
 +
 +      case OpCode_blenddict:
 +        env.argStack.clear ();
 +        return true;
 +
 +      case OpCode_Subrs:
 +        if (unlikely (!env.argStack.check_pop_uint (dictval.subrsOffset)))
 +          return false;
 +        env.argStack.clear ();
 +        break;
 +
 +      default:
 +        if (unlikely (!DictOpSet::process_op (op, env)))
 +          return false;
 +        if (!env.argStack.is_empty ()) return true;
 +        break;
 +    }
 +
 +    dictval.pushVal (op, env.substr);
 +    return true;
 +  }
 +};
 +
 +typedef DictInterpreter<CFF2TopDictOpSet, CFF2TopDictValues> CFF2TopDict_Interpreter;
 +typedef DictInterpreter<CFF2FontDictOpSet, CFF2FontDictValues> CFF2FontDict_Interpreter;
 +typedef DictInterpreter<CFF2PrivateDictOpSet, CFF2PrivateDictValues> CFF2PrivateDict_Interpreter;
 +
 +}; /* namespace CFF */
 +
 +namespace OT {
 +
 +using namespace CFF;
 +
 +struct cff2
 +{
 +  static const hb_tag_t tableTag        = HB_OT_TAG_cff2;
 +
 +  inline bool sanitize (hb_sanitize_context_t *c) const
 +  {
 +    TRACE_SANITIZE (this);
 +    return_trace (c->check_struct (this) &&
 +                  likely (version.major == 2));
 +  }
 +
 +  template <typename PrivOpSet, typename PrivDictVal>
 +  struct accelerator_templ_t
 +  {
 +    inline void init (hb_face_t *face)
 +    {
 +      topDict.init ();
 +      fontDicts.init ();
 +      privateDicts.init ();
 +      
 +      this->blob = sc.reference_table<cff2> (face);
 +
 +      /* setup for run-time santization */
 +      sc.init (this->blob);
 +      sc.start_processing ();
 +      
 +      const OT::cff2 *cff2 = this->blob->template as<OT::cff2> ();
 +
 +      if (cff2 == &Null(OT::cff2))
 +      { fini (); return; }
 +
 +      { /* parse top dict */
 +        ByteStr topDictStr (cff2 + cff2->topDict, cff2->topDictSize);
 +        if (unlikely (!topDictStr.sanitize (&sc))) { fini (); return; }
 +        CFF2TopDict_Interpreter top_interp;
 +        top_interp.env.init (topDictStr);
 +        if (unlikely (!top_interp.interpret (topDict))) { fini (); return; }
 +      }
 +      
 +      globalSubrs = &StructAtOffset<CFF2Subrs> (cff2, cff2->topDict + cff2->topDictSize);
 +      varStore = &StructAtOffsetOrNull<CFF2VariationStore> (cff2, topDict.vstoreOffset);
 +      charStrings = &StructAtOffsetOrNull<CFF2CharStrings> (cff2, topDict.charStringsOffset);
 +      fdArray = &StructAtOffsetOrNull<CFF2FDArray> (cff2, topDict.FDArrayOffset);
 +      fdSelect = &StructAtOffsetOrNull<CFF2FDSelect> (cff2, topDict.FDSelectOffset);
 +      
 +      if (((varStore != &Null(CFF2VariationStore)) && unlikely (!varStore->sanitize (&sc))) ||
 +          (charStrings == &Null(CFF2CharStrings)) || unlikely (!charStrings->sanitize (&sc)) ||
 +          (fdArray == &Null(CFF2FDArray)) || unlikely (!fdArray->sanitize (&sc)) ||
 +          (((fdSelect != &Null(CFF2FDSelect)) && unlikely (!fdSelect->sanitize (&sc, fdArray->count)))))
 +      { fini (); return; }
 +
 +      num_glyphs = charStrings->count;
 +      if (num_glyphs != sc.get_num_glyphs ())
 +      { fini (); return; }
 +
 +      fdCount = fdArray->count;
 +      privateDicts.resize (fdCount);
 +
 +      /* parse font dicts and gather private dicts */
 +      for (unsigned int i = 0; i < fdCount; i++)
 +      {
 +        const ByteStr fontDictStr = (*fdArray)[i];
 +        if (unlikely (!fontDictStr.sanitize (&sc))) { fini (); return; }
 +        CFF2FontDictValues  *font;
 +        CFF2FontDict_Interpreter font_interp;
 +        font_interp.env.init (fontDictStr);
 +        font = fontDicts.push ();
 +        if (unlikely (!font_interp.interpret (*font))) { fini (); return; }
 +
 +        const ByteStr privDictStr (StructAtOffsetOrNull<UnsizedByteStr> (cff2, font->privateDictInfo.offset), font->privateDictInfo.size);
 +        if (unlikely (!privDictStr.sanitize (&sc))) { fini (); return; }
 +        DictInterpreter<PrivOpSet, PrivDictVal> priv_interp;
 +        priv_interp.env.init(privDictStr);
 +        if (unlikely (!priv_interp.interpret (privateDicts[i]))) { fini (); return; }
 +
 +        privateDicts[i].localSubrs = &StructAtOffsetOrNull<CFF2Subrs> (privDictStr.str, privateDicts[i].subrsOffset);
 +        if (privateDicts[i].localSubrs != &Null(CFF2Subrs) &&
 +          unlikely (!privateDicts[i].localSubrs->sanitize (&sc)))
 +        { fini (); return; }
 +      }
 +    }
 +
 +    inline void fini (void)
 +    {
 +      sc.end_processing ();
 +      fontDicts.fini ();
 +      privateDicts.fini ();
 +      hb_blob_destroy (blob);
 +      blob = nullptr;
 +    }
 +
 +    inline bool is_valid (void) const { return blob != nullptr; }
 +
 +    inline bool get_extents (hb_codepoint_t glyph,
 +           hb_glyph_extents_t *extents) const
 +    {
 +      // XXX: TODO
 +      if (glyph >= num_glyphs)
 +        return false;
 +      
 +      return true;
 +    }
 +
 +    protected:
 +    hb_blob_t               *blob;
 +    hb_sanitize_context_t   sc;
 +
 +    public:
 +    CFF2TopDictValues         topDict;
 +    const CFF2Subrs           *globalSubrs;
 +    const CFF2VariationStore  *varStore;
 +    const CFF2CharStrings     *charStrings;
 +    const CFF2FDArray         *fdArray;
 +    const CFF2FDSelect        *fdSelect;
 +    unsigned int              fdCount;
 +
 +    hb_vector_t<CFF2FontDictValues>     fontDicts;
 +    hb_vector_t<PrivDictVal>  privateDicts;
 +
 +    unsigned int            num_glyphs;
 +  };
 +
 +  typedef accelerator_templ_t<CFF2PrivateDictOpSet, CFF2PrivateDictValues> accelerator_t;
 +  typedef accelerator_templ_t<CFF2PrivateDictOpSet_Subset, CFF2PrivateDictValues_Subset> accelerator_subset_t;
 +
 +  inline bool subset (hb_subset_plan_t *plan) const
 +  {
 +    hb_blob_t *cff2_prime = nullptr;
 +
 +    bool success = true;
 +    if (hb_subset_cff2 (plan, &cff2_prime)) {
 +      success = success && plan->add_table (HB_OT_TAG_cff2, cff2_prime);
 +    } else {
 +      success = false;
 +    }
 +    hb_blob_destroy (cff2_prime);
 +
 +    return success;
 +  }
 +
 +  public:
 +  FixedVersion<HBUINT8> version;        /* Version of CFF2 table. set to 0x0200u */
 +  OffsetTo<TopDict, HBUINT8> topDict;   /* headerSize = Offset to Top DICT. */
 +  HBUINT16       topDictSize;           /* Top DICT size */
 +
 +  public:
 +  DEFINE_SIZE_STATIC (5);
 +};
 +
 +} /* namespace OT */
 +
 +#endif /* HB_OT_CFF2_TABLE_HH */
  #include "hb-ot-hmtx-table.hh"
  #include "hb-ot-kern-table.hh"
  #include "hb-ot-post-table.hh"
+ #include "hb-ot-glyf-table.hh"
++#include "hb-ot-cff1-table.hh"
++#include "hb-ot-cff2-table.hh"
  #include "hb-ot-color-cbdt-table.hh"
  
  
index 6796709,0000000..ec196ca
mode 100644,000000..100644
--- /dev/null
@@@ -1,202 -1,0 +1,202 @@@
- #include "hb-ot-cff-common-private.hh"
 +/*
 + * Copyright © 2018 Adobe Systems Incorporated.
 + *
 + *  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
 + */
 +
- #include "hb-subset-cff-common-private.hh"
++#include "hb-ot-cff-common.hh"
 +#include "hb-ot-cff2-table.hh"
++#include "hb-subset-cff-common.hh"
 +
 +using namespace CFF;
 +
 +/**
 + * hb_plan_subset_cff_fdselect
 + * Determine an optimal FDSelect format according to a provided plan.
 + *
 + * Return value: FDSelect format, size, and ranges for the most compact subset FDSelect
 + * along with a font index remapping table
 + **/
 +
 +bool
 +hb_plan_subset_cff_fdselect (const hb_vector_t<hb_codepoint_t> &glyphs,
 +                            unsigned int fdCount,
 +                            const FDSelect &src, /* IN */
 +                            unsigned int &subset_fd_count /* OUT */,
 +                            unsigned int &subst_fdselect_size /* OUT */,
 +                            unsigned int &subst_fdselect_format /* OUT */,
 +                            hb_vector_t<hb_codepoint_t> &subst_first_glyphs /* OUT */,
 +                            FDMap &fdmap /* OUT */)
 +{
 +  subset_fd_count = 0;
 +  subst_fdselect_size = 0;
 +  subst_fdselect_format = 0;
 +  unsigned int  num_ranges = 0;
 +
 +  unsigned int subset_num_glyphs = glyphs.len;
 +  if (subset_num_glyphs == 0)
 +    return true;
 +
 +  {
 +    /* use hb_set to determine the subset of font dicts */
 +    hb_set_t  *set = hb_set_create ();
 +    if (set == &Null (hb_set_t))
 +      return false;
 +    hb_codepoint_t  prev_fd = HB_SET_VALUE_INVALID;
 +    for (hb_codepoint_t i = 0; i < subset_num_glyphs; i++)
 +    {
 +      hb_codepoint_t  fd = src.get_fd (glyphs[i]);
 +      set->add (fd);
 +      
 +      if (fd != prev_fd)
 +      {
 +        num_ranges++;
 +        prev_fd = fd;
 +        subst_first_glyphs.push (i);
 +      }
 +    }
 +
 +    subset_fd_count = set->get_population ();
 +    if (subset_fd_count == fdCount)
 +    {
 +      /* all font dicts belong to the subset. no need to subset FDSelect & FDArray */
 +      hb_set_destroy (set);
 +      return true;
 +    }
 +
 +    /* create a fdmap */
 +    fdmap.resize (fdCount);
 +    for (unsigned int i = 0; i < fdmap.len; i++)
 +      fdmap[i] = HB_SET_VALUE_INVALID;
 +    hb_codepoint_t  fd = HB_SET_VALUE_INVALID;
 +    unsigned int fdindex = 0;
 +    while (set->next (&fd))
 +      fdmap[fd] = fdindex++;
 +    assert (fdindex == subset_fd_count);
 +    hb_set_destroy (set);
 +  }
 +
 +  /* determine which FDSelect format is most compact */
 +  if (subset_fd_count > 0xFF)
 +  {
 +    assert (src.format == 4);
 +    subst_fdselect_format = 4;
 +    subst_fdselect_size = FDSelect4::min_size + FDSelect4_Range::static_size * num_ranges;
 +  }
 +  else
 +  {
 +    unsigned int format0_size = FDSelect0::min_size + HBUINT8::static_size * subset_num_glyphs;
 +    unsigned int format3_size = FDSelect3::min_size + FDSelect3_Range::static_size * num_ranges;
 +
 +    if (format0_size <= format3_size)
 +    {
 +      // subst_fdselect_format = 0;
 +      subst_fdselect_size = format0_size;
 +      subst_first_glyphs.fini ();
 +    }
 +    else
 +    {
 +      subst_fdselect_format = 3;
 +      subst_fdselect_size = format3_size;
 +    }
 +  }
 +
 +  return true;
 +}
 +
 +template <typename FDSELECT3_4>
 +static inline bool
 +serialize_fdselect_3_4 (hb_serialize_context_t *c,
 +                          unsigned int num_glyphs,
 +                          const FDSelect &src,
 +                          unsigned int size,
 +                          const hb_vector_t<hb_codepoint_t> &first_glyphs,
 +                          const FDMap &fdmap)
 +{
 +  TRACE_SERIALIZE (this);
 +  FDSELECT3_4 *p = c->allocate_size<FDSELECT3_4> (size);
 +  if (unlikely (p == nullptr)) return_trace (false);
 +  p->nRanges.set (first_glyphs.len);
 +  for (unsigned int i = 0; i < first_glyphs.len; i++)
 +  {
 +    hb_codepoint_t  glyph = first_glyphs[i];
 +    p->ranges[i].first.set (glyph);
 +    p->ranges[i].fd.set (fdmap[src.get_fd (glyph)]);
 +  }
 +  p->sentinel().set (num_glyphs);
 +  return_trace (true);
 +}
 +
 +/**
 + * hb_serialize_cff_fdselect
 + * Serialize a subset FDSelect format planned above.
 + **/
 +bool
 +hb_serialize_cff_fdselect (hb_serialize_context_t *c,
 +                          const hb_vector_t<hb_codepoint_t> &glyphs,
 +                          const FDSelect &src,
 +                          unsigned int fd_count,
 +                          unsigned int fdselect_format,
 +                          unsigned int size,
 +                          const hb_vector_t<hb_codepoint_t> &first_glyphs,
 +                          const FDMap &fdmap)
 +{
 +  TRACE_SERIALIZE (this);
 +  FDSelect  *p = c->allocate_min<FDSelect> ();
 +  if (unlikely (p == nullptr)) return_trace (false);
 +  p->format.set (fdselect_format);
 +  size -= FDSelect::min_size;
 +
 +  switch (fdselect_format)
 +  {
 +    case 0:
 +    {
 +      FDSelect0 *p = c->allocate_size<FDSelect0> (size);
 +      if (unlikely (p == nullptr)) return_trace (false);
 +      for (unsigned int i = 0; i < glyphs.len; i++)
 +        p->fds[i].set (fdmap[src.get_fd (glyphs[i])]);
 +      break;
 +    }
 +    
 +    case 3:
 +      return serialize_fdselect_3_4<FDSelect3> (c,
 +                                                glyphs.len,
 +                                                src,
 +                                                size,
 +                                                first_glyphs,
 +                                                fdmap);
 +    
 +    case 4:
 +      return serialize_fdselect_3_4<FDSelect4> (c,
 +                                                glyphs.len,
 +                                                src,
 +                                                size,
 +                                                first_glyphs,
 +                                                fdmap);
 +
 +    default:
 +      assert(false);
 +  }
 +  
 +  return_trace (true);
 +}
index 4013c32,0000000..883584b
mode 100644,000000..100644
--- /dev/null
@@@ -1,233 -1,0 +1,233 @@@
- #include "hb-private.hh"
 +/*
 + * Copyright © 2018 Adobe Systems Incorporated.
 + *
 + *  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_SUBSET_CFF_COMMON_PRIVATE_HH
 +#define HB_SUBSET_CFF_COMMON_PRIVATE_HH
 +
- #include "hb-cff-interp-cs-common-private.hh"
++#include "hb.hh"
 +
 +#include "hb-subset-plan.hh"
++#include "hb-cff-interp-cs-common.hh"
 +
 +namespace CFF {
 +
 +/* Used for writing a temporary charstring */
 +struct ByteStrBuff : hb_vector_t<char, 1>
 +{
 +  inline bool encode_byte (unsigned char b)
 +  {
 +    return (push ((const char)b) != &Crap(char));
 +  }
 +
 +  inline bool encode_num (const Number& n)
 +  {
 +    if (n.in_int_range ())
 +    {
 +      int v = n.to_int ();
 +      if ((-1131 <= v) && (v <= 1131))
 +      {
 +        if ((-107 <= v) && (v <= 107))
 +          return encode_byte (v + 139);
 +        else if (v > 0)
 +        {
 +          v -= 108;
 +          return encode_byte ((v >> 8) + OpCode_TwoBytePosInt0) && encode_byte (v & 0xFF);
 +        }
 +        else
 +        {
 +          v = -v - 108;
 +          return encode_byte ((v >> 8) + OpCode_TwoByteNegInt0) && encode_byte (v & 0xFF);
 +        }
 +      }
 +      assert ((v & ~0xFFFF) == 0);
 +      return encode_byte (OpCode_shortint) &&
 +             encode_byte ((v >> 8) & 0xFF) &&
 +             encode_byte (v & 0xFF);
 +    }
 +    else
 +    {
 +      int32_t v = n.to_fixed ();
 +      return encode_byte (OpCode_fixedcs) &&
 +             encode_byte ((v >> 24) & 0xFF) &&
 +             encode_byte ((v >> 16) & 0xFF) &&
 +             encode_byte ((v >> 8) & 0xFF) &&
 +             encode_byte (v & 0xFF);
 +    }
 +  }
 +
 +  inline bool encode_op (OpCode op)
 +  {
 +    if (Is_OpCode_ESC (op))
 +      return encode_byte (OpCode_escape) &&
 +             encode_byte (Unmake_OpCode_ESC (op));
 +    else
 +      return encode_byte (op);
 +  }
 +};
 +
 +struct ByteStrBuffArray : hb_vector_t<ByteStrBuff, 1>
 +{
 +  inline void fini (void)
 +  {
 +    for (unsigned int i = 0; i < len; i++)
 +      hb_vector_t<ByteStrBuff, 1>::operator[] (i).fini ();
 +    hb_vector_t<ByteStrBuff, 1>::fini ();
 +  }
 +};
 +
 +
 +template <typename ACCESSOR, typename ENV, typename OPSET>
 +struct SubrFlattener
 +{
 +  inline SubrFlattener (const ACCESSOR &acc_, const hb_vector_t<hb_codepoint_t> &glyphs_)
 +    : acc (acc_),
 +      glyphs (glyphs_)
 +  {}
 +
 +  inline bool flatten (ByteStrBuffArray &flat_charstrings)
 +  {
 +    if (!flat_charstrings.resize (glyphs.len))
 +      return false;
 +    for (unsigned int i = 0; i < glyphs.len; i++)
 +      flat_charstrings[i].init ();
 +    for (unsigned int i = 0; i < glyphs.len; i++)
 +    {
 +      hb_codepoint_t  glyph = glyphs[i];
 +      const ByteStr str = (*acc.charStrings)[glyph];
 +      unsigned int fd = acc.fdSelect->get_fd (glyph);
 +      CSInterpreter<ENV, OPSET, ByteStrBuff> interp;
 +      interp.env.init (str, *acc.globalSubrs, *acc.privateDicts[fd].localSubrs);
 +      if (unlikely (!interp.interpret (flat_charstrings[i])))
 +        return false;
 +    }
 +    return true;
 +  }
 +  
 +  const ACCESSOR &acc;
 +  const hb_vector_t<hb_codepoint_t> &glyphs;
 +};
 +
 +struct SubrRefMaps
 +{
 +  inline void init (void)
 +  {
 +    valid = false;
 +    global_map = nullptr;
 +    local_maps.init ();
 +  }
 +
 +  inline void init (unsigned int fd_count)
 +  {
 +    valid = true;
 +    global_map = hb_set_create ();
 +    if (global_map == hb_set_get_empty ())
 +      valid = false;
 +    if (!local_maps.resize (fd_count))
 +      valid = false;
 +
 +    for (unsigned int i = 0; i < local_maps.len; i++)
 +    {
 +      local_maps[i] = hb_set_create ();
 +      if (local_maps[i] == hb_set_get_empty ())
 +        valid = false;
 +    }
 +  }
 +
 +  inline void fini (void)
 +  {
 +    hb_set_destroy (global_map);
 +    for (unsigned int i = 0; i < local_maps.len; i++)
 +      hb_set_destroy (local_maps[i]);
 +    local_maps.fini ();
 +  }
 +
 +  bool is_valid (void) const { return valid; }
 +  bool  valid;
 +  hb_set_t  *global_map;
 +  hb_vector_t<hb_set_t *> local_maps;
 +};
 +
 +struct SubrRefMapPair
 +{
 +  inline void init (void) {}
 +
 +  hb_set_t  *global_map;
 +  hb_set_t  *local_map;
 +};
 +
 +template <typename ACCESSOR, typename ENV, typename OPSET>
 +struct SubrSubsetter
 +{
 +  inline SubrSubsetter (const ACCESSOR &acc_, const hb_vector_t<hb_codepoint_t> &glyphs_)
 +    : acc (acc_),
 +      glyphs (glyphs_)
 +  {}
 +  
 +  bool collect_refs (SubrRefMaps& refmaps /*OUT*/)
 +  {
 +    refmaps.init (acc.fdCount);
 +    if (unlikely (!refmaps.valid)) return false;
 +    for (unsigned int i = 0; i < glyphs.len; i++)
 +    {
 +      hb_codepoint_t  glyph = glyphs[i];
 +      const ByteStr str = (*acc.charStrings)[glyph];
 +      unsigned int fd = acc.fdSelect->get_fd (glyph);
 +      SubrRefMapPair  pair = { refmaps.global_map, refmaps.local_maps[fd] };
 +      CSInterpreter<ENV, OPSET, SubrRefMapPair> interp;
 +      interp.env.init (str, *acc.globalSubrs, *acc.privateDicts[fd].localSubrs);
 +      if (unlikely (!interp.interpret (pair)))
 +        return false;
 +    }
 +    return true;
 +  }
 +
 +  const ACCESSOR &acc;
 +  const hb_vector_t<hb_codepoint_t> &glyphs;
 +};
 +
 +};  /* namespace CFF */
 +
 +HB_INTERNAL bool
 +hb_plan_subset_cff_fdselect (const hb_vector_t<hb_codepoint_t> &glyphs,
 +                            unsigned int fdCount,
 +                            const CFF::FDSelect &src, /* IN */
 +                            unsigned int &subset_fd_count /* OUT */,
 +                            unsigned int &subst_fdselect_size /* OUT */,
 +                            unsigned int &subst_fdselect_format /* OUT */,
 +                            hb_vector_t<hb_codepoint_t> &subst_first_glyphs /* OUT */,
 +                            CFF::FDMap &fdmap /* OUT */);
 +
 +HB_INTERNAL bool
 +hb_serialize_cff_fdselect (hb_serialize_context_t *c,
 +                          const hb_vector_t<hb_codepoint_t> &glyphs,
 +                          const CFF::FDSelect &src,
 +                          unsigned int fd_count,
 +                          unsigned int fdselect_format,
 +                          unsigned int size,
 +                          const hb_vector_t<hb_codepoint_t> &first_glyphs,
 +                          const CFF::FDMap &fdmap);
 +
 +#endif /* HB_SUBSET_CFF_COMMON_PRIVATE_HH */
index 4dbf3ff,0000000..577182e
mode 100644,000000..100644
--- /dev/null
@@@ -1,712 -1,0 +1,712 @@@
- #include "hb-open-type-private.hh"
 +/*
 + * Copyright © 2018 Adobe Systems Incorporated.
 + *
 + *  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
 + */
 +
- #include "hb-subset-cff-common-private.hh"
++#include "hb-open-type.hh"
 +#include "hb-ot-cff1-table.hh"
 +#include "hb-set.h"
 +#include "hb-subset-cff1.hh"
 +#include "hb-subset-plan.hh"
++#include "hb-subset-cff-common.hh"
 +#include "hb-cff1-interp-cs.hh"
 +
 +using namespace CFF;
 +
 +struct CFF1SubTableOffsets {
 +  inline CFF1SubTableOffsets (void)
 +  {
 +    memset (this, 0, sizeof(*this));
 +    localSubrsInfos.init ();
 +  }
 +
 +  inline ~CFF1SubTableOffsets (void)
 +  {
 +    localSubrsInfos.fini ();
 +  }
 +
 +  unsigned int  nameIndexOffset;
 +  TableInfo     topDictInfo;
 +  unsigned int  stringIndexOffset;
 +  TableInfo     globalSubrsInfo;
 +  unsigned int  encodingOffset;
 +  unsigned int  charsetOffset;
 +  TableInfo     FDSelectInfo;
 +  TableInfo     FDArrayInfo;
 +  TableInfo     charStringsInfo;
 +  TableInfo     privateDictInfo;
 +  hb_vector_t<TableInfo>  localSubrsInfos;
 +};
 +
 +struct CFF1TopDict_OpSerializer : OpSerializer
 +{
 +  inline bool serialize (hb_serialize_context_t *c,
 +                         const OpStr &opstr,
 +                         const CFF1SubTableOffsets &offsets) const
 +  {
 +    TRACE_SERIALIZE (this);
 +
 +    switch (opstr.op)
 +    {
 +      case OpCode_charset:
 +        return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.charsetOffset));
 +
 +      case OpCode_Encoding:
 +        return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.encodingOffset));
 +
 +      case OpCode_CharStrings:
 +        return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.charStringsInfo.offset));
 +
 +      case OpCode_FDArray:
 +        return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.FDArrayInfo.offset));
 +
 +      case OpCode_FDSelect:
 +        return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.FDSelectInfo.offset));
 +
 +      case OpCode_Private:
 +        {
 +          if (unlikely (!UnsizedByteStr::serialize_int2 (c, offsets.privateDictInfo.size)))
 +            return_trace (false);
 +          if (unlikely (!UnsizedByteStr::serialize_int4 (c, offsets.privateDictInfo.offset)))
 +            return_trace (false);
 +          HBUINT8 *p = c->allocate_size<HBUINT8> (1);
 +          if (unlikely (p == nullptr)) return_trace (false);
 +          p->set (OpCode_Private);
 +        }
 +        break;
 +
 +      default:
 +        return_trace (copy_opstr (c, opstr));
 +    }
 +    return_trace (true);
 +  }
 +
 +  inline unsigned int calculate_serialized_size (const OpStr &opstr) const
 +  {
 +    switch (opstr.op)
 +    {
 +      case OpCode_charset:
 +      case OpCode_Encoding:
 +      case OpCode_CharStrings:
 +      case OpCode_FDArray:
 +      case OpCode_FDSelect:
 +        return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (opstr.op);
 +    
 +      case OpCode_Private:
 +        return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_Private);
 +    
 +      default:
 +        return opstr.str.len;
 +    }
 +  }
 +};
 +
 +struct CFF1FontDict_OpSerializer : OpSerializer
 +{
 +  inline bool serialize (hb_serialize_context_t *c,
 +                         const OpStr &opstr,
 +                         const TableInfo &privateDictInfo) const
 +  {
 +    TRACE_SERIALIZE (this);
 +
 +    if (opstr.op == OpCode_Private)
 +    {
 +      /* serialize the private dict size as a 2-byte integer */
 +      if (unlikely (!UnsizedByteStr::serialize_int2 (c, privateDictInfo.size)))
 +        return_trace (false);
 +
 +      /* serialize the private dict offset as a 4-byte integer */
 +      if (unlikely (!UnsizedByteStr::serialize_int4 (c, privateDictInfo.offset)))
 +        return_trace (false);
 +
 +      /* serialize the opcode */
 +      HBUINT8 *p = c->allocate_size<HBUINT8> (1);
 +      if (unlikely (p == nullptr)) return_trace (false);
 +      p->set (OpCode_Private);
 +
 +      return_trace (true);
 +    }
 +    else
 +    {
 +      HBUINT8 *d = c->allocate_size<HBUINT8> (opstr.str.len);
 +      if (unlikely (d == nullptr)) return_trace (false);
 +      memcpy (d, &opstr.str.str[0], opstr.str.len);
 +    }
 +    return_trace (true);
 +  }
 +
 +  inline unsigned int calculate_serialized_size (const OpStr &opstr) const
 +  {
 +    if (opstr.op == OpCode_Private)
 +      return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_Private);
 +    else
 +      return opstr.str.len;
 +  }
 +};
 +
 +struct CFF1PrivateDict_OpSerializer : OpSerializer
 +{
 +  inline CFF1PrivateDict_OpSerializer (bool drop_hints_=false, bool flatten_subrs_=false)
 +    : drop_hints (drop_hints_), flatten_subrs (flatten_subrs_) {}
 +
 +  inline bool serialize (hb_serialize_context_t *c,
 +                         const OpStr &opstr,
 +                         const unsigned int subrsOffset) const
 +  {
 +    TRACE_SERIALIZE (this);
 +
 +    if (drop_hints && DictOpSet::is_hint_op (opstr.op))
 +      return true;
 +    if (opstr.op == OpCode_Subrs)
 +    {
 +      if (flatten_subrs)
 +        return_trace (true);
 +      else
 +        return_trace (FontDict::serialize_offset2_op(c, OpCode_Subrs, subrsOffset));
 +    }
 +    else
 +      return_trace (copy_opstr (c, opstr));
 +  }
 +
 +  inline unsigned int calculate_serialized_size (const OpStr &opstr) const
 +  {
 +    if (drop_hints && DictOpSet::is_hint_op (opstr.op))
 +      return 0;
 +    if (opstr.op == OpCode_Subrs)
 +    {
 +      if (flatten_subrs)
 +        return 0;
 +      else
 +        return OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_Subrs);
 +    }
 +    else
 +      return opstr.str.len;
 +  }
 +
 +  protected:
 +  const bool  drop_hints;
 +  const bool  flatten_subrs;
 +};
 +
 +struct CFF1CSOpSet_Flatten : CFF1CSOpSet<CFF1CSOpSet_Flatten, ByteStrBuff>
 +{
 +  static inline bool process_op (OpCode op, CFF1CSInterpEnv &env, ByteStrBuff& flatStr)
 +  {
 +    if (unlikely (!SUPER::process_op (op, env, flatStr)))
 +      return false;
 +    switch (op)
 +    {
 +      case OpCode_hintmask:
 +      case OpCode_cntrmask:
 +        if (unlikely (!flatStr.encode_op (op)))
 +          return false;
 +        for (int i = -env.hintmask_size; i < 0; i++)
 +          if (unlikely (!flatStr.encode_byte (env.substr[i])))
 +            return false;
 +        break;
 +      default:
 +        if (!SUPER::is_subr_op (op) &&
 +            !SUPER::is_arg_op (op))
 +          return flatStr.encode_op (op);
 +    }
 +    return true;
 +  }
 +
 +  static inline void flush_stack (CFF1CSInterpEnv &env, ByteStrBuff& flatStr)
 +  {
 +    for (unsigned int i = 0; i < env.argStack.size; i++)
 +      flatStr.encode_num (env.argStack.elements[i]);
 +    SUPER::flush_stack (env, flatStr);
 +  }
 +
 +  private:
 +  typedef CFF1CSOpSet<CFF1CSOpSet_Flatten, ByteStrBuff> SUPER;
 +};
 +
 +struct CFF1CSOpSet_SubsetSubrs : CFF1CSOpSet<CFF1CSOpSet_SubsetSubrs, SubrRefMapPair>
 +{
 +  static inline bool process_op (OpCode op, CFF1CSInterpEnv &env, SubrRefMapPair& refMapPair)
 +  {
 +    unsigned int  subr_num;
 +    switch (op) {
 +      case OpCode_callsubr:
 +        if (!unlikely (env.popSubrNum(env.localSubrs, subr_num)))
 +          return false;
 +        env.argStack.unpop ();
 +        refMapPair.local_map->add (subr_num);
 +        break;
 +      case OpCode_callgsubr:
 +        if (!unlikely (env.popSubrNum(env.globalSubrs, subr_num)))
 +          return false;
 +        env.argStack.unpop ();
 +        refMapPair.global_map->add (subr_num);
 +        break;
 +      default:
 +        break;
 +    }
 +    return CFF1CSOpSet<CFF1CSOpSet_SubsetSubrs, SubrRefMapPair>::process_op (op, env, refMapPair);
 +  }
 +};
 +
 +struct cff_subset_plan {
 +  inline cff_subset_plan (void)
 +    : final_size (0),
 +      orig_fdcount (0),
 +      subst_fdcount (1),
 +      subst_fdselect_format (0),
 +      offsets (),
 +      flatten_subrs (true),
 +      drop_hints (false)
 +  {
 +    topdict_sizes.init ();
 +    topdict_sizes.resize (1);
 +    subst_fdselect_first_glyphs.init ();
 +    fdmap.init ();
 +    subset_charstrings.init ();
 +    flat_charstrings.init ();
 +    privateDictInfos.init ();
 +    subrRefMaps.init ();
 +  }
 +
 +  inline ~cff_subset_plan (void)
 +  {
 +    topdict_sizes.fini ();
 +    subst_fdselect_first_glyphs.fini ();
 +    fdmap.fini ();
 +    subset_charstrings.fini ();
 +    flat_charstrings.fini ();
 +    privateDictInfos.fini ();
 +    subrRefMaps.fini ();
 +  }
 +
 +  inline bool create (const OT::cff1::accelerator_subset_t &acc,
 +                      hb_subset_plan_t *plan)
 +  {
 +    final_size = 0;
 +    orig_fdcount = acc.fdCount;
 +    drop_hints = plan->drop_hints;
 +
 +    /* CFF header */
 +    final_size += OT::cff1::static_size;
 +    
 +    /* Name INDEX */
 +    offsets.nameIndexOffset = final_size;
 +    final_size += acc.nameIndex->get_size ();
 +    
 +    /* top dict INDEX */
 +    {
 +      offsets.topDictInfo.offset = final_size;
 +      CFF1TopDict_OpSerializer topSzr;
 +      unsigned int topDictSize = TopDict::calculate_serialized_size (acc.topDicts[0], topSzr);
 +      offsets.topDictInfo.offSize = calcOffSize(topDictSize);
 +      final_size += CFF1IndexOf<TopDict>::calculate_serialized_size<CFF1TopDictValues> (offsets.topDictInfo.offSize, acc.topDicts, topdict_sizes, topSzr);
 +    }
 +
 +    /* String INDEX */
 +    offsets.stringIndexOffset = final_size;
 +    final_size += acc.stringIndex->get_size ();
 +    
 +    if (flatten_subrs)
 +    {
 +      /* Flatten global & local subrs */
 +      SubrFlattener<const OT::cff1::accelerator_subset_t, CFF1CSInterpEnv, CFF1CSOpSet_Flatten> flattener(acc, plan->glyphs);
 +      if (!flattener.flatten (flat_charstrings))
 +        return false;
 +      
 +      /* no global/local subroutines */
 +      offsets.globalSubrsInfo.size = HBUINT16::static_size; /* count 0 only */
 +    }
 +    else
 +    {
 +      /* Subset global & local subrs */
 +      SubrSubsetter<const OT::cff1::accelerator_subset_t, CFF1CSInterpEnv, CFF1CSOpSet_SubsetSubrs> subsetter(acc, plan->glyphs);
 +      if (!subsetter.collect_refs (subrRefMaps))
 +        return false;
 +      
 +      offsets.globalSubrsInfo.size = acc.globalSubrs->calculate_serialized_size (offsets.globalSubrsInfo.offSize, subrRefMaps.global_map, 1);
 +      if (!offsets.localSubrsInfos.resize (orig_fdcount))
 +        return false;
 +      for (unsigned int i = 0; i < orig_fdcount; i++)
 +        offsets.localSubrsInfos[i].size = acc.privateDicts[i].localSubrs->calculate_serialized_size (offsets.localSubrsInfos[i].offSize, subrRefMaps.local_maps[i], 1);
 +    }
 +    /* global subrs */
 +    offsets.globalSubrsInfo.offset = final_size;
 +    final_size += offsets.globalSubrsInfo.size;
 +
 +    /* Encoding */
 +    offsets.encodingOffset = final_size;
 +    if (acc.encoding != &Null(Encoding))
 +      final_size += acc.encoding->get_size ();
 +
 +    /* Charset */
 +    offsets.charsetOffset = final_size;
 +    if (acc.charset != &Null(Charset))
 +      final_size += acc.charset->get_size (acc.num_glyphs);
 +
 +    /* FDSelect */
 +    if (acc.fdSelect != &Null(CFF1FDSelect))
 +    {
 +      offsets.FDSelectInfo.offset = final_size;
 +      if (unlikely (!hb_plan_subset_cff_fdselect (plan->glyphs,
 +                                  orig_fdcount,
 +                                  *acc.fdSelect,
 +                                  subst_fdcount,
 +                                  offsets.FDSelectInfo.size,
 +                                  subst_fdselect_format,
 +                                  subst_fdselect_first_glyphs,
 +                                  fdmap)))
 +        return false;
 +      
 +      if (!is_fds_subsetted ())
 +        offsets.FDSelectInfo.size = acc.fdSelect->calculate_serialized_size (acc.num_glyphs);
 +      final_size += offsets.FDSelectInfo.size;
 +    }
 +
 +    /* FDArray (FDIndex) */
 +    if (acc.fdArray != &Null(CFF1FDArray)) {
 +      offsets.FDArrayInfo.offset = final_size;
 +      CFF1FontDict_OpSerializer fontSzr;
 +      final_size += CFF1FDArray::calculate_serialized_size(offsets.FDArrayInfo.offSize/*OUT*/, acc.fontDicts, subst_fdcount, fdmap, fontSzr);
 +    }
 +
 +    /* CharStrings */
 +    {
 +      offsets.charStringsInfo.offset = final_size;
 +      unsigned int dataSize = 0;
 +      for (unsigned int i = 0; i < plan->glyphs.len; i++)
 +      {
 +        if (flatten_subrs)
 +        {
 +          ByteStrBuff &flatstr = flat_charstrings[i];
 +          ByteStr str (&flatstr[0], flatstr.len);
 +          subset_charstrings.push (str);
 +          dataSize += flatstr.len;
 +        }
 +        else
 +        {
 +          const ByteStr str = (*acc.charStrings)[plan->glyphs[i]];
 +          subset_charstrings.push (str);
 +          dataSize += str.len;
 +        }
 +      }
 +      offsets.charStringsInfo.offSize = calcOffSize (dataSize + 1);
 +      final_size += CFF1CharStrings::calculate_serialized_size (offsets.charStringsInfo.offSize, plan->glyphs.len, dataSize);
 +    }
 +
 +    /* private dicts & local subrs */
 +    offsets.privateDictInfo.offset = final_size;
 +    for (unsigned int i = 0; i < orig_fdcount; i++)
 +    {
 +      if (!fdmap.excludes (i))
 +      {
 +        unsigned int  priv_size;
 +        CFF1PrivateDict_OpSerializer privSzr (plan->drop_hints, flatten_subrs);
 +        priv_size = PrivateDict::calculate_serialized_size (acc.privateDicts[i], privSzr);
 +        TableInfo  privInfo = { final_size, priv_size, 0 };
 +        privateDictInfos.push (privInfo);
 +        final_size += privInfo.size;
 +        if (!flatten_subrs)
 +          final_size += offsets.localSubrsInfos[i].size;
 +      }
 +    }
 +
 +    if (!acc.is_CID ())
 +      offsets.privateDictInfo = privateDictInfos[0];
 +
 +    return ((subset_charstrings.len == plan->glyphs.len) &&
 +            (privateDictInfos.len == subst_fdcount));
 +  }
 +
 +  inline unsigned int get_final_size (void) const  { return final_size; }
 +
 +  unsigned int        final_size;
 +  hb_vector_t<unsigned int> topdict_sizes;
 +  CFF1SubTableOffsets  offsets;
 +
 +  unsigned int    orig_fdcount;
 +  unsigned int    subst_fdcount;
 +  inline bool     is_fds_subsetted (void) const { return subst_fdcount < orig_fdcount; }
 +  unsigned int    subst_fdselect_format;
 +  hb_vector_t<hb_codepoint_t>   subst_fdselect_first_glyphs;
 +
 +  /* font dict index remap table from fullset FDArray to subset FDArray.
 +   * set to HB_SET_VALUE_INVALID if excluded from subset */
 +  FDMap   fdmap;
 +
 +  hb_vector_t<ByteStr>    subset_charstrings;
 +  ByteStrBuffArray        flat_charstrings;
 +  hb_vector_t<TableInfo>  privateDictInfos;
 +
 +  SubrRefMaps             subrRefMaps;
 +
 +  bool            flatten_subrs;
 +  bool            drop_hints;
 +};
 +
 +static inline bool _write_cff1 (const cff_subset_plan &plan,
 +                                const OT::cff1::accelerator_subset_t  &acc,
 +                                const hb_vector_t<hb_codepoint_t>& glyphs,
 +                                unsigned int dest_sz,
 +                                void *dest)
 +{
 +  hb_serialize_context_t c (dest, dest_sz);
 +
 +  char RETURN_OP[1] = { OpCode_return };
 +  const ByteStr NULL_SUBR (RETURN_OP, 1);
 +
 +  OT::cff1 *cff = c.start_serialize<OT::cff1> ();
 +  if (unlikely (!c.extend_min (*cff)))
 +    return false;
 +
 +  /* header */
 +  cff->version.major.set (0x01);
 +  cff->version.minor.set (0x00);
 +  cff->nameIndex.set (cff->min_size);
 +  cff->offSize.set (4); /* unused? */
 +
 +  /* name INDEX */
 +  {
 +    assert (cff->nameIndex == c.head - c.start);
 +    CFF1NameIndex *dest = c.start_embed<CFF1NameIndex> ();
 +    if (unlikely (dest == nullptr)) return false;
 +    if (unlikely (!dest->serialize (&c, *acc.nameIndex)))
 +    {
 +      DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF name INDEX");
 +      return false;
 +    }
 +  }
 +
 +  /* top dict INDEX */
 +  {
 +    assert (plan.offsets.topDictInfo.offset == c.head - c.start);
 +    CFF1IndexOf<TopDict> *dest = c.start_embed< CFF1IndexOf<TopDict> > ();
 +    if (dest == nullptr) return false;
 +    CFF1TopDict_OpSerializer topSzr;
 +    if (unlikely (!dest->serialize (&c, plan.offsets.topDictInfo.offSize, acc.topDicts, plan.topdict_sizes, topSzr, plan.offsets)))
 +    {
 +      DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF top dict");
 +      return false;
 +    }
 +  }
 +
 +  /* String INDEX */
 +  {
 +    assert (plan.offsets.stringIndexOffset == c.head - c.start);
 +    CFF1StringIndex *dest = c.start_embed<CFF1StringIndex> ();
 +    if (unlikely (dest == nullptr)) return false;
 +    if (unlikely (!dest->serialize (&c, *acc.stringIndex)))
 +    {
 +      DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF string INDEX");
 +      return false;
 +    }
 +  }
 +
 +  /* global subrs */
 +  {
 +    assert (plan.offsets.globalSubrsInfo.offset != 0);
 +    assert (plan.offsets.globalSubrsInfo.offset == c.head - c.start);
 +    CFF1Subrs *dest = c.start_embed<CFF1Subrs> ();
 +    if (unlikely (dest == nullptr)) return false;
 +    if (unlikely (!dest->serialize (&c, *acc.globalSubrs, plan.offsets.globalSubrsInfo.offSize, plan.subrRefMaps.global_map, NULL_SUBR)))
 +    {
 +      DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF global subrs");
 +      return false;
 +    }
 +  }
 +
 +  /* Encoding */
 +  if (acc.encoding != &Null(Encoding)){
 +    assert (plan.offsets.encodingOffset == c.head - c.start);
 +    Encoding *dest = c.start_embed<Encoding> ();
 +    if (unlikely (dest == nullptr)) return false;
 +    if (unlikely (!dest->serialize (&c, *acc.encoding, acc.num_glyphs)))  // XXX: TODO
 +    {
 +      DEBUG_MSG (SUBSET, nullptr, "failed to serialize Encoding");
 +      return false;
 +    }
 +  }
 +
 +  /* Charset */
 +  if (acc.charset != &Null(Charset))
 +  {
 +    assert (plan.offsets.charsetOffset == c.head - c.start);
 +    Charset *dest = c.start_embed<Charset> ();
 +    if (unlikely (dest == nullptr)) return false;
 +    if (unlikely (!dest->serialize (&c, *acc.charset, acc.num_glyphs)))  // XXX: TODO
 +    {
 +      DEBUG_MSG (SUBSET, nullptr, "failed to serialize Charset");
 +      return false;
 +    }
 +  }
 +
 +  /* FDSelect */
 +  if (acc.fdSelect != &Null(CFF1FDSelect))
 +  {
 +    assert (plan.offsets.FDSelectInfo.offset == c.head - c.start);
 +    
 +    if (plan.is_fds_subsetted ())
 +    {
 +      if (unlikely (!hb_serialize_cff_fdselect (&c, glyphs, *acc.fdSelect, acc.fdCount,
 +                                                plan.subst_fdselect_format, plan.offsets.FDSelectInfo.size,
 +                                                plan.subst_fdselect_first_glyphs,
 +                                                plan.fdmap)))
 +      {
 +        DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF subset FDSelect");
 +        return false;
 +      }
 +    }
 +    else
 +    {
 +      CFF1FDSelect *dest = c.start_embed<CFF1FDSelect> ();
 +      if (unlikely (!dest->serialize (&c, *acc.fdSelect, acc.num_glyphs)))
 +      {
 +        DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF FDSelect");
 +        return false;
 +      }
 +    }
 +  }
 +
 +  /* FDArray (FD Index) */
 +  if (acc.fdArray != &Null(CFF1FDArray))
 +  {
 +    assert (plan.offsets.FDArrayInfo.offset == c.head - c.start);
 +    CFF1FDArray  *fda = c.start_embed<CFF1FDArray> ();
 +    if (unlikely (fda == nullptr)) return false;
 +    CFF1FontDict_OpSerializer  fontSzr;
 +    if (unlikely (!fda->serialize (&c, plan.offsets.FDArrayInfo.offSize,
 +                                   acc.fontDicts, plan.subst_fdcount, plan.fdmap,
 +                                   fontSzr, plan.privateDictInfos)))
 +    {
 +      DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF FDArray");
 +      return false;
 +    }
 +  }
 +
 +  /* CharStrings */
 +  {
 +    assert (plan.offsets.charStringsInfo.offset == c.head - c.start);
 +    CFF1CharStrings  *cs = c.start_embed<CFF1CharStrings> ();
 +    if (unlikely (cs == nullptr)) return false;
 +    if (unlikely (!cs->serialize (&c, plan.offsets.charStringsInfo.offSize, plan.subset_charstrings)))
 +    {
 +      DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF CharStrings");
 +      return false;
 +    }
 +  }
 +
 +  /* private dicts & local subrs */
 +  assert (plan.offsets.privateDictInfo.offset == c.head - c.start);
 +  for (unsigned int i = 0; i < acc.privateDicts.len; i++)
 +  {
 +    if (!plan.fdmap.excludes (i))
 +    {
 +      PrivateDict  *pd = c.start_embed<PrivateDict> ();
 +      if (unlikely (pd == nullptr)) return false;
 +      unsigned int priv_size = plan.flatten_subrs? 0: plan.privateDictInfos[plan.fdmap[i]].size;
 +      bool result;
 +      CFF1PrivateDict_OpSerializer privSzr (plan.drop_hints, plan.flatten_subrs);
 +      /* N.B. local subrs immediately follows its corresponding private dict. i.e., subr offset == private dict size */
 +      result = pd->serialize (&c, acc.privateDicts[i], privSzr, priv_size);
 +      if (unlikely (!result))
 +      {
 +        DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF Private Dict[%d]", i);
 +        return false;
 +      }
 +      if (!plan.flatten_subrs && (acc.privateDicts[i].subrsOffset != 0))
 +      {
 +        CFF1Subrs *subrs = c.start_embed<CFF1Subrs> ();
 +        if (unlikely (subrs == nullptr) || acc.privateDicts[i].localSubrs == &Null(CFF1Subrs))
 +        {
 +          DEBUG_MSG (SUBSET, nullptr, "CFF subset: local subrs unexpectedly null [%d]", i);
 +          return false;
 +        }
 +        if (unlikely (!subrs->serialize (&c, *acc.privateDicts[i].localSubrs, plan.offsets.localSubrsInfos[i].offSize, plan.subrRefMaps.local_maps[i], NULL_SUBR)))
 +        {
 +          DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF local subrs [%d]", i);
 +          return false;
 +        }
 +      }
 +    }
 +  }
 +
 +  assert (c.head == c.end);
 +  c.end_serialize ();
 +
 +  return true;
 +}
 +
 +static bool
 +_hb_subset_cff1 (const OT::cff1::accelerator_subset_t  &acc,
 +                const char                      *data,
 +                hb_subset_plan_t                *plan,
 +                hb_blob_t                       **prime /* OUT */)
 +{
 +  cff_subset_plan cff_plan;
 +
 +  if (unlikely (!cff_plan.create (acc, plan)))
 +  {
 +    DEBUG_MSG(SUBSET, nullptr, "Failed to generate a cff subsetting plan.");
 +    return false;
 +  }
 +
 +  unsigned int  cff_prime_size = cff_plan.get_final_size ();
 +  char *cff_prime_data = (char *) calloc (1, cff_prime_size);
 +
 +  if (unlikely (!_write_cff1 (cff_plan, acc, plan->glyphs,
 +                              cff_prime_size, cff_prime_data))) {
 +    DEBUG_MSG(SUBSET, nullptr, "Failed to write a subset cff.");
 +    free (cff_prime_data);
 +    return false;
 +  }
 +
 +  *prime = hb_blob_create (cff_prime_data,
 +                           cff_prime_size,
 +                           HB_MEMORY_MODE_READONLY,
 +                           cff_prime_data,
 +                           free);
 +  return true;
 +}
 +
 +/**
 + * hb_subset_cff1:
 + * Subsets the CFF table according to a provided plan.
 + *
 + * Return value: subsetted cff table.
 + **/
 +bool
 +hb_subset_cff1 (hb_subset_plan_t *plan,
 +                hb_blob_t       **prime /* OUT */)
 +{
 +  hb_blob_t *cff_blob = hb_sanitize_context_t().reference_table<CFF::cff1> (plan->source);
 +  const char *data = hb_blob_get_data(cff_blob, nullptr);
 +
 +  OT::cff1::accelerator_subset_t acc;
 +  acc.init(plan->source);
 +  bool result = likely (acc.is_valid ()) &&
 +                        _hb_subset_cff1 (acc, data, plan, prime);
 +  hb_blob_destroy (cff_blob);
 +  acc.fini ();
 +
 +  return result;
 +}
index 729bc12,0000000..eb2bc53
mode 100644,000000..100644
--- /dev/null
@@@ -1,38 -1,0 +1,38 @@@
- #include "hb-private.hh"
 +/*
 + * Copyright © 2018 Adobe Systems Incorporated.
 + *
 + *  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_SUBSET_CFF1_HH
 +#define HB_SUBSET_CFF1_HH
 +
++#include "hb.hh"
 +
 +#include "hb-subset-plan.hh"
 +
 +HB_INTERNAL bool
 +hb_subset_cff1 (hb_subset_plan_t *plan,
 +               hb_blob_t        **cff_prime /* OUT */);
 +
 +#endif /* HB_SUBSET_CFF1_HH */
index 8d45b00,0000000..fee09d8
mode 100644,000000..100644
--- /dev/null
@@@ -1,577 -1,0 +1,577 @@@
- #include "hb-open-type-private.hh"
 +/*
 + * Copyright © 2018 Adobe Systems Incorporated.
 + *
 + *  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
 + */
 +
- #include "hb-subset-cff-common-private.hh"
++#include "hb-open-type.hh"
 +#include "hb-ot-cff2-table.hh"
 +#include "hb-set.h"
 +#include "hb-subset-cff2.hh"
 +#include "hb-subset-plan.hh"
++#include "hb-subset-cff-common.hh"
 +#include "hb-cff2-interp-cs.hh"
 +
 +using namespace CFF;
 +
 +struct CFF2SubTableOffsets {
 +  inline CFF2SubTableOffsets (void)
 +  {
 +    memset (this, 0, sizeof(*this));
 +    localSubrsInfos.init ();
 +  }
 +
 +  inline ~CFF2SubTableOffsets (void)
 +  {
 +    localSubrsInfos.fini ();
 +  }
 +
 +  unsigned int  topDictSize;
 +  unsigned int  varStoreOffset;
 +  TableInfo     FDSelectInfo;
 +  TableInfo     FDArrayInfo;
 +  TableInfo     charStringsInfo;
 +  unsigned int  privateDictsOffset;
 +  TableInfo     globalSubrsInfo;
 +  hb_vector_t<TableInfo>  localSubrsInfos;
 +};
 +
 +struct CFF2TopDict_OpSerializer : OpSerializer
 +{
 +  inline bool serialize (hb_serialize_context_t *c,
 +                         const OpStr &opstr,
 +                         const CFF2SubTableOffsets &offsets) const
 +  {
 +    TRACE_SERIALIZE (this);
 +
 +    switch (opstr.op)
 +    {
 +      case OpCode_vstore:
 +        return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.varStoreOffset));
 +
 +      case OpCode_CharStrings:
 +        return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.charStringsInfo.offset));
 +
 +      case OpCode_FDArray:
 +        return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.FDArrayInfo.offset));
 +
 +      case OpCode_FDSelect:
 +        return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.FDSelectInfo.offset));
 +
 +      default:
 +        return_trace (copy_opstr (c, opstr));
 +    }
 +    return_trace (true);
 +  }
 +
 +  inline unsigned int calculate_serialized_size (const OpStr &opstr) const
 +  {
 +    switch (opstr.op)
 +    {
 +      case OpCode_vstore:
 +      case OpCode_CharStrings:
 +      case OpCode_FDArray:
 +      case OpCode_FDSelect:
 +        return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (opstr.op);
 +    
 +      default:
 +        return opstr.str.len;
 +    }
 +  }
 +};
 +
 +struct CFF2FontDict_OpSerializer : OpSerializer
 +{
 +  inline bool serialize (hb_serialize_context_t *c,
 +                         const OpStr &opstr,
 +                         const TableInfo& privDictInfo) const
 +  {
 +    TRACE_SERIALIZE (this);
 +
 +    if (opstr.op == OpCode_Private)
 +    {
 +      /* serialize the private dict size as a 2-byte integer */
 +      if (unlikely (!UnsizedByteStr::serialize_int2 (c, privDictInfo.size)))
 +        return_trace (false);
 +
 +      /* serialize the private dict offset as a 4-byte integer */
 +      if (unlikely (!UnsizedByteStr::serialize_int4 (c, privDictInfo.offset)))
 +        return_trace (false);
 +
 +      /* serialize the opcode */
 +      HBUINT8 *p = c->allocate_size<HBUINT8> (1);
 +      if (unlikely (p == nullptr)) return_trace (false);
 +      p->set (OpCode_Private);
 +
 +      return_trace (true);
 +    }
 +    else
 +    {
 +      HBUINT8 *d = c->allocate_size<HBUINT8> (opstr.str.len);
 +      if (unlikely (d == nullptr)) return_trace (false);
 +      memcpy (d, &opstr.str.str[0], opstr.str.len);
 +    }
 +    return_trace (true);
 +  }
 +
 +  inline unsigned int calculate_serialized_size (const OpStr &opstr) const
 +  {
 +    if (opstr.op == OpCode_Private)
 +      return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_Private);
 +    else
 +      return opstr.str.len;
 +  }
 +};
 +
 +struct CFF2PrivateDict_OpSerializer : OpSerializer
 +{
 +  inline bool serialize (hb_serialize_context_t *c,
 +                         const OpStr &opstr,
 +                         const unsigned int subrsOffset) const
 +  {
 +    TRACE_SERIALIZE (this);
 +
 +    if (opstr.op == OpCode_Subrs)
 +      return_trace (FontDict::serialize_offset2_op(c, OpCode_Subrs, subrsOffset));
 +    else
 +      return_trace (copy_opstr (c, opstr));
 +  }
 +
 +  inline unsigned int calculate_serialized_size (const OpStr &opstr) const
 +  {
 +    if (opstr.op == OpCode_Subrs)
 +      return OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_Subrs);
 +    else
 +      return opstr.str.len;
 +  }
 +};
 +
 +struct CFF2PrivateDict_OpSerializer_DropHints : CFF2PrivateDict_OpSerializer
 +{
 +  inline bool serialize (hb_serialize_context_t *c,
 +                         const OpStr &opstr,
 +                         const unsigned int subrsOffset) const
 +  {
 +    if (DictOpSet::is_hint_op (opstr.op))
 +      return true;
 +    else
 +      return CFF2PrivateDict_OpSerializer::serialize (c, opstr, subrsOffset);
 +  }
 +
 +  inline unsigned int calculate_serialized_size (const OpStr &opstr) const
 +  {
 +    if (DictOpSet::is_hint_op (opstr.op))
 +      return 0;
 +    else
 +      return CFF2PrivateDict_OpSerializer::calculate_serialized_size (opstr);
 +  }
 +};
 +
 +struct CFF2CSOpSet_SubsetSubrs : CFF2CSOpSet<CFF2CSOpSet_SubsetSubrs, SubrRefMapPair>
 +{
 +  static inline bool process_op (OpCode op, CFF2CSInterpEnv &env, SubrRefMapPair& refMapPair)
 +  {
 +    unsigned int  subr_num;
 +    switch (op) {
 +      case OpCode_callsubr:
 +        if (!unlikely (env.popSubrNum(env.localSubrs, subr_num)))
 +          return false;
 +        env.argStack.unpop ();
 +        refMapPair.local_map->add (subr_num);
 +        break;
 +      case OpCode_callgsubr:
 +        if (!unlikely (env.popSubrNum(env.globalSubrs, subr_num)))
 +          return false;
 +        env.argStack.unpop ();
 +        refMapPair.global_map->add (subr_num);
 +        break;
 +      default:
 +        break;
 +    }
 +    return CFF2CSOpSet<CFF2CSOpSet_SubsetSubrs, SubrRefMapPair>::process_op (op, env, refMapPair);
 +  }
 +};
 +
 +struct cff2_subset_plan {
 +  inline cff2_subset_plan (void)
 +    : final_size (0),
 +      orig_fdcount (0),
 +      subst_fdcount(1),
 +      subst_fdselect_format (0)
 +  {
 +    subst_fdselect_first_glyphs.init ();
 +    fdmap.init ();
 +    subset_charstrings.init ();
 +    privateDictInfos.init ();
 +    subrRefMaps.init ();
 +  }
 +
 +  inline ~cff2_subset_plan (void)
 +  {
 +    subst_fdselect_first_glyphs.fini ();
 +    fdmap.fini ();
 +    subset_charstrings.fini ();
 +    privateDictInfos.fini ();
 +    subrRefMaps.fini ();
 +  }
 +
 +  inline bool create (const OT::cff2::accelerator_subset_t &acc,
 +              hb_subset_plan_t *plan)
 +  {
 +    final_size = 0;
 +    orig_fdcount = acc.fdArray->count;
 +
 +    drop_hints = plan->drop_hints;
 +
 +    /* CFF2 header */
 +    final_size += OT::cff2::static_size;
 +    
 +    /* top dict */
 +    {
 +      CFF2TopDict_OpSerializer topSzr;
 +      offsets.topDictSize = TopDict::calculate_serialized_size (acc.topDict, topSzr);
 +      final_size += offsets.topDictSize;
 +    }
 +
 +    /* Subset global & local subrs */
 +    {
 +      SubrSubsetter<const OT::cff2::accelerator_subset_t, CFF2CSInterpEnv, CFF2CSOpSet_SubsetSubrs> subsetter(acc, plan->glyphs);
 +      if (!subsetter.collect_refs (subrRefMaps))
 +        return false;
 +      
 +      offsets.globalSubrsInfo.size = acc.globalSubrs->calculate_serialized_size (offsets.globalSubrsInfo.offSize, subrRefMaps.global_map);
 +      if (!offsets.localSubrsInfos.resize (orig_fdcount))
 +        return false;
 +      for (unsigned int i = 0; i < orig_fdcount; i++)
 +        offsets.localSubrsInfos[i].size = acc.privateDicts[i].localSubrs->calculate_serialized_size (offsets.localSubrsInfos[i].offSize, subrRefMaps.local_maps[i]);
 +    }
 +    
 +    /* global subrs */
 +    offsets.globalSubrsInfo.offset = final_size;
 +    final_size += offsets.globalSubrsInfo.size;
 +
 +    /* variation store */
 +    if (acc.varStore != &Null(CFF2VariationStore))
 +    {
 +      offsets.varStoreOffset = final_size;
 +      final_size += acc.varStore->get_size ();
 +    }
 +
 +    /* FDSelect */
 +    if (acc.fdSelect != &Null(CFF2FDSelect))
 +    {
 +      offsets.FDSelectInfo.offset = final_size;
 +      if (unlikely (!hb_plan_subset_cff_fdselect (plan->glyphs,
 +                                  orig_fdcount,
 +                                  *(const FDSelect *)acc.fdSelect,
 +                                  subst_fdcount,
 +                                  offsets.FDSelectInfo.size,
 +                                  subst_fdselect_format,
 +                                  subst_fdselect_first_glyphs,
 +                                  fdmap)))
 +        return false;
 +      
 +      if (!is_fds_subsetted ())
 +        offsets.FDSelectInfo.size = acc.fdSelect->calculate_serialized_size (acc.num_glyphs);
 +      final_size += offsets.FDSelectInfo.size;
 +    }
 +
 +    /* FDArray (FDIndex) */
 +    {
 +      offsets.FDArrayInfo.offset = final_size;
 +      CFF2FontDict_OpSerializer fontSzr;
 +      final_size += CFF2FDArray::calculate_serialized_size(offsets.FDArrayInfo.offSize/*OUT*/, acc.fontDicts, subst_fdcount, fdmap, fontSzr);
 +    }
 +
 +    /* CharStrings */
 +    {
 +      offsets.charStringsInfo.offset = final_size;
 +      unsigned int dataSize = 0;
 +      for (unsigned int i = 0; i < plan->glyphs.len; i++)
 +      {
 +        const ByteStr str = (*acc.charStrings)[plan->glyphs[i]];
 +        subset_charstrings.push (str);
 +        dataSize += str.len;
 +      }
 +      offsets.charStringsInfo.offSize = calcOffSize (dataSize + 1);
 +      final_size += CFF2CharStrings::calculate_serialized_size (offsets.charStringsInfo.offSize, plan->glyphs.len, dataSize);
 +    }
 +
 +    /* private dicts & local subrs */
 +    offsets.privateDictsOffset = final_size;
 +    for (unsigned int i = 0; i < orig_fdcount; i++)
 +    {
 +      if (!fdmap.excludes (i))
 +      {
 +        unsigned int priv_size;
 +        if (plan->drop_hints)
 +        {
 +          CFF2PrivateDict_OpSerializer_DropHints privSzr_drop;
 +          priv_size = PrivateDict::calculate_serialized_size (acc.privateDicts[i], privSzr_drop);
 +        }
 +        else
 +        {
 +          CFF2PrivateDict_OpSerializer privSzr;
 +          priv_size = PrivateDict::calculate_serialized_size (acc.privateDicts[i], privSzr);
 +        }
 +        TableInfo  privInfo = { final_size, priv_size, 0 };
 +        privateDictInfos.push (privInfo);
 +        final_size += privInfo.size + offsets.localSubrsInfos[i].size;
 +      }
 +    }
 +
 +    return true;
 +  }
 +
 +  inline unsigned int get_final_size (void) const  { return final_size; }
 +
 +  unsigned int        final_size;
 +  CFF2SubTableOffsets offsets;
 +
 +  unsigned int    orig_fdcount;
 +  unsigned int    subst_fdcount;
 +  inline bool     is_fds_subsetted (void) const { return subst_fdcount < orig_fdcount; }
 +  unsigned int    subst_fdselect_format;
 +  hb_vector_t<hb_codepoint_t>   subst_fdselect_first_glyphs;
 +
 +  FDMap   fdmap;
 +
 +  hb_vector_t<ByteStr> subset_charstrings;
 +  hb_vector_t<TableInfo> privateDictInfos;
 +
 +  SubrRefMaps             subrRefMaps;
 +
 +  bool            drop_hints;
 +};
 +
 +static inline bool _write_cff2 (const cff2_subset_plan &plan,
 +                                const OT::cff2::accelerator_subset_t  &acc,
 +                                const hb_vector_t<hb_codepoint_t>& glyphs,
 +                                unsigned int dest_sz,
 +                                void *dest)
 +{
 +  hb_serialize_context_t c (dest, dest_sz);
 +
 +  OT::cff2 *cff2 = c.start_serialize<OT::cff2> ();
 +  if (unlikely (!c.extend_min (*cff2)))
 +    return false;
 +
 +  /* header */
 +  cff2->version.major.set (0x02);
 +  cff2->version.minor.set (0x00);
 +  cff2->topDict.set (OT::cff2::static_size);
 +
 +  /* top dict */
 +  {
 +    assert (cff2->topDict == c.head - c.start);
 +    cff2->topDictSize.set (plan.offsets.topDictSize);
 +    TopDict &dict = cff2 + cff2->topDict;
 +    CFF2TopDict_OpSerializer topSzr;
 +    if (unlikely (!dict.serialize (&c, acc.topDict, topSzr, plan.offsets)))
 +    {
 +      DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 top dict");
 +      return false;
 +    }
 +  }
 +
 +  /* global subrs */
 +  {
 +    assert (cff2->topDict + plan.offsets.topDictSize == c.head - c.start);
 +    CFF2Subrs *dest = c.start_embed<CFF2Subrs> ();
 +    if (unlikely (dest == nullptr)) return false;
 +    if (unlikely (!dest->serialize (&c, *acc.globalSubrs, plan.offsets.globalSubrsInfo.offSize, plan.subrRefMaps.global_map)))
 +    {
 +      DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 global subrs");
 +      return false;
 +    }
 +  }
 +  
 +  /* variation store */
 +  if (acc.varStore != &Null(CFF2VariationStore))
 +  {
 +    assert (plan.offsets.varStoreOffset == c.head - c.start);
 +    CFF2VariationStore *dest = c.start_embed<CFF2VariationStore> ();
 +    if (unlikely (!dest->serialize (&c, acc.varStore)))
 +    {
 +      DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 Variation Store");
 +      return false;
 +    }
 +  }
 +
 +  /* FDSelect */
 +  if (acc.fdSelect != &Null(CFF2FDSelect))
 +  {
 +    assert (plan.offsets.FDSelectInfo.offset == c.head - c.start);
 +    
 +    if (plan.is_fds_subsetted ())
 +    {
 +      if (unlikely (!hb_serialize_cff_fdselect (&c, glyphs, *(const FDSelect *)acc.fdSelect, acc.fdArray->count,
 +                                                plan.subst_fdselect_format, plan.offsets.FDSelectInfo.size,
 +                                                plan.subst_fdselect_first_glyphs,
 +                                                plan.fdmap)))
 +      {
 +        DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 subset FDSelect");
 +        return false;
 +      }
 +    }
 +    else
 +    {
 +      CFF2FDSelect *dest = c.start_embed<CFF2FDSelect> ();
 +      if (unlikely (!dest->serialize (&c, *acc.fdSelect, acc.num_glyphs)))
 +      {
 +        DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 FDSelect");
 +        return false;
 +      }
 +    }
 +  }
 +
 +  /* FDArray (FD Index) */
 +  {
 +    assert (plan.offsets.FDArrayInfo.offset == c.head - c.start);
 +    CFF2FDArray  *fda = c.start_embed<CFF2FDArray> ();
 +    if (unlikely (fda == nullptr)) return false;
 +    CFF2FontDict_OpSerializer  fontSzr;
 +    if (unlikely (!fda->serialize (&c, plan.offsets.FDArrayInfo.offSize,
 +                                   acc.fontDicts, plan.subst_fdcount, plan.fdmap,
 +                                   fontSzr, plan.privateDictInfos)))
 +    {
 +      DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 FDArray");
 +      return false;
 +    }
 +  }
 +
 +  /* CharStrings */
 +  {
 +    assert (plan.offsets.charStringsInfo.offset == c.head - c.start);
 +    CFF2CharStrings  *cs = c.start_embed<CFF2CharStrings> ();
 +    if (unlikely (cs == nullptr)) return false;
 +    if (unlikely (!cs->serialize (&c, plan.offsets.charStringsInfo.offSize, plan.subset_charstrings)))
 +    {
 +      DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 CharStrings");
 +      return false;
 +    }
 +  }
 +
 +  /* private dicts & local subrs */
 +  assert (plan.offsets.privateDictsOffset == c.head - c.start);
 +  for (unsigned int i = 0; i < acc.privateDicts.len; i++)
 +  {
 +    if (!plan.fdmap.excludes (i))
 +    {
 +      PrivateDict  *pd = c.start_embed<PrivateDict> ();
 +      if (unlikely (pd == nullptr)) return false;
 +      unsigned int priv_size = plan.privateDictInfos[plan.fdmap[i]].size;
 +      bool result;
 +      if (plan.drop_hints)
 +      {
 +        CFF2PrivateDict_OpSerializer_DropHints privSzr_drop;
 +        result = pd->serialize (&c, acc.privateDicts[i], privSzr_drop, priv_size);
 +      }
 +      else
 +      {
 +        CFF2PrivateDict_OpSerializer privSzr;
 +        result = pd->serialize (&c, acc.privateDicts[i], privSzr, priv_size);
 +      }
 +      if (unlikely (!result))
 +      {
 +        DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 Private Dict[%d]", i);
 +        return false;
 +      }
 +      if (acc.privateDicts[i].subrsOffset != 0)
 +      {
 +        CFF2Subrs *subrs = c.start_embed<CFF2Subrs> ();
 +        if (unlikely (subrs == nullptr) || acc.privateDicts[i].localSubrs == &Null(CFF2Subrs))
 +        {
 +          DEBUG_MSG (SUBSET, nullptr, "CFF2 subset: local subrs unexpectedly null [%d]", i);
 +          return false;
 +        }
 +        if (unlikely (!subrs->serialize (&c, *acc.privateDicts[i].localSubrs, plan.offsets.localSubrsInfos[i].offSize, plan.subrRefMaps.local_maps[i])))
 +        {
 +          DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 local subrs [%d]", i);
 +          return false;
 +        }
 +      }
 +    }
 +  }
 +
 +  assert (c.head == c.end);
 +  c.end_serialize ();
 +
 +  return true;
 +}
 +
 +static bool
 +_hb_subset_cff2 (const OT::cff2::accelerator_subset_t  &acc,
 +                const char                      *data,
 +                hb_subset_plan_t                *plan,
 +                hb_blob_t                       **prime /* OUT */)
 +{
 +  cff2_subset_plan cff2_plan;
 +
 +  if (unlikely (!cff2_plan.create (acc, plan)))
 +  {
 +    DEBUG_MSG(SUBSET, nullptr, "Failed to generate a cff2 subsetting plan.");
 +    return false;
 +  }
 +
 +  unsigned int  cff2_prime_size = cff2_plan.get_final_size ();
 +  char *cff2_prime_data = (char *) calloc (1, cff2_prime_size);
 +
 +  if (unlikely (!_write_cff2 (cff2_plan, acc, plan->glyphs,
 +                              cff2_prime_size, cff2_prime_data))) {
 +    DEBUG_MSG(SUBSET, nullptr, "Failed to write a subset cff2.");
 +    free (cff2_prime_data);
 +    return false;
 +  }
 +
 +  *prime = hb_blob_create (cff2_prime_data,
 +                                cff2_prime_size,
 +                                HB_MEMORY_MODE_READONLY,
 +                                cff2_prime_data,
 +                                free);
 +  return true;
 +}
 +
 +/**
 + * hb_subset_cff2:
 + * Subsets the CFF2 table according to a provided plan.
 + *
 + * Return value: subsetted cff2 table.
 + **/
 +bool
 +hb_subset_cff2 (hb_subset_plan_t *plan,
 +                hb_blob_t       **prime /* OUT */)
 +{
 +  hb_blob_t *cff2_blob = hb_sanitize_context_t().reference_table<CFF::cff2> (plan->source);
 +  const char *data = hb_blob_get_data(cff2_blob, nullptr);
 +
 +  OT::cff2::accelerator_subset_t acc;
 +  acc.init(plan->source);
 +  bool result = likely (acc.is_valid ()) &&
 +                _hb_subset_cff2 (acc, data, plan, prime);
 +
 +  hb_blob_destroy (cff2_blob);
 +  acc.fini ();
 +
 +  return result;
 +}
index f927070,0000000..0701240
mode 100644,000000..100644
--- /dev/null
@@@ -1,38 -1,0 +1,38 @@@
- #include "hb-private.hh"
 +/*
 + * Copyright © 2018 Adobe Systems Incorporated.
 + *
 + *  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_SUBSET_CFF2_HH
 +#define HB_SUBSET_CFF2_HH
 +
++#include "hb.hh"
 +
 +#include "hb-subset-plan.hh"
 +
 +HB_INTERNAL bool
 +hb_subset_cff2 (hb_subset_plan_t *plan,
 +               hb_blob_t       **cff2_prime /* OUT */);
 +
 +#endif /* HB_SUBSET_CFF2_HH */
Simple merge