drop hints from CFF1 charstrings

renamed confusing Stack.size to Stack.count
This commit is contained in:
Michiharu Ariza 2018-08-31 13:28:16 -07:00
parent 8c5e03b541
commit 968168bf0e
9 changed files with 193 additions and 200 deletions

View File

@ -379,40 +379,40 @@ inline float parse_bcd (SubByteStr& substr, float& v)
template <typename ELEM, int LIMIT>
struct Stack
{
inline void init (void) { size = 0; }
inline void init (void) { count = 0; }
inline void fini (void) { }
inline void push (const ELEM &v)
{
if (likely (size < kSizeLimit))
elements[size++] = v;
if (likely (count < kSizeLimit))
elements[count++] = v;
}
inline const ELEM& pop (void)
{
if (likely (size > 0))
return elements[--size];
if (likely (count > 0))
return elements[--count];
else
return Null(ELEM);
}
inline void unpop (void)
{
if (likely (size < kSizeLimit))
size++;
if (likely (count < kSizeLimit))
count++;
}
inline void clear (void) { size = 0; }
inline void clear (void) { count = 0; }
inline bool check_overflow (unsigned int count=1) const { return (count <= kSizeLimit) && (count + size <= kSizeLimit); }
inline bool check_underflow (unsigned int count=1) const { return (count <= size); }
inline bool check_overflow (unsigned int n=1) const { return (n <= kSizeLimit) && (n + count <= kSizeLimit); }
inline bool check_underflow (unsigned int n=1) const { return (n <= count); }
inline unsigned int get_size (void) const { return size; }
inline bool is_empty (void) const { return size == 0; }
inline unsigned int get_count (void) const { return count; }
inline bool is_empty (void) const { return count == 0; }
static const unsigned int kSizeLimit = LIMIT;
unsigned int size;
unsigned int count;
ELEM elements[kSizeLimit];
};
@ -469,11 +469,11 @@ struct ArgStack : Stack<Number, 513>
inline bool check_pop_delta (hb_vector_t<Number>& vec, bool even=false)
{
if (even && unlikely ((this->size & 1) != 0))
if (even && unlikely ((this->count & 1) != 0))
return false;
float val = 0.0f;
for (unsigned int i = 0; i < size; i++) {
for (unsigned int i = 0; i < count; i++) {
val += elements[i].to_real ();
Number *n = vec.push ();
n->set_real (val);
@ -564,6 +564,17 @@ struct InterpEnv
return true;
}
inline void pop_n_args (unsigned int n)
{
assert (n <= argStack.count);
argStack.count -= n;
}
inline void clear_args (void)
{
pop_n_args (argStack.count);
}
SubByteStr substr;
ArgStack argStack;
};
@ -604,7 +615,7 @@ struct OpSet
env.argStack.push_int ((int)op - 139);
} else {
/* invalid unknown operator */
env.argStack.clear ();
env.clear_args ();
return false;
}
break;

View File

