1
0
Fork 0

Merge pull request #59725 from bruvzg/hb_420

This commit is contained in:
Rémi Verschelde 2022-03-31 13:44:16 +02:00 committed by GitHub
commit e17ce39d59
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
57 changed files with 3044 additions and 2371 deletions

View File

@ -204,7 +204,7 @@ Files extracted from upstream source:
## harfbuzz
- Upstream: https://github.com/harfbuzz/harfbuzz
- Version: 4.0.1 (1f79ba9407ecd54e382997940cbcc3fb71bef8be, 2022)
- Version: 4.2.0 (9d5730b958974bc9db95e46e6bad52e9e9cd6e1c, 2022)
- License: MIT
Files extracted from upstream source:

View File

@ -0,0 +1,110 @@
#ifndef OT_LAYOUT_GSUB_ALTERNATESET_HH
#define OT_LAYOUT_GSUB_ALTERNATESET_HH
#include "Common.hh"
namespace OT {
namespace Layout {
namespace GSUB {
struct AlternateSet
{
protected:
Array16Of<HBGlyphID16>
alternates; /* Array of alternate GlyphIDs--in
* arbitrary order */
public:
DEFINE_SIZE_ARRAY (2, alternates);
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (alternates.sanitize (c));
}
bool intersects (const hb_set_t *glyphs) const
{ return hb_any (alternates, glyphs); }
void closure (hb_closure_context_t *c) const
{ c->output->add_array (alternates.arrayZ, alternates.len); }
void collect_glyphs (hb_collect_glyphs_context_t *c) const
{ c->output->add_array (alternates.arrayZ, alternates.len); }
bool apply (hb_ot_apply_context_t *c) const
{
TRACE_APPLY (this);
unsigned int count = alternates.len;
if (unlikely (!count)) return_trace (false);
hb_mask_t glyph_mask = c->buffer->cur().mask;
hb_mask_t lookup_mask = c->lookup_mask;
/* Note: This breaks badly if two features enabled this lookup together. */
unsigned int shift = hb_ctz (lookup_mask);
unsigned int alt_index = ((lookup_mask & glyph_mask) >> shift);
/* If alt_index is MAX_VALUE, randomize feature if it is the rand feature. */
if (alt_index == HB_OT_MAP_MAX_VALUE && c->random)
{
/* Maybe we can do better than unsafe-to-break all; but since we are
* changing random state, it would be hard to track that. Good 'nough. */
c->buffer->unsafe_to_break (0, c->buffer->len);
alt_index = c->random_number () % count + 1;
}
if (unlikely (alt_index > count || alt_index == 0)) return_trace (false);
c->replace_glyph (alternates[alt_index - 1]);
return_trace (true);
}
unsigned
get_alternates (unsigned start_offset,
unsigned *alternate_count /* IN/OUT. May be NULL. */,
hb_codepoint_t *alternate_glyphs /* OUT. May be NULL. */) const
{
if (alternates.len && alternate_count)
{
+ alternates.sub_array (start_offset, alternate_count)
| hb_sink (hb_array (alternate_glyphs, *alternate_count))
;
}
return alternates.len;
}
template <typename Iterator,
hb_requires (hb_is_source_of (Iterator, hb_codepoint_t))>
bool serialize (hb_serialize_context_t *c,
Iterator alts)
{
TRACE_SERIALIZE (this);
return_trace (alternates.serialize (c, alts));
}
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;
auto it =
+ hb_iter (alternates)
| hb_filter (glyphset)
| hb_map (glyph_map)
;
auto *out = c->serializer->start_embed (*this);
return_trace (out->serialize (c->serializer, it) &&
out->alternates);
}
};
}
}
}
#endif /* OT_LAYOUT_GSUB_ALTERNATESET_HH */

View File

@ -0,0 +1,51 @@
#ifndef OT_LAYOUT_GSUB_ALTERNATESUBST_HH
#define OT_LAYOUT_GSUB_ALTERNATESUBST_HH
#include "AlternateSubstFormat1.hh"
#include "Common.hh"
namespace OT {
namespace Layout {
namespace GSUB {
struct AlternateSubst
{
protected:
union {
HBUINT16 format; /* Format identifier */
AlternateSubstFormat1 format1;
} u;
public:
template <typename context_t, typename ...Ts>
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
{
TRACE_DISPATCH (this, u.format);
if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
switch (u.format) {
case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
default:return_trace (c->default_return_value ());
}
}
bool serialize (hb_serialize_context_t *c,
hb_sorted_array_t<const HBGlyphID16> glyphs,
hb_array_t<const unsigned int> alternate_len_list,
hb_array_t<const HBGlyphID16> alternate_glyphs_list)
{
TRACE_SERIALIZE (this);
if (unlikely (!c->extend_min (u.format))) return_trace (false);
unsigned int format = 1;
u.format = format;
switch (u.format) {
case 1: return_trace (u.format1.serialize (c, glyphs, alternate_len_list, alternate_glyphs_list));
default:return_trace (false);
}
}
};
}
}
}
#endif /* OT_LAYOUT_GSUB_ALTERNATESUBST_HH */

View File

@ -0,0 +1,128 @@
#ifndef OT_LAYOUT_GSUB_ALTERNATESUBSTFORMAT1_HH
#define OT_LAYOUT_GSUB_ALTERNATESUBSTFORMAT1_HH
#include "AlternateSet.hh"
#include "Common.hh"
namespace OT {
namespace Layout {
namespace GSUB {
struct AlternateSubstFormat1
{
protected:
HBUINT16 format; /* Format identifier--format = 1 */
Offset16To<Coverage>
coverage; /* Offset to Coverage table--from
* beginning of Substitution table */
Array16OfOffset16To<AlternateSet>
alternateSet; /* Array of AlternateSet tables
* ordered by Coverage Index */
public:
DEFINE_SIZE_ARRAY (6, alternateSet);
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (coverage.sanitize (c, this) && alternateSet.sanitize (c, this));
}
bool intersects (const hb_set_t *glyphs) const
{ return (this+coverage).intersects (glyphs); }
bool may_have_non_1to1 () const
{ return false; }
void closure (hb_closure_context_t *c) const
{
+ hb_zip (this+coverage, alternateSet)
| hb_filter (c->parent_active_glyphs (), hb_first)
| hb_map (hb_second)
| hb_map (hb_add (this))
| hb_apply ([c] (const AlternateSet &_) { _.closure (c); })
;
}
void closure_lookups (hb_closure_lookups_context_t *c) const {}
void collect_glyphs (hb_collect_glyphs_context_t *c) const
{
if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
+ hb_zip (this+coverage, alternateSet)
| hb_map (hb_second)
| hb_map (hb_add (this))
| hb_apply ([c] (const AlternateSet &_) { _.collect_glyphs (c); })
;
}
const Coverage &get_coverage () const { return this+coverage; }
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 gid,
unsigned start_offset,
unsigned *alternate_count /* IN/OUT. May be NULL. */,
hb_codepoint_t *alternate_glyphs /* OUT. May be NULL. */) const
{ return (this+alternateSet[(this+coverage).get_coverage (gid)])
.get_alternates (start_offset, alternate_count, alternate_glyphs); }
bool apply (hb_ot_apply_context_t *c) const
{
TRACE_APPLY (this);
unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
if (likely (index == NOT_COVERED)) return_trace (false);
return_trace ((this+alternateSet[index]).apply (c));
}
bool serialize (hb_serialize_context_t *c,
hb_sorted_array_t<const HBGlyphID16> glyphs,
hb_array_t<const unsigned int> alternate_len_list,
hb_array_t<const HBGlyphID16> alternate_glyphs_list)
{
TRACE_SERIALIZE (this);
if (unlikely (!c->extend_min (this))) return_trace (false);
if (unlikely (!alternateSet.serialize (c, glyphs.length))) return_trace (false);
for (unsigned int i = 0; i < glyphs.length; i++)
{
unsigned int alternate_len = alternate_len_list[i];
if (unlikely (!alternateSet[i]
.serialize_serialize (c, alternate_glyphs_list.sub_array (0, alternate_len))))
return_trace (false);
alternate_glyphs_list += alternate_len;
}
return_trace (coverage.serialize_serialize (c, glyphs));
}
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;
auto *out = c->serializer->start_embed (*this);
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
out->format = format;
hb_sorted_vector_t<hb_codepoint_t> new_coverage;
+ hb_zip (this+coverage, alternateSet)
| hb_filter (glyphset, hb_first)
| hb_filter (subset_offset_array (c, out->alternateSet, this), hb_second)
| hb_map (hb_first)
| hb_map (glyph_map)
| hb_sink (new_coverage)
;
out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
return_trace (bool (new_coverage));
}
};
}
}
}
#endif /* OT_LAYOUT_GSUB_ALTERNATESUBSTFORMAT1_HH */

View File

@ -0,0 +1,18 @@
#ifndef OT_LAYOUT_GSUB_CHAINCONTEXTSUBST_HH
#define OT_LAYOUT_GSUB_CHAINCONTEXTSUBST_HH
// TODO(garretrieger): move to new layout.
#include "../../../hb-ot-layout-gsubgpos.hh"
#include "Common.hh"
namespace OT {
namespace Layout {
namespace GSUB {
struct ChainContextSubst : ChainContext {};
}
}
}
#endif /* OT_LAYOUT_GSUB_CHAINCONTEXTSUBST_HH */

View File

@ -0,0 +1,21 @@
#ifndef OT_LAYOUT_GSUB_COMMON_HH
#define OT_LAYOUT_GSUB_COMMON_HH
#include "../../../hb-serialize.hh"
#include "../../../hb-ot-layout-gsubgpos.hh"
namespace OT {
namespace Layout {
namespace GSUB {
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);
}
}
}
#endif /* OT_LAYOUT_GSUB_COMMON_HH */

View File

@ -0,0 +1,18 @@
#ifndef OT_LAYOUT_GSUB_CONTEXTSUBST_HH
#define OT_LAYOUT_GSUB_CONTEXTSUBST_HH
// TODO(garretrieger): move to new layout.
#include "../../../hb-ot-layout-gsubgpos.hh"
#include "Common.hh"
namespace OT {
namespace Layout {
namespace GSUB {
struct ContextSubst : Context {};
}
}
}
#endif /* OT_LAYOUT_GSUB_CONTEXTSUBST_HH */

View File

@ -0,0 +1,22 @@
#ifndef OT_LAYOUT_GSUB_EXTENSIONSUBST_HH
#define OT_LAYOUT_GSUB_EXTENSIONSUBST_HH
// TODO(garretrieger): move to new layout.
#include "../../../hb-ot-layout-gsubgpos.hh"
#include "Common.hh"
namespace OT {
namespace Layout {
namespace GSUB {
struct ExtensionSubst : Extension<ExtensionSubst>
{
typedef struct SubstLookupSubTable SubTable;
bool is_reverse () const;
};
}
}
}
#endif /* OT_LAYOUT_GSUB_EXTENSIONSUBST_HH */

View File

@ -0,0 +1,58 @@
#ifndef OT_LAYOUT_GSUB_GSUB_HH
#define OT_LAYOUT_GSUB_GSUB_HH
// TODO(garretrieger): move to new layout.
#include "../../../hb-ot-layout-gsubgpos.hh"
#include "Common.hh"
#include "SubstLookup.hh"
using OT::Layout::GSUB::SubstLookup;
namespace OT {
namespace Layout {
namespace GSUB {
/*
* GSUB -- Glyph Substitution
* https://docs.microsoft.com/en-us/typography/opentype/spec/gsub
*/
struct GSUB : GSUBGPOS
{
static constexpr hb_tag_t tableTag = HB_OT_TAG_GSUB;
const SubstLookup& get_lookup (unsigned int i) const
{ return static_cast<const SubstLookup &> (GSUBGPOS::get_lookup (i)); }
bool subset (hb_subset_context_t *c) const
{
hb_subset_layout_context_t l (c, tableTag, c->plan->gsub_lookups, c->plan->gsub_langsys, c->plan->gsub_features);
return GSUBGPOS::subset<SubstLookup> (&l);
}
bool sanitize (hb_sanitize_context_t *c) const
{ return GSUBGPOS::sanitize<SubstLookup> (c); }
HB_INTERNAL bool is_blocklisted (hb_blob_t *blob,
hb_face_t *face) const;
void closure_lookups (hb_face_t *face,
const hb_set_t *glyphs,
hb_set_t *lookup_indexes /* IN/OUT */) const
{ GSUBGPOS::closure_lookups<SubstLookup> (face, glyphs, lookup_indexes); }
typedef GSUBGPOS::accelerator_t<GSUB> accelerator_t;
};
}
}
struct GSUB_accelerator_t : Layout::GSUB::GSUB::accelerator_t {
GSUB_accelerator_t (hb_face_t *face) : Layout::GSUB::GSUB::accelerator_t (face) {}
};
}
#endif /* OT_LAYOUT_GSUB_GSUB_HH */

View File

@ -0,0 +1,135 @@
#ifndef OT_LAYOUT_GSUB_LIGATURE_HH
#define OT_LAYOUT_GSUB_LIGATURE_HH
#include "Common.hh"
namespace OT {
namespace Layout {
namespace GSUB {
struct Ligature
{
protected:
HBGlyphID16 ligGlyph; /* GlyphID of ligature to substitute */
HeadlessArrayOf<HBGlyphID16>
component; /* Array of component GlyphIDs--start
* with the second component--ordered
* in writing direction */
public:
DEFINE_SIZE_ARRAY (4, component);
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (ligGlyph.sanitize (c) && component.sanitize (c));
}
bool intersects (const hb_set_t *glyphs) const
{ return hb_all (component, glyphs); }
void closure (hb_closure_context_t *c) const
{
if (!intersects (c->glyphs)) return;
c->output->add (ligGlyph);
}
void collect_glyphs (hb_collect_glyphs_context_t *c) const
{
c->input->add_array (component.arrayZ, component.get_length ());
c->output->add (ligGlyph);
}
bool would_apply (hb_would_apply_context_t *c) const
{
if (c->len != component.lenP1)
return false;
for (unsigned int i = 1; i < c->len; i++)
if (likely (c->glyphs[i] != component[i]))
return false;
return true;
}
bool apply (hb_ot_apply_context_t *c) const
{
TRACE_APPLY (this);
unsigned int count = component.lenP1;
if (unlikely (!count)) return_trace (false);
/* Special-case to make it in-place and not consider this
* as a "ligated" substitution. */
if (unlikely (count == 1))
{
c->replace_glyph (ligGlyph);
return_trace (true);
}
unsigned int total_component_count = 0;
unsigned int match_end = 0;
unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
if (likely (!match_input (c, count,
&component[1],
match_glyph,
nullptr,
&match_end,
match_positions,
&total_component_count)))
{
c->buffer->unsafe_to_concat (c->buffer->idx, match_end);
return_trace (false);
}
ligate_input (c,
count,
match_positions,
match_end,
ligGlyph,
total_component_count);
return_trace (true);
}
template <typename Iterator,
hb_requires (hb_is_source_of (Iterator, hb_codepoint_t))>
bool serialize (hb_serialize_context_t *c,
hb_codepoint_t ligature,
Iterator components /* Starting from second */)
{
TRACE_SERIALIZE (this);
if (unlikely (!c->extend_min (this))) return_trace (false);
ligGlyph = ligature;
if (unlikely (!component.serialize (c, components))) return_trace (false);
return_trace (true);
}
bool subset (hb_subset_context_t *c, unsigned coverage_idx) const
{
TRACE_SUBSET (this);
const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map;
if (!intersects (&glyphset) || !glyphset.has (ligGlyph)) return_trace (false);
// Ensure Coverage table is always packed after this.
c->serializer->add_virtual_link (coverage_idx);
auto it =
+ hb_iter (component)
| hb_map (glyph_map)
;
auto *out = c->serializer->start_embed (*this);
return_trace (out->serialize (c->serializer,
glyph_map[ligGlyph],
it)); }
};
}
}
}
#endif /* OT_LAYOUT_GSUB_LIGATURE_HH */

