Added CFF2 Subr nullifier
along with CFF2 charstring interpreter
factored out common code between CFF1 & CFF2 to CSInterpreter
moved fetch_op from Interpreter to InterpEnv
misc code clean up & bug fixes
diff --git a/src/Makefile.sources b/src/Makefile.sources
index f5e1a6d..f7ae086 100644
--- a/src/Makefile.sources
+++ b/src/Makefile.sources
@@ -155,6 +155,7 @@
hb-cff-interp-common-private.hh \
hb-cff-interp-cs-common-private.hh \
hb-cff1-interp-cs.hh \
+ hb-cff2-interp-cs.hh \
hb-cff-interp-dict-common-private.hh \
$(NULL)
diff --git a/src/hb-cff-interp-common-private.hh b/src/hb-cff-interp-common-private.hh
index 0f81b48..9b4d488 100644
--- a/src/hb-cff-interp-common-private.hh
+++ b/src/hb-cff-interp-common-private.hh
@@ -56,7 +56,7 @@
OpCode_Subrs, /* 19 CFF Private, CFF2 Private */
OpCode_defaultWidthX, /* 20 CFF Private (0) */
OpCode_nominalWidthX, /* 21 CFF Private (0) */
- OpCode_vsindex, /* 22 CFF2 Private/CS */
+ OpCode_vsindexdict, /* 22 CFF2 Private/CS */
OpCode_blenddict, /* 23 CFF2 Private/CS */
OpCode_vstore, /* 24 CFF2 Top */
OpCode_reserved25, /* 25 */
@@ -142,8 +142,8 @@
// OpCode_escape, /* 12 CFF, CFF2 */
OpCode_Reserved13 = 13,
OpCode_endchar, /* 14 CFF */
- // OpCode_vsindex, /* 15 CFF2 */
- OpCode_blendcs = 16, /* 16 CFF2 */
+ OpCode_vsindexcs, /* 15 CFF2 */
+ OpCode_blendcs, /* 16 CFF2 */
OpCode_Reserved17,
OpCode_hstemhm, /* 18 CFF, CFF2 */
OpCode_hintmask, /* 19 CFF, CFF2 */
@@ -365,8 +365,8 @@
inline void clear (void) { size = 0; }
- inline bool check_overflow (unsigned int count) const { return (count <= kSizeLimit) && (count + size <= kSizeLimit); }
- inline bool check_underflow (unsigned int count) const { return (count <= size); }
+ 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 unsigned int get_size (void) const { return size; }
inline bool is_empty (void) const { return size == 0; }
@@ -396,7 +396,7 @@
inline bool check_pop_num (Number& n)
{
- if (unlikely (!this->check_underflow (1)))
+ if (unlikely (!this->check_underflow ()))
return false;
n = this->pop ();
return true;
@@ -413,7 +413,7 @@
inline bool check_pop_int (int& v)
{
- if (unlikely (!this->check_underflow (1)))
+ if (unlikely (!this->check_underflow ()))
return false;
v = this->pop ().to_int ();
return true;
@@ -501,6 +501,21 @@
argStack.fini ();
}
+ inline bool fetch_op (OpCode &op)
+ {
+ if (unlikely (!substr.avail ()))
+ return false;
+ op = (OpCode)(unsigned char)substr[0];
+ if (op == OpCode_escape) {
+ if (unlikely (!substr.avail ()))
+ return false;
+ op = Make_OpCode_ESC (substr[1]);
+ substr.inc ();
+ }
+ substr.inc ();
+ return true;
+ }
+
SubByteStr substr;
ArgStack argStack;
};
@@ -558,21 +573,6 @@
inline void fini (void) { env.fini (); }
- inline bool fetch_op (OpCode &op)
- {
- if (unlikely (!env.substr.avail ()))
- return false;
- op = (OpCode)(unsigned char)env.substr[0];
- if (op == OpCode_escape) {
- if (unlikely (!env.substr.avail ()))
- return false;
- op = Make_OpCode_ESC (env.substr[1]);
- env.substr.inc ();
- }
- env.substr.inc ();
- return true;
- }
-
ENV env;
};
diff --git a/src/hb-cff-interp-cs-common-private.hh b/src/hb-cff-interp-cs-common-private.hh
index cf98e0f..3172535 100644
--- a/src/hb-cff-interp-cs-common-private.hh
+++ b/src/hb-cff-interp-cs-common-private.hh
@@ -64,6 +64,11 @@
{
InterpEnv::init (str);
+ stack_cleared = false;
+ seen_moveto = true;
+ seen_hintmask = false;
+ hstem_count = 0;
+ vstem_count = 0;
callStack.init ();
globalSubrs.init (globalSubrs_);
localSubrs.init (localSubrs_);
@@ -105,20 +110,55 @@
inline bool returnFromSubr (void)
{
- if (unlikely (!callStack.check_underflow (1)))
+ if (unlikely (!callStack.check_underflow ()))
return false;
substr = callStack.pop ();
return true;
}
+ inline void determine_hintmask_size (void)
+ {
+ if (!seen_hintmask)
+ {
+ vstem_count += argStack.size / 2;
+ hintmask_size = (hstem_count + vstem_count + 7) >> 3;
+ seen_hintmask = true;
+ }
+ clear_stack ();
+ }
+
+ inline void process_moveto (void)
+ {
+ clear_stack ();
+
+ if (!seen_moveto)
+ {
+ determine_hintmask_size ();
+ seen_moveto = 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; }
protected:
- bool endchar_flag;
+ bool endchar_flag;
+ bool stack_cleared;
+ bool seen_moveto;
+ bool seen_hintmask;
public:
+ unsigned int hstem_count;
+ unsigned int vstem_count;
+ unsigned int hintmask_size;
CallStack callStack;
BiasedSubrs<SUBRS> globalSubrs;
BiasedSubrs<SUBRS> localSubrs;
@@ -131,6 +171,12 @@
{
switch (op) {
+ case OpCode_return:
+ return env.returnFromSubr ();
+ case OpCode_endchar:
+ env.set_endchar (true);
+ return true;
+
case OpCode_longintcs:
return env.argStack.push_longint_from_substr (env.substr);
@@ -140,9 +186,50 @@
case OpCode_callgsubr:
return env.callSubr (env.globalSubrs);
+ case OpCode_hstem:
+ case OpCode_hstemhm:
+ env.hstem_count += env.argStack.size / 2;
+ env.clear_stack ();
+ break;
+ case OpCode_vstem:
+ case OpCode_vstemhm:
+ env.vstem_count += env.argStack.size / 2;
+ env.clear_stack ();
+ break;
+ case OpCode_hintmask:
+ case OpCode_cntrmask:
+ env.determine_hintmask_size ();
+ if (unlikely (!env.substr.avail (env.hintmask_size)))
+ return false;
+ env.substr.inc (env.hintmask_size);
+ break;
+
+ case OpCode_vmoveto:
+ case OpCode_rlineto:
+ case OpCode_hlineto:
+ case OpCode_vlineto:
+ case OpCode_rmoveto:
+ case OpCode_hmoveto:
+ env.process_moveto ();
+ break;
+ case OpCode_rrcurveto:
+ case OpCode_rcurveline:
+ case OpCode_rlinecurve:
+ case OpCode_vvcurveto:
+ case OpCode_hhcurveto:
+ case OpCode_vhcurveto:
+ case OpCode_hvcurveto:
+ case OpCode_hflex:
+ case OpCode_flex:
+ case OpCode_hflex1:
+ case OpCode_flex1:
+ env.clear_stack ();
+ break;
+
default:
return OpSet::process_op (op, env);
}
+ return true;
}
};
@@ -157,13 +244,11 @@
for (;;) {
OpCode op;
- if (unlikely (!super.fetch_op (op) ||
+ if (unlikely (!super.env.fetch_op (op) ||
!OPSET::process_op (op, super.env, param)))
return false;
if (super.env.is_endchar ())
break;
- if (!super.env.substr.avail ())
- return false;
}
return true;
diff --git a/src/hb-cff-interp-dict-common-private.hh b/src/hb-cff-interp-dict-common-private.hh
index 60764fd..62041c9 100644
--- a/src/hb-cff-interp-dict-common-private.hh
+++ b/src/hb-cff-interp-dict-common-private.hh
@@ -170,7 +170,8 @@
do
{
OpCode op;
- if (unlikely (!super.fetch_op (op) || !OPSET::process_op (op, super.env, param)))
+ if (unlikely (!super.env.fetch_op (op) ||
+ !OPSET::process_op (op, super.env, param)))
return false;
} while (super.env.substr.avail ());
diff --git a/src/hb-cff1-interp-cs.hh b/src/hb-cff1-interp-cs.hh
index 6767d0f..c76a788 100644
--- a/src/hb-cff1-interp-cs.hh
+++ b/src/hb-cff1-interp-cs.hh
@@ -38,11 +38,6 @@
inline void init (const ByteStr &str, const CFF1Subrs &globalSubrs, const CFF1Subrs &localSubrs)
{
CSInterpEnv<CFF1Subrs>::init (str, globalSubrs, localSubrs);
- seen_width = false;
- seen_moveto = true;
- seen_hintmask = false;
- hstem_count = 0;
- vstem_count = 0;
for (unsigned int i = 0; i < kTransientArraySize; i++)
transient_array[i].set_int (0);
}
@@ -50,34 +45,6 @@
bool check_transient_array_index (unsigned int i) const
{ return i < kTransientArraySize; }
- inline void determine_hintmask_size (void)
- {
- if (!seen_hintmask)
- {
- vstem_count += argStack.size / 2;
- hintmask_size = (hstem_count + vstem_count + 7) >> 3;
- seen_hintmask = true;
- }
- clear_stack ();
- }
-
- inline void process_moveto (void)
- {
- clear_stack ();
-
- if (!seen_moveto)
- {
- determine_hintmask_size ();
- seen_moveto = true;
- }
- }
-
- inline void clear_stack (void)
- {
- seen_width = true;
- argStack.clear ();
- }
-
inline void process_width (void)
{
if (!seen_width && (argStack.size > 0))
@@ -90,11 +57,6 @@
bool seen_width;
Number width;
- bool seen_moveto;
- bool seen_hintmask;
- unsigned int hintmask_size;
- unsigned int hstem_count;
- unsigned int vstem_count;
static const unsigned int kTransientArraySize = 32;
Number transient_array[kTransientArraySize];
@@ -109,11 +71,6 @@
switch (op) {
- case OpCode_return:
- return env.returnFromSubr ();
- case OpCode_endchar:
- env.set_endchar (true);
- return true;
case OpCode_and:
if (unlikely (!env.argStack.check_pop_num2 (n1, n2))) return false;
env.argStack.push_int ((n1.to_real() != 0.0f) && (n2.to_real() != 0.0f));
@@ -223,45 +180,6 @@
}
}
break;
- case OpCode_hstem:
- case OpCode_hstemhm:
- env.hstem_count += env.argStack.size / 2;
- env.clear_stack ();
- break;
- case OpCode_vstem:
- case OpCode_vstemhm:
- env.vstem_count += env.argStack.size / 2;
- env.clear_stack ();
- break;
- case OpCode_hintmask:
- case OpCode_cntrmask:
- env.determine_hintmask_size ();
- if (unlikely (!env.substr.avail (env.hintmask_size)))
- return false;
- env.substr.inc (env.hintmask_size);
- break;
-
- case OpCode_vmoveto:
- case OpCode_rlineto:
- case OpCode_hlineto:
- case OpCode_vlineto:
- case OpCode_rmoveto:
- case OpCode_hmoveto:
- env.process_moveto ();
- break;
- case OpCode_rrcurveto:
- case OpCode_rcurveline:
- case OpCode_rlinecurve:
- case OpCode_vvcurveto:
- case OpCode_hhcurveto:
- case OpCode_vhcurveto:
- case OpCode_hvcurveto:
- case OpCode_hflex:
- case OpCode_flex:
- case OpCode_hflex1:
- case OpCode_flex1:
- env.clear_stack ();
- break;
default:
typedef CSOpSet<CFF1Subrs, PARAM> SUPER;
if (unlikely (!SUPER::process_op (op, env, param)))
diff --git a/src/hb-cff2-interp-cs.hh b/src/hb-cff2-interp-cs.hh
new file mode 100644
index 0000000..519b5fc
--- /dev/null
+++ b/src/hb-cff2-interp-cs.hh
@@ -0,0 +1,97 @@
+/*
+ * Copyright © 2018 Adobe Systems Incorporated.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Adobe Author(s): Michiharu Ariza
+ */
+#ifndef HB_CFF2_INTERP_CS_HH
+#define HB_CFF2_INTERP_CS_HH
+
+#include "hb-private.hh"
+#include "hb-cff-interp-cs-common-private.hh"
+
+namespace CFF {
+
+using namespace OT;
+
+struct CFF2CSInterpEnv : CSInterpEnv<CFF2Subrs>
+{
+ inline void init (const ByteStr &str, const CFF2Subrs &globalSubrs_, const CFF2Subrs &localSubrs_)
+ {
+ CSInterpEnv<CFF2Subrs>::init (str, globalSubrs_, localSubrs_);
+ ivs = 0;
+ }
+
+ inline bool fetch_op (OpCode &op)
+ {
+ if (unlikely (substr.avail ()))
+ return CSInterpEnv<CFF2Subrs>::fetch_op (op);
+
+ /* make up return or endchar op */
+ if (callStack.check_underflow ())
+ op = OpCode_return;
+ else
+ op = OpCode_endchar;
+ return true;
+ }
+
+ inline unsigned int get_ivs (void) const { return ivs; }
+ inline void set_ivs (unsigned int ivs_) { ivs = ivs_; }
+
+ protected:
+ unsigned int ivs;
+};
+
+template <typename PARAM>
+struct CFF2CSOpSet : CSOpSet<CFF2Subrs, PARAM>
+{
+ static inline bool process_op (OpCode op, CFF2CSInterpEnv &env, PARAM& param)
+ {
+ switch (op) {
+
+ case OpCode_blendcs:
+ env.clear_stack (); // XXX: TODO
+ break;
+ case OpCode_vsindexcs:
+ {
+ unsigned int ivs;
+ if (unlikely (!env.argStack.check_pop_uint (ivs))) return false;
+ env.set_ivs (ivs);
+ env.clear_stack ();
+ }
+ break;
+ default:
+ typedef CSOpSet<CFF2Subrs, PARAM> SUPER;
+ if (unlikely (!SUPER::process_op (op, env, param)))
+ return false;
+ break;
+ }
+ return true;
+ }
+};
+
+template <typename OPSET, typename PARAM>
+struct CFF2CSInterpreter : CSInterpreter<CFF2CSInterpEnv, OPSET, PARAM> {};
+
+} /* namespace CFF */
+
+#endif /* HB_CFF2_INTERP_CS_HH */
diff --git a/src/hb-ot-cff-common-private.hh b/src/hb-ot-cff-common-private.hh
index e22ee87..3f9f865 100644
--- a/src/hb-ot-cff-common-private.hh
+++ b/src/hb-ot-cff-common-private.hh
@@ -557,6 +557,8 @@
inline bool serialize (hb_serialize_context_t *c, const Subrs<COUNT> &subrs, unsigned int offSize, const hb_set_t *set, const ByteStr& nullStr = ByteStr())
{
TRACE_SERIALIZE (this);
+ if (&subrs == &Null(Subrs<COUNT>))
+ return_trace (true);
if ((subrs.count == 0) || (hb_set_get_population (set) == 0))
{
if (!unlikely (c->allocate_size<COUNT> (COUNT::static_size)))
@@ -580,6 +582,8 @@
/* in parallel to above */
inline unsigned int calculate_serialized_size (unsigned int &offSize /*OUT*/, const hb_set_t *set, unsigned int nullStrSize = 0) const
{
+ if (this == &Null(Subrs<COUNT>))
+ return 0;
unsigned int count_ = CFFIndex<COUNT>::count;
offSize = 0;
if ((count_ == 0) || (hb_set_get_population (set) == 0))
diff --git a/src/hb-ot-cff2-table.hh b/src/hb-ot-cff2-table.hh
index f5d356d..da4acf4 100644
--- a/src/hb-ot-cff2-table.hh
+++ b/src/hb-ot-cff2-table.hh
@@ -318,6 +318,7 @@
return false;
env.argStack.clear ();
break;
+ case OpCode_vsindexdict:
case OpCode_blenddict:
// XXX: TODO
return true;
@@ -442,10 +443,11 @@
if (num_glyphs != sc.get_num_glyphs ())
{ fini (); return; }
- privateDicts.resize (fdArray->count);
+ fdCount = fdArray->count;
+ privateDicts.resize (fdCount);
/* parse font dicts and gather private dicts */
- for (unsigned int i = 0; i < fdArray->count; i++)
+ for (unsigned int i = 0; i < fdCount; i++)
{
const ByteStr fontDictStr = (*fdArray)[i];
if (unlikely (!fontDictStr.sanitize (&sc))) { fini (); return; }
@@ -500,6 +502,7 @@
const CFF2CharStrings *charStrings;
const CFF2FDArray *fdArray;
const CFF2FDSelect *fdSelect;
+ unsigned int fdCount;
hb_vector_t<CFF2FontDictValues> fontDicts;
hb_vector_t<PrivDictVal> privateDicts;
diff --git a/src/hb-subset-cff1.cc b/src/hb-subset-cff1.cc
index 5e54349..921b1df 100644
--- a/src/hb-subset-cff1.cc
+++ b/src/hb-subset-cff1.cc
@@ -555,6 +555,7 @@
}
}
+ assert (c.head == c.end);
c.end_serialize ();
return true;
diff --git a/src/hb-subset-cff2.cc b/src/hb-subset-cff2.cc
index 7835523..ab876c9 100644
--- a/src/hb-subset-cff2.cc
+++ b/src/hb-subset-cff2.cc
@@ -30,6 +30,7 @@
#include "hb-subset-cff2.hh"
#include "hb-subset-plan.hh"
#include "hb-subset-cff-common-private.hh"
+#include "hb-cff2-interp-cs.hh"
using namespace CFF;
@@ -37,6 +38,12 @@
inline CFF2SubTableOffsets (void)
{
memset (this, 0, sizeof(*this));
+ localSubrsInfos.init ();
+ }
+
+ inline ~CFF2SubTableOffsets (void)
+ {
+ localSubrsInfos.fini ();
}
unsigned int topDictSize;
@@ -45,6 +52,8 @@
TableInfo FDArrayInfo;
TableInfo charStringsInfo;
unsigned int privateDictsOffset;
+ TableInfo globalSubrsInfo;
+ hb_vector_t<TableInfo> localSubrsInfos;
};
struct CFF2TopDict_OpSerializer : OpSerializer
@@ -157,6 +166,31 @@
}
};
+struct CFF2CSOpSet_SubrSubset : CFF2CSOpSet<SubrRefMapPair>
+{
+ static inline bool process_op (OpCode op, CFF2CSInterpEnv &env, SubrRefMapPair& refMapPair)
+ {
+ unsigned int subr_num;
+ switch (op) {
+ case OpCode_callsubr:
+ if (!unlikely (env.popSubrNum(env.localSubrs, subr_num)))
+ return false;
+ env.argStack.unpop ();
+ refMapPair.local_map->add (subr_num);
+ break;
+ case OpCode_callgsubr:
+ if (!unlikely (env.popSubrNum(env.globalSubrs, subr_num)))
+ return false;
+ env.argStack.unpop ();
+ refMapPair.global_map->add (subr_num);
+ break;
+ default:
+ break;
+ }
+ return CFF2CSOpSet<SubrRefMapPair>::process_op (op, env, refMapPair);
+ }
+};
+
struct cff2_subset_plan {
inline cff2_subset_plan (void)
: final_size (0),
@@ -176,6 +210,7 @@
fdmap.fini ();
subset_charstrings.fini ();
privateDictInfos.fini ();
+ subrRefMaps.fini ();
}
inline bool create (const OT::cff2::accelerator_subset_t &acc,
@@ -194,8 +229,22 @@
final_size += offsets.topDictSize;
}
+ /* Subset global & local subrs */
+ {
+ SubrSubsetter<const OT::cff2::accelerator_subset_t, CFF2CSInterpEnv, CFF2CSOpSet_SubrSubset> subsetter(acc, plan->glyphs);
+ if (!subsetter.collect_refs (subrRefMaps))
+ return false;
+
+ offsets.globalSubrsInfo.size = acc.globalSubrs->calculate_serialized_size (offsets.globalSubrsInfo.offSize, subrRefMaps.global_map);
+ if (!offsets.localSubrsInfos.resize (orig_fdcount))
+ return false;
+ for (unsigned int i = 0; i < orig_fdcount; i++)
+ offsets.localSubrsInfos[i].size = acc.privateDicts[i].localSubrs->calculate_serialized_size (offsets.localSubrsInfos[i].offSize, subrRefMaps.local_maps[i]);
+ }
+
/* global subrs */
- final_size += acc.globalSubrs->get_size ();
+ offsets.globalSubrsInfo.offset = final_size;
+ final_size += offsets.globalSubrsInfo.size;
/* variation store */
if (acc.varStore != &Null(CFF2VariationStore))
@@ -253,7 +302,7 @@
CFF2PrivateDict_OpSerializer privSzr;
TableInfo privInfo = { final_size, PrivateDict::calculate_serialized_size (acc.privateDicts[i], privSzr), 0 };
privateDictInfos.push (privInfo);
- final_size += privInfo.size + acc.privateDicts[i].localSubrs->get_size ();
+ final_size += privInfo.size + offsets.localSubrsInfos[i].size;
}
}
@@ -275,6 +324,8 @@
hb_vector_t<ByteStr> subset_charstrings;
hb_vector_t<TableInfo> privateDictInfos;
+
+ SubrRefMaps subrRefMaps;
};
static inline bool _write_cff2 (const cff2_subset_plan &plan,
@@ -312,8 +363,7 @@
assert (cff2->topDict + plan.offsets.topDictSize == c.head - c.start);
CFF2Subrs *dest = c.start_embed<CFF2Subrs> ();
if (unlikely (dest == nullptr)) return false;
- CFFIndex<HBUINT32> *super = dest;
- if (unlikely (!super->serialize (&c, *acc.globalSubrs)))
+ if (unlikely (!dest->serialize (&c, *acc.globalSubrs, plan.offsets.globalSubrsInfo.offSize, plan.subrRefMaps.global_map)))
{
DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 global subrs");
return false;
@@ -409,8 +459,7 @@
DEBUG_MSG (SUBSET, nullptr, "CFF2 subset: local subrs unexpectedly null [%d]", i);
return false;
}
- CFFIndex<HBUINT32> *super = subrs;
- if (unlikely (!super->serialize (&c, *acc.privateDicts[i].localSubrs)))
+ if (unlikely (!subrs->serialize (&c, *acc.privateDicts[i].localSubrs, plan.offsets.localSubrsInfos[i].offSize, plan.subrRefMaps.local_maps[i])))
{
DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 local subrs [%d]", i);
return false;
@@ -419,6 +468,7 @@
}
}
+ assert (c.head == c.end);
c.end_serialize ();
return true;