Merge mozilla-central to mozilla-inbound

This commit is contained in:
Ed Morley 2012-11-19 15:46:27 +00:00
commit 89e976f545
52 changed files with 2627 additions and 1447 deletions

View File

@ -43,7 +43,6 @@ HBSOURCES = \
hb-shape.cc \
hb-shape-plan-private.hh \
hb-shape-plan.cc \
hb-shape-plan.h \
hb-shaper-list.hh \
hb-shaper-impl-private.hh \
hb-shaper-private.hh \
@ -62,6 +61,7 @@ HBHEADERS = \
hb-font.h \
hb-set.h \
hb-shape.h \
hb-shape-plan.h \
hb-unicode.h \
hb-version.h \
$(NULL)
@ -81,11 +81,12 @@ HBSOURCES += \
hb-ot-shape-complex-arabic.cc \
hb-ot-shape-complex-arabic-fallback.hh \
hb-ot-shape-complex-arabic-table.hh \
hb-ot-shape-complex-default.cc \
hb-ot-shape-complex-indic.cc \
hb-ot-shape-complex-indic-machine.hh \
hb-ot-shape-complex-indic-private.hh \
hb-ot-shape-complex-indic-table.hh \
hb-ot-shape-complex-misc.cc \
hb-ot-shape-complex-thai.cc \
hb-ot-shape-complex-private.hh \
hb-ot-shape-normalize-private.hh \
hb-ot-shape-normalize.cc \
@ -242,7 +243,7 @@ arabic-table: gen-arabic-table.py ArabicShaping.txt UnicodeData.txt
.PHONY: unicode-tables arabic-table indic-table
EXTRA_DIST += hb-ot-shape-complex-indic-machine.rl
hb-ot-shape-complex-indic-machine.hh: hb-ot-shape-complex-indic-machine.rl
$(srcdir)/hb-ot-shape-complex-indic-machine.hh: hb-ot-shape-complex-indic-machine.rl
$(AM_V_GEN)$(top_srcdir)/missing --run ragel -e -F1 -o "$@.tmp" "$<" && \
mv "$@.tmp" "$@" || ( $(RM) "$@.tmp" && false )

View File

@ -47,8 +47,9 @@ CPPSRCS = \
hb-ot-layout.cc \
hb-ot-map.cc \
hb-ot-shape-complex-arabic.cc \
hb-ot-shape-complex-default.cc \
hb-ot-shape-complex-indic.cc \
hb-ot-shape-complex-misc.cc \
hb-ot-shape-complex-thai.cc \
hb-ot-shape-fallback.cc \
hb-ot-shape-normalize.cc \
hb-ot-shape.cc \

View File

@ -36,47 +36,10 @@
#include "hb-unicode-private.hh"
ASSERT_STATIC (sizeof (hb_glyph_info_t) == 20);
ASSERT_STATIC (sizeof (hb_glyph_info_t) == sizeof (hb_glyph_position_t));
/*
* hb_segment_properties_t
*/
typedef struct hb_segment_properties_t {
hb_direction_t direction;
hb_script_t script;
hb_language_t language;
ASSERT_POD ();
} hb_segment_properties_t;
#define _HB_BUFFER_PROPS_DEFAULT { HB_DIRECTION_INVALID, HB_SCRIPT_INVALID, HB_LANGUAGE_INVALID }
static inline hb_bool_t
hb_segment_properties_equal (const hb_segment_properties_t *a,
const hb_segment_properties_t *b)
{
return a->direction == b->direction &&
a->script == b->script &&
a->language == b->language;
}
#if 0
static inline unsigned int
hb_segment_properties_hash (const hb_segment_properties_t *p)
{
/* TODO improve */
return (unsigned int) p->direction +
(unsigned int) p->script +
(intptr_t) (p->language);
}
#endif
/*
* hb_buffer_t
*/
@ -89,6 +52,7 @@ struct hb_buffer_t {
hb_unicode_funcs_t *unicode; /* Unicode functions */
hb_segment_properties_t props; /* Script, language, direction */
hb_buffer_flags_t flags; /* BOT / EOT / etc. */
/* Buffer contents */
@ -133,6 +97,7 @@ struct hb_buffer_t {
/* Methods */
HB_INTERNAL void reset (void);
HB_INTERNAL void clear (void);
inline unsigned int backtrack_len (void) const
{ return have_output? out_len : idx; }
@ -144,15 +109,15 @@ struct hb_buffer_t {
HB_INTERNAL void deallocate_var_all (void);
HB_INTERNAL void add (hb_codepoint_t codepoint,
hb_mask_t mask,
unsigned int cluster);
HB_INTERNAL void reverse_range (unsigned int start, unsigned int end);
HB_INTERNAL void reverse (void);
HB_INTERNAL void reverse_clusters (void);
HB_INTERNAL void guess_properties (void);
HB_INTERNAL void guess_segment_properties (void);
HB_INTERNAL void swap_buffers (void);
HB_INTERNAL void remove_output (void);
HB_INTERNAL void clear_output (void);
HB_INTERNAL void clear_positions (void);

View File

@ -35,6 +35,29 @@
#define HB_DEBUG_BUFFER (HB_DEBUG+0)
#endif
hb_bool_t
hb_segment_properties_equal (const hb_segment_properties_t *a,
const hb_segment_properties_t *b)
{
return a->direction == b->direction &&
a->script == b->script &&
a->language == b->language &&
a->reserved1 == b->reserved1 &&
a->reserved2 == b->reserved2;
}
unsigned int
hb_segment_properties_hash (const hb_segment_properties_t *p)
{
return (unsigned int) p->direction ^
(unsigned int) p->script ^
(intptr_t) (p->language);
}
/* Here is how the buffer works internally:
*
* There are two info pointers: info and out_info. They always have
@ -71,7 +94,7 @@ hb_buffer_t::enlarge (unsigned int size)
if (unlikely (_hb_unsigned_int_mul_overflows (size, sizeof (info[0]))))
goto done;
while (size > new_allocated)
while (size >= new_allocated)
new_allocated += (new_allocated >> 1) + 32;
ASSERT_STATIC (sizeof (info[0]) == sizeof (pos[0]));
@ -142,8 +165,18 @@ hb_buffer_t::reset (void)
hb_unicode_funcs_destroy (unicode);
unicode = hb_unicode_funcs_get_default ();
hb_segment_properties_t default_props = _HB_BUFFER_PROPS_DEFAULT;
clear ();
}
void
hb_buffer_t::clear (void)
{
if (unlikely (hb_object_is_inert (this)))
return;
hb_segment_properties_t default_props = HB_SEGMENT_PROPERTIES_DEFAULT;
props = default_props;
flags = HB_BUFFER_FLAGS_DEFAULT;
content_type = HB_BUFFER_CONTENT_TYPE_INVALID;
in_error = false;
@ -165,7 +198,6 @@ hb_buffer_t::reset (void)
void
hb_buffer_t::add (hb_codepoint_t codepoint,
hb_mask_t mask,
unsigned int cluster)
{
hb_glyph_info_t *glyph;
@ -176,12 +208,25 @@ hb_buffer_t::add (hb_codepoint_t codepoint,
memset (glyph, 0, sizeof (*glyph));
glyph->codepoint = codepoint;
glyph->mask = mask;
glyph->mask = 1;
glyph->cluster = cluster;
len++;
}
void
hb_buffer_t::remove_output (void)
{
if (unlikely (hb_object_is_inert (this)))
return;
have_output = false;
have_positions = false;
out_len = 0;
out_info = info;
}
void
hb_buffer_t::clear_output (void)
{
@ -446,7 +491,7 @@ hb_buffer_t::merge_out_clusters (unsigned int start,
}
void
hb_buffer_t::guess_properties (void)
hb_buffer_t::guess_segment_properties (void)
{
if (unlikely (!len)) return;
assert (content_type == HB_BUFFER_CONTENT_TYPE_UNICODE);
@ -548,7 +593,7 @@ void hb_buffer_t::deallocate_var_all (void)
/* Public API */
hb_buffer_t *
hb_buffer_create ()
hb_buffer_create (void)
{
hb_buffer_t *buffer;
@ -567,7 +612,8 @@ hb_buffer_get_empty (void)
HB_OBJECT_HEADER_STATIC,
const_cast<hb_unicode_funcs_t *> (&_hb_unicode_funcs_nil),
_HB_BUFFER_PROPS_DEFAULT,
HB_SEGMENT_PROPERTIES_DEFAULT,
HB_BUFFER_FLAGS_DEFAULT,
HB_BUFFER_CONTENT_TYPE_INVALID,
true, /* in_error */
@ -702,6 +748,40 @@ hb_buffer_get_language (hb_buffer_t *buffer)
return buffer->props.language;
}
void
hb_buffer_set_segment_properties (hb_buffer_t *buffer,
const hb_segment_properties_t *props)
{
if (unlikely (hb_object_is_inert (buffer)))
return;
buffer->props = *props;
}
void
hb_buffer_get_segment_properties (hb_buffer_t *buffer,
hb_segment_properties_t *props)
{
*props = buffer->props;
}
void
hb_buffer_set_flags (hb_buffer_t *buffer,
hb_buffer_flags_t flags)
{
if (unlikely (hb_object_is_inert (buffer)))
return;
buffer->flags = flags;
}
hb_buffer_flags_t
hb_buffer_get_flags (hb_buffer_t *buffer)
{
return buffer->flags;
}
void
hb_buffer_reset (hb_buffer_t *buffer)
@ -709,6 +789,12 @@ hb_buffer_reset (hb_buffer_t *buffer)
buffer->reset ();
}
void
hb_buffer_clear (hb_buffer_t *buffer)
{
buffer->clear ();
}
hb_bool_t
hb_buffer_pre_allocate (hb_buffer_t *buffer, unsigned int size)
{
@ -724,10 +810,9 @@ hb_buffer_allocation_successful (hb_buffer_t *buffer)
void
hb_buffer_add (hb_buffer_t *buffer,
hb_codepoint_t codepoint,
hb_mask_t mask,
unsigned int cluster)
{
buffer->add (codepoint, mask, cluster);
buffer->add (codepoint, cluster);
buffer->clear_context (1);
}
@ -801,9 +886,9 @@ hb_buffer_reverse_clusters (hb_buffer_t *buffer)
}
void
hb_buffer_guess_properties (hb_buffer_t *buffer)
hb_buffer_guess_segment_properties (hb_buffer_t *buffer)
{
buffer->guess_properties ();
buffer->guess_segment_properties ();
}
template <typename T>
@ -828,7 +913,14 @@ hb_buffer_add_utf (hb_buffer_t *buffer,
buffer->ensure (buffer->len + item_length * sizeof (T) / 4);
if (!buffer->len)
/* If buffer is empty and pre-context provided, install it.
* This check is written this way, to make sure people can
* provide pre-context in one add_utf() call, then provide
* text in a follow-up call. See:
*
* https://bugzilla.mozilla.org/show_bug.cgi?id=801410#c13
*/
if (!buffer->len && item_offset > 0)
{
/* Add pre-context */
buffer->clear_context (0);
@ -849,7 +941,7 @@ hb_buffer_add_utf (hb_buffer_t *buffer,
hb_codepoint_t u;
const T *old_next = next;
next = hb_utf_next (next, end, &u);
buffer->add (u, 1, old_next - (const T *) text);
buffer->add (u, old_next - (const T *) text);
}
/* Add post-context */
@ -972,3 +1064,231 @@ hb_buffer_normalize_glyphs (hb_buffer_t *buffer)
}
normalize_glyphs_cluster (buffer, start, end, backward);
}
/*
* Serialize
*/
static const char *serialize_formats[] = {
"TEXT",
"JSON",
NULL
};
const char **
hb_buffer_serialize_list_formats (void)
{
return serialize_formats;
}
hb_buffer_serialize_format_t
hb_buffer_serialize_format_from_string (const char *str, int len)
{
/* Upper-case it. */
return (hb_buffer_serialize_format_t) (hb_tag_from_string (str, len) & ~0x20202020);
}
const char *
hb_buffer_serialize_format_to_string (hb_buffer_serialize_format_t format)
{
switch (format)
{
case HB_BUFFER_SERIALIZE_FORMAT_TEXT: return serialize_formats[0];
case HB_BUFFER_SERIALIZE_FORMAT_JSON: return serialize_formats[1];
default:
case HB_BUFFER_SERIALIZE_FORMAT_INVALID: return NULL;
}
}
static unsigned int
_hb_buffer_serialize_glyphs_json (hb_buffer_t *buffer,
unsigned int start,
unsigned int end,
char *buf,
unsigned int buf_size,
unsigned int *buf_consumed,
hb_font_t *font,
hb_buffer_serialize_flags_t flags)
{
hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, NULL);
hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, NULL);
*buf_consumed = 0;
for (unsigned int i = start; i < end; i++)
{
char b[1024];
char *p = b;
/* In the following code, we know b is large enough that no overflow can happen. */
#define APPEND(s) HB_STMT_START { strcpy (p, s); p += strlen (s); } HB_STMT_END
if (i)
*p++ = ',';
*p++ = '{';
APPEND ("\"g\":");
if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES))
{
char g[128];
hb_font_glyph_to_string (font, info[i].codepoint, g, sizeof (g));
*p++ = '"';
for (char *q = g; *q; q++) {
if (*q == '"')
*p++ = '\\';
*p++ = *q;
}
*p++ = '"';
}
else
p += snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint);
if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) {
p += snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"cl\":%u", info[i].cluster);
}
if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS))
{
p += snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"dx\":%d,\"dy\":%d",
pos[i].x_offset, pos[i].y_offset);
p += snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"ax\":%d,\"ay\":%d",
pos[i].x_advance, pos[i].y_advance);
}
*p++ = '}';
if (buf_size > (p - b))
{
unsigned int l = p - b;
memcpy (buf, b, l);
buf += l;
buf_size -= l;
*buf_consumed += l;
*buf = '\0';
} else
return i - start;
}
return end - start;
}
static unsigned int
_hb_buffer_serialize_glyphs_text (hb_buffer_t *buffer,
unsigned int start,
unsigned int end,
char *buf,
unsigned int buf_size,
unsigned int *buf_consumed,
hb_font_t *font,
hb_buffer_serialize_flags_t flags)
{
hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, NULL);
hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, NULL);
hb_direction_t direction = hb_buffer_get_direction (buffer);
*buf_consumed = 0;
for (unsigned int i = start; i < end; i++)
{
char b[1024];
char *p = b;
/* In the following code, we know b is large enough that no overflow can happen. */
if (i)
*p++ = '|';
if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES))
{
hb_font_glyph_to_string (font, info[i].codepoint, p, 128);
p += strlen (p);
}
else
p += snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint);
if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) {
p += snprintf (p, ARRAY_LENGTH (b) - (p - b), "=%u", info[i].cluster);
}
if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS))
{
if (pos[i].x_offset || pos[i].y_offset)
p += snprintf (p, ARRAY_LENGTH (b) - (p - b), "@%d,%d", pos[i].x_offset, pos[i].y_offset);
*p++ = '+';
if (HB_DIRECTION_IS_HORIZONTAL (direction) || pos[i].x_advance)
p += snprintf (p, ARRAY_LENGTH (b) - (p - b), "%d", pos[i].x_advance);
if (HB_DIRECTION_IS_VERTICAL (direction) || pos->y_advance)
p += snprintf (p, ARRAY_LENGTH (b) - (p - b), ",%d", pos[i].y_advance);
}
if (buf_size > (p - b))
{
unsigned int l = p - b;
memcpy (buf, b, l);
buf += l;
buf_size -= l;
*buf_consumed += l;
*buf = '\0';
} else
return i - start;
}
return end - start;
}
/* Returns number of items, starting at start, that were serialized. */
unsigned int
hb_buffer_serialize_glyphs (hb_buffer_t *buffer,
unsigned int start,
unsigned int end,
char *buf,
unsigned int buf_size,
unsigned int *buf_consumed,
hb_font_t *font, /* May be NULL */
hb_buffer_serialize_format_t format,
hb_buffer_serialize_flags_t flags)
{
assert (start <= end && end <= buffer->len);
*buf_consumed = 0;
assert ((!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID) ||
buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS);
if (unlikely (start == end))
return 0;
if (!font)
font = hb_font_get_empty ();
switch (format)
{
case HB_BUFFER_SERIALIZE_FORMAT_TEXT:
return _hb_buffer_serialize_glyphs_text (buffer, start, end,
buf, buf_size, buf_consumed,
font, flags);
case HB_BUFFER_SERIALIZE_FORMAT_JSON:
return _hb_buffer_serialize_glyphs_json (buffer, start, end,
buf, buf_size, buf_consumed,
font, flags);
default:
case HB_BUFFER_SERIALIZE_FORMAT_INVALID:
return 0;
}
}
hb_bool_t
hb_buffer_deserialize_glyphs (hb_buffer_t *buffer,
const char *buf,
unsigned int buf_len,
unsigned int *buf_consumed,
hb_font_t *font, /* May be NULL */
hb_buffer_serialize_format_t format)
{
return false;
}

View File