View File

@ -0,0 +1,118 @@
#ifndef OT_LAYOUT_GSUB_LIGATURESET_HH
#define OT_LAYOUT_GSUB_LIGATURESET_HH
#include "Common.hh"
#include "Ligature.hh"
namespace OT {
namespace Layout {
namespace GSUB {
struct LigatureSet
{
protected:
Array16OfOffset16To<Ligature>
ligature; /* Array LigatureSet tables
* ordered by preference */
public:
DEFINE_SIZE_ARRAY (2, ligature);
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (ligature.sanitize (c, this));
}
bool intersects (const hb_set_t *glyphs) const
{
return
+ hb_iter (ligature)
| hb_map (hb_add (this))
| hb_map ([glyphs] (const Ligature &_) { return _.intersects (glyphs); })
| hb_any
;
}
void closure (hb_closure_context_t *c) const
{
+ hb_iter (ligature)
| hb_map (hb_add (this))
| hb_apply ([c] (const Ligature &_) { _.closure (c); })
;
}
void collect_glyphs (hb_collect_glyphs_context_t *c) const
{
+ hb_iter (ligature)
| hb_map (hb_add (this))
| hb_apply ([c] (const Ligature &_) { _.collect_glyphs (c); })
;
}
bool would_apply (hb_would_apply_context_t *c) const
{
return
+ hb_iter (ligature)
| hb_map (hb_add (this))
| hb_map ([c] (const Ligature &_) { return _.would_apply (c); })
| hb_any
;
}
bool apply (hb_ot_apply_context_t *c) const
{
TRACE_APPLY (this);
unsigned int num_ligs = ligature.len;
for (unsigned int i = 0; i < num_ligs; i++)
{
const Ligature &lig = this+ligature[i];
if (lig.apply (c)) return_trace (true);
}
return_trace (false);
}
bool serialize (hb_serialize_context_t *c,
hb_array_t<const HBGlyphID16> ligatures,
hb_array_t<const unsigned int> component_count_list,
hb_array_t<const HBGlyphID16> &component_list /* Starting from second for each ligature */)
{
TRACE_SERIALIZE (this);
if (unlikely (!c->extend_min (this))) return_trace (false);
if (unlikely (!ligature.serialize (c, ligatures.length))) return_trace (false);
for (unsigned int i = 0; i < ligatures.length; i++)
{
unsigned int component_count = (unsigned) hb_max ((int) component_count_list[i] - 1, 0);
if (unlikely (!ligature[i].serialize_serialize (c,
ligatures[i],
component_list.sub_array (0, component_count))))
return_trace (false);
component_list += component_count;
}
return_trace (true);
}
bool subset (hb_subset_context_t *c, unsigned coverage_idx) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (*this);
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+ hb_iter (ligature)
| hb_filter (subset_offset_array (c, out->ligature, this, coverage_idx))
| hb_drain
;
if (bool (out->ligature))
// Ensure Coverage table is always packed after this.
c->serializer->add_virtual_link (coverage_idx);
return_trace (bool (out->ligature));
}
};
}
}
}
#endif /* OT_LAYOUT_GSUB_LIGATURESET_HH */

View File

@ -0,0 +1,59 @@
#ifndef OT_LAYOUT_GSUB_LIGATURESUBST_HH
#define OT_LAYOUT_GSUB_LIGATURESUBST_HH
#include "Common.hh"
#include "LigatureSubstFormat1.hh"
namespace OT {
namespace Layout {
namespace GSUB {
struct LigatureSubst
{
protected:
union {
HBUINT16 format; /* Format identifier */
LigatureSubstFormat1 format1;
} u;
public:
template <typename context_t, typename ...Ts>
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
{
TRACE_DISPATCH (this, u.format);
if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
switch (u.format) {
case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
default:return_trace (c->default_return_value ());
}
}
bool serialize (hb_serialize_context_t *c,
hb_sorted_array_t<const HBGlyphID16> first_glyphs,
hb_array_t<const unsigned int> ligature_per_first_glyph_count_list,
hb_array_t<const HBGlyphID16> ligatures_list,
hb_array_t<const unsigned int> component_count_list,
hb_array_t<const HBGlyphID16> component_list /* Starting from second for each ligature */)
{
TRACE_SERIALIZE (this);
if (unlikely (!c->extend_min (u.format))) return_trace (false);
unsigned int format = 1;
u.format = format;
switch (u.format) {
case 1: return_trace (u.format1.serialize (c,
first_glyphs,
ligature_per_first_glyph_count_list,
ligatures_list,
component_count_list,
component_list));
default:return_trace (false);
}
}
};
}
}
}
#endif /* OT_LAYOUT_GSUB_LIGATURESUBST_HH */

View File

@ -0,0 +1,165 @@
#ifndef OT_LAYOUT_GSUB_LIGATURESUBSTFORMAT1_HH
#define OT_LAYOUT_GSUB_LIGATURESUBSTFORMAT1_HH
#include "Common.hh"
#include "LigatureSet.hh"
namespace OT {
namespace Layout {
namespace GSUB {
struct LigatureSubstFormat1
{
protected:
HBUINT16 format; /* Format identifier--format = 1 */
Offset16To<Coverage>
coverage; /* Offset to Coverage table--from
* beginning of Substitution table */
Array16OfOffset16To<LigatureSet>
ligatureSet; /* Array LigatureSet tables
* ordered by Coverage Index */
public:
DEFINE_SIZE_ARRAY (6, ligatureSet);
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this));
}
bool intersects (const hb_set_t *glyphs) const
{
return
+ hb_zip (this+coverage, ligatureSet)
| hb_filter (*glyphs, hb_first)
| hb_map (hb_second)
| hb_map ([this, glyphs] (const Offset16To<LigatureSet> &_)
{ return (this+_).intersects (glyphs); })
| hb_any
;
}
bool may_have_non_1to1 () const
{ return true; }
void closure (hb_closure_context_t *c) const
{
+ hb_zip (this+coverage, ligatureSet)
| hb_filter (c->parent_active_glyphs (), hb_first)
| hb_map (hb_second)
| hb_map (hb_add (this))
| hb_apply ([c] (const LigatureSet &_) { _.closure (c); })
;
}
void closure_lookups (hb_closure_lookups_context_t *c) const {}
void collect_glyphs (hb_collect_glyphs_context_t *c) const
{
if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
+ hb_zip (this+coverage, ligatureSet)
| hb_map (hb_second)
| hb_map (hb_add (this))
| hb_apply ([c] (const LigatureSet &_) { _.collect_glyphs (c); })
;
}
const Coverage &get_coverage () const { return this+coverage; }
bool would_apply (hb_would_apply_context_t *c) const
{
unsigned int index = (this+coverage).get_coverage (c->glyphs[0]);
if (likely (index == NOT_COVERED)) return false;
const LigatureSet &lig_set = this+ligatureSet[index];
return lig_set.would_apply (c);
}
bool apply (hb_ot_apply_context_t *c) const
{
TRACE_APPLY (this);
unsigned int index = (this+coverage).get_coverage (c->buffer->cur ().codepoint);
if (likely (index == NOT_COVERED)) return_trace (false);
const LigatureSet &lig_set = this+ligatureSet[index];
return_trace (lig_set.apply (c));
}
bool serialize (hb_serialize_context_t *c,
hb_sorted_array_t<const HBGlyphID16> first_glyphs,
hb_array_t<const unsigned int> ligature_per_first_glyph_count_list,
hb_array_t<const HBGlyphID16> ligatures_list,
hb_array_t<const unsigned int> component_count_list,
hb_array_t<const HBGlyphID16> component_list /* Starting from second for each ligature */)
{
TRACE_SERIALIZE (this);
if (unlikely (!c->extend_min (this))) return_trace (false);
if (unlikely (!ligatureSet.serialize (c, first_glyphs.length))) return_trace (false);
for (unsigned int i = 0; i < first_glyphs.length; i++)
{
unsigned int ligature_count = ligature_per_first_glyph_count_list[i];
if (unlikely (!ligatureSet[i]
.serialize_serialize (c,
ligatures_list.sub_array (0, ligature_count),
component_count_list.sub_array (0, ligature_count),
component_list))) return_trace (false);
ligatures_list += ligature_count;
component_count_list += ligature_count;
}
return_trace (coverage.serialize_serialize (c, first_glyphs));
}
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;
auto *out = c->serializer->start_embed (*this);
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
out->format = format;
// Due to a bug in some older versions of windows 7 the Coverage table must be
// packed after the LigatureSet and Ligature tables, so serialize Coverage first
// which places it last in the packed order.
hb_set_t new_coverage;
+ hb_zip (this+coverage, hb_iter (ligatureSet) | hb_map (hb_add (this)))
| hb_filter (glyphset, hb_first)
| hb_filter ([&] (const LigatureSet& _) {
return _.intersects (&glyphset);
}, hb_second)
| hb_map (hb_first)
| hb_sink (new_coverage);
if (!c->serializer->push<Coverage> ()
->serialize (c->serializer,
+ new_coverage.iter () | hb_map_retains_sorting (glyph_map)))
{
c->serializer->pop_discard ();
return_trace (false);
}
unsigned coverage_idx = c->serializer->pop_pack ();
c->serializer->add_link (out->coverage, coverage_idx);
+ hb_zip (this+coverage, ligatureSet)
| hb_filter (new_coverage, hb_first)
| hb_map (hb_second)
// to ensure that the repacker always orders the coverage table after the LigatureSet
// and LigatureSubtable's they will be linked to the Coverage table via a virtual link
// the coverage table object idx is passed down to facilitate this.
| hb_apply (subset_offset_array (c, out->ligatureSet, this, coverage_idx))
;
return_trace (bool (new_coverage));
}
};
}
}
}
#endif /* OT_LAYOUT_GSUB_LIGATURESUBSTFORMAT1_HH */

View File

@ -0,0 +1,53 @@
#ifndef OT_LAYOUT_GSUB_MULTIPLESUBST_HH
#define OT_LAYOUT_GSUB_MULTIPLESUBST_HH
#include "Common.hh"
#include "MultipleSubstFormat1.hh"
namespace OT {
namespace Layout {
namespace GSUB {
struct MultipleSubst
{
protected:
union {
HBUINT16 format; /* Format identifier */
MultipleSubstFormat1 format1;
} u;
public:
template <typename context_t, typename ...Ts>
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
{
TRACE_DISPATCH (this, u.format);
if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
switch (u.format) {
case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
default:return_trace (c->default_return_value ());
}
}
bool serialize (hb_serialize_context_t *c,
hb_sorted_array_t<const HBGlyphID16> glyphs,
hb_array_t<const unsigned int> substitute_len_list,
hb_array_t<const HBGlyphID16> substitute_glyphs_list)
{
TRACE_SERIALIZE (this);
if (unlikely (!c->extend_min (u.format))) return_trace (false);
unsigned int format = 1;
u.format = format;
switch (u.format) {
case 1: return_trace (u.format1.serialize (c, glyphs, substitute_len_list, substitute_glyphs_list));
default:return_trace (false);
}
}
};
}
}
}
#endif /* OT_LAYOUT_GSUB_MULTIPLESUBST_HH */

View File

@ -0,0 +1,120 @@
#ifndef OT_LAYOUT_GSUB_MULTIPLESUBSTFORMAT1_HH
#define OT_LAYOUT_GSUB_MULTIPLESUBSTFORMAT1_HH
#include "Common.hh"
#include "Sequence.hh"
namespace OT {
namespace Layout {
namespace GSUB {
struct MultipleSubstFormat1
{
protected:
HBUINT16 format; /* Format identifier--format = 1 */
Offset16To<Coverage>
coverage; /* Offset to Coverage table--from
* beginning of Substitution table */
Array16OfOffset16To<Sequence>
sequence; /* Array of Sequence tables
* ordered by Coverage Index */
public:
DEFINE_SIZE_ARRAY (6, sequence);
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (coverage.sanitize (c, this) && sequence.sanitize (c, this));
}
bool intersects (const hb_set_t *glyphs) const
{ return (this+coverage).intersects (glyphs); }
bool may_have_non_1to1 () const
{ return true; }
void closure (hb_closure_context_t *c) const
{
+ hb_zip (this+coverage, sequence)
| hb_filter (c->parent_active_glyphs (), hb_first)
| hb_map (hb_second)
| hb_map (hb_add (this))
| hb_apply ([c] (const Sequence &_) { _.closure (c); })
;
}
void closure_lookups (hb_closure_lookups_context_t *c) const {}
void collect_glyphs (hb_collect_glyphs_context_t *c) const
{
if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
+ hb_zip (this+coverage, sequence)
| hb_map (hb_second)
| hb_map (hb_add (this))
| hb_apply ([c] (const Sequence &_) { _.collect_glyphs (c); })
;
}
const Coverage &get_coverage () const { return this+coverage; }
bool would_apply (hb_would_apply_context_t *c) const
{ return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
bool apply (hb_ot_apply_context_t *c) const
{
TRACE_APPLY (this);
unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
if (likely (index == NOT_COVERED)) return_trace (false);
return_trace ((this+sequence[index]).apply (c));
}
bool serialize (hb_serialize_context_t *c,
hb_sorted_array_t<const HBGlyphID16> glyphs,
hb_array_t<const unsigned int> substitute_len_list,
hb_array_t<const HBGlyphID16> substitute_glyphs_list)
{
TRACE_SERIALIZE (this);
if (unlikely (!c->extend_min (this))) return_trace (false);
if (unlikely (!sequence.serialize (c, glyphs.length))) return_trace (false);
for (unsigned int i = 0; i < glyphs.length; i++)
{
unsigned int substitute_len = substitute_len_list[i];
if (unlikely (!sequence[i]
.serialize_serialize (c, substitute_glyphs_list.sub_array (0, substitute_len))))
return_trace (false);
substitute_glyphs_list += substitute_len;
}
return_trace (coverage.serialize_serialize (c, glyphs));
}
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;
auto *out = c->serializer->start_embed (*this);
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
out->format = format;
hb_sorted_vector_t<hb_codepoint_t> new_coverage;
+ hb_zip (this+coverage, sequence)
| hb_filter (glyphset, hb_first)
| hb_filter (subset_offset_array (c, out->sequence, this), hb_second)
| hb_map (hb_first)
| hb_map (glyph_map)
| hb_sink (new_coverage)
;
out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
return_trace (bool (new_coverage));
}
};
}
}
}
#endif /* OT_LAYOUT_GSUB_MULTIPLESUBSTFORMAT1_HH */

View File

@ -0,0 +1,36 @@
#ifndef OT_LAYOUT_GSUB_REVERSECHAINSINGLESUBST_HH
#define OT_LAYOUT_GSUB_REVERSECHAINSINGLESUBST_HH
#include "Common.hh"
#include "ReverseChainSingleSubstFormat1.hh"
namespace OT {
namespace Layout {
namespace GSUB {
struct ReverseChainSingleSubst
{
protected:
union {
HBUINT16 format; /* Format identifier */
ReverseChainSingleSubstFormat1 format1;
} u;
public:
template <typename context_t, typename ...Ts>
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
{
TRACE_DISPATCH (this, u.format);
if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
switch (u.format) {
case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
default:return_trace (c->default_return_value ());
}
}
};
}
}
}
#endif /* HB_OT_LAYOUT_GSUB_REVERSECHAINSINGLESUBST_HH */

