1
0
mirror of https://github.com/godotengine/godot.git synced 2025-11-10 13:00:37 +00:00

HarfBuzz: Update to version 5.3.1

This commit is contained in:
bruvzg
2022-10-21 10:36:19 +03:00
parent 72b845b287
commit 7afd76bba6
46 changed files with 1349 additions and 443 deletions

View File

@@ -214,7 +214,7 @@ Files extracted from upstream source:
## harfbuzz ## harfbuzz
- Upstream: https://github.com/harfbuzz/harfbuzz - Upstream: https://github.com/harfbuzz/harfbuzz
- Version: 5.2.0 (4a1d891c6317d2c83e5f3c2607ec5f5ccedffcde, 2022) - Version: 5.3.1 (970321db7bddbe8c579b73751fc655a924ea3ce6, 2022)
- License: MIT - License: MIT
Files extracted from upstream source: Files extracted from upstream source:

View File

@@ -39,7 +39,7 @@ struct GPOS : GSUBGPOS
bool subset (hb_subset_context_t *c) const bool subset (hb_subset_context_t *c) const
{ {
hb_subset_layout_context_t l (c, tableTag, c->plan->gpos_lookups, c->plan->gpos_langsys, c->plan->gpos_features); hb_subset_layout_context_t l (c, tableTag);
return GSUBGPOS::subset<PosLookup> (&l); return GSUBGPOS::subset<PosLookup> (&l);
} }

View File

@@ -80,6 +80,24 @@ struct SinglePosFormat1
return_trace (true); return_trace (true);
} }
bool
position_single (hb_font_t *font,
hb_direction_t direction,
hb_codepoint_t gid,
hb_glyph_position_t &pos) const
{
unsigned int index = (this+coverage).get_coverage (gid);
if (likely (index == NOT_COVERED)) return false;
/* This is ugly... */
hb_buffer_t buffer;
buffer.props.direction = direction;
OT::hb_ot_apply_context_t c (1, font, &buffer);
valueFormat.apply_value (&c, this, values, pos);
return true;
}
template<typename Iterator, template<typename Iterator,
typename SrcLookup, typename SrcLookup,
hb_requires (hb_is_iterator (Iterator))> hb_requires (hb_is_iterator (Iterator))>

View File

@@ -68,7 +68,7 @@ struct SinglePosFormat2
unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint); unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint);
if (likely (index == NOT_COVERED)) return_trace (false); if (likely (index == NOT_COVERED)) return_trace (false);
if (likely (index >= valueCount)) return_trace (false); if (unlikely (index >= valueCount)) return_trace (false);
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{ {
@@ -92,6 +92,28 @@ struct SinglePosFormat2
return_trace (true); return_trace (true);
} }
bool
position_single (hb_font_t *font,
hb_direction_t direction,
hb_codepoint_t gid,
hb_glyph_position_t &pos) const
{
unsigned int index = (this+coverage).get_coverage (gid);
if (likely (index == NOT_COVERED)) return false;
if (unlikely (index >= valueCount)) return false;
/* This is ugly... */
hb_buffer_t buffer;
buffer.props.direction = direction;
OT::hb_ot_apply_context_t c (1, font, &buffer);
valueFormat.apply_value (&c, this,
&values[index * valueFormat.get_len ()],
pos);
return true;
}
template<typename Iterator, template<typename Iterator,
typename SrcLookup, typename SrcLookup,
hb_requires (hb_is_iterator (Iterator))> hb_requires (hb_is_iterator (Iterator))>

View File

@@ -27,7 +27,7 @@ struct GSUB : GSUBGPOS
bool subset (hb_subset_context_t *c) const bool subset (hb_subset_context_t *c) const
{ {
hb_subset_layout_context_t l (c, tableTag, c->plan->gsub_lookups, c->plan->gsub_langsys, c->plan->gsub_features); hb_subset_layout_context_t l (c, tableTag);
return GSUBGPOS::subset<SubstLookup> (&l); return GSUBGPOS::subset<SubstLookup> (&l);
} }

View File

@@ -118,7 +118,7 @@ struct Ligature
match_positions[i] += delta; match_positions[i] += delta;
if (i) if (i)
*p++ = ','; *p++ = ',';
sprintf (p, "%u", match_positions[i]); snprintf (p, sizeof(buf), "%u", match_positions[i]);
p += strlen(p); p += strlen(p);
} }

View File

@@ -117,7 +117,7 @@ struct Sequence
{ {
if (buf < p) if (buf < p)
*p++ = ','; *p++ = ',';
sprintf (p, "%u", i); snprintf (p, sizeof(buf), "%u", i);
p += strlen(p); p += strlen(p);
} }

View File

