switch (op)
{ case OpCode_return: case OpCode_endchar:
skip_command = true; break;
case OpCode_hstem: case OpCode_hstemhm: case OpCode_vstem: case OpCode_vstemhm: case OpCode_hintmask: case OpCode_cntrmask: if (param.drop_hints)
skip_command = true; break;
default: break;
}
if (!skip_command)
{
cs_command_t cmd (op); /* Capture resolved blend values */ for (unsignedint i = 0; i < env.argStack.get_count ();)
{ const blend_arg_t &arg = env.argStack[i]; if (arg.blending ())
{ /* For blend args, capture only the resolved default value */
cmd.args.push (arg); /* Skip over the multiple blend values */
i += arg.numValues;
} else
{
cmd.args.push (arg);
i++;
}
}
param.commands->push (cmd);
}
}
switch (op)
{ case OpCode_return: case OpCode_endchar: /* dummy opcodes in CFF2. ignore */ break;
case OpCode_hstem: case OpCode_hstemhm: case OpCode_vstem: case OpCode_vstemhm: case OpCode_hintmask: case OpCode_cntrmask: if (param.drop_hints)
{
env.clear_args (); return;
}
HB_FALLTHROUGH;
staticvoid process_blend (cff2_priv_dict_interp_env_t& env, cff2_private_blend_encoder_param_t& param)
{ unsignedint n, k;
param.process_blend ();
k = param.region_count;
n = env.argStack.pop_uint (); /* copy the blend values into blend array of the default values */ unsignedint start = env.argStack.get_count () - ((k+1) * n); /* let an obvious error case fail, but note CFF2 spec doesn't forbid n==0 */ if (unlikely (start > env.argStack.get_count ()))
{
env.set_error (); return;
} for (unsignedint i = 0; i < n; i++)
{ const hb_array_t<const number_t> blends = env.argStack.sub_array (start + n + (i * k), k);
process_arg_blend (param, env.argStack[start + i], blends, n, i);
}
/* pop off blend values leaving default values now adorned with blend values */
env.argStack.pop (k * n);
}
staticvoid process_op (op_code_t op, cff2_priv_dict_interp_env_t& env, cff2_private_blend_encoder_param_t& param)
{ switch (op) { case OpCode_StdHW: case OpCode_StdVW: case OpCode_BlueScale: case OpCode_BlueShift: case OpCode_BlueFuzz: case OpCode_ExpansionFactor: case OpCode_LanguageGroup: case OpCode_BlueValues: case OpCode_OtherBlues: case OpCode_FamilyBlues: case OpCode_FamilyOtherBlues: case OpCode_StemSnapH: case OpCode_StemSnapV: break; case OpCode_vsindexdict:
env.process_vsindex ();
param.ivs = env.get_ivs ();
env.clear_args (); return; case OpCode_blenddict:
process_blend (env, param); return;
default:
dict_opset_t::process_op (op, env); if (!env.argStack.is_empty ()) return; break;
}
if (unlikely (env.in_error ())) return;
// Write args then op
str_buff_t str;
str_encoder_t encoder (str);
unsigned count = env.argStack.get_count (); for (unsigned i = 0; i < count; i++)
encoder.encode_num_tp (env.argStack[i]);
encoder.encode_op (op);
auto bytes = str.as_bytes ();
param.c->embed (&bytes, bytes.length);
if (desubroutinize)
{ /* Flatten global & local subrs */
subr_flattener_t<const OT::cff2::accelerator_subset_t, cff2_cs_interp_env_t<blend_arg_t>, cff2_cs_opset_flatten_t>
flattener(acc, plan);
/* Enable command capture if requested (for specialization) */ if (capture_commands)
{ if (!charstring_commands.resize_exact (num_glyphs)) returnfalse;
if (!flattener.flatten (subset_charstrings, &charstring_commands)) returnfalse;
} else
{ if (!flattener.flatten (subset_charstrings)) returnfalse;
}
} else
{
cff2_subr_subsetter_t subr_subsetter (acc, plan);
/* Subset subrs: collect used subroutines, leaving all unused ones behind */ if (!subr_subsetter.subset ()) returnfalse;
/* encode charstrings, global subrs, local subrs with new subroutine numbers */ if (!subr_subsetter.encode_charstrings (subset_charstrings, !pinned)) returnfalse;
if (!subr_subsetter.encode_globalsubrs (subset_globalsubrs)) returnfalse;
/* local subrs */ if (!subset_localsubrs.resize (orig_fdcount)) returnfalse; for (unsignedint fd = 0; fd < orig_fdcount; fd++)
{
subset_localsubrs[fd].init (); if (!subr_subsetter.encode_localsubrs (fd, subset_localsubrs[fd])) returnfalse;
}
}
/* Serialize charstrings using CFF1 format with widths */ staticbool
_serialize_cff1_charstrings (hb_serialize_context_t *c,
OT::cff2_subset_plan &plan, unsigned default_width, unsigned nominal_width)
{
c->push ();
// CFF1 requires: // 1. Width at the beginning (if != defaultWidthX) // 2. endchar at the end
str_buff_vec_t cff1_charstrings; if (unlikely (!cff1_charstrings.resize (plan.subset_charstrings.length)))
{
c->pop_discard (); returnfalse;
}
for (unsigned i = 0; i < plan.subset_charstrings.length; i++)
{ // Get width for this glyph from hmtx_map unsigned width = 0; if (plan.hmtx_map->has (i))
width = plan.hmtx_map->get (i).first;
// Encode width if different from default
str_encoder_t encoder (cff1_charstrings[i]); if (width != default_width)
{ int delta = (int) width - (int) nominal_width;
encoder.encode_int (delta);
}
// Use specialized commands if available, otherwise use binary if (plan.capture_commands && i < plan.charstring_commands.length &&
plan.charstring_commands[i].length > 0)
{ // Specialize and encode commands auto &commands = plan.charstring_commands[i];
CFF::specialize_commands (commands, 48); /* maxstack=48 for CFF1 */ if (unlikely (!CFF::encode_commands (commands, cff1_charstrings[i])))
{
c->pop_discard (); returnfalse;
}
} else
{ // Use binary CharString const str_buff_t &cs = plan.subset_charstrings[i]; for (unsigned j = 0; j < cs.length; j++)
cff1_charstrings[i].push (cs[j]);
}
// Check if it already ends with endchar (0x0e) or return (0x0b) if (cff1_charstrings[i].length == 0 ||
(cff1_charstrings[i].tail () != 0x0e && cff1_charstrings[i].tail () != 0x0b))
{ // Append endchar operator if (unlikely (!cff1_charstrings[i].push_or_fail (0x0e)))
{
c->pop_discard (); returnfalse;
}
}
}
/* Serialize CID Charset (format 2 range: gid 0-N -> cid 0-N) */ staticbool
_serialize_cff1_charset (hb_serialize_context_t *c, unsignedint num_glyphs,
objidx_t &charset_link)
{ // For CID fonts, create a simple identity charset // Format 2: one range covering all glyphs (except .notdef)
c->push ();
auto *charset = c->start_embed<Charset> (); if (unlikely (!charset))
{
c->pop_discard (); returnfalse;
}
// Create a single range for CID 1 to num_glyphs-1
hb_vector_t<code_pair_t> ranges; if (num_glyphs > 1)
{
code_pair_t range;
range.code = 1; // first CID
range.glyph = num_glyphs - 2; // nLeft (covers glyphs 1 to num_glyphs-1)
ranges.push (range);
}
bool
OT::cff2::accelerator_subset_t::serialize (hb_serialize_context_t *c, struct cff2_subset_plan &plan,
hb_array_t<int> normalized_coords) const
{ /* push charstrings onto the object stack first which will ensure it packs as the last objectinthetable.Keepingthechastringslastsatisfiestherequirementsforpatching viaIFTB.Ifthisorderingneedstobechangedinthefuture,charstringsshouldbeleft
at the end whenever HB_SUBSET_FLAGS_ITFB_REQUIREMENTS is enabled. */ if (!_serialize_cff2_charstrings(c, plan, *this)) returnfalse;
/* private dicts & local subrs */
hb_vector_t<table_info_t> private_dict_infos; if (unlikely (!private_dict_infos.resize (plan.subset_fdcount))) returnfalse;
for (int i = (int)privateDicts.length; --i >= 0 ;)
{ if (plan.fdmap.has (i))
{
objidx_t subrs_link = 0;
if (unlikely (!cff2_plan.create (*this, c->plan))) returnfalse;
// If instantiating (pinned) and downgrade flag is set, convert to CFF1 if (cff2_plan.pinned && (c->plan->flags & HB_SUBSET_FLAGS_DOWNGRADE_CFF2))
{ // Serialize CFF1 to the subsetter's serializer // If we run out of room, returning true will cause subsetter to retry with larger buffer bool result = CFF::serialize_cff2_to_cff1 (c->serializer, cff2_plan, topDict, *this);
if (c->serializer->ran_out_of_room ()) returntrue; // Subsetter will retry with larger buffer
if (result && !c->serializer->in_error ())
{ // Success - end serialization to resolve links
c->serializer->end_serialize ();
// Copy the serialized CFF1 data and add as CFF table
hb_blob_t *cff_blob = c->serializer->copy_blob (); if (cff_blob)
{
c->plan->add_table (HB_TAG('C','F','F',' '), cff_blob);
hb_blob_destroy (cff_blob);
// Return false to signal CFF2 table is not needed returnfalse;
}
}
// Conversion failed - don't fall back, fail hard for debugging returnfalse;
}
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.128Bemerkung:
(vorverarbeitet am 2026-09-28)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.