View File

@ -0,0 +1,228 @@
#ifndef OT_LAYOUT_GSUB_REVERSECHAINSINGLESUBSTFORMAT1_HH
#define OT_LAYOUT_GSUB_REVERSECHAINSINGLESUBSTFORMAT1_HH
#include "Common.hh"
namespace OT {
namespace Layout {
namespace GSUB {
struct ReverseChainSingleSubstFormat1
{
protected:
HBUINT16 format; /* Format identifier--format = 1 */
Offset16To<Coverage>
coverage; /* Offset to Coverage table--from
* beginning of table */
Array16OfOffset16To<Coverage>
backtrack; /* Array of coverage tables
* in backtracking sequence, in glyph
* sequence order */
Array16OfOffset16To<Coverage>
lookaheadX; /* Array of coverage tables
* in lookahead sequence, in glyph
* sequence order */
Array16Of<HBGlyphID16>
substituteX; /* Array of substitute
* GlyphIDs--ordered by Coverage Index */
public:
DEFINE_SIZE_MIN (10);
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this)))
return_trace (false);
const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
if (!lookahead.sanitize (c, this))
return_trace (false);
const Array16Of<HBGlyphID16> &substitute = StructAfter<Array16Of<HBGlyphID16>> (lookahead);
return_trace (substitute.sanitize (c));
}
bool intersects (const hb_set_t *glyphs) const
{
if (!(this+coverage).intersects (glyphs))
return false;
const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
unsigned int count;
count = backtrack.len;
for (unsigned int i = 0; i < count; i++)
if (!(this+backtrack[i]).intersects (glyphs))
return false;
count = lookahead.len;
for (unsigned int i = 0; i < count; i++)
if (!(this+lookahead[i]).intersects (glyphs))
return false;
return true;
}
bool may_have_non_1to1 () const
{ return false; }
void closure (hb_closure_context_t *c) const
{
if (!intersects (c->glyphs)) return;
const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
const Array16Of<HBGlyphID16> &substitute = StructAfter<Array16Of<HBGlyphID16>> (lookahead);
+ hb_zip (this+coverage, substitute)
| hb_filter (c->parent_active_glyphs (), hb_first)
| hb_map (hb_second)
| hb_sink (c->output)
;
}
void closure_lookups (hb_closure_lookups_context_t *c) const {}
void collect_glyphs (hb_collect_glyphs_context_t *c) const
{
if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
unsigned int count;
count = backtrack.len;
for (unsigned int i = 0; i < count; i++)
if (unlikely (!(this+backtrack[i]).collect_coverage (c->before))) return;
const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
count = lookahead.len;
for (unsigned int i = 0; i < count; i++)
if (unlikely (!(this+lookahead[i]).collect_coverage (c->after))) return;
const Array16Of<HBGlyphID16> &substitute = StructAfter<Array16Of<HBGlyphID16>> (lookahead);
count = substitute.len;
c->output->add_array (substitute.arrayZ, substitute.len);
}
const Coverage &get_coverage () const { return this+coverage; }
bool would_apply (hb_would_apply_context_t *c) const
{ return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
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);
const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
const Array16Of<HBGlyphID16> &substitute = StructAfter<Array16Of<HBGlyphID16>> (lookahead);
if (unlikely (index >= substitute.len)) return_trace (false);
unsigned int start_index = 0, end_index = 0;
if (match_backtrack (c,
backtrack.len, (HBUINT16 *) backtrack.arrayZ,
match_coverage, this,
&start_index) &&
match_lookahead (c,
lookahead.len, (HBUINT16 *) lookahead.arrayZ,
match_coverage, this,
c->buffer->idx + 1, &end_index))
{
c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index);
c->replace_glyph_inplace (substitute[index]);
/* Note: We DON'T decrease buffer->idx. The main loop does it
* for us. This is useful for preventing surprises if someone
* calls us through a Context lookup. */
return_trace (true);
}
else
{
c->buffer->unsafe_to_concat_from_outbuffer (start_index, end_index);
return_trace (false);
}
}
template<typename Iterator,
hb_requires (hb_is_iterator (Iterator))>
bool serialize_coverage_offset_array (hb_subset_context_t *c, Iterator it) const
{
TRACE_SERIALIZE (this);
auto *out = c->serializer->start_embed<Array16OfOffset16To<Coverage>> ();
if (unlikely (!c->serializer->allocate_size<HBUINT16> (HBUINT16::static_size)))
return_trace (false);
for (auto& offset : it) {
auto *o = out->serialize_append (c->serializer);
if (unlikely (!o) || !o->serialize_subset (c, offset, this))
return_trace (false);
}
return_trace (true);
}
template<typename Iterator, typename BacktrackIterator, typename LookaheadIterator,
hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_pair_t)),
hb_requires (hb_is_iterator (BacktrackIterator)),
hb_requires (hb_is_iterator (LookaheadIterator))>
bool serialize (hb_subset_context_t *c,
Iterator coverage_subst_iter,
BacktrackIterator backtrack_iter,
LookaheadIterator lookahead_iter) const
{
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);
if (!serialize_coverage_offset_array (c, backtrack_iter)) return_trace (false);
if (!serialize_coverage_offset_array (c, lookahead_iter)) return_trace (false);
auto *substitute_out = c->serializer->start_embed<Array16Of<HBGlyphID16>> ();
auto substitutes =
+ coverage_subst_iter
| hb_map (hb_second)
;
auto glyphs =
+ coverage_subst_iter
| hb_map_retains_sorting (hb_first)
;
if (unlikely (! c->serializer->check_success (substitute_out->serialize (c->serializer, substitutes))))
return_trace (false);
if (unlikely (!out->coverage.serialize_serialize (c->serializer, glyphs)))
return_trace (false);
return_trace (true);
}
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 Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
const Array16Of<HBGlyphID16> &substitute = StructAfter<Array16Of<HBGlyphID16>> (lookahead);
auto it =
+ hb_zip (this+coverage, substitute)
| hb_filter (glyphset, hb_first)
| hb_filter (glyphset, hb_second)
| hb_map_retains_sorting ([&] (hb_pair_t<hb_codepoint_t, const HBGlyphID16 &> p) -> hb_codepoint_pair_t
{ return hb_pair (glyph_map[p.first], glyph_map[p.second]); })
;
return_trace (bool (it) && serialize (c, it, backtrack.iter (), lookahead.iter ()));
}
};
}
}
}
#endif /* HB_OT_LAYOUT_GSUB_REVERSECHAINSINGLESUBSTFORMAT1_HH */

View File

@ -0,0 +1,103 @@
#ifndef OT_LAYOUT_GSUB_SEQUENCE_HH
#define OT_LAYOUT_GSUB_SEQUENCE_HH
#include "Common.hh"
namespace OT {
namespace Layout {
namespace GSUB {
struct Sequence
{
protected:
Array16Of<HBGlyphID16>
substitute; /* String of GlyphIDs to substitute */
public:
DEFINE_SIZE_ARRAY (2, substitute);
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (substitute.sanitize (c));
}
bool intersects (const hb_set_t *glyphs) const
{ return hb_all (substitute, glyphs); }
void closure (hb_closure_context_t *c) const
{ c->output->add_array (substitute.arrayZ, substitute.len); }
void collect_glyphs (hb_collect_glyphs_context_t *c) const
{ c->output->add_array (substitute.arrayZ, substitute.len); }
bool apply (hb_ot_apply_context_t *c) const
{
TRACE_APPLY (this);
unsigned int count = substitute.len;
/* Special-case to make it in-place and not consider this
* as a "multiplied" substitution. */
if (unlikely (count == 1))
{
c->replace_glyph (substitute.arrayZ[0]);
return_trace (true);
}
/* Spec disallows this, but Uniscribe allows it.
* https://github.com/harfbuzz/harfbuzz/issues/253 */
else if (unlikely (count == 0))
{
c->buffer->delete_glyph ();
return_trace (true);
}
unsigned int klass = _hb_glyph_info_is_ligature (&c->buffer->cur()) ?
HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH : 0;
unsigned lig_id = _hb_glyph_info_get_lig_id (&c->buffer->cur());
for (unsigned int i = 0; i < count; i++)
{
/* If is attached to a ligature, don't disturb that.
* https://github.com/harfbuzz/harfbuzz/issues/3069 */
if (!lig_id)
_hb_glyph_info_set_lig_props_for_component (&c->buffer->cur(), i);
c->output_glyph_for_component (substitute.arrayZ[i], klass);
}
c->buffer->skip_glyph ();
return_trace (true);
}
template <typename Iterator,
hb_requires (hb_is_source_of (Iterator, hb_codepoint_t))>
bool serialize (hb_serialize_context_t *c,
Iterator subst)
{
TRACE_SERIALIZE (this);
return_trace (substitute.serialize (c, subst));
}
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;
if (!intersects (&glyphset)) return_trace (false);
auto it =
+ hb_iter (substitute)
| hb_map (glyph_map)
;
auto *out = c->serializer->start_embed (*this);
return_trace (out->serialize (c->serializer, it));
}
};
}
}
}
#endif /* OT_LAYOUT_GSUB_SEQUENCE_HH */

View File

@ -0,0 +1,75 @@
#ifndef OT_LAYOUT_GSUB_SINGLESUBST_HH
#define OT_LAYOUT_GSUB_SINGLESUBST_HH
#include "Common.hh"
#include "SingleSubstFormat1.hh"
#include "SingleSubstFormat2.hh"
namespace OT {
namespace Layout {
namespace GSUB {
struct SingleSubst
{
protected:
union {
HBUINT16 format; /* Format identifier */
SingleSubstFormat1 format1;
SingleSubstFormat2 format2;
} u;
public:
template <typename context_t, typename ...Ts>
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
{
TRACE_DISPATCH (this, u.format);
if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
switch (u.format) {
case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
default:return_trace (c->default_return_value ());
}
}
template<typename Iterator,
hb_requires (hb_is_sorted_source_of (Iterator,
const hb_codepoint_pair_t))>
bool serialize (hb_serialize_context_t *c,
Iterator glyphs)
{
TRACE_SERIALIZE (this);
if (unlikely (!c->extend_min (u.format))) return_trace (false);
unsigned format = 2;
unsigned delta = 0;
if (glyphs)
{
format = 1;
auto get_delta = [=] (hb_codepoint_pair_t _)
{ return (unsigned) (_.second - _.first) & 0xFFFF; };
delta = get_delta (*glyphs);
if (!hb_all (++(+glyphs), delta, get_delta)) format = 2;
}
u.format = format;
switch (u.format) {
case 1: return_trace (u.format1.serialize (c,
+ glyphs
| hb_map_retains_sorting (hb_first),
delta));
case 2: return_trace (u.format2.serialize (c, glyphs));
default:return_trace (false);
}
}
};
template<typename Iterator>
static void
SingleSubst_serialize (hb_serialize_context_t *c,
Iterator it)
{ c->start_embed<SingleSubst> ()->serialize (c, it); }
}
}
}
#endif /* OT_LAYOUT_GSUB_SINGLESUBST_HH */

View File

@ -0,0 +1,122 @@
#ifndef OT_LAYOUT_GSUB_SINGLESUBSTFORMAT1_HH
#define OT_LAYOUT_GSUB_SINGLESUBSTFORMAT1_HH
#include "Common.hh"
namespace OT {
namespace Layout {
namespace GSUB {
struct SingleSubstFormat1
{
protected:
HBUINT16 format; /* Format identifier--format = 1 */
Offset16To<Coverage>
coverage; /* Offset to Coverage table--from
* beginning of Substitution table */
HBUINT16 deltaGlyphID; /* Add to original GlyphID to get
* substitute GlyphID, modulo 0x10000 */
public:
DEFINE_SIZE_STATIC (6);
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (coverage.sanitize (c, this) && deltaGlyphID.sanitize (c));
}
bool intersects (const hb_set_t *glyphs) const
{ return (this+coverage).intersects (glyphs); }
bool may_have_non_1to1 () const
{ return false; }
void closure (hb_closure_context_t *c) const
{
unsigned d = deltaGlyphID;
+ hb_iter (this+coverage)
| hb_filter (c->parent_active_glyphs ())
| hb_map ([d] (hb_codepoint_t g) { return (g + d) & 0xFFFFu; })
| hb_sink (c->output)
;
}
void closure_lookups (hb_closure_lookups_context_t *c) const {}
void collect_glyphs (hb_collect_glyphs_context_t *c) const
{
if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
unsigned d = deltaGlyphID;
+ hb_iter (this+coverage)
| hb_map ([d] (hb_codepoint_t g) { return (g + d) & 0xFFFFu; })
| hb_sink (c->output)
;
}
const Coverage &get_coverage () const { return this+coverage; }
bool would_apply (hb_would_apply_context_t *c) const
{ return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
bool apply (hb_ot_apply_context_t *c) const
{
TRACE_APPLY (this);
hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
unsigned int index = (this+coverage).get_coverage (glyph_id);
if (likely (index == NOT_COVERED)) return_trace (false);
/* According to the Adobe Annotated OpenType Suite, result is always
* limited to 16bit. */
glyph_id = (glyph_id + deltaGlyphID) & 0xFFFFu;
c->replace_glyph (glyph_id);
return_trace (true);
}
template<typename Iterator,
hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))>
bool serialize (hb_serialize_context_t *c,
Iterator glyphs,
unsigned delta)
{
TRACE_SERIALIZE (this);
if (unlikely (!c->extend_min (this))) return_trace (false);
if (unlikely (!coverage.serialize_serialize (c, glyphs))) return_trace (false);
c->check_assign (deltaGlyphID, delta, HB_SERIALIZE_ERROR_INT_OVERFLOW);
return_trace (true);
}
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;
hb_codepoint_t delta = deltaGlyphID;
auto it =
+ hb_iter (this+coverage)
| hb_filter (glyphset)
| hb_map_retains_sorting ([&] (hb_codepoint_t g) {
return hb_codepoint_pair_t (g,
(g + delta) & 0xFFFF); })
| hb_filter (glyphset, hb_second)
| hb_map_retains_sorting ([&] (hb_codepoint_pair_t p) -> hb_codepoint_pair_t
{ return hb_pair (glyph_map[p.first], glyph_map[p.second]); })
;
bool ret = bool (it);
SingleSubst_serialize (c->serializer, it);
return_trace (ret);
}
};
}
}
}
#endif /* OT_LAYOUT_GSUB_SINGLESUBSTFORMAT1_HH */

View File

