harfbuzz: update harfbuzz to 1.5.1

This commit is contained in:
Roy Tam 2019-02-22 21:58:17 +08:00
commit 26d0be66f3
85 changed files with 5230 additions and 906 deletions

View file

@ -11,6 +11,7 @@ EXTRA_DIST = \
harfbuzz.doap \
README.python \
BUILD.md \
CMakeLists.txt \
$(NULL)
MAINTAINERCLEANFILES = \

1694
gfx/harfbuzz/NEWS Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,9 +1,9 @@
gfx/harfbuzz status as of 2017-01-05:
gfx/harfbuzz status as of 2017-09-05:
This directory contains the harfbuzz source from the 'master' branch of
https://github.com/behdad/harfbuzz.
Current version: 1.4.1
Current version: 1.5.1
UPDATING:

7
gfx/harfbuzz/THANKS Normal file
View file

@ -0,0 +1,7 @@
Bradley Grainger
Khaled Hosny
Kenichi Ishibashi
Ryan Lortie
Jeff Muizelaar
suzuki toshiya
Philip Withnall

View file

@ -1,6 +1,6 @@
AC_PREREQ([2.64])
AC_INIT([HarfBuzz],
[1.4.1],
[1.5.1],
[https://github.com/behdad/harfbuzz/issues/new],
[harfbuzz],
[http://harfbuzz.org/])

View file

@ -25,11 +25,13 @@ HBLIBS =
HBNONPCLIBS =
HBDEPS =
HBSOURCES = $(HB_BASE_sources)
HBSOURCES += $(HB_BASE_RAGEL_GENERATED_sources)
HBHEADERS = $(HB_BASE_headers)
HBNODISTHEADERS = $(HB_NODIST_headers)
if HAVE_OT
HBSOURCES += $(HB_OT_sources)
HBSOURCES += $(HB_OT_RAGEL_GENERATED_sources)
HBHEADERS += $(HB_OT_headers)
endif
@ -218,7 +220,7 @@ harfbuzz.def: $(HBHEADERS) $(HBNODISTHEADERS)
(cat $^ || echo 'hb_ERROR ()' ) | \
$(EGREP) '^hb_.* \(' | \
sed -e 's/ (.*//' | \
LANG=C sort; \
LC_ALL=C sort; \
echo LIBRARY libharfbuzz-0.dll; \
) >"$@"
@ ! grep -q hb_ERROR "$@" \
@ -251,19 +253,13 @@ built-sources: $(BUILT_SOURCES)
.PHONY: unicode-tables arabic-table indic-table use-table built-sources
RAGEL_GENERATED = \
$(srcdir)/hb-buffer-deserialize-json.hh \
$(srcdir)/hb-buffer-deserialize-text.hh \
$(srcdir)/hb-ot-shape-complex-indic-machine.hh \
$(srcdir)/hb-ot-shape-complex-myanmar-machine.hh \
$(srcdir)/hb-ot-shape-complex-use-machine.hh \
$(patsubst %,$(srcdir)/%,$(HB_BASE_RAGEL_GENERATED_sources)) \
$(patsubst %,$(srcdir)/%,$(HB_OT_RAGEL_GENERATED_sources)) \
$(NULL)
BUILT_SOURCES += $(RAGEL_GENERATED)
EXTRA_DIST += \
hb-buffer-deserialize-json.rl \
hb-buffer-deserialize-text.rl \
hb-ot-shape-complex-indic-machine.rl \
hb-ot-shape-complex-myanmar-machine.rl \
hb-ot-shape-complex-use-machine.rl \
$(HB_BASE_RAGEL_sources) \
$(HB_OT_RAGEL_sources) \
$(NULL)
MAINTAINERCLEANFILES += $(RAGEL_GENERATED)
$(srcdir)/%.hh: $(srcdir)/%.rl
@ -299,6 +295,8 @@ test_buffer_serialize_SOURCES = test-buffer-serialize.cc
test_buffer_serialize_CPPFLAGS = $(HBCFLAGS)
test_buffer_serialize_LDADD = libharfbuzz.la $(HBLIBS)
check: harfbuzz.def # For check-defs.sh
dist_check_SCRIPTS = \
check-c-linkage-decls.sh \
check-defs.sh \

View file

@ -21,7 +21,7 @@ for def in $defs; do
lib=`echo "$def" | sed 's/[.]def$//;s@.*/@@'`
so=.libs/lib${lib}.so
EXPORTED_SYMBOLS="`nm "$so" | grep ' [BCDGINRSTVW] ' | grep -v ' _fini\>\| _init\>\| _fdata\>\| _ftext\>\| _fbss\>\| __bss_start\>\| __bss_start__\>\| __bss_end__\>\| _edata\>\| _end\>\| _bss_end__\>\| __end__\>\| __gcov_flush\>\| llvm_' | cut -d' ' -f3`"
EXPORTED_SYMBOLS="`nm "$so" | grep ' [BCDGINRSTVW] .' | grep -v ' _fini\>\| _init\>\| _fdata\>\| _ftext\>\| _fbss\>\| __bss_start\>\| __bss_start__\>\| __bss_end__\>\| _edata\>\| _end\>\| _bss_end__\>\| __end__\>\| __gcov_flush\>\| llvm_' | cut -d' ' -f3`"
if test -f "$so"; then

View file

@ -20,7 +20,7 @@ for suffix in so dylib; do
so=.libs/libharfbuzz.$suffix
if ! test -f "$so"; then continue; fi
EXPORTED_SYMBOLS="`nm "$so" | grep ' [BCDGINRSTVW] ' | grep -v ' _fini\>\| _init\>\| _fdata\>\| _ftext\>\| _fbss\>\| __bss_start\>\| __bss_start__\>\| __bss_end__\>\| _edata\>\| _end\>\| _bss_end__\>\| __end__\>\| __gcov_flush\>\| ___gcov_flush\>\| llvm_\| _llvm_' | cut -d' ' -f3`"
EXPORTED_SYMBOLS="`nm "$so" | grep ' [BCDGINRSTVW] .' | grep -v ' _fini\>\| _init\>\| _fdata\>\| _ftext\>\| _fbss\>\| __bss_start\>\| __bss_start__\>\| __bss_end__\>\| _edata\>\| _end\>\| _bss_end__\>\| __end__\>\| __gcov_flush\>\| ___gcov_flush\>\| llvm_\| _llvm_' | cut -d' ' -f3`"
prefix=`basename "$so" | sed 's/libharfbuzz/hb/; s/-/_/g; s/[.].*//'`

View file

@ -134,7 +134,7 @@ def print_joining_table(f):
for (start,end) in ranges:
if p not in [start>>page_bits, end>>page_bits]: continue
offset = "joining_offset_0x%04xu" % start
print " if (hb_in_range (u, 0x%04Xu, 0x%04Xu)) return joining_table[u - 0x%04Xu + %s];" % (start, end, start, offset)
print " if (hb_in_range<hb_codepoint_t> (u, 0x%04Xu, 0x%04Xu)) return joining_table[u - 0x%04Xu + %s];" % (start, end, start, offset)
print " break;"
print ""
print " default:"

View file

@ -232,7 +232,7 @@ for p in sorted(pages):
for (start,end) in zip (starts, ends):
if p not in [start>>page_bits, end>>page_bits]: continue
offset = "indic_offset_0x%04xu" % start
print " if (hb_in_range (u, 0x%04Xu, 0x%04Xu)) return indic_table[u - 0x%04Xu + %s];" % (start, end-1, start, offset)
print " if (hb_in_range<hb_codepoint_t> (u, 0x%04Xu, 0x%04Xu)) return indic_table[u - 0x%04Xu + %s];" % (start, end-1, start, offset)
for u,d in singles.items ():
if p != u>>page_bits: continue
print " if (unlikely (u == 0x%04Xu)) return _(%s,%s);" % (u, short[0][d[0]], short[1][d[1]])

View file

@ -210,11 +210,13 @@ def is_SYM_MOD(U, UISC, UGC):
def is_VARIATION_SELECTOR(U, UISC, UGC):
return 0xFE00 <= U <= 0xFE0F
def is_VOWEL(U, UISC, UGC):
# https://github.com/roozbehp/unicode-data/issues/6
return (UISC == Pure_Killer or
(UGC != Lo and UISC in [Vowel, Vowel_Dependent]))
(UGC != Lo and UISC in [Vowel, Vowel_Dependent] and U not in [0xAA29]))
def is_VOWEL_MOD(U, UISC, UGC):
# https://github.com/roozbehp/unicode-data/issues/6
return (UISC in [Tone_Mark, Cantillation_Mark, Register_Shifter, Visarga] or
(UGC != Lo and UISC == Bindu))
(UGC != Lo and (UISC == Bindu or U in [0xAA29])))
use_mapping = {
'B': is_BASE,
@ -449,7 +451,7 @@ for p in sorted(pages):
for (start,end) in zip (starts, ends):
if p not in [start>>page_bits, end>>page_bits]: continue
offset = "use_offset_0x%04xu" % start
print " if (hb_in_range (u, 0x%04Xu, 0x%04Xu)) return use_table[u - 0x%04Xu + %s];" % (start, end-1, start, offset)
print " if (hb_in_range<hb_codepoint_t> (u, 0x%04Xu, 0x%04Xu)) return use_table[u - 0x%04Xu + %s];" % (start, end-1, start, offset)
for u,d in singles.items ():
if p != u>>page_bits: continue
print " if (unlikely (u == 0x%04Xu)) return %s;" % (u, d[0])

View file

@ -5,7 +5,7 @@ includedir=/usr/local/include
Name: harfbuzz
Description: HarfBuzz text shaping library ICU integration
Version: 1.4.1
Version: 1.5.1
Requires: harfbuzz
Requires.private: icu-uc

View file

@ -5,7 +5,7 @@ includedir=/usr/local/include
Name: harfbuzz
Description: HarfBuzz text shaping library
Version: 1.4.1
Version: 1.5.1
Libs: -L${libdir} -lharfbuzz
Libs.private:

View file

@ -124,13 +124,13 @@ typedef unsigned int hb_atomic_int_impl_t;
#include <builtins.h>
static inline int hb_fetch_and_add(volatile int* AI, unsigned int V) {
static inline int _hb_fetch_and_add(volatile int* AI, unsigned int V) {
__lwsync();
int result = __fetch_and_add(AI, V);
__isync();
return result;
}
static inline int hb_compare_and_swaplp(volatile long* P, long O, long N) {
static inline int _hb_compare_and_swaplp(volatile long* P, long O, long N) {
__sync();
int result = __compare_and_swaplp (P, &O, N);
__sync();
@ -139,10 +139,10 @@ static inline int hb_compare_and_swaplp(volatile long* P, long O, long N) {
typedef int hb_atomic_int_impl_t;
#define HB_ATOMIC_INT_IMPL_INIT(V) (V)
#define hb_atomic_int_impl_add(AI, V) hb_fetch_and_add (&(AI), (V))
#define hb_atomic_int_impl_add(AI, V) _hb_fetch_and_add (&(AI), (V))
#define hb_atomic_ptr_impl_get(P) (__sync(), (void *) *(P))
#define hb_atomic_ptr_impl_cmpexch(P,O,N) hb_compare_and_swaplp ((long*)(P), (long)(O), (long)(N))
#define hb_atomic_ptr_impl_cmpexch(P,O,N) _hb_compare_and_swaplp ((long*)(P), (long)(O), (long)(N))
#elif !defined(HB_NO_MT)

View file

@ -327,6 +327,7 @@ hb_blob_is_immutable (hb_blob_t *blob)
unsigned int
hb_blob_get_length (hb_blob_t *blob)
{
if(unlikely(!blob)) return 0; // wallpaper TenFourFox issue 309
return blob->length;
}

View file

@ -50,6 +50,7 @@ ASSERT_STATIC (sizeof (hb_glyph_info_t) == sizeof (hb_glyph_position_t));
HB_MARK_AS_FLAG_T (hb_buffer_flags_t);
HB_MARK_AS_FLAG_T (hb_buffer_serialize_flags_t);
HB_MARK_AS_FLAG_T (hb_buffer_diff_flags_t);
enum hb_buffer_scratch_flags_t {
HB_BUFFER_SCRATCH_FLAG_DEFAULT = 0x00000000u,
@ -57,6 +58,8 @@ enum hb_buffer_scratch_flags_t {
HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES = 0x00000002u,
HB_BUFFER_SCRATCH_FLAG_HAS_SPACE_FALLBACK = 0x00000004u,
HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT = 0x00000008u,
HB_BUFFER_SCRATCH_FLAG_HAS_UNSAFE_TO_BREAK = 0x00000010u,
/* Reserved for complex shapers' internal use. */
HB_BUFFER_SCRATCH_FLAG_COMPLEX0 = 0x01000000u,
HB_BUFFER_SCRATCH_FLAG_COMPLEX1 = 0x02000000u,
@ -232,25 +235,31 @@ struct hb_buffer_t {
for (unsigned int j = 0; j < len; j++)
info[j].mask |= mask;
}
HB_INTERNAL void set_masks (hb_mask_t value,
hb_mask_t mask,
unsigned int cluster_start,
unsigned int cluster_end);
HB_INTERNAL void set_masks (hb_mask_t value, hb_mask_t mask,
unsigned int cluster_start, unsigned int cluster_end);
HB_INTERNAL void merge_clusters (unsigned int start,
unsigned int end)
inline void merge_clusters (unsigned int start, unsigned int end)
{
if (end - start < 2)
return;
merge_clusters_impl (start, end);
}
HB_INTERNAL void merge_clusters_impl (unsigned int start,
unsigned int end);
HB_INTERNAL void merge_out_clusters (unsigned int start,
unsigned int end);
HB_INTERNAL void merge_clusters_impl (unsigned int start, unsigned int end);
HB_INTERNAL void merge_out_clusters (unsigned int start, unsigned int end);
/* Merge clusters for deleting current glyph, and skip it. */
HB_INTERNAL void delete_glyph (void);
inline void unsafe_to_break (unsigned int start,
unsigned int end)
{
if (end - start < 2)
return;
unsafe_to_break_impl (start, end);
}
HB_INTERNAL void unsafe_to_break_impl (unsigned int start, unsigned int end);
HB_INTERNAL void unsafe_to_break_from_outbuffer (unsigned int start, unsigned int end);
/* Internal methods */
HB_INTERNAL bool enlarge (unsigned int size);
@ -282,9 +291,66 @@ struct hb_buffer_t {
return ret;
}
HB_INTERNAL bool message_impl (hb_font_t *font, const char *fmt, va_list ap) HB_PRINTF_FUNC(3, 0);
static inline void
set_cluster (hb_glyph_info_t &info, unsigned int cluster, unsigned int mask = 0)
{
if (info.cluster != cluster)
{
if (mask & HB_GLYPH_FLAG_UNSAFE_TO_BREAK)
info.mask |= HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
else
info.mask &= ~HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
}
info.cluster = cluster;
}
int
_unsafe_to_break_find_min_cluster (const hb_glyph_info_t *info,
unsigned int start, unsigned int end,
unsigned int cluster) const
{
for (unsigned int i = start; i < end; i++)
cluster = MIN (cluster, info[i].cluster);
return cluster;
}
void
_unsafe_to_break_set_mask (hb_glyph_info_t *info,
unsigned int start, unsigned int end,
unsigned int cluster)
{
for (unsigned int i = start; i < end; i++)
if (cluster != info[i].cluster)
{
scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_UNSAFE_TO_BREAK;
info[i].mask |= HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
}
}
};
/* Loop over clusters. Duplicated in foreach_syllable(). */
#define foreach_cluster(buffer, start, end) \
for (unsigned int \
_count = buffer->len, \
start = 0, end = _count ? _next_cluster (buffer, 0) : 0; \
start < _count; \
start = end, end = _next_cluster (buffer, start))
static inline unsigned int
_next_cluster (hb_buffer_t *buffer, unsigned int start)
{
hb_glyph_info_t *info = buffer->info;
unsigned int count = buffer->len;
unsigned int cluster = info[start].cluster;
while (++start < count && cluster == info[start].cluster)
;
return start;
}
#define HB_BUFFER_XALLOCATE_VAR(b, func, var) \
b->func (offsetof (hb_glyph_info_t, var) - offsetof(hb_glyph_info_t, var1), \
sizeof (b->info[0].var))

View file

@ -145,10 +145,16 @@ _hb_buffer_serialize_glyphs_json (hb_buffer_t *buffer,
if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS))
{
p += snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"dx\":%d,\"dy\":%d",
pos[i].x_offset, pos[i].y_offset);
p += snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"ax\":%d,\"ay\":%d",
pos[i].x_advance, pos[i].y_advance);
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"dx\":%d,\"dy\":%d",
pos[i].x_offset, pos[i].y_offset));
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"ax\":%d,\"ay\":%d",
pos[i].x_advance, pos[i].y_advance));
}
if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS)
{
if (info[i].mask & HB_GLYPH_FLAG_DEFINED)
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"fl\":%u", info[i].mask & HB_GLYPH_FLAG_DEFINED));
}
if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS)
@ -156,9 +162,9 @@ _hb_buffer_serialize_glyphs_json (hb_buffer_t *buffer,
hb_glyph_extents_t extents;
hb_font_get_glyph_extents(font, info[i].codepoint, &extents);
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"xb\":%d,\"yb\":%d",
extents.x_bearing, extents.y_bearing));
extents.x_bearing, extents.y_bearing));
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"w\":%d,\"h\":%d",
extents.width, extents.height));
extents.width, extents.height));
}
*p++ = '}';
@ -226,6 +232,12 @@ _hb_buffer_serialize_glyphs_text (hb_buffer_t *buffer,
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",%d", pos[i].y_advance));
}
if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS)
{
if (info[i].mask &HB_GLYPH_FLAG_DEFINED)
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "#%X", info[i].mask &HB_GLYPH_FLAG_DEFINED));
}
if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS)
{
hb_glyph_extents_t extents;
@ -311,6 +323,8 @@ hb_buffer_serialize_glyphs (hb_buffer_t *buffer,
if (!buf_consumed)
buf_consumed = &sconsumed;
*buf_consumed = 0;
if (buf_size)
*buf = '\0';
assert ((!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID) ||
buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS);

View file

@ -31,10 +31,6 @@
#include "hb-utf-private.hh"
#ifndef HB_DEBUG_BUFFER
#define HB_DEBUG_BUFFER (HB_DEBUG+0)
#endif
/**
* SECTION: hb-buffer
* @title: Buffers
@ -267,7 +263,7 @@ hb_buffer_t::add (hb_codepoint_t codepoint,
memset (glyph, 0, sizeof (*glyph));
glyph->codepoint = codepoint;
glyph->mask = 1;
glyph->mask = 0;
glyph->cluster = cluster;
len++;
@ -550,7 +546,10 @@ hb_buffer_t::merge_clusters_impl (unsigned int start,
unsigned int end)
{
if (cluster_level == HB_BUFFER_CLUSTER_LEVEL_CHARACTERS)
{
unsafe_to_break (start, end);
return;
}
unsigned int cluster = info[start].cluster;
@ -568,10 +567,10 @@ hb_buffer_t::merge_clusters_impl (unsigned int start,
/* If we hit the start of buffer, continue in out-buffer. */
if (idx == start)
for (unsigned int i = out_len; i && out_info[i - 1].cluster == info[start].cluster; i--)
out_info[i - 1].cluster = cluster;
set_cluster (out_info[i - 1], cluster);
for (unsigned int i = start; i < end; i++)
info[i].cluster = cluster;
set_cluster (info[i], cluster);
}
void
hb_buffer_t::merge_out_clusters (unsigned int start,
@ -599,14 +598,16 @@ hb_buffer_t::merge_out_clusters (unsigned int start,
/* If we hit the end of out-buffer, continue in buffer. */
if (end == out_len)
for (unsigned int i = idx; i < len && info[i].cluster == out_info[end - 1].cluster; i++)
info[i].cluster = cluster;
set_cluster (info[i], cluster);
for (unsigned int i = start; i < end; i++)
out_info[i].cluster = cluster;
set_cluster (out_info[i], cluster);
}
void
hb_buffer_t::delete_glyph ()
{
/* The logic here is duplicated in hb_ot_hide_default_ignorables(). */
unsigned int cluster = info[idx].cluster;
if (idx + 1 < len && cluster == info[idx + 1].cluster)
{
@ -619,9 +620,10 @@ hb_buffer_t::delete_glyph ()
/* Merge cluster backward. */
if (cluster < out_info[out_len - 1].cluster)
{
unsigned int mask = info[idx].mask;
unsigned int old_cluster = out_info[out_len - 1].cluster;
for (unsigned i = out_len; i && out_info[i - 1].cluster == old_cluster; i--)
out_info[i - 1].cluster = cluster;
set_cluster (out_info[i - 1], cluster, mask);
}
goto done;
}
@ -637,6 +639,32 @@ done:
skip_glyph ();
}
void
hb_buffer_t::unsafe_to_break_impl (unsigned int start, unsigned int end)
{
unsigned int cluster = (unsigned int) -1;
cluster = _unsafe_to_break_find_min_cluster (info, start, end, cluster);
_unsafe_to_break_set_mask (info, start, end, cluster);
}
void
hb_buffer_t::unsafe_to_break_from_outbuffer (unsigned int start, unsigned int end)
{
if (!have_output)
{
unsafe_to_break_impl (start, end);
return;
}
assert (start <= out_len);
assert (idx <= end);
unsigned int cluster = (unsigned int) -1;
cluster = _unsafe_to_break_find_min_cluster (out_info, start, out_len, cluster);
cluster = _unsafe_to_break_find_min_cluster (info, idx, end, cluster);
_unsafe_to_break_set_mask (out_info, start, out_len, cluster);
_unsafe_to_break_set_mask (info, idx, end, cluster);
}
void
hb_buffer_t::guess_segment_properties (void)
{
@ -1379,6 +1407,23 @@ hb_buffer_get_glyph_positions (hb_buffer_t *buffer,
return (hb_glyph_position_t *) buffer->pos;
}
/**
* hb_glyph_info_get_glyph_flags:
* @info: a #hb_glyph_info_t.
*
* Returns glyph flags encoded within a #hb_glyph_info_t.
*
* Return value:
* The #hb_glyph_flags_t encoded within @info.
*
* Since: 1.5.0
**/
hb_glyph_flags_t
(hb_glyph_info_get_glyph_flags) (const hb_glyph_info_t *info)
{
return hb_glyph_info_get_glyph_flags (info);
}
/**
* hb_buffer_reverse:
* @buffer: an #hb_buffer_t.
@ -1666,6 +1711,58 @@ hb_buffer_add_codepoints (hb_buffer_t *buffer,
}
/**
* hb_buffer_append:
* @buffer: an #hb_buffer_t.
* @source: source #hb_buffer_t.
* @start: start index into source buffer to copy. Use 0 to copy from start of buffer.
* @end: end index into source buffer to copy. Use (unsigned int) -1 to copy to end of buffer.
*
* Append (part of) contents of another buffer to this buffer.
*
* Since: 1.5.0
**/
HB_EXTERN void
hb_buffer_append (hb_buffer_t *buffer,
hb_buffer_t *source,
unsigned int start,
unsigned int end)
{
assert (!buffer->have_output && !source->have_output);
assert (buffer->have_positions == source->have_positions ||
!buffer->len || !source->len);
assert (buffer->content_type == source->content_type ||
!buffer->len || !source->len);
if (end > source->len)
end = source->len;
if (start > end)
start = end;
if (start == end)
return;
if (!buffer->len)
buffer->content_type = source->content_type;
if (!buffer->have_positions && source->have_positions)
buffer->clear_positions ();
if (buffer->len + (end - start) < buffer->len) /* Overflows. */
{
buffer->in_error = true;
return;
}
unsigned int orig_len = buffer->len;
hb_buffer_set_length (buffer, buffer->len + (end - start));
if (buffer->in_error)
return;
memcpy (buffer->info + orig_len, source->info + start, (end - start) * sizeof (buffer->info[0]));
if (buffer->have_positions)
memcpy (buffer->pos + orig_len, source->pos + start, (end - start) * sizeof (buffer->pos[0]));
}
static int
compare_info_codepoint (const hb_glyph_info_t *pa,
const hb_glyph_info_t *pb)
@ -1736,7 +1833,8 @@ void
hb_buffer_normalize_glyphs (hb_buffer_t *buffer)
{
assert (buffer->have_positions);
assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS);
assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS ||
(!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID));
bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
@ -1775,6 +1873,98 @@ hb_buffer_t::sort (unsigned int start, unsigned int end, int(*compar)(const hb_g
}
}
/*
* Comparing buffers.
*/
/**
* hb_buffer_diff:
*
* 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
* callers if just comparing two buffers is needed.
*
* Since: 1.5.0
**/
hb_buffer_diff_flags_t
hb_buffer_diff (hb_buffer_t *buffer,
hb_buffer_t *reference,
hb_codepoint_t dottedcircle_glyph,
unsigned int position_fuzz)
{
if (buffer->content_type != reference->content_type && buffer->len && reference->len)
return HB_BUFFER_DIFF_FLAG_CONTENT_TYPE_MISMATCH;
hb_buffer_diff_flags_t result = HB_BUFFER_DIFF_FLAG_EQUAL;
bool contains = dottedcircle_glyph != (hb_codepoint_t) -1;
unsigned int count = reference->len;
if (buffer->len != count)
{
/*
* we can't compare glyph-by-glyph, but we do want to know if there
* are .notdef or dottedcircle glyphs present in the reference buffer
*/
const hb_glyph_info_t *info = reference->info;
unsigned int i;
for (i = 0; i < count; i++)
{
if (contains && info[i].codepoint == dottedcircle_glyph)
result |= HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT;
if (contains && info[i].codepoint == 0)
result |= HB_BUFFER_DIFF_FLAG_NOTDEF_PRESENT;
}
result |= HB_BUFFER_DIFF_FLAG_LENGTH_MISMATCH;
return hb_buffer_diff_flags_t (result);
}
if (!count)
return hb_buffer_diff_flags_t (result);
const hb_glyph_info_t *buf_info = buffer->info;
const hb_glyph_info_t *ref_info = reference->info;
for (unsigned int i = 0; i < count; i++)
{
if (buf_info->codepoint != ref_info->codepoint)
result |= HB_BUFFER_DIFF_FLAG_CODEPOINT_MISMATCH;
if (buf_info->cluster != ref_info->cluster)
result |= HB_BUFFER_DIFF_FLAG_CLUSTER_MISMATCH;
if ((buf_info->mask & HB_GLYPH_FLAG_DEFINED) != (ref_info->mask & HB_GLYPH_FLAG_DEFINED))
result |= HB_BUFFER_DIFF_FLAG_GLYPH_FLAGS_MISMATCH;
if (contains && ref_info->codepoint == dottedcircle_glyph)
result |= HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT;
if (contains && ref_info->codepoint == 0)
result |= HB_BUFFER_DIFF_FLAG_NOTDEF_PRESENT;
buf_info++;
ref_info++;
}
if (buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS)
{
assert (buffer->have_positions);
const hb_glyph_position_t *buf_pos = buffer->pos;
const hb_glyph_position_t *ref_pos = reference->pos;
for (unsigned int i = 0; i < count; i++)
{
if ((unsigned int) abs (buf_pos->x_advance - ref_pos->x_advance) > position_fuzz ||
(unsigned int) abs (buf_pos->y_advance - ref_pos->y_advance) > position_fuzz ||
(unsigned int) abs (buf_pos->x_offset - ref_pos->x_offset) > position_fuzz ||
(unsigned int) abs (buf_pos->y_offset - ref_pos->y_offset) > position_fuzz)
{
result |= HB_BUFFER_DIFF_FLAG_POSITION_MISMATCH;
break;
}
buf_pos++;
ref_pos++;
}
}
return result;
}
/*
* Debugging.
*/

View file

@ -63,7 +63,7 @@ HB_BEGIN_DECLS
*/
typedef struct hb_glyph_info_t {
hb_codepoint_t codepoint;
hb_mask_t mask;
hb_mask_t mask; /* Holds hb_glyph_flags_t after hb_shape(), plus other things. */
uint32_t cluster;
/*< private >*/
@ -71,6 +71,19 @@ typedef struct hb_glyph_info_t {
hb_var_int_t var2;
} hb_glyph_info_t;
typedef enum { /*< flags >*/
HB_GLYPH_FLAG_UNSAFE_TO_BREAK = 0x00000001,
HB_GLYPH_FLAG_DEFINED = 0x00000001 /* OR of all defined flags */
} hb_glyph_flags_t;
HB_EXTERN hb_glyph_flags_t
hb_glyph_info_get_glyph_flags (const hb_glyph_info_t *info);
#define hb_glyph_info_get_glyph_flags(info) \
((hb_glyph_flags_t) ((unsigned int) (info)->mask & HB_GLYPH_FLAG_DEFINED))
/**
* hb_glyph_position_t:
* @x_advance: how much the line advances after drawing this glyph when setting
@ -163,6 +176,7 @@ HB_EXTERN void *
hb_buffer_get_user_data (hb_buffer_t *buffer,
hb_user_data_key_t *key);
/**
* hb_buffer_content_type_t:
* @HB_BUFFER_CONTENT_TYPE_INVALID: Initial value for new buffer.
@ -359,6 +373,11 @@ hb_buffer_add_codepoints (hb_buffer_t *buffer,
unsigned int item_offset,
int item_length);
HB_EXTERN void
hb_buffer_append (hb_buffer_t *buffer,
hb_buffer_t *source,
unsigned int start,
unsigned int end);
HB_EXTERN hb_bool_t
hb_buffer_set_length (hb_buffer_t *buffer,
@ -403,7 +422,8 @@ typedef enum { /*< flags >*/
HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS = 0x00000001u,
HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS = 0x00000002u,
HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES = 0x00000004u,
HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS = 0x00000008u
HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS = 0x00000008u,
HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS = 0x00000010u
} hb_buffer_serialize_flags_t;
/**
@ -452,6 +472,45 @@ hb_buffer_deserialize_glyphs (hb_buffer_t *buffer,
hb_buffer_serialize_format_t format);
/*
* Compare buffers
*/
typedef enum { /*< flags >*/
HB_BUFFER_DIFF_FLAG_EQUAL = 0x0000,
/* Buffers with different content_type cannot be meaningfully compared
* in any further detail. */
HB_BUFFER_DIFF_FLAG_CONTENT_TYPE_MISMATCH = 0x0001,
/* For buffers with differing length, the per-glyph comparison is not
* attempted, though we do still scan reference for dottedcircle / .notdef
* glyphs. */
HB_BUFFER_DIFF_FLAG_LENGTH_MISMATCH = 0x0002,
/* We want to know if dottedcircle / .notdef glyphs are present in the
* reference, as we may not care so much about other differences in this
* case. */
HB_BUFFER_DIFF_FLAG_NOTDEF_PRESENT = 0x0004,
HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT = 0x0008,
/* If the buffers have the same length, we compare them glyph-by-glyph
* and report which aspect(s) of the glyph info/position are different. */
HB_BUFFER_DIFF_FLAG_CODEPOINT_MISMATCH = 0x0010,
HB_BUFFER_DIFF_FLAG_CLUSTER_MISMATCH = 0x0020,
HB_BUFFER_DIFF_FLAG_GLYPH_FLAGS_MISMATCH = 0x0040,
HB_BUFFER_DIFF_FLAG_POSITION_MISMATCH = 0x0080
} hb_buffer_diff_flags_t;
/* Compare the contents of two buffers, report types of differences. */
hb_buffer_diff_flags_t
hb_buffer_diff (hb_buffer_t *buffer,
hb_buffer_t *reference,
hb_codepoint_t dottedcircle_glyph,
unsigned int position_fuzz);
/*
* Debugging.
*/

View file

@ -186,8 +186,10 @@ lang_equal (hb_language_t v1,
const unsigned char *p1 = (const unsigned char *) v1;
const unsigned char *p2 = (const unsigned char *) v2;
while (*p1 && *p1 == canon_map[*p2])
p1++, p2++;
while (*p1 && *p1 == canon_map[*p2]) {
p1++;
p2++;
}
return *p1 == canon_map[*p2];
}
@ -219,9 +221,18 @@ struct hb_language_item_t {
}
inline hb_language_item_t & operator = (const char *s) {
lang = (hb_language_t) strdup (s);
for (unsigned char *p = (unsigned char *) lang; *p; p++)
*p = canon_map[*p];
/* If a custom allocated is used calling strdup() pairs
badly with a call to the custom free() in finish() below.
Therefore don't call strdup(), implement its behavior.
*/
size_t len = strlen(s) + 1;
lang = (hb_language_t) malloc(len);
if (likely (lang))
{
memcpy((unsigned char *) lang, s, len);
for (unsigned char *p = (unsigned char *) lang; *p; p++)
*p = canon_map[*p];
}
return *this;
}
@ -263,6 +274,11 @@ retry:
return NULL;
lang->next = first_lang;
*lang = key;
if (unlikely (!lang->lang))
{
free (lang);
return NULL;
}
if (!hb_atomic_ptr_cmpexch (&langs, first_lang, lang)) {
lang->finish ();
@ -605,3 +621,371 @@ hb_version_atleast (unsigned int major,
{
return HB_VERSION_ATLEAST (major, minor, micro);
}
/* hb_feature_t and hb_variation_t */
static bool
parse_space (const char **pp, const char *end)
{
while (*pp < end && ISSPACE (**pp))
(*pp)++;
return true;
}
static bool
parse_char (const char **pp, const char *end, char c)
{
parse_space (pp, end);
if (*pp == end || **pp != c)
return false;
(*pp)++;
return true;
}
static bool
parse_uint (const char **pp, const char *end, unsigned int *pv)
{
char buf[32];
unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - *pp));
strncpy (buf, *pp, len);
buf[len] = '\0';
char *p = buf;
char *pend = p;
unsigned int v;
/* Intentionally use strtol instead of strtoul, such that
* -1 turns into "big number"... */
errno = 0;
v = strtol (p, &pend, 0);
if (errno || p == pend)
return false;
*pv = v;
*pp += pend - p;
return true;
}
static bool
parse_uint32 (const char **pp, const char *end, uint32_t *pv)
{
char buf[32];
unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - *pp));
strncpy (buf, *pp, len);
buf[len] = '\0';
char *p = buf;
char *pend = p;
unsigned int v;
/* Intentionally use strtol instead of strtoul, such that
* -1 turns into "big number"... */
errno = 0;
v = strtol (p, &pend, 0);
if (errno || p == pend)
return false;
*pv = v;
*pp += pend - p;
return true;
}
static bool
parse_float (const char **pp, const char *end, float *pv)
{
char buf[32];
unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - *pp));
strncpy (buf, *pp, len);
buf[len] = '\0';
char *p = buf;
char *pend = p;
float v;
errno = 0;
v = strtod (p, &pend);
if (errno || p == pend)
return false;
*pv = v;
*pp += pend - p;
return true;
}
static bool
parse_bool (const char **pp, const char *end, uint32_t *pv)
{
parse_space (pp, end);
const char *p = *pp;
while (*pp < end && ISALPHA(**pp))
(*pp)++;
/* CSS allows on/off as aliases 1/0. */
if (*pp - p == 2 || 0 == strncmp (p, "on", 2))
*pv = 1;
else if (*pp - p == 3 || 0 == strncmp (p, "off", 2))
*pv = 0;
else
return false;
return true;
}
/* hb_feature_t */
static bool
parse_feature_value_prefix (const char **pp, const char *end, hb_feature_t *feature)
{
if (parse_char (pp, end, '-'))
feature->value = 0;
else {
parse_char (pp, end, '+');
feature->value = 1;
}
return true;
}
static bool
parse_tag (const char **pp, const char *end, hb_tag_t *tag)
{
parse_space (pp, end);
char quote = 0;
if (*pp < end && (**pp == '\'' || **pp == '"'))
{
quote = **pp;
(*pp)++;
}
const char *p = *pp;
while (*pp < end && ISALNUM(**pp))
(*pp)++;
if (p == *pp || *pp - p > 4)
return false;
*tag = hb_tag_from_string (p, *pp - p);
if (quote)
{
/* CSS expects exactly four bytes. And we only allow quotations for
* CSS compatibility. So, enforce the length. */
if (*pp - p != 4)
return false;
if (*pp == end || **pp != quote)
return false;
(*pp)++;
}
return true;
}
static bool
parse_feature_indices (const char **pp, const char *end, hb_feature_t *feature)
{
parse_space (pp, end);
bool has_start;
feature->start = 0;
feature->end = (unsigned int) -1;
if (!parse_char (pp, end, '['))
return true;
has_start = parse_uint (pp, end, &feature->start);
if (parse_char (pp, end, ':')) {
parse_uint (pp, end, &feature->end);
} else {
if (has_start)
feature->end = feature->start + 1;
}
return parse_char (pp, end, ']');
}
static bool
parse_feature_value_postfix (const char **pp, const char *end, hb_feature_t *feature)
{
bool had_equal = parse_char (pp, end, '=');
bool had_value = parse_uint32 (pp, end, &feature->value) ||
parse_bool (pp, end, &feature->value);
/* CSS doesn't use equal-sign between tag and value.
* If there was an equal-sign, then there *must* be a value.
* A value without an eqaul-sign is ok, but not required. */
return !had_equal || had_value;
}
static bool
parse_one_feature (const char **pp, const char *end, hb_feature_t *feature)
{
return parse_feature_value_prefix (pp, end, feature) &&
parse_tag (pp, end, &feature->tag) &&
parse_feature_indices (pp, end, feature) &&
parse_feature_value_postfix (pp, end, feature) &&
parse_space (pp, end) &&
*pp == end;
}
/**
* hb_feature_from_string:
* @str: (array length=len) (element-type uint8_t): a string to parse
* @len: length of @str, or -1 if string is %NULL terminated
* @feature: (out): the #hb_feature_t to initialize with the parsed values
*
* Parses a string into a #hb_feature_t.
*
* TODO: document the syntax here.
*
* Return value:
* %true if @str is successfully parsed, %false otherwise.
*
* Since: 0.9.5
**/
hb_bool_t
hb_feature_from_string (const char *str, int len,
hb_feature_t *feature)
{
hb_feature_t feat;
if (len < 0)
len = strlen (str);
if (likely (parse_one_feature (&str, str + len, &feat)))
{
if (feature)
*feature = feat;
return true;
}
if (feature)
memset (feature, 0, sizeof (*feature));
return false;
}
/**
* hb_feature_to_string:
* @feature: an #hb_feature_t to convert
* @buf: (array length=size) (out): output string
* @size: the allocated size of @buf
*
* Converts a #hb_feature_t into a %NULL-terminated string in the format
* understood by hb_feature_from_string(). The client in responsible for
* allocating big enough size for @buf, 128 bytes is more than enough.
*
* Since: 0.9.5
**/
void
hb_feature_to_string (hb_feature_t *feature,
char *buf, unsigned int size)
{
if (unlikely (!size)) return;
char s[128];
unsigned int len = 0;
if (feature->value == 0)
s[len++] = '-';
hb_tag_to_string (feature->tag, s + len);
len += 4;
while (len && s[len - 1] == ' ')
len--;
if (feature->start != 0 || feature->end != (unsigned int) -1)
{
s[len++] = '[';
if (feature->start)
len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->start));
if (feature->end != feature->start + 1) {
s[len++] = ':';
if (feature->end != (unsigned int) -1)
len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->end));
}
s[len++] = ']';
}
if (feature->value > 1)
{
s[len++] = '=';
len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->value));
}
assert (len < ARRAY_LENGTH (s));
len = MIN (len, size - 1);
memcpy (buf, s, len);
buf[len] = '\0';
}
/* hb_variation_t */
static bool
parse_variation_value (const char **pp, const char *end, hb_variation_t *variation)
{
parse_char (pp, end, '='); /* Optional. */
return parse_float (pp, end, &variation->value);
}
static bool
parse_one_variation (const char **pp, const char *end, hb_variation_t *variation)
{
return parse_tag (pp, end, &variation->tag) &&
parse_variation_value (pp, end, variation) &&
parse_space (pp, end) &&
*pp == end;
}
/**
* hb_variation_from_string:
*
* Since: 1.4.2
*/
hb_bool_t
hb_variation_from_string (const char *str, int len,
hb_variation_t *variation)
{
hb_variation_t var;
if (len < 0)
len = strlen (str);
if (likely (parse_one_variation (&str, str + len, &var)))
{
if (variation)
*variation = var;
return true;
}
if (variation)
memset (variation, 0, sizeof (*variation));
return false;
}
/**
* hb_variation_to_string:
*
* Since: 1.4.2
*/
void
hb_variation_to_string (hb_variation_t *variation,
char *buf, unsigned int size)
{
if (unlikely (!size)) return;
char s[128];
unsigned int len = 0;
hb_tag_to_string (variation->tag, s + len);
len += 4;
while (len && s[len - 1] == ' ')
len--;
s[len++] = '=';
len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%g", variation->value));
assert (len < ARRAY_LENGTH (s));
len = MIN (len, size - 1);
memcpy (buf, s, len);
buf[len] = '\0';
}

