harfbuzz/src/hb-ot-layout-gsub-table.hh

411 lines
14 KiB
C++
Raw Normal View History

2008-01-23 23:01:55 +01:00
/*
2011-04-21 23:14:28 +02:00
* Copyright © 2007,2008,2009,2010 Red Hat, Inc.
* Copyright © 2010,2012,2013 Google, Inc.
2008-01-23 23:01:55 +01:00
*
2010-04-22 06:11:43 +02:00
* This is part of HarfBuzz, a text shaping library.
2008-01-23 23:01:55 +01:00
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Red Hat Author(s): Behdad Esfahbod
* Google Author(s): Behdad Esfahbod
2008-01-23 23:01:55 +01:00
*/
#ifndef HB_OT_LAYOUT_GSUB_TABLE_HH
#define HB_OT_LAYOUT_GSUB_TABLE_HH
2008-01-23 23:01:55 +01:00
#include "hb-ot-layout-gsubgpos.hh"
#include "OT/Layout/GSUB/Common.hh"
#include "OT/Layout/GSUB/SingleSubst.hh"
#include "OT/Layout/GSUB/MultipleSubst.hh"
#include "OT/Layout/GSUB/AlternateSubst.hh"
#include "OT/Layout/GSUB/LigatureSubst.hh"
#include "OT/Layout/GSUB/ReverseChainSingleSubst.hh"
2008-01-23 23:01:55 +01:00
namespace OT {
using Layout::GSUB::hb_codepoint_pair_t;
using Layout::GSUB::SingleSubst;
using Layout::GSUB::MultipleSubst;
using Layout::GSUB::AlternateSubst;
using Layout::GSUB::LigatureSubst;
using Layout::GSUB::ReverseChainSingleSubst;
2008-01-23 23:01:55 +01:00
2012-11-23 22:51:43 +01:00
struct ContextSubst : Context {};
2009-05-17 01:59:15 +02:00
2012-11-23 22:51:43 +01:00
struct ChainContextSubst : ChainContext {};
2009-04-16 19:40:13 +02:00
2012-11-23 22:57:36 +01:00
struct ExtensionSubst : Extension<ExtensionSubst>
2009-05-20 05:42:30 +02:00
{
2018-09-04 01:53:03 +02:00
typedef struct SubstLookupSubTable SubTable;
bool is_reverse () const;
2009-04-16 19:40:13 +02:00
};
2009-04-16 01:50:16 +02:00
/*
* SubstLookup
*/
2009-05-20 05:42:30 +02:00
struct SubstLookupSubTable
{
2018-09-04 02:16:09 +02:00
friend struct Lookup;
2009-04-16 01:50:16 +02:00
friend struct SubstLookup;
enum Type {
Single = 1,
Multiple = 2,
Alternate = 3,
Ligature = 4,
Context = 5,
ChainContext = 6,
Extension = 7,
2009-08-18 22:41:59 +02:00
ReverseChainSingle = 8
};
template <typename context_t, typename ...Ts>
2019-05-08 05:58:43 +02:00
typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type, Ts&&... ds) const
{
2014-12-13 05:36:49 +01:00
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);
}
protected:
2009-04-16 01:50:16 +02:00
union {
2010-05-11 01:45:41 +02:00
SingleSubst single;
MultipleSubst multiple;
AlternateSubst alternate;
LigatureSubst ligature;
ContextSubst context;
2010-05-11 01:45:41 +02:00
ChainContextSubst chainContext;
ExtensionSubst extension;
ReverseChainSingleSubst reverseChainContextSingle;
2009-04-16 01:50:16 +02:00
} u;
2010-05-11 00:08:46 +02:00
public:
2018-12-12 16:07:38 +01:00
DEFINE_SIZE_MIN (0);
2009-04-16 01:50:16 +02:00
};
2009-04-16 19:40:13 +02:00
2009-05-20 05:42:30 +02:00
struct SubstLookup : Lookup
{
2018-09-04 01:53:03 +02:00
typedef SubstLookupSubTable SubTable;
const SubTable& get_subtable (unsigned int i) const
2018-09-04 01:53:03 +02:00
{ return Lookup::get_subtable<SubTable> (i); }
2009-04-16 01:50:16 +02:00
static inline bool lookup_type_is_reverse (unsigned int lookup_type)
2018-09-04 01:53:03 +02:00
{ return lookup_type == SubTable::ReverseChainSingle; }
bool is_reverse () const
2009-05-20 05:42:30 +02:00
{
2009-04-16 01:50:16 +02:00
unsigned int type = get_type ();
2018-09-04 01:53:03 +02:00
if (unlikely (type == SubTable::Extension))
2020-02-21 10:35:44 +01:00
return reinterpret_cast<const ExtensionSubst &> (get_subtable (0)).is_reverse ();
return lookup_type_is_reverse (type);
2009-04-16 01:50:16 +02:00
}
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
2015-02-19 08:47:18 +01:00
{
TRACE_APPLY (this);
return_trace (dispatch (c));
2015-02-19 08:47:18 +01:00
}
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
2012-11-23 23:55:40 +01:00
{
if (!c->should_visit_lookup (this_index))
2019-01-18 18:53:06 +01:00
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 ();
2019-01-18 18:53:06 +01:00
return ret;
2012-11-24 00:13:48 +01:00
}
2019-10-23 01:00:43 +02:00
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
2012-11-24 00:13:48 +01:00
{
c->set_recurse_func (dispatch_recurse_func<hb_collect_glyphs_context_t>);
2019-01-18 20:59:18 +01:00
return dispatch (c);
2012-11-23 23:55:40 +01:00
}
2012-08-02 03:18:54 +02:00
template <typename set_t>
void collect_coverage (set_t *glyphs) const
2012-08-02 03:18:54 +02:00
{
hb_collect_coverage_context_t<set_t> c (glyphs);
dispatch (&c);
2012-08-02 03:18:54 +02:00
}
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);
2009-08-04 08:27:37 +02:00
bool serialize_single (hb_serialize_context_t *c,
uint32_t lookup_props,
2021-09-19 22:30:12 +02:00
hb_sorted_array_t<const HBGlyphID16> glyphs,
hb_array_t<const HBGlyphID16> substitutes)
2012-09-05 03:13:17 +02:00
{
2012-11-23 21:32:14 +01:00
TRACE_SERIALIZE (this);
2018-09-04 01:53:03 +02:00
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);
2012-09-05 03:13:17 +02:00
}
bool serialize_multiple (hb_serialize_context_t *c,
uint32_t lookup_props,
2021-09-19 22:30:12 +02:00
hb_sorted_array_t<const HBGlyphID16> glyphs,
2018-12-18 22:49:08 +01:00
hb_array_t<const unsigned int> substitute_len_list,
2021-09-19 22:30:12 +02:00
hb_array_t<const HBGlyphID16> substitute_glyphs_list)
2012-09-05 03:13:17 +02:00
{
2012-11-23 21:32:14 +01:00
TRACE_SERIALIZE (this);
2018-09-04 01:53:03 +02:00
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);
2012-09-05 03:13:17 +02:00
}
bool serialize_alternate (hb_serialize_context_t *c,
uint32_t lookup_props,
2021-09-19 22:30:12 +02:00
hb_sorted_array_t<const HBGlyphID16> glyphs,
2018-12-18 22:49:08 +01:00
hb_array_t<const unsigned int> alternate_len_list,
2021-09-19 22:30:12 +02:00
hb_array_t<const HBGlyphID16> alternate_glyphs_list)
2012-09-05 03:13:17 +02:00
{
2012-11-23 21:32:14 +01:00
TRACE_SERIALIZE (this);
2018-09-04 01:53:03 +02:00
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);
2012-09-05 03:13:17 +02:00
}
bool serialize_ligature (hb_serialize_context_t *c,
uint32_t lookup_props,
2021-09-19 22:30:12 +02:00
hb_sorted_array_t<const HBGlyphID16> first_glyphs,
2018-12-18 22:49:08 +01:00
hb_array_t<const unsigned int> ligature_per_first_glyph_count_list,
2021-09-19 22:30:12 +02:00
hb_array_t<const HBGlyphID16> ligatures_list,
2018-12-18 22:49:08 +01:00
hb_array_t<const unsigned int> component_count_list,
2021-09-19 22:30:12 +02:00
hb_array_t<const HBGlyphID16> component_list /* Starting from second for each ligature */)
2012-09-05 03:13:17 +02:00
{
2012-11-23 21:32:14 +01:00
TRACE_SERIALIZE (this);
2018-09-04 01:53:03 +02:00
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);
2012-09-05 03:13:17 +02:00
}
2013-03-09 07:59:30 +01:00
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);
2013-03-09 07:59:30 +01:00
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))
2019-05-11 05:43:26 +02:00
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;
}
2019-10-23 01:00:43 +02:00
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>
2019-05-08 05:58:43 +02:00
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
{ return Lookup::dispatch<SubTable> (c, std::forward<Ts> (ds)...); }
2018-09-04 01:53:03 +02:00
bool subset (hb_subset_context_t *c) const
{ return Lookup::subset<SubTable> (c); }
2013-03-09 07:59:30 +01:00
bool sanitize (hb_sanitize_context_t *c) const
2018-09-04 02:16:09 +02:00
{ return Lookup::sanitize<SubTable> (c); }
2009-04-16 01:50:16 +02:00
};
2008-01-24 00:02:28 +01:00
/*
* GSUB -- Glyph Substitution
* https://docs.microsoft.com/en-us/typography/opentype/spec/gsub
2008-01-24 00:02:28 +01:00
*/
2009-05-20 05:42:30 +02:00
struct GSUB : GSUBGPOS
{
static constexpr hb_tag_t tableTag = HB_OT_TAG_GSUB;
2008-01-24 00:02:28 +01:00
const SubstLookup& get_lookup (unsigned int i) const
2019-12-10 20:18:32 +01:00
{ return static_cast<const SubstLookup &> (GSUBGPOS::get_lookup (i)); }
2009-04-16 01:50:16 +02:00
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);
}
2018-09-01 01:31:00 +02:00
bool sanitize (hb_sanitize_context_t *c) const
{ return GSUBGPOS::sanitize<SubstLookup> (c); }
2018-08-26 09:47:55 +02:00
2020-06-05 21:57:23 +02:00
HB_INTERNAL bool is_blocklisted (hb_blob_t *blob,
hb_face_t *face) const;
void closure_lookups (hb_face_t *face,
2020-07-29 06:03:32 +02:00
const hb_set_t *glyphs,
hb_set_t *lookup_indexes /* IN/OUT */) const
{ GSUBGPOS::closure_lookups<SubstLookup> (face, glyphs, lookup_indexes); }
2018-08-26 09:47:55 +02:00
typedef GSUBGPOS::accelerator_t<GSUB> accelerator_t;
2008-01-24 00:02:28 +01:00
};
2009-05-16 00:54:53 +02:00
struct GSUB_accelerator_t : GSUB::accelerator_t {
GSUB_accelerator_t (hb_face_t *face) : GSUB::accelerator_t (face) {}
};
2018-11-06 05:19:04 +01:00
2009-05-18 03:06:08 +02:00
/* Out-of-class implementation for methods recursing */
2009-05-16 00:54:53 +02:00
#ifndef HB_NO_OT_LAYOUT
/*static*/ inline bool ExtensionSubst::is_reverse () const
{
return SubstLookup::lookup_type_is_reverse (get_type ());
}
template <typename context_t>
/*static*/ typename context_t::return_t SubstLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
2012-11-23 23:55:40 +01:00
{
2018-11-06 05:19:04 +01:00
const SubstLookup &l = c->face->table.GSUB.get_relaxed ()->table->get_lookup (lookup_index);
return l.dispatch (c);
2012-11-23 23:55:40 +01:00
}
2019-10-23 01:00:43 +02:00
/*static*/ typename hb_closure_context_t::return_t SubstLookup::closure_glyphs_recurse_func (hb_closure_context_t *c, unsigned lookup_index, hb_set_t *covered_seq_indices, unsigned seq_index, unsigned end_index)
{
const SubstLookup &l = c->face->table.GSUB.get_relaxed ()->table->get_lookup (lookup_index);
if (l.may_have_non_1to1 ())
hb_set_add_range (covered_seq_indices, seq_index, end_index);
return l.dispatch (c);
}
2019-10-23 01:00:43 +02:00
/*static*/ inline hb_closure_lookups_context_t::return_t SubstLookup::dispatch_closure_lookups_recurse_func (hb_closure_lookups_context_t *c, unsigned this_index)
{
const SubstLookup &l = c->face->table.GSUB.get_relaxed ()->table->get_lookup (this_index);
return l.closure_lookups (c, this_index);
}
/*static*/ bool SubstLookup::apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index)
2009-05-20 05:42:30 +02:00
{
2018-11-06 05:19:04 +01:00
const SubstLookup &l = c->face->table.GSUB.get_relaxed ()->table->get_lookup (lookup_index);
unsigned int saved_lookup_props = c->lookup_props;
unsigned int saved_lookup_index = c->lookup_index;
c->set_lookup_index (lookup_index);
c->set_lookup_props (l.get_props ());
bool ret = l.dispatch (c);
c->set_lookup_index (saved_lookup_index);
c->set_lookup_props (saved_lookup_props);
return ret;
2009-05-16 00:54:53 +02:00
}
#endif
2009-05-16 00:54:53 +02:00
2012-11-17 03:49:54 +01:00
} /* namespace OT */
2010-07-23 21:11:18 +02:00
#endif /* HB_OT_LAYOUT_GSUB_TABLE_HH */