[HarfBuzz] harfbuzz: Branch 'master' - 2 commits

Behdad Esfahbod behdad at kemper.freedesktop.org
Sun Aug 13 22:09:29 UTC 2017


 src/hb-buffer.cc      |    5 +
 src/hb-coretext.cc    |    6 ++
 src/hb-directwrite.cc |    2 
 src/hb-graphite2.cc   |    1 
 src/hb-uniscribe.cc   |    2 
 util/options.hh       |  131 +++++++++++++++++++++++++++++++++++++++++++++++++-
 6 files changed, 144 insertions(+), 3 deletions(-)

New commits:
commit 239119a631fee7701be4d444adeda808b915863a
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Sun Aug 13 15:08:34 2017 -0700

    [unsafe-to-break] Mark all positions as unsafe in alternative shapers

diff --git a/src/hb-coretext.cc b/src/hb-coretext.cc
index e237335e..ba96d399 100644
--- a/src/hb-coretext.cc
+++ b/src/hb-coretext.cc
@@ -1180,6 +1180,9 @@ resize_and_retry:
 	pos->x_advance = info->mask;
 	pos->x_offset = info->var1.i32;
 	pos->y_offset = info->var2.i32;
+
+	info->mask = HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
+
 	info++, pos++;
       }
     else
@@ -1188,6 +1191,9 @@ resize_and_retry:
 	pos->y_advance = info->mask;
 	pos->x_offset = info->var1.i32;
 	pos->y_offset = info->var2.i32;
+
+	info->mask = HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
+
 	info++, pos++;
       }
 
diff --git a/src/hb-directwrite.cc b/src/hb-directwrite.cc
index ab07d8a3..14df8221 100644
--- a/src/hb-directwrite.cc
+++ b/src/hb-directwrite.cc
@@ -880,6 +880,8 @@ retry_getglyphs:
     pos->x_offset =
       x_mult * (isRightToLeft ? -info->var1.i32 : info->var1.i32);
     pos->y_offset = y_mult * info->var2.i32;
+
+    info->mask = HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
   }
 
   if (isRightToLeft)
diff --git a/src/hb-graphite2.cc b/src/hb-graphite2.cc
index c9799e9d..6eb34b0e 100644
--- a/src/hb-graphite2.cc
+++ b/src/hb-graphite2.cc
@@ -355,6 +355,7 @@ _hb_graphite2_shape (hb_shape_plan_t    *shape_plan,
       hb_glyph_info_t *info = &buffer->info[clusters[i].base_glyph + j];
       info->codepoint = gids[clusters[i].base_glyph + j];
       info->cluster = clusters[i].cluster;
+      info->mask = HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
       info->var1.i32 = clusters[i].advance;     // all glyphs in the cluster get the same advance
     }
   }
diff --git a/src/hb-uniscribe.cc b/src/hb-uniscribe.cc
index 58f983db..d25accd5 100644
--- a/src/hb-uniscribe.cc
+++ b/src/hb-uniscribe.cc
@@ -1024,6 +1024,8 @@ retry:
     pos->x_advance = x_mult * (int32_t) info->mask;
     pos->x_offset = x_mult * (backward ? -info->var1.i32 : info->var1.i32);
     pos->y_offset = y_mult * info->var2.i32;
+
+    info->mask = HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
   }
 
   if (backward)
commit 05fabbd03eae7b84ebbce7abbdc55c1d67ceacf9
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Aug 11 19:51:06 2017 -0700

    [unsafe-to-break] Towards verifying unsafe-to-break in --verify
    
    We break and shape fragments and reconstruct shape result from them.
    Remains to compare to original buffer.  Going to add some buffer
    comparison API and use here, instead of open-coding.