View file

@ -362,6 +362,42 @@ typedef struct hb_user_data_key_t {
typedef void (*hb_destroy_func_t) (void *user_data);
/* Font features and variations. */
typedef struct hb_feature_t {
hb_tag_t tag;
uint32_t value;
unsigned int start;
unsigned int end;
} hb_feature_t;
HB_EXTERN hb_bool_t
hb_feature_from_string (const char *str, int len,
hb_feature_t *feature);
HB_EXTERN void
hb_feature_to_string (hb_feature_t *feature,
char *buf, unsigned int size);
/**
* hb_variation_t:
*
* Since: 1.4.2
*/
typedef struct hb_variation_t {
hb_tag_t tag;
float value;
} hb_variation_t;
HB_EXTERN hb_bool_t
hb_variation_from_string (const char *str, int len,
hb_variation_t *variation);
HB_EXTERN void
hb_variation_to_string (hb_variation_t *variation,
char *buf, unsigned int size);
HB_END_DECLS
#endif /* HB_COMMON_H */

View file

@ -69,8 +69,8 @@ hb_coretext_face_create (CGFontRef cg_font)
}
HB_SHAPER_DATA_ENSURE_DECLARE(coretext, face)
HB_SHAPER_DATA_ENSURE_DECLARE(coretext, font)
HB_SHAPER_DATA_ENSURE_DEFINE(coretext, face)
HB_SHAPER_DATA_ENSURE_DEFINE(coretext, font)
/*
@ -641,22 +641,23 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
/* active_features.qsort (); */
for (unsigned int j = 0; j < active_features.len; j++)
{
CFStringRef keys[2] = {
CFStringRef keys[] = {
kCTFontFeatureTypeIdentifierKey,
kCTFontFeatureSelectorIdentifierKey
};
CFNumberRef values[2] = {
CFNumberRef values[] = {
CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &active_features[j].rec.feature),
CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &active_features[j].rec.setting)
};
ASSERT_STATIC (ARRAY_LENGTH (keys) == ARRAY_LENGTH (values));
CFDictionaryRef dict = CFDictionaryCreate (kCFAllocatorDefault,
(const void **) keys,
(const void **) values,
2,
ARRAY_LENGTH (keys),
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
CFRelease (values[0]);
CFRelease (values[1]);
for (unsigned int i = 0; i < ARRAY_LENGTH (values); i++)
CFRelease (values[i]);
CFArrayAppendValue (features_array, dict);
CFRelease (dict);
@ -699,9 +700,6 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
active_features.remove (feature - active_features.array);
}
}
if (!range_records.len) /* No active feature found. */
goto fail_features;
}
else
{
@ -833,7 +831,7 @@ resize_and_retry:
CFAttributedStringSetAttribute (attr_string, CFRangeMake (0, chars_len),
kCTFontAttributeName, face_data->ct_font);
if (num_features)
if (num_features && range_records.len)
{
unsigned int start = 0;
range_record_t *last_range = &range_records[0];
@ -859,6 +857,30 @@ resize_and_retry:
CFAttributedStringSetAttribute (attr_string, CFRangeMake (start, chars_len - start),
kCTFontAttributeName, last_range->font);
}
/* Enable/disable kern if requested.
*
* Note: once kern is disabled, reenabling it doesn't currently seem to work in CoreText.
*/
if (num_features)
{
unsigned int zeroint = 0;
CFNumberRef zero = CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &zeroint);
for (unsigned int i = 0; i < num_features; i++)
{
const hb_feature_t &feature = features[i];
if (feature.tag == HB_TAG('k','e','r','n') &&
feature.start < chars_len && feature.start < feature.end)
{
CFRange feature_range = CFRangeMake (feature.start,
MIN (feature.end, chars_len) - feature.start);
if (feature.value)
CFAttributedStringRemoveAttribute (attr_string, feature_range, kCTKernAttributeName);
else
CFAttributedStringSetAttribute (attr_string, feature_range, kCTKernAttributeName, zero);
}
}
CFRelease (zero);
}
int level = HB_DIRECTION_IS_FORWARD (buffer->props.direction) ? 0 : 1;
CFNumberRef level_number = CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &level);
@ -868,6 +890,7 @@ resize_and_retry:
1,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
CFRelease (level_number);
if (unlikely (!options))
FAIL ("CFDictionaryCreate failed");
@ -1157,6 +1180,9 @@ resize_and_retry:
pos->x_advance = info->mask;
pos->x_offset = info->var1.i32;
pos->y_offset = info->var2.i32;
info->mask = HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
info++, pos++;
}
else
@ -1165,6 +1191,9 @@ resize_and_retry:
pos->y_advance = info->mask;
pos->x_offset = info->var1.i32;
pos->y_offset = info->var2.i32;
info->mask = HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
info++, pos++;
}
@ -1222,6 +1251,9 @@ fail:
* AAT shaper
*/
HB_SHAPER_DATA_ENSURE_DEFINE(coretext_aat, face)
HB_SHAPER_DATA_ENSURE_DEFINE(coretext_aat, font)
/*
* shaper face data
*/

View file

