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_required_feature
hb_ot_layout_lookup_collect_glyphs
hb_ot_layout_lookup_get_glyph_alternates
hb_ot_layout_lookup_substitute_closure
hb_ot_layout_lookups_substitute_closure
hb_ot_layout_lookup_would_substitute

View File

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

View File

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

View File

@ -151,9 +151,8 @@ struct hb_subset_layout_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>
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 (); }
@ -161,15 +160,13 @@ struct hb_collect_variation_indices_context_t :
hb_set_t *layout_variation_indices;
const hb_set_t *glyph_set;
const hb_map_t *gpos_lookups;
unsigned int debug_depth;
hb_collect_variation_indices_context_t (hb_set_t *layout_variation_indices_,
const hb_set_t *glyph_set_,
const hb_map_t *gpos_lookups_) :
layout_variation_indices (layout_variation_indices_),
glyph_set (glyph_set_),
gpos_lookups (gpos_lookups_),
debug_depth (0) {}
gpos_lookups (gpos_lookups_) {}
};
template<typename OutputArray>

View File

@ -556,6 +556,20 @@ struct AlternateSet
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,
@ -628,6 +642,14 @@ struct AlternateSubstFormat1
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);

View File

@ -42,26 +42,22 @@ namespace OT {
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>
return_t dispatch (const T &obj) { return obj.intersects (this->glyphs); }
static return_t default_return_value () { return false; }
bool stop_sublookup_iteration (return_t r) const { return r; }
const hb_set_t *glyphs;
unsigned int debug_depth;
hb_intersects_context_t (const hb_set_t *glyphs_) :
glyphs (glyphs_),
debug_depth (0) {}
glyphs (glyphs_) {}
};
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);
template <typename 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];
recurse_func_t recurse_func;
unsigned int nesting_level_left;
unsigned int debug_depth;
hb_closure_context_t (hb_face_t *face_,
hb_set_t *glyphs_,
@ -112,7 +107,6 @@ struct hb_closure_context_t :
glyphs (glyphs_),
recurse_func (nullptr),
nesting_level_left (nesting_level_left_),
debug_depth (0),
done_lookups (done_lookups_),
lookup_count (0)
{}
@ -134,9 +128,8 @@ struct hb_closure_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);
template <typename 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;
recurse_func_t recurse_func;
unsigned int nesting_level_left;
unsigned int debug_depth;
hb_closure_lookups_context_t (hb_face_t *face_,
const hb_set_t *glyphs_,
@ -188,7 +180,6 @@ struct hb_closure_lookups_context_t :
glyphs (glyphs_),
recurse_func (nullptr),
nesting_level_left (nesting_level_left_),
debug_depth (0),
visited_lookups (visited_lookups_),
inactive_lookups (inactive_lookups_),
lookup_count (0) {}
@ -202,9 +193,8 @@ struct hb_closure_lookups_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>
return_t dispatch (const T &obj) { return obj.would_apply (this); }
static return_t default_return_value () { return false; }
@ -214,7 +204,6 @@ struct hb_would_apply_context_t :
const hb_codepoint_t *glyphs;
unsigned int len;
bool zero_context;
unsigned int debug_depth;
hb_would_apply_context_t (hb_face_t *face_,
const hb_codepoint_t *glyphs_,
@ -223,15 +212,12 @@ struct hb_would_apply_context_t :
face (face_),
glyphs (glyphs_),
len (len_),
zero_context (zero_context_),
debug_depth (0) {}
zero_context (zero_context_) {}
};
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);
template <typename 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;
hb_set_t *recursed_lookups;
unsigned int nesting_level_left;
unsigned int debug_depth;
hb_collect_glyphs_context_t (hb_face_t *face_,
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 ()),
recurse_func (nullptr),
recursed_lookups (hb_set_create ()),
nesting_level_left (nesting_level_left_),
debug_depth (0) {}
nesting_level_left (nesting_level_left_) {}
~hb_collect_glyphs_context_t () { hb_set_destroy (recursed_lookups); }
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>
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;
typedef const Coverage &return_t; // Stoopid that we have to dupe this here.
template <typename T>
return_t dispatch (const T &obj) { return obj.get_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_) :
set (set_),
debug_depth (0) {}
set (set_) {}
set_t *set;
unsigned int debug_depth;
};
@ -701,7 +682,7 @@ struct hb_ot_apply_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>
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;
/* Dispatch interface. */
const char *get_name () { return "GET_SUBTABLES"; }
template <typename T>
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);
const OT::SubstLookup& l = face->table.GSUB->table->get_lookup (lookup_index);
return l.would_apply (&c, &face->table.GSUB->accels[lookup_index]);
}
@ -1380,7 +1379,7 @@ void
hb_ot_layout_substitute_start (hb_font_t *font,
hb_buffer_t *buffer)
{
_hb_ot_layout_set_glyph_props (font, buffer);
_hb_ot_layout_set_glyph_props (font, buffer);
}
void
@ -1969,4 +1968,62 @@ hb_ot_layout_get_baseline (hb_font_t *font,
return result;
}
#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

View File

@ -323,6 +323,14 @@ hb_ot_layout_feature_with_variations_get_lookups (hb_face_t *face,
HB_EXTERN hb_bool_t
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_ot_layout_lookup_would_substitute (hb_face_t *face,
unsigned int lookup_index,
@ -449,7 +457,6 @@ hb_ot_layout_get_baseline (hb_font_t *font,
hb_tag_t language_tag,
hb_position_t *coord /* OUT. May be NULL. */);
HB_END_DECLS
#endif /* HB_OT_LAYOUT_H */

View File

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

View File

@ -16,6 +16,7 @@ tests = [
'test-font.c',
'test-map.c',
'test-object.c',
'test-ot-alternates.c',
'test-ot-color.c',
'test-ot-face.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 ();
}