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

@ -35,9 +35,10 @@ using namespace OT;
struct CFF1CSInterpEnv : CSInterpEnv<Number, CFF1Subrs> 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; processed_width = false;
has_width = false; has_width = false;
for (unsigned int i = 0; i < kTransientArraySize; i++) for (unsigned int i = 0; i < kTransientArraySize; i++)

@ -33,12 +33,60 @@ namespace CFF {
using namespace OT; 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> 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_); SUPER::init (str, *acc.globalSubrs, *acc.privateDicts[fd].localSubrs);
ivs = 0; set_region_count (acc.region_count);
set_vsindex (acc.privateDicts[fd].vsindex);
} }
inline bool fetch_op (OpCode &op) inline bool fetch_op (OpCode &op)
@ -58,14 +106,17 @@ struct CFF2CSInterpEnv : CSInterpEnv<BlendArg, CFF2Subrs>
{ {
unsigned int index; unsigned int index;
if (likely (argStack.check_pop_uint (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 unsigned int get_region_count (void) const { return region_count; }
inline void set_ivs (unsigned int ivs_) { ivs = ivs_; } 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: protected:
unsigned int ivs; unsigned int region_count;
unsigned int vsindex;
typedef CSInterpEnv<BlendArg, CFF2Subrs> SUPER; 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) static inline bool process_op (OpCode op, CFF2CSInterpEnv &env, PARAM& param)
{ {
switch (op) { 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: case OpCode_blendcs:
return OPSET::process_blend (env, param); return OPSET::process_blend (env, param);
case OpCode_vsindexcs: case OpCode_vsindexcs:
if (unlikely (env.argStack.peek ().blended ()))
return false;
OPSET::process_vsindex (env, param); OPSET::process_vsindex (env, param);
break; break;
default: default:
if (unlikely (!SUPER::process_op (op, env, param))) return SUPER::process_op (op, env, param);
return false;
break;
} }
return true; return true;
} }
static inline bool process_blend (CFF2CSInterpEnv &env, PARAM& param) static inline bool process_blend (CFF2CSInterpEnv &env, PARAM& param)
{ {
// XXX: TODO leave default values? unsigned int n, k;
OPSET::flush_args (env, param);
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; return true;
} }

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

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

@ -42,30 +42,34 @@ struct ByteStrBuff : hb_vector_t<char, 1>
return (push ((const char)b) != &Crap(char)); 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 ((-107 <= v) && (v <= 107))
if ((-1131 <= v) && (v <= 1131)) return encode_byte (v + 139);
else if (v > 0)
{ {
if ((-107 <= v) && (v <= 107)) v -= 108;
return encode_byte (v + 139); return encode_byte ((v >> 8) + OpCode_TwoBytePosInt0) && encode_byte (v & 0xFF);
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); else
return encode_byte (OpCode_shortint) && {
encode_byte ((v >> 8) & 0xFF) && v = -v - 108;
encode_byte (v & 0xFF); 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 else
{ {
@ -258,10 +262,10 @@ struct FlattenParam
bool drop_hints; bool drop_hints;
}; };
template <typename ACCESSOR, typename ENV, typename OPSET> template <typename ACC, typename ENV, typename OPSET>
struct SubrFlattener struct SubrFlattener
{ {
inline SubrFlattener (const ACCESSOR &acc_, inline SubrFlattener (const ACC &acc_,
const hb_vector_t<hb_codepoint_t> &glyphs_, const hb_vector_t<hb_codepoint_t> &glyphs_,
bool drop_hints_) bool drop_hints_)
: acc (acc_), : acc (acc_),
@ -281,7 +285,7 @@ struct SubrFlattener
const ByteStr str = (*acc.charStrings)[glyph]; const ByteStr str = (*acc.charStrings)[glyph];
unsigned int fd = acc.fdSelect->get_fd (glyph); unsigned int fd = acc.fdSelect->get_fd (glyph);
CSInterpreter<ENV, OPSET, FlattenParam> interp; 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 }; FlattenParam param = { flat_charstrings[i], drop_hints };
if (unlikely (!interp.interpret (param))) if (unlikely (!interp.interpret (param)))
return false; return false;
@ -289,7 +293,7 @@ struct SubrFlattener
return true; return true;
} }
const ACCESSOR &acc; const ACC &acc;
const hb_vector_t<hb_codepoint_t> &glyphs; const hb_vector_t<hb_codepoint_t> &glyphs;
bool drop_hints; bool drop_hints;
}; };
@ -342,10 +346,10 @@ struct SubrRefMapPair
hb_set_t *local_map; hb_set_t *local_map;
}; };
template <typename ACCESSOR, typename ENV, typename OPSET> template <typename ACC, typename ENV, typename OPSET>
struct SubrSubsetter 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_), : acc (acc_),
glyphs (glyphs_) glyphs (glyphs_)
{} {}
@ -361,14 +365,14 @@ struct SubrSubsetter
unsigned int fd = acc.fdSelect->get_fd (glyph); unsigned int fd = acc.fdSelect->get_fd (glyph);
SubrRefMapPair pair = { refmaps.global_map, refmaps.local_maps[fd] }; SubrRefMapPair pair = { refmaps.global_map, refmaps.local_maps[fd] };
CSInterpreter<ENV, OPSET, SubrRefMapPair> interp; 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))) if (unlikely (!interp.interpret (pair)))
return false; return false;
} }
return true; return true;
} }
const ACCESSOR &acc; const ACC &acc;
const hb_vector_t<hb_codepoint_t> &glyphs; 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) static inline void flush_hintmask (OpCode op, CFF1CSInterpEnv &env, FlattenParam& param)
{ {
SUPER::flush_hintmask (op, env, param); SUPER::flush_hintmask (op, env, param);
for (unsigned int i = 0; i < env.hintmask_size; i++) if (!param.drop_hints)
param.flatStr.encode_byte (env.substr[i]); for (unsigned int i = 0; i < env.hintmask_size; i++)
param.flatStr.encode_byte (env.substr[i]);
} }
private: private:

@ -77,12 +77,6 @@ struct CFF2TopDict_OpSerializer : CFFTopDict_OpSerializer
struct CFF2CSOpSet_Flatten : CFF2CSOpSet<CFF2CSOpSet_Flatten, FlattenParam> 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) static inline void flush_args_and_op (OpCode op, CFF2CSInterpEnv &env, FlattenParam& param)
{ {
switch (op) 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) 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++) for (unsigned int i = env.argStack.count - n; i < env.argStack.count;)
param.flatStr.encode_num (env.argStack.elements[i]); {
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); 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) 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: private:

Loading…
Cancel
Save