diff --git a/docs/harfbuzz-sections.txt b/docs/harfbuzz-sections.txt index 38b357dd1..fe9b89c05 100644 --- a/docs/harfbuzz-sections.txt +++ b/docs/harfbuzz-sections.txt @@ -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 diff --git a/src/hb-debug.hh b/src/hb-debug.hh index 5c13e5d1a..ec3a1ff21 100644 --- a/src/hb-debug.hh +++ b/src/hb-debug.hh @@ -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 diff --git a/src/hb-dispatch.hh b/src/hb-dispatch.hh index 1ce3fac93..327770a89 100644 --- a/src/hb-dispatch.hh +++ b/src/hb-dispatch.hh @@ -35,7 +35,7 @@ * Dispatch */ -template +template struct hb_dispatch_context_t { private: @@ -43,6 +43,8 @@ struct hb_dispatch_context_t const Context* thiz () const { return static_cast (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 diff --git a/src/hb-ot-layout-common.hh b/src/hb-ot-layout-common.hh index fdd1f31c7..132e9522b 100644 --- a/src/hb-ot-layout-common.hh +++ b/src/hb-ot-layout-common.hh @@ -151,9 +151,8 @@ struct hb_subset_layout_context_t : }; struct hb_collect_variation_indices_context_t : - hb_dispatch_context_t + hb_dispatch_context_t { - const char *get_name () { return "CLOSURE_LAYOUT_VARIATION_IDXES"; } template 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 diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh index fdddca545..4a9d38a5b 100644 --- a/src/hb-ot-layout-gsub-table.hh +++ b/src/hb-ot-layout-gsub-table.hh @@ -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 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); diff --git a/src/hb-ot-layout-gsubgpos.hh b/src/hb-ot-layout-gsubgpos.hh index 0026f83a5..e935a9505 100644 --- a/src/hb-ot-layout-gsubgpos.hh +++ b/src/hb-ot-layout-gsubgpos.hh @@ -42,26 +42,22 @@ namespace OT { struct hb_intersects_context_t : - hb_dispatch_context_t + hb_dispatch_context_t { - const char *get_name () { return "INTERSECTS"; } template 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_dispatch_context_t { - const char *get_name () { return "CLOSURE"; } typedef return_t (*recurse_func_t) (hb_closure_context_t *c, unsigned int lookup_index); template 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_dispatch_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 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_dispatch_context_t { - const char *get_name () { return "WOULD_APPLY"; } template 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_dispatch_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 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 struct hb_collect_coverage_context_t : - hb_dispatch_context_t, const Coverage &, HB_DEBUG_GET_COVERAGE> + hb_dispatch_context_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 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_dispatch_context_t { template 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 array_t; /* Dispatch interface. */ - const char *get_name () { return "GET_SUBTABLES"; } template return_t dispatch (const T &obj) { diff --git a/src/hb-ot-layout.cc b/src/hb-ot-layout.cc index 48f4a9315..b612c1e2f 100644 --- a/src/hb-ot-layout.cc +++ b/src/hb-ot-layout.cc @@ -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 +{ + 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 auto + _dispatch (const T &obj, hb_priority<1>, Ts&&... ds) HB_AUTO_RETURN + ( obj.get_glyph_alternates (hb_forward (ds)...) ) + template auto + _dispatch (const T &obj, hb_priority<0>, Ts&&... ds) HB_AUTO_RETURN + ( default_return_value () ) + public: + template auto + dispatch (const T &obj, Ts&&... ds) HB_AUTO_RETURN + ( _dispatch (obj, hb_prioritize, hb_forward (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 diff --git a/src/hb-ot-layout.h b/src/hb-ot-layout.h index 363dea89c..545d5f7fc 100644 --- a/src/hb-ot-layout.h +++ b/src/hb-ot-layout.h @@ -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 */ diff --git a/test/api/Makefile.am b/test/api/Makefile.am index 01e12c570..bf29d2200 100644 --- a/test/api/Makefile.am +++ b/test/api/Makefile.am @@ -40,6 +40,7 @@ TEST_PROGS = \ test-font \ test-map \ test-object \ + test-ot-alternates \ test-ot-color \ test-ot-face \ test-ot-glyphname \ diff --git a/test/api/meson.build b/test/api/meson.build index e824a6c6f..7c9862592 100644 --- a/test/api/meson.build +++ b/test/api/meson.build @@ -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', diff --git a/test/api/test-ot-alternates.c b/test/api/test-ot-alternates.c new file mode 100644 index 000000000..4db6b1558 --- /dev/null +++ b/test/api/test-ot-alternates.c @@ -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 +#include + +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 (); +}