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:
parent
3c1e16df75
commit
3de9bc9cb1
135
src/3rdparty/harfbuzz-ng/NEWS
vendored
135
src/3rdparty/harfbuzz-ng/NEWS
vendored
@ -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
|
||||
=====================================
|
||||
|
3
src/3rdparty/harfbuzz-ng/README
vendored
3
src/3rdparty/harfbuzz-ng/README
vendored
@ -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:
|
||||
|
1
src/3rdparty/harfbuzz-ng/harfbuzz-ng.pro
vendored
1
src/3rdparty/harfbuzz-ng/harfbuzz-ng.pro
vendored
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
9
src/3rdparty/harfbuzz-ng/src/hb-blob.cc
vendored
9
src/3rdparty/harfbuzz-ng/src/hb-blob.cc
vendored
@ -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 ();
|
||||
|
@ -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"
|
||||
{
|
||||
|
@ -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);
|
||||
|
||||
|
6
src/3rdparty/harfbuzz-ng/src/hb-buffer.cc
vendored
6
src/3rdparty/harfbuzz-ng/src/hb-buffer.cc
vendored
@ -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:
|
||||
|
12
src/3rdparty/harfbuzz-ng/src/hb-common.cc
vendored
12
src/3rdparty/harfbuzz-ng/src/hb-common.cc
vendored
@ -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;
|
||||
|
22
src/3rdparty/harfbuzz-ng/src/hb-common.h
vendored
22
src/3rdparty/harfbuzz-ng/src/hb-common.h
vendored
@ -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);
|
||||
|
@ -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);
|
||||
|
8
src/3rdparty/harfbuzz-ng/src/hb-face.cc
vendored
8
src/3rdparty/harfbuzz-ng/src/hb-face.cc
vendored
@ -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;
|
||||
|
4
src/3rdparty/harfbuzz-ng/src/hb-font.cc
vendored
4
src/3rdparty/harfbuzz-ng/src/hb-font.cc
vendored
@ -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;
|
||||
|
13
src/3rdparty/harfbuzz-ng/src/hb-mutex-private.hh
vendored
13
src/3rdparty/harfbuzz-ng/src/hb-mutex-private.hh
vendored
@ -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)
|
||||
|
107
src/3rdparty/harfbuzz-ng/src/hb-object-private.hh
vendored
107
src/3rdparty/harfbuzz-ng/src/hb-object-private.hh
vendored
@ -68,8 +68,6 @@ struct hb_reference_count_t
|
||||
#define HB_USER_DATA_ARRAY_INIT {HB_MUTEX_INIT, HB_LOCKABLE_SET_INIT}
|
||||
struct hb_user_data_array_t
|
||||
{
|
||||
/* TODO Add tracing. */
|
||||
|
||||
struct hb_user_data_item_t {
|
||||
hb_user_data_key_t *key;
|
||||
void *data;
|
||||
@ -106,69 +104,6 @@ struct hb_object_header_t
|
||||
|
||||
#define HB_OBJECT_HEADER_STATIC {HB_REFERENCE_COUNT_INVALID, HB_USER_DATA_ARRAY_INIT}
|
||||
|
||||
static inline void *create (unsigned int size) {
|
||||
hb_object_header_t *obj = (hb_object_header_t *) calloc (1, size);
|
||||
|
||||
if (likely (obj))
|
||||
obj->init ();
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
inline void init (void) {
|
||||
ref_count.init (1);
|
||||
user_data.init ();
|
||||
}
|
||||
|
||||
inline bool is_inert (void) const {
|
||||
return unlikely (ref_count.is_invalid ());
|
||||
}
|
||||
|
||||
inline void reference (void) {
|
||||
if (unlikely (!this || this->is_inert ()))
|
||||
return;
|
||||
ref_count.inc ();
|
||||
}
|
||||
|
||||
inline bool destroy (void) {
|
||||
if (unlikely (!this || this->is_inert ()))
|
||||
return false;
|
||||
if (ref_count.dec () != 1)
|
||||
return false;
|
||||
|
||||
ref_count.finish (); /* Do this before user_data */
|
||||
user_data.finish ();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool set_user_data (hb_user_data_key_t *key,
|
||||
void * data,
|
||||
hb_destroy_func_t destroy_func,
|
||||
hb_bool_t replace) {
|
||||
if (unlikely (!this || this->is_inert ()))
|
||||
return false;
|
||||
|
||||
return user_data.set (key, data, destroy_func, replace);
|
||||
}
|
||||
|
||||
inline void *get_user_data (hb_user_data_key_t *key) {
|
||||
if (unlikely (!this || this->is_inert ()))
|
||||
return NULL;
|
||||
|
||||
return user_data.get (key);
|
||||
}
|
||||
|
||||
inline void trace (const char *function) const {
|
||||
if (unlikely (!this)) return;
|
||||
/* TODO We cannot use DEBUG_MSG_FUNC here since that one currently only
|
||||
* prints the class name and throws away the template info. */
|
||||
DEBUG_MSG (OBJECT, (void *) this,
|
||||
"%s refcount=%d",
|
||||
function,
|
||||
this ? ref_count.ref_count : 0);
|
||||
}
|
||||
|
||||
private:
|
||||
ASSERT_POD ();
|
||||
};
|
||||
@ -179,32 +114,56 @@ struct hb_object_header_t
|
||||
template <typename Type>
|
||||
static inline void hb_object_trace (const Type *obj, const char *function)
|
||||
{
|
||||
obj->header.trace (function);
|
||||
DEBUG_MSG (OBJECT, (void *) obj,
|
||||
"%s refcount=%d",
|
||||
function,
|
||||
obj ? obj->header.ref_count.ref_count : 0);
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
static inline Type *hb_object_create (void)
|
||||
{
|
||||
Type *obj = (Type *) hb_object_header_t::create (sizeof (Type));
|
||||
Type *obj = (Type *) calloc (1, sizeof (Type));
|
||||
|
||||
if (unlikely (!obj))
|
||||
return obj;
|
||||
|
||||
hb_object_init (obj);
|
||||
hb_object_trace (obj, HB_FUNC);
|
||||
return obj;
|
||||
}
|
||||
template <typename Type>
|
||||
static inline void hb_object_init (Type *obj)
|
||||
{
|
||||
obj->header.ref_count.init (1);
|
||||
obj->header.user_data.init ();
|
||||
}
|
||||
template <typename Type>
|
||||
static inline bool hb_object_is_inert (const Type *obj)
|
||||
{
|
||||
return unlikely (obj->header.is_inert ());
|
||||
return unlikely (obj->header.ref_count.is_invalid ());
|
||||
}
|
||||
template <typename Type>
|
||||
static inline Type *hb_object_reference (Type *obj)
|
||||
{
|
||||
hb_object_trace (obj, HB_FUNC);
|
||||
obj->header.reference ();
|
||||
if (unlikely (!obj || hb_object_is_inert (obj)))
|
||||
return obj;
|
||||
obj->header.ref_count.inc ();
|
||||
return obj;
|
||||
}
|
||||
template <typename Type>
|
||||
static inline bool hb_object_destroy (Type *obj)
|
||||
{
|
||||
hb_object_trace (obj, HB_FUNC);
|
||||
return obj->header.destroy ();
|
||||
if (unlikely (!obj || hb_object_is_inert (obj)))
|
||||
return false;
|
||||
if (obj->header.ref_count.dec () != 1)
|
||||
return false;
|
||||
|
||||
obj->header.ref_count.finish (); /* Do this before user_data */
|
||||
obj->header.user_data.finish ();
|
||||
return true;
|
||||
}
|
||||
template <typename Type>
|
||||
static inline bool hb_object_set_user_data (Type *obj,
|
||||
@ -213,14 +172,18 @@ static inline bool hb_object_set_user_data (Type *obj,
|
||||
hb_destroy_func_t destroy,
|
||||
hb_bool_t replace)
|
||||
{
|
||||
return obj->header.set_user_data (key, data, destroy, replace);
|
||||
if (unlikely (!obj || hb_object_is_inert (obj)))
|
||||
return false;
|
||||
return obj->header.user_data.set (key, data, destroy, replace);
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
static inline void *hb_object_get_user_data (Type *obj,
|
||||
hb_user_data_key_t *key)
|
||||
{
|
||||
return obj->header.get_user_data (key);
|
||||
if (unlikely (!obj || hb_object_is_inert (obj)))
|
||||
return NULL;
|
||||
return obj->header.user_data.get (key);
|
||||
}
|
||||
|
||||
|
||||
|
@ -197,6 +197,8 @@ struct TTCHeader
|
||||
|
||||
struct OpenTypeFontFile
|
||||
{
|
||||
static const hb_tag_t tableTag = HB_TAG ('_','_','_','_'); /* Sanitizer needs this. */
|
||||
|
||||
static const hb_tag_t CFFTag = HB_TAG ('O','T','T','O'); /* OpenType with Postscript outlines */
|
||||
static const hb_tag_t TrueTypeTag = HB_TAG ( 0 , 1 , 0 , 0 ); /* OpenType with TrueType outlines */
|
||||
static const hb_tag_t TTCTag = HB_TAG ('t','t','c','f'); /* TrueType Collection */
|
||||
|
124
src/3rdparty/harfbuzz-ng/src/hb-open-type-private.hh
vendored
124
src/3rdparty/harfbuzz-ng/src/hb-open-type-private.hh
vendored
@ -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>
|
||||
|
205
src/3rdparty/harfbuzz-ng/src/hb-ot-font.cc
vendored
205
src/3rdparty/harfbuzz-ng/src/hb-ot-font.cc
vendored
@ -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;
|
||||
}
|
||||
|
||||
|
65
src/3rdparty/harfbuzz-ng/src/hb-ot-hhea-table.hh
vendored
65
src/3rdparty/harfbuzz-ng/src/hb-ot-hhea-table.hh
vendored
@ -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 */
|
||||
|
||||
|
37
src/3rdparty/harfbuzz-ng/src/hb-ot-hmtx-table.hh
vendored
37
src/3rdparty/harfbuzz-ng/src/hb-ot-hmtx-table.hh
vendored
@ -35,22 +35,27 @@ namespace OT {
|
||||
|
||||
/*
|
||||
* hmtx -- The Horizontal Metrics Table
|
||||
* vmtx -- The Vertical Metrics Table
|
||||
*/
|
||||
|
||||
#define HB_OT_TAG_hmtx HB_TAG('h','m','t','x')
|
||||
#define HB_OT_TAG_vmtx HB_TAG('v','m','t','x')
|
||||
|
||||
|
||||
struct LongHorMetric
|
||||
struct LongMetric
|
||||
{
|
||||
USHORT advanceWidth;
|
||||
SHORT lsb;
|
||||
USHORT advance; /* Advance width/height. */
|
||||
SHORT lsb; /* Leading (left/top) side bearing. */
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (4);
|
||||
};
|
||||
|
||||
struct hmtx
|
||||
struct _mtx
|
||||
{
|
||||
static const hb_tag_t tableTag = HB_OT_TAG_hmtx;
|
||||
static const hb_tag_t tableTag = HB_TAG('_','m','t','x');
|
||||
|
||||
static const hb_tag_t hmtxTag = HB_OT_TAG_hmtx;
|
||||
static const hb_tag_t vmtxTag = HB_OT_TAG_vmtx;
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c) {
|
||||
TRACE_SANITIZE (this);
|
||||
@ -60,7 +65,7 @@ struct hmtx
|
||||
}
|
||||
|
||||
public:
|
||||
LongHorMetric longHorMetric[VAR]; /* Paired advance width and left side
|
||||
LongMetric longMetric[VAR]; /* Paired advance width and leading
|
||||
* bearing values for each glyph. The
|
||||
* value numOfHMetrics comes from
|
||||
* the 'hhea' table. If the font is
|
||||
@ -68,23 +73,29 @@ struct hmtx
|
||||
* be in the array, but that entry is
|
||||
* required. The last entry applies to
|
||||
* all subsequent glyphs. */
|
||||
SHORT leftSideBearingX[VAR]; /* Here the advanceWidth is assumed
|
||||
* to be the same as the advanceWidth
|
||||
SHORT leadingBearingX[VAR]; /* Here the advance is assumed
|
||||
* to be the same as the advance
|
||||
* for the last entry above. The
|
||||
* number of entries in this array is
|
||||
* derived from numGlyphs (from 'maxp'
|
||||
* table) minus numberOfHMetrics. This
|
||||
* generally is used with a run of
|
||||
* monospaced glyphs (e.g., Kanji
|
||||
* table) minus numberOfLongMetrics.
|
||||
* This generally is used with a run
|
||||
* of monospaced glyphs (e.g., Kanji
|
||||
* fonts or Courier fonts). Only one
|
||||
* run is allowed and it must be at
|
||||
* the end. This allows a monospaced
|
||||
* font to vary the left side bearing
|
||||
* font to vary the side bearing
|
||||
* values for each glyph. */
|
||||
public:
|
||||
DEFINE_SIZE_ARRAY2 (0, longHorMetric, leftSideBearingX);
|
||||
DEFINE_SIZE_ARRAY2 (0, longMetric, leadingBearingX);
|
||||
};
|
||||
|
||||
struct hmtx : _mtx {
|
||||
static const hb_tag_t tableTag = HB_OT_TAG_hmtx;
|
||||
};
|
||||
struct vmtx : _mtx {
|
||||
static const hb_tag_t tableTag = HB_OT_TAG_vmtx;
|
||||
};
|
||||
|
||||
} /* namespace OT */
|
||||
|
||||
|
@ -345,8 +345,8 @@ struct AnchorMatrix
|
||||
inline const Anchor& get_anchor (unsigned int row, unsigned int col, unsigned int cols, bool *found) const {
|
||||
*found = false;
|
||||
if (unlikely (row >= rows || col >= cols)) return Null(Anchor);
|
||||
*found = !matrix[row * cols + col].is_null ();
|
||||
return this+matrix[row * cols + col];
|
||||
*found = !matrixZ[row * cols + col].is_null ();
|
||||
return this+matrixZ[row * cols + col];
|
||||
}
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c, unsigned int cols) {
|
||||
@ -354,19 +354,19 @@ struct AnchorMatrix
|
||||
if (!c->check_struct (this)) return TRACE_RETURN (false);
|
||||
if (unlikely (rows > 0 && cols >= ((unsigned int) -1) / rows)) return TRACE_RETURN (false);
|
||||
unsigned int count = rows * cols;
|
||||
if (!c->check_array (matrix, matrix[0].static_size, count)) return TRACE_RETURN (false);
|
||||
if (!c->check_array (matrixZ, matrixZ[0].static_size, count)) return TRACE_RETURN (false);
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
if (!matrix[i].sanitize (c, this)) return TRACE_RETURN (false);
|
||||
if (!matrixZ[i].sanitize (c, this)) return TRACE_RETURN (false);
|
||||
return TRACE_RETURN (true);
|
||||
}
|
||||
|
||||
USHORT rows; /* Number of rows */
|
||||
protected:
|
||||
OffsetTo<Anchor>
|
||||
matrix[VAR]; /* Matrix of offsets to Anchor tables--
|
||||
matrixZ[VAR]; /* Matrix of offsets to Anchor tables--
|
||||
* from beginning of AnchorMatrix table */
|
||||
public:
|
||||
DEFINE_SIZE_ARRAY (2, matrix);
|
||||
DEFINE_SIZE_ARRAY (2, matrixZ);
|
||||
};
|
||||
|
||||
|
||||
@ -530,7 +530,7 @@ struct SinglePos
|
||||
template <typename context_t>
|
||||
inline typename context_t::return_t dispatch (context_t *c) const
|
||||
{
|
||||
TRACE_DISPATCH (this);
|
||||
TRACE_DISPATCH (this, u.format);
|
||||
switch (u.format) {
|
||||
case 1: return TRACE_RETURN (c->dispatch (u.format1));
|
||||
case 2: return TRACE_RETURN (c->dispatch (u.format2));
|
||||
@ -583,7 +583,7 @@ struct PairSet
|
||||
unsigned int len2 = valueFormats[1].get_len ();
|
||||
unsigned int record_size = USHORT::static_size * (1 + len1 + len2);
|
||||
|
||||
const PairValueRecord *record = CastP<PairValueRecord> (array);
|
||||
const PairValueRecord *record = CastP<PairValueRecord> (arrayZ);
|
||||
unsigned int count = len;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
@ -602,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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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));
|
||||
|
@ -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
|
||||
|
4
src/3rdparty/harfbuzz-ng/src/hb-ot-layout.cc
vendored
4
src/3rdparty/harfbuzz-ng/src/hb-ot-layout.cc
vendored
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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
@ -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:
|
||||
|
@ -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 &&
|
||||
|
@ -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",
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
8
src/3rdparty/harfbuzz-ng/src/hb-ot-shape.cc
vendored
8
src/3rdparty/harfbuzz-ng/src/hb-ot-shape.cc
vendored
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
123
src/3rdparty/harfbuzz-ng/src/hb-private.hh
vendored
123
src/3rdparty/harfbuzz-ng/src/hb-private.hh
vendored
@ -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));
|
||||
|
@ -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) {
|
||||
|
53
src/3rdparty/harfbuzz-ng/src/hb-shape-plan.cc
vendored
53
src/3rdparty/harfbuzz-ng/src/hb-shape-plan.cc
vendored
@ -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);
|
||||
}
|
||||
|
110
src/3rdparty/harfbuzz-ng/src/hb-shape.cc
vendored
110
src/3rdparty/harfbuzz-ng/src/hb-shape.cc
vendored
@ -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
|
||||
}
|
||||
|
6
src/3rdparty/harfbuzz-ng/src/hb-shaper.cc
vendored
6
src/3rdparty/harfbuzz-ng/src/hb-shaper.cc
vendored
@ -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
|
||||
}
|
||||
|
4
src/3rdparty/harfbuzz-ng/src/hb-unicode.cc
vendored
4
src/3rdparty/harfbuzz-ng/src/hb-unicode.cc
vendored
@ -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;
|
||||
|
4
src/3rdparty/harfbuzz-ng/src/hb-version.h
vendored
4
src/3rdparty/harfbuzz-ng/src/hb-version.h
vendored
@ -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) <= \
|
||||
|
Loading…
Reference in New Issue
Block a user