Merge pull request #2473 from harfbuzz/gsub-alternate

fixes #673
This commit is contained in:
Ebrahim Byagowi 2020-06-19 10:46:12 +04:30 committed by GitHub
commit a512ca8eae
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 162 additions and 45 deletions

View File

@ -574,6 +574,7 @@ hb_ot_layout_language_get_feature_indexes
hb_ot_layout_language_get_feature_tags hb_ot_layout_language_get_feature_tags
hb_ot_layout_language_get_required_feature hb_ot_layout_language_get_required_feature
hb_ot_layout_lookup_collect_glyphs hb_ot_layout_lookup_collect_glyphs
hb_ot_layout_lookup_get_glyph_alternates
hb_ot_layout_lookup_substitute_closure hb_ot_layout_lookup_substitute_closure
hb_ot_layout_lookups_substitute_closure hb_ot_layout_lookups_substitute_closure
hb_ot_layout_lookup_would_substitute hb_ot_layout_lookup_would_substitute

View File

@ -373,10 +373,6 @@ struct hb_no_trace_t {
#define HB_DEBUG_FT (HB_DEBUG+0) #define HB_DEBUG_FT (HB_DEBUG+0)
#endif #endif
#ifndef HB_DEBUG_GET_COVERAGE
#define HB_DEBUG_GET_COVERAGE (HB_DEBUG+0)
#endif
#ifndef HB_DEBUG_OBJECT #ifndef HB_DEBUG_OBJECT
#define HB_DEBUG_OBJECT (HB_DEBUG+0) #define HB_DEBUG_OBJECT (HB_DEBUG+0)
#endif #endif

View File

@ -35,7 +35,7 @@
* Dispatch * Dispatch
*/ */
template <typename Context, typename Return, unsigned int MaxDebugDepth> template <typename Context, typename Return=hb_empty_t, unsigned int MaxDebugDepth=0>
struct hb_dispatch_context_t struct hb_dispatch_context_t
{ {
private: private:
@ -43,6 +43,8 @@ struct hb_dispatch_context_t
const Context* thiz () const { return static_cast<const Context *> (this); } const Context* thiz () const { return static_cast<const Context *> (this); }
Context* thiz () { return static_cast< Context *> (this); } Context* thiz () { return static_cast< Context *> (this); }
public: public:
const char *get_name () { return "UNKNOWN"; }
static constexpr unsigned debug_depth = 0;
static constexpr unsigned max_debug_depth = MaxDebugDepth; static constexpr unsigned max_debug_depth = MaxDebugDepth;
typedef Return return_t; typedef Return return_t;
template <typename T, typename F> template <typename T, typename F>

View File

@ -151,9 +151,8 @@ struct hb_subset_layout_context_t :
}; };
struct hb_collect_variation_indices_context_t : struct hb_collect_variation_indices_context_t :
hb_dispatch_context_t<hb_collect_variation_indices_context_t, hb_empty_t, 0> hb_dispatch_context_t<hb_collect_variation_indices_context_t>
{ {
const char *get_name () { return "CLOSURE_LAYOUT_VARIATION_IDXES"; }
template <typename T> template <typename T>
return_t dispatch (const T &obj) { obj.collect_variation_indices (this); return hb_empty_t (); } return_t dispatch (const T &obj) { obj.collect_variation_indices (this); return hb_empty_t (); }
static return_t default_return_value () { return hb_empty_t (); } static return_t default_return_value () { return hb_empty_t (); }
@ -161,15 +160,13 @@ struct hb_collect_variation_indices_context_t :
hb_set_t *layout_variation_indices; hb_set_t *layout_variation_indices;
const hb_set_t *glyph_set; const hb_set_t *glyph_set;
const hb_map_t *gpos_lookups; const hb_map_t *gpos_lookups;
unsigned int debug_depth;
hb_collect_variation_indices_context_t (hb_set_t *layout_variation_indices_, hb_collect_variation_indices_context_t (hb_set_t *layout_variation_indices_,
const hb_set_t *glyph_set_, const hb_set_t *glyph_set_,
const hb_map_t *gpos_lookups_) : const hb_map_t *gpos_lookups_) :
layout_variation_indices (layout_variation_indices_), layout_variation_indices (layout_variation_indices_),
glyph_set (glyph_set_), glyph_set (glyph_set_),
gpos_lookups (gpos_lookups_), gpos_lookups (gpos_lookups_) {}
debug_depth (0) {}
}; };
template<typename OutputArray> template<typename OutputArray>

View File

@ -556,6 +556,20 @@ struct AlternateSet
return_trace (true); 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, template <typename Iterator,
hb_requires (hb_is_source_of (Iterator, hb_codepoint_t))> hb_requires (hb_is_source_of (Iterator, hb_codepoint_t))>
bool serialize (hb_serialize_context_t *c, bool serialize (hb_serialize_context_t *c,
@ -628,6 +642,14 @@ struct AlternateSubstFormat1
bool would_apply (hb_would_apply_context_t *c) const bool would_apply (hb_would_apply_context_t *c) const
{ return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; } { 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 bool apply (hb_ot_apply_context_t *c) const
{ {
TRACE_APPLY (this); TRACE_APPLY (this);

View File

@ -42,26 +42,22 @@ namespace OT {
struct hb_intersects_context_t : struct hb_intersects_context_t :
hb_dispatch_context_t<hb_intersects_context_t, bool, 0> hb_dispatch_context_t<hb_intersects_context_t, bool>
{ {
const char *get_name () { return "INTERSECTS"; }
template <typename T> template <typename T>
return_t dispatch (const T &obj) { return obj.intersects (this->glyphs); } return_t dispatch (const T &obj) { return obj.intersects (this->glyphs); }
static return_t default_return_value () { return false; } static return_t default_return_value () { return false; }
bool stop_sublookup_iteration (return_t r) const { return r; } bool stop_sublookup_iteration (return_t r) const { return r; }
const hb_set_t *glyphs; const hb_set_t *glyphs;
unsigned int debug_depth;
hb_intersects_context_t (const hb_set_t *glyphs_) : hb_intersects_context_t (const hb_set_t *glyphs_) :
glyphs (glyphs_), glyphs (glyphs_) {}
debug_depth (0) {}
}; };
struct hb_closure_context_t : struct hb_closure_context_t :
hb_dispatch_context_t<hb_closure_context_t, hb_empty_t, 0> hb_dispatch_context_t<hb_closure_context_t>
{ {
const char *get_name () { return "CLOSURE"; }
typedef return_t (*recurse_func_t) (hb_closure_context_t *c, unsigned int lookup_index); typedef return_t (*recurse_func_t) (hb_closure_context_t *c, unsigned int lookup_index);
template <typename T> template <typename T>
return_t dispatch (const T &obj) { obj.closure (this); return hb_empty_t (); } return_t dispatch (const T &obj) { obj.closure (this); return hb_empty_t (); }
@ -102,7 +98,6 @@ struct hb_closure_context_t :
hb_set_t output[1]; hb_set_t output[1];
recurse_func_t recurse_func; recurse_func_t recurse_func;
unsigned int nesting_level_left; unsigned int nesting_level_left;
unsigned int debug_depth;
hb_closure_context_t (hb_face_t *face_, hb_closure_context_t (hb_face_t *face_,
hb_set_t *glyphs_, hb_set_t *glyphs_,
@ -112,7 +107,6 @@ struct hb_closure_context_t :
glyphs (glyphs_), glyphs (glyphs_),
recurse_func (nullptr), recurse_func (nullptr),
nesting_level_left (nesting_level_left_), nesting_level_left (nesting_level_left_),
debug_depth (0),
done_lookups (done_lookups_), done_lookups (done_lookups_),
lookup_count (0) lookup_count (0)
{} {}
@ -134,9 +128,8 @@ struct hb_closure_context_t :
}; };
struct hb_closure_lookups_context_t : struct hb_closure_lookups_context_t :
hb_dispatch_context_t<hb_closure_lookups_context_t, hb_empty_t, 0> hb_dispatch_context_t<hb_closure_lookups_context_t>
{ {
const char *get_name () { return "CLOSURE_LOOKUPS"; }
typedef return_t (*recurse_func_t) (hb_closure_lookups_context_t *c, unsigned lookup_index); typedef return_t (*recurse_func_t) (hb_closure_lookups_context_t *c, unsigned lookup_index);
template <typename T> template <typename T>
return_t dispatch (const T &obj) { obj.closure_lookups (this); return hb_empty_t (); } return_t dispatch (const T &obj) { obj.closure_lookups (this); return hb_empty_t (); }
@ -177,7 +170,6 @@ struct hb_closure_lookups_context_t :
const hb_set_t *glyphs; const hb_set_t *glyphs;
recurse_func_t recurse_func; recurse_func_t recurse_func;
unsigned int nesting_level_left; unsigned int nesting_level_left;
unsigned int debug_depth;
hb_closure_lookups_context_t (hb_face_t *face_, hb_closure_lookups_context_t (hb_face_t *face_,
const hb_set_t *glyphs_, const hb_set_t *glyphs_,
@ -188,7 +180,6 @@ struct hb_closure_lookups_context_t :
glyphs (glyphs_), glyphs (glyphs_),
recurse_func (nullptr), recurse_func (nullptr),
nesting_level_left (nesting_level_left_), nesting_level_left (nesting_level_left_),
debug_depth (0),
visited_lookups (visited_lookups_), visited_lookups (visited_lookups_),
inactive_lookups (inactive_lookups_), inactive_lookups (inactive_lookups_),
lookup_count (0) {} lookup_count (0) {}
@ -202,9 +193,8 @@ struct hb_closure_lookups_context_t :
}; };
struct hb_would_apply_context_t : struct hb_would_apply_context_t :
hb_dispatch_context_t<hb_would_apply_context_t, bool, 0> hb_dispatch_context_t<hb_would_apply_context_t, bool>
{ {
const char *get_name () { return "WOULD_APPLY"; }
template <typename T> template <typename T>
return_t dispatch (const T &obj) { return obj.would_apply (this); } return_t dispatch (const T &obj) { return obj.would_apply (this); }
static return_t default_return_value () { return false; } static return_t default_return_value () { return false; }
@ -214,7 +204,6 @@ struct hb_would_apply_context_t :
const hb_codepoint_t *glyphs; const hb_codepoint_t *glyphs;
unsigned int len; unsigned int len;
bool zero_context; bool zero_context;
unsigned int debug_depth;
hb_would_apply_context_t (hb_face_t *face_, hb_would_apply_context_t (hb_face_t *face_,
const hb_codepoint_t *glyphs_, const hb_codepoint_t *glyphs_,
@ -223,15 +212,12 @@ struct hb_would_apply_context_t :
face (face_), face (face_),
glyphs (glyphs_), glyphs (glyphs_),
len (len_), len (len_),
zero_context (zero_context_), zero_context (zero_context_) {}
debug_depth (0) {}
}; };
struct hb_collect_glyphs_context_t : struct hb_collect_glyphs_context_t :
hb_dispatch_context_t<hb_collect_glyphs_context_t, hb_empty_t, 0> hb_dispatch_context_t<hb_collect_glyphs_context_t>
{ {
const char *get_name () { return "COLLECT_GLYPHS"; }
typedef return_t (*recurse_func_t) (hb_collect_glyphs_context_t *c, unsigned int lookup_index); typedef return_t (*recurse_func_t) (hb_collect_glyphs_context_t *c, unsigned int lookup_index);
template <typename T> template <typename T>
return_t dispatch (const T &obj) { obj.collect_glyphs (this); return hb_empty_t (); } return_t dispatch (const T &obj) { obj.collect_glyphs (this); return hb_empty_t (); }
@ -282,7 +268,6 @@ struct hb_collect_glyphs_context_t :
recurse_func_t recurse_func; recurse_func_t recurse_func;
hb_set_t *recursed_lookups; hb_set_t *recursed_lookups;
unsigned int nesting_level_left; unsigned int nesting_level_left;
unsigned int debug_depth;
hb_collect_glyphs_context_t (hb_face_t *face_, hb_collect_glyphs_context_t (hb_face_t *face_,
hb_set_t *glyphs_before, /* OUT. May be NULL */ hb_set_t *glyphs_before, /* OUT. May be NULL */
@ -297,8 +282,7 @@ struct hb_collect_glyphs_context_t :
output (glyphs_output ? glyphs_output : hb_set_get_empty ()), output (glyphs_output ? glyphs_output : hb_set_get_empty ()),
recurse_func (nullptr), recurse_func (nullptr),
recursed_lookups (hb_set_create ()), recursed_lookups (hb_set_create ()),
nesting_level_left (nesting_level_left_), nesting_level_left (nesting_level_left_) {}
debug_depth (0) {}
~hb_collect_glyphs_context_t () { hb_set_destroy (recursed_lookups); } ~hb_collect_glyphs_context_t () { hb_set_destroy (recursed_lookups); }
void set_recurse_func (recurse_func_t func) { recurse_func = func; } void set_recurse_func (recurse_func_t func) { recurse_func = func; }
@ -308,10 +292,9 @@ struct hb_collect_glyphs_context_t :
template <typename set_t> template <typename set_t>
struct hb_collect_coverage_context_t : struct hb_collect_coverage_context_t :
hb_dispatch_context_t<hb_collect_coverage_context_t<set_t>, const Coverage &, HB_DEBUG_GET_COVERAGE> hb_dispatch_context_t<hb_collect_coverage_context_t<set_t>, const Coverage &>
{ {
const char *get_name () { return "GET_COVERAGE"; } typedef const Coverage &return_t; // Stoopid that we have to dupe this here.
typedef const Coverage &return_t;
template <typename T> template <typename T>
return_t dispatch (const T &obj) { return obj.get_coverage (); } return_t dispatch (const T &obj) { return obj.get_coverage (); }
static return_t default_return_value () { return Null (Coverage); } static return_t default_return_value () { return Null (Coverage); }
@ -322,11 +305,9 @@ struct hb_collect_coverage_context_t :
} }
hb_collect_coverage_context_t (set_t *set_) : hb_collect_coverage_context_t (set_t *set_) :
set (set_), set (set_) {}
debug_depth (0) {}
set_t *set; set_t *set;
unsigned int debug_depth;
}; };
@ -701,7 +682,7 @@ struct hb_ot_apply_context_t :
struct hb_get_subtables_context_t : struct hb_get_subtables_context_t :
hb_dispatch_context_t<hb_get_subtables_context_t, hb_empty_t, HB_DEBUG_APPLY> hb_dispatch_context_t<hb_get_subtables_context_t>
{ {
template <typename Type> template <typename Type>
static inline bool apply_to (const void *obj, OT::hb_ot_apply_context_t *c) static inline bool apply_to (const void *obj, OT::hb_ot_apply_context_t *c)
@ -737,7 +718,6 @@ struct hb_get_subtables_context_t :
typedef hb_vector_t<hb_applicable_t> array_t; typedef hb_vector_t<hb_applicable_t> array_t;
/* Dispatch interface. */ /* Dispatch interface. */
const char *get_name () { return "GET_SUBTABLES"; }
template <typename T> template <typename T>
return_t dispatch (const T &obj) return_t dispatch (const T &obj)
{ {

View File

@ -1362,7 +1362,6 @@ hb_ot_layout_lookup_would_substitute (hb_face_t *face,
OT::hb_would_apply_context_t c (face, glyphs, glyphs_length, (bool) zero_context); OT::hb_would_apply_context_t c (face, glyphs, glyphs_length, (bool) zero_context);
const OT::SubstLookup& l = face->table.GSUB->table->get_lookup (lookup_index); const OT::SubstLookup& l = face->table.GSUB->table->get_lookup (lookup_index);
return l.would_apply (&c, &face->table.GSUB->accels[lookup_index]); return l.would_apply (&c, &face->table.GSUB->accels[lookup_index]);
} }
@ -1969,4 +1968,62 @@ hb_ot_layout_get_baseline (hb_font_t *font,
return result; return result;
} }
#endif #endif
struct hb_get_glyph_alternates_dispatch_t :
hb_dispatch_context_t<hb_get_glyph_alternates_dispatch_t, unsigned>
{
static return_t default_return_value () { return 0; }
bool stop_sublookup_iteration (return_t r) const { return r; }
hb_face_t *face;
hb_get_glyph_alternates_dispatch_t (hb_face_t *face) :
face (face) {}
private:
template <typename T, typename ...Ts> auto
_dispatch (const T &obj, hb_priority<1>, Ts&&... ds) HB_AUTO_RETURN
( obj.get_glyph_alternates (hb_forward<Ts> (ds)...) )
template <typename T, typename ...Ts> auto
_dispatch (const T &obj, hb_priority<0>, Ts&&... ds) HB_AUTO_RETURN
( default_return_value () )
public:
template <typename T, typename ...Ts> auto
dispatch (const T &obj, Ts&&... ds) HB_AUTO_RETURN
( _dispatch (obj, hb_prioritize, hb_forward<Ts> (ds)...) )
};
/**
* hb_ot_layout_lookup_get_glyph_alternates:
* @face: a face.
* @lookup_index: index of the feature lookup to query.
* @glyph: a glyph id.
* @start_offset: starting offset.
* @alternate_count: (inout) (allow-none): Input = the maximum number of alternate glyphs to return;
* Output = the actual number of alternate glyphs returned (may be zero).
* @alternate_glyphs: (out caller-allocates) (array length=alternate_count): A glyphs buffer.
* Alternate glyphs associated with the glyph id.
*
* Fetches alternates of a glyph from a given GSUB lookup index.
*
* Return value: total number of alternates found in the specific lookup index for the given glyph id.
*
* Since: REPLACEME
**/
HB_EXTERN unsigned
hb_ot_layout_lookup_get_glyph_alternates (hb_face_t *face,
unsigned lookup_index,
hb_codepoint_t glyph,
unsigned start_offset,
unsigned *alternate_count /* IN/OUT. May be NULL. */,
hb_codepoint_t *alternate_glyphs /* OUT. May be NULL. */)
{
hb_get_glyph_alternates_dispatch_t c (face);
const OT::SubstLookup &lookup = face->table.GSUB->table->get_lookup (lookup_index);
auto ret = lookup.dispatch (&c, glyph, start_offset, alternate_count, alternate_glyphs);
if (!ret && alternate_count) *alternate_count = 0;
return ret;
}
#endif #endif

View File

@ -323,6 +323,14 @@ hb_ot_layout_feature_with_variations_get_lookups (hb_face_t *face,
HB_EXTERN hb_bool_t HB_EXTERN hb_bool_t
hb_ot_layout_has_substitution (hb_face_t *face); hb_ot_layout_has_substitution (hb_face_t *face);
HB_EXTERN unsigned
hb_ot_layout_lookup_get_glyph_alternates (hb_face_t *face,
unsigned lookup_index,
hb_codepoint_t glyph,
unsigned start_offset,
unsigned *alternate_count /* IN/OUT */,
hb_codepoint_t *alternate_glyphs /* OUT */);
HB_EXTERN hb_bool_t HB_EXTERN hb_bool_t
hb_ot_layout_lookup_would_substitute (hb_face_t *face, hb_ot_layout_lookup_would_substitute (hb_face_t *face,
unsigned int lookup_index, unsigned int lookup_index,
@ -449,7 +457,6 @@ hb_ot_layout_get_baseline (hb_font_t *font,
hb_tag_t language_tag, hb_tag_t language_tag,
hb_position_t *coord /* OUT. May be NULL. */); hb_position_t *coord /* OUT. May be NULL. */);
HB_END_DECLS HB_END_DECLS
#endif /* HB_OT_LAYOUT_H */ #endif /* HB_OT_LAYOUT_H */

View File

@ -40,6 +40,7 @@ TEST_PROGS = \
test-font \ test-font \
test-map \ test-map \
test-object \ test-object \
test-ot-alternates \
test-ot-color \ test-ot-color \
test-ot-face \ test-ot-face \
test-ot-glyphname \ test-ot-glyphname \

View File

@ -16,6 +16,7 @@ tests = [
'test-font.c', 'test-font.c',
'test-map.c', 'test-map.c',
'test-object.c', 'test-object.c',
'test-ot-alternates.c',
'test-ot-color.c', 'test-ot-color.c',
'test-ot-face.c', 'test-ot-face.c',
'test-ot-glyphname.c', 'test-ot-glyphname.c',

View File

@ -0,0 +1,53 @@
/*
* Copyright © 2020 Ebrahim Byagowi
*
* This is part of HarfBuzz, a text shaping library.
*
* 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.
*/
#include "hb-test.h"
#include <hb.h>
#include <hb-ot.h>
static void
test_ot_layout_lookup_get_glyph_alternates (void)
{
hb_face_t *face = hb_test_open_font_file ("fonts/SourceSansPro-Regular.otf");
hb_codepoint_t alternates[3];
unsigned alternates_count = 3;
g_assert_cmpuint (7, ==, hb_ot_layout_lookup_get_glyph_alternates (face, 1, 1091, 2, &alternates_count, alternates));
g_assert_cmpuint (3, ==, alternates_count);
g_assert_cmpuint (1606, ==, alternates[0]);
g_assert_cmpuint (1578, ==, alternates[1]);
g_assert_cmpuint (1592, ==, alternates[2]);
hb_face_destroy (face);
}
int
main (int argc, char **argv)
{
hb_test_init (&argc, &argv);
hb_test_add (test_ot_layout_lookup_get_glyph_alternates);
return hb_test_run ();
}