Index: third_party/harfbuzz-ng/src/hb-buffer.cc |
diff --git a/third_party/harfbuzz-ng/src/hb-buffer.cc b/third_party/harfbuzz-ng/src/hb-buffer.cc |
index 9c9b32e3adaccfc1d4a81f0be09747c3e72b64d7..fec9225b483afbefc2878ddbced12b1a0f79ebf6 100644 |
--- a/third_party/harfbuzz-ng/src/hb-buffer.cc |
+++ b/third_party/harfbuzz-ng/src/hb-buffer.cc |
@@ -37,9 +37,6 @@ |
#define HB_DEBUG_BUFFER (HB_DEBUG+0) |
#endif |
-#define _HB_BUFFER_UNICODE_FUNCS_DEFAULT (const_cast<hb_unicode_funcs_t *> (&_hb_unicode_funcs_default)) |
-#define _HB_BUFFER_PROPS_DEFAULT { HB_DIRECTION_INVALID, HB_SCRIPT_INVALID, HB_LANGUAGE_INVALID } |
- |
/* Here is how the buffer works internally: |
* |
* There are two info pointers: info and out_info. They always have |
@@ -126,12 +123,16 @@ hb_buffer_t::get_scratch_buffer (unsigned int *size) |
{ |
have_output = false; |
have_positions = false; |
+ |
out_len = 0; |
+ out_info = info; |
+ |
*size = allocated * sizeof (pos[0]); |
return pos; |
} |
+ |
/* HarfBuzz-Internal API */ |
void |
@@ -141,11 +142,12 @@ hb_buffer_t::reset (void) |
return; |
hb_unicode_funcs_destroy (unicode); |
- unicode = _HB_BUFFER_UNICODE_FUNCS_DEFAULT; |
+ unicode = hb_unicode_funcs_get_default (); |
hb_segment_properties_t default_props = _HB_BUFFER_PROPS_DEFAULT; |
props = default_props; |
+ content_type = HB_BUFFER_CONTENT_TYPE_INVALID; |
in_error = false; |
have_output = false; |
have_positions = false; |
@@ -153,12 +155,11 @@ hb_buffer_t::reset (void) |
idx = 0; |
len = 0; |
out_len = 0; |
+ out_info = info; |
serial = 0; |
memset (allocated_var_bytes, 0, sizeof allocated_var_bytes); |
memset (allocated_var_owner, 0, sizeof allocated_var_owner); |
- |
- out_info = info; |
} |
void |
@@ -202,6 +203,9 @@ hb_buffer_t::clear_positions (void) |
have_output = false; |
have_positions = true; |
+ out_len = 0; |
+ out_info = info; |
+ |
memset (pos, 0, sizeof (pos[0]) * len); |
} |
@@ -230,47 +234,17 @@ hb_buffer_t::swap_buffers (void) |
idx = 0; |
} |
-void |
-hb_buffer_t::replace_glyphs_be16 (unsigned int num_in, |
- unsigned int num_out, |
- const char *glyph_data_be) |
-{ |
- if (!make_room_for (num_in, num_out)) return; |
- |
- hb_glyph_info_t orig_info = info[idx]; |
- for (unsigned int i = 1; i < num_in; i++) |
- { |
- hb_glyph_info_t *inf = &info[idx + i]; |
- orig_info.cluster = MIN (orig_info.cluster, inf->cluster); |
- } |
- |
- hb_glyph_info_t *pinfo = &out_info[out_len]; |
- const unsigned char *data = (const unsigned char *) glyph_data_be; |
- for (unsigned int i = 0; i < num_out; i++) |
- { |
- *pinfo = orig_info; |
- pinfo->codepoint = (data[2*i] << 8) | data[2*i+1]; |
- pinfo++; |
- } |
- |
- idx += num_in; |
- out_len += num_out; |
-} |
void |
hb_buffer_t::replace_glyphs (unsigned int num_in, |
unsigned int num_out, |
const uint32_t *glyph_data) |
{ |
- if (!make_room_for (num_in, num_out)) return; |
+ if (unlikely (!make_room_for (num_in, num_out))) return; |
- hb_glyph_info_t orig_info = info[idx]; |
- for (unsigned int i = 1; i < num_in; i++) |
- { |
- hb_glyph_info_t *inf = &info[idx + i]; |
- orig_info.cluster = MIN (orig_info.cluster, inf->cluster); |
- } |
+ merge_clusters (idx, idx + num_in); |
+ hb_glyph_info_t orig_info = info[idx]; |
hb_glyph_info_t *pinfo = &out_info[out_len]; |
for (unsigned int i = 0; i < num_out; i++) |
{ |
@@ -286,7 +260,7 @@ hb_buffer_t::replace_glyphs (unsigned int num_in, |
void |
hb_buffer_t::output_glyph (hb_codepoint_t glyph_index) |
{ |
- if (!make_room_for (0, 1)) return; |
+ if (unlikely (!make_room_for (0, 1))) return; |
out_info[out_len] = info[idx]; |
out_info[out_len].codepoint = glyph_index; |
@@ -295,46 +269,39 @@ hb_buffer_t::output_glyph (hb_codepoint_t glyph_index) |
} |
void |
-hb_buffer_t::copy_glyph (void) |
+hb_buffer_t::output_info (hb_glyph_info_t &glyph_info) |
{ |
- if (!make_room_for (0, 1)) return; |
+ if (unlikely (!make_room_for (0, 1))) return; |
- out_info[out_len] = info[idx]; |
+ out_info[out_len] = glyph_info; |
out_len++; |
} |
void |
-hb_buffer_t::replace_glyph (hb_codepoint_t glyph_index) |
+hb_buffer_t::copy_glyph (void) |
{ |
- if (!make_room_for (1, 1)) return; |
+ if (unlikely (!make_room_for (0, 1))) return; |
out_info[out_len] = info[idx]; |
- out_info[out_len].codepoint = glyph_index; |
- idx++; |
out_len++; |
} |
void |
-hb_buffer_t::next_glyph (void) |
+hb_buffer_t::replace_glyph (hb_codepoint_t glyph_index) |
{ |
- if (have_output) |
- { |
- if (out_info != info) |
- { |
- if (unlikely (!ensure (out_len + 1))) return; |
- out_info[out_len] = info[idx]; |
- } |
- else if (out_len != idx) |
- out_info[out_len] = info[idx]; |
- |
- out_len++; |
+ if (unlikely (out_info != info || out_len != idx)) { |
+ if (unlikely (!make_room_for (1, 1))) return; |
+ out_info[out_len] = info[idx]; |
} |
+ out_info[out_len].codepoint = glyph_index; |
idx++; |
+ out_len++; |
} |
+ |
void |
hb_buffer_t::set_masks (hb_mask_t value, |
hb_mask_t mask, |
@@ -424,32 +391,69 @@ void |
hb_buffer_t::merge_clusters (unsigned int start, |
unsigned int end) |
{ |
- unsigned int cluster = this->info[start].cluster; |
+ if (unlikely (end - start < 2)) |
+ return; |
+ |
+ unsigned int cluster = info[start].cluster; |
for (unsigned int i = start + 1; i < end; i++) |
- cluster = MIN (cluster, this->info[i].cluster); |
+ cluster = MIN (cluster, info[i].cluster); |
+ |
+ /* Extend end */ |
+ while (end < len && info[end - 1].cluster == info[end].cluster) |
+ end++; |
+ |
+ /* Extend start */ |
+ while (idx < start && info[start - 1].cluster == info[start].cluster) |
+ 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--) |
+ out_info[i - 1].cluster = cluster; |
+ |
for (unsigned int i = start; i < end; i++) |
- this->info[i].cluster = cluster; |
+ info[i].cluster = cluster; |
} |
void |
hb_buffer_t::merge_out_clusters (unsigned int start, |
unsigned int end) |
{ |
- unsigned int cluster = this->out_info[start].cluster; |
+ if (unlikely (end - start < 2)) |
+ return; |
+ |
+ unsigned int cluster = out_info[start].cluster; |
for (unsigned int i = start + 1; i < end; i++) |
- cluster = MIN (cluster, this->out_info[i].cluster); |
+ cluster = MIN (cluster, out_info[i].cluster); |
+ |
+ /* Extend start */ |
+ while (start && out_info[start - 1].cluster == out_info[start].cluster) |
+ start--; |
+ |
+ /* Extend end */ |
+ while (end < out_len && out_info[end - 1].cluster == out_info[end].cluster) |
+ end++; |
+ |
+ /* 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++) |
+ info[i].cluster = cluster; |
+ |
for (unsigned int i = start; i < end; i++) |
- this->out_info[i].cluster = cluster; |
+ out_info[i].cluster = cluster; |
} |
void |
hb_buffer_t::guess_properties (void) |
{ |
+ if (unlikely (!len)) return; |
+ assert (content_type == HB_BUFFER_CONTENT_TYPE_UNICODE); |
+ |
/* If script is set to INVALID, guess from buffer contents */ |
if (props.script == HB_SCRIPT_INVALID) { |
for (unsigned int i = 0; i < len; i++) { |
- hb_script_t script = hb_unicode_script (unicode, info[i].codepoint); |
+ hb_script_t script = unicode->script (info[i].codepoint); |
if (likely (script != HB_SCRIPT_COMMON && |
script != HB_SCRIPT_INHERITED && |
script != HB_SCRIPT_UNKNOWN)) { |
@@ -518,6 +522,22 @@ void hb_buffer_t::deallocate_var (unsigned int byte_i, unsigned int count, const |
} |
} |
+void hb_buffer_t::assert_var (unsigned int byte_i, unsigned int count, const char *owner) |
+{ |
+ if (DEBUG (BUFFER)) |
+ dump_var_allocation (this); |
+ |
+ DEBUG_MSG (BUFFER, this, |
+ "Asserting var bytes %d..%d for %s", |
+ byte_i, byte_i + count - 1, owner); |
+ |
+ assert (byte_i < 8 && byte_i + count <= 8); |
+ for (unsigned int i = byte_i; i < byte_i + count; i++) { |
+ assert (allocated_var_bytes[i]); |
+ assert (0 == strcmp (allocated_var_owner[i], owner)); |
+ } |
+} |
+ |
void hb_buffer_t::deallocate_var_all (void) |
{ |
memset (allocated_var_bytes, 0, sizeof (allocated_var_bytes)); |
@@ -545,9 +565,10 @@ hb_buffer_get_empty (void) |
static const hb_buffer_t _hb_buffer_nil = { |
HB_OBJECT_HEADER_STATIC, |
- _HB_BUFFER_UNICODE_FUNCS_DEFAULT, |
+ const_cast<hb_unicode_funcs_t *> (&_hb_unicode_funcs_nil), |
_HB_BUFFER_PROPS_DEFAULT, |
+ HB_BUFFER_CONTENT_TYPE_INVALID, |
true, /* in_error */ |
true, /* have_output */ |
true /* have_positions */ |
@@ -594,6 +615,20 @@ hb_buffer_get_user_data (hb_buffer_t *buffer, |
void |
+hb_buffer_set_content_type (hb_buffer_t *buffer, |
+ hb_buffer_content_type_t content_type) |
+{ |
+ buffer->content_type = content_type; |
+} |
+ |
+hb_buffer_content_type_t |
+hb_buffer_get_content_type (hb_buffer_t *buffer) |
+{ |
+ return buffer->content_type; |
+} |
+ |
+ |
+void |
hb_buffer_set_unicode_funcs (hb_buffer_t *buffer, |
hb_unicode_funcs_t *unicode) |
{ |
@@ -601,7 +636,8 @@ hb_buffer_set_unicode_funcs (hb_buffer_t *buffer, |
return; |
if (!unicode) |
- unicode = _HB_BUFFER_UNICODE_FUNCS_DEFAULT; |
+ unicode = hb_unicode_funcs_get_default (); |
+ |
hb_unicode_funcs_reference (unicode); |
hb_unicode_funcs_destroy (buffer->unicode); |
@@ -832,6 +868,11 @@ hb_buffer_add_utf8 (hb_buffer_t *buffer, |
unsigned int item_offset, |
int item_length) |
{ |
+ assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE || |
+ (!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID)); |
+ if (unlikely (hb_object_is_inert (buffer))) |
+ return; |
+ buffer->content_type = HB_BUFFER_CONTENT_TYPE_UNICODE; |
#define UTF_NEXT(S, E, U) hb_utf8_next (S, E, &(U)) |
ADD_UTF (uint8_t); |
#undef UTF_NEXT |
@@ -866,6 +907,11 @@ hb_buffer_add_utf16 (hb_buffer_t *buffer, |
unsigned int item_offset, |
int item_length) |
{ |
+ assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE || |
+ (!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID)); |
+ if (unlikely (hb_object_is_inert (buffer))) |
+ return; |
+ buffer->content_type = HB_BUFFER_CONTENT_TYPE_UNICODE; |
#define UTF_NEXT(S, E, U) hb_utf16_next (S, E, &(U)) |
ADD_UTF (uint16_t); |
#undef UTF_NEXT |
@@ -878,9 +924,90 @@ hb_buffer_add_utf32 (hb_buffer_t *buffer, |
unsigned int item_offset, |
int item_length) |
{ |
+ assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE || |
+ (!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID)); |
+ if (unlikely (hb_object_is_inert (buffer))) |
+ return; |
+ buffer->content_type = HB_BUFFER_CONTENT_TYPE_UNICODE; |
#define UTF_NEXT(S, E, U) ((U) = *(S), (S)+1) |
ADD_UTF (uint32_t); |
#undef UTF_NEXT |
} |
+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); |
+} |