[HarfBuzz] harfbuzz: Branch 'master' - 3 commits
Behdad Esfahbod
behdad at kemper.freedesktop.org
Fri Jun 19 13:32:14 PDT 2015
src/hb-buffer-private.hh | 20 ++++++++++++++
src/hb-buffer.cc | 36 ++++++++++++++++++++++++--
src/hb-ot-shape.cc | 65 ++++++++++++++++++++++++++++-------------------
test/api/test-shape.c | 43 +++++++++++++++++++++++++++++++
4 files changed, 136 insertions(+), 28 deletions(-)
New commits:
commit 5f13bbd9d4b0970851626e2ce3cf4ecb3cfde801
Author: Behdad Esfahbod <behdad at behdad.org>
Date: Fri Jun 19 13:31:49 2015 -0700
When removing default-ignorables, merge clusters
Fixes test-shape, and:
https://code.google.com/p/chromium/issues/detail?id=497578
diff --git a/src/hb-buffer-private.hh b/src/hb-buffer-private.hh
index 6a33962..ced748f 100644
--- a/src/hb-buffer-private.hh
+++ b/src/hb-buffer-private.hh
@@ -192,6 +192,8 @@ struct hb_buffer_t {
unsigned int end);
HB_INTERNAL void merge_out_clusters (unsigned int start,
unsigned int end);
+ /* Merge clusters for deleting current glyph, and skip it. */
+ HB_INTERNAL void delete_glyph (void);
/* Internal methods */
HB_INTERNAL bool enlarge (unsigned int size);
diff --git a/src/hb-buffer.cc b/src/hb-buffer.cc
index e13ee4a..4f953f0 100644
--- a/src/hb-buffer.cc
+++ b/src/hb-buffer.cc
@@ -529,7 +529,7 @@ hb_buffer_t::merge_clusters (unsigned int start,
/* If we hit the start of buffer, continue in out-buffer. */
if (idx == start)
- for (unsigned i = out_len; i && out_info[i - 1].cluster == info[start].cluster; i--)
+ for (unsigned int i = out_len; i && out_info[i - 1].cluster == info[start].cluster; i--)
out_info[i - 1].cluster = cluster;
for (unsigned int i = start; i < end; i++)
@@ -561,12 +561,44 @@ hb_buffer_t::merge_out_clusters (unsigned int start,
/* If we hit the end of out-buffer, continue in buffer. */
if (end == out_len)
- for (unsigned i = idx; i < len && info[i].cluster == out_info[end - 1].cluster; i++)
+ for (unsigned int i = idx; i < len && info[i].cluster == out_info[end - 1].cluster; i++)
info[i].cluster = cluster;
for (unsigned int i = start; i < end; i++)
out_info[i].cluster = cluster;
}
+void
+hb_buffer_t::delete_glyph ()
+{
+ unsigned int cluster = info[idx].cluster;
+ if (idx + 1 < len && cluster == info[idx + 1].cluster)
+ {
+ /* Cluster survives; do nothing. */
+ goto done;
+ }
+
+ if (out_len)
+ {
+ /* Merge cluster backward. */
+ if (cluster < out_info[out_len - 1].cluster)
+ {
+ unsigned int old_cluster = out_info[out_len - 1].cluster;
+ for (unsigned i = out_len; i && out_info[i - 1].cluster == old_cluster; i--)
+ out_info[i - 1].cluster = cluster;
+ }
+ goto done;
+ }
+
+ if (idx + 1 < len)
+ {
+ /* Merge cluster forward. */
+ merge_clusters (idx, idx + 2);
+ goto done;
+ }
+
+done:
+ skip_glyph ();
+}
void
hb_buffer_t::guess_segment_properties (void)
diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc
index 5688604..a531d77 100644
--- a/src/hb-ot-shape.cc
+++ b/src/hb-ot-shape.cc
@@ -692,7 +692,7 @@ hb_ot_hide_default_ignorables (hb_ot_shape_context_t *c)
if (!_hb_glyph_info_ligated (&info[buffer->idx]) &&
_hb_glyph_info_is_default_ignorable (&info[buffer->idx]))
{
- buffer->skip_glyph ();
+ buffer->delete_glyph ();
continue;
}
buffer->next_glyph ();
commit 82b521aeb7cc73879b44ca4278d6fa8b4347527f
Author: Behdad Esfahbod <behdad at behdad.org>
Date: Fri Jun 19 11:57:57 2015 -0700
Rewrite hide_default_ignorables
Separate the loops for the two cases of replacing with space
and deleting. For deleting, use the out-buffer machinery.
Needed for upcoming cluster merge fix.
diff --git a/src/hb-buffer-private.hh b/src/hb-buffer-private.hh
index 069f925..6a33962 100644
--- a/src/hb-buffer-private.hh
+++ b/src/hb-buffer-private.hh
@@ -151,6 +151,24 @@ struct hb_buffer_t {
idx++;
}
+ inline void
+ next_glyphs (unsigned int count)
+ {
+ if (have_output)
+ {
+ if (unlikely (out_info != info || out_len != idx)) {
+ if (unlikely (!make_room_for (count, count))) return;
+ {
+ while (count--)
+ out_info[out_len++] = info[idx++];
+ return;
+ }
+ }
+ out_len += count;
+ }
+
+ idx += count;
+ }
/* Advance idx without copying to output. */
inline void skip_glyph (void) { idx++; }
diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc
index 5fb0e05..5688604 100644
--- a/src/hb-ot-shape.cc
+++ b/src/hb-ot-shape.cc
@@ -647,45 +647,58 @@ hb_ot_position (hb_ot_shape_context_t *c)
static void
hb_ot_hide_default_ignorables (hb_ot_shape_context_t *c)
{
- if (c->buffer->flags & HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES)
- return;
+ hb_buffer_t *buffer = c->buffer;
- hb_codepoint_t space;
- enum {
- SPACE_DONT_KNOW,
- SPACE_AVAILABLE,
- SPACE_UNAVAILABLE
- } space_status = SPACE_DONT_KNOW;
+ if (buffer->flags & HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES)
+ return;
- unsigned int count = c->buffer->len;
- hb_glyph_info_t *info = c->buffer->info;
- hb_glyph_position_t *pos = c->buffer->pos;
- unsigned int j = 0;
- for (unsigned int i = 0; i < count; i++)
+ unsigned int count = buffer->len;
+ hb_glyph_info_t *info = buffer->info;
+ hb_glyph_position_t *pos = buffer->pos;
+ unsigned int i = 0;
+ for (i = 0; i < count; i++)
{
if (unlikely (!_hb_glyph_info_ligated (&info[i]) &&
_hb_glyph_info_is_default_ignorable (&info[i])))
- {
- if (space_status == SPACE_DONT_KNOW)
- space_status = c->font->get_glyph (' ', 0, &space) ? SPACE_AVAILABLE : SPACE_UNAVAILABLE;
+ break;
+ }
+
+ /* No default-ignorables found; return. */
+ if (i == count)
+ return;
- if (space_status == SPACE_AVAILABLE)
+ hb_codepoint_t space;
+ if (c->font->get_glyph (' ', 0, &space))
+ {
+ /* Replace default-ignorables with a zero-advance space glyph. */
+ for (/*continue*/; i < count; i++)
+ {
+ if (!_hb_glyph_info_ligated (&info[i]) &&
+ _hb_glyph_info_is_default_ignorable (&info[i]))
{
info[i].codepoint = space;
- pos[i].x_advance = 0;
- pos[i].y_advance = 0;
+ pos[i].x_advance = pos[i].y_advance = pos[i].x_offset = pos[i].y_offset = 0;
}
- else
- continue; /* Delete it. XXX Merge clusters? */
}
- if (j != i)
+ }
+ else
+ {
+ /* Merge clusters and delete default-ignorables. */
+ buffer->clear_output ();
+ buffer->idx = 0;
+ buffer->next_glyphs (i);
+ while (buffer->idx < buffer->len)
{
- info[j] = info[i];
- pos[j] = pos[i];
+ if (!_hb_glyph_info_ligated (&info[buffer->idx]) &&
+ _hb_glyph_info_is_default_ignorable (&info[buffer->idx]))
+ {
+ buffer->skip_glyph ();
+ continue;
+ }
+ buffer->next_glyph ();
}
- j++;
+ buffer->swap_buffers ();
}
- c->buffer->len = j;
}
commit b3a2f6afbac1956b65f29a17b9dc896e86135329
Author: Behdad Esfahbod <behdad at behdad.org>
Date: Thu Jun 18 17:15:33 2015 -0700
[test] Add test for cluster merging
Based on test from https://code.google.com/p/chromium/issues/detail?id=497578
Currently fails. Basically, if there's a default_ignorable at the
start of text, and font has no space glyph, we remove the default_ignorable,
and that makes the first char in text to correspond to no cluster.
Fix coming.
diff --git a/test/api/test-shape.c b/test/api/test-shape.c
index ccf6eed..eb24407 100644
--- a/test/api/test-shape.c
+++ b/test/api/test-shape.c
@@ -139,6 +139,48 @@ test_shape (void)
}
static void
+test_shape_clusters (void)
+{
+ hb_face_t *face;
+ hb_font_t *font;
+ hb_buffer_t *buffer;
+ unsigned int len;
+ hb_glyph_info_t *glyphs;
+
+ face = hb_face_create (NULL, 0);
+ font = hb_font_create (face);
+ hb_face_destroy (face);
+
+ buffer = hb_buffer_create ();
+ hb_buffer_set_direction (buffer, HB_DIRECTION_LTR);
+ {
+ /* https://code.google.com/p/chromium/issues/detail?id=497578 */
+ hb_codepoint_t test[] = {0xFFF1, 0xF0B6};
+ hb_buffer_add_utf32 (buffer, test, 2, 0, 2);
+ }
+
+ hb_shape (font, buffer, NULL, 0);
+
+ len = hb_buffer_get_length (buffer);
+ glyphs = hb_buffer_get_glyph_infos (buffer, NULL);
+
+ {
+ const hb_codepoint_t output_glyphs[] = {0};
+ const hb_position_t output_clusters[] = {0};
+ unsigned int i;
+ g_assert_cmpint (len, ==, 1);
+ for (i = 0; i < len; i++) {
+ g_assert_cmphex (glyphs[i].codepoint, ==, output_glyphs[i]);
+ g_assert_cmphex (glyphs[i].cluster, ==, output_clusters[i]);
+ }
+ }
+
+ hb_buffer_destroy (buffer);
+ hb_font_destroy (font);
+}
+
+
+static void
test_shape_list (void)
{
const char **shapers = hb_shape_list_shapers ();
@@ -157,6 +199,7 @@ main (int argc, char **argv)
hb_test_init (&argc, &argv);
hb_test_add (test_shape);
+ hb_test_add (test_shape_clusters);
/* TODO test fallback shaper */
/* TODO test shaper_full */
hb_test_add (test_shape_list);
More information about the HarfBuzz
mailing list