diff --git a/src/hb-buffer.cc b/src/hb-buffer.cc
index 297956e6..4ab5996f 100644
--- a/src/hb-buffer.cc
+++ b/src/hb-buffer.cc
@@ -1716,7 +1716,8 @@ hb_buffer_append (hb_buffer_t *buffer,
 		  unsigned int end)
 {
   assert (!buffer->have_output && !source->have_output);
-  assert (buffer->have_positions == source->have_positions);
+  assert (buffer->have_positions == source->have_positions ||
+	  !buffer->len || !source->len);
   assert (buffer->content_type == source->content_type ||
 	  !buffer->len || !source->len);
 
@@ -1729,6 +1730,8 @@ hb_buffer_append (hb_buffer_t *buffer,
 
   if (!buffer->len)
     buffer->content_type = source->content_type;
+  if (!buffer->have_positions && source->have_positions)
+    buffer->clear_positions ();
 
   if (buffer->len + (end - start) < buffer->len) /* Overflows. */
   {
diff --git a/util/options.hh b/util/options.hh
index fedd1217..d134f7ac 100644
--- a/util/options.hh
+++ b/util/options.hh
@@ -36,6 +36,7 @@
 #include <stddef.h>
 #include <string.h>
 #include <stdio.h>
+#include <assert.h>
 #include <math.h>
 #include <locale.h>
 #include <errno.h>
@@ -216,6 +217,15 @@ struct shape_options_t : option_group_t
     hb_buffer_guess_segment_properties (buffer);
   }
 
+  static void copy_buffer_properties (hb_buffer_t *dst, hb_buffer_t *src)
+  {
+    hb_segment_properties_t props;
+    hb_buffer_get_segment_properties (src, &props);
+    hb_buffer_set_segment_properties (dst, &props);
+    hb_buffer_set_flags (dst, hb_buffer_get_flags (src));
+    hb_buffer_set_cluster_level (dst, hb_buffer_get_cluster_level (src));
+  }
+
   void populate_buffer (hb_buffer_t *buffer, const char *text, int text_len,
 			const char *text_before, const char *text_after)
   {
@@ -246,6 +256,13 @@ struct shape_options_t : option_group_t
 
   hb_bool_t shape (hb_font_t *font, hb_buffer_t *buffer, const char **error=NULL)
   {
+    hb_buffer_t *text_buffer = NULL;
+    if (verify)
+    {
+      text_buffer = hb_buffer_create ();
+      hb_buffer_append (text_buffer, buffer, 0, -1);
+    }
+
     if (!hb_shape_full (font, buffer, features, num_features, shapers))
     {
       if (error)
@@ -256,13 +273,28 @@ struct shape_options_t : option_group_t
     if (normalize_glyphs)
       hb_buffer_normalize_glyphs (buffer);
 
-    if (verify && !verify_buffer (buffer, error))
+    if (verify && !verify_buffer (buffer, text_buffer, font, error))
       return false;
 
+    if (text_buffer)
+      hb_buffer_destroy (text_buffer);
+
     return true;
   }
 
-  bool verify_buffer (hb_buffer_t *buffer, const char **error=NULL)
+  bool verify_buffer (hb_buffer_t  *buffer,
+		      hb_buffer_t  *text_buffer,
+		      hb_font_t    *font,
+		      const char  **error=NULL)
+  {
+    if (!verify_buffer_monotone (buffer, error))
+      return false;
+    if (!verify_buffer_safe_to_break (buffer, text_buffer, font, error))
+      return false;
+    return true;
+  }
+
+  bool verify_buffer_monotone (hb_buffer_t *buffer, const char **error=NULL)
   {
     /* Check that clusters are monotone. */
     if (cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES ||
@@ -286,6 +318,101 @@ struct shape_options_t : option_group_t
     return true;
   }
 
+  bool verify_buffer_safe_to_break (hb_buffer_t  *buffer,
+				    hb_buffer_t  *text_buffer,
+				    hb_font_t    *font,
+				    const char  **error=NULL)
+  {
+    if (cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES &&
+	cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS)
+    {
+      /* Cannot perform this check without monotone clusters.
+       * Then again, unsafe-to-break flag is much harder to use without
+       * monotone clusters. */
+      return true;
+    }
+
+    /* Check that breaking up shaping at safe-to-break is indeed safe. */
+
+    hb_buffer_t *fragment = hb_buffer_create ();
+    hb_buffer_t *reconstruction = hb_buffer_create ();
+    copy_buffer_properties (reconstruction, buffer);
+
+    unsigned int num_glyphs;
+    hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, &num_glyphs);
+
+    unsigned int num_chars;
+    hb_glyph_info_t *text = hb_buffer_get_glyph_infos (text_buffer, &num_chars);
+
+    /* Chop text and shape fragments. */
+    bool forward = HB_DIRECTION_IS_FORWARD (hb_buffer_get_direction (buffer));
+    unsigned int start = 0;
+    unsigned int text_start = forward ? 0 : num_chars;
+    unsigned int text_end = text_start;
+    for (unsigned int end = 1; end < num_glyphs + 1; end++)
+    {
+      if (end < num_glyphs &&
+	  (info[end].cluster == info[end-1].cluster ||
+	   info[end-(forward?0:1)].mask & HB_GLYPH_FLAG_UNSAFE_TO_BREAK))
+	  continue;
+
+      /* Shape segment corresponding to glyphs start..end. */
+      if (end == num_glyphs)
+      {
+        if (forward)
+	  text_end = num_chars;
+	else
+	  text_start = 0;
+      }
+      else
+      {
+	unsigned int cluster = info[end].cluster;
+	if (forward)
+	  while (text_end < num_chars && text[text_end].cluster != cluster)
+	    text_end++;
+	else
+	  while (text_start && text[text_start - 1].cluster != cluster)
+	    text_start--;
+      }
+      assert (text_start < text_end);
+
+      //printf("start %d end %d text start %d end %d\n", start, end, text_start, text_end);
+      hb_buffer_clear_contents (fragment);
+      copy_buffer_properties (fragment, buffer);
+      hb_buffer_append (fragment, text_buffer, text_start, text_end);
+      if (!hb_shape_full (font, fragment, features, num_features, shapers))
+      {
+	if (error)
+	  *error = "all shapers failed while shaping fragment.";
+	return false;
+      }
+      hb_buffer_append (reconstruction, fragment, 0, -1);
+
+      start = end;
+      if (forward)
+	text_start = text_end;
+      else
+	text_end = text_start;
+    }
+
+    hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, NULL);
+
+    unsigned int r_num_glyphs;
+    hb_glyph_info_t *r_info = hb_buffer_get_glyph_infos (reconstruction, &r_num_glyphs);
+    hb_glyph_position_t *r_pos = hb_buffer_get_glyph_positions (reconstruction, NULL);
+
+    /* TODO Compare buffers. Remove assert. */
+    assert (num_glyphs == r_num_glyphs);
+
+    //hb_buffer_set_length (buffer, 0);
+    //hb_buffer_append (buffer, reconstruction, 0, -1);
+
+    hb_buffer_destroy (reconstruction);
+    hb_buffer_destroy (fragment);
+
+    return true;
+  }
+
   void shape_closure (const char *text, int text_len,
 		      hb_font_t *font, hb_buffer_t *buffer,
 		      hb_set_t *glyphs)


More information about the HarfBuzz mailing list