Drop hints from CFF2 charstrings

Templatized ArgStack so it may store the default value along with blend deltas as BlendArg while parsing blend operator arguments in CFF2 charstring
Added get_region_count() method to VarRegionList & VariationStore
pull/1113/head
Michiharu Ariza 6 years ago
parent fcf177885b
commit f2d299b0b7
  1. 67
      src/hb-cff-interp-common.hh
  2. 5
      src/hb-cff1-interp-cs.hh
  3. 91
      src/hb-cff2-interp-cs.hh
  4. 22
      src/hb-ot-cff2-table.hh
  5. 6
      src/hb-ot-layout-common.hh
  6. 60
      src/hb-subset-cff-common.hh
  7. 5
      src/hb-subset-cff1.cc
  8. 54
      src/hb-subset-cff2.cc

@ -210,7 +210,10 @@ inline unsigned int OpCode_Size (OpCode op) { return Is_OpCode_ESC (op)? 2: 1; }
struct Number
{
inline Number (void) { set_int (0); }
inline void init (void)
{ set_int (0); }
inline void fini (void)
{}
inline void set_int (int v) { format = NumInt; u.int_val = v; };
inline int to_int (void) const { return is_int ()? u.int_val: (int)to_real (); }
@ -336,7 +339,15 @@ struct ByteStr
struct SubByteStr
{
inline SubByteStr (void)
: str (), offset (0) {}
{ init (); }
inline void init (void)
{
str = ByteStr (0);
offset = 0;
}
inline void fini (void) {}
inline SubByteStr (const ByteStr &str_, unsigned int offset_ = 0)
: str (str_), offset (offset_) {}
@ -379,15 +390,35 @@ inline float parse_bcd (SubByteStr& substr, float& v)
template <typename ELEM, int LIMIT>
struct Stack
{
inline void init (void) { count = 0; }
inline void fini (void) { }
inline void init (void)
{
count = 0;
elements.init ();
elements.resize (kSizeLimit);
for (unsigned int i = 0; i < elements.len; i++)
elements[i].init ();
}
inline void fini (void)
{
for (unsigned int i = 0; i < elements.len; i++)
elements[i].fini ();
}
inline void push (const ELEM &v)
{
if (likely (count < kSizeLimit))
if (likely (count < elements.len))
elements[count++] = v;
}
inline ELEM &push (void)
{
if (likely (count < elements.len))
return elements[count++];
else
return Crap(ELEM);
}
inline const ELEM& pop (void)
{
if (likely (count > 0))
@ -396,9 +427,17 @@ struct Stack
return Null(ELEM);
}
inline const ELEM& peek (void)
{
if (likely (count > 0))
return elements[count];
else
return Null(ELEM);
}
inline void unpop (void)
{
if (likely (count < kSizeLimit))
if (likely (count < elements.len))
count++;
}
@ -413,7 +452,7 @@ struct Stack
static const unsigned int kSizeLimit = LIMIT;
unsigned int count;
ELEM elements[kSizeLimit];
hb_vector_t<ELEM, kSizeLimit> elements;
};
/* argument stack */
@ -422,16 +461,20 @@ struct ArgStack : Stack<ARG, 513>
{
inline void push_int (int v)
{
ARG n;
ARG &n = S::push ();
n.set_int (v);
S::push (n);
}
inline void push_fixed (int32_t v)
{
ARG &n = S::push ();
n.set_fixed (v);
}
inline void push_real (float v)
{
ARG n;
ARG &n = S::push ();
n.set_real (v);
S::push (n);
}
inline bool check_pop_num (ARG& n)
@ -495,7 +538,7 @@ struct ArgStack : Stack<ARG, 513>
{
if (unlikely (!substr.avail (4) || !S::check_overflow (1)))
return false;
push_real ((int32_t)*(const HBUINT32*)&substr[0] / 65536.0);
push_fixed ((int32_t)*(const HBUINT32*)&substr[0]);
substr.inc (4);
return true;
}

@ -35,9 +35,10 @@ using namespace OT;
struct CFF1CSInterpEnv : CSInterpEnv<Number, CFF1Subrs>
{
inline void init (const ByteStr &str, const CFF1Subrs &globalSubrs, const CFF1Subrs &localSubrs)
template <typename ACC>
inline void init (const ByteStr &str, ACC &acc, unsigned int fd)
{
SUPER::init (str, globalSubrs, localSubrs);
SUPER::init (str, *acc.globalSubrs, *acc.privateDicts[fd].localSubrs);
processed_width = false;
has_width = false;
for (unsigned int i = 0; i < kTransientArraySize; i++)

@ -33,12 +33,60 @@ namespace CFF {
using namespace OT;
struct BlendArg : Number
{
inline void init (void)
{
Number::init ();
deltas.init ();
}
inline void fini (void)
{
Number::fini ();
for (unsigned int i = 0; i < deltas.len; i++)
deltas[i].fini ();
deltas.fini ();
}
inline void set_int (int v) { reset_blends (); Number::set_int (v); }
inline void set_fixed (int32_t v) { reset_blends (); Number::set_fixed (v); }
inline void set_real (float v) { reset_blends (); Number::set_real (v); }
inline void set_blends (unsigned int numValues_, unsigned int valueIndex_,
unsigned int numBlends, const BlendArg *blends_)
{
numValues = numValues_;
valueIndex = valueIndex_;
deltas.resize (numBlends);
for (unsigned int i = 0; i < numBlends; i++)
deltas[i] = blends_[i];
}
inline bool blended (void) const { return deltas.len > 0; }
inline void reset_blends (void)
{
numValues = valueIndex = 0;
deltas.resize (0);
}
unsigned int numValues;
unsigned int valueIndex;
hb_vector_t<Number> deltas;
};
typedef InterpEnv<BlendArg> BlendInterpEnv;
typedef DictVal<BlendArg> BlendDictVal;
struct CFF2CSInterpEnv : CSInterpEnv<BlendArg, CFF2Subrs>
{
inline void init (const ByteStr &str, const CFF2Subrs &globalSubrs_, const CFF2Subrs &localSubrs_)
template <typename ACC>
inline void init (const ByteStr &str, ACC &acc, unsigned int fd)
{
SUPER::init (str, globalSubrs_, localSubrs_);
ivs = 0;
SUPER::init (str, *acc.globalSubrs, *acc.privateDicts[fd].localSubrs);
set_region_count (acc.region_count);
set_vsindex (acc.privateDicts[fd].vsindex);
}
inline bool fetch_op (OpCode &op)
@ -58,14 +106,17 @@ struct CFF2CSInterpEnv : CSInterpEnv<BlendArg, CFF2Subrs>
{
unsigned int index;
if (likely (argStack.check_pop_uint (index)))
set_ivs (argStack.check_pop_uint (index));
set_vsindex (argStack.check_pop_uint (index));
}
inline unsigned int get_ivs (void) const { return ivs; }
inline void set_ivs (unsigned int ivs_) { ivs = ivs_; }
inline unsigned int get_region_count (void) const { return region_count; }
inline void set_region_count (unsigned int region_count_) { region_count = region_count_; }
inline unsigned int get_vsindex (void) const { return vsindex; }
inline void set_vsindex (unsigned int vsindex_) { vsindex = vsindex_; }
protected:
unsigned int ivs;
unsigned int region_count;
unsigned int vsindex;
typedef CSInterpEnv<BlendArg, CFF2Subrs> SUPER;
};
@ -76,26 +127,42 @@ struct CFF2CSOpSet : CSOpSet<BlendArg, OPSET, CFF2CSInterpEnv, PARAM>
static inline bool process_op (OpCode op, CFF2CSInterpEnv &env, PARAM& param)
{
switch (op) {
case OpCode_callsubr:
case OpCode_callgsubr:
/* a subroutine number shoudln't be a blended value */
return (!env.argStack.peek ().blended () &&
SUPER::process_op (op, env, param));
case OpCode_blendcs:
return OPSET::process_blend (env, param);
case OpCode_vsindexcs:
if (unlikely (env.argStack.peek ().blended ()))
return false;
OPSET::process_vsindex (env, param);
break;
default:
if (unlikely (!SUPER::process_op (op, env, param)))
return false;
break;
return SUPER::process_op (op, env, param);
}
return true;
}
static inline bool process_blend (CFF2CSInterpEnv &env, PARAM& param)
{
// XXX: TODO leave default values?
OPSET::flush_args (env, param);
unsigned int n, k;
k = env.get_region_count ();
if (unlikely (!env.argStack.check_pop_uint (n) ||
(k+1) * n > env.argStack.get_count ()))
return false;
/* copy the blend values into blend array of the default values */
unsigned int start = env.argStack.get_count () - ((k+1) * n);
for (unsigned int i = 0; i < n; i++)
env.argStack.elements[start + i].set_blends (n, i, k, &env.argStack.elements[start + n + (i * k)]);
/* pop off blend values leaving default values now adorned with blend values */
env.argStack.count -= k * n;
return true;
}

@ -48,13 +48,6 @@ typedef Subrs<HBUINT32> CFF2Subrs;
typedef FDSelect3_4<HBUINT32, HBUINT16> FDSelect4;
typedef FDSelect3_4_Range<HBUINT32, HBUINT16> FDSelect4_Range;
struct BlendArg : Number
{
// XXX: TODO
};
typedef InterpEnv<BlendArg> BlendInterpEnv;
struct CFF2FDSelect
{
inline bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const
@ -271,6 +264,7 @@ struct CFF2PrivateDictValues_Base : DictValues<VAL>
DictValues<VAL>::init ();
subrsOffset = 0;
localSubrs = &Null(CFF2Subrs);
vsindex = 0;
}
inline void fini (void)
@ -291,9 +285,9 @@ struct CFF2PrivateDictValues_Base : DictValues<VAL>
unsigned int subrsOffset;
const CFF2Subrs *localSubrs;
unsigned int vsindex;
};
typedef DictVal<BlendArg> BlendDictVal;
typedef CFF2PrivateDictValues_Base<OpStr> CFF2PrivateDictValues_Subset;
typedef CFF2PrivateDictValues_Base<NumDictVal> CFF2PrivateDictValues;
@ -332,9 +326,11 @@ struct CFF2PrivateDictOpSet : DictOpSet<>
env.clear_args ();
break;
case OpCode_vsindexdict:
if (unlikely (!env.argStack.check_pop_uint (dictval.vsindex)))
return false;
break;
case OpCode_blenddict:
// XXX: TODO
return true;
break;
default:
if (unlikely (!DictOpSet::process_op (op, env)))
@ -458,6 +454,11 @@ struct cff2
if (num_glyphs != sc.get_num_glyphs ())
{ fini (); return; }
if (varStore != &Null(CFF2VariationStore))
region_count = varStore->varStore.get_region_count ();
else
region_count = 0;
fdCount = fdArray->count;
privateDicts.resize (fdCount);
@ -523,6 +524,7 @@ struct cff2
hb_vector_t<PRIVDICTVAL> privateDicts;
unsigned int num_glyphs;
unsigned int region_count;
};
typedef accelerator_templ_t<CFF2PrivateDictOpSet, CFF2PrivateDictValues> accelerator_t;

@ -1346,6 +1346,9 @@ struct VarRegionList
axesZ.sanitize (c, (unsigned int) axisCount * (unsigned int) regionCount));
}
inline unsigned int get_region_count (void) const
{ return regionCount; }
protected:
HBUINT16 axisCount;
HBUINT16 regionCount;
@ -1444,6 +1447,9 @@ struct VariationStore
dataSets.sanitize (c, this));
}
inline unsigned int get_region_count (void) const
{ return (this+regions).get_region_count (); }
protected:
HBUINT16 format;
LOffsetTo<VarRegionList> regions;