@ -0,0 +1,120 @@
#ifndef OT_LAYOUT_GSUB_SINGLESUBSTFORMAT2_HH
#define OT_LAYOUT_GSUB_SINGLESUBSTFORMAT2_HH
#include "Common.hh"
namespace OT {
namespace Layout {
namespace GSUB {
struct SingleSubstFormat2
{
protected:
HBUINT16 format; /* Format identifier--format = 2 */
Offset16To<Coverage>
coverage; /* Offset to Coverage table--from
* beginning of Substitution table */
Array16Of<HBGlyphID16>
substitute; /* Array of substitute
* GlyphIDs--ordered by Coverage Index */
public:
DEFINE_SIZE_ARRAY (6, substitute);
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (coverage.sanitize (c, this) && substitute.sanitize (c));
}
bool intersects (const hb_set_t *glyphs) const
{ return (this+coverage).intersects (glyphs); }
bool may_have_non_1to1 () const
{ return false; }
void closure (hb_closure_context_t *c) const
{
+ hb_zip (this+coverage, substitute)
| hb_filter (c->parent_active_glyphs (), hb_first)
| hb_map (hb_second)
| hb_sink (c->output)
;
}
void closure_lookups (hb_closure_lookups_context_t *c) const {}
void collect_glyphs (hb_collect_glyphs_context_t *c) const
{
if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
+ hb_zip (this+coverage, substitute)
| hb_map (hb_second)
| hb_sink (c->output)
;
}
const Coverage &get_coverage () const { return this+coverage; }
bool would_apply (hb_would_apply_context_t *c) const
{ return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
bool apply (hb_ot_apply_context_t *c) const
{
TRACE_APPLY (this);
unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
if (likely (index == NOT_COVERED)) return_trace (false);
if (unlikely (index >= substitute.len)) return_trace (false);
c->replace_glyph (substitute[index]);
return_trace (true);
}
template<typename Iterator,
hb_requires (hb_is_sorted_source_of (Iterator,
hb_codepoint_pair_t))>
bool serialize (hb_serialize_context_t *c,
Iterator it)
{
TRACE_SERIALIZE (this);
auto substitutes =
+ it
| hb_map (hb_second)
;
auto glyphs =
+ it
| hb_map_retains_sorting (hb_first)
;
if (unlikely (!c->extend_min (this))) return_trace (false);
if (unlikely (!substitute.serialize (c, substitutes))) return_trace (false);
if (unlikely (!coverage.serialize_serialize (c, glyphs))) return_trace (false);
return_trace (true);
}
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;
auto it =
+ hb_zip (this+coverage, substitute)
| hb_filter (glyphset, hb_first)
| hb_filter (glyphset, hb_second)
| hb_map_retains_sorting ([&] (hb_pair_t<hb_codepoint_t, const HBGlyphID16 &> p) -> hb_codepoint_pair_t
{ return hb_pair (glyph_map[p.first], glyph_map[p.second]); })
;
bool ret = bool (it);
SingleSubst_serialize (c->serializer, it);
return_trace (ret);
}
};
}
}
}
#endif /* OT_LAYOUT_GSUB_SINGLESUBSTFORMAT2_HH */

View File

@ -0,0 +1,224 @@
#ifndef OT_LAYOUT_GSUB_SUBSTLOOKUP_HH
#define OT_LAYOUT_GSUB_SUBSTLOOKUP_HH
#include "Common.hh"
#include "SubstLookupSubTable.hh"
namespace OT {
namespace Layout {
namespace GSUB {
struct SubstLookup : Lookup
{
typedef SubstLookupSubTable SubTable;
bool sanitize (hb_sanitize_context_t *c) const
{ return Lookup::sanitize<SubTable> (c); }
const SubTable& get_subtable (unsigned int i) const
{ return Lookup::get_subtable<SubTable> (i); }
static inline bool lookup_type_is_reverse (unsigned int lookup_type)
{ return lookup_type == SubTable::ReverseChainSingle; }
bool is_reverse () const
{
unsigned int type = get_type ();
if (unlikely (type == SubTable::Extension))
return reinterpret_cast<const ExtensionSubst &> (get_subtable (0)).is_reverse ();
return lookup_type_is_reverse (type);
}
bool may_have_non_1to1 () const
{
hb_have_non_1to1_context_t c;
return dispatch (&c);
}
bool apply (hb_ot_apply_context_t *c) const
{
TRACE_APPLY (this);
return_trace (dispatch (c));
}
bool intersects (const hb_set_t *glyphs) const
{
hb_intersects_context_t c (glyphs);
return dispatch (&c);
}
hb_closure_context_t::return_t closure (hb_closure_context_t *c, unsigned int this_index) const
{
if (!c->should_visit_lookup (this_index))
return hb_closure_context_t::default_return_value ();
c->set_recurse_func (dispatch_closure_recurse_func);
hb_closure_context_t::return_t ret = dispatch (c);
c->flush ();
return ret;
}
hb_closure_lookups_context_t::return_t closure_lookups (hb_closure_lookups_context_t *c, unsigned this_index) const
{
if (c->is_lookup_visited (this_index))
return hb_closure_lookups_context_t::default_return_value ();
c->set_lookup_visited (this_index);
if (!intersects (c->glyphs))
{
c->set_lookup_inactive (this_index);
return hb_closure_lookups_context_t::default_return_value ();
}
c->set_recurse_func (dispatch_closure_lookups_recurse_func);
hb_closure_lookups_context_t::return_t ret = dispatch (c);
return ret;
}
hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
{
c->set_recurse_func (dispatch_recurse_func<hb_collect_glyphs_context_t>);
return dispatch (c);
}
template <typename set_t>
void collect_coverage (set_t *glyphs) const
{
hb_collect_coverage_context_t<set_t> c (glyphs);
dispatch (&c);
}
bool would_apply (hb_would_apply_context_t *c,
const hb_ot_layout_lookup_accelerator_t *accel) const
{
if (unlikely (!c->len)) return false;
if (!accel->may_have (c->glyphs[0])) return false;
return dispatch (c);
}
static inline bool apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index);
bool serialize_single (hb_serialize_context_t *c,
uint32_t lookup_props,
hb_sorted_array_t<const HBGlyphID16> glyphs,
hb_array_t<const HBGlyphID16> substitutes)
{
TRACE_SERIALIZE (this);
if (unlikely (!Lookup::serialize (c, SubTable::Single, lookup_props, 1))) return_trace (false);
if (c->push<SubTable> ()->u.single.serialize (c, hb_zip (glyphs, substitutes)))
{
c->add_link (get_subtables<SubTable> ()[0], c->pop_pack ());
return_trace (true);
}
c->pop_discard ();
return_trace (false);
}
bool serialize_multiple (hb_serialize_context_t *c,
uint32_t lookup_props,
hb_sorted_array_t<const HBGlyphID16> glyphs,
hb_array_t<const unsigned int> substitute_len_list,
hb_array_t<const HBGlyphID16> substitute_glyphs_list)
{
TRACE_SERIALIZE (this);
if (unlikely (!Lookup::serialize (c, SubTable::Multiple, lookup_props, 1))) return_trace (false);
if (c->push<SubTable> ()->u.multiple.
serialize (c,
glyphs,
substitute_len_list,
substitute_glyphs_list))
{
c->add_link (get_subtables<SubTable> ()[0], c->pop_pack ());
return_trace (true);
}
c->pop_discard ();
return_trace (false);
}
bool serialize_alternate (hb_serialize_context_t *c,
uint32_t lookup_props,
hb_sorted_array_t<const HBGlyphID16> glyphs,
hb_array_t<const unsigned int> alternate_len_list,
hb_array_t<const HBGlyphID16> alternate_glyphs_list)
{
TRACE_SERIALIZE (this);
if (unlikely (!Lookup::serialize (c, SubTable::Alternate, lookup_props, 1))) return_trace (false);
if (c->push<SubTable> ()->u.alternate.
serialize (c,
glyphs,
alternate_len_list,
alternate_glyphs_list))
{
c->add_link (get_subtables<SubTable> ()[0], c->pop_pack ());
return_trace (true);
}
c->pop_discard ();
return_trace (false);
}
bool serialize_ligature (hb_serialize_context_t *c,
uint32_t lookup_props,
hb_sorted_array_t<const HBGlyphID16> first_glyphs,
hb_array_t<const unsigned int> ligature_per_first_glyph_count_list,
hb_array_t<const HBGlyphID16> ligatures_list,
hb_array_t<const unsigned int> component_count_list,
hb_array_t<const HBGlyphID16> component_list /* Starting from second for each ligature */)
{
TRACE_SERIALIZE (this);
if (unlikely (!Lookup::serialize (c, SubTable::Ligature, lookup_props, 1))) return_trace (false);
if (c->push<SubTable> ()->u.ligature.
serialize (c,
first_glyphs,
ligature_per_first_glyph_count_list,
ligatures_list,
component_count_list,
component_list))
{
c->add_link (get_subtables<SubTable> ()[0], c->pop_pack ());
return_trace (true);
}
c->pop_discard ();
return_trace (false);
}
template <typename context_t>
static inline typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index);
static inline typename hb_closure_context_t::return_t closure_glyphs_recurse_func (hb_closure_context_t *c, unsigned lookup_index, hb_set_t *covered_seq_indices, unsigned seq_index, unsigned end_index);
static inline hb_closure_context_t::return_t dispatch_closure_recurse_func (hb_closure_context_t *c, unsigned lookup_index, hb_set_t *covered_seq_indices, unsigned seq_index, unsigned end_index)
{
if (!c->should_visit_lookup (lookup_index))
return hb_empty_t ();
hb_closure_context_t::return_t ret = closure_glyphs_recurse_func (c, lookup_index, covered_seq_indices, seq_index, end_index);
/* While in theory we should flush here, it will cause timeouts because a recursive
* lookup can keep growing the glyph set. Skip, and outer loop will retry up to
* HB_CLOSURE_MAX_STAGES time, which should be enough for every realistic font. */
//c->flush ();
return ret;
}
HB_INTERNAL static hb_closure_lookups_context_t::return_t dispatch_closure_lookups_recurse_func (hb_closure_lookups_context_t *c, unsigned lookup_index);
template <typename context_t, typename ...Ts>
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
{ return Lookup::dispatch<SubTable> (c, std::forward<Ts> (ds)...); }
bool subset (hb_subset_context_t *c) const
{ return Lookup::subset<SubTable> (c); }
};
}
}
}
#endif /* OT_LAYOUT_GSUB_SUBSTLOOKUP_HH */

View File

@ -0,0 +1,77 @@
#ifndef OT_LAYOUT_GSUB_SUBSTLOOKUPSUBTABLE_HH
#define OT_LAYOUT_GSUB_SUBSTLOOKUPSUBTABLE_HH
#include "Common.hh"
#include "SingleSubst.hh"
#include "MultipleSubst.hh"
#include "AlternateSubst.hh"
#include "LigatureSubst.hh"
#include "ContextSubst.hh"
#include "ChainContextSubst.hh"
#include "ExtensionSubst.hh"
#include "ReverseChainSingleSubst.hh"
namespace OT {
namespace Layout {
namespace GSUB {
struct SubstLookupSubTable
{
friend struct ::OT::Lookup;
friend struct SubstLookup;
protected:
union {
SingleSubst single;
MultipleSubst multiple;
AlternateSubst alternate;
LigatureSubst ligature;
ContextSubst context;
ChainContextSubst chainContext;
ExtensionSubst extension;
ReverseChainSingleSubst reverseChainContextSingle;
} u;
public:
DEFINE_SIZE_MIN (0);
enum Type {
Single = 1,
Multiple = 2,
Alternate = 3,
Ligature = 4,
Context = 5,
ChainContext = 6,
Extension = 7,
ReverseChainSingle = 8
};
template <typename context_t, typename ...Ts>
typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type, Ts&&... ds) const
{
TRACE_DISPATCH (this, lookup_type);
switch (lookup_type) {
case Single: return_trace (u.single.dispatch (c, std::forward<Ts> (ds)...));
case Multiple: return_trace (u.multiple.dispatch (c, std::forward<Ts> (ds)...));
case Alternate: return_trace (u.alternate.dispatch (c, std::forward<Ts> (ds)...));
case Ligature: return_trace (u.ligature.dispatch (c, std::forward<Ts> (ds)...));
case Context: return_trace (u.context.dispatch (c, std::forward<Ts> (ds)...));
case ChainContext: return_trace (u.chainContext.dispatch (c, std::forward<Ts> (ds)...));
case Extension: return_trace (u.extension.dispatch (c, std::forward<Ts> (ds)...));
case ReverseChainSingle: return_trace (u.reverseChainContextSingle.dispatch (c, std::forward<Ts> (ds)...));
default: return_trace (c->default_return_value ());
}
}
bool intersects (const hb_set_t *glyphs, unsigned int lookup_type) const
{
hb_intersects_context_t c (glyphs);
return dispatch (&c, lookup_type);
}
};
}
}
}
#endif /* HB_OT_LAYOUT_GSUB_SUBSTLOOKUPSUBTABLE_HH */

View File

