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

Reply via email to