@ -34,8 +34,8 @@
#define HB_DEBUG_DIRECTWRITE (HB_DEBUG+0)
#endif
HB_SHAPER_DATA_ENSURE_DECLARE(directwrite, face)
HB_SHAPER_DATA_ENSURE_DECLARE(directwrite, font)
HB_SHAPER_DATA_ENSURE_DEFINE(directwrite, face)
HB_SHAPER_DATA_ENSURE_DEFINE(directwrite, font)
/*
@ -671,7 +671,7 @@ retry_getglyphs:
DWRITE_SHAPING_GLYPH_PROPERTIES* glyphProperties = (DWRITE_SHAPING_GLYPH_PROPERTIES*)
malloc (maxGlyphCount * sizeof (DWRITE_SHAPING_GLYPH_PROPERTIES));
hr = analyzer->GetGlyphs (textString, textLength, fontFace, FALSE,
hr = analyzer->GetGlyphs (textString, textLength, fontFace, false,
isRightToLeft, &runHead->mScript, localeName, NULL, &dwFeatures,
featureRangeLengths, 1, maxGlyphCount, clusterMap, textProperties, glyphIndices,
glyphProperties, &glyphCount);
@ -719,7 +719,7 @@ retry_getglyphs:
hr = analyzer->GetGlyphPlacements (textString,
clusterMap, textProperties, textLength, glyphIndices,
glyphProperties, glyphCount, fontFace, fontEmSize,
FALSE, isRightToLeft, &runHead->mScript, localeName,
false, isRightToLeft, &runHead->mScript, localeName,
&dwFeatures, featureRangeLengths, 1,
glyphAdvances, glyphOffsets);
@ -880,6 +880,8 @@ retry_getglyphs:
pos->x_offset =
x_mult * (isRightToLeft ? -info->var1.i32 : info->var1.i32);
pos->y_offset = y_mult * info->var2.i32;
info->mask = HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
}
if (isRightToLeft)
@ -915,7 +917,7 @@ _hb_directwrite_shape(hb_shape_plan_t *shape_plan,
*/
hb_bool_t
hb_shape_dwrite_experimental_width(hb_font_t *font,
hb_directwrite_shape_experimental_width(hb_font_t *font,
hb_buffer_t *buffer,
const hb_feature_t *features,
unsigned int num_features,

View file

@ -30,7 +30,7 @@
HB_BEGIN_DECLS
HB_EXTERN hb_bool_t
hb_shape_dwrite_experimental_width(hb_font_t *font, hb_buffer_t *buffer,
hb_directwrite_shape_experimental_width(hb_font_t *font, hb_buffer_t *buffer,
const hb_feature_t *features, unsigned int num_features, float width);
HB_END_DECLS

View file

@ -50,12 +50,23 @@ struct hb_face_t {
void *user_data;
hb_destroy_func_t destroy;
unsigned int index;
mutable unsigned int upem;
mutable unsigned int num_glyphs;
unsigned int index; /* Face index in a collection, zero-based. */
mutable unsigned int upem; /* Units-per-EM. */
mutable unsigned int num_glyphs; /* Number of glyphs. */
struct hb_shaper_data_t shaper_data;
enum dirty_t {
DIRTY_NOTHING = 0x0000,
DIRTY_INDEX = 0x0001,
DIRTY_UPEM = 0x0002,
DIRTY_NUM_GLYPHS = 0x0004,
} dirty;
struct hb_shaper_data_t shaper_data; /* Various shaper data. */
/* Various non-shaping data. */
/* ... */
/* Cache */
struct plan_node_t {
hb_shape_plan_t *shape_plan;
plan_node_t *next;
@ -95,6 +106,8 @@ struct hb_face_t {
HB_INTERNAL void load_num_glyphs (void) const;
};
HB_MARK_AS_FLAG_T (hb_face_t::dirty_t);
extern HB_INTERNAL const hb_face_t _hb_face_nil;
#define HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS

View file

@ -28,15 +28,11 @@
#include "hb-private.hh"
#include "hb-ot-layout-private.hh"
#include "hb-font-private.hh"
#include "hb-face-private.hh"
#include "hb-open-file-private.hh"
#include "hb-ot-head-table.hh"
#include "hb-ot-maxp-table.hh"
#include <string.h>
/*
* hb_face_t
@ -55,6 +51,8 @@ const hb_face_t _hb_face_nil = {
1000, /* upem */
0, /* num_glyphs */
hb_face_t::DIRTY_NOTHING, /* dirty */
{
#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INVALID,
#include "hb-shaper-list.hh"
@ -175,7 +173,7 @@ hb_face_create (hb_blob_t *blob,
closure,
(hb_destroy_func_t) _hb_face_for_data_closure_destroy);
hb_face_set_index (face, index);
face->index = index;
return face;
}
@ -369,6 +367,11 @@ hb_face_set_index (hb_face_t *face,
if (face->immutable)
return;
if (face->index == index)
return;
face->dirty |= face->DIRTY_INDEX;
face->index = index;
}
@ -404,6 +407,11 @@ hb_face_set_upem (hb_face_t *face,
if (face->immutable)
return;
if (face->upem == upem)
return;
face->dirty |= face->DIRTY_UPEM;
face->upem = upem;
}
@ -448,6 +456,11 @@ hb_face_set_glyph_count (hb_face_t *face,
if (face->immutable)
return;
if (face->num_glyphs == glyph_count)
return;
face->dirty |= face->DIRTY_NUM_GLYPHS;
face->num_glyphs = glyph_count;
}

View file

@ -28,6 +28,10 @@
#include "hb-shaper-impl-private.hh"
HB_SHAPER_DATA_ENSURE_DEFINE(fallback, face)
HB_SHAPER_DATA_ENSURE_DEFINE(fallback, font)
/*
* shaper face data
*/
@ -125,7 +129,7 @@ _hb_fallback_shape (hb_shape_plan_t *shape_plan HB_UNUSED,
pos[i].y_advance = 0;
continue;
}
font->get_nominal_glyph (info[i].codepoint, &info[i].codepoint);
(void) font->get_nominal_glyph (info[i].codepoint, &info[i].codepoint);
font->get_glyph_advance_for_direction (info[i].codepoint,
direction,
&pos[i].x_advance,

View file

@ -116,6 +116,16 @@ struct hb_font_t {
void *user_data;
hb_destroy_func_t destroy;
enum dirty_t {
DIRTY_NOTHING = 0x0000,
DIRTY_FACE = 0x0001,
DIRTY_PARENT = 0x0002,
DIRTY_FUNCS = 0x0004,
DIRTY_SCALE = 0x0008,
DIRTY_PPEM = 0x0010,
DIRTY_VARIATIONS = 0x0020,
} dirty;
struct hb_shaper_data_t shaper_data;
@ -543,6 +553,8 @@ struct hb_font_t {
}
};
HB_MARK_AS_FLAG_T (hb_font_t::dirty_t);
#define HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS
#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_PROTOTYPE(shaper, font);
#include "hb-shaper-list.hh"

View file

@ -28,14 +28,7 @@
#include "hb-private.hh"
#include "hb-ot-layout-private.hh"
#include "hb-font-private.hh"
#include "hb-open-file-private.hh"
#include "hb-ot-head-table.hh"
#include "hb-ot-maxp-table.hh"
#include <string.h>
/*
@ -1203,6 +1196,8 @@ hb_font_get_empty (void)
NULL, /* user_data */
NULL, /* destroy */
hb_font_t::DIRTY_NOTHING, /* dirty */
{
#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INVALID,
#include "hb-shaper-list.hh"
@ -1355,6 +1350,11 @@ hb_font_set_parent (hb_font_t *font,
if (!parent)
parent = hb_font_get_empty ();
if (parent == font->parent)
return;
font->dirty |= font->DIRTY_PARENT;
hb_font_t *old = font->parent;
font->parent = hb_font_reference (parent);
@ -1378,6 +1378,37 @@ hb_font_get_parent (hb_font_t *font)
return font->parent;
}
/**
* hb_font_set_face:
* @font: a font.
* @face: new face.
*
* Sets font-face of @font.
*
* Since: 1.4.3
**/
void
hb_font_set_face (hb_font_t *font,
hb_face_t *face)
{
if (font->immutable)
return;
if (unlikely (!face))
face = hb_face_get_empty ();
if (font->face == face)
return;
font->dirty |= font->DIRTY_FACE;
hb_face_t *old = font->face;
font->face = hb_face_reference (face);
hb_face_destroy (old);
}
/**
* hb_font_get_face:
* @font: a font.
@ -1424,6 +1455,8 @@ hb_font_set_funcs (hb_font_t *font,
if (!klass)
klass = hb_font_funcs_get_empty ();
font->dirty |= font->DIRTY_FUNCS;
hb_font_funcs_reference (klass);
hb_font_funcs_destroy (font->klass);
font->klass = klass;
@ -1479,6 +1512,11 @@ hb_font_set_scale (hb_font_t *font,
if (font->immutable)
return;
if (font->x_scale == x_scale && font->y_scale == y_scale)
return;
font->dirty |= font->DIRTY_SCALE;
font->x_scale = x_scale;
font->y_scale = y_scale;
}
@ -1520,6 +1558,11 @@ hb_font_set_ppem (hb_font_t *font,
if (font->immutable)
return;
if (font->x_ppem == x_ppem && font->y_ppem == y_ppem)
return;
font->dirty |= font->DIRTY_PPEM;
font->x_ppem = x_ppem;
font->y_ppem = y_ppem;
}
@ -1543,30 +1586,122 @@ hb_font_get_ppem (hb_font_t *font,
if (y_ppem) *y_ppem = font->y_ppem;
}
/*
* Variations
*/
static void
_hb_font_adopt_var_coords_normalized (hb_font_t *font,
int *coords, /* 2.14 normalized */
unsigned int coords_length)
{
if (font->num_coords == coords_length &&
(coords_length == 0 ||
0 == memcmp (font->coords, coords, coords_length * sizeof (coords[0]))))
{
free (coords);
return;
}
font->dirty |= font->DIRTY_VARIATIONS;
free (font->coords);
font->coords = coords;
font->num_coords = coords_length;
}
/**
* hb_font_set_variations:
*
* Since: 1.4.2
*/
void
hb_font_set_variations (hb_font_t *font,
const hb_variation_t *variations,
unsigned int variations_length)
{
if (font->immutable)
return;
if (!variations_length)
{
hb_font_set_var_coords_normalized (font, NULL, 0);
return;
}
unsigned int coords_length = hb_ot_var_get_axis_count (font->face);
int *normalized = coords_length ? (int *) calloc (coords_length, sizeof (int)) : NULL;
if (unlikely (coords_length && !normalized))
return;
hb_ot_var_normalize_variations (font->face,
variations, variations_length,
normalized, coords_length);
_hb_font_adopt_var_coords_normalized (font, normalized, coords_length);
}
/**
* hb_font_set_var_coords_design:
*
* Since: 1.4.2
*/
void
hb_font_set_var_coords_design (hb_font_t *font,
const float *coords,
unsigned int coords_length)
{
if (font->immutable)
return;
int *normalized = coords_length ? (int *) calloc (coords_length, sizeof (int)) : NULL;
if (unlikely (coords_length && !normalized))
return;
hb_ot_var_normalize_coords (font->face, coords_length, coords, normalized);
_hb_font_adopt_var_coords_normalized (font, normalized, coords_length);
}
/**
* hb_font_set_var_coords_normalized:
*
* Since: 1.4.2
*/
void
hb_font_set_var_coords_normalized (hb_font_t *font,
int *coords, /* XXX 2.14 normalized */
const int *coords, /* 2.14 normalized */
unsigned int coords_length)
{
if (font->immutable)
return;
/* Skip tail zero entries. */
while (coords_length && !coords[coords_length - 1])
coords_length--;
int *copy = coords_length ? (int *) calloc (coords_length, sizeof (coords[0])) : NULL;
if (unlikely (coords_length && !copy))
return;
free (font->coords);
if (coords_length)
memcpy (copy, coords, coords_length * sizeof (coords[0]));
font->coords = copy;
font->num_coords = coords_length;
_hb_font_adopt_var_coords_normalized (font, copy, coords_length);
}
/**
* hb_font_get_var_coords_normalized:
*
* Return value is valid as long as variation coordinates of the font
* are not modified.
*
* Since: 1.4.2
*/
const int *
hb_font_get_var_coords_normalized (hb_font_t *font,
unsigned int *length)
{
if (length)
*length = font->num_coords;
return font->coords;
}

View file

@ -563,6 +563,10 @@ hb_font_set_parent (hb_font_t *font,
HB_EXTERN hb_font_t *
hb_font_get_parent (hb_font_t *font);
HB_EXTERN void
hb_font_set_face (hb_font_t *font,
hb_face_t *face);
HB_EXTERN hb_face_t *
hb_font_get_face (hb_font_t *font);
@ -603,12 +607,25 @@ hb_font_get_ppem (hb_font_t *font,
unsigned int *x_ppem,
unsigned int *y_ppem);
HB_EXTERN void
hb_font_set_variations (hb_font_t *font,
const hb_variation_t *variations,
unsigned int variations_length);
HB_EXTERN void
hb_font_set_var_coords_design (hb_font_t *font,
const float *coords,
unsigned int coords_length);
HB_EXTERN void
hb_font_set_var_coords_normalized (hb_font_t *font,
int *coords, /* XXX 2.14 normalized */
const int *coords, /* 2.14 normalized */
unsigned int coords_length);
HB_EXTERN const int *
hb_font_get_var_coords_normalized (hb_font_t *font,
unsigned int *length);
HB_END_DECLS
#endif /* HB_FONT_H */

View file

@ -493,7 +493,7 @@ reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
return NULL;
buffer = (FT_Byte *) malloc (length);
if (buffer == NULL)
if (!buffer)
return NULL;
error = FT_Load_Sfnt_Table (ft_face, tag, 0, buffer, &length);
@ -521,7 +521,7 @@ hb_ft_face_create (FT_Face ft_face,
{
hb_face_t *face;
if (ft_face->stream->read == NULL) {
if (!ft_face->stream->read) {
hb_blob_t *blob;
blob = hb_blob_create ((const char *) ft_face->stream->base,
@ -621,17 +621,22 @@ hb_ft_font_create (FT_Face ft_face,
FT_MM_Var *mm_var = NULL;
if (!FT_Get_MM_Var (ft_face, &mm_var))
{
FT_Fixed coords[mm_var->num_axis];
int hbCoords[mm_var->num_axis];
if (!FT_Get_Var_Blend_Coordinates (ft_face, mm_var->num_axis, coords))
FT_Fixed *ft_coords = (FT_Fixed *) calloc (mm_var->num_axis, sizeof (FT_Fixed));
int *coords = (int *) calloc (mm_var->num_axis, sizeof (int));
if (coords && ft_coords)
{
for (int i = 0; i < mm_var->num_axis; ++i)
hbCoords[i] = coords[i] >> 2;
if (!FT_Get_Var_Blend_Coordinates (ft_face, mm_var->num_axis, ft_coords))
{
for (unsigned int i = 0; i < mm_var->num_axis; ++i)
coords[i] = ft_coords[i] >>= 2;
hb_font_set_var_coords_normalized (font, hbCoords, mm_var->num_axis);
hb_font_set_var_coords_normalized (font, coords, mm_var->num_axis);
}
}
free (coords);
free (ft_coords);
free (mm_var);
}
free (mm_var);
#endif
return font;
@ -736,6 +741,20 @@ hb_ft_font_set_funcs (hb_font_t *font)
FT_Set_Transform (ft_face, &matrix, NULL);
}
unsigned int num_coords;
const int *coords = hb_font_get_var_coords_normalized (font, &num_coords);
if (num_coords)
{
FT_Fixed *ft_coords = (FT_Fixed *) calloc (num_coords, sizeof (FT_Fixed));
if (ft_coords)
{
for (unsigned int i = 0; i < num_coords; i++)
ft_coords[i] = coords[i] << 2;
FT_Set_Var_Blend_Coordinates (ft_face, num_coords, ft_coords);
free (ft_coords);
}
}
ft_face->generic.data = blob;
ft_face->generic.finalizer = (FT_Generic_Finalizer) _release_blob;

View file

@ -27,7 +27,6 @@
*/
#define HB_SHAPER graphite2
#define hb_graphite2_shaper_font_data_t gr_font
#include "hb-shaper-impl-private.hh"
#include "hb-graphite2.h"
@ -35,8 +34,8 @@
#include <graphite2/Segment.h>
HB_SHAPER_DATA_ENSURE_DECLARE(graphite2, face)
HB_SHAPER_DATA_ENSURE_DECLARE(graphite2, font)
HB_SHAPER_DATA_ENSURE_DEFINE(graphite2, face)
HB_SHAPER_DATA_ENSURE_DEFINE(graphite2, font)
/*
@ -153,26 +152,17 @@ hb_graphite2_face_get_gr_face (hb_face_t *face)
* shaper font data
*/
static float hb_graphite2_get_advance (const void *hb_font, unsigned short gid)
{
return ((hb_font_t *) hb_font)->get_glyph_h_advance (gid);
}
struct hb_graphite2_shaper_font_data_t {};
hb_graphite2_shaper_font_data_t *
_hb_graphite2_shaper_font_data_create (hb_font_t *font)
_hb_graphite2_shaper_font_data_create (hb_font_t *font HB_UNUSED)
{
if (unlikely (!hb_graphite2_shaper_face_data_ensure (font->face))) return NULL;
hb_face_t *face = font->face;
hb_graphite2_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
return gr_make_font_with_advance_fn (font->x_scale, font, &hb_graphite2_get_advance, face_data->grface);
return (hb_graphite2_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED;
}
void
_hb_graphite2_shaper_font_data_destroy (hb_graphite2_shaper_font_data_t *data)
_hb_graphite2_shaper_font_data_destroy (hb_graphite2_shaper_font_data_t *data HB_UNUSED)
{
gr_font_destroy (data);
}
/*
@ -181,8 +171,7 @@ _hb_graphite2_shaper_font_data_destroy (hb_graphite2_shaper_font_data_t *data)
gr_font *
hb_graphite2_font_get_gr_font (hb_font_t *font)
{
if (unlikely (!hb_graphite2_shaper_font_data_ensure (font))) return NULL;
return HB_SHAPER_DATA_GET (font);
return NULL;
}
@ -230,7 +219,6 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan,
{
hb_face_t *face = font->face;
gr_face *grface = HB_SHAPER_DATA_GET (face)->grface;
gr_font *grfont = HB_SHAPER_DATA_GET (font);
const char *lang = hb_language_to_string (hb_buffer_get_language (buffer));
const char *lang_end = lang ? strchr (lang, '-') : NULL;
@ -262,7 +250,7 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan,
hb_tag_t script_tag[2];
hb_ot_tags_from_script (hb_buffer_get_script (buffer), &script_tag[0], &script_tag[1]);
seg = gr_make_seg (grfont, grface,
seg = gr_make_seg (NULL, grface,
script_tag[1] == HB_TAG_NONE ? script_tag[0] : script_tag[1],
feats,
gr_utf32, chars, buffer->len,
@ -313,7 +301,7 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan,
hb_codepoint_t *pg = gids;
clusters[0].cluster = buffer->info[0].cluster;
float curradv = HB_DIRECTION_IS_BACKWARD(buffer->props.direction) ? gr_slot_origin_X(gr_seg_first_slot(seg)) : 0.;
float curradv = 0.;
if (HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
{
curradv = gr_slot_origin_X(gr_seg_first_slot(seg));
@ -342,13 +330,10 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan,
c->base_glyph = ic;
c->num_glyphs = 0;
if (HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
{
ci++;
clusters[ci].advance = curradv - gr_slot_origin_X(is);
} else {
c->advance = curradv - gr_slot_origin_X(is);
else
clusters[ci].advance = gr_slot_origin_X(is) - curradv;
ci++;
}
ci++;
curradv = gr_slot_origin_X(is);
}
clusters[ci].num_glyphs++;
@ -357,7 +342,9 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan,
clusters[ci].num_chars = after + 1 - clusters[ci].base_char;
}
if (!HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
if (HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
clusters[ci].advance += curradv;
else
clusters[ci].advance = gr_seg_advance_X(seg) - curradv;
ci++;
@ -368,53 +355,54 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan,
hb_glyph_info_t *info = &buffer->info[clusters[i].base_glyph + j];
info->codepoint = gids[clusters[i].base_glyph + j];
info->cluster = clusters[i].cluster;
info->mask = HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
info->var1.i32 = clusters[i].advance; // all glyphs in the cluster get the same advance
}
}
buffer->len = glyph_count;
float yscale = font->y_scale / font->x_scale;
unsigned int upem = hb_face_get_upem (face);
float xscale = (float) font->x_scale / upem;
float yscale = (float) font->y_scale / upem;
yscale *= yscale / xscale;
/* Positioning. */
unsigned int currclus = (unsigned int) -1;
const hb_glyph_info_t *info = buffer->info;
hb_glyph_position_t *pPos = hb_buffer_get_glyph_positions (buffer, NULL);
if (!HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
{
int currclus = -1;
const hb_glyph_info_t *info = buffer->info;
hb_glyph_position_t *pPos = hb_buffer_get_glyph_positions (buffer, NULL);
curradvx = 0;
for (is = gr_seg_first_slot (seg); is; pPos++, ++info, is = gr_slot_next_in_segment (is))
{
pPos->x_offset = gr_slot_origin_X (is) - curradvx;
pPos->x_offset = gr_slot_origin_X (is) * xscale - curradvx;
pPos->y_offset = gr_slot_origin_Y (is) * yscale - curradvy;
if (info->cluster != currclus) {
pPos->x_advance = info->var1.i32;
pPos->x_advance = info->var1.i32 * xscale;
curradvx += pPos->x_advance;
currclus = info->cluster;
} else
pPos->x_advance = 0.;
pPos->y_advance = gr_slot_advance_Y (is, grface, grfont) * yscale;
pPos->y_advance = gr_slot_advance_Y (is, grface, NULL) * yscale;
curradvy += pPos->y_advance;
}
}
else
{
int currclus = -1;
const hb_glyph_info_t *info = buffer->info;
hb_glyph_position_t *pPos = hb_buffer_get_glyph_positions (buffer, NULL);
curradvx = gr_seg_advance_X(seg);
for (is = gr_seg_first_slot (seg); is; pPos++, info++, is = gr_slot_next_in_segment (is))
{
if (info->cluster != currclus)
{
pPos->x_advance = info->var1.i32;
if (currclus != -1) curradvx -= info[-1].var1.i32;
pPos->x_advance = info->var1.i32 * xscale;
curradvx -= pPos->x_advance;
currclus = info->cluster;
} else
pPos->x_advance = 0.;
pPos->x_advance = 0.;
pPos->y_advance = gr_slot_advance_Y (is, grface, grfont) * yscale;
pPos->y_advance = gr_slot_advance_Y (is, grface, NULL) * yscale;
curradvy -= pPos->y_advance;
pPos->x_offset = gr_slot_origin_X (is) - curradvx + pPos->x_advance;
pPos->x_offset = (gr_slot_origin_X (is) - info->var1.i32) * xscale - curradvx + pPos->x_advance;
pPos->y_offset = gr_slot_origin_Y (is) * yscale - curradvy;
}
hb_buffer_reverse_clusters (buffer);

View file

@ -39,9 +39,13 @@ HB_BEGIN_DECLS
HB_EXTERN gr_face *
hb_graphite2_face_get_gr_face (hb_face_t *face);
#ifndef HB_DISABLE_DEPRECATED
HB_EXTERN gr_font *
hb_graphite2_font_get_gr_font (hb_font_t *font);
#endif
HB_END_DECLS

View file

@ -142,7 +142,7 @@ struct TTCHeaderVersion1
Tag ttcTag; /* TrueType Collection ID string: 'ttcf' */
FixedVersion<>version; /* Version of the TTC Header (1.0),
* 0x00010000u */
ArrayOf<OffsetTo<OffsetTable, ULONG>, ULONG>
ArrayOf<LOffsetTo<OffsetTable>, ULONG>
table; /* Array of offsets to the OffsetTable for each font
* from the beginning of the file */
public:

View file

@ -30,6 +30,7 @@
#define HB_OPEN_TYPE_PRIVATE_HH
#include "hb-private.hh"
#include "hb-face-private.hh"
namespace OT {
@ -829,6 +830,7 @@ struct OffsetTo : Offset<OffsetType>
}
DEFINE_SIZE_STATIC (sizeof(OffsetType));
};
template <typename Type> struct LOffsetTo : OffsetTo<Type, ULONG> {};
template <typename Base, typename OffsetType, typename Type>
static inline const Type& operator + (const Base &base, const OffsetTo<Type, OffsetType> &offset) { return offset (base); }
template <typename Base, typename OffsetType, typename Type>
@ -950,6 +952,7 @@ struct ArrayOf
public:
DEFINE_SIZE_ARRAY (sizeof (LenType), array);
};
template <typename Type> struct LArrayOf : ArrayOf<Type, ULONG> {};
/* Array of Offset's */
template <typename Type, typename OffsetType=USHORT>
@ -1061,6 +1064,104 @@ struct SortedArrayOf : ArrayOf<Type, LenType>
};
/* Lazy struct and blob loaders. */
/* Logic is shared between hb_lazy_loader_t and hb_lazy_table_loader_t */
template <typename T>
struct hb_lazy_loader_t
{
inline void init (hb_face_t *face_)
{
face = face_;
instance = NULL;
}
inline void fini (void)
{
if (instance && instance != &OT::Null(T))
{
instance->fini();
free (instance);
}
}
inline const T* get (void) const
{
retry:
T *p = (T *) hb_atomic_ptr_get (&instance);
if (unlikely (!p))
{
p = (T *) calloc (1, sizeof (T));
if (unlikely (!p))
p = const_cast<T *> (&OT::Null(T));
else
p->init (face);
if (unlikely (!hb_atomic_ptr_cmpexch (const_cast<T **>(&instance), NULL, p)))
{
if (p != &OT::Null(T))
p->fini ();
goto retry;
}
}
return p;
}
inline const T* operator-> (void) const
{
return get ();
}
private:
hb_face_t *face;
T *instance;
};
/* Logic is shared between hb_lazy_loader_t and hb_lazy_table_loader_t */
template <typename T>
struct hb_lazy_table_loader_t
{
inline void init (hb_face_t *face_)
{
face = face_;
instance = NULL;
blob = NULL;
}
inline void fini (void)
{
hb_blob_destroy (blob);
}
inline const T* get (void) const
{
retry:
T *p = (T *) hb_atomic_ptr_get (&instance);
if (unlikely (!p))
{
hb_blob_t *blob_ = OT::Sanitizer<T>::sanitize (face->reference_table (T::tableTag));
p = const_cast<T *>(OT::Sanitizer<T>::lock_instance (blob_));
if (!hb_atomic_ptr_cmpexch (const_cast<T **>(&instance), NULL, p))
{
hb_blob_destroy (blob_);
goto retry;
}
blob = blob_;
}
return p;
}
inline const T* operator-> (void) const
{
return get();
}
private:
hb_face_t *face;
T *instance;
mutable hb_blob_t *blob;
};
} /* namespace OT */

View file

@ -216,7 +216,7 @@ struct IndexSubtableRecord
USHORT firstGlyphIndex;
USHORT lastGlyphIndex;
OffsetTo<IndexSubtable, ULONG> offsetToSubtable;
LOffsetTo<IndexSubtable> offsetToSubtable;
DEFINE_SIZE_STATIC(8);
};
@ -275,7 +275,7 @@ struct BitmapSizeTable
}
protected:
OffsetTo<IndexSubtableArray, ULONG> indexSubtableArrayOffset;
LOffsetTo<IndexSubtableArray> indexSubtableArrayOffset;
ULONG indexTablesSize;
ULONG numberOfIndexSubtables;
ULONG colorRef;
@ -348,8 +348,8 @@ struct CBLC
}
protected:
FixedVersion<>version;
ArrayOf<BitmapSizeTable, ULONG> sizeTables;
FixedVersion<> version;
LArrayOf<BitmapSizeTable> sizeTables;
public:
DEFINE_SIZE_ARRAY(8, sizeTables);

View file

@ -380,9 +380,9 @@ struct VariationSelectorRecord
}
UINT24 varSelector; /* Variation selector. */
OffsetTo<DefaultUVS, ULONG>
LOffsetTo<DefaultUVS>
defaultUVS; /* Offset to Default UVS Table. May be 0. */
OffsetTo<NonDefaultUVS, ULONG>
LOffsetTo<NonDefaultUVS>
nonDefaultUVS; /* Offset to Non-Default UVS Table. May be 0. */
public:
DEFINE_SIZE_STATIC (11);
@ -486,7 +486,7 @@ struct EncodingRecord
USHORT platformID; /* Platform ID. */
USHORT encodingID; /* Platform-specific encoding ID. */
OffsetTo<CmapSubtable, ULONG>
LOffsetTo<CmapSubtable>
subtable; /* Byte offset from beginning of table to the subtable for this encoding. */
public:
DEFINE_SIZE_STATIC (8);

View file

@ -37,6 +37,7 @@
#include "hb-ot-hhea-table.hh"
#include "hb-ot-hmtx-table.hh"
#include "hb-ot-os2-table.hh"
#include "hb-ot-var-hvar-table.hh"
//#include "hb-ot-post-table.hh"
@ -50,12 +51,16 @@ struct hb_ot_face_metrics_accelerator_t
unsigned short line_gap;
bool has_font_extents;
const OT::_mtx *table;
const OT::hmtxvmtx *table;
hb_blob_t *blob;
const OT::HVARVVAR *var;
hb_blob_t *var_blob;
inline void init (hb_face_t *face,
hb_tag_t _hea_tag,
hb_tag_t _mtx_tag,
hb_tag_t _var_tag,
hb_tag_t os2_tag,
unsigned int default_advance = 0)
{
@ -91,7 +96,7 @@ struct hb_ot_face_metrics_accelerator_t
this->has_font_extents = got_font_extents;
this->blob = OT::Sanitizer<OT::_mtx>::sanitize (face->reference_table (_mtx_tag));
this->blob = OT::Sanitizer<OT::hmtxvmtx>::sanitize (face->reference_table (_mtx_tag));
/* Cap num_metrics() and num_advances() based on table length. */
unsigned int len = hb_blob_get_length (this->blob);
@ -107,15 +112,20 @@ struct hb_ot_face_metrics_accelerator_t
hb_blob_destroy (this->blob);
this->blob = hb_blob_get_empty ();
}
this->table = OT::Sanitizer<OT::_mtx>::lock_instance (this->blob);
this->table = OT::Sanitizer<OT::hmtxvmtx>::lock_instance (this->blob);
this->var_blob = OT::Sanitizer<OT::HVARVVAR>::sanitize (face->reference_table (_var_tag));
this->var = OT::Sanitizer<OT::HVARVVAR>::lock_instance (this->var_blob);
}
inline void fini (void)
{
hb_blob_destroy (this->blob);
hb_blob_destroy (this->var_blob);
}
inline unsigned int get_advance (hb_codepoint_t glyph) const
inline unsigned int get_advance (hb_codepoint_t glyph,
hb_font_t *font) const
{
if (unlikely (glyph >= this->num_metrics))
{
@ -128,10 +138,8 @@ struct hb_ot_face_metrics_accelerator_t
return this->default_advance;
}
if (glyph >= this->num_advances)
glyph = this->num_advances - 1;
return this->table->longMetric[glyph].advance;
return this->table->longMetric[MIN (glyph, (uint32_t) this->num_advances - 1)].advance
+ this->var->get_advance_var (glyph, font->coords, font->num_coords); // TODO Optimize?!
}
};
@ -216,7 +224,7 @@ struct hb_ot_face_cbdt_accelerator_t
const OT::CBDT *cbdt;
unsigned int cbdt_len;
float upem;
unsigned int upem;
inline void init (hb_face_t *face)
{
@ -246,11 +254,11 @@ struct hb_ot_face_cbdt_accelerator_t
{
unsigned int x_ppem = upem, y_ppem = upem; /* TODO Use font ppem if available. */
if (cblc == NULL)
if (!cblc)
return false; // Not a color bitmap font.
const OT::IndexSubtableRecord *subtable_record = this->cblc->find_table(glyph, &x_ppem, &y_ppem);
if (subtable_record == NULL)
if (!subtable_record || !x_ppem || !y_ppem)
return false;
if (subtable_record->get_extents (extents))
@ -421,55 +429,13 @@ struct hb_ot_face_cmap_accelerator_t
}
};
template <typename T>
struct hb_lazy_loader_t
{
inline void init (hb_face_t *face_)
{
face = face_;
instance = NULL;
}
inline void fini (void)
{
if (instance && instance != &OT::Null(T))
{
instance->fini();
free (instance);
}
}
inline const T* operator-> (void) const
{
retry:
T *p = (T *) hb_atomic_ptr_get (&instance);
if (unlikely (!p))
{
p = (T *) calloc (1, sizeof (T));
if (unlikely (!p))
return &OT::Null(T);
p->init (face);
if (unlikely (!hb_atomic_ptr_cmpexch (const_cast<T **>(&instance), NULL, p)))
{
p->fini ();
goto retry;
}
}
return p;
}
private:
hb_face_t *face;
T *instance;
};
struct hb_ot_font_t
{
hb_ot_face_cmap_accelerator_t cmap;
hb_ot_face_metrics_accelerator_t h_metrics;
hb_ot_face_metrics_accelerator_t v_metrics;
hb_lazy_loader_t<hb_ot_face_glyf_accelerator_t> glyf;
hb_lazy_loader_t<hb_ot_face_cbdt_accelerator_t> cbdt;
OT::hb_lazy_loader_t<hb_ot_face_glyf_accelerator_t> glyf;
OT::hb_lazy_loader_t<hb_ot_face_cbdt_accelerator_t> cbdt;
};
@ -482,8 +448,8 @@ _hb_ot_font_create (hb_face_t *face)
return NULL;
ot_font->cmap.init (face);
ot_font->h_metrics.init (face, HB_OT_TAG_hhea, HB_OT_TAG_hmtx, HB_OT_TAG_os2);
ot_font->v_metrics.init (face, HB_OT_TAG_vhea, HB_OT_TAG_vmtx, HB_TAG_NONE,
ot_font->h_metrics.init (face, HB_OT_TAG_hhea, HB_OT_TAG_hmtx, HB_OT_TAG_HVAR, HB_OT_TAG_os2);
ot_font->v_metrics.init (face, HB_OT_TAG_vhea, HB_OT_TAG_vmtx, HB_OT_TAG_VVAR, HB_TAG_NONE,
ot_font->h_metrics.ascender - ot_font->h_metrics.descender); /* TODO Can we do this lazily? */
ot_font->glyf.init (face);
ot_font->cbdt.init (face);
@ -529,23 +495,23 @@ hb_ot_get_variation_glyph (hb_font_t *font HB_UNUSED,
}
static hb_position_t
hb_ot_get_glyph_h_advance (hb_font_t *font HB_UNUSED,
hb_ot_get_glyph_h_advance (hb_font_t *font,
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;
return font->em_scale_x (ot_font->h_metrics.get_advance (glyph));
return font->em_scale_x (ot_font->h_metrics.get_advance (glyph, font));
}
static hb_position_t
hb_ot_get_glyph_v_advance (hb_font_t *font HB_UNUSED,
hb_ot_get_glyph_v_advance (hb_font_t *font,
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;
return font->em_scale_y (-(int) ot_font->v_metrics.get_advance (glyph));
return font->em_scale_y (-(int) ot_font->v_metrics.get_advance (glyph, font));
}
static hb_bool_t
@ -559,6 +525,7 @@ hb_ot_get_glyph_extents (hb_font_t *font HB_UNUSED,
bool ret = ot_font->glyf->get_extents (glyph, extents);
if (!ret)
ret = ot_font->cbdt->get_extents (glyph, extents);
// TODO Hook up side-bearings variations.
extents->x_bearing = font->em_scale_x (extents->x_bearing);
extents->y_bearing = font->em_scale_y (extents->y_bearing);
extents->width = font->em_scale_x (extents->width);
@ -576,6 +543,7 @@ hb_ot_get_font_h_extents (hb_font_t *font HB_UNUSED,
metrics->ascender = font->em_scale_y (ot_font->h_metrics.ascender);
metrics->descender = font->em_scale_y (ot_font->h_metrics.descender);
metrics->line_gap = font->em_scale_y (ot_font->h_metrics.line_gap);
// TODO Hook up variations.
return ot_font->h_metrics.has_font_extents;
}
@ -589,6 +557,7 @@ hb_ot_get_font_v_extents (hb_font_t *font HB_UNUSED,
metrics->ascender = font->em_scale_x (ot_font->v_metrics.ascender);
metrics->descender = font->em_scale_x (ot_font->v_metrics.descender);
metrics->line_gap = font->em_scale_x (ot_font->v_metrics.line_gap);
// TODO Hook up variations.
return ot_font->v_metrics.has_font_extents;
}

View file

@ -50,10 +50,8 @@ struct LongMetric
DEFINE_SIZE_STATIC (4);
};
struct _mtx
struct hmtxvmtx
{
static const hb_tag_t tableTag = HB_TAG('_','m','t','x');
static const hb_tag_t hmtxTag = HB_OT_TAG_hmtx;
static const hb_tag_t vmtxTag = HB_OT_TAG_vmtx;
@ -91,10 +89,10 @@ struct _mtx
DEFINE_SIZE_ARRAY2 (0, longMetric, leadingBearingX);
};
struct hmtx : _mtx {
struct hmtx : hmtxvmtx {
static const hb_tag_t tableTag = HB_OT_TAG_hmtx;
};
struct vmtx : _mtx {
struct vmtx : hmtxvmtx {
static const hb_tag_t tableTag = HB_OT_TAG_vmtx;
};

View file

@ -941,7 +941,7 @@ struct Coverage
}
struct Iter {
Iter (void) : format (0) {};
Iter (void) : format (0), u () {};
inline void init (const Coverage &c_) {
format = c_.u.format;
switch (format) {
@ -982,8 +982,8 @@ struct Coverage
private:
unsigned int format;
union {
CoverageFormat2::Iter format2; /* Put this one first since it's larger; helps shut up compiler. */
CoverageFormat1::Iter format1;
CoverageFormat2::Iter format2;
} u;
};
@ -1323,6 +1323,14 @@ struct VariationStore
this+regions);
}
inline float get_delta (unsigned int index,
int *coords, unsigned int coord_count) const
{
unsigned int outer = index >> 16;
unsigned int inner = index & 0xFFFF;
return get_delta (outer, inner, coords, coord_count);
}
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@ -1334,7 +1342,7 @@ struct VariationStore
protected:
USHORT format;
OffsetTo<VarRegionList, ULONG> regions;
LOffsetTo<VarRegionList> regions;
OffsetArrayOf<VarData, ULONG> dataSets;
public:
DEFINE_SIZE_ARRAY (8, dataSets);
@ -1433,8 +1441,8 @@ struct FeatureTableSubstitutionRecord
}
protected:
USHORT featureIndex;
OffsetTo<Feature, ULONG> feature;
USHORT featureIndex;
LOffsetTo<Feature> feature;
public:
DEFINE_SIZE_STATIC (6);
};
@ -1481,9 +1489,9 @@ struct FeatureVariationRecord
}
protected:
OffsetTo<ConditionSet, ULONG>
LOffsetTo<ConditionSet>
conditions;
OffsetTo<FeatureTableSubstitution, ULONG>
LOffsetTo<FeatureTableSubstitution>
substitutions;
public:
DEFINE_SIZE_STATIC (8);
@ -1527,7 +1535,7 @@ struct FeatureVariations
protected:
FixedVersion<> version; /* Version--0x00010000u */
ArrayOf<FeatureVariationRecord, ULONG>
LArrayOf<FeatureVariationRecord>
varRecords;
public:
DEFINE_SIZE_ARRAY (8, varRecords);

View file

@ -295,7 +295,7 @@ struct MarkGlyphSetsFormat1
protected:
USHORT format; /* Format identifier--format = 1 */
ArrayOf<OffsetTo<Coverage, ULONG> >
ArrayOf<LOffsetTo<Coverage> >
coverage; /* Array of long offsets to mark set
* coverage tables */
public:
@ -443,7 +443,7 @@ struct GDEF
* definitions--from beginning of GDEF
* header (may be NULL). Introduced
* in version 0x00010002. */
OffsetTo<VariationStore, ULONG>
LOffsetTo<VariationStore>
varStore; /* Offset to the table of Item Variation
* Store--from beginning of GDEF
* header (may be NULL). Introduced

View file

@ -432,6 +432,7 @@ struct MarkArray : ArrayOf<MarkRecord> /* Array of MarkRecords--in Coverage orde
hb_position_t mark_x, mark_y, base_x, base_y;
buffer->unsafe_to_break (glyph_pos, buffer->idx);
mark_anchor.get_anchor (c, buffer->cur().codepoint, &mark_x, &mark_y);
glyph_anchor.get_anchor (c, buffer->info[glyph_pos].codepoint, &base_x, &base_y);
@ -643,6 +644,7 @@ struct PairSet
min = mid + 1;
else
{
buffer->unsafe_to_break (buffer->idx, pos + 1);
valueFormats[0].apply_value (c, this, &record->values[0], buffer->cur_pos());
valueFormats[1].apply_value (c, this, &record->values[len1], buffer->pos[pos]);
if (len2)
@ -790,6 +792,7 @@ struct PairPosFormat2
unsigned int klass2 = (this+classDef2).get_class (buffer->info[skippy_iter.idx].codepoint);
if (unlikely (klass1 >= class1Count || klass2 >= class2Count)) return_trace (false);
buffer->unsafe_to_break (buffer->idx, skippy_iter.idx + 1);
const Value *v = &values[record_len * (klass1 * class2Count + klass2)];
valueFormat1.apply_value (c, this, v, buffer->cur_pos());
valueFormat2.apply_value (c, this, v + len1, buffer->pos[skippy_iter.idx]);
@ -929,6 +932,7 @@ struct CursivePosFormat1
unsigned int i = buffer->idx;
unsigned int j = skippy_iter.idx;
buffer->unsafe_to_break (i, j);
hb_position_t entry_x, entry_y, exit_x, exit_y;
(this+this_record.exitAnchor).get_anchor (c, buffer->info[i].codepoint, &exit_x, &exit_y);
(this+next_record.entryAnchor).get_anchor (c, buffer->info[j].codepoint, &entry_x, &entry_y);

View file

@ -1014,14 +1014,17 @@ struct ReverseChainSingleSubstFormat1
const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
unsigned int start_index = 0, end_index = 0;
if (match_backtrack (c,
backtrack.len, (USHORT *) backtrack.array,
match_coverage, this) &&
match_coverage, this,
&start_index) &&
match_lookahead (c,
lookahead.len, (USHORT *) lookahead.array,
match_coverage, this,
1))
1, &end_index))
{
c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index);
c->replace_glyph_inplace (substitute[index]);
/* Note: We DON'T decrease buffer->idx. The main loop does it
* for us. This is useful for preventing surprises if someone

View file

@ -319,7 +319,7 @@ struct hb_apply_context_t :
if (!c->check_glyph_property (&info, lookup_props))
return SKIP_YES;
if (unlikely (_hb_glyph_info_is_default_ignorable_and_not_fvs (&info) &&
if (unlikely (_hb_glyph_info_is_default_ignorable_and_not_hidden (&info) &&
(ignore_zwnj || !_hb_glyph_info_is_zwnj (&info)) &&
(ignore_zwj || !_hb_glyph_info_is_zwj (&info))))
return SKIP_MAYBE;
@ -342,13 +342,13 @@ struct hb_apply_context_t :
inline void init (hb_apply_context_t *c_, bool context_match = false)
{
c = c_;
match_glyph_data = NULL,
match_glyph_data = NULL;
matcher.set_match_func (NULL, NULL);
matcher.set_lookup_props (c->lookup_props);
/* Ignore ZWNJ if we are matching GSUB context, or matching GPOS. */
matcher.set_ignore_zwnj (context_match || c->table_index == 1);
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 (context_match || c->table_index == 1 || c->auto_zwj);
matcher.set_ignore_zwj (c->table_index == 1 || (context_match || c->auto_zwj));
matcher.set_mask (context_match ? -1 : c->lookup_mask);
}
inline void set_lookup_props (unsigned int lookup_props)
@ -457,45 +457,50 @@ struct hb_apply_context_t :
return ret;
}
unsigned int table_index; /* GSUB/GPOS */
skipping_iterator_t iter_input, iter_context;
hb_font_t *font;
hb_face_t *face;
hb_buffer_t *buffer;
recurse_func_t recurse_func;
const GDEF &gdef;
const VariationStore &var_store;
hb_direction_t direction;
hb_mask_t lookup_mask;
bool auto_zwj;
recurse_func_t recurse_func;
unsigned int nesting_level_left;
unsigned int lookup_props;
const GDEF &gdef;
bool has_glyph_classes;
const VariationStore &var_store;
skipping_iterator_t iter_input, iter_context;
unsigned int table_index; /* GSUB/GPOS */
unsigned int lookup_index;
unsigned int lookup_props;
unsigned int nesting_level_left;
unsigned int debug_depth;
bool auto_zwnj;
bool auto_zwj;
bool has_glyph_classes;
hb_apply_context_t (unsigned int table_index_,
hb_font_t *font_,
hb_buffer_t *buffer_) :
table_index (table_index_),
iter_input (), iter_context (),
font (font_), face (font->face), buffer (buffer_),
recurse_func (NULL),
gdef (*hb_ot_layout_from_face (face)->gdef),
var_store (gdef.get_var_store ()),
direction (buffer_->props.direction),
lookup_mask (1),
auto_zwj (true),
recurse_func (NULL),
nesting_level_left (HB_MAX_NESTING_LEVEL),
lookup_props (0),
gdef (*hb_ot_layout_from_face (face)->gdef),
has_glyph_classes (gdef.has_glyph_classes ()),
var_store (gdef.get_var_store ()),
iter_input (),
iter_context (),
table_index (table_index_),
lookup_index ((unsigned int) -1),
debug_depth (0) {}
lookup_props (0),
nesting_level_left (HB_MAX_NESTING_LEVEL),
debug_depth (0),
auto_zwnj (true),
auto_zwj (true),
has_glyph_classes (gdef.has_glyph_classes ()) {}
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_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_)
@ -886,7 +891,8 @@ static inline bool match_backtrack (hb_apply_context_t *c,
unsigned int count,
const USHORT backtrack[],
match_func_t match_func,
const void *match_data)
const void *match_data,
unsigned int *match_start)
{
TRACE_APPLY (NULL);
@ -898,6 +904,8 @@ static inline bool match_backtrack (hb_apply_context_t *c,
if (!skippy_iter.prev ())
return_trace (false);
*match_start = skippy_iter.idx;
return_trace (true);
}
@ -906,7 +914,8 @@ static inline bool match_lookahead (hb_apply_context_t *c,
const USHORT lookahead[],
match_func_t match_func,
const void *match_data,
unsigned int offset)
unsigned int offset,
unsigned int *end_index)
{
TRACE_APPLY (NULL);
@ -918,6 +927,8 @@ static inline bool match_lookahead (hb_apply_context_t *c,
if (!skippy_iter.next ())
return_trace (false);
*end_index = skippy_iter.idx + 1;
return_trace (true);
}
@ -996,7 +1007,29 @@ static inline bool apply_lookup (hb_apply_context_t *c,
if (!delta)
continue;
/* Recursed lookup changed buffer len. Adjust. */
/* Recursed lookup changed buffer len. Adjust.
*
* TODO:
*
* Right now, if buffer length increased by n, we assume n new glyphs
* were added right after the current position, and if buffer length
* was decreased by n, we assume n match positions after the current
* one where removed. The former (buffer length increased) case is
* fine, but the decrease case can be improved in at least two ways,
* both of which are significant:
*
* - If recursed-to lookup is MultipleSubst and buffer length
* decreased, then it's current match position that was deleted,
* NOT the one after it.
*
* - If buffer length was decreased by n, it does not necessarily
* mean that n match positions where removed, as there might
* have been marks and default-ignorables in the sequence. We
* should instead drop match positions between current-position
* and current-position + n instead.
*
* It should be possible to construct tests for both of these cases.
*/
end += delta;
if (end <= int (match_positions[idx]))
@ -1118,10 +1151,11 @@ static inline bool context_apply_lookup (hb_apply_context_t *c,
inputCount, input,
lookup_context.funcs.match, lookup_context.match_data,
&match_length, match_positions)
&& apply_lookup (c,
&& (c->buffer->unsafe_to_break (c->buffer->idx, c->buffer->idx + match_length),
apply_lookup (c,
inputCount, match_positions,
lookupCount, lookupRecord,
match_length);
match_length));
}
struct Rule
@ -1639,7 +1673,7 @@ static inline bool chain_context_apply_lookup (hb_apply_context_t *c,
const LookupRecord lookupRecord[],
ChainContextApplyLookupContext &lookup_context)
{
unsigned int match_length = 0;
unsigned int start_index = 0, match_length = 0, end_index = 0;
unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
return match_input (c,
inputCount, input,
@ -1647,15 +1681,17 @@ static inline bool chain_context_apply_lookup (hb_apply_context_t *c,
&match_length, match_positions)
&& match_backtrack (c,
backtrackCount, backtrack,
lookup_context.funcs.match, lookup_context.match_data[0])
lookup_context.funcs.match, lookup_context.match_data[0],
&start_index)
&& match_lookahead (c,
lookaheadCount, lookahead,
lookup_context.funcs.match, lookup_context.match_data[2],
match_length)
&& apply_lookup (c,
match_length, &end_index)
&& (c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index),
apply_lookup (c,
inputCount, match_positions,
lookupCount, lookupRecord,
match_length);
match_length));
}
struct ChainRule
@ -2313,7 +2349,7 @@ struct GSUBGPOS
featureList; /* FeatureList table */
OffsetTo<LookupList>
lookupList; /* LookupList table */
OffsetTo<FeatureVariations, ULONG>
LOffsetTo<FeatureVariations>
featureVars; /* Offset to Feature Variations
table--from beginning of table
* (may be NULL). Introduced

View file

@ -34,6 +34,7 @@
#include "hb-font-private.hh"
#include "hb-buffer-private.hh"
#include "hb-set-private.hh"
#include "hb-open-type-private.hh"
/* Private API corresponding to hb-ot-layout.h: */
@ -125,6 +126,8 @@ namespace OT {
struct GSUB;
struct GPOS;
struct MATH;
struct fvar;
struct avar;
}
struct hb_ot_layout_lookup_accelerator_t
@ -153,12 +156,15 @@ struct hb_ot_layout_t
hb_blob_t *gdef_blob;
hb_blob_t *gsub_blob;
hb_blob_t *gpos_blob;
hb_blob_t *math_blob;
const struct OT::GDEF *gdef;
const struct OT::GSUB *gsub;
const struct OT::GPOS *gpos;
const struct OT::MATH *math;
/* TODO Move the following out of this struct. */
OT::hb_lazy_table_loader_t<struct OT::MATH> math;
OT::hb_lazy_table_loader_t<struct OT::fvar> fvar;
OT::hb_lazy_table_loader_t<struct OT::avar> avar;
unsigned int gsub_lookup_count;
unsigned int gpos_lookup_count;
@ -191,8 +197,7 @@ _hb_ot_layout_destroy (hb_ot_layout_t *layout);
#define syllable() var1.u8[3] /* GSUB/GPOS shaping boundaries */
/* loop over syllables */
/* Loop over syllables. Based on foreach_cluster(). */
#define foreach_syllable(buffer, start, end) \
for (unsigned int \
_count = buffer->len, \
@ -234,7 +239,8 @@ _next_syllable (hb_buffer_t *buffer, unsigned int start)
enum hb_unicode_props_flags_t {
UPROPS_MASK_GEN_CAT = 0x001Fu,
UPROPS_MASK_IGNORABLE = 0x0020u,
UPROPS_MASK_FVS = 0x0040u, /* MONGOLIAN FREE VARIATION SELECTOR 1..3 */
UPROPS_MASK_HIDDEN = 0x0040u, /* MONGOLIAN FREE VARIATION SELECTOR 1..3,
* or TAG characters */
/* If GEN_CAT=FORMAT, top byte masks: */
UPROPS_MASK_Cf_ZWJ = 0x0100u,
@ -267,7 +273,11 @@ _hb_glyph_info_set_unicode_props (hb_glyph_info_t *info, hb_buffer_t *buffer)
* Fixes:
* https://github.com/behdad/harfbuzz/issues/234
*/
if (unlikely (hb_in_range (u, 0x180Bu, 0x180Du))) props |= UPROPS_MASK_FVS;
if (unlikely (hb_in_range (u, 0x180Bu, 0x180Du))) props |= UPROPS_MASK_HIDDEN;
/* TAG characters need similar treatment. Fixes:
* https://github.com/behdad/harfbuzz/issues/463
*/
if (unlikely (hb_in_range (u, 0xE0020u, 0xE007Fu))) props |= UPROPS_MASK_HIDDEN;
}
else if (unlikely (HB_UNICODE_GENERAL_CATEGORY_IS_NON_ENCLOSING_MARK_OR_MODIFIER_SYMBOL (gen_cat)))
{
@ -367,9 +377,9 @@ _hb_glyph_info_is_default_ignorable (const hb_glyph_info_t *info)
!_hb_glyph_info_ligated (info);
}
static inline hb_bool_t
_hb_glyph_info_is_default_ignorable_and_not_fvs (const hb_glyph_info_t *info)
_hb_glyph_info_is_default_ignorable_and_not_hidden (const hb_glyph_info_t *info)
{
return ((info->unicode_props() & (UPROPS_MASK_IGNORABLE|UPROPS_MASK_FVS))
return ((info->unicode_props() & (UPROPS_MASK_IGNORABLE|UPROPS_MASK_HIDDEN))
== UPROPS_MASK_IGNORABLE) &&
!_hb_glyph_info_ligated (info);
}
@ -617,5 +627,4 @@ _hb_buffer_assert_gsubgpos_vars (hb_buffer_t *buffer)
#undef lig_props
#undef glyph_props
#endif /* HB_OT_LAYOUT_PRIVATE_HH */

View file

@ -34,15 +34,10 @@
#include "hb-ot-layout-gdef-table.hh"
#include "hb-ot-layout-gsub-table.hh"
#include "hb-ot-layout-gpos-table.hh"
#include "hb-ot-layout-jstf-table.hh"
#include "hb-ot-layout-jstf-table.hh" // Just so we compile it; unused otherwise.
#include "hb-ot-map-private.hh"
#include <stdlib.h>
#include <string.h>
HB_SHAPER_DATA_ENSURE_DECLARE(ot, face)
hb_ot_layout_t *
_hb_ot_layout_create (hb_face_t *face)
@ -60,9 +55,9 @@ _hb_ot_layout_create (hb_face_t *face)
layout->gpos_blob = OT::Sanitizer<OT::GPOS>::sanitize (face->reference_table (HB_OT_TAG_GPOS));
layout->gpos = OT::Sanitizer<OT::GPOS>::lock_instance (layout->gpos_blob);
/* The MATH table is rarely used, so only try and load it in _get_math. */
layout->math_blob = NULL;
layout->math = NULL;
layout->math.init (face);
layout->fvar.init (face);
layout->avar.init (face);
{
/*
@ -106,10 +101,18 @@ _hb_ot_layout_create (hb_face_t *face)
|| (928 == gdef_len && 59332 == gpos_len && 23298 == gsub_len)
/* sha1sum:6d400781948517c3c0441ba42acb309584b73033 tahomabd.ttf from Windows 8.1 */
|| (940 == gdef_len && 60732 == gpos_len && 23310 == gsub_len)
/* tahoma.ttf v6.04 from Windows 8.1 x64, see https://bugzilla.mozilla.org/show_bug.cgi?id=1279925 */
|| (964 == gdef_len && 60072 == gpos_len && 23836 == gsub_len)
/* tahomabd.ttf v6.04 from Windows 8.1 x64, see https://bugzilla.mozilla.org/show_bug.cgi?id=1279925 */
|| (976 == gdef_len && 61456 == gpos_len && 23832 == gsub_len)
/* sha1sum:e55fa2dfe957a9f7ec26be516a0e30b0c925f846 tahoma.ttf from Windows 10 */
|| (994 == gdef_len && 60336 == gpos_len && 24474 == gsub_len)
/* sha1sum:7199385abb4c2cc81c83a151a7599b6368e92343 tahomabd.ttf from Windows 10 */
|| (1006 == gdef_len && 61740 == gpos_len && 24470 == gsub_len)
/* tahoma.ttf v6.91 from Windows 10 x64, see https://bugzilla.mozilla.org/show_bug.cgi?id=1279925 */
|| (1006 == gdef_len && 61346 == gpos_len && 24576 == gsub_len)
/* tahomabd.ttf v6.91 from Windows 10 x64, see https://bugzilla.mozilla.org/show_bug.cgi?id=1279925 */
|| (1018 == gdef_len && 62828 == gpos_len && 24572 == gsub_len)
/* sha1sum:b9c84d820c49850d3d27ec498be93955b82772b5 tahoma.ttf from Windows 10 AU */
|| (1006 == gdef_len && 61352 == gpos_len && 24576 == gsub_len)
/* sha1sum:2bdfaab28174bdadd2f3d4200a30a7ae31db79d2 tahomabd.ttf from Windows 10 AU */
@ -130,6 +133,14 @@ _hb_ot_layout_create (hb_face_t *face)
/* 2c0c90c6f6087ffbfea76589c93113a9cbb0e75f cantarell-fonts-0.0.21/otf/Cantarell-Bold.otf */
/* 55461f5b853c6da88069ffcdf7f4dd3f8d7e3e6b cantarell-fonts-0.0.21/otf/Cantarell-Bold-Oblique.otf */
|| (188 == gdef_len && 3426 == gpos_len && 264 == gsub_len)
/* d125afa82a77a6475ac0e74e7c207914af84b37a padauk-2.80/Padauk.ttf RHEL 7.2 */
|| (1058 == gdef_len && 11818 == gpos_len && 47032 == gsub_len)
/* 0f7b80437227b90a577cc078c0216160ae61b031 padauk-2.80/Padauk-Bold.ttf RHEL 7.2*/
|| (1046 == gdef_len && 12600 == gpos_len && 47030 == gsub_len)
/* d3dde9aa0a6b7f8f6a89ef1002e9aaa11b882290 padauk-2.80/Padauk.ttf Ubuntu 16.04 */
|| (1058 == gdef_len && 16770 == gpos_len && 71796 == gsub_len)
/* 5f3c98ccccae8a953be2d122c1b3a77fd805093f padauk-2.80/Padauk-Bold.ttf Ubuntu 16.04 */
|| (1046 == gdef_len && 17862 == gpos_len && 71790 == gsub_len)
/* 6c93b63b64e8b2c93f5e824e78caca555dc887c7 padauk-2.80/Padauk-book.ttf */
|| (1046 == gdef_len && 17112 == gpos_len && 71788 == gsub_len)
/* d89b1664058359b8ec82e35d3531931125991fb9 padauk-2.80/Padauk-bookbold.ttf */
@ -138,6 +149,9 @@ _hb_ot_layout_create (hb_face_t *face)
|| (1330 == gdef_len && 57938 == gpos_len && 109904 == gsub_len)
/* 91fcc10cf15e012d27571e075b3b4dfe31754a8a padauk-3.0/Padauk-bookbold.ttf */
|| (1330 == gdef_len && 58972 == gpos_len && 109904 == gsub_len)
/* sha1sum: c26e41d567ed821bed997e937bc0c41435689e85 Padauk.ttf
* "Padauk Regular" "Version 2.5", see https://crbug.com/681813 */
|| (1004 == gdef_len && 14836 == gpos_len && 59092 == gsub_len)
)
{
/* Many versions of Tahoma have bad GDEF tables that incorrectly classify some spacing marks
@ -187,7 +201,10 @@ _hb_ot_layout_destroy (hb_ot_layout_t *layout)
hb_blob_destroy (layout->gdef_blob);
hb_blob_destroy (layout->gsub_blob);
hb_blob_destroy (layout->gpos_blob);
hb_blob_destroy (layout->math_blob);
layout->math.fini ();
layout->fvar.fini ();
layout->avar.fini ();
free (layout);
}
@ -262,7 +279,7 @@ hb_ot_layout_get_ligature_carets (hb_font_t *font,
hb_codepoint_t glyph,
unsigned int start_offset,
unsigned int *caret_count /* IN/OUT */,
int *caret_array /* OUT */)
hb_position_t *caret_array /* OUT */)
{
return _get_gdef (font->face).get_lig_carets (font, direction, glyph, start_offset, caret_count, caret_array);
}
@ -1202,6 +1219,7 @@ inline void hb_ot_map_t::apply (const Proxy &proxy,
c.set_lookup_index (lookup_index);
c.set_lookup_mask (lookups[table_index][i].mask);
c.set_auto_zwj (lookups[table_index][i].auto_zwj);
c.set_auto_zwnj (lookups[table_index][i].auto_zwnj);
apply_string<Proxy> (&c,
proxy.table.get_lookup (lookup_index),
proxy.accels[lookup_index]);

View file

@ -50,6 +50,7 @@ struct hb_ot_map_t
hb_mask_t mask;
hb_mask_t _1_mask; /* mask for value=1, for quick access */
unsigned int needs_fallback : 1;
unsigned int auto_zwnj : 1;
unsigned int auto_zwj : 1;
static int cmp (const feature_map_t *a, const feature_map_t *b)
@ -58,6 +59,7 @@ struct hb_ot_map_t
struct lookup_map_t {
unsigned short index;
unsigned short auto_zwnj : 1;
unsigned short auto_zwj : 1;
hb_mask_t mask;
@ -113,7 +115,7 @@ struct hb_ot_map_t
assert (stage <= stages[table_index].len);
unsigned int start = stage ? stages[table_index][stage - 1].last_lookup : 0;
unsigned int end = stage < stages[table_index].len ? stages[table_index][stage].last_lookup : lookups[table_index].len;
*plookups = &lookups[table_index][start];
*plookups = end == start ? NULL : &lookups[table_index][start];
*lookup_count = end - start;
}
@ -150,8 +152,9 @@ enum hb_ot_map_feature_flags_t {
F_NONE = 0x0000u,
F_GLOBAL = 0x0001u, /* Feature applies to all characters; results in no mask allocated for it. */
F_HAS_FALLBACK = 0x0002u, /* Has fallback implementation, so include mask bit even if feature not found. */
F_MANUAL_ZWJ = 0x0004u, /* Don't skip over ZWJ when matching. */
F_GLOBAL_SEARCH = 0x0008u /* If feature not found in LangSys, look for it in global feature list and pick one. */
F_MANUAL_ZWNJ = 0x0004u, /* Don't skip over ZWNJ when matching **context**. */
F_MANUAL_ZWJ = 0x0008u, /* Don't skip over ZWJ when matching **input**. */
F_GLOBAL_SEARCH = 0x0010u /* If feature not found in LangSys, look for it in global feature list and pick one. */
};
HB_MARK_AS_FLAG_T (hb_ot_map_feature_flags_t);
/* Macro version for where const is desired. */
@ -196,7 +199,8 @@ struct hb_ot_map_builder_t
unsigned int feature_index,
unsigned int variations_index,
hb_mask_t mask,
bool auto_zwj);
bool auto_zwnj = true,
bool auto_zwj = true);
struct feature_info_t {
hb_tag_t tag;

View file

@ -85,6 +85,7 @@ hb_ot_map_builder_t::add_lookups (hb_ot_map_t &m,
unsigned int feature_index,
unsigned int variations_index,
hb_mask_t mask,
bool auto_zwnj,
bool auto_zwj)
{
unsigned int lookup_indices[32];
@ -112,6 +113,7 @@ hb_ot_map_builder_t::add_lookups (hb_ot_map_t &m,
return;
lookup->mask = mask;
lookup->index = lookup_indices[i];
lookup->auto_zwnj = auto_zwnj;
lookup->auto_zwj = auto_zwj;
}
@ -136,7 +138,11 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m,
const int *coords,
unsigned int num_coords)
{
m.global_mask = 1;
ASSERT_STATIC (!(HB_GLYPH_FLAG_DEFINED & (HB_GLYPH_FLAG_DEFINED + 1)));
unsigned int global_bit_mask = HB_GLYPH_FLAG_DEFINED + 1;
unsigned int global_bit_shift = _hb_popcount32 (HB_GLYPH_FLAG_DEFINED);
m.global_mask = global_bit_mask;
unsigned int required_feature_index[2];
hb_tag_t required_feature_tag[2];
@ -188,7 +194,8 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m,
/* Allocate bits now */
unsigned int next_bit = 1;
unsigned int next_bit = global_bit_shift + 1;
for (unsigned int i = 0; i < feature_infos.len; i++)
{
const feature_info_t *info = &feature_infos[i];
@ -243,11 +250,12 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m,
map->index[1] = feature_index[1];
map->stage[0] = info->stage[0];
map->stage[1] = info->stage[1];
map->auto_zwnj = !(info->flags & F_MANUAL_ZWNJ);
map->auto_zwj = !(info->flags & F_MANUAL_ZWJ);
if ((info->flags & F_GLOBAL) && info->max_value == 1) {
/* Uses the global bit */
map->shift = 0;
map->mask = 1;
map->shift = global_bit_shift;
map->mask = global_bit_mask;
} else {
map->shift = next_bit;
map->mask = (1u << (next_bit + bits_needed)) - (1u << next_bit);
@ -284,8 +292,7 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m,
add_lookups (m, face, table_index,
required_feature_index[table_index],
variations_index,
1 /* mask */,
true /* auto_zwj */);
global_bit_mask);
for (unsigned i = 0; i < m.features.len; i++)
if (m.features[i].stage[table_index] == stage)
@ -293,6 +300,7 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m,
m.features[i].index[table_index],
variations_index,
m.features[i].mask,
m.features[i].auto_zwnj,
m.features[i].auto_zwj);
/* Sort lookups and merge duplicates */
@ -307,6 +315,7 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m,
else
{
m.lookups[table_index][j].mask |= m.lookups[table_index][i].mask;
m.lookups[table_index][j].auto_zwnj &= m.lookups[table_index][i].auto_zwnj;
m.lookups[table_index][j].auto_zwj &= m.lookups[table_index][i].auto_zwj;
}
m.lookups[table_index].shrink (j + 1);

View file

@ -0,0 +1,722 @@
/*
* Copyright © 2016 Igalia S.L.
*
* 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.
*
* Igalia Author(s): Frédéric Wang
*/
#ifndef HB_OT_MATH_TABLE_HH
#define HB_OT_MATH_TABLE_HH
#include "hb-open-type-private.hh"
#include "hb-ot-layout-common-private.hh"
#include "hb-ot-math.h"
namespace OT {
struct MathValueRecord
{
inline hb_position_t get_x_value (hb_font_t *font, const void *base) const
{ return font->em_scale_x (value) + (base+deviceTable).get_x_delta (font); }
inline hb_position_t get_y_value (hb_font_t *font, const void *base) const
{ return font->em_scale_y (value) + (base+deviceTable).get_y_delta (font); }
inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && deviceTable.sanitize (c, base));
}
protected:
SHORT value; /* The X or Y value in design units */
OffsetTo<Device> deviceTable; /* Offset to the device table - from the
* beginning of parent table. May be NULL.
* Suggested format for device table is 1. */
public:
DEFINE_SIZE_STATIC (4);
};
struct MathConstants
{
inline bool sanitize_math_value_records (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
unsigned int count = ARRAY_LENGTH (mathValueRecords);
for (unsigned int i = 0; i < count; i++)
if (!mathValueRecords[i].sanitize (c, this))
return_trace (false);
return_trace (true);
}
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && sanitize_math_value_records(c));
}
inline hb_position_t get_value (hb_ot_math_constant_t constant,
hb_font_t *font) const
{
switch (constant) {
case HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN:
case HB_OT_MATH_CONSTANT_SCRIPT_SCRIPT_PERCENT_SCALE_DOWN:
return percentScaleDown[constant - HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN];
case HB_OT_MATH_CONSTANT_DELIMITED_SUB_FORMULA_MIN_HEIGHT:
case HB_OT_MATH_CONSTANT_DISPLAY_OPERATOR_MIN_HEIGHT:
return font->em_scale_y (minHeight[constant - HB_OT_MATH_CONSTANT_DELIMITED_SUB_FORMULA_MIN_HEIGHT]);
case HB_OT_MATH_CONSTANT_RADICAL_KERN_AFTER_DEGREE:
case HB_OT_MATH_CONSTANT_RADICAL_KERN_BEFORE_DEGREE:
case HB_OT_MATH_CONSTANT_SKEWED_FRACTION_HORIZONTAL_GAP:
case HB_OT_MATH_CONSTANT_SPACE_AFTER_SCRIPT:
return mathValueRecords[constant - HB_OT_MATH_CONSTANT_MATH_LEADING].get_x_value(font, this);
case HB_OT_MATH_CONSTANT_ACCENT_BASE_HEIGHT:
case HB_OT_MATH_CONSTANT_AXIS_HEIGHT:
case HB_OT_MATH_CONSTANT_FLATTENED_ACCENT_BASE_HEIGHT:
case HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_DISPLAY_STYLE_SHIFT_DOWN:
case HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_GAP_MIN:
case HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_SHIFT_DOWN:
case HB_OT_MATH_CONSTANT_FRACTION_DENOM_DISPLAY_STYLE_GAP_MIN:
case HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_DISPLAY_STYLE_SHIFT_UP:
case HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_GAP_MIN:
case HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_SHIFT_UP:
case HB_OT_MATH_CONSTANT_FRACTION_NUM_DISPLAY_STYLE_GAP_MIN:
case HB_OT_MATH_CONSTANT_FRACTION_RULE_THICKNESS:
case HB_OT_MATH_CONSTANT_LOWER_LIMIT_BASELINE_DROP_MIN:
case HB_OT_MATH_CONSTANT_LOWER_LIMIT_GAP_MIN:
case HB_OT_MATH_CONSTANT_MATH_LEADING:
case HB_OT_MATH_CONSTANT_OVERBAR_EXTRA_ASCENDER:
case HB_OT_MATH_CONSTANT_OVERBAR_RULE_THICKNESS:
case HB_OT_MATH_CONSTANT_OVERBAR_VERTICAL_GAP:
case HB_OT_MATH_CONSTANT_RADICAL_DISPLAY_STYLE_VERTICAL_GAP:
case HB_OT_MATH_CONSTANT_RADICAL_EXTRA_ASCENDER:
case HB_OT_MATH_CONSTANT_RADICAL_RULE_THICKNESS:
case HB_OT_MATH_CONSTANT_RADICAL_VERTICAL_GAP:
case HB_OT_MATH_CONSTANT_SKEWED_FRACTION_VERTICAL_GAP:
case HB_OT_MATH_CONSTANT_STACK_BOTTOM_DISPLAY_STYLE_SHIFT_DOWN:
case HB_OT_MATH_CONSTANT_STACK_BOTTOM_SHIFT_DOWN:
case HB_OT_MATH_CONSTANT_STACK_DISPLAY_STYLE_GAP_MIN:
case HB_OT_MATH_CONSTANT_STACK_GAP_MIN:
case HB_OT_MATH_CONSTANT_STACK_TOP_DISPLAY_STYLE_SHIFT_UP:
case HB_OT_MATH_CONSTANT_STACK_TOP_SHIFT_UP:
case HB_OT_MATH_CONSTANT_STRETCH_STACK_BOTTOM_SHIFT_DOWN:
case HB_OT_MATH_CONSTANT_STRETCH_STACK_GAP_ABOVE_MIN:
case HB_OT_MATH_CONSTANT_STRETCH_STACK_GAP_BELOW_MIN:
case HB_OT_MATH_CONSTANT_STRETCH_STACK_TOP_SHIFT_UP:
case HB_OT_MATH_CONSTANT_SUBSCRIPT_BASELINE_DROP_MIN:
case HB_OT_MATH_CONSTANT_SUBSCRIPT_SHIFT_DOWN:
case HB_OT_MATH_CONSTANT_SUBSCRIPT_TOP_MAX:
case HB_OT_MATH_CONSTANT_SUB_SUPERSCRIPT_GAP_MIN:
case HB_OT_MATH_CONSTANT_SUPERSCRIPT_BASELINE_DROP_MAX:
case HB_OT_MATH_CONSTANT_SUPERSCRIPT_BOTTOM_MAX_WITH_SUBSCRIPT:
case HB_OT_MATH_CONSTANT_SUPERSCRIPT_BOTTOM_MIN:
case HB_OT_MATH_CONSTANT_SUPERSCRIPT_SHIFT_UP:
case HB_OT_MATH_CONSTANT_SUPERSCRIPT_SHIFT_UP_CRAMPED:
case HB_OT_MATH_CONSTANT_UNDERBAR_EXTRA_DESCENDER:
case HB_OT_MATH_CONSTANT_UNDERBAR_RULE_THICKNESS:
case HB_OT_MATH_CONSTANT_UNDERBAR_VERTICAL_GAP:
case HB_OT_MATH_CONSTANT_UPPER_LIMIT_BASELINE_RISE_MIN:
case HB_OT_MATH_CONSTANT_UPPER_LIMIT_GAP_MIN:
return mathValueRecords[constant - HB_OT_MATH_CONSTANT_MATH_LEADING].get_y_value(font, this);
case HB_OT_MATH_CONSTANT_RADICAL_DEGREE_BOTTOM_RAISE_PERCENT:
return radicalDegreeBottomRaisePercent;
default:
return 0;
}
}
protected:
SHORT percentScaleDown[2];
USHORT minHeight[2];
MathValueRecord mathValueRecords[51];
SHORT radicalDegreeBottomRaisePercent;
public:
DEFINE_SIZE_STATIC (214);
};
struct MathItalicsCorrectionInfo
{
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
coverage.sanitize (c, this) &&
italicsCorrection.sanitize (c, this));
}
inline hb_position_t get_value (hb_codepoint_t glyph,
hb_font_t *font) const
{
unsigned int index = (this+coverage).get_coverage (glyph);
return italicsCorrection[index].get_x_value (font, this);
}
protected:
OffsetTo<Coverage> coverage; /* Offset to Coverage table -
* from the beginning of
* MathItalicsCorrectionInfo
* table. */
ArrayOf<MathValueRecord> italicsCorrection; /* Array of MathValueRecords
* defining italics correction
* values for each
* covered glyph. */
public:
DEFINE_SIZE_ARRAY (4, italicsCorrection);
};
struct MathTopAccentAttachment
{
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
topAccentCoverage.sanitize (c, this) &&
topAccentAttachment.sanitize (c, this));
}
inline hb_position_t get_value (hb_codepoint_t glyph,
hb_font_t *font) const
{
unsigned int index = (this+topAccentCoverage).get_coverage (glyph);
if (index == NOT_COVERED)
return font->get_glyph_h_advance (glyph) / 2;
return topAccentAttachment[index].get_x_value(font, this);
}
protected:
OffsetTo<Coverage> topAccentCoverage; /* Offset to Coverage table -
* from the beginning of
* MathTopAccentAttachment
* table. */
ArrayOf<MathValueRecord> topAccentAttachment; /* Array of MathValueRecords
* defining top accent
* attachment points for each
* covered glyph. */
public:
DEFINE_SIZE_ARRAY (2 + 2, topAccentAttachment);
};
struct MathKern
{
inline bool sanitize_math_value_records (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
unsigned int count = 2 * heightCount + 1;
for (unsigned int i = 0; i < count; i++)
if (!mathValueRecords[i].sanitize (c, this)) return_trace (false);
return_trace (true);
}
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
c->check_array (mathValueRecords,
mathValueRecords[0].static_size,
2 * heightCount + 1) &&
sanitize_math_value_records (c));
}
inline hb_position_t get_value (hb_position_t correction_height, hb_font_t *font) const
{
const MathValueRecord* correctionHeight = mathValueRecords;
const MathValueRecord* kernValue = mathValueRecords + heightCount;
int sign = font->y_scale < 0 ? -1 : +1;
/* The description of the MathKern table is a ambiguous, but interpreting
* "between the two heights found at those indexes" for 0 < i < len as
*
* correctionHeight[i-1] < correction_height <= correctionHeight[i]
*
* makes the result consistent with the limit cases and we can just use the
* binary search algorithm of std::upper_bound:
*/
unsigned int i = 0;
unsigned int count = heightCount;
while (count > 0)
{
unsigned int half = count / 2;
hb_position_t height = correctionHeight[i + half].get_y_value(font, this);
if (sign * height < sign * correction_height)
{
i += half + 1;
count -= half + 1;
} else
count = half;
}
return kernValue[i].get_x_value(font, this);
}
protected:
USHORT heightCount;
MathValueRecord mathValueRecords[VAR]; /* Array of correction heights at
* which the kern value changes.
* Sorted by the height value in
* design units (heightCount entries),
* Followed by:
* Array of kern values corresponding
* to heights. (heightCount+1 entries).
*/
public:
DEFINE_SIZE_ARRAY (2, mathValueRecords);
};
struct MathKernInfoRecord
{
inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE (this);
unsigned int count = ARRAY_LENGTH (mathKern);
for (unsigned int i = 0; i < count; i++)
if (unlikely (!mathKern[i].sanitize (c, base)))
return_trace (false);
return_trace (true);
}
inline hb_position_t get_kerning (hb_ot_math_kern_t kern,
hb_position_t correction_height,
hb_font_t *font,
const void *base) const
{
unsigned int idx = kern;
if (unlikely (idx >= ARRAY_LENGTH (mathKern))) return 0;
return (base+mathKern[idx]).get_value (correction_height, font);
}
protected:
/* Offset to MathKern table for each corner -
* from the beginning of MathKernInfo table. May be NULL. */
OffsetTo<MathKern> mathKern[4];
public:
DEFINE_SIZE_STATIC (8);
};
struct MathKernInfo
{
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
mathKernCoverage.sanitize (c, this) &&
mathKernInfoRecords.sanitize (c, this));
}
inline hb_position_t get_kerning (hb_codepoint_t glyph,
hb_ot_math_kern_t kern,
hb_position_t correction_height,
hb_font_t *font) const
{
unsigned int index = (this+mathKernCoverage).get_coverage (glyph);
return mathKernInfoRecords[index].get_kerning (kern, correction_height, font, this);
}
protected:
OffsetTo<Coverage> mathKernCoverage; /* Offset to Coverage table -
* from the beginning of the
* MathKernInfo table. */
ArrayOf<MathKernInfoRecord> mathKernInfoRecords; /* Array of
* MathKernInfoRecords,
* per-glyph information for
* mathematical positioning
* of subscripts and
* superscripts. */
public:
DEFINE_SIZE_ARRAY (4, mathKernInfoRecords);
};
struct MathGlyphInfo
{
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
mathItalicsCorrectionInfo.sanitize (c, this) &&
mathTopAccentAttachment.sanitize (c, this) &&
extendedShapeCoverage.sanitize (c, this) &&
mathKernInfo.sanitize(c, this));
}
inline hb_position_t
get_italics_correction (hb_codepoint_t glyph, hb_font_t *font) const
{ return (this+mathItalicsCorrectionInfo).get_value (glyph, font); }
inline hb_position_t
get_top_accent_attachment (hb_codepoint_t glyph, hb_font_t *font) const
{ return (this+mathTopAccentAttachment).get_value (glyph, font); }
inline bool is_extended_shape (hb_codepoint_t glyph) const
{ return (this+extendedShapeCoverage).get_coverage (glyph) != NOT_COVERED; }
inline hb_position_t get_kerning (hb_codepoint_t glyph,
hb_ot_math_kern_t kern,
hb_position_t correction_height,
hb_font_t *font) const
{ return (this+mathKernInfo).get_kerning (glyph, kern, correction_height, font); }
protected:
/* Offset to MathItalicsCorrectionInfo table -
* from the beginning of MathGlyphInfo table. */
OffsetTo<MathItalicsCorrectionInfo> mathItalicsCorrectionInfo;
/* Offset to MathTopAccentAttachment table -
* from the beginning of MathGlyphInfo table. */
OffsetTo<MathTopAccentAttachment> mathTopAccentAttachment;
/* Offset to coverage table for Extended Shape glyphs -
* from the beginning of MathGlyphInfo table. When the left or right glyph of
* a box is an extended shape variant, the (ink) box (and not the default
* position defined by values in MathConstants table) should be used for
* vertical positioning purposes. May be NULL.. */
OffsetTo<Coverage> extendedShapeCoverage;
/* Offset to MathKernInfo table -
* from the beginning of MathGlyphInfo table. */
OffsetTo<MathKernInfo> mathKernInfo;
public:
DEFINE_SIZE_STATIC (8);
};
struct MathGlyphVariantRecord
{
friend struct MathGlyphConstruction;
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this));
}
protected:
GlyphID variantGlyph; /* Glyph ID for the variant. */
USHORT advanceMeasurement; /* Advance width/height, in design units, of the
* variant, in the direction of requested
* glyph extension. */
public:
DEFINE_SIZE_STATIC (4);
};
struct PartFlags : USHORT
{
enum Flags {
Extender = 0x0001u, /* If set, the part can be skipped or repeated. */
Defined = 0x0001u, /* All defined flags. */
};
public:
DEFINE_SIZE_STATIC (2);
};
struct MathGlyphPartRecord
{
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this));
}
inline void extract (hb_ot_math_glyph_part_t &out,
int scale,
hb_font_t *font) const
{
out.glyph = glyph;
out.start_connector_length = font->em_scale (startConnectorLength, scale);
out.end_connector_length = font->em_scale (endConnectorLength, scale);
out.full_advance = font->em_scale (fullAdvance, scale);
ASSERT_STATIC ((unsigned int) HB_MATH_GLYPH_PART_FLAG_EXTENDER ==
(unsigned int) PartFlags::Extender);
out.flags = (hb_ot_math_glyph_part_flags_t)
(unsigned int)
(partFlags & PartFlags::Defined);
}
protected:
GlyphID glyph; /* Glyph ID for the part. */
USHORT startConnectorLength; /* Advance width/ height of the straight bar
* connector material, in design units, is at
* the beginning of the glyph, in the
* direction of the extension. */
USHORT endConnectorLength; /* Advance width/ height of the straight bar
* connector material, in design units, is at
* the end of the glyph, in the direction of
* the extension. */
USHORT fullAdvance; /* Full advance width/height for this part,
* in the direction of the extension.
* In design units. */
PartFlags partFlags; /* Part qualifiers. */
public:
DEFINE_SIZE_STATIC (10);
};
struct MathGlyphAssembly
{
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
italicsCorrection.sanitize(c, this) &&
partRecords.sanitize(c));
}
inline unsigned int get_parts (hb_direction_t direction,
hb_font_t *font,
unsigned int start_offset,
unsigned int *parts_count, /* IN/OUT */
hb_ot_math_glyph_part_t *parts /* OUT */,
hb_position_t *italics_correction /* OUT */) const
{
if (parts_count)
{
int scale = font->dir_scale (direction);
const MathGlyphPartRecord *arr =
partRecords.sub_array (start_offset, parts_count);
unsigned int count = *parts_count;
for (unsigned int i = 0; i < count; i++)
arr[i].extract (parts[i], scale, font);
}
if (italics_correction)
*italics_correction = italicsCorrection.get_x_value (font, this);
return partRecords.len;
}
protected:
MathValueRecord italicsCorrection; /* Italics correction of this
* MathGlyphAssembly. Should not
* depend on the assembly size. */
ArrayOf<MathGlyphPartRecord> partRecords; /* Array of part records, from
* left to right and bottom to
* top. */
public:
DEFINE_SIZE_ARRAY (6, partRecords);
};
struct MathGlyphConstruction
{
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
glyphAssembly.sanitize(c, this) &&
mathGlyphVariantRecord.sanitize(c));
}
inline const MathGlyphAssembly &get_assembly (void) const
{ return this+glyphAssembly; }
inline unsigned int get_variants (hb_direction_t direction,
hb_font_t *font,
unsigned int start_offset,
unsigned int *variants_count, /* IN/OUT */
hb_ot_math_glyph_variant_t *variants /* OUT */) const
{
if (variants_count)
{
int scale = font->dir_scale (direction);
const MathGlyphVariantRecord *arr =
mathGlyphVariantRecord.sub_array (start_offset, variants_count);
unsigned int count = *variants_count;
for (unsigned int i = 0; i < count; i++)
{
variants[i].glyph = arr[i].variantGlyph;
variants[i].advance = font->em_scale (arr[i].advanceMeasurement, scale);
}
}
return mathGlyphVariantRecord.len;
}
protected:
/* Offset to MathGlyphAssembly table for this shape - from the beginning of
MathGlyphConstruction table. May be NULL. */
OffsetTo<MathGlyphAssembly> glyphAssembly;
/* MathGlyphVariantRecords for alternative variants of the glyphs. */
ArrayOf<MathGlyphVariantRecord> mathGlyphVariantRecord;
public:
DEFINE_SIZE_ARRAY (4, mathGlyphVariantRecord);
};
struct MathVariants
{
inline bool sanitize_offsets (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
unsigned int count = vertGlyphCount + horizGlyphCount;
for (unsigned int i = 0; i < count; i++)
if (!glyphConstruction[i].sanitize (c, this)) return_trace (false);
return_trace (true);
}
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
vertGlyphCoverage.sanitize (c, this) &&
horizGlyphCoverage.sanitize (c, this) &&
c->check_array (glyphConstruction,
glyphConstruction[0].static_size,
vertGlyphCount + horizGlyphCount) &&
sanitize_offsets (c));
}
inline hb_position_t get_min_connector_overlap (hb_direction_t direction,
hb_font_t *font) const
{ return font->em_scale_dir (minConnectorOverlap, direction); }
inline unsigned int get_glyph_variants (hb_codepoint_t glyph,
hb_direction_t direction,
hb_font_t *font,
unsigned int start_offset,
unsigned int *variants_count, /* IN/OUT */
hb_ot_math_glyph_variant_t *variants /* OUT */) const
{ return get_glyph_construction (glyph, direction, font)
.get_variants (direction, font, start_offset, variants_count, variants); }
inline unsigned int get_glyph_parts (hb_codepoint_t glyph,
hb_direction_t direction,
hb_font_t *font,
unsigned int start_offset,
unsigned int *parts_count, /* IN/OUT */
hb_ot_math_glyph_part_t *parts /* OUT */,
hb_position_t *italics_correction /* OUT */) const
{ return get_glyph_construction (glyph, direction, font)
.get_assembly ()
.get_parts (direction, font,
start_offset, parts_count, parts,
italics_correction); }
private:
inline const MathGlyphConstruction &
get_glyph_construction (hb_codepoint_t glyph,
hb_direction_t direction,
hb_font_t *font) const
{
bool vertical = HB_DIRECTION_IS_VERTICAL (direction);
unsigned int count = vertical ? vertGlyphCount : horizGlyphCount;
const OffsetTo<Coverage> &coverage = vertical ? vertGlyphCoverage
: horizGlyphCoverage;
unsigned int index = (this+coverage).get_coverage (glyph);
if (unlikely (index >= count)) return Null(MathGlyphConstruction);
if (!vertical)
index += vertGlyphCount;
return this+glyphConstruction[index];
}
protected:
USHORT minConnectorOverlap; /* Minimum overlap of connecting
* glyphs during glyph construction,
* in design units. */
OffsetTo<Coverage> vertGlyphCoverage; /* Offset to Coverage table -
* from the beginning of MathVariants
* table. */
OffsetTo<Coverage> horizGlyphCoverage; /* Offset to Coverage table -
* from the beginning of MathVariants
* table. */
USHORT vertGlyphCount; /* Number of glyphs for which
* information is provided for
* vertically growing variants. */
USHORT horizGlyphCount; /* Number of glyphs for which
* information is provided for
* horizontally growing variants. */
/* Array of offsets to MathGlyphConstruction tables - from the beginning of
the MathVariants table, for shapes growing in vertical/horizontal
direction. */
OffsetTo<MathGlyphConstruction> glyphConstruction[VAR];
public:
DEFINE_SIZE_ARRAY (10, glyphConstruction);
};
/*
* MATH -- The MATH Table
*/
struct MATH
{
static const hb_tag_t tableTag = HB_OT_TAG_MATH;
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (version.sanitize (c) &&
likely (version.major == 1) &&
mathConstants.sanitize (c, this) &&
mathGlyphInfo.sanitize (c, this) &&
mathVariants.sanitize (c, this));
}
inline hb_position_t get_constant (hb_ot_math_constant_t constant,
hb_font_t *font) const
{ return (this+mathConstants).get_value (constant, font); }
inline const MathGlyphInfo &get_math_glyph_info (void) const
{ return this+mathGlyphInfo; }
inline const MathVariants &get_math_variants (void) const
{ return this+mathVariants; }
protected:
FixedVersion<>version; /* Version of the MATH table
* initially set to 0x00010000u */
OffsetTo<MathConstants> mathConstants;/* MathConstants table */
OffsetTo<MathGlyphInfo> mathGlyphInfo;/* MathGlyphInfo table */
OffsetTo<MathVariants> mathVariants; /* MathVariants table */
public:
DEFINE_SIZE_STATIC (10);
};
} /* namespace OT */
#endif /* HB_OT_MATH_TABLE_HH */