@ -64,7 +64,6 @@ struct CSInterpEnv : InterpEnv
{
InterpEnv::init (str);
stack_cleared = false;
seen_moveto = true;
seen_hintmask = false;
hstem_count = 0;
@ -121,25 +120,17 @@ struct CSInterpEnv : InterpEnv
{
if (!seen_hintmask)
{
vstem_count += argStack.size / 2;
vstem_count += argStack.get_count() / 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;
@ -162,7 +153,8 @@ struct CSOpSet : OpSet
return env.returnFromSubr ();
case OpCode_endchar:
env.set_endchar (true);
return true;
OPSET::flush_op (op, env, param);
break;
case OpCode_fixedcs:
return env.argStack.push_fixed_from_substr (env.substr);
@ -175,19 +167,15 @@ struct CSOpSet : OpSet
case OpCode_hstem:
case OpCode_hstemhm:
OPSET::process_hstem (env, param);
OPSET::process_hstem (op, env, param);
break;
case OpCode_vstem:
case OpCode_vstemhm:
OPSET::process_vstem (env, param);
OPSET::process_vstem (op, 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);
OPSET::process_hintmask (op, env, param);
break;
case OpCode_vmoveto:
@ -196,7 +184,7 @@ struct CSOpSet : OpSet
case OpCode_vlineto:
case OpCode_rmoveto:
case OpCode_hmoveto:
OPSET::process_moveto (env, param);
OPSET::process_moveto (op, env, param);
break;
case OpCode_rrcurveto:
case OpCode_rcurveline:
@ -205,11 +193,14 @@ struct CSOpSet : OpSet
case OpCode_hhcurveto:
case OpCode_vhcurveto:
case OpCode_hvcurveto:
OPSET::process_path (op, env, param);
break;
case OpCode_hflex:
case OpCode_flex:
case OpCode_hflex1:
case OpCode_flex1:
OPSET::flush_stack (env, param);
OPSET::process_flex (op, env, param);
break;
default:
@ -218,87 +209,76 @@ struct CSOpSet : OpSet
return true;
}
static inline void process_hstem (ENV &env, PARAM& param)
static inline void process_hstem (OpCode op, ENV &env, PARAM& param)
{
env.hstem_count += env.argStack.size / 2;
OPSET::flush_stack (env, param);
env.hstem_count += env.argStack.count / 2;
OPSET::flush_args_and_op (op, env, param);
}
static inline void process_vstem (ENV &env, PARAM& param)
static inline void process_vstem (OpCode op, ENV &env, PARAM& param)
{
env.vstem_count += env.argStack.size / 2;
OPSET::flush_stack (env, param);
env.vstem_count += env.argStack.count / 2;
OPSET::flush_args_and_op (op, env, param);
}
static inline void process_moveto (ENV &env, PARAM& param)
static inline void process_hintmask (OpCode op, ENV &env, PARAM& param)
{
env.determine_hintmask_size ();
if (likely (env.substr.avail (env.hintmask_size)))
{
OPSET::flush_hintmask (op, env, param);
env.substr.inc (env.hintmask_size);
}
}
static inline void process_flex (OpCode op, ENV &env, PARAM& param)
{
OPSET::flush_args_and_op (op, env, param);
}
static inline void process_moveto (OpCode op, ENV &env, PARAM& param)
{
if (!env.seen_moveto)
{
env.determine_hintmask_size ();
env.seen_moveto = true;
}
OPSET::flush_stack (env, param);
OPSET::flush_args_and_op (op, env, param);
}
static inline void flush_stack (ENV &env, PARAM& param)
static inline void process_path (OpCode op, ENV &env, PARAM& param)
{
env.clear_stack ();
OPSET::flush_args_and_op (op, env, param);
}
/* numeric / logical / arithmetic operators */
static inline bool is_arg_op (OpCode op)
static inline void flush_args_and_op (OpCode op, ENV &env, PARAM& param)
{
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);
}
OPSET::flush_n_args_and_op (op, env.argStack.count, env, param);
}
/* hint operators (excluding hint/counter mask) */
static inline bool is_hint_op (OpCode op)
static inline void flush_n_args_and_op (OpCode op, unsigned int n, ENV &env, PARAM& param)
{
switch (op)
{
case OpCode_hstem:
case OpCode_vstem:
case OpCode_hstemhm:
case OpCode_vstemhm:
case OpCode_hflex:
case OpCode_flex:
case OpCode_hflex1:
case OpCode_flex1:
return true;
default:
return false;
}
OPSET::flush_n_args (n, env, param);
OPSET::flush_op (op, env, param);
}
static inline void flush_args (ENV &env, PARAM& param)
{
OPSET::flush_n_args (env.argStack.count, env, param);
}
static inline void flush_n_args (unsigned int n, ENV &env, PARAM& param)
{
env.pop_n_args (n);
}
static inline void flush_op (OpCode op, ENV &env, PARAM& param)
{
}
static inline void flush_hintmask (OpCode op, ENV &env, PARAM& param)
{
OPSET::flush_args_and_op (op, env, param);
}
static inline bool is_subr_op (OpCode op)

View File

@ -169,12 +169,12 @@ struct TopDictOpSet : DictOpSet
case OpCode_CharStrings:
if (unlikely (!env.argStack.check_pop_uint (dictval.charStringsOffset)))
return false;
env.argStack.clear ();
env.clear_args ();
break;
case OpCode_FDArray:
if (unlikely (!env.argStack.check_pop_uint (dictval.FDArrayOffset)))
return false;
env.argStack.clear ();
env.clear_args ();
break;
default:
return DictOpSet::process_op (op, env);

View File

