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
This commit is contained in:
parent
fcf177885b
commit
f2d299b0b7
|
@ -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,11 +42,8 @@ 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 ())
|
||||
{
|
||||
int v = n.to_int ();
|
||||
if ((-1131 <= v) && (v <= 1131))
|
||||
{
|
||||
if ((-107 <= v) && (v <= 107))
|
||||
|
@ -67,6 +64,13 @@ struct ByteStrBuff : hb_vector_t<char, 1>
|
|||
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
|
||||
{
|
||||
int32_t v = n.to_fixed ();
|
||||
|
@ -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,6 +148,7 @@ struct CFF1CSOpSet_Flatten : CFF1CSOpSet<CFF1CSOpSet_Flatten, FlattenParam>
|
|||
static inline void flush_hintmask (OpCode op, CFF1CSInterpEnv &env, FlattenParam& param)
|
||||
{
|
||||
SUPER::flush_hintmask (op, env, param);
|
||||
if (!param.drop_hints)
|
||||
for (unsigned int i = 0; i < env.hintmask_size; i++)
|
||||
param.flatStr.encode_byte (env.substr[i]);
|
||||
}
|
||||
|
|
|
@ -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,15 +111,57 @@ 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)
|
||||
{
|
||||
switch (op)
|
||||
{
|
||||
case OpCode_return:
|
||||
case OpCode_endchar:
|
||||
return;
|
||||
default:
|
||||
param.flatStr.encode_op (op);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
typedef CFF2CSOpSet<CFF2CSOpSet_Flatten, FlattenParam> SUPER;
|
||||
|
|
Loading…
Reference in New Issue