Update bundled HarfBuzz-NG to 0.9.38

Most important changes:
* Fixes for Arabic, Hangul, Hebrew, Indic,
  Mandaic, Myanmar, and New Tai Lue shapers.
* Fixed out-of-bounds access in Indic shaper.
* Build and stability fixes, various optimizations.

Change-Id: I4f0e32c017f62fe576bee41a430d3da6d571de80
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
This commit is contained in:
Konstantin Ritt 2015-01-24 19:41:33 +04:00
parent 3c1e16df75
commit 3de9bc9cb1
45 changed files with 2413 additions and 1865 deletions

View File

@ -1,3 +1,138 @@
Overview of changes leading to 0.9.38
Friday, January 23, 2015
=====================================
- Fix minor out-of-bounds access in Indic shaper.
- Change New Tai Lue shaping engine from South-East Asian to default,
reflecting change in Unicode encoding model.
- Add hb-shape --font-size. Can take up to two numbers for separate
x / y size.
- Fix CoreText and FreeType scale issues with negative scales.
- Reject blobs larger than 2GB. This might break some icu-le-hb clients
that need security fixes. See:
http://www.icu-project.org/trac/ticket/11450
- Avoid accessing font tables during face destruction, in casce rogue
clients released face data already.
- Fix up gobject-introspection a bit. Python bindings kinda working.
See README.python.
- Misc fixes.
- API additions:
hb_ft_face_create_referenced()
hb_ft_font_create_referenced()
Overview of changes leading to 0.9.37
Wednesday, December 17, 2014
=====================================
- Fix out-of-bounds access in Context lookup format 3.
- Indic: Allow ZWJ/ZWNJ before syllable modifiers.
Overview of changes leading to 0.9.36
Thursday, November 20, 2014
=====================================
- First time that three months went by without a release since
0.9.2 was released on August 10, 2012!
- Fix performance bug in hb_ot_collect_glyphs():
https://bugzilla.mozilla.org/show_bug.cgi?id=1090869
- Add basic vertical-text support to hb-ot-font.
- Misc build fixes.
Overview of changes leading to 0.9.35
Saturday, August 13, 2014
=====================================
- Fix major shape-plan caching bug when more than one shaper were
provided to hb_shape_full() (as exercised by XeTeX).
http://www.mail-archive.com/debian-bugs-dist@lists.debian.org/msg1246370.html
- Fix Arabic fallback shaping regression. This was broken in 0.9.32.
- Major hb-coretext fixes. That backend is complete now, including
respecing buffer direction and language, down to vertical writing.
- Build fixes for Windows CE. Should build fine now.
- Misc fixes:
Use atexit() only if it's safe to call from shared library
https://bugs.freedesktop.org/show_bug.cgi?id=82246
Mandaic had errors in its Unicode Joining_Type
https://bugs.freedesktop.org/show_bug.cgi?id=82306
- API changes:
* hb_buffer_clear_contents() does not reset buffer flags now.
After 763e5466c0a03a7c27020e1e2598e488612529a7, one doesn't
need to set flags for different pieces of text. The flags now
are something the client sets up once, depending on how it
actually uses the buffer. As such, don't clear it in
clear_contents().
I don't expect any changes to be needed to any existing client.
Overview of changes leading to 0.9.34
Saturday, August 2, 2014
=====================================
- hb_feature_from_string() now accepts CSS font-feature-settings format.
- As a result, hb-shape / hb-view --features also accept CSS-style strings.
Eg, "'liga' off" is accepted now.
- Add old-spec Myanmar shaper:
https://bugs.freedesktop.org/show_bug.cgi?id=81775
- Don't apply 'calt' in Hangul shaper.
- Fix mark advance zeroing for Hebrew shaper:
https://bugs.freedesktop.org/show_bug.cgi?id=76767
- Implement Windows-1256 custom Arabic shaping. Only built on Windows,
and requires help from get_glyph(). Used by Firefox.
https://bugzilla.mozilla.org/show_bug.cgi?id=1045139
- Disable 'liga' in vertical text.
- Build fixes.
- API changes:
* Make HB_BUFFER_FLAG_BOT/EOT easier to use.
Previously, we expected users to provide BOT/EOT flags when the
text *segment* was at paragraph boundaries. This meant that for
clients that provide full paragraph to HarfBuzz (eg. Pango), they
had code like this:
hb_buffer_set_flags (hb_buffer,
(item_offset == 0 ? HB_BUFFER_FLAG_BOT : 0) |
(item_offset + item_length == paragraph_length ?
HB_BUFFER_FLAG_EOT : 0));
hb_buffer_add_utf8 (hb_buffer,
paragraph_text, paragraph_length,
item_offset, item_length);
After this change such clients can simply say:
hb_buffer_set_flags (hb_buffer,
HB_BUFFER_FLAG_BOT | HB_BUFFER_FLAG_EOT);
hb_buffer_add_utf8 (hb_buffer,
paragraph_text, paragraph_length,
item_offset, item_length);
Ie, HarfBuzz itself checks whether the segment is at the beginning/end
of the paragraph. Clients that only pass item-at-a-time to HarfBuzz
continue not setting any flags whatsoever.
Another way to put it is: if there's pre-context text in the buffer,
HarfBuzz ignores the BOT flag. If there's post-context, it ignores
EOT flag.
Overview of changes leading to 0.9.33
Tuesday, July 22, 2014
=====================================
- Turn off ARabic 'cswh' feature that was accidentally turned on.
- Add HB_TAG_MAX_SIGNED.
- Make hb_face_make_immutable() really make face immutable!
- Windows build fixes.
Overview of changes leading to 0.9.32
Thursday, July 17, 2014
=====================================

View File