@ -51,7 +51,7 @@ struct CFF1CSInterpEnv : CSInterpEnv<CFF1Subrs>
{
if (!processed_width)
{
if ((this->argStack.size & 1) != 0)
if ((this->argStack.count & 1) != 0)
{
width = this->argStack.elements[0];
has_width = true;
@ -163,8 +163,8 @@ struct CFF1CSOpSet : CSOpSet<OPSET, CFF1CSInterpEnv, PARAM>
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]);
if (unlikely (i >= env.argStack.count || !env.argStack.check_overflow (1))) return false;
env.argStack.push (env.argStack.elements[env.argStack.count - i - 1]);
}
break;
case OpCode_roll:
@ -172,13 +172,13 @@ struct CFF1CSOpSet : CSOpSet<OPSET, CFF1CSInterpEnv, PARAM>
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 (unlikely (n < 0 || n > env.argStack.count)) return false;
if (likely (n > 0))
{
if (j < 0)
j = n - (-j % n);
j %= n;
unsigned int top = env.argStack.size - 1;
unsigned int top = env.argStack.count - 1;
unsigned int bot = top - n + 1;
env.argStack.reverse_range (top - j + 1, top);
env.argStack.reverse_range (bot, top - j);
@ -194,10 +194,10 @@ struct CFF1CSOpSet : CSOpSet<OPSET, CFF1CSInterpEnv, PARAM>
return true;
}
static inline void flush_stack (CFF1CSInterpEnv &env, PARAM& param)
static inline void flush_args (CFF1CSInterpEnv &env, PARAM& param)
{
env.check_width ();
SUPER::flush_stack (env, param);
SUPER::flush_args (env, param);
}
private:

View File

@ -54,13 +54,11 @@ struct CFF2CSInterpEnv : CSInterpEnv<CFF2Subrs>
return true;
}
inline bool process_vsindex (void)
inline void process_vsindex (void)
{
unsigned int index;
if (unlikely (!argStack.check_pop_uint (index)))
return false;
set_ivs (index);
return true;
if (likely (argStack.check_pop_uint (index)))
set_ivs (argStack.check_pop_uint (index));
}
inline unsigned int get_ivs (void) const { return ivs; }
@ -81,7 +79,8 @@ struct CFF2CSOpSet : CSOpSet<OPSET, CFF2CSInterpEnv, PARAM>
return OPSET::process_blend (env, param);
case OpCode_vsindexcs:
return OPSET::process_vsindex (env, param);
OPSET::process_vsindex (env, param);
break;
default:
typedef CSOpSet<OPSET, CFF2CSInterpEnv, PARAM> SUPER;
@ -95,13 +94,14 @@ struct CFF2CSOpSet : CSOpSet<OPSET, CFF2CSInterpEnv, PARAM>
static inline bool process_blend (CFF2CSInterpEnv &env, PARAM& param)
{
// XXX: TODO leave default values?
OPSET::flush_stack (env, param);
OPSET::flush_args (env, param);
return true;
}
static inline bool process_vsindex (CFF2CSInterpEnv &env, PARAM& param)
static inline void process_vsindex (CFF2CSInterpEnv &env, PARAM& param)
{
return env.process_vsindex ();
env.process_vsindex ();
OPSET::flush_n_args_and_op (OpCode_vsindexcs, 1, env, param);
}
};

View File

