Update HarfBuzz to 12.1.0

This commit is contained in:
DeeJayLSP 2025-10-12 20:05:24 -03:00
parent cb7cd815ee
commit 276e1c222c
132 changed files with 8318 additions and 6792 deletions

View file

@ -55,6 +55,7 @@ if env["builtin_harfbuzz"]:
# "src/hb-glib.cc",
# "src/hb-gobject-structs.cc",
"src/hb-icu.cc",
# "src/hb-kbts.cc",
"src/hb-map.cc",
"src/hb-number.cc",
"src/hb-ot-cff1-table.cc",
@ -95,14 +96,19 @@ if env["builtin_harfbuzz"]:
"src/hb-shaper.cc",
"src/hb-static.cc",
"src/hb-style.cc",
"src/hb-subset-cff-common.cc",
"src/hb-subset-cff1.cc",
"src/hb-subset-cff2.cc",
"src/hb-subset-input.cc",
"src/hb-subset-instancer-iup.cc",
"src/hb-subset-instancer-solver.cc",
"src/hb-subset-plan.cc",
"src/hb-subset-serialize.cc",
# "src/hb-subset-cff-common.cc",
# "src/hb-subset-cff1.cc",
# "src/hb-subset-cff2.cc",
# "src/hb-subset-input.cc",
# "src/hb-subset-instancer-iup.cc",
# "src/hb-subset-instancer-solver.cc",
# "src/hb-subset-plan.cc",
# "src/hb-subset-serialize.cc",
# "src/hb-subset-table-cff.cc",
# "src/hb-subset-table-color.cc",
# "src/hb-subset-table-layout.cc",
# "src/hb-subset-table-other.cc",
# "src/hb-subset-table-var.cc",
"src/hb-subset.cc",
"src/hb-ucd.cc",
"src/hb-unicode.cc",

View file

@ -436,7 +436,7 @@ Patches:
## harfbuzz
- Upstream: https://github.com/harfbuzz/harfbuzz
- Version: 11.3.2 (4e3df1c1383481ed5717603d5dd3453a04fb16ba, 2025)
- Version: 12.1.0 (a790c38b782f9d8e6f0299d2837229e5726fc669, 2025)
- License: MIT
Files extracted from upstream source:

View file

@ -178,7 +178,10 @@ struct hb_colrv1_closure_context_t :
{ glyphs->add (glyph_id); }
void add_layer_indices (unsigned first_layer_index, unsigned num_of_layers)
{ layer_indices->add_range (first_layer_index, first_layer_index + num_of_layers - 1); }
{
if (num_of_layers == 0) return;
layer_indices->add_range (first_layer_index, first_layer_index + num_of_layers - 1);
}
void add_palette_index (unsigned palette_index)
{ palette_indices->add (palette_index); }
@ -650,10 +653,10 @@ struct PaintColrLayers
TRACE_SUBSET (this);
auto *out = c->serializer->embed (this);
if (unlikely (!out)) return_trace (false);
return_trace (c->serializer->check_assign (out->firstLayerIndex, c->plan->colrv1_layers.get (firstLayerIndex),
HB_SERIALIZE_ERROR_INT_OVERFLOW));
return_trace (true);
uint32_t first_layer_index = numLayers ? c->plan->colrv1_layers.get (firstLayerIndex) : 0;
return_trace (c->serializer->check_assign (out->firstLayerIndex, first_layer_index,
HB_SERIALIZE_ERROR_INT_OVERFLOW));
}
bool sanitize (hb_sanitize_context_t *c) const
@ -2057,7 +2060,7 @@ struct delta_set_index_map_subset_plan_t
outer_bit_count = 1;
inner_bit_count = 1;
if (unlikely (!output_map.resize (map_count, false))) return false;
if (unlikely (!output_map.resize_dirty (map_count))) return false;
for (unsigned idx = 0; idx < map_count; idx++)
{

View file

@ -307,6 +307,7 @@ struct CPAL
if (first_color_to_layer_index.has (first_color_record_idx)) continue;
first_color_index_for_layer.push (first_color_record_idx);
if (unlikely (!c->serializer->propagate_error (first_color_index_for_layer))) return_trace (false);
first_color_to_layer_index.set (first_color_record_idx,
first_color_index_for_layer.length - 1);
}

View file

@ -97,12 +97,17 @@ struct Coverage
}
}
unsigned int get_coverage (hb_codepoint_t glyph_id,
hb_ot_lookup_cache_t *cache) const
hb_ot_layout_mapping_cache_t *cache) const
{
unsigned coverage;
if (cache && cache->get (glyph_id, &coverage)) return coverage;
if (cache && cache->get (glyph_id, &coverage)) return coverage < cache->MAX_VALUE ? coverage : NOT_COVERED;
coverage = get_coverage (glyph_id);
if (cache) cache->set (glyph_id, coverage);
if (cache) {
if (coverage == NOT_COVERED)
cache->set_unchecked (glyph_id, cache->MAX_VALUE);
else if (likely (coverage < cache->MAX_VALUE))
cache->set_unchecked (glyph_id, coverage);
}
return coverage;
}
@ -332,7 +337,7 @@ struct Coverage
}
iter_t __end__ () const
{
iter_t it = {};
iter_t it;
it.format = format;
switch (format)
{

View file

@ -977,7 +977,7 @@ struct GDEF
}
#ifndef HB_NO_GDEF_CACHE
table->get_mark_glyph_sets ().collect_coverage (mark_glyph_set_digests);
table->get_mark_glyph_sets ().collect_coverage (mark_glyph_sets);
#endif
}
~accelerator_t () { table.destroy (); }
@ -1006,14 +1006,16 @@ struct GDEF
{
return
#ifndef HB_NO_GDEF_CACHE
mark_glyph_set_digests[set_index].may_have (glyph_id) &&
mark_glyph_sets[set_index].may_have (glyph_id)
#else
table->mark_set_covers (set_index, glyph_id)
#endif
table->mark_set_covers (set_index, glyph_id);
;
}
hb_blob_ptr_t<GDEF> table;
#ifndef HB_NO_GDEF_CACHE
hb_vector_t<hb_set_digest_t> mark_glyph_set_digests;
hb_vector_t<hb_bit_set_t> mark_glyph_sets;
mutable hb_cache_t<21, 3> glyph_props_cache;
static_assert (sizeof (glyph_props_cache) == 512, "");
#endif

View file

@ -77,6 +77,13 @@ struct AnchorMatrix
return_trace (true);
}
bool offset_is_null (unsigned row, unsigned col, unsigned num_cols) const
{
if (unlikely (row >= rows || col >= num_cols)) return true;
auto &offset = matrixZ[row * num_cols + col];
return offset.is_null ();
}
};

View file

@ -80,9 +80,8 @@ propagate_attachment_offsets (hb_glyph_position_t *pos,
{
/* Adjusts offsets of attached glyphs (both cursive and mark) to accumulate
* offset of glyph they are attached to. */
int chain = pos[i].attach_chain(), type = pos[i].attach_type();
if (likely (!chain))
return;
int chain = pos[i].attach_chain();
int type = pos[i].attach_type();
pos[i].attach_chain() = 0;
@ -94,7 +93,8 @@ propagate_attachment_offsets (hb_glyph_position_t *pos,
if (unlikely (!nesting_level))
return;
propagate_attachment_offsets (pos, len, j, direction, nesting_level - 1);
if (pos[j].attach_chain())
propagate_attachment_offsets (pos, len, j, direction, nesting_level - 1);
assert (!!(type & GPOS_impl::ATTACH_TYPE_MARK) ^ !!(type & GPOS_impl::ATTACH_TYPE_CURSIVE));
@ -110,17 +110,37 @@ propagate_attachment_offsets (hb_glyph_position_t *pos,
pos[i].x_offset += pos[j].x_offset;
pos[i].y_offset += pos[j].y_offset;
assert (j < i);
if (HB_DIRECTION_IS_FORWARD (direction))
for (unsigned int k = j; k < i; k++) {
pos[i].x_offset -= pos[k].x_advance;
pos[i].y_offset -= pos[k].y_advance;
}
else
for (unsigned int k = j + 1; k < i + 1; k++) {
pos[i].x_offset += pos[k].x_advance;
pos[i].y_offset += pos[k].y_advance;
}
// i is the position of the mark; j is the base.
if (j < i)
{
/* This is the common case: mark follows base.
* And currently the only way in OpenType. */
if (HB_DIRECTION_IS_FORWARD (direction))
for (unsigned int k = j; k < i; k++) {
pos[i].x_offset -= pos[k].x_advance;
pos[i].y_offset -= pos[k].y_advance;
}
else
for (unsigned int k = j + 1; k < i + 1; k++) {
pos[i].x_offset += pos[k].x_advance;
pos[i].y_offset += pos[k].y_advance;
}
}
else // j > i
{
/* This can happen with `kerx`: a mark attaching
* to a base after it in the logical order. */
if (HB_DIRECTION_IS_FORWARD (direction))
for (unsigned int k = i; k < j; k++) {
pos[i].x_offset += pos[k].x_advance;
pos[i].y_offset += pos[k].y_advance;
}
else
for (unsigned int k = i + 1; k < j + 1; k++) {
pos[i].x_offset -= pos[k].x_advance;
pos[i].y_offset -= pos[k].y_advance;
}
}
}
}
@ -149,8 +169,20 @@ GPOS::position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer)
/* Handle attachments */
if (buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT)
for (unsigned i = 0; i < len; i++)
propagate_attachment_offsets (pos, len, i, direction);
{
auto *pos = buffer->pos;
// https://github.com/harfbuzz/harfbuzz/issues/5514
if (HB_DIRECTION_IS_FORWARD (direction))
{
for (unsigned i = 0; i < len; i++)
if (pos[i].attach_chain())
propagate_attachment_offsets (pos, len, i, direction);
} else {
for (unsigned i = len; i-- > 0; )
if (pos[i].attach_chain())
propagate_attachment_offsets (pos, len, i, direction);
}
}
if (unlikely (font->slant_xy) &&
HB_DIRECTION_IS_HORIZONTAL (direction))

View file

@ -19,22 +19,30 @@ struct LigatureArray : List16OfOffset16To<LigatureAttach>
bool subset (hb_subset_context_t *c,
Iterator coverage,
unsigned class_count,
const hb_map_t *klass_mapping) const
const hb_map_t *klass_mapping,
hb_sorted_vector_t<hb_codepoint_t> &new_coverage /* OUT */) const
{
TRACE_SUBSET (this);
const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = c->plan->glyph_map_gsub;
auto *out = c->serializer->start_embed (this);
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
bool ret = false;
for (const auto _ : + hb_zip (coverage, *this)
| hb_filter (glyphset, hb_first))
| hb_filter (glyph_map, hb_first))
{
const LigatureAttach& src = (this + _.second);
bool non_empty = + hb_range (src.rows * class_count)
| hb_filter ([=] (unsigned index) { return klass_mapping->has (index % class_count); })
| hb_map ([&] (const unsigned index) { return !src.offset_is_null (index / class_count, index % class_count, class_count); })
| hb_any;
if (!non_empty) continue;
auto *matrix = out->serialize_append (c->serializer);
if (unlikely (!matrix)) return_trace (false);
const LigatureAttach& src = (this + _.second);
auto indexes =
+ hb_range (src.rows * class_count)
| hb_filter ([=] (unsigned index) { return klass_mapping->has (index % class_count); })
@ -44,6 +52,9 @@ struct LigatureArray : List16OfOffset16To<LigatureAttach>
this,
src.rows,
indexes);
hb_codepoint_t new_gid = glyph_map.get (_.first);
new_coverage.push (new_gid);
}
return_trace (ret);
}

View file

@ -209,19 +209,22 @@ struct MarkBasePosFormat1_2
;
new_coverage.reset ();
+ base_iter
| hb_map (hb_first)
| hb_map (glyph_map)
| hb_sink (new_coverage)
;
if (!out->baseCoverage.serialize_serialize (c->serializer, new_coverage.iter ()))
return_trace (false);
hb_sorted_vector_t<unsigned> base_indexes;
for (const unsigned row : + base_iter
| hb_map (hb_second))
auto &base_array = (this+baseArray);
for (const auto _ : + base_iter)
{
unsigned row = _.second;
bool non_empty = + hb_range ((unsigned) classCount)
| hb_filter (klass_mapping)
| hb_map ([&] (const unsigned col) { return !base_array.offset_is_null (row, col, (unsigned) classCount); })
| hb_any
;
if (!non_empty) continue;
hb_codepoint_t new_g = glyph_map.get ( _.first);
new_coverage.push (new_g);
+ hb_range ((unsigned) classCount)
| hb_filter (klass_mapping)
| hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; })
@ -229,8 +232,12 @@ struct MarkBasePosFormat1_2
;
}
if (!new_coverage) return_trace (false);
if (!out->baseCoverage.serialize_serialize (c->serializer, new_coverage.iter ()))
return_trace (false);
return_trace (out->baseArray.serialize_subset (c, baseArray, this,
base_iter.len (),
new_coverage.length,
base_indexes.iter ()));
}
};

View file

@ -200,19 +200,13 @@ struct MarkLigPosFormat1_2
&klass_mapping)))
return_trace (false);
auto new_ligature_coverage =
+ hb_iter (this + ligatureCoverage)
| hb_take ((this + ligatureArray).len)
| hb_map_retains_sorting (glyph_map)
| hb_filter ([] (hb_codepoint_t glyph) { return glyph != HB_MAP_VALUE_INVALID; })
;
if (!out->ligatureCoverage.serialize_serialize (c->serializer, new_ligature_coverage))
hb_sorted_vector_t<hb_codepoint_t> new_lig_coverage;
if (!out->ligatureArray.serialize_subset (c, ligatureArray, this,
hb_iter (this+ligatureCoverage),
classCount, &klass_mapping, new_lig_coverage))
return_trace (false);
return_trace (out->ligatureArray.serialize_subset (c, ligatureArray, this,
hb_iter (this+ligatureCoverage),
classCount, &klass_mapping));
return_trace (out->ligatureCoverage.serialize_serialize (c->serializer, new_lig_coverage.iter ()));
}
};

View file

@ -196,19 +196,23 @@ struct MarkMarkPosFormat1_2
;
new_coverage.reset ();
+ mark2_iter
| hb_map (hb_first)
| hb_map (glyph_map)
| hb_sink (new_coverage)
;
if (!out->mark2Coverage.serialize_serialize (c->serializer, new_coverage.iter ()))
return_trace (false);
hb_sorted_vector_t<unsigned> mark2_indexes;
for (const unsigned row : + mark2_iter
| hb_map (hb_second))
auto &mark2_array = (this+mark2Array);
for (const auto _ : + mark2_iter)
{
unsigned row = _.second;
bool non_empty = + hb_range ((unsigned) classCount)
| hb_filter (klass_mapping)
| hb_map ([&] (const unsigned col) { return !mark2_array.offset_is_null (row, col, (unsigned) classCount); })
| hb_any
;
if (!non_empty) continue;
hb_codepoint_t new_g = glyph_map.get ( _.first);
new_coverage.push (new_g);
+ hb_range ((unsigned) classCount)
| hb_filter (klass_mapping)
| hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; })
@ -216,6 +220,10 @@ struct MarkMarkPosFormat1_2
;
}
if (!new_coverage) return_trace (false);
if (!out->mark2Coverage.serialize_serialize (c->serializer, new_coverage.iter ()))
return_trace (false);
return_trace (out->mark2Array.serialize_subset (c, mark2Array, this,
mark2_iter.len (),
mark2_indexes.iter ()));

View file

@ -103,46 +103,29 @@ struct PairPosFormat1_3
const Coverage &get_coverage () const { return this+coverage; }
unsigned cache_cost () const
struct external_cache_t
{
return (this+coverage).cost ();
}
static void * cache_func (void *p, hb_ot_lookup_cache_op_t op)
hb_ot_layout_mapping_cache_t coverage;
};
void *external_cache_create () const
{
switch (op)
external_cache_t *cache = (external_cache_t *) hb_malloc (sizeof (external_cache_t));
if (likely (cache))
{
case hb_ot_lookup_cache_op_t::CREATE:
{
hb_ot_lookup_cache_t *cache = (hb_ot_lookup_cache_t *) hb_malloc (sizeof (hb_ot_lookup_cache_t));
if (likely (cache))
cache->clear ();
return cache;
}
case hb_ot_lookup_cache_op_t::ENTER:
return (void *) true;
case hb_ot_lookup_cache_op_t::LEAVE:
return nullptr;
case hb_ot_lookup_cache_op_t::DESTROY:
{
hb_ot_lookup_cache_t *cache = (hb_ot_lookup_cache_t *) p;
hb_free (cache);
return nullptr;
}
cache->coverage.clear ();
}
return nullptr;
return cache;
}
bool apply_cached (hb_ot_apply_context_t *c) const { return _apply (c, true); }
bool apply (hb_ot_apply_context_t *c) const { return _apply (c, false); }
bool _apply (hb_ot_apply_context_t *c, bool cached) const
bool apply (hb_ot_apply_context_t *c, void *external_cache) const
{
TRACE_APPLY (this);
hb_buffer_t *buffer = c->buffer;
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
hb_ot_lookup_cache_t *cache = cached ? (hb_ot_lookup_cache_t *) c->lookup_accel->cache : nullptr;
unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint, cache);
external_cache_t *cache = (external_cache_t *) external_cache;
unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint, cache ? &cache->coverage : nullptr);
#else
unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint);
#endif

View file

@ -123,56 +123,32 @@ struct PairPosFormat2_4 : ValueBase
const Coverage &get_coverage () const { return this+coverage; }
struct pair_pos_cache_t
struct external_cache_t
{
hb_ot_lookup_cache_t coverage;
hb_ot_lookup_cache_t first;
hb_ot_lookup_cache_t second;
hb_ot_layout_mapping_cache_t coverage;
hb_ot_layout_mapping_cache_t first;
hb_ot_layout_mapping_cache_t second;
};
unsigned cache_cost () const
void *external_cache_create () const
{
return (this+coverage).cost () + (this+classDef1).cost () + (this+classDef2).cost ();
}
static void * cache_func (void *p, hb_ot_lookup_cache_op_t op)
{
switch (op)
external_cache_t *cache = (external_cache_t *) hb_malloc (sizeof (external_cache_t));
if (likely (cache))
{
case hb_ot_lookup_cache_op_t::CREATE:
{
pair_pos_cache_t *cache = (pair_pos_cache_t *) hb_malloc (sizeof (pair_pos_cache_t));
if (likely (cache))
{
cache->coverage.clear ();
cache->first.clear ();
cache->second.clear ();
}
return cache;
}
case hb_ot_lookup_cache_op_t::ENTER:
return (void *) true;
case hb_ot_lookup_cache_op_t::LEAVE:
return nullptr;
case hb_ot_lookup_cache_op_t::DESTROY:
{
pair_pos_cache_t *cache = (pair_pos_cache_t *) p;
hb_free (cache);
return nullptr;
}
cache->coverage.clear ();
cache->first.clear ();
cache->second.clear ();
}
return nullptr;
return cache;
}
bool apply_cached (hb_ot_apply_context_t *c) const { return _apply (c, true); }
bool apply (hb_ot_apply_context_t *c) const { return _apply (c, false); }
bool _apply (hb_ot_apply_context_t *c, bool cached) const
bool apply (hb_ot_apply_context_t *c, void *external_cache) const
{
TRACE_APPLY (this);
hb_buffer_t *buffer = c->buffer;
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
pair_pos_cache_t *cache = cached ? (pair_pos_cache_t *) c->lookup_accel->cache : nullptr;
external_cache_t *cache = (external_cache_t *) external_cache;
unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint, cache ? &cache->coverage : nullptr);
#else
unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint);

View file

@ -58,7 +58,12 @@ struct ValueFormat : HBUINT16
NumType& operator = (uint16_t i) { v = i; return *this; }
unsigned int get_len () const { return hb_popcount ((unsigned int) *this); }
// Note: spec says skip 2 bytes per bit in the valueformat. But reports
// from Microsoft developers indicate that only the fields that are
// currently defined are counted. We don't expect any new fields to
// be added to ValueFormat. As such, we use the faster hb_popcount8
// that only processes the lowest 8 bits.
unsigned int get_len () const { return hb_popcount8 ((uint8_t) *this); }
unsigned int get_size () const { return get_len () * Value::static_size; }
hb_vector_t<unsigned> get_device_table_indices () const {

View file

@ -91,6 +91,19 @@ struct AlternateSet
return alternates.len;
}
void
collect_alternates (hb_codepoint_t gid,
hb_map_t *alternate_count /* IN/OUT */,
hb_map_t *alternate_glyphs /* IN/OUT */) const
{
+ hb_enumerate (alternates)
| hb_map ([gid] (hb_pair_t<unsigned, hb_codepoint_t> _) { return hb_pair (gid + (_.first << 24), _.second); })
| hb_apply ([&] (const hb_pair_t<hb_codepoint_t, hb_codepoint_t> &p) -> void
{ _hb_collect_glyph_alternates_add (p.first, p.second,
alternate_count, alternate_glyphs); })
;
}
template <typename Iterator,
hb_requires (hb_is_source_of (Iterator, hb_codepoint_t))>
bool serialize (hb_serialize_context_t *c,

View file

@ -69,6 +69,19 @@ struct AlternateSubstFormat1_2
{ return (this+alternateSet[(this+coverage).get_coverage (gid)])
.get_alternates (start_offset, alternate_count, alternate_glyphs); }
void
collect_glyph_alternates (hb_map_t *alternate_count /* IN/OUT */,
hb_map_t *alternate_glyphs /* IN/OUT */) const
{
+ hb_iter (alternateSet)
| hb_map (hb_add (this))
| hb_zip (this+coverage)
| hb_apply ([&] (const hb_pair_t<const AlternateSet<Types> &, hb_codepoint_t> _) {
_.first.collect_alternates (_.second, alternate_count, alternate_glyphs);
})
;
}
bool apply (hb_ot_apply_context_t *c) const
{
TRACE_APPLY (this);

View file

@ -44,6 +44,18 @@ struct Ligature
c->output->add (ligGlyph);
}
template <typename set_t>
void collect_second (set_t &s) const
{
if (unlikely (!component.get_length ()))
{
// A ligature without any components. Anything matches.
s = set_t::full ();
return;
}
s.add (component.arrayZ[0]);
}
bool would_apply (hb_would_apply_context_t *c) const
{
if (c->len != component.lenP1)
@ -91,15 +103,6 @@ struct Ligature
unsigned int total_component_count = 0;
if (unlikely (count > HB_MAX_CONTEXT_LENGTH)) return false;
unsigned match_positions_stack[4];
unsigned *match_positions = match_positions_stack;
if (unlikely (count > ARRAY_LENGTH (match_positions_stack)))
{
match_positions = (unsigned *) hb_malloc (hb_max (count, 1u) * sizeof (unsigned));
if (unlikely (!match_positions))
return_trace (false);
}
unsigned int match_end = 0;
if (likely (!match_input (c, count,
@ -107,12 +110,9 @@ struct Ligature
match_glyph,
nullptr,
&match_end,
match_positions,
&total_component_count)))
{
c->buffer->unsafe_to_concat (c->buffer->idx, match_end);
if (match_positions != match_positions_stack)
hb_free (match_positions);
return_trace (false);
}
@ -129,10 +129,10 @@ struct Ligature
match_end += delta;
for (unsigned i = 0; i < count; i++)
{
match_positions[i] += delta;
c->match_positions[i] += delta;
if (i)
*p++ = ',';
snprintf (p, sizeof(buf) - (p - buf), "%u", match_positions[i]);
snprintf (p, sizeof(buf) - (p - buf), "%u", c->match_positions[i]);
p += strlen(p);
}
@ -143,7 +143,6 @@ struct Ligature
ligate_input (c,
count,
match_positions,
match_end,
ligGlyph,
total_component_count);
@ -156,8 +155,6 @@ struct Ligature
pos);
}
if (match_positions != match_positions_stack)
hb_free (match_positions);
return_trace (true);
}

View file

@ -62,6 +62,15 @@ struct LigatureSet
;
}
template <typename set_t>
void collect_seconds (set_t &s) const
{
+ hb_iter (ligature)
| hb_map (hb_add (this))
| hb_apply ([&s] (const Ligature<Types> &_) { _.collect_second (s); })
;
}
bool would_apply (hb_would_apply_context_t *c) const
{
return
@ -72,14 +81,14 @@ struct LigatureSet
;
}
bool apply (hb_ot_apply_context_t *c) const
bool apply (hb_ot_apply_context_t *c, const hb_set_digest_t *seconds = nullptr) const
{
TRACE_APPLY (this);
unsigned int num_ligs = ligature.len;
#ifndef HB_NO_OT_RULESETS_FAST_PATH
if (HB_OPTIMIZE_SIZE_VAL || num_ligs <= 4)
if (HB_OPTIMIZE_SIZE_VAL || num_ligs <= 1)
#endif
{
slow:
@ -91,7 +100,7 @@ struct LigatureSet
return_trace (false);
}
/* This version is optimized for speed by matching the first component
/* This version is optimized for speed by matching the second component
* of the ligature here, instead of calling into the ligation code.
*
* This is replicated in ChainRuleSet and RuleSet. */
@ -101,11 +110,11 @@ struct LigatureSet
skippy_iter.set_match_func (match_always, nullptr);
skippy_iter.set_glyph_data ((HBUINT16 *) nullptr);
unsigned unsafe_to;
hb_codepoint_t first = (unsigned) -1;
hb_codepoint_t second = (unsigned) -1;
bool matched = skippy_iter.next (&unsafe_to);
if (likely (matched))
{
first = c->buffer->info[skippy_iter.idx].codepoint;
second = c->buffer->info[skippy_iter.idx].codepoint;
unsafe_to = skippy_iter.idx + 1;
if (skippy_iter.may_skip (c->buffer->info[skippy_iter.idx]))
@ -118,13 +127,14 @@ struct LigatureSet
else
goto slow;
if (seconds && !seconds->may_have (second))
return_trace (false);
bool unsafe_to_concat = false;
for (unsigned int i = 0; i < num_ligs; i++)
{
const auto &lig = this+ligature.arrayZ[i];
if (unlikely (lig.component.lenP1 <= 1) ||
lig.component.arrayZ[0] == first)
lig.component.arrayZ[0] == second)
{
if (lig.apply (c))
{

View file

@ -78,52 +78,44 @@ struct LigatureSubstFormat1_2
return lig_set.would_apply (c);
}
unsigned cache_cost () const
struct external_cache_t
{
return (this+coverage).cost ();
}
static void * cache_func (void *p, hb_ot_lookup_cache_op_t op)
hb_ot_layout_mapping_cache_t coverage;
hb_set_digest_t seconds;
};
void *external_cache_create () const
{
switch (op)
external_cache_t *cache = (external_cache_t *) hb_malloc (sizeof (external_cache_t));
if (likely (cache))
{
case hb_ot_lookup_cache_op_t::CREATE:
{
hb_ot_lookup_cache_t *cache = (hb_ot_lookup_cache_t *) hb_malloc (sizeof (hb_ot_lookup_cache_t));
if (likely (cache))
cache->clear ();
return cache;
}
case hb_ot_lookup_cache_op_t::ENTER:
return (void *) true;
case hb_ot_lookup_cache_op_t::LEAVE:
return nullptr;
case hb_ot_lookup_cache_op_t::DESTROY:
{
hb_ot_lookup_cache_t *cache = (hb_ot_lookup_cache_t *) p;
hb_free (cache);
return nullptr;
}
cache->coverage.clear ();
cache->seconds.init ();
+ hb_iter (ligatureSet)
| hb_map (hb_add (this))
| hb_apply ([cache] (const LigatureSet<Types> &_) { _.collect_seconds (cache->seconds); })
;
}
return nullptr;
return cache;
}
bool apply_cached (hb_ot_apply_context_t *c) const { return _apply (c, true); }
bool apply (hb_ot_apply_context_t *c) const { return _apply (c, false); }
bool _apply (hb_ot_apply_context_t *c, bool cached) const
bool apply (hb_ot_apply_context_t *c, void *external_cache) const
{
TRACE_APPLY (this);
hb_buffer_t *buffer = c->buffer;
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
hb_ot_lookup_cache_t *cache = cached ? (hb_ot_lookup_cache_t *) c->lookup_accel->cache : nullptr;
unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint, cache);
external_cache_t *cache = (external_cache_t *) external_cache;
const hb_set_digest_t *seconds = cache ? &cache->seconds : nullptr;
unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint, cache ? &cache->coverage : nullptr);
#else
const hb_set_digest_t *seconds = nullptr;
unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint);
#endif
if (index == NOT_COVERED) return_trace (false);
const auto &lig_set = this+ligatureSet[index];
return_trace (lig_set.apply (c));
return_trace (lig_set.apply (c, seconds));
}
bool serialize (hb_serialize_context_t *c,

View file

@ -123,6 +123,21 @@ struct SingleSubstFormat1_3
return 1;
}
void
collect_glyph_alternates (hb_map_t *alternate_count /* IN/OUT */,
hb_map_t *alternate_glyphs /* IN/OUT */) const
{
hb_codepoint_t d = deltaGlyphID;
hb_codepoint_t mask = get_mask ();
+ hb_iter (this+coverage)
| hb_map ([d, mask] (hb_codepoint_t g) { return hb_pair (g, (g + d) & mask); })
| hb_apply ([&] (const hb_pair_t<hb_codepoint_t, hb_codepoint_t> &p) -> void
{ _hb_collect_glyph_alternates_add (p.first, p.second,
alternate_count, alternate_glyphs); })
;
}
bool apply (hb_ot_apply_context_t *c) const
{
TRACE_APPLY (this);

View file

@ -100,6 +100,17 @@ struct SingleSubstFormat2_4
return 1;
}
void
collect_glyph_alternates (hb_map_t *alternate_count /* IN/OUT */,
hb_map_t *alternate_glyphs /* IN/OUT */) const
{
+ hb_zip (this+coverage, substitute)
| hb_apply ([&] (const hb_pair_t<hb_codepoint_t, hb_codepoint_t> &p) -> void
{ _hb_collect_glyph_alternates_add (p.first, p.second,
alternate_count, alternate_glyphs); })
;
}
bool apply (hb_ot_apply_context_t *c) const
{
TRACE_APPLY (this);

View file

@ -29,8 +29,8 @@
#ifndef OT_LAYOUT_TYPES_HH
#define OT_LAYOUT_TYPES_HH
using hb_ot_lookup_cache_t = hb_cache_t<15, 8, 7>;
static_assert (sizeof (hb_ot_lookup_cache_t) == 256, "");
using hb_ot_layout_mapping_cache_t = hb_cache_t<15, 8, 7>;
static_assert (sizeof (hb_ot_layout_mapping_cache_t) == 256, "");
namespace OT {
namespace Layout {

View file

@ -11,6 +11,8 @@ namespace OT {
//namespace Var {
#ifndef HB_NO_DRAW
struct hb_transforming_pen_context_t
{
hb_transform_t<> transform;
@ -411,6 +413,8 @@ VARC::get_path_at (const hb_varc_context_t &c,
return true;
}
#endif
//} // namespace Var
} // namespace OT

View file

@ -194,6 +194,7 @@ struct VARC
hb_codepoint_t gid,
hb_glyph_extents_t *extents) const
{
#ifndef HB_NO_DRAW
if (!table->has_data ()) return false;
hb_extents_t<> f_extents;
@ -207,6 +208,9 @@ struct VARC
*extents = f_extents.to_glyph_extents (font->x_scale < 0, font->y_scale < 0);
return ret;
#else
return false;
#endif
}
private:

View file

@ -533,7 +533,11 @@ struct Glyph
bool get_extents_without_var_scaled (hb_font_t *font, const glyf_accelerator_t &glyf_accelerator,
hb_glyph_extents_t *extents) const
{
if (type == EMPTY) return true; /* Empty glyph; zero extents. */
if (type == EMPTY)
{
*extents = {0, 0, 0, 0};
return true; /* Empty glyph; zero extents. */
}
return header->get_extents_without_var_scaled (font, glyf_accelerator, gid, extents);
}

View file

@ -189,7 +189,7 @@ struct SimpleGlyph
unsigned old_length = points.length;
points.alloc (points.length + num_points + 4); // Allocate for phantom points, to avoid a possible copy
if (unlikely (!points.resize (points.length + num_points, false))) return false;
if (unlikely (!points.resize_dirty (points.length + num_points))) return false;
auto points_ = points.as_array ().sub_array (old_length);
if (!phantom_only)
hb_memset (points_.arrayZ, 0, sizeof (contour_point_t) * num_points);

View file

@ -445,8 +445,7 @@ struct glyf_accelerator_t
if (coords)
{
hb_glyf_scratch_t *scratch = acquire_scratch ();
if (unlikely (!scratch))
return false;
if (unlikely (!scratch)) return false;
bool ret = get_points (font,
gid,
points_aggregator_t (font, extents, nullptr, true),
@ -493,8 +492,7 @@ struct glyf_accelerator_t
if (!has_data ()) return false;
hb_glyf_scratch_t *scratch = acquire_scratch ();
if (unlikely (!scratch))
return true;
if (unlikely (!scratch)) return true;
bool ret = get_points (font, gid, glyf_impl::path_builder_t (font, draw_session),
hb_array (font->coords,
@ -523,6 +521,7 @@ struct glyf_accelerator_t
hb_glyf_scratch_t *acquire_scratch () const
{
if (!has_data ()) return nullptr;
hb_glyf_scratch_t *scratch = cached_scratch.get_acquire ();
if (!scratch || unlikely (!cached_scratch.cmpexch (scratch, nullptr)))
{
@ -534,6 +533,8 @@ struct glyf_accelerator_t
}
void release_scratch (hb_glyf_scratch_t *scratch) const
{
if (!scratch)
return;
if (!cached_scratch.cmpexch (nullptr, scratch))
{
scratch->~hb_glyf_scratch_t ();

View file

@ -470,8 +470,12 @@ struct graph_t
num_roots_for_space_.push (1);
bool removed_nil = false;
vertices_.alloc (objects.length);
vertices_scratch_.alloc (objects.length);
ordering_.resize (objects.length);
ordering_scratch_.alloc (objects.length);
unsigned count = objects.length;
unsigned order = objects.length;
unsigned skip = 0;
for (unsigned i = 0; i < count; i++)
{
// If this graph came from a serialization buffer object 0 is the
@ -479,6 +483,9 @@ struct graph_t
if (i == 0 && !objects.arrayZ[i])
{
removed_nil = true;
order--;
ordering_.resize(objects.length - 1);
skip++;
continue;
}
@ -488,6 +495,12 @@ struct graph_t
check_success (v->link_positions_valid (count, removed_nil));
// To start we set the ordering to match the provided objects
// list. Note: objects are provided to us in reverse order (ie.
// the last object is the root).
unsigned obj_idx = i - skip;
ordering_[--order] = obj_idx;
if (!removed_nil) continue;
// Fix indices to account for removed nil object.
for (auto& l : v->obj.all_links_writer ()) {
@ -508,10 +521,10 @@ struct graph_t
}
void print () const {
for (int i = vertices_.length - 1; i >= 0; i--)
for (unsigned id : ordering_)
{
const auto& v = vertices_[i];
printf("%d: %u [", i, (unsigned int)v.table_size());
const auto& v = vertices_[id];
printf("%u: %u [", id, (unsigned int)v.table_size());
for (const auto &l : v.obj.real_links) {
printf("%u, ", l.objidx);
}
@ -533,6 +546,7 @@ struct graph_t
{
return !successful ||
vertices_.in_error () ||
ordering_.in_error() ||
num_roots_for_space_.in_error ();
}
@ -543,10 +557,10 @@ struct graph_t
unsigned root_idx () const
{
// Object graphs are in reverse order, the first object is at the end
// of the vector. Since the graph is topologically sorted it's safe to
// First element of ordering_ is the root.
// Since the graph is topologically sorted it's safe to
// assume the first object has no incoming edges.
return vertices_.length - 1;
return ordering_[0];
}
const hb_serialize_context_t::object_t& object (unsigned i) const
@ -604,55 +618,51 @@ struct graph_t
hb_priority_queue_t<int64_t> queue;
queue.alloc (vertices_.length);
hb_vector_t<vertex_t> &sorted_graph = vertices_scratch_;
if (unlikely (!check_success (sorted_graph.resize (vertices_.length)))) return;
hb_vector_t<unsigned> id_map;
if (unlikely (!check_success (id_map.resize (vertices_.length)))) return;
hb_vector_t<unsigned> &new_ordering = ordering_scratch_;
if (unlikely (!check_success (new_ordering.resize (vertices_.length)))) return;
hb_vector_t<unsigned> removed_edges;
if (unlikely (!check_success (removed_edges.resize (vertices_.length)))) return;
update_parents ();
queue.insert (root ().modified_distance (0), root_idx ());
int new_id = root_idx ();
unsigned order = 1;
unsigned pos = 0;
while (!queue.in_error () && !queue.is_empty ())
{
unsigned next_id = queue.pop_minimum().second;
sorted_graph[new_id] = std::move (vertices_[next_id]);
const vertex_t& next = sorted_graph[new_id];
if (unlikely (!check_success(new_id >= 0))) {
if (unlikely (!check_success(pos < new_ordering.length))) {
// We are out of ids. Which means we've visited a node more than once.
// This graph contains a cycle which is not allowed.
DEBUG_MSG (SUBSET_REPACK, nullptr, "Invalid graph. Contains cycle.");
return;
}
id_map[next_id] = new_id--;
new_ordering[pos++] = next_id;
const vertex_t& next = vertices_[next_id];
for (const auto& link : next.obj.all_links ()) {
removed_edges[link.objidx]++;
if (!(vertices_[link.objidx].incoming_edges () - removed_edges[link.objidx]))
const auto& v = vertices_[link.objidx];
if (!(v.incoming_edges () - removed_edges[link.objidx]))
// Add the order that the links were encountered to the priority.
// This ensures that ties between priorities objects are broken in a consistent
// way. More specifically this is set up so that if a set of objects have the same
// distance they'll be added to the topological order in the order that they are
// referenced from the parent object.
queue.insert (vertices_[link.objidx].modified_distance (order++),
queue.insert (v.modified_distance (order++),
link.objidx);
}
}
check_success (!queue.in_error ());
check_success (!sorted_graph.in_error ());
check_success (!new_ordering.in_error ());
check_success (remap_all_obj_indices (id_map, &sorted_graph));
vertices_ = std::move (sorted_graph);
hb_swap (ordering_, new_ordering);
if (!check_success (new_id == -1))
if (!check_success (pos == vertices_.length)) {
print_orphaned_nodes ();
}
}
/*
@ -662,8 +672,8 @@ struct graph_t
*/
void find_space_roots (hb_set_t& visited, hb_set_t& roots)
{
int root_index = (int) root_idx ();
for (int i = root_index; i >= 0; i--)
unsigned root_index = root_idx ();
for (unsigned i : ordering_)
{
if (visited.has (i)) continue;
@ -846,7 +856,6 @@ struct graph_t
if (subgraph.in_error ())
return false;
unsigned original_root_idx = root_idx ();
hb_map_t index_map;
bool made_changes = false;
for (auto entry : subgraph.iter ())
@ -869,14 +878,6 @@ struct graph_t
if (!made_changes)
return false;
if (original_root_idx != root_idx ()
&& parents.has (original_root_idx))
{
// If the root idx has changed since parents was determined, update root idx in parents
parents.add (root_idx ());
parents.del (original_root_idx);
}
auto new_subgraph =
+ subgraph.keys ()
| hb_map([&] (uint32_t node_idx) {
@ -965,9 +966,9 @@ struct graph_t
*/
template<typename O>
unsigned move_child (unsigned old_parent_idx,
const O* old_offset,
unsigned new_parent_idx,
const O* new_offset)
const O* old_offset,
unsigned new_parent_idx,
const O* new_offset)
{
distance_invalid = true;
positions_invalid = true;
@ -992,6 +993,50 @@ struct graph_t
return child_id;
}
/*
* Moves all outgoing links in old parent that have
* a link position between [old_post_start, old_pos_end)
* to the new parent. Links are placed serially in the new
* parent starting at new_pos_start.
*/
template<typename O>
void move_children (unsigned old_parent_idx,
unsigned old_pos_start,
unsigned old_pos_end,
unsigned new_parent_idx,
unsigned new_pos_start)
{
distance_invalid = true;
positions_invalid = true;
auto& old_v = vertices_[old_parent_idx];
auto& new_v = vertices_[new_parent_idx];
hb_vector_t<hb_serialize_context_t::object_t::link_t> old_links;
for (const auto& l : old_v.obj.real_links)
{
if (l.position < old_pos_start || l.position >= old_pos_end)
{
old_links.push(l);
continue;
}
unsigned array_pos = l.position - old_pos_start;
unsigned child_id = l.objidx;
auto* new_link = new_v.obj.real_links.push ();
new_link->width = O::static_size;
new_link->objidx = child_id;
new_link->position = new_pos_start + array_pos;
auto& child = vertices_[child_id];
child.add_parent (new_parent_idx, false);
child.remove_parent (old_parent_idx);
}
old_v.obj.real_links = std::move (old_links);
}
/*
* duplicates all nodes in the subgraph reachable from node_idx. Does not re-assign
* links. index_map is updated with mappings from old id to new id. If a duplication has already
@ -1021,8 +1066,11 @@ struct graph_t
distance_invalid = true;
auto* clone = vertices_.push ();
unsigned clone_idx = vertices_.length - 1;
ordering_.push(clone_idx);
auto& child = vertices_[node_idx];
if (vertices_.in_error ()) {
if (vertices_.in_error () || ordering_.in_error()) {
return -1;
}
@ -1032,7 +1080,6 @@ struct graph_t
clone->space = child.space;
clone->reset_parents ();
unsigned clone_idx = vertices_.length - 2;
for (const auto& l : child.obj.real_links)
{
clone->obj.real_links.push (l);
@ -1047,15 +1094,6 @@ struct graph_t
check_success (!clone->obj.real_links.in_error ());
check_success (!clone->obj.virtual_links.in_error ());
// The last object is the root of the graph, so swap back the root to the end.
// The root's obj idx does change, however since it's root nothing else refers to it.
// all other obj idx's will be unaffected.
hb_swap (vertices_[vertices_.length - 2], *clone);
// Since the root moved, update the parents arrays of all children on the root.
for (const auto& l : root ().obj.all_links ())
vertices_[l.objidx].remap_parent (root_idx () - 1, root_idx ());
return clone_idx;
}
@ -1205,7 +1243,10 @@ struct graph_t
distance_invalid = true;
auto* clone = vertices_.push ();
if (vertices_.in_error ()) {
unsigned clone_idx = vertices_.length - 1;
ordering_.push(clone_idx);
if (vertices_.in_error () || ordering_.in_error()) {
return -1;
}
@ -1214,17 +1255,6 @@ struct graph_t
clone->distance = 0;
clone->space = 0;
unsigned clone_idx = vertices_.length - 2;
// The last object is the root of the graph, so swap back the root to the end.
// The root's obj idx does change, however since it's root nothing else refers to it.
// all other obj idx's will be unaffected.
hb_swap (vertices_[vertices_.length - 2], *clone);
// Since the root moved, update the parents arrays of all children on the root.
for (const auto& l : root ().obj.all_links ())
vertices_[l.objidx].remap_parent (root_idx () - 1, root_idx ());
return clone_idx;
}
@ -1386,7 +1416,8 @@ struct graph_t
size_t total_size = 0;
unsigned count = vertices_.length;
for (unsigned i = 0; i < count; i++) {
size_t size = vertices_.arrayZ[i].obj.tail - vertices_.arrayZ[i].obj.head;
const auto& obj = vertices_.arrayZ[i].obj;
size_t size = obj.tail - obj.head;
total_size += size;
}
return total_size;
@ -1459,7 +1490,7 @@ struct graph_t
if (!positions_invalid) return;
unsigned current_pos = 0;
for (int i = root_idx (); i >= 0; i--)
for (unsigned i : ordering_)
{
auto& v = vertices_[i];
v.start = current_pos;
@ -1491,11 +1522,11 @@ struct graph_t
unsigned count = vertices_.length;
for (unsigned i = 0; i < count; i++)
vertices_.arrayZ[i].distance = hb_int_max (int64_t);
vertices_.tail ().distance = 0;
vertices_[root_idx ()].distance = 0;
hb_priority_queue_t<int64_t> queue;
queue.alloc (count);
queue.insert (0, vertices_.length - 1);
queue.insert (0, root_idx ());
hb_vector_t<bool> visited;
visited.resize (vertices_.length);
@ -1505,22 +1536,23 @@ struct graph_t
unsigned next_idx = queue.pop_minimum ().second;
if (visited[next_idx]) continue;
const auto& next = vertices_[next_idx];
int64_t next_distance = vertices_[next_idx].distance;
int64_t next_distance = next.distance;
visited[next_idx] = true;
for (const auto& link : next.obj.all_links ())
{
if (visited[link.objidx]) continue;
const auto& child = vertices_.arrayZ[link.objidx].obj;
auto& child_v = vertices_.arrayZ[link.objidx];
const auto& child = child_v.obj;
unsigned link_width = link.width ? link.width : 4; // treat virtual offsets as 32 bits wide
int64_t child_weight = (child.tail - child.head) +
((int64_t) 1 << (link_width * 8)) * (vertices_.arrayZ[link.objidx].space + 1);
((int64_t) 1 << (link_width * 8)) * (child_v.space + 1);
int64_t child_distance = next_distance + child_weight;
if (child_distance < vertices_.arrayZ[link.objidx].distance)
if (child_distance < child_v.distance)
{
vertices_.arrayZ[link.objidx].distance = child_distance;
child_v.distance = child_distance;
queue.insert (child_distance, link.objidx);
}
}
@ -1563,9 +1595,10 @@ struct graph_t
if (!id_map) return;
for (unsigned i : subgraph)
{
unsigned num_real = vertices_[i].obj.real_links.length;
auto& obj = vertices_[i].obj;
unsigned num_real = obj.real_links.length;
unsigned count = 0;
for (auto& link : vertices_[i].obj.all_links_writer ())
for (auto& link : obj.all_links_writer ())
{
count++;
const uint32_t *v;
@ -1577,25 +1610,6 @@ struct graph_t
}
}
/*
* Updates all objidx's in all links using the provided mapping.
*/
bool remap_all_obj_indices (const hb_vector_t<unsigned>& id_map,
hb_vector_t<vertex_t>* sorted_graph) const
{
unsigned count = sorted_graph->length;
for (unsigned i = 0; i < count; i++)
{
if (!(*sorted_graph)[i].remap_parents (id_map))
return false;
for (auto& link : sorted_graph->arrayZ[i].obj.all_links_writer ())
{
link.objidx = id_map[link.objidx];
}
}
return true;
}
/*
* Finds all nodes in targets that are reachable from start_idx, nodes in visited will be skipped.
* For this search the graph is treated as being undirected.
@ -1631,7 +1645,16 @@ struct graph_t
public:
// TODO(garretrieger): make private, will need to move most of offset overflow code into graph.
hb_vector_t<vertex_t> vertices_;
hb_vector_t<vertex_t> vertices_scratch_;
// Specifies the current topological ordering of this graph
//
// ordering_[pos] = obj index
//
// specifies that the 'pos'th spot is filled by the object
// given by obj index.
hb_vector_t<unsigned> ordering_;
hb_vector_t<unsigned> ordering_scratch_;
private:
bool parents_invalid;
bool distance_invalid;

View file

@ -87,6 +87,12 @@ struct Lookup : public OT::Lookup
return lookupType == extension_type (table_tag);
}
bool use_mark_filtering_set () const
{
unsigned flag = lookupFlag;
return flag & 0x0010u;
}
bool make_extension (gsubgpos_graph_context_t& c,
unsigned this_index)
{
@ -220,6 +226,9 @@ struct Lookup : public OT::Lookup
}
hb_memcpy (buffer, v->obj.head, v->table_size());
if (use_mark_filtering_set ())
hb_memcpy (buffer + new_size - 2, v->obj.tail - 2, 2);
v->obj.head = buffer;
v->obj.tail = buffer + new_size;

View file

@ -105,6 +105,23 @@ struct LigatureSubstFormat1 : public OT::Layout::GSUB_impl::LigatureSubstFormat1
return result;
}
hb_vector_t<unsigned> ligature_index_to_object_id(const graph_t::vertex_and_table_t<LigatureSet>& liga_set) const {
hb_vector_t<unsigned> map;
map.resize_exact(liga_set.table->ligature.len);
if (map.in_error()) return map;
for (unsigned i = 0; i < map.length; i++) {
map[i] = (unsigned) -1;
}
for (const auto& l : liga_set.vertex->obj.real_links) {
if (l.position < 2) continue;
unsigned array_index = (l.position - 2) / 2;
map[array_index] = l.objidx;
}
return map;
}
hb_vector_t<unsigned> compute_split_points(gsubgpos_graph_context_t& c,
unsigned parent_index,
unsigned this_index) const
@ -128,9 +145,16 @@ struct LigatureSubstFormat1 : public OT::Layout::GSUB_impl::LigatureSubstFormat1
return hb_vector_t<unsigned> {};
}
// Finding the object id associated with an array index is O(n)
// so to avoid O(n^2), precompute the mapping by scanning through
// all links
auto index_to_id = ligature_index_to_object_id(liga_set);
if (index_to_id.in_error()) return hb_vector_t<unsigned>();
for (unsigned j = 0; j < liga_set.table->ligature.len; j++)
{
const unsigned liga_id = c.graph.index_for_offset (liga_set.index, &liga_set.table->ligature[j]);
const unsigned liga_id = index_to_id[j];
if (liga_id == (unsigned) -1) continue; // no outgoing link, ignore
const unsigned liga_size = c.graph.vertices_[liga_id].table_size ();
accumulated += OT::HBUINT16::static_size; // for ligature offset
@ -154,7 +178,6 @@ struct LigatureSubstFormat1 : public OT::Layout::GSUB_impl::LigatureSubstFormat1
return split_points;
}
struct split_context_t
{
gsubgpos_graph_context_t& c;
@ -323,19 +346,19 @@ struct LigatureSubstFormat1 : public OT::Layout::GSUB_impl::LigatureSubstFormat1
{
// This liga set partially overlaps [start, end). We'll need to create
// a new liga set sub table and move the intersecting ligas to it.
unsigned liga_count = hb_min(end, current_end) - hb_max(start, current_start);
unsigned start_index = hb_max(start, current_start) - count;
unsigned end_index = hb_min(end, current_end) - count;
unsigned liga_count = end_index - start_index;
auto result = new_liga_set(c, liga_count);
liga_set_prime_id = result.first;
LigatureSet* prime = result.second;
if (liga_set_prime_id == (unsigned) -1) return -1;
unsigned new_index = 0;
for (unsigned j = hb_max(start, current_start) - count; j < hb_min(end, current_end) - count; j++) {
c.graph.move_child<> (liga_set_index,
&liga_set.table->ligature[j],
liga_set_prime_id,
&prime->ligature[new_index++]);
}
c.graph.move_children<OT::Offset16>(
liga_set_index,
2 + start_index * 2,
2 + end_index * 2,
liga_set_prime_id,
2);
liga_set_end = i;
if (i < liga_set_start) liga_set_start = i;
@ -392,8 +415,12 @@ struct LigatureSubstFormat1 : public OT::Layout::GSUB_impl::LigatureSubstFormat1
// duplicated. Code later on will re-add the virtual links as needed (via retained_indices).
clear_virtual_links(c, liga_set.index);
retained_indices.add(liga_set.index);
for (const auto& liga_offset : liga_set.table->ligature) {
unsigned liga_index = c.graph.index_for_offset(liga_set.index, &liga_offset);
auto index_to_id = ligature_index_to_object_id(liga_set);
if (index_to_id.in_error()) return false;
for (unsigned i = 0; i < liga_set.table->ligature.len; i++) {
unsigned liga_index = index_to_id[i];
if (liga_index != (unsigned) -1) {
clear_virtual_links(c, liga_index);
retained_indices.add(liga_index);

View file

@ -113,7 +113,7 @@ will_overflow (graph_t& graph,
hb_hashmap_t<overflow_record_t*, bool> record_set;
const auto& vertices = graph.vertices_;
for (int parent_idx = vertices.length - 1; parent_idx >= 0; parent_idx--)
for (unsigned parent_idx : graph.ordering_)
{
// Don't need to check virtual links for overflow
for (const auto& link : vertices.arrayZ[parent_idx].obj.real_links)
@ -173,6 +173,7 @@ template <typename O> inline void
serialize_link_of_type (const hb_serialize_context_t::object_t::link_t& link,
char* head,
unsigned size,
const hb_vector_t<unsigned>& id_map,
hb_serialize_context_t* c)
{
assert(link.position + link.width <= size);
@ -180,9 +181,7 @@ serialize_link_of_type (const hb_serialize_context_t::object_t::link_t& link,
OT::Offset<O>* offset = reinterpret_cast<OT::Offset<O>*> (head + link.position);
*offset = 0;
c->add_link (*offset,
// serializer has an extra nil object at the start of the
// object array. So all id's are +1 of what our id's are.
link.objidx + 1,
id_map[link.objidx],
(hb_serialize_context_t::whence_t) link.whence,
link.bias);
}
@ -191,6 +190,7 @@ inline
void serialize_link (const hb_serialize_context_t::object_t::link_t& link,
char* head,
unsigned size,
const hb_vector_t<unsigned>& id_map,
hb_serialize_context_t* c)
{
switch (link.width)
@ -201,21 +201,21 @@ void serialize_link (const hb_serialize_context_t::object_t::link_t& link,
case 4:
if (link.is_signed)
{
serialize_link_of_type<OT::HBINT32> (link, head, size, c);
serialize_link_of_type<OT::HBINT32> (link, head, size, id_map, c);
} else {
serialize_link_of_type<OT::HBUINT32> (link, head, size, c);
serialize_link_of_type<OT::HBUINT32> (link, head, size, id_map, c);
}
return;
case 2:
if (link.is_signed)
{
serialize_link_of_type<OT::HBINT16> (link, head, size, c);
serialize_link_of_type<OT::HBINT16> (link, head, size, id_map, c);
} else {
serialize_link_of_type<OT::HBUINT16> (link, head, size, c);
serialize_link_of_type<OT::HBUINT16> (link, head, size, id_map, c);
}
return;
case 3:
serialize_link_of_type<OT::HBUINT24> (link, head, size, c);
serialize_link_of_type<OT::HBUINT24> (link, head, size, id_map, c);
return;
default:
// Unexpected link width.
@ -241,25 +241,36 @@ inline hb_blob_t* serialize (const graph_t& graph)
c.start_serialize<void> ();
const auto& vertices = graph.vertices_;
for (unsigned i = 0; i < vertices.length; i++) {
// Objects are placed in the serializer in reverse order since children need
// to be inserted before their parents.
// Maps from our obj id's to the id's used during this serialization.
hb_vector_t<unsigned> id_map;
id_map.resize(graph.ordering_.length);
for (int pos = graph.ordering_.length - 1; pos >= 0; pos--) {
unsigned i = graph.ordering_[pos];
c.push ();
size_t size = vertices[i].obj.tail - vertices[i].obj.head;
auto& v = vertices[i];
size_t size = v.obj.tail - v.obj.head;
char* start = c.allocate_size <char> (size);
if (!start) {
DEBUG_MSG (SUBSET_REPACK, nullptr, "Buffer out of space.");
return nullptr;
}
hb_memcpy (start, vertices[i].obj.head, size);
hb_memcpy (start, v.obj.head, size);
// Only real links needs to be serialized.
for (const auto& link : vertices[i].obj.real_links)
serialize_link (link, start, size, &c);
for (const auto& link : v.obj.real_links)
serialize_link (link, start, size, id_map, &c);
// All duplications are already encoded in the graph, so don't
// enable sharing during packing.
c.pop_pack (false);
id_map[i] = c.pop_pack (false);
}
c.end_serialize ();

View file

@ -47,8 +47,7 @@ using namespace OT;
struct ankr;
using hb_aat_class_cache_t = hb_cache_t<15, 8, 7>;
static_assert (sizeof (hb_aat_class_cache_t) == 256, "");
using hb_aat_class_cache_t = hb_ot_layout_mapping_cache_t;
struct hb_aat_scratch_t
{
@ -79,7 +78,10 @@ struct hb_aat_scratch_t
{
hb_bit_set_t *s = buffer_glyph_set.get_acquire ();
if (s && buffer_glyph_set.cmpexch (s, nullptr))
{
s->clear ();
return s;
}
s = (hb_bit_set_t *) hb_calloc (1, sizeof (hb_bit_set_t));
if (unlikely (!s))
@ -124,13 +126,14 @@ struct hb_aat_apply_context_t :
const OT::GDEF &gdef;
bool has_glyph_classes;
const hb_sorted_vector_t<hb_aat_map_t::range_flags_t> *range_flags = nullptr;
hb_mask_t subtable_flags = 0;
bool buffer_is_reversed = false;
// Caches
bool using_buffer_glyph_set = false;
hb_bit_set_t *buffer_glyph_set = nullptr;
const hb_bit_set_t *left_set = nullptr;
const hb_bit_set_t *right_set = nullptr;
const hb_bit_set_t *machine_glyph_set = nullptr;
const hb_bit_set_t *first_set = nullptr;
const hb_bit_set_t *second_set = nullptr;
hb_aat_class_cache_t *machine_class_cache = nullptr;
hb_mask_t subtable_flags = 0;
/* Unused. For debug tracing only. */
unsigned int lookup_index;
@ -146,6 +149,12 @@ struct hb_aat_apply_context_t :
void set_lookup_index (unsigned int i) { lookup_index = i; }
void reverse_buffer ()
{
buffer->reverse ();
buffer_is_reversed = !buffer_is_reversed;
}
void setup_buffer_glyph_set ()
{
using_buffer_glyph_set = buffer->len >= 4 && buffer_glyph_set;
@ -156,11 +165,11 @@ struct hb_aat_apply_context_t :
bool buffer_intersects_machine () const
{
if (likely (using_buffer_glyph_set))
return buffer_glyph_set->intersects (*machine_glyph_set);
return buffer_glyph_set->intersects (*first_set);
// Faster for shorter buffers.
for (unsigned i = 0; i < buffer->len; i++)
if (machine_glyph_set->has (buffer->info[i].codepoint))
if (first_set->has (buffer->info[i].codepoint))
return true;
return false;
}
@ -639,6 +648,23 @@ struct LookupFormat10
glyphs.add_range (firstGlyph, firstGlyph + glyphCount - 1);
}
template <typename set_t, typename filter_t>
void collect_glyphs_filtered (set_t &glyphs, const filter_t &filter) const
{
if (unlikely (!glyphCount)) return;
if (firstGlyph == DELETED_GLYPH) return;
const HBUINT8 *p = valueArrayZ.arrayZ;
for (unsigned i = 0; i < glyphCount; i++)
{
unsigned int v = 0;
unsigned int count = valueSize;
for (unsigned int j = 0; j < count; j++)
v = (v << 8) | *p++;
if (filter (v))
glyphs.add (firstGlyph + i);
}
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@ -709,6 +735,7 @@ struct Lookup
case 4: hb_barrier (); u.format4.collect_glyphs_filtered (glyphs, filter); return;
case 6: hb_barrier (); u.format6.collect_glyphs_filtered (glyphs, filter); return;
case 8: hb_barrier (); u.format8.collect_glyphs_filtered (glyphs, filter); return;
case 10: hb_barrier (); u.format10.collect_glyphs_filtered (glyphs, filter); return;
default:return;
}
}
@ -838,11 +865,6 @@ struct StateTable
STATE_START_OF_LINE = 1,
};
template <typename set_t>
void collect_glyphs (set_t &glyphs, unsigned num_glyphs) const
{
(this+classTable).collect_glyphs (glyphs, num_glyphs);
}
template <typename set_t, typename table_t>
void collect_initial_glyphs (set_t &glyphs, unsigned num_glyphs, const table_t &table) const
{
@ -1082,6 +1104,8 @@ struct SubtableGlyphCoverage
for (unsigned i = 0; i < subtable_count; i++)
{
uint32_t offset = (uint32_t) subtableOffsets[i];
// A font file called SFNSDisplay.ttf has value 0xFFFFFFFF in the offsets.
// Just ignore it.
if (offset == 0 || offset == 0xFFFFFFFF)
continue;
if (unlikely (!subtableOffsets[i].sanitize (c, this, bytes)))

View file

@ -120,12 +120,12 @@ struct KerxSubTableFormat0
}
template <typename set_t>
void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const
void collect_glyphs (set_t &first_set, set_t &second_set, unsigned num_glyphs) const
{
for (const KernPair& pair : pairs)
{
left_set.add (pair.left);
right_set.add (pair.right);
first_set.add (pair.left);
second_set.add (pair.right);
}
}
@ -140,7 +140,7 @@ struct KerxSubTableFormat0
int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const
{
if (!(*c->left_set)[left] || !(*c->right_set)[right]) return 0;
if (!(*c->first_set)[left] || !(*c->second_set)[right]) return 0;
return table.get_kerning (left, right, c);
}
};
@ -396,10 +396,10 @@ struct KerxSubTableFormat1
}
template <typename set_t>
void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const
void collect_glyphs (set_t &first_set, set_t &second_set, unsigned num_glyphs) const
{
machine.collect_initial_glyphs (left_set, num_glyphs, *this);
//machine.collect_glyphs (right_set, num_glyphs); // right_set is unused for machine kerning
machine.collect_initial_glyphs (first_set, num_glyphs, *this);
//machine.collect_glyphs (second_set, num_glyphs); // second_set is unused for machine kerning
}
protected:
@ -451,10 +451,10 @@ struct KerxSubTableFormat2
}
template <typename set_t>
void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const
void collect_glyphs (set_t &first_set, set_t &second_set, unsigned num_glyphs) const
{
(this+leftClassTable).collect_glyphs (left_set, num_glyphs);
(this+rightClassTable).collect_glyphs (right_set, num_glyphs);
(this+leftClassTable).collect_glyphs (first_set, num_glyphs);
(this+rightClassTable).collect_glyphs (second_set, num_glyphs);
}
struct accelerator_t
@ -468,7 +468,7 @@ struct KerxSubTableFormat2
int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const
{
if (!(*c->left_set)[left] || !(*c->right_set)[right]) return 0;
if (!(*c->first_set)[left] || !(*c->second_set)[right]) return 0;
return table.get_kerning (left, right, c);
}
};
@ -629,6 +629,8 @@ struct KerxSubTableFormat4
}
o.attach_type() = OT::Layout::GPOS_impl::ATTACH_TYPE_MARK;
o.attach_chain() = (int) mark - (int) buffer->idx;
if (c->buffer_is_reversed)
o.attach_chain() = -o.attach_chain();
buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
}
@ -671,10 +673,10 @@ struct KerxSubTableFormat4
}
template <typename set_t>
void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const
void collect_glyphs (set_t &first_set, set_t &second_set, unsigned num_glyphs) const
{
machine.collect_initial_glyphs (left_set, num_glyphs, *this);
//machine.collect_glyphs (right_set, num_glyphs); // right_set is unused for machine kerning
machine.collect_initial_glyphs (first_set, num_glyphs, *this);
//machine.collect_glyphs (second_set, num_glyphs); // second_set is unused for machine kerning
}
protected:
@ -762,19 +764,19 @@ struct KerxSubTableFormat6
}
template <typename set_t>
void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const
void collect_glyphs (set_t &first_set, set_t &second_set, unsigned num_glyphs) const
{
if (is_long ())
{
const auto &t = u.l;
(this+t.rowIndexTable).collect_glyphs (left_set, num_glyphs);
(this+t.columnIndexTable).collect_glyphs (right_set, num_glyphs);
(this+t.rowIndexTable).collect_glyphs (first_set, num_glyphs);
(this+t.columnIndexTable).collect_glyphs (second_set, num_glyphs);
}
else
{
const auto &t = u.s;
(this+t.rowIndexTable).collect_glyphs (left_set, num_glyphs);
(this+t.columnIndexTable).collect_glyphs (right_set, num_glyphs);
(this+t.rowIndexTable).collect_glyphs (first_set, num_glyphs);
(this+t.columnIndexTable).collect_glyphs (second_set, num_glyphs);
}
}
@ -789,7 +791,7 @@ struct KerxSubTableFormat6
int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const
{
if (!(*c->left_set)[left] || !(*c->right_set)[right]) return 0;
if (!(*c->first_set)[left] || !(*c->second_set)[right]) return 0;
return table.get_kerning (left, right, c);
}
};
@ -878,15 +880,15 @@ struct KerxSubTable
}
template <typename set_t>
void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const
void collect_glyphs (set_t &first_set, set_t &second_set, unsigned num_glyphs) const
{
unsigned int subtable_type = get_type ();
switch (subtable_type) {
case 0: u.format0.collect_glyphs (left_set, right_set, num_glyphs); return;
case 1: u.format1.collect_glyphs (left_set, right_set, num_glyphs); return;
case 2: u.format2.collect_glyphs (left_set, right_set, num_glyphs); return;
case 4: u.format4.collect_glyphs (left_set, right_set, num_glyphs); return;
case 6: u.format6.collect_glyphs (left_set, right_set, num_glyphs); return;
case 0: u.format0.collect_glyphs (first_set, second_set, num_glyphs); return;
case 1: u.format1.collect_glyphs (first_set, second_set, num_glyphs); return;
case 2: u.format2.collect_glyphs (first_set, second_set, num_glyphs); return;
case 4: u.format4.collect_glyphs (first_set, second_set, num_glyphs); return;
case 6: u.format6.collect_glyphs (first_set, second_set, num_glyphs); return;
default: return;
}
}
@ -923,8 +925,8 @@ struct KerxSubTable
struct kern_subtable_accelerator_data_t
{
hb_bit_set_t left_set;
hb_bit_set_t right_set;
hb_bit_set_t first_set;
hb_bit_set_t second_set;
mutable hb_aat_class_cache_t class_cache;
};
@ -1017,9 +1019,8 @@ struct KerxTable
if (HB_DIRECTION_IS_HORIZONTAL (c->buffer->props.direction) != st->u.header.is_horizontal ())
goto skip;
c->left_set = &subtable_accel.left_set;
c->right_set = &subtable_accel.right_set;
c->machine_glyph_set = &subtable_accel.left_set;
c->first_set = &subtable_accel.first_set;
c->second_set = &subtable_accel.second_set;
c->machine_class_cache = &subtable_accel.class_cache;
if (!c->buffer_intersects_machine ())
@ -1051,8 +1052,8 @@ struct KerxTable
}
}
if (reverse)
c->buffer->reverse ();
if (reverse != c->buffer_is_reversed)
c->reverse_buffer ();
{
/* See comment in sanitize() for conditional here. */
@ -1060,15 +1061,14 @@ struct KerxTable
ret |= st->dispatch (c);
}
if (reverse)
c->buffer->reverse ();
(void) c->buffer->message (c->font, "end subtable %u", c->lookup_index);
skip:
st = &StructAfter<SubTable> (*st);
c->set_lookup_index (c->lookup_index + 1);
}
if (c->buffer_is_reversed)
c->reverse_buffer ();
return ret;
}
@ -1133,7 +1133,7 @@ struct KerxTable
if (unlikely (accel_data.subtable_accels.in_error ()))
return accel_data;
st->collect_glyphs (subtable_accel.left_set, subtable_accel.right_set, num_glyphs);
st->collect_glyphs (subtable_accel.first_set, subtable_accel.second_set, num_glyphs);
subtable_accel.class_cache.clear ();
st = &StructAfter<SubTable> (*st);

View file

@ -1169,15 +1169,15 @@ struct Chain
hb_map ([subtable_flags] (const hb_aat_map_t::range_flags_t _) -> bool { return subtable_flags & (_.flags); })))
goto skip;
c->subtable_flags = subtable_flags;
c->machine_glyph_set = accel ? &accel->subtables[i].glyph_set : &Null(hb_bit_set_t);
c->machine_class_cache = accel ? &accel->subtables[i].class_cache : nullptr;
if (!(coverage & ChainSubtable<Types>::AllDirections) &&
HB_DIRECTION_IS_VERTICAL (c->buffer->props.direction) !=
bool (coverage & ChainSubtable<Types>::Vertical))
goto skip;
c->subtable_flags = subtable_flags;
c->first_set = accel ? &accel->subtables[i].glyph_set : &Null(hb_bit_set_t);
c->machine_class_cache = accel ? &accel->subtables[i].class_cache : nullptr;
if (!c->buffer_intersects_machine ())
{
(void) c->buffer->message (c->font, "skipped chainsubtable %u because no glyph matches", c->lookup_index);
@ -1219,22 +1219,21 @@ struct Chain
if (!c->buffer->message (c->font, "start chainsubtable %u", c->lookup_index))
goto skip;
if (reverse)
c->buffer->reverse ();
if (reverse != c->buffer_is_reversed)
c->reverse_buffer ();
subtable->apply (c);
if (reverse)
c->buffer->reverse ();
(void) c->buffer->message (c->font, "end chainsubtable %u", c->lookup_index);
if (unlikely (!c->buffer->successful)) return;
if (unlikely (!c->buffer->successful)) break;
skip:
subtable = &StructAfter<ChainSubtable<Types>> (*subtable);
c->set_lookup_index (c->lookup_index + 1);
}
if (c->buffer_is_reversed)
c->reverse_buffer ();
}
unsigned int get_size () const { return length; }

View file

@ -92,6 +92,7 @@ template <typename Type>
struct __attribute__((packed)) hb_packed_t { Type v; };
#ifndef HB_FAST_NUM_ACCESS
#if defined(__OPTIMIZE__) && \
defined(__BYTE_ORDER) && \
(__BYTE_ORDER == __BIG_ENDIAN || \
@ -102,6 +103,13 @@ struct __attribute__((packed)) hb_packed_t { Type v; };
#else
#define HB_FAST_NUM_ACCESS 0
#endif
// https://github.com/harfbuzz/harfbuzz/issues/5456
#if defined(__GNUC__) && !defined(__clang__) && (__GNUC__ <= 12)
#undef HB_FAST_NUM_ACCESS
#define HB_FAST_NUM_ACCESS 0
#endif
#endif
template <bool BE, typename Type, int Bytes = sizeof (Type)>
@ -846,6 +854,17 @@ HB_FUNCOBJ (hb_clamp);
* Bithacks.
*/
/* Return the number of 1 bits in a uint8_t; faster than hb_popcount() */
static inline unsigned
hb_popcount8 (uint8_t v)
{
static const uint8_t popcount4[16] = {
0, 1, 1, 2, 1, 2, 2, 3,
1, 2, 2, 3, 2, 3, 3, 4
};
return popcount4[v & 0xF] + popcount4[v >> 4];
}
/* Return the number of 1 bits in v. */
template <typename T>
static inline unsigned int

105
thirdparty/harfbuzz/src/hb-alloc-pool.hh vendored Normal file
View file

@ -0,0 +1,105 @@
/*
* 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.
*
* Author(s): Behdad Esfahbod
*/
#ifndef HB_ALLOC_POOL_HH
#define HB_ALLOC_POOL_HH
#include "hb-vector.hh"
/* Memory pool for persistent small- to medium-sized allocations.
*
* Some AI musings on this, not necessarily true:
*
* This is a very simple implementation, but it's good enough for our
* purposes. It's not thread-safe. It's not very fast. It's not
* very memory efficient. It's not very cache efficient. It's not
* very anything efficient. But it's simple and it works. And it's
* good enough for our purposes. If you need something more
* sophisticated, use a real allocator. Or use a real language. */
struct hb_alloc_pool_t
{
unsigned ChunkSize = 65536 - 2 * sizeof (void *);
void *alloc (size_t size, unsigned alignment = 2 * sizeof (void *))
{
if (unlikely (chunks.in_error ())) return nullptr;
assert (alignment > 0);
assert (alignment <= 2 * sizeof (void *));
assert ((alignment & (alignment - 1)) == 0); /* power of two */
if (size > (ChunkSize) / 4)
{
/* Big chunk, allocate separately. */
hb_vector_t<char> chunk;
if (unlikely (!chunk.resize (size))) return nullptr;
void *ret = chunk.arrayZ;
chunks.push (std::move (chunk));
if (chunks.in_error ()) return nullptr;
if (chunks.length > 1)
{
// Bring back the previous last chunk to the end, so that
// we can continue to allocate from it.
hb_swap (chunks.arrayZ[chunks.length - 1], chunks.arrayZ[chunks.length - 2]);
}
return ret;
}
unsigned pad = (unsigned)(-(uintptr_t) current_chunk.arrayZ) & (alignment - 1);
// Small chunk, allocate from the last chunk.
if (current_chunk.length < pad + size)
{
chunks.push ();
if (unlikely (chunks.in_error ())) return nullptr;
hb_vector_t<char> &chunk = chunks.arrayZ[chunks.length - 1];
if (unlikely (!chunk.resize (ChunkSize))) return nullptr;
current_chunk = chunk;
pad = (unsigned)(-(uintptr_t) current_chunk.arrayZ) & (alignment - 1);
}
current_chunk += pad;
assert (current_chunk.length >= size);
void *ret = current_chunk.arrayZ;
current_chunk += size;
return ret;
}
void discard (void *p_, size_t size)
{
// Reclaim memory if we can.
char *p = (char *) p_;
if (current_chunk.arrayZ == p + size && current_chunk.backwards_length >= size)
current_chunk -= size;
}
private:
hb_vector_t<hb_vector_t<char>> chunks;
hb_array_t<char> current_chunk;
};
#endif /* HB_ALLOC_POOL_HH */

View file

@ -40,7 +40,6 @@
* Atomic integers and pointers.
*/
/* We need external help for these */
#if defined(hb_atomic_int_impl_add) \
@ -80,27 +79,11 @@ _hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N)
#include <atomic>
#define HB_STL_ATOMIC_IMPL
#define _hb_memory_r_barrier() std::atomic_thread_fence(std::memory_order_acquire)
#define _hb_memory_w_barrier() std::atomic_thread_fence(std::memory_order_release)
#define hb_atomic_int_impl_add(AI, V) (reinterpret_cast<std::atomic<typename std::decay<decltype (*(AI))>::type> *> (AI)->fetch_add ((V), std::memory_order_acq_rel))
#define hb_atomic_int_impl_set_relaxed(AI, V) (reinterpret_cast<std::atomic<typename std::decay<decltype (*(AI))>::type> *> (AI)->store ((V), std::memory_order_relaxed))
#define hb_atomic_int_impl_set(AI, V) (reinterpret_cast<std::atomic<typename std::decay<decltype (*(AI))>::type> *> (AI)->store ((V), std::memory_order_release))
#define hb_atomic_int_impl_get_relaxed(AI) (reinterpret_cast<std::atomic<typename std::decay<decltype (*(AI))>::type> const *> (AI)->load (std::memory_order_relaxed))
#define hb_atomic_int_impl_get(AI) (reinterpret_cast<std::atomic<typename std::decay<decltype (*(AI))>::type> const *> (AI)->load (std::memory_order_acquire))
#define hb_atomic_ptr_impl_set_relaxed(P, V) (reinterpret_cast<std::atomic<void*> *> (P)->store ((V), std::memory_order_relaxed))
#define hb_atomic_ptr_impl_get_relaxed(P) (reinterpret_cast<std::atomic<void*> const *> (P)->load (std::memory_order_relaxed))
#define hb_atomic_ptr_impl_get(P) (reinterpret_cast<std::atomic<void*> *> (P)->load (std::memory_order_acquire))
static inline bool
_hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N)
{
const void *O = O_; // Need lvalue
return reinterpret_cast<std::atomic<const void*> *> (P)->compare_exchange_weak (O, N, std::memory_order_acq_rel, std::memory_order_relaxed);
}
#define hb_atomic_ptr_impl_cmpexch(P,O,N) _hb_atomic_ptr_impl_cmplexch ((const void **) (P), (O), (N))
#else /* defined(HB_NO_MT) */
#define hb_atomic_int_impl_add(AI, V) ((*(AI) += (V)) - (V))
@ -159,6 +142,81 @@ inline T hb_atomic_int_impl_get (const T *AI) { T v = *AI; _hb_memory_r_barrier
inline void *hb_atomic_ptr_impl_get (void ** const P) { void *v = *P; _hb_memory_r_barrier (); return v; }
#endif
#ifdef HB_STL_ATOMIC_IMPL
template <typename T>
struct hb_atomic_t
{
hb_atomic_t () = default;
constexpr hb_atomic_t (T v) : v (v) {}
constexpr hb_atomic_t (const hb_atomic_t& o) : v (o.get_relaxed ()) {}
constexpr hb_atomic_t (hb_atomic_t&& o) : v (o.get_relaxed ()) { o.set_relaxed ({}); }
hb_atomic_t &operator= (const hb_atomic_t& o) { set_relaxed (o.get_relaxed ()); return *this; }
hb_atomic_t &operator= (hb_atomic_t&& o){ set_relaxed (o.get_relaxed ()); o.set_relaxed ({}); return *this; }
hb_atomic_t &operator= (T v_)
{
set_relaxed (v_);
return *this;
}
operator T () const { return get_relaxed (); }
void set_relaxed (T v_) { v.store (v_, std::memory_order_relaxed); }
void set_release (T v_) { v.store (v_, std::memory_order_release); }
T get_relaxed () const { return v.load (std::memory_order_relaxed); }
T get_acquire () const { return v.load (std::memory_order_acquire); }
T inc () { return v.fetch_add (1, std::memory_order_acq_rel); }
T dec () { return v.fetch_add (-1, std::memory_order_acq_rel); }
int operator++ (int) { return inc (); }
int operator-- (int) { return dec (); }
long operator|= (long v_)
{
set_relaxed (get_relaxed () | v_);
return *this;
}
friend void swap (hb_atomic_t &a, hb_atomic_t &b) noexcept
{
T v = a.get_acquire ();
a.set_relaxed (b.get_acquire ());
b.set_relaxed (v);
}
std::atomic<T> v = 0;
};
template <typename T>
struct hb_atomic_t<T *>
{
hb_atomic_t () = default;
constexpr hb_atomic_t (T *v) : v (v) {}
hb_atomic_t (const hb_atomic_t &other) = delete;
void init (T *v_ = nullptr) { set_relaxed (v_); }
void set_relaxed (T *v_) { v.store (v_, std::memory_order_relaxed); }
T *get_relaxed () const { return v.load (std::memory_order_relaxed); }
T *get_acquire () const { return v.load (std::memory_order_acquire); }
bool cmpexch (T *old, T *new_) { return v.compare_exchange_weak (old, new_, std::memory_order_acq_rel, std::memory_order_relaxed); }
operator bool () const { return get_acquire () != nullptr; }
T *operator->() const { return get_acquire (); }
template <typename C>
operator C * () const
{
return get_acquire ();
}
friend void swap (hb_atomic_t &a, hb_atomic_t &b) noexcept
{
T *p = a.get_acquire ();
a.set_relaxed (b.get_acquire ());
b.set_relaxed (p);
}
std::atomic<T *> v = nullptr;
};
#else
template <typename T>
struct hb_atomic_t
@ -194,7 +252,7 @@ struct hb_atomic_t<T*>
void set_relaxed (T* v_) { hb_atomic_ptr_impl_set_relaxed (&v, v_); }
T *get_relaxed () const { return (T *) hb_atomic_ptr_impl_get_relaxed (&v); }
T *get_acquire () const { return (T *) hb_atomic_ptr_impl_get ((void **) &v); }
bool cmpexch (const T *old, T *new_) { return hb_atomic_ptr_impl_cmpexch ((void **) &v, (void *) old, (void *) new_); }
bool cmpexch (T *old, T *new_) { return hb_atomic_ptr_impl_cmpexch ((void **) &v, (void *) old, (void *) new_); }
operator bool () const { return get_acquire () != nullptr; }
T * operator -> () const { return get_acquire (); }
@ -203,6 +261,8 @@ struct hb_atomic_t<T*>
T *v = nullptr;
};
#endif
static inline bool hb_barrier ()
{
_hb_compiler_memory_r_barrier ();

View file

@ -176,7 +176,7 @@ struct hb_inc_bimap_t
{
hb_codepoint_t count = get_population ();
hb_vector_t <hb_codepoint_t> work;
if (unlikely (!work.resize (count, false))) return;
if (unlikely (!work.resize_dirty (count))) return;
for (hb_codepoint_t rhs = 0; rhs < count; rhs++)
work.arrayZ[rhs] = back_map[rhs];

View file

@ -142,6 +142,7 @@ struct hb_bit_page_t
bool operator [] (hb_codepoint_t g) const { return get (g); }
bool operator () (hb_codepoint_t g) const { return get (g); }
bool has (hb_codepoint_t g) const { return get (g); }
void add_range (hb_codepoint_t a, hb_codepoint_t b)
{
@ -290,7 +291,7 @@ struct hb_bit_page_t
unsigned int j = m & ELT_MASK;
const elt_t vv = v[i] & ~((elt_t (1) << j) - 1);
for (const elt_t *p = &vv; i < len (); p = &v[++i])
for (const elt_t *p = &vv; i < len (); p = ((const elt_t *) &v[0]) + (++i))
if (*p)
{
*codepoint = i * ELT_BITS + elt_get_min (*p);
@ -346,6 +347,36 @@ struct hb_bit_page_t
return 0;
}
/*
* Iterator implementation.
*/
struct iter_t : hb_iter_with_fallback_t<iter_t, hb_codepoint_t>
{
static constexpr bool is_sorted_iterator = true;
iter_t (const hb_bit_page_t &s_ = Null (hb_bit_page_t), bool init = true) : s (&s_), v (INVALID)
{
if (init)
v = s->get_min ();
}
typedef hb_codepoint_t __item_t__;
hb_codepoint_t __item__ () const { return v; }
bool __more__ () const { return v != INVALID; }
void __next__ () {
s->next (&v);
}
void __prev__ () { s->previous (&v); }
iter_t end () const { return iter_t (*s, false); }
bool operator != (const iter_t& o) const
{ return v != o.v; }
protected:
const hb_bit_page_t *s;
hb_codepoint_t v;
};
iter_t iter () const { return iter_t (*this); }
operator iter_t () const { return iter (); }
static constexpr hb_codepoint_t INVALID = HB_SET_VALUE_INVALID;
typedef unsigned long long elt_t;

View file

@ -368,7 +368,7 @@ struct hb_bit_set_invertible_t
unsigned __len__ () const { return l; }
iter_t end () const { return iter_t (*s, false); }
bool operator != (const iter_t& o) const
{ return v != o.v || s != o.s; }
{ return v != o.v; }
protected:
const hb_bit_set_invertible_t *s;

View file

@ -91,10 +91,10 @@ struct hb_bit_set_t
if (pages.length < count && (unsigned) pages.allocated < count && count <= 2)
exact_size = true; // Most sets are small and local
if (unlikely (!pages.resize (count, clear, exact_size) ||
!page_map.resize (count, clear)))
if (unlikely (!pages.resize_full (count, clear, exact_size) ||
!page_map.resize_full (count, clear, false)))
{
pages.resize (page_map.length, clear, exact_size);
pages.resize_full (page_map.length, clear, exact_size);
successful = false;
return false;
}
@ -108,10 +108,11 @@ struct hb_bit_set_t
page_map.alloc (sz);
}
void reset ()
hb_bit_set_t& reset ()
{
successful = true;
clear ();
return *this;
}
void clear ()
@ -394,7 +395,7 @@ struct hb_bit_set_t
{
if (unlikely (!successful)) return;
unsigned int count = other.pages.length;
if (unlikely (!resize (count, false, exact_size)))
if (unlikely (!resize (count, false, exact_size)))
return;
population = other.population;
@ -922,7 +923,7 @@ struct hb_bit_set_t
unsigned __len__ () const { return l; }
iter_t end () const { return iter_t (*s, false); }
bool operator != (const iter_t& o) const
{ return s != o.s || v != o.v; }
{ return v != o.v; }
protected:
const hb_bit_set_t *s;

View file

@ -32,7 +32,7 @@
#include "hb.hh"
#line 36 "hb-buffer-deserialize-text-unicode.hh"
#line 33 "hb-buffer-deserialize-text-unicode.hh"
static const unsigned char _deserialize_text_unicode_trans_keys[] = {
0u, 0u, 43u, 102u, 48u, 102u, 48u, 124u, 48u, 57u, 62u, 124u, 48u, 124u, 60u, 117u,
85u, 117u, 85u, 117u, 0
@ -150,12 +150,12 @@ _hb_buffer_deserialize_text_unicode (hb_buffer_t *buffer,
hb_glyph_info_t info = {0};
const hb_glyph_position_t pos = {0};
#line 154 "hb-buffer-deserialize-text-unicode.hh"
#line 147 "hb-buffer-deserialize-text-unicode.hh"
{
cs = deserialize_text_unicode_start;
}
#line 159 "hb-buffer-deserialize-text-unicode.hh"
#line 150 "hb-buffer-deserialize-text-unicode.hh"
{
int _slen;
int _trans;
@ -215,7 +215,7 @@ _resume:
hb_memset (&info, 0, sizeof (info));
}
break;
#line 219 "hb-buffer-deserialize-text-unicode.hh"
#line 203 "hb-buffer-deserialize-text-unicode.hh"
}
_again:
@ -238,7 +238,7 @@ _again:
*end_ptr = p;
}
break;
#line 242 "hb-buffer-deserialize-text-unicode.hh"
#line 224 "hb-buffer-deserialize-text-unicode.hh"
}
}

View file

@ -163,7 +163,7 @@ buffer_verify_unsafe_to_break (hb_buffer_t *buffer,
hb_buffer_append (fragment, text_buffer, text_start, text_end);
if (!hb_shape_full (font, fragment, features, num_features, shapers) ||
fragment->successful || fragment->shaping_failed)
fragment->successful)
{
hb_buffer_destroy (reconstruction);
hb_buffer_destroy (fragment);
@ -313,11 +313,11 @@ buffer_verify_unsafe_to_concat (hb_buffer_t *buffer,
* Shape the two fragment streams.
*/
if (!hb_shape_full (font, fragments[0], features, num_features, shapers) ||
!fragments[0]->successful || fragments[0]->shaping_failed)
!fragments[0]->successful)
goto out;
if (!hb_shape_full (font, fragments[1], features, num_features, shapers) ||
!fragments[1]->successful || fragments[1]->shaping_failed)
!fragments[1]->successful)
goto out;
if (!forward)

View file

@ -158,14 +158,15 @@ hb_segment_properties_overlay (hb_segment_properties_t *p,
bool
hb_buffer_t::enlarge (unsigned int size)
{
if (unlikely (!successful))
return false;
if (unlikely (size > max_len))
{
successful = false;
return false;
}
if (unlikely (!successful))
return false;
unsigned int new_allocated = allocated;
hb_glyph_position_t *new_pos = nullptr;
hb_glyph_info_t *new_info = nullptr;
@ -226,6 +227,13 @@ hb_buffer_t::shift_forward (unsigned int count)
assert (have_output);
if (unlikely (!ensure (len + count))) return false;
max_ops -= len - idx;
if (unlikely (max_ops < 0))
{
successful = false;
return false;
}
memmove (info + idx + count, info + idx, (len - idx) * sizeof (info[0]));
if (idx + count > len)
{
@ -297,7 +305,6 @@ hb_buffer_t::clear ()
props = default_props;
successful = true;
shaping_failed = false;
have_output = false;
have_positions = false;
@ -320,7 +327,6 @@ hb_buffer_t::enter ()
{
deallocate_var_all ();
serial = 0;
shaping_failed = false;
scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT;
unsigned mul;
if (likely (!hb_unsigned_mul_overflows (len, HB_BUFFER_MAX_LEN_FACTOR, &mul)))
@ -339,7 +345,6 @@ hb_buffer_t::leave ()
max_ops = HB_BUFFER_MAX_OPS_DEFAULT;
deallocate_var_all ();
serial = 0;
// Intentionally not reseting shaping_failed, such that it can be inspected.
}
@ -520,7 +525,19 @@ hb_buffer_t::set_masks (hb_mask_t value,
hb_mask_t not_mask = ~mask;
value &= mask;
max_ops -= len;
if (unlikely (max_ops < 0))
successful = false;
unsigned int count = len;
if (cluster_start == 0 && cluster_end == (unsigned int) -1)
{
for (unsigned int i = 0; i < count; i++)
info[i].mask = (info[i].mask & not_mask) | value;
return;
}
for (unsigned int i = 0; i < count; i++)
if (cluster_start <= info[i].cluster && info[i].cluster < cluster_end)
info[i].mask = (info[i].mask & not_mask) | value;
@ -536,6 +553,10 @@ hb_buffer_t::merge_clusters_impl (unsigned int start,
return;
}
max_ops -= end - start;
if (unlikely (max_ops < 0))
successful = false;
unsigned int cluster = info[start].cluster;
for (unsigned int i = start + 1; i < end; i++)
@ -569,6 +590,10 @@ hb_buffer_t::merge_out_clusters (unsigned int start,
if (unlikely (end - start < 2))
return;
max_ops -= end - start;
if (unlikely (max_ops < 0))
successful = false;
unsigned int cluster = out_info[start].cluster;
for (unsigned int i = start + 1; i < end; i++)
@ -726,7 +751,6 @@ DEFINE_NULL_INSTANCE (hb_buffer_t) =
HB_SEGMENT_PROPERTIES_DEFAULT,
false, /* successful */
true, /* shaping_failed */
false, /* have_output */
true /* have_positions */

View file

@ -32,6 +32,7 @@
#include "hb.hh"
#include "hb-unicode.hh"
#include "hb-set-digest.hh"
static_assert ((sizeof (hb_glyph_info_t) == 20), "");
@ -44,14 +45,14 @@ HB_MARK_AS_FLAG_T (hb_buffer_diff_flags_t);
enum hb_buffer_scratch_flags_t {
HB_BUFFER_SCRATCH_FLAG_DEFAULT = 0x00000000u,
HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII = 0x00000001u,
HB_BUFFER_SCRATCH_FLAG_HAS_FRACTION_SLASH = 0x00000001u,
HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES = 0x00000002u,
HB_BUFFER_SCRATCH_FLAG_HAS_SPACE_FALLBACK = 0x00000004u,
HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT = 0x00000008u,
HB_BUFFER_SCRATCH_FLAG_HAS_CGJ = 0x00000010u,
HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS = 0x00000020u,
HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE = 0x00000040u,
HB_BUFFER_SCRATCH_FLAG_HAS_VARIATION_SELECTOR_FALLBACK= 0x00000080u,
HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE = 0x00000020u,
HB_BUFFER_SCRATCH_FLAG_HAS_VARIATION_SELECTOR_FALLBACK= 0x00000040u,
HB_BUFFER_SCRATCH_FLAG_HAS_CONTINUATIONS = 0x00000080u,
/* Reserved for shapers' internal use. */
HB_BUFFER_SCRATCH_FLAG_SHAPER0 = 0x01000000u,
@ -90,7 +91,6 @@ struct hb_buffer_t
hb_segment_properties_t props; /* Script, language, direction */
bool successful; /* Allocations successful */
bool shaping_failed; /* Shaping failure */
bool have_output; /* Whether we have an output buffer going on */
bool have_positions; /* Whether we have positions */
@ -110,6 +110,7 @@ struct hb_buffer_t
hb_codepoint_t context[2][CONTEXT_LENGTH];
unsigned int context_len[2];
hb_set_digest_t digest; /* Manually updated sometimes */
/*
* Managed by enter / leave
@ -200,6 +201,12 @@ struct hb_buffer_t
void collect_codepoints (set_t &d) const
{ d.clear (); d.add_array (&info[0].codepoint, len, sizeof (info[0])); }
void update_digest ()
{
digest = hb_set_digest_t ();
collect_codepoints (digest);
}
HB_INTERNAL void similar (const hb_buffer_t &src);
HB_INTERNAL void reset ();
HB_INTERNAL void clear ();
@ -346,7 +353,7 @@ struct hb_buffer_t
{
if (out_info != info || out_len != idx)
{
if (unlikely (!make_room_for (1, 1))) return false;
if (unlikely (!ensure (out_len + 1))) return false;
out_info[out_len] = info[idx];
}
out_len++;
@ -363,7 +370,7 @@ struct hb_buffer_t
{
if (out_info != info || out_len != idx)
{
if (unlikely (!make_room_for (n, n))) return false;
if (unlikely (!ensure (out_len + n))) return false;
memmove (out_info + out_len, info + idx, n * sizeof (out_info[0]));
}
out_len += n;
@ -404,22 +411,12 @@ struct hb_buffer_t
/* Adds glyph flags in mask to infos with clusters between start and end.
* The start index will be from out-buffer if from_out_buffer is true.
* If interior is true, then the cluster having the minimum value is skipped. */
void _set_glyph_flags (hb_mask_t mask,
unsigned start = 0,
unsigned end = (unsigned) -1,
bool interior = false,
bool from_out_buffer = false)
void _set_glyph_flags_impl (hb_mask_t mask,
unsigned start,
unsigned end,
bool interior,
bool from_out_buffer)
{
if (unlikely (end != (unsigned) -1 && end - start > 255))
return;
end = hb_min (end, len);
if (interior && !from_out_buffer && end - start < 2)
return;
scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS;
if (!from_out_buffer || !have_output)
{
if (!interior)
@ -456,6 +453,25 @@ struct hb_buffer_t
}
}
HB_ALWAYS_INLINE
void _set_glyph_flags (hb_mask_t mask,
unsigned start = 0,
unsigned end = (unsigned) -1,
bool interior = false,
bool from_out_buffer = false)
{
if (unlikely (end != (unsigned) -1 && end - start > 255))
return;
end = hb_min (end, len);
if (interior && !from_out_buffer && end - start < 2)
return;
_set_glyph_flags_impl (mask, start, end, interior, from_out_buffer);
}
void unsafe_to_break (unsigned int start = 0, unsigned int end = -1)
{
_set_glyph_flags (HB_GLYPH_FLAG_UNSAFE_TO_BREAK | HB_GLYPH_FLAG_UNSAFE_TO_CONCAT,
@ -606,6 +622,10 @@ struct hb_buffer_t
if (unlikely (start == end))
return;
max_ops -= end - start;
if (unlikely (max_ops < 0))
successful = false;
unsigned cluster_first = infos[start].cluster;
unsigned cluster_last = infos[end - 1].cluster;
@ -614,10 +634,7 @@ struct hb_buffer_t
{
for (unsigned int i = start; i < end; i++)
if (cluster != infos[i].cluster)
{
scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS;
infos[i].mask |= mask;
}
return;
}
@ -626,18 +643,12 @@ struct hb_buffer_t
if (cluster == cluster_first)
{
for (unsigned int i = end; start < i && infos[i - 1].cluster != cluster_first; i--)
{
scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS;
infos[i - 1].mask |= mask;
}
}
else /* cluster == cluster_last */
{
for (unsigned int i = start; i < end && infos[i].cluster != cluster_last; i++)
{
scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS;
infos[i].mask |= mask;
}
}
}
unsigned

View file

@ -75,6 +75,8 @@ struct hb_cache_t
static_assert ((key_bits >= cache_bits), "");
static_assert ((key_bits + value_bits <= cache_bits + 8 * sizeof (item_t)), "");
static constexpr unsigned MAX_VALUE = (1u << value_bits) - 1;
hb_cache_t () { clear (); }
void clear ()
@ -100,6 +102,12 @@ struct hb_cache_t
{
if (unlikely ((key >> key_bits) || (value >> value_bits)))
return; /* Overflows */
set_unchecked (key, value);
}
HB_HOT
void set_unchecked (unsigned int key, unsigned int value)
{
unsigned int k = key & ((1u<<cache_bits)-1);
unsigned int v = ((key>>cache_bits)<<value_bits) | value;
values[k] = v;

View file

@ -72,7 +72,7 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<ELEM, CFF2Subrs>
cff2_cs_interp_env_t (const hb_ubytes_t &str, ACC &acc, unsigned int fd,
const int *coords_=nullptr, unsigned int num_coords_=0)
: SUPER (str, acc.globalSubrs, acc.privateDicts[fd].localSubrs),
cached_scalars_vector (&acc.cached_scalars_vector)
region_count (0), cached_scalars_vector (&acc.cached_scalars_vector)
{
coords = coords_;
num_coords = num_coords_;

View file

@ -631,6 +631,9 @@ hb_script_get_horizontal_direction (hb_script_t script)
/* Unicode-16.0 additions */
case HB_SCRIPT_GARAY:
/* Unicode-17.0 additions */
case HB_SCRIPT_SIDETIC:
return HB_DIRECTION_RTL;

View file

@ -38,7 +38,6 @@
#ifndef HB_EXPERIMENTAL_API
#define HB_NO_BEYOND_64K
#define HB_NO_CUBIC_GLYF
#define HB_NO_VAR_COMPOSITES
#endif
#ifdef HB_TINY
@ -91,7 +90,10 @@
#ifdef HB_MINI
#define HB_NO_AAT
#define HB_NO_LEGACY
#define HB_NO_BORING_EXPANSION
#define HB_NO_BEYOND_64K
#define HB_NO_CUBIC_GLYF
#define HB_NO_VAR_COMPOSITES
#define HB_NO_VAR_HVF
#endif
#ifdef __OPTIMIZE_SIZE__
@ -109,12 +111,6 @@
/* Closure of options. */
#ifdef HB_NO_BORING_EXPANSION
#define HB_NO_BEYOND_64K
#define HB_NO_CUBIC_GLYF
#define HB_NO_VAR_COMPOSITES
#endif
#ifdef HB_NO_VAR
#define HB_NO_VAR_COMPOSITES
#endif

View file

@ -410,8 +410,8 @@ hb_coretext_get_glyph_name (hb_font_t *font,
return false;
CFIndex len = CFStringGetLength (cf_name);
if (len > size - 1)
len = size - 1;
if (len > (CFIndex)size - 1)
len = (CFIndex)size - 1;
CFStringGetBytes (cf_name, CFRangeMake (0, len),
kCFStringEncodingUTF8, 0, false,

View file

@ -167,8 +167,8 @@ create_cg_font (CFArrayRef ct_font_desc_array, unsigned int named_instance_index
}
else
named_instance_index--;
auto ct_font_desc = (CFArrayGetCount (ct_font_desc_array) > named_instance_index) ?
(CTFontDescriptorRef) CFArrayGetValueAtIndex (ct_font_desc_array, named_instance_index) : nullptr;
auto ct_font_desc = (CFArrayGetCount (ct_font_desc_array) > (CFIndex) named_instance_index) ?
(CTFontDescriptorRef) CFArrayGetValueAtIndex (ct_font_desc_array, (CFIndex) named_instance_index) : nullptr;
if (unlikely (!ct_font_desc))
{
CFRelease (ct_font_desc_array);

View file

@ -394,6 +394,10 @@ struct hb_no_trace_t {
#define HB_DEBUG_WASM (HB_DEBUG+0)
#endif
#ifndef HB_DEBUG_KBTS
#define HB_DEBUG_KBTS (HB_DEBUG+0)
#endif
/*
* With tracing.
*/
@ -484,7 +488,7 @@ struct hb_no_trace_t {
#ifndef HB_BUFFER_MESSAGE_MORE
#define HB_BUFFER_MESSAGE_MORE (HB_DEBUG+1)
#define HB_BUFFER_MESSAGE_MORE (HB_DEBUG+0)
#endif

View file

@ -84,8 +84,7 @@ hb_face_count (hb_blob_t *blob)
hb_sanitize_context_t c (blob);
const char *start = hb_blob_get_data (blob, nullptr);
auto *ot = reinterpret_cast<OT::OpenTypeFontFile *> (const_cast<char *> (start));
auto *ot = blob->as<OT::OpenTypeFontFile> ();
if (unlikely (!ot->sanitize (&c)))
return 0;

107
thirdparty/harfbuzz/src/hb-free-pool.hh vendored Normal file
View file

@ -0,0 +1,107 @@
/*
* Copyright © 2019 Facebook, 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.
*
* Facebook Author(s): Behdad Esfahbod
*/
#ifndef HB_FREE_POOL_HH
#define HB_FREE_POOL_HH
#include "hb.hh"
/* Memory pool for persistent alloc/free of small objects.
*
* Some AI musings on this, not necessarily true:
*
* This is a very simple implementation, but it's good enough for our
* purposes. It's not thread-safe. It's not very fast. It's not
* very memory efficient. It's not very cache efficient. It's not
* very anything efficient. But it's simple and it works. And it's
* good enough for our purposes. If you need something more
* sophisticated, use a real allocator. Or use a real language. */
template <typename T, unsigned ChunkLen = 32>
struct hb_free_pool_t
{
hb_free_pool_t () : next (nullptr) {}
~hb_free_pool_t ()
{
next = nullptr;
+ hb_iter (chunks)
| hb_apply (hb_free)
;
}
T* alloc ()
{
if (unlikely (!next))
{
if (unlikely (!chunks.alloc (chunks.length + 1))) return nullptr;
chunk_t *chunk = (chunk_t *) hb_malloc (sizeof (chunk_t));
if (unlikely (!chunk)) return nullptr;
chunks.push (chunk);
next = chunk->thread ();
}
T* obj = next;
next = * ((T**) next);
hb_memset (obj, 0, sizeof (T));
return obj;
}
void release (T* obj)
{
* (T**) obj = next;
next = obj;
}
private:
static_assert (ChunkLen > 1, "");
static_assert (sizeof (T) >= sizeof (void *), "");
static_assert (alignof (T) % alignof (void *) == 0, "");
struct chunk_t
{
T* thread ()
{
for (unsigned i = 0; i < ARRAY_LENGTH (arrayZ) - 1; i++)
* (T**) &arrayZ[i] = &arrayZ[i + 1];
* (T**) &arrayZ[ARRAY_LENGTH (arrayZ) - 1] = nullptr;
return arrayZ;
}
T arrayZ[ChunkLen];
};
T* next;
hb_vector_t<chunk_t *> chunks;
};
#endif /* HB_FREE_POOL_HH */

View file

@ -266,7 +266,7 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan HB_UNUSED,
gr_segment *seg = nullptr;
const gr_slot *is;
unsigned int ci = 0, ic = 0;
unsigned int curradvx = 0, curradvy = 0;
int curradvx = 0, curradvy = 0;
unsigned int scratch_size;
hb_buffer_t::scratch_buffer_t *scratch = buffer->get_scratch_buffer (&scratch_size);

View file

@ -972,7 +972,7 @@ struct
Proj&& f = hb_identity) const
{
for (auto it = hb_iter (c); it; ++it)
if (!hb_match (std::forward<Pred> (p), hb_get (std::forward<Proj> (f), *it)))
if (!hb_match (p, hb_get (f, *it)))
return false;
return true;
}
@ -989,7 +989,7 @@ struct
Proj&& f = hb_identity) const
{
for (auto it = hb_iter (c); it; ++it)
if (hb_match (std::forward<Pred> (p), hb_get (std::forward<Proj> (f), *it)))
if (hb_match (p, hb_get (f, *it)))
return true;
return false;
}
@ -1006,7 +1006,7 @@ struct
Proj&& f = hb_identity) const
{
for (auto it = hb_iter (c); it; ++it)
if (hb_match (std::forward<Pred> (p), hb_get (std::forward<Proj> (f), *it)))
if (hb_match (p, hb_get (f, *it)))
return false;
return true;
}

259
thirdparty/harfbuzz/src/hb-kbts.cc vendored Normal file
View file

@ -0,0 +1,259 @@
/*
* 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.
*
* Author(s): Khaled Hosny
*/
#include "hb.hh"
#if HAVE_KBTS
#include "hb-shaper-impl.hh"
#define KB_TEXT_SHAPE_IMPLEMENTATION
#define KB_TEXT_SHAPE_STATIC
#define KB_TEXT_SHAPE_NO_CRT
#define KBTS_MEMSET hb_memset
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-align"
#pragma GCC diagnostic ignored "-Wunused-function"
#pragma GCC diagnostic ignored "-Wsign-compare"
#include "kb_text_shape.h"
#pragma GCC diagnostic pop
hb_kbts_face_data_t *
_hb_kbts_shaper_face_data_create (hb_face_t *face)
{
hb_blob_t *blob = hb_face_reference_blob (face);
unsigned int blob_length;
const char *blob_data = hb_blob_get_data (blob, &blob_length);
if (unlikely (!blob_length))
{
DEBUG_MSG (KBTS, blob, "Empty blob");
hb_blob_destroy (blob);
return nullptr;
}
void *data = hb_malloc (blob_length);
if (likely (data))
hb_memcpy (data, blob_data, blob_length);
hb_blob_destroy (blob);
blob = nullptr;
if (unlikely (!data))
{
DEBUG_MSG (KBTS, face, "Failed to allocate memory for font data");
return nullptr;
}
kbts_font *kb_font = (kbts_font *) hb_calloc (1, sizeof (kbts_font));
if (unlikely (!kb_font))
{
hb_free (data);
return nullptr;
}
size_t memory_size;
{
unsigned scratch_size = kbts_ReadFontHeader (kb_font, data, blob_length);
void *scratch = hb_malloc (scratch_size);
memory_size = kbts_ReadFontData (kb_font, scratch, scratch_size);
hb_free (scratch);
}
void *memory = hb_malloc (memory_size);
if (unlikely (!kbts_PostReadFontInitialize (kb_font, memory, memory_size)))
{
DEBUG_MSG (KBTS, face, "kbts_PostReadFontInitialize failed");
hb_free (memory);
hb_free (data);
hb_free (kb_font);
return nullptr;
}
return (hb_kbts_face_data_t *) kb_font;
}
void
_hb_kbts_shaper_face_data_destroy (hb_kbts_face_data_t *data)
{
kbts_font *font = (kbts_font *) data;
assert (kbts_FontIsValid (font));
hb_free (font->FileBase);
hb_free (font->GlyphLookupMatrix);
hb_free (font);
}
hb_kbts_font_data_t *
_hb_kbts_shaper_font_data_create (hb_font_t *font)
{
return (hb_kbts_font_data_t *) HB_SHAPER_DATA_SUCCEEDED;
}
void
_hb_kbts_shaper_font_data_destroy (hb_kbts_font_data_t *data)
{
}
hb_bool_t
_hb_kbts_shape (hb_shape_plan_t *shape_plan,
hb_font_t *font,
hb_buffer_t *buffer,
const hb_feature_t *features,
unsigned int num_features)
{
hb_face_t *face = font->face;
kbts_font *kb_font = (kbts_font *) (const void *) face->data.kbts;
kbts_direction kb_direction;
switch (buffer->props.direction)
{
case HB_DIRECTION_LTR: kb_direction = KBTS_DIRECTION_LTR; break;
case HB_DIRECTION_RTL: kb_direction = KBTS_DIRECTION_RTL; break;
case HB_DIRECTION_TTB:
case HB_DIRECTION_BTT:
DEBUG_MSG (KBTS, face, "Vertical direction is not supported");
return false;
default:
case HB_DIRECTION_INVALID:
DEBUG_MSG (KBTS, face, "Invalid direction");
return false;
}
kbts_script kb_script = KBTS_SCRIPT_DONT_KNOW;
kbts_language kb_language = KBTS_LANGUAGE_DEFAULT;
{
hb_tag_t scripts[HB_OT_MAX_TAGS_PER_SCRIPT];
hb_tag_t language;
unsigned int script_count = ARRAY_LENGTH (scripts);
unsigned int language_count = 1;
hb_ot_tags_from_script_and_language (buffer->props.script, buffer->props.language,
&script_count, scripts,
&language_count, &language);
for (unsigned int i = 0; i < script_count && scripts[i] != HB_TAG_NONE; ++i)
{
kb_script = kbts_ScriptTagToScript (hb_uint32_swap (scripts[i]));
if (kb_script != KBTS_SCRIPT_DONT_KNOW)
break;
}
if (language_count)
kb_language = (kbts_language) hb_uint32_swap (language);
}
hb_vector_t<kbts_glyph> kb_glyphs;
if (unlikely (!kb_glyphs.resize_full (buffer->len, false, true)))
return false;
for (size_t i = 0; i < buffer->len; ++i)
kb_glyphs.arrayZ[i] = kbts_CodepointToGlyph (kb_font, buffer->info[i].codepoint);
if (num_features)
{
for (unsigned int i = 0; i < num_features; ++i)
{
hb_feature_t feature = features[i];
for (unsigned int j = 0; j < buffer->len; ++j)
{
kbts_glyph *kb_glyph = &kb_glyphs.arrayZ[j];
if (hb_in_range (j, feature.start, feature.end))
{
if (!kb_glyph->Config)
kb_glyph->Config = (kbts_glyph_config *) hb_calloc (1, sizeof (kbts_glyph_config));
kbts_glyph_config *config = kb_glyph->Config;
while (!kbts_GlyphConfigOverrideFeatureFromTag (config, hb_uint32_swap (feature.tag),
feature.value > 1, feature.value))
{
config->FeatureOverrides = (kbts_feature_override *) hb_realloc (config->FeatureOverrides,
config->RequiredFeatureOverrideCapacity);
config->FeatureOverrideCapacity += 1;
}
}
}
}
}
kbts_shape_state *kb_shape_state;
{
size_t kb_shape_state_size = kbts_SizeOfShapeState (kb_font);
void *kb_shape_state_buffer = hb_malloc (kb_shape_state_size);
if (unlikely (!kb_shape_state_buffer))
{
DEBUG_MSG (KBTS, face, "Failed to allocate memory for shape state");
return false;
}
kb_shape_state = kbts_PlaceShapeState (kb_shape_state_buffer, kb_shape_state_size);
}
kbts_shape_config kb_shape_config = kbts_ShapeConfig (kb_font, kb_script, kb_language);
uint32_t glyph_count = buffer->len;
uint32_t glyph_capacity = kb_glyphs.length;
while (kbts_Shape (kb_shape_state, &kb_shape_config, KBTS_DIRECTION_LTR, kb_direction,
kb_glyphs.arrayZ, &glyph_count, glyph_capacity))
{
glyph_capacity = kb_shape_state->RequiredGlyphCapacity;
/* kb increases capacity by a fixed number only. We increase it by 50% to
* avoid O(n^2) behavior in case of expanding text.
*
* https://github.com/JimmyLefevre/kb/issues/32
*/
glyph_capacity += glyph_capacity / 2;
if (unlikely (!kb_glyphs.resize_full (glyph_capacity, false, true)))
return false;
}
hb_buffer_set_content_type (buffer, HB_BUFFER_CONTENT_TYPE_GLYPHS);
hb_buffer_set_length (buffer, glyph_count);
hb_glyph_info_t *info = buffer->info;
hb_glyph_position_t *pos = buffer->pos;
buffer->clear_positions ();
for (size_t i = 0; i < glyph_count; ++i)
{
kbts_glyph kb_glyph = kb_glyphs.arrayZ[i];
info[i].codepoint = kb_glyph.Id;
info[i].cluster = 0; // FIXME
pos[i].x_advance = font->em_scalef_x (kb_glyph.AdvanceX);
pos[i].y_advance = font->em_scalef_y (kb_glyph.AdvanceY);
pos[i].x_offset = font->em_scalef_x (kb_glyph.OffsetX);
pos[i].y_offset = font->em_scalef_y (kb_glyph.OffsetY);
if (kb_glyph.Config)
hb_free (kb_glyph.Config->FeatureOverrides);
}
hb_free (kb_shape_state);
buffer->clear_glyph_flags ();
buffer->unsafe_to_break ();
return true;
}
#endif

View file

@ -70,7 +70,7 @@ struct hb_kern_machine_t
continue;
}
skippy_iter.reset (idx);
skippy_iter.reset_fast (idx);
unsigned unsafe_to;
if (!skippy_iter.next (&unsafe_to))
{

View file

@ -29,20 +29,20 @@
#ifndef HB_BUFFER_MAX_LEN_FACTOR
#define HB_BUFFER_MAX_LEN_FACTOR 64
#define HB_BUFFER_MAX_LEN_FACTOR 256
#endif
#ifndef HB_BUFFER_MAX_LEN_MIN
#define HB_BUFFER_MAX_LEN_MIN 16384
#define HB_BUFFER_MAX_LEN_MIN 65536
#endif
#ifndef HB_BUFFER_MAX_LEN_DEFAULT
#define HB_BUFFER_MAX_LEN_DEFAULT 0x3FFFFFFF /* Shaping more than a billion chars? Let us know! */
#endif
#ifndef HB_BUFFER_MAX_OPS_FACTOR
#define HB_BUFFER_MAX_OPS_FACTOR 1024
#define HB_BUFFER_MAX_OPS_FACTOR 4096
#endif
#ifndef HB_BUFFER_MAX_OPS_MIN
#define HB_BUFFER_MAX_OPS_MIN 16384
#define HB_BUFFER_MAX_OPS_MIN 65536
#endif
#ifndef HB_BUFFER_MAX_OPS_DEFAULT
#define HB_BUFFER_MAX_OPS_DEFAULT 0x1FFFFFFF /* Shaping more than a billion operations? Let us know! */

View file

@ -70,11 +70,18 @@ static inline Type& StructAtOffsetUnaligned(void *P, unsigned int offset)
* Any extra arguments are forwarded to get_size, so for example
* it can work with UnsizedArrayOf<> as well. */
template <typename Type, typename TObject, typename ...Ts>
static inline const Type& StructAfter(const TObject &X, Ts... args)
{ return StructAtOffset<Type>(&X, X.get_size(args...)); }
static inline auto StructAfter(const TObject &X, Ts... args) HB_AUTO_RETURN((
StructAtOffset<Type>(&X, X.get_size(std::forward<Ts> (args)...))
))
/* The is_const shenanigans is to avoid ambiguous overload with gcc-8.
* It disables this path when TObject is const.
* See: https://github.com/harfbuzz/harfbuzz/issues/5429 */
template <typename Type, typename TObject, typename ...Ts>
static inline Type& StructAfter(TObject &X, Ts... args)
{ return StructAtOffset<Type>(&X, X.get_size(args...)); }
static inline auto StructAfter(TObject &X, Ts... args) HB_AUTO_RETURN((
sizeof(int[std::is_const<TObject>::value ? -1 : +1]) > 0 ?
StructAtOffset<Type>(&X, X.get_size(std::forward<Ts> (args)...))
: *reinterpret_cast<Type*> (0)
))
/*

View file

@ -47,11 +47,11 @@ struct hb_hashmap_t
hb_hashmap_t () { init (); }
~hb_hashmap_t () { fini (); }
hb_hashmap_t (const hb_hashmap_t& o) : hb_hashmap_t ()
void _copy (const hb_hashmap_t& o)
{
if (unlikely (!o.mask)) return;
if (item_t::is_trivial)
if (hb_is_trivially_copy_assignable (item_t))
{
items = (item_t *) hb_malloc (sizeof (item_t) * (o.mask + 1));
if (unlikely (!items))
@ -70,8 +70,16 @@ struct hb_hashmap_t
alloc (o.population); hb_copy (o, *this);
}
hb_hashmap_t (const hb_hashmap_t& o) : hb_hashmap_t () { _copy (o); }
hb_hashmap_t& operator= (const hb_hashmap_t& o)
{
reset ();
if (!items) { _copy (o); return *this; }
alloc (o.population); hb_copy (o, *this); return *this;
}
hb_hashmap_t (hb_hashmap_t&& o) noexcept : hb_hashmap_t () { hb_swap (*this, o); }
hb_hashmap_t& operator= (const hb_hashmap_t& o) { reset (); alloc (o.population); hb_copy (o, *this); return *this; }
hb_hashmap_t& operator= (hb_hashmap_t&& o) noexcept { hb_swap (*this, o); return *this; }
hb_hashmap_t (std::initializer_list<hb_pair_t<K, V>> lst) : hb_hashmap_t ()
@ -130,10 +138,7 @@ struct hb_hashmap_t
uint32_t total_hash () const
{ return (hash * 31u) + hb_hash (value); }
static constexpr bool is_trivial = hb_is_trivially_constructible(K) &&
hb_is_trivially_destructible(K) &&
hb_is_trivially_constructible(V) &&
hb_is_trivially_destructible(V);
static constexpr bool is_trivially_constructible = (hb_is_trivially_constructible(K) && hb_is_trivially_constructible(V));
};
hb_object_header_t header;
@ -174,19 +179,19 @@ struct hb_hashmap_t
if (likely (items))
{
unsigned size = mask + 1;
if (!item_t::is_trivial)
for (unsigned i = 0; i < size; i++)
items[i].~item_t ();
for (unsigned i = 0; i < size; i++)
items[i].~item_t ();
hb_free (items);
items = nullptr;
}
population = occupancy = 0;
}
void reset ()
hb_hashmap_t& reset ()
{
successful = true;
clear ();
return *this;
}
bool in_error () const { return !successful; }
@ -197,7 +202,7 @@ struct hb_hashmap_t
if (new_population != 0 && (new_population + new_population / 2) < mask) return true;
unsigned int power = hb_bit_storage (hb_max ((unsigned) population, new_population) * 2 + 8);
unsigned int power = hb_bit_storage (hb_max (hb_max ((unsigned) population, new_population) * 2, 4u));
unsigned int new_size = 1u << power;
item_t *new_items = (item_t *) hb_malloc ((size_t) new_size * sizeof (item_t));
if (unlikely (!new_items))
@ -205,7 +210,7 @@ struct hb_hashmap_t
successful = false;
return false;
}
if (!item_t::is_trivial)
if (!item_t::is_trivially_constructible)
for (auto &_ : hb_iter (new_items, new_size))
new (&_) item_t ();
else
@ -231,9 +236,8 @@ struct hb_hashmap_t
std::move (old_items[i].value));
}
}
if (!item_t::is_trivial)
for (unsigned int i = 0; i < old_size; i++)
old_items[i].~item_t ();
for (unsigned int i = 0; i < old_size; i++)
old_items[i].~item_t ();
hb_free (old_items);
@ -335,7 +339,13 @@ struct hb_hashmap_t
bool has (const K &key, VV **vp = nullptr) const
{
if (!items) return false;
auto *item = fetch_item (key, hb_hash (key));
return has_with_hash (key, hb_hash (key), vp);
}
template <typename VV=V>
bool has_with_hash (const K &key, uint32_t hash, VV **vp = nullptr) const
{
if (!items) return false;
auto *item = fetch_item (key, hash);
if (item)
{
if (vp) *vp = std::addressof (item->value);
@ -481,10 +491,17 @@ struct hb_hashmap_t
/* Sink interface. */
hb_hashmap_t& operator << (const hb_pair_t<K, V>& v)
{ set (v.first, v.second); return *this; }
template <typename V2 = V,
hb_enable_if (!std::is_trivially_copyable<V2>::value)>
hb_hashmap_t& operator << (const hb_pair_t<K, V&&>& v)
{ set (v.first, std::move (v.second)); return *this; }
template <typename K2 = K,
hb_enable_if (!std::is_trivially_copyable<K2>::value)>
hb_hashmap_t& operator << (const hb_pair_t<K&&, V>& v)
{ set (std::move (v.first), v.second); return *this; }
template <typename K2 = K, typename V2 = V,
hb_enable_if (!std::is_trivially_copyable<K2>::value &&
!std::is_trivially_copyable<V2>::value)>
hb_hashmap_t& operator << (const hb_pair_t<K&&, V&&>& v)
{ set (std::move (v.first), std::move (v.second)); return *this; }

View file

@ -31,7 +31,7 @@
#include "hb.hh"
#line 35 "hb-number-parser.hh"
#line 32 "hb-number-parser.hh"
static const unsigned char _double_parser_trans_keys[] = {
0u, 0u, 43u, 57u, 46u, 57u, 48u, 57u, 43u, 57u, 48u, 57u, 48u, 101u, 48u, 57u,
46u, 101u, 0
@ -135,12 +135,12 @@ strtod_rl (const char *p, const char **end_ptr /* IN/OUT */)
int cs;
#line 139 "hb-number-parser.hh"
#line 132 "hb-number-parser.hh"
{
cs = double_parser_start;
}
#line 144 "hb-number-parser.hh"
#line 135 "hb-number-parser.hh"
{
int _slen;
int _trans;
@ -198,7 +198,7 @@ _resume:
exp_overflow = true;
}
break;
#line 202 "hb-number-parser.hh"
#line 187 "hb-number-parser.hh"
}
_again:

View file

@ -82,6 +82,7 @@ struct NumType
NumType operator ++ (int) { NumType c (*this); ++*this; return c; }
NumType operator -- (int) { NumType c (*this); --*this; return c; }
uint32_t hash () const { return hb_array ((const char *) &v, sizeof (v)).hash (); }
HB_INTERNAL static int cmp (const NumType *a, const NumType *b)
{ return b->cmp (*a); }
HB_INTERNAL static int cmp (const void *a, const void *b)
@ -1498,8 +1499,8 @@ struct TupleValues
VALUE_RUN_COUNT_MASK = 0x3F
};
static unsigned compile (hb_array_t<const int> values, /* IN */
hb_array_t<unsigned char> encoded_bytes /* OUT */)
static unsigned compile_unsafe (hb_array_t<const int> values, /* IN */
unsigned char *encoded_bytes /* OUT */)
{
unsigned num_values = values.length;
unsigned encoded_len = 0;
@ -1508,24 +1509,23 @@ struct TupleValues
{
int val = values.arrayZ[i];
if (val == 0)
encoded_len += encode_value_run_as_zeroes (i, encoded_bytes.sub_array (encoded_len), values);
else if (val >= -128 && val <= 127)
encoded_len += encode_value_run_as_bytes (i, encoded_bytes.sub_array (encoded_len), values);
else if (val >= -32768 && val <= 32767)
encoded_len += encode_value_run_as_words (i, encoded_bytes.sub_array (encoded_len), values);
encoded_len += encode_value_run_as_zeroes (i, encoded_bytes + encoded_len, values);
else if ((int8_t) val == val)
encoded_len += encode_value_run_as_bytes (i, encoded_bytes + encoded_len, values);
else if ((int16_t) val == val)
encoded_len += encode_value_run_as_words (i, encoded_bytes + encoded_len, values);
else
encoded_len += encode_value_run_as_longs (i, encoded_bytes.sub_array (encoded_len), values);
encoded_len += encode_value_run_as_longs (i, encoded_bytes + encoded_len, values);
}
return encoded_len;
}
static unsigned encode_value_run_as_zeroes (unsigned& i,
hb_array_t<unsigned char> encoded_bytes,
unsigned char *it,
hb_array_t<const int> values)
{
unsigned num_values = values.length;
unsigned run_length = 0;
auto it = encoded_bytes.iter ();
unsigned encoded_len = 0;
while (i < num_values && values.arrayZ[i] == 0)
{
@ -1549,7 +1549,7 @@ struct TupleValues
}
static unsigned encode_value_run_as_bytes (unsigned &i,
hb_array_t<unsigned char> encoded_bytes,
unsigned char *it,
hb_array_t<const int> values)
{
unsigned start = i;
@ -1557,7 +1557,7 @@ struct TupleValues
while (i < num_values)
{
int val = values.arrayZ[i];
if (val > 127 || val < -128)
if ((int8_t) val != val)
break;
/* from fonttools: if there're 2 or more zeros in a sequence,
@ -1570,7 +1570,6 @@ struct TupleValues
unsigned run_length = i - start;
unsigned encoded_len = 0;
auto it = encoded_bytes.iter ();
while (run_length >= 64)
{
@ -1578,10 +1577,9 @@ struct TupleValues
encoded_len++;
for (unsigned j = 0; j < 64; j++)
{
*it++ = static_cast<char> (values.arrayZ[start + j]);
encoded_len++;
}
it[j] = static_cast<char> (values.arrayZ[start + j]);
it += 64;
encoded_len += 64;
start += 64;
run_length -= 64;
@ -1592,18 +1590,16 @@ struct TupleValues
*it++ = (VALUES_ARE_BYTES | (run_length - 1));
encoded_len++;
while (start < i)
{
*it++ = static_cast<char> (values.arrayZ[start++]);
encoded_len++;
}
for (unsigned j = 0; j < run_length; j++)
it[j] = static_cast<char> (values.arrayZ[start + j]);
encoded_len += run_length;
}
return encoded_len;
}
static unsigned encode_value_run_as_words (unsigned &i,
hb_array_t<unsigned char> encoded_bytes,
unsigned char *it,
hb_array_t<const int> values)
{
unsigned start = i;
@ -1612,22 +1608,24 @@ struct TupleValues
{
int val = values.arrayZ[i];
/* start a new run for a single zero value*/
if ((int16_t) val != val)
break;
/* start a new run for a single zero value. */
if (val == 0) break;
/* from fonttools: continue word-encoded run if there's only one
/* From fonttools: continue word-encoded run if there's only one
* single value in the range [-128, 127] because it is more compact.
* Only start a new run when there're 2 continuous such values. */
if (val >= -128 && val <= 127 &&
if ((int8_t) val == val &&
i + 1 < num_values &&
values.arrayZ[i+1] >= -128 && values.arrayZ[i+1] <= 127)
(int8_t) values.arrayZ[i+1] == values.arrayZ[i+1])
break;
i++;
}
unsigned run_length = i - start;
auto it = encoded_bytes.iter ();
unsigned encoded_len = 0;
while (run_length >= 64)
{
@ -1664,7 +1662,7 @@ struct TupleValues
}
static unsigned encode_value_run_as_longs (unsigned &i,
hb_array_t<unsigned char> encoded_bytes,
unsigned char *it,
hb_array_t<const int> values)
{
unsigned start = i;
@ -1673,14 +1671,13 @@ struct TupleValues
{
int val = values.arrayZ[i];
if (val >= -32768 && val <= 32767)
if ((int16_t) val == val)
break;
i++;
}
unsigned run_length = i - start;
auto it = encoded_bytes.iter ();
unsigned encoded_len = 0;
while (run_length >= 64)
{
@ -1738,7 +1735,7 @@ struct TupleValues
unsigned run_count = (control & VALUE_RUN_COUNT_MASK) + 1;
if (consume_all)
{
if (unlikely (!values.resize (values.length + run_count, false)))
if (unlikely (!values.resize_dirty (values.length + run_count)))
return false;
}
unsigned stop = i + run_count;

View file

@ -79,7 +79,7 @@ struct Dict : UnsizedByteStr
{
TRACE_SERIALIZE (this);
for (unsigned int i = 0; i < dictval.get_count (); i++)
if (unlikely (!opszr.serialize (c, dictval[i], std::forward<Ts> (ds)...)))
if (unlikely (!opszr.serialize (c, dictval[i], ds...)))
return_trace (false);
return_trace (true);

View file

@ -30,396 +30,396 @@
#include "hb.hh"
#endif
_S(".notdef")
_S("space")
_S("exclam")
_S("quotedbl")
_S("numbersign")
_S("dollar")
_S("percent")
_S("ampersand")
_S("quoteright")
_S("parenleft")
_S("parenright")
_S("asterisk")
_S("plus")
_S("comma")
_S("hyphen")
_S("period")
_S("slash")
_S("zero")
_S("one")
_S("two")
_S("three")
_S("four")
_S("five")
_S("six")
_S("seven")
_S("eight")
_S("nine")
_S("colon")
_S("semicolon")
_S("less")
_S("equal")
_S("greater")
_S("question")
_S("at")
_S("A")
_S("B")
_S("C")
_S("D")
_S("E")
_S("F")
_S("G")
_S("H")
_S("I")
_S("J")
_S("K")
_S("L")
_S("M")
_S("N")
_S("O")
_S("P")
_S("Q")
_S("R")
_S("S")
_S("T")
_S("U")
_S("V")
_S("W")
_S("X")
_S("Y")
_S("Z")
_S("bracketleft")
_S("backslash")
_S("bracketright")
_S("asciicircum")
_S("underscore")
_S("quoteleft")
_S("a")
_S("b")
_S("c")
_S("d")
_S("e")
_S("f")
_S("g")
_S("h")
_S("i")
_S("j")
_S("k")
_S("l")
_S("m")
_S("n")
_S("o")
_S("p")
_S("q")
_S("r")
_S("s")
_S("t")
_S("u")
_S("v")
_S("w")
_S("x")
_S("y")
_S("z")
_S("braceleft")
_S("bar")
_S("braceright")
_S("asciitilde")
_S("exclamdown")
_S("cent")
_S("sterling")
_S("fraction")
_S("yen")
_S("florin")
_S("section")
_S("currency")
_S("quotesingle")
_S("quotedblleft")
_S("guillemotleft")
_S("guilsinglleft")
_S("guilsinglright")
_S("fi")
_S("fl")
_S("endash")
_S("dagger")
_S("daggerdbl")
_S("periodcentered")
_S("paragraph")
_S("bullet")
_S("quotesinglbase")
_S("quotedblbase")
_S("quotedblright")
_S("guillemotright")
_S("ellipsis")
_S("perthousand")
_S("questiondown")
_S("grave")
_S("acute")
_S("circumflex")
_S("tilde")
_S("macron")
_S("breve")
_S("dotaccent")
_S("dieresis")
_S("ring")
_S("cedilla")
_S("hungarumlaut")
_S("ogonek")
_S("caron")
_S("emdash")
_S("AE")
_S("ordfeminine")
_S("Lslash")
_S("Oslash")
_S("OE")
_S("ordmasculine")
_S("ae")
_S("dotlessi")
_S("lslash")
_S("oslash")
_S("oe")
_S("germandbls")
_S("onesuperior")
_S("logicalnot")
_S("mu")
_S("trademark")
_S("Eth")
_S("onehalf")
_S("plusminus")
_S("Thorn")
_S("onequarter")
_S("divide")
_S("brokenbar")
_S("degree")
_S("thorn")
_S("threequarters")
_S("twosuperior")
_S("registered")
_S("minus")
_S("eth")
_S("multiply")
_S("threesuperior")
_S("copyright")
_S("Aacute")
_S("Acircumflex")
_S("Adieresis")
_S("Agrave")
_S("Aring")
_S("Atilde")
_S("Ccedilla")
_S("Eacute")
_S("Ecircumflex")
_S("Edieresis")
_S("Egrave")
_S("Iacute")
_S("Icircumflex")
_S("Idieresis")
_S("Igrave")
_S("Ntilde")
_S("Oacute")
_S("Ocircumflex")
_S("Odieresis")
_S("Ograve")
_S("Otilde")
_S("Scaron")
_S("Uacute")
_S("Ucircumflex")
_S("Udieresis")
_S("Ugrave")
_S("Yacute")
_S("Ydieresis")
_S("Zcaron")
_S("aacute")
_S("acircumflex")
_S("adieresis")
_S("agrave")
_S("aring")
_S("atilde")
_S("ccedilla")
_S("eacute")
_S("ecircumflex")
_S("edieresis")
_S("egrave")
_S("iacute")
_S("icircumflex")
_S("idieresis")
_S("igrave")
_S("ntilde")
_S("oacute")
_S("ocircumflex")
_S("odieresis")
_S("ograve")
_S("otilde")
_S("scaron")
_S("uacute")
_S("ucircumflex")
_S("udieresis")
_S("ugrave")
_S("yacute")
_S("ydieresis")
_S("zcaron")
_S("exclamsmall")
_S("Hungarumlautsmall")
_S("dollaroldstyle")
_S("dollarsuperior")
_S("ampersandsmall")
_S("Acutesmall")
_S("parenleftsuperior")
_S("parenrightsuperior")
_S("twodotenleader")
_S("onedotenleader")
_S("zerooldstyle")
_S("oneoldstyle")
_S("twooldstyle")
_S("threeoldstyle")
_S("fouroldstyle")
_S("fiveoldstyle")
_S("sixoldstyle")
_S("sevenoldstyle")
_S("eightoldstyle")
_S("nineoldstyle")
_S("commasuperior")
_S("threequartersemdash")
_S("periodsuperior")
_S("questionsmall")
_S("asuperior")
_S("bsuperior")
_S("centsuperior")
_S("dsuperior")
_S("esuperior")
_S("isuperior")
_S("lsuperior")
_S("msuperior")
_S("nsuperior")
_S("osuperior")
_S("rsuperior")
_S("ssuperior")
_S("tsuperior")
_S("ff")
_S("ffi")
_S("ffl")
_S("parenleftinferior")
_S("parenrightinferior")
_S("Circumflexsmall")
_S("hyphensuperior")
_S("Gravesmall")
_S("Asmall")
_S("Bsmall")
_S("Csmall")
_S("Dsmall")
_S("Esmall")
_S("Fsmall")
_S("Gsmall")
_S("Hsmall")
_S("Ismall")
_S("Jsmall")
_S("Ksmall")
_S("Lsmall")
_S("Msmall")
_S("Nsmall")
_S("Osmall")
_S("Psmall")
_S("Qsmall")
_S("Rsmall")
_S("Ssmall")
_S("Tsmall")
_S("Usmall")
_S("Vsmall")
_S("Wsmall")
_S("Xsmall")
_S("Ysmall")
_S("Zsmall")
_S("colonmonetary")
_S("onefitted")
_S("rupiah")
_S("Tildesmall")
_S("exclamdownsmall")
_S("centoldstyle")
_S("Lslashsmall")
_S("Scaronsmall")
_S("Zcaronsmall")
_S("Dieresissmall")
_S("Brevesmall")
_S("Caronsmall")
_S("Dotaccentsmall")
_S("Macronsmall")
_S("figuredash")
_S("hypheninferior")
_S("Ogoneksmall")
_S("Ringsmall")
_S("Cedillasmall")
_S("questiondownsmall")
_S("oneeighth")
_S("threeeighths")
_S("fiveeighths")
_S("seveneighths")
_S("onethird")
_S("twothirds")
_S("zerosuperior")
_S("foursuperior")
_S("fivesuperior")
_S("sixsuperior")
_S("sevensuperior")
_S("eightsuperior")
_S("ninesuperior")
_S("zeroinferior")
_S("oneinferior")
_S("twoinferior")
_S("threeinferior")
_S("fourinferior")
_S("fiveinferior")
_S("sixinferior")
_S("seveninferior")
_S("eightinferior")
_S("nineinferior")
_S("centinferior")
_S("dollarinferior")
_S("periodinferior")
_S("commainferior")
_S("Agravesmall")
_S("Aacutesmall")
_S("Acircumflexsmall")
_S("Atildesmall")
_S("Adieresissmall")
_S("Aringsmall")
_S("AEsmall")
_S("Ccedillasmall")
_S("Egravesmall")
_S("Eacutesmall")
_S("Ecircumflexsmall")
_S("Edieresissmall")
_S("Igravesmall")
_S("Iacutesmall")
_S("Icircumflexsmall")
_S("Idieresissmall")
_S("Ethsmall")
_S("Ntildesmall")
_S("Ogravesmall")
_S("Oacutesmall")
_S("Ocircumflexsmall")
_S("Otildesmall")
_S("Odieresissmall")
_S("OEsmall")
_S("Oslashsmall")
_S("Ugravesmall")
_S("Uacutesmall")
_S("Ucircumflexsmall")
_S("Udieresissmall")
_S("Yacutesmall")
_S("Thornsmall")
_S("Ydieresissmall")
_S("001.000")
_S("001.001")
_S("001.002")
_S("001.003")
_S("Black")
_S("Bold")
_S("Book")
_S("Light")
_S("Medium")
_S("Regular")
_S("Roman")
_S("Semibold")
HB_STR(".notdef")
HB_STR("space")
HB_STR("exclam")
HB_STR("quotedbl")
HB_STR("numbersign")
HB_STR("dollar")
HB_STR("percent")
HB_STR("ampersand")
HB_STR("quoteright")
HB_STR("parenleft")
HB_STR("parenright")
HB_STR("asterisk")
HB_STR("plus")
HB_STR("comma")
HB_STR("hyphen")
HB_STR("period")
HB_STR("slash")
HB_STR("zero")
HB_STR("one")
HB_STR("two")
HB_STR("three")
HB_STR("four")
HB_STR("five")
HB_STR("six")
HB_STR("seven")
HB_STR("eight")
HB_STR("nine")
HB_STR("colon")
HB_STR("semicolon")
HB_STR("less")
HB_STR("equal")
HB_STR("greater")
HB_STR("question")
HB_STR("at")
HB_STR("A")
HB_STR("B")
HB_STR("C")
HB_STR("D")
HB_STR("E")
HB_STR("F")
HB_STR("G")
HB_STR("H")
HB_STR("I")
HB_STR("J")
HB_STR("K")
HB_STR("L")
HB_STR("M")
HB_STR("N")
HB_STR("O")
HB_STR("P")
HB_STR("Q")
HB_STR("R")
HB_STR("S")
HB_STR("T")
HB_STR("U")
HB_STR("V")
HB_STR("W")
HB_STR("X")
HB_STR("Y")
HB_STR("Z")
HB_STR("bracketleft")
HB_STR("backslash")
HB_STR("bracketright")
HB_STR("asciicircum")
HB_STR("underscore")
HB_STR("quoteleft")
HB_STR("a")
HB_STR("b")
HB_STR("c")
HB_STR("d")
HB_STR("e")
HB_STR("f")
HB_STR("g")
HB_STR("h")
HB_STR("i")
HB_STR("j")
HB_STR("k")
HB_STR("l")
HB_STR("m")
HB_STR("n")
HB_STR("o")
HB_STR("p")
HB_STR("q")
HB_STR("r")
HB_STR("s")
HB_STR("t")
HB_STR("u")
HB_STR("v")
HB_STR("w")
HB_STR("x")
HB_STR("y")
HB_STR("z")
HB_STR("braceleft")
HB_STR("bar")
HB_STR("braceright")
HB_STR("asciitilde")
HB_STR("exclamdown")
HB_STR("cent")
HB_STR("sterling")
HB_STR("fraction")
HB_STR("yen")
HB_STR("florin")
HB_STR("section")
HB_STR("currency")
HB_STR("quotesingle")
HB_STR("quotedblleft")
HB_STR("guillemotleft")
HB_STR("guilsinglleft")
HB_STR("guilsinglright")
HB_STR("fi")
HB_STR("fl")
HB_STR("endash")
HB_STR("dagger")
HB_STR("daggerdbl")
HB_STR("periodcentered")
HB_STR("paragraph")
HB_STR("bullet")
HB_STR("quotesinglbase")
HB_STR("quotedblbase")
HB_STR("quotedblright")
HB_STR("guillemotright")
HB_STR("ellipsis")
HB_STR("perthousand")
HB_STR("questiondown")
HB_STR("grave")
HB_STR("acute")
HB_STR("circumflex")
HB_STR("tilde")
HB_STR("macron")
HB_STR("breve")
HB_STR("dotaccent")
HB_STR("dieresis")
HB_STR("ring")
HB_STR("cedilla")
HB_STR("hungarumlaut")
HB_STR("ogonek")
HB_STR("caron")
HB_STR("emdash")
HB_STR("AE")
HB_STR("ordfeminine")
HB_STR("Lslash")
HB_STR("Oslash")
HB_STR("OE")
HB_STR("ordmasculine")
HB_STR("ae")
HB_STR("dotlessi")
HB_STR("lslash")
HB_STR("oslash")
HB_STR("oe")
HB_STR("germandbls")
HB_STR("onesuperior")
HB_STR("logicalnot")
HB_STR("mu")
HB_STR("trademark")
HB_STR("Eth")
HB_STR("onehalf")
HB_STR("plusminus")
HB_STR("Thorn")
HB_STR("onequarter")
HB_STR("divide")
HB_STR("brokenbar")
HB_STR("degree")
HB_STR("thorn")
HB_STR("threequarters")
HB_STR("twosuperior")
HB_STR("registered")
HB_STR("minus")
HB_STR("eth")
HB_STR("multiply")
HB_STR("threesuperior")
HB_STR("copyright")
HB_STR("Aacute")
HB_STR("Acircumflex")
HB_STR("Adieresis")
HB_STR("Agrave")
HB_STR("Aring")
HB_STR("Atilde")
HB_STR("Ccedilla")
HB_STR("Eacute")
HB_STR("Ecircumflex")
HB_STR("Edieresis")
HB_STR("Egrave")
HB_STR("Iacute")
HB_STR("Icircumflex")
HB_STR("Idieresis")
HB_STR("Igrave")
HB_STR("Ntilde")
HB_STR("Oacute")
HB_STR("Ocircumflex")
HB_STR("Odieresis")
HB_STR("Ograve")
HB_STR("Otilde")
HB_STR("Scaron")
HB_STR("Uacute")
HB_STR("Ucircumflex")
HB_STR("Udieresis")
HB_STR("Ugrave")
HB_STR("Yacute")
HB_STR("Ydieresis")
HB_STR("Zcaron")
HB_STR("aacute")
HB_STR("acircumflex")
HB_STR("adieresis")
HB_STR("agrave")
HB_STR("aring")
HB_STR("atilde")
HB_STR("ccedilla")
HB_STR("eacute")
HB_STR("ecircumflex")
HB_STR("edieresis")
HB_STR("egrave")
HB_STR("iacute")
HB_STR("icircumflex")
HB_STR("idieresis")
HB_STR("igrave")
HB_STR("ntilde")
HB_STR("oacute")
HB_STR("ocircumflex")
HB_STR("odieresis")
HB_STR("ograve")
HB_STR("otilde")
HB_STR("scaron")
HB_STR("uacute")
HB_STR("ucircumflex")
HB_STR("udieresis")
HB_STR("ugrave")
HB_STR("yacute")
HB_STR("ydieresis")
HB_STR("zcaron")
HB_STR("exclamsmall")
HB_STR("Hungarumlautsmall")
HB_STR("dollaroldstyle")
HB_STR("dollarsuperior")
HB_STR("ampersandsmall")
HB_STR("Acutesmall")
HB_STR("parenleftsuperior")
HB_STR("parenrightsuperior")
HB_STR("twodotenleader")
HB_STR("onedotenleader")
HB_STR("zerooldstyle")
HB_STR("oneoldstyle")
HB_STR("twooldstyle")
HB_STR("threeoldstyle")
HB_STR("fouroldstyle")
HB_STR("fiveoldstyle")
HB_STR("sixoldstyle")
HB_STR("sevenoldstyle")
HB_STR("eightoldstyle")
HB_STR("nineoldstyle")
HB_STR("commasuperior")
HB_STR("threequartersemdash")
HB_STR("periodsuperior")
HB_STR("questionsmall")
HB_STR("asuperior")
HB_STR("bsuperior")
HB_STR("centsuperior")
HB_STR("dsuperior")
HB_STR("esuperior")
HB_STR("isuperior")
HB_STR("lsuperior")
HB_STR("msuperior")
HB_STR("nsuperior")
HB_STR("osuperior")
HB_STR("rsuperior")
HB_STR("ssuperior")
HB_STR("tsuperior")
HB_STR("ff")
HB_STR("ffi")
HB_STR("ffl")
HB_STR("parenleftinferior")
HB_STR("parenrightinferior")
HB_STR("Circumflexsmall")
HB_STR("hyphensuperior")
HB_STR("Gravesmall")
HB_STR("Asmall")
HB_STR("Bsmall")
HB_STR("Csmall")
HB_STR("Dsmall")
HB_STR("Esmall")
HB_STR("Fsmall")
HB_STR("Gsmall")
HB_STR("Hsmall")
HB_STR("Ismall")
HB_STR("Jsmall")
HB_STR("Ksmall")
HB_STR("Lsmall")
HB_STR("Msmall")
HB_STR("Nsmall")
HB_STR("Osmall")
HB_STR("Psmall")
HB_STR("Qsmall")
HB_STR("Rsmall")
HB_STR("Ssmall")
HB_STR("Tsmall")
HB_STR("Usmall")
HB_STR("Vsmall")
HB_STR("Wsmall")
HB_STR("Xsmall")
HB_STR("Ysmall")
HB_STR("Zsmall")
HB_STR("colonmonetary")
HB_STR("onefitted")
HB_STR("rupiah")
HB_STR("Tildesmall")
HB_STR("exclamdownsmall")
HB_STR("centoldstyle")
HB_STR("Lslashsmall")
HB_STR("Scaronsmall")
HB_STR("Zcaronsmall")
HB_STR("Dieresissmall")
HB_STR("Brevesmall")
HB_STR("Caronsmall")
HB_STR("Dotaccentsmall")
HB_STR("Macronsmall")
HB_STR("figuredash")
HB_STR("hypheninferior")
HB_STR("Ogoneksmall")
HB_STR("Ringsmall")
HB_STR("Cedillasmall")
HB_STR("questiondownsmall")
HB_STR("oneeighth")
HB_STR("threeeighths")
HB_STR("fiveeighths")
HB_STR("seveneighths")
HB_STR("onethird")
HB_STR("twothirds")
HB_STR("zerosuperior")
HB_STR("foursuperior")
HB_STR("fivesuperior")
HB_STR("sixsuperior")
HB_STR("sevensuperior")
HB_STR("eightsuperior")
HB_STR("ninesuperior")
HB_STR("zeroinferior")
HB_STR("oneinferior")
HB_STR("twoinferior")
HB_STR("threeinferior")
HB_STR("fourinferior")
HB_STR("fiveinferior")
HB_STR("sixinferior")
HB_STR("seveninferior")
HB_STR("eightinferior")
HB_STR("nineinferior")
HB_STR("centinferior")
HB_STR("dollarinferior")
HB_STR("periodinferior")
HB_STR("commainferior")
HB_STR("Agravesmall")
HB_STR("Aacutesmall")
HB_STR("Acircumflexsmall")
HB_STR("Atildesmall")
HB_STR("Adieresissmall")
HB_STR("Aringsmall")
HB_STR("AEsmall")
HB_STR("Ccedillasmall")
HB_STR("Egravesmall")
HB_STR("Eacutesmall")
HB_STR("Ecircumflexsmall")
HB_STR("Edieresissmall")
HB_STR("Igravesmall")
HB_STR("Iacutesmall")
HB_STR("Icircumflexsmall")
HB_STR("Idieresissmall")
HB_STR("Ethsmall")
HB_STR("Ntildesmall")
HB_STR("Ogravesmall")
HB_STR("Oacutesmall")
HB_STR("Ocircumflexsmall")
HB_STR("Otildesmall")
HB_STR("Odieresissmall")
HB_STR("OEsmall")
HB_STR("Oslashsmall")
HB_STR("Ugravesmall")
HB_STR("Uacutesmall")
HB_STR("Ucircumflexsmall")
HB_STR("Udieresissmall")
HB_STR("Yacutesmall")
HB_STR("Thornsmall")
HB_STR("Ydieresissmall")
HB_STR("001.000")
HB_STR("001.001")
HB_STR("001.002")
HB_STR("001.003")
HB_STR("Black")
HB_STR("Bold")
HB_STR("Book")
HB_STR("Light")
HB_STR("Medium")
HB_STR("Regular")
HB_STR("Roman")
HB_STR("Semibold")
#endif /* HB_OT_CFF1_STD_STR_HH */

View file

@ -326,7 +326,7 @@ struct Charset0
void collect_glyph_to_sid_map (glyph_to_sid_map_t *mapping, unsigned int num_glyphs) const
{
mapping->resize (num_glyphs, false);
mapping->resize_dirty (num_glyphs);
for (hb_codepoint_t gid = 1; gid < num_glyphs; gid++)
mapping->arrayZ[gid] = {sids[gid - 1], gid};
}
@ -426,7 +426,7 @@ struct Charset1_2 {
void collect_glyph_to_sid_map (glyph_to_sid_map_t *mapping, unsigned int num_glyphs) const
{
mapping->resize (num_glyphs, false);
mapping->resize_dirty (num_glyphs);
hb_codepoint_t gid = 1;
if (gid >= num_glyphs)
return;

View file

@ -466,6 +466,11 @@ hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data,
{
const auto &glyf = *ot_face->glyf;
auto *scratch = glyf.acquire_scratch ();
if (unlikely (!scratch))
{
ot_font->h.release_advance_cache (advance_cache);
goto fallback;
}
OT::hb_scalar_cache_t *gvar_cache = ot_font->draw.acquire_gvar_cache (gvar);
for (unsigned int i = 0; i < count; i++)
@ -516,8 +521,7 @@ hb_ot_get_glyph_v_advances (hb_font_t* font, void* font_data,
{
hb_font_extents_t font_extents;
font->get_h_extents_with_fallback (&font_extents);
hb_position_t advance = font_extents.ascender - font_extents.descender;
advance = font->em_scale_y (- (int) advance);
hb_position_t advance = font_extents.descender - font_extents.ascender;
for (unsigned int i = 0; i < count; i++)
{
*first_advance = advance;
@ -587,6 +591,11 @@ hb_ot_get_glyph_v_advances (hb_font_t* font, void* font_data,
{
const auto &glyf = *ot_face->glyf;
auto *scratch = glyf.acquire_scratch ();
if (unlikely (!scratch))
{
ot_font->v.release_advance_cache (advance_cache);
goto fallback;
}
OT::hb_scalar_cache_t *gvar_cache = ot_font->draw.acquire_gvar_cache (gvar);
for (unsigned int i = 0; i < count; i++)
@ -665,7 +674,7 @@ hb_ot_get_glyph_v_origins (hb_font_t *font,
hb_position_t origin;
unsigned cv;
if (origin_cache->get (*first_glyph, &cv))
origin = font->y_scale < 0 ? -cv : cv;
origin = font->y_scale < 0 ? -static_cast<hb_position_t>(cv) : static_cast<hb_position_t>(cv);
else
{
origin = font->em_scalef_y (VORG.get_y_origin (*first_glyph));
@ -689,7 +698,7 @@ hb_ot_get_glyph_v_origins (hb_font_t *font,
hb_position_t origin;
unsigned cv;
if (origin_cache->get (*first_glyph, &cv))
origin = font->y_scale < 0 ? -cv : cv;
origin = font->y_scale < 0 ? -static_cast<hb_position_t>(cv) : static_cast<hb_position_t>(cv);
else
{
origin = font->em_scalef_y (VORG.get_y_origin (*first_glyph) +
@ -718,6 +727,11 @@ hb_ot_get_glyph_v_origins (hb_font_t *font,
if (origin_cache && vmtx.has_data() && glyf.has_data ())
{
auto *scratch = glyf.acquire_scratch ();
if (unlikely (!scratch))
{
ot_font->v_origin.release_origin_cache (origin_cache);
return false;
}
OT::hb_scalar_cache_t *gvar_cache = font->has_nonzero_coords ?
ot_font->draw.acquire_gvar_cache (*ot_face->gvar) :
nullptr;
@ -727,7 +741,7 @@ hb_ot_get_glyph_v_origins (hb_font_t *font,
hb_position_t origin;
unsigned cv;
if (origin_cache->get (*first_glyph, &cv))
origin = font->y_scale < 0 ? -cv : cv;
origin = font->y_scale < 0 ? -static_cast<hb_position_t>(cv) : static_cast<hb_position_t>(cv);
else
{
origin = font->em_scalef_y (glyf.get_v_origin_with_var_unscaled (*first_glyph, font, *scratch, gvar_cache));
@ -761,7 +775,7 @@ hb_ot_get_glyph_v_origins (hb_font_t *font,
unsigned cv;
if (origin_cache->get (*first_glyph, &cv))
origin = font->y_scale < 0 ? -cv : cv;
origin = font->y_scale < 0 ? -static_cast<hb_position_t>(cv) : static_cast<hb_position_t>(cv);
else
{
hb_glyph_extents_t extents = {0};

View file

@ -371,9 +371,9 @@ struct hmtxvmtx
hb_scalar_cache_t *store_cache = nullptr) const
{
unsigned int advance = get_advance_without_var_unscaled (glyph);
return advance + roundf (var_table->get_advance_delta_unscaled (glyph,
return hb_max(0.0f, advance + roundf (var_table->get_advance_delta_unscaled (glyph,
font->coords, font->num_coords,
store_cache));
store_cache)));
}
#endif

View file

@ -92,9 +92,10 @@ struct KernSubTableFormat3
{
set_t set;
if (likely (glyphCount))
set.add_range (0, glyphCount - 1);
left_set.union_ (set);
right_set.union_ (set);
{
left_set.add_range (0, num_glyphs - 1);
right_set.add_range (0, num_glyphs - 1);
}
}
protected:

View file

@ -141,6 +141,7 @@ struct hb_subset_layout_context_t :
const hb_map_t *lookup_index_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_map_w_duplicates;
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;
const hb_set_t *catch_all_record_feature_idxes;
@ -165,6 +166,7 @@ struct hb_subset_layout_context_t :
lookup_index_map = &c_->plan->gsub_lookups;
script_langsys_map = &c_->plan->gsub_langsys;
feature_index_map = &c_->plan->gsub_features;
feature_map_w_duplicates = &c_->plan->gsub_features_w_duplicates;
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;
catch_all_record_feature_idxes = &c_->plan->gsub_old_features;
@ -175,6 +177,7 @@ struct hb_subset_layout_context_t :
lookup_index_map = &c_->plan->gpos_lookups;
script_langsys_map = &c_->plan->gpos_langsys;
feature_index_map = &c_->plan->gpos_features;
feature_map_w_duplicates = &c_->plan->gpos_features_w_duplicates;
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;
catch_all_record_feature_idxes = &c_->plan->gpos_old_features;
@ -1082,15 +1085,15 @@ struct LangSys
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
const uint32_t *v;
out->reqFeatureIndex = l->feature_index_map->has (reqFeatureIndex, &v) ? *v : 0xFFFFu;
out->reqFeatureIndex = l->feature_map_w_duplicates->has (reqFeatureIndex, &v) ? *v : 0xFFFFu;
if (!l->visitFeatureIndex (featureIndex.len))
return_trace (false);
auto it =
+ hb_iter (featureIndex)
| hb_filter (l->feature_index_map)
| hb_map (l->feature_index_map)
| hb_filter (l->feature_map_w_duplicates)
| hb_map (l->feature_map_w_duplicates)
;
bool ret = bool (it);
@ -1337,7 +1340,7 @@ struct Lookup
TRACE_DISPATCH (this, lookup_type);
unsigned int count = get_subtable_count ();
for (unsigned int i = 0; i < count; i++) {
typename context_t::return_t r = get_subtable<TSubTable> (i).dispatch (c, lookup_type, std::forward<Ts> (ds)...);
typename context_t::return_t r = get_subtable<TSubTable> (i).dispatch (c, lookup_type, ds...);
if (c->stop_sublookup_iteration (r))
return_trace (r);
}
@ -1387,6 +1390,11 @@ struct Lookup
{
unsigned new_flag = lookupFlag;
new_flag &= ~LookupFlag::UseMarkFilteringSet;
// https://github.com/harfbuzz/harfbuzz/issues/5499
// If we remove UseMarkFilteringSet flag because the set is now empty,
// we need to add IgnoreMarks flag, otherwise the lookup will not
// ignore any marks, which changes the behavior.
new_flag |= LookupFlag::IgnoreMarks;
out->lookupFlag = new_flag;
}
else
@ -2078,7 +2086,7 @@ struct ClassDef
}
}
unsigned int get_class (hb_codepoint_t glyph_id,
hb_ot_lookup_cache_t *cache) const
hb_ot_layout_mapping_cache_t *cache) const
{
unsigned klass;
if (cache && cache->get (glyph_id, &klass)) return klass;
@ -2326,151 +2334,177 @@ struct delta_row_encoding_t
{
/* each byte represents a region, value is one of 0/1/2/4, which means bytes
* needed for this region */
hb_vector_t<uint8_t> chars;
struct chars_t : hb_vector_t<uint8_t>
{
int cmp (const chars_t& other) const
{
return as_array ().cmp (other.as_array ());
}
hb_pair_t<unsigned, unsigned> get_width ()
{
unsigned width = 0;
unsigned columns = 0;
for (unsigned i = 0; i < length; i++)
{
unsigned v = arrayZ[i];
width += v;
columns += (v != 0);
}
return hb_pair (width, columns);
}
HB_HOT
hb_pair_t<unsigned, unsigned> combine_width (const chars_t& other) const
{
unsigned combined_width = 0;
unsigned combined_columns = 0;
for (unsigned i = 0; i < length; i++)
{
unsigned v = hb_max (arrayZ[i], other.arrayZ[i]);
combined_width += v;
combined_columns += (v != 0);
}
return hb_pair (combined_width, combined_columns);
}
};
hb_pair_t<unsigned, unsigned> combine_width (const delta_row_encoding_t& other_encoding) const { return chars.combine_width (other_encoding.chars); }
// Actual data
chars_t chars;
unsigned width = 0;
hb_vector_t<uint8_t> columns;
unsigned overhead = 0;
hb_vector_t<const hb_vector_t<int>*> items;
delta_row_encoding_t () = default;
delta_row_encoding_t (hb_vector_t<uint8_t>&& chars_,
const hb_vector_t<int>* row = nullptr) :
delta_row_encoding_t ()
delta_row_encoding_t (hb_vector_t<const hb_vector_t<int>*> &&rows, unsigned num_cols)
{
chars = std::move (chars_);
width = get_width ();
columns = get_columns ();
overhead = get_chars_overhead (columns);
if (row) items.push (row);
assert (rows);
items = std::move (rows);
if (unlikely (!chars.resize (num_cols)))
return;
calculate_chars ();
}
void merge (const delta_row_encoding_t& other)
{
items.alloc (items.length + other.items.length);
for (auto &row : other.items)
add_row (row);
// Merge chars
assert (chars.length == other.chars.length);
for (unsigned i = 0; i < chars.length; i++)
chars.arrayZ[i] = hb_max (chars.arrayZ[i], other.chars.arrayZ[i]);
chars_changed ();
}
void chars_changed ()
{
auto _ = chars.get_width ();
width = _.first;
overhead = get_chars_overhead (_.second);
}
void calculate_chars ()
{
assert (items);
bool long_words = false;
for (auto &row : items)
{
assert (row->length == chars.length);
/* 0/1/2 byte encoding */
for (unsigned i = 0; i < row->length; i++)
{
int v = row->arrayZ[i];
if (v == 0)
continue;
else if (v > 32767 || v < -32768)
{
long_words = true;
chars.arrayZ[i] = hb_max (chars.arrayZ[i], 4);
}
else if (v > 127 || v < -128)
chars.arrayZ[i] = hb_max (chars.arrayZ[i], 2);
else
chars.arrayZ[i] = hb_max (chars.arrayZ[i], 1);
}
}
if (long_words)
{
// Convert 1s to 2s
for (auto &v : chars)
if (v == 1)
v = 2;
}
chars_changed ();
}
bool is_empty () const
{ return !items; }
static hb_vector_t<uint8_t> get_row_chars (const hb_vector_t<int>& row)
{
hb_vector_t<uint8_t> ret;
if (!ret.alloc (row.length)) return ret;
bool long_words = false;
/* 0/1/2 byte encoding */
for (int i = row.length - 1; i >= 0; i--)
{
int v = row.arrayZ[i];
if (v == 0)
ret.push (0);
else if (v > 32767 || v < -32768)
{
long_words = true;
break;
}
else if (v > 127 || v < -128)
ret.push (2);
else
ret.push (1);
}
if (!long_words)
return ret;
/* redo, 0/2/4 bytes encoding */
ret.reset ();
for (int i = row.length - 1; i >= 0; i--)
{
int v = row.arrayZ[i];
if (v == 0)
ret.push (0);
else if (v > 32767 || v < -32768)
ret.push (4);
else
ret.push (2);
}
return ret;
}
inline unsigned get_width ()
{
unsigned ret = + hb_iter (chars)
| hb_reduce (hb_add, 0u)
;
return ret;
}
hb_vector_t<uint8_t> get_columns ()
{
hb_vector_t<uint8_t> cols;
cols.alloc (chars.length);
for (auto v : chars)
{
uint8_t flag = v ? 1 : 0;
cols.push (flag);
}
return cols;
}
static inline unsigned get_chars_overhead (const hb_vector_t<uint8_t>& cols)
static inline unsigned get_chars_overhead (unsigned num_columns)
{
unsigned c = 4 + 6; // 4 bytes for LOffset, 6 bytes for VarData header
unsigned cols_bit_count = 0;
for (auto v : cols)
if (v) cols_bit_count++;
return c + cols_bit_count * 2;
return c + num_columns * 2;
}
unsigned get_gain () const
unsigned get_gain (unsigned additional_bytes_per_rows = 1) const
{
int count = items.length;
return hb_max (0, (int) overhead - count);
return hb_max (0, (int) overhead - count * (int) additional_bytes_per_rows);
}
int gain_from_merging (const delta_row_encoding_t& other_encoding) const
{
int combined_width = 0;
for (unsigned i = 0; i < chars.length; i++)
combined_width += hb_max (chars.arrayZ[i], other_encoding.chars.arrayZ[i]);
// Back of the envelope calculations to reject early.
signed additional_bytes_per_rows = other_encoding.width - width;
if (additional_bytes_per_rows > 0)
{
if (get_gain (additional_bytes_per_rows) == 0)
return 0;
}
else
{
if (other_encoding.get_gain (-additional_bytes_per_rows) == 0)
return 0;
}
hb_vector_t<uint8_t> combined_columns;
combined_columns.alloc (columns.length);
for (unsigned i = 0; i < columns.length; i++)
combined_columns.push (columns.arrayZ[i] | other_encoding.columns.arrayZ[i]);
auto pair = combine_width (other_encoding);
unsigned combined_width = pair.first;
unsigned combined_columns = pair.second;
int combined_overhead = get_chars_overhead (combined_columns);
int combined_gain = (int) overhead + (int) other_encoding.overhead - combined_overhead
- (combined_width - (int) width) * items.length
- (combined_width - (int) other_encoding.width) * other_encoding.items.length;
int combined_gain = (int) overhead + (int) other_encoding.overhead;
combined_gain -= (combined_width - (int) width) * items.length;
combined_gain -= (combined_width - (int) other_encoding.width) * other_encoding.items.length;
combined_gain -= get_chars_overhead (combined_columns);
return combined_gain;
}
bool add_row (const hb_vector_t<int>* row)
{ return items.push (row); }
static int cmp (const void *pa, const void *pb)
{
const delta_row_encoding_t *a = (const delta_row_encoding_t *)pa;
const delta_row_encoding_t *b = (const delta_row_encoding_t *)pb;
int gain_a = a->get_gain ();
int gain_b = b->get_gain ();
if (gain_a != gain_b)
return gain_a - gain_b;
return (b->chars).as_array ().cmp ((a->chars).as_array ());
}
static int cmp_width (const void *pa, const void *pb)
{
const delta_row_encoding_t *a = (const delta_row_encoding_t *)pa;
const delta_row_encoding_t *b = (const delta_row_encoding_t *)pb;
if (a->width != b->width)
return (int) a->width - (int) b->width;
return (b->chars).as_array ().cmp ((a->chars).as_array ());
return b->chars.cmp (a->chars);
}
bool add_row (const hb_vector_t<int>* row)
{ return items.push (row); }
};
struct VarRegionAxis
@ -2575,7 +2609,7 @@ struct hb_scalar_cache_t
return scratch_cache;
}
auto *cache = (hb_scalar_cache_t *) hb_malloc (sizeof (hb_scalar_cache_t) - sizeof (values) + sizeof (values[0]) * count);
auto *cache = (hb_scalar_cache_t *) hb_malloc (sizeof (hb_scalar_cache_t) - sizeof (static_values) + sizeof (static_values[0]) * count);
if (unlikely (!cache)) return (hb_scalar_cache_t *) &Null(hb_scalar_cache_t);
cache->length = count;
@ -2593,6 +2627,7 @@ struct hb_scalar_cache_t
void clear ()
{
auto *values = &static_values[0];
for (unsigned i = 0; i < length; i++)
values[i] = INVALID;
}
@ -2605,6 +2640,7 @@ struct hb_scalar_cache_t
*value = 0.f;
return true;
}
auto *values = &static_values[0];
auto *cached_value = &values[i];
if (*cached_value != INVALID)
{
@ -2618,13 +2654,14 @@ struct hb_scalar_cache_t
void set (unsigned i, float value)
{
if (unlikely (i >= length)) return;
auto *values = &static_values[0];
auto *cached_value = &values[i];
*cached_value = roundf(value * MULTIPLIER);
}
private:
unsigned length;
mutable hb_atomic_t<int> values[STATIC_LENGTH];
mutable hb_atomic_t<int> static_values[STATIC_LENGTH];
};
struct VarRegionList
@ -3439,7 +3476,7 @@ struct ItemVariationStore
for (unsigned i = 0; i < count; i++)
{
hb_inc_bimap_t *map = inner_maps.push ();
if (!c->propagate_error(inner_maps))
if (unlikely (!c->propagate_error(inner_maps)))
return_trace(nullptr);
auto &data = this+dataSets[i];
@ -4425,7 +4462,7 @@ struct FeatureTableSubstitutionRecord
if (unlikely (!s->extend_min (this))) return_trace (false);
uint32_t *new_feature_idx;
if (!c->feature_index_map->has (feature_index, &new_feature_idx))
if (!c->feature_map_w_duplicates->has (feature_index, &new_feature_idx))
return_trace (false);
if (!s->check_assign (featureIndex, *new_feature_idx, HB_SERIALIZE_ERROR_INT_OVERFLOW))
@ -4443,7 +4480,7 @@ struct FeatureTableSubstitutionRecord
{
TRACE_SUBSET (this);
uint32_t *new_feature_index;
if (!c->feature_index_map->has (featureIndex, &new_feature_index))
if (!c->feature_map_w_duplicates->has (featureIndex, &new_feature_index))
return_trace (false);
auto *out = c->subset_context->serializer->embed (this);
@ -4717,7 +4754,7 @@ struct FeatureVariations
int keep_up_to = -1;
for (int i = varRecords.len - 1; i >= 0; i--) {
if (varRecords[i].intersects_features (this, l->feature_index_map)) {
if (varRecords[i].intersects_features (this, l->feature_map_w_duplicates)) {
keep_up_to = i;
break;
}

View file

@ -63,12 +63,20 @@ inline bool PosLookup::dispatch_recurse_func<hb_ot_apply_context_t> (hb_ot_apply
c->set_lookup_index (lookup_index);
c->set_lookup_props (l.get_props ());
uint32_t stack_match_positions[8];
hb_vector_t<uint32_t> saved_match_positions;
saved_match_positions.set_storage (stack_match_positions);
hb_swap (c->match_positions, saved_match_positions);
bool ret = false;
auto *accel = gpos->get_accel (lookup_index);
ret = accel && accel->apply (c, l.get_subtable_count (), false);
ret = accel && accel->apply (c, false);
c->set_lookup_index (saved_lookup_index);
c->set_lookup_props (saved_lookup_props);
hb_swap (c->match_positions, saved_match_positions);
return ret;
}
#endif

View file

@ -76,12 +76,20 @@ inline bool SubstLookup::dispatch_recurse_func<hb_ot_apply_context_t> (hb_ot_app
c->set_lookup_index (lookup_index);
c->set_lookup_props (l.get_props ());
uint32_t stack_match_positions[8];
hb_vector_t<uint32_t> saved_match_positions;
saved_match_positions.set_storage (stack_match_positions);
hb_swap (c->match_positions, saved_match_positions);
bool ret = false;
auto *accel = gsub->get_accel (lookup_index);
ret = accel && accel->apply (c, l.get_subtable_count (), false);
ret = accel && accel->apply (c, false);
c->set_lookup_index (saved_lookup_index);
c->set_lookup_props (saved_lookup_props);
hb_swap (c->match_positions, saved_match_positions);
return ret;
}
#endif

View file

@ -455,7 +455,7 @@ struct matcher_t
HB_ALWAYS_INLINE
#endif
may_skip_t may_skip (const context_t *c,
const hb_glyph_info_t &info) const
const hb_glyph_info_t &info) const
{
if (!c->check_glyph_property (&info, lookup_props))
return SKIP_YES;
@ -670,15 +670,29 @@ struct hb_ot_apply_context_t :
{
const char *get_name () { return "APPLY"; }
typedef return_t (*recurse_func_t) (hb_ot_apply_context_t *c, unsigned int lookup_index);
template <typename T>
return_t dispatch (const T &obj) { return obj.apply (this); }
static inline auto apply_ (const T &obj, hb_ot_apply_context_t *c, hb_priority<1>) HB_RETURN (return_t, obj.apply (c, nullptr) )
template <typename T>
static inline auto apply_ (const T &obj, hb_ot_apply_context_t *c, hb_priority<0>) HB_RETURN (return_t, obj.apply (c) )
template <typename T>
return_t dispatch (const T &obj) { return apply_(obj, this, hb_prioritize); }
static return_t default_return_value () { return false; }
bool stop_sublookup_iteration (return_t r) const { return r; }
return_t recurse (unsigned int sub_lookup_index)
{
if (unlikely (nesting_level_left == 0 || !recurse_func || buffer->max_ops-- <= 0))
assert (recurse_func);
if (unlikely (nesting_level_left == 0))
{
buffer->shaping_failed = true;
buffer->successful = false;
return default_return_value ();
}
buffer->max_ops--;
if (unlikely (buffer->max_ops < 0))
{
buffer->successful = false;
return default_return_value ();
}
@ -701,7 +715,6 @@ struct hb_ot_apply_context_t :
const hb_ot_layout_lookup_accelerator_t *lookup_accel = nullptr;
const ItemVariationStore &var_store;
hb_scalar_cache_t *var_store_cache;
hb_set_digest_t digest;
hb_direction_t direction;
hb_mask_t lookup_mask = 1;
@ -719,6 +732,9 @@ struct hb_ot_apply_context_t :
signed last_base = -1; // GPOS uses
unsigned last_base_until = 0; // GPOS uses
hb_vector_t<uint32_t> match_positions;
uint32_t stack_match_positions[8];
hb_ot_apply_context_t (unsigned int table_index_,
hb_font_t *font_,
hb_buffer_t *buffer_,
@ -747,7 +763,7 @@ struct hb_ot_apply_context_t :
has_glyph_classes (gdef.has_glyph_classes ())
{
init_iters ();
buffer->collect_codepoints (digest);
match_positions.set_storage (stack_match_positions);
}
void init_iters ()
@ -772,7 +788,9 @@ struct hb_ot_apply_context_t :
return buffer->random_state;
}
bool match_properties_mark (hb_codepoint_t glyph,
HB_ALWAYS_INLINE
HB_HOT
bool match_properties_mark (const hb_glyph_info_t *info,
unsigned int glyph_props,
unsigned int match_props) const
{
@ -780,7 +798,7 @@ struct hb_ot_apply_context_t :
* match_props has the set index.
*/
if (match_props & LookupFlag::UseMarkFilteringSet)
return gdef_accel.mark_set_covers (match_props >> 16, glyph);
return gdef_accel.mark_set_covers (match_props >> 16, info->codepoint);
/* The second byte of match_props has the meaning
* "ignore marks of attachment type different than
@ -796,7 +814,7 @@ struct hb_ot_apply_context_t :
HB_ALWAYS_INLINE
#endif
bool check_glyph_property (const hb_glyph_info_t *info,
unsigned int match_props) const
unsigned match_props) const
{
unsigned int glyph_props = _hb_glyph_info_get_glyph_props (info);
@ -807,7 +825,7 @@ struct hb_ot_apply_context_t :
return false;
if (unlikely (glyph_props & HB_OT_LAYOUT_GLYPH_PROPS_MARK))
return match_properties_mark (info->codepoint, glyph_props, match_props);
return match_properties_mark (info, glyph_props, match_props);
return true;
}
@ -817,7 +835,7 @@ struct hb_ot_apply_context_t :
bool ligature = false,
bool component = false)
{
digest.add (glyph_index);
buffer->digest.add (glyph_index);
if (new_syllables != (unsigned) -1)
buffer->cur().syllable() = new_syllables;
@ -875,54 +893,58 @@ struct hb_ot_apply_context_t :
}
};
enum class hb_ot_lookup_cache_op_t
enum class hb_ot_subtable_cache_op_t
{
CREATE,
ENTER,
LEAVE,
DESTROY,
};
struct hb_accelerate_subtables_context_t :
hb_dispatch_context_t<hb_accelerate_subtables_context_t>
{
template <typename Type>
static inline bool apply_to (const void *obj, hb_ot_apply_context_t *c)
template <typename T>
static inline auto apply_ (const T *obj, hb_ot_apply_context_t *c, void *external_cache, hb_priority<1>) HB_RETURN (bool, obj->apply (c, external_cache) )
template <typename T>
static inline auto apply_ (const T *obj, hb_ot_apply_context_t *c, void *external_cache, hb_priority<0>) HB_RETURN (bool, obj->apply (c) )
template <typename T>
static inline bool apply_to (const void *obj, hb_ot_apply_context_t *c, void *external_cache)
{
const Type *typed_obj = (const Type *) obj;
return typed_obj->apply (c);
const T *typed_obj = (const T *) obj;
return apply_ (typed_obj, c, external_cache, hb_prioritize);
}
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
template <typename T>
static inline auto apply_cached_ (const T *obj, hb_ot_apply_context_t *c, hb_priority<1>) HB_RETURN (bool, obj->apply_cached (c) )
static inline auto apply_cached_ (const T *obj, hb_ot_apply_context_t *c, void *external_cache, hb_priority<2>) HB_RETURN (bool, obj->apply_cached (c, external_cache) )
template <typename T>
static inline auto apply_cached_ (const T *obj, hb_ot_apply_context_t *c, hb_priority<0>) HB_RETURN (bool, obj->apply (c) )
template <typename Type>
static inline bool apply_cached_to (const void *obj, hb_ot_apply_context_t *c)
static inline auto apply_cached_ (const T *obj, hb_ot_apply_context_t *c, void *external_cache, hb_priority<1>) HB_RETURN (bool, obj->apply (c, external_cache) )
template <typename T>
static inline auto apply_cached_ (const T *obj, hb_ot_apply_context_t *c, void *external_cache, hb_priority<0>) HB_RETURN (bool, obj->apply (c) )
template <typename T>
static inline bool apply_cached_to (const void *obj, hb_ot_apply_context_t *c, void *external_cache)
{
const Type *typed_obj = (const Type *) obj;
return apply_cached_ (typed_obj, c, hb_prioritize);
const T *typed_obj = (const T *) obj;
return apply_cached_ (typed_obj, c, external_cache, hb_prioritize);
}
template <typename T>
static inline auto cache_func_ (void *p,
hb_ot_lookup_cache_op_t op,
hb_priority<1>) HB_RETURN (void *, T::cache_func (p, op) )
static inline auto cache_func_ (hb_ot_apply_context_t *c,
hb_ot_subtable_cache_op_t op,
hb_priority<1>) HB_RETURN (bool, T::cache_func (c, op) )
template <typename T=void>
static inline void * cache_func_ (void *p,
hb_ot_lookup_cache_op_t op HB_UNUSED,
hb_priority<0>) { return (void *) false; }
static inline bool cache_func_ (hb_ot_apply_context_t *c,
hb_ot_subtable_cache_op_t op HB_UNUSED,
hb_priority<0>) { return false; }
template <typename Type>
static inline void * cache_func_to (void *p,
hb_ot_lookup_cache_op_t op)
static inline bool cache_func_to (hb_ot_apply_context_t *c,
hb_ot_subtable_cache_op_t op)
{
return cache_func_<Type> (p, op, hb_prioritize);
return cache_func_<Type> (c, op, hb_prioritize);
}
#endif
typedef bool (*hb_apply_func_t) (const void *obj, hb_ot_apply_context_t *c);
typedef void * (*hb_cache_func_t) (void *p, hb_ot_lookup_cache_op_t op);
typedef bool (*hb_apply_func_t) (const void *obj, hb_ot_apply_context_t *c, void *external_cache);
typedef bool (*hb_cache_func_t) (hb_ot_apply_context_t *c, hb_ot_subtable_cache_op_t op);
struct hb_applicable_t
{
@ -935,6 +957,7 @@ struct hb_accelerate_subtables_context_t :
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
, hb_apply_func_t apply_cached_func_
, hb_cache_func_t cache_func_
, void *external_cache_
#endif
)
{
@ -943,27 +966,34 @@ struct hb_accelerate_subtables_context_t :
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
apply_cached_func = apply_cached_func_;
cache_func = cache_func_;
external_cache = external_cache_;
#endif
digest.init ();
obj_.get_coverage ().collect_coverage (&digest);
}
#ifdef HB_NO_OT_LAYOUT_LOOKUP_CACHE
bool apply (hb_ot_apply_context_t *c) const
{
return digest.may_have (c->buffer->cur().codepoint) && apply_func (obj, c);
return digest.may_have (c->buffer->cur().codepoint) && apply_func (obj, c, nullptr);
}
#else
bool apply (hb_ot_apply_context_t *c) const
{
return digest.may_have (c->buffer->cur().codepoint) && apply_func (obj, c, external_cache);
}
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
bool apply_cached (hb_ot_apply_context_t *c) const
{
return digest.may_have (c->buffer->cur().codepoint) && apply_cached_func (obj, c);
return digest.may_have (c->buffer->cur().codepoint) && apply_cached_func (obj, c, external_cache);
}
bool cache_enter (hb_ot_apply_context_t *c) const
{
return (bool) cache_func (c, hb_ot_lookup_cache_op_t::ENTER);
return cache_func (c, hb_ot_subtable_cache_op_t::ENTER);
}
void cache_leave (hb_ot_apply_context_t *c) const
{
cache_func (c, hb_ot_lookup_cache_op_t::LEAVE);
cache_func (c, hb_ot_subtable_cache_op_t::LEAVE);
}
#endif
@ -973,6 +1003,7 @@ struct hb_accelerate_subtables_context_t :
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
hb_apply_func_t apply_cached_func;
hb_cache_func_t cache_func;
void *external_cache;
#endif
hb_set_digest_t digest;
};
@ -982,12 +1013,23 @@ struct hb_accelerate_subtables_context_t :
auto cache_cost (const T &obj, hb_priority<1>) HB_AUTO_RETURN ( obj.cache_cost () )
template <typename T>
auto cache_cost (const T &obj, hb_priority<0>) HB_AUTO_RETURN ( 0u )
template <typename T>
auto external_cache_create (const T &obj, hb_priority<1>) HB_AUTO_RETURN ( obj.external_cache_create () )
template <typename T>
auto external_cache_create (const T &obj, hb_priority<0>) HB_AUTO_RETURN ( nullptr )
#endif
/* Dispatch interface. */
template <typename T>
return_t dispatch (const T &obj)
{
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
void *external_cache = nullptr;
if (i < 8)
external_cache = external_cache_create (obj, hb_prioritize);
#endif
hb_applicable_t *entry = &array[i++];
entry->init (obj,
@ -995,6 +1037,7 @@ struct hb_accelerate_subtables_context_t :
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
, apply_cached_to<T>
, cache_func_to<T>
, external_cache
#endif
);
@ -1008,10 +1051,10 @@ struct hb_accelerate_subtables_context_t :
* and we allocate the cache opportunity to the costliest subtable.
*/
unsigned cost = cache_cost (obj, hb_prioritize);
if (cost > cache_user_cost)
if (cost > subtable_cache_user_cost)
{
cache_user_idx = i - 1;
cache_user_cost = cost;
subtable_cache_user_idx = i - 1;
subtable_cache_user_cost = cost;
}
#endif
@ -1026,8 +1069,8 @@ struct hb_accelerate_subtables_context_t :
unsigned i = 0;
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
unsigned cache_user_idx = (unsigned) -1;
unsigned cache_user_cost = 0;
unsigned subtable_cache_user_idx = (unsigned) -1;
unsigned subtable_cache_user_cost = 0;
#endif
};
@ -1176,38 +1219,50 @@ static inline bool match_class (hb_glyph_info_t &info, unsigned value, const voi
const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
return class_def.get_class (info.codepoint) == value;
}
static inline bool match_class_cached (hb_glyph_info_t &info, unsigned value, const void *data)
static inline unsigned get_class_cached (const ClassDef &class_def, hb_glyph_info_t &info)
{
unsigned klass = info.syllable();
if (klass < 255)
return klass == value;
const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
return klass;
klass = class_def.get_class (info.codepoint);
if (likely (klass < 255))
info.syllable() = klass;
return klass == value;
return klass;
}
static inline bool match_class_cached1 (hb_glyph_info_t &info, unsigned value, const void *data)
static inline bool match_class_cached (hb_glyph_info_t &info, unsigned value, const void *data)
{
const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
return get_class_cached (class_def, info) == value;
}
static inline unsigned get_class_cached1 (const ClassDef &class_def, hb_glyph_info_t &info)
{
unsigned klass = info.syllable() & 0x0F;
if (klass < 15)
return klass == value;
const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
return klass;
klass = class_def.get_class (info.codepoint);
if (likely (klass < 15))
info.syllable() = (info.syllable() & 0xF0) | klass;
return klass == value;
return klass;
}
static inline bool match_class_cached2 (hb_glyph_info_t &info, unsigned value, const void *data)
static inline bool match_class_cached1 (hb_glyph_info_t &info, unsigned value, const void *data)
{
const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
return get_class_cached1 (class_def, info) == value;
}
static inline unsigned get_class_cached2 (const ClassDef &class_def, hb_glyph_info_t &info)
{
unsigned klass = (info.syllable() & 0xF0) >> 4;
if (klass < 15)
return klass == value;
const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
return klass;
klass = class_def.get_class (info.codepoint);
if (likely (klass < 15))
info.syllable() = (info.syllable() & 0x0F) | (klass << 4);
return klass == value;
return klass;
}
static inline bool match_class_cached2 (hb_glyph_info_t &info, unsigned value, const void *data)
{
const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
return get_class_cached2 (class_def, info) == value;
}
static inline bool match_coverage (hb_glyph_info_t &info, unsigned value, const void *data)
{
@ -1246,7 +1301,6 @@ static bool match_input (hb_ot_apply_context_t *c,
match_func_t match_func,
const void *match_data,
unsigned int *end_position,
unsigned int *match_positions,
unsigned int *p_total_component_count = nullptr)
{
TRACE_APPLY (nullptr);
@ -1304,7 +1358,10 @@ static bool match_input (hb_ot_apply_context_t *c,
return_trace (false);
}
match_positions[i] = skippy_iter.idx;
if (unlikely (i + 1 > c->match_positions.length &&
!c->match_positions.resize_dirty (i + 1)))
return_trace (false);
c->match_positions.arrayZ[i] = skippy_iter.idx;
unsigned int this_lig_id = _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]);
unsigned int this_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]);
@ -1364,13 +1421,12 @@ static bool match_input (hb_ot_apply_context_t *c,
*p_total_component_count = total_component_count;
}
match_positions[0] = buffer->idx;
c->match_positions.arrayZ[0] = buffer->idx;
return_trace (true);
}
static inline bool ligate_input (hb_ot_apply_context_t *c,
unsigned int count, /* Including the first glyph */
const unsigned int *match_positions, /* Including the first glyph */
unsigned int match_end,
hb_codepoint_t lig_glyph,
unsigned int total_component_count)
@ -1413,10 +1469,10 @@ static inline bool ligate_input (hb_ot_apply_context_t *c,
* https://bugzilla.gnome.org/show_bug.cgi?id=437633
*/
bool is_base_ligature = _hb_glyph_info_is_base_glyph (&buffer->info[match_positions[0]]);
bool is_mark_ligature = _hb_glyph_info_is_mark (&buffer->info[match_positions[0]]);
bool is_base_ligature = _hb_glyph_info_is_base_glyph (&buffer->info[c->match_positions.arrayZ[0]]);
bool is_mark_ligature = _hb_glyph_info_is_mark (&buffer->info[c->match_positions.arrayZ[0]]);
for (unsigned int i = 1; i < count; i++)
if (!_hb_glyph_info_is_mark (&buffer->info[match_positions[i]]))
if (!_hb_glyph_info_is_mark (&buffer->info[c->match_positions.arrayZ[i]]))
{
is_base_ligature = false;
is_mark_ligature = false;
@ -1442,7 +1498,7 @@ static inline bool ligate_input (hb_ot_apply_context_t *c,
for (unsigned int i = 1; i < count; i++)
{
while (buffer->idx < match_positions[i] && buffer->successful)
while (buffer->idx < c->match_positions.arrayZ[i] && buffer->successful)
{
if (is_ligature)
{
@ -1681,7 +1737,6 @@ static inline void recurse_lookups (context_t *c,
static inline void apply_lookup (hb_ot_apply_context_t *c,
unsigned int count, /* Including the first glyph */
unsigned int *match_positions, /* Including the first glyph */
unsigned int lookupCount,
const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */
unsigned int match_end)
@ -1689,9 +1744,6 @@ static inline void apply_lookup (hb_ot_apply_context_t *c,
hb_buffer_t *buffer = c->buffer;
int end;
unsigned int *match_positions_input = match_positions;
unsigned int match_positions_count = count;
/* All positions are distance from beginning of *output* buffer.
* Adjust. */
{
@ -1701,7 +1753,7 @@ static inline void apply_lookup (hb_ot_apply_context_t *c,
int delta = bl - buffer->idx;
/* Convert positions to new indexing. */
for (unsigned int j = 0; j < count; j++)
match_positions[j] += delta;
c->match_positions.arrayZ[j] += delta;
}
for (unsigned int i = 0; i < lookupCount && buffer->successful; i++)
@ -1713,10 +1765,10 @@ static inline void apply_lookup (hb_ot_apply_context_t *c,
unsigned int orig_len = buffer->backtrack_len () + buffer->lookahead_len ();
/* This can happen if earlier recursed lookups deleted many entries. */
if (unlikely (match_positions[idx] >= orig_len))
if (unlikely (c->match_positions.arrayZ[idx] >= orig_len))
continue;
if (unlikely (!buffer->move_to (match_positions[idx])))
if (unlikely (!buffer->move_to (c->match_positions.arrayZ[idx])))
break;
if (unlikely (buffer->max_ops <= 0))
@ -1775,9 +1827,9 @@ static inline void apply_lookup (hb_ot_apply_context_t *c,
*/
end += delta;
if (end < int (match_positions[idx]))
if (end < int (c->match_positions.arrayZ[idx]))
{
/* End might end up being smaller than match_positions[idx] if the recursed
/* End might end up being smaller than match_positions.arrayZ[idx] if the recursed
* lookup ended up removing many items.
* Just never rewind end beyond start of current position, since that is
* not possible in the recursed lookup. Also adjust delta as such.
@ -1785,8 +1837,8 @@ static inline void apply_lookup (hb_ot_apply_context_t *c,
* https://bugs.chromium.org/p/chromium/issues/detail?id=659496
* https://github.com/harfbuzz/harfbuzz/issues/1611
*/
delta += match_positions[idx] - end;
end = match_positions[idx];
delta += c->match_positions.arrayZ[idx] - end;
end = c->match_positions.arrayZ[idx];
}
unsigned int next = idx + 1; /* next now is the position after the recursed lookup. */
@ -1795,27 +1847,9 @@ static inline void apply_lookup (hb_ot_apply_context_t *c,
{
if (unlikely (delta + count > HB_MAX_CONTEXT_LENGTH))
break;
if (unlikely (delta + count > match_positions_count))
{
unsigned new_match_positions_count = hb_max (delta + count, hb_max(match_positions_count, 4u) * 1.5);
if (match_positions == match_positions_input)
{
match_positions = (unsigned int *) hb_malloc (new_match_positions_count * sizeof (match_positions[0]));
if (unlikely (!match_positions))
break;
memcpy (match_positions, match_positions_input, count * sizeof (match_positions[0]));
match_positions_count = new_match_positions_count;
}
else
{
unsigned int *new_match_positions = (unsigned int *) hb_realloc (match_positions, new_match_positions_count * sizeof (match_positions[0]));
if (unlikely (!new_match_positions))
break;
match_positions = new_match_positions;
match_positions_count = new_match_positions_count;
}
}
if (unlikely (count + delta > c->match_positions.length &&
!c->match_positions.resize_dirty (count + delta)))
return;
}
else
{
@ -1825,23 +1859,20 @@ static inline void apply_lookup (hb_ot_apply_context_t *c,
}
/* Shift! */
memmove (match_positions + next + delta, match_positions + next,
(count - next) * sizeof (match_positions[0]));
memmove (c->match_positions + next + delta, c->match_positions + next,
(count - next) * sizeof (c->match_positions.arrayZ[0]));
next += delta;
count += delta;
/* Fill in new entries. */
for (unsigned int j = idx + 1; j < next; j++)
match_positions[j] = match_positions[j - 1] + 1;
c->match_positions.arrayZ[j] = c->match_positions.arrayZ[j - 1] + 1;
/* And fixup the rest. */
for (; next < count; next++)
match_positions[next] += delta;
c->match_positions.arrayZ[next] += delta;
}
if (match_positions != match_positions_input)
hb_free (match_positions);
assert (end >= 0);
(void) buffer->move_to (end);
}
@ -1944,25 +1975,17 @@ static bool context_apply_lookup (hb_ot_apply_context_t *c,
const ContextApplyLookupContext &lookup_context)
{
if (unlikely (inputCount > HB_MAX_CONTEXT_LENGTH)) return false;
unsigned match_positions_stack[4];
unsigned *match_positions = match_positions_stack;
if (unlikely (inputCount > ARRAY_LENGTH (match_positions_stack)))
{
match_positions = (unsigned *) hb_malloc (hb_max (inputCount, 1u) * sizeof (match_positions[0]));
if (unlikely (!match_positions))
return false;
}
unsigned match_end = 0;
bool ret = false;
if (match_input (c,
inputCount, input,
lookup_context.funcs.match, lookup_context.match_data,
&match_end, match_positions))
&match_end))
{
c->buffer->unsafe_to_break (c->buffer->idx, match_end);
apply_lookup (c,
inputCount, match_positions,
inputCount,
lookupCount, lookupRecord,
match_end);
ret = true;
@ -1973,12 +1996,34 @@ static bool context_apply_lookup (hb_ot_apply_context_t *c,
ret = false;
}
if (unlikely (match_positions != match_positions_stack))
hb_free (match_positions);
return ret;
}
static inline bool context_cache_func (hb_ot_apply_context_t *c, hb_ot_subtable_cache_op_t op)
{
switch (op)
{
case hb_ot_subtable_cache_op_t::ENTER:
{
if (!HB_BUFFER_TRY_ALLOCATE_VAR (c->buffer, syllable))
return false;
auto &info = c->buffer->info;
unsigned count = c->buffer->len;
for (unsigned i = 0; i < count; i++)
info[i].syllable() = 255;
c->new_syllables = 255;
return true;
}
case hb_ot_subtable_cache_op_t::LEAVE:
{
c->new_syllables = (unsigned) -1;
HB_BUFFER_DEALLOCATE_VAR (c->buffer, syllable);
break;
}
}
return false;
}
template <typename Types>
struct Rule
{
@ -2607,41 +2652,14 @@ struct ContextFormat2_5
unsigned cache_cost () const
{
unsigned c = (this+classDef).cost () * ruleSet.len;
return c >= 4 ? c : 0;
return (this+classDef).cost ();
}
static void * cache_func (void *p, hb_ot_lookup_cache_op_t op)
static bool cache_func (hb_ot_apply_context_t *c, hb_ot_subtable_cache_op_t op)
{
switch (op)
{
case hb_ot_lookup_cache_op_t::CREATE:
return (void *) true;
case hb_ot_lookup_cache_op_t::ENTER:
{
hb_ot_apply_context_t *c = (hb_ot_apply_context_t *) p;
if (!HB_BUFFER_TRY_ALLOCATE_VAR (c->buffer, syllable))
return (void *) false;
auto &info = c->buffer->info;
unsigned count = c->buffer->len;
for (unsigned i = 0; i < count; i++)
info[i].syllable() = 255;
c->new_syllables = 255;
return (void *) true;
}
case hb_ot_lookup_cache_op_t::LEAVE:
{
hb_ot_apply_context_t *c = (hb_ot_apply_context_t *) p;
c->new_syllables = (unsigned) -1;
HB_BUFFER_DEALLOCATE_VAR (c->buffer, syllable);
return nullptr;
}
case hb_ot_lookup_cache_op_t::DESTROY:
return nullptr;
}
return nullptr;
return context_cache_func (c, op);
}
bool apply_cached (hb_ot_apply_context_t *c) const { return _apply (c, true); }
bool apply_cached (hb_ot_apply_context_t *c, void *external_cache HB_UNUSED) const { return _apply (c, true); }
bool apply (hb_ot_apply_context_t *c) const { return _apply (c, false); }
bool _apply (hb_ot_apply_context_t *c, bool cached) const
{
@ -2656,10 +2674,7 @@ struct ContextFormat2_5
&class_def
};
if (cached && c->buffer->cur().syllable() < 255)
index = c->buffer->cur().syllable ();
else
index = class_def.get_class (c->buffer->cur().codepoint);
index = cached ? get_class_cached (class_def, c->buffer->cur()) : class_def.get_class (c->buffer->cur().codepoint);
const RuleSet &rule_set = this+ruleSet[index];
return_trace (rule_set.apply (c, lookup_context));
}
@ -3067,14 +3082,6 @@ static bool chain_context_apply_lookup (hb_ot_apply_context_t *c,
const ChainContextApplyLookupContext &lookup_context)
{
if (unlikely (inputCount > HB_MAX_CONTEXT_LENGTH)) return false;
unsigned match_positions_stack[4];
unsigned *match_positions = match_positions_stack;
if (unlikely (inputCount > ARRAY_LENGTH (match_positions_stack)))
{
match_positions = (unsigned *) hb_malloc (hb_max (inputCount, 1u) * sizeof (match_positions[0]));
if (unlikely (!match_positions))
return false;
}
unsigned start_index = c->buffer->out_len;
unsigned end_index = c->buffer->idx;
@ -3083,15 +3090,14 @@ static bool chain_context_apply_lookup (hb_ot_apply_context_t *c,
if (!(match_input (c,
inputCount, input,
lookup_context.funcs.match[1], lookup_context.match_data[1],
&match_end, match_positions) && (end_index = match_end)
&match_end) && (end_index = match_end)
&& match_lookahead (c,
lookaheadCount, lookahead,
lookup_context.funcs.match[2], lookup_context.match_data[2],
match_end, &end_index)))
{
c->buffer->unsafe_to_concat (c->buffer->idx, end_index);
ret = false;
goto done;
return false;
}
if (!match_backtrack (c,
@ -3100,19 +3106,14 @@ static bool chain_context_apply_lookup (hb_ot_apply_context_t *c,
&start_index))
{
c->buffer->unsafe_to_concat_from_outbuffer (start_index, end_index);
ret = false;
goto done;
return false;
}
c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index);
apply_lookup (c,
inputCount, match_positions,
inputCount,
lookupCount, lookupRecord,
match_end);
done:
if (unlikely (match_positions != match_positions_stack))
hb_free (match_positions);
return ret;
}
@ -3460,7 +3461,7 @@ struct ChainRuleSet
const auto &input = StructAfter<decltype (r.inputX)> (r.backtrack);
const auto &lookahead = StructAfter<decltype (r.lookaheadX)> (input);
unsigned lenP1 = hb_max ((unsigned) input.lenP1, 1u);
unsigned lenP1 = input.lenP1;
if (lenP1 > 1 ?
(!match_input ||
match_input (*first, input.arrayZ[0], input_data))
@ -3468,6 +3469,7 @@ struct ChainRuleSet
(!lookahead.len || !match_lookahead ||
match_lookahead (*first, lookahead.arrayZ[0], lookahead_data)))
{
lenP1 = hb_max (lenP1, 1u);
if (!second ||
(lenP1 > 2 ?
(!match_input ||
@ -3858,40 +3860,14 @@ struct ChainContextFormat2_5
unsigned cache_cost () const
{
return (this+lookaheadClassDef).cost () * ruleSet.len;
return (this+inputClassDef).cost () + (this+lookaheadClassDef).cost ();
}
static void * cache_func (void *p, hb_ot_lookup_cache_op_t op)
static bool cache_func (hb_ot_apply_context_t *c, hb_ot_subtable_cache_op_t op)
{
switch (op)
{
case hb_ot_lookup_cache_op_t::CREATE:
return (void *) true;
case hb_ot_lookup_cache_op_t::ENTER:
{
hb_ot_apply_context_t *c = (hb_ot_apply_context_t *) p;
if (!HB_BUFFER_TRY_ALLOCATE_VAR (c->buffer, syllable))
return (void *) false;
auto &info = c->buffer->info;
unsigned count = c->buffer->len;
for (unsigned i = 0; i < count; i++)
info[i].syllable() = 255;
c->new_syllables = 255;
return (void *) true;
}
case hb_ot_lookup_cache_op_t::LEAVE:
{
hb_ot_apply_context_t *c = (hb_ot_apply_context_t *) p;
c->new_syllables = (unsigned) -1;
HB_BUFFER_DEALLOCATE_VAR (c->buffer, syllable);
return nullptr;
}
case hb_ot_lookup_cache_op_t::DESTROY:
return nullptr;
}
return nullptr;
return context_cache_func (c, op);
}
bool apply_cached (hb_ot_apply_context_t *c) const { return _apply (c, true); }
bool apply_cached (hb_ot_apply_context_t *c, void *external_cache HB_UNUSED) const { return _apply (c, true); }
bool apply (hb_ot_apply_context_t *c) const { return _apply (c, false); }
bool _apply (hb_ot_apply_context_t *c, bool cached) const
{
@ -3914,11 +3890,9 @@ struct ChainContextFormat2_5
&lookahead_class_def}
};
// Note: Corresponds to match_class_cached2
if (cached && ((c->buffer->cur().syllable() & 0xF0) >> 4) < 15)
index = (c->buffer->cur().syllable () & 0xF0) >> 4;
else
index = input_class_def.get_class (c->buffer->cur().codepoint);
index = cached
? get_class_cached2 (input_class_def, c->buffer->cur())
: input_class_def.get_class (c->buffer->cur().codepoint);
const ChainRuleSet &rule_set = this+ruleSet[index];
return_trace (rule_set.apply (c, lookup_context));
}
@ -4413,22 +4387,14 @@ struct hb_ot_layout_lookup_accelerator_t
for (auto& subtable : hb_iter (thiz->subtables, count))
thiz->digest.union_ (subtable.digest);
thiz->count = count;
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
if (c_accelerate_subtables.cache_user_cost < 4)
c_accelerate_subtables.cache_user_idx = (unsigned) -1;
thiz->cache_user_idx = c_accelerate_subtables.cache_user_idx;
if (thiz->cache_user_idx != (unsigned) -1)
{
thiz->cache = thiz->subtables[thiz->cache_user_idx].cache_func (nullptr, hb_ot_lookup_cache_op_t::CREATE);
if (!thiz->cache)
thiz->cache_user_idx = (unsigned) -1;
}
thiz->subtable_cache_user_idx = c_accelerate_subtables.subtable_cache_user_idx;
for (unsigned i = 0; i < count; i++)
if (i != thiz->cache_user_idx)
thiz->subtables[i].apply_cached_func = thiz->subtables[i].apply_func;
if (i != thiz->subtable_cache_user_idx)
thiz->subtables[i].apply_cached_func = thiz->subtables[i].apply_func;
#endif
return thiz;
@ -4437,11 +4403,8 @@ struct hb_ot_layout_lookup_accelerator_t
void fini ()
{
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
if (cache)
{
assert (cache_user_idx != (unsigned) -1);
subtables[cache_user_idx].cache_func (cache, hb_ot_lookup_cache_op_t::DESTROY);
}
for (unsigned i = 0; i < count; i++)
hb_free (subtables[i].external_cache);
#endif
}
@ -4451,14 +4414,14 @@ struct hb_ot_layout_lookup_accelerator_t
#ifndef HB_OPTIMIZE_SIZE
HB_ALWAYS_INLINE
#endif
bool apply (hb_ot_apply_context_t *c, unsigned subtables_count, bool use_cache) const
bool apply (hb_ot_apply_context_t *c, bool use_cache) const
{
c->lookup_accel = this;
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
if (use_cache)
{
return
+ hb_iter (hb_iter (subtables, subtables_count))
+ hb_iter (hb_iter (subtables, count))
| hb_map ([&c] (const hb_accelerate_subtables_context_t::hb_applicable_t &_) { return _.apply_cached (c); })
| hb_any
;
@ -4467,7 +4430,7 @@ struct hb_ot_layout_lookup_accelerator_t
#endif
{
return
+ hb_iter (hb_iter (subtables, subtables_count))
+ hb_iter (hb_iter (subtables, count))
| hb_map ([&c] (const hb_accelerate_subtables_context_t::hb_applicable_t &_) { return _.apply (c); })
| hb_any
;
@ -4478,8 +4441,8 @@ struct hb_ot_layout_lookup_accelerator_t
bool cache_enter (hb_ot_apply_context_t *c) const
{
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
return cache_user_idx != (unsigned) -1 &&
subtables[cache_user_idx].cache_enter (c);
return subtable_cache_user_idx != (unsigned) -1 &&
subtables[subtable_cache_user_idx].cache_enter (c);
#else
return false;
#endif
@ -4487,19 +4450,17 @@ struct hb_ot_layout_lookup_accelerator_t
void cache_leave (hb_ot_apply_context_t *c) const
{
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
subtables[cache_user_idx].cache_leave (c);
subtables[subtable_cache_user_idx].cache_leave (c);
#endif
}
hb_set_digest_t digest;
private:
unsigned count = 0; /* Number of subtables in the array. */
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
public:
void *cache = nullptr;
private:
unsigned cache_user_idx = (unsigned) -1;
unsigned subtable_cache_user_idx = (unsigned) -1;
#endif
private:
hb_accelerate_subtables_context_t::hb_applicable_t subtables[HB_VAR_ARRAY];
};

View file

@ -1915,31 +1915,33 @@ struct GPOSProxy
static inline bool
apply_forward (OT::hb_ot_apply_context_t *c,
const OT::hb_ot_layout_lookup_accelerator_t &accel,
unsigned subtable_count)
const OT::hb_ot_layout_lookup_accelerator_t &accel)
{
bool use_cache = accel.cache_enter (c);
bool use_hot_subtable_cache = accel.cache_enter (c);
bool ret = false;
hb_buffer_t *buffer = c->buffer;
while (buffer->idx < buffer->len && buffer->successful)
while (buffer->successful)
{
bool applied = false;
auto &cur = buffer->cur();
if (accel.digest.may_have (cur.codepoint) &&
(cur.mask & c->lookup_mask) &&
c->check_glyph_property (&cur, c->lookup_props))
{
applied = accel.apply (c, subtable_count, use_cache);
}
hb_glyph_info_t *info = buffer->info;
unsigned j = buffer->idx;
while (j < buffer->len &&
!(accel.digest.may_have (info[j].codepoint) &&
(info[j].mask & c->lookup_mask) &&
c->check_glyph_property (&info[j], c->lookup_props)))
j++;
if (unlikely (j > buffer->idx && !buffer->next_glyphs (j - buffer->idx)))
break;
if (buffer->idx >= buffer->len)
break;
if (applied)
if (accel.apply (c, use_hot_subtable_cache))
ret = true;
else
(void) buffer->next_glyph ();
}
if (use_cache)
if (use_hot_subtable_cache)
accel.cache_leave (c);
return ret;
@ -1947,8 +1949,7 @@ apply_forward (OT::hb_ot_apply_context_t *c,
static inline bool
apply_backward (OT::hb_ot_apply_context_t *c,
const OT::hb_ot_layout_lookup_accelerator_t &accel,
unsigned subtable_count)
const OT::hb_ot_layout_lookup_accelerator_t &accel)
{
bool ret = false;
hb_buffer_t *buffer = c->buffer;
@ -1958,11 +1959,10 @@ apply_backward (OT::hb_ot_apply_context_t *c,
if (accel.digest.may_have (cur.codepoint) &&
(cur.mask & c->lookup_mask) &&
c->check_glyph_property (&cur, c->lookup_props))
ret |= accel.apply (c, subtable_count, false);
ret |= accel.apply (c, false);
/* The reverse lookup doesn't "advance" cursor (for good reason). */
buffer->idx--;
}
while ((int) buffer->idx >= 0);
return ret;
@ -1975,7 +1975,6 @@ apply_string (OT::hb_ot_apply_context_t *c,
const OT::hb_ot_layout_lookup_accelerator_t &accel)
{
hb_buffer_t *buffer = c->buffer;
unsigned subtable_count = lookup.get_subtable_count ();
if (unlikely (!buffer->len || !c->lookup_mask))
return false;
@ -1991,7 +1990,7 @@ apply_string (OT::hb_ot_apply_context_t *c,
buffer->clear_output ();
buffer->idx = 0;
ret = apply_forward (c, accel, subtable_count);
ret = apply_forward (c, accel);
if (!Proxy::always_inplace)
buffer->sync ();
@ -2001,7 +2000,7 @@ apply_string (OT::hb_ot_apply_context_t *c,
/* in-place backward substitution/positioning */
assert (!buffer->have_output);
buffer->idx = buffer->len - 1;
ret = apply_backward (c, accel, subtable_count);
ret = apply_backward (c, accel);
}
return ret;
@ -2037,11 +2036,8 @@ inline void hb_ot_map_t::apply (const Proxy &proxy,
if (buffer->messaging () &&
!buffer->message (font, "start lookup %u feature '%c%c%c%c'", lookup_index, HB_UNTAG (lookup.feature_tag))) continue;
/* c.digest is a digest of all the current glyphs in the buffer
* (plus some past glyphs).
*
* Only try applying the lookup if there is any overlap. */
if (accel->digest.may_intersect (c.digest))
/* Only try applying the lookup if there is any overlap. */
if (accel->digest.may_intersect (buffer->digest))
{
c.set_lookup_index (lookup_index);
c.set_lookup_mask (lookup.mask, false);
@ -2067,7 +2063,7 @@ inline void hb_ot_map_t::apply (const Proxy &proxy,
if (stage->pause_func (plan, font, buffer))
{
/* Refresh working buffer digest since buffer changed. */
buffer->collect_codepoints (c.digest);
buffer->update_digest ();
}
}
}
@ -2601,6 +2597,7 @@ hb_ot_layout_get_baseline_with_fallback2 (hb_font_t *font,
#endif
#ifndef HB_NO_LAYOUT_RARELY_USED
struct hb_get_glyph_alternates_dispatch_t :
hb_dispatch_context_t<hb_get_glyph_alternates_dispatch_t, unsigned>
{
@ -2620,7 +2617,6 @@ struct hb_get_glyph_alternates_dispatch_t :
( _dispatch (obj, hb_prioritize, std::forward<Ts> (ds)...) )
};
#ifndef HB_NO_LAYOUT_RARELY_USED
/**
* hb_ot_layout_lookup_get_glyph_alternates:
* @face: a face.
@ -2654,6 +2650,64 @@ hb_ot_layout_lookup_get_glyph_alternates (hb_face_t *face,
return ret;
}
struct hb_collect_glyph_alternates_dispatch_t :
hb_dispatch_context_t<hb_collect_glyph_alternates_dispatch_t, bool>
{
static return_t default_return_value () { return false; }
bool stop_sublookup_iteration (return_t r) const { return false; }
private:
template <typename T, typename ...Ts> auto
_dispatch (const T &obj, hb_priority<1>, Ts&&... ds) HB_AUTO_RETURN
( (obj.collect_glyph_alternates (std::forward<Ts> (ds)...), true) )
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_collect_glyph_alternates:
* @face: a face.
* @lookup_index: index of the feature lookup to query.
* @alternate_count: (inout): mapping from glyph index to number of alternates for that glyph.
* @alternate_glyphs: (inout): mapping from encoded glyph index and alternate index, to alternate glyph ids.
*
* Collects alternates of glyphs from a given GSUB lookup index.
*
* For one-to-one GSUB glyph substitutions, this function collects the
* substituted glyph.
*
* For lookups that assign multiple alternates to a glyph, all alternate glyphs are collected.
*
* For other lookup types, nothing is performed and `false` is returned.
*
* The `alternate_count` mapping will contain the number of alternates for each glyph id.
* Upon entry, this mapping should contain the glyph ids as keys, and the number of alternates
* currently known for each glyph id as values.
*
* The `alternate_glyphs` mapping will contain the alternate glyph ids for each glyph id.
* The mapping is encoded in the following way, upon entry and after processing:
* If G is the glyph id, and A0, A1, ..., A(n-1) are the alternate glyph ids,
* the mapping will contain the following entries: (G + (i << 24)) -> A(i)
* for i = 0, 1, ..., n-1 where n is the number of alternates for G as per `alternate_count`.
*
* Return value: `true` if alternates were collected, `false` otherwise.
* Since: 12.1.0
*/
HB_EXTERN hb_bool_t
hb_ot_layout_lookup_collect_glyph_alternates (hb_face_t *face,
unsigned lookup_index,
hb_map_t *alternate_count /* IN/OUT */,
hb_map_t *alternate_glyphs /* IN/OUT */)
{
hb_collect_glyph_alternates_dispatch_t c;
const OT::SubstLookup &lookup = face->table.GSUB->table->get_lookup (lookup_index);
return lookup.dispatch (&c, alternate_count, alternate_glyphs);
}
struct hb_position_single_dispatch_t :
hb_dispatch_context_t<hb_position_single_dispatch_t, bool>

View file

@ -383,6 +383,12 @@ hb_ot_layout_lookup_get_glyph_alternates (hb_face_t *face,
unsigned *alternate_count /* IN/OUT */,
hb_codepoint_t *alternate_glyphs /* OUT */);
HB_EXTERN hb_bool_t
hb_ot_layout_lookup_collect_glyph_alternates (hb_face_t *face,
unsigned lookup_index,
hb_map_t *alternate_count /* IN/OUT */,
hb_map_t *alternate_glyphs /* IN/OUT */);
HB_EXTERN hb_bool_t
hb_ot_layout_lookup_would_substitute (hb_face_t *face,
unsigned int lookup_index,

View file

@ -217,8 +217,6 @@ _hb_glyph_info_set_unicode_props (hb_glyph_info_t *info, hb_buffer_t *buffer)
if (u >= 0x80u)
{
buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII;
if (unlikely (unicode->is_default_ignorable (u)))
{
buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES;
@ -247,6 +245,7 @@ _hb_glyph_info_set_unicode_props (hb_glyph_info_t *info, hb_buffer_t *buffer)
if (unlikely (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (gen_cat)))
{
buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_CONTINUATIONS;
props |= UPROPS_MASK_CONTINUATION;
props |= unicode->modified_combining_class (u)<<8;
}
@ -361,8 +360,9 @@ _hb_glyph_info_unhide (hb_glyph_info_t *info)
}
static inline void
_hb_glyph_info_set_continuation (hb_glyph_info_t *info)
_hb_glyph_info_set_continuation (hb_glyph_info_t *info, hb_buffer_t *buffer)
{
buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_CONTINUATIONS;
info->unicode_props() |= UPROPS_MASK_CONTINUATION;
}
static inline void
@ -410,18 +410,6 @@ _hb_glyph_info_is_zwj (const hb_glyph_info_t *info)
return _hb_glyph_info_is_unicode_format (info) && (info->unicode_props() & UPROPS_MASK_Cf_ZWJ);
}
static inline bool
_hb_glyph_info_is_joiner (const hb_glyph_info_t *info)
{
return _hb_glyph_info_is_unicode_format (info) && (info->unicode_props() & (UPROPS_MASK_Cf_ZWNJ|UPROPS_MASK_Cf_ZWJ));
}
static inline void
_hb_glyph_info_flip_joiners (hb_glyph_info_t *info)
{
if (!_hb_glyph_info_is_unicode_format (info))
return;
info->unicode_props() ^= UPROPS_MASK_Cf_ZWNJ | UPROPS_MASK_Cf_ZWJ;
}
static inline bool
_hb_glyph_info_is_aat_deleted (const hb_glyph_info_t *info)
{
return _hb_glyph_info_is_unicode_format (info) && (info->unicode_props() & UPROPS_MASK_Cf_AAT_DELETED);
@ -657,4 +645,18 @@ _hb_buffer_assert_gsubgpos_vars (hb_buffer_t *buffer)
#undef lig_props
#undef glyph_props
static inline void
_hb_collect_glyph_alternates_add (hb_codepoint_t from,
hb_codepoint_t to,
hb_map_t *alternate_count,
hb_map_t *alternate_glyphs)
{
hb_codepoint_t zero = 0;
hb_codepoint_t *i = &zero;
alternate_count->has (from, &i);
alternate_glyphs->set (from | (*i << 24), to);
alternate_count->set (from, *i + 1);
}
#endif /* HB_OT_LAYOUT_HH */

View file

@ -69,6 +69,8 @@ struct MathValueRecord
struct MathConstants
{
friend struct MATH;
MathConstants* copy (hb_serialize_context_t *c) const
{
TRACE_SERIALIZE (this);
@ -1109,8 +1111,8 @@ struct MATH
{
#ifndef HB_NO_MATH
switch HB_CODEPOINT_ENCODE3 (font->face->table.MATH.get_blob ()->length,
get_constant (HB_OT_MATH_CONSTANT_DISPLAY_OPERATOR_MIN_HEIGHT, font),
get_constant (HB_OT_MATH_CONSTANT_DELIMITED_SUB_FORMULA_MIN_HEIGHT, font))
(this+mathConstants).minHeight[1], // displayOperatorMinHeight
(this+mathConstants).minHeight[0]) // delimitedSubFormulaMinHeight
{
/* sha1sum:ab4a4fe054d23061f3c039493d6f665cfda2ecf5 cambria.ttc
* sha1sum:086855301bff644f9d8827b88491fcf73a6d4cb9 cambria.ttc

View file

@ -31,264 +31,264 @@
#endif
_S(".notdef")
_S(".null")
_S("nonmarkingreturn")
_S("space")
_S("exclam")
_S("quotedbl")
_S("numbersign")
_S("dollar")
_S("percent")
_S("ampersand")
_S("quotesingle")
_S("parenleft")
_S("parenright")
_S("asterisk")
_S("plus")
_S("comma")
_S("hyphen")
_S("period")
_S("slash")
_S("zero")
_S("one")
_S("two")
_S("three")
_S("four")
_S("five")
_S("six")
_S("seven")
_S("eight")
_S("nine")
_S("colon")
_S("semicolon")
_S("less")
_S("equal")
_S("greater")
_S("question")
_S("at")
_S("A")
_S("B")
_S("C")
_S("D")
_S("E")
_S("F")
_S("G")
_S("H")
_S("I")
_S("J")
_S("K")
_S("L")
_S("M")
_S("N")
_S("O")
_S("P")
_S("Q")
_S("R")
_S("S")
_S("T")
_S("U")
_S("V")
_S("W")
_S("X")
_S("Y")
_S("Z")
_S("bracketleft")
_S("backslash")
_S("bracketright")
_S("asciicircum")
_S("underscore")
_S("grave")
_S("a")
_S("b")
_S("c")
_S("d")
_S("e")
_S("f")
_S("g")
_S("h")
_S("i")
_S("j")
_S("k")
_S("l")
_S("m")
_S("n")
_S("o")
_S("p")
_S("q")
_S("r")
_S("s")
_S("t")
_S("u")
_S("v")
_S("w")
_S("x")
_S("y")
_S("z")
_S("braceleft")
_S("bar")
_S("braceright")
_S("asciitilde")
_S("Adieresis")
_S("Aring")
_S("Ccedilla")
_S("Eacute")
_S("Ntilde")
_S("Odieresis")
_S("Udieresis")
_S("aacute")
_S("agrave")
_S("acircumflex")
_S("adieresis")
_S("atilde")
_S("aring")
_S("ccedilla")
_S("eacute")
_S("egrave")
_S("ecircumflex")
_S("edieresis")
_S("iacute")
_S("igrave")
_S("icircumflex")
_S("idieresis")
_S("ntilde")
_S("oacute")
_S("ograve")
_S("ocircumflex")
_S("odieresis")
_S("otilde")
_S("uacute")
_S("ugrave")
_S("ucircumflex")
_S("udieresis")
_S("dagger")
_S("degree")
_S("cent")
_S("sterling")
_S("section")
_S("bullet")
_S("paragraph")
_S("germandbls")
_S("registered")
_S("copyright")
_S("trademark")
_S("acute")
_S("dieresis")
_S("notequal")
_S("AE")
_S("Oslash")
_S("infinity")
_S("plusminus")
_S("lessequal")
_S("greaterequal")
_S("yen")
_S("mu")
_S("partialdiff")
_S("summation")
_S("product")
_S("pi")
_S("integral")
_S("ordfeminine")
_S("ordmasculine")
_S("Omega")
_S("ae")
_S("oslash")
_S("questiondown")
_S("exclamdown")
_S("logicalnot")
_S("radical")
_S("florin")
_S("approxequal")
_S("Delta")
_S("guillemotleft")
_S("guillemotright")
_S("ellipsis")
_S("nonbreakingspace")
_S("Agrave")
_S("Atilde")
_S("Otilde")
_S("OE")
_S("oe")
_S("endash")
_S("emdash")
_S("quotedblleft")
_S("quotedblright")
_S("quoteleft")
_S("quoteright")
_S("divide")
_S("lozenge")
_S("ydieresis")
_S("Ydieresis")
_S("fraction")
_S("currency")
_S("guilsinglleft")
_S("guilsinglright")
_S("fi")
_S("fl")
_S("daggerdbl")
_S("periodcentered")
_S("quotesinglbase")
_S("quotedblbase")
_S("perthousand")
_S("Acircumflex")
_S("Ecircumflex")
_S("Aacute")
_S("Edieresis")
_S("Egrave")
_S("Iacute")
_S("Icircumflex")
_S("Idieresis")
_S("Igrave")
_S("Oacute")
_S("Ocircumflex")
_S("apple")
_S("Ograve")
_S("Uacute")
_S("Ucircumflex")
_S("Ugrave")
_S("dotlessi")
_S("circumflex")
_S("tilde")
_S("macron")
_S("breve")
_S("dotaccent")
_S("ring")
_S("cedilla")
_S("hungarumlaut")
_S("ogonek")
_S("caron")
_S("Lslash")
_S("lslash")
_S("Scaron")
_S("scaron")
_S("Zcaron")
_S("zcaron")
_S("brokenbar")
_S("Eth")
_S("eth")
_S("Yacute")
_S("yacute")
_S("Thorn")
_S("thorn")
_S("minus")
_S("multiply")
_S("onesuperior")
_S("twosuperior")
_S("threesuperior")
_S("onehalf")
_S("onequarter")
_S("threequarters")
_S("franc")
_S("Gbreve")
_S("gbreve")
_S("Idotaccent")
_S("Scedilla")
_S("scedilla")
_S("Cacute")
_S("cacute")
_S("Ccaron")
_S("ccaron")
_S("dcroat")
HB_STR(".notdef")
HB_STR(".null")
HB_STR("nonmarkingreturn")
HB_STR("space")
HB_STR("exclam")
HB_STR("quotedbl")
HB_STR("numbersign")
HB_STR("dollar")
HB_STR("percent")
HB_STR("ampersand")
HB_STR("quotesingle")
HB_STR("parenleft")
HB_STR("parenright")
HB_STR("asterisk")
HB_STR("plus")
HB_STR("comma")
HB_STR("hyphen")
HB_STR("period")
HB_STR("slash")
HB_STR("zero")
HB_STR("one")
HB_STR("two")
HB_STR("three")
HB_STR("four")
HB_STR("five")
HB_STR("six")
HB_STR("seven")
HB_STR("eight")
HB_STR("nine")
HB_STR("colon")
HB_STR("semicolon")
HB_STR("less")
HB_STR("equal")
HB_STR("greater")
HB_STR("question")
HB_STR("at")
HB_STR("A")
HB_STR("B")
HB_STR("C")
HB_STR("D")
HB_STR("E")
HB_STR("F")
HB_STR("G")
HB_STR("H")
HB_STR("I")
HB_STR("J")
HB_STR("K")
HB_STR("L")
HB_STR("M")
HB_STR("N")
HB_STR("O")
HB_STR("P")
HB_STR("Q")
HB_STR("R")
HB_STR("S")
HB_STR("T")
HB_STR("U")
HB_STR("V")
HB_STR("W")
HB_STR("X")
HB_STR("Y")
HB_STR("Z")
HB_STR("bracketleft")
HB_STR("backslash")
HB_STR("bracketright")
HB_STR("asciicircum")
HB_STR("underscore")
HB_STR("grave")
HB_STR("a")
HB_STR("b")
HB_STR("c")
HB_STR("d")
HB_STR("e")
HB_STR("f")
HB_STR("g")
HB_STR("h")
HB_STR("i")
HB_STR("j")
HB_STR("k")
HB_STR("l")
HB_STR("m")
HB_STR("n")
HB_STR("o")
HB_STR("p")
HB_STR("q")
HB_STR("r")
HB_STR("s")
HB_STR("t")
HB_STR("u")
HB_STR("v")
HB_STR("w")
HB_STR("x")
HB_STR("y")
HB_STR("z")
HB_STR("braceleft")
HB_STR("bar")
HB_STR("braceright")
HB_STR("asciitilde")
HB_STR("Adieresis")
HB_STR("Aring")
HB_STR("Ccedilla")
HB_STR("Eacute")
HB_STR("Ntilde")
HB_STR("Odieresis")
HB_STR("Udieresis")
HB_STR("aacute")
HB_STR("agrave")
HB_STR("acircumflex")
HB_STR("adieresis")
HB_STR("atilde")
HB_STR("aring")
HB_STR("ccedilla")
HB_STR("eacute")
HB_STR("egrave")
HB_STR("ecircumflex")
HB_STR("edieresis")
HB_STR("iacute")
HB_STR("igrave")
HB_STR("icircumflex")
HB_STR("idieresis")
HB_STR("ntilde")
HB_STR("oacute")
HB_STR("ograve")
HB_STR("ocircumflex")
HB_STR("odieresis")
HB_STR("otilde")
HB_STR("uacute")
HB_STR("ugrave")
HB_STR("ucircumflex")
HB_STR("udieresis")
HB_STR("dagger")
HB_STR("degree")
HB_STR("cent")
HB_STR("sterling")
HB_STR("section")
HB_STR("bullet")
HB_STR("paragraph")
HB_STR("germandbls")
HB_STR("registered")
HB_STR("copyright")
HB_STR("trademark")
HB_STR("acute")
HB_STR("dieresis")
HB_STR("notequal")
HB_STR("AE")
HB_STR("Oslash")
HB_STR("infinity")
HB_STR("plusminus")
HB_STR("lessequal")
HB_STR("greaterequal")
HB_STR("yen")
HB_STR("mu")
HB_STR("partialdiff")
HB_STR("summation")
HB_STR("product")
HB_STR("pi")
HB_STR("integral")
HB_STR("ordfeminine")
HB_STR("ordmasculine")
HB_STR("Omega")
HB_STR("ae")
HB_STR("oslash")
HB_STR("questiondown")
HB_STR("exclamdown")
HB_STR("logicalnot")
HB_STR("radical")
HB_STR("florin")
HB_STR("approxequal")
HB_STR("Delta")
HB_STR("guillemotleft")
HB_STR("guillemotright")
HB_STR("ellipsis")
HB_STR("nonbreakingspace")
HB_STR("Agrave")
HB_STR("Atilde")
HB_STR("Otilde")
HB_STR("OE")
HB_STR("oe")
HB_STR("endash")
HB_STR("emdash")
HB_STR("quotedblleft")
HB_STR("quotedblright")
HB_STR("quoteleft")
HB_STR("quoteright")
HB_STR("divide")
HB_STR("lozenge")
HB_STR("ydieresis")
HB_STR("Ydieresis")
HB_STR("fraction")
HB_STR("currency")
HB_STR("guilsinglleft")
HB_STR("guilsinglright")
HB_STR("fi")
HB_STR("fl")
HB_STR("daggerdbl")
HB_STR("periodcentered")
HB_STR("quotesinglbase")
HB_STR("quotedblbase")
HB_STR("perthousand")
HB_STR("Acircumflex")
HB_STR("Ecircumflex")
HB_STR("Aacute")
HB_STR("Edieresis")
HB_STR("Egrave")
HB_STR("Iacute")
HB_STR("Icircumflex")
HB_STR("Idieresis")
HB_STR("Igrave")
HB_STR("Oacute")
HB_STR("Ocircumflex")
HB_STR("apple")
HB_STR("Ograve")
HB_STR("Uacute")
HB_STR("Ucircumflex")
HB_STR("Ugrave")
HB_STR("dotlessi")
HB_STR("circumflex")
HB_STR("tilde")
HB_STR("macron")
HB_STR("breve")
HB_STR("dotaccent")
HB_STR("ring")
HB_STR("cedilla")
HB_STR("hungarumlaut")
HB_STR("ogonek")
HB_STR("caron")
HB_STR("Lslash")
HB_STR("lslash")
HB_STR("Scaron")
HB_STR("scaron")
HB_STR("Zcaron")
HB_STR("zcaron")
HB_STR("brokenbar")
HB_STR("Eth")
HB_STR("eth")
HB_STR("Yacute")
HB_STR("yacute")
HB_STR("Thorn")
HB_STR("thorn")
HB_STR("minus")
HB_STR("multiply")
HB_STR("onesuperior")
HB_STR("twosuperior")
HB_STR("threesuperior")
HB_STR("onehalf")
HB_STR("onequarter")
HB_STR("threequarters")
HB_STR("franc")
HB_STR("Gbreve")
HB_STR("gbreve")
HB_STR("Idotaccent")
HB_STR("Scedilla")
HB_STR("scedilla")
HB_STR("Cacute")
HB_STR("cacute")
HB_STR("Ccaron")
HB_STR("ccaron")
HB_STR("dcroat")
#endif /* HB_OT_POST_MACROMAN_HH */

View file

@ -409,16 +409,13 @@ position_around_base (const hb_ot_shape_plan_t *plan,
}
static inline void
position_cluster (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer,
unsigned int start,
unsigned int end,
bool adjust_offsets_when_zeroing)
position_cluster_impl (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer,
unsigned int start,
unsigned int end,
bool adjust_offsets_when_zeroing)
{
if (end - start < 2)
return;
/* Find the base glyph */
hb_glyph_info_t *info = buffer->info;
for (unsigned int i = start; i < end; i++)
@ -441,6 +438,20 @@ position_cluster (const hb_ot_shape_plan_t *plan,
}
}
static HB_ALWAYS_INLINE void
position_cluster (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer,
unsigned int start,
unsigned int end,
bool adjust_offsets_when_zeroing)
{
if (end - start < 2)
return;
position_cluster_impl (plan, font, buffer, start, end, adjust_offsets_when_zeroing);
}
void
_hb_ot_shape_fallback_mark_position (const hb_ot_shape_plan_t *plan,
hb_font_t *font,

View file

@ -78,14 +78,14 @@
static inline void
set_glyph (hb_glyph_info_t &info, hb_font_t *font)
{
(void) font->get_nominal_glyph (info.codepoint, &info.glyph_index());
(void) font->get_nominal_glyph (info.codepoint, &info.normalizer_glyph_index());
}
static inline void
output_char (hb_buffer_t *buffer, hb_codepoint_t unichar, hb_codepoint_t glyph)
{
/* This is very confusing indeed. */
buffer->cur().glyph_index() = glyph;
buffer->cur().normalizer_glyph_index() = glyph;
(void) buffer->output_glyph (unichar);
_hb_glyph_info_set_unicode_props (&buffer->prev(), buffer);
}
@ -93,7 +93,7 @@ output_char (hb_buffer_t *buffer, hb_codepoint_t unichar, hb_codepoint_t glyph)
static inline void
next_char (hb_buffer_t *buffer, hb_codepoint_t glyph)
{
buffer->cur().glyph_index() = glyph;
buffer->cur().normalizer_glyph_index() = glyph;
(void) buffer->next_glyph ();
}
@ -210,7 +210,7 @@ handle_variation_selector_cluster (const hb_ot_shape_normalize_context_t *c,
hb_font_t * const font = c->font;
for (; buffer->idx < end - 1 && buffer->successful;) {
if (unlikely (buffer->unicode->is_variation_selector (buffer->cur(+1).codepoint))) {
if (font->get_variation_glyph (buffer->cur().codepoint, buffer->cur(+1).codepoint, &buffer->cur().glyph_index()))
if (font->get_variation_glyph (buffer->cur().codepoint, buffer->cur(+1).codepoint, &buffer->cur().normalizer_glyph_index()))
{
hb_codepoint_t unicode = buffer->cur().codepoint;
(void) buffer->replace_glyphs (2, 1, &unicode);
@ -342,7 +342,7 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan,
unsigned int done = font->get_nominal_glyphs (end - buffer->idx,
&buffer->cur().codepoint,
sizeof (buffer->info[0]),
&buffer->cur().glyph_index(),
&buffer->cur().normalizer_glyph_index(),
sizeof (buffer->info[0]));
if (unlikely (!buffer->next_glyphs (done))) break;
}
@ -456,7 +456,7 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan,
buffer->out_len--; /* Remove the second composable. */
/* Modify starter and carry on. */
buffer->out_info[starter].codepoint = composed;
buffer->out_info[starter].glyph_index() = glyph;
buffer->out_info[starter].normalizer_glyph_index() = glyph;
_hb_glyph_info_set_unicode_props (&buffer->out_info[starter], buffer);
continue;

View file

@ -32,7 +32,7 @@
/* buffer var allocations, used during the normalization process */
#define glyph_index() var1.u32
#define normalizer_glyph_index() var1.u32
struct hb_ot_shape_plan_t;

View file

@ -484,6 +484,9 @@ hb_set_unicode_props (hb_buffer_t *buffer)
{
_hb_glyph_info_set_unicode_props (&info[i], buffer);
if (info[i].codepoint < 0x80)
continue;
unsigned gen_cat = _hb_glyph_info_get_general_category (&info[i]);
if (FLAG_UNSAFE (gen_cat) &
(FLAG (HB_UNICODE_GENERAL_CATEGORY_LOWERCASE_LETTER) |
@ -498,7 +501,7 @@ hb_set_unicode_props (hb_buffer_t *buffer)
if (unlikely (gen_cat == HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL &&
hb_in_range<hb_codepoint_t> (info[i].codepoint, 0x1F3FBu, 0x1F3FFu)))
{
_hb_glyph_info_set_continuation (&info[i]);
_hb_glyph_info_set_continuation (&info[i], buffer);
}
/* Regional_Indicators are hairy as hell...
* https://github.com/harfbuzz/harfbuzz/issues/2265 */
@ -506,18 +509,18 @@ hb_set_unicode_props (hb_buffer_t *buffer)
{
if (_hb_codepoint_is_regional_indicator (info[i - 1].codepoint) &&
!_hb_glyph_info_is_continuation (&info[i - 1]))
_hb_glyph_info_set_continuation (&info[i]);
_hb_glyph_info_set_continuation (&info[i], buffer);
}
#ifndef HB_NO_EMOJI_SEQUENCES
else if (unlikely (_hb_glyph_info_is_zwj (&info[i])))
{
_hb_glyph_info_set_continuation (&info[i]);
_hb_glyph_info_set_continuation (&info[i], buffer);
if (i + 1 < count &&
_hb_unicode_is_emoji_Extended_Pictographic (info[i + 1].codepoint))
{
i++;
_hb_glyph_info_set_unicode_props (&info[i], buffer);
_hb_glyph_info_set_continuation (&info[i]);
_hb_glyph_info_set_continuation (&info[i], buffer);
}
}
#endif
@ -536,7 +539,9 @@ hb_set_unicode_props (hb_buffer_t *buffer)
* https://github.com/harfbuzz/harfbuzz/issues/3844
*/
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], buffer);
else if (unlikely (info[i].codepoint == 0x2044u /* FRACTION SLASH */))
buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_FRACTION_SLASH;
}
}
@ -572,7 +577,7 @@ hb_insert_dotted_circle (hb_buffer_t *buffer, hb_font_t *font)
static void
hb_form_clusters (hb_buffer_t *buffer)
{
if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII))
if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_CONTINUATIONS))
return;
if (HB_BUFFER_CLUSTER_LEVEL_IS_GRAPHEMES (buffer->cluster_level))
@ -614,14 +619,14 @@ hb_ensure_native_direction (hb_buffer_t *buffer)
for (unsigned i = 0; i < count; i++)
{
auto gc = _hb_glyph_info_get_general_category (&info[i]);
if (gc == HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER)
found_number = true;
else if (HB_UNICODE_GENERAL_CATEGORY_IS_LETTER (gc))
if (HB_UNICODE_GENERAL_CATEGORY_IS_LETTER (gc))
{
found_letter = true;
break;
}
else if (_hb_codepoint_is_regional_indicator (info[i].codepoint))
else if (gc == HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER)
found_number = true;
else if (unlikely (_hb_codepoint_is_regional_indicator (info[i].codepoint)))
found_ri = true;
}
if ((found_number || found_ri) && !found_letter)
@ -687,7 +692,7 @@ hb_ot_shape_setup_masks_fraction (const hb_ot_shape_context_t *c)
return;
#endif
if (!(c->buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII) ||
if (!(c->buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_FRACTION_SLASH) ||
!c->plan->has_frac)
return;
@ -788,7 +793,13 @@ hb_ot_zero_width_default_ignorables (const hb_buffer_t *buffer)
unsigned int i = 0;
for (i = 0; i < count; i++)
if (unlikely (_hb_glyph_info_is_default_ignorable (&info[i])))
pos[i].x_advance = pos[i].y_advance = pos[i].x_offset = pos[i].y_offset = 0;
{
pos[i].x_advance = pos[i].y_advance = 0;
if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction))
pos[i].x_offset = 0;
else
pos[i].y_offset = 0;
}
}
static void
@ -843,11 +854,11 @@ hb_ot_hide_default_ignorables (hb_buffer_t *buffer,
static inline void
hb_ot_map_glyphs_fast (hb_buffer_t *buffer)
{
/* Normalization process sets up glyph_index(), we just copy it. */
/* Normalization process sets up normalizer_glyph_index(), we just copy it. */
unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
for (unsigned int i = 0; i < count; i++)
info[i].codepoint = info[i].glyph_index();
info[i].codepoint = info[i].normalizer_glyph_index();
buffer->content_type = HB_BUFFER_CONTENT_TYPE_GLYPHS;
}
@ -885,7 +896,7 @@ hb_ot_substitute_default (const hb_ot_shape_context_t *c)
hb_ot_rotate_chars (c);
HB_BUFFER_ALLOCATE_VAR (buffer, glyph_index);
HB_BUFFER_ALLOCATE_VAR (buffer, normalizer_glyph_index);
_hb_ot_shape_normalize (c->plan, buffer, c->font);
@ -897,7 +908,7 @@ hb_ot_substitute_default (const hb_ot_shape_context_t *c)
hb_ot_map_glyphs_fast (buffer);
HB_BUFFER_DEALLOCATE_VAR (buffer, glyph_index);
HB_BUFFER_DEALLOCATE_VAR (buffer, normalizer_glyph_index);
}
static inline void
@ -912,11 +923,17 @@ hb_ot_substitute_plan (const hb_ot_shape_context_t *c)
#ifndef HB_NO_AAT_SHAPE
if (unlikely (c->plan->apply_morx))
{
hb_aat_layout_substitute (c->plan, c->font, c->buffer,
c->user_features, c->num_user_features);
c->buffer->update_digest ();
}
else
#endif
{
c->buffer->update_digest ();
c->plan->substitute (c->font, buffer);
}
}
static inline void
@ -1098,8 +1115,33 @@ hb_propagate_flags (hb_buffer_t *buffer)
/* Propagate cluster-level glyph flags to be the same on all cluster glyphs.
* Simplifies using them. */
if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS))
hb_mask_t and_mask = HB_GLYPH_FLAG_DEFINED;
if ((buffer->flags & HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT) == 0)
and_mask &= ~HB_GLYPH_FLAG_UNSAFE_TO_CONCAT;
hb_glyph_info_t *info = buffer->info;
if ((buffer->flags & HB_BUFFER_FLAG_PRODUCE_SAFE_TO_INSERT_TATWEEL) == 0)
{
foreach_cluster (buffer, start, end)
{
if (end - start == 1)
{
info[start].mask &= and_mask;
continue;
}
unsigned int mask = 0;
for (unsigned int i = start; i < end; i++)
mask |= info[i].mask;
mask &= and_mask;
for (unsigned int i = start; i < end; i++)
info[i].mask = mask;
}
return;
}
/* If we are producing SAFE_TO_INSERT_TATWEEL, then do two things:
*
@ -1107,30 +1149,20 @@ hb_propagate_flags (hb_buffer_t *buffer)
* are UNSAFE_TO_BREAK, then clear the SAFE_TO_INSERT_TATWEEL,
* - Any place that is SAFE_TO_INSERT_TATWEEL, is also now UNSAFE_TO_BREAK.
*
* We couldn't make this interaction earlier. It has to be done here.
* We couldn't make this interaction earlier. It has to be done this way.
*/
bool flip_tatweel = buffer->flags & HB_BUFFER_FLAG_PRODUCE_SAFE_TO_INSERT_TATWEEL;
bool clear_concat = (buffer->flags & HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT) == 0;
hb_glyph_info_t *info = buffer->info;
foreach_cluster (buffer, start, end)
{
unsigned int mask = 0;
for (unsigned int i = start; i < end; i++)
mask |= info[i].mask & HB_GLYPH_FLAG_DEFINED;
mask |= info[i].mask;
if (flip_tatweel)
{
if (mask & HB_GLYPH_FLAG_UNSAFE_TO_BREAK)
mask &= ~HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL;
if (mask & HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL)
mask |= HB_GLYPH_FLAG_UNSAFE_TO_BREAK | HB_GLYPH_FLAG_UNSAFE_TO_CONCAT;
}
if (mask & HB_GLYPH_FLAG_UNSAFE_TO_BREAK)
mask &= ~HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL;
if (mask & HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL)
mask |= HB_GLYPH_FLAG_UNSAFE_TO_BREAK | HB_GLYPH_FLAG_UNSAFE_TO_CONCAT;
if (clear_concat)
mask &= ~HB_GLYPH_FLAG_UNSAFE_TO_CONCAT;
mask &= and_mask;
for (unsigned int i = start; i < end; i++)
info[i].mask = mask;
@ -1171,8 +1203,6 @@ hb_ot_shape_internal (hb_ot_shape_context_t *c)
_hb_buffer_deallocate_unicode_vars (c->buffer);
c->buffer->props.direction = c->target_direction;
c->buffer->leave ();
}

View file

@ -6,10 +6,10 @@
*
* on files with these headers:
*
* # ArabicShaping-16.0.0.txt
* # Date: 2024-07-30
* # Scripts-16.0.0.txt
* # Date: 2024-04-30, 21:48:40 GMT
* # ArabicShaping-17.0.0.txt
* # Date: 2025-08-14
* # Scripts-17.0.0.txt
* # Date: 2025-07-24, 13:28:55 GMT
*/
#ifndef HB_OT_SHAPER_ARABIC_JOINING_LIST_HH

View file

@ -6,10 +6,10 @@
*
* on files with these headers:
*
* # ArabicShaping-16.0.0.txt
* # Date: 2024-07-30
* # Blocks-16.0.0.txt
* # Date: 2024-02-02
* # ArabicShaping-17.0.0.txt
* # Date: 2025-08-14
* # Blocks-17.0.0.txt
* # Date: 2025-08-01
* UnicodeData.txt does not have a header.
*/
@ -80,7 +80,7 @@ static const uint8_t joining_table[] =
/* Arabic Extended-B */
/* 0860 */ R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,
/* 0880 */ R,R,R,C,C,C,D,U,U,D,D,D,D,D,R,X,U,U,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
/* 0880 */ R,R,R,C,C,C,D,U,U,D,D,D,D,D,R,D,U,U,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
/* Arabic Extended-A */
@ -140,9 +140,9 @@ static const uint8_t joining_table[] =
/* Arabic Extended-C */
/* 10EC0 */ R,D,D,
/* 10EC0 */ R,D,D,X,D,D,
#define joining_offset_0x10f30u 1185
#define joining_offset_0x10f30u 1188
/* Sogdian */
@ -161,14 +161,14 @@ static const uint8_t joining_table[] =
/* 10FA0 */ D,U,D,D,R,R,R,U,D,R,R,D,D,R,D,D,
/* 10FC0 */ U,D,R,R,D,U,U,U,U,R,D,L,
#define joining_offset_0x110bdu 1341
#define joining_offset_0x110bdu 1344
/* Kaithi */
/* 110A0 */ U,X,X,
/* 110C0 */ X,X,X,X,X,X,X,X,X,X,X,X,X,U,
#define joining_offset_0x1e900u 1358
#define joining_offset_0x1e900u 1361
/* Adlam */
@ -176,7 +176,7 @@ static const uint8_t joining_table[] =
/* 1E920 */ D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,
/* 1E940 */ D,D,D,D,X,X,X,X,X,X,X,T,
}; /* Table items: 1434; occupancy: 57% */
}; /* Table items: 1437; occupancy: 58% */
static unsigned int
@ -204,7 +204,7 @@ joining_type (hb_codepoint_t u)
if (hb_in_range<hb_codepoint_t> (u, 0x10AC0u, 0x10AEFu)) return joining_table[u - 0x10AC0u + joining_offset_0x10ac0u];
if (hb_in_range<hb_codepoint_t> (u, 0x10B80u, 0x10BAFu)) return joining_table[u - 0x10B80u + joining_offset_0x10b80u];
if (hb_in_range<hb_codepoint_t> (u, 0x10D00u, 0x10D23u)) return joining_table[u - 0x10D00u + joining_offset_0x10d00u];
if (hb_in_range<hb_codepoint_t> (u, 0x10EC2u, 0x10EC4u)) return joining_table[u - 0x10EC2u + joining_offset_0x10ec2u];
if (hb_in_range<hb_codepoint_t> (u, 0x10EC2u, 0x10EC7u)) return joining_table[u - 0x10EC2u + joining_offset_0x10ec2u];
if (hb_in_range<hb_codepoint_t> (u, 0x10F30u, 0x10FCBu)) return joining_table[u - 0x10F30u + joining_offset_0x10f30u];
break;

View file

@ -53,7 +53,7 @@ enum indic_syllable_type_t {
};
#line 57 "hb-ot-shaper-indic-machine.hh"
#line 54 "hb-ot-shaper-indic-machine.hh"
#define indic_syllable_machine_ex_A 9u
#define indic_syllable_machine_ex_C 1u
#define indic_syllable_machine_ex_CM 16u
@ -77,7 +77,7 @@ enum indic_syllable_type_t {
#define indic_syllable_machine_ex_ZWNJ 5u
#line 81 "hb-ot-shaper-indic-machine.hh"
#line 76 "hb-ot-shaper-indic-machine.hh"
static const unsigned char _indic_syllable_machine_trans_keys[] = {
8u, 57u, 4u, 57u, 5u, 57u, 5u, 57u, 13u, 13u, 4u, 57u, 4u, 57u, 4u, 57u,
8u, 57u, 5u, 57u, 5u, 57u, 13u, 13u, 4u, 57u, 4u, 57u, 4u, 57u, 4u, 57u,
@ -1126,7 +1126,7 @@ find_syllables_indic (hb_buffer_t *buffer)
int cs;
hb_glyph_info_t *info = buffer->info;
#line 1130 "hb-ot-shaper-indic-machine.hh"
#line 1119 "hb-ot-shaper-indic-machine.hh"
{
cs = indic_syllable_machine_start;
ts = 0;
@ -1142,7 +1142,7 @@ find_syllables_indic (hb_buffer_t *buffer)
unsigned int syllable_serial = 1;
#line 1146 "hb-ot-shaper-indic-machine.hh"
#line 1131 "hb-ot-shaper-indic-machine.hh"
{
int _slen;
int _trans;
@ -1156,7 +1156,7 @@ _resume:
#line 1 "NONE"
{ts = p;}
break;
#line 1160 "hb-ot-shaper-indic-machine.hh"
#line 1143 "hb-ot-shaper-indic-machine.hh"
}
_keys = _indic_syllable_machine_trans_keys + (cs<<1);
@ -1268,7 +1268,7 @@ _eof_trans:
#line 117 "hb-ot-shaper-indic-machine.rl"
{act = 7;}
break;
#line 1272 "hb-ot-shaper-indic-machine.hh"
#line 1232 "hb-ot-shaper-indic-machine.hh"
}
_again:
@ -1277,7 +1277,7 @@ _again:
#line 1 "NONE"
{ts = 0;}
break;
#line 1281 "hb-ot-shaper-indic-machine.hh"
#line 1239 "hb-ot-shaper-indic-machine.hh"
}
if ( ++p != pe )

View file

@ -6,12 +6,12 @@
*
* on files with these headers:
*
* # IndicSyllabicCategory-16.0.0.txt
* # Date: 2024-04-30, 21:48:21 GMT
* # IndicPositionalCategory-16.0.0.txt
* # Date: 2024-04-30, 21:48:21 GMT
* # Blocks-16.0.0.txt
* # Date: 2024-02-02
* # IndicSyllabicCategory-17.0.0.txt
* # Date: 2025-08-01, 04:02:23 GMT
* # IndicPositionalCategory-17.0.0.txt
* # Date: 2025-07-29, 13:35:52 GMT
* # Blocks-17.0.0.txt
* # Date: 2025-08-01
*/
#include "hb.hh"

View file

@ -48,7 +48,7 @@ enum khmer_syllable_type_t {
};
#line 52 "hb-ot-shaper-khmer-machine.hh"
#line 49 "hb-ot-shaper-khmer-machine.hh"
#define khmer_syllable_machine_ex_C 1u
#define khmer_syllable_machine_ex_DOTTEDCIRCLE 11u
#define khmer_syllable_machine_ex_H 4u
@ -66,7 +66,7 @@ enum khmer_syllable_type_t {
#define khmer_syllable_machine_ex_ZWNJ 5u
#line 70 "hb-ot-shaper-khmer-machine.hh"
#line 65 "hb-ot-shaper-khmer-machine.hh"
static const unsigned char _khmer_syllable_machine_trans_keys[] = {
5u, 26u, 5u, 26u, 1u, 15u, 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u,
5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 1u, 15u, 5u, 26u, 5u, 26u,
@ -294,7 +294,7 @@ find_syllables_khmer (hb_buffer_t *buffer)
int cs;
hb_glyph_info_t *info = buffer->info;
#line 298 "hb-ot-shaper-khmer-machine.hh"
#line 287 "hb-ot-shaper-khmer-machine.hh"
{
cs = khmer_syllable_machine_start;
ts = 0;
@ -310,7 +310,7 @@ find_syllables_khmer (hb_buffer_t *buffer)
unsigned int syllable_serial = 1;
#line 314 "hb-ot-shaper-khmer-machine.hh"
#line 299 "hb-ot-shaper-khmer-machine.hh"
{
int _slen;
int _trans;
@ -324,7 +324,7 @@ _resume:
#line 1 "NONE"
{ts = p;}
break;
#line 328 "hb-ot-shaper-khmer-machine.hh"
#line 311 "hb-ot-shaper-khmer-machine.hh"
}
_keys = _khmer_syllable_machine_trans_keys + (cs<<1);
@ -394,7 +394,7 @@ _eof_trans:
#line 98 "hb-ot-shaper-khmer-machine.rl"
{act = 3;}
break;
#line 398 "hb-ot-shaper-khmer-machine.hh"
#line 368 "hb-ot-shaper-khmer-machine.hh"
}
_again:
@ -403,7 +403,7 @@ _again:
#line 1 "NONE"
{ts = 0;}
break;
#line 407 "hb-ot-shaper-khmer-machine.hh"
#line 375 "hb-ot-shaper-khmer-machine.hh"
}
if ( ++p != pe )

View file

@ -50,7 +50,7 @@ enum myanmar_syllable_type_t {
};
#line 54 "hb-ot-shaper-myanmar-machine.hh"
#line 51 "hb-ot-shaper-myanmar-machine.hh"
#define myanmar_syllable_machine_ex_A 9u
#define myanmar_syllable_machine_ex_As 32u
#define myanmar_syllable_machine_ex_C 1u
@ -78,7 +78,7 @@ enum myanmar_syllable_type_t {
#define myanmar_syllable_machine_ex_ZWNJ 5u
#line 82 "hb-ot-shaper-myanmar-machine.hh"
#line 77 "hb-ot-shaper-myanmar-machine.hh"
static const unsigned char _myanmar_syllable_machine_trans_keys[] = {
1u, 57u, 3u, 57u, 5u, 57u, 5u, 57u, 3u, 57u, 5u, 57u, 3u, 57u, 3u, 57u,
3u, 57u, 3u, 57u, 3u, 57u, 5u, 57u, 1u, 15u, 3u, 57u, 3u, 57u, 3u, 57u,
@ -549,7 +549,7 @@ find_syllables_myanmar (hb_buffer_t *buffer)
int cs;
hb_glyph_info_t *info = buffer->info;
#line 553 "hb-ot-shaper-myanmar-machine.hh"
#line 542 "hb-ot-shaper-myanmar-machine.hh"
{
cs = myanmar_syllable_machine_start;
ts = 0;
@ -565,7 +565,7 @@ find_syllables_myanmar (hb_buffer_t *buffer)
unsigned int syllable_serial = 1;
#line 569 "hb-ot-shaper-myanmar-machine.hh"
#line 554 "hb-ot-shaper-myanmar-machine.hh"
{
int _slen;
int _trans;
@ -579,7 +579,7 @@ _resume:
#line 1 "NONE"
{ts = p;}
break;
#line 583 "hb-ot-shaper-myanmar-machine.hh"
#line 566 "hb-ot-shaper-myanmar-machine.hh"
}
_keys = _myanmar_syllable_machine_trans_keys + (cs<<1);
@ -649,7 +649,7 @@ _eof_trans:
#line 113 "hb-ot-shaper-myanmar-machine.rl"
{act = 3;}
break;
#line 653 "hb-ot-shaper-myanmar-machine.hh"
#line 623 "hb-ot-shaper-myanmar-machine.hh"
}
_again:
@ -658,7 +658,7 @@ _again:
#line 1 "NONE"
{ts = 0;}
break;
#line 662 "hb-ot-shaper-myanmar-machine.hh"
#line 630 "hb-ot-shaper-myanmar-machine.hh"
}
if ( ++p != pe )

View file

@ -191,7 +191,7 @@ static const struct thai_above_state_machine_edge_t {
};
static enum thai_below_state_t
static const enum thai_below_state_t
{
B0, /* No descender */
B1, /* Removable descender */
@ -334,7 +334,7 @@ preprocess_text_thai (const hb_ot_shape_plan_t *plan,
/* Is SARA AM. Decompose and reorder. */
(void) buffer->output_glyph (NIKHAHIT_FROM_SARA_AM (u));
_hb_glyph_info_set_continuation (&buffer->prev());
_hb_glyph_info_set_continuation (&buffer->prev(), buffer);
if (unlikely (!buffer->replace_glyph (SARA_AA_FROM_SARA_AM (u)))) break;
/* Make Nikhahit be recognized as a ccc=0 mark when zeroing widths. */

View file

@ -53,7 +53,7 @@ enum use_syllable_type_t {
};
#line 57 "hb-ot-shaper-use-machine.hh"
#line 54 "hb-ot-shaper-use-machine.hh"
#define use_syllable_machine_ex_B 1u
#define use_syllable_machine_ex_CGJ 6u
#define use_syllable_machine_ex_CMAbv 31u
@ -100,7 +100,7 @@ enum use_syllable_type_t {
#define use_syllable_machine_ex_ZWNJ 14u
#line 104 "hb-ot-shaper-use-machine.hh"
#line 99 "hb-ot-shaper-use-machine.hh"
static const unsigned char _use_syllable_machine_trans_keys[] = {
49u, 51u, 0u, 56u, 11u, 56u, 11u, 56u, 1u, 53u, 14u, 48u, 14u, 47u, 14u, 47u,
14u, 47u, 14u, 46u, 14u, 46u, 14u, 14u, 14u, 48u, 14u, 48u, 14u, 48u, 1u, 14u,
@ -929,7 +929,7 @@ find_syllables_use (hb_buffer_t *buffer)
unsigned int act HB_UNUSED;
int cs;
#line 933 "hb-ot-shaper-use-machine.hh"
#line 922 "hb-ot-shaper-use-machine.hh"
{
cs = use_syllable_machine_start;
ts = 0;
@ -942,7 +942,7 @@ find_syllables_use (hb_buffer_t *buffer)
unsigned int syllable_serial = 1;
#line 946 "hb-ot-shaper-use-machine.hh"
#line 931 "hb-ot-shaper-use-machine.hh"
{
int _slen;
int _trans;
@ -956,7 +956,7 @@ _resume:
#line 1 "NONE"
{ts = p;}
break;
#line 960 "hb-ot-shaper-use-machine.hh"
#line 943 "hb-ot-shaper-use-machine.hh"
}
_keys = _use_syllable_machine_trans_keys + (cs<<1);
@ -1078,7 +1078,7 @@ _eof_trans:
#line 181 "hb-ot-shaper-use-machine.rl"
{act = 9;}
break;
#line 1082 "hb-ot-shaper-use-machine.hh"
#line 1039 "hb-ot-shaper-use-machine.hh"
}
_again:
@ -1087,7 +1087,7 @@ _again:
#line 1 "NONE"
{ts = 0;}
break;
#line 1091 "hb-ot-shaper-use-machine.hh"
#line 1046 "hb-ot-shaper-use-machine.hh"
}
if ( ++p != pe )

View file

@ -6,18 +6,18 @@
*
* on files with these headers:
*
* # IndicSyllabicCategory-16.0.0.txt
* # Date: 2024-04-30, 21:48:21 GMT
* # IndicPositionalCategory-16.0.0.txt
* # Date: 2024-04-30, 21:48:21 GMT
* # ArabicShaping-16.0.0.txt
* # Date: 2024-07-30
* # DerivedCoreProperties-16.0.0.txt
* # Date: 2024-05-31, 18:09:32 GMT
* # Blocks-16.0.0.txt
* # Date: 2024-02-02
* # Scripts-16.0.0.txt
* # Date: 2024-04-30, 21:48:40 GMT
* # IndicSyllabicCategory-17.0.0.txt
* # Date: 2025-08-01, 04:02:23 GMT
* # IndicPositionalCategory-17.0.0.txt
* # Date: 2025-07-29, 13:35:52 GMT
* # ArabicShaping-17.0.0.txt
* # Date: 2025-08-14
* # DerivedCoreProperties-17.0.0.txt
* # Date: 2025-07-30, 23:55:08 GMT
* # Blocks-17.0.0.txt
* # Date: 2025-08-01
* # Scripts-17.0.0.txt
* # Date: 2025-07-24, 13:28:55 GMT
* # Override values For Indic_Syllabic_Category
* # Not derivable
* # Initial version based on Unicode 7.0 by Andrew Glass 2014-03-17
@ -103,7 +103,7 @@
#include <stdint.h>
static const uint8_t hb_use_u8[3345]=
static const uint8_t hb_use_u8[3343]=
{
16, 50, 51, 51, 51, 52, 51, 83, 118, 131, 57, 58, 59, 195, 211, 62,
51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
@ -127,24 +127,24 @@ static const uint8_t hb_use_u8[3345]=
49, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 50, 51, 2, 2, 2,
2, 2, 2, 2, 2, 52, 53, 2, 54, 2, 2, 55, 56, 2, 57, 58,
59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 2, 70, 71, 72, 73,
2, 74, 2, 75, 76, 77, 78, 2, 2, 79, 80, 81, 82, 2, 83, 84,
2, 85, 85, 85, 85, 85, 85, 85, 85, 86, 85, 85, 85, 85, 85, 85,
85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
85, 85, 85, 85, 85, 85, 85, 85, 87, 2, 2, 2, 2, 2, 2, 2,
2, 74, 2, 75, 76, 77, 78, 79, 2, 80, 81, 82, 83, 2, 84, 85,
2, 86, 86, 86, 86, 86, 86, 86, 86, 87, 86, 86, 86, 86, 86, 86,
86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
86, 86, 86, 86, 86, 86, 86, 86, 88, 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, 88, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 89, 90, 2, 2, 2, 91, 2, 2, 2, 92,
93, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 94, 94, 94, 95, 2, 2, 2, 2, 2,
2, 2, 2, 89, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 90, 91, 2, 2, 2, 92, 2, 2, 2, 93,
94, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 95, 95, 95, 96, 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, 96, 97, 2, 2, 2, 2, 2,
2, 2, 2, 98, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 97, 98, 2, 2, 2, 2, 2,
2, 2, 2, 99, 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, 99, 2, 2, 100, 2, 2, 2, 101, 2, 102, 2, 2, 2,
2, 2, 2, 103, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 104, 104, 105, 106, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
104, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
2, 2, 2, 100, 2, 2, 101, 2, 2, 2, 102, 2, 103, 2, 2, 2,
2, 2, 2, 104, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 105, 105, 106, 107, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105,
105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105,
105, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
0, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 3, 4,
0, 5, 0, 0, 0, 0, 0, 6, 0, 0, 7, 0, 0, 0, 0, 0,
0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@ -193,99 +193,99 @@ static const uint8_t hb_use_u8[3345]=
48, 48, 48, 48, 15, 82, 83, 84, 85, 86, 87, 0, 0, 0, 0, 88,
0, 9, 0, 0, 30, 0, 89, 81, 90, 2, 2, 2, 2, 9, 0, 0,
0, 42, 42, 91, 92, 2, 2, 2, 2, 2, 2, 2, 2, 13, 9, 0,
0, 93, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
9, 22, 80, 45, 22, 94, 61, 0, 0, 95, 96, 95, 95, 97, 98, 0,
0, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 9, 0, 0, 0, 0,
0, 2, 2, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2, 29, 0, 0,
0, 2, 2, 2, 2, 2, 9, 0, 0, 2, 2, 2, 52, 99, 45, 0,
0, 2, 2, 100, 101, 102, 103, 61, 63, 104, 16, 45, 22, 59, 21, 80,
48, 48, 76, 11, 11, 11, 105, 46, 40, 11, 106, 74, 2, 2, 2, 2,
2, 2, 2, 107, 22, 20, 20, 22, 48, 48, 22, 108, 2, 2, 2, 9,
0, 0, 0, 0, 0, 0, 109, 110, 110, 110, 110, 0, 0, 0, 0, 0,
0, 106, 74, 2, 2, 2, 2, 2, 2, 60, 61, 59, 25, 22, 111, 61,
2, 2, 2, 2, 107, 22, 23, 45, 45, 102, 112, 0, 0, 0, 0, 0,
0, 2, 2, 61, 18, 48, 23, 113, 102, 102, 102, 114, 115, 0, 0, 0,
0, 2, 2, 2, 2, 2, 0, 30, 2, 11, 46, 116, 116, 116, 11, 116,
116, 15, 116, 116, 116, 26, 0, 40, 0, 0, 0, 117, 51, 11, 5, 0,
0, 0, 0, 0, 0, 0, 118, 0, 0, 0, 0, 0, 0, 0, 6, 119,
120, 42, 42, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 120, 120,
121, 120, 120, 120, 120, 120, 120, 120, 120, 0, 0, 122, 0, 0, 0, 0,
0, 0, 7, 122, 0, 0, 0, 0, 0, 46, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 123, 123, 0, 0,
0, 2, 2, 2, 2, 0, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0,
124, 0, 123, 123, 0, 0, 0, 0, 0, 2, 53, 2, 108, 2, 10, 2,
2, 2, 65, 19, 16, 0, 0, 31, 0, 2, 2, 0, 0, 0, 0, 0,
0, 29, 2, 2, 2, 2, 2, 2, 2, 2, 2, 125, 23, 23, 23, 23,
23, 23, 23, 126, 0, 0, 0, 0, 0, 11, 11, 11, 11, 11, 11, 11,
11, 11, 2, 0, 0, 0, 0, 0, 52, 2, 2, 2, 22, 22, 127, 116,
0, 2, 2, 2, 128, 20, 59, 20, 113, 102, 129, 0, 0, 0, 0, 0,
0, 11, 130, 2, 2, 2, 2, 2, 2, 2, 131, 23, 22, 20, 48, 132,
133, 134, 0, 0, 0, 0, 0, 0, 0, 2, 2, 52, 30, 2, 2, 2,
2, 2, 2, 2, 2, 10, 22, 59, 99, 76, 135, 136, 137, 0, 0, 0,
0, 2, 138, 2, 2, 2, 2, 139, 0, 30, 2, 42, 5, 0, 79, 15,
2, 140, 20, 53, 128, 140, 2, 2, 141, 10, 9, 0, 0, 0, 0, 0,
0, 2, 2, 2, 2, 2, 142, 21, 25, 0, 0, 143, 144, 0, 0, 0,
0, 2, 65, 45, 23, 80, 47, 145, 0, 81, 81, 81, 81, 81, 81, 81,
81, 0, 0, 0, 0, 0, 0, 0, 6, 120, 120, 120, 120, 121, 0, 0,
0, 2, 2, 2, 2, 2, 9, 2, 2, 2, 9, 2, 30, 2, 2, 2,
2, 2, 30, 2, 2, 2, 30, 9, 0, 128, 20, 27, 31, 0, 0, 146,
147, 2, 2, 30, 2, 30, 2, 2, 2, 2, 2, 2, 0, 14, 37, 0,
148, 2, 2, 13, 37, 0, 30, 2, 2, 2, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 30, 2, 2, 9, 2, 2, 11, 41, 0, 0, 0,
0, 2, 2, 2, 0, 27, 22, 22, 30, 2, 2, 2, 0, 0, 0, 0,
0, 2, 2, 2, 2, 2, 27, 38, 0, 2, 2, 2, 116, 116, 116, 116,
116, 149, 2, 9, 0, 0, 0, 0, 0, 2, 14, 14, 0, 0, 0, 0,
0, 9, 2, 2, 9, 2, 2, 2, 2, 30, 2, 9, 0, 30, 2, 0,
0, 150, 151, 152, 2, 2, 2, 2, 2, 2, 2, 2, 2, 22, 22, 20,
20, 20, 22, 22, 134, 0, 0, 0, 0, 0, 153, 153, 153, 153, 153, 153,
153, 153, 153, 153, 2, 2, 2, 2, 2, 53, 52, 53, 0, 0, 0, 0,
154, 11, 74, 2, 2, 2, 2, 2, 2, 18, 19, 21, 16, 24, 37, 0,
0, 0, 31, 0, 0, 0, 0, 0, 0, 11, 49, 2, 2, 2, 2, 2,
2, 2, 2, 2, 128, 20, 22, 155, 22, 21, 156, 157, 2, 2, 2, 2,
2, 0, 0, 65, 158, 0, 0, 0, 0, 2, 13, 0, 0, 0, 0, 0,
0, 2, 65, 25, 20, 20, 20, 22, 22, 108, 159, 0, 0, 56, 160, 31,
161, 30, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 23,
19, 22, 22, 162, 44, 0, 0, 0, 49, 128, 0, 0, 0, 0, 0, 0,
0, 2, 2, 2, 9, 9, 2, 2, 30, 2, 2, 2, 2, 2, 2, 2,
30, 2, 2, 2, 2, 2, 2, 2, 10, 18, 19, 21, 22, 163, 31, 0,
0, 11, 11, 30, 2, 2, 2, 9, 30, 9, 2, 30, 2, 2, 58, 17,
23, 16, 23, 47, 32, 33, 32, 34, 0, 0, 0, 0, 35, 0, 0, 0,
2, 2, 23, 0, 11, 11, 11, 46, 0, 11, 11, 46, 0, 0, 0, 0,
0, 2, 2, 2, 2, 2, 30, 0, 9, 2, 2, 2, 30, 45, 59, 20,
20, 31, 33, 32, 32, 25, 164, 29, 165, 166, 37, 0, 0, 0, 0, 0,
0, 12, 26, 0, 0, 0, 0, 0, 0, 2, 2, 65, 25, 20, 20, 20,
22, 23, 126, 15, 17, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 0,
167, 168, 0, 0, 0, 0, 0, 0, 0, 18, 19, 20, 20, 66, 99, 25,
161, 11, 169, 9, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2,
65, 25, 20, 20, 0, 48, 48, 11, 170, 37, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 2, 2, 20, 0, 23, 19, 20, 20, 21, 16, 82,
170, 38, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 10, 171,
25, 20, 22, 22, 169, 9, 0, 0, 0, 2, 2, 2, 2, 2, 9, 43,
136, 23, 22, 20, 76, 21, 22, 0, 0, 2, 2, 2, 9, 0, 0, 0,
0, 2, 2, 2, 2, 2, 2, 18, 19, 20, 21, 22, 105, 170, 37, 0,
0, 2, 2, 2, 9, 30, 0, 2, 2, 2, 2, 30, 9, 2, 2, 2,
2, 23, 23, 18, 32, 33, 12, 172, 166, 173, 174, 0, 0, 0, 0, 0,
0, 2, 2, 2, 2, 0, 2, 2, 2, 65, 25, 20, 20, 0, 22, 23,
29, 108, 0, 33, 0, 0, 0, 0, 0, 52, 20, 22, 22, 22, 140, 2,
2, 2, 175, 141, 11, 15, 176, 61, 177, 0, 0, 1, 148, 0, 0, 0,
0, 52, 20, 22, 16, 19, 20, 2, 2, 2, 2, 159, 159, 159, 178, 178,
178, 178, 178, 178, 15, 179, 0, 30, 0, 22, 20, 20, 31, 22, 22, 11,
170, 0, 61, 61, 61, 61, 61, 61, 61, 66, 21, 82, 46, 0, 0, 0,
0, 2, 2, 2, 2, 2, 2, 2, 9, 22, 80, 45, 22, 93, 61, 0,
0, 94, 95, 94, 94, 96, 97, 0, 0, 2, 2, 2, 2, 2, 2, 2,
0, 2, 2, 9, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 0,
0, 2, 2, 2, 2, 29, 0, 0, 0, 2, 2, 2, 2, 2, 9, 0,
0, 2, 2, 2, 52, 98, 45, 0, 0, 2, 2, 99, 100, 101, 102, 61,
63, 103, 16, 45, 22, 59, 21, 80, 48, 48, 76, 11, 11, 11, 104, 46,
40, 11, 105, 74, 2, 2, 2, 2, 2, 2, 2, 106, 22, 20, 20, 22,
48, 48, 22, 107, 2, 2, 2, 9, 0, 0, 0, 0, 0, 0, 108, 109,
109, 109, 109, 0, 0, 0, 0, 0, 0, 105, 74, 2, 2, 2, 2, 2,
2, 60, 61, 59, 25, 22, 110, 61, 2, 2, 2, 2, 106, 22, 23, 45,
45, 101, 111, 0, 0, 0, 0, 0, 0, 2, 2, 61, 18, 48, 23, 112,
101, 101, 101, 113, 114, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 30,
2, 11, 46, 115, 115, 115, 11, 115, 115, 15, 115, 115, 115, 26, 0, 40,
0, 0, 0, 116, 51, 11, 5, 0, 0, 0, 0, 0, 0, 0, 117, 0,
0, 0, 0, 0, 0, 0, 6, 118, 119, 42, 42, 5, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 119, 119, 120, 119, 119, 119, 119, 119, 119, 119,
119, 0, 0, 121, 0, 0, 0, 0, 0, 0, 7, 121, 0, 0, 0, 0,
0, 46, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9,
0, 0, 0, 0, 122, 122, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0,
30, 0, 0, 0, 0, 0, 0, 0, 123, 0, 122, 122, 0, 0, 0, 0,
0, 2, 53, 2, 107, 2, 10, 2, 2, 2, 65, 19, 16, 0, 0, 31,
0, 2, 2, 0, 0, 0, 0, 0, 0, 29, 2, 2, 2, 2, 2, 2,
2, 2, 2, 124, 23, 23, 23, 23, 23, 23, 23, 125, 0, 0, 0, 0,
0, 11, 11, 11, 11, 11, 11, 11, 11, 11, 2, 0, 0, 0, 0, 0,
52, 2, 2, 2, 22, 22, 126, 115, 0, 2, 2, 2, 127, 20, 59, 20,
112, 101, 128, 0, 0, 0, 0, 0, 0, 11, 129, 2, 2, 2, 2, 2,
2, 2, 130, 23, 22, 20, 48, 131, 132, 133, 0, 0, 0, 0, 0, 0,
0, 2, 2, 52, 30, 2, 2, 2, 2, 2, 2, 2, 2, 10, 22, 59,
98, 76, 134, 135, 136, 0, 0, 0, 0, 2, 137, 2, 2, 2, 2, 138,
0, 30, 2, 42, 5, 0, 79, 15, 2, 139, 20, 53, 127, 139, 2, 2,
140, 10, 9, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 141, 21,
25, 0, 0, 142, 143, 0, 0, 0, 0, 2, 65, 45, 23, 80, 47, 144,
0, 81, 81, 81, 81, 81, 81, 81, 81, 0, 0, 0, 0, 0, 0, 0,
6, 119, 119, 119, 119, 120, 0, 0, 0, 2, 2, 2, 2, 2, 9, 2,
2, 2, 9, 2, 30, 2, 2, 2, 2, 2, 30, 2, 2, 2, 30, 9,
0, 127, 20, 27, 31, 0, 0, 145, 146, 2, 2, 30, 2, 30, 2, 2,
2, 2, 2, 2, 0, 14, 37, 0, 147, 2, 2, 13, 37, 0, 30, 2,
2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 2, 2,
9, 2, 2, 11, 41, 0, 0, 0, 0, 2, 2, 2, 0, 27, 22, 22,
30, 2, 2, 2, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 27, 38,
0, 2, 2, 2, 115, 115, 115, 115, 115, 148, 2, 9, 0, 0, 0, 0,
0, 2, 14, 14, 0, 0, 0, 0, 0, 9, 2, 2, 9, 2, 2, 2,
2, 30, 2, 9, 0, 30, 2, 0, 0, 149, 150, 151, 2, 2, 2, 2,
2, 2, 2, 2, 2, 22, 22, 20, 20, 20, 22, 22, 133, 0, 0, 0,
0, 0, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 2, 2, 2, 2,
2, 53, 52, 53, 0, 0, 0, 0, 153, 11, 74, 2, 2, 2, 2, 2,
2, 18, 19, 21, 16, 24, 37, 0, 0, 0, 31, 0, 0, 0, 0, 0,
0, 11, 49, 2, 2, 2, 2, 2, 2, 2, 2, 2, 127, 20, 22, 154,
22, 21, 155, 156, 2, 2, 2, 2, 2, 0, 0, 65, 157, 0, 0, 0,
0, 2, 13, 0, 0, 0, 0, 0, 0, 2, 65, 25, 20, 20, 20, 22,
22, 107, 158, 0, 0, 56, 159, 31, 160, 30, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 23, 19, 22, 22, 161, 44, 0, 0, 0,
49, 127, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 9, 9, 2, 2,
30, 2, 2, 2, 2, 2, 2, 2, 30, 2, 2, 2, 2, 2, 2, 2,
10, 18, 19, 21, 22, 162, 31, 0, 0, 11, 11, 30, 2, 2, 2, 9,
30, 9, 2, 30, 2, 2, 58, 17, 23, 16, 23, 47, 32, 33, 32, 34,
0, 0, 0, 0, 35, 0, 0, 0, 2, 2, 23, 0, 11, 11, 11, 46,
0, 11, 11, 46, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 30, 0,
9, 2, 2, 2, 30, 45, 59, 20, 20, 31, 33, 32, 32, 25, 163, 29,
164, 165, 37, 0, 0, 0, 0, 0, 0, 12, 26, 0, 0, 0, 0, 0,
0, 2, 2, 65, 25, 20, 20, 20, 22, 23, 125, 15, 17, 0, 0, 0,
0, 2, 2, 2, 2, 2, 0, 0, 166, 167, 0, 0, 0, 0, 0, 0,
0, 18, 19, 20, 20, 66, 98, 25, 160, 11, 168, 9, 0, 0, 0, 0,
0, 2, 2, 2, 2, 2, 2, 2, 65, 25, 20, 20, 0, 48, 48, 11,
169, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 20,
0, 23, 19, 20, 20, 21, 16, 82, 169, 38, 0, 0, 0, 0, 0, 0,
0, 2, 2, 2, 2, 2, 10, 170, 25, 20, 22, 22, 168, 9, 0, 0,
0, 2, 2, 2, 2, 2, 9, 43, 135, 23, 22, 20, 76, 21, 22, 0,
0, 2, 2, 2, 9, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 18,
19, 20, 21, 22, 104, 169, 37, 0, 0, 2, 2, 2, 9, 30, 0, 2,
2, 2, 2, 30, 9, 2, 2, 2, 2, 23, 23, 18, 32, 33, 12, 171,
165, 172, 173, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 2, 2,
2, 65, 25, 20, 20, 0, 22, 23, 29, 107, 0, 33, 0, 0, 0, 0,
0, 52, 20, 22, 22, 22, 139, 2, 2, 2, 174, 140, 11, 15, 175, 61,
176, 0, 0, 1, 147, 0, 0, 0, 0, 52, 20, 22, 16, 19, 20, 2,
2, 2, 2, 158, 158, 158, 177, 177, 177, 177, 177, 177, 15, 178, 0, 30,
0, 16, 20, 16, 16, 0, 0, 0, 0, 22, 20, 20, 31, 22, 22, 11,
169, 0, 61, 61, 61, 61, 61, 61, 61, 66, 21, 82, 46, 0, 0, 0,
0, 2, 2, 2, 9, 2, 30, 2, 2, 52, 22, 22, 31, 0, 38, 22,
27, 11, 160, 180, 181, 0, 0, 0, 0, 2, 2, 2, 30, 9, 2, 2,
27, 11, 159, 179, 180, 0, 0, 0, 0, 2, 2, 2, 30, 9, 2, 2,
2, 2, 2, 2, 2, 2, 23, 23, 47, 22, 35, 82, 68, 0, 0, 0,
0, 2, 182, 66, 47, 0, 0, 0, 0, 11, 183, 2, 2, 2, 2, 2,
2, 2, 2, 23, 22, 20, 31, 0, 48, 16, 144, 0, 0, 0, 0, 0,
0, 2, 2, 2, 2, 2, 157, 0, 0, 184, 184, 184, 184, 184, 184, 184,
184, 185, 185, 185, 186, 187, 185, 184, 184, 188, 184, 184, 189, 190, 190, 190,
190, 190, 190, 190, 0, 0, 0, 0, 0, 184, 184, 184, 184, 184, 191, 0,
0, 2, 2, 2, 2, 2, 2, 2, 22, 22, 22, 22, 22, 22, 192, 193,
194, 11, 11, 11, 46, 0, 0, 0, 0, 29, 74, 2, 2, 2, 2, 2,
0, 2, 181, 66, 47, 0, 0, 0, 0, 11, 182, 2, 2, 2, 2, 2,
2, 2, 2, 23, 22, 20, 31, 0, 48, 16, 143, 0, 0, 0, 0, 0,
0, 2, 2, 2, 2, 2, 156, 0, 0, 183, 183, 183, 183, 183, 183, 183,
183, 184, 184, 184, 185, 186, 184, 183, 183, 187, 183, 183, 188, 189, 189, 189,
189, 189, 189, 189, 0, 0, 0, 0, 0, 183, 183, 183, 183, 183, 190, 0,
0, 2, 2, 2, 2, 2, 2, 2, 22, 22, 22, 22, 22, 22, 191, 192,
193, 11, 11, 11, 46, 0, 0, 0, 0, 29, 74, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 65, 47, 0, 2, 2, 2, 2, 2, 9, 0,
58, 195, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 0, 0, 0, 40, 116, 26, 0, 0, 0, 0, 0,
58, 194, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 0, 0, 0, 40, 115, 26, 0, 0, 0, 0, 0,
0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
30, 2, 2, 2, 2, 2, 0, 58, 37, 0, 6, 120, 120, 120, 121, 0,
30, 2, 2, 2, 2, 2, 0, 58, 37, 0, 6, 119, 119, 119, 120, 0,
0, 11, 11, 11, 49, 2, 2, 2, 0, 2, 2, 2, 2, 2, 0, 0,
2, 2, 2, 2, 2, 2, 2, 2, 46, 2, 2, 2, 2, 2, 2, 11,
11, 2, 2, 2, 2, 2, 2, 22, 22, 2, 2, 2, 2, 2, 2, 2,
@ -301,22 +301,21 @@ static const uint8_t hb_use_u8[3345]=
VMBlw,VMPst, IS, VAbv, MPst, MPre, MBlw, MBlw, B, MBlw, MBlw, VPst,VMPst,VMPst, B, MBlw,
VPst, VPre, VAbv, VAbv,VMPst,VMPst,VMBlw, B,VMPst, VBlw, VPst, CGJ, CGJ, VPst,VMAbv,VMAbv,
FMAbv, FAbv,CMAbv,FMAbv,VMAbv,FMAbv, VAbv, IS,FMAbv, B,FMAbv, B, CGJ, WJ, CGJ, GB,
CMAbv,CMAbv, B, GB, B, VAbv, SUB, FPst, FPst,VMBlw, FPst, FPst, FBlw,VMAbv,FMBlw, VAbv,
VPre, B, MPre, MBlw, SUB, FAbv, FAbv, MAbv, SUB, Sk, VPst, VAbv,VMAbv,VMAbv, FAbv,CMAbv,
VPst, H, B, O,SMAbv,SMAbv,SMAbv, VPst, IS, RK, RK, VBlw, FAbv,VMPre,VMPre,FMAbv,
CMBlw,VMBlw,VMBlw,VMAbv, CS, O,FMAbv, ZWNJ, CGJ, WJ, WJ, WJ, O,FMPst, O, SB,
SE, O, H, MPst, VPst, H,VMAbv, VAbv,VMBlw, B, VBlw, FPst, VPst, FAbv,VMPst, B,
CMAbv, VAbv, MBlw, MPst, MBlw, H, O, VBlw, MPst, MPre, MAbv, MBlw, O, B, FAbv, FAbv,
FPst, VBlw, B, VBlw,VMAbv, B, VPre, O,VMPst, IS, O,VMPst, VBlw, VPst,VMBlw,VMBlw,
VMAbv, O, IS,VMBlw, B,VMPst,VMAbv,VMPst, CS, CS, B, N, N, O, HN, VPre,
VBlw, VAbv, IS,CMAbv, O, VPst, B, R, R,CMBlw, VAbv, VPre,VMAbv,VMAbv, H, VAbv,
CMBlw,VMPst, O,VMAbv,CMBlw, IS, R,FMAbv, B, CS, CS, H,CMBlw,VMPst, H,VMPst,
VAbv,VMAbv, VPst, MPst, R, MPst,CMBlw, B,FMBlw, CS, SUB, SUB, GB, FBlw, FBlw,CMAbv,
IS, VBlw, IS, R, MBlw, GB, VAbv, R,VMPst, G, G, J, J, J, SB, SE,
J, HR, G, G, HM, HM, HM, G, O, MPre, MPre, MPst,VMAbv, MBlw, VBlw, O,
VBlw,
CMAbv,CMAbv, B, VAbv, SUB, FPst, FPst,VMBlw, FPst, FPst, FBlw,VMAbv,FMBlw, VAbv, VPre, B,
MPre, MBlw, SUB, FAbv, FAbv, MAbv, SUB, Sk, VPst, VAbv,VMAbv,VMAbv, FAbv,CMAbv, VPst, H,
B, O,SMAbv,SMAbv,SMAbv, VPst, IS, RK, RK, VBlw, FAbv,VMPre,VMPre,FMAbv,CMBlw,VMBlw,
VMBlw,VMAbv, CS, O,FMAbv, ZWNJ, CGJ, WJ, WJ, WJ, O,FMPst, O, SB, SE, O,
H, MPst, VPst, H,VMAbv, VAbv,VMBlw, B, VBlw, FPst, VPst, FAbv,VMPst, B,CMAbv, VAbv,
MBlw, MPst, MBlw, H, O, VBlw, MPst, MPre, MAbv, MBlw, O, B, FAbv, FAbv, FPst, VBlw,
B, VBlw,VMAbv, B, VPre, O,VMPst, IS, O,VMPst, VBlw, VPst,VMBlw,VMBlw,VMAbv, O,
IS,VMBlw, B,VMPst,VMAbv,VMPst, CS, CS, B, N, N, O, HN, VPre, VBlw, VAbv,
IS,CMAbv, O, VPst, B, R, R,CMBlw, VAbv, VPre,VMAbv,VMAbv, H, VAbv,CMBlw,VMPst,
O,VMAbv,CMBlw, IS, R,FMAbv, B, CS, CS, H,CMBlw,VMPst, H,VMPst, VAbv,VMAbv,
VPst, MPst, R, MPst,CMBlw, B,FMBlw, CS, SUB, SUB, GB, FBlw, FBlw,CMAbv, IS, VBlw,
IS, R, MBlw, GB, VAbv, R,VMPst, G, G, J, J, J, SB, SE, J, HR,
G, G, HM, HM, HM, G, O, MPre, MPre, MPst,VMAbv, MBlw, VBlw, O, VBlw,
};
static const uint16_t hb_use_u16[856]=
static const uint16_t hb_use_u16[864]=
{
0, 0, 1, 2, 0, 3, 0, 3, 0, 0, 4, 5, 0, 6, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0,
@ -330,48 +329,48 @@ static const uint16_t hb_use_u16[856]=
73, 74, 75, 76, 77, 0, 0, 0, 10, 10, 78, 79, 80, 81, 82, 83,
84, 85, 0, 0, 0, 0, 0, 0, 10, 86, 10, 87, 10, 88, 89, 90,
10, 10, 10, 91, 92, 93, 2, 0, 94, 0, 10, 10, 10, 10, 10, 95,
96, 10, 97, 0, 0, 0, 0, 0, 98, 99,100,101, 31, 10,102,103,
10, 10,104, 10,105,106, 0, 0, 10,107, 10, 10, 10,108,109,110,
2, 2, 0, 0, 0, 0, 0, 0,111, 10, 10,112,113, 2,114,115,
116, 10,117, 10, 10, 10,118,119, 10, 10,120,121,122, 0, 0, 0,
0, 0, 0, 0, 0,123,124,125, 0, 0, 0, 0, 0, 0, 0,126,
127,128,129, 0, 0, 0,130,131,132, 0, 0, 0, 0, 0, 0,133,
0, 0, 0, 0,134, 0, 0, 0, 0, 0, 0, 0, 0, 0,135, 0,
0, 0, 0, 10, 10, 10,136,137, 0, 0,138, 0, 0, 0, 0, 0,
139, 10,140, 0, 10, 10, 10,141,142, 10, 10,143,144, 2,145,146,
10, 10,147, 10,148,149, 0, 0,150, 10, 10,151,152, 2,153, 99,
10, 10,154,155,156, 2, 10,157, 10, 10, 10,158,159, 0,160,161,
0, 0, 0, 0, 10, 10,162, 2,163, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0,164, 0, 0, 0, 0, 0, 0, 0,165,
0, 0, 0, 0, 0, 0, 0,166,166,167, 34,168, 0, 0, 0, 0,
169,170, 10,171, 95, 0, 0, 0, 0, 0, 0, 0, 70, 10,172, 0,
10,173,174, 0, 0, 0, 0, 0, 10, 10,175, 2, 9, 10,176, 10,
177, 0, 0, 0, 0, 0, 0, 0, 10, 10,178,173, 0, 0, 0, 0,
0, 0, 0, 10,179,180, 0, 10,181, 0, 0,182,183, 0, 0, 0,
184, 10, 10,185,186,187,188,189,190, 10, 10,191,192, 0, 0, 0,
193, 10,194,195,196, 10, 10,197,190, 10, 10,198,199,106,200,103,
10, 34,201,202,203, 0, 0, 0,204,205, 95, 10, 10,206,207, 2,
208, 21, 22,209,210,211,212,213,214, 10, 10,215,216,217,218, 0,
10, 10, 10,219,220,221,222, 0,200, 10, 10,223,224, 2, 0, 0,
10, 10,225,226,227,228, 0, 0, 10, 10, 10,229,230, 2, 0, 0,
10, 10,231,232, 2, 10,141, 0, 10,233,234,104,235, 0, 0, 0,
10, 10,236,237, 0, 0, 0, 0,238,239, 10,240,241, 2, 0, 0,
0, 0,242, 10, 10,243,244, 0,245, 10, 10,246,247,248, 10, 10,
249,250, 0, 0, 0, 0, 0, 0, 22, 10,225,251, 8, 10, 71, 19,
10,252, 74,253, 0, 0, 0, 0,254, 10, 10,255,256, 2,257, 10,
258,259, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10,260,
261, 49, 10,262,263,264, 0, 0,265,265,265,265,265,265,265,265,
265,265,265,266,267,268,265,265,265,265,265,265,265,265,265,269,
10,270,271, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,
10, 10, 10,272, 0, 0, 0, 0, 0, 0, 0, 0,273, 10,274, 2,
10, 10, 10, 10,275,276,277,277,278,279, 0, 0, 0, 0,280, 0,
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,177, 0,281,
10, 10, 10, 10, 10, 10,106, 71, 95,282, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0,283, 10, 10, 71,284,285, 0, 0, 0,
0, 10,286, 0, 10, 10,287, 2, 0, 0, 0, 0, 0, 10,288, 2,
0, 0, 0, 0, 0, 10,289,106, 10, 10, 10, 10,290, 2, 0, 0,
130,130,130,130,130,130,130,130,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,130,
96, 10, 97, 0, 0, 0, 0, 0, 10, 98, 99,100, 31, 10,101,102,
10, 10,103, 10,104,105, 0, 0, 10,106, 10, 10, 10,107,108,109,
2, 2, 0, 0, 0, 0, 0, 0,110, 10, 10,111,112, 2,113,114,
115, 10,116, 10, 10, 10,117,118, 10, 10,119,120,121, 0, 0, 0,
0, 0, 0, 0, 0,122,123,124, 0, 0, 0, 0, 0, 0, 0,125,
126,127,128, 0, 0, 0,129,130,131, 0, 0, 0, 0, 0, 0,132,
0, 0, 0, 0,133, 0, 0, 0, 0, 0, 0, 0, 0, 0,134, 0,
0, 0, 0, 10, 10, 10,135,136, 0, 0,137, 0, 0, 0, 0, 0,
138, 10,139, 0, 10, 10, 10,140,141, 10, 10,142,143, 2,144,145,
10, 10,146, 10,147,148, 0, 0,149, 10, 10,150,151, 2,152, 98,
10, 10,153,154,155, 2, 10,156, 10, 10, 10,157,158, 0,159,160,
0, 0, 0, 0, 10, 10,161, 2,162, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0,163, 0, 0, 0, 0, 0, 0, 0,164,
0, 0, 0, 0, 0, 0, 0,165,165,166, 34,167, 0, 0, 0, 0,
168,169, 10,170, 95, 0, 0, 0, 0, 0, 0, 0, 70, 10,171, 0,
10,172,173, 0, 0, 0, 0, 0, 10, 10,174, 2, 9, 10,175, 10,
176, 0, 0, 0, 0, 0, 0, 0, 10, 10,177,172, 0, 0, 0, 0,
0, 0, 0, 10,178,179, 0, 10,180, 0, 0,181,182, 0, 0, 0,
183, 10, 10,184,185,186,187,188,189, 10, 10,190,191, 0, 0, 0,
192, 10,193,194,195, 10, 10,196,189, 10, 10,197,198,105,199,102,
10, 34,200,201,202, 0, 0, 0,203,204, 95, 10, 10,205,206, 2,
207, 21, 22,208,209,210,211,212,213, 10, 10,214,215,216,217, 0,
10, 10, 10,218,219,220,221, 0,199, 10, 10,222,223, 2, 0, 0,
10, 10,224,225,226,227, 0, 0, 10, 10, 10,228,229, 2, 0, 0,
10, 10,230,231, 2, 10,140, 0, 10,232,233,103,234, 0, 0, 0,
10, 10,235,236, 0, 0, 0, 0,237,238, 10,239,240, 2, 0, 0,
0, 0,241, 10, 10,242,243, 0,244, 10, 10,245,246,247, 10, 10,
248,249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,250, 0,
22, 10,224,251, 8, 10, 71, 19, 10,252, 74,253, 0, 0, 0, 0,
254, 10, 10,255,256, 2,257, 10,258,259, 2, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 10,260,261, 49, 10,262,263,264, 0, 0,
265,265,265,265,265,265,265,265,265,265,265,266,267,268,265,265,
265,265,265,265,265,265,265,269, 10,270,271, 2, 0, 0, 0, 0,
0, 0, 0, 0, 2, 0, 0, 0, 10, 10, 10,272, 0, 0, 0, 0,
0, 0, 0, 0,273, 10,274, 2, 10, 10, 10, 10,275,276,277,277,
278,279, 0, 0, 0, 0,280, 0, 10, 10, 10, 10, 10, 10, 10, 10,
10, 10, 10, 10, 10,176, 0,281, 10, 10, 10, 10, 10, 10,105, 71,
95,282, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,283,
10, 10, 71,284,285, 0, 0, 0, 0, 10,286, 0, 10, 10,287, 2,
0, 0, 0, 0, 0, 10,288, 2, 0, 0, 0, 0, 0, 10,289,105,
10, 10, 10, 10,290, 2, 0, 0,129,129,129,129,129,129,129,129,
162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,129,
};
static inline uint8_t hb_use_b4 (const uint8_t* a, unsigned i)
@ -380,7 +379,7 @@ static inline uint8_t hb_use_b4 (const uint8_t* a, unsigned i)
}
static inline uint8_t hb_use_get_category (unsigned u)
{
return u<921600 ? hb_use_u8[2953u+(((hb_use_u8[625u+(((hb_use_u16[((hb_use_u8[113u+(((hb_use_b4(hb_use_u8,u>>1>>3>>3>>5))<<5)+((u>>1>>3>>3)&31))])<<3)+((u>>1>>3)&7)])<<3)+((u>>1)&7))])<<1)+((u)&1))] : O;
return u<921600 ? hb_use_u8[2953u+((hb_use_u8[625u+((hb_use_u16[((hb_use_u8[113u+((hb_use_b4(hb_use_u8,((((((((u)>>1))>>3))>>3))>>5)))<<5)+((((((((u)>>1))>>3))>>3))&31)])<<3)+((((((u)>>1))>>3))&7)])<<3)+((((u)>>1))&7)])<<1)+((u)&1)] : O;
}
@ -388,7 +387,7 @@ static inline uint8_t hb_use_get_category (unsigned u)
#include <stdint.h>
static const uint8_t hb_use_u8[3657]=
static const uint8_t hb_use_u8[3663]=
{
16, 50, 51, 51, 51, 52, 51, 83, 118, 131, 57, 58, 59, 195, 211, 62,
51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
@ -404,16 +403,16 @@ static const uint8_t hb_use_u8[3657]=
1, 1, 1, 1, 1, 1, 1, 1, 1, 25, 26, 27, 28, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 29,
30, 1, 1, 1, 1, 1, 31, 1, 1, 1, 1, 32, 33, 1, 34, 35,
36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 1, 48, 49, 50,
51, 52, 52, 52, 52, 53, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
52, 52, 52, 52, 54, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 55, 1, 1, 1, 1, 1, 1, 1, 1, 56, 57, 1, 58, 1,
59, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 60, 61, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 62, 1, 1,
1, 1, 63, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 64, 65, 1, 66, 67, 1, 1, 1, 68, 1, 1, 1, 1, 1,
1, 69, 70, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69,
69, 0, 1, 2, 2, 0, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0,
36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
52, 53, 53, 53, 53, 54, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
53, 53, 53, 53, 55, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 56, 1, 1, 1, 1, 1, 1, 1, 1, 57, 58, 1, 59, 1,
60, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 61, 62, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 63, 1, 1,
1, 1, 64, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 65, 66, 1, 67, 68, 1, 1, 1, 69, 1, 1, 1, 1, 1,
1, 70, 71, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
70, 0, 1, 2, 2, 0, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 7, 8, 0, 0, 9, 0, 0, 0, 0,
0, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
@ -437,190 +436,190 @@ static const uint8_t hb_use_u8[3657]=
0, 0, 0, 0, 0, 56, 179, 180, 0, 56, 181, 182, 0, 56, 183, 184,
185, 186, 187, 188, 0, 0, 0, 0, 0, 56, 189, 0, 0, 0, 0, 0,
0, 190, 191, 192, 0, 0, 193, 194, 195, 196, 197, 198, 56, 199, 0, 0,
0, 200, 201, 202, 203, 204, 205, 0, 0, 206, 207, 208, 209, 210, 67, 0,
0, 0, 0, 0, 0, 0, 0, 0, 211, 212, 213, 214, 0, 0, 0, 0,
0, 215, 215, 215, 215, 215, 215, 215, 215, 215, 216, 217, 215, 215, 215, 215,
215, 215, 215, 215, 215, 215, 215, 215, 218, 219, 220, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 67, 0, 56, 221, 0, 0, 0, 0, 0,
0, 0, 0, 222, 223, 0, 0, 0, 0, 56, 56, 224, 225, 226, 0, 0,
227, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 228,
229, 56, 56, 56, 230, 231, 0, 0, 0, 0, 0, 0, 232, 0, 0, 0,
0, 56, 233, 234, 0, 0, 0, 0, 0, 0, 0, 0, 0, 101, 235, 56,
236, 0, 0, 0, 0, 0, 0, 101, 237, 0, 0, 0, 0, 0, 0, 101,
238, 56, 56, 239, 0, 0, 0, 0, 0, 240, 240, 240, 240, 240, 240, 240,
240, 241, 241, 241, 241, 241, 241, 241, 242, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 2, 2, 2, 2, 0, 0,
0, 0, 0, 0, 0, 0, 3, 4, 0, 5, 0, 0, 0, 0, 0, 6,
0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 10, 11, 11, 11, 11, 0, 0, 0, 9, 12,
0, 2, 2, 2, 2, 13, 14, 0, 0, 11, 15, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 16, 17, 18, 19, 20, 21, 22, 16, 23, 24,
25, 12, 26, 27, 20, 2, 2, 2, 2, 2, 20, 0, 2, 2, 2, 2,
2, 0, 2, 2, 2, 2, 2, 2, 2, 28, 29, 30, 2, 2, 2, 9,
30, 9, 30, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 9, 2, 2,
2, 9, 9, 0, 2, 2, 0, 17, 18, 19, 20, 31, 32, 33, 32, 34,
0, 0, 0, 0, 35, 0, 0, 2, 30, 2, 0, 0, 0, 0, 0, 9,
36, 12, 15, 30, 2, 2, 9, 0, 30, 9, 2, 30, 9, 2, 0, 37,
18, 19, 31, 0, 27, 38, 27, 39, 0, 40, 0, 0, 0, 30, 2, 9,
9, 0, 0, 0, 2, 2, 2, 2, 2, 41, 42, 43, 0, 0, 0, 0,
0, 12, 15, 30, 2, 2, 2, 2, 30, 2, 30, 2, 2, 2, 2, 2,
2, 9, 2, 30, 2, 2, 0, 17, 18, 19, 20, 21, 27, 22, 35, 24,
0, 0, 0, 0, 0, 30, 41, 41, 44, 12, 29, 30, 2, 2, 2, 9,
30, 9, 2, 30, 2, 2, 0, 17, 45, 0, 0, 27, 22, 0, 0, 2,
30, 30, 0, 0, 0, 0, 0, 0, 0, 0, 46, 30, 2, 2, 9, 0,
2, 9, 2, 2, 0, 30, 9, 9, 2, 0, 30, 9, 0, 2, 9, 0,
2, 2, 2, 2, 2, 2, 0, 0, 23, 16, 47, 0, 48, 33, 48, 34,
0, 0, 0, 0, 35, 0, 0, 0, 0, 15, 29, 49, 2, 2, 2, 9,
2, 9, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 17,
22, 16, 23, 47, 22, 38, 22, 39, 0, 0, 0, 27, 31, 2, 9, 0,
0, 10, 29, 30, 2, 2, 2, 9, 2, 2, 2, 30, 2, 2, 0, 17,
45, 0, 0, 35, 47, 0, 0, 0, 9, 50, 51, 0, 0, 0, 0, 0,
0, 11, 29, 2, 2, 2, 2, 9, 2, 2, 2, 2, 2, 2, 52, 53,
23, 19, 20, 31, 48, 33, 48, 34, 54, 0, 0, 0, 35, 0, 0, 0,
30, 12, 29, 30, 2, 2, 2, 2, 2, 2, 2, 2, 9, 0, 2, 2,
2, 2, 30, 2, 2, 2, 2, 30, 0, 2, 2, 2, 9, 0, 55, 0,
35, 23, 22, 31, 31, 18, 48, 48, 25, 0, 23, 0, 0, 0, 0, 0,
0, 2, 0, 2, 9, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0,
0, 2, 2, 56, 56, 57, 0, 0, 18, 2, 2, 2, 2, 30, 2, 2,
2, 2, 2, 2, 2, 2, 2, 9, 0, 58, 21, 59, 22, 22, 20, 20,
46, 21, 11, 31, 11, 2, 2, 60, 61, 61, 61, 61, 61, 62, 61, 61,
61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 63,
0, 0, 0, 0, 64, 0, 0, 0, 0, 2, 2, 2, 2, 2, 65, 45,
59, 66, 22, 22, 67, 68, 69, 70, 71, 2, 2, 2, 2, 2, 1, 0,
5, 2, 2, 2, 23, 20, 2, 2, 72, 71, 73, 74, 65, 73, 29, 29,
2, 52, 22, 53, 2, 2, 2, 2, 2, 2, 75, 76, 77, 29, 29, 78,
79, 2, 2, 2, 2, 2, 29, 45, 0, 2, 59, 80, 0, 0, 0, 0,
30, 2, 59, 47, 0, 0, 0, 0, 0, 2, 59, 0, 0, 0, 0, 0,
0, 2, 2, 2, 2, 2, 2, 9, 2, 9, 59, 0, 0, 0, 0, 0,
0, 2, 2, 81, 45, 22, 59, 20, 48, 48, 48, 48, 15, 82, 83, 84,
85, 86, 87, 0, 0, 0, 0, 88, 0, 9, 0, 0, 30, 0, 89, 81,
90, 2, 2, 2, 2, 9, 0, 0, 0, 42, 42, 91, 92, 2, 2, 2,
2, 2, 2, 2, 2, 13, 9, 0, 0, 93, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 9, 22, 80, 45, 22, 94, 61, 0,
0, 95, 96, 95, 95, 97, 98, 0, 0, 2, 2, 2, 2, 2, 2, 2,
0, 0, 0, 0, 200, 0, 0, 0, 0, 201, 202, 203, 204, 205, 206, 0,
0, 207, 208, 209, 210, 211, 67, 0, 0, 0, 0, 0, 0, 0, 0, 0,
212, 213, 214, 215, 0, 0, 0, 0, 0, 216, 216, 216, 216, 216, 216, 216,
216, 216, 217, 218, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216,
219, 220, 221, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67,
0, 56, 222, 0, 0, 0, 0, 0, 0, 0, 0, 223, 224, 0, 0, 0,
0, 56, 56, 225, 226, 227, 0, 0, 228, 56, 56, 56, 56, 56, 56, 56,
56, 56, 56, 56, 56, 56, 56, 229, 230, 56, 56, 56, 231, 232, 0, 0,
0, 0, 0, 0, 233, 0, 0, 0, 0, 56, 234, 235, 0, 0, 0, 0,
0, 0, 0, 0, 0, 101, 236, 56, 237, 0, 0, 0, 0, 0, 0, 101,
238, 0, 0, 0, 0, 0, 0, 101, 239, 56, 56, 240, 0, 0, 0, 0,
0, 241, 241, 241, 241, 241, 241, 241, 241, 242, 242, 242, 242, 242, 242, 242,
243, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
0, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 3, 4,
0, 5, 0, 0, 0, 0, 0, 6, 0, 0, 7, 0, 0, 0, 0, 0,
0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 10, 11,
11, 11, 11, 0, 0, 0, 9, 12, 0, 2, 2, 2, 2, 13, 14, 0,
0, 11, 15, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 16, 17,
18, 19, 20, 21, 22, 16, 23, 24, 25, 12, 26, 27, 20, 2, 2, 2,
2, 2, 20, 0, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2,
2, 28, 29, 30, 2, 2, 2, 9, 30, 9, 30, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 9, 2, 2, 2, 9, 9, 0, 2, 2, 0, 17,
18, 19, 20, 31, 32, 33, 32, 34, 0, 0, 0, 0, 35, 0, 0, 2,
30, 2, 0, 0, 0, 0, 0, 9, 36, 12, 15, 30, 2, 2, 9, 0,
30, 9, 2, 30, 9, 2, 0, 37, 18, 19, 31, 0, 27, 38, 27, 39,
0, 40, 0, 0, 0, 30, 2, 9, 9, 0, 0, 0, 2, 2, 2, 2,
2, 41, 42, 43, 0, 0, 0, 0, 0, 12, 15, 30, 2, 2, 2, 2,
30, 2, 30, 2, 2, 2, 2, 2, 2, 9, 2, 30, 2, 2, 0, 17,
18, 19, 20, 21, 27, 22, 35, 24, 0, 0, 0, 0, 0, 30, 41, 41,
44, 12, 29, 30, 2, 2, 2, 9, 30, 9, 2, 30, 2, 2, 0, 17,
45, 0, 0, 27, 22, 0, 0, 2, 30, 30, 0, 0, 0, 0, 0, 0,
0, 0, 46, 30, 2, 2, 9, 0, 2, 9, 2, 2, 0, 30, 9, 9,
2, 0, 30, 9, 0, 2, 9, 0, 2, 2, 2, 2, 2, 2, 0, 0,
23, 16, 47, 0, 48, 33, 48, 34, 0, 0, 0, 0, 35, 0, 0, 0,
0, 15, 29, 49, 2, 2, 2, 9, 2, 9, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 0, 17, 22, 16, 23, 47, 22, 38, 22, 39,
0, 0, 0, 27, 31, 2, 9, 0, 0, 10, 29, 30, 2, 2, 2, 9,
2, 2, 2, 30, 2, 2, 0, 17, 45, 0, 0, 35, 47, 0, 0, 0,
9, 50, 51, 0, 0, 0, 0, 0, 0, 11, 29, 2, 2, 2, 2, 9,
2, 2, 2, 2, 2, 2, 52, 53, 23, 19, 20, 31, 48, 33, 48, 34,
54, 0, 0, 0, 35, 0, 0, 0, 30, 12, 29, 30, 2, 2, 2, 2,
2, 2, 2, 2, 9, 0, 2, 2, 2, 2, 30, 2, 2, 2, 2, 30,
0, 2, 2, 2, 9, 0, 55, 0, 35, 23, 22, 31, 31, 18, 48, 48,
25, 0, 23, 0, 0, 0, 0, 0, 0, 2, 0, 2, 9, 0, 0, 0,
0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 2, 56, 56, 57, 0, 0,
18, 2, 2, 2, 2, 30, 2, 2, 2, 2, 2, 2, 2, 2, 2, 9,
0, 58, 21, 59, 22, 22, 20, 20, 46, 21, 11, 31, 11, 2, 2, 60,
61, 61, 61, 61, 61, 62, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61,
61, 61, 61, 61, 61, 61, 61, 63, 0, 0, 0, 0, 64, 0, 0, 0,
0, 2, 2, 2, 2, 2, 65, 45, 59, 66, 22, 22, 67, 68, 69, 70,
71, 2, 2, 2, 2, 2, 1, 0, 5, 2, 2, 2, 23, 20, 2, 2,
72, 71, 73, 74, 65, 73, 29, 29, 2, 52, 22, 53, 2, 2, 2, 2,
2, 2, 75, 76, 77, 29, 29, 78, 79, 2, 2, 2, 2, 2, 29, 45,
0, 2, 59, 80, 0, 0, 0, 0, 30, 2, 59, 47, 0, 0, 0, 0,
0, 2, 59, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 9,
2, 9, 59, 0, 0, 0, 0, 0, 0, 2, 2, 81, 45, 22, 59, 20,
48, 48, 48, 48, 15, 82, 83, 84, 85, 86, 87, 0, 0, 0, 0, 88,
0, 9, 0, 0, 30, 0, 89, 81, 90, 2, 2, 2, 2, 9, 0, 0,
0, 42, 42, 91, 92, 2, 2, 2, 2, 2, 2, 2, 2, 13, 9, 0,
0, 2, 2, 2, 2, 2, 2, 2, 9, 22, 80, 45, 22, 93, 61, 0,
0, 94, 95, 94, 94, 96, 97, 0, 0, 2, 2, 2, 2, 2, 2, 2,
0, 2, 2, 9, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 0,
0, 2, 2, 2, 2, 29, 0, 0, 0, 2, 2, 2, 2, 2, 9, 0,
0, 2, 2, 2, 52, 99, 45, 0, 0, 2, 2, 100, 101, 102, 103, 61,
63, 104, 16, 45, 22, 59, 21, 80, 48, 48, 76, 11, 11, 11, 105, 46,
40, 11, 106, 74, 2, 2, 2, 2, 2, 2, 2, 107, 22, 20, 20, 22,
48, 48, 22, 108, 2, 2, 2, 9, 0, 0, 0, 0, 0, 0, 109, 110,
110, 110, 110, 0, 0, 0, 0, 0, 0, 106, 74, 2, 2, 2, 2, 2,
2, 60, 61, 59, 25, 22, 111, 61, 2, 2, 2, 2, 107, 22, 23, 45,
45, 102, 112, 0, 0, 0, 0, 0, 0, 2, 2, 61, 18, 48, 23, 113,
102, 102, 102, 114, 115, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 30,
2, 11, 46, 116, 116, 116, 11, 116, 116, 15, 116, 116, 116, 26, 0, 40,
0, 0, 0, 117, 51, 11, 5, 0, 0, 0, 0, 0, 0, 0, 118, 0,
0, 0, 0, 0, 0, 0, 6, 119, 120, 42, 42, 5, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 120, 120, 121, 120, 120, 120, 120, 120, 120, 120,
120, 0, 0, 122, 0, 0, 0, 0, 0, 0, 7, 122, 0, 0, 0, 0,
0, 2, 2, 2, 52, 98, 45, 0, 0, 2, 2, 99, 100, 101, 102, 61,
63, 103, 16, 45, 22, 59, 21, 80, 48, 48, 76, 11, 11, 11, 104, 46,
40, 11, 105, 74, 2, 2, 2, 2, 2, 2, 2, 106, 22, 20, 20, 22,
48, 48, 22, 107, 2, 2, 2, 9, 0, 0, 0, 0, 0, 0, 108, 109,
109, 109, 109, 0, 0, 0, 0, 0, 0, 105, 74, 2, 2, 2, 2, 2,
2, 60, 61, 59, 25, 22, 110, 61, 2, 2, 2, 2, 106, 22, 23, 45,
45, 101, 111, 0, 0, 0, 0, 0, 0, 2, 2, 61, 18, 48, 23, 112,
101, 101, 101, 113, 114, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 30,
2, 11, 46, 115, 115, 115, 11, 115, 115, 15, 115, 115, 115, 26, 0, 40,
0, 0, 0, 116, 51, 11, 5, 0, 0, 0, 0, 0, 0, 0, 117, 0,
0, 0, 0, 0, 0, 0, 6, 118, 119, 42, 42, 5, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 119, 119, 120, 119, 119, 119, 119, 119, 119, 119,
119, 0, 0, 121, 0, 0, 0, 0, 0, 0, 7, 121, 0, 0, 0, 0,
0, 46, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9,
0, 0, 0, 0, 123, 123, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0,
30, 0, 0, 0, 0, 0, 0, 0, 124, 0, 123, 123, 0, 0, 0, 0,
0, 2, 53, 2, 108, 2, 10, 2, 2, 2, 65, 19, 16, 0, 0, 31,
0, 0, 0, 0, 122, 122, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0,
30, 0, 0, 0, 0, 0, 0, 0, 123, 0, 122, 122, 0, 0, 0, 0,
0, 2, 53, 2, 107, 2, 10, 2, 2, 2, 65, 19, 16, 0, 0, 31,
0, 2, 2, 0, 0, 0, 0, 0, 0, 29, 2, 2, 2, 2, 2, 2,
2, 2, 2, 125, 23, 23, 23, 23, 23, 23, 23, 126, 0, 0, 0, 0,
2, 2, 2, 124, 23, 23, 23, 23, 23, 23, 23, 125, 0, 0, 0, 0,
0, 11, 11, 11, 11, 11, 11, 11, 11, 11, 2, 0, 0, 0, 0, 0,
52, 2, 2, 2, 22, 22, 127, 116, 0, 2, 2, 2, 128, 20, 59, 20,
113, 102, 129, 0, 0, 0, 0, 0, 0, 11, 130, 2, 2, 2, 2, 2,
2, 2, 131, 23, 22, 20, 48, 132, 133, 134, 0, 0, 0, 0, 0, 0,
52, 2, 2, 2, 22, 22, 126, 115, 0, 2, 2, 2, 127, 20, 59, 20,
112, 101, 128, 0, 0, 0, 0, 0, 0, 11, 129, 2, 2, 2, 2, 2,
2, 2, 130, 23, 22, 20, 48, 131, 132, 133, 0, 0, 0, 0, 0, 0,
0, 2, 2, 52, 30, 2, 2, 2, 2, 2, 2, 2, 2, 10, 22, 59,
99, 76, 135, 136, 137, 0, 0, 0, 0, 2, 138, 2, 2, 2, 2, 139,
0, 30, 2, 42, 5, 0, 79, 15, 2, 140, 20, 53, 128, 140, 2, 2,
141, 10, 9, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 142, 21,
25, 0, 0, 143, 144, 0, 0, 0, 0, 2, 65, 45, 23, 80, 47, 145,
98, 76, 134, 135, 136, 0, 0, 0, 0, 2, 137, 2, 2, 2, 2, 138,
0, 30, 2, 42, 5, 0, 79, 15, 2, 139, 20, 53, 127, 139, 2, 2,
140, 10, 9, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 141, 21,
25, 0, 0, 142, 143, 0, 0, 0, 0, 2, 65, 45, 23, 80, 47, 144,
0, 81, 81, 81, 81, 81, 81, 81, 81, 0, 0, 0, 0, 0, 0, 0,
6, 120, 120, 120, 120, 121, 0, 0, 0, 2, 2, 2, 2, 2, 9, 2,
6, 119, 119, 119, 119, 120, 0, 0, 0, 2, 2, 2, 2, 2, 9, 2,
2, 2, 9, 2, 30, 2, 2, 2, 2, 2, 30, 2, 2, 2, 30, 9,
0, 128, 20, 27, 31, 0, 0, 146, 147, 2, 2, 30, 2, 30, 2, 2,
2, 2, 2, 2, 0, 14, 37, 0, 148, 2, 2, 13, 37, 0, 30, 2,
0, 127, 20, 27, 31, 0, 0, 145, 146, 2, 2, 30, 2, 30, 2, 2,
2, 2, 2, 2, 0, 14, 37, 0, 147, 2, 2, 13, 37, 0, 30, 2,
2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 2, 2,
9, 2, 2, 11, 41, 0, 0, 0, 0, 2, 2, 2, 0, 27, 22, 22,
30, 2, 2, 2, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 27, 38,
0, 2, 2, 2, 116, 116, 116, 116, 116, 149, 2, 9, 0, 0, 0, 0,
0, 2, 2, 2, 115, 115, 115, 115, 115, 148, 2, 9, 0, 0, 0, 0,
0, 2, 14, 14, 0, 0, 0, 0, 0, 9, 2, 2, 9, 2, 2, 2,
2, 30, 2, 9, 0, 30, 2, 0, 0, 150, 151, 152, 2, 2, 2, 2,
2, 2, 2, 2, 2, 22, 22, 20, 20, 20, 22, 22, 134, 0, 0, 0,
0, 0, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 2, 2, 2, 2,
2, 53, 52, 53, 0, 0, 0, 0, 154, 11, 74, 2, 2, 2, 2, 2,
2, 30, 2, 9, 0, 30, 2, 0, 0, 149, 150, 151, 2, 2, 2, 2,
2, 2, 2, 2, 2, 22, 22, 20, 20, 20, 22, 22, 133, 0, 0, 0,
0, 0, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 2, 2, 2, 2,
2, 53, 52, 53, 0, 0, 0, 0, 153, 11, 74, 2, 2, 2, 2, 2,
2, 18, 19, 21, 16, 24, 37, 0, 0, 0, 31, 0, 0, 0, 0, 0,
0, 11, 49, 2, 2, 2, 2, 2, 2, 2, 2, 2, 128, 20, 22, 155,
22, 21, 156, 157, 2, 2, 2, 2, 2, 0, 0, 65, 158, 0, 0, 0,
0, 11, 49, 2, 2, 2, 2, 2, 2, 2, 2, 2, 127, 20, 22, 154,
22, 21, 155, 156, 2, 2, 2, 2, 2, 0, 0, 65, 157, 0, 0, 0,
0, 2, 13, 0, 0, 0, 0, 0, 0, 2, 65, 25, 20, 20, 20, 22,
22, 108, 159, 0, 0, 56, 160, 31, 161, 30, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 23, 19, 22, 22, 162, 44, 0, 0, 0,
49, 128, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 9, 9, 2, 2,
22, 107, 158, 0, 0, 56, 159, 31, 160, 30, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 23, 19, 22, 22, 161, 44, 0, 0, 0,
49, 127, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 9, 9, 2, 2,
30, 2, 2, 2, 2, 2, 2, 2, 30, 2, 2, 2, 2, 2, 2, 2,
10, 18, 19, 21, 22, 163, 31, 0, 0, 11, 11, 30, 2, 2, 2, 9,
10, 18, 19, 21, 22, 162, 31, 0, 0, 11, 11, 30, 2, 2, 2, 9,
30, 9, 2, 30, 2, 2, 58, 17, 23, 16, 23, 47, 32, 33, 32, 34,
0, 0, 0, 0, 35, 0, 0, 0, 2, 2, 23, 0, 11, 11, 11, 46,
0, 11, 11, 46, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 30, 0,
9, 2, 2, 2, 30, 45, 59, 20, 20, 31, 33, 32, 32, 25, 164, 29,
165, 166, 37, 0, 0, 0, 0, 0, 0, 12, 26, 0, 0, 0, 0, 0,
0, 2, 2, 65, 25, 20, 20, 20, 22, 23, 126, 15, 17, 0, 0, 0,
0, 2, 2, 2, 2, 2, 0, 0, 167, 168, 0, 0, 0, 0, 0, 0,
0, 18, 19, 20, 20, 66, 99, 25, 161, 11, 169, 9, 0, 0, 0, 0,
9, 2, 2, 2, 30, 45, 59, 20, 20, 31, 33, 32, 32, 25, 163, 29,
164, 165, 37, 0, 0, 0, 0, 0, 0, 12, 26, 0, 0, 0, 0, 0,
0, 2, 2, 65, 25, 20, 20, 20, 22, 23, 125, 15, 17, 0, 0, 0,
0, 2, 2, 2, 2, 2, 0, 0, 166, 167, 0, 0, 0, 0, 0, 0,
0, 18, 19, 20, 20, 66, 98, 25, 160, 11, 168, 9, 0, 0, 0, 0,
0, 2, 2, 2, 2, 2, 2, 2, 65, 25, 20, 20, 0, 48, 48, 11,
170, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 20,
0, 23, 19, 20, 20, 21, 16, 82, 170, 38, 0, 0, 0, 0, 0, 0,
0, 2, 2, 2, 2, 2, 10, 171, 25, 20, 22, 22, 169, 9, 0, 0,
0, 2, 2, 2, 2, 2, 9, 43, 136, 23, 22, 20, 76, 21, 22, 0,
169, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 20,
0, 23, 19, 20, 20, 21, 16, 82, 169, 38, 0, 0, 0, 0, 0, 0,
0, 2, 2, 2, 2, 2, 10, 170, 25, 20, 22, 22, 168, 9, 0, 0,
0, 2, 2, 2, 2, 2, 9, 43, 135, 23, 22, 20, 76, 21, 22, 0,
0, 2, 2, 2, 9, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 18,
19, 20, 21, 22, 105, 170, 37, 0, 0, 2, 2, 2, 9, 30, 0, 2,
2, 2, 2, 30, 9, 2, 2, 2, 2, 23, 23, 18, 32, 33, 12, 172,
166, 173, 174, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 2, 2,
2, 65, 25, 20, 20, 0, 22, 23, 29, 108, 0, 33, 0, 0, 0, 0,
0, 52, 20, 22, 22, 22, 140, 2, 2, 2, 175, 141, 11, 15, 176, 61,
177, 0, 0, 1, 148, 0, 0, 0, 0, 52, 20, 22, 16, 19, 20, 2,
2, 2, 2, 159, 159, 159, 178, 178, 178, 178, 178, 178, 15, 179, 0, 30,
0, 22, 20, 20, 31, 22, 22, 11, 170, 0, 61, 61, 61, 61, 61, 61,
61, 66, 21, 82, 46, 0, 0, 0, 0, 2, 2, 2, 9, 2, 30, 2,
2, 52, 22, 22, 31, 0, 38, 22, 27, 11, 160, 180, 181, 0, 0, 0,
0, 2, 2, 2, 30, 9, 2, 2, 2, 2, 2, 2, 2, 2, 23, 23,
47, 22, 35, 82, 68, 0, 0, 0, 0, 2, 182, 66, 47, 0, 0, 0,
0, 11, 183, 2, 2, 2, 2, 2, 2, 2, 2, 23, 22, 20, 31, 0,
48, 16, 144, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 157, 0,
0, 184, 184, 184, 184, 184, 184, 184, 184, 185, 185, 185, 186, 187, 185, 184,
184, 188, 184, 184, 189, 190, 190, 190, 190, 190, 190, 190, 0, 0, 0, 0,
0, 184, 184, 184, 184, 184, 191, 0, 0, 2, 2, 2, 2, 2, 2, 2,
22, 22, 22, 22, 22, 22, 192, 193, 194, 11, 11, 11, 46, 0, 0, 0,
0, 29, 74, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 65, 47,
0, 2, 2, 2, 2, 2, 9, 0, 58, 195, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0,
40, 116, 26, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 30, 2, 2, 2, 2, 2, 0, 58,
37, 0, 6, 120, 120, 120, 121, 0, 0, 11, 11, 11, 49, 2, 2, 2,
0, 2, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2,
46, 2, 2, 2, 2, 2, 2, 11, 11, 2, 2, 2, 2, 2, 2, 22,
22, 2, 2, 2, 2, 2, 2, 2, 20, 2, 2, 44, 44, 44, 92, 0,
0, O, O, O, GB, B, B, O, SB, O, SE, GB, O, O, WJ,FMPst,
FMPst, O, CGJ, B, O, B,VMAbv,VMAbv,VMAbv, O,VMAbv, B,CMBlw,CMBlw,CMBlw,VMAbv,
VMPst, VAbv, VPst,CMBlw, B, VPst, VPre, VPst, VBlw, VBlw, VBlw, VBlw, VAbv, VAbv, VAbv, VPst,
VPst, VPst, H, VPre, VPst,VMBlw, O, O, VAbv, GB,VMAbv,VMPst,VMPst, O, B, VBlw,
O, O, VPre, VPre, O, VPre, H, O, VPst,FMAbv, O,CMBlw, O, VAbv, O, VAbv,
H, O,VMBlw,VMAbv,CMAbv, GB, GB, O, MBlw,CMAbv,CMAbv, VPst, VAbv,VMAbv, O, VPst,
O, VPre, VPre,VMAbv, B, O, CS, CS,VMPst, B, VAbv, VAbv, B, R, O, HVM,
O, O,FMBlw, O,CMAbv, O,CMBlw, VAbv, VBlw, B, SUB, SUB, SUB, O, SUB, SUB,
O,FMBlw, O, B, VPst, VBlw, VPre,VMAbv,VMBlw,VMPst, IS, VAbv, MPst, MPre, MBlw, MBlw,
B, MBlw, MBlw, VPst,VMPst,VMPst, B, MBlw, VPst, VPre, VAbv, VAbv,VMPst,VMPst,VMBlw, B,
VMPst, VBlw, VPst, CGJ, CGJ, VPst,VMAbv,VMAbv,FMAbv, FAbv,CMAbv,FMAbv,VMAbv,FMAbv, VAbv, IS,
FMAbv, B,FMAbv, B, CGJ, WJ, CGJ, GB,CMAbv,CMAbv, B, GB, B, VAbv, SUB, FPst,
FPst,VMBlw, FPst, FPst, FBlw,VMAbv,FMBlw, VAbv, VPre, B, MPre, MBlw, SUB, FAbv, FAbv, MAbv,
SUB, Sk, VPst, VAbv,VMAbv,VMAbv, FAbv,CMAbv, VPst, H, B, O,SMAbv,SMAbv,SMAbv, VPst,
IS, RK, RK, VBlw, FAbv,VMPre,VMPre,FMAbv,CMBlw,VMBlw,VMBlw,VMAbv, CS, O,FMAbv, ZWNJ,
CGJ, WJ, WJ, WJ, O,FMPst, O, SB, SE, O, H, MPst, VPst, H,VMAbv, VAbv,
VMBlw, B, VBlw, FPst, VPst, FAbv,VMPst, B,CMAbv, VAbv, MBlw, MPst, MBlw, H, O, VBlw,
MPst, MPre, MAbv, MBlw, O, B, FAbv, FAbv, FPst, VBlw, B, VBlw,VMAbv, B, VPre, O,
VMPst, IS, O,VMPst, VBlw, VPst,VMBlw,VMBlw,VMAbv, O, IS,VMBlw, B,VMPst,VMAbv,VMPst,
CS, CS, B, N, N, O, HN, VPre, VBlw, VAbv, IS,CMAbv, O, VPst, B, R,
R,CMBlw, VAbv, VPre,VMAbv,VMAbv, H, VAbv,CMBlw,VMPst, O,VMAbv,CMBlw, IS, R,FMAbv,
B, CS, CS, H,CMBlw,VMPst, H,VMPst, VAbv,VMAbv, VPst, MPst, R, MPst,CMBlw, B,
FMBlw, CS, SUB, SUB, GB, FBlw, FBlw,CMAbv, IS, VBlw, IS, R, MBlw, GB, VAbv, R,
VMPst, G, G, J, J, J, SB, SE, J, HR, G, G, HM, HM, HM, G,
O, MPre, MPre, MPst,VMAbv, MBlw, VBlw, O, VBlw,
19, 20, 21, 22, 104, 169, 37, 0, 0, 2, 2, 2, 9, 30, 0, 2,
2, 2, 2, 30, 9, 2, 2, 2, 2, 23, 23, 18, 32, 33, 12, 171,
165, 172, 173, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 2, 2,
2, 65, 25, 20, 20, 0, 22, 23, 29, 107, 0, 33, 0, 0, 0, 0,
0, 52, 20, 22, 22, 22, 139, 2, 2, 2, 174, 140, 11, 15, 175, 61,
176, 0, 0, 1, 147, 0, 0, 0, 0, 52, 20, 22, 16, 19, 20, 2,
2, 2, 2, 158, 158, 158, 177, 177, 177, 177, 177, 177, 15, 178, 0, 30,
0, 16, 20, 16, 16, 0, 0, 0, 0, 22, 20, 20, 31, 22, 22, 11,
169, 0, 61, 61, 61, 61, 61, 61, 61, 66, 21, 82, 46, 0, 0, 0,
0, 2, 2, 2, 9, 2, 30, 2, 2, 52, 22, 22, 31, 0, 38, 22,
27, 11, 159, 179, 180, 0, 0, 0, 0, 2, 2, 2, 30, 9, 2, 2,
2, 2, 2, 2, 2, 2, 23, 23, 47, 22, 35, 82, 68, 0, 0, 0,
0, 2, 181, 66, 47, 0, 0, 0, 0, 11, 182, 2, 2, 2, 2, 2,
2, 2, 2, 23, 22, 20, 31, 0, 48, 16, 143, 0, 0, 0, 0, 0,
0, 2, 2, 2, 2, 2, 156, 0, 0, 183, 183, 183, 183, 183, 183, 183,
183, 184, 184, 184, 185, 186, 184, 183, 183, 187, 183, 183, 188, 189, 189, 189,
189, 189, 189, 189, 0, 0, 0, 0, 0, 183, 183, 183, 183, 183, 190, 0,
0, 2, 2, 2, 2, 2, 2, 2, 22, 22, 22, 22, 22, 22, 191, 192,
193, 11, 11, 11, 46, 0, 0, 0, 0, 29, 74, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 65, 47, 0, 2, 2, 2, 2, 2, 9, 0,
58, 194, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 0, 0, 0, 40, 115, 26, 0, 0, 0, 0, 0,
0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
30, 2, 2, 2, 2, 2, 0, 58, 37, 0, 6, 119, 119, 119, 120, 0,
0, 11, 11, 11, 49, 2, 2, 2, 0, 2, 2, 2, 2, 2, 0, 0,
2, 2, 2, 2, 2, 2, 2, 2, 46, 2, 2, 2, 2, 2, 2, 11,
11, 2, 2, 2, 2, 2, 2, 22, 22, 2, 2, 2, 2, 2, 2, 2,
20, 2, 2, 44, 44, 44, 92, 0, 0, O, O, O, GB, B, B, O,
SB, O, SE, GB, O, O, WJ,FMPst,FMPst, O, CGJ, B, O, B,VMAbv,VMAbv,
VMAbv, O,VMAbv, B,CMBlw,CMBlw,CMBlw,VMAbv,VMPst, VAbv, VPst,CMBlw, B, VPst, VPre, VPst,
VBlw, VBlw, VBlw, VBlw, VAbv, VAbv, VAbv, VPst, VPst, VPst, H, VPre, VPst,VMBlw, O, O,
VAbv, GB,VMAbv,VMPst,VMPst, O, B, VBlw, O, O, VPre, VPre, O, VPre, H, O,
VPst,FMAbv, O,CMBlw, O, VAbv, O, VAbv, H, O,VMBlw,VMAbv,CMAbv, GB, GB, O,
MBlw,CMAbv,CMAbv, VPst, VAbv,VMAbv, O, VPst, O, VPre, VPre,VMAbv, B, O, CS, CS,
VMPst, B, VAbv, VAbv, B, R, O, HVM, O, O,FMBlw, O,CMAbv, O,CMBlw, VAbv,
VBlw, B, SUB, SUB, SUB, O, SUB, SUB, O,FMBlw, O, B, VPst, VBlw, VPre,VMAbv,
VMBlw,VMPst, IS, VAbv, MPst, MPre, MBlw, MBlw, B, MBlw, MBlw, VPst,VMPst,VMPst, B, MBlw,
VPst, VPre, VAbv, VAbv,VMPst,VMPst,VMBlw, B,VMPst, VBlw, VPst, CGJ, CGJ, VPst,VMAbv,VMAbv,
FMAbv, FAbv,CMAbv,FMAbv,VMAbv,FMAbv, VAbv, IS,FMAbv, B,FMAbv, B, CGJ, WJ, CGJ, GB,
CMAbv,CMAbv, B, VAbv, SUB, FPst, FPst,VMBlw, FPst, FPst, FBlw,VMAbv,FMBlw, VAbv, VPre, B,
MPre, MBlw, SUB, FAbv, FAbv, MAbv, SUB, Sk, VPst, VAbv,VMAbv,VMAbv, FAbv,CMAbv, VPst, H,
B, O,SMAbv,SMAbv,SMAbv, VPst, IS, RK, RK, VBlw, FAbv,VMPre,VMPre,FMAbv,CMBlw,VMBlw,
VMBlw,VMAbv, CS, O,FMAbv, ZWNJ, CGJ, WJ, WJ, WJ, O,FMPst, O, SB, SE, O,
H, MPst, VPst, H,VMAbv, VAbv,VMBlw, B, VBlw, FPst, VPst, FAbv,VMPst, B,CMAbv, VAbv,
MBlw, MPst, MBlw, H, O, VBlw, MPst, MPre, MAbv, MBlw, O, B, FAbv, FAbv, FPst, VBlw,
B, VBlw,VMAbv, B, VPre, O,VMPst, IS, O,VMPst, VBlw, VPst,VMBlw,VMBlw,VMAbv, O,
IS,VMBlw, B,VMPst,VMAbv,VMPst, CS, CS, B, N, N, O, HN, VPre, VBlw, VAbv,
IS,CMAbv, O, VPst, B, R, R,CMBlw, VAbv, VPre,VMAbv,VMAbv, H, VAbv,CMBlw,VMPst,
O,VMAbv,CMBlw, IS, R,FMAbv, B, CS, CS, H,CMBlw,VMPst, H,VMPst, VAbv,VMAbv,
VPst, MPst, R, MPst,CMBlw, B,FMBlw, CS, SUB, SUB, GB, FBlw, FBlw,CMAbv, IS, VBlw,
IS, R, MBlw, GB, VAbv, R,VMPst, G, G, J, J, J, SB, SE, J, HR,
G, G, HM, HM, HM, G, O, MPre, MPre, MPst,VMAbv, MBlw, VBlw, O, VBlw,
};
static const uint16_t hb_use_u16[486]=
static const uint16_t hb_use_u16[488]=
{
0, 0, 1, 2, 0, 3, 4, 5, 0, 6, 7, 0, 8, 0, 9, 10,
11, 12, 10, 13, 14, 10, 10, 15, 16, 17, 18, 19, 20, 21, 22, 23,
@ -631,28 +630,28 @@ static const uint16_t hb_use_u16[486]=
31, 66, 67, 68, 10, 69, 70, 10, 71, 72, 73, 74, 75, 76, 77, 0,
10, 10, 78, 79, 80, 81, 82, 83, 84, 85, 10, 86, 10, 87, 10, 88,
89, 90, 10, 91, 92, 93, 2, 0, 94, 0, 10, 95, 96, 10, 97, 0,
98, 99,100,101, 31, 10,102,103,104, 10,105,106, 10,107, 10,108,
109,110, 2, 2,111, 10, 10,112,113, 2,114,115,116, 10,117, 10,
118,119,120,121,122, 0, 0,123,124,125, 0,126,127,128,129, 0,
130,131,132, 0, 0,133,134, 0,135, 0, 0, 10,136,137,138, 0,
139, 10,140, 0, 10,141,142, 10, 10,143,144, 2,145,146,147, 10,
148,149,150, 10, 10,151,152, 2,153, 99,154,155,156, 2, 10,157,
10,158,159, 0,160,161,162, 2,163, 0, 0,164, 0,165, 0,166,
166,167, 34,168,169,170, 10,171, 95, 0,172, 0, 10,173,174, 0,
175, 2,176, 10,177, 0,178,173,179,180,181, 0, 0,182,183, 0,
184, 10, 10,185,186,187,188,189,190, 10, 10,191,192, 0,193, 10,
194,195,196, 10, 10,197, 10,198,199,106,200,103, 10, 34,201,202,
203, 0,204,205, 95, 10, 10,206,207, 2,208, 21, 22,209,210,211,
212,213,214, 10, 10,215,216,217,218, 0, 10,219,220,221,222, 0,
200, 10, 10,223,224, 2,225,226,227,228, 10,229,230, 2,231,232,
2, 10,141, 0, 10,233,234,104,235, 0,236,237,238,239, 10,240,
241, 2,242, 10, 10,243,244, 0,245, 10, 10,246,247,248,249,250,
22, 10,225,251, 8, 10, 71, 19, 10,252, 74,253,254, 10, 10,255,
256, 2,257, 10,258,259, 10,260,261, 49, 10,262,263,264,265,265,
265,266,267,268,265,269, 10,270,271, 2, 10,272,273, 10,274, 2,
275,276,277,277,278,279,280, 0, 10,177, 0,281,106, 71, 95,282,
0,283, 71,284,285, 0,286, 0,287, 2,288, 2,289,106,290, 2,
130,130,163,163,163,130,
10, 98, 99,100, 31, 10,101,102,103, 10,104,105, 10,106, 10,107,
108,109, 2, 2,110, 10, 10,111,112, 2,113,114,115, 10,116, 10,
117,118,119,120,121, 0, 0,122,123,124, 0,125,126,127,128, 0,
129,130,131, 0, 0,132,133, 0,134, 0, 0, 10,135,136,137, 0,
138, 10,139, 0, 10,140,141, 10, 10,142,143, 2,144,145,146, 10,
147,148,149, 10, 10,150,151, 2,152, 98,153,154,155, 2, 10,156,
10,157,158, 0,159,160,161, 2,162, 0, 0,163, 0,164, 0,165,
165,166, 34,167,168,169, 10,170, 95, 0,171, 0, 10,172,173, 0,
174, 2,175, 10,176, 0,177,172,178,179,180, 0, 0,181,182, 0,
183, 10, 10,184,185,186,187,188,189, 10, 10,190,191, 0,192, 10,
193,194,195, 10, 10,196, 10,197,198,105,199,102, 10, 34,200,201,
202, 0,203,204, 95, 10, 10,205,206, 2,207, 21, 22,208,209,210,
211,212,213, 10, 10,214,215,216,217, 0, 10,218,219,220,221, 0,
199, 10, 10,222,223, 2,224,225,226,227, 10,228,229, 2,230,231,
2, 10,140, 0, 10,232,233,103,234, 0,235,236,237,238, 10,239,
240, 2,241, 10, 10,242,243, 0,244, 10, 10,245,246,247,248,249,
250, 0, 22, 10,224,251, 8, 10, 71, 19, 10,252, 74,253,254, 10,
10,255,256, 2,257, 10,258,259, 10,260,261, 49, 10,262,263,264,
265,265,265,266,267,268,265,269, 10,270,271, 2, 10,272,273, 10,
274, 2,275,276,277,277,278,279,280, 0, 10,176, 0,281,105, 71,
95,282, 0,283, 71,284,285, 0,286, 0,287, 2,288, 2,289,105,
290, 2,129,129,162,162,162,129,
};
static inline uint8_t hb_use_b4 (const uint8_t* a, unsigned i)
@ -661,11 +660,13 @@ static inline uint8_t hb_use_b4 (const uint8_t* a, unsigned i)
}
static inline uint8_t hb_use_get_category (unsigned u)
{
return u<921600 ? hb_use_u8[3265u+(((hb_use_u8[937u+(((hb_use_u16[((hb_use_u8[369u+(((hb_use_u8[113u+(((hb_use_b4(hb_use_u8,u>>1>>3>>1>>3>>4))<<4)+((u>>1>>3>>1>>3)&15))])<<3)+((u>>1>>3>>1)&7))])<<1)+((u>>1>>3)&1)])<<3)+((u>>1)&7))])<<1)+((u)&1))] : O;
return u<921600 ? hb_use_u8[3273u+((hb_use_u8[945u+((hb_use_u16[((hb_use_u8[369u+((hb_use_u8[113u+((hb_use_b4(hb_use_u8,((((((((((u)>>1))>>3))>>1))>>3))>>4)))<<4)+((((((((((u)>>1))>>3))>>1))>>3))&15)])<<3)+((((((((u)>>1))>>3))>>1))&7)])<<1)+((((((u)>>1))>>3))&1)])<<3)+((((u)>>1))&7)])<<1)+((u)&1)] : O;
}
#endif
#undef B
#undef CGJ
#undef CS

View file

@ -10,8 +10,8 @@
* # Date: 2015-03-12, 21:17:00 GMT [AG]
* # Date: 2019-11-08, 23:22:00 GMT [AG]
*
* # Scripts-16.0.0.txt
* # Date: 2024-04-30, 21:48:40 GMT
* # Scripts-17.0.0.txt
* # Date: 2025-07-24, 13:28:55 GMT
*/
#include "hb.hh"

View file

@ -396,6 +396,12 @@ hb_ot_shaper_categorize (hb_script_t script,
case HB_SCRIPT_TODHRI:
case HB_SCRIPT_TULU_TIGALARI:
/* Unicode-17.0 additions */
case HB_SCRIPT_BERIA_ERFE:
case HB_SCRIPT_SIDETIC:
case HB_SCRIPT_TAI_YO:
case HB_SCRIPT_TOLONG_SIKI:
/* If the designer designed the font for the 'DFLT' script,
* (or we ended up arbitrarily pick 'latn'), use the default shaper.
* Otherwise, use the specific shaper.

View file

@ -7,7 +7,7 @@
* on files with these headers:
*
* <meta name="updated_at" content="2024-12-06T06:35:00Z" />
* File-Date: 2025-03-10
* File-Date: 2025-08-25
*/
#ifndef HB_OT_TAG_TABLE_HH
@ -704,7 +704,7 @@ static const LangTag ot_languages3[] = {
/*{HB_TAG('g','u','z',' '), HB_TAG('G','U','Z',' ')},*/ /* Gusii */
{HB_TAG('g','w','i',' '), HB_TAG('A','T','H',' ')}, /* Gwichʼin -> Athapaskan */
{HB_TAG('g','y','n',' '), HB_TAG('C','P','P',' ')}, /* Guyanese Creole English -> Creoles */
{HB_TAG('h','a','a',' '), HB_TAG('A','T','H',' ')}, /* Han -> Athapaskan */
{HB_TAG('h','a','a',' '), HB_TAG('A','T','H',' ')}, /* Hän -> Athapaskan */
{HB_TAG('h','a','e',' '), HB_TAG('O','R','O',' ')}, /* Eastern Oromo -> Oromo */
{HB_TAG('h','a','i',' '), HB_TAG('H','A','I','0')}, /* Haida [macrolanguage] */
{HB_TAG('h','a','k',' '), HB_TAG('Z','H','S',' ')}, /* Hakka Chinese -> Chinese, Simplified */
@ -921,7 +921,7 @@ static const LangTag ot_languages3[] = {
{HB_TAG('k','v','t',' '), HB_TAG('K','R','N',' ')}, /* Lahta Karen -> Karen */
{HB_TAG('k','v','u',' '), HB_TAG('K','R','N',' ')}, /* Yinbaw Karen -> Karen */
{HB_TAG('k','v','y',' '), HB_TAG('K','R','N',' ')}, /* Yintale Karen -> Karen */
/*{HB_TAG('k','w','k',' '), HB_TAG('K','W','K',' ')},*/ /* Kwakiutl -> Kwakʼwala */
/*{HB_TAG('k','w','k',' '), HB_TAG('K','W','K',' ')},*/ /* Kwakʼwala */
{HB_TAG('k','w','w',' '), HB_TAG('C','P','P',' ')}, /* Kwinti -> Creoles */
{HB_TAG('k','w','y',' '), HB_TAG('K','O','N','0')}, /* San Salvador Kongo -> Kongo */
{HB_TAG('k','x','c',' '), HB_TAG('K','M','S',' ')}, /* Konso -> Komso */

View file

@ -388,13 +388,18 @@ struct avar
const auto &var_store = this+v2.varStore;
auto *var_store_cache = var_store.create_cache ();
hb_vector_t<int> coords_2_14;
coords_2_14.resize (coords_length);
for (unsigned i = 0; i < coords_length; i++)
coords_2_14[i] = roundf (coords[i] / 4.f); // 16.16 -> 2.14
hb_vector_t<int> out;
out.alloc (coords_length);
for (unsigned i = 0; i < coords_length; i++)
{
int v = coords[i];
uint32_t varidx = varidx_map.map (i);
float delta = var_store.get_delta (varidx, coords, coords_length, var_store_cache);
float delta = var_store.get_delta (varidx, coords_2_14.arrayZ, coords_2_14.length, var_store_cache);
v += roundf (delta * 4); // 2.14 -> 16.16
v = hb_clamp (v, -(1<<16), +(1<<16));
out.push (v);

File diff suppressed because it is too large Load diff

View file

@ -66,7 +66,7 @@ struct cvar
if (!TupleVariationData<>::get_tuple_iterator (var_data_bytes, axis_count, this,
shared_indices, &iterator))
return false;
return tupleVariationData.decompile_tuple_variations (point_count, is_gvar, iterator,
axes_old_index_tag_map,
shared_indices,
@ -113,7 +113,7 @@ struct cvar
bool apply_to_all = (indices.length == 0);
unsigned num_deltas = apply_to_all ? num_cvt_item : indices.length;
if (unlikely (!unpacked_deltas.resize (num_deltas, false))) return false;
if (unlikely (!unpacked_deltas.resize_dirty (num_deltas))) return false;
if (unlikely (!TupleVariationData<>::decompile_deltas (p, unpacked_deltas, end))) return false;
for (unsigned int i = 0; i < num_deltas; i++)
@ -158,7 +158,8 @@ struct cvar
tuple_variations))
return_trace (false);
if (!tuple_variations.instantiate (c->plan->axes_location, c->plan->axes_triple_distances))
optimize_scratch_t scratch;
if (!tuple_variations.instantiate (c->plan->axes_location, c->plan->axes_triple_distances, scratch))
return_trace (false);
if (!tuple_variations.compile_bytes (c->plan->axes_index_map, c->plan->axes_old_index_tag_map,

View file

@ -66,12 +66,14 @@ struct glyph_variations_t
hb_vector_t<tuple_variations_t> glyph_variations;
hb_vector_t<char> compiled_shared_tuples;
hb_vector_t<F2DOT14> compiled_shared_tuples;
private:
unsigned shared_tuples_count = 0;
/* shared coords-> index map after instantiation */
hb_hashmap_t<const hb_vector_t<char>*, unsigned> shared_tuples_idx_map;
hb_hashmap_t<const hb_vector_t<F2DOT14>*, unsigned> shared_tuples_idx_map;
hb_alloc_pool_t pool;
public:
unsigned compiled_shared_tuples_count () const
@ -128,6 +130,7 @@ struct glyph_variations_t
iterator, &(plan->axes_old_index_tag_map),
shared_indices, shared_tuples,
tuple_vars, /* OUT */
&pool,
is_composite_glyph))
return false;
glyph_variations.push (std::move (tuple_vars));
@ -139,6 +142,7 @@ struct glyph_variations_t
{
unsigned count = plan->new_to_old_gid_list.length;
bool iup_optimize = false;
optimize_scratch_t scratch;
iup_optimize = plan->flags & HB_SUBSET_FLAGS_OPTIMIZE_IUP_DELTAS;
for (unsigned i = 0; i < count; i++)
{
@ -146,7 +150,7 @@ struct glyph_variations_t
contour_point_vector_t *all_points;
if (!plan->new_gid_contour_points_map.has (new_gid, &all_points))
return false;
if (!glyph_variations[i].instantiate (plan->axes_location, plan->axes_triple_distances, all_points, iup_optimize))
if (!glyph_variations[i].instantiate (plan->axes_location, plan->axes_triple_distances, scratch, &pool, all_points, iup_optimize))
return false;
}
return true;
@ -161,7 +165,8 @@ struct glyph_variations_t
if (!vars.compile_bytes (axes_index_map, axes_old_index_tag_map,
true, /* use shared points*/
true,
&shared_tuples_idx_map))
&shared_tuples_idx_map,
&pool))
return false;
return true;
@ -172,20 +177,21 @@ struct glyph_variations_t
{
/* key is pointer to compiled_peak_coords inside each tuple, hashing
* function will always deref pointers first */
hb_hashmap_t<const hb_vector_t<char>*, unsigned> coords_count_map;
hb_hashmap_t<const hb_vector_t<F2DOT14>*, unsigned> coords_count_map;
/* count the num of shared coords */
for (tuple_variations_t& vars: glyph_variations)
{
for (tuple_delta_t& var : vars.tuple_vars)
{
if (!var.compile_peak_coords (axes_index_map, axes_old_index_tag_map))
if (!var.compile_coords (axes_index_map, axes_old_index_tag_map, &pool))
return false;
unsigned* count;
if (coords_count_map.has (&(var.compiled_peak_coords), &count))
coords_count_map.set (&(var.compiled_peak_coords), *count + 1);
unsigned *count;
unsigned hash = hb_hash (&var.compiled_peak_coords);
if (coords_count_map.has_with_hash (&(var.compiled_peak_coords), hash, &count))
(*count)++;
else
coords_count_map.set (&(var.compiled_peak_coords), 1);
coords_count_map.set_with_hash (&(var.compiled_peak_coords), hash, 1);
}
}
@ -193,66 +199,45 @@ struct glyph_variations_t
return false;
/* add only those coords that are used more than once into the vector and sort */
hb_vector_t<const hb_vector_t<char>*> shared_coords;
if (unlikely (!shared_coords.alloc (coords_count_map.get_population ())))
return false;
for (const auto _ : coords_count_map.iter ())
{
if (_.second == 1) continue;
shared_coords.push (_.first);
}
hb_vector_t<hb_pair_t<const hb_vector_t<F2DOT14>*, unsigned>> shared_coords {
+ hb_iter (coords_count_map)
| hb_filter ([] (const hb_pair_t<const hb_vector_t<F2DOT14>*, unsigned>& p) { return p.second > 1; })
};
if (unlikely (shared_coords.in_error ())) return false;
/* no shared tuples: no coords are used more than once */
if (!shared_coords) return true;
/* sorting based on the coords frequency first (high to low), then compare
* the coords bytes */
hb_qsort (shared_coords.arrayZ, shared_coords.length, sizeof (hb_vector_t<char>*), _cmp_coords, (void *) (&coords_count_map));
shared_coords.qsort (_cmp_coords);
/* build shared_coords->idx map and shared tuples byte array */
shared_tuples_count = hb_min (0xFFFu + 1, shared_coords.length);
unsigned len = shared_tuples_count * (shared_coords[0]->length);
unsigned len = shared_tuples_count * (shared_coords[0].first->length);
if (unlikely (!compiled_shared_tuples.alloc (len)))
return false;
for (unsigned i = 0; i < shared_tuples_count; i++)
{
shared_tuples_idx_map.set (shared_coords[i], i);
shared_tuples_idx_map.set (shared_coords[i].first, i);
/* add a concat() in hb_vector_t? */
for (char c : shared_coords[i]->iter ())
for (auto c : shared_coords[i].first->iter ())
compiled_shared_tuples.push (c);
}
return true;
}
static int _cmp_coords (const void *pa, const void *pb, void *arg)
static int _cmp_coords (const void *pa, const void *pb)
{
const hb_hashmap_t<const hb_vector_t<char>*, unsigned>* coords_count_map =
reinterpret_cast<const hb_hashmap_t<const hb_vector_t<char>*, unsigned>*> (arg);
const hb_pair_t<hb_vector_t<F2DOT14> *, unsigned> *a = (const hb_pair_t<hb_vector_t<F2DOT14> *, unsigned> *) pa;
const hb_pair_t<hb_vector_t<F2DOT14> *, unsigned> *b = (const hb_pair_t<hb_vector_t<F2DOT14> *, unsigned> *) pb;
/* shared_coords is hb_vector_t<const hb_vector_t<char>*> so casting pa/pb
* to be a pointer to a pointer */
const hb_vector_t<char>** a = reinterpret_cast<const hb_vector_t<char>**> (const_cast<void*>(pa));
const hb_vector_t<char>** b = reinterpret_cast<const hb_vector_t<char>**> (const_cast<void*>(pb));
if (a->second != b->second)
return b->second - a->second; // high to low
bool has_a = coords_count_map->has (*a);
bool has_b = coords_count_map->has (*b);
if (has_a && has_b)
{
unsigned a_num = coords_count_map->get (*a);
unsigned b_num = coords_count_map->get (*b);
if (a_num != b_num)
return b_num - a_num;
return (*b)->as_array().cmp ((*a)->as_array ());
}
else if (has_a) return -1;
else if (has_b) return 1;
else return 0;
return b->first->as_array().cmp (a->first->as_array ());
}
template<typename Iterator,
@ -402,9 +387,9 @@ struct gvar_GVAR
out->sharedTuples = 0;
else
{
hb_array_t<const char> shared_tuples = glyph_vars.compiled_shared_tuples.as_array ().copy (c);
hb_array_t<const F2DOT14> shared_tuples = glyph_vars.compiled_shared_tuples.as_array ().copy (c);
if (!shared_tuples.arrayZ) return_trace (false);
out->sharedTuples = shared_tuples.arrayZ - (char *) out;
out->sharedTuples = (const char *) shared_tuples.arrayZ - (char *) out;
}
char *glyph_var_data = c->start_embed<char> ();
@ -686,7 +671,7 @@ struct gvar_GVAR
if (!deltas)
{
if (unlikely (!deltas_vec.resize (count, false))) return false;
if (unlikely (!deltas_vec.resize_dirty (count))) return false;
deltas = deltas_vec.as_array ();
hb_memset (deltas.arrayZ + (phantom_only ? count - 4 : 0), 0,
(phantom_only ? 4 : count) * sizeof (deltas[0]));
@ -703,9 +688,9 @@ struct gvar_GVAR
bool apply_to_all = (indices.length == 0);
unsigned num_deltas = apply_to_all ? points.length : indices.length;
unsigned start_deltas = (phantom_only && num_deltas >= 4 ? num_deltas - 4 : 0);
if (unlikely (!x_deltas.resize (num_deltas, false))) return false;
if (unlikely (!x_deltas.resize_dirty (num_deltas))) return false;
if (unlikely (!GlyphVariationData::decompile_deltas (p, x_deltas, end, false, start_deltas))) return false;
if (unlikely (!y_deltas.resize (num_deltas, false))) return false;
if (unlikely (!y_deltas.resize_dirty (num_deltas))) return false;
if (unlikely (!GlyphVariationData::decompile_deltas (p, y_deltas, end, false, start_deltas))) return false;
if (!apply_to_all)

View file

@ -42,57 +42,62 @@ struct index_map_subset_plan_t
VORG_INDEX
};
void init (const DeltaSetIndexMap &index_map,
void init (const DeltaSetIndexMap *index_map,
hb_inc_bimap_t &outer_map,
hb_vector_t<hb_set_t *> &inner_sets,
const hb_subset_plan_t *plan,
bool bypass_empty = true)
{
map_count = 0;
outer_bit_count = 0;
inner_bit_count = 1;
max_inners.init ();
output_map.init ();
if (bypass_empty && !index_map.get_map_count ()) return;
if (bypass_empty && (!index_map || !index_map->get_map_count ())) return;
unsigned int last_val = (unsigned int)-1;
hb_codepoint_t last_gid = HB_CODEPOINT_INVALID;
outer_bit_count = (index_map.get_width () * 8) - index_map.get_inner_bit_count ();
max_inners.resize (inner_sets.length);
for (unsigned i = 0; i < inner_sets.length; i++) max_inners[i] = 0;
/* Search backwards for a map value different from the last map value */
auto &new_to_old_gid_list = plan->new_to_old_gid_list;
unsigned count = new_to_old_gid_list.length;
for (unsigned j = count; j; j--)
if (!index_map)
{
hb_codepoint_t gid = new_to_old_gid_list.arrayZ[j - 1].first;
hb_codepoint_t old_gid = new_to_old_gid_list.arrayZ[j - 1].second;
unsigned int v = index_map.map (old_gid);
if (last_gid == HB_CODEPOINT_INVALID)
map_count = new_to_old_gid_list.tail ().first + 1;
}
else
{
for (unsigned j = count; j; j--)
{
last_val = v;
last_gid = gid;
continue;
hb_codepoint_t gid = new_to_old_gid_list.arrayZ[j - 1].first;
hb_codepoint_t old_gid = new_to_old_gid_list.arrayZ[j - 1].second;
unsigned int v = index_map->map (old_gid);
if (last_gid == HB_CODEPOINT_INVALID)
{
last_val = v;
last_gid = gid;
continue;
}
if (v != last_val)
break;
last_gid = gid;
}
if (v != last_val)
break;
last_gid = gid;
if (unlikely (last_gid == (hb_codepoint_t)-1)) return;
map_count = last_gid + 1;
}
if (unlikely (last_gid == (hb_codepoint_t)-1)) return;
map_count = last_gid + 1;
for (auto _ : plan->new_to_old_gid_list)
{
hb_codepoint_t gid = _.first;
if (gid >= map_count) break;
hb_codepoint_t old_gid = _.second;
unsigned int v = index_map.map (old_gid);
unsigned int v = index_map ? index_map->map (old_gid): old_gid;
unsigned int outer = v >> 16;
unsigned int inner = v & 0xFFFF;
outer_map.add (outer);
@ -113,6 +118,9 @@ struct index_map_subset_plan_t
const hb_vector_t<hb_inc_bimap_t> &inner_maps,
const hb_subset_plan_t *plan)
{
outer_bit_count = 1;
inner_bit_count = 1;
for (unsigned int i = 0; i < max_inners.length; i++)
{
if (inner_maps[i].get_population () == 0) continue;
@ -128,9 +136,13 @@ struct index_map_subset_plan_t
if (unlikely (new_gid >= map_count)) break;
uint32_t v = input_map->map (old_gid);
unsigned int outer = v >> 16;
output_map.arrayZ[new_gid] = (outer_map[outer] << 16) | (inner_maps[outer][v & 0xFFFF]);
uint32_t v = input_map? input_map->map (old_gid) : old_gid;
unsigned outer = v >> 16;
unsigned new_outer = outer_map[outer];
unsigned bit_count = (new_outer == 0) ? 1 : hb_bit_storage (new_outer);
outer_bit_count = hb_max (bit_count, outer_bit_count);
output_map.arrayZ[new_gid] = (new_outer << 16) | (inner_maps[outer][v & 0xFFFF]);
}
}
@ -204,8 +216,8 @@ struct hvarvvar_subset_plan_t
if (unlikely (!index_map_plans.length || !inner_sets.length || !inner_maps.length)) return;
bool retain_adv_map = false;
index_map_plans[0].init (*index_maps[0], outer_map, inner_sets, plan, false);
if (index_maps[0] == &Null (DeltaSetIndexMap))
index_map_plans[0].init (index_maps[0], outer_map, inner_sets, plan, false);
if (!index_maps[0])
{
retain_adv_map = plan->flags & HB_SUBSET_FLAGS_RETAIN_GIDS;
outer_map.add (0);
@ -215,7 +227,7 @@ struct hvarvvar_subset_plan_t
}
for (unsigned int i = 1; i < index_maps.length; i++)
index_map_plans[i].init (*index_maps[i], outer_map, inner_sets, plan);
index_map_plans[i].init (index_maps[i], outer_map, inner_sets, plan);
outer_map.sort ();
@ -303,9 +315,14 @@ struct HVARVVAR
void listup_index_maps (hb_vector_t<const DeltaSetIndexMap *> &index_maps) const
{
index_maps.push (&(this+advMap));
index_maps.push (&(this+lsbMap));
index_maps.push (&(this+rsbMap));
if (advMap) index_maps.push (&(this+advMap));
else index_maps.push (nullptr);
if (lsbMap) index_maps.push (&(this+lsbMap));
else index_maps.push (nullptr);
if (rsbMap) index_maps.push (&(this+rsbMap));
else index_maps.push (nullptr);
}
bool serialize_index_maps (hb_serialize_context_t *c,
@ -428,7 +445,8 @@ struct VVAR : HVARVVAR {
void listup_index_maps (hb_vector_t<const DeltaSetIndexMap *> &index_maps) const
{
HVARVVAR::listup_index_maps (index_maps);
index_maps.push (&(this+vorgMap));
if (vorgMap) index_maps.push (&(this+vorgMap));
else index_maps.push (nullptr);
}
bool serialize_index_maps (hb_serialize_context_t *c,

Some files were not shown because too many files have changed in this diff Show more