View file

@ -26,33 +26,15 @@
#include "hb-open-type-private.hh"
#include "hb-ot-layout-math-table.hh"
HB_SHAPER_DATA_ENSURE_DECLARE(ot, face)
#include "hb-ot-layout-private.hh"
#include "hb-ot-math-table.hh"
static inline const OT::MATH&
_get_math (hb_face_t *face)
{
if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return OT::Null(OT::MATH);
hb_ot_layout_t * layout = hb_ot_layout_from_face (face);
retry:
const OT::MATH *math = (const OT::MATH *) hb_atomic_ptr_get (&layout->math);
if (unlikely (!math))
{
hb_blob_t *blob = OT::Sanitizer<OT::MATH>::sanitize (face->reference_table (HB_OT_TAG_MATH));
math = OT::Sanitizer<OT::MATH>::lock_instance (blob);
if (!hb_atomic_ptr_cmpexch (&layout->math, NULL, math))
{
hb_blob_destroy (blob);
goto retry;
}
layout->math_blob = blob;
}
return *math;
return *(layout->math.get ());
}
/*
@ -64,10 +46,9 @@ retry:
* @face: #hb_face_t to test
*
* This function allows to verify the presence of an OpenType MATH table on the
* face. If so, such a table will be loaded into memory and sanitized. You can
* then safely call other functions for math layout and shaping.
* face.
*
* Return value: #TRUE if face has a MATH table and #FALSE otherwise
* Return value: true if face has a MATH table, false otherwise
*
* Since: 1.3.3
**/
@ -136,10 +117,10 @@ hb_ot_math_get_glyph_top_accent_attachment (hb_font_t *font,
/**
* hb_ot_math_is_glyph_extended_shape:
* @font: a #hb_font_t to test
* @face: a #hb_face_t to test
* @glyph: a glyph index to test
*
* Return value: #TRUE if the glyph is an extended shape and #FALSE otherwise
* Return value: true if the glyph is an extended shape, false otherwise
*
* Since: 1.3.3
**/

View file

@ -139,28 +139,28 @@ joining_type (hb_codepoint_t u)
switch (u >> 12)
{
case 0x0u:
if (hb_in_range (u, 0x0600u, 0x08E2u)) return joining_table[u - 0x0600u + joining_offset_0x0600u];
if (hb_in_range<hb_codepoint_t> (u, 0x0600u, 0x08E2u)) return joining_table[u - 0x0600u + joining_offset_0x0600u];
break;
case 0x1u:
if (hb_in_range (u, 0x1806u, 0x18AAu)) return joining_table[u - 0x1806u + joining_offset_0x1806u];
if (hb_in_range<hb_codepoint_t> (u, 0x1806u, 0x18AAu)) return joining_table[u - 0x1806u + joining_offset_0x1806u];
break;
case 0x2u:
if (hb_in_range (u, 0x200Cu, 0x2069u)) return joining_table[u - 0x200Cu + joining_offset_0x200cu];
if (hb_in_range<hb_codepoint_t> (u, 0x200Cu, 0x2069u)) return joining_table[u - 0x200Cu + joining_offset_0x200cu];
break;
case 0xAu:
if (hb_in_range (u, 0xA840u, 0xA873u)) return joining_table[u - 0xA840u + joining_offset_0xa840u];
if (hb_in_range<hb_codepoint_t> (u, 0xA840u, 0xA873u)) return joining_table[u - 0xA840u + joining_offset_0xa840u];
break;
case 0x10u:
if (hb_in_range (u, 0x10AC0u, 0x10AEFu)) return joining_table[u - 0x10AC0u + joining_offset_0x10ac0u];
if (hb_in_range (u, 0x10B80u, 0x10BAFu)) return joining_table[u - 0x10B80u + joining_offset_0x10b80u];
if (hb_in_range<hb_codepoint_t> (u, 0x10AC0u, 0x10AEFu)) return joining_table[u - 0x10AC0u + joining_offset_0x10ac0u];
if (hb_in_range<hb_codepoint_t> (u, 0x10B80u, 0x10BAFu)) return joining_table[u - 0x10B80u + joining_offset_0x10b80u];
break;
case 0x1Eu:
if (hb_in_range (u, 0x1E900u, 0x1E943u)) return joining_table[u - 0x1E900u + joining_offset_0x1e900u];
if (hb_in_range<hb_codepoint_t> (u, 0x1E900u, 0x1E943u)) return joining_table[u - 0x1E900u + joining_offset_0x1e900u];
break;
default:

View file

@ -199,6 +199,9 @@ collect_features_arabic (hb_ot_shape_planner_t *plan)
* 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.
*
* A pause after calt is required to make KFGQPC Uthmanic Script HAFS
* work correctly. See https://github.com/behdad/harfbuzz/issues/505
*/
map->add_gsub_pause (nuke_joiners);
@ -222,7 +225,10 @@ collect_features_arabic (hb_ot_shape_planner_t *plan)
if (plan->props.script == HB_SCRIPT_ARABIC)
map->add_gsub_pause (arabic_fallback_shape);
/* No pause after rclt. See 98460779bae19e4d64d29461ff154b3527bf8420. */
map->add_global_bool_feature (HB_TAG('r','c','l','t'));
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
@ -232,7 +238,6 @@ collect_features_arabic (hb_ot_shape_planner_t *plan)
* Note that IranNastaliq uses this feature extensively
* to fixup broken glyph sequences. Oh well...
* Test case: U+0643,U+0640,U+0631. */
//map->add_gsub_pause (NULL);
//map->add_global_bool_feature (HB_TAG('c','s','w','h'));
map->add_global_bool_feature (HB_TAG('m','s','e','t'));
}
@ -316,7 +321,10 @@ 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)
{
info[prev].arabic_shaping_action() = entry->prev_action;
buffer->unsafe_to_break (prev, i + 1);
}
info[i].arabic_shaping_action() = entry->curr_action;
@ -345,7 +353,7 @@ mongolian_variation_selectors (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 (unlikely (hb_in_range (info[i].codepoint, 0x180Bu, 0x180Du)))
if (unlikely (hb_in_range<hb_codepoint_t> (info[i].codepoint, 0x180Bu, 0x180Du)))
info[i].arabic_shaping_action() = info[i - 1].arabic_shaping_action();
}
@ -540,7 +548,7 @@ apply_stch (const hb_ot_shape_plan_t *plan,
/* See if we can improve the fit by adding an extra repeat and squeezing them together a bit. */
hb_position_t extra_repeat_overlap = 0;
hb_position_t shortfall = sign * w_remaining - sign * w_repeating * (n_copies + 1);
if (shortfall > 0)
if (shortfall > 0 && n_repeating > 0)
{
++n_copies;
hb_position_t excess = (n_copies + 1) * sign * w_repeating - sign * w_remaining;

View file

@ -32,7 +32,7 @@
/* Same order as the feature array below */
enum {
NONE,
_JMO,
LJMO,
VJMO,
@ -105,16 +105,16 @@ data_destroy_hangul (void *data)
#define NCount (VCount * TCount)
#define SCount (LCount * NCount)
#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 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 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 isL(u) (hb_in_ranges<hb_codepoint_t> ((u), 0x1100u, 0x115Fu, 0xA960u, 0xA97Cu))
#define isV(u) (hb_in_ranges<hb_codepoint_t> ((u), 0x1160u, 0x11A7u, 0xD7B0u, 0xD7C6u))
#define isT(u) (hb_in_ranges<hb_codepoint_t> ((u), 0x11A8u, 0x11FFu, 0xD7CBu, 0xD7FBu))
#define isHangulTone(u) (hb_in_range ((u), 0x302Eu, 0x302Fu))
#define isHangulTone(u) (hb_in_range<hb_codepoint_t> ((u), 0x302Eu, 0x302Fu))
/* buffer var allocations */
#define hangul_shaping_feature() complex_var_u8_0() /* hangul jamo shaping feature */
@ -202,6 +202,7 @@ preprocess_text_hangul (const hb_ot_shape_plan_t *plan,
if (start < end && end == buffer->out_len)
{
/* Tone mark follows a valid syllable; move it in front, unless it's zero width. */
buffer->unsafe_to_break_from_outbuffer (start, buffer->idx);
buffer->next_glyph ();
if (!is_zero_width_char (font, u))
{
@ -258,6 +259,7 @@ preprocess_text_hangul (const hb_ot_shape_plan_t *plan,
else
t = 0; /* The next character was not a trailing jamo. */
}
buffer->unsafe_to_break (buffer->idx, buffer->idx + (t ? 3 : 2));
/* We've got a syllable <L,V,T?>; see if it can potentially be composed. */
if (isCombiningL (l) && isCombiningV (v) && (t == 0 || isCombiningT (t)))
@ -322,6 +324,8 @@ preprocess_text_hangul (const hb_ot_shape_plan_t *plan,
end = start + 1;
continue;
}
else
buffer->unsafe_to_break (buffer->idx, buffer->idx + 2); /* Mark unsafe between LV and T. */
}
/* Otherwise, decompose if font doesn't support <LV> or <LVT>,
@ -368,6 +372,8 @@ preprocess_text_hangul (const hb_ot_shape_plan_t *plan,
buffer->merge_out_clusters (start, end);
continue;
}
else if ((!tindex && buffer->idx + 1 < count && isT (buffer->cur(+1).codepoint)))
buffer->unsafe_to_break (buffer->idx, buffer->idx + 2); /* Mark unsafe between LV and T. */
}
if (has_glyph)

View file

@ -121,7 +121,7 @@ enum indic_syllabic_category_t {
INDIC_SYLLABIC_CATEGORY_CONSONANT_PREFIXED = OT_X, /* Don't care. */
INDIC_SYLLABIC_CATEGORY_CONSONANT_SUBJOINED = OT_CM,
INDIC_SYLLABIC_CATEGORY_CONSONANT_SUCCEEDING_REPHA = OT_N,
INDIC_SYLLABIC_CATEGORY_CONSONANT_WITH_STACKER = OT_Repha, /* TODO */
INDIC_SYLLABIC_CATEGORY_CONSONANT_WITH_STACKER = OT_C,
INDIC_SYLLABIC_CATEGORY_GEMINATION_MARK = OT_SM,
INDIC_SYLLABIC_CATEGORY_INVISIBLE_STACKER = OT_Coeng,
INDIC_SYLLABIC_CATEGORY_JOINER = OT_ZWJ,
@ -132,7 +132,7 @@ enum indic_syllabic_category_t {
INDIC_SYLLABIC_CATEGORY_NUMBER_JOINER = OT_PLACEHOLDER, /* Don't care. */
INDIC_SYLLABIC_CATEGORY_PURE_KILLER = OT_M, /* Is like a vowel matra. */
INDIC_SYLLABIC_CATEGORY_REGISTER_SHIFTER = OT_RS,
INDIC_SYLLABIC_CATEGORY_SYLLABLE_MODIFIER = OT_M, /* Misc Khmer signs. */
INDIC_SYLLABIC_CATEGORY_SYLLABLE_MODIFIER = OT_SM,
INDIC_SYLLABIC_CATEGORY_TONE_LETTER = OT_X,
INDIC_SYLLABIC_CATEGORY_TONE_MARK = OT_N,
INDIC_SYLLABIC_CATEGORY_VIRAMA = OT_H,

View file

@ -398,28 +398,35 @@ hb_indic_get_categories (hb_codepoint_t u)
switch (u >> 12)
{
case 0x0u:
if (hb_in_range (u, 0x0028u, 0x003Fu)) return indic_table[u - 0x0028u + indic_offset_0x0028u];
if (hb_in_range (u, 0x00B0u, 0x00D7u)) return indic_table[u - 0x00B0u + indic_offset_0x00b0u];
if (hb_in_range (u, 0x0900u, 0x0DF7u)) return indic_table[u - 0x0900u + indic_offset_0x0900u];
if (hb_in_range<hb_codepoint_t> (u, 0x0028u, 0x003Fu)) return indic_table[u - 0x0028u + indic_offset_0x0028u];
if (hb_in_range<hb_codepoint_t> (u, 0x00B0u, 0x00D7u)) return indic_table[u - 0x00B0u + indic_offset_0x00b0u];
if (hb_in_range<hb_codepoint_t> (u, 0x0900u, 0x0DF7u)) return indic_table[u - 0x0900u + indic_offset_0x0900u];
if (unlikely (u == 0x00A0u)) return _(CP,x);
break;
case 0x1u:
if (hb_in_range (u, 0x1000u, 0x109Fu)) return indic_table[u - 0x1000u + indic_offset_0x1000u];
if (hb_in_range (u, 0x1780u, 0x17EFu)) return indic_table[u - 0x1780u + indic_offset_0x1780u];
if (hb_in_range (u, 0x1CD0u, 0x1CFFu)) return indic_table[u - 0x1CD0u + indic_offset_0x1cd0u];
if (hb_in_range<hb_codepoint_t> (u, 0x1000u, 0x109Fu)) return indic_table[u - 0x1000u + indic_offset_0x1000u];
if (hb_in_range<hb_codepoint_t> (u, 0x1780u, 0x17EFu)) return indic_table[u - 0x1780u + indic_offset_0x1780u];
if (hb_in_range<hb_codepoint_t> (u, 0x1CD0u, 0x1CFFu)) return indic_table[u - 0x1CD0u + indic_offset_0x1cd0u];
break;
case 0x2u:
if (hb_in_range (u, 0x2008u, 0x2017u)) return indic_table[u - 0x2008u + indic_offset_0x2008u];
if (hb_in_range (u, 0x2070u, 0x2087u)) return indic_table[u - 0x2070u + indic_offset_0x2070u];
if (hb_in_range<hb_codepoint_t> (u, 0x2008u, 0x2017u)) return indic_table[u - 0x2008u + indic_offset_0x2008u];
if (hb_in_range<hb_codepoint_t> (u, 0x2070u, 0x2087u)) return indic_table[u - 0x2070u + indic_offset_0x2070u];
if (unlikely (u == 0x25CCu)) return _(CP,x);
break;
case 0xAu:
if (hb_in_range (u, 0xA8E0u, 0xA8F7u)) return indic_table[u - 0xA8E0u + indic_offset_0xa8e0u];
if (hb_in_range (u, 0xA9E0u, 0xA9FFu)) return indic_table[u - 0xA9E0u + indic_offset_0xa9e0u];
if (hb_in_range (u, 0xAA60u, 0xAA7Fu)) return indic_table[u - 0xAA60u + indic_offset_0xaa60u];
if (hb_in_range<hb_codepoint_t> (u, 0xA8E0u, 0xA8F7u)) return indic_table[u - 0xA8E0u + indic_offset_0xa8e0u];
if (hb_in_range<hb_codepoint_t> (u, 0xA9E0u, 0xA9FFu)) return indic_table[u - 0xA9E0u + indic_offset_0xa9e0u];
if (hb_in_range<hb_codepoint_t> (u, 0xAA60u, 0xAA7Fu)) return indic_table[u - 0xAA60u + indic_offset_0xaa60u];
break;
case 0x11u:
// According to ScriptExtensions.txt, these Grantha marks may also be used in Tamil,
// so the Indic shaper needs to know their categories.
if (unlikely (u == 0x11303)) return _(Vs,R);
if (unlikely (u == 0x1133c)) return _(N,B);
break;
default:

View file

@ -177,15 +177,15 @@ set_indic_properties (hb_glyph_info_t &info)
*/
/* The following act more like the Bindus. */
if (unlikely (hb_in_range (u, 0x0953u, 0x0954u)))
if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x0953u, 0x0954u)))
cat = OT_SM;
/* The following act like consonants. */
else if (unlikely (hb_in_ranges (u, 0x0A72u, 0x0A73u,
else if (unlikely (hb_in_ranges<hb_codepoint_t> (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)))
else if (unlikely (hb_in_range<hb_codepoint_t> (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.
@ -193,15 +193,24 @@ set_indic_properties (hb_glyph_info_t &info)
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,
else if (unlikely (hb_in_ranges<hb_codepoint_t> (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<hb_codepoint_t> (u, 0x17CDu, 0x17D1u) ||
u == 0x17CBu || u == 0x17D3u || u == 0x17DDu)) /* Khmer Various signs */
{
/* These can occur mid-syllable (eg. before matras), even though Unicode marks them as Syllable_Modifier.
* https://github.com/roozbehp/unicode-data/issues/5 */
cat = OT_M;
pos = POS_ABOVE_C;
}
else if (unlikely (u == 0x17C6u)) cat = OT_N; /* Khmer Bindu doesn't like to be repositioned. */
else if (unlikely (hb_in_range (u, 0x2010u, 0x2011u)))
else if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x2010u, 0x2011u)))
cat = OT_PLACEHOLDER;
else if (unlikely (u == 0x25CCu)) cat = OT_DOTTEDCIRCLE;
@ -411,12 +420,12 @@ 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);
map->add_feature (indic_features[i].tag, 1, indic_features[i].flags | F_MANUAL_ZWJ | F_MANUAL_ZWNJ);
map->add_gsub_pause (NULL);
}
map->add_gsub_pause (final_reordering);
for (; i < INDIC_NUM_FEATURES; i++) {
map->add_feature (indic_features[i].tag, 1, indic_features[i].flags | F_MANUAL_ZWJ);
map->add_feature (indic_features[i].tag, 1, indic_features[i].flags | F_MANUAL_ZWJ | F_MANUAL_ZWNJ);
}
map->add_global_bool_feature (HB_TAG('c','a','l','t'));
@ -615,6 +624,8 @@ setup_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED,
hb_buffer_t *buffer)
{
find_syllables (buffer);
foreach_syllable (buffer, start, end)
buffer->unsafe_to_break (start, end);
}
static int
@ -1497,7 +1508,7 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan,
if (reph_pos == REPH_POS_AFTER_SUB)
{
new_reph_pos = base;
while (new_reph_pos < end &&
while (new_reph_pos + 1 < end &&
!( FLAG_SAFE (info[new_reph_pos + 1].indic_position()) & (FLAG (POS_POST_C) | FLAG (POS_AFTER_POST) | FLAG (POS_SMVD))))
new_reph_pos++;
if (new_reph_pos < end)
@ -1738,7 +1749,7 @@ decompose_indic (const hb_ot_shape_normalize_context_t *c,
#endif
}
if ((ab == 0x0DDAu || hb_in_range (ab, 0x0DDCu, 0x0DDEu)))
if ((ab == 0x0DDAu || hb_in_range<hb_codepoint_t> (ab, 0x0DDCu, 0x0DDEu)))
{
/*
* Sinhala split matras... Let the fun begin.

View file

@ -175,7 +175,7 @@ set_myanmar_properties (hb_glyph_info_t &info)
/* Myanmar
* http://www.microsoft.com/typography/OpenTypeDev/myanmar/intro.htm#analyze
*/
if (unlikely (hb_in_range (u, 0xFE00u, 0xFE0Fu)))
if (unlikely (hb_in_range<hb_codepoint_t> (u, 0xFE00u, 0xFE0Fu)))
cat = (indic_category_t) OT_VS;
switch (u)
@ -297,6 +297,8 @@ setup_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED,
hb_buffer_t *buffer)
{
find_syllables (buffer);
foreach_syllable (buffer, start, end)
buffer->unsafe_to_break (start, end);
}
static int

View file

@ -191,6 +191,9 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner)
case HB_SCRIPT_MANICHAEAN:
case HB_SCRIPT_PSALTER_PAHLAVI:
/* Unicode-9.0 additions */
case HB_SCRIPT_ADLAM:
/* 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).
* But note that Arabic shaping is applicable only to horizontal layout; for

View file

@ -52,7 +52,7 @@ get_consonant_type (hb_codepoint_t u)
return RC;
if (u == 0x0E0Eu || u == 0x0E0Fu)
return DC;
if (hb_in_range (u, 0x0E01u, 0x0E2Eu))
if (hb_in_range<hb_codepoint_t> (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 == 0x0E31u || hb_in_range (u, 0x0E34u, 0x0E37u) ||
u == 0x0E47u || hb_in_range (u, 0x0E4Du, 0x0E4Eu))
if (u == 0x0E31u || hb_in_range<hb_codepoint_t> (u, 0x0E34u, 0x0E37u) ||
u == 0x0E47u || hb_in_range<hb_codepoint_t> (u, 0x0E4Du, 0x0E4Eu))
return AV;
if (hb_in_range (u, 0x0E38u, 0x0E3Au))
if (hb_in_range<hb_codepoint_t> (u, 0x0E38u, 0x0E3Au))
return BV;
if (hb_in_range (u, 0x0E48u, 0x0E4Cu))
if (hb_in_range<hb_codepoint_t> (u, 0x0E48u, 0x0E4Cu))
return T;
return NOT_MARK;
}
@ -244,6 +244,7 @@ do_thai_pua_shaping (const hb_ot_shape_plan_t *plan HB_UNUSED,
/* At least one of the above/below actions is NOP. */
thai_action_t action = above_edge.action != NOP ? above_edge.action : below_edge.action;
buffer->unsafe_to_break (base, i);
if (action == RD)
info[base].codepoint = thai_pua_shape (info[base].codepoint, action, font);
else
@ -310,7 +311,7 @@ preprocess_text_thai (const hb_ot_shape_plan_t *plan,
#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 ((x) & ~0x0080u, 0x0E34u, 0x0E37u, 0x0E47u, 0x0E4Eu, 0x0E31u, 0x0E31u))
#define IS_TONE_MARK(x) (hb_in_ranges<hb_codepoint_t> ((x) & ~0x0080u, 0x0E34u, 0x0E37u, 0x0E47u, 0x0E4Eu, 0x0E31u, 0x0E31u))
buffer->clear_output ();
unsigned int count = buffer->len;

View file

@ -38,31 +38,31 @@
static const unsigned char _use_syllable_machine_trans_keys[] = {
1u, 1u, 0u, 39u, 21u, 21u, 8u, 39u, 8u, 39u, 1u, 1u, 8u, 39u, 8u, 39u,
8u, 39u, 8u, 26u, 8u, 26u, 8u, 26u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u,
8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 13u, 21u,
4u, 4u, 13u, 13u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 26u, 8u, 26u,
8u, 26u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u,
8u, 39u, 8u, 39u, 8u, 39u, 1u, 1u, 1u, 39u, 8u, 39u, 21u, 42u, 41u, 42u,
42u, 42u, 0
8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u,
13u, 21u, 4u, 4u, 13u, 13u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 26u,
8u, 26u, 8u, 26u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u,
8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 1u, 1u, 1u, 39u, 8u, 39u,
21u, 42u, 41u, 42u, 42u, 42u, 0
};
static const char _use_syllable_machine_key_spans[] = {
1, 40, 1, 32, 32, 1, 32, 32,
32, 19, 19, 19, 32, 32, 32, 32,
32, 32, 32, 32, 32, 32, 32, 9,
1, 1, 32, 32, 32, 32, 19, 19,
19, 32, 32, 32, 32, 32, 32, 32,
32, 32, 32, 1, 39, 32, 22, 2,
1
32, 32, 32, 32, 32, 32, 32, 32,
9, 1, 1, 32, 32, 32, 32, 19,
19, 19, 32, 32, 32, 32, 32, 32,
32, 32, 32, 32, 32, 1, 39, 32,
22, 2, 1
};
static const short _use_syllable_machine_index_offsets[] = {
0, 2, 43, 45, 78, 111, 113, 146,
179, 212, 232, 252, 272, 305, 338, 371,
404, 437, 470, 503, 536, 569, 602, 635,
645, 647, 649, 682, 715, 748, 781, 801,
821, 841, 874, 907, 940, 973, 1006, 1039,
1072, 1105, 1138, 1171, 1173, 1213, 1246, 1269,
1272
668, 678, 680, 682, 715, 748, 781, 814,
834, 854, 874, 907, 940, 973, 1006, 1039,
1072, 1105, 1138, 1171, 1204, 1237, 1239, 1279,
1312, 1335, 1338
};
static const char _use_syllable_machine_indicies[] = {
@ -131,112 +131,120 @@ static const char _use_syllable_machine_indicies[] = {
43, 44, 28, 45, 46, 47, 28, 29,
28, 28, 28, 28, 28, 28, 28, 28,
28, 28, 28, 28, 28, 33, 34, 35,
36, 37, 28, 28, 33, 28, 28, 28,
36, 37, 28, 50, 33, 28, 28, 28,
42, 43, 44, 28, 45, 46, 47, 28,
29, 28, 28, 28, 28, 28, 28, 28,
28, 28, 28, 28, 28, 28, 33, 34,
35, 36, 37, 38, 39, 33, 28, 28,
35, 36, 37, 28, 28, 33, 28, 28,
28, 42, 43, 44, 28, 45, 46, 47,
28, 29, 28, 28, 30, 31, 28, 28,
28, 29, 28, 28, 28, 28, 28, 28,
28, 28, 28, 28, 28, 28, 28, 33,
34, 35, 36, 37, 38, 39, 33, 40,
28, 41, 42, 43, 44, 28, 45, 46,
34, 35, 36, 37, 38, 39, 33, 28,
28, 28, 42, 43, 44, 28, 45, 46,
47, 28, 29, 28, 28, 30, 31, 28,
28, 28, 28, 28, 28, 28, 28, 28,
33, 34, 35, 36, 37, 38, 39, 33,
40, 32, 41, 42, 43, 44, 28, 45,
46, 47, 28, 51, 50, 50, 50, 50,
50, 50, 50, 52, 50, 5, 53, 51,
50, 6, 54, 54, 1, 55, 54, 54,
54, 54, 54, 54, 54, 54, 56, 10,
11, 12, 13, 14, 15, 16, 10, 17,
19, 19, 20, 21, 22, 54, 23, 24,
25, 54, 6, 54, 54, 1, 55, 54,
54, 54, 54, 54, 54, 54, 54, 54,
40, 28, 41, 42, 43, 44, 28, 45,
46, 47, 28, 29, 28, 28, 30, 31,
28, 28, 28, 28, 28, 28, 28, 28,
28, 33, 34, 35, 36, 37, 38, 39,
33, 40, 32, 41, 42, 43, 44, 28,
45, 46, 47, 28, 52, 51, 51, 51,
51, 51, 51, 51, 53, 51, 5, 54,
52, 51, 6, 55, 55, 1, 56, 55,
55, 55, 55, 55, 55, 55, 55, 57,
10, 11, 12, 13, 14, 15, 16, 10,
17, 19, 19, 20, 21, 22, 54, 23,
24, 25, 54, 6, 54, 54, 54, 54,
54, 54, 54, 54, 54, 54, 54, 54,
54, 10, 11, 12, 13, 14, 54, 54,
54, 54, 54, 54, 20, 21, 22, 54,
23, 24, 25, 54, 6, 54, 54, 54,
54, 54, 54, 54, 54, 54, 54, 54,
54, 54, 54, 11, 12, 13, 14, 54,
54, 54, 54, 54, 54, 54, 54, 54,
54, 23, 24, 25, 54, 6, 54, 54,
54, 54, 54, 54, 54, 54, 54, 54,
54, 54, 54, 54, 54, 12, 13, 14,
54, 6, 54, 54, 54, 54, 54, 54,
54, 54, 54, 54, 54, 54, 54, 54,
54, 54, 13, 14, 54, 6, 54, 54,
54, 54, 54, 54, 54, 54, 54, 54,
54, 54, 54, 54, 54, 54, 54, 14,
54, 6, 54, 54, 54, 54, 54, 54,
54, 54, 54, 54, 54, 54, 54, 54,
54, 12, 13, 14, 54, 54, 54, 54,
54, 54, 54, 54, 54, 54, 23, 24,
25, 54, 6, 54, 54, 54, 54, 54,
54, 54, 54, 54, 54, 54, 54, 54,
54, 54, 12, 13, 14, 54, 54, 54,
54, 54, 54, 54, 54, 54, 54, 54,
24, 25, 54, 6, 54, 54, 54, 54,
54, 54, 54, 54, 54, 54, 54, 54,
54, 54, 54, 12, 13, 14, 54, 54,
54, 54, 54, 54, 54, 54, 54, 54,
54, 54, 25, 54, 6, 54, 54, 54,
54, 54, 54, 54, 54, 54, 54, 54,
54, 54, 54, 11, 12, 13, 14, 54,
54, 54, 54, 54, 54, 20, 21, 22,
54, 23, 24, 25, 54, 6, 54, 54,
54, 54, 54, 54, 54, 54, 54, 54,
54, 54, 54, 54, 11, 12, 13, 14,
54, 54, 54, 54, 54, 54, 54, 21,
22, 54, 23, 24, 25, 54, 6, 54,
54, 54, 54, 54, 54, 54, 54, 54,
54, 54, 54, 54, 54, 11, 12, 13,
14, 54, 54, 54, 54, 54, 54, 54,
54, 22, 54, 23, 24, 25, 54, 6,
54, 54, 54, 54, 54, 54, 54, 54,
54, 54, 54, 54, 54, 10, 11, 12,
13, 14, 54, 16, 10, 54, 54, 54,
20, 21, 22, 54, 23, 24, 25, 54,
6, 54, 54, 54, 54, 54, 54, 54,
54, 54, 54, 54, 54, 54, 10, 11,
12, 13, 14, 54, 54, 10, 54, 54,
54, 20, 21, 22, 54, 23, 24, 25,
54, 6, 54, 54, 54, 54, 54, 54,
54, 54, 54, 54, 54, 54, 54, 10,
11, 12, 13, 14, 15, 16, 10, 54,
54, 54, 20, 21, 22, 54, 23, 24,
25, 54, 6, 54, 54, 1, 55, 54,
54, 54, 54, 54, 54, 54, 54, 54,
10, 11, 12, 13, 14, 15, 16, 10,
17, 54, 19, 20, 21, 22, 54, 23,
24, 25, 54, 1, 57, 3, 54, 54,
54, 3, 54, 54, 6, 54, 54, 1,
55, 54, 54, 54, 54, 54, 54, 54,
54, 54, 10, 11, 12, 13, 14, 15,
16, 10, 17, 18, 19, 20, 21, 22,
54, 23, 24, 25, 54, 6, 54, 54,
1, 55, 54, 54, 54, 54, 54, 54,
54, 54, 54, 10, 11, 12, 13, 14,
15, 16, 10, 17, 18, 19, 20, 21,
22, 54, 23, 24, 25, 54, 59, 58,
58, 58, 58, 58, 58, 58, 58, 58,
58, 58, 58, 58, 58, 58, 58, 58,
58, 58, 59, 60, 58, 59, 60, 58,
60, 58, 0
17, 19, 19, 20, 21, 22, 55, 23,
24, 25, 55, 6, 55, 55, 1, 56,
55, 55, 55, 55, 55, 55, 55, 55,
55, 10, 11, 12, 13, 14, 15, 16,
10, 17, 19, 19, 20, 21, 22, 55,
23, 24, 25, 55, 6, 55, 55, 55,
55, 55, 55, 55, 55, 55, 55, 55,
55, 55, 10, 11, 12, 13, 14, 55,
55, 55, 55, 55, 55, 20, 21, 22,
55, 23, 24, 25, 55, 6, 55, 55,
55, 55, 55, 55, 55, 55, 55, 55,
55, 55, 55, 55, 11, 12, 13, 14,
55, 55, 55, 55, 55, 55, 55, 55,
55, 55, 23, 24, 25, 55, 6, 55,
55, 55, 55, 55, 55, 55, 55, 55,
55, 55, 55, 55, 55, 55, 12, 13,
14, 55, 6, 55, 55, 55, 55, 55,
55, 55, 55, 55, 55, 55, 55, 55,
55, 55, 55, 13, 14, 55, 6, 55,
55, 55, 55, 55, 55, 55, 55, 55,
55, 55, 55, 55, 55, 55, 55, 55,
14, 55, 6, 55, 55, 55, 55, 55,
55, 55, 55, 55, 55, 55, 55, 55,
55, 55, 12, 13, 14, 55, 55, 55,
55, 55, 55, 55, 55, 55, 55, 23,
24, 25, 55, 6, 55, 55, 55, 55,
55, 55, 55, 55, 55, 55, 55, 55,
55, 55, 55, 12, 13, 14, 55, 55,
55, 55, 55, 55, 55, 55, 55, 55,
55, 24, 25, 55, 6, 55, 55, 55,
55, 55, 55, 55, 55, 55, 55, 55,
55, 55, 55, 55, 12, 13, 14, 55,
55, 55, 55, 55, 55, 55, 55, 55,
55, 55, 55, 25, 55, 6, 55, 55,
55, 55, 55, 55, 55, 55, 55, 55,
55, 55, 55, 55, 11, 12, 13, 14,
55, 55, 55, 55, 55, 55, 20, 21,
22, 55, 23, 24, 25, 55, 6, 55,
55, 55, 55, 55, 55, 55, 55, 55,
55, 55, 55, 55, 55, 11, 12, 13,
14, 55, 55, 55, 55, 55, 55, 55,
21, 22, 55, 23, 24, 25, 55, 6,
55, 55, 55, 55, 55, 55, 55, 55,
55, 55, 55, 55, 55, 55, 11, 12,
13, 14, 55, 55, 55, 55, 55, 55,
55, 55, 22, 55, 23, 24, 25, 55,
6, 55, 55, 55, 55, 55, 55, 55,
55, 55, 55, 55, 55, 55, 10, 11,
12, 13, 14, 55, 16, 10, 55, 55,
55, 20, 21, 22, 55, 23, 24, 25,
55, 6, 55, 55, 55, 55, 55, 55,
55, 55, 55, 55, 55, 55, 55, 10,
11, 12, 13, 14, 55, 58, 10, 55,
55, 55, 20, 21, 22, 55, 23, 24,
25, 55, 6, 55, 55, 55, 55, 55,
55, 55, 55, 55, 55, 55, 55, 55,
10, 11, 12, 13, 14, 55, 55, 10,
55, 55, 55, 20, 21, 22, 55, 23,
24, 25, 55, 6, 55, 55, 55, 55,
55, 55, 55, 55, 55, 55, 55, 55,
55, 10, 11, 12, 13, 14, 15, 16,
10, 55, 55, 55, 20, 21, 22, 55,
23, 24, 25, 55, 6, 55, 55, 1,
56, 55, 55, 55, 55, 55, 55, 55,
55, 55, 10, 11, 12, 13, 14, 15,
16, 10, 17, 55, 19, 20, 21, 22,
55, 23, 24, 25, 55, 1, 59, 3,
55, 55, 55, 3, 55, 55, 6, 55,
55, 1, 56, 55, 55, 55, 55, 55,
55, 55, 55, 55, 10, 11, 12, 13,
14, 15, 16, 10, 17, 18, 19, 20,
21, 22, 55, 23, 24, 25, 55, 6,
55, 55, 1, 56, 55, 55, 55, 55,
55, 55, 55, 55, 55, 10, 11, 12,
13, 14, 15, 16, 10, 17, 18, 19,
20, 21, 22, 55, 23, 24, 25, 55,
61, 60, 60, 60, 60, 60, 60, 60,
60, 60, 60, 60, 60, 60, 60, 60,
60, 60, 60, 60, 61, 62, 60, 61,
62, 60, 62, 60, 0
};
static const char _use_syllable_machine_trans_targs[] = {
1, 26, 2, 3, 1, 23, 1, 43,
44, 46, 28, 29, 30, 31, 32, 39,
40, 41, 45, 42, 36, 37, 38, 33,
34, 35, 1, 1, 1, 1, 4, 5,
22, 7, 8, 9, 10, 11, 18, 19,
20, 21, 15, 16, 17, 12, 13, 14,
6, 1, 1, 24, 25, 1, 1, 0,
27, 1, 1, 47, 48
1, 27, 2, 3, 1, 24, 1, 45,
46, 48, 29, 30, 31, 32, 33, 40,
41, 43, 47, 44, 37, 38, 39, 34,
35, 36, 1, 1, 1, 1, 4, 5,
23, 7, 8, 9, 10, 11, 18, 19,
21, 22, 15, 16, 17, 12, 13, 14,
6, 1, 20, 1, 25, 26, 1, 1,
0, 28, 42, 1, 1, 49, 50
};
static const char _use_syllable_machine_trans_actions[] = {
@ -246,8 +254,8 @@ static const char _use_syllable_machine_trans_actions[] = {
0, 0, 7, 8, 9, 10, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 11, 12, 0, 0, 13, 14, 0,
2, 15, 16, 0, 0
0, 11, 0, 12, 0, 0, 13, 14,
0, 2, 0, 15, 16, 0, 0
};
static const char _use_syllable_machine_to_state_actions[] = {
@ -257,7 +265,7 @@ static const char _use_syllable_machine_to_state_actions[] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0
0, 0, 0
};
static const char _use_syllable_machine_from_state_actions[] = {
@ -267,17 +275,17 @@ static const char _use_syllable_machine_from_state_actions[] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0
0, 0, 0
};
static const short _use_syllable_machine_eof_trans[] = {
1, 0, 27, 29, 29, 50, 29, 29,
29, 29, 29, 29, 29, 29, 29, 29,
29, 29, 29, 29, 29, 29, 29, 51,
54, 51, 55, 55, 55, 55, 55, 55,
55, 55, 55, 55, 55, 55, 55, 55,
55, 55, 55, 58, 55, 55, 59, 59,
59
29, 29, 29, 29, 29, 29, 29, 29,
52, 55, 52, 56, 56, 56, 56, 56,
56, 56, 56, 56, 56, 56, 56, 56,
56, 56, 56, 56, 56, 60, 56, 56,
61, 61, 61
};
static const int use_syllable_machine_start = 1;
@ -291,7 +299,7 @@ static const int use_syllable_machine_en_main = 1;
#line 138 "hb-ot-shape-complex-use-machine.rl"
#line 139 "hb-ot-shape-complex-use-machine.rl"
#define found_syllable(syllable_type) \
@ -311,7 +319,7 @@ find_syllables (hb_buffer_t *buffer)
int cs;
hb_glyph_info_t *info = buffer->info;
#line 315 "hb-ot-shape-complex-use-machine.hh"
#line 323 "hb-ot-shape-complex-use-machine.hh"
{
cs = use_syllable_machine_start;
ts = 0;
@ -319,7 +327,7 @@ find_syllables (hb_buffer_t *buffer)
act = 0;
}
#line 159 "hb-ot-shape-complex-use-machine.rl"
#line 160 "hb-ot-shape-complex-use-machine.rl"
p = 0;
@ -328,7 +336,7 @@ find_syllables (hb_buffer_t *buffer)
unsigned int last = 0;
unsigned int syllable_serial = 1;
#line 332 "hb-ot-shape-complex-use-machine.hh"
#line 340 "hb-ot-shape-complex-use-machine.hh"
{
int _slen;
int _trans;
@ -342,7 +350,7 @@ _resume:
#line 1 "NONE"
{ts = p;}
break;
#line 346 "hb-ot-shape-complex-use-machine.hh"
#line 354 "hb-ot-shape-complex-use-machine.hh"
}
_keys = _use_syllable_machine_trans_keys + (cs<<1);
@ -365,58 +373,58 @@ _eof_trans:
{te = p+1;}
break;
case 8:
#line 127 "hb-ot-shape-complex-use-machine.rl"
#line 128 "hb-ot-shape-complex-use-machine.rl"
{te = p+1;{ found_syllable (independent_cluster); }}
break;
case 10:
#line 129 "hb-ot-shape-complex-use-machine.rl"
#line 130 "hb-ot-shape-complex-use-machine.rl"
{te = p+1;{ found_syllable (standard_cluster); }}
break;
case 6:
#line 133 "hb-ot-shape-complex-use-machine.rl"
#line 134 "hb-ot-shape-complex-use-machine.rl"
{te = p+1;{ found_syllable (broken_cluster); }}
break;
case 5:
#line 134 "hb-ot-shape-complex-use-machine.rl"
#line 135 "hb-ot-shape-complex-use-machine.rl"
{te = p+1;{ found_syllable (non_cluster); }}
break;
case 7:
#line 127 "hb-ot-shape-complex-use-machine.rl"
#line 128 "hb-ot-shape-complex-use-machine.rl"
{te = p;p--;{ found_syllable (independent_cluster); }}
break;
case 11:
#line 128 "hb-ot-shape-complex-use-machine.rl"
#line 129 "hb-ot-shape-complex-use-machine.rl"
{te = p;p--;{ found_syllable (virama_terminated_cluster); }}
break;
case 9:
#line 129 "hb-ot-shape-complex-use-machine.rl"
#line 130 "hb-ot-shape-complex-use-machine.rl"
{te = p;p--;{ found_syllable (standard_cluster); }}
break;
case 13:
#line 130 "hb-ot-shape-complex-use-machine.rl"
#line 131 "hb-ot-shape-complex-use-machine.rl"
{te = p;p--;{ found_syllable (number_joiner_terminated_cluster); }}
break;
case 12:
#line 131 "hb-ot-shape-complex-use-machine.rl"
#line 132 "hb-ot-shape-complex-use-machine.rl"
{te = p;p--;{ found_syllable (numeral_cluster); }}
break;
case 16:
#line 132 "hb-ot-shape-complex-use-machine.rl"
#line 133 "hb-ot-shape-complex-use-machine.rl"
{te = p;p--;{ found_syllable (symbol_cluster); }}
break;
case 14:
#line 133 "hb-ot-shape-complex-use-machine.rl"
#line 134 "hb-ot-shape-complex-use-machine.rl"
{te = p;p--;{ found_syllable (broken_cluster); }}
break;
case 15:
#line 134 "hb-ot-shape-complex-use-machine.rl"
#line 135 "hb-ot-shape-complex-use-machine.rl"
{te = p;p--;{ found_syllable (non_cluster); }}
break;
case 1:
#line 133 "hb-ot-shape-complex-use-machine.rl"
#line 134 "hb-ot-shape-complex-use-machine.rl"
{{p = ((te))-1;}{ found_syllable (broken_cluster); }}
break;
#line 420 "hb-ot-shape-complex-use-machine.hh"
#line 428 "hb-ot-shape-complex-use-machine.hh"
}
_again:
@ -425,7 +433,7 @@ _again:
#line 1 "NONE"
{ts = 0;}
break;
#line 429 "hb-ot-shape-complex-use-machine.hh"
#line 437 "hb-ot-shape-complex-use-machine.hh"
}
if ( ++p != pe )
@ -441,7 +449,7 @@ _again:
}
#line 168 "hb-ot-shape-complex-use-machine.rl"
#line 169 "hb-ot-shape-complex-use-machine.rl"
}

View file

@ -89,7 +89,8 @@ SMBlw = 42; # SYM_MOD_BELOW
consonant_modifiers = CMAbv* CMBlw* ((H B | SUB) VS? CMAbv? CMBlw*)*;
medial_consonants = MPre? MAbv? MBlw? MPst?;
# Override: Allow two MBlw. https://github.com/behdad/harfbuzz/issues/376
medial_consonants = MPre? MAbv? MBlw?.MBlw? MPst?;
dependent_vowels = VPre* VAbv* VBlw* VPst*;
vowel_modifiers = VMPre* VMAbv* VMBlw* VMPst*;
final_consonants = FAbv* FBlw* FPst* FM?;

View file

@ -9,7 +9,7 @@
* # IndicSyllabicCategory-9.0.0.txt
* # Date: 2016-05-21, 02:46:00 GMT [RP]
* # IndicPositionalCategory-9.0.0.txt
* # Date: 2016-02-25, 00:48:00 GMT [RP]
* # Date: 2016-06-09, 19:33:00 GMT [RP]
* # Blocks-9.0.0.txt
* # Date: 2016-02-05, 23:48:00 GMT [KW]
* UnicodeData.txt does not have a header.
@ -410,7 +410,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = {
/* AA00 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* AA10 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* AA20 */ B, B, B, B, B, B, B, B, B, VAbv, VAbv, VAbv, VAbv, VBlw, VAbv, VPre,
/* AA20 */ B, B, B, B, B, B, B, B, B, VMAbv, VAbv, VAbv, VAbv, VBlw, VAbv, VPre,
/* AA30 */ VPre, VAbv, VBlw, MPst, MPre, MBlw, MBlw, O, O, O, O, O, O, O, O, O,
/* AA40 */ B, B, B, FAbv, B, B, B, B, B, B, B, B, FAbv, FPst, O, O,
/* AA50 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O,
@ -644,47 +644,47 @@ hb_use_get_categories (hb_codepoint_t u)
switch (u >> 12)
{
case 0x0u:
if (hb_in_range (u, 0x0028u, 0x003Fu)) return use_table[u - 0x0028u + use_offset_0x0028u];
if (hb_in_range (u, 0x00A0u, 0x00D7u)) return use_table[u - 0x00A0u + use_offset_0x00a0u];
if (hb_in_range (u, 0x0900u, 0x0DF7u)) return use_table[u - 0x0900u + use_offset_0x0900u];
if (hb_in_range<hb_codepoint_t> (u, 0x0028u, 0x003Fu)) return use_table[u - 0x0028u + use_offset_0x0028u];
if (hb_in_range<hb_codepoint_t> (u, 0x00A0u, 0x00D7u)) return use_table[u - 0x00A0u + use_offset_0x00a0u];
if (hb_in_range<hb_codepoint_t> (u, 0x0900u, 0x0DF7u)) return use_table[u - 0x0900u + use_offset_0x0900u];
if (unlikely (u == 0x034Fu)) return CGJ;
break;
case 0x1u:
if (hb_in_range (u, 0x1000u, 0x109Fu)) return use_table[u - 0x1000u + use_offset_0x1000u];
if (hb_in_range (u, 0x1700u, 0x17EFu)) return use_table[u - 0x1700u + use_offset_0x1700u];
if (hb_in_range (u, 0x1900u, 0x1A9Fu)) return use_table[u - 0x1900u + use_offset_0x1900u];
if (hb_in_range (u, 0x1B00u, 0x1C4Fu)) return use_table[u - 0x1B00u + use_offset_0x1b00u];
if (hb_in_range (u, 0x1CD0u, 0x1CFFu)) return use_table[u - 0x1CD0u + use_offset_0x1cd0u];
if (hb_in_range (u, 0x1DF8u, 0x1DFFu)) return use_table[u - 0x1DF8u + use_offset_0x1df8u];
if (hb_in_range<hb_codepoint_t> (u, 0x1000u, 0x109Fu)) return use_table[u - 0x1000u + use_offset_0x1000u];
if (hb_in_range<hb_codepoint_t> (u, 0x1700u, 0x17EFu)) return use_table[u - 0x1700u + use_offset_0x1700u];
if (hb_in_range<hb_codepoint_t> (u, 0x1900u, 0x1A9Fu)) return use_table[u - 0x1900u + use_offset_0x1900u];
if (hb_in_range<hb_codepoint_t> (u, 0x1B00u, 0x1C4Fu)) return use_table[u - 0x1B00u + use_offset_0x1b00u];
if (hb_in_range<hb_codepoint_t> (u, 0x1CD0u, 0x1CFFu)) return use_table[u - 0x1CD0u + use_offset_0x1cd0u];
if (hb_in_range<hb_codepoint_t> (u, 0x1DF8u, 0x1DFFu)) return use_table[u - 0x1DF8u + use_offset_0x1df8u];
break;
case 0x2u:
if (hb_in_range (u, 0x2008u, 0x2017u)) return use_table[u - 0x2008u + use_offset_0x2008u];
if (hb_in_range (u, 0x2060u, 0x2087u)) return use_table[u - 0x2060u + use_offset_0x2060u];
if (hb_in_range<hb_codepoint_t> (u, 0x2008u, 0x2017u)) return use_table[u - 0x2008u + use_offset_0x2008u];
if (hb_in_range<hb_codepoint_t> (u, 0x2060u, 0x2087u)) return use_table[u - 0x2060u + use_offset_0x2060u];
if (unlikely (u == 0x25CCu)) return GB;
break;
case 0xAu:
if (hb_in_range (u, 0xA800u, 0xAAF7u)) return use_table[u - 0xA800u + use_offset_0xa800u];
if (hb_in_range (u, 0xABC0u, 0xABFFu)) return use_table[u - 0xABC0u + use_offset_0xabc0u];
if (hb_in_range<hb_codepoint_t> (u, 0xA800u, 0xAAF7u)) return use_table[u - 0xA800u + use_offset_0xa800u];
if (hb_in_range<hb_codepoint_t> (u, 0xABC0u, 0xABFFu)) return use_table[u - 0xABC0u + use_offset_0xabc0u];
break;
case 0xFu:
if (hb_in_range (u, 0xFE00u, 0xFE0Fu)) return use_table[u - 0xFE00u + use_offset_0xfe00u];
if (hb_in_range<hb_codepoint_t> (u, 0xFE00u, 0xFE0Fu)) return use_table[u - 0xFE00u + use_offset_0xfe00u];
break;
case 0x10u:
if (hb_in_range (u, 0x10A00u, 0x10A47u)) return use_table[u - 0x10A00u + use_offset_0x10a00u];
if (hb_in_range<hb_codepoint_t> (u, 0x10A00u, 0x10A47u)) return use_table[u - 0x10A00u + use_offset_0x10a00u];
break;
case 0x11u:
if (hb_in_range (u, 0x11000u, 0x110BFu)) return use_table[u - 0x11000u + use_offset_0x11000u];
if (hb_in_range (u, 0x11100u, 0x1123Fu)) return use_table[u - 0x11100u + use_offset_0x11100u];
if (hb_in_range (u, 0x11280u, 0x11377u)) return use_table[u - 0x11280u + use_offset_0x11280u];
if (hb_in_range (u, 0x11400u, 0x114DFu)) return use_table[u - 0x11400u + use_offset_0x11400u];
if (hb_in_range (u, 0x11580u, 0x1173Fu)) return use_table[u - 0x11580u + use_offset_0x11580u];
if (hb_in_range (u, 0x11C00u, 0x11CB7u)) return use_table[u - 0x11C00u + use_offset_0x11c00u];
if (hb_in_range<hb_codepoint_t> (u, 0x11000u, 0x110BFu)) return use_table[u - 0x11000u + use_offset_0x11000u];
if (hb_in_range<hb_codepoint_t> (u, 0x11100u, 0x1123Fu)) return use_table[u - 0x11100u + use_offset_0x11100u];
if (hb_in_range<hb_codepoint_t> (u, 0x11280u, 0x11377u)) return use_table[u - 0x11280u + use_offset_0x11280u];
if (hb_in_range<hb_codepoint_t> (u, 0x11400u, 0x114DFu)) return use_table[u - 0x11400u + use_offset_0x11400u];
if (hb_in_range<hb_codepoint_t> (u, 0x11580u, 0x1173Fu)) return use_table[u - 0x11580u + use_offset_0x11580u];
if (hb_in_range<hb_codepoint_t> (u, 0x11C00u, 0x11CB7u)) return use_table[u - 0x11C00u + use_offset_0x11c00u];
if (unlikely (u == 0x1107Fu)) return HN;
break;

View file

@ -354,6 +354,8 @@ setup_syllables (const hb_ot_shape_plan_t *plan,
hb_buffer_t *buffer)
{
find_syllables (buffer);
foreach_syllable (buffer, start, end)
buffer->unsafe_to_break (start, end);
setup_rphf_mask (plan, buffer);
setup_topographical_masks (plan, buffer);
}
@ -572,28 +574,6 @@ decompose_use (const hb_ot_shape_normalize_context_t *c,
*/
case 0x1112Eu : *a = 0x11127u; *b= 0x11131u; return true;
case 0x1112Fu : *a = 0x11127u; *b= 0x11132u; return true;
/*
* Decompose split matras that don't have Unicode decompositions.
*/
/* Limbu */
case 0x1925u : *a = 0x1920u; *b= 0x1923u; return true;
case 0x1926u : *a = 0x1920u; *b= 0x1924u; return true;
/* Balinese */
case 0x1B3Cu : *a = 0x1B42u; *b= 0x1B3Cu; return true;
#if 0
/* Lepcha */
case 0x1C29u : *a = no decomp, -> LEFT; return true;
/* Javanese */
case 0xA9C0u : *a = no decomp, -> RIGHT; return true;
/* Sharada */
case 0x111BFu : *a = no decomp, -> ABOVE; return true;
#endif
}
return (bool) c->unicode->decompose (ab, a, b);

View file

@ -307,6 +307,9 @@ position_around_base (const hb_ot_shape_plan_t *plan,
unsigned int end)
{
hb_direction_t horiz_dir = HB_DIRECTION_INVALID;
buffer->unsafe_to_break (base, end);
hb_glyph_extents_t base_extents;
if (!font->get_glyph_extents (buffer->info[base].codepoint,
&base_extents))

View file

@ -91,7 +91,7 @@ compose_unicode (const hb_ot_shape_normalize_context_t *c,
static inline void
set_glyph (hb_glyph_info_t &info, hb_font_t *font)
{
font->get_nominal_glyph (info.codepoint, &info.glyph_index());
(void) font->get_nominal_glyph (info.codepoint, &info.glyph_index());
}
static inline void

View file

@ -128,6 +128,8 @@ hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner,
* shaper face data
*/
HB_SHAPER_DATA_ENSURE_DEFINE(ot, face)
hb_ot_shaper_face_data_t *
_hb_ot_shaper_face_data_create (hb_face_t *face)
{
@ -145,6 +147,8 @@ _hb_ot_shaper_face_data_destroy (hb_ot_shaper_face_data_t *data)
* shaper font data
*/
HB_SHAPER_DATA_ENSURE_DEFINE(ot, font)
struct hb_ot_shaper_font_data_t {};
hb_ot_shaper_font_data_t *
@ -271,8 +275,7 @@ hb_insert_dotted_circle (hb_buffer_t *buffer, hb_font_t *font)
static void
hb_form_clusters (hb_buffer_t *buffer)
{
if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII) ||
buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES)
if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII))
return;
/* Loop duplicated in hb_ensure_native_direction(), and in _hb-coretext.cc */
@ -284,11 +287,17 @@ hb_form_clusters (hb_buffer_t *buffer)
if (likely (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[i])) &&
!_hb_glyph_info_is_joiner (&info[i])))
{
buffer->merge_clusters (base, i);
if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES)
buffer->merge_clusters (base, i);
else
buffer->unsafe_to_break (base, i);
base = i;
}
}
buffer->merge_clusters (base, count);
if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES)
buffer->merge_clusters (base, count);
else
buffer->unsafe_to_break (base, count);
}
static void
@ -362,7 +371,18 @@ hb_ot_shape_setup_masks_fraction (hb_ot_shape_context_t *c)
hb_buffer_t *buffer = c->buffer;
/* TODO look in pre/post context text also. */
hb_mask_t pre_mask, post_mask;
if (HB_DIRECTION_IS_FORWARD (buffer->props.direction))
{
pre_mask = c->plan->numr_mask | c->plan->frac_mask;
post_mask = c->plan->frac_mask | c->plan->dnom_mask;
}
else
{
pre_mask = c->plan->frac_mask | c->plan->dnom_mask;
post_mask = c->plan->numr_mask | c->plan->frac_mask;
}
unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
for (unsigned int i = 0; i < count; i++)
@ -379,11 +399,13 @@ hb_ot_shape_setup_masks_fraction (hb_ot_shape_context_t *c)
HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER)
end++;
buffer->unsafe_to_break (start, end);
for (unsigned int j = start; j < i; j++)
info[j].mask |= c->plan->numr_mask | c->plan->frac_mask;
info[j].mask |= pre_mask;
info[i].mask |= c->plan->frac_mask;
for (unsigned int j = i + 1; j < end; j++)
info[j].mask |= c->plan->frac_mask | c->plan->dnom_mask;
info[j].mask |= post_mask;
i = end - 1;
}
@ -494,9 +516,10 @@ hb_ot_hide_default_ignorables (hb_ot_shape_context_t *c)
/* Merge cluster backward. */
if (cluster < info[j - 1].cluster)
{
unsigned int mask = info[i].mask;
unsigned int old_cluster = info[j - 1].cluster;
for (unsigned k = j; k && info[k - 1].cluster == old_cluster; k--)
info[k - 1].cluster = cluster;
buffer->set_cluster (info[k - 1], cluster, mask);
}
continue;
}
@ -562,8 +585,6 @@ hb_ot_substitute_default (hb_ot_shape_context_t *c)
{
hb_buffer_t *buffer = c->buffer;
hb_ot_shape_initialize_masks (c);
hb_ot_mirror_chars (c);
HB_BUFFER_ALLOCATE_VAR (buffer, glyph_index);
@ -767,6 +788,31 @@ hb_ot_position (hb_ot_shape_context_t *c)
_hb_buffer_deallocate_gsubgpos_vars (c->buffer);
}
static inline void
hb_propagate_flags (hb_buffer_t *buffer)
{
/* Propagate cluster-level glyph flags to be the same on all cluster glyphs.
* Simplifies using them. */
if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_UNSAFE_TO_BREAK))
return;
hb_glyph_info_t *info = buffer->info;
foreach_cluster (buffer, start, end)
{
unsigned int mask = 0;
for (unsigned int i = start; i < end; i++)
if (info[i].mask & HB_GLYPH_FLAG_UNSAFE_TO_BREAK)
{
mask = HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
break;
}
if (mask)
for (unsigned int i = start; i < end; i++)
info[i].mask |= mask;
}
}
/* Pull it all together! */
@ -793,8 +839,10 @@ hb_ot_shape_internal (hb_ot_shape_context_t *c)
c->buffer->clear_output ();
hb_ot_shape_initialize_masks (c);
hb_set_unicode_props (c->buffer);
hb_insert_dotted_circle (c->buffer, c->font);
hb_form_clusters (c->buffer);
hb_ensure_native_direction (c->buffer);
@ -810,6 +858,8 @@ hb_ot_shape_internal (hb_ot_shape_context_t *c)
if (c->plan->shaper->postprocess_glyphs)
c->plan->shaper->postprocess_glyphs (c->plan, c->buffer, c->font);
hb_propagate_flags (c->buffer);
_hb_buffer_deallocate_unicode_vars (c->buffer);
c->buffer->props.direction = c->target_direction;

