/* in case variation data is empty, push an empty struct into the vector,
* keep the vector in sync with the new_to_old_gid_list */ if (!var_data || ! p->has_data () || !all_contour_points->length ||
!GlyphVariationData::get_tuple_iterator (var_data, axis_count,
var_data.arrayZ,
shared_indices, &iterator))
{
glyph_variations.push (std::move (tuple_vars)); continue;
}
bool instantiate (const hb_subset_plan_t *plan)
{ unsigned count = plan->new_to_old_gid_list.length; bool iup_optimize = false;
iup_optimize = plan->flags & HB_SUBSET_FLAGS_OPTIMIZE_IUP_DELTAS; for (unsigned i = 0; i < count; i++)
{
hb_codepoint_t new_gid = plan->new_to_old_gid_list[i].first;
contour_point_vector_t *all_points; if (!plan->new_gid_contour_points_map.has (new_gid, &all_points)) returnfalse; if (!glyph_variations[i].instantiate (plan->axes_location, plan->axes_triple_distances, all_points, iup_optimize)) returnfalse;
} returntrue;
}
bool compile_bytes (const hb_map_t& axes_index_map, const hb_map_t& axes_old_index_tag_map)
{ if (!compile_shared_tuples (axes_index_map, axes_old_index_tag_map)) returnfalse; for (tuple_variations_t& vars: glyph_variations) if (!vars.compile_bytes (axes_index_map, axes_old_index_tag_map, true, /* use shared points*/ true,
&shared_tuples_idx_map)) returnfalse;
returntrue;
}
bool compile_shared_tuples (const hb_map_t& axes_index_map, const hb_map_t& axes_old_index_tag_map)
{ /* key is pointer to compiled_peak_coords inside each tuple, hashing
* function will always deref pointers first */
hb_hashmap_t<const hb_vector_t<char>*, unsigned> coords_count_map;
/* count the num of shared coords */ for (tuple_variations_t& vars: glyph_variations)
{ for (tuple_delta_t& var : vars.tuple_vars)
{ if (!var.compile_peak_coords (axes_index_map, axes_old_index_tag_map)) returnfalse; unsigned* count; if (coords_count_map.has (&(var.compiled_peak_coords), &count))
coords_count_map.set (&(var.compiled_peak_coords), *count + 1); else
coords_count_map.set (&(var.compiled_peak_coords), 1);
}
}
if (!coords_count_map || coords_count_map.in_error ()) returnfalse;
/* add only those coords that are used more than once into the vector and sort */
hb_vector_t<const hb_vector_t<char>*> shared_coords; if (unlikely (!shared_coords.alloc (coords_count_map.get_population ()))) returnfalse;
for (constauto _ : coords_count_map.iter ())
{ if (_.second == 1) continue;
shared_coords.push (_.first);
}
/* no shared tuples: no coords are used more than once */ if (!shared_coords) returntrue; /* sorting based on the coords frequency first (high to low), then compare
* the coords bytes */
hb_qsort (shared_coords.arrayZ, shared_coords.length, sizeof (hb_vector_t<char>*), _cmp_coords, (void *) (&coords_count_map));
/* build shared_coords->idx map and shared tuples byte array */
shared_tuples_count = hb_min (0xFFFu + 1, shared_coords.length); unsigned len = shared_tuples_count * (shared_coords[0]->length); if (unlikely (!compiled_shared_tuples.alloc (len))) returnfalse;
for (unsigned i = 0; i < shared_tuples_count; i++)
{
shared_tuples_idx_map.set (shared_coords[i], i); /* add a concat() in hb_vector_t? */ for (char c : shared_coords[i]->iter ())
compiled_shared_tuples.push (c);
}
/* shared_coords is hb_vector_t<const hb_vector_t<char>*> so casting pa/pb
* to be a pointer to a pointer */ const hb_vector_t<char>** a = reinterpret_cast<const hb_vector_t<char>**> (const_cast<void*>(pa)); const hb_vector_t<char>** b = reinterpret_cast<const hb_vector_t<char>**> (const_cast<void*>(pb));
/* GlyphVariationData not sanitized here; must be checked while accessing each glyph variation data */ bool sanitize (hb_sanitize_context_t *c) const
{ return sanitize_shallow (c); }
bool decompile_glyph_variations (hb_subset_context_t *c,
glyph_variations_t& glyph_vars /* OUT */) const
{
hb_hashmap_t<hb_codepoint_t, hb_bytes_t> new_gid_var_data_map; auto it = hb_iter (c->plan->new_to_old_gid_list); if (it->first == 0 && !(c->plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE))
{
new_gid_var_data_map.set (0, hb_bytes_t ());
it++;
}
unsigned glyph_var_data_size = glyph_vars.compiled_byte_size (); /* According to the spec: If the short format (Offset16) is used for offsets, * the value stored is the offset divided by 2, so the maximum data size should
* be 2 * 0xFFFFu, which is 0x1FFFEu */ bool long_offset = glyph_var_data_size > 0x1FFFEu || force_long_offsets;
out->flags = long_offset ? 1 : 0;
auto it = hb_iter (c->plan->new_to_old_gid_list); if (it->first == 0 && !(c->plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE))
it++; unsignedint subset_data_size = 0; for (auto &_ : it)
{
hb_codepoint_t old_gid = _.second;
subset_data_size += get_glyph_var_data_bytes (c->source_blob, glyph_count, old_gid).length;
}
/* According to the spec: If the short format (Offset16) is used for offsets, * the value stored is the offset divided by 2, so the maximum data size should
* be 2 * 0xFFFFu, which is 0x1FFFEu */ bool long_offset = subset_data_size > 0x1FFFEu; #ifdef HB_EXPERIMENTAL_API
long_offset = long_offset || (c->plan->flags & HB_SUBSET_FLAGS_IFTB_REQUIREMENTS); #endif
out->flags = long_offset ? 1 : 0;
/* This ordering relative to the shared tuples array, which puts the glyphVariationData
last in the table, is required when HB_SUBSET_FLAGS_IFTB_REQUIREMENTS is set */ char *subset_data = c->serializer->allocate_size<char> (subset_data_size, false); if (!subset_data) return_trace (false);
out->dataZ = subset_data - (char *) out;
/* For shared tuples that only have one axis active, shared the index of * that axis as a cache. This will speed up caclulate_scalar() a lot
* for fonts with lots of axes and many "monovar" tuples. */
hb_array_t<const F2DOT14> shared_tuples = (table+table->sharedTuples).as_array (table->sharedTupleCount * table->axisCount); unsigned count = table->sharedTupleCount; if (unlikely (!shared_tuple_active_idx.resize (count, false))) return; unsigned axis_count = table->axisCount; for (unsigned i = 0; i < count; i++)
{
hb_array_t<const F2DOT14> tuple = shared_tuples.sub_array (axis_count * i, axis_count); int idx1 = -1, idx2 = -1; for (unsigned j = 0; j < axis_count; j++)
{ const F2DOT14 &peak = tuple.arrayZ[j]; if (peak.to_int () != 0)
{ if (idx1 == -1)
idx1 = j; elseif (idx2 == -1)
idx2 = j; else
{
idx1 = idx2 = -1; break;
}
}
}
shared_tuple_active_idx.arrayZ[i] = {idx1, idx2};
}
}
~accelerator_t () { table.destroy (); }
hb_bytes_t var_data_bytes = table->get_glyph_var_data_bytes (table.get_blob (), glyphCount, glyph); if (!var_data_bytes.as<GlyphVariationData> ()->has_data ()) returntrue;
hb_vector_t<unsignedint> shared_indices;
GlyphVariationData::tuple_iterator_t iterator; if (!GlyphVariationData::get_tuple_iterator (var_data_bytes, table->axisCount,
var_data_bytes.arrayZ,
shared_indices, &iterator)) returntrue; /* so isn't applied at all */
/* Save original points for inferred delta calculation */
contour_point_vector_t orig_points_vec; // Populated lazily auto orig_points = orig_points_vec.as_array ();
/* flag is used to indicate referenced point */
contour_point_vector_t deltas_vec; // Populated lazily auto deltas = deltas_vec.as_array ();
if (HB_OPTIMIZE_SIZE_VAL)
{ for (unsignedint i = 0; i < num_deltas; i++)
{ unsignedint pt_index; if (apply_to_all)
pt_index = i; else
{
pt_index = indices[i]; if (unlikely (pt_index >= deltas.length)) continue;
} if (phantom_only && pt_index < count - 4) continue; auto &delta = deltas.arrayZ[pt_index];
delta.flag = 1; /* this point is referenced, i.e., explicit deltas specified */
delta.x += x_deltas.arrayZ[i] * scalar;
delta.y += y_deltas.arrayZ[i] * scalar;
}
} else
{ /* Ouch. Four cases... for optimization. */ if (scalar != 1.0f)
{ if (apply_to_all) for (unsignedint i = phantom_only ? count - 4 : 0; i < count; i++)
{ unsignedint pt_index = i; auto &delta = deltas.arrayZ[pt_index];
delta.x += x_deltas.arrayZ[i] * scalar;
delta.y += y_deltas.arrayZ[i] * scalar;
} else for (unsignedint i = 0; i < num_deltas; i++)
{ unsignedint pt_index = indices[i]; if (unlikely (pt_index >= deltas.length)) continue; if (phantom_only && pt_index < count - 4) continue; auto &delta = deltas.arrayZ[pt_index];
delta.flag = 1; /* this point is referenced, i.e., explicit deltas specified */
delta.x += x_deltas.arrayZ[i] * scalar;
delta.y += y_deltas.arrayZ[i] * scalar;
}
} else
{ if (apply_to_all) for (unsignedint i = phantom_only ? count - 4 : 0; i < count; i++)
{ unsignedint pt_index = i; auto &delta = deltas.arrayZ[pt_index];
delta.x += x_deltas.arrayZ[i];
delta.y += y_deltas.arrayZ[i];
} else for (unsignedint i = 0; i < num_deltas; i++)
{ unsignedint pt_index = indices[i]; if (unlikely (pt_index >= deltas.length)) continue; if (phantom_only && pt_index < count - 4) continue; auto &delta = deltas.arrayZ[pt_index];
delta.flag = 1; /* this point is referenced, i.e., explicit deltas specified */
delta.x += x_deltas.arrayZ[i];
delta.y += y_deltas.arrayZ[i];
}
}
}
/* infer deltas for unreferenced points */ if (!apply_to_all && !phantom_only)
{ if (!end_points)
{ for (unsigned i = 0; i < count; ++i) if (points.arrayZ[i].is_end_point)
end_points.push (i); if (unlikely (end_points.in_error ())) returnfalse;
}
unsigned start_point = 0; for (unsigned end_point : end_points)
{ /* Check the number of unreferenced points in a contour. If no unref points or no ref points, nothing to do. */ unsigned unref_count = 0; for (unsigned i = start_point; i < end_point + 1; i++)
unref_count += deltas.arrayZ[i].flag;
unref_count = (end_point - start_point + 1) - unref_count;
for (;;)
{ /* Locate the next gap of unreferenced points between two referenced points prev and next. * Note that a gap may wrap around at left (start_point) and/or at right (end_point).
*/ unsignedint prev, next, i; for (;;)
{
i = j;
j = next_index (i, start_point, end_point); if (deltas.arrayZ[i].flag && !deltas.arrayZ[j].flag) break;
}
prev = j = i; for (;;)
{
i = j;
j = next_index (i, start_point, end_point); if (!deltas.arrayZ[i].flag && deltas.arrayZ[j].flag) break;
}
next = j; /* Infer deltas for all unref points in the gap between prev and next */
i = prev; for (;;)
{
i = next_index (i, start_point, end_point); if (i == next) break;
deltas.arrayZ[i].x = infer_delta (orig_points, deltas, i, prev, next, &contour_point_t::x);
deltas.arrayZ[i].y = infer_delta (orig_points, deltas, i, prev, next, &contour_point_t::y); if (--unref_count == 0) goto no_more_gaps;
}
}
no_more_gaps:
start_point = end_point + 1;
}
}
flush = true;
} while (iterator.move_to_next ());
if (flush)
{ for (unsignedint i = phantom_only ? count - 4 : 0; i < count; i++)
points.arrayZ[i].translate (deltas.arrayZ[i]);
}
protected:
FixedVersion<>version; /* Version number of the glyph variations table
* Set to 0x00010000u. */
HBUINT16 axisCount; /* The number of variation axes for this font. This must be
* the same number as axisCount in the 'fvar' table. */
HBUINT16 sharedTupleCount; /* The number of shared tuple records. Shared tuple records * can be referenced within glyph variation data tables for * multiple glyphs, as opposed to other tuple records stored
* directly within a glyph variation data table. */
NNOffset32To<UnsizedArrayOf<F2DOT14>>
sharedTuples; /* Offset from the start of this table to the shared tuple records.
* Array of tuple records shared across all glyph variation data tables. */
HBUINT16 glyphCountX; /* The number of glyphs in this font. This must match the number of
* glyphs stored elsewhere in the font. */
HBUINT16 flags; /* Bit-field that gives the format of the offset array that follows. * If bit 0 is clear, the offsets are uint16; if bit 0 is set, the
* offsets are uint32. */
Offset32To<GlyphVariationData>
dataZ; /* Offset from the start of this table to the array of
* GlyphVariationData tables. */
UnsizedArrayOf<HBUINT8>
offsetZ; /* Offsets from the start of the GlyphVariationData array
* to each GlyphVariationData table. */ public:
DEFINE_SIZE_ARRAY (20, offsetZ);
};
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.