mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge mozilla-central to mozilla-inbound
This commit is contained in:
commit
89e976f545
@ -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 )
|
||||
|
||||
|
@ -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 \
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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); \
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -1343,6 +1343,7 @@ struct SubstLookup : Lookup
|
||||
else
|
||||
{
|
||||
/* in-place backward substitution */
|
||||
c->buffer->remove_output ();
|
||||
c->buffer->idx = c->buffer->len - 1;
|
||||
do
|
||||
{
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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 ();
|
||||
|
@ -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 */
|
||||
};
|
||||
|
225
gfx/harfbuzz/src/hb-ot-shape-complex-default.cc
Normal file
225
gfx/harfbuzz/src/hb-ot-shape-complex-default.cc
Normal 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
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
||||
/*
|
||||
|
@ -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 */
|
||||
};
|
||||
|
@ -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 */
|
||||
};
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
378
gfx/harfbuzz/src/hb-ot-shape-complex-thai.cc
Normal file
378
gfx/harfbuzz/src/hb-ot-shape-complex-thai.cc
Normal 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 */
|
||||
};
|
@ -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]))
|
||||
{
|
||||
|
@ -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 */
|
||||
|
@ -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))
|
||||
{
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -35,6 +35,7 @@
|
||||
|
||||
HB_BEGIN_DECLS
|
||||
|
||||
/* TODO remove */
|
||||
void
|
||||
hb_ot_shape_glyphs_closure (hb_font_t *font,
|
||||
hb_buffer_t *buffer,
|
||||
|
@ -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++)
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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. */
|
||||
|
@ -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,
|
||||
|
@ -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[] = {
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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) >= \
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user