Merge branch 'master' into cff-subset

This commit is contained in:
Michiharu Ariza 2018-09-24 10:09:25 -07:00
commit 0604bf2b38
24 changed files with 364 additions and 122 deletions

View File

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

View File

@ -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/[.].*//'`

View File

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

View File

@ -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:

View File

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

View File

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

View File

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

View File

@ -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 :

View File

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

View File

@ -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.

View File

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

View File

@ -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,

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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,

View File

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

View File

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

View File

@ -361,6 +361,7 @@ test_fontfuncs_subclassing (void)
hb_font_destroy (font3);
hb_font_destroy (font2);
}

View File

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

View File

@ -262,6 +262,7 @@ test_set_algebra (void)
hb_set_destroy (s);
hb_set_destroy (o);
hb_set_destroy (o2);
}
static void

View File

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