summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/harfbuzz-ng/src/OT/Layout
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rdparty/harfbuzz-ng/src/OT/Layout')
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/Coverage.hh27
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/CoverageFormat1.hh2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/CoverageFormat2.hh19
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/RangeRecord.hh12
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/GDEF/GDEF.hh256
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/Anchor.hh1
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/AnchorFormat3.hh38
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/AnchorMatrix.hh20
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/Common.hh2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/CursivePosFormat1.hh48
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/GPOS.hh2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/LigatureArray.hh13
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkArray.hh8
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkBasePosFormat1.hh15
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkLigPosFormat1.hh33
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkMarkPosFormat1.hh19
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkRecord.hh11
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairPosFormat1.hh48
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairPosFormat2.hh92
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairSet.hh17
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairValueRecord.hh6
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/SinglePos.hh12
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/SinglePosFormat1.hh40
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/SinglePosFormat2.hh43
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/ValueFormat.hh143
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/Common.hh2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/Ligature.hh22
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/LigatureSet.hh73
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/LigatureSubstFormat1.hh2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh9
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/Sequence.hh2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/SingleSubst.hh2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/SingleSubstFormat1.hh38
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/SingleSubstFormat2.hh25
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/types.hh8
35 files changed, 804 insertions, 306 deletions
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/Coverage.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/Coverage.hh
index d35654e245..344e87afb3 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/Coverage.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/Coverage.hh
@@ -57,10 +57,14 @@ struct Coverage
public:
DEFINE_SIZE_UNION (2, format);
+#ifndef HB_OPTIMIZE_SIZE
+ HB_ALWAYS_INLINE
+#endif
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
if (!u.format.sanitize (c)) return_trace (false);
+ hb_barrier ();
switch (u.format)
{
case 1: return_trace (u.format1.sanitize (c));
@@ -113,22 +117,33 @@ struct Coverage
TRACE_SERIALIZE (this);
if (unlikely (!c->extend_min (this))) return_trace (false);
- unsigned count = 0;
+ unsigned count = hb_len (glyphs);
unsigned num_ranges = 0;
hb_codepoint_t last = (hb_codepoint_t) -2;
+ hb_codepoint_t max = 0;
+ bool unsorted = false;
for (auto g: glyphs)
{
+ if (last != (hb_codepoint_t) -2 && g < last)
+ unsorted = true;
if (last + 1 != g)
- num_ranges++;
+ num_ranges++;
last = g;
- count++;
+ if (g > max) max = g;
}
- u.format = count <= num_ranges * 3 ? 1 : 2;
+ u.format = !unsorted && count <= num_ranges * 3 ? 1 : 2;
#ifndef HB_NO_BEYOND_64K
- if (count && last > 0xFFFFu)
+ if (max > 0xFFFFu)
u.format += 2;
+ if (unlikely (max > 0xFFFFFFu))
+#else
+ if (unlikely (max > 0xFFFFu))
#endif
+ {
+ c->check_success (false, HB_SERIALIZE_ERROR_INT_OVERFLOW);
+ return_trace (false);
+ }
switch (u.format)
{
@@ -148,8 +163,8 @@ struct Coverage
auto it =
+ iter ()
| hb_take (c->plan->source->get_num_glyphs ())
- | hb_filter (c->plan->glyph_map_gsub)
| hb_map_retains_sorting (c->plan->glyph_map_gsub)
+ | hb_filter ([] (hb_codepoint_t glyph) { return glyph != HB_MAP_VALUE_INVALID; })
;
// Cache the iterator result as it will be iterated multiple times
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/CoverageFormat1.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/CoverageFormat1.hh
index 5d68e3d15e..3f598d40ef 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/CoverageFormat1.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/CoverageFormat1.hh
@@ -79,7 +79,7 @@ struct CoverageFormat1_3
{
if (glyphArray.len > glyphs->get_population () * hb_bit_storage ((unsigned) glyphArray.len) / 2)
{
- for (hb_codepoint_t g = HB_SET_VALUE_INVALID; glyphs->next (&g);)
+ for (auto g : *glyphs)
if (get_coverage (g) != NOT_COVERED)
return true;
return false;
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/CoverageFormat2.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/CoverageFormat2.hh
index d7fcc35202..9c87542356 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/CoverageFormat2.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/CoverageFormat2.hh
@@ -95,19 +95,26 @@ struct CoverageFormat2_4
unsigned count = 0;
unsigned range = (unsigned) -1;
last = (hb_codepoint_t) -2;
+ unsigned unsorted = false;
for (auto g: glyphs)
{
if (last + 1 != g)
{
+ if (unlikely (last != (hb_codepoint_t) -2 && last + 1 > g))
+ unsorted = true;
+
range++;
- rangeRecord[range].first = g;
- rangeRecord[range].value = count;
+ rangeRecord.arrayZ[range].first = g;
+ rangeRecord.arrayZ[range].value = count;
}
- rangeRecord[range].last = g;
+ rangeRecord.arrayZ[range].last = g;
last = g;
count++;
}
+ if (unlikely (unsorted))
+ rangeRecord.as_array ().qsort (RangeRecord<Types>::cmp_range);
+
return_trace (true);
}
@@ -115,7 +122,7 @@ struct CoverageFormat2_4
{
if (rangeRecord.len > glyphs->get_population () * hb_bit_storage ((unsigned) rangeRecord.len) / 2)
{
- for (hb_codepoint_t g = HB_SET_VALUE_INVALID; glyphs->next (&g);)
+ for (auto g : *glyphs)
if (get_coverage (g) != NOT_COVERED)
return true;
return false;
@@ -185,8 +192,8 @@ struct CoverageFormat2_4
if (__more__ ())
{
unsigned int old = coverage;
- j = c->rangeRecord[i].first;
- coverage = c->rangeRecord[i].value;
+ j = c->rangeRecord.arrayZ[i].first;
+ coverage = c->rangeRecord.arrayZ[i].value;
if (unlikely (coverage != old + 1))
{
/* Broken table. Skip. Important to avoid DoS.
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/RangeRecord.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/RangeRecord.hh
index a62629fad3..85aacace9a 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/RangeRecord.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/RangeRecord.hh
@@ -51,6 +51,18 @@ struct RangeRecord
int cmp (hb_codepoint_t g) const
{ return g < first ? -1 : g <= last ? 0 : +1; }
+ HB_INTERNAL static int cmp_range (const void *pa, const void *pb) {
+ const RangeRecord *a = (const RangeRecord *) pa;
+ const RangeRecord *b = (const RangeRecord *) pb;
+ if (a->first < b->first) return -1;
+ if (a->first > b->first) return +1;
+ if (a->last < b->last) return -1;
+ if (a->last > b->last) return +1;
+ if (a->value < b->value) return -1;
+ if (a->value > b->value) return +1;
+ return 0;
+ }
+
unsigned get_population () const
{
if (unlikely (last < first)) return 0;
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GDEF/GDEF.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GDEF/GDEF.hh
index 0551fcf812..45baeb4ec5 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GDEF/GDEF.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GDEF/GDEF.hh
@@ -29,9 +29,10 @@
#ifndef OT_LAYOUT_GDEF_GDEF_HH
#define OT_LAYOUT_GDEF_GDEF_HH
-#include "../../../hb-ot-layout-common.hh"
+#include "../../../hb-ot-var-common.hh"
#include "../../../hb-font.hh"
+#include "../../../hb-cache.hh"
namespace OT {
@@ -48,8 +49,6 @@ struct AttachPoint : Array16Of<HBUINT16>
{
TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (*this);
- if (unlikely (!out)) return_trace (false);
-
return_trace (out->serialize (c->serializer, + iter ()));
}
};
@@ -190,7 +189,7 @@ struct CaretValueFormat3
friend struct CaretValue;
hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction,
- const VariationStore &var_store) const
+ const ItemVariationStore &var_store) const
{
return HB_DIRECTION_IS_HORIZONTAL (direction) ?
font->em_scale_x (coordinate) + (this+deviceTable).get_x_delta (font, var_store) :
@@ -201,22 +200,23 @@ struct CaretValueFormat3
{
TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (*this);
- if (unlikely (!out)) return_trace (false);
if (!c->serializer->embed (caretValueFormat)) return_trace (false);
if (!c->serializer->embed (coordinate)) return_trace (false);
unsigned varidx = (this+deviceTable).get_variation_index ();
- if (c->plan->layout_variation_idx_delta_map.has (varidx))
+ hb_pair_t<unsigned, int> *new_varidx_delta;
+ if (!c->plan->layout_variation_idx_delta_map.has (varidx, &new_varidx_delta))
+ return_trace (false);
+
+ uint32_t new_varidx = hb_first (*new_varidx_delta);
+ int delta = hb_second (*new_varidx_delta);
+ if (delta != 0)
{
- int delta = hb_second (c->plan->layout_variation_idx_delta_map.get (varidx));
- if (delta != 0)
- {
- if (!c->serializer->check_assign (out->coordinate, coordinate + delta, HB_SERIALIZE_ERROR_INT_OVERFLOW))
- return_trace (false);
- }
+ if (!c->serializer->check_assign (out->coordinate, coordinate + delta, HB_SERIALIZE_ERROR_INT_OVERFLOW))
+ return_trace (false);
}
- if (c->plan->all_axes_pinned)
+ if (new_varidx == HB_OT_LAYOUT_NO_VARIATIONS_INDEX)
return_trace (c->serializer->check_assign (out->caretValueFormat, 1, HB_SERIALIZE_ERROR_INT_OVERFLOW));
if (!c->serializer->embed (deviceTable))
@@ -251,7 +251,7 @@ struct CaretValue
hb_position_t get_caret_value (hb_font_t *font,
hb_direction_t direction,
hb_codepoint_t glyph_id,
- const VariationStore &var_store) const
+ const ItemVariationStore &var_store) const
{
switch (u.format) {
case 1: return u.format1.get_caret_value (font, direction);
@@ -291,6 +291,7 @@ struct CaretValue
{
TRACE_SANITIZE (this);
if (!u.format.sanitize (c)) return_trace (false);
+ hb_barrier ();
switch (u.format) {
case 1: return_trace (u.format1.sanitize (c));
case 2: return_trace (u.format2.sanitize (c));
@@ -315,7 +316,7 @@ struct LigGlyph
unsigned get_lig_carets (hb_font_t *font,
hb_direction_t direction,
hb_codepoint_t glyph_id,
- const VariationStore &var_store,
+ const ItemVariationStore &var_store,
unsigned start_offset,
unsigned *caret_count /* IN/OUT */,
hb_position_t *caret_array /* OUT */) const
@@ -371,7 +372,7 @@ struct LigCaretList
unsigned int get_lig_carets (hb_font_t *font,
hb_direction_t direction,
hb_codepoint_t glyph_id,
- const VariationStore &var_store,
+ const ItemVariationStore &var_store,
unsigned int start_offset,
unsigned int *caret_count /* IN/OUT */,
hb_position_t *caret_array /* OUT */) const
@@ -441,6 +442,30 @@ struct MarkGlyphSetsFormat1
bool covers (unsigned int set_index, hb_codepoint_t glyph_id) const
{ return (this+coverage[set_index]).get_coverage (glyph_id) != NOT_COVERED; }
+ void collect_used_mark_sets (const hb_set_t& glyph_set,
+ hb_set_t& used_mark_sets /* OUT */) const
+ {
+ unsigned i = 0;
+ for (const auto &offset : coverage)
+ {
+ const auto &cov = this+offset;
+ if (cov.intersects (&glyph_set))
+ used_mark_sets.add (i);
+
+ i++;
+ }
+ }
+
+ template <typename set_t>
+ void collect_coverage (hb_vector_t<set_t> &sets) const
+ {
+ for (const auto &offset : coverage)
+ {
+ const auto &cov = this+offset;
+ cov.collect_coverage (sets.push ());
+ }
+ }
+
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
@@ -451,6 +476,7 @@ struct MarkGlyphSetsFormat1
bool ret = true;
for (const Offset32To<Coverage>& offset : coverage.iter ())
{
+ auto snap = c->serializer->snapshot ();
auto *o = out->coverage.serialize_append (c->serializer);
if (unlikely (!o))
{
@@ -458,11 +484,17 @@ struct MarkGlyphSetsFormat1
break;
}
- //not using o->serialize_subset (c, offset, this, out) here because
- //OTS doesn't allow null offset.
- //See issue: https://github.com/khaledhosny/ots/issues/172
+ //skip empty coverage
c->serializer->push ();
- c->dispatch (this+offset);
+ bool res = false;
+ if (offset) res = c->dispatch (this+offset);
+ if (!res)
+ {
+ c->serializer->pop_discard ();
+ c->serializer->revert (snap);
+ (out->coverage.len)--;
+ continue;
+ }
c->serializer->add_link (*o, c->serializer->pop_pack ());
}
@@ -494,6 +526,24 @@ struct MarkGlyphSets
}
}
+ template <typename set_t>
+ void collect_coverage (hb_vector_t<set_t> &sets) const
+ {
+ switch (u.format) {
+ case 1: u.format1.collect_coverage (sets); return;
+ default:return;
+ }
+ }
+
+ void collect_used_mark_sets (const hb_set_t& glyph_set,
+ hb_set_t& used_mark_sets /* OUT */) const
+ {
+ switch (u.format) {
+ case 1: u.format1.collect_used_mark_sets (glyph_set, used_mark_sets); return;
+ default:return;
+ }
+ }
+
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
@@ -507,6 +557,7 @@ struct MarkGlyphSets
{
TRACE_SANITIZE (this);
if (!u.format.sanitize (c)) return_trace (false);
+ hb_barrier ();
switch (u.format) {
case 1: return_trace (u.format1.sanitize (c));
default:return_trace (true);
@@ -558,7 +609,7 @@ struct GDEFVersion1_2
* definitions--from beginning of GDEF
* header (may be NULL). Introduced
* in version 0x00010002. */
- Offset32To<VariationStore>
+ Offset32To<ItemVariationStore>
varStore; /* Offset to the table of Item Variation
* Store--from beginning of GDEF
* header (may be NULL). Introduced
@@ -581,43 +632,109 @@ struct GDEFVersion1_2
attachList.sanitize (c, this) &&
ligCaretList.sanitize (c, this) &&
markAttachClassDef.sanitize (c, this) &&
+ hb_barrier () &&
(version.to_int () < 0x00010002u || markGlyphSetsDef.sanitize (c, this)) &&
(version.to_int () < 0x00010003u || varStore.sanitize (c, this)));
}
+ static void remap_varidx_after_instantiation (const hb_map_t& varidx_map,
+ hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>>& layout_variation_idx_delta_map /* IN/OUT */)
+ {
+ /* varidx_map is empty which means varstore is empty after instantiation,
+ * no variations, map all varidx to HB_OT_LAYOUT_NO_VARIATIONS_INDEX.
+ * varidx_map doesn't have original varidx, indicating delta row is all
+ * zeros, map varidx to HB_OT_LAYOUT_NO_VARIATIONS_INDEX */
+ for (auto _ : layout_variation_idx_delta_map.iter_ref ())
+ {
+ /* old_varidx->(varidx, delta) mapping generated for subsetting, then this
+ * varidx is used as key of varidx_map during instantiation */
+ uint32_t varidx = _.second.first;
+ uint32_t *new_varidx;
+ if (varidx_map.has (varidx, &new_varidx))
+ _.second.first = *new_varidx;
+ else
+ _.second.first = HB_OT_LAYOUT_NO_VARIATIONS_INDEX;
+ }
+ }
+
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
- auto *out = c->serializer->embed (*this);
- if (unlikely (!out)) return_trace (false);
-
- bool subset_glyphclassdef = out->glyphClassDef.serialize_subset (c, glyphClassDef, this, nullptr, false, true);
- bool subset_attachlist = out->attachList.serialize_subset (c, attachList, this);
- bool subset_ligcaretlist = out->ligCaretList.serialize_subset (c, ligCaretList, this);
- bool subset_markattachclassdef = out->markAttachClassDef.serialize_subset (c, markAttachClassDef, this, nullptr, false, true);
+ auto *out = c->serializer->start_embed (*this);
+ if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
- bool subset_markglyphsetsdef = false;
- if (version.to_int () >= 0x00010002u)
- {
- subset_markglyphsetsdef = out->markGlyphSetsDef.serialize_subset (c, markGlyphSetsDef, this);
- }
+ // Push var store first (if it's needed) so that it's last in the
+ // serialization order. Some font consumers assume that varstore runs to
+ // the end of the GDEF table.
+ // See: https://github.com/harfbuzz/harfbuzz/issues/4636
+ auto snapshot_version0 = c->serializer->snapshot ();
+ if (unlikely (version.to_int () >= 0x00010002u && !c->serializer->embed (markGlyphSetsDef)))
+ return_trace (false);
bool subset_varstore = false;
+ unsigned varstore_index = (unsigned) -1;
+ auto snapshot_version2 = c->serializer->snapshot ();
if (version.to_int () >= 0x00010003u)
{
+ if (unlikely (!c->serializer->embed (varStore))) return_trace (false);
if (c->plan->all_axes_pinned)
out->varStore = 0;
+ else if (c->plan->normalized_coords)
+ {
+ if (varStore)
+ {
+ item_variations_t item_vars;
+ if (item_vars.instantiate (this+varStore, c->plan, true, true,
+ c->plan->gdef_varstore_inner_maps.as_array ())) {
+ subset_varstore = out->varStore.serialize_serialize (c->serializer,
+ item_vars.has_long_word (),
+ c->plan->axis_tags,
+ item_vars.get_region_list (),
+ item_vars.get_vardata_encodings ());
+ varstore_index = c->serializer->last_added_child_index();
+ }
+ remap_varidx_after_instantiation (item_vars.get_varidx_map (),
+ c->plan->layout_variation_idx_delta_map);
+ }
+ }
else
+ {
subset_varstore = out->varStore.serialize_subset (c, varStore, this, c->plan->gdef_varstore_inner_maps.as_array ());
+ varstore_index = c->serializer->last_added_child_index();
+ }
+ }
+
+ out->version.major = version.major;
+ out->version.minor = version.minor;
+
+ if (!subset_varstore && version.to_int () >= 0x00010002u) {
+ c->serializer->revert (snapshot_version2);
+ }
+
+ bool subset_markglyphsetsdef = false;
+ if (version.to_int () >= 0x00010002u)
+ {
+ subset_markglyphsetsdef = out->markGlyphSetsDef.serialize_subset (c, markGlyphSetsDef, this);
}
if (subset_varstore)
{
out->version.minor = 3;
+ c->plan->has_gdef_varstore = true;
} else if (subset_markglyphsetsdef) {
- out->version.minor = 2;
+ out->version.minor = 2;
} else {
out->version.minor = 0;
+ c->serializer->revert (snapshot_version0);
+ }
+
+ bool subset_glyphclassdef = out->glyphClassDef.serialize_subset (c, glyphClassDef, this, nullptr, false, true);
+ bool subset_attachlist = out->attachList.serialize_subset (c, attachList, this);
+ bool subset_markattachclassdef = out->markAttachClassDef.serialize_subset (c, markAttachClassDef, this, nullptr, false, true);
+ bool subset_ligcaretlist = out->ligCaretList.serialize_subset (c, ligCaretList, this);
+
+ if (subset_varstore && varstore_index != (unsigned) -1) {
+ c->serializer->repack_last(varstore_index);
}
return_trace (subset_glyphclassdef || subset_attachlist ||
@@ -654,6 +771,7 @@ struct GDEF
{
TRACE_SANITIZE (this);
if (unlikely (!u.version.sanitize (c))) return_trace (false);
+ hb_barrier ();
switch (u.version.major) {
case 1: return_trace (u.version1.sanitize (c));
#ifndef HB_NO_BEYOND_64K
@@ -784,14 +902,14 @@ struct GDEF
default: return false;
}
}
- const VariationStore &get_var_store () const
+ const ItemVariationStore &get_var_store () const
{
switch (u.version.major) {
- case 1: return u.version.to_int () >= 0x00010003u ? this+u.version1.varStore : Null(VariationStore);
+ case 1: return u.version.to_int () >= 0x00010003u ? this+u.version1.varStore : Null(ItemVariationStore);
#ifndef HB_NO_BEYOND_64K
case 2: return this+u.version2.varStore;
#endif
- default: return Null(VariationStore);
+ default: return Null(ItemVariationStore);
}
}
@@ -858,43 +976,51 @@ struct GDEF
hb_blob_destroy (table.get_blob ());
table = hb_blob_get_empty ();
}
+
+#ifndef HB_NO_GDEF_CACHE
+ table->get_mark_glyph_sets ().collect_coverage (mark_glyph_set_digests);
+#endif
}
~accelerator_t () { table.destroy (); }
- hb_blob_ptr_t<GDEF> table;
- };
+ unsigned int get_glyph_props (hb_codepoint_t glyph) const
+ {
+ unsigned v;
- void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
- { get_lig_caret_list ().collect_variation_indices (c); }
+#ifndef HB_NO_GDEF_CACHE
+ if (glyph_props_cache.get (glyph, &v))
+ return v;
+#endif
- void remap_layout_variation_indices (const hb_set_t *layout_variation_indices,
- hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map /* OUT */) const
- {
- if (!has_var_store ()) return;
- if (layout_variation_indices->is_empty ()) return;
+ v = table->get_glyph_props (glyph);
- unsigned new_major = 0, new_minor = 0;
- unsigned last_major = (layout_variation_indices->get_min ()) >> 16;
- for (unsigned idx : layout_variation_indices->iter ())
- {
- uint16_t major = idx >> 16;
- if (major >= get_var_store ().get_sub_table_count ()) break;
- if (major != last_major)
- {
- new_minor = 0;
- ++new_major;
- }
+#ifndef HB_NO_GDEF_CACHE
+ if (likely (table.get_blob ())) // Don't try setting if we are the null instance!
+ glyph_props_cache.set (glyph, v);
+#endif
- unsigned new_idx = (new_major << 16) + new_minor;
- if (!layout_variation_idx_delta_map->has (idx))
- continue;
- int delta = hb_second (layout_variation_idx_delta_map->get (idx));
+ return v;
- layout_variation_idx_delta_map->set (idx, hb_pair_t<unsigned, int> (new_idx, delta));
- ++new_minor;
- last_major = major;
}
- }
+
+ bool mark_set_covers (unsigned int set_index, hb_codepoint_t glyph_id) const
+ {
+ return
+#ifndef HB_NO_GDEF_CACHE
+ mark_glyph_set_digests[set_index].may_have (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;
+ mutable hb_cache_t<21, 3, 8> glyph_props_cache;
+#endif
+ };
+
+ void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
+ { get_lig_caret_list ().collect_variation_indices (c); }
protected:
union {
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/Anchor.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/Anchor.hh
index 49e76e7750..7802e397f4 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/Anchor.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/Anchor.hh
@@ -25,6 +25,7 @@ struct Anchor
{
TRACE_SANITIZE (this);
if (!u.format.sanitize (c)) return_trace (false);
+ hb_barrier ();
switch (u.format) {
case 1: return_trace (u.format1.sanitize (c));
case 2: return_trace (u.format2.sanitize (c));
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/AnchorFormat3.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/AnchorFormat3.hh
index e7e3c5c6d1..b5422652c4 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/AnchorFormat3.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/AnchorFormat3.hh
@@ -25,7 +25,9 @@ struct AnchorFormat3
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
- return_trace (c->check_struct (this) && xDeviceTable.sanitize (c, this) && yDeviceTable.sanitize (c, this));
+ if (unlikely (!c->check_struct (this))) return_trace (false);
+
+ return_trace (xDeviceTable.sanitize (c, this) && yDeviceTable.sanitize (c, this));
}
void get_anchor (hb_ot_apply_context_t *c, hb_codepoint_t glyph_id HB_UNUSED,
@@ -35,25 +37,35 @@ struct AnchorFormat3
*x = font->em_fscale_x (xCoordinate);
*y = font->em_fscale_y (yCoordinate);
- if (font->x_ppem || font->num_coords)
+ if ((font->x_ppem || font->num_coords) && xDeviceTable.sanitize (&c->sanitizer, this))
+ {
+ hb_barrier ();
*x += (this+xDeviceTable).get_x_delta (font, c->var_store, c->var_store_cache);
- if (font->y_ppem || font->num_coords)
+ }
+ if ((font->y_ppem || font->num_coords) && yDeviceTable.sanitize (&c->sanitizer, this))
+ {
+ hb_barrier ();
*y += (this+yDeviceTable).get_y_delta (font, c->var_store, c->var_store_cache);
+ }
}
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (*this);
- if (unlikely (!out)) return_trace (false);
if (unlikely (!c->serializer->embed (format))) return_trace (false);
if (unlikely (!c->serializer->embed (xCoordinate))) return_trace (false);
if (unlikely (!c->serializer->embed (yCoordinate))) return_trace (false);
unsigned x_varidx = xDeviceTable ? (this+xDeviceTable).get_variation_index () : HB_OT_LAYOUT_NO_VARIATIONS_INDEX;
- if (c->plan->layout_variation_idx_delta_map.has (x_varidx))
+ if (x_varidx != HB_OT_LAYOUT_NO_VARIATIONS_INDEX)
{
- int delta = hb_second (c->plan->layout_variation_idx_delta_map.get (x_varidx));
+ hb_pair_t<unsigned, int> *new_varidx_delta;
+ if (!c->plan->layout_variation_idx_delta_map.has (x_varidx, &new_varidx_delta))
+ return_trace (false);
+
+ x_varidx = hb_first (*new_varidx_delta);
+ int delta = hb_second (*new_varidx_delta);
if (delta != 0)
{
if (!c->serializer->check_assign (out->xCoordinate, xCoordinate + delta,
@@ -63,9 +75,14 @@ struct AnchorFormat3
}
unsigned y_varidx = yDeviceTable ? (this+yDeviceTable).get_variation_index () : HB_OT_LAYOUT_NO_VARIATIONS_INDEX;
- if (c->plan->layout_variation_idx_delta_map.has (y_varidx))
+ if (y_varidx != HB_OT_LAYOUT_NO_VARIATIONS_INDEX)
{
- int delta = hb_second (c->plan->layout_variation_idx_delta_map.get (y_varidx));
+ hb_pair_t<unsigned, int> *new_varidx_delta;
+ if (!c->plan->layout_variation_idx_delta_map.has (y_varidx, &new_varidx_delta))
+ return_trace (false);
+
+ y_varidx = hb_first (*new_varidx_delta);
+ int delta = hb_second (*new_varidx_delta);
if (delta != 0)
{
if (!c->serializer->check_assign (out->yCoordinate, yCoordinate + delta,
@@ -74,7 +91,10 @@ struct AnchorFormat3
}
}
- if (c->plan->all_axes_pinned)
+ /* in case that all axes are pinned or no variations after instantiation,
+ * both var_idxes will be mapped to HB_OT_LAYOUT_NO_VARIATIONS_INDEX */
+ if (x_varidx == HB_OT_LAYOUT_NO_VARIATIONS_INDEX &&
+ y_varidx == HB_OT_LAYOUT_NO_VARIATIONS_INDEX)
return_trace (c->serializer->check_assign (out->format, 1, HB_SERIALIZE_ERROR_INT_OVERFLOW));
if (!c->serializer->embed (xDeviceTable)) return_trace (false);
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/AnchorMatrix.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/AnchorMatrix.hh
index c442efa1ea..2557e9a723 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/AnchorMatrix.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/AnchorMatrix.hh
@@ -8,7 +8,7 @@ namespace GPOS_impl {
struct AnchorMatrix
{
HBUINT16 rows; /* Number of rows */
- UnsizedArrayOf<Offset16To<Anchor>>
+ UnsizedArrayOf<Offset16To<Anchor, AnchorMatrix>>
matrixZ; /* Matrix of offsets to Anchor tables--
* from beginning of AnchorMatrix table */
public:
@@ -18,21 +18,31 @@ struct AnchorMatrix
{
TRACE_SANITIZE (this);
if (!c->check_struct (this)) return_trace (false);
+ hb_barrier ();
if (unlikely (hb_unsigned_mul_overflows (rows, cols))) return_trace (false);
unsigned int count = rows * cols;
if (!c->check_array (matrixZ.arrayZ, count)) return_trace (false);
+
+ if (c->lazy_some_gpos)
+ return_trace (true);
+
+ hb_barrier ();
for (unsigned int i = 0; i < count; i++)
if (!matrixZ[i].sanitize (c, this)) return_trace (false);
return_trace (true);
}
- const Anchor& get_anchor (unsigned int row, unsigned int col,
- unsigned int cols, bool *found) const
+ const Anchor& get_anchor (hb_ot_apply_context_t *c,
+ unsigned int row, unsigned int col,
+ unsigned int cols, bool *found) const
{
*found = false;
if (unlikely (row >= rows || col >= cols)) return Null (Anchor);
- *found = !matrixZ[row * cols + col].is_null ();
- return this+matrixZ[row * cols + col];
+ auto &offset = matrixZ[row * cols + col];
+ if (unlikely (!offset.sanitize (&c->sanitizer, this))) return Null (Anchor);
+ hb_barrier ();
+ *found = !offset.is_null ();
+ return this+offset;
}
template <typename Iterator,
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/Common.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/Common.hh
index 408197454f..696d25d75c 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/Common.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/Common.hh
@@ -23,7 +23,7 @@ static void SinglePos_serialize (hb_serialize_context_t *c,
const SrcLookup *src,
Iterator it,
const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map,
- bool all_axes_pinned);
+ unsigned new_format);
}
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/CursivePosFormat1.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/CursivePosFormat1.hh
index ff255e090a..6b019ac513 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/CursivePosFormat1.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/CursivePosFormat1.hh
@@ -11,37 +11,38 @@ struct EntryExitRecord
{
friend struct CursivePosFormat1;
- bool sanitize (hb_sanitize_context_t *c, const void *base) const
+ bool sanitize (hb_sanitize_context_t *c, const struct CursivePosFormat1 *base) const
{
TRACE_SANITIZE (this);
return_trace (entryAnchor.sanitize (c, base) && exitAnchor.sanitize (c, base));
}
void collect_variation_indices (hb_collect_variation_indices_context_t *c,
- const void *src_base) const
+ const struct CursivePosFormat1 *src_base) const
{
(src_base+entryAnchor).collect_variation_indices (c);
(src_base+exitAnchor).collect_variation_indices (c);
}
- EntryExitRecord* subset (hb_subset_context_t *c,
- const void *src_base) const
+ bool subset (hb_subset_context_t *c,
+ const struct CursivePosFormat1 *src_base) const
{
TRACE_SERIALIZE (this);
auto *out = c->serializer->embed (this);
- if (unlikely (!out)) return_trace (nullptr);
+ if (unlikely (!out)) return_trace (false);
- out->entryAnchor.serialize_subset (c, entryAnchor, src_base);
- out->exitAnchor.serialize_subset (c, exitAnchor, src_base);
- return_trace (out);
+ bool ret = false;
+ ret |= out->entryAnchor.serialize_subset (c, entryAnchor, src_base);
+ ret |= out->exitAnchor.serialize_subset (c, exitAnchor, src_base);
+ return_trace (ret);
}
protected:
- Offset16To<Anchor>
+ Offset16To<Anchor, struct CursivePosFormat1>
entryAnchor; /* Offset to EntryAnchor table--from
* beginning of CursivePos
* subtable--may be NULL */
- Offset16To<Anchor>
+ Offset16To<Anchor, struct CursivePosFormat1>
exitAnchor; /* Offset to ExitAnchor table--from
* beginning of CursivePos
* subtable--may be NULL */
@@ -91,7 +92,13 @@ struct CursivePosFormat1
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
- return_trace (coverage.sanitize (c, this) && entryExitRecord.sanitize (c, this));
+ if (unlikely (!coverage.sanitize (c, this)))
+ return_trace (false);
+
+ if (c->lazy_some_gpos)
+ return_trace (entryExitRecord.sanitize_shallow (c));
+ else
+ return_trace (entryExitRecord.sanitize (c, this));
}
bool intersects (const hb_set_t *glyphs) const
@@ -119,23 +126,27 @@ struct CursivePosFormat1
hb_buffer_t *buffer = c->buffer;
const EntryExitRecord &this_record = entryExitRecord[(this+coverage).get_coverage (buffer->cur().codepoint)];
- if (!this_record.entryAnchor) return_trace (false);
+ if (!this_record.entryAnchor ||
+ unlikely (!this_record.entryAnchor.sanitize (&c->sanitizer, this))) return_trace (false);
+ hb_barrier ();
hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
- skippy_iter.reset (buffer->idx, 1);
+ skippy_iter.reset_fast (buffer->idx);
unsigned unsafe_from;
- if (!skippy_iter.prev (&unsafe_from))
+ if (unlikely (!skippy_iter.prev (&unsafe_from)))
{
buffer->unsafe_to_concat_from_outbuffer (unsafe_from, buffer->idx + 1);
return_trace (false);
}
const EntryExitRecord &prev_record = entryExitRecord[(this+coverage).get_coverage (buffer->info[skippy_iter.idx].codepoint)];
- if (!prev_record.exitAnchor)
+ if (!prev_record.exitAnchor ||
+ unlikely (!prev_record.exitAnchor.sanitize (&c->sanitizer, this)))
{
buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1);
return_trace (false);
}
+ hb_barrier ();
unsigned int i = skippy_iter.idx;
unsigned int j = buffer->idx;
@@ -200,8 +211,8 @@ struct CursivePosFormat1
* Arabic. */
unsigned int child = i;
unsigned int parent = j;
- hb_position_t x_offset = entry_x - exit_x;
- hb_position_t y_offset = entry_y - exit_y;
+ hb_position_t x_offset = roundf (entry_x - exit_x);
+ hb_position_t y_offset = roundf (entry_y - exit_y);
if (!(c->lookup_props & LookupFlag::RightToLeft))
{
unsigned int k = child;
@@ -253,7 +264,7 @@ struct CursivePosFormat1
hb_requires (hb_is_iterator (Iterator))>
void serialize (hb_subset_context_t *c,
Iterator it,
- const void *src_base)
+ const struct CursivePosFormat1 *src_base)
{
if (unlikely (!c->serializer->extend_min ((*this)))) return;
this->format = 1;
@@ -278,7 +289,6 @@ struct CursivePosFormat1
const hb_map_t &glyph_map = *c->plan->glyph_map;
auto *out = c->serializer->start_embed (*this);
- if (unlikely (!out)) return_trace (false);
auto it =
+ hb_zip (this+coverage, entryExitRecord)
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/GPOS.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/GPOS.hh
index 9493ec987e..f4af98b25f 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/GPOS.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/GPOS.hh
@@ -156,7 +156,7 @@ GPOS::position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer)
{
for (unsigned i = 0; i < len; i++)
if (unlikely (pos[i].y_offset))
- pos[i].x_offset += _hb_roundf (font->slant_xy * pos[i].y_offset);
+ pos[i].x_offset += roundf (font->slant_xy * pos[i].y_offset);
}
}
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/LigatureArray.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/LigatureArray.hh
index a2d807cc32..59cca40aad 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/LigatureArray.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/LigatureArray.hh
@@ -27,6 +27,7 @@ struct LigatureArray : List16OfOffset16To<LigatureAttach>
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))
{
@@ -38,13 +39,13 @@ struct LigatureArray : List16OfOffset16To<LigatureAttach>
+ hb_range (src.rows * class_count)
| hb_filter ([=] (unsigned index) { return klass_mapping->has (index % class_count); })
;
- matrix->serialize_subset (c,
- _.second,
- this,
- src.rows,
- indexes);
+ ret |= matrix->serialize_subset (c,
+ _.second,
+ this,
+ src.rows,
+ indexes);
}
- return_trace (this->len);
+ return_trace (ret);
}
};
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkArray.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkArray.hh
index ff43ffb8c5..0887cc158b 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkArray.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkArray.hh
@@ -28,7 +28,7 @@ struct MarkArray : Array16Of<MarkRecord> /* Array of MarkRecords--in Cove
const Anchor& mark_anchor = this + record.markAnchor;
bool found;
- const Anchor& glyph_anchor = anchors.get_anchor (glyph_index, mark_class, class_count, &found);
+ const Anchor& glyph_anchor = anchors.get_anchor (c, glyph_index, mark_class, class_count, &found);
/* If this subtable doesn't have an anchor for this base and this class,
* return false such that the subsequent subtables have a chance at it. */
if (unlikely (!found)) return_trace (false);
@@ -82,10 +82,10 @@ struct MarkArray : Array16Of<MarkRecord> /* Array of MarkRecords--in Cove
| hb_map (hb_second)
;
+ bool ret = false;
unsigned new_length = 0;
for (const auto& mark_record : mark_iter) {
- if (unlikely (!mark_record.subset (c, this, klass_mapping)))
- return_trace (false);
+ ret |= mark_record.subset (c, this, klass_mapping);
new_length++;
}
@@ -93,7 +93,7 @@ struct MarkArray : Array16Of<MarkRecord> /* Array of MarkRecords--in Cove
HB_SERIALIZE_ERROR_ARRAY_OVERFLOW)))
return_trace (false);
- return_trace (true);
+ return_trace (ret);
}
};
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkBasePosFormat1.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkBasePosFormat1.hh
index eb4712049b..1b8f3c80a9 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkBasePosFormat1.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkBasePosFormat1.hh
@@ -197,9 +197,10 @@ struct MarkBasePosFormat1_2
if (!out->markCoverage.serialize_serialize (c->serializer, new_coverage.iter ()))
return_trace (false);
- out->markArray.serialize_subset (c, markArray, this,
- (this+markCoverage).iter (),
- &klass_mapping);
+ if (unlikely (!out->markArray.serialize_subset (c, markArray, this,
+ (this+markCoverage).iter (),
+ &klass_mapping)))
+ return_trace (false);
unsigned basecount = (this+baseArray).rows;
auto base_iter =
@@ -228,11 +229,9 @@ struct MarkBasePosFormat1_2
;
}
- out->baseArray.serialize_subset (c, baseArray, this,
- base_iter.len (),
- base_indexes.iter ());
-
- return_trace (true);
+ return_trace (out->baseArray.serialize_subset (c, baseArray, this,
+ base_iter.len (),
+ base_indexes.iter ()));
}
};
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkLigPosFormat1.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkLigPosFormat1.hh
index 7e7b438aa7..d6bee277c7 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkLigPosFormat1.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkLigPosFormat1.hh
@@ -126,15 +126,15 @@ struct MarkLigPosFormat1_2
return_trace (false);
}
- j = (unsigned) c->last_base;
+ unsigned idx = (unsigned) c->last_base;
/* Checking that matched glyph is actually a ligature by GDEF is too strong; disabled */
- //if (!_hb_glyph_info_is_ligature (&buffer->info[j])) { return_trace (false); }
+ //if (!_hb_glyph_info_is_ligature (&buffer->info[idx])) { return_trace (false); }
- unsigned int lig_index = (this+ligatureCoverage).get_coverage (buffer->info[j].codepoint);
+ unsigned int lig_index = (this+ligatureCoverage).get_coverage (buffer->info[idx].codepoint);
if (lig_index == NOT_COVERED)
{
- buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1);
+ buffer->unsafe_to_concat_from_outbuffer (idx, buffer->idx + 1);
return_trace (false);
}
@@ -145,7 +145,7 @@ struct MarkLigPosFormat1_2
unsigned int comp_count = lig_attach.rows;
if (unlikely (!comp_count))
{
- buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1);
+ buffer->unsafe_to_concat_from_outbuffer (idx, buffer->idx + 1);
return_trace (false);
}
@@ -154,7 +154,7 @@ struct MarkLigPosFormat1_2
* can directly use the component index. If not, we attach the mark
* glyph to the last component of the ligature. */
unsigned int comp_index;
- unsigned int lig_id = _hb_glyph_info_get_lig_id (&buffer->info[j]);
+ unsigned int lig_id = _hb_glyph_info_get_lig_id (&buffer->info[idx]);
unsigned int mark_id = _hb_glyph_info_get_lig_id (&buffer->cur());
unsigned int mark_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
if (lig_id && lig_id == mark_id && mark_comp > 0)
@@ -162,14 +162,14 @@ struct MarkLigPosFormat1_2
else
comp_index = comp_count - 1;
- return_trace ((this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, j));
+ return_trace ((this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, idx));
}
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
- const hb_map_t &glyph_map = *c->plan->glyph_map;
+ 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);
@@ -195,23 +195,24 @@ struct MarkLigPosFormat1_2
if (!out->markCoverage.serialize_serialize (c->serializer, new_mark_coverage))
return_trace (false);
- out->markArray.serialize_subset (c, markArray, this,
- (this+markCoverage).iter (),
- &klass_mapping);
+ if (unlikely (!out->markArray.serialize_subset (c, markArray, this,
+ (this+markCoverage).iter (),
+ &klass_mapping)))
+ return_trace (false);
auto new_ligature_coverage =
+ hb_iter (this + ligatureCoverage)
- | hb_filter (glyphset)
+ | 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))
return_trace (false);
- out->ligatureArray.serialize_subset (c, ligatureArray, this,
- hb_iter (this+ligatureCoverage), classCount, &klass_mapping);
-
- return_trace (true);
+ return_trace (out->ligatureArray.serialize_subset (c, ligatureArray, this,
+ hb_iter (this+ligatureCoverage),
+ classCount, &klass_mapping));
}
};
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkMarkPosFormat1.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkMarkPosFormat1.hh
index fbcebb8044..57eb782a95 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkMarkPosFormat1.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkMarkPosFormat1.hh
@@ -42,6 +42,7 @@ struct MarkMarkPosFormat1_2
mark1Coverage.sanitize (c, this) &&
mark2Coverage.sanitize (c, this) &&
mark1Array.sanitize (c, this) &&
+ hb_barrier () &&
mark2Array.sanitize (c, this, (unsigned int) classCount));
}
@@ -100,16 +101,16 @@ struct MarkMarkPosFormat1_2
/* now we search backwards for a suitable mark glyph until a non-mark glyph */
hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
- skippy_iter.reset (buffer->idx, 1);
+ skippy_iter.reset_fast (buffer->idx);
skippy_iter.set_lookup_props (c->lookup_props & ~(uint32_t)LookupFlag::IgnoreFlags);
unsigned unsafe_from;
- if (!skippy_iter.prev (&unsafe_from))
+ if (unlikely (!skippy_iter.prev (&unsafe_from)))
{
buffer->unsafe_to_concat_from_outbuffer (unsafe_from, buffer->idx + 1);
return_trace (false);
}
- if (!_hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx]))
+ if (likely (!_hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx])))
{
buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1);
return_trace (false);
@@ -183,9 +184,10 @@ struct MarkMarkPosFormat1_2
if (!out->mark1Coverage.serialize_serialize (c->serializer, new_coverage.iter ()))
return_trace (false);
- out->mark1Array.serialize_subset (c, mark1Array, this,
- (this+mark1Coverage).iter (),
- &klass_mapping);
+ if (unlikely (!out->mark1Array.serialize_subset (c, mark1Array, this,
+ (this+mark1Coverage).iter (),
+ &klass_mapping)))
+ return_trace (false);
unsigned mark2count = (this+mark2Array).rows;
auto mark2_iter =
@@ -214,9 +216,10 @@ struct MarkMarkPosFormat1_2
;
}
- out->mark2Array.serialize_subset (c, mark2Array, this, mark2_iter.len (), mark2_indexes.iter ());
+ return_trace (out->mark2Array.serialize_subset (c, mark2Array, this,
+ mark2_iter.len (),
+ mark2_indexes.iter ()));
- return_trace (true);
}
};
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkRecord.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkRecord.hh
index a7d489d2a5..3d11c7773c 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkRecord.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkRecord.hh
@@ -24,17 +24,16 @@ struct MarkRecord
return_trace (c->check_struct (this) && markAnchor.sanitize (c, base));
}
- MarkRecord *subset (hb_subset_context_t *c,
- const void *src_base,
- const hb_map_t *klass_mapping) const
+ bool subset (hb_subset_context_t *c,
+ const void *src_base,
+ const hb_map_t *klass_mapping) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->embed (this);
- if (unlikely (!out)) return_trace (nullptr);
+ if (unlikely (!out)) return_trace (false);
out->klass = klass_mapping->get (klass);
- out->markAnchor.serialize_subset (c, markAnchor, src_base);
- return_trace (out);
+ return_trace (out->markAnchor.serialize_subset (c, markAnchor, src_base));
}
void collect_variation_indices (hb_collect_variation_indices_context_t *c,
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairPosFormat1.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairPosFormat1.hh
index b4a9a9ad53..ac2774a76f 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairPosFormat1.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairPosFormat1.hh
@@ -36,6 +36,7 @@ struct PairPosFormat1_3
TRACE_SANITIZE (this);
if (!c->check_struct (this)) return_trace (false);
+ hb_barrier ();
unsigned int len1 = valueFormat[0].get_len ();
unsigned int len2 = valueFormat[1].get_len ();
@@ -55,7 +56,7 @@ struct PairPosFormat1_3
if (pairSet.len > glyphs->get_population () * hb_bit_storage ((unsigned) pairSet.len) / 4)
{
- for (hb_codepoint_t g = HB_SET_VALUE_INVALID; glyphs->next (&g);)
+ for (hb_codepoint_t g : glyphs->iter())
{
unsigned i = cov.get_coverage (g);
if ((this+pairSet[i]).intersects (glyphs, valueFormat))
@@ -110,9 +111,9 @@ struct PairPosFormat1_3
if (likely (index == NOT_COVERED)) return_trace (false);
hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
- skippy_iter.reset (buffer->idx, 1);
+ skippy_iter.reset_fast (buffer->idx);
unsigned unsafe_to;
- if (!skippy_iter.next (&unsafe_to))
+ if (unlikely (!skippy_iter.next (&unsafe_to)))
{
buffer->unsafe_to_concat (buffer->idx, unsafe_to);
return_trace (false);
@@ -131,20 +132,33 @@ struct PairPosFormat1_3
auto *out = c->serializer->start_embed (*this);
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
out->format = format;
- out->valueFormat[0] = valueFormat[0];
- out->valueFormat[1] = valueFormat[1];
- if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
+
+ hb_pair_t<unsigned, unsigned> newFormats = hb_pair (valueFormat[0], valueFormat[1]);
+
+ if (c->plan->normalized_coords)
{
- hb_pair_t<unsigned, unsigned> newFormats = compute_effective_value_formats (glyphset);
- out->valueFormat[0] = newFormats.first;
- out->valueFormat[1] = newFormats.second;
+ /* all device flags will be dropped when full instancing, no need to strip
+ * hints, also do not strip emtpy cause we don't compute the new default
+ * value during stripping */
+ newFormats = compute_effective_value_formats (glyphset, false, false, &c->plan->layout_variation_idx_delta_map);
}
-
- if (c->plan->all_axes_pinned)
+ /* do not strip hints for VF */
+ else if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
{
- out->valueFormat[0] = out->valueFormat[0].drop_device_table_flags ();
- out->valueFormat[1] = out->valueFormat[1].drop_device_table_flags ();
+ hb_blob_t* blob = hb_face_reference_table (c->plan->source, HB_TAG ('f','v','a','r'));
+ bool has_fvar = (blob != hb_blob_get_empty ());
+ hb_blob_destroy (blob);
+
+ bool strip = !has_fvar;
+ /* special case: strip hints when a VF has no GDEF varstore after
+ * subsetting*/
+ if (has_fvar && !c->plan->has_gdef_varstore)
+ strip = true;
+ newFormats = compute_effective_value_formats (glyphset, strip, true);
}
+
+ out->valueFormat[0] = newFormats.first;
+ out->valueFormat[1] = newFormats.second;
hb_sorted_vector_t<hb_codepoint_t> new_coverage;
@@ -175,7 +189,9 @@ struct PairPosFormat1_3
}
- hb_pair_t<unsigned, unsigned> compute_effective_value_formats (const hb_set_t& glyphset) const
+ hb_pair_t<unsigned, unsigned> compute_effective_value_formats (const hb_set_t& glyphset,
+ bool strip_hints, bool strip_empty,
+ const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *varidx_delta_map = nullptr) const
{
unsigned record_size = PairSet::get_size (valueFormat);
@@ -195,8 +211,8 @@ struct PairPosFormat1_3
{
if (record->intersects (glyphset))
{
- format1 = format1 | valueFormat[0].get_effective_format (record->get_values_1 ());
- format2 = format2 | valueFormat[1].get_effective_format (record->get_values_2 (valueFormat[0]));
+ format1 = format1 | valueFormat[0].get_effective_format (record->get_values_1 (), strip_hints, strip_empty, &set, varidx_delta_map);
+ format2 = format2 | valueFormat[1].get_effective_format (record->get_values_2 (valueFormat[0]), strip_hints, strip_empty, &set, varidx_delta_map);
}
record = &StructAtOffset<const PairValueRecord> (record, record_size);
}
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairPosFormat2.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairPosFormat2.hh
index de15a29e3c..9c805b39a1 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairPosFormat2.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairPosFormat2.hh
@@ -8,7 +8,7 @@ namespace Layout {
namespace GPOS_impl {
template <typename Types>
-struct PairPosFormat2_4
+struct PairPosFormat2_4 : ValueBase
{
protected:
HBUINT16 format; /* Format identifier--format = 2 */
@@ -50,13 +50,13 @@ struct PairPosFormat2_4
unsigned int len1 = valueFormat1.get_len ();
unsigned int len2 = valueFormat2.get_len ();
unsigned int stride = HBUINT16::static_size * (len1 + len2);
- unsigned int record_size = valueFormat1.get_size () + valueFormat2.get_size ();
unsigned int count = (unsigned int) class1Count * (unsigned int) class2Count;
return_trace (c->check_range ((const void *) values,
count,
- record_size) &&
- valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], count, stride) &&
- valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride));
+ stride) &&
+ (c->lazy_some_gpos ||
+ (valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], count, stride) &&
+ valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride))));
}
bool intersects (const hb_set_t *glyphs) const
@@ -131,40 +131,46 @@ struct PairPosFormat2_4
if (likely (index == NOT_COVERED)) return_trace (false);
hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
- skippy_iter.reset (buffer->idx, 1);
+ skippy_iter.reset_fast (buffer->idx);
unsigned unsafe_to;
- if (!skippy_iter.next (&unsafe_to))
+ if (unlikely (!skippy_iter.next (&unsafe_to)))
{
buffer->unsafe_to_concat (buffer->idx, unsafe_to);
return_trace (false);
}
- unsigned int len1 = valueFormat1.get_len ();
- unsigned int len2 = valueFormat2.get_len ();
- unsigned int record_len = len1 + len2;
+ unsigned int klass2 = (this+classDef2).get_class (buffer->info[skippy_iter.idx].codepoint);
+ if (!klass2)
+ {
+ buffer->unsafe_to_concat (buffer->idx, skippy_iter.idx + 1);
+ return_trace (false);
+ }
unsigned int klass1 = (this+classDef1).get_class (buffer->cur().codepoint);
- unsigned int klass2 = (this+classDef2).get_class (buffer->info[skippy_iter.idx].codepoint);
if (unlikely (klass1 >= class1Count || klass2 >= class2Count))
{
buffer->unsafe_to_concat (buffer->idx, skippy_iter.idx + 1);
return_trace (false);
}
+ unsigned int len1 = valueFormat1.get_len ();
+ unsigned int len2 = valueFormat2.get_len ();
+ unsigned int record_len = len1 + len2;
+
const Value *v = &values[record_len * (klass1 * class2Count + klass2)];
bool applied_first = false, applied_second = false;
/* Isolate simple kerning and apply it half to each side.
- * Results in better cursor positinoing / underline drawing.
+ * Results in better cursor positioning / underline drawing.
*
* Disabled, because causes issues... :-(
* https://github.com/harfbuzz/harfbuzz/issues/3408
* https://github.com/harfbuzz/harfbuzz/pull/3235#issuecomment-1029814978
*/
#ifndef HB_SPLIT_KERN
- if (0)
+ if (false)
#endif
{
if (!len2)
@@ -224,8 +230,8 @@ struct PairPosFormat2_4
c->buffer->idx, skippy_iter.idx);
}
- applied_first = valueFormat1.apply_value (c, this, v, buffer->cur_pos());
- applied_second = valueFormat2.apply_value (c, this, v + len1, buffer->pos[skippy_iter.idx]);
+ applied_first = len1 && valueFormat1.apply_value (c, this, v, buffer->cur_pos());
+ applied_second = len2 && valueFormat2.apply_value (c, this, v + len1, buffer->pos[skippy_iter.idx]);
if (applied_first || applied_second)
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
@@ -281,44 +287,52 @@ struct PairPosFormat2_4
unsigned len2 = valueFormat2.get_len ();
hb_pair_t<unsigned, unsigned> newFormats = hb_pair (valueFormat1, valueFormat2);
- if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
- newFormats = compute_effective_value_formats (klass1_map, klass2_map);
-
- out->valueFormat1 = newFormats.first;
- out->valueFormat2 = newFormats.second;
- if (c->plan->all_axes_pinned)
+ if (c->plan->normalized_coords)
+ {
+ /* in case of full instancing, all var device flags will be dropped so no
+ * need to strip hints here */
+ newFormats = compute_effective_value_formats (klass1_map, klass2_map, false, false, &c->plan->layout_variation_idx_delta_map);
+ }
+ /* do not strip hints for VF */
+ else if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
{
- out->valueFormat1 = out->valueFormat1.drop_device_table_flags ();
- out->valueFormat2 = out->valueFormat2.drop_device_table_flags ();
+ hb_blob_t* blob = hb_face_reference_table (c->plan->source, HB_TAG ('f','v','a','r'));
+ bool has_fvar = (blob != hb_blob_get_empty ());
+ hb_blob_destroy (blob);
+
+ bool strip = !has_fvar;
+ /* special case: strip hints when a VF has no GDEF varstore after
+ * subsetting*/
+ if (has_fvar && !c->plan->has_gdef_varstore)
+ strip = true;
+ newFormats = compute_effective_value_formats (klass1_map, klass2_map, strip, true);
}
+ out->valueFormat1 = newFormats.first;
+ out->valueFormat2 = newFormats.second;
+
+ unsigned total_len = len1 + len2;
+ hb_vector_t<unsigned> class2_idxs (+ hb_range ((unsigned) class2Count) | hb_filter (klass2_map));
for (unsigned class1_idx : + hb_range ((unsigned) class1Count) | hb_filter (klass1_map))
{
- for (unsigned class2_idx : + hb_range ((unsigned) class2Count) | hb_filter (klass2_map))
+ for (unsigned class2_idx : class2_idxs)
{
- unsigned idx = (class1_idx * (unsigned) class2Count + class2_idx) * (len1 + len2);
+ unsigned idx = (class1_idx * (unsigned) class2Count + class2_idx) * total_len;
valueFormat1.copy_values (c->serializer, out->valueFormat1, this, &values[idx], &c->plan->layout_variation_idx_delta_map);
valueFormat2.copy_values (c->serializer, out->valueFormat2, this, &values[idx + len1], &c->plan->layout_variation_idx_delta_map);
}
}
- const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
- const hb_map_t &glyph_map = *c->plan->glyph_map;
-
- auto it =
- + hb_iter (this+coverage)
- | hb_filter (glyphset)
- | hb_map_retains_sorting (glyph_map)
- ;
-
- out->coverage.serialize_serialize (c->serializer, it);
- return_trace (out->class1Count && out->class2Count && bool (it));
+ bool ret = out->coverage.serialize_subset(c, coverage, this);
+ return_trace (out->class1Count && out->class2Count && ret);
}
hb_pair_t<unsigned, unsigned> compute_effective_value_formats (const hb_map_t& klass1_map,
- const hb_map_t& klass2_map) const
+ const hb_map_t& klass2_map,
+ bool strip_hints, bool strip_empty,
+ const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *varidx_delta_map = nullptr) const
{
unsigned len1 = valueFormat1.get_len ();
unsigned len2 = valueFormat2.get_len ();
@@ -332,8 +346,8 @@ struct PairPosFormat2_4
for (unsigned class2_idx : + hb_range ((unsigned) class2Count) | hb_filter (klass2_map))
{
unsigned idx = (class1_idx * (unsigned) class2Count + class2_idx) * record_size;
- format1 = format1 | valueFormat1.get_effective_format (&values[idx]);
- format2 = format2 | valueFormat2.get_effective_format (&values[idx + len1]);
+ format1 = format1 | valueFormat1.get_effective_format (&values[idx], strip_hints, strip_empty, this, varidx_delta_map);
+ format2 = format2 | valueFormat2.get_effective_format (&values[idx + len1], strip_hints, strip_empty, this, varidx_delta_map);
}
if (format1 == valueFormat1 && format2 == valueFormat2)
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairSet.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairSet.hh
index 147b8e00ea..5560fab174 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairSet.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairSet.hh
@@ -9,7 +9,7 @@ namespace GPOS_impl {
template <typename Types>
-struct PairSet
+struct PairSet : ValueBase
{
template <typename Types2>
friend struct PairPosFormat1_3;
@@ -45,15 +45,18 @@ struct PairSet
bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) const
{
TRACE_SANITIZE (this);
- if (!(c->check_struct (this)
- && c->check_range (&firstPairValueRecord,
+ if (!(c->check_struct (this) &&
+ hb_barrier () &&
+ c->check_range (&firstPairValueRecord,
len,
closure->stride))) return_trace (false);
+ hb_barrier ();
unsigned int count = len;
const PairValueRecord *record = &firstPairValueRecord;
- return_trace (closure->valueFormats[0].sanitize_values_stride_unsafe (c, this, &record->values[0], count, closure->stride) &&
- closure->valueFormats[1].sanitize_values_stride_unsafe (c, this, &record->values[closure->len1], count, closure->stride));
+ return_trace (c->lazy_some_gpos ||
+ (closure->valueFormats[0].sanitize_values_stride_unsafe (c, this, &record->values[0], count, closure->stride) &&
+ closure->valueFormats[1].sanitize_values_stride_unsafe (c, this, &record->values[closure->len1], count, closure->stride)));
}
bool intersects (const hb_set_t *glyphs,
@@ -120,8 +123,8 @@ struct PairSet
c->buffer->idx, pos);
}
- bool applied_first = valueFormats[0].apply_value (c, this, &record->values[0], buffer->cur_pos());
- bool applied_second = valueFormats[1].apply_value (c, this, &record->values[len1], buffer->pos[pos]);
+ bool applied_first = len1 && valueFormats[0].apply_value (c, this, &record->values[0], buffer->cur_pos());
+ bool applied_second = len2 && valueFormats[1].apply_value (c, this, &record->values[len1], buffer->pos[pos]);
if (applied_first || applied_second)
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairValueRecord.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairValueRecord.hh
index 3222477764..d00618b763 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairValueRecord.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairValueRecord.hh
@@ -22,14 +22,14 @@ struct PairValueRecord
ValueRecord values; /* Positioning data for the first glyph
* followed by for second glyph */
public:
- DEFINE_SIZE_ARRAY (Types::size, values);
+ DEFINE_SIZE_ARRAY (Types::HBGlyphID::static_size, values);
int cmp (hb_codepoint_t k) const
{ return secondGlyph.cmp (k); }
struct context_t
{
- const void *base;
+ const ValueBase *base;
const ValueFormat *valueFormats;
const ValueFormat *newFormats;
unsigned len1; /* valueFormats[0].get_len() */
@@ -62,7 +62,7 @@ struct PairValueRecord
void collect_variation_indices (hb_collect_variation_indices_context_t *c,
const ValueFormat *valueFormats,
- const void *base) const
+ const ValueBase *base) const
{
unsigned record1_len = valueFormats[0].get_len ();
unsigned record2_len = valueFormats[1].get_len ();
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/SinglePos.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/SinglePos.hh
index 3af6c49965..a0243a218c 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/SinglePos.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/SinglePos.hh
@@ -39,14 +39,12 @@ struct SinglePos
const SrcLookup* src,
Iterator glyph_val_iter_pairs,
const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map,
- bool all_axes_pinned)
+ unsigned newFormat)
{
if (unlikely (!c->extend_min (u.format))) return;
unsigned format = 2;
- ValueFormat new_format = src->get_value_format ();
-
- if (all_axes_pinned)
- new_format = new_format.drop_device_table_flags ();
+ ValueFormat new_format;
+ new_format = newFormat;
if (glyph_val_iter_pairs)
format = get_format (glyph_val_iter_pairs);
@@ -89,8 +87,8 @@ SinglePos_serialize (hb_serialize_context_t *c,
const SrcLookup *src,
Iterator it,
const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map,
- bool all_axes_pinned)
-{ c->start_embed<SinglePos> ()->serialize (c, src, it, layout_variation_idx_delta_map, all_axes_pinned); }
+ unsigned new_format)
+{ c->start_embed<SinglePos> ()->serialize (c, src, it, layout_variation_idx_delta_map, new_format); }
}
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/SinglePosFormat1.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/SinglePosFormat1.hh
index f7a170f34e..b2d151d446 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/SinglePosFormat1.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/SinglePosFormat1.hh
@@ -8,7 +8,7 @@ namespace OT {
namespace Layout {
namespace GPOS_impl {
-struct SinglePosFormat1
+struct SinglePosFormat1 : ValueBase
{
protected:
HBUINT16 format; /* Format identifier--format = 1 */
@@ -28,7 +28,16 @@ struct SinglePosFormat1
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
coverage.sanitize (c, this) &&
+ hb_barrier () &&
+ /* The coverage table may use a range to represent a set
+ * of glyphs, which means a small number of bytes can
+ * generate a large glyph set. Manually modify the
+ * sanitizer max ops to take this into account.
+ *
+ * Note: This check *must* be right after coverage sanitize. */
+ c->check_ops ((this + coverage).get_population () >> 1) &&
valueFormat.sanitize_value (c, this, values));
+
}
bool intersects (const hb_set_t *glyphs) const
@@ -82,6 +91,7 @@ struct SinglePosFormat1
bool
position_single (hb_font_t *font,
+ hb_blob_t *table_blob,
hb_direction_t direction,
hb_codepoint_t gid,
hb_glyph_position_t &pos) const
@@ -92,7 +102,7 @@ struct SinglePosFormat1
/* This is ugly... */
hb_buffer_t buffer;
buffer.props.direction = direction;
- OT::hb_ot_apply_context_t c (1, font, &buffer);
+ OT::hb_ot_apply_context_t c (1, font, &buffer, table_blob);
valueFormat.apply_value (&c, this, values, pos);
return true;
@@ -137,6 +147,30 @@ struct SinglePosFormat1
hb_set_t intersection;
(this+coverage).intersect_set (glyphset, intersection);
+ unsigned new_format = valueFormat;
+
+ if (c->plan->normalized_coords)
+ {
+ new_format = valueFormat.get_effective_format (values.arrayZ, false, false, this, &c->plan->layout_variation_idx_delta_map);
+ }
+ /* do not strip hints for VF */
+ else if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
+ {
+ hb_blob_t* blob = hb_face_reference_table (c->plan->source, HB_TAG ('f','v','a','r'));
+ bool has_fvar = (blob != hb_blob_get_empty ());
+ hb_blob_destroy (blob);
+
+ bool strip = !has_fvar;
+ /* special case: strip hints when a VF has no GDEF varstore after
+ * subsetting*/
+ if (has_fvar && !c->plan->has_gdef_varstore)
+ strip = true;
+ new_format = valueFormat.get_effective_format (values.arrayZ,
+ strip, /* strip hints */
+ true, /* strip empty */
+ this, nullptr);
+ }
+
auto it =
+ hb_iter (intersection)
| hb_map_retains_sorting (glyph_map)
@@ -144,7 +178,7 @@ struct SinglePosFormat1
;
bool ret = bool (it);
- SinglePos_serialize (c->serializer, this, it, &c->plan->layout_variation_idx_delta_map, c->plan->all_axes_pinned);
+ SinglePos_serialize (c->serializer, this, it, &c->plan->layout_variation_idx_delta_map, new_format);
return_trace (ret);
}
};
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/SinglePosFormat2.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/SinglePosFormat2.hh
index e8f2d7c2c6..ae4a5ed756 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/SinglePosFormat2.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/SinglePosFormat2.hh
@@ -7,7 +7,7 @@ namespace OT {
namespace Layout {
namespace GPOS_impl {
-struct SinglePosFormat2
+struct SinglePosFormat2 : ValueBase
{
protected:
HBUINT16 format; /* Format identifier--format = 2 */
@@ -94,6 +94,7 @@ struct SinglePosFormat2
bool
position_single (hb_font_t *font,
+ hb_blob_t *table_blob,
hb_direction_t direction,
hb_codepoint_t gid,
hb_glyph_position_t &pos) const
@@ -105,7 +106,7 @@ struct SinglePosFormat2
/* This is ugly... */
hb_buffer_t buffer;
buffer.props.direction = direction;
- OT::hb_ot_apply_context_t c (1, font, &buffer);
+ OT::hb_ot_apply_context_t c (1, font, &buffer, table_blob);
valueFormat.apply_value (&c, this,
&values[index * valueFormat.get_len ()],
@@ -142,6 +143,37 @@ struct SinglePosFormat2
coverage.serialize_serialize (c, glyphs);
}
+ template<typename Iterator,
+ hb_requires (hb_is_iterator (Iterator))>
+ unsigned compute_effective_format (const hb_face_t *face,
+ Iterator it,
+ bool is_instancing, bool strip_hints,
+ bool has_gdef_varstore,
+ const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *varidx_delta_map) const
+ {
+ hb_blob_t* blob = hb_face_reference_table (face, HB_TAG ('f','v','a','r'));
+ bool has_fvar = (blob != hb_blob_get_empty ());
+ hb_blob_destroy (blob);
+
+ unsigned new_format = 0;
+ if (is_instancing)
+ {
+ new_format = new_format | valueFormat.get_effective_format (+ it | hb_map (hb_second), false, false, this, varidx_delta_map);
+ }
+ /* do not strip hints for VF */
+ else if (strip_hints)
+ {
+ bool strip = !has_fvar;
+ if (has_fvar && !has_gdef_varstore)
+ strip = true;
+ new_format = new_format | valueFormat.get_effective_format (+ it | hb_map (hb_second), strip, true, this, nullptr);
+ }
+ else
+ new_format = valueFormat;
+
+ return new_format;
+ }
+
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
@@ -162,8 +194,13 @@ struct SinglePosFormat2
})
;
+ unsigned new_format = compute_effective_format (c->plan->source, it,
+ bool (c->plan->normalized_coords),
+ bool (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING),
+ c->plan->has_gdef_varstore,
+ &c->plan->layout_variation_idx_delta_map);
bool ret = bool (it);
- SinglePos_serialize (c->serializer, this, it, &c->plan->layout_variation_idx_delta_map, c->plan->all_axes_pinned);
+ SinglePos_serialize (c->serializer, this, it, &c->plan->layout_variation_idx_delta_map, new_format);
return_trace (ret);
}
};
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/ValueFormat.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/ValueFormat.hh
index 1aa451abcc..9442cc1cc5 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/ValueFormat.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/ValueFormat.hh
@@ -9,6 +9,8 @@ namespace GPOS_impl {
typedef HBUINT16 Value;
+struct ValueBase {}; // Dummy base class tag for OffsetTo<Value> bases.
+
typedef UnsizedArrayOf<Value> ValueRecord;
struct ValueFormat : HBUINT16
@@ -78,7 +80,7 @@ struct ValueFormat : HBUINT16
}
bool apply_value (hb_ot_apply_context_t *c,
- const void *base,
+ const ValueBase *base,
const Value *values,
hb_glyph_position_t &glyph_pos) const
{
@@ -114,35 +116,57 @@ struct ValueFormat : HBUINT16
if (!use_x_device && !use_y_device) return ret;
- const VariationStore &store = c->var_store;
+ const ItemVariationStore &store = c->var_store;
auto *cache = c->var_store_cache;
/* pixel -> fractional pixel */
- if (format & xPlaDevice) {
- if (use_x_device) glyph_pos.x_offset += (base + get_device (values, &ret)).get_x_delta (font, store, cache);
+ if (format & xPlaDevice)
+ {
+ if (use_x_device) glyph_pos.x_offset += get_device (values, &ret, base, c->sanitizer).get_x_delta (font, store, cache);
values++;
}
- if (format & yPlaDevice) {
- if (use_y_device) glyph_pos.y_offset += (base + get_device (values, &ret)).get_y_delta (font, store, cache);
+ if (format & yPlaDevice)
+ {
+ if (use_y_device) glyph_pos.y_offset += get_device (values, &ret, base, c->sanitizer).get_y_delta (font, store, cache);
values++;
}
- if (format & xAdvDevice) {
- if (horizontal && use_x_device) glyph_pos.x_advance += (base + get_device (values, &ret)).get_x_delta (font, store, cache);
+ if (format & xAdvDevice)
+ {
+ if (horizontal && use_x_device) glyph_pos.x_advance += get_device (values, &ret, base, c->sanitizer).get_x_delta (font, store, cache);
values++;
}
- if (format & yAdvDevice) {
+ if (format & yAdvDevice)
+ {
/* y_advance values grow downward but font-space grows upward, hence negation */
- if (!horizontal && use_y_device) glyph_pos.y_advance -= (base + get_device (values, &ret)).get_y_delta (font, store, cache);
+ if (!horizontal && use_y_device) glyph_pos.y_advance -= get_device (values, &ret, base, c->sanitizer).get_y_delta (font, store, cache);
values++;
}
return ret;
}
- unsigned int get_effective_format (const Value *values) const
+ unsigned int get_effective_format (const Value *values, bool strip_hints, bool strip_empty, const ValueBase *base,
+ const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *varidx_delta_map) const
{
unsigned int format = *this;
for (unsigned flag = xPlacement; flag <= yAdvDevice; flag = flag << 1) {
- if (format & flag) should_drop (*values++, (Flags) flag, &format);
+ if (format & flag)
+ {
+ if (strip_hints && flag >= xPlaDevice)
+ {
+ format = format & ~flag;
+ values++;
+ continue;
+ }
+ if (varidx_delta_map && flag >= xPlaDevice)
+ {
+ update_var_flag (values++, (Flags) flag, &format, base, varidx_delta_map);
+ continue;
+ }
+ /* do not strip empty when instancing, cause we don't know whether the new
+ * default value is 0 or not */
+ if (strip_empty) should_drop (*values, (Flags) flag, &format);
+ values++;
+ }
}
return format;
@@ -150,18 +174,19 @@ struct ValueFormat : HBUINT16
template<typename Iterator,
hb_requires (hb_is_iterator (Iterator))>
- unsigned int get_effective_format (Iterator it) const {
+ unsigned int get_effective_format (Iterator it, bool strip_hints, bool strip_empty, const ValueBase *base,
+ const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *varidx_delta_map) const {
unsigned int new_format = 0;
for (const hb_array_t<const Value>& values : it)
- new_format = new_format | get_effective_format (&values);
+ new_format = new_format | get_effective_format (&values, strip_hints, strip_empty, base, varidx_delta_map);
return new_format;
}
void copy_values (hb_serialize_context_t *c,
unsigned int new_format,
- const void *base,
+ const ValueBase *base,
const Value *values,
const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map) const
{
@@ -174,6 +199,9 @@ struct ValueFormat : HBUINT16
if (format & xAdvance) x_adv = copy_value (c, new_format, xAdvance, *values++);
if (format & yAdvance) y_adv = copy_value (c, new_format, yAdvance, *values++);
+ if (!has_device ())
+ return;
+
if (format & xPlaDevice)
{
add_delta_to_value (x_placement, base, values, layout_variation_idx_delta_map);
@@ -210,7 +238,7 @@ struct ValueFormat : HBUINT16
}
void collect_variation_indices (hb_collect_variation_indices_context_t *c,
- const void *base,
+ const ValueBase *base,
const hb_array_t<const Value>& values) const
{
unsigned format = *this;
@@ -233,30 +261,19 @@ struct ValueFormat : HBUINT16
if (format & ValueFormat::xAdvDevice)
{
-
(base + get_device (&(values[i]))).collect_variation_indices (c);
i++;
}
if (format & ValueFormat::yAdvDevice)
{
-
(base + get_device (&(values[i]))).collect_variation_indices (c);
i++;
}
}
- unsigned drop_device_table_flags () const
- {
- unsigned format = *this;
- for (unsigned flag = xPlaDevice; flag <= yAdvDevice; flag = flag << 1)
- format = format & ~flag;
-
- return format;
- }
-
private:
- bool sanitize_value_devices (hb_sanitize_context_t *c, const void *base, const Value *values) const
+ bool sanitize_value_devices (hb_sanitize_context_t *c, const ValueBase *base, const Value *values) const
{
unsigned int format = *this;
@@ -273,18 +290,31 @@ struct ValueFormat : HBUINT16
return true;
}
- static inline Offset16To<Device>& get_device (Value* value)
+ static inline Offset16To<Device, ValueBase>& get_device (Value* value)
{
- return *static_cast<Offset16To<Device> *> (value);
+ return *static_cast<Offset16To<Device, ValueBase> *> (value);
}
- static inline const Offset16To<Device>& get_device (const Value* value, bool *worked=nullptr)
+ static inline const Offset16To<Device, ValueBase>& get_device (const Value* value)
+ {
+ return *static_cast<const Offset16To<Device, ValueBase> *> (value);
+ }
+ static inline const Device& get_device (const Value* value,
+ bool *worked,
+ const ValueBase *base,
+ hb_sanitize_context_t &c)
{
if (worked) *worked |= bool (*value);
- return *static_cast<const Offset16To<Device> *> (value);
+ auto &offset = *static_cast<const Offset16To<Device> *> (value);
+
+ if (unlikely (!offset.sanitize (&c, base)))
+ return Null(Device);
+ hb_barrier ();
+
+ return base + offset;
}
void add_delta_to_value (HBINT16 *value,
- const void *base,
+ const ValueBase *base,
const Value *src_value,
const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map) const
{
@@ -296,7 +326,8 @@ struct ValueFormat : HBUINT16
*value += hb_second (*varidx_delta);
}
- bool copy_device (hb_serialize_context_t *c, const void *base,
+ bool copy_device (hb_serialize_context_t *c,
+ const ValueBase *base,
const Value *src_value,
const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map,
unsigned int new_format, Flags flag) const
@@ -337,32 +368,34 @@ struct ValueFormat : HBUINT16
return (format & devices) != 0;
}
- bool sanitize_value (hb_sanitize_context_t *c, const void *base, const Value *values) const
+ bool sanitize_value (hb_sanitize_context_t *c, const ValueBase *base, const Value *values) const
{
TRACE_SANITIZE (this);
- return_trace (c->check_range (values, get_size ()) && (!has_device () || sanitize_value_devices (c, base, values)));
+
+ if (unlikely (!c->check_range (values, get_size ()))) return_trace (false);
+
+ if (c->lazy_some_gpos)
+ return_trace (true);
+
+ return_trace (!has_device () || sanitize_value_devices (c, base, values));
}
- bool sanitize_values (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count) const
+ bool sanitize_values (hb_sanitize_context_t *c, const ValueBase *base, const Value *values, unsigned int count) const
{
TRACE_SANITIZE (this);
- unsigned int len = get_len ();
-
- if (!c->check_range (values, count, get_size ())) return_trace (false);
+ unsigned size = get_size ();
- if (!has_device ()) return_trace (true);
+ if (!c->check_range (values, count, size)) return_trace (false);
- for (unsigned int i = 0; i < count; i++) {
- if (!sanitize_value_devices (c, base, values))
- return_trace (false);
- values += len;
- }
+ if (c->lazy_some_gpos)
+ return_trace (true);
- return_trace (true);
+ hb_barrier ();
+ return_trace (sanitize_values_stride_unsafe (c, base, values, count, size));
}
/* Just sanitize referenced Device tables. Doesn't check the values themselves. */
- bool sanitize_values_stride_unsafe (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count, unsigned int stride) const
+ bool sanitize_values_stride_unsafe (hb_sanitize_context_t *c, const ValueBase *base, const Value *values, unsigned int count, unsigned int stride) const
{
TRACE_SANITIZE (this);
@@ -385,6 +418,20 @@ struct ValueFormat : HBUINT16
*format = *format & ~flag;
}
+ void update_var_flag (const Value* value, Flags flag,
+ unsigned int* format, const ValueBase *base,
+ const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *varidx_delta_map) const
+ {
+ if (*value)
+ {
+ unsigned varidx = (base + get_device (value)).get_variation_index ();
+ hb_pair_t<unsigned, int> *varidx_delta;
+ if (varidx_delta_map->has (varidx, &varidx_delta) &&
+ varidx_delta->first != HB_OT_LAYOUT_NO_VARIATIONS_INDEX)
+ return;
+ }
+ *format = *format & ~flag;
+ }
};
}
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/Common.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/Common.hh
index 968bba0481..b849494d88 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/Common.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/Common.hh
@@ -8,8 +8,6 @@ namespace OT {
namespace Layout {
namespace GSUB_impl {
-typedef hb_pair_t<hb_codepoint_t, hb_codepoint_t> hb_codepoint_pair_t;
-
template<typename Iterator>
static void SingleSubst_serialize (hb_serialize_context_t *c,
Iterator it);
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/Ligature.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/Ligature.hh
index ffe39d52ab..e0ec82a236 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/Ligature.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/Ligature.hh
@@ -10,10 +10,10 @@ namespace GSUB_impl {
template <typename Types>
struct Ligature
{
- protected:
+ public:
typename Types::HBGlyphID
ligGlyph; /* GlyphID of ligature to substitute */
- HeadlessArrayOf<typename Types::HBGlyphID>
+ HeadlessArray16Of<typename Types::HBGlyphID>
component; /* Array of component GlyphIDs--start
* with the second component--ordered
* in writing direction */
@@ -29,6 +29,9 @@ struct Ligature
bool intersects (const hb_set_t *glyphs) const
{ return hb_all (component, glyphs); }
+ bool intersects_lig_glyph (const hb_set_t *glyphs) const
+ { return glyphs->has(ligGlyph); }
+
void closure (hb_closure_context_t *c) const
{
if (!intersects (c->glyphs)) return;
@@ -87,8 +90,17 @@ 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;
- unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
if (likely (!match_input (c, count,
&component[1],
@@ -99,6 +111,8 @@ struct Ligature
&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);
}
@@ -142,6 +156,8 @@ struct Ligature
pos);
}
+ if (match_positions != match_positions_stack)
+ hb_free (match_positions);
return_trace (true);
}
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/LigatureSet.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/LigatureSet.hh
index 637cec7137..08665438c4 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/LigatureSet.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/LigatureSet.hh
@@ -34,6 +34,18 @@ struct LigatureSet
;
}
+ bool intersects_lig_glyph (const hb_set_t *glyphs) const
+ {
+ return
+ + hb_iter (ligature)
+ | hb_map (hb_add (this))
+ | hb_map ([glyphs] (const Ligature<Types> &_) {
+ return _.intersects_lig_glyph (glyphs) && _.intersects (glyphs);
+ })
+ | hb_any
+ ;
+ }
+
void closure (hb_closure_context_t *c) const
{
+ hb_iter (ligature)
@@ -63,12 +75,69 @@ struct LigatureSet
bool apply (hb_ot_apply_context_t *c) 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)
+#endif
+ {
+ slow:
+ for (unsigned int i = 0; i < num_ligs; i++)
+ {
+ const auto &lig = this+ligature.arrayZ[i];
+ if (lig.apply (c)) return_trace (true);
+ }
+ return_trace (false);
+ }
+
+ /* This version is optimized for speed by matching the first component
+ * of the ligature here, instead of calling into the ligation code.
+ *
+ * This is replicated in ChainRuleSet and RuleSet. */
+
+ hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+ skippy_iter.reset (c->buffer->idx);
+ skippy_iter.set_match_func (match_always, nullptr);
+ skippy_iter.set_glyph_data ((HBUINT16 *) nullptr);
+ unsigned unsafe_to;
+ hb_codepoint_t first = (unsigned) -1;
+ bool matched = skippy_iter.next (&unsafe_to);
+ if (likely (matched))
+ {
+ first = c->buffer->info[skippy_iter.idx].codepoint;
+ unsafe_to = skippy_iter.idx + 1;
+
+ if (skippy_iter.may_skip (c->buffer->info[skippy_iter.idx]))
+ {
+ /* Can't use the fast path if eg. the next char is a default-ignorable
+ * or other skippable. */
+ goto slow;
+ }
+ }
+ else
+ goto slow;
+
+ bool unsafe_to_concat = false;
+
for (unsigned int i = 0; i < num_ligs; i++)
{
- const auto &lig = this+ligature[i];
- if (lig.apply (c)) return_trace (true);
+ const auto &lig = this+ligature.arrayZ[i];
+ if (unlikely (lig.component.lenP1 <= 1) ||
+ lig.component.arrayZ[0] == first)
+ {
+ if (lig.apply (c))
+ {
+ if (unsafe_to_concat)
+ c->buffer->unsafe_to_concat (c->buffer->idx, unsafe_to);
+ return_trace (true);
+ }
+ }
+ else if (likely (lig.component.lenP1 > 1))
+ unsafe_to_concat = true;
}
+ if (likely (unsafe_to_concat))
+ c->buffer->unsafe_to_concat (c->buffer->idx, unsafe_to);
return_trace (false);
}
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/LigatureSubstFormat1.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/LigatureSubstFormat1.hh
index 32b642c38a..5c7df97d13 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/LigatureSubstFormat1.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/LigatureSubstFormat1.hh
@@ -130,7 +130,7 @@ struct LigatureSubstFormat1_2
+ hb_zip (this+coverage, hb_iter (ligatureSet) | hb_map (hb_add (this)))
| hb_filter (glyphset, hb_first)
| hb_filter ([&] (const LigatureSet<Types>& _) {
- return _.intersects (&glyphset);
+ return _.intersects_lig_glyph (&glyphset);
}, hb_second)
| hb_map (hb_first)
| hb_sink (new_coverage);
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh
index 2c2e1aa44f..ec374f2f02 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh
@@ -33,9 +33,11 @@ struct ReverseChainSingleSubstFormat1
TRACE_SANITIZE (this);
if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this)))
return_trace (false);
+ hb_barrier ();
const auto &lookahead = StructAfter<decltype (lookaheadX)> (backtrack);
if (!lookahead.sanitize (c, this))
return_trace (false);
+ hb_barrier ();
const auto &substitute = StructAfter<decltype (substituteX)> (lookahead);
return_trace (substitute.sanitize (c));
}
@@ -109,12 +111,12 @@ struct ReverseChainSingleSubstFormat1
bool apply (hb_ot_apply_context_t *c) const
{
TRACE_APPLY (this);
- if (unlikely (c->nesting_level_left != HB_MAX_NESTING_LEVEL))
- return_trace (false); /* No chaining to this type */
-
unsigned int index = (this+coverage).get_coverage (c->buffer->cur ().codepoint);
if (likely (index == NOT_COVERED)) return_trace (false);
+ if (unlikely (c->nesting_level_left != HB_MAX_NESTING_LEVEL))
+ return_trace (false); /* No chaining to this type */
+
const auto &lookahead = StructAfter<decltype (lookaheadX)> (backtrack);
const auto &substitute = StructAfter<decltype (substituteX)> (lookahead);
@@ -191,7 +193,6 @@ struct ReverseChainSingleSubstFormat1
TRACE_SERIALIZE (this);
auto *out = c->serializer->start_embed (this);
- if (unlikely (!c->serializer->check_success (out))) return_trace (false);
if (unlikely (!c->serializer->embed (this->format))) return_trace (false);
if (unlikely (!c->serializer->embed (this->coverage))) return_trace (false);
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/Sequence.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/Sequence.hh
index ae3292f329..a26cf8c6a6 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/Sequence.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/Sequence.hh
@@ -53,7 +53,7 @@ struct Sequence
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->message (c->font,
- "replaced glyph at %u (multiple subtitution)",
+ "replaced glyph at %u (multiple substitution)",
c->buffer->idx - 1u);
}
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/SingleSubst.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/SingleSubst.hh
index 4529927ba6..181c9e52e5 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/SingleSubst.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/SingleSubst.hh
@@ -57,7 +57,7 @@ struct SingleSubst
#ifndef HB_NO_BEYOND_64K
if (+ glyphs
- | hb_map_retains_sorting (hb_first)
+ | hb_map_retains_sorting (hb_second)
| hb_filter ([] (hb_codepoint_t gid) { return gid > 0xFFFFu; }))
{
format += 2;
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/SingleSubstFormat1.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/SingleSubstFormat1.hh
index 78725352c2..850be86c04 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/SingleSubstFormat1.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/SingleSubstFormat1.hh
@@ -25,7 +25,15 @@ struct SingleSubstFormat1_3
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
- return_trace (coverage.sanitize (c, this) && deltaGlyphID.sanitize (c));
+ return_trace (c->check_struct (this) &&
+ coverage.sanitize (c, this) &&
+ /* The coverage table may use a range to represent a set
+ * of glyphs, which means a small number of bytes can
+ * generate a large glyph set. Manually modify the
+ * sanitizer max ops to take this into account.
+ *
+ * Note: This check *must* be right after coverage sanitize. */
+ c->check_ops ((this + coverage).get_population () >> 1));
}
hb_codepoint_t get_mask () const
@@ -87,6 +95,34 @@ struct SingleSubstFormat1_3
bool would_apply (hb_would_apply_context_t *c) const
{ return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
+ unsigned
+ get_glyph_alternates (hb_codepoint_t glyph_id,
+ unsigned start_offset,
+ unsigned *alternate_count /* IN/OUT. May be NULL. */,
+ hb_codepoint_t *alternate_glyphs /* OUT. May be NULL. */) const
+ {
+ unsigned int index = (this+coverage).get_coverage (glyph_id);
+ if (likely (index == NOT_COVERED))
+ {
+ if (alternate_count)
+ *alternate_count = 0;
+ return 0;
+ }
+
+ if (alternate_count && *alternate_count)
+ {
+ hb_codepoint_t d = deltaGlyphID;
+ hb_codepoint_t mask = get_mask ();
+
+ glyph_id = (glyph_id + d) & mask;
+
+ *alternate_glyphs = glyph_id;
+ *alternate_count = 1;
+ }
+
+ return 1;
+ }
+
bool apply (hb_ot_apply_context_t *c) const
{
TRACE_APPLY (this);
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/SingleSubstFormat2.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/SingleSubstFormat2.hh
index 17aa087363..9c651abe71 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/SingleSubstFormat2.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/SingleSubstFormat2.hh
@@ -75,6 +75,31 @@ struct SingleSubstFormat2_4
bool would_apply (hb_would_apply_context_t *c) const
{ return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
+ unsigned
+ get_glyph_alternates (hb_codepoint_t glyph_id,
+ unsigned start_offset,
+ unsigned *alternate_count /* IN/OUT. May be NULL. */,
+ hb_codepoint_t *alternate_glyphs /* OUT. May be NULL. */) const
+ {
+ unsigned int index = (this+coverage).get_coverage (glyph_id);
+ if (likely (index == NOT_COVERED))
+ {
+ if (alternate_count)
+ *alternate_count = 0;
+ return 0;
+ }
+
+ if (alternate_count && *alternate_count)
+ {
+ glyph_id = substitute[index];
+
+ *alternate_glyphs = glyph_id;
+ *alternate_count = 1;
+ }
+
+ return 1;
+ }
+
bool apply (hb_ot_apply_context_t *c) const
{
TRACE_APPLY (this);
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/types.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/types.hh
index 6a43403e94..3840db0598 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/types.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/types.hh
@@ -38,8 +38,8 @@ struct SmallTypes {
using HBUINT = HBUINT16;
using HBGlyphID = HBGlyphID16;
using Offset = Offset16;
- template <typename Type, bool has_null=true>
- using OffsetTo = OT::Offset16To<Type, has_null>;
+ template <typename Type, typename BaseType=void, bool has_null=true>
+ using OffsetTo = OT::Offset16To<Type, BaseType, has_null>;
template <typename Type>
using ArrayOf = OT::Array16Of<Type>;
template <typename Type>
@@ -52,8 +52,8 @@ struct MediumTypes {
using HBUINT = HBUINT24;
using HBGlyphID = HBGlyphID24;
using Offset = Offset24;
- template <typename Type, bool has_null=true>
- using OffsetTo = OT::Offset24To<Type, has_null>;
+ template <typename Type, typename BaseType=void, bool has_null=true>
+ using OffsetTo = OT::Offset24To<Type, BaseType, has_null>;
template <typename Type>
using ArrayOf = OT::Array24Of<Type>;
template <typename Type>