View file

@ -28,9 +28,6 @@
#include "hb-private.hh"
#include <string.h>
/* hb_script_t */
@ -201,6 +198,7 @@ static const LangTag ot_languages[] = {
{"alt", HB_TAG('A','L','T',' ')}, /* [Southern] Altai */
{"am", HB_TAG('A','M','H',' ')}, /* Amharic */
{"amf", HB_TAG('H','B','N',' ')}, /* Hammer-Banna */
{"amw", HB_TAG('S','Y','R',' ')}, /* Western Neo-Aramaic */
{"an", HB_TAG('A','R','G',' ')}, /* Aragonese */
{"ang", HB_TAG('A','N','G',' ')}, /* Old English (ca. 450-1100) */
{"ar", HB_TAG('A','R','A',' ')}, /* Arabic [macrolanguage] */
@ -239,6 +237,7 @@ static const LangTag ot_languages[] = {
{"bg", HB_TAG('B','G','R',' ')}, /* Bulgarian */
{"bgc", HB_TAG('B','G','C',' ')}, /* Haryanvi */
{"bgq", HB_TAG('B','G','Q',' ')}, /* Bagri */
{"bgr", HB_TAG('Q','I','N',' ')}, /* Bawm Chin */
{"bhb", HB_TAG('B','H','I',' ')}, /* Bhili */
{"bhk", HB_TAG('B','I','K',' ')}, /* Albay Bicolano (retired code) */
{"bho", HB_TAG('B','H','O',' ')}, /* Bhojpuri */
@ -270,8 +269,10 @@ static const LangTag ot_languages[] = {
{"ca", HB_TAG('C','A','T',' ')}, /* Catalan */
{"cak", HB_TAG('C','A','K',' ')}, /* Kaqchikel */
{"cbk", HB_TAG('C','B','K',' ')}, /* Chavacano */
{"cbl", HB_TAG('Q','I','N',' ')}, /* Bualkhaw Chin */
{"ce", HB_TAG('C','H','E',' ')}, /* Chechen */
{"ceb", HB_TAG('C','E','B',' ')}, /* Cebuano */
{"cfm", HB_TAG('H','A','L',' ')}, /* Halam/Falam Chin */
{"cgg", HB_TAG('C','G','G',' ')}, /* Chiga */
{"ch", HB_TAG('C','H','A',' ')}, /* Chamorro */
{"chk", HB_TAG('C','H','K','0')}, /* Chuukese */
@ -279,8 +280,17 @@ static const LangTag ot_languages[] = {
{"chp", HB_TAG('C','H','P',' ')}, /* Chipewyan */
{"chr", HB_TAG('C','H','R',' ')}, /* Cherokee */
{"chy", HB_TAG('C','H','Y',' ')}, /* Cheyenne */
{"cja", HB_TAG('C','J','A',' ')}, /* Western Cham */
{"cjm", HB_TAG('C','J','M',' ')}, /* Eastern Cham */
{"cka", HB_TAG('Q','I','N',' ')}, /* Khumi Awa Chin */
{"ckb", HB_TAG('K','U','R',' ')}, /* Central Kurdish (Sorani) */
{"ckt", HB_TAG('C','H','K',' ')}, /* Chukchi */
{"cld", HB_TAG('S','Y','R',' ')}, /* Chaldean Neo-Aramaic */
{"cmr", HB_TAG('Q','I','N',' ')}, /* Mro-Khimi Chin */
{"cnb", HB_TAG('Q','I','N',' ')}, /* Chinbon Chin */
{"cnh", HB_TAG('Q','I','N',' ')}, /* Hakha Chin */
{"cnk", HB_TAG('Q','I','N',' ')}, /* Khumi Chin */
{"cnw", HB_TAG('Q','I','N',' ')}, /* Ngawn Chin */
{"cop", HB_TAG('C','O','P',' ')}, /* Coptic */
{"cpp", HB_TAG('C','P','P',' ')}, /* Creoles */
{"cr", HB_TAG('C','R','E',' ')}, /* Cree */
@ -293,6 +303,9 @@ static const LangTag ot_languages[] = {
{"crx", HB_TAG('C','R','R',' ')}, /* Carrier */
{"cs", HB_TAG('C','S','Y',' ')}, /* Czech */
{"csb", HB_TAG('C','S','B',' ')}, /* Kashubian */
{"csh", HB_TAG('Q','I','N',' ')}, /* Asho Chin */
{"csy", HB_TAG('Q','I','N',' ')}, /* Siyin Chin */
{"ctd", HB_TAG('Q','I','N',' ')}, /* Tedim Chin */
{"ctg", HB_TAG('C','T','G',' ')}, /* Chittagonian */
{"cts", HB_TAG('B','I','K',' ')}, /* Northern Catanduanes Bikol */
{"cu", HB_TAG('C','S','L',' ')}, /* Church Slavic */
@ -300,7 +313,9 @@ static const LangTag ot_languages[] = {
{"cv", HB_TAG('C','H','U',' ')}, /* Chuvash */
{"cwd", HB_TAG('D','C','R',' ')}, /* Woods Cree */
{"cy", HB_TAG('W','E','L',' ')}, /* Welsh */
{"czt", HB_TAG('Q','I','N',' ')}, /* Zotung Chin */
{"da", HB_TAG('D','A','N',' ')}, /* Danish */
{"dao", HB_TAG('Q','I','N',' ')}, /* Daai Chin */
{"dap", HB_TAG('N','I','S',' ')}, /* Nisi (India) */
{"dar", HB_TAG('D','A','R',' ')}, /* Dargwa */
{"dax", HB_TAG('D','A','X',' ')}, /* Dayi */
@ -343,7 +358,7 @@ static const LangTag ot_languages[] = {
{"fi", HB_TAG('F','I','N',' ')}, /* Finnish */
{"fil", HB_TAG('P','I','L',' ')}, /* Filipino */
{"fj", HB_TAG('F','J','I',' ')}, /* Fijian */
{"flm", HB_TAG('H','A','L',' ')}, /* Halam */
{"flm", HB_TAG('H','A','L',' ')}, /* Halam/Falam Chin [retired ISO639 code] */
{"fo", HB_TAG('F','O','S',' ')}, /* Faroese */
{"fon", HB_TAG('F','O','N',' ')}, /* Fon */
{"fr", HB_TAG('F','R','A',' ')}, /* French */
@ -390,6 +405,7 @@ static const LangTag ot_languages[] = {
{"he", HB_TAG('I','W','R',' ')}, /* Hebrew */
{"hi", HB_TAG('H','I','N',' ')}, /* Hindi */
{"hil", HB_TAG('H','I','L',' ')}, /* Hiligaynon */
{"hlt", HB_TAG('Q','I','N',' ')}, /* Matu Chin */
{"hmn", HB_TAG('H','M','N',' ')}, /* Hmong */
{"hnd", HB_TAG('H','N','D',' ')}, /* [Southern] Hindko */
{"hne", HB_TAG('C','H','H',' ')}, /* Chattisgarhi */
@ -553,6 +569,7 @@ static const LangTag ot_languages[] = {
{"mos", HB_TAG('M','O','S',' ')}, /* Mossi */
{"mpe", HB_TAG('M','A','J',' ')}, /* Majang */
{"mr", HB_TAG('M','A','R',' ')}, /* Marathi */
{"mrh", HB_TAG('Q','I','N',' ')}, /* Mara Chin */
{"mrj", HB_TAG('H','M','A',' ')}, /* High Mari */
{"ms", HB_TAG('M','L','Y',' ')}, /* Malay [macrolanguage] */
{"msc", HB_TAG('M','N','K',' ')}, /* Sankaran Maninka */
@ -617,6 +634,7 @@ static const LangTag ot_languages[] = {
{"pcc", HB_TAG('P','C','C',' ')}, /* Bouyei */
{"pcd", HB_TAG('P','C','D',' ')}, /* Picard */
{"pce", HB_TAG('P','L','G',' ')}, /* [Ruching] Palaung */
{"pck", HB_TAG('Q','I','N',' ')}, /* Paite Chin */
{"pdc", HB_TAG('P','D','C',' ')}, /* Pennsylvania German */
{"pes", HB_TAG('F','A','R',' ')}, /* Iranian Persian */
{"phk", HB_TAG('P','H','K',' ')}, /* Phake */
@ -674,6 +692,7 @@ static const LangTag ot_languages[] = {
{"se", HB_TAG('N','S','M',' ')}, /* Northern Sami */
{"seh", HB_TAG('S','N','A',' ')}, /* Sena */
{"sel", HB_TAG('S','E','L',' ')}, /* Selkup */
{"sez", HB_TAG('Q','I','N',' ')}, /* Senthang Chin */
{"sg", HB_TAG('S','G','O',' ')}, /* Sango */
{"sga", HB_TAG('S','G','A',' ')}, /* Old Irish (to 900) */
{"sgs", HB_TAG('S','G','S',' ')}, /* Samogitian */
@ -713,12 +732,15 @@ static const LangTag ot_languages[] = {
{"swh", HB_TAG('S','W','K',' ')}, /* Kiswahili/Swahili */
{"swv", HB_TAG('M','A','W',' ')}, /* Shekhawati */
{"sxu", HB_TAG('S','X','U',' ')}, /* Upper Saxon */
{"syc", HB_TAG('S','Y','R',' ')}, /* Classical Syriac */
{"syl", HB_TAG('S','Y','L',' ')}, /* Sylheti */
{"syr", HB_TAG('S','Y','R',' ')}, /* Syriac [macrolanguage] */
{"szl", HB_TAG('S','Z','L',' ')}, /* Silesian */
{"ta", HB_TAG('T','A','M',' ')}, /* Tamil */
{"tab", HB_TAG('T','A','B',' ')}, /* Tabasaran */
{"tcp", HB_TAG('Q','I','N',' ')}, /* Tawr Chin */
{"tcy", HB_TAG('T','U','L',' ')}, /* Tulu */
{"tcz", HB_TAG('Q','I','N',' ')}, /* Thado Chin */
{"tdd", HB_TAG('T','D','D',' ')}, /* Tai Nüa */
{"te", HB_TAG('T','E','L',' ')}, /* Telugu */
{"tem", HB_TAG('T','M','N',' ')}, /* Temne */
@ -786,11 +808,13 @@ static const LangTag ot_languages[] = {
{"yap", HB_TAG('Y','A','P',' ')}, /* Yapese */
{"yi", HB_TAG('J','I','I',' ')}, /* Yiddish [macrolanguage] */
{"yo", HB_TAG('Y','B','A',' ')}, /* Yoruba */
{"yos", HB_TAG('Q','I','N',' ')}, /* Yos, deprecated by IANA in favor of Zou [zom] */
{"yso", HB_TAG('N','I','S',' ')}, /* Nisi (China) */
{"za", HB_TAG('Z','H','A',' ')}, /* Chuang/Zhuang [macrolanguage] */
{"zea", HB_TAG('Z','E','A',' ')}, /* Zeeuws */
{"zgh", HB_TAG('Z','G','H',' ')}, /* Standard Morrocan Tamazigh */
{"zne", HB_TAG('Z','N','D',' ')}, /* Zande */
{"zom", HB_TAG('Q','I','N',' ')}, /* Zou */
{"zu", HB_TAG('Z','U','L',' ')}, /* Zulu */
{"zum", HB_TAG('L','R','C',' ')}, /* Kumzari */
{"zza", HB_TAG('Z','Z','A',' ')}, /* Zazaki */
@ -907,6 +931,30 @@ hb_ot_tag_from_language (hb_language_t language)
return HB_TAG('A','P','P','H'); /* Phonetic transcription—Americanist conventions */
}
/*
* "Syre" is a BCP-47 script tag, meaning the Estrangela variant of the Syriac script.
* It can be applied to any language.
*/
if (strstr (lang_str, "-syre")) {
return HB_TAG('S','Y','R','E'); /* Estrangela Syriac */
}
/*
* "Syrj" is a BCP-47 script tag, meaning the Western variant of the Syriac script.
* It can be applied to any language.
*/
if (strstr (lang_str, "-syrj")) {
return HB_TAG('S','Y','R','J'); /* Western Syriac */
}
/*
* "Syrn" is a BCP-47 script tag, meaning the Eastern variant of the Syriac script.
* It can be applied to any language.
*/
if (strstr (lang_str, "-syrn")) {
return HB_TAG('S','Y','R','N'); /* Eastern Syriac */
}
/* Find a language matching in the first component */
{
const LangTag *lang_tag;
@ -962,6 +1010,22 @@ hb_ot_tag_to_language (hb_tag_t tag)
if (tag == HB_OT_TAG_DEFAULT_LANGUAGE)
return NULL;
/* struct LangTag has only room for 3-letter language tags. */
switch (tag) {
case HB_TAG('A','P','P','H'): /* Phonetic transcription—Americanist conventions */
return hb_language_from_string ("und-fonnapa", -1);
case HB_TAG('I','P','P','H'): /* Phonetic transcription—IPA conventions */
return hb_language_from_string ("und-fonipa", -1);
case HB_TAG('S','Y','R',' '): /* Syriac [macrolanguage] */
return hb_language_from_string ("syr", -1);
case HB_TAG('S','Y','R','E'): /* Estrangela Syriac */
return hb_language_from_string ("und-Syre", -1);
case HB_TAG('S','Y','R','J'): /* Western Syriac */
return hb_language_from_string ("und-Syrj", -1);
case HB_TAG('S','Y','R','N'): /* Eastern Syriac */
return hb_language_from_string ("und-Syrn", -1);
}
for (i = 0; i < ARRAY_LENGTH (ot_languages); i++)
if (ot_languages[i].tag == tag)
return hb_language_from_string (ot_languages[i].language, -1);
@ -976,14 +1040,6 @@ hb_ot_tag_to_language (hb_tag_t tag)
}
}
/* struct LangTag has only room for 3-letter language tags. */
switch (tag) {
case HB_TAG('A','P','P','H'): /* Phonetic transcription—Americanist conventions */
return hb_language_from_string ("und-fonnapa", -1);
case HB_TAG('I','P','P','H'): /* Phonetic transcription—IPA conventions */
return hb_language_from_string ("und-fonipa", -1);
}
/* Else return a custom language in the form of "x-hbotABCD" */
{
unsigned char buf[11] = "x-hbot";

View file

@ -0,0 +1,149 @@
/*
* Copyright © 2017 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_VAR_AVAR_TABLE_HH
#define HB_OT_VAR_AVAR_TABLE_HH
#include "hb-open-type-private.hh"
namespace OT {
struct AxisValueMap
{
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this));
}
public:
F2DOT14 fromCoord; /* A normalized coordinate value obtained using
* default normalization. */
F2DOT14 toCoord; /* The modified, normalized coordinate value. */
public:
DEFINE_SIZE_STATIC (4);
};
struct SegmentMaps : ArrayOf<AxisValueMap>
{
inline int map (int value) const
{
/* The following special-cases are not part of OpenType, which requires
* that at least -1, 0, and +1 must be mapped. But we include these as
* part of a better error recovery scheme. */
if (len < 2)
{
if (!len)
return value;
else /* len == 1*/
return value - array[0].fromCoord + array[0].toCoord;
}
if (value <= array[0].fromCoord)
return value - array[0].fromCoord + array[0].toCoord;
unsigned int i;
unsigned int count = len;
for (i = 1; i < count && value > array[i].fromCoord; i++)
;
if (value >= array[i].fromCoord)
return value - array[i].fromCoord + array[i].toCoord;
if (unlikely (array[i-1].fromCoord == array[i].fromCoord))
return array[i-1].toCoord;
int denom = array[i].fromCoord - array[i-1].fromCoord;
return array[i-1].toCoord +
((array[i].toCoord - array[i-1].toCoord) *
(value - array[i-1].fromCoord) + denom/2) / denom;
}
DEFINE_SIZE_ARRAY (2, array);
};
/*
* avar Axis Variations Table
*/
#define HB_OT_TAG_avar HB_TAG('a','v','a','r')
struct avar
{
static const hb_tag_t tableTag = HB_OT_TAG_avar;
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
if (unlikely (!(version.sanitize (c) &&
version.major == 1 &&
c->check_struct (this))))
return_trace (false);
const SegmentMaps *map = &axisSegmentMapsZ;
unsigned int count = axisCount;
for (unsigned int i = 0; i < count; i++)
{
if (unlikely (!map->sanitize (c)))
return_trace (false);
map = &StructAfter<SegmentMaps> (*map);
}
return_trace (true);
}
inline void map_coords (int *coords, unsigned int coords_length) const
{
unsigned int count = MIN<unsigned int> (coords_length, axisCount);
const SegmentMaps *map = &axisSegmentMapsZ;
for (unsigned int i = 0; i < count; i++)
{
coords[i] = map->map (coords[i]);
map = &StructAfter<SegmentMaps> (*map);
}
}
protected:
FixedVersion<>version; /* Version of the avar table
* initially set to 0x00010000u */
USHORT reserved; /* This field is permanently reserved. Set to 0. */
USHORT axisCount; /* The number of variation axes in the font. This
* must be the same number as axisCount in the
* 'fvar' table. */
SegmentMaps axisSegmentMapsZ;
public:
DEFINE_SIZE_MIN (8);
};
} /* namespace OT */
#endif /* HB_OT_VAR_AVAR_TABLE_HH */

View file

@ -0,0 +1,209 @@
/*
* Copyright © 2017 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_VAR_FVAR_TABLE_HH
#define HB_OT_VAR_FVAR_TABLE_HH
#include "hb-open-type-private.hh"
namespace OT {
struct InstanceRecord
{
inline bool sanitize (hb_sanitize_context_t *c, unsigned int axis_count) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
c->check_array (coordinates, coordinates[0].static_size, axis_count));
}
protected:
USHORT subfamilyNameID;/* The name ID for entries in the 'name' table
* that provide subfamily names for this instance. */
USHORT reserved; /* Reserved for future use — set to 0. */
Fixed coordinates[VAR];/* The coordinates array for this instance. */
//USHORT postScriptNameIDX;/*Optional. The name ID for entries in the 'name'
// * table that provide PostScript names for this
// * instance. */
public:
DEFINE_SIZE_ARRAY (4, coordinates);
};
struct AxisRecord
{
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this));
}
public:
Tag axisTag; /* Tag identifying the design variation for the axis. */
Fixed minValue; /* The minimum coordinate value for the axis. */
Fixed defaultValue; /* The default coordinate value for the axis. */
Fixed maxValue; /* The maximum coordinate value for the axis. */
USHORT reserved; /* Reserved for future use — set to 0. */
USHORT axisNameID; /* The name ID for entries in the 'name' table that
* provide a display name for this axis. */
public:
DEFINE_SIZE_STATIC (20);
};
/*
* fvar Font Variations Table
*/
#define HB_OT_TAG_fvar HB_TAG('f','v','a','r')
struct fvar
{
static const hb_tag_t tableTag = HB_OT_TAG_fvar;
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (version.sanitize (c) &&
likely (version.major == 1) &&
c->check_struct (this) &&
instanceSize >= axisCount * 4 + 4 &&
axisSize <= 1024 && /* Arbitrary, just to simplify overflow checks. */
instanceSize <= 1024 && /* Arbitrary, just to simplify overflow checks. */
c->check_range (this, things) &&
c->check_range (&StructAtOffset<char> (this, things),
axisCount * axisSize + instanceCount * instanceSize));
}
inline unsigned int get_axis_count (void) const
{ return axisCount; }
inline bool get_axis (unsigned int index, hb_ot_var_axis_t *info) const
{
if (unlikely (index >= axisCount))
return false;
if (info)
{
const AxisRecord &axis = get_axes ()[index];
info->tag = axis.axisTag;
info->name_id = axis.axisNameID;
info->default_value = axis.defaultValue / 65536.;
/* Ensure order, to simplify client math. */
info->min_value = MIN<float> (info->default_value, axis.minValue / 65536.);
info->max_value = MAX<float> (info->default_value, axis.maxValue / 65536.);
}
return true;
}
inline unsigned int get_axis_infos (unsigned int start_offset,
unsigned int *axes_count /* IN/OUT */,
hb_ot_var_axis_t *axes_array /* OUT */) const
{
if (axes_count)
{
unsigned int count = axisCount;
start_offset = MIN (start_offset, count);
count -= start_offset;
axes_array += start_offset;
count = MIN (count, *axes_count);
*axes_count = count;
for (unsigned int i = 0; i < count; i++)
get_axis (start_offset + i, axes_array + i);
}
return axisCount;
}
inline bool find_axis (hb_tag_t tag, unsigned int *index, hb_ot_var_axis_t *info) const
{
const AxisRecord *axes = get_axes ();
unsigned int count = get_axis_count ();
for (unsigned int i = 0; i < count; i++)
if (axes[i].axisTag == tag)
{
if (index)
*index = i;
return get_axis (i, info);
}
if (index)
*index = HB_OT_VAR_NO_AXIS_INDEX;
return false;
}
inline int normalize_axis_value (unsigned int axis_index, float v) const
{
hb_ot_var_axis_t axis;
if (!get_axis (axis_index, &axis))
return 0;
v = MAX (MIN (v, axis.max_value), axis.min_value); /* Clamp. */
if (v == axis.default_value)
return 0;
else if (v < axis.default_value)
v = (v - axis.default_value) / (axis.default_value - axis.min_value);
else
v = (v - axis.default_value) / (axis.max_value - axis.default_value);
return (int) (v * 16384. + (v >= 0. ? .5 : -.5));
}
protected:
inline const AxisRecord * get_axes (void) const
{ return &StructAtOffset<AxisRecord> (this, things); }
inline const InstanceRecord * get_instances (void) const
{ return &StructAtOffset<InstanceRecord> (get_axes () + axisCount, 0); }
protected:
FixedVersion<>version; /* Version of the fvar table
* initially set to 0x00010000u */
Offset<> things; /* Offset in bytes from the beginning of the table
* to the start of the AxisRecord array. */
USHORT reserved; /* This field is permanently reserved. Set to 2. */
USHORT axisCount; /* The number of variation axes in the font (the
* number of records in the axes array). */
USHORT axisSize; /* The size in bytes of each VariationAxisRecord —
* set to 20 (0x0014) for this version. */
USHORT instanceCount; /* The number of named instances defined in the font
* (the number of records in the instances array). */
USHORT instanceSize; /* The size in bytes of each InstanceRecord — set
* to either axisCount * sizeof(Fixed) + 4, or to
* axisCount * sizeof(Fixed) + 6. */
public:
DEFINE_SIZE_STATIC (16);
};
} /* namespace OT */
#endif /* HB_OT_VAR_FVAR_TABLE_HH */

View file

@ -0,0 +1,165 @@
/*
* Copyright © 2017 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_VAR_HVAR_TABLE_HH
#define HB_OT_VAR_HVAR_TABLE_HH
#include "hb-ot-layout-common-private.hh"
namespace OT {
struct DeltaSetIndexMap
{
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
c->check_array (mapData, get_width (), mapCount));
}
unsigned int map (unsigned int v) const /* Returns 16.16 outer.inner. */
{
/* If count is zero, pass value unchanged. This takes
* care of direct mapping for advance map. */
if (!mapCount)
return v;
if (v >= mapCount)
v = mapCount - 1;
unsigned int u = 0;
{ /* Fetch it. */
unsigned int w = get_width ();
const BYTE *p = mapData + w * v;
for (; w; w--)
u = (u << 8) + *p++;
}
{ /* Repack it. */
unsigned int n = get_inner_bitcount ();
unsigned int outer = u >> n;
unsigned int inner = u & ((1 << n) - 1);
u = (outer<<16) | inner;
}
return u;
}
protected:
inline unsigned int get_width (void) const
{ return ((format >> 4) & 3) + 1; }
inline unsigned int get_inner_bitcount (void) const
{ return (format & 0xF) + 1; }
protected:
USHORT format; /* A packed field that describes the compressed
* representation of delta-set indices. */
USHORT mapCount; /* The number of mapping entries. */
BYTE mapData[VAR]; /* The delta-set index mapping data. */
public:
DEFINE_SIZE_ARRAY (4, mapData);
};
/*
* HVAR -- The Horizontal Metrics Variations Table
* VVAR -- The Vertical Metrics Variations Table
*/
#define HB_OT_TAG_HVAR HB_TAG('H','V','A','R')
#define HB_OT_TAG_VVAR HB_TAG('V','V','A','R')
struct HVARVVAR
{
static const hb_tag_t HVARTag = HB_OT_TAG_HVAR;
static const hb_tag_t VVARTag = HB_OT_TAG_VVAR;
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (version.sanitize (c) &&
likely (version.major == 1) &&
varStore.sanitize (c, this) &&
advMap.sanitize (c, this) &&
lsbMap.sanitize (c, this) &&
rsbMap.sanitize (c, this));
}
inline float get_advance_var (hb_codepoint_t glyph,
int *coords, unsigned int coord_count) const
{
unsigned int varidx = (this+advMap).map (glyph);
return (this+varStore).get_delta (varidx, coords, coord_count);
}
inline bool has_sidebearing_deltas (void) const
{ return lsbMap && rsbMap; }
protected:
FixedVersion<>version; /* Version of the metrics variation table
* initially set to 0x00010000u */
LOffsetTo<VariationStore>
varStore; /* Offset to item variation store table. */
LOffsetTo<DeltaSetIndexMap>
advMap; /* Offset to advance var-idx mapping. */
LOffsetTo<DeltaSetIndexMap>
lsbMap; /* Offset to lsb/tsb var-idx mapping. */
LOffsetTo<DeltaSetIndexMap>
rsbMap; /* Offset to rsb/bsb var-idx mapping. */
public:
DEFINE_SIZE_STATIC (20);
};
struct HVAR : HVARVVAR {
static const hb_tag_t tableTag = HB_OT_TAG_HVAR;
};
struct VVAR : HVARVVAR {
static const hb_tag_t tableTag = HB_OT_TAG_VVAR;
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (static_cast<const HVARVVAR *> (this)->sanitize (c) &&
vorgMap.sanitize (c, this));
}
protected:
LOffsetTo<DeltaSetIndexMap>
vorgMap; /* Offset to vertical-origin var-idx mapping. */
public:
DEFINE_SIZE_STATIC (24);
};
} /* namespace OT */
#endif /* HB_OT_VAR_HVAR_TABLE_HH */

