Update bundled HarfBuzz-NG copy to 0.9.32

- Unicode 7.0 support
- New shapers
- Multiple improvements in Arabic, Indic, and Hebrew shapers
- Build fixes, optimizations, etc.

Change-Id: I0ba14b619c3e6fb35cddd9d65e694af41197d6ae
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@digia.com>
This commit is contained in:
Konstantin Ritt 2014-07-18 03:13:19 +03:00
parent 0078013693
commit 461c2b2004
67 changed files with 4292 additions and 3399 deletions

View File

@ -41,7 +41,7 @@
#include <harfbuzz/hb.h>
#if ((HB_VERSION_MAJOR*10000 + HB_VERSION_MINOR*100 + HB_VERSION_MICRO) < 912)
#if !HB_VERSION_ATLEAST(0, 9, 31)
# error "This version of harfbuzz is too old."
#endif

View File

@ -4,5 +4,6 @@ Martin Hosken
Jonathan Kew
Lars Knoll
Werner Lemberg
Roozbeh Pournader
Owen Taylor
David Turner

View File

@ -1,3 +1,122 @@
Overview of changes leading to 0.9.32
Thursday, July 17, 2014
=====================================
- Apply Arabic shaping features in spec order exactly.
- Another fix for Mongolian free variation selectors.
- For non-Arabic scripts in Arabic shaper apply 'rlig' and 'calt'
together.
- Minor adjustment to U+FFFD logic.
- Fix hb-coretext build.
Overview of changes leading to 0.9.31
Wednesday, July 16, 2014
=====================================
- Only accept valid UTF-8/16/32; we missed many cases before.
- Better shaping of invalid UTF-8/16/32. Falls back to
U+FFFD REPLACEMENT CHARACTER now.
- With all changes in this release, the buffer will contain fully
valid Unicode after hb_buffer_add_utf8/16/32 no matter how
broken the input is. This can be overriden though. See below.
- Fix Mongolian Variation Selectors for fonts without GDEF.
- Fix minor invalid buffer access.
- Accept zh-Hant and zh-Hans language tags. hb_ot_tag_to_language()
now uses these instead of private tags.
- Build fixes.
- New API:
* hb_buffer_add_codepoints(). This does what hb_buffer_add_utf32()
used to do, ie. no validity check on the input at all. add_utf32
now replaces invalid Unicode codepoints with the replacement
character (see below).
* hb_buffer_set_replacement_codepoint()
* hb_buffer_get_replacement_codepoint()
Previously, in hb_buffer_add_utf8 and hb_buffer_add_utf16, when
we detected broken input, we replaced that with (hb_codepoint_t)-1.
This has changed to use U+FFFD now, but can be changed using these
new API.
Overview of changes leading to 0.9.30
Wednesday, July 9, 2014
=====================================
- Update to Unicode 7.0.0:
* New scripts Manichaean and Psalter Pahlavi are shaped using
Arabic shaper.
* All the other new scripts to through the generic shaper for
now.
- Minor Indic improvements.
- Fix graphite2 backend cluster mapping [crasher!]
- API changes:
* New HB_SCRIPT_* values for Unicode 7.0 scripts.
* New function hb_ot_layout_language_get_required_feature().
- Build fixes.
Overview of changes leading to 0.9.29
Thursday, May 29, 2014
=====================================
- Implement cmap in hb-ot-font.h. No variation-selectors yet.
- Myanmar: Allow MedialYa+Asat.
- Various Indic fixes:
* Support most characters in Extended Devanagary and Vedic
Unicode blocks.
* Allow digits and a some punctuation as consonant placeholders.
- Build fixes.
Overview of changes leading to 0.9.28
Monday, April 28, 2014
=====================================
- Unbreak old-spec Indic shaping. (bug 76705)
- Fix shaping of U+17DD and U+0FC6.
- Add HB_NO_MERGE_CLUSTERS build option. NOT to be enabled by default
for shipping libraries. It's an option for further experimentation
right now. When we are sure how to do it properly, we will add
public run-time API for the functionality.
- Build fixes.
Overview of changes leading to 0.9.27
Tuesday, March 18, 2014
=====================================
- Don't use "register" storage class specifier
- Wrap definition of free_langs() with HAVE_ATEXIT
- Add coretext_aat shaper and hb_coretext_face_create() constructor
- If HAVE_ICU_BUILTIN is defined, use hb-icu Unicode callbacks
- Add Myanmar test case from OpenType Myanmar spec
- Only do fallback Hebrew composition if no GPOS 'mark' available
- Allow bootstrapping without gtk-doc
- Use AM_MISSING_PROG for ragel and git
- Typo in ucdn's Makefile.am
- Improve MemoryBarrier() implementation
Overview of changes leading to 0.9.26
Thursday, January 30, 2014
=====================================
- Misc fixes.
- Fix application of 'rtlm' feature.
- Automatically apply frac/numr/dnom around U+2044 FRACTION SLASH.
- New header: hb-ot-shape.h
- Uniscribe: fix scratch-buffer accounting.
- Reorder Tai Tham SAKOT to after tone-marks.
- Add Hangul shaper.
- New files:
hb-ot-shape-complex-hangul.cc
hb-ot-shape-complex-hebrew.cc
hb-ot-shape-complex-tibetan.cc
- Disable 'cswh' feature in Arabic shaper.
- Coretext: better handle surrogate pairs.
- Add HB_TAG_MAX and _HB_SCRIPT_MAX_VALUE.
Overview of changes leading to 0.9.25
Wednesday, December 4, 2013
=====================================

View File

@ -7,8 +7,7 @@ CONFIG += \
load(qt_helper_lib)
DEFINES += HAVE_CONFIG_H
HEADERS += $$PWD/src/config.h
DEFINES += HAVE_OT HAVE_ATEXIT HB_NO_UNICODE_FUNCS HB_DISABLE_DEPRECATED
INCLUDEPATH += $$PWD/include
@ -39,6 +38,7 @@ HEADERS += \
$$PWD/src/hb-object-private.hh \
$$PWD/src/hb-open-file-private.hh \
$$PWD/src/hb-open-type-private.hh \
$$PWD/src/hb-ot-cmap-table.hh \
$$PWD/src/hb-ot-head-table.hh \
$$PWD/src/hb-ot-hhea-table.hh \
$$PWD/src/hb-ot-hmtx-table.hh \
@ -58,6 +58,7 @@ HEADERS += \
$$PWD/src/hb-blob.h \
$$PWD/src/hb-buffer.h \
$$PWD/src/hb-common.h \
$$PWD/src/hb-deprecated.h \
$$PWD/src/hb-face.h \
$$PWD/src/hb-font.h \
$$PWD/src/hb-set.h \
@ -68,6 +69,7 @@ HEADERS += \
# Open Type
SOURCES += \
$$PWD/src/hb-ot-font.cc \
$$PWD/src/hb-ot-layout.cc \
$$PWD/src/hb-ot-map.cc \
$$PWD/src/hb-ot-shape.cc \
@ -106,6 +108,7 @@ HEADERS += \
HEADERS += \
$$PWD/src/hb-ot.h \
$$PWD/src/hb-ot-font.h \
$$PWD/src/hb-ot-layout.h \
$$PWD/src/hb-ot-shape.h \
$$PWD/src/hb-ot-tag.h

View File

@ -0,0 +1 @@
#include "../../src/hb-ot-font.h"

View File

@ -1,14 +0,0 @@
#ifndef HB_CONFIG_H
#define HB_CONFIG_H
#define HAVE_OT
#define HAVE_ATEXIT
#define HB_NO_UNICODE_FUNCS
#define HB_DISABLE_DEPRECATED
// because strdup() is not part of strict Posix, declare it here
extern "C" char *strdup(const char *src);
#endif /* HB_CONFIG_H */

View File

@ -47,18 +47,22 @@
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#if defined(__MINGW32__) && !defined(MemoryBarrier)
/* MinGW has a convoluted history of supporting MemoryBarrier
* properly. As such, define a function to wrap the whole
* thing. */
static inline void _HBMemoryBarrier (void) {
#if !defined(MemoryBarrier)
long dummy = 0;
InterlockedExchange (&dummy, 1);
}
# define MemoryBarrier _HBMemoryBarrier
#else
MemoryBarrier ();
#endif
}
typedef LONG hb_atomic_int_t;
#define hb_atomic_int_add(AI, V) InterlockedExchangeAdd (&(AI), (V))
#define hb_atomic_ptr_get(P) (MemoryBarrier (), (void *) *(P))
#define hb_atomic_ptr_get(P) (_HBMemoryBarrier (), (void *) *(P))
#define hb_atomic_ptr_cmpexch(P,O,N) (InterlockedCompareExchangePointer ((void **) (P), (void *) (N), (void *) (O)) == (void *) (O))
@ -78,7 +82,7 @@ typedef int32_t hb_atomic_int_t;
#if (MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_4 || __IPHONE_VERSION_MIN_REQUIRED >= 20100)
#define hb_atomic_ptr_cmpexch(P,O,N) OSAtomicCompareAndSwapPtrBarrier ((void *) (O), (void *) (N), (void **) (P))
#else
#if __ppc64__ || __x86_64__ || __arm64__
#if __ppc64__ || __x86_64__ || __aarch64__
#define hb_atomic_ptr_cmpexch(P,O,N) OSAtomicCompareAndSwap64Barrier ((int64_t) (O), (int64_t) (N), (int64_t*) (P))
#else
#define hb_atomic_ptr_cmpexch(P,O,N) OSAtomicCompareAndSwap32Barrier ((int32_t) (O), (int32_t) (N), (int32_t*) (P))

View File

@ -25,7 +25,9 @@
*/
/* http://www.oracle.com/technetwork/articles/servers-storage-dev/standardheaderfiles-453865.html */
#ifndef _POSIX_C_SOURCE
#define _POSIX_C_SOURCE 199309L
#endif
#include "hb-private.hh"

View File

@ -47,14 +47,13 @@ HB_BEGIN_DECLS
* - Use MODE_READONLY otherse, unless you really really
* really know what you are doing,
*
* - MODE_WRITABLE is appropriate if you relaly made a
* - MODE_WRITABLE is appropriate if you really made a
* copy of data solely for the purpose of passing to
* HarfBuzz and doing that just once (no reuse!),
*
* - If the font is mmap()ed, it's ok to use
* READONLY_MAY_MAKE_WRITABLE, however, there were
* design problems with that mode, so HarfBuzz do not
* really use it anymore. If not sure, use MODE_READONLY.
* READONLY_MAY_MAKE_WRITABLE, however, using that mode
* correctly is very tricky. Use MODE_READONLY instead.
*/
typedef enum {
HB_MEMORY_MODE_DUPLICATE,

View File

@ -52,6 +52,7 @@ struct hb_buffer_t {
hb_unicode_funcs_t *unicode; /* Unicode functions */
hb_segment_properties_t props; /* Script, language, direction */
hb_buffer_flags_t flags; /* BOT / EOT / etc. */
hb_codepoint_t replacement; /* U+FFFD or something else. */
/* Buffer contents */

View File

@ -63,7 +63,7 @@ hb_buffer_serialize_format_t
hb_buffer_serialize_format_from_string (const char *str, int len)
{
/* Upper-case it. */
return (hb_buffer_serialize_format_t) (hb_tag_from_string (str, len) & ~0x20202020);
return (hb_buffer_serialize_format_t) (hb_tag_from_string (str, len) & ~0x20202020u);
}
/**

View File

@ -178,6 +178,7 @@ hb_buffer_t::reset (void)
hb_unicode_funcs_destroy (unicode);
unicode = hb_unicode_funcs_get_default ();
replacement = HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT;
clear ();
}
@ -500,6 +501,10 @@ void
hb_buffer_t::merge_clusters (unsigned int start,
unsigned int end)
{
#ifdef HB_NO_MERGE_CLUSTERS
return;
#endif
if (unlikely (end - start < 2))
return;
@ -528,6 +533,10 @@ void
hb_buffer_t::merge_out_clusters (unsigned int start,
unsigned int end)
{
#ifdef HB_NO_MERGE_CLUSTERS
return;
#endif
if (unlikely (end - start < 2))
return;
@ -695,6 +704,7 @@ hb_buffer_get_empty (void)
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,
true, /* in_error */
@ -1039,6 +1049,42 @@ hb_buffer_get_flags (hb_buffer_t *buffer)
}
/**
* hb_buffer_set_replacement_codepoint:
* @buffer: a buffer.
* @replacement:
*
*
*
* Since: 1.0
**/
void
hb_buffer_set_replacement_codepoint (hb_buffer_t *buffer,
hb_codepoint_t replacement)
{
if (unlikely (hb_object_is_inert (buffer)))
return;
buffer->replacement = replacement;
}
/**
* hb_buffer_get_replacement_codepoint:
* @buffer: a buffer.
*
*
*
* Return value:
*
* Since: 1.0
**/
hb_codepoint_t
hb_buffer_get_replacement_codepoint (hb_buffer_t *buffer)
{
return buffer->replacement;
}
/**
* hb_buffer_reset:
* @buffer: a buffer.
@ -1282,7 +1328,7 @@ hb_buffer_guess_segment_properties (hb_buffer_t *buffer)
buffer->guess_segment_properties ();
}
template <typename T>
template <bool validate, typename T>
static inline void
hb_buffer_add_utf (hb_buffer_t *buffer,
const T *text,
@ -1290,6 +1336,9 @@ hb_buffer_add_utf (hb_buffer_t *buffer,
unsigned int item_offset,
int item_length)
{
typedef hb_utf_t<T, true> utf_t;
const hb_codepoint_t replacement = buffer->replacement;
assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE ||
(!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID));
@ -1297,7 +1346,7 @@ hb_buffer_add_utf (hb_buffer_t *buffer,
return;
if (text_length == -1)
text_length = hb_utf_strlen (text);
text_length = utf_t::strlen (text);
if (item_length == -1)
item_length = text_length - item_offset;
@ -1320,7 +1369,7 @@ hb_buffer_add_utf (hb_buffer_t *buffer,
while (start < prev && buffer->context_len[0] < buffer->CONTEXT_LENGTH)
{
hb_codepoint_t u;
prev = hb_utf_prev (prev, start, &u);
prev = utf_t::prev (prev, start, &u, replacement);
buffer->context[0][buffer->context_len[0]++] = u;
}
}
@ -1331,7 +1380,7 @@ hb_buffer_add_utf (hb_buffer_t *buffer,
{
hb_codepoint_t u;
const T *old_next = next;
next = hb_utf_next (next, end, &u);
next = utf_t::next (next, end, &u, replacement);
buffer->add (u, old_next - (const T *) text);
}
@ -1341,7 +1390,7 @@ hb_buffer_add_utf (hb_buffer_t *buffer,
while (next < end && buffer->context_len[1] < buffer->CONTEXT_LENGTH)
{
hb_codepoint_t u;
next = hb_utf_next (next, end, &u);
next = utf_t::next (next, end, &u, replacement);
buffer->context[1][buffer->context_len[1]++] = u;
}
@ -1367,7 +1416,7 @@ hb_buffer_add_utf8 (hb_buffer_t *buffer,
unsigned int item_offset,
int item_length)
{
hb_buffer_add_utf (buffer, (const uint8_t *) text, text_length, item_offset, item_length);
hb_buffer_add_utf<true> (buffer, (const uint8_t *) text, text_length, item_offset, item_length);
}
/**
@ -1389,7 +1438,7 @@ hb_buffer_add_utf16 (hb_buffer_t *buffer,
unsigned int item_offset,
int item_length)
{
hb_buffer_add_utf (buffer, text, text_length, item_offset, item_length);
hb_buffer_add_utf<true> (buffer, text, text_length, item_offset, item_length);
}
/**
@ -1411,7 +1460,29 @@ hb_buffer_add_utf32 (hb_buffer_t *buffer,
unsigned int item_offset,
int item_length)
{
hb_buffer_add_utf (buffer, text, text_length, item_offset, item_length);
hb_buffer_add_utf<true> (buffer, text, text_length, item_offset, item_length);
}
/**
* hb_buffer_add_codepoints:
* @buffer: a buffer.
* @text: (array length=text_length):
* @text_length:
* @item_offset:
* @item_length:
*
*
*
* Since: 1.0
**/
void
hb_buffer_add_codepoints (hb_buffer_t *buffer,
const hb_codepoint_t *text,
int text_length,
unsigned int item_offset,
int item_length)
{
hb_buffer_add_utf<false> (buffer, text, text_length, item_offset, item_length);
}

View File

@ -186,12 +186,25 @@ hb_buffer_flags_t
hb_buffer_get_flags (hb_buffer_t *buffer);
#define HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT 0xFFFDu
/* Sets codepoint used to replace invalid UTF-8/16/32 entries.
* Default is 0xFFFDu. */
void
hb_buffer_set_replacement_codepoint (hb_buffer_t *buffer,
hb_codepoint_t replacement);
hb_codepoint_t
hb_buffer_get_replacement_codepoint (hb_buffer_t *buffer);
/* Resets the buffer. Afterwards it's as if it was just created,
* except that it has a larger buffer allocated perhaps... */
void
hb_buffer_reset (hb_buffer_t *buffer);
/* Like reset, but does NOT clear unicode_funcs. */
/* Like reset, but does NOT clear unicode_funcs and replacement_codepoint. */
void
hb_buffer_clear_contents (hb_buffer_t *buffer);
@ -240,6 +253,14 @@ hb_buffer_add_utf32 (hb_buffer_t *buffer,
unsigned int item_offset,
int item_length);
/* Like add_utf32 but does NOT check for invalid Unicode codepoints. */
void
hb_buffer_add_codepoints (hb_buffer_t *buffer,
const hb_codepoint_t *text,
int text_length,
unsigned int item_offset,
int item_length);
/* Clears any new items added at the end */
hb_bool_t

View File

@ -234,6 +234,7 @@ struct hb_language_item_t {
static hb_language_item_t *langs;
#ifdef HAVE_ATEXIT
static inline
void free_langs (void)
{
@ -244,6 +245,7 @@ void free_langs (void)
langs = next;
}
}
#endif
static hb_language_item_t *
lang_find_or_insert (const char *key)
@ -297,9 +299,11 @@ hb_language_from_string (const char *str, int len)
if (len >= 0)
{
/* NUL-terminate it. */
len = MIN (len, (int) sizeof (strbuf) - 1);
str = (char *) memcpy (strbuf, str, len);
memcpy (strbuf, str, len);
strbuf[len] = '\0';
str = strbuf;
}
hb_language_item_t *item = lang_find_or_insert (str);
@ -367,7 +371,7 @@ hb_script_from_iso15924_tag (hb_tag_t tag)
return HB_SCRIPT_INVALID;
/* Be lenient, adjust case (one capital letter followed by three small letters) */
tag = (tag & 0xDFDFDFDF) | 0x00202020;
tag = (tag & 0xDFDFDFDFu) | 0x00202020u;
switch (tag) {
@ -387,7 +391,7 @@ hb_script_from_iso15924_tag (hb_tag_t tag)
}
/* If it looks right, just use the tag as a script */
if (((uint32_t) tag & 0xE0E0E0E0) == 0x40606060)
if (((uint32_t) tag & 0xE0E0E0E0u) == 0x40606060u)
return (hb_script_t) tag;
/* Otherwise, return unknown */
@ -480,6 +484,14 @@ hb_script_get_horizontal_direction (hb_script_t script)
case HB_SCRIPT_MEROITIC_CURSIVE:
case HB_SCRIPT_MEROITIC_HIEROGLYPHS:
/* Unicode-7.0 additions */
case HB_SCRIPT_MANICHAEAN:
case HB_SCRIPT_MENDE_KIKAKUI:
case HB_SCRIPT_NABATAEAN:
case HB_SCRIPT_OLD_NORTH_ARABIAN:
case HB_SCRIPT_PALMYRENE:
case HB_SCRIPT_PSALTER_PAHLAVI:
return HB_DIRECTION_RTL;
}
@ -557,7 +569,7 @@ hb_version_string (void)
}
/**
* hb_version_check:
* hb_version_atleast:
* @major:
* @minor:
* @micro:
@ -569,9 +581,9 @@ hb_version_string (void)
* Since: 1.0
**/
hb_bool_t
hb_version_check (unsigned int major,
hb_version_atleast (unsigned int major,
unsigned int minor,
unsigned int micro)
{
return HB_VERSION_CHECK (major, minor, micro);
return HB_VERSION_ATLEAST (major, minor, micro);
}

View File

@ -270,17 +270,6 @@ typedef enum
/*6.1*/ HB_SCRIPT_SORA_SOMPENG = HB_TAG ('S','o','r','a'),
/*6.1*/ HB_SCRIPT_TAKRI = HB_TAG ('T','a','k','r'),
/* No script set. */
/*---*/ 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
} hb_script_t;
/* These are moved out of hb_script_t because glib-mkenums chokes otherwise. */
#if 0
/*7.0*/ HB_SCRIPT_BASSA_VAH = HB_TAG ('B','a','s','s'),
/*7.0*/ HB_SCRIPT_CAUCASIAN_ALBANIAN = HB_TAG ('A','g','h','b'),
/*7.0*/ HB_SCRIPT_DUPLOYAN = HB_TAG ('D','u','p','l'),
@ -292,19 +281,27 @@ typedef enum
/*7.0*/ HB_SCRIPT_MAHAJANI = HB_TAG ('M','a','h','j'),
/*7.0*/ HB_SCRIPT_MANICHAEAN = HB_TAG ('M','a','n','i'),
/*7.0*/ HB_SCRIPT_MENDE_KIKAKUI = HB_TAG ('M','e','n','d'),
/*7.0*/ HB_SCRIPT_MODI = ???
/*7.0*/ HB_SCRIPT_MODI = HB_TAG ('M','o','d','i'),
/*7.0*/ HB_SCRIPT_MRO = HB_TAG ('M','r','o','o'),
/*7.0*/ HB_SCRIPT_NABATAEAN = HB_TAG ('N','b','a','t'),
/*7.0*/ HB_SCRIPT_OLD_NORTH_ARABIAN = HB_TAG ('N','a','r','b'),
/*7.0*/ HB_SCRIPT_OLD_PERMIC = HB_TAG ('P','e','r','m'),
/*7.0*/ HB_SCRIPT_PAHAWH_HMONG = HB_TAG ('H','m','n','g'),
/*7.0*/ HB_SCRIPT_PALMYRENE = HB_TAG ('P','a','l','m'),
/*7.0*/ HB_SCRIPT_PAU_CIN_HAU = ???
/*7.0*/ HB_SCRIPT_PAU_CIN_HAU = HB_TAG ('P','a','u','c'),
/*7.0*/ HB_SCRIPT_PSALTER_PAHLAVI = HB_TAG ('P','h','l','p'),
/*7.0*/ HB_SCRIPT_SIDDHAM = ???
/*7.0*/ HB_SCRIPT_SIDDHAM = HB_TAG ('S','i','d','d'),
/*7.0*/ HB_SCRIPT_TIRHUTA = HB_TAG ('T','i','r','h'),
/*7.0*/ HB_SCRIPT_WARANG_CITI = HB_TAG ('W','a','r','a'),
#endif
/* No script set. */
/*---*/ 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
} hb_script_t;
/* Script functions */

View File