@ -437,13 +437,13 @@ struct CFF1TopDictOpSet : TopDictOpSet
case OpCode_FontBBox:
case OpCode_XUID:
case OpCode_BaseFontBlend:
env.argStack.clear ();
env.clear_args ();
break;
case OpCode_CIDCount:
if (unlikely (!env.argStack.check_pop_uint (dictval.cidCount)))
return false;
env.argStack.clear ();
env.clear_args ();
break;
case OpCode_ROS:
@ -451,25 +451,25 @@ struct CFF1TopDictOpSet : TopDictOpSet
!env.argStack.check_pop_uint (dictval.ros[1]) ||
!env.argStack.check_pop_uint (dictval.ros[0])))
return false;
env.argStack.clear ();
env.clear_args ();
break;
case OpCode_Encoding:
if (unlikely (!env.argStack.check_pop_uint (dictval.EncodingOffset)))
return false;
env.argStack.clear ();
env.clear_args ();
break;
case OpCode_charset:
if (unlikely (!env.argStack.check_pop_uint (dictval.CharsetOffset)))
return false;
env.argStack.clear ();
env.clear_args ();
break;
case OpCode_FDSelect:
if (unlikely (!env.argStack.check_pop_uint (dictval.FDSelectOffset)))
return false;
env.argStack.clear ();
env.clear_args ();
break;
case OpCode_Private:
@ -477,7 +477,7 @@ struct CFF1TopDictOpSet : TopDictOpSet
return false;
if (unlikely (!env.argStack.check_pop_uint (dictval.privateDictInfo.size)))
return false;
env.argStack.clear ();
env.clear_args ();
break;
default:
@ -517,14 +517,14 @@ struct CFF1FontDictOpSet : DictOpSet
case OpCode_FontName:
case OpCode_FontMatrix:
case OpCode_PaintType:
env.argStack.clear ();
env.clear_args ();
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 ();
env.clear_args ();
break;
default:
@ -602,12 +602,12 @@ struct CFF1PrivateDictOpSet : DictOpSet
case OpCode_nominalWidthX:
if (unlikely (!env.argStack.check_pop_num (val.single_val)))
return false;
env.argStack.clear ();
env.clear_args ();
break;
case OpCode_Subrs:
if (unlikely (!env.argStack.check_pop_uint (dictval.subrsOffset)))
return false;
env.argStack.clear ();
env.clear_args ();
break;
default:
@ -644,13 +644,13 @@ struct CFF1PrivateDictOpSet_Subset : DictOpSet
case OpCode_initialRandomSeed:
case OpCode_defaultWidthX:
case OpCode_nominalWidthX:
env.argStack.clear ();
env.clear_args ();
break;
case OpCode_Subrs:
if (unlikely (!env.argStack.check_pop_uint (dictval.subrsOffset)))
return false;
env.argStack.clear ();
env.clear_args ();
break;
default:

View File

@ -183,19 +183,19 @@ struct CFF2TopDictOpSet : TopDictOpSet
DictVal val;
val.init ();
dictval.pushVal (op, env.substr);
env.argStack.clear ();
env.clear_args ();
}
break;
case OpCode_vstore:
if (unlikely (!env.argStack.check_pop_uint (dictval.vstoreOffset)))
return false;
env.argStack.clear ();
env.clear_args ();
break;
case OpCode_FDSelect:
if (unlikely (!env.argStack.check_pop_uint (dictval.FDSelectOffset)))
return false;
env.argStack.clear ();
env.clear_args ();
break;
default:
@ -236,7 +236,7 @@ struct CFF2FontDictOpSet : DictOpSet
return false;
if (unlikely (!env.argStack.check_pop_uint (dictval.privateDictInfo.size)))
return false;
env.argStack.clear ();
env.clear_args ();
break;
default:
@ -301,7 +301,7 @@ struct CFF2PrivateDictOpSet : DictOpSet
case OpCode_LanguageGroup:
if (unlikely (!env.argStack.check_pop_num (val.single_val)))
return false;
env.argStack.clear ();
env.clear_args ();
break;
case OpCode_BlueValues:
case OpCode_OtherBlues:
@ -311,12 +311,12 @@ struct CFF2PrivateDictOpSet : DictOpSet
case OpCode_StemSnapV:
if (unlikely (!env.argStack.check_pop_delta (val.multi_val)))
return false;
env.argStack.clear ();
env.clear_args ();
break;
case OpCode_Subrs:
if (unlikely (!env.argStack.check_pop_uint (dictval.subrsOffset)))
return false;
env.argStack.clear ();
env.clear_args ();
break;
case OpCode_vsindexdict:
case OpCode_blenddict:
@ -353,17 +353,17 @@ struct CFF2PrivateDictOpSet_Subset : DictOpSet
case OpCode_StemSnapV:
case OpCode_LanguageGroup:
case OpCode_ExpansionFactor:
env.argStack.clear ();
env.clear_args ();
break;
case OpCode_blenddict:
env.argStack.clear ();
env.clear_args ();
return true;
case OpCode_Subrs:
if (unlikely (!env.argStack.check_pop_uint (dictval.subrsOffset)))
return false;
env.argStack.clear ();
env.clear_args ();
break;
default:

View File