@@ -102,17 +102,19 @@ struct Glyph
hb_bytes_t &dest_bytes /* OUT */) const hb_bytes_t &dest_bytes /* OUT */) const
{ {
GlyphHeader *glyph_header = nullptr; GlyphHeader *glyph_header = nullptr;
if (all_points.length > 4) if (type != EMPTY && all_points.length > 4)
{ {
glyph_header = (GlyphHeader *) hb_calloc (1, GlyphHeader::static_size); glyph_header = (GlyphHeader *) hb_calloc (1, GlyphHeader::static_size);
if (unlikely (!glyph_header)) return false; if (unlikely (!glyph_header)) return false;
} }
int xMin, xMax; int xMin = 0, xMax = 0;
int yMin = 0, yMax = 0;
if (all_points.length > 4)
{
xMin = xMax = roundf (all_points[0].x); xMin = xMax = roundf (all_points[0].x);
int yMin, yMax;
yMin = yMax = roundf (all_points[0].y); yMin = yMax = roundf (all_points[0].y);
}
for (unsigned i = 1; i < all_points.length - 4; i++) for (unsigned i = 1; i < all_points.length - 4; i++)
{ {
@@ -128,7 +130,7 @@ struct Glyph
/*for empty glyphs: all_points only include phantom points. /*for empty glyphs: all_points only include phantom points.
*just update metrics and then return */ *just update metrics and then return */
if (all_points.length == 4) if (!glyph_header)
return true; return true;
glyph_header->numberOfContours = header->numberOfContours; glyph_header->numberOfContours = header->numberOfContours;
@@ -145,10 +147,17 @@ struct Glyph
hb_font_t *font, hb_font_t *font,
const glyf_accelerator_t &glyf, const glyf_accelerator_t &glyf,
hb_bytes_t &dest_start, /* IN/OUT */ hb_bytes_t &dest_start, /* IN/OUT */
hb_bytes_t &dest_end /* OUT */) const hb_bytes_t &dest_end /* OUT */)
{ {
contour_point_vector_t all_points, deltas; contour_point_vector_t all_points, deltas;
get_points (font, glyf, all_points, &deltas, false); if (!get_points (font, glyf, all_points, &deltas, false, false))
return false;
// .notdef, set type to empty so we only update metrics and don't compile bytes for
// it
if (gid == 0 &&
!(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE))
type = EMPTY;
switch (type) { switch (type) {
case COMPOSITE: case COMPOSITE:
@@ -171,7 +180,12 @@ struct Glyph
break; break;
} }
return compile_header_bytes (plan, all_points, dest_start); if (!compile_header_bytes (plan, all_points, dest_start))
{
dest_end.fini ();
return false;
}
return true;
} }
@@ -182,6 +196,7 @@ struct Glyph
bool get_points (hb_font_t *font, const accelerator_t &glyf_accelerator, bool get_points (hb_font_t *font, const accelerator_t &glyf_accelerator,
contour_point_vector_t &all_points /* OUT */, contour_point_vector_t &all_points /* OUT */,
contour_point_vector_t *deltas = nullptr, /* OUT */ contour_point_vector_t *deltas = nullptr, /* OUT */
bool shift_points_hori = true,
bool use_my_metrics = true, bool use_my_metrics = true,
bool phantom_only = false, bool phantom_only = false,
unsigned int depth = 0) const unsigned int depth = 0) const
@@ -238,8 +253,7 @@ struct Glyph
if (deltas != nullptr && depth == 0 && type == COMPOSITE) if (deltas != nullptr && depth == 0 && type == COMPOSITE)
{ {
if (unlikely (!deltas->resize (points.length))) return false; if (unlikely (!deltas->resize (points.length))) return false;
for (unsigned i = 0 ; i < points.length; i++) deltas->copy_vector (points);
deltas->arrayZ[i] = points.arrayZ[i];
} }
#ifndef HB_NO_VAR #ifndef HB_NO_VAR
@@ -271,14 +285,9 @@ struct Glyph
comp_points.reset (); comp_points.reset ();
if (unlikely (!glyf_accelerator.glyph_for_gid (item.get_gid ()) if (unlikely (!glyf_accelerator.glyph_for_gid (item.get_gid ())
.get_points (font, glyf_accelerator, comp_points, .get_points (font, glyf_accelerator, comp_points,
deltas, use_my_metrics, phantom_only, depth + 1))) deltas, shift_points_hori, use_my_metrics, phantom_only, depth + 1)))
return false; return false;
/* Copy phantom points from component if USE_MY_METRICS flag set */
if (use_my_metrics && item.is_use_my_metrics ())
for (unsigned int i = 0; i < PHANTOM_COUNT; i++)
phantoms[i] = comp_points[comp_points.length - PHANTOM_COUNT + i];
/* Apply component transformation & translation */ /* Apply component transformation & translation */
item.transform_points (comp_points); item.transform_points (comp_points);
@@ -299,6 +308,11 @@ struct Glyph
} }
} }
/* Copy phantom points from component if USE_MY_METRICS flag set */
if (use_my_metrics && item.is_use_my_metrics ())
for (unsigned int i = 0; i < PHANTOM_COUNT; i++)
phantoms[i] = comp_points[comp_points.length - PHANTOM_COUNT + i];
all_points.extend (comp_points.sub_array (0, comp_points.length - PHANTOM_COUNT)); all_points.extend (comp_points.sub_array (0, comp_points.length - PHANTOM_COUNT));
comp_index++; comp_index++;
@@ -310,7 +324,7 @@ struct Glyph
all_points.extend (phantoms); all_points.extend (phantoms);
} }
if (depth == 0) /* Apply at top level */ if (depth == 0 && shift_points_hori) /* Apply at top level */
{ {
/* Undocumented rasterizer behavior: /* Undocumented rasterizer behavior:
* Shift points horizontally by the updated left side bearing * Shift points horizontally by the updated left side bearing
@@ -332,8 +346,14 @@ struct Glyph
hb_bytes_t get_bytes () const { return bytes; } hb_bytes_t get_bytes () const { return bytes; }
Glyph (hb_bytes_t bytes_ = hb_bytes_t (), Glyph () : bytes (),
hb_codepoint_t gid_ = (hb_codepoint_t) -1) : bytes (bytes_), header (bytes.as<GlyphHeader> ()),
gid (-1),
type(EMPTY)
{}
Glyph (hb_bytes_t bytes_,
hb_codepoint_t gid_ = (unsigned) -1) : bytes (bytes_),
header (bytes.as<GlyphHeader> ()), header (bytes.as<GlyphHeader> ()),
gid (gid_) gid (gid_)
{ {

View File

@@ -271,31 +271,29 @@ struct SimpleGlyph
} }
//convert absolute values to relative values //convert absolute values to relative values
unsigned num_points = all_points.length - 4; unsigned num_points = all_points.length - 4;
hb_vector_t<hb_pair_t<int, int>> deltas;
deltas.resize (num_points);
for (unsigned i = 0; i < num_points; i++)
{
deltas[i].first = i == 0 ? roundf (all_points[i].x) : roundf (all_points[i].x) - roundf (all_points[i-1].x);
deltas[i].second = i == 0 ? roundf (all_points[i].y) : roundf (all_points[i].y) - roundf (all_points[i-1].y);
}
hb_vector_t<uint8_t> flags, x_coords, y_coords; hb_vector_t<uint8_t> flags, x_coords, y_coords;
flags.alloc (num_points); if (unlikely (!flags.alloc (num_points))) return false;
x_coords.alloc (2*num_points); if (unlikely (!x_coords.alloc (2*num_points))) return false;
y_coords.alloc (2*num_points); if (unlikely (!y_coords.alloc (2*num_points))) return false;
uint8_t lastflag = 0, repeat = 0; uint8_t lastflag = 0, repeat = 0;
int prev_x = 0.f, prev_y = 0.f;
for (unsigned i = 0; i < num_points; i++) for (unsigned i = 0; i < num_points; i++)
{ {
uint8_t flag = all_points[i].flag; uint8_t flag = all_points[i].flag;
flag &= FLAG_ON_CURVE + FLAG_OVERLAP_SIMPLE; flag &= FLAG_ON_CURVE + FLAG_OVERLAP_SIMPLE;
encode_coord (deltas[i].first, flag, FLAG_X_SHORT, FLAG_X_SAME, x_coords); float cur_x = roundf (all_points[i].x);
encode_coord (deltas[i].second, flag, FLAG_Y_SHORT, FLAG_Y_SAME, y_coords); float cur_y = roundf (all_points[i].y);
encode_coord (cur_x - prev_x, flag, FLAG_X_SHORT, FLAG_X_SAME, x_coords);
encode_coord (cur_y - prev_y, flag, FLAG_Y_SHORT, FLAG_Y_SAME, y_coords);
if (i == 0) lastflag = flag + 1; //make lastflag != flag for the first point if (i == 0) lastflag = flag + 1; //make lastflag != flag for the first point
encode_flag (flag, repeat, lastflag, flags); encode_flag (flag, repeat, lastflag, flags);
prev_x = cur_x;
prev_y = cur_y;
} }
unsigned len_before_instrs = 2 * header.numberOfContours + 2; unsigned len_before_instrs = 2 * header.numberOfContours + 2;

View File

@@ -14,7 +14,6 @@ namespace glyf_impl {
struct SubsetGlyph struct SubsetGlyph
{ {
hb_codepoint_t new_gid;
hb_codepoint_t old_gid; hb_codepoint_t old_gid;
Glyph source_glyph; Glyph source_glyph;
hb_bytes_t dest_start; /* region of source_glyph to copy first */ hb_bytes_t dest_start; /* region of source_glyph to copy first */

View File

@@ -72,10 +72,13 @@ struct glyf
if (unlikely (!c->serializer->check_success (glyf_prime))) return_trace (false); if (unlikely (!c->serializer->check_success (glyf_prime))) return_trace (false);
hb_vector_t<glyf_impl::SubsetGlyph> glyphs; hb_vector_t<glyf_impl::SubsetGlyph> glyphs;
_populate_subset_glyphs (c->plan, &glyphs); _populate_subset_glyphs (c->plan, glyphs);
if (!c->plan->pinned_at_default) if (!c->plan->pinned_at_default)
_compile_subset_glyphs_with_deltas (c->plan, &glyphs); {
if (!_compile_subset_glyphs_with_deltas (c->plan, &glyphs))
return_trace (false);
}
auto padded_offsets = auto padded_offsets =
+ hb_iter (glyphs) + hb_iter (glyphs)
@@ -105,9 +108,9 @@ struct glyf
void void
_populate_subset_glyphs (const hb_subset_plan_t *plan, _populate_subset_glyphs (const hb_subset_plan_t *plan,
hb_vector_t<glyf_impl::SubsetGlyph> *glyphs /* OUT */) const; hb_vector_t<glyf_impl::SubsetGlyph> &glyphs /* OUT */) const;
void bool
_compile_subset_glyphs_with_deltas (const hb_subset_plan_t *plan, _compile_subset_glyphs_with_deltas (const hb_subset_plan_t *plan,
hb_vector_t<glyf_impl::SubsetGlyph> *glyphs /* OUT */) const; hb_vector_t<glyf_impl::SubsetGlyph> *glyphs /* OUT */) const;
@@ -180,7 +183,7 @@ struct glyf_accelerator_t
contour_point_vector_t all_points; contour_point_vector_t all_points;
bool phantom_only = !consumer.is_consuming_contour_points (); bool phantom_only = !consumer.is_consuming_contour_points ();
if (unlikely (!glyph_for_gid (gid).get_points (font, *this, all_points, nullptr, true, phantom_only))) if (unlikely (!glyph_for_gid (gid).get_points (font, *this, all_points, nullptr, true, true, phantom_only)))
return false; return false;
if (consumer.is_consuming_contour_points ()) if (consumer.is_consuming_contour_points ())
@@ -374,44 +377,43 @@ struct glyf_accelerator_t
inline void inline void
glyf::_populate_subset_glyphs (const hb_subset_plan_t *plan, glyf::_populate_subset_glyphs (const hb_subset_plan_t *plan,
hb_vector_t<glyf_impl::SubsetGlyph> *glyphs /* OUT */) const hb_vector_t<glyf_impl::SubsetGlyph>& glyphs /* OUT */) const
{ {
OT::glyf_accelerator_t glyf (plan->source); OT::glyf_accelerator_t glyf (plan->source);
unsigned num_glyphs = plan->num_output_glyphs ();
if (!glyphs.resize (num_glyphs)) return;
+ hb_range (plan->num_output_glyphs ()) for (auto p : plan->glyph_map->iter ())
| hb_map ([&] (hb_codepoint_t new_gid)
{ {
glyf_impl::SubsetGlyph subset_glyph = {0}; unsigned new_gid = p.second;
subset_glyph.new_gid = new_gid; glyf_impl::SubsetGlyph& subset_glyph = glyphs.arrayZ[new_gid];
subset_glyph.old_gid = p.first;
/* should never fail: all old gids should be mapped */ if (unlikely (new_gid == 0 &&
if (!plan->old_gid_for_new_gid (new_gid, &subset_glyph.old_gid)) !(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE)) &&
return subset_glyph; plan->pinned_at_default)
if (new_gid == 0 &&
!(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE))
subset_glyph.source_glyph = glyf_impl::Glyph (); subset_glyph.source_glyph = glyf_impl::Glyph ();
else else
subset_glyph.source_glyph = glyf.glyph_for_gid (subset_glyph.old_gid, true); subset_glyph.source_glyph = glyf.glyph_for_gid (subset_glyph.old_gid, true);
if (plan->flags & HB_SUBSET_FLAGS_NO_HINTING) if (plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
subset_glyph.drop_hints_bytes (); subset_glyph.drop_hints_bytes ();
else else
subset_glyph.dest_start = subset_glyph.source_glyph.get_bytes (); subset_glyph.dest_start = subset_glyph.source_glyph.get_bytes ();
return subset_glyph; }
})
| hb_sink (glyphs)
;
} }
inline void inline bool
glyf::_compile_subset_glyphs_with_deltas (const hb_subset_plan_t *plan, glyf::_compile_subset_glyphs_with_deltas (const hb_subset_plan_t *plan,
hb_vector_t<glyf_impl::SubsetGlyph> *glyphs /* OUT */) const hb_vector_t<glyf_impl::SubsetGlyph> *glyphs /* OUT */) const
{ {
OT::glyf_accelerator_t glyf (plan->source); OT::glyf_accelerator_t glyf (plan->source);
hb_font_t *font = hb_font_create (plan->source); hb_font_t *font = hb_font_create (plan->source);
if (unlikely (!font)) return false;
hb_vector_t<hb_variation_t> vars; hb_vector_t<hb_variation_t> vars;
vars.alloc (plan->user_axes_location->get_population ()); if (unlikely (!vars.alloc (plan->user_axes_location->get_population ())))
return false;
for (auto _ : *plan->user_axes_location) for (auto _ : *plan->user_axes_location)
{ {
@@ -423,9 +425,16 @@ glyf::_compile_subset_glyphs_with_deltas (const hb_subset_plan_t *plan,
hb_font_set_variations (font, vars.arrayZ, plan->user_axes_location->get_population ()); hb_font_set_variations (font, vars.arrayZ, plan->user_axes_location->get_population ());
for (auto& subset_glyph : *glyphs) for (auto& subset_glyph : *glyphs)
const_cast<glyf_impl::SubsetGlyph &> (subset_glyph).compile_bytes_with_deltas (plan, font, glyf); {
if (!const_cast<glyf_impl::SubsetGlyph &> (subset_glyph).compile_bytes_with_deltas (plan, font, glyf))
{
hb_font_destroy (font);
return false;
}
}
hb_font_destroy (font); hb_font_destroy (font);
return true;
} }

View File

@@ -70,8 +70,8 @@ struct graph_t
{ {
DEBUG_MSG (SUBSET_REPACK, nullptr, DEBUG_MSG (SUBSET_REPACK, nullptr,
"vertex [%lu] bytes != [%lu] bytes, depth = %u", "vertex [%lu] bytes != [%lu] bytes, depth = %u",
table_size (), (unsigned long) table_size (),
other.table_size (), (unsigned long) other.table_size (),
depth); depth);
auto a = as_bytes (); auto a = as_bytes ();
@@ -495,6 +495,12 @@ struct graph_t
return as_table_from_index<T> (index_for_offset (parent, offset), std::forward<Ts>(ds)...); return as_table_from_index<T> (index_for_offset (parent, offset), std::forward<Ts>(ds)...);
} }
template <typename T, typename ...Ts>
vertex_and_table_t<T> as_mutable_table (unsigned parent, const void* offset, Ts... ds)
{
return as_table_from_index<T> (mutable_index_for_offset (parent, offset), std::forward<Ts>(ds)...);
}
template <typename T, typename ...Ts> template <typename T, typename ...Ts>
vertex_and_table_t<T> as_table_from_index (unsigned index, Ts... ds) vertex_and_table_t<T> as_table_from_index (unsigned index, Ts... ds)
{ {
@@ -833,7 +839,20 @@ struct graph_t
* parent to the clone. The copy is a shallow copy, objects * parent to the clone. The copy is a shallow copy, objects
* linked from child are not duplicated. * linked from child are not duplicated.
*/ */
bool duplicate (unsigned parent_idx, unsigned child_idx) unsigned duplicate_if_shared (unsigned parent_idx, unsigned child_idx)
{
unsigned new_idx = duplicate (parent_idx, child_idx);
if (new_idx == (unsigned) -1) return child_idx;
return new_idx;
}
/*
* Creates a copy of child and re-assigns the link from
* parent to the clone. The copy is a shallow copy, objects
* linked from child are not duplicated.
*/
unsigned duplicate (unsigned parent_idx, unsigned child_idx)
{ {
update_parents (); update_parents ();
@@ -849,7 +868,7 @@ struct graph_t
// to child are from parent. // to child are from parent.
DEBUG_MSG (SUBSET_REPACK, nullptr, " Not duplicating %d => %d", DEBUG_MSG (SUBSET_REPACK, nullptr, " Not duplicating %d => %d",
parent_idx, child_idx); parent_idx, child_idx);
return false; return -1;
} }
DEBUG_MSG (SUBSET_REPACK, nullptr, " Duplicating %d => %d", DEBUG_MSG (SUBSET_REPACK, nullptr, " Duplicating %d => %d",
@@ -869,7 +888,7 @@ struct graph_t
reassign_link (l, parent_idx, clone_idx); reassign_link (l, parent_idx, clone_idx);
} }
return true; return clone_idx;
} }

View File

@@ -131,8 +131,10 @@ struct Lookup : public OT::Lookup
for (unsigned i = 0; i < subTable.len; i++) for (unsigned i = 0; i < subTable.len; i++)
{ {
unsigned subtable_index = c.graph.index_for_offset (this_index, &subTable[i]); unsigned subtable_index = c.graph.index_for_offset (this_index, &subTable[i]);
unsigned parent_index = this_index;
if (is_ext) { if (is_ext) {
unsigned ext_subtable_index = subtable_index; unsigned ext_subtable_index = subtable_index;
parent_index = ext_subtable_index;
ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>* extension = ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>* extension =
(ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>*) (ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>*)
c.graph.object (ext_subtable_index).head; c.graph.object (ext_subtable_index).head;
@@ -150,9 +152,9 @@ struct Lookup : public OT::Lookup
switch (type) switch (type)
{ {
case 2: case 2:
new_sub_tables = split_subtable<PairPos> (c, subtable_index); break; new_sub_tables = split_subtable<PairPos> (c, parent_index, subtable_index); break;
case 4: case 4:
new_sub_tables = split_subtable<MarkBasePos> (c, subtable_index); break; new_sub_tables = split_subtable<MarkBasePos> (c, parent_index, subtable_index); break;
default: default:
break; break;
} }
@@ -172,13 +174,14 @@ struct Lookup : public OT::Lookup
template<typename T> template<typename T>
hb_vector_t<unsigned> split_subtable (gsubgpos_graph_context_t& c, hb_vector_t<unsigned> split_subtable (gsubgpos_graph_context_t& c,
unsigned parent_idx,
unsigned objidx) unsigned objidx)
{ {
T* sub_table = (T*) c.graph.object (objidx).head; T* sub_table = (T*) c.graph.object (objidx).head;
if (!sub_table || !sub_table->sanitize (c.graph.vertices_[objidx])) if (!sub_table || !sub_table->sanitize (c.graph.vertices_[objidx]))
return hb_vector_t<unsigned> (); return hb_vector_t<unsigned> ();
return sub_table->split_subtables (c, objidx); return sub_table->split_subtables (c, parent_idx, objidx);
} }
void add_sub_tables (gsubgpos_graph_context_t& c, void add_sub_tables (gsubgpos_graph_context_t& c,

View File

@@ -209,7 +209,9 @@ struct MarkBasePosFormat1 : public OT::Layout::GPOS_impl::MarkBasePosFormat1_2<S
return vertex_len >= MarkBasePosFormat1::static_size; return vertex_len >= MarkBasePosFormat1::static_size;
} }
hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c, unsigned this_index) hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c,
unsigned parent_index,
unsigned this_index)
{ {
hb_set_t visited; hb_set_t visited;
@@ -261,7 +263,7 @@ struct MarkBasePosFormat1 : public OT::Layout::GPOS_impl::MarkBasePosFormat1_2<S
split_context_t split_context { split_context_t split_context {
c, c,
this, this,
this_index, c.graph.duplicate_if_shared (parent_index, this_index),
std::move (class_to_info), std::move (class_to_info),
c.graph.vertices_[mark_array_id].position_to_index_map (), c.graph.vertices_[mark_array_id].position_to_index_map (),
}; };
@@ -365,7 +367,7 @@ struct MarkBasePosFormat1 : public OT::Layout::GPOS_impl::MarkBasePosFormat1_2<S
classCount = count; classCount = count;
auto mark_coverage = sc.c.graph.as_table<Coverage> (this_index, auto mark_coverage = sc.c.graph.as_mutable_table<Coverage> (this_index,
&markCoverage); &markCoverage);
if (!mark_coverage) return false; if (!mark_coverage) return false;
hb_set_t marks = sc.marks_for (0, count); hb_set_t marks = sc.marks_for (0, count);
@@ -380,7 +382,7 @@ struct MarkBasePosFormat1 : public OT::Layout::GPOS_impl::MarkBasePosFormat1_2<S
return false; return false;
auto base_array = sc.c.graph.as_table<AnchorMatrix> (this_index, auto base_array = sc.c.graph.as_mutable_table<AnchorMatrix> (this_index,
&baseArray, &baseArray,
old_count); old_count);
if (!base_array || !base_array.table->shrink (sc.c, if (!base_array || !base_array.table->shrink (sc.c,
@@ -389,7 +391,7 @@ struct MarkBasePosFormat1 : public OT::Layout::GPOS_impl::MarkBasePosFormat1_2<S
count)) count))
return false; return false;
auto mark_array = sc.c.graph.as_table<MarkArray> (this_index, auto mark_array = sc.c.graph.as_mutable_table<MarkArray> (this_index,
&markArray); &markArray);
if (!mark_array || !mark_array.table->shrink (sc.c, if (!mark_array || !mark_array.table->shrink (sc.c,
sc.mark_array_links, sc.mark_array_links,
@@ -469,11 +471,12 @@ struct MarkBasePosFormat1 : public OT::Layout::GPOS_impl::MarkBasePosFormat1_2<S
struct MarkBasePos : public OT::Layout::GPOS_impl::MarkBasePos struct MarkBasePos : public OT::Layout::GPOS_impl::MarkBasePos
{ {
hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c, hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c,
unsigned parent_index,
unsigned this_index) unsigned this_index)
{ {
switch (u.format) { switch (u.format) {
case 1: case 1:
return ((MarkBasePosFormat1*)(&u.format1))->split_subtables (c, this_index); return ((MarkBasePosFormat1*)(&u.format1))->split_subtables (c, parent_index, this_index);
#ifndef HB_NO_BORING_EXPANSION #ifndef HB_NO_BORING_EXPANSION
case 2: HB_FALLTHROUGH; case 2: HB_FALLTHROUGH;
// Don't split 24bit PairPos's. // Don't split 24bit PairPos's.

View File

@@ -47,7 +47,9 @@ struct PairPosFormat1 : public OT::Layout::GPOS_impl::PairPosFormat1_3<SmallType
min_size + pairSet.get_size () - pairSet.len.get_size(); min_size + pairSet.get_size () - pairSet.len.get_size();
} }
hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c, unsigned this_index) hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c,
unsigned parent_index,
unsigned this_index)
{ {
hb_set_t visited; hb_set_t visited;
@@ -81,7 +83,7 @@ struct PairPosFormat1 : public OT::Layout::GPOS_impl::PairPosFormat1_3<SmallType
split_context_t split_context { split_context_t split_context {
c, c,
this, this,
this_index, c.graph.duplicate_if_shared (parent_index, this_index),
}; };
return actuate_subtable_split<split_context_t> (split_context, split_points); return actuate_subtable_split<split_context_t> (split_context, split_points);
@@ -125,23 +127,19 @@ struct PairPosFormat1 : public OT::Layout::GPOS_impl::PairPosFormat1_3<SmallType
pairSet.len = count; pairSet.len = count;
c.graph.vertices_[this_index].obj.tail -= (old_count - count) * SmallTypes::size; c.graph.vertices_[this_index].obj.tail -= (old_count - count) * SmallTypes::size;
unsigned coverage_id = c.graph.mutable_index_for_offset (this_index, &coverage); auto coverage = c.graph.as_mutable_table<Coverage> (this_index, &this->coverage);
unsigned coverage_size = c.graph.vertices_[coverage_id].table_size (); if (!coverage) return false;
auto& coverage_v = c.graph.vertices_[coverage_id];
Coverage* coverage_table = (Coverage*) coverage_v.obj.head;
if (!coverage_table || !coverage_table->sanitize (coverage_v))
return false;
unsigned coverage_size = coverage.vertex->table_size ();
auto new_coverage = auto new_coverage =
+ hb_zip (coverage_table->iter (), hb_range ()) + hb_zip (coverage.table->iter (), hb_range ())
| hb_filter ([&] (hb_pair_t<unsigned, unsigned> p) { | hb_filter ([&] (hb_pair_t<unsigned, unsigned> p) {
return p.second < count; return p.second < count;
}) })
| hb_map_retains_sorting (hb_first) | hb_map_retains_sorting (hb_first)
; ;
return Coverage::make_coverage (c, new_coverage, coverage_id, coverage_size); return Coverage::make_coverage (c, new_coverage, coverage.index, coverage_size);
} }
// Create a new PairPos including PairSet's from start (inclusive) to end (exclusive). // Create a new PairPos including PairSet's from start (inclusive) to end (exclusive).
@@ -206,7 +204,9 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4<SmallType
min_size + class1_count * get_class1_record_size (); min_size + class1_count * get_class1_record_size ();
} }
hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c, unsigned this_index) hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c,
unsigned parent_index,
unsigned this_index)
{ {
const unsigned base_size = OT::Layout::GPOS_impl::PairPosFormat2_4<SmallTypes>::min_size; const unsigned base_size = OT::Layout::GPOS_impl::PairPosFormat2_4<SmallTypes>::min_size;
const unsigned class_def_2_size = size_of (c, this_index, &classDef2); const unsigned class_def_2_size = size_of (c, this_index, &classDef2);
@@ -287,7 +287,7 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4<SmallType
split_context_t split_context { split_context_t split_context {
c, c,
this, this,
this_index, c.graph.duplicate_if_shared (parent_index, this_index),
class1_record_size, class1_record_size,
total_value_len, total_value_len,
value_1_len, value_1_len,
@@ -508,40 +508,37 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4<SmallType
graph.vertices_[split_context.this_index].obj.tail -= graph.vertices_[split_context.this_index].obj.tail -=
(old_count - count) * split_context.class1_record_size; (old_count - count) * split_context.class1_record_size;
unsigned coverage_id = auto coverage =
graph.mutable_index_for_offset (split_context.this_index, &coverage); graph.as_mutable_table<Coverage> (split_context.this_index, &this->coverage);
unsigned class_def_1_id = if (!coverage) return false;
graph.mutable_index_for_offset (split_context.this_index, &classDef1);
auto& coverage_v = graph.vertices_[coverage_id]; auto class_def_1 =
auto& class_def_1_v = graph.vertices_[class_def_1_id]; graph.as_mutable_table<ClassDef> (split_context.this_index, &classDef1);
Coverage* coverage_table = (Coverage*) coverage_v.obj.head; if (!class_def_1) return false;
ClassDef* class_def_1_table = (ClassDef*) class_def_1_v.obj.head;
if (!coverage_table
|| !coverage_table->sanitize (coverage_v)
|| !class_def_1_table
|| !class_def_1_table->sanitize (class_def_1_v))
return false;
auto klass_map = auto klass_map =
+ coverage_table->iter () + coverage.table->iter ()
| hb_map_retains_sorting ([&] (hb_codepoint_t gid) { | hb_map_retains_sorting ([&] (hb_codepoint_t gid) {
return hb_pair_t<hb_codepoint_t, hb_codepoint_t> (gid, class_def_1_table->get_class (gid)); return hb_pair_t<hb_codepoint_t, hb_codepoint_t> (gid, class_def_1.table->get_class (gid));
}) })
| hb_filter ([&] (hb_codepoint_t klass) { | hb_filter ([&] (hb_codepoint_t klass) {
return klass < count; return klass < count;
}, hb_second) }, hb_second)
; ;
auto new_coverage = + klass_map | hb_map_retains_sorting (hb_first);
if (!Coverage::make_coverage (split_context.c, if (!Coverage::make_coverage (split_context.c,
+ klass_map | hb_map_retains_sorting (hb_first), + new_coverage,
coverage_id, coverage.index,
coverage_v.table_size ())) // existing ranges my not be kept, worst case size is a format 1
// coverage table.
4 + new_coverage.len() * 2))
return false; return false;
return ClassDef::make_class_def (split_context.c, return ClassDef::make_class_def (split_context.c,
+ klass_map, + klass_map,
class_def_1_id, class_def_1.index,
class_def_1_v.table_size ()); class_def_1.vertex->table_size ());
} }
hb_hashmap_t<unsigned, unsigned> hb_hashmap_t<unsigned, unsigned>
@@ -605,13 +602,15 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4<SmallType
struct PairPos : public OT::Layout::GPOS_impl::PairPos struct PairPos : public OT::Layout::GPOS_impl::PairPos
{ {
hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c, unsigned this_index) hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c,
unsigned parent_index,
unsigned this_index)
{ {
switch (u.format) { switch (u.format) {
case 1: case 1:
return ((PairPosFormat1*)(&u.format1))->split_subtables (c, this_index); return ((PairPosFormat1*)(&u.format1))->split_subtables (c, parent_index, this_index);
case 2: case 2:
return ((PairPosFormat2*)(&u.format2))->split_subtables (c, this_index); return ((PairPosFormat2*)(&u.format2))->split_subtables (c, parent_index, this_index);
#ifndef HB_NO_BORING_EXPANSION #ifndef HB_NO_BORING_EXPANSION
case 3: HB_FALLTHROUGH; case 3: HB_FALLTHROUGH;
case 4: HB_FALLTHROUGH; case 4: HB_FALLTHROUGH;

View File

@@ -70,9 +70,9 @@ struct DecompositionAction
ActionSubrecordHeader ActionSubrecordHeader
header; header;
HBFixed lowerLimit; /* If the distance factor is less than this value, F16DOT16 lowerLimit; /* If the distance factor is less than this value,
* then the ligature is decomposed. */ * then the ligature is decomposed. */
HBFixed upperLimit; /* If the distance factor is greater than this value, F16DOT16 upperLimit; /* If the distance factor is greater than this value,
* then the ligature is decomposed. */ * then the ligature is decomposed. */
HBUINT16 order; /* Numerical order in which this ligature will HBUINT16 order; /* Numerical order in which this ligature will
* be decomposed; you may want infrequent ligatures * be decomposed; you may want infrequent ligatures
@@ -118,7 +118,7 @@ struct ConditionalAddGlyphAction
protected: protected:
ActionSubrecordHeader ActionSubrecordHeader
header; header;
HBFixed substThreshold; /* Distance growth factor (in ems) at which F16DOT16 substThreshold; /* Distance growth factor (in ems) at which
* this glyph is replaced and the growth factor * this glyph is replaced and the growth factor
* recalculated. */ * recalculated. */
HBGlyphID16 addGlyph; /* Glyph to be added as kashida. If this value is HBGlyphID16 addGlyph; /* Glyph to be added as kashida. If this value is
@@ -146,13 +146,13 @@ struct DuctileGlyphAction
HBUINT32 variationAxis; /* The 4-byte tag identifying the ductile axis. HBUINT32 variationAxis; /* The 4-byte tag identifying the ductile axis.
* This would normally be 0x64756374 ('duct'), * This would normally be 0x64756374 ('duct'),
* but you may use any axis the font contains. */ * but you may use any axis the font contains. */
HBFixed minimumLimit; /* The lowest value for the ductility axis that F16DOT16 minimumLimit; /* The lowest value for the ductility axis that
* still yields an acceptable appearance. Normally * still yields an acceptable appearance. Normally
* this will be 1.0. */ * this will be 1.0. */
HBFixed noStretchValue; /* This is the default value that corresponds to F16DOT16 noStretchValue; /* This is the default value that corresponds to
* no change in appearance. Normally, this will * no change in appearance. Normally, this will
* be 1.0. */ * be 1.0. */
HBFixed maximumLimit; /* The highest value for the ductility axis that F16DOT16 maximumLimit; /* The highest value for the ductility axis that
* still yields an acceptable appearance. */ * still yields an acceptable appearance. */
public: public:
DEFINE_SIZE_STATIC (22); DEFINE_SIZE_STATIC (22);
@@ -271,14 +271,14 @@ struct JustWidthDeltaEntry
}; };
protected: protected:
HBFixed beforeGrowLimit;/* The ratio by which the advance width of the F16DOT16 beforeGrowLimit;/* The ratio by which the advance width of the
* glyph is permitted to grow on the left or top side. */ * glyph is permitted to grow on the left or top side. */
HBFixed beforeShrinkLimit; F16DOT16 beforeShrinkLimit;
/* The ratio by which the advance width of the /* The ratio by which the advance width of the
* glyph is permitted to shrink on the left or top side. */ * glyph is permitted to shrink on the left or top side. */
HBFixed afterGrowLimit; /* The ratio by which the advance width of the glyph F16DOT16 afterGrowLimit; /* The ratio by which the advance width of the glyph
* is permitted to shrink on the left or top side. */ * is permitted to shrink on the left or top side. */
HBFixed afterShrinkLimit; F16DOT16 afterShrinkLimit;
/* The ratio by which the advance width of the glyph /* The ratio by which the advance width of the glyph
* is at most permitted to shrink on the right or * is at most permitted to shrink on the right or
* bottom side. */ * bottom side. */

View File

@@ -62,7 +62,7 @@ struct TrackTableEntry
} }
protected: protected:
HBFixed track; /* Track value for this record. */ F16DOT16 track; /* Track value for this record. */
NameID trackNameID; /* The 'name' table index for this track. NameID trackNameID; /* The 'name' table index for this track.
* (a short word or phrase like "loose" * (a short word or phrase like "loose"
* or "very tight") */ * or "very tight") */
@@ -82,7 +82,7 @@ struct TrackData
const void *base) const const void *base) const
{ {
unsigned int sizes = nSizes; unsigned int sizes = nSizes;
hb_array_t<const HBFixed> size_table ((base+sizeTable).arrayZ, sizes); hb_array_t<const F16DOT16> size_table ((base+sizeTable).arrayZ, sizes);
float s0 = size_table[idx].to_float (); float s0 = size_table[idx].to_float ();
float s1 = size_table[idx + 1].to_float (); float s1 = size_table[idx + 1].to_float ();
@@ -120,7 +120,7 @@ struct TrackData
if (!sizes) return 0.; if (!sizes) return 0.;
if (sizes == 1) return trackTableEntry->get_value (base, 0, sizes); if (sizes == 1) return trackTableEntry->get_value (base, 0, sizes);
hb_array_t<const HBFixed> size_table ((base+sizeTable).arrayZ, sizes); hb_array_t<const F16DOT16> size_table ((base+sizeTable).arrayZ, sizes);
unsigned int size_index; unsigned int size_index;
for (size_index = 0; size_index < sizes - 1; size_index++) for (size_index = 0; size_index < sizes - 1; size_index++)
if (size_table[size_index].to_float () >= ptem) if (size_table[size_index].to_float () >= ptem)
@@ -141,7 +141,7 @@ struct TrackData
protected: protected:
HBUINT16 nTracks; /* Number of separate tracks included in this table. */ HBUINT16 nTracks; /* Number of separate tracks included in this table. */
HBUINT16 nSizes; /* Number of point sizes included in this table. */ HBUINT16 nSizes; /* Number of point sizes included in this table. */
NNOffset32To<UnsizedArrayOf<HBFixed>> NNOffset32To<UnsizedArrayOf<F16DOT16>>
sizeTable; /* Offset from start of the tracking table to sizeTable; /* Offset from start of the tracking table to
* Array[nSizes] of size values.. */ * Array[nSizes] of size values.. */
UnsizedArrayOf<TrackTableEntry> UnsizedArrayOf<TrackTableEntry>

View File

@@ -131,6 +131,7 @@ static const hb_aat_feature_mapping_t feature_mappings[] =
{HB_TAG ('p','n','u','m'), HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_NUMBERS, (hb_aat_layout_feature_selector_t) 4}, {HB_TAG ('p','n','u','m'), HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_NUMBERS, (hb_aat_layout_feature_selector_t) 4},
{HB_TAG ('p','w','i','d'), HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_TEXT, (hb_aat_layout_feature_selector_t) 7}, {HB_TAG ('p','w','i','d'), HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_TEXT, (hb_aat_layout_feature_selector_t) 7},
{HB_TAG ('q','w','i','d'), HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_QUARTER_WIDTH_TEXT, (hb_aat_layout_feature_selector_t) 7}, {HB_TAG ('q','w','i','d'), HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_QUARTER_WIDTH_TEXT, (hb_aat_layout_feature_selector_t) 7},
{HB_TAG ('r','l','i','g'), HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES, HB_AAT_LAYOUT_FEATURE_SELECTOR_REQUIRED_LIGATURES_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_REQUIRED_LIGATURES_OFF},
{HB_TAG ('r','u','b','y'), HB_AAT_LAYOUT_FEATURE_TYPE_RUBY_KANA, HB_AAT_LAYOUT_FEATURE_SELECTOR_RUBY_KANA_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_RUBY_KANA_OFF}, {HB_TAG ('r','u','b','y'), HB_AAT_LAYOUT_FEATURE_TYPE_RUBY_KANA, HB_AAT_LAYOUT_FEATURE_SELECTOR_RUBY_KANA_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_RUBY_KANA_OFF},
{HB_TAG ('s','i','n','f'), HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_POSITION, HB_AAT_LAYOUT_FEATURE_SELECTOR_SCIENTIFIC_INFERIORS, HB_AAT_LAYOUT_FEATURE_SELECTOR_NORMAL_POSITION}, {HB_TAG ('s','i','n','f'), HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_POSITION, HB_AAT_LAYOUT_FEATURE_SELECTOR_SCIENTIFIC_INFERIORS, HB_AAT_LAYOUT_FEATURE_SELECTOR_NORMAL_POSITION},
{HB_TAG ('s','m','c','p'), HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE, HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_SMALL_CAPS, HB_AAT_LAYOUT_FEATURE_SELECTOR_DEFAULT_LOWER_CASE}, {HB_TAG ('s','m','c','p'), HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE, HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_SMALL_CAPS, HB_AAT_LAYOUT_FEATURE_SELECTOR_DEFAULT_LOWER_CASE},

View File

@@ -71,6 +71,7 @@
#define HB_NO_LANGUAGE_PRIVATE_SUBTAG #define HB_NO_LANGUAGE_PRIVATE_SUBTAG
#define HB_NO_LAYOUT_FEATURE_PARAMS #define HB_NO_LAYOUT_FEATURE_PARAMS
#define HB_NO_LAYOUT_COLLECT_GLYPHS #define HB_NO_LAYOUT_COLLECT_GLYPHS
#define HB_NO_LAYOUT_RARELY_USED
#define HB_NO_LAYOUT_UNUSED #define HB_NO_LAYOUT_UNUSED
#define HB_NO_MATH #define HB_NO_MATH
#define HB_NO_META #define HB_NO_META

View File

@@ -69,9 +69,9 @@ struct shared_ptr
operator T * () const { return p; } operator T * () const { return p; }
T& operator * () const { return *get (); } T& operator * () const { return *get (); }
T* operator -> () const { return get (); } T* operator -> () const { return get (); }
operator bool () { return p; } operator bool () const { return p; }
bool operator == (const shared_ptr &o) { return p == o.p; } bool operator == (const shared_ptr &o) const { return p == o.p; }
bool operator != (const shared_ptr &o) { return p != o.p; } bool operator != (const shared_ptr &o) const { return p != o.p; }
static T* get_empty() { return v::get_empty (); } static T* get_empty() { return v::get_empty (); }
T* reference() { return v::reference (p); } T* reference() { return v::reference (p); }

View File

@@ -633,20 +633,29 @@ hb_face_collect_variation_unicodes (hb_face_t *face,
* face-builder: A face that has add_table(). * face-builder: A face that has add_table().
*/ */
struct face_table_info_t
{
hb_blob_t* data;
unsigned order;
};
struct hb_face_builder_data_t struct hb_face_builder_data_t
{ {
hb_hashmap_t<hb_tag_t, hb_blob_t *> tables; hb_hashmap_t<hb_tag_t, face_table_info_t> tables;
}; };
static int compare_entries (const void* pa, const void* pb) static int compare_entries (const void* pa, const void* pb)
{ {
const auto& a = * (const hb_pair_t<hb_tag_t, hb_blob_t*> *) pa; const auto& a = * (const hb_pair_t<hb_tag_t, face_table_info_t> *) pa;
const auto& b = * (const hb_pair_t<hb_tag_t, hb_blob_t*> *) pb; const auto& b = * (const hb_pair_t<hb_tag_t, face_table_info_t> *) pb;
/* Order by blob size first (smallest to largest) and then table tag */ /* Order by blob size first (smallest to largest) and then table tag */
if (a.second->length != b.second->length) if (a.second.order != b.second.order)
return a.second->length < b.second->length ? -1 : +1; return a.second.order < b.second.order ? -1 : +1;
if (a.second.data->length != b.second.data->length)
return a.second.data->length < b.second.data->length ? -1 : +1;
return a.first < b.first ? -1 : a.first == b.first ? 0 : +1; return a.first < b.first ? -1 : a.first == b.first ? 0 : +1;
} }
@@ -668,8 +677,8 @@ _hb_face_builder_data_destroy (void *user_data)
{ {
hb_face_builder_data_t *data = (hb_face_builder_data_t *) user_data; hb_face_builder_data_t *data = (hb_face_builder_data_t *) user_data;
for (hb_blob_t* b : data->tables.values()) for (auto info : data->tables.values())
hb_blob_destroy (b); hb_blob_destroy (info.data);
data->tables.fini (); data->tables.fini ();
@@ -683,8 +692,8 @@ _hb_face_builder_data_reference_blob (hb_face_builder_data_t *data)
unsigned int table_count = data->tables.get_population (); unsigned int table_count = data->tables.get_population ();
unsigned int face_length = table_count * 16 + 12; unsigned int face_length = table_count * 16 + 12;
for (hb_blob_t* b : data->tables.values()) for (auto info : data->tables.values())
face_length += hb_ceil_to_4 (hb_blob_get_length (b)); face_length += hb_ceil_to_4 (hb_blob_get_length (info.data));
char *buf = (char *) hb_malloc (face_length); char *buf = (char *) hb_malloc (face_length);
if (unlikely (!buf)) if (unlikely (!buf))
@@ -699,7 +708,7 @@ _hb_face_builder_data_reference_blob (hb_face_builder_data_t *data)
hb_tag_t sfnt_tag = is_cff ? OT::OpenTypeFontFile::CFFTag : OT::OpenTypeFontFile::TrueTypeTag; hb_tag_t sfnt_tag = is_cff ? OT::OpenTypeFontFile::CFFTag : OT::OpenTypeFontFile::TrueTypeTag;
// Sort the tags so that produced face is deterministic. // Sort the tags so that produced face is deterministic.
hb_vector_t<hb_pair_t <hb_tag_t, hb_blob_t*>> sorted_entries; hb_vector_t<hb_pair_t <hb_tag_t, face_table_info_t>> sorted_entries;
data->tables.iter () | hb_sink (sorted_entries); data->tables.iter () | hb_sink (sorted_entries);
if (unlikely (sorted_entries.in_error ())) if (unlikely (sorted_entries.in_error ()))
{ {
@@ -708,7 +717,13 @@ _hb_face_builder_data_reference_blob (hb_face_builder_data_t *data)
} }
sorted_entries.qsort (compare_entries); sorted_entries.qsort (compare_entries);
bool ret = f->serialize_single (&c, sfnt_tag, + sorted_entries.iter());
bool ret = f->serialize_single (&c,
sfnt_tag,
+ sorted_entries.iter()
| hb_map ([&] (hb_pair_t<hb_tag_t, face_table_info_t> _) {
return hb_pair_t<hb_tag_t, hb_blob_t*> (_.first, _.second.data);
}));
c.end_serialize (); c.end_serialize ();
@@ -729,7 +744,7 @@ _hb_face_builder_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void
if (!tag) if (!tag)
return _hb_face_builder_data_reference_blob (data); return _hb_face_builder_data_reference_blob (data);
return hb_blob_reference (data->tables[tag]); return hb_blob_reference (data->tables[tag].data);
} }
@@ -777,8 +792,8 @@ hb_face_builder_add_table (hb_face_t *face, hb_tag_t tag, hb_blob_t *blob)
hb_face_builder_data_t *data = (hb_face_builder_data_t *) face->user_data; hb_face_builder_data_t *data = (hb_face_builder_data_t *) face->user_data;
hb_blob_t* previous = data->tables.get (tag); hb_blob_t* previous = data->tables.get (tag).data;
if (!data->tables.set (tag, hb_blob_reference (blob))) if (!data->tables.set (tag, face_table_info_t {hb_blob_reference (blob), 0}))
{ {
hb_blob_destroy (blob); hb_blob_destroy (blob);
return false; return false;
@@ -787,3 +802,36 @@ hb_face_builder_add_table (hb_face_t *face, hb_tag_t tag, hb_blob_t *blob)
hb_blob_destroy (previous); hb_blob_destroy (previous);
return true; return true;
} }
/**
* hb_face_builder_sort_tables:
* @face: A face object created with hb_face_builder_create()
* @tags: (array zero-terminated=1): ordered list of table tags terminated by
* %HB_TAG_NONE
*
* Set the ordering of tables for serialization. Any tables not
* specified in the tags list will be ordered after the tables in
* tags, ordered by the default sort ordering.
*
* Since: 5.3.0
**/
void
hb_face_builder_sort_tables (hb_face_t *face,
const hb_tag_t *tags)
{
hb_face_builder_data_t *data = (hb_face_builder_data_t *) face->user_data;
// Sort all unspecified tables after any specified tables.
for (auto& info : data->tables.values_ref())
info.order = -1;
unsigned order = 0;
for (const hb_tag_t* tag = tags;
*tag;
tag++)
{
face_table_info_t* info;
if (!data->tables.has (*tag, &info)) continue;
info->order = order++;
}
}

View File

@@ -171,6 +171,10 @@ hb_face_builder_add_table (hb_face_t *face,
hb_tag_t tag, hb_tag_t tag,
hb_blob_t *blob); hb_blob_t *blob);
HB_EXTERN void
hb_face_builder_sort_tables (hb_face_t *face,
const hb_tag_t *tags);
HB_END_DECLS HB_END_DECLS

View File

@@ -133,6 +133,18 @@ struct
template <typename T> constexpr auto template <typename T> constexpr auto
operator () (T *v) const HB_AUTO_RETURN (*v) operator () (T *v) const HB_AUTO_RETURN (*v)
template <typename T> constexpr auto
operator () (const hb::shared_ptr<T>& v) const HB_AUTO_RETURN (*v)
template <typename T> constexpr auto
operator () (hb::shared_ptr<T>& v) const HB_AUTO_RETURN (*v)
template <typename T> constexpr auto
operator () (const hb::unique_ptr<T>& v) const HB_AUTO_RETURN (*v)
template <typename T> constexpr auto
operator () (hb::unique_ptr<T>& v) const HB_AUTO_RETURN (*v)
} }
HB_FUNCOBJ (hb_deref); HB_FUNCOBJ (hb_deref);

View File

@@ -141,27 +141,24 @@ typedef HBINT32 FWORD32;
/* 16-bit unsigned integer (HBUINT16) that describes a quantity in FUnits. */ /* 16-bit unsigned integer (HBUINT16) that describes a quantity in FUnits. */
typedef HBUINT16 UFWORD; typedef HBUINT16 UFWORD;
/* 16-bit signed fixed number with the low 14 bits of fraction (2.14). */ template <typename Type, unsigned fraction_bits>
struct F2DOT14 : HBINT16 struct HBFixed : Type
{ {
F2DOT14& operator = (uint16_t i ) { HBINT16::operator= (i); return *this; } static constexpr float shift = (float) (1 << fraction_bits);
// 16384 means 1<<14 static_assert (Type::static_size * 8 > fraction_bits, "");
float to_float () const { return ((int32_t) v) / 16384.f; }
void set_float (float f) { v = roundf (f * 16384.f); } HBFixed& operator = (typename Type::type i ) { Type::operator= (i); return *this; }
float to_float () const { return ((int32_t) Type::v) / shift; }
void set_float (float f) { Type::v = roundf (f * shift); }
public: public:
DEFINE_SIZE_STATIC (2); DEFINE_SIZE_STATIC (Type::static_size);
}; };
/* 16-bit signed fixed number with the low 14 bits of fraction (2.14). */
using F2DOT14 = HBFixed<HBINT16, 14>;
/* 32-bit signed fixed-point number (16.16). */ /* 32-bit signed fixed-point number (16.16). */
struct HBFixed : HBINT32 using F16DOT16 = HBFixed<HBINT32, 16>;
{
HBFixed& operator = (uint32_t i) { HBINT32::operator= (i); return *this; }
// 65536 means 1<<16
float to_float () const { return ((int32_t) v) / 65536.f; }
void set_float (float f) { v = roundf (f * 65536.f); }
public:
DEFINE_SIZE_STATIC (4);
};
/* Date represented in number of seconds since 12:00 midnight, January 1, /* Date represented in number of seconds since 12:00 midnight, January 1,
* 1904. The value is represented as a signed 64-bit integer. */ * 1904. The value is represented as a signed 64-bit integer. */

View File

@@ -358,14 +358,14 @@ struct Affine2x3
return_trace (c->check_struct (this)); return_trace (c->check_struct (this));
} }
HBFixed xx; F16DOT16 xx;
HBFixed yx; F16DOT16 yx;
HBFixed xy; F16DOT16 xy;
HBFixed yy; F16DOT16 yy;
HBFixed dx; F16DOT16 dx;
HBFixed dy; F16DOT16 dy;
public: public:
DEFINE_SIZE_STATIC (6 * HBFixed::static_size); DEFINE_SIZE_STATIC (6 * F16DOT16::static_size);
}; };
struct PaintColrLayers struct PaintColrLayers

View File

@@ -295,8 +295,8 @@ hb_ot_color_has_png (hb_face_t *face)
* @glyph: a glyph index * @glyph: a glyph index
* *
* Fetches the PNG image for a glyph. This function takes a font object, not a face object, * Fetches the PNG image for a glyph. This function takes a font object, not a face object,
* as input. To get an optimally sized PNG blob, the UPEM value must be set on the @font * as input. To get an optimally sized PNG blob, the PPEM values must be set on the @font
* object. If UPEM is unset, the blob returned will be the largest PNG available. * object. If PPEM is unset, the blob returned will be the largest PNG available.
* *
* If the glyph has no PNG image, the singleton empty blob is returned. * If the glyph has no PNG image, the singleton empty blob is returned.
* *

View File

@@ -40,7 +40,6 @@
#include "hb-ot-cff1-table.hh" #include "hb-ot-cff1-table.hh"
#include "hb-ot-cff2-table.hh" #include "hb-ot-cff2-table.hh"
#include "hb-ot-hmtx-table.hh" #include "hb-ot-hmtx-table.hh"
#include "hb-ot-os2-table.hh"
#include "hb-ot-post-table.hh" #include "hb-ot-post-table.hh"
#include "hb-ot-stat-table.hh" // Just so we compile it; unused otherwise. #include "hb-ot-stat-table.hh" // Just so we compile it; unused otherwise.
#include "hb-ot-vorg-table.hh" #include "hb-ot-vorg-table.hh"
@@ -349,15 +348,13 @@ hb_ot_get_glyph_extents (hb_font_t *font,
#if !defined(HB_NO_OT_FONT_BITMAP) && !defined(HB_NO_COLOR) #if !defined(HB_NO_OT_FONT_BITMAP) && !defined(HB_NO_COLOR)
if (ot_face->sbix->get_extents (font, glyph, extents)) return true; if (ot_face->sbix->get_extents (font, glyph, extents)) return true;
if (ot_face->CBDT->get_extents (font, glyph, extents)) return true;
#endif #endif
if (ot_face->glyf->get_extents (font, glyph, extents)) return true; if (ot_face->glyf->get_extents (font, glyph, extents)) return true;
#ifndef HB_NO_OT_FONT_CFF #ifndef HB_NO_OT_FONT_CFF
if (ot_face->cff1->get_extents (font, glyph, extents)) return true; if (ot_face->cff1->get_extents (font, glyph, extents)) return true;
if (ot_face->cff2->get_extents (font, glyph, extents)) return true; if (ot_face->cff2->get_extents (font, glyph, extents)) return true;
#endif #endif
#if !defined(HB_NO_OT_FONT_BITMAP) && !defined(HB_NO_COLOR)
if (ot_face->CBDT->get_extents (font, glyph, extents)) return true;
#endif
// TODO Hook up side-bearings variations. // TODO Hook up side-bearings variations.
return false; return false;

View File

@@ -94,6 +94,19 @@ static bool ClassDef_remap_and_serialize (
hb_sorted_vector_t<hb_pair_t<hb_codepoint_t, hb_codepoint_t>> &glyph_and_klass, /* IN/OUT */ hb_sorted_vector_t<hb_pair_t<hb_codepoint_t, hb_codepoint_t>> &glyph_and_klass, /* IN/OUT */
hb_map_t *klass_map /*IN/OUT*/); hb_map_t *klass_map /*IN/OUT*/);
struct hb_collect_feature_substitutes_with_var_context_t
{
const hb_map_t *axes_index_tag_map;
const hb_hashmap_t<hb_tag_t, int> *axes_location;
hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *record_cond_idx_map;
hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map;
// not stored in subset_plan
hb_set_t *feature_indices;
bool apply;
unsigned cur_record_idx;
hb_hashmap_t<hb::shared_ptr<hb_map_t>, unsigned> *conditionset_map;
};
struct hb_prune_langsys_context_t struct hb_prune_langsys_context_t
{ {
@@ -160,24 +173,40 @@ struct hb_subset_layout_context_t :
const hb_map_t *lookup_index_map; const hb_map_t *lookup_index_map;
const hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> *script_langsys_map; const hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> *script_langsys_map;
const hb_map_t *feature_index_map; const hb_map_t *feature_index_map;
const hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map;
hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *feature_record_cond_idx_map;
unsigned cur_script_index; unsigned cur_script_index;
unsigned cur_feature_var_record_idx;
hb_subset_layout_context_t (hb_subset_context_t *c_, hb_subset_layout_context_t (hb_subset_context_t *c_,
hb_tag_t tag_, hb_tag_t tag_) :
hb_map_t *lookup_map_,
hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> *script_langsys_map_,
hb_map_t *feature_index_map_) :
subset_context (c_), subset_context (c_),
table_tag (tag_), table_tag (tag_),
lookup_index_map (lookup_map_),
script_langsys_map (script_langsys_map_),
feature_index_map (feature_index_map_),
cur_script_index (0xFFFFu), cur_script_index (0xFFFFu),
cur_feature_var_record_idx (0u),
script_count (0), script_count (0),
langsys_count (0), langsys_count (0),
feature_index_count (0), feature_index_count (0),
lookup_index_count (0) lookup_index_count (0)
{} {
if (tag_ == HB_OT_TAG_GSUB)
{
lookup_index_map = c_->plan->gsub_lookups;
script_langsys_map = c_->plan->gsub_langsys;
feature_index_map = c_->plan->gsub_features;
feature_substitutes_map = c_->plan->gsub_feature_substitutes_map;
feature_record_cond_idx_map = c_->plan->user_axes_location->is_empty () ? nullptr : c_->plan->gsub_feature_record_cond_idx_map;
}
else
{
lookup_index_map = c_->plan->gpos_lookups;
script_langsys_map = c_->plan->gpos_langsys;
feature_index_map = c_->plan->gpos_features;
feature_substitutes_map = c_->plan->gpos_feature_substitutes_map;
feature_record_cond_idx_map = c_->plan->user_axes_location->is_empty () ? nullptr : c_->plan->gpos_feature_record_cond_idx_map;
}
}
private: private:
unsigned script_count; unsigned script_count;
@@ -324,6 +353,31 @@ struct subset_record_array_t
const void *base; const void *base;
}; };
template<typename OutputArray, typename Arg>
struct subset_record_array_arg_t
{
subset_record_array_arg_t (hb_subset_layout_context_t *c_, OutputArray* out_,
const void *base_,
Arg &&arg_) : subset_layout_context (c_),
out (out_), base (base_), arg (arg_) {}
template <typename T>
void
operator () (T&& record)
{
auto snap = subset_layout_context->subset_context->serializer->snapshot ();
bool ret = record.subset (subset_layout_context, base, arg);
if (!ret) subset_layout_context->subset_context->serializer->revert (snap);
else out->len++;
}
private:
hb_subset_layout_context_t *subset_layout_context;
OutputArray *out;
const void *base;
Arg &&arg;
};
/* /*
* Helper to subset a RecordList/record array. Subsets each Record in the array and * Helper to subset a RecordList/record array. Subsets each Record in the array and
* discards the record if the subset operation returns false. * discards the record if the subset operation returns false.
@@ -335,6 +389,13 @@ struct
operator () (hb_subset_layout_context_t *c, OutputArray* out, operator () (hb_subset_layout_context_t *c, OutputArray* out,
const void *base) const const void *base) const
{ return subset_record_array_t<OutputArray> (c, out, base); } { return subset_record_array_t<OutputArray> (c, out, base); }
/* Variant with one extra argument passed to subset */
template<typename OutputArray, typename Arg>
subset_record_array_arg_t<OutputArray, Arg>
operator () (hb_subset_layout_context_t *c, OutputArray* out,
const void *base, Arg &&arg) const
{ return subset_record_array_arg_t<OutputArray, Arg> (c, out, base, arg); }
} }
HB_FUNCOBJ (subset_record_array); HB_FUNCOBJ (subset_record_array);
@@ -431,94 +492,6 @@ struct IndexArray : Array16Of<Index>
}; };
struct Record_sanitize_closure_t {
hb_tag_t tag;
const void *list_base;
};
template <typename Type>
struct Record
{
int cmp (hb_tag_t a) const { return tag.cmp (a); }
bool subset (hb_subset_layout_context_t *c, const void *base) const
{
TRACE_SUBSET (this);
auto *out = c->subset_context->serializer->embed (this);
if (unlikely (!out)) return_trace (false);
bool ret = out->offset.serialize_subset (c->subset_context, offset, base, c, &tag);
return_trace (ret);
}
bool sanitize (hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE (this);
const Record_sanitize_closure_t closure = {tag, base};
return_trace (c->check_struct (this) && offset.sanitize (c, base, &closure));
}
Tag tag; /* 4-byte Tag identifier */
Offset16To<Type>
offset; /* Offset from beginning of object holding
* the Record */
public:
DEFINE_SIZE_STATIC (6);
};
template <typename Type>
struct RecordArrayOf : SortedArray16Of<Record<Type>>
{
const Offset16To<Type>& get_offset (unsigned int i) const
{ return (*this)[i].offset; }
Offset16To<Type>& get_offset (unsigned int i)
{ return (*this)[i].offset; }
const Tag& get_tag (unsigned int i) const
{ return (*this)[i].tag; }
unsigned int get_tags (unsigned int start_offset,
unsigned int *record_count /* IN/OUT */,
hb_tag_t *record_tags /* OUT */) const
{
if (record_count)
{
+ this->sub_array (start_offset, record_count)
| hb_map (&Record<Type>::tag)
| hb_sink (hb_array (record_tags, *record_count))
;
}
return this->len;
}
bool find_index (hb_tag_t tag, unsigned int *index) const
{
return this->bfind (tag, index, HB_NOT_FOUND_STORE, Index::NOT_FOUND_INDEX);
}
};
template <typename Type>
struct RecordListOf : RecordArrayOf<Type>
{
const Type& operator [] (unsigned int i) const
{ return this+this->get_offset (i); }
bool subset (hb_subset_context_t *c,
hb_subset_layout_context_t *l) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (*this);
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+ this->iter ()
| hb_apply (subset_record_array (l, out, this))
;
return_trace (true);
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (RecordArrayOf<Type>::sanitize (c, this));
}
};
/* https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#size */ /* https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#size */
struct FeatureParamsSize struct FeatureParamsSize
{ {
@@ -801,6 +774,10 @@ struct FeatureParams
DEFINE_SIZE_MIN (0); DEFINE_SIZE_MIN (0);
}; };
struct Record_sanitize_closure_t {
hb_tag_t tag;
const void *list_base;
};
struct Feature struct Feature
{ {
@@ -897,6 +874,103 @@ struct Feature
DEFINE_SIZE_ARRAY_SIZED (4, lookupIndex); DEFINE_SIZE_ARRAY_SIZED (4, lookupIndex);
}; };
template <typename Type>
struct Record
{
int cmp (hb_tag_t a) const { return tag.cmp (a); }
bool subset (hb_subset_layout_context_t *c, const void *base, const void *f_sub = nullptr) const
{
TRACE_SUBSET (this);
auto *out = c->subset_context->serializer->embed (this);
if (unlikely (!out)) return_trace (false);
if (!f_sub)
return_trace (out->offset.serialize_subset (c->subset_context, offset, base, c, &tag));
const Feature& f = *reinterpret_cast<const Feature *> (f_sub);
auto *s = c->subset_context->serializer;
s->push ();
out->offset = 0;
bool ret = f.subset (c->subset_context, c, &tag);
if (ret)
s->add_link (out->offset, s->pop_pack ());
else
s->pop_discard ();
return_trace (ret);
}
bool sanitize (hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE (this);
const Record_sanitize_closure_t closure = {tag, base};
return_trace (c->check_struct (this) && offset.sanitize (c, base, &closure));
}
Tag tag; /* 4-byte Tag identifier */
Offset16To<Type>
offset; /* Offset from beginning of object holding
* the Record */
public:
DEFINE_SIZE_STATIC (6);
};
template <typename Type>
struct RecordArrayOf : SortedArray16Of<Record<Type>>
{
const Offset16To<Type>& get_offset (unsigned int i) const
{ return (*this)[i].offset; }
Offset16To<Type>& get_offset (unsigned int i)
{ return (*this)[i].offset; }
const Tag& get_tag (unsigned int i) const
{ return (*this)[i].tag; }
unsigned int get_tags (unsigned int start_offset,
unsigned int *record_count /* IN/OUT */,
hb_tag_t *record_tags /* OUT */) const
{
if (record_count)
{
+ this->sub_array (start_offset, record_count)
| hb_map (&Record<Type>::tag)
| hb_sink (hb_array (record_tags, *record_count))
;
}
return this->len;
}
bool find_index (hb_tag_t tag, unsigned int *index) const
{
return this->bfind (tag, index, HB_NOT_FOUND_STORE, Index::NOT_FOUND_INDEX);
}
};
template <typename Type>
struct RecordListOf : RecordArrayOf<Type>
{
const Type& operator [] (unsigned int i) const
{ return this+this->get_offset (i); }
bool subset (hb_subset_context_t *c,
hb_subset_layout_context_t *l) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (*this);
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+ this->iter ()
| hb_apply (subset_record_array (l, out, this))
;
return_trace (true);
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (RecordArrayOf<Type>::sanitize (c, this));
}
};
struct RecordListOfFeature : RecordListOf<Feature> struct RecordListOfFeature : RecordListOf<Feature>
{ {
bool subset (hb_subset_context_t *c, bool subset (hb_subset_context_t *c,
@@ -907,11 +981,20 @@ struct RecordListOfFeature : RecordListOf<Feature>
if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false); if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
unsigned count = this->len; unsigned count = this->len;
+ hb_zip (*this, hb_range (count)) + hb_zip (*this, hb_range (count))
| hb_filter (l->feature_index_map, hb_second) | hb_filter (l->feature_index_map, hb_second)
| hb_map (hb_first) | hb_apply ([l, out, this] (const hb_pair_t<const Record<Feature>&, unsigned>& _)
| hb_apply (subset_record_array (l, out, this)) {
const Feature *f_sub = nullptr;
const Feature **f = nullptr;
if (l->feature_substitutes_map->has (_.second, &f))
f_sub = *f;
subset_record_array (l, out, this, f_sub) (_.first);
})
; ;
return_trace (true); return_trace (true);
} }
}; };
@@ -2692,6 +2775,13 @@ struct VariationStore
/* /*
* Feature Variations * Feature Variations
*/ */
enum Cond_with_Var_flag_t
{
KEEP_COND_WITH_VAR = 0,
DROP_COND_WITH_VAR = 1,
DROP_RECORD_WITH_VAR = 2,
MEM_ERR_WITH_VAR = 3,
};
struct ConditionFormat1 struct ConditionFormat1
{ {
@@ -2702,10 +2792,52 @@ struct ConditionFormat1
TRACE_SUBSET (this); TRACE_SUBSET (this);
auto *out = c->serializer->embed (this); auto *out = c->serializer->embed (this);
if (unlikely (!out)) return_trace (false); if (unlikely (!out)) return_trace (false);
return_trace (true);
const hb_map_t *index_map = c->plan->axes_index_map;
if (index_map->is_empty ()) return_trace (true);
if (!index_map->has (axisIndex))
return_trace (false);
return_trace (c->serializer->check_assign (out->axisIndex, index_map->get (axisIndex),
HB_SERIALIZE_ERROR_INT_OVERFLOW));
} }
private: private:
Cond_with_Var_flag_t keep_with_variations (hb_collect_feature_substitutes_with_var_context_t *c,
hb_map_t *condition_map /* OUT */) const
{
//invalid axis index, drop the entire record
if (!c->axes_index_tag_map->has (axisIndex))
return DROP_RECORD_WITH_VAR;
hb_tag_t axis_tag = c->axes_index_tag_map->get (axisIndex);
//axis not pinned, keep the condition
if (!c->axes_location->has (axis_tag))
{
// add axisIndex->value into the hashmap so we can check if the record is
// unique with variations
int16_t min_val = filterRangeMinValue;
int16_t max_val = filterRangeMaxValue;
hb_codepoint_t val = (max_val << 16) + min_val;
condition_map->set (axisIndex, val);
return KEEP_COND_WITH_VAR;
}
//axis pinned, check if condition is met
//TODO: add check for axis Ranges
int v = c->axes_location->get (axis_tag);
//condition not met, drop the entire record
if (v < filterRangeMinValue || v > filterRangeMaxValue)
return DROP_RECORD_WITH_VAR;
//axis pinned and condition met, drop the condition
return DROP_COND_WITH_VAR;
}
bool evaluate (const int *coords, unsigned int coord_len) const bool evaluate (const int *coords, unsigned int coord_len) const
{ {
int coord = axisIndex < coord_len ? coords[axisIndex] : 0; int coord = axisIndex < coord_len ? coords[axisIndex] : 0;
@@ -2737,6 +2869,15 @@ struct Condition
} }
} }
Cond_with_Var_flag_t keep_with_variations (hb_collect_feature_substitutes_with_var_context_t *c,
hb_map_t *condition_map /* OUT */) const
{
switch (u.format) {
case 1: return u.format1.keep_with_variations (c, condition_map);
default:return KEEP_COND_WITH_VAR;
}
}
template <typename context_t, typename ...Ts> template <typename context_t, typename ...Ts>
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
{ {
@@ -2778,15 +2919,65 @@ struct ConditionSet
return true; return true;
} }
bool subset (hb_subset_context_t *c) const Cond_with_Var_flag_t keep_with_variations (hb_collect_feature_substitutes_with_var_context_t *c) const
{
hb_map_t *condition_map = hb_map_create ();
if (unlikely (!condition_map)) return MEM_ERR_WITH_VAR;
hb::shared_ptr<hb_map_t> p {condition_map};
hb_set_t *cond_set = hb_set_create ();
if (unlikely (!cond_set)) return MEM_ERR_WITH_VAR;
hb::shared_ptr<hb_set_t> s {cond_set};
unsigned num_kept_cond = 0, cond_idx = 0;
for (const auto& offset : conditions)
{
Cond_with_Var_flag_t ret = (this+offset).keep_with_variations (c, condition_map);
// one condition is not met, drop the entire record
if (ret == DROP_RECORD_WITH_VAR)
return DROP_RECORD_WITH_VAR;
// axis not pinned, keep this condition
if (ret == KEEP_COND_WITH_VAR)
{
cond_set->add (cond_idx);
num_kept_cond++;
}
cond_idx++;
}
// all conditions met
if (num_kept_cond == 0) return DROP_COND_WITH_VAR;
//check if condition_set is unique with variations
if (c->conditionset_map->has (p))
//duplicate found, drop the entire record
return DROP_RECORD_WITH_VAR;
c->conditionset_map->set (p, 1);
c->record_cond_idx_map->set (c->cur_record_idx, s);
return KEEP_COND_WITH_VAR;
}
bool subset (hb_subset_context_t *c,
hb_subset_layout_context_t *l) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (this); auto *out = c->serializer->start_embed (this);
if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false); if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
+ conditions.iter () hb_set_t *retained_cond_set = nullptr;
| hb_apply (subset_offset_array (c, out->conditions, this)) if (l->feature_record_cond_idx_map != nullptr)
; retained_cond_set = l->feature_record_cond_idx_map->get (l->cur_feature_var_record_idx);
unsigned int count = conditions.len;
for (unsigned int i = 0; i < count; i++)
{
if (retained_cond_set != nullptr && !retained_cond_set->has (i))
continue;
subset_offset_array (c, out->conditions, this) (conditions[i]);
}
return_trace (bool (out->conditions)); return_trace (bool (out->conditions));
} }
@@ -2820,10 +3011,19 @@ struct FeatureTableSubstitutionRecord
feature_indexes->add (featureIndex); feature_indexes->add (featureIndex);
} }
void collect_feature_substitutes_with_variations (hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map,
const hb_set_t *feature_indices,
const void *base) const
{
if (feature_indices->has (featureIndex))
feature_substitutes_map->set (featureIndex, &(base+feature));
}
bool subset (hb_subset_layout_context_t *c, const void *base) const bool subset (hb_subset_layout_context_t *c, const void *base) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
if (!c->feature_index_map->has (featureIndex)) { if (!c->feature_index_map->has (featureIndex) ||
c->feature_substitutes_map->has (featureIndex)) {
// Feature that is being substituted is not being retained, so we don't // Feature that is being substituted is not being retained, so we don't
// need this. // need this.
return_trace (false); return_trace (false);
@@ -2865,10 +3065,16 @@ struct FeatureTableSubstitution
} }
void collect_lookups (const hb_set_t *feature_indexes, void collect_lookups (const hb_set_t *feature_indexes,
const hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map,
hb_set_t *lookup_indexes /* OUT */) const hb_set_t *lookup_indexes /* OUT */) const
{ {
+ hb_iter (substitutions) + hb_iter (substitutions)
| hb_filter (feature_indexes, &FeatureTableSubstitutionRecord::featureIndex) | hb_filter (feature_indexes, &FeatureTableSubstitutionRecord::featureIndex)
| hb_filter ([feature_substitutes_map] (const FeatureTableSubstitutionRecord& record)
{
if (feature_substitutes_map == nullptr) return true;
return !feature_substitutes_map->has (record.featureIndex);
})
| hb_apply ([this, lookup_indexes] (const FeatureTableSubstitutionRecord& r) | hb_apply ([this, lookup_indexes] (const FeatureTableSubstitutionRecord& r)
{ r.collect_lookups (this, lookup_indexes); }) { r.collect_lookups (this, lookup_indexes); })
; ;
@@ -2890,6 +3096,12 @@ struct FeatureTableSubstitution
return false; return false;
} }
void collect_feature_substitutes_with_variations (hb_collect_feature_substitutes_with_var_context_t *c) const
{
for (const FeatureTableSubstitutionRecord& record : substitutions)
record.collect_feature_substitutes_with_variations (c->feature_substitutes_map, c->feature_indices, this);
}
bool subset (hb_subset_context_t *c, bool subset (hb_subset_context_t *c,
hb_subset_layout_context_t *l) const hb_subset_layout_context_t *l) const
{ {
@@ -2929,9 +3141,10 @@ struct FeatureVariationRecord
void collect_lookups (const void *base, void collect_lookups (const void *base,
const hb_set_t *feature_indexes, const hb_set_t *feature_indexes,
const hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map,
hb_set_t *lookup_indexes /* OUT */) const hb_set_t *lookup_indexes /* OUT */) const
{ {
return (base+substitutions).collect_lookups (feature_indexes, lookup_indexes); return (base+substitutions).collect_lookups (feature_indexes, feature_substitutes_map, lookup_indexes);
} }
void closure_features (const void *base, void closure_features (const void *base,
@@ -2946,13 +3159,25 @@ struct FeatureVariationRecord
return (base+substitutions).intersects_features (feature_index_map); return (base+substitutions).intersects_features (feature_index_map);
} }
void collect_feature_substitutes_with_variations (hb_collect_feature_substitutes_with_var_context_t *c,
const void *base) const
{
// ret == 1, all conditions met
if ((base+conditions).keep_with_variations (c) == DROP_COND_WITH_VAR &&
c->apply)
{
(base+substitutions).collect_feature_substitutes_with_variations (c);
c->apply = false; // set variations only once
}
}
bool subset (hb_subset_layout_context_t *c, const void *base) const bool subset (hb_subset_layout_context_t *c, const void *base) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
auto *out = c->subset_context->serializer->embed (this); auto *out = c->subset_context->serializer->embed (this);
if (unlikely (!out)) return_trace (false); if (unlikely (!out)) return_trace (false);
out->conditions.serialize_subset (c->subset_context, conditions, base); out->conditions.serialize_subset (c->subset_context, conditions, base, c);
out->substitutions.serialize_subset (c->subset_context, substitutions, base, c); out->substitutions.serialize_subset (c->subset_context, substitutions, base, c);
return_trace (true); return_trace (true);
@@ -3002,6 +3227,16 @@ struct FeatureVariations
return (this+record.substitutions).find_substitute (feature_index); return (this+record.substitutions).find_substitute (feature_index);
} }
void collect_feature_substitutes_with_variations (hb_collect_feature_substitutes_with_var_context_t *c) const
{
unsigned int count = varRecords.len;
for (unsigned int i = 0; i < count; i++)
{
c->cur_record_idx = i;
varRecords[i].collect_feature_substitutes_with_variations (c, this);
}
}
FeatureVariations* copy (hb_serialize_context_t *c) const FeatureVariations* copy (hb_serialize_context_t *c) const
{ {
TRACE_SERIALIZE (this); TRACE_SERIALIZE (this);
@@ -3009,17 +3244,25 @@ struct FeatureVariations
} }
void collect_lookups (const hb_set_t *feature_indexes, void collect_lookups (const hb_set_t *feature_indexes,
const hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map,
hb_set_t *lookup_indexes /* OUT */) const hb_set_t *lookup_indexes /* OUT */) const
{ {
for (const FeatureVariationRecord& r : varRecords) for (const FeatureVariationRecord& r : varRecords)
r.collect_lookups (this, feature_indexes, lookup_indexes); r.collect_lookups (this, feature_indexes, feature_substitutes_map, lookup_indexes);
} }
void closure_features (const hb_map_t *lookup_indexes, void closure_features (const hb_map_t *lookup_indexes,
const hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *feature_record_cond_idx_map,
hb_set_t *feature_indexes /* OUT */) const hb_set_t *feature_indexes /* OUT */) const
{ {
for (const FeatureVariationRecord& record : varRecords) unsigned int count = varRecords.len;
record.closure_features (this, lookup_indexes, feature_indexes); for (unsigned int i = 0; i < count; i++)
{
if (feature_record_cond_idx_map != nullptr &&
!feature_record_cond_idx_map->has (i))
continue;
varRecords[i].closure_features (this, lookup_indexes, feature_indexes);
}
} }
bool subset (hb_subset_context_t *c, bool subset (hb_subset_context_t *c,
@@ -3041,7 +3284,13 @@ struct FeatureVariations
} }
unsigned count = (unsigned) (keep_up_to + 1); unsigned count = (unsigned) (keep_up_to + 1);
for (unsigned i = 0; i < count; i++) { for (unsigned i = 0; i < count; i++)
{
if (l->feature_record_cond_idx_map != nullptr &&
!l->feature_record_cond_idx_map->has (i))
continue;
l->cur_feature_var_record_idx = i;
subset_record_array (l, &(out->varRecords), this) (varRecords[i]); subset_record_array (l, &(out->varRecords), this) (varRecords[i]);
} }
return_trace (bool (out->varRecords)); return_trace (bool (out->varRecords));