@ -36,12 +36,11 @@
#include "hb-common.h"
#include "hb-unicode.h"
#include "hb-font.h"
HB_BEGIN_DECLS
typedef struct hb_buffer_t hb_buffer_t;
typedef struct hb_glyph_info_t {
hb_codepoint_t codepoint;
hb_mask_t mask;
@ -62,12 +61,36 @@ typedef struct hb_glyph_position_t {
hb_var_int_t var;
} hb_glyph_position_t;
typedef enum {
HB_BUFFER_CONTENT_TYPE_INVALID = 0,
HB_BUFFER_CONTENT_TYPE_UNICODE,
HB_BUFFER_CONTENT_TYPE_GLYPHS
} hb_buffer_content_type_t;
typedef struct hb_segment_properties_t {
hb_direction_t direction;
hb_script_t script;
hb_language_t language;
/*< private >*/
void *reserved1;
void *reserved2;
} hb_segment_properties_t;
#define HB_SEGMENT_PROPERTIES_DEFAULT {HB_DIRECTION_INVALID, \
HB_SCRIPT_INVALID, \
HB_LANGUAGE_INVALID, \
NULL, \
NULL}
hb_bool_t
hb_segment_properties_equal (const hb_segment_properties_t *a,
const hb_segment_properties_t *b);
unsigned int
hb_segment_properties_hash (const hb_segment_properties_t *p);
/*
* hb_buffer_t
*/
typedef struct hb_buffer_t hb_buffer_t;
hb_buffer_t *
hb_buffer_create (void);
@ -93,6 +116,12 @@ hb_buffer_get_user_data (hb_buffer_t *buffer,
hb_user_data_key_t *key);
typedef enum {
HB_BUFFER_CONTENT_TYPE_INVALID = 0,
HB_BUFFER_CONTENT_TYPE_UNICODE,
HB_BUFFER_CONTENT_TYPE_GLYPHS
} hb_buffer_content_type_t;
void
hb_buffer_set_content_type (hb_buffer_t *buffer,
hb_buffer_content_type_t content_type);
@ -126,15 +155,46 @@ void
hb_buffer_set_language (hb_buffer_t *buffer,
hb_language_t language);
hb_language_t
hb_buffer_get_language (hb_buffer_t *buffer);
void
hb_buffer_set_segment_properties (hb_buffer_t *buffer,
const hb_segment_properties_t *props);
void
hb_buffer_get_segment_properties (hb_buffer_t *buffer,
hb_segment_properties_t *props);
void
hb_buffer_guess_segment_properties (hb_buffer_t *buffer);
typedef enum {
HB_BUFFER_FLAGS_DEFAULT = 0x00000000,
HB_BUFFER_FLAG_BOT = 0x00000001, /* Beginning-of-text */
HB_BUFFER_FLAG_EOT = 0x00000002, /* End-of-text */
HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES = 0x00000004
} hb_buffer_flags_t;
void
hb_buffer_set_flags (hb_buffer_t *buffer,
hb_buffer_flags_t flags);
hb_buffer_flags_t
hb_buffer_get_flags (hb_buffer_t *buffer);
/* Resets the buffer. Afterwards it's as if it was just created,
* except that it has a larger buffer allocated perhaps... */
void
hb_buffer_reset (hb_buffer_t *buffer);
/* Like reset, but does NOT clear unicode_funcs. */
void
hb_buffer_clear (hb_buffer_t *buffer);
/* Returns false if allocation failed */
hb_bool_t
hb_buffer_pre_allocate (hb_buffer_t *buffer,
@ -151,16 +211,12 @@ hb_buffer_reverse (hb_buffer_t *buffer);
void
hb_buffer_reverse_clusters (hb_buffer_t *buffer);
void
hb_buffer_guess_properties (hb_buffer_t *buffer);
/* Filling the buffer in */
void
hb_buffer_add (hb_buffer_t *buffer,
hb_codepoint_t codepoint,
hb_mask_t mask,
unsigned int cluster);
void
@ -213,11 +269,53 @@ hb_buffer_get_glyph_positions (hb_buffer_t *buffer,
void
hb_buffer_normalize_glyphs (hb_buffer_t *buffer);
/*
* NOT IMPLEMENTED
void
hb_buffer_normalize_characters (hb_buffer_t *buffer);
*/
* Serialize
*/
typedef enum {
HB_BUFFER_SERIALIZE_FLAGS_DEFAULT = 0x00000000,
HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS = 0x00000001,
HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS = 0x00000002,
HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES = 0x00000004
} hb_buffer_serialize_flags_t;
typedef enum {
HB_BUFFER_SERIALIZE_FORMAT_TEXT = HB_TAG('T','E','X','T'),
HB_BUFFER_SERIALIZE_FORMAT_JSON = HB_TAG('J','S','O','N'),
HB_BUFFER_SERIALIZE_FORMAT_INVALID = HB_TAG_NONE
} hb_buffer_serialize_format_t;
/* len=-1 means str is NUL-terminated. */
hb_buffer_serialize_format_t
hb_buffer_serialize_format_from_string (const char *str, int len);
const char *
hb_buffer_serialize_format_to_string (hb_buffer_serialize_format_t format);
const char **
hb_buffer_serialize_list_formats (void);
/* Returns number of items, starting at start, that were serialized. */
unsigned int
hb_buffer_serialize_glyphs (hb_buffer_t *buffer,
unsigned int start,
unsigned int end,
char *buf,
unsigned int buf_size,
unsigned int *buf_consumed,
hb_font_t *font, /* May be NULL */
hb_buffer_serialize_format_t format,
hb_buffer_serialize_flags_t flags);
hb_bool_t
hb_buffer_deserialize_glyphs (hb_buffer_t *buffer,
const char *buf,
unsigned int buf_len,
unsigned int *buf_consumed,
hb_font_t *font, /* May be NULL */
hb_buffer_serialize_format_t format);
HB_END_DECLS

View File

@ -98,14 +98,14 @@ _hb_fallback_shape (hb_shape_plan_t *shape_plan,
hb_codepoint_t space;
font->get_glyph (' ', 0, &space);
buffer->guess_properties ();
buffer->guess_segment_properties ();
buffer->clear_positions ();
unsigned int count = buffer->len;
for (unsigned int i = 0; i < count; i++)
{
if (buffer->unicode->is_zero_width (buffer->info[i].codepoint)) {
if (buffer->unicode->is_default_ignorable (buffer->info[i].codepoint)) {
buffer->info[i].codepoint = space;
buffer->pos[i].x_advance = 0;
buffer->pos[i].y_advance = 0;

View File

@ -100,6 +100,7 @@ struct hb_face_t {
unsigned int index;
mutable unsigned int upem;
mutable unsigned int num_glyphs;
struct hb_shaper_data_t shaper_data;
@ -130,8 +131,16 @@ struct hb_face_t {
return upem;
}
inline unsigned int get_num_glyphs (void) const
{
if (unlikely (num_glyphs == (unsigned int) -1))
load_num_glyphs ();
return num_glyphs;
}
private:
HB_INTERNAL void load_upem (void) const;
HB_INTERNAL void load_num_glyphs (void) const;
};
#define HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS

View File

@ -34,6 +34,7 @@
#include "hb-blob.h"
#include "hb-open-file-private.hh"
#include "hb-ot-head-table.hh"
#include "hb-ot-maxp-table.hh"
#include "hb-cache-private.hh"
@ -520,6 +521,7 @@ static const hb_face_t _hb_face_nil = {
0, /* index */
1000, /* upem */
0, /* num_glyphs */
{
#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INVALID,
@ -549,6 +551,7 @@ hb_face_create_for_tables (hb_reference_table_func_t reference_table_func,
face->destroy = destroy;
face->upem = 0;
face->num_glyphs = (unsigned int) -1;
return face;
}
@ -736,7 +739,6 @@ hb_face_get_upem (hb_face_t *face)
return face->get_upem ();
}
void
hb_face_t::load_upem (void) const
{
@ -746,6 +748,31 @@ hb_face_t::load_upem (void) const
hb_blob_destroy (head_blob);
}
void
hb_face_set_glyph_count (hb_face_t *face,
unsigned int glyph_count)
{
if (hb_object_is_inert (face))
return;
face->num_glyphs = glyph_count;
}
unsigned int
hb_face_get_glyph_count (hb_face_t *face)
{
return face->get_num_glyphs ();
}
void
hb_face_t::load_num_glyphs (void) const
{
hb_blob_t *maxp_blob = OT::Sanitizer<OT::maxp>::sanitize (reference_table (HB_OT_TAG_maxp));
const OT::maxp *maxp_table = OT::Sanitizer<OT::maxp>::lock_instance (maxp_blob);
num_glyphs = maxp_table->get_num_glyphs ();
hb_blob_destroy (maxp_blob);
}
/*
* hb_font_t

View File

@ -105,6 +105,13 @@ hb_face_set_upem (hb_face_t *face,
unsigned int
hb_face_get_upem (hb_face_t *face);
void
hb_face_set_glyph_count (hb_face_t *face,
unsigned int glyph_count);
unsigned int
hb_face_get_glyph_count (hb_face_t *face);
/*
* hb_font_funcs_t

View File

@ -242,7 +242,7 @@ hb_ft_get_glyph_name (hb_font_t *font HB_UNUSED,
FT_Face ft_face = (FT_Face) font_data;
hb_bool_t ret = !FT_Get_Glyph_Name (ft_face, glyph, name, size);
if (!ret)
if (!ret || (size && !*name))
snprintf (name, size, "gid%u", glyph);
return ret;

View File

@ -30,7 +30,7 @@
#include "hb-icu-le/PortableFontInstance.h"
#include "layout/LayoutEngine.h"
#include "layout/loengine.h"
#include "unicode/unistr.h"
#include "hb-icu.h"
@ -117,13 +117,13 @@ _hb_icu_le_shape (hb_shape_plan_t *shape_plan,
le_int32 language_code = -1 /* TODO */;
le_int32 typography_flags = 3; // essential for ligatures and kerning
LEErrorCode status = LE_NO_ERROR;
LayoutEngine *le = LayoutEngine::layoutEngineFactory (font_instance,
script_code,
language_code,
typography_flags,
status);
le_engine *le = le_create ((const le_font *) font_instance,
script_code,
language_code,
typography_flags,
&status);
if (status != LE_NO_ERROR)
{ delete (le); return false; }
{ le_close (le); return false; }
retry:
@ -138,20 +138,22 @@ retry:
ALLOCATE_ARRAY (LEUnicode, chars, buffer->len);
ALLOCATE_ARRAY (unsigned int, clusters, buffer->len);
/* XXX Use UTF-16 decoder! */
for (unsigned int i = 0; i < buffer->len; i++) {
chars[i] = buffer->info[i].codepoint;
clusters[i] = buffer->info[i].cluster;
}
unsigned int glyph_count = le->layoutChars(chars,
unsigned int glyph_count = le_layoutChars (le,
chars,
0,
buffer->len,
buffer->len,
HB_DIRECTION_IS_BACKWARD (buffer->props.direction),
0., 0.,
status);
&status);
if (status != LE_NO_ERROR)
{ delete (le); return false; }
{ le_close (le); return false; }
unsigned int num_glyphs = scratch_size / (sizeof (LEGlyphID) +
sizeof (le_int32) +
@ -160,7 +162,7 @@ retry:
if (unlikely (glyph_count >= num_glyphs || glyph_count > buffer->allocated)) {
buffer->ensure (buffer->allocated * 2);
if (buffer->in_error)
{ delete (le); return false; }
{ le_close (le); return false; }
goto retry;
}
@ -168,9 +170,9 @@ retry:
ALLOCATE_ARRAY (le_int32, indices, glyph_count);
ALLOCATE_ARRAY (float, positions, glyph_count * 2 + 2);
le->getGlyphs(glyphs, status);
le->getCharIndices(indices, status);
le->getGlyphPositions(positions, status);
le_getGlyphs (le, glyphs, &status);
le_getCharIndices (le, indices, &status);
le_getGlyphPositions (le, positions, &status);
#undef ALLOCATE_ARRAY
@ -187,7 +189,7 @@ retry:
info[j].codepoint = glyphs[i];
info[j].cluster = clusters[indices[i]];
/* icu-le doesn't seem to have separapte advance values. */
/* icu-le doesn't seem to have separate advance values. */
info[j].mask = positions[2 * i + 2] - positions[2 * i];
info[j].var1.u32 = 0;
info[j].var2.u32 = -positions[2 * i + 1];
@ -208,6 +210,6 @@ retry:
pos->y_offset = info->var2.u32;
}
delete (le);
le_close (le);
return true;
}

View File

@ -138,13 +138,13 @@ static const void *_NullPool[64 / sizeof (void *)];
/* Generic nul-content Null objects. */
template <typename Type>
static inline const Type& Null (void) {
ASSERT_STATIC (Type::min_size <= sizeof (_NullPool));
ASSERT_STATIC (sizeof (Type) <= sizeof (_NullPool));
return *CastP<Type> (_NullPool);
}
/* Specializaiton for arbitrary-content arbitrary-sized Null objects. */
#define DEFINE_NULL_DATA(Type, data) \
static const char _Null##Type[Type::min_size + 1] = data; /* +1 is for nul-termination in data */ \
static const char _Null##Type[sizeof (Type) + 1] = data; /* +1 is for nul-termination in data */ \
template <> \
inline const Type& Null<Type> (void) { \
return *CastP<Type> (_Null##Type); \

View File

@ -47,7 +47,7 @@ struct head
inline unsigned int get_upem (void) const {
unsigned int upem = unitsPerEm;
/* If no valid head table found, assume 1000, which matches typicaly Type1 usage. */
/* If no valid head table found, assume 1000, which matches typical Type1 usage. */
return 16 <= upem && upem <= 16384 ? upem : 1000;
}

View File

@ -403,6 +403,8 @@ struct CoverageFormat1
glyphs->add (glyphArray[i]);
}
public:
/* Older compilers need this to be public. */
struct Iter {
inline void init (const struct CoverageFormat1 &c_) { c = &c_; i = 0; };
inline bool more (void) { return i < c->glyphArray.len; }
@ -414,6 +416,7 @@ struct CoverageFormat1
const struct CoverageFormat1 *c;
unsigned int i;
};
private:
protected:
USHORT coverageFormat; /* Format identifier--format = 1 */
@ -497,6 +500,8 @@ struct CoverageFormat2
rangeRecord[i].add_coverage (glyphs);
}
public:
/* Older compilers need this to be public. */
struct Iter {
inline void init (const CoverageFormat2 &c_) {
c = &c_;
@ -522,6 +527,7 @@ struct CoverageFormat2
const struct CoverageFormat2 *c;
unsigned int i, j, coverage;
};
private:
protected:
USHORT coverageFormat; /* Format identifier--format = 2 */

View File

@ -1343,6 +1343,7 @@ struct SubstLookup : Lookup
else
{
/* in-place backward substitution */
c->buffer->remove_output ();
c->buffer->idx = c->buffer->len - 1;
do
{

View File

@ -459,7 +459,7 @@ static inline bool match_input (hb_apply_context_t *c,
if (!skippy_iter.next (&property)) return TRACE_RETURN (false);
if (likely (!match_func (c->buffer->info[skippy_iter.idx].codepoint, input[i - 1], match_data))) return false;
if (likely (!match_func (c->buffer->info[skippy_iter.idx].codepoint, input[i - 1], match_data))) return TRACE_RETURN (false);
unsigned int this_lig_id = get_lig_id (c->buffer->info[skippy_iter.idx]);
unsigned int this_lig_comp = get_lig_comp (c->buffer->info[skippy_iter.idx]);
@ -491,7 +491,7 @@ static inline bool match_input (hb_apply_context_t *c,
if (p_total_component_count)
*p_total_component_count = total_component_count;
return true;
return TRACE_RETURN (true);
}
static inline void ligate_input (hb_apply_context_t *c,
unsigned int count, /* Including the first glyph (not matched) */
@ -655,9 +655,10 @@ static inline bool apply_lookup (hb_apply_context_t *c,
const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */
apply_lookup_func_t apply_func)
{
hb_auto_trace_t<HB_DEBUG_APPLY> trace (&c->debug_depth, "APPLY", NULL, HB_FUNC, "idx %d codepoint %u", c->buffer->idx, c->buffer->cur().codepoint);
unsigned int end = c->buffer->len;
if (unlikely (count == 0 || c->buffer->idx + count > end))
return false;
return TRACE_RETURN (false);
/* TODO We don't support lookupRecord arrays that are not increasing:
* Should be easy for in_place ones at least. */
@ -669,13 +670,13 @@ static inline bool apply_lookup (hb_apply_context_t *c,
for (unsigned int i = 0; i < count; /* NOP */)
{
if (unlikely (c->buffer->idx == end))
return true;
return TRACE_RETURN (true);
while (c->should_mark_skip_current_glyph ())
{
/* No lookup applied for this index */
c->buffer->next_glyph ();
if (unlikely (c->buffer->idx == end))
return true;
return TRACE_RETURN (true);
}
if (lookupCount && i == lookupRecord->sequenceIndex)
@ -690,7 +691,7 @@ static inline bool apply_lookup (hb_apply_context_t *c,
/* Err, this is wrong if the lookup jumped over some glyphs */
i += c->buffer->idx - old_pos;
if (unlikely (c->buffer->idx == end))
return true;
return TRACE_RETURN (true);
if (!done)
goto not_applied;
@ -704,7 +705,7 @@ static inline bool apply_lookup (hb_apply_context_t *c,
}
}
return true;
return TRACE_RETURN (true);
}

View File

@ -49,14 +49,6 @@
* GDEF
*/
typedef enum {
HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED = 0x0001,
HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH = 0x0002,
HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE = 0x0004,
HB_OT_LAYOUT_GLYPH_CLASS_MARK = 0x0008,
HB_OT_LAYOUT_GLYPH_CLASS_COMPONENT = 0x0010
} hb_ot_layout_glyph_class_t;
/*
@ -138,7 +130,7 @@ static inline uint8_t allocate_lig_id (hb_buffer_t *buffer) {
HB_INTERNAL hb_bool_t
hb_ot_layout_would_substitute_lookup_fast (hb_face_t *face,
hb_ot_layout_lookup_would_substitute_fast (hb_face_t *face,
unsigned int lookup_index,
const hb_codepoint_t *glyphs,
unsigned int glyphs_length,

View File

@ -374,12 +374,12 @@ hb_ot_layout_language_find_feature (hb_face_t *face,
}
unsigned int
hb_ot_layout_feature_get_lookup_indexes (hb_face_t *face,
hb_tag_t table_tag,
unsigned int feature_index,
unsigned int start_offset,
unsigned int *lookup_count /* IN/OUT */,
unsigned int *lookup_indexes /* OUT */)
hb_ot_layout_feature_get_lookups (hb_face_t *face,
hb_tag_t table_tag,
unsigned int feature_index,
unsigned int start_offset,
unsigned int *lookup_count /* IN/OUT */,
unsigned int *lookup_indexes /* OUT */)
{
const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
const OT::Feature &f = g.get_feature (feature_index);
@ -399,18 +399,18 @@ hb_ot_layout_has_substitution (hb_face_t *face)
}
hb_bool_t
hb_ot_layout_would_substitute_lookup (hb_face_t *face,
hb_ot_layout_lookup_would_substitute (hb_face_t *face,
unsigned int lookup_index,
const hb_codepoint_t *glyphs,
unsigned int glyphs_length,
hb_bool_t zero_context)
{
if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return false;
return hb_ot_layout_would_substitute_lookup_fast (face, lookup_index, glyphs, glyphs_length, zero_context);
return hb_ot_layout_lookup_would_substitute_fast (face, lookup_index, glyphs, glyphs_length, zero_context);
}
hb_bool_t
hb_ot_layout_would_substitute_lookup_fast (hb_face_t *face,
hb_ot_layout_lookup_would_substitute_fast (hb_face_t *face,
unsigned int lookup_index,
const hb_codepoint_t *glyphs,
unsigned int glyphs_length,
@ -452,7 +452,7 @@ hb_ot_layout_substitute_finish (hb_font_t *font, hb_buffer_t *buffer)
}
void
hb_ot_layout_substitute_closure_lookup (hb_face_t *face,
hb_ot_layout_lookup_substitute_closure (hb_face_t *face,
unsigned int lookup_index,
hb_set_t *glyphs)
{

View File

@ -50,6 +50,27 @@ HB_BEGIN_DECLS
hb_bool_t
hb_ot_layout_has_glyph_classes (hb_face_t *face);
typedef enum {
HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED = 0x0001,
HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH = 0x0002,
HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE = 0x0004,
HB_OT_LAYOUT_GLYPH_CLASS_MARK = 0x0008,
HB_OT_LAYOUT_GLYPH_CLASS_COMPONENT = 0x0010
} hb_ot_layout_glyph_class_t;
#ifdef HB_NOT_IMPLEMENTED
hb_ot_layout_glyph_class_t
Xhb_ot_layout_get_glyph_class (hb_face_t *face,
hb_codepoint_t glyph);
#endif
#ifdef HB_NOT_IMPLEMENTED
Xhb_ot_layout_get_glyphs_in_class (hb_face_t *face,
hb_ot_layout_glyph_class_t klass,
hb_set_t *glyphs /* OUT */);
#endif
/* Not that useful. Provides list of attach points for a glyph that a
* client may want to cache */
unsigned int
@ -154,12 +175,64 @@ hb_ot_layout_language_find_feature (hb_face_t *face,
unsigned int *feature_index);
unsigned int
hb_ot_layout_feature_get_lookup_indexes (hb_face_t *face,
hb_ot_layout_feature_get_lookups (hb_face_t *face,
hb_tag_t table_tag,
unsigned int feature_index,
unsigned int start_offset,
unsigned int *lookup_count /* IN/OUT */,
unsigned int *lookup_indexes /* OUT */);
#ifdef HB_NOT_IMPLEMENTED
void
Xhb_ot_layout_collect_lookups (hb_face_t *face,
hb_tag_t table_tag,
const hb_tag_t *scripts,
const hb_tag_t *languages,
const hb_tag_t *features,
hb_set_t *lookup_indexes /* OUT */);
#endif
void
hb_ot_shape_plan_collect_lookups (hb_shape_plan_t *shape_plan,
hb_tag_t table_tag,
hb_set_t *lookup_indexes /* OUT */);
#ifdef HB_NOT_IMPLEMENTED
void
Xhb_ot_layout_lookup_collect_glyphs (hb_face_t *face,
hb_tag_t table_tag,
unsigned int lookup_index,
hb_set_t *glyphs_before, /* OUT. May be NULL */
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 */);
#endif
#ifdef HB_NOT_IMPLEMENTED
typedef struct
{
const hb_codepoint_t *before,
unsigned int before_length,
const hb_codepoint_t *input,
unsigned int input_length,
const hb_codepoint_t *after,
unsigned int after_length,
} hb_ot_layout_glyph_sequence_t;
typedef hb_bool_t
(*hb_ot_layout_glyph_sequence_func_t) (hb_font_t *font,
hb_tag_t table_tag,
unsigned int lookup_index,
const hb_ot_layout_glyph_sequence_t *sequence,
void *user_data);
void
Xhb_ot_layout_lookup_enumerate_sequences (hb_face_t *face,
hb_tag_t table_tag,
unsigned int feature_index,
unsigned int start_offset,
unsigned int *lookup_count /* IN/OUT */,
unsigned int *lookup_indexes /* OUT */);
unsigned int lookup_index,
hb_ot_layout_glyph_sequence_func_t callback,
void *user_data);
#endif
/*
@ -170,16 +243,30 @@ hb_bool_t
hb_ot_layout_has_substitution (hb_face_t *face);
hb_bool_t
hb_ot_layout_would_substitute_lookup (hb_face_t *face,
hb_ot_layout_lookup_would_substitute (hb_face_t *face,
unsigned int lookup_index,
const hb_codepoint_t *glyphs,
unsigned int glyphs_length,
hb_bool_t zero_context);
void
hb_ot_layout_substitute_closure_lookup (hb_face_t *face,
hb_ot_layout_lookup_substitute_closure (hb_face_t *face,
unsigned int lookup_index,
hb_set_t *glyphs);
hb_set_t *glyphs
/*TODO , hb_bool_t inclusive */);
#ifdef HB_NOT_IMPLEMENTED
/* Note: You better have GDEF when using this API, or marks won't do much. */
hb_bool_t
Xhb_ot_layout_lookup_substitute (hb_font_t *font,
unsigned int lookup_index,
const hb_ot_layout_glyph_sequence_t *sequence,
unsigned int out_size,
hb_codepoint_t *glyphs_out, /* OUT */
unsigned int *clusters_out, /* OUT */
unsigned int *out_length /* OUT */);
#endif
/*
* GPOS
@ -188,6 +275,15 @@ hb_ot_layout_substitute_closure_lookup (hb_face_t *face,
hb_bool_t
hb_ot_layout_has_positioning (hb_face_t *face);
#ifdef HB_NOT_IMPLEMENTED
/* Note: You better have GDEF when using this API, or marks won't do much. */
hb_bool_t
Xhb_ot_layout_lookup_position (hb_font_t *font,
unsigned int lookup_index,
const hb_ot_layout_glyph_sequence_t *sequence,
hb_glyph_position_t *positions /* IN / OUT */);
#endif
HB_END_DECLS

View File

@ -115,10 +115,7 @@ struct hb_ot_map_t
*lookup_count = end - start;
}
inline hb_tag_t get_chosen_script (unsigned int table_index) const
{ return chosen_script[table_index]; }
HB_INTERNAL void substitute_closure (const struct hb_ot_shape_plan_t *plan, hb_face_t *face, hb_set_t *glyphs) const;
HB_INTERNAL void collect_lookups (unsigned int table_index, hb_set_t *lookups) const;
HB_INTERNAL void substitute (const struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const;
HB_INTERNAL void position (const struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const;
@ -130,6 +127,9 @@ struct hb_ot_map_t
pauses[1].finish ();
}
public:
hb_tag_t chosen_script[2];
bool found_script[2];
private:
@ -140,7 +140,6 @@ struct hb_ot_map_t
hb_mask_t global_mask;
hb_tag_t chosen_script[2];
hb_prealloced_array_t<feature_map_t, 8> features;
hb_prealloced_array_t<lookup_map_t, 32> lookups[2]; /* GSUB/GPOS */
hb_prealloced_array_t<pause_map_t, 1> pauses[2]; /* GSUB/GPOS */
@ -151,7 +150,8 @@ struct hb_ot_map_builder_t
{
public:
hb_ot_map_builder_t (void) { memset (this, 0, sizeof (*this)); }
HB_INTERNAL hb_ot_map_builder_t (hb_face_t *face_,
const hb_segment_properties_t *props_);
HB_INTERNAL void add_feature (hb_tag_t tag, unsigned int value, bool global, bool has_fallback = false);
@ -163,9 +163,7 @@ struct hb_ot_map_builder_t
inline void add_gpos_pause (hb_ot_map_t::pause_func_t pause_func)
{ add_pause (1, pause_func); }
HB_INTERNAL void compile (hb_face_t *face,
const hb_segment_properties_t *props,
struct hb_ot_map_t &m);
HB_INTERNAL void compile (struct hb_ot_map_t &m);
inline void finish (void) {
feature_infos.finish ();
@ -195,6 +193,17 @@ struct hb_ot_map_builder_t
HB_INTERNAL void add_pause (unsigned int table_index, hb_ot_map_t::pause_func_t pause_func);
public:
hb_face_t *face;
hb_segment_properties_t props;
hb_tag_t chosen_script[2];
bool found_script[2];
unsigned int script_index[2], language_index[2];
private:
unsigned int current_stage[2]; /* GSUB/GPOS */
hb_prealloced_array_t<feature_info_t,16> feature_infos;
hb_prealloced_array_t<pause_info_t, 1> pauses[2]; /* GSUB/GPOS */

View File

@ -41,11 +41,11 @@ hb_ot_map_t::add_lookups (hb_face_t *face,
offset = 0;
do {
len = ARRAY_LENGTH (lookup_indices);
hb_ot_layout_feature_get_lookup_indexes (face,
table_tags[table_index],
feature_index,
offset, &len,
lookup_indices);
hb_ot_layout_feature_get_lookups (face,
table_tags[table_index],
feature_index,
offset, &len,
lookup_indices);
for (unsigned int i = 0; i < len; i++) {
hb_ot_map_t::lookup_map_t *lookup = lookups[table_index].push ();
@ -59,6 +59,30 @@ hb_ot_map_t::add_lookups (hb_face_t *face,
} while (len == ARRAY_LENGTH (lookup_indices));
}
hb_ot_map_builder_t::hb_ot_map_builder_t (hb_face_t *face_,
const hb_segment_properties_t *props_)
{
memset (this, 0, sizeof (*this));
face = face_;
props = *props_;
/* Fetch script/language indices for GSUB/GPOS. We need these later to skip
* features not available in either table and not waste precious bits for them. */
hb_tag_t script_tags[3] = {HB_TAG_NONE, HB_TAG_NONE, HB_TAG_NONE};
hb_tag_t language_tag;
hb_ot_tags_from_script (props.script, &script_tags[0], &script_tags[1]);
language_tag = hb_ot_tag_from_language (props.language);
for (unsigned int table_index = 0; table_index < 2; table_index++) {
hb_tag_t table_tag = table_tags[table_index];
found_script[table_index] = hb_ot_layout_table_choose_script (face, table_tag, script_tags, &script_index[table_index], &chosen_script[table_index]);
hb_ot_layout_script_find_language (face, table_tag, script_index[table_index], language_tag, &language_index[table_index]);
}
}
void hb_ot_map_builder_t::add_feature (hb_tag_t tag, unsigned int value, bool global, bool has_fallback)
{
@ -114,11 +138,10 @@ void hb_ot_map_t::position (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_
hb_ot_layout_position_lookup (font, buffer, lookups[table_index][i].index, lookups[table_index][i].mask);
}
void hb_ot_map_t::substitute_closure (const hb_ot_shape_plan_t *plan, hb_face_t *face, hb_set_t *glyphs) const
void hb_ot_map_t::collect_lookups (unsigned int table_index, hb_set_t *lookups_out) const
{
unsigned int table_index = 0;
for (unsigned int i = 0; i < lookups[table_index].len; i++)
hb_ot_layout_substitute_closure_lookup (face, lookups[table_index][i].index, glyphs);
hb_set_add (lookups_out, lookups[table_index][i].index);
}
void hb_ot_map_builder_t::add_pause (unsigned int table_index, hb_ot_map_t::pause_func_t pause_func)
@ -133,33 +156,18 @@ void hb_ot_map_builder_t::add_pause (unsigned int table_index, hb_ot_map_t::paus
}
void
hb_ot_map_builder_t::compile (hb_face_t *face,
const hb_segment_properties_t *props,
hb_ot_map_t &m)
hb_ot_map_builder_t::compile (hb_ot_map_t &m)
{
m.global_mask = 1;
m.global_mask = 1;
for (unsigned int table_index = 0; table_index < 2; table_index++) {
m.chosen_script[table_index] = chosen_script[table_index];
m.found_script[table_index] = found_script[table_index];
}
if (!feature_infos.len)
return;
/* Fetch script/language indices for GSUB/GPOS. We need these later to skip
* features not available in either table and not waste precious bits for them. */
hb_tag_t script_tags[3] = {HB_TAG_NONE};
hb_tag_t language_tag;
hb_ot_tags_from_script (props->script, &script_tags[0], &script_tags[1]);
language_tag = hb_ot_tag_from_language (props->language);
unsigned int script_index[2], language_index[2];
for (unsigned int table_index = 0; table_index < 2; table_index++) {
hb_tag_t table_tag = table_tags[table_index];
hb_ot_layout_table_choose_script (face, table_tag, script_tags, &script_index[table_index], &m.chosen_script[table_index]);
hb_ot_layout_script_find_language (face, table_tag, script_index[table_index], language_tag, &language_index[table_index]);
}
/* Sort features and merge duplicates */
{
feature_infos.sort ();

View File

@ -64,15 +64,31 @@ static unsigned int get_joining_type (hb_codepoint_t u, hb_unicode_general_categ
return j_type;
}
/* Mongolian joining data is not in ArabicJoining.txt yet */
/* Mongolian joining data is not in ArabicJoining.txt yet. */
if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x1800, 0x18AF)))
{
if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x1880, 0x1886)))
return JOINING_TYPE_U;
/* All letters, SIBE SYLLABLE BOUNDARY MARKER, and NIRUGU are D */
if (gen_cat == HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER || u == 0x1807 || u == 0x180A)
if ((FLAG(gen_cat) & (FLAG (HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER) |
FLAG (HB_UNICODE_GENERAL_CATEGORY_MODIFIER_LETTER)))
|| u == 0x1807 || u == 0x180A)
return JOINING_TYPE_D;
}
if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x200C, 0x200D))) {
/* 'Phags-pa joining data is not in ArabicJoining.txt yet. */
if (unlikely (hb_in_range<hb_codepoint_t> (u, 0xA840, 0xA872)))
{
if (unlikely (u == 0xA872))
/* XXX Looks like this should be TYPE_L, but we don't support that yet! */
return JOINING_TYPE_R;
return JOINING_TYPE_D;
}
if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x200C, 0x200D)))
{
return u == 0x200C ? JOINING_TYPE_U : JOINING_TYPE_C;
}
@ -178,8 +194,9 @@ collect_features_arabic (hb_ot_shape_planner_t *plan)
map->add_bool_feature (HB_TAG('c','a','l','t'));
map->add_gsub_pause (NULL);
/* ArabicOT spec enables 'cswh' for Arabic where as for basic shaper it's disabled by default. */
map->add_bool_feature (HB_TAG('c','s','w','h'));
map->add_bool_feature (HB_TAG('d','l','i','g'));
map->add_bool_feature (HB_TAG('m','s','e','t'));
}
#include "hb-ot-shape-complex-arabic-fallback.hh"
@ -234,17 +251,18 @@ arabic_joining (hb_buffer_t *buffer)
HB_BUFFER_ALLOCATE_VAR (buffer, arabic_shaping_action);
/* Check pre-context */
for (unsigned int i = 0; i < buffer->context_len[0]; i++)
{
unsigned int this_type = get_joining_type (buffer->context[0][i], buffer->unicode->general_category (buffer->context[0][i]));
if (!(buffer->flags & HB_BUFFER_FLAG_BOT))
for (unsigned int i = 0; i < buffer->context_len[0]; i++)
{
unsigned int this_type = get_joining_type (buffer->context[0][i], buffer->unicode->general_category (buffer->context[0][i]));
if (unlikely (this_type == JOINING_TYPE_T))
continue;
if (unlikely (this_type == JOINING_TYPE_T))
continue;
const arabic_state_table_entry *entry = &arabic_state_table[state][this_type];
state = entry->next_state;
break;
}
const arabic_state_table_entry *entry = &arabic_state_table[state][this_type];
state = entry->next_state;
break;
}
for (unsigned int i = 0; i < count; i++)
{
@ -266,18 +284,19 @@ arabic_joining (hb_buffer_t *buffer)
state = entry->next_state;
}
for (unsigned int i = 0; i < buffer->context_len[1]; i++)
{
unsigned int this_type = get_joining_type (buffer->context[1][i], buffer->unicode->general_category (buffer->context[0][i]));
if (!(buffer->flags & HB_BUFFER_FLAG_EOT))
for (unsigned int i = 0; i < buffer->context_len[1]; i++)
{
unsigned int this_type = get_joining_type (buffer->context[1][i], buffer->unicode->general_category (buffer->context[1][i]));
if (unlikely (this_type == JOINING_TYPE_T))
continue;
if (unlikely (this_type == JOINING_TYPE_T))
continue;
const arabic_state_table_entry *entry = &arabic_state_table[state][this_type];
if (entry->prev_action != NONE && prev != (unsigned int) -1)
buffer->info[prev].arabic_shaping_action() = entry->prev_action;
break;
}
const arabic_state_table_entry *entry = &arabic_state_table[state][this_type];
if (entry->prev_action != NONE && prev != (unsigned int) -1)
buffer->info[prev].arabic_shaping_action() = entry->prev_action;
break;
}
HB_BUFFER_DEALLOCATE_VAR (buffer, arabic_shaping_action);
@ -332,6 +351,9 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_arabic =
data_destroy_arabic,
NULL, /* preprocess_text_arabic */
NULL, /* normalization_preference */
NULL, /* decompose */
NULL, /* compose */
setup_masks_arabic,
true, /* zero_width_attached_marks */
true, /* fallback_position */
};

View File

@ -0,0 +1,225 @@
/*
* Copyright © 2010,2012 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod
*/
#include "hb-ot-shape-complex-private.hh"
/* TODO Add kana, and other small shapers here */
/* The default shaper *only* adds additional per-script features.*/
static const hb_tag_t hangul_features[] =
{
HB_TAG('l','j','m','o'),
HB_TAG('v','j','m','o'),
HB_TAG('t','j','m','o'),
HB_TAG_NONE
};
static const hb_tag_t tibetan_features[] =
{
HB_TAG('a','b','v','s'),
HB_TAG('b','l','w','s'),
HB_TAG('a','b','v','m'),
HB_TAG('b','l','w','m'),
HB_TAG_NONE
};
static void
collect_features_default (hb_ot_shape_planner_t *plan)
{
const hb_tag_t *script_features = NULL;
switch ((hb_tag_t) plan->props.script)
{
/* Unicode-1.1 additions */
case HB_SCRIPT_HANGUL:
script_features = hangul_features;
break;
/* Unicode-2.0 additions */
case HB_SCRIPT_TIBETAN:
script_features = tibetan_features;
break;
}
for (; script_features && *script_features; script_features++)
plan->map.add_bool_feature (*script_features);
}
static hb_ot_shape_normalization_mode_t
normalization_preference_default (const hb_segment_properties_t *props)
{
switch ((hb_tag_t) props->script)
{
/* Unicode-1.1 additions */
case HB_SCRIPT_HANGUL:
return HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_FULL;
}
return HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS;
}
static bool
compose_default (const hb_ot_shape_normalize_context_t *c,
hb_codepoint_t a,
hb_codepoint_t b,
hb_codepoint_t *ab)
{
/* Hebrew presentation-form shaping.
* https://bugzilla.mozilla.org/show_bug.cgi?id=728866 */
// Hebrew presentation forms with dagesh, for characters 0x05D0..0x05EA;
// note that some letters do not have a dagesh presForm encoded
static const hb_codepoint_t sDageshForms[0x05EA - 0x05D0 + 1] = {
0xFB30, // ALEF
0xFB31, // BET
0xFB32, // GIMEL
0xFB33, // DALET
0xFB34, // HE
0xFB35, // VAV
0xFB36, // ZAYIN
0, // HET
0xFB38, // TET
0xFB39, // YOD
0xFB3A, // FINAL KAF
0xFB3B, // KAF
0xFB3C, // LAMED
0, // FINAL MEM
0xFB3E, // MEM
0, // FINAL NUN
0xFB40, // NUN
0xFB41, // SAMEKH
0, // AYIN
0xFB43, // FINAL PE
0xFB44, // PE
0, // FINAL TSADI
0xFB46, // TSADI
0xFB47, // QOF
0xFB48, // RESH
0xFB49, // SHIN
0xFB4A // TAV
};
bool found = c->unicode->compose (a, b, ab);
if (!found && (b & ~0x7F) == 0x0580) {
// special-case Hebrew presentation forms that are excluded from
// standard normalization, but wanted for old fonts
switch (b) {
case 0x05B4: // HIRIQ
if (a == 0x05D9) { // YOD
*ab = 0xFB1D;
found = true;
}
break;
case 0x05B7: // patah
if (a == 0x05F2) { // YIDDISH YOD YOD
*ab = 0xFB1F;
found = true;
} else if (a == 0x05D0) { // ALEF
*ab = 0xFB2E;
found = true;
}
break;
case 0x05B8: // QAMATS
if (a == 0x05D0) { // ALEF
*ab = 0xFB2F;
found = true;
}
break;
case 0x05B9: // HOLAM
if (a == 0x05D5) { // VAV
*ab = 0xFB4B;
found = true;
}
break;
case 0x05BC: // DAGESH
if (a >= 0x05D0 && a <= 0x05EA) {
*ab = sDageshForms[a - 0x05D0];
found = (*ab != 0);
} else if (a == 0xFB2A) { // SHIN WITH SHIN DOT
*ab = 0xFB2C;
found = true;
} else if (a == 0xFB2B) { // SHIN WITH SIN DOT
*ab = 0xFB2D;
found = true;
}
break;
case 0x05BF: // RAFE
switch (a) {
case 0x05D1: // BET
*ab = 0xFB4C;
found = true;
break;
case 0x05DB: // KAF
*ab = 0xFB4D;
found = true;
break;
case 0x05E4: // PE
*ab = 0xFB4E;
found = true;
break;
}
break;
case 0x05C1: // SHIN DOT
if (a == 0x05E9) { // SHIN
*ab = 0xFB2A;
found = true;
} else if (a == 0xFB49) { // SHIN WITH DAGESH
*ab = 0xFB2C;
found = true;
}
break;
case 0x05C2: // SIN DOT
if (a == 0x05E9) { // SHIN
*ab = 0xFB2B;
found = true;
} else if (a == 0xFB49) { // SHIN WITH DAGESH
*ab = 0xFB2D;
found = true;
}
break;
}
}
return found;
}
const hb_ot_complex_shaper_t _hb_ot_complex_shaper_default =
{
"default",
collect_features_default,
NULL, /* override_features */
NULL, /* data_create */
NULL, /* data_destroy */
NULL, /* preprocess_text */
normalization_preference_default,
NULL, /* decompose */
compose_default,
NULL, /* setup_masks */
true, /* zero_width_attached_marks */
true, /* fallback_position */
};

File diff suppressed because it is too large Load Diff

View File

@ -55,8 +55,9 @@ RS = 13;
Coeng = 14;
Repha = 15;
Ra = 16;
CM = 17;
c = (C | Ra); # is_consonant
c = (C | Ra)CM*; # is_consonant
n = ((ZWNJ?.RS)? (N.N?)?); # is_consonant_modifier
z = ZWJ|ZWNJ; # is_joiner
h = H | Coeng; # is_halant_or_coeng

View File

@ -39,7 +39,7 @@
#define indic_position() complex_var_u8_1() /* indic_matra_category_t */
#define INDIC_TABLE_ELEMENT_TYPE uint8_t
#define INDIC_TABLE_ELEMENT_TYPE uint16_t
/* Cateories used in the OpenType spec:
* https://www.microsoft.com/typography/otfntdev/devanot/shaping.aspx
@ -63,7 +63,8 @@ enum indic_category_t {
OT_RS, /* Register Shifter, used in Khmer OT spec */
OT_Coeng,
OT_Repha,
OT_Ra /* Not explicitly listed in the OT spec, but used in the grammar. */
OT_Ra, /* Not explicitly listed in the OT spec, but used in the grammar. */
OT_CM
};
/* Visual positions in a syllable from left to right. */
@ -103,7 +104,7 @@ enum indic_syllabic_category_t {
INDIC_SYLLABIC_CATEGORY_CONSONANT_DEAD = OT_C,
INDIC_SYLLABIC_CATEGORY_CONSONANT_FINAL = OT_C,
INDIC_SYLLABIC_CATEGORY_CONSONANT_HEAD_LETTER = OT_C,
INDIC_SYLLABIC_CATEGORY_CONSONANT_MEDIAL = OT_C,
INDIC_SYLLABIC_CATEGORY_CONSONANT_MEDIAL = OT_CM,
INDIC_SYLLABIC_CATEGORY_CONSONANT_PLACEHOLDER = OT_NBSP,
INDIC_SYLLABIC_CATEGORY_CONSONANT_SUBJOINED = OT_C,
INDIC_SYLLABIC_CATEGORY_CONSONANT_REPHA = OT_Repha,
@ -111,7 +112,7 @@ enum indic_syllabic_category_t {
INDIC_SYLLABIC_CATEGORY_NUKTA = OT_N,
INDIC_SYLLABIC_CATEGORY_REGISTER_SHIFTER = OT_RS,
INDIC_SYLLABIC_CATEGORY_TONE_LETTER = OT_X,
INDIC_SYLLABIC_CATEGORY_TONE_MARK = OT_X,
INDIC_SYLLABIC_CATEGORY_TONE_MARK = OT_N,
INDIC_SYLLABIC_CATEGORY_VIRAMA = OT_H,
INDIC_SYLLABIC_CATEGORY_VISARGA = OT_SM,
INDIC_SYLLABIC_CATEGORY_VOWEL = OT_V,
@ -138,16 +139,16 @@ enum indic_matra_category_t {
INDIC_MATRA_CATEGORY_TOP_AND_RIGHT = INDIC_MATRA_CATEGORY_RIGHT,
INDIC_MATRA_CATEGORY_INVISIBLE = INDIC_MATRA_CATEGORY_NOT_APPLICABLE,
INDIC_MATRA_CATEGORY_OVERSTRUCK = INDIC_MATRA_CATEGORY_NOT_APPLICABLE,
INDIC_MATRA_CATEGORY_VISUAL_ORDER_LEFT = INDIC_MATRA_CATEGORY_NOT_APPLICABLE
INDIC_MATRA_CATEGORY_OVERSTRUCK = POS_AFTER_MAIN,
INDIC_MATRA_CATEGORY_VISUAL_ORDER_LEFT = POS_PRE_M
};
/* Note: We use ASSERT_STATIC_EXPR_ZERO() instead of ASSERT_STATIC_EXPR() and the comma operation
* because gcc fails to optimize the latter and fills the table in at runtime. */
#define INDIC_COMBINE_CATEGORIES(S,M) \
(ASSERT_STATIC_EXPR_ZERO (M == INDIC_MATRA_CATEGORY_NOT_APPLICABLE || (S == INDIC_SYLLABIC_CATEGORY_VIRAMA || S == INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT)) + \
ASSERT_STATIC_EXPR_ZERO (S < 16 && M < 16) + \
((M << 4) | S))
ASSERT_STATIC_EXPR_ZERO (S < 255 && M < 255) + \
((M << 8) | S))
#include "hb-ot-shape-complex-indic-table.hh"
@ -221,7 +222,7 @@ matra_position (hb_codepoint_t u, indic_position_t side)
case POS_ABOVE_C: return MATRA_POS_TOP (u);
case POS_BELOW_C: return MATRA_POS_BOTTOM (u);
};
abort ();
return side;
}
@ -285,7 +286,7 @@ is_joiner (const hb_glyph_info_t &info)
* We treat Vowels and placeholders as if they were consonants. This is safe because Vowels
* cannot happen in a consonant syllable. The plus side however is, we can call the
* consonant syllable logic from the vowel syllable function and get it all right! */
#define CONSONANT_FLAGS (FLAG (OT_C) | FLAG (OT_Ra) | FLAG (OT_V) | FLAG (OT_NBSP) | FLAG (OT_DOTTEDCIRCLE))
#define CONSONANT_FLAGS (FLAG (OT_C) | FLAG (OT_CM) | FLAG (OT_Ra) | FLAG (OT_V) | FLAG (OT_NBSP) | FLAG (OT_DOTTEDCIRCLE))
static inline bool
is_consonant (const hb_glyph_info_t &info)
{
@ -304,8 +305,8 @@ set_indic_properties (hb_glyph_info_t &info)
{
hb_codepoint_t u = info.codepoint;
unsigned int type = get_indic_categories (u);
indic_category_t cat = (indic_category_t) (type & 0x0F);
indic_position_t pos = (indic_position_t) (type >> 4);
indic_category_t cat = (indic_category_t) (type & 0x7F);
indic_position_t pos = (indic_position_t) (type >> 8);
/*

View File

@ -123,6 +123,8 @@ static const indic_config_t indic_configs[] =
{HB_SCRIPT_MALAYALAM, true, 0x0D4D,BASE_POS_LAST, REPH_POS_AFTER_MAIN, REPH_MODE_LOG_REPHA},
{HB_SCRIPT_SINHALA, false,0x0DCA,BASE_POS_FIRST,REPH_POS_AFTER_MAIN, REPH_MODE_EXPLICIT},
{HB_SCRIPT_KHMER, false,0x17D2,BASE_POS_FIRST,REPH_POS_DEFAULT, REPH_MODE_VIS_REPHA},
/* Myanmar does not have the "old_indic" behavior, even though it has a "new" tag. */
{HB_SCRIPT_MYANMAR, false, 0x1039,BASE_POS_LAST, REPH_POS_DEFAULT, REPH_MODE_EXPLICIT},
};
@ -247,6 +249,8 @@ override_features_indic (hb_ot_shape_planner_t *plan)
/* Uniscribe does not apply 'kern'. */
if (indic_options ().uniscribe_bug_compatible)
plan->map.add_feature (HB_TAG('k','e','r','n'), 0, true);
plan->map.add_feature (HB_TAG('l','i','g','a'), 0, true);
}
@ -265,7 +269,7 @@ struct would_substitute_feature_t
hb_face_t *face) const
{
for (unsigned int i = 0; i < count; i++)
if (hb_ot_layout_would_substitute_lookup_fast (face, lookups[i].index, glyphs, glyphs_count, zero_context))
if (hb_ot_layout_lookup_would_substitute_fast (face, lookups[i].index, glyphs, glyphs_count, zero_context))
return true;
return false;
}
@ -303,6 +307,7 @@ struct indic_shape_plan_t
bool is_old_spec;
hb_codepoint_t virama_glyph;
would_substitute_feature_t rphf;
would_substitute_feature_t pref;
would_substitute_feature_t blwf;
would_substitute_feature_t pstf;
@ -324,9 +329,10 @@ data_create_indic (const hb_ot_shape_plan_t *plan)
break;
}
indic_plan->is_old_spec = indic_plan->config->has_old_spec && ((plan->map.get_chosen_script (0) & 0x000000FF) != '2');
indic_plan->is_old_spec = indic_plan->config->has_old_spec && ((plan->map.chosen_script[0] & 0x000000FF) != '2');
indic_plan->virama_glyph = (hb_codepoint_t) -1;
indic_plan->rphf.init (&plan->map, HB_TAG('r','p','h','f'));
indic_plan->pref.init (&plan->map, HB_TAG('p','r','e','f'));
indic_plan->blwf.init (&plan->map, HB_TAG('b','l','w','f'));
indic_plan->pstf.init (&plan->map, HB_TAG('p','s','t','f'));
@ -428,7 +434,9 @@ update_consonant_positions (const hb_ot_shape_plan_t *plan,
* https://www.microsoft.com/typography/otfntdev/devanot/shaping.aspx */
static void
initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, hb_buffer_t *buffer,
initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
hb_face_t *face,
hb_buffer_t *buffer,
unsigned int start, unsigned int end)
{
const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data;
@ -459,22 +467,29 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, hb_buffer
unsigned int limit = start;
if (indic_plan->mask_array[RPHF] &&
start + 3 <= end &&
info[start].indic_category() == OT_Ra &&
info[start + 1].indic_category() == OT_H &&
(/* TODO Handle other Reph modes. */
(indic_plan->config->reph_mode == REPH_MODE_IMPLICIT && !is_joiner (info[start + 2])) ||
(indic_plan->config->reph_mode == REPH_MODE_EXPLICIT && info[start + 2].indic_category() == OT_ZWJ)
))
{
limit += 2;
while (limit < end && is_joiner (info[limit]))
limit++;
base = start;
has_reph = true;
/* See if it matches the 'rphf' feature. */
hb_codepoint_t glyphs[2] = {info[start].codepoint, info[start + 1].codepoint};
if (indic_plan->rphf.would_substitute (glyphs, ARRAY_LENGTH (glyphs), true, face))
{
limit += 2;
while (limit < end && is_joiner (info[limit]))
limit++;
base = start;
has_reph = true;
}
};
switch (indic_plan->config->base_pos)
{
default:
assert (false);
/* fallthrough */
case BASE_POS_LAST:
{
/* -> starting from the end of the syllable, move backwards */
@ -514,7 +529,7 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, hb_buffer
* half form.
* A ZWJ before a Halant, requests a subjoined form instead, and hence
* search continues. This is particularly important for Bengali
* sequence Ra,H,Ya that shouls form Ya-Phalaa by subjoining Ya. */
* sequence Ra,H,Ya that should form Ya-Phalaa by subjoining Ya. */
if (start < i &&
info[i].indic_category() == OT_ZWJ &&
info[i - 1].indic_category() == OT_H)
@ -548,9 +563,6 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, hb_buffer
info[i].indic_position() = POS_BELOW_C;
}
break;
default:
abort ();
}
/* -> If the syllable starts with Ra + Halant (in a script that has Reph)
@ -651,13 +663,17 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, hb_buffer
if ((FLAG (info[i].indic_category()) & (JOINER_FLAGS | FLAG (OT_N) | FLAG (OT_RS) | HALANT_OR_COENG_FLAGS)))
{
info[i].indic_position() = last_pos;
if (unlikely (indic_options ().uniscribe_bug_compatible &&
info[i].indic_category() == OT_H &&
if (unlikely (info[i].indic_category() == OT_H &&
info[i].indic_position() == POS_PRE_M))
{
/*
* Uniscribe doesn't move the Halant with Left Matra.
* TEST: U+092B,U+093F,U+094DE
* We follow. This is important for the Sinhala
* U+0DDA split matra since it decomposes to U+0DD9,U+0DCA
* where U+0DD9 is a left matra and U+0DCA is the virama.
* We don't want to move the virama with the left matra.
* TEST: U+0D9A,U+0DDA
*/
for (unsigned int j = i; j > start; j--)
if (info[j - 1].indic_position() != POS_PRE_M) {
@ -725,9 +741,9 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, hb_buffer
if (indic_plan->mask_array[PREF] && base + 2 < end)
{
/* Find a Halant,Ra sequence and mark it for pre-base reordering processing. */
for (unsigned int i = base + 1; i + 1 < end; i++)
if (is_halant_or_coeng (info[i + (indic_plan->is_old_spec ? 1 : 0)]) &&
info[i + (indic_plan->is_old_spec ? 0 : 1)].indic_category() == OT_Ra)
for (unsigned int i = base + 1; i + 1 < end; i++) {
hb_codepoint_t glyphs[2] = {info[i].codepoint, info[i + 1].codepoint};
if (indic_plan->pref.would_substitute (glyphs, ARRAY_LENGTH (glyphs), true, face))
{
info[i++].mask |= indic_plan->mask_array[PREF];
info[i++].mask |= indic_plan->mask_array[PREF];
@ -743,6 +759,7 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, hb_buffer
break;
}
}
}
/* Apply ZWJ/ZWNJ effects */
@ -768,15 +785,17 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, hb_buffer
static void
initial_reordering_vowel_syllable (const hb_ot_shape_plan_t *plan,
hb_face_t *face,
hb_buffer_t *buffer,
unsigned int start, unsigned int end)
{
/* We made the vowels look like consonants. So let's call the consonant logic! */
initial_reordering_consonant_syllable (plan, buffer, start, end);
initial_reordering_consonant_syllable (plan, face, buffer, start, end);
}
static void
initial_reordering_standalone_cluster (const hb_ot_shape_plan_t *plan,
hb_face_t *face,
hb_buffer_t *buffer,
unsigned int start, unsigned int end)
{
@ -792,20 +811,22 @@ initial_reordering_standalone_cluster (const hb_ot_shape_plan_t *plan,
return;
}
initial_reordering_consonant_syllable (plan, buffer, start, end);
initial_reordering_consonant_syllable (plan, face, buffer, start, end);
}
static void
initial_reordering_broken_cluster (const hb_ot_shape_plan_t *plan,
hb_face_t *face,
hb_buffer_t *buffer,
unsigned int start, unsigned int end)
{
/* We already inserted dotted-circles, so just call the standalone_cluster. */
initial_reordering_standalone_cluster (plan, buffer, start, end);
initial_reordering_standalone_cluster (plan, face, buffer, start, end);
}
static void
initial_reordering_non_indic_cluster (const hb_ot_shape_plan_t *plan HB_UNUSED,
hb_face_t *face HB_UNUSED,
hb_buffer_t *buffer HB_UNUSED,
unsigned int start HB_UNUSED, unsigned int end HB_UNUSED)
{
@ -816,16 +837,17 @@ initial_reordering_non_indic_cluster (const hb_ot_shape_plan_t *plan HB_UNUSED,
static void
initial_reordering_syllable (const hb_ot_shape_plan_t *plan,
hb_face_t *face,
hb_buffer_t *buffer,
unsigned int start, unsigned int end)
{
syllable_type_t syllable_type = (syllable_type_t) (buffer->info[start].syllable() & 0x0F);
switch (syllable_type) {
case consonant_syllable: initial_reordering_consonant_syllable (plan, buffer, start, end); return;
case vowel_syllable: initial_reordering_vowel_syllable (plan, buffer, start, end); return;
case standalone_cluster: initial_reordering_standalone_cluster (plan, buffer, start, end); return;
case broken_cluster: initial_reordering_broken_cluster (plan, buffer, start, end); return;
case non_indic_cluster: initial_reordering_non_indic_cluster (plan, buffer, start, end); return;
case consonant_syllable: initial_reordering_consonant_syllable (plan, face, buffer, start, end); return;
case vowel_syllable: initial_reordering_vowel_syllable (plan, face, buffer, start, end); return;
case standalone_cluster: initial_reordering_standalone_cluster (plan, face, buffer, start, end); return;
case broken_cluster: initial_reordering_broken_cluster (plan, face, buffer, start, end); return;
case non_indic_cluster: initial_reordering_non_indic_cluster (plan, face, buffer, start, end); return;
}
}
@ -850,7 +872,7 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan,
if (!font->get_glyph (0x25CC, 0, &dottedcircle_glyph))
return;
hb_glyph_info_t dottedcircle;
hb_glyph_info_t dottedcircle = {0};
dottedcircle.codepoint = 0x25CC;
set_indic_properties (dottedcircle);
dottedcircle.codepoint = dottedcircle_glyph;
@ -893,11 +915,11 @@ initial_reordering (const hb_ot_shape_plan_t *plan,
unsigned int last_syllable = info[0].syllable();
for (unsigned int i = 1; i < count; i++)
if (last_syllable != info[i].syllable()) {
initial_reordering_syllable (plan, buffer, last, i);
initial_reordering_syllable (plan, font->face, buffer, last, i);
last = i;
last_syllable = info[last].syllable();
}
initial_reordering_syllable (plan, buffer, last, count);
initial_reordering_syllable (plan, font->face, buffer, last, count);
}
static void
@ -1157,21 +1179,28 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan,
*/
unsigned int new_pos = base;
while (new_pos > start &&
!(is_one_of (info[new_pos - 1], FLAG(OT_M) | HALANT_OR_COENG_FLAGS)))
new_pos--;
/* In Khmer coeng model, a V,Ra can go *after* matras. If it goes after a
* split matra, it should be reordered to *before* the left part of such matra. */
if (new_pos > start && info[new_pos - 1].indic_category() == OT_M)
/* Malayalam / Tamil do not have "half" forms or explicit virama forms.
* The glyphs formed by 'half' are Chillus or ligated explicit viramas.
* We want to position matra after them.
*/
if (buffer->props.script != HB_SCRIPT_MALAYALAM && buffer->props.script != HB_SCRIPT_TAMIL)
{
unsigned int old_pos = i;
for (unsigned int i = base + 1; i < old_pos; i++)
if (info[i].indic_category() == OT_M)
{
new_pos--;
break;
}
while (new_pos > start &&
!(is_one_of (info[new_pos - 1], FLAG(OT_M) | HALANT_OR_COENG_FLAGS)))
new_pos--;
/* In Khmer coeng model, a V,Ra can go *after* matras. If it goes after a
* split matra, it should be reordered to *before* the left part of such matra. */
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)
{
new_pos--;
break;
}
}
}
if (new_pos > start && is_halant_or_coeng (info[new_pos - 1]))
@ -1244,11 +1273,108 @@ final_reordering (const hb_ot_shape_plan_t *plan,
static hb_ot_shape_normalization_mode_t
normalization_preference_indic (const hb_ot_shape_plan_t *plan)
normalization_preference_indic (const hb_segment_properties_t *props)
{
return HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT;
}
static bool
decompose_indic (const hb_ot_shape_normalize_context_t *c,
hb_codepoint_t ab,
hb_codepoint_t *a,
hb_codepoint_t *b)
{
switch (ab)
{
/* Don't decompose these. */
case 0x0931 : return false;
case 0x0B94 : return false;
/*
* Decompose split matras that don't have Unicode decompositions.
*/
case 0x0F77 : *a = 0x0FB2; *b= 0x0F81; return true;
case 0x0F79 : *a = 0x0FB3; *b= 0x0F81; return true;
case 0x17BE : *a = 0x17C1; *b= 0x17BE; return true;
case 0x17BF : *a = 0x17C1; *b= 0x17BF; return true;
case 0x17C0 : *a = 0x17C1; *b= 0x17C0; return true;
case 0x17C4 : *a = 0x17C1; *b= 0x17C4; return true;
case 0x17C5 : *a = 0x17C1; *b= 0x17C5; return true;
case 0x1925 : *a = 0x1920; *b= 0x1923; return true;
case 0x1926 : *a = 0x1920; *b= 0x1924; return true;
case 0x1B3C : *a = 0x1B42; *b= 0x1B3C; return true;
case 0x1112E : *a = 0x11127; *b= 0x11131; return true;
case 0x1112F : *a = 0x11127; *b= 0x11132; return true;
#if 0
/* This one has no decomposition in Unicode, but needs no decomposition either. */
/* case 0x0AC9 : return false; */
case 0x0B57 : *a = no decomp, -> RIGHT; return true;
case 0x1C29 : *a = no decomp, -> LEFT; return true;
case 0xA9C0 : *a = no decomp, -> RIGHT; return true;
case 0x111BF : *a = no decomp, -> ABOVE; return true;
#endif
}
if ((ab == 0x0DDA || hb_in_range<hb_codepoint_t> (ab, 0x0DDC, 0x0DDE)))
{
/*
* Sinhala split matras... Let the fun begin.
*
* These four characters have Unicode decompositions. However, Uniscribe
* decomposes them "Khmer-style", that is, it uses the character itself to
* get the second half. The first half of all four decompositions is always
* U+0DD9.
*
* Now, there are buggy fonts, namely, the widely used lklug.ttf, that are
* broken with Uniscribe. But we need to support them. As such, we only
* do the Uniscribe-style decomposition if the character is transformed into
* its "sec.half" form by the 'pstf' feature. Otherwise, we fall back to
* Unicode decomposition.
*
* Note that we can't unconditionally use Unicode decomposition. That would
* break some other fonts, that are designed to work with Uniscribe, and
* don't have positioning features for the Unicode-style decomposition.
*
* Argh...
*/
const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) c->plan->data;
hb_codepoint_t glyph;
if (indic_options ().uniscribe_bug_compatible ||
(c->font->get_glyph (ab, 0, &glyph) &&
indic_plan->pstf.would_substitute (&glyph, 1, true, c->font->face)))
{
/* Ok, safe to use Uniscribe-style decomposition. */
*a = 0x0DD9;
*b = ab;
return true;
}
}
return c->unicode->decompose (ab, a, b);
}
static bool
compose_indic (const hb_ot_shape_normalize_context_t *c,
hb_codepoint_t a,
hb_codepoint_t b,
hb_codepoint_t *ab)
{
/* Avoid recomposing split matras. */
if (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (c->unicode->general_category (a)))
return false;
/* Composition-exclusion exceptions that we want to recompose. */
if (a == 0x09AF && b == 0x09BC) { *ab = 0x09DF; return true; }
return c->unicode->compose (a, b, ab);
}
const hb_ot_complex_shaper_t _hb_ot_complex_shaper_indic =
{
"indic",
@ -1258,6 +1384,9 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_indic =
data_destroy_indic,
NULL, /* preprocess_text */
normalization_preference_indic,
decompose_indic,
compose_indic,
setup_masks_indic,
false, /* zero_width_attached_marks */
false, /* fallback_position */
};

View File

@ -1,208 +0,0 @@
/*
* Copyright © 2010,2012 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod
*/
#include "hb-ot-shape-complex-private.hh"
/* TODO Add kana, and other small shapers here */
/* The default shaper *only* adds additional per-script features.*/
static const hb_tag_t hangul_features[] =
{
HB_TAG('l','j','m','o'),
HB_TAG('v','j','m','o'),
HB_TAG('t','j','m','o'),
HB_TAG_NONE
};
static const hb_tag_t tibetan_features[] =
{
HB_TAG('a','b','v','s'),
HB_TAG('b','l','w','s'),
HB_TAG('a','b','v','m'),
HB_TAG('b','l','w','m'),
HB_TAG_NONE
};
static void
collect_features_default (hb_ot_shape_planner_t *plan)
{
const hb_tag_t *script_features = NULL;
switch ((hb_tag_t) plan->props.script)
{
/* Unicode-1.1 additions */
case HB_SCRIPT_HANGUL:
script_features = hangul_features;
break;
/* Unicode-2.0 additions */
case HB_SCRIPT_TIBETAN:
script_features = tibetan_features;
break;
}
for (; script_features && *script_features; script_features++)
plan->map.add_bool_feature (*script_features);
}
static hb_ot_shape_normalization_mode_t
normalization_preference_default (const hb_ot_shape_plan_t *plan)
{
switch ((hb_tag_t) plan->props.script)
{
/* Unicode-1.1 additions */
case HB_SCRIPT_HANGUL:
return HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_FULL;
}
return HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS;
}
const hb_ot_complex_shaper_t _hb_ot_complex_shaper_default =
{
"default",
collect_features_default,
NULL, /* override_features */
NULL, /* data_create */
NULL, /* data_destroy */
NULL, /* preprocess_text */
normalization_preference_default,
NULL, /* setup_masks */
true, /* zero_width_attached_marks */
};
/* Thai / Lao shaper */
static void
preprocess_text_thai (const hb_ot_shape_plan_t *plan HB_UNUSED,
hb_buffer_t *buffer,
hb_font_t *font HB_UNUSED)
{
/* The following is NOT specified in the MS OT Thai spec, however, it seems
* to be what Uniscribe and other engines implement. According to Eric Muller:
*
* When you have a SARA AM, decompose it in NIKHAHIT + SARA AA, *and* move the
* NIKHAHIT backwards over any tone mark (0E48-0E4B).
*
* <0E14, 0E4B, 0E33> -> <0E14, 0E4D, 0E4B, 0E32>
*
* This reordering is legit only when the NIKHAHIT comes from a SARA AM, not
* when it's there to start with. The string <0E14, 0E4B, 0E4D> is probably
* not what a user wanted, but the rendering is nevertheless nikhahit above
* chattawa.
*
* Same for Lao.
*
* Note:
*
* Uniscribe also does so below-marks reordering. Namely, it positions U+0E3A
* after U+0E38 and U+0E39. We do that by modifying the ccc for U+0E3A.
* See unicode->modified_combining_class (). Lao does NOT have a U+0E3A
* equivalent.
*/
/*
* Here are the characters of significance:
*
* Thai Lao
* SARA AM: U+0E33 U+0EB3
* SARA AA: U+0E32 U+0EB2
* Nikhahit: U+0E4D U+0ECD
*
* Testing shows that Uniscribe reorder the following marks:
* Thai: <0E31,0E34..0E37,0E47..0E4E>
* Lao: <0EB1,0EB4..0EB7,0EC7..0ECE>
*
* Note how the Lao versions are the same as Thai + 0x80.
*/
/* We only get one script at a time, so a script-agnostic implementation
* is adequate here. */
#define IS_SARA_AM(x) (((x) & ~0x0080) == 0x0E33)
#define NIKHAHIT_FROM_SARA_AM(x) ((x) - 0xE33 + 0xE4D)
#define SARA_AA_FROM_SARA_AM(x) ((x) - 1)
#define IS_TONE_MARK(x) (hb_in_ranges<hb_codepoint_t> ((x) & ~0x0080, 0x0E34, 0x0E37, 0x0E47, 0x0E4E, 0x0E31, 0x0E31))
buffer->clear_output ();
unsigned int count = buffer->len;
for (buffer->idx = 0; buffer->idx < count;)
{
hb_codepoint_t u = buffer->cur().codepoint;
if (likely (!IS_SARA_AM (u))) {
buffer->next_glyph ();
continue;
}
/* Is SARA AM. Decompose and reorder. */
hb_codepoint_t decomposed[2] = {hb_codepoint_t (NIKHAHIT_FROM_SARA_AM (u)),
hb_codepoint_t (SARA_AA_FROM_SARA_AM (u))};
buffer->replace_glyphs (1, 2, decomposed);
if (unlikely (buffer->in_error))
return;
/* Ok, let's see... */
unsigned int end = buffer->out_len;
unsigned int start = end - 2;
while (start > 0 && IS_TONE_MARK (buffer->out_info[start - 1].codepoint))
start--;
if (start + 2 < end)
{
/* Move Nikhahit (end-2) to the beginning */
buffer->merge_out_clusters (start, end);
hb_glyph_info_t t = buffer->out_info[end - 2];
memmove (buffer->out_info + start + 1,
buffer->out_info + start,
sizeof (buffer->out_info[0]) * (end - start - 2));
buffer->out_info[start] = t;
}
else
{
/* Since we decomposed, and NIKHAHIT is combining, merge clusters with the
* previous cluster. */
if (start)
buffer->merge_out_clusters (start - 1, end);
}
}
buffer->swap_buffers ();
}
const hb_ot_complex_shaper_t _hb_ot_complex_shaper_thai =
{
"thai",
NULL, /* collect_features */
NULL, /* override_features */
NULL, /* data_create */
NULL, /* data_destroy */
preprocess_text_thai,
NULL, /* normalization_preference */
NULL, /* setup_masks */
true, /* zero_width_attached_marks */
};

View File

@ -56,6 +56,7 @@ struct hb_ot_complex_shaper_t
/* collect_features()
* Called during shape_plan().
* Shapers should use plan->map to add their features and callbacks.
* May be NULL.
*/
void (*collect_features) (hb_ot_shape_planner_t *plan);
@ -63,6 +64,7 @@ struct hb_ot_complex_shaper_t
* Called during shape_plan().
* Shapers should use plan->map to override features and add callbacks after
* common features are added.
* May be NULL.
*/
void (*override_features) (hb_ot_shape_planner_t *plan);
@ -78,13 +80,15 @@ struct hb_ot_complex_shaper_t
* Called when the shape_plan is being destroyed.
* plan->data is passed here for destruction.
* If NULL is returned, means a plan failure.
* May be NULL. */
* May be NULL.
*/
void (*data_destroy) (void *data);
/* preprocess_text()
* Called during shape().
* Shapers can use to modify text before shaping starts.
* May be NULL.
*/
void (*preprocess_text) (const hb_ot_shape_plan_t *plan,
hb_buffer_t *buffer,
@ -93,20 +97,41 @@ struct hb_ot_complex_shaper_t
/* normalization_preference()
* Called during shape().
* May be NULL.
*/
hb_ot_shape_normalization_mode_t
(*normalization_preference) (const hb_ot_shape_plan_t *plan);
(*normalization_preference) (const hb_segment_properties_t *props);
/* decompose()
* Called during shape()'s normalization.
* May be NULL.
*/
bool (*decompose) (const hb_ot_shape_normalize_context_t *c,
hb_codepoint_t ab,
hb_codepoint_t *a,
hb_codepoint_t *b);
/* compose()
* Called during shape()'s normalization.
* May be NULL.
*/
bool (*compose) (const hb_ot_shape_normalize_context_t *c,
hb_codepoint_t a,
hb_codepoint_t b,
hb_codepoint_t *ab);
/* setup_masks()
* Called during shape().
* Shapers should use map to get feature masks and set on buffer.
* Shapers may NOT modify characters.
* May be NULL.
*/
void (*setup_masks) (const hb_ot_shape_plan_t *plan,
hb_buffer_t *buffer,
hb_font_t *font);
bool zero_width_attached_marks;
bool fallback_position;
};
#define HB_COMPLEX_SHAPER_IMPLEMENT(name) extern HB_INTERNAL const hb_ot_complex_shaper_t _hb_ot_complex_shaper_##name;
@ -115,9 +140,9 @@ HB_COMPLEX_SHAPERS_IMPLEMENT_SHAPERS
static inline const hb_ot_complex_shaper_t *
hb_ot_shape_complex_categorize (const hb_segment_properties_t *props)
hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner)
{
switch ((hb_tag_t) props->script)
switch ((hb_tag_t) planner->props.script)
{
default:
return &_hb_ot_complex_shaper_default;
@ -130,11 +155,18 @@ hb_ot_shape_complex_categorize (const hb_segment_properties_t *props)
/* Unicode-5.0 additions */
case HB_SCRIPT_NKO:
case HB_SCRIPT_PHAGS_PA:
/* Unicode-6.0 additions */
case HB_SCRIPT_MANDAIC:
return &_hb_ot_complex_shaper_arabic;
/* For Arabic script, use the Arabic shaper even if no OT script tag was found.
* This is because we do fallback shaping for Arabic script (and not others). */
if (planner->map.chosen_script[0] != HB_OT_TAG_DEFAULT_SCRIPT ||
planner->props.script == HB_SCRIPT_ARABIC)
return &_hb_ot_complex_shaper_arabic;
else
return &_hb_ot_complex_shaper_default;
/* Unicode-1.1 additions */
@ -170,9 +202,6 @@ hb_ot_shape_complex_categorize (const hb_segment_properties_t *props)
/* Unicode-5.1 additions */
case HB_SCRIPT_SAURASHTRA:
/* Unicode-5.2 additions */
case HB_SCRIPT_MEETEI_MAYEK:
/* Unicode-6.0 additions */
case HB_SCRIPT_BATAK:
case HB_SCRIPT_BRAHMI:
@ -197,11 +226,9 @@ hb_ot_shape_complex_categorize (const hb_segment_properties_t *props)
case HB_SCRIPT_TAI_LE:
/* Unicode-4.1 additions */
case HB_SCRIPT_KHAROSHTHI:
case HB_SCRIPT_SYLOTI_NAGRI:
/* Unicode-5.0 additions */
case HB_SCRIPT_PHAGS_PA:
/* Unicode-5.1 additions */
case HB_SCRIPT_KAYAH_LI:
@ -209,12 +236,6 @@ hb_ot_shape_complex_categorize (const hb_segment_properties_t *props)
case HB_SCRIPT_TAI_VIET:
/* May need Indic treatment in the future? */
/* Unicode-3.0 additions */
case HB_SCRIPT_MYANMAR:
#endif
/* Unicode-1.1 additions */
@ -229,12 +250,10 @@ hb_ot_shape_complex_categorize (const hb_segment_properties_t *props)
case HB_SCRIPT_TELUGU:
/* Unicode-3.0 additions */
case HB_SCRIPT_KHMER:
case HB_SCRIPT_SINHALA:
/* Unicode-4.1 additions */
case HB_SCRIPT_BUGINESE:
case HB_SCRIPT_KHAROSHTHI:
case HB_SCRIPT_NEW_TAI_LUE:
/* Unicode-5.0 additions */
@ -249,14 +268,40 @@ hb_ot_shape_complex_categorize (const hb_segment_properties_t *props)
/* Unicode-5.2 additions */
case HB_SCRIPT_JAVANESE:
case HB_SCRIPT_KAITHI:
case HB_SCRIPT_MEETEI_MAYEK:
case HB_SCRIPT_TAI_THAM:
/* Unicode-6.1 additions */
case HB_SCRIPT_CHAKMA:
case HB_SCRIPT_SHARADA:
case HB_SCRIPT_TAKRI:
return &_hb_ot_complex_shaper_indic;
/* Only use Indic shaper if the font has Indic tables. */
if (planner->map.found_script[0])
return &_hb_ot_complex_shaper_indic;
else
return &_hb_ot_complex_shaper_default;
case HB_SCRIPT_KHMER:
/* If the font has 'liga', let the generic shaper do it. */
if (!planner->map.found_script[0] ||
hb_ot_layout_language_find_feature (planner->face, HB_OT_TAG_GSUB,
planner->map.script_index[0],
planner->map.language_index[0],
HB_TAG ('l','i','g','a'), NULL))
return &_hb_ot_complex_shaper_default;
else
return &_hb_ot_complex_shaper_indic;
case HB_SCRIPT_MYANMAR:
/* For Myanmar, we only want to use the Indic shaper if the "new" script
* tag is found. For "old" script tag we want to use the default shaper. */
if (planner->map.chosen_script[0] == HB_TAG ('m','y','m','2'))
return &_hb_ot_complex_shaper_indic;
else
return &_hb_ot_complex_shaper_default;
}
}

View File

@ -0,0 +1,378 @@
/*
* Copyright © 2010,2012 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod
*/
#include "hb-ot-shape-complex-private.hh"
/* Thai / Lao shaper */
/* PUA shaping */
enum thai_consonant_type_t
{
NC,
AC,
RC,
DC,
NOT_CONSONANT,
NUM_CONSONANT_TYPES = NOT_CONSONANT
};
static thai_consonant_type_t
get_consonant_type (hb_codepoint_t u)
{
if (u == 0x0E1B || u == 0x0E1D || u == 0x0E1F/* || u == 0x0E2C*/)
return AC;
if (u == 0x0E0D || u == 0x0E10)
return RC;
if (u == 0x0E0E || u == 0x0E0F)
return DC;
if (hb_in_range<hb_codepoint_t> (u, 0x0E01, 0x0E2E))
return NC;
return NOT_CONSONANT;
}
enum thai_mark_type_t
{
AV,
BV,
T,
NOT_MARK,
NUM_MARK_TYPES = NOT_MARK
};
static thai_mark_type_t
get_mark_type (hb_codepoint_t u)
{
if (u == 0x0E31 || hb_in_range<hb_codepoint_t> (u, 0x0E34, 0x0E37) ||
u == 0x0E47 || hb_in_range<hb_codepoint_t> (u, 0x0E4D, 0x0E4E))
return AV;
if (hb_in_range<hb_codepoint_t> (u, 0x0E38, 0x0E3A))
return BV;
if (hb_in_range<hb_codepoint_t> (u, 0x0E48, 0x0E4C))
return T;
return NOT_MARK;
}
enum thai_action_t
{
NOP,
SD, /* Shift combining-mark down */
SL, /* Shift combining-mark left */
SDL, /* Shift combining-mark down-left */
RD /* Remove descender from base */
};
static hb_codepoint_t
thai_pua_shape (hb_codepoint_t u, thai_action_t action, hb_font_t *font)
{
struct thai_pua_mapping_t {
hb_codepoint_t u;
hb_codepoint_t win_pua;
hb_codepoint_t mac_pua;
} const *pua_mappings = NULL;
static const thai_pua_mapping_t SD_mappings[] = {
{0x0E48, 0xF70A, 0xF88B}, /* MAI EK */
{0x0E49, 0xF70B, 0xF88E}, /* MAI THO */
{0x0E4A, 0xF70C, 0xF891}, /* MAI TRI */
{0x0E4B, 0xF70D, 0xF894}, /* MAI CHATTAWA */
{0x0E4C, 0xF70E, 0xF897}, /* THANTHAKHAT */
{0x0E38, 0xF718, 0xF89B}, /* SARA U */
{0x0E39, 0xF719, 0xF89C}, /* SARA UU */
{0x0E3A, 0xF71A, 0xF89D}, /* PHINTHU */
{0x0000, 0x0000, 0x0000}
};
static const thai_pua_mapping_t SDL_mappings[] = {
{0x0E48, 0xF705, 0xF88C}, /* MAI EK */
{0x0E49, 0xF706, 0xF88F}, /* MAI THO */
{0x0E4A, 0xF707, 0xF892}, /* MAI TRI */
{0x0E4B, 0xF708, 0xF895}, /* MAI CHATTAWA */
{0x0E4C, 0xF709, 0xF898}, /* THANTHAKHAT */
{0x0000, 0x0000, 0x0000}
};
static const thai_pua_mapping_t SL_mappings[] = {
{0x0E48, 0xF713, 0xF88A}, /* MAI EK */
{0x0E49, 0xF714, 0xF88D}, /* MAI THO */
{0x0E4A, 0xF715, 0xF890}, /* MAI TRI */
{0x0E4B, 0xF716, 0xF893}, /* MAI CHATTAWA */
{0x0E4C, 0xF717, 0xF896}, /* THANTHAKHAT */
{0x0E31, 0xF710, 0xF884}, /* MAI HAN-AKAT */
{0x0E34, 0xF701, 0xF885}, /* SARA I */
{0x0E35, 0xF702, 0xF886}, /* SARA II */
{0x0E36, 0xF703, 0xF887}, /* SARA UE */
{0x0E37, 0xF704, 0xF888}, /* SARA UEE */
{0x0E47, 0xF712, 0xF889}, /* MAITAIKHU */
{0x0E4D, 0xF711, 0xF899}, /* NIKHAHIT */
{0x0000, 0x0000, 0x0000}
};
static const thai_pua_mapping_t RD_mappings[] = {
{0x0E0D, 0xF70F, 0xF89A}, /* YO YING */
{0x0E10, 0xF700, 0xF89E}, /* THO THAN */
{0x0000, 0x0000, 0x0000}
};
switch (action) {
default: assert (false); /* Fallthrough */
case NOP: return u;
case SD: pua_mappings = SD_mappings; break;
case SDL: pua_mappings = SDL_mappings; break;
case SL: pua_mappings = SL_mappings; break;
case RD: pua_mappings = RD_mappings; break;
}
for (; pua_mappings->u; pua_mappings++)
if (pua_mappings->u == u)
{
hb_codepoint_t glyph;
if (hb_font_get_glyph (font, pua_mappings->win_pua, 0, &glyph))
return pua_mappings->win_pua;
if (hb_font_get_glyph (font, pua_mappings->mac_pua, 0, &glyph))
return pua_mappings->mac_pua;
break;
}
return u;
}
static enum thai_above_state_t
{ /* Cluster above looks like: */
T0, /* ⣤ */
T1, /* ⣼ */
T2, /* ⣾ */
T3, /* ⣿ */
NUM_ABOVE_STATES
} thai_above_start_state[NUM_CONSONANT_TYPES + 1/* For NOT_CONSONANT */] =
{
T0, /* NC */
T1, /* AC */
T0, /* RC */
T0, /* DC */
T3, /* NOT_CONSONANT */
};
static const struct thai_above_state_machine_edge_t {
thai_action_t action;
thai_above_state_t next_state;
} thai_above_state_machine[NUM_ABOVE_STATES][NUM_MARK_TYPES] =
{ /*AV*/ /*BV*/ /*T*/
/*T0*/ {{NOP,T3}, {NOP,T0}, {SD, T3}},
/*T1*/ {{SL, T2}, {NOP,T1}, {SDL,T2}},
/*T2*/ {{NOP,T3}, {NOP,T2}, {SL, T3}},
/*T3*/ {{NOP,T3}, {NOP,T3}, {NOP,T3}},
};
static enum thai_below_state_t
{
B0, /* No descender */
B1, /* Removable descender */
B2, /* Strict descender */
NUM_BELOW_STATES
} thai_below_start_state[NUM_CONSONANT_TYPES + 1/* For NOT_CONSONANT */] =
{
B0, /* NC */
B0, /* AC */
B1, /* RC */
B2, /* DC */
B2, /* NOT_CONSONANT */
};
static const struct thai_below_state_machine_edge_t {
thai_action_t action;
thai_below_state_t next_state;
} thai_below_state_machine[NUM_BELOW_STATES][NUM_MARK_TYPES] =
{ /*AV*/ /*BV*/ /*T*/
/*B0*/ {{NOP,B0}, {NOP,B2}, {NOP, B0}},
/*B1*/ {{NOP,B1}, {RD, B2}, {NOP, B1}},
/*B2*/ {{NOP,B2}, {SD, B2}, {NOP, B2}},
};
static void
do_thai_pua_shaping (const hb_ot_shape_plan_t *plan,
hb_buffer_t *buffer,
hb_font_t *font)
{
thai_above_state_t above_state = thai_above_start_state[NOT_CONSONANT];
thai_below_state_t below_state = thai_below_start_state[NOT_CONSONANT];
unsigned int base = 0;
hb_glyph_info_t *info = buffer->info;
unsigned int count = buffer->len;
for (unsigned int i = 0; i < count; i++)
{
thai_mark_type_t mt = get_mark_type (info[i].codepoint);
if (mt == NOT_MARK) {
thai_consonant_type_t ct = get_consonant_type (info[i].codepoint);
above_state = thai_above_start_state[ct];
below_state = thai_below_start_state[ct];
base = i;
continue;
}
const thai_above_state_machine_edge_t &above_edge = thai_above_state_machine[above_state][mt];
const thai_below_state_machine_edge_t &below_edge = thai_below_state_machine[below_state][mt];
above_state = above_edge.next_state;
below_state = below_edge.next_state;
/* At least one of the above/below actions is NOP. */
thai_action_t action = above_edge.action != NOP ? above_edge.action : below_edge.action;
if (action == RD)
info[base].codepoint = thai_pua_shape (info[base].codepoint, action, font);
else
info[i].codepoint = thai_pua_shape (info[i].codepoint, action, font);
}
}
static void
preprocess_text_thai (const hb_ot_shape_plan_t *plan,
hb_buffer_t *buffer,
hb_font_t *font)
{
/* This function implements the shaping logic documented here:
*
* http://linux.thai.net/~thep/th-otf/shaping.html
*
* The first shaping rule listed there is needed even if the font has Thai
* OpenType tables. The rest do fallback positioning based on PUA codepoints.
* We implement that only if there exist no Thai GSUB in the font.
*/
/* The following is NOT specified in the MS OT Thai spec, however, it seems
* to be what Uniscribe and other engines implement. According to Eric Muller:
*
* When you have a SARA AM, decompose it in NIKHAHIT + SARA AA, *and* move the
* NIKHAHIT backwards over any tone mark (0E48-0E4B).
*
* <0E14, 0E4B, 0E33> -> <0E14, 0E4D, 0E4B, 0E32>
*
* This reordering is legit only when the NIKHAHIT comes from a SARA AM, not
* when it's there to start with. The string <0E14, 0E4B, 0E4D> is probably
* not what a user wanted, but the rendering is nevertheless nikhahit above
* chattawa.
*
* Same for Lao.
*
* Note:
*
* Uniscribe also does some below-marks reordering. Namely, it positions U+0E3A
* after U+0E38 and U+0E39. We do that by modifying the ccc for U+0E3A.
* See unicode->modified_combining_class (). Lao does NOT have a U+0E3A
* equivalent.
*/
/*
* Here are the characters of significance:
*
* Thai Lao
* SARA AM: U+0E33 U+0EB3
* SARA AA: U+0E32 U+0EB2
* Nikhahit: U+0E4D U+0ECD
*
* Testing shows that Uniscribe reorder the following marks:
* Thai: <0E31,0E34..0E37,0E47..0E4E>
* Lao: <0EB1,0EB4..0EB7,0EC7..0ECE>
*
* Note how the Lao versions are the same as Thai + 0x80.
*/
/* We only get one script at a time, so a script-agnostic implementation
* is adequate here. */
#define IS_SARA_AM(x) (((x) & ~0x0080) == 0x0E33)
#define NIKHAHIT_FROM_SARA_AM(x) ((x) - 0xE33 + 0xE4D)
#define SARA_AA_FROM_SARA_AM(x) ((x) - 1)
#define IS_TONE_MARK(x) (hb_in_ranges<hb_codepoint_t> ((x) & ~0x0080, 0x0E34, 0x0E37, 0x0E47, 0x0E4E, 0x0E31, 0x0E31))
buffer->clear_output ();
unsigned int count = buffer->len;
for (buffer->idx = 0; buffer->idx < count;)
{
hb_codepoint_t u = buffer->cur().codepoint;
if (likely (!IS_SARA_AM (u))) {
buffer->next_glyph ();
continue;
}
/* Is SARA AM. Decompose and reorder. */
hb_codepoint_t decomposed[2] = {hb_codepoint_t (NIKHAHIT_FROM_SARA_AM (u)),
hb_codepoint_t (SARA_AA_FROM_SARA_AM (u))};
buffer->replace_glyphs (1, 2, decomposed);
if (unlikely (buffer->in_error))
return;
/* Ok, let's see... */
unsigned int end = buffer->out_len;
unsigned int start = end - 2;
while (start > 0 && IS_TONE_MARK (buffer->out_info[start - 1].codepoint))
start--;
if (start + 2 < end)
{
/* Move Nikhahit (end-2) to the beginning */
buffer->merge_out_clusters (start, end);
hb_glyph_info_t t = buffer->out_info[end - 2];
memmove (buffer->out_info + start + 1,
buffer->out_info + start,
sizeof (buffer->out_info[0]) * (end - start - 2));
buffer->out_info[start] = t;
}
else
{
/* Since we decomposed, and NIKHAHIT is combining, merge clusters with the
* previous cluster. */
if (start)
buffer->merge_out_clusters (start - 1, end);
}
}
buffer->swap_buffers ();
/* If font has Thai GSUB, we are done. */
if (plan->props.script == HB_SCRIPT_THAI && !plan->map.found_script[0])
do_thai_pua_shaping (plan, buffer, font);
}
const hb_ot_complex_shaper_t _hb_ot_complex_shaper_thai =
{
"thai",
NULL, /* collect_features */
NULL, /* override_features */
NULL, /* data_create */
NULL, /* data_destroy */
preprocess_text_thai,
NULL, /* normalization_preference */
NULL, /* decompose */
NULL, /* compose */
NULL, /* setup_masks */
true, /* zero_width_attached_marks */
false,/* fallback_position */
};

View File

@ -138,10 +138,10 @@ recategorize_combining_class (hb_codepoint_t u,
/* Lao */
case HB_MODIFIED_COMBINING_CLASS_CCC118: /* sign u / sign uu */
return HB_UNICODE_COMBINING_CLASS_BELOW_RIGHT;
return HB_UNICODE_COMBINING_CLASS_BELOW;
case HB_MODIFIED_COMBINING_CLASS_CCC122: /* mai */
return HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT;
return HB_UNICODE_COMBINING_CLASS_ABOVE;
/* Tibetan */
@ -311,7 +311,7 @@ position_around_base (const hb_ot_shape_plan_t *plan,
hb_glyph_extents_t component_extents = base_extents;
unsigned int last_lig_component = (unsigned int) -1;
unsigned int last_combining_class = 255;
hb_glyph_extents_t cluster_extents;
hb_glyph_extents_t cluster_extents = base_extents; /* Initialization is just to shut gcc up. */
for (unsigned int i = base + 1; i < end; i++)
if (_hb_glyph_info_get_modified_combining_class (&buffer->info[i]))
{

View File

@ -35,6 +35,8 @@
/* buffer var allocations, used during the normalization process */
#define glyph_index() var1.u32
struct hb_ot_shape_plan_t;
enum hb_ot_shape_normalization_mode_t {
HB_OT_SHAPE_NORMALIZATION_MODE_DECOMPOSED,
HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS, /* never composes base-to-base */
@ -44,8 +46,26 @@ enum hb_ot_shape_normalization_mode_t {
HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT = HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS
};
HB_INTERNAL void _hb_ot_shape_normalize (hb_font_t *font,
HB_INTERNAL void _hb_ot_shape_normalize (const hb_ot_shape_plan_t *shaper,
hb_buffer_t *buffer,
hb_ot_shape_normalization_mode_t mode);
hb_font_t *font);
struct hb_ot_shape_normalize_context_t
{
const hb_ot_shape_plan_t *plan;
hb_buffer_t *buffer;
hb_font_t *font;
hb_unicode_funcs_t *unicode;
bool (*decompose) (const hb_ot_shape_normalize_context_t *c,
hb_codepoint_t ab,
hb_codepoint_t *a,
hb_codepoint_t *b);
bool (*compose) (const hb_ot_shape_normalize_context_t *c,
hb_codepoint_t a,
hb_codepoint_t b,
hb_codepoint_t *ab);
};
#endif /* HB_OT_SHAPE_NORMALIZE_PRIVATE_HH */

View File

@ -25,6 +25,7 @@
*/
#include "hb-ot-shape-normalize-private.hh"
#include "hb-ot-shape-complex-private.hh"
#include "hb-ot-shape-private.hh"
@ -81,181 +82,24 @@
* egrep "`echo -n ';('; grep ';<' UnicodeData.txt | cut -d';' -f1 | tr '\n' '|'; echo ') '`" UnicodeData.txt
*/
static hb_bool_t
decompose_func (hb_unicode_funcs_t *unicode,
hb_codepoint_t ab,
hb_codepoint_t *a,
hb_codepoint_t *b)
static bool
decompose_unicode (const hb_ot_shape_normalize_context_t *c,
hb_codepoint_t ab,
hb_codepoint_t *a,
hb_codepoint_t *b)
{
/* XXX FIXME, move these to complex shapers and propagage to normalizer.*/
switch (ab) {
case 0x0AC9 : return false;
case 0x0931 : return false;
case 0x0B94 : return false;
/* These ones have Unicode decompositions, but we do it
* this way to be close to what Uniscribe does. */
case 0x0DDA : *a = 0x0DD9; *b= 0x0DDA; return true;
case 0x0DDC : *a = 0x0DD9; *b= 0x0DDC; return true;
case 0x0DDD : *a = 0x0DD9; *b= 0x0DDD; return true;
case 0x0DDE : *a = 0x0DD9; *b= 0x0DDE; return true;
case 0x0F77 : *a = 0x0FB2; *b= 0x0F81; return true;
case 0x0F79 : *a = 0x0FB3; *b= 0x0F81; return true;
case 0x17BE : *a = 0x17C1; *b= 0x17BE; return true;
case 0x17BF : *a = 0x17C1; *b= 0x17BF; return true;
case 0x17C0 : *a = 0x17C1; *b= 0x17C0; return true;
case 0x17C4 : *a = 0x17C1; *b= 0x17C4; return true;
case 0x17C5 : *a = 0x17C1; *b= 0x17C5; return true;
case 0x1925 : *a = 0x1920; *b= 0x1923; return true;
case 0x1926 : *a = 0x1920; *b= 0x1924; return true;
case 0x1B3C : *a = 0x1B42; *b= 0x1B3C; return true;
case 0x1112E : *a = 0x11127; *b= 0x11131; return true;
case 0x1112F : *a = 0x11127; *b= 0x11132; return true;
#if 0
case 0x0B57 : *a = 0xno decomp, -> RIGHT; return true;
case 0x1C29 : *a = 0xno decomp, -> LEFT; return true;
case 0xA9C0 : *a = 0xno decomp, -> RIGHT; return true;
case 0x111BF : *a = 0xno decomp, -> ABOVE; return true;
#endif
}
return unicode->decompose (ab, a, b);
return c->unicode->decompose (ab, a, b);
}
static hb_bool_t
compose_func (hb_unicode_funcs_t *unicode,
hb_codepoint_t a,
hb_codepoint_t b,
hb_codepoint_t *ab)
static bool
compose_unicode (const hb_ot_shape_normalize_context_t *c,
hb_codepoint_t a,
hb_codepoint_t b,
hb_codepoint_t *ab)
{
/* XXX, this belongs to indic normalizer. */
if (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (unicode->general_category (a)))
return false;
/* XXX, add composition-exclusion exceptions to Indic shaper. */
if (a == 0x09AF && b == 0x09BC) { *ab = 0x09DF; return true; }
/* XXX, these belong to the hebew / default shaper. */
/* Hebrew presentation-form shaping.
* https://bugzilla.mozilla.org/show_bug.cgi?id=728866 */
// Hebrew presentation forms with dagesh, for characters 0x05D0..0x05EA;
// note that some letters do not have a dagesh presForm encoded
static const hb_codepoint_t sDageshForms[0x05EA - 0x05D0 + 1] = {
0xFB30, // ALEF
0xFB31, // BET
0xFB32, // GIMEL
0xFB33, // DALET
0xFB34, // HE
0xFB35, // VAV
0xFB36, // ZAYIN
0, // HET
0xFB38, // TET
0xFB39, // YOD
0xFB3A, // FINAL KAF
0xFB3B, // KAF
0xFB3C, // LAMED
0, // FINAL MEM
0xFB3E, // MEM
0, // FINAL NUN
0xFB40, // NUN
0xFB41, // SAMEKH
0, // AYIN
0xFB43, // FINAL PE
0xFB44, // PE
0, // FINAL TSADI
0xFB46, // TSADI
0xFB47, // QOF
0xFB48, // RESH
0xFB49, // SHIN
0xFB4A // TAV
};
hb_bool_t found = unicode->compose (a, b, ab);
if (!found && (b & ~0x7F) == 0x0580) {
// special-case Hebrew presentation forms that are excluded from
// standard normalization, but wanted for old fonts
switch (b) {
case 0x05B4: // HIRIQ
if (a == 0x05D9) { // YOD
*ab = 0xFB1D;
found = true;
}
break;
case 0x05B7: // patah
if (a == 0x05F2) { // YIDDISH YOD YOD
*ab = 0xFB1F;
found = true;
} else if (a == 0x05D0) { // ALEF
*ab = 0xFB2E;
found = true;
}
break;
case 0x05B8: // QAMATS
if (a == 0x05D0) { // ALEF
*ab = 0xFB2F;
found = true;
}
break;
case 0x05B9: // HOLAM
if (a == 0x05D5) { // VAV
*ab = 0xFB4B;
found = true;
}
break;
case 0x05BC: // DAGESH
if (a >= 0x05D0 && a <= 0x05EA) {
*ab = sDageshForms[a - 0x05D0];
found = (*ab != 0);
} else if (a == 0xFB2A) { // SHIN WITH SHIN DOT
*ab = 0xFB2C;
found = true;
} else if (a == 0xFB2B) { // SHIN WITH SIN DOT
*ab = 0xFB2D;
found = true;
}
break;
case 0x05BF: // RAFE
switch (a) {
case 0x05D1: // BET
*ab = 0xFB4C;
found = true;
break;
case 0x05DB: // KAF
*ab = 0xFB4D;
found = true;
break;
case 0x05E4: // PE
*ab = 0xFB4E;
found = true;
break;
}
break;
case 0x05C1: // SHIN DOT
if (a == 0x05E9) { // SHIN
*ab = 0xFB2A;
found = true;
} else if (a == 0xFB49) { // SHIN WITH DAGESH
*ab = 0xFB2C;
found = true;
}
break;
case 0x05C2: // SIN DOT
if (a == 0x05E9) { // SHIN
*ab = 0xFB2B;
found = true;
} else if (a == 0xFB49) { // SHIN WITH DAGESH
*ab = 0xFB2D;
found = true;
}
break;
}
}
return found;
return c->unicode->compose (a, b, ab);
}
static inline void
set_glyph (hb_glyph_info_t &info, hb_font_t *font)
{
@ -285,38 +129,38 @@ skip_char (hb_buffer_t *buffer)
/* Returns 0 if didn't decompose, number of resulting characters otherwise. */
static inline unsigned int
decompose (hb_font_t *font, hb_buffer_t *buffer, bool shortest, hb_codepoint_t ab)
decompose (const hb_ot_shape_normalize_context_t *c, bool shortest, hb_codepoint_t ab)
{
hb_codepoint_t a, b, a_glyph, b_glyph;
if (!decompose_func (buffer->unicode, ab, &a, &b) ||
(b && !font->get_glyph (b, 0, &b_glyph)))
if (!c->decompose (c, ab, &a, &b) ||
(b && !c->font->get_glyph (b, 0, &b_glyph)))
return 0;
bool has_a = font->get_glyph (a, 0, &a_glyph);
bool has_a = c->font->get_glyph (a, 0, &a_glyph);
if (shortest && has_a) {
/* Output a and b */
output_char (buffer, a, a_glyph);
output_char (c->buffer, a, a_glyph);
if (likely (b)) {
output_char (buffer, b, b_glyph);
output_char (c->buffer, b, b_glyph);
return 2;
}
return 1;
}
unsigned int ret;
if ((ret = decompose (font, buffer, shortest, a))) {
if ((ret = decompose (c, shortest, a))) {
if (b) {
output_char (buffer, b, b_glyph);
output_char (c->buffer, b, b_glyph);
return ret + 1;
}
return ret;
}
if (has_a) {
output_char (buffer, a, a_glyph);
output_char (c->buffer, a, a_glyph);
if (likely (b)) {
output_char (buffer, b, b_glyph);
output_char (c->buffer, b, b_glyph);
return 2;
}
return 1;
@ -327,41 +171,42 @@ decompose (hb_font_t *font, hb_buffer_t *buffer, bool shortest, hb_codepoint_t a
/* Returns 0 if didn't decompose, number of resulting characters otherwise. */
static inline bool
decompose_compatibility (hb_font_t *font, hb_buffer_t *buffer, hb_codepoint_t u)
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 = buffer->unicode->decompose_compatibility (u, decomposed);
len = c->buffer->unicode->decompose_compatibility (u, decomposed);
if (!len)
return 0;
for (i = 0; i < len; i++)
if (!font->get_glyph (decomposed[i], 0, &glyphs[i]))
if (!c->font->get_glyph (decomposed[i], 0, &glyphs[i]))
return 0;
for (i = 0; i < len; i++)
output_char (buffer, decomposed[i], glyphs[i]);
output_char (c->buffer, decomposed[i], glyphs[i]);
return len;
}
/* Returns true if recomposition may be benefitial. */
static inline bool
decompose_current_character (hb_font_t *font, hb_buffer_t *buffer, bool shortest)
decompose_current_character (const hb_ot_shape_normalize_context_t *c, bool shortest)
{
hb_buffer_t * const buffer = c->buffer;
hb_codepoint_t glyph;
unsigned int len = 1;
/* Kind of a cute waterfall here... */
if (shortest && font->get_glyph (buffer->cur().codepoint, 0, &glyph))
if (shortest && c->font->get_glyph (buffer->cur().codepoint, 0, &glyph))
next_char (buffer, glyph);
else if ((len = decompose (font, buffer, shortest, buffer->cur().codepoint)))
else if ((len = decompose (c, shortest, buffer->cur().codepoint)))
skip_char (buffer);
else if (!shortest && font->get_glyph (buffer->cur().codepoint, 0, &glyph))
else if (!shortest && c->font->get_glyph (buffer->cur().codepoint, 0, &glyph))
next_char (buffer, glyph);
else if ((len = decompose_compatibility (font, buffer, buffer->cur().codepoint)))
else if ((len = decompose_compatibility (c, buffer->cur().codepoint)))
skip_char (buffer);
else
next_char (buffer, glyph); /* glyph is initialized in earlier branches. */
@ -374,49 +219,51 @@ decompose_current_character (hb_font_t *font, hb_buffer_t *buffer, bool shortest
}
static inline void
handle_variation_selector_cluster (hb_font_t *font, hb_buffer_t *buffer, unsigned int end)
handle_variation_selector_cluster (const hb_ot_shape_normalize_context_t *c, unsigned int end)
{
hb_buffer_t * const buffer = c->buffer;
for (; buffer->idx < end - 1;) {
if (unlikely (buffer->unicode->is_variation_selector (buffer->cur(+1).codepoint))) {
/* The next two lines are some ugly lines... But work. */
font->get_glyph (buffer->cur().codepoint, buffer->cur(+1).codepoint, &buffer->cur().glyph_index());
c->font->get_glyph (buffer->cur().codepoint, buffer->cur(+1).codepoint, &buffer->cur().glyph_index());
buffer->replace_glyphs (2, 1, &buffer->cur().codepoint);
} else {
set_glyph (buffer->cur(), font);
set_glyph (buffer->cur(), c->font);
buffer->next_glyph ();
}
}
if (likely (buffer->idx < end)) {
set_glyph (buffer->cur(), font);
set_glyph (buffer->cur(), c->font);
buffer->next_glyph ();
}
}
/* Returns true if recomposition may be benefitial. */
static inline bool
decompose_multi_char_cluster (hb_font_t *font, hb_buffer_t *buffer, unsigned int end)
decompose_multi_char_cluster (const hb_ot_shape_normalize_context_t *c, unsigned int end)
{
hb_buffer_t * const buffer = c->buffer;
/* TODO Currently if there's a variation-selector we give-up, it's just too hard. */
for (unsigned int i = buffer->idx; i < end; i++)
if (unlikely (buffer->unicode->is_variation_selector (buffer->info[i].codepoint))) {
handle_variation_selector_cluster (font, buffer, end);
handle_variation_selector_cluster (c, end);
return false;
}
while (buffer->idx < end)
decompose_current_character (font, buffer, false);
decompose_current_character (c, false);
/* We can be smarter here and only return true if there are at least two ccc!=0 marks.
* But does not matter. */
return true;
}
static inline bool
decompose_cluster (hb_font_t *font, hb_buffer_t *buffer, bool short_circuit, unsigned int end)
decompose_cluster (const hb_ot_shape_normalize_context_t *c, bool short_circuit, unsigned int end)
{
if (likely (buffer->idx + 1 == end))
return decompose_current_character (font, buffer, short_circuit);
if (likely (c->buffer->idx + 1 == end))
return decompose_current_character (c, short_circuit);
else
return decompose_multi_char_cluster (font, buffer, end);
return decompose_multi_char_cluster (c, end);
}
@ -431,9 +278,22 @@ compare_combining_class (const hb_glyph_info_t *pa, const hb_glyph_info_t *pb)
void
_hb_ot_shape_normalize (hb_font_t *font, hb_buffer_t *buffer,
hb_ot_shape_normalization_mode_t mode)
_hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan,
hb_buffer_t *buffer,
hb_font_t *font)
{
hb_ot_shape_normalization_mode_t mode = plan->shaper->normalization_preference ?
plan->shaper->normalization_preference (&buffer->props) :
HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT;
const hb_ot_shape_normalize_context_t c = {
plan,
buffer,
font,
buffer->unicode,
plan->shaper->decompose ? plan->shaper->decompose : decompose_unicode,
plan->shaper->compose ? plan->shaper->compose : compose_unicode
};
bool short_circuit = mode != HB_OT_SHAPE_NORMALIZATION_MODE_DECOMPOSED &&
mode != HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT;
bool can_use_recompose = false;
@ -457,7 +317,7 @@ _hb_ot_shape_normalize (hb_font_t *font, hb_buffer_t *buffer,
if (buffer->cur().cluster != buffer->info[end].cluster)
break;
can_use_recompose = decompose_cluster (font, buffer, short_circuit, end) || can_use_recompose;
can_use_recompose = decompose_cluster (&c, short_circuit, end) || can_use_recompose;
}
buffer->swap_buffers ();
@ -517,10 +377,10 @@ _hb_ot_shape_normalize (hb_font_t *font, hb_buffer_t *buffer,
(starter == buffer->out_len - 1 ||
_hb_glyph_info_get_modified_combining_class (&buffer->prev()) < _hb_glyph_info_get_modified_combining_class (&buffer->cur())) &&
/* And compose. */
compose_func (buffer->unicode,
buffer->out_info[starter].codepoint,
buffer->cur().codepoint,
&composed) &&
c.compose (&c,
buffer->out_info[starter].codepoint,
buffer->cur().codepoint,
&composed) &&
/* And the font has glyph for the composite. */
font->get_glyph (composed, 0, &glyph))
{

View File

@ -46,7 +46,16 @@ struct hb_ot_shape_plan_t
hb_ot_map_t map;
const void *data;
inline void substitute_closure (hb_face_t *face, hb_set_t *glyphs) const { map.substitute_closure (this, face, glyphs); }
inline void collect_lookups (hb_tag_t table_tag, hb_set_t *lookups) const
{
unsigned int table_index;
switch (table_tag) {
case HB_OT_TAG_GSUB: table_index = 0; break;
case HB_OT_TAG_GPOS: table_index = 1; break;
default: return;
}
map.collect_lookups (table_index, lookups);
}
inline void substitute (hb_font_t *font, hb_buffer_t *buffer) const { map.substitute (this, font, buffer); }
inline void position (hb_font_t *font, hb_buffer_t *buffer) const { map.position (this, font, buffer); }
@ -65,14 +74,14 @@ struct hb_ot_shape_planner_t
face (master_plan->face),
props (master_plan->props),
shaper (NULL),
map () {}
map (face, &props) {}
~hb_ot_shape_planner_t (void) { map.finish (); }
inline void compile (hb_ot_shape_plan_t &plan)
{
plan.props = props;
plan.shaper = shaper;
map.compile (face, &props, plan.map);
map.compile (plan.map);
}
private:
@ -85,7 +94,7 @@ inline void
_hb_glyph_info_set_unicode_props (hb_glyph_info_t *info, hb_unicode_funcs_t *unicode)
{
info->unicode_props0() = ((unsigned int) unicode->general_category (info->codepoint)) |
(unicode->is_zero_width (info->codepoint) ? 0x80 : 0);
(unicode->is_default_ignorable (info->codepoint) ? 0x80 : 0);
info->unicode_props1() = unicode->modified_combining_class (info->codepoint);
}
@ -108,7 +117,7 @@ _hb_glyph_info_get_modified_combining_class (const hb_glyph_info_t *info)
}
inline hb_bool_t
_hb_glyph_info_is_zero_width (const hb_glyph_info_t *info)
_hb_glyph_info_is_default_ignorable (const hb_glyph_info_t *info)
{
return !!(info->unicode_props0() & 0x80);
}

View File

@ -175,7 +175,7 @@ _hb_ot_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan,
hb_ot_shape_planner_t planner (shape_plan);
planner.shaper = hb_ot_shape_complex_categorize (&shape_plan->props);
planner.shaper = hb_ot_shape_complex_categorize (&planner);
hb_ot_shape_collect_features (&planner, &shape_plan->props, user_features, num_user_features);
@ -237,7 +237,7 @@ hb_set_unicode_props (hb_buffer_t *buffer)
static void
hb_insert_dotted_circle (hb_buffer_t *buffer, hb_font_t *font)
{
if (buffer->context_len[0] ||
if (!(buffer->flags & HB_BUFFER_FLAG_BOT) ||
_hb_glyph_info_get_general_category (&buffer->info[0]) !=
HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
return;
@ -362,10 +362,7 @@ hb_ot_substitute_default (hb_ot_shape_context_t *c)
HB_BUFFER_ALLOCATE_VAR (c->buffer, glyph_index);
_hb_ot_shape_normalize (c->font, c->buffer,
c->plan->shaper->normalization_preference ?
c->plan->shaper->normalization_preference (c->plan) :
HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT);
_hb_ot_shape_normalize (c->plan, c->buffer, c->font);
hb_ot_shape_setup_masks (c);
@ -454,12 +451,6 @@ hb_ot_position_complex (hb_ot_shape_context_t *c)
return ret;
}
static inline void
hb_ot_position_complex_fallback (hb_ot_shape_context_t *c)
{
_hb_ot_shape_fallback_position (c->plan, c->font, c->buffer);
}
static inline void
hb_ot_truetype_kern (hb_ot_shape_context_t *c)
{
@ -485,12 +476,6 @@ hb_ot_truetype_kern (hb_ot_shape_context_t *c)
}
}
static inline void
hb_position_complex_fallback_visual (hb_ot_shape_context_t *c)
{
hb_ot_truetype_kern (c);
}
static inline void
hb_ot_position (hb_ot_shape_context_t *c)
{
@ -498,28 +483,33 @@ hb_ot_position (hb_ot_shape_context_t *c)
hb_bool_t fallback = !hb_ot_position_complex (c);
if (fallback)
hb_ot_position_complex_fallback (c);
if (fallback && c->plan->shaper->fallback_position)
_hb_ot_shape_fallback_position (c->plan, c->font, c->buffer);
if (HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction))
hb_buffer_reverse (c->buffer);
/* Visual fallback goes here. */
if (fallback)
hb_position_complex_fallback_visual (c);
hb_ot_truetype_kern (c);
}
/* Post-process */
static void
hb_ot_hide_zerowidth (hb_ot_shape_context_t *c)
hb_ot_hide_default_ignorables (hb_ot_shape_context_t *c)
{
if (c->buffer->flags & HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES)
return;
hb_codepoint_t space = 0;
unsigned int count = c->buffer->len;
for (unsigned int i = 0; i < count; i++)
if (unlikely (!is_a_ligature (c->buffer->info[i]) &&
_hb_glyph_info_is_zero_width (&c->buffer->info[i])))
_hb_glyph_info_is_default_ignorable (&c->buffer->info[i])))
{
if (!space) {
/* We assume that the space glyph is not gid0. */
@ -557,7 +547,7 @@ hb_ot_shape_internal (hb_ot_shape_context_t *c)
hb_ot_substitute (c);
hb_ot_position (c);
hb_ot_hide_zerowidth (c);
hb_ot_hide_default_ignorables (c);
HB_BUFFER_DEALLOCATE_VAR (c->buffer, unicode_props1);
HB_BUFFER_DEALLOCATE_VAR (c->buffer, unicode_props0);
@ -582,16 +572,35 @@ _hb_ot_shape (hb_shape_plan_t *shape_plan,
}
static inline void
hb_ot_map_glyphs_dumb (hb_font_t *font,
hb_buffer_t *buffer)
void
hb_ot_shape_plan_collect_lookups (hb_shape_plan_t *shape_plan,
hb_tag_t table_tag,
hb_set_t *lookup_indexes /* OUT */)
{
unsigned int count = buffer->len;
for (unsigned int i = 0; i < count; i++)
font->get_glyph (buffer->info[i].codepoint, 0, &buffer->info[i].codepoint);
HB_SHAPER_DATA_GET (shape_plan)->collect_lookups (table_tag, lookup_indexes);
}
/* TODO Move this to hb-ot-shape-normalize, make it do decompose, and make it public. */
static void
add_char (hb_font_t *font,
hb_unicode_funcs_t *unicode,
hb_bool_t mirror,
hb_codepoint_t u,
hb_set_t *glyphs)
{
hb_codepoint_t glyph;
if (font->get_glyph (u, 0, &glyph))
glyphs->add (glyph);
if (mirror)
{
hb_codepoint_t m = unicode->mirroring (u);
if (m != u && font->get_glyph (m, 0, &glyph))
glyphs->add (glyph);
}
}
void
hb_ot_shape_glyphs_closure (hb_font_t *font,
hb_buffer_t *buffer,
@ -601,29 +610,30 @@ hb_ot_shape_glyphs_closure (hb_font_t *font,
{
hb_ot_shape_plan_t plan;
buffer->guess_properties ();
buffer->guess_segment_properties ();
/* TODO cache / ensure correct backend, etc. */
hb_shape_plan_t *shape_plan = hb_shape_plan_create (font->face, &buffer->props, features, num_features, NULL);
const char *shapers[] = {"ot", NULL};
hb_shape_plan_t *shape_plan = hb_shape_plan_create_cached (font->face, &buffer->props,
features, num_features, shapers);
/* TODO: normalization? have shapers do closure()? */
/* TODO: Deal with mirrored chars? */
hb_ot_map_glyphs_dumb (font, buffer);
bool mirror = hb_script_get_horizontal_direction (buffer->props.script) == HB_DIRECTION_RTL;
/* Seed it. It's user's responsibility to have cleard glyphs
* if that's what they desire. */
unsigned int count = buffer->len;
for (unsigned int i = 0; i < count; i++)
glyphs->add (buffer->info[i].codepoint);
add_char (font, buffer->unicode, mirror, buffer->info[i].codepoint, glyphs);
hb_set_t lookups;
lookups.init ();
hb_ot_shape_plan_collect_lookups (shape_plan, HB_OT_TAG_GSUB, &lookups);
/* And find transitive closure. */
hb_set_t copy;
copy.init ();
do {
copy.set (glyphs);
HB_SHAPER_DATA_GET (shape_plan)->substitute_closure (font->face, glyphs);
} while (!copy.equal (glyphs));
for (hb_codepoint_t lookup_index = -1; hb_set_next (&lookups, &lookup_index);)
hb_ot_layout_lookup_substitute_closure (font->face, lookup_index, glyphs);
} while (!copy.is_equal (glyphs));
hb_shape_plan_destroy (shape_plan);
}

View File

@ -38,6 +38,8 @@
static hb_tag_t
hb_ot_old_tag_from_script (hb_script_t script)
{
/* This seems to be accurate as of end of 2012. */
switch ((hb_tag_t) script) {
case HB_SCRIPT_INVALID: return HB_OT_TAG_DEFAULT_SCRIPT;
@ -91,6 +93,7 @@ hb_ot_new_tag_from_script (hb_script_t script)
case HB_SCRIPT_ORIYA: return HB_TAG('o','r','y','2');
case HB_SCRIPT_TAMIL: return HB_TAG('t','m','l','2');
case HB_SCRIPT_TELUGU: return HB_TAG('t','e','l','2');
case HB_SCRIPT_MYANMAR: return HB_TAG('m','y','m','2');
}
return HB_OT_TAG_DEFAULT_SCRIPT;
@ -109,6 +112,7 @@ hb_ot_new_tag_to_script (hb_tag_t tag)
case HB_TAG('o','r','y','2'): return HB_SCRIPT_ORIYA;
case HB_TAG('t','m','l','2'): return HB_SCRIPT_TAMIL;
case HB_TAG('t','e','l','2'): return HB_SCRIPT_TELUGU;
case HB_TAG('m','y','m','2'): return HB_SCRIPT_MYANMAR;
}
return HB_SCRIPT_UNKNOWN;

View File

@ -35,6 +35,7 @@
HB_BEGIN_DECLS
/* TODO remove */
void
hb_ot_shape_glyphs_closure (hb_font_t *font,
hb_buffer_t *buffer,

View File

@ -98,7 +98,7 @@ struct hb_set_digest_lowest_bits_t
private:
mask_t mask_for (hb_codepoint_t g) const { return ((mask_t) 1) << (g & (sizeof (mask_t) * 8 - 1)); }
static inline mask_t mask_for (hb_codepoint_t g) { return ((mask_t) 1) << (g & (sizeof (mask_t) * 8 - 1)); }
mask_t mask;
};
@ -147,7 +147,7 @@ struct hb_set_t
inline void clear (void) {
memset (elts, 0, sizeof elts);
}
inline bool empty (void) const {
inline bool is_empty (void) const {
for (unsigned int i = 0; i < ARRAY_LENGTH (elts); i++)
if (elts[i])
return false;
@ -161,6 +161,7 @@ struct hb_set_t
}
inline void add_range (hb_codepoint_t a, hb_codepoint_t b)
{
/* TODO Speedup */
for (unsigned int i = a; i < b + 1; i++)
add (i);
}
@ -169,6 +170,12 @@ struct hb_set_t
if (unlikely (g > MAX_G)) return;
elt (g) &= ~mask (g);
}
inline void del_range (hb_codepoint_t a, hb_codepoint_t b)
{
/* TODO Speedup */
for (unsigned int i = a; i < b + 1; i++)
del (i);
}
inline bool has (hb_codepoint_t g) const
{
if (unlikely (g > MAX_G)) return false;
@ -185,7 +192,7 @@ struct hb_set_t
return true;
return false;
}
inline bool equal (const hb_set_t *other) const
inline bool is_equal (const hb_set_t *other) const
{
for (unsigned int i = 0; i < ELTS; i++)
if (elts[i] != other->elts[i])
@ -217,7 +224,7 @@ struct hb_set_t
for (unsigned int i = 0; i < ELTS; i++)
elts[i] ^= other->elts[i];
}
inline bool next (hb_codepoint_t *codepoint)
inline bool next (hb_codepoint_t *codepoint) const
{
if (unlikely (*codepoint == SENTINEL)) {
hb_codepoint_t i = get_min ();
@ -234,6 +241,28 @@ struct hb_set_t
}
return false;
}
inline bool next_range (hb_codepoint_t *first, hb_codepoint_t *last) const
{
hb_codepoint_t i;
i = *last;
if (!next (&i))
return false;
*last = *first = i;
while (next (&i) && i == *last + 1)
(*last)++;
return true;
}
inline unsigned int get_population (void) const
{
unsigned int count = 0;
for (unsigned int i = 0; i < ELTS; i++)
count += _hb_popcount32 (elts[i]);
return count;
}
inline hb_codepoint_t get_min (void) const
{
for (unsigned int i = 0; i < ELTS; i++)

View File

@ -32,7 +32,7 @@
hb_set_t *
hb_set_create ()
hb_set_create (void)
{
hb_set_t *set;
@ -73,25 +73,25 @@ hb_set_destroy (hb_set_t *set)
}
hb_bool_t
hb_set_set_user_data (hb_set_t *set,
hb_user_data_key_t *key,
void * data,
hb_destroy_func_t destroy,
hb_bool_t replace)
hb_set_set_user_data (hb_set_t *set,
hb_user_data_key_t *key,
void * data,
hb_destroy_func_t destroy,
hb_bool_t replace)
{
return hb_object_set_user_data (set, key, data, destroy, replace);
}
void *
hb_set_get_user_data (hb_set_t *set,
hb_user_data_key_t *key)
hb_set_get_user_data (hb_set_t *set,
hb_user_data_key_t *key)
{
return hb_object_get_user_data (set, key);
}
hb_bool_t
hb_set_allocation_successful (hb_set_t *set HB_UNUSED)
hb_set_allocation_successful (const hb_set_t *set HB_UNUSED)
{
return true;
}
@ -103,13 +103,13 @@ hb_set_clear (hb_set_t *set)
}
hb_bool_t
hb_set_empty (hb_set_t *set)
hb_set_is_empty (const hb_set_t *set)
{
return set->empty ();
return set->is_empty ();
}
hb_bool_t
hb_set_has (hb_set_t *set,
hb_set_has (const hb_set_t *set,
hb_codepoint_t codepoint)
{
return set->has (codepoint);
@ -122,6 +122,14 @@ hb_set_add (hb_set_t *set,
set->add (codepoint);
}
void
hb_set_add_range (hb_set_t *set,
hb_codepoint_t first,
hb_codepoint_t last)
{
set->add_range (first, last);
}
void
hb_set_del (hb_set_t *set,
hb_codepoint_t codepoint)
@ -129,63 +137,85 @@ hb_set_del (hb_set_t *set,
set->del (codepoint);
}
hb_bool_t
hb_set_equal (hb_set_t *set,
hb_set_t *other)
void
hb_set_del_range (hb_set_t *set,
hb_codepoint_t first,
hb_codepoint_t last)
{
return set->equal (other);
set->del_range (first, last);
}
hb_bool_t
hb_set_is_equal (const hb_set_t *set,
const hb_set_t *other)
{
return set->is_equal (other);
}
void
hb_set_set (hb_set_t *set,
hb_set_t *other)
hb_set_set (hb_set_t *set,
const hb_set_t *other)
{
set->set (other);
}
void
hb_set_union (hb_set_t *set,
hb_set_t *other)
hb_set_union (hb_set_t *set,
const hb_set_t *other)
{
set->union_ (other);
}
void
hb_set_intersect (hb_set_t *set,
hb_set_t *other)
hb_set_intersect (hb_set_t *set,
const hb_set_t *other)
{
set->intersect (other);
}
void
hb_set_subtract (hb_set_t *set,
hb_set_t *other)
hb_set_subtract (hb_set_t *set,
const hb_set_t *other)
{
set->subtract (other);
}
void
hb_set_symmetric_difference (hb_set_t *set,
hb_set_t *other)
hb_set_symmetric_difference (hb_set_t *set,
const hb_set_t *other)
{
set->symmetric_difference (other);
}
unsigned int
hb_set_population (const hb_set_t *set)
{
return set->get_population ();
}
hb_codepoint_t
hb_set_min (hb_set_t *set)
hb_set_get_min (const hb_set_t *set)
{
return set->get_min ();
}
hb_codepoint_t
hb_set_max (hb_set_t *set)
hb_set_get_max (const hb_set_t *set)
{
return set->get_max ();
}
hb_bool_t
hb_set_next (hb_set_t *set,
hb_set_next (const hb_set_t *set,
hb_codepoint_t *codepoint)
{
return set->next (codepoint);
}
hb_bool_t
hb_set_next_range (const hb_set_t *set,
hb_codepoint_t *first,
hb_codepoint_t *last)
{
return set->next_range (first, last);
}

View File

@ -65,16 +65,16 @@ hb_set_get_user_data (hb_set_t *set,
/* Returns false if allocation has failed before */
hb_bool_t
hb_set_allocation_successful (hb_set_t *set);
hb_set_allocation_successful (const hb_set_t *set);
void
hb_set_clear (hb_set_t *set);
hb_bool_t
hb_set_empty (hb_set_t *set);
hb_set_is_empty (const hb_set_t *set);
hb_bool_t
hb_set_has (hb_set_t *set,
hb_set_has (const hb_set_t *set,
hb_codepoint_t codepoint);
/* Right now limited to 16-bit integers. Eventually will do full codepoint range, sans -1
@ -83,48 +83,65 @@ void
hb_set_add (hb_set_t *set,
hb_codepoint_t codepoint);
void
hb_set_add_range (hb_set_t *set,
hb_codepoint_t first,
hb_codepoint_t last);
void
hb_set_del (hb_set_t *set,
hb_codepoint_t codepoint);
void
hb_set_del_range (hb_set_t *set,
hb_codepoint_t first,
hb_codepoint_t last);
hb_bool_t
hb_set_equal (hb_set_t *set,
hb_set_t *other);
hb_set_is_equal (const hb_set_t *set,
const hb_set_t *other);
void
hb_set_set (hb_set_t *set,
hb_set_t *other);
hb_set_set (hb_set_t *set,
const hb_set_t *other);
void
hb_set_union (hb_set_t *set,
hb_set_t *other);
hb_set_union (hb_set_t *set,
const hb_set_t *other);
void
hb_set_intersect (hb_set_t *set,
hb_set_t *other);
hb_set_intersect (hb_set_t *set,
const hb_set_t *other);
void
hb_set_subtract (hb_set_t *set,
hb_set_t *other);
hb_set_subtract (hb_set_t *set,
const hb_set_t *other);
void
hb_set_symmetric_difference (hb_set_t *set,
hb_set_t *other);
hb_set_symmetric_difference (hb_set_t *set,
const hb_set_t *other);
unsigned int
hb_set_population (const hb_set_t *set);
/* Returns -1 if set empty. */
hb_codepoint_t
hb_set_min (hb_set_t *set);
hb_set_get_min (const hb_set_t *set);
/* Returns -1 if set empty. */
hb_codepoint_t
hb_set_max (hb_set_t *set);
hb_set_get_max (const hb_set_t *set);
/* Pass -1 in to get started. */
hb_bool_t
hb_set_next (hb_set_t *set,
hb_set_next (const hb_set_t *set,
hb_codepoint_t *codepoint);
/* TODO: Add faster iteration API? */
/* Pass -1 for first and last to get started. */
hb_bool_t
hb_set_next_range (const hb_set_t *set,
hb_codepoint_t *first,
hb_codepoint_t *last);
HB_END_DECLS

View File

@ -28,9 +28,8 @@
#define HB_SHAPE_PLAN_PRIVATE_HH
#include "hb-private.hh"
#include "hb-shape-plan.h"
#include "hb-object-private.hh"
#include "hb-shaper-private.hh"

View File

@ -24,8 +24,6 @@
* Google Author(s): Behdad Esfahbod
*/
#include "hb-private.hh"
#include "hb-shape-plan-private.hh"
#include "hb-shaper-private.hh"
#include "hb-font-private.hh"
@ -119,7 +117,7 @@ hb_shape_plan_get_empty (void)
true, /* default_shaper_list */
NULL, /* face */
_HB_BUFFER_PROPS_DEFAULT, /* props */
HB_SEGMENT_PROPERTIES_DEFAULT, /* props */
NULL, /* shaper_func */
@ -153,9 +151,26 @@ hb_shape_plan_destroy (hb_shape_plan_t *shape_plan)
free (shape_plan);
}
hb_bool_t
hb_shape_plan_set_user_data (hb_shape_plan_t *shape_plan,
hb_user_data_key_t *key,
void * data,
hb_destroy_func_t destroy,
hb_bool_t replace)
{
return hb_object_set_user_data (shape_plan, key, data, destroy, replace);
}
void *
hb_shape_plan_get_user_data (hb_shape_plan_t *shape_plan,
hb_user_data_key_t *key)
{
return hb_object_get_user_data (shape_plan, key);
}
hb_bool_t
hb_shape_plan_execute (hb_shape_plan *shape_plan,
hb_shape_plan_execute (hb_shape_plan_t *shape_plan,
hb_font_t *font,
hb_buffer_t *buffer,
const hb_feature_t *features,

View File

@ -24,52 +24,68 @@
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_H_IN
#error "Include <hb.h> instead."
#endif
#ifndef HB_SHAPE_PLAN_H
#define HB_SHAPE_PLAN_H
/* TODO To become public one day */
#include "hb-common.h"
#include "hb-font.h"
#include "hb-private.hh"
HB_BEGIN_DECLS
#include "hb-buffer-private.hh"
typedef struct hb_shape_plan_t hb_shape_plan_t;
typedef struct hb_shape_plan_t hb_shape_plan;
/*
* hb_shape_plan_t
*/
HB_INTERNAL hb_shape_plan_t *
hb_shape_plan_t *
hb_shape_plan_create (hb_face_t *face,
const hb_segment_properties_t *props,
const hb_feature_t *user_features,
unsigned int num_user_features,
const char * const *shaper_list);
HB_INTERNAL hb_shape_plan_t *
hb_shape_plan_t *
hb_shape_plan_create_cached (hb_face_t *face,
const hb_segment_properties_t *props,
const hb_feature_t *user_features,
unsigned int num_user_features,
const char * const *shaper_list);
HB_INTERNAL hb_shape_plan_t *
hb_shape_plan_t *
hb_shape_plan_get_empty (void);
HB_INTERNAL hb_shape_plan_t *
hb_shape_plan_t *
hb_shape_plan_reference (hb_shape_plan_t *shape_plan);
HB_INTERNAL void
void
hb_shape_plan_destroy (hb_shape_plan_t *shape_plan);
hb_bool_t
hb_shape_plan_set_user_data (hb_shape_plan_t *shape_plan,
hb_user_data_key_t *key,
void * data,
hb_destroy_func_t destroy,
hb_bool_t replace);
HB_INTERNAL hb_bool_t
hb_shape_plan_execute (hb_shape_plan *shape_plan,
void *
hb_shape_plan_get_user_data (hb_shape_plan_t *shape_plan,
hb_user_data_key_t *key);
hb_bool_t
hb_shape_plan_execute (hb_shape_plan_t *shape_plan,
hb_font_t *font,
hb_buffer_t *buffer,
const hb_feature_t *features,
unsigned int num_features);
#ifdef HB_NOT_IMPLEMENTED
const char *
Xhb_shape_plan_get_shaper (hb_shape_plan_t *shape_plan);
#endif
HB_END_DECLS
#endif /* HB_SHAPE_PLAN_H */

View File

@ -176,7 +176,7 @@ hb_feature_to_string (hb_feature_t *feature,
len += 4;
while (len && s[len - 1] == ' ')
len--;
if (feature->start != 0 || feature->start != (unsigned int) -1)
if (feature->start != 0 || feature->end != (unsigned int) -1)
{
s[len++] = '[';
if (feature->start)
@ -255,7 +255,7 @@ hb_shape_full (hb_font_t *font,
assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE);
buffer->guess_properties ();
buffer->guess_segment_properties ();
hb_shape_plan_t *shape_plan = hb_shape_plan_create_cached (font->face, &buffer->props, features, num_features, shaper_list);
hb_bool_t res = hb_shape_plan_execute (shape_plan, font, buffer, features, num_features);

View File

@ -29,15 +29,11 @@
#endif /* HB_SHAPER_LIST_HH */ /* Dummy header guards */
/* v--- Add new shapers in the right place here. */
#ifdef HAVE_GRAPHITE2
/* Only picks up fonts that have a "Silf" table. */
HB_SHAPER_IMPLEMENT (graphite2)
#endif
#ifdef HAVE_UNISCRIBE
HB_SHAPER_IMPLEMENT (uniscribe)
#endif
#ifdef HAVE_CORETEXT
HB_SHAPER_IMPLEMENT (coretext)
#endif
#ifdef HAVE_OT
HB_SHAPER_IMPLEMENT (ot) /* <--- This is our main OpenType shaper. */
@ -46,9 +42,14 @@ HB_SHAPER_IMPLEMENT (ot) /* <--- This is our main OpenType shaper. */
#ifdef HAVE_HB_OLD
HB_SHAPER_IMPLEMENT (old)
#endif
#ifdef HAVE_ICU_LE
HB_SHAPER_IMPLEMENT (icu_le)
#endif
#ifdef HAVE_UNISCRIBE
HB_SHAPER_IMPLEMENT (uniscribe)
#endif
#ifdef HAVE_CORETEXT
HB_SHAPER_IMPLEMENT (coretext)
#endif
HB_SHAPER_IMPLEMENT (fallback) /* <--- This should be last. */

View File

@ -29,8 +29,6 @@
#include "hb-private.hh"
#include "hb-shape-plan.h" /* TODO remove */
typedef hb_bool_t hb_shape_func_t (hb_shape_plan_t *shape_plan,
hb_font_t *font,
hb_buffer_t *buffer,

View File

@ -25,8 +25,8 @@
*/
#include "hb-private.hh"
#include "hb-shaper-private.hh"
#include "hb-atomic-private.hh"
static const hb_shaper_pair_t all_shapers[] = {

View File

@ -119,47 +119,73 @@ HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE
0xE0100, 0xE01EF)); /* VARIATION SELECTOR-17..256 */
}
/* Zero-Width invisible characters:
/* Default_Ignorable codepoints:
*
* 00AD SOFT HYPHEN
* 034F COMBINING GRAPHEME JOINER
* Note that as of Oct 2012 (Unicode 6.2), U+180E MONGOLIAN VOWEL SEPARATOR
* is NOT Default_Ignorable, but it really behaves in a way that it should
* be. That has been reported to the Unicode Technical Committee for
* consideration. As such, we include it here, since Uniscribe removes it.
*
* 180E MONGOLIAN VOWEL SEPARATOR
* Gathered from:
* http://unicode.org/cldr/utility/list-unicodeset.jsp?a=[:DI:]&abb=on&ucd=on&esc=on
*
* 200B ZERO WIDTH SPACE
* 200C ZERO WIDTH NON-JOINER
* 200D ZERO WIDTH JOINER
* 200E LEFT-TO-RIGHT MARK
* 200F RIGHT-TO-LEFT MARK
* Last updated to the page with the following versions:
* Version 3.6; ICU version: 50.0.1.0; Unicode version: 6.1.0.0
*
* 2028 LINE SEPARATOR
* 4,167 Code Points
*
* 202A LEFT-TO-RIGHT EMBEDDING
* 202B RIGHT-TO-LEFT EMBEDDING
* 202C POP DIRECTIONAL FORMATTING
* 202D LEFT-TO-RIGHT OVERRIDE
* 202E RIGHT-TO-LEFT OVERRIDE
* [\u00AD\u034F\u115F\u1160\u17B4\u17B5\u180B-\u180D\u200B-\u200F\u202A-\u202E\u2060-\u206F\u3164\uFE00-\uFE0F\uFEFF\uFFA0\uFFF0-\uFFF8\U0001D173-\U0001D17A\U000E0000-\U000E0FFF]
*
* 2060 WORD JOINER
* 2061 FUNCTION APPLICATION
* 2062 INVISIBLE TIMES
* 2063 INVISIBLE SEPARATOR
*
* FEFF ZERO WIDTH NO-BREAK SPACE
* 00AD ;SOFT HYPHEN
* 034F ;COMBINING GRAPHEME JOINER
* 115F ;HANGUL CHOSEONG FILLER
* 1160 ;HANGUL JUNGSEONG FILLER
* 17B4 ;KHMER VOWEL INHERENT AQ
* 17B5 ;KHMER VOWEL INHERENT AA
* 180B..180D ;MONGOLIAN FREE VARIATION SELECTOR THREE
* 200B..200F ;RIGHT-TO-LEFT MARK
* 202A..202E ;RIGHT-TO-LEFT OVERRIDE
* 2060..206F ;NOMINAL DIGIT SHAPES
* 3164 ;HANGUL FILLER
* FE00..FE0F ;VARIATION SELECTOR-16
* FEFF ;ZERO WIDTH NO-BREAK SPACE
* FFA0 ;HALFWIDTH HANGUL FILLER
* FFF0..FFF8 ;<unassigned-FFF8>
* 1D173..1D17A ;MUSICAL SYMBOL END PHRASE
* E0000..E0FFF ;<unassigned-E0FFF>
*/
inline hb_bool_t
is_zero_width (hb_codepoint_t ch)
is_default_ignorable (hb_codepoint_t ch)
{
return ((ch & ~0x007F) == 0x2000 && (hb_in_ranges<hb_codepoint_t> (ch,
0x200B, 0x200F,
0x202A, 0x202E,
0x2060, 0x2064) ||
(ch == 0x2028))) ||
unlikely (ch == 0x0009 ||
ch == 0x00AD ||
ch == 0x034F ||
ch == 0x180E ||
ch == 0xFEFF);
hb_codepoint_t plane = ch >> 16;
if (likely (plane == 0))
{
/* BMP */
hb_codepoint_t page = ch >> 8;
switch (page) {
case 0x00: return unlikely (ch == 0x00AD);
case 0x03: return unlikely (ch == 0x034F);
case 0x11: return hb_in_range<hb_codepoint_t> (ch, 0x115F, 0x1160);
case 0x17: return hb_in_range<hb_codepoint_t> (ch, 0x17B4, 0x17B5);
case 0x18: return hb_in_range<hb_codepoint_t> (ch, 0x180B, 0x180E);
case 0x20: return hb_in_ranges<hb_codepoint_t> (ch, 0x200B, 0x200F,
0x202A, 0x202E,
0x2060, 0x206F);
case 0x31: return unlikely (ch == 0x3164);
case 0xFE: return hb_in_range<hb_codepoint_t> (ch, 0xFE00, 0xFE0F) || ch == 0xFEFF;
case 0xFF: return hb_in_range<hb_codepoint_t> (ch, 0xFFF0, 0xFFF8) || ch == 0xFFA0;
default: return false;
}
}
else
{
/* Other planes */
switch (plane) {
case 0x01: return hb_in_range<hb_codepoint_t> (ch, 0x0001D173, 0x0001D17A);
case 0x0E: return hb_in_range<hb_codepoint_t> (ch, 0x000E0000, 0x000E0FFF);
default: return false;
}
}
}

View File

@ -77,8 +77,8 @@ hb_utf_prev (const uint8_t *text,
const uint8_t *start,
hb_codepoint_t *unicode)
{
const uint8_t *end = text;
while (start < text && (*--text & 0xc0) == 0x80 && end - text < 4)
const uint8_t *end = text--;
while (start < text && (*text & 0xc0) == 0x80 && end - text < 4)
text--;
hb_codepoint_t c = *text, mask;

View File

@ -38,9 +38,9 @@ HB_BEGIN_DECLS
#define HB_VERSION_MAJOR 0
#define HB_VERSION_MINOR 9
#define HB_VERSION_MICRO 4
#define HB_VERSION_MICRO 6
#define HB_VERSION_STRING "0.9.4"
#define HB_VERSION_STRING "0.9.6"
#define HB_VERSION_CHECK(major,minor,micro) \
((major)*10000+(minor)*100+(micro) >= \

View File

@ -34,6 +34,7 @@
#include "hb-font.h"
#include "hb-set.h"
#include "hb-shape.h"
#include "hb-shape-plan.h"
#include "hb-unicode.h"
#include "hb-version.h"

View File

@ -99,5 +99,5 @@ main (int argc, char **argv)
(argc > 4 &&
!hb_font_glyph_from_string (font, argv[4], -1, &glyphs[1])))
return 2;
return !hb_ot_layout_would_substitute_lookup (face, strtol (argv[2], NULL, 0), glyphs, len, false);
return !hb_ot_layout_lookup_would_substitute (face, strtol (argv[2], NULL, 0), glyphs, len, false);
}