diff --git a/src/hb-ot-cff-common-private.hh b/src/hb-ot-cff-common-private.hh index 4384703aa..9e89b4ec5 100644 --- a/src/hb-ot-cff-common-private.hh +++ b/src/hb-ot-cff-common-private.hh @@ -289,6 +289,7 @@ struct Index inline const unsigned int offset_at (unsigned int index) const { + assert (index <= count); const HBUINT8 *p = offsets + offSize * index; unsigned int size = offSize; unsigned int offset = 0; @@ -317,7 +318,12 @@ struct Index inline unsigned int get_size (void) const { if (this != &Null(Index)) - return count.static_size + offSize.static_size + offset_array_size () + (offset_at (count) - 1); + { + if (count > 0) + return min_size + offset_array_size () + (offset_at (count) - 1); + else + return count.static_size; /* empty Index contains count only */ + } else return 0; } diff --git a/src/hb-ot-cff2-table.hh b/src/hb-ot-cff2-table.hh index 9447a9d59..22125798f 100644 --- a/src/hb-ot-cff2-table.hh +++ b/src/hb-ot-cff2-table.hh @@ -212,41 +212,17 @@ struct CFF2FontDictOpSet } }; -struct CFF2PrivateDictValues : DictValues +struct CFF2PrivateDictValues_Base : DictValues { inline void init (void) { DictValues::init (); - - languageGroup = 0; - expansionFactor = 0.06f; - vsIndex = 0; subrsOffset.set (0); - blueScale = 0.039625f; - blueShift = 7.0f; - 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 (void) { - blueValues.fini (); - otherBlues.fini (); - familyBlues.fini (); - familyOtherBlues.fini (); - stemSnapH.fini (); - stemSnapV.fini (); - DictValues::fini (); } @@ -261,10 +237,48 @@ struct CFF2PrivateDictValues : DictValues return size; } + LOffsetTo subrsOffset; + const Subrs *localSubrs; +}; + +struct CFF2PrivateDictValues : CFF2PrivateDictValues_Base +{ + inline void init (void) + { + CFF2PrivateDictValues_Base::init (); + + languageGroup = 0; + expansionFactor = 0.06f; + vsIndex = 0; + blueScale = 0.039625f; + blueShift = 7.0f; + 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 (); + } + + inline void fini (void) + { + blueValues.fini (); + otherBlues.fini (); + familyBlues.fini (); + familyOtherBlues.fini (); + stemSnapH.fini (); + stemSnapV.fini (); + + CFF2PrivateDictValues_Base::fini (); + } + int languageGroup; float expansionFactor; int vsIndex; - OffsetTo subrsOffset; float blueScale; float blueShift; float blueFuzz; @@ -276,8 +290,6 @@ struct CFF2PrivateDictValues : DictValues hb_vector_t familyOtherBlues; hb_vector_t stemSnapH; hb_vector_t stemSnapV; - - const Subrs *localSubrs; }; struct CFF2PrivateDictOpSet @@ -368,6 +380,56 @@ struct CFF2PrivateDictOpSet } }; +struct CFF2PrivateDictOpSet_Subset +{ + static inline bool process_op (const ByteStr& str, unsigned int& offset, OpCode op, Stack& stack, CFF2PrivateDictValues_Base& val) + { + switch (op) { + case OpCode_BlueValues: + case OpCode_OtherBlues: + case OpCode_FamilyBlues: + case OpCode_FamilyOtherBlues: + case OpCode_StdHW: + case OpCode_StdVW: + case OpCode_BlueScale: + case OpCode_BlueShift: + case OpCode_BlueFuzz: + case OpCode_StemSnapH: + case OpCode_StemSnapV: + case OpCode_LanguageGroup: + case OpCode_ExpansionFactor: + case OpCode_blend: + stack.clear (); + break; + + case OpCode_BCD: + { + float v; + return parse_bcd (str, offset, v); + } + + case OpCode_Subrs: + if (unlikely (!check_pop_offset (stack, val.subrsOffset))) + return false; + break; + case OpCode_longint: /* 5-byte integer */ + if (unlikely (!str.check_limit (offset, 5) || !stack.check_overflow (1))) + return false; + stack.push_int ((int32_t)((str[offset + 1] << 24) | (str[offset + 2] << 16) || (str[offset + 3] << 8) || str[offset + 4])); + offset += 4; + break; + + default: + return false; + } + + if (op != OpCode_blend) + val.pushOpStr (op, str, offset + 1); + + return true; + } +}; + typedef Interpreter CFF2TopDict_Interpreter; typedef Interpreter CFF2FontDict_Interpreter; typedef Interpreter CFF2PrivateDict_Interpreter; @@ -389,7 +451,8 @@ struct cff2 likely (version.major == 2)); } - struct accelerator_t + template + struct accelerator_templ_t { inline void init (hb_face_t *face) { @@ -402,7 +465,7 @@ struct cff2 sc.init (this->blob); sc.start_processing (); - const OT::cff2 *cff2 = this->blob->as (); + const OT::cff2 *cff2 = this->blob->template as (); if (cff2 == &Null(OT::cff2)) { @@ -460,7 +523,7 @@ struct cff2 } const ByteStr privDictStr (font->privateDictOffset (cff2), font->privateDictSize); - CFF2PrivateDict_Interpreter priv_interp; + Interpreter priv_interp; if (unlikely (!privDictStr.sanitize (&sc) || !priv_interp.interpret (privDictStr, privateDicts[i]))) { @@ -468,7 +531,12 @@ struct cff2 return; } - privateDicts[i].localSubrs = &privateDicts[i].subrsOffset (cff2); + privateDicts[i].localSubrs = &privateDicts[i].subrsOffset (privDictStr.str); + if (unlikely (!privateDicts[i].localSubrs->sanitize (&sc))) + { + fini (); + return; + } } } @@ -506,11 +574,14 @@ struct cff2 const FDSelect *fdSelect; hb_vector_t fontDicts; - hb_vector_t privateDicts; + hb_vector_t privateDicts; unsigned int num_glyphs; }; + typedef accelerator_templ_t accelerator_t; + typedef accelerator_templ_t accelerator_subset_t; + inline bool subset (hb_subset_plan_t *plan) const { hb_blob_t *cff2_prime = nullptr; diff --git a/src/hb-subset-cff2.cc b/src/hb-subset-cff2.cc index a0244c15a..6bf397c31 100644 --- a/src/hb-subset-cff2.cc +++ b/src/hb-subset-cff2.cc @@ -156,7 +156,7 @@ struct subset_plan { private_off_and_size_pairs.fini (); } - inline bool create (const OT::cff2::accelerator_t &acc, + inline bool create (const OT::cff2::accelerator_subset_t &acc, hb_subset_plan_t *plan) { final_size = 0; @@ -233,7 +233,7 @@ struct subset_plan { }; static inline bool _write_cff2 (const subset_plan &plan, - const OT::cff2::accelerator_t &acc, + const OT::cff2::accelerator_subset_t &acc, unsigned int dest_sz, void *dest) { @@ -329,14 +329,15 @@ static inline bool _write_cff2 (const subset_plan &plan, PrivateDict *pd = c.start_embed (); if (unlikely (pd == nullptr)) return false; CFF2PrivateDict_OpSerializer privSzr; - if (unlikely (!pd->serialize (&c, acc.privateDicts[i], privSzr, acc.privateDicts[i].subrsOffset))) + /* N.B. local subrs immediately follows its corresponding private dict. i.e., subr offset == private dict size */ + if (unlikely (!pd->serialize (&c, acc.privateDicts[i], privSzr, plan.private_off_and_size_pairs[i].size))) { DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 Private Dict[%d]", i); return false; } if (acc.privateDicts[i].subrsOffset != 0) { - Subrs *subrs = c.allocate_size (acc.privateDicts[i].localSubrs->get_size ()); + Subrs *subrs = c.start_embed (); if (unlikely (subrs == nullptr) || acc.privateDicts[i].localSubrs == &Null(Subrs)) { DEBUG_MSG (SUBSET, nullptr, "CFF2 subset: local subrs unexpectedly null [%d]", i); @@ -356,7 +357,7 @@ static inline bool _write_cff2 (const subset_plan &plan, } static bool -_hb_subset_cff2 (const OT::cff2::accelerator_t &acc, +_hb_subset_cff2 (const OT::cff2::accelerator_subset_t &acc, const char *data, hb_subset_plan_t *plan, hb_blob_t **prime /* OUT */) @@ -400,7 +401,7 @@ hb_subset_cff2 (hb_subset_plan_t *plan, hb_blob_t *cff2_blob = hb_sanitize_context_t().reference_table (plan->source); const char *data = hb_blob_get_data(cff2_blob, nullptr); - OT::cff2::accelerator_t acc; + OT::cff2::accelerator_subset_t acc; acc.init(plan->source); bool result = likely (acc.is_valid ()) && _hb_subset_cff2 (acc,