View File

@@ -4236,13 +4236,19 @@ struct GSUBGPOS
} }
void feature_variation_collect_lookups (const hb_set_t *feature_indexes, void feature_variation_collect_lookups (const hb_set_t *feature_indexes,
const hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map,
hb_set_t *lookup_indexes /* OUT */) const hb_set_t *lookup_indexes /* OUT */) const
{ {
#ifndef HB_NO_VAR #ifndef HB_NO_VAR
get_feature_variations ().collect_lookups (feature_indexes, lookup_indexes); get_feature_variations ().collect_lookups (feature_indexes, feature_substitutes_map, lookup_indexes);
#endif #endif
} }
#ifndef HB_NO_VAR
void collect_feature_substitutes_with_variations (hb_collect_feature_substitutes_with_var_context_t *c) const
{ get_feature_variations ().collect_feature_substitutes_with_variations (c); }
#endif
template <typename TLookup> template <typename TLookup>
void closure_lookups (hb_face_t *face, void closure_lookups (hb_face_t *face,
const hb_set_t *glyphs, const hb_set_t *glyphs,
@@ -4278,6 +4284,8 @@ struct GSUBGPOS
} }
void prune_features (const hb_map_t *lookup_indices, /* IN */ void prune_features (const hb_map_t *lookup_indices, /* IN */
const hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *feature_record_cond_idx_map, /* IN */
const hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map, /* IN */
hb_set_t *feature_indices /* IN/OUT */) const hb_set_t *feature_indices /* IN/OUT */) const
{ {
#ifndef HB_NO_VAR #ifndef HB_NO_VAR
@@ -4285,7 +4293,7 @@ struct GSUBGPOS
// if the FeatureVariation's table and the alternate version(s) intersect the // if the FeatureVariation's table and the alternate version(s) intersect the
// set of lookup indices. // set of lookup indices.
hb_set_t alternate_feature_indices; hb_set_t alternate_feature_indices;
get_feature_variations ().closure_features (lookup_indices, &alternate_feature_indices); get_feature_variations ().closure_features (lookup_indices, feature_record_cond_idx_map, &alternate_feature_indices);
if (unlikely (alternate_feature_indices.in_error())) if (unlikely (alternate_feature_indices.in_error()))
{ {
feature_indices->err (); feature_indices->err ();
@@ -4295,7 +4303,6 @@ struct GSUBGPOS
for (unsigned i : feature_indices->iter()) for (unsigned i : feature_indices->iter())
{ {
const Feature& f = get_feature (i);
hb_tag_t tag = get_feature_tag (i); hb_tag_t tag = get_feature_tag (i);
if (tag == HB_TAG ('p', 'r', 'e', 'f')) if (tag == HB_TAG ('p', 'r', 'e', 'f'))
// Note: Never ever drop feature 'pref', even if it's empty. // Note: Never ever drop feature 'pref', even if it's empty.
@@ -4305,11 +4312,16 @@ struct GSUBGPOS
continue; continue;
if (!f.featureParams.is_null () && const Feature *f = &(get_feature (i));
const Feature** p = nullptr;
if (feature_substitutes_map->has (i, &p))
f = *p;
if (!f->featureParams.is_null () &&
tag == HB_TAG ('s', 'i', 'z', 'e')) tag == HB_TAG ('s', 'i', 'z', 'e'))
continue; continue;
if (!f.intersects_lookup_indexes (lookup_indices) if (!f->intersects_lookup_indexes (lookup_indices)
#ifndef HB_NO_VAR #ifndef HB_NO_VAR
&& !alternate_feature_indices.has (i) && !alternate_feature_indices.has (i)
#endif #endif

View File

@@ -1271,7 +1271,7 @@ hb_ot_layout_collect_lookups (hb_face_t *face,
hb_set_next (&feature_indexes, &feature_index);) hb_set_next (&feature_indexes, &feature_index);)
g.get_feature (feature_index).add_lookup_indexes_to (lookup_indexes); g.get_feature (feature_index).add_lookup_indexes_to (lookup_indexes);
g.feature_variation_collect_lookups (&feature_indexes, lookup_indexes); g.feature_variation_collect_lookups (&feature_indexes, nullptr, lookup_indexes);
} }
@@ -1709,6 +1709,8 @@ hb_ot_layout_get_size_params (hb_face_t *face,
return false; return false;
} }
/** /**
* hb_ot_layout_feature_get_name_ids: * hb_ot_layout_feature_get_name_ids:
* @face: #hb_face_t to work upon * @face: #hb_face_t to work upon
@@ -2341,6 +2343,7 @@ struct hb_get_glyph_alternates_dispatch_t :
( _dispatch (obj, hb_prioritize, std::forward<Ts> (ds)...) ) ( _dispatch (obj, hb_prioritize, std::forward<Ts> (ds)...) )
}; };
#ifndef HB_NO_LAYOUT_RARELY_USED
/** /**
* hb_ot_layout_lookup_get_glyph_alternates: * hb_ot_layout_lookup_get_glyph_alternates:
* @face: a face. * @face: a face.
@@ -2373,4 +2376,72 @@ hb_ot_layout_lookup_get_glyph_alternates (hb_face_t *face,
return ret; return ret;
} }
struct hb_position_single_dispatch_t :
hb_dispatch_context_t<hb_position_single_dispatch_t, bool>
{
static return_t default_return_value () { return false; }
bool stop_sublookup_iteration (return_t r) const { return r; }
private:
template <typename T, typename ...Ts> auto
_dispatch (const T &obj, hb_priority<1>, Ts&&... ds) HB_AUTO_RETURN
( obj.position_single (std::forward<Ts> (ds)...) )
template <typename T, typename ...Ts> auto
_dispatch (const T &obj, hb_priority<0>, Ts&&... ds) HB_AUTO_RETURN
( default_return_value () )
public:
template <typename T, typename ...Ts> auto
dispatch (const T &obj, Ts&&... ds) HB_AUTO_RETURN
( _dispatch (obj, hb_prioritize, std::forward<Ts> (ds)...) )
};
/**
* hb_ot_layout_lookup_get_optical_bound:
* @font: a font.
* @lookup_index: index of the feature lookup to query.
* @direction: edge of the glyph to query.
* @glyph: a glyph id.
*
* Fetches the optical bound of a glyph positioned at the margin of text.
* The direction identifies which edge of the glyph to query.
*
* Return value: Adjustment value. Negative values mean the glyph will stick out of the margin.
*
* Since: 5.3.0
**/
hb_position_t
hb_ot_layout_lookup_get_optical_bound (hb_font_t *font,
unsigned lookup_index,
hb_direction_t direction,
hb_codepoint_t glyph)
{
const OT::PosLookup &lookup = font->face->table.GPOS->table->get_lookup (lookup_index);
hb_glyph_position_t pos = {0};
hb_position_single_dispatch_t c;
lookup.dispatch (&c, font, direction, glyph, pos);
hb_position_t ret = 0;
switch (direction)
{
case HB_DIRECTION_LTR:
ret = pos.x_offset;
break;
case HB_DIRECTION_RTL:
ret = pos.x_advance - pos.x_offset;
break;
case HB_DIRECTION_TTB:
ret = pos.y_offset;
break;
case HB_DIRECTION_BTT:
ret = pos.y_advance - pos.y_offset;
break;
case HB_DIRECTION_INVALID:
default:
break;
}
return ret;
}
#endif
#endif #endif

View File

@@ -403,6 +403,16 @@ hb_ot_layout_get_size_params (hb_face_t *face,
unsigned int *range_start, /* OUT. May be NULL */ unsigned int *range_start, /* OUT. May be NULL */
unsigned int *range_end /* OUT. May be NULL */); unsigned int *range_end /* OUT. May be NULL */);
HB_EXTERN hb_position_t
hb_ot_layout_lookup_get_optical_bound (hb_font_t *font,
unsigned lookup_index,
hb_direction_t direction,
hb_codepoint_t glyph);
/*
* GSUB/GPOS
*/
HB_EXTERN hb_bool_t HB_EXTERN hb_bool_t
hb_ot_layout_feature_get_name_ids (hb_face_t *face, hb_ot_layout_feature_get_name_ids (hb_face_t *face,
@@ -423,6 +433,7 @@ hb_ot_layout_feature_get_characters (hb_face_t *face,
unsigned int *char_count /* IN/OUT. May be NULL */, unsigned int *char_count /* IN/OUT. May be NULL */,
hb_codepoint_t *characters /* OUT. May be NULL */); hb_codepoint_t *characters /* OUT. May be NULL */);
/* /*
* BASE * BASE
*/ */

View File

@@ -282,7 +282,7 @@ struct post
* 0x00020000 for version 2.0 * 0x00020000 for version 2.0
* 0x00025000 for version 2.5 (deprecated) * 0x00025000 for version 2.5 (deprecated)
* 0x00030000 for version 3.0 */ * 0x00030000 for version 3.0 */
HBFixed italicAngle; /* Italic angle in counter-clockwise degrees F16DOT16 italicAngle; /* Italic angle in counter-clockwise degrees
* from the vertical. Zero for upright text, * from the vertical. Zero for upright text,
* negative for text that leans to the right * negative for text that leans to the right
* (forward). */ * (forward). */

View File

@@ -527,18 +527,20 @@ hb_set_unicode_props (hb_buffer_t *buffer)
} }
#endif #endif
/* Or part of the Other_Grapheme_Extend that is not marks. /* Or part of the Other_Grapheme_Extend that is not marks.
* As of Unicode 11 that is just: * As of Unicode 15 that is just:
* *
* 200C ; Other_Grapheme_Extend # Cf ZERO WIDTH NON-JOINER * 200C ; Other_Grapheme_Extend # Cf ZERO WIDTH NON-JOINER
* FF9E..FF9F ; Other_Grapheme_Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK * FF9E..FF9F ; Other_Grapheme_Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK
* E0020..E007F ; Other_Grapheme_Extend # Cf [96] TAG SPACE..CANCEL TAG * E0020..E007F ; Other_Grapheme_Extend # Cf [96] TAG SPACE..CANCEL TAG
* *
* ZWNJ is special, we don't want to merge it as there's no need, and keeping * ZWNJ is special, we don't want to merge it as there's no need, and keeping
* it separate results in more granular clusters. Ignore Katakana for now. * it separate results in more granular clusters.
* Tags are used for Emoji sub-region flag sequences: * Tags are used for Emoji sub-region flag sequences:
* https://github.com/harfbuzz/harfbuzz/issues/1556 * https://github.com/harfbuzz/harfbuzz/issues/1556
* Katakana ones were requested:
* https://github.com/harfbuzz/harfbuzz/issues/3844
*/ */
else if (unlikely (hb_in_range<hb_codepoint_t> (info[i].codepoint, 0xE0020u, 0xE007Fu))) else if (unlikely (hb_in_ranges<hb_codepoint_t> (info[i].codepoint, 0xFF9Eu, 0xFF9Fu, 0xE0020u, 0xE007Fu)))
_hb_glyph_info_set_continuation (&info[i]); _hb_glyph_info_set_continuation (&info[i]);
} }
} }

