parent
90af2143d5
commit
a9910e258f
10 changed files with 440 additions and 330 deletions
@ -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,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,59 @@ |
|||||||
|
#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 { |
||||||
|
// TODO(garretrieger): move this ot layout::GSUB namespace
|
||||||
|
//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 : GSUB::accelerator_t { |
||||||
|
GSUB_accelerator_t (hb_face_t *face) : GSUB::accelerator_t (face) {} |
||||||
|
}; |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//}
|
||||||
|
//}
|
||||||
|
} |
||||||
|
|
||||||
|
#endif /* OT_LAYOUT_GSUB_GSUB_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 */ |
Loading…
Reference in new issue