Merge branch 'master' into var-subset

This commit is contained in:
Michiharu Ariza 2019-07-01 15:17:19 -07:00
commit 5763a92749
35 changed files with 631 additions and 477 deletions

View File

@ -45,7 +45,7 @@ jobs:
- run: rm -rf harfbuzz-* - run: rm -rf harfbuzz-*
- run: make distdir && cd harfbuzz-* && cmake -DHB_CHECK=ON -Bbuild -H. -GNinja && ninja -Cbuild && CTEST_OUTPUT_ON_FAILURE=1 ninja -Cbuild test && ninja -Cbuild install - run: make distdir && cd harfbuzz-* && cmake -DHB_CHECK=ON -Bbuild -H. -GNinja && ninja -Cbuild && CTEST_OUTPUT_ON_FAILURE=1 ninja -Cbuild test && ninja -Cbuild install
alpine-O3-NOMMAP: alpine-O3-Os-NOMMAP:
docker: docker:
- image: alpine - image: alpine
steps: steps:
@ -55,6 +55,10 @@ jobs:
- run: CFLAGS="-O3" CXXFLAGS="-O3 -DHB_NO_MMAP" ./autogen.sh - run: CFLAGS="-O3" CXXFLAGS="-O3 -DHB_NO_MMAP" ./autogen.sh
- run: make -j32 - run: make -j32
- run: make check || .ci/fail.sh - run: make check || .ci/fail.sh
- run: make clean
- run: CFLAGS="-Os -DHB_OPTIMIZE_SIZE" CXXFLAGS="-Os -DHB_NO_MMAP -DHB_OPTIMIZE_SIZE" ./autogen.sh
- run: make -j32
- run: make check || .ci/fail.sh
archlinux-py3-all: archlinux-py3-all:
docker: docker:
@ -197,7 +201,7 @@ jobs:
- image: fedora - image: fedora
steps: steps:
- checkout - checkout
- run: dnf install -y pkg-config ragel gcc gcc-c++ automake autoconf libtool make which glib2-devel freetype-devel cairo-devel libicu-devel gobject-introspection-devel graphite2-devel redhat-rpm-config python wine mingw32-gcc-c++ mingw64-gcc-c++ mingw32-glib2 mingw32-cairo mingw32-freetype mingw64-glib2 mingw64-cairo mingw64-freetype glibc-devel.i686 || true - run: dnf install -y pkg-config ragel gcc gcc-c++ automake autoconf libtool make which glib2-devel freetype-devel cairo-devel libicu-devel gobject-introspection-devel graphite2-devel redhat-rpm-config python mingw32-gcc-c++ mingw64-gcc-c++ mingw32-glib2 mingw32-cairo mingw32-freetype mingw64-glib2 mingw64-cairo mingw64-freetype glibc-devel.i686 || true
- run: CFLAGS="-O0" CXXFLAGS="-O0" CPPFLAGS="-DHB_DEBUG" NOCONFIGURE=1 ./autogen.sh --with-freetype --with-glib --with-gobject --with-cairo --with-icu --with-graphite2 - run: CFLAGS="-O0" CXXFLAGS="-O0" CPPFLAGS="-DHB_DEBUG" NOCONFIGURE=1 ./autogen.sh --with-freetype --with-glib --with-gobject --with-cairo --with-icu --with-graphite2
- run: mkdir build && cd build && ../configure && make -j32 && (make check || ../.ci/fail.sh) - run: mkdir build && cd build && ../configure && make -j32 && (make check || ../.ci/fail.sh)
- run: pip install pefile - run: pip install pefile
@ -307,7 +311,7 @@ workflows:
- distcheck - distcheck
# autotools based builds # autotools based builds
- alpine-O3-NOMMAP - alpine-O3-Os-NOMMAP
- archlinux-py3-all - archlinux-py3-all
#- void-notest #- void-notest
- gcc-valgrind - gcc-valgrind

View File

@ -1,5 +1,5 @@
# Build Configuration for Travis # Build Configuration for Travis
dist: xenial dist: trusty
language: cpp language: cpp

View File

@ -108,7 +108,7 @@ endmacro ()
if (UNIX) if (UNIX)
list(APPEND CMAKE_REQUIRED_LIBRARIES m) list(APPEND CMAKE_REQUIRED_LIBRARIES m)
endif () endif ()
check_funcs(atexit mprotect sysconf getpagesize mmap isatty newlocale strtod_l round) check_funcs(atexit mprotect sysconf getpagesize mmap isatty newlocale strtod_l)
check_include_file(unistd.h HAVE_UNISTD_H) check_include_file(unistd.h HAVE_UNISTD_H)
if (${HAVE_UNISTD_H}) if (${HAVE_UNISTD_H})
add_definitions(-DHAVE_UNISTD_H) add_definitions(-DHAVE_UNISTD_H)

View File