View File

@@ -25,6 +25,7 @@
* # Updated for Unicode 12.1 by Andrew Glass 2019-05-24 * # Updated for Unicode 12.1 by Andrew Glass 2019-05-24
* # Updated for Unicode 13.0 by Andrew Glass 2020-07-28 * # Updated for Unicode 13.0 by Andrew Glass 2020-07-28
* # Updated for Unicode 14.0 by Andrew Glass 2021-09-25 * # Updated for Unicode 14.0 by Andrew Glass 2021-09-25
* # Updated for Unicode 15.0 by Andrew Glass 2022-09-16
* # Override values For Indic_Positional_Category * # Override values For Indic_Positional_Category
* # Not derivable * # Not derivable
* # Initial version based on Unicode 7.0 by Andrew Glass 2014-03-17 * # Initial version based on Unicode 7.0 by Andrew Glass 2014-03-17
@@ -34,6 +35,7 @@
* # Updated for Unicode 12.1 by Andrew Glass 2019-05-30 * # Updated for Unicode 12.1 by Andrew Glass 2019-05-30
* # Updated for Unicode 13.0 by Andrew Glass 2020-07-28 * # Updated for Unicode 13.0 by Andrew Glass 2020-07-28
* # Updated for Unicode 14.0 by Andrew Glass 2021-09-28 * # Updated for Unicode 14.0 by Andrew Glass 2021-09-28
* # Updated for Unicode 15.0 by Andrew Glass 2022-09-16
* UnicodeData.txt does not have a header. * UnicodeData.txt does not have a header.
*/ */
@@ -90,7 +92,7 @@
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
static const uint8_t static const uint8_t
hb_use_u8[3115] = hb_use_u8[3141] =
{ {
16, 50, 51, 51, 51, 52, 51, 83, 118, 131, 51, 57, 58, 179, 195, 61, 16, 50, 51, 51, 51, 52, 51, 83, 118, 131, 51, 57, 58, 179, 195, 61,
51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
@@ -125,11 +127,11 @@ hb_use_u8[3115] =
2, 2, 2, 2, 2, 2, 2, 2, 2, 88, 89, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 88, 89, 2, 2, 2, 2, 2,
2, 2, 2, 90, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 90, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 91, 2, 2, 92, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 91, 2, 2, 92, 2, 2, 2, 93, 2, 2, 2, 2, 2,
2, 2, 2, 93, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 94, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 94, 94, 95, 96, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 2, 95, 95, 96, 97, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
94, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
0, 2, 2, 2, 2, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 4, 0, 2, 2, 2, 2, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 4,
0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 7, 0, 0, 0, 0, 0, 0,
@@ -226,70 +228,72 @@ hb_use_u8[3115] =
0, 9, 47, 2, 2, 2, 2, 2, 2, 2, 2, 2, 125, 18, 20, 151, 0, 9, 47, 2, 2, 2, 2, 2, 2, 2, 2, 2, 125, 18, 20, 151,
20, 19, 152, 153, 2, 2, 2, 2, 2, 0, 0, 63, 154, 0, 0, 0, 20, 19, 152, 153, 2, 2, 2, 2, 2, 0, 0, 63, 154, 0, 0, 0,
0, 2, 11, 0, 0, 0, 0, 0, 0, 2, 63, 23, 18, 18, 18, 20, 0, 2, 11, 0, 0, 0, 0, 0, 0, 2, 63, 23, 18, 18, 18, 20,
20, 106, 155, 0, 0, 156, 157, 29, 158, 28, 2, 2, 2, 2, 2, 2, 20, 106, 155, 0, 0, 54, 156, 29, 157, 28, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 21, 17, 20, 20, 159, 42, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 21, 17, 20, 20, 158, 42, 0, 0, 0,
47, 125, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 7, 7, 2, 2, 47, 125, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 7, 7, 2, 2,
28, 2, 2, 2, 2, 2, 2, 2, 28, 2, 2, 2, 2, 2, 2, 2, 28, 2, 2, 2, 2, 2, 2, 2, 28, 2, 2, 2, 2, 2, 2, 2,
8, 16, 17, 19, 20, 160, 29, 0, 0, 9, 9, 28, 2, 2, 2, 7, 8, 16, 17, 19, 20, 159, 29, 0, 0, 9, 9, 28, 2, 2, 2, 7,
28, 7, 2, 28, 2, 2, 56, 15, 21, 14, 21, 45, 30, 31, 30, 32, 28, 7, 2, 28, 2, 2, 56, 15, 21, 14, 21, 45, 30, 31, 30, 32,
0, 0, 0, 0, 33, 0, 0, 0, 2, 2, 21, 0, 9, 9, 9, 44, 0, 0, 0, 0, 33, 0, 0, 0, 2, 2, 21, 0, 9, 9, 9, 44,
0, 9, 9, 44, 0, 0, 0, 0, 0, 2, 2, 63, 23, 18, 18, 18, 0, 9, 9, 44, 0, 0, 0, 0, 0, 2, 2, 63, 23, 18, 18, 18,
20, 21, 123, 13, 15, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 0, 20, 21, 123, 13, 15, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 0,
161, 162, 0, 0, 0, 0, 0, 0, 0, 16, 17, 18, 18, 64, 97, 23, 160, 161, 0, 0, 0, 0, 0, 0, 0, 16, 17, 18, 18, 64, 97, 23,
158, 9, 163, 7, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 157, 9, 162, 7, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2,
63, 23, 18, 18, 0, 46, 46, 9, 164, 35, 0, 0, 0, 0, 0, 0, 63, 23, 18, 18, 0, 46, 46, 9, 163, 35, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 2, 2, 18, 0, 21, 17, 18, 18, 19, 14, 80, 0, 0, 0, 0, 0, 2, 2, 18, 0, 21, 17, 18, 18, 19, 14, 80,
164, 36, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 8, 165, 163, 36, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 8, 164,
23, 18, 20, 20, 163, 7, 0, 0, 0, 2, 2, 2, 2, 2, 7, 41, 23, 18, 20, 20, 162, 7, 0, 0, 0, 2, 2, 2, 2, 2, 7, 41,
133, 21, 20, 18, 74, 19, 20, 0, 0, 2, 2, 2, 7, 0, 0, 0, 133, 21, 20, 18, 74, 19, 20, 0, 0, 2, 2, 2, 7, 0, 0, 0,
0, 2, 2, 2, 2, 2, 2, 16, 17, 18, 19, 20, 103, 164, 35, 0, 0, 2, 2, 2, 2, 2, 2, 16, 17, 18, 19, 20, 103, 163, 35, 0,
0, 2, 2, 2, 7, 28, 0, 2, 2, 2, 2, 28, 7, 2, 2, 2, 0, 2, 2, 2, 7, 28, 0, 2, 2, 2, 2, 28, 7, 2, 2, 2,
2, 21, 21, 16, 30, 31, 10, 166, 167, 168, 169, 0, 0, 0, 0, 0, 2, 21, 21, 16, 30, 31, 10, 165, 166, 167, 168, 0, 0, 0, 0, 0,
0, 2, 2, 2, 2, 0, 2, 2, 2, 63, 23, 18, 18, 0, 20, 21, 0, 2, 2, 2, 2, 0, 2, 2, 2, 63, 23, 18, 18, 0, 20, 21,
27, 106, 0, 31, 0, 0, 0, 0, 0, 50, 18, 20, 20, 20, 137, 2, 27, 106, 0, 31, 0, 0, 0, 0, 0, 50, 18, 20, 20, 20, 137, 2,
2, 2, 170, 171, 9, 13, 172, 70, 173, 0, 0, 1, 144, 0, 0, 0, 2, 2, 169, 170, 9, 13, 171, 70, 172, 0, 0, 1, 144, 0, 0, 0,
0, 50, 18, 20, 14, 17, 18, 2, 2, 2, 2, 155, 155, 155, 174, 174, 0, 50, 18, 20, 14, 17, 18, 2, 2, 2, 2, 155, 155, 155, 173, 173,
174, 174, 174, 174, 13, 175, 0, 28, 0, 20, 18, 18, 29, 20, 20, 9, 173, 173, 173, 173, 13, 174, 0, 28, 0, 20, 18, 18, 29, 20, 20, 9,
164, 0, 59, 59, 59, 59, 59, 59, 59, 64, 19, 80, 44, 0, 0, 0, 163, 0, 59, 59, 59, 59, 59, 59, 59, 64, 19, 80, 44, 0, 0, 0,
0, 2, 2, 2, 7, 2, 28, 2, 2, 50, 20, 20, 29, 0, 36, 20, 0, 2, 2, 2, 7, 2, 28, 2, 2, 50, 20, 20, 29, 0, 36, 20,
25, 9, 157, 176, 172, 0, 0, 0, 0, 2, 2, 2, 28, 7, 2, 2, 25, 9, 156, 175, 171, 0, 0, 0, 0, 2, 2, 2, 28, 7, 2, 2,
2, 2, 2, 2, 2, 2, 21, 21, 45, 20, 33, 80, 66, 0, 0, 0, 2, 2, 2, 2, 2, 2, 21, 21, 45, 20, 33, 80, 66, 0, 0, 0,
0, 2, 177, 64, 45, 0, 0, 0, 0, 9, 178, 2, 2, 2, 2, 2, 0, 2, 176, 64, 45, 0, 0, 0, 0, 9, 177, 2, 2, 2, 2, 2,
2, 2, 2, 21, 20, 18, 29, 0, 46, 14, 140, 0, 0, 0, 0, 0, 2, 2, 2, 21, 20, 18, 29, 0, 46, 14, 140, 0, 0, 0, 0, 0,
0, 179, 179, 179, 106, 7, 0, 0, 0, 9, 9, 9, 44, 0, 0, 0, 0, 178, 178, 178, 106, 179, 178, 0, 0, 145, 2, 2, 180, 114, 114, 114,
0, 2, 2, 2, 2, 2, 7, 0, 56, 180, 18, 18, 18, 18, 18, 18, 114, 114, 114, 114, 0, 0, 0, 0, 0, 9, 9, 9, 44, 0, 0, 0,
0, 2, 2, 2, 2, 2, 7, 0, 56, 181, 18, 18, 18, 18, 18, 18,
18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 0, 0, 0, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 0, 0, 0,
38, 114, 24, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 38, 114, 24, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0,
0, 2, 2, 2, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 56, 0, 2, 2, 2, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 56,
35, 0, 4, 118, 118, 118, 119, 0, 0, 9, 9, 9, 47, 2, 2, 2, 35, 0, 4, 118, 118, 118, 119, 0, 0, 9, 9, 9, 47, 2, 2, 2,
0, 2, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2,
44, 2, 2, 2, 2, 2, 2, 9, 9, 2, 2, 42, 42, 42, 90, 0, 44, 2, 2, 2, 2, 2, 2, 9, 9, 2, 2, 2, 2, 2, 2, 20,
0, O, O, O, GB, B, B, GB, O, O, WJ,FMPst,FMPst, O, CGJ, B, 20, 2, 2, 42, 42, 42, 90, 0, 0, O, O, O, GB, B, B, GB,
O, B,VMAbv,VMAbv,VMAbv, O,VMAbv, B,CMBlw,CMBlw,CMBlw,VMAbv,VMPst, VAbv, VPst,CMBlw, O, O, WJ,FMPst,FMPst, O, CGJ, B, O, B,VMAbv,VMAbv,VMAbv, O,VMAbv, B,
B, VPst, VPre, VPst, VBlw, VBlw, VBlw, VBlw, VAbv, VAbv, VAbv, VPst, VPst, VPst, H, VPre, CMBlw,CMBlw,CMBlw,VMAbv,VMPst, VAbv, VPst,CMBlw, B, VPst, VPre, VPst, VBlw, VBlw, VBlw, VBlw,
VPst,VMBlw, O, O, VAbv, GB,VMAbv,VMPst,VMPst, O, B, VBlw, O, O, VPre, VPre, VAbv, VAbv, VAbv, VPst, VPst, VPst, H, VPre, VPst,VMBlw, O, O, VAbv, GB,VMAbv,VMPst,
O, VPre, H, O, VPst,FMAbv, O,CMBlw, O, VAbv, O, VAbv, H, O,VMBlw,VMAbv, VMPst, O, B, VBlw, O, O, VPre, VPre, O, VPre, H, O, VPst,FMAbv, O,CMBlw,
CMAbv, GB, GB, O, MBlw,CMAbv,CMAbv, VPst, VAbv,VMAbv, O, VPst, O, VPre, VPre,VMAbv, O, VAbv, O, VAbv, H, O,VMBlw,VMAbv,CMAbv, GB, GB, O, MBlw,CMAbv,CMAbv, VPst,
B, O, CS, CS,VMPst, B, VAbv, VAbv, B, R, O, HVM, O, O, FBlw, O, VAbv,VMAbv, O, VPst, O, VPre, VPre,VMAbv, B, O, CS, CS,VMPst, B, VAbv, VAbv,
CMAbv, O,CMBlw, VAbv, VBlw, B, SUB, SUB, SUB, O, SUB, SUB, O, FBlw, O, B, B, R, O, HVM, O, O,FMBlw, O,CMAbv, O,CMBlw, VAbv, VBlw, B, SUB, SUB,
VPst, VBlw, VPre,VMAbv,VMBlw,VMPst, IS, VAbv, MPst, MPre, MBlw, MBlw, B, MBlw, MBlw, VPst, SUB, O, SUB, SUB, O,FMBlw, O, B, VPst, VBlw, VPre,VMAbv,VMBlw,VMPst, IS, VAbv,
VMPst,VMPst, B, MBlw, VPst, VPre, VAbv, VAbv,VMPst,VMPst,VMBlw, B,VMPst, VBlw, VPst, CGJ, MPst, MPre, MBlw, MBlw, B, MBlw, MBlw, VPst,VMPst,VMPst, B, MBlw, VPst, VPre, VAbv, VAbv,
CGJ, VPst,VMAbv,VMAbv,FMAbv, FAbv,CMAbv,FMAbv,VMAbv,FMAbv, VAbv, IS,FMAbv, B,FMAbv, B, VMPst,VMPst,VMBlw, B,VMPst, VBlw, VPst, CGJ, CGJ, VPst,VMAbv,VMAbv,FMAbv, FAbv,CMAbv,FMAbv,
CGJ, WJ, CGJ, GB,CMAbv,CMAbv, B, GB, B, VAbv, SUB, FPst, FPst,VMBlw, FPst, FPst, VMAbv,FMAbv, VAbv, IS,FMAbv, B,FMAbv, B, CGJ, WJ, CGJ, GB,CMAbv,CMAbv, B, GB,
FBlw,VMAbv,FMBlw, VAbv, VPre, B, MPre, MBlw, SUB, FAbv, FAbv, MAbv, SUB, Sk, VPst, VAbv, B, VAbv, SUB, FPst, FPst,VMBlw, FPst, FPst, FBlw,VMAbv,FMBlw, VAbv, VPre, B, MPre, MBlw,
VMAbv,VMAbv, FAbv,CMAbv, VPst, H, B, O,SMAbv,SMBlw,SMAbv,SMAbv,SMAbv, VPst, IS, VBlw, SUB, FAbv, FAbv, MAbv, SUB, Sk, VPst, VAbv,VMAbv,VMAbv, FAbv,CMAbv, VPst, H, B, O,
FAbv,VMPre,VMPre,FMAbv,CMBlw,VMBlw,VMBlw,VMAbv, CS, O,FMAbv, ZWNJ, CGJ, WJ, WJ, WJ, SMAbv,SMBlw,SMAbv,SMAbv,SMAbv, VPst, IS, VBlw, FAbv,VMPre,VMPre,FMAbv,CMBlw,VMBlw,VMBlw,VMAbv,
O,FMPst, O, O, H, MPst, VPst, H,VMAbv, VAbv,VMBlw, B, VBlw, FPst, VPst, FAbv, CS, O,FMAbv, ZWNJ, CGJ, WJ, WJ, WJ, O,FMPst, O, O, H, MPst, VPst, H,
VMPst, B,CMAbv, VAbv, MBlw, MPst, MBlw, H, O, VBlw, MPst, MPre, MAbv, MBlw, O, B, VMAbv, VAbv,VMBlw, B, VBlw, FPst, VPst, FAbv,VMPst, B,CMAbv, VAbv, MBlw, MPst, MBlw, H,
FAbv, FAbv, FPst, VBlw, B, B, VPre, O,VMPst, IS, O,VMPst, VBlw, VPst,VMBlw,VMBlw, O, VBlw, MPst, MPre, MAbv, MBlw, O, B, FAbv, FAbv, FPst, VBlw, B, B, VPre, O,
VMAbv, O, IS,VMBlw, B,VMPst,VMAbv,VMPst, CS, CS, B, N, N, O, HN, VPre, VMPst, IS, O,VMPst, VBlw, VPst,VMBlw,VMBlw,VMAbv, O, IS,VMBlw, B,VMPst,VMAbv,VMPst,
VBlw, VAbv, IS,CMAbv, O, VPst, B, R, R, O,FMBlw,CMBlw, VAbv, VPre,VMAbv,VMAbv, CS, CS, B, N, N, O, HN, VPre, VBlw, VAbv, IS,CMAbv, O, VPst, B, R,
H, VAbv,CMBlw,FMAbv, B, CS, CS, H,CMBlw,VMPst, H,VMPst, VAbv,VMAbv, VPst, IS, R,CMBlw, VAbv, VPre,VMAbv,VMAbv, H, VAbv,CMBlw,FMAbv, B, CS, CS, H,CMBlw,VMPst,
R, MPst, R, MPst,CMBlw, B,FMBlw, VBlw,VMAbv, R, MBlw, MBlw, GB, FBlw, FBlw,CMAbv, H,VMPst, VAbv,VMAbv, VPst, IS, R, MPst, R, MPst,CMBlw, B,FMBlw, VBlw,VMAbv, R,
IS, VBlw, IS, GB, VAbv, R,VMPst, H, H, O, VBlw, MBlw, MBlw, GB, FBlw, FBlw,CMAbv, IS, VBlw, IS, GB, VAbv, R,VMPst, H, H, B,
H, B,VMBlw, O, VBlw,
}; };
static const uint16_t static const uint16_t
hb_use_u16[776] = hb_use_u16[784] =
{ {
0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 3, 4, 0, 5, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 3, 4, 0, 5, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0,
@@ -332,14 +336,14 @@ hb_use_u16[776] =
9,242, 73,243, 0, 0, 0, 0,244, 9, 9,245,246, 2,247, 9, 9,242, 73,243, 0, 0, 0, 0,244, 9, 9,245,246, 2,247, 9,
248,249, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9,250, 248,249, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9,250,
251, 48, 9,252,253, 2, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 251, 48, 9,252,253, 2, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 98,254, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 9, 9, 9,254,255,256, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,
9, 9, 9,255, 0, 0, 0, 0, 9, 9, 9, 9,256,257,258,258, 9, 9, 9,257, 0, 0, 0, 0, 9, 9, 9, 9,258,259,260,260,
259,260, 0, 0, 0, 0,261, 0, 9, 9, 9, 9, 9,262, 0, 0, 261,262, 0, 0, 0, 0,263, 0, 9, 9, 9, 9, 9,264, 0, 0,
9, 9, 9, 9, 9, 9,105, 70, 94,263, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9,105, 70, 94,265, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0,264, 9, 9, 70,265,266, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,266, 9, 9, 70,267,268, 0, 0, 0,
0, 9,267, 0, 9, 9,268, 2, 9, 9, 9, 9,269, 2, 0, 0, 0, 9,269, 0, 9, 9,270, 2, 0, 0, 0, 0, 0, 9,271, 2,
129,129,129,129,129,129,129,129,160,160,160,160,160,160,160,160, 9, 9, 9, 9,272, 2, 0, 0,129,129,129,129,129,129,129,129,
160,160,160,160,160,160,160,129, 160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,129,
}; };
static inline unsigned static inline unsigned
@@ -350,7 +354,7 @@ hb_use_b4 (const uint8_t* a, unsigned i)
static inline uint_fast8_t static inline uint_fast8_t
hb_use_get_category (unsigned u) hb_use_get_category (unsigned u)
{ {
return u<921600u?hb_use_u8[2753+(((hb_use_u8[593+(((hb_use_u16[((hb_use_u8[113+(((hb_use_b4(hb_use_u8,u>>1>>3>>3>>5))<<5)+((u>>1>>3>>3)&31u))])<<3)+((u>>1>>3)&7u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:O; return u<921600u?hb_use_u8[2777+(((hb_use_u8[593+(((hb_use_u16[((hb_use_u8[113+(((hb_use_b4(hb_use_u8,u>>1>>3>>3>>5))<<5)+((u>>1>>3>>3)&31u))])<<3)+((u>>1>>3)&7u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:O;
} }
#undef B #undef B

View File

@@ -342,6 +342,40 @@ _hb_preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan HB_UNUSED,
} }
break; break;
case HB_SCRIPT_KHOJKI:
for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;)
{
bool matched = false;
switch (buffer->cur ().codepoint)
{
case 0x11200u:
switch (buffer->cur (1).codepoint)
{
case 0x1122Cu: case 0x11231u: case 0x11233u:
matched = true;
break;
}
break;
case 0x11206u:
matched = 0x1122Cu == buffer->cur (1).codepoint;
break;
case 0x1122Cu:
switch (buffer->cur (1).codepoint)
{
case 0x11230u: case 0x11231u:
matched = true;
break;
}
break;
case 0x11240u:
matched = 0x1122Eu == buffer->cur (1).codepoint;
break;
}
(void) buffer->next_glyph ();
if (matched) _output_with_dotted_circle (buffer);
}
break;
case HB_SCRIPT_KHUDAWADI: case HB_SCRIPT_KHUDAWADI:
for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;) for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;)
{ {

View File

@@ -136,7 +136,7 @@ struct AxisValueFormat1
NameID valueNameID; /* The name ID for entries in the 'name' table NameID valueNameID; /* The name ID for entries in the 'name' table
* that provide a display string for this * that provide a display string for this
* attribute value. */ * attribute value. */
HBFixed value; /* A numeric value for this attribute value. */ F16DOT16 value; /* A numeric value for this attribute value. */
public: public:
DEFINE_SIZE_STATIC (12); DEFINE_SIZE_STATIC (12);
}; };
@@ -195,10 +195,10 @@ struct AxisValueFormat2
NameID valueNameID; /* The name ID for entries in the 'name' table NameID valueNameID; /* The name ID for entries in the 'name' table
* that provide a display string for this * that provide a display string for this
* attribute value. */ * attribute value. */
HBFixed nominalValue; /* A numeric value for this attribute value. */ F16DOT16 nominalValue; /* A numeric value for this attribute value. */
HBFixed rangeMinValue; /* The minimum value for a range associated F16DOT16 rangeMinValue; /* The minimum value for a range associated
* with the specified name ID. */ * with the specified name ID. */
HBFixed rangeMaxValue; /* The maximum value for a range associated F16DOT16 rangeMaxValue; /* The maximum value for a range associated
* with the specified name ID. */ * with the specified name ID. */
public: public:
DEFINE_SIZE_STATIC (20); DEFINE_SIZE_STATIC (20);
@@ -258,8 +258,8 @@ struct AxisValueFormat3
NameID valueNameID; /* The name ID for entries in the 'name' table NameID valueNameID; /* The name ID for entries in the 'name' table
* that provide a display string for this * that provide a display string for this
* attribute value. */ * attribute value. */
HBFixed value; /* A numeric value for this attribute value. */ F16DOT16 value; /* A numeric value for this attribute value. */
HBFixed linkedValue; /* The numeric value for a style-linked mapping F16DOT16 linkedValue; /* The numeric value for a style-linked mapping
* from this value. */ * from this value. */
public: public:
DEFINE_SIZE_STATIC (16); DEFINE_SIZE_STATIC (16);
@@ -280,7 +280,7 @@ struct AxisValueRecord
HBUINT16 axisIndex; /* Zero-base index into the axis record array HBUINT16 axisIndex; /* Zero-base index into the axis record array
* identifying the axis to which this value * identifying the axis to which this value
* applies. Must be less than designAxisCount. */ * applies. Must be less than designAxisCount. */
HBFixed value; /* A numeric value for this attribute value. */ F16DOT16 value; /* A numeric value for this attribute value. */
public: public:
DEFINE_SIZE_STATIC (6); DEFINE_SIZE_STATIC (6);
}; };

View File

@@ -44,9 +44,47 @@ struct InstanceRecord
{ {
friend struct fvar; friend struct fvar;
hb_array_t<const HBFixed> get_coordinates (unsigned int axis_count) const hb_array_t<const F16DOT16> get_coordinates (unsigned int axis_count) const
{ return coordinatesZ.as_array (axis_count); } { return coordinatesZ.as_array (axis_count); }
bool subset (hb_subset_context_t *c,
unsigned axis_count,
bool has_postscript_nameid) const
{
TRACE_SUBSET (this);
if (unlikely (!c->serializer->embed (subfamilyNameID))) return_trace (false);
if (unlikely (!c->serializer->embed (flags))) return_trace (false);
const hb_array_t<const F16DOT16> coords = get_coordinates (axis_count);
const hb_hashmap_t<hb_tag_t, float> *axes_location = c->plan->user_axes_location;
for (unsigned i = 0 ; i < axis_count; i++)
{
unsigned *axis_tag;
// only keep instances whose coordinates == pinned axis location
if (!c->plan->axes_old_index_tag_map->has (i, &axis_tag)) continue;
if (axes_location->has (*axis_tag) &&
fabsf (axes_location->get (*axis_tag) - coords[i].to_float ()) > 0.001f)
return_trace (false);
if (!c->plan->axes_index_map->has (i))
continue;
if (!c->serializer->embed (coords[i]))
return_trace (false);
}
if (has_postscript_nameid)
{
NameID name_id;
name_id = StructAfter<NameID> (coords);
if (!c->serializer->embed (name_id))
return_trace (false);
}
return_trace (true);
}
bool sanitize (hb_sanitize_context_t *c, unsigned int axis_count) const bool sanitize (hb_sanitize_context_t *c, unsigned int axis_count) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
@@ -58,7 +96,7 @@ struct InstanceRecord
NameID subfamilyNameID;/* The name ID for entries in the 'name' table NameID subfamilyNameID;/* The name ID for entries in the 'name' table
* that provide subfamily names for this instance. */ * that provide subfamily names for this instance. */
HBUINT16 flags; /* Reserved for future use — set to 0. */ HBUINT16 flags; /* Reserved for future use — set to 0. */
UnsizedArrayOf<HBFixed> UnsizedArrayOf<F16DOT16>
coordinatesZ; /* The coordinates array for this instance. */ coordinatesZ; /* The coordinates array for this instance. */
//NameID postScriptNameIDX;/*Optional. The name ID for entries in the 'name' //NameID postScriptNameIDX;/*Optional. The name ID for entries in the 'name'
// * table that provide PostScript names for this // * table that provide PostScript names for this
@@ -151,9 +189,9 @@ struct AxisRecord
public: public:
Tag axisTag; /* Tag identifying the design variation for the axis. */ Tag axisTag; /* Tag identifying the design variation for the axis. */
protected: protected:
HBFixed minValue; /* The minimum coordinate value for the axis. */ F16DOT16 minValue; /* The minimum coordinate value for the axis. */
HBFixed defaultValue; /* The default coordinate value for the axis. */ F16DOT16 defaultValue; /* The default coordinate value for the axis. */
HBFixed maxValue; /* The maximum coordinate value for the axis. */ F16DOT16 maxValue; /* The maximum coordinate value for the axis. */
public: public:
HBUINT16 flags; /* Axis flags. */ HBUINT16 flags; /* Axis flags. */
NameID axisNameID; /* The name ID for entries in the 'name' table that NameID axisNameID; /* The name ID for entries in the 'name' table that
@@ -268,7 +306,7 @@ struct fvar
if (coords_length && *coords_length) if (coords_length && *coords_length)
{ {
hb_array_t<const HBFixed> instanceCoords = instance->get_coordinates (axisCount) hb_array_t<const F16DOT16> instanceCoords = instance->get_coordinates (axisCount)
.sub_array (0, coords_length); .sub_array (0, coords_length);
for (unsigned int i = 0; i < instanceCoords.length; i++) for (unsigned int i = 0; i < instanceCoords.length; i++)
coords[i] = instanceCoords.arrayZ[i].to_float (); coords[i] = instanceCoords.arrayZ[i].to_float ();
@@ -301,7 +339,7 @@ struct fvar
if (hb_any (+ hb_zip (instance->get_coordinates (axisCount), hb_range ((unsigned)axisCount)) if (hb_any (+ hb_zip (instance->get_coordinates (axisCount), hb_range ((unsigned)axisCount))
| hb_filter (pinned_axes, hb_second) | hb_filter (pinned_axes, hb_second)
| hb_map ([&] (const hb_pair_t<const HBFixed&, unsigned>& _) | hb_map ([&] (const hb_pair_t<const F16DOT16&, unsigned>& _)
{ {
hb_tag_t axis_tag = pinned_axes.get (_.second); hb_tag_t axis_tag = pinned_axes.get (_.second);
float location = user_axes_location->get (axis_tag); float location = user_axes_location->get (axis_tag);
@@ -321,6 +359,48 @@ struct fvar
} }
} }
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
unsigned retained_axis_count = c->plan->axes_index_map->get_population ();
if (!retained_axis_count) //all axes are pinned
return_trace (false);
fvar *out = c->serializer->embed (this);
if (unlikely (!out)) return_trace (false);
if (!c->serializer->check_assign (out->axisCount, retained_axis_count, HB_SERIALIZE_ERROR_INT_OVERFLOW))
return_trace (false);
bool has_postscript_nameid = false;
if (instanceSize >= axisCount * 4 + 6)
has_postscript_nameid = true;
if (!c->serializer->check_assign (out->instanceSize, retained_axis_count * 4 + (has_postscript_nameid ? 6 : 4),
HB_SERIALIZE_ERROR_INT_OVERFLOW))
return_trace (false);
auto axes_records = get_axes ();
for (unsigned i = 0 ; i < (unsigned)axisCount; i++)
{
if (!c->plan->axes_index_map->has (i)) continue;
if (unlikely (!c->serializer->embed (axes_records[i])))
return_trace (false);
}
if (!c->serializer->check_assign (out->firstAxis, get_size (), HB_SERIALIZE_ERROR_INT_OVERFLOW))
return_trace (false);
for (unsigned i = 0 ; i < (unsigned)instanceCount; i++)
{
const InstanceRecord *instance = get_instance (i);
auto snap = c->serializer->snapshot ();
if (!instance->subset (c, axisCount, has_postscript_nameid))
c->serializer->revert (snap);
}
return_trace (true);
}
public: public:
hb_array_t<const AxisRecord> get_axes () const hb_array_t<const AxisRecord> get_axes () const
{ return hb_array (&(this+firstAxis), axisCount); } { return hb_array (&(this+firstAxis), axisCount); }
@@ -346,8 +426,8 @@ struct fvar
HBUINT16 instanceCount; /* The number of named instances defined in the font HBUINT16 instanceCount; /* The number of named instances defined in the font
* (the number of records in the instances array). */ * (the number of records in the instances array). */
HBUINT16 instanceSize; /* The size in bytes of each InstanceRecord — set HBUINT16 instanceSize; /* The size in bytes of each InstanceRecord — set
* to either axisCount * sizeof(HBFixed) + 4, or to * to either axisCount * sizeof(F16DOT16) + 4, or to
* axisCount * sizeof(HBFixed) + 6. */ * axisCount * sizeof(F16DOT16) + 6. */
public: public:
DEFINE_SIZE_STATIC (16); DEFINE_SIZE_STATIC (16);

View File

@@ -244,7 +244,7 @@ bool _process_overflows (const hb_vector_t<graph::overflow_record_t>& overflows,
{ {
// The child object is shared, we may be able to eliminate the overflow // The child object is shared, we may be able to eliminate the overflow
// by duplicating it. // by duplicating it.
if (!sorted_graph.duplicate (r.parent, r.child)) continue; if (sorted_graph.duplicate (r.parent, r.child) == (unsigned) -1) continue;
return true; return true;
} }

View File

@@ -0,0 +1,76 @@
/*
* Copyright © 2022 Google, Inc.
*
* 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.
*
* Google Author(s): Garret Rieger
*/
#ifndef HB_SUBSET_ACCELERATOR_HH
#define HB_SUBSET_ACCELERATOR_HH
#include "hb.hh"
#include "hb-map.hh"
#include "hb-set.hh"
struct hb_subset_accelerator_t
{
static hb_user_data_key_t* user_data_key()
{
static hb_user_data_key_t key;
return &key;
}
static hb_subset_accelerator_t* create(const hb_map_t& unicode_to_gid_,
const hb_set_t& unicodes_) {
hb_subset_accelerator_t* accel =
(hb_subset_accelerator_t*) hb_malloc (sizeof(hb_subset_accelerator_t));
new (accel) hb_subset_accelerator_t (unicode_to_gid_, unicodes_);
return accel;
}
static void destroy(void* value) {
if (!value) return;
hb_subset_accelerator_t* accel = (hb_subset_accelerator_t*) value;
accel->~hb_subset_accelerator_t ();
hb_free (accel);
}
hb_subset_accelerator_t(const hb_map_t& unicode_to_gid_,
const hb_set_t& unicodes_)
: unicode_to_gid(unicode_to_gid_), unicodes(unicodes_) {}
const hb_map_t unicode_to_gid;
const hb_set_t unicodes;
// TODO(garretrieger): cumulative glyf checksum map
// TODO(garretrieger): sanitized table cache.
bool in_error () const
{
return unicode_to_gid.in_error() || unicodes.in_error ();
}
};
#endif /* HB_SUBSET_ACCELERATOR_HH */

View File

@@ -89,7 +89,6 @@ hb_subset_input_create_or_fail (void)
hb_tag_t default_no_subset_tables[] = { hb_tag_t default_no_subset_tables[] = {
HB_TAG ('a', 'v', 'a', 'r'), HB_TAG ('a', 'v', 'a', 'r'),
HB_TAG ('f', 'v', 'a', 'r'),
HB_TAG ('g', 'a', 's', 'p'), HB_TAG ('g', 'a', 's', 'p'),
HB_TAG ('c', 'v', 't', ' '), HB_TAG ('c', 'v', 't', ' '),
HB_TAG ('f', 'p', 'g', 'm'), HB_TAG ('f', 'p', 'g', 'm'),
@@ -393,7 +392,7 @@ hb_subset_input_get_user_data (const hb_subset_input_t *input,
* *
* Since: EXPERIMENTAL * Since: EXPERIMENTAL
**/ **/
hb_bool_t HB_EXTERN hb_bool_t
hb_subset_input_pin_axis_to_default (hb_subset_input_t *input, hb_subset_input_pin_axis_to_default (hb_subset_input_t *input,
hb_face_t *face, hb_face_t *face,
hb_tag_t axis_tag) hb_tag_t axis_tag)
@@ -417,7 +416,7 @@ hb_subset_input_pin_axis_to_default (hb_subset_input_t *input,
* *
* Since: EXPERIMENTAL * Since: EXPERIMENTAL
**/ **/
hb_bool_t HB_EXTERN hb_bool_t
hb_subset_input_pin_axis_location (hb_subset_input_t *input, hb_subset_input_pin_axis_location (hb_subset_input_t *input,
hb_face_t *face, hb_face_t *face,
hb_tag_t axis_tag, hb_tag_t axis_tag,
@@ -432,3 +431,51 @@ hb_subset_input_pin_axis_location (hb_subset_input_t *input,
} }
#endif #endif
#endif #endif
#ifdef HB_EXPERIMENTAL_API
/**
* hb_subset_preprocess
* @input: a #hb_face_t object.
*
* Preprocesses the face and attaches data that will be needed by the
* subsetter. Future subsetting operations can then use the precomputed data
* to speed up the subsetting operation.
*
* Since: EXPERIMENTAL
**/
HB_EXTERN hb_face_t *
hb_subset_preprocess (hb_face_t *source)
{
hb_subset_input_t* input = hb_subset_input_create_or_fail ();
hb_set_clear (hb_subset_input_set(input, HB_SUBSET_SETS_UNICODE));
hb_set_invert (hb_subset_input_set(input, HB_SUBSET_SETS_UNICODE));
hb_set_clear (hb_subset_input_set(input,
HB_SUBSET_SETS_LAYOUT_FEATURE_TAG));
hb_set_invert (hb_subset_input_set(input,
HB_SUBSET_SETS_LAYOUT_FEATURE_TAG));
hb_set_clear (hb_subset_input_set(input,
HB_SUBSET_SETS_LAYOUT_SCRIPT_TAG));
hb_set_invert (hb_subset_input_set(input,
HB_SUBSET_SETS_LAYOUT_SCRIPT_TAG));
hb_set_clear (hb_subset_input_set(input,
HB_SUBSET_SETS_NAME_ID));
hb_set_invert (hb_subset_input_set(input,
HB_SUBSET_SETS_NAME_ID));
hb_subset_input_set_flags(input,
HB_SUBSET_FLAGS_NOTDEF_OUTLINE |
HB_SUBSET_FLAGS_GLYPH_NAMES |
HB_SUBSET_FLAGS_RETAIN_GIDS);
input->attach_accelerator_data = true;
hb_face_t* new_source = hb_subset_or_fail (source, input);
hb_subset_input_destroy (input);
return new_source;
}
#endif

View File

@@ -59,6 +59,7 @@ struct hb_subset_input_t
}; };
unsigned flags; unsigned flags;
bool attach_accelerator_data = false;
hb_hashmap_t<hb_tag_t, float> *axes_location; hb_hashmap_t<hb_tag_t, float> *axes_location;
inline unsigned num_sets () const inline unsigned num_sets () const

View File

@@ -25,6 +25,7 @@
*/ */
#include "hb-subset-plan.hh" #include "hb-subset-plan.hh"
#include "hb-subset-accelerator.hh"
#include "hb-map.hh" #include "hb-map.hh"
#include "hb-set.hh" #include "hb-set.hh"
@@ -129,7 +130,9 @@ template <typename T>
static void _collect_layout_indices (hb_subset_plan_t *plan, static void _collect_layout_indices (hb_subset_plan_t *plan,
const T& table, const T& table,
hb_set_t *lookup_indices, /* OUT */ hb_set_t *lookup_indices, /* OUT */
hb_set_t *feature_indices /* OUT */) hb_set_t *feature_indices, /* OUT */
hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *feature_record_cond_idx_map, /* OUT */
hb_hashmap_t<unsigned, const OT::Feature*> *feature_substitutes_map /* OUT */)
{ {
unsigned num_features = table.get_feature_count (); unsigned num_features = table.get_feature_count ();
hb_vector_t<hb_tag_t> features; hb_vector_t<hb_tag_t> features;
@@ -154,16 +157,37 @@ static void _collect_layout_indices (hb_subset_plan_t *plan,
retain_all_features ? nullptr : features.arrayZ, retain_all_features ? nullptr : features.arrayZ,
feature_indices); feature_indices);
#ifndef HB_NO_VAR
// collect feature substitutes with variations
if (!plan->user_axes_location->is_empty ())
{
hb_hashmap_t<hb::shared_ptr<hb_map_t>, unsigned> conditionset_map;
OT::hb_collect_feature_substitutes_with_var_context_t c =
{
plan->axes_old_index_tag_map,
plan->axes_location,
feature_record_cond_idx_map,
feature_substitutes_map,
feature_indices,
true,
0,
&conditionset_map
};
table.collect_feature_substitutes_with_variations (&c);
}
#endif
for (unsigned feature_index : *feature_indices) for (unsigned feature_index : *feature_indices)
{ {
//TODO: replace HB_OT_LAYOUT_NO_VARIATIONS_INDEX with variation_index for const OT::Feature* f = &(table.get_feature (feature_index));
//instancing const OT::Feature **p = nullptr;
const OT::Feature &f = table.get_feature_variation (feature_index, HB_OT_LAYOUT_NO_VARIATIONS_INDEX); if (feature_substitutes_map->has (feature_index, &p))
f.add_lookup_indexes_to (lookup_indices); f = *p;
f->add_lookup_indexes_to (lookup_indices);
} }
//TODO: update for instancing: only collect lookups from feature_indexes that have no variations table.feature_variation_collect_lookups (feature_indices, feature_substitutes_map, lookup_indices);
table.feature_variation_collect_lookups (feature_indices, lookup_indices);
} }
@@ -171,6 +195,7 @@ static inline void
_GSUBGPOS_find_duplicate_features (const OT::GSUBGPOS &g, _GSUBGPOS_find_duplicate_features (const OT::GSUBGPOS &g,
const hb_map_t *lookup_indices, const hb_map_t *lookup_indices,
const hb_set_t *feature_indices, const hb_set_t *feature_indices,
const hb_hashmap_t<unsigned, const OT::Feature*> *feature_substitutes_map,
hb_map_t *duplicate_feature_map /* OUT */) hb_map_t *duplicate_feature_map /* OUT */)
{ {
if (feature_indices->is_empty ()) return; if (feature_indices->is_empty ()) return;
@@ -195,16 +220,22 @@ _GSUBGPOS_find_duplicate_features (const OT::GSUBGPOS &g,
hb_set_t* same_tag_features = unique_features.get (t); hb_set_t* same_tag_features = unique_features.get (t);
for (unsigned other_f_index : same_tag_features->iter ()) for (unsigned other_f_index : same_tag_features->iter ())
{ {
const OT::Feature& f = g.get_feature (i); const OT::Feature* f = &(g.get_feature (i));
const OT::Feature& other_f = g.get_feature (other_f_index); const OT::Feature **p = nullptr;
if (feature_substitutes_map->has (i, &p))
f = *p;
const OT::Feature* other_f = &(g.get_feature (other_f_index));
if (feature_substitutes_map->has (other_f_index, &p))
f = *p;
auto f_iter = auto f_iter =
+ hb_iter (f.lookupIndex) + hb_iter (f->lookupIndex)
| hb_filter (lookup_indices) | hb_filter (lookup_indices)
; ;
auto other_f_iter = auto other_f_iter =
+ hb_iter (other_f.lookupIndex) + hb_iter (other_f->lookupIndex)
| hb_filter (lookup_indices) | hb_filter (lookup_indices)
; ;
@@ -237,7 +268,9 @@ _closure_glyphs_lookups_features (hb_subset_plan_t *plan,
hb_set_t *gids_to_retain, hb_set_t *gids_to_retain,
hb_map_t *lookups, hb_map_t *lookups,
hb_map_t *features, hb_map_t *features,
script_langsys_map *langsys_map) script_langsys_map *langsys_map,
hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *feature_record_cond_idx_map,
hb_hashmap_t<unsigned, const OT::Feature*> *feature_substitutes_map)
{ {
hb_blob_ptr_t<T> table = plan->source_table<T> (); hb_blob_ptr_t<T> table = plan->source_table<T> ();
hb_tag_t table_tag = table->tableTag; hb_tag_t table_tag = table->tableTag;
@@ -245,7 +278,9 @@ _closure_glyphs_lookups_features (hb_subset_plan_t *plan,
_collect_layout_indices<T> (plan, _collect_layout_indices<T> (plan,
*table, *table,
&lookup_indices, &lookup_indices,
&feature_indices); &feature_indices,
feature_record_cond_idx_map,
feature_substitutes_map);
if (table_tag == HB_OT_TAG_GSUB) if (table_tag == HB_OT_TAG_GSUB)
hb_ot_layout_lookups_substitute_closure (plan->source, hb_ot_layout_lookups_substitute_closure (plan->source,
@@ -257,9 +292,12 @@ _closure_glyphs_lookups_features (hb_subset_plan_t *plan,
_remap_indexes (&lookup_indices, lookups); _remap_indexes (&lookup_indices, lookups);
// prune features // prune features
table->prune_features (lookups, &feature_indices); table->prune_features (lookups,
plan->user_axes_location->is_empty () ? nullptr : feature_record_cond_idx_map,
feature_substitutes_map,
&feature_indices);
hb_map_t duplicate_feature_map; hb_map_t duplicate_feature_map;
_GSUBGPOS_find_duplicate_features (*table, lookups, &feature_indices, &duplicate_feature_map); _GSUBGPOS_find_duplicate_features (*table, lookups, &feature_indices, feature_substitutes_map, &duplicate_feature_map);
feature_indices.clear (); feature_indices.clear ();
table->prune_langsys (&duplicate_feature_map, plan->layout_scripts, langsys_map, &feature_indices); table->prune_langsys (&duplicate_feature_map, plan->layout_scripts, langsys_map, &feature_indices);
@@ -419,14 +457,19 @@ _populate_unicodes_to_retain (const hb_set_t *unicodes,
hb_subset_plan_t *plan) hb_subset_plan_t *plan)
{ {
OT::cmap::accelerator_t cmap (plan->source); OT::cmap::accelerator_t cmap (plan->source);
unsigned size_threshold = plan->source->get_num_glyphs (); unsigned size_threshold = plan->source->get_num_glyphs ();
if (glyphs->is_empty () && unicodes->get_population () < size_threshold) if (glyphs->is_empty () && unicodes->get_population () < size_threshold)
{ {
const hb_map_t* unicode_to_gid = nullptr;
if (plan->accelerator)
unicode_to_gid = &plan->accelerator->unicode_to_gid;
// This is approach to collection is faster, but can only be used if glyphs // This is approach to collection is faster, but can only be used if glyphs
// are not being explicitly added to the subset and the input unicodes set is // are not being explicitly added to the subset and the input unicodes set is
// not excessively large (eg. an inverted set). // not excessively large (eg. an inverted set).
plan->unicode_to_new_gid_list.alloc (unicodes->get_population ()); plan->unicode_to_new_gid_list.alloc (unicodes->get_population ());
if (!unicode_to_gid) {
for (hb_codepoint_t cp : *unicodes) for (hb_codepoint_t cp : *unicodes)
{ {
hb_codepoint_t gid; hb_codepoint_t gid;
@@ -439,21 +482,48 @@ _populate_unicodes_to_retain (const hb_set_t *unicodes,
plan->codepoint_to_glyph->set (cp, gid); plan->codepoint_to_glyph->set (cp, gid);
plan->unicode_to_new_gid_list.push (hb_pair (cp, gid)); plan->unicode_to_new_gid_list.push (hb_pair (cp, gid));
} }
} else {
// Use in memory unicode to gid map it's faster then looking up from
// the map. This code is mostly duplicated from above to avoid doing
// conditionals on the presence of the unicode_to_gid map each
// iteration.
for (hb_codepoint_t cp : *unicodes)
{
hb_codepoint_t gid = unicode_to_gid->get (cp);
if (gid == HB_MAP_VALUE_INVALID)
{
DEBUG_MSG(SUBSET, nullptr, "Drop U+%04X; no gid", cp);
continue;
}
plan->codepoint_to_glyph->set (cp, gid);
plan->unicode_to_new_gid_list.push (hb_pair (cp, gid));
}
}
} }
else else
{ {
// This approach is slower, but can handle adding in glyphs to the subset and will match // This approach is slower, but can handle adding in glyphs to the subset and will match
// them with cmap entries. // them with cmap entries.
hb_map_t unicode_glyphid_map;
hb_set_t cmap_unicodes; hb_map_t unicode_glyphid_map_storage;
cmap.collect_mapping (&cmap_unicodes, &unicode_glyphid_map); hb_set_t cmap_unicodes_storage;
const hb_map_t* unicode_glyphid_map = &unicode_glyphid_map_storage;
const hb_set_t* cmap_unicodes = &cmap_unicodes_storage;
if (!plan->accelerator) {
cmap.collect_mapping (&cmap_unicodes_storage, &unicode_glyphid_map_storage);
plan->unicode_to_new_gid_list.alloc (hb_min(unicodes->get_population () plan->unicode_to_new_gid_list.alloc (hb_min(unicodes->get_population ()
+ glyphs->get_population (), + glyphs->get_population (),
cmap_unicodes.get_population ())); cmap_unicodes->get_population ()));
} else {
unicode_glyphid_map = &plan->accelerator->unicode_to_gid;
cmap_unicodes = &plan->accelerator->unicodes;
}
for (hb_codepoint_t cp : cmap_unicodes) for (hb_codepoint_t cp : *cmap_unicodes)
{ {
hb_codepoint_t gid = unicode_glyphid_map[cp]; hb_codepoint_t gid = (*unicode_glyphid_map)[cp];
if (!unicodes->has (cp) && !glyphs->has (gid)) if (!unicodes->has (cp) && !glyphs->has (gid))
continue; continue;
@@ -509,9 +579,7 @@ _glyf_add_gid_and_children (const OT::glyf_accelerator_t &glyf,
static void static void
_populate_gids_to_retain (hb_subset_plan_t* plan, _populate_gids_to_retain (hb_subset_plan_t* plan,
bool close_over_gsub, hb_set_t* drop_tables)
bool close_over_gpos,
bool close_over_gdef)
{ {
OT::glyf_accelerator_t glyf (plan->source); OT::glyf_accelerator_t glyf (plan->source);
#ifndef HB_NO_SUBSET_CFF #ifndef HB_NO_SUBSET_CFF
@@ -523,32 +591,42 @@ _populate_gids_to_retain (hb_subset_plan_t* plan,
_cmap_closure (plan->source, plan->unicodes, plan->_glyphset_gsub); _cmap_closure (plan->source, plan->unicodes, plan->_glyphset_gsub);
#ifndef HB_NO_SUBSET_LAYOUT #ifndef HB_NO_SUBSET_LAYOUT
if (close_over_gsub) if (!drop_tables->has (HB_OT_TAG_GSUB))
// closure all glyphs/lookups/features needed for GSUB substitutions. // closure all glyphs/lookups/features needed for GSUB substitutions.
_closure_glyphs_lookups_features<GSUB> ( _closure_glyphs_lookups_features<GSUB> (
plan, plan,
plan->_glyphset_gsub, plan->_glyphset_gsub,
plan->gsub_lookups, plan->gsub_lookups,
plan->gsub_features, plan->gsub_features,
plan->gsub_langsys); plan->gsub_langsys,
plan->gsub_feature_record_cond_idx_map,
plan->gsub_feature_substitutes_map);
if (close_over_gpos) if (!drop_tables->has (HB_OT_TAG_GPOS))
_closure_glyphs_lookups_features<GPOS> ( _closure_glyphs_lookups_features<GPOS> (
plan, plan,
plan->_glyphset_gsub, plan->_glyphset_gsub,
plan->gpos_lookups, plan->gpos_lookups,
plan->gpos_features, plan->gpos_features,
plan->gpos_langsys); plan->gpos_langsys,
plan->gpos_feature_record_cond_idx_map,
plan->gpos_feature_substitutes_map);
#endif #endif
_remove_invalid_gids (plan->_glyphset_gsub, plan->source->get_num_glyphs ()); _remove_invalid_gids (plan->_glyphset_gsub, plan->source->get_num_glyphs ());
hb_set_set (plan->_glyphset_mathed, plan->_glyphset_gsub); hb_set_set (plan->_glyphset_mathed, plan->_glyphset_gsub);
if (!drop_tables->has (HB_OT_TAG_MATH))
{
_math_closure (plan, plan->_glyphset_mathed); _math_closure (plan, plan->_glyphset_mathed);
_remove_invalid_gids (plan->_glyphset_mathed, plan->source->get_num_glyphs ()); _remove_invalid_gids (plan->_glyphset_mathed, plan->source->get_num_glyphs ());
}
hb_set_t cur_glyphset = *plan->_glyphset_mathed; hb_set_t cur_glyphset = *plan->_glyphset_mathed;
if (!drop_tables->has (HB_OT_TAG_COLR))
{
_colr_closure (plan->source, plan->colrv1_layers, plan->colr_palettes, &cur_glyphset); _colr_closure (plan->source, plan->colrv1_layers, plan->colr_palettes, &cur_glyphset);
_remove_invalid_gids (&cur_glyphset, plan->source->get_num_glyphs ()); _remove_invalid_gids (&cur_glyphset, plan->source->get_num_glyphs ());
}
hb_set_set (plan->_glyphset_colred, &cur_glyphset); hb_set_set (plan->_glyphset_colred, &cur_glyphset);
@@ -570,7 +648,7 @@ _populate_gids_to_retain (hb_subset_plan_t* plan,
#ifndef HB_NO_VAR #ifndef HB_NO_VAR
if (close_over_gdef) if (!drop_tables->has (HB_OT_TAG_GDEF))
_collect_layout_variation_indices (plan); _collect_layout_variation_indices (plan);
#endif #endif
} }
@@ -659,18 +737,22 @@ _normalize_axes_location (hb_face_t *face, hb_subset_plan_t *plan)
seg_maps = face->table.avar->get_segment_maps (); seg_maps = face->table.avar->get_segment_maps ();
bool axis_not_pinned = false; bool axis_not_pinned = false;
unsigned axis_count = 0; unsigned old_axis_idx = 0, new_axis_idx = 0;
for (const auto& axis : axes) for (const auto& axis : axes)
{ {
hb_tag_t axis_tag = axis.get_axis_tag (); hb_tag_t axis_tag = axis.get_axis_tag ();
plan->axes_old_index_tag_map->set (old_axis_idx, axis_tag);
if (!plan->user_axes_location->has (axis_tag)) if (!plan->user_axes_location->has (axis_tag))
{ {
axis_not_pinned = true; axis_not_pinned = true;
plan->axes_index_map->set (old_axis_idx, new_axis_idx);
new_axis_idx++;
} }
else else
{ {
int normalized_v = axis.normalize_axis_value (plan->user_axes_location->get (axis_tag)); int normalized_v = axis.normalize_axis_value (plan->user_axes_location->get (axis_tag));
if (has_avar && axis_count < face->table.avar->get_axis_count ()) if (has_avar && old_axis_idx < face->table.avar->get_axis_count ())
{ {
normalized_v = seg_maps->map (normalized_v); normalized_v = seg_maps->map (normalized_v);
} }
@@ -681,7 +763,7 @@ _normalize_axes_location (hb_face_t *face, hb_subset_plan_t *plan)
if (has_avar) if (has_avar)
seg_maps = &StructAfter<OT::SegmentMaps> (*seg_maps); seg_maps = &StructAfter<OT::SegmentMaps> (*seg_maps);
axis_count++; old_axis_idx++;
} }
plan->all_axes_pinned = !axis_not_pinned; plan->all_axes_pinned = !axis_not_pinned;
} }
@@ -741,6 +823,13 @@ hb_subset_plan_create_or_fail (hb_face_t *face,
plan->gsub_features = hb_map_create (); plan->gsub_features = hb_map_create ();
plan->gpos_features = hb_map_create (); plan->gpos_features = hb_map_create ();
plan->check_success (plan->gsub_feature_record_cond_idx_map = hb_hashmap_create<unsigned, hb::shared_ptr<hb_set_t>> ());
plan->check_success (plan->gpos_feature_record_cond_idx_map = hb_hashmap_create<unsigned, hb::shared_ptr<hb_set_t>> ());
plan->check_success (plan->gsub_feature_substitutes_map = hb_hashmap_create<unsigned, const OT::Feature*> ());
plan->check_success (plan->gpos_feature_substitutes_map = hb_hashmap_create<unsigned, const OT::Feature*> ());
plan->colrv1_layers = hb_map_create (); plan->colrv1_layers = hb_map_create ();
plan->colr_palettes = hb_map_create (); plan->colr_palettes = hb_map_create ();
plan->check_success (plan->layout_variation_idx_delta_map = hb_hashmap_create<unsigned, hb_pair_t<unsigned, int>> ()); plan->check_success (plan->layout_variation_idx_delta_map = hb_hashmap_create<unsigned, hb_pair_t<unsigned, int>> ());
@@ -751,12 +840,21 @@ hb_subset_plan_create_or_fail (hb_face_t *face,
plan->check_success (plan->user_axes_location = hb_hashmap_create<hb_tag_t, float> ()); plan->check_success (plan->user_axes_location = hb_hashmap_create<hb_tag_t, float> ());
if (plan->user_axes_location && input->axes_location) if (plan->user_axes_location && input->axes_location)
*plan->user_axes_location = *input->axes_location; *plan->user_axes_location = *input->axes_location;
plan->check_success (plan->axes_index_map = hb_map_create ());
plan->check_success (plan->axes_old_index_tag_map = hb_map_create ());
plan->all_axes_pinned = false; plan->all_axes_pinned = false;
plan->pinned_at_default = true; plan->pinned_at_default = true;
plan->check_success (plan->vmtx_map = hb_hashmap_create<unsigned, hb_pair_t<unsigned, int>> ()); plan->check_success (plan->vmtx_map = hb_hashmap_create<unsigned, hb_pair_t<unsigned, int>> ());
plan->check_success (plan->hmtx_map = hb_hashmap_create<unsigned, hb_pair_t<unsigned, int>> ()); plan->check_success (plan->hmtx_map = hb_hashmap_create<unsigned, hb_pair_t<unsigned, int>> ());
void* accel = hb_face_get_user_data(face, hb_subset_accelerator_t::user_data_key());
plan->attach_accelerator_data = input->attach_accelerator_data;
if (accel)
plan->accelerator = (hb_subset_accelerator_t*) accel;
if (unlikely (plan->in_error ())) { if (unlikely (plan->in_error ())) {
hb_subset_plan_destroy (plan); hb_subset_plan_destroy (plan);
return nullptr; return nullptr;
@@ -768,10 +866,7 @@ hb_subset_plan_create_or_fail (hb_face_t *face,
_populate_unicodes_to_retain (input->sets.unicodes, input->sets.glyphs, plan); _populate_unicodes_to_retain (input->sets.unicodes, input->sets.glyphs, plan);
_populate_gids_to_retain (plan, _populate_gids_to_retain (plan, input->sets.drop_tables);
!input->sets.drop_tables->has (HB_OT_TAG_GSUB),
!input->sets.drop_tables->has (HB_OT_TAG_GPOS),
!input->sets.drop_tables->has (HB_OT_TAG_GDEF));
_create_old_gid_to_new_gid_map (face, _create_old_gid_to_new_gid_map (face,
input->flags & HB_SUBSET_FLAGS_RETAIN_GIDS, input->flags & HB_SUBSET_FLAGS_RETAIN_GIDS,

View File

@@ -31,11 +31,16 @@
#include "hb-subset.h" #include "hb-subset.h"
#include "hb-subset-input.hh" #include "hb-subset-input.hh"
#include "hb-subset-accelerator.hh"
#include "hb-map.hh" #include "hb-map.hh"
#include "hb-bimap.hh" #include "hb-bimap.hh"
#include "hb-set.hh" #include "hb-set.hh"
namespace OT {
struct Feature;
}
struct hb_subset_plan_t struct hb_subset_plan_t
{ {
hb_subset_plan_t () hb_subset_plan_t ()
@@ -67,9 +72,15 @@ struct hb_subset_plan_t
hb_map_destroy (gpos_features); hb_map_destroy (gpos_features);
hb_map_destroy (colrv1_layers); hb_map_destroy (colrv1_layers);
hb_map_destroy (colr_palettes); hb_map_destroy (colr_palettes);
hb_map_destroy (axes_index_map);
hb_map_destroy (axes_old_index_tag_map);
hb_hashmap_destroy (gsub_langsys); hb_hashmap_destroy (gsub_langsys);
hb_hashmap_destroy (gpos_langsys); hb_hashmap_destroy (gpos_langsys);
hb_hashmap_destroy (gsub_feature_record_cond_idx_map);
hb_hashmap_destroy (gpos_feature_record_cond_idx_map);
hb_hashmap_destroy (gsub_feature_substitutes_map);
hb_hashmap_destroy (gpos_feature_substitutes_map);
hb_hashmap_destroy (axes_location); hb_hashmap_destroy (axes_location);
hb_hashmap_destroy (sanitized_table_cache); hb_hashmap_destroy (sanitized_table_cache);
hb_hashmap_destroy (hmtx_map); hb_hashmap_destroy (hmtx_map);
@@ -87,6 +98,7 @@ struct hb_subset_plan_t
bool successful; bool successful;
unsigned flags; unsigned flags;
bool attach_accelerator_data = false;
// For each cp that we'd like to retain maps to the corresponding gid. // For each cp that we'd like to retain maps to the corresponding gid.
hb_set_t *unicodes; hb_set_t *unicodes;
@@ -143,6 +155,15 @@ struct hb_subset_plan_t
hb_map_t *gsub_features; hb_map_t *gsub_features;
hb_map_t *gpos_features; hb_map_t *gpos_features;
//active feature variation records/condition index with variations
hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *gsub_feature_record_cond_idx_map;
hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *gpos_feature_record_cond_idx_map;
//feature index-> address of substituation feature table mapping with
//variations
hb_hashmap_t<unsigned, const OT::Feature*> *gsub_feature_substitutes_map;
hb_hashmap_t<unsigned, const OT::Feature*> *gpos_feature_substitutes_map;
//active layers/palettes we'd like to retain //active layers/palettes we'd like to retain
hb_map_t *colrv1_layers; hb_map_t *colrv1_layers;
hb_map_t *colr_palettes; hb_map_t *colr_palettes;
@@ -158,6 +179,10 @@ struct hb_subset_plan_t
hb_hashmap_t<hb_tag_t, int> *axes_location; hb_hashmap_t<hb_tag_t, int> *axes_location;
//user specified axes location map //user specified axes location map
hb_hashmap_t<hb_tag_t, float> *user_axes_location; hb_hashmap_t<hb_tag_t, float> *user_axes_location;
//retained old axis index -> new axis index mapping in fvar axis array
hb_map_t *axes_index_map;
//axis_index->axis_tag mapping in fvar axis array
hb_map_t *axes_old_index_tag_map;
bool all_axes_pinned; bool all_axes_pinned;
bool pinned_at_default; bool pinned_at_default;
@@ -166,6 +191,8 @@ struct hb_subset_plan_t
//vmtx metrics map: new gid->(advance, lsb) //vmtx metrics map: new gid->(advance, lsb)
hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *vmtx_map; hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *vmtx_map;
const hb_subset_accelerator_t* accelerator;
public: public:
template<typename T> template<typename T>

View File

@@ -50,11 +50,13 @@
#include "hb-ot-color-cbdt-table.hh" #include "hb-ot-color-cbdt-table.hh"
#include "hb-ot-layout-gsub-table.hh" #include "hb-ot-layout-gsub-table.hh"
#include "hb-ot-layout-gpos-table.hh" #include "hb-ot-layout-gpos-table.hh"
#include "hb-ot-var-fvar-table.hh"
#include "hb-ot-var-gvar-table.hh" #include "hb-ot-var-gvar-table.hh"
#include "hb-ot-var-hvar-table.hh" #include "hb-ot-var-hvar-table.hh"
#include "hb-ot-math-table.hh" #include "hb-ot-math-table.hh"
#include "hb-ot-stat-table.hh" #include "hb-ot-stat-table.hh"
#include "hb-repacker.hh" #include "hb-repacker.hh"
#include "hb-subset-accelerator.hh"
using OT::Layout::GSUB; using OT::Layout::GSUB;
using OT::Layout::GPOS; using OT::Layout::GPOS;
@@ -475,6 +477,9 @@ _subset_table (hb_subset_plan_t *plan,
case HB_OT_TAG_HVAR: return _subset<const OT::HVAR> (plan, buf); case HB_OT_TAG_HVAR: return _subset<const OT::HVAR> (plan, buf);
case HB_OT_TAG_VVAR: return _subset<const OT::VVAR> (plan, buf); case HB_OT_TAG_VVAR: return _subset<const OT::VVAR> (plan, buf);
#endif #endif
case HB_OT_TAG_fvar:
if (plan->user_axes_location->is_empty ()) return _passthrough (plan, tag);
return _subset<const OT::fvar> (plan, buf);
case HB_OT_TAG_STAT: case HB_OT_TAG_STAT:
/*TODO(qxliu): change the condition as we support more complex /*TODO(qxliu): change the condition as we support more complex
* instancing operation*/ * instancing operation*/
@@ -490,6 +495,27 @@ _subset_table (hb_subset_plan_t *plan,
} }
} }
static void _attach_accelerator_data (const hb_subset_plan_t* plan,
hb_face_t* face /* IN/OUT */)
{
hb_subset_accelerator_t* accel =
hb_subset_accelerator_t::create (*plan->codepoint_to_glyph,
*plan->unicodes);
if (accel->in_error ())
{
hb_subset_accelerator_t::destroy (accel);
return;
}
if (!hb_face_set_user_data(face,
hb_subset_accelerator_t::user_data_key(),
accel,
hb_subset_accelerator_t::destroy,
true))
hb_subset_accelerator_t::destroy (accel);
}
/** /**
* hb_subset_or_fail: * hb_subset_or_fail:
* @source: font face data to be subset. * @source: font face data to be subset.
@@ -572,6 +598,10 @@ hb_subset_plan_execute_or_fail (hb_subset_plan_t *plan)
offset += num_tables; offset += num_tables;
} }
if (success && plan->attach_accelerator_data) {
_attach_accelerator_data (plan, plan->dest);
}
end: end:
return success ? hb_face_reference (plan->dest) : nullptr; return success ? hb_face_reference (plan->dest) : nullptr;
} }

View File

@@ -70,6 +70,14 @@ typedef struct hb_subset_plan_t hb_subset_plan_t;
* in the final subset. * in the final subset.
* @HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES: If set then the unicode ranges in * @HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES: If set then the unicode ranges in
* OS/2 will not be recalculated. * OS/2 will not be recalculated.
* @HB_SUBSET_FLAGS_PATCH_MODE: If set the subsetter behaviour will be modified
* to produce a subset that is better suited to patching. For example cmap
* subtable format will be kept stable.
* @HB_SUBSET_FLAGS_OMIT_GLYF: If set the subsetter won't actually produce the final
* glyf table bytes. The table directory will include and entry as if the table was
* there but the actual final font blob will be truncated prior to the glyf data. This
* is a useful performance optimization when a font aware binary patching algorithm
* is being used to diff two subsets.
* *
* List of boolean properties that can be configured on the subset input. * List of boolean properties that can be configured on the subset input.
* *
@@ -86,6 +94,8 @@ typedef enum { /*< flags >*/
HB_SUBSET_FLAGS_NOTDEF_OUTLINE = 0x00000040u, HB_SUBSET_FLAGS_NOTDEF_OUTLINE = 0x00000040u,
HB_SUBSET_FLAGS_GLYPH_NAMES = 0x00000080u, HB_SUBSET_FLAGS_GLYPH_NAMES = 0x00000080u,
HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES = 0x00000100u, HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES = 0x00000100u,
// Not supported yet: HB_SUBSET_FLAGS_PATCH_MODE = 0x00000200u,
// Not supported yet: HB_SUBSET_FLAGS_OMIT_GLYF = 0x00000400u,
} hb_subset_flags_t; } hb_subset_flags_t;
/** /**
@@ -169,6 +179,13 @@ hb_subset_input_pin_axis_location (hb_subset_input_t *input,
#endif #endif
#endif #endif
#ifdef HB_EXPERIMENTAL_API
HB_EXTERN hb_face_t *
hb_subset_preprocess (hb_face_t *source);
#endif
HB_EXTERN hb_face_t * HB_EXTERN hb_face_t *
hb_subset_or_fail (hb_face_t *source, const hb_subset_input_t *input); hb_subset_or_fail (hb_face_t *source, const hb_subset_input_t *input);

View File

@@ -47,20 +47,20 @@ HB_BEGIN_DECLS
* *
* The minor component of the library version available at compile-time. * The minor component of the library version available at compile-time.
*/ */
#define HB_VERSION_MINOR 2 #define HB_VERSION_MINOR 3
/** /**
* HB_VERSION_MICRO: * HB_VERSION_MICRO:
* *
* The micro component of the library version available at compile-time. * The micro component of the library version available at compile-time.
*/ */
#define HB_VERSION_MICRO 0 #define HB_VERSION_MICRO 1
/** /**
* HB_VERSION_STRING: * HB_VERSION_STRING:
* *
* A string literal containing the library version available at compile-time. * A string literal containing the library version available at compile-time.
*/ */
#define HB_VERSION_STRING "5.2.0" #define HB_VERSION_STRING "5.3.1"
/** /**
* HB_VERSION_ATLEAST: * HB_VERSION_ATLEAST: