#include "hb-open-type-private.hh"
#include "hb-ot-layout-common-private.hh"
+#include "hb-subset-plan.hh"
namespace CFF {
OpCode_reserved255 = 255
};
-inline OpCode Make_OpCode_ESC(unsigned char byte2) { return (OpCode)(OpCode_ESC_Base + byte2); }
+inline OpCode Make_OpCode_ESC (unsigned char byte2) { return (OpCode)(OpCode_ESC_Base + byte2); }
+inline unsigned int OpCode_Size (OpCode op) { return (op >= OpCode_ESC_Base)? 2: 1; }
+
+/* pair of table offset and length */
+struct offset_size_pair {
+ unsigned int offset;
+ unsigned int size;
+};
+
+/* byte string */
+struct UnsizedByteStr : UnsizedArrayOf <HBUINT8>
+{
+ // encode 2-byte int (Dict/CharString) or 4-byte int (Dict)
+ template <typename INTTYPE, int minVal, int maxVal>
+ inline static bool serialize_int (hb_serialize_context_t *c, OpCode intOp, int value)
+ {
+ TRACE_SERIALIZE (this);
+
+ if (unlikely ((value < minVal || value > maxVal)))
+ return_trace (false);
+
+ HBUINT8 *p = c->allocate_size<HBUINT8> (1);
+ if (unlikely (p == nullptr)) return_trace (false);
+ p->set (intOp);
+
+ INTTYPE *ip = c->allocate_size<INTTYPE> (INTTYPE::static_size);
+ if (unlikely (ip == nullptr)) return_trace (false);
+ ip->set ((unsigned int)value);
+
+ return_trace (true);
+ }
+
+ inline static bool serialize_int4 (hb_serialize_context_t *c, int value)
+ { return serialize_int<HBUINT32, 0, 0x7FFFFFFF> (c, OpCode_longint, value); }
+
+ inline static bool serialize_int2 (hb_serialize_context_t *c, int value)
+ { return serialize_int<HBUINT16, 0, 0x7FFF> (c, OpCode_shortint, value); }
+};
+
+struct ByteStr
+{
+ ByteStr (const UnsizedByteStr& s, unsigned int l)
+ : str (&s), len (l) {}
+ ByteStr (const char *s=nullptr, unsigned int l=0)
+ : str ((const UnsizedByteStr *)s), len (l) {}
+ /* sub-string */
+ ByteStr (const ByteStr &bs, unsigned int offset, unsigned int l)
+ {
+ str = (const UnsizedByteStr *)&bs.str[offset];
+ len = l;
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) const { return str->sanitize (c, len); }
+
+ inline const HBUINT8& operator [] (unsigned int i) const {
+ assert (str && (i < len));
+ return (*str)[i];
+ }
+
+ inline bool check_limit (unsigned int offset, unsigned int count) const
+ { return (offset + count <= len); }
+
+ const UnsizedByteStr *str;
+ unsigned int len;
+};
+
+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 */
struct Index
c->check_array (data_base (), 1, max_offset () - 1)));
}
- inline unsigned int offset_array_size (void) const
+ 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 Index &src)
+ {
+ TRACE_SANITIZE (this);
+ unsigned int size = src.get_size ();
+ Index *dest = c->allocate_size<Index> (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> &bytesArray)
+ {
+ TRACE_SERIALIZE (this);
+
+ /* serialize Index header */
+ if (unlikely (!c->extend_min (*this))) return_trace (false);
+ this->count.set (bytesArray.len);
+ this->offSize.set (offSize);
+ if (!unlikely (c->allocate_size<HBUINT8> (offSize * (bytesArray.len + 1))))
+ return_trace (false);
+
+ /* serialize indices */
+ unsigned int offset = 1;
+ for (unsigned int i = 0; i < bytesArray.len; i++)
+ {
+ set_offset_at (i, offset);
+ offset += bytesArray[i].len;
+ }
+
+ /* serialize data */
+ for (unsigned int i = 0; i < bytesArray.len; i++)
+ {
+ HBUINT8 *dest = c->allocate_size<HBUINT8> (bytesArray[i].len);
+ if (dest == nullptr)
+ return_trace (false);
+ memcpy (dest, &bytesArray[i].str[0], bytesArray[i].len);
+ }
+ 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
{
const HBUINT8 *p = offsets + offSize * index;
inline unsigned int data_size (void) const
{ return HBINT8::static_size; };
- inline hb_bytes_t operator [] (unsigned int index) const
+ inline ByteStr operator [] (unsigned int index) const
{
if (likely (index < count))
- {
- hb_bytes_t b;
- b.bytes = data_base () + offset_at (index) - 1;
- b.len = offset_at (index + 1) - offset_at (index);
- return b;
- }
- return Null(hb_bytes_t);
+ 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
- { return count.static_size + offSize.static_size + offset_array_size () + (offset_at (count) - 1); }
+ {
+ if (this != &Null(Index))
+ return count.static_size + offSize.static_size + offset_array_size () + (offset_at (count) - 1);
+ else
+ return 0;
+ }
protected:
inline unsigned int max_offset (void) const
HBUINT8 offsets[VAR]; /* The array of (count + 1) offsets into objects array (1-base). */
/* HBUINT8 data[VAR]; Object data */
public:
- DEFINE_SIZE_MIN (6);
+ DEFINE_SIZE_ARRAY (5, offsets);
};
template <typename Type>
struct IndexOf : Index
{
- inline const Type& operator [] (unsigned int index) const
+ inline ByteStr operator [] (unsigned int index) const
{
if (likely (index < count))
- return StructAtOffset<Type>(data_base (), offset_at (index) - 1);
- return Null(Type);
+ return ByteStr (data_base () + offset_at (index) - 1, length_at (index));
+ return Null(ByteStr);
}
};
-struct UnsizedByteStr : UnsizedArrayOf <HBUINT8> {};
+/* an operator prefixed by its operands in a byte string */
+struct OpStr
+{
+ OpCode op;
+ ByteStr str;
+ bool update;
+};
-struct ByteStr {
- ByteStr (const UnsizedByteStr& s, unsigned int l)
- : str (s), len (l) {}
+typedef hb_vector_t <OpStr> OpStrs;
- inline bool sanitize (hb_sanitize_context_t *c) const { return str.sanitize (c, len); }
+/* base param type for dict parsing */
+struct DictValues
+{
+ inline void init (void)
+ {
+ opStart = 0;
+ opStrs.init ();
+ }
- inline const HBUINT8& operator [] (unsigned int i) const { return str[i]; }
+ inline void fini (void)
+ {
+ opStrs.fini ();
+ }
- inline bool check_limit (unsigned int offset, unsigned int count) const
- { return (offset + count <= len); }
+ void pushOpStr (OpCode op, const ByteStr& str, unsigned int offset, bool update)
+ {
+ OpStr *opstr = opStrs.push ();
+ opstr->op = op;
+ opstr->str = ByteStr (str, opStart, offset - opStart);
+ opstr->update = update;
+ opStart = offset;
+ }
- const UnsizedByteStr& str;
- const unsigned int len;
+ unsigned int opStart;
+ OpStrs opStrs;
+};
+
+/* base of OP_SERIALIZER */
+struct OpSerializer
+{
+ protected:
+ inline bool copy_opstr (hb_serialize_context_t *c, const OpStr& opstr) const
+ {
+ TRACE_SERIALIZE (this);
+
+ 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);
+ }
};
/* Top Dict, Font Dict, Private Dict */
-typedef UnsizedByteStr Dict;
+struct Dict : UnsizedByteStr
+{
+ template <typename OP_SERIALIZER, typename PARAM>
+ inline bool serialize (hb_serialize_context_t *c,
+ const DictValues &values,
+ OP_SERIALIZER& opszr,
+ PARAM& param)
+ {
+ TRACE_SERIALIZE (this);
+ for (unsigned int i = 0; i < values.opStrs.len; i++)
+ {
+ if (unlikely (!opszr.serialize (c, values.opStrs[i], param)))
+ return_trace (false);
+ }
+ return_trace (true);
+ }
-typedef Index CharStrings;
-typedef Index Subrs;
-typedef IndexOf<Dict> FDArray;
+ /* in parallel to above */
+ template <typename OP_SERIALIZER>
+ inline static unsigned int calculate_serialized_size (const DictValues &values,
+ OP_SERIALIZER& opszr)
+ {
+ unsigned int size = 0;
+ for (unsigned int i = 0; i < values.opStrs.len; i++)
+ size += opszr.calculate_serialized_size (values.opStrs[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> ((op >= OpCode_ESC_Base)? 2: 1);
+ if (unlikely (p == nullptr)) return_trace (false);
+ if (op >= OpCode_ESC_Base)
+ {
+ p->set (OpCode_escape);
+ op = (OpCode)(op - OpCode_ESC_Base);
+ 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_longint); }
+
+ 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 FDArray : IndexOf<FontDict>
+{
+ template <typename DICTVAL, typename OP_SERIALIZER>
+ inline bool serialize (hb_serialize_context_t *c,
+ unsigned int offSize,
+ const hb_vector_t<DICTVAL> &fontDicts,
+ OP_SERIALIZER& opszr,
+ const hb_vector_t<offset_size_pair> &privatePairs)
+ {
+ TRACE_SERIALIZE (this);
+ if (unlikely (!c->extend_min (*this))) return_trace (false);
+ this->count.set (fontDicts.len);
+ this->offSize.set (offSize);
+ if (!unlikely (c->allocate_size<HBUINT8> (offSize * (fontDicts.len + 1))))
+ return_trace (false);
+
+ /* serialize font dict offsets */
+ unsigned int offset = 1;
+ unsigned int i;
+ for (i = 0; i < fontDicts.len; i++)
+ {
+ set_offset_at (i, offset);
+ offset += FontDict::calculate_serialized_size (fontDicts[i], opszr);
+ }
+ set_offset_at (i, offset);
+
+ /* serialize font dicts */
+ for (unsigned int i = 0; i < fontDicts.len; i++)
+ {
+ FontDict *dict = c->start_embed<FontDict> ();
+ if (unlikely (!dict->serialize (c, fontDicts[i], opszr, privatePairs[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,
+ OP_SERIALIZER& opszr)
+ {
+ unsigned int dictsSize = 0;
+ for (unsigned int i = 0; i < fontDicts.len; i++)
+ dictsSize += FontDict::calculate_serialized_size (fontDicts[i], opszr);
+
+ offSize = calcOffSize (dictsSize + 1);
+ return Index::calculate_serialized_size (offSize, fontDicts.len, dictsSize);
+ }
+};
/* FDSelect */
struct FDSelect0 {
return_trace (likely (c->check_struct (this) && fds[c->get_num_glyphs () - 1].sanitize (c)));
}
+ inline unsigned int get_size (unsigned int num_glyphs) const
+ { return HBUINT8::static_size * num_glyphs; }
+
HBUINT8 fds[VAR];
DEFINE_SIZE_MIN (1);
};
struct FDSelect3 {
+ inline unsigned int get_size (void) const
+ { return HBUINT16::static_size * 2 + FDSelect3_Range::static_size * nRanges; }
+
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
+
return_trace (likely (c->check_struct (this) && (format == 0 || format == 3) &&
(format == 0)? u.format0.sanitize (c): u.format3.sanitize (c)));
}
+ inline bool serialize (hb_serialize_context_t *c, const FDSelect &src, unsigned int num_glyphs)
+ {
+ TRACE_SANITIZE (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 if (likely (format == 3))
+ size += u.format3.get_size ();
+ return size;
+ }
+
HBUINT8 format;
union {
FDSelect0 format0;
DEFINE_SIZE_MIN (2);
};
+typedef Index CharStrings;
+typedef Index Subrs;
+
inline float parse_bcd (const ByteStr& str, unsigned int& offset, float& v)
{
// XXX: TODO
template <typename OpSet, typename Param>
struct Interpreter {
- inline void init ()
+ inline Interpreter (void)
{
stack.init ();
}
- inline void fini ()
+ inline ~Interpreter (void)
{
stack.fini ();
}
inline bool interpret (const ByteStr& str, Param& param)
{
- param.init();
+ param.init ();
for (unsigned int i = 0; i < str.len; i++)
{
- unsigned char byte = str[i];
- if ((OpCode_shortint == byte) ||
- (OpCode_OneByteIntFirst <= byte && OpCode_TwoByteNegInt3 >= byte))
+ OpCode op = (OpCode)(unsigned char)str[i];
+ if ((OpCode_shortint == op) ||
+ (OpCode_OneByteIntFirst <= op && OpCode_TwoByteNegInt3 >= op))
{
- if (unlikely (!process_intop (str, i, byte)))
+ if (unlikely (!process_intop (str, i, op)))
return false;
} else {
- if (byte == OpCode_escape) {
+ if (op == OpCode_escape) {
if (unlikely (!str.check_limit (i, 1)))
return false;
- byte = Make_OpCode_ESC(str[++i]);
+ op = Make_OpCode_ESC(str[++i]);
}
- if (unlikely (!OpSet::process_op (str, i, byte, stack, param)))
+ if (unlikely (!OpSet::process_op (str, i, op, stack, param)))
return false;
}
}
+
return true;
}
- inline bool process_intop (const ByteStr& str, unsigned int& offset, unsigned char byte)
+ inline bool process_intop (const ByteStr& str, unsigned int& offset, OpCode op)
{
- switch (byte) {
+ switch (op) {
case OpCode_TwoBytePosInt0: case OpCode_TwoBytePosInt1:
case OpCode_TwoBytePosInt2: case OpCode_TwoBytePosInt3:
- if (unlikely (str.check_limit (offset, 2) || !stack.check_overflow (1)))
+ if (unlikely (!str.check_limit (offset, 2) || !stack.check_overflow (1)))
return false;
- stack.push ((int16_t)((byte - OpCode_TwoBytePosInt0) * 256 + str[offset + 1] + 108));
+ stack.push ((int16_t)((op - OpCode_TwoBytePosInt0) * 256 + str[offset + 1] + 108));
+ offset++;
break;
case OpCode_TwoByteNegInt0: case OpCode_TwoByteNegInt1:
case OpCode_TwoByteNegInt2: case OpCode_TwoByteNegInt3:
if (unlikely (!str.check_limit (offset, 2) || !stack.check_overflow (1)))
return false;
- stack.push ((int16_t)(-(byte - OpCode_TwoByteNegInt0) * 256 - str[offset + 1] - 108));
+ stack.push ((int16_t)(-(op - OpCode_TwoByteNegInt0) * 256 - str[offset + 1] - 108));
+ offset++;
break;
case OpCode_shortint: /* 3-byte integer */
if (unlikely (!str.check_limit (offset, 3) || !stack.check_overflow (1)))
return false;
- stack.push ((int16_t)((str[offset + 1] << 8) | str[offset + 2]));
+ stack.push ((int16_t)*(const HBUINT16*)&str[offset + 1]);
+ offset += 2;
break;
default:
/* 1-byte integer */
- if (likely ((OpCode_OneByteIntFirst <= byte) && (byte <= OpCode_OneByteIntLast)) &&
+ if (likely ((OpCode_OneByteIntFirst <= op) && (op <= OpCode_OneByteIntLast)) &&
likely (stack.check_overflow (1)))
{
- stack.push ((int)byte - 139);
+ stack.push ((int)op - 139);
} else {
return false;
}
Stack stack;
};
+/* used by subsettter */
+struct SubTableOffsets {
+ inline SubTableOffsets (void)
+ {
+ memset (this, 0, sizeof(*this));
+ }
+
+ unsigned int topDictSize;
+ unsigned int varStoreOffset;
+ unsigned int FDSelectOffset;
+ unsigned int FDArrayOffset;
+ unsigned int FDArrayOffSize;
+ unsigned int charStringsOffset;
+ unsigned int charStringsOffSize;
+ unsigned int privateDictsOffset;
+};
+
} /* namespace CFF */
#endif /* HB_OT_CFF_COMMON_PRIVATE_HH */
*/
#define HB_OT_TAG_cff2 HB_TAG('C','F','F','2')
-struct CFF2TopDictValues
+struct CFF2VariationStore
{
- inline void init ()
+ 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_SANITIZE (this);
+ CFF2VariationStore *dest = c->allocate_size<CFF2VariationStore> (varStore->size);
+ if (unlikely (dest == nullptr)) return_trace (false);
+ memcpy (dest, varStore, size);
+ return_trace (true);
+ }
+
+ inline unsigned int get_size (void) const { return size; }
+
+ HBUINT16 size;
+ VariationStore varStore;
+
+ DEFINE_SIZE_MIN (2 + VariationStore::min_size);
+};
+
+struct CFF2TopDictValues : DictValues
+{
+ inline void init (void)
+ {
+ DictValues::init ();
charStringsOffset.set (0);
vstoreOffset.set (0);
FDArrayOffset.set (0);
FDSelectOffset.set (0);
+ }
+
+ inline void fini (void)
+ {
+ DictValues::fini ();
FontMatrix[0] = FontMatrix[3] = 0.001f;
FontMatrix[1] = FontMatrix[2] = FontMatrix[4] = FontMatrix[5] = 0.0f;
}
- LOffsetTo<CharStrings> charStringsOffset;
- LOffsetTo<VariationStore> vstoreOffset;
- LOffsetTo<FDArray> FDArrayOffset;
- LOffsetTo<FDSelect> FDSelectOffset;
+ inline unsigned int calculate_serialized_size (void) const
+ {
+ unsigned int size = 0;
+ for (unsigned int i = 0; i < opStrs.len; i++)
+ {
+ OpCode op = opStrs[i].op;
+ if (op == OpCode_FontMatrix)
+ size += opStrs[i].str.len;
+ else
+ size += OpCode_Size (OpCode_longint) + 4 + OpCode_Size (op);
+ }
+ return size;
+ }
+
float FontMatrix[6];
+ LOffsetTo<CharStrings> charStringsOffset;
+ LOffsetTo<CFF2VariationStore> vstoreOffset;
+ LOffsetTo<FDArray> FDArrayOffset;
+ LOffsetTo<FDSelect> FDSelectOffset;
};
struct CFF2TopDictOpSet
{
- static inline bool process_op (const ByteStr& str, unsigned int& offset, unsigned char byte, Stack& stack, CFF2TopDictValues& val)
+ static inline bool process_op (const ByteStr& str, unsigned int& offset, OpCode op, Stack& stack, CFF2TopDictValues& val)
{
- switch (byte) {
+ switch (op) {
case OpCode_CharStrings:
if (unlikely (!check_pop_offset (stack, val.charStringsOffset)))
return false;
+ val.pushOpStr (op, str, offset + 1, true);
break;
case OpCode_vstore:
if (unlikely (!check_pop_offset (stack, val.vstoreOffset)))
return false;
+ val.pushOpStr (op, str, offset + 1, true);
break;
case OpCode_FDArray:
if (unlikely (!check_pop_offset (stack, val.FDArrayOffset)))
return false;
+ val.pushOpStr (op, str, offset + 1, true);
break;
case OpCode_FDSelect:
if (unlikely (!check_pop_offset (stack, val.FDSelectOffset)))
return false;
+ val.pushOpStr (op, str, offset + 1, true);
break;
case OpCode_FontMatrix:
if (unlikely (!stack.check_underflow (6)))
return false;
for (int i = 0; i < 6; i++)
val.FontMatrix[i] = stack.pop ().to_real ();
+ val.pushOpStr (op, str, offset + 1, false);
break;
case OpCode_longint: /* 5-byte integer */
if (unlikely (!str.check_limit (offset, 5) || !stack.check_overflow (1)))
return false;
- stack.push ((int32_t)((str[offset + 1] << 24) | (str[offset + 2] << 16) | (str[offset + 3] << 8) | str[offset + 4]));
+ stack.push ((int32_t)*(const HBUINT32*)&str[offset + 1]);
offset += 4;
break;
stack.clear ();
return false;
}
+
return true;
}
};
-struct CFF2FontDictValues
+struct CFF2FontDictValues : DictValues
{
- inline void init ()
+ inline void init (void)
{
+ DictValues::init ();
privateDictSize = 0;
privateDictOffset.set (0);
}
- unsigned int privateDictSize;
- OffsetTo<Dict> privateDictOffset;
+ inline void fini (void)
+ {
+ DictValues::fini ();
+ }
+
+ unsigned int privateDictSize;
+ LOffsetTo<PrivateDict> privateDictOffset;
};
struct CFF2FontDictOpSet
{
- static inline bool process_op (const ByteStr& str, unsigned int& offset, unsigned char byte, Stack& stack, CFF2FontDictValues& val)
+ static inline bool process_op (const ByteStr& str, unsigned int& offset, OpCode op, Stack& stack, CFF2FontDictValues& val)
{
- switch (byte) {
+ switch (op) {
case OpCode_Private:
- if (unlikely (!stack.check_pop_uint (val.privateDictSize)))
- return false;
if (unlikely (!check_pop_offset (stack, val.privateDictOffset)))
return false;
+ if (unlikely (!stack.check_pop_uint (val.privateDictSize)))
+ return false;
+ val.pushOpStr (op, str, offset + 1, true);
break;
case OpCode_longint: /* 5-byte integer */
if (unlikely (!str.check_limit (offset, 5) || !stack.check_overflow (1)))
return false;
- stack.push ((int32_t)((str[offset + 1] << 24) | (str[offset + 2] << 16) || (str[offset + 3] << 8) || str[offset + 4]));
+ stack.push ((int32_t)((str[offset + 1] << 24) | ((uint32_t)str[offset + 2] << 16) | ((uint32_t)str[offset + 3] << 8) | str[offset + 4]));
+ offset += 4;
break;
case OpCode_BCD: /* real number */
float v;
stack.clear ();
return false;
}
+
return true;
}
};
-struct CFF2PrivateDictValues
+struct CFF2PrivateDictValues : DictValues
{
- inline void init ()
+ inline void init (void)
{
+ DictValues::init ();
+
languageGroup = 0;
expansionFactor = 0.06f;
vsIndex = 0;
blueFuzz = 1.0f;
stdHW = UNSET_REAL_VALUE;
stdVW = UNSET_REAL_VALUE;
+ subrsOffset.set (0);
blueValues.init ();
otherBlues.init ();
familyBlues.init ();
familyOtherBlues.init ();
stemSnapH.init ();
stemSnapV.init ();
+
+ localSubrs = &Null(Subrs);
}
- inline void fini ()
+ inline void fini (void)
{
blueValues.fini ();
otherBlues.fini ();
familyOtherBlues.fini ();
stemSnapH.fini ();
stemSnapV.fini ();
+
+ DictValues::fini ();
+ }
+
+ inline unsigned int calculate_serialized_size (void) const
+ {
+ unsigned int size = 0;
+ for (unsigned int i = 0; i < opStrs.len; i++)
+ if (opStrs[i].op == OpCode_Subrs)
+ size += OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_Subrs);
+ else
+ size += opStrs[i].str.len;
+ return size;
}
int languageGroup;
hb_vector_t <float> familyOtherBlues;
hb_vector_t <float> stemSnapH;
hb_vector_t <float> stemSnapV;
+
+ const Subrs *localSubrs;
};
struct CFF2PrivateDictOpSet
{
- static inline bool process_op (const ByteStr& str, unsigned int& offset, unsigned char byte, Stack& stack, CFF2PrivateDictValues& val)
+ static inline bool process_op (const ByteStr& str, unsigned int& offset, OpCode op, Stack& stack, CFF2PrivateDictValues& val)
{
- switch (byte) {
+ switch (op) {
case OpCode_BlueValues:
if (unlikely (!stack.check_pop_delta (val.blueValues, true)))
return false;
case OpCode_blend:
// XXX: TODO
break;
+ case OpCode_longint: /* 5-byte integer */
+ if (unlikely (!str.check_limit (offset, 5) || !stack.check_overflow (1)))
+ return false;
+ stack.push ((int32_t)((str[offset + 1] << 24) | (str[offset + 2] << 16) || (str[offset + 3] << 8) || str[offset + 4]));
+ offset += 4;
+ break;
+ case OpCode_BCD: /* real number */
+ float v;
+ if (unlikely (!stack.check_overflow (1) || !parse_bcd (str, offset, v)))
+ return false;
+ stack.push (v);
+ break;
default:
return false;
}
+
+ if (op != OpCode_blend)
+ val.pushOpStr (op, str, offset + 1, op == OpCode_Subrs);
+
return true;
}
};
{
inline void init (hb_face_t *face)
{
- hb_sanitize_context_t c;
- this->blob = c.reference_table<cff2> (face);
+ 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->as<OT::cff2> ();
if (cff2 == &Null(OT::cff2))
{ /* parse top dict */
ByteStr topDictStr (cff2 + cff2->topDict, cff2->topDictSize);
- if (unlikely (!topDictStr.sanitize (&c)))
+ CFF2TopDict_Interpreter top_interp;
+ if (unlikely (!topDictStr.sanitize (&sc) ||
+ !top_interp.interpret (topDictStr, top)))
{
fini ();
return;
}
- CFF2TopDict_Interpreter top_interp;
- top_interp.init ();
- top_interp.interpret (topDictStr, top);
- top_interp.fini ();
}
- varStore = &OT::StructAtOffset<VariationStore>(cff2, top.vstoreOffset);
- charStrings = &OT::StructAtOffset<CharStrings>(cff2, top.charStringsOffset);
- fdArray = &OT::StructAtOffset<FDArray>(cff2, top.FDArrayOffset);
- fdSelect = &OT::StructAtOffset<FDSelect>(cff2, top.FDSelectOffset);
+ globalSubrs = &OT::StructAtOffset<Subrs> (cff2, cff2->topDict + cff2->topDictSize);
+ varStore = &top.vstoreOffset (cff2);
+ charStrings = &top.charStringsOffset (cff2);
+ fdArray = &top.FDArrayOffset (cff2);
+ fdSelect = &top.FDSelectOffset (cff2);
- if (((varStore != &Null(VariationStore)) && unlikely (!varStore->sanitize (&c))) ||
- ((charStrings == &Null(CharStrings)) || unlikely (!charStrings->sanitize (&c))) ||
- ((fdArray == &Null(FDArray)) || unlikely (!fdArray->sanitize (&c))) ||
- ((fdSelect == &Null(FDSelect)) || unlikely (!fdSelect->sanitize (&c))))
+ if (((varStore != &Null(CFF2VariationStore)) && unlikely (!varStore->sanitize (&sc))) ||
+ ((charStrings == &Null(CharStrings)) || unlikely (!charStrings->sanitize (&sc))) ||
+ ((fdArray == &Null(FDArray)) || unlikely (!fdArray->sanitize (&sc))) ||
+ ((fdSelect != &Null(FDSelect)) && unlikely (!fdSelect->sanitize (&sc))))
{
fini ();
return;
}
num_glyphs = charStrings->count;
- if (num_glyphs != c.get_num_glyphs ())
+ if (num_glyphs != sc.get_num_glyphs ())
{
fini ();
return;
}
+
+ privateDicts.resize (fdArray->count);
+
+ // parse font dicts and gather private dicts
+ for (unsigned int i = 0; i < fdArray->count; i++)
+ {
+ const ByteStr fontDictStr = (*fdArray)[i];
+ CFF2FontDictValues *font;
+ CFF2FontDict_Interpreter font_interp;
+ font = fontDicts.push ();
+ if (unlikely (!fontDictStr.sanitize (&sc) ||
+ !font_interp.interpret (fontDictStr, *font)))
+ {
+ fini ();
+ return;
+ }
+
+ const ByteStr privDictStr (font->privateDictOffset (cff2), font->privateDictSize);
+ CFF2PrivateDict_Interpreter priv_interp;
+ if (unlikely (!privDictStr.sanitize (&sc) ||
+ !priv_interp.interpret (privDictStr, privateDicts[i])))
+ {
+ fini ();
+ return;
+ }
+
+ privateDicts[i].localSubrs = &privateDicts[i].subrsOffset (cff2);
+ }
}
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
{
private:
hb_blob_t *blob;
+ hb_sanitize_context_t sc;
- CFF2TopDictValues top;
- const VariationStore *varStore;
- const CharStrings *charStrings;
- const FDArray *fdArray;
- const FDSelect *fdSelect;
+ public:
+ CFF2TopDictValues top;
+ const Subrs *globalSubrs;
+ const CFF2VariationStore *varStore;
+ const CharStrings *charStrings;
+ const FDArray *fdArray;
+ const FDSelect *fdSelect;
+
+ hb_vector_t<CFF2FontDictValues> fontDicts;
+ hb_vector_t<CFF2PrivateDictValues> privateDicts;
unsigned int num_glyphs;
};
return success;
}
- protected:
- FixedVersion<HBUINT8> version; /* Version of CFF2 table. set to 0x0200u */
- OffsetTo<Dict, HBUINT8> topDict; /* headerSize = Offset to Top DICT. */
- HBUINT16 topDictSize; /* Top DICT size */
+ 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);
/* Global nul-content Null pool. Enlarge as necessary. */
-#define HB_NULL_POOL_SIZE 264
+#define HB_NULL_POOL_SIZE 800
extern HB_INTERNAL
hb_vector_size_impl_t const _hb_NullPool[(HB_NULL_POOL_SIZE + sizeof (hb_vector_size_impl_t) - 1) / sizeof (hb_vector_size_impl_t)];
#include "hb-subset-cff2.hh"
#include "hb-subset-plan.hh"
-static bool
-_calculate_cff2_prime_size (const OT::cff2::accelerator_t &cff2,
- hb_vector_t<hb_codepoint_t> &glyph_ids,
- hb_bool_t drop_hints,
- unsigned int *cff2_size /* OUT */,
- hb_vector_t<unsigned int> *instruction_ranges /* OUT */)
+using namespace CFF;
+
+struct CFF2TopDict_OpSerializer : OpSerializer
{
- // XXX: TODO
- *cff2_size = 0;
- return true;
-}
+ inline bool serialize (hb_serialize_context_t *c,
+ const OpStr &opstr,
+ const SubTableOffsets &offsets) const
+ {
+ TRACE_SERIALIZE (this);
-static bool
-_write_cff2_prime (hb_subset_plan_t *plan,
- const OT::cff2::accelerator_t &cff2,
- const char *cff2_data,
- hb_vector_t<unsigned int> &instruction_ranges,
- unsigned int cff2_prime_size,
- char *cff2_prime_data /* OUT */)
+ 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.charStringsOffset));
+
+ case OpCode_FDArray:
+ return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.FDArrayOffset));
+
+ case OpCode_FDSelect:
+ return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.FDSelectOffset));
+
+ 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_longint) + 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 offset_size_pair& privOffSize) 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, privOffSize.size)))
+ return_trace (false);
+
+ /* serialize the private dict offset as a 4-byte integer */
+ if (unlikely (!UnsizedByteStr::serialize_int4 (c, privOffSize.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_longint) + 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 subset_plan {
+ inline subset_plan (void)
+ {
+ subset_charstrings.init ();
+ private_off_and_size_pairs.init ();
+ }
+
+ inline ~subset_plan (void)
+ {
+ subset_charstrings.fini ();
+ private_off_and_size_pairs.fini ();
+ }
+
+ inline bool create (const OT::cff2::accelerator_t &acc,
+ hb_subset_plan_t *plan)
+ {
+ final_size = 0;
+
+ /* CFF2 header */
+ final_size += OT::cff2::static_size;
+
+ /* top dict */
+ {
+ CFF2TopDict_OpSerializer topSzr;
+ offsets.topDictSize = TopDict::calculate_serialized_size<CFF2TopDict_OpSerializer> (acc.top, topSzr);
+ final_size += offsets.topDictSize;
+ }
+
+ /* global subrs */
+ final_size += acc.globalSubrs->get_size ();
+
+ /* variation store */
+ if (acc.varStore != &Null(CFF2VariationStore))
+ {
+ offsets.varStoreOffset = final_size;
+ final_size += acc.varStore->get_size ();
+ }
+
+ /* FDSelect */
+ if (acc.fdSelect != &Null(FDSelect))
+ {
+ offsets.FDSelectOffset = final_size;
+ final_size += acc.fdSelect->calculate_serialized_size (acc.num_glyphs);
+ }
+
+ /* FDArray (FDIndex) */
+ {
+ offsets.FDArrayOffset = final_size;
+ CFF2FontDict_OpSerializer fontSzr;
+ final_size += FDArray::calculate_serialized_size(offsets.FDArrayOffSize/*OUT*/, acc.fontDicts, fontSzr);
+ }
+
+ /* CharStrings */
+ {
+ offsets.charStringsOffset = 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.charStringsOffSize = calcOffSize (dataSize + 1);
+ final_size += CharStrings::calculate_serialized_size (offsets.charStringsOffSize, plan->glyphs.len, dataSize);
+ }
+
+ /* private dicts & local subrs */
+ offsets.privateDictsOffset = final_size;
+ for (unsigned int i = 0; i < acc.fdArray->count; i++)
+ {
+ CFF2PrivateDict_OpSerializer privSzr;
+ unsigned int private_size = PrivateDict::calculate_serialized_size (acc.privateDicts[i], privSzr);
+ offset_size_pair pair = { final_size, private_size };
+ private_off_and_size_pairs.push (pair);
+ final_size += private_size + acc.privateDicts[i].localSubrs->get_size ();
+ }
+
+ return true;
+ }
+
+ inline unsigned int get_final_size (void) const { return final_size; }
+
+ unsigned int final_size;
+ SubTableOffsets offsets;
+
+ hb_vector_t<ByteStr> subset_charstrings;
+ hb_vector_t<offset_size_pair> private_off_and_size_pairs;
+};
+
+static inline bool _write_cff2 (const subset_plan &plan,
+ const OT::cff2::accelerator_t &acc,
+ unsigned int dest_sz,
+ void *dest)
{
- // XXX: TODO
+ hb_serialize_context_t c (dest, dest_sz);
+
+ TRACE_SERIALIZE (this);
+ OT::cff2 *cff2 = c.start_serialize<OT::cff2> ();
+ if (unlikely (!c.extend_min (*cff2)))
+ return_trace (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.top, topSzr, plan.offsets)))
+ {
+ DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 top dict");
+ return_trace (false);
+ }
+ }
+
+ /* global subrs */
+ {
+ assert (cff2->topDict + plan.offsets.topDictSize == c.head - c.start);
+ Subrs *dest = c.start_embed<Subrs> ();
+ if (unlikely (dest == nullptr)) return_trace (false);;
+ if (unlikely (!dest->serialize (&c, *acc.globalSubrs)))
+ {
+ DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 global subrs");
+ return_trace (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_trace (false);
+ }
+ }
+
+ /* FDSelect */
+ if (acc.fdSelect != &Null(FDSelect))
+ {
+ assert (plan.offsets.FDSelectOffset == c.head - c.start);
+ FDSelect *dest = c.start_embed<FDSelect> ();
+ if (unlikely (!dest->serialize (&c, *acc.fdSelect, acc.num_glyphs)))
+ {
+ DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 FDSelect");
+ return_trace (false);
+ }
+ }
+
+ /* FDArray (FD Index) */
+ {
+ assert (plan.offsets.FDArrayOffset == c.head - c.start);
+ FDArray *fda = c.start_embed<FDArray> ();
+ if (unlikely (fda == nullptr)) return_trace (false);
+ CFF2FontDict_OpSerializer fontSzr;
+ if (unlikely (!fda->serialize (&c, plan.offsets.FDArrayOffSize, acc.fontDicts, fontSzr, plan.private_off_and_size_pairs)))
+ {
+ DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 FDArray");
+ return_trace (false);
+ }
+ }
+
+ /* CharStrings */
+ {
+ assert (plan.offsets.charStringsOffset == c.head - c.start);
+ CharStrings *cs = c.start_embed<CharStrings> ();
+ if (unlikely (cs == nullptr)) return_trace (false);
+ if (unlikely (!cs->serialize (&c, plan.offsets.charStringsOffSize, plan.subset_charstrings)))
+ {
+ DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 CharStrings");
+ return_trace (false);
+ }
+ }
+
+ /* private dicts & local subrs */
+ assert (plan.offsets.privateDictsOffset == c.head - c.start);
+ for (unsigned int i = 0; i < acc.privateDicts.len; i++)
+ {
+ PrivateDict *pd = c.start_embed<PrivateDict> ();
+ if (unlikely (pd == nullptr)) return_trace (false);
+ CFF2PrivateDict_OpSerializer privSzr;
+ if (unlikely (!pd->serialize (&c, acc.privateDicts[i], privSzr, acc.privateDicts[i].subrsOffset)))
+ {
+ DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 Private Dict[%d]", i);
+ return_trace (false);
+ }
+ if (acc.privateDicts[i].subrsOffset != 0)
+ {
+ Subrs *subrs = c.allocate_size<Subrs> (acc.privateDicts[i].localSubrs->get_size ());
+ if (unlikely (subrs == nullptr) || acc.privateDicts[i].localSubrs == &Null(Subrs))
+ {
+ DEBUG_MSG (SUBSET, nullptr, "CFF2 subset: local subrs unexpectedly null [%d]", i);
+ return_trace (false);
+ }
+ if (unlikely (!subrs->serialize (&c, *acc.privateDicts[i].localSubrs)))
+ {
+ DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 local subrs [%d]", i);
+ return_trace (false);
+ }
+ }
+ }
+
+ c.end_serialize ();
+
return true;
}
static bool
-_hb_subset_cff2 (const OT::cff2::accelerator_t &cff2,
- const char *cff2_data,
- hb_subset_plan_t *plan,
- hb_blob_t **cff2_prime /* OUT */)
+_hb_subset_cff2 (const OT::cff2::accelerator_t &acc,
+ const char *data,
+ hb_subset_plan_t *plan,
+ hb_blob_t **prime /* OUT */)
{
- hb_vector_t<hb_codepoint_t> &glyphs_to_retain = plan->glyphs;
-
- unsigned int cff2_prime_size;
- hb_vector_t<unsigned int> instruction_ranges;
- instruction_ranges.init();
-
- if (unlikely (!_calculate_cff2_prime_size (cff2,
- glyphs_to_retain,
- plan->drop_hints,
- &cff2_prime_size,
- &instruction_ranges))) {
- instruction_ranges.fini();
+ subset_plan cff2_subset_plan;
+
+ if (unlikely (!cff2_subset_plan.create (acc, plan)))
+ {
+ DEBUG_MSG(SUBSET, nullptr, "Failed to generate a cff2 subsetting plan.");
return false;
}
+ unsigned int cff2_prime_size = cff2_subset_plan.get_final_size ();
char *cff2_prime_data = (char *) calloc (1, cff2_prime_size);
- if (unlikely (!_write_cff2_prime (plan, cff2, cff2_data,
- instruction_ranges,
- cff2_prime_size, cff2_prime_data))) {
+
+ if (unlikely (!_write_cff2 (cff2_subset_plan, acc,
+ cff2_prime_size, cff2_prime_data))) {
+ DEBUG_MSG(SUBSET, nullptr, "Failed to write a subset cff2.");
free (cff2_prime_data);
- instruction_ranges.fini();
return false;
}
- instruction_ranges.fini();
- *cff2_prime = hb_blob_create (cff2_prime_data,
+ *prime = hb_blob_create (cff2_prime_data,
cff2_prime_size,
HB_MEMORY_MODE_READONLY,
cff2_prime_data,
free);
- // XXX: TODO
return true;
}
**/
bool
hb_subset_cff2 (hb_subset_plan_t *plan,
- hb_blob_t **cff2_prime /* OUT */)
+ hb_blob_t **prime /* OUT */)
{
hb_blob_t *cff2_blob = OT::hb_sanitize_context_t().reference_table<CFF::cff2> (plan->source);
- const char *cff2_data = hb_blob_get_data(cff2_blob, nullptr);
+ const char *data = hb_blob_get_data(cff2_blob, nullptr);
- OT::cff2::accelerator_t cff2;
- cff2.init(plan->source);
- bool result = _hb_subset_cff2 (cff2,
- cff2_data,
+ OT::cff2::accelerator_t acc;
+ acc.init(plan->source);
+ bool result = likely (acc.is_valid ()) &&
+ _hb_subset_cff2 (acc,
+ data,
plan,
- cff2_prime);
+ prime);
hb_blob_destroy (cff2_blob);
- cff2.fini();
+ acc.fini();
return result;
}