bug 789687 - update harfbuzz to upstream commit fecdfa95daf4916695f23e7dab89ab363be11b89. r=jdaggett

This commit is contained in:
Jonathan Kew 2012-10-09 13:11:24 +01:00
parent 02be153e3c
commit 217dfe2093
57 changed files with 3901 additions and 1428 deletions

View File

@ -51,6 +51,7 @@ HBSOURCES = \
hb-tt-font.cc \
hb-unicode-private.hh \
hb-unicode.cc \
hb-utf-private.hh \
hb-warning.cc \
$(NULL)
HBHEADERS = \
@ -78,6 +79,7 @@ HBSOURCES += \
hb-ot-map-private.hh \
hb-ot-shape.cc \
hb-ot-shape-complex-arabic.cc \
hb-ot-shape-complex-arabic-fallback.hh \
hb-ot-shape-complex-arabic-table.hh \
hb-ot-shape-complex-indic.cc \
hb-ot-shape-complex-indic-machine.hh \
@ -98,6 +100,11 @@ HBHEADERS += \
$(NULL)
endif
if HAVE_PTHREAD
HBCFLAGS += $(PTHREAD_CFLAGS)
HBLIBS += $(PTHREAD_LIBS)
endif
if HAVE_GLIB
HBCFLAGS += $(GLIB_CFLAGS)
HBLIBS += $(GLIB_LIBS)
@ -163,6 +170,21 @@ HBSOURCES += hb-old.cc
endif
DIST_SUBDIRS += hb-old
if HAVE_ICU_LE
SUBDIRS += hb-icu-le
HBCFLAGS += -I$(srcdir)/hb-icu-le
HBLIBS += hb-icu-le/libhb-icu-le.la
HBSOURCES += hb-icu-le.cc
endif
DIST_SUBDIRS += hb-icu-le
if HAVE_UCDN
SUBDIRS += hb-ucdn
HBCFLAGS += -I$(srcdir)/hb-ucdn
HBLIBS += hb-ucdn/libhb-ucdn.la
HBSOURCES += hb-ucdn.cc
endif
DIST_SUBDIRS += hb-ucdn
# Put the library together
@ -170,16 +192,18 @@ DIST_SUBDIRS += hb-old
if OS_WIN32
export_symbols = -export-symbols harfbuzz.def
harfbuzz_def_dependency = harfbuzz.def
endif
libharfbuzz_la_LINK = $(CXXLINK) $(libharfbuzz_la_LDFLAGS)
else
# Use a C linker, not C++; Don't link to libstdc++
libharfbuzz_la_LINK = $(LINK) $(libharfbuzz_la_LDFLAGS)
endif
libharfbuzz_la_SOURCES = $(HBSOURCES) $(HBHEADERS)
nodist_libharfbuzz_la_SOURCES = $(nodist_HBSOURCES)
libharfbuzz_la_CPPFLAGS = $(HBCFLAGS)
libharfbuzz_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(HB_LIBTOOL_VERSION_INFO) $(export_symbols) -no-undefined
libharfbuzz_la_LIBADD = $(HBLIBS)
libharfbuzz_la_DEPENDENCIES = $(harfbuzz_def_dependency)
EXTRA_libharfbuzz_la_DEPENDENCIES = $(harfbuzz_def_dependency)
pkginclude_HEADERS = $(HBHEADERS)
nodist_pkginclude_HEADERS = hb-version.h
@ -217,23 +241,18 @@ arabic-table: gen-arabic-table.py ArabicShaping.txt UnicodeData.txt
.PHONY: unicode-tables arabic-table indic-table
BUILT_SOURCES += hb-ot-shape-complex-indic-machine.hh
EXTRA_DIST += hb-ot-shape-complex-indic-machine.rl
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 )
noinst_PROGRAMS = main indic test-would-substitute
noinst_PROGRAMS = main test-would-substitute
bin_PROGRAMS =
main_SOURCES = main.cc
main_CPPFLAGS = $(HBCFLAGS)
main_LDADD = libharfbuzz.la $(HBLIBS)
indic_SOURCES = indic.cc
indic_CPPFLAGS = $(HBCFLAGS)
indic_LDADD = libharfbuzz.la $(HBLIBS)
test_would_substitute_SOURCES = test-would-substitute.cc
test_would_substitute_CPPFLAGS = $(HBCFLAGS) $(FREETYPE_CFLAGS)
test_would_substitute_LDADD = libharfbuzz.la $(HBLIBS) $(FREETYPE_LIBS)
@ -244,7 +263,6 @@ dist_check_SCRIPTS = \
check-exported-symbols.sh \
check-includes.sh \
check-internal-symbols.sh \
check-static-inits.sh \
$(NULL)
if HAVE_ICU
@ -252,6 +270,11 @@ else
dist_check_SCRIPTS += check-libstdc++.sh
endif
if HAVE_ICU_LE
else
dist_check_SCRIPTS += check-static-inits.sh
endif
TESTS = $(dist_check_SCRIPTS)
TESTS_ENVIRONMENT = \
srcdir="$(srcdir)" \

View File

@ -27,7 +27,7 @@ for suffix in so dylib; do
fi
done
if ! $tested; then
echo "check-internal-symbols.sh: libharfbuzz shared library not found; skipping test"
echo "check-libstdc++.sh: libharfbuzz shared library not found; skipping test"
exit 77
fi

View File

@ -28,10 +28,10 @@ for obj in $OBJS; do
fi
done
echo "Checking that no object file has lazy static C++ constructors/destructors"
echo "Checking that no object file has lazy static C++ constructors/destructors or other such stuff"
for obj in $OBJS; do
if objdump -t "$obj" | grep '__c'; then
echo "Ouch, $obj has lazy static C++ constructors/destructors"
echo "Ouch, $obj has lazy static C++ constructors/destructors or other such stuff"
stat=1
fi
done

View File