@ -31,18 +31,12 @@
#include "hb-coretext.h"
#include "hb-face-private.hh"
#ifndef HB_DEBUG_CORETEXT
#define HB_DEBUG_CORETEXT (HB_DEBUG+0)
#endif
HB_SHAPER_DATA_ENSURE_DECLARE(coretext, face)
HB_SHAPER_DATA_ENSURE_DECLARE(coretext, font)
typedef bool (*qt_get_font_table_func_t) (void *user_data, unsigned int tag, unsigned char *buffer, unsigned int *length);
struct FontEngineFaceData {
@ -56,6 +50,42 @@ struct CoreTextFontEngineData {
};
static void
release_table_data (void *user_data)
{
CFDataRef cf_data = reinterpret_cast<CFDataRef> (user_data);
CFRelease(cf_data);
}
static hb_blob_t *
reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
{
CGFontRef cg_font = reinterpret_cast<CGFontRef> (user_data);
CFDataRef cf_data = CGFontCopyTableForTag (cg_font, tag);
if (unlikely (!cf_data))
return NULL;
const char *data = reinterpret_cast<const char*> (CFDataGetBytePtr (cf_data));
const size_t length = CFDataGetLength (cf_data);
if (!data || !length)
return NULL;
return hb_blob_create (data, length, HB_MEMORY_MODE_READONLY,
reinterpret_cast<void *> (const_cast<__CFData *> (cf_data)),
release_table_data);
}
hb_face_t *
hb_coretext_face_create (CGFontRef cg_font)
{
return hb_face_create_for_tables (reference_table, CGFontRetain (cg_font), (hb_destroy_func_t) CGFontRelease);
}
HB_SHAPER_DATA_ENSURE_DECLARE(coretext, face)
HB_SHAPER_DATA_ENSURE_DECLARE(coretext, font)
/*
* shaper face data
*/
@ -76,31 +106,33 @@ release_data (void *info, const void *data, size_t size)
hb_coretext_shaper_face_data_t *
_hb_coretext_shaper_face_data_create (hb_face_t *face)
{
hb_blob_t *mort_blob = face->reference_table (HB_CORETEXT_TAG_MORT);
/* Umm, we just reference the table to check whether it exists.
* Maybe add better API for this? */
if (!hb_blob_get_length (mort_blob))
{
hb_blob_destroy (mort_blob);
mort_blob = face->reference_table (HB_CORETEXT_TAG_MORX);
if (!hb_blob_get_length (mort_blob))
{
hb_blob_destroy (mort_blob);
return NULL;
}
}
hb_blob_destroy (mort_blob);
hb_coretext_shaper_face_data_t *data = (hb_coretext_shaper_face_data_t *) calloc (1, sizeof (hb_coretext_shaper_face_data_t));
if (unlikely (!data))
return NULL;
#if 0
if (face->destroy == (hb_destroy_func_t) CGFontRelease)
{
data->cg_font = CGFontRetain ((CGFontRef) face->user_data);
}
else
{
hb_blob_t *blob = hb_face_reference_blob (face);
unsigned int blob_length;
const char *blob_data = hb_blob_get_data (blob, &blob_length);
if (unlikely (!blob_length))
DEBUG_MSG (CORETEXT, face, "Face has empty blob");
CGDataProviderRef provider = CGDataProviderCreateWithData (blob, blob_data, blob_length, &release_data);
data->cg_font = CGFontCreateWithDataProvider (provider);
CGDataProviderRelease (provider);
}
#else
FontEngineFaceData *fontEngineFaceData = (FontEngineFaceData *) face->user_data;
CoreTextFontEngineData *coreTextFontEngineData = (CoreTextFontEngineData *) fontEngineFaceData->user_data;
data->cg_font = coreTextFontEngineData->cgFont;
if (likely (data->cg_font))
CFRetain (data->cg_font);
#endif
if (unlikely (!data->cg_font)) {
DEBUG_MSG (CORETEXT, face, "Face CGFontCreateWithDataProvider() failed");
free (data);
@ -144,13 +176,17 @@ _hb_coretext_shaper_font_data_create (hb_font_t *font)
return NULL;
hb_face_t *face = font->face;
#if 0
hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
data->ct_font = CTFontCreateWithGraphicsFont (face_data->cg_font, font->y_scale, NULL, NULL);
#else
FontEngineFaceData *fontEngineFaceData = (FontEngineFaceData *) face->user_data;
CoreTextFontEngineData *coreTextFontEngineData = (CoreTextFontEngineData *) fontEngineFaceData->user_data;
data->ct_font = coreTextFontEngineData->ctFont;
if (likely (data->ct_font))
CFRetain (data->ct_font);
#endif
if (unlikely (!data->ct_font)) {
DEBUG_MSG (CORETEXT, font, "Font CTFontCreateWithGraphicsFont() failed");
free (data);
@ -468,7 +504,7 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
event->start = false;
event->feature = feature;
}
feature_events.sort ();
feature_events.qsort ();
/* Add a strategic final event. */
{
active_feature_t feature;
@ -498,14 +534,12 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
if (unlikely (!range))
goto fail_features;
unsigned int offset = feature_records.len;
if (active_features.len)
{
CFMutableArrayRef features_array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
/* TODO sort and resolve conflicting features? */
/* active_features.sort (); */
/* active_features.qsort (); */
for (unsigned int j = 0; j < active_features.len; j++)
{
CFStringRef keys[2] = {
@ -603,13 +637,13 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
for (unsigned int i = 0; i < buffer->len; i++) {
hb_codepoint_t c = buffer->info[i].codepoint;
buffer->info[i].utf16_index() = chars_len;
if (likely (c < 0x10000))
if (likely (c <= 0xFFFFu))
pchars[chars_len++] = c;
else if (unlikely (c >= 0x110000))
pchars[chars_len++] = 0xFFFD;
else if (unlikely (c > 0x10FFFFu))
pchars[chars_len++] = 0xFFFDu;
else {
pchars[chars_len++] = 0xD800 + ((c - 0x10000) >> 10);
pchars[chars_len++] = 0xDC00 + ((c - 0x10000) & ((1 << 10) - 1));
pchars[chars_len++] = 0xD800u + ((c - 0x10000u) >> 10);
pchars[chars_len++] = 0xDC00u + ((c - 0x10000u) & ((1 << 10) - 1));
}
}
@ -635,7 +669,7 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
hb_codepoint_t c = buffer->info[i].codepoint;
unsigned int cluster = buffer->info[i].cluster;
log_clusters[chars_len++] = cluster;
if (c >= 0x10000 && c < 0x110000)
if (hb_in_range (c, 0x10000u, 0x10FFFFu))
log_clusters[chars_len++] = cluster; /* Surrogates. */
}
@ -705,10 +739,10 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
for (CFIndex j = range.location; j < range.location + range.length; j++)
{
UniChar ch = CFStringGetCharacterAtIndex (string_ref, j);
if (hb_in_range<UniChar> (ch, 0xDC00, 0xDFFF) && range.location < j)
if (hb_in_range<UniChar> (ch, 0xDC00u, 0xDFFFu) && range.location < j)
{
ch = CFStringGetCharacterAtIndex (string_ref, j - 1);
if (hb_in_range<UniChar> (ch, 0xD800, 0xDBFF))
if (hb_in_range<UniChar> (ch, 0xD800u, 0xDBFFu))
/* This is the second of a surrogate pair. Don't need .notdef
* for this one. */
continue;
@ -866,3 +900,97 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
return true;
}
/*
* AAT shaper
*/
HB_SHAPER_DATA_ENSURE_DECLARE(coretext_aat, face)
HB_SHAPER_DATA_ENSURE_DECLARE(coretext_aat, font)
/*
* shaper face data
*/
struct hb_coretext_aat_shaper_face_data_t {};
hb_coretext_aat_shaper_face_data_t *
_hb_coretext_aat_shaper_face_data_create (hb_face_t *face)
{
hb_blob_t *mort_blob = face->reference_table (HB_CORETEXT_TAG_MORT);
/* Umm, we just reference the table to check whether it exists.
* Maybe add better API for this? */
if (!hb_blob_get_length (mort_blob))
{
hb_blob_destroy (mort_blob);
mort_blob = face->reference_table (HB_CORETEXT_TAG_MORX);
if (!hb_blob_get_length (mort_blob))
{
hb_blob_destroy (mort_blob);
return NULL;
}
}
hb_blob_destroy (mort_blob);
return hb_coretext_shaper_face_data_ensure (face) ? (hb_coretext_aat_shaper_face_data_t *) HB_SHAPER_DATA_SUCCEEDED : NULL;
}
void
_hb_coretext_aat_shaper_face_data_destroy (hb_coretext_aat_shaper_face_data_t *data HB_UNUSED)
{
}
/*
* shaper font data
*/
struct hb_coretext_aat_shaper_font_data_t {};
hb_coretext_aat_shaper_font_data_t *
_hb_coretext_aat_shaper_font_data_create (hb_font_t *font)
{
return hb_coretext_shaper_font_data_ensure (font) ? (hb_coretext_aat_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED : NULL;
}
void
_hb_coretext_aat_shaper_font_data_destroy (hb_coretext_aat_shaper_font_data_t *data HB_UNUSED)
{
}
/*
* shaper shape_plan data
*/
struct hb_coretext_aat_shaper_shape_plan_data_t {};
hb_coretext_aat_shaper_shape_plan_data_t *
_hb_coretext_aat_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan HB_UNUSED,
const hb_feature_t *user_features HB_UNUSED,
unsigned int num_user_features HB_UNUSED)
{
return (hb_coretext_aat_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
}
void
_hb_coretext_aat_shaper_shape_plan_data_destroy (hb_coretext_aat_shaper_shape_plan_data_t *data HB_UNUSED)
{
}
/*
* shaper
*/
hb_bool_t
_hb_coretext_aat_shape (hb_shape_plan_t *shape_plan,
hb_font_t *font,
hb_buffer_t *buffer,
const hb_feature_t *features,
unsigned int num_features)
{
return _hb_coretext_shape (shape_plan, font, buffer, features, num_features);
}

View File

@ -30,7 +30,7 @@
#include "hb.h"
#include <TargetConditionals.h>
#if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
#if TARGET_OS_IPHONE
# include <CoreText/CoreText.h>
# include <CoreGraphics/CoreGraphics.h>
#else
@ -44,6 +44,10 @@ HB_BEGIN_DECLS
#define HB_CORETEXT_TAG_MORX HB_TAG('m','o','r','x')
hb_face_t *
hb_coretext_face_create (CGFontRef cg_font);
CGFontRef
hb_coretext_face_get_cg_font (hb_face_t *face);

View File

@ -110,9 +110,9 @@ typedef struct OffsetTable
protected:
Tag sfnt_version; /* '\0\001\0\00' if TrueType / 'OTTO' if CFF */
USHORT numTables; /* Number of tables. */
USHORT searchRange; /* (Maximum power of 2 <= numTables) x 16 */
USHORT entrySelector; /* Log2(maximum power of 2 <= numTables). */
USHORT rangeShift; /* NumTables x 16-searchRange. */
USHORT searchRangeZ; /* (Maximum power of 2 <= numTables) x 16 */
USHORT entrySelectorZ; /* Log2(maximum power of 2 <= numTables). */
USHORT rangeShiftZ; /* NumTables x 16-searchRange. */
TableRecord tables[VAR]; /* TableRecord entries. numTables items */
public:
DEFINE_SIZE_ARRAY (12, tables);
@ -138,8 +138,8 @@ struct TTCHeaderVersion1
protected:
Tag ttcTag; /* TrueType Collection ID string: 'ttcf' */
FixedVersion version; /* Version of the TTC Header (1.0),
* 0x00010000 */
LongOffsetLongArrayOf<OffsetTable>
* 0x00010000u */
ArrayOf<OffsetTo<OffsetTable, ULONG>, ULONG>
table; /* Array of offsets to the OffsetTable for each font
* from the beginning of the file */
public:
@ -184,7 +184,7 @@ struct TTCHeader
struct {
Tag ttcTag; /* TrueType Collection ID string: 'ttcf' */
FixedVersion version; /* Version of the TTC Header (1.0 or 2.0),
* 0x00010000 or 0x00020000 */
* 0x00010000u or 0x00020000u */
} header;
TTCHeaderVersion1 version1;
} u;

View File

@ -42,36 +42,36 @@ namespace OT {
/* Cast to struct T, reference to reference */
template<typename Type, typename TObject>
inline const Type& CastR(const TObject &X)
static inline const Type& CastR(const TObject &X)
{ return reinterpret_cast<const Type&> (X); }
template<typename Type, typename TObject>
inline Type& CastR(TObject &X)
static inline Type& CastR(TObject &X)
{ return reinterpret_cast<Type&> (X); }
/* Cast to struct T, pointer to pointer */
template<typename Type, typename TObject>
inline const Type* CastP(const TObject *X)
static inline const Type* CastP(const TObject *X)
{ return reinterpret_cast<const Type*> (X); }
template<typename Type, typename TObject>
inline Type* CastP(TObject *X)
static inline Type* CastP(TObject *X)
{ return reinterpret_cast<Type*> (X); }
/* StructAtOffset<T>(P,Ofs) returns the struct T& that is placed at memory
* location pointed to by P plus Ofs bytes. */
template<typename Type>
inline const Type& StructAtOffset(const void *P, unsigned int offset)
static inline const Type& StructAtOffset(const void *P, unsigned int offset)
{ return * reinterpret_cast<const Type*> ((const char *) P + offset); }
template<typename Type>
inline Type& StructAtOffset(void *P, unsigned int offset)
static inline Type& StructAtOffset(void *P, unsigned int offset)
{ return * reinterpret_cast<Type*> ((char *) P + offset); }
/* StructAfter<T>(X) returns the struct T& that is placed after X.
* Works with X of variable size also. X must implement get_size() */
template<typename Type, typename TObject>
inline const Type& StructAfter(const TObject &X)
static inline const Type& StructAfter(const TObject &X)
{ return StructAtOffset<Type>(&X, X.get_size()); }
template<typename Type, typename TObject>
inline Type& StructAfter(TObject &X)
static inline Type& StructAfter(TObject &X)
{ return StructAtOffset<Type>(&X, X.get_size()); }
@ -132,7 +132,7 @@ inline Type& StructAfter(TObject &X)
/* Global nul-content Null pool. Enlarge as necessary. */
/* TODO This really should be a extern HB_INTERNAL and defined somewhere... */
static const void *_NullPool[64 / sizeof (void *)];
static const void *_NullPool[(256+8) / sizeof (void *)];
/* Generic nul-content Null objects. */
template <typename Type>
@ -145,7 +145,7 @@ static inline const Type& Null (void) {
#define DEFINE_NULL_DATA(Type, data) \
static const char _Null##Type[sizeof (Type) + 1] = data; /* +1 is for nul-termination in data */ \
template <> \
inline const Type& Null<Type> (void) { \
/*static*/ inline const Type& Null<Type> (void) { \
return *CastP<Type> (_Null##Type); \
} /* The following line really exists such that we end in a place needing semicolon */ \
ASSERT_STATIC (Type::min_size + 1 <= sizeof (_Null##Type))
@ -266,6 +266,15 @@ struct hb_sanitize_context_t
return TRACE_RETURN (this->writable);
}
template <typename Type, typename ValueType>
inline bool try_set (Type *obj, const ValueType &v) {
if (this->may_edit (obj, obj->static_size)) {
obj->set (v);
return true;
}
return false;
}
mutable unsigned int debug_depth;
const char *start, *end;
bool writable;
@ -572,6 +581,7 @@ struct IntType
DEFINE_SIZE_STATIC (Size);
};
typedef uint8_t BYTE; /* 8-bit unsigned integer. */
typedef IntType<uint16_t, 2> USHORT; /* 16-bit unsigned integer. */
typedef IntType<int16_t, 2> SHORT; /* 16-bit signed integer. */
typedef IntType<uint32_t, 4> ULONG; /* 32-bit unsigned integer. */
@ -616,24 +626,17 @@ typedef USHORT GlyphID;
/* Script/language-system/feature index */
struct Index : USHORT {
static const unsigned int NOT_FOUND_INDEX = 0xFFFF;
static const unsigned int NOT_FOUND_INDEX = 0xFFFFu;
};
DEFINE_NULL_DATA (Index, "\xff\xff");
/* Offset to a table, same as uint16 (length = 16 bits), Null offset = 0x0000 */
struct Offset : USHORT
/* Offset, Null offset = 0 */
template <typename Type=USHORT>
struct Offset : Type
{
inline bool is_null (void) const { return 0 == *this; }
public:
DEFINE_SIZE_STATIC (2);
};
/* LongOffset to a table, same as uint32 (length = 32 bits), Null offset = 0x00000000 */
struct LongOffset : ULONG
{
inline bool is_null (void) const { return 0 == *this; }
public:
DEFINE_SIZE_STATIC (4);
DEFINE_SIZE_STATIC (sizeof(Type));
};
@ -682,12 +685,12 @@ struct FixedVersion
/*
* Template subclasses of Offset and LongOffset that do the dereferencing.
* Template subclasses of Offset that do the dereferencing.
* Use: (base+offset)
*/
template <typename OffsetType, typename Type>
struct GenericOffsetTo : OffsetType
template <typename Type, typename OffsetType=USHORT>
struct OffsetTo : Offset<OffsetType>
{
inline const Type& operator () (const void *base) const
{
@ -721,40 +724,25 @@ struct GenericOffsetTo : OffsetType
return TRACE_RETURN (likely (obj.sanitize (c, user_data)) || neuter (c));
}
inline bool try_set (hb_sanitize_context_t *c, const OffsetType &v) {
if (c->may_edit (this, this->static_size)) {
this->set (v);
return true;
}
return false;
}
/* Set the offset to Null */
inline bool neuter (hb_sanitize_context_t *c) {
if (c->may_edit (this, this->static_size)) {
this->set (0); /* 0 is Null offset */
return true;
}
return false;
return c->try_set (this, 0);
}
DEFINE_SIZE_STATIC (sizeof(OffsetType));
};
template <typename Base, typename OffsetType, typename Type>
inline const Type& operator + (const Base &base, const GenericOffsetTo<OffsetType, Type> &offset) { return offset (base); }
static inline const Type& operator + (const Base &base, const OffsetTo<Type, OffsetType> &offset) { return offset (base); }
template <typename Base, typename OffsetType, typename Type>
inline Type& operator + (Base &base, GenericOffsetTo<OffsetType, Type> &offset) { return offset (base); }
template <typename Type>
struct OffsetTo : GenericOffsetTo<Offset, Type> {};
template <typename Type>
struct LongOffsetTo : GenericOffsetTo<LongOffset, Type> {};
static inline Type& operator + (Base &base, OffsetTo<Type, OffsetType> &offset) { return offset (base); }
/*
* Array Types
*/
template <typename LenType, typename Type>
struct GenericArrayOf
/* An array with a number of elements. */
template <typename Type, typename LenType=USHORT>
struct ArrayOf
{
const Type *sub_array (unsigned int start_offset, unsigned int *pcount /* IN/OUT */) const
{
@ -837,6 +825,16 @@ struct GenericArrayOf
return TRACE_RETURN (true);
}
template <typename SearchType>
inline int lsearch (const SearchType &x) const
{
unsigned int count = len;
for (unsigned int i = 0; i < count; i++)
if (!this->array[i].cmp (x))
return i;
return -1;
}
private:
inline bool sanitize_shallow (hb_sanitize_context_t *c) {
TRACE_SANITIZE (this);
@ -850,26 +848,10 @@ struct GenericArrayOf
DEFINE_SIZE_ARRAY (sizeof (LenType), array);
};
/* An array with a USHORT number of elements. */
template <typename Type>
struct ArrayOf : GenericArrayOf<USHORT, Type> {};
/* An array with a ULONG number of elements. */
template <typename Type>
struct LongArrayOf : GenericArrayOf<ULONG, Type> {};
/* Array of Offset's */
template <typename Type>
struct OffsetArrayOf : ArrayOf<OffsetTo<Type> > {};
/* Array of LongOffset's */
template <typename Type>
struct LongOffsetArrayOf : ArrayOf<LongOffsetTo<Type> > {};
/* LongArray of LongOffset's */
template <typename Type>
struct LongOffsetLongArrayOf : LongArrayOf<LongOffsetTo<Type> > {};
/* Array of offsets relative to the beginning of the array itself. */
template <typename Type>
struct OffsetListOf : OffsetArrayOf<Type>
@ -892,9 +874,8 @@ struct OffsetListOf : OffsetArrayOf<Type>
};
/* An array with a USHORT number of elements,
* starting at second element. */
template <typename Type>
/* An array starting at second element. */
template <typename Type, typename LenType=USHORT>
struct HeadlessArrayOf
{
inline const Type& operator [] (unsigned int i) const
@ -941,19 +922,19 @@ struct HeadlessArrayOf
return TRACE_RETURN (true);
}
USHORT len;
LenType len;
Type array[VAR];
public:
DEFINE_SIZE_ARRAY (sizeof (USHORT), array);
DEFINE_SIZE_ARRAY (sizeof (LenType), array);
};
/* An array with sorted elements. Supports binary searching. */
template <typename Type>
struct SortedArrayOf : ArrayOf<Type> {
template <typename Type, typename LenType=USHORT>
struct SortedArrayOf : ArrayOf<Type, LenType>
{
template <typename SearchType>
inline int search (const SearchType &x) const
inline int bsearch (const SearchType &x) const
{
/* Hand-coded bsearch here since this is in the hot inner loop. */
int min = 0, max = (int) this->len - 1;

View File

@ -0,0 +1,517 @@
/*
* Copyright © 2014 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_OT_CMAP_TABLE_HH
#define HB_OT_CMAP_TABLE_HH
#include "hb-open-type-private.hh"
namespace OT {
/*
* cmap -- Character To Glyph Index Mapping Table
*/
#define HB_OT_TAG_cmap HB_TAG('c','m','a','p')
struct CmapSubtableFormat0
{
inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
{
hb_codepoint_t gid = codepoint < 256 ? glyphIdArray[codepoint] : 0;
if (!gid)
return false;
*glyph = gid;
return true;
}
inline bool sanitize (hb_sanitize_context_t *c) {
TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this));
}
protected:
USHORT format; /* Format number is set to 0. */
USHORT lengthZ; /* Byte length of this subtable. */
USHORT languageZ; /* Ignore. */
BYTE glyphIdArray[256];/* An array that maps character
* code to glyph index values. */
public:
DEFINE_SIZE_STATIC (6 + 256);
};
struct CmapSubtableFormat4
{
inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
{
unsigned int segCount;
const USHORT *endCount;
const USHORT *startCount;
const USHORT *idDelta;
const USHORT *idRangeOffset;
const USHORT *glyphIdArray;
unsigned int glyphIdArrayLength;
segCount = this->segCountX2 / 2;
endCount = this->values;
startCount = endCount + segCount + 1;
idDelta = startCount + segCount;
idRangeOffset = idDelta + segCount;
glyphIdArray = idRangeOffset + segCount;
glyphIdArrayLength = (this->length - 16 - 8 * segCount) / 2;
/* Custom two-array bsearch. */
int min = 0, max = (int) segCount - 1;
unsigned int i;
while (min <= max)
{
int mid = (min + max) / 2;
if (codepoint < startCount[mid])
max = mid - 1;
else if (codepoint > endCount[mid])
min = mid + 1;
else
{
i = mid;
goto found;
}
}
return false;
found:
hb_codepoint_t gid;
unsigned int rangeOffset = idRangeOffset[i];
if (rangeOffset == 0)
gid = codepoint + idDelta[i];
else
{
/* Somebody has been smoking... */
unsigned int index = rangeOffset / 2 + (codepoint - startCount[i]) + i - segCount;
if (unlikely (index >= glyphIdArrayLength))
return false;
gid = glyphIdArray[index];
if (unlikely (!gid))
return false;
gid += idDelta[i];
}
*glyph = gid & 0xFFFFu;
return true;
}
inline bool sanitize (hb_sanitize_context_t *c)
{
TRACE_SANITIZE (this);
if (unlikely (!c->check_struct (this)))
return TRACE_RETURN (false);
if (unlikely (!c->check_range (this, length)))
{
/* Some broken fonts have too long of a "length" value.
* If that is the case, just change the value to truncate
* the subtable at the end of the blob. */
uint16_t new_length = (uint16_t) MIN ((uintptr_t) 65535,
(uintptr_t) (c->end -
(char *) this));
if (!c->try_set (&length, new_length))
return TRACE_RETURN (false);
}
return TRACE_RETURN (16 + 4 * (unsigned int) segCountX2 <= length);
}
protected:
USHORT format; /* Format number is set to 4. */
USHORT length; /* This is the length in bytes of the
* subtable. */
USHORT languageZ; /* Ignore. */
USHORT segCountX2; /* 2 x segCount. */
USHORT searchRangeZ; /* 2 * (2**floor(log2(segCount))) */
USHORT entrySelectorZ; /* log2(searchRange/2) */
USHORT rangeShiftZ; /* 2 x segCount - searchRange */
USHORT values[VAR];
#if 0
USHORT endCount[segCount]; /* End characterCode for each segment,
* last=0xFFFFu. */
USHORT reservedPad; /* Set to 0. */
USHORT startCount[segCount]; /* Start character code for each segment. */
SHORT idDelta[segCount]; /* Delta for all character codes in segment. */
USHORT idRangeOffset[segCount];/* Offsets into glyphIdArray or 0 */
USHORT glyphIdArray[VAR]; /* Glyph index array (arbitrary length) */
#endif
public:
DEFINE_SIZE_ARRAY (14, values);
};
struct CmapSubtableLongGroup
{
friend struct CmapSubtableFormat12;
friend struct CmapSubtableFormat13;
int cmp (hb_codepoint_t codepoint) const
{
if (codepoint < startCharCode) return -1;
if (codepoint > endCharCode) return +1;
return 0;
}
inline bool sanitize (hb_sanitize_context_t *c) {
TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this));
}
private:
ULONG startCharCode; /* First character code in this group. */
ULONG endCharCode; /* Last character code in this group. */
ULONG glyphID; /* Glyph index; interpretation depends on
* subtable format. */
public:
DEFINE_SIZE_STATIC (12);
};
template <typename UINT>
struct CmapSubtableTrimmed
{
inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
{
/* Rely on our implicit array bound-checking. */
hb_codepoint_t gid = glyphIdArray[codepoint - startCharCode];
if (!gid)
return false;
*glyph = gid;
return true;
}
inline bool sanitize (hb_sanitize_context_t *c) {
TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this) && glyphIdArray.sanitize (c));
}
protected:
UINT formatReserved; /* Subtable format and (maybe) padding. */
UINT lengthZ; /* Byte length of this subtable. */
UINT languageZ; /* Ignore. */
UINT startCharCode; /* First character code covered. */
ArrayOf<GlyphID, UINT>
glyphIdArray; /* Array of glyph index values for character
* codes in the range. */
public:
DEFINE_SIZE_ARRAY (5 * sizeof (UINT), glyphIdArray);
};
struct CmapSubtableFormat6 : CmapSubtableTrimmed<USHORT> {};
struct CmapSubtableFormat10 : CmapSubtableTrimmed<ULONG > {};
template <typename T>
struct CmapSubtableLongSegmented
{
inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
{
int i = groups.bsearch (codepoint);
if (i == -1)
return false;
*glyph = T::group_get_glyph (groups[i], codepoint);
return true;
}
inline bool sanitize (hb_sanitize_context_t *c) {
TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this) && groups.sanitize (c));
}
protected:
USHORT format; /* Subtable format; set to 12. */
USHORT reservedZ; /* Reserved; set to 0. */
ULONG lengthZ; /* Byte length of this subtable. */
ULONG languageZ; /* Ignore. */
SortedArrayOf<CmapSubtableLongGroup, ULONG>
groups; /* Groupings. */
public:
DEFINE_SIZE_ARRAY (16, groups);
};
struct CmapSubtableFormat12 : CmapSubtableLongSegmented<CmapSubtableFormat12>
{
static inline hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group,
hb_codepoint_t u)
{ return group.glyphID + (u - group.startCharCode); }
};
struct CmapSubtableFormat13 : CmapSubtableLongSegmented<CmapSubtableFormat13>
{
static inline hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group,
hb_codepoint_t u HB_UNUSED)
{ return group.glyphID; }
};
typedef enum
{
GLYPH_VARIANT_NOT_FOUND = 0,
GLYPH_VARIANT_FOUND = 1,
GLYPH_VARIANT_USE_DEFAULT = 2
} glyph_variant_t;
struct UnicodeValueRange
{
inline int cmp (const hb_codepoint_t &codepoint) const
{
if (codepoint < startUnicodeValue) return -1;
if (codepoint > startUnicodeValue + additionalCount) return +1;
return 0;
}
inline bool sanitize (hb_sanitize_context_t *c) {
TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this));
}
UINT24 startUnicodeValue; /* First value in this range. */
BYTE additionalCount; /* Number of additional values in this
* range. */
public:
DEFINE_SIZE_STATIC (4);
};
typedef SortedArrayOf<UnicodeValueRange, ULONG> DefaultUVS;
struct UVSMapping
{
inline int cmp (const hb_codepoint_t &codepoint) const
{
return unicodeValue.cmp (codepoint);
}
inline bool sanitize (hb_sanitize_context_t *c) {
TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this));
}
UINT24 unicodeValue; /* Base Unicode value of the UVS */
GlyphID glyphID; /* Glyph ID of the UVS */
public:
DEFINE_SIZE_STATIC (5);
};
typedef SortedArrayOf<UVSMapping, ULONG> NonDefaultUVS;
struct VariationSelectorRecord
{
inline glyph_variant_t get_glyph (hb_codepoint_t codepoint,
hb_codepoint_t *glyph,
const void *base) const
{
int i;
const DefaultUVS &defaults = base+defaultUVS;
i = defaults.bsearch (codepoint);
if (i != -1)
return GLYPH_VARIANT_USE_DEFAULT;
const NonDefaultUVS &nonDefaults = base+nonDefaultUVS;
i = nonDefaults.bsearch (codepoint);
if (i != -1)
{
*glyph = nonDefaults[i].glyphID;
return GLYPH_VARIANT_FOUND;
}
return GLYPH_VARIANT_NOT_FOUND;
}
inline int cmp (const hb_codepoint_t &variation_selector) const
{
return varSelector.cmp (variation_selector);
}
inline bool sanitize (hb_sanitize_context_t *c, void *base) {
TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this) &&
defaultUVS.sanitize (c, base) &&
nonDefaultUVS.sanitize (c, base));
}
UINT24 varSelector; /* Variation selector. */
OffsetTo<DefaultUVS, ULONG>
defaultUVS; /* Offset to Default UVS Table. May be 0. */
OffsetTo<NonDefaultUVS, ULONG>
nonDefaultUVS; /* Offset to Non-Default UVS Table. May be 0. */
public:
DEFINE_SIZE_STATIC (11);
};
struct CmapSubtableFormat14
{
inline glyph_variant_t get_glyph_variant (hb_codepoint_t codepoint,
hb_codepoint_t variation_selector,
hb_codepoint_t *glyph) const
{
return record[record.bsearch(variation_selector)].get_glyph (codepoint, glyph, this);
}
inline bool sanitize (hb_sanitize_context_t *c) {
TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this) &&
record.sanitize (c, this));
}
protected:
USHORT format; /* Format number is set to 0. */
ULONG lengthZ; /* Byte length of this subtable. */
SortedArrayOf<VariationSelectorRecord, ULONG>
record; /* Variation selector records; sorted
* in increasing order of `varSelector'. */
public:
DEFINE_SIZE_ARRAY (10, record);
};
struct CmapSubtable
{
/* Note: We intentionally do NOT implement subtable formats 2 and 8. */
inline bool get_glyph (hb_codepoint_t codepoint,
hb_codepoint_t *glyph) const
{
switch (u.format) {
case 0: return u.format0 .get_glyph(codepoint, glyph);
case 4: return u.format4 .get_glyph(codepoint, glyph);
case 6: return u.format6 .get_glyph(codepoint, glyph);
case 10: return u.format10.get_glyph(codepoint, glyph);
case 12: return u.format12.get_glyph(codepoint, glyph);
case 13: return u.format13.get_glyph(codepoint, glyph);
case 14:
default: return false;
}
}
inline glyph_variant_t get_glyph_variant (hb_codepoint_t codepoint,
hb_codepoint_t variation_selector,
hb_codepoint_t *glyph) const
{
switch (u.format) {
case 14: return u.format14.get_glyph_variant(codepoint, variation_selector, glyph);
default: return GLYPH_VARIANT_NOT_FOUND;
}
}
inline bool sanitize (hb_sanitize_context_t *c) {
TRACE_SANITIZE (this);
if (!u.format.sanitize (c)) return TRACE_RETURN (false);
switch (u.format) {
case 0: return TRACE_RETURN (u.format0 .sanitize (c));
case 4: return TRACE_RETURN (u.format4 .sanitize (c));
case 6: return TRACE_RETURN (u.format6 .sanitize (c));
case 10: return TRACE_RETURN (u.format10.sanitize (c));
case 12: return TRACE_RETURN (u.format12.sanitize (c));
case 13: return TRACE_RETURN (u.format13.sanitize (c));
case 14: return TRACE_RETURN (u.format14.sanitize (c));
default:return TRACE_RETURN (true);
}
}
protected:
union {
USHORT format; /* Format identifier */
CmapSubtableFormat0 format0;
CmapSubtableFormat4 format4;
CmapSubtableFormat6 format6;
CmapSubtableFormat10 format10;
CmapSubtableFormat12 format12;
CmapSubtableFormat13 format13;
CmapSubtableFormat14 format14;
} u;
public:
DEFINE_SIZE_UNION (2, format);
};
struct EncodingRecord
{
inline int cmp (const EncodingRecord &other) const
{
int ret;
ret = platformID.cmp (other.platformID);
if (ret) return ret;
ret = encodingID.cmp (other.encodingID);
if (ret) return ret;
return 0;
}
inline bool sanitize (hb_sanitize_context_t *c, void *base) {
TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this) &&
subtable.sanitize (c, base));
}
USHORT platformID; /* Platform ID. */
USHORT encodingID; /* Platform-specific encoding ID. */
OffsetTo<CmapSubtable, ULONG>
subtable; /* Byte offset from beginning of table to the subtable for this encoding. */
public:
DEFINE_SIZE_STATIC (8);
};
struct cmap
{
static const hb_tag_t tableTag = HB_OT_TAG_cmap;
inline const CmapSubtable *find_subtable (unsigned int platform_id,
unsigned int encoding_id) const
{
EncodingRecord key;
key.platformID.set (platform_id);
key.encodingID.set (encoding_id);
/* Note: We can use bsearch, but since it has no performance
* implications, we use lsearch and as such accept fonts with
* unsorted subtable list. */
int result = encodingRecord./*bsearch*/lsearch (key);
if (result == -1 || !encodingRecord[result].subtable)
return NULL;
return &(this+encodingRecord[result].subtable);
}
inline bool sanitize (hb_sanitize_context_t *c) {
TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this) &&
likely (version == 0) &&
encodingRecord.sanitize (c, this));
}
USHORT version; /* Table version number (0). */
SortedArrayOf<EncodingRecord>
encodingRecord; /* Encoding tables. */
public:
DEFINE_SIZE_ARRAY (4, encodingRecord);
};
} /* namespace OT */
#endif /* HB_OT_CMAP_TABLE_HH */