View file

@ -0,0 +1,110 @@
/*
* Copyright © 2017 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_VAR_MVAR_TABLE_HH
#define HB_OT_VAR_MVAR_TABLE_HH
#include "hb-ot-layout-common-private.hh"
namespace OT {
struct VariationValueRecord
{
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this));
}
public:
Tag valueTag; /* Four-byte tag identifying a font-wide measure. */
ULONG varIdx; /* Outer/inner index into VariationStore item. */
public:
DEFINE_SIZE_STATIC (8);
};
/*
* MVAR -- Metrics Variations Table
*/
#define HB_OT_TAG_MVAR HB_TAG('M','V','A','R')
struct MVAR
{
static const hb_tag_t tableTag = HB_OT_TAG_MVAR;
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (version.sanitize (c) &&
likely (version.major == 1) &&
c->check_struct (this) &&
valueRecordSize >= VariationValueRecord::static_size &&
varStore.sanitize (c, this) &&
c->check_array (values, valueRecordSize, valueRecordCount));
}
inline float get_var (hb_tag_t tag,
int *coords, unsigned int coord_count) const
{
const VariationValueRecord *record;
record = (VariationValueRecord *) bsearch (&tag, values,
valueRecordCount, valueRecordSize,
(hb_compare_func_t) tag_compare);
if (!record)
return 0.;
return (this+varStore).get_delta (record->varIdx, coords, coord_count);
}
protected:
static inline int tag_compare (const hb_tag_t *a, const Tag *b)
{ return b->cmp (*a); }
protected:
FixedVersion<>version; /* Version of the metrics variation table
* initially set to 0x00010000u */
USHORT reserved; /* Not used; set to 0. */
USHORT valueRecordSize;/* The size in bytes of each value record —
* must be greater than zero. */
USHORT valueRecordCount;/* The number of value records — may be zero. */
OffsetTo<VariationStore>
varStore; /* Offset to item variation store table. */
BYTE values[VAR]; /* Array of value records. The records must be
* in binary order of their valueTag field. */
public:
DEFINE_SIZE_ARRAY (12, values);
};
} /* namespace OT */
#endif /* HB_OT_VAR_MVAR_TABLE_HH */

