Merge branch 'master' into cff-subset
This commit is contained in:
commit
0604bf2b38
@ -79,6 +79,54 @@ jobs:
|
||||
- run: make
|
||||
- run: LD_LIBRARY_PATH="$PWD/freetype-2.9/objs/.libs" make check || .ci/fail.sh
|
||||
|
||||
clang-asan:
|
||||
docker:
|
||||
- image: ubuntu:18.04
|
||||
steps:
|
||||
- checkout
|
||||
- run: apt update || true
|
||||
- run: apt install -y clang-6.0 binutils libtool autoconf automake make pkg-config gtk-doc-tools ragel libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python python-pip
|
||||
- run: pip install fonttools
|
||||
- run: CPPFLAGS="-fsanitize=address" LDFLAGS="-fsanitize=address" CC=clang-6.0 CXX=clang++-6.0 ./autogen.sh --with-freetype --with-glib --with-cairo --with-icu --with-graphite2
|
||||
- run: make
|
||||
- run: make check || .ci/fail.sh
|
||||
|
||||
clang-msan:
|
||||
docker:
|
||||
- image: ubuntu:18.04
|
||||
steps:
|
||||
- checkout
|
||||
- run: apt update || true
|
||||
- run: apt install -y clang-6.0 binutils libtool autoconf automake make pkg-config ragel libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python python-pip
|
||||
- run: pip install fonttools
|
||||
- run: CPPFLAGS="-fsanitize=memory" LDFLAGS="-fsanitize=memory" CC=clang-6.0 CXX=clang++-6.0 ./autogen.sh --with-freetype --with-glib --with-cairo --with-icu --with-graphite2
|
||||
- run: make
|
||||
- run: make check || .ci/fail.sh
|
||||
|
||||
clang-tsan:
|
||||
docker:
|
||||
- image: ubuntu:18.04
|
||||
steps:
|
||||
- checkout
|
||||
- run: apt update || true
|
||||
- run: apt install -y clang-6.0 binutils libtool autoconf automake make pkg-config ragel libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python python-pip
|
||||
- run: pip install fonttools
|
||||
- run: CPPFLAGS="-fsanitize=thread" LDFLAGS="-fsanitize=thread" CC=clang-6.0 CXX=clang++-6.0 ./autogen.sh --with-freetype --with-glib --with-cairo --with-icu --with-graphite2
|
||||
- run: make
|
||||
- run: make check || .ci/fail.sh
|
||||
|
||||
clang-ubsan:
|
||||
docker:
|
||||
- image: ubuntu:18.04
|
||||
steps:
|
||||
- checkout
|
||||
- run: apt update || true
|
||||
- run: apt install -y clang-6.0 binutils libtool autoconf automake make pkg-config ragel libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python python-pip
|
||||
- run: pip install fonttools
|
||||
- run: CPPFLAGS="-fsanitize=undefined" LDFLAGS="-fsanitize=undefined" CC=clang-6.0 CXX=clang++-6.0 ./autogen.sh --with-freetype --with-glib --with-cairo --with-icu --with-graphite2
|
||||
- run: make
|
||||
- run: make check || .ci/fail.sh
|
||||
|
||||
fedora-outoftreebuild:
|
||||
docker:
|
||||
- image: fedora
|
||||
@ -200,6 +248,10 @@ workflows:
|
||||
- alpine-O3-NOMMAP
|
||||
- archlinux-debug-O0-py3
|
||||
- clang-O3-O0
|
||||
- clang-asan
|
||||
#- clang-msan
|
||||
- clang-tsan
|
||||
#- clang-ubsan
|
||||
- fedora-outoftreebuild
|
||||
|
||||
# cmake based builds
|
||||
|
@ -26,7 +26,7 @@ for soname in harfbuzz harfbuzz-subset harfbuzz-icu harfbuzz-gobject; do
|
||||
symprefix=
|
||||
if test $suffix = dylib; then symprefix=_; fi
|
||||
|
||||
EXPORTED_SYMBOLS="`nm "$so" | grep ' [BCDGINRSTVW] .' | grep -v " $symprefix\\($IGNORED_SYMBOLS\\>\\)" | cut -d' ' -f3 | c++filt`"
|
||||
EXPORTED_SYMBOLS="`nm "$so" | grep ' [BCDGINRSTV] .' | grep -v " $symprefix\\($IGNORED_SYMBOLS\\>\\)" | cut -d' ' -f3 | c++filt`"
|
||||
|
||||
prefix=$symprefix`basename "$so" | sed 's/libharfbuzz/hb/; s/-/_/g; s/[.].*//'`
|
||||
|
||||
|
@ -569,7 +569,8 @@ struct StateTableDriver
|
||||
/* If there's no action and we're just epsilon-transitioning to state 0,
|
||||
* safe to break. */
|
||||
if (c->is_actionable (this, entry) ||
|
||||
!(entry->newState == 0 && entry->flags == context_t::DontAdvance))
|
||||
!(entry->newState == StateTable<EntryData>::STATE_START_OF_TEXT &&
|
||||
entry->flags == context_t::DontAdvance))
|
||||
buffer->unsafe_to_break (buffer->idx - 1, buffer->idx + 1);
|
||||
}
|
||||
|
||||
|
@ -608,16 +608,14 @@ struct InsertionSubtable
|
||||
hb_buffer_t *buffer = driver->buffer;
|
||||
unsigned int flags = entry->flags;
|
||||
|
||||
if (entry->data.markedInsertIndex != 0xFFFF)
|
||||
if (entry->data.markedInsertIndex != 0xFFFF && mark_set)
|
||||
{
|
||||
unsigned int count = (entry->flags & MarkedInsertCount);
|
||||
unsigned int count = (flags & MarkedInsertCount);
|
||||
unsigned int start = entry->data.markedInsertIndex;
|
||||
const GlyphID *glyphs = &insertionAction[start];
|
||||
if (unlikely (!c->sanitizer.check_array (glyphs, count))) return false;
|
||||
|
||||
bool before = entry->flags & MarkedInsertBefore;
|
||||
|
||||
if (unlikely (!mark_set)) return false;
|
||||
bool before = flags & MarkedInsertBefore;
|
||||
|
||||
unsigned int end = buffer->out_len;
|
||||
buffer->move_to (mark);
|
||||
@ -635,12 +633,12 @@ struct InsertionSubtable
|
||||
|
||||
if (entry->data.currentInsertIndex != 0xFFFF)
|
||||
{
|
||||
unsigned int count = (entry->flags & CurrentInsertCount) >> 5;
|
||||
unsigned int count = (flags & CurrentInsertCount) >> 5;
|
||||
unsigned int start = entry->data.currentInsertIndex;
|
||||
const GlyphID *glyphs = &insertionAction[start];
|
||||
if (unlikely (!c->sanitizer.check_array (glyphs, count))) return false;
|
||||
|
||||
bool before = entry->flags & CurrentInsertBefore;
|
||||
bool before = flags & CurrentInsertBefore;
|
||||
|
||||
unsigned int end = buffer->out_len;
|
||||
|
||||
@ -652,7 +650,20 @@ struct InsertionSubtable
|
||||
if (!before)
|
||||
buffer->skip_glyph ();
|
||||
|
||||
buffer->move_to (end);
|
||||
/* Humm. Not sure where to move to. There's this wording under
|
||||
* DontAdvance flag:
|
||||
*
|
||||
* "If set, don't update the glyph index before going to the new state.
|
||||
* This does not mean that the glyph pointed to is the same one as
|
||||
* before. If you've made insertions immediately downstream of the
|
||||
* current glyph, the next glyph processed would in fact be the first
|
||||
* one inserted."
|
||||
*
|
||||
* This suggests that if DontAdvance is NOT set, we should move to
|
||||
* end+count. If it *was*, then move to end, such that newly inserted
|
||||
* glyphs are now visible.
|
||||
*/
|
||||
buffer->move_to ((flags & DontAdvance) ? end : end + count);
|
||||
}
|
||||
|
||||
if (flags & SetMark)
|
||||
@ -730,8 +741,25 @@ struct ChainSubtable
|
||||
friend struct Chain;
|
||||
|
||||
inline unsigned int get_size (void) const { return length; }
|
||||
inline unsigned int get_type (void) const { return coverage & 0xFF; }
|
||||
inline unsigned int get_type (void) const { return coverage & SubtableType; }
|
||||
|
||||
enum Coverage
|
||||
{
|
||||
Vertical = 0x80000000, /* If set, this subtable will only be applied
|
||||
* to vertical text. If clear, this subtable
|
||||
* will only be applied to horizontal text. */
|
||||
Descending = 0x40000000, /* If set, this subtable will process glyphs
|
||||
* in descending order. If clear, it will
|
||||
* process the glyphs in ascending order. */
|
||||
AllDirections = 0x20000000, /* If set, this subtable will be applied to
|
||||
* both horizontal and vertical text (i.e.
|
||||
* the state of bit 0x80000000 is ignored). */
|
||||
Logical = 0x10000000, /* If set, this subtable will process glyphs
|
||||
* in logical order (or reverse logical order,
|
||||
* depending on the value of bit 0x80000000). */
|
||||
Reserved = 0x0FFFFF00, /* Reserved, set to zero. */
|
||||
SubtableType = 0x000000FF, /* Subtable type; see following table. */
|
||||
};
|
||||
enum Type
|
||||
{
|
||||
Rearrangement = 0,
|
||||
@ -806,14 +834,59 @@ struct Chain
|
||||
unsigned int count = subtableCount;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
bool reverse;
|
||||
|
||||
if (!(subtable->subFeatureFlags & flags))
|
||||
goto skip;
|
||||
|
||||
if (!(subtable->coverage & ChainSubtable::AllDirections) &&
|
||||
HB_DIRECTION_IS_VERTICAL (c->buffer->props.direction) !=
|
||||
bool (subtable->coverage & ChainSubtable::Vertical))
|
||||
goto skip;
|
||||
|
||||
/* Buffer contents is always in logical direction. Determine if
|
||||
* we need to reverse before applying this subtable. We reverse
|
||||
* back after if we did reverse indeed.
|
||||
*
|
||||
* Quoting the spac:
|
||||
* """
|
||||
* Bits 28 and 30 of the coverage field control the order in which
|
||||
* glyphs are processed when the subtable is run by the layout engine.
|
||||
* Bit 28 is used to indicate if the glyph processing direction is
|
||||
* the same as logical order or layout order. Bit 30 is used to
|
||||
* indicate whether glyphs are processed forwards or backwards within
|
||||
* that order.
|
||||
|
||||
Bit 30 Bit 28 Interpretation for Horizontal Text
|
||||
0 0 The subtable is processed in layout order
|
||||
(the same order as the glyphs, which is
|
||||
always left-to-right).
|
||||
1 0 The subtable is processed in reverse layout order
|
||||
(the order opposite that of the glyphs, which is
|
||||
always right-to-left).
|
||||
0 1 The subtable is processed in logical order
|
||||
(the same order as the characters, which may be
|
||||
left-to-right or right-to-left).
|
||||
1 1 The subtable is processed in reverse logical order
|
||||
(the order opposite that of the characters, which
|
||||
may be right-to-left or left-to-right).
|
||||
*/
|
||||
reverse = subtable->coverage & ChainSubtable::Logical ?
|
||||
bool (subtable->coverage & ChainSubtable::Descending) :
|
||||
bool (subtable->coverage & ChainSubtable::Descending) !=
|
||||
HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction);
|
||||
|
||||
if (!c->buffer->message (c->font, "start chain subtable %d", c->lookup_index))
|
||||
goto skip;
|
||||
|
||||
if (reverse)
|
||||
c->buffer->reverse ();
|
||||
|
||||
subtable->dispatch (c);
|
||||
|
||||
if (reverse)
|
||||
c->buffer->reverse ();
|
||||
|
||||
(void) c->buffer->message (c->font, "end chain subtable %d", c->lookup_index);
|
||||
|
||||
skip:
|
||||
|
@ -574,18 +574,45 @@ fail_without_close:
|
||||
wchar_t * wchar_file_name = (wchar_t *) malloc (sizeof (wchar_t) * size);
|
||||
if (unlikely (wchar_file_name == nullptr)) goto fail_without_close;
|
||||
mbstowcs (wchar_file_name, file_name, size);
|
||||
#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP)
|
||||
{
|
||||
CREATEFILE2_EXTENDED_PARAMETERS ceparams = { 0 };
|
||||
ceparams.dwSize = sizeof(CREATEFILE2_EXTENDED_PARAMETERS);
|
||||
ceparams.dwFileAttributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED & 0xFFFF;
|
||||
ceparams.dwFileFlags = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED & 0xFFF00000;
|
||||
ceparams.dwSecurityQosFlags = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED & 0x000F0000;
|
||||
ceparams.lpSecurityAttributes = nullptr;
|
||||
ceparams.hTemplateFile = nullptr;
|
||||
fd = CreateFile2 (wchar_file_name, GENERIC_READ, FILE_SHARE_READ,
|
||||
OPEN_EXISTING, &ceparams);
|
||||
}
|
||||
#else
|
||||
fd = CreateFileW (wchar_file_name, GENERIC_READ, FILE_SHARE_READ, nullptr,
|
||||
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED,
|
||||
nullptr);
|
||||
#endif
|
||||
free (wchar_file_name);
|
||||
|
||||
if (unlikely (fd == INVALID_HANDLE_VALUE)) goto fail_without_close;
|
||||
|
||||
#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP)
|
||||
{
|
||||
LARGE_INTEGER length;
|
||||
GetFileSizeEx (fd, &length);
|
||||
file->length = length.LowPart;
|
||||
file->mapping = CreateFileMappingFromApp (fd, nullptr, PAGE_READONLY, length.QuadPart, nullptr);
|
||||
}
|
||||
#else
|
||||
file->length = (unsigned long) GetFileSize (fd, nullptr);
|
||||
file->mapping = CreateFileMapping (fd, nullptr, PAGE_READONLY, 0, 0, nullptr);
|
||||
#endif
|
||||
if (unlikely (file->mapping == nullptr)) goto fail;
|
||||
|
||||
#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP)
|
||||
file->contents = (char *) MapViewOfFileFromApp (file->mapping, FILE_MAP_READ, 0, 0);
|
||||
#else
|
||||
file->contents = (char *) MapViewOfFile (file->mapping, FILE_MAP_READ, 0, 0, 0);
|
||||
#endif
|
||||
if (unlikely (file->contents == nullptr)) goto fail;
|
||||
|
||||
CloseHandle (fd);
|
||||
|
@ -1887,6 +1887,10 @@ hb_buffer_t::sort (unsigned int start, unsigned int end, int(*compar)(const hb_g
|
||||
|
||||
/**
|
||||
* hb_buffer_diff:
|
||||
* @buffer: a buffer.
|
||||
* @reference: other buffer to compare to.
|
||||
* @dottedcircle_glyph: glyph id of U+25CC DOTTED CIRCLE, or (hb_codepont_t) -1.
|
||||
* @position_fuzz: allowed absolute difference in position values.
|
||||
*
|
||||
* If dottedcircle_glyph is (hb_codepoint_t) -1 then %HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT
|
||||
* and %HB_BUFFER_DIFF_FLAG_NOTDEF_PRESENT are never returned. This should be used by most
|
||||
|
@ -44,7 +44,6 @@ HB_BEGIN_DECLS
|
||||
* hb_glyph_info_t:
|
||||
* @codepoint: either a Unicode code point (before shaping) or a glyph index
|
||||
* (after shaping).
|
||||
* @mask:
|
||||
* @cluster: the index of the character in the original text that corresponds
|
||||
* to this #hb_glyph_info_t, or whatever the client passes to
|
||||
* hb_buffer_add(). More than one #hb_glyph_info_t can have the same
|
||||
@ -59,11 +58,13 @@ HB_BEGIN_DECLS
|
||||
*
|
||||
* The #hb_glyph_info_t is the structure that holds information about the
|
||||
* glyphs and their relation to input text.
|
||||
*
|
||||
*/
|
||||
typedef struct hb_glyph_info_t {
|
||||
typedef struct hb_glyph_info_t
|
||||
{
|
||||
hb_codepoint_t codepoint;
|
||||
hb_mask_t mask; /* Holds hb_glyph_flags_t after hb_shape(), plus other things. */
|
||||
/*< private >*/
|
||||
hb_mask_t mask;
|
||||
/*< public >*/
|
||||
uint32_t cluster;
|
||||
|
||||
/*< private >*/
|
||||
@ -92,6 +93,7 @@ typedef struct hb_glyph_info_t {
|
||||
typedef enum { /*< flags >*/
|
||||
HB_GLYPH_FLAG_UNSAFE_TO_BREAK = 0x00000001,
|
||||
|
||||
/*< private >*/
|
||||
HB_GLYPH_FLAG_DEFINED = 0x00000001 /* OR of all defined flags */
|
||||
} hb_glyph_flags_t;
|
||||
|
||||
@ -298,7 +300,15 @@ hb_buffer_set_flags (hb_buffer_t *buffer,
|
||||
HB_EXTERN hb_buffer_flags_t
|
||||
hb_buffer_get_flags (hb_buffer_t *buffer);
|
||||
|
||||
/*
|
||||
/**
|
||||
* hb_buffer_cluster_level_t:
|
||||
* @HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES: Return cluster values grouped by graphemes into
|
||||
* monotone order.
|
||||
* @HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS: Return cluster values grouped into monotone order.
|
||||
* @HB_BUFFER_CLUSTER_LEVEL_CHARACTERS: Don't group cluster values.
|
||||
* @HB_BUFFER_CLUSTER_LEVEL_DEFAULT: Default cluster level,
|
||||
* equal to @HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES.
|
||||
*
|
||||
* Since: 0.9.42
|
||||
*/
|
||||
typedef enum {
|
||||
|
@ -515,12 +515,14 @@ struct range_record_t {
|
||||
#define kUpperCaseType 38
|
||||
|
||||
/* Table data courtesy of Apple. */
|
||||
static const struct feature_mapping_t {
|
||||
FourCharCode otFeatureTag;
|
||||
static const struct feature_mapping_t
|
||||
{
|
||||
hb_tag_t otFeatureTag;
|
||||
uint16_t aatFeatureType;
|
||||
uint16_t selectorToEnable;
|
||||
uint16_t selectorToDisable;
|
||||
} feature_mappings[] = {
|
||||
} feature_mappings[] =
|
||||
{
|
||||
{ 'c2pc', kUpperCaseType, kUpperCasePetiteCapsSelector, kDefaultUpperCaseSelector },
|
||||
{ 'c2sc', kUpperCaseType, kUpperCaseSmallCapsSelector, kDefaultUpperCaseSelector },
|
||||
{ 'calt', kContextualAlternatesType, kContextualAlternatesOnSelector, kContextualAlternatesOffSelector },
|
||||
@ -601,7 +603,7 @@ static const struct feature_mapping_t {
|
||||
static int
|
||||
_hb_feature_mapping_cmp (const void *key_, const void *entry_)
|
||||
{
|
||||
unsigned int key = * (unsigned int *) key_;
|
||||
hb_tag_t key = * (unsigned int *) key_;
|
||||
const feature_mapping_t * entry = (const feature_mapping_t *) entry_;
|
||||
return key < entry->otFeatureTag ? -1 :
|
||||
key > entry->otFeatureTag ? 1 :
|
||||
|
@ -36,12 +36,12 @@
|
||||
|
||||
|
||||
/**
|
||||
* hb_face_count: Get number of faces on the blob
|
||||
* @blob:
|
||||
* hb_face_count:
|
||||
* @blob: a blob.
|
||||
*
|
||||
* Get number of faces in a blob.
|
||||
*
|
||||
*
|
||||
* Return value: Number of faces on the blob
|
||||
* Return value: Number of faces in @blob
|
||||
*
|
||||
* Since: 1.7.7
|
||||
**/
|
||||
@ -488,6 +488,9 @@ hb_face_get_glyph_count (const hb_face_t *face)
|
||||
/**
|
||||
* hb_face_get_table_tags:
|
||||
* @face: a face.
|
||||
* @start_offset: index of first tag to return.
|
||||
* @table_count: input length of @table_tags array, output number of items written.
|
||||
* @table_tags: array to write tags into.
|
||||
*
|
||||
* Retrieves table tags for a face, if possible.
|
||||
*
|
||||
|
@ -1703,9 +1703,11 @@ hb_font_get_ppem (hb_font_t *font,
|
||||
/**
|
||||
* hb_font_set_ptem:
|
||||
* @font: a font.
|
||||
* @ptem:
|
||||
* @ptem: font size in points.
|
||||
*
|
||||
* Sets "point size" of the font.
|
||||
* Sets "point size" of the font. Set to 0 to unset.
|
||||
*
|
||||
* There are 72 points in an inch.
|
||||
*
|
||||
* Since: 1.6.0
|
||||
**/
|
||||
@ -1931,9 +1933,9 @@ hb_font_get_variation_glyph_trampoline (hb_font_t *font,
|
||||
/**
|
||||
* hb_font_funcs_set_glyph_func:
|
||||
* @ffuncs: font functions.
|
||||
* @func: (closure user_data) (destroy destroy) (scope notified):
|
||||
* @user_data:
|
||||
* @destroy:
|
||||
* @func: (closure user_data) (destroy destroy) (scope notified): callback function.
|
||||
* @user_data: data to pass to @func.
|
||||
* @destroy: function to call when @user_data is not needed anymore.
|
||||
*
|
||||
* Deprecated. Use hb_font_funcs_set_nominal_glyph_func() and
|
||||
* hb_font_funcs_set_variation_glyph_func() instead.
|
||||
|
@ -344,10 +344,10 @@ struct hb_ot_apply_context_t :
|
||||
match_glyph_data = nullptr;
|
||||
matcher.set_match_func (nullptr, nullptr);
|
||||
matcher.set_lookup_props (c->lookup_props);
|
||||
/* Ignore ZWNJ if we are matching GSUB context, or matching GPOS. */
|
||||
/* Ignore ZWNJ if we are matching GPOS, or matching GSUB context and asked to. */
|
||||
matcher.set_ignore_zwnj (c->table_index == 1 || (context_match && c->auto_zwnj));
|
||||
/* Ignore ZWJ if we are matching GSUB context, or matching GPOS, or if asked to. */
|
||||
matcher.set_ignore_zwj (c->table_index == 1 || (context_match || c->auto_zwj));
|
||||
/* Ignore ZWJ if we are matching context, or asked to. */
|
||||
matcher.set_ignore_zwj (context_match || c->auto_zwj);
|
||||
matcher.set_mask (context_match ? -1 : c->lookup_mask);
|
||||
}
|
||||
inline void set_lookup_props (unsigned int lookup_props)
|
||||
@ -508,19 +508,20 @@ struct hb_ot_apply_context_t :
|
||||
random (false),
|
||||
random_state (1) {}
|
||||
|
||||
inline void set_lookup_mask (hb_mask_t mask) { lookup_mask = mask; }
|
||||
inline void set_auto_zwj (bool auto_zwj_) { auto_zwj = auto_zwj_; }
|
||||
inline void set_auto_zwnj (bool auto_zwnj_) { auto_zwnj = auto_zwnj_; }
|
||||
inline void set_random (bool random_) { random = random_; }
|
||||
inline void set_recurse_func (recurse_func_t func) { recurse_func = func; }
|
||||
inline void set_lookup_index (unsigned int lookup_index_) { lookup_index = lookup_index_; }
|
||||
inline void set_lookup_props (unsigned int lookup_props_)
|
||||
inline void reinit_iters (void)
|
||||
{
|
||||
lookup_props = lookup_props_;
|
||||
iter_input.init (this, false);
|
||||
iter_context.init (this, true);
|
||||
}
|
||||
|
||||
inline void set_lookup_mask (hb_mask_t mask) { lookup_mask = mask; }
|
||||
inline void set_auto_zwj (bool auto_zwj_) { auto_zwj = auto_zwj_; reinit_iters (); }
|
||||
inline void set_auto_zwnj (bool auto_zwnj_) { auto_zwnj = auto_zwnj_; reinit_iters (); }
|
||||
inline void set_random (bool random_) { random = random_; }
|
||||
inline void set_recurse_func (recurse_func_t func) { recurse_func = func; }
|
||||
inline void set_lookup_index (unsigned int lookup_index_) { lookup_index = lookup_index_; }
|
||||
inline void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; reinit_iters (); }
|
||||
|
||||
inline uint32_t random_number (void)
|
||||
{
|
||||
/* http://www.cplusplus.com/reference/random/minstd_rand/ */
|
||||
|
@ -131,6 +131,7 @@ struct post
|
||||
{
|
||||
index_to_offset.fini ();
|
||||
free (gids_sorted_by_name.get ());
|
||||
hb_blob_destroy (blob);
|
||||
}
|
||||
|
||||
inline bool get_glyph_name (hb_codepoint_t glyph,
|
||||
|
@ -95,7 +95,8 @@ static const indic_config_t indic_configs[] =
|
||||
* Indic shaper.
|
||||
*/
|
||||
|
||||
struct feature_list_t {
|
||||
struct feature_list_t
|
||||
{
|
||||
hb_tag_t tag;
|
||||
hb_ot_map_feature_flags_t flags;
|
||||
};
|
||||
@ -130,7 +131,10 @@ indic_features[] =
|
||||
{HB_TAG('b','l','w','s'), F_GLOBAL},
|
||||
{HB_TAG('p','s','t','s'), F_GLOBAL},
|
||||
{HB_TAG('h','a','l','n'), F_GLOBAL},
|
||||
/* Positioning features, though we don't care about the types. */
|
||||
/*
|
||||
* Positioning features.
|
||||
* We don't care about the types.
|
||||
*/
|
||||
{HB_TAG('d','i','s','t'), F_GLOBAL},
|
||||
{HB_TAG('a','b','v','m'), F_GLOBAL},
|
||||
{HB_TAG('b','l','w','m'), F_GLOBAL},
|
||||
@ -158,12 +162,14 @@ enum {
|
||||
_BLWS,
|
||||
_PSTS,
|
||||
_HALN,
|
||||
|
||||
_DIST,
|
||||
_ABVM,
|
||||
_BLWM,
|
||||
|
||||
INDIC_NUM_FEATURES,
|
||||
INDIC_BASIC_FEATURES = INIT /* Don't forget to update this! */
|
||||
INDIC_BASIC_FEATURES = INIT, /* Don't forget to update this! */
|
||||
INDIC_SUBST_FEATURES = _DIST /* Don't forget to update this! */
|
||||
};
|
||||
|
||||
static void
|
||||
@ -199,14 +205,19 @@ collect_features_indic (hb_ot_shape_planner_t *plan)
|
||||
|
||||
unsigned int i = 0;
|
||||
map->add_gsub_pause (initial_reordering);
|
||||
|
||||
for (; i < INDIC_BASIC_FEATURES; i++) {
|
||||
map->add_feature (indic_features[i].tag, 1, indic_features[i].flags | F_MANUAL_ZWJ | F_MANUAL_ZWNJ);
|
||||
map->add_gsub_pause (nullptr);
|
||||
}
|
||||
|
||||
map->add_gsub_pause (final_reordering);
|
||||
for (; i < INDIC_NUM_FEATURES; i++) {
|
||||
|
||||
for (; i < INDIC_SUBST_FEATURES; i++)
|
||||
map->add_feature (indic_features[i].tag, 1, indic_features[i].flags | F_MANUAL_ZWJ | F_MANUAL_ZWNJ);
|
||||
}
|
||||
|
||||
for (; i < INDIC_NUM_FEATURES; i++)
|
||||
map->add_feature (indic_features[i].tag, 1, indic_features[i].flags);
|
||||
|
||||
map->add_global_bool_feature (HB_TAG('c','a','l','t'));
|
||||
map->add_global_bool_feature (HB_TAG('c','l','i','g'));
|
||||
|
@ -32,7 +32,8 @@
|
||||
* Khmer shaper.
|
||||
*/
|
||||
|
||||
struct feature_list_t {
|
||||
struct feature_list_t
|
||||
{
|
||||
hb_tag_t tag;
|
||||
hb_ot_map_feature_flags_t flags;
|
||||
};
|
||||
@ -57,7 +58,10 @@ khmer_features[] =
|
||||
{HB_TAG('a','b','v','s'), F_GLOBAL},
|
||||
{HB_TAG('b','l','w','s'), F_GLOBAL},
|
||||
{HB_TAG('p','s','t','s'), F_GLOBAL},
|
||||
/* Positioning features, though we don't care about the types. */
|
||||
/*
|
||||
* Positioning features.
|
||||
* We don't care about the types.
|
||||
*/
|
||||
{HB_TAG('d','i','s','t'), F_GLOBAL},
|
||||
{HB_TAG('a','b','v','m'), F_GLOBAL},
|
||||
{HB_TAG('b','l','w','m'), F_GLOBAL},
|
||||
@ -77,12 +81,14 @@ enum {
|
||||
_ABVS,
|
||||
_BLWS,
|
||||
_PSTS,
|
||||
|
||||
_DIST,
|
||||
_ABVM,
|
||||
_BLWM,
|
||||
|
||||
KHMER_NUM_FEATURES,
|
||||
KHMER_BASIC_FEATURES = _PRES /* Don't forget to update this! */
|
||||
KHMER_BASIC_FEATURES = _PRES, /* Don't forget to update this! */
|
||||
KHMER_SUBST_FEATURES = _DIST, /* Don't forget to update this! */
|
||||
};
|
||||
|
||||
static void
|
||||
@ -121,15 +127,16 @@ collect_features_khmer (hb_ot_shape_planner_t *plan)
|
||||
map->add_global_bool_feature (HB_TAG('c','c','m','p'));
|
||||
|
||||
unsigned int i = 0;
|
||||
for (; i < KHMER_BASIC_FEATURES; i++) {
|
||||
for (; i < KHMER_BASIC_FEATURES; i++)
|
||||
map->add_feature (khmer_features[i].tag, 1, khmer_features[i].flags | F_MANUAL_ZWJ | F_MANUAL_ZWNJ);
|
||||
}
|
||||
|
||||
map->add_gsub_pause (clear_syllables);
|
||||
|
||||
for (; i < KHMER_NUM_FEATURES; i++) {
|
||||
for (; i < KHMER_SUBST_FEATURES; i++)
|
||||
map->add_feature (khmer_features[i].tag, 1, khmer_features[i].flags | F_MANUAL_ZWJ | F_MANUAL_ZWNJ);
|
||||
}
|
||||
|
||||
for (; i < KHMER_NUM_FEATURES; i++)
|
||||
map->add_feature (khmer_features[i].tag, 1, khmer_features[i].flags);
|
||||
|
||||
map->add_global_bool_feature (HB_TAG('c','a','l','t'));
|
||||
map->add_global_bool_feature (HB_TAG('c','l','i','g'));
|
||||
|
@ -54,7 +54,14 @@ other_features[] =
|
||||
HB_TAG('a','b','v','s'),
|
||||
HB_TAG('b','l','w','s'),
|
||||
HB_TAG('p','s','t','s'),
|
||||
/* Positioning features, though we don't care about the types. */
|
||||
};
|
||||
static const hb_tag_t
|
||||
positioning_features[] =
|
||||
{
|
||||
/*
|
||||
* Positioning features.
|
||||
* We don't care about the types.
|
||||
*/
|
||||
HB_TAG('d','i','s','t'),
|
||||
/* Pre-release version of Windows 8 Myanmar font had abvm,blwm
|
||||
* features. The released Windows 8 version of the font (as well
|
||||
@ -96,14 +103,20 @@ collect_features_myanmar (hb_ot_shape_planner_t *plan)
|
||||
|
||||
|
||||
map->add_gsub_pause (initial_reordering);
|
||||
|
||||
for (unsigned int i = 0; i < ARRAY_LENGTH (basic_features); i++)
|
||||
{
|
||||
map->add_feature (basic_features[i], 1, F_GLOBAL | F_MANUAL_ZWJ);
|
||||
map->add_gsub_pause (nullptr);
|
||||
}
|
||||
|
||||
map->add_gsub_pause (final_reordering);
|
||||
|
||||
for (unsigned int i = 0; i < ARRAY_LENGTH (other_features); i++)
|
||||
map->add_feature (other_features[i], 1, F_GLOBAL | F_MANUAL_ZWJ);
|
||||
|
||||
for (unsigned int i = 0; i < ARRAY_LENGTH (positioning_features); i++)
|
||||
map->add_feature (positioning_features[i], 1, F_GLOBAL);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -86,7 +86,14 @@ other_features[] =
|
||||
HB_TAG('h','a','l','n'),
|
||||
HB_TAG('p','r','e','s'),
|
||||
HB_TAG('p','s','t','s'),
|
||||
/* Positioning features, though we don't care about the types. */
|
||||
};
|
||||
static const hb_tag_t
|
||||
positioning_features[] =
|
||||
{
|
||||
/*
|
||||
* Positioning features.
|
||||
* We don't care about the types.
|
||||
*/
|
||||
HB_TAG('d','i','s','t'),
|
||||
HB_TAG('a','b','v','m'),
|
||||
HB_TAG('b','l','w','m'),
|
||||
@ -146,9 +153,13 @@ collect_features_use (hb_ot_shape_planner_t *plan)
|
||||
map->add_feature (arabic_features[i], 1, F_NONE);
|
||||
map->add_gsub_pause (nullptr);
|
||||
|
||||
/* "Standard typographic presentation" and "Positional feature application" */
|
||||
/* "Standard typographic presentation" */
|
||||
for (unsigned int i = 0; i < ARRAY_LENGTH (other_features); i++)
|
||||
map->add_feature (other_features[i], 1, F_GLOBAL | F_MANUAL_ZWJ);
|
||||
|
||||
/* "Positional feature application" */
|
||||
for (unsigned int i = 0; i < ARRAY_LENGTH (positioning_features); i++)
|
||||
map->add_feature (positioning_features[i], 1, F_GLOBAL);
|
||||
}
|
||||
|
||||
struct use_shape_plan_t
|
||||
|
@ -294,6 +294,16 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan,
|
||||
_hb_buffer_assert_unicode_vars (buffer);
|
||||
|
||||
hb_ot_shape_normalization_mode_t mode = plan->shaper->normalization_preference;
|
||||
if (mode == HB_OT_SHAPE_NORMALIZATION_MODE_AUTO)
|
||||
{
|
||||
if (plan->has_mark)
|
||||
// https://github.com/harfbuzz/harfbuzz/issues/653#issuecomment-423905920
|
||||
//mode = HB_OT_SHAPE_NORMALIZATION_MODE_DECOMPOSED;
|
||||
mode = HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS;
|
||||
else
|
||||
mode = HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS;
|
||||
}
|
||||
|
||||
const hb_ot_shape_normalize_context_t c = {
|
||||
plan,
|
||||
buffer,
|
||||
@ -358,65 +368,6 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan,
|
||||
|
||||
i = end;
|
||||
}
|
||||
|
||||
|
||||
if (mode == HB_OT_SHAPE_NORMALIZATION_MODE_NONE ||
|
||||
mode == HB_OT_SHAPE_NORMALIZATION_MODE_DECOMPOSED)
|
||||
return;
|
||||
|
||||
/* Third round, recompose */
|
||||
|
||||
/* As noted in the comment earlier, we don't try to combine
|
||||
* ccc=0 chars with their previous Starter. */
|
||||
|
||||
buffer->clear_output ();
|
||||
count = buffer->len;
|
||||
unsigned int starter = 0;
|
||||
buffer->next_glyph ();
|
||||
while (buffer->idx < count && buffer->successful)
|
||||
{
|
||||
hb_codepoint_t composed, glyph;
|
||||
if (/* We don't try to compose a non-mark character with it's preceding starter.
|
||||
* This is both an optimization to avoid trying to compose every two neighboring
|
||||
* glyphs in most scripts AND a desired feature for Hangul. Apparently Hangul
|
||||
* fonts are not designed to mix-and-match pre-composed syllables and Jamo. */
|
||||
HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer->cur())))
|
||||
{
|
||||
if (/* If there's anything between the starter and this char, they should have CCC
|
||||
* smaller than this character's. */
|
||||
(starter == buffer->out_len - 1 ||
|
||||
info_cc (buffer->prev()) < info_cc (buffer->cur())) &&
|
||||
/* And compose. */
|
||||
c.compose (&c,
|
||||
buffer->out_info[starter].codepoint,
|
||||
buffer->cur().codepoint,
|
||||
&composed) &&
|
||||
/* And the font has glyph for the composite. */
|
||||
font->get_nominal_glyph (composed, &glyph))
|
||||
{
|
||||
/* Composes. */
|
||||
buffer->next_glyph (); /* Copy to out-buffer. */
|
||||
if (unlikely (!buffer->successful))
|
||||
return;
|
||||
buffer->merge_out_clusters (starter, buffer->out_len);
|
||||
buffer->out_len--; /* Remove the second composable. */
|
||||
/* Modify starter and carry on. */
|
||||
buffer->out_info[starter].codepoint = composed;
|
||||
buffer->out_info[starter].glyph_index() = glyph;
|
||||
_hb_glyph_info_set_unicode_props (&buffer->out_info[starter], buffer);
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* Blocked, or doesn't compose. */
|
||||
buffer->next_glyph ();
|
||||
|
||||
if (info_cc (buffer->prev()) == 0)
|
||||
starter = buffer->out_len - 1;
|
||||
}
|
||||
buffer->swap_buffers ();
|
||||
|
||||
if (buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_CGJ)
|
||||
{
|
||||
/* For all CGJ, check if it prevented any reordering at all.
|
||||
@ -430,4 +381,62 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan,
|
||||
_hb_glyph_info_unhide (&buffer->info[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Third round, recompose */
|
||||
|
||||
if (mode == HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS ||
|
||||
mode == HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT)
|
||||
{
|
||||
/* As noted in the comment earlier, we don't try to combine
|
||||
* ccc=0 chars with their previous Starter. */
|
||||
|
||||
buffer->clear_output ();
|
||||
count = buffer->len;
|
||||
unsigned int starter = 0;
|
||||
buffer->next_glyph ();
|
||||
while (buffer->idx < count && buffer->successful)
|
||||
{
|
||||
hb_codepoint_t composed, glyph;
|
||||
if (/* We don't try to compose a non-mark character with it's preceding starter.
|
||||
* This is both an optimization to avoid trying to compose every two neighboring
|
||||
* glyphs in most scripts AND a desired feature for Hangul. Apparently Hangul
|
||||
* fonts are not designed to mix-and-match pre-composed syllables and Jamo. */
|
||||
HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer->cur())))
|
||||
{
|
||||
if (/* If there's anything between the starter and this char, they should have CCC
|
||||
* smaller than this character's. */
|
||||
(starter == buffer->out_len - 1 ||
|
||||
info_cc (buffer->prev()) < info_cc (buffer->cur())) &&
|
||||
/* And compose. */
|
||||
c.compose (&c,
|
||||
buffer->out_info[starter].codepoint,
|
||||
buffer->cur().codepoint,
|
||||
&composed) &&
|
||||
/* And the font has glyph for the composite. */
|
||||
font->get_nominal_glyph (composed, &glyph))
|
||||
{
|
||||
/* Composes. */
|
||||
buffer->next_glyph (); /* Copy to out-buffer. */
|
||||
if (unlikely (!buffer->successful))
|
||||
return;
|
||||
buffer->merge_out_clusters (starter, buffer->out_len);
|
||||
buffer->out_len--; /* Remove the second composable. */
|
||||
/* Modify starter and carry on. */
|
||||
buffer->out_info[starter].codepoint = composed;
|
||||
buffer->out_info[starter].glyph_index() = glyph;
|
||||
_hb_glyph_info_set_unicode_props (&buffer->out_info[starter], buffer);
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* Blocked, or doesn't compose. */
|
||||
buffer->next_glyph ();
|
||||
|
||||
if (info_cc (buffer->prev()) == 0)
|
||||
starter = buffer->out_len - 1;
|
||||
}
|
||||
buffer->swap_buffers ();
|
||||
}
|
||||
}
|
||||
|
@ -38,10 +38,11 @@ struct hb_ot_shape_plan_t;
|
||||
enum hb_ot_shape_normalization_mode_t {
|
||||
HB_OT_SHAPE_NORMALIZATION_MODE_NONE,
|
||||
HB_OT_SHAPE_NORMALIZATION_MODE_DECOMPOSED,
|
||||
HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS, /* never composes base-to-base */
|
||||
HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT, /* always fully decomposes and then recompose back */
|
||||
HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS, /* Never composes base-to-base */
|
||||
HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT, /* Always fully decomposes and then recompose back */
|
||||
|
||||
HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT = HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS
|
||||
HB_OT_SHAPE_NORMALIZATION_MODE_AUTO, /* Choose decomposed if GPOS mark feature available, compose otherwise. */
|
||||
HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT = HB_OT_SHAPE_NORMALIZATION_MODE_AUTO
|
||||
};
|
||||
|
||||
HB_INTERNAL void _hb_ot_shape_normalize (const hb_ot_shape_plan_t *shaper,
|
||||
|
@ -237,7 +237,9 @@ struct _hb_alignof
|
||||
# undef _WIN32_WINNT
|
||||
# endif
|
||||
# ifndef _WIN32_WINNT
|
||||
# define _WIN32_WINNT 0x0600
|
||||
# if !defined(WINAPI_FAMILY) || !(WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP)
|
||||
# define _WIN32_WINNT 0x0600
|
||||
# endif
|
||||
# endif
|
||||
# ifndef WIN32_LEAN_AND_MEAN
|
||||
# define WIN32_LEAN_AND_MEAN 1
|
||||
|
@ -51,12 +51,18 @@ static inline hb_face_t *
|
||||
hb_subset_test_open_font (const char *font_path)
|
||||
{
|
||||
#if GLIB_CHECK_VERSION(2,37,2)
|
||||
char* path = g_test_build_filename(G_TEST_DIST, font_path, NULL);
|
||||
char* path = g_test_build_filename (G_TEST_DIST, font_path, NULL);
|
||||
#else
|
||||
char* path = g_strdup(font_path);
|
||||
char* path = g_strdup (font_path);
|
||||
#endif
|
||||
|
||||
return hb_face_create (hb_blob_create_from_file (path), 0);
|
||||
hb_blob_t* blob = hb_blob_create_from_file (path);
|
||||
hb_face_t* face = hb_face_create (blob, 0);
|
||||
hb_blob_destroy (blob);
|
||||
|
||||
g_free (path);
|
||||
|
||||
return face;
|
||||
}
|
||||
|
||||
static inline hb_subset_input_t *
|
||||
|
@ -361,6 +361,7 @@ test_fontfuncs_subclassing (void)
|
||||
|
||||
|
||||
hb_font_destroy (font3);
|
||||
hb_font_destroy (font2);
|
||||
}
|
||||
|
||||
|
||||
|
@ -100,10 +100,14 @@ test_has_data (void)
|
||||
hb_face = hb_face_get_empty ();
|
||||
hb_font = hb_font_create (hb_face);
|
||||
g_assert(!hb_ot_math_has_data (hb_face)); // MATH table not available
|
||||
hb_font_destroy (hb_font);
|
||||
hb_face_destroy (hb_face);
|
||||
|
||||
hb_font = hb_font_get_empty ();
|
||||
hb_face = hb_font_get_face (hb_font);
|
||||
g_assert(!hb_ot_math_has_data (hb_face)); // MATH table not available
|
||||
hb_font_destroy (hb_font);
|
||||
hb_face_destroy (hb_face);
|
||||
|
||||
cleanupFreeType();
|
||||
}
|
||||
|
@ -262,6 +262,7 @@ test_set_algebra (void)
|
||||
|
||||
hb_set_destroy (s);
|
||||
hb_set_destroy (o);
|
||||
hb_set_destroy (o2);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -9,7 +9,7 @@ def cmd(command):
|
||||
p = subprocess.Popen (
|
||||
command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
p.wait ()
|
||||
print (p.stderr.read (), end="") # file=sys.stderr
|
||||
print (p.stderr.read ().decode ("utf-8").strip ()) # file=sys.stderr
|
||||
return p.stdout.read ().decode ("utf-8").strip (), p.returncode
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user