/* 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 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,
&pool)) 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<F2DOT14>*, 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_coords (axes_index_map, axes_old_index_tag_map, &pool)) returnfalse; unsigned *count; unsigned hash = hb_hash (&var.compiled_peak_coords); if (coords_count_map.has_with_hash (&(var.compiled_peak_coords), hash, &count))
(*count)++; else
coords_count_map.set_with_hash (&(var.compiled_peak_coords), hash, 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<hb_pair_t<const hb_vector_t<F2DOT14>*, unsigned>> shared_coords {
+ hb_iter (coords_count_map)
| hb_filter ([] (const hb_pair_t<const hb_vector_t<F2DOT14>*, unsigned>& p) { return p.second > 1; })
}; if (unlikely (shared_coords.in_error ())) returnfalse;
/* 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 */
shared_coords.qsort (_cmp_coords);
/* 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].first->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].first, i); /* add a concat() in hb_vector_t? */ for (auto c : shared_coords[i].first->iter ())
compiled_shared_tuples.push (c);
}
/* 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<GidOffsetType>& 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, *thevaluestoredistheoffsetdividedby2,sothemaximumdatasizeshould
* 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++;
size_t subset_data_size = 0; unsigned padding_size = 0; for (auto &_ : it)
{
hb_codepoint_t old_gid = _.second; unsigned glyph_data_size = get_glyph_var_data_bytes (c->source_blob, glyph_count, old_gid).length; if (glyph_data_size % 2)
{
glyph_data_size++;
padding_size++;
}
subset_data_size += glyph_data_size;
}
/* According to the spec: If the short format (Offset16) is used for offsets, *thevaluestoredistheoffsetdividedby2,sothemaximumdatasizeshould
* 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 */ if (long_offset)
subset_data_size -= padding_size; char *subset_data = c->serializer->allocate_size<char> (subset_data_size, false); if (!subset_data) return_trace (false);
out->dataZ = subset_data - (char *) out;
auto &shared_indices = scratch.shared_indices;
shared_indices.clear ();
typename 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 */ auto &orig_points_vec = scratch.orig_points;
orig_points_vec.clear (); // Populated lazily auto orig_points = orig_points_vec.as_array ();
/* flag is used to indicate referenced point */ auto &deltas_vec = scratch.deltas;
deltas_vec.clear (); // 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.add_delta (x_deltas.arrayZ[i] * scalar,
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++)
{ auto &delta = deltas.arrayZ[i];
delta.add_delta (x_deltas.arrayZ[i] * scalar,
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.add_delta (x_deltas.arrayZ[i] * scalar,
y_deltas.arrayZ[i] * scalar);
}
} else
{ if (apply_to_all) for (unsignedint i = phantom_only ? count - 4 : 0; i < count; i++)
{ auto &delta = deltas.arrayZ[i];
delta.add_delta (x_deltas.arrayZ[i],
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.add_delta (x_deltas.arrayZ[i],
y_deltas.arrayZ[i]);
}
}
}
/* infer deltas for unreferenced points */ if (!apply_to_all && !phantom_only)
{ unsigned start_point = 0; unsigned end_point = 0; while (true)
{ while (end_point < count && !points.arrayZ[end_point].is_end_point)
end_point++; if (unlikely (end_point == count)) break;
/* 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. *Notethatagapmaywraparoundatleft(start_point)and/oratright(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 = 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 *canbereferencedwithinglyphvariationdatatablesfor *multipleglyphs,asopposedtoothertuplerecordsstored
* 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. */
GidOffsetType 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. *Ifbit0isclear,theoffsetsareuint16;ifbit0isset,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);
};
using gvar = gvar_GVAR<HBUINT16, HB_OT_TAG_gvar>; using GVAR = gvar_GVAR<HBUINT24, HB_OT_TAG_GVAR>;
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.