@ -122,7 +122,7 @@ def print_shaping_table(f):
keys = shapes.keys ()
min_u, max_u = min (keys), max (keys)
for u in range (min_u, max_u + 1):
s = [shapes[u][shape] if u in shapes and shape in shapes[u] else u
s = [shapes[u][shape] if u in shapes and shape in shapes[u] else 0
for shape in ['initial', 'medial', 'final', 'isolated']]
value = ', '.join ("0x%04X" % c for c in s)
print " {%s}, /* U+%04X %s */" % (value, u, names[u] if u in names else "")
@ -148,9 +148,9 @@ def print_shaping_table(f):
ligas[liga[0]].append ((liga[1], c))
max_i = max (len (ligas[l]) for l in ligas)
print
print "static const struct {"
print "static const struct ligature_set_t {"
print " uint16_t first;"
print " struct {"
print " struct ligature_pairs_t {"
print " uint16_t second;"
print " uint16_t ligature;"
print " } ligatures[%d];" % max_i

View File

@ -42,17 +42,28 @@
#if 0
#elif !defined(HB_NO_MT) && defined(_MSC_VER) && _MSC_VER >= 1600
#elif !defined(HB_NO_MT) && defined(_MSC_VER) || defined(__MINGW32__)
#include <intrin.h>
/* On x86, _InterlockedCompareExchangePointer is a macro defined in concrt.h */
#include <concrt.h>
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
/* mingw32 does not have MemoryBarrier.
* MemoryBarrier may be defined as a macro or a function.
* Just make a failsafe version for ourselves. */
#ifdef MemoryBarrier
#define HBMemoryBarrier MemoryBarrier
#else
static inline void HBMemoryBarrier (void) {
long dummy = 0;
InterlockedExchange (&dummy, 1);
}
#endif
typedef long hb_atomic_int_t;
#define hb_atomic_int_add(AI, V) _InterlockedExchangeAdd (&(AI), (V))
#define hb_atomic_int_add(AI, V) InterlockedExchangeAdd (&(AI), (V))
#define hb_atomic_ptr_get(P) (MemoryBarrier (), (void *) *(P))
#define hb_atomic_ptr_cmpexch(P,O,N) (_InterlockedCompareExchangePointer ((void **) (P), (void *) (N), (void *) (O)) == (void *) (O))
#define hb_atomic_ptr_get(P) (HBMemoryBarrier (), (void *) *(P))
#define hb_atomic_ptr_cmpexch(P,O,N) (InterlockedCompareExchangePointer ((void **) (P), (void *) (N), (void *) (O)) == (void *) (O))
#elif !defined(HB_NO_MT) && defined(__APPLE__)
@ -74,19 +85,6 @@ typedef int hb_atomic_int_t;
#define hb_atomic_ptr_get(P) (void *) (__sync_synchronize (), *(P))
#define hb_atomic_ptr_cmpexch(P,O,N) __sync_bool_compare_and_swap ((P), (O), (N))
#elif !defined(HB_NO_MT) && defined(HAVE_GLIB)
#include <glib.h>
typedef int hb_atomic_int_t;
#if GLIB_CHECK_VERSION(2,29,5)
#define hb_atomic_int_add(AI, V) g_atomic_int_add (&(AI), (V))
#else
#define hb_atomic_int_add(AI, V) g_atomic_int_exchange_and_add (&(AI), (V))
#endif
#define hb_atomic_ptr_get(P) g_atomic_pointer_get (P)
#define hb_atomic_ptr_cmpexch(P,O,N) g_atomic_pointer_compare_and_exchange ((void **) (P), (void *) (O), (void *) (N))
#elif !defined(HB_NO_MT)

View File

@ -1,7 +1,7 @@
/*
* Copyright © 1998-2004 David Turner and Werner Lemberg
* Copyright © 2004,2007,2009,2010 Red Hat, Inc.
* Copyright © 2011 Google, Inc.
* Copyright © 2011,2012 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
@ -92,6 +92,8 @@ struct hb_buffer_t {
/* Buffer contents */
hb_buffer_content_type_t content_type;
bool in_error; /* Allocation failed */
bool have_output; /* Whether we have an output buffer going on */
bool have_positions; /* Whether we have positions */
@ -115,9 +117,18 @@ struct hb_buffer_t {
inline hb_glyph_info_t prev (void) const { return info[out_len - 1]; }
unsigned int serial;
/* These reflect current allocations of the bytes in glyph_info_t's var1 and var2. */
uint8_t allocated_var_bytes[8];
const char *allocated_var_owner[8];
/* Text before / after the main buffer contents.
* Always in Unicode, and ordered outward.
* Index 0 is for "pre-context", 1 for "post-context". */
static const unsigned int CONTEXT_LENGTH = 5;
hb_codepoint_t context[2][CONTEXT_LENGTH];
unsigned int context_len[2];
/* Methods */
@ -129,6 +140,7 @@ struct hb_buffer_t {
HB_INTERNAL void allocate_var (unsigned int byte_i, unsigned int count, const char *owner);
HB_INTERNAL void deallocate_var (unsigned int byte_i, unsigned int count, const char *owner);
HB_INTERNAL void assert_var (unsigned int byte_i, unsigned int count, const char *owner);
HB_INTERNAL void deallocate_var_all (void);
HB_INTERNAL void add (hb_codepoint_t codepoint,
@ -151,11 +163,26 @@ struct hb_buffer_t {
HB_INTERNAL void replace_glyph (hb_codepoint_t glyph_index);
/* Makes a copy of the glyph at idx to output and replace glyph_index */
HB_INTERNAL void output_glyph (hb_codepoint_t glyph_index);
HB_INTERNAL void output_info (hb_glyph_info_t &glyph_info);
/* Copies glyph at idx to output but doesn't advance idx */
HB_INTERNAL void copy_glyph (void);
/* Copies glyph at idx to output and advance idx.
* If there's no output, just advance idx. */
HB_INTERNAL void next_glyph (void);
inline void
next_glyph (void)
{
if (have_output)
{
if (unlikely (out_info != info || out_len != idx)) {
if (unlikely (!make_room_for (1, 1))) return;
out_info[out_len] = info[idx];
}
out_len++;
}
idx++;
}
/* Advance idx without copying to output. */
inline void skip_glyph (void) { idx++; }
@ -188,6 +215,8 @@ struct hb_buffer_t {
HB_INTERNAL bool make_room_for (unsigned int num_in, unsigned int num_out);
HB_INTERNAL void *get_scratch_buffer (unsigned int *size);
inline void clear_context (unsigned int side) { context_len[side] = 0; }
};
@ -198,6 +227,8 @@ struct hb_buffer_t {
HB_BUFFER_XALLOCATE_VAR (b, allocate_var, var (), #var)
#define HB_BUFFER_DEALLOCATE_VAR(b, var) \
HB_BUFFER_XALLOCATE_VAR (b, deallocate_var, var (), #var)
#define HB_BUFFER_ASSERT_VAR(b, var) \
HB_BUFFER_XALLOCATE_VAR (b, assert_var, var (), #var)
#endif /* HB_BUFFER_PRIVATE_HH */

View File

@ -1,7 +1,7 @@
/*
* Copyright © 1998-2004 David Turner and Werner Lemberg
* Copyright © 2004,2007,2009,2010 Red Hat, Inc.
* Copyright © 2011 Google, Inc.
* Copyright © 2011,2012 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
@ -28,9 +28,7 @@
*/
#include "hb-buffer-private.hh"
#include <string.h>
#include "hb-utf-private.hh"
#ifndef HB_DEBUG_BUFFER
@ -147,6 +145,7 @@ hb_buffer_t::reset (void)
hb_segment_properties_t default_props = _HB_BUFFER_PROPS_DEFAULT;
props = default_props;
content_type = HB_BUFFER_CONTENT_TYPE_INVALID;
in_error = false;
have_output = false;
have_positions = false;
@ -159,6 +158,9 @@ hb_buffer_t::reset (void)
serial = 0;
memset (allocated_var_bytes, 0, sizeof allocated_var_bytes);
memset (allocated_var_owner, 0, sizeof allocated_var_owner);
memset (context, 0, sizeof context);
memset (context_len, 0, sizeof context_len);
}
void
@ -267,6 +269,16 @@ hb_buffer_t::output_glyph (hb_codepoint_t glyph_index)
out_len++;
}
void
hb_buffer_t::output_info (hb_glyph_info_t &glyph_info)
{
if (unlikely (!make_room_for (0, 1))) return;
out_info[out_len] = glyph_info;
out_len++;
}
void
hb_buffer_t::copy_glyph (void)
{
@ -290,21 +302,6 @@ hb_buffer_t::replace_glyph (hb_codepoint_t glyph_index)
out_len++;
}
void
hb_buffer_t::next_glyph (void)
{
if (have_output)
{
if (unlikely (out_info != info || out_len != idx)) {
if (unlikely (!make_room_for (1, 1))) return;
out_info[out_len] = info[idx];
}
out_len++;
}
idx++;
}
void
hb_buffer_t::set_masks (hb_mask_t value,
@ -451,6 +448,9 @@ hb_buffer_t::merge_out_clusters (unsigned int start,
void
hb_buffer_t::guess_properties (void)
{
if (unlikely (!len)) return;
assert (content_type == HB_BUFFER_CONTENT_TYPE_UNICODE);
/* If script is set to INVALID, guess from buffer contents */
if (props.script == HB_SCRIPT_INVALID) {
for (unsigned int i = 0; i < len; i++) {
@ -523,6 +523,22 @@ void hb_buffer_t::deallocate_var (unsigned int byte_i, unsigned int count, const
}
}
void hb_buffer_t::assert_var (unsigned int byte_i, unsigned int count, const char *owner)
{
if (DEBUG (BUFFER))
dump_var_allocation (this);
DEBUG_MSG (BUFFER, this,
"Asserting var bytes %d..%d for %s",
byte_i, byte_i + count - 1, owner);
assert (byte_i < 8 && byte_i + count <= 8);
for (unsigned int i = byte_i; i < byte_i + count; i++) {
assert (allocated_var_bytes[i]);
assert (0 == strcmp (allocated_var_owner[i], owner));
}
}
void hb_buffer_t::deallocate_var_all (void)
{
memset (allocated_var_bytes, 0, sizeof (allocated_var_bytes));
@ -553,9 +569,12 @@ hb_buffer_get_empty (void)
const_cast<hb_unicode_funcs_t *> (&_hb_unicode_funcs_nil),
_HB_BUFFER_PROPS_DEFAULT,
HB_BUFFER_CONTENT_TYPE_INVALID,
true, /* in_error */
true, /* have_output */
true /* have_positions */
/* Zero is good enough for everything else. */
};
return const_cast<hb_buffer_t *> (&_hb_buffer_nil);
@ -598,6 +617,20 @@ hb_buffer_get_user_data (hb_buffer_t *buffer,
}
void
hb_buffer_set_content_type (hb_buffer_t *buffer,
hb_buffer_content_type_t content_type)
{
buffer->content_type = content_type;
}
hb_buffer_content_type_t
hb_buffer_get_content_type (hb_buffer_t *buffer)
{
return buffer->content_type;
}
void
hb_buffer_set_unicode_funcs (hb_buffer_t *buffer,
hb_unicode_funcs_t *unicode)
@ -695,6 +728,7 @@ hb_buffer_add (hb_buffer_t *buffer,
unsigned int cluster)
{
buffer->add (codepoint, mask, cluster);
buffer->clear_context (1);
}
hb_bool_t
@ -715,6 +749,11 @@ hb_buffer_set_length (hb_buffer_t *buffer,
}
buffer->len = length;
if (!length)
buffer->clear_context (0);
buffer->clear_context (1);
return true;
}
@ -767,68 +806,63 @@ hb_buffer_guess_properties (hb_buffer_t *buffer)
buffer->guess_properties ();
}
#define ADD_UTF(T) \
HB_STMT_START { \
if (text_length == -1) { \
text_length = 0; \
const T *p = (const T *) text; \
while (*p) { \
text_length++; \
p++; \
} \
} \
if (item_length == -1) \
item_length = text_length - item_offset; \
buffer->ensure (buffer->len + item_length * sizeof (T) / 4); \
const T *next = (const T *) text + item_offset; \
const T *end = next + item_length; \
while (next < end) { \
hb_codepoint_t u; \
const T *old_next = next; \
next = UTF_NEXT (next, end, u); \
hb_buffer_add (buffer, u, 1, old_next - (const T *) text); \
} \
} HB_STMT_END
#define UTF8_COMPUTE(Char, Mask, Len) \
if (Char < 128) { Len = 1; Mask = 0x7f; } \
else if ((Char & 0xe0) == 0xc0) { Len = 2; Mask = 0x1f; } \
else if ((Char & 0xf0) == 0xe0) { Len = 3; Mask = 0x0f; } \
else if ((Char & 0xf8) == 0xf0) { Len = 4; Mask = 0x07; } \
else Len = 0;
static inline const uint8_t *
hb_utf8_next (const uint8_t *text,
const uint8_t *end,
hb_codepoint_t *unicode)
template <typename T>
static inline void
hb_buffer_add_utf (hb_buffer_t *buffer,
const T *text,
int text_length,
unsigned int item_offset,
int item_length)
{
uint8_t c = *text;
unsigned int mask, len;
assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE ||
(!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID));
/* TODO check for overlong sequences? */
if (unlikely (hb_object_is_inert (buffer)))
return;
UTF8_COMPUTE (c, mask, len);
if (unlikely (!len || (unsigned int) (end - text) < len)) {
*unicode = -1;
return text + 1;
} else {
hb_codepoint_t result;
unsigned int i;
result = c & mask;
for (i = 1; i < len; i++)
{
if (unlikely ((text[i] & 0xc0) != 0x80))
{
*unicode = -1;
return text + 1;
}
result <<= 6;
result |= (text[i] & 0x3f);
}
*unicode = result;
return text + len;
if (text_length == -1)
text_length = hb_utf_strlen (text);
if (item_length == -1)
item_length = text_length - item_offset;
buffer->ensure (buffer->len + item_length * sizeof (T) / 4);
if (!buffer->len)
{
/* Add pre-context */
buffer->clear_context (0);
const T *prev = text + item_offset;
const T *start = text;
while (start < prev && buffer->context_len[0] < buffer->CONTEXT_LENGTH)
{
hb_codepoint_t u;
prev = hb_utf_prev (prev, start, &u);
buffer->context[0][buffer->context_len[0]++] = u;
}
}
const T *next = text + item_offset;
const T *end = next + item_length;
while (next < end)
{
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);
}
/* Add post-context */
buffer->clear_context (1);
end = text + text_length;
while (next < end && buffer->context_len[1] < buffer->CONTEXT_LENGTH)
{
hb_codepoint_t u;
next = hb_utf_next (next, end, &u);
buffer->context[1][buffer->context_len[1]++] = u;
}
buffer->content_type = HB_BUFFER_CONTENT_TYPE_UNICODE;
}
void
@ -838,31 +872,7 @@ hb_buffer_add_utf8 (hb_buffer_t *buffer,
unsigned int item_offset,
int item_length)
{
#define UTF_NEXT(S, E, U) hb_utf8_next (S, E, &(U))
ADD_UTF (uint8_t);
#undef UTF_NEXT
}
static inline const uint16_t *
hb_utf16_next (const uint16_t *text,
const uint16_t *end,
hb_codepoint_t *unicode)
{
uint16_t c = *text++;
if (unlikely (c >= 0xd800 && c < 0xdc00)) {
/* high surrogate */
uint16_t l;
if (text < end && ((l = *text), likely (l >= 0xdc00 && l < 0xe000))) {
/* low surrogate */
*unicode = ((hb_codepoint_t) ((c) - 0xd800) * 0x400 + (l) - 0xdc00 + 0x10000);
text++;
} else
*unicode = -1;
} else
*unicode = c;
return text;
hb_buffer_add_utf (buffer, (const uint8_t *) text, text_length, item_offset, item_length);
}
void
@ -872,9 +882,7 @@ hb_buffer_add_utf16 (hb_buffer_t *buffer,
unsigned int item_offset,
int item_length)
{
#define UTF_NEXT(S, E, U) hb_utf16_next (S, E, &(U))
ADD_UTF (uint16_t);
#undef UTF_NEXT
hb_buffer_add_utf (buffer, text, text_length, item_offset, item_length);
}
void
@ -884,9 +892,7 @@ hb_buffer_add_utf32 (hb_buffer_t *buffer,
unsigned int item_offset,
int item_length)
{
#define UTF_NEXT(S, E, U) ((U) = *(S), (S)+1)
ADD_UTF (uint32_t);
#undef UTF_NEXT
hb_buffer_add_utf (buffer, text, text_length, item_offset, item_length);
}
@ -949,7 +955,7 @@ void
hb_buffer_normalize_glyphs (hb_buffer_t *buffer)
{
assert (buffer->have_positions);
/* XXX assert (buffer->have_glyphs); */
assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS);
bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);

View File

@ -1,7 +1,7 @@
/*
* Copyright © 1998-2004 David Turner and Werner Lemberg
* Copyright © 2004,2007,2009 Red Hat, Inc.
* Copyright © 2011 Google, Inc.
* Copyright © 2011,2012 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
@ -62,6 +62,12 @@ 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;
hb_buffer_t *
hb_buffer_create (void);
@ -87,6 +93,14 @@ hb_buffer_get_user_data (hb_buffer_t *buffer,
hb_user_data_key_t *key);
void
hb_buffer_set_content_type (hb_buffer_t *buffer,
hb_buffer_content_type_t content_type);
hb_buffer_content_type_t
hb_buffer_get_content_type (hb_buffer_t *buffer);
void
hb_buffer_set_unicode_funcs (hb_buffer_t *buffer,
hb_unicode_funcs_t *unicode_funcs);

View File

@ -58,6 +58,15 @@ hb_tag_from_string (const char *s, int len)
return HB_TAG_CHAR4 (tag);
}
void
hb_tag_to_string (hb_tag_t tag, char *buf)
{
buf[0] = (char) (uint8_t) (tag >> 24);
buf[1] = (char) (uint8_t) (tag >> 16);
buf[2] = (char) (uint8_t) (tag >> 8);
buf[3] = (char) (uint8_t) (tag >> 0);
}
/* hb_direction_t */

View File

@ -95,10 +95,14 @@ typedef uint32_t hb_tag_t;
#define HB_TAG_NONE HB_TAG(0,0,0,0)
/* len=-1 means str is NUL-terminated */
/* len=-1 means str is NUL-terminated. */
hb_tag_t
hb_tag_from_string (const char *str, int len);
/* buf should have 4 bytes. */
void
hb_tag_to_string (hb_tag_t tag, char *buf);
/* hb_direction_t */

View File

@ -589,10 +589,10 @@ _hb_face_for_data_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void
if (tag == HB_TAG_NONE)
return hb_blob_reference (data->blob);
const OpenTypeFontFile &ot_file = *Sanitizer<OpenTypeFontFile>::lock_instance (data->blob);
const OpenTypeFontFace &ot_face = ot_file.get_face (data->index);
const OT::OpenTypeFontFile &ot_file = *OT::Sanitizer<OT::OpenTypeFontFile>::lock_instance (data->blob);
const OT::OpenTypeFontFace &ot_face = ot_file.get_face (data->index);
const OpenTypeTable &table = ot_face.get_table_by_tag (tag);
const OT::OpenTypeTable &table = ot_face.get_table_by_tag (tag);
hb_blob_t *blob = hb_blob_create_sub_blob (data->blob, table.offset, table.length);
@ -608,7 +608,7 @@ hb_face_create (hb_blob_t *blob,
if (unlikely (!blob || !hb_blob_get_length (blob)))
return hb_face_get_empty ();
hb_face_for_data_closure_t *closure = _hb_face_for_data_closure_create (Sanitizer<OpenTypeFontFile>::sanitize (hb_blob_reference (blob)), index);
hb_face_for_data_closure_t *closure = _hb_face_for_data_closure_create (OT::Sanitizer<OT::OpenTypeFontFile>::sanitize (hb_blob_reference (blob)), index);
if (unlikely (!closure))
return hb_face_get_empty ();
@ -740,8 +740,8 @@ hb_face_get_upem (hb_face_t *face)
void
hb_face_t::load_upem (void) const
{
hb_blob_t *head_blob = Sanitizer<head>::sanitize (reference_table (HB_OT_TAG_head));
const head *head_table = Sanitizer<head>::lock_instance (head_blob);
hb_blob_t *head_blob = OT::Sanitizer<OT::head>::sanitize (reference_table (HB_OT_TAG_head));
const OT::head *head_table = OT::Sanitizer<OT::head>::lock_instance (head_blob);
upem = head_table->get_upem ();
hb_blob_destroy (head_blob);
}

View File

@ -211,11 +211,6 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan,
gr_face *grface = HB_SHAPER_DATA_GET (face)->grface;
gr_font *grfont = HB_SHAPER_DATA_GET (font);
unsigned int charlen;
hb_glyph_info_t *bufferi = hb_buffer_get_glyph_infos (buffer, &charlen);
int success = 0;
const char *lang = hb_language_to_string (hb_buffer_get_language (buffer));
const char *lang_end = strchr (lang, '-');
int lang_len = lang_end ? lang_end - lang : -1;
@ -229,24 +224,23 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan,
features++;
}
/* TODO Use scratch buffer for these. */
hb_codepoint_t *gids = NULL, *pg;
hb_graphite2_cluster_t *clusters = NULL;
gr_segment *seg = NULL;
uint32_t *text = NULL;
const gr_slot *is;
unsigned int ci = 0, ic = 0;
float curradvx = 0., curradvy = 0.;
unsigned int glyphlen = 0;
unsigned int *p;
text = (uint32_t *) malloc ((charlen + 1) * sizeof (uint32_t));
if (!text) goto dieout;
unsigned int scratch_size;
char *scratch = (char *) buffer->get_scratch_buffer (&scratch_size);
p = text;
for (unsigned int i = 0; i < charlen; ++i)
*p++ = bufferi++->codepoint;
*p = 0;
#define ALLOCATE_ARRAY(Type, name, len) \
Type *name = (Type *) scratch; \
scratch += (len) * sizeof ((name)[0]); \
scratch_size -= (len) * sizeof ((name)[0]);
ALLOCATE_ARRAY (uint32_t, chars, buffer->len);
for (unsigned int i = 0; i < buffer->len; ++i)
chars[i] = buffer->info[i].codepoint;
hb_tag_t script_tag[2];
hb_ot_tags_from_script (hb_buffer_get_script (buffer), &script_tag[0], &script_tag[1]);
@ -254,18 +248,40 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan,
seg = gr_make_seg (grfont, grface,
script_tag[1] == HB_TAG_NONE ? script_tag[0] : script_tag[1],
feats,
gr_utf32, text, charlen,
gr_utf32, chars, buffer->len,
2 | (hb_buffer_get_direction (buffer) == HB_DIRECTION_RTL ? 1 : 0));
if (!seg) goto dieout;
glyphlen = gr_seg_n_slots (seg);
clusters = (hb_graphite2_cluster_t *) calloc (charlen, sizeof (hb_graphite2_cluster_t));
if (!glyphlen || !clusters) goto dieout;
if (unlikely (!seg)) {
if (feats) gr_featureval_destroy (feats);
return false;
}
gids = (hb_codepoint_t *) malloc (glyphlen * sizeof (hb_codepoint_t));
if (!gids) goto dieout;
unsigned int glyph_count = gr_seg_n_slots (seg);
if (unlikely (!glyph_count)) {
if (feats) gr_featureval_destroy (feats);
gr_seg_destroy (seg);
return false;
}
pg = gids;
scratch = (char *) buffer->get_scratch_buffer (&scratch_size);
while ((sizeof (hb_graphite2_cluster_t) * buffer->len +
sizeof (hb_codepoint_t) * glyph_count) > scratch_size)
{
buffer->ensure (buffer->allocated * 2);
if (unlikely (buffer->in_error)) {
if (feats) gr_featureval_destroy (feats);
gr_seg_destroy (seg);
return false;
}
scratch = (char *) buffer->get_scratch_buffer (&scratch_size);
}
ALLOCATE_ARRAY (hb_graphite2_cluster_t, clusters, buffer->len);
ALLOCATE_ARRAY (hb_codepoint_t, gids, glyph_count);
memset (clusters, 0, sizeof (clusters[0]) * buffer->len);
hb_codepoint_t *pg = gids;
for (is = gr_seg_first_slot (seg), ic = 0; is; is = gr_slot_next_in_segment (is), ic++)
{
unsigned int before = gr_slot_before (is);
@ -325,13 +341,8 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan,
if (HB_DIRECTION_IS_BACKWARD (buffer->props.direction))
hb_buffer_reverse_clusters (buffer);
success = 1;
dieout:
if (feats) gr_featureval_destroy (feats);
if (gids) free (gids);
if (clusters) free (clusters);
if (seg) gr_seg_destroy (seg);
if (text) free (text);
return success;
gr_seg_destroy (seg);
return true;
}

View File

@ -0,0 +1,213 @@
/*
* Copyright © 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
*/
#define HB_SHAPER icu_le
#define hb_icu_le_shaper_font_data_t PortableFontInstance
#include "hb-shaper-impl-private.hh"
#include "hb-icu-le/PortableFontInstance.h"
#include "layout/LayoutEngine.h"
#include "unicode/unistr.h"
#include "hb-icu.h"
/*
* shaper face data
*/
struct hb_icu_le_shaper_face_data_t {};
hb_icu_le_shaper_face_data_t *
_hb_icu_le_shaper_face_data_create (hb_face_t *face)
{
return (hb_icu_le_shaper_face_data_t *) HB_SHAPER_DATA_SUCCEEDED;
}
void
_hb_icu_le_shaper_face_data_destroy (hb_icu_le_shaper_face_data_t *data)
{
}
/*
* shaper font data
*/
hb_icu_le_shaper_font_data_t *
_hb_icu_le_shaper_font_data_create (hb_font_t *font)
{
LEErrorCode status = LE_NO_ERROR;
hb_icu_le_shaper_font_data_t *data = new PortableFontInstance (font->face,
font->x_scale,
font->y_scale,
status);
if (status != LE_NO_ERROR) {
delete (data);
return NULL;
}
return data;
}
void
_hb_icu_le_shaper_font_data_destroy (hb_icu_le_shaper_font_data_t *data)
{
delete (data);
}
/*
* shaper shape_plan data
*/
struct hb_icu_le_shaper_shape_plan_data_t {};
hb_icu_le_shaper_shape_plan_data_t *
_hb_icu_le_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan,
const hb_feature_t *user_features,
unsigned int num_user_features)
{
return (hb_icu_le_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
}
void
_hb_icu_le_shaper_shape_plan_data_destroy (hb_icu_le_shaper_shape_plan_data_t *data)
{
}
/*
* shaper
*/
hb_bool_t
_hb_icu_le_shape (hb_shape_plan_t *shape_plan,
hb_font_t *font,
hb_buffer_t *buffer,
const hb_feature_t *features,
unsigned int num_features)
{
LEFontInstance *font_instance = HB_SHAPER_DATA_GET (font);
le_int32 script_code = hb_icu_script_from_script (shape_plan->props.script);
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);
if (status != LE_NO_ERROR)
{ delete (le); return false; }
retry:
unsigned int scratch_size;
char *scratch = (char *) buffer->get_scratch_buffer (&scratch_size);
#define ALLOCATE_ARRAY(Type, name, len) \
Type *name = (Type *) scratch; \
scratch += (len) * sizeof ((name)[0]); \
scratch_size -= (len) * sizeof ((name)[0]);
ALLOCATE_ARRAY (LEUnicode, chars, buffer->len);
ALLOCATE_ARRAY (unsigned int, clusters, buffer->len);
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,
0,
buffer->len,
buffer->len,
HB_DIRECTION_IS_BACKWARD (buffer->props.direction),
0., 0.,
status);
if (status != LE_NO_ERROR)
{ delete (le); return false; }
unsigned int num_glyphs = scratch_size / (sizeof (LEGlyphID) +
sizeof (le_int32) +
sizeof (float) * 2);
if (unlikely (glyph_count >= num_glyphs || glyph_count > buffer->allocated)) {
buffer->ensure (buffer->allocated * 2);
if (buffer->in_error)
{ delete (le); return false; }
goto retry;
}
ALLOCATE_ARRAY (LEGlyphID, glyphs, glyph_count);
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);
#undef ALLOCATE_ARRAY
/* Ok, we've got everything we need, now compose output buffer,
* very, *very*, carefully! */
unsigned int j = 0;
hb_glyph_info_t *info = buffer->info;
for (unsigned int i = 0; i < glyph_count; i++)
{
if (glyphs[i] >= 0xFFFE)
continue;
info[j].codepoint = glyphs[i];
info[j].cluster = clusters[indices[i]];
/* icu-le doesn't seem to have separapte 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];
j++;
}
buffer->len = j;
buffer->clear_positions ();
for (unsigned int i = 0; i < buffer->len; i++) {
hb_glyph_info_t *info = &buffer->info[i];
hb_glyph_position_t *pos = &buffer->pos[i];
/* TODO vertical */
pos->x_advance = info->mask;
pos->x_offset = info->var1.u32;
pos->y_offset = info->var2.u32;
}
delete (le);
return true;
}

View File

@ -65,26 +65,6 @@ typedef pthread_mutex_t hb_mutex_impl_t;
#define hb_mutex_impl_finish(M) pthread_mutex_destroy (M)
#elif !defined(HB_NO_MT) && defined(HAVE_GLIB)
#include <glib.h>
#if !GLIB_CHECK_VERSION(2,32,0)
typedef GStaticMutex hb_mutex_impl_t;
#define HB_MUTEX_IMPL_INIT G_STATIC_MUTEX_INIT
#define hb_mutex_impl_init(M) g_static_mutex_init (M)
#define hb_mutex_impl_lock(M) g_static_mutex_lock (M)
#define hb_mutex_impl_unlock(M) g_static_mutex_unlock (M)
#define hb_mutex_impl_finish(M) g_static_mutex_free (M)
#else
typedef GMutex hb_mutex_impl_t;
#define HB_MUTEX_IMPL_INIT {0}
#define hb_mutex_impl_init(M) g_mutex_init (M)
#define hb_mutex_impl_lock(M) g_mutex_lock (M)
#define hb_mutex_impl_unlock(M) g_mutex_unlock (M)
#define hb_mutex_impl_finish(M) g_mutex_clear (M)
#endif
#elif !defined(HB_NO_MT) && defined(HAVE_INTEL_ATOMIC_PRIMITIVES)
#if defined(HAVE_SCHED_H) && defined(HAVE_SCHED_YIELD)

View File

@ -337,6 +337,9 @@ retry:
ALLOCATE_ARRAY (HB_GlyphAttributes, item.attributes, num_glyphs);
ALLOCATE_ARRAY (HB_Fixed, item.advances, num_glyphs);
ALLOCATE_ARRAY (HB_FixedPoint, item.offsets, num_glyphs);
/* Apparently in some cases the offsets array will not be fully assigned to.
* Clear it. */
memset (item.offsets, 0, num_glyphs * sizeof (item.offsets[0]));
uint32_t *vis_clusters;
ALLOCATE_ARRAY (uint32_t, vis_clusters, num_glyphs);

View File

@ -32,6 +32,8 @@
#include "hb-open-type-private.hh"
namespace OT {
/*
*
@ -253,5 +255,7 @@ struct OpenTypeFontFile
};
} // namespace OT
#endif /* HB_OPEN_FILE_PRIVATE_HH */

View File

@ -34,6 +34,8 @@
#include "hb-blob.h"
namespace OT {
/*
* Casts
@ -325,6 +327,160 @@ struct Sanitizer
/*
* Serialize
*/
#ifndef HB_DEBUG_SERIALIZE
#define HB_DEBUG_SERIALIZE (HB_DEBUG+0)
#endif
#define TRACE_SERIALIZE() \
hb_auto_trace_t<HB_DEBUG_SERIALIZE> trace (&c->debug_depth, "SERIALIZE", c, HB_FUNC, "");
struct hb_serialize_context_t
{
inline hb_serialize_context_t (void *start, unsigned int size)
{
this->start = (char *) start;
this->end = this->start + size;
this->ran_out_of_room = false;
this->head = this->start;
this->debug_depth = 0;
}
template <typename Type>
inline Type *start_serialize (void)
{
DEBUG_MSG_LEVEL (SERIALIZE, this->start, 0, +1,
"start [%p..%p] (%lu bytes)",
this->start, this->end,
(unsigned long) (this->end - this->start));
return start_embed<Type> ();
}
inline void end_serialize (void)
{
DEBUG_MSG_LEVEL (SERIALIZE, this->start, 0, -1,
"end [%p..%p] serialized %d bytes; %s",
this->start, this->end,
(int) (this->head - this->start),
this->ran_out_of_room ? "RAN OUT OF ROOM" : "did not ran out of room");
}
template <typename Type>
inline Type *copy (void)
{
assert (!this->ran_out_of_room);
unsigned int len = this->head - this->start;
void *p = malloc (len);
if (p)
memcpy (p, this->start, len);
return reinterpret_cast<Type *> (p);
}
template <typename Type>
inline Type *allocate_size (unsigned int size)
{
if (unlikely (this->ran_out_of_room || this->end - this->head < size)) {
this->ran_out_of_room = true;
return NULL;
}
memset (this->head, 0, size);
char *ret = this->head;
this->head += size;
return reinterpret_cast<Type *> (ret);
}
template <typename Type>
inline Type *allocate_min (void)
{
return this->allocate_size<Type> (Type::min_size);
}
template <typename Type>
inline Type *start_embed (void)
{
Type *ret = reinterpret_cast<Type *> (this->head);
return ret;
}
template <typename Type>
inline Type *embed (const Type &obj)
{
unsigned int size = obj.get_size ();
Type *ret = this->allocate_size<Type> (size);
if (unlikely (!ret)) return NULL;
memcpy (ret, obj, size);
return ret;
}
template <typename Type>
inline Type *extend_min (Type &obj)
{
unsigned int size = obj.min_size;
assert (this->start <= (char *) &obj && (char *) &obj <= this->head && (char *) &obj + size >= this->head);
if (unlikely (!this->allocate_size<Type> (((char *) &obj) + size - this->head))) return NULL;
return reinterpret_cast<Type *> (&obj);
}
template <typename Type>
inline Type *extend (Type &obj)
{
unsigned int size = obj.get_size ();
assert (this->start < (char *) &obj && (char *) &obj <= this->head && (char *) &obj + size >= this->head);
if (unlikely (!this->allocate_size<Type> (((char *) &obj) + size - this->head))) return NULL;
return reinterpret_cast<Type *> (&obj);
}
inline void truncate (void *head)
{
assert (this->start < head && head <= this->head);
this->head = (char *) head;
}
unsigned int debug_depth;
char *start, *end, *head;
bool ran_out_of_room;
};
template <typename Type>
struct Supplier
{
inline Supplier (const Type *array, unsigned int len_)
{
head = array;
len = len_;
}
inline const Type operator [] (unsigned int i) const
{
if (unlikely (i >= len)) return Type ();
return head[i];
}
inline void advance (unsigned int count)
{
if (unlikely (count > len))
count = len;
len -= count;
head += count;
}
private:
inline Supplier (const Supplier<Type> &); /* Disallow copy */
inline Supplier<Type>& operator= (const Supplier<Type> &); /* Disallow copy */
unsigned int len;
const Type *head;
};
/*
*
@ -371,6 +527,8 @@ struct IntType
inline operator Type(void) const { return v; }
inline bool operator == (const IntType<Type> &o) const { return v == o.v; }
inline bool operator != (const IntType<Type> &o) const { return v != o.v; }
static inline int cmp (const IntType<Type> *a, const IntType<Type> *b) { return b->cmp (*a); }
inline int cmp (IntType<Type> va) const { Type a = va; Type b = v; return a < b ? -1 : a == b ? 0 : +1; }
inline int cmp (Type a) const { Type b = v; return a < b ? -1 : a == b ? 0 : +1; }
inline bool sanitize (hb_sanitize_context_t *c) {
TRACE_SANITIZE ();
@ -382,11 +540,6 @@ struct IntType
DEFINE_SIZE_STATIC (sizeof (Type));
};
/* Typedef these to avoid clash with windows.h */
#define USHORT HB_USHORT
#define SHORT HB_SHORT
#define ULONG HB_ULONG
#define LONG HB_LONG
typedef IntType<uint16_t> USHORT; /* 16-bit unsigned integer. */
typedef IntType<int16_t> SHORT; /* 16-bit signed integer. */
typedef IntType<uint32_t> ULONG; /* 32-bit unsigned integer. */
@ -493,6 +646,18 @@ struct GenericOffsetTo : OffsetType
if (unlikely (!offset)) return Null(Type);
return StructAtOffset<Type> (base, offset);
}
inline Type& operator () (void *base)
{
unsigned int offset = *this;
return StructAtOffset<Type> (base, offset);
}
inline Type& serialize (hb_serialize_context_t *c, void *base)
{
Type *t = c->start_embed<Type> ();
this->set ((char *) t - (char *) base); /* TODO(serialize) Overflow? */
return *t;
}
inline bool sanitize (hb_sanitize_context_t *c, void *base) {
TRACE_SANITIZE ();
@ -523,7 +688,9 @@ struct GenericOffsetTo : OffsetType
}
};
template <typename Base, typename OffsetType, typename Type>
inline const Type& operator + (const Base &base, GenericOffsetTo<OffsetType, Type> offset) { return offset (base); }
inline const Type& operator + (const Base &base, const GenericOffsetTo<OffsetType, Type> &offset) { return offset (base); }
template <typename Base, typename OffsetType, typename Type>
inline Type& operator + (Base &base, GenericOffsetTo<OffsetType, Type> &offset) { return offset (base); }
template <typename Type>
struct OffsetTo : GenericOffsetTo<Offset, Type> {};
@ -556,9 +723,35 @@ struct GenericArrayOf
if (unlikely (i >= len)) return Null(Type);
return array[i];
}
inline Type& operator [] (unsigned int i)
{
return array[i];
}
inline unsigned int get_size (void) const
{ return len.static_size + len * Type::static_size; }
inline bool serialize (hb_serialize_context_t *c,
unsigned int items_len)
{
TRACE_SERIALIZE ();
if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
len.set (items_len); /* TODO(serialize) Overflow? */
if (unlikely (!c->extend (*this))) return TRACE_RETURN (false);
return TRACE_RETURN (true);
}
inline bool serialize (hb_serialize_context_t *c,
Supplier<Type> &items,
unsigned int items_len)
{
TRACE_SERIALIZE ();
if (unlikely (!serialize (c, items_len))) return TRACE_RETURN (false);
for (unsigned int i = 0; i < items_len; i++)
array[i] = items[i];
items.advance (items_len);
return TRACE_RETURN (true);
}
inline bool sanitize (hb_sanitize_context_t *c) {
TRACE_SANITIZE ();
if (unlikely (!sanitize_shallow (c))) return TRACE_RETURN (false);
@ -662,6 +855,21 @@ struct HeadlessArrayOf
inline unsigned int get_size (void) const
{ return len.static_size + (len ? len - 1 : 0) * Type::static_size; }
inline bool serialize (hb_serialize_context_t *c,
Supplier<Type> &items,
unsigned int items_len)
{
TRACE_SERIALIZE ();
if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
len.set (items_len); /* TODO(serialize) Overflow? */
if (unlikely (!items_len)) return TRACE_RETURN (true);
if (unlikely (!c->extend (*this))) return TRACE_RETURN (false);
for (unsigned int i = 0; i < items_len - 1; i++)
array[i] = items[i];
items.advance (items_len - 1);
return TRACE_RETURN (true);
}
inline bool sanitize_shallow (hb_sanitize_context_t *c) {
return c->check_struct (this)
&& c->check_array (this, Type::static_size, len);
@ -714,5 +922,7 @@ struct SortedArrayOf : ArrayOf<Type> {
};
} // namespace OT
#endif /* HB_OPEN_TYPE_PRIVATE_HH */

View File

@ -32,6 +32,8 @@
#include "hb-open-type-private.hh"
namespace OT {
/*
* head -- Font Header
@ -141,5 +143,7 @@ struct head
};
} // namespace OT
#endif /* HB_OT_HEAD_TABLE_HH */

View File

@ -30,6 +30,8 @@
#include "hb-open-type-private.hh"
namespace OT {
/*
* hhea -- The Horizontal Header Table
@ -89,4 +91,7 @@ struct hhea
};
} // namespace OT
#endif /* HB_OT_HHEA_TABLE_HH */

View File

@ -30,6 +30,8 @@
#include "hb-open-type-private.hh"
namespace OT {
/*
* hmtx -- The Horizontal Metrics Table
@ -83,4 +85,8 @@ struct hmtx
DEFINE_SIZE_ARRAY2 (0, longHorMetric, leftSideBearingX);
};
} // namespace OT
#endif /* HB_OT_HMTX_TABLE_HH */

View File

@ -34,6 +34,9 @@
#include "hb-set-private.hh"
namespace OT {
#define NOT_COVERED ((unsigned int) -1)
#define MAX_NESTING_LEVEL 8
@ -310,11 +313,29 @@ struct Lookup
return flag;
}
inline bool serialize (hb_serialize_context_t *c,
unsigned int lookup_type,
uint32_t lookup_props,
unsigned int num_subtables)
{
TRACE_SERIALIZE ();
if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
lookupType.set (lookup_type);
lookupFlag.set (lookup_props & 0xFFFF);
if (unlikely (!subTable.serialize (c, num_subtables))) return TRACE_RETURN (false);
if (lookupFlag & LookupFlag::UseMarkFilteringSet)
{
USHORT &markFilteringSet = StructAfter<USHORT> (subTable);
markFilteringSet.set (lookup_props >> 16);
}
return TRACE_RETURN (true);
}
inline bool sanitize (hb_sanitize_context_t *c) {
TRACE_SANITIZE ();
/* Real sanitize of the subtables is done by GSUB/GPOS/... */
if (!(c->check_struct (this) && subTable.sanitize (c))) return TRACE_RETURN (false);
if (unlikely (lookupFlag & LookupFlag::UseMarkFilteringSet))
if (lookupFlag & LookupFlag::UseMarkFilteringSet)
{
USHORT &markFilteringSet = StructAfter<USHORT> (subTable);
if (!markFilteringSet.sanitize (c)) return TRACE_RETURN (false);
@ -352,6 +373,20 @@ struct CoverageFormat1
return i;
}
inline bool serialize (hb_serialize_context_t *c,
Supplier<GlyphID> &glyphs,
unsigned int num_glyphs)
{
TRACE_SERIALIZE ();
if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
glyphArray.len.set (num_glyphs);
if (unlikely (!c->extend (glyphArray))) return TRACE_RETURN (false);
for (unsigned int i = 0; i < num_glyphs; i++)
glyphArray[i] = glyphs[i];
glyphs.advance (num_glyphs);
return TRACE_RETURN (true);
}
inline bool sanitize (hb_sanitize_context_t *c) {
TRACE_SANITIZE ();
return TRACE_RETURN (glyphArray.sanitize (c));
@ -403,6 +438,38 @@ struct CoverageFormat2
return NOT_COVERED;
}
inline bool serialize (hb_serialize_context_t *c,
Supplier<GlyphID> &glyphs,
unsigned int num_glyphs)
{
TRACE_SERIALIZE ();
if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
if (unlikely (!num_glyphs)) return TRACE_RETURN (true);
unsigned int num_ranges = 1;
for (unsigned int i = 1; i < num_glyphs; i++)
if (glyphs[i - 1] + 1 != glyphs[i])
num_ranges++;
rangeRecord.len.set (num_ranges);
if (unlikely (!c->extend (rangeRecord))) return TRACE_RETURN (false);
unsigned int range = 0;
rangeRecord[range].start = glyphs[0];
rangeRecord[range].value.set (0);
for (unsigned int i = 1; i < num_glyphs; i++)
if (glyphs[i - 1] + 1 != glyphs[i]) {
range++;
rangeRecord[range].start = glyphs[i];
rangeRecord[range].value.set (i);
rangeRecord[range].end = glyphs[i];
} else {
rangeRecord[range].end = glyphs[i];
}
glyphs.advance (num_glyphs);
return TRACE_RETURN (true);
}
inline bool sanitize (hb_sanitize_context_t *c) {
TRACE_SANITIZE ();
return TRACE_RETURN (rangeRecord.sanitize (c));
@ -479,6 +546,24 @@ struct Coverage
}
}
inline bool serialize (hb_serialize_context_t *c,
Supplier<GlyphID> &glyphs,
unsigned int num_glyphs)
{
TRACE_SERIALIZE ();
if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
unsigned int num_ranges = 1;
for (unsigned int i = 1; i < num_glyphs; i++)
if (glyphs[i - 1] + 1 != glyphs[i])
num_ranges++;
u.format.set (num_glyphs * 2 < num_ranges * 3 ? 1 : 2);
switch (u.format) {
case 1: return TRACE_RETURN (u.format1.serialize (c, glyphs, num_glyphs));
case 2: return TRACE_RETURN (u.format2.serialize (c, glyphs, num_glyphs));
default:return TRACE_RETURN (false);
}
}
inline bool sanitize (hb_sanitize_context_t *c) {
TRACE_SANITIZE ();
if (!u.format.sanitize (c)) return TRACE_RETURN (false);
@ -763,5 +848,7 @@ struct Device
};
} // namespace OT
#endif /* HB_OT_LAYOUT_COMMON_PRIVATE_HH */

View File

@ -34,6 +34,8 @@
#include "hb-font-private.hh"
namespace OT {
/*
* Attachment List Table
@ -421,5 +423,7 @@ struct GDEF
};
} // namespace OT
#endif /* HB_OT_LAYOUT_GDEF_TABLE_HH */

View File

@ -32,6 +32,8 @@
#include "hb-ot-layout-gsubgpos-private.hh"
namespace OT {
/* buffer **position** var allocations */
#define attach_lookback() var.u16[0] /* number of glyphs to go back to attach this glyph to its base */
@ -1529,11 +1531,11 @@ struct PosLookup : Lookup
return false;
}
inline bool apply_string (hb_apply_context_t *c) const
inline bool apply_string (hb_apply_context_t *c, const hb_set_digest_t *digest) const
{
bool ret = false;
if (unlikely (!c->buffer->len))
if (unlikely (!c->buffer->len || !c->lookup_mask))
return false;
c->set_lookup (*this);
@ -1543,7 +1545,7 @@ struct PosLookup : Lookup
while (c->buffer->idx < c->buffer->len)
{
if ((c->buffer->cur().mask & c->lookup_mask) &&
c->digest.may_have (c->buffer->cur().codepoint) &&
digest->may_have (c->buffer->cur().codepoint) &&
apply_once (c))
ret = true;
else
@ -1578,9 +1580,6 @@ struct GPOS : GSUBGPOS
inline void add_coverage (set_t *glyphs, unsigned int lookup_index) const
{ get_lookup (lookup_index).add_coverage (glyphs); }
inline bool position_lookup (hb_apply_context_t *c, unsigned int lookup_index) const
{ return get_lookup (lookup_index).apply_string (c); }
static inline void position_start (hb_font_t *font, hb_buffer_t *buffer);
static inline void position_finish (hb_font_t *font, hb_buffer_t *buffer, hb_bool_t zero_width_attahced_marks);
@ -1598,20 +1597,20 @@ struct GPOS : GSUBGPOS
static void
fix_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction)
{
unsigned int j = pos[i].cursive_chain();
if (likely (!j))
return;
unsigned int j = pos[i].cursive_chain();
if (likely (!j))
return;
j += i;
j += i;
pos[i].cursive_chain() = 0;
pos[i].cursive_chain() = 0;
fix_cursive_minor_offset (pos, j, direction);
fix_cursive_minor_offset (pos, j, direction);
if (HB_DIRECTION_IS_HORIZONTAL (direction))
pos[i].y_offset += pos[j].y_offset;
else
pos[i].x_offset += pos[j].x_offset;
if (HB_DIRECTION_IS_HORIZONTAL (direction))
pos[i].y_offset += pos[j].y_offset;
else
pos[i].x_offset += pos[j].x_offset;
}
static void
@ -1713,5 +1712,7 @@ static inline bool position_lookup (hb_apply_context_t *c, unsigned int lookup_i
#undef cursive_chain
} // namespace OT
#endif /* HB_OT_LAYOUT_GPOS_TABLE_HH */

View File

@ -32,6 +32,8 @@
#include "hb-ot-layout-gsubgpos-private.hh"
namespace OT {
struct SingleSubstFormat1
{
@ -70,6 +72,18 @@ struct SingleSubstFormat1
return TRACE_RETURN (true);
}
inline bool serialize (hb_serialize_context_t *c,
Supplier<GlyphID> &glyphs,
unsigned int num_glyphs,
int delta)
{
TRACE_SERIALIZE ();
if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
deltaGlyphID.set (delta); /* TODO(serilaize) overflow? */
return TRACE_RETURN (true);
}
inline bool sanitize (hb_sanitize_context_t *c) {
TRACE_SANITIZE ();
return TRACE_RETURN (coverage.sanitize (c, this) && deltaGlyphID.sanitize (c));
@ -122,6 +136,18 @@ struct SingleSubstFormat2
return TRACE_RETURN (true);
}
inline bool serialize (hb_serialize_context_t *c,
Supplier<GlyphID> &glyphs,
Supplier<GlyphID> &substitutes,
unsigned int num_glyphs)
{
TRACE_SERIALIZE ();
if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
if (unlikely (!substitute.serialize (c, substitutes, num_glyphs))) return TRACE_RETURN (false);
if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
return TRACE_RETURN (true);
}
inline bool sanitize (hb_sanitize_context_t *c) {
TRACE_SANITIZE ();
return TRACE_RETURN (coverage.sanitize (c, this) && substitute.sanitize (c));
@ -142,6 +168,7 @@ struct SingleSubstFormat2
struct SingleSubst
{
friend struct SubstLookupSubTable;
friend struct SubstLookup;
private:
@ -174,6 +201,33 @@ struct SingleSubst
}
}
inline bool serialize (hb_serialize_context_t *c,
Supplier<GlyphID> &glyphs,
Supplier<GlyphID> &substitutes,
unsigned int num_glyphs)
{
TRACE_SERIALIZE ();
if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false);
unsigned int format = 2;
int delta;
if (num_glyphs) {
format = 1;
/* TODO(serialize) check for wrap-around */
delta = substitutes[0] - glyphs[0];
for (unsigned int i = 1; i < num_glyphs; i++)
if (delta != substitutes[i] - glyphs[i]) {
format = 2;
break;
}
}
u.format.set (format);
switch (u.format) {
case 1: return TRACE_RETURN (u.format1.serialize (c, glyphs, num_glyphs, delta));
case 2: return TRACE_RETURN (u.format2.serialize (c, glyphs, substitutes, num_glyphs));
default:return TRACE_RETURN (false);
}
}
inline bool sanitize (hb_sanitize_context_t *c) {
TRACE_SANITIZE ();
if (!u.format.sanitize (c)) return TRACE_RETURN (false);
@ -223,6 +277,16 @@ struct Sequence
return TRACE_RETURN (true);
}
inline bool serialize (hb_serialize_context_t *c,
Supplier<GlyphID> &glyphs,
unsigned int num_glyphs)
{
TRACE_SERIALIZE ();
if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
if (unlikely (!substitute.serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
return TRACE_RETURN (true);
}
public:
inline bool sanitize (hb_sanitize_context_t *c) {
TRACE_SANITIZE ();
@ -267,6 +331,24 @@ struct MultipleSubstFormat1
return TRACE_RETURN ((this+sequence[index]).apply (c));
}
inline bool serialize (hb_serialize_context_t *c,
Supplier<GlyphID> &glyphs,
Supplier<unsigned int> &substitute_len_list,
unsigned int num_glyphs,
Supplier<GlyphID> &substitute_glyphs_list)
{
TRACE_SERIALIZE ();
if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
if (unlikely (!sequence.serialize (c, num_glyphs))) return TRACE_RETURN (false);
for (unsigned int i = 0; i < num_glyphs; i++)
if (unlikely (!sequence[i].serialize (c, this).serialize (c,
substitute_glyphs_list,
substitute_len_list[i]))) return TRACE_RETURN (false);
substitute_len_list.advance (num_glyphs);
if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
return TRACE_RETURN (true);
}
inline bool sanitize (hb_sanitize_context_t *c) {
TRACE_SANITIZE ();
return TRACE_RETURN (coverage.sanitize (c, this) && sequence.sanitize (c, this));
@ -287,6 +369,7 @@ struct MultipleSubstFormat1
struct MultipleSubst
{
friend struct SubstLookupSubTable;
friend struct SubstLookup;
private:
@ -316,6 +399,22 @@ struct MultipleSubst
}
}
inline bool serialize (hb_serialize_context_t *c,
Supplier<GlyphID> &glyphs,
Supplier<unsigned int> &substitute_len_list,
unsigned int num_glyphs,
Supplier<GlyphID> &substitute_glyphs_list)
{
TRACE_SERIALIZE ();
if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false);
unsigned int format = 1;
u.format.set (format);
switch (u.format) {
case 1: return TRACE_RETURN (u.format1.serialize (c, glyphs, substitute_len_list, num_glyphs, substitute_glyphs_list));
default:return TRACE_RETURN (false);
}
}
inline bool sanitize (hb_sanitize_context_t *c) {
TRACE_SANITIZE ();
if (!u.format.sanitize (c)) return TRACE_RETURN (false);
@ -389,6 +488,24 @@ struct AlternateSubstFormat1
return TRACE_RETURN (true);
}
inline bool serialize (hb_serialize_context_t *c,
Supplier<GlyphID> &glyphs,
Supplier<unsigned int> &alternate_len_list,
unsigned int num_glyphs,
Supplier<GlyphID> &alternate_glyphs_list)
{
TRACE_SERIALIZE ();
if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
if (unlikely (!alternateSet.serialize (c, num_glyphs))) return TRACE_RETURN (false);
for (unsigned int i = 0; i < num_glyphs; i++)
if (unlikely (!alternateSet[i].serialize (c, this).serialize (c,
alternate_glyphs_list,
alternate_len_list[i]))) return TRACE_RETURN (false);
alternate_len_list.advance (num_glyphs);
if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
return TRACE_RETURN (true);
}
inline bool sanitize (hb_sanitize_context_t *c) {
TRACE_SANITIZE ();
return TRACE_RETURN (coverage.sanitize (c, this) && alternateSet.sanitize (c, this));
@ -409,6 +526,7 @@ struct AlternateSubstFormat1
struct AlternateSubst
{
friend struct SubstLookupSubTable;
friend struct SubstLookup;
private:
@ -438,6 +556,22 @@ struct AlternateSubst
}
}
inline bool serialize (hb_serialize_context_t *c,
Supplier<GlyphID> &glyphs,
Supplier<unsigned int> &alternate_len_list,
unsigned int num_glyphs,
Supplier<GlyphID> &alternate_glyphs_list)
{
TRACE_SERIALIZE ();
if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false);
unsigned int format = 1;
u.format.set (format);
switch (u.format) {
case 1: return TRACE_RETURN (u.format1.serialize (c, glyphs, alternate_len_list, num_glyphs, alternate_glyphs_list));
default:return TRACE_RETURN (false);
}
}
inline bool sanitize (hb_sanitize_context_t *c) {
TRACE_SANITIZE ();
if (!u.format.sanitize (c)) return TRACE_RETURN (false);
@ -489,135 +623,43 @@ struct Ligature
unsigned int count = component.len;
if (unlikely (count < 1)) return TRACE_RETURN (false);
hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, count - 1);
if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
unsigned int end_offset;
bool is_mark_ligature;
unsigned int total_component_count;
/*
* This is perhaps the trickiest part of GSUB... Remarks:
*
* - If all components of the ligature were marks, we call this a mark ligature.
*
* - If there is no GDEF, and the ligature is NOT a mark ligature, we categorize
* it as a ligature glyph. Though, really, this will not really be used...
*
* - If it *is* a mark ligature, we don't allocate a new ligature id, and leave
* the ligature to keep its old ligature id. This will allow it to attach to
* a base ligature in GPOS. Eg. if the sequence is: LAM,LAM,SHADDA,FATHA,HEH,
* and LAM,LAM,HEH for a ligature, they will leave SHADDA and FATHA wit a
* ligature id and component value of 2. Then if SHADDA,FATHA form a ligature
* later, we don't want them to lose their ligature id/component, otherwise
* GPOS will fail to correctly position the mark ligature on top of the
* LAM,LAM,HEH ligature. See:
* https://bugzilla.gnome.org/show_bug.cgi?id=676343
*
* - If a ligature is formed of components that some of which are also ligatures
* themselves, and those ligature components had marks attached to *their*
* components, we have to attach the marks to the new ligature component
* positions! Now *that*'s tricky! And these marks may be following the
* last component of the whole sequence, so we should loop forward looking
* for them and update them.
*
* Eg. the sequence is LAM,LAM,SHADDA,FATHA,HEH, and the font first forms a
* 'calt' ligature of LAM,HEH, leaving the SHADDA and FATHA with a ligature
* id and component == 1. Now, during 'liga', the LAM and the LAM-HEH ligature
* form a LAM-LAM-HEH ligature. We need to reassign the SHADDA and FATHA to
* the new ligature with a component value of 2.
*
* This in fact happened to a font... See:
* https://bugzilla.gnome.org/show_bug.cgi?id=437633
*
* - Ligatures cannot be formed across glyphs attached to different components
* of previous ligatures. Eg. the sequence is LAM,SHADDA,LAM,FATHA,HEH, and
* LAM,LAM,HEH form a ligature, leaving SHADDA,FATHA next to eachother.
* However, it would be wrong to ligate that SHADDA,FATHA sequence.o
* There is an exception to this: If a ligature tries ligating with marks that
* belong to it itself, go ahead, assuming that the font designer knows what
* they are doing (otherwise it can break Indic stuff when a matra wants to
* ligate with a conjunct...)
*/
bool is_mark_ligature = !!(c->property & HB_OT_LAYOUT_GLYPH_CLASS_MARK);
unsigned int total_component_count = 0;
total_component_count += get_lig_num_comps (c->buffer->cur());
unsigned int first_lig_id = get_lig_id (c->buffer->cur());
unsigned int first_lig_comp = get_lig_comp (c->buffer->cur());
for (unsigned int i = 1; i < count; i++)
{
unsigned int property;
if (!skippy_iter.next (&property)) return TRACE_RETURN (false);
if (likely (c->buffer->info[skippy_iter.idx].codepoint != component[i])) 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]);
if (first_lig_id && first_lig_comp) {
/* If first component was attached to a previous ligature component,
* all subsequent components should be attached to the same ligature
* component, otherwise we shouldn't ligate them. */
if (first_lig_id != this_lig_id || first_lig_comp != this_lig_comp)
return TRACE_RETURN (false);
} else {
/* If first component was NOT attached to a previous ligature component,
* all subsequent components should also NOT be attached to any ligature
* component, unless they are attached to the first component itself! */
if (this_lig_id && this_lig_comp && (this_lig_id != first_lig_id))
return TRACE_RETURN (false);
}
is_mark_ligature = is_mark_ligature && (property & HB_OT_LAYOUT_GLYPH_CLASS_MARK);
total_component_count += get_lig_num_comps (c->buffer->info[skippy_iter.idx]);
}
if (likely (!match_input (c, count,
&component[1],
match_glyph,
NULL,
&end_offset,
&is_mark_ligature,
&total_component_count)))
return TRACE_RETURN (false);
/* Deal, we are forming the ligature. */
c->buffer->merge_clusters (c->buffer->idx, skippy_iter.idx + 1);
c->buffer->merge_clusters (c->buffer->idx, c->buffer->idx + end_offset);
unsigned int klass = is_mark_ligature ? 0 : HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE;
unsigned int lig_id = is_mark_ligature ? 0 : allocate_lig_id (c->buffer);
unsigned int last_lig_id = get_lig_id (c->buffer->cur());
unsigned int last_num_components = get_lig_num_comps (c->buffer->cur());
unsigned int components_so_far = last_num_components;
ligate_input (c,
count,
&component[1],
ligGlyph,
match_glyph,
NULL,
is_mark_ligature,
total_component_count);
if (!is_mark_ligature)
set_lig_props_for_ligature (c->buffer->cur(), lig_id, total_component_count);
c->replace_glyph (ligGlyph, klass);
for (unsigned int i = 1; i < count; i++)
{
while (c->should_mark_skip_current_glyph ())
{
if (!is_mark_ligature) {
unsigned int new_lig_comp = components_so_far - last_num_components +
MIN (MAX (get_lig_comp (c->buffer->cur()), 1u), last_num_components);
set_lig_props_for_mark (c->buffer->cur(), lig_id, new_lig_comp);
}
c->buffer->next_glyph ();
}
last_lig_id = get_lig_id (c->buffer->cur());
last_num_components = get_lig_num_comps (c->buffer->cur());
components_so_far += last_num_components;
/* Skip the base glyph */
c->buffer->idx++;
}
if (!is_mark_ligature && last_lig_id) {
/* Re-adjust components for any marks following. */
for (unsigned int i = c->buffer->idx; i < c->buffer->len; i++) {
if (last_lig_id == get_lig_id (c->buffer->info[i])) {
unsigned int new_lig_comp = components_so_far - last_num_components +
MIN (MAX (get_lig_comp (c->buffer->info[i]), 1u), last_num_components);
set_lig_props_for_mark (c->buffer->info[i], lig_id, new_lig_comp);
} else
break;
}
}
return TRACE_RETURN (true);
}
inline bool serialize (hb_serialize_context_t *c,
GlyphID ligature,
Supplier<GlyphID> &components, /* Starting from second */
unsigned int num_components /* Including first component */)
{
TRACE_SERIALIZE ();
if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
ligGlyph = ligature;
if (unlikely (!component.serialize (c, components, num_components))) return TRACE_RETURN (false);
return TRACE_RETURN (true);
}
@ -676,6 +718,25 @@ struct LigatureSet
return TRACE_RETURN (false);
}
inline bool serialize (hb_serialize_context_t *c,
Supplier<GlyphID> &ligatures,
Supplier<unsigned int> &component_count_list,
unsigned int num_ligatures,
Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
{
TRACE_SERIALIZE ();
if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
if (unlikely (!ligature.serialize (c, num_ligatures))) return TRACE_RETURN (false);
for (unsigned int i = 0; i < num_ligatures; i++)
if (unlikely (!ligature[i].serialize (c, this).serialize (c,
ligatures[i],
component_list,
component_count_list[i]))) return TRACE_RETURN (false);
ligatures.advance (num_ligatures);
component_count_list.advance (num_ligatures);
return TRACE_RETURN (true);
}
public:
inline bool sanitize (hb_sanitize_context_t *c) {
TRACE_SANITIZE ();
@ -728,6 +789,28 @@ struct LigatureSubstFormat1
return TRACE_RETURN (lig_set.apply (c));
}
inline bool serialize (hb_serialize_context_t *c,
Supplier<GlyphID> &first_glyphs,
Supplier<unsigned int> &ligature_per_first_glyph_count_list,
unsigned int num_first_glyphs,
Supplier<GlyphID> &ligatures_list,
Supplier<unsigned int> &component_count_list,
Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
{
TRACE_SERIALIZE ();
if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
if (unlikely (!ligatureSet.serialize (c, num_first_glyphs))) return TRACE_RETURN (false);
for (unsigned int i = 0; i < num_first_glyphs; i++)
if (unlikely (!ligatureSet[i].serialize (c, this).serialize (c,
ligatures_list,
component_count_list,
ligature_per_first_glyph_count_list[i],
component_list))) return TRACE_RETURN (false);
ligature_per_first_glyph_count_list.advance (num_first_glyphs);
if (unlikely (!coverage.serialize (c, this).serialize (c, first_glyphs, num_first_glyphs))) return TRACE_RETURN (false);
return TRACE_RETURN (true);
}
inline bool sanitize (hb_sanitize_context_t *c) {
TRACE_SANITIZE ();
return TRACE_RETURN (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this));
@ -748,6 +831,7 @@ struct LigatureSubstFormat1
struct LigatureSubst
{
friend struct SubstLookupSubTable;
friend struct SubstLookup;
private:
@ -785,6 +869,25 @@ struct LigatureSubst
}
}
inline bool serialize (hb_serialize_context_t *c,
Supplier<GlyphID> &first_glyphs,
Supplier<unsigned int> &ligature_per_first_glyph_count_list,
unsigned int num_first_glyphs,
Supplier<GlyphID> &ligatures_list,
Supplier<unsigned int> &component_count_list,
Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
{
TRACE_SERIALIZE ();
if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false);
unsigned int format = 1;
u.format.set (format);
switch (u.format) {
case 1: return TRACE_RETURN (u.format1.serialize (c, first_glyphs, ligature_per_first_glyph_count_list, num_first_glyphs,
ligatures_list, component_count_list, component_list));
default:return TRACE_RETURN (false);
}
}
inline bool sanitize (hb_sanitize_context_t *c) {
TRACE_SANITIZE ();
if (!u.format.sanitize (c)) return TRACE_RETURN (false);
@ -1183,10 +1286,10 @@ struct SubstLookup : Lookup
}
}
inline bool would_apply (hb_would_apply_context_t *c) const
inline bool would_apply (hb_would_apply_context_t *c, const hb_set_digest_t *digest) const
{
if (unlikely (!c->len)) return false;
if (!c->digest.may_have (c->glyphs[0])) return false;
if (!digest->may_have (c->glyphs[0])) return false;
unsigned int lookup_type = get_type ();
unsigned int count = get_subtable_count ();
for (unsigned int i = 0; i < count; i++)
@ -1210,11 +1313,11 @@ struct SubstLookup : Lookup
return false;
}
inline bool apply_string (hb_apply_context_t *c) const
inline bool apply_string (hb_apply_context_t *c, const hb_set_digest_t *digest) const
{
bool ret = false;
if (unlikely (!c->buffer->len))
if (unlikely (!c->buffer->len || !c->lookup_mask))
return false;
c->set_lookup (*this);
@ -1228,7 +1331,7 @@ struct SubstLookup : Lookup
while (c->buffer->idx < c->buffer->len)
{
if ((c->buffer->cur().mask & c->lookup_mask) &&
c->digest.may_have (c->buffer->cur().codepoint) &&
digest->may_have (c->buffer->cur().codepoint) &&
apply_once (c))
ret = true;
else
@ -1244,7 +1347,7 @@ struct SubstLookup : Lookup
do
{
if ((c->buffer->cur().mask & c->lookup_mask) &&
c->digest.may_have (c->buffer->cur().codepoint) &&
digest->may_have (c->buffer->cur().codepoint) &&
apply_once (c))
ret = true;
else
@ -1257,7 +1360,66 @@ struct SubstLookup : Lookup
return ret;
}
inline bool sanitize (hb_sanitize_context_t *c) {
private:
inline SubstLookupSubTable& serialize_subtable (hb_serialize_context_t *c,
unsigned int i)
{ return CastR<OffsetArrayOf<SubstLookupSubTable> > (subTable)[i].serialize (c, this); }
public:
inline bool serialize_single (hb_serialize_context_t *c,
uint32_t lookup_props,
Supplier<GlyphID> &glyphs,
Supplier<GlyphID> &substitutes,
unsigned int num_glyphs)
{
TRACE_SERIALIZE ();
if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Single, lookup_props, 1))) return TRACE_RETURN (false);
return TRACE_RETURN (serialize_subtable (c, 0).u.single.serialize (c, glyphs, substitutes, num_glyphs));
}
inline bool serialize_multiple (hb_serialize_context_t *c,
uint32_t lookup_props,
Supplier<GlyphID> &glyphs,
Supplier<unsigned int> &substitute_len_list,
unsigned int num_glyphs,
Supplier<GlyphID> &substitute_glyphs_list)
{
TRACE_SERIALIZE ();
if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Multiple, lookup_props, 1))) return TRACE_RETURN (false);
return TRACE_RETURN (serialize_subtable (c, 0).u.multiple.serialize (c, glyphs, substitute_len_list, num_glyphs,
substitute_glyphs_list));
}
inline bool serialize_alternate (hb_serialize_context_t *c,
uint32_t lookup_props,
Supplier<GlyphID> &glyphs,
Supplier<unsigned int> &alternate_len_list,
unsigned int num_glyphs,
Supplier<GlyphID> &alternate_glyphs_list)
{
TRACE_SERIALIZE ();
if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Alternate, lookup_props, 1))) return TRACE_RETURN (false);
return TRACE_RETURN (serialize_subtable (c, 0).u.alternate.serialize (c, glyphs, alternate_len_list, num_glyphs,
alternate_glyphs_list));
}
inline bool serialize_ligature (hb_serialize_context_t *c,
uint32_t lookup_props,
Supplier<GlyphID> &first_glyphs,
Supplier<unsigned int> &ligature_per_first_glyph_count_list,
unsigned int num_first_glyphs,
Supplier<GlyphID> &ligatures_list,
Supplier<unsigned int> &component_count_list,
Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
{
TRACE_SERIALIZE ();
if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Ligature, lookup_props, 1))) return TRACE_RETURN (false);
return TRACE_RETURN (serialize_subtable (c, 0).u.ligature.serialize (c, first_glyphs, ligature_per_first_glyph_count_list, num_first_glyphs,
ligatures_list, component_count_list, component_list));
}
inline bool sanitize (hb_sanitize_context_t *c)
{
TRACE_SANITIZE ();
if (unlikely (!Lookup::sanitize (c))) return TRACE_RETURN (false);
OffsetArrayOf<SubstLookupSubTable> &list = CastR<OffsetArrayOf<SubstLookupSubTable> > (subTable);
@ -1297,12 +1459,6 @@ struct GSUB : GSUBGPOS
inline void add_coverage (set_t *glyphs, unsigned int lookup_index) const
{ get_lookup (lookup_index).add_coverage (glyphs); }
inline bool would_substitute_lookup (hb_would_apply_context_t *c, unsigned int lookup_index) const
{ return get_lookup (lookup_index).would_apply (c); }
inline bool substitute_lookup (hb_apply_context_t *c, unsigned int lookup_index) const
{ return get_lookup (lookup_index).apply_string (c); }
static inline void substitute_start (hb_font_t *font, hb_buffer_t *buffer);
static inline void substitute_finish (hb_font_t *font, hb_buffer_t *buffer);
@ -1410,5 +1566,7 @@ static inline bool substitute_lookup (hb_apply_context_t *c, unsigned int lookup
}
} // namespace OT
#endif /* HB_OT_LAYOUT_GSUB_TABLE_HH */

View File

@ -34,6 +34,8 @@
#include "hb-set-private.hh"
namespace OT {
#ifndef HB_DEBUG_CLOSURE
#define HB_DEBUG_CLOSURE (HB_DEBUG+0)
@ -76,18 +78,17 @@ struct hb_would_apply_context_t
hb_face_t *face;
const hb_codepoint_t *glyphs;
unsigned int len;
const hb_set_digest_t digest;
bool zero_context;
unsigned int debug_depth;
hb_would_apply_context_t (hb_face_t *face_,
const hb_codepoint_t *glyphs_,
unsigned int len_,
const hb_set_digest_t *digest_
) :
bool zero_context_) :
face (face_),
glyphs (glyphs_),
len (len_),
digest (*digest_),
zero_context (zero_context_),
debug_depth (0) {};
};
@ -113,21 +114,22 @@ struct hb_apply_context_t
unsigned int debug_depth;
const GDEF &gdef;
bool has_glyph_classes;
const hb_set_digest_t digest;
hb_apply_context_t (hb_font_t *font_,
hb_buffer_t *buffer_,
hb_mask_t lookup_mask_,
const hb_set_digest_t *digest_) :
hb_mask_t lookup_mask_) :
font (font_), face (font->face), buffer (buffer_),
direction (buffer_->props.direction),
lookup_mask (lookup_mask_),
nesting_level_left (MAX_NESTING_LEVEL),
lookup_props (0), property (0), debug_depth (0),
gdef (*hb_ot_layout_from_face (face)->gdef),
has_glyph_classes (gdef.has_glyph_classes ()),
digest (*digest_) {}
has_glyph_classes (gdef.has_glyph_classes ()) {}
void set_lookup_props (unsigned int lookup_props_) {
lookup_props = lookup_props_;
}
void set_lookup (const Lookup &l) {
lookup_props = l.get_props ();
@ -416,26 +418,160 @@ static inline bool match_input (hb_apply_context_t *c,
const USHORT input[], /* Array of input values--start with second glyph */
match_func_t match_func,
const void *match_data,
unsigned int *end_offset = NULL)
unsigned int *end_offset = NULL,
bool *p_is_mark_ligature = NULL,
unsigned int *p_total_component_count = NULL)
{
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);
hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, count - 1);
if (skippy_iter.has_no_chance ())
return false;
if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
/*
* This is perhaps the trickiest part of OpenType... Remarks:
*
* - If all components of the ligature were marks, we call this a mark ligature.
*
* - If there is no GDEF, and the ligature is NOT a mark ligature, we categorize
* it as a ligature glyph.
*
* - Ligatures cannot be formed across glyphs attached to different components
* of previous ligatures. Eg. the sequence is LAM,SHADDA,LAM,FATHA,HEH, and
* LAM,LAM,HEH form a ligature, leaving SHADDA,FATHA next to eachother.
* However, it would be wrong to ligate that SHADDA,FATHA sequence.o
* There is an exception to this: If a ligature tries ligating with marks that
* belong to it itself, go ahead, assuming that the font designer knows what
* they are doing (otherwise it can break Indic stuff when a matra wants to
* ligate with a conjunct...)
*/
bool is_mark_ligature = !!(c->property & HB_OT_LAYOUT_GLYPH_CLASS_MARK);
unsigned int total_component_count = 0;
total_component_count += get_lig_num_comps (c->buffer->cur());
unsigned int first_lig_id = get_lig_id (c->buffer->cur());
unsigned int first_lig_comp = get_lig_comp (c->buffer->cur());
for (unsigned int i = 1; i < count; i++)
{
if (!skippy_iter.next ())
return false;
unsigned int property;
if (likely (!match_func (c->buffer->info[skippy_iter.idx].codepoint, input[i - 1], match_data)))
return false;
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;
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]);
if (first_lig_id && first_lig_comp) {
/* If first component was attached to a previous ligature component,
* all subsequent components should be attached to the same ligature
* component, otherwise we shouldn't ligate them. */
if (first_lig_id != this_lig_id || first_lig_comp != this_lig_comp)
return TRACE_RETURN (false);
} else {
/* If first component was NOT attached to a previous ligature component,
* all subsequent components should also NOT be attached to any ligature
* component, unless they are attached to the first component itself! */
if (this_lig_id && this_lig_comp && (this_lig_id != first_lig_id))
return TRACE_RETURN (false);
}
is_mark_ligature = is_mark_ligature && (property & HB_OT_LAYOUT_GLYPH_CLASS_MARK);
total_component_count += get_lig_num_comps (c->buffer->info[skippy_iter.idx]);
}
if (end_offset)
*end_offset = skippy_iter.idx - c->buffer->idx + 1;
if (p_is_mark_ligature)
*p_is_mark_ligature = is_mark_ligature;
if (p_total_component_count)
*p_total_component_count = total_component_count;
return true;
}
static inline void ligate_input (hb_apply_context_t *c,
unsigned int count, /* Including the first glyph (not matched) */
const USHORT input[], /* Array of input values--start with second glyph */
hb_codepoint_t lig_glyph,
match_func_t match_func,
const void *match_data,
bool is_mark_ligature,
unsigned int total_component_count)
{
/*
* - If it *is* a mark ligature, we don't allocate a new ligature id, and leave
* the ligature to keep its old ligature id. This will allow it to attach to
* a base ligature in GPOS. Eg. if the sequence is: LAM,LAM,SHADDA,FATHA,HEH,
* and LAM,LAM,HEH for a ligature, they will leave SHADDA and FATHA wit a
* ligature id and component value of 2. Then if SHADDA,FATHA form a ligature
* later, we don't want them to lose their ligature id/component, otherwise
* GPOS will fail to correctly position the mark ligature on top of the
* LAM,LAM,HEH ligature. See:
* https://bugzilla.gnome.org/show_bug.cgi?id=676343
*
* - If a ligature is formed of components that some of which are also ligatures
* themselves, and those ligature components had marks attached to *their*
* components, we have to attach the marks to the new ligature component
* positions! Now *that*'s tricky! And these marks may be following the
* last component of the whole sequence, so we should loop forward looking
* for them and update them.
*
* Eg. the sequence is LAM,LAM,SHADDA,FATHA,HEH, and the font first forms a
* 'calt' ligature of LAM,HEH, leaving the SHADDA and FATHA with a ligature
* id and component == 1. Now, during 'liga', the LAM and the LAM-HEH ligature
* form a LAM-LAM-HEH ligature. We need to reassign the SHADDA and FATHA to
* the new ligature with a component value of 2.
*
* This in fact happened to a font... See:
* https://bugzilla.gnome.org/show_bug.cgi?id=437633
*/
unsigned int klass = is_mark_ligature ? 0 : HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE;
unsigned int lig_id = is_mark_ligature ? 0 : allocate_lig_id (c->buffer);
unsigned int last_lig_id = get_lig_id (c->buffer->cur());
unsigned int last_num_components = get_lig_num_comps (c->buffer->cur());
unsigned int components_so_far = last_num_components;
if (!is_mark_ligature)
set_lig_props_for_ligature (c->buffer->cur(), lig_id, total_component_count);
c->replace_glyph (lig_glyph, klass);
for (unsigned int i = 1; i < count; i++)
{
while (c->should_mark_skip_current_glyph ())
{
if (!is_mark_ligature) {
unsigned int new_lig_comp = components_so_far - last_num_components +
MIN (MAX (get_lig_comp (c->buffer->cur()), 1u), last_num_components);
set_lig_props_for_mark (c->buffer->cur(), lig_id, new_lig_comp);
}
c->buffer->next_glyph ();
}
last_lig_id = get_lig_id (c->buffer->cur());
last_num_components = get_lig_num_comps (c->buffer->cur());
components_so_far += last_num_components;
/* Skip the base glyph */
c->buffer->idx++;
}
if (!is_mark_ligature && last_lig_id) {
/* Re-adjust components for any marks following. */
for (unsigned int i = c->buffer->idx; i < c->buffer->len; i++) {
if (last_lig_id == get_lig_id (c->buffer->info[i])) {
unsigned int new_lig_comp = components_so_far - last_num_components +
MIN (MAX (get_lig_comp (c->buffer->info[i]), 1u), last_num_components);
set_lig_props_for_mark (c->buffer->info[i], lig_id, new_lig_comp);
} else
break;
}
}
}
static inline bool match_backtrack (hb_apply_context_t *c,
unsigned int count,
@ -443,20 +579,22 @@ static inline bool match_backtrack (hb_apply_context_t *c,
match_func_t match_func,
const void *match_data)
{
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);
hb_apply_context_t::mark_skipping_backward_iterator_t skippy_iter (c, c->buffer->backtrack_len (), count, true);
if (skippy_iter.has_no_chance ())
return false;
return TRACE_RETURN (false);
for (unsigned int i = 0; i < count; i++)
{
if (!skippy_iter.prev ())
return false;
return TRACE_RETURN (false);
if (likely (!match_func (c->buffer->out_info[skippy_iter.idx].codepoint, backtrack[i], match_data)))
return false;
return TRACE_RETURN (false);
}
return true;
return TRACE_RETURN (true);
}
static inline bool match_lookahead (hb_apply_context_t *c,
@ -466,20 +604,22 @@ static inline bool match_lookahead (hb_apply_context_t *c,
const void *match_data,
unsigned int offset)
{
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);
hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx + offset - 1, count, true);
if (skippy_iter.has_no_chance ())
return false;
return TRACE_RETURN (false);
for (unsigned int i = 0; i < count; i++)
{
if (!skippy_iter.next ())
return false;
return TRACE_RETURN (false);
if (likely (!match_func (c->buffer->info[skippy_iter.idx].codepoint, lookahead[i], match_data)))
return false;
return TRACE_RETURN (false);
}
return true;
return TRACE_RETURN (true);
}
@ -1066,8 +1206,7 @@ static inline bool chain_context_would_apply_lookup (hb_would_apply_context_t *c
const LookupRecord lookupRecord[],
ChainContextApplyLookupContext &lookup_context)
{
return !backtrackCount
&& !lookaheadCount
return (c->zero_context ? !backtrackCount && !lookaheadCount : true)
&& would_match_input (c,
inputCount, input,
lookup_context.funcs.match, lookup_context.match_data[1]);
@ -1680,5 +1819,7 @@ struct GSUBGPOS
};
} // namespace OT
#endif /* HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH */

View File

@ -139,9 +139,10 @@ 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,
unsigned int lookup_index,
const hb_codepoint_t *glyphs,
unsigned int glyphs_length,
unsigned int lookup_index);
hb_bool_t zero_context);
/* Should be called before all the substitute_lookup's are done. */
@ -184,15 +185,21 @@ hb_ot_layout_position_finish (hb_font_t *font,
* hb_ot_layout_t
*/
namespace OT {
struct GDEF;
struct GSUB;
struct GPOS;
}
struct hb_ot_layout_t
{
hb_blob_t *gdef_blob;
hb_blob_t *gsub_blob;
hb_blob_t *gpos_blob;
const struct GDEF *gdef;
const struct GSUB *gsub;
const struct GPOS *gpos;
const struct OT::GDEF *gdef;
const struct OT::GSUB *gsub;
const struct OT::GPOS *gpos;
unsigned int gsub_lookup_count;
unsigned int gpos_lookup_count;

View File

@ -35,7 +35,6 @@
#include "hb-ot-layout-gpos-table.hh"
#include "hb-ot-maxp-table.hh"
#include <stdlib.h>
#include <string.h>
@ -49,14 +48,14 @@ _hb_ot_layout_create (hb_face_t *face)
if (unlikely (!layout))
return NULL;
layout->gdef_blob = Sanitizer<GDEF>::sanitize (face->reference_table (HB_OT_TAG_GDEF));
layout->gdef = Sanitizer<GDEF>::lock_instance (layout->gdef_blob);
layout->gdef_blob = OT::Sanitizer<OT::GDEF>::sanitize (face->reference_table (HB_OT_TAG_GDEF));
layout->gdef = OT::Sanitizer<OT::GDEF>::lock_instance (layout->gdef_blob);
layout->gsub_blob = Sanitizer<GSUB>::sanitize (face->reference_table (HB_OT_TAG_GSUB));
layout->gsub = Sanitizer<GSUB>::lock_instance (layout->gsub_blob);
layout->gsub_blob = OT::Sanitizer<OT::GSUB>::sanitize (face->reference_table (HB_OT_TAG_GSUB));
layout->gsub = OT::Sanitizer<OT::GSUB>::lock_instance (layout->gsub_blob);
layout->gpos_blob = Sanitizer<GPOS>::sanitize (face->reference_table (HB_OT_TAG_GPOS));
layout->gpos = Sanitizer<GPOS>::lock_instance (layout->gpos_blob);
layout->gpos_blob = OT::Sanitizer<OT::GPOS>::sanitize (face->reference_table (HB_OT_TAG_GPOS));
layout->gpos = OT::Sanitizer<OT::GPOS>::lock_instance (layout->gpos_blob);
layout->gsub_lookup_count = layout->gsub->get_lookup_count ();
layout->gpos_lookup_count = layout->gpos->get_lookup_count ();
@ -92,22 +91,22 @@ _hb_ot_layout_destroy (hb_ot_layout_t *layout)
free (layout);
}
static inline const GDEF&
static inline const OT::GDEF&
_get_gdef (hb_face_t *face)
{
if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(GDEF);
if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return OT::Null(OT::GDEF);
return *hb_ot_layout_from_face (face)->gdef;
}
static inline const GSUB&
static inline const OT::GSUB&
_get_gsub (hb_face_t *face)
{
if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(GSUB);
if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return OT::Null(OT::GSUB);
return *hb_ot_layout_from_face (face)->gsub;
}
static inline const GPOS&
static inline const OT::GPOS&
_get_gpos (hb_face_t *face)
{
if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(GPOS);
if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return OT::Null(OT::GPOS);
return *hb_ot_layout_from_face (face)->gpos;
}
@ -149,14 +148,14 @@ hb_ot_layout_get_ligature_carets (hb_font_t *font,
* GSUB/GPOS
*/
static const GSUBGPOS&
static const OT::GSUBGPOS&
get_gsubgpos_table (hb_face_t *face,
hb_tag_t table_tag)
{
switch (table_tag) {
case HB_OT_TAG_GSUB: return _get_gsub (face);
case HB_OT_TAG_GPOS: return _get_gpos (face);
default: return Null(GSUBGPOS);
default: return OT::Null(OT::GSUBGPOS);
}
}
@ -168,7 +167,7 @@ hb_ot_layout_table_get_script_tags (hb_face_t *face,
unsigned int *script_count /* IN/OUT */,
hb_tag_t *script_tags /* OUT */)
{
const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
return g.get_script_tags (start_offset, script_count, script_tags);
}
@ -179,8 +178,8 @@ hb_ot_layout_table_find_script (hb_face_t *face,
hb_tag_t script_tag,
unsigned int *script_index)
{
ASSERT_STATIC (Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX);
const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX);
const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
if (g.find_script_index (script_tag, script_index))
return true;
@ -205,8 +204,8 @@ hb_ot_layout_table_choose_script (hb_face_t *face,
unsigned int *script_index,
hb_tag_t *chosen_script)
{
ASSERT_STATIC (Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX);
const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX);
const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
while (*script_tags)
{
@ -254,7 +253,7 @@ hb_ot_layout_table_get_feature_tags (hb_face_t *face,
unsigned int *feature_count /* IN/OUT */,
hb_tag_t *feature_tags /* OUT */)
{
const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
return g.get_feature_tags (start_offset, feature_count, feature_tags);
}
@ -268,7 +267,7 @@ hb_ot_layout_script_get_language_tags (hb_face_t *face,
unsigned int *language_count /* IN/OUT */,
hb_tag_t *language_tags /* OUT */)
{
const Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index);
const OT::Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index);
return s.get_lang_sys_tags (start_offset, language_count, language_tags);
}
@ -280,8 +279,8 @@ hb_ot_layout_script_find_language (hb_face_t *face,
hb_tag_t language_tag,
unsigned int *language_index)
{
ASSERT_STATIC (Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX);
const Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index);
ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX);
const OT::Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index);
if (s.find_lang_sys_index (language_tag, language_index))
return true;
@ -301,7 +300,7 @@ hb_ot_layout_language_get_required_feature_index (hb_face_t *face,
unsigned int language_index,
unsigned int *feature_index)
{
const LangSys &l = get_gsubgpos_table (face, table_tag).get_script (script_index).get_lang_sys (language_index);
const OT::LangSys &l = get_gsubgpos_table (face, table_tag).get_script (script_index).get_lang_sys (language_index);
if (feature_index) *feature_index = l.get_required_feature_index ();
@ -317,8 +316,8 @@ hb_ot_layout_language_get_feature_indexes (hb_face_t *face,
unsigned int *feature_count /* IN/OUT */,
unsigned int *feature_indexes /* OUT */)
{
const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
const LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
return l.get_feature_indexes (start_offset, feature_count, feature_indexes);
}
@ -332,8 +331,8 @@ hb_ot_layout_language_get_feature_tags (hb_face_t *face,
unsigned int *feature_count /* IN/OUT */,
hb_tag_t *feature_tags /* OUT */)
{
const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
const LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
ASSERT_STATIC (sizeof (unsigned int) == sizeof (hb_tag_t));
unsigned int ret = l.get_feature_indexes (start_offset, feature_count, (unsigned int *) feature_tags);
@ -356,9 +355,9 @@ hb_ot_layout_language_find_feature (hb_face_t *face,
hb_tag_t feature_tag,
unsigned int *feature_index)
{
ASSERT_STATIC (Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX);
const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
const LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX);
const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
unsigned int num_features = l.get_feature_count ();
for (unsigned int i = 0; i < num_features; i++) {
@ -382,48 +381,53 @@ hb_ot_layout_feature_get_lookup_indexes (hb_face_t *face,
unsigned int *lookup_count /* IN/OUT */,
unsigned int *lookup_indexes /* OUT */)
{
const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
const Feature &f = g.get_feature (feature_index);
const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
const OT::Feature &f = g.get_feature (feature_index);
return f.get_lookup_indexes (start_offset, lookup_count, lookup_indexes);
}
/*
* GSUB
* OT::GSUB
*/
hb_bool_t
hb_ot_layout_has_substitution (hb_face_t *face)
{
return &_get_gsub (face) != &Null(GSUB);
return &_get_gsub (face) != &OT::Null(OT::GSUB);
}
hb_bool_t
hb_ot_layout_would_substitute_lookup (hb_face_t *face,
unsigned int lookup_index,
const hb_codepoint_t *glyphs,
unsigned int glyphs_length,
unsigned int lookup_index)
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, glyphs, glyphs_length, lookup_index);
return hb_ot_layout_would_substitute_lookup_fast (face, lookup_index, glyphs, glyphs_length, zero_context);
}
hb_bool_t
hb_ot_layout_would_substitute_lookup_fast (hb_face_t *face,
unsigned int lookup_index,
const hb_codepoint_t *glyphs,
unsigned int glyphs_length,
unsigned int lookup_index)
hb_bool_t zero_context)
{
if (unlikely (lookup_index >= hb_ot_layout_from_face (face)->gsub_lookup_count)) return false;
hb_would_apply_context_t c (face, glyphs, glyphs_length, &hb_ot_layout_from_face (face)->gsub_digests[lookup_index]);
return hb_ot_layout_from_face (face)->gsub->would_substitute_lookup (&c, lookup_index);
OT::hb_would_apply_context_t c (face, glyphs, glyphs_length, zero_context);
const OT::SubstLookup& l = hb_ot_layout_from_face (face)->gsub->get_lookup (lookup_index);
return l.would_apply (&c, &hb_ot_layout_from_face (face)->gsub_digests[lookup_index]);
}
void
hb_ot_layout_substitute_start (hb_font_t *font, hb_buffer_t *buffer)
{
GSUB::substitute_start (font, buffer);
OT::GSUB::substitute_start (font, buffer);
}
hb_bool_t
@ -433,39 +437,43 @@ hb_ot_layout_substitute_lookup (hb_font_t *font,
hb_mask_t mask)
{
if (unlikely (lookup_index >= hb_ot_layout_from_face (font->face)->gsub_lookup_count)) return false;
hb_apply_context_t c (font, buffer, mask, &hb_ot_layout_from_face (font->face)->gsub_digests[lookup_index]);
return hb_ot_layout_from_face (font->face)->gsub->substitute_lookup (&c, lookup_index);
OT::hb_apply_context_t c (font, buffer, mask);
const OT::SubstLookup& l = hb_ot_layout_from_face (font->face)->gsub->get_lookup (lookup_index);
return l.apply_string (&c, &hb_ot_layout_from_face (font->face)->gsub_digests[lookup_index]);
}
void
hb_ot_layout_substitute_finish (hb_font_t *font, hb_buffer_t *buffer)
{
GSUB::substitute_finish (font, buffer);
OT::GSUB::substitute_finish (font, buffer);
}
void
hb_ot_layout_substitute_closure_lookup (hb_face_t *face,
hb_set_t *glyphs,
unsigned int lookup_index)
unsigned int lookup_index,
hb_set_t *glyphs)
{
hb_closure_context_t c (face, glyphs);
OT::hb_closure_context_t c (face, glyphs);
_get_gsub (face).closure_lookup (&c, lookup_index);
}
/*
* GPOS
* OT::GPOS
*/
hb_bool_t
hb_ot_layout_has_positioning (hb_face_t *face)
{
return &_get_gpos (face) != &Null(GPOS);
return &_get_gpos (face) != &OT::Null(OT::GPOS);
}
void
hb_ot_layout_position_start (hb_font_t *font, hb_buffer_t *buffer)
{
GPOS::position_start (font, buffer);
OT::GPOS::position_start (font, buffer);
}
hb_bool_t
@ -475,12 +483,16 @@ hb_ot_layout_position_lookup (hb_font_t *font,
hb_mask_t mask)
{
if (unlikely (lookup_index >= hb_ot_layout_from_face (font->face)->gpos_lookup_count)) return false;
hb_apply_context_t c (font, buffer, mask, &hb_ot_layout_from_face (font->face)->gpos_digests[lookup_index]);
return hb_ot_layout_from_face (font->face)->gpos->position_lookup (&c, lookup_index);
OT::hb_apply_context_t c (font, buffer, mask);
const OT::PosLookup& l = hb_ot_layout_from_face (font->face)->gpos->get_lookup (lookup_index);
return l.apply_string (&c, &hb_ot_layout_from_face (font->face)->gpos_digests[lookup_index]);
}
void
hb_ot_layout_position_finish (hb_font_t *font, hb_buffer_t *buffer, hb_bool_t zero_width_attached_marks)
{
GPOS::position_finish (font, buffer, zero_width_attached_marks);
OT::GPOS::position_finish (font, buffer, zero_width_attached_marks);
}

View File

