Bug 1226175 - Update in-tree harfbuzz to release 1.1.0 to pick up Syriac Abbreviation Mark support ('stch' feature). r=jdaggett

This commit is contained in:
Jonathan Kew 2015-11-20 21:49:09 +00:00
parent c31b75ac2a
commit 3aeb07f68e
33 changed files with 1228 additions and 491 deletions

View File

@ -15,6 +15,7 @@ DISTCHECK_CONFIGURE_FLAGS = --enable-introspection
# Convenience targets:
lib: $(BUILT_SOURCES) libharfbuzz.la
fuzzing: $(BUILT_SOURCES) libharfbuzz-fuzzing.la
lib_LTLIBRARIES = libharfbuzz.la
@ -219,6 +220,22 @@ pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = harfbuzz.pc
EXTRA_DIST += harfbuzz.pc.in
FUZZING_CPPFLAGS= \
-DHB_MAX_NESTING_LEVEL=3 \
-DHB_SANITIZE_MAX_EDITS=3 \
-DHB_BUFFER_MAX_EXPANSION_FACTOR=3 \
-DHB_BUFFER_MAX_LEN_MIN=8 \
-DHB_BUFFER_MAX_LEN_DEFAULT=128 \
$(NULL)
EXTRA_LTLIBRARIES = libharfbuzz-fuzzing.la
libharfbuzz_fuzzing_la_LINK = $(libharfbuzz_la_LINK)
libharfbuzz_fuzzing_la_SOURCES = $(libharfbuzz_la_SOURCES)
libharfbuzz_fuzzing_la_CPPFLAGS = $(libharfbuzz_la_CPPFLAGS) $(FUZZING_CPPFLAGS)
libharfbuzz_fuzzing_la_LDFLAGS = $(libharfbuzz_la_LDFLAGS)
libharfbuzz_fuzzing_la_LIBADD = $(libharfbuzz_la_LIBADD)
EXTRA_libharfbuzz_fuzzing_la_DEPENDENCIES = $(EXTRA_libharfbuzz_la_DEPENDENCIES)
CLEANFILES += libharfbuzz-fuzzing.la
if HAVE_ICU
lib_LTLIBRARIES += libharfbuzz-icu.la
libharfbuzz_icu_la_SOURCES = hb-icu.cc

View File

