From aca73c9df2054f62cf10a5c27bc5fa7823747f8b Mon Sep 17 00:00:00 2001 From: Michiharu Ariza Date: Thu, 6 Sep 2018 17:28:15 -0700 Subject: [PATCH] subset CFF1 Encoding & Charset fixed misc Charset bugs added source file hb-ot-cff1.table.cc renamed things for clarity & consistency --- src/Makefile.sources | 1 + src/hb-cff-interp-dict-common.hh | 15 +- src/hb-ot-cff-common.hh | 34 +-- src/hb-ot-cff1-table.cc | 130 ++++++++++ src/hb-ot-cff1-table.hh | 403 +++++++++++++++++++++++++------ src/hb-ot-cff2-table.hh | 24 +- src/hb-subset-cff1.cc | 247 ++++++++++++++++--- src/hb-subset-cff2.cc | 30 +-- 8 files changed, 737 insertions(+), 147 deletions(-) create mode 100644 src/hb-ot-cff1-table.cc diff --git a/src/Makefile.sources b/src/Makefile.sources index 9c64c3c08..a4cf4bc68 100644 --- a/src/Makefile.sources +++ b/src/Makefile.sources @@ -27,6 +27,7 @@ HB_BASE_sources = \ hb-ot-cmap-table.hh \ hb-ot-glyf-table.hh \ hb-ot-cff1-table.hh \ + hb-ot-cff1-table.cc \ hb-ot-cff2-table.hh \ hb-ot-hdmx-table.hh \ hb-ot-head-table.hh \ diff --git a/src/hb-cff-interp-dict-common.hh b/src/hb-cff-interp-dict-common.hh index 38918578c..1badbaaf7 100644 --- a/src/hb-cff-interp-dict-common.hh +++ b/src/hb-cff-interp-dict-common.hh @@ -66,7 +66,7 @@ struct DictValues values.fini (); } - inline void pushVal (OpCode op, const SubByteStr& substr) + inline void addOp (OpCode op, const SubByteStr& substr = SubByteStr ()) { VAL *val = values.push (); val->op = op; @@ -74,7 +74,7 @@ struct DictValues opStart = substr.offset; } - inline void pushVal (OpCode op, const SubByteStr& substr, const VAL &v) + inline void addOp (OpCode op, const SubByteStr& substr, const VAL &v) { VAL *val = values.push (v); val->op = op; @@ -82,6 +82,17 @@ struct DictValues opStart = substr.offset; } + inline bool hasOp (OpCode op) const + { + for (unsigned int i = 0; i < getNumValues (); i++) + if (getValue (i).op == op) return true; + return false; + } + + inline unsigned getNumValues (void) const { return values.len; } + inline const VAL &getValue (unsigned int i) const { return values[i]; } + inline const VAL &operator [] (unsigned int i) const { return getValue (i); } + unsigned int opStart; hb_vector_t values; }; diff --git a/src/hb-ot-cff-common.hh b/src/hb-ot-cff-common.hh index 3aa1c34da..f948f5dfd 100644 --- a/src/hb-ot-cff-common.hh +++ b/src/hb-ot-cff-common.hh @@ -192,7 +192,7 @@ struct CFFIndex }; template -struct IndexOf : CFFIndex +struct CFFIndexOf : CFFIndex { inline const ByteStr operator [] (unsigned int index) const { @@ -204,7 +204,8 @@ struct IndexOf : CFFIndex template inline bool serialize (hb_serialize_context_t *c, unsigned int offSize_, - const hb_vector_t &dataArray, + const DATA *dataArray, + unsigned int dataArrayLen, const hb_vector_t &dataSizeArray, const PARAM1 ¶m1, const PARAM2 ¶m2) @@ -212,15 +213,15 @@ struct IndexOf : CFFIndex TRACE_SERIALIZE (this); /* serialize CFFIndex header */ if (unlikely (!c->extend_min (*this))) return_trace (false); - this->count.set (dataArray.len); + this->count.set (dataArrayLen); this->offSize.set (offSize_); - if (!unlikely (c->allocate_size (offSize_ * (dataArray.len + 1)))) + if (!unlikely (c->allocate_size (offSize_ * (dataArrayLen + 1)))) return_trace (false); /* serialize indices */ unsigned int offset = 1; unsigned int i = 0; - for (; i < dataArray.len; i++) + for (; i < dataArrayLen; i++) { CFFIndex::set_offset_at (i, offset); offset += dataSizeArray[i]; @@ -228,7 +229,7 @@ struct IndexOf : CFFIndex CFFIndex::set_offset_at (i, offset); /* serialize data */ - for (unsigned int i = 0; i < dataArray.len; i++) + for (unsigned int i = 0; i < dataArrayLen; i++) { TYPE *dest = c->start_embed (); if (unlikely (dest == nullptr || @@ -241,13 +242,14 @@ struct IndexOf : CFFIndex /* in parallel to above */ template inline static unsigned int calculate_serialized_size (unsigned int &offSize_ /* OUT */, - const hb_vector_t &dataArray, + const DATA *dataArray, + unsigned int dataArrayLen, hb_vector_t &dataSizeArray, /* OUT */ const PARAM ¶m) { /* determine offset size */ unsigned int totalDataSize = 0; - for (unsigned int i = 0; i < dataArray.len; i++) + for (unsigned int i = 0; i < dataArrayLen; i++) { unsigned int dataSize = TYPE::calculate_serialized_size (dataArray[i], param); dataSizeArray[i] = dataSize; @@ -255,7 +257,7 @@ struct IndexOf : CFFIndex } offSize_ = calcOffSize (totalDataSize); - return CFFIndex::calculate_serialized_size (offSize_, dataArray.len, totalDataSize); + return CFFIndex::calculate_serialized_size (offSize_, dataArrayLen, totalDataSize); } }; @@ -269,9 +271,9 @@ struct Dict : UnsizedByteStr PARAM& param) { TRACE_SERIALIZE (this); - for (unsigned int i = 0; i < dictval.values.len; i++) + for (unsigned int i = 0; i < dictval.getNumValues (); i++) { - if (unlikely (!opszr.serialize (c, dictval.values[i], param))) + if (unlikely (!opszr.serialize (c, dictval[i], param))) return_trace (false); } return_trace (true); @@ -283,8 +285,8 @@ struct Dict : UnsizedByteStr OP_SERIALIZER& opszr) { unsigned int size = 0; - for (unsigned int i = 0; i < dictval.values.len; i++) - size += opszr.calculate_serialized_size (dictval.values[i]); + for (unsigned int i = 0; i < dictval.getNumValues (); i++) + size += opszr.calculate_serialized_size (dictval[i]); return size; } @@ -368,7 +370,7 @@ struct FDMap : hb_vector_t }; template -struct FDArray : IndexOf +struct FDArray : CFFIndexOf { template inline bool serialize (hb_serialize_context_t *c, @@ -392,10 +394,10 @@ struct FDArray : IndexOf for (unsigned i = 0; i < fontDicts.len; i++) if (!fdmap.excludes (i)) { - IndexOf::set_offset_at (fid++, offset); + CFFIndexOf::set_offset_at (fid++, offset); offset += FontDict::calculate_serialized_size (fontDicts[i], opszr); } - IndexOf::set_offset_at (fid, offset); + CFFIndexOf::set_offset_at (fid, offset); /* serialize font dicts */ for (unsigned int i = 0; i < fontDicts.len; i++) diff --git a/src/hb-ot-cff1-table.cc b/src/hb-ot-cff1-table.cc new file mode 100644 index 000000000..9ac2f1590 --- /dev/null +++ b/src/hb-ot-cff1-table.cc @@ -0,0 +1,130 @@ +/* + * 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 + */ + +#include "hb-ot-cff1-table.hh" + +/* SID to code */ +static const uint8_t standard_encoding [] = +{ + 0, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, + 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, + 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, + 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, + 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, + 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 177, + 178, 179, 180, 182, 183, 184, 185, 186, 187, 188, 189, 191, 193, 194, 195, 196, + 197, 198, 199, 200, 202, 203, 205, 206, 207, 208, 225, 227, 232, 233, 234, 235, + 241, 245, 248, 249, 250, 251 +}; + +/* SID to code */ +static const uint8_t expert_encoding [] = +{ + 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 45, 46, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 58, 59, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 87, 88, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 201, 0, 0, 0, 0, 189, 0, 0, 188, 0, + 0, 0, 0, 190, 202, 0, 0, 0, 0, 203, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 33, 34, 36, 37, 38, 39, 40, 41, 42, 43, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, 60, 61, 62, 63, 65, 66, 67, + 68, 69, 73, 76, 77, 78, 79, 82, 83, 84, 86, 89, 90, 91, 93, 94, + 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, + 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, + 161, 162, 163, 166, 167, 168, 169, 170, 172, 175, 178, 179, 182, 183, 184, 191, + 192, 193, 194, 195, 196, 197, 200, 204, 205, 206, 207, 208, 209, 210, 211, 212, + 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, + 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, + 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255 +}; + +/* glyph ID to SID */ +static const uint16_t expert_charset [] = +{ + 0, 1, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 13, 14, 15, 99, + 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 27, 28, 249, 250, 251, 252, + 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 109, 110, + 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, + 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, + 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, + 315, 316, 317, 318, 158, 155, 163, 319, 320, 321, 322, 323, 324, 325, 326, 150, + 164, 169, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, + 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, + 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, + 373, 374, 375, 376, 377, 378 +}; + +/* glyph ID to SID */ +static const uint16_t expert_subset_charset [] = +{ + 0, 1, 231, 232, 235, 236, 237, 238, 13, 14, 15, 99, 239, 240, 241, 242, + 243, 244, 245, 246, 247, 248, 27, 28, 249, 250, 251, 253, 254, 255, 256, 257, + 258, 259, 260, 261, 262, 263, 264, 265, 266, 109, 110, 267, 268, 269, 270, 272, + 300, 301, 302, 305, 314, 315, 158, 155, 163, 320, 321, 322, 323, 324, 325, 326, + 150, 164, 169, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, + 340, 341, 342, 343, 344, 345, 346 +}; + +hb_codepoint_t OT::cff1::lookup_standard_encoding (hb_codepoint_t sid) +{ + if (sid < ARRAY_LENGTH (standard_encoding)) + return (hb_codepoint_t)standard_encoding[sid]; + else + return 0; +} + +hb_codepoint_t OT::cff1::lookup_expert_encoding (hb_codepoint_t sid) +{ + if (sid < ARRAY_LENGTH (expert_encoding)) + return (hb_codepoint_t)expert_encoding[sid]; + else + return 0; +} + +hb_codepoint_t OT::cff1::lookup_expert_charset (hb_codepoint_t glyph) +{ + if (glyph < ARRAY_LENGTH (expert_charset)) + return (hb_codepoint_t)expert_charset[glyph]; + else + return 0; +} + +hb_codepoint_t OT::cff1::lookup_expert_subset_charset (hb_codepoint_t glyph) +{ + if (glyph < ARRAY_LENGTH (expert_subset_charset)) + return (hb_codepoint_t)expert_subset_charset[glyph]; + else + return 0; +} diff --git a/src/hb-ot-cff1-table.hh b/src/hb-ot-cff1-table.hh index ebb89c159..f5eba464d 100644 --- a/src/hb-ot-cff1-table.hh +++ b/src/hb-ot-cff1-table.hh @@ -38,8 +38,13 @@ namespace CFF { */ #define HB_OT_TAG_cff1 HB_TAG('C','F','F',' ') +#define CFF_UNDEF_CODE 0xFFFFFFFF + +enum EncodingID { StandardEncoding = 0, ExpertEncoding = 1 }; +enum CharsetID { ISOAdobeCharset = 0, ExpertCharset = 1, ExpertSubsetCharset = 2 }; + typedef CFFIndex CFF1Index; -template struct CFF1IndexOf : IndexOf {}; +template struct CFF1IndexOf : CFFIndexOf {}; typedef CFFIndex CFF1Index; typedef CFF1Index CFF1CharStrings; @@ -56,15 +61,14 @@ struct Encoding0 { return_trace (c->check_struct (this) && codes[nCodes - 1].sanitize (c)); } - inline bool get_code (hb_codepoint_t glyph, hb_codepoint_t &code) const + inline hb_codepoint_t get_code (hb_codepoint_t glyph) const { if (glyph < nCodes) { - code = (hb_codepoint_t)codes[glyph]; - return true; + return (hb_codepoint_t)codes[glyph]; } else - return false; + return CFF_UNDEF_CODE; } inline unsigned int get_size (void) const @@ -99,19 +103,17 @@ struct Encoding1 { return_trace (c->check_struct (this) && ((nRanges == 0) || (ranges[nRanges - 1]).sanitize (c))); } - inline bool get_code (hb_codepoint_t glyph, hb_codepoint_t &code) const + inline hb_codepoint_t get_code (hb_codepoint_t glyph) const { for (unsigned int i = 0; i < nRanges; i++) { if (glyph <= ranges[i].nLeft) { - code = (hb_codepoint_t)ranges[i].first + glyph; - return true; + return (hb_codepoint_t)ranges[i].first + glyph; } glyph -= (ranges[i].nLeft + 1); } - - return false; + return CFF_UNDEF_CODE; } HBUINT8 nRanges; @@ -120,7 +122,7 @@ struct Encoding1 { DEFINE_SIZE_ARRAY (1, ranges); }; -struct EncSupplement { +struct SuppEncoding { inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -140,27 +142,28 @@ struct CFF1SuppEncData { return_trace (c->check_struct (this) && ((nSups == 0) || (supps[nSups - 1]).sanitize (c))); } - inline bool get_code (hb_codepoint_t glyph, hb_codepoint_t &code) const + inline void get_codes (hb_codepoint_t sid, hb_vector_t &codes) const { for (unsigned int i = 0; i < nSups; i++) - if (glyph == supps[i].glyph) - { - code = supps[i].code; - return true; - } - - return false; + if (sid == supps[i].glyph) + codes.push (supps[i].code); } inline unsigned int get_size (void) const - { return HBUINT8::static_size + EncSupplement::static_size * nSups; } + { return HBUINT8::static_size + SuppEncoding::static_size * nSups; } HBUINT8 nSups; - EncSupplement supps[VAR]; + SuppEncoding supps[VAR]; DEFINE_SIZE_ARRAY (1, supps); }; +struct code_pair +{ + hb_codepoint_t code; + hb_codepoint_t glyph; +}; + struct Encoding { inline bool sanitize (hb_sanitize_context_t *c) const { @@ -176,7 +179,8 @@ struct Encoding { return_trace (((format & 0x80) == 0) || suppEncData ().sanitize (c)); } - inline bool serialize (hb_serialize_context_t *c, const Encoding &src, unsigned int num_glyphs) + /* serialize a fullset Encoding */ + inline bool serialize (hb_serialize_context_t *c, const Encoding &src) { TRACE_SERIALIZE (this); unsigned int size = src.get_size (); @@ -186,27 +190,104 @@ struct Encoding { return_trace (true); } - inline unsigned int calculate_serialized_size (void) const - { return get_size (); } // XXX: TODO + /* serialize a subset Encoding */ + inline bool serialize (hb_serialize_context_t *c, + uint8_t format, + unsigned int enc_count, + const hb_vector_t& code_ranges, + const hb_vector_t& supp_codes) + { + TRACE_SERIALIZE (this); + Encoding *dest = c->extend_min (*this); + if (unlikely (dest == nullptr)) return_trace (false); + dest->format.set (format | ((supp_codes.len > 0)? 0x80: 0)); + if (format == 0) + { + Encoding0 *fmt0 = c->allocate_size (Encoding0::min_size + HBUINT8::static_size * enc_count); + if (unlikely (fmt0 == nullptr)) return_trace (false); + fmt0->nCodes.set (enc_count); + unsigned int glyph = 0; + for (unsigned int i = 0; i < code_ranges.len; i++) + { + hb_codepoint_t code = code_ranges[i].code; + for (int left = (int)code_ranges[i].glyph; left >= 0; left--) + fmt0->codes[glyph++].set (code++); + assert ((glyph <= 0x100) && (code <= 0x100)); + } + } + else + { + Encoding1 *fmt1 = c->allocate_size (Encoding1::min_size + Encoding1_Range::static_size * code_ranges.len); + if (unlikely (fmt1 == nullptr)) return_trace (false); + fmt1->nRanges.set (code_ranges.len); + for (unsigned int i = 0; i < code_ranges.len; i++) + { + assert ((code_ranges[i].code <= 0xFF) && (code_ranges[i].glyph <= 0xFF)); + fmt1->ranges[i].first.set (code_ranges[i].code); + fmt1->ranges[i].nLeft.set (code_ranges[i].glyph); + } + } + if (supp_codes.len > 0) + { + CFF1SuppEncData *suppData = c->allocate_size (CFF1SuppEncData::min_size + SuppEncoding::static_size * supp_codes.len); + if (unlikely (suppData == nullptr)) return_trace (false); + suppData->nSups.set (supp_codes.len); + for (unsigned int i = 0; i < supp_codes.len; i++) + { + suppData->supps[i].code.set (supp_codes[i].code); + suppData->supps[i].glyph.set (supp_codes[i].glyph); /* actually SID */ + } + } + return_trace (true); + } + + /* parallel to above: calculate the size of a subset Encoding */ + static inline unsigned int calculate_serialized_size ( + uint8_t format, + unsigned int enc_count, + unsigned int supp_count) + { + unsigned int size = min_size; + if (format == 0) + size += Encoding0::min_size + HBUINT8::static_size * enc_count; + else + size += Encoding1::min_size + Encoding1_Range::static_size * enc_count; + if (supp_count > 0) + size += CFF1SuppEncData::min_size + SuppEncoding::static_size * supp_count; + return size; + } inline unsigned int get_size (void) const { unsigned int size = min_size; - if ((format & 0x7F) == 0) + if (table_format () == 0) size += u.format0.get_size (); else size += u.format1.get_size (); - if ((format & 0x80) != 0) + if (has_supplement ()) size += suppEncData ().get_size (); return size; } - inline bool get_code (hb_codepoint_t glyph, hb_codepoint_t &code) const + inline hb_codepoint_t get_code (hb_codepoint_t glyph) const { - // XXX: TODO - return false; + if (table_format () == 0) + return u.format0.get_code (glyph); + else + return u.format1.get_code (glyph); } + inline uint8_t table_format (void) const { return (format & 0x7F); } + inline bool has_supplement (void) const { return (format & 0x80) != 0; } + + inline void get_supplement_codes (hb_codepoint_t sid, hb_vector_t &codes) const + { + codes.resize (0); + if (has_supplement ()) + suppEncData().get_codes (sid, codes); + } + + protected: inline const CFF1SuppEncData &suppEncData (void) const { if ((format & 0x7F) == 0) @@ -215,7 +296,9 @@ struct Encoding { return StructAfter (u.format1.ranges[u.format1.nRanges-1]); } + public: HBUINT8 format; + union { Encoding0 format0; Encoding1 format1; @@ -233,7 +316,7 @@ struct Charset0 { return_trace (c->check_struct (this) && sids[num_glyphs - 1].sanitize (c)); } - inline unsigned int get_sid (hb_codepoint_t glyph) + inline hb_codepoint_t get_sid (hb_codepoint_t glyph) const { if (glyph == 0) return 0; @@ -260,44 +343,69 @@ struct Charset_Range { return_trace (c->check_struct (this)); } - HBUINT8 first; + HBUINT16 first; TYPE nLeft; - DEFINE_SIZE_STATIC (1 + TYPE::static_size); + DEFINE_SIZE_STATIC (HBUINT16::static_size + TYPE::static_size); }; template struct Charset1_2 { - inline bool sanitize (hb_sanitize_context_t *c) const + inline bool sanitize (hb_sanitize_context_t *c, unsigned int num_glyphs) const { TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && ((nRanges == 0) || (ranges[nRanges - 1]).sanitize (c))); + if (unlikely (!c->check_struct (this))) + return_trace (false); + num_glyphs--; + for (unsigned int i = 0; num_glyphs > 0; i++) + { + if (unlikely (!ranges[i].sanitize (c) || (num_glyphs < ranges[i].nLeft + 1))) + return_trace (false); + num_glyphs -= (ranges[i].nLeft + 1); + } + return_trace (true); } - inline bool get_sid (hb_codepoint_t glyph, unsigned int &sid) const + inline hb_codepoint_t get_sid (hb_codepoint_t glyph) const { - for (unsigned int i = 0; i < nRanges; i++) + if (glyph == 0) return 0; + glyph--; + for (unsigned int i = 0;; i++) { if (glyph <= ranges[i].nLeft) - { - sid = (hb_codepoint_t)ranges[i].first + glyph; - return true; - } + return (hb_codepoint_t)ranges[i].first + glyph; glyph -= (ranges[i].nLeft + 1); } - return false; + return 0; } - inline unsigned int get_size (void) const - { return HBUINT8::static_size + Charset_Range::static_size * nRanges; } + inline unsigned int get_size (unsigned int num_glyphs) const + { + unsigned int size = HBUINT8::static_size; + int glyph = (int)num_glyphs; + + assert (glyph > 0); + glyph--; + for (unsigned int i = 0; glyph > 0; i++) + { + glyph -= (ranges[i].nLeft + 1); + size += Charset_Range::static_size; + } + + return size; + } - HBUINT8 nRanges; Charset_Range ranges[VAR]; - DEFINE_SIZE_ARRAY (1, ranges); + DEFINE_SIZE_ARRAY (0, ranges); }; +typedef Charset1_2 Charset1; +typedef Charset1_2 Charset2; +typedef Charset_Range Charset1_Range; +typedef Charset_Range Charset2_Range; + struct Charset { inline bool sanitize (hb_sanitize_context_t *c) const { @@ -308,13 +416,14 @@ struct Charset { if (format == 0) return_trace (u.format0.sanitize (c, c->get_num_glyphs ())); else if (format == 1) - return_trace (u.format1.sanitize (c)); + return_trace (u.format1.sanitize (c, c->get_num_glyphs ())); else if (likely (format == 2)) - return_trace (u.format2.sanitize (c)); + return_trace (u.format2.sanitize (c, c->get_num_glyphs ())); else return_trace (false); } + /* serialize a fullset Charset */ inline bool serialize (hb_serialize_context_t *c, const Charset &src, unsigned int num_glyphs) { TRACE_SERIALIZE (this); @@ -325,8 +434,68 @@ struct Charset { return_trace (true); } - inline unsigned int calculate_serialized_size (unsigned int num_glyphs) const - { return get_size (num_glyphs); } // XXX: TODO + /* serialize a subset Charset */ + inline bool serialize (hb_serialize_context_t *c, + uint8_t format, + unsigned int num_glyphs, + const hb_vector_t& sid_ranges) + { + TRACE_SERIALIZE (this); + Charset *dest = c->extend_min (*this); + if (unlikely (dest == nullptr)) return_trace (false); + dest->format.set (format); + if (format == 0) + { + Charset0 *fmt0 = c->allocate_size (Charset0::min_size + HBUINT8::static_size * (num_glyphs - 1)); + if (unlikely (fmt0 == nullptr)) return_trace (false); + unsigned int glyph = 0; + for (unsigned int i = 0; i < sid_ranges.len; i++) + { + hb_codepoint_t sid = sid_ranges[i].code; + for (int left = (int)sid_ranges[i].glyph; left >= 0; left--) + fmt0->sids[glyph++].set (sid++); + } + } + else if (format == 1) + { + Charset1 *fmt1 = c->allocate_size (Charset1::min_size + Charset1_Range::static_size * sid_ranges.len); + if (unlikely (fmt1 == nullptr)) return_trace (false); + for (unsigned int i = 0; i < sid_ranges.len; i++) + { + assert (sid_ranges[i].glyph <= 0xFF); + fmt1->ranges[i].first.set (sid_ranges[i].code); + fmt1->ranges[i].nLeft.set (sid_ranges[i].glyph); + } + } + else /* format 2 */ + { + Charset2 *fmt2 = c->allocate_size (Charset2::min_size + Charset2_Range::static_size * sid_ranges.len); + if (unlikely (fmt2 == nullptr)) return_trace (false); + for (unsigned int i = 0; i < sid_ranges.len; i++) + { + assert (sid_ranges[i].glyph <= 0xFFFF); + fmt2->ranges[i].first.set (sid_ranges[i].code); + fmt2->ranges[i].nLeft.set (sid_ranges[i].glyph); + } + } + return_trace (true); + } + + /* parallel to above: calculate the size of a subset Charset */ + static inline unsigned int calculate_serialized_size ( + uint8_t format, + unsigned int count) + { + unsigned int size = min_size; + if (format == 0) + size += Charset0::min_size + HBUINT8::static_size * (count - 1); + else if (format == 1) + size += Charset1::min_size + Charset1_Range::static_size * count; + else + size += Charset2::min_size + Charset2_Range::static_size * count; + + return size; + } inline unsigned int get_size (unsigned int num_glyphs) const { @@ -334,23 +503,27 @@ struct Charset { if (format == 0) size += u.format0.get_size (num_glyphs); else if (format == 1) - size += u.format1.get_size (); + size += u.format1.get_size (num_glyphs); else - size += u.format2.get_size (); + size += u.format2.get_size (num_glyphs); return size; } - inline bool get_sid (hb_codepoint_t glyph, unsigned int &sid) const + inline hb_codepoint_t get_sid (hb_codepoint_t glyph) const { - // XXX: TODO - return false; + if (format == 0) + return u.format0.get_sid (glyph); + else if (format == 1) + return u.format1.get_sid (glyph); + else + return u.format2.get_sid (glyph); } HBUINT8 format; union { - Charset0 format0; - Charset1_2 format1; - Charset1_2 format2; + Charset0 format0; + Charset1 format1; + Charset2 format2; } u; DEFINE_SIZE_MIN (1); @@ -381,16 +554,16 @@ struct CFF1TopDictValues : TopDictValues inline unsigned int calculate_serialized_size (void) const { unsigned int size = 0; - for (unsigned int i = 0; i < values.len; i++) + for (unsigned int i = 0; i < getNumValues (); i++) { - OpCode op = values[i].op; + OpCode op = getValue (i).op; switch (op) { case OpCode_FDSelect: size += OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (op); break; default: - size += TopDictValues::calculate_serialized_op_size (values[i]); + size += TopDictValues::calculate_serialized_op_size (getValue (i)); break; } } @@ -400,13 +573,44 @@ struct CFF1TopDictValues : TopDictValues unsigned int ros[3]; /* registry, ordering, supplement */ unsigned int cidCount; - enum EncodingID { StandardEncoding = 0, ExpertEncoding = 1 }; unsigned int EncodingOffset; unsigned int CharsetOffset; unsigned int FDSelectOffset; TableInfo privateDictInfo; }; +/* a copy of a parsed out CFF1TopDictValues augmented with additional operators */ +struct CFF1TopDictValuesMod : CFF1TopDictValues +{ + inline void init (const CFF1TopDictValues *base_= &Null(CFF1TopDictValues)) + { + SUPER::init (); + base = base_; + } + + inline void fini (void) + { + SUPER::fini (); + } + + inline unsigned getNumValues (void) const + { + return base->getNumValues () + SUPER::getNumValues (); + } + inline const OpStr &getValue (unsigned int i) const + { + if (i < base->getNumValues ()) + return (*base)[i]; + else + return SUPER::values[i - base->getNumValues ()]; + } + inline const OpStr &operator [] (unsigned int i) const { return getValue (i); } + + protected: + typedef CFF1TopDictValues SUPER; + const CFF1TopDictValues *base; +}; + struct CFF1TopDictOpSet : TopDictOpSet { static inline bool process_op (OpCode op, NumInterpEnv& env, CFF1TopDictValues& dictval) @@ -488,7 +692,7 @@ struct CFF1TopDictOpSet : TopDictOpSet break; } - dictval.pushVal (op, env.substr); + dictval.addOp (op, env.substr); return true; } }; @@ -534,7 +738,7 @@ struct CFF1FontDictOpSet : DictOpSet break; } - dictval.pushVal (op, env.substr); + dictval.addOp (op, env.substr); return true; } }; @@ -557,11 +761,11 @@ struct CFF1PrivateDictValues_Base : DictValues inline unsigned int calculate_serialized_size (void) const { unsigned int size = 0; - for (unsigned int i = 0; i < DictValues::values.len; i++) - if (DictValues::values[i].op == OpCode_Subrs) + for (unsigned int i = 0; i < DictValues::getNumValues; i++) + if (DictValues::getValue (i).op == OpCode_Subrs) size += OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_Subrs); else - size += DictValues::values[i].str.len; + size += DictValues::getValue (i).str.len; return size; } @@ -617,7 +821,7 @@ struct CFF1PrivateDictOpSet : DictOpSet break; } - dictval.pushVal (op, env.substr, val); + dictval.addOp (op, env.substr, val); return true; } }; @@ -660,7 +864,7 @@ struct CFF1PrivateDictOpSet_Subset : DictOpSet break; } - dictval.pushVal (op, env.substr); + dictval.addOp (op, env.substr); return true; } }; @@ -730,6 +934,8 @@ struct cff1 encoding = &Null(Encoding); charset = &StructAtOffsetOrNull (cff, topDicts[0].CharsetOffset); + if (unlikely (is_CID () && (charset == &Null(Charset)))) + { fini (); return; } fdCount = 1; if (is_CID ()) @@ -746,8 +952,7 @@ struct cff1 { fdArray = &Null(CFF1FDArray); fdSelect = &Null(CFF1FDSelect); - if (topDicts[0].EncodingOffset != CFF1TopDictValues::StandardEncoding && - topDicts[0].EncodingOffset != CFF1TopDictValues::ExpertEncoding) + if (!is_predef_encoding ()) { encoding = &StructAtOffsetOrNull (cff, topDicts[0].EncodingOffset); if ((encoding == &Null (Encoding)) || !encoding->sanitize (&sc)) @@ -833,6 +1038,58 @@ struct cff1 inline bool is_valid (void) const { return blob != nullptr; } inline bool is_CID (void) const { return topDicts[0].is_CID (); } + inline bool is_predef_encoding (void) const { return topDicts[0].EncodingOffset <= ExpertEncoding; } + inline bool is_predef_charset (void) const { return topDicts[0].CharsetOffset <= ExpertSubsetCharset; } + + inline hb_codepoint_t glyph_to_code (hb_codepoint_t glyph) const + { + if (encoding != &Null(Encoding)) + return encoding->get_code (glyph); + else + { + hb_codepoint_t sid = glyph_to_sid (glyph); + if (sid == 0) return 0; + hb_codepoint_t code = 0; + switch (topDicts[0].EncodingOffset) + { + case StandardEncoding: + code = lookup_standard_encoding (sid); + break; + case ExpertEncoding: + code = lookup_expert_encoding (sid); + break; + default: + break; + } + return code; + } + } + + inline hb_codepoint_t glyph_to_sid (hb_codepoint_t glyph) const + { + if (charset != &Null(Charset)) + return charset->get_sid (glyph); + else + { + hb_codepoint_t sid = 0; + switch (topDicts[0].CharsetOffset) + { + case ISOAdobeCharset: + if (glyph <= 228 /*zcaron*/) sid = glyph; + break; + case ExpertCharset: + sid = lookup_expert_charset (glyph); + break; + case ExpertSubsetCharset: + sid = lookup_expert_subset_charset (glyph); + break; + default: + break; + } + return sid; + } + } + inline bool get_extents (hb_codepoint_t glyph, hb_glyph_extents_t *extents) const { @@ -884,6 +1141,12 @@ struct cff1 return success; } + protected: + static hb_codepoint_t lookup_standard_encoding (hb_codepoint_t sid); + static hb_codepoint_t lookup_expert_encoding (hb_codepoint_t sid); + static hb_codepoint_t lookup_expert_charset (hb_codepoint_t glyph); + static hb_codepoint_t lookup_expert_subset_charset (hb_codepoint_t glyph); + public: FixedVersion version; /* Version of CFF table. set to 0x0100u */ OffsetTo nameIndex; /* headerSize = Offset to Name INDEX. */ diff --git a/src/hb-ot-cff2-table.hh b/src/hb-ot-cff2-table.hh index 9e07f305f..19e480211 100644 --- a/src/hb-ot-cff2-table.hh +++ b/src/hb-ot-cff2-table.hh @@ -39,7 +39,7 @@ namespace CFF { #define HB_OT_TAG_cff2 HB_TAG('C','F','F','2') typedef CFFIndex CFF2Index; -template struct CFF2IndexOf : IndexOf {}; +template struct CFF2IndexOf : CFFIndexOf {}; typedef CFF2Index CFF2CharStrings; typedef FDArray CFF2FDArray; @@ -152,9 +152,9 @@ struct CFF2TopDictValues : TopDictValues inline unsigned int calculate_serialized_size (void) const { unsigned int size = 0; - for (unsigned int i = 0; i < values.len; i++) + for (unsigned int i = 0; i < getNumValues (); i++) { - OpCode op = values[i].op; + OpCode op = getValue (i).op; switch (op) { case OpCode_vstore: @@ -162,7 +162,7 @@ struct CFF2TopDictValues : TopDictValues size += OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (op); break; default: - size += TopDictValues::calculate_serialized_op_size (values[i]); + size += TopDictValues::calculate_serialized_op_size (getValue (i)); break; } } @@ -182,7 +182,7 @@ struct CFF2TopDictOpSet : TopDictOpSet { DictVal val; val.init (); - dictval.pushVal (op, env.substr); + dictval.addOp (op, env.substr); env.clear_args (); } break; @@ -205,7 +205,7 @@ struct CFF2TopDictOpSet : TopDictOpSet if (!env.argStack.is_empty ()) return true; } - dictval.pushVal (op, env.substr); + dictval.addOp (op, env.substr); return true; } @@ -248,7 +248,7 @@ struct CFF2FontDictOpSet : DictOpSet return true; } - dictval.pushVal (op, env.substr); + dictval.addOp (op, env.substr); return true; } @@ -275,11 +275,11 @@ struct CFF2PrivateDictValues_Base : DictValues inline unsigned int calculate_serialized_size (void) const { unsigned int size = 0; - for (unsigned int i = 0; i < DictValues::values.len; i++) - if (DictValues::values[i].op == OpCode_Subrs) + for (unsigned int i = 0; i < DictValues::getNumValues; i++) + if (DictValues::getValue (i).op == OpCode_Subrs) size += OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_Subrs); else - size += DictValues::values[i].str.len; + size += DictValues::getValue (i).str.len; return size; } @@ -339,7 +339,7 @@ struct CFF2PrivateDictOpSet : DictOpSet break; } - dictval.pushVal (op, env.substr, val); + dictval.addOp (op, env.substr, val); return true; } }; @@ -382,7 +382,7 @@ struct CFF2PrivateDictOpSet_Subset : DictOpSet break; } - dictval.pushVal (op, env.substr); + dictval.addOp (op, env.substr); return true; } diff --git a/src/hb-subset-cff1.cc b/src/hb-subset-cff1.cc index 932699be0..c637be677 100644 --- a/src/hb-subset-cff1.cc +++ b/src/hb-subset-cff1.cc @@ -186,54 +186,214 @@ struct cff_subset_plan { inline cff_subset_plan (void) : final_size (0), orig_fdcount (0), - subst_fdcount (1), - subst_fdselect_format (0), + subset_fdcount (1), + subset_fdselect_format (0), offsets (), flatten_subrs (true), drop_hints (false) { topdict_sizes.init (); topdict_sizes.resize (1); - subst_fdselect_first_glyphs.init (); + topdict_mod.init (); + subset_fdselect_first_glyphs.init (); fdmap.init (); subset_charstrings.init (); flat_charstrings.init (); privateDictInfos.init (); subrRefMaps.init (); + subset_enc_code_ranges.init (); + subset_enc_supp_codes.init (); + subset_charset_ranges.init (); } inline ~cff_subset_plan (void) { topdict_sizes.fini (); - subst_fdselect_first_glyphs.fini (); + topdict_mod.fini (); + subset_fdselect_first_glyphs.fini (); fdmap.fini (); subset_charstrings.fini (); flat_charstrings.fini (); privateDictInfos.fini (); subrRefMaps.fini (); + subset_enc_code_ranges.fini (); + subset_enc_supp_codes.init (); + subset_charset_ranges.fini (); + } + + inline unsigned int plan_subset_encoding (const OT::cff1::accelerator_subset_t &acc, hb_subset_plan_t *plan) + { + const Encoding *encoding = acc.encoding; + unsigned int size0, size1, supp_size; + hb_codepoint_t code, last_code = CFF_UNDEF_CODE; + hb_vector_t supp_codes; + + subset_enc_code_ranges.resize (0); + supp_size = 0; + supp_codes.init (); + + subset_enc_num_codes = plan->glyphs.len - 1; + unsigned int glyph; + for (glyph = 1; glyph < plan->glyphs.len; glyph++) + { + hb_codepoint_t orig_glyph = plan->glyphs[glyph]; + code = acc.glyph_to_code (orig_glyph); + if (code == CFF_UNDEF_CODE) + { + subset_enc_num_codes = glyph - 1; + break; + } + + if (code != last_code + 1) + { + if (subset_enc_code_ranges.len > 0) + { + code_pair &pair = subset_enc_code_ranges[subset_enc_code_ranges.len - 1]; + pair.glyph = glyph - pair.glyph - 1; + } + code_pair pair = { code, glyph }; + subset_enc_code_ranges.push (pair); + } + last_code = code; + + if (encoding != &Null(Encoding)) + { + hb_codepoint_t sid = acc.glyph_to_sid (orig_glyph); + encoding->get_supplement_codes (sid, supp_codes); + for (unsigned int i = 0; i < supp_codes.len; i++) + { + code_pair pair = { supp_codes[i], sid }; + subset_enc_supp_codes.push (pair); + } + supp_size += SuppEncoding::static_size * supp_codes.len; + } + } + supp_codes.fini (); + if (subset_enc_code_ranges.len > 0) + { + code_pair &pair = subset_enc_code_ranges[subset_enc_code_ranges.len - 1]; + pair.glyph = glyph - pair.glyph - 1; + } + + assert (subset_enc_num_codes <= 0xFF); + size0 = Encoding0::min_size + HBUINT8::static_size * subset_enc_num_codes; + size1 = Encoding1::min_size + Encoding1_Range::static_size * subset_enc_code_ranges.len; + + if (size0 < size1) + subset_enc_format = 0; + else + subset_enc_format = 1; + + return Encoding::calculate_serialized_size ( + subset_enc_format, + subset_enc_format? subset_enc_code_ranges.len: subset_enc_num_codes, + subset_enc_supp_codes.len); + } + + inline unsigned int plan_subset_charset (const OT::cff1::accelerator_subset_t &acc, hb_subset_plan_t *plan) + { + const Charset *charset = acc.charset; + unsigned int size0, size_ranges; + hb_codepoint_t sid, last_sid = CFF_UNDEF_CODE; + bool two_byte = false; + + subset_charset_ranges.resize (0); + unsigned int glyph; + for (glyph = 1; glyph < plan->glyphs.len; glyph++) + { + hb_codepoint_t orig_glyph = plan->glyphs[glyph]; + sid = acc.glyph_to_sid (orig_glyph); + + if (sid != last_sid + 1) + { + if (subset_charset_ranges.len > 0) + { + code_pair &pair = subset_charset_ranges[subset_charset_ranges.len - 1]; + pair.glyph = glyph - pair.glyph - 1; + if ((pair.glyph & ~0xFF) != 0) two_byte = true; + } + code_pair pair = { sid, glyph }; + subset_charset_ranges.push (pair); + } + last_sid = sid; + } + + if (subset_charset_ranges.len > 0) + { + code_pair &pair = subset_charset_ranges[subset_charset_ranges.len - 1]; + pair.glyph = glyph - pair.glyph - 1; + if ((pair.glyph & ~0xFF) != 0) two_byte = true; + } + + size0 = Charset0::min_size + HBUINT16::static_size * (plan->glyphs.len - 1); + if (!two_byte) + size_ranges = Charset1::min_size + Charset1_Range::static_size * subset_charset_ranges.len; + else + size_ranges = Charset2::min_size + Charset2_Range::static_size * subset_charset_ranges.len; + + if (size0 < size_ranges) + subset_charset_format = 0; + else if (!two_byte) + subset_charset_format = 1; + else + subset_charset_format = 2; + + return Charset::calculate_serialized_size ( + subset_charset_format, + subset_charset_format? subset_charset_ranges.len: plan->glyphs.len); } inline bool create (const OT::cff1::accelerator_subset_t &acc, hb_subset_plan_t *plan) { + /* make sure notdef is first */ + if ((plan->glyphs.len == 0) || (plan->glyphs[0] != 0)) return false; + final_size = 0; + num_glyphs = plan->glyphs.len; orig_fdcount = acc.fdCount; drop_hints = plan->drop_hints; + /* check whether the subset renumbers any glyph IDs */ + gid_renum = false; + for (unsigned int glyph = 0; glyph < plan->glyphs.len; glyph++) + { + if (plan->glyphs[glyph] != glyph) { + gid_renum = true; + break; + } + } + + subset_charset = gid_renum || !acc.is_predef_charset (); + subset_encoding = !acc.is_CID() && (gid_renum || !acc.is_predef_encoding ()); + /* CFF header */ final_size += OT::cff1::static_size; /* Name INDEX */ offsets.nameIndexOffset = final_size; final_size += acc.nameIndex->get_size (); - + /* top dict INDEX */ { + /* Add encoding/charset to a (copy of) top dict as necessary */ + topdict_mod.init (&acc.topDicts[0]); + bool need_to_add_enc = (subset_encoding && !acc.topDicts[0].hasOp (OpCode_Encoding)); + bool need_to_add_set = (subset_charset && !acc.topDicts[0].hasOp (OpCode_charset)); + if (need_to_add_enc || need_to_add_set) + { + if (need_to_add_enc) + topdict_mod.addOp (OpCode_Encoding); + if (need_to_add_set) + topdict_mod.addOp (OpCode_charset); + } offsets.topDictInfo.offset = final_size; CFF1TopDict_OpSerializer topSzr; - unsigned int topDictSize = TopDict::calculate_serialized_size (acc.topDicts[0], topSzr); + unsigned int topDictSize = TopDict::calculate_serialized_size (topdict_mod, topSzr); offsets.topDictInfo.offSize = calcOffSize(topDictSize); - final_size += CFF1IndexOf::calculate_serialized_size (offsets.topDictInfo.offSize, acc.topDicts, topdict_sizes, topSzr); + final_size += CFF1IndexOf::calculate_serialized_size + (offsets.topDictInfo.offSize, + &topdict_mod, 1, topdict_sizes, topSzr); } /* String INDEX */ @@ -270,13 +430,13 @@ struct cff_subset_plan { /* Encoding */ offsets.encodingOffset = final_size; - if (acc.encoding != &Null(Encoding)) - final_size += acc.encoding->get_size (); + if (subset_encoding) + final_size += plan_subset_encoding (acc, plan); /* Charset */ offsets.charsetOffset = final_size; - if (acc.charset != &Null(Charset)) - final_size += acc.charset->get_size (acc.num_glyphs); + if (subset_charset) + final_size += plan_subset_charset (acc, plan); /* FDSelect */ if (acc.fdSelect != &Null(CFF1FDSelect)) @@ -285,10 +445,10 @@ struct cff_subset_plan { if (unlikely (!hb_plan_subset_cff_fdselect (plan->glyphs, orig_fdcount, *acc.fdSelect, - subst_fdcount, + subset_fdcount, offsets.FDSelectInfo.size, - subst_fdselect_format, - subst_fdselect_first_glyphs, + subset_fdselect_format, + subset_fdselect_first_glyphs, fdmap))) return false; @@ -301,7 +461,7 @@ struct cff_subset_plan { if (acc.fdArray != &Null(CFF1FDArray)) { offsets.FDArrayInfo.offset = final_size; CFFFontDict_OpSerializer fontSzr; - final_size += CFF1FDArray::calculate_serialized_size(offsets.FDArrayInfo.offSize/*OUT*/, acc.fontDicts, subst_fdcount, fdmap, fontSzr); + final_size += CFF1FDArray::calculate_serialized_size(offsets.FDArrayInfo.offSize/*OUT*/, acc.fontDicts, subset_fdcount, fdmap, fontSzr); } /* CharStrings */ @@ -349,20 +509,22 @@ struct cff_subset_plan { offsets.privateDictInfo = privateDictInfos[0]; return ((subset_charstrings.len == plan->glyphs.len) && - (privateDictInfos.len == subst_fdcount)); + (privateDictInfos.len == subset_fdcount)); } inline unsigned int get_final_size (void) const { return final_size; } - unsigned int final_size; + unsigned int final_size; hb_vector_t topdict_sizes; - CFF1SubTableOffsets offsets; + CFF1TopDictValuesMod topdict_mod; + CFF1SubTableOffsets offsets; + unsigned int num_glyphs; unsigned int orig_fdcount; - unsigned int subst_fdcount; - inline bool is_fds_subsetted (void) const { return subst_fdcount < orig_fdcount; } - unsigned int subst_fdselect_format; - hb_vector_t subst_fdselect_first_glyphs; + unsigned int subset_fdcount; + inline bool is_fds_subsetted (void) const { return subset_fdcount < orig_fdcount; } + unsigned int subset_fdselect_format; + hb_vector_t subset_fdselect_first_glyphs; /* font dict index remap table from fullset FDArray to subset FDArray. * set to HB_SET_VALUE_INVALID if excluded from subset */ @@ -374,8 +536,19 @@ struct cff_subset_plan { SubrRefMaps subrRefMaps; - bool flatten_subrs; - bool drop_hints; + bool flatten_subrs; + bool drop_hints; + + bool gid_renum; + bool subset_encoding; + uint8_t subset_enc_format; + unsigned int subset_enc_num_codes; + hb_vector_t subset_enc_code_ranges; + hb_vector_t subset_enc_supp_codes; + + uint8_t subset_charset_format; + hb_vector_t subset_charset_ranges; + bool subset_charset; }; static inline bool _write_cff1 (const cff_subset_plan &plan, @@ -417,7 +590,9 @@ static inline bool _write_cff1 (const cff_subset_plan &plan, CFF1IndexOf *dest = c.start_embed< CFF1IndexOf > (); if (dest == nullptr) return false; CFF1TopDict_OpSerializer topSzr; - if (unlikely (!dest->serialize (&c, plan.offsets.topDictInfo.offSize, acc.topDicts, plan.topdict_sizes, topSzr, plan.offsets))) + if (unlikely (!dest->serialize (&c, plan.offsets.topDictInfo.offSize, + &plan.topdict_mod, 1, + plan.topdict_sizes, topSzr, plan.offsets))) { DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF top dict"); return false; @@ -450,11 +625,16 @@ static inline bool _write_cff1 (const cff_subset_plan &plan, } /* Encoding */ - if (acc.encoding != &Null(Encoding)){ + if (plan.subset_encoding) + { assert (plan.offsets.encodingOffset == c.head - c.start); Encoding *dest = c.start_embed (); if (unlikely (dest == nullptr)) return false; - if (unlikely (!dest->serialize (&c, *acc.encoding, acc.num_glyphs))) // XXX: TODO + if (unlikely (!dest->serialize (&c, + plan.subset_enc_format, + plan.subset_enc_num_codes, + plan.subset_enc_code_ranges, + plan.subset_enc_supp_codes))) { DEBUG_MSG (SUBSET, nullptr, "failed to serialize Encoding"); return false; @@ -462,12 +642,15 @@ static inline bool _write_cff1 (const cff_subset_plan &plan, } /* Charset */ - if (acc.charset != &Null(Charset)) + if (plan.subset_charset) { assert (plan.offsets.charsetOffset == c.head - c.start); Charset *dest = c.start_embed (); if (unlikely (dest == nullptr)) return false; - if (unlikely (!dest->serialize (&c, *acc.charset, acc.num_glyphs))) // XXX: TODO + if (unlikely (!dest->serialize (&c, + plan.subset_charset_format, + plan.num_glyphs, + plan.subset_charset_ranges))) { DEBUG_MSG (SUBSET, nullptr, "failed to serialize Charset"); return false; @@ -482,8 +665,8 @@ static inline bool _write_cff1 (const cff_subset_plan &plan, if (plan.is_fds_subsetted ()) { if (unlikely (!hb_serialize_cff_fdselect (&c, glyphs, *acc.fdSelect, acc.fdCount, - plan.subst_fdselect_format, plan.offsets.FDSelectInfo.size, - plan.subst_fdselect_first_glyphs, + plan.subset_fdselect_format, plan.offsets.FDSelectInfo.size, + plan.subset_fdselect_first_glyphs, plan.fdmap))) { DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF subset FDSelect"); @@ -509,7 +692,7 @@ static inline bool _write_cff1 (const cff_subset_plan &plan, if (unlikely (fda == nullptr)) return false; CFFFontDict_OpSerializer fontSzr; if (unlikely (!fda->serialize (&c, plan.offsets.FDArrayInfo.offSize, - acc.fontDicts, plan.subst_fdcount, plan.fdmap, + acc.fontDicts, plan.subset_fdcount, plan.fdmap, fontSzr, plan.privateDictInfos))) { DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF FDArray"); diff --git a/src/hb-subset-cff2.cc b/src/hb-subset-cff2.cc index e00fda580..391304a65 100644 --- a/src/hb-subset-cff2.cc +++ b/src/hb-subset-cff2.cc @@ -197,12 +197,12 @@ struct cff2_subset_plan { inline cff2_subset_plan (void) : final_size (0), orig_fdcount (0), - subst_fdcount(1), - subst_fdselect_format (0), + subset_fdcount(1), + subset_fdselect_format (0), flatten_subrs (true), drop_hints (false) { - subst_fdselect_first_glyphs.init (); + subset_fdselect_first_glyphs.init (); fdmap.init (); subset_charstrings.init (); flat_charstrings.init (); @@ -212,7 +212,7 @@ struct cff2_subset_plan { inline ~cff2_subset_plan (void) { - subst_fdselect_first_glyphs.fini (); + subset_fdselect_first_glyphs.fini (); fdmap.fini (); subset_charstrings.fini (); flat_charstrings.fini (); @@ -281,10 +281,10 @@ struct cff2_subset_plan { if (unlikely (!hb_plan_subset_cff_fdselect (plan->glyphs, orig_fdcount, *(const FDSelect *)acc.fdSelect, - subst_fdcount, + subset_fdcount, offsets.FDSelectInfo.size, - subst_fdselect_format, - subst_fdselect_first_glyphs, + subset_fdselect_format, + subset_fdselect_first_glyphs, fdmap))) return false; @@ -297,7 +297,7 @@ struct cff2_subset_plan { { offsets.FDArrayInfo.offset = final_size; CFFFontDict_OpSerializer fontSzr; - final_size += CFF2FDArray::calculate_serialized_size(offsets.FDArrayInfo.offSize/*OUT*/, acc.fontDicts, subst_fdcount, fdmap, fontSzr); + final_size += CFF2FDArray::calculate_serialized_size(offsets.FDArrayInfo.offSize/*OUT*/, acc.fontDicts, subset_fdcount, fdmap, fontSzr); } /* CharStrings */ @@ -350,10 +350,10 @@ struct cff2_subset_plan { CFF2SubTableOffsets offsets; unsigned int orig_fdcount; - unsigned int subst_fdcount; - inline bool is_fds_subsetted (void) const { return subst_fdcount < orig_fdcount; } - unsigned int subst_fdselect_format; - hb_vector_t subst_fdselect_first_glyphs; + unsigned int subset_fdcount; + inline bool is_fds_subsetted (void) const { return subset_fdcount < orig_fdcount; } + unsigned int subset_fdselect_format; + hb_vector_t subset_fdselect_first_glyphs; FDMap fdmap; @@ -429,8 +429,8 @@ static inline bool _write_cff2 (const cff2_subset_plan &plan, if (plan.is_fds_subsetted ()) { if (unlikely (!hb_serialize_cff_fdselect (&c, glyphs, *(const FDSelect *)acc.fdSelect, acc.fdArray->count, - plan.subst_fdselect_format, plan.offsets.FDSelectInfo.size, - plan.subst_fdselect_first_glyphs, + plan.subset_fdselect_format, plan.offsets.FDSelectInfo.size, + plan.subset_fdselect_first_glyphs, plan.fdmap))) { DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 subset FDSelect"); @@ -455,7 +455,7 @@ static inline bool _write_cff2 (const cff2_subset_plan &plan, if (unlikely (fda == nullptr)) return false; CFFFontDict_OpSerializer fontSzr; if (unlikely (!fda->serialize (&c, plan.offsets.FDArrayInfo.offSize, - acc.fontDicts, plan.subst_fdcount, plan.fdmap, + acc.fontDicts, plan.subset_fdcount, plan.fdmap, fontSzr, plan.privateDictInfos))) { DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 FDArray");