@ -171,14 +171,15 @@ hb_ot_layout_has_substitution (hb_face_t *face);
hb_bool_t
hb_ot_layout_would_substitute_lookup (hb_face_t *face,
unsigned int lookup_index,
const hb_codepoint_t *glyphs,
unsigned int glyphs_length,
unsigned int lookup_index);
hb_bool_t zero_context);
void
hb_ot_layout_substitute_closure_lookup (hb_face_t *face,
hb_set_t *glyphs,
unsigned int lookup_index);
unsigned int lookup_index,
hb_set_t *glyphs);
/*
* GPOS

View File

@ -49,6 +49,7 @@ struct hb_ot_map_t
unsigned int shift;
hb_mask_t mask;
hb_mask_t _1_mask; /* mask for value=1, for quick access */
hb_bool_t needs_fallback;
static int cmp (const feature_map_t *a, const feature_map_t *b)
{ return a->tag < b->tag ? -1 : a->tag > b->tag ? 1 : 0; }
@ -80,6 +81,11 @@ struct hb_ot_map_t
return map ? map->mask : 0;
}
inline bool needs_fallback (hb_tag_t feature_tag) const {
const feature_map_t *map = features.bsearch (&feature_tag);
return map ? map->needs_fallback : false;
}
inline hb_mask_t get_1_mask (hb_tag_t feature_tag) const {
const feature_map_t *map = features.bsearch (&feature_tag);
return map ? map->_1_mask : 0;
@ -147,10 +153,10 @@ struct hb_ot_map_builder_t
hb_ot_map_builder_t (void) { memset (this, 0, sizeof (*this)); }
HB_INTERNAL void add_feature (hb_tag_t tag, unsigned int value, bool global);
HB_INTERNAL void add_feature (hb_tag_t tag, unsigned int value, bool global, bool has_fallback = false);
inline void add_bool_feature (hb_tag_t tag, bool global = true)
{ add_feature (tag, 1, global); }
inline void add_bool_feature (hb_tag_t tag, bool global = true, bool has_fallback = false)
{ add_feature (tag, 1, global, has_fallback); }
inline void add_gsub_pause (hb_ot_map_t::pause_func_t pause_func)
{ add_pause (0, pause_func); }
@ -174,6 +180,7 @@ struct hb_ot_map_builder_t
unsigned int seq; /* sequence#, used for stable sorting only */
unsigned int max_value;
bool global; /* whether the feature applies value to every glyph in the buffer */
bool has_fallback; /* whether to allocate bits even if feature not found */
unsigned int default_value; /* for non-global features, what should the unset glyphs take */
unsigned int stage[2]; /* GSUB/GPOS */

View File

@ -60,7 +60,7 @@ hb_ot_map_t::add_lookups (hb_face_t *face,
}
void hb_ot_map_builder_t::add_feature (hb_tag_t tag, unsigned int value, bool global)
void hb_ot_map_builder_t::add_feature (hb_tag_t tag, unsigned int value, bool global, bool has_fallback)
{
feature_info_t *info = feature_infos.push();
if (unlikely (!info)) return;
@ -68,6 +68,7 @@ void hb_ot_map_builder_t::add_feature (hb_tag_t tag, unsigned int value, bool gl
info->seq = feature_infos.len;
info->max_value = value;
info->global = global;
info->has_fallback = has_fallback;
info->default_value = global ? value : 0;
info->stage[0] = current_stage[0];
info->stage[1] = current_stage[1];
@ -116,16 +117,8 @@ void hb_ot_map_t::position (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_
void hb_ot_map_t::substitute_closure (const hb_ot_shape_plan_t *plan, hb_face_t *face, hb_set_t *glyphs) const
{
unsigned int table_index = 0;
unsigned int i = 0;
for (unsigned int pause_index = 0; pause_index < pauses[table_index].len; pause_index++) {
const pause_map_t *pause = &pauses[table_index][pause_index];
for (; i < pause->num_lookups; i++)
hb_ot_layout_substitute_closure_lookup (face, glyphs, lookups[table_index][i].index);
}
for (; i < lookups[table_index].len; i++)
hb_ot_layout_substitute_closure_lookup (face, glyphs, lookups[table_index][i].index);
for (unsigned int i = 0; i < lookups[table_index].len; i++)
hb_ot_layout_substitute_closure_lookup (face, lookups[table_index][i].index, glyphs);
}
void hb_ot_map_builder_t::add_pause (unsigned int table_index, hb_ot_map_t::pause_func_t pause_func)
@ -183,6 +176,7 @@ hb_ot_map_builder_t::compile (hb_face_t *face,
feature_infos[j].global = false;
feature_infos[j].max_value = MAX (feature_infos[j].max_value, feature_infos[i].max_value);
}
feature_infos[j].has_fallback = feature_infos[j].has_fallback || feature_infos[i].has_fallback;
feature_infos[j].stage[0] = MIN (feature_infos[j].stage[0], feature_infos[i].stage[0]);
feature_infos[j].stage[1] = MIN (feature_infos[j].stage[1], feature_infos[i].stage[1]);
/* Inherit default_value from j */
@ -217,7 +211,7 @@ hb_ot_map_builder_t::compile (hb_face_t *face,
language_index[table_index],
info->tag,
&feature_index[table_index]);
if (!found)
if (!found && !info->has_fallback)
continue;
@ -242,6 +236,7 @@ hb_ot_map_builder_t::compile (hb_face_t *face,
m.global_mask |= (info->default_value << map->shift) & map->mask;
}
map->_1_mask = (1 << map->shift) & map->mask;
map->needs_fallback = !found;
}
feature_infos.shrink (0); /* Done with these */

View File

@ -30,6 +30,8 @@
#include "hb-open-type-private.hh"
namespace OT {
/*
* maxp -- The Maximum Profile Table
@ -61,5 +63,7 @@ struct maxp
};
} // namespace OT
#endif /* HB_OT_MAXP_TABLE_HH */

View File

@ -30,6 +30,8 @@
#include "hb-open-type-private.hh"
namespace OT {
/*
* name -- The Naming Table
@ -124,5 +126,7 @@ struct name
};
} // namespace OT
#endif /* HB_OT_NAME_TABLE_HH */

View File

@ -0,0 +1,253 @@
/*
* Copyright © 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
*/
#ifndef HB_OT_SHAPE_COMPLEX_ARABIC_FALLBACK_HH
#define HB_OT_SHAPE_COMPLEX_ARABIC_FALLBACK_HH
#include "hb-private.hh"
#include "hb-ot-shape-private.hh"
#include "hb-ot-layout-gsub-table.hh"
static const hb_tag_t arabic_fallback_features[] =
{
HB_TAG('i','n','i','t'),
HB_TAG('m','e','d','i'),
HB_TAG('f','i','n','a'),
HB_TAG('i','s','o','l'),
HB_TAG('r','l','i','g'),
};
/* Same order as the fallback feature array */
enum {
FALLBACK_INIT,
FALLBACK_MEDI,
FALLBACK_FINA,
FALLBACK_ISOL,
FALLBACK_RLIG,
ARABIC_NUM_FALLBACK_FEATURES
};
static OT::SubstLookup *
arabic_fallback_synthesize_lookup_single (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
unsigned int feature_index)
{
OT::GlyphID glyphs[SHAPING_TABLE_LAST - SHAPING_TABLE_FIRST + 1];
OT::GlyphID substitutes[SHAPING_TABLE_LAST - SHAPING_TABLE_FIRST + 1];
unsigned int num_glyphs = 0;
/* Populate arrays */
for (hb_codepoint_t u = SHAPING_TABLE_FIRST; u < SHAPING_TABLE_LAST + 1; u++)
{
hb_codepoint_t s = shaping_table[u - SHAPING_TABLE_FIRST][feature_index];
hb_codepoint_t u_glyph, s_glyph;
if (!s ||
!hb_font_get_glyph (font, u, 0, &u_glyph) ||
!hb_font_get_glyph (font, s, 0, &s_glyph) ||
u_glyph == s_glyph ||
u_glyph > 0xFFFF || s_glyph > 0xFFFF)
continue;
glyphs[num_glyphs].set (u_glyph);
substitutes[num_glyphs].set (s_glyph);
num_glyphs++;
}
/* Bubble-sort!
* May not be good-enough for presidential candidate interviews, but good-enough for us... */
hb_bubble_sort (&glyphs[0], num_glyphs, OT::GlyphID::cmp, &substitutes[0]);
OT::Supplier<OT::GlyphID> glyphs_supplier (glyphs, num_glyphs);
OT::Supplier<OT::GlyphID> substitutes_supplier (substitutes, num_glyphs);
/* Each glyph takes four bytes max, and there's some overhead. */
char buf[(SHAPING_TABLE_LAST - SHAPING_TABLE_FIRST + 1) * 4 + 128];
OT::hb_serialize_context_t c (buf, sizeof (buf));
OT::SubstLookup *lookup = c.start_serialize<OT::SubstLookup> ();
bool ret = lookup->serialize_single (&c,
OT::LookupFlag::IgnoreMarks,
glyphs_supplier,
substitutes_supplier,
num_glyphs);
c.end_serialize ();
/* TODO sanitize the results? */
return ret ? c.copy<OT::SubstLookup> () : NULL;
}
static OT::SubstLookup *
arabic_fallback_synthesize_lookup_ligature (const hb_ot_shape_plan_t *plan,
hb_font_t *font)
{
OT::GlyphID first_glyphs[ARRAY_LENGTH_CONST (ligature_table)];
unsigned int first_glyphs_indirection[ARRAY_LENGTH_CONST (ligature_table)];
unsigned int ligature_per_first_glyph_count_list[ARRAY_LENGTH_CONST (first_glyphs)];
unsigned int num_first_glyphs = 0;
/* We know that all our ligatures are 2-component */
OT::GlyphID ligature_list[ARRAY_LENGTH_CONST (first_glyphs) * ARRAY_LENGTH_CONST(ligature_table[0].ligatures)];
unsigned int component_count_list[ARRAY_LENGTH_CONST (ligature_list)];
OT::GlyphID component_list[ARRAY_LENGTH_CONST (ligature_list) * 1/* One extra component per ligature */];
unsigned int num_ligatures = 0;
/* Populate arrays */
/* Sort out the first-glyphs */
for (unsigned int first_glyph_idx = 0; first_glyph_idx < ARRAY_LENGTH (first_glyphs); first_glyph_idx++)
{
hb_codepoint_t first_u = ligature_table[first_glyph_idx].first;
hb_codepoint_t first_glyph;
if (!hb_font_get_glyph (font, first_u, 0, &first_glyph))
continue;
first_glyphs[num_first_glyphs].set (first_glyph);
ligature_per_first_glyph_count_list[num_first_glyphs] = 0;
first_glyphs_indirection[num_first_glyphs] = first_glyph_idx;
num_first_glyphs++;
}
hb_bubble_sort (&first_glyphs[0], num_first_glyphs, OT::GlyphID::cmp, &first_glyphs_indirection[0]);
/* Now that the first-glyphs are sorted, walk again, populate ligatures. */
for (unsigned int i = 0; i < num_first_glyphs; i++)
{
unsigned int first_glyph_idx = first_glyphs_indirection[i];
for (unsigned int second_glyph_idx = 0; second_glyph_idx < ARRAY_LENGTH (ligature_table[0].ligatures); second_glyph_idx++)
{
hb_codepoint_t second_u = ligature_table[first_glyph_idx].ligatures[second_glyph_idx].second;
hb_codepoint_t ligature_u = ligature_table[first_glyph_idx].ligatures[second_glyph_idx].ligature;
hb_codepoint_t second_glyph, ligature_glyph;
if (!second_u ||
!hb_font_get_glyph (font, second_u, 0, &second_glyph) ||
!hb_font_get_glyph (font, ligature_u, 0, &ligature_glyph))
continue;
ligature_per_first_glyph_count_list[i]++;
ligature_list[num_ligatures].set (ligature_glyph);
component_count_list[num_ligatures] = 2;
component_list[num_ligatures].set (second_glyph);
num_ligatures++;
}
}
OT::Supplier<OT::GlyphID> first_glyphs_supplier (first_glyphs, num_first_glyphs);
OT::Supplier<unsigned int > ligature_per_first_glyph_count_supplier (ligature_per_first_glyph_count_list, num_first_glyphs);
OT::Supplier<OT::GlyphID> ligatures_supplier (ligature_list, num_ligatures);
OT::Supplier<unsigned int > component_count_supplier (component_count_list, num_ligatures);
OT::Supplier<OT::GlyphID> component_supplier (component_list, num_ligatures);
/* 16 bytes per ligature ought to be enough... */
char buf[ARRAY_LENGTH_CONST (ligature_list) * 16 + 128];
OT::hb_serialize_context_t c (buf, sizeof (buf));
OT::SubstLookup *lookup = c.start_serialize<OT::SubstLookup> ();
bool ret = lookup->serialize_ligature (&c,
OT::LookupFlag::IgnoreMarks,
first_glyphs_supplier,
ligature_per_first_glyph_count_supplier,
num_first_glyphs,
ligatures_supplier,
component_count_supplier,
component_supplier);
c.end_serialize ();
/* TODO sanitize the results? */
return ret ? c.copy<OT::SubstLookup> () : NULL;
}
static OT::SubstLookup *
arabic_fallback_synthesize_lookup (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
unsigned int feature_index)
{
if (feature_index < 4)
return arabic_fallback_synthesize_lookup_single (plan, font, feature_index);
else
return arabic_fallback_synthesize_lookup_ligature (plan, font);
}
struct arabic_fallback_plan_t
{
ASSERT_POD ();
hb_mask_t mask_array[ARABIC_NUM_FALLBACK_FEATURES];
OT::SubstLookup *lookup_array[ARABIC_NUM_FALLBACK_FEATURES];
hb_set_digest_t digest_array[ARABIC_NUM_FALLBACK_FEATURES];
};
static const arabic_fallback_plan_t arabic_fallback_plan_nil = {};
static arabic_fallback_plan_t *
arabic_fallback_plan_create (const hb_ot_shape_plan_t *plan,
hb_font_t *font)
{
arabic_fallback_plan_t *fallback_plan = (arabic_fallback_plan_t *) calloc (1, sizeof (arabic_fallback_plan_t));
if (unlikely (!fallback_plan))
return const_cast<arabic_fallback_plan_t *> (&arabic_fallback_plan_nil);
for (unsigned int i = 0; i < ARABIC_NUM_FALLBACK_FEATURES; i++) {
fallback_plan->mask_array[i] = plan->map.get_1_mask (arabic_fallback_features[i]);
if (fallback_plan->mask_array[i]) {
fallback_plan->lookup_array[i] = arabic_fallback_synthesize_lookup (plan, font, i);
if (fallback_plan->lookup_array[i])
fallback_plan->lookup_array[i]->add_coverage (&fallback_plan->digest_array[i]);
}
}
return fallback_plan;
}
static void
arabic_fallback_plan_destroy (arabic_fallback_plan_t *fallback_plan)
{
if (!fallback_plan || fallback_plan == &arabic_fallback_plan_nil)
return;
for (unsigned int i = 0; i < ARABIC_NUM_FALLBACK_FEATURES; i++)
if (fallback_plan->lookup_array[i])
free (fallback_plan->lookup_array[i]);
free (fallback_plan);
}
static void
arabic_fallback_plan_shape (arabic_fallback_plan_t *fallback_plan,
hb_font_t *font,
hb_buffer_t *buffer)
{
for (unsigned int i = 0; i < ARABIC_NUM_FALLBACK_FEATURES; i++)
if (fallback_plan->lookup_array[i]) {
OT::hb_apply_context_t c (font, buffer, fallback_plan->mask_array[i]);
fallback_plan->lookup_array[i]->apply_string (&c, &fallback_plan->digest_array[i]);
}
}
#endif /* HB_OT_SHAPE_COMPLEX_ARABIC_FALLBACK_HH */

View File

@ -729,24 +729,24 @@ static const uint8_t joining_table[] =
static const uint16_t shaping_table[][4] =
{
{0x0621, 0x0621, 0x0621, 0xFE80}, /* U+0621 ARABIC LETTER HAMZA ISOLATED FORM */
{0x0622, 0x0622, 0xFE82, 0xFE81}, /* U+0622 ARABIC LETTER ALEF WITH MADDA ABOVE */
{0x0623, 0x0623, 0xFE84, 0xFE83}, /* U+0623 ARABIC LETTER ALEF WITH HAMZA ABOVE */
{0x0624, 0x0624, 0xFE86, 0xFE85}, /* U+0624 ARABIC LETTER WAW WITH HAMZA ABOVE */
{0x0625, 0x0625, 0xFE88, 0xFE87}, /* U+0625 ARABIC LETTER ALEF WITH HAMZA BELOW */
{0x0000, 0x0000, 0x0000, 0xFE80}, /* U+0621 ARABIC LETTER HAMZA ISOLATED FORM */
{0x0000, 0x0000, 0xFE82, 0xFE81}, /* U+0622 ARABIC LETTER ALEF WITH MADDA ABOVE */
{0x0000, 0x0000, 0xFE84, 0xFE83}, /* U+0623 ARABIC LETTER ALEF WITH HAMZA ABOVE */
{0x0000, 0x0000, 0xFE86, 0xFE85}, /* U+0624 ARABIC LETTER WAW WITH HAMZA ABOVE */
{0x0000, 0x0000, 0xFE88, 0xFE87}, /* U+0625 ARABIC LETTER ALEF WITH HAMZA BELOW */
{0xFE8B, 0xFE8C, 0xFE8A, 0xFE89}, /* U+0626 ARABIC LETTER YEH WITH HAMZA ABOVE */
{0x0627, 0x0627, 0xFE8E, 0xFE8D}, /* U+0627 ARABIC LETTER ALEF */
{0x0000, 0x0000, 0xFE8E, 0xFE8D}, /* U+0627 ARABIC LETTER ALEF */
{0xFE91, 0xFE92, 0xFE90, 0xFE8F}, /* U+0628 ARABIC LETTER BEH */
{0x0629, 0x0629, 0xFE94, 0xFE93}, /* U+0629 ARABIC LETTER TEH MARBUTA */
{0x0000, 0x0000, 0xFE94, 0xFE93}, /* U+0629 ARABIC LETTER TEH MARBUTA */
{0xFE97, 0xFE98, 0xFE96, 0xFE95}, /* U+062A ARABIC LETTER TEH */
{0xFE9B, 0xFE9C, 0xFE9A, 0xFE99}, /* U+062B ARABIC LETTER THEH */
{0xFE9F, 0xFEA0, 0xFE9E, 0xFE9D}, /* U+062C ARABIC LETTER JEEM */
{0xFEA3, 0xFEA4, 0xFEA2, 0xFEA1}, /* U+062D ARABIC LETTER HAH */
{0xFEA7, 0xFEA8, 0xFEA6, 0xFEA5}, /* U+062E ARABIC LETTER KHAH */
{0x062F, 0x062F, 0xFEAA, 0xFEA9}, /* U+062F ARABIC LETTER DAL */
{0x0630, 0x0630, 0xFEAC, 0xFEAB}, /* U+0630 ARABIC LETTER THAL */
{0x0631, 0x0631, 0xFEAE, 0xFEAD}, /* U+0631 ARABIC LETTER REH */
{0x0632, 0x0632, 0xFEB0, 0xFEAF}, /* U+0632 ARABIC LETTER ZAIN */
{0x0000, 0x0000, 0xFEAA, 0xFEA9}, /* U+062F ARABIC LETTER DAL */
{0x0000, 0x0000, 0xFEAC, 0xFEAB}, /* U+0630 ARABIC LETTER THAL */
{0x0000, 0x0000, 0xFEAE, 0xFEAD}, /* U+0631 ARABIC LETTER REH */
{0x0000, 0x0000, 0xFEB0, 0xFEAF}, /* U+0632 ARABIC LETTER ZAIN */
{0xFEB3, 0xFEB4, 0xFEB2, 0xFEB1}, /* U+0633 ARABIC LETTER SEEN */
{0xFEB7, 0xFEB8, 0xFEB6, 0xFEB5}, /* U+0634 ARABIC LETTER SHEEN */
{0xFEBB, 0xFEBC, 0xFEBA, 0xFEB9}, /* U+0635 ARABIC LETTER SAD */
@ -755,12 +755,12 @@ static const uint16_t shaping_table[][4] =
{0xFEC7, 0xFEC8, 0xFEC6, 0xFEC5}, /* U+0638 ARABIC LETTER ZAH */
{0xFECB, 0xFECC, 0xFECA, 0xFEC9}, /* U+0639 ARABIC LETTER AIN */
{0xFECF, 0xFED0, 0xFECE, 0xFECD}, /* U+063A ARABIC LETTER GHAIN */
{0x063B, 0x063B, 0x063B, 0x063B}, /* U+063B */
{0x063C, 0x063C, 0x063C, 0x063C}, /* U+063C */
{0x063D, 0x063D, 0x063D, 0x063D}, /* U+063D */
{0x063E, 0x063E, 0x063E, 0x063E}, /* U+063E */
{0x063F, 0x063F, 0x063F, 0x063F}, /* U+063F */
{0x0640, 0x0640, 0x0640, 0x0640}, /* U+0640 */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+063B */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+063C */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+063D */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+063E */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+063F */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+0640 */
{0xFED3, 0xFED4, 0xFED2, 0xFED1}, /* U+0641 ARABIC LETTER FEH */
{0xFED7, 0xFED8, 0xFED6, 0xFED5}, /* U+0642 ARABIC LETTER QAF */
{0xFEDB, 0xFEDC, 0xFEDA, 0xFED9}, /* U+0643 ARABIC LETTER KAF */
@ -768,146 +768,146 @@ static const uint16_t shaping_table[][4] =
{0xFEE3, 0xFEE4, 0xFEE2, 0xFEE1}, /* U+0645 ARABIC LETTER MEEM */
{0xFEE7, 0xFEE8, 0xFEE6, 0xFEE5}, /* U+0646 ARABIC LETTER NOON */
{0xFEEB, 0xFEEC, 0xFEEA, 0xFEE9}, /* U+0647 ARABIC LETTER HEH */
{0x0648, 0x0648, 0xFEEE, 0xFEED}, /* U+0648 ARABIC LETTER WAW */
{0x0000, 0x0000, 0xFEEE, 0xFEED}, /* U+0648 ARABIC LETTER WAW */
{0xFBE8, 0xFBE9, 0xFEF0, 0xFEEF}, /* U+0649 ARABIC LETTER */
{0xFEF3, 0xFEF4, 0xFEF2, 0xFEF1}, /* U+064A ARABIC LETTER YEH */
{0x064B, 0x064B, 0x064B, 0x064B}, /* U+064B */
{0x064C, 0x064C, 0x064C, 0x064C}, /* U+064C */
{0x064D, 0x064D, 0x064D, 0x064D}, /* U+064D */
{0x064E, 0x064E, 0x064E, 0x064E}, /* U+064E */
{0x064F, 0x064F, 0x064F, 0x064F}, /* U+064F */
{0x0650, 0x0650, 0x0650, 0x0650}, /* U+0650 */
{0x0651, 0x0651, 0x0651, 0x0651}, /* U+0651 */
{0x0652, 0x0652, 0x0652, 0x0652}, /* U+0652 */
{0x0653, 0x0653, 0x0653, 0x0653}, /* U+0653 */
{0x0654, 0x0654, 0x0654, 0x0654}, /* U+0654 */
{0x0655, 0x0655, 0x0655, 0x0655}, /* U+0655 */
{0x0656, 0x0656, 0x0656, 0x0656}, /* U+0656 */
{0x0657, 0x0657, 0x0657, 0x0657}, /* U+0657 */
{0x0658, 0x0658, 0x0658, 0x0658}, /* U+0658 */
{0x0659, 0x0659, 0x0659, 0x0659}, /* U+0659 */
{0x065A, 0x065A, 0x065A, 0x065A}, /* U+065A */
{0x065B, 0x065B, 0x065B, 0x065B}, /* U+065B */
{0x065C, 0x065C, 0x065C, 0x065C}, /* U+065C */
{0x065D, 0x065D, 0x065D, 0x065D}, /* U+065D */
{0x065E, 0x065E, 0x065E, 0x065E}, /* U+065E */
{0x065F, 0x065F, 0x065F, 0x065F}, /* U+065F */
{0x0660, 0x0660, 0x0660, 0x0660}, /* U+0660 */
{0x0661, 0x0661, 0x0661, 0x0661}, /* U+0661 */
{0x0662, 0x0662, 0x0662, 0x0662}, /* U+0662 */
{0x0663, 0x0663, 0x0663, 0x0663}, /* U+0663 */
{0x0664, 0x0664, 0x0664, 0x0664}, /* U+0664 */
{0x0665, 0x0665, 0x0665, 0x0665}, /* U+0665 */
{0x0666, 0x0666, 0x0666, 0x0666}, /* U+0666 */
{0x0667, 0x0667, 0x0667, 0x0667}, /* U+0667 */
{0x0668, 0x0668, 0x0668, 0x0668}, /* U+0668 */
{0x0669, 0x0669, 0x0669, 0x0669}, /* U+0669 */
{0x066A, 0x066A, 0x066A, 0x066A}, /* U+066A */
{0x066B, 0x066B, 0x066B, 0x066B}, /* U+066B */
{0x066C, 0x066C, 0x066C, 0x066C}, /* U+066C */
{0x066D, 0x066D, 0x066D, 0x066D}, /* U+066D */
{0x066E, 0x066E, 0x066E, 0x066E}, /* U+066E */
{0x066F, 0x066F, 0x066F, 0x066F}, /* U+066F */
{0x0670, 0x0670, 0x0670, 0x0670}, /* U+0670 */
{0x0671, 0x0671, 0xFB51, 0xFB50}, /* U+0671 ARABIC LETTER ALEF WASLA */
{0x0672, 0x0672, 0x0672, 0x0672}, /* U+0672 */
{0x0673, 0x0673, 0x0673, 0x0673}, /* U+0673 */
{0x0674, 0x0674, 0x0674, 0x0674}, /* U+0674 */
{0x0675, 0x0675, 0x0675, 0x0675}, /* U+0675 */
{0x0676, 0x0676, 0x0676, 0x0676}, /* U+0676 */
{0x0677, 0x0677, 0x0677, 0xFBDD}, /* U+0677 ARABIC LETTER U WITH HAMZA ABOVE ISOLATED FORM */
{0x0678, 0x0678, 0x0678, 0x0678}, /* U+0678 */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+064B */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+064C */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+064D */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+064E */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+064F */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+0650 */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+0651 */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+0652 */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+0653 */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+0654 */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+0655 */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+0656 */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+0657 */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+0658 */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+0659 */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+065A */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+065B */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+065C */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+065D */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+065E */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+065F */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+0660 */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+0661 */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+0662 */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+0663 */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+0664 */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+0665 */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+0666 */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+0667 */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+0668 */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+0669 */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+066A */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+066B */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+066C */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+066D */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+066E */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+066F */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+0670 */
{0x0000, 0x0000, 0xFB51, 0xFB50}, /* U+0671 ARABIC LETTER ALEF WASLA */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+0672 */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+0673 */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+0674 */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+0675 */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+0676 */
{0x0000, 0x0000, 0x0000, 0xFBDD}, /* U+0677 ARABIC LETTER U WITH HAMZA ABOVE ISOLATED FORM */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+0678 */
{0xFB68, 0xFB69, 0xFB67, 0xFB66}, /* U+0679 ARABIC LETTER TTEH */
{0xFB60, 0xFB61, 0xFB5F, 0xFB5E}, /* U+067A ARABIC LETTER TTEHEH */
{0xFB54, 0xFB55, 0xFB53, 0xFB52}, /* U+067B ARABIC LETTER BEEH */
{0x067C, 0x067C, 0x067C, 0x067C}, /* U+067C */
{0x067D, 0x067D, 0x067D, 0x067D}, /* U+067D */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+067C */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+067D */
{0xFB58, 0xFB59, 0xFB57, 0xFB56}, /* U+067E ARABIC LETTER PEH */
{0xFB64, 0xFB65, 0xFB63, 0xFB62}, /* U+067F ARABIC LETTER TEHEH */
{0xFB5C, 0xFB5D, 0xFB5B, 0xFB5A}, /* U+0680 ARABIC LETTER BEHEH */
{0x0681, 0x0681, 0x0681, 0x0681}, /* U+0681 */
{0x0682, 0x0682, 0x0682, 0x0682}, /* U+0682 */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+0681 */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+0682 */
{0xFB78, 0xFB79, 0xFB77, 0xFB76}, /* U+0683 ARABIC LETTER NYEH */
{0xFB74, 0xFB75, 0xFB73, 0xFB72}, /* U+0684 ARABIC LETTER DYEH */
{0x0685, 0x0685, 0x0685, 0x0685}, /* U+0685 */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+0685 */
{0xFB7C, 0xFB7D, 0xFB7B, 0xFB7A}, /* U+0686 ARABIC LETTER TCHEH */
{0xFB80, 0xFB81, 0xFB7F, 0xFB7E}, /* U+0687 ARABIC LETTER TCHEHEH */
{0x0688, 0x0688, 0xFB89, 0xFB88}, /* U+0688 ARABIC LETTER DDAL */
{0x0689, 0x0689, 0x0689, 0x0689}, /* U+0689 */
{0x068A, 0x068A, 0x068A, 0x068A}, /* U+068A */
{0x068B, 0x068B, 0x068B, 0x068B}, /* U+068B */
{0x068C, 0x068C, 0xFB85, 0xFB84}, /* U+068C ARABIC LETTER DAHAL */
{0x068D, 0x068D, 0xFB83, 0xFB82}, /* U+068D ARABIC LETTER DDAHAL */
{0x068E, 0x068E, 0xFB87, 0xFB86}, /* U+068E ARABIC LETTER DUL */
{0x068F, 0x068F, 0x068F, 0x068F}, /* U+068F */
{0x0690, 0x0690, 0x0690, 0x0690}, /* U+0690 */
{0x0691, 0x0691, 0xFB8D, 0xFB8C}, /* U+0691 ARABIC LETTER RREH */
{0x0692, 0x0692, 0x0692, 0x0692}, /* U+0692 */
{0x0693, 0x0693, 0x0693, 0x0693}, /* U+0693 */
{0x0694, 0x0694, 0x0694, 0x0694}, /* U+0694 */
{0x0695, 0x0695, 0x0695, 0x0695}, /* U+0695 */
{0x0696, 0x0696, 0x0696, 0x0696}, /* U+0696 */
{0x0697, 0x0697, 0x0697, 0x0697}, /* U+0697 */
{0x0698, 0x0698, 0xFB8B, 0xFB8A}, /* U+0698 ARABIC LETTER JEH */
{0x0699, 0x0699, 0x0699, 0x0699}, /* U+0699 */
{0x069A, 0x069A, 0x069A, 0x069A}, /* U+069A */
{0x069B, 0x069B, 0x069B, 0x069B}, /* U+069B */
{0x069C, 0x069C, 0x069C, 0x069C}, /* U+069C */
{0x069D, 0x069D, 0x069D, 0x069D}, /* U+069D */
{0x069E, 0x069E, 0x069E, 0x069E}, /* U+069E */
{0x069F, 0x069F, 0x069F, 0x069F}, /* U+069F */
{0x06A0, 0x06A0, 0x06A0, 0x06A0}, /* U+06A0 */
{0x06A1, 0x06A1, 0x06A1, 0x06A1}, /* U+06A1 */
{0x06A2, 0x06A2, 0x06A2, 0x06A2}, /* U+06A2 */
{0x06A3, 0x06A3, 0x06A3, 0x06A3}, /* U+06A3 */
{0x0000, 0x0000, 0xFB89, 0xFB88}, /* U+0688 ARABIC LETTER DDAL */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+0689 */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+068A */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+068B */
{0x0000, 0x0000, 0xFB85, 0xFB84}, /* U+068C ARABIC LETTER DAHAL */
{0x0000, 0x0000, 0xFB83, 0xFB82}, /* U+068D ARABIC LETTER DDAHAL */
{0x0000, 0x0000, 0xFB87, 0xFB86}, /* U+068E ARABIC LETTER DUL */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+068F */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+0690 */
{0x0000, 0x0000, 0xFB8D, 0xFB8C}, /* U+0691 ARABIC LETTER RREH */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+0692 */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+0693 */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+0694 */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+0695 */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+0696 */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+0697 */
{0x0000, 0x0000, 0xFB8B, 0xFB8A}, /* U+0698 ARABIC LETTER JEH */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+0699 */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+069A */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+069B */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+069C */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+069D */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+069E */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+069F */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+06A0 */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+06A1 */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+06A2 */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+06A3 */
{0xFB6C, 0xFB6D, 0xFB6B, 0xFB6A}, /* U+06A4 ARABIC LETTER VEH */
{0x06A5, 0x06A5, 0x06A5, 0x06A5}, /* U+06A5 */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+06A5 */
{0xFB70, 0xFB71, 0xFB6F, 0xFB6E}, /* U+06A6 ARABIC LETTER PEHEH */
{0x06A7, 0x06A7, 0x06A7, 0x06A7}, /* U+06A7 */
{0x06A8, 0x06A8, 0x06A8, 0x06A8}, /* U+06A8 */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+06A7 */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+06A8 */
{0xFB90, 0xFB91, 0xFB8F, 0xFB8E}, /* U+06A9 ARABIC LETTER KEHEH */
{0x06AA, 0x06AA, 0x06AA, 0x06AA}, /* U+06AA */
{0x06AB, 0x06AB, 0x06AB, 0x06AB}, /* U+06AB */
{0x06AC, 0x06AC, 0x06AC, 0x06AC}, /* U+06AC */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+06AA */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+06AB */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+06AC */
{0xFBD5, 0xFBD6, 0xFBD4, 0xFBD3}, /* U+06AD ARABIC LETTER NG */
{0x06AE, 0x06AE, 0x06AE, 0x06AE}, /* U+06AE */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+06AE */
{0xFB94, 0xFB95, 0xFB93, 0xFB92}, /* U+06AF ARABIC LETTER GAF */
{0x06B0, 0x06B0, 0x06B0, 0x06B0}, /* U+06B0 */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+06B0 */
{0xFB9C, 0xFB9D, 0xFB9B, 0xFB9A}, /* U+06B1 ARABIC LETTER NGOEH */
{0x06B2, 0x06B2, 0x06B2, 0x06B2}, /* U+06B2 */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+06B2 */
{0xFB98, 0xFB99, 0xFB97, 0xFB96}, /* U+06B3 ARABIC LETTER GUEH */
{0x06B4, 0x06B4, 0x06B4, 0x06B4}, /* U+06B4 */
{0x06B5, 0x06B5, 0x06B5, 0x06B5}, /* U+06B5 */
{0x06B6, 0x06B6, 0x06B6, 0x06B6}, /* U+06B6 */
{0x06B7, 0x06B7, 0x06B7, 0x06B7}, /* U+06B7 */
{0x06B8, 0x06B8, 0x06B8, 0x06B8}, /* U+06B8 */
{0x06B9, 0x06B9, 0x06B9, 0x06B9}, /* U+06B9 */
{0x06BA, 0x06BA, 0xFB9F, 0xFB9E}, /* U+06BA ARABIC LETTER NOON GHUNNA */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+06B4 */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+06B5 */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+06B6 */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+06B7 */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+06B8 */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+06B9 */
{0x0000, 0x0000, 0xFB9F, 0xFB9E}, /* U+06BA ARABIC LETTER NOON GHUNNA */
{0xFBA2, 0xFBA3, 0xFBA1, 0xFBA0}, /* U+06BB ARABIC LETTER RNOON */
{0x06BC, 0x06BC, 0x06BC, 0x06BC}, /* U+06BC */
{0x06BD, 0x06BD, 0x06BD, 0x06BD}, /* U+06BD */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+06BC */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+06BD */
{0xFBAC, 0xFBAD, 0xFBAB, 0xFBAA}, /* U+06BE ARABIC LETTER HEH DOACHASHMEE */
{0x06BF, 0x06BF, 0x06BF, 0x06BF}, /* U+06BF */
{0x06C0, 0x06C0, 0xFBA5, 0xFBA4}, /* U+06C0 ARABIC LETTER HEH WITH YEH ABOVE */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+06BF */
{0x0000, 0x0000, 0xFBA5, 0xFBA4}, /* U+06C0 ARABIC LETTER HEH WITH YEH ABOVE */
{0xFBA8, 0xFBA9, 0xFBA7, 0xFBA6}, /* U+06C1 ARABIC LETTER HEH GOAL */
{0x06C2, 0x06C2, 0x06C2, 0x06C2}, /* U+06C2 */
{0x06C3, 0x06C3, 0x06C3, 0x06C3}, /* U+06C3 */
{0x06C4, 0x06C4, 0x06C4, 0x06C4}, /* U+06C4 */
{0x06C5, 0x06C5, 0xFBE1, 0xFBE0}, /* U+06C5 ARABIC LETTER KIRGHIZ OE */
{0x06C6, 0x06C6, 0xFBDA, 0xFBD9}, /* U+06C6 ARABIC LETTER OE */
{0x06C7, 0x06C7, 0xFBD8, 0xFBD7}, /* U+06C7 ARABIC LETTER U */
{0x06C8, 0x06C8, 0xFBDC, 0xFBDB}, /* U+06C8 ARABIC LETTER YU */
{0x06C9, 0x06C9, 0xFBE3, 0xFBE2}, /* U+06C9 ARABIC LETTER KIRGHIZ YU */
{0x06CA, 0x06CA, 0x06CA, 0x06CA}, /* U+06CA */
{0x06CB, 0x06CB, 0xFBDF, 0xFBDE}, /* U+06CB ARABIC LETTER VE */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+06C2 */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+06C3 */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+06C4 */
{0x0000, 0x0000, 0xFBE1, 0xFBE0}, /* U+06C5 ARABIC LETTER KIRGHIZ OE */
{0x0000, 0x0000, 0xFBDA, 0xFBD9}, /* U+06C6 ARABIC LETTER OE */
{0x0000, 0x0000, 0xFBD8, 0xFBD7}, /* U+06C7 ARABIC LETTER U */
{0x0000, 0x0000, 0xFBDC, 0xFBDB}, /* U+06C8 ARABIC LETTER YU */
{0x0000, 0x0000, 0xFBE3, 0xFBE2}, /* U+06C9 ARABIC LETTER KIRGHIZ YU */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+06CA */
{0x0000, 0x0000, 0xFBDF, 0xFBDE}, /* U+06CB ARABIC LETTER VE */
{0xFBFE, 0xFBFF, 0xFBFD, 0xFBFC}, /* U+06CC ARABIC LETTER FARSI YEH */
{0x06CD, 0x06CD, 0x06CD, 0x06CD}, /* U+06CD */
{0x06CE, 0x06CE, 0x06CE, 0x06CE}, /* U+06CE */
{0x06CF, 0x06CF, 0x06CF, 0x06CF}, /* U+06CF */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+06CD */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+06CE */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+06CF */
{0xFBE6, 0xFBE7, 0xFBE5, 0xFBE4}, /* U+06D0 ARABIC LETTER E */
{0x06D1, 0x06D1, 0x06D1, 0x06D1}, /* U+06D1 */
{0x06D2, 0x06D2, 0xFBAF, 0xFBAE}, /* U+06D2 ARABIC LETTER YEH BARREE */
{0x06D3, 0x06D3, 0xFBB1, 0xFBB0}, /* U+06D3 ARABIC LETTER YEH BARREE WITH HAMZA ABOVE */
{0x0000, 0x0000, 0x0000, 0x0000}, /* U+06D1 */
{0x0000, 0x0000, 0xFBAF, 0xFBAE}, /* U+06D2 ARABIC LETTER YEH BARREE */
{0x0000, 0x0000, 0xFBB1, 0xFBB0}, /* U+06D3 ARABIC LETTER YEH BARREE WITH HAMZA ABOVE */
};
#define SHAPING_TABLE_FIRST 0x0621

View File

@ -28,7 +28,6 @@
#include "hb-ot-shape-private.hh"
/* buffer var allocations */
#define arabic_shaping_action() complex_var_u8_0() /* arabic shaping action */
@ -81,24 +80,6 @@ static unsigned int get_joining_type (hb_codepoint_t u, hb_unicode_general_categ
JOINING_TYPE_T : JOINING_TYPE_U;
}
static hb_codepoint_t get_arabic_shape (hb_codepoint_t u, unsigned int shape)
{
if (likely (hb_in_range<hb_codepoint_t> (u, SHAPING_TABLE_FIRST, SHAPING_TABLE_LAST)) && shape < 4)
return shaping_table[u - SHAPING_TABLE_FIRST][shape];
return u;
}
static uint16_t get_ligature (hb_codepoint_t first, hb_codepoint_t second)
{
if (unlikely (!second)) return 0;
for (unsigned i = 0; i < ARRAY_LENGTH (ligature_table); i++)
if (ligature_table[i].first == first)
for (unsigned j = 0; j < ARRAY_LENGTH (ligature_table[i].ligatures); j++)
if (ligature_table[i].ligatures[j].second == second)
return ligature_table[i].ligatures[j].ligature;
return 0;
}
static const hb_tag_t arabic_features[] =
{
HB_TAG('i','n','i','t'),
@ -161,6 +142,10 @@ static const struct arabic_state_table_entry {
};
static void
arabic_fallback_shape (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer);
static void
collect_features_arabic (hb_ot_shape_planner_t *plan)
@ -183,12 +168,12 @@ collect_features_arabic (hb_ot_shape_planner_t *plan)
map->add_gsub_pause (NULL);
for (unsigned int i = 0; i < ARABIC_NUM_FEATURES; i++)
map->add_bool_feature (arabic_features[i], false);
map->add_bool_feature (arabic_features[i], false, i < 4); /* The first four features have fallback. */
map->add_gsub_pause (NULL);
map->add_bool_feature (HB_TAG('r','l','i','g'));
map->add_gsub_pause (NULL);
map->add_bool_feature (HB_TAG('r','l','i','g'), true, true);
map->add_gsub_pause (arabic_fallback_shape);
map->add_bool_feature (HB_TAG('c','a','l','t'));
map->add_gsub_pause (NULL);
@ -197,16 +182,20 @@ collect_features_arabic (hb_ot_shape_planner_t *plan)
map->add_bool_feature (HB_TAG('c','s','w','h'));
}
#include "hb-ot-shape-complex-arabic-fallback.hh"
struct arabic_shape_plan_t
{
ASSERT_POD ();
bool do_fallback;
/* The "+ 1" in the next array is to accommodate for the "NONE" command,
* which is not an OpenType feature, but this simplifies the code by not
* having to do a "if (... < NONE) ..." and just rely on the fact that
* mask_array[NONE] == 0. */
hb_mask_t mask_array[ARABIC_NUM_FEATURES + 1];
bool do_fallback;
arabic_fallback_plan_t *fallback_plan;
};
static void *
@ -216,75 +205,47 @@ data_create_arabic (const hb_ot_shape_plan_t *plan)
if (unlikely (!arabic_plan))
return NULL;
hb_mask_t total_masks = 0;
arabic_plan->do_fallback = plan->props.script == HB_SCRIPT_ARABIC;
for (unsigned int i = 0; i < ARABIC_NUM_FEATURES; i++) {
arabic_plan->mask_array[i] = plan->map.get_1_mask (arabic_features[i]);
total_masks |= arabic_plan->mask_array[i];
if (i < 4)
arabic_plan->do_fallback = arabic_plan->do_fallback && plan->map.needs_fallback (arabic_features[i]);
}
/* Pitfalls:
* - This path fires if user force-set init/medi/fina/isol off,
* - If font does not declare script 'arab', well, what to do?
* Most probably it's safe to assume that init/medi/fina/isol
* still mean Arabic shaping, although they do not have to.
*/
arabic_plan->do_fallback = 0 == total_masks;
return arabic_plan;
}
static void
data_destroy_arabic (void *data)
{
arabic_shape_plan_t *arabic_plan = (arabic_shape_plan_t *) data;
arabic_fallback_plan_destroy (arabic_plan->fallback_plan);
free (data);
}
static void
arabic_fallback_shape (hb_font_t *font, hb_buffer_t *buffer)
{
/* Only Arabic has presentation forms encoded in Unicode. */
if (buffer->props.script != HB_SCRIPT_ARABIC)
return;
unsigned int count = buffer->len;
hb_codepoint_t glyph;
/* Shape to presentation forms */
for (unsigned int i = 0; i < count; i++) {
hb_codepoint_t u = buffer->info[i].codepoint;
hb_codepoint_t shaped = get_arabic_shape (u, buffer->info[i].arabic_shaping_action());
if (shaped != u && font->get_glyph (shaped, 0, &glyph))
buffer->info[i].codepoint = shaped;
}
/* Mandatory ligatures */
buffer->clear_output ();
for (buffer->idx = 0; buffer->idx + 1 < count;) {
hb_codepoint_t ligature = get_ligature (buffer->cur().codepoint,
buffer->cur(+1).codepoint);
if (likely (!ligature) || !(font->get_glyph (ligature, 0, &glyph))) {
buffer->next_glyph ();
continue;
}
buffer->replace_glyphs (2, 1, &ligature);
/* Technically speaking we can skip marks and stuff, like the GSUB path does.
* But who cares, we're in fallback! */
}
for (; buffer->idx < count;)
buffer->next_glyph ();
buffer->swap_buffers ();
}
static void
arabic_joining (hb_buffer_t *buffer)
{
unsigned int count = buffer->len;
unsigned int prev = 0, state = 0;
unsigned int prev = (unsigned int) -1, state = 0;
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 (unlikely (this_type == JOINING_TYPE_T))
continue;
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++)
{
unsigned int this_type = get_joining_type (buffer->info[i].codepoint, _hb_glyph_info_get_general_category (&buffer->info[i]));
@ -296,7 +257,7 @@ arabic_joining (hb_buffer_t *buffer)
const arabic_state_table_entry *entry = &arabic_state_table[state][this_type];
if (entry->prev_action != NONE)
if (entry->prev_action != NONE && prev != (unsigned int) -1)
buffer->info[prev].arabic_shaping_action() = entry->prev_action;
buffer->info[i].arabic_shaping_action() = entry->curr_action;
@ -305,21 +266,21 @@ arabic_joining (hb_buffer_t *buffer)
state = entry->next_state;
}
HB_BUFFER_DEALLOCATE_VAR (buffer, arabic_shaping_action);
}
static void
preprocess_text_arabic (const hb_ot_shape_plan_t *plan,
hb_buffer_t *buffer,
hb_font_t *font)
{
const arabic_shape_plan_t *arabic_plan = (const arabic_shape_plan_t *) plan->data;
if (unlikely (arabic_plan->do_fallback))
for (unsigned int i = 0; i < buffer->context_len[1]; i++)
{
arabic_joining (buffer);
arabic_fallback_shape (font, buffer);
unsigned int this_type = get_joining_type (buffer->context[1][i], buffer->unicode->general_category (buffer->context[0][i]));
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;
}
HB_BUFFER_DEALLOCATE_VAR (buffer, arabic_shaping_action);
}
static void
@ -329,15 +290,39 @@ setup_masks_arabic (const hb_ot_shape_plan_t *plan,
{
const arabic_shape_plan_t *arabic_plan = (const arabic_shape_plan_t *) plan->data;
if (likely (!arabic_plan->do_fallback))
{
arabic_joining (buffer);
unsigned int count = buffer->len;
for (unsigned int i = 0; i < count; i++)
buffer->info[i].mask |= arabic_plan->mask_array[buffer->info[i].arabic_shaping_action()];
}
arabic_joining (buffer);
unsigned int count = buffer->len;
for (unsigned int i = 0; i < count; i++)
buffer->info[i].mask |= arabic_plan->mask_array[buffer->info[i].arabic_shaping_action()];
}
static void
arabic_fallback_shape (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer)
{
const arabic_shape_plan_t *arabic_plan = (const arabic_shape_plan_t *) plan->data;
if (!arabic_plan->do_fallback)
return;
retry:
arabic_fallback_plan_t *fallback_plan = (arabic_fallback_plan_t *) hb_atomic_ptr_get (&arabic_plan->fallback_plan);
if (unlikely (!fallback_plan))
{
/* This sucks. We need a font to build the fallback plan... */
fallback_plan = arabic_fallback_plan_create (plan, font);
if (unlikely (!hb_atomic_ptr_cmpexch (&(const_cast<arabic_shape_plan_t *> (arabic_plan))->fallback_plan, NULL, fallback_plan))) {
arabic_fallback_plan_destroy (fallback_plan);
goto retry;
}
}
arabic_fallback_plan_shape (fallback_plan, font, buffer);
}
const hb_ot_complex_shaper_t _hb_ot_complex_shaper_arabic =
{
"arabic",
@ -345,7 +330,7 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_arabic =
NULL, /* override_features */
data_create_arabic,
data_destroy_arabic,
preprocess_text_arabic,
NULL, /* preprocess_text_arabic */
NULL, /* normalization_preference */
setup_masks_arabic,
true, /* zero_width_attached_marks */

File diff suppressed because it is too large Load Diff

View File

@ -62,44 +62,45 @@ z = ZWJ|ZWNJ; # is_joiner
h = H | Coeng; # is_halant_or_coeng
reph = (Ra H | Repha); # possible reph
cn = c.n?;
cn = c.ZWJ?.n?;
forced_rakar = ZWJ H ZWJ Ra;
matra_group = z{0,3}.M.N?.(H | forced_rakar)?;
syllable_tail = (SM.ZWNJ?)? (Coeng (cn|V))? (VD VD?)?;
syllable_tail = (Coeng (cn|V))? (SM.ZWNJ?)? (VD VD?)?;
place_holder = NBSP | DOTTEDCIRCLE;
halant_group = (z?.h.ZWJ?);
halant_group = (z?.h.(ZWJ.N?)?);
final_halant_group = halant_group | h.ZWNJ;
halant_or_matra_group = (final_halant_group | matra_group{0,4});
halant_or_matra_group = (final_halant_group | (h.ZWJ)? matra_group{0,4});
consonant_syllable = Repha? (cn.halant_group){0,4} cn A? halant_or_matra_group? syllable_tail;
vowel_syllable = reph? V.n? (ZWJ | (halant_group.cn){0,4} halant_or_matra_group? syllable_tail);
standalone_cluster = reph? place_holder.n? (halant_group.cn){0,4} halant_or_matra_group? syllable_tail;
broken_cluster = n? (halant_group.cn){0,4} halant_or_matra_group syllable_tail;
other = any;
main := |*
consonant_syllable => { process_syllable (consonant_syllable); };
vowel_syllable => { process_syllable (vowel_syllable); };
standalone_cluster => { process_syllable (standalone_cluster); };
other => { process_syllable (non_indic); };
consonant_syllable => { found_syllable (consonant_syllable); };
vowel_syllable => { found_syllable (vowel_syllable); };
standalone_cluster => { found_syllable (standalone_cluster); };
broken_cluster => { found_syllable (broken_cluster); };
other => { found_syllable (non_indic_cluster); };
*|;
}%%
#define process_syllable(func) \
#define found_syllable(syllable_type) \
HB_STMT_START { \
if (0) fprintf (stderr, "syllable %d..%d %s\n", last, p+1, #func); \
if (0) fprintf (stderr, "syllable %d..%d %s\n", last, p+1, #syllable_type); \
for (unsigned int i = last; i < p+1; i++) \
info[i].syllable() = syllable_serial; \
PASTE (initial_reordering_, func) (plan, buffer, last, p+1); \
info[i].syllable() = (syllable_serial << 4) | syllable_type; \
last = p+1; \
syllable_serial++; \
if (unlikely (!syllable_serial)) syllable_serial++; \
if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
} HB_STMT_END
static void
find_syllables (const hb_ot_shape_plan_t *plan, hb_buffer_t *buffer)
find_syllables (hb_buffer_t *buffer)
{
unsigned int p, pe, eof, ts, te, act;
int cs;
@ -113,7 +114,7 @@ find_syllables (const hb_ot_shape_plan_t *plan, hb_buffer_t *buffer)
pe = eof = buffer->len;
unsigned int last = 0;
uint8_t syllable_serial = 1;
unsigned int syllable_serial = 1;
%%{
write exec;
}%%

View File

@ -300,7 +300,7 @@ is_halant_or_coeng (const hb_glyph_info_t &info)
}
static inline void
set_indic_properties (hb_glyph_info_t &info)
set_indic_properties (hb_glyph_info_t &info)
{
hb_codepoint_t u = info.codepoint;
unsigned int type = get_indic_categories (u);

View File

@ -202,6 +202,10 @@ enum {
INDIC_BASIC_FEATURES = INIT /* Don't forget to update this! */
};
static void
setup_syllables (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer);
static void
initial_reordering (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
@ -216,6 +220,9 @@ collect_features_indic (hb_ot_shape_planner_t *plan)
{
hb_ot_map_builder_t *map = &plan->map;
/* Do this before any lookups have been applied. */
map->add_gsub_pause (setup_syllables);
map->add_bool_feature (HB_TAG('l','o','c','l'));
/* The Indic specs do not require ccmp, but we apply it here since if
* there is a use of it, it's typically at the beginning. */
@ -254,10 +261,11 @@ struct would_substitute_feature_t
inline bool would_substitute (hb_codepoint_t *glyphs,
unsigned int glyphs_count,
bool zero_context,
hb_face_t *face) const
{
for (unsigned int i = 0; i < count; i++)
if (hb_ot_layout_would_substitute_lookup_fast (face, glyphs, glyphs_count, lookups[i].index))
if (hb_ot_layout_would_substitute_lookup_fast (face, lookups[i].index, glyphs, glyphs_count, zero_context))
return true;
return false;
}
@ -340,13 +348,25 @@ consonant_position_from_face (const indic_shape_plan_t *indic_plan,
hb_codepoint_t *glyphs, unsigned int glyphs_len,
hb_face_t *face)
{
if (indic_plan->pref.would_substitute (glyphs, glyphs_len, face)) return POS_BELOW_C;
if (indic_plan->blwf.would_substitute (glyphs, glyphs_len, face)) return POS_BELOW_C;
if (indic_plan->pstf.would_substitute (glyphs, glyphs_len, face)) return POS_POST_C;
bool zero_context = indic_plan->is_old_spec ? false : true;
if (indic_plan->pref.would_substitute (glyphs, glyphs_len, zero_context, face)) return POS_BELOW_C;
if (indic_plan->blwf.would_substitute (glyphs, glyphs_len, zero_context, face)) return POS_BELOW_C;
if (indic_plan->pstf.would_substitute (glyphs, glyphs_len, zero_context, face)) return POS_POST_C;
return POS_BASE_C;
}
enum syllable_type_t {
consonant_syllable,
vowel_syllable,
standalone_cluster,
broken_cluster,
non_indic_cluster,
};
#include "hb-ot-shape-complex-indic-machine.hh"
static void
setup_masks_indic (const hb_ot_shape_plan_t *plan HB_UNUSED,
hb_buffer_t *buffer,
@ -363,6 +383,14 @@ setup_masks_indic (const hb_ot_shape_plan_t *plan HB_UNUSED,
set_indic_properties (buffer->info[i]);
}
static void
setup_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED,
hb_font_t *font HB_UNUSED,
hb_buffer_t *buffer)
{
find_syllables (buffer);
}
static int
compare_indic_order (const hb_glyph_info_t *pa, const hb_glyph_info_t *pb)
{
@ -445,7 +473,7 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, hb_buffer
has_reph = true;
};
switch (indic_plan->config->base_pos == BASE_POS_LAST)
switch (indic_plan->config->base_pos)
{
case BASE_POS_LAST:
{
@ -694,13 +722,12 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, hb_buffer
info[i].mask |= mask;
}
/* XXX This will not match for old-Indic spec since the Halant-Ra order is reversed already. */
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]) &&
info[i + 1].indic_category() == OT_Ra)
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)
{
info[i++].mask |= indic_plan->mask_array[PREF];
info[i++].mask |= indic_plan->mask_array[PREF];
@ -769,15 +796,87 @@ initial_reordering_standalone_cluster (const hb_ot_shape_plan_t *plan,
}
static void
initial_reordering_non_indic (const hb_ot_shape_plan_t *plan HB_UNUSED,
hb_buffer_t *buffer HB_UNUSED,
unsigned int start HB_UNUSED, unsigned int end HB_UNUSED)
initial_reordering_broken_cluster (const hb_ot_shape_plan_t *plan,
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);
}
static void
initial_reordering_non_indic_cluster (const hb_ot_shape_plan_t *plan HB_UNUSED,
hb_buffer_t *buffer HB_UNUSED,
unsigned int start HB_UNUSED, unsigned int end HB_UNUSED)
{
/* Nothing to do right now. If we ever switch to using the output
* buffer in the reordering process, we'd need to next_glyph() here. */
}
#include "hb-ot-shape-complex-indic-machine.hh"
static void
initial_reordering_syllable (const hb_ot_shape_plan_t *plan,
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;
}
}
static inline void
insert_dotted_circles (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer)
{
/* Note: This loop is extra overhead, but should not be measurable. */
bool has_broken_syllables = false;
unsigned int count = buffer->len;
for (unsigned int i = 0; i < count; i++)
if ((buffer->info[i].syllable() & 0x0F) == broken_cluster) {
has_broken_syllables = true;
break;
}
if (likely (!has_broken_syllables))
return;
hb_codepoint_t dottedcircle_glyph;
if (!font->get_glyph (0x25CC, 0, &dottedcircle_glyph))
return;
hb_glyph_info_t dottedcircle;
dottedcircle.codepoint = 0x25CC;
set_indic_properties (dottedcircle);
dottedcircle.codepoint = dottedcircle_glyph;
buffer->clear_output ();
buffer->idx = 0;
unsigned int last_syllable = 0;
while (buffer->idx < buffer->len)
{
unsigned int syllable = buffer->cur().syllable();
syllable_type_t syllable_type = (syllable_type_t) (syllable & 0x0F);
if (unlikely (last_syllable != syllable && syllable_type == broken_cluster))
{
hb_glyph_info_t info = dottedcircle;
info.cluster = buffer->cur().cluster;
info.mask = buffer->cur().mask;
info.syllable() = buffer->cur().syllable();
buffer->output_info (info);
last_syllable = syllable;
}
buffer->next_glyph ();
}
buffer->swap_buffers ();
}
static void
initial_reordering (const hb_ot_shape_plan_t *plan,
@ -785,7 +884,20 @@ initial_reordering (const hb_ot_shape_plan_t *plan,
hb_buffer_t *buffer)
{
update_consonant_positions (plan, font, buffer);
find_syllables (plan, buffer);
insert_dotted_circles (plan, font, buffer);
hb_glyph_info_t *info = buffer->info;
unsigned int count = buffer->len;
if (unlikely (!count)) return;
unsigned int last = 0;
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);
last = i;
last_syllable = info[last].syllable();
}
initial_reordering_syllable (plan, buffer, last, count);
}
static void
@ -829,11 +941,11 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan,
/* If we lost track of base, alas, position before last thingy. */
unsigned int new_pos = base == end ? base - 2 : base - 1;
/* Malayalam does not have "half" forms or explicit virama forms.
* The glyphs formed by 'half' are Chillus. We want to position
* matra after them all.
/* 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)
if (buffer->props.script != HB_SCRIPT_MALAYALAM && buffer->props.script != HB_SCRIPT_TAMIL)
{
while (new_pos > start &&
!(is_one_of (info[new_pos], (FLAG (OT_M) | FLAG (OT_H) | FLAG (OT_Coeng)))))
@ -853,7 +965,7 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan,
new_pos = start; /* No move. */
}
if (start < new_pos)
if (start < new_pos && info[new_pos].indic_position () != POS_PRE_M)
{
/* Now go see if there's actually any matras... */
for (unsigned int i = new_pos; i > start; i--)
@ -1109,7 +1221,7 @@ final_reordering (const hb_ot_shape_plan_t *plan,
hb_buffer_t *buffer)
{
unsigned int count = buffer->len;
if (!count) return;
if (unlikely (!count)) return;
hb_glyph_info_t *info = buffer->info;
unsigned int last = 0;
@ -1122,11 +1234,21 @@ final_reordering (const hb_ot_shape_plan_t *plan,
}
final_reordering_syllable (plan, buffer, last, count);
/* Zero syllables now... */
for (unsigned int i = 0; i < count; i++)
info[i].syllable() = 0;
HB_BUFFER_DEALLOCATE_VAR (buffer, indic_category);
HB_BUFFER_DEALLOCATE_VAR (buffer, indic_position);
}
static hb_ot_shape_normalization_mode_t
normalization_preference_indic (const hb_ot_shape_plan_t *plan)
{
return HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT;
}
const hb_ot_complex_shaper_t _hb_ot_complex_shaper_indic =
{
"indic",
@ -1135,7 +1257,7 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_indic =
data_create_indic,
data_destroy_indic,
NULL, /* preprocess_text */
NULL, /* normalization_preference */
normalization_preference_indic,
setup_masks_indic,
false, /* zero_width_attached_marks */
};

View File

@ -36,4 +36,9 @@ HB_INTERNAL void _hb_ot_shape_fallback_position (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer);
HB_INTERNAL void _hb_ot_shape_fallback_position_recategorize_marks (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer);
#endif /* HB_OT_SHAPE_FALLBACK_PRIVATE_HH */

View File

@ -26,28 +26,55 @@
#include "hb-ot-shape-fallback-private.hh"
static void
zero_mark_advances (hb_buffer_t *buffer,
unsigned int start,
unsigned int end)
{
for (unsigned int i = start; i < end; i++)
if (_hb_glyph_info_get_general_category (&buffer->info[i]) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
{
buffer->pos[i].x_advance = 0;
buffer->pos[i].y_advance = 0;
}
}
static unsigned int
recategorize_combining_class (unsigned int modified_combining_class)
recategorize_combining_class (hb_codepoint_t u,
unsigned int klass)
{
if (modified_combining_class >= 200)
return modified_combining_class;
if (klass >= 200)
return klass;
/* This should be kept in sync with modified combining class mapping
* from hb-unicode.cc. */
switch (modified_combining_class)
/* Thai / Lao need some per-character work. */
if ((u & ~0xFF) == 0x0E00)
{
if (unlikely (klass == 0))
{
switch (u)
{
case 0x0E31:
case 0x0E34:
case 0x0E35:
case 0x0E36:
case 0x0E37:
case 0x0E47:
case 0x0E4C:
case 0x0E4D:
case 0x0E4E:
klass = HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT;
break;
case 0x0EB1:
case 0x0EB4:
case 0x0EB5:
case 0x0EB6:
case 0x0EB7:
case 0x0EBB:
case 0x0ECC:
case 0x0ECD:
klass = HB_UNICODE_COMBINING_CLASS_ABOVE;
break;
case 0x0EBC:
klass = HB_UNICODE_COMBINING_CLASS_BELOW;
break;
}
} else {
/* Thai virama is below-right */
if (u == 0x0E3A)
klass = HB_UNICODE_COMBINING_CLASS_BELOW_RIGHT;
}
}
switch (klass)
{
/* Hebrew */
@ -101,23 +128,20 @@ recategorize_combining_class (unsigned int modified_combining_class)
/* Thai */
/* Note: to be useful we also need to position U+0E3A that has ccc=9 (virama).
* But viramas can be both above and below based on the codepoint / script. */
case HB_MODIFIED_COMBINING_CLASS_CCC103: /* sara u / sara uu */
return HB_UNICODE_COMBINING_CLASS_BELOW;
return HB_UNICODE_COMBINING_CLASS_BELOW_RIGHT;
case HB_MODIFIED_COMBINING_CLASS_CCC107: /* mai */
return HB_UNICODE_COMBINING_CLASS_ABOVE;
return HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT;
/* Lao */
case HB_MODIFIED_COMBINING_CLASS_CCC118: /* sign u / sign uu */
return HB_UNICODE_COMBINING_CLASS_BELOW;
return HB_UNICODE_COMBINING_CLASS_BELOW_RIGHT;
case HB_MODIFIED_COMBINING_CLASS_CCC122: /* mai */
return HB_UNICODE_COMBINING_CLASS_ABOVE;
return HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT;
/* Tibetan */
@ -133,7 +157,35 @@ recategorize_combining_class (unsigned int modified_combining_class)
}
return modified_combining_class;
return klass;
}
void
_hb_ot_shape_fallback_position_recategorize_marks (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer)
{
unsigned int count = buffer->len;
for (unsigned int i = 0; i < count; i++)
if (_hb_glyph_info_get_general_category (&buffer->info[i]) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) {
unsigned int combining_class = _hb_glyph_info_get_modified_combining_class (&buffer->info[i]);
combining_class = recategorize_combining_class (buffer->info[i].codepoint, combining_class);
_hb_glyph_info_set_modified_combining_class (&buffer->info[i], combining_class);
}
}
static void
zero_mark_advances (hb_buffer_t *buffer,
unsigned int start,
unsigned int end)
{
for (unsigned int i = start; i < end; i++)
if (_hb_glyph_info_get_general_category (&buffer->info[i]) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
{
buffer->pos[i].x_advance = 0;
buffer->pos[i].y_advance = 0;
}
}
static inline void
@ -171,6 +223,7 @@ position_mark (const hb_ot_shape_plan_t *plan,
}
/* Fall through */
default:
case HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW:
case HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE:
case HB_UNICODE_COMBINING_CLASS_BELOW:
@ -234,6 +287,7 @@ position_around_base (const hb_ot_shape_plan_t *plan,
unsigned int base,
unsigned int end)
{
hb_direction_t horiz_dir = HB_DIRECTION_INVALID;
hb_glyph_extents_t base_extents;
if (!font->get_glyph_extents (buffer->info[base].codepoint,
&base_extents))
@ -245,33 +299,61 @@ position_around_base (const hb_ot_shape_plan_t *plan,
base_extents.x_bearing += buffer->pos[base].x_offset;
base_extents.y_bearing += buffer->pos[base].y_offset;
/* XXX Handle ligature component positioning... */
HB_UNUSED bool is_ligature = is_a_ligature (buffer->info[base]);
unsigned int lig_id = get_lig_id (buffer->info[base]);
unsigned int num_lig_components = get_lig_num_comps (buffer->info[base]);
hb_position_t x_offset = 0, y_offset = 0;
if (HB_DIRECTION_IS_FORWARD (buffer->props.direction)) {
x_offset -= buffer->pos[base].x_advance;
y_offset -= buffer->pos[base].y_advance;
}
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;
for (unsigned int i = base + 1; i < end; i++)
if (_hb_glyph_info_get_general_category (&buffer->info[i]) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
if (_hb_glyph_info_get_modified_combining_class (&buffer->info[i]))
{
unsigned int this_combining_class = recategorize_combining_class (_hb_glyph_info_get_modified_combining_class (&buffer->info[i]));
if (this_combining_class != last_combining_class)
cluster_extents = base_extents;
if (num_lig_components > 1) {
unsigned int this_lig_id = get_lig_id (buffer->info[i]);
unsigned int this_lig_component = get_lig_comp (buffer->info[i]) - 1;
/* Conditions for attaching to the last component. */
if (!lig_id || lig_id != this_lig_id || this_lig_component >= num_lig_components)
this_lig_component = num_lig_components - 1;
if (last_lig_component != this_lig_component)
{
last_lig_component = this_lig_component;
last_combining_class = 255;
component_extents = base_extents;
if (unlikely (horiz_dir == HB_DIRECTION_INVALID)) {
if (HB_DIRECTION_IS_HORIZONTAL (plan->props.direction))
horiz_dir = plan->props.direction;
else
horiz_dir = hb_script_get_horizontal_direction (plan->props.script);
}
if (horiz_dir == HB_DIRECTION_LTR)
component_extents.x_bearing += (this_lig_component * component_extents.width) / num_lig_components;
else
component_extents.x_bearing += ((num_lig_components - 1 - this_lig_component) * component_extents.width) / num_lig_components;
component_extents.width /= num_lig_components;
}
}
position_mark (plan, font, buffer, base_extents, i, this_combining_class);
unsigned int this_combining_class = _hb_glyph_info_get_modified_combining_class (&buffer->info[i]);
if (last_combining_class != this_combining_class)
{
last_combining_class = this_combining_class;
cluster_extents = component_extents;
}
position_mark (plan, font, buffer, cluster_extents, i, this_combining_class);
buffer->pos[i].x_advance = 0;
buffer->pos[i].y_advance = 0;
buffer->pos[i].x_offset += x_offset;
buffer->pos[i].y_offset += y_offset;
/* combine cluster extents. */
last_combining_class = this_combining_class;
} else {
if (HB_DIRECTION_IS_FORWARD (buffer->props.direction)) {
x_offset -= buffer->pos[i].x_advance;
@ -281,8 +363,6 @@ position_around_base (const hb_ot_shape_plan_t *plan,
y_offset += buffer->pos[i].y_advance;
}
}
}
static inline void
@ -297,14 +377,17 @@ position_cluster (const hb_ot_shape_plan_t *plan,
/* Find the base glyph */
for (unsigned int i = start; i < end; i++)
if (is_a_ligature (buffer->info[i]) ||
!(FLAG (_hb_glyph_info_get_general_category (&buffer->info[i])) &
(FLAG (HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK) |
FLAG (HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK) |
FLAG (HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK))))
if (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer->info[i])))
{
position_around_base (plan, font, buffer, i, end);
break;
/* Find mark glyphs */
unsigned int j;
for (j = i + 1; j < end; j++)
if (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer->info[j])))
break;
position_around_base (plan, font, buffer, i, j);
i = j - 1;
}
}

View File

@ -38,6 +38,7 @@
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 */
HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT, /* always fully decomposes and then recompose back */
HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_FULL, /* including base-to-base composition */
HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT = HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS

View File

@ -130,10 +130,7 @@ compose_func (hb_unicode_funcs_t *unicode,
hb_codepoint_t *ab)
{
/* XXX, this belongs to indic normalizer. */
if ((FLAG (unicode->general_category (a)) &
(FLAG (HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK) |
FLAG (HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK) |
FLAG (HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK))))
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; }
@ -414,10 +411,10 @@ decompose_multi_char_cluster (hb_font_t *font, hb_buffer_t *buffer, unsigned int
}
static inline bool
decompose_cluster (hb_font_t *font, hb_buffer_t *buffer, bool recompose, unsigned int end)
decompose_cluster (hb_font_t *font, hb_buffer_t *buffer, bool short_circuit, unsigned int end)
{
if (likely (buffer->idx + 1 == end))
return decompose_current_character (font, buffer, recompose);
return decompose_current_character (font, buffer, short_circuit);
else
return decompose_multi_char_cluster (font, buffer, end);
}
@ -437,7 +434,8 @@ void
_hb_ot_shape_normalize (hb_font_t *font, hb_buffer_t *buffer,
hb_ot_shape_normalization_mode_t mode)
{
bool recompose = mode != HB_OT_SHAPE_NORMALIZATION_MODE_DECOMPOSED;
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;
unsigned int count;
@ -459,7 +457,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, recompose, end) || can_use_recompose;
can_use_recompose = decompose_cluster (font, buffer, short_circuit, end) || can_use_recompose;
}
buffer->swap_buffers ();
@ -495,7 +493,7 @@ _hb_ot_shape_normalize (hb_font_t *font, hb_buffer_t *buffer,
}
if (!recompose)
if (mode == HB_OT_SHAPE_NORMALIZATION_MODE_DECOMPOSED)
return;
/* Third round, recompose */

View File

@ -95,6 +95,12 @@ _hb_glyph_info_get_general_category (const hb_glyph_info_t *info)
return (hb_unicode_general_category_t) (info->unicode_props0() & 0x7F);
}
inline void
_hb_glyph_info_set_modified_combining_class (hb_glyph_info_t *info, unsigned int modified_class)
{
info->unicode_props1() = modified_class;
}
inline unsigned int
_hb_glyph_info_get_modified_combining_class (const hb_glyph_info_t *info)
{

View File

@ -234,15 +234,41 @@ hb_set_unicode_props (hb_buffer_t *buffer)
_hb_glyph_info_set_unicode_props (&buffer->info[i], buffer->unicode);
}
static void
hb_insert_dotted_circle (hb_buffer_t *buffer, hb_font_t *font)
{
if (buffer->context_len[0] ||
_hb_glyph_info_get_general_category (&buffer->info[0]) !=
HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
return;
hb_codepoint_t dottedcircle_glyph;
if (!font->get_glyph (0x25CC, 0, &dottedcircle_glyph))
return;
hb_glyph_info_t dottedcircle;
dottedcircle.codepoint = 0x25CC;
_hb_glyph_info_set_unicode_props (&dottedcircle, buffer->unicode);
buffer->clear_output ();
buffer->idx = 0;
hb_glyph_info_t info = dottedcircle;
info.cluster = buffer->cur().cluster;
info.mask = buffer->cur().mask;
buffer->output_info (info);
while (buffer->idx < buffer->len)
buffer->next_glyph ();
buffer->swap_buffers ();
}
static void
hb_form_clusters (hb_buffer_t *buffer)
{
unsigned int count = buffer->len;
for (unsigned int i = 1; i < count; i++)
if (FLAG (_hb_glyph_info_get_general_category (&buffer->info[i])) &
(FLAG (HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK) |
FLAG (HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK) |
FLAG (HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)))
if (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer->info[i])))
buffer->merge_clusters (i - 1, i + 1);
}
@ -316,6 +342,16 @@ hb_ot_map_glyphs_fast (hb_buffer_t *buffer)
buffer->info[i].codepoint = buffer->info[i].glyph_index();
}
static inline void
hb_synthesize_glyph_classes (hb_ot_shape_context_t *c)
{
unsigned int count = c->buffer->len;
for (unsigned int i = 0; i < count; i++)
c->buffer->info[i].glyph_props() = _hb_glyph_info_get_general_category (&c->buffer->info[i]) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK ?
HB_OT_LAYOUT_GLYPH_CLASS_MARK :
HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH;
}
static inline void
hb_ot_substitute_default (hb_ot_shape_context_t *c)
{
@ -333,22 +369,15 @@ hb_ot_substitute_default (hb_ot_shape_context_t *c)
hb_ot_shape_setup_masks (c);
/* This is unfortunate to go here, but necessary... */
if (!hb_ot_layout_has_positioning (c->face))
_hb_ot_shape_fallback_position_recategorize_marks (c->plan, c->font, c->buffer);
hb_ot_map_glyphs_fast (c->buffer);
HB_BUFFER_DEALLOCATE_VAR (c->buffer, glyph_index);
}
static inline void
hb_synthesize_glyph_classes (hb_ot_shape_context_t *c)
{
unsigned int count = c->buffer->len;
for (unsigned int i = 0; i < count; i++)
c->buffer->info[i].glyph_props() = _hb_glyph_info_get_general_category (&c->buffer->info[i]) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK ?
HB_OT_LAYOUT_GLYPH_CLASS_MARK :
HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH;
}
static inline void
hb_ot_substitute_complex (hb_ot_shape_context_t *c)
{
@ -357,8 +386,7 @@ hb_ot_substitute_complex (hb_ot_shape_context_t *c)
if (!hb_ot_layout_has_glyph_classes (c->face))
hb_synthesize_glyph_classes (c);
if (hb_ot_layout_has_substitution (c->face))
c->plan->substitute (c->font, c->buffer);
c->plan->substitute (c->font, c->buffer);
hb_ot_layout_substitute_finish (c->font, c->buffer);
@ -486,14 +514,18 @@ hb_ot_position (hb_ot_shape_context_t *c)
static void
hb_ot_hide_zerowidth (hb_ot_shape_context_t *c)
{
hb_codepoint_t space;
if (!c->font->get_glyph (' ', 0, &space))
return; /* No point! */
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_zero_width (&c->buffer->info[i])))
{
if (!space) {
/* We assume that the space glyph is not gid0. */
if (unlikely (!c->font->get_glyph (' ', 0, &space)) || !space)
return; /* No point! */
}
c->buffer->info[i].codepoint = space;
c->buffer->pos[i].x_advance = 0;
c->buffer->pos[i].y_advance = 0;
@ -517,6 +549,7 @@ hb_ot_shape_internal (hb_ot_shape_context_t *c)
c->buffer->clear_output ();
hb_set_unicode_props (c->buffer);
hb_insert_dotted_circle (c->buffer, c->font);
hb_form_clusters (c->buffer);
hb_ensure_native_direction (c->buffer);
@ -556,7 +589,7 @@ hb_ot_map_glyphs_dumb (hb_font_t *font,
{
unsigned int count = buffer->len;
for (unsigned int i = 0; i < count; i++)
font->get_glyph (buffer->cur().codepoint, 0, &buffer->cur().codepoint);
font->get_glyph (buffer->info[i].codepoint, 0, &buffer->info[i].codepoint);
}
void

View File

@ -77,6 +77,8 @@ static inline Type MAX (const Type &a, const Type &b) { return a > b ? a : b; }
#undef ARRAY_LENGTH
template <typename Type, unsigned int n>
static inline unsigned int ARRAY_LENGTH (const Type (&a)[n]) { return n; }
/* A const version, but does not detect erratically being called on pointers. */
#define ARRAY_LENGTH_CONST(__array) ((signed int) (sizeof (__array) / sizeof (__array[0])))
#define HB_STMT_START do
#define HB_STMT_END while (0)
@ -544,7 +546,7 @@ _hb_debug (unsigned int level,
#define DEBUG_LEVEL(WHAT, LEVEL) (_hb_debug ((LEVEL), HB_DEBUG_##WHAT))
#define DEBUG(WHAT) (DEBUG_LEVEL (WHAT, 0))
template <int max_level> inline void
template <int max_level> static inline void
_hb_debug_msg_va (const char *what,
const void *obj,
const char *func,
@ -581,12 +583,13 @@ _hb_debug_msg_va (const char *what,
fprintf (stderr, " " VRBAR LBAR);
if (func) {
/* If there's a class name, just write that. */
const char *dotdot = strstr (func, "::");
/* Skip return type */
const char *space = strchr (func, ' ');
if (space && dotdot && space < dotdot)
if (space)
func = space + 1;
unsigned int func_len = dotdot ? dotdot - func : strlen (func);
/* Skip parameter list */
const char *paren = strchr (func, '(');
unsigned int func_len = paren ? paren - func : strlen (func);
fprintf (stderr, "%.*s: ", func_len, func);
}
@ -605,7 +608,7 @@ _hb_debug_msg_va<0> (const char *what HB_UNUSED,
const char *message HB_UNUSED,
va_list ap HB_UNUSED) {}
template <int max_level> inline void
template <int max_level> static inline void
_hb_debug_msg (const char *what,
const void *obj,
const char *func,
@ -614,7 +617,7 @@ _hb_debug_msg (const char *what,
int level_dir,
const char *message,
...) HB_PRINTF_FUNC(7, 8);
template <int max_level> inline void
template <int max_level> static inline void
_hb_debug_msg (const char *what,
const void *obj,
const char *func,

View File

@ -1,5 +1,6 @@
/*
* Copyright © 2009 Red Hat, Inc.
* Copyright © 2012 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
@ -22,6 +23,7 @@
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Red Hat Author(s): Behdad Esfahbod
* Google Author(s): Behdad Esfahbod
*/
#include "hb-private.hh"
@ -32,6 +34,172 @@
#include "hb-font-private.hh"
static void
parse_space (const char **pp, const char *end)
{
char c;
#define ISSPACE(c) ((c)==' '||(c)=='\f'||(c)=='\n'||(c)=='\r'||(c)=='\t'||(c)=='\v')
while (*pp < end && (c = **pp, ISSPACE (c)))
(*pp)++;
#undef ISSPACE
}
static hb_bool_t
parse_char (const char **pp, const char *end, char c)
{
parse_space (pp, end);
if (*pp == end || **pp != c)
return false;
(*pp)++;
return true;
}
static hb_bool_t
parse_uint (const char **pp, const char *end, unsigned int *pv)
{
char buf[32];
strncpy (buf, *pp, end - *pp);
buf[ARRAY_LENGTH (buf) - 1] = '\0';
char *p = buf;
char *pend = p;
unsigned int v;
v = strtol (p, &pend, 0);
if (p == pend)
return false;
*pv = v;
*pp += pend - p;
return true;
}
static hb_bool_t
parse_feature_value_prefix (const char **pp, const char *end, hb_feature_t *feature)
{
if (parse_char (pp, end, '-'))
feature->value = 0;
else {
parse_char (pp, end, '+');
feature->value = 1;
}
return true;
}
static hb_bool_t
parse_feature_tag (const char **pp, const char *end, hb_feature_t *feature)
{
const char *p = *pp;
char c;
parse_space (pp, end);
#define ISALNUM(c) (('a' <= (c) && (c) <= 'z') || ('A' <= (c) && (c) <= 'Z') || ('0' <= (c) && (c) <= '9'))
while (*pp < end && (c = **pp, ISALNUM(c)))
(*pp)++;
#undef ISALNUM
if (p == *pp)
return false;
feature->tag = hb_tag_from_string (p, *pp - p);
return true;
}
static hb_bool_t
parse_feature_indices (const char **pp, const char *end, hb_feature_t *feature)
{
parse_space (pp, end);
hb_bool_t has_start;
feature->start = 0;
feature->end = (unsigned int) -1;
if (!parse_char (pp, end, '['))
return true;
has_start = parse_uint (pp, end, &feature->start);
if (parse_char (pp, end, ':')) {
parse_uint (pp, end, &feature->end);
} else {
if (has_start)
feature->end = feature->start + 1;
}
return parse_char (pp, end, ']');
}
static hb_bool_t
parse_feature_value_postfix (const char **pp, const char *end, hb_feature_t *feature)
{
return !parse_char (pp, end, '=') || parse_uint (pp, end, &feature->value);
}
static hb_bool_t
parse_one_feature (const char **pp, const char *end, hb_feature_t *feature)
{
return parse_feature_value_prefix (pp, end, feature) &&
parse_feature_tag (pp, end, feature) &&
parse_feature_indices (pp, end, feature) &&
parse_feature_value_postfix (pp, end, feature) &&
*pp == end;
}
hb_bool_t
hb_feature_from_string (const char *str, int len,
hb_feature_t *feature)
{
if (len < 0)
len = strlen (str);
return parse_one_feature (&str, str + len, feature);
}
void
hb_feature_to_string (hb_feature_t *feature,
char *buf, unsigned int size)
{
if (unlikely (!size)) return;
char s[128];
unsigned int len = 0;
if (feature->value == 0)
s[len++] = '-';
hb_tag_to_string (feature->tag, s + len);
len += 4;
while (len && s[len - 1] == ' ')
len--;
if (feature->start != 0 || feature->start != (unsigned int) -1)
{
s[len++] = '[';
if (feature->start)
len += snprintf (s + len, ARRAY_LENGTH (s) - len, "%d", feature->start);
if (feature->end != feature->start + 1) {
s[len++] = ':';
if (feature->end != (unsigned int) -1)
len += snprintf (s + len, ARRAY_LENGTH (s) - len, "%d", feature->end);
}
s[len++] = ']';
}
if (feature->value > 1)
{
s[len++] = '=';
len += snprintf (s + len, ARRAY_LENGTH (s) - len, "%d", feature->value);
}
assert (len < ARRAY_LENGTH (s));
len = MIN (len, size - 1);
memcpy (buf, s, len);
s[len] = '\0';
}
static const char **static_shaper_list;
static
@ -85,11 +253,16 @@ hb_shape_full (hb_font_t *font,
if (unlikely (!buffer->len))
return true;
assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE);
buffer->guess_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);
hb_shape_plan_destroy (shape_plan);
if (res)
buffer->content_type = HB_BUFFER_CONTENT_TYPE_GLYPHS;
return res;
}

View File

@ -1,5 +1,6 @@
/*
* Copyright © 2009 Red Hat, Inc.
* Copyright © 2012 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
@ -22,6 +23,7 @@
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Red Hat Author(s): Behdad Esfahbod
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_H_IN
@ -45,6 +47,17 @@ typedef struct hb_feature_t {
unsigned int end;
} hb_feature_t;
/* len=-1 means str is NUL-terminated */
hb_bool_t
hb_feature_from_string (const char *str, int len,
hb_feature_t *feature);
/* something like 128 bytes is more than enough.
* nul-terminates. */
void
hb_feature_to_string (hb_feature_t *feature,
char *buf, unsigned int size);
void
hb_shape (hb_font_t *font,

View File

@ -47,4 +47,8 @@ HB_SHAPER_IMPLEMENT (ot) /* <--- This is our main OpenType shaper. */
HB_SHAPER_IMPLEMENT (old)
#endif
#ifdef HAVE_ICU_LE
HB_SHAPER_IMPLEMENT (icu_le)
#endif
HB_SHAPER_IMPLEMENT (fallback) /* <--- This should be last. */

205
gfx/harfbuzz/src/hb-ucdn.cc Normal file
View File

@ -0,0 +1,205 @@
/*
* Copyright (C) 2012 Grigori Goronzy <greg@kinoho.net>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "hb-private.hh"
#include "hb-unicode-private.hh"
#include "ucdn.h"
static const hb_script_t ucdn_script_translate[] =
{
HB_SCRIPT_COMMON,
HB_SCRIPT_LATIN,
HB_SCRIPT_GREEK,
HB_SCRIPT_CYRILLIC,
HB_SCRIPT_ARMENIAN,
HB_SCRIPT_HEBREW,
HB_SCRIPT_ARABIC,
HB_SCRIPT_SYRIAC,
HB_SCRIPT_THAANA,
HB_SCRIPT_DEVANAGARI,
HB_SCRIPT_BENGALI,
HB_SCRIPT_GURMUKHI,
HB_SCRIPT_GUJARATI,
HB_SCRIPT_ORIYA,
HB_SCRIPT_TAMIL,
HB_SCRIPT_TELUGU,
HB_SCRIPT_KANNADA,
HB_SCRIPT_MALAYALAM,
HB_SCRIPT_SINHALA,
HB_SCRIPT_THAI,
HB_SCRIPT_LAO,
HB_SCRIPT_TIBETAN,
HB_SCRIPT_MYANMAR,
HB_SCRIPT_GEORGIAN,
HB_SCRIPT_HANGUL,
HB_SCRIPT_ETHIOPIC,
HB_SCRIPT_CHEROKEE,
HB_SCRIPT_CANADIAN_ABORIGINAL,
HB_SCRIPT_OGHAM,
HB_SCRIPT_RUNIC,
HB_SCRIPT_KHMER,
HB_SCRIPT_MONGOLIAN,
HB_SCRIPT_HIRAGANA,
HB_SCRIPT_KATAKANA,
HB_SCRIPT_BOPOMOFO,
HB_SCRIPT_HAN,
HB_SCRIPT_YI,
HB_SCRIPT_OLD_ITALIC,
HB_SCRIPT_GOTHIC,
HB_SCRIPT_DESERET,
HB_SCRIPT_INHERITED,
HB_SCRIPT_TAGALOG,
HB_SCRIPT_HANUNOO,
HB_SCRIPT_BUHID,
HB_SCRIPT_TAGBANWA,
HB_SCRIPT_LIMBU,
HB_SCRIPT_TAI_LE,
HB_SCRIPT_LINEAR_B,
HB_SCRIPT_UGARITIC,
HB_SCRIPT_SHAVIAN,
HB_SCRIPT_OSMANYA,
HB_SCRIPT_CYPRIOT,
HB_SCRIPT_BRAILLE,
HB_SCRIPT_BUGINESE,
HB_SCRIPT_COPTIC,
HB_SCRIPT_NEW_TAI_LUE,
HB_SCRIPT_GLAGOLITIC,
HB_SCRIPT_TIFINAGH,
HB_SCRIPT_SYLOTI_NAGRI,
HB_SCRIPT_OLD_PERSIAN,
HB_SCRIPT_KHAROSHTHI,
HB_SCRIPT_BALINESE,
HB_SCRIPT_CUNEIFORM,
HB_SCRIPT_PHOENICIAN,
HB_SCRIPT_PHAGS_PA,
HB_SCRIPT_NKO,
HB_SCRIPT_SUNDANESE,
HB_SCRIPT_LEPCHA,
HB_SCRIPT_OL_CHIKI,
HB_SCRIPT_VAI,
HB_SCRIPT_SAURASHTRA,
HB_SCRIPT_KAYAH_LI,
HB_SCRIPT_REJANG,
HB_SCRIPT_LYCIAN,
HB_SCRIPT_CARIAN,
HB_SCRIPT_LYDIAN,
HB_SCRIPT_CHAM,
HB_SCRIPT_TAI_THAM,
HB_SCRIPT_TAI_VIET,
HB_SCRIPT_AVESTAN,
HB_SCRIPT_EGYPTIAN_HIEROGLYPHS,
HB_SCRIPT_SAMARITAN,
HB_SCRIPT_LISU,
HB_SCRIPT_BAMUM,
HB_SCRIPT_JAVANESE,
HB_SCRIPT_MEETEI_MAYEK,
HB_SCRIPT_IMPERIAL_ARAMAIC,
HB_SCRIPT_OLD_SOUTH_ARABIAN,
HB_SCRIPT_INSCRIPTIONAL_PARTHIAN,
HB_SCRIPT_INSCRIPTIONAL_PAHLAVI,
HB_SCRIPT_OLD_TURKIC,
HB_SCRIPT_KAITHI,
HB_SCRIPT_BATAK,
HB_SCRIPT_BRAHMI,
HB_SCRIPT_MANDAIC,
HB_SCRIPT_CHAKMA,
HB_SCRIPT_MEROITIC_CURSIVE,
HB_SCRIPT_MEROITIC_HIEROGLYPHS,
HB_SCRIPT_MIAO,
HB_SCRIPT_SHARADA,
HB_SCRIPT_SORA_SOMPENG,
HB_SCRIPT_TAKRI,
HB_SCRIPT_UNKNOWN,
};
static hb_unicode_combining_class_t
hb_ucdn_combining_class(hb_unicode_funcs_t *ufuncs, hb_codepoint_t unicode,
void *user_data)
{
return (hb_unicode_combining_class_t) ucdn_get_combining_class(unicode);
}
static unsigned int
hb_ucdn_eastasian_width(hb_unicode_funcs_t *ufuncs, hb_codepoint_t unicode,
void *user_data)
{
int w = ucdn_get_east_asian_width(unicode);
return (w == UCDN_EAST_ASIAN_F || w == UCDN_EAST_ASIAN_W) ? 2 : 1;
}
static hb_unicode_general_category_t
hb_ucdn_general_category(hb_unicode_funcs_t *ufuncs,
hb_codepoint_t unicode, void *user_data)
{
return (hb_unicode_general_category_t)ucdn_get_general_category(unicode);
}
static hb_codepoint_t
hb_ucdn_mirroring(hb_unicode_funcs_t *ufuncs, hb_codepoint_t unicode,
void *user_data)
{
return ucdn_mirror(unicode);
}
static hb_script_t
hb_ucdn_script(hb_unicode_funcs_t *ufuncs, hb_codepoint_t unicode,
void *user_data)
{
return ucdn_script_translate[ucdn_get_script(unicode)];
}
static hb_bool_t
hb_ucdn_compose(hb_unicode_funcs_t *ufuncs, hb_codepoint_t a,
hb_codepoint_t b, hb_codepoint_t *ab, void *user_data)
{
return ucdn_compose(ab, a, b);
}
static hb_bool_t
hb_ucdn_decompose(hb_unicode_funcs_t *ufuncs, hb_codepoint_t ab,
hb_codepoint_t *a, hb_codepoint_t *b, void *user_data)
{
return ucdn_decompose(ab, a, b);
}
static unsigned int
hb_ucdn_decompose_compatibility(hb_unicode_funcs_t *ufuncs, hb_codepoint_t u,
hb_codepoint_t *decomposed, void *user_data)
{
return ucdn_compat_decompose(u, decomposed);
}
extern "C" HB_INTERNAL
hb_unicode_funcs_t *
hb_ucdn_get_unicode_funcs (void)
{
static const hb_unicode_funcs_t _hb_ucdn_unicode_funcs = {
HB_OBJECT_HEADER_STATIC,
NULL, /* parent */
true, /* immutable */
{
#define HB_UNICODE_FUNC_IMPLEMENT(name) hb_ucdn_##name,
HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_UNICODE_FUNC_IMPLEMENT
}
};
return const_cast<hb_unicode_funcs_t *> (&_hb_ucdn_unicode_funcs);
}

View File

@ -268,4 +268,13 @@ extern HB_INTERNAL const hb_unicode_funcs_t _hb_unicode_funcs_nil;
#define HB_MODIFIED_COMBINING_CLASS_CCC132 132 /* sign u */
/* Misc */
#define HB_UNICODE_GENERAL_CATEGORY_IS_MARK(gen_cat) \
(FLAG (gen_cat) & \
(FLAG (HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK) | \
FLAG (HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK) | \
FLAG (HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)))
#endif /* HB_UNICODE_PRIVATE_HH */

View File

@ -112,6 +112,7 @@ hb_unicode_decompose_compatibility_nil (hb_unicode_funcs_t *ufuncs HB_UNUSED
#define HB_UNICODE_FUNCS_IMPLEMENT_SET \
HB_UNICODE_FUNCS_IMPLEMENT (glib) \
HB_UNICODE_FUNCS_IMPLEMENT (icu) \
HB_UNICODE_FUNCS_IMPLEMENT (ucdn) \
HB_UNICODE_FUNCS_IMPLEMENT (nil) \
/* ^--- Add new callbacks before nil */
@ -134,6 +135,8 @@ hb_unicode_funcs_get_default (void)
HB_UNICODE_FUNCS_IMPLEMENT(glib)
#elif defined(HAVE_ICU)
HB_UNICODE_FUNCS_IMPLEMENT(icu)
#elif defined(HAVE_UCDN)
HB_UNICODE_FUNCS_IMPLEMENT(ucdn)
#else
#define HB_UNICODE_FUNCS_NIL 1
HB_UNICODE_FUNCS_IMPLEMENT(nil)

View File

@ -33,8 +33,6 @@
#include <windows.h>
#include <usp10.h>
typedef ULONG WIN_ULONG;
#include "hb-uniscribe.h"
#include "hb-ot-name-table.hh"
@ -121,8 +119,8 @@ populate_log_font (LOGFONTW *lf,
lf->lfHeight = -font->y_scale;
lf->lfCharSet = DEFAULT_CHARSET;
hb_blob_t *blob = Sanitizer<name>::sanitize (hb_face_reference_table (font->face, HB_TAG ('n','a','m','e')));
const name *name_table = Sanitizer<name>::lock_instance (blob);
hb_blob_t *blob = OT::Sanitizer<OT::name>::sanitize (hb_face_reference_table (font->face, HB_TAG ('n','a','m','e')));
const OT::name *name_table = OT::Sanitizer<OT::name>::lock_instance (blob);
unsigned int len = name_table->get_name (3, 1, 0x409, 4,
lf->lfFaceName,
sizeof (lf->lfFaceName[0]) * LF_FACESIZE)
@ -305,7 +303,7 @@ retry:
SCRIPT_ITEM items[MAX_ITEMS + 1];
SCRIPT_CONTROL bidi_control = {0};
SCRIPT_STATE bidi_state = {0};
WIN_ULONG script_tags[MAX_ITEMS];
ULONG script_tags[MAX_ITEMS];
int item_count;
/* MinGW32 doesn't define fMergeNeutralItems, so we bruteforce */

View File

@ -0,0 +1,204 @@
/*
* Copyright © 2011,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
*/
#ifndef HB_UTF_PRIVATE_HH
#define HB_UTF_PRIVATE_HH
#include "hb-private.hh"
/* UTF-8 */
#define HB_UTF8_COMPUTE(Char, Mask, Len) \
if (Char < 128) { Len = 1; Mask = 0x7f; } \
else if ((Char & 0xe0) == 0xc0) { Len = 2; Mask = 0x1f; } \
else if ((Char & 0xf0) == 0xe0) { Len = 3; Mask = 0x0f; } \
else if ((Char & 0xf8) == 0xf0) { Len = 4; Mask = 0x07; } \
else Len = 0;
static inline const uint8_t *
hb_utf_next (const uint8_t *text,
const uint8_t *end,
hb_codepoint_t *unicode)
{
hb_codepoint_t c = *text, mask;
unsigned int len;
/* TODO check for overlong sequences? */
HB_UTF8_COMPUTE (c, mask, len);
if (unlikely (!len || (unsigned int) (end - text) < len)) {
*unicode = -1;
return text + 1;
} else {
hb_codepoint_t result;
unsigned int i;
result = c & mask;
for (i = 1; i < len; i++)
{
if (unlikely ((text[i] & 0xc0) != 0x80))
{
*unicode = -1;
return text + 1;
}
result <<= 6;
result |= (text[i] & 0x3f);
}
*unicode = result;
return text + len;
}
}
static inline const uint8_t *
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)
text--;
hb_codepoint_t c = *text, mask;
unsigned int len;
/* TODO check for overlong sequences? */
HB_UTF8_COMPUTE (c, mask, len);
if (unlikely (!len || (unsigned int) (end - text) != len)) {
*unicode = -1;
return end - 1;
} else {
hb_codepoint_t result;
unsigned int i;
result = c & mask;
for (i = 1; i < len; i++)
{
result <<= 6;
result |= (text[i] & 0x3f);
}
*unicode = result;
return text;
}
}
static inline unsigned int
hb_utf_strlen (const uint8_t *text)
{
return strlen ((const char *) text);
}
/* UTF-16 */
static inline const uint16_t *
hb_utf_next (const uint16_t *text,
const uint16_t *end,
hb_codepoint_t *unicode)
{
hb_codepoint_t c = *text++;
if (unlikely (hb_in_range<hb_codepoint_t> (c, 0xd800, 0xdbff)))
{
/* high surrogate */
hb_codepoint_t l;
if (text < end && ((l = *text), likely (hb_in_range<hb_codepoint_t> (l, 0xdc00, 0xdfff))))
{
/* low surrogate */
*unicode = (c << 10) + l - ((0xd800 << 10) - 0x10000 + 0xdc00);
text++;
} else
*unicode = -1;
} else
*unicode = c;
return text;
}
static inline const uint16_t *
hb_utf_prev (const uint16_t *text,
const uint16_t *start,
hb_codepoint_t *unicode)
{
hb_codepoint_t c = *--text;
if (unlikely (hb_in_range<hb_codepoint_t> (c, 0xdc00, 0xdfff)))
{
/* low surrogate */
hb_codepoint_t h;
if (start < text && ((h = *(text - 1)), likely (hb_in_range<hb_codepoint_t> (h, 0xd800, 0xdbff))))
{
/* high surrogate */
*unicode = (h << 10) + c - ((0xd800 << 10) - 0x10000 + 0xdc00);
text--;
} else
*unicode = -1;
} else
*unicode = c;
return text;
}
static inline unsigned int
hb_utf_strlen (const uint16_t *text)
{
unsigned int l = 0;
while (*text++) l++;
return l;
}
/* UTF-32 */
static inline const uint32_t *
hb_utf_next (const uint32_t *text,
const uint32_t *end,
hb_codepoint_t *unicode)
{
*unicode = *text++;
return text;
}
static inline const uint32_t *
hb_utf_prev (const uint32_t *text,
const uint32_t *start,
hb_codepoint_t *unicode)
{
*unicode = *--text;
return text;
}
static inline unsigned int
hb_utf_strlen (const uint32_t *text)
{
unsigned int l = 0;
while (*text++) l++;
return l;
}
#endif /* HB_UTF_PRIVATE_HH */

View File

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

View File

@ -36,6 +36,8 @@
#include <stdio.h>
using namespace OT;
int
main (int argc, char **argv)

View File

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