@ -106,43 +106,50 @@ struct CFF1TopDict_OpSerializer : CFFTopDict_OpSerializer
struct CFF1CSOpSet_Flatten : CFF1CSOpSet<CFF1CSOpSet_Flatten, FlattenParam>
{
static inline bool process_op (OpCode op, CFF1CSInterpEnv &env, FlattenParam& param)
static inline void flush_args_and_op (OpCode op, CFF1CSInterpEnv &env, FlattenParam& param)
{
if (param.drop_hints && CSOPSET::is_hint_op (op))
{
env.clear_stack ();
return true;
}
if (unlikely (!SUPER::process_op (op, env, param)))
return false;
switch (op)
{
case OpCode_hstem:
case OpCode_hstemhm:
case OpCode_vstem:
case OpCode_vstemhm:
case OpCode_hintmask:
case OpCode_cntrmask:
case OpCode_hflex:
case OpCode_flex:
case OpCode_hflex1:
case OpCode_flex1:
if (param.drop_hints)
{
env.clear_stack ();
return true;
env.clear_args ();
return;
}
if (unlikely (!param.flatStr.encode_op (op)))
return false;
for (int i = -env.hintmask_size; i < 0; i++)
if (unlikely (!param.flatStr.encode_byte (env.substr[i])))
return false;
break;
/* NO BREAK */
default:
if (!CSOPSET::is_subr_op (op) &&
!CSOPSET::is_arg_op (op))
return param.flatStr.encode_op (op);
SUPER::flush_args_and_op (op, env, param);
break;
}
return true;
}
static inline void flush_stack (CFF1CSInterpEnv &env, FlattenParam& param)
static inline void flush_n_args (unsigned int n, CFF1CSInterpEnv &env, FlattenParam& param)
{
for (unsigned int i = 0; i < env.argStack.size; i++)
for (unsigned int i = env.argStack.count - n; i < env.argStack.count; i++)
param.flatStr.encode_num (env.argStack.elements[i]);
SUPER::flush_stack (env, param);
SUPER::flush_n_args (n, env, param);
}
static inline void flush_op (OpCode op, CFF1CSInterpEnv &env, FlattenParam& param)
{
param.flatStr.encode_op (op);
}
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]);
}
private:

View File

@ -77,59 +77,54 @@ struct CFF2TopDict_OpSerializer : CFFTopDict_OpSerializer
struct CFF2CSOpSet_Flatten : CFF2CSOpSet<CFF2CSOpSet_Flatten, FlattenParam>
{
static inline bool process_op (OpCode op, CFF2CSInterpEnv &env, FlattenParam& param)
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)
{
if (param.drop_hints && CSOPSET::is_hint_op (op))
{
env.clear_stack ();
return true;
}
if (unlikely (!SUPER::process_op (op, env, param)))
return false;
switch (op)
{
case OpCode_hintmask:
case OpCode_cntrmask:
if (param.drop_hints)
{
env.clear_stack ();
return true;
}
if (unlikely (!param.flatStr.encode_op (op)))
return false;
for (int i = -env.hintmask_size; i < 0; i++)
if (unlikely (!param.flatStr.encode_byte (env.substr[i])))
return false;
break;
case OpCode_return:
case OpCode_endchar:
/* dummy opcodes in CFF2. ignore */
break;
case OpCode_hstem:
case OpCode_hstemhm:
case OpCode_vstem:
case OpCode_vstemhm:
case OpCode_hintmask:
case OpCode_cntrmask:
case OpCode_hflex:
case OpCode_flex:
case OpCode_hflex1:
case OpCode_flex1:
if (param.drop_hints)
{
env.clear_args ();
return;
}
/* NO BREAK */
default:
if (!CSOPSET::is_subr_op (op) &&
!CSOPSET::is_arg_op (op))
return param.flatStr.encode_op (op);
SUPER::flush_args_and_op (op, env, param);
break;
}
return true;
}
static inline bool process_blend (CFF2CSInterpEnv &env, FlattenParam& param)
static inline void flush_n_args (unsigned int n, CFF2CSInterpEnv &env, FlattenParam& param)
{
flush_stack (env, param);
return true;
}
static inline bool process_vsindex (CFF2CSInterpEnv &env, FlattenParam& param)
{
flush_stack (env, param);
return true;
}
static inline void flush_stack (CFF2CSInterpEnv &env, FlattenParam& param)
{
for (unsigned int i = 0; i < env.argStack.size; i++)
for (unsigned int i = env.argStack.count - n; i < env.argStack.count; i++)
param.flatStr.encode_num (env.argStack.elements[i]);
SUPER::flush_stack (env, param);
SUPER::flush_n_args (n, env, param);
}
static inline void flush_op (OpCode op, CFF2CSInterpEnv &env, FlattenParam& param)
{
param.flatStr.encode_op (op);
}
private: