summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/hb-buffer.cc76
-rw-r--r--src/hb-buffer.h13
-rw-r--r--src/hb-private.hh29
-rw-r--r--util/options.cc1
-rw-r--r--util/options.hh7
5 files changed, 118 insertions, 8 deletions
diff --git a/src/hb-buffer.cc b/src/hb-buffer.cc
index 44571da0..ec296594 100644
--- a/src/hb-buffer.cc
+++ b/src/hb-buffer.cc
@@ -887,3 +887,79 @@ hb_buffer_add_utf32 (hb_buffer_t *buffer,
}
+static int
+compare_info_codepoint (const hb_glyph_info_t *pa,
+ const hb_glyph_info_t *pb)
+{
+ return (int) pb->codepoint - (int) pa->codepoint;
+}
+
+static inline void
+normalize_glyphs_cluster (hb_buffer_t *buffer,
+ unsigned int start,
+ unsigned int end,
+ bool backward)
+{
+ hb_glyph_position_t *pos = buffer->pos;
+
+ /* Total cluster advance */
+ hb_position_t total_x_advance = 0, total_y_advance = 0;
+ for (unsigned int i = start; i < end; i++)
+ {
+ total_x_advance += pos[i].x_advance;
+ total_y_advance += pos[i].y_advance;
+ }
+
+ hb_position_t x_advance = 0, y_advance = 0;
+ for (unsigned int i = start; i < end; i++)
+ {
+ pos[i].x_offset += x_advance;
+ pos[i].y_offset += y_advance;
+
+ x_advance += pos[i].x_advance;
+ y_advance += pos[i].y_advance;
+
+ pos[i].x_advance = 0;
+ pos[i].y_advance = 0;
+ }
+
+ if (backward)
+ {
+ /* Transfer all cluster advance to the last glyph. */
+ pos[end - 1].x_advance = total_x_advance;
+ pos[end - 1].y_advance = total_y_advance;
+
+ hb_bubble_sort (buffer->info + start, end - start - 1, compare_info_codepoint, buffer->pos + start);
+ } else {
+ /* Transfer all cluster advance to the first glyph. */
+ pos[start].x_advance += total_x_advance;
+ pos[start].y_advance += total_y_advance;
+ for (unsigned int i = start + 1; i < end; i++) {
+ pos[i].x_offset -= total_x_advance;
+ pos[i].y_offset -= total_y_advance;
+ }
+ hb_bubble_sort (buffer->info + start + 1, end - start - 1, compare_info_codepoint, buffer->pos + start + 1);
+ }
+}
+
+void
+hb_buffer_normalize_glyphs (hb_buffer_t *buffer)
+{
+ assert (buffer->have_positions);
+ /* XXX assert (buffer->have_glyphs); */
+
+ bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
+
+ unsigned int count = buffer->len;
+ if (unlikely (!count)) return;
+ hb_glyph_info_t *info = buffer->info;
+
+ unsigned int start = 0;
+ unsigned int end;
+ for (end = start + 1; end < count; end++)
+ if (info[start].cluster != info[end].cluster) {
+ normalize_glyphs_cluster (buffer, start, end, backward);
+ start = end;
+ }
+ normalize_glyphs_cluster (buffer, start, end, backward);
+}
diff --git a/src/hb-buffer.h b/src/hb-buffer.h
index 73adc2e7..d67cfd63 100644
--- a/src/hb-buffer.h
+++ b/src/hb-buffer.h
@@ -193,6 +193,19 @@ hb_buffer_get_glyph_positions (hb_buffer_t *buffer,
unsigned int *length);
+/* Reorders a glyph buffer to have canonical in-cluster glyph order / position.
+ * The resulting clusters should behave identical to pre-reordering clusters.
+ * NOTE: This has nothing to do with Unicode normalization. */
+void
+hb_buffer_normalize_glyphs (hb_buffer_t *buffer);
+
+/*
+ * NOT IMPLEMENTED
+void
+hb_buffer_normalize_characters (hb_buffer_t *buffer);
+*/
+
+
HB_END_DECLS
#endif /* HB_BUFFER_H */
diff --git a/src/hb-private.hh b/src/hb-private.hh
index 29cd68c2..02ed9cea 100644
--- a/src/hb-private.hh
+++ b/src/hb-private.hh
@@ -737,8 +737,8 @@ hb_in_range (T u, T lo, T hi)
#define FLAG(x) (1<<(x))
-template <typename T> inline void
-hb_bubble_sort (T *array, unsigned int len, int(*compar)(const T *, const T *))
+template <typename T, typename T2> inline void
+hb_bubble_sort (T *array, unsigned int len, int(*compar)(const T *, const T *), T2 *array2)
{
if (unlikely (!len))
return;
@@ -748,11 +748,21 @@ hb_bubble_sort (T *array, unsigned int len, int(*compar)(const T *, const T *))
unsigned int new_k = 0;
for (unsigned int j = 0; j < k; j++)
- if (compar (&array[j], &array[j+1]) > 0) {
- T t;
- t = array[j];
- array[j] = array[j + 1];
- array[j + 1] = t;
+ if (compar (&array[j], &array[j+1]) > 0)
+ {
+ {
+ T t;
+ t = array[j];
+ array[j] = array[j + 1];
+ array[j + 1] = t;
+ }
+ if (array2)
+ {
+ T2 t;
+ t = array2[j];
+ array2[j] = array2[j + 1];
+ array2[j + 1] = t;
+ }
new_k = j;
}
@@ -760,6 +770,11 @@ hb_bubble_sort (T *array, unsigned int len, int(*compar)(const T *, const T *))
} while (k);
}
+template <typename T> inline void
+hb_bubble_sort (T *array, unsigned int len, int(*compar)(const T *, const T *))
+{
+ hb_bubble_sort (array, len, compar, (int *) NULL);
+}
diff --git a/util/options.cc b/util/options.cc
index db1b2447..584190e0 100644
--- a/util/options.cc
+++ b/util/options.cc
@@ -396,6 +396,7 @@ shape_options_t::add_options (option_parser_t *parser)
{"language", 0, 0, G_OPTION_ARG_STRING, &this->language, "Set text language (default: $LANG)", "langstr"},
{"script", 0, 0, G_OPTION_ARG_STRING, &this->script, "Set text script (default: auto)", "ISO-15924 tag"},
{"utf8-clusters", 0, 0, G_OPTION_ARG_NONE, &this->utf8_clusters, "Use UTF8 byte indices, not char indices", NULL},
+ {"normalize-glyphs",0, 0, G_OPTION_ARG_NONE, &this->normalize_glyphs, "Rearrange glyph clusters in nominal order", NULL},
{NULL}
};
parser->add_group (entries,
diff --git a/util/options.hh b/util/options.hh
index 9b7baa71..24852305 100644
--- a/util/options.hh
+++ b/util/options.hh
@@ -148,6 +148,7 @@ struct shape_options_t : option_group_t
num_features = 0;
shapers = NULL;
utf8_clusters = false;
+ normalize_glyphs = false;
add_options (parser);
}
@@ -188,7 +189,10 @@ struct shape_options_t : option_group_t
hb_bool_t shape (hb_font_t *font, hb_buffer_t *buffer)
{
- return hb_shape_full (font, buffer, features, num_features, shapers);
+ hb_bool_t res = hb_shape_full (font, buffer, features, num_features, shapers);
+ if (normalize_glyphs)
+ hb_buffer_normalize_glyphs (buffer);
+ return res;
}
void shape_closure (const char *text, int text_len,
@@ -208,6 +212,7 @@ struct shape_options_t : option_group_t
unsigned int num_features;
char **shapers;
hb_bool_t utf8_clusters;
+ hb_bool_t normalize_glyphs;
};