@ -86,6 +86,72 @@ struct hb_bit_page_t
void set_range (hb_codepoint_t a, hb_codepoint_t b, bool v)
{ if (v) add_range (a, b); else del_range (a, b); }
// Writes out page values to the array p. Returns the number of values
// written. At most size codepoints will be written.
unsigned int write (uint32_t base,
unsigned int start_value,
hb_codepoint_t *p,
unsigned int size) const
{
unsigned int start_v = start_value >> ELT_BITS_LOG_2;
unsigned int start_bit = start_value & ELT_MASK;
unsigned int count = 0;
for (unsigned i = start_v; i < len () && count < size; i++)
{
elt_t bits = v[i];
uint32_t v_base = base | (i << ELT_BITS_LOG_2);
for (unsigned int j = start_bit; j < ELT_BITS && count < size; j++)
{
if ((elt_t(1) << j) & bits) {
*p++ = v_base | j;
count++;
}
}
start_bit = 0;
}
return count;
}
// Writes out the values NOT in this page to the array p. Returns the
// number of values written. At most size codepoints will be written.
// Returns the number of codepoints written. next_value holds the next value
// that should be written (if not present in this page). This is used to fill
// any missing value gaps between this page and the previous page, if any.
// next_value is updated to one more than the last value present in this page.
unsigned int write_inverted (uint32_t base,
unsigned int start_value,
hb_codepoint_t *p,
unsigned int size,
hb_codepoint_t *next_value) const
{
unsigned int start_v = start_value >> ELT_BITS_LOG_2;
unsigned int start_bit = start_value & ELT_MASK;
unsigned int count = 0;
for (unsigned i = start_v; i < len () && count < size; i++)
{
elt_t bits = v[i];
uint32_t v_offset = i << ELT_BITS_LOG_2;
for (unsigned int j = start_bit; j < ELT_BITS && count < size; j++)
{
if ((elt_t(1) << j) & bits)
{
hb_codepoint_t value = base | v_offset | j;
// Emit all the missing values from next_value up to value - 1.
for (hb_codepoint_t k = *next_value; k < value && count < size; k++)
{
*p++ = k;
count++;
}
// Skip over this value;
*next_value = value + 1;
}
}
start_bit = 0;
}
return count;
}
bool is_equal (const hb_bit_page_t &other) const
{
return 0 == hb_memcmp (&v, &other.v, sizeof (v));
@ -179,6 +245,9 @@ struct hb_bit_page_t
typedef unsigned long long elt_t;
static constexpr unsigned PAGE_BITS = 512;
static_assert ((PAGE_BITS & ((PAGE_BITS) - 1)) == 0, "");
static constexpr unsigned PAGE_BITS_LOG_2 = 9;
static_assert (1 << PAGE_BITS_LOG_2 == PAGE_BITS, "");
static constexpr unsigned PAGE_BITMASK = PAGE_BITS - 1;
static unsigned int elt_get_min (const elt_t &elt) { return hb_ctz (elt); }
static unsigned int elt_get_max (const elt_t &elt) { return hb_bit_storage (elt) - 1; }
@ -186,7 +255,10 @@ struct hb_bit_page_t
typedef hb_vector_size_t<elt_t, PAGE_BITS / 8> vector_t;
static constexpr unsigned ELT_BITS = sizeof (elt_t) * 8;
static constexpr unsigned ELT_BITS_LOG_2 = 6;
static_assert (1 << ELT_BITS_LOG_2 == ELT_BITS, "");
static constexpr unsigned ELT_MASK = ELT_BITS - 1;
static constexpr unsigned BITS = sizeof (vector_t) * 8;
static constexpr unsigned MASK = BITS - 1;
static_assert ((unsigned) PAGE_BITS == (unsigned) BITS, "");

View File

@ -323,6 +323,14 @@ struct hb_bit_set_invertible_t
return true;
}
unsigned int next_many (hb_codepoint_t codepoint,
hb_codepoint_t *out,
unsigned int size) const
{
return inverted ? s.next_many_inverted (codepoint, out, size)
: s.next_many (codepoint, out, size);
}
static constexpr hb_codepoint_t INVALID = hb_bit_set_t::INVALID;
/*

View File

@ -203,7 +203,7 @@ struct hb_bit_set_t
bool set_sorted_array (bool v, const T *array, unsigned int count, unsigned int stride=sizeof(T))
{
if (unlikely (!successful)) return true; /* https://github.com/harfbuzz/harfbuzz/issues/657 */
if (!count) return true;
if (unlikely (!count)) return true;
dirty ();
hb_codepoint_t g = *array;
hb_codepoint_t last_g = g;
@ -222,7 +222,7 @@ struct hb_bit_set_t
if (v || page) /* The v check is to optimize out the page check if v is true. */
page->add (g);
array = (const T *) ((const char *) array + stride);
array = &StructAtOffsetUnaligned<T> (array, stride);
count--;
}
while (count && (g = *array, g < end));
@ -700,6 +700,99 @@ struct hb_bit_set_t
return true;
}
unsigned int next_many (hb_codepoint_t codepoint,
hb_codepoint_t *out,
unsigned int size) const
{
// By default, start at the first bit of the first page of values.
unsigned int start_page = 0;
unsigned int start_page_value = 0;
if (unlikely (codepoint != INVALID))
{
const auto* page_map_array = page_map.arrayZ;
unsigned int major = get_major (codepoint);
unsigned int i = last_page_lookup;
if (unlikely (i >= page_map.length || page_map_array[i].major != major))
{
page_map.bfind (major, &i, HB_NOT_FOUND_STORE_CLOSEST);
if (i >= page_map.length)
return 0; // codepoint is greater than our max element.
}
start_page = i;
start_page_value = page_remainder (codepoint + 1);
if (unlikely (start_page_value == 0))
{
// The export-after value was last in the page. Start on next page.
start_page++;
start_page_value = 0;
}
}
unsigned int initial_size = size;
for (unsigned int i = start_page; i < page_map.length && size; i++)
{
uint32_t base = major_start (page_map[i].major);
unsigned int n = pages[page_map[i].index].write (base, start_page_value, out, size);
out += n;
size -= n;
start_page_value = 0;
}
return initial_size - size;
}
unsigned int next_many_inverted (hb_codepoint_t codepoint,
hb_codepoint_t *out,
unsigned int size) const
{
unsigned int initial_size = size;
// By default, start at the first bit of the first page of values.
unsigned int start_page = 0;
unsigned int start_page_value = 0;
if (unlikely (codepoint != INVALID))
{
const auto* page_map_array = page_map.arrayZ;
unsigned int major = get_major (codepoint);
unsigned int i = last_page_lookup;
if (unlikely (i >= page_map.length || page_map_array[i].major != major))
{
page_map.bfind(major, &i, HB_NOT_FOUND_STORE_CLOSEST);
if (unlikely (i >= page_map.length))
{
// codepoint is greater than our max element.
while (++codepoint != INVALID && size)
{
*out++ = codepoint;
size--;
}
return initial_size - size;
}
}
start_page = i;
start_page_value = page_remainder (codepoint + 1);
if (unlikely (start_page_value == 0))
{
// The export-after value was last in the page. Start on next page.
start_page++;
start_page_value = 0;
}
}
hb_codepoint_t next_value = codepoint + 1;
for (unsigned int i=start_page; i<page_map.length && size; i++)
{
uint32_t base = major_start (page_map[i].major);
unsigned int n = pages[page_map[i].index].write_inverted (base, start_page_value, out, size, &next_value);
out += n;
size -= n;
start_page_value = 0;
}
while (next_value < HB_SET_VALUE_INVALID && size) {
*out++ = next_value++;
size--;
}
return initial_size - size;
}
bool has_population () const { return population != UINT_MAX; }
unsigned int get_population () const
{
@ -809,8 +902,9 @@ struct hb_bit_set_t
}
page_t &page_at (unsigned int i) { return pages[page_map[i].index]; }
const page_t &page_at (unsigned int i) const { return pages[page_map[i].index]; }
unsigned int get_major (hb_codepoint_t g) const { return g / page_t::PAGE_BITS; }
hb_codepoint_t major_start (unsigned int major) const { return major * page_t::PAGE_BITS; }
unsigned int get_major (hb_codepoint_t g) const { return g >> page_t::PAGE_BITS_LOG_2; }
unsigned int page_remainder (hb_codepoint_t g) const { return g & page_t::PAGE_BITMASK; }
hb_codepoint_t major_start (unsigned int major) const { return major << page_t::PAGE_BITS_LOG_2; }
};

View File

@ -295,7 +295,6 @@ hb_buffer_t::clear ()
idx = 0;
len = 0;
out_len = 0;
out_info = info;
memset (context, 0, sizeof context);
@ -405,6 +404,7 @@ hb_buffer_t::sync ()
reset:
have_output = false;
out_len = 0;
out_info = info;
idx = 0;
}

View File

@ -897,7 +897,7 @@ resize_and_retry:
DEBUG_MSG (CORETEXT, nullptr, "Num runs: %d", num_runs);
buffer->len = 0;
uint32_t status_and = ~0, status_or = 0;
uint32_t status_or = 0;
CGFloat advances_so_far = 0;
/* For right-to-left runs, CoreText returns the glyphs positioned such that
* any trailing whitespace is to the left of (0,0). Adjust coordinate system
@ -918,7 +918,6 @@ resize_and_retry:
CTRunRef run = static_cast<CTRunRef>(CFArrayGetValueAtIndex (glyph_runs, i));
CTRunStatus run_status = CTRunGetStatus (run);
status_or |= run_status;
status_and &= run_status;
DEBUG_MSG (CORETEXT, run, "CTRunStatus: %x", run_status);
CGFloat run_advance = CTRunGetTypographicBounds (run, range_all, nullptr, nullptr, nullptr);
if (HB_DIRECTION_IS_VERTICAL (buffer->props.direction))
@ -1140,21 +1139,6 @@ resize_and_retry:
buffer->len += num_glyphs;
}
/* Mac OS 10.6 doesn't have kCTTypesetterOptionForcedEmbeddingLevel,
* or if it does, it doesn't respect it. So we get runs with wrong
* directions. As such, disable the assert... It wouldn't crash, but
* cursoring will be off...
*
* https://crbug.com/419769
*/
if (false)
{
/* Make sure all runs had the expected direction. */
HB_UNUSED bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
assert (bool (status_and & kCTRunStatusRightToLeft) == backward);
assert (bool (status_or & kCTRunStatusRightToLeft) == backward);
}
buffer->clear_positions ();
unsigned int count = buffer->len;

View File

@ -382,6 +382,7 @@ hb_ft_get_glyph_v_advance (hb_font_t *font,
/* Note: FreeType's vertical metrics grows downward while other FreeType coordinates
* have a Y growing upward. Hence the extra negation. */
return (-v + (1<<9)) >> 10;
}
#endif

View File

@ -714,7 +714,7 @@ struct CmapSubtableLongSegmented
if (unlikely ((unsigned int) (gid + end - start) >= num_glyphs))
end = start + (hb_codepoint_t) num_glyphs - gid;
out->add_range (start, end);
out->add_range (start, hb_min (end, 0x10FFFFu));
}
}
@ -883,7 +883,7 @@ struct DefaultUVS : SortedArray32Of<UnicodeValueRange>
hb_codepoint_t first = arrayZ[i].startUnicodeValue;
hb_codepoint_t last = hb_min ((hb_codepoint_t) (first + arrayZ[i].additionalCount),
(hb_codepoint_t) HB_UNICODE_MAX);
out->add_range (first, last);
out->add_range (first, hb_min (last, 0x10FFFFu));
}
}

View File