@ -78,12 +78,6 @@ GTK_DOC_CHECK([1.15],[--flavour no-tmpl])
# Functions and headers # Functions and headers
AC_CHECK_FUNCS(atexit mprotect sysconf getpagesize mmap isatty newlocale strtod_l posix_memalign) AC_CHECK_FUNCS(atexit mprotect sysconf getpagesize mmap isatty newlocale strtod_l posix_memalign)
save_libs="$LIBS"
LIBS="$LIBS -lm"
AC_CHECK_FUNCS([round], ,[AC_CHECK_DECLS([round], , ,[#include <math.h>])])
LIBS="$save_libs"
AC_CHECK_HEADERS(unistd.h sys/mman.h xlocale.h stdbool.h) AC_CHECK_HEADERS(unistd.h sys/mman.h xlocale.h stdbool.h)
# Compiler flags # Compiler flags

View File

@ -31,14 +31,15 @@ ce = {i for i,u in enumerate(ucd) if u['Comp_Ex'] == 'Y'}
assert not any(v for v in dm.values() if len(v) not in (1,2)) assert not any(v for v in dm.values() if len(v) not in (1,2))
dm1 = sorted(set(v for v in dm.values() if len(v) == 1)) dm1 = sorted(set(v for v in dm.values() if len(v) == 1))
dm1_array = ['0x%04Xu' % v for v in dm1] dm1_u16_array = ['0x%04Xu' % v for v in dm1 if v[0] <= 0xFFFF]
dm1_u32_array = ['0x%04Xu' % v for v in dm1 if v[0] > 0xFFFF]
dm1_order = {v:i+1 for i,v in enumerate(dm1)} dm1_order = {v:i+1 for i,v in enumerate(dm1)}
dm2 = sorted((v, i) for i,v in dm.items() if len(v) == 2) dm2 = sorted((v, i) for i,v in dm.items() if len(v) == 2)
dm2 = [("HB_CODEPOINT_ENCODE3 (0x%04Xu, 0x%04Xu, 0x%04Xu)" % dm2 = [("HB_CODEPOINT_ENCODE3 (0x%04Xu, 0x%04Xu, 0x%04Xu)" %
(v+(i if i not in ce and not ccc[i] else 0,)), v) (v+(i if i not in ce and not ccc[i] else 0,)), v)
for v,i in dm2] for v,i in dm2]
dm2_array = [s for s,v in dm2] dm2_array = [s for s,v in dm2]
l = 1 + len(dm1_array) l = 1 + len(dm1_u16_array) + len(dm1_u32_array)
dm2_order = {v[1]:i+l for i,v in enumerate(dm2)} dm2_order = {v[1]:i+l for i,v in enumerate(dm2)}
dm_order = {None: 0} dm_order = {None: 0}
dm_order.update(dm1_order) dm_order.update(dm1_order)
@ -89,7 +90,8 @@ print()
code = packTab.Code('_hb_ucd') code = packTab.Code('_hb_ucd')
sc_array, _ = code.addArray('hb_script_t', 'sc_map', sc_array) sc_array, _ = code.addArray('hb_script_t', 'sc_map', sc_array)
dm1_array, _ = code.addArray('hb_codepoint_t', 'dm1_map', dm1_array) dm1_16_array, _ = code.addArray('uint16_t', 'dm1_u16_map', dm1_u16_array)
dm1_32_array, _ = code.addArray('uint32_t', 'dm1_u32_map', dm1_u32_array)
dm2_array, _ = code.addArray('uint64_t', 'dm2_map', dm2_array) dm2_array, _ = code.addArray('uint64_t', 'dm2_map', dm2_array)
code.print_c(linkage='static inline') code.print_c(linkage='static inline')

View File

@ -1,6 +1,6 @@
/* /*
* Copyright © 2017 Google, Inc. * Copyright © 2017 Google, Inc.
* Copyright © 2019 Google, Inc. * Copyright © 2019 Facebook, Inc.
* *
* This is part of HarfBuzz, a text shaping library. * This is part of HarfBuzz, a text shaping library.
* *
@ -167,19 +167,37 @@ template <unsigned Pos=1, typename Appl, typename V>
auto hb_partial (Appl&& a, V&& v) HB_AUTO_RETURN auto hb_partial (Appl&& a, V&& v) HB_AUTO_RETURN
(( hb_partial_t<Pos, Appl, V> (a, v) )) (( hb_partial_t<Pos, Appl, V> (a, v) ))
/* The following hacky replacement version is to make Visual Stuiod build:. */ \ /* The following, HB_PARTIALIZE, macro uses a particular corner-case
/* https://github.com/harfbuzz/harfbuzz/issues/1730 */ \ * of C++11 that is not particularly well-supported by all compilers.
* What's happening is that it's using "this" in a trailing return-type
* via decltype(). Broken compilers deduce the type of "this" pointer
* in that context differently from what it resolves to in the body
* of the function.
*
* One probable cause of this is that at the time of trailing return
* type declaration, "this" points to an incomplete type, whereas in
* the function body the type is complete. That doesn't justify the
* error in any way, but is probably what's happening.
*
* In the case of MSVC, we get around this by using C++14 "decltype(auto)"
* which deduces the type from the actual return statement. For gcc 4.8
* we use "+this" instead of "this" which produces an rvalue that seems
* to be deduced as the same type with this particular compiler, and seem
* to be fine as default code path as well.
*/
#ifdef _MSC_VER #ifdef _MSC_VER
/* https://github.com/harfbuzz/harfbuzz/issues/1730 */ \
#define HB_PARTIALIZE(Pos) \ #define HB_PARTIALIZE(Pos) \
template <typename _T> \ template <typename _T> \
decltype(auto) operator () (_T&& _v) const \ decltype(auto) operator () (_T&& _v) const \
{ return hb_partial<Pos> (this, hb_forward<_T> (_v)); } \ { return hb_partial<Pos> (this, hb_forward<_T> (_v)); } \
static_assert (true, "") static_assert (true, "")
#else #else
/* https://github.com/harfbuzz/harfbuzz/issues/1724 */
#define HB_PARTIALIZE(Pos) \ #define HB_PARTIALIZE(Pos) \
template <typename _T> \ template <typename _T> \
auto operator () (_T&& _v) const HB_AUTO_RETURN \ auto operator () (_T&& _v) const HB_AUTO_RETURN \
(hb_partial<Pos> (this, hb_forward<_T> (_v))) \ (hb_partial<Pos> (+this, hb_forward<_T> (_v))) \
static_assert (true, "") static_assert (true, "")
#endif #endif
@ -400,7 +418,7 @@ hb_bit_storage (T v)
return sizeof (unsigned long long) * 8 - __builtin_clzll (v); return sizeof (unsigned long long) * 8 - __builtin_clzll (v);
#endif #endif
#if (defined(_MSC_VER) && _MSC_VER >= 1500) || defined(__MINGW32__) #if (defined(_MSC_VER) && _MSC_VER >= 1500) || (defined(__MINGW32__) && (__GNUC__ < 4))
if (sizeof (T) <= sizeof (unsigned int)) if (sizeof (T) <= sizeof (unsigned int))
{ {
unsigned long where; unsigned long where;
@ -474,7 +492,7 @@ hb_ctz (T v)
return __builtin_ctzll (v); return __builtin_ctzll (v);
#endif #endif
#if (defined(_MSC_VER) && _MSC_VER >= 1500) || defined(__MINGW32__) #if (defined(_MSC_VER) && _MSC_VER >= 1500) || (defined(__MINGW32__) && (__GNUC__ < 4))
if (sizeof (T) <= sizeof (unsigned int)) if (sizeof (T) <= sizeof (unsigned int))
{ {
unsigned long where; unsigned long where;
@ -628,115 +646,213 @@ hb_bsearch (const void *key, const void *base,
/* From https://github.com/noporpoise/sort_r /* From https://github.com/noporpoise/sort_r
* With following modifications: Feb 5, 2019 (c8c65c1e)
* Modified to support optional argument using templates */
* 10 November 2018:
* https://github.com/noporpoise/sort_r/issues/7
*/
/* Isaac Turner 29 April 2014 Public Domain */ /* Isaac Turner 29 April 2014 Public Domain */
/* /*
hb_qsort function to be exported.
hb_sort_r function to be exported.
Parameters: Parameters:
base is the array to be sorted base is the array to be sorted
nel is the number of elements in the array nel is the number of elements in the array
width is the size in bytes of each element of the array width is the size in bytes of each element of the array
compar is the comparison function compar is the comparison function
arg is a pointer to be passed to the comparison function arg (optional) is a pointer to be passed to the comparison function
void hb_sort_r(void *base, size_t nel, size_t width, void hb_qsort(void *base, size_t nel, size_t width,
int (*compar)(const void *_a, const void *_b, void *_arg), int (*compar)(const void *_a, const void *_b, [void *_arg]),
void *arg); [void *arg]);
*/ */
#define SORT_R_SWAP(a,b,tmp) ((tmp) = (a), (a) = (b), (b) = (tmp))
/* swap a, b iff a>b */ /* swap a and b */
/* __restrict is same as restrict but better support on old machines */ /* a and b must not be equal! */
static int sort_r_cmpswap(char *__restrict a, char *__restrict b, size_t w, static inline void sort_r_swap(char *__restrict a, char *__restrict b,
int (*compar)(const void *_a, const void *_b, size_t w)
void *_arg),
void *arg)
{ {
char tmp, *end = a+w; char tmp, *end = a+w;
if(compar(a, b, arg) > 0) { for(; a < end; a++, b++) { SORT_R_SWAP(*a, *b, tmp); }
for(; a < end; a++, b++) { tmp = *a; *a = *b; *b = tmp; } }
/* swap a, b iff a>b */
/* a and b must not be equal! */
/* __restrict is same as restrict but better support on old machines */
template <typename ...Ts>
static inline int sort_r_cmpswap(char *__restrict a,
char *__restrict b, size_t w,
int (*compar)(const void *_a,
const void *_b,
Ts... _ds),
Ts... ds)
{
if(compar(a, b, ds...) > 0) {
sort_r_swap(a, b, w);
return 1; return 1;
} }
return 0; return 0;
} }
/*
Swap consecutive blocks of bytes of size na and nb starting at memory addr ptr,
with the smallest swap so that the blocks are in the opposite order. Blocks may
be internally re-ordered e.g.
12345ab -> ab34512
123abc -> abc123
12abcde -> deabc12
*/
static inline void sort_r_swap_blocks(char *ptr, size_t na, size_t nb)
{
if(na > 0 && nb > 0) {
if(na > nb) { sort_r_swap(ptr, ptr+na, nb); }
else { sort_r_swap(ptr, ptr+nb, na); }
}
}
/* Implement recursive quicksort ourselves */
/* Note: quicksort is not stable, equivalent values may be swapped */ /* Note: quicksort is not stable, equivalent values may be swapped */
template <typename ...Ts>
static inline void sort_r_simple(void *base, size_t nel, size_t w, static inline void sort_r_simple(void *base, size_t nel, size_t w,
int (*compar)(const void *_a, const void *_b, int (*compar)(const void *_a,
void *_arg), const void *_b,
void *arg) Ts... _ds),
Ts... ds)
{ {
char *b = (char *)base, *end = b + nel*w; char *b = (char *)base, *end = b + nel*w;
if(nel < 7) {
/* for(size_t i=0; i<nel; i++) {printf("%4i", *(int*)(b + i*sizeof(int)));}
printf("\n"); */
if(nel < 10) {
/* Insertion sort for arbitrarily small inputs */ /* Insertion sort for arbitrarily small inputs */
char *pi, *pj; char *pi, *pj;
for(pi = b+w; pi < end; pi += w) { for(pi = b+w; pi < end; pi += w) {
for(pj = pi; pj > b && sort_r_cmpswap(pj-w,pj,w,compar,arg); pj -= w) {} for(pj = pi; pj > b && sort_r_cmpswap(pj-w,pj,w,compar,ds...); pj -= w) {}
} }
} }
else else
{ {
/* nel > 6; Quicksort */ /* nel > 9; Quicksort */
/* Use median of first, middle and last items as pivot */ int cmp;
char *x, *y, *xend, ch; char *pl, *ple, *pr, *pre, *pivot;
char *pl, *pm, *pr;
char *last = b+w*(nel-1), *tmp; char *last = b+w*(nel-1), *tmp;
/*
Use median of second, middle and second-last items as pivot.
First and last may have been swapped with pivot and therefore be extreme
*/
char *l[3]; char *l[3];
l[0] = b; l[0] = b + w;
l[1] = b+w*(nel/2); l[1] = b+w*(nel/2);
l[2] = last; l[2] = last - w;
if(compar(l[0],l[1],arg) > 0) { tmp=l[0]; l[0]=l[1]; l[1]=tmp; } /* printf("pivots: %i, %i, %i\n", *(int*)l[0], *(int*)l[1], *(int*)l[2]); */
if(compar(l[1],l[2],arg) > 0) {
tmp=l[1]; l[1]=l[2]; l[2]=tmp; /* swap(l[1],l[2]) */ if(compar(l[0],l[1],ds...) > 0) { SORT_R_SWAP(l[0], l[1], tmp); }
if(compar(l[0],l[1],arg) > 0) { tmp=l[0]; l[0]=l[1]; l[1]=tmp; } if(compar(l[1],l[2],ds...) > 0) {
SORT_R_SWAP(l[1], l[2], tmp);
if(compar(l[0],l[1],ds...) > 0) { SORT_R_SWAP(l[0], l[1], tmp); }
} }
/* swap l[id], l[2] to put pivot as last element */ /* swap mid value (l[1]), and last element to put pivot as last element */
for(x = l[1], y = last, xend = x+w; x<xend; x++, y++) { if(l[1] != last) { sort_r_swap(l[1], last, w); }
ch = *x; *x = *y; *y = ch;
}
pl = b; /*
pr = last; pl is the next item on the left to be compared to the pivot
pr is the last item on the right that was compared to the pivot
ple is the left position to put the next item that equals the pivot
ple is the last right position where we put an item that equals the pivot
v- end (beyond the array)
EEEEEELLLLLLLLuuuuuuuuGGGGGGGEEEEEEEE.
^- b ^- ple ^- pl ^- pr ^- pre ^- last (where the pivot is)
Pivot comparison key:
E = equal, L = less than, u = unknown, G = greater than, E = equal
*/
pivot = last;
ple = pl = b;
pre = pr = last;
/*
Strategy:
Loop into the list from the left and right at the same time to find:
- an item on the left that is greater than the pivot
- an item on the right that is less than the pivot
Once found, they are swapped and the loop continues.
Meanwhile items that are equal to the pivot are moved to the edges of the
array.
*/
while(pl < pr) { while(pl < pr) {
pm = pl+((pr-pl+1)>>1); /* Move left hand items which are equal to the pivot to the far left.
for(; pl < pm; pl += w) { break when we find an item that is greater than the pivot */
if(sort_r_cmpswap(pl, pr, w, compar, arg)) { for(; pl < pr; pl += w) {
pr -= w; /* pivot now at pl */ cmp = compar(pl, pivot, ds...);
break; if(cmp > 0) { break; }
else if(cmp == 0) {
if(ple < pl) { sort_r_swap(ple, pl, w); }
ple += w;
} }
} }
pm = pl+((pr-pl)>>1); /* break if last batch of left hand items were equal to pivot */
for(; pm < pr; pr -= w) { if(pl >= pr) { break; }
if(sort_r_cmpswap(pl, pr, w, compar, arg)) { /* Move right hand items which are equal to the pivot to the far right.
pl += w; /* pivot now at pr */ break when we find an item that is less than the pivot */
for(; pl < pr; ) {
pr -= w; /* Move right pointer onto an unprocessed item */
cmp = compar(pr, pivot, ds...);
if(cmp == 0) {
pre -= w;
if(pr < pre) { sort_r_swap(pr, pre, w); }
}
else if(cmp < 0) {
if(pl < pr) { sort_r_swap(pl, pr, w); }
pl += w;
break; break;
} }
} }
} }
sort_r_simple(b, (pl-b)/w, w, compar, arg); pl = pr; /* pr may have gone below pl */
sort_r_simple(pl+w, (end-(pl+w))/w, w, compar, arg);
/*
Now we need to go from: EEELLLGGGGEEEE
to: LLLEEEEEEEGGGG
Pivot comparison key:
E = equal, L = less than, u = unknown, G = greater than, E = equal
*/
sort_r_swap_blocks(b, ple-b, pl-ple);
sort_r_swap_blocks(pr, pre-pr, end-pre);
/*for(size_t i=0; i<nel; i++) {printf("%4i", *(int*)(b + i*sizeof(int)));}
printf("\n");*/
sort_r_simple(b, (pl-ple)/w, w, compar, ds...);
sort_r_simple(end-(pre-pr), (pre-pr)/w, w, compar, ds...);
} }
} }
static inline void static inline void
hb_sort_r (void *base, size_t nel, size_t width, hb_qsort (void *base, size_t nel, size_t width,
int (*compar)(const void *_a, const void *_b, void *_arg), int (*compar)(const void *_a, const void *_b))
void *arg)
{ {
sort_r_simple(base, nel, width, compar, arg); #if defined(__OPTIMIZE_SIZE__) && !defined(HB_USE_INTERNAL_QSORT)
qsort (base, nel, width, compar);
#else
sort_r_simple (base, nel, width, compar);
#endif
}
static inline void
hb_qsort (void *base, size_t nel, size_t width,
int (*compar)(const void *_a, const void *_b, void *_arg),
void *arg)
{
#ifdef HAVE_GNU_QSORT_R
qsort_r (base, nel, width, compar, arg);
#else
sort_r_simple (base, nel, width, compar, arg);
#endif
} }

View File

@ -141,13 +141,13 @@ struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
hb_sorted_array_t<Type> qsort (int (*cmp_)(const void*, const void*)) hb_sorted_array_t<Type> qsort (int (*cmp_)(const void*, const void*))
{ {
if (likely (length)) if (likely (length))
::qsort (arrayZ, length, this->item_size, cmp_); hb_qsort (arrayZ, length, this->item_size, cmp_);
return hb_sorted_array_t<Type> (*this); return hb_sorted_array_t<Type> (*this);
} }
hb_sorted_array_t<Type> qsort () hb_sorted_array_t<Type> qsort ()
{ {
if (likely (length)) if (likely (length))
::qsort (arrayZ, length, this->item_size, Type::cmp); hb_qsort (arrayZ, length, this->item_size, Type::cmp);
return hb_sorted_array_t<Type> (*this); return hb_sorted_array_t<Type> (*this);
} }
void qsort (unsigned int start, unsigned int end) void qsort (unsigned int start, unsigned int end)
@ -155,7 +155,7 @@ struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
end = hb_min (end, length); end = hb_min (end, length);
assert (start <= end); assert (start <= end);
if (likely (start < end)) if (likely (start < end))
::qsort (arrayZ + start, end - start, this->item_size, Type::cmp); hb_qsort (arrayZ + start, end - start, this->item_size, Type::cmp);
} }
/* /*

View File

@ -107,7 +107,7 @@ _hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N)
static inline void _hb_memory_barrier () static inline void _hb_memory_barrier ()
{ {
#ifndef MemoryBarrier #if !defined(MemoryBarrier) && !defined(__MINGW32_VERSION)
/* MinGW has a convoluted history of supporting MemoryBarrier. */ /* MinGW has a convoluted history of supporting MemoryBarrier. */
LONG dummy = 0; LONG dummy = 0;
InterlockedExchange (&dummy, 1); InterlockedExchange (&dummy, 1);

View File

@ -543,6 +543,10 @@ _hb_mapped_file_destroy (void *file_)
hb_blob_t * hb_blob_t *
hb_blob_create_from_file (const char *file_name) hb_blob_create_from_file (const char *file_name)
{ {
#ifdef HB_NO_OPEN
return hb_blob_get_empty ();
#endif
/* Adopted from glib's gmappedfile.c with Matthias Clasen and /* Adopted from glib's gmappedfile.c with Matthias Clasen and
Allison Lortie permission but changed a lot to suit our need. */ Allison Lortie permission but changed a lot to suit our need. */
#if defined(HAVE_MMAP) && !defined(HB_NO_MMAP) #if defined(HAVE_MMAP) && !defined(HB_NO_MMAP)

View File

@ -2026,9 +2026,6 @@ hb_buffer_set_message_func (hb_buffer_t *buffer,
bool bool
hb_buffer_t::message_impl (hb_font_t *font, const char *fmt, va_list ap) hb_buffer_t::message_impl (hb_font_t *font, const char *fmt, va_list ap)
{ {
#ifdef HB_NO_BUFFER_MESSAGE
return false;
#endif
char buf[100]; char buf[100];
vsnprintf (buf, sizeof (buf), fmt, ap); vsnprintf (buf, sizeof (buf), fmt, ap);
return (bool) this->message_func (this, font, buf, this->message_data); return (bool) this->message_func (this, font, buf, this->message_data);

View File

@ -347,7 +347,13 @@ struct hb_buffer_t
HB_INTERNAL void sort (unsigned int start, unsigned int end, int(*compar)(const hb_glyph_info_t *, const hb_glyph_info_t *)); HB_INTERNAL void sort (unsigned int start, unsigned int end, int(*compar)(const hb_glyph_info_t *, const hb_glyph_info_t *));
bool messaging () { return unlikely (message_func); } bool messaging ()
{
#ifdef HB_NO_BUFFER_MESSAGE
return false;
#endif
return unlikely (message_func);
}
bool message (hb_font_t *font, const char *fmt, ...) HB_PRINTF_FUNC(3, 4) bool message (hb_font_t *font, const char *fmt, ...) HB_PRINTF_FUNC(3, 4)
{ {
if (!messaging ()) if (!messaging ())

View File

@ -76,8 +76,8 @@ struct biased_subrs_t
void fini () {} void fini () {}
unsigned int get_count () const { return (subrs == nullptr)? 0: subrs->count; } unsigned int get_count () const { return (subrs == nullptr) ? 0 : subrs->count; }
unsigned int get_bias () const { return bias; } unsigned int get_bias () const { return bias; }
byte_str_t operator [] (unsigned int index) const byte_str_t operator [] (unsigned int index) const
{ {

View File

@ -134,10 +134,10 @@ struct dict_opset_t : opset_t<number_t>
return value; return value;
case END: case END:
value = (double)(neg? -int_part: int_part); value = (double) (neg ? -int_part : int_part);
if (frac_count > 0) if (frac_count > 0)
{ {
double frac = (frac_part / pow (10.0, (double)frac_count)); double frac = (frac_part / pow (10.0, (double) frac_count));
if (neg) frac = -frac; if (neg) frac = -frac;
value += frac; value += frac;
} }
@ -146,16 +146,16 @@ struct dict_opset_t : opset_t<number_t>
if (value == 0.0) if (value == 0.0)
return value; return value;
if (exp_neg) if (exp_neg)
return neg? -DBL_MIN: DBL_MIN; return neg ? -DBL_MIN : DBL_MIN;
else else
return neg? -DBL_MAX: DBL_MAX; return neg ? -DBL_MAX : DBL_MAX;
} }
if (exp_part != 0) if (exp_part != 0)
{ {
if (exp_neg) if (exp_neg)
value /= pow (10.0, (double)exp_part); value /= pow (10.0, (double) exp_part);
else else
value *= pow (10.0, (double)exp_part); value *= pow (10.0, (double) exp_part);
} }
return value; return value;

View File

@ -35,6 +35,9 @@
#include <xlocale.h> #include <xlocale.h>
#endif #endif
#ifdef HB_NO_SETLOCALE
#define setlocale(Category, Locale) "C"
#endif
/** /**
* SECTION:hb-common * SECTION:hb-common

View File

@ -60,7 +60,10 @@
#define HB_NO_GETENV #define HB_NO_GETENV
#define HB_NO_LAYOUT_UNUSED #define HB_NO_LAYOUT_UNUSED
#define HB_NO_MATH #define HB_NO_MATH
#define HB_NO_MMAP
#define HB_NO_NAME #define HB_NO_NAME
#define HB_NO_OPEN
#define HB_NO_SETLOCALE
#define HB_NO_SUBSET_LAYOUT #define HB_NO_SUBSET_LAYOUT
#endif #endif

View File

@ -106,7 +106,7 @@ typedef volatile int hb_mutex_impl_t;
#define HB_MUTEX_IMPL_INIT 0 #define HB_MUTEX_IMPL_INIT 0
#define hb_mutex_impl_init(M) *(M) = 0 #define hb_mutex_impl_init(M) *(M) = 0
#define hb_mutex_impl_lock(M) HB_STMT_START { while (*(M)) HB_SCHED_YIELD (); (*(M))++; } HB_STMT_END #define hb_mutex_impl_lock(M) HB_STMT_START { while (*(M)) HB_SCHED_YIELD (); (*(M))++; } HB_STMT_END
#define hb_mutex_impl_unlock(M) (*(M))--; #define hb_mutex_impl_unlock(M) (*(M))--
#define hb_mutex_impl_finish(M) HB_STMT_START {} HB_STMT_END #define hb_mutex_impl_finish(M) HB_STMT_START {} HB_STMT_END

View File

@ -82,22 +82,14 @@ struct str_buff_vec_t : hb_vector_t<str_buff_t>
template <typename COUNT> template <typename COUNT>
struct CFFIndex struct CFFIndex
{ {
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (likely ((count.sanitize (c) && count == 0) || /* empty INDEX */
(c->check_struct (this) && offSize >= 1 && offSize <= 4 &&
c->check_array (offsets, offSize, count + 1) &&
c->check_array ((const HBUINT8*)data_base (), 1, max_offset () - 1))));
}
static unsigned int calculate_offset_array_size (unsigned int offSize, unsigned int count) static unsigned int calculate_offset_array_size (unsigned int offSize, unsigned int count)
{ return offSize * (count + 1); } { return offSize * (count + 1); }
unsigned int offset_array_size () const unsigned int offset_array_size () const
{ return calculate_offset_array_size (offSize, count); } { return calculate_offset_array_size (offSize, count); }
static unsigned int calculate_serialized_size (unsigned int offSize_, unsigned int count, unsigned int dataSize) static unsigned int calculate_serialized_size (unsigned int offSize_, unsigned int count,
unsigned int dataSize)
{ {
if (count == 0) if (count == 0)
return COUNT::static_size; return COUNT::static_size;
@ -199,11 +191,11 @@ struct CFFIndex
unsigned int length_at (unsigned int index) const unsigned int length_at (unsigned int index) const
{ {
if (likely ((offset_at (index + 1) >= offset_at (index)) && if (likely ((offset_at (index + 1) >= offset_at (index)) &&
(offset_at (index + 1) <= offset_at (count)))) (offset_at (index + 1) <= offset_at (count))))
return offset_at (index + 1) - offset_at (index); return offset_at (index + 1) - offset_at (index);
else else
return 0; return 0;
} }
const unsigned char *data_base () const const unsigned char *data_base () const
@ -216,12 +208,12 @@ struct CFFIndex
if (likely (index < count)) if (likely (index < count))
return byte_str_t (data_base () + offset_at (index) - 1, length_at (index)); return byte_str_t (data_base () + offset_at (index) - 1, length_at (index));
else else
return Null(byte_str_t); return Null (byte_str_t);
} }
unsigned int get_size () const unsigned int get_size () const
{ {
if (this != &Null(CFFIndex)) if (this != &Null (CFFIndex))
{ {
if (count > 0) if (count > 0)
return min_size + offset_array_size () + (offset_at (count) - 1); return min_size + offset_array_size () + (offset_at (count) - 1);
@ -232,6 +224,15 @@ struct CFFIndex
return 0; return 0;
} }
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (likely ((count.sanitize (c) && count == 0) || /* empty INDEX */
(c->check_struct (this) && offSize >= 1 && offSize <= 4 &&
c->check_array (offsets, offSize, count + 1) &&
c->check_array ((const HBUINT8*) data_base (), 1, max_offset () - 1))));
}
protected: protected:
unsigned int max_offset () const unsigned int max_offset () const
{ {
@ -245,10 +246,10 @@ struct CFFIndex
} }
public: public:
COUNT count; /* Number of object data. Note there are (count+1) offsets */ COUNT count; /* Number of object data. Note there are (count+1) offsets */
HBUINT8 offSize; /* The byte size of each offset in the offsets array. */ HBUINT8 offSize; /* The byte size of each offset in the offsets array. */
HBUINT8 offsets[VAR]; /* The array of (count + 1) offsets into objects array (1-base). */ HBUINT8 offsets[VAR]; /* The array of (count + 1) offsets into objects array (1-base). */
/* HBUINT8 data[VAR]; Object data */ /* HBUINT8 data[VAR]; Object data */
public: public:
DEFINE_SIZE_ARRAY (COUNT::static_size + HBUINT8::static_size, offsets); DEFINE_SIZE_ARRAY (COUNT::static_size + HBUINT8::static_size, offsets);
}; };
@ -293,7 +294,7 @@ struct CFFIndexOf : CFFIndex<COUNT>
/* serialize data */ /* serialize data */
for (unsigned int i = 0; i < dataArrayLen; i++) for (unsigned int i = 0; i < dataArrayLen; i++)
{ {
TYPE *dest = c->start_embed<TYPE> (); TYPE *dest = c->start_embed<TYPE> ();
if (unlikely (dest == nullptr || if (unlikely (dest == nullptr ||
!dest->serialize (c, dataArray[i], param1, param2))) !dest->serialize (c, dataArray[i], param1, param2)))
return_trace (false); return_trace (false);
@ -310,7 +311,7 @@ struct CFFIndexOf : CFFIndex<COUNT>
const PARAM &param) const PARAM &param)
{ {
/* determine offset size */ /* determine offset size */
unsigned int totalDataSize = 0; unsigned int totalDataSize = 0;
for (unsigned int i = 0; i < dataArrayLen; i++) for (unsigned int i = 0; i < dataArrayLen; i++)
{ {
unsigned int dataSize = TYPE::calculate_serialized_size (dataArray[i], param); unsigned int dataSize = TYPE::calculate_serialized_size (dataArray[i], param);
@ -334,10 +335,9 @@ struct Dict : UnsizedByteStr
{ {
TRACE_SERIALIZE (this); TRACE_SERIALIZE (this);
for (unsigned int i = 0; i < dictval.get_count (); i++) for (unsigned int i = 0; i < dictval.get_count (); i++)
{
if (unlikely (!opszr.serialize (c, dictval[i], param))) if (unlikely (!opszr.serialize (c, dictval[i], param)))
return_trace (false); return_trace (false);
}
return_trace (true); return_trace (true);
} }
@ -391,14 +391,10 @@ struct Dict : UnsizedByteStr
{ return serialize_int_op<HBUINT16, 0, 0x7FFF> (c, op, value, OpCode_shortint); } { return serialize_int_op<HBUINT16, 0, 0x7FFF> (c, op, value, OpCode_shortint); }
static bool serialize_offset4_op (hb_serialize_context_t *c, op_code_t op, int value) static bool serialize_offset4_op (hb_serialize_context_t *c, op_code_t op, int value)
{ { return serialize_uint4_op (c, op, value); }
return serialize_uint4_op (c, op, value);
}
static bool serialize_offset2_op (hb_serialize_context_t *c, op_code_t op, int value) static bool serialize_offset2_op (hb_serialize_context_t *c, op_code_t op, int value)
{ { return serialize_uint2_op (c, op, value); }
return serialize_uint2_op (c, op, value);
}
}; };
struct TopDict : Dict {}; struct TopDict : Dict {};
@ -432,7 +428,7 @@ struct FDArray : CFFIndexOf<COUNT, FontDict>
return_trace (false); return_trace (false);
/* serialize font dict offsets */ /* serialize font dict offsets */
unsigned int offset = 1; unsigned int offset = 1;
unsigned int fid = 0; unsigned int fid = 0;
for (; fid < fontDicts.length; fid++) for (; fid < fontDicts.length; fid++)
{ {
@ -524,9 +520,7 @@ struct FDSelect0 {
} }
hb_codepoint_t get_fd (hb_codepoint_t glyph) const hb_codepoint_t get_fd (hb_codepoint_t glyph) const
{ { return (hb_codepoint_t) fds[glyph]; }
return (hb_codepoint_t)fds[glyph];
}
unsigned int get_size (unsigned int num_glyphs) const unsigned int get_size (unsigned int num_glyphs) const
{ return HBUINT8::static_size * num_glyphs; } { return HBUINT8::static_size * num_glyphs; }
@ -537,7 +531,8 @@ struct FDSelect0 {
}; };
template <typename GID_TYPE, typename FD_TYPE> template <typename GID_TYPE, typename FD_TYPE>
struct FDSelect3_4_Range { struct FDSelect3_4_Range
{
bool sanitize (hb_sanitize_context_t *c, const void * /*nullptr*/, unsigned int fdcount) const bool sanitize (hb_sanitize_context_t *c, const void * /*nullptr*/, unsigned int fdcount) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
@ -546,12 +541,13 @@ struct FDSelect3_4_Range {
GID_TYPE first; GID_TYPE first;
FD_TYPE fd; FD_TYPE fd;
public:
DEFINE_SIZE_STATIC (GID_TYPE::static_size + FD_TYPE::static_size); DEFINE_SIZE_STATIC (GID_TYPE::static_size + FD_TYPE::static_size);
}; };
template <typename GID_TYPE, typename FD_TYPE> template <typename GID_TYPE, typename FD_TYPE>
struct FDSelect3_4 { struct FDSelect3_4
{
unsigned int get_size () const unsigned int get_size () const
{ return GID_TYPE::static_size * 2 + ranges.get_size (); } { return GID_TYPE::static_size * 2 + ranges.get_size (); }
@ -563,10 +559,8 @@ struct FDSelect3_4 {
return_trace (false); return_trace (false);
for (unsigned int i = 1; i < nRanges (); i++) for (unsigned int i = 1; i < nRanges (); i++)
{
if (unlikely (ranges[i - 1].first >= ranges[i].first)) if (unlikely (ranges[i - 1].first >= ranges[i].first))
return_trace (false); return_trace (false);
}
if (unlikely (!sentinel().sanitize (c) || (sentinel() != c->get_num_glyphs ()))) if (unlikely (!sentinel().sanitize (c) || (sentinel() != c->get_num_glyphs ())))
return_trace (false); return_trace (false);
@ -598,17 +592,8 @@ struct FDSelect3_4 {
typedef FDSelect3_4<HBUINT16, HBUINT8> FDSelect3; typedef FDSelect3_4<HBUINT16, HBUINT8> FDSelect3;
typedef FDSelect3_4_Range<HBUINT16, HBUINT8> FDSelect3_Range; typedef FDSelect3_4_Range<HBUINT16, HBUINT8> FDSelect3_Range;
struct FDSelect { struct FDSelect
bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const {
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) && (format == 0 || format == 3) &&
((format == 0)?
u.format0.sanitize (c, fdcount):
u.format3.sanitize (c, fdcount))));
}
bool serialize (hb_serialize_context_t *c, const FDSelect &src, unsigned int num_glyphs) bool serialize (hb_serialize_context_t *c, const FDSelect &src, unsigned int num_glyphs)
{ {
TRACE_SERIALIZE (this); TRACE_SERIALIZE (this);
@ -624,30 +609,46 @@ struct FDSelect {
unsigned int get_size (unsigned int num_glyphs) const unsigned int get_size (unsigned int num_glyphs) const
{ {
unsigned int size = format.static_size; switch (format)
if (format == 0) {
size += u.format0.get_size (num_glyphs); case 0: return format.static_size + u.format0.get_size (num_glyphs);
else case 3: return format.static_size + u.format3.get_size ();
size += u.format3.get_size (); default:return 0;
return size; }
} }
hb_codepoint_t get_fd (hb_codepoint_t glyph) const hb_codepoint_t get_fd (hb_codepoint_t glyph) const
{ {
if (this == &Null(FDSelect)) if (this == &Null (FDSelect))
return 0; return 0;
if (format == 0) switch (format)
return u.format0.get_fd (glyph); {
else case 0: return u.format0.get_fd (glyph);
return u.format3.get_fd (glyph); case 3: return u.format3.get_fd (glyph);
default:return 0;
}
} }
HBUINT8 format; bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const
union { {
FDSelect0 format0; TRACE_SANITIZE (this);
FDSelect3 format3; if (unlikely (!c->check_struct (this)))
} u; return_trace (false);
switch (format)
{
case 0: return_trace (u.format0.sanitize (c, fdcount));
case 3: return_trace (u.format3.sanitize (c, fdcount));
default:return_trace (false);
}
}
HBUINT8 format;
union {
FDSelect0 format0;
FDSelect3 format3;
} u;
public:
DEFINE_SIZE_MIN (1); DEFINE_SIZE_MIN (1);
}; };

View File

@ -161,21 +161,8 @@ struct CFF1SuppEncData {
DEFINE_SIZE_ARRAY_SIZED (1, supps); DEFINE_SIZE_ARRAY_SIZED (1, supps);
}; };
struct Encoding { struct Encoding
bool sanitize (hb_sanitize_context_t *c) const {
{
TRACE_SANITIZE (this);
if (unlikely (!c->check_struct (this)))
return_trace (false);
unsigned int fmt = format & 0x7F;
if (unlikely (fmt > 1))
return_trace (false);
if (unlikely (!((fmt == 0)? u.format0.sanitize (c): u.format1.sanitize (c))))
return_trace (false);
return_trace (((format & 0x80) == 0) || suppEncData ().sanitize (c));
}
/* serialize a fullset Encoding */ /* serialize a fullset Encoding */
bool serialize (hb_serialize_context_t *c, const Encoding &src) bool serialize (hb_serialize_context_t *c, const Encoding &src)
{ {
@ -197,11 +184,12 @@ struct Encoding {
TRACE_SERIALIZE (this); TRACE_SERIALIZE (this);
Encoding *dest = c->extend_min (*this); Encoding *dest = c->extend_min (*this);
if (unlikely (dest == nullptr)) return_trace (false); if (unlikely (dest == nullptr)) return_trace (false);
dest->format = format | ((supp_codes.length > 0)? 0x80: 0); dest->format = format | ((supp_codes.length > 0) ? 0x80 : 0);
if (format == 0) switch (format) {
case 0:
{ {
Encoding0 *fmt0 = c->allocate_size<Encoding0> (Encoding0::min_size + HBUINT8::static_size * enc_count); Encoding0 *fmt0 = c->allocate_size<Encoding0> (Encoding0::min_size + HBUINT8::static_size * enc_count);
if (unlikely (fmt0 == nullptr)) return_trace (false); if (unlikely (fmt0 == nullptr)) return_trace (false);
fmt0->nCodes () = enc_count; fmt0->nCodes () = enc_count;
unsigned int glyph = 0; unsigned int glyph = 0;
for (unsigned int i = 0; i < code_ranges.length; i++) for (unsigned int i = 0; i < code_ranges.length; i++)
@ -213,7 +201,9 @@ struct Encoding {
return_trace (false); return_trace (false);
} }
} }
else break;
case 1:
{ {
Encoding1 *fmt1 = c->allocate_size<Encoding1> (Encoding1::min_size + Encoding1_Range::static_size * code_ranges.length); Encoding1 *fmt1 = c->allocate_size<Encoding1> (Encoding1::min_size + Encoding1_Range::static_size * code_ranges.length);
if (unlikely (fmt1 == nullptr)) return_trace (false); if (unlikely (fmt1 == nullptr)) return_trace (false);
@ -226,7 +216,11 @@ struct Encoding {
fmt1->ranges[i].nLeft = code_ranges[i].glyph; fmt1->ranges[i].nLeft = code_ranges[i].glyph;
} }
} }
if (supp_codes.length > 0) break;
}
if (supp_codes.length)
{ {
CFF1SuppEncData *suppData = c->allocate_size<CFF1SuppEncData> (CFF1SuppEncData::min_size + SuppEncoding::static_size * supp_codes.length); CFF1SuppEncData *suppData = c->allocate_size<CFF1SuppEncData> (CFF1SuppEncData::min_size + SuppEncoding::static_size * supp_codes.length);
if (unlikely (suppData == nullptr)) return_trace (false); if (unlikely (suppData == nullptr)) return_trace (false);
@ -237,6 +231,7 @@ struct Encoding {
suppData->supps[i].glyph = supp_codes[i].glyph; /* actually SID */ suppData->supps[i].glyph = supp_codes[i].glyph; /* actually SID */
} }
} }
return_trace (true); return_trace (true);
} }
@ -245,11 +240,13 @@ struct Encoding {
unsigned int enc_count, unsigned int enc_count,
unsigned int supp_count) unsigned int supp_count)
{ {
unsigned int size = min_size; unsigned int size = min_size;
if (format == 0) switch (format)
size += Encoding0::min_size + HBUINT8::static_size * enc_count; {
else case 0: size += Encoding0::min_size + HBUINT8::static_size * enc_count; break;
size += Encoding1::min_size + Encoding1_Range::static_size * enc_count; case 1: size += Encoding1::min_size + Encoding1_Range::static_size * enc_count; break;
default:return 0;
}
if (supp_count > 0) if (supp_count > 0)
size += CFF1SuppEncData::min_size + SuppEncoding::static_size * supp_count; size += CFF1SuppEncData::min_size + SuppEncoding::static_size * supp_count;
return size; return size;
@ -258,10 +255,11 @@ struct Encoding {
unsigned int get_size () const unsigned int get_size () const
{ {
unsigned int size = min_size; unsigned int size = min_size;
if (table_format () == 0) switch (table_format ())
size += u.format0.get_size (); {
else case 0: size += u.format0.get_size (); break;
size += u.format1.get_size (); case 1: size += u.format1.get_size (); break;
}
if (has_supplement ()) if (has_supplement ())
size += suppEncData ().get_size (); size += suppEncData ().get_size ();
return size; return size;
@ -269,14 +267,16 @@ struct Encoding {
hb_codepoint_t get_code (hb_codepoint_t glyph) const hb_codepoint_t get_code (hb_codepoint_t glyph) const
{ {
if (table_format () == 0) switch (table_format ())
return u.format0.get_code (glyph); {
else case 0: return u.format0.get_code (glyph);
return u.format1.get_code (glyph); case 1: return u.format1.get_code (glyph);
default:return 0;
}
} }
uint8_t table_format () const { return (format & 0x7F); } uint8_t table_format () const { return format & 0x7F; }
bool has_supplement () const { return (format & 0x80) != 0; } bool has_supplement () const { return format & 0x80; }
void get_supplement_codes (hb_codepoint_t sid, hb_vector_t<hb_codepoint_t> &codes) const void get_supplement_codes (hb_codepoint_t sid, hb_vector_t<hb_codepoint_t> &codes) const
{ {
@ -285,21 +285,37 @@ struct Encoding {
suppEncData().get_codes (sid, codes); suppEncData().get_codes (sid, codes);
} }
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
if (unlikely (!c->check_struct (this)))
return_trace (false);
switch (table_format ())
{
case 0: if (unlikely (!u.format0.sanitize (c))) { return_trace (false); } break;
case 1: if (unlikely (!u.format1.sanitize (c))) { return_trace (false); } break;
default:return_trace (false);
}
return_trace (likely (!has_supplement () || suppEncData ().sanitize (c)));
}
protected: protected:
const CFF1SuppEncData &suppEncData () const const CFF1SuppEncData &suppEncData () const
{ {
if ((format & 0x7F) == 0) switch (table_format ())
return StructAfter<CFF1SuppEncData> (u.format0.codes[u.format0.nCodes ()-1]); {
else case 0: return StructAfter<CFF1SuppEncData> (u.format0.codes[u.format0.nCodes ()-1]);
return StructAfter<CFF1SuppEncData> (u.format1.ranges[u.format1.nRanges ()-1]); case 1: return StructAfter<CFF1SuppEncData> (u.format1.ranges[u.format1.nRanges ()-1]);
default:return Null (CFF1SuppEncData);
}
} }
public: public:
HBUINT8 format; HBUINT8 format;
union { union {
Encoding0 format0; Encoding0 format0;
Encoding1 format1; Encoding1 format1;
} u; } u;
/* CFF1SuppEncData suppEncData; */ /* CFF1SuppEncData suppEncData; */
@ -433,23 +449,8 @@ typedef Charset1_2<HBUINT16> Charset2;
typedef Charset_Range<HBUINT8> Charset1_Range; typedef Charset_Range<HBUINT8> Charset1_Range;
typedef Charset_Range<HBUINT16> Charset2_Range; typedef Charset_Range<HBUINT16> Charset2_Range;
struct Charset { struct Charset
bool sanitize (hb_sanitize_context_t *c) const {
{
TRACE_SANITIZE (this);
if (unlikely (!c->check_struct (this)))
return_trace (false);
if (format == 0)
return_trace (u.format0.sanitize (c, c->get_num_glyphs ()));
else if (format == 1)
return_trace (u.format1.sanitize (c, c->get_num_glyphs ()));
else if (likely (format == 2))
return_trace (u.format2.sanitize (c, c->get_num_glyphs ()));
else
return_trace (false);
}
/* serialize a fullset Charset */ /* serialize a fullset Charset */
bool serialize (hb_serialize_context_t *c, const Charset &src, unsigned int num_glyphs) bool serialize (hb_serialize_context_t *c, const Charset &src, unsigned int num_glyphs)
{ {
@ -471,10 +472,12 @@ struct Charset {
Charset *dest = c->extend_min (*this); Charset *dest = c->extend_min (*this);
if (unlikely (dest == nullptr)) return_trace (false); if (unlikely (dest == nullptr)) return_trace (false);
dest->format = format; dest->format = format;
if (format == 0) switch (format)
{
case 0:
{ {
Charset0 *fmt0 = c->allocate_size<Charset0> (Charset0::min_size + HBUINT16::static_size * (num_glyphs - 1)); Charset0 *fmt0 = c->allocate_size<Charset0> (Charset0::min_size + HBUINT16::static_size * (num_glyphs - 1));
if (unlikely (fmt0 == nullptr)) return_trace (false); if (unlikely (fmt0 == nullptr)) return_trace (false);
unsigned int glyph = 0; unsigned int glyph = 0;
for (unsigned int i = 0; i < sid_ranges.length; i++) for (unsigned int i = 0; i < sid_ranges.length; i++)
{ {
@ -483,7 +486,9 @@ struct Charset {
fmt0->sids[glyph++] = sid++; fmt0->sids[glyph++] = sid++;
} }
} }
else if (format == 1) break;
case 1:
{ {
Charset1 *fmt1 = c->allocate_size<Charset1> (Charset1::min_size + Charset1_Range::static_size * sid_ranges.length); Charset1 *fmt1 = c->allocate_size<Charset1> (Charset1::min_size + Charset1_Range::static_size * sid_ranges.length);
if (unlikely (fmt1 == nullptr)) return_trace (false); if (unlikely (fmt1 == nullptr)) return_trace (false);
@ -495,7 +500,9 @@ struct Charset {
fmt1->ranges[i].nLeft = sid_ranges[i].glyph; fmt1->ranges[i].nLeft = sid_ranges[i].glyph;
} }
} }
else /* format 2 */ break;
case 2:
{ {
Charset2 *fmt2 = c->allocate_size<Charset2> (Charset2::min_size + Charset2_Range::static_size * sid_ranges.length); Charset2 *fmt2 = c->allocate_size<Charset2> (Charset2::min_size + Charset2_Range::static_size * sid_ranges.length);
if (unlikely (fmt2 == nullptr)) return_trace (false); if (unlikely (fmt2 == nullptr)) return_trace (false);
@ -506,56 +513,72 @@ struct Charset {
fmt2->ranges[i].first = sid_ranges[i].code; fmt2->ranges[i].first = sid_ranges[i].code;
fmt2->ranges[i].nLeft = sid_ranges[i].glyph; fmt2->ranges[i].nLeft = sid_ranges[i].glyph;
} }
}
break;
} }
return_trace (true); return_trace (true);
} }
/* parallel to above: calculate the size of a subset Charset */ /* parallel to above: calculate the size of a subset Charset */
static unsigned int calculate_serialized_size ( static unsigned int calculate_serialized_size (uint8_t format,
uint8_t format, unsigned int count)
unsigned int count)
{ {
unsigned int size = min_size; switch (format)
if (format == 0) {
size += Charset0::min_size + HBUINT16::static_size * (count - 1); case 0: return min_size + Charset0::min_size + HBUINT16::static_size * (count - 1);
else if (format == 1) case 1: return min_size + Charset1::min_size + Charset1_Range::static_size * count;
size += Charset1::min_size + Charset1_Range::static_size * count; case 2: return min_size + Charset2::min_size + Charset2_Range::static_size * count;
else default:return 0;
size += Charset2::min_size + Charset2_Range::static_size * count; }
return size;
} }
unsigned int get_size (unsigned int num_glyphs) const unsigned int get_size (unsigned int num_glyphs) const
{ {
unsigned int size = min_size; switch (format)
if (format == 0) {
size += u.format0.get_size (num_glyphs); case 0: return min_size + u.format0.get_size (num_glyphs);
else if (format == 1) case 1: return min_size + u.format1.get_size (num_glyphs);
size += u.format1.get_size (num_glyphs); case 2: return min_size + u.format2.get_size (num_glyphs);
else default:return 0;
size += u.format2.get_size (num_glyphs); }
return size;
} }
hb_codepoint_t get_sid (hb_codepoint_t glyph) const hb_codepoint_t get_sid (hb_codepoint_t glyph) const
{ {
if (format == 0) switch (format)
return u.format0.get_sid (glyph); {
else if (format == 1) case 0: return u.format0.get_sid (glyph);
return u.format1.get_sid (glyph); case 1: return u.format1.get_sid (glyph);
else case 2: return u.format2.get_sid (glyph);
return u.format2.get_sid (glyph); default:return 0;
}
} }
hb_codepoint_t get_glyph (hb_codepoint_t sid, unsigned int num_glyphs) const hb_codepoint_t get_glyph (hb_codepoint_t sid, unsigned int num_glyphs) const
{ {
if (format == 0) switch (format)
return u.format0.get_glyph (sid, num_glyphs); {
else if (format == 1) case 0: return u.format0.get_glyph (sid, num_glyphs);
return u.format1.get_glyph (sid, num_glyphs); case 1: return u.format1.get_glyph (sid, num_glyphs);
else case 2: return u.format2.get_glyph (sid, num_glyphs);
return u.format2.get_glyph (sid, num_glyphs); default:return 0;
}
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
if (unlikely (!c->check_struct (this)))
return_trace (false);
switch (format)
{
case 0: return_trace (u.format0.sanitize (c, c->get_num_glyphs ()));
case 1: return_trace (u.format1.sanitize (c, c->get_num_glyphs ()));
case 2: return_trace (u.format2.sanitize (c, c->get_num_glyphs ()));
default:return_trace (false);
}
} }
HBUINT8 format; HBUINT8 format;

View File

@ -51,18 +51,6 @@ typedef FDSelect3_4_Range<HBUINT32, HBUINT16> FDSelect4_Range;
struct CFF2FDSelect struct CFF2FDSelect
{ {
bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) && (format == 0 || format == 3 || format == 4) &&
((format == 0)?
u.format0.sanitize (c, fdcount):
((format == 3)?
u.format3.sanitize (c, fdcount):
u.format4.sanitize (c, fdcount)))));
}
bool serialize (hb_serialize_context_t *c, const CFF2FDSelect &src, unsigned int num_glyphs) bool serialize (hb_serialize_context_t *c, const CFF2FDSelect &src, unsigned int num_glyphs)
{ {
TRACE_SERIALIZE (this); TRACE_SERIALIZE (this);
@ -78,35 +66,51 @@ struct CFF2FDSelect
unsigned int get_size (unsigned int num_glyphs) const unsigned int get_size (unsigned int num_glyphs) const
{ {
unsigned int size = format.static_size; switch (format)
if (format == 0) {
size += u.format0.get_size (num_glyphs); case 0: return format.static_size + u.format0.get_size (num_glyphs);
else if (format == 3) case 3: return format.static_size + u.format3.get_size ();
size += u.format3.get_size (); case 4: return format.static_size + u.format4.get_size ();
else default:return 0;
size += u.format4.get_size (); }
return size;
} }
hb_codepoint_t get_fd (hb_codepoint_t glyph) const hb_codepoint_t get_fd (hb_codepoint_t glyph) const
{ {
if (this == &Null(CFF2FDSelect)) if (this == &Null (CFF2FDSelect))
return 0; return 0;
if (format == 0)
return u.format0.get_fd (glyph); switch (format)
else if (format == 3) {
return u.format3.get_fd (glyph); case 0: return u.format0.get_fd (glyph);
else case 3: return u.format3.get_fd (glyph);
return u.format4.get_fd (glyph); case 4: return u.format4.get_fd (glyph);
default:return 0;
}
} }
HBUINT8 format; bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const
union { {
FDSelect0 format0; TRACE_SANITIZE (this);
FDSelect3 format3; if (unlikely (!c->check_struct (this)))
FDSelect4 format4; return_trace (false);
} u;
switch (format)
{
case 0: return_trace (u.format0.sanitize (c, fdcount));
case 3: return_trace (u.format3.sanitize (c, fdcount));
case 4: return_trace (u.format4.sanitize (c, fdcount));
default:return_trace (false);
}
}
HBUINT8 format;
union {
FDSelect0 format0;
FDSelect3 format3;
FDSelect4 format4;
} u;
public:
DEFINE_SIZE_MIN (2); DEFINE_SIZE_MIN (2);
}; };

View File

@ -185,7 +185,7 @@ struct glyf
+ hb_range (plan->num_output_glyphs ()) + hb_range (plan->num_output_glyphs ())
| hb_map ([&] (hb_codepoint_t new_gid) { | hb_map ([&] (hb_codepoint_t new_gid) {
SubsetGlyph subset_glyph; SubsetGlyph subset_glyph = {0};
subset_glyph.new_gid = new_gid; subset_glyph.new_gid = new_gid;
// should never fail: all old gids should be mapped // should never fail: all old gids should be mapped

View File

@ -94,39 +94,35 @@ struct maxp
return_trace (likely (version.major == 0 && version.minor == 0x5000u)); return_trace (likely (version.major == 0 && version.minor == 0x5000u));
} }
bool subset (hb_subset_plan_t *plan) const bool subset (hb_subset_context_t *c) const
{ {
hb_blob_t *maxp_blob = hb_sanitize_context_t().reference_table<maxp> (plan->source); TRACE_SUBSET (this);
hb_blob_t *maxp_prime_blob = hb_blob_copy_writable_or_fail (maxp_blob); maxp *maxp_prime = c->serializer->embed (this);
hb_blob_destroy (maxp_blob); if (unlikely (!maxp_prime)) return_trace (false);
if (unlikely (!maxp_prime_blob)) { maxp_prime->numGlyphs = c->plan->num_output_glyphs ();
return false;
}
maxp *maxp_prime = (maxp *) hb_blob_get_data (maxp_prime_blob, nullptr);
maxp_prime->set_num_glyphs (plan->num_output_glyphs ());
if (plan->drop_hints)
drop_hint_fields (plan, maxp_prime);
bool result = plan->add_table (HB_OT_TAG_maxp, maxp_prime_blob);
hb_blob_destroy (maxp_prime_blob);
return result;
}
static void drop_hint_fields (hb_subset_plan_t *plan HB_UNUSED, maxp *maxp_prime)
{
if (maxp_prime->version.major == 1) if (maxp_prime->version.major == 1)
{ {
maxpV1Tail &v1 = StructAfter<maxpV1Tail> (*maxp_prime); const maxpV1Tail *src_v1 = &StructAfter<maxpV1Tail> (*this);
v1.maxZones = 1; maxpV1Tail *dest_v1 = c->serializer->embed<maxpV1Tail> (src_v1);
v1.maxTwilightPoints = 0; if (unlikely (!dest_v1)) return_trace (false);
v1.maxStorage = 0;
v1.maxFunctionDefs = 0; if (c->plan->drop_hints)
v1.maxInstructionDefs = 0; drop_hint_fields (dest_v1);
v1.maxStackElements = 0;
v1.maxSizeOfInstructions = 0;
} }
return_trace (true);
}
static void drop_hint_fields (maxpV1Tail* dest_v1)
{
dest_v1->maxZones = 1;
dest_v1->maxTwilightPoints = 0;
dest_v1->maxStorage = 0;
dest_v1->maxFunctionDefs = 0;
dest_v1->maxInstructionDefs = 0;
dest_v1->maxStackElements = 0;
dest_v1->maxSizeOfInstructions = 0;
} }
protected: protected:

View File

@ -145,29 +145,20 @@ struct OS2
} }
} }
bool subset (hb_subset_plan_t *plan) const bool subset (hb_subset_context_t *c) const
{ {
hb_blob_t *os2_blob = hb_sanitize_context_t ().reference_table<OS2> (plan->source); TRACE_SUBSET (this);
hb_blob_t *os2_prime_blob = hb_blob_create_sub_blob (os2_blob, 0, -1); OS2 *os2_prime = c->serializer->embed (this);
// TODO(grieger): move to hb_blob_copy_writable_or_fail if (unlikely (!os2_prime)) return_trace (false);
hb_blob_destroy (os2_blob);
OS2 *os2_prime = (OS2 *) hb_blob_get_data_writable (os2_prime_blob, nullptr);
if (unlikely (!os2_prime)) {
hb_blob_destroy (os2_prime_blob);
return false;
}
uint16_t min_cp, max_cp; uint16_t min_cp, max_cp;
find_min_and_max_codepoint (plan->unicodes, &min_cp, &max_cp); find_min_and_max_codepoint (c->plan->unicodes, &min_cp, &max_cp);
os2_prime->usFirstCharIndex = min_cp; os2_prime->usFirstCharIndex = min_cp;
os2_prime->usLastCharIndex = max_cp; os2_prime->usLastCharIndex = max_cp;
_update_unicode_ranges (plan->unicodes, os2_prime->ulUnicodeRange); _update_unicode_ranges (c->plan->unicodes, os2_prime->ulUnicodeRange);
bool result = plan->add_table (HB_OT_TAG_OS2, os2_prime_blob);
hb_blob_destroy (os2_prime_blob); return_trace (true);
return result;
} }
void _update_unicode_ranges (const hb_set_t *codepoints, void _update_unicode_ranges (const hb_set_t *codepoints,
@ -218,6 +209,15 @@ struct OS2
font_page_t get_font_page () const font_page_t get_font_page () const
{ return (font_page_t) (version == 0 ? fsSelection & 0xFF00 : 0); } { return (font_page_t) (version == 0 ? fsSelection & 0xFF00 : 0); }
unsigned get_size () const
{
unsigned result = min_size;
if (version >= 1) result += v1X.get_size ();
if (version >= 2) result += v2X.get_size ();
if (version >= 5) result += v5X.get_size ();
return result;
}
bool sanitize (hb_sanitize_context_t *c) const bool sanitize (hb_sanitize_context_t *c) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);

View File

@ -73,26 +73,25 @@ struct post
{ {
static constexpr hb_tag_t tableTag = HB_OT_TAG_post; static constexpr hb_tag_t tableTag = HB_OT_TAG_post;
bool subset (hb_subset_plan_t *plan) const void serialize (hb_serialize_context_t *c) const
{ {
unsigned int post_prime_length; post *post_prime = c->allocate_min<post> ();
hb_blob_t *post_blob = hb_sanitize_context_t ().reference_table<post>(plan->source); if (unlikely (!post_prime)) return;
hb_blob_t *post_prime_blob = hb_blob_create_sub_blob (post_blob, 0, post::min_size);
post *post_prime = (post *) hb_blob_get_data_writable (post_prime_blob, &post_prime_length);
hb_blob_destroy (post_blob);
if (unlikely (!post_prime || post_prime_length != post::min_size))
{
hb_blob_destroy (post_prime_blob);
DEBUG_MSG(SUBSET, nullptr, "Invalid source post table with length %d.", post_prime_length);
return false;
}
memcpy (post_prime, this, post::min_size);
post_prime->version.major = 3; // Version 3 does not have any glyph names. post_prime->version.major = 3; // Version 3 does not have any glyph names.
bool result = plan->add_table (HB_OT_TAG_post, post_prime_blob); }
hb_blob_destroy (post_prime_blob);
return result; bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
post *post_prime = c->serializer->start_embed<post> ();
if (unlikely (!post_prime)) return_trace (false);
serialize (c->serializer);
if (c->serializer->in_error () || c->serializer->ran_out_of_room) return_trace (false);
return_trace (true);
} }
struct accelerator_t struct accelerator_t
@ -158,7 +157,7 @@ struct post
for (unsigned int i = 0; i < count; i++) for (unsigned int i = 0; i < count; i++)
gids[i] = i; gids[i] = i;
hb_sort_r (gids, count, sizeof (gids[0]), cmp_gids, (void *) this); hb_qsort (gids, count, sizeof (gids[0]), cmp_gids, (void *) this);
if (unlikely (!gids_sorted_by_name.cmpexch (nullptr, gids))) if (unlikely (!gids_sorted_by_name.cmpexch (nullptr, gids)))
{ {

View File

@ -59,14 +59,14 @@ enum
struct AxisValueFormat1 struct AxisValueFormat1
{ {
hb_ot_name_id_t get_value_name_id () const { return valueNameID; }
bool sanitize (hb_sanitize_context_t *c) const bool sanitize (hb_sanitize_context_t *c) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this))); return_trace (likely (c->check_struct (this)));
} }
hb_ot_name_id_t get_value_name_id () const { return valueNameID; }
protected: protected:
HBUINT16 format; /* Format identifier — set to 1. */ HBUINT16 format; /* Format identifier — set to 1. */
HBUINT16 axisIndex; /* Zero-base index into the axis record array HBUINT16 axisIndex; /* Zero-base index into the axis record array
@ -84,14 +84,14 @@ struct AxisValueFormat1
struct AxisValueFormat2 struct AxisValueFormat2
{ {
hb_ot_name_id_t get_value_name_id () const { return valueNameID; }
bool sanitize (hb_sanitize_context_t *c) const bool sanitize (hb_sanitize_context_t *c) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this))); return_trace (likely (c->check_struct (this)));
} }
hb_ot_name_id_t get_value_name_id () const { return valueNameID; }
protected: protected:
HBUINT16 format; /* Format identifier — set to 2. */ HBUINT16 format; /* Format identifier — set to 2. */
HBUINT16 axisIndex; /* Zero-base index into the axis record array HBUINT16 axisIndex; /* Zero-base index into the axis record array
@ -113,14 +113,14 @@ struct AxisValueFormat2
struct AxisValueFormat3 struct AxisValueFormat3
{ {
hb_ot_name_id_t get_value_name_id () const { return valueNameID; }
bool sanitize (hb_sanitize_context_t *c) const bool sanitize (hb_sanitize_context_t *c) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this))); return_trace (likely (c->check_struct (this)));
} }
hb_ot_name_id_t get_value_name_id () const { return valueNameID; }
protected: protected:
HBUINT16 format; /* Format identifier — set to 3. */ HBUINT16 format; /* Format identifier — set to 3. */
HBUINT16 axisIndex; /* Zero-base index into the axis record array HBUINT16 axisIndex; /* Zero-base index into the axis record array
@ -157,14 +157,14 @@ struct AxisValueRecord
struct AxisValueFormat4 struct AxisValueFormat4
{ {
hb_ot_name_id_t get_value_name_id () const { return valueNameID; }
bool sanitize (hb_sanitize_context_t *c) const bool sanitize (hb_sanitize_context_t *c) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this))); return_trace (likely (c->check_struct (this)));
} }
hb_ot_name_id_t get_value_name_id () const { return valueNameID; }
protected: protected:
HBUINT16 format; /* Format identifier — set to 4. */ HBUINT16 format; /* Format identifier — set to 4. */
HBUINT16 axisCount; /* The total number of axes contributing to HBUINT16 axisCount; /* The total number of axes contributing to
@ -183,6 +183,18 @@ struct AxisValueFormat4
struct AxisValue struct AxisValue
{ {
hb_ot_name_id_t get_value_name_id () const
{
switch (u.format)
{
case 1: return u.format1.get_value_name_id ();
case 2: return u.format2.get_value_name_id ();
case 3: return u.format3.get_value_name_id ();
case 4: return u.format4.get_value_name_id ();
default:return HB_OT_NAME_ID_INVALID;
}
}
bool sanitize (hb_sanitize_context_t *c) const bool sanitize (hb_sanitize_context_t *c) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
@ -191,23 +203,11 @@ struct AxisValue
switch (u.format) switch (u.format)
{ {
case 1: return_trace (likely (u.format1.sanitize (c))); case 1: return_trace (u.format1.sanitize (c));
case 2: return_trace (likely (u.format2.sanitize (c))); case 2: return_trace (u.format2.sanitize (c));
case 3: return_trace (likely (u.format3.sanitize (c))); case 3: return_trace (u.format3.sanitize (c));
case 4: return_trace (likely (u.format4.sanitize (c))); case 4: return_trace (u.format4.sanitize (c));
default: return_trace (true); default:return_trace (true);
}
}
hb_ot_name_id_t get_value_name_id () const
{
switch (u.format)
{
case 1: return u.format1.get_value_name_id ();
case 2: return u.format2.get_value_name_id ();
case 3: return u.format3.get_value_name_id ();
case 4: return u.format4.get_value_name_id ();
default: return HB_OT_NAME_ID_INVALID;
} }
} }
@ -226,14 +226,14 @@ struct AxisValue
struct StatAxisRecord struct StatAxisRecord
{ {
hb_ot_name_id_t get_name_id () const { return nameID; }
bool sanitize (hb_sanitize_context_t *c) const bool sanitize (hb_sanitize_context_t *c) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this))); return_trace (likely (c->check_struct (this)));
} }
hb_ot_name_id_t get_name_id () const { return nameID; }
protected: protected:
Tag tag; /* A tag identifying the axis of design variation. */ Tag tag; /* A tag identifying the axis of design variation. */
NameID nameID; /* The name ID for entries in the 'name' table that NameID nameID; /* The name ID for entries in the 'name' table that
@ -249,16 +249,6 @@ struct STAT
{ {
static constexpr hb_tag_t tableTag = HB_OT_TAG_STAT; static constexpr hb_tag_t tableTag = HB_OT_TAG_STAT;
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) &&
version.major == 1 &&
version.minor > 0 &&
designAxesOffset.sanitize (c, this, designAxisCount) &&
offsetToAxisValueOffsets.sanitize (c, this, axisValueCount, &(this+offsetToAxisValueOffsets))));
}
bool has_data () const { return version.to_int (); } bool has_data () const { return version.to_int (); }
unsigned get_design_axis_count () const { return designAxisCount; } unsigned get_design_axis_count () const { return designAxisCount; }
@ -295,6 +285,16 @@ struct STAT
; ;
} }
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) &&
version.major == 1 &&
version.minor > 0 &&
designAxesOffset.sanitize (c, this, designAxisCount) &&
offsetToAxisValueOffsets.sanitize (c, this, axisValueCount, &(this+offsetToAxisValueOffsets))));
}
protected: protected:
hb_array_t<const StatAxisRecord> const get_design_axes () const hb_array_t<const StatAxisRecord> const get_design_axes () const
{ return (this+designAxesOffset).as_array (designAxisCount); } { return (this+designAxesOffset).as_array (designAxisCount); }

View File

@ -145,7 +145,9 @@ hb_ot_all_tags_from_script (hb_script_t script,
hb_tag_t new_tag = hb_ot_new_tag_from_script (script); hb_tag_t new_tag = hb_ot_new_tag_from_script (script);
if (unlikely (new_tag != HB_OT_TAG_DEFAULT_SCRIPT)) if (unlikely (new_tag != HB_OT_TAG_DEFAULT_SCRIPT))
{ {
tags[i++] = new_tag | '3'; /* HB_SCRIPT_MYANMAR maps to 'mym2', but there is no 'mym3'. */
if (new_tag != HB_TAG('m','y','m','2'))
tags[i++] = new_tag | '3';
if (*count > i) if (*count > i)
tags[i++] = new_tag; tags[i++] = new_tag;
} }

View File

@ -55,7 +55,7 @@ hb_plan_subset_cff_fdselect (const hb_subset_plan_t *plan,
subset_fd_count = 0; subset_fd_count = 0;
subset_fdselect_size = 0; subset_fdselect_size = 0;
subset_fdselect_format = 0; subset_fdselect_format = 0;
unsigned int num_ranges = 0; unsigned int num_ranges = 0;
unsigned int subset_num_glyphs = plan->num_output_glyphs (); unsigned int subset_num_glyphs = plan->num_output_glyphs ();
if (subset_num_glyphs == 0) if (subset_num_glyphs == 0)
@ -63,14 +63,14 @@ hb_plan_subset_cff_fdselect (const hb_subset_plan_t *plan,
{ {
/* use hb_set to determine the subset of font dicts */ /* use hb_set to determine the subset of font dicts */
hb_set_t *set = hb_set_create (); hb_set_t *set = hb_set_create ();
if (set == &Null (hb_set_t)) if (set == &Null (hb_set_t))
return false; return false;
hb_codepoint_t prev_fd = CFF_UNDEF_CODE; hb_codepoint_t prev_fd = CFF_UNDEF_CODE;
for (hb_codepoint_t i = 0; i < subset_num_glyphs; i++) for (hb_codepoint_t i = 0; i < subset_num_glyphs; i++)
{ {
hb_codepoint_t glyph; hb_codepoint_t glyph;
hb_codepoint_t fd; hb_codepoint_t fd;
if (!plan->old_gid_for_new_gid (i, &glyph)) if (!plan->old_gid_for_new_gid (i, &glyph))
{ {
/* fonttools retains FDSelect & font dicts for missing glyphs. do the same */ /* fonttools retains FDSelect & font dicts for missing glyphs. do the same */
@ -145,10 +145,10 @@ hb_plan_subset_cff_fdselect (const hb_subset_plan_t *plan,
template <typename FDSELECT3_4> template <typename FDSELECT3_4>
static inline bool static inline bool
serialize_fdselect_3_4 (hb_serialize_context_t *c, serialize_fdselect_3_4 (hb_serialize_context_t *c,
const unsigned int num_glyphs, const unsigned int num_glyphs,
const FDSelect &src, const FDSelect &src,
unsigned int size, unsigned int size,
const hb_vector_t<code_pair_t> &fdselect_ranges) const hb_vector_t<code_pair_t> &fdselect_ranges)
{ {
TRACE_SERIALIZE (this); TRACE_SERIALIZE (this);
FDSELECT3_4 *p = c->allocate_size<FDSELECT3_4> (size); FDSELECT3_4 *p = c->allocate_size<FDSELECT3_4> (size);
@ -159,7 +159,7 @@ serialize_fdselect_3_4 (hb_serialize_context_t *c,
p->ranges[i].first = fdselect_ranges[i].glyph; p->ranges[i].first = fdselect_ranges[i].glyph;
p->ranges[i].fd = fdselect_ranges[i].code; p->ranges[i].fd = fdselect_ranges[i].code;
} }
p->sentinel() = num_glyphs; p->sentinel () = num_glyphs;
return_trace (true); return_trace (true);
} }
@ -169,15 +169,15 @@ serialize_fdselect_3_4 (hb_serialize_context_t *c,
**/ **/
bool bool
hb_serialize_cff_fdselect (hb_serialize_context_t *c, hb_serialize_cff_fdselect (hb_serialize_context_t *c,
const unsigned int num_glyphs, const unsigned int num_glyphs,
const FDSelect &src, const FDSelect &src,
unsigned int fd_count, unsigned int fd_count,
unsigned int fdselect_format, unsigned int fdselect_format,
unsigned int size, unsigned int size,
const hb_vector_t<code_pair_t> &fdselect_ranges) const hb_vector_t<code_pair_t> &fdselect_ranges)
{ {
TRACE_SERIALIZE (this); TRACE_SERIALIZE (this);
FDSelect *p = c->allocate_min<FDSelect> (); FDSelect *p = c->allocate_min<FDSelect> ();
if (unlikely (p == nullptr)) return_trace (false); if (unlikely (p == nullptr)) return_trace (false);
p->format = fdselect_format; p->format = fdselect_format;
size -= FDSelect::min_size; size -= FDSelect::min_size;
@ -185,42 +185,34 @@ hb_serialize_cff_fdselect (hb_serialize_context_t *c,
switch (fdselect_format) switch (fdselect_format)
{ {
#if CFF_SERIALIZE_FDSELECT_0 #if CFF_SERIALIZE_FDSELECT_0
case 0: case 0:
{
FDSelect0 *p = c->allocate_size<FDSelect0> (size);
if (unlikely (p == nullptr)) return_trace (false);
unsigned int range_index = 0;
unsigned int fd = fdselect_ranges[range_index++].code;
for (unsigned int i = 0; i < num_glyphs; i++)
{ {
FDSelect0 *p = c->allocate_size<FDSelect0> (size); if ((range_index < fdselect_ranges.len) &&
if (unlikely (p == nullptr)) return_trace (false); (i >= fdselect_ranges[range_index].glyph))
unsigned int range_index = 0;
unsigned int fd = fdselect_ranges[range_index++].code;
for (unsigned int i = 0; i < num_glyphs; i++)
{ {
if ((range_index < fdselect_ranges.len) && fd = fdselect_ranges[range_index++].code;
(i >= fdselect_ranges[range_index].glyph))
{
fd = fdselect_ranges[range_index++].code;
}
p->fds[i] = fd;
} }
break; p->fds[i] = fd;
} }
return_trace (true);
}
#endif /* CFF_SERIALIZE_FDSELECT_0 */ #endif /* CFF_SERIALIZE_FDSELECT_0 */
case 3: case 3:
return serialize_fdselect_3_4<FDSelect3> (c, return serialize_fdselect_3_4<FDSelect3> (c, num_glyphs, src,
num_glyphs, size, fdselect_ranges);
src,
size,
fdselect_ranges);
case 4: case 4:
return serialize_fdselect_3_4<FDSelect4> (c, return serialize_fdselect_3_4<FDSelect4> (c, num_glyphs, src,
num_glyphs, size, fdselect_ranges);
src,
size,
fdselect_ranges);
default: default:
assert(false); return_trace (false);
} }
return_trace (true);
} }

View File

@ -1037,7 +1037,7 @@ static inline bool _write_cff1 (const cff_subset_plan &plan,
bool result; bool result;
cff_private_dict_op_serializer_t privSzr (plan.desubroutinize, plan.drop_hints); cff_private_dict_op_serializer_t privSzr (plan.desubroutinize, plan.drop_hints);
/* N.B. local subrs immediately follows its corresponding private dict. i.e., subr offset == private dict size */ /* N.B. local subrs immediately follows its corresponding private dict. i.e., subr offset == private dict size */
unsigned int subroffset = (plan.offsets.localSubrsInfos[i].size > 0)? priv_size: 0; unsigned int subroffset = (plan.offsets.localSubrsInfos[i].size > 0) ? priv_size : 0;
result = pd->serialize (&c, acc.privateDicts[i], privSzr, subroffset); result = pd->serialize (&c, acc.privateDicts[i], privSzr, subroffset);
if (unlikely (!result)) if (unlikely (!result))
{ {

View File

@ -545,7 +545,7 @@ static inline bool _write_cff2 (const cff2_subset_plan &plan,
bool result; bool result;
cff_private_dict_op_serializer_t privSzr (plan.desubroutinize, plan.drop_hints); cff_private_dict_op_serializer_t privSzr (plan.desubroutinize, plan.drop_hints);
/* N.B. local subrs immediately follows its corresponding private dict. i.e., subr offset == private dict size */ /* N.B. local subrs immediately follows its corresponding private dict. i.e., subr offset == private dict size */
unsigned int subroffset = (plan.offsets.localSubrsInfos[i].size > 0)? priv_size: 0; unsigned int subroffset = (plan.offsets.localSubrsInfos[i].size > 0) ? priv_size : 0;
result = pd->serialize (&c, acc.privateDicts[i], privSzr, subroffset); result = pd->serialize (&c, acc.privateDicts[i], privSzr, subroffset);
if (unlikely (!result)) if (unlikely (!result))
{ {

View File

@ -183,7 +183,7 @@ _subset_table (hb_subset_plan_t *plan,
result = _subset2<const OT::vmtx> (plan); result = _subset2<const OT::vmtx> (plan);
break; break;
case HB_OT_TAG_maxp: case HB_OT_TAG_maxp:
result = _subset<const OT::maxp> (plan); result = _subset2<const OT::maxp> (plan);
break; break;
case HB_OT_TAG_loca: case HB_OT_TAG_loca:
DEBUG_MSG(SUBSET, nullptr, "skip loca handled by glyf"); DEBUG_MSG(SUBSET, nullptr, "skip loca handled by glyf");
@ -192,10 +192,10 @@ _subset_table (hb_subset_plan_t *plan,
result = _subset<const OT::cmap> (plan); result = _subset<const OT::cmap> (plan);
break; break;
case HB_OT_TAG_OS2: case HB_OT_TAG_OS2:
result = _subset<const OT::OS2> (plan); result = _subset2<const OT::OS2> (plan);
break; break;
case HB_OT_TAG_post: case HB_OT_TAG_post:
result = _subset<const OT::post> (plan); result = _subset2<const OT::post> (plan);
break; break;
#ifndef HB_NO_SUBSET_CFF #ifndef HB_NO_SUBSET_CFF

View File

@ -86,8 +86,8 @@ _hb_ucd_sc_map[138] =
HB_SCRIPT_MARCHEN, HB_SCRIPT_OSAGE, HB_SCRIPT_MARCHEN, HB_SCRIPT_OSAGE,
HB_SCRIPT_TANGUT, HB_SCRIPT_NEWA, HB_SCRIPT_TANGUT, HB_SCRIPT_NEWA,
}; };
static const hb_codepoint_t static const uint16_t
_hb_ucd_dm1_map[935] = _hb_ucd_dm1_u16_map[825] =
{ {
0x003Bu, 0x004Bu, 0x0060u, 0x00B4u, 0x00B7u, 0x00C5u, 0x02B9u, 0x0300u, 0x003Bu, 0x004Bu, 0x0060u, 0x00B4u, 0x00B7u, 0x00C5u, 0x02B9u, 0x0300u,
0x0301u, 0x0313u, 0x0385u, 0x0386u, 0x0388u, 0x0389u, 0x038Au, 0x038Cu, 0x0301u, 0x0313u, 0x0385u, 0x0386u, 0x0388u, 0x0389u, 0x038Au, 0x038Cu,
@ -192,20 +192,25 @@ _hb_ucd_dm1_map[935] =
0x9A6Au, 0x9B12u, 0x9B6Fu, 0x9C40u, 0x9C57u, 0x9CFDu, 0x9D67u, 0x9DB4u, 0x9A6Au, 0x9B12u, 0x9B6Fu, 0x9C40u, 0x9C57u, 0x9CFDu, 0x9D67u, 0x9DB4u,
0x9DFAu, 0x9E1Eu, 0x9E7Fu, 0x9E97u, 0x9E9Fu, 0x9EBBu, 0x9ECEu, 0x9EF9u, 0x9DFAu, 0x9E1Eu, 0x9E7Fu, 0x9E97u, 0x9E9Fu, 0x9EBBu, 0x9ECEu, 0x9EF9u,
0x9EFEu, 0x9F05u, 0x9F0Fu, 0x9F16u, 0x9F3Bu, 0x9F43u, 0x9F8Du, 0x9F8Eu, 0x9EFEu, 0x9F05u, 0x9F0Fu, 0x9F16u, 0x9F3Bu, 0x9F43u, 0x9F8Du, 0x9F8Eu,
0x9F9Cu,0x20122u,0x2051Cu,0x20525u,0x2054Bu,0x2063Au,0x20804u,0x208DEu, 0x9F9Cu,
0x20A2Cu,0x20B63u,0x214E4u,0x216A8u,0x216EAu,0x219C8u,0x21B18u,0x21D0Bu, };
0x21DE4u,0x21DE6u,0x22183u,0x2219Fu,0x22331u,0x226D4u,0x22844u,0x2284Au, static const uint32_t
0x22B0Cu,0x22BF1u,0x2300Au,0x232B8u,0x2335Fu,0x23393u,0x2339Cu,0x233C3u, _hb_ucd_dm1_u32_map[110] =
0x233D5u,0x2346Du,0x236A3u,0x238A7u,0x23A8Du,0x23AFAu,0x23CBCu,0x23D1Eu, {
0x23ED1u,0x23F5Eu,0x23F8Eu,0x24263u,0x242EEu,0x243ABu,0x24608u,0x24735u, 0x20122u,0x2051Cu,0x20525u,0x2054Bu,0x2063Au,0x20804u,0x208DEu,0x20A2Cu,
0x24814u,0x24C36u,0x24C92u,0x24FA1u,0x24FB8u,0x25044u,0x250F2u,0x250F3u, 0x20B63u,0x214E4u,0x216A8u,0x216EAu,0x219C8u,0x21B18u,0x21D0Bu,0x21DE4u,
0x25119u,0x25133u,0x25249u,0x2541Du,0x25626u,0x2569Au,0x256C5u,0x2597Cu, 0x21DE6u,0x22183u,0x2219Fu,0x22331u,0x226D4u,0x22844u,0x2284Au,0x22B0Cu,
0x25AA7u,0x25BABu,0x25C80u,0x25CD0u,0x25F86u,0x261DAu,0x26228u,0x26247u, 0x22BF1u,0x2300Au,0x232B8u,0x2335Fu,0x23393u,0x2339Cu,0x233C3u,0x233D5u,
0x262D9u,0x2633Eu,0x264DAu,0x26523u,0x265A8u,0x267A7u,0x267B5u,0x26B3Cu, 0x2346Du,0x236A3u,0x238A7u,0x23A8Du,0x23AFAu,0x23CBCu,0x23D1Eu,0x23ED1u,
0x26C36u,0x26CD5u,0x26D6Bu,0x26F2Cu,0x26FB1u,0x270D2u,0x273CAu,0x27667u, 0x23F5Eu,0x23F8Eu,0x24263u,0x242EEu,0x243ABu,0x24608u,0x24735u,0x24814u,
0x278AEu,0x27966u,0x27CA8u,0x27ED3u,0x27F2Fu,0x285D2u,0x285EDu,0x2872Eu, 0x24C36u,0x24C92u,0x24FA1u,0x24FB8u,0x25044u,0x250F2u,0x250F3u,0x25119u,
0x28BFAu,0x28D77u,0x29145u,0x291DFu,0x2921Au,0x2940Au,0x29496u,0x295B6u, 0x25133u,0x25249u,0x2541Du,0x25626u,0x2569Au,0x256C5u,0x2597Cu,0x25AA7u,
0x29B30u,0x2A0CEu,0x2A105u,0x2A20Eu,0x2A291u,0x2A392u,0x2A600u, 0x25BABu,0x25C80u,0x25CD0u,0x25F86u,0x261DAu,0x26228u,0x26247u,0x262D9u,
0x2633Eu,0x264DAu,0x26523u,0x265A8u,0x267A7u,0x267B5u,0x26B3Cu,0x26C36u,
0x26CD5u,0x26D6Bu,0x26F2Cu,0x26FB1u,0x270D2u,0x273CAu,0x27667u,0x278AEu,
0x27966u,0x27CA8u,0x27ED3u,0x27F2Fu,0x285D2u,0x285EDu,0x2872Eu,0x28BFAu,
0x28D77u,0x29145u,0x291DFu,0x2921Au,0x2940Au,0x29496u,0x295B6u,0x29B30u,
0x2A0CEu,0x2A105u,0x2A20Eu,0x2A291u,0x2A392u,0x2A600u,
}; };
static const uint64_t static const uint64_t
_hb_ucd_dm2_map[1025] = _hb_ucd_dm2_map[1025] =

View File

@ -148,13 +148,19 @@ hb_ucd_decompose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
if (likely (!i)) return false; if (likely (!i)) return false;
i--; i--;
if (i < ARRAY_LENGTH (_hb_ucd_dm1_map)) if (i < ARRAY_LENGTH (_hb_ucd_dm1_u16_map) + ARRAY_LENGTH (_hb_ucd_dm1_u32_map))
{ {
*a = _hb_ucd_dm1_map[i]; if (i < ARRAY_LENGTH (_hb_ucd_dm1_u16_map))
*a = _hb_ucd_dm1_u16_map[i];
else
{
i -= ARRAY_LENGTH (_hb_ucd_dm1_u16_map);
*a = _hb_ucd_dm1_u32_map[i];
}
*b = 0; *b = 0;
return true; return true;
} }
i -= ARRAY_LENGTH (_hb_ucd_dm1_map); i -= ARRAY_LENGTH (_hb_ucd_dm1_u16_map) + ARRAY_LENGTH (_hb_ucd_dm1_u32_map);
uint64_t v = _hb_ucd_dm2_map[i]; uint64_t v = _hb_ucd_dm2_map[i];
*a = HB_CODEPOINT_DECODE3_1 (v); *a = HB_CODEPOINT_DECODE3_1 (v);

View File

@ -31,6 +31,10 @@
#include <usp10.h> #include <usp10.h>
#include <rpc.h> #include <rpc.h>
#ifndef E_NOT_SUFFICIENT_BUFFER
#define E_NOT_SUFFICIENT_BUFFER HRESULT_FROM_WIN32 (ERROR_INSUFFICIENT_BUFFER)
#endif
#include "hb-uniscribe.h" #include "hb-uniscribe.h"
#include "hb-open-file.hh" #include "hb-open-file.hh"

View File

@ -66,7 +66,6 @@
#pragma GCC diagnostic error "-Wcast-align" #pragma GCC diagnostic error "-Wcast-align"
#pragma GCC diagnostic error "-Wcast-function-type" #pragma GCC diagnostic error "-Wcast-function-type"
#pragma GCC diagnostic error "-Wdelete-non-virtual-dtor" #pragma GCC diagnostic error "-Wdelete-non-virtual-dtor"
#pragma GCC diagnostic error "-Wdouble-promotion"
#pragma GCC diagnostic error "-Wextra-semi-stmt" #pragma GCC diagnostic error "-Wextra-semi-stmt"
#pragma GCC diagnostic error "-Wformat-security" #pragma GCC diagnostic error "-Wformat-security"
#pragma GCC diagnostic error "-Wimplicit-function-declaration" #pragma GCC diagnostic error "-Wimplicit-function-declaration"
@ -99,6 +98,7 @@
#pragma GCC diagnostic warning "-Wbuiltin-macro-redefined" #pragma GCC diagnostic warning "-Wbuiltin-macro-redefined"
#pragma GCC diagnostic warning "-Wdeprecated" #pragma GCC diagnostic warning "-Wdeprecated"
#pragma GCC diagnostic warning "-Wdisabled-optimization" #pragma GCC diagnostic warning "-Wdisabled-optimization"
#pragma GCC diagnostic warning "-Wdouble-promotion"
#pragma GCC diagnostic warning "-Wformat=2" #pragma GCC diagnostic warning "-Wformat=2"
#pragma GCC diagnostic warning "-Wignored-pragma-optimize" #pragma GCC diagnostic warning "-Wignored-pragma-optimize"
#pragma GCC diagnostic warning "-Wlogical-op" #pragma GCC diagnostic warning "-Wlogical-op"
@ -183,8 +183,15 @@
#include <stdarg.h> #include <stdarg.h>
#if (defined(_MSC_VER) && _MSC_VER >= 1500) || defined(__MINGW32__) #if (defined(_MSC_VER) && _MSC_VER >= 1500) || defined(__MINGW32__)
#ifdef __MINGW32_VERSION
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN 1
#endif
#include <windows.h>
#else
#include <intrin.h> #include <intrin.h>
#endif #endif
#endif
#define HB_PASTE1(a,b) a##b #define HB_PASTE1(a,b) a##b
#define HB_PASTE(a,b) HB_PASTE1(a,b) #define HB_PASTE(a,b) HB_PASTE1(a,b)
@ -352,7 +359,7 @@ extern "C" int hb_memalign_impl(void **memptr, size_t alignment, size_t size);
# define HB_NO_GETENV # define HB_NO_GETENV
# endif # endif
# if _WIN32_WCE < 0x800 # if _WIN32_WCE < 0x800
# define setlocale(Category, Locale) "C" # define HB_NO_SETLOCALE
static int errno = 0; /* Use something better? */ static int errno = 0; /* Use something better? */
# endif # endif
# elif defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP) # elif defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP)
@ -508,20 +515,6 @@ typedef uint64_t hb_vector_size_impl_t;
#define VAR 1 #define VAR 1
/* fallback for round() */
static inline double
_hb_round (double x)
{
if (x >= 0)
return floor (x + 0.5);
else
return ceil (x - 0.5);
}
#if !defined (HAVE_ROUND) && !defined (HAVE_DECL_ROUND)
#define round(x) _hb_round(x)
#endif
/* fallback for posix_memalign() */ /* fallback for posix_memalign() */
static inline int static inline int
_hb_memalign(void **memptr, size_t alignment, size_t size) _hb_memalign(void **memptr, size_t alignment, size_t size)

View File

@ -190,7 +190,6 @@ test_ot_tag_script_indic (void)
test_indic_tags ("ory3", "ory2", "orya", HB_SCRIPT_ORIYA); test_indic_tags ("ory3", "ory2", "orya", HB_SCRIPT_ORIYA);
test_indic_tags ("tml3", "tml2", "taml", HB_SCRIPT_TAMIL); test_indic_tags ("tml3", "tml2", "taml", HB_SCRIPT_TAMIL);
test_indic_tags ("tel3", "tel2", "telu", HB_SCRIPT_TELUGU); test_indic_tags ("tel3", "tel2", "telu", HB_SCRIPT_TELUGU);
test_indic_tags ("mym3", "mym2", "mymr", HB_SCRIPT_MYANMAR);
} }
@ -506,6 +505,7 @@ test_ot_tag_full (void)
test_tags (HB_SCRIPT_INVALID, "x-hbsc5678-hbot1234", HB_OT_MAX_TAGS_PER_SCRIPT, HB_OT_MAX_TAGS_PER_LANGUAGE, 1, 1, "5678", "1234"); test_tags (HB_SCRIPT_INVALID, "x-hbsc5678-hbot1234", HB_OT_MAX_TAGS_PER_SCRIPT, HB_OT_MAX_TAGS_PER_LANGUAGE, 1, 1, "5678", "1234");
test_tags (HB_SCRIPT_MALAYALAM, "ml", HB_OT_MAX_TAGS_PER_SCRIPT, HB_OT_MAX_TAGS_PER_LANGUAGE, 3, 2, "mlm3", "mlm2", "mlym", "MAL", "MLR"); test_tags (HB_SCRIPT_MALAYALAM, "ml", HB_OT_MAX_TAGS_PER_SCRIPT, HB_OT_MAX_TAGS_PER_LANGUAGE, 3, 2, "mlm3", "mlm2", "mlym", "MAL", "MLR");
test_tags (HB_SCRIPT_MALAYALAM, "ml", 1, 1, 1, 1, "mlm3", "MAL"); test_tags (HB_SCRIPT_MALAYALAM, "ml", 1, 1, 1, 1, "mlm3", "MAL");
test_tags (HB_SCRIPT_MYANMAR, "und", HB_OT_MAX_TAGS_PER_SCRIPT, 0, 2, 0, "mym2", "mymr");
test_tags (HB_SCRIPT_INVALID, "xyz", HB_OT_MAX_TAGS_PER_SCRIPT, HB_OT_MAX_TAGS_PER_LANGUAGE, 0, 1, "XYZ"); test_tags (HB_SCRIPT_INVALID, "xyz", HB_OT_MAX_TAGS_PER_SCRIPT, HB_OT_MAX_TAGS_PER_LANGUAGE, 0, 1, "XYZ");
test_tags (HB_SCRIPT_INVALID, "xy", HB_OT_MAX_TAGS_PER_SCRIPT, HB_OT_MAX_TAGS_PER_LANGUAGE, 0, 0); test_tags (HB_SCRIPT_INVALID, "xy", HB_OT_MAX_TAGS_PER_SCRIPT, HB_OT_MAX_TAGS_PER_LANGUAGE, 0, 0);
} }