@ -42,30 +42,34 @@ struct ByteStrBuff : hb_vector_t<char, 1>
return (push ((const char)b) != &Crap(char));
}
inline bool encode_num (const Number& n)
inline bool encode_int (int v)
{
if (n.in_int_range ())
if ((-1131 <= v) && (v <= 1131))
{
int v = n.to_int ();
if ((-1131 <= v) && (v <= 1131))
if ((-107 <= v) && (v <= 107))
return encode_byte (v + 139);
else if (v > 0)
{
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);
}
v -= 108;
return encode_byte ((v >> 8) + OpCode_TwoBytePosInt0) && encode_byte (v & 0xFF);
}
assert ((v & ~0xFFFF) == 0);
return encode_byte (OpCode_shortint) &&
encode_byte ((v >> 8) & 0xFF) &&
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);
}
inline bool encode_num (const Number& n)
{
if (n.in_int_range ())
{
return encode_int (n.to_int ());
}
else
{
@ -258,10 +262,10 @@ struct FlattenParam
bool drop_hints;
};
template <typename ACCESSOR, typename ENV, typename OPSET>
template <typename ACC, typename ENV, typename OPSET>
struct SubrFlattener
{
inline SubrFlattener (const ACCESSOR &acc_,
inline SubrFlattener (const ACC &acc_,
const hb_vector_t<hb_codepoint_t> &glyphs_,
bool drop_hints_)
: acc (acc_),
@ -281,7 +285,7 @@ struct SubrFlattener
const ByteStr str = (*acc.charStrings)[glyph];
unsigned int fd = acc.fdSelect->get_fd (glyph);
CSInterpreter<ENV, OPSET, FlattenParam> interp;
interp.env.init (str, *acc.globalSubrs, *acc.privateDicts[fd].localSubrs);
interp.env.init (str, acc, fd);
FlattenParam param = { flat_charstrings[i], drop_hints };
if (unlikely (!interp.interpret (param)))
return false;
@ -289,7 +293,7 @@ struct SubrFlattener
return true;
}
const ACCESSOR &acc;
const ACC &acc;
const hb_vector_t<hb_codepoint_t> &glyphs;
bool drop_hints;
};
@ -342,10 +346,10 @@ struct SubrRefMapPair
hb_set_t *local_map;
};
template <typename ACCESSOR, typename ENV, typename OPSET>
template <typename ACC, typename ENV, typename OPSET>
struct SubrSubsetter
{
inline SubrSubsetter (const ACCESSOR &acc_, const hb_vector_t<hb_codepoint_t> &glyphs_)
inline SubrSubsetter (const ACC &acc_, const hb_vector_t<hb_codepoint_t> &glyphs_)
: acc (acc_),
glyphs (glyphs_)
{}
@ -361,14 +365,14 @@ struct SubrSubsetter
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);
interp.env.init (str, acc, fd);
if (unlikely (!interp.interpret (pair)))
return false;
}
return true;
}
const ACCESSOR &acc;
const ACC &acc;
const hb_vector_t<hb_codepoint_t> &glyphs;
};

