diff --git a/docs/harfbuzz-sections.txt b/docs/harfbuzz-sections.txt index 38b357dd1..ae3038ffa 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_alternates hb_ot_layout_lookup_substitute_closure hb_ot_layout_lookups_substitute_closure hb_ot_layout_lookup_would_substitute diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh index fdddca545..b7f5f6446 100644 --- a/src/hb-ot-layout-gsub-table.hh +++ b/src/hb-ot-layout-gsub-table.hh @@ -522,6 +522,8 @@ struct MultipleSubst struct AlternateSet { + friend struct AlternateSubstFormat1; + bool intersects (const hb_set_t *glyphs) const { return hb_any (alternates, glyphs); } @@ -628,6 +630,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; } + const ArrayOf &get_alternates (hb_codepoint_t gid) const + { + unsigned index = (this+coverage).get_coverage (gid); + if (index == NOT_COVERED) return Null (ArrayOf); + + return (this+alternateSet[index]).alternates; + } + bool apply (hb_ot_apply_context_t *c) const { TRACE_APPLY (this); @@ -715,6 +725,14 @@ struct AlternateSubst } } + const ArrayOf &get_alternates (hb_codepoint_t gid) const + { + switch (u.format) { + case 1: return u.format1.get_alternates (gid); + default:return Null (ArrayOf); + } + } + template typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { @@ -1463,6 +1481,18 @@ struct SubstLookup : Lookup substitute_glyphs_list)); } + const ArrayOf &get_alternates (hb_codepoint_t gid) const + { + if (get_type () != SubTable::Alternate) return Null (ArrayOf); + unsigned size = get_subtable_count (); + for (unsigned i = 0; i < size; ++i) + { + const ArrayOf &alternates = get_subtable (i).u.alternate.get_alternates (gid); + if (alternates.len) return alternates; + } + return Null (ArrayOf); + } + bool serialize_alternate (hb_serialize_context_t *c, uint32_t lookup_props, hb_sorted_array_t glyphs, diff --git a/src/hb-ot-layout.cc b/src/hb-ot-layout.cc index 48f4a9315..972d71647 100644 --- a/src/hb-ot-layout.cc +++ b/src/hb-ot-layout.cc @@ -1969,4 +1969,41 @@ hb_ot_layout_get_baseline (hb_font_t *font, return result; } #endif + +/** + * hb_ot_layout_lookup_get_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_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) +{ + const OT::SubstLookup &lookup = face->table.GSUB->table->get_lookup (lookup_index); + const OT::ArrayOf &alternates = lookup.get_alternates (glyph); + if (alternate_count) + { + + alternates.sub_array (start_offset, alternate_count) + | hb_sink (hb_array (alternate_glyphs, *alternate_count)) + ; + } + return alternates.len; +} + #endif diff --git a/src/hb-ot-layout.h b/src/hb-ot-layout.h index 363dea89c..fedf32e1e 100644 --- a/src/hb-ot-layout.h +++ b/src/hb-ot-layout.h @@ -449,6 +449,13 @@ hb_ot_layout_get_baseline (hb_font_t *font, hb_tag_t language_tag, hb_position_t *coord /* OUT. May be NULL. */); +HB_EXTERN unsigned +hb_ot_layout_lookup_get_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); HB_END_DECLS 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..f91acecc1 --- /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_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_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_alternates); + return hb_test_run (); +}