View File

@ -0,0 +1,289 @@
/*
* Copyright © 2011,2014 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod, Roozbeh Pournader
*/
#include "hb-private.hh"
#include "hb-ot.h"
#include "hb-font-private.hh"
#include "hb-ot-cmap-table.hh"
#include "hb-ot-hhea-table.hh"
#include "hb-ot-hmtx-table.hh"
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;
};
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));
if (unlikely (!ot_font))
return NULL;
ot_font->num_glyphs = font->face->get_num_glyphs ();
{
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;
return ot_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);
free (ot_font);
}
static hb_bool_t
hb_ot_get_glyph (hb_font_t *font HB_UNUSED,
void *font_data,
hb_codepoint_t unicode,
hb_codepoint_t variation_selector,
hb_codepoint_t *glyph,
void *user_data 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);
}
static hb_position_t
hb_ot_get_glyph_h_advance (hb_font_t *font HB_UNUSED,
void *font_data,
hb_codepoint_t glyph,
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);
}
static hb_position_t
hb_ot_get_glyph_v_advance (hb_font_t *font HB_UNUSED,
void *font_data,
hb_codepoint_t glyph,
void *user_data HB_UNUSED)
{
/* TODO */
return 0;
}
static hb_bool_t
hb_ot_get_glyph_h_origin (hb_font_t *font HB_UNUSED,
void *font_data HB_UNUSED,
hb_codepoint_t glyph HB_UNUSED,
hb_position_t *x HB_UNUSED,
hb_position_t *y HB_UNUSED,
void *user_data HB_UNUSED)
{
/* We always work in the horizontal coordinates. */
return true;
}
static hb_bool_t
hb_ot_get_glyph_v_origin (hb_font_t *font HB_UNUSED,
void *font_data,
hb_codepoint_t glyph,
hb_position_t *x,
hb_position_t *y,
void *user_data HB_UNUSED)
{
/* TODO */
return false;
}
static hb_position_t
hb_ot_get_glyph_h_kerning (hb_font_t *font,
void *font_data,
hb_codepoint_t left_glyph,
hb_codepoint_t right_glyph,
void *user_data HB_UNUSED)
{
/* TODO */
return 0;
}
static hb_position_t
hb_ot_get_glyph_v_kerning (hb_font_t *font HB_UNUSED,
void *font_data HB_UNUSED,
hb_codepoint_t top_glyph HB_UNUSED,
hb_codepoint_t bottom_glyph HB_UNUSED,
void *user_data HB_UNUSED)
{
return 0;
}
static hb_bool_t
hb_ot_get_glyph_extents (hb_font_t *font HB_UNUSED,
void *font_data,
hb_codepoint_t glyph,
hb_glyph_extents_t *extents,
void *user_data HB_UNUSED)
{
/* TODO */
return false;
}
static hb_bool_t
hb_ot_get_glyph_contour_point (hb_font_t *font HB_UNUSED,
void *font_data,
hb_codepoint_t glyph,
unsigned int point_index,
hb_position_t *x,
hb_position_t *y,
void *user_data HB_UNUSED)
{
/* TODO */
return false;
}
static hb_bool_t
hb_ot_get_glyph_name (hb_font_t *font HB_UNUSED,
void *font_data,
hb_codepoint_t glyph,
char *name, unsigned int size,
void *user_data HB_UNUSED)
{
/* TODO */
return false;
}
static hb_bool_t
hb_ot_get_glyph_from_name (hb_font_t *font HB_UNUSED,
void *font_data,
const char *name, int len, /* -1 means nul-terminated */
hb_codepoint_t *glyph,
void *user_data HB_UNUSED)
{
/* TODO */
return false;
}
static hb_font_funcs_t *
_hb_ot_get_font_funcs (void)
{
static const hb_font_funcs_t ot_ffuncs = {
HB_OBJECT_HEADER_STATIC,
true, /* immutable */
{
#define HB_FONT_FUNC_IMPLEMENT(name) hb_ot_get_##name,
HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_FONT_FUNC_IMPLEMENT
}
};
return const_cast<hb_font_funcs_t *> (&ot_ffuncs);
}
void
hb_ot_font_set_funcs (hb_font_t *font)
{
hb_ot_font_t *ot_font = _hb_ot_font_create (font);
if (unlikely (!ot_font))
return;
hb_font_set_funcs (font,
_hb_ot_get_font_funcs (),
ot_font,
(hb_destroy_func_t) _hb_ot_font_destroy);
}

View File

@ -0,0 +1,41 @@
/*
* Copyright © 2014 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod, Roozbeh Pournader
*/
#ifndef HB_OT_FONT_H
#define HB_OT_FONT_H
#include "hb.h"
HB_BEGIN_DECLS
void
hb_ot_font_set_funcs (hb_font_t *font);
HB_END_DECLS
#endif /* HB_OT_FONT_H */

View File

@ -58,12 +58,12 @@ struct head
protected:
FixedVersion version; /* Version of the head table--currently
* 0x00010000 for version 1.0. */
* 0x00010000u for version 1.0. */
FixedVersion fontRevision; /* Set by font manufacturer. */
ULONG checkSumAdjustment; /* To compute: set it to 0, sum the
* entire font as ULONG, then store
* 0xB1B0AFBA - sum. */
ULONG magicNumber; /* Set to 0x5F0F3CF5. */
* 0xB1B0AFBAu - sum. */
ULONG magicNumber; /* Set to 0x5F0F3CF5u. */
USHORT flags; /* Bit 0: Baseline for font at y=0;
* Bit 1: Left sidebearing point at x=0;
* Bit 2: Instructions may depend on point size;

View File

@ -49,8 +49,8 @@ struct hhea
return TRACE_RETURN (c->check_struct (this) && likely (version.major == 1));
}
protected:
FixedVersion version; /* 0x00010000 for version 1.0. */
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

View File

@ -59,7 +59,7 @@ struct hmtx
return TRACE_RETURN (true);
}
protected:
public:
LongHorMetric longHorMetric[VAR]; /* Paired advance width and left side
* bearing values for each glyph. The
* value numOfHMetrics comes from

View File

@ -103,7 +103,8 @@ struct RecordArrayOf : SortedArrayOf<Record<Type> > {
}
inline bool find_index (hb_tag_t tag, unsigned int *index) const
{
int i = this->search (tag);
/* If we want to allow non-sorted data, we can lsearch(). */
int i = this->/*lsearch*/bsearch (tag);
if (i != -1) {
if (index) *index = i;
return true;
@ -189,10 +190,10 @@ struct LangSys
unsigned int *feature_indexes /* OUT */) const
{ return featureIndex.get_indexes (start_offset, feature_count, feature_indexes); }
inline bool has_required_feature (void) const { return reqFeatureIndex != 0xffff; }
inline bool has_required_feature (void) const { return reqFeatureIndex != 0xFFFFu; }
inline unsigned int get_required_feature_index (void) const
{
if (reqFeatureIndex == 0xffff)
if (reqFeatureIndex == 0xFFFFu)
return Index::NOT_FOUND_INDEX;
return reqFeatureIndex;;
}
@ -203,11 +204,11 @@ struct LangSys
return TRACE_RETURN (c->check_struct (this) && featureIndex.sanitize (c));
}
Offset lookupOrder; /* = Null (reserved for an offset to a
Offset<> lookupOrderZ; /* = Null (reserved for an offset to a
* reordering table) */
USHORT reqFeatureIndex;/* Index of a feature required for this
* language system--if no required features
* = 0xFFFF */
* = 0xFFFFu */
IndexArray featureIndex; /* Array of indices into the FeatureList */
public:
DEFINE_SIZE_ARRAY (6, featureIndex);
@ -447,9 +448,9 @@ struct FeatureParams
TRACE_SANITIZE (this);
if (tag == HB_TAG ('s','i','z','e'))
return TRACE_RETURN (u.size.sanitize (c));
if ((tag & 0xFFFF0000) == HB_TAG ('s','s','\0','\0')) /* ssXX */
if ((tag & 0xFFFF0000u) == HB_TAG ('s','s','\0','\0')) /* ssXX */
return TRACE_RETURN (u.stylisticSet.sanitize (c));
if ((tag & 0xFFFF0000) == HB_TAG ('c','v','\0','\0')) /* cvXX */
if ((tag & 0xFFFF0000u) == HB_TAG ('c','v','\0','\0')) /* cvXX */
return TRACE_RETURN (u.characterVariants.sanitize (c));
return TRACE_RETURN (true);
}
@ -501,11 +502,11 @@ struct Feature
* Adobe tools, only the 'size' feature had FeatureParams defined.
*/
Offset orig_offset = featureParams;
OffsetTo<FeatureParams> orig_offset = featureParams;
if (unlikely (!featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE)))
return TRACE_RETURN (false);
if (likely (!orig_offset))
if (likely (orig_offset.is_null ()))
return TRACE_RETURN (true);
if (featureParams == 0 && closure &&
@ -513,13 +514,13 @@ struct Feature
closure->list_base && closure->list_base < this)
{
unsigned int new_offset_int = (unsigned int) orig_offset -
((char *) this - (char *) closure->list_base);
(((char *) this) - ((char *) closure->list_base));
Offset new_offset;
OffsetTo<FeatureParams> new_offset;
/* Check that it did not overflow. */
new_offset.set (new_offset_int);
if (new_offset == new_offset_int &&
featureParams.try_set (c, new_offset) &&
c->try_set (&featureParams, new_offset) &&
!featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE))
return TRACE_RETURN (false);
}
@ -584,7 +585,7 @@ struct Lookup
TRACE_SERIALIZE (this);
if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
lookupType.set (lookup_type);
lookupFlag.set (lookup_props & 0xFFFF);
lookupFlag.set (lookup_props & 0xFFFFu);
if (unlikely (!subTable.serialize (c, num_subtables))) return TRACE_RETURN (false);
if (lookupFlag & LookupFlag::UseMarkFilteringSet)
{
@ -608,7 +609,7 @@ struct Lookup
USHORT lookupType; /* Different enumerations for GSUB and GPOS */
USHORT lookupFlag; /* Lookup qualifiers */
ArrayOf<Offset>
ArrayOf<Offset<> >
subTable; /* Array of SubTables */
USHORT markFilteringSetX[VAR]; /* Index (base 0) into GDEF mark glyph sets
* structure. This field is only present if bit
@ -631,7 +632,7 @@ struct CoverageFormat1
private:
inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
{
int i = glyphArray.search (glyph_id);
int i = glyphArray.bsearch (glyph_id);
ASSERT_STATIC (((unsigned int) -1) == NOT_COVERED);
return i;
}
@ -696,7 +697,7 @@ struct CoverageFormat2
private:
inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
{
int i = rangeRecord.search (glyph_id);
int i = rangeRecord.bsearch (glyph_id);
if (i != -1) {
const RangeRecord &range = rangeRecord[i];
return (unsigned int) range.value + (glyph_id - range.start);
@ -992,7 +993,7 @@ struct ClassDefFormat2
private:
inline unsigned int get_class (hb_codepoint_t glyph_id) const
{
int i = rangeRecord.search (glyph_id);
int i = rangeRecord.bsearch (glyph_id);
if (i != -1)
return rangeRecord[i].value;
return 0;
@ -1130,7 +1131,7 @@ struct Device
unsigned int byte = deltaValue[s >> (4 - f)];
unsigned int bits = (byte >> (16 - (((s & ((1 << (4 - f)) - 1)) + 1) << f)));
unsigned int mask = (0xFFFF >> (16 - (1 << f)));
unsigned int mask = (0xFFFFu >> (16 - (1 << f)));
int delta = bits & mask;

View File

@ -282,7 +282,7 @@ struct MarkGlyphSetsFormat1
protected:
USHORT format; /* Format identifier--format = 1 */
LongOffsetArrayOf<Coverage>
ArrayOf<OffsetTo<Coverage, ULONG> >
coverage; /* Array of long offsets to mark set
* coverage tables */
public:
@ -360,9 +360,9 @@ struct GDEF
hb_position_t *caret_array /* OUT */) const
{ return (this+ligCaretList).get_lig_carets (font, direction, glyph_id, start_offset, caret_count, caret_array); }
inline bool has_mark_sets (void) const { return version.to_int () >= 0x00010002 && markGlyphSetsDef[0] != 0; }
inline bool has_mark_sets (void) const { return version.to_int () >= 0x00010002u && markGlyphSetsDef[0] != 0; }
inline bool mark_set_covers (unsigned int set_index, hb_codepoint_t glyph_id) const
{ return version.to_int () >= 0x00010002 && (this+markGlyphSetsDef[0]).covers (set_index, glyph_id); }
{ return version.to_int () >= 0x00010002u && (this+markGlyphSetsDef[0]).covers (set_index, glyph_id); }
inline bool sanitize (hb_sanitize_context_t *c) {
TRACE_SANITIZE (this);
@ -372,7 +372,7 @@ struct GDEF
attachList.sanitize (c, this) &&
ligCaretList.sanitize (c, this) &&
markAttachClassDef.sanitize (c, this) &&
(version.to_int () < 0x00010002 || markGlyphSetsDef[0].sanitize (c, this)));
(version.to_int () < 0x00010002u || markGlyphSetsDef[0].sanitize (c, this)));
}
@ -400,7 +400,7 @@ struct GDEF
protected:
FixedVersion version; /* Version of the GDEF table--currently
* 0x00010002 */
* 0x00010002u */
OffsetTo<ClassDef>
glyphClassDef; /* Offset to class definition table
* for glyph type--from beginning of

View File

@ -49,18 +49,18 @@ typedef Value ValueRecord[VAR];
struct ValueFormat : USHORT
{
enum Flags {
xPlacement = 0x0001, /* Includes horizontal adjustment for placement */
yPlacement = 0x0002, /* Includes vertical adjustment for placement */
xAdvance = 0x0004, /* Includes horizontal adjustment for advance */
yAdvance = 0x0008, /* Includes vertical adjustment for advance */
xPlaDevice = 0x0010, /* Includes horizontal Device table for placement */
yPlaDevice = 0x0020, /* Includes vertical Device table for placement */
xAdvDevice = 0x0040, /* Includes horizontal Device table for advance */
yAdvDevice = 0x0080, /* Includes vertical Device table for advance */
ignored = 0x0F00, /* Was used in TrueType Open for MM fonts */
reserved = 0xF000, /* For future use */
xPlacement = 0x0001u, /* Includes horizontal adjustment for placement */
yPlacement = 0x0002u, /* Includes vertical adjustment for placement */
xAdvance = 0x0004u, /* Includes horizontal adjustment for advance */
yAdvance = 0x0008u, /* Includes vertical adjustment for advance */
xPlaDevice = 0x0010u, /* Includes horizontal Device table for placement */
yPlaDevice = 0x0020u, /* Includes vertical Device table for placement */
xAdvDevice = 0x0040u, /* Includes horizontal Device table for advance */
yAdvDevice = 0x0080u, /* Includes vertical Device table for advance */
ignored = 0x0F00u, /* Was used in TrueType Open for MM fonts */
reserved = 0xF000u, /* For future use */
devices = 0x00F0 /* Mask for having any Device table */
devices = 0x00F0u /* Mask for having any Device table */
};
/* All fields are options. Only those available advance the value pointer. */
@ -1608,14 +1608,14 @@ GPOS::position_finish (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
/* Out-of-class implementation for methods recursing */
template <typename context_t>
inline typename context_t::return_t PosLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
/*static*/ inline typename context_t::return_t PosLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
{
const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->gpos);
const PosLookup &l = gpos.get_lookup (lookup_index);
return l.dispatch (c);
}
inline bool PosLookup::apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index)
/*static*/ inline bool PosLookup::apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index)
{
const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->gpos);
const PosLookup &l = gpos.get_lookup (lookup_index);

View File