@ -131,11 +131,25 @@ hb_ot_get_glyph_v_advances (hb_font_t* font, void* font_data,
const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data;
const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx;
for (unsigned int i = 0; i < count; i++)
if (vmtx.has_data ())
for (unsigned int i = 0; i < count; i++)
{
*first_advance = font->em_scale_y (-(int) vmtx.get_advance (*first_glyph, font));
first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
}
else
{
*first_advance = font->em_scale_y (-(int) vmtx.get_advance (*first_glyph, font));
first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
hb_font_extents_t font_extents;
font->get_h_extents_with_fallback (&font_extents);
hb_position_t advance = -(font_extents.ascender - font_extents.descender);
for (unsigned int i = 0; i < count; i++)
{
*first_advance = advance;
first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
}
}
}
#endif
@ -163,9 +177,19 @@ hb_ot_get_glyph_v_origin (hb_font_t *font,
hb_glyph_extents_t extents = {0};
if (ot_face->glyf->get_extents (font, glyph, &extents))
{
const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx;
hb_position_t tsb = vmtx.get_side_bearing (font, glyph);
*y = extents.y_bearing + font->em_scale_y (tsb);
if (ot_face->vmtx->has_data ())
{
const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx;
hb_position_t tsb = vmtx.get_side_bearing (font, glyph);
*y = extents.y_bearing + font->em_scale_y (tsb);
return true;
}
hb_font_extents_t font_extents;
font->get_h_extents_with_fallback (&font_extents);
hb_position_t advance = font_extents.ascender - font_extents.descender;
int diff = advance - -extents.height;
*y = extents.y_bearing + (diff >> 1);
return true;
}

View File

@ -820,8 +820,7 @@ struct glyf
}
#ifndef HB_NO_VAR
if (unlikely (!glyf_accelerator.gvar->apply_deltas_to_points (gid, font, points.as_array ())))
return false;
glyf_accelerator.gvar->apply_deltas_to_points (gid, font, points.as_array ());
#endif
switch (type) {

View File

@ -170,13 +170,12 @@ struct hmtxvmtx
{
friend struct hmtxvmtx;
accelerator_t (hb_face_t *face,
unsigned int default_advance_ = 0)
accelerator_t (hb_face_t *face)
{
table = hb_sanitize_context_t ().reference_table<hmtxvmtx> (face, T::tableTag);
var_table = hb_sanitize_context_t ().reference_table<HVARVVAR> (face, T::variationsTag);
default_advance = default_advance_ ? default_advance_ : hb_face_get_upem (face);
default_advance = T::is_horizontal ? hb_face_get_upem (face) / 2 : hb_face_get_upem (face);
/* Populate count variables and sort them out as we go */
@ -220,6 +219,8 @@ struct hmtxvmtx
var_table.destroy ();
}
bool has_data () const { return (bool) num_bearings; }
int get_side_bearing (hb_codepoint_t glyph) const
{
if (glyph < num_long_metrics)

View File

@ -37,7 +37,7 @@
#ifndef HB_MAX_NESTING_LEVEL
#define HB_MAX_NESTING_LEVEL 6
#define HB_MAX_NESTING_LEVEL 64
#endif
#ifndef HB_MAX_CONTEXT_LENGTH
#define HB_MAX_CONTEXT_LENGTH 64
@ -60,6 +60,10 @@
#define HB_MAX_LANGSYS 2000
#endif
#ifndef HB_MAX_LANGSYS_FEATURE_COUNT
#define HB_MAX_LANGSYS_FEATURE_COUNT 50000
#endif
#ifndef HB_MAX_FEATURES
#define HB_MAX_FEATURES 750
#endif
@ -105,34 +109,15 @@ struct hb_prune_langsys_context_t
script_langsys_map (script_langsys_map_),
duplicate_feature_map (duplicate_feature_map_),
new_feature_indexes (new_collected_feature_indexes_),
script_count (0),langsys_count (0) {}
script_count (0),langsys_feature_count (0) {}
bool visitedScript (const void *s)
bool visitScript ()
{ return script_count++ < HB_MAX_SCRIPTS; }
bool visitLangsys (unsigned feature_count)
{
if (script_count++ > HB_MAX_SCRIPTS)
return true;
return visited (s, visited_script);
}
bool visitedLangsys (const void *l)
{
if (langsys_count++ > HB_MAX_LANGSYS)
return true;
return visited (l, visited_langsys);
}
private:
template <typename T>
bool visited (const T *p, hb_set_t &visited_set)
{
hb_codepoint_t delta = (hb_codepoint_t) ((uintptr_t) p - (uintptr_t) table);
if (visited_set.in_error () || visited_set.has (delta))
return true;
visited_set.add (delta);
return false;
langsys_feature_count += feature_count;
return langsys_feature_count < HB_MAX_LANGSYS_FEATURE_COUNT;
}
public:
@ -142,10 +127,8 @@ struct hb_prune_langsys_context_t
hb_set_t *new_feature_indexes;
private:
hb_set_t visited_script;
hb_set_t visited_langsys;
unsigned script_count;
unsigned langsys_count;
unsigned langsys_feature_count;
};
struct hb_subset_layout_context_t :
@ -643,11 +626,14 @@ struct LangSys
| hb_map (feature_index_map)
;
if (iter.len () != o_iter.len ())
return false;
for (; iter && o_iter; iter++, o_iter++)
{
unsigned a = *iter;
unsigned b = *o_iter;
if (a != b) return false;
}
for (const auto _ : + hb_zip (iter, o_iter))
if (_.first != _.second) return false;
if (iter || o_iter) return false;
return true;
}
@ -732,7 +718,7 @@ struct Script
unsigned script_index) const
{
if (!has_default_lang_sys () && !get_lang_sys_count ()) return;
if (c->visitedScript (this)) return;
if (!c->visitScript ()) return;
if (!c->script_langsys_map->has (script_index))
{
@ -749,15 +735,14 @@ struct Script
{
//only collect features from non-redundant langsys
const LangSys& d = get_default_lang_sys ();
if (!c->visitedLangsys (&d)) {
if (c->visitLangsys (d.get_feature_count ())) {
d.collect_features (c);
}
for (auto _ : + hb_zip (langSys, hb_range (langsys_count)))
{
const LangSys& l = this+_.first.offset;
if (c->visitedLangsys (&l)) continue;
if (!c->visitLangsys (l.get_feature_count ())) continue;
if (l.compare (d, c->duplicate_feature_map)) continue;
l.collect_features (c);
@ -769,7 +754,7 @@ struct Script
for (auto _ : + hb_zip (langSys, hb_range (langsys_count)))
{
const LangSys& l = this+_.first.offset;
if (c->visitedLangsys (&l)) continue;
if (!c->visitLangsys (l.get_feature_count ())) continue;
l.collect_features (c);
c->script_langsys_map->get (script_index)->add (_.second);
}

File diff suppressed because it is too large Load Diff

View File

@ -408,12 +408,11 @@ struct hb_ot_apply_context_t :
{
matcher_t () :
lookup_props (0),
mask (-1),
ignore_zwnj (false),
ignore_zwj (false),
mask (-1),
#define arg1(arg) (arg) /* Remove the macro to see why it's needed! */
syllable arg1(0),
#undef arg1
per_syllable (false),
syllable {0},
match_func (nullptr),
match_data (nullptr) {}
@ -423,7 +422,8 @@ struct hb_ot_apply_context_t :
void set_ignore_zwj (bool ignore_zwj_) { ignore_zwj = ignore_zwj_; }
void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; }
void set_mask (hb_mask_t mask_) { mask = mask_; }
void set_syllable (uint8_t syllable_) { syllable = syllable_; }
void set_per_syllable (bool per_syllable_) { per_syllable = per_syllable_; }
void set_syllable (uint8_t syllable_) { syllable = per_syllable ? syllable_ : 0; }
void set_match_func (match_func_t match_func_,
const void *match_data_)
{ match_func = match_func_; match_data = match_data_; }
@ -469,9 +469,10 @@ struct hb_ot_apply_context_t :
protected:
unsigned int lookup_props;
hb_mask_t mask;
bool ignore_zwnj;
bool ignore_zwj;
hb_mask_t mask;
bool per_syllable;
uint8_t syllable;
match_func_t match_func;
const void *match_data;
@ -490,6 +491,7 @@ struct hb_ot_apply_context_t :
/* Ignore ZWJ if we are matching context, or asked to. */
matcher.set_ignore_zwj (context_match || c->auto_zwj);
matcher.set_mask (context_match ? -1 : c->lookup_mask);
matcher.set_per_syllable (c->per_syllable);
}
void set_lookup_props (unsigned int lookup_props)
{
@ -636,6 +638,7 @@ struct hb_ot_apply_context_t :
bool has_glyph_classes;
bool auto_zwnj;
bool auto_zwj;
bool per_syllable;
bool random;
uint32_t random_state;
@ -664,6 +667,7 @@ struct hb_ot_apply_context_t :
has_glyph_classes (gdef.has_glyph_classes ()),
auto_zwnj (true),
auto_zwj (true),
per_syllable (false),
random (false),
random_state (1) { init_iters (); }
@ -676,6 +680,7 @@ struct hb_ot_apply_context_t :
void set_lookup_mask (hb_mask_t mask) { lookup_mask = mask; init_iters (); }
void set_auto_zwj (bool auto_zwj_) { auto_zwj = auto_zwj_; init_iters (); }
void set_auto_zwnj (bool auto_zwnj_) { auto_zwnj = auto_zwnj_; init_iters (); }
void set_per_syllable (bool per_syllable_) { per_syllable = per_syllable_; init_iters (); }
void set_random (bool random_) { random = random_; }
void set_recurse_func (recurse_func_t func) { recurse_func = func; }
void set_lookup_index (unsigned int lookup_index_) { lookup_index = lookup_index_; }
@ -1415,13 +1420,18 @@ static inline void apply_lookup (hb_ot_apply_context_t *c,
if (unlikely (idx == 0 && lookupRecord[i].lookupListIndex == c->lookup_index))
continue;
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))
continue;
if (unlikely (!buffer->move_to (match_positions[idx])))
break;
if (unlikely (buffer->max_ops <= 0))
break;
unsigned int orig_len = buffer->backtrack_len () + buffer->lookahead_len ();
if (!c->recurse (lookupRecord[i].lookupListIndex))
continue;
@ -1457,15 +1467,18 @@ static inline void apply_lookup (hb_ot_apply_context_t *c,
*/
end += delta;
if (end <= int (match_positions[idx]))
if (end < int (match_positions[idx]))
{
/* End might end up being smaller than match_positions[idx] if the recursed
* lookup ended up removing many items, more than we have had matched.
* Just never rewind end back and get out of here.
* https://bugs.chromium.org/p/chromium/issues/detail?id=659496 */
* 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.
*
* 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];
/* There can't be any further changes. */
break;
}
unsigned int next = idx + 1; /* next now is the position after the recursed lookup. */
@ -1477,7 +1490,7 @@ static inline void apply_lookup (hb_ot_apply_context_t *c,
}
else
{
/* NOTE: delta is negative. */
/* NOTE: delta is non-positive. */
delta = hb_max (delta, (int) next - (int) count);
next -= delta;
}

View File

@ -54,6 +54,8 @@
#include "hb-aat-layout-morx-table.hh"
#include "hb-aat-layout-opbd-table.hh" // Just so we compile it; unused otherwise.
using OT::Layout::GSUB::GSUB;
/**
* SECTION:hb-ot-layout
* @title: hb-ot-layout
@ -389,7 +391,7 @@ hb_ot_layout_get_ligature_carets (hb_font_t *font,
*/
bool
OT::GSUB::is_blocklisted (hb_blob_t *blob HB_UNUSED,
GSUB::is_blocklisted (hb_blob_t *blob HB_UNUSED,
hb_face_t *face) const
{
#ifdef HB_NO_OT_LAYOUT_BLOCKLIST
@ -1006,7 +1008,7 @@ struct hb_collect_features_context_t
hb_collect_features_context_t (hb_face_t *face,
hb_tag_t table_tag,
hb_set_t *feature_indices_,
const hb_tag_t *features)
const hb_tag_t *features)
: g (get_gsubgpos_table (face, table_tag)),
feature_indices (feature_indices_),
@ -1033,7 +1035,7 @@ struct hb_collect_features_context_t
{
hb_tag_t tag = g.get_feature_tag (i);
if (features_set.has (tag))
feature_indices_filter.add(i);
feature_indices_filter.add(i);
}
}
@ -1529,7 +1531,7 @@ hb_ot_layout_lookups_substitute_closure (hb_face_t *face,
hb_map_t done_lookups_glyph_count;
hb_hashmap_t<unsigned, hb_set_t *> done_lookups_glyph_set;
OT::hb_closure_context_t c (face, glyphs, &done_lookups_glyph_count, &done_lookups_glyph_set);
const OT::GSUB& gsub = *face->table.GSUB->table;
const GSUB& gsub = *face->table.GSUB->table;
unsigned int iteration_count = 0;
unsigned int glyphs_length;
@ -1808,7 +1810,7 @@ struct GSUBProxy
table (*face->table.GSUB->table),
accels (face->table.GSUB->accels) {}
const OT::GSUB &table;
const GSUB &table;
const OT::hb_ot_layout_lookup_accelerator_t *accels;
};
@ -1929,6 +1931,7 @@ inline void hb_ot_map_t::apply (const Proxy &proxy,
c.set_auto_zwj (lookups[table_index][i].auto_zwj);
c.set_auto_zwnj (lookups[table_index][i].auto_zwnj);
c.set_random (lookups[table_index][i].random);
c.set_per_syllable (lookups[table_index][i].per_syllable);
apply_string<Proxy> (&c,
proxy.table.get_lookup (lookup_index),
@ -2086,11 +2089,11 @@ hb_ot_layout_get_baseline_with_fallback (hb_font_t *font,
hb_position_t *coord /* OUT */)
{
if (hb_ot_layout_get_baseline (font,
baseline_tag,
direction,
script_tag,
language_tag,
coord))
baseline_tag,
direction,
script_tag,
language_tag,
coord))
return;
/* Synthesize missing baselines.
@ -2107,17 +2110,19 @@ hb_ot_layout_get_baseline_with_fallback (hb_font_t *font,
hb_codepoint_t glyph;
hb_glyph_extents_t extents;
if (HB_DIRECTION_IS_HORIZONTAL (direction) &&
(hb_font_get_nominal_glyph (font, 0x2212u, &glyph) ||
hb_font_get_nominal_glyph (font, '-', &glyph)) &&
hb_font_get_glyph_extents (font, glyph, &extents))
(hb_font_get_nominal_glyph (font, 0x2212u, &glyph) ||
hb_font_get_nominal_glyph (font, '-', &glyph)) &&
hb_font_get_glyph_extents (font, glyph, &extents))
{
*coord = extents.y_bearing + extents.height / 2;
*coord = extents.y_bearing + extents.height / 2;
}
else
{
hb_position_t x_height = 0;
hb_ot_metrics_get_position (font, HB_OT_METRICS_TAG_X_HEIGHT, &x_height);
*coord = x_height / 2;
hb_position_t x_height = font->y_scale / 2;
#ifndef HB_NO_METRICS
hb_ot_metrics_get_position_with_fallback (font, HB_OT_METRICS_TAG_X_HEIGHT, &x_height);
#endif
*coord = x_height / 2;
}
}
break;
@ -2128,32 +2133,32 @@ hb_ot_layout_get_baseline_with_fallback (hb_font_t *font,
hb_position_t embox_top, embox_bottom;
hb_ot_layout_get_baseline_with_fallback (font,
HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT,
direction,
script_tag,
language_tag,
&embox_top);
HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT,
direction,
script_tag,
language_tag,
&embox_top);
hb_ot_layout_get_baseline_with_fallback (font,
HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_BOTTOM_OR_LEFT,
direction,
script_tag,
language_tag,
&embox_bottom);
HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_BOTTOM_OR_LEFT,
direction,
script_tag,
language_tag,
&embox_bottom);
if (baseline_tag == HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_TOP_OR_RIGHT)
*coord = embox_top + (embox_bottom - embox_top) / 10;
*coord = embox_top + (embox_bottom - embox_top) / 10;
else
*coord = embox_bottom + (embox_top - embox_bottom) / 10;
*coord = embox_bottom + (embox_top - embox_bottom) / 10;
}
break;
case HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT:
if (hb_ot_layout_get_baseline (font,
HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_BOTTOM_OR_LEFT,
direction,
script_tag,
language_tag,
coord))
HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_BOTTOM_OR_LEFT,
direction,
script_tag,
language_tag,
coord))
*coord += HB_DIRECTION_IS_HORIZONTAL (direction) ? font->y_scale : font->x_scale;
else
{
@ -2165,11 +2170,11 @@ hb_ot_layout_get_baseline_with_fallback (hb_font_t *font,
case HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_BOTTOM_OR_LEFT:
if (hb_ot_layout_get_baseline (font,
HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT,
direction,
script_tag,
language_tag,
coord))
HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT,
direction,
script_tag,
language_tag,
coord))
*coord -= HB_DIRECTION_IS_HORIZONTAL (direction) ? font->y_scale : font->x_scale;
else
{
@ -2226,11 +2231,11 @@ hb_ot_layout_get_baseline_with_fallback (hb_font_t *font,
}
if (ch &&
hb_font_get_nominal_glyph (font, ch, &glyph) &&
hb_font_get_glyph_extents (font, glyph, &extents))
*coord = extents.y_bearing;
hb_font_get_nominal_glyph (font, ch, &glyph) &&
hb_font_get_glyph_extents (font, glyph, &extents))
*coord = extents.y_bearing;
else
*coord = font->y_scale * 6 / 10; // FIXME makes assumptions about origin
*coord = font->y_scale * 6 / 10; // FIXME makes assumptions about origin
}
else
*coord = font->x_scale * 6 / 10; // FIXME makes assumptions about origin
@ -2240,17 +2245,17 @@ hb_ot_layout_get_baseline_with_fallback (hb_font_t *font,
{
hb_position_t top, bottom;
hb_ot_layout_get_baseline_with_fallback (font,
HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT,
direction,
script_tag,
language_tag,
&top);
HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT,
direction,
script_tag,
language_tag,
&top);
hb_ot_layout_get_baseline_with_fallback (font,
HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_BOTTOM_OR_LEFT,
direction,
script_tag,
language_tag,
&bottom);
HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_BOTTOM_OR_LEFT,
direction,
script_tag,
language_tag,
&bottom);
*coord = (top + bottom) / 2;
}
@ -2260,17 +2265,17 @@ hb_ot_layout_get_baseline_with_fallback (hb_font_t *font,
{
hb_position_t top, bottom;
hb_ot_layout_get_baseline_with_fallback (font,
HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_TOP_OR_RIGHT,
direction,
script_tag,
language_tag,
&top);
HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_TOP_OR_RIGHT,
direction,
script_tag,
language_tag,
&top);
hb_ot_layout_get_baseline_with_fallback (font,
HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_BOTTOM_OR_LEFT,
direction,
script_tag,
language_tag,
&bottom);
HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_BOTTOM_OR_LEFT,
direction,
script_tag,
language_tag,
&bottom);
*coord = (top + bottom) / 2;
}

View File

@ -108,13 +108,17 @@ hb_ot_layout_delete_glyphs_inplace (hb_buffer_t *buffer,
namespace OT {
struct hb_ot_apply_context_t;
struct SubstLookup;
struct hb_ot_layout_lookup_accelerator_t;
namespace Layout {
namespace GSUB {
struct SubstLookup;
}
}
}
HB_INTERNAL void
hb_ot_layout_substitute_lookup (OT::hb_ot_apply_context_t *c,
const OT::SubstLookup &lookup,
const OT::Layout::GSUB::SubstLookup &lookup,
const OT::hb_ot_layout_lookup_accelerator_t &accel);
@ -168,17 +172,6 @@ _hb_next_syllable (hb_buffer_t *buffer, unsigned int start)
return start;
}
static inline void
_hb_clear_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED,
hb_font_t *font HB_UNUSED,
hb_buffer_t *buffer)
{
hb_glyph_info_t *info = buffer->info;
unsigned int count = buffer->len;
for (unsigned int i = 0; i < count; i++)
info[i].syllable() = 0;
}
/* unicode_props */
@ -485,6 +478,8 @@ static inline uint8_t
_hb_allocate_lig_id (hb_buffer_t *buffer)
{
uint8_t lig_id = buffer->next_serial () & 0x07;
if (unlikely (!lig_id))
lig_id = _hb_allocate_lig_id (buffer); /* in case of overflow */
return lig_id;
}

View File

@ -117,7 +117,8 @@ hb_ot_map_builder_t::add_lookups (hb_ot_map_t &m,
hb_mask_t mask,
bool auto_zwnj,
bool auto_zwj,
bool random)
bool random,
bool per_syllable)
{
unsigned int lookup_indices[32];
unsigned int offset, len;
@ -145,6 +146,7 @@ hb_ot_map_builder_t::add_lookups (hb_ot_map_t &m,
lookup->auto_zwnj = auto_zwnj;
lookup->auto_zwj = auto_zwj;
lookup->random = random;
lookup->per_syllable = per_syllable;
}
offset += len;
@ -277,6 +279,7 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m,
map->auto_zwnj = !(info->flags & F_MANUAL_ZWNJ);
map->auto_zwj = !(info->flags & F_MANUAL_ZWJ);
map->random = !!(info->flags & F_RANDOM);
map->per_syllable = !!(info->flags & F_PER_SYLLABLE);
if ((info->flags & F_GLOBAL) && info->max_value == 1) {
/* Uses the global bit */
map->shift = global_bit_shift;
@ -319,7 +322,8 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m,
m.features[i].mask,
m.features[i].auto_zwnj,
m.features[i].auto_zwj,
m.features[i].random);
m.features[i].random,
m.features[i].per_syllable);
/* Sort lookups and merge duplicates */
if (last_num_lookups < m.lookups[table_index].length)

View File

@ -56,6 +56,7 @@ struct hb_ot_map_t
unsigned int auto_zwnj : 1;
unsigned int auto_zwj : 1;
unsigned int random : 1;
unsigned int per_syllable : 1;
int cmp (const hb_tag_t tag_) const
{ return tag_ < tag ? -1 : tag_ > tag ? 1 : 0; }
@ -66,6 +67,7 @@ struct hb_ot_map_t
unsigned short auto_zwnj : 1;
unsigned short auto_zwj : 1;
unsigned short random : 1;
unsigned short per_syllable : 1;
hb_mask_t mask;
HB_INTERNAL static int cmp (const void *pa, const void *pb)
@ -183,7 +185,8 @@ enum hb_ot_map_feature_flags_t
F_GLOBAL_MANUAL_JOINERS= F_GLOBAL | F_MANUAL_JOINERS,
F_GLOBAL_HAS_FALLBACK = F_GLOBAL | F_HAS_FALLBACK,
F_GLOBAL_SEARCH = 0x0010u, /* If feature not found in LangSys, look for it in global feature list and pick one. */
F_RANDOM = 0x0020u /* Randomly select a glyph from an AlternateSubstFormat1 subtable. */
F_RANDOM = 0x0020u, /* Randomly select a glyph from an AlternateSubstFormat1 subtable. */
F_PER_SYLLABLE = 0x0040u /* Contain lookup application to within syllable. */
};
HB_MARK_AS_FLAG_T (hb_ot_map_feature_flags_t);
@ -237,7 +240,8 @@ struct hb_ot_map_builder_t
hb_mask_t mask,
bool auto_zwnj = true,
bool auto_zwj = true,
bool random = false);
bool random = false,
bool per_syllable = false);
struct feature_info_t {
hb_tag_t tag;

View File

@ -316,9 +316,9 @@ hb_ot_metrics_get_position_with_fallback (hb_font_t *font,
break;
case HB_OT_METRICS_TAG_X_HEIGHT:
if (hb_font_get_nominal_glyph (font, 'o', &glyph) &&
if (hb_font_get_nominal_glyph (font, 'x', &glyph) &&
hb_font_get_glyph_extents (font, glyph, &extents))
*position = extents.height + 2 * extents.y_bearing;
*position = extents.y_bearing;
else
*position = font->y_scale / 2;
break;

View File

@ -109,17 +109,17 @@ indic_features[] =
* These features are applied in order, one at a time, after initial_reordering,
* constrained to the syllable.
*/
{HB_TAG('n','u','k','t'), F_GLOBAL_MANUAL_JOINERS},
{HB_TAG('a','k','h','n'), F_GLOBAL_MANUAL_JOINERS},
{HB_TAG('r','p','h','f'), F_MANUAL_JOINERS},
{HB_TAG('r','k','r','f'), F_GLOBAL_MANUAL_JOINERS},
{HB_TAG('p','r','e','f'), F_MANUAL_JOINERS},
{HB_TAG('b','l','w','f'), F_MANUAL_JOINERS},
{HB_TAG('a','b','v','f'), F_MANUAL_JOINERS},
{HB_TAG('h','a','l','f'), F_MANUAL_JOINERS},
{HB_TAG('p','s','t','f'), F_MANUAL_JOINERS},
{HB_TAG('v','a','t','u'), F_GLOBAL_MANUAL_JOINERS},
{HB_TAG('c','j','c','t'), F_GLOBAL_MANUAL_JOINERS},
{HB_TAG('n','u','k','t'), F_GLOBAL_MANUAL_JOINERS | F_PER_SYLLABLE},
{HB_TAG('a','k','h','n'), F_GLOBAL_MANUAL_JOINERS | F_PER_SYLLABLE},
{HB_TAG('r','p','h','f'), F_MANUAL_JOINERS | F_PER_SYLLABLE},
{HB_TAG('r','k','r','f'), F_GLOBAL_MANUAL_JOINERS | F_PER_SYLLABLE},
{HB_TAG('p','r','e','f'), F_MANUAL_JOINERS | F_PER_SYLLABLE},
{HB_TAG('b','l','w','f'), F_MANUAL_JOINERS | F_PER_SYLLABLE},
{HB_TAG('a','b','v','f'), F_MANUAL_JOINERS | F_PER_SYLLABLE},
{HB_TAG('h','a','l','f'), F_MANUAL_JOINERS | F_PER_SYLLABLE},
{HB_TAG('p','s','t','f'), F_MANUAL_JOINERS | F_PER_SYLLABLE},
{HB_TAG('v','a','t','u'), F_GLOBAL_MANUAL_JOINERS | F_PER_SYLLABLE},
{HB_TAG('c','j','c','t'), F_GLOBAL_MANUAL_JOINERS | F_PER_SYLLABLE},
/*
* Other features.
* These features are applied all at once, after final_reordering, constrained
@ -127,12 +127,12 @@ indic_features[] =
* Default Bengali font in Windows for example has intermixed
* lookups for init,pres,abvs,blws features.
*/
{HB_TAG('i','n','i','t'), F_MANUAL_JOINERS},
{HB_TAG('p','r','e','s'), F_GLOBAL_MANUAL_JOINERS},
{HB_TAG('a','b','v','s'), F_GLOBAL_MANUAL_JOINERS},
{HB_TAG('b','l','w','s'), F_GLOBAL_MANUAL_JOINERS},
{HB_TAG('p','s','t','s'), F_GLOBAL_MANUAL_JOINERS},
{HB_TAG('h','a','l','n'), F_GLOBAL_MANUAL_JOINERS},
{HB_TAG('i','n','i','t'), F_MANUAL_JOINERS | F_PER_SYLLABLE},
{HB_TAG('p','r','e','s'), F_GLOBAL_MANUAL_JOINERS | F_PER_SYLLABLE},
{HB_TAG('a','b','v','s'), F_GLOBAL_MANUAL_JOINERS | F_PER_SYLLABLE},
{HB_TAG('b','l','w','s'), F_GLOBAL_MANUAL_JOINERS | F_PER_SYLLABLE},
{HB_TAG('p','s','t','s'), F_GLOBAL_MANUAL_JOINERS | F_PER_SYLLABLE},
{HB_TAG('h','a','l','n'), F_GLOBAL_MANUAL_JOINERS | F_PER_SYLLABLE},
};
/*
@ -183,10 +183,10 @@ collect_features_indic (hb_ot_shape_planner_t *plan)
/* Do this before any lookups have been applied. */
map->add_gsub_pause (setup_syllables_indic);
map->enable_feature (HB_TAG('l','o','c','l'));
map->enable_feature (HB_TAG('l','o','c','l'), F_PER_SYLLABLE);
/* The Indic specs do not require ccmp, but we apply it here since if
* there is a use of it, it's typically at the beginning. */
map->enable_feature (HB_TAG('c','c','m','p'));
map->enable_feature (HB_TAG('c','c','m','p'), F_PER_SYLLABLE);
unsigned int i = 0;
@ -201,8 +201,6 @@ collect_features_indic (hb_ot_shape_planner_t *plan)
for (; i < INDIC_NUM_FEATURES; i++)
map->add_feature (indic_features[i]);
map->add_gsub_pause (_hb_clear_syllables);
}
static void

View File

@ -368,6 +368,7 @@ set_indic_properties (hb_glyph_info_t &info)
else if (unlikely (u == 0x0980u)) cat = OT_PLACEHOLDER; /* https://github.com/harfbuzz/harfbuzz/issues/538 */
else if (unlikely (u == 0x09FCu)) cat = OT_PLACEHOLDER; /* https://github.com/harfbuzz/harfbuzz/pull/1613 */
else if (unlikely (u == 0x0C80u)) cat = OT_PLACEHOLDER; /* https://github.com/harfbuzz/harfbuzz/pull/623 */
else if (unlikely (u == 0x0D04u)) cat = OT_PLACEHOLDER; /* https://github.com/harfbuzz/harfbuzz/pull/3511 */
else if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x2010u, 0x2011u)))
cat = OT_PLACEHOLDER;
else if (unlikely (u == 0x25CCu)) cat = OT_DOTTEDCIRCLE;

