| 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);
|
| +}
|
|
|