View file

@ -0,0 +1,159 @@
/*
* Copyright © 2017 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
*/
#include "hb-open-type-private.hh"
#include "hb-ot-layout-private.hh"
#include "hb-ot-var-avar-table.hh"
#include "hb-ot-var-fvar-table.hh"
#include "hb-ot-var-mvar-table.hh"
#include "hb-ot-var.h"
/*
* fvar/avar
*/
static inline const OT::fvar&
_get_fvar (hb_face_t *face)
{
if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return OT::Null(OT::fvar);
hb_ot_layout_t * layout = hb_ot_layout_from_face (face);
return *(layout->fvar.get ());
}
static inline const OT::avar&
_get_avar (hb_face_t *face)
{
if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return OT::Null(OT::avar);
hb_ot_layout_t * layout = hb_ot_layout_from_face (face);
return *(layout->avar.get ());
}
/**
* hb_ot_var_has_data:
* @face: #hb_face_t to test
*
* This function allows to verify the presence of OpenType variation data on the face.
* Alternatively, use hb_ot_var_get_axis_count().
*
* Return value: true if face has a `fvar' table and false otherwise
*
* Since: 1.4.2
**/
hb_bool_t
hb_ot_var_has_data (hb_face_t *face)
{
return &_get_fvar (face) != &OT::Null(OT::fvar);
}
/**
* hb_ot_var_get_axis_count:
*
* Since: 1.4.2
**/
unsigned int
hb_ot_var_get_axis_count (hb_face_t *face)
{
const OT::fvar &fvar = _get_fvar (face);
return fvar.get_axis_count ();
}
/**
* hb_ot_var_get_axes:
*
* Since: 1.4.2
**/
unsigned int
hb_ot_var_get_axes (hb_face_t *face,
unsigned int start_offset,
unsigned int *axes_count /* IN/OUT */,
hb_ot_var_axis_t *axes_array /* OUT */)
{
const OT::fvar &fvar = _get_fvar (face);
return fvar.get_axis_infos (start_offset, axes_count, axes_array);
}
/**
* hb_ot_var_find_axis:
*
* Since: 1.4.2
**/
hb_bool_t
hb_ot_var_find_axis (hb_face_t *face,
hb_tag_t axis_tag,
unsigned int *axis_index,
hb_ot_var_axis_t *axis_info)
{
const OT::fvar &fvar = _get_fvar (face);
return fvar.find_axis (axis_tag, axis_index, axis_info);
}
/**
* hb_ot_var_normalize_variations:
*
* Since: 1.4.2
**/
void
hb_ot_var_normalize_variations (hb_face_t *face,
const hb_variation_t *variations, /* IN */
unsigned int variations_length,
int *coords, /* OUT */
unsigned int coords_length)
{
for (unsigned int i = 0; i < coords_length; i++)
coords[i] = 0;
const OT::fvar &fvar = _get_fvar (face);
for (unsigned int i = 0; i < variations_length; i++)
{
unsigned int axis_index;
if (hb_ot_var_find_axis (face, variations[i].tag, &axis_index, NULL) &&
axis_index < coords_length)
coords[axis_index] = fvar.normalize_axis_value (axis_index, variations[i].value);
}
const OT::avar &avar = _get_avar (face);
avar.map_coords (coords, coords_length);
}
/**
* hb_ot_var_normalize_coords:
*
* Since: 1.4.2
**/
void
hb_ot_var_normalize_coords (hb_face_t *face,
unsigned int coords_length,
const float *design_coords, /* IN */
int *normalized_coords /* OUT */)
{
const OT::fvar &fvar = _get_fvar (face);
for (unsigned int i = 0; i < coords_length; i++)
normalized_coords[i] = fvar.normalize_axis_value (i, design_coords[i]);
const OT::avar &avar = _get_avar (face);
avar.map_coords (normalized_coords, coords_length);
}

