зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1113070 - Update harfbuzz to 0.9.37+ (upstream 7d5e7613ced3dd39d05df83ca7e8952cbecd68f6). r=jdaggett
This commit is contained in:
Родитель
d0995b2be9
Коммит
5c21d8fd9f
|
@ -234,8 +234,8 @@ hb-gobject-enums.%: hb-gobject-enums.%.tmpl $(HBHEADERS)
|
|||
$(AM_V_GEN) $(GLIB_MKENUMS) \
|
||||
--identifier-prefix hb_ --symbol-prefix hb_gobject \
|
||||
--template $^ | \
|
||||
sed 's/_t_get_type/_get_type/g; s/_T (/ (/g' > "$@.tmp" && \
|
||||
mv "$@.tmp" "$@" || ( $(RM) "@.tmp" && false )
|
||||
sed 's/_t_get_type/_get_type/g; s/_T (/ (/g' > "$@" \
|
||||
|| ($(RM) "$@"; false)
|
||||
endif
|
||||
EXTRA_DIST += \
|
||||
harfbuzz-gobject.pc.in \
|
||||
|
@ -251,8 +251,8 @@ EXTRA_DIST += \
|
|||
-e 's@%libdir%@$(libdir)@g' \
|
||||
-e 's@%includedir%@$(includedir)@g' \
|
||||
-e 's@%VERSION%@$(VERSION)@g' \
|
||||
"$<" \
|
||||
> "$@.tmp" && mv "$@.tmp" "$@" || ( $(RM) "$@.tmp"; false )
|
||||
"$<" > "$@" \
|
||||
|| ($(RM) "$@"; false)
|
||||
|
||||
CLEANFILES += $(pkgconfig_DATA)
|
||||
|
||||
|
@ -265,8 +265,9 @@ harfbuzz.def: $(HBHEADERS) $(HBNODISTHEADERS)
|
|||
sed -e 's/ (.*//' | \
|
||||
LANG=C sort; \
|
||||
echo LIBRARY libharfbuzz-$(HB_VERSION_MAJOR).dll; \
|
||||
) >"$@.tmp"
|
||||
@ ! grep -q hb_ERROR "$@.tmp" && mv "$@.tmp" "$@" || ($(RM) "$@"; false)
|
||||
) >"$@"
|
||||
@ ! grep -q hb_ERROR "$@" \
|
||||
|| ($(RM) "$@"; false)
|
||||
|
||||
|
||||
GENERATORS = \
|
||||
|
@ -278,26 +279,25 @@ EXTRA_DIST += $(GENERATORS)
|
|||
unicode-tables: arabic-table indic-table
|
||||
|
||||
indic-table: gen-indic-table.py IndicSyllabicCategory.txt IndicMatraCategory.txt Blocks.txt
|
||||
$(AM_V_GEN) $(builddir)/$^ > hb-ot-shape-complex-indic-table.cc.tmp && \
|
||||
mv hb-ot-shape-complex-indic-table.cc.tmp $(srcdir)/hb-ot-shape-complex-indic-table.cc || \
|
||||
($(RM) hb-ot-shape-complex-indic-table.cc.tmp; false)
|
||||
$(AM_V_GEN) $(builddir)/$^ > hb-ot-shape-complex-indic-table.cc \
|
||||
|| ($(RM) hb-ot-shape-complex-indic-table.cc; false)
|
||||
|
||||
arabic-table: gen-arabic-table.py ArabicShaping.txt UnicodeData.txt Blocks.txt
|
||||
$(AM_V_GEN) $(builddir)/$^ > hb-ot-shape-complex-arabic-table.hh.tmp && \
|
||||
mv hb-ot-shape-complex-arabic-table.hh.tmp $(srcdir)/hb-ot-shape-complex-arabic-table.hh || \
|
||||
($(RM) hb-ot-shape-complex-arabic-table.hh.tmp; false)
|
||||
$(AM_V_GEN) $(builddir)/$^ > hb-ot-shape-complex-arabic-table.hh \
|
||||
|| ($(RM) hb-ot-shape-complex-arabic-table.hh; false)
|
||||
|
||||
built-sources: $(BUILT_SOURCES)
|
||||
|
||||
.PHONY: unicode-tables arabic-table indic-table built-sources
|
||||
|
||||
BUILT_SOURCES += \
|
||||
hb-buffer-deserialize-json.hh \
|
||||
hb-buffer-deserialize-text.hh \
|
||||
hb-ot-shape-complex-indic-machine.hh \
|
||||
hb-ot-shape-complex-myanmar-machine.hh \
|
||||
hb-ot-shape-complex-sea-machine.hh \
|
||||
RAGEL_GENERATED = \
|
||||
$(srcdir)/hb-buffer-deserialize-json.hh \
|
||||
$(srcdir)/hb-buffer-deserialize-text.hh \
|
||||
$(srcdir)/hb-ot-shape-complex-indic-machine.hh \
|
||||
$(srcdir)/hb-ot-shape-complex-myanmar-machine.hh \
|
||||
$(srcdir)/hb-ot-shape-complex-sea-machine.hh \
|
||||
$(NULL)
|
||||
BUILT_SOURCES += $(RAGEL_GENERATED)
|
||||
EXTRA_DIST += \
|
||||
hb-buffer-deserialize-json.rl \
|
||||
hb-buffer-deserialize-text.rl \
|
||||
|
@ -305,9 +305,10 @@ EXTRA_DIST += \
|
|||
hb-ot-shape-complex-myanmar-machine.rl \
|
||||
hb-ot-shape-complex-sea-machine.rl \
|
||||
$(NULL)
|
||||
.rl.hh:
|
||||
$(AM_V_GEN)$(RAGEL) -e -F1 -o "$@.tmp" "$<" && \
|
||||
mv "$@.tmp" "$@" || ( $(RM) "$@.tmp" && false )
|
||||
MAINTAINERCLEANFILES += $(RAGEL_GENERATED)
|
||||
$(srcdir)/%.hh: $(srcdir)/%.rl
|
||||
$(AM_V_GEN)(cd $(srcdir) && $(RAGEL) -e -F1 -o "$*.hh" "$*.rl") \
|
||||
|| ($(RM) "$@"; false)
|
||||
|
||||
noinst_PROGRAMS = \
|
||||
main \
|
||||
|
|
|
@ -17,14 +17,14 @@ fi
|
|||
tested=false
|
||||
for suffix in so dylib; do
|
||||
so=.libs/libharfbuzz.$suffix
|
||||
if test -f "$so"; then
|
||||
echo "Checking that we are not linking to libstdc++"
|
||||
if ldd $so | grep 'libstdc[+][+]'; then
|
||||
echo "Ouch, linked to libstdc++"
|
||||
stat=1
|
||||
fi
|
||||
tested=true
|
||||
if ! test -f "$so"; then continue; fi
|
||||
|
||||
echo "Checking that we are not linking to libstdc++"
|
||||
if ldd $so | grep 'libstdc[+][+]'; then
|
||||
echo "Ouch, linked to libstdc++"
|
||||
stat=1
|
||||
fi
|
||||
tested=true
|
||||
done
|
||||
if ! $tested; then
|
||||
echo "check-libstdc++.sh: libharfbuzz shared library not found; skipping test"
|
||||
|
|
|
@ -22,8 +22,8 @@ fi
|
|||
|
||||
echo "Checking that no object file has static initializers"
|
||||
for obj in $OBJS; do
|
||||
if objdump -t "$obj" | grep '[.]ctors'; then
|
||||
echo "Ouch, $obj has static initializers"
|
||||
if objdump -t "$obj" | grep '[.][cd]tors' | grep -v '\<00*\>'; then
|
||||
echo "Ouch, $obj has static initializers/finalizers"
|
||||
stat=1
|
||||
fi
|
||||
done
|
||||
|
|
|
@ -16,11 +16,17 @@ fi
|
|||
|
||||
echo "Checking that we are not exposing internal symbols"
|
||||
tested=false
|
||||
for so in `ls .libs/lib*.so .libs/lib*.dylib 2>/dev/null` ; do
|
||||
for suffix in so dylib; do
|
||||
so=.libs/libharfbuzz.$suffix
|
||||
if ! test -f "$so"; then continue; fi
|
||||
|
||||
EXPORTED_SYMBOLS="`nm "$so" | grep ' [BCDGINRSTVW] ' | grep -v ' _fini\>\| _init\>\| _fdata\>\| _ftext\>\| _fbss\>\| __bss_start\>\| __bss_start__\>\| __bss_end__\>\| _edata\>\| _end\>\| _bss_end__\>\| __end__\>' | cut -d' ' -f3`"
|
||||
EXPORTED_SYMBOLS="`nm "$so" | grep ' [BCDGINRSTVW] ' | grep -v ' _fini\>\| _init\>\| _fdata\>\| _ftext\>\| _fbss\>\| __bss_start\>\| __bss_start__\>\| __bss_end__\>\| _edata\>\| _end\>\| _bss_end__\>\| __end__\>\| __gcov_flush\>\| llvm_' | cut -d' ' -f3`"
|
||||
|
||||
prefix=`basename "$so" | sed 's/libharfbuzz/hb/; s/-/_/g; s/[.].*//'`
|
||||
|
||||
# On mac, C symbols are prefixed with _
|
||||
if test $suffix = dylib; then prefix="_$prefix"; fi
|
||||
|
||||
echo "Processing $so"
|
||||
if echo "$EXPORTED_SYMBOLS" | grep -v "^${prefix}_"; then
|
||||
echo "Ouch, internal symbols exposed"
|
||||
|
|
|
@ -102,7 +102,10 @@ hb_blob_create (const char *data,
|
|||
{
|
||||
hb_blob_t *blob;
|
||||
|
||||
if (!length || !(blob = hb_object_create<hb_blob_t> ())) {
|
||||
if (!length ||
|
||||
length >= 1u << 31 ||
|
||||
data + length < data /* overflows */ ||
|
||||
!(blob = hb_object_create<hb_blob_t> ())) {
|
||||
if (destroy)
|
||||
destroy (user_data);
|
||||
return hb_blob_get_empty ();
|
||||
|
|
|
@ -117,8 +117,8 @@ _hb_buffer_deserialize_glyphs_json (hb_buffer_t *buffer,
|
|||
|
||||
const char *tok = NULL;
|
||||
int cs;
|
||||
hb_glyph_info_t info;
|
||||
hb_glyph_position_t pos;
|
||||
hb_glyph_info_t info = {0};
|
||||
hb_glyph_position_t pos = {0};
|
||||
%%{
|
||||
write init;
|
||||
write exec;
|
||||
|
|
|
@ -48,15 +48,13 @@ struct hb_buffer_t {
|
|||
ASSERT_POD ();
|
||||
|
||||
/* Information about how the text in the buffer should be treated */
|
||||
|
||||
hb_unicode_funcs_t *unicode; /* Unicode functions */
|
||||
hb_segment_properties_t props; /* Script, language, direction */
|
||||
hb_buffer_flags_t flags; /* BOT / EOT / etc. */
|
||||
hb_codepoint_t replacement; /* U+FFFD or something else. */
|
||||
|
||||
/* Buffer contents */
|
||||
|
||||
hb_buffer_content_type_t content_type;
|
||||
hb_segment_properties_t props; /* Script, language, direction */
|
||||
|
||||
bool in_error; /* Allocation failed */
|
||||
bool have_output; /* Whether we have an output buffer going on */
|
||||
|
@ -183,6 +181,9 @@ struct hb_buffer_t {
|
|||
inline bool ensure (unsigned int size)
|
||||
{ return likely (!size || size < allocated) ? true : enlarge (size); }
|
||||
|
||||
inline bool ensure_inplace (unsigned int size)
|
||||
{ return likely (!size || size < allocated); }
|
||||
|
||||
HB_INTERNAL bool make_room_for (unsigned int num_in, unsigned int num_out);
|
||||
HB_INTERNAL bool shift_forward (unsigned int count);
|
||||
|
||||
|
|
|
@ -178,6 +178,7 @@ hb_buffer_t::reset (void)
|
|||
|
||||
hb_unicode_funcs_destroy (unicode);
|
||||
unicode = hb_unicode_funcs_get_default ();
|
||||
flags = HB_BUFFER_FLAG_DEFAULT;
|
||||
replacement = HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT;
|
||||
|
||||
clear ();
|
||||
|
@ -191,7 +192,6 @@ hb_buffer_t::clear (void)
|
|||
|
||||
hb_segment_properties_t default_props = HB_SEGMENT_PROPERTIES_DEFAULT;
|
||||
props = default_props;
|
||||
flags = HB_BUFFER_FLAG_DEFAULT;
|
||||
|
||||
content_type = HB_BUFFER_CONTENT_TYPE_INVALID;
|
||||
in_error = false;
|
||||
|
@ -702,11 +702,11 @@ hb_buffer_get_empty (void)
|
|||
HB_OBJECT_HEADER_STATIC,
|
||||
|
||||
const_cast<hb_unicode_funcs_t *> (&_hb_unicode_funcs_nil),
|
||||
HB_SEGMENT_PROPERTIES_DEFAULT,
|
||||
HB_BUFFER_FLAG_DEFAULT,
|
||||
HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT,
|
||||
|
||||
HB_BUFFER_CONTENT_TYPE_INVALID,
|
||||
HB_SEGMENT_PROPERTIES_DEFAULT,
|
||||
true, /* in_error */
|
||||
true, /* have_output */
|
||||
true /* have_positions */
|
||||
|
|
|
@ -234,7 +234,7 @@ struct hb_language_item_t {
|
|||
|
||||
static hb_language_item_t *langs;
|
||||
|
||||
#ifdef HAVE_ATEXIT
|
||||
#ifdef HB_USE_ATEXIT
|
||||
static inline
|
||||
void free_langs (void)
|
||||
{
|
||||
|
@ -269,7 +269,7 @@ retry:
|
|||
goto retry;
|
||||
}
|
||||
|
||||
#ifdef HAVE_ATEXIT
|
||||
#ifdef HB_USE_ATEXIT
|
||||
if (!first_lang)
|
||||
atexit (free_langs); /* First person registers atexit() callback. */
|
||||
#endif
|
||||
|
|
|
@ -123,12 +123,13 @@ hb_direction_from_string (const char *str, int len);
|
|||
const char *
|
||||
hb_direction_to_string (hb_direction_t direction);
|
||||
|
||||
#define HB_DIRECTION_IS_VALID(dir) ((((unsigned int) (dir)) & ~3U) == 4)
|
||||
/* Direction must be valid for the following */
|
||||
#define HB_DIRECTION_IS_HORIZONTAL(dir) ((((unsigned int) (dir)) & ~1U) == 4)
|
||||
#define HB_DIRECTION_IS_VERTICAL(dir) ((((unsigned int) (dir)) & ~1U) == 6)
|
||||
#define HB_DIRECTION_IS_FORWARD(dir) ((((unsigned int) (dir)) & ~2U) == 4)
|
||||
#define HB_DIRECTION_IS_BACKWARD(dir) ((((unsigned int) (dir)) & ~2U) == 5)
|
||||
#define HB_DIRECTION_IS_VALID(dir) ((((unsigned int) (dir)) & ~3U) == 4)
|
||||
#define HB_DIRECTION_REVERSE(dir) ((hb_direction_t) (((unsigned int) (dir)) ^ 1)) /* Direction must be valid */
|
||||
#define HB_DIRECTION_REVERSE(dir) ((hb_direction_t) (((unsigned int) (dir)) ^ 1))
|
||||
|
||||
|
||||
/* hb_language_t */
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
*/
|
||||
|
||||
#define HB_SHAPER coretext
|
||||
#define hb_coretext_shaper_face_data_t CGFont
|
||||
#include "hb-shaper-impl-private.hh"
|
||||
|
||||
#include "hb-coretext.h"
|
||||
|
@ -77,10 +78,6 @@ HB_SHAPER_DATA_ENSURE_DECLARE(coretext, font)
|
|||
* shaper face data
|
||||
*/
|
||||
|
||||
struct hb_coretext_shaper_face_data_t {
|
||||
CGFontRef cg_font;
|
||||
};
|
||||
|
||||
static void
|
||||
release_data (void *info, const void *data, size_t size)
|
||||
{
|
||||
|
@ -93,13 +90,11 @@ release_data (void *info, const void *data, size_t size)
|
|||
hb_coretext_shaper_face_data_t *
|
||||
_hb_coretext_shaper_face_data_create (hb_face_t *face)
|
||||
{
|
||||
hb_coretext_shaper_face_data_t *data = (hb_coretext_shaper_face_data_t *) calloc (1, sizeof (hb_coretext_shaper_face_data_t));
|
||||
if (unlikely (!data))
|
||||
return NULL;
|
||||
hb_coretext_shaper_face_data_t *data = NULL;
|
||||
|
||||
if (face->destroy == (hb_destroy_func_t) CGFontRelease)
|
||||
{
|
||||
data->cg_font = CGFontRetain ((CGFontRef) face->user_data);
|
||||
data = CGFontRetain ((CGFontRef) face->user_data);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -110,14 +105,15 @@ _hb_coretext_shaper_face_data_create (hb_face_t *face)
|
|||
DEBUG_MSG (CORETEXT, face, "Face has empty blob");
|
||||
|
||||
CGDataProviderRef provider = CGDataProviderCreateWithData (blob, blob_data, blob_length, &release_data);
|
||||
data->cg_font = CGFontCreateWithDataProvider (provider);
|
||||
CGDataProviderRelease (provider);
|
||||
if (likely (provider))
|
||||
{
|
||||
data = CGFontCreateWithDataProvider (provider);
|
||||
CGDataProviderRelease (provider);
|
||||
}
|
||||
}
|
||||
|
||||
if (unlikely (!data->cg_font)) {
|
||||
if (unlikely (!data)) {
|
||||
DEBUG_MSG (CORETEXT, face, "Face CGFontCreateWithDataProvider() failed");
|
||||
free (data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return data;
|
||||
|
@ -126,8 +122,7 @@ _hb_coretext_shaper_face_data_create (hb_face_t *face)
|
|||
void
|
||||
_hb_coretext_shaper_face_data_destroy (hb_coretext_shaper_face_data_t *data)
|
||||
{
|
||||
CFRelease (data->cg_font);
|
||||
free (data);
|
||||
CFRelease (data);
|
||||
}
|
||||
|
||||
CGFontRef
|
||||
|
@ -135,7 +130,7 @@ hb_coretext_face_get_cg_font (hb_face_t *face)
|
|||
{
|
||||
if (unlikely (!hb_coretext_shaper_face_data_ensure (face))) return NULL;
|
||||
hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
|
||||
return face_data->cg_font;
|
||||
return face_data;
|
||||
}
|
||||
|
||||
|
||||
|
@ -159,7 +154,7 @@ _hb_coretext_shaper_font_data_create (hb_font_t *font)
|
|||
hb_face_t *face = font->face;
|
||||
hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
|
||||
|
||||
data->ct_font = CTFontCreateWithGraphicsFont (face_data->cg_font, font->y_scale, NULL, NULL);
|
||||
data->ct_font = CTFontCreateWithGraphicsFont (face_data, font->y_scale, NULL, NULL);
|
||||
if (unlikely (!data->ct_font)) {
|
||||
DEBUG_MSG (CORETEXT, font, "Font CTFontCreateWithGraphicsFont() failed");
|
||||
free (data);
|
||||
|
@ -332,7 +327,7 @@ struct range_record_t {
|
|||
#define kUpperCaseType 38
|
||||
|
||||
/* Table data courtesy of Apple. */
|
||||
struct feature_mapping_t {
|
||||
static const struct feature_mapping_t {
|
||||
FourCharCode otFeatureTag;
|
||||
uint16_t aatFeatureType;
|
||||
uint16_t selectorToEnable;
|
||||
|
@ -436,12 +431,29 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
|
|||
hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
|
||||
hb_coretext_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font);
|
||||
|
||||
/* Attach marks to their bases, to match the 'ot' shaper.
|
||||
* Adapted from hb-ot-shape:hb_form_clusters().
|
||||
* Note that this only makes us be closer to the 'ot' shaper,
|
||||
* but by no means the same. For example, if there's
|
||||
* B1 M1 B2 M2, and B1-B2 form a ligature, M2's cluster will
|
||||
* continue pointing to B2 even though B2 was merged into B1's
|
||||
* cluster... */
|
||||
{
|
||||
hb_unicode_funcs_t *unicode = buffer->unicode;
|
||||
unsigned int count = buffer->len;
|
||||
hb_glyph_info_t *info = buffer->info;
|
||||
for (unsigned int i = 1; i < count; i++)
|
||||
if (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (unicode->general_category (info[i].codepoint)))
|
||||
buffer->merge_clusters (i - 1, i + 1);
|
||||
}
|
||||
|
||||
hb_auto_array_t<feature_record_t> feature_records;
|
||||
hb_auto_array_t<range_record_t> range_records;
|
||||
|
||||
/*
|
||||
* Set up features.
|
||||
* (copied + modified from code from hb-uniscribe.cc)
|
||||
*/
|
||||
hb_auto_array_t<feature_record_t> feature_records;
|
||||
hb_auto_array_t<range_record_t> range_records;
|
||||
if (num_features)
|
||||
{
|
||||
/* Sort features by start/end events. */
|
||||
|
@ -549,7 +561,6 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
|
|||
CFRelease (attributes);
|
||||
|
||||
range->font = CTFontCreateCopyWithAttributes (font_data->ct_font, 0.0, NULL, font_desc);
|
||||
|
||||
CFRelease (font_desc);
|
||||
}
|
||||
else
|
||||
|
@ -584,32 +595,26 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
|
|||
num_features = 0;
|
||||
}
|
||||
|
||||
#define FAIL(...) \
|
||||
HB_STMT_START { \
|
||||
DEBUG_MSG (CORETEXT, NULL, __VA_ARGS__); \
|
||||
return false; \
|
||||
} HB_STMT_END;
|
||||
|
||||
unsigned int scratch_size;
|
||||
hb_buffer_t::scratch_buffer_t *scratch = buffer->get_scratch_buffer (&scratch_size);
|
||||
|
||||
#define ALLOCATE_ARRAY(Type, name, len) \
|
||||
#define ALLOCATE_ARRAY(Type, name, len, on_no_room) \
|
||||
Type *name = (Type *) scratch; \
|
||||
{ \
|
||||
unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch)); \
|
||||
assert (_consumed <= scratch_size); \
|
||||
if (unlikely (_consumed > scratch_size)) \
|
||||
{ \
|
||||
on_no_room; \
|
||||
assert (0); \
|
||||
} \
|
||||
scratch += _consumed; \
|
||||
scratch_size -= _consumed; \
|
||||
}
|
||||
|
||||
#define utf16_index() var1.u32
|
||||
|
||||
ALLOCATE_ARRAY (UniChar, pchars, buffer->len * 2);
|
||||
|
||||
ALLOCATE_ARRAY (UniChar, pchars, buffer->len * 2, /*nothing*/);
|
||||
unsigned int chars_len = 0;
|
||||
for (unsigned int i = 0; i < buffer->len; i++) {
|
||||
hb_codepoint_t c = buffer->info[i].codepoint;
|
||||
buffer->info[i].utf16_index() = chars_len;
|
||||
if (likely (c <= 0xFFFFu))
|
||||
pchars[chars_len++] = c;
|
||||
else if (unlikely (c > 0x10FFFFu))
|
||||
|
@ -620,232 +625,439 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
|
|||
}
|
||||
}
|
||||
|
||||
#undef utf16_index
|
||||
|
||||
CFStringRef string_ref = CFStringCreateWithCharactersNoCopy (NULL,
|
||||
pchars, chars_len,
|
||||
kCFAllocatorNull);
|
||||
|
||||
CFMutableAttributedStringRef attr_string = CFAttributedStringCreateMutable (NULL, chars_len);
|
||||
CFAttributedStringReplaceString (attr_string, CFRangeMake (0, 0), string_ref);
|
||||
CFAttributedStringSetAttribute (attr_string, CFRangeMake (0, chars_len),
|
||||
kCTFontAttributeName, font_data->ct_font);
|
||||
|
||||
if (num_features)
|
||||
ALLOCATE_ARRAY (unsigned int, log_clusters, chars_len, /*nothing*/);
|
||||
chars_len = 0;
|
||||
for (unsigned int i = 0; i < buffer->len; i++)
|
||||
{
|
||||
ALLOCATE_ARRAY (unsigned int, log_clusters, chars_len);
|
||||
|
||||
/* Need log_clusters to assign features. */
|
||||
chars_len = 0;
|
||||
for (unsigned int i = 0; i < buffer->len; i++)
|
||||
{
|
||||
hb_codepoint_t c = buffer->info[i].codepoint;
|
||||
unsigned int cluster = buffer->info[i].cluster;
|
||||
log_clusters[chars_len++] = cluster;
|
||||
if (hb_in_range (c, 0x10000u, 0x10FFFFu))
|
||||
log_clusters[chars_len++] = cluster; /* Surrogates. */
|
||||
}
|
||||
|
||||
unsigned int start = 0;
|
||||
range_record_t *last_range = &range_records[0];
|
||||
for (unsigned int k = 0; k < chars_len; k++)
|
||||
{
|
||||
range_record_t *range = last_range;
|
||||
while (log_clusters[k] < range->index_first)
|
||||
range--;
|
||||
while (log_clusters[k] > range->index_last)
|
||||
range++;
|
||||
if (range != last_range)
|
||||
{
|
||||
if (last_range->font)
|
||||
CFAttributedStringSetAttribute (attr_string, CFRangeMake (start, k - start),
|
||||
kCTFontAttributeName, last_range->font);
|
||||
|
||||
start = k;
|
||||
}
|
||||
|
||||
last_range = range;
|
||||
}
|
||||
if (start != chars_len && last_range->font)
|
||||
CFAttributedStringSetAttribute (attr_string, CFRangeMake (start, chars_len - start - 1),
|
||||
kCTFontAttributeName, last_range->font);
|
||||
|
||||
for (unsigned int i = 0; i < range_records.len; i++)
|
||||
if (range_records[i].font)
|
||||
CFRelease (range_records[i].font);
|
||||
hb_codepoint_t c = buffer->info[i].codepoint;
|
||||
unsigned int cluster = buffer->info[i].cluster;
|
||||
log_clusters[chars_len++] = cluster;
|
||||
if (hb_in_range (c, 0x10000u, 0x10FFFFu))
|
||||
log_clusters[chars_len++] = cluster; /* Surrogates. */
|
||||
}
|
||||
|
||||
CTLineRef line = CTLineCreateWithAttributedString (attr_string);
|
||||
CFRelease (attr_string);
|
||||
#define FAIL(...) \
|
||||
HB_STMT_START { \
|
||||
DEBUG_MSG (CORETEXT, NULL, __VA_ARGS__); \
|
||||
ret = false; \
|
||||
goto fail; \
|
||||
} HB_STMT_END;
|
||||
|
||||
CFArrayRef glyph_runs = CTLineGetGlyphRuns (line);
|
||||
unsigned int num_runs = CFArrayGetCount (glyph_runs);
|
||||
bool ret = true;
|
||||
CFStringRef string_ref = NULL;
|
||||
CTLineRef line = NULL;
|
||||
|
||||
buffer->len = 0;
|
||||
|
||||
const CFRange range_all = CFRangeMake (0, 0);
|
||||
|
||||
for (unsigned int i = 0; i < num_runs; i++)
|
||||
if (0)
|
||||
{
|
||||
CTRunRef run = (CTRunRef) CFArrayGetValueAtIndex (glyph_runs, i);
|
||||
resize_and_retry:
|
||||
DEBUG_MSG (CORETEXT, buffer, "Buffer resize");
|
||||
/* string_ref uses the scratch-buffer for backing store, and line references
|
||||
* string_ref (via attr_string). We must release those before resizing buffer. */
|
||||
assert (string_ref);
|
||||
assert (line);
|
||||
CFRelease (string_ref);
|
||||
CFRelease (line);
|
||||
string_ref = NULL;
|
||||
line = NULL;
|
||||
|
||||
/* CoreText does automatic font fallback (AKA "cascading") for characters
|
||||
* not supported by the requested font, and provides no way to turn it off,
|
||||
* so we detect if the returned run uses a font other than the requested
|
||||
* one and fill in the buffer with .notdef glyphs instead of random glyph
|
||||
* indices from a different font.
|
||||
*/
|
||||
CFDictionaryRef attributes = CTRunGetAttributes (run);
|
||||
CTFontRef run_ct_font = static_cast<CTFontRef>(CFDictionaryGetValue (attributes, kCTFontAttributeName));
|
||||
CGFontRef run_cg_font = CTFontCopyGraphicsFont (run_ct_font, 0);
|
||||
if (!CFEqual (run_cg_font, face_data->cg_font))
|
||||
{
|
||||
CFRelease (run_cg_font);
|
||||
/* Get previous start-of-scratch-area, that we use later for readjusting
|
||||
* our existing scratch arrays. */
|
||||
unsigned int old_scratch_used;
|
||||
hb_buffer_t::scratch_buffer_t *old_scratch;
|
||||
old_scratch = buffer->get_scratch_buffer (&old_scratch_used);
|
||||
old_scratch_used = scratch - old_scratch;
|
||||
|
||||
CFRange range = CTRunGetStringRange (run);
|
||||
buffer->ensure (buffer->len + range.length);
|
||||
if (buffer->in_error)
|
||||
FAIL ("Buffer resize failed");
|
||||
hb_glyph_info_t *info = buffer->info + buffer->len;
|
||||
|
||||
CGGlyph notdef = 0;
|
||||
double advance = CTFontGetAdvancesForGlyphs (font_data->ct_font, kCTFontHorizontalOrientation, ¬def, NULL, 1);
|
||||
|
||||
for (CFIndex j = range.location; j < range.location + range.length; j++)
|
||||
{
|
||||
UniChar ch = CFStringGetCharacterAtIndex (string_ref, j);
|
||||
if (hb_in_range<UniChar> (ch, 0xDC00u, 0xDFFFu) && range.location < j)
|
||||
{
|
||||
ch = CFStringGetCharacterAtIndex (string_ref, j - 1);
|
||||
if (hb_in_range<UniChar> (ch, 0xD800u, 0xDBFFu))
|
||||
/* This is the second of a surrogate pair. Don't need .notdef
|
||||
* for this one. */
|
||||
continue;
|
||||
}
|
||||
|
||||
info->codepoint = notdef;
|
||||
/* TODO We have to fixup clusters later. See vis_clusters in
|
||||
* hb-uniscribe.cc for example. */
|
||||
info->cluster = j;
|
||||
|
||||
info->mask = advance;
|
||||
info->var1.u32 = 0;
|
||||
info->var2.u32 = 0;
|
||||
|
||||
info++;
|
||||
buffer->len++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
CFRelease (run_cg_font);
|
||||
|
||||
unsigned int num_glyphs = CTRunGetGlyphCount (run);
|
||||
if (num_glyphs == 0)
|
||||
continue;
|
||||
|
||||
buffer->ensure (buffer->len + num_glyphs);
|
||||
if (unlikely (!buffer->ensure (buffer->allocated * 2)))
|
||||
FAIL ("Buffer resize failed");
|
||||
|
||||
/* Adjust scratch, pchars, and log_cluster arrays. This is ugly, but really the
|
||||
* cleanest way to do without completely restructuring the rest of this shaper. */
|
||||
scratch = buffer->get_scratch_buffer (&scratch_size);
|
||||
pchars = reinterpret_cast<UniChar *> (((char *) scratch + ((char *) pchars - (char *) old_scratch)));
|
||||
log_clusters = reinterpret_cast<unsigned int *> (((char *) scratch + ((char *) log_clusters - (char *) old_scratch)));
|
||||
scratch += old_scratch_used;
|
||||
scratch_size -= old_scratch_used;
|
||||
}
|
||||
retry:
|
||||
{
|
||||
string_ref = CFStringCreateWithCharactersNoCopy (NULL,
|
||||
pchars, chars_len,
|
||||
kCFAllocatorNull);
|
||||
if (unlikely (!string_ref))
|
||||
FAIL ("CFStringCreateWithCharactersNoCopy failed");
|
||||
|
||||
/* Testing indicates that CTRunGetGlyphsPtr, etc (almost?) always
|
||||
* succeed, and so copying data to our own buffer will be rare. */
|
||||
/* Create an attributed string, populate it, and create a line from it, then release attributed string. */
|
||||
{
|
||||
CFMutableAttributedStringRef attr_string = CFAttributedStringCreateMutable (kCFAllocatorDefault,
|
||||
chars_len);
|
||||
if (unlikely (!attr_string))
|
||||
FAIL ("CFAttributedStringCreateMutable failed");
|
||||
CFAttributedStringReplaceString (attr_string, CFRangeMake (0, 0), string_ref);
|
||||
if (HB_DIRECTION_IS_VERTICAL (buffer->props.direction))
|
||||
{
|
||||
CFAttributedStringSetAttribute (attr_string, CFRangeMake (0, chars_len),
|
||||
kCTVerticalFormsAttributeName, kCFBooleanTrue);
|
||||
}
|
||||
|
||||
const CGGlyph* glyphs = CTRunGetGlyphsPtr (run);
|
||||
if (!glyphs) {
|
||||
ALLOCATE_ARRAY (CGGlyph, glyph_buf, num_glyphs);
|
||||
CTRunGetGlyphs (run, range_all, glyph_buf);
|
||||
glyphs = glyph_buf;
|
||||
if (buffer->props.language)
|
||||
{
|
||||
/* What's the iOS equivalent of this check?
|
||||
* The symbols was introduced in iOS 7.0.
|
||||
* At any rate, our fallback is safe and works fine. */
|
||||
#if MAC_OS_X_VERSION_MIN_REQUIRED < 1090
|
||||
# define kCTLanguageAttributeName CFSTR ("NSLanguage")
|
||||
#endif
|
||||
CFStringRef lang = CFStringCreateWithCStringNoCopy (kCFAllocatorDefault,
|
||||
hb_language_to_string (buffer->props.language),
|
||||
kCFStringEncodingUTF8,
|
||||
kCFAllocatorNull);
|
||||
if (unlikely (!lang))
|
||||
FAIL ("CFStringCreateWithCStringNoCopy failed");
|
||||
CFAttributedStringSetAttribute (attr_string, CFRangeMake (0, chars_len),
|
||||
kCTLanguageAttributeName, lang);
|
||||
CFRelease (lang);
|
||||
}
|
||||
CFAttributedStringSetAttribute (attr_string, CFRangeMake (0, chars_len),
|
||||
kCTFontAttributeName, font_data->ct_font);
|
||||
|
||||
if (num_features)
|
||||
{
|
||||
unsigned int start = 0;
|
||||
range_record_t *last_range = &range_records[0];
|
||||
for (unsigned int k = 0; k < chars_len; k++)
|
||||
{
|
||||
range_record_t *range = last_range;
|
||||
while (log_clusters[k] < range->index_first)
|
||||
range--;
|
||||
while (log_clusters[k] > range->index_last)
|
||||
range++;
|
||||
if (range != last_range)
|
||||
{
|
||||
if (last_range->font)
|
||||
CFAttributedStringSetAttribute (attr_string, CFRangeMake (start, k - start),
|
||||
kCTFontAttributeName, last_range->font);
|
||||
|
||||
start = k;
|
||||
}
|
||||
|
||||
last_range = range;
|
||||
}
|
||||
if (start != chars_len && last_range->font)
|
||||
CFAttributedStringSetAttribute (attr_string, CFRangeMake (start, chars_len - start),
|
||||
kCTFontAttributeName, last_range->font);
|
||||
}
|
||||
|
||||
int level = HB_DIRECTION_IS_FORWARD (buffer->props.direction) ? 0 : 1;
|
||||
CFNumberRef level_number = CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &level);
|
||||
CFDictionaryRef options = CFDictionaryCreate (kCFAllocatorDefault,
|
||||
(const void **) &kCTTypesetterOptionForcedEmbeddingLevel,
|
||||
(const void **) &level_number,
|
||||
1,
|
||||
&kCFTypeDictionaryKeyCallBacks,
|
||||
&kCFTypeDictionaryValueCallBacks);
|
||||
if (unlikely (!options))
|
||||
FAIL ("CFDictionaryCreate failed");
|
||||
|
||||
CTTypesetterRef typesetter = CTTypesetterCreateWithAttributedStringAndOptions (attr_string, options);
|
||||
CFRelease (options);
|
||||
CFRelease (attr_string);
|
||||
if (unlikely (!typesetter))
|
||||
FAIL ("CTTypesetterCreateWithAttributedStringAndOptions failed");
|
||||
|
||||
line = CTTypesetterCreateLine (typesetter, CFRangeMake(0, 0));
|
||||
CFRelease (typesetter);
|
||||
if (unlikely (!line))
|
||||
FAIL ("CTTypesetterCreateLine failed");
|
||||
}
|
||||
|
||||
const CGPoint* positions = CTRunGetPositionsPtr (run);
|
||||
if (!positions) {
|
||||
ALLOCATE_ARRAY (CGPoint, position_buf, num_glyphs);
|
||||
CTRunGetPositions (run, range_all, position_buf);
|
||||
positions = position_buf;
|
||||
}
|
||||
CFArrayRef glyph_runs = CTLineGetGlyphRuns (line);
|
||||
unsigned int num_runs = CFArrayGetCount (glyph_runs);
|
||||
DEBUG_MSG (CORETEXT, NULL, "Num runs: %d", num_runs);
|
||||
|
||||
const CFIndex* string_indices = CTRunGetStringIndicesPtr (run);
|
||||
if (!string_indices) {
|
||||
ALLOCATE_ARRAY (CFIndex, index_buf, num_glyphs);
|
||||
CTRunGetStringIndices (run, range_all, index_buf);
|
||||
string_indices = index_buf;
|
||||
}
|
||||
buffer->len = 0;
|
||||
uint32_t status_and = ~0, status_or = 0;
|
||||
|
||||
const CFRange range_all = CFRangeMake (0, 0);
|
||||
|
||||
for (unsigned int i = 0; i < num_runs; i++)
|
||||
{
|
||||
CTRunRef run = static_cast<CTRunRef>(CFArrayGetValueAtIndex (glyph_runs, i));
|
||||
CTRunStatus run_status = CTRunGetStatus (run);
|
||||
status_or |= run_status;
|
||||
status_and &= run_status;
|
||||
DEBUG_MSG (CORETEXT, run, "CTRunStatus: %x", run_status);
|
||||
|
||||
/* CoreText does automatic font fallback (AKA "cascading") for characters
|
||||
* not supported by the requested font, and provides no way to turn it off,
|
||||
* so we must detect if the returned run uses a font other than the requested
|
||||
* one and fill in the buffer with .notdef glyphs instead of random glyph
|
||||
* indices from a different font.
|
||||
*/
|
||||
CFDictionaryRef attributes = CTRunGetAttributes (run);
|
||||
CTFontRef run_ct_font = static_cast<CTFontRef>(CFDictionaryGetValue (attributes, kCTFontAttributeName));
|
||||
if (!CFEqual (run_ct_font, font_data->ct_font))
|
||||
{
|
||||
/* The run doesn't use our main font instance. We have to figure out
|
||||
* whether font fallback happened, or this is just CoreText giving us
|
||||
* another CTFont using the same underlying CGFont. CoreText seems
|
||||
* to do that in a variety of situations, one of which being vertical
|
||||
* text, but also perhaps for caching reasons.
|
||||
*
|
||||
* First, see if it uses any of our subfonts created to set font features...
|
||||
*
|
||||
* Next, compare the CGFont to the one we used to create our fonts.
|
||||
* Even this doesn't work all the time.
|
||||
*
|
||||
* Finally, we compare PS names, which I don't think are unique...
|
||||
*
|
||||
* Looks like if we really want to be sure here we have to modify the
|
||||
* font to change the name table, similar to what we do in the uniscribe
|
||||
* backend.
|
||||
*
|
||||
* However, even that wouldn't work if we were passed in the CGFont to
|
||||
* begin with.
|
||||
*
|
||||
* Webkit uses a slightly different approach: it installs LastResort
|
||||
* as fallback chain, and then checks PS name of used font against
|
||||
* LastResort. That one is safe for any font except for LastResort,
|
||||
* as opposed to ours, which can fail if we are using any uninstalled
|
||||
* font that has the same name as an installed font.
|
||||
*
|
||||
* See: http://github.com/behdad/harfbuzz/pull/36
|
||||
*/
|
||||
bool matched = false;
|
||||
for (unsigned int i = 0; i < range_records.len; i++)
|
||||
if (range_records[i].font && CFEqual (run_ct_font, range_records[i].font))
|
||||
{
|
||||
matched = true;
|
||||
break;
|
||||
}
|
||||
if (!matched)
|
||||
{
|
||||
CGFontRef run_cg_font = CTFontCopyGraphicsFont (run_ct_font, 0);
|
||||
if (run_cg_font)
|
||||
{
|
||||
matched = CFEqual (run_cg_font, face_data);
|
||||
CFRelease (run_cg_font);
|
||||
}
|
||||
}
|
||||
if (!matched)
|
||||
{
|
||||
CFStringRef font_ps_name = CTFontCopyName (font_data->ct_font, kCTFontPostScriptNameKey);
|
||||
CFStringRef run_ps_name = CTFontCopyName (run_ct_font, kCTFontPostScriptNameKey);
|
||||
CFComparisonResult result = CFStringCompare (run_ps_name, font_ps_name, 0);
|
||||
CFRelease (run_ps_name);
|
||||
CFRelease (font_ps_name);
|
||||
if (result == kCFCompareEqualTo)
|
||||
matched = true;
|
||||
}
|
||||
if (!matched)
|
||||
{
|
||||
CFRange range = CTRunGetStringRange (run);
|
||||
DEBUG_MSG (CORETEXT, run, "Run used fallback font: %ld..%ld",
|
||||
range.location, range.location + range.length);
|
||||
if (!buffer->ensure_inplace (buffer->len + range.length))
|
||||
goto resize_and_retry;
|
||||
hb_glyph_info_t *info = buffer->info + buffer->len;
|
||||
|
||||
CGGlyph notdef = 0;
|
||||
double advance = CTFontGetAdvancesForGlyphs (font_data->ct_font, kCTFontHorizontalOrientation, ¬def, NULL, 1);
|
||||
|
||||
unsigned int old_len = buffer->len;
|
||||
for (CFIndex j = range.location; j < range.location + range.length; j++)
|
||||
{
|
||||
UniChar ch = CFStringGetCharacterAtIndex (string_ref, j);
|
||||
if (hb_in_range<UniChar> (ch, 0xDC00u, 0xDFFFu) && range.location < j)
|
||||
{
|
||||
ch = CFStringGetCharacterAtIndex (string_ref, j - 1);
|
||||
if (hb_in_range<UniChar> (ch, 0xD800u, 0xDBFFu))
|
||||
/* This is the second of a surrogate pair. Don't need .notdef
|
||||
* for this one. */
|
||||
continue;
|
||||
}
|
||||
|
||||
info->codepoint = notdef;
|
||||
info->cluster = log_clusters[j];
|
||||
|
||||
info->mask = advance;
|
||||
info->var1.u32 = 0;
|
||||
info->var2.u32 = 0;
|
||||
|
||||
info++;
|
||||
buffer->len++;
|
||||
}
|
||||
if (HB_DIRECTION_IS_BACKWARD (buffer->props.direction))
|
||||
buffer->reverse_range (old_len, buffer->len);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int num_glyphs = CTRunGetGlyphCount (run);
|
||||
if (num_glyphs == 0)
|
||||
continue;
|
||||
|
||||
if (!buffer->ensure_inplace (buffer->len + num_glyphs))
|
||||
goto resize_and_retry;
|
||||
|
||||
hb_glyph_info_t *run_info = buffer->info + buffer->len;
|
||||
|
||||
/* Testing used to indicate that CTRunGetGlyphsPtr, etc (almost?) always
|
||||
* succeed, and so copying data to our own buffer will be rare. Reports
|
||||
* have it that this changed in OS X 10.10 Yosemite, and NULL is returned
|
||||
* frequently. At any rate, we can test that codepath by setting USE_PTR
|
||||
* to false. */
|
||||
|
||||
#define USE_PTR true
|
||||
|
||||
#define SCRATCH_SAVE() \
|
||||
unsigned int scratch_size_saved = scratch_size; \
|
||||
hb_buffer_t::scratch_buffer_t *scratch_saved = scratch
|
||||
|
||||
#define SCRATCH_RESTORE() \
|
||||
scratch_size = scratch_size_saved; \
|
||||
scratch = scratch_saved;
|
||||
|
||||
{
|
||||
SCRATCH_SAVE();
|
||||
const CGGlyph* glyphs = USE_PTR ? CTRunGetGlyphsPtr (run) : NULL;
|
||||
if (!glyphs) {
|
||||
ALLOCATE_ARRAY (CGGlyph, glyph_buf, num_glyphs, goto resize_and_retry);
|
||||
CTRunGetGlyphs (run, range_all, glyph_buf);
|
||||
glyphs = glyph_buf;
|
||||
}
|
||||
const CFIndex* string_indices = USE_PTR ? CTRunGetStringIndicesPtr (run) : NULL;
|
||||
if (!string_indices) {
|
||||
ALLOCATE_ARRAY (CFIndex, index_buf, num_glyphs, goto resize_and_retry);
|
||||
CTRunGetStringIndices (run, range_all, index_buf);
|
||||
string_indices = index_buf;
|
||||
}
|
||||
hb_glyph_info_t *info = run_info;
|
||||
for (unsigned int j = 0; j < num_glyphs; j++)
|
||||
{
|
||||
info->codepoint = glyphs[j];
|
||||
info->cluster = log_clusters[string_indices[j]];
|
||||
info++;
|
||||
}
|
||||
SCRATCH_RESTORE();
|
||||
}
|
||||
{
|
||||
SCRATCH_SAVE();
|
||||
const CGPoint* positions = USE_PTR ? CTRunGetPositionsPtr (run) : NULL;
|
||||
if (!positions) {
|
||||
ALLOCATE_ARRAY (CGPoint, position_buf, num_glyphs, goto resize_and_retry);
|
||||
CTRunGetPositions (run, range_all, position_buf);
|
||||
positions = position_buf;
|
||||
}
|
||||
double run_advance = CTRunGetTypographicBounds (run, range_all, NULL, NULL, NULL);
|
||||
DEBUG_MSG (CORETEXT, run, "Run advance: %g", run_advance);
|
||||
hb_glyph_info_t *info = run_info;
|
||||
if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction))
|
||||
{
|
||||
for (unsigned int j = 0; j < num_glyphs; j++)
|
||||
{
|
||||
double advance = (j + 1 < num_glyphs ? positions[j + 1].x : positions[0].x + run_advance) - positions[j].x;
|
||||
info->mask = advance;
|
||||
info->var1.u32 = positions[0].x; /* Yes, zero. */
|
||||
info->var2.u32 = positions[j].y;
|
||||
info++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
run_advance = -run_advance;
|
||||
for (unsigned int j = 0; j < num_glyphs; j++)
|
||||
{
|
||||
double advance = (j + 1 < num_glyphs ? positions[j + 1].y : positions[0].y + run_advance) - positions[j].y;
|
||||
info->mask = advance;
|
||||
info->var1.u32 = positions[j].x;
|
||||
info->var2.u32 = positions[0].y; /* Yes, zero. */
|
||||
info++;
|
||||
}
|
||||
}
|
||||
SCRATCH_RESTORE();
|
||||
}
|
||||
#undef SCRATCH_RESTORE
|
||||
#undef SCRATCH_SAVE
|
||||
#undef USE_PTR
|
||||
#undef ALLOCATE_ARRAY
|
||||
|
||||
double run_width = CTRunGetTypographicBounds (run, range_all, NULL, NULL, NULL);
|
||||
|
||||
for (unsigned int j = 0; j < num_glyphs; j++) {
|
||||
double advance = (j + 1 < num_glyphs ? positions[j + 1].x : positions[0].x + run_width) - positions[j].x;
|
||||
|
||||
hb_glyph_info_t *info = &buffer->info[buffer->len];
|
||||
|
||||
info->codepoint = glyphs[j];
|
||||
info->cluster = string_indices[j];
|
||||
|
||||
/* Currently, we do all x-positioning by setting the advance, we never use x-offset. */
|
||||
info->mask = advance;
|
||||
info->var1.u32 = 0;
|
||||
info->var2.u32 = positions[j].y;
|
||||
|
||||
buffer->len++;
|
||||
buffer->len += num_glyphs;
|
||||
}
|
||||
}
|
||||
|
||||
buffer->clear_positions ();
|
||||
/* Make sure all runs had the expected direction. */
|
||||
bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
|
||||
assert (bool (status_and & kCTRunStatusRightToLeft) == backward);
|
||||
assert (bool (status_or & kCTRunStatusRightToLeft) == backward);
|
||||
|
||||
unsigned int count = buffer->len;
|
||||
for (unsigned int i = 0; i < count; ++i) {
|
||||
hb_glyph_info_t *info = &buffer->info[i];
|
||||
hb_glyph_position_t *pos = &buffer->pos[i];
|
||||
buffer->clear_positions ();
|
||||
|
||||
/* TODO vertical */
|
||||
pos->x_advance = info->mask;
|
||||
pos->x_offset = info->var1.u32;
|
||||
pos->y_offset = info->var2.u32;
|
||||
}
|
||||
|
||||
/* Fix up clusters so that we never return out-of-order indices;
|
||||
* if core text has reordered glyphs, we'll merge them to the
|
||||
* beginning of the reordered cluster.
|
||||
*
|
||||
* This does *not* mean we'll form the same clusters as Uniscribe
|
||||
* or the native OT backend, only that the cluster indices will be
|
||||
* monotonic in the output buffer. */
|
||||
if (HB_DIRECTION_IS_FORWARD (buffer->props.direction)) {
|
||||
unsigned int prev_cluster = 0;
|
||||
for (unsigned int i = 0; i < count; i++) {
|
||||
unsigned int curr_cluster = buffer->info[i].cluster;
|
||||
if (curr_cluster < prev_cluster) {
|
||||
for (unsigned int j = i; j > 0; j--) {
|
||||
if (buffer->info[j - 1].cluster > curr_cluster)
|
||||
buffer->info[j - 1].cluster = curr_cluster;
|
||||
else
|
||||
break;
|
||||
}
|
||||
unsigned int count = buffer->len;
|
||||
hb_glyph_info_t *info = buffer->info;
|
||||
hb_glyph_position_t *pos = buffer->pos;
|
||||
if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction))
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
pos->x_advance = info->mask;
|
||||
pos->x_offset = info->var1.u32;
|
||||
pos->y_offset = info->var2.u32;
|
||||
info++, pos++;
|
||||
}
|
||||
prev_cluster = curr_cluster;
|
||||
}
|
||||
} else {
|
||||
unsigned int prev_cluster = (unsigned int)-1;
|
||||
for (unsigned int i = 0; i < count; i++) {
|
||||
unsigned int curr_cluster = buffer->info[i].cluster;
|
||||
if (curr_cluster > prev_cluster) {
|
||||
for (unsigned int j = i; j > 0; j--) {
|
||||
if (buffer->info[j - 1].cluster < curr_cluster)
|
||||
buffer->info[j - 1].cluster = curr_cluster;
|
||||
else
|
||||
break;
|
||||
}
|
||||
else
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
pos->y_advance = info->mask;
|
||||
pos->x_offset = info->var1.u32;
|
||||
pos->y_offset = info->var2.u32;
|
||||
info++, pos++;
|
||||
}
|
||||
|
||||
/* Fix up clusters so that we never return out-of-order indices;
|
||||
* if core text has reordered glyphs, we'll merge them to the
|
||||
* beginning of the reordered cluster. CoreText is nice enough
|
||||
* to tell us whenever it has produced nonmonotonic results...
|
||||
* Note that we assume the input clusters were nonmonotonic to
|
||||
* begin with.
|
||||
*
|
||||
* This does *not* mean we'll form the same clusters as Uniscribe
|
||||
* or the native OT backend, only that the cluster indices will be
|
||||
* monotonic in the output buffer. */
|
||||
if (count > 1 && (status_or & kCTRunStatusNonMonotonic))
|
||||
{
|
||||
hb_glyph_info_t *info = buffer->info;
|
||||
if (HB_DIRECTION_IS_FORWARD (buffer->props.direction))
|
||||
{
|
||||
unsigned int cluster = info[count - 1].cluster;
|
||||
for (unsigned int i = count - 1; i > 0; i--)
|
||||
{
|
||||
cluster = MIN (cluster, info[i - 1].cluster);
|
||||
info[i - 1].cluster = cluster;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned int cluster = info[0].cluster;
|
||||
for (unsigned int i = 1; i < count; i++)
|
||||
{
|
||||
cluster = MIN (cluster, info[i].cluster);
|
||||
info[i].cluster = cluster;
|
||||
}
|
||||
}
|
||||
prev_cluster = curr_cluster;
|
||||
}
|
||||
}
|
||||
|
||||
CFRelease (string_ref);
|
||||
CFRelease (line);
|
||||
#undef FAIL
|
||||
|
||||
return true;
|
||||
fail:
|
||||
if (string_ref)
|
||||
CFRelease (string_ref);
|
||||
if (line)
|
||||
CFRelease (line);
|
||||
|
||||
for (unsigned int i = 0; i < range_records.len; i++)
|
||||
if (range_records[i].font)
|
||||
CFRelease (range_records[i].font);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -66,7 +66,7 @@ struct hb_face_t {
|
|||
{
|
||||
hb_blob_t *blob;
|
||||
|
||||
if (unlikely (!this || !reference_table_func))
|
||||
if (unlikely (!reference_table_func))
|
||||
return hb_blob_get_empty ();
|
||||
|
||||
blob = reference_table_func (/*XXX*/const_cast<hb_face_t *> (this), tag, user_data);
|
||||
|
|
|
@ -136,7 +136,7 @@ hb_ft_get_glyph_v_origin (hb_font_t *font HB_UNUSED,
|
|||
void *user_data HB_UNUSED)
|
||||
{
|
||||
FT_Face ft_face = (FT_Face) font_data;
|
||||
int load_flags = FT_LOAD_DEFAULT;
|
||||
int load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING;
|
||||
|
||||
if (unlikely (FT_Load_Glyph (ft_face, glyph, load_flags)))
|
||||
return false;
|
||||
|
@ -185,7 +185,7 @@ hb_ft_get_glyph_extents (hb_font_t *font HB_UNUSED,
|
|||
void *user_data HB_UNUSED)
|
||||
{
|
||||
FT_Face ft_face = (FT_Face) font_data;
|
||||
int load_flags = FT_LOAD_DEFAULT;
|
||||
int load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING;
|
||||
|
||||
if (unlikely (FT_Load_Glyph (ft_face, glyph, load_flags)))
|
||||
return false;
|
||||
|
@ -455,7 +455,7 @@ retry:
|
|||
goto retry;
|
||||
}
|
||||
|
||||
#ifdef HAVE_ATEXIT
|
||||
#ifdef HB_USE_ATEXIT
|
||||
atexit (free_ft_library); /* First person registers atexit() callback. */
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -274,8 +274,8 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan,
|
|||
while ((DIV_CEIL (sizeof (hb_graphite2_cluster_t) * buffer->len, sizeof (*scratch)) +
|
||||
DIV_CEIL (sizeof (hb_codepoint_t) * glyph_count, sizeof (*scratch))) > scratch_size)
|
||||
{
|
||||
buffer->ensure (buffer->allocated * 2);
|
||||
if (unlikely (buffer->in_error)) {
|
||||
if (unlikely (!buffer->ensure (buffer->allocated * 2)))
|
||||
{
|
||||
if (feats) gr_featureval_destroy (feats);
|
||||
gr_seg_destroy (seg);
|
||||
return false;
|
||||
|
|
|
@ -46,7 +46,7 @@
|
|||
|
||||
#include <windows.h>
|
||||
typedef CRITICAL_SECTION hb_mutex_impl_t;
|
||||
#define HB_MUTEX_IMPL_INIT { NULL, 0, 0, NULL, NULL, 0 }
|
||||
#define HB_MUTEX_IMPL_INIT {0}
|
||||
#define hb_mutex_impl_init(M) InitializeCriticalSection (M)
|
||||
#define hb_mutex_impl_lock(M) EnterCriticalSection (M)
|
||||
#define hb_mutex_impl_unlock(M) LeaveCriticalSection (M)
|
||||
|
|
|
@ -68,8 +68,6 @@ struct hb_reference_count_t
|
|||
#define HB_USER_DATA_ARRAY_INIT {HB_MUTEX_INIT, HB_LOCKABLE_SET_INIT}
|
||||
struct hb_user_data_array_t
|
||||
{
|
||||
/* TODO Add tracing. */
|
||||
|
||||
struct hb_user_data_item_t {
|
||||
hb_user_data_key_t *key;
|
||||
void *data;
|
||||
|
@ -106,69 +104,6 @@ struct hb_object_header_t
|
|||
|
||||
#define HB_OBJECT_HEADER_STATIC {HB_REFERENCE_COUNT_INVALID, HB_USER_DATA_ARRAY_INIT}
|
||||
|
||||
static inline void *create (unsigned int size) {
|
||||
hb_object_header_t *obj = (hb_object_header_t *) calloc (1, size);
|
||||
|
||||
if (likely (obj))
|
||||
obj->init ();
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
inline void init (void) {
|
||||
ref_count.init (1);
|
||||
user_data.init ();
|
||||
}
|
||||
|
||||
inline bool is_inert (void) const {
|
||||
return unlikely (ref_count.is_invalid ());
|
||||
}
|
||||
|
||||
inline void reference (void) {
|
||||
if (unlikely (!this || this->is_inert ()))
|
||||
return;
|
||||
ref_count.inc ();
|
||||
}
|
||||
|
||||
inline bool destroy (void) {
|
||||
if (unlikely (!this || this->is_inert ()))
|
||||
return false;
|
||||
if (ref_count.dec () != 1)
|
||||
return false;
|
||||
|
||||
ref_count.finish (); /* Do this before user_data */
|
||||
user_data.finish ();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool set_user_data (hb_user_data_key_t *key,
|
||||
void * data,
|
||||
hb_destroy_func_t destroy_func,
|
||||
hb_bool_t replace) {
|
||||
if (unlikely (!this || this->is_inert ()))
|
||||
return false;
|
||||
|
||||
return user_data.set (key, data, destroy_func, replace);
|
||||
}
|
||||
|
||||
inline void *get_user_data (hb_user_data_key_t *key) {
|
||||
if (unlikely (!this || this->is_inert ()))
|
||||
return NULL;
|
||||
|
||||
return user_data.get (key);
|
||||
}
|
||||
|
||||
inline void trace (const char *function) const {
|
||||
if (unlikely (!this)) return;
|
||||
/* TODO We cannot use DEBUG_MSG_FUNC here since that one currently only
|
||||
* prints the class name and throws away the template info. */
|
||||
DEBUG_MSG (OBJECT, (void *) this,
|
||||
"%s refcount=%d",
|
||||
function,
|
||||
this ? ref_count.ref_count : 0);
|
||||
}
|
||||
|
||||
private:
|
||||
ASSERT_POD ();
|
||||
};
|
||||
|
@ -179,32 +114,56 @@ struct hb_object_header_t
|
|||
template <typename Type>
|
||||
static inline void hb_object_trace (const Type *obj, const char *function)
|
||||
{
|
||||
obj->header.trace (function);
|
||||
DEBUG_MSG (OBJECT, (void *) obj,
|
||||
"%s refcount=%d",
|
||||
function,
|
||||
obj ? obj->header.ref_count.ref_count : 0);
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
static inline Type *hb_object_create (void)
|
||||
{
|
||||
Type *obj = (Type *) hb_object_header_t::create (sizeof (Type));
|
||||
Type *obj = (Type *) calloc (1, sizeof (Type));
|
||||
|
||||
if (unlikely (!obj))
|
||||
return obj;
|
||||
|
||||
hb_object_init (obj);
|
||||
hb_object_trace (obj, HB_FUNC);
|
||||
return obj;
|
||||
}
|
||||
template <typename Type>
|
||||
static inline void hb_object_init (Type *obj)
|
||||
{
|
||||
obj->header.ref_count.init (1);
|
||||
obj->header.user_data.init ();
|
||||
}
|
||||
template <typename Type>
|
||||
static inline bool hb_object_is_inert (const Type *obj)
|
||||
{
|
||||
return unlikely (obj->header.is_inert ());
|
||||
return unlikely (obj->header.ref_count.is_invalid ());
|
||||
}
|
||||
template <typename Type>
|
||||
static inline Type *hb_object_reference (Type *obj)
|
||||
{
|
||||
hb_object_trace (obj, HB_FUNC);
|
||||
obj->header.reference ();
|
||||
if (unlikely (!obj || hb_object_is_inert (obj)))
|
||||
return obj;
|
||||
obj->header.ref_count.inc ();
|
||||
return obj;
|
||||
}
|
||||
template <typename Type>
|
||||
static inline bool hb_object_destroy (Type *obj)
|
||||
{
|
||||
hb_object_trace (obj, HB_FUNC);
|
||||
return obj->header.destroy ();
|
||||
if (unlikely (!obj || hb_object_is_inert (obj)))
|
||||
return false;
|
||||
if (obj->header.ref_count.dec () != 1)
|
||||
return false;
|
||||
|
||||
obj->header.ref_count.finish (); /* Do this before user_data */
|
||||
obj->header.user_data.finish ();
|
||||
return true;
|
||||
}
|
||||
template <typename Type>
|
||||
static inline bool hb_object_set_user_data (Type *obj,
|
||||
|
@ -213,14 +172,18 @@ static inline bool hb_object_set_user_data (Type *obj,
|
|||
hb_destroy_func_t destroy,
|
||||
hb_bool_t replace)
|
||||
{
|
||||
return obj->header.set_user_data (key, data, destroy, replace);
|
||||
if (unlikely (!obj || hb_object_is_inert (obj)))
|
||||
return false;
|
||||
return obj->header.user_data.set (key, data, destroy, replace);
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
static inline void *hb_object_get_user_data (Type *obj,
|
||||
hb_user_data_key_t *key)
|
||||
{
|
||||
return obj->header.get_user_data (key);
|
||||
if (unlikely (!obj || hb_object_is_inert (obj)))
|
||||
return NULL;
|
||||
return obj->header.user_data.get (key);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -197,6 +197,8 @@ struct TTCHeader
|
|||
|
||||
struct OpenTypeFontFile
|
||||
{
|
||||
static const hb_tag_t tableTag = HB_TAG ('_','_','_','_'); /* Sanitizer needs this. */
|
||||
|
||||
static const hb_tag_t CFFTag = HB_TAG ('O','T','T','O'); /* OpenType with Postscript outlines */
|
||||
static const hb_tag_t TrueTypeTag = HB_TAG ( 0 , 1 , 0 , 0 ); /* OpenType with TrueType outlines */
|
||||
static const hb_tag_t TTCTag = HB_TAG ('t','t','c','f'); /* TrueType Collection */
|
||||
|
|
|
@ -194,10 +194,11 @@ struct hb_sanitize_context_t
|
|||
{
|
||||
this->start = hb_blob_get_data (this->blob, NULL);
|
||||
this->end = this->start + hb_blob_get_length (this->blob);
|
||||
assert (this->start <= this->end); /* Must not overflow. */
|
||||
this->edit_count = 0;
|
||||
this->debug_depth = 0;
|
||||
|
||||
DEBUG_MSG_LEVEL (SANITIZE, this->blob, 0, +1,
|
||||
DEBUG_MSG_LEVEL (SANITIZE, start, 0, +1,
|
||||
"start [%p..%p] (%lu bytes)",
|
||||
this->start, this->end,
|
||||
(unsigned long) (this->end - this->start));
|
||||
|
@ -205,7 +206,7 @@ struct hb_sanitize_context_t
|
|||
|
||||
inline void end_processing (void)
|
||||
{
|
||||
DEBUG_MSG_LEVEL (SANITIZE, this->blob, 0, -1,
|
||||
DEBUG_MSG_LEVEL (SANITIZE, this->start, 0, -1,
|
||||
"end [%p..%p] %u edit requests",
|
||||
this->start, this->end, this->edit_count);
|
||||
|
||||
|
@ -217,28 +218,31 @@ struct hb_sanitize_context_t
|
|||
inline bool check_range (const void *base, unsigned int len) const
|
||||
{
|
||||
const char *p = (const char *) base;
|
||||
bool ok = this->start <= p && p <= this->end && (unsigned int) (this->end - p) >= len;
|
||||
|
||||
hb_auto_trace_t<HB_DEBUG_SANITIZE, bool> trace
|
||||
(&this->debug_depth, "SANITIZE", this->blob, NULL,
|
||||
"check_range [%p..%p] (%d bytes) in [%p..%p]",
|
||||
DEBUG_MSG_LEVEL (SANITIZE, p, this->debug_depth+1, 0,
|
||||
"check_range [%p..%p] (%d bytes) in [%p..%p] -> %s",
|
||||
p, p + len, len,
|
||||
this->start, this->end);
|
||||
this->start, this->end,
|
||||
ok ? "OK" : "OUT-OF-RANGE");
|
||||
|
||||
return TRACE_RETURN (likely (this->start <= p && p <= this->end && (unsigned int) (this->end - p) >= len));
|
||||
return likely (ok);
|
||||
}
|
||||
|
||||
inline bool check_array (const void *base, unsigned int record_size, unsigned int len) const
|
||||
{
|
||||
const char *p = (const char *) base;
|
||||
bool overflows = _hb_unsigned_int_mul_overflows (len, record_size);
|
||||
unsigned int array_size = record_size * len;
|
||||
bool ok = !overflows && this->check_range (base, array_size);
|
||||
|
||||
hb_auto_trace_t<HB_DEBUG_SANITIZE, bool> trace
|
||||
(&this->debug_depth, "SANITIZE", this->blob, NULL,
|
||||
"check_array [%p..%p] (%d*%d=%ld bytes) in [%p..%p]",
|
||||
p, p + (record_size * len), record_size, len, (unsigned long) record_size * len,
|
||||
this->start, this->end);
|
||||
DEBUG_MSG_LEVEL (SANITIZE, p, this->debug_depth+1, 0,
|
||||
"check_array [%p..%p] (%d*%d=%d bytes) in [%p..%p] -> %s",
|
||||
p, p + (record_size * len), record_size, len, (unsigned int) array_size,
|
||||
this->start, this->end,
|
||||
overflows ? "OVERFLOWS" : ok ? "OK" : "OUT-OF-RANGE");
|
||||
|
||||
return TRACE_RETURN (likely (!overflows && this->check_range (base, record_size * len)));
|
||||
return likely (ok);
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
|
@ -255,15 +259,14 @@ struct hb_sanitize_context_t
|
|||
const char *p = (const char *) base;
|
||||
this->edit_count++;
|
||||
|
||||
hb_auto_trace_t<HB_DEBUG_SANITIZE, bool> trace
|
||||
(&this->debug_depth, "SANITIZE", this->blob, NULL,
|
||||
DEBUG_MSG_LEVEL (SANITIZE, p, this->debug_depth+1, 0,
|
||||
"may_edit(%u) [%p..%p] (%d bytes) in [%p..%p] -> %s",
|
||||
this->edit_count,
|
||||
p, p + len, len,
|
||||
this->start, this->end,
|
||||
this->writable ? "GRANTED" : "DENIED");
|
||||
|
||||
return TRACE_RETURN (this->writable);
|
||||
return this->writable;
|
||||
}
|
||||
|
||||
template <typename Type, typename ValueType>
|
||||
|
@ -297,7 +300,7 @@ struct Sanitizer
|
|||
c->init (blob);
|
||||
|
||||
retry:
|
||||
DEBUG_MSG_FUNC (SANITIZE, blob, "start");
|
||||
DEBUG_MSG_FUNC (SANITIZE, c->start, "start");
|
||||
|
||||
c->start_processing ();
|
||||
|
||||
|
@ -311,13 +314,13 @@ struct Sanitizer
|
|||
sane = t->sanitize (c);
|
||||
if (sane) {
|
||||
if (c->edit_count) {
|
||||
DEBUG_MSG_FUNC (SANITIZE, blob, "passed first round with %d edits; going for second round", c->edit_count);
|
||||
DEBUG_MSG_FUNC (SANITIZE, c->start, "passed first round with %d edits; going for second round", c->edit_count);
|
||||
|
||||
/* sanitize again to ensure no toe-stepping */
|
||||
c->edit_count = 0;
|
||||
sane = t->sanitize (c);
|
||||
if (c->edit_count) {
|
||||
DEBUG_MSG_FUNC (SANITIZE, blob, "requested %d edits in second round; FAILLING", c->edit_count);
|
||||
DEBUG_MSG_FUNC (SANITIZE, c->start, "requested %d edits in second round; FAILLING", c->edit_count);
|
||||
sane = false;
|
||||
}
|
||||
}
|
||||
|
@ -330,7 +333,7 @@ struct Sanitizer
|
|||
if (c->start) {
|
||||
c->writable = true;
|
||||
/* ok, we made it writable by relocating. try again */
|
||||
DEBUG_MSG_FUNC (SANITIZE, blob, "retry");
|
||||
DEBUG_MSG_FUNC (SANITIZE, c->start, "retry");
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
|
@ -338,7 +341,7 @@ struct Sanitizer
|
|||
|
||||
c->end_processing ();
|
||||
|
||||
DEBUG_MSG_FUNC (SANITIZE, blob, sane ? "PASSED" : "FAILED");
|
||||
DEBUG_MSG_FUNC (SANITIZE, c->start, sane ? "PASSED" : "FAILED");
|
||||
if (sane)
|
||||
return blob;
|
||||
else {
|
||||
|
@ -533,32 +536,77 @@ template <typename Type>
|
|||
struct BEInt<Type, 2>
|
||||
{
|
||||
public:
|
||||
inline void set (Type i) { hb_be_uint16_put (v,i); }
|
||||
inline operator Type (void) const { return hb_be_uint16_get (v); }
|
||||
inline bool operator == (const BEInt<Type, 2>& o) const { return hb_be_uint16_eq (v, o.v); }
|
||||
inline void set (Type V)
|
||||
{
|
||||
v[0] = (V >> 8) & 0xFF;
|
||||
v[1] = (V ) & 0xFF;
|
||||
}
|
||||
inline operator Type (void) const
|
||||
{
|
||||
return (v[0] << 8)
|
||||
+ (v[1] );
|
||||
}
|
||||
inline bool operator == (const BEInt<Type, 2>& o) const
|
||||
{
|
||||
return v[0] == o.v[0]
|
||||
&& v[1] == o.v[1];
|
||||
}
|
||||
inline bool operator != (const BEInt<Type, 2>& o) const { return !(*this == o); }
|
||||
private: uint8_t v[2];
|
||||
};
|
||||
template <typename Type>
|
||||
struct BEInt<Type, 4>
|
||||
{
|
||||
public:
|
||||
inline void set (Type i) { hb_be_uint32_put (v,i); }
|
||||
inline operator Type (void) const { return hb_be_uint32_get (v); }
|
||||
inline bool operator == (const BEInt<Type, 4>& o) const { return hb_be_uint32_eq (v, o.v); }
|
||||
inline bool operator != (const BEInt<Type, 4>& o) const { return !(*this == o); }
|
||||
private: uint8_t v[4];
|
||||
};
|
||||
template <typename Type>
|
||||
struct BEInt<Type, 3>
|
||||
{
|
||||
public:
|
||||
inline void set (Type i) { hb_be_uint24_put (v,i); }
|
||||
inline operator Type (void) const { return hb_be_uint24_get (v); }
|
||||
inline bool operator == (const BEInt<Type, 3>& o) const { return hb_be_uint24_eq (v, o.v); }
|
||||
inline void set (Type V)
|
||||
{
|
||||
v[0] = (V >> 16) & 0xFF;
|
||||
v[1] = (V >> 8) & 0xFF;
|
||||
v[2] = (V ) & 0xFF;
|
||||
}
|
||||
inline operator Type (void) const
|
||||
{
|
||||
return (v[0] << 16)
|
||||
+ (v[1] << 8)
|
||||
+ (v[2] );
|
||||
}
|
||||
inline bool operator == (const BEInt<Type, 3>& o) const
|
||||
{
|
||||
return v[0] == o.v[0]
|
||||
&& v[1] == o.v[1]
|
||||
&& v[2] == o.v[2];
|
||||
}
|
||||
inline bool operator != (const BEInt<Type, 3>& o) const { return !(*this == o); }
|
||||
private: uint8_t v[3];
|
||||
};
|
||||
template <typename Type>
|
||||
struct BEInt<Type, 4>
|
||||
{
|
||||
public:
|
||||
inline void set (Type V)
|
||||
{
|
||||
v[0] = (V >> 24) & 0xFF;
|
||||
v[1] = (V >> 16) & 0xFF;
|
||||
v[2] = (V >> 8) & 0xFF;
|
||||
v[3] = (V ) & 0xFF;
|
||||
}
|
||||
inline operator Type (void) const
|
||||
{
|
||||
return (v[0] << 24)
|
||||
+ (v[1] << 16)
|
||||
+ (v[2] << 8)
|
||||
+ (v[3] );
|
||||
}
|
||||
inline bool operator == (const BEInt<Type, 4>& o) const
|
||||
{
|
||||
return v[0] == o.v[0]
|
||||
&& v[1] == o.v[1]
|
||||
&& v[2] == o.v[2]
|
||||
&& v[3] == o.v[3];
|
||||
}
|
||||
inline bool operator != (const BEInt<Type, 4>& o) const { return !(*this == o); }
|
||||
private: uint8_t v[4];
|
||||
};
|
||||
|
||||
/* Integer types in big-endian order and no alignment requirement */
|
||||
template <typename Type, unsigned int Size>
|
||||
|
|
|
@ -35,17 +35,128 @@
|
|||
#include "hb-ot-hmtx-table.hh"
|
||||
|
||||
|
||||
struct hb_ot_face_metrics_accelerator_t
|
||||
{
|
||||
unsigned int num_metrics;
|
||||
unsigned int num_advances;
|
||||
unsigned int default_advance;
|
||||
const OT::_mtx *table;
|
||||
hb_blob_t *blob;
|
||||
|
||||
inline void init (hb_face_t *face,
|
||||
hb_tag_t _hea_tag, hb_tag_t _mtx_tag,
|
||||
unsigned int default_advance)
|
||||
{
|
||||
this->default_advance = default_advance;
|
||||
this->num_metrics = face->get_num_glyphs ();
|
||||
|
||||
hb_blob_t *_hea_blob = OT::Sanitizer<OT::_hea>::sanitize (face->reference_table (_hea_tag));
|
||||
const OT::_hea *_hea = OT::Sanitizer<OT::_hea>::lock_instance (_hea_blob);
|
||||
this->num_advances = _hea->numberOfLongMetrics;
|
||||
hb_blob_destroy (_hea_blob);
|
||||
|
||||
this->blob = OT::Sanitizer<OT::_mtx>::sanitize (face->reference_table (_mtx_tag));
|
||||
if (unlikely (!this->num_advances ||
|
||||
2 * (this->num_advances + this->num_metrics) < hb_blob_get_length (this->blob)))
|
||||
{
|
||||
this->num_metrics = this->num_advances = 0;
|
||||
hb_blob_destroy (this->blob);
|
||||
this->blob = hb_blob_get_empty ();
|
||||
}
|
||||
this->table = OT::Sanitizer<OT::_mtx>::lock_instance (this->blob);
|
||||
}
|
||||
|
||||
inline void fini (void)
|
||||
{
|
||||
hb_blob_destroy (this->blob);
|
||||
}
|
||||
|
||||
inline unsigned int get_advance (hb_codepoint_t glyph) const
|
||||
{
|
||||
if (unlikely (glyph >= this->num_metrics))
|
||||
{
|
||||
/* If this->num_metrics is zero, it means we don't have the metrics table
|
||||
* for this direction: return one EM. Otherwise, it means that the glyph
|
||||
* index is out of bound: return zero. */
|
||||
if (this->num_metrics)
|
||||
return 0;
|
||||
else
|
||||
return this->default_advance;
|
||||
}
|
||||
|
||||
if (glyph >= this->num_advances)
|
||||
glyph = this->num_advances - 1;
|
||||
|
||||
return this->table->longMetric[glyph].advance;
|
||||
}
|
||||
};
|
||||
|
||||
struct hb_ot_face_cmap_accelerator_t
|
||||
{
|
||||
const OT::CmapSubtable *table;
|
||||
const OT::CmapSubtable *uvs_table;
|
||||
hb_blob_t *blob;
|
||||
|
||||
inline void init (hb_face_t *face)
|
||||
{
|
||||
this->blob = OT::Sanitizer<OT::cmap>::sanitize (face->reference_table (HB_OT_TAG_cmap));
|
||||
const OT::cmap *cmap = OT::Sanitizer<OT::cmap>::lock_instance (this->blob);
|
||||
const OT::CmapSubtable *subtable = NULL;
|
||||
const OT::CmapSubtable *subtable_uvs = NULL;
|
||||
|
||||
/* 32-bit subtables. */
|
||||
if (!subtable) subtable = cmap->find_subtable (3, 10);
|
||||
if (!subtable) subtable = cmap->find_subtable (0, 6);
|
||||
if (!subtable) subtable = cmap->find_subtable (0, 4);
|
||||
/* 16-bit subtables. */
|
||||
if (!subtable) subtable = cmap->find_subtable (3, 1);
|
||||
if (!subtable) subtable = cmap->find_subtable (0, 3);
|
||||
if (!subtable) subtable = cmap->find_subtable (0, 2);
|
||||
if (!subtable) subtable = cmap->find_subtable (0, 1);
|
||||
if (!subtable) subtable = cmap->find_subtable (0, 0);
|
||||
/* Meh. */
|
||||
if (!subtable) subtable = &OT::Null(OT::CmapSubtable);
|
||||
|
||||
/* UVS subtable. */
|
||||
if (!subtable_uvs) subtable_uvs = cmap->find_subtable (0, 5);
|
||||
/* Meh. */
|
||||
if (!subtable_uvs) subtable_uvs = &OT::Null(OT::CmapSubtable);
|
||||
|
||||
this->table = subtable;
|
||||
this->uvs_table = subtable_uvs;
|
||||
}
|
||||
|
||||
inline void fini (void)
|
||||
{
|
||||
hb_blob_destroy (this->blob);
|
||||
}
|
||||
|
||||
inline bool get_glyph (hb_codepoint_t unicode,
|
||||
hb_codepoint_t variation_selector,
|
||||
hb_codepoint_t *glyph) const
|
||||
{
|
||||
if (unlikely (variation_selector))
|
||||
{
|
||||
switch (this->uvs_table->get_glyph_variant (unicode,
|
||||
variation_selector,
|
||||
glyph))
|
||||
{
|
||||
case OT::GLYPH_VARIANT_NOT_FOUND: return false;
|
||||
case OT::GLYPH_VARIANT_FOUND: return true;
|
||||
case OT::GLYPH_VARIANT_USE_DEFAULT: break;
|
||||
}
|
||||
}
|
||||
|
||||
return this->table->get_glyph (unicode, glyph);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct hb_ot_font_t
|
||||
{
|
||||
unsigned int num_glyphs;
|
||||
unsigned int num_hmetrics;
|
||||
const OT::hmtx *hmtx;
|
||||
hb_blob_t *hmtx_blob;
|
||||
|
||||
const OT::CmapSubtable *cmap;
|
||||
const OT::CmapSubtable *cmap_uvs;
|
||||
hb_blob_t *cmap_blob;
|
||||
hb_ot_face_cmap_accelerator_t cmap;
|
||||
hb_ot_face_metrics_accelerator_t h_metrics;
|
||||
hb_ot_face_metrics_accelerator_t v_metrics;
|
||||
};
|
||||
|
||||
|
||||
|
@ -53,50 +164,16 @@ static hb_ot_font_t *
|
|||
_hb_ot_font_create (hb_font_t *font)
|
||||
{
|
||||
hb_ot_font_t *ot_font = (hb_ot_font_t *) calloc (1, sizeof (hb_ot_font_t));
|
||||
hb_face_t *face = font->face;
|
||||
|
||||
if (unlikely (!ot_font))
|
||||
return NULL;
|
||||
|
||||
ot_font->num_glyphs = font->face->get_num_glyphs ();
|
||||
unsigned int upem = face->get_upem ();
|
||||
|
||||
{
|
||||
hb_blob_t *hhea_blob = OT::Sanitizer<OT::hhea>::sanitize (font->face->reference_table (HB_OT_TAG_hhea));
|
||||
const OT::hhea *hhea = OT::Sanitizer<OT::hhea>::lock_instance (hhea_blob);
|
||||
ot_font->num_hmetrics = hhea->numberOfHMetrics;
|
||||
hb_blob_destroy (hhea_blob);
|
||||
}
|
||||
ot_font->hmtx_blob = OT::Sanitizer<OT::hmtx>::sanitize (font->face->reference_table (HB_OT_TAG_hmtx));
|
||||
if (unlikely (!ot_font->num_hmetrics ||
|
||||
2 * (ot_font->num_hmetrics + ot_font->num_glyphs) < hb_blob_get_length (ot_font->hmtx_blob)))
|
||||
{
|
||||
hb_blob_destroy (ot_font->hmtx_blob);
|
||||
free (ot_font);
|
||||
return NULL;
|
||||
}
|
||||
ot_font->hmtx = OT::Sanitizer<OT::hmtx>::lock_instance (ot_font->hmtx_blob);
|
||||
|
||||
ot_font->cmap_blob = OT::Sanitizer<OT::cmap>::sanitize (font->face->reference_table (HB_OT_TAG_cmap));
|
||||
const OT::cmap *cmap = OT::Sanitizer<OT::cmap>::lock_instance (ot_font->cmap_blob);
|
||||
const OT::CmapSubtable *subtable = NULL;
|
||||
const OT::CmapSubtable *subtable_uvs = NULL;
|
||||
|
||||
/* 32-bit subtables. */
|
||||
if (!subtable) subtable = cmap->find_subtable (0, 6);
|
||||
if (!subtable) subtable = cmap->find_subtable (0, 4);
|
||||
if (!subtable) subtable = cmap->find_subtable (3, 10);
|
||||
/* 16-bit subtables. */
|
||||
if (!subtable) subtable = cmap->find_subtable (0, 3);
|
||||
if (!subtable) subtable = cmap->find_subtable (3, 1);
|
||||
/* Meh. */
|
||||
if (!subtable) subtable = &OT::Null(OT::CmapSubtable);
|
||||
|
||||
/* UVS subtable. */
|
||||
if (!subtable_uvs) subtable_uvs = cmap->find_subtable (0, 5);
|
||||
/* Meh. */
|
||||
if (!subtable_uvs) subtable_uvs = &OT::Null(OT::CmapSubtable);
|
||||
|
||||
ot_font->cmap = subtable;
|
||||
ot_font->cmap_uvs = subtable_uvs;
|
||||
ot_font->cmap.init (face);
|
||||
ot_font->h_metrics.init (face, HB_OT_TAG_hhea, HB_OT_TAG_hmtx, upem>>1);
|
||||
ot_font->v_metrics.init (face, HB_OT_TAG_vhea, HB_OT_TAG_vmtx, upem); /* TODO Can we do this lazily? */
|
||||
|
||||
return ot_font;
|
||||
}
|
||||
|
@ -104,8 +181,9 @@ _hb_ot_font_create (hb_font_t *font)
|
|||
static void
|
||||
_hb_ot_font_destroy (hb_ot_font_t *ot_font)
|
||||
{
|
||||
hb_blob_destroy (ot_font->cmap_blob);
|
||||
hb_blob_destroy (ot_font->hmtx_blob);
|
||||
ot_font->cmap.fini ();
|
||||
ot_font->h_metrics.fini ();
|
||||
ot_font->v_metrics.fini ();
|
||||
|
||||
free (ot_font);
|
||||
}
|
||||
|
@ -121,20 +199,7 @@ hb_ot_get_glyph (hb_font_t *font HB_UNUSED,
|
|||
|
||||
{
|
||||
const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
|
||||
|
||||
if (unlikely (variation_selector))
|
||||
{
|
||||
switch (ot_font->cmap_uvs->get_glyph_variant (unicode,
|
||||
variation_selector,
|
||||
glyph))
|
||||
{
|
||||
case OT::GLYPH_VARIANT_NOT_FOUND: return false;
|
||||
case OT::GLYPH_VARIANT_FOUND: return true;
|
||||
case OT::GLYPH_VARIANT_USE_DEFAULT: break;
|
||||
}
|
||||
}
|
||||
|
||||
return ot_font->cmap->get_glyph (unicode, glyph);
|
||||
return ot_font->cmap.get_glyph (unicode, variation_selector, glyph);
|
||||
}
|
||||
|
||||
static hb_position_t
|
||||
|
@ -144,14 +209,7 @@ hb_ot_get_glyph_h_advance (hb_font_t *font HB_UNUSED,
|
|||
void *user_data HB_UNUSED)
|
||||
{
|
||||
const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
|
||||
|
||||
if (unlikely (glyph >= ot_font->num_glyphs))
|
||||
return 0; /* Maybe better to return notdef's advance instead? */
|
||||
|
||||
if (glyph >= ot_font->num_hmetrics)
|
||||
glyph = ot_font->num_hmetrics - 1;
|
||||
|
||||
return font->em_scale_x (ot_font->hmtx->longHorMetric[glyph].advanceWidth);
|
||||
return font->em_scale_x (ot_font->h_metrics.get_advance (glyph));
|
||||
}
|
||||
|
||||
static hb_position_t
|
||||
|
@ -160,8 +218,8 @@ hb_ot_get_glyph_v_advance (hb_font_t *font HB_UNUSED,
|
|||
hb_codepoint_t glyph,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
/* TODO */
|
||||
return 0;
|
||||
const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
|
||||
return font->em_scale_y (-ot_font->v_metrics.get_advance (glyph));
|
||||
}
|
||||
|
||||
static hb_bool_t
|
||||
|
@ -206,6 +264,7 @@ hb_ot_get_glyph_v_kerning (hb_font_t *font HB_UNUSED,
|
|||
hb_codepoint_t bottom_glyph HB_UNUSED,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
/* OpenType doesn't have vertical-kerning other than GPOS. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -35,14 +35,19 @@ namespace OT {
|
|||
|
||||
/*
|
||||
* hhea -- The Horizontal Header Table
|
||||
* vhea -- The Vertical Header Table
|
||||
*/
|
||||
|
||||
#define HB_OT_TAG_hhea HB_TAG('h','h','e','a')
|
||||
#define HB_OT_TAG_vhea HB_TAG('v','h','e','a')
|
||||
|
||||
|
||||
struct hhea
|
||||
struct _hea
|
||||
{
|
||||
static const hb_tag_t tableTag = HB_OT_TAG_hhea;
|
||||
static const hb_tag_t tableTag = HB_TAG('_','h','e','a');
|
||||
|
||||
static const hb_tag_t hheaTag = HB_OT_TAG_hhea;
|
||||
static const hb_tag_t vheaTag = HB_OT_TAG_vhea;
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c) {
|
||||
TRACE_SANITIZE (this);
|
||||
|
@ -51,45 +56,45 @@ struct hhea
|
|||
|
||||
public:
|
||||
FixedVersion version; /* 0x00010000u for version 1.0. */
|
||||
FWORD ascender; /* Typographic ascent. <a
|
||||
* href="http://developer.apple.com/fonts/TTRefMan/RM06/Chap6hhea.html">
|
||||
* (Distance from baseline of highest
|
||||
* ascender)</a> */
|
||||
FWORD descender; /* Typographic descent. <a
|
||||
* href="http://developer.apple.com/fonts/TTRefMan/RM06/Chap6hhea.html">
|
||||
* (Distance from baseline of lowest
|
||||
* descender)</a> */
|
||||
FWORD lineGap; /* Typographic line gap. Negative
|
||||
* LineGap values are treated as zero
|
||||
* in Windows 3.1, System 6, and
|
||||
* System 7. */
|
||||
UFWORD advanceWidthMax; /* Maximum advance width value in
|
||||
* 'hmtx' table. */
|
||||
FWORD minLeftSideBearing; /* Minimum left sidebearing value in
|
||||
* 'hmtx' table. */
|
||||
FWORD minRightSideBearing; /* Minimum right sidebearing value;
|
||||
FWORD ascender; /* Typographic ascent. */
|
||||
FWORD descender; /* Typographic descent. */
|
||||
FWORD lineGap; /* Typographic line gap. */
|
||||
UFWORD advanceMax; /* Maximum advance width/height value in
|
||||
* metrics table. */
|
||||
FWORD minLeadingBearing; /* Minimum left/top sidebearing value in
|
||||
* metrics table. */
|
||||
FWORD minTrailingBearing; /* Minimum right/bottom sidebearing value;
|
||||
* calculated as Min(aw - lsb -
|
||||
* (xMax - xMin)). */
|
||||
FWORD xMaxExtent; /* Max(lsb + (xMax - xMin)). */
|
||||
* (xMax - xMin)) for horizontal. */
|
||||
FWORD maxExtent; /* horizontal: Max(lsb + (xMax - xMin)),
|
||||
* vertical: minLeadingBearing+(yMax-yMin). */
|
||||
SHORT caretSlopeRise; /* Used to calculate the slope of the
|
||||
* cursor (rise/run); 1 for vertical. */
|
||||
SHORT caretSlopeRun; /* 0 for vertical. */
|
||||
* cursor (rise/run); 1 for vertical caret,
|
||||
* 0 for horizontal.*/
|
||||
SHORT caretSlopeRun; /* 0 for vertical caret, 1 for horizontal. */
|
||||
SHORT caretOffset; /* The amount by which a slanted
|
||||
* highlight on a glyph needs
|
||||
* to be shifted to produce the
|
||||
* best appearance. Set to 0 for
|
||||
* non--slanted fonts */
|
||||
SHORT reserved1; /* set to 0 */
|
||||
SHORT reserved2; /* set to 0 */
|
||||
SHORT reserved3; /* set to 0 */
|
||||
SHORT reserved4; /* set to 0 */
|
||||
* non-slanted fonts. */
|
||||
SHORT reserved1; /* Set to 0. */
|
||||
SHORT reserved2; /* Set to 0. */
|
||||
SHORT reserved3; /* Set to 0. */
|
||||
SHORT reserved4; /* Set to 0. */
|
||||
SHORT metricDataFormat; /* 0 for current format. */
|
||||
USHORT numberOfHMetrics; /* Number of hMetric entries in 'hmtx'
|
||||
* table */
|
||||
USHORT numberOfLongMetrics; /* Number of LongMetric entries in metric
|
||||
* table. */
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (36);
|
||||
};
|
||||
|
||||
struct hhea : _hea {
|
||||
static const hb_tag_t tableTag = HB_OT_TAG_hhea;
|
||||
};
|
||||
struct vhea : _hea {
|
||||
static const hb_tag_t tableTag = HB_OT_TAG_vhea;
|
||||
};
|
||||
|
||||
|
||||
} /* namespace OT */
|
||||
|
||||
|
|
|
@ -35,22 +35,27 @@ namespace OT {
|
|||
|
||||
/*
|
||||
* hmtx -- The Horizontal Metrics Table
|
||||
* vmtx -- The Vertical Metrics Table
|
||||
*/
|
||||
|
||||
#define HB_OT_TAG_hmtx HB_TAG('h','m','t','x')
|
||||
#define HB_OT_TAG_vmtx HB_TAG('v','m','t','x')
|
||||
|
||||
|
||||
struct LongHorMetric
|
||||
struct LongMetric
|
||||
{
|
||||
USHORT advanceWidth;
|
||||
SHORT lsb;
|
||||
USHORT advance; /* Advance width/height. */
|
||||
SHORT lsb; /* Leading (left/top) side bearing. */
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (4);
|
||||
};
|
||||
|
||||
struct hmtx
|
||||
struct _mtx
|
||||
{
|
||||
static const hb_tag_t tableTag = HB_OT_TAG_hmtx;
|
||||
static const hb_tag_t tableTag = HB_TAG('_','m','t','x');
|
||||
|
||||
static const hb_tag_t hmtxTag = HB_OT_TAG_hmtx;
|
||||
static const hb_tag_t vmtxTag = HB_OT_TAG_vmtx;
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c) {
|
||||
TRACE_SANITIZE (this);
|
||||
|
@ -60,7 +65,7 @@ struct hmtx
|
|||
}
|
||||
|
||||
public:
|
||||
LongHorMetric longHorMetric[VAR]; /* Paired advance width and left side
|
||||
LongMetric longMetric[VAR]; /* Paired advance width and leading
|
||||
* bearing values for each glyph. The
|
||||
* value numOfHMetrics comes from
|
||||
* the 'hhea' table. If the font is
|
||||
|
@ -68,23 +73,29 @@ struct hmtx
|
|||
* be in the array, but that entry is
|
||||
* required. The last entry applies to
|
||||
* all subsequent glyphs. */
|
||||
SHORT leftSideBearingX[VAR]; /* Here the advanceWidth is assumed
|
||||
* to be the same as the advanceWidth
|
||||
SHORT leadingBearingX[VAR]; /* Here the advance is assumed
|
||||
* to be the same as the advance
|
||||
* for the last entry above. The
|
||||
* number of entries in this array is
|
||||
* derived from numGlyphs (from 'maxp'
|
||||
* table) minus numberOfHMetrics. This
|
||||
* generally is used with a run of
|
||||
* monospaced glyphs (e.g., Kanji
|
||||
* table) minus numberOfLongMetrics.
|
||||
* This generally is used with a run
|
||||
* of monospaced glyphs (e.g., Kanji
|
||||
* fonts or Courier fonts). Only one
|
||||
* run is allowed and it must be at
|
||||
* the end. This allows a monospaced
|
||||
* font to vary the left side bearing
|
||||
* font to vary the side bearing
|
||||
* values for each glyph. */
|
||||
public:
|
||||
DEFINE_SIZE_ARRAY2 (0, longHorMetric, leftSideBearingX);
|
||||
DEFINE_SIZE_ARRAY2 (0, longMetric, leadingBearingX);
|
||||
};
|
||||
|
||||
struct hmtx : _mtx {
|
||||
static const hb_tag_t tableTag = HB_OT_TAG_hmtx;
|
||||
};
|
||||
struct vmtx : _mtx {
|
||||
static const hb_tag_t tableTag = HB_OT_TAG_vmtx;
|
||||
};
|
||||
|
||||
} /* namespace OT */
|
||||
|
||||
|
|
|
@ -345,8 +345,8 @@ struct AnchorMatrix
|
|||
inline const Anchor& get_anchor (unsigned int row, unsigned int col, unsigned int cols, bool *found) const {
|
||||
*found = false;
|
||||
if (unlikely (row >= rows || col >= cols)) return Null(Anchor);
|
||||
*found = !matrix[row * cols + col].is_null ();
|
||||
return this+matrix[row * cols + col];
|
||||
*found = !matrixZ[row * cols + col].is_null ();
|
||||
return this+matrixZ[row * cols + col];
|
||||
}
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c, unsigned int cols) {
|
||||
|
@ -354,19 +354,19 @@ struct AnchorMatrix
|
|||
if (!c->check_struct (this)) return TRACE_RETURN (false);
|
||||
if (unlikely (rows > 0 && cols >= ((unsigned int) -1) / rows)) return TRACE_RETURN (false);
|
||||
unsigned int count = rows * cols;
|
||||
if (!c->check_array (matrix, matrix[0].static_size, count)) return TRACE_RETURN (false);
|
||||
if (!c->check_array (matrixZ, matrixZ[0].static_size, count)) return TRACE_RETURN (false);
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
if (!matrix[i].sanitize (c, this)) return TRACE_RETURN (false);
|
||||
if (!matrixZ[i].sanitize (c, this)) return TRACE_RETURN (false);
|
||||
return TRACE_RETURN (true);
|
||||
}
|
||||
|
||||
USHORT rows; /* Number of rows */
|
||||
protected:
|
||||
OffsetTo<Anchor>
|
||||
matrix[VAR]; /* Matrix of offsets to Anchor tables--
|
||||
matrixZ[VAR]; /* Matrix of offsets to Anchor tables--
|
||||
* from beginning of AnchorMatrix table */
|
||||
public:
|
||||
DEFINE_SIZE_ARRAY (2, matrix);
|
||||
DEFINE_SIZE_ARRAY (2, matrixZ);
|
||||
};
|
||||
|
||||
|
||||
|
@ -530,7 +530,7 @@ struct SinglePos
|
|||
template <typename context_t>
|
||||
inline typename context_t::return_t dispatch (context_t *c) const
|
||||
{
|
||||
TRACE_DISPATCH (this);
|
||||
TRACE_DISPATCH (this, u.format);
|
||||
switch (u.format) {
|
||||
case 1: return TRACE_RETURN (c->dispatch (u.format1));
|
||||
case 2: return TRACE_RETURN (c->dispatch (u.format2));
|
||||
|
@ -583,7 +583,7 @@ struct PairSet
|
|||
unsigned int len2 = valueFormats[1].get_len ();
|
||||
unsigned int record_size = USHORT::static_size * (1 + len1 + len2);
|
||||
|
||||
const PairValueRecord *record = CastP<PairValueRecord> (array);
|
||||
const PairValueRecord *record = CastP<PairValueRecord> (arrayZ);
|
||||
unsigned int count = len;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
|
@ -602,7 +602,7 @@ struct PairSet
|
|||
unsigned int len2 = valueFormats[1].get_len ();
|
||||
unsigned int record_size = USHORT::static_size * (1 + len1 + len2);
|
||||
|
||||
const PairValueRecord *record = CastP<PairValueRecord> (array);
|
||||
const PairValueRecord *record = CastP<PairValueRecord> (arrayZ);
|
||||
unsigned int count = len;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
|
@ -634,20 +634,20 @@ struct PairSet
|
|||
inline bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) {
|
||||
TRACE_SANITIZE (this);
|
||||
if (!(c->check_struct (this)
|
||||
&& c->check_array (array, USHORT::static_size * closure->stride, len))) return TRACE_RETURN (false);
|
||||
&& c->check_array (arrayZ, USHORT::static_size * closure->stride, len))) return TRACE_RETURN (false);
|
||||
|
||||
unsigned int count = len;
|
||||
PairValueRecord *record = CastP<PairValueRecord> (array);
|
||||
PairValueRecord *record = CastP<PairValueRecord> (arrayZ);
|
||||
return TRACE_RETURN (closure->valueFormats[0].sanitize_values_stride_unsafe (c, closure->base, &record->values[0], count, closure->stride)
|
||||
&& closure->valueFormats[1].sanitize_values_stride_unsafe (c, closure->base, &record->values[closure->len1], count, closure->stride));
|
||||
}
|
||||
|
||||
protected:
|
||||
USHORT len; /* Number of PairValueRecords */
|
||||
USHORT array[VAR]; /* Array of PairValueRecords--ordered
|
||||
USHORT arrayZ[VAR]; /* Array of PairValueRecords--ordered
|
||||
* by GlyphID of the second glyph */
|
||||
public:
|
||||
DEFINE_SIZE_ARRAY (2, array);
|
||||
DEFINE_SIZE_ARRAY (2, arrayZ);
|
||||
};
|
||||
|
||||
struct PairPosFormat1
|
||||
|
@ -822,7 +822,7 @@ struct PairPos
|
|||
template <typename context_t>
|
||||
inline typename context_t::return_t dispatch (context_t *c) const
|
||||
{
|
||||
TRACE_DISPATCH (this);
|
||||
TRACE_DISPATCH (this, u.format);
|
||||
switch (u.format) {
|
||||
case 1: return TRACE_RETURN (c->dispatch (u.format1));
|
||||
case 2: return TRACE_RETURN (c->dispatch (u.format2));
|
||||
|
@ -989,7 +989,7 @@ struct CursivePos
|
|||
template <typename context_t>
|
||||
inline typename context_t::return_t dispatch (context_t *c) const
|
||||
{
|
||||
TRACE_DISPATCH (this);
|
||||
TRACE_DISPATCH (this, u.format);
|
||||
switch (u.format) {
|
||||
case 1: return TRACE_RETURN (c->dispatch (u.format1));
|
||||
default:return TRACE_RETURN (c->default_return_value ());
|
||||
|
@ -1088,7 +1088,7 @@ struct MarkBasePos
|
|||
template <typename context_t>
|
||||
inline typename context_t::return_t dispatch (context_t *c) const
|
||||
{
|
||||
TRACE_DISPATCH (this);
|
||||
TRACE_DISPATCH (this, u.format);
|
||||
switch (u.format) {
|
||||
case 1: return TRACE_RETURN (c->dispatch (u.format1));
|
||||
default:return TRACE_RETURN (c->default_return_value ());
|
||||
|
@ -1209,7 +1209,7 @@ struct MarkLigPos
|
|||
template <typename context_t>
|
||||
inline typename context_t::return_t dispatch (context_t *c) const
|
||||
{
|
||||
TRACE_DISPATCH (this);
|
||||
TRACE_DISPATCH (this, u.format);
|
||||
switch (u.format) {
|
||||
case 1: return TRACE_RETURN (c->dispatch (u.format1));
|
||||
default:return TRACE_RETURN (c->default_return_value ());
|
||||
|
@ -1328,7 +1328,7 @@ struct MarkMarkPos
|
|||
template <typename context_t>
|
||||
inline typename context_t::return_t dispatch (context_t *c) const
|
||||
{
|
||||
TRACE_DISPATCH (this);
|
||||
TRACE_DISPATCH (this, u.format);
|
||||
switch (u.format) {
|
||||
case 1: return TRACE_RETURN (c->dispatch (u.format1));
|
||||
default:return TRACE_RETURN (c->default_return_value ());
|
||||
|
@ -1387,7 +1387,7 @@ struct PosLookupSubTable
|
|||
template <typename context_t>
|
||||
inline typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const
|
||||
{
|
||||
TRACE_DISPATCH (this);
|
||||
TRACE_DISPATCH (this, lookup_type);
|
||||
switch (lookup_type) {
|
||||
case Single: return TRACE_RETURN (u.single.dispatch (c));
|
||||
case Pair: return TRACE_RETURN (u.pair.dispatch (c));
|
||||
|
@ -1488,8 +1488,8 @@ struct PosLookup : Lookup
|
|||
template <typename context_t>
|
||||
inline typename context_t::return_t dispatch (context_t *c) const
|
||||
{
|
||||
TRACE_DISPATCH (this);
|
||||
unsigned int lookup_type = get_type ();
|
||||
TRACE_DISPATCH (this, lookup_type);
|
||||
unsigned int count = get_subtable_count ();
|
||||
for (unsigned int i = 0; i < count; i++) {
|
||||
typename context_t::return_t r = get_subtable (i).dispatch (c, lookup_type);
|
||||
|
|
|
@ -200,7 +200,7 @@ struct SingleSubst
|
|||
TRACE_SERIALIZE (this);
|
||||
if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false);
|
||||
unsigned int format = 2;
|
||||
int delta;
|
||||
int delta = 0;
|
||||
if (num_glyphs) {
|
||||
format = 1;
|
||||
/* TODO(serialize) check for wrap-around */
|
||||
|
@ -222,7 +222,7 @@ struct SingleSubst
|
|||
template <typename context_t>
|
||||
inline typename context_t::return_t dispatch (context_t *c) const
|
||||
{
|
||||
TRACE_DISPATCH (this);
|
||||
TRACE_DISPATCH (this, u.format);
|
||||
switch (u.format) {
|
||||
case 1: return TRACE_RETURN (c->dispatch (u.format1));
|
||||
case 2: return TRACE_RETURN (c->dispatch (u.format2));
|
||||
|
@ -422,7 +422,7 @@ struct MultipleSubst
|
|||
template <typename context_t>
|
||||
inline typename context_t::return_t dispatch (context_t *c) const
|
||||
{
|
||||
TRACE_DISPATCH (this);
|
||||
TRACE_DISPATCH (this, u.format);
|
||||
switch (u.format) {
|
||||
case 1: return TRACE_RETURN (c->dispatch (u.format1));
|
||||
default:return TRACE_RETURN (c->default_return_value ());
|
||||
|
@ -573,7 +573,7 @@ struct AlternateSubst
|
|||
template <typename context_t>
|
||||
inline typename context_t::return_t dispatch (context_t *c) const
|
||||
{
|
||||
TRACE_DISPATCH (this);
|
||||
TRACE_DISPATCH (this, u.format);
|
||||
switch (u.format) {
|
||||
case 1: return TRACE_RETURN (c->dispatch (u.format1));
|
||||
default:return TRACE_RETURN (c->default_return_value ());
|
||||
|
@ -889,7 +889,7 @@ struct LigatureSubst
|
|||
template <typename context_t>
|
||||
inline typename context_t::return_t dispatch (context_t *c) const
|
||||
{
|
||||
TRACE_DISPATCH (this);
|
||||
TRACE_DISPATCH (this, u.format);
|
||||
switch (u.format) {
|
||||
case 1: return TRACE_RETURN (c->dispatch (u.format1));
|
||||
default:return TRACE_RETURN (c->default_return_value ());
|
||||
|
@ -1053,7 +1053,7 @@ struct ReverseChainSingleSubst
|
|||
template <typename context_t>
|
||||
inline typename context_t::return_t dispatch (context_t *c) const
|
||||
{
|
||||
TRACE_DISPATCH (this);
|
||||
TRACE_DISPATCH (this, u.format);
|
||||
switch (u.format) {
|
||||
case 1: return TRACE_RETURN (c->dispatch (u.format1));
|
||||
default:return TRACE_RETURN (c->default_return_value ());
|
||||
|
@ -1100,7 +1100,7 @@ struct SubstLookupSubTable
|
|||
template <typename context_t>
|
||||
inline typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const
|
||||
{
|
||||
TRACE_DISPATCH (this);
|
||||
TRACE_DISPATCH (this, lookup_type);
|
||||
switch (lookup_type) {
|
||||
case Single: return TRACE_RETURN (u.single.dispatch (c));
|
||||
case Multiple: return TRACE_RETURN (u.multiple.dispatch (c));
|
||||
|
@ -1275,8 +1275,8 @@ struct SubstLookup : Lookup
|
|||
template <typename context_t>
|
||||
inline typename context_t::return_t dispatch (context_t *c) const
|
||||
{
|
||||
TRACE_DISPATCH (this);
|
||||
unsigned int lookup_type = get_type ();
|
||||
TRACE_DISPATCH (this, lookup_type);
|
||||
unsigned int count = get_subtable_count ();
|
||||
for (unsigned int i = 0; i < count; i++) {
|
||||
typename context_t::return_t r = get_subtable (i).dispatch (c, lookup_type);
|
||||
|
|
|
@ -38,10 +38,10 @@ namespace OT {
|
|||
|
||||
|
||||
|
||||
#define TRACE_DISPATCH(this) \
|
||||
#define TRACE_DISPATCH(this, format) \
|
||||
hb_auto_trace_t<context_t::max_debug_depth, typename context_t::return_t> trace \
|
||||
(&c->debug_depth, c->get_name (), this, HB_FUNC, \
|
||||
"");
|
||||
"format %d", (int) format);
|
||||
|
||||
#ifndef HB_DEBUG_CLOSURE
|
||||
#define HB_DEBUG_CLOSURE (HB_DEBUG+0)
|
||||
|
@ -168,6 +168,10 @@ struct hb_collect_glyphs_context_t
|
|||
if (output == hb_set_get_empty ())
|
||||
return HB_VOID;
|
||||
|
||||
/* Return if new lookup was recursed to before. */
|
||||
if (recursed_lookups.has (lookup_index))
|
||||
return HB_VOID;
|
||||
|
||||
hb_set_t *old_before = before;
|
||||
hb_set_t *old_input = input;
|
||||
hb_set_t *old_after = after;
|
||||
|
@ -181,6 +185,8 @@ struct hb_collect_glyphs_context_t
|
|||
input = old_input;
|
||||
after = old_after;
|
||||
|
||||
recursed_lookups.add (lookup_index);
|
||||
|
||||
return HB_VOID;
|
||||
}
|
||||
|
||||
|
@ -190,6 +196,7 @@ struct hb_collect_glyphs_context_t
|
|||
hb_set_t *after;
|
||||
hb_set_t *output;
|
||||
recurse_func_t recurse_func;
|
||||
hb_set_t recursed_lookups;
|
||||
unsigned int nesting_level_left;
|
||||
unsigned int debug_depth;
|
||||
|
||||
|
@ -205,18 +212,30 @@ struct hb_collect_glyphs_context_t
|
|||
after (glyphs_after ? glyphs_after : hb_set_get_empty ()),
|
||||
output (glyphs_output ? glyphs_output : hb_set_get_empty ()),
|
||||
recurse_func (NULL),
|
||||
recursed_lookups (),
|
||||
nesting_level_left (nesting_level_left_),
|
||||
debug_depth (0) {}
|
||||
debug_depth (0)
|
||||
{
|
||||
recursed_lookups.init ();
|
||||
}
|
||||
~hb_collect_glyphs_context_t (void)
|
||||
{
|
||||
recursed_lookups.fini ();
|
||||
}
|
||||
|
||||
void set_recurse_func (recurse_func_t func) { recurse_func = func; }
|
||||
};
|
||||
|
||||
|
||||
|
||||
#ifndef HB_DEBUG_GET_COVERAGE
|
||||
#define HB_DEBUG_GET_COVERAGE (HB_DEBUG+0)
|
||||
#endif
|
||||
|
||||
struct hb_get_coverage_context_t
|
||||
{
|
||||
inline const char *get_name (void) { return "GET_COVERAGE"; }
|
||||
static const unsigned int max_debug_depth = 0;
|
||||
static const unsigned int max_debug_depth = HB_DEBUG_GET_COVERAGE;
|
||||
typedef const Coverage &return_t;
|
||||
template <typename T>
|
||||
inline return_t dispatch (const T &obj) { return obj.get_coverage (); }
|
||||
|
@ -1117,9 +1136,9 @@ struct Rule
|
|||
inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
|
||||
{
|
||||
TRACE_CLOSURE (this);
|
||||
const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0));
|
||||
const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (inputZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0));
|
||||
context_closure_lookup (c,
|
||||
inputCount, input,
|
||||
inputCount, inputZ,
|
||||
lookupCount, lookupRecord,
|
||||
lookup_context);
|
||||
}
|
||||
|
@ -1127,9 +1146,9 @@ struct Rule
|
|||
inline void collect_glyphs (hb_collect_glyphs_context_t *c, ContextCollectGlyphsLookupContext &lookup_context) const
|
||||
{
|
||||
TRACE_COLLECT_GLYPHS (this);
|
||||
const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0));
|
||||
const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (inputZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0));
|
||||
context_collect_glyphs_lookup (c,
|
||||
inputCount, input,
|
||||
inputCount, inputZ,
|
||||
lookupCount, lookupRecord,
|
||||
lookup_context);
|
||||
}
|
||||
|
@ -1137,15 +1156,15 @@ struct Rule
|
|||
inline bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
|
||||
{
|
||||
TRACE_WOULD_APPLY (this);
|
||||
const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0));
|
||||
return TRACE_RETURN (context_would_apply_lookup (c, inputCount, input, lookupCount, lookupRecord, lookup_context));
|
||||
const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (inputZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0));
|
||||
return TRACE_RETURN (context_would_apply_lookup (c, inputCount, inputZ, lookupCount, lookupRecord, lookup_context));
|
||||
}
|
||||
|
||||
inline bool apply (hb_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
|
||||
{
|
||||
TRACE_APPLY (this);
|
||||
const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0));
|
||||
return TRACE_RETURN (context_apply_lookup (c, inputCount, input, lookupCount, lookupRecord, lookup_context));
|
||||
const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (inputZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0));
|
||||
return TRACE_RETURN (context_apply_lookup (c, inputCount, inputZ, lookupCount, lookupRecord, lookup_context));
|
||||
}
|
||||
|
||||
public:
|
||||
|
@ -1153,8 +1172,8 @@ struct Rule
|
|||
TRACE_SANITIZE (this);
|
||||
return inputCount.sanitize (c)
|
||||
&& lookupCount.sanitize (c)
|
||||
&& c->check_range (input,
|
||||
input[0].static_size * inputCount
|
||||
&& c->check_range (inputZ,
|
||||
inputZ[0].static_size * inputCount
|
||||
+ lookupRecordX[0].static_size * lookupCount);
|
||||
}
|
||||
|
||||
|
@ -1163,12 +1182,12 @@ struct Rule
|
|||
* glyph sequence--includes the first
|
||||
* glyph */
|
||||
USHORT lookupCount; /* Number of LookupRecords */
|
||||
USHORT input[VAR]; /* Array of match inputs--start with
|
||||
USHORT inputZ[VAR]; /* Array of match inputs--start with
|
||||
* second glyph */
|
||||
LookupRecord lookupRecordX[VAR]; /* Array of LookupRecords--in
|
||||
* design order */
|
||||
public:
|
||||
DEFINE_SIZE_ARRAY2 (4, input, lookupRecordX);
|
||||
DEFINE_SIZE_ARRAY2 (4, inputZ, lookupRecordX);
|
||||
};
|
||||
|
||||
struct RuleSet
|
||||
|
@ -1413,16 +1432,16 @@ struct ContextFormat3
|
|||
inline void closure (hb_closure_context_t *c) const
|
||||
{
|
||||
TRACE_CLOSURE (this);
|
||||
if (!(this+coverage[0]).intersects (c->glyphs))
|
||||
if (!(this+coverageZ[0]).intersects (c->glyphs))
|
||||
return;
|
||||
|
||||
const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount);
|
||||
const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * glyphCount);
|
||||
struct ContextClosureLookupContext lookup_context = {
|
||||
{intersects_coverage},
|
||||
this
|
||||
};
|
||||
context_closure_lookup (c,
|
||||
glyphCount, (const USHORT *) (coverage + 1),
|
||||
glyphCount, (const USHORT *) (coverageZ + 1),
|
||||
lookupCount, lookupRecord,
|
||||
lookup_context);
|
||||
}
|
||||
|
@ -1430,16 +1449,16 @@ struct ContextFormat3
|
|||
inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
|
||||
{
|
||||
TRACE_COLLECT_GLYPHS (this);
|
||||
(this+coverage[0]).add_coverage (c->input);
|
||||
(this+coverageZ[0]).add_coverage (c->input);
|
||||
|
||||
const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount);
|
||||
const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * glyphCount);
|
||||
struct ContextCollectGlyphsLookupContext lookup_context = {
|
||||
{collect_coverage},
|
||||
this
|
||||
};
|
||||
|
||||
context_collect_glyphs_lookup (c,
|
||||
glyphCount, (const USHORT *) (coverage + 1),
|
||||
glyphCount, (const USHORT *) (coverageZ + 1),
|
||||
lookupCount, lookupRecord,
|
||||
lookup_context);
|
||||
}
|
||||
|
@ -1448,41 +1467,42 @@ struct ContextFormat3
|
|||
{
|
||||
TRACE_WOULD_APPLY (this);
|
||||
|
||||
const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount);
|
||||
const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * glyphCount);
|
||||
struct ContextApplyLookupContext lookup_context = {
|
||||
{match_coverage},
|
||||
this
|
||||
};
|
||||
return TRACE_RETURN (context_would_apply_lookup (c, glyphCount, (const USHORT *) (coverage + 1), lookupCount, lookupRecord, lookup_context));
|
||||
return TRACE_RETURN (context_would_apply_lookup (c, glyphCount, (const USHORT *) (coverageZ + 1), lookupCount, lookupRecord, lookup_context));
|
||||
}
|
||||
|
||||
inline const Coverage &get_coverage (void) const
|
||||
{
|
||||
return this+coverage[0];
|
||||
return this+coverageZ[0];
|
||||
}
|
||||
|
||||
inline bool apply (hb_apply_context_t *c) const
|
||||
{
|
||||
TRACE_APPLY (this);
|
||||
unsigned int index = (this+coverage[0]).get_coverage (c->buffer->cur().codepoint);
|
||||
unsigned int index = (this+coverageZ[0]).get_coverage (c->buffer->cur().codepoint);
|
||||
if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
|
||||
|
||||
const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount);
|
||||
const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * glyphCount);
|
||||
struct ContextApplyLookupContext lookup_context = {
|
||||
{match_coverage},
|
||||
this
|
||||
};
|
||||
return TRACE_RETURN (context_apply_lookup (c, glyphCount, (const USHORT *) (coverage + 1), lookupCount, lookupRecord, lookup_context));
|
||||
return TRACE_RETURN (context_apply_lookup (c, glyphCount, (const USHORT *) (coverageZ + 1), lookupCount, lookupRecord, lookup_context));
|
||||
}
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c) {
|
||||
TRACE_SANITIZE (this);
|
||||
if (!c->check_struct (this)) return TRACE_RETURN (false);
|
||||
unsigned int count = glyphCount;
|
||||
if (!c->check_array (coverage, coverage[0].static_size, count)) return TRACE_RETURN (false);
|
||||
if (!count) return TRACE_RETURN (false); /* We want to access coverageZ[0] freely. */
|
||||
if (!c->check_array (coverageZ, coverageZ[0].static_size, count)) return TRACE_RETURN (false);
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
if (!coverage[i].sanitize (c, this)) return TRACE_RETURN (false);
|
||||
LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * count);
|
||||
if (!coverageZ[i].sanitize (c, this)) return TRACE_RETURN (false);
|
||||
LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * count);
|
||||
return TRACE_RETURN (c->check_array (lookupRecord, lookupRecord[0].static_size, lookupCount));
|
||||
}
|
||||
|
||||
|
@ -1492,12 +1512,12 @@ struct ContextFormat3
|
|||
* sequence */
|
||||
USHORT lookupCount; /* Number of LookupRecords */
|
||||
OffsetTo<Coverage>
|
||||
coverage[VAR]; /* Array of offsets to Coverage
|
||||
coverageZ[VAR]; /* Array of offsets to Coverage
|
||||
* table in glyph sequence order */
|
||||
LookupRecord lookupRecordX[VAR]; /* Array of LookupRecords--in
|
||||
* design order */
|
||||
public:
|
||||
DEFINE_SIZE_ARRAY2 (6, coverage, lookupRecordX);
|
||||
DEFINE_SIZE_ARRAY2 (6, coverageZ, lookupRecordX);
|
||||
};
|
||||
|
||||
struct Context
|
||||
|
@ -1505,7 +1525,7 @@ struct Context
|
|||
template <typename context_t>
|
||||
inline typename context_t::return_t dispatch (context_t *c) const
|
||||
{
|
||||
TRACE_DISPATCH (this);
|
||||
TRACE_DISPATCH (this, u.format);
|
||||
switch (u.format) {
|
||||
case 1: return TRACE_RETURN (c->dispatch (u.format1));
|
||||
case 2: return TRACE_RETURN (c->dispatch (u.format2));
|
||||
|
@ -2090,6 +2110,7 @@ struct ChainContextFormat3
|
|||
if (!backtrack.sanitize (c, this)) return TRACE_RETURN (false);
|
||||
OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
|
||||
if (!input.sanitize (c, this)) return TRACE_RETURN (false);
|
||||
if (!input.len) return TRACE_RETURN (false); /* To be consistent with Context. */
|
||||
OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
|
||||
if (!lookahead.sanitize (c, this)) return TRACE_RETURN (false);
|
||||
ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
|
||||
|
@ -2122,7 +2143,7 @@ struct ChainContext
|
|||
template <typename context_t>
|
||||
inline typename context_t::return_t dispatch (context_t *c) const
|
||||
{
|
||||
TRACE_DISPATCH (this);
|
||||
TRACE_DISPATCH (this, u.format);
|
||||
switch (u.format) {
|
||||
case 1: return TRACE_RETURN (c->dispatch (u.format1));
|
||||
case 2: return TRACE_RETURN (c->dispatch (u.format2));
|
||||
|
|
|
@ -207,7 +207,7 @@ struct arabic_fallback_plan_t
|
|||
|
||||
static const arabic_fallback_plan_t arabic_fallback_plan_nil = {};
|
||||
|
||||
#if (defined(_WIN32) || defined(__CYGWIN__)) && !defined(HB_WITH_WIN1256)
|
||||
#if (defined(_WIN32) || defined(__CYGWIN__)) && !defined(HB_NO_WIN1256)
|
||||
#define HB_WITH_WIN1256
|
||||
#endif
|
||||
|
||||
|
|
|
@ -313,8 +313,11 @@ OT_TABLE_END
|
|||
/*
|
||||
* Include a second time to get the table data...
|
||||
*/
|
||||
#if 0
|
||||
#include "hb-private.hh" /* Make check-includes.sh happy. */
|
||||
#endif
|
||||
#ifdef OT_MEASURE
|
||||
#include __FILE__
|
||||
#include "hb-ot-shape-complex-arabic-win1256.hh"
|
||||
#endif
|
||||
|
||||
#define HB_OT_SHAPE_COMPLEX_ARABIC_WIN1256_HH
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
#include "hb-private.hh"
|
||||
|
||||
|
||||
#line 36 "../../src/hb-ot-shape-complex-indic-machine.hh.tmp"
|
||||
#line 36 "hb-ot-shape-complex-indic-machine.hh.tmp"
|
||||
static const unsigned char _indic_syllable_machine_trans_keys[] = {
|
||||
1u, 16u, 13u, 13u, 5u, 7u, 5u, 7u, 7u, 7u, 5u, 7u, 5u, 7u, 7u, 7u,
|
||||
5u, 7u, 5u, 7u, 7u, 7u, 5u, 7u, 5u, 7u, 7u, 7u, 4u, 4u, 6u, 6u,
|
||||
|
@ -1550,7 +1550,7 @@ find_syllables (hb_buffer_t *buffer)
|
|||
int cs;
|
||||
hb_glyph_info_t *info = buffer->info;
|
||||
|
||||
#line 1554 "../../src/hb-ot-shape-complex-indic-machine.hh.tmp"
|
||||
#line 1554 "hb-ot-shape-complex-indic-machine.hh.tmp"
|
||||
{
|
||||
cs = indic_syllable_machine_start;
|
||||
ts = 0;
|
||||
|
@ -1567,7 +1567,7 @@ find_syllables (hb_buffer_t *buffer)
|
|||
unsigned int last = 0;
|
||||
unsigned int syllable_serial = 1;
|
||||
|
||||
#line 1571 "../../src/hb-ot-shape-complex-indic-machine.hh.tmp"
|
||||
#line 1571 "hb-ot-shape-complex-indic-machine.hh.tmp"
|
||||
{
|
||||
int _slen;
|
||||
int _trans;
|
||||
|
@ -1581,7 +1581,7 @@ _resume:
|
|||
#line 1 "NONE"
|
||||
{ts = p;}
|
||||
break;
|
||||
#line 1585 "../../src/hb-ot-shape-complex-indic-machine.hh.tmp"
|
||||
#line 1585 "hb-ot-shape-complex-indic-machine.hh.tmp"
|
||||
}
|
||||
|
||||
_keys = _indic_syllable_machine_trans_keys + (cs<<1);
|
||||
|
@ -1700,7 +1700,7 @@ _eof_trans:
|
|||
#line 93 "../../src/hb-ot-shape-complex-indic-machine.rl"
|
||||
{act = 6;}
|
||||
break;
|
||||
#line 1704 "../../src/hb-ot-shape-complex-indic-machine.hh.tmp"
|
||||
#line 1704 "hb-ot-shape-complex-indic-machine.hh.tmp"
|
||||
}
|
||||
|
||||
_again:
|
||||
|
@ -1709,7 +1709,7 @@ _again:
|
|||
#line 1 "NONE"
|
||||
{ts = 0;}
|
||||
break;
|
||||
#line 1713 "../../src/hb-ot-shape-complex-indic-machine.hh.tmp"
|
||||
#line 1713 "hb-ot-shape-complex-indic-machine.hh.tmp"
|
||||
}
|
||||
|
||||
if ( ++p != pe )
|
||||
|
|
|
@ -69,7 +69,7 @@ cn = c.ZWJ?.n?;
|
|||
forced_rakar = ZWJ H ZWJ Ra;
|
||||
symbol = Symbol.N?;
|
||||
matra_group = z{0,3}.M.N?.(H | forced_rakar)?;
|
||||
syllable_tail = (SM.SM?.ZWNJ?)? A{0,3}? VD{0,2};
|
||||
syllable_tail = (z?.SM.SM?.ZWNJ?)? A{0,3}? VD{0,2};
|
||||
place_holder = PLACEHOLDER | DOTTEDCIRCLE;
|
||||
halant_group = (z?.h.(ZWJ.N?)?);
|
||||
final_halant_group = halant_group | h.ZWNJ;
|
||||
|
|
|
@ -96,6 +96,8 @@
|
|||
|
||||
#if (defined(__WIN32__) && !defined(__WINE__)) || defined(_MSC_VER)
|
||||
#define snprintf _snprintf
|
||||
/* Windows CE only has _strdup, while rest of Windows has both. */
|
||||
#define strdup _strdup
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
@ -126,10 +128,47 @@
|
|||
# ifndef _WIN32_WINNT
|
||||
# define _WIN32_WINNT 0x0600
|
||||
# endif
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# define STRICT
|
||||
# ifndef WIN32_LEAN_AND_MEAN
|
||||
# define WIN32_LEAN_AND_MEAN 1
|
||||
# endif
|
||||
# ifndef STRICT
|
||||
# define STRICT 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32_WCE
|
||||
/* Some things not defined on Windows CE. */
|
||||
#define MemoryBarrier()
|
||||
#define getenv(Name) NULL
|
||||
#define setlocale(Category, Locale) "C"
|
||||
static int errno = 0; /* Use something better? */
|
||||
#endif
|
||||
|
||||
#if HAVE_ATEXIT
|
||||
/* atexit() is only safe to be called from shared libraries on certain
|
||||
* platforms. Whitelist.
|
||||
* https://bugs.freedesktop.org/show_bug.cgi?id=82246 */
|
||||
# if defined(__linux) && defined(__GLIBC_PREREQ)
|
||||
# if __GLIBC_PREREQ(2,3)
|
||||
/* From atexit() manpage, it's safe with glibc 2.2.3 on Linux. */
|
||||
# define HB_USE_ATEXIT 1
|
||||
# endif
|
||||
# elif defined(_MSC_VER) || defined(__MINGW32__)
|
||||
/* For MSVC:
|
||||
* http://msdn.microsoft.com/en-ca/library/tze57ck3.aspx
|
||||
* http://msdn.microsoft.com/en-ca/library/zk17ww08.aspx
|
||||
* mingw32 headers say atexit is safe to use in shared libraries.
|
||||
*/
|
||||
# define HB_USE_ATEXIT 1
|
||||
# elif defined(__ANDROID__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
|
||||
/* This was fixed in Android NKD r8 or r8b:
|
||||
* https://code.google.com/p/android/issues/detail?id=6455
|
||||
* which introduced GCC 4.6:
|
||||
* https://developer.android.com/tools/sdk/ndk/index.html
|
||||
*/
|
||||
# define HB_USE_ATEXIT 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Basics */
|
||||
|
||||
|
@ -500,47 +539,6 @@ struct hb_lockable_set_t
|
|||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/* Big-endian handling */
|
||||
|
||||
static inline uint16_t hb_be_uint16 (const uint16_t v)
|
||||
{
|
||||
const uint8_t *V = (const uint8_t *) &v;
|
||||
return (V[0] << 8) | V[1];
|
||||
}
|
||||
|
||||
static inline uint16_t hb_uint16_swap (const uint16_t v)
|
||||
{
|
||||
return (v >> 8) | (v << 8);
|
||||
}
|
||||
|
||||
static inline uint32_t hb_uint32_swap (const uint32_t v)
|
||||
{
|
||||
return (hb_uint16_swap (v) << 16) | hb_uint16_swap (v >> 16);
|
||||
}
|
||||
|
||||
/* Note, of the following macros, uint16_get is the one called many many times.
|
||||
* If there is any optimizations to be done, it's in that macro. However, I
|
||||
* already confirmed that on my T400 ThinkPad at least, using bswap_16(), which
|
||||
* results in a single ror instruction, does NOT speed this up. In fact, it
|
||||
* resulted in a minor slowdown. At any rate, note that v may not be correctly
|
||||
* aligned, so I think the current implementation is optimal.
|
||||
*/
|
||||
|
||||
#define hb_be_uint16_put(v,V) HB_STMT_START { v[0] = (V>>8); v[1] = (V); } HB_STMT_END
|
||||
#define hb_be_uint16_get(v) (uint16_t) ((v[0] << 8) + v[1])
|
||||
#define hb_be_uint16_eq(a,b) (a[0] == b[0] && a[1] == b[1])
|
||||
|
||||
#define hb_be_uint32_put(v,V) HB_STMT_START { v[0] = (V>>24); v[1] = (V>>16); v[2] = (V>>8); v[3] = (V); } HB_STMT_END
|
||||
#define hb_be_uint32_get(v) (uint32_t) ((v[0] << 24) + (v[1] << 16) + (v[2] << 8) + v[3])
|
||||
#define hb_be_uint32_eq(a,b) (a[0] == b[0] && a[1] == b[1] && a[2] == b[2] && a[3] == b[3])
|
||||
|
||||
#define hb_be_uint24_put(v,V) HB_STMT_START { v[0] = (V>>16); v[1] = (V>>8); v[2] = (V); } HB_STMT_END
|
||||
#define hb_be_uint24_get(v) (uint32_t) ((v[0] << 16) + (v[1] << 8) + v[2])
|
||||
#define hb_be_uint24_eq(a,b) (a[0] == b[0] && a[1] == b[1] && a[2] == b[2])
|
||||
|
||||
|
||||
/* ASCII tag/character handling */
|
||||
|
||||
static inline bool ISALPHA (unsigned char c)
|
||||
|
@ -585,6 +583,15 @@ _hb_debug (unsigned int level,
|
|||
#define DEBUG_LEVEL_ENABLED(WHAT, LEVEL) (_hb_debug ((LEVEL), HB_DEBUG_##WHAT))
|
||||
#define DEBUG_ENABLED(WHAT) (DEBUG_LEVEL_ENABLED (WHAT, 0))
|
||||
|
||||
template <int max_level> static inline void
|
||||
_hb_debug_msg_va (const char *what,
|
||||
const void *obj,
|
||||
const char *func,
|
||||
bool indented,
|
||||
unsigned int level,
|
||||
int level_dir,
|
||||
const char *message,
|
||||
va_list ap) HB_PRINTF_FUNC(7, 0);
|
||||
template <int max_level> static inline void
|
||||
_hb_debug_msg_va (const char *what,
|
||||
const void *obj,
|
||||
|
@ -708,7 +715,9 @@ _hb_debug_msg<0> (const char *what HB_UNUSED,
|
|||
*/
|
||||
|
||||
template <typename T>
|
||||
struct hb_printer_t {};
|
||||
struct hb_printer_t {
|
||||
const char *print (const T&) { return "something"; }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct hb_printer_t<bool> {
|
||||
|
@ -815,7 +824,9 @@ hb_in_range (T u, T lo, T hi)
|
|||
* to generate a warning than unused variables. */
|
||||
ASSERT_STATIC (sizeof (hb_assert_unsigned_t<T>) >= 0);
|
||||
|
||||
return (u - lo) <= (hi - lo);
|
||||
/* The casts below are important as if T is smaller than int,
|
||||
* the subtract results will become a signed int! */
|
||||
return (T)(u - lo) <= (T)(hi - lo);
|
||||
}
|
||||
|
||||
template <typename T> static inline bool
|
||||
|
@ -839,7 +850,7 @@ hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2, T lo3, T hi3)
|
|||
#define FLAG_RANGE(x,y) (ASSERT_STATIC_EXPR_ZERO ((x) < (y)) + FLAG(y+1) - FLAG(x))
|
||||
|
||||
|
||||
template <typename T, typename T2> inline void
|
||||
template <typename T, typename T2> static inline void
|
||||
hb_bubble_sort (T *array, unsigned int len, int(*compar)(const T *, const T *), T2 *array2)
|
||||
{
|
||||
if (unlikely (!len))
|
||||
|
@ -872,7 +883,7 @@ hb_bubble_sort (T *array, unsigned int len, int(*compar)(const T *, const T *),
|
|||
} while (k);
|
||||
}
|
||||
|
||||
template <typename T> inline void
|
||||
template <typename T> static inline void
|
||||
hb_bubble_sort (T *array, unsigned int len, int(*compar)(const T *, const T *))
|
||||
{
|
||||
hb_bubble_sort (array, len, compar, (int *) NULL);
|
||||
|
@ -901,12 +912,12 @@ hb_codepoint_parse (const char *s, unsigned int len, int base, hb_codepoint_t *o
|
|||
|
||||
struct hb_options_t
|
||||
{
|
||||
int initialized : 1;
|
||||
int uniscribe_bug_compatible : 1;
|
||||
unsigned int initialized : 1;
|
||||
unsigned int uniscribe_bug_compatible : 1;
|
||||
};
|
||||
|
||||
union hb_options_union_t {
|
||||
int i;
|
||||
unsigned int i;
|
||||
hb_options_t opts;
|
||||
};
|
||||
ASSERT_STATIC (sizeof (int) == sizeof (hb_options_union_t));
|
||||
|
|
|
@ -150,7 +150,7 @@ struct hb_set_t
|
|||
bool in_error;
|
||||
|
||||
inline void init (void) {
|
||||
header.init ();
|
||||
hb_object_init (this);
|
||||
clear ();
|
||||
}
|
||||
inline void fini (void) {
|
||||
|
|
|
@ -29,6 +29,12 @@
|
|||
#include "hb-font-private.hh"
|
||||
#include "hb-buffer-private.hh"
|
||||
|
||||
|
||||
#ifndef HB_DEBUG_SHAPE_PLAN
|
||||
#define HB_DEBUG_SHAPE_PLAN (HB_DEBUG+0)
|
||||
#endif
|
||||
|
||||
|
||||
#define HB_SHAPER_IMPLEMENT(shaper) \
|
||||
HB_SHAPER_DATA_ENSURE_DECLARE(shaper, face) \
|
||||
HB_SHAPER_DATA_ENSURE_DECLARE(shaper, font)
|
||||
|
@ -42,6 +48,11 @@ hb_shape_plan_plan (hb_shape_plan_t *shape_plan,
|
|||
unsigned int num_user_features,
|
||||
const char * const *shaper_list)
|
||||
{
|
||||
DEBUG_MSG_FUNC (SHAPE_PLAN, shape_plan,
|
||||
"num_features=%d shaper_list=%p",
|
||||
num_user_features,
|
||||
shaper_list);
|
||||
|
||||
const hb_shaper_pair_t *shapers = _hb_shapers_get ();
|
||||
|
||||
#define HB_SHAPER_PLAN(shaper) \
|
||||
|
@ -104,6 +115,12 @@ hb_shape_plan_create (hb_face_t *face,
|
|||
unsigned int num_user_features,
|
||||
const char * const *shaper_list)
|
||||
{
|
||||
DEBUG_MSG_FUNC (SHAPE_PLAN, NULL,
|
||||
"face=%p num_features=%d shaper_list=%p",
|
||||
face,
|
||||
num_user_features,
|
||||
shaper_list);
|
||||
|
||||
hb_shape_plan_t *shape_plan;
|
||||
hb_feature_t *features = NULL;
|
||||
|
||||
|
@ -271,6 +288,11 @@ hb_shape_plan_execute (hb_shape_plan_t *shape_plan,
|
|||
const hb_feature_t *features,
|
||||
unsigned int num_features)
|
||||
{
|
||||
DEBUG_MSG_FUNC (SHAPE_PLAN, shape_plan,
|
||||
"num_features=%d shaper_func=%p",
|
||||
num_features,
|
||||
shape_plan->shaper_func);
|
||||
|
||||
if (unlikely (hb_object_is_inert (shape_plan) ||
|
||||
hb_object_is_inert (font) ||
|
||||
hb_object_is_inert (buffer)))
|
||||
|
@ -383,6 +405,12 @@ hb_shape_plan_create_cached (hb_face_t *face,
|
|||
unsigned int num_user_features,
|
||||
const char * const *shaper_list)
|
||||
{
|
||||
DEBUG_MSG_FUNC (SHAPE_PLAN, NULL,
|
||||
"face=%p num_features=%d shaper_list=%p",
|
||||
face,
|
||||
num_user_features,
|
||||
shaper_list);
|
||||
|
||||
hb_shape_plan_proposal_t proposal = {
|
||||
*props,
|
||||
shaper_list,
|
||||
|
@ -392,25 +420,22 @@ hb_shape_plan_create_cached (hb_face_t *face,
|
|||
};
|
||||
|
||||
if (shaper_list) {
|
||||
/* Choose shaper. Adapted from hb_shape_plan_plan(). */
|
||||
#define HB_SHAPER_PLAN(shaper) \
|
||||
HB_STMT_START { \
|
||||
if (hb_##shaper##_shaper_face_data_ensure (face)) \
|
||||
proposal.shaper_func = _hb_##shaper##_shape; \
|
||||
} HB_STMT_END
|
||||
|
||||
/* Choose shaper. Adapted from hb_shape_plan_plan().
|
||||
* Must choose shaper exactly the same way as that function. */
|
||||
for (const char * const *shaper_item = shaper_list; *shaper_item; shaper_item++)
|
||||
if (0)
|
||||
;
|
||||
#define HB_SHAPER_IMPLEMENT(shaper) \
|
||||
else if (0 == strcmp (*shaper_item, #shaper)) \
|
||||
HB_SHAPER_PLAN (shaper);
|
||||
else if (0 == strcmp (*shaper_item, #shaper) && \
|
||||
hb_##shaper##_shaper_face_data_ensure (face)) \
|
||||
{ \
|
||||
proposal.shaper_func = _hb_##shaper##_shape; \
|
||||
break; \
|
||||
}
|
||||
#include "hb-shaper-list.hh"
|
||||
#undef HB_SHAPER_IMPLEMENT
|
||||
|
||||
#undef HB_SHAPER_PLAN
|
||||
|
||||
if (unlikely (!proposal.shaper_list))
|
||||
if (unlikely (!proposal.shaper_func))
|
||||
return hb_shape_plan_get_empty ();
|
||||
}
|
||||
|
||||
|
@ -419,7 +444,10 @@ retry:
|
|||
hb_face_t::plan_node_t *cached_plan_nodes = (hb_face_t::plan_node_t *) hb_atomic_ptr_get (&face->shape_plans);
|
||||
for (hb_face_t::plan_node_t *node = cached_plan_nodes; node; node = node->next)
|
||||
if (hb_shape_plan_matches (node->shape_plan, &proposal))
|
||||
{
|
||||
DEBUG_MSG_FUNC (SHAPE_PLAN, node->shape_plan, "fulfilled from cache");
|
||||
return hb_shape_plan_reference (node->shape_plan);
|
||||
}
|
||||
|
||||
/* Not found. */
|
||||
|
||||
|
@ -442,6 +470,7 @@ retry:
|
|||
free (node);
|
||||
goto retry;
|
||||
}
|
||||
DEBUG_MSG_FUNC (SHAPE_PLAN, shape_plan, "inserted into cache");
|
||||
|
||||
return hb_shape_plan_reference (shape_plan);
|
||||
}
|
||||
|
|
|
@ -320,7 +320,7 @@ retry:
|
|||
goto retry;
|
||||
}
|
||||
|
||||
#ifdef HAVE_ATEXIT
|
||||
#ifdef HB_USE_ATEXIT
|
||||
atexit (free_static_shaper_list); /* First person registers atexit() callback. */
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -100,7 +100,7 @@ retry:
|
|||
goto retry;
|
||||
}
|
||||
|
||||
#ifdef HAVE_ATEXIT
|
||||
#ifdef HB_USE_ATEXIT
|
||||
atexit (free_static_shapers); /* First person registers atexit() callback. */
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -43,6 +43,12 @@
|
|||
#endif
|
||||
|
||||
|
||||
static inline uint16_t hb_uint16_swap (const uint16_t v)
|
||||
{ return (v >> 8) | (v << 8); }
|
||||
static inline uint32_t hb_uint32_swap (const uint32_t v)
|
||||
{ return (hb_uint16_swap (v) << 16) | hb_uint16_swap (v >> 16); }
|
||||
|
||||
|
||||
typedef HRESULT (WINAPI *SIOT) /*ScriptItemizeOpenType*/(
|
||||
const WCHAR *pwcInChars,
|
||||
int cInChars,
|
||||
|
@ -245,7 +251,7 @@ retry:
|
|||
goto retry;
|
||||
}
|
||||
|
||||
#ifdef HAVE_ATEXIT
|
||||
#ifdef HB_USE_ATEXIT
|
||||
atexit (free_uniscribe_funcs); /* First person registers atexit() callback. */
|
||||
#endif
|
||||
}
|
||||
|
@ -903,8 +909,7 @@ retry:
|
|||
FAIL ("ScriptShapeOpenType() set fNoGlyphIndex");
|
||||
if (unlikely (hr == E_OUTOFMEMORY))
|
||||
{
|
||||
buffer->ensure (buffer->allocated * 2);
|
||||
if (buffer->in_error)
|
||||
if (unlikely (!buffer->ensure (buffer->allocated * 2)))
|
||||
FAIL ("Buffer resize failed");
|
||||
goto retry;
|
||||
}
|
||||
|
@ -973,8 +978,7 @@ retry:
|
|||
|
||||
#undef utf16_index
|
||||
|
||||
buffer->ensure (glyphs_len);
|
||||
if (buffer->in_error)
|
||||
if (unlikely (!buffer->ensure (glyphs_len)))
|
||||
FAIL ("Buffer in error");
|
||||
|
||||
#undef FAIL
|
||||
|
|
|
@ -38,9 +38,9 @@ HB_BEGIN_DECLS
|
|||
|
||||
#define HB_VERSION_MAJOR 0
|
||||
#define HB_VERSION_MINOR 9
|
||||
#define HB_VERSION_MICRO 34
|
||||
#define HB_VERSION_MICRO 37
|
||||
|
||||
#define HB_VERSION_STRING "0.9.34"
|
||||
#define HB_VERSION_STRING "0.9.37"
|
||||
|
||||
#define HB_VERSION_ATLEAST(major,minor,micro) \
|
||||
((major)*10000+(minor)*100+(micro) <= \
|
||||
|
|
Загрузка…
Ссылка в новой задаче