@ -35,9 +35,37 @@
#include "hb-unicode-private.hh"
#ifndef HB_BUFFER_MAX_EXPANSION_FACTOR
#define HB_BUFFER_MAX_EXPANSION_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 /* Shaping more than a billion chars? Let us know! */
#endif
ASSERT_STATIC (sizeof (hb_glyph_info_t) == 20);
ASSERT_STATIC (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);
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_CURSIVE = 0x00000008u,
HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT = 0x00000010u,
/* Reserved for complex shapers' internal use. */
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);
/*
* hb_buffer_t
@ -52,6 +80,8 @@ struct hb_buffer_t {
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_buffer_scratch_flags_t scratch_flags; /* Have space-flallback, etc. */
unsigned int max_len; /* Maximum allowed len. */
/* Buffer contents */
hb_buffer_content_type_t content_type;
@ -76,8 +106,8 @@ struct hb_buffer_t {
inline hb_glyph_position_t &cur_pos (unsigned int i = 0) { return pos[idx + i]; }
inline hb_glyph_position_t cur_pos (unsigned int i = 0) const { return pos[idx + i]; }
inline hb_glyph_info_t &prev (void) { return out_info[out_len - 1]; }
inline hb_glyph_info_t prev (void) const { return info[out_len - 1]; }
inline hb_glyph_info_t &prev (void) { return out_info[out_len ? out_len - 1 : 0]; }
inline hb_glyph_info_t prev (void) const { return out_info[out_len ? out_len - 1 : 0]; }
inline bool has_separate_output (void) const { return info != out_info; }
@ -144,12 +174,13 @@ struct hb_buffer_t {
if (have_output)
{
if (unlikely (out_info != info || out_len != idx)) {
if (unlikely (!make_room_for (1, 1))) return;
if (unlikely (!make_room_for (1, 1)))
goto done;
out_info[out_len] = info[idx];
}
out_len++;
}
done:
idx++;
}

View File

@ -91,6 +91,11 @@ hb_buffer_t::enlarge (unsigned int size)
{
if (unlikely (in_error))
return false;
if (unlikely (size > max_len))
{
in_error = true;
return false;
}
unsigned int new_allocated = allocated;
hb_glyph_position_t *new_pos = NULL;
@ -198,6 +203,7 @@ hb_buffer_t::clear (void)
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;
in_error = false;
@ -318,7 +324,9 @@ hb_buffer_t::replace_glyphs (unsigned int num_in,
unsigned int num_out,
const uint32_t *glyph_data)
{
if (unlikely (!make_room_for (num_in, num_out))) return;
if (unlikely (!make_room_for (num_in, num_out)))
goto done;
{
merge_clusters (idx, idx + num_in);
@ -331,39 +339,50 @@ hb_buffer_t::replace_glyphs (unsigned int num_in,
pinfo++;
}
idx += num_in;
out_len += num_out;
}
done:
idx += num_in;
}
void
hb_buffer_t::output_glyph (hb_codepoint_t glyph_index)
{
if (unlikely (!make_room_for (0, 1))) return;
if (unlikely (!make_room_for (0, 1)))
goto done;
out_info[out_len] = info[idx];
out_info[out_len].codepoint = glyph_index;
out_len++;
done:
;
}
void
hb_buffer_t::output_info (const hb_glyph_info_t &glyph_info)
{
if (unlikely (!make_room_for (0, 1))) return;
if (unlikely (!make_room_for (0, 1)))
goto done;
out_info[out_len] = glyph_info;
out_len++;
done:
;
}
void
hb_buffer_t::copy_glyph (void)
{
if (unlikely (!make_room_for (0, 1))) return;
if (unlikely (!make_room_for (0, 1)))
goto done;
out_info[out_len] = info[idx];
out_len++;
done:
;
}
bool
@ -381,7 +400,7 @@ hb_buffer_t::move_to (unsigned int i)
if (out_len < i)
{
unsigned int count = i - out_len;
if (unlikely (!make_room_for (count, count))) return false;
if (unlikely (!make_room_for (count, count))) return false; // XXX verify bailout
memmove (out_info + out_len, info + idx, count * sizeof (out_info[0]));
idx += count;
@ -408,13 +427,15 @@ void
hb_buffer_t::replace_glyph (hb_codepoint_t glyph_index)
{
if (unlikely (out_info != info || out_len != idx)) {
if (unlikely (!make_room_for (1, 1))) return;
if (unlikely (!make_room_for (1, 1)))
goto out;
out_info[out_len] = info[idx];
}
out_info[out_len].codepoint = glyph_index;
idx++;
out_len++;
out:
idx++;
}
@ -714,6 +735,8 @@ hb_buffer_create (void)
if (!(buffer = hb_object_create<hb_buffer_t> ()))
return hb_buffer_get_empty ();
buffer->max_len = HB_BUFFER_MAX_LEN_DEFAULT;
buffer->reset ();
return buffer;
@ -738,6 +761,8 @@ hb_buffer_get_empty (void)
HB_BUFFER_FLAG_DEFAULT,
HB_BUFFER_CLUSTER_LEVEL_DEFAULT,
HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT,
HB_BUFFER_SCRATCH_FLAG_DEFAULT,
HB_BUFFER_MAX_LEN_DEFAULT,
HB_BUFFER_CONTENT_TYPE_INVALID,
HB_SEGMENT_PROPERTIES_DEFAULT,

View File

@ -61,14 +61,6 @@ struct hb_font_funcs_t {
hb_bool_t immutable;
/* Don't access these directly. Call hb_font_get_*() instead. */
struct {
#define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_func_t name;
HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_FONT_FUNC_IMPLEMENT
} get;
struct {
#define HB_FONT_FUNC_IMPLEMENT(name) void *name;
HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
@ -80,6 +72,16 @@ struct hb_font_funcs_t {
HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_FONT_FUNC_IMPLEMENT
} destroy;
/* Don't access these directly. Call font->get_*() instead. */
union get_t {
struct get_funcs_t {
#define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_func_t name;
HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_FONT_FUNC_IMPLEMENT
} f;
void (*array[]) (void);
} get;
};
@ -144,6 +146,20 @@ struct hb_font_t {
/* Public getters */
HB_INTERNAL bool has_func (unsigned int i);
/* has_* ... */
#define HB_FONT_FUNC_IMPLEMENT(name) \
bool \
has_##name##_func (void) \
{ \
hb_font_funcs_t *funcs = this->klass; \
unsigned int i = offsetof (hb_font_funcs_t::get_t::get_funcs_t, name) / sizeof (funcs->get.array[0]); \
return has_func (i); \
}
HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_FONT_FUNC_IMPLEMENT
inline hb_bool_t has_glyph (hb_codepoint_t unicode)
{
hb_codepoint_t glyph;
@ -154,85 +170,85 @@ struct hb_font_t {
hb_codepoint_t *glyph)
{
*glyph = 0;
return klass->get.glyph (this, user_data,
unicode, variation_selector, glyph,
klass->user_data.glyph);
return klass->get.f.glyph (this, user_data,
unicode, variation_selector, glyph,
klass->user_data.glyph);
}
inline hb_position_t get_glyph_h_advance (hb_codepoint_t glyph)
{
return klass->get.glyph_h_advance (this, user_data,
glyph,
klass->user_data.glyph_h_advance);
return klass->get.f.glyph_h_advance (this, user_data,
glyph,
klass->user_data.glyph_h_advance);
}
inline hb_position_t get_glyph_v_advance (hb_codepoint_t glyph)
{
return klass->get.glyph_v_advance (this, user_data,
glyph,
klass->user_data.glyph_v_advance);
return klass->get.f.glyph_v_advance (this, user_data,
glyph,
klass->user_data.glyph_v_advance);
}
inline hb_bool_t get_glyph_h_origin (hb_codepoint_t glyph,
hb_position_t *x, hb_position_t *y)
{
*x = *y = 0;
return klass->get.glyph_h_origin (this, user_data,
glyph, x, y,
klass->user_data.glyph_h_origin);
return klass->get.f.glyph_h_origin (this, user_data,
glyph, x, y,
klass->user_data.glyph_h_origin);
}
inline hb_bool_t get_glyph_v_origin (hb_codepoint_t glyph,
hb_position_t *x, hb_position_t *y)
{
*x = *y = 0;
return klass->get.glyph_v_origin (this, user_data,
glyph, x, y,
klass->user_data.glyph_v_origin);
return klass->get.f.glyph_v_origin (this, user_data,
glyph, x, y,
klass->user_data.glyph_v_origin);
}
inline hb_position_t get_glyph_h_kerning (hb_codepoint_t left_glyph, hb_codepoint_t right_glyph)
{
return klass->get.glyph_h_kerning (this, user_data,
left_glyph, right_glyph,
klass->user_data.glyph_h_kerning);
return klass->get.f.glyph_h_kerning (this, user_data,
left_glyph, right_glyph,
klass->user_data.glyph_h_kerning);
}
inline hb_position_t get_glyph_v_kerning (hb_codepoint_t top_glyph, hb_codepoint_t bottom_glyph)
{
return klass->get.glyph_v_kerning (this, user_data,
top_glyph, bottom_glyph,
klass->user_data.glyph_v_kerning);
return klass->get.f.glyph_v_kerning (this, user_data,
top_glyph, bottom_glyph,
klass->user_data.glyph_v_kerning);
}
inline hb_bool_t get_glyph_extents (hb_codepoint_t glyph,
hb_glyph_extents_t *extents)
{
memset (extents, 0, sizeof (*extents));
return klass->get.glyph_extents (this, user_data,
glyph,
extents,
klass->user_data.glyph_extents);
return klass->get.f.glyph_extents (this, user_data,
glyph,
extents,
klass->user_data.glyph_extents);
}
inline hb_bool_t get_glyph_contour_point (hb_codepoint_t glyph, unsigned int point_index,
hb_position_t *x, hb_position_t *y)
{
*x = *y = 0;
return klass->get.glyph_contour_point (this, user_data,
glyph, point_index,
x, y,
klass->user_data.glyph_contour_point);
return klass->get.f.glyph_contour_point (this, user_data,
glyph, point_index,
x, y,
klass->user_data.glyph_contour_point);
}
inline hb_bool_t get_glyph_name (hb_codepoint_t glyph,
char *name, unsigned int size)
{
if (size) *name = '\0';
return klass->get.glyph_name (this, user_data,
glyph,
name, size,
klass->user_data.glyph_name);
return klass->get.f.glyph_name (this, user_data,
glyph,
name, size,
klass->user_data.glyph_name);
}
inline hb_bool_t get_glyph_from_name (const char *name, int len, /* -1 means nul-terminated */
@ -240,10 +256,10 @@ struct hb_font_t {
{
*glyph = 0;
if (len == -1) len = strlen (name);
return klass->get.glyph_from_name (this, user_data,
name, len,
glyph,
klass->user_data.glyph_from_name);
return klass->get.f.glyph_from_name (this, user_data,
name, len,
glyph,
klass->user_data.glyph_from_name);
}
@ -298,6 +314,26 @@ struct hb_font_t {
}
}
inline void add_glyph_h_origin (hb_codepoint_t glyph,
hb_position_t *x, hb_position_t *y)
{
hb_position_t origin_x, origin_y;
get_glyph_h_origin (glyph, &origin_x, &origin_y);
*x += origin_x;
*y += origin_y;
}
inline void add_glyph_v_origin (hb_codepoint_t glyph,
hb_position_t *x, hb_position_t *y)
{
hb_position_t origin_x, origin_y;
get_glyph_v_origin (glyph, &origin_x, &origin_y);
*x += origin_x;
*y += origin_y;
}
inline void add_glyph_origin_for_direction (hb_codepoint_t glyph,
hb_direction_t direction,
hb_position_t *x, hb_position_t *y)
@ -310,6 +346,26 @@ struct hb_font_t {
*y += origin_y;
}
inline void subtract_glyph_h_origin (hb_codepoint_t glyph,
hb_position_t *x, hb_position_t *y)
{
hb_position_t origin_x, origin_y;
get_glyph_h_origin (glyph, &origin_x, &origin_y);
*x -= origin_x;
*y -= origin_y;
}
inline void subtract_glyph_v_origin (hb_codepoint_t glyph,
hb_position_t *x, hb_position_t *y)
{
hb_position_t origin_x, origin_y;
get_glyph_v_origin (glyph, &origin_x, &origin_y);
*x -= origin_x;
*y -= origin_y;
}
inline void subtract_glyph_origin_for_direction (hb_codepoint_t glyph,
hb_direction_t direction,
hb_position_t *x, hb_position_t *y)

View File

@ -45,130 +45,176 @@
*/
static hb_bool_t
hb_font_get_glyph_nil (hb_font_t *font,
hb_font_get_glyph_nil (hb_font_t *font HB_UNUSED,
void *font_data HB_UNUSED,
hb_codepoint_t unicode,
hb_codepoint_t variation_selector,
hb_codepoint_t *glyph,
void *user_data HB_UNUSED)
{
if (font->parent)
return font->parent->get_glyph (unicode, variation_selector, glyph);
*glyph = 0;
return false;
}
static hb_bool_t
hb_font_get_glyph_parent (hb_font_t *font,
void *font_data HB_UNUSED,
hb_codepoint_t unicode,
hb_codepoint_t variation_selector,
hb_codepoint_t *glyph,
void *user_data HB_UNUSED)
{
return font->parent->get_glyph (unicode, variation_selector, glyph);
}
static hb_position_t
hb_font_get_glyph_h_advance_nil (hb_font_t *font,
hb_font_get_glyph_h_advance_nil (hb_font_t *font HB_UNUSED,
void *font_data HB_UNUSED,
hb_codepoint_t glyph,
void *user_data HB_UNUSED)
{
if (font->parent)
return font->parent_scale_x_distance (font->parent->get_glyph_h_advance (glyph));
return font->x_scale;
}
static hb_position_t
hb_font_get_glyph_h_advance_parent (hb_font_t *font,
void *font_data HB_UNUSED,
hb_codepoint_t glyph,
void *user_data HB_UNUSED)
{
return font->parent_scale_x_distance (font->parent->get_glyph_h_advance (glyph));
}
static hb_position_t
hb_font_get_glyph_v_advance_nil (hb_font_t *font,
hb_font_get_glyph_v_advance_nil (hb_font_t *font HB_UNUSED,
void *font_data HB_UNUSED,
hb_codepoint_t glyph,
void *user_data HB_UNUSED)
{
if (font->parent)
return font->parent_scale_y_distance (font->parent->get_glyph_v_advance (glyph));
return font->y_scale;
}
static hb_bool_t
hb_font_get_glyph_h_origin_nil (hb_font_t *font,
void *font_data HB_UNUSED,
hb_codepoint_t glyph,
hb_position_t *x,
hb_position_t *y,
void *user_data HB_UNUSED)
static hb_position_t
hb_font_get_glyph_v_advance_parent (hb_font_t *font,
void *font_data HB_UNUSED,
hb_codepoint_t glyph,
void *user_data HB_UNUSED)
{
if (font->parent) {
hb_bool_t ret = font->parent->get_glyph_h_origin (glyph, x, y);
if (ret)
font->parent_scale_position (x, y);
return ret;
}
*x = *y = 0;
return false;
return font->parent_scale_y_distance (font->parent->get_glyph_v_advance (glyph));
}
static hb_bool_t
hb_font_get_glyph_v_origin_nil (hb_font_t *font,
hb_font_get_glyph_h_origin_nil (hb_font_t *font HB_UNUSED,
void *font_data HB_UNUSED,
hb_codepoint_t glyph,
hb_position_t *x,
hb_position_t *y,
void *user_data HB_UNUSED)
{
if (font->parent) {
hb_bool_t ret = font->parent->get_glyph_v_origin (glyph, x, y);
if (ret)
font->parent_scale_position (x, y);
return ret;
}
*x = *y = 0;
return false;
}
static hb_bool_t
hb_font_get_glyph_h_origin_parent (hb_font_t *font,
void *font_data HB_UNUSED,
hb_codepoint_t glyph,
hb_position_t *x,
hb_position_t *y,
void *user_data HB_UNUSED)
{
hb_bool_t ret = font->parent->get_glyph_h_origin (glyph, x, y);
if (ret)
font->parent_scale_position (x, y);
return ret;
}
static hb_bool_t
hb_font_get_glyph_v_origin_nil (hb_font_t *font HB_UNUSED,
void *font_data HB_UNUSED,
hb_codepoint_t glyph,
hb_position_t *x,
hb_position_t *y,
void *user_data HB_UNUSED)
{
*x = *y = 0;
return false;
}
static hb_bool_t
hb_font_get_glyph_v_origin_parent (hb_font_t *font,
void *font_data HB_UNUSED,
hb_codepoint_t glyph,
hb_position_t *x,
hb_position_t *y,
void *user_data HB_UNUSED)
{
hb_bool_t ret = font->parent->get_glyph_v_origin (glyph, x, y);
if (ret)
font->parent_scale_position (x, y);
return ret;
}
static hb_position_t
hb_font_get_glyph_h_kerning_nil (hb_font_t *font,
hb_font_get_glyph_h_kerning_nil (hb_font_t *font HB_UNUSED,
void *font_data HB_UNUSED,
hb_codepoint_t left_glyph,
hb_codepoint_t right_glyph,
void *user_data HB_UNUSED)
{
if (font->parent)
return font->parent_scale_x_distance (font->parent->get_glyph_h_kerning (left_glyph, right_glyph));
return 0;
}
static hb_position_t
hb_font_get_glyph_h_kerning_parent (hb_font_t *font,
void *font_data HB_UNUSED,
hb_codepoint_t left_glyph,
hb_codepoint_t right_glyph,
void *user_data HB_UNUSED)
{
return font->parent_scale_x_distance (font->parent->get_glyph_h_kerning (left_glyph, right_glyph));
}
static hb_position_t
hb_font_get_glyph_v_kerning_nil (hb_font_t *font,
hb_font_get_glyph_v_kerning_nil (hb_font_t *font HB_UNUSED,
void *font_data HB_UNUSED,
hb_codepoint_t top_glyph,
hb_codepoint_t bottom_glyph,
void *user_data HB_UNUSED)
{
if (font->parent)
return font->parent_scale_y_distance (font->parent->get_glyph_v_kerning (top_glyph, bottom_glyph));
return 0;
}
static hb_position_t
hb_font_get_glyph_v_kerning_parent (hb_font_t *font,
void *font_data HB_UNUSED,
hb_codepoint_t top_glyph,
hb_codepoint_t bottom_glyph,
void *user_data HB_UNUSED)
{
return font->parent_scale_y_distance (font->parent->get_glyph_v_kerning (top_glyph, bottom_glyph));
}
static hb_bool_t
hb_font_get_glyph_extents_nil (hb_font_t *font,
hb_font_get_glyph_extents_nil (hb_font_t *font HB_UNUSED,
void *font_data HB_UNUSED,
hb_codepoint_t glyph,
hb_glyph_extents_t *extents,
void *user_data HB_UNUSED)
{
if (font->parent) {
hb_bool_t ret = font->parent->get_glyph_extents (glyph, extents);
if (ret) {
font->parent_scale_position (&extents->x_bearing, &extents->y_bearing);
font->parent_scale_distance (&extents->width, &extents->height);
}
return ret;
}
memset (extents, 0, sizeof (*extents));
return false;
}
static hb_bool_t
hb_font_get_glyph_extents_parent (hb_font_t *font,
void *font_data HB_UNUSED,
hb_codepoint_t glyph,
hb_glyph_extents_t *extents,
void *user_data HB_UNUSED)
{
hb_bool_t ret = font->parent->get_glyph_extents (glyph, extents);
if (ret) {
font->parent_scale_position (&extents->x_bearing, &extents->y_bearing);
font->parent_scale_distance (&extents->width, &extents->height);
}
return ret;
}
static hb_bool_t
hb_font_get_glyph_contour_point_nil (hb_font_t *font,
hb_font_get_glyph_contour_point_nil (hb_font_t *font HB_UNUSED,
void *font_data HB_UNUSED,
hb_codepoint_t glyph,
unsigned int point_index,
@ -176,44 +222,63 @@ hb_font_get_glyph_contour_point_nil (hb_font_t *font,
hb_position_t *y,
void *user_data HB_UNUSED)
{
if (font->parent) {
hb_bool_t ret = font->parent->get_glyph_contour_point (glyph, point_index, x, y);
if (ret)
font->parent_scale_position (x, y);
return ret;
}
*x = *y = 0;
return false;
}
static hb_bool_t
hb_font_get_glyph_contour_point_parent (hb_font_t *font,
void *font_data HB_UNUSED,
hb_codepoint_t glyph,
unsigned int point_index,
hb_position_t *x,
hb_position_t *y,
void *user_data HB_UNUSED)
{
hb_bool_t ret = font->parent->get_glyph_contour_point (glyph, point_index, x, y);
if (ret)
font->parent_scale_position (x, y);
return ret;
}
static hb_bool_t
hb_font_get_glyph_name_nil (hb_font_t *font,
hb_font_get_glyph_name_nil (hb_font_t *font HB_UNUSED,
void *font_data HB_UNUSED,
hb_codepoint_t glyph,
char *name, unsigned int size,
void *user_data HB_UNUSED)
{
if (font->parent)
return font->parent->get_glyph_name (glyph, name, size);
if (size) *name = '\0';
return false;
}
static hb_bool_t
hb_font_get_glyph_name_parent (hb_font_t *font,
void *font_data HB_UNUSED,
hb_codepoint_t glyph,
char *name, unsigned int size,
void *user_data HB_UNUSED)
{
return font->parent->get_glyph_name (glyph, name, size);
}
static hb_bool_t
hb_font_get_glyph_from_name_nil (hb_font_t *font,
hb_font_get_glyph_from_name_nil (hb_font_t *font HB_UNUSED,
void *font_data HB_UNUSED,
const char *name, int len, /* -1 means nul-terminated */
hb_codepoint_t *glyph,
void *user_data HB_UNUSED)
{
if (font->parent)
return font->parent->get_glyph_from_name (name, len, glyph);
*glyph = 0;
return false;
}
static hb_bool_t
hb_font_get_glyph_from_name_parent (hb_font_t *font,
void *font_data HB_UNUSED,
const char *name, int len, /* -1 means nul-terminated */
hb_codepoint_t *glyph,
void *user_data HB_UNUSED)
{
return font->parent->get_glyph_from_name (name, len, glyph);
}
static const hb_font_funcs_t _hb_font_funcs_nil = {
@ -222,9 +287,44 @@ static const hb_font_funcs_t _hb_font_funcs_nil = {
true, /* immutable */
{
#define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_nil,
#define HB_FONT_FUNC_IMPLEMENT(name) NULL,
HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_FONT_FUNC_IMPLEMENT
},
{
#define HB_FONT_FUNC_IMPLEMENT(name) NULL,
HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_FONT_FUNC_IMPLEMENT
},
{
{
#define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_nil,
HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_FONT_FUNC_IMPLEMENT
}
}
};
static const hb_font_funcs_t _hb_font_funcs_parent = {
HB_OBJECT_HEADER_STATIC,
true, /* immutable */
{
#define HB_FONT_FUNC_IMPLEMENT(name) NULL,
HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_FONT_FUNC_IMPLEMENT
},
{
#define HB_FONT_FUNC_IMPLEMENT(name) NULL,
HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_FONT_FUNC_IMPLEMENT
},
{
{
#define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_parent,
HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_FONT_FUNC_IMPLEMENT
}
}
};
@ -246,7 +346,7 @@ hb_font_funcs_create (void)
if (!(ffuncs = hb_object_create<hb_font_funcs_t> ()))
return hb_font_funcs_get_empty ();
ffuncs->get = _hb_font_funcs_nil.get;
ffuncs->get = _hb_font_funcs_parent.get;
return ffuncs;
}
@ -263,7 +363,7 @@ hb_font_funcs_create (void)
hb_font_funcs_t *
hb_font_funcs_get_empty (void)
{
return const_cast<hb_font_funcs_t *> (&_hb_font_funcs_nil);
return const_cast<hb_font_funcs_t *> (&_hb_font_funcs_parent);
}
/**
@ -398,11 +498,11 @@ hb_font_funcs_set_##name##_func (hb_font_funcs_t *ffuncs, \
ffuncs->destroy.name (ffuncs->user_data.name); \
\
if (func) { \
ffuncs->get.name = func; \
ffuncs->get.f.name = func; \
ffuncs->user_data.name = user_data; \
ffuncs->destroy.name = destroy; \
} else { \
ffuncs->get.name = hb_font_get_##name##_nil; \
ffuncs->get.f.name = hb_font_get_##name##_parent; \
ffuncs->user_data.name = NULL; \
ffuncs->destroy.name = NULL; \
} \
@ -411,6 +511,13 @@ hb_font_funcs_set_##name##_func (hb_font_funcs_t *ffuncs, \
HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_FONT_FUNC_IMPLEMENT
bool
hb_font_t::has_func (unsigned int i)
{
if (parent && parent != hb_font_get_empty () && parent->has_func (i))
return true;
return this->klass->get.array[i] != _hb_font_funcs_parent.get.array[i];
}
/* Public getters */
@ -858,6 +965,7 @@ hb_font_create (hb_face_t *face)
return hb_font_get_empty ();
hb_face_make_immutable (face);
font->parent = hb_font_get_empty ();
font->face = hb_face_reference (face);
font->klass = hb_font_funcs_get_empty ();
@ -917,8 +1025,8 @@ hb_font_get_empty (void)
NULL, /* parent */
const_cast<hb_face_t *> (&_hb_face_nil),
0, /* x_scale */
0, /* y_scale */
1000, /* x_scale */
1000, /* y_scale */
0, /* x_ppem */
0, /* y_ppem */

View File

@ -216,18 +216,6 @@ hb_ft_get_glyph_v_advance (hb_font_t *font HB_UNUSED,
return (-v + (1<<9)) >> 10;
}
static hb_bool_t
hb_ft_get_glyph_h_origin (hb_font_t *font HB_UNUSED,
void *font_data HB_UNUSED,
hb_codepoint_t glyph HB_UNUSED,
hb_position_t *x HB_UNUSED,
hb_position_t *y HB_UNUSED,
void *user_data HB_UNUSED)
{
/* We always work in the horizontal coordinates. */
return true;
}
static hb_bool_t
hb_ft_get_glyph_v_origin (hb_font_t *font HB_UNUSED,
void *font_data,
@ -272,17 +260,6 @@ hb_ft_get_glyph_h_kerning (hb_font_t *font,
return kerningv.x;
}
static hb_position_t
hb_ft_get_glyph_v_kerning (hb_font_t *font HB_UNUSED,
void *font_data HB_UNUSED,
hb_codepoint_t top_glyph HB_UNUSED,
hb_codepoint_t bottom_glyph HB_UNUSED,
void *user_data HB_UNUSED)
{
/* FreeType API doesn't support vertical kerning */
return 0;
}
static hb_bool_t
hb_ft_get_glyph_extents (hb_font_t *font HB_UNUSED,
void *font_data,
@ -300,6 +277,16 @@ hb_ft_get_glyph_extents (hb_font_t *font HB_UNUSED,
extents->y_bearing = ft_face->glyph->metrics.horiBearingY;
extents->width = ft_face->glyph->metrics.width;
extents->height = -ft_face->glyph->metrics.height;
if (font->x_scale < 0)
{
extents->x_bearing = -extents->x_bearing;
extents->width = -extents->width;
}
if (font->y_scale < 0)
{
extents->y_bearing = -extents->y_bearing;
extents->height = -extents->height;
}
return true;
}
@ -380,23 +367,52 @@ hb_ft_get_glyph_from_name (hb_font_t *font HB_UNUSED,
}
static hb_font_funcs_t *static_ft_funcs = NULL;
#ifdef HB_USE_ATEXIT
static
void free_static_ft_funcs (void)
{
hb_font_funcs_destroy (static_ft_funcs);
}
#endif
static void
_hb_ft_font_set_funcs (hb_font_t *font, FT_Face ft_face, bool unref)
{
static const hb_font_funcs_t ft_ffuncs = {
HB_OBJECT_HEADER_STATIC,
retry:
hb_font_funcs_t *funcs = (hb_font_funcs_t *) hb_atomic_ptr_get (&static_ft_funcs);
true, /* immutable */
if (unlikely (!funcs))
{
funcs = hb_font_funcs_create ();
{
#define HB_FONT_FUNC_IMPLEMENT(name) hb_ft_get_##name,
HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_FONT_FUNC_IMPLEMENT
hb_font_funcs_set_glyph_func (funcs, hb_ft_get_glyph, NULL, NULL);
hb_font_funcs_set_glyph_h_advance_func (funcs, hb_ft_get_glyph_h_advance, NULL, NULL);
hb_font_funcs_set_glyph_v_advance_func (funcs, hb_ft_get_glyph_v_advance, NULL, NULL);
//hb_font_funcs_set_glyph_h_origin_func (funcs, hb_ft_get_glyph_h_origin, NULL, NULL);
hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ft_get_glyph_v_origin, NULL, NULL);
hb_font_funcs_set_glyph_h_kerning_func (funcs, hb_ft_get_glyph_h_kerning, NULL, NULL);
//hb_font_funcs_set_glyph_v_kerning_func (funcs, hb_ft_get_glyph_v_kerning, NULL, NULL);
hb_font_funcs_set_glyph_extents_func (funcs, hb_ft_get_glyph_extents, NULL, NULL);
hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ft_get_glyph_contour_point, NULL, NULL);
hb_font_funcs_set_glyph_name_func (funcs, hb_ft_get_glyph_name, NULL, NULL);
hb_font_funcs_set_glyph_from_name_func (funcs, hb_ft_get_glyph_from_name, NULL, NULL);
hb_font_funcs_make_immutable (funcs);
if (!hb_atomic_ptr_cmpexch (&static_ft_funcs, NULL, funcs)) {
hb_font_funcs_destroy (funcs);
goto retry;
}
#ifdef HB_USE_ATEXIT
atexit (free_static_ft_funcs); /* First person registers atexit() callback. */
#endif
};
hb_font_set_funcs (font,
const_cast<hb_font_funcs_t *> (&ft_ffuncs),
funcs,
_hb_ft_font_create (ft_face, unref),
(hb_destroy_func_t) _hb_ft_font_destroy);
}

View File

@ -185,7 +185,7 @@ struct hb_dispatch_context_t
/* This limits sanitizing time on really broken fonts. */
#ifndef HB_SANITIZE_MAX_EDITS
#define HB_SANITIZE_MAX_EDITS 100
#define HB_SANITIZE_MAX_EDITS 8
#endif
struct hb_sanitize_context_t :
@ -399,9 +399,9 @@ struct Sanitizer
struct hb_serialize_context_t
{
inline hb_serialize_context_t (void *start, unsigned int size)
inline hb_serialize_context_t (void *start_, unsigned int size)
{
this->start = (char *) start;
this->start = (char *) start_;
this->end = this->start + size;
this->ran_out_of_room = false;
@ -495,10 +495,10 @@ struct hb_serialize_context_t
return reinterpret_cast<Type *> (&obj);
}
inline void truncate (void *head)
inline void truncate (void *new_head)
{
assert (this->start < head && head <= this->head);
this->head = (char *) head;
assert (this->start < new_head && new_head <= this->head);
this->head = (char *) new_head;
}
unsigned int debug_depth;

View File

@ -46,11 +46,9 @@ struct hb_ot_face_metrics_accelerator_t
hb_blob_t *blob;
inline void init (hb_face_t *face,
hb_tag_t _hea_tag, hb_tag_t _mtx_tag,
unsigned int default_advance_)
hb_tag_t _hea_tag, hb_tag_t _mtx_tag)
{
this->default_advance = default_advance_;
this->num_metrics = face->get_num_glyphs ();
this->default_advance = face->get_upem ();
hb_blob_t *_hea_blob = OT::Sanitizer<OT::_hea>::sanitize (face->reference_table (_hea_tag));
const OT::_hea *_hea = OT::Sanitizer<OT::_hea>::lock_instance (_hea_blob);
@ -58,8 +56,16 @@ struct hb_ot_face_metrics_accelerator_t
hb_blob_destroy (_hea_blob);
this->blob = OT::Sanitizer<OT::_mtx>::sanitize (face->reference_table (_mtx_tag));
if (unlikely (!this->num_advances ||
2 * (this->num_advances + this->num_metrics) > hb_blob_get_length (this->blob)))
/* Cap num_metrics() and num_advances() based on table length. */
unsigned int len = hb_blob_get_length (this->blob);
if (unlikely (this->num_advances * 4 > len))
this->num_advances = len / 4;
this->num_metrics = this->num_advances + (len - 4 * this->num_advances) / 2;
/* We MUST set num_metrics to zero if num_advances is zero.
* Our get_advance() depends on that. */
if (unlikely (!this->num_advances))
{
this->num_metrics = this->num_advances = 0;
hb_blob_destroy (this->blob);
@ -245,11 +251,9 @@ _hb_ot_font_create (hb_face_t *face)
if (unlikely (!ot_font))
return NULL;
unsigned int upem = face->get_upem ();
ot_font->cmap.init (face);
ot_font->h_metrics.init (face, HB_OT_TAG_hhea, HB_OT_TAG_hmtx, upem>>1);
ot_font->v_metrics.init (face, HB_OT_TAG_vhea, HB_OT_TAG_vmtx, upem); /* TODO Can we do this lazily? */
ot_font->h_metrics.init (face, HB_OT_TAG_hhea, HB_OT_TAG_hmtx);
ot_font->v_metrics.init (face, HB_OT_TAG_vhea, HB_OT_TAG_vmtx); /* TODO Can we do this lazily? */
ot_font->glyf.init (face);
return ot_font;
@ -300,52 +304,6 @@ hb_ot_get_glyph_v_advance (hb_font_t *font HB_UNUSED,
return font->em_scale_y (-(int) ot_font->v_metrics.get_advance (glyph));
}
static hb_bool_t
hb_ot_get_glyph_h_origin (hb_font_t *font HB_UNUSED,
void *font_data HB_UNUSED,
hb_codepoint_t glyph HB_UNUSED,
hb_position_t *x HB_UNUSED,
hb_position_t *y HB_UNUSED,
void *user_data HB_UNUSED)
{
/* We always work in the horizontal coordinates. */
return true;
}
static hb_bool_t
hb_ot_get_glyph_v_origin (hb_font_t *font HB_UNUSED,
void *font_data,
hb_codepoint_t glyph,
hb_position_t *x,
hb_position_t *y,
void *user_data HB_UNUSED)
{
/* TODO */
return false;
}
static hb_position_t
hb_ot_get_glyph_h_kerning (hb_font_t *font,
void *font_data,
hb_codepoint_t left_glyph,
hb_codepoint_t right_glyph,
void *user_data HB_UNUSED)
{
/* TODO */
return 0;
}
static hb_position_t
hb_ot_get_glyph_v_kerning (hb_font_t *font HB_UNUSED,
void *font_data HB_UNUSED,
hb_codepoint_t top_glyph HB_UNUSED,
hb_codepoint_t bottom_glyph HB_UNUSED,
void *user_data HB_UNUSED)
{
/* OpenType doesn't have vertical-kerning other than GPOS. */
return 0;
}
static hb_bool_t
hb_ot_get_glyph_extents (hb_font_t *font HB_UNUSED,
void *font_data,
@ -362,58 +320,52 @@ hb_ot_get_glyph_extents (hb_font_t *font HB_UNUSED,
return ret;
}
static hb_bool_t
hb_ot_get_glyph_contour_point (hb_font_t *font HB_UNUSED,
void *font_data,
hb_codepoint_t glyph,
unsigned int point_index,
hb_position_t *x,
hb_position_t *y,
void *user_data HB_UNUSED)
{
/* TODO */
return false;
}
static hb_bool_t
hb_ot_get_glyph_name (hb_font_t *font HB_UNUSED,
void *font_data,
hb_codepoint_t glyph,
char *name, unsigned int size,
void *user_data HB_UNUSED)
{
/* TODO */
return false;
}
static hb_font_funcs_t *static_ot_funcs = NULL;
static hb_bool_t
hb_ot_get_glyph_from_name (hb_font_t *font HB_UNUSED,
void *font_data,
const char *name, int len, /* -1 means nul-terminated */
hb_codepoint_t *glyph,
void *user_data HB_UNUSED)
#ifdef HB_USE_ATEXIT
static
void free_static_ot_funcs (void)
{
/* TODO */
return false;
hb_font_funcs_destroy (static_ot_funcs);
}
#endif
static hb_font_funcs_t *
_hb_ot_get_font_funcs (void)
{
static const hb_font_funcs_t ot_ffuncs = {
HB_OBJECT_HEADER_STATIC,
retry:
hb_font_funcs_t *funcs = (hb_font_funcs_t *) hb_atomic_ptr_get (&static_ot_funcs);
true, /* immutable */
if (unlikely (!funcs))
{
funcs = hb_font_funcs_create ();
{
#define HB_FONT_FUNC_IMPLEMENT(name) hb_ot_get_##name,
HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_FONT_FUNC_IMPLEMENT
hb_font_funcs_set_glyph_func (funcs, hb_ot_get_glyph, NULL, NULL);
hb_font_funcs_set_glyph_h_advance_func (funcs, hb_ot_get_glyph_h_advance, NULL, NULL);
hb_font_funcs_set_glyph_v_advance_func (funcs, hb_ot_get_glyph_v_advance, NULL, NULL);
//hb_font_funcs_set_glyph_h_origin_func (funcs, hb_ot_get_glyph_h_origin, NULL, NULL);
//hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ot_get_glyph_v_origin, NULL, NULL);
//hb_font_funcs_set_glyph_h_kerning_func (funcs, hb_ot_get_glyph_h_kerning, NULL, NULL); TODO
//hb_font_funcs_set_glyph_v_kerning_func (funcs, hb_ot_get_glyph_v_kerning, NULL, NULL);
hb_font_funcs_set_glyph_extents_func (funcs, hb_ot_get_glyph_extents, NULL, NULL);
//hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ot_get_glyph_contour_point, NULL, NULL); TODO
//hb_font_funcs_set_glyph_name_func (funcs, hb_ot_get_glyph_name, NULL, NULL); TODO
//hb_font_funcs_set_glyph_from_name_func (funcs, hb_ot_get_glyph_from_name, NULL, NULL); TODO
hb_font_funcs_make_immutable (funcs);
if (!hb_atomic_ptr_cmpexch (&static_ot_funcs, NULL, funcs)) {
hb_font_funcs_destroy (funcs);
goto retry;
}
#ifdef HB_USE_ATEXIT
atexit (free_static_ot_funcs); /* First person registers atexit() callback. */
#endif
};
return const_cast<hb_font_funcs_t *> (&ot_ffuncs);
return funcs;
}

View File

@ -34,6 +34,14 @@
#include "hb-set-private.hh"
#ifndef HB_MAX_NESTING_LEVEL
#define HB_MAX_NESTING_LEVEL 6
#endif
#ifndef HB_MAX_CONTEXT_LENGTH
#define HB_MAX_CONTEXT_LENGTH 64
#endif
namespace OT {
@ -44,8 +52,6 @@ namespace OT {
#define NOT_COVERED ((unsigned int) -1)
#define MAX_NESTING_LEVEL 6
#define MAX_CONTEXT_LENGTH 64
@ -573,6 +579,11 @@ struct LookupFlag : USHORT
DEFINE_SIZE_STATIC (2);
};
} /* namespace OT */
/* This has to be outside the namespace. */
HB_MARK_AS_FLAG_T (OT::LookupFlag::Flags);
namespace OT {
struct Lookup
{
inline unsigned int get_subtable_count (void) const { return subTable.len; }

View File

@ -426,6 +426,7 @@ struct MarkArray : ArrayOf<MarkRecord> /* Array of MarkRecords--in Coverage orde
o.x_offset = base_x - mark_x;
o.y_offset = base_y - mark_y;
o.attach_lookback() = buffer->idx - glyph_pos;
buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
buffer->idx++;
return_trace (true);
@ -993,6 +994,7 @@ struct CursivePosFormat1
reverse_cursive_minor_offset (pos, child, c->direction, parent);
pos[child].cursive_chain() = parent - child;
buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_CURSIVE;
if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction)))
pos[child].y_offset = y_offset;
else
@ -1599,12 +1601,14 @@ GPOS::position_finish (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
hb_direction_t direction = buffer->props.direction;
/* Handle cursive connections */
for (unsigned int i = 0; i < len; i++)
fix_cursive_minor_offset (pos, i, direction);
if (buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_CURSIVE)
for (unsigned int i = 0; i < len; i++)
fix_cursive_minor_offset (pos, i, direction);
/* Handle attachments */
for (unsigned int i = 0; i < len; i++)
fix_mark_attachment (pos, i, direction);
if (buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT)
for (unsigned int i = 0; i < len; i++)
fix_mark_attachment (pos, i, direction);
}

View File

@ -630,7 +630,7 @@ struct Ligature
unsigned int total_component_count = 0;
unsigned int match_length = 0;
unsigned int match_positions[MAX_CONTEXT_LENGTH];
unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
if (likely (!match_input (c, count,
&component[1],
@ -970,7 +970,7 @@ struct ReverseChainSingleSubstFormat1
inline bool apply (hb_apply_context_t *c) const
{
TRACE_APPLY (this);
if (unlikely (c->nesting_level_left != MAX_NESTING_LEVEL))
if (unlikely (c->nesting_level_left != HB_MAX_NESTING_LEVEL))
return_trace (false); /* No chaining to this type */
unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);

View File

@ -74,7 +74,7 @@ struct hb_closure_context_t :
hb_closure_context_t (hb_face_t *face_,
hb_set_t *glyphs_,
unsigned int nesting_level_left_ = MAX_NESTING_LEVEL) :
unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
face (face_),
glyphs (glyphs_),
recurse_func (NULL),
@ -196,7 +196,7 @@ struct hb_collect_glyphs_context_t :
hb_set_t *glyphs_input, /* OUT. May be NULL */
hb_set_t *glyphs_after, /* OUT. May be NULL */
hb_set_t *glyphs_output, /* OUT. May be NULL */
unsigned int nesting_level_left_ = MAX_NESTING_LEVEL) :
unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
face (face_),
before (glyphs_before ? glyphs_before : hb_set_get_empty ()),
input (glyphs_input ? glyphs_input : hb_set_get_empty ()),
@ -355,11 +355,11 @@ struct hb_apply_context_t :
{
matcher.set_lookup_props (lookup_props);
}
inline void set_match_func (matcher_t::match_func_t match_func,
const void *match_data,
inline void set_match_func (matcher_t::match_func_t match_func_,
const void *match_data_,
const USHORT glyph_data[])
{
matcher.set_match_func (match_func, match_data);
matcher.set_match_func (match_func_, match_data_);
match_glyph_data = glyph_data;
}
@ -483,7 +483,7 @@ struct hb_apply_context_t :
lookup_mask (1),
auto_zwj (true),
recurse_func (NULL),
nesting_level_left (MAX_NESTING_LEVEL),
nesting_level_left (HB_MAX_NESTING_LEVEL),
lookup_props (0),
gdef (*hb_ot_layout_from_face (face)->gdef),
has_glyph_classes (gdef.has_glyph_classes ()),
@ -704,13 +704,13 @@ static inline bool match_input (hb_apply_context_t *c,
match_func_t match_func,
const void *match_data,
unsigned int *end_offset,
unsigned int match_positions[MAX_CONTEXT_LENGTH],
unsigned int match_positions[HB_MAX_CONTEXT_LENGTH],
bool *p_is_mark_ligature = NULL,
unsigned int *p_total_component_count = NULL)
{
TRACE_APPLY (NULL);
if (unlikely (count > MAX_CONTEXT_LENGTH)) return_trace (false);
if (unlikely (count > HB_MAX_CONTEXT_LENGTH)) return_trace (false);
hb_buffer_t *buffer = c->buffer;
@ -784,7 +784,7 @@ static inline bool match_input (hb_apply_context_t *c,
}
static inline bool ligate_input (hb_apply_context_t *c,
unsigned int count, /* Including the first glyph */
unsigned int match_positions[MAX_CONTEXT_LENGTH], /* Including the first glyph */
unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */
unsigned int match_length,
hb_codepoint_t lig_glyph,
bool is_mark_ligature,
@ -836,14 +836,13 @@ static inline bool ligate_input (hb_apply_context_t *c,
if (_hb_glyph_info_get_general_category (&buffer->cur()) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
{
_hb_glyph_info_set_general_category (&buffer->cur(), HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER);
_hb_glyph_info_set_modified_combining_class (&buffer->cur(), 0);
}
}
c->replace_glyph_with_ligature (lig_glyph, klass);
for (unsigned int i = 1; i < count; i++)
{
while (buffer->idx < match_positions[i])
while (buffer->idx < match_positions[i] && !buffer->in_error)
{
if (!is_mark_ligature) {
unsigned int new_lig_comp = components_so_far - last_num_components +
@ -944,7 +943,7 @@ static inline void recurse_lookups (context_t *c,
static inline bool apply_lookup (hb_apply_context_t *c,
unsigned int count, /* Including the first glyph */
unsigned int match_positions[MAX_CONTEXT_LENGTH], /* Including the first glyph */
unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */
unsigned int lookupCount,
const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */
unsigned int match_length)
@ -989,13 +988,13 @@ static inline bool apply_lookup (hb_apply_context_t *c,
/* end can't go back past the current match position.
* Note: this is only true because we do NOT allow MultipleSubst
* with zero sequence len. */
end = MAX ((int) match_positions[idx] + 1, int (end) + delta);
end = MAX (MIN((int) match_positions[idx] + 1, (int) new_len), int (end) + delta);
unsigned int next = idx + 1; /* next now is the position after the recursed lookup. */
if (delta > 0)
{
if (unlikely (delta + count > MAX_CONTEXT_LENGTH))
if (unlikely (delta + count > HB_MAX_CONTEXT_LENGTH))
break;
}
else
@ -1094,7 +1093,7 @@ static inline bool context_apply_lookup (hb_apply_context_t *c,
ContextApplyLookupContext &lookup_context)
{
unsigned int match_length = 0;
unsigned int match_positions[MAX_CONTEXT_LENGTH];
unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
return match_input (c,
inputCount, input,
lookup_context.funcs.match, lookup_context.match_data,
@ -1621,7 +1620,7 @@ static inline bool chain_context_apply_lookup (hb_apply_context_t *c,
ChainContextApplyLookupContext &lookup_context)
{
unsigned int match_length = 0;
unsigned int match_positions[MAX_CONTEXT_LENGTH];
unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
return match_input (c,
inputCount, input,
lookup_context.funcs.match, lookup_context.match_data[1],

View File

@ -49,7 +49,7 @@ hb_ot_layout_table_find_feature (hb_face_t *face,
* GDEF
*/
typedef enum
enum hb_ot_layout_glyph_props_flags_t
{
/* The following three match LookupFlags::Ignore* numbers. */
HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH = 0x02u,
@ -64,7 +64,8 @@ typedef enum
HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE = HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED |
HB_OT_LAYOUT_GLYPH_PROPS_LIGATED |
HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED
} hb_ot_layout_glyph_class_mask_t;
};
HB_MARK_AS_FLAG_T (hb_ot_layout_glyph_props_flags_t);
/*
@ -180,8 +181,7 @@ _hb_ot_layout_destroy (hb_ot_layout_t *layout);
*/
/* buffer var allocations, used during the entire shaping process */
#define unicode_props0() var2.u8[0]
#define unicode_props1() var2.u8[1]
#define unicode_props() var2.u16[0]
/* buffer var allocations, used during the GSUB/GPOS processing */
#define glyph_props() var1.u16[0] /* GDEF glyph properties */
@ -214,48 +214,123 @@ _next_syllable (hb_buffer_t *buffer, unsigned int start)
/* unicode_props */
enum {
MASK0_ZWJ = 0x20u,
MASK0_ZWNJ = 0x40u,
MASK0_IGNORABLE = 0x80u,
MASK0_GEN_CAT = 0x1Fu
/* Design:
* unicode_props() is a two-byte number. The low byte includes:
* - General_Category: 5 bits.
* - A bit each for:
* * Is it Default_Ignorable(); we have a modified Default_Ignorable().
* * Is it U+200D ZWJ?
* * Is it U+200C ZWNJ?
*
* The high-byte has different meanings, switched by the Gen-Cat:
* - For Mn,Mc,Me: the modified Combining_Class.
* - For Ws: index of which space character this is, if space fallback
* is needed, ie. we don't set this by default, only if asked to.
*
* If needed, we can use the ZWJ/ZWNJ to use the high byte as well,
* freeing two more bits.
*/
enum hb_unicode_props_flags_t {
UPROPS_MASK_ZWJ = 0x20u,
UPROPS_MASK_ZWNJ = 0x40u,
UPROPS_MASK_IGNORABLE = 0x80u,
UPROPS_MASK_GEN_CAT = 0x1Fu
};
HB_MARK_AS_FLAG_T (hb_unicode_props_flags_t);
static inline void
_hb_glyph_info_set_unicode_props (hb_glyph_info_t *info, hb_unicode_funcs_t *unicode)
_hb_glyph_info_set_unicode_props (hb_glyph_info_t *info, hb_buffer_t *buffer)
{
/* XXX This shouldn't be inlined, or at least not while is_default_ignorable() is inline. */
info->unicode_props0() = ((unsigned int) unicode->general_category (info->codepoint)) |
(unicode->is_default_ignorable (info->codepoint) ? MASK0_IGNORABLE : 0) |
(info->codepoint == 0x200Cu ? MASK0_ZWNJ : 0) |
(info->codepoint == 0x200Du ? MASK0_ZWJ : 0);
info->unicode_props1() = unicode->modified_combining_class (info->codepoint);
hb_unicode_funcs_t *unicode = buffer->unicode;
unsigned int u = info->codepoint;
unsigned int gen_cat = (unsigned int) unicode->general_category (u);
unsigned int props = gen_cat;
if (u >= 0x80)
{
buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII;
if (unlikely (unicode->is_default_ignorable (u)))
{
buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES;
props |= UPROPS_MASK_IGNORABLE;
if (u == 0x200Cu) props |= UPROPS_MASK_ZWNJ;
if (u == 0x200Du) props |= UPROPS_MASK_ZWJ;
}
else if (unlikely (HB_UNICODE_GENERAL_CATEGORY_IS_NON_ENCLOSING_MARK (gen_cat)))
{
/* Only Mn and Mc can have non-zero ccc:
* http://www.unicode.org/policies/stability_policy.html#Property_Value
* """
* Canonical_Combining_Class, General_Category
* All characters other than those with General_Category property values
* Spacing_Mark (Mc) and Nonspacing_Mark (Mn) have the Canonical_Combining_Class
* property value 0.
* 1.1.5+
* """
*
* Also, all Mn's that are Default_Ignorable, have ccc=0, hence
* the "else if".
*/
props |= unicode->modified_combining_class (info->codepoint)<<8;
}
}
info->unicode_props() = props;
}
static inline void
_hb_glyph_info_set_general_category (hb_glyph_info_t *info,
hb_unicode_general_category_t gen_cat)
{
info->unicode_props0() = (unsigned int) gen_cat | ((info->unicode_props0()) & ~MASK0_GEN_CAT);
/* Clears top-byte. */
info->unicode_props() = (unsigned int) gen_cat | (info->unicode_props() & (0xFF & ~UPROPS_MASK_GEN_CAT));
}
static inline hb_unicode_general_category_t
_hb_glyph_info_get_general_category (const hb_glyph_info_t *info)
{
return (hb_unicode_general_category_t) (info->unicode_props0() & MASK0_GEN_CAT);
return (hb_unicode_general_category_t) (info->unicode_props() & UPROPS_MASK_GEN_CAT);
}
static inline bool
_hb_glyph_info_is_unicode_mark (const hb_glyph_info_t *info)
{
return HB_UNICODE_GENERAL_CATEGORY_IS_MARK (info->unicode_props() & UPROPS_MASK_GEN_CAT);
}
static inline void
_hb_glyph_info_set_modified_combining_class (hb_glyph_info_t *info,
unsigned int modified_class)
{
info->unicode_props1() = modified_class;
if (unlikely (!_hb_glyph_info_is_unicode_mark (info)))
return;
info->unicode_props() = (modified_class<<8) | (info->unicode_props() & 0xFF);
}
static inline unsigned int
_hb_glyph_info_get_modified_combining_class (const hb_glyph_info_t *info)
{
return info->unicode_props1();
return _hb_glyph_info_is_unicode_mark (info) ? info->unicode_props()>>8 : 0;
}
static inline bool
_hb_glyph_info_is_unicode_space (const hb_glyph_info_t *info)
{
return _hb_glyph_info_get_general_category (info) ==
HB_UNICODE_GENERAL_CATEGORY_SPACE_SEPARATOR;
}
static inline void
_hb_glyph_info_set_unicode_space_fallback_type (hb_glyph_info_t *info, hb_unicode_funcs_t::space_t s)
{
if (unlikely (!_hb_glyph_info_is_unicode_space (info)))
return;
info->unicode_props() = (((unsigned int) s)<<8) | (info->unicode_props() & 0xFF);
}
static inline hb_unicode_funcs_t::space_t
_hb_glyph_info_get_unicode_space_fallback_type (const hb_glyph_info_t *info)
{
return _hb_glyph_info_is_unicode_space (info) ?
(hb_unicode_funcs_t::space_t) (info->unicode_props()>>8) :
hb_unicode_funcs_t::NOT_SPACE;
}
static inline bool _hb_glyph_info_ligated (const hb_glyph_info_t *info);
@ -263,25 +338,25 @@ static inline bool _hb_glyph_info_ligated (const hb_glyph_info_t *info);
static inline hb_bool_t
_hb_glyph_info_is_default_ignorable (const hb_glyph_info_t *info)
{
return (info->unicode_props0() & MASK0_IGNORABLE) && !_hb_glyph_info_ligated (info);
return (info->unicode_props() & UPROPS_MASK_IGNORABLE) && !_hb_glyph_info_ligated (info);
}
static inline hb_bool_t
_hb_glyph_info_is_zwnj (const hb_glyph_info_t *info)
{
return !!(info->unicode_props0() & MASK0_ZWNJ);
return !!(info->unicode_props() & UPROPS_MASK_ZWNJ);
}
static inline hb_bool_t
_hb_glyph_info_is_zwj (const hb_glyph_info_t *info)
{
return !!(info->unicode_props0() & MASK0_ZWJ);
return !!(info->unicode_props() & UPROPS_MASK_ZWJ);
}
static inline void
_hb_glyph_info_flip_joiners (hb_glyph_info_t *info)
{
info->unicode_props0() ^= MASK0_ZWNJ | MASK0_ZWJ;
info->unicode_props() ^= UPROPS_MASK_ZWNJ | UPROPS_MASK_ZWJ;
}
/* lig_props: aka lig_id / lig_comp
@ -455,22 +530,19 @@ _hb_glyph_info_clear_substituted_and_ligated_and_multiplied (hb_glyph_info_t *in
static inline void
_hb_buffer_allocate_unicode_vars (hb_buffer_t *buffer)
{
HB_BUFFER_ALLOCATE_VAR (buffer, unicode_props0);
HB_BUFFER_ALLOCATE_VAR (buffer, unicode_props1);
HB_BUFFER_ALLOCATE_VAR (buffer, unicode_props);
}
static inline void
_hb_buffer_deallocate_unicode_vars (hb_buffer_t *buffer)
{
HB_BUFFER_DEALLOCATE_VAR (buffer, unicode_props0);
HB_BUFFER_DEALLOCATE_VAR (buffer, unicode_props1);
HB_BUFFER_DEALLOCATE_VAR (buffer, unicode_props);
}
static inline void
_hb_buffer_assert_unicode_vars (hb_buffer_t *buffer)
{
HB_BUFFER_ASSERT_VAR (buffer, unicode_props0);
HB_BUFFER_ASSERT_VAR (buffer, unicode_props1);
HB_BUFFER_ASSERT_VAR (buffer, unicode_props);
}
static inline void

View File

@ -890,7 +890,7 @@ apply_forward (OT::hb_apply_context_t *c,
{
bool ret = false;
hb_buffer_t *buffer = c->buffer;
while (buffer->idx < buffer->len)
while (buffer->idx < buffer->len && !buffer->in_error)
{
if (accel.may_have (buffer->cur().codepoint) &&
(buffer->cur().mask & c->lookup_mask) &&

View File

@ -159,23 +159,9 @@ enum hb_ot_map_feature_flags_t {
F_MANUAL_ZWJ = 0x0004u, /* Don't skip over ZWJ when matching. */
F_GLOBAL_SEARCH = 0x0008u /* If feature not found in LangSys, look for it in global feature list and pick one. */
};
HB_MARK_AS_FLAG_T (hb_ot_map_feature_flags_t);
/* Macro version for where const is desired. */
#define F_COMBINE(l,r) (hb_ot_map_feature_flags_t ((unsigned int) (l) | (unsigned int) (r)))
static inline hb_ot_map_feature_flags_t
operator | (hb_ot_map_feature_flags_t l, hb_ot_map_feature_flags_t r)
{ return hb_ot_map_feature_flags_t ((unsigned int) l | (unsigned int) r); }
static inline hb_ot_map_feature_flags_t
operator & (hb_ot_map_feature_flags_t l, hb_ot_map_feature_flags_t r)
{ return hb_ot_map_feature_flags_t ((unsigned int) l & (unsigned int) r); }
static inline hb_ot_map_feature_flags_t
operator ~ (hb_ot_map_feature_flags_t r)
{ return hb_ot_map_feature_flags_t (~(unsigned int) r); }
static inline hb_ot_map_feature_flags_t&
operator |= (hb_ot_map_feature_flags_t &l, hb_ot_map_feature_flags_t r)
{ l = l | r; return l; }
static inline hb_ot_map_feature_flags_t&
operator &= (hb_ot_map_feature_flags_t& l, hb_ot_map_feature_flags_t r)
{ l = l & r; return l; }
struct hb_ot_map_builder_t

View File

@ -28,9 +28,38 @@
#include "hb-ot-shape-private.hh"
#ifndef HB_DEBUG_ARABIC
#define HB_DEBUG_ARABIC (HB_DEBUG+0)
#endif
/* buffer var allocations */
#define arabic_shaping_action() complex_var_u8_0() /* arabic shaping action */
#define HB_BUFFER_SCRATCH_FLAG_ARABIC_HAS_STCH HB_BUFFER_SCRATCH_FLAG_COMPLEX0
/* See:
* https://github.com/behdad/harfbuzz/commit/6e6f82b6f3dde0fc6c3c7d991d9ec6cfff57823d#commitcomment-14248516 */
#define HB_ARABIC_GENERAL_CATEGORY_IS_WORD(gen_cat) \
(FLAG_SAFE (gen_cat) & \
(FLAG (HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED) | \
FLAG (HB_UNICODE_GENERAL_CATEGORY_PRIVATE_USE) | \
/*FLAG (HB_UNICODE_GENERAL_CATEGORY_LOWERCASE_LETTER) |*/ \
FLAG (HB_UNICODE_GENERAL_CATEGORY_MODIFIER_LETTER) | \
FLAG (HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER) | \
/*FLAG (HB_UNICODE_GENERAL_CATEGORY_TITLECASE_LETTER) |*/ \
/*FLAG (HB_UNICODE_GENERAL_CATEGORY_UPPERCASE_LETTER) |*/ \
FLAG (HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK) | \
FLAG (HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK) | \
FLAG (HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) | \
FLAG (HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER) | \
FLAG (HB_UNICODE_GENERAL_CATEGORY_LETTER_NUMBER) | \
FLAG (HB_UNICODE_GENERAL_CATEGORY_OTHER_NUMBER) | \
FLAG (HB_UNICODE_GENERAL_CATEGORY_CURRENCY_SYMBOL) | \
FLAG (HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL) | \
FLAG (HB_UNICODE_GENERAL_CATEGORY_MATH_SYMBOL) | \
FLAG (HB_UNICODE_GENERAL_CATEGORY_OTHER_SYMBOL)))
/*
* Joining types:
@ -84,7 +113,7 @@ static const hb_tag_t arabic_features[] =
/* Same order as the feature array */
enum {
enum arabic_action_t {
ISOL,
FINA,
FIN2,
@ -95,7 +124,11 @@ enum {
NONE,
ARABIC_NUM_FEATURES = NONE
ARABIC_NUM_FEATURES = NONE,
/* We abuse the same byte for other things... */
STCH_FIXED,
STCH_REPEATING,
};
static const struct arabic_state_table_entry {
@ -139,6 +172,11 @@ arabic_fallback_shape (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer);
static void
record_stch (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer);
static void
collect_features_arabic (hb_ot_shape_planner_t *plan)
{
@ -165,6 +203,9 @@ collect_features_arabic (hb_ot_shape_planner_t *plan)
map->add_gsub_pause (nuke_joiners);
map->add_global_bool_feature (HB_TAG('s','t','c','h'));
map->add_gsub_pause (record_stch);
map->add_global_bool_feature (HB_TAG('c','c','m','p'));
map->add_global_bool_feature (HB_TAG('l','o','c','l'));
@ -208,8 +249,10 @@ struct arabic_shape_plan_t
* mask_array[NONE] == 0. */
hb_mask_t mask_array[ARABIC_NUM_FEATURES + 1];
bool do_fallback;
arabic_fallback_plan_t *fallback_plan;
unsigned int do_fallback : 1;
unsigned int has_stch : 1;
};
void *
@ -220,6 +263,7 @@ data_create_arabic (const hb_ot_shape_plan_t *plan)
return NULL;
arabic_plan->do_fallback = plan->props.script == HB_SCRIPT_ARABIC;
arabic_plan->has_stch = !!plan->map.get_1_mask (HB_TAG ('s','t','c','h'));
for (unsigned int i = 0; i < ARABIC_NUM_FEATURES; i++) {
arabic_plan->mask_array[i] = plan->map.get_1_mask (arabic_features[i]);
arabic_plan->do_fallback = arabic_plan->do_fallback &&
@ -320,8 +364,6 @@ setup_masks_arabic_plan (const arabic_shape_plan_t *arabic_plan,
hb_glyph_info_t *info = buffer->info;
for (unsigned int i = 0; i < count; i++)
info[i].mask |= arabic_plan->mask_array[info[i].arabic_shaping_action()];
HB_BUFFER_DEALLOCATE_VAR (buffer, arabic_shaping_action);
}
static void
@ -371,6 +413,194 @@ retry:
arabic_fallback_plan_shape (fallback_plan, font, buffer);
}
/*
* Stretch feature: "stch".
* See example here:
* https://www.microsoft.com/typography/OpenTypeDev/syriac/intro.htm
* We implement this in a generic way, such that the Arabic subtending
* marks can use it as well.
*/
static void
record_stch (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer)
{
const arabic_shape_plan_t *arabic_plan = (const arabic_shape_plan_t *) plan->data;
if (!arabic_plan->has_stch)
return;
/* 'stch' feature was just applied. Look for anything that multiplied,
* and record it for stch treatment later. Note that rtlm, frac, etc
* are applied before stch, but we assume that they didn't result in
* anything multiplying into 5 pieces, so it's safe-ish... */
unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
for (unsigned int i = 0; i < count; i++)
if (unlikely (_hb_glyph_info_multiplied (&info[i])))
{
unsigned int comp = _hb_glyph_info_get_lig_comp (&info[i]);
info[i].arabic_shaping_action() = comp % 2 ? STCH_REPEATING : STCH_FIXED;
buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_ARABIC_HAS_STCH;
}
}
static void
apply_stch (const hb_ot_shape_plan_t *plan,
hb_buffer_t *buffer,
hb_font_t *font)
{
if (likely (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_ARABIC_HAS_STCH)))
return;
/* The Arabic shaper currently always processes in RTL mode, so we should
* stretch / position the stretched pieces to the left / preceding glyphs. */
/* We do a two pass implementation:
* First pass calculates the exact number of extra glyphs we need,
* We then enlarge buffer to have that much room,
* Second pass applies the stretch, copying things to the end of buffer.
*/
/* 30 = 2048 / 70.
* https://www.microsoft.com/typography/cursivescriptguidelines.mspx */
hb_position_t overlap = font->x_scale / 30;
DEBUG_MSG (ARABIC, NULL, "overlap for stretching is %d", overlap);
int sign = font->x_scale < 0 ? -1 : +1;
unsigned int extra_glyphs_needed = 0; // Set during MEASURE, used during CUT
typedef enum { MEASURE, CUT } step_t;
for (step_t step = MEASURE; step <= CUT; step = (step_t) (step + 1))
{
unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
hb_glyph_position_t *pos = buffer->pos;
unsigned int new_len = count + extra_glyphs_needed; // write head during CUT
unsigned int j = new_len;
for (unsigned int i = count; i; i--)
{
if (!hb_in_range<unsigned> (info[i - 1].arabic_shaping_action(), STCH_FIXED, STCH_REPEATING))
{
if (step == CUT)
{
--j;
info[j] = info[i - 1];
pos[j] = pos[i - 1];
}
continue;
}
/* Yay, justification! */
hb_position_t w_total = 0; // Total to be filled
hb_position_t w_fixed = 0; // Sum of fixed tiles
hb_position_t w_repeating = 0; // Sum of repeating tiles
int n_fixed = 0;
int n_repeating = 0;
unsigned int end = i;
while (i &&
hb_in_range<unsigned> (info[i - 1].arabic_shaping_action(), STCH_FIXED, STCH_REPEATING))
{
i--;
hb_glyph_extents_t extents;
if (!font->get_glyph_extents (info[i].codepoint, &extents))
extents.width = 0;
extents.width -= overlap;
if (info[i].arabic_shaping_action() == STCH_FIXED)
{
w_fixed += extents.width;
n_fixed++;
}
else
{
w_repeating += extents.width;
n_repeating++;
}
}
unsigned int start = i;
unsigned int context = i;
while (context &&
!hb_in_range<unsigned> (info[context - 1].arabic_shaping_action(), STCH_FIXED, STCH_REPEATING) &&
(_hb_glyph_info_is_default_ignorable (&info[context - 1]) ||
HB_ARABIC_GENERAL_CATEGORY_IS_WORD (_hb_glyph_info_get_general_category (&info[context - 1]))))
{
context--;
w_total += pos[context].x_advance;
}
i++; // Don't touch i again.
DEBUG_MSG (ARABIC, NULL, "%s stretch at (%d,%d,%d)",
step == MEASURE ? "measuring" : "cutting", context, start, end);
DEBUG_MSG (ARABIC, NULL, "rest of word: count=%d width %d", start - context, w_total);
DEBUG_MSG (ARABIC, NULL, "fixed tiles: count=%d width=%d", n_fixed, w_fixed);
DEBUG_MSG (ARABIC, NULL, "repeating tiles: count=%d width=%d", n_repeating, w_repeating);
/* Number of additional times to repeat each repeating tile. */
int n_copies = 0;
hb_position_t w_remaining = w_total - w_fixed - overlap;
if (sign * w_remaining > sign * w_repeating && sign * w_repeating > 0)
n_copies = (sign * w_remaining + sign * w_repeating / 4) / (sign * w_repeating) - 1;
if (step == MEASURE)
{
extra_glyphs_needed += n_copies * n_repeating;
DEBUG_MSG (ARABIC, NULL, "will add extra %d copies of repeating tiles", n_copies);
}
else
{
hb_position_t x_offset = -overlap;
for (unsigned int k = end; k > start; k--)
{
hb_glyph_extents_t extents;
if (!font->get_glyph_extents (info[k - 1].codepoint, &extents))
extents.width = 0;
extents.width -= overlap;
unsigned int repeat = 1;
if (info[k - 1].arabic_shaping_action() == STCH_REPEATING)
repeat += n_copies;
DEBUG_MSG (ARABIC, NULL, "appending %d copies of glyph %d; j=%d",
repeat, info[k - 1].codepoint, j);
for (unsigned int n = 0; n < repeat; n++)
{
x_offset -= extents.width;
pos[k - 1].x_offset = x_offset;
/* Append copy. */
--j;
info[j] = info[k - 1];
pos[j] = pos[k - 1];
}
}
}
}
if (step == MEASURE)
{
if (unlikely (!buffer->ensure (count + extra_glyphs_needed)))
break;
}
else
{
assert (j == 0);
buffer->len = new_len;
}
}
}
static void
postprocess_glyphs_arabic (const hb_ot_shape_plan_t *plan,
hb_buffer_t *buffer,
hb_font_t *font)
{
apply_stch (plan, buffer, font);
HB_BUFFER_DEALLOCATE_VAR (buffer, arabic_shaping_action);
}
const hb_ot_complex_shaper_t _hb_ot_complex_shaper_arabic =
{
@ -379,7 +609,8 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_arabic =
NULL, /* override_features */
data_create_arabic,
data_destroy_arabic,
NULL, /* preprocess_text_arabic */
NULL, /* preprocess_text */
postprocess_glyphs_arabic,
HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
NULL, /* decompose */
NULL, /* compose */

View File

@ -35,6 +35,7 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_default =
NULL, /* data_create */
NULL, /* data_destroy */
NULL, /* preprocess_text */
NULL, /* postprocess_glyphs */
HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
NULL, /* decompose */
NULL, /* compose */

View File

@ -188,7 +188,7 @@ preprocess_text_hangul (const hb_ot_shape_plan_t *plan,
*/
unsigned int count = buffer->len;
for (buffer->idx = 0; buffer->idx < count;)
for (buffer->idx = 0; buffer->idx < count && !buffer->in_error;)
{
hb_codepoint_t u = buffer->cur().codepoint;
@ -411,13 +411,14 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_hangul =
"hangul",
collect_features_hangul,
override_features_hangul,
data_create_hangul, /* data_create */
data_destroy_hangul, /* data_destroy */
data_create_hangul,
data_destroy_hangul,
preprocess_text_hangul,
NULL, /* postprocess_glyphs */
HB_OT_SHAPE_NORMALIZATION_MODE_NONE,
NULL, /* decompose */
NULL, /* compose */
setup_masks_hangul, /* setup_masks */
setup_masks_hangul,
HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
false, /* fallback_position */
};

View File

@ -163,6 +163,7 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_hebrew =
NULL, /* data_create */
NULL, /* data_destroy */
NULL, /* preprocess_text */
NULL, /* postprocess_glyphs */
HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
NULL, /* decompose */
compose_hebrew,

View File

@ -756,7 +756,7 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
{
default:
assert (false);
/* fallthrough */
HB_FALLTHROUGH;
case BASE_POS_LAST:
{
@ -1243,7 +1243,7 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED,
buffer->idx = 0;
unsigned int last_syllable = 0;
while (buffer->idx < buffer->len)
while (buffer->idx < buffer->len && !buffer->in_error)
{
unsigned int syllable = buffer->cur().syllable();
syllable_type_t syllable_type = (syllable_type_t) (syllable & 0x0F);
@ -1251,10 +1251,10 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED,
{
last_syllable = syllable;
hb_glyph_info_t info = dottedcircle;
info.cluster = buffer->cur().cluster;
info.mask = buffer->cur().mask;
info.syllable() = buffer->cur().syllable();
hb_glyph_info_t ginfo = dottedcircle;
ginfo.cluster = buffer->cur().cluster;
ginfo.mask = buffer->cur().mask;
ginfo.syllable() = buffer->cur().syllable();
/* TODO Set glyph_props? */
/* Insert dottedcircle after possible Repha. */
@ -1263,7 +1263,7 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED,
buffer->cur().indic_category() == OT_Repha)
buffer->next_glyph ();
buffer->output_info (info);
buffer->output_info (ginfo);
}
else
buffer->next_glyph ();
@ -1631,8 +1631,8 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan,
if (new_pos > start && info[new_pos - 1].indic_category() == OT_M)
{
unsigned int old_pos = i;
for (unsigned int i = base + 1; i < old_pos; i++)
if (info[i].indic_category() == OT_M)
for (unsigned int j = base + 1; j < old_pos; j++)
if (info[j].indic_category() == OT_M)
{
new_pos--;
break;
@ -1834,6 +1834,7 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_indic =
data_create_indic,
data_destroy_indic,
NULL, /* preprocess_text */
NULL, /* postprocess_glyphs */
HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
decompose_indic,
compose_indic,

View File

@ -455,12 +455,12 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED,
{
last_syllable = syllable;
hb_glyph_info_t info = dottedcircle;
info.cluster = buffer->cur().cluster;
info.mask = buffer->cur().mask;
info.syllable() = buffer->cur().syllable();
hb_glyph_info_t ginfo = dottedcircle;
ginfo.cluster = buffer->cur().cluster;
ginfo.mask = buffer->cur().mask;
ginfo.syllable() = buffer->cur().syllable();
buffer->output_info (info);
buffer->output_info (ginfo);
}
else
buffer->next_glyph ();
@ -507,6 +507,7 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_myanmar_old =
NULL, /* data_create */
NULL, /* data_destroy */
NULL, /* preprocess_text */
NULL, /* postprocess_glyphs */
HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
NULL, /* decompose */
NULL, /* compose */
@ -523,6 +524,7 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_myanmar =
NULL, /* data_create */
NULL, /* data_destroy */
NULL, /* preprocess_text */
NULL, /* postprocess_glyphs */
HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
NULL, /* decompose */
NULL, /* compose */

View File

@ -110,6 +110,15 @@ struct hb_ot_complex_shaper_t
hb_buffer_t *buffer,
hb_font_t *font);
/* postprocess_glyphs()
* Called during shape().
* Shapers can use to modify glyphs after shaping ends.
* May be NULL.
*/
void (*postprocess_glyphs) (const hb_ot_shape_plan_t *plan,
hb_buffer_t *buffer,
hb_font_t *font);
hb_ot_shape_normalization_mode_t normalization_preference;

View File

@ -139,7 +139,7 @@ thai_pua_shape (hb_codepoint_t u, thai_action_t action, hb_font_t *font)
};
switch (action) {
default: assert (false); /* Fallthrough */
default: assert (false); HB_FALLTHROUGH;
case NOP: return u;
case SD: pua_mappings = SD_mappings; break;
case SDL: pua_mappings = SDL_mappings; break;
@ -315,7 +315,7 @@ preprocess_text_thai (const hb_ot_shape_plan_t *plan,
buffer->clear_output ();
unsigned int count = buffer->len;
for (buffer->idx = 0; buffer->idx < count;)
for (buffer->idx = 0; buffer->idx < count && !buffer->in_error;)
{
hb_codepoint_t u = buffer->cur().codepoint;
if (likely (!IS_SARA_AM (u))) {
@ -330,7 +330,7 @@ preprocess_text_thai (const hb_ot_shape_plan_t *plan,
if (unlikely (buffer->in_error))
return;
/* Make Nikhahit be recognized as a mark when zeroing widths. */
/* Make Nikhahit be recognized as a ccc=0 mark when zeroing widths. */
unsigned int end = buffer->out_len;
_hb_glyph_info_set_general_category (&buffer->out_info[end - 2], HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK);
@ -372,6 +372,7 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_thai =
NULL, /* data_create */
NULL, /* data_destroy */
preprocess_text_thai,
NULL, /* postprocess_glyphs */
HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
NULL, /* decompose */
NULL, /* compose */

View File

@ -52,6 +52,7 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_tibetan =
NULL, /* data_create */
NULL, /* data_destroy */
NULL, /* preprocess_text */
NULL, /* postprocess_glyphs */
HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
NULL, /* decompose */
NULL, /* compose */

View File

@ -490,11 +490,6 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED,
if (likely (!has_broken_syllables))
return;
hb_codepoint_t dottedcircle_glyph;
if (!font->get_glyph (0x25CCu, 0, &dottedcircle_glyph))
return;
hb_glyph_info_t dottedcircle = {0};
if (!font->get_glyph (0x25CCu, 0, &dottedcircle.codepoint))
return;
@ -503,9 +498,8 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED,
buffer->clear_output ();
buffer->idx = 0;
unsigned int last_syllable = 0;
while (buffer->idx < buffer->len)
while (buffer->idx < buffer->len && !buffer->in_error)
{
unsigned int syllable = buffer->cur().syllable();
syllable_type_t syllable_type = (syllable_type_t) (syllable & 0x0F);
@ -513,10 +507,10 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED,
{
last_syllable = syllable;
hb_glyph_info_t info = dottedcircle;
info.cluster = buffer->cur().cluster;
info.mask = buffer->cur().mask;
info.syllable() = buffer->cur().syllable();
hb_glyph_info_t ginfo = dottedcircle;
ginfo.cluster = buffer->cur().cluster;
ginfo.mask = buffer->cur().mask;
ginfo.syllable() = buffer->cur().syllable();
/* TODO Set glyph_props? */
/* Insert dottedcircle after possible Repha. */
@ -525,7 +519,7 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED,
buffer->cur().use_category() == USE_R)
buffer->next_glyph ();
buffer->output_info (info);
buffer->output_info (ginfo);
}
else
buffer->next_glyph ();
@ -576,6 +570,7 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_use =
data_create_use,
data_destroy_use,
NULL, /* preprocess_text */
NULL, /* postprocess_glyphs */
HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
NULL, /* decompose */
compose_use,

View File

@ -45,5 +45,9 @@ HB_INTERNAL void _hb_ot_shape_fallback_kern (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer);
HB_INTERNAL void _hb_ot_shape_fallback_spaces (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer);
#endif /* HB_OT_SHAPE_FALLBACK_PRIVATE_HH */

View File

@ -224,7 +224,7 @@ position_mark (const hb_ot_shape_plan_t *plan,
pos.x_offset += base_extents.x_bearing + base_extents.width - mark_extents.width / 2 - mark_extents.x_bearing;
break;
}
/* Fall through */
HB_FALLTHROUGH;
default:
case HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW:
@ -259,6 +259,7 @@ position_mark (const hb_ot_shape_plan_t *plan,
case HB_UNICODE_COMBINING_CLASS_BELOW_RIGHT:
/* Add gap, fall-through. */
base_extents.height -= y_gap;
HB_FALLTHROUGH;
case HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW_LEFT:
case HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW:
@ -279,6 +280,7 @@ position_mark (const hb_ot_shape_plan_t *plan,
/* Add gap, fall-through. */
base_extents.y_bearing += y_gap;
base_extents.height -= y_gap;
HB_FALLTHROUGH;
case HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE:
case HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE_RIGHT:
@ -482,3 +484,70 @@ _hb_ot_shape_fallback_kern (const hb_ot_shape_plan_t *plan,
idx = skippy_iter.idx;
}
}
/* Adjusts width of various spaces. */
void
_hb_ot_shape_fallback_spaces (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer)
{
if (!HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction))
return;
hb_glyph_info_t *info = buffer->info;
hb_glyph_position_t *pos = buffer->pos;
unsigned int count = buffer->len;
for (unsigned int i = 0; i < count; i++)
if (_hb_glyph_info_is_unicode_space (&info[i]) && !_hb_glyph_info_ligated (&info[i]))
{
hb_unicode_funcs_t::space_t space_type = _hb_glyph_info_get_unicode_space_fallback_type (&info[i]);
hb_codepoint_t glyph;
typedef hb_unicode_funcs_t t;
switch (space_type)
{
case t::NOT_SPACE: /* Shouldn't happen. */
case t::SPACE:
break;
case t::SPACE_EM:
case t::SPACE_EM_2:
case t::SPACE_EM_3:
case t::SPACE_EM_4:
case t::SPACE_EM_5:
case t::SPACE_EM_6:
case t::SPACE_EM_16:
pos[i].x_advance = (font->x_scale + ((int) space_type)/2) / (int) space_type;
break;
case t::SPACE_4_EM_18:
pos[i].x_advance = font->x_scale * 4 / 18;
break;
case t::SPACE_FIGURE:
for (char u = '0'; u <= '9'; u++)
if (font->get_glyph (u, 0, &glyph))
{
pos[i].x_advance = font->get_glyph_h_advance (glyph);
break;
}
break;
case t::SPACE_PUNCTUATION:
if (font->get_glyph ('.', 0, &glyph))
pos[i].x_advance = font->get_glyph_h_advance (glyph);
else if (font->get_glyph (',', 0, &glyph))
pos[i].x_advance = font->get_glyph_h_advance (glyph);
break;
case t::SPACE_NARROW:
/* Half-space?
* Unicode doc http://www.unicode.org/charts/PDF/U2000.pdf says ~1/4 or 1/5 of EM.
* However, in my testing, many fonts have their regular space being about that
* size. To me, a percentage of the space width makes more sense. Half is as
* good as any. */
pos[i].x_advance /= 2;
break;
}
}
}

View File

@ -62,24 +62,12 @@
* with previous base, use that. This needs the itemizer to have this
* knowledge too. We need to provide assistance to the itemizer.
*
* - When a font does not support a character but supports its decomposition,
* well, use the decomposition (preferring the canonical decomposition, but
* falling back to the compatibility decomposition if necessary). The
* compatibility decomposition is really nice to have, for characters like
* ellipsis, or various-sized space characters.
* - When a font does not support a character but supports its canonical
* decomposition, well, use the decomposition.
*
* - The complex shapers can customize the compose and decompose functions to
* offload some of their requirements to the normalizer. For example, the
* Indic shaper may want to disallow recomposing of two matras.
*
* - We try compatibility decomposition if decomposing through canonical
* decomposition alone failed to find a sequence that the font supports.
* We don't try compatibility decomposition recursively during the canonical
* decomposition phase. This has minimal impact. There are only a handful
* of Greek letter that have canonical decompositions that include characters
* with compatibility decomposition. Those can be found using this command:
*
* egrep "`echo -n ';('; grep ';<' UnicodeData.txt | cut -d';' -f1 | tr '\n' '|'; echo ') '`" UnicodeData.txt
*/
static bool
@ -110,8 +98,8 @@ static inline void
output_char (hb_buffer_t *buffer, hb_codepoint_t unichar, hb_codepoint_t glyph)
{
buffer->cur().glyph_index() = glyph;
buffer->output_glyph (unichar);
_hb_glyph_info_set_unicode_props (&buffer->prev(), buffer->unicode);
buffer->output_glyph (unichar); /* This is very confusing indeed. */
_hb_glyph_info_set_unicode_props (&buffer->prev(), buffer);
}
static inline void
@ -171,28 +159,6 @@ decompose (const hb_ot_shape_normalize_context_t *c, bool shortest, hb_codepoint
return 0;
}
/* Returns 0 if didn't decompose, number of resulting characters otherwise. */
static inline unsigned int
decompose_compatibility (const hb_ot_shape_normalize_context_t *c, hb_codepoint_t u)
{
unsigned int len, i;
hb_codepoint_t decomposed[HB_UNICODE_MAX_DECOMPOSITION_LEN];
hb_codepoint_t glyphs[HB_UNICODE_MAX_DECOMPOSITION_LEN];
len = c->buffer->unicode->decompose_compatibility (u, decomposed);
if (!len)
return 0;
for (i = 0; i < len; i++)
if (!c->font->get_glyph (decomposed[i], 0, &glyphs[i]))
return 0;
for (i = 0; i < len; i++)
output_char (c->buffer, decomposed[i], glyphs[i]);
return len;
}
static inline void
decompose_current_character (const hb_ot_shape_normalize_context_t *c, bool shortest)
{
@ -200,17 +166,50 @@ decompose_current_character (const hb_ot_shape_normalize_context_t *c, bool shor
hb_codepoint_t u = buffer->cur().codepoint;
hb_codepoint_t glyph;
/* Kind of a cute waterfall here... */
if (shortest && c->font->get_glyph (u, 0, &glyph))
{
next_char (buffer, glyph);
else if (decompose (c, shortest, u))
return;
}
if (decompose (c, shortest, u))
{
skip_char (buffer);
else if (!shortest && c->font->get_glyph (u, 0, &glyph))
return;
}
if (!shortest && c->font->get_glyph (u, 0, &glyph))
{
next_char (buffer, glyph);
else if (decompose_compatibility (c, u))
skip_char (buffer);
else
next_char (buffer, glyph); /* glyph is initialized in earlier branches. */
return;
}
if (_hb_glyph_info_is_unicode_space (&buffer->cur()))
{
hb_codepoint_t space_glyph;
hb_unicode_funcs_t::space_t space_type = buffer->unicode->space_fallback_type (u);
if (space_type != hb_unicode_funcs_t::NOT_SPACE && c->font->get_glyph (0x0020u, 0, &space_glyph))
{
_hb_glyph_info_set_unicode_space_fallback_type (&buffer->cur(), space_type);
next_char (buffer, space_glyph);
buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_SPACE_FALLBACK;
return;
}
}
if (u == 0x2011u)
{
/* U+2011 is the only sensible character that is a no-break version of another character
* and not a space. The space ones are handled already. Handle this lone one. */
hb_codepoint_t other_glyph;
if (c->font->get_glyph (0x2010u, 0, &other_glyph))
{
next_char (buffer, other_glyph);
return;
}
}
next_char (buffer, glyph); /* glyph is initialized in earlier branches. */
}
static inline void
@ -219,7 +218,7 @@ handle_variation_selector_cluster (const hb_ot_shape_normalize_context_t *c, uns
/* TODO Currently if there's a variation-selector we give-up, it's just too hard. */
hb_buffer_t * const buffer = c->buffer;
hb_font_t * const font = c->font;
for (; buffer->idx < end - 1;) {
for (; buffer->idx < end - 1 && !buffer->in_error;) {
if (unlikely (buffer->unicode->is_variation_selector (buffer->cur(+1).codepoint))) {
/* The next two lines are some ugly lines... But work. */
if (font->get_glyph (buffer->cur().codepoint, buffer->cur(+1).codepoint, &buffer->cur().glyph_index()))
@ -255,13 +254,13 @@ static inline void
decompose_multi_char_cluster (const hb_ot_shape_normalize_context_t *c, unsigned int end, bool short_circuit)
{
hb_buffer_t * const buffer = c->buffer;
for (unsigned int i = buffer->idx; i < end; i++)
for (unsigned int i = buffer->idx; i < end && !buffer->in_error; i++)
if (unlikely (buffer->unicode->is_variation_selector (buffer->info[i].codepoint))) {
handle_variation_selector_cluster (c, end, short_circuit);
return;
}
while (buffer->idx < end)
while (buffer->idx < end && !buffer->in_error)
decompose_current_character (c, short_circuit);
}
@ -321,7 +320,7 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan,
buffer->clear_output ();
count = buffer->len;
for (buffer->idx = 0; buffer->idx < count;)
for (buffer->idx = 0; buffer->idx < count && !buffer->in_error;)
{
unsigned int end;
for (end = buffer->idx + 1; end < count; end++)
@ -371,7 +370,7 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan,
count = buffer->len;
unsigned int starter = 0;
buffer->next_glyph ();
while (buffer->idx < count)
while (buffer->idx < count && !buffer->in_error)
{
hb_codepoint_t composed, glyph;
if (/* We don't try to compose a non-mark character with it's preceding starter.
@ -400,7 +399,7 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan,
/* Modify starter and carry on. */
buffer->out_info[starter].codepoint = composed;
buffer->out_info[starter].glyph_index() = glyph;
_hb_glyph_info_set_unicode_props (&buffer->out_info[starter], buffer->unicode);
_hb_glyph_info_set_unicode_props (&buffer->out_info[starter], buffer);
continue;
}

View File

@ -228,7 +228,7 @@ hb_set_unicode_props (hb_buffer_t *buffer)
unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
for (unsigned int i = 0; i < count; i++)
_hb_glyph_info_set_unicode_props (&info[i], buffer->unicode);
_hb_glyph_info_set_unicode_props (&info[i], buffer);
}
static void
@ -245,7 +245,7 @@ hb_insert_dotted_circle (hb_buffer_t *buffer, hb_font_t *font)
hb_glyph_info_t dottedcircle = {0};
dottedcircle.codepoint = 0x25CCu;
_hb_glyph_info_set_unicode_props (&dottedcircle, buffer->unicode);
_hb_glyph_info_set_unicode_props (&dottedcircle, buffer);
buffer->clear_output ();
@ -254,7 +254,7 @@ hb_insert_dotted_circle (hb_buffer_t *buffer, hb_font_t *font)
info.cluster = buffer->cur().cluster;
info.mask = buffer->cur().mask;
buffer->output_info (info);
while (buffer->idx < buffer->len)
while (buffer->idx < buffer->len && !buffer->in_error)
buffer->next_glyph ();
buffer->swap_buffers ();
@ -263,7 +263,8 @@ hb_insert_dotted_circle (hb_buffer_t *buffer, hb_font_t *font)
static void
hb_form_clusters (hb_buffer_t *buffer)
{
if (buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES)
if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII) ||
buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES)
return;
/* Loop duplicated in hb_ensure_native_direction(). */
@ -346,7 +347,8 @@ hb_ot_mirror_chars (hb_ot_shape_context_t *c)
static inline void
hb_ot_shape_setup_masks_fraction (hb_ot_shape_context_t *c)
{
if (!c->plan->has_frac)
if (!(c->buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII) ||
!c->plan->has_frac)
return;
hb_buffer_t *buffer = c->buffer;
@ -416,7 +418,8 @@ hb_ot_zero_width_default_ignorables (hb_ot_shape_context_t *c)
{
hb_buffer_t *buffer = c->buffer;
if (buffer->flags & HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES)
if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES) ||
(buffer->flags & HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES))
return;
unsigned int count = buffer->len;
@ -433,7 +436,8 @@ hb_ot_hide_default_ignorables (hb_ot_shape_context_t *c)
{
hb_buffer_t *buffer = c->buffer;
if (buffer->flags & HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES)
if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES) ||
(buffer->flags & HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES))
return;
unsigned int count = buffer->len;
@ -525,7 +529,7 @@ hb_synthesize_glyph_classes (hb_ot_shape_context_t *c)
hb_glyph_info_t *info = c->buffer->info;
for (unsigned int i = 0; i < count; i++)
{
hb_ot_layout_glyph_class_mask_t klass;
hb_ot_layout_glyph_props_flags_t klass;
/* Never mark default-ignorables as marks.
* They won't get in the way of lookups anyway,
@ -549,9 +553,6 @@ hb_ot_substitute_default (hb_ot_shape_context_t *c)
{
hb_buffer_t *buffer = c->buffer;
if (c->plan->shaper->preprocess_text)
c->plan->shaper->preprocess_text (c->plan, buffer, c->font);
hb_ot_shape_initialize_masks (c);
hb_ot_mirror_chars (c);
@ -576,7 +577,6 @@ hb_ot_substitute_complex (hb_ot_shape_context_t *c)
{
hb_buffer_t *buffer = c->buffer;
_hb_buffer_allocate_gsubgpos_vars (buffer);
hb_ot_layout_substitute_start (c->font, buffer);
if (!hb_ot_layout_has_glyph_classes (c->face))
@ -593,6 +593,9 @@ static inline void
hb_ot_substitute (hb_ot_shape_context_t *c)
{
hb_ot_substitute_default (c);
_hb_buffer_allocate_gsubgpos_vars (c->buffer);
hb_ot_substitute_complex (c);
}
@ -615,6 +618,9 @@ zero_mark_width (hb_glyph_position_t *pos)
static inline void
zero_mark_widths_by_unicode (hb_buffer_t *buffer, bool adjust_offsets)
{
if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII))
return;
unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
for (unsigned int i = 0; i < count; i++)
@ -629,6 +635,10 @@ zero_mark_widths_by_unicode (hb_buffer_t *buffer, bool adjust_offsets)
static inline void
zero_mark_widths_by_gdef (hb_buffer_t *buffer, bool adjust_offsets)
{
/* This one is a hack; Technically GDEF can mark ASCII glyphs as marks, but we don't listen. */
if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII))
return;
unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
for (unsigned int i = 0; i < count; i++)
@ -647,18 +657,29 @@ hb_ot_position_default (hb_ot_shape_context_t *c)
unsigned int count = c->buffer->len;
hb_glyph_info_t *info = c->buffer->info;
hb_glyph_position_t *pos = c->buffer->pos;
for (unsigned int i = 0; i < count; i++)
{
c->font->get_glyph_advance_for_direction (info[i].codepoint,
direction,
&pos[i].x_advance,
&pos[i].y_advance);
c->font->subtract_glyph_origin_for_direction (info[i].codepoint,
direction,
&pos[i].x_offset,
&pos[i].y_offset);
if (HB_DIRECTION_IS_HORIZONTAL (direction))
{
for (unsigned int i = 0; i < count; i++)
pos[i].x_advance = c->font->get_glyph_h_advance (info[i].codepoint);
if (c->font->has_glyph_h_origin_func ())
for (unsigned int i = 0; i < count; i++)
c->font->subtract_glyph_h_origin (info[i].codepoint,
&pos[i].x_offset,
&pos[i].y_offset);
}
else
{
for (unsigned int i = 0; i < count; i++)
pos[i].y_advance = c->font->get_glyph_v_advance (info[i].codepoint);
if (c->font->has_glyph_v_origin_func ())
for (unsigned int i = 0; i < count; i++)
c->font->subtract_glyph_v_origin (info[i].codepoint,
&pos[i].x_offset,
&pos[i].y_offset);
}
if (c->buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_SPACE_FALLBACK)
_hb_ot_shape_fallback_spaces (c->plan, c->font, c->buffer);
}
static inline bool
@ -703,23 +724,21 @@ hb_ot_position_complex (hb_ot_shape_context_t *c)
hb_glyph_info_t *info = c->buffer->info;
hb_glyph_position_t *pos = c->buffer->pos;
/* Change glyph origin to what GPOS expects, apply GPOS, change it back. */
/* Change glyph origin to what GPOS expects (horizontal), apply GPOS, change it back. */
for (unsigned int i = 0; i < count; i++) {
c->font->add_glyph_origin_for_direction (info[i].codepoint,
HB_DIRECTION_LTR,
&pos[i].x_offset,
&pos[i].y_offset);
}
if (c->font->has_glyph_h_origin_func ())
for (unsigned int i = 0; i < count; i++)
c->font->add_glyph_h_origin (info[i].codepoint,
&pos[i].x_offset,
&pos[i].y_offset);
c->plan->position (c->font, c->buffer);
for (unsigned int i = 0; i < count; i++) {
c->font->subtract_glyph_origin_for_direction (info[i].codepoint,
HB_DIRECTION_LTR,
&pos[i].x_offset,
&pos[i].y_offset);
}
if (c->font->has_glyph_h_origin_func ())
for (unsigned int i = 0; i < count; i++)
c->font->subtract_glyph_h_origin (info[i].codepoint,
&pos[i].x_offset,
&pos[i].y_offset);
ret = true;
}
@ -778,6 +797,12 @@ 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_int_mul_overflows (c->buffer->len, HB_BUFFER_MAX_EXPANSION_FACTOR)))
{
c->buffer->max_len = MAX (c->buffer->len * HB_BUFFER_MAX_EXPANSION_FACTOR,
(unsigned) HB_BUFFER_MAX_LEN_MIN);
}
/* Save the original direction, we use it later. */
c->target_direction = c->buffer->props.direction;
@ -792,15 +817,22 @@ hb_ot_shape_internal (hb_ot_shape_context_t *c)
hb_ensure_native_direction (c->buffer);
if (c->plan->shaper->preprocess_text)
c->plan->shaper->preprocess_text (c->plan, c->buffer, c->font);
hb_ot_substitute (c);
hb_ot_position (c);
hb_ot_hide_default_ignorables (c);
if (c->plan->shaper->postprocess_glyphs)
c->plan->shaper->postprocess_glyphs (c->plan, c->buffer, c->font);
_hb_buffer_deallocate_unicode_vars (c->buffer);
c->buffer->props.direction = c->target_direction;
c->buffer->max_len = HB_BUFFER_MAX_LEN_DEFAULT;
c->buffer->deallocate_var_all ();
}

View File

@ -53,6 +53,9 @@
#include <errno.h>
#include <stdarg.h>
#ifdef _MSC_VER
#include <windows.h> /* ensure DEFINE_ENUM_FLAG_OPERATORS is defined */
#endif
/* Compile-time custom allocator support. */
@ -119,6 +122,36 @@ extern "C" void hb_free_impl(void *ptr);
#define HB_FUNC __func__
#endif
/*
* Borrowed from https://bugzilla.mozilla.org/show_bug.cgi?id=1215411
* HB_FALLTHROUGH is an annotation to suppress compiler warnings about switch
* cases that fall through without a break or return statement. HB_FALLTHROUGH
* is only needed on cases that have code:
*
* switch (foo) {
* case 1: // These cases have no code. No fallthrough annotations are needed.
* case 2:
* case 3:
* foo = 4; // This case has code, so a fallthrough annotation is needed:
* HB_FALLTHROUGH;
* default:
* return foo;
* }
*/
#if defined(__clang__) && __cplusplus >= 201103L
/* clang's fallthrough annotations are only available starting in C++11. */
# define HB_FALLTHROUGH [[clang::fallthrough]]
#elif defined(_MSC_VER)
/*
* MSVC's __fallthrough annotations are checked by /analyze (Code Analysis):
* https://msdn.microsoft.com/en-us/library/ms235402%28VS.80%29.aspx
*/
# include <sal.h>
# define HB_FALLTHROUGH __fallthrough
#else
# define HB_FALLTHROUGH /* FALLTHROUGH */
#endif
#if defined(_WIN32) || defined(__CYGWIN__)
/* We need Windows Vista for both Uniscribe backend and for
* MemoryBarrier. We don't support compiling on Windows XP,
@ -210,9 +243,9 @@ static inline unsigned int ARRAY_LENGTH (const Type (&)[n]) { return n; }
#define _ASSERT_STATIC0(_line, _cond) _ASSERT_STATIC1 (_line, (_cond))
#define ASSERT_STATIC(_cond) _ASSERT_STATIC0 (__LINE__, (_cond))
/* Note: C++ allows sizeof() of variable-lengh arrays. So, if _cond is not
* constant, it still compiles (ouch!), but at least we'll get a -Wvla warning. */
#define ASSERT_STATIC_EXPR_ZERO(_cond) (0 * sizeof (char[(_cond) ? 1 : -1]))
template <unsigned int cond> class hb_assert_constant_t {};
#define ASSERT_STATIC_EXPR_ZERO(_cond) (0 * (unsigned int) sizeof (hb_assert_constant_t<_cond>))
#define _PASTE1(a,b) a##b
#define PASTE(a,b) _PASTE1(a,b)
@ -861,6 +894,34 @@ hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2, T lo3, T hi3)
}
/* Enable bitwise ops on enums marked as flags_t */
/* To my surprise, looks like the function resolver is happy to silently cast
* one enum to another... So this doesn't provide the type-checking that I
* originally had in mind... :(.
*
* On MSVC use DEFINE_ENUM_FLAG_OPERATORS. See:
* https://github.com/behdad/harfbuzz/pull/163
*/
#ifdef _MSC_VER
# pragma warning(disable:4200)
# pragma warning(disable:4800)
# define HB_MARK_AS_FLAG_T(flags_t) DEFINE_ENUM_FLAG_OPERATORS (##flags_t##);
#else
# define HB_MARK_AS_FLAG_T(flags_t) template <> class hb_mark_as_flags_t<flags_t> {};
template <class T> class hb_mark_as_flags_t;
template <class T> static inline T operator | (T l, T r)
{ hb_mark_as_flags_t<T> unused HB_UNUSED; return T ((unsigned int) l | (unsigned int) r); }
template <class T> static inline T operator & (T l, T r)
{ hb_mark_as_flags_t<T> unused HB_UNUSED; return T ((unsigned int) l & (unsigned int) r); }
template <class T> static inline T operator ~ (T r)
{ hb_mark_as_flags_t<T> unused HB_UNUSED; return T (~(unsigned int) r); }
template <class T> static inline T& operator |= (T &l, T r)
{ hb_mark_as_flags_t<T> unused HB_UNUSED; l = l | r; return l; }
template <class T> static inline T& operator &= (T& l, T r)
{ hb_mark_as_flags_t<T> unused HB_UNUSED; l = l & r; return l; }
#endif
/* Useful for set-operations on small enums.
* For example, for testing "x ∈ {x1, x2, x3}" use:
* (FLAG_SAFE(x) & (FLAG(x1) | FLAG(x2) | FLAG(x3)))

View File

@ -199,6 +199,50 @@ HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE
}
}
/* Space estimates based on:
* http://www.unicode.org/charts/PDF/U2000.pdf
* https://www.microsoft.com/typography/developers/fdsspec/spaces.aspx
*/
enum space_t {
NOT_SPACE = 0,
SPACE_EM = 1,
SPACE_EM_2 = 2,
SPACE_EM_3 = 3,
SPACE_EM_4 = 4,
SPACE_EM_5 = 5,
SPACE_EM_6 = 6,
SPACE_EM_16 = 16,
SPACE_4_EM_18, /* 4/18th of an EM! */
SPACE,
SPACE_FIGURE,
SPACE_PUNCTUATION,
SPACE_NARROW,
};
static inline space_t
space_fallback_type (hb_codepoint_t u)
{
switch (u)
{
/* All GC=Zs chars that can use a fallback. */
default: return NOT_SPACE; /* Shouldn't happen. */
case 0x0020u: return SPACE; /* U+0020 SPACE */
case 0x00A0u: return SPACE; /* U+00A0 NO-BREAK SPACE */
case 0x2000u: return SPACE_EM_2; /* U+2000 EN QUAD */
case 0x2001u: return SPACE_EM; /* U+2001 EM QUAD */
case 0x2002u: return SPACE_EM_2; /* U+2002 EN SPACE */
case 0x2003u: return SPACE_EM; /* U+2003 EM SPACE */
case 0x2004u: return SPACE_EM_3; /* U+2004 THREE-PER-EM SPACE */
case 0x2005u: return SPACE_EM_4; /* U+2005 FOUR-PER-EM SPACE */
case 0x2006u: return SPACE_EM_6; /* U+2006 SIX-PER-EM SPACE */
case 0x2007u: return SPACE_FIGURE; /* U+2007 FIGURE SPACE */
case 0x2008u: return SPACE_PUNCTUATION; /* U+2008 PUNCTUATION SPACE */
case 0x2009u: return SPACE_EM_5; /* U+2009 THIN SPACE */
case 0x200Au: return SPACE_EM_16; /* U+200A HAIR SPACE */
case 0x202Fu: return SPACE_NARROW; /* U+202F NARROW NO-BREAK SPACE */
case 0x205Fu: return SPACE_4_EM_18; /* U+205F MEDIUM MATHEMATICAL SPACE */
case 0x3000u: return SPACE_EM; /* U+3000 IDEOGRAPHIC SPACE */
}
}
struct {
#define HB_UNICODE_FUNC_IMPLEMENT(name) hb_unicode_##name##_func_t name;
@ -313,5 +357,9 @@ extern HB_INTERNAL const hb_unicode_funcs_t _hb_unicode_funcs_nil;
FLAG (HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK) | \
FLAG (HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)))
#define HB_UNICODE_GENERAL_CATEGORY_IS_NON_ENCLOSING_MARK(gen_cat) \
(FLAG_SAFE (gen_cat) & \
(FLAG (HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK) | \
FLAG (HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)))
#endif /* HB_UNICODE_PRIVATE_HH */

View File

@ -146,11 +146,11 @@ struct hb_utf16_t
return text;
}
if (likely (hb_in_range (c, 0xD800u, 0xDBFFu)))
if (likely (c <= 0xDBFFu && text < end))
{
/* High-surrogate in c */
hb_codepoint_t l;
if (text < end && ((l = *text), likely (hb_in_range (l, 0xDC00u, 0xDFFFu))))
hb_codepoint_t l = *text;
if (likely (hb_in_range (l, 0xDC00u, 0xDFFFu)))
{
/* Low-surrogate in l */
*unicode = (c << 10) + l - ((0xD800u << 10) - 0x10000u + 0xDC00u);
@ -170,8 +170,7 @@ struct hb_utf16_t
hb_codepoint_t *unicode,
hb_codepoint_t replacement)
{
const uint16_t *end = text--;
hb_codepoint_t c = *text;
hb_codepoint_t c = *--text;
if (likely (!hb_in_range (c, 0xD800u, 0xDFFFu)))
{
@ -179,14 +178,22 @@ struct hb_utf16_t
return text;
}
if (likely (start < text && hb_in_range (c, 0xDC00u, 0xDFFFu)))
text--;
if (likely (next (text, end, unicode, replacement) == end))
return text;
if (likely (c >= 0xDC00u && start < text))
{
/* Low-surrogate in c */
hb_codepoint_t h = text[-1];
if (likely (hb_in_range (h, 0xD800u, 0xDBFFu)))
{
/* High-surrogate in h */
*unicode = (h << 10) + c - ((0xD800u << 10) - 0x10000u + 0xDC00u);
text--;
return text;
}
}
/* Lonely / out-of-order surrogate. */
*unicode = replacement;
return end - 1;
return text;
}
@ -211,14 +218,9 @@ struct hb_utf32_t
hb_codepoint_t *unicode,
hb_codepoint_t replacement)
{
hb_codepoint_t c = *text++;
if (validate && unlikely (c > 0x10FFFFu || hb_in_range (c, 0xD800u, 0xDFFFu)))
goto error;
*unicode = c;
return text;
error:
*unicode = replacement;
hb_codepoint_t c = *unicode = *text++;
if (validate && unlikely (c >= 0xD800u && (c <= 0xDFFFu || c > 0x10FFFFu)))
*unicode = replacement;
return text;
}
@ -228,8 +230,10 @@ struct hb_utf32_t
hb_codepoint_t *unicode,
hb_codepoint_t replacement)
{
next (text - 1, text, unicode, replacement);
return text - 1;
hb_codepoint_t c = *unicode = *--text;
if (validate && unlikely (c >= 0xD800u && (c <= 0xDFFFu || c > 0x10FFFFu)))
*unicode = replacement;
return text;
}
static inline unsigned int

View File

@ -37,10 +37,10 @@ HB_BEGIN_DECLS
#define HB_VERSION_MAJOR 1
#define HB_VERSION_MINOR 0
#define HB_VERSION_MICRO 6
#define HB_VERSION_MINOR 1
#define HB_VERSION_MICRO 0
#define HB_VERSION_STRING "1.0.6"
#define HB_VERSION_STRING "1.1.0"
#define HB_VERSION_ATLEAST(major,minor,micro) \
((major)*10000+(minor)*100+(micro) <= \