Merge pull request #3353 from harfbuzz/buffer-create-similar

Add `hb_buffer_create_similar()`; use it in util
This commit is contained in:
Behdad Esfahbod 2022-01-04 07:33:59 -07:00 committed by GitHub
commit c5e5d5e0bc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 182 additions and 72 deletions

View File

@ -45,6 +45,7 @@ hb_memory_mode_t
HB_SEGMENT_PROPERTIES_DEFAULT
HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT
hb_buffer_create
hb_buffer_create_similar
hb_buffer_reference
hb_buffer_get_empty
hb_buffer_destroy
@ -103,6 +104,7 @@ hb_buffer_serialize_format_to_string
hb_buffer_serialize_list_formats
hb_segment_properties_equal
hb_segment_properties_hash
hb_segment_properties_overlay
hb_buffer_diff
hb_buffer_set_message_func
hb_buffer_t

View File

@ -86,7 +86,46 @@ hb_segment_properties_hash (const hb_segment_properties_t *p)
(intptr_t) (p->language);
}
/**
* hb_segment_properties_overlay:
* @p: #hb_segment_properties_t to fill in.
* @src: #hb_segment_properties_t to fill in from.
*
* Fills in missing fields of @p from @src in a considered manner.
*
* First, if @p does not have direction set, direction is copied from @src.
*
* Next, if @p and @src have the same direction (which can be unset), if @p
* does not have script set, script is copied from @src.
*
* Finally, if @p and @src have the same direction and script (which either
* can be unset), if @p does not have language set, language is copied from
* @src.
*
* Since: REPLACEME
**/
void
hb_segment_properties_overlay (hb_segment_properties_t *p,
const hb_segment_properties_t *src)
{
if (unlikely (!p || !src))
return;
if (!p->direction)
p->direction = src->direction;
if (p->direction != src->direction)
return;
if (!p->script)
p->script = src->script;
if (p->script != src->script)
return;
if (!p->language)
p->language = src->language;
}
/* Here is how the buffer works internally:
*
@ -216,12 +255,25 @@ hb_buffer_t::get_scratch_buffer (unsigned int *size)
/* HarfBuzz-Internal API */
void
hb_buffer_t::similar (const hb_buffer_t &src)
{
hb_unicode_funcs_destroy (unicode);
unicode = hb_unicode_funcs_reference (src.unicode);
flags = src.flags;
cluster_level = src.cluster_level;
replacement = src.invisible;
invisible = src.invisible;
not_found = src.not_found;
}
void
hb_buffer_t::reset ()
{
hb_unicode_funcs_destroy (unicode);
unicode = hb_unicode_funcs_reference (hb_unicode_funcs_get_default ());
flags = HB_BUFFER_FLAG_DEFAULT;
cluster_level = HB_BUFFER_CLUSTER_LEVEL_DEFAULT;
replacement = HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT;
invisible = 0;
not_found = 0;
@ -232,11 +284,10 @@ hb_buffer_t::reset ()
void
hb_buffer_t::clear ()
{
content_type = HB_BUFFER_CONTENT_TYPE_INVALID;
hb_segment_properties_t default_props = HB_SEGMENT_PROPERTIES_DEFAULT;
props = default_props;
scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT;
content_type = HB_BUFFER_CONTENT_TYPE_INVALID;
successful = true;
have_output = false;
have_positions = false;
@ -244,16 +295,44 @@ hb_buffer_t::clear ()
idx = 0;
len = 0;
out_len = 0;
out_info = info;
serial = 0;
out_info = info;
memset (context, 0, sizeof context);
memset (context_len, 0, sizeof context_len);
deallocate_var_all ();
serial = 0;
scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT;
}
void
hb_buffer_t::enter ()
{
deallocate_var_all ();
serial = 0;
scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT;
if (likely (!hb_unsigned_mul_overflows (len, HB_BUFFER_MAX_LEN_FACTOR)))
{
max_len = hb_max (len * HB_BUFFER_MAX_LEN_FACTOR,
(unsigned) HB_BUFFER_MAX_LEN_MIN);
}
if (likely (!hb_unsigned_mul_overflows (len, HB_BUFFER_MAX_OPS_FACTOR)))
{
max_ops = hb_max (len * HB_BUFFER_MAX_OPS_FACTOR,
(unsigned) HB_BUFFER_MAX_OPS_MIN);
}
}
void
hb_buffer_t::leave ()
{
max_len = HB_BUFFER_MAX_LEN_DEFAULT;
max_ops = HB_BUFFER_MAX_OPS_DEFAULT;
deallocate_var_all ();
serial = 0;
}
void
hb_buffer_t::add (hb_codepoint_t codepoint,
unsigned int cluster)
@ -565,12 +644,11 @@ DEFINE_NULL_INSTANCE (hb_buffer_t) =
HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT,
0, /* invisible */
0, /* not_found */
HB_BUFFER_SCRATCH_FLAG_DEFAULT,
HB_BUFFER_MAX_LEN_DEFAULT,
HB_BUFFER_MAX_OPS_DEFAULT,
HB_BUFFER_CONTENT_TYPE_INVALID,
HB_SEGMENT_PROPERTIES_DEFAULT,
false, /* successful */
false, /* have_output */
true /* have_positions */
@ -609,6 +687,47 @@ hb_buffer_create ()
return buffer;
}
/**
* hb_buffer_create_similar:
* @src: An #hb_buffer_t
*
* Resets the buffer to its initial status, as if it was just newly created
* with hb_buffer_create().
*
* Return value: (transfer full):
* A newly allocated #hb_buffer_t, similar to hb_buffer_create(). The only
* difference is that the buffer is configured similarly to @src.
*
* Since: REPLACEME
**/
hb_buffer_t *
hb_buffer_create_similar (const hb_buffer_t *src)
{
hb_buffer_t *buffer = hb_buffer_create ();
buffer->similar (*src);
return buffer;
}
/**
* hb_buffer_reset:
* @buffer: An #hb_buffer_t
*
* Resets the buffer to its initial status, as if it was just newly created
* with hb_buffer_create().
*
* Since: 0.9.2
**/
void
hb_buffer_reset (hb_buffer_t *buffer)
{
if (unlikely (hb_object_is_immutable (buffer)))
return;
buffer->reset ();
}
/**
* hb_buffer_get_empty:
*
@ -1156,24 +1275,6 @@ hb_buffer_get_not_found_glyph (hb_buffer_t *buffer)
}
/**
* hb_buffer_reset:
* @buffer: An #hb_buffer_t
*
* Resets the buffer to its initial status, as if it was just newly created
* with hb_buffer_create().
*
* Since: 0.9.2
**/
void
hb_buffer_reset (hb_buffer_t *buffer)
{
if (unlikely (hb_object_is_immutable (buffer)))
return;
buffer->reset ();
}
/**
* hb_buffer_clear_contents:
* @buffer: An #hb_buffer_t
@ -1749,6 +1850,8 @@ hb_buffer_append (hb_buffer_t *buffer,
if (!buffer->have_positions && source->have_positions)
buffer->clear_positions ();
hb_segment_properties_overlay (&buffer->props, &source->props);
memcpy (buffer->info + orig_len, source->info + start, (end - start) * sizeof (buffer->info[0]));
if (buffer->have_positions)
memcpy (buffer->pos + orig_len, source->pos + start, (end - start) * sizeof (buffer->pos[0]));

View File

@ -170,6 +170,9 @@ hb_segment_properties_equal (const hb_segment_properties_t *a,
HB_EXTERN unsigned int
hb_segment_properties_hash (const hb_segment_properties_t *p);
HB_EXTERN void
hb_segment_properties_overlay (hb_segment_properties_t *p,
const hb_segment_properties_t *src);
/**
@ -184,6 +187,13 @@ typedef struct hb_buffer_t hb_buffer_t;
HB_EXTERN hb_buffer_t *
hb_buffer_create (void);
HB_EXTERN hb_buffer_t *
hb_buffer_create_similar (const hb_buffer_t *src);
HB_EXTERN void
hb_buffer_reset (hb_buffer_t *buffer);
HB_EXTERN hb_buffer_t *
hb_buffer_get_empty (void);
@ -391,8 +401,9 @@ HB_EXTERN hb_codepoint_t
hb_buffer_get_not_found_glyph (hb_buffer_t *buffer);
HB_EXTERN void
hb_buffer_reset (hb_buffer_t *buffer);
/*
* Content API.
*/
HB_EXTERN void
hb_buffer_clear_contents (hb_buffer_t *buffer);