View File

@ -45,11 +45,11 @@ khmer_features[] =
* These features are applied all at once, before reordering, constrained
* to the syllable.
*/
{HB_TAG('p','r','e','f'), F_MANUAL_JOINERS},
{HB_TAG('b','l','w','f'), F_MANUAL_JOINERS},
{HB_TAG('a','b','v','f'), F_MANUAL_JOINERS},
{HB_TAG('p','s','t','f'), F_MANUAL_JOINERS},
{HB_TAG('c','f','a','r'), F_MANUAL_JOINERS},
{HB_TAG('p','r','e','f'), F_MANUAL_JOINERS | F_PER_SYLLABLE},
{HB_TAG('b','l','w','f'), F_MANUAL_JOINERS | F_PER_SYLLABLE},
{HB_TAG('a','b','v','f'), F_MANUAL_JOINERS | F_PER_SYLLABLE},
{HB_TAG('p','s','t','f'), F_MANUAL_JOINERS | F_PER_SYLLABLE},
{HB_TAG('c','f','a','r'), F_MANUAL_JOINERS | F_PER_SYLLABLE},
/*
* Other features.
* These features are applied all at once after clearing syllables.
@ -107,16 +107,10 @@ collect_features_khmer (hb_ot_shape_planner_t *plan)
*
* https://github.com/harfbuzz/harfbuzz/issues/974
*/
map->enable_feature (HB_TAG('l','o','c','l'));
map->enable_feature (HB_TAG('c','c','m','p'));
map->enable_feature (HB_TAG('l','o','c','l'), F_PER_SYLLABLE);
map->enable_feature (HB_TAG('c','c','m','p'), F_PER_SYLLABLE);
unsigned int i = 0;
for (; i < KHMER_BASIC_FEATURES; i++)
map->add_feature (khmer_features[i]);
map->add_gsub_pause (_hb_clear_syllables);
for (; i < KHMER_NUM_FEATURES; i++)
for (unsigned i = 0; i < KHMER_NUM_FEATURES; i++)
map->add_feature (khmer_features[i]);
}

View File

@ -79,22 +79,20 @@ collect_features_myanmar (hb_ot_shape_planner_t *plan)
/* Do this before any lookups have been applied. */
map->add_gsub_pause (setup_syllables_myanmar);
map->enable_feature (HB_TAG('l','o','c','l'));
map->enable_feature (HB_TAG('l','o','c','l'), F_PER_SYLLABLE);
/* The Indic specs do not require ccmp, but we apply it here since if
* there is a use of it, it's typically at the beginning. */
map->enable_feature (HB_TAG('c','c','m','p'));
map->enable_feature (HB_TAG('c','c','m','p'), F_PER_SYLLABLE);
map->add_gsub_pause (reorder_myanmar);
for (unsigned int i = 0; i < ARRAY_LENGTH (myanmar_basic_features); i++)
{
map->enable_feature (myanmar_basic_features[i], F_MANUAL_ZWJ);
map->enable_feature (myanmar_basic_features[i], F_MANUAL_ZWJ | F_PER_SYLLABLE);
map->add_gsub_pause (nullptr);
}
map->add_gsub_pause (_hb_clear_syllables);
for (unsigned int i = 0; i < ARRAY_LENGTH (myanmar_other_features); i++)
map->enable_feature (myanmar_other_features[i], F_MANUAL_ZWJ);
}

File diff suppressed because it is too large Load Diff

View File