@ -1,3 +1,6 @@
[![Build Status](https://travis-ci.org/behdad/harfbuzz.svg)](https://travis-ci.org/behdad/harfbuzz)
[![Coverage Status](https://img.shields.io/coveralls/behdad/harfbuzz.svg)](https://coveralls.io/r/behdad/harfbuzz)
This is HarfBuzz, a text shaping library.
For bug reports, mailing list, and other information please visit:

View File

@ -8,6 +8,7 @@ CONFIG += \
load(qt_helper_lib)
DEFINES += HAVE_OT HAVE_ATEXIT HB_NO_UNICODE_FUNCS HB_DISABLE_DEPRECATED
win32: DEFINES += HB_NO_WIN1256
INCLUDEPATH += $$PWD/include

View File

@ -44,7 +44,6 @@
#elif !defined(HB_NO_MT) && (defined(_WIN32) || defined(__CYGWIN__))
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
/* MinGW has a convoluted history of supporting MemoryBarrier

View File

@ -78,8 +78,8 @@ _hb_blob_destroy_user_data (hb_blob_t *blob)
}
/**
* hb_blob_create: (Xconstructor)
* @data: (array length=length) (closure user_data) (destroy destroy) (scope notified) (transfer none): Pointer to blob data.
* hb_blob_create: (skip)
* @data: Pointer to blob data.
* @length: Length of @data in bytes.
* @mode: Memory mode for @data.
* @user_data: Data parameter to pass to @destroy.
@ -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 ();

View File

@ -459,8 +459,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};
#line 466 "hb-buffer-deserialize-json.hh"
{

View File

@ -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);

View File

@ -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 */
@ -1400,7 +1400,7 @@ hb_buffer_add_utf (hb_buffer_t *buffer,
/**
* hb_buffer_add_utf8:
* @buffer: a buffer.
* @text: (array length=text_length):
* @text: (array length=text_length) (element-type uint8_t):
* @text_length:
* @item_offset:
* @item_length:

View File

@ -33,10 +33,6 @@
#include <locale.h>
#ifdef _WIN32_WCE
#define strdup(x) _strdup(x)
#endif
/* hb_options_t */
@ -238,8 +234,8 @@ struct hb_language_item_t {
static hb_language_item_t *langs;
#ifdef HAVE_ATEXIT
static inline
#ifdef HB_USE_ATEXIT
static
void free_langs (void)
{
while (langs) {
@ -273,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
@ -349,7 +345,7 @@ hb_language_get_default (void)
hb_language_t language = (hb_language_t) hb_atomic_ptr_get (&default_language);
if (unlikely (language == HB_LANGUAGE_INVALID)) {
language = hb_language_from_string (setlocale (LC_CTYPE, NULL), -1);
hb_atomic_ptr_cmpexch (&default_language, HB_LANGUAGE_INVALID, language);
(void) hb_atomic_ptr_cmpexch (&default_language, HB_LANGUAGE_INVALID, language);
}
return default_language;

View File

@ -95,6 +95,7 @@ typedef uint32_t hb_tag_t;
#define HB_TAG_NONE HB_TAG(0,0,0,0)
#define HB_TAG_MAX HB_TAG(0xff,0xff,0xff,0xff)
#define HB_TAG_MAX_SIGNED HB_TAG(0x7f,0xff,0xff,0xff)
/* len=-1 means str is NUL-terminated. */
hb_tag_t
@ -122,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 */
@ -295,11 +297,17 @@ typedef enum
/*7.0*/ HB_SCRIPT_WARANG_CITI = HB_TAG ('W','a','r','a'),
/* No script set. */
/*---*/ HB_SCRIPT_INVALID = HB_TAG_NONE,
HB_SCRIPT_INVALID = HB_TAG_NONE,
/* Dummy value to ensure any hb_tag_t value can be passed/stored as hb_script_t
* without risking undefined behavior. */
/*---*/ _HB_SCRIPT_MAX_VALUE = HB_TAG_MAX
/* Dummy values to ensure any hb_tag_t value can be passed/stored as hb_script_t
* without risking undefined behavior. Include both a signed and unsigned max,
* since technically enums are int, and indeed, hb_script_t ends up being signed.
* See this thread for technicalities:
*
* http://lists.freedesktop.org/archives/harfbuzz/2014-March/004150.html
*/
_HB_SCRIPT_MAX_VALUE = HB_TAG_MAX, /*< skip >*/
_HB_SCRIPT_MAX_VALUE_SIGNED = HB_TAG_MAX_SIGNED /*< skip >*/
} hb_script_t;
@ -309,7 +317,7 @@ typedef enum
hb_script_t
hb_script_from_iso15924_tag (hb_tag_t tag);
/* suger for tag_from_string() then script_from_iso15924_tag */
/* sugar for tag_from_string() then script_from_iso15924_tag */
/* len=-1 means s is NUL-terminated */
hb_script_t
hb_script_from_string (const char *s, int len);

View File

@ -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);

View File

@ -298,7 +298,7 @@ hb_face_get_user_data (hb_face_t *face,
void
hb_face_make_immutable (hb_face_t *face)
{
if (hb_object_is_inert (face))
if (unlikely (hb_object_is_inert (face)))
return;
face->immutable = true;
@ -368,7 +368,7 @@ void
hb_face_set_index (hb_face_t *face,
unsigned int index)
{
if (hb_object_is_inert (face))
if (face->immutable)
return;
face->index = index;
@ -403,7 +403,7 @@ void
hb_face_set_upem (hb_face_t *face,
unsigned int upem)
{
if (hb_object_is_inert (face))
if (face->immutable)
return;
face->upem = upem;
@ -447,7 +447,7 @@ void
hb_face_set_glyph_count (hb_face_t *face,
unsigned int glyph_count)
{
if (hb_object_is_inert (face))
if (face->immutable)
return;
face->num_glyphs = glyph_count;

View File

@ -357,7 +357,7 @@ hb_font_funcs_get_user_data (hb_font_funcs_t *ffuncs,
void
hb_font_funcs_make_immutable (hb_font_funcs_t *ffuncs)
{
if (hb_object_is_inert (ffuncs))
if (unlikely (hb_object_is_inert (ffuncs)))
return;
ffuncs->immutable = true;
@ -1034,7 +1034,7 @@ hb_font_get_user_data (hb_font_t *font,
void
hb_font_make_immutable (hb_font_t *font)
{
if (hb_object_is_inert (font))
if (unlikely (hb_object_is_inert (font)))
return;
font->immutable = true;

View File

@ -44,21 +44,10 @@
#elif !defined(HB_NO_MT) && (defined(_WIN32) || defined(__CYGWIN__))
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
typedef CRITICAL_SECTION hb_mutex_impl_t;
#ifdef _WIN32_WCE
#define HB_MUTEX_IMPL_INIT { 0, 0, NULL, NULL, 0 }
#else
#define HB_MUTEX_IMPL_INIT { NULL, 0, 0, NULL, NULL, 0 }
#endif
#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP)
#define hb_mutex_impl_init(M) InitializeCriticalSectionEx (M, 0, 0)
#else
#define HB_MUTEX_IMPL_INIT {0}
#define hb_mutex_impl_init(M) InitializeCriticalSection (M)
#endif
#define hb_mutex_impl_lock(M) EnterCriticalSection (M)
#define hb_mutex_impl_unlock(M) LeaveCriticalSection (M)
#define hb_mutex_impl_finish(M) DeleteCriticalSection (M)

View File

@ -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);
}

View File

@ -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 */

View File

@ -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>
@ -289,7 +292,7 @@ template <typename Type>
struct Sanitizer
{
static hb_blob_t *sanitize (hb_blob_t *blob) {
hb_sanitize_context_t c[1] = {{0}};
hb_sanitize_context_t c[1] = {{0, NULL, NULL, false, 0, NULL}};
bool sane;
/* TODO is_sane() stuff */
@ -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>

View File

@ -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;
}

View File

@ -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 */

View File

@ -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 */

View File

@ -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,12 +602,24 @@ 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_array = CastP<PairValueRecord> (arrayZ);
unsigned int count = len;
for (unsigned int i = 0; i < count; i++)
/* Hand-coded bsearch. */
if (unlikely (!count))
return TRACE_RETURN (false);
hb_codepoint_t x = buffer->info[pos].codepoint;
int min = 0, max = (int) count - 1;
while (min <= max)
{
/* TODO bsearch */
if (buffer->info[pos].codepoint == record->secondGlyph)
int mid = (min + max) / 2;
const PairValueRecord *record = &StructAtOffset<PairValueRecord> (record_array, record_size * mid);
hb_codepoint_t mid_x = record->secondGlyph;
if (x < mid_x)
max = mid - 1;
else if (x > mid_x)
min = mid + 1;
else
{
valueFormats[0].apply_value (c->font, c->direction, this,
&record->values[0], buffer->cur_pos());
@ -618,7 +630,6 @@ struct PairSet
buffer->idx = pos;
return TRACE_RETURN (true);
}
record = &StructAtOffset<PairValueRecord> (record, record_size);
}
return TRACE_RETURN (false);
@ -634,20 +645,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 +833,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 +1000,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 +1099,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 +1220,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 +1339,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 +1398,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 +1499,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);
@ -1589,6 +1600,8 @@ GPOS::position_start (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
void
GPOS::position_finish (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
{
_hb_buffer_assert_gsubgpos_vars (buffer);
unsigned int len;
hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, &len);
hb_direction_t direction = buffer->props.direction;
@ -1600,8 +1613,6 @@ GPOS::position_finish (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
/* Handle attachments */
for (unsigned int i = 0; i < len; i++)
fix_mark_attachment (pos, i, direction);
_hb_buffer_deallocate_gsubgpos_vars (buffer);
}

View File

@ -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);
@ -1338,7 +1338,7 @@ struct GSUB : GSUBGPOS
void
GSUB::substitute_start (hb_font_t *font, hb_buffer_t *buffer)
{
_hb_buffer_allocate_gsubgpos_vars (buffer);
_hb_buffer_assert_gsubgpos_vars (buffer);
const GDEF &gdef = *hb_ot_layout_from_face (font->face)->gdef;
unsigned int count = buffer->len;

View File

@ -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));

View File

@ -126,8 +126,7 @@ struct hb_ot_layout_lookup_accelerator_t
lookup.add_coverage (&digest);
}
template <typename TLookup>
inline void fini (const TLookup &lookup)
inline void fini (void)
{
}
@ -419,6 +418,13 @@ _hb_buffer_deallocate_unicode_vars (hb_buffer_t *buffer)
HB_BUFFER_DEALLOCATE_VAR (buffer, unicode_props1);
}
static inline void
_hb_buffer_assert_unicode_vars (hb_buffer_t *buffer)
{
HB_BUFFER_ASSERT_VAR (buffer, unicode_props0);
HB_BUFFER_ASSERT_VAR (buffer, unicode_props1);
}
static inline void
_hb_buffer_allocate_gsubgpos_vars (hb_buffer_t *buffer)
{
@ -435,6 +441,14 @@ _hb_buffer_deallocate_gsubgpos_vars (hb_buffer_t *buffer)
HB_BUFFER_DEALLOCATE_VAR (buffer, glyph_props);
}
static inline void
_hb_buffer_assert_gsubgpos_vars (hb_buffer_t *buffer)
{
HB_BUFFER_ASSERT_VAR (buffer, glyph_props);
HB_BUFFER_ASSERT_VAR (buffer, lig_props);
HB_BUFFER_ASSERT_VAR (buffer, syllable);
}
/* Make sure no one directly touches our props... */
#undef unicode_props0
#undef unicode_props1

View File

@ -84,9 +84,9 @@ void
_hb_ot_layout_destroy (hb_ot_layout_t *layout)
{
for (unsigned int i = 0; i < layout->gsub_lookup_count; i++)
layout->gsub_accels[i].fini (layout->gsub->get_lookup (i));
layout->gsub_accels[i].fini ();
for (unsigned int i = 0; i < layout->gpos_lookup_count; i++)
layout->gpos_accels[i].fini (layout->gpos->get_lookup (i));
layout->gpos_accels[i].fini ();
free (layout->gsub_accels);
free (layout->gpos_accels);

View File

@ -33,6 +33,8 @@
#include "hb-ot-layout-gsub-table.hh"
/* Features ordered the same as the entries in shaping_table rows,
* followed by rlig. Don't change. */
static const hb_tag_t arabic_fallback_features[] =
{
HB_TAG('i','n','i','t'),
@ -42,16 +44,6 @@ static const hb_tag_t arabic_fallback_features[] =
HB_TAG('r','l','i','g'),
};
/* Same order as the fallback feature array */
enum {
FALLBACK_INIT,
FALLBACK_MEDI,
FALLBACK_FINA,
FALLBACK_ISOL,
FALLBACK_RLIG,
ARABIC_NUM_FALLBACK_FEATURES
};
static OT::SubstLookup *
arabic_fallback_synthesize_lookup_single (const hb_ot_shape_plan_t *plan HB_UNUSED,
hb_font_t *font,
@ -80,6 +72,9 @@ arabic_fallback_synthesize_lookup_single (const hb_ot_shape_plan_t *plan HB_UNUS
num_glyphs++;
}
if (!num_glyphs)
return NULL;
/* Bubble-sort!
* May not be good-enough for presidential candidate interviews, but good-enough for us... */
hb_bubble_sort (&glyphs[0], num_glyphs, OT::GlyphID::cmp, &substitutes[0]);
@ -157,6 +152,9 @@ arabic_fallback_synthesize_lookup_ligature (const hb_ot_shape_plan_t *plan HB_UN
}
}
if (!num_ligatures)
return NULL;
OT::Supplier<OT::GlyphID> first_glyphs_supplier (first_glyphs, num_first_glyphs);
OT::Supplier<unsigned int > ligature_per_first_glyph_count_supplier (ligature_per_first_glyph_count_list, num_first_glyphs);
OT::Supplier<OT::GlyphID> ligatures_supplier (ligature_list, num_ligatures);
@ -193,17 +191,108 @@ arabic_fallback_synthesize_lookup (const hb_ot_shape_plan_t *plan,
return arabic_fallback_synthesize_lookup_ligature (plan, font);
}
#define ARABIC_FALLBACK_MAX_LOOKUPS 5
struct arabic_fallback_plan_t
{
ASSERT_POD ();
hb_mask_t mask_array[ARABIC_NUM_FALLBACK_FEATURES];
OT::SubstLookup *lookup_array[ARABIC_NUM_FALLBACK_FEATURES];
hb_ot_layout_lookup_accelerator_t accel_array[ARABIC_NUM_FALLBACK_FEATURES];
unsigned int num_lookups;
bool free_lookups;
hb_mask_t mask_array[ARABIC_FALLBACK_MAX_LOOKUPS];
OT::SubstLookup *lookup_array[ARABIC_FALLBACK_MAX_LOOKUPS];
hb_ot_layout_lookup_accelerator_t accel_array[ARABIC_FALLBACK_MAX_LOOKUPS];
};
static const arabic_fallback_plan_t arabic_fallback_plan_nil = {};
#if (defined(_WIN32) || defined(__CYGWIN__)) && !defined(HB_NO_WIN1256)
#define HB_WITH_WIN1256
#endif
#ifdef HB_WITH_WIN1256
#include "hb-ot-shape-complex-arabic-win1256.hh"
#endif
struct ManifestLookup {
OT::Tag tag;
OT::OffsetTo<OT::SubstLookup> lookupOffset;
};
typedef OT::ArrayOf<ManifestLookup> Manifest;
static bool
arabic_fallback_plan_init_win1256 (arabic_fallback_plan_t *fallback_plan,
const hb_ot_shape_plan_t *plan,
hb_font_t *font)
{
#ifdef HB_WITH_WIN1256
/* Does this font look like it's Windows-1256-encoded? */
hb_codepoint_t g;
if (!(hb_font_get_glyph (font, 0x0627u, 0, &g) && g == 199 /* ALEF */ &&
hb_font_get_glyph (font, 0x0644u, 0, &g) && g == 225 /* LAM */ &&
hb_font_get_glyph (font, 0x0649u, 0, &g) && g == 236 /* ALEF MAKSURA */ &&
hb_font_get_glyph (font, 0x064Au, 0, &g) && g == 237 /* YEH */ &&
hb_font_get_glyph (font, 0x0652u, 0, &g) && g == 250 /* SUKUN */))
return false;
const Manifest &manifest = reinterpret_cast<const Manifest&> (arabic_win1256_gsub_lookups.manifest);
ASSERT_STATIC (sizeof (arabic_win1256_gsub_lookups.manifestData) / sizeof (ManifestLookup)
<= ARABIC_FALLBACK_MAX_LOOKUPS);
/* TODO sanitize the table? */
unsigned j = 0;
unsigned int count = manifest.len;
for (unsigned int i = 0; i < count; i++)
{
fallback_plan->mask_array[j] = plan->map.get_1_mask (manifest[i].tag);
if (fallback_plan->mask_array[j])
{
fallback_plan->lookup_array[j] = const_cast<OT::SubstLookup*> (&(&manifest+manifest[i].lookupOffset));
if (fallback_plan->lookup_array[j])
{
fallback_plan->accel_array[j].init (*fallback_plan->lookup_array[j]);
j++;
}
}
}
fallback_plan->num_lookups = j;
fallback_plan->free_lookups = false;
return j > 0;
#else
return false;
#endif
}
static bool
arabic_fallback_plan_init_unicode (arabic_fallback_plan_t *fallback_plan,
const hb_ot_shape_plan_t *plan,
hb_font_t *font)
{
ASSERT_STATIC (ARRAY_LENGTH_CONST(arabic_fallback_features) <= ARABIC_FALLBACK_MAX_LOOKUPS);
unsigned int j = 0;
for (unsigned int i = 0; i < ARRAY_LENGTH(arabic_fallback_features) ; i++)
{
fallback_plan->mask_array[j] = plan->map.get_1_mask (arabic_fallback_features[i]);
if (fallback_plan->mask_array[j])
{
fallback_plan->lookup_array[j] = arabic_fallback_synthesize_lookup (plan, font, i);
if (fallback_plan->lookup_array[j])
{
fallback_plan->accel_array[j].init (*fallback_plan->lookup_array[j]);
j++;
}
}
}
fallback_plan->num_lookups = j;
fallback_plan->free_lookups = true;
return j > 0;
}
static arabic_fallback_plan_t *
arabic_fallback_plan_create (const hb_ot_shape_plan_t *plan,
hb_font_t *font)
@ -212,17 +301,21 @@ arabic_fallback_plan_create (const hb_ot_shape_plan_t *plan,
if (unlikely (!fallback_plan))
return const_cast<arabic_fallback_plan_t *> (&arabic_fallback_plan_nil);
for (unsigned int i = 0; i < ARABIC_NUM_FALLBACK_FEATURES; i++)
{
fallback_plan->mask_array[i] = plan->map.get_1_mask (arabic_fallback_features[i]);
if (fallback_plan->mask_array[i]) {
fallback_plan->lookup_array[i] = arabic_fallback_synthesize_lookup (plan, font, i);
if (fallback_plan->lookup_array[i])
fallback_plan->accel_array[i].init (*fallback_plan->lookup_array[i]);
}
}
fallback_plan->num_lookups = 0;
fallback_plan->free_lookups = false;
return fallback_plan;
/* Try synthesizing GSUB table using Unicode Arabic Presentation Forms,
* in case the font has cmap entries for the presentation-forms characters. */
if (arabic_fallback_plan_init_unicode (fallback_plan, plan, font))
return fallback_plan;
/* See if this looks like a Windows-1256-encoded font. If it does, use a
* hand-coded GSUB table. */
if (arabic_fallback_plan_init_win1256 (fallback_plan, plan, font))
return fallback_plan;
free (fallback_plan);
return const_cast<arabic_fallback_plan_t *> (&arabic_fallback_plan_nil);
}
static void
@ -231,11 +324,12 @@ arabic_fallback_plan_destroy (arabic_fallback_plan_t *fallback_plan)
if (!fallback_plan || fallback_plan == &arabic_fallback_plan_nil)
return;
for (unsigned int i = 0; i < ARABIC_NUM_FALLBACK_FEATURES; i++)
for (unsigned int i = 0; i < fallback_plan->num_lookups; i++)
if (fallback_plan->lookup_array[i])
{
fallback_plan->accel_array[i].fini (fallback_plan->lookup_array[i]);
free (fallback_plan->lookup_array[i]);
fallback_plan->accel_array[i].fini ();
if (fallback_plan->free_lookups)
free (fallback_plan->lookup_array[i]);
}
free (fallback_plan);
@ -247,7 +341,7 @@ arabic_fallback_plan_shape (arabic_fallback_plan_t *fallback_plan,
hb_buffer_t *buffer)
{
OT::hb_apply_context_t c (0, font, buffer);
for (unsigned int i = 0; i < ARABIC_NUM_FALLBACK_FEATURES; i++)
for (unsigned int i = 0; i < fallback_plan->num_lookups; i++)
if (fallback_plan->lookup_array[i]) {
c.set_lookup_mask (fallback_plan->mask_array[i]);
hb_ot_layout_substitute_lookup (&c,

View File

@ -70,7 +70,7 @@ static const uint8_t joining_table[] =
/* Mandaic */
/* 0840 */ R,D,D,D,D,D,R,D,D,R,D,D,D,D,D,R,D,D,D,D,R,D,U,U,U,X,X,X,X,X,X,X,
/* 0840 */ R,D,D,D,D,D,R,R,D,R,D,D,D,D,D,D,D,D,D,D,R,D,U,U,U,X,X,X,X,X,X,X,
/* 0860 */ X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
/* 0880 */ X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,

View File

@ -223,8 +223,8 @@ data_create_arabic (const hb_ot_shape_plan_t *plan)
for (unsigned int i = 0; i < ARABIC_NUM_FEATURES; i++) {
arabic_plan->mask_array[i] = plan->map.get_1_mask (arabic_features[i]);
arabic_plan->do_fallback = arabic_plan->do_fallback &&
!FEATURE_IS_SYRIAC (arabic_features[i]) &&
plan->map.needs_fallback (arabic_features[i]);
(FEATURE_IS_SYRIAC (arabic_features[i]) ||
plan->map.needs_fallback (arabic_features[i]));
}
return arabic_plan;
@ -248,18 +248,17 @@ arabic_joining (hb_buffer_t *buffer)
unsigned int prev = (unsigned int) -1, state = 0;
/* Check pre-context */
if (!(buffer->flags & HB_BUFFER_FLAG_BOT))
for (unsigned int i = 0; i < buffer->context_len[0]; i++)
{
unsigned int this_type = get_joining_type (buffer->context[0][i], buffer->unicode->general_category (buffer->context[0][i]));
for (unsigned int i = 0; i < buffer->context_len[0]; i++)
{
unsigned int this_type = get_joining_type (buffer->context[0][i], buffer->unicode->general_category (buffer->context[0][i]));
if (unlikely (this_type == JOINING_TYPE_T))
continue;
if (unlikely (this_type == JOINING_TYPE_T))
continue;
const arabic_state_table_entry *entry = &arabic_state_table[state][this_type];
state = entry->next_state;
break;
}
const arabic_state_table_entry *entry = &arabic_state_table[state][this_type];
state = entry->next_state;
break;
}
for (unsigned int i = 0; i < count; i++)
{
@ -281,19 +280,18 @@ arabic_joining (hb_buffer_t *buffer)
state = entry->next_state;
}
if (!(buffer->flags & HB_BUFFER_FLAG_EOT))
for (unsigned int i = 0; i < buffer->context_len[1]; i++)
{
unsigned int this_type = get_joining_type (buffer->context[1][i], buffer->unicode->general_category (buffer->context[1][i]));
for (unsigned int i = 0; i < buffer->context_len[1]; i++)
{
unsigned int this_type = get_joining_type (buffer->context[1][i], buffer->unicode->general_category (buffer->context[1][i]));
if (unlikely (this_type == JOINING_TYPE_T))
continue;
if (unlikely (this_type == JOINING_TYPE_T))
continue;
const arabic_state_table_entry *entry = &arabic_state_table[state][this_type];
if (entry->prev_action != NONE && prev != (unsigned int) -1)
info[prev].arabic_shaping_action() = entry->prev_action;
break;
}
const arabic_state_table_entry *entry = &arabic_state_table[state][this_type];
if (entry->prev_action != NONE && prev != (unsigned int) -1)
info[prev].arabic_shaping_action() = entry->prev_action;
break;
}
}
static void

View File

@ -59,6 +59,15 @@ collect_features_hangul (hb_ot_shape_planner_t *plan)
map->add_feature (hangul_features[i], 1, F_NONE);
}
static void
override_features_hangul (hb_ot_shape_planner_t *plan)
{
/* Uniscribe does not apply 'calt' for Hangul, and certain fonts
* (Noto Sans CJK, Source Sans Han, etc) apply all of jamo lookups
* in calt, which is not desirable. */
plan->map.add_feature (HB_TAG('c','a','l','t'), 0, F_GLOBAL);
}
struct hangul_shape_plan_t
{
ASSERT_POD ();
@ -404,7 +413,7 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_hangul =
{
"hangul",
collect_features_hangul,
NULL, /* override_features */
override_features_hangul,
data_create_hangul, /* data_create */
data_destroy_hangul, /* data_destroy */
preprocess_text_hangul,

View File

@ -167,6 +167,6 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_hebrew =
NULL, /* decompose */
compose_hebrew,
NULL, /* setup_masks */
HB_OT_SHAPE_ZERO_WIDTH_MARKS_DEFAULT,
HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
true, /* fallback_position */
};

File diff suppressed because it is too large Load Diff

View File

@ -861,41 +861,41 @@ hb_indic_get_categories (hb_codepoint_t u)
switch (u >> 12)
{
case 0x0u:
if (hb_in_range (u, 0x0028u, 0x0040u)) return indic_table[u - 0x0028u + indic_offset_0x0028u];
if (hb_in_range (u, 0x00D0u, 0x00D8u)) return indic_table[u - 0x00D0u + indic_offset_0x00d0u];
if (hb_in_range (u, 0x0900u, 0x0DF8u)) return indic_table[u - 0x0900u + indic_offset_0x0900u];
if (hb_in_range (u, 0x0028u, 0x003Fu)) return indic_table[u - 0x0028u + indic_offset_0x0028u];
if (hb_in_range (u, 0x00D0u, 0x00D7u)) return indic_table[u - 0x00D0u + indic_offset_0x00d0u];
if (hb_in_range (u, 0x0900u, 0x0DF7u)) return indic_table[u - 0x0900u + indic_offset_0x0900u];
if (unlikely (u == 0x00A0u)) return _(CP,x);
break;
case 0x1u:
if (hb_in_range (u, 0x1000u, 0x10A0u)) return indic_table[u - 0x1000u + indic_offset_0x1000u];
if (hb_in_range (u, 0x1700u, 0x17F0u)) return indic_table[u - 0x1700u + indic_offset_0x1700u];
if (hb_in_range (u, 0x1900u, 0x1AA0u)) return indic_table[u - 0x1900u + indic_offset_0x1900u];
if (hb_in_range (u, 0x1B00u, 0x1C50u)) return indic_table[u - 0x1B00u + indic_offset_0x1b00u];
if (hb_in_range (u, 0x1CD0u, 0x1CF8u)) return indic_table[u - 0x1CD0u + indic_offset_0x1cd0u];
if (hb_in_range (u, 0x1000u, 0x109Fu)) return indic_table[u - 0x1000u + indic_offset_0x1000u];
if (hb_in_range (u, 0x1700u, 0x17EFu)) return indic_table[u - 0x1700u + indic_offset_0x1700u];
if (hb_in_range (u, 0x1900u, 0x1A9Fu)) return indic_table[u - 0x1900u + indic_offset_0x1900u];
if (hb_in_range (u, 0x1B00u, 0x1C4Fu)) return indic_table[u - 0x1B00u + indic_offset_0x1b00u];
if (hb_in_range (u, 0x1CD0u, 0x1CF7u)) return indic_table[u - 0x1CD0u + indic_offset_0x1cd0u];
break;
case 0x2u:
if (hb_in_range (u, 0x2008u, 0x2018u)) return indic_table[u - 0x2008u + indic_offset_0x2008u];
if (hb_in_range (u, 0x2008u, 0x2017u)) return indic_table[u - 0x2008u + indic_offset_0x2008u];
if (unlikely (u == 0x25CCu)) return _(CP,x);
break;
case 0xAu:
if (hb_in_range (u, 0xA800u, 0xAAF8u)) return indic_table[u - 0xA800u + indic_offset_0xa800u];
if (hb_in_range (u, 0xABC0u, 0xAC00u)) return indic_table[u - 0xABC0u + indic_offset_0xabc0u];
if (hb_in_range (u, 0xA800u, 0xAAF7u)) return indic_table[u - 0xA800u + indic_offset_0xa800u];
if (hb_in_range (u, 0xABC0u, 0xABFFu)) return indic_table[u - 0xABC0u + indic_offset_0xabc0u];
break;
case 0x10u:
if (hb_in_range (u, 0x10A00u, 0x10A48u)) return indic_table[u - 0x10A00u + indic_offset_0x10a00u];
if (hb_in_range (u, 0x10A00u, 0x10A47u)) return indic_table[u - 0x10A00u + indic_offset_0x10a00u];
break;
case 0x11u:
if (hb_in_range (u, 0x11000u, 0x110C0u)) return indic_table[u - 0x11000u + indic_offset_0x11000u];
if (hb_in_range (u, 0x11100u, 0x11238u)) return indic_table[u - 0x11100u + indic_offset_0x11100u];
if (hb_in_range (u, 0x112B0u, 0x11378u)) return indic_table[u - 0x112B0u + indic_offset_0x112b0u];
if (hb_in_range (u, 0x11480u, 0x114E0u)) return indic_table[u - 0x11480u + indic_offset_0x11480u];
if (hb_in_range (u, 0x11580u, 0x115C8u)) return indic_table[u - 0x11580u + indic_offset_0x11580u];
if (hb_in_range (u, 0x11600u, 0x116D0u)) return indic_table[u - 0x11600u + indic_offset_0x11600u];
if (hb_in_range (u, 0x11000u, 0x110BFu)) return indic_table[u - 0x11000u + indic_offset_0x11000u];
if (hb_in_range (u, 0x11100u, 0x11237u)) return indic_table[u - 0x11100u + indic_offset_0x11100u];
if (hb_in_range (u, 0x112B0u, 0x11377u)) return indic_table[u - 0x112B0u + indic_offset_0x112b0u];
if (hb_in_range (u, 0x11480u, 0x114DFu)) return indic_table[u - 0x11480u + indic_offset_0x11480u];
if (hb_in_range (u, 0x11580u, 0x115C7u)) return indic_table[u - 0x11580u + indic_offset_0x11580u];
if (hb_in_range (u, 0x11600u, 0x116CFu)) return indic_table[u - 0x11600u + indic_offset_0x11600u];
break;
default:

View File

@ -921,14 +921,32 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
info[start].indic_position() = POS_RA_TO_BECOME_REPH;
/* For old-style Indic script tags, move the first post-base Halant after
* last consonant. Only do this if there is *not* a Halant after last
* consonant. Otherwise it becomes messy. */
if (indic_plan->is_old_spec) {
* last consonant.
*
* Reports suggest that in some scripts Uniscribe does this only if there
* is *not* a Halant after last consonant already (eg. Kannada), while it
* does it unconditionally in other scripts (eg. Malayalam). We don't
* currently know about other scripts, so we single out Malayalam for now.
*
* Kannada test case:
* U+0C9A,U+0CCD,U+0C9A,U+0CCD
* With some versions of Lohit Kannada.
* https://bugs.freedesktop.org/show_bug.cgi?id=59118
*
* Malayalam test case:
* U+0D38,U+0D4D,U+0D31,U+0D4D,U+0D31,U+0D4D
* With lohit-ttf-20121122/Lohit-Malayalam.ttf
*/
if (indic_plan->is_old_spec)
{
bool disallow_double_halants = buffer->props.script != HB_SCRIPT_MALAYALAM;
for (unsigned int i = base + 1; i < end; i++)
if (info[i].indic_category() == OT_H) {
if (info[i].indic_category() == OT_H)
{
unsigned int j;
for (j = end - 1; j > i; j--)
if (is_consonant (info[j]) || info[j].indic_category() == OT_H)
if (is_consonant (info[j]) ||
(disallow_double_halants && info[j].indic_category() == OT_H))
break;
if (info[j].indic_category() != OT_H && j > i) {
/* Move Halant to after last consonant. */
@ -1267,6 +1285,7 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED,
info.cluster = buffer->cur().cluster;
info.mask = buffer->cur().mask;
info.syllable() = buffer->cur().syllable();
/* TODO Set glyph_props? */
/* Insert dottedcircle after possible Repha. */
while (buffer->idx < buffer->len &&

View File

@ -536,6 +536,24 @@ final_reordering (const hb_ot_shape_plan_t *plan,
}
/* Uniscribe seems to have a shaper for 'mymr' that is like the
* generic shaper, except that it zeros mark advances GDEF_LATE. */
const hb_ot_complex_shaper_t _hb_ot_complex_shaper_myanmar_old =
{
"default",
NULL, /* collect_features */
NULL, /* override_features */
NULL, /* data_create */
NULL, /* data_destroy */
NULL, /* preprocess_text */
HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
NULL, /* decompose */
NULL, /* compose */
NULL, /* setup_masks */
HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
true, /* fallback_position */
};
const hb_ot_complex_shaper_t _hb_ot_complex_shaper_myanmar =
{
"myanmar",

View File

@ -56,6 +56,7 @@ enum hb_ot_shape_zero_width_marks_type_t {
HB_COMPLEX_SHAPER_IMPLEMENT (arabic) \
HB_COMPLEX_SHAPER_IMPLEMENT (hangul) \
HB_COMPLEX_SHAPER_IMPLEMENT (hebrew) \
HB_COMPLEX_SHAPER_IMPLEMENT (myanmar_old) \
HB_COMPLEX_SHAPER_IMPLEMENT (indic) \
HB_COMPLEX_SHAPER_IMPLEMENT (myanmar) \
HB_COMPLEX_SHAPER_IMPLEMENT (sea) \
@ -258,6 +259,7 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner)
/* Unicode-4.1 additions */
case HB_SCRIPT_KHAROSHTHI:
case HB_SCRIPT_NEW_TAI_LUE:
case HB_SCRIPT_SYLOTI_NAGRI:
/* Unicode-5.1 additions */
@ -329,16 +331,15 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner)
return &_hb_ot_complex_shaper_default;
case HB_SCRIPT_MYANMAR:
/* For Myanmar, we only want to use the Myanmar shaper if the "new" script
* tag is found. For "old" script tag we want to use the default shaper. */
if (planner->map.chosen_script[0] == HB_TAG ('m','y','m','2'))
return &_hb_ot_complex_shaper_myanmar;
else if (planner->map.chosen_script[0] == HB_TAG ('m','y','m','r'))
return &_hb_ot_complex_shaper_myanmar_old;
else
return &_hb_ot_complex_shaper_default;
/* Unicode-4.1 additions */
case HB_SCRIPT_BUGINESE:
case HB_SCRIPT_NEW_TAI_LUE:
/* Unicode-5.1 additions */
case HB_SCRIPT_CHAM:

View File

@ -415,6 +415,8 @@ _hb_ot_shape_fallback_position (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer)
{
_hb_buffer_assert_gsubgpos_vars (buffer);
unsigned int start = 0;
unsigned int last_cluster = buffer->info[0].cluster;
unsigned int count = buffer->len;

View File

@ -289,6 +289,8 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan,
hb_buffer_t *buffer,
hb_font_t *font)
{
_hb_buffer_assert_unicode_vars (buffer);
hb_ot_shape_normalization_mode_t mode = plan->shaper->normalization_preference;
const hb_ot_shape_normalize_context_t c = {
plan,

View File

@ -43,7 +43,6 @@
static hb_tag_t common_features[] = {
HB_TAG('c','c','m','p'),
HB_TAG('l','i','g','a'),
HB_TAG('l','o','c','l'),
HB_TAG('m','a','r','k'),
HB_TAG('m','k','m','k'),
@ -56,6 +55,7 @@ static hb_tag_t horizontal_features[] = {
HB_TAG('c','l','i','g'),
HB_TAG('c','u','r','s'),
HB_TAG('k','e','r','n'),
HB_TAG('l','i','g','a'),
HB_TAG('r','c','l','t'),
};
@ -236,6 +236,7 @@ static void
hb_insert_dotted_circle (hb_buffer_t *buffer, hb_font_t *font)
{
if (!(buffer->flags & HB_BUFFER_FLAG_BOT) ||
buffer->context_len[0] ||
_hb_glyph_info_get_general_category (&buffer->info[0]) !=
HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
return;
@ -243,7 +244,7 @@ hb_insert_dotted_circle (hb_buffer_t *buffer, hb_font_t *font)
if (!font->has_glyph (0x25CCu))
return;
hb_glyph_info_t dottedcircle;
hb_glyph_info_t dottedcircle = {0};
dottedcircle.codepoint = 0x25CCu;
_hb_glyph_info_set_unicode_props (&dottedcircle, buffer->unicode);
@ -447,6 +448,7 @@ hb_ot_substitute_complex (hb_ot_shape_context_t *c)
{
hb_buffer_t *buffer = c->buffer;
_hb_buffer_allocate_gsubgpos_vars (buffer);
hb_ot_layout_substitute_start (c->font, buffer);
if (!hb_ot_layout_has_glyph_classes (c->face))
@ -635,6 +637,8 @@ hb_ot_position (hb_ot_shape_context_t *c)
if (fallback)
_hb_ot_shape_fallback_kern (c->plan, c->font, c->buffer);
_hb_buffer_deallocate_gsubgpos_vars (c->buffer);
}

View File

@ -87,7 +87,7 @@
#endif
#ifndef HB_INTERNAL
# ifndef __MINGW32__
# if !defined(__MINGW32__) && !defined(__CYGWIN__)
# define HB_INTERNAL __attribute__((__visibility__("hidden")))
# else
# define HB_INTERNAL
@ -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
@ -116,15 +118,56 @@
#define HB_FUNC __func__
#endif
// Take from https://github.com/behdad/harfbuzz/commit/26a963b9cb4af3119177f277a2d48a5d537458fb
#if defined(_WIN32_WCE)
#if defined(_WIN32) || defined(__CYGWIN__)
/* We need Windows Vista for both Uniscribe backend and for
* MemoryBarrier. We don't support compiling on Windows XP,
* though we run on it fine. */
# if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0600
# undef _WIN32_WINNT
# endif
# ifndef _WIN32_WINNT
# define _WIN32_WINNT 0x0600
# endif
# 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? */
#elif defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP)
#define getenv(Name) NULL
#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 */
@ -280,7 +323,7 @@ typedef int (*hb_compare_func_t) (const void *, const void *);
/* arrays and maps */
#define HB_PREALLOCED_ARRAY_INIT {0}
#define HB_PREALLOCED_ARRAY_INIT {0, 0, NULL}
template <typename Type, unsigned int StaticSize=16>
struct hb_prealloced_array_t
{
@ -496,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)
@ -581,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,
@ -704,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> {
@ -811,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
@ -835,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))
@ -868,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);
@ -897,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));

View File

@ -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) {

View File

@ -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);
}

View File

@ -34,15 +34,15 @@
#include "hb-font-private.hh"
static void
static bool
parse_space (const char **pp, const char *end)
{
char c;
while (*pp < end && (c = **pp, ISSPACE (c)))
while (*pp < end && ISSPACE (**pp))
(*pp)++;
return true;
}
static hb_bool_t
static bool
parse_char (const char **pp, const char *end, char c)
{
parse_space (pp, end);
@ -54,7 +54,7 @@ parse_char (const char **pp, const char *end, char c)
return true;
}
static hb_bool_t
static bool
parse_uint (const char **pp, const char *end, unsigned int *pv)
{
char buf[32];
@ -78,7 +78,27 @@ parse_uint (const char **pp, const char *end, unsigned int *pv)
return true;
}
static hb_bool_t
static bool
parse_bool (const char **pp, const char *end, unsigned int *pv)
{
parse_space (pp, end);
const char *p = *pp;
while (*pp < end && ISALPHA(**pp))
(*pp)++;
/* CSS allows on/off as aliases 1/0. */
if (*pp - p == 2 || 0 == strncmp (p, "on", 2))
*pv = 1;
else if (*pp - p == 3 || 0 == strncmp (p, "off", 2))
*pv = 0;
else
return false;
return true;
}
static bool
parse_feature_value_prefix (const char **pp, const char *end, hb_feature_t *feature)
{
if (parse_char (pp, end, '-'))
@ -91,32 +111,48 @@ parse_feature_value_prefix (const char **pp, const char *end, hb_feature_t *feat
return true;
}
static hb_bool_t
static bool
parse_feature_tag (const char **pp, const char *end, hb_feature_t *feature)
{
const char *p = *pp;
char c;
parse_space (pp, end);
#define ISALNUM(c) (('a' <= (c) && (c) <= 'z') || ('A' <= (c) && (c) <= 'Z') || ('0' <= (c) && (c) <= '9'))
while (*pp < end && (c = **pp, ISALNUM(c)))
(*pp)++;
#undef ISALNUM
char quote = 0;
if (p == *pp)
if (*pp < end && (**pp == '\'' || **pp == '"'))
{
quote = **pp;
(*pp)++;
}
const char *p = *pp;
while (*pp < end && ISALNUM(**pp))
(*pp)++;
if (p == *pp || *pp - p > 4)
return false;
feature->tag = hb_tag_from_string (p, *pp - p);
if (quote)
{
/* CSS expects exactly four bytes. And we only allow quotations for
* CSS compatibility. So, enforce the length. */
if (*pp - p != 4)
return false;
if (*pp == end || **pp != quote)
return false;
(*pp)++;
}
return true;
}
static hb_bool_t
static bool
parse_feature_indices (const char **pp, const char *end, hb_feature_t *feature)
{
parse_space (pp, end);
hb_bool_t has_start;
bool has_start;
feature->start = 0;
feature->end = (unsigned int) -1;
@ -136,20 +172,27 @@ parse_feature_indices (const char **pp, const char *end, hb_feature_t *feature)
return parse_char (pp, end, ']');
}
static hb_bool_t
static bool
parse_feature_value_postfix (const char **pp, const char *end, hb_feature_t *feature)
{
return !parse_char (pp, end, '=') || parse_uint (pp, end, &feature->value);
bool had_equal = parse_char (pp, end, '=');
bool had_value = parse_uint (pp, end, &feature->value) ||
parse_bool (pp, end, &feature->value);
/* CSS doesn't use equal-sign between tag and value.
* If there was an equal-sign, then there *must* be a value.
* A value without an eqaul-sign is ok, but not required. */
return !had_equal || had_value;
}
static hb_bool_t
static bool
parse_one_feature (const char **pp, const char *end, hb_feature_t *feature)
{
return parse_feature_value_prefix (pp, end, feature) &&
parse_feature_tag (pp, end, feature) &&
parse_feature_indices (pp, end, feature) &&
parse_feature_value_postfix (pp, end, feature) &&
parse_space (pp, end) &&
*pp == end;
}
@ -157,7 +200,7 @@ parse_one_feature (const char **pp, const char *end, hb_feature_t *feature)
* hb_feature_from_string:
* @str: (array length=len):
* @len:
* @feature: (out):
* @feature: (out) (optional):
*
*
*
@ -169,10 +212,21 @@ hb_bool_t
hb_feature_from_string (const char *str, int len,
hb_feature_t *feature)
{
hb_feature_t feat;
if (len < 0)
len = strlen (str);
return parse_one_feature (&str, str + len, feature);
if (likely (parse_one_feature (&str, str + len, &feat)))
{
if (feature)
*feature = feat;
return true;
}
if (feature)
memset (feature, 0, sizeof (*feature));
return false;
}
/**
@ -203,18 +257,18 @@ hb_feature_to_string (hb_feature_t *feature,
{
s[len++] = '[';
if (feature->start)
len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%d", feature->start));
len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->start));
if (feature->end != feature->start + 1) {
s[len++] = ':';
if (feature->end != (unsigned int) -1)
len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%d", feature->end));
len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->end));
}
s[len++] = ']';
}
if (feature->value > 1)
{
s[len++] = '=';
len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%d", feature->value));
len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->value));
}
assert (len < ARRAY_LENGTH (s));
len = MIN (len, size - 1);
@ -225,11 +279,13 @@ hb_feature_to_string (hb_feature_t *feature,
static const char **static_shaper_list;
static inline
#ifdef HB_USE_ATEXIT
static
void free_static_shaper_list (void)
{
free (static_shaper_list);
}
#endif
/**
* hb_shape_list_shapers:
@ -266,7 +322,7 @@ retry:
goto retry;
}
#ifdef HAVE_ATEXIT
#ifdef HB_USE_ATEXIT
atexit (free_static_shaper_list); /* First person registers atexit() callback. */
#endif
}

View File

@ -40,12 +40,14 @@ static const hb_shaper_pair_t all_shapers[] = {
static const hb_shaper_pair_t *static_shapers;
static inline
#ifdef HB_USE_ATEXIT
static
void free_static_shapers (void)
{
if (unlikely (static_shapers != all_shapers))
free ((void *) static_shapers);
}
#endif
const hb_shaper_pair_t *
_hb_shapers_get (void)
@ -100,7 +102,7 @@ retry:
goto retry;
}
#ifdef HAVE_ATEXIT
#ifdef HB_USE_ATEXIT
atexit (free_static_shapers); /* First person registers atexit() callback. */
#endif
}

View File

@ -157,7 +157,7 @@ hb_unicode_funcs_get_default (void)
/**
* hb_unicode_funcs_create: (Xconstructor)
* @parent: (allow-none):
* @parent: (nullable):
*
*
*
@ -310,7 +310,7 @@ hb_unicode_funcs_get_user_data (hb_unicode_funcs_t *ufuncs,
void
hb_unicode_funcs_make_immutable (hb_unicode_funcs_t *ufuncs)
{
if (hb_object_is_inert (ufuncs))
if (unlikely (hb_object_is_inert (ufuncs)))
return;
ufuncs->immutable = true;

View File

@ -38,9 +38,9 @@ HB_BEGIN_DECLS
#define HB_VERSION_MAJOR 0
#define HB_VERSION_MINOR 9
#define HB_VERSION_MICRO 32
#define HB_VERSION_MICRO 38
#define HB_VERSION_STRING "0.9.32"
#define HB_VERSION_STRING "0.9.38"
#define HB_VERSION_ATLEAST(major,minor,micro) \
((major)*10000+(minor)*100+(micro) <= \