@ -148,8 +148,9 @@ struct CFF1CSOpSet_Flatten : CFF1CSOpSet<CFF1CSOpSet_Flatten, FlattenParam>
static inline void flush_hintmask (OpCode op, CFF1CSInterpEnv &env, FlattenParam& param)
{
SUPER::flush_hintmask (op, env, param);
for (unsigned int i = 0; i < env.hintmask_size; i++)
param.flatStr.encode_byte (env.substr[i]);
if (!param.drop_hints)
for (unsigned int i = 0; i < env.hintmask_size; i++)
param.flatStr.encode_byte (env.substr[i]);
}
private:

@ -77,12 +77,6 @@ struct CFF2TopDict_OpSerializer : CFFTopDict_OpSerializer
struct CFF2CSOpSet_Flatten : CFF2CSOpSet<CFF2CSOpSet_Flatten, FlattenParam>
{
static inline bool process_blend (CFF2CSInterpEnv &env, FlattenParam& param)
{
flush_args (env, param);
return true;
}
static inline void flush_args_and_op (OpCode op, CFF2CSInterpEnv &env, FlattenParam& param)
{
switch (op)
@ -117,14 +111,56 @@ struct CFF2CSOpSet_Flatten : CFF2CSOpSet<CFF2CSOpSet_Flatten, FlattenParam>
static inline void flush_n_args (unsigned int n, CFF2CSInterpEnv &env, FlattenParam& param)
{
for (unsigned int i = env.argStack.count - n; i < env.argStack.count; i++)
param.flatStr.encode_num (env.argStack.elements[i]);
for (unsigned int i = env.argStack.count - n; i < env.argStack.count;)
{
const BlendArg &arg = env.argStack.elements[i];
if (arg.blended ())
{
assert ((arg.numValues > 0) && (n >= arg.numValues));
flatten_blends (arg, i, env, param);
i += arg.numValues;
}
else
{
param.flatStr.encode_num (arg);
i++;
}
}
SUPER::flush_n_args (n, env, param);
}
static inline void flatten_blends (const BlendArg &arg, unsigned int i, CFF2CSInterpEnv &env, FlattenParam& param)
{
/* flatten the default values */
for (unsigned int j = 0; j < arg.numValues; j++)
{
const BlendArg &arg1 = env.argStack.elements[i + j];
assert (arg1.blended () && (arg.numValues == arg1.numValues) && (arg1.valueIndex == j) &&
(arg1.deltas.len == env.get_region_count ()));
param.flatStr.encode_num (arg1);
}
/* flatten deltas for each value */
for (unsigned int j = 0; j < arg.numValues; j++)
{
const BlendArg &arg1 = env.argStack.elements[i + j];
for (unsigned int k = 0; k < arg1.deltas.len; k++)
param.flatStr.encode_num (arg1.deltas[k]);
}
/* flatten the number of values followed by blend operator */
param.flatStr.encode_int (arg.numValues);
param.flatStr.encode_op (OpCode_blendcs);
}
static inline void flush_op (OpCode op, CFF2CSInterpEnv &env, FlattenParam& param)
{
param.flatStr.encode_op (op);
switch (op)
{
case OpCode_return:
case OpCode_endchar:
return;
default:
param.flatStr.encode_op (op);
}
}
private:

Loading…
Cancel
Save