View file

@ -0,0 +1,105 @@
/*
* Copyright © 2017 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.
*
* Red Hat Author(s): Behdad Esfahbod
*/
#ifndef HB_OT_H_IN
#error "Include <hb-ot.h> instead."
#endif
#ifndef HB_OT_VAR_H
#define HB_OT_VAR_H
#include "hb.h"
HB_BEGIN_DECLS
#define HB_OT_TAG_VAR_AXIS_ITALIC HB_TAG('i','t','a','l')
#define HB_OT_TAG_VAR_AXIS_OPTICAL_SIZE HB_TAG('o','p','s','z')
#define HB_OT_TAG_VAR_AXIS_SLANT HB_TAG('s','l','n','t')
#define HB_OT_TAG_VAR_AXIS_WIDTH HB_TAG('w','d','t','h')
#define HB_OT_TAG_VAR_AXIS_WEIGHT HB_TAG('w','g','h','t')
/*
* fvar / avar
*/
/**
* hb_ot_var_axis_t:
*
* Since: 1.4.2
*/
typedef struct hb_ot_var_axis_t {
hb_tag_t tag;
unsigned int name_id;
float min_value;
float default_value;
float max_value;
} hb_ot_var_axis_t;
HB_EXTERN hb_bool_t
hb_ot_var_has_data (hb_face_t *face);
/**
* HB_OT_VAR_NO_AXIS_INDEX:
*
* Since: 1.4.2
*/
#define HB_OT_VAR_NO_AXIS_INDEX 0xFFFFFFFFu
HB_EXTERN unsigned int
hb_ot_var_get_axis_count (hb_face_t *face);
HB_EXTERN unsigned int
hb_ot_var_get_axes (hb_face_t *face,
unsigned int start_offset,
unsigned int *axes_count /* IN/OUT */,
hb_ot_var_axis_t *axes_array /* OUT */);
HB_EXTERN hb_bool_t
hb_ot_var_find_axis (hb_face_t *face,
hb_tag_t axis_tag,
unsigned int *axis_index,
hb_ot_var_axis_t *axis_info);
HB_EXTERN void
hb_ot_var_normalize_variations (hb_face_t *face,
const hb_variation_t *variations, /* IN */
unsigned int variations_length,
int *coords, /* OUT */
unsigned int coords_length);
HB_EXTERN void
hb_ot_var_normalize_coords (hb_face_t *face,
unsigned int coords_length,
const float *design_coords, /* IN */
int *normalized_coords /* OUT */);
HB_END_DECLS
#endif /* HB_OT_VAR_H */

View file

@ -35,6 +35,7 @@
#include "hb-ot-math.h"
#include "hb-ot-tag.h"
#include "hb-ot-shape.h"
#include "hb-ot-var.h"
HB_BEGIN_DECLS

View file

@ -74,10 +74,9 @@ extern "C" void hb_free_impl(void *ptr);
/* Compiler attributes */
#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))
#if (defined(__GNUC__) || defined(__clang__)) && defined(__OPTIMIZE__)
#define likely(expr) (__builtin_expect (!!(expr), 1))
#define unlikely(expr) (__builtin_expect (!!(expr), 0))
#else
#define likely(expr) (expr)
#define unlikely(expr) (expr)
@ -168,7 +167,6 @@ extern "C" void hb_free_impl(void *ptr);
# if defined(_WIN32_WCE)
/* Some things not defined on Windows CE. */
# define strdup _strdup
# define vsnprintf _vsnprintf
# define getenv(Name) NULL
# if _WIN32_WCE < 0x800
@ -180,9 +178,6 @@ static int errno = 0; /* Use something better? */
# endif
# if defined(_MSC_VER) && _MSC_VER < 1900
# define snprintf _snprintf
# elif defined(_MSC_VER) && _MSC_VER >= 1900
# /* Covers VC++ Error for strdup being a deprecated POSIX name and to instead use _strdup instead */
# define strdup _strdup
# endif
#endif

View file

@ -105,7 +105,7 @@ hb_set_destroy (hb_set_t *set)
* @set: a set.
* @key:
* @data:
* @destroy (closure data):
* @destroy:
* @replace:
*
* Return value:

View file

@ -35,13 +35,6 @@
#endif
#define HB_SHAPER_IMPLEMENT(shaper) \
HB_SHAPER_DATA_ENSURE_DECLARE(shaper, face) \
HB_SHAPER_DATA_ENSURE_DECLARE(shaper, font)
#include "hb-shaper-list.hh"
#undef HB_SHAPER_IMPLEMENT
static void
hb_shape_plan_plan (hb_shape_plan_t *shape_plan,
const hb_feature_t *user_features,
@ -167,7 +160,7 @@ hb_shape_plan_create2 (hb_face_t *face,
assert (props->direction != HB_DIRECTION_INVALID);
hb_face_make_immutable (face);
shape_plan->default_shaper_list = shaper_list == NULL;
shape_plan->default_shaper_list = !shaper_list;
shape_plan->face_unsafe = face;
shape_plan->props = *props;
shape_plan->num_user_features = num_user_features;
@ -430,7 +423,7 @@ hb_shape_plan_matches (const hb_shape_plan_t *shape_plan,
return hb_segment_properties_equal (&shape_plan->props, &proposal->props) &&
hb_shape_plan_user_features_match (shape_plan, proposal) &&
hb_shape_plan_coords_match (shape_plan, proposal) &&
((shape_plan->default_shaper_list && proposal->shaper_list == NULL) ||
((shape_plan->default_shaper_list && !proposal->shaper_list) ||
(shape_plan->shaper_func == proposal->shaper_func));
}
@ -438,11 +431,12 @@ static inline hb_bool_t
hb_non_global_user_features_present (const hb_feature_t *user_features,
unsigned int num_user_features)
{
while (num_user_features)
while (num_user_features) {
if (user_features->start != 0 || user_features->end != (unsigned int) -1)
return true;
else
num_user_features--, user_features++;
num_user_features--;
user_features++;
}
return false;
}

View file

@ -45,254 +45,6 @@
* contains the output glyphs and their positions.
**/
static bool
parse_space (const char **pp, const char *end)
{
while (*pp < end && ISSPACE (**pp))
(*pp)++;
return true;
}
static bool
parse_char (const char **pp, const char *end, char c)
{
parse_space (pp, end);
if (*pp == end || **pp != c)
return false;
(*pp)++;
return true;
}
static bool
parse_uint (const char **pp, const char *end, unsigned int *pv)
{
char buf[32];
unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - *pp));
strncpy (buf, *pp, len);
buf[len] = '\0';
char *p = buf;
char *pend = p;
unsigned int v;
/* Intentionally use strtol instead of strtoul, such that
* -1 turns into "big number"... */
errno = 0;
v = strtol (p, &pend, 0);
if (errno || p == pend)
return false;
*pv = v;
*pp += pend - p;
return true;
}
static bool
parse_bool (const char **pp, const char *end, unsigned int *pv)
{
parse_space (pp, end);
const char *p = *pp;
while (*pp < end && ISALPHA(**pp))
(*pp)++;
/* CSS allows on/off as aliases 1/0. */
if (*pp - p == 2 || 0 == strncmp (p, "on", 2))
*pv = 1;
else if (*pp - p == 3 || 0 == strncmp (p, "off", 2))
*pv = 0;
else
return false;
return true;
}
static bool
parse_feature_value_prefix (const char **pp, const char *end, hb_feature_t *feature)
{
if (parse_char (pp, end, '-'))
feature->value = 0;
else {
parse_char (pp, end, '+');
feature->value = 1;
}
return true;
}
static bool
parse_feature_tag (const char **pp, const char *end, hb_feature_t *feature)
{
parse_space (pp, end);
char quote = 0;
if (*pp < end && (**pp == '\'' || **pp == '"'))
{
quote = **pp;
(*pp)++;
}
const char *p = *pp;
while (*pp < end && ISALNUM(**pp))
(*pp)++;
if (p == *pp || *pp - p > 4)
return false;
feature->tag = hb_tag_from_string (p, *pp - p);
if (quote)
{
/* CSS expects exactly four bytes. And we only allow quotations for
* CSS compatibility. So, enforce the length. */
if (*pp - p != 4)
return false;
if (*pp == end || **pp != quote)
return false;
(*pp)++;
}
return true;
}
static bool
parse_feature_indices (const char **pp, const char *end, hb_feature_t *feature)
{
parse_space (pp, end);
bool has_start;
feature->start = 0;
feature->end = (unsigned int) -1;
if (!parse_char (pp, end, '['))
return true;
has_start = parse_uint (pp, end, &feature->start);
if (parse_char (pp, end, ':')) {
parse_uint (pp, end, &feature->end);
} else {
if (has_start)
feature->end = feature->start + 1;
}
return parse_char (pp, end, ']');
}
static bool
parse_feature_value_postfix (const char **pp, const char *end, hb_feature_t *feature)
{
bool had_equal = parse_char (pp, end, '=');
bool had_value = parse_uint (pp, end, &feature->value) ||
parse_bool (pp, end, &feature->value);
/* CSS doesn't use equal-sign between tag and value.
* If there was an equal-sign, then there *must* be a value.
* A value without an eqaul-sign is ok, but not required. */
return !had_equal || had_value;
}
static bool
parse_one_feature (const char **pp, const char *end, hb_feature_t *feature)
{
return parse_feature_value_prefix (pp, end, feature) &&
parse_feature_tag (pp, end, feature) &&
parse_feature_indices (pp, end, feature) &&
parse_feature_value_postfix (pp, end, feature) &&
parse_space (pp, end) &&
*pp == end;
}
/**
* hb_feature_from_string:
* @str: (array length=len) (element-type uint8_t): a string to parse
* @len: length of @str, or -1 if string is %NULL terminated
* @feature: (out): the #hb_feature_t to initialize with the parsed values
*
* Parses a string into a #hb_feature_t.
*
* TODO: document the syntax here.
*
* Return value:
* %true if @str is successfully parsed, %false otherwise.
*
* Since: 0.9.5
**/
hb_bool_t
hb_feature_from_string (const char *str, int len,
hb_feature_t *feature)
{
hb_feature_t feat;
if (len < 0)
len = strlen (str);
if (likely (parse_one_feature (&str, str + len, &feat)))
{
if (feature)
*feature = feat;
return true;
}
if (feature)
memset (feature, 0, sizeof (*feature));
return false;
}
/**
* hb_feature_to_string:
* @feature: an #hb_feature_t to convert
* @buf: (array length=size) (out): output string
* @size: the allocated size of @buf
*
* Converts a #hb_feature_t into a %NULL-terminated string in the format
* understood by hb_feature_from_string(). The client in responsible for
* allocating big enough size for @buf, 128 bytes is more than enough.
*
* Since: 0.9.5
**/
void
hb_feature_to_string (hb_feature_t *feature,
char *buf, unsigned int size)
{
if (unlikely (!size)) return;
char s[128];
unsigned int len = 0;
if (feature->value == 0)
s[len++] = '-';
hb_tag_to_string (feature->tag, s + len);
len += 4;
while (len && s[len - 1] == ' ')
len--;
if (feature->start != 0 || feature->end != (unsigned int) -1)
{
s[len++] = '[';
if (feature->start)
len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->start));
if (feature->end != feature->start + 1) {
s[len++] = ':';
if (feature->end != (unsigned int) -1)
len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->end));
}
s[len++] = ']';
}
if (feature->value > 1)
{
s[len++] = '=';
len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->value));
}
assert (len < ARRAY_LENGTH (s));
len = MIN (len, size - 1);
memcpy (buf, s, len);
buf[len] = '\0';
}
static const char **static_shaper_list;
#ifdef HB_USE_ATEXIT
@ -362,7 +114,7 @@ retry:
* shapers will be used in the given order, otherwise the default shapers list
* will be used.
*
* Return value: %FALSE if all shapers failed, %TRUE otherwise
* Return value: false if all shapers failed, true otherwise
*
* Since: 0.9.2
**/

View file

@ -40,22 +40,6 @@
HB_BEGIN_DECLS
typedef struct hb_feature_t {
hb_tag_t tag;
uint32_t value;
unsigned int start;
unsigned int end;
} hb_feature_t;
HB_EXTERN hb_bool_t
hb_feature_from_string (const char *str, int len,
hb_feature_t *feature);
HB_EXTERN void
hb_feature_to_string (hb_feature_t *feature,
char *buf, unsigned int size);
HB_EXTERN void
hb_shape (hb_font_t *font,
hb_buffer_t *buffer,

View file

@ -65,27 +65,31 @@ struct hb_shaper_data_t {
#define HB_SHAPER_DATA_INVALID ((void *) -1)
#define HB_SHAPER_DATA_IS_INVALID(data) ((void *) (data) == HB_SHAPER_DATA_INVALID)
#define HB_SHAPER_DATA_TYPE(shaper, object) struct hb_##shaper##_shaper_##object##_data_t
#define HB_SHAPER_DATA_TYPE_NAME(shaper, object) hb_##shaper##_shaper_##object##_data_t
#define HB_SHAPER_DATA_TYPE(shaper, object) struct HB_SHAPER_DATA_TYPE_NAME(shaper, object)
#define HB_SHAPER_DATA_INSTANCE(shaper, object, instance) (* (HB_SHAPER_DATA_TYPE(shaper, object) **) &(instance)->shaper_data.shaper)
#define HB_SHAPER_DATA(shaper, object) HB_SHAPER_DATA_INSTANCE (shaper, object, object)
#define HB_SHAPER_DATA(shaper, object) HB_SHAPER_DATA_INSTANCE(shaper, object, object)
#define HB_SHAPER_DATA_CREATE_FUNC(shaper, object) _hb_##shaper##_shaper_##object##_data_create
#define HB_SHAPER_DATA_DESTROY_FUNC(shaper, object) _hb_##shaper##_shaper_##object##_data_destroy
#define HB_SHAPER_DATA_ENSURE_FUNC(shaper, object) hb_##shaper##_shaper_##object##_data_ensure
#define HB_SHAPER_DATA_PROTOTYPE(shaper, object) \
HB_SHAPER_DATA_TYPE (shaper, object); /* Type forward declaration. */ \
extern "C" HB_INTERNAL HB_SHAPER_DATA_TYPE (shaper, object) * \
HB_SHAPER_DATA_CREATE_FUNC (shaper, object) (hb_##object##_t *object HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS); \
extern "C" HB_INTERNAL void \
HB_SHAPER_DATA_DESTROY_FUNC (shaper, object) (HB_SHAPER_DATA_TYPE (shaper, object) *data)
HB_SHAPER_DATA_DESTROY_FUNC (shaper, object) (HB_SHAPER_DATA_TYPE (shaper, object) *data); \
extern "C" HB_INTERNAL bool \
HB_SHAPER_DATA_ENSURE_FUNC (shaper, object) (hb_##object##_t *object)
#define HB_SHAPER_DATA_DESTROY(shaper, object) \
if (HB_SHAPER_DATA_TYPE (shaper, object) *data = HB_SHAPER_DATA (shaper, object)) \
if (data != HB_SHAPER_DATA_INVALID && data != HB_SHAPER_DATA_SUCCEEDED) \
HB_SHAPER_DATA_DESTROY_FUNC (shaper, object) (data);
#define HB_SHAPER_DATA_ENSURE_DECLARE(shaper, object) \
static inline bool \
hb_##shaper##_shaper_##object##_data_ensure (hb_##object##_t *object) \
#define HB_SHAPER_DATA_ENSURE_DEFINE(shaper, object) \
bool \
HB_SHAPER_DATA_ENSURE_FUNC(shaper, object) (hb_##object##_t *object) \
{\
retry: \
HB_SHAPER_DATA_TYPE (shaper, object) *data = (HB_SHAPER_DATA_TYPE (shaper, object) *) hb_atomic_ptr_get (&HB_SHAPER_DATA (shaper, object)); \

View file

@ -105,6 +105,10 @@ HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE
inline unsigned int
modified_combining_class (hb_codepoint_t unicode)
{
/* XXX This hack belongs to the Arabic shaper:
* Put HAMZA ABOVE in the same class as SHADDA. */
if (unlikely (unicode == 0x0654u)) unicode = 0x0651u;
/* XXX This hack belongs to the Myanmar shaper. */
if (unlikely (unicode == 0x1037u)) unicode = 0x103Au;
@ -126,7 +130,7 @@ HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE
{
/* 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,
return unlikely (hb_in_ranges<hb_codepoint_t> (unicode,
0xFE00u, 0xFE0Fu, /* VARIATION SELECTOR-1..16 */
0xE0100u, 0xE01EFu)); /* VARIATION SELECTOR-17..256 */
}
@ -179,13 +183,13 @@ HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE
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,
case 0x17: return hb_in_range<hb_codepoint_t> (ch, 0x17B4u, 0x17B5u);
case 0x18: return hb_in_range<hb_codepoint_t> (ch, 0x180Bu, 0x180Eu);
case 0x20: return hb_in_ranges<hb_codepoint_t> (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);
case 0xFE: return hb_in_range<hb_codepoint_t> (ch, 0xFE00u, 0xFE0Fu) || ch == 0xFEFFu;
case 0xFF: return hb_in_range<hb_codepoint_t> (ch, 0xFFF0u, 0xFFF8u);
default: return false;
}
}
@ -193,9 +197,9 @@ HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE
{
/* Other planes */
switch (plane) {
case 0x01: return hb_in_ranges (ch, 0x1BCA0u, 0x1BCA3u,
case 0x01: return hb_in_ranges<hb_codepoint_t> (ch, 0x1BCA0u, 0x1BCA3u,
0x1D173u, 0x1D17Au);
case 0x0E: return hb_in_range (ch, 0xE0000u, 0xE0FFFu);
case 0x0E: return hb_in_range<hb_codepoint_t> (ch, 0xE0000u, 0xE0FFFu);
default: return false;
}
}
@ -346,12 +350,13 @@ extern HB_INTERNAL const hb_unicode_funcs_t _hb_unicode_funcs_nil;
#define HB_MODIFIED_COMBINING_CLASS_CCC122 122 /* mai * */
/* Tibetan
* Modify U+0F74 (ccc=132) to reorder before ccc=130 marks.
*
* In case of multiple vowel-signs, use u first (but after achung)
* this allows Dzongkha multi-vowel shortcuts to render correctly
*/
#define HB_MODIFIED_COMBINING_CLASS_CCC129 129 /* sign aa */
#define HB_MODIFIED_COMBINING_CLASS_CCC130 130 /* sign i */
#define HB_MODIFIED_COMBINING_CLASS_CCC132 128 /* sign u */
#define HB_MODIFIED_COMBINING_CLASS_CCC130 132 /* sign i */
#define HB_MODIFIED_COMBINING_CLASS_CCC132 131 /* sign u */
/* Misc */

View file

@ -293,8 +293,8 @@ struct range_record_t {
unsigned int index_last; /* == end - 1 */
};
HB_SHAPER_DATA_ENSURE_DECLARE(uniscribe, face)
HB_SHAPER_DATA_ENSURE_DECLARE(uniscribe, font)
HB_SHAPER_DATA_ENSURE_DEFINE(uniscribe, face)
HB_SHAPER_DATA_ENSURE_DEFINE(uniscribe, font)
/*
@ -1024,6 +1024,8 @@ retry:
pos->x_advance = x_mult * (int32_t) info->mask;
pos->x_offset = x_mult * (backward ? -info->var1.i32 : info->var1.i32);
pos->y_offset = y_mult * info->var2.i32;
info->mask = HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
}
if (backward)

View file

@ -48,7 +48,7 @@ struct hb_utf8_t
if (c > 0x7Fu)
{
if (hb_in_range (c, 0xC2u, 0xDFu)) /* Two-byte */
if (hb_in_range<hb_codepoint_t> (c, 0xC2u, 0xDFu)) /* Two-byte */
{
unsigned int t1;
if (likely (text < end &&
@ -60,7 +60,7 @@ struct hb_utf8_t
else
goto error;
}
else if (hb_in_range (c, 0xE0u, 0xEFu)) /* Three-byte */
else if (hb_in_range<hb_codepoint_t> (c, 0xE0u, 0xEFu)) /* Three-byte */
{
unsigned int t1, t2;
if (likely (1 < end - text &&
@ -68,14 +68,14 @@ struct hb_utf8_t
(t2 = text[1] - 0x80u) <= 0x3Fu))
{
c = ((c&0xFu)<<12) | (t1<<6) | t2;
if (unlikely (c < 0x0800u || hb_in_range (c, 0xD800u, 0xDFFFu)))
if (unlikely (c < 0x0800u || hb_in_range<hb_codepoint_t> (c, 0xD800u, 0xDFFFu)))
goto error;
text += 2;
}
else
goto error;
}
else if (hb_in_range (c, 0xF0u, 0xF4u)) /* Four-byte */
else if (hb_in_range<hb_codepoint_t> (c, 0xF0u, 0xF4u)) /* Four-byte */
{
unsigned int t1, t2, t3;
if (likely (2 < end - text &&
@ -84,7 +84,7 @@ struct hb_utf8_t
(t3 = text[2] - 0x80u) <= 0x3Fu))
{
c = ((c&0x7u)<<18) | (t1<<12) | (t2<<6) | t3;
if (unlikely (!hb_in_range (c, 0x10000u, 0x10FFFFu)))
if (unlikely (!hb_in_range<hb_codepoint_t> (c, 0x10000u, 0x10FFFFu)))
goto error;
text += 3;
}
@ -140,7 +140,7 @@ struct hb_utf16_t
{
hb_codepoint_t c = *text++;
if (likely (!hb_in_range (c, 0xD800u, 0xDFFFu)))
if (likely (!hb_in_range<hb_codepoint_t> (c, 0xD800u, 0xDFFFu)))
{
*unicode = c;
return text;
@ -150,7 +150,7 @@ struct hb_utf16_t
{
/* High-surrogate in c */
hb_codepoint_t l = *text;
if (likely (hb_in_range (l, 0xDC00u, 0xDFFFu)))
if (likely (hb_in_range<hb_codepoint_t> (l, 0xDC00u, 0xDFFFu)))
{
/* Low-surrogate in l */
*unicode = (c << 10) + l - ((0xD800u << 10) - 0x10000u + 0xDC00u);
@ -172,7 +172,7 @@ struct hb_utf16_t
{
hb_codepoint_t c = *--text;
if (likely (!hb_in_range (c, 0xD800u, 0xDFFFu)))
if (likely (!hb_in_range<hb_codepoint_t> (c, 0xD800u, 0xDFFFu)))
{
*unicode = c;
return text;
@ -182,7 +182,7 @@ struct hb_utf16_t
{
/* Low-surrogate in c */
hb_codepoint_t h = text[-1];
if (likely (hb_in_range (h, 0xD800u, 0xDBFFu)))
if (likely (hb_in_range<hb_codepoint_t> (h, 0xD800u, 0xDBFFu)))
{
/* High-surrogate in h */
*unicode = (h << 10) + c - ((0xD800u << 10) - 0x10000u + 0xDC00u);

View file

@ -37,10 +37,10 @@ HB_BEGIN_DECLS
#define HB_VERSION_MAJOR 1
#define HB_VERSION_MINOR 4
#define HB_VERSION_MINOR 5
#define HB_VERSION_MICRO 1
#define HB_VERSION_STRING "1.4.1"
#define HB_VERSION_STRING "1.5.1"
#define HB_VERSION_ATLEAST(major,minor,micro) \
((major)*10000+(minor)*100+(micro) <= \

View file

@ -16,6 +16,7 @@ EXPORTS.harfbuzz += [
'hb-ot-math.h',
'hb-ot-shape.h',
'hb-ot-tag.h',
'hb-ot-var.h',
'hb-ot.h',
'hb-set.h',
'hb-shape-plan.h',
@ -39,7 +40,6 @@ SOURCES += [
UNIFIED_SOURCES += [
'hb-buffer.cc',
'hb-face.cc',
'hb-fallback-shape.cc',
'hb-font.cc',
'hb-ot-layout.cc',
'hb-ot-map.cc',
@ -54,6 +54,7 @@ UNIFIED_SOURCES += [
'hb-ot-shape-fallback.cc',
'hb-ot-shape-normalize.cc',
'hb-ot-tag.cc',
'hb-ot-var.cc',
'hb-set.cc',
'hb-shape.cc',
'hb-shaper.cc',