#ifndef HB_BUFFER_HH
#define HB_BUFFER_HH
#include "hb.hh"
#include "hb-unicode.hh"
#ifndef HB_BUFFER_MAX_LEN_FACTOR
#define HB_BUFFER_MAX_LEN_FACTOR 32
#endif
#ifndef HB_BUFFER_MAX_LEN_MIN
#define HB_BUFFER_MAX_LEN_MIN 8192
#endif
#ifndef HB_BUFFER_MAX_LEN_DEFAULT
#define HB_BUFFER_MAX_LEN_DEFAULT 0x3FFFFFFF
#endif
#ifndef HB_BUFFER_MAX_OPS_FACTOR
#define HB_BUFFER_MAX_OPS_FACTOR 64
#endif
#ifndef HB_BUFFER_MAX_OPS_MIN
#define HB_BUFFER_MAX_OPS_MIN 1024
#endif
#ifndef HB_BUFFER_MAX_OPS_DEFAULT
#define HB_BUFFER_MAX_OPS_DEFAULT 0x1FFFFFFF
#endif
static_assert ((sizeof (hb_glyph_info_t) == 20), "");
static_assert ((sizeof (hb_glyph_info_t) == sizeof (hb_glyph_position_t)), "");
HB_MARK_AS_FLAG_T (hb_buffer_flags_t);
HB_MARK_AS_FLAG_T (hb_buffer_serialize_flags_t);
HB_MARK_AS_FLAG_T (hb_buffer_diff_flags_t);
enum hb_buffer_scratch_flags_t {
HB_BUFFER_SCRATCH_FLAG_DEFAULT = 0x00000000u,
HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII = 0x00000001u,
HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES = 0x00000002u,
HB_BUFFER_SCRATCH_FLAG_HAS_SPACE_FALLBACK = 0x00000004u,
HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT = 0x00000008u,
HB_BUFFER_SCRATCH_FLAG_HAS_UNSAFE_TO_BREAK = 0x00000010u,
HB_BUFFER_SCRATCH_FLAG_HAS_CGJ = 0x00000020u,
HB_BUFFER_SCRATCH_FLAG_COMPLEX0 = 0x01000000u,
HB_BUFFER_SCRATCH_FLAG_COMPLEX1 = 0x02000000u,
HB_BUFFER_SCRATCH_FLAG_COMPLEX2 = 0x04000000u,
HB_BUFFER_SCRATCH_FLAG_COMPLEX3 = 0x08000000u,
};
HB_MARK_AS_FLAG_T (hb_buffer_scratch_flags_t);
struct hb_buffer_t
{
hb_object_header_t header;
hb_unicode_funcs_t *unicode;
hb_buffer_flags_t flags;
hb_buffer_cluster_level_t cluster_level;
hb_codepoint_t replacement;
hb_codepoint_t invisible;
hb_buffer_scratch_flags_t scratch_flags;
unsigned int max_len;
int max_ops;
hb_buffer_content_type_t content_type;
hb_segment_properties_t props;
bool successful;
bool have_output;
bool have_positions;
unsigned int idx;
unsigned int len;
unsigned int out_len;
unsigned int allocated;
hb_glyph_info_t *info;
hb_glyph_info_t *out_info;
hb_glyph_position_t *pos;
unsigned int serial;
static constexpr unsigned CONTEXT_LENGTH = 5u;
hb_codepoint_t context[2][CONTEXT_LENGTH];
unsigned int context_len[2];
#ifndef HB_NO_BUFFER_MESSAGE
hb_buffer_message_func_t message_func;
void *message_data;
hb_destroy_func_t message_destroy;
#endif
#ifndef HB_NDEBUG
uint8_t allocated_var_bits;
#endif
bool in_error () const { return !successful; }
void allocate_var (unsigned int start, unsigned int count)
{
#ifndef HB_NDEBUG
unsigned int end = start + count;
assert (end <= 8);
unsigned int bits = (1u<<end) - (1u<<start);
assert (0 == (allocated_var_bits & bits));
allocated_var_bits |= bits;
#endif
}
void deallocate_var (unsigned int start, unsigned int count)
{
#ifndef HB_NDEBUG
unsigned int end = start + count;
assert (end <= 8);
unsigned int bits = (1u<<end) - (1u<<start);
assert (bits == (allocated_var_bits & bits));
allocated_var_bits &= ~bits;
#endif
}
void assert_var (unsigned int start, unsigned int count)
{
#ifndef HB_NDEBUG
unsigned int end = start + count;
assert (end <= 8);
unsigned int bits = (1u<<end) - (1u<<start);
assert (bits == (allocated_var_bits & bits));
#endif
}
void deallocate_var_all ()
{
#ifndef HB_NDEBUG
allocated_var_bits = 0;
#endif
}
hb_glyph_info_t &cur (unsigned int i = 0) { return info[idx + i]; }
hb_glyph_info_t cur (unsigned int i = 0) const { return info[idx + i]; }
hb_glyph_position_t &cur_pos (unsigned int i = 0) { return pos[idx + i]; }
hb_glyph_position_t cur_pos (unsigned int i = 0) const { return pos[idx + i]; }
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]; }
bool has_separate_output () const { return info != out_info; }
HB_INTERNAL void reset ();
HB_INTERNAL void clear ();
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++; }
HB_INTERNAL void add (hb_codepoint_t codepoint,
unsigned int cluster);
HB_INTERNAL void add_info (const hb_glyph_info_t &glyph_info);
HB_INTERNAL void reverse_range (unsigned int start, unsigned int end);
HB_INTERNAL void reverse ();
HB_INTERNAL void reverse_clusters ();
HB_INTERNAL void guess_segment_properties ();
HB_INTERNAL void swap_buffers ();
HB_INTERNAL void remove_output ();
HB_INTERNAL void clear_output ();
HB_INTERNAL void clear_positions ();
HB_INTERNAL void replace_glyphs (unsigned int num_in,
unsigned int num_out,
const hb_codepoint_t *glyph_data);
void replace_glyph (hb_codepoint_t glyph_index)
{
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++;
}
hb_glyph_info_t & output_glyph (hb_codepoint_t glyph_index)
{
if (unlikely (!make_room_for (0, 1))) return Crap(hb_glyph_info_t);
if (unlikely (idx == len && !out_len))
return Crap(hb_glyph_info_t);
out_info[out_len] = idx < len ? info[idx] : out_info[out_len - 1];
out_info[out_len].codepoint = glyph_index;
out_len++;
return out_info[out_len - 1];
}
void output_info (const hb_glyph_info_t &glyph_info)
{
if (unlikely (!make_room_for (0, 1))) return;
out_info[out_len] = glyph_info;
out_len++;
}
void copy_glyph ()
{
if (unlikely (!make_room_for (0, 1))) return;
out_info[out_len] = info[idx];
out_len++;
}
void
next_glyph ()
{
if (have_output)
{
if (out_info != info || out_len != idx)
{
if (unlikely (!make_room_for (1, 1))) return;
out_info[out_len] = info[idx];
}
out_len++;
}
idx++;
}
void
next_glyphs (unsigned int n)
{
if (have_output)
{
if (out_info != info || out_len != idx)
{
if (unlikely (!make_room_for (n, n))) return;
memmove (out_info + out_len, info + idx, n * sizeof (out_info[0]));
}
out_len += n;
}
idx += n;
}
void skip_glyph () { idx++; }
void reset_masks (hb_mask_t mask)
{
for (unsigned int j = 0; j < len; j++)
info[j].mask = mask;
}
void add_masks (hb_mask_t mask)
{
for (unsigned int j = 0; j < len; j++)
info[j].mask |= mask;
}
HB_INTERNAL void set_masks (hb_mask_t value, hb_mask_t mask,
unsigned int cluster_start, unsigned int cluster_end);
void merge_clusters (unsigned int start, unsigned int end)
{
if (end - start < 2)
return;
merge_clusters_impl (start, end);
}
HB_INTERNAL void merge_clusters_impl (unsigned int start, unsigned int end);
HB_INTERNAL void merge_out_clusters (unsigned int start, unsigned int end);
HB_INTERNAL void delete_glyph ();
void unsafe_to_break (unsigned int start,
unsigned int end)
{
if (end - start < 2)
return;
unsafe_to_break_impl (start, end);
}
HB_INTERNAL void unsafe_to_break_impl (unsigned int start, unsigned int end);
HB_INTERNAL void unsafe_to_break_from_outbuffer (unsigned int start, unsigned int end);
HB_INTERNAL bool move_to (unsigned int i);
HB_INTERNAL bool enlarge (unsigned int size);
bool ensure (unsigned int size)
{ return likely (!size || size < allocated) ? true : enlarge (size); }
bool ensure_inplace (unsigned int size)
{ return likely (!size || size < allocated); }
HB_INTERNAL bool make_room_for (unsigned int num_in, unsigned int num_out);
HB_INTERNAL bool shift_forward (unsigned int count);
typedef long scratch_buffer_t;
HB_INTERNAL scratch_buffer_t *get_scratch_buffer (unsigned int *size);
void clear_context (unsigned int side) { context_len[side] = 0; }
HB_INTERNAL void sort (unsigned int start, unsigned int end, int(*compar)(const hb_glyph_info_t *, const hb_glyph_info_t *));
bool messaging ()
{
#ifdef HB_NO_BUFFER_MESSAGE
return false;
#else
return unlikely (message_func);
#endif
}
bool message (hb_font_t *font, const char *fmt, ...) HB_PRINTF_FUNC(3, 4)
{
#ifdef HB_NO_BUFFER_MESSAGE
return true;
#else
if (!messaging ())
return true;
va_list ap;
va_start (ap, fmt);
bool ret = message_impl (font, fmt, ap);
va_end (ap);
return ret;
#endif
}
HB_INTERNAL bool message_impl (hb_font_t *font, const char *fmt, va_list ap) HB_PRINTF_FUNC(3, 0);
static void
set_cluster (hb_glyph_info_t &inf, unsigned int cluster, unsigned int mask = 0)
{
if (inf.cluster != cluster)
{
if (mask & HB_GLYPH_FLAG_UNSAFE_TO_BREAK)
inf.mask |= HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
else
inf.mask &= ~HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
}
inf.cluster = cluster;
}
int
_unsafe_to_break_find_min_cluster (const hb_glyph_info_t *infos,
unsigned int start, unsigned int end,
unsigned int cluster) const
{
for (unsigned int i = start; i < end; i++)
cluster = hb_min (cluster, infos[i].cluster);
return cluster;
}
void
_unsafe_to_break_set_mask (hb_glyph_info_t *infos,
unsigned int start, unsigned int end,
unsigned int cluster)
{
for (unsigned int i = start; i < end; i++)
if (cluster != infos[i].cluster)
{
scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_UNSAFE_TO_BREAK;
infos[i].mask |= HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
}
}
void unsafe_to_break_all () { unsafe_to_break_impl (0, len); }
void safe_to_break_all ()
{
for (unsigned int i = 0; i < len; i++)
info[i].mask &= ~HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
}
};
DECLARE_NULL_INSTANCE (hb_buffer_t);
#define foreach_cluster(buffer, start, end) \
for (unsigned int \
_count = buffer->len, \
start = 0, end = _count ? _next_cluster (buffer, 0) : 0; \
start < _count; \
start = end, end = _next_cluster (buffer, start))
static inline unsigned int
_next_cluster (hb_buffer_t *buffer, unsigned int start)
{
hb_glyph_info_t *info = buffer->info;
unsigned int count = buffer->len;
unsigned int cluster = info[start].cluster;
while (++start < count && cluster == info[start].cluster)
;
return start;
}
#define HB_BUFFER_XALLOCATE_VAR(b, func, var) \
b->func (offsetof (hb_glyph_info_t, var) - offsetof(hb_glyph_info_t, var1), \
sizeof (b->info[0].var))
#define HB_BUFFER_ALLOCATE_VAR(b, var) HB_BUFFER_XALLOCATE_VAR (b, allocate_var, var ())
#define HB_BUFFER_DEALLOCATE_VAR(b, var) HB_BUFFER_XALLOCATE_VAR (b, deallocate_var, var ())
#define HB_BUFFER_ASSERT_VAR(b, var) HB_BUFFER_XALLOCATE_VAR (b, assert_var, var ())
#endif