|
|
|
@ -64,22 +64,18 @@ struct remap_sid_t : hb_inc_bimap_t |
|
|
|
|
static unsigned int unoffset_sid (unsigned int sid) { return sid - num_std_strings; } |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
struct cff1_sub_table_offsets_t : cff_sub_table_offsets_t |
|
|
|
|
struct cff1_sub_table_info_t : cff_sub_table_info_t |
|
|
|
|
{ |
|
|
|
|
cff1_sub_table_offsets_t () |
|
|
|
|
: cff_sub_table_offsets_t (), |
|
|
|
|
nameIndexOffset (0), |
|
|
|
|
encodingOffset (0) |
|
|
|
|
{ |
|
|
|
|
stringIndexInfo.init (); |
|
|
|
|
charsetInfo.init (); |
|
|
|
|
cff1_sub_table_info_t () |
|
|
|
|
: cff_sub_table_info_t (), |
|
|
|
|
encoding_link (0), |
|
|
|
|
charset_link (0) |
|
|
|
|
{ |
|
|
|
|
privateDictInfo.init (); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
unsigned int nameIndexOffset; |
|
|
|
|
table_info_t stringIndexInfo; |
|
|
|
|
unsigned int encodingOffset; |
|
|
|
|
table_info_t charsetInfo; |
|
|
|
|
objidx_t encoding_link; |
|
|
|
|
objidx_t charset_link; |
|
|
|
|
table_info_t privateDictInfo; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
@ -117,13 +113,13 @@ struct cff1_top_dict_values_mod_t : cff1_top_dict_values_t |
|
|
|
|
|
|
|
|
|
struct top_dict_modifiers_t |
|
|
|
|
{ |
|
|
|
|
top_dict_modifiers_t (const cff1_sub_table_offsets_t &offsets_, |
|
|
|
|
top_dict_modifiers_t (const cff1_sub_table_info_t &info_, |
|
|
|
|
const unsigned int (&nameSIDs_)[name_dict_values_t::ValCount]) |
|
|
|
|
: offsets (offsets_), |
|
|
|
|
: info (info_), |
|
|
|
|
nameSIDs (nameSIDs_) |
|
|
|
|
{} |
|
|
|
|
|
|
|
|
|
const cff1_sub_table_offsets_t &offsets; |
|
|
|
|
const cff1_sub_table_info_t &info; |
|
|
|
|
const unsigned int (&nameSIDs)[name_dict_values_t::ValCount]; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
@ -139,22 +135,20 @@ struct cff1_top_dict_op_serializer_t : cff_top_dict_op_serializer_t<cff1_top_dic |
|
|
|
|
switch (op) |
|
|
|
|
{ |
|
|
|
|
case OpCode_charset: |
|
|
|
|
return_trace (FontDict::serialize_offset4_op(c, op, mod.offsets.charsetInfo.offset)); |
|
|
|
|
if (mod.info.charset_link) |
|
|
|
|
return_trace (FontDict::serialize_link4_op(c, op, mod.info.charset_link, whence_t::Absolute)); |
|
|
|
|
else |
|
|
|
|
goto fall_back; |
|
|
|
|
|
|
|
|
|
case OpCode_Encoding: |
|
|
|
|
return_trace (FontDict::serialize_offset4_op(c, op, mod.offsets.encodingOffset)); |
|
|
|
|
if (mod.info.encoding_link) |
|
|
|
|
return_trace (FontDict::serialize_link4_op(c, op, mod.info.encoding_link, whence_t::Absolute)); |
|
|
|
|
else |
|
|
|
|
goto fall_back; |
|
|
|
|
|
|
|
|
|
case OpCode_Private: |
|
|
|
|
{ |
|
|
|
|
if (unlikely (!UnsizedByteStr::serialize_int2 (c, mod.offsets.privateDictInfo.size))) |
|
|
|
|
return_trace (false); |
|
|
|
|
if (unlikely (!UnsizedByteStr::serialize_int4 (c, mod.offsets.privateDictInfo.offset))) |
|
|
|
|
return_trace (false); |
|
|
|
|
HBUINT8 *p = c->allocate_size<HBUINT8> (1); |
|
|
|
|
if (unlikely (p == nullptr)) return_trace (false); |
|
|
|
|
*p = OpCode_Private; |
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|
return_trace (UnsizedByteStr::serialize_int2 (c, mod.info.privateDictInfo.size) && |
|
|
|
|
Dict::serialize_link4_op (c, op, mod.info.privateDictInfo.link, whence_t::Absolute)); |
|
|
|
|
|
|
|
|
|
case OpCode_version: |
|
|
|
|
case OpCode_Notice: |
|
|
|
@ -180,69 +174,20 @@ struct cff1_top_dict_op_serializer_t : cff_top_dict_op_serializer_t<cff1_top_dic |
|
|
|
|
UnsizedByteStr::serialize_int2 (c, mod.nameSIDs[name_dict_values_t::ordering]) && |
|
|
|
|
copy_opstr (c, supp_op)); |
|
|
|
|
} |
|
|
|
|
fall_back: |
|
|
|
|
default: |
|
|
|
|
return_trace (cff_top_dict_op_serializer_t<cff1_top_dict_val_t>::serialize (c, opstr, mod.offsets)); |
|
|
|
|
return_trace (cff_top_dict_op_serializer_t<cff1_top_dict_val_t>::serialize (c, opstr, mod.info)); |
|
|
|
|
} |
|
|
|
|
return_trace (true); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
unsigned int calculate_serialized_size (const cff1_top_dict_val_t &opstr) const |
|
|
|
|
{ |
|
|
|
|
op_code_t op = opstr.op; |
|
|
|
|
switch (op) |
|
|
|
|
{ |
|
|
|
|
case OpCode_charset: |
|
|
|
|
case OpCode_Encoding: |
|
|
|
|
return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (op); |
|
|
|
|
|
|
|
|
|
case OpCode_Private: |
|
|
|
|
return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_Private); |
|
|
|
|
|
|
|
|
|
case OpCode_version: |
|
|
|
|
case OpCode_Notice: |
|
|
|
|
case OpCode_Copyright: |
|
|
|
|
case OpCode_FullName: |
|
|
|
|
case OpCode_FamilyName: |
|
|
|
|
case OpCode_Weight: |
|
|
|
|
case OpCode_PostScript: |
|
|
|
|
case OpCode_BaseFontName: |
|
|
|
|
case OpCode_FontName: |
|
|
|
|
return OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (op); |
|
|
|
|
|
|
|
|
|
case OpCode_ROS: |
|
|
|
|
return ((OpCode_Size (OpCode_shortint) + 2) * 2) + (opstr.str.length - opstr.last_arg_offset)/* supplement + op */; |
|
|
|
|
|
|
|
|
|
default: |
|
|
|
|
return cff_top_dict_op_serializer_t<cff1_top_dict_val_t>::calculate_serialized_size (opstr); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
struct font_dict_values_mod_t |
|
|
|
|
{ |
|
|
|
|
void init (const cff1_font_dict_values_t *base_, |
|
|
|
|
unsigned int fontName_, |
|
|
|
|
const table_info_t &privateDictInfo_) |
|
|
|
|
{ |
|
|
|
|
base = base_; |
|
|
|
|
fontName = fontName_; |
|
|
|
|
privateDictInfo = privateDictInfo_; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
unsigned get_count () const { return base->get_count (); } |
|
|
|
|
|
|
|
|
|
const op_str_t &operator [] (unsigned int i) const { return (*base)[i]; } |
|
|
|
|
|
|
|
|
|
const cff1_font_dict_values_t *base; |
|
|
|
|
table_info_t privateDictInfo; |
|
|
|
|
unsigned int fontName; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
struct cff1_font_dict_op_serializer_t : cff_font_dict_op_serializer_t |
|
|
|
|
{ |
|
|
|
|
bool serialize (hb_serialize_context_t *c, |
|
|
|
|
const op_str_t &opstr, |
|
|
|
|
const font_dict_values_mod_t &mod) const |
|
|
|
|
const cff1_font_dict_values_mod_t &mod) const |
|
|
|
|
{ |
|
|
|
|
TRACE_SERIALIZE (this); |
|
|
|
|
|
|
|
|
@ -252,14 +197,6 @@ struct cff1_font_dict_op_serializer_t : cff_font_dict_op_serializer_t |
|
|
|
|
return_trace (SUPER::serialize (c, opstr, mod.privateDictInfo)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
unsigned int calculate_serialized_size (const op_str_t &opstr) const |
|
|
|
|
{ |
|
|
|
|
if (opstr.op == OpCode_FontName) |
|
|
|
|
return OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_FontName); |
|
|
|
|
else |
|
|
|
|
return SUPER::calculate_serialized_size (opstr); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private: |
|
|
|
|
typedef cff_font_dict_op_serializer_t SUPER; |
|
|
|
|
}; |
|
|
|
@ -425,8 +362,7 @@ struct cff1_subr_subsetter_t : subr_subsetter_t<cff1_subr_subsetter_t, CFF1Subrs |
|
|
|
|
|
|
|
|
|
struct cff_subset_plan { |
|
|
|
|
cff_subset_plan () |
|
|
|
|
: final_size (0), |
|
|
|
|
offsets (), |
|
|
|
|
: info (), |
|
|
|
|
orig_fdcount (0), |
|
|
|
|
subset_fdcount (1), |
|
|
|
|
subset_fdselect_format (0), |
|
|
|
@ -466,7 +402,7 @@ struct cff_subset_plan { |
|
|
|
|
sidmap.fini (); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
unsigned int plan_subset_encoding (const OT::cff1::accelerator_subset_t &acc, hb_subset_plan_t *plan) |
|
|
|
|
void 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; |
|
|
|
@ -525,14 +461,9 @@ struct cff_subset_plan { |
|
|
|
|
subset_enc_format = 0; |
|
|
|
|
else |
|
|
|
|
subset_enc_format = 1; |
|
|
|
|
|
|
|
|
|
return Encoding::calculate_serialized_size ( |
|
|
|
|
subset_enc_format, |
|
|
|
|
subset_enc_format? subset_enc_code_ranges.length: subset_enc_num_codes, |
|
|
|
|
subset_enc_supp_codes.length); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
unsigned int plan_subset_charset (const OT::cff1::accelerator_subset_t &acc, hb_subset_plan_t *plan) |
|
|
|
|
void plan_subset_charset (const OT::cff1::accelerator_subset_t &acc, hb_subset_plan_t *plan) |
|
|
|
|
{ |
|
|
|
|
unsigned int size0, size_ranges; |
|
|
|
|
hb_codepoint_t sid, last_sid = CFF_UNDEF_CODE; |
|
|
|
@ -574,10 +505,6 @@ struct cff_subset_plan { |
|
|
|
|
subset_charset_format = 1; |
|
|
|
|
else |
|
|
|
|
subset_charset_format = 2; |
|
|
|
|
|
|
|
|
|
return Charset::calculate_serialized_size ( |
|
|
|
|
subset_charset_format, |
|
|
|
|
subset_charset_format? subset_charset_ranges.length: plan->num_output_glyphs ()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool collect_sids_in_dicts (const OT::cff1::accelerator_subset_t &acc) |
|
|
|
@ -609,7 +536,6 @@ struct cff_subset_plan { |
|
|
|
|
hb_codepoint_t old_glyph; |
|
|
|
|
if (!plan->old_gid_for_new_gid (0, &old_glyph) || (old_glyph != 0)) return false; |
|
|
|
|
|
|
|
|
|
final_size = 0; |
|
|
|
|
num_glyphs = plan->num_output_glyphs (); |
|
|
|
|
orig_fdcount = acc.fdCount; |
|
|
|
|
drop_hints = plan->drop_hints; |
|
|
|
@ -630,13 +556,6 @@ struct cff_subset_plan { |
|
|
|
|
subset_charset = gid_renum || !acc.is_predef_charset (); |
|
|
|
|
subset_encoding = !acc.is_CID() && !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 */ |
|
|
|
@ -650,15 +569,6 @@ struct cff_subset_plan { |
|
|
|
|
if (need_to_add_set) |
|
|
|
|
topdict_mod.add_op (OpCode_charset); |
|
|
|
|
} |
|
|
|
|
offsets.topDictInfo.offset = final_size; |
|
|
|
|
cff1_top_dict_op_serializer_t topSzr; |
|
|
|
|
unsigned int topDictSize = TopDict::calculate_serialized_size (topdict_mod, topSzr); |
|
|
|
|
offsets.topDictInfo.offSize = calcOffSize(topDictSize); |
|
|
|
|
if (unlikely (offsets.topDictInfo.offSize > 4)) |
|
|
|
|
return false; |
|
|
|
|
final_size += CFF1IndexOf<TopDict>::calculate_serialized_size<cff1_top_dict_values_mod_t> |
|
|
|
|
(offsets.topDictInfo.offSize, |
|
|
|
|
&topdict_mod, 1, topdict_sizes, topSzr); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Determine re-mapping of font index as fdmap among other info */ |
|
|
|
@ -668,7 +578,7 @@ struct cff_subset_plan { |
|
|
|
|
orig_fdcount, |
|
|
|
|
*acc.fdSelect, |
|
|
|
|
subset_fdcount, |
|
|
|
|
offsets.FDSelectInfo.size, |
|
|
|
|
info.fd_select.size, |
|
|
|
|
subset_fdselect_format, |
|
|
|
|
subset_fdselect_ranges, |
|
|
|
|
fdmap))) |
|
|
|
@ -684,19 +594,12 @@ struct cff_subset_plan { |
|
|
|
|
return false; |
|
|
|
|
if (unlikely (sidmap.get_population () > 0x8000)) /* assumption: a dict won't reference that many strings */ |
|
|
|
|
return false; |
|
|
|
|
if (subset_charset) |
|
|
|
|
offsets.charsetInfo.size = plan_subset_charset (acc, plan); |
|
|
|
|
|
|
|
|
|
if (subset_charset) plan_subset_charset (acc, plan); |
|
|
|
|
|
|
|
|
|
topdict_mod.reassignSIDs (sidmap); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* String INDEX */ |
|
|
|
|
{ |
|
|
|
|
offsets.stringIndexInfo.offset = final_size; |
|
|
|
|
offsets.stringIndexInfo.size = acc.stringIndex->calculate_serialized_size (offsets.stringIndexInfo.offSize, sidmap); |
|
|
|
|
final_size += offsets.stringIndexInfo.size; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (desubroutinize) |
|
|
|
|
{ |
|
|
|
|
/* Flatten global & local subrs */ |
|
|
|
@ -704,9 +607,6 @@ struct cff_subset_plan { |
|
|
|
|
flattener(acc, plan); |
|
|
|
|
if (!flattener.flatten (subset_charstrings)) |
|
|
|
|
return false; |
|
|
|
|
|
|
|
|
|
/* no global/local subroutines */ |
|
|
|
|
offsets.globalSubrsInfo.size = CFF1Subrs::calculate_serialized_size (1, 0, 0); |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
@ -723,131 +623,49 @@ struct cff_subset_plan { |
|
|
|
|
if (!subr_subsetter.encode_globalsubrs (subset_globalsubrs)) |
|
|
|
|
return false; |
|
|
|
|
|
|
|
|
|
/* global subrs */ |
|
|
|
|
unsigned int dataSize = subset_globalsubrs.total_size (); |
|
|
|
|
offsets.globalSubrsInfo.offSize = calcOffSize (dataSize); |
|
|
|
|
if (unlikely (offsets.globalSubrsInfo.offSize > 4)) |
|
|
|
|
return false; |
|
|
|
|
offsets.globalSubrsInfo.size = CFF1Subrs::calculate_serialized_size (offsets.globalSubrsInfo.offSize, subset_globalsubrs.length, dataSize); |
|
|
|
|
|
|
|
|
|
/* local subrs */ |
|
|
|
|
if (!offsets.localSubrsInfos.resize (orig_fdcount)) |
|
|
|
|
return false; |
|
|
|
|
if (!subset_localsubrs.resize (orig_fdcount)) |
|
|
|
|
return false; |
|
|
|
|
for (unsigned int fd = 0; fd < orig_fdcount; fd++) |
|
|
|
|
{ |
|
|
|
|
subset_localsubrs[fd].init (); |
|
|
|
|
offsets.localSubrsInfos[fd].init (); |
|
|
|
|
if (fdmap.has (fd)) |
|
|
|
|
{ |
|
|
|
|
if (!subr_subsetter.encode_localsubrs (fd, subset_localsubrs[fd])) |
|
|
|
|
return false; |
|
|
|
|
|
|
|
|
|
unsigned int dataSize = subset_localsubrs[fd].total_size (); |
|
|
|
|
if (dataSize > 0) |
|
|
|
|
{ |
|
|
|
|
offsets.localSubrsInfos[fd].offset = final_size; |
|
|
|
|
offsets.localSubrsInfos[fd].offSize = calcOffSize (dataSize); |
|
|
|
|
if (unlikely (offsets.localSubrsInfos[fd].offSize > 4)) |
|
|
|
|
return false; |
|
|
|
|
offsets.localSubrsInfos[fd].size = CFF1Subrs::calculate_serialized_size (offsets.localSubrsInfos[fd].offSize, subset_localsubrs[fd].length, dataSize); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* global subrs */ |
|
|
|
|
offsets.globalSubrsInfo.offset = final_size; |
|
|
|
|
final_size += offsets.globalSubrsInfo.size; |
|
|
|
|
|
|
|
|
|
/* Encoding */ |
|
|
|
|
if (!subset_encoding) |
|
|
|
|
offsets.encodingOffset = acc.topDict.EncodingOffset; |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
offsets.encodingOffset = final_size; |
|
|
|
|
final_size += plan_subset_encoding (acc, plan); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Charset */ |
|
|
|
|
if (!subset_charset && acc.is_predef_charset ()) |
|
|
|
|
offsets.charsetInfo.offset = acc.topDict.CharsetOffset; |
|
|
|
|
else |
|
|
|
|
offsets.charsetInfo.offset = final_size; |
|
|
|
|
final_size += offsets.charsetInfo.size; |
|
|
|
|
|
|
|
|
|
/* FDSelect */ |
|
|
|
|
if (acc.fdSelect != &Null(CFF1FDSelect)) |
|
|
|
|
{ |
|
|
|
|
offsets.FDSelectInfo.offset = final_size; |
|
|
|
|
final_size += offsets.FDSelectInfo.size; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* FDArray (FDIndex) */ |
|
|
|
|
if (acc.fdArray != &Null(CFF1FDArray)) { |
|
|
|
|
offsets.FDArrayInfo.offset = final_size; |
|
|
|
|
cff1_font_dict_op_serializer_t fontSzr; |
|
|
|
|
unsigned int dictsSize = 0; |
|
|
|
|
for (unsigned int i = 0; i < acc.fontDicts.length; i++) |
|
|
|
|
if (fdmap.has (i)) |
|
|
|
|
dictsSize += FontDict::calculate_serialized_size (acc.fontDicts[i], fontSzr); |
|
|
|
|
|
|
|
|
|
offsets.FDArrayInfo.offSize = calcOffSize (dictsSize); |
|
|
|
|
if (unlikely (offsets.FDArrayInfo.offSize > 4)) |
|
|
|
|
return false; |
|
|
|
|
final_size += CFF1Index::calculate_serialized_size (offsets.FDArrayInfo.offSize, subset_fdcount, dictsSize); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* CharStrings */ |
|
|
|
|
{ |
|
|
|
|
offsets.charStringsInfo.offset = final_size; |
|
|
|
|
unsigned int dataSize = subset_charstrings.total_size (); |
|
|
|
|
offsets.charStringsInfo.offSize = calcOffSize (dataSize); |
|
|
|
|
if (unlikely (offsets.charStringsInfo.offSize > 4)) |
|
|
|
|
return false; |
|
|
|
|
final_size += CFF1CharStrings::calculate_serialized_size (offsets.charStringsInfo.offSize, plan->num_output_glyphs (), dataSize); |
|
|
|
|
} |
|
|
|
|
if (subset_encoding) |
|
|
|
|
plan_subset_encoding (acc, plan); |
|
|
|
|
|
|
|
|
|
/* private dicts & local subrs */ |
|
|
|
|
offsets.privateDictInfo.offset = final_size; |
|
|
|
|
for (unsigned int i = 0; i < orig_fdcount; i++) |
|
|
|
|
if (!acc.is_CID ()) |
|
|
|
|
fontdicts_mod.push (cff1_font_dict_values_mod_t ()); |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
if (fdmap.has (i)) |
|
|
|
|
{ |
|
|
|
|
bool has_localsubrs = offsets.localSubrsInfos[i].size > 0; |
|
|
|
|
cff_private_dict_op_serializer_t privSzr (desubroutinize, plan->drop_hints); |
|
|
|
|
unsigned int priv_size = PrivateDict::calculate_serialized_size (acc.privateDicts[i], privSzr, has_localsubrs); |
|
|
|
|
table_info_t privInfo = { final_size, priv_size, 0 }; |
|
|
|
|
font_dict_values_mod_t fontdict_mod; |
|
|
|
|
if (!acc.is_CID ()) |
|
|
|
|
fontdict_mod.init ( &Null(cff1_font_dict_values_t), CFF_UNDEF_SID, privInfo ); |
|
|
|
|
else |
|
|
|
|
fontdict_mod.init ( &acc.fontDicts[i], sidmap[acc.fontDicts[i].fontName], privInfo ); |
|
|
|
|
fontdicts_mod.push (fontdict_mod); |
|
|
|
|
final_size += privInfo.size; |
|
|
|
|
|
|
|
|
|
if (!plan->desubroutinize && has_localsubrs) |
|
|
|
|
+ hb_iter (acc.fontDicts) |
|
|
|
|
| hb_filter ([&] (const cff1_font_dict_values_t &_) |
|
|
|
|
{ return fdmap.has (&_ - &acc.fontDicts[0]); } ) |
|
|
|
|
| hb_map ([&] (const cff1_font_dict_values_t &_) |
|
|
|
|
{ |
|
|
|
|
offsets.localSubrsInfos[i].offset = final_size; |
|
|
|
|
final_size += offsets.localSubrsInfos[i].size; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
cff1_font_dict_values_mod_t mod; |
|
|
|
|
mod.init (&_, sidmap[_.fontName]); |
|
|
|
|
return mod; |
|
|
|
|
}) |
|
|
|
|
| hb_sink (fontdicts_mod) |
|
|
|
|
; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (!acc.is_CID ()) |
|
|
|
|
offsets.privateDictInfo = fontdicts_mod[0].privateDictInfo; |
|
|
|
|
|
|
|
|
|
return ((subset_charstrings.length == plan->num_output_glyphs ()) |
|
|
|
|
&& (fontdicts_mod.length == subset_fdcount)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
unsigned int get_final_size () const { return final_size; } |
|
|
|
|
|
|
|
|
|
unsigned int final_size; |
|
|
|
|
hb_vector_t<unsigned int> topdict_sizes; |
|
|
|
|
cff1_top_dict_values_mod_t topdict_mod; |
|
|
|
|
cff1_sub_table_offsets_t offsets; |
|
|
|
|
cff1_sub_table_info_t info; |
|
|
|
|
|
|
|
|
|
unsigned int num_glyphs; |
|
|
|
|
unsigned int orig_fdcount; |
|
|
|
@ -862,7 +680,7 @@ struct cff_subset_plan { |
|
|
|
|
str_buff_vec_t subset_charstrings; |
|
|
|
|
str_buff_vec_t subset_globalsubrs; |
|
|
|
|
hb_vector_t<str_buff_vec_t> subset_localsubrs; |
|
|
|
|
hb_vector_t<font_dict_values_mod_t> fontdicts_mod; |
|
|
|
|
hb_vector_t<cff1_font_dict_values_mod_t> fontdicts_mod; |
|
|
|
|
|
|
|
|
|
bool drop_hints; |
|
|
|
|
|
|
|
|
@ -883,186 +701,153 @@ struct cff_subset_plan { |
|
|
|
|
bool desubroutinize; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
static inline bool _write_cff1 (hb_serialize_context_t *c, |
|
|
|
|
const cff_subset_plan &plan, |
|
|
|
|
const OT::cff1::accelerator_subset_t &acc, |
|
|
|
|
unsigned int num_glyphs) |
|
|
|
|
static bool _serialize_cff1 (hb_serialize_context_t *c, |
|
|
|
|
cff_subset_plan &plan, |
|
|
|
|
const OT::cff1::accelerator_subset_t &acc, |
|
|
|
|
unsigned int num_glyphs) |
|
|
|
|
{ |
|
|
|
|
OT::cff1 *cff = c->allocate_min<OT::cff1> (); |
|
|
|
|
if (unlikely (!cff)) |
|
|
|
|
return false; |
|
|
|
|
|
|
|
|
|
/* header */ |
|
|
|
|
cff->version.major = 0x01; |
|
|
|
|
cff->version.minor = 0x00; |
|
|
|
|
cff->nameIndex = cff->min_size; |
|
|
|
|
cff->offSize = 4; /* unused? */ |
|
|
|
|
|
|
|
|
|
/* name INDEX */ |
|
|
|
|
/* private dicts & local subrs */ |
|
|
|
|
for (int i = (int)acc.privateDicts.length; --i >= 0 ;) |
|
|
|
|
{ |
|
|
|
|
assert (cff->nameIndex == (unsigned) (c->head - c->start)); |
|
|
|
|
CFF1NameIndex *dest = c->start_embed<CFF1NameIndex> (); |
|
|
|
|
if (unlikely (dest == nullptr)) return false; |
|
|
|
|
if (unlikely (!dest->serialize (c, *acc.nameIndex))) |
|
|
|
|
if (plan.fdmap.has (i)) |
|
|
|
|
{ |
|
|
|
|
DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF name INDEX"); |
|
|
|
|
return false; |
|
|
|
|
objidx_t subrs_link = 0; |
|
|
|
|
if (plan.subset_localsubrs[i].length > 0) |
|
|
|
|
{ |
|
|
|
|
c->push (); |
|
|
|
|
CFF1Subrs *dest = c->start_embed <CFF1Subrs> (); |
|
|
|
|
if (unlikely (dest == nullptr)) return false; |
|
|
|
|
if (unlikely (!dest->serialize (c, plan.subset_localsubrs[i]))) return false; |
|
|
|
|
subrs_link = c->pop_pack (); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
c->push (); |
|
|
|
|
PrivateDict *pd = c->start_embed<PrivateDict> (); |
|
|
|
|
if (unlikely (pd == nullptr)) return false; |
|
|
|
|
bool result; |
|
|
|
|
cff_private_dict_op_serializer_t privSzr (plan.desubroutinize, plan.drop_hints); |
|
|
|
|
/* N.B. local subrs immediately follows its corresponding private dict. i.e., subr offset == private dict size */ |
|
|
|
|
result = pd->serialize (c, acc.privateDicts[i], privSzr, subrs_link); |
|
|
|
|
if (unlikely (!result)) return false; |
|
|
|
|
unsigned fd = plan.fdmap[i]; |
|
|
|
|
plan.fontdicts_mod[fd].privateDictInfo.size = c->length (); |
|
|
|
|
plan.fontdicts_mod[fd].privateDictInfo.link = c->pop_pack (); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* top dict INDEX */ |
|
|
|
|
if (!acc.is_CID ()) |
|
|
|
|
plan.info.privateDictInfo = plan.fontdicts_mod[0].privateDictInfo; |
|
|
|
|
|
|
|
|
|
/* CharStrings */ |
|
|
|
|
{ |
|
|
|
|
assert (plan.offsets.topDictInfo.offset == (unsigned) (c->head - c->start)); |
|
|
|
|
CFF1IndexOf<TopDict> *dest = c->start_embed< CFF1IndexOf<TopDict>> (); |
|
|
|
|
if (dest == nullptr) return false; |
|
|
|
|
cff1_top_dict_op_serializer_t topSzr; |
|
|
|
|
top_dict_modifiers_t modifier (plan.offsets, plan.topDictModSIDs); |
|
|
|
|
if (unlikely (!dest->serialize (c, plan.offsets.topDictInfo.offSize, |
|
|
|
|
&plan.topdict_mod, 1, |
|
|
|
|
plan.topdict_sizes, topSzr, modifier))) |
|
|
|
|
{ |
|
|
|
|
DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF top dict"); |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
c->push (); |
|
|
|
|
CFF1CharStrings *cs = c->start_embed<CFF1CharStrings> (); |
|
|
|
|
if (unlikely (cs == nullptr)) return false; |
|
|
|
|
if (unlikely (!cs->serialize (c, plan.subset_charstrings))) return false; |
|
|
|
|
plan.info.char_strings_link = c->pop_pack (); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* String INDEX */ |
|
|
|
|
/* FDArray (FD Index) */ |
|
|
|
|
if (acc.fdArray != &Null(CFF1FDArray)) |
|
|
|
|
{ |
|
|
|
|
assert (plan.offsets.stringIndexInfo.offset == (unsigned) (c->head - c->start)); |
|
|
|
|
CFF1StringIndex *dest = c->start_embed<CFF1StringIndex> (); |
|
|
|
|
if (unlikely (dest == nullptr)) return false; |
|
|
|
|
if (unlikely (!dest->serialize (c, *acc.stringIndex, plan.offsets.stringIndexInfo.offSize, plan.sidmap))) |
|
|
|
|
{ |
|
|
|
|
DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF string INDEX"); |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
c->push (); |
|
|
|
|
CFF1FDArray *fda = c->start_embed<CFF1FDArray> (); |
|
|
|
|
if (unlikely (fda == nullptr)) return false; |
|
|
|
|
cff1_font_dict_op_serializer_t fontSzr; |
|
|
|
|
auto it = + hb_zip (+ hb_iter (plan.fontdicts_mod), + hb_iter (plan.fontdicts_mod)); |
|
|
|
|
if (unlikely (!fda->serialize (c, it, fontSzr))) return false; |
|
|
|
|
plan.info.fd_array_link = c->pop_pack (false); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* global subrs */ |
|
|
|
|
/* FDSelect */ |
|
|
|
|
if (acc.fdSelect != &Null(CFF1FDSelect)) |
|
|
|
|
{ |
|
|
|
|
assert (plan.offsets.globalSubrsInfo.offset != 0); |
|
|
|
|
assert (plan.offsets.globalSubrsInfo.offset == (unsigned) (c->head - c->start)); |
|
|
|
|
c->push (); |
|
|
|
|
if (unlikely (!hb_serialize_cff_fdselect (c, num_glyphs, *acc.fdSelect, acc.fdCount, |
|
|
|
|
plan.subset_fdselect_format, plan.info.fd_select.size, |
|
|
|
|
plan.subset_fdselect_ranges))) return false; |
|
|
|
|
plan.info.fd_select.link = c->pop_pack (); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
CFF1Subrs *dest = c->start_embed <CFF1Subrs> (); |
|
|
|
|
/* Charset */ |
|
|
|
|
if (plan.subset_charset) |
|
|
|
|
{ |
|
|
|
|
c->push (); |
|
|
|
|
Charset *dest = c->start_embed<Charset> (); |
|
|
|
|
if (unlikely (dest == nullptr)) return false; |
|
|
|
|
if (unlikely (!dest->serialize (c, plan.offsets.globalSubrsInfo.offSize, plan.subset_globalsubrs))) |
|
|
|
|
{ |
|
|
|
|
DEBUG_MSG (SUBSET, nullptr, "failed to serialize global subroutines"); |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
if (unlikely (!dest->serialize (c, |
|
|
|
|
plan.subset_charset_format, |
|
|
|
|
plan.num_glyphs, |
|
|
|
|
plan.subset_charset_ranges))) return false; |
|
|
|
|
plan.info.charset_link = c->pop_pack (); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Encoding */ |
|
|
|
|
if (plan.subset_encoding) |
|
|
|
|
{ |
|
|
|
|
assert (plan.offsets.encodingOffset == (unsigned) (c->head - c->start)); |
|
|
|
|
Encoding *dest = c->start_embed<Encoding> (); |
|
|
|
|
if (unlikely (dest == nullptr)) return false; |
|
|
|
|
c->push (); |
|
|
|
|
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; |
|
|
|
|
} |
|
|
|
|
plan.subset_enc_supp_codes))) return false; |
|
|
|
|
plan.info.encoding_link = c->pop_pack (); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Charset */ |
|
|
|
|
if (plan.subset_charset) |
|
|
|
|
/* global subrs */ |
|
|
|
|
{ |
|
|
|
|
assert (plan.offsets.charsetInfo.offset == (unsigned) (c->head - c->start)); |
|
|
|
|
Charset *dest = c->start_embed<Charset> (); |
|
|
|
|
c->push (); |
|
|
|
|
CFF1Subrs *dest = c->start_embed <CFF1Subrs> (); |
|
|
|
|
if (unlikely (dest == nullptr)) return false; |
|
|
|
|
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; |
|
|
|
|
} |
|
|
|
|
if (unlikely (!dest->serialize (c, plan.subset_globalsubrs))) return false; |
|
|
|
|
c->pop_pack (); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* FDSelect */ |
|
|
|
|
if (acc.fdSelect != &Null(CFF1FDSelect)) |
|
|
|
|
/* String INDEX */ |
|
|
|
|
{ |
|
|
|
|
assert (plan.offsets.FDSelectInfo.offset == (unsigned) (c->head - c->start)); |
|
|
|
|
|
|
|
|
|
if (unlikely (!hb_serialize_cff_fdselect (c, num_glyphs, *acc.fdSelect, acc.fdCount, |
|
|
|
|
plan.subset_fdselect_format, plan.offsets.FDSelectInfo.size, |
|
|
|
|
plan.subset_fdselect_ranges))) |
|
|
|
|
{ |
|
|
|
|
DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF subset FDSelect"); |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
c->push (); |
|
|
|
|
CFF1StringIndex *dest = c->start_embed<CFF1StringIndex> (); |
|
|
|
|
if (unlikely (dest == nullptr)) return false; |
|
|
|
|
if (unlikely (!dest->serialize (c, *acc.stringIndex, plan.sidmap))) return false; |
|
|
|
|
c->pop_pack (); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* FDArray (FD Index) */ |
|
|
|
|
if (acc.fdArray != &Null(CFF1FDArray)) |
|
|
|
|
{ |
|
|
|
|
assert (plan.offsets.FDArrayInfo.offset == (unsigned) (c->head - c->start)); |
|
|
|
|
CFF1FDArray *fda = c->start_embed<CFF1FDArray> (); |
|
|
|
|
if (unlikely (fda == nullptr)) return false; |
|
|
|
|
cff1_font_dict_op_serializer_t fontSzr; |
|
|
|
|
if (unlikely (!fda->serialize (c, plan.offsets.FDArrayInfo.offSize, |
|
|
|
|
plan.fontdicts_mod, |
|
|
|
|
fontSzr))) |
|
|
|
|
{ |
|
|
|
|
DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF FDArray"); |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
OT::cff1 *cff = c->allocate_min<OT::cff1> (); |
|
|
|
|
if (unlikely (!cff)) |
|
|
|
|
return false; |
|
|
|
|
|
|
|
|
|
/* CharStrings */ |
|
|
|
|
/* header */ |
|
|
|
|
cff->version.major = 0x01; |
|
|
|
|
cff->version.minor = 0x00; |
|
|
|
|
cff->nameIndex = cff->min_size; |
|
|
|
|
cff->offSize = 4; /* unused? */ |
|
|
|
|
|
|
|
|
|
/* name INDEX */ |
|
|
|
|
if (unlikely (!(*acc.nameIndex).copy (c))) return false; |
|
|
|
|
|
|
|
|
|
/* top dict INDEX */ |
|
|
|
|
{ |
|
|
|
|
assert (plan.offsets.charStringsInfo.offset == (unsigned) (c->head - c->start)); |
|
|
|
|
CFF1CharStrings *cs = c->start_embed<CFF1CharStrings> (); |
|
|
|
|
if (unlikely (cs == nullptr)) return false; |
|
|
|
|
if (unlikely (!cs->serialize (c, plan.offsets.charStringsInfo.offSize, plan.subset_charstrings))) |
|
|
|
|
{ |
|
|
|
|
DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF CharStrings"); |
|
|
|
|
/* serialize singleton TopDict */ |
|
|
|
|
c->push (); |
|
|
|
|
TopDict *top = c->start_embed<TopDict> (); |
|
|
|
|
if (top == nullptr) return false; |
|
|
|
|
cff1_top_dict_op_serializer_t topSzr; |
|
|
|
|
top_dict_modifiers_t modifier (plan.info, plan.topDictModSIDs); |
|
|
|
|
if (unlikely (!top->serialize (c, plan.topdict_mod, topSzr, modifier))) |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
unsigned top_size = c->length (); |
|
|
|
|
c->pop_pack (false); |
|
|
|
|
|
|
|
|
|
/* private dicts & local subrs */ |
|
|
|
|
assert (plan.offsets.privateDictInfo.offset == (unsigned) (c->head - c->start)); |
|
|
|
|
for (unsigned int i = 0; i < acc.privateDicts.length; i++) |
|
|
|
|
{ |
|
|
|
|
if (plan.fdmap.has (i)) |
|
|
|
|
{ |
|
|
|
|
PrivateDict *pd = c->start_embed<PrivateDict> (); |
|
|
|
|
if (unlikely (pd == nullptr)) return false; |
|
|
|
|
unsigned int priv_size = plan.fontdicts_mod[plan.fdmap[i]].privateDictInfo.size; |
|
|
|
|
bool result; |
|
|
|
|
cff_private_dict_op_serializer_t privSzr (plan.desubroutinize, plan.drop_hints); |
|
|
|
|
/* N.B. local subrs immediately follows its corresponding private dict. i.e., subr offset == private dict size */ |
|
|
|
|
unsigned int subroffset = (plan.offsets.localSubrsInfos[i].size > 0) ? priv_size : 0; |
|
|
|
|
result = pd->serialize (c, acc.privateDicts[i], privSzr, subroffset); |
|
|
|
|
if (unlikely (!result)) |
|
|
|
|
{ |
|
|
|
|
DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF Private Dict[%d]", i); |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
if (plan.offsets.localSubrsInfos[i].size > 0) |
|
|
|
|
{ |
|
|
|
|
CFF1Subrs *dest = c->start_embed <CFF1Subrs> (); |
|
|
|
|
if (unlikely (dest == nullptr)) return false; |
|
|
|
|
if (unlikely (!dest->serialize (c, plan.offsets.localSubrsInfos[i].offSize, plan.subset_localsubrs[i]))) |
|
|
|
|
{ |
|
|
|
|
DEBUG_MSG (SUBSET, nullptr, "failed to serialize local subroutines"); |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
/* serialize INDEX header for above */ |
|
|
|
|
CFF1Index *dest = c->start_embed<CFF1Index> (); |
|
|
|
|
if (dest == nullptr) return false; |
|
|
|
|
return dest->serialize_header (c, hb_iter (hb_array_t<unsigned> (&top_size, 1))); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static inline bool |
|
|
|
|
static bool |
|
|
|
|
_hb_subset_cff1 (const OT::cff1::accelerator_subset_t &acc, |
|
|
|
|
hb_subset_context_t *c) |
|
|
|
|
{ |
|
|
|
@ -1074,12 +859,7 @@ _hb_subset_cff1 (const OT::cff1::accelerator_subset_t &acc, |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (unlikely (!_write_cff1 (c->serializer, cff_plan, acc, c->plan->num_output_glyphs ()))) { |
|
|
|
|
DEBUG_MSG(SUBSET, nullptr, "Failed to write a subset cff."); |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return true; |
|
|
|
|
return _serialize_cff1 (c->serializer, cff_plan, acc, c->plan->num_output_glyphs ()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|