mirror of https://github.com/godotengine/godot
Merge pull request #59725 from bruvzg/hb_420
This commit is contained in:
commit
e17ce39d59
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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, "");
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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]);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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 (); }
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
Loading…
Reference in New Issue