View File

@ -87,18 +87,21 @@ struct hb_buffer_t
{
hb_object_header_t header;
/* Information about how the text in the buffer should be treated */
/*
* Information about how the text in the buffer should be treated.
*/
hb_unicode_funcs_t *unicode; /* Unicode functions */
hb_buffer_flags_t flags; /* BOT / EOT / etc. */
hb_buffer_cluster_level_t cluster_level;
hb_codepoint_t replacement; /* U+FFFD or something else. */
hb_codepoint_t invisible; /* 0 or something else. */
hb_codepoint_t not_found; /* 0 or something else. */
hb_buffer_scratch_flags_t scratch_flags; /* Have space-fallback, etc. */
unsigned int max_len; /* Maximum allowed len. */
int max_ops; /* Maximum allowed operations. */
/* Buffer contents */
/*
* Buffer contents
*/
hb_buffer_content_type_t content_type;
hb_segment_properties_t props; /* Script, language, direction */
@ -115,8 +118,6 @@ struct hb_buffer_t
hb_glyph_info_t *out_info;
hb_glyph_position_t *pos;
unsigned int serial;
/* Text before / after the main buffer contents.
* Always in Unicode, and ordered outward.
* Index 0 is for "pre-context", 1 for "post-context". */
@ -124,7 +125,25 @@ struct hb_buffer_t
hb_codepoint_t context[2][CONTEXT_LENGTH];
unsigned int context_len[2];
/* Debugging API */
/*
* Managed by enter / leave
*/
#ifndef HB_NDEBUG
uint8_t allocated_var_bits;
#endif
uint8_t serial;
hb_buffer_scratch_flags_t scratch_flags; /* Have space-fallback, etc. */
unsigned int max_len; /* Maximum allowed len. */
int max_ops; /* Maximum allowed operations. */
/* The bits here reflect current allocations of the bytes in glyph_info_t's var1 and var2. */
/*
* Messaging callback
*/
#ifndef HB_NO_BUFFER_MESSAGE
hb_buffer_message_func_t message_func;
void *message_data;
@ -134,11 +153,6 @@ struct hb_buffer_t
static constexpr unsigned message_depth = 0u;
#endif
/* Internal debugging. */
/* The bits here reflect current allocations of the bytes in glyph_info_t's var1 and var2. */
#ifndef HB_NDEBUG
uint8_t allocated_var_bits;
#endif
/* Methods */
@ -190,12 +204,17 @@ struct hb_buffer_t
hb_glyph_info_t &prev () { return out_info[out_len ? out_len - 1 : 0]; }
hb_glyph_info_t prev () const { return out_info[out_len ? out_len - 1 : 0]; }
HB_INTERNAL void similar (const hb_buffer_t &src);
HB_INTERNAL void reset ();
HB_INTERNAL void clear ();
/* Called around shape() */
HB_INTERNAL void enter ();
HB_INTERNAL void leave ();
unsigned int backtrack_len () const { return have_output ? out_len : idx; }
unsigned int lookahead_len () const { return len - idx; }
unsigned int next_serial () { return serial++; }
uint8_t next_serial () { return ++serial ? serial : ++serial; }
HB_INTERNAL void add (hb_codepoint_t codepoint,
unsigned int cluster);

View File

@ -482,10 +482,9 @@ _hb_glyph_info_get_lig_num_comps (const hb_glyph_info_t *info)
}
static inline uint8_t
_hb_allocate_lig_id (hb_buffer_t *buffer) {
_hb_allocate_lig_id (hb_buffer_t *buffer)
{
uint8_t lig_id = buffer->next_serial () & 0x07;
if (unlikely (!lig_id))
lig_id = _hb_allocate_lig_id (buffer); /* in case of overflow */
return lig_id;
}

View File

@ -1145,18 +1145,7 @@ hb_propagate_flags (hb_buffer_t *buffer)
static void
hb_ot_shape_internal (hb_ot_shape_context_t *c)
{
c->buffer->deallocate_var_all ();
c->buffer->scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT;
if (likely (!hb_unsigned_mul_overflows (c->buffer->len, HB_BUFFER_MAX_LEN_FACTOR)))
{
c->buffer->max_len = hb_max (c->buffer->len * HB_BUFFER_MAX_LEN_FACTOR,
(unsigned) HB_BUFFER_MAX_LEN_MIN);
}
if (likely (!hb_unsigned_mul_overflows (c->buffer->len, HB_BUFFER_MAX_OPS_FACTOR)))
{
c->buffer->max_ops = hb_max (c->buffer->len * HB_BUFFER_MAX_OPS_FACTOR,
(unsigned) HB_BUFFER_MAX_OPS_MIN);
}
c->buffer->enter ();
/* Save the original direction, we use it later. */
c->target_direction = c->buffer->props.direction;
@ -1188,9 +1177,7 @@ hb_ot_shape_internal (hb_ot_shape_context_t *c)
c->buffer->props.direction = c->target_direction;
c->buffer->max_len = HB_BUFFER_MAX_LEN_DEFAULT;
c->buffer->max_ops = HB_BUFFER_MAX_OPS_DEFAULT;
c->buffer->deallocate_var_all ();
c->buffer->leave ();
}

View File

@ -60,15 +60,6 @@ struct shape_options_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)
{
@ -183,9 +174,8 @@ struct shape_options_t
/* 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);
hb_buffer_t *fragment = hb_buffer_create_similar (buffer);
hb_buffer_t *reconstruction = hb_buffer_create_similar (buffer);
unsigned int num_glyphs;
hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, &num_glyphs);
@ -234,7 +224,6 @@ struct shape_options_t
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_flags_t flags = hb_buffer_get_flags (fragment);
if (0 < text_start)