Add function to compare two buffers
authorJonathan Kew <jfkthame@gmail.com>
Sat, 19 Jul 2014 22:09:09 +0000 (23:09 +0100)
committerBehdad Esfahbod <behdad@behdad.org>
Mon, 14 Aug 2017 18:44:12 +0000 (11:44 -0700)
Based on patch from Jonathan Kew.

Needs more cleaning up and documentation.

New API:
hb_buffer_diff_flags_t
hb_buffer_diff()

src/hb-buffer-private.hh
src/hb-buffer-serialize.cc
src/hb-buffer.cc
src/hb-buffer.h

index 25da222..37380b4 100644 (file)
@@ -50,6 +50,7 @@ ASSERT_STATIC (sizeof (hb_glyph_info_t) == sizeof (hb_glyph_position_t));
 
 HB_MARK_AS_FLAG_T (hb_buffer_flags_t);
 HB_MARK_AS_FLAG_T (hb_buffer_serialize_flags_t);
+HB_MARK_AS_FLAG_T (hb_buffer_diff_flags_t);
 
 enum hb_buffer_scratch_flags_t {
   HB_BUFFER_SCRATCH_FLAG_DEFAULT                       = 0x00000000u,
index f4a89ac..517d746 100644 (file)
@@ -153,8 +153,8 @@ _hb_buffer_serialize_glyphs_json (hb_buffer_t *buffer,
 
     if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS)
     {
-      if (info[i].mask &HB_GLYPH_FLAG_DEFINED)
-       p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"fl\":%u", info[i].mask &HB_GLYPH_FLAG_DEFINED));
+      if (info[i].mask & HB_GLYPH_FLAG_DEFINED)
+       p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"fl\":%u", info[i].mask & HB_GLYPH_FLAG_DEFINED));
     }
 
     if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS)
index 4ab5996..bfec0a7 100644 (file)
@@ -1860,6 +1860,88 @@ hb_buffer_t::sort (unsigned int start, unsigned int end, int(*compar)(const hb_g
   }
 }
 
+
+/*
+ * Comparing buffers.
+ */
+
+hb_buffer_diff_flags_t
+hb_buffer_diff (hb_buffer_t *buffer,
+               hb_buffer_t *reference,
+               hb_codepoint_t dottedcircle_glyph,
+               unsigned int position_fuzz)
+{
+  if (buffer->content_type != reference->content_type)
+    return HB_BUFFER_DIFF_FLAG_CONTENT_TYPE_MISMATCH;
+
+  hb_buffer_diff_flags_t result = HB_BUFFER_DIFF_FLAG_EQUAL;
+
+  unsigned int count = reference->len;
+
+  if (buffer->len != count)
+  {
+    /*
+     * we can't compare glyph-by-glyph, but we do want to know if there
+     * are .notdef or dottedcircle glyphs present in the reference buffer
+     */
+    const hb_glyph_info_t *info = reference->info;
+    unsigned int i;
+    for (i = 0; i < count; i++)
+    {
+      if (info[i].codepoint == dottedcircle_glyph)
+        result |= HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT;
+      else if (info[i].codepoint == 0)
+        result |= HB_BUFFER_DIFF_FLAG_NOTDEF_PRESENT;
+    }
+    result |= HB_BUFFER_DIFF_FLAG_LENGTH_MISMATCH;
+    return hb_buffer_diff_flags_t (result);
+  }
+
+  if (!count)
+    return hb_buffer_diff_flags_t (result);
+
+  const hb_glyph_info_t *buf_info = buffer->info;
+  const hb_glyph_info_t *ref_info = reference->info;
+  for (unsigned int i = 0; i < count; i++)
+  {
+    if (buf_info->codepoint != ref_info->codepoint)
+      result |= HB_BUFFER_DIFF_FLAG_CODEPOINT_MISMATCH;
+    if (buf_info->cluster != ref_info->cluster)
+      result |= HB_BUFFER_DIFF_FLAG_CLUSTER_MISMATCH;
+    if ((buf_info->mask & HB_GLYPH_FLAG_DEFINED) != (ref_info->mask & HB_GLYPH_FLAG_DEFINED))
+      result |= HB_BUFFER_DIFF_FLAG_MASK_MISMATCH;
+    if (ref_info->codepoint == dottedcircle_glyph)
+      result |= HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT;
+    else if (ref_info->codepoint == 0)
+      result |= HB_BUFFER_DIFF_FLAG_NOTDEF_PRESENT;
+    buf_info++;
+    ref_info++;
+  }
+
+  if (buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS)
+  {
+    assert (buffer->have_positions);
+    const hb_glyph_position_t *buf_pos = buffer->pos;
+    const hb_glyph_position_t *ref_pos = reference->pos;
+    for (unsigned int i = 0; i < count; i++)
+    {
+      if (abs (buf_pos->x_advance - ref_pos->x_advance) > position_fuzz ||
+          abs (buf_pos->y_advance - ref_pos->y_advance) > position_fuzz ||
+          abs (buf_pos->x_offset - ref_pos->x_offset) > position_fuzz ||
+          abs (buf_pos->y_offset - ref_pos->y_offset) > position_fuzz)
+      {
+        result |= HB_BUFFER_DIFF_FLAG_POSITION_MISMATCH;
+        break;
+      }
+      buf_pos++;
+      ref_pos++;
+    }
+  }
+
+  return result;
+}
+
+
 /*
  * Debugging.
  */
index 1d40747..abb1ea3 100644 (file)
@@ -466,6 +466,45 @@ hb_buffer_deserialize_glyphs (hb_buffer_t *buffer,
 
 
 /*
+ * Compare buffers
+ */
+
+typedef enum { /*< flags >*/
+  HB_BUFFER_DIFF_FLAG_EQUAL                    = 0x0000,
+
+  /* Buffers with different content_type cannot be meaningfully compared
+   * in any further detail. */
+  HB_BUFFER_DIFF_FLAG_CONTENT_TYPE_MISMATCH    = 0X0001,
+
+  /* For buffers with differing length, the per-glyph comparison is not
+   * attempted, though we do still scan reference for dottedcircle / .notdef
+   * glyphs. */
+  HB_BUFFER_DIFF_FLAG_LENGTH_MISMATCH          = 0X0002,
+
+  /* We want to know if dottedcircle / .notdef glyphs are present in the
+   * reference, as we may not care so much about other differences in this
+   * case. */
+  HB_BUFFER_DIFF_FLAG_NOTDEF_PRESENT           = 0x0004,
+  HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT    = 0x0008,
+
+  /* If the buffers have the same length, we compare them glyph-by-glyph
+   * and report which aspect(s) of the glyph info/position are different. */
+  HB_BUFFER_DIFF_FLAG_CODEPOINT_MISMATCH       = 0x0010,
+  HB_BUFFER_DIFF_FLAG_CLUSTER_MISMATCH         = 0x0010,
+  HB_BUFFER_DIFF_FLAG_MASK_MISMATCH            = 0x0040,
+  HB_BUFFER_DIFF_FLAG_POSITION_MISMATCH                = 0x0080
+
+} hb_buffer_diff_flags_t;
+
+/* Compare the contents of two buffers, report types of differences. */
+hb_buffer_diff_flags_t
+hb_buffer_diff (hb_buffer_t *buffer,
+               hb_buffer_t *reference,
+               hb_codepoint_t dottedcircle_glyph,
+               unsigned int position_fuzz);
+
+
+/*
  * Debugging.
  */