docs/harfbuzz-sections.txt | 3 + src/hb-blob.cc | 25 +++++++++++++ src/hb-blob.h | 3 + src/hb-set-private.hh | 81 ++++++++++++++++++++++++++++++++++++++++++-- src/hb-set.cc | 49 ++++++++++++++++++++++++++ src/hb-set.h | 19 ++++++++-- src/hb-subset-input.cc | 6 +-- src/hb-subset.h | 2 - test/api/test-set.c | 53 +++++++++++++++++++++++++++- test/api/test-subset-glyf.c | 3 + test/api/test-subset.c | 7 ++- util/hb-subset.cc | 2 - 12 files changed, 235 insertions(+), 18 deletions(-)
New commits: commit 694eaf636713b8d0bbe13f38c2553b1a2f3d2d3a Author: Behdad Esfahbod <beh...@behdad.org> Date: Wed Feb 14 01:00:10 2018 -0800 [set] Add backwards iterator New API: - hb_set_previous() - hb_set_previous_range() diff --git a/docs/harfbuzz-sections.txt b/docs/harfbuzz-sections.txt index 5df33a81..91faa0b7 100644 --- a/docs/harfbuzz-sections.txt +++ b/docs/harfbuzz-sections.txt @@ -528,7 +528,9 @@ hb_set_intersect hb_set_is_empty hb_set_is_equal hb_set_next +hb_set_previous hb_set_next_range +hb_set_previous_range hb_set_reference hb_set_set hb_set_set_user_data diff --git a/src/hb-set-private.hh b/src/hb-set-private.hh index 45963487..7282b079 100644 --- a/src/hb-set-private.hh +++ b/src/hb-set-private.hh @@ -125,6 +125,33 @@ struct hb_set_t *codepoint = i * ELT_BITS + j; return true; } + inline bool previous (hb_codepoint_t *codepoint) const + { + unsigned int m = (*codepoint - 1) & MASK; + if (m == MASK) + { + *codepoint = INVALID; + return false; + } + unsigned int i = m / ELT_BITS; + unsigned int j = m & ELT_MASK; + + for (; (int) j >= 0; j--) + if (v[i] & (elt_t (1) << j)) + goto found; + for (i--; (int) i >= 0; i--) + if (v[i]) + for (j = ELT_BITS - 1; (int) j >= 0; j--) + if (v[i] & (elt_t (1) << j)) + goto found; + + *codepoint = INVALID; + return false; + + found: + *codepoint = i * ELT_BITS + j; + return true; + } inline hb_codepoint_t get_min (void) const { for (unsigned int i = 0; i < len (); i++) @@ -476,7 +503,7 @@ struct hb_set_t if (pages[page_map[i].index].next (codepoint)) { *codepoint += page_map[i].major * page_t::PAGE_BITS; - return true; + return true; } i++; } @@ -492,6 +519,37 @@ struct hb_set_t *codepoint = INVALID; return false; } + inline bool previous (hb_codepoint_t *codepoint) const + { + if (unlikely (*codepoint == INVALID)) { + *codepoint = get_max (); + return *codepoint != INVALID; + } + + page_map_t map = {get_major (*codepoint), 0}; + unsigned int i; + page_map.bfind (map, &i); + if (i < page_map.len && page_map[i].major == map.major) + { + if (pages[page_map[i].index].previous (codepoint)) + { + *codepoint += page_map[i].major * page_t::PAGE_BITS; + return true; + } + } + i--; + for (; (int) i >= 0; i--) + { + hb_codepoint_t m = pages[page_map[i].index].get_max (); + if (m != INVALID) + { + *codepoint = page_map[i].major * page_t::PAGE_BITS + m; + return true; + } + } + *codepoint = INVALID; + return false; + } inline bool next_range (hb_codepoint_t *first, hb_codepoint_t *last) const { hb_codepoint_t i; @@ -503,12 +561,31 @@ struct hb_set_t return false; } + /* TODO Speed up. */ *last = *first = i; while (next (&i) && i == *last + 1) (*last)++; return true; } + inline bool previous_range (hb_codepoint_t *first, hb_codepoint_t *last) const + { + hb_codepoint_t i; + + i = *first; + if (!previous (&i)) + { + *last = *first = INVALID; + return false; + } + + /* TODO Speed up. */ + *last = *first = i; + while (previous (&i) && i == *first - 1) + (*first)--; + + return true; + } inline unsigned int get_population (void) const { diff --git a/src/hb-set.cc b/src/hb-set.cc index f3b864c1..07cf9d09 100644 --- a/src/hb-set.cc +++ b/src/hb-set.cc @@ -437,7 +437,9 @@ hb_set_get_max (const hb_set_t *set) * @set: a set. * @codepoint: (inout): * - * + * Gets the next number in @set that is greater than current value of @codepoint. + * + * Set @codepoint to %HB_SET_VALUE_INVALID to get started. * * Return value: whether there was a next value. * @@ -451,6 +453,26 @@ hb_set_next (const hb_set_t *set, } /** + * hb_set_previous: + * @set: a set. + * @codepoint: (inout): + * + * Gets the previous number in @set that is slower than current value of @codepoint. + * + * Set @codepoint to %HB_SET_VALUE_INVALID to get started. + * + * Return value: whether there was a previous value. + * + * Since: 1.8.0 + **/ +hb_bool_t +hb_set_previous (const hb_set_t *set, + hb_codepoint_t *codepoint) +{ + return set->previous (codepoint); +} + +/** * hb_set_next_range: * @set: a set. * @first: (out): output first codepoint in the range. @@ -459,6 +481,8 @@ hb_set_next (const hb_set_t *set, * Gets the next consecutive range of numbers in @set that * are greater than current value of @last. * + * Set @last to %HB_SET_VALUE_INVALID to get started. + * * Return value: whether there was a next range. * * Since: 0.9.7 @@ -470,3 +494,26 @@ hb_set_next_range (const hb_set_t *set, { return set->next_range (first, last); } + +/** + * hb_set_previous_range: + * @set: a set. + * @first: (inout): input current first and output first codepoint in the range. + * @last: (out): output last codepoint in the range. + * + * Gets the previous consecutive range of numbers in @set that + * are greater than current value of @last. + * + * Set @first to %HB_SET_VALUE_INVALID to get started. + * + * Return value: whether there was a previous range. + * + * Since: 1.8.0 + **/ +hb_bool_t +hb_set_previous_range (const hb_set_t *set, + hb_codepoint_t *first, + hb_codepoint_t *last) +{ + return set->previous_range (first, last); +} diff --git a/src/hb-set.h b/src/hb-set.h index 2ce40607..b0f82f82 100644 --- a/src/hb-set.h +++ b/src/hb-set.h @@ -129,25 +129,36 @@ hb_set_symmetric_difference (hb_set_t *set, HB_EXTERN unsigned int hb_set_get_population (const hb_set_t *set); -/* Returns -1 if set empty. */ +/* Returns HB_SET_VALUE_INVALID if set empty. */ HB_EXTERN hb_codepoint_t hb_set_get_min (const hb_set_t *set); -/* Returns -1 if set empty. */ +/* Returns HB_SET_VALUE_INVALID if set empty. */ HB_EXTERN hb_codepoint_t hb_set_get_max (const hb_set_t *set); -/* Pass -1 in to get started. */ +/* Pass HB_SET_VALUE_INVALID in to get started. */ HB_EXTERN hb_bool_t hb_set_next (const hb_set_t *set, hb_codepoint_t *codepoint); -/* Pass -1 for first and last to get started. */ +/* Pass HB_SET_VALUE_INVALID in to get started. */ +HB_EXTERN hb_bool_t +hb_set_previous (const hb_set_t *set, + hb_codepoint_t *codepoint); + +/* Pass HB_SET_VALUE_INVALID for first and last to get started. */ HB_EXTERN hb_bool_t hb_set_next_range (const hb_set_t *set, hb_codepoint_t *first, hb_codepoint_t *last); +/* Pass HB_SET_VALUE_INVALID for first and last to get started. */ +HB_EXTERN hb_bool_t +hb_set_previous_range (const hb_set_t *set, + hb_codepoint_t *first, + hb_codepoint_t *last); + HB_END_DECLS diff --git a/test/api/test-set.c b/test/api/test-set.c index bbea2cf5..60e11d98 100644 --- a/test/api/test-set.c +++ b/test/api/test-set.c @@ -32,25 +32,33 @@ static void test_empty (hb_set_t *s) { - hb_codepoint_t next = HB_SET_VALUE_INVALID; + hb_codepoint_t next; g_assert_cmpint (hb_set_get_population (s), ==, 0); g_assert_cmpint (hb_set_get_min (s), ==, HB_SET_VALUE_INVALID); g_assert_cmpint (hb_set_get_max (s), ==, HB_SET_VALUE_INVALID); g_assert (!hb_set_has (s, 13)); + next = 53043; g_assert (!hb_set_next (s, &next)); g_assert_cmpint (next, ==, HB_SET_VALUE_INVALID); + next = 07734; + g_assert (!hb_set_previous (s, &next)); + g_assert_cmpint (next, ==, HB_SET_VALUE_INVALID); g_assert (hb_set_is_empty (s)); } static void test_not_empty (hb_set_t *s) { - hb_codepoint_t next = HB_SET_VALUE_INVALID; + hb_codepoint_t next; g_assert_cmpint (hb_set_get_population (s), !=, 0); g_assert_cmpint (hb_set_get_min (s), !=, HB_SET_VALUE_INVALID); g_assert_cmpint (hb_set_get_max (s), !=, HB_SET_VALUE_INVALID); + next = HB_SET_VALUE_INVALID; g_assert (hb_set_next (s, &next)); g_assert_cmpint (next, !=, HB_SET_VALUE_INVALID); + next = HB_SET_VALUE_INVALID; + g_assert (hb_set_previous (s, &next)); + g_assert_cmpint (next, !=, HB_SET_VALUE_INVALID); } static void @@ -271,6 +279,27 @@ test_set_iter (void) g_assert (!hb_set_next (s, &next)); g_assert_cmpint (next, ==, HB_SET_VALUE_INVALID); + next = HB_SET_VALUE_INVALID; + g_assert (hb_set_previous (s, &next)); + g_assert_cmpint (next, ==, 20005); + g_assert (hb_set_previous (s, &next)); + g_assert_cmpint (next, ==, 1200); + g_assert (hb_set_previous (s, &next)); + g_assert_cmpint (next, ==, 1100); + g_assert (hb_set_previous (s, &next)); + g_assert_cmpint (next, ==, 15); + g_assert (hb_set_previous (s, &next)); + g_assert (hb_set_previous (s, &next)); + g_assert_cmpint (next, ==, 13); + g_assert (hb_set_previous (s, &next)); + g_assert (hb_set_previous (s, &next)); + g_assert (hb_set_previous (s, &next)); + g_assert_cmpint (next, ==, 10); + g_assert (hb_set_previous (s, &next)); + g_assert_cmpint (next, ==, 6); + g_assert (!hb_set_previous (s, &next)); + g_assert_cmpint (next, ==, HB_SET_VALUE_INVALID); + first = last = HB_SET_VALUE_INVALID; g_assert (hb_set_next_range (s, &first, &last)); g_assert_cmpint (first, ==, 6); @@ -291,6 +320,26 @@ test_set_iter (void) g_assert_cmpint (first, ==, HB_SET_VALUE_INVALID); g_assert_cmpint (last, ==, HB_SET_VALUE_INVALID); + first = last = HB_SET_VALUE_INVALID; + g_assert (hb_set_previous_range (s, &first, &last)); + g_assert_cmpint (first, ==, 20005); + g_assert_cmpint (last, ==, 20005); + g_assert (hb_set_previous_range (s, &first, &last)); + g_assert_cmpint (first, ==, 1200); + g_assert_cmpint (last, ==, 1200); + g_assert (hb_set_previous_range (s, &first, &last)); + g_assert_cmpint (first, ==, 1100); + g_assert_cmpint (last, ==, 1100); + g_assert (hb_set_previous_range (s, &first, &last)); + g_assert_cmpint (first, ==, 10); + g_assert_cmpint (last, ==, 15); + g_assert (hb_set_previous_range (s, &first, &last)); + g_assert_cmpint (first, ==, 6); + g_assert_cmpint (last, ==, 6); + g_assert (!hb_set_previous_range (s, &first, &last)); + g_assert_cmpint (first, ==, HB_SET_VALUE_INVALID); + g_assert_cmpint (last, ==, HB_SET_VALUE_INVALID); + hb_set_destroy (s); } commit fe3bc524bd4f93bd67c13ed402720a13dd3484d3 Author: Behdad Esfahbod <beh...@behdad.org> Date: Tue Feb 13 23:51:45 2018 -0800 [set] Allow starting iteration from a non-member of the set diff --git a/src/hb-set-private.hh b/src/hb-set-private.hh index d71d4122..45963487 100644 --- a/src/hb-set-private.hh +++ b/src/hb-set-private.hh @@ -471,7 +471,7 @@ struct hb_set_t page_map_t map = {get_major (*codepoint), 0}; unsigned int i; page_map.bfind (map, &i); - if (i < page_map.len) + if (i < page_map.len && page_map[i].major == map.major) { if (pages[page_map[i].index].next (codepoint)) { commit a989f3edec5864d5de8b217aa595c962d8fc4b0a Author: Behdad Esfahbod <beh...@behdad.org> Date: Tue Feb 13 22:12:36 2018 -0800 Add hb_blob_copy_writable_or_fail() New API: - hb_blob_copy_writable_or_fail() diff --git a/docs/harfbuzz-sections.txt b/docs/harfbuzz-sections.txt index a9b4d53e..5df33a81 100644 --- a/docs/harfbuzz-sections.txt +++ b/docs/harfbuzz-sections.txt @@ -9,6 +9,7 @@ HB_EXTERN <FILE>hb-blob</FILE> hb_blob_create hb_blob_create_sub_blob +hb_blob_copy_writable_or_fail hb_blob_destroy hb_blob_get_data hb_blob_get_data_writable diff --git a/src/hb-blob.cc b/src/hb-blob.cc index 80460125..b5291f65 100644 --- a/src/hb-blob.cc +++ b/src/hb-blob.cc @@ -171,6 +171,31 @@ hb_blob_create_sub_blob (hb_blob_t *parent, } /** + * hb_blob_copy_writable_or_fail: + * @blob: A blob. + * + * Makes a writable copy of @blob. + * + * Return value: New blob, or nullptr if allocation failed. + * + * Since: 1.8.0 + **/ +hb_blob_t * +hb_blob_copy_writable_or_fail (hb_blob_t *blob) +{ + blob = hb_blob_create (blob->data, + blob->length, + HB_MEMORY_MODE_DUPLICATE, + nullptr, + nullptr); + + if (unlikely (blob == hb_blob_get_empty ())) + blob = nullptr; + + return blob; +} + +/** * hb_blob_get_empty: * * Returns the singleton empty blob. diff --git a/src/hb-blob.h b/src/hb-blob.h index 53682d3e..fd561f73 100644 --- a/src/hb-blob.h +++ b/src/hb-blob.h @@ -83,6 +83,9 @@ hb_blob_create_sub_blob (hb_blob_t *parent, unsigned int length); HB_EXTERN hb_blob_t * +hb_blob_copy_writable_or_fail (hb_blob_t *blob); + +HB_EXTERN hb_blob_t * hb_blob_get_empty (void); HB_EXTERN hb_blob_t * commit 9046e924421869bf167b52cd394e868796091f62 Author: Behdad Esfahbod <beh...@behdad.org> Date: Tue Feb 13 22:07:12 2018 -0800 [subset] Rename constructor to hb_subset_input_create_or_fail() To signify that unlike rest of library, returns nullptr on failure. diff --git a/src/hb-subset-input.cc b/src/hb-subset-input.cc index 75c01684..d41cff60 100644 --- a/src/hb-subset-input.cc +++ b/src/hb-subset-input.cc @@ -29,19 +29,17 @@ #include "hb-set-private.hh" /** - * hb_subset_input_create: + * hb_subset_input_create_or_fail: * * Return value: New subset input. * * Since: 1.8.0 **/ hb_subset_input_t * -hb_subset_input_create (void) +hb_subset_input_create_or_fail (void) { hb_subset_input_t *input = hb_object_create<hb_subset_input_t>(); - /* Unlike libharfbuzz, in this lib we return nullptr - * in case of allocation failure. */ if (unlikely (!input)) return nullptr; diff --git a/src/hb-subset.h b/src/hb-subset.h index 81e11fe6..de7759b2 100644 --- a/src/hb-subset.h +++ b/src/hb-subset.h @@ -54,7 +54,7 @@ hb_subset_profile_destroy (hb_subset_profile_t *profile); typedef struct hb_subset_input_t hb_subset_input_t; HB_EXTERN hb_subset_input_t * -hb_subset_input_create (void); +hb_subset_input_create_or_fail (void); HB_EXTERN hb_subset_input_t * hb_subset_input_reference (hb_subset_input_t *subset_input); diff --git a/test/api/test-subset-glyf.c b/test/api/test-subset-glyf.c index 014f2433..62af9399 100644 --- a/test/api/test-subset-glyf.c +++ b/test/api/test-subset-glyf.c @@ -95,9 +95,10 @@ test_subset_glyf (void) hb_blob_t *glyf_expected_blob; hb_blob_t *glyf_actual_blob; hb_subset_profile_t *profile = hb_subset_profile_create(); - hb_subset_input_t *input = hb_subset_input_create (); + hb_subset_input_t *input = hb_subset_input_create_or_fail (); hb_set_t *codepoints = hb_set_reference (hb_subset_input_unicode_set (input)); + g_assert (input); g_assert (face_abc); g_assert (face_ac); diff --git a/test/api/test-subset.c b/test/api/test-subset.c index 44eba158..68c00134 100644 --- a/test/api/test-subset.c +++ b/test/api/test-subset.c @@ -43,12 +43,15 @@ test_subset (void) hb_face_t *face = hb_face_create(font_blob, 0); hb_subset_profile_t *profile = hb_subset_profile_create(); - hb_subset_input_t *input = hb_subset_input_create (); + hb_subset_input_t *input = hb_subset_input_create_or_fail (); hb_face_t *out_face = hb_subset(face, profile, input); + hb_blob_t *output; + + g_assert (input); g_assert(out_face); g_assert(out_face != hb_face_get_empty ()); - hb_blob_t *output = hb_face_reference_blob (out_face); + output = hb_face_reference_blob (out_face); unsigned int output_length; const char *output_data = hb_blob_get_data(output, &output_length); diff --git a/util/hb-subset.cc b/util/hb-subset.cc index 16abd14d..ea657aff 100644 --- a/util/hb-subset.cc +++ b/util/hb-subset.cc @@ -43,7 +43,7 @@ struct subset_consumer_t const font_options_t *font_opts) { font = hb_font_reference (font_opts->get_font ()); - input = hb_subset_input_create (); + input = hb_subset_input_create_or_fail (); } void consume_line (const char *text, _______________________________________________ HarfBuzz mailing list HarfBuzz@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/harfbuzz