@ -53,7 +53,7 @@
#define GB USE(GB) /* BASE_OTHER */
#define H USE(H) /* HALANT */
#define HN USE(HN) /* HALANT_NUM */
#define HVM USE(HVM) /* HALANT_OR_VOWEL_MODIFIER */
#define IS USE(IS) /* INVISIBLE_STACKER */
#define J USE(J) /* HIEROGLYPH_JOINER */
#define N USE(N) /* BASE_NUM */
#define O USE(O) /* OTHER */
@ -278,7 +278,7 @@ static const uint8_t use_table[] = {
/* 1000 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 1010 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 1020 */ B, B, B, B, B, B, B, B, B, B, B, VPst, VPst, VAbv, VAbv, VBlw,
/* 1030 */ VBlw, VPre, VAbv, VAbv, VAbv, VAbv, VMAbv, VMBlw, VMPst, H, VAbv, MPst, MPre, MBlw, MBlw, B,
/* 1030 */ VBlw, VPre, VAbv, VAbv, VAbv, VAbv, VMAbv, VMBlw, VMPst, IS, VAbv, MPst, MPre, MBlw, MBlw, B,
/* 1040 */ B, B, B, B, B, B, B, B, B, B, O, GB, O, O, GB, O,
/* 1050 */ B, B, B, B, B, B, VPst, VPst, VBlw, VBlw, B, B, B, B, MBlw, MBlw,
/* 1060 */ MBlw, B, VPst, VMPst, VMPst, B, B, VPst, VPst, VMPst, VMPst, VMPst, VMPst, VMPst, B, B,
@ -316,7 +316,7 @@ static const uint8_t use_table[] = {
/* 17A0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 17B0 */ B, B, B, B, CGJ, CGJ, VPst, VAbv, VAbv, VAbv, VAbv, VBlw, VBlw, VBlw, VPre, VPre,
/* 17C0 */ VPre, VPre, VPre, VPre, VPre, VPre, VMAbv, VMPst, VPst, VMAbv, VMAbv, FMAbv, FAbv, CMAbv, FMAbv, VMAbv,
/* 17D0 */ FMAbv, VAbv, H, FMAbv, O, O, O, O, O, O, O, O, B, FMAbv, WJ, WJ,
/* 17D0 */ FMAbv, VAbv, IS, FMAbv, O, O, O, O, O, O, O, O, B, FMAbv, WJ, WJ,
/* 17E0 */ B, B, B, B, B, B, B, B, B, B, WJ, WJ, WJ, WJ, WJ, WJ,
/* 17F0 */ O, O, O, O, O, O, O, O, O, O, WJ, WJ, WJ, WJ, WJ, WJ,
@ -396,7 +396,7 @@ static const uint8_t use_table[] = {
/* 1B80 */ VMAbv, FAbv, VMPst, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 1B90 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 1BA0 */ B, SUB, SUB, SUB, VAbv, VBlw, VPre, VPst, VAbv, VAbv, VPst, H, SUB, SUB, B, B,
/* 1BA0 */ B, SUB, SUB, SUB, VAbv, VBlw, VPre, VPst, VAbv, VAbv, VPst, IS, SUB, SUB, B, B,
/* 1BB0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* Batak */
@ -555,7 +555,7 @@ static const uint8_t use_table[] = {
/* Meetei Mayek Extensions */
/* AAE0 */ B, B, B, B, B, B, B, B, B, B, B, VPre, VBlw, VAbv, VPre, VPst,
/* AAF0 */ O, O, O, O, O, VMPst, H, WJ,
/* AAF0 */ O, O, O, O, O, VMPst, IS, WJ,
#define use_offset_0xabc0u 4040
@ -606,7 +606,7 @@ static const uint8_t use_table[] = {
/* 10A00 */ B, VBlw, VBlw, VBlw, WJ, VAbv, VBlw, WJ, WJ, WJ, WJ, WJ, VPst, VMBlw, VMBlw, VMAbv,
/* 10A10 */ B, B, B, B, WJ, B, B, B, WJ, B, B, B, B, B, B, B,
/* 10A20 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 10A30 */ B, B, B, B, B, B, WJ, WJ, CMAbv, CMBlw, CMBlw, WJ, WJ, WJ, WJ, H,
/* 10A30 */ B, B, B, B, B, B, WJ, WJ, CMAbv, CMBlw, CMBlw, WJ, WJ, WJ, WJ, IS,
/* 10A40 */ B, B, B, B, B, B, B, B, B, WJ, WJ, WJ, WJ, WJ, WJ, WJ,
#define use_offset_0x10ac0u 4304
@ -699,7 +699,7 @@ static const uint8_t use_table[] = {
/* 11100 */ VMAbv, VMAbv, VMAbv, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 11110 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 11120 */ B, B, B, B, B, B, B, VBlw, VBlw, VBlw, VAbv, VAbv, VPre, VBlw, VAbv, VAbv,
/* 11130 */ VBlw, VAbv, VAbv, H, CMAbv, WJ, B, B, B, B, B, B, B, B, B, B,
/* 11130 */ VBlw, VAbv, VAbv, IS, CMAbv, WJ, B, B, B, B, B, B, B, B, B, B,
/* 11140 */ O, O, O, O, B, VPst, VPst, B, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ,
/* Mahajani */
@ -752,7 +752,7 @@ static const uint8_t use_table[] = {
/* 11310 */ B, WJ, WJ, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 11320 */ B, B, B, B, B, B, B, B, B, WJ, B, B, B, B, B, B,
/* 11330 */ B, WJ, B, B, WJ, B, B, B, B, B, WJ, CMBlw, CMBlw, B, VPst, VPst,
/* 11340 */ VAbv, VPst, VPst, VPst, VPst, WJ, WJ, VPre, VPre, WJ, WJ, VPre, VPre, HVM, WJ, WJ,
/* 11340 */ VAbv, VPst, VPst, VPst, VPst, WJ, WJ, VPre, VPre, WJ, WJ, VPre, VPre, H, WJ, WJ,
/* 11350 */ O, WJ, WJ, WJ, WJ, WJ, WJ, VPst, WJ, WJ, WJ, WJ, WJ, O, B, B,
/* 11360 */ B, B, VPst, VPst, WJ, WJ, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, WJ, WJ, WJ,
/* 11370 */ VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, WJ, WJ, WJ,
@ -842,7 +842,7 @@ static const uint8_t use_table[] = {
/* 11900 */ B, B, B, B, B, B, B, WJ, WJ, B, WJ, WJ, B, B, B, B,
/* 11910 */ B, B, B, B, WJ, B, B, WJ, B, B, B, B, B, B, B, B,
/* 11920 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 11930 */ VPst, VPst, VPst, VPst, VPst, VPre, WJ, VPre, VPre, WJ, WJ, VMAbv, VMAbv, VPst, H, R,
/* 11930 */ VPst, VPst, VPst, VPst, VPst, VPre, WJ, VPre, VPre, WJ, WJ, VMAbv, VMAbv, VPst, IS, R,
/* 11940 */ MPst, R, MPst, CMBlw, O, O, O, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ,
/* 11950 */ B, B, B, B, B, B, B, B, B, B, WJ, WJ, WJ, WJ, WJ, WJ,
@ -864,7 +864,7 @@ static const uint8_t use_table[] = {
/* 11A10 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 11A20 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 11A30 */ B, B, B, FMBlw, VBlw, VMAbv, VMAbv, VMAbv, VMAbv, VMPst, R, MBlw, MBlw, MBlw, MBlw, GB,
/* 11A40 */ O, O, O, O, O, GB, O, H, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ,
/* 11A40 */ O, O, O, O, O, GB, O, IS, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ,
/* Soyombo */
@ -872,7 +872,7 @@ static const uint8_t use_table[] = {
/* 11A60 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 11A70 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 11A80 */ B, B, B, B, R, R, R, R, R, R, FBlw, FBlw, FBlw, FBlw, FBlw, FBlw,
/* 11A90 */ FBlw, FBlw, FBlw, FBlw, FBlw, FBlw, VMAbv, VMPst, CMAbv, H, O, O, O, B, O, O,
/* 11A90 */ FBlw, FBlw, FBlw, FBlw, FBlw, FBlw, VMAbv, VMPst, CMAbv, IS, O, O, O, B, O, O,
#define use_offset_0x11c00u 6592
@ -904,7 +904,7 @@ static const uint8_t use_table[] = {
/* 11D10 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 11D20 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 11D30 */ B, VAbv, VAbv, VAbv, VAbv, VAbv, VBlw, WJ, WJ, WJ, VAbv, WJ, VAbv, VAbv, WJ, VAbv,
/* 11D40 */ VMAbv, VMAbv, CMBlw, VAbv, VBlw, H, R, MBlw, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ,
/* 11D40 */ VMAbv, VMAbv, CMBlw, VAbv, VBlw, IS, R, MBlw, WJ, WJ, WJ, WJ, WJ, WJ, WJ, WJ,
/* 11D50 */ B, B, B, B, B, B, B, B, B, B, WJ, WJ, WJ, WJ, WJ, WJ,
/* Gunjala Gondi */
@ -912,7 +912,7 @@ static const uint8_t use_table[] = {
/* 11D60 */ B, B, B, B, B, B, WJ, B, B, WJ, B, B, B, B, B, B,
/* 11D70 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 11D80 */ B, B, B, B, B, B, B, B, B, B, VPst, VPst, VPst, VPst, VPst, WJ,
/* 11D90 */ VAbv, VAbv, WJ, VPst, VPst, VMAbv, VMPst, H, O, WJ, WJ, WJ, WJ, WJ, WJ, WJ,
/* 11D90 */ VAbv, VAbv, WJ, VPst, VPst, VMAbv, VMPst, IS, O, WJ, WJ, WJ, WJ, WJ, WJ, WJ,
/* 11DA0 */ B, B, B, B, B, B, B, B, B, B, WJ, WJ, WJ, WJ, WJ, WJ,
#define use_offset_0x11ee0u 6952
@ -1531,7 +1531,7 @@ hb_use_get_category (hb_glyph_info_t info)
#undef GB
#undef H
#undef HN
#undef HVM
#undef IS
#undef J
#undef N
#undef O

View File

@ -115,25 +115,24 @@ collect_features_use (hb_ot_shape_planner_t *plan)
map->add_gsub_pause (setup_syllables_use);
/* "Default glyph pre-processing group" */
map->enable_feature (HB_TAG('l','o','c','l'));
map->enable_feature (HB_TAG('c','c','m','p'));
map->enable_feature (HB_TAG('n','u','k','t'));
map->enable_feature (HB_TAG('a','k','h','n'), F_MANUAL_ZWJ);
map->enable_feature (HB_TAG('l','o','c','l'), F_PER_SYLLABLE);
map->enable_feature (HB_TAG('c','c','m','p'), F_PER_SYLLABLE);
map->enable_feature (HB_TAG('n','u','k','t'), F_PER_SYLLABLE);
map->enable_feature (HB_TAG('a','k','h','n'), F_MANUAL_ZWJ | F_PER_SYLLABLE);
/* "Reordering group" */
map->add_gsub_pause (_hb_clear_substitution_flags);
map->add_feature (HB_TAG('r','p','h','f'), F_MANUAL_ZWJ);
map->add_feature (HB_TAG('r','p','h','f'), F_MANUAL_ZWJ | F_PER_SYLLABLE);
map->add_gsub_pause (record_rphf_use);
map->add_gsub_pause (_hb_clear_substitution_flags);
map->enable_feature (HB_TAG('p','r','e','f'), F_MANUAL_ZWJ);
map->enable_feature (HB_TAG('p','r','e','f'), F_MANUAL_ZWJ | F_PER_SYLLABLE);
map->add_gsub_pause (record_pref_use);
/* "Orthographic unit shaping group" */
for (unsigned int i = 0; i < ARRAY_LENGTH (use_basic_features); i++)
map->enable_feature (use_basic_features[i], F_MANUAL_ZWJ);
map->enable_feature (use_basic_features[i], F_MANUAL_ZWJ | F_PER_SYLLABLE);
map->add_gsub_pause (reorder_use);
map->add_gsub_pause (_hb_clear_syllables);
/* "Topographical features" */
for (unsigned int i = 0; i < ARRAY_LENGTH (use_topographical_features); i++)
@ -350,7 +349,7 @@ record_pref_use (const hb_ot_shape_plan_t *plan HB_UNUSED,
static inline bool
is_halant_use (const hb_glyph_info_t &info)
{
return (info.use_category() == USE(H) || info.use_category() == USE(HVM)) &&
return (info.use_category() == USE(H) || info.use_category() == USE(IS)) &&
!_hb_glyph_info_ligated (&info);
}

View File

@ -935,17 +935,23 @@ hb_ot_substitute_pre (const hb_ot_shape_context_t *c)
_hb_buffer_allocate_gsubgpos_vars (c->buffer);
hb_ot_substitute_complex (c);
#ifndef HB_NO_AAT_SHAPE
if (c->plan->apply_morx && c->plan->apply_gpos)
hb_aat_layout_remove_deleted_glyphs (c->buffer);
#endif
}
static inline void
hb_ot_substitute_post (const hb_ot_shape_context_t *c)
{
hb_ot_hide_default_ignorables (c->buffer, c->font);
#ifndef HB_NO_AAT_SHAPE
if (c->plan->apply_morx)
if (c->plan->apply_morx && !c->plan->apply_gpos)
hb_aat_layout_remove_deleted_glyphs (c->buffer);
#endif
hb_ot_hide_default_ignorables (c->buffer, c->font);
if (c->plan->shaper->postprocess_glyphs &&
c->buffer->message(c->font, "start postprocess-glyphs")) {
c->plan->shaper->postprocess_glyphs (c->plan, c->buffer, c->font);

View File

@ -577,10 +577,11 @@ struct gvar
hb_bytes_t bytes ((const char *) p, length);
hb_vector_t<unsigned int> private_indices;
if (iterator.current_tuple->has_private_points () &&
bool has_private_points = iterator.current_tuple->has_private_points ();
if (has_private_points &&
!GlyphVariationData::unpack_points (p, private_indices, bytes))
return false;
const hb_array_t<unsigned int> &indices = private_indices.length ? private_indices : shared_indices;
const hb_array_t<unsigned int> &indices = has_private_points ? private_indices : shared_indices;
bool apply_to_all = (indices.length == 0);
unsigned int num_deltas = apply_to_all ? points.length : indices.length;

View File

@ -256,6 +256,29 @@ hb_set_add (hb_set_t *set,
set->add (codepoint);
}
/**
* hb_set_add_sorted_array:
* @set: A set
* @sorted_codepoints: (array length=num_codepoints): Array of codepoints to add
* @num_codepoints: Length of @sorted_codepoints
*
* Adds @num_codepoints codepoints to a set at once.
* The codepoints array must be in increasing order,
* with size at least @num_codepoints.
*
* Since: 4.1.0
*/
HB_EXTERN void
hb_set_add_sorted_array (hb_set_t *set,
const hb_codepoint_t *sorted_codepoints,
unsigned int num_codepoints)
{
/* Immutible-safe. */
set->add_sorted_array (sorted_codepoints,
num_codepoints,
sizeof(hb_codepoint_t));
}
/**
* hb_set_add_range:
* @set: A set
@ -591,3 +614,28 @@ hb_set_previous_range (const hb_set_t *set,
{
return set->previous_range (first, last);
}
/**
* hb_set_next_many:
* @set: A set
* @codepoint: Outputting codepoints starting after this one.
* Use #HB_SET_VALUE_INVALID to get started.
* @out: (array length=size): An array of codepoints to write to.
* @size: The maximum number of codepoints to write out.
*
* Finds the next element in @set that is greater than @codepoint. Writes out
* codepoints to @out, until either the set runs out of elements, or @size
* codepoints are written, whichever comes first.
*
* Return value: the number of values written.
*
* Since: 4.2.0
**/
unsigned int
hb_set_next_many (const hb_set_t *set,
hb_codepoint_t codepoint,
hb_codepoint_t *out,
unsigned int size)
{
return set->next_many (codepoint, out, size);
}

View File

@ -110,6 +110,11 @@ hb_set_add_range (hb_set_t *set,
hb_codepoint_t first,
hb_codepoint_t last);
HB_EXTERN void
hb_set_add_sorted_array (hb_set_t *set,
const hb_codepoint_t *sorted_codepoints,
unsigned int num_codepoints);
HB_EXTERN void
hb_set_del (hb_set_t *set,
hb_codepoint_t codepoint);
@ -180,6 +185,12 @@ hb_set_previous_range (const hb_set_t *set,
hb_codepoint_t *first,
hb_codepoint_t *last);
/* Pass HB_SET_VALUE_INVALID in to get started. */
HB_EXTERN unsigned int
hb_set_next_many (const hb_set_t *set,
hb_codepoint_t codepoint,
hb_codepoint_t *out,
unsigned int size);
HB_END_DECLS

View File

@ -109,6 +109,7 @@ struct hb_sparseset_t
typedef bool value_t;
value_t operator [] (hb_codepoint_t k) const { return get (k); }
bool has (hb_codepoint_t k) const { return (*this)[k] != SENTINEL; }
/* Predicate. */
bool operator () (hb_codepoint_t k) const { return has (k); }
@ -138,6 +139,8 @@ struct hb_sparseset_t
{ return s.next_range (first, last); }
bool previous_range (hb_codepoint_t *first, hb_codepoint_t *last) const
{ return s.previous_range (first, last); }
unsigned int next_many (hb_codepoint_t codepoint, hb_codepoint_t *out, unsigned int size) const
{ return s.next_many (codepoint, out, size); }
unsigned int get_population () const { return s.get_population (); }
hb_codepoint_t get_min () const { return s.get_min (); }

View File

@ -56,6 +56,7 @@ const unsigned char _hb_Null_AAT_Lookup[2] = {0xFF, 0xFF};
/* hb_face_t */
#ifndef HB_NO_BORING_EXPANSION
static inline unsigned
load_num_glyphs_from_loca (const hb_face_t *face)
{
@ -72,6 +73,7 @@ load_num_glyphs_from_loca (const hb_face_t *face)
return ret;
}
#endif
static inline unsigned
load_num_glyphs_from_maxp (const hb_face_t *face)

View File

@ -40,6 +40,8 @@
#include "hb-ot-stat-table.hh"
#include "hb-ot-math-table.hh"
using OT::Layout::GSUB::GSUB;
typedef hb_hashmap_t<unsigned, hb_set_t *> script_langsys_map;
#ifndef HB_NO_SUBSET_CFF
@ -358,7 +360,7 @@ _populate_gids_to_retain (hb_subset_plan_t* plan,
#ifndef HB_NO_SUBSET_LAYOUT
if (close_over_gsub)
// closure all glyphs/lookups/features needed for GSUB substitutions.
_closure_glyphs_lookups_features<OT::GSUB> (
_closure_glyphs_lookups_features<GSUB> (
plan->source,
plan->_glyphset_gsub,
plan->layout_features,

View File

@ -55,6 +55,8 @@
#include "hb-ot-math-table.hh"
#include "hb-repacker.hh"
using OT::Layout::GSUB::GSUB;
/**
* SECTION:hb-subset
* @title: hb-subset
@ -312,7 +314,7 @@ _subset_table (hb_subset_plan_t *plan, hb_tag_t tag)
#ifndef HB_NO_SUBSET_LAYOUT
case HB_OT_TAG_GDEF: return _subset<const OT::GDEF> (plan);
case HB_OT_TAG_GSUB: return _subset<const OT::GSUB> (plan);
case HB_OT_TAG_GSUB: return _subset<const GSUB> (plan);
case HB_OT_TAG_GPOS: return _subset<const OT::GPOS> (plan);
case HB_OT_TAG_gvar: return _subset<const OT::gvar> (plan);
case HB_OT_TAG_HVAR: return _subset<const OT::HVAR> (plan);

View File

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