@ -44,7 +44,7 @@ struct SingleSubstFormat1
for (iter.init (this+coverage); iter.more (); iter.next ()) {
hb_codepoint_t glyph_id = iter.get_glyph ();
if (c->glyphs->has (glyph_id))
c->glyphs->add ((glyph_id + deltaGlyphID) & 0xFFFF);
c->glyphs->add ((glyph_id + deltaGlyphID) & 0xFFFFu);
}
}
@ -55,7 +55,7 @@ struct SingleSubstFormat1
for (iter.init (this+coverage); iter.more (); iter.next ()) {
hb_codepoint_t glyph_id = iter.get_glyph ();
c->input->add (glyph_id);
c->output->add ((glyph_id + deltaGlyphID) & 0xFFFF);
c->output->add ((glyph_id + deltaGlyphID) & 0xFFFFu);
}
}
@ -79,7 +79,7 @@ struct SingleSubstFormat1
/* According to the Adobe Annotated OpenType Suite, result is always
* limited to 16bit. */
glyph_id = (glyph_id + deltaGlyphID) & 0xFFFF;
glyph_id = (glyph_id + deltaGlyphID) & 0xFFFFu;
c->replace_glyph (glyph_id);
return TRACE_RETURN (true);
@ -270,23 +270,34 @@ struct Sequence
inline bool apply (hb_apply_context_t *c) const
{
TRACE_APPLY (this);
if (unlikely (!substitute.len)) return TRACE_RETURN (false);
unsigned int count = substitute.len;
/* TODO:
* Testing shows that Uniscribe actually allows zero-len susbstitute,
* which essentially deletes a glyph. We don't allow for now. It
* can be confusing to the client since the cluster from the deleted
* glyph won't be merged with any output cluster... Also, currently
* buffer->move_to() makes assumptions about this too. Perhaps fix
* in the future after figuring out what to do with the clusters.
*/
if (unlikely (!count)) return TRACE_RETURN (false);
/* Special-case to make it in-place and not consider this
* as a "multiplied" substitution. */
if (unlikely (count == 1))
{
c->replace_glyph (substitute.array[0]);
return TRACE_RETURN (true);
}
unsigned int klass = _hb_glyph_info_is_ligature (&c->buffer->cur()) ?
HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH : 0;
unsigned int count = substitute.len;
if (count == 1) /* Special-case to make it in-place. */
{
c->replace_glyph (substitute.array[0]);
}
else
{
for (unsigned int i = 0; i < count; i++) {
_hb_glyph_info_set_lig_props_for_component (&c->buffer->cur(), i);
c->output_glyph (substitute.array[i], klass);
c->output_glyph_for_component (substitute.array[i], klass);
}
c->buffer->skip_glyph ();
}
return TRACE_RETURN (true);
}
@ -624,7 +635,16 @@ struct Ligature
{
TRACE_APPLY (this);
unsigned int count = component.len;
if (unlikely (count < 1)) return TRACE_RETURN (false);
if (unlikely (!count)) return TRACE_RETURN (false);
/* Special-case to make it in-place and not consider this
* as a "ligated" substitution. */
if (unlikely (count == 1))
{
c->replace_glyph (ligGlyph);
return TRACE_RETURN (true);
}
bool is_mark_ligature = false;
unsigned int total_component_count = 0;
@ -1338,7 +1358,7 @@ GSUB::substitute_finish (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer HB_UNUSE
/* Out-of-class implementation for methods recursing */
inline bool ExtensionSubst::is_reverse (void) const
/*static*/ inline bool ExtensionSubst::is_reverse (void) const
{
unsigned int type = get_type ();
if (unlikely (type == SubstLookupSubTable::Extension))
@ -1347,14 +1367,14 @@ inline bool ExtensionSubst::is_reverse (void) const
}
template <typename context_t>
inline typename context_t::return_t SubstLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
/*static*/ inline typename context_t::return_t SubstLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
{
const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
const SubstLookup &l = gsub.get_lookup (lookup_index);
return l.dispatch (c);
}
inline bool SubstLookup::apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index)
/*static*/ inline bool SubstLookup::apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index)
{
const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
const SubstLookup &l = gsub.get_lookup (lookup_index);

View File

@ -349,11 +349,7 @@ struct hb_apply_context_t
may_skip (const hb_apply_context_t *c,
const hb_glyph_info_t &info) const
{
unsigned int property;
property = _hb_glyph_info_get_glyph_props (&info);
if (!c->match_properties (info.codepoint, property, lookup_props))
if (!c->check_glyph_property (&info, lookup_props))
return SKIP_YES;
if (unlikely (_hb_glyph_info_is_default_ignorable (&info) &&
@ -487,7 +483,6 @@ struct hb_apply_context_t
const hb_glyph_info_t &info = c->buffer->out_info[idx];
matcher_t::may_skip_t skip = matcher.may_skip (c, info);
if (unlikely (skip == matcher_t::SKIP_YES))
continue;
@ -538,10 +533,12 @@ struct hb_apply_context_t
}
inline bool
match_properties (hb_codepoint_t glyph,
unsigned int glyph_props,
check_glyph_property (const hb_glyph_info_t *info,
unsigned int lookup_props) const
{
hb_codepoint_t glyph = info->codepoint;
unsigned int glyph_props = _hb_glyph_info_get_glyph_props (info);
/* Not covered, if, for example, glyph class is ligature and
* lookup_props includes LookupFlags::IgnoreLigatures
*/
@ -554,26 +551,27 @@ struct hb_apply_context_t
return true;
}
inline bool
check_glyph_property (hb_glyph_info_t *info,
unsigned int lookup_props) const
{
unsigned int property;
property = _hb_glyph_info_get_glyph_props (info);
return match_properties (info->codepoint, property, lookup_props);
}
inline void _set_glyph_props (hb_codepoint_t glyph_index,
unsigned int class_guess = 0,
bool ligature = false) const
bool ligature = false,
bool component = false) const
{
unsigned int add_in = _hb_glyph_info_get_glyph_props (&buffer->cur()) &
HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE;
add_in |= HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED;
if (ligature)
{
add_in |= HB_OT_LAYOUT_GLYPH_PROPS_LIGATED;
/* In the only place that the MULTIPLIED bit is used, Uniscribe
* seems to only care about the "last" transformation between
* Ligature and Multiple substitions. Ie. if you ligate, expand,
* and ligate again, it forgives the multiplication and acts as
* if only ligation happened. As such, clear MULTIPLIED bit.
*/
add_in &= ~HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED;
}
if (component)
add_in |= HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED;
if (likely (has_glyph_classes))
_hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | gdef.get_glyph_props (glyph_index));
else if (class_guess)
@ -596,10 +594,10 @@ struct hb_apply_context_t
_set_glyph_props (glyph_index, class_guess, true);
buffer->replace_glyph (glyph_index);
}
inline void output_glyph (hb_codepoint_t glyph_index,
inline void output_glyph_for_component (hb_codepoint_t glyph_index,
unsigned int class_guess) const
{
_set_glyph_props (glyph_index, class_guess);
_set_glyph_props (glyph_index, class_guess, false, true);
buffer->output_glyph (glyph_index);
}
};
@ -882,6 +880,7 @@ static inline void ligate_input (hb_apply_context_t *c,
break;
}
}
TRACE_RETURN (true);
}
static inline bool match_backtrack (hb_apply_context_t *c,
@ -994,7 +993,9 @@ static inline bool apply_lookup (hb_apply_context_t *c,
/* Recursed lookup changed buffer len. Adjust. */
/* end can't go back past the current match position. */
/* end can't go back past the current match position.
* Note: this is only true because we do NOT allow MultipleSubst
* with zero sequence len. */
end = MAX ((int) match_positions[idx] + 1, int (end) + delta);
unsigned int next = idx + 1; /* next now is the position after the recursed lookup. */
@ -2253,8 +2254,8 @@ struct GSUBGPOS
inline unsigned int get_feature_count (void) const
{ return (this+featureList).len; }
inline const Tag& get_feature_tag (unsigned int i) const
{ return (this+featureList).get_tag (i); }
inline hb_tag_t get_feature_tag (unsigned int i) const
{ return i == Index::NOT_FOUND_INDEX ? HB_TAG_NONE : (this+featureList).get_tag (i); }
inline unsigned int get_feature_tags (unsigned int start_offset,
unsigned int *feature_count /* IN/OUT */,
hb_tag_t *feature_tags /* OUT */) const
@ -2279,7 +2280,7 @@ struct GSUBGPOS
protected:
FixedVersion version; /* Version of the GSUB/GPOS table--initially set
* to 0x00010000 */
* to 0x00010000u */
OffsetTo<ScriptList>
scriptList; /* ScriptList table */
OffsetTo<FeatureList>

View File

@ -214,7 +214,7 @@ struct JSTF
protected:
FixedVersion version; /* Version of the JSTF table--initially set
* to 0x00010000 */
* to 0x00010000u */
RecordArrayOf<JstfScript>
scriptList; /* Array of JstfScripts--listed
* alphabetically by ScriptTag */

View File

@ -50,9 +50,11 @@ typedef enum
/* The following are used internally; not derived from GDEF. */
HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED = 0x10u,
HB_OT_LAYOUT_GLYPH_PROPS_LIGATED = 0x20u,
HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED = 0x40u,
HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE = HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED |
HB_OT_LAYOUT_GLYPH_PROPS_LIGATED
HB_OT_LAYOUT_GLYPH_PROPS_LIGATED |
HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED
} hb_ot_layout_glyph_class_mask_t;
@ -182,62 +184,62 @@ enum {
MASK0_GEN_CAT = 0x1Fu
};
inline void
static inline void
_hb_glyph_info_set_unicode_props (hb_glyph_info_t *info, hb_unicode_funcs_t *unicode)
{
/* XXX This shouldn't be inlined, or at least not while is_default_ignorable() is inline. */
info->unicode_props0() = ((unsigned int) unicode->general_category (info->codepoint)) |
(unicode->is_default_ignorable (info->codepoint) ? MASK0_IGNORABLE : 0) |
(info->codepoint == 0x200C ? MASK0_ZWNJ : 0) |
(info->codepoint == 0x200D ? MASK0_ZWJ : 0);
(info->codepoint == 0x200Cu ? MASK0_ZWNJ : 0) |
(info->codepoint == 0x200Du ? MASK0_ZWJ : 0);
info->unicode_props1() = unicode->modified_combining_class (info->codepoint);
}
inline void
static inline void
_hb_glyph_info_set_general_category (hb_glyph_info_t *info,
hb_unicode_general_category_t gen_cat)
{
info->unicode_props0() = (unsigned int) gen_cat | ((info->unicode_props0()) & ~MASK0_GEN_CAT);
}
inline hb_unicode_general_category_t
static inline hb_unicode_general_category_t
_hb_glyph_info_get_general_category (const hb_glyph_info_t *info)
{
return (hb_unicode_general_category_t) (info->unicode_props0() & MASK0_GEN_CAT);
}
inline void
static inline void
_hb_glyph_info_set_modified_combining_class (hb_glyph_info_t *info,
unsigned int modified_class)
{
info->unicode_props1() = modified_class;
}
inline unsigned int
static inline unsigned int
_hb_glyph_info_get_modified_combining_class (const hb_glyph_info_t *info)
{
return info->unicode_props1();
}
inline hb_bool_t
static inline hb_bool_t
_hb_glyph_info_is_default_ignorable (const hb_glyph_info_t *info)
{
return !!(info->unicode_props0() & MASK0_IGNORABLE);
}
inline hb_bool_t
static inline hb_bool_t
_hb_glyph_info_is_zwnj (const hb_glyph_info_t *info)
{
return !!(info->unicode_props0() & MASK0_ZWNJ);
}
inline hb_bool_t
static inline hb_bool_t
_hb_glyph_info_is_zwj (const hb_glyph_info_t *info)
{
return !!(info->unicode_props0() & MASK0_ZWJ);
}
inline void
static inline void
_hb_glyph_info_flip_joiners (hb_glyph_info_t *info)
{
info->unicode_props0() ^= MASK0_ZWNJ | MASK0_ZWJ;
@ -339,31 +341,31 @@ _hb_allocate_lig_id (hb_buffer_t *buffer) {
/* glyph_props: */
inline void
static inline void
_hb_glyph_info_set_glyph_props (hb_glyph_info_t *info, unsigned int props)
{
info->glyph_props() = props;
}
inline unsigned int
static inline unsigned int
_hb_glyph_info_get_glyph_props (const hb_glyph_info_t *info)
{
return info->glyph_props();
}
inline bool
static inline bool
_hb_glyph_info_is_base_glyph (const hb_glyph_info_t *info)
{
return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH);
}
inline bool
static inline bool
_hb_glyph_info_is_ligature (const hb_glyph_info_t *info)
{
return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE);
}
inline bool
static inline bool
_hb_glyph_info_is_mark (const hb_glyph_info_t *info)
{
return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MARK);
@ -381,23 +383,43 @@ _hb_glyph_info_ligated (const hb_glyph_info_t *info)
return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_LIGATED);
}
static inline bool
_hb_glyph_info_multiplied (const hb_glyph_info_t *info)
{
return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED);
}
static inline bool
_hb_glyph_info_ligated_and_didnt_multiply (const hb_glyph_info_t *info)
{
return _hb_glyph_info_ligated (info) && !_hb_glyph_info_multiplied (info);
}
static inline void
_hb_glyph_info_clear_ligated_and_multiplied (hb_glyph_info_t *info)
{
info->glyph_props() &= ~(HB_OT_LAYOUT_GLYPH_PROPS_LIGATED |
HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED);
}
/* Allocation / deallocation. */
inline void
static inline void
_hb_buffer_allocate_unicode_vars (hb_buffer_t *buffer)
{
HB_BUFFER_ALLOCATE_VAR (buffer, unicode_props0);
HB_BUFFER_ALLOCATE_VAR (buffer, unicode_props1);
}
inline void
static inline void
_hb_buffer_deallocate_unicode_vars (hb_buffer_t *buffer)
{
HB_BUFFER_DEALLOCATE_VAR (buffer, unicode_props0);
HB_BUFFER_DEALLOCATE_VAR (buffer, unicode_props1);
}
inline void
static inline void
_hb_buffer_allocate_gsubgpos_vars (hb_buffer_t *buffer)
{
HB_BUFFER_ALLOCATE_VAR (buffer, glyph_props);
@ -405,7 +427,7 @@ _hb_buffer_allocate_gsubgpos_vars (hb_buffer_t *buffer)
HB_BUFFER_ALLOCATE_VAR (buffer, syllable);
}
inline void
static inline void
_hb_buffer_deallocate_gsubgpos_vars (hb_buffer_t *buffer)
{
HB_BUFFER_DEALLOCATE_VAR (buffer, syllable);

View File

@ -327,9 +327,28 @@ hb_ot_layout_language_get_required_feature_index (hb_face_t *face,
unsigned int language_index,
unsigned int *feature_index)
{
const OT::LangSys &l = get_gsubgpos_table (face, table_tag).get_script (script_index).get_lang_sys (language_index);
return hb_ot_layout_language_get_required_feature (face,
table_tag,
script_index,
language_index,
feature_index,
NULL);
}
if (feature_index) *feature_index = l.get_required_feature_index ();
hb_bool_t
hb_ot_layout_language_get_required_feature (hb_face_t *face,
hb_tag_t table_tag,
unsigned int script_index,
unsigned int language_index,
unsigned int *feature_index,
hb_tag_t *feature_tag)
{
const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
unsigned int index = l.get_required_feature_index ();
if (feature_index) *feature_index = index;
if (feature_tag) *feature_tag = g.get_feature_tag (index);
return l.has_required_feature ();
}
@ -468,11 +487,12 @@ _hb_ot_layout_collect_lookups_features (hb_face_t *face,
if (!features)
{
unsigned int required_feature_index;
if (hb_ot_layout_language_get_required_feature_index (face,
if (hb_ot_layout_language_get_required_feature (face,
table_tag,
script_index,
language_index,
&required_feature_index))
&required_feature_index,
NULL))
_hb_ot_layout_collect_lookups_lookups (face,
table_tag,
required_feature_index,

View File

@ -92,9 +92,9 @@ hb_ot_layout_get_ligature_carets (hb_font_t *font,
* GSUB/GPOS feature query and enumeration interface
*/
#define HB_OT_LAYOUT_NO_SCRIPT_INDEX ((unsigned int) 0xFFFF)
#define HB_OT_LAYOUT_NO_FEATURE_INDEX ((unsigned int) 0xFFFF)
#define HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX ((unsigned int) 0xFFFF)
#define HB_OT_LAYOUT_NO_SCRIPT_INDEX 0xFFFFu
#define HB_OT_LAYOUT_NO_FEATURE_INDEX 0xFFFFu
#define HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX 0xFFFFu
unsigned int
hb_ot_layout_table_get_script_tags (hb_face_t *face,
@ -146,6 +146,14 @@ hb_ot_layout_language_get_required_feature_index (hb_face_t *face,
unsigned int language_index,
unsigned int *feature_index);
hb_bool_t
hb_ot_layout_language_get_required_feature (hb_face_t *face,
hb_tag_t table_tag,
unsigned int script_index,
unsigned int language_index,
unsigned int *feature_index,
hb_tag_t *feature_tag);
unsigned int
hb_ot_layout_language_get_feature_indexes (hb_face_t *face,
hb_tag_t table_tag,

View File

@ -153,26 +153,26 @@ struct hb_ot_map_t
};
enum hb_ot_map_feature_flags_t {
F_NONE = 0x0000,
F_GLOBAL = 0x0001,
F_HAS_FALLBACK = 0x0002,
F_MANUAL_ZWJ = 0x0004
F_NONE = 0x0000u,
F_GLOBAL = 0x0001u,
F_HAS_FALLBACK = 0x0002u,
F_MANUAL_ZWJ = 0x0004u
};
/* Macro version for where const is desired. */
#define F_COMBINE(l,r) (hb_ot_map_feature_flags_t ((unsigned int) (l) | (unsigned int) (r)))
inline hb_ot_map_feature_flags_t
static inline hb_ot_map_feature_flags_t
operator | (hb_ot_map_feature_flags_t l, hb_ot_map_feature_flags_t r)
{ return hb_ot_map_feature_flags_t ((unsigned int) l | (unsigned int) r); }
inline hb_ot_map_feature_flags_t
static inline hb_ot_map_feature_flags_t
operator & (hb_ot_map_feature_flags_t l, hb_ot_map_feature_flags_t r)
{ return hb_ot_map_feature_flags_t ((unsigned int) l & (unsigned int) r); }
inline hb_ot_map_feature_flags_t
static inline hb_ot_map_feature_flags_t
operator ~ (hb_ot_map_feature_flags_t r)
{ return hb_ot_map_feature_flags_t (~(unsigned int) r); }
inline hb_ot_map_feature_flags_t&
static inline hb_ot_map_feature_flags_t&
operator |= (hb_ot_map_feature_flags_t &l, hb_ot_map_feature_flags_t r)
{ l = l | r; return l; }
inline hb_ot_map_feature_flags_t&
static inline hb_ot_map_feature_flags_t&
operator &= (hb_ot_map_feature_flags_t& l, hb_ot_map_feature_flags_t r)
{ l = l & r; return l; }

View File

@ -99,6 +99,7 @@ void hb_ot_map_builder_t::add_feature (hb_tag_t tag, unsigned int value,
{
feature_info_t *info = feature_infos.push();
if (unlikely (!info)) return;
if (unlikely (!tag)) return;
info->tag = tag;
info->seq = feature_infos.len;
info->max_value = value;
@ -131,9 +132,25 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m)
{
m.global_mask = 1;
for (unsigned int table_index = 0; table_index < 2; table_index++) {
unsigned int required_feature_index[2];
hb_tag_t required_feature_tag[2];
/* We default to applying required feature in stage 0. If the required
* feature has a tag that is known to the shaper, we apply required feature
* in the stage for that tag.
*/
unsigned int required_feature_stage[2] = {0, 0};
for (unsigned int table_index = 0; table_index < 2; table_index++)
{
m.chosen_script[table_index] = chosen_script[table_index];
m.found_script[table_index] = found_script[table_index];
hb_ot_layout_language_get_required_feature (face,
table_tags[table_index],
script_index[table_index],
language_index[table_index],
&required_feature_index[table_index],
&required_feature_tag[table_index]);
}
if (!feature_infos.len)
@ -141,7 +158,7 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m)
/* Sort features and merge duplicates */
{
feature_infos.sort ();
feature_infos.qsort ();
unsigned int j = 0;
for (unsigned int i = 1; i < feature_infos.len; i++)
if (feature_infos[i].tag != feature_infos[j].tag)
@ -166,7 +183,8 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m)
/* Allocate bits now */
unsigned int next_bit = 1;
for (unsigned int i = 0; i < feature_infos.len; i++) {
for (unsigned int i = 0; i < feature_infos.len; i++)
{
const feature_info_t *info = &feature_infos[i];
unsigned int bits_needed;
@ -184,12 +202,20 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m)
hb_bool_t found = false;
unsigned int feature_index[2];
for (unsigned int table_index = 0; table_index < 2; table_index++)
{
if (required_feature_tag[table_index] == info->tag)
{
required_feature_stage[table_index] = info->stage[table_index];
found = true;
continue;
}
found |= hb_ot_layout_language_find_feature (face,
table_tags[table_index],
script_index[table_index],
language_index[table_index],
info->tag,
&feature_index[table_index]);
}
if (!found && !(info->flags & F_HAS_FALLBACK))
continue;
@ -224,23 +250,21 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m)
add_gsub_pause (NULL);
add_gpos_pause (NULL);
for (unsigned int table_index = 0; table_index < 2; table_index++) {
hb_tag_t table_tag = table_tags[table_index];
for (unsigned int table_index = 0; table_index < 2; table_index++)
{
/* Collect lookup indices for features */
unsigned int required_feature_index;
if (hb_ot_layout_language_get_required_feature_index (face,
table_tag,
script_index[table_index],
language_index[table_index],
&required_feature_index))
m.add_lookups (face, table_index, required_feature_index, 1, true);
unsigned int stage_index = 0;
unsigned int last_num_lookups = 0;
for (unsigned stage = 0; stage < current_stage[table_index]; stage++)
{
if (required_feature_index[table_index] != HB_OT_LAYOUT_NO_FEATURE_INDEX &&
required_feature_stage[table_index] == stage)
m.add_lookups (face, table_index,
required_feature_index[table_index],
1 /* mask */,
true /* auto_zwj */);
for (unsigned i = 0; i < m.features.len; i++)
if (m.features[i].stage[table_index] == stage)
m.add_lookups (face, table_index,
@ -251,7 +275,7 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m)
/* Sort lookups and merge duplicates */
if (last_num_lookups < m.lookups[table_index].len)
{
m.lookups[table_index].sort (last_num_lookups, m.lookups[table_index].len);
m.lookups[table_index].qsort (last_num_lookups, m.lookups[table_index].len);
unsigned int j = last_num_lookups;
for (unsigned int i = j + 1; i < m.lookups[table_index].len; i++)

View File

@ -50,13 +50,13 @@ struct maxp
inline bool sanitize (hb_sanitize_context_t *c) {
TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this) &&
likely (version.major == 1 || (version.major == 0 && version.minor == 0x5000)));
likely (version.major == 1 || (version.major == 0 && version.minor == 0x5000u)));
}
/* We only implement version 0.5 as none of the extra fields in version 1.0 are useful. */
protected:
FixedVersion version; /* Version of the maxp table (0.5 or 1.0),
* 0x00005000 or 0x00010000. */
* 0x00005000u or 0x00010000u. */
USHORT numGlyphs; /* The number of glyphs in the font. */
public:
DEFINE_SIZE_STATIC (6);

View File

@ -121,7 +121,7 @@ struct name
/* We only implement format 0 for now. */
USHORT format; /* Format selector (=0/1). */
USHORT count; /* Number of name records. */
Offset stringOffset; /* Offset to start of string storage (from start of table). */
Offset<> stringOffset; /* Offset to start of string storage (from start of table). */
NameRecord nameRecord[VAR]; /* The name records where count is the number of records. */
public:
DEFINE_SIZE_ARRAY (6, nameRecord);

View File

@ -71,7 +71,7 @@ arabic_fallback_synthesize_lookup_single (const hb_ot_shape_plan_t *plan HB_UNUS
!hb_font_get_glyph (font, u, 0, &u_glyph) ||
!hb_font_get_glyph (font, s, 0, &s_glyph) ||
u_glyph == s_glyph ||
u_glyph > 0xFFFF || s_glyph > 0xFFFF)
u_glyph > 0xFFFFu || s_glyph > 0xFFFFu)
continue;
glyphs[num_glyphs].set (u_glyph);

File diff suppressed because it is too large Load Diff

View File

@ -57,68 +57,41 @@ enum {
static unsigned int get_joining_type (hb_codepoint_t u, hb_unicode_general_category_t gen_cat)
{
if (likely (hb_in_range<hb_codepoint_t> (u, JOINING_TABLE_FIRST, JOINING_TABLE_LAST))) {
unsigned int j_type = joining_table[u - JOINING_TABLE_FIRST];
unsigned int j_type = joining_type(u);
if (likely (j_type != JOINING_TYPE_X))
return j_type;
return (FLAG(gen_cat) &
(FLAG(HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) |
FLAG(HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK) |
FLAG(HB_UNICODE_GENERAL_CATEGORY_FORMAT))
) ? JOINING_TYPE_T : JOINING_TYPE_U;
}
/* Mongolian joining data is not in ArabicJoining.txt yet. */
if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x1800, 0x18AF)))
{
if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x1880, 0x1886)))
return JOINING_TYPE_U;
/* All letters, SIBE SYLLABLE BOUNDARY MARKER, and NIRUGU are D */
if ((FLAG(gen_cat) & (FLAG (HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER) |
FLAG (HB_UNICODE_GENERAL_CATEGORY_MODIFIER_LETTER)))
|| u == 0x1807 || u == 0x180A)
return JOINING_TYPE_D;
}
/* 'Phags-pa joining data is not in ArabicJoining.txt yet. */
if (unlikely (hb_in_range<hb_codepoint_t> (u, 0xA840, 0xA872)))
{
if (unlikely (u == 0xA872))
return JOINING_TYPE_L;
return JOINING_TYPE_D;
}
if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x200C, 0x200D)))
{
return u == 0x200C ? JOINING_TYPE_U : JOINING_TYPE_C;
}
return (FLAG(gen_cat) & (FLAG(HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) | FLAG(HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK) | FLAG(HB_UNICODE_GENERAL_CATEGORY_FORMAT))) ?
JOINING_TYPE_T : JOINING_TYPE_U;
}
#define FEATURE_IS_SYRIAC(tag) hb_in_range<unsigned char> ((unsigned char) (tag), '2', '3')
static const hb_tag_t arabic_features[] =
{
HB_TAG('i','n','i','t'),
HB_TAG('m','e','d','i'),
HB_TAG('f','i','n','a'),
HB_TAG('i','s','o','l'),
/* Syriac */
HB_TAG('m','e','d','2'),
HB_TAG('f','i','n','a'),
HB_TAG('f','i','n','2'),
HB_TAG('f','i','n','3'),
HB_TAG('m','e','d','i'),
HB_TAG('m','e','d','2'),
HB_TAG('i','n','i','t'),
HB_TAG_NONE
};
/* Same order as the feature array */
enum {
INIT,
MEDI,
FINA,
ISOL,
/* Syriac */
MED2,
FINA,
FIN2,
FIN3,
MEDI,
MED2,
INIT,
NONE,
@ -171,14 +144,23 @@ collect_features_arabic (hb_ot_shape_planner_t *plan)
{
hb_ot_map_builder_t *map = &plan->map;
/* For Language forms (in ArabicOT speak), we do the iso/fina/medi/init together,
* then rlig and calt each in their own stage. This makes IranNastaliq's ALLAH
* ligature work correctly. It's unfortunate though...
/* We apply features according to the Arabic spec, with pauses
* in between most.
*
* This also makes Arial Bold in Windows7 work. See:
* The pause between init/medi/... and rlig is required. See eg:
* https://bugzilla.mozilla.org/show_bug.cgi?id=644184
*
* TODO: Add test cases for these two.
* The pauses between init/medi/... themselves are not necessarily
* needed as only one of those features is applied to any character.
* The only difference it makes is when fonts have contextual
* substitutions. We now follow the order of the spec, which makes
* for better experience if that's what Uniscribe is doing.
*
* At least for Arabic, looks like Uniscribe has a pause between
* rlig and calt. Otherwise the IranNastaliq's ALLAH ligature won't
* work. However, testing shows that rlig and calt are applied
* together for Mongolian in Uniscribe. As such, we only add a
* pause for Arabic, not other scripts.
*/
map->add_gsub_pause (nuke_joiners);
@ -189,16 +171,28 @@ collect_features_arabic (hb_ot_shape_planner_t *plan)
map->add_gsub_pause (NULL);
for (unsigned int i = 0; i < ARABIC_NUM_FEATURES; i++)
map->add_feature (arabic_features[i], 1, i < 4 ? F_HAS_FALLBACK : F_NONE); /* The first four features have fallback. */
{
bool has_fallback = plan->props.script == HB_SCRIPT_ARABIC && !FEATURE_IS_SYRIAC (arabic_features[i]);
map->add_feature (arabic_features[i], 1, has_fallback ? F_HAS_FALLBACK : F_NONE);
map->add_gsub_pause (NULL);
}
map->add_feature (HB_TAG('r','l','i','g'), 1, F_GLOBAL|F_HAS_FALLBACK);
if (plan->props.script == HB_SCRIPT_ARABIC)
map->add_gsub_pause (arabic_fallback_shape);
map->add_global_bool_feature (HB_TAG('c','a','l','t'));
map->add_gsub_pause (NULL);
/* The spec includes 'cswh'. Earlier versions of Windows
* used to enable this by default, but testing suggests
* that Windows 8 and later do not enable it by default,
* and spec now says 'Off by default'.
* We disabled this in ae23c24c32.
* Note that IranNastaliq uses this feature extensively
* to fixup broken glyph sequences. Oh well...
* Test case: U+0643,U+0640,U+0631. */
//map->add_global_bool_feature (HB_TAG('c','s','w','h'));
map->add_global_bool_feature (HB_TAG('m','s','e','t'));
}
@ -228,8 +222,9 @@ data_create_arabic (const hb_ot_shape_plan_t *plan)
arabic_plan->do_fallback = plan->props.script == HB_SCRIPT_ARABIC;
for (unsigned int i = 0; i < ARABIC_NUM_FEATURES; i++) {
arabic_plan->mask_array[i] = plan->map.get_1_mask (arabic_features[i]);
if (i < 4)
arabic_plan->do_fallback = arabic_plan->do_fallback && plan->map.needs_fallback (arabic_features[i]);
arabic_plan->do_fallback = arabic_plan->do_fallback &&
!FEATURE_IS_SYRIAC (arabic_features[i]) &&
plan->map.needs_fallback (arabic_features[i]);
}
return arabic_plan;
@ -249,10 +244,9 @@ static void
arabic_joining (hb_buffer_t *buffer)
{
unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
unsigned int prev = (unsigned int) -1, state = 0;
HB_BUFFER_ALLOCATE_VAR (buffer, arabic_shaping_action);
/* Check pre-context */
if (!(buffer->flags & HB_BUFFER_FLAG_BOT))
for (unsigned int i = 0; i < buffer->context_len[0]; i++)
@ -269,20 +263,19 @@ arabic_joining (hb_buffer_t *buffer)
for (unsigned int i = 0; i < count; i++)
{
unsigned int this_type = get_joining_type (buffer->info[i].codepoint, _hb_glyph_info_get_general_category (&buffer->info[i]));
unsigned int this_type = get_joining_type (info[i].codepoint, _hb_glyph_info_get_general_category (&info[i]));
if (unlikely (this_type == JOINING_TYPE_T)) {
buffer->info[i].arabic_shaping_action() = NONE;
info[i].arabic_shaping_action() = NONE;
continue;
}
const arabic_state_table_entry *entry = &arabic_state_table[state][this_type];
if (entry->prev_action != NONE && prev != (unsigned int) -1)
for (; prev < i; prev++)
buffer->info[prev].arabic_shaping_action() = entry->prev_action;
info[prev].arabic_shaping_action() = entry->prev_action;
buffer->info[i].arabic_shaping_action() = entry->curr_action;
info[i].arabic_shaping_action() = entry->curr_action;
prev = i;
state = entry->next_state;
@ -298,12 +291,20 @@ arabic_joining (hb_buffer_t *buffer)
const arabic_state_table_entry *entry = &arabic_state_table[state][this_type];
if (entry->prev_action != NONE && prev != (unsigned int) -1)
buffer->info[prev].arabic_shaping_action() = entry->prev_action;
info[prev].arabic_shaping_action() = entry->prev_action;
break;
}
}
HB_BUFFER_DEALLOCATE_VAR (buffer, arabic_shaping_action);
static void
mongolian_variation_selectors (hb_buffer_t *buffer)
{
/* Copy arabic_shaping_action() from base to Mongolian variation selectors. */
unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
for (unsigned int i = 1; i < count; i++)
if (unlikely (hb_in_range (info[i].codepoint, 0x180Bu, 0x180Du)))
info[i].arabic_shaping_action() = info[i - 1].arabic_shaping_action();
}
static void
@ -311,12 +312,20 @@ setup_masks_arabic (const hb_ot_shape_plan_t *plan,
hb_buffer_t *buffer,
hb_font_t *font HB_UNUSED)
{
HB_BUFFER_ALLOCATE_VAR (buffer, arabic_shaping_action);
const arabic_shape_plan_t *arabic_plan = (const arabic_shape_plan_t *) plan->data;
arabic_joining (buffer);
if (plan->props.script == HB_SCRIPT_MONGOLIAN)
mongolian_variation_selectors (buffer);
unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
for (unsigned int i = 0; i < count; i++)
buffer->info[i].mask |= arabic_plan->mask_array[buffer->info[i].arabic_shaping_action()];
info[i].mask |= arabic_plan->mask_array[info[i].arabic_shaping_action()];
HB_BUFFER_DEALLOCATE_VAR (buffer, arabic_shaping_action);
}
@ -326,9 +335,10 @@ nuke_joiners (const hb_ot_shape_plan_t *plan HB_UNUSED,
hb_buffer_t *buffer)
{
unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
for (unsigned int i = 0; i < count; i++)
if (_hb_glyph_info_is_zwj (&buffer->info[i]))
_hb_glyph_info_flip_joiners (&buffer->info[i]);
if (_hb_glyph_info_is_zwj (&info[i]))
_hb_glyph_info_flip_joiners (&info[i]);
}
static void

View File

@ -86,26 +86,26 @@ data_destroy_hangul (void *data)
}
/* Constants for algorithmic hangul syllable [de]composition. */
#define LBase 0x1100
#define VBase 0x1161
#define TBase 0x11A7
#define LCount 19
#define VCount 21
#define TCount 28
#define SBase 0xAC00
#define LBase 0x1100u
#define VBase 0x1161u
#define TBase 0x11A7u
#define LCount 19u
#define VCount 21u
#define TCount 28u
#define SBase 0xAC00u
#define NCount (VCount * TCount)
#define SCount (LCount * NCount)
#define isCombiningL(u) (hb_in_range<hb_codepoint_t> ((u), LBase, LBase+LCount-1))
#define isCombiningV(u) (hb_in_range<hb_codepoint_t> ((u), VBase, VBase+VCount-1))
#define isCombiningT(u) (hb_in_range<hb_codepoint_t> ((u), TBase+1, TBase+TCount-1))
#define isCombinedS(u) (hb_in_range<hb_codepoint_t> ((u), SBase, SBase+SCount-1))
#define isCombiningL(u) (hb_in_range ((u), LBase, LBase+LCount-1))
#define isCombiningV(u) (hb_in_range ((u), VBase, VBase+VCount-1))
#define isCombiningT(u) (hb_in_range ((u), TBase+1, TBase+TCount-1))
#define isCombinedS(u) (hb_in_range ((u), SBase, SBase+SCount-1))
#define isL(u) (hb_in_ranges<hb_codepoint_t> ((u), 0x1100, 0x115F, 0xA960, 0xA97C))
#define isV(u) (hb_in_ranges<hb_codepoint_t> ((u), 0x1160, 0x11A7, 0xD7B0, 0xD7C6))
#define isT(u) (hb_in_ranges<hb_codepoint_t> ((u), 0x11A8, 0x11FF, 0xD7CB, 0xD7FB))
#define isL(u) (hb_in_ranges ((u), 0x1100u, 0x115Fu, 0xA960u, 0xA97Cu))
#define isV(u) (hb_in_ranges ((u), 0x1160u, 0x11A7u, 0xD7B0u, 0xD7C6u))
#define isT(u) (hb_in_ranges ((u), 0x11A8u, 0x11FFu, 0xD7CBu, 0xD7FBu))
#define isHangulTone(u) (hb_in_range<hb_codepoint_t> ((u), 0x302e, 0x302f))
#define isHangulTone(u) (hb_in_range ((u), 0x302Eu, 0x302Fu))
/* buffer var allocations */
#define hangul_shaping_feature() complex_var_u8_0() /* hangul jamo shaping feature */
@ -211,14 +211,14 @@ preprocess_text_hangul (const hb_ot_shape_plan_t *plan,
else
{
/* No valid syllable as base for tone mark; try to insert dotted circle. */
if (font->has_glyph (0x25cc))
if (font->has_glyph (0x25CCu))
{
hb_codepoint_t chars[2];
if (!is_zero_width_char (font, u)) {
chars[0] = u;
chars[1] = 0x25cc;
chars[1] = 0x25CCu;
} else {
chars[0] = 0x25cc;
chars[0] = 0x25CCu;
chars[1] = u;
}
buffer->replace_glyphs (1, 2, chars);

View File

@ -35,116 +35,116 @@ compose_hebrew (const hb_ot_shape_normalize_context_t *c,
{
/* Hebrew presentation-form shaping.
* https://bugzilla.mozilla.org/show_bug.cgi?id=728866
* Hebrew presentation forms with dagesh, for characters 0x05D0..0x05EA;
* Hebrew presentation forms with dagesh, for characters U+05D0..05EA;
* Note that some letters do not have a dagesh presForm encoded.
*/
static const hb_codepoint_t sDageshForms[0x05EA - 0x05D0 + 1] = {
0xFB30, /* ALEF */
0xFB31, /* BET */
0xFB32, /* GIMEL */
0xFB33, /* DALET */
0xFB34, /* HE */
0xFB35, /* VAV */
0xFB36, /* ZAYIN */
0x0000, /* HET */
0xFB38, /* TET */
0xFB39, /* YOD */
0xFB3A, /* FINAL KAF */
0xFB3B, /* KAF */
0xFB3C, /* LAMED */
0x0000, /* FINAL MEM */
0xFB3E, /* MEM */
0x0000, /* FINAL NUN */
0xFB40, /* NUN */
0xFB41, /* SAMEKH */
0x0000, /* AYIN */
0xFB43, /* FINAL PE */
0xFB44, /* PE */
0x0000, /* FINAL TSADI */
0xFB46, /* TSADI */
0xFB47, /* QOF */
0xFB48, /* RESH */
0xFB49, /* SHIN */
0xFB4A /* TAV */
static const hb_codepoint_t sDageshForms[0x05EAu - 0x05D0u + 1] = {
0xFB30u, /* ALEF */
0xFB31u, /* BET */
0xFB32u, /* GIMEL */
0xFB33u, /* DALET */
0xFB34u, /* HE */
0xFB35u, /* VAV */
0xFB36u, /* ZAYIN */
0x0000u, /* HET */
0xFB38u, /* TET */
0xFB39u, /* YOD */
0xFB3Au, /* FINAL KAF */
0xFB3Bu, /* KAF */
0xFB3Cu, /* LAMED */
0x0000u, /* FINAL MEM */
0xFB3Eu, /* MEM */
0x0000u, /* FINAL NUN */
0xFB40u, /* NUN */
0xFB41u, /* SAMEKH */
0x0000u, /* AYIN */
0xFB43u, /* FINAL PE */
0xFB44u, /* PE */
0x0000u, /* FINAL TSADI */
0xFB46u, /* TSADI */
0xFB47u, /* QOF */
0xFB48u, /* RESH */
0xFB49u, /* SHIN */
0xFB4Au /* TAV */
};
bool found = c->unicode->compose (a, b, ab);
if (!found)
if (!found && !c->plan->has_mark)
{
/* Special-case Hebrew presentation forms that are excluded from
* standard normalization, but wanted for old fonts. */
switch (b) {
case 0x05B4: /* HIRIQ */
if (a == 0x05D9) { /* YOD */
*ab = 0xFB1D;
case 0x05B4u: /* HIRIQ */
if (a == 0x05D9u) { /* YOD */
*ab = 0xFB1Du;
found = true;
}
break;
case 0x05B7: /* patah */
if (a == 0x05F2) { /* YIDDISH YOD YOD */
*ab = 0xFB1F;
case 0x05B7u: /* patah */
if (a == 0x05F2u) { /* YIDDISH YOD YOD */
*ab = 0xFB1Fu;
found = true;
} else if (a == 0x05D0) { /* ALEF */
*ab = 0xFB2E;
} else if (a == 0x05D0u) { /* ALEF */
*ab = 0xFB2Eu;
found = true;
}
break;
case 0x05B8: /* QAMATS */
if (a == 0x05D0) { /* ALEF */
*ab = 0xFB2F;
case 0x05B8u: /* QAMATS */
if (a == 0x05D0u) { /* ALEF */
*ab = 0xFB2Fu;
found = true;
}
break;
case 0x05B9: /* HOLAM */
if (a == 0x05D5) { /* VAV */
*ab = 0xFB4B;
case 0x05B9u: /* HOLAM */
if (a == 0x05D5u) { /* VAV */
*ab = 0xFB4Bu;
found = true;
}
break;
case 0x05BC: /* DAGESH */
if (a >= 0x05D0 && a <= 0x05EA) {
*ab = sDageshForms[a - 0x05D0];
case 0x05BCu: /* DAGESH */
if (a >= 0x05D0u && a <= 0x05EAu) {
*ab = sDageshForms[a - 0x05D0u];
found = (*ab != 0);
} else if (a == 0xFB2A) { /* SHIN WITH SHIN DOT */
*ab = 0xFB2C;
} else if (a == 0xFB2Au) { /* SHIN WITH SHIN DOT */
*ab = 0xFB2Cu;
found = true;
} else if (a == 0xFB2B) { /* SHIN WITH SIN DOT */
*ab = 0xFB2D;
} else if (a == 0xFB2Bu) { /* SHIN WITH SIN DOT */
*ab = 0xFB2Du;
found = true;
}
break;
case 0x05BF: /* RAFE */
case 0x05BFu: /* RAFE */
switch (a) {
case 0x05D1: /* BET */
*ab = 0xFB4C;
case 0x05D1u: /* BET */
*ab = 0xFB4Cu;
found = true;
break;
case 0x05DB: /* KAF */
*ab = 0xFB4D;
case 0x05DBu: /* KAF */
*ab = 0xFB4Du;
found = true;
break;
case 0x05E4: /* PE */
*ab = 0xFB4E;
case 0x05E4u: /* PE */
*ab = 0xFB4Eu;
found = true;
break;
}
break;
case 0x05C1: /* SHIN DOT */
if (a == 0x05E9) { /* SHIN */
*ab = 0xFB2A;
case 0x05C1u: /* SHIN DOT */
if (a == 0x05E9u) { /* SHIN */
*ab = 0xFB2Au;
found = true;
} else if (a == 0xFB49) { /* SHIN WITH DAGESH */
*ab = 0xFB2C;
} else if (a == 0xFB49u) { /* SHIN WITH DAGESH */
*ab = 0xFB2Cu;
found = true;
}
break;
case 0x05C2: /* SIN DOT */
if (a == 0x05E9) { /* SHIN */
*ab = 0xFB2B;
case 0x05C2u: /* SIN DOT */
if (a == 0x05E9u) { /* SHIN */
*ab = 0xFB2Bu;
found = true;
} else if (a == 0xFB49) { /* SHIN WITH DAGESH */
*ab = 0xFB2D;
} else if (a == 0xFB49u) { /* SHIN WITH DAGESH */
*ab = 0xFB2Du;
found = true;
}
break;

File diff suppressed because it is too large Load Diff

View File

@ -53,17 +53,29 @@ enum indic_category_t {
OT_SM = 8,
OT_VD = 9,
OT_A = 10,
OT_NBSP = 11,
OT_PLACEHOLDER = 11,
OT_DOTTEDCIRCLE = 12,
OT_RS = 13, /* Register Shifter, used in Khmer OT spec. */
OT_Coeng = 14, /* Khmer-style Virama. */
OT_Repha = 15, /* Atomically-encoded logical or visual repha. */
OT_Ra = 16,
OT_CM = 17, /* Consonant-Medial. */
OT_Avag = 18, /* Avagraha. */
OT_Symbol = 18, /* Avagraha, etc that take marks (SM,A,VD). */
OT_CM2 = 31 /* Consonant-Medial, second slot. */
};
#define MEDIAL_FLAGS (FLAG (OT_CM) | FLAG (OT_CM2))
/* Note:
*
* We treat Vowels and placeholders as if they were consonants. This is safe because Vowels
* cannot happen in a consonant syllable. The plus side however is, we can call the
* consonant syllable logic from the vowel syllable function and get it all right! */
#define CONSONANT_FLAGS (FLAG (OT_C) | FLAG (OT_Ra) | MEDIAL_FLAGS | FLAG (OT_V) | FLAG (OT_PLACEHOLDER) | FLAG (OT_DOTTEDCIRCLE))
#define JOINER_FLAGS (FLAG (OT_ZWJ) | FLAG (OT_ZWNJ))
#define HALANT_OR_COENG_FLAGS (FLAG (OT_H) | FLAG (OT_Coeng))
/* Visual positions in a syllable from left to right. */
enum indic_position_t {
POS_START,
@ -95,18 +107,28 @@ enum indic_position_t {
enum indic_syllabic_category_t {
INDIC_SYLLABIC_CATEGORY_OTHER = OT_X,
INDIC_SYLLABIC_CATEGORY_AVAGRAHA = OT_Avag,
INDIC_SYLLABIC_CATEGORY_AVAGRAHA = OT_Symbol,
INDIC_SYLLABIC_CATEGORY_BINDU = OT_SM,
INDIC_SYLLABIC_CATEGORY_BRAHMI_JOINING_NUMBER = OT_PLACEHOLDER, /* TODO */
INDIC_SYLLABIC_CATEGORY_CANTILLATION_MARK = OT_A,
INDIC_SYLLABIC_CATEGORY_CONSONANT = OT_C,
INDIC_SYLLABIC_CATEGORY_CONSONANT_DEAD = OT_C,
INDIC_SYLLABIC_CATEGORY_CONSONANT_FINAL = OT_CM,
INDIC_SYLLABIC_CATEGORY_CONSONANT_HEAD_LETTER = OT_C,
INDIC_SYLLABIC_CATEGORY_CONSONANT_MEDIAL = OT_CM,
INDIC_SYLLABIC_CATEGORY_CONSONANT_PLACEHOLDER = OT_NBSP,
INDIC_SYLLABIC_CATEGORY_CONSONANT_PLACEHOLDER = OT_PLACEHOLDER,
INDIC_SYLLABIC_CATEGORY_CONSONANT_PRECEDING_REPHA = OT_Repha,
INDIC_SYLLABIC_CATEGORY_CONSONANT_SUBJOINED = OT_CM,
INDIC_SYLLABIC_CATEGORY_CONSONANT_REPHA = OT_Repha,
INDIC_SYLLABIC_CATEGORY_CONSONANT_SUCCEEDING_REPHA = OT_N,
INDIC_SYLLABIC_CATEGORY_GEMINATION_MARK = OT_SM,
INDIC_SYLLABIC_CATEGORY_INVISIBLE_STACKER = OT_H, /* TODO */
INDIC_SYLLABIC_CATEGORY_JOINER = OT_ZWJ,
INDIC_SYLLABIC_CATEGORY_MODIFYING_LETTER = OT_X,
INDIC_SYLLABIC_CATEGORY_NON_JOINER = OT_ZWNJ,
INDIC_SYLLABIC_CATEGORY_NUKTA = OT_N,
INDIC_SYLLABIC_CATEGORY_NUMBER = OT_PLACEHOLDER,
INDIC_SYLLABIC_CATEGORY_NUMBER_JOINER = OT_PLACEHOLDER, /* TODO */
INDIC_SYLLABIC_CATEGORY_PURE_KILLER = OT_H, /* TODO */
INDIC_SYLLABIC_CATEGORY_REGISTER_SHIFTER = OT_RS,
INDIC_SYLLABIC_CATEGORY_TONE_LETTER = OT_X,
INDIC_SYLLABIC_CATEGORY_TONE_MARK = OT_N,
@ -135,7 +157,6 @@ enum indic_matra_category_t {
INDIC_MATRA_CATEGORY_TOP_AND_LEFT_AND_RIGHT = INDIC_MATRA_CATEGORY_RIGHT,
INDIC_MATRA_CATEGORY_TOP_AND_RIGHT = INDIC_MATRA_CATEGORY_RIGHT,
INDIC_MATRA_CATEGORY_INVISIBLE = INDIC_MATRA_CATEGORY_NOT_APPLICABLE,
INDIC_MATRA_CATEGORY_OVERSTRUCK = POS_AFTER_MAIN,
INDIC_MATRA_CATEGORY_VISUAL_ORDER_LEFT = POS_PRE_M
};
@ -143,7 +164,15 @@ enum indic_matra_category_t {
/* Note: We use ASSERT_STATIC_EXPR_ZERO() instead of ASSERT_STATIC_EXPR() and the comma operation
* because gcc fails to optimize the latter and fills the table in at runtime. */
#define INDIC_COMBINE_CATEGORIES(S,M) \
(ASSERT_STATIC_EXPR_ZERO (M == INDIC_MATRA_CATEGORY_NOT_APPLICABLE || (S == INDIC_SYLLABIC_CATEGORY_VIRAMA || S == INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT)) + \
(ASSERT_STATIC_EXPR_ZERO (M == INDIC_MATRA_CATEGORY_NOT_APPLICABLE || \
( \
S == INDIC_SYLLABIC_CATEGORY_CONSONANT_MEDIAL || \
S == INDIC_SYLLABIC_CATEGORY_GEMINATION_MARK || \
S == INDIC_SYLLABIC_CATEGORY_REGISTER_SHIFTER || \
S == INDIC_SYLLABIC_CATEGORY_CONSONANT_SUCCEEDING_REPHA || \
S == INDIC_SYLLABIC_CATEGORY_VIRAMA || \
S == INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT || \
false)) + \
ASSERT_STATIC_EXPR_ZERO (S < 255 && M < 255) + \
((M << 8) | S))

File diff suppressed because it is too large Load Diff

View File

@ -37,19 +37,19 @@
*/
#define IN_HALF_BLOCK(u, Base) (((u) & ~0x7F) == (Base))
#define IN_HALF_BLOCK(u, Base) (((u) & ~0x7Fu) == (Base))
#define IS_DEVA(u) (IN_HALF_BLOCK (u, 0x0900))
#define IS_BENG(u) (IN_HALF_BLOCK (u, 0x0980))
#define IS_GURU(u) (IN_HALF_BLOCK (u, 0x0A00))
#define IS_GUJR(u) (IN_HALF_BLOCK (u, 0x0A80))
#define IS_ORYA(u) (IN_HALF_BLOCK (u, 0x0B00))
#define IS_TAML(u) (IN_HALF_BLOCK (u, 0x0B80))
#define IS_TELU(u) (IN_HALF_BLOCK (u, 0x0C00))
#define IS_KNDA(u) (IN_HALF_BLOCK (u, 0x0C80))
#define IS_MLYM(u) (IN_HALF_BLOCK (u, 0x0D00))
#define IS_SINH(u) (IN_HALF_BLOCK (u, 0x0D80))
#define IS_KHMR(u) (IN_HALF_BLOCK (u, 0x1780))
#define IS_DEVA(u) (IN_HALF_BLOCK (u, 0x0900u))
#define IS_BENG(u) (IN_HALF_BLOCK (u, 0x0980u))
#define IS_GURU(u) (IN_HALF_BLOCK (u, 0x0A00u))
#define IS_GUJR(u) (IN_HALF_BLOCK (u, 0x0A80u))
#define IS_ORYA(u) (IN_HALF_BLOCK (u, 0x0B00u))
#define IS_TAML(u) (IN_HALF_BLOCK (u, 0x0B80u))
#define IS_TELU(u) (IN_HALF_BLOCK (u, 0x0C00u))
#define IS_KNDA(u) (IN_HALF_BLOCK (u, 0x0C80u))
#define IS_MLYM(u) (IN_HALF_BLOCK (u, 0x0D00u))
#define IS_SINH(u) (IN_HALF_BLOCK (u, 0x0D80u))
#define IS_KHMR(u) (IN_HALF_BLOCK (u, 0x1780u))
#define MATRA_POS_LEFT(u) POS_PRE_M
@ -60,8 +60,8 @@
IS_GUJR(u) ? POS_AFTER_POST : \
IS_ORYA(u) ? POS_AFTER_POST : \
IS_TAML(u) ? POS_AFTER_POST : \
IS_TELU(u) ? (u <= 0x0C42 ? POS_BEFORE_SUB : POS_AFTER_SUB) : \
IS_KNDA(u) ? (u < 0x0CC3 || u > 0xCD6 ? POS_BEFORE_SUB : POS_AFTER_SUB) : \
IS_TELU(u) ? (u <= 0x0C42u ? POS_BEFORE_SUB : POS_AFTER_SUB) : \
IS_KNDA(u) ? (u < 0x0CC3u || u > 0xCD6u ? POS_BEFORE_SUB : POS_AFTER_SUB) : \
IS_MLYM(u) ? POS_AFTER_POST : \
IS_SINH(u) ? POS_AFTER_SUB : \
IS_KHMR(u) ? POS_AFTER_POST : \
@ -112,20 +112,20 @@ matra_position (hb_codepoint_t u, indic_position_t side)
* Or completely remove it and just check in the tables.
*/
static const hb_codepoint_t ra_chars[] = {
0x0930, /* Devanagari */
0x09B0, /* Bengali */
0x09F0, /* Bengali */
0x0A30, /* Gurmukhi */ /* No Reph */
0x0AB0, /* Gujarati */
0x0B30, /* Oriya */
0x0BB0, /* Tamil */ /* No Reph */
0x0C30, /* Telugu */ /* Reph formed only with ZWJ */
0x0CB0, /* Kannada */
0x0D30, /* Malayalam */ /* No Reph, Logical Repha */
0x0930u, /* Devanagari */
0x09B0u, /* Bengali */
0x09F0u, /* Bengali */
0x0A30u, /* Gurmukhi */ /* No Reph */
0x0AB0u, /* Gujarati */
0x0B30u, /* Oriya */
0x0BB0u, /* Tamil */ /* No Reph */
0x0C30u, /* Telugu */ /* Reph formed only with ZWJ */
0x0CB0u, /* Kannada */
0x0D30u, /* Malayalam */ /* No Reph, Logical Repha */
0x0DBB, /* Sinhala */ /* Reph formed only with ZWJ */
0x0DBBu, /* Sinhala */ /* Reph formed only with ZWJ */
0x179A, /* Khmer */ /* No Reph, Visual Repha */
0x179Au, /* Khmer */ /* No Reph, Visual Repha */
};
static inline bool
@ -145,28 +145,18 @@ is_one_of (const hb_glyph_info_t &info, unsigned int flags)
return !!(FLAG (info.indic_category()) & flags);
}
#define JOINER_FLAGS (FLAG (OT_ZWJ) | FLAG (OT_ZWNJ))
static inline bool
is_joiner (const hb_glyph_info_t &info)
{
return is_one_of (info, JOINER_FLAGS);
}
#define MEDIAL_FLAGS (FLAG (OT_CM) | FLAG (OT_CM2))
/* Note:
*
* We treat Vowels and placeholders as if they were consonants. This is safe because Vowels
* cannot happen in a consonant syllable. The plus side however is, we can call the
* consonant syllable logic from the vowel syllable function and get it all right! */
#define CONSONANT_FLAGS (FLAG (OT_C) | FLAG (OT_Ra) | MEDIAL_FLAGS | FLAG (OT_V) | FLAG (OT_NBSP) | FLAG (OT_DOTTEDCIRCLE))
static inline bool
is_consonant (const hb_glyph_info_t &info)
{
return is_one_of (info, CONSONANT_FLAGS);
}
#define HALANT_OR_COENG_FLAGS (FLAG (OT_H) | FLAG (OT_Coeng))
static inline bool
is_halant_or_coeng (const hb_glyph_info_t &info)
{
@ -178,7 +168,7 @@ set_indic_properties (hb_glyph_info_t &info)
{
hb_codepoint_t u = info.codepoint;
unsigned int type = hb_indic_get_categories (u);
indic_category_t cat = (indic_category_t) (type & 0x7F);
indic_category_t cat = (indic_category_t) (type & 0x7Fu);
indic_position_t pos = (indic_position_t) (type >> 8);
@ -188,48 +178,59 @@ set_indic_properties (hb_glyph_info_t &info)
/* The spec says U+0952 is OT_A. However, testing shows that Uniscribe
* treats U+0951..U+0954 all behave similarly.
* TESTS:
* treats a whole bunch of characters similarly.
* TESTS: For example, for U+0951:
* U+092E,U+0947,U+0952
* U+092E,U+0952,U+0947
* U+092E,U+0947,U+0951
* U+092E,U+0951,U+0947
* U+092E,U+0951,U+0952
* U+092E,U+0952,U+0951
*/
if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x0951, 0x0954)))
if (unlikely (hb_in_ranges (u, 0x0951u, 0x0952u,
0x1CD0u, 0x1CD2u,
0x1CD4u, 0x1CE1u) ||
u == 0x1CF4u))
cat = OT_A;
if (unlikely (u == 0x17D1))
cat = OT_X;
if (cat == OT_X &&
unlikely (hb_in_range<hb_codepoint_t> (u, 0x17CB, 0x17D3))) /* Khmer Various signs */
/* The following act more like the Bindus. */
else if (unlikely (hb_in_range (u, 0x0953u, 0x0954u)))
cat = OT_SM;
/* The following act like consonants. */
else if (unlikely (hb_in_ranges (u, 0x0A72u, 0x0A73u,
0x1CF5u, 0x1CF6u)))
cat = OT_C;
/* TODO: The following should only be allowed after a Visarga.
* For now, just treat them like regular tone marks. */
else if (unlikely (hb_in_range (u, 0x1CE2u, 0x1CE8u)))
cat = OT_A;
/* TODO: The following should only be allowed after some of
* the nasalization marks, maybe only for U+1CE9..U+1CF1.
* For now, just treat them like tone marks. */
else if (unlikely (u == 0x1CEDu))
cat = OT_A;
/* The following take marks in standalone clusters, similar to Avagraha. */
else if (unlikely (hb_in_ranges (u, 0xA8F2u, 0xA8F7u,
0x1CE9u, 0x1CECu,
0x1CEEu, 0x1CF1u)))
{
cat = OT_Symbol;
ASSERT_STATIC ((int) INDIC_SYLLABIC_CATEGORY_AVAGRAHA == OT_Symbol);
}
else if (unlikely (hb_in_range (u, 0x17CDu, 0x17D1u) ||
u == 0x17CBu || u == 0x17D3u || u == 0x17DDu)) /* Khmer Various signs */
{
/* These are like Top Matras. */
cat = OT_M;
pos = POS_ABOVE_C;
}
if (u == 0x17C6) /* Khmer Bindu doesn't like to be repositioned. */
cat = OT_N;
if (unlikely (u == 0x17D2)) cat = OT_Coeng; /* Khmer coeng */
else if (unlikely (u == 0x200C)) cat = OT_ZWNJ;
else if (unlikely (u == 0x200D)) cat = OT_ZWJ;
else if (unlikely (u == 0x25CC)) cat = OT_DOTTEDCIRCLE;
else if (unlikely (u == 0x0A71)) cat = OT_SM; /* GURMUKHI ADDAK. Move it to the end. */
else if (unlikely (u == 0xA982)) cat = OT_SM; /* Javanese repha. */
else if (unlikely (u == 0xA9BE)) cat = OT_CM2; /* Javanese medial ya. */
else if (unlikely (u == 0xA9BD)) { cat = OT_M; pos = POS_POST_C; } /* Javanese vocalic r. */
if (cat == OT_Repha) {
/* There are two kinds of characters marked as Repha:
* - The ones that are GenCat=Mn are already positioned visually, ie. after base. (eg. Khmer)
* - The ones that are GenCat=Lo is encoded logically, ie. beginning of syllable. (eg. Malayalam)
*
* We recategorize the first kind to look like a Nukta and attached to the base directly.
*/
if (_hb_glyph_info_get_general_category (&info) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
cat = OT_N;
}
else if (unlikely (u == 0x17C6u)) cat = OT_N; /* Khmer Bindu doesn't like to be repositioned. */
else if (unlikely (u == 0x17D2u)) cat = OT_Coeng; /* Khmer coeng */
else if (unlikely (hb_in_range (u, 0x2010u, 0x2011u)))
cat = OT_PLACEHOLDER;
else if (unlikely (u == 0x25CCu)) cat = OT_DOTTEDCIRCLE;
else if (unlikely (u == 0xA982u)) cat = OT_SM; /* Javanese repha. */
else if (unlikely (u == 0xA9BEu)) cat = OT_CM2; /* Javanese medial ya. */
else if (unlikely (u == 0xA9BDu)) { cat = OT_M; pos = POS_POST_C; } /* Javanese vocalic r. */
/*
@ -246,12 +247,12 @@ set_indic_properties (hb_glyph_info_t &info)
{
pos = matra_position (u, pos);
}
else if ((FLAG (cat) & (FLAG (OT_SM) | FLAG (OT_VD) | FLAG (OT_A) | FLAG (OT_Avag))))
else if ((FLAG (cat) & (FLAG (OT_SM) | FLAG (OT_VD) | FLAG (OT_A) | FLAG (OT_Symbol))))
{
pos = POS_SMVD;
}
if (unlikely (u == 0x0B01)) pos = POS_BEFORE_SUB; /* Oriya Bindu is BeforeSub in the spec. */
if (unlikely (u == 0x0B01u)) pos = POS_BEFORE_SUB; /* Oriya Bindu is BeforeSub in the spec. */
@ -316,19 +317,19 @@ static const indic_config_t indic_configs[] =
{
/* Default. Should be first. */
{HB_SCRIPT_INVALID, false, 0,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_1},
{HB_SCRIPT_DEVANAGARI,true, 0x094D,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE},
{HB_SCRIPT_BENGALI, true, 0x09CD,BASE_POS_LAST, REPH_POS_AFTER_SUB, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE},
{HB_SCRIPT_GURMUKHI, true, 0x0A4D,BASE_POS_LAST, REPH_POS_BEFORE_SUB, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE},
{HB_SCRIPT_GUJARATI, true, 0x0ACD,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE},
{HB_SCRIPT_ORIYA, true, 0x0B4D,BASE_POS_LAST, REPH_POS_AFTER_MAIN, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE},
{HB_SCRIPT_TAMIL, true, 0x0BCD,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_2},
{HB_SCRIPT_TELUGU, true, 0x0C4D,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_EXPLICIT, BLWF_MODE_POST_ONLY, PREF_LEN_2},
{HB_SCRIPT_KANNADA, true, 0x0CCD,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_IMPLICIT, BLWF_MODE_POST_ONLY, PREF_LEN_2},
{HB_SCRIPT_MALAYALAM, true, 0x0D4D,BASE_POS_LAST, REPH_POS_AFTER_MAIN, REPH_MODE_LOG_REPHA,BLWF_MODE_PRE_AND_POST, PREF_LEN_2},
{HB_SCRIPT_SINHALA, false,0x0DCA,BASE_POS_LAST_SINHALA,
{HB_SCRIPT_DEVANAGARI,true, 0x094Du,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE},
{HB_SCRIPT_BENGALI, true, 0x09CDu,BASE_POS_LAST, REPH_POS_AFTER_SUB, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE},
{HB_SCRIPT_GURMUKHI, true, 0x0A4Du,BASE_POS_LAST, REPH_POS_BEFORE_SUB, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE},
{HB_SCRIPT_GUJARATI, true, 0x0ACDu,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE},
{HB_SCRIPT_ORIYA, true, 0x0B4Du,BASE_POS_LAST, REPH_POS_AFTER_MAIN, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE},
{HB_SCRIPT_TAMIL, true, 0x0BCDu,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_2},
{HB_SCRIPT_TELUGU, true, 0x0C4Du,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_EXPLICIT, BLWF_MODE_POST_ONLY, PREF_LEN_2},
{HB_SCRIPT_KANNADA, true, 0x0CCDu,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_IMPLICIT, BLWF_MODE_POST_ONLY, PREF_LEN_2},
{HB_SCRIPT_MALAYALAM, true, 0x0D4Du,BASE_POS_LAST, REPH_POS_AFTER_MAIN, REPH_MODE_LOG_REPHA,BLWF_MODE_PRE_AND_POST, PREF_LEN_2},
{HB_SCRIPT_SINHALA, false,0x0DCAu,BASE_POS_LAST_SINHALA,
REPH_POS_AFTER_MAIN, REPH_MODE_EXPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE},
{HB_SCRIPT_KHMER, false,0x17D2,BASE_POS_FIRST,REPH_POS_DONT_CARE, REPH_MODE_VIS_REPHA,BLWF_MODE_PRE_AND_POST, PREF_LEN_2},
{HB_SCRIPT_JAVANESE, false,0xA9C0,BASE_POS_FIRST,REPH_POS_DONT_CARE, REPH_MODE_VIS_REPHA,BLWF_MODE_PRE_AND_POST, PREF_LEN_1},
{HB_SCRIPT_KHMER, false,0x17D2u,BASE_POS_FIRST,REPH_POS_DONT_CARE, REPH_MODE_VIS_REPHA,BLWF_MODE_PRE_AND_POST, PREF_LEN_2},
{HB_SCRIPT_JAVANESE, false,0xA9C0u,BASE_POS_FIRST,REPH_POS_DONT_CARE, REPH_MODE_VIS_REPHA,BLWF_MODE_PRE_AND_POST, PREF_LEN_1},
};
@ -552,12 +553,12 @@ data_create_indic (const hb_ot_shape_plan_t *plan)
break;
}
indic_plan->is_old_spec = indic_plan->config->has_old_spec && ((plan->map.chosen_script[0] & 0x000000FF) != '2');
indic_plan->is_old_spec = indic_plan->config->has_old_spec && ((plan->map.chosen_script[0] & 0x000000FFu) != '2');
indic_plan->virama_glyph = (hb_codepoint_t) -1;
/* Use zero-context would_substitute() matching for new-spec of the main
* Indic scripts, but not for old-spec or scripts with one spec only. */
bool zero_context = indic_plan->config->has_old_spec || !indic_plan->is_old_spec;
* Indic scripts, and scripts with one spec only, but not for old-specs. */
bool zero_context = !indic_plan->is_old_spec;
indic_plan->rphf.init (&plan->map, HB_TAG('r','p','h','f'), zero_context);
indic_plan->pref.init (&plan->map, HB_TAG('p','r','e','f'), zero_context);
indic_plan->blwf.init (&plan->map, HB_TAG('b','l','w','f'), zero_context);
@ -614,7 +615,7 @@ enum syllable_type_t {
consonant_syllable,
vowel_syllable,
standalone_cluster,
avagraha_cluster,
symbol_cluster,
broken_cluster,
non_indic_cluster,
};
@ -634,8 +635,9 @@ setup_masks_indic (const hb_ot_shape_plan_t *plan HB_UNUSED,
* and setup masks later on in a pause-callback. */
unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
for (unsigned int i = 0; i < count; i++)
set_indic_properties (buffer->info[i]);
set_indic_properties (info[i]);
}
static void
@ -672,10 +674,12 @@ update_consonant_positions (const hb_ot_shape_plan_t *plan,
{
hb_face_t *face = font->face;
unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
for (unsigned int i = 0; i < count; i++)
if (buffer->info[i].indic_position() == POS_BASE_C) {
hb_codepoint_t consonant = buffer->info[i].codepoint;
buffer->info[i].indic_position() = consonant_position_from_face (indic_plan, consonant, virama, face);
if (info[i].indic_position() == POS_BASE_C)
{
hb_codepoint_t consonant = info[i].codepoint;
info[i].indic_position() = consonant_position_from_face (indic_plan, consonant, virama, face);
}
}
}
@ -725,8 +729,13 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
))
{
/* See if it matches the 'rphf' feature. */
hb_codepoint_t glyphs[2] = {info[start].codepoint, info[start + 1].codepoint};
if (indic_plan->rphf.would_substitute (glyphs, ARRAY_LENGTH (glyphs), face))
hb_codepoint_t glyphs[3] = {info[start].codepoint,
info[start + 1].codepoint,
indic_plan->config->reph_mode == REPH_MODE_EXPLICIT ?
info[start + 2].codepoint : 0};
if (indic_plan->rphf.would_substitute (glyphs, 2, face) ||
(indic_plan->config->reph_mode == REPH_MODE_EXPLICIT &&
indic_plan->rphf.would_substitute (glyphs, 3, face)))
{
limit += 2;
while (limit < end && is_joiner (info[limit]))
@ -801,7 +810,7 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
case BASE_POS_LAST_SINHALA:
{
/* Sinhala base positioning is slightly different from main Indic, in that:
* 1. It's ZWJ behavior is different,
* 1. Its ZWJ behavior is different,
* 2. We don't need to look into the font for consonant positions.
*/
@ -1151,8 +1160,8 @@ initial_reordering_standalone_cluster (const hb_ot_shape_plan_t *plan,
hb_buffer_t *buffer,
unsigned int start, unsigned int end)
{
/* We treat NBSP/dotted-circle as if they are consonants, so we should just chain.
* Only if not in compatibility mode that is... */
/* We treat placeholder/dotted-circle as if they are consonants, so we
* should just chain. Only if not in compatibility mode that is... */
if (hb_options ().uniscribe_bug_compatible)
{
@ -1177,7 +1186,7 @@ initial_reordering_broken_cluster (const hb_ot_shape_plan_t *plan,
}
static void
initial_reordering_avagraha_cluster (const hb_ot_shape_plan_t *plan HB_UNUSED,
initial_reordering_symbol_cluster (const hb_ot_shape_plan_t *plan HB_UNUSED,
hb_face_t *face HB_UNUSED,
hb_buffer_t *buffer HB_UNUSED,
unsigned int start HB_UNUSED, unsigned int end HB_UNUSED)
@ -1208,7 +1217,7 @@ initial_reordering_syllable (const hb_ot_shape_plan_t *plan,
case consonant_syllable: initial_reordering_consonant_syllable (plan, face, buffer, start, end); return;
case vowel_syllable: initial_reordering_vowel_syllable (plan, face, buffer, start, end); return;
case standalone_cluster: initial_reordering_standalone_cluster (plan, face, buffer, start, end); return;
case avagraha_cluster: initial_reordering_avagraha_cluster (plan, face, buffer, start, end); return;
case symbol_cluster: initial_reordering_symbol_cluster (plan, face, buffer, start, end); return;
case broken_cluster: initial_reordering_broken_cluster (plan, face, buffer, start, end); return;
case non_indic_cluster: initial_reordering_non_indic_cluster (plan, face, buffer, start, end); return;
}
@ -1222,8 +1231,10 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED,
/* Note: This loop is extra overhead, but should not be measurable. */
bool has_broken_syllables = false;
unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
for (unsigned int i = 0; i < count; i++)
if ((buffer->info[i].syllable() & 0x0F) == broken_cluster) {
if ((info[i].syllable() & 0x0F) == broken_cluster)
{
has_broken_syllables = true;
break;
}
@ -1232,11 +1243,11 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED,
hb_codepoint_t dottedcircle_glyph;
if (!font->get_glyph (0x25CC, 0, &dottedcircle_glyph))
if (!font->get_glyph (0x25CCu, 0, &dottedcircle_glyph))
return;
hb_glyph_info_t dottedcircle = {0};
dottedcircle.codepoint = 0x25CC;
dottedcircle.codepoint = 0x25CCu;
set_indic_properties (dottedcircle);
dottedcircle.codepoint = dottedcircle_glyph;
@ -1302,6 +1313,27 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan,
const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data;
hb_glyph_info_t *info = buffer->info;
/* This function relies heavily on halant glyphs. Lots of ligation
* and possibly multiplication substitutions happened prior to this
* phase, and that might have messed up our properties. Recover
* from a particular case of that where we're fairly sure that a
* class of OT_H is desired but has been lost. */
if (indic_plan->virama_glyph)
{
unsigned int virama_glyph = indic_plan->virama_glyph;
for (unsigned int i = start; i < end; i++)
if (info[i].codepoint == virama_glyph &&
_hb_glyph_info_ligated (&info[i]) &&
_hb_glyph_info_multiplied (&info[i]))
{
/* This will make sure that this glyph passes is_halant_or_coeng() test. */
info[i].indic_category() = OT_H;
_hb_glyph_info_clear_ligated_and_multiplied (&info[i]);
}
}
/* 4. Final reordering:
*
* After the localized forms and basic shaping forms GSUB features have been
@ -1310,20 +1342,44 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan,
* cluster.
*/
bool try_pref = !!indic_plan->mask_array[PREF];
/* Find base again */
unsigned int base;
for (base = start; base < end; base++)
if (info[base].indic_position() >= POS_BASE_C) {
if (info[base].indic_position() >= POS_BASE_C)
{
if (try_pref && base + 1 < end && indic_plan->config->pref_len == 2)
{
for (unsigned int i = base + 1; i < end; i++)
if ((info[i].mask & indic_plan->mask_array[PREF]) != 0)
{
if (!(_hb_glyph_info_substituted (&info[i]) &&
_hb_glyph_info_ligated_and_didnt_multiply (&info[i])))
{
/* Ok, this was a 'pref' candidate but didn't form any.
* Base is around here... */
base = i;
while (base < end && is_halant_or_coeng (info[base]))
base++;
info[base].indic_position() = POS_BASE_C;
try_pref = false;
}
break;
}
}
if (start < base && info[base].indic_position() > POS_BASE_C)
base--;
break;
}
if (base == end && start < base &&
info[base - 1].indic_category() != OT_ZWJ)
is_one_of (info[base - 1], FLAG (OT_ZWJ)))
base--;
if (base < end)
while (start < base &&
(info[base].indic_category() == OT_H ||
info[base].indic_category() == OT_N))
is_one_of (info[base], (FLAG (OT_N) | HALANT_OR_COENG_FLAGS)))
base--;
@ -1349,7 +1405,7 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan,
if (buffer->props.script != HB_SCRIPT_MALAYALAM && buffer->props.script != HB_SCRIPT_TAMIL)
{
while (new_pos > start &&
!(is_one_of (info[new_pos], (FLAG (OT_M) | FLAG (OT_H) | FLAG (OT_Coeng)))))
!(is_one_of (info[new_pos], (FLAG (OT_M) | HALANT_OR_COENG_FLAGS))))
new_pos--;
/* If we found no Halant we are done.
@ -1412,7 +1468,7 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan,
if (start + 1 < end &&
info[start].indic_position() == POS_RA_TO_BECOME_REPH &&
((info[start].indic_category() == OT_Repha) ^
_hb_glyph_info_ligated (&info[start])))
_hb_glyph_info_ligated_and_didnt_multiply (&info[start])))
{
unsigned int new_reph_pos;
reph_position_t reph_pos = indic_plan->config->reph_pos;
@ -1549,7 +1605,7 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan,
* the following rules:
*/
if (indic_plan->mask_array[PREF] && base + 1 < end) /* Otherwise there can't be any pre-base reordering Ra. */
if (try_pref && base + 1 < end) /* Otherwise there can't be any pre-base reordering Ra. */
{
unsigned int pref_len = indic_plan->config->pref_len;
for (unsigned int i = base + 1; i < end; i++)
@ -1565,7 +1621,7 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan,
* If pref len is longer than one, then only reorder if it ligated. If
* pref len is one, only reorder if it didn't ligate with other things. */
if (_hb_glyph_info_substituted (&info[i]) &&
((pref_len == 1) ^ _hb_glyph_info_ligated (&info[i])))
((pref_len == 1) ^ _hb_glyph_info_ligated_and_didnt_multiply (&info[i])))
{
/*
* 2. Try to find a target position the same way as for pre-base matra.
@ -1699,37 +1755,37 @@ decompose_indic (const hb_ot_shape_normalize_context_t *c,
switch (ab)
{
/* Don't decompose these. */
case 0x0931 : return false;
case 0x0B94 : return false;
case 0x0931u : return false;
case 0x0B94u : return false;
/*
* Decompose split matras that don't have Unicode decompositions.
*/
case 0x0F77 : *a = 0x0FB2; *b= 0x0F81; return true;
case 0x0F79 : *a = 0x0FB3; *b= 0x0F81; return true;
case 0x17BE : *a = 0x17C1; *b= 0x17BE; return true;
case 0x17BF : *a = 0x17C1; *b= 0x17BF; return true;
case 0x17C0 : *a = 0x17C1; *b= 0x17C0; return true;
case 0x17C4 : *a = 0x17C1; *b= 0x17C4; return true;
case 0x17C5 : *a = 0x17C1; *b= 0x17C5; return true;
case 0x1925 : *a = 0x1920; *b= 0x1923; return true;
case 0x1926 : *a = 0x1920; *b= 0x1924; return true;
case 0x1B3C : *a = 0x1B42; *b= 0x1B3C; return true;
case 0x1112E : *a = 0x11127; *b= 0x11131; return true;
case 0x1112F : *a = 0x11127; *b= 0x11132; return true;
case 0x0F77u : *a = 0x0FB2u; *b= 0x0F81u; return true;
case 0x0F79u : *a = 0x0FB3u; *b= 0x0F81u; return true;
case 0x17BEu : *a = 0x17C1u; *b= 0x17BEu; return true;
case 0x17BFu : *a = 0x17C1u; *b= 0x17BFu; return true;
case 0x17C0u : *a = 0x17C1u; *b= 0x17C0u; return true;
case 0x17C4u : *a = 0x17C1u; *b= 0x17C4u; return true;
case 0x17C5u : *a = 0x17C1u; *b= 0x17C5u; return true;
case 0x1925u : *a = 0x1920u; *b= 0x1923u; return true;
case 0x1926u : *a = 0x1920u; *b= 0x1924u; return true;
case 0x1B3Cu : *a = 0x1B42u; *b= 0x1B3Cu; return true;
case 0x1112Eu : *a = 0x11127u; *b= 0x11131u; return true;
case 0x1112Fu : *a = 0x11127u; *b= 0x11132u; return true;
#if 0
/* This one has no decomposition in Unicode, but needs no decomposition either. */
/* case 0x0AC9 : return false; */
case 0x0B57 : *a = no decomp, -> RIGHT; return true;
case 0x1C29 : *a = no decomp, -> LEFT; return true;
case 0xA9C0 : *a = no decomp, -> RIGHT; return true;
case 0x111BF : *a = no decomp, -> ABOVE; return true;
/* case 0x0AC9u : return false; */
case 0x0B57u : *a = no decomp, -> RIGHT; return true;
case 0x1C29u : *a = no decomp, -> LEFT; return true;
case 0xA9C0u : *a = no decomp, -> RIGHT; return true;
case 0x111BuF : *a = no decomp, -> ABOVE; return true;
#endif
}
if ((ab == 0x0DDA || hb_in_range<hb_codepoint_t> (ab, 0x0DDC, 0x0DDE)))
if ((ab == 0x0DDAu || hb_in_range (ab, 0x0DDCu, 0x0DDEu)))
{
/*
* Sinhala split matras... Let the fun begin.
@ -1766,7 +1822,7 @@ decompose_indic (const hb_ot_shape_normalize_context_t *c,
indic_plan->pstf.would_substitute (&glyph, 1, c->font->face)))
{
/* Ok, safe to use Uniscribe-style decomposition. */
*a = 0x0DD9;
*a = 0x0DD9u;
*b = ab;
return true;
}
@ -1786,7 +1842,7 @@ compose_indic (const hb_ot_shape_normalize_context_t *c,
return false;
/* Composition-exclusion exceptions that we want to recompose. */
if (a == 0x09AF && b == 0x09BC) { *ab = 0x09DF; return true; }
if (a == 0x09AFu && b == 0x09BCu) { *ab = 0x09DFu; return true; }
return c->unicode->compose (a, b, ab);
}

View File

@ -62,7 +62,7 @@ static const short _myanmar_syllable_machine_index_offsets[] = {
static const char _myanmar_syllable_machine_indicies[] = {
1, 1, 2, 3, 4, 4, 0, 5,
0, 6, 0, 1, 0, 0, 0, 7,
0, 6, 1, 0, 0, 0, 0, 7,
0, 8, 1, 0, 9, 10, 11, 12,
13, 14, 15, 16, 17, 18, 19, 0,
21, 22, 23, 23, 20, 24, 20, 25,
@ -119,14 +119,14 @@ static const char _myanmar_syllable_machine_indicies[] = {
20, 20, 20, 20, 20, 20, 20, 20,
20, 31, 20, 33, 20, 35, 20, 21,
20, 23, 23, 20, 24, 20, 25, 20,
20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 34, 20,
20, 27, 20, 29, 20, 31, 32, 33,
34, 35, 20, 21, 20, 23, 23, 20,
24, 20, 25, 20, 20, 20, 20, 20,
20, 20, 34, 20, 20, 27, 20, 20,
20, 31, 32, 33, 34, 35, 20, 21,
20, 23, 23, 20, 24, 20, 25, 20,
20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 34, 20,
20, 27, 28, 29, 20, 31, 32, 33,
34, 35, 20, 21, 22, 23, 23, 20,
24, 20, 25, 20, 20, 20, 20, 20,
@ -169,8 +169,8 @@ static const char _myanmar_syllable_machine_indicies[] = {
25, 20, 20, 20, 20, 20, 20, 20,
26, 20, 20, 27, 28, 29, 30, 31,
32, 33, 34, 35, 20, 1, 1, 2,
3, 3, 3, 42, 5, 42, 6, 42,
1, 42, 42, 42, 1, 42, 8, 1,
3, 3, 3, 42, 5, 42, 6, 1,
42, 42, 42, 42, 1, 42, 8, 1,
42, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 42, 2, 42, 3, 3,
42, 5, 42, 6, 42, 42, 42, 42,
@ -191,14 +191,14 @@ static const char _myanmar_syllable_machine_indicies[] = {
42, 42, 42, 42, 42, 42, 42, 42,
42, 42, 13, 42, 15, 42, 17, 42,
2, 42, 3, 3, 42, 5, 42, 6,
42, 42, 42, 42, 42, 42, 42, 42,
42, 42, 42, 42, 42, 42, 42, 16,
42, 42, 9, 42, 11, 42, 13, 14,
15, 16, 17, 42, 2, 42, 3, 3,
42, 5, 42, 6, 42, 42, 42, 42,
42, 42, 42, 16, 42, 42, 9, 42,
42, 42, 13, 14, 15, 16, 17, 42,
2, 42, 3, 3, 42, 5, 42, 6,
42, 42, 42, 42, 42, 42, 42, 42,
42, 42, 42, 42, 42, 42, 42, 16,
42, 42, 9, 10, 11, 42, 13, 14,
15, 16, 17, 42, 2, 3, 3, 3,
42, 5, 42, 6, 42, 42, 42, 42,

View File

@ -134,7 +134,7 @@ enum myanmar_category_t {
OT_D = 19, /* Digits except zero */
OT_D0 = 20, /* Digit zero */
OT_DB = OT_N, /* Dot below */
OT_GB = OT_DOTTEDCIRCLE,
OT_GB = OT_PLACEHOLDER,
OT_MH = 21, /* Various consonant medial types */
OT_MR = 22, /* Various consonant medial types */
OT_MW = 23, /* Various consonant medial types */
@ -157,12 +157,6 @@ is_one_of (const hb_glyph_info_t &info, unsigned int flags)
return !!(FLAG (info.myanmar_category()) & flags);
}
/* Note:
*
* We treat Vowels and placeholders as if they were consonants. This is safe because Vowels
* cannot happen in a consonant syllable. The plus side however is, we can call the
* consonant syllable logic from the vowel syllable function and get it all right! */
#define CONSONANT_FLAGS (FLAG (OT_C) | FLAG (OT_CM) | FLAG (OT_Ra) | FLAG (OT_V) | FLAG (OT_NBSP) | FLAG (OT_GB))
static inline bool
is_consonant (const hb_glyph_info_t &info)
{
@ -175,82 +169,80 @@ set_myanmar_properties (hb_glyph_info_t &info)
{
hb_codepoint_t u = info.codepoint;
unsigned int type = hb_indic_get_categories (u);
indic_category_t cat = (indic_category_t) (type & 0x7F);
indic_category_t cat = (indic_category_t) (type & 0x7Fu);
indic_position_t pos = (indic_position_t) (type >> 8);
/* Myanmar
* http://www.microsoft.com/typography/OpenTypeDev/myanmar/intro.htm#analyze
*/
if (unlikely (hb_in_range<hb_codepoint_t> (u, 0xFE00, 0xFE0F)))
if (unlikely (hb_in_range (u, 0xFE00u, 0xFE0Fu)))
cat = (indic_category_t) OT_VS;
else if (unlikely (u == 0x200C)) cat = (indic_category_t) OT_ZWNJ;
else if (unlikely (u == 0x200D)) cat = (indic_category_t) OT_ZWJ;
switch (u)
{
case 0x104E:
case 0x104Eu:
cat = (indic_category_t) OT_C; /* The spec says C, IndicSyllableCategory doesn't have. */
break;
case 0x002D: case 0x00A0: case 0x00D7: case 0x2012:
case 0x2013: case 0x2014: case 0x2015: case 0x2022:
case 0x25CC: case 0x25FB: case 0x25FC: case 0x25FD:
case 0x25FE:
case 0x002Du: case 0x00A0u: case 0x00D7u: case 0x2012u:
case 0x2013u: case 0x2014u: case 0x2015u: case 0x2022u:
case 0x25CCu: case 0x25FBu: case 0x25FCu: case 0x25FDu:
case 0x25FEu:
cat = (indic_category_t) OT_GB;
break;
case 0x1004: case 0x101B: case 0x105A:
case 0x1004u: case 0x101Bu: case 0x105Au:
cat = (indic_category_t) OT_Ra;
break;
case 0x1032: case 0x1036:
case 0x1032u: case 0x1036u:
cat = (indic_category_t) OT_A;
break;
case 0x103A:
case 0x103Au:
cat = (indic_category_t) OT_As;
break;
case 0x1041: case 0x1042: case 0x1043: case 0x1044:
case 0x1045: case 0x1046: case 0x1047: case 0x1048:
case 0x1049: case 0x1090: case 0x1091: case 0x1092:
case 0x1093: case 0x1094: case 0x1095: case 0x1096:
case 0x1097: case 0x1098: case 0x1099:
case 0x1041u: case 0x1042u: case 0x1043u: case 0x1044u:
case 0x1045u: case 0x1046u: case 0x1047u: case 0x1048u:
case 0x1049u: case 0x1090u: case 0x1091u: case 0x1092u:
case 0x1093u: case 0x1094u: case 0x1095u: case 0x1096u:
case 0x1097u: case 0x1098u: case 0x1099u:
cat = (indic_category_t) OT_D;
break;
case 0x1040:
case 0x1040u:
cat = (indic_category_t) OT_D; /* XXX The spec says D0, but Uniscribe doesn't seem to do. */
break;
case 0x103E: case 0x1060:
case 0x103Eu: case 0x1060u:
cat = (indic_category_t) OT_MH;
break;
case 0x103C:
case 0x103Cu:
cat = (indic_category_t) OT_MR;
break;
case 0x103D: case 0x1082:
case 0x103Du: case 0x1082u:
cat = (indic_category_t) OT_MW;
break;
case 0x103B: case 0x105E: case 0x105F:
case 0x103Bu: case 0x105Eu: case 0x105Fu:
cat = (indic_category_t) OT_MY;
break;
case 0x1063: case 0x1064: case 0x1069: case 0x106A:
case 0x106B: case 0x106C: case 0x106D: case 0xAA7B:
case 0x1063u: case 0x1064u: case 0x1069u: case 0x106Au:
case 0x106Bu: case 0x106Cu: case 0x106Du: case 0xAA7Bu:
cat = (indic_category_t) OT_PT;
break;
case 0x1038: case 0x1087: case 0x1088: case 0x1089:
case 0x108A: case 0x108B: case 0x108C: case 0x108D:
case 0x108F: case 0x109A: case 0x109B: case 0x109C:
case 0x1038u: case 0x1087u: case 0x1088u: case 0x1089u:
case 0x108Au: case 0x108Bu: case 0x108Cu: case 0x108Du:
case 0x108Fu: case 0x109Au: case 0x109Bu: case 0x109Cu:
cat = (indic_category_t) OT_SM;
break;
case 0x104A: case 0x104B:
case 0x104Au: case 0x104Bu:
cat = (indic_category_t) OT_P;
break;
}
@ -285,8 +277,9 @@ setup_masks_myanmar (const hb_ot_shape_plan_t *plan HB_UNUSED,
* and setup masks later on in a pause-callback. */
unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
for (unsigned int i = 0; i < count; i++)
set_myanmar_properties (buffer->info[i]);
set_myanmar_properties (info[i]);
}
static void
@ -459,8 +452,10 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED,
/* Note: This loop is extra overhead, but should not be measurable. */
bool has_broken_syllables = false;
unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
for (unsigned int i = 0; i < count; i++)
if ((buffer->info[i].syllable() & 0x0F) == broken_cluster) {
if ((info[i].syllable() & 0x0F) == broken_cluster)
{
has_broken_syllables = true;
break;
}
@ -469,11 +464,11 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED,
hb_codepoint_t dottedcircle_glyph;
if (!font->get_glyph (0x25CC, 0, &dottedcircle_glyph))
if (!font->get_glyph (0x25CCu, 0, &dottedcircle_glyph))
return;
hb_glyph_info_t dottedcircle = {0};
dottedcircle.codepoint = 0x25CC;
dottedcircle.codepoint = 0x25CCu;
set_myanmar_properties (dottedcircle);
dottedcircle.codepoint = dottedcircle_glyph;

View File

@ -173,6 +173,10 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner)
/* Unicode-6.0 additions */
case HB_SCRIPT_MANDAIC:
/* Unicode-7.0 additions */
case HB_SCRIPT_MANICHAEAN:
case HB_SCRIPT_PSALTER_PAHLAVI:
/* For Arabic script, use the Arabic shaper even if no OT script tag was found.
* This is because we do fallback shaping for Arabic script (and not others). */
if (planner->map.chosen_script[0] != HB_OT_TAG_DEFAULT_SCRIPT ||

View File

@ -139,11 +139,11 @@ set_sea_properties (hb_glyph_info_t &info)
{
hb_codepoint_t u = info.codepoint;
unsigned int type = hb_indic_get_categories (u);
indic_category_t cat = (indic_category_t) (type & 0x7F);
indic_category_t cat = (indic_category_t) (type & 0x7Fu);
indic_position_t pos = (indic_position_t) (type >> 8);
/* Medial Ra */
if (u == 0x1A55 || u == 0xAA34)
if (u == 0x1A55u || u == 0xAA34u)
cat = (indic_category_t) OT_MR;
if (cat == OT_M)
@ -174,8 +174,9 @@ setup_masks_sea (const hb_ot_shape_plan_t *plan HB_UNUSED,
* and setup masks later on in a pause-callback. */
unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
for (unsigned int i = 0; i < count; i++)
set_sea_properties (buffer->info[i]);
set_sea_properties (info[i]);
}
static void
@ -278,8 +279,10 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED,
/* Note: This loop is extra overhead, but should not be measurable. */
bool has_broken_syllables = false;
unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
for (unsigned int i = 0; i < count; i++)
if ((buffer->info[i].syllable() & 0x0F) == broken_cluster) {
if ((info[i].syllable() & 0x0F) == broken_cluster)
{
has_broken_syllables = true;
break;
}
@ -288,11 +291,11 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED,
hb_codepoint_t dottedcircle_glyph;
if (!font->get_glyph (0x25CC, 0, &dottedcircle_glyph))
if (!font->get_glyph (0x25CCu, 0, &dottedcircle_glyph))
return;
hb_glyph_info_t dottedcircle = {0};
dottedcircle.codepoint = 0x25CC;
dottedcircle.codepoint = 0x25CCu;
set_sea_properties (dottedcircle);
dottedcircle.codepoint = dottedcircle_glyph;

View File

@ -46,13 +46,13 @@ enum thai_consonant_type_t
static thai_consonant_type_t
get_consonant_type (hb_codepoint_t u)
{
if (u == 0x0E1B || u == 0x0E1D || u == 0x0E1F/* || u == 0x0E2C*/)
if (u == 0x0E1Bu || u == 0x0E1Du || u == 0x0E1Fu/* || u == 0x0E2Cu*/)
return AC;
if (u == 0x0E0D || u == 0x0E10)
if (u == 0x0E0Du || u == 0x0E10u)
return RC;
if (u == 0x0E0E || u == 0x0E0F)
if (u == 0x0E0Eu || u == 0x0E0Fu)
return DC;
if (hb_in_range<hb_codepoint_t> (u, 0x0E01, 0x0E2E))
if (hb_in_range (u, 0x0E01u, 0x0E2Eu))
return NC;
return NOT_CONSONANT;
}
@ -70,12 +70,12 @@ enum thai_mark_type_t
static thai_mark_type_t
get_mark_type (hb_codepoint_t u)
{
if (u == 0x0E31 || hb_in_range<hb_codepoint_t> (u, 0x0E34, 0x0E37) ||
u == 0x0E47 || hb_in_range<hb_codepoint_t> (u, 0x0E4D, 0x0E4E))
if (u == 0x0E31u || hb_in_range (u, 0x0E34u, 0x0E37u) ||
u == 0x0E47u || hb_in_range (u, 0x0E4Du, 0x0E4Eu))
return AV;
if (hb_in_range<hb_codepoint_t> (u, 0x0E38, 0x0E3A))
if (hb_in_range (u, 0x0E38u, 0x0E3Au))
return BV;
if (hb_in_range<hb_codepoint_t> (u, 0x0E48, 0x0E4C))
if (hb_in_range (u, 0x0E48u, 0x0E4Cu))
return T;
return NOT_MARK;
}
@ -99,43 +99,43 @@ thai_pua_shape (hb_codepoint_t u, thai_action_t action, hb_font_t *font)
hb_codepoint_t mac_pua;
} const *pua_mappings = NULL;
static const thai_pua_mapping_t SD_mappings[] = {
{0x0E48, 0xF70A, 0xF88B}, /* MAI EK */
{0x0E49, 0xF70B, 0xF88E}, /* MAI THO */
{0x0E4A, 0xF70C, 0xF891}, /* MAI TRI */
{0x0E4B, 0xF70D, 0xF894}, /* MAI CHATTAWA */
{0x0E4C, 0xF70E, 0xF897}, /* THANTHAKHAT */
{0x0E38, 0xF718, 0xF89B}, /* SARA U */
{0x0E39, 0xF719, 0xF89C}, /* SARA UU */
{0x0E3A, 0xF71A, 0xF89D}, /* PHINTHU */
{0x0000, 0x0000, 0x0000}
{0x0E48u, 0xF70Au, 0xF88Bu}, /* MAI EK */
{0x0E49u, 0xF70Bu, 0xF88Eu}, /* MAI THO */
{0x0E4Au, 0xF70Cu, 0xF891u}, /* MAI TRI */
{0x0E4Bu, 0xF70Du, 0xF894u}, /* MAI CHATTAWA */
{0x0E4Cu, 0xF70Eu, 0xF897u}, /* THANTHAKHAT */
{0x0E38u, 0xF718u, 0xF89Bu}, /* SARA U */
{0x0E39u, 0xF719u, 0xF89Cu}, /* SARA UU */
{0x0E3Au, 0xF71Au, 0xF89Du}, /* PHINTHU */
{0x0000u, 0x0000u, 0x0000u}
};
static const thai_pua_mapping_t SDL_mappings[] = {
{0x0E48, 0xF705, 0xF88C}, /* MAI EK */
{0x0E49, 0xF706, 0xF88F}, /* MAI THO */
{0x0E4A, 0xF707, 0xF892}, /* MAI TRI */
{0x0E4B, 0xF708, 0xF895}, /* MAI CHATTAWA */
{0x0E4C, 0xF709, 0xF898}, /* THANTHAKHAT */
{0x0000, 0x0000, 0x0000}
{0x0E48u, 0xF705u, 0xF88Cu}, /* MAI EK */
{0x0E49u, 0xF706u, 0xF88Fu}, /* MAI THO */
{0x0E4Au, 0xF707u, 0xF892u}, /* MAI TRI */
{0x0E4Bu, 0xF708u, 0xF895u}, /* MAI CHATTAWA */
{0x0E4Cu, 0xF709u, 0xF898u}, /* THANTHAKHAT */
{0x0000u, 0x0000u, 0x0000u}
};
static const thai_pua_mapping_t SL_mappings[] = {
{0x0E48, 0xF713, 0xF88A}, /* MAI EK */
{0x0E49, 0xF714, 0xF88D}, /* MAI THO */
{0x0E4A, 0xF715, 0xF890}, /* MAI TRI */
{0x0E4B, 0xF716, 0xF893}, /* MAI CHATTAWA */
{0x0E4C, 0xF717, 0xF896}, /* THANTHAKHAT */
{0x0E31, 0xF710, 0xF884}, /* MAI HAN-AKAT */
{0x0E34, 0xF701, 0xF885}, /* SARA I */
{0x0E35, 0xF702, 0xF886}, /* SARA II */
{0x0E36, 0xF703, 0xF887}, /* SARA UE */
{0x0E37, 0xF704, 0xF888}, /* SARA UEE */
{0x0E47, 0xF712, 0xF889}, /* MAITAIKHU */
{0x0E4D, 0xF711, 0xF899}, /* NIKHAHIT */
{0x0000, 0x0000, 0x0000}
{0x0E48u, 0xF713u, 0xF88Au}, /* MAI EK */
{0x0E49u, 0xF714u, 0xF88Du}, /* MAI THO */
{0x0E4Au, 0xF715u, 0xF890u}, /* MAI TRI */
{0x0E4Bu, 0xF716u, 0xF893u}, /* MAI CHATTAWA */
{0x0E4Cu, 0xF717u, 0xF896u}, /* THANTHAKHAT */
{0x0E31u, 0xF710u, 0xF884u}, /* MAI HAN-AKAT */
{0x0E34u, 0xF701u, 0xF885u}, /* SARA I */
{0x0E35u, 0xF702u, 0xF886u}, /* SARA II */
{0x0E36u, 0xF703u, 0xF887u}, /* SARA UE */
{0x0E37u, 0xF704u, 0xF888u}, /* SARA UEE */
{0x0E47u, 0xF712u, 0xF889u}, /* MAITAIKHU */
{0x0E4Du, 0xF711u, 0xF899u}, /* NIKHAHIT */
{0x0000u, 0x0000u, 0x0000u}
};
static const thai_pua_mapping_t RD_mappings[] = {
{0x0E0D, 0xF70F, 0xF89A}, /* YO YING */
{0x0E10, 0xF700, 0xF89E}, /* THO THAN */
{0x0000, 0x0000, 0x0000}
{0x0E0Du, 0xF70Fu, 0xF89Au}, /* YO YING */
{0x0E10u, 0xF700u, 0xF89Eu}, /* THO THAN */
{0x0000u, 0x0000u, 0x0000u}
};
switch (action) {
@ -308,10 +308,10 @@ preprocess_text_thai (const hb_ot_shape_plan_t *plan,
/* We only get one script at a time, so a script-agnostic implementation
* is adequate here. */
#define IS_SARA_AM(x) (((x) & ~0x0080) == 0x0E33)
#define NIKHAHIT_FROM_SARA_AM(x) ((x) - 0xE33 + 0xE4D)
#define IS_SARA_AM(x) (((x) & ~0x0080u) == 0x0E33u)
#define NIKHAHIT_FROM_SARA_AM(x) ((x) - 0x0E33u + 0x0E4Du)
#define SARA_AA_FROM_SARA_AM(x) ((x) - 1)
#define IS_TONE_MARK(x) (hb_in_ranges<hb_codepoint_t> ((x) & ~0x0080, 0x0E34, 0x0E37, 0x0E47, 0x0E4E, 0x0E31, 0x0E31))
#define IS_TONE_MARK(x) (hb_in_ranges ((x) & ~0x0080u, 0x0E34u, 0x0E37u, 0x0E47u, 0x0E4Eu, 0x0E31u, 0x0E31u))
buffer->clear_output ();
unsigned int count = buffer->len;
@ -330,8 +330,11 @@ preprocess_text_thai (const hb_ot_shape_plan_t *plan,
if (unlikely (buffer->in_error))
return;
/* Ok, let's see... */
/* Make Nikhahit be recognized as a mark when zeroing widths. */
unsigned int end = buffer->out_len;
_hb_glyph_info_set_general_category (&buffer->out_info[end - 2], HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK);
/* Ok, let's see... */
unsigned int start = end - 2;
while (start > 0 && IS_TONE_MARK (buffer->out_info[start - 1].codepoint))
start--;

View File

@ -35,42 +35,42 @@ recategorize_combining_class (hb_codepoint_t u,
return klass;
/* Thai / Lao need some per-character work. */
if ((u & ~0xFF) == 0x0E00)
if ((u & ~0xFF) == 0x0E00u)
{
if (unlikely (klass == 0))
{
switch (u)
{
case 0x0E31:
case 0x0E34:
case 0x0E35:
case 0x0E36:
case 0x0E37:
case 0x0E47:
case 0x0E4C:
case 0x0E4D:
case 0x0E4E:
case 0x0E31u:
case 0x0E34u:
case 0x0E35u:
case 0x0E36u:
case 0x0E37u:
case 0x0E47u:
case 0x0E4Cu:
case 0x0E4Du:
case 0x0E4Eu:
klass = HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT;
break;
case 0x0EB1:
case 0x0EB4:
case 0x0EB5:
case 0x0EB6:
case 0x0EB7:
case 0x0EBB:
case 0x0ECC:
case 0x0ECD:
case 0x0EB1u:
case 0x0EB4u:
case 0x0EB5u:
case 0x0EB6u:
case 0x0EB7u:
case 0x0EBBu:
case 0x0ECCu:
case 0x0ECDu:
klass = HB_UNICODE_COMBINING_CLASS_ABOVE;
break;
case 0x0EBC:
case 0x0EBCu:
klass = HB_UNICODE_COMBINING_CLASS_BELOW;
break;
}
} else {
/* Thai virama is below-right */
if (u == 0x0E3A)
if (u == 0x0E3Au)
klass = HB_UNICODE_COMBINING_CLASS_BELOW_RIGHT;
}
}
@ -167,11 +167,12 @@ _hb_ot_shape_fallback_position_recategorize_marks (const hb_ot_shape_plan_t *pla
hb_buffer_t *buffer)
{
unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
for (unsigned int i = 0; i < count; i++)
if (_hb_glyph_info_get_general_category (&buffer->info[i]) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) {
unsigned int combining_class = _hb_glyph_info_get_modified_combining_class (&buffer->info[i]);
combining_class = recategorize_combining_class (buffer->info[i].codepoint, combining_class);
_hb_glyph_info_set_modified_combining_class (&buffer->info[i], combining_class);
if (_hb_glyph_info_get_general_category (&info[i]) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) {
unsigned int combining_class = _hb_glyph_info_get_modified_combining_class (&info[i]);
combining_class = recategorize_combining_class (info[i].codepoint, combining_class);
_hb_glyph_info_set_modified_combining_class (&info[i], combining_class);
}
}
@ -181,8 +182,9 @@ zero_mark_advances (hb_buffer_t *buffer,
unsigned int start,
unsigned int end)
{
hb_glyph_info_t *info = buffer->info;
for (unsigned int i = start; i < end; i++)
if (_hb_glyph_info_get_general_category (&buffer->info[i]) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
if (_hb_glyph_info_get_general_category (&info[i]) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
{
buffer->pos[i].x_advance = 0;
buffer->pos[i].y_advance = 0;
@ -327,12 +329,13 @@ position_around_base (const hb_ot_shape_plan_t *plan,
unsigned int last_lig_component = (unsigned int) -1;
unsigned int last_combining_class = 255;
hb_glyph_extents_t cluster_extents = base_extents; /* Initialization is just to shut gcc up. */
hb_glyph_info_t *info = buffer->info;
for (unsigned int i = base + 1; i < end; i++)
if (_hb_glyph_info_get_modified_combining_class (&buffer->info[i]))
if (_hb_glyph_info_get_modified_combining_class (&info[i]))
{
if (num_lig_components > 1) {
unsigned int this_lig_id = _hb_glyph_info_get_lig_id (&buffer->info[i]);
unsigned int this_lig_component = _hb_glyph_info_get_lig_comp (&buffer->info[i]) - 1;
unsigned int this_lig_id = _hb_glyph_info_get_lig_id (&info[i]);
unsigned int this_lig_component = _hb_glyph_info_get_lig_comp (&info[i]) - 1;
/* Conditions for attaching to the last component. */
if (!lig_id || lig_id != this_lig_id || this_lig_component >= num_lig_components)
this_lig_component = num_lig_components - 1;
@ -355,7 +358,7 @@ position_around_base (const hb_ot_shape_plan_t *plan,
}
}
unsigned int this_combining_class = _hb_glyph_info_get_modified_combining_class (&buffer->info[i]);
unsigned int this_combining_class = _hb_glyph_info_get_modified_combining_class (&info[i]);
if (last_combining_class != this_combining_class)
{
last_combining_class = this_combining_class;
@ -391,13 +394,14 @@ position_cluster (const hb_ot_shape_plan_t *plan,
return;
/* Find the base glyph */
hb_glyph_info_t *info = buffer->info;
for (unsigned int i = start; i < end; i++)
if (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer->info[i])))
if (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[i])))
{
/* Find mark glyphs */
unsigned int j;
for (j = i + 1; j < end; j++)
if (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer->info[j])))
if (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[j])))
break;
position_around_base (plan, font, buffer, i, j);
@ -432,15 +436,13 @@ _hb_ot_shape_fallback_kern (const hb_ot_shape_plan_t *plan,
{
if (!plan->has_kern) return;
unsigned int count = buffer->len;
OT::hb_apply_context_t c (1, font, buffer);
c.set_lookup_mask (plan->kern_mask);
c.set_lookup_props (OT::LookupFlag::IgnoreMarks);
unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
hb_glyph_position_t *pos = buffer->pos;
for (unsigned int idx = 0; idx < count;)
{
OT::hb_apply_context_t::skipping_forward_iterator_t skippy_iter (&c, idx, 1);

View File

@ -44,6 +44,7 @@ struct hb_ot_shape_plan_t
hb_mask_t kern_mask;
unsigned int has_frac : 1;
unsigned int has_kern : 1;
unsigned int has_mark : 1;
inline void collect_lookups (hb_tag_t table_tag, hb_set_t *lookups) const
{
@ -92,6 +93,7 @@ struct hb_ot_shape_planner_t
plan.has_frac = plan.frac_mask || (plan.numr_mask && plan.dnom_mask);
plan.has_kern = !!plan.kern_mask;
plan.has_mark = !!plan.map.get_1_mask (HB_TAG ('m','a','r','k'));
}
private:

View File

@ -37,6 +37,7 @@
#include "hb-ot-shape-normalize-private.hh"
#include "hb-ot-layout-private.hh"
#include "hb-unicode-private.hh"
#include "hb-set-private.hh"
@ -226,8 +227,9 @@ static void
hb_set_unicode_props (hb_buffer_t *buffer)
{
unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
for (unsigned int i = 0; i < count; i++)
_hb_glyph_info_set_unicode_props (&buffer->info[i], buffer->unicode);
_hb_glyph_info_set_unicode_props (&info[i], buffer->unicode);
}
static void
@ -238,11 +240,11 @@ hb_insert_dotted_circle (hb_buffer_t *buffer, hb_font_t *font)
HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
return;
if (!font->has_glyph (0x25CC))
if (!font->has_glyph (0x25CCu))
return;
hb_glyph_info_t dottedcircle;
dottedcircle.codepoint = 0x25CC;
dottedcircle.codepoint = 0x25CCu;
_hb_glyph_info_set_unicode_props (&dottedcircle, buffer->unicode);
buffer->clear_output ();
@ -262,8 +264,9 @@ static void
hb_form_clusters (hb_buffer_t *buffer)
{
unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
for (unsigned int i = 1; i < count; i++)
if (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer->info[i])))
if (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[i])))
buffer->merge_clusters (i - 1, i + 1);
}
@ -321,7 +324,7 @@ hb_ot_shape_setup_masks_fraction (hb_ot_shape_context_t *c)
hb_glyph_info_t *info = buffer->info;
for (unsigned int i = 0; i < count; i++)
{
if (info[i].codepoint == 0x2044) /* FRACTION SLASH */
if (info[i].codepoint == 0x2044u) /* FRACTION SLASH */
{
unsigned int start = i, end = i + 1;
while (start &&
@ -381,8 +384,9 @@ hb_ot_map_glyphs_fast (hb_buffer_t *buffer)
{
/* Normalization process sets up glyph_index(), we just copy it. */
unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
for (unsigned int i = 0; i < count; i++)
buffer->info[i].codepoint = buffer->info[i].glyph_index();
info[i].codepoint = info[i].glyph_index();
}
static inline void
@ -391,11 +395,24 @@ hb_synthesize_glyph_classes (hb_ot_shape_context_t *c)
unsigned int count = c->buffer->len;
hb_glyph_info_t *info = c->buffer->info;
for (unsigned int i = 0; i < count; i++)
_hb_glyph_info_set_glyph_props (&info[i],
_hb_glyph_info_get_general_category (&info[i])
== HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK ?
HB_OT_LAYOUT_GLYPH_PROPS_MARK :
HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH);
{
hb_ot_layout_glyph_class_mask_t klass;
/* Never mark default-ignorables as marks.
* They won't get in the way of lookups anyway,
* but having them as mark will cause them to be skipped
* over if the lookup-flag says so, but at least for the
* Mongolian variation selectors, looks like Uniscribe
* marks them as non-mark. Some Mongolian fonts without
* GDEF rely on this. Another notable character that
* this applies to is COMBINING GRAPHEME JOINER. */
klass = (_hb_glyph_info_get_general_category (&info[i]) !=
HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK ||
_hb_glyph_info_is_default_ignorable (&info[i])) ?
HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH :
HB_OT_LAYOUT_GLYPH_PROPS_MARK;
_hb_glyph_info_set_glyph_props (&info[i], klass);
}
}
static inline void
@ -452,26 +469,44 @@ hb_ot_substitute (hb_ot_shape_context_t *c)
/* Position */
static inline void
zero_mark_widths_by_unicode (hb_buffer_t *buffer)
adjust_mark_offsets (hb_glyph_position_t *pos)
{
pos->x_offset -= pos->x_advance;
pos->y_offset -= pos->y_advance;
}
static inline void
zero_mark_width (hb_glyph_position_t *pos)
{
pos->x_advance = 0;
pos->y_advance = 0;
}
static inline void
zero_mark_widths_by_unicode (hb_buffer_t *buffer, bool adjust_offsets)
{
unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
for (unsigned int i = 0; i < count; i++)
if (_hb_glyph_info_get_general_category (&buffer->info[i]) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
if (_hb_glyph_info_get_general_category (&info[i]) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
{
buffer->pos[i].x_advance = 0;
buffer->pos[i].y_advance = 0;
if (adjust_offsets)
adjust_mark_offsets (&buffer->pos[i]);
zero_mark_width (&buffer->pos[i]);
}
}
static inline void
zero_mark_widths_by_gdef (hb_buffer_t *buffer)
zero_mark_widths_by_gdef (hb_buffer_t *buffer, bool adjust_offsets)
{
unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
for (unsigned int i = 0; i < count; i++)
if (_hb_glyph_info_is_mark (&buffer->info[i]))
if (_hb_glyph_info_is_mark (&info[i]))
{
buffer->pos[i].x_advance = 0;
buffer->pos[i].y_advance = 0;
if (adjust_offsets)
adjust_mark_offsets (&buffer->pos[i]);
zero_mark_width (&buffer->pos[i]);
}
}
@ -501,16 +536,28 @@ hb_ot_position_complex (hb_ot_shape_context_t *c)
{
bool ret = false;
unsigned int count = c->buffer->len;
bool has_positioning = hb_ot_layout_has_positioning (c->face);
/* If the font has no GPOS, AND, no fallback positioning will
* happen, AND, direction is forward, then when zeroing mark
* widths, we shift the mark with it, such that the mark
* is positioned hanging over the previous glyph. When
* direction is backward we don't shift and it will end up
* hanging over the next glyph after the final reordering.
* If fallback positinoing happens or GPOS is present, we don't
* care.
*/
bool adjust_offsets_when_zeroing = !(has_positioning || c->plan->shaper->fallback_position ||
HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction));
switch (c->plan->shaper->zero_width_marks)
{
case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY:
zero_mark_widths_by_gdef (c->buffer);
zero_mark_widths_by_gdef (c->buffer, adjust_offsets_when_zeroing);
break;
/* Not currently used for any shaper:
case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_EARLY:
zero_mark_widths_by_unicode (c->buffer);
zero_mark_widths_by_unicode (c->buffer, adjust_offsets_when_zeroing);
break;
*/
@ -521,7 +568,7 @@ hb_ot_position_complex (hb_ot_shape_context_t *c)
break;
}
if (hb_ot_layout_has_positioning (c->face))
if (has_positioning)
{
hb_glyph_info_t *info = c->buffer->info;
hb_glyph_position_t *pos = c->buffer->pos;
@ -550,11 +597,11 @@ hb_ot_position_complex (hb_ot_shape_context_t *c)
switch (c->plan->shaper->zero_width_marks)
{
case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_LATE:
zero_mark_widths_by_unicode (c->buffer);
zero_mark_widths_by_unicode (c->buffer, adjust_offsets_when_zeroing);
break;
case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE:
zero_mark_widths_by_gdef (c->buffer);
zero_mark_widths_by_gdef (c->buffer, adjust_offsets_when_zeroing);
break;
default:
@ -731,8 +778,9 @@ hb_ot_shape_glyphs_closure (hb_font_t *font,
bool mirror = hb_script_get_horizontal_direction (buffer->props.script) == HB_DIRECTION_RTL;
unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
for (unsigned int i = 0; i < count; i++)
add_char (font, buffer->unicode, mirror, buffer->info[i].codepoint, glyphs);
add_char (font, buffer->unicode, mirror, info[i].codepoint, glyphs);
hb_set_t lookups;
lookups.init ();

View File

@ -24,15 +24,15 @@
* Red Hat Author(s): Behdad Esfahbod
*/
#ifndef HB_OT_H_IN
#error "Include <hb-ot.h> instead."
#endif
#ifndef HB_OT_SHAPE_H
#define HB_OT_SHAPE_H
#define HB_OT_SHAPE_H_IN
#include "hb.h"
#include "hb-ot-layout.h"
#include "hb-ot-tag.h"
HB_BEGIN_DECLS
/* TODO port to shape-plan / set. */
@ -50,5 +50,4 @@ hb_ot_shape_plan_collect_lookups (hb_shape_plan_t *shape_plan,
HB_END_DECLS
#undef HB_OT_SHAPE_H_IN
#endif /* HB_OT_SHAPE_H */

View File

@ -57,7 +57,7 @@ hb_ot_old_tag_from_script (hb_script_t script)
}
/* Else, just change first char to lowercase and return */
return ((hb_tag_t) script) | 0x20000000;
return ((hb_tag_t) script) | 0x20000000u;
}
static hb_script_t
@ -70,13 +70,13 @@ hb_ot_old_tag_to_script (hb_tag_t tag)
/* Any spaces at the end of the tag are replaced by repeating the last
* letter. Eg 'nko ' -> 'Nkoo' */
if (unlikely ((tag & 0x0000FF00) == 0x00002000))
tag |= (tag >> 8) & 0x0000FF00; /* Copy second letter to third */
if (unlikely ((tag & 0x000000FF) == 0x00000020))
tag |= (tag >> 8) & 0x000000FF; /* Copy third letter to fourth */
if (unlikely ((tag & 0x0000FF00u) == 0x00002000u))
tag |= (tag >> 8) & 0x0000FF00u; /* Copy second letter to third */
if (unlikely ((tag & 0x000000FFu) == 0x00000020u))
tag |= (tag >> 8) & 0x000000FFu; /* Copy third letter to fourth */
/* Change first char to uppercase and return */
return (hb_script_t) (tag & ~0x20000000);
return (hb_script_t) (tag & ~0x20000000u);
}
static hb_tag_t
@ -146,7 +146,7 @@ hb_ot_tags_from_script (hb_script_t script,
hb_script_t
hb_ot_tag_to_script (hb_tag_t tag)
{
if (unlikely ((tag & 0x000000FF) == '2'))
if (unlikely ((tag & 0x000000FFu) == '2'))
return hb_ot_new_tag_to_script (tag);
return hb_ot_old_tag_to_script (tag);
@ -156,7 +156,7 @@ hb_ot_tag_to_script (hb_tag_t tag)
/* hb_language_t */
typedef struct {
char language[6];
char language[4];
hb_tag_t tag;
} LangTag;
@ -763,12 +763,18 @@ static const LangTag ot_languages[] = {
/*{"??", HB_TAG('Z','H','P',' ')},*/ /* Chinese Phonetic */
};
static const LangTag ot_languages_zh[] = {
typedef struct {
char language[8];
hb_tag_t tag;
} LangTagLong;
static const LangTagLong ot_languages_zh[] = {
{"zh-cn", HB_TAG('Z','H','S',' ')}, /* Chinese (China) */
{"zh-hk", HB_TAG('Z','H','H',' ')}, /* Chinese (Hong Kong) */
{"zh-mo", HB_TAG('Z','H','T',' ')}, /* Chinese (Macao) */
{"zh-sg", HB_TAG('Z','H','S',' ')}, /* Chinese (Singapore) */
{"zh-tw", HB_TAG('Z','H','T',' ')} /* Chinese (Taiwan) */
{"zh-tw", HB_TAG('Z','H','T',' ')}, /* Chinese (Taiwan) */
{"zh-hans", HB_TAG('Z','H','S',' ')}, /* Chinese (Simplified) */
{"zh-hant", HB_TAG('Z','H','T',' ')}, /* Chinese (Traditional) */
};
static int
@ -800,7 +806,6 @@ hb_tag_t
hb_ot_tag_from_language (hb_language_t language)
{
const char *lang_str, *s;
const LangTag *lang_tag;
if (language == HB_LANGUAGE_INVALID)
return HB_OT_TAG_DEFAULT_LANGUAGE;
@ -822,11 +827,14 @@ hb_ot_tag_from_language (hb_language_t language)
}
/* Find a language matching in the first component */
{
const LangTag *lang_tag;
lang_tag = (LangTag *) bsearch (lang_str, ot_languages,
ARRAY_LENGTH (ot_languages), sizeof (LangTag),
(hb_compare_func_t) lang_compare_first_component);
if (lang_tag)
return lang_tag->tag;
}
/* Otherwise, check the Chinese ones */
if (0 == lang_compare_first_component (lang_str, "zh"))
@ -835,8 +843,9 @@ hb_ot_tag_from_language (hb_language_t language)
for (i = 0; i < ARRAY_LENGTH (ot_languages_zh); i++)
{
const LangTagLong *lang_tag;
lang_tag = &ot_languages_zh[i];
if (lang_matches (lang_tag->language, lang_str))
if (lang_matches (lang_str, lang_tag->language))
return lang_tag->tag;
}
@ -849,7 +858,7 @@ hb_ot_tag_from_language (hb_language_t language)
s = lang_str + strlen (lang_str);
if (s - lang_str == 3) {
/* Assume it's ISO-639-3 and upper-case and use it. */
return hb_tag_from_string (lang_str, s - lang_str) & ~0x20202000;
return hb_tag_from_string (lang_str, s - lang_str) & ~0x20202000u;
}
return HB_OT_TAG_DEFAULT_LANGUAGE;
@ -868,21 +877,12 @@ hb_ot_tag_to_language (hb_tag_t tag)
return hb_language_from_string (ot_languages[i].language, -1);
/* If tag starts with ZH, it's Chinese */
if ((tag & 0xFFFF0000) == 0x5A480000) {
if ((tag & 0xFFFF0000u) == 0x5A480000u) {
switch (tag) {
case HB_TAG('Z','H','H',' '): return hb_language_from_string ("zh-hk", -1); /* Hong Kong */
default: {
/* Encode the tag... */
unsigned char buf[14] = "zh-x-hbot";
buf[9] = tag >> 24;
buf[10] = (tag >> 16) & 0xFF;
buf[11] = (tag >> 8) & 0xFF;
buf[12] = tag & 0xFF;
if (buf[12] == 0x20)
buf[12] = '\0';
buf[13] = '\0';
return hb_language_from_string ((char *) buf, -1);
}
case HB_TAG('Z','H','S',' '): return hb_language_from_string ("zh-Hans", -1); /* Simplified */
case HB_TAG('Z','H','T',' '): return hb_language_from_string ("zh-Hant", -1); /* Traditional */
default: break; /* Fall through */
}
}

View File

@ -30,6 +30,7 @@
#include "hb.h"
#include "hb-ot-font.h"
#include "hb-ot-layout.h"
#include "hb-ot-tag.h"
#include "hb-ot-shape.h"

View File

@ -54,23 +54,77 @@
#include <stdarg.h>
/* Compiler attributes */
/* Essentials */
#ifndef NULL
# define NULL ((void *) 0)
#if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__)
#define _HB_BOOLEAN_EXPR(expr) ((expr) ? 1 : 0)
#define likely(expr) (__builtin_expect (_HB_BOOLEAN_EXPR(expr), 1))
#define unlikely(expr) (__builtin_expect (_HB_BOOLEAN_EXPR(expr), 0))
#else
#define likely(expr) (expr)
#define unlikely(expr) (expr)
#endif
#ifndef __GNUC__
#undef __attribute__
#define __attribute__(x)
#endif
#if __GNUC__ >= 3
#define HB_PURE_FUNC __attribute__((pure))
#define HB_CONST_FUNC __attribute__((const))
#define HB_PRINTF_FUNC(format_idx, arg_idx) __attribute__((__format__ (__printf__, format_idx, arg_idx)))
#else
#define HB_PURE_FUNC
#define HB_CONST_FUNC
#define HB_PRINTF_FUNC(format_idx, arg_idx)
#endif
#if __GNUC__ >= 4
#define HB_UNUSED __attribute__((unused))
#else
#define HB_UNUSED
#endif
#ifndef HB_INTERNAL
# ifndef __MINGW32__
# define HB_INTERNAL __attribute__((__visibility__("hidden")))
# else
# define HB_INTERNAL
# endif
#endif
#if (defined(__WIN32__) && !defined(__WINE__)) || defined(_MSC_VER)
#define snprintf _snprintf
#endif
#ifdef _MSC_VER
#undef inline
#define inline __inline
#endif
#ifdef __STRICT_ANSI__
#undef inline
#define inline __inline__
#endif
#if __GNUC__ >= 3
#define HB_FUNC __PRETTY_FUNCTION__
#elif defined(_MSC_VER)
#define HB_FUNC __FUNCSIG__
#else
#define HB_FUNC __func__
#endif
/* Void! */
struct _hb_void_t {};
typedef const _hb_void_t &hb_void_t;
#define HB_VOID (* (const _hb_void_t *) NULL)
/* Basics */
#ifndef NULL
# define NULL ((void *) 0)
#endif
#undef MIN
template <typename Type>
static inline Type MIN (const Type &a, const Type &b) { return a < b ? a : b; }
@ -92,7 +146,7 @@ static inline unsigned int ARRAY_LENGTH (const Type (&)[n]) { return n; }
#define HB_STMT_START do
#define HB_STMT_END while (0)
#define _ASSERT_STATIC1(_line, _cond) typedef int _static_assert_on_line_##_line##_failed[(_cond)?1:-1]
#define _ASSERT_STATIC1(_line, _cond) HB_UNUSED typedef int _static_assert_on_line_##_line##_failed[(_cond)?1:-1]
#define _ASSERT_STATIC0(_line, _cond) _ASSERT_STATIC1 (_line, (_cond))
#define ASSERT_STATIC(_cond) _ASSERT_STATIC0 (__LINE__, (_cond))
@ -139,7 +193,7 @@ ASSERT_STATIC (sizeof (hb_var_int_t) == 4);
/* Check _assertion in a method environment */
#define _ASSERT_POD1(_line) \
inline void _static_assertion_on_line_##_line (void) const \
HB_UNUSED inline void _static_assertion_on_line_##_line (void) const \
{ _ASSERT_INSTANCE_POD1 (_line, *this); /* Make sure it's POD. */ }
# define _ASSERT_POD0(_line) _ASSERT_POD1 (_line)
# define ASSERT_POD() _ASSERT_POD0 (__LINE__)
@ -148,68 +202,10 @@ ASSERT_STATIC (sizeof (hb_var_int_t) == 4);
/* Misc */
#if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__)
#define _HB_BOOLEAN_EXPR(expr) ((expr) ? 1 : 0)
#define likely(expr) (__builtin_expect (_HB_BOOLEAN_EXPR(expr), 1))
#define unlikely(expr) (__builtin_expect (_HB_BOOLEAN_EXPR(expr), 0))
#else
#define likely(expr) (expr)
#define unlikely(expr) (expr)
#endif
#ifndef __GNUC__
#undef __attribute__
#define __attribute__(x)
#endif
#if __GNUC__ >= 3
#define HB_PURE_FUNC __attribute__((pure))
#define HB_CONST_FUNC __attribute__((const))
#define HB_PRINTF_FUNC(format_idx, arg_idx) __attribute__((__format__ (__printf__, format_idx, arg_idx)))
#else
#define HB_PURE_FUNC
#define HB_CONST_FUNC
#define HB_PRINTF_FUNC(format_idx, arg_idx)
#endif
#if __GNUC__ >= 4
#define HB_UNUSED __attribute__((unused))
#else
#define HB_UNUSED
#endif
#ifndef HB_INTERNAL
# ifndef __MINGW32__
# define HB_INTERNAL __attribute__((__visibility__("hidden")))
# else
# define HB_INTERNAL
# endif
#endif
#if (defined(__WIN32__) && !defined(__WINE__)) || defined(_MSC_VER)
#define snprintf _snprintf
#endif
#ifdef _MSC_VER
#undef inline
#define inline __inline
#endif
#ifdef __STRICT_ANSI__
#undef inline
#define inline __inline__
#endif
#if __GNUC__ >= 3
#define HB_FUNC __PRETTY_FUNCTION__
#elif defined(_MSC_VER)
#define HB_FUNC __FUNCSIG__
#else
#define HB_FUNC __func__
#endif
/* Void! */
struct _hb_void_t {};
typedef const _hb_void_t &hb_void_t;
#define HB_VOID (* (const _hb_void_t *) NULL)
/* Return the number of 1 bits in mask. */
static inline HB_CONST_FUNC unsigned int
@ -219,7 +215,7 @@ _hb_popcount32 (uint32_t mask)
return __builtin_popcount (mask);
#else
/* "HACKMEM 169" */
register uint32_t y;
uint32_t y;
y = (mask >> 1) &033333333333;
y = mask - y - ((y >>1) & 033333333333);
return (((y + (y >> 3)) & 030707070707) % 077);
@ -233,7 +229,7 @@ _hb_bit_storage (unsigned int number)
#if defined(__GNUC__) && (__GNUC__ >= 4) && defined(__OPTIMIZE__)
return likely (number) ? (sizeof (unsigned int) * 8 - __builtin_clz (number)) : 0;
#else
register unsigned int n_bits = 0;
unsigned int n_bits = 0;
while (number) {
n_bits++;
number >>= 1;
@ -249,7 +245,7 @@ _hb_ctz (unsigned int number)
#if defined(__GNUC__) && (__GNUC__ >= 4) && defined(__OPTIMIZE__)
return likely (number) ? __builtin_ctz (number) : 0;
#else
register unsigned int n_bits = 0;
unsigned int n_bits = 0;
if (unlikely (!number)) return 0;
while (!(number & 1)) {
n_bits++;
@ -276,7 +272,7 @@ typedef int (*hb_compare_func_t) (const void *, const void *);
#define HB_PREALLOCED_ARRAY_INIT {0}
template <typename Type, unsigned int StaticSize>
template <typename Type, unsigned int StaticSize=16>
struct hb_prealloced_array_t
{
unsigned int len;
@ -357,14 +353,14 @@ struct hb_prealloced_array_t
return NULL;
}
inline void sort (void)
inline void qsort (void)
{
qsort (array, len, sizeof (Type), (hb_compare_func_t) Type::cmp);
::qsort (array, len, sizeof (Type), (hb_compare_func_t) Type::cmp);
}
inline void sort (unsigned int start, unsigned int end)
inline void qsort (unsigned int start, unsigned int end)
{
qsort (array + start, end - start, sizeof (Type), (hb_compare_func_t) Type::cmp);
::qsort (array + start, end - start, sizeof (Type), (hb_compare_func_t) Type::cmp);
}
template <typename T>
@ -387,12 +383,11 @@ struct hb_prealloced_array_t
}
};
#define HB_AUTO_ARRAY_PREALLOCED 16
template <typename Type>
struct hb_auto_array_t : hb_prealloced_array_t <Type, HB_AUTO_ARRAY_PREALLOCED>
struct hb_auto_array_t : hb_prealloced_array_t <Type>
{
hb_auto_array_t (void) { hb_prealloced_array_t<Type, HB_AUTO_ARRAY_PREALLOCED>::init (); }
~hb_auto_array_t (void) { hb_prealloced_array_t<Type, HB_AUTO_ARRAY_PREALLOCED>::finish (); }
hb_auto_array_t (void) { hb_prealloced_array_t<Type>::init (); }
~hb_auto_array_t (void) { hb_prealloced_array_t<Type>::finish (); }
};
@ -725,7 +720,7 @@ static inline void _hb_warn_no_return (bool returned)
}
}
template <>
inline void _hb_warn_no_return<hb_void_t> (bool returned HB_UNUSED)
/*static*/ inline void _hb_warn_no_return<hb_void_t> (bool returned HB_UNUSED)
{}
template <int max_level, typename ret_t>
@ -791,20 +786,23 @@ struct hb_auto_trace_t<0, ret_t> {
/* Misc */
template <typename T> class hb_assert_unsigned_t;
template <> class hb_assert_unsigned_t<unsigned char> {};
template <> class hb_assert_unsigned_t<unsigned short> {};
template <> class hb_assert_unsigned_t<unsigned int> {};
template <> class hb_assert_unsigned_t<unsigned long> {};
/* Pre-mature optimization:
* Checks for lo <= u <= hi but with an optimization if lo and hi
* are only different in a contiguous set of lower-most bits.
*/
template <typename T> static inline bool
hb_in_range (T u, T lo, T hi)
{
if ( ((lo^hi) & lo) == 0 &&
((lo^hi) & hi) == (lo^hi) &&
((lo^hi) & ((lo^hi) + 1)) == 0 )
return (u & ~(lo^hi)) == lo;
else
return lo <= u && u <= hi;
/* The sizeof() is here to force template instantiation.
* I'm sure there are better ways to do this but can't think of
* one right now. Declaring a variable won't work as HB_UNUSED
* is unsable on some platforms and unused types are less likely
* to generate a warning than unused variables. */
ASSERT_STATIC (sizeof (hb_assert_unsigned_t<T>) >= 0);
return (u - lo) <= (hi - lo);
}
template <typename T> static inline bool

View File

@ -104,8 +104,6 @@ hb_shape_plan_create (hb_face_t *face,
unsigned int num_user_features,
const char * const *shaper_list)
{
assert (props->direction != HB_DIRECTION_INVALID);
hb_shape_plan_t *shape_plan;
hb_feature_t *features = NULL;
@ -120,6 +118,8 @@ hb_shape_plan_create (hb_face_t *face,
return hb_shape_plan_get_empty ();
}
assert (props->direction != HB_DIRECTION_INVALID);
hb_face_make_immutable (face);
shape_plan->default_shaper_list = shaper_list == NULL;
shape_plan->face_unsafe = face;

View File

@ -34,25 +34,21 @@
/* Only picks up fonts that have a "Silf" table. */
HB_SHAPER_IMPLEMENT (graphite2)
#endif
#ifdef HAVE_CORETEXT
/* Only picks up fonts that have a "mort" or "morx" table. */
HB_SHAPER_IMPLEMENT (coretext)
HB_SHAPER_IMPLEMENT (coretext_aat)
#endif
#ifdef HAVE_OT
HB_SHAPER_IMPLEMENT (ot) /* <--- This is our main OpenType shaper. */
#endif
#ifdef HAVE_HB_OLD
HB_SHAPER_IMPLEMENT (old)
#endif
#ifdef HAVE_ICU_LE
HB_SHAPER_IMPLEMENT (icu_le)
#endif
#ifdef HAVE_UNISCRIBE
HB_SHAPER_IMPLEMENT (uniscribe)
#endif
#ifdef HAVE_CORETEXT
HB_SHAPER_IMPLEMENT (coretext)
#endif
#ifdef HAVE_FALLBACK
HB_SHAPER_IMPLEMENT (fallback) /* <--- This should be last. */

View File

@ -102,72 +102,70 @@ HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE
}
unsigned int
inline unsigned int
modified_combining_class (hb_codepoint_t unicode)
{
/* XXX This hack belongs to the Myanmar shaper. */
if (unlikely (unicode == 0x1037)) unicode = 0x103A;
if (unlikely (unicode == 0x1037u)) unicode = 0x103Au;
/* XXX This hack belongs to the SEA shaper (for Tai Tham):
* Reorder SAKOT to ensure it comes after any tone marks. */
if (unlikely (unicode == 0x1A60)) return 254;
if (unlikely (unicode == 0x1A60u)) return 254;
/* XXX This hack belongs to the Tibetan shaper:
* Reorder PADMA to ensure it comes after any vowel marks. */
if (unlikely (unicode == 0x0FC6u)) return 254;
return _hb_modified_combining_class[combining_class (unicode)];
}
inline hb_bool_t
static inline hb_bool_t
is_variation_selector (hb_codepoint_t unicode)
{
return unlikely (hb_in_ranges<hb_codepoint_t> (unicode,
0x180B, 0x180D, /* MONGOLIAN FREE VARIATION SELECTOR ONE..THREE */
0xFE00, 0xFE0F, /* VARIATION SELECTOR-1..16 */
0xE0100, 0xE01EF)); /* VARIATION SELECTOR-17..256 */
/* U+180B..180D MONGOLIAN FREE VARIATION SELECTORs are handled in the
* Arabic shaper. No need to match them here. */
return unlikely (hb_in_ranges (unicode,
0xFE00u, 0xFE0Fu, /* VARIATION SELECTOR-1..16 */
0xE0100u, 0xE01EFu)); /* VARIATION SELECTOR-17..256 */
}
/* Default_Ignorable codepoints:
*
* Note that as of Oct 2012 (Unicode 6.2), U+180E MONGOLIAN VOWEL SEPARATOR
* is NOT Default_Ignorable, but it really behaves in a way that it should
* be. That has been reported to the Unicode Technical Committee for
* consideration. As such, we include it here, since Uniscribe removes it.
* It *is* in Unicode 6.3 however. U+061C ARABIC LETTER MARK from Unicode
* 6.3 is also added manually. The new Unicode 6.3 bidi formatting
* characters are encoded in a block that was Default_Ignorable already.
*
* Note: While U+115F, U+1160, U+3164 and U+FFA0 are Default_Ignorable,
* we do NOT want to hide them, as the way Uniscribe has implemented them
* is with regular spacing glyphs, and that's the way fonts are made to work.
* As such, we make exceptions for those four.
*
* Gathered from:
* http://unicode.org/cldr/utility/list-unicodeset.jsp?a=[:DI:]&abb=on&ucd=on&esc=on
*
* Last updated to the page with the following versions:
* Version 3.6; ICU version: 50.0.1.0; Unicode version: 6.1.0.0
*
* 4,167 Code Points
*
* [\u00AD\u034F\u115F\u1160\u17B4\u17B5\u180B-\u180D\u200B-\u200F\u202A-\u202E\u2060-\u206F\u3164\uFE00-\uFE0F\uFEFF\uFFA0\uFFF0-\uFFF8\U0001D173-\U0001D17A\U000E0000-\U000E0FFF]
*
* 00AD ;SOFT HYPHEN
* 034F ;COMBINING GRAPHEME JOINER
* #115F ;HANGUL CHOSEONG FILLER
* #1160 ;HANGUL JUNGSEONG FILLER
* 17B4 ;KHMER VOWEL INHERENT AQ
* 17B5 ;KHMER VOWEL INHERENT AA
* 180B..180D ;MONGOLIAN FREE VARIATION SELECTOR THREE
* 200B..200F ;RIGHT-TO-LEFT MARK
* 202A..202E ;RIGHT-TO-LEFT OVERRIDE
* 2060..206F ;NOMINAL DIGIT SHAPES
* #3164 ;HANGUL FILLER
* FE00..FE0F ;VARIATION SELECTOR-16
* FEFF ;ZERO WIDTH NO-BREAK SPACE
* #FFA0 ;HALFWIDTH HANGUL FILLER
* FFF0..FFF8 ;<unassigned-FFF8>
* 1D173..1D17A ;MUSICAL SYMBOL END PHRASE
* E0000..E0FFF ;<unassigned-E0FFF>
* Unicode 7.0:
* $ grep '; Default_Ignorable_Code_Point ' DerivedCoreProperties.txt | sed 's/;.*#/#/'
* 00AD # Cf SOFT HYPHEN
* 034F # Mn COMBINING GRAPHEME JOINER
* 061C # Cf ARABIC LETTER MARK
* 115F..1160 # Lo [2] HANGUL CHOSEONG FILLER..HANGUL JUNGSEONG FILLER
* 17B4..17B5 # Mn [2] KHMER VOWEL INHERENT AQ..KHMER VOWEL INHERENT AA
* 180B..180D # Mn [3] MONGOLIAN FREE VARIATION SELECTOR ONE..MONGOLIAN FREE VARIATION SELECTOR THREE
* 180E # Cf MONGOLIAN VOWEL SEPARATOR
* 200B..200F # Cf [5] ZERO WIDTH SPACE..RIGHT-TO-LEFT MARK
* 202A..202E # Cf [5] LEFT-TO-RIGHT EMBEDDING..RIGHT-TO-LEFT OVERRIDE
* 2060..2064 # Cf [5] WORD JOINER..INVISIBLE PLUS
* 2065 # Cn <reserved-2065>
* 2066..206F # Cf [10] LEFT-TO-RIGHT ISOLATE..NOMINAL DIGIT SHAPES
* 3164 # Lo HANGUL FILLER
* FE00..FE0F # Mn [16] VARIATION SELECTOR-1..VARIATION SELECTOR-16
* FEFF # Cf ZERO WIDTH NO-BREAK SPACE
* FFA0 # Lo HALFWIDTH HANGUL FILLER
* FFF0..FFF8 # Cn [9] <reserved-FFF0>..<reserved-FFF8>
* 1BCA0..1BCA3 # Cf [4] SHORTHAND FORMAT LETTER OVERLAP..SHORTHAND FORMAT UP STEP
* 1D173..1D17A # Cf [8] MUSICAL SYMBOL BEGIN BEAM..MUSICAL SYMBOL END PHRASE
* E0000 # Cn <reserved-E0000>
* E0001 # Cf LANGUAGE TAG
* E0002..E001F # Cn [30] <reserved-E0002>..<reserved-E001F>
* E0020..E007F # Cf [96] TAG SPACE..CANCEL TAG
* E0080..E00FF # Cn [128] <reserved-E0080>..<reserved-E00FF>
* E0100..E01EF # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256
* E01F0..E0FFF # Cn [3600] <reserved-E01F0>..<reserved-E0FFF>
*/
inline hb_bool_t
static inline hb_bool_t
is_default_ignorable (hb_codepoint_t ch)
{
hb_codepoint_t plane = ch >> 16;
@ -176,16 +174,16 @@ HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE
/* BMP */
hb_codepoint_t page = ch >> 8;
switch (page) {
case 0x00: return unlikely (ch == 0x00AD);
case 0x03: return unlikely (ch == 0x034F);
case 0x06: return unlikely (ch == 0x061C);
case 0x17: return hb_in_range<hb_codepoint_t> (ch, 0x17B4, 0x17B5);
case 0x18: return hb_in_range<hb_codepoint_t> (ch, 0x180B, 0x180E);
case 0x20: return hb_in_ranges<hb_codepoint_t> (ch, 0x200B, 0x200F,
0x202A, 0x202E,
0x2060, 0x206F);
case 0xFE: return hb_in_range<hb_codepoint_t> (ch, 0xFE00, 0xFE0F) || ch == 0xFEFF;
case 0xFF: return hb_in_range<hb_codepoint_t> (ch, 0xFFF0, 0xFFF8);
case 0x00: return unlikely (ch == 0x00ADu);
case 0x03: return unlikely (ch == 0x034Fu);
case 0x06: return unlikely (ch == 0x061Cu);
case 0x17: return hb_in_range (ch, 0x17B4u, 0x17B5u);
case 0x18: return hb_in_range (ch, 0x180Bu, 0x180Eu);
case 0x20: return hb_in_ranges (ch, 0x200Bu, 0x200Fu,
0x202Au, 0x202Eu,
0x2060u, 0x206Fu);
case 0xFE: return hb_in_range (ch, 0xFE00u, 0xFE0Fu) || ch == 0xFEFFu;
case 0xFF: return hb_in_range (ch, 0xFFF0u, 0xFFF8u);
default: return false;
}
}
@ -193,8 +191,9 @@ HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE
{
/* Other planes */
switch (plane) {
case 0x01: return hb_in_range<hb_codepoint_t> (ch, 0x0001D173, 0x0001D17A);
case 0x0E: return hb_in_range<hb_codepoint_t> (ch, 0x000E0000, 0x000E0FFF);
case 0x01: return hb_in_ranges (ch, 0x1BCA0u, 0x1BCA3u,
0x1D173u, 0x1D17Au);
case 0x0E: return hb_in_range (ch, 0xE0000u, 0xE0FFFu);
default: return false;
}
}

View File

@ -133,7 +133,7 @@ hb_unicode_funcs_get_default (void)
#ifdef HAVE_GLIB
HB_UNICODE_FUNCS_IMPLEMENT(glib)
#elif 0 && defined(HAVE_ICU)
#elif defined(HAVE_ICU) && defined(HAVE_ICU_BUILTIN)
HB_UNICODE_FUNCS_IMPLEMENT(icu)
#elif defined(HAVE_UCDN)
HB_UNICODE_FUNCS_IMPLEMENT(ucdn)
@ -146,8 +146,13 @@ hb_unicode_funcs_get_default (void)
}
#if !defined(HB_NO_UNICODE_FUNCS) && defined(HB_UNICODE_FUNCS_NIL)
#pragma message("Could not find any Unicode functions implementation, you have to provide your own.")
#pragma message("To suppress this warnings, define HB_NO_UNICODE_FUNCS.")
#ifdef _MSC_VER
#pragma message("Could not find any Unicode functions implementation, you have to provide your own")
#pragma message("To suppress this warnings, define HB_NO_UNICODE_FUNCS")
#else
#warning "Could not find any Unicode functions implementation, you have to provide your own"
#warning "To suppress this warning, define HB_NO_UNICODE_FUNCS"
#endif
#endif
/**

View File

@ -1,5 +1,5 @@
/*
* Copyright © 2011,2012 Google, Inc.
* Copyright © 2011,2012,2014 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
@ -29,176 +29,221 @@
#include "hb-private.hh"
template <typename T, bool validate=true> struct hb_utf_t;
/* UTF-8 */
#define HB_UTF8_COMPUTE(Char, Mask, Len) \
if (Char < 128) { Len = 1; Mask = 0x7f; } \
else if ((Char & 0xe0) == 0xc0) { Len = 2; Mask = 0x1f; } \
else if ((Char & 0xf0) == 0xe0) { Len = 3; Mask = 0x0f; } \
else if ((Char & 0xf8) == 0xf0) { Len = 4; Mask = 0x07; } \
else Len = 0;
template <>
struct hb_utf_t<uint8_t, true>
{
static inline const uint8_t *
hb_utf_next (const uint8_t *text,
next (const uint8_t *text,
const uint8_t *end,
hb_codepoint_t *unicode)
hb_codepoint_t *unicode,
hb_codepoint_t replacement)
{
hb_codepoint_t c = *text, mask;
unsigned int len;
/* Written to only accept well-formed sequences.
* Based on ideas from ICU's U8_NEXT.
* Generates one "replacement" for each ill-formed byte. */
/* TODO check for overlong sequences? */
hb_codepoint_t c = *text++;
HB_UTF8_COMPUTE (c, mask, len);
if (unlikely (!len || (unsigned int) (end - text) < len)) {
*unicode = -1;
return text + 1;
} else {
hb_codepoint_t result;
unsigned int i;
result = c & mask;
for (i = 1; i < len; i++)
if (c > 0x7Fu)
{
if (unlikely ((text[i] & 0xc0) != 0x80))
if (hb_in_range (c, 0xC2u, 0xDFu)) /* Two-byte */
{
*unicode = -1;
return text + 1;
unsigned int t1;
if (likely (text < end &&
(t1 = text[0] - 0x80u) <= 0x3Fu))
{
c = ((c&0x1Fu)<<6) | t1;
text++;
}
result <<= 6;
result |= (text[i] & 0x3f);
else
goto error;
}
*unicode = result;
return text + len;
else if (hb_in_range (c, 0xE0u, 0xEFu)) /* Three-byte */
{
unsigned int t1, t2;
if (likely (1 < end - text &&
(t1 = text[0] - 0x80u) <= 0x3Fu &&
(t2 = text[1] - 0x80u) <= 0x3Fu))
{
c = ((c&0xFu)<<12) | (t1<<6) | t2;
if (unlikely (c < 0x0800u || hb_in_range (c, 0xD800u, 0xDFFFu)))
goto error;
text += 2;
}
else
goto error;
}
else if (hb_in_range (c, 0xF0u, 0xF4u)) /* Four-byte */
{
unsigned int t1, t2, t3;
if (likely (2 < end - text &&
(t1 = text[0] - 0x80u) <= 0x3Fu &&
(t2 = text[1] - 0x80u) <= 0x3Fu &&
(t3 = text[2] - 0x80u) <= 0x3Fu))
{
c = ((c&0x7u)<<18) | (t1<<12) | (t2<<6) | t3;
if (unlikely (!hb_in_range (c, 0x10000u, 0x10FFFFu)))
goto error;
text += 3;
}
else
goto error;
}
else
goto error;
}
*unicode = c;
return text;
error:
*unicode = replacement;
return text;
}
static inline const uint8_t *
hb_utf_prev (const uint8_t *text,
prev (const uint8_t *text,
const uint8_t *start,
hb_codepoint_t *unicode)
hb_codepoint_t *unicode,
hb_codepoint_t replacement)
{
const uint8_t *end = text--;
while (start < text && (*text & 0xc0) == 0x80 && end - text < 4)
text--;
hb_codepoint_t c = *text, mask;
unsigned int len;
/* TODO check for overlong sequences? */
HB_UTF8_COMPUTE (c, mask, len);
if (unlikely (!len || (unsigned int) (end - text) != len)) {
*unicode = -1;
return end - 1;
} else {
hb_codepoint_t result;
unsigned int i;
result = c & mask;
for (i = 1; i < len; i++)
{
result <<= 6;
result |= (text[i] & 0x3f);
}
*unicode = result;
if (likely (next (text, end, unicode, replacement) == end))
return text;
}
}
*unicode = replacement;
return end - 1;
}
static inline unsigned int
hb_utf_strlen (const uint8_t *text)
strlen (const uint8_t *text)
{
return strlen ((const char *) text);
return ::strlen ((const char *) text);
}
};
/* UTF-16 */
template <>
struct hb_utf_t<uint16_t, true>
{
static inline const uint16_t *
hb_utf_next (const uint16_t *text,
next (const uint16_t *text,
const uint16_t *end,
hb_codepoint_t *unicode)
hb_codepoint_t *unicode,
hb_codepoint_t replacement)
{
hb_codepoint_t c = *text++;
if (unlikely (hb_in_range<hb_codepoint_t> (c, 0xd800, 0xdbff)))
if (likely (!hb_in_range (c, 0xD800u, 0xDFFFu)))
{
/* high surrogate */
hb_codepoint_t l;
if (text < end && ((l = *text), likely (hb_in_range<hb_codepoint_t> (l, 0xdc00, 0xdfff))))
{
/* low surrogate */
*unicode = (c << 10) + l - ((0xd800 << 10) - 0x10000 + 0xdc00);
text++;
} else
*unicode = -1;
} else
*unicode = c;
return text;
}
if (likely (hb_in_range (c, 0xD800u, 0xDBFFu)))
{
/* High-surrogate in c */
hb_codepoint_t l;
if (text < end && ((l = *text), likely (hb_in_range (l, 0xDC00u, 0xDFFFu))))
{
/* Low-surrogate in l */
*unicode = (c << 10) + l - ((0xD800u << 10) - 0x10000u + 0xDC00u);
text++;
return text;
}
}
/* Lonely / out-of-order surrogate. */
*unicode = replacement;
return text;
}
static inline const uint16_t *
hb_utf_prev (const uint16_t *text,
prev (const uint16_t *text,
const uint16_t *start,
hb_codepoint_t *unicode)
hb_codepoint_t *unicode,
hb_codepoint_t replacement)
{
hb_codepoint_t c = *--text;
const uint16_t *end = text--;
hb_codepoint_t c = *text;
if (unlikely (hb_in_range<hb_codepoint_t> (c, 0xdc00, 0xdfff)))
if (likely (!hb_in_range (c, 0xD800u, 0xDFFFu)))
{
/* low surrogate */
hb_codepoint_t h;
if (start < text && ((h = *(text - 1)), likely (hb_in_range<hb_codepoint_t> (h, 0xd800, 0xdbff))))
{
/* high surrogate */
*unicode = (h << 10) + c - ((0xd800 << 10) - 0x10000 + 0xdc00);
text--;
} else
*unicode = -1;
} else
*unicode = c;
return text;
}
if (likely (start < text && hb_in_range (c, 0xDC00u, 0xDFFFu)))
text--;
if (likely (next (text, end, unicode, replacement) == end))
return text;
*unicode = replacement;
return end - 1;
}
static inline unsigned int
hb_utf_strlen (const uint16_t *text)
strlen (const uint16_t *text)
{
unsigned int l = 0;
while (*text++) l++;
return l;
}
};
/* UTF-32 */
static inline const uint32_t *
hb_utf_next (const uint32_t *text,
const uint32_t *end HB_UNUSED,
hb_codepoint_t *unicode)
template <bool validate>
struct hb_utf_t<uint32_t, validate>
{
*unicode = *text++;
static inline const uint32_t *
next (const uint32_t *text,
const uint32_t *end HB_UNUSED,
hb_codepoint_t *unicode,
hb_codepoint_t replacement)
{
hb_codepoint_t c = *text++;
if (validate && unlikely (c > 0x10FFFFu || hb_in_range (c, 0xD800u, 0xDFFFu)))
goto error;
*unicode = c;
return text;
error:
*unicode = replacement;
return text;
}
static inline const uint32_t *
hb_utf_prev (const uint32_t *text,
prev (const uint32_t *text,
const uint32_t *start HB_UNUSED,
hb_codepoint_t *unicode)
hb_codepoint_t *unicode,
hb_codepoint_t replacement)
{
*unicode = *--text;
return text;
next (text - 1, text, unicode, replacement);
return text - 1;
}
static inline unsigned int
hb_utf_strlen (const uint32_t *text)
strlen (const uint32_t *text)
{
unsigned int l = 0;
while (*text++) l++;
return l;
}
};
#endif /* HB_UTF_PRIVATE_HH */

View File

@ -38,12 +38,12 @@ HB_BEGIN_DECLS
#define HB_VERSION_MAJOR 0
#define HB_VERSION_MINOR 9
#define HB_VERSION_MICRO 25
#define HB_VERSION_MICRO 32
#define HB_VERSION_STRING "0.9.25"
#define HB_VERSION_STRING "0.9.32"
#define HB_VERSION_CHECK(major,minor,micro) \
((major)*10000+(minor)*100+(micro) >= \
#define HB_VERSION_ATLEAST(major,minor,micro) \
((major)*10000+(minor)*100+(micro) <= \
HB_VERSION_MAJOR*10000+HB_VERSION_MINOR*100+HB_VERSION_MICRO)
@ -56,7 +56,7 @@ const char *
hb_version_string (void);
hb_bool_t
hb_version_check (unsigned int major,
hb_version_atleast (unsigned int major,
unsigned int minor,
unsigned int micro);

View File

@ -53,14 +53,3 @@
#endif
#include "hb-unicode-private.hh"
#if !defined(HB_NO_UNICODE_FUNCS) && defined(HB_UNICODE_FUNCS_NIL)
#ifdef _MSC_VER
#pragma message("Could not find any Unicode functions implementation, you have to provide your own")
#pragma message("To suppress this warnings, define HB_NO_UNICODE_FUNCS")
#else
#warning "Could not find any Unicode functions implementation, you have to provide your own"
#warning "To suppress this warning, define HB_NO_UNICODE_FUNCS"
#endif
#endif

View File

@ -1076,7 +1076,7 @@ int QTextEngine::shapeTextWithHarfbuzzNG(const QScriptItem &si, const ushort *st
hb_buffer_set_segment_properties(buffer, &props);
hb_buffer_guess_segment_properties(buffer);
uint buffer_flags = 0; // HB_BUFFER_FLAG_DEFAULT
uint buffer_flags = HB_BUFFER_FLAG_DEFAULT;
// Symbol encoding used to encode various crap in the 32..255 character code range,
// and thus might override U+00AD [SHY]; avoid hiding default ignorables
if (actualFontEngine->symbol)