Merge pull request #357 from khaledhosny/graphite-scale
[graphite] Fix shaping with varying font sizes
diff --git a/NEWS b/NEWS
index 8c3ef11..43a3bac 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,34 @@
+Overview of changes leading to 1.4.2
+Monday, January 23, 2017
+====================================
+
+- Implement OpenType Font Variation tables avar/fvar/HVAR/VVAR.
+- hb-shape and hb-view now accept --variations.
+- New API:
+
+hb_variation_t
+hb_variation_from_string()
+hb_variation_to_string()
+
+hb_font_set_variations()
+hb_font_set_var_coords_design()
+hb_font_get_var_coords_normalized()
+
+hb-ot-var.h:
+hb_ot_var_axis_t
+hb_ot_var_has_data()
+hb_ot_var_get_axis_count()
+hb_ot_var_get_axes()
+hb_ot_var_find_axis()
+hb_ot_var_normalize_variations()
+hb_ot_var_normalize_coords()
+
+- MVAR to be implemented later. Access to named instances to be
+ implemented later as well.
+
+- Misc fixes.
+
+
Overview of changes leading to 1.4.1
Thursday, January 5, 2017
====================================
diff --git a/configure.ac b/configure.ac
index 32dcf18..31fa97d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,6 +1,6 @@
AC_PREREQ([2.64])
AC_INIT([HarfBuzz],
- [1.4.1],
+ [1.4.2],
[https://github.com/behdad/harfbuzz/issues/new],
[harfbuzz],
[http://harfbuzz.org/])
diff --git a/docs/harfbuzz-docs.xml b/docs/harfbuzz-docs.xml
index 7a42d23..00113e9 100644
--- a/docs/harfbuzz-docs.xml
+++ b/docs/harfbuzz-docs.xml
@@ -180,7 +180,7 @@
<title>Index of new symbols in 1.2.3</title>
<xi:include href="xml/api-index-1.2.3.xml"><xi:fallback /></xi:include>
</index>
- <index id="api-index-1.3.3" role="1.3.3">
+ <index id="api-index-1-3-3" role="1.3.3">
<title>Index of new symbols in 1.3.3</title>
<xi:include href="xml/api-index-1.3.3.xml"><xi:fallback /></xi:include>
</index>
diff --git a/docs/harfbuzz-sections.txt b/docs/harfbuzz-sections.txt
index 270c87c..a91eb4c 100644
--- a/docs/harfbuzz-sections.txt
+++ b/docs/harfbuzz-sections.txt
@@ -245,6 +245,7 @@
hb_font_get_user_data
hb_font_get_variation_glyph
hb_font_get_variation_glyph_func_t
+hb_font_get_var_coords_normalized
hb_font_glyph_from_string
hb_font_glyph_to_string
hb_font_is_immutable
@@ -252,9 +253,16 @@
hb_font_reference
hb_font_set_funcs
hb_font_set_funcs_data
+hb_font_set_parent
hb_font_set_ppem
hb_font_set_scale
hb_font_set_user_data
+hb_variation_t
+hb_variation_from_string
+hb_variation_to_string
+hb_font_set_variations
+hb_font_set_var_coords_design
+hb_font_set_var_coords_normalized
hb_font_subtract_glyph_origin_for_direction
hb_font_t
hb_reference_table_func_t
@@ -266,7 +274,6 @@
hb_font_get_font_v_extents_func_t
hb_font_get_h_extents
hb_font_get_v_extents
-hb_font_set_parent
</SECTION>
<SECTION>
@@ -304,6 +311,9 @@
HB_GOBJECT_TYPE_FONT_FUNCS
HB_GOBJECT_TYPE_MEMORY_MODE
HB_GOBJECT_TYPE_OT_LAYOUT_GLYPH_CLASS
+HB_GOBJECT_TYPE_OT_MATH_CONSTANT
+HB_GOBJECT_TYPE_OT_MATH_GLYPH_PART_FLAGS
+HB_GOBJECT_TYPE_OT_MATH_KERN
HB_GOBJECT_TYPE_SCRIPT
HB_GOBJECT_TYPE_SHAPE_PLAN
HB_GOBJECT_TYPE_UNICODE_COMBINING_CLASS
@@ -328,6 +338,9 @@
hb_gobject_font_get_type
hb_gobject_memory_mode_get_type
hb_gobject_ot_layout_glyph_class_get_type
+hb_gobject_ot_math_constant_get_type
+hb_gobject_ot_math_glyph_part_flags_get_type
+hb_gobject_ot_math_kern_get_type
hb_gobject_script_get_type
hb_gobject_shape_plan_get_type
hb_gobject_unicode_combining_class_get_type
@@ -384,12 +397,14 @@
HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX
HB_OT_LAYOUT_NO_FEATURE_INDEX
HB_OT_LAYOUT_NO_SCRIPT_INDEX
+HB_OT_LAYOUT_NO_VARIATIONS_INDEX
HB_OT_TAG_GDEF
HB_OT_TAG_GPOS
HB_OT_TAG_GSUB
HB_OT_TAG_JSTF
hb_ot_layout_collect_lookups
hb_ot_layout_feature_get_lookups
+hb_ot_layout_feature_with_variations_get_lookups
hb_ot_layout_get_attach_points
hb_ot_layout_get_glyph_class
hb_ot_layout_get_glyphs_in_class
@@ -410,6 +425,7 @@
hb_ot_layout_script_find_language
hb_ot_layout_script_get_language_tags
hb_ot_layout_table_choose_script
+hb_ot_layout_table_find_feature_variations
hb_ot_layout_table_find_script
hb_ot_layout_table_get_feature_tags
hb_ot_layout_table_get_script_tags
@@ -423,6 +439,23 @@
</SECTION>
<SECTION>
+<FILE>hb-ot-var</FILE>
+HB_OT_TAG_VAR_AXIS_ITALIC
+HB_OT_TAG_VAR_AXIS_OPTICAL_SIZE
+HB_OT_TAG_VAR_AXIS_SLANT
+HB_OT_TAG_VAR_AXIS_WEIGHT
+HB_OT_TAG_VAR_AXIS_WIDTH
+HB_OT_VAR_NO_AXIS_INDEX
+hb_ot_var_axis_t
+hb_ot_var_has_data
+hb_ot_var_find_axis
+hb_ot_var_get_axis_count
+hb_ot_var_get_axes
+hb_ot_var_normalize_variations
+hb_ot_var_normalize_coords
+</SECTION>
+
+<SECTION>
<FILE>hb-ot-math</FILE>
HB_OT_TAG_MATH
HB_OT_MATH_SCRIPT
@@ -486,8 +519,8 @@
<SECTION>
<FILE>hb-shape</FILE>
-hb_feature_from_string
hb_feature_t
+hb_feature_from_string
hb_feature_to_string
hb_shape
hb_shape_full
@@ -498,6 +531,8 @@
<FILE>hb-shape-plan</FILE>
hb_shape_plan_create
hb_shape_plan_create_cached
+hb_shape_plan_create2
+hb_shape_plan_create_cached2
hb_shape_plan_destroy
hb_shape_plan_execute
hb_shape_plan_get_empty
@@ -552,6 +587,8 @@
<FILE>hb-uniscribe</FILE>
hb_uniscribe_font_get_hfont
hb_uniscribe_font_get_logfontw
+<SUBSECTION Private>
+hb_directwrite_shape_experimental_width
</SECTION>
<SECTION>
diff --git a/m4/ax_pthread.m4 b/m4/ax_pthread.m4
index d90de34..4c4051e 100644
--- a/m4/ax_pthread.m4
+++ b/m4/ax_pthread.m4
@@ -19,10 +19,10 @@
# is necessary on AIX to use the special cc_r compiler alias.)
#
# NOTE: You are assumed to not only compile your program with these flags,
-# but also link it with them as well. e.g. you should link with
+# but also to link with them as well. For example, you might link with
# $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS
#
-# If you are only building threads programs, you may wish to use these
+# If you are only building threaded programs, you may wish to use these
# variables in your default LIBS, CFLAGS, and CC:
#
# LIBS="$PTHREAD_LIBS $LIBS"
@@ -30,8 +30,8 @@
# CC="$PTHREAD_CC"
#
# In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant
-# has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to that name
-# (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
+# has a nonstandard name, this macro defines PTHREAD_CREATE_JOINABLE to
+# that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
#
# Also HAVE_PTHREAD_PRIO_INHERIT is defined if pthread is found and the
# PTHREAD_PRIO_INHERIT symbol is defined when compiling with
@@ -82,35 +82,40 @@
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
-#serial 18
+#serial 23
AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD])
AC_DEFUN([AX_PTHREAD], [
AC_REQUIRE([AC_CANONICAL_HOST])
+AC_REQUIRE([AC_PROG_CC])
+AC_REQUIRE([AC_PROG_SED])
AC_LANG_PUSH([C])
ax_pthread_ok=no
# We used to check for pthread.h first, but this fails if pthread.h
-# requires special compiler flags (e.g. on True64 or Sequent).
+# requires special compiler flags (e.g. on Tru64 or Sequent).
# It gets checked for in the link test anyway.
# First of all, check if the user has set any of the PTHREAD_LIBS,
# etcetera environment variables, and if threads linking works using
# them:
-if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then
- save_CFLAGS="$CFLAGS"
+if test "x$PTHREAD_CFLAGS$PTHREAD_LIBS" != "x"; then
+ ax_pthread_save_CC="$CC"
+ ax_pthread_save_CFLAGS="$CFLAGS"
+ ax_pthread_save_LIBS="$LIBS"
+ AS_IF([test "x$PTHREAD_CC" != "x"], [CC="$PTHREAD_CC"])
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
- save_LIBS="$LIBS"
LIBS="$PTHREAD_LIBS $LIBS"
- AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS])
- AC_TRY_LINK_FUNC(pthread_join, ax_pthread_ok=yes)
- AC_MSG_RESULT($ax_pthread_ok)
- if test x"$ax_pthread_ok" = xno; then
+ AC_MSG_CHECKING([for pthread_join using $CC $PTHREAD_CFLAGS $PTHREAD_LIBS])
+ AC_LINK_IFELSE([AC_LANG_CALL([], [pthread_join])], [ax_pthread_ok=yes])
+ AC_MSG_RESULT([$ax_pthread_ok])
+ if test "x$ax_pthread_ok" = "xno"; then
PTHREAD_LIBS=""
PTHREAD_CFLAGS=""
fi
- LIBS="$save_LIBS"
- CFLAGS="$save_CFLAGS"
+ CC="$ax_pthread_save_CC"
+ CFLAGS="$ax_pthread_save_CFLAGS"
+ LIBS="$ax_pthread_save_LIBS"
fi
# We must check for the threads library under a number of different
@@ -123,7 +128,7 @@
# which indicates that we try without any flags at all, and "pthread-config"
# which is a program returning the flags for the Pth emulation library.
-ax_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
+ax_pthread_flags="pthreads none -Kthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
# The ordering *is* (sometimes) important. Some notes on the
# individual items follow:
@@ -132,68 +137,225 @@
# none: in case threads are in libc; should be tried before -Kthread and
# other compiler flags to prevent continual compiler warnings
# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
-# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
-# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
-# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads)
-# -pthreads: Solaris/gcc
-# -mthreads: Mingw32/gcc, Lynx/gcc
+# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads), Tru64
+# (Note: HP C rejects this with "bad form for `-t' option")
+# -pthreads: Solaris/gcc (Note: HP C also rejects)
# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
-# doesn't hurt to check since this sometimes defines pthreads too;
-# also defines -D_REENTRANT)
-# ... -mt is also the pthreads flag for HP/aCC
+# doesn't hurt to check since this sometimes defines pthreads and
+# -D_REENTRANT too), HP C (must be checked before -lpthread, which
+# is present but should not be used directly; and before -mthreads,
+# because the compiler interprets this as "-mt" + "-hreads")
+# -mthreads: Mingw32/gcc, Lynx/gcc
# pthread: Linux, etcetera
# --thread-safe: KAI C++
# pthread-config: use pthread-config program (for GNU Pth library)
-case ${host_os} in
+case $host_os in
+
+ freebsd*)
+
+ # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
+ # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
+
+ ax_pthread_flags="-kthread lthread $ax_pthread_flags"
+ ;;
+
+ hpux*)
+
+ # From the cc(1) man page: "[-mt] Sets various -D flags to enable
+ # multi-threading and also sets -lpthread."
+
+ ax_pthread_flags="-mt -pthread pthread $ax_pthread_flags"
+ ;;
+
+ openedition*)
+
+ # IBM z/OS requires a feature-test macro to be defined in order to
+ # enable POSIX threads at all, so give the user a hint if this is
+ # not set. (We don't define these ourselves, as they can affect
+ # other portions of the system API in unpredictable ways.)
+
+ AC_EGREP_CPP([AX_PTHREAD_ZOS_MISSING],
+ [
+# if !defined(_OPEN_THREADS) && !defined(_UNIX03_THREADS)
+ AX_PTHREAD_ZOS_MISSING
+# endif
+ ],
+ [AC_MSG_WARN([IBM z/OS requires -D_OPEN_THREADS or -D_UNIX03_THREADS to enable pthreads support.])])
+ ;;
+
solaris*)
# On Solaris (at least, for some versions), libc contains stubbed
# (non-functional) versions of the pthreads routines, so link-based
- # tests will erroneously succeed. (We need to link with -pthreads/-mt/
- # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather
- # a function called by this macro, so we could check for that, but
- # who knows whether they'll stub that too in a future libc.) So,
- # we'll just look for -pthreads and -lpthread first:
+ # tests will erroneously succeed. (N.B.: The stubs are missing
+ # pthread_cleanup_push, or rather a function called by this macro,
+ # so we could check for that, but who knows whether they'll stub
+ # that too in a future libc.) So we'll check first for the
+ # standard Solaris way of linking pthreads (-mt -lpthread).
- ax_pthread_flags="-pthreads pthread -mt -pthread $ax_pthread_flags"
- ;;
-
- darwin*)
- ax_pthread_flags="-pthread $ax_pthread_flags"
+ ax_pthread_flags="-mt,pthread pthread $ax_pthread_flags"
;;
esac
-if test x"$ax_pthread_ok" = xno; then
-for flag in $ax_pthread_flags; do
+# GCC generally uses -pthread, or -pthreads on some platforms (e.g. SPARC)
- case $flag in
+AS_IF([test "x$GCC" = "xyes"],
+ [ax_pthread_flags="-pthread -pthreads $ax_pthread_flags"])
+
+# The presence of a feature test macro requesting re-entrant function
+# definitions is, on some systems, a strong hint that pthreads support is
+# correctly enabled
+
+case $host_os in
+ darwin* | hpux* | linux* | osf* | solaris*)
+ ax_pthread_check_macro="_REENTRANT"
+ ;;
+
+ aix*)
+ ax_pthread_check_macro="_THREAD_SAFE"
+ ;;
+
+ *)
+ ax_pthread_check_macro="--"
+ ;;
+esac
+AS_IF([test "x$ax_pthread_check_macro" = "x--"],
+ [ax_pthread_check_cond=0],
+ [ax_pthread_check_cond="!defined($ax_pthread_check_macro)"])
+
+# Are we compiling with Clang?
+
+AC_CACHE_CHECK([whether $CC is Clang],
+ [ax_cv_PTHREAD_CLANG],
+ [ax_cv_PTHREAD_CLANG=no
+ # Note that Autoconf sets GCC=yes for Clang as well as GCC
+ if test "x$GCC" = "xyes"; then
+ AC_EGREP_CPP([AX_PTHREAD_CC_IS_CLANG],
+ [/* Note: Clang 2.7 lacks __clang_[a-z]+__ */
+# if defined(__clang__) && defined(__llvm__)
+ AX_PTHREAD_CC_IS_CLANG
+# endif
+ ],
+ [ax_cv_PTHREAD_CLANG=yes])
+ fi
+ ])
+ax_pthread_clang="$ax_cv_PTHREAD_CLANG"
+
+ax_pthread_clang_warning=no
+
+# Clang needs special handling, because older versions handle the -pthread
+# option in a rather... idiosyncratic way
+
+if test "x$ax_pthread_clang" = "xyes"; then
+
+ # Clang takes -pthread; it has never supported any other flag
+
+ # (Note 1: This will need to be revisited if a system that Clang
+ # supports has POSIX threads in a separate library. This tends not
+ # to be the way of modern systems, but it's conceivable.)
+
+ # (Note 2: On some systems, notably Darwin, -pthread is not needed
+ # to get POSIX threads support; the API is always present and
+ # active. We could reasonably leave PTHREAD_CFLAGS empty. But
+ # -pthread does define _REENTRANT, and while the Darwin headers
+ # ignore this macro, third-party headers might not.)
+
+ PTHREAD_CFLAGS="-pthread"
+ PTHREAD_LIBS=
+
+ ax_pthread_ok=yes
+
+ # However, older versions of Clang make a point of warning the user
+ # that, in an invocation where only linking and no compilation is
+ # taking place, the -pthread option has no effect ("argument unused
+ # during compilation"). They expect -pthread to be passed in only
+ # when source code is being compiled.
+ #
+ # Problem is, this is at odds with the way Automake and most other
+ # C build frameworks function, which is that the same flags used in
+ # compilation (CFLAGS) are also used in linking. Many systems
+ # supported by AX_PTHREAD require exactly this for POSIX threads
+ # support, and in fact it is often not straightforward to specify a
+ # flag that is used only in the compilation phase and not in
+ # linking. Such a scenario is extremely rare in practice.
+ #
+ # Even though use of the -pthread flag in linking would only print
+ # a warning, this can be a nuisance for well-run software projects
+ # that build with -Werror. So if the active version of Clang has
+ # this misfeature, we search for an option to squash it.
+
+ AC_CACHE_CHECK([whether Clang needs flag to prevent "argument unused" warning when linking with -pthread],
+ [ax_cv_PTHREAD_CLANG_NO_WARN_FLAG],
+ [ax_cv_PTHREAD_CLANG_NO_WARN_FLAG=unknown
+ # Create an alternate version of $ac_link that compiles and
+ # links in two steps (.c -> .o, .o -> exe) instead of one
+ # (.c -> exe), because the warning occurs only in the second
+ # step
+ ax_pthread_save_ac_link="$ac_link"
+ ax_pthread_sed='s/conftest\.\$ac_ext/conftest.$ac_objext/g'
+ ax_pthread_link_step=`$as_echo "$ac_link" | sed "$ax_pthread_sed"`
+ ax_pthread_2step_ac_link="($ac_compile) && (echo ==== >&5) && ($ax_pthread_link_step)"
+ ax_pthread_save_CFLAGS="$CFLAGS"
+ for ax_pthread_try in '' -Qunused-arguments -Wno-unused-command-line-argument unknown; do
+ AS_IF([test "x$ax_pthread_try" = "xunknown"], [break])
+ CFLAGS="-Werror -Wunknown-warning-option $ax_pthread_try -pthread $ax_pthread_save_CFLAGS"
+ ac_link="$ax_pthread_save_ac_link"
+ AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])],
+ [ac_link="$ax_pthread_2step_ac_link"
+ AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])],
+ [break])
+ ])
+ done
+ ac_link="$ax_pthread_save_ac_link"
+ CFLAGS="$ax_pthread_save_CFLAGS"
+ AS_IF([test "x$ax_pthread_try" = "x"], [ax_pthread_try=no])
+ ax_cv_PTHREAD_CLANG_NO_WARN_FLAG="$ax_pthread_try"
+ ])
+
+ case "$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" in
+ no | unknown) ;;
+ *) PTHREAD_CFLAGS="$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG $PTHREAD_CFLAGS" ;;
+ esac
+
+fi # $ax_pthread_clang = yes
+
+if test "x$ax_pthread_ok" = "xno"; then
+for ax_pthread_try_flag in $ax_pthread_flags; do
+
+ case $ax_pthread_try_flag in
none)
AC_MSG_CHECKING([whether pthreads work without any flags])
;;
+ -mt,pthread)
+ AC_MSG_CHECKING([whether pthreads work with -mt -lpthread])
+ PTHREAD_CFLAGS="-mt"
+ PTHREAD_LIBS="-lpthread"
+ ;;
+
-*)
- AC_MSG_CHECKING([whether pthreads work with $flag])
- PTHREAD_CFLAGS="$flag"
+ AC_MSG_CHECKING([whether pthreads work with $ax_pthread_try_flag])
+ PTHREAD_CFLAGS="$ax_pthread_try_flag"
;;
pthread-config)
- AC_CHECK_PROG(ax_pthread_config, pthread-config, yes, no)
- if test x"$ax_pthread_config" = xno; then continue; fi
+ AC_CHECK_PROG([ax_pthread_config], [pthread-config], [yes], [no])
+ AS_IF([test "x$ax_pthread_config" = "xno"], [continue])
PTHREAD_CFLAGS="`pthread-config --cflags`"
PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
;;
*)
- AC_MSG_CHECKING([for the pthreads library -l$flag])
- PTHREAD_LIBS="-l$flag"
+ AC_MSG_CHECKING([for the pthreads library -l$ax_pthread_try_flag])
+ PTHREAD_LIBS="-l$ax_pthread_try_flag"
;;
esac
- save_LIBS="$LIBS"
- save_CFLAGS="$CFLAGS"
- LIBS="$PTHREAD_LIBS $LIBS"
+ ax_pthread_save_CFLAGS="$CFLAGS"
+ ax_pthread_save_LIBS="$LIBS"
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+ LIBS="$PTHREAD_LIBS $LIBS"
# Check for various functions. We must include pthread.h,
# since some functions may be macros. (On the Sequent, we
@@ -204,7 +366,11 @@
# pthread_cleanup_push because it is one of the few pthread
# functions on Solaris that doesn't have a non-functional libc stub.
# We try pthread_create on general principles.
+
AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>
+# if $ax_pthread_check_cond
+# error "$ax_pthread_check_macro must be defined"
+# endif
static void routine(void *a) { a = 0; }
static void *start_routine(void *a) { return a; }],
[pthread_t th; pthread_attr_t attr;
@@ -213,16 +379,14 @@
pthread_attr_init(&attr);
pthread_cleanup_push(routine, 0);
pthread_cleanup_pop(0) /* ; */])],
- [ax_pthread_ok=yes],
- [])
+ [ax_pthread_ok=yes],
+ [])
- LIBS="$save_LIBS"
- CFLAGS="$save_CFLAGS"
+ CFLAGS="$ax_pthread_save_CFLAGS"
+ LIBS="$ax_pthread_save_LIBS"
- AC_MSG_RESULT($ax_pthread_ok)
- if test "x$ax_pthread_ok" = xyes; then
- break;
- fi
+ AC_MSG_RESULT([$ax_pthread_ok])
+ AS_IF([test "x$ax_pthread_ok" = "xyes"], [break])
PTHREAD_LIBS=""
PTHREAD_CFLAGS=""
@@ -230,76 +394,88 @@
fi
# Various other checks:
-if test "x$ax_pthread_ok" = xyes; then
- save_LIBS="$LIBS"
- LIBS="$PTHREAD_LIBS $LIBS"
- save_CFLAGS="$CFLAGS"
+if test "x$ax_pthread_ok" = "xyes"; then
+ ax_pthread_save_CFLAGS="$CFLAGS"
+ ax_pthread_save_LIBS="$LIBS"
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+ LIBS="$PTHREAD_LIBS $LIBS"
# Detect AIX lossage: JOINABLE attribute is called UNDETACHED.
- AC_MSG_CHECKING([for joinable pthread attribute])
- attr_name=unknown
- for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
- AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>],
- [int attr = $attr; return attr /* ; */])],
- [attr_name=$attr; break],
- [])
- done
- AC_MSG_RESULT($attr_name)
- if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then
- AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name,
- [Define to necessary symbol if this constant
- uses a non-standard name on your system.])
- fi
+ AC_CACHE_CHECK([for joinable pthread attribute],
+ [ax_cv_PTHREAD_JOINABLE_ATTR],
+ [ax_cv_PTHREAD_JOINABLE_ATTR=unknown
+ for ax_pthread_attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>],
+ [int attr = $ax_pthread_attr; return attr /* ; */])],
+ [ax_cv_PTHREAD_JOINABLE_ATTR=$ax_pthread_attr; break],
+ [])
+ done
+ ])
+ AS_IF([test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xunknown" && \
+ test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xPTHREAD_CREATE_JOINABLE" && \
+ test "x$ax_pthread_joinable_attr_defined" != "xyes"],
+ [AC_DEFINE_UNQUOTED([PTHREAD_CREATE_JOINABLE],
+ [$ax_cv_PTHREAD_JOINABLE_ATTR],
+ [Define to necessary symbol if this constant
+ uses a non-standard name on your system.])
+ ax_pthread_joinable_attr_defined=yes
+ ])
- AC_MSG_CHECKING([if more special flags are required for pthreads])
- flag=no
- case ${host_os} in
- aix* | freebsd* | darwin*) flag="-D_THREAD_SAFE";;
- osf* | hpux*) flag="-D_REENTRANT";;
- solaris*)
- if test "$GCC" = "yes"; then
- flag="-D_REENTRANT"
- else
- flag="-mt -D_REENTRANT"
- fi
- ;;
- esac
- AC_MSG_RESULT(${flag})
- if test "x$flag" != xno; then
- PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS"
- fi
+ AC_CACHE_CHECK([whether more special flags are required for pthreads],
+ [ax_cv_PTHREAD_SPECIAL_FLAGS],
+ [ax_cv_PTHREAD_SPECIAL_FLAGS=no
+ case $host_os in
+ solaris*)
+ ax_cv_PTHREAD_SPECIAL_FLAGS="-D_POSIX_PTHREAD_SEMANTICS"
+ ;;
+ esac
+ ])
+ AS_IF([test "x$ax_cv_PTHREAD_SPECIAL_FLAGS" != "xno" && \
+ test "x$ax_pthread_special_flags_added" != "xyes"],
+ [PTHREAD_CFLAGS="$ax_cv_PTHREAD_SPECIAL_FLAGS $PTHREAD_CFLAGS"
+ ax_pthread_special_flags_added=yes])
AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT],
- ax_cv_PTHREAD_PRIO_INHERIT, [
- AC_LINK_IFELSE([
- AC_LANG_PROGRAM([[#include <pthread.h>]], [[int i = PTHREAD_PRIO_INHERIT;]])],
- [ax_cv_PTHREAD_PRIO_INHERIT=yes],
- [ax_cv_PTHREAD_PRIO_INHERIT=no])
+ [ax_cv_PTHREAD_PRIO_INHERIT],
+ [AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <pthread.h>]],
+ [[int i = PTHREAD_PRIO_INHERIT;]])],
+ [ax_cv_PTHREAD_PRIO_INHERIT=yes],
+ [ax_cv_PTHREAD_PRIO_INHERIT=no])
])
- AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes"],
- AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], 1, [Have PTHREAD_PRIO_INHERIT.]))
+ AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes" && \
+ test "x$ax_pthread_prio_inherit_defined" != "xyes"],
+ [AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], [1], [Have PTHREAD_PRIO_INHERIT.])
+ ax_pthread_prio_inherit_defined=yes
+ ])
- LIBS="$save_LIBS"
- CFLAGS="$save_CFLAGS"
+ CFLAGS="$ax_pthread_save_CFLAGS"
+ LIBS="$ax_pthread_save_LIBS"
- # More AIX lossage: must compile with xlc_r or cc_r
- if test x"$GCC" != xyes; then
- AC_CHECK_PROGS(PTHREAD_CC, xlc_r cc_r, ${CC})
- else
- PTHREAD_CC=$CC
+ # More AIX lossage: compile with *_r variant
+ if test "x$GCC" != "xyes"; then
+ case $host_os in
+ aix*)
+ AS_CASE(["x/$CC"],
+ [x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6],
+ [#handle absolute path differently from PATH based program lookup
+ AS_CASE(["x$CC"],
+ [x/*],
+ [AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"])],
+ [AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC])])])
+ ;;
+ esac
fi
-else
- PTHREAD_CC="$CC"
fi
-AC_SUBST(PTHREAD_LIBS)
-AC_SUBST(PTHREAD_CFLAGS)
-AC_SUBST(PTHREAD_CC)
+test -n "$PTHREAD_CC" || PTHREAD_CC="$CC"
+
+AC_SUBST([PTHREAD_LIBS])
+AC_SUBST([PTHREAD_CFLAGS])
+AC_SUBST([PTHREAD_CC])
# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
-if test x"$ax_pthread_ok" = xyes; then
- ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1])
+if test "x$ax_pthread_ok" = "xyes"; then
+ ifelse([$1],,[AC_DEFINE([HAVE_PTHREAD],[1],[Define if you have POSIX threads libraries and header files.])],[$1])
:
else
ax_pthread_ok=no
diff --git a/src/Makefile.am b/src/Makefile.am
index 8cfe4ac..e322d56 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -218,7 +218,7 @@
(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 "$@" \
@@ -299,6 +299,8 @@
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 \
diff --git a/src/Makefile.sources b/src/Makefile.sources
index e727598..6363cf9 100644
--- a/src/Makefile.sources
+++ b/src/Makefile.sources
@@ -76,11 +76,11 @@
hb-ot-layout-gsubgpos-private.hh \
hb-ot-layout-gsub-table.hh \
hb-ot-layout-jstf-table.hh \
- hb-ot-layout-math-table.hh \
hb-ot-layout-private.hh \
hb-ot-map.cc \
hb-ot-map-private.hh \
hb-ot-math.cc \
+ hb-ot-math-table.hh \
hb-ot-shape.cc \
hb-ot-shape-complex-arabic.cc \
hb-ot-shape-complex-arabic-fallback.hh \
@@ -108,6 +108,11 @@
hb-ot-shape-fallback-private.hh \
hb-ot-shape-fallback.cc \
hb-ot-shape-private.hh \
+ hb-ot-var.cc \
+ hb-ot-var-avar-table.hh \
+ hb-ot-var-fvar-table.hh \
+ hb-ot-var-hvar-table.hh \
+ hb-ot-var-mvar-table.hh \
$(NULL)
HB_OT_headers = \
@@ -117,6 +122,7 @@
hb-ot-math.h \
hb-ot-shape.h \
hb-ot-tag.h \
+ hb-ot-var.h \
$(NULL)
# Optional Sources and Headers with external deps
diff --git a/src/hb-common.cc b/src/hb-common.cc
index 3564e43..64e77d4 100644
--- a/src/hb-common.cc
+++ b/src/hb-common.cc
@@ -605,3 +605,347 @@
{
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_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 = strtof (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, 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;
+}
+
+/* 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_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_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';
+}
diff --git a/src/hb-common.h b/src/hb-common.h
index 2cbee76..634cb96 100644
--- a/src/hb-common.h
+++ b/src/hb-common.h
@@ -362,6 +362,42 @@
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 */
diff --git a/src/hb-coretext.cc b/src/hb-coretext.cc
index e857dfa..86de0be 100644
--- a/src/hb-coretext.cc
+++ b/src/hb-coretext.cc
@@ -69,8 +69,8 @@
}
-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)
/*
diff --git a/src/hb-directwrite.cc b/src/hb-directwrite.cc
index b5c1113..ab07d8a 100644
--- a/src/hb-directwrite.cc
+++ b/src/hb-directwrite.cc
@@ -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 @@
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 @@
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);
@@ -915,7 +915,7 @@
*/
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,
diff --git a/src/hb-directwrite.h b/src/hb-directwrite.h
index 0eb116f..e743af2 100644
--- a/src/hb-directwrite.h
+++ b/src/hb-directwrite.h
@@ -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
diff --git a/src/hb-face-private.hh b/src/hb-face-private.hh
index c4266ff..eb0e850 100644
--- a/src/hb-face-private.hh
+++ b/src/hb-face-private.hh
@@ -50,12 +50,23 @@
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 {
+ NOTHING = 0x0000,
+ INDEX = 0x0001,
+ UPEM = 0x0002,
+ 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 @@
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
diff --git a/src/hb-face.cc b/src/hb-face.cc
index 6b563bc..1800c99 100644
--- a/src/hb-face.cc
+++ b/src/hb-face.cc
@@ -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 @@
1000, /* upem */
0, /* num_glyphs */
+ hb_face_t::NOTHING, /* dirty */
+
{
#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INVALID,
#include "hb-shaper-list.hh"
@@ -175,7 +173,7 @@
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 @@
if (face->immutable)
return;
+ if (face->index == index)
+ return;
+
+ face->dirty |= face->INDEX;
+
face->index = index;
}
@@ -404,6 +407,11 @@
if (face->immutable)
return;
+ if (face->upem == upem)
+ return;
+
+ face->dirty |= face->UPEM;
+
face->upem = upem;
}
@@ -448,6 +456,11 @@
if (face->immutable)
return;
+ if (face->num_glyphs == glyph_count)
+ return;
+
+ face->dirty |= face->NUM_GLYPHS;
+
face->num_glyphs = glyph_count;
}
diff --git a/src/hb-fallback-shape.cc b/src/hb-fallback-shape.cc
index ac6d4b0..4b60c6c 100644
--- a/src/hb-fallback-shape.cc
+++ b/src/hb-fallback-shape.cc
@@ -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 @@
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,
diff --git a/src/hb-font-private.hh b/src/hb-font-private.hh
index 53671d7..fbb16a0 100644
--- a/src/hb-font-private.hh
+++ b/src/hb-font-private.hh
@@ -116,6 +116,16 @@
void *user_data;
hb_destroy_func_t destroy;
+ enum dirty_t {
+ NOTHING = 0x0000,
+ FACE = 0x0001,
+ PARENT = 0x0002,
+ FUNCS = 0x0004,
+ SCALE = 0x0008,
+ PPEM = 0x0010,
+ VARIATIONS = 0x0020,
+ } dirty;
+
struct hb_shaper_data_t shaper_data;
@@ -543,6 +553,8 @@
}
};
+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"
diff --git a/src/hb-font.cc b/src/hb-font.cc
index 2935c4b..e900bd3 100644
--- a/src/hb-font.cc
+++ b/src/hb-font.cc
@@ -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 @@
NULL, /* user_data */
NULL, /* destroy */
+ hb_font_t::NOTHING, /* dirty */
+
{
#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INVALID,
#include "hb-shaper-list.hh"
@@ -1355,6 +1350,11 @@
if (!parent)
parent = hb_font_get_empty ();
+ if (parent == font->parent)
+ return;
+
+ font->dirty |= font->PARENT;
+
hb_font_t *old = font->parent;
font->parent = hb_font_reference (parent);
@@ -1379,6 +1379,37 @@
}
/**
+ * 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->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 @@
if (!klass)
klass = hb_font_funcs_get_empty ();
+ font->dirty |= font->FUNCS;
+
hb_font_funcs_reference (klass);
hb_font_funcs_destroy (font->klass);
font->klass = klass;
@@ -1479,6 +1512,11 @@
if (font->immutable)
return;
+ if (font->x_scale == x_scale && font->y_scale == y_scale)
+ return;
+
+ font->dirty |= font->SCALE;
+
font->x_scale = x_scale;
font->y_scale = y_scale;
}
@@ -1520,6 +1558,11 @@
if (font->immutable)
return;
+ if (font->x_ppem == x_ppem && font->y_ppem == y_ppem)
+ return;
+
+ font->dirty |= font->PPEM;
+
font->x_ppem = x_ppem;
font->y_ppem = y_ppem;
}
@@ -1543,30 +1586,122 @@
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->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;
}
diff --git a/src/hb-font.h b/src/hb-font.h
index 8813286..85fb56d 100644
--- a/src/hb-font.h
+++ b/src/hb-font.h
@@ -563,6 +563,10 @@
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 @@
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 */
diff --git a/src/hb-ft.cc b/src/hb-ft.cc
index f127066..48d6a0e 100644
--- a/src/hb-ft.cc
+++ b/src/hb-ft.cc
@@ -621,17 +621,22 @@
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 @@
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;
diff --git a/src/hb-graphite2.cc b/src/hb-graphite2.cc
index f253a5f..5b804b8 100644
--- a/src/hb-graphite2.cc
+++ b/src/hb-graphite2.cc
@@ -34,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)
/*
diff --git a/src/hb-open-file-private.hh b/src/hb-open-file-private.hh
index 5357ddc..f208419 100644
--- a/src/hb-open-file-private.hh
+++ b/src/hb-open-file-private.hh
@@ -142,7 +142,7 @@
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:
diff --git a/src/hb-open-type-private.hh b/src/hb-open-type-private.hh
index 2cc1fb2..d90d68c 100644
--- a/src/hb-open-type-private.hh
+++ b/src/hb-open-type-private.hh
@@ -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 @@
}
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 @@
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 @@
};
+/* 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 */
diff --git a/src/hb-ot-cbdt-table.hh b/src/hb-ot-cbdt-table.hh
index 52897ab..0a7fbf5 100644
--- a/src/hb-ot-cbdt-table.hh
+++ b/src/hb-ot-cbdt-table.hh
@@ -216,7 +216,7 @@
USHORT firstGlyphIndex;
USHORT lastGlyphIndex;
- OffsetTo<IndexSubtable, ULONG> offsetToSubtable;
+ LOffsetTo<IndexSubtable> offsetToSubtable;
DEFINE_SIZE_STATIC(8);
};
@@ -275,7 +275,7 @@
}
protected:
- OffsetTo<IndexSubtableArray, ULONG> indexSubtableArrayOffset;
+ LOffsetTo<IndexSubtableArray> indexSubtableArrayOffset;
ULONG indexTablesSize;
ULONG numberOfIndexSubtables;
ULONG colorRef;
@@ -348,8 +348,8 @@
}
protected:
- FixedVersion<>version;
- ArrayOf<BitmapSizeTable, ULONG> sizeTables;
+ FixedVersion<> version;
+ LArrayOf<BitmapSizeTable> sizeTables;
public:
DEFINE_SIZE_ARRAY(8, sizeTables);
diff --git a/src/hb-ot-cmap-table.hh b/src/hb-ot-cmap-table.hh
index d7a94a1..3a53a1c 100644
--- a/src/hb-ot-cmap-table.hh
+++ b/src/hb-ot-cmap-table.hh
@@ -380,9 +380,9 @@
}
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 @@
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);
diff --git a/src/hb-ot-font.cc b/src/hb-ot-font.cc
index 5be055d..009db20 100644
--- a/src/hb-ot-font.cc
+++ b/src/hb-ot-font.cc
@@ -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 @@
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 @@
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 @@
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 @@
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, this->num_advances - 1)].advance
+ + this->var->get_advance_var (glyph, font->coords, font->num_coords); // TODO Optimize?!
}
};
@@ -421,55 +429,13 @@
}
};
-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 @@
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 @@
}
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 @@
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 @@
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 @@
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;
}
diff --git a/src/hb-ot-hmtx-table.hh b/src/hb-ot-hmtx-table.hh
index a9606b3..30aa625 100644
--- a/src/hb-ot-hmtx-table.hh
+++ b/src/hb-ot-hmtx-table.hh
@@ -50,10 +50,8 @@
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 @@
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;
};
diff --git a/src/hb-ot-layout-common-private.hh b/src/hb-ot-layout-common-private.hh
index 62ca7a3..180e5f0 100644
--- a/src/hb-ot-layout-common-private.hh
+++ b/src/hb-ot-layout-common-private.hh
@@ -1323,6 +1323,14 @@
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 @@
protected:
USHORT format;
- OffsetTo<VarRegionList, ULONG> regions;
+ LOffsetTo<VarRegionList> regions;
OffsetArrayOf<VarData, ULONG> dataSets;
public:
DEFINE_SIZE_ARRAY (8, dataSets);
@@ -1433,8 +1441,8 @@
}
protected:
- USHORT featureIndex;
- OffsetTo<Feature, ULONG> feature;
+ USHORT featureIndex;
+ LOffsetTo<Feature> feature;
public:
DEFINE_SIZE_STATIC (6);
};
@@ -1481,9 +1489,9 @@
}
protected:
- OffsetTo<ConditionSet, ULONG>
+ LOffsetTo<ConditionSet>
conditions;
- OffsetTo<FeatureTableSubstitution, ULONG>
+ LOffsetTo<FeatureTableSubstitution>
substitutions;
public:
DEFINE_SIZE_STATIC (8);
@@ -1527,7 +1535,7 @@
protected:
FixedVersion<> version; /* Version--0x00010000u */
- ArrayOf<FeatureVariationRecord, ULONG>
+ LArrayOf<FeatureVariationRecord>
varRecords;
public:
DEFINE_SIZE_ARRAY (8, varRecords);
diff --git a/src/hb-ot-layout-gdef-table.hh b/src/hb-ot-layout-gdef-table.hh
index b70cbb7..552df0f 100644
--- a/src/hb-ot-layout-gdef-table.hh
+++ b/src/hb-ot-layout-gdef-table.hh
@@ -295,7 +295,7 @@
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 @@
* 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
diff --git a/src/hb-ot-layout-gsubgpos-private.hh b/src/hb-ot-layout-gsubgpos-private.hh
index fd75c54..b7a0122 100644
--- a/src/hb-ot-layout-gsubgpos-private.hh
+++ b/src/hb-ot-layout-gsubgpos-private.hh
@@ -2313,7 +2313,7 @@
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
diff --git a/src/hb-ot-layout-private.hh b/src/hb-ot-layout-private.hh
index a4272de..071a439 100644
--- a/src/hb-ot-layout-private.hh
+++ b/src/hb-ot-layout-private.hh
@@ -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 @@
struct GSUB;
struct GPOS;
struct MATH;
+ struct fvar;
+ struct avar;
}
struct hb_ot_layout_lookup_accelerator_t
@@ -153,12 +156,15 @@
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;
@@ -617,5 +623,4 @@
#undef lig_props
#undef glyph_props
-
#endif /* HB_OT_LAYOUT_PRIVATE_HH */
diff --git a/src/hb-ot-layout.cc b/src/hb-ot-layout.cc
index 145ec76..a1682a5 100644
--- a/src/hb-ot-layout.cc
+++ b/src/hb-ot-layout.cc
@@ -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 @@
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);
{
/*
@@ -110,10 +105,16 @@
|| (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)
+ /* 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 */
+ || (1018 == gdef_len && 62834 == gpos_len && 24572 == gsub_len)
/* sha1sum:b0d36cf5a2fbe746a3dd277bffc6756a820807a7 Tahoma.ttf from Mac OS X 10.9 */
|| (832 == gdef_len && 47162 == gpos_len && 7324 == gsub_len)
/* sha1sum:12fc4538e84d461771b30c18b5eb6bd434e30fba Tahoma Bold.ttf from Mac OS X 10.9 */
|| (844 == gdef_len && 45474 == gpos_len && 7302 == gsub_len)
+ /* sha1sum:eb8afadd28e9cf963e886b23a30b44ab4fd83acc himalaya.ttf from Windows 7 */
+ || (180 == gdef_len && 7254 == gpos_len && 13054 == gsub_len)
/* sha1sum:73da7f025b238a3f737aa1fde22577a6370f77b0 himalaya.ttf from Windows 8 */
|| (192 == gdef_len && 7254 == gpos_len && 12638 == gsub_len)
/* sha1sum:6e80fd1c0b059bbee49272401583160dc1e6a427 himalaya.ttf from Windows 8.1 */
@@ -181,7 +182,10 @@
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);
}
diff --git a/src/hb-ot-layout-math-table.hh b/src/hb-ot-math-table.hh
similarity index 99%
rename from src/hb-ot-layout-math-table.hh
rename to src/hb-ot-math-table.hh
index b52b121..191d79e 100644
--- a/src/hb-ot-layout-math-table.hh
+++ b/src/hb-ot-math-table.hh
@@ -24,8 +24,8 @@
* Igalia Author(s): Frédéric Wang
*/
-#ifndef HB_OT_LAYOUT_MATH_TABLE_HH
-#define HB_OT_LAYOUT_MATH_TABLE_HH
+#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"
@@ -716,7 +716,7 @@
DEFINE_SIZE_STATIC (10);
};
-} /* mathspace OT */
+} /* namespace OT */
-#endif /* HB_OT_LAYOUT_MATH_TABLE_HH */
+#endif /* HB_OT_MATH_TABLE_HH */
diff --git a/src/hb-ot-math.cc b/src/hb-ot-math.cc
index 9ef21d2..f82a073 100644
--- a/src/hb-ot-math.cc
+++ b/src/hb-ot-math.cc
@@ -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 @@
* @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_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
**/
diff --git a/src/hb-ot-shape-complex-arabic.cc b/src/hb-ot-shape-complex-arabic.cc
index 56ec5cd..57ffc1d 100644
--- a/src/hb-ot-shape-complex-arabic.cc
+++ b/src/hb-ot-shape-complex-arabic.cc
@@ -540,7 +540,7 @@
/* 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;
diff --git a/src/hb-ot-shape-complex-hangul.cc b/src/hb-ot-shape-complex-hangul.cc
index eb95a28..af50565 100644
--- a/src/hb-ot-shape-complex-hangul.cc
+++ b/src/hb-ot-shape-complex-hangul.cc
@@ -32,7 +32,7 @@
/* Same order as the feature array below */
enum {
- NONE,
+ _JMO,
LJMO,
VJMO,
diff --git a/src/hb-ot-shape-complex-private.hh b/src/hb-ot-shape-complex-private.hh
index 39572df..952441b 100644
--- a/src/hb-ot-shape-complex-private.hh
+++ b/src/hb-ot-shape-complex-private.hh
@@ -191,6 +191,9 @@
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
diff --git a/src/hb-ot-shape-complex-use.cc b/src/hb-ot-shape-complex-use.cc
index 5b19d5d..af68706 100644
--- a/src/hb-ot-shape-complex-use.cc
+++ b/src/hb-ot-shape-complex-use.cc
@@ -572,28 +572,6 @@
*/
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);
diff --git a/src/hb-ot-shape-normalize.cc b/src/hb-ot-shape-normalize.cc
index 107617e..94a3d7d 100644
--- a/src/hb-ot-shape-normalize.cc
+++ b/src/hb-ot-shape-normalize.cc
@@ -91,7 +91,7 @@
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
diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc
index ddd6662..2eacb34 100644
--- a/src/hb-ot-shape.cc
+++ b/src/hb-ot-shape.cc
@@ -128,6 +128,8 @@
* 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 @@
* shaper font data
*/
+HB_SHAPER_DATA_ENSURE_DEFINE(ot, font)
+
struct hb_ot_shaper_font_data_t {};
hb_ot_shaper_font_data_t *
@@ -362,6 +366,18 @@
hb_buffer_t *buffer = c->buffer;
+ 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;
+ }
+
/* TODO look in pre/post context text also. */
unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
@@ -380,10 +396,10 @@
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;
}
diff --git a/src/hb-ot-tag.cc b/src/hb-ot-tag.cc
index 5f21ac0..9b0db50 100644
--- a/src/hb-ot-tag.cc
+++ b/src/hb-ot-tag.cc
@@ -28,9 +28,6 @@
#include "hb-private.hh"
-#include <string.h>
-
-
/* hb_script_t */
@@ -201,6 +198,7 @@
{"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 @@
{"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 @@
{"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 @@
{"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 @@
{"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 @@
{"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 @@
{"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 @@
{"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 @@
{"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 @@
{"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 @@
{"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 @@
{"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 @@
{"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 @@
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 @@
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 @@
}
}
- /* 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";
diff --git a/src/hb-ot-var-avar-table.hh b/src/hb-ot-var-avar-table.hh
new file mode 100644
index 0000000..ace0f5f
--- /dev/null
+++ b/src/hb-ot-var-avar-table.hh
@@ -0,0 +1,144 @@
+/*
+ * 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)
+ return value;
+
+ 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 */
diff --git a/src/hb-ot-var-fvar-table.hh b/src/hb-ot-var-fvar-table.hh
new file mode 100644
index 0000000..9f6fb32
--- /dev/null
+++ b/src/hb-ot-var-fvar-table.hh
@@ -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 */
diff --git a/src/hb-ot-var-hvar-table.hh b/src/hb-ot-var-hvar-table.hh
new file mode 100644
index 0000000..f9d801e
--- /dev/null
+++ b/src/hb-ot-var-hvar-table.hh
@@ -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 */
diff --git a/src/hb-ot-var-mvar-table.hh b/src/hb-ot-var-mvar-table.hh
new file mode 100644
index 0000000..3cb7498
--- /dev/null
+++ b/src/hb-ot-var-mvar-table.hh
@@ -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 */
diff --git a/src/hb-ot-var.cc b/src/hb-ot-var.cc
new file mode 100644
index 0000000..691196d
--- /dev/null
+++ b/src/hb-ot-var.cc
@@ -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);
+}
diff --git a/src/hb-ot-var.h b/src/hb-ot-var.h
new file mode 100644
index 0000000..a2c0c5f
--- /dev/null
+++ b/src/hb-ot-var.h
@@ -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 */
diff --git a/src/hb-ot.h b/src/hb-ot.h
index 113e37b..2120a3e 100644
--- a/src/hb-ot.h
+++ b/src/hb-ot.h
@@ -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
diff --git a/src/hb-set.cc b/src/hb-set.cc
index cb7fcdb..f3fe1ba 100644
--- a/src/hb-set.cc
+++ b/src/hb-set.cc
@@ -105,7 +105,7 @@
* @set: a set.
* @key:
* @data:
- * @destroy (closure data):
+ * @destroy:
* @replace:
*
* Return value:
diff --git a/src/hb-shape-plan.cc b/src/hb-shape-plan.cc
index 600faae..1ac77be 100644
--- a/src/hb-shape-plan.cc
+++ b/src/hb-shape-plan.cc
@@ -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,
diff --git a/src/hb-shape.cc b/src/hb-shape.cc
index 706f144..f080a15 100644
--- a/src/hb-shape.cc
+++ b/src/hb-shape.cc
@@ -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 @@
* 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
**/
diff --git a/src/hb-shape.h b/src/hb-shape.h
index 53bb845..39507ff 100644
--- a/src/hb-shape.h
+++ b/src/hb-shape.h
@@ -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,
diff --git a/src/hb-shaper-private.hh b/src/hb-shaper-private.hh
index d1d1146..381398a 100644
--- a/src/hb-shaper-private.hh
+++ b/src/hb-shaper-private.hh
@@ -65,27 +65,31 @@
#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)); \
diff --git a/src/hb-uniscribe.cc b/src/hb-uniscribe.cc
index 6e4db01..58f983d 100644
--- a/src/hb-uniscribe.cc
+++ b/src/hb-uniscribe.cc
@@ -293,8 +293,8 @@
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)
/*
diff --git a/test/api/test-font.c b/test/api/test-font.c
index 34f6c74..527dfcd 100644
--- a/test/api/test-font.c
+++ b/test/api/test-font.c
@@ -35,13 +35,23 @@
static void
test_face_empty (void)
{
+ hb_face_t *created_from_empty;
+ hb_face_t *created_from_null;
+
g_assert (hb_face_get_empty ());
- g_assert (hb_face_get_empty () != hb_face_create (hb_blob_get_empty (), 0));
- g_assert (hb_face_get_empty () != hb_face_create (NULL, 0));
+
+ created_from_empty = hb_face_create (hb_blob_get_empty (), 0);
+ g_assert (hb_face_get_empty () != created_from_empty);
+
+ created_from_null = hb_face_create (NULL, 0);
+ g_assert (hb_face_get_empty () != created_from_null);
g_assert (hb_face_reference_table (hb_face_get_empty (), HB_TAG ('h','e','a','d')) == hb_blob_get_empty ());
g_assert_cmpint (hb_face_get_upem (hb_face_get_empty ()), ==, 1000);
+
+ hb_face_destroy (created_from_null);
+ hb_face_destroy (created_from_empty);
}
static void
@@ -357,14 +367,29 @@
static void
test_font_empty (void)
{
+ hb_font_t *created_from_empty;
+ hb_font_t *created_from_null;
+ hb_font_t *created_sub_from_null;
+
g_assert (hb_font_get_empty ());
- g_assert (hb_font_get_empty () != hb_font_create (hb_face_get_empty ()));
- g_assert (hb_font_get_empty () != hb_font_create (NULL));
- g_assert (hb_font_get_empty () != hb_font_create_sub_font (NULL));
+
+ created_from_empty = hb_font_create (hb_face_get_empty ());
+ g_assert (hb_font_get_empty () != created_from_empty);
+
+ created_from_null = hb_font_create (NULL);
+ g_assert (hb_font_get_empty () != created_from_null);
+
+ created_sub_from_null = hb_font_create_sub_font (NULL);
+ g_assert (hb_font_get_empty () != created_sub_from_null);
+
g_assert (hb_font_is_immutable (hb_font_get_empty ()));
g_assert (hb_font_get_face (hb_font_get_empty ()) == hb_face_get_empty ());
g_assert (hb_font_get_parent (hb_font_get_empty ()) == NULL);
+
+ hb_font_destroy (created_sub_from_null);
+ hb_font_destroy (created_from_null);
+ hb_font_destroy (created_from_empty);
}
static void
diff --git a/test/api/test-ot-math.c b/test/api/test-ot-math.c
index 049656a..0ca5566 100644
--- a/test/api/test-ot-math.c
+++ b/test/api/test-ot-math.c
@@ -70,14 +70,18 @@
if ((ft_error = FT_Set_Char_Size (ft_face, 2000, 1000, 0, 0)))
abort();
hb_font = hb_ft_font_create (ft_face, NULL);
- hb_face = hb_ft_face_create_cached(ft_face);
+ hb_face = hb_face_reference (hb_font_get_face (hb_font));
}
static inline void
closeFont (void)
{
+ hb_face_destroy (hb_face);
hb_font_destroy (hb_font);
FT_Done_Face (ft_face);
+ hb_face = NULL;
+ hb_font = NULL;
+ ft_face = NULL;
}
static void
@@ -93,6 +97,14 @@
g_assert(hb_ot_math_has_data (hb_face)); // MATH table available
closeFont();
+ hb_face = hb_face_get_empty ();
+ hb_font = hb_font_create (hb_face);
+ g_assert(!hb_ot_math_has_data (hb_face)); // MATH table not available
+
+ hb_font = hb_font_get_empty ();
+ hb_face = hb_font_get_face (hb_font);
+ g_assert(!hb_ot_math_has_data (hb_face)); // MATH table not available
+
cleanupFreeType();
}
@@ -400,6 +412,11 @@
test_get_glyph_variants (void)
{
hb_codepoint_t glyph;
+ hb_ot_math_glyph_variant_t variants[20];
+ unsigned variantsSize = sizeof (variants) / sizeof (variants[0]);
+ unsigned int count;
+ unsigned int offset = 0;
+
initFreeType();
openFont("fonts/MathTestFontEmpty.otf");
@@ -463,10 +480,6 @@
NULL), ==, 0);
g_assert(hb_font_get_glyph_from_name (hb_font, "arrowleft", -1, &glyph));
- hb_ot_math_glyph_variant_t variants[20];
- unsigned variantsSize = sizeof (variants) / sizeof (variants[0]);
- unsigned int count;
- unsigned int offset = 0;
do {
count = variantsSize;
hb_ot_math_get_glyph_variants (hb_font,
@@ -523,6 +536,11 @@
test_get_glyph_assembly (void)
{
hb_codepoint_t glyph;
+ hb_ot_math_glyph_part_t parts[20];
+ unsigned partsSize = sizeof (parts) / sizeof (parts[0]);
+ unsigned int count;
+ unsigned int offset = 0;
+
initFreeType();
openFont("fonts/MathTestFontEmpty.otf");
@@ -590,10 +608,6 @@
NULL), ==, 0);
g_assert(hb_font_get_glyph_from_name (hb_font, "arrowright", -1, &glyph));
- hb_ot_math_glyph_part_t parts[20];
- unsigned partsSize = sizeof (parts) / sizeof (parts[0]);
- unsigned int count;
- unsigned int offset = 0;
do {
count = partsSize;
hb_ot_math_get_glyph_assembly (hb_font,
diff --git a/test/api/test-ot-tag.c b/test/api/test-ot-tag.c
index e54e552..f5cbd9d 100644
--- a/test/api/test-ot-tag.c
+++ b/test/api/test-ot-tag.c
@@ -188,11 +188,48 @@
test_language_two_way ("ENG", "en");
test_tag_from_language ("ENG", "en_US");
+ test_language_two_way ("CJA", "cja"); /* Western Cham */
+ test_language_two_way ("CJM", "cjm"); /* Eastern Cham */
test_language_two_way ("EVN", "eve");
+ test_language_two_way ("HAL", "cfm"); /* BCP47 and current ISO639-3 code for Halam/Falam Chin */
+ test_tag_from_language ("HAL", "flm"); /* Retired ISO639-3 code for Halam/Falam Chin */
+
+ test_tag_from_language ("QIN", "bgr"); /* Bawm Chin */
+ test_tag_from_language ("QIN", "cbl"); /* Bualkhaw Chin */
+ test_tag_from_language ("QIN", "cka"); /* Khumi Awa Chin */
+ test_tag_from_language ("QIN", "cmr"); /* Mro-Khimi Chin */
+ test_tag_from_language ("QIN", "cnb"); /* Chinbon Chin */
+ test_tag_from_language ("QIN", "cnh"); /* Hakha Chin */
+ test_tag_from_language ("QIN", "cnk"); /* Khumi Chin */
+ test_tag_from_language ("QIN", "cnw"); /* Ngawn Chin */
+ test_tag_from_language ("QIN", "csh"); /* Asho Chin */
+ test_tag_from_language ("QIN", "csy"); /* Siyin Chin */
+ test_tag_from_language ("QIN", "ctd"); /* Tedim Chin */
+ test_tag_from_language ("QIN", "czt"); /* Zotung Chin */
+ test_tag_from_language ("QIN", "dao"); /* Daai Chin */
+ test_tag_from_language ("QIN", "hlt"); /* Matu Chin */
+ test_tag_from_language ("QIN", "mrh"); /* Mara Chin */
+ test_tag_from_language ("QIN", "pck"); /* Paite Chin */
+ test_tag_from_language ("QIN", "sez"); /* Senthang Chin */
+ test_tag_from_language ("QIN", "tcp"); /* Tawr Chin */
+ test_tag_from_language ("QIN", "tcz"); /* Thado Chin */
+ test_tag_from_language ("QIN", "yos"); /* Yos, deprecated by IANA in favor of Zou [zom] */
+ test_tag_from_language ("QIN", "zom"); /* Zou */
+ test_tag_to_language ("QIN", "bgr"); /* no single BCP47 tag for Chin; picking Bawm Chin */
+
test_language_two_way ("FAR", "fa");
test_tag_from_language ("FAR", "fa_IR");
+ test_language_two_way ("SWA", "aii"); /* Swadaya Aramaic */
+
+ test_language_two_way ("SYR", "syr"); /* Syriac [macrolanguage] */
+ test_tag_from_language ("SYR", "amw"); /* Western Neo-Aramaic */
+ test_tag_from_language ("SYR", "cld"); /* Chaldean Neo-Aramaic */
+ test_tag_from_language ("SYR", "syc"); /* Classical Syriac */
+
+ test_language_two_way ("TUA", "tru"); /* Turoyo Aramaic */
+
test_language_two_way ("ZHH", "zh-hk"); /* Chinese (Hong Kong) */
test_tag_from_language ("ZHS", "zh"); /* Chinese */
@@ -238,6 +275,27 @@
test_tag_from_language ("APPH", "und-fonnapa");
test_tag_to_language ("APPH", "und-fonnapa");
+ /* Estrangela Syriac */
+ test_tag_from_language ("SYRE", "aii-Syre");
+ test_tag_from_language ("SYRE", "de-Syre");
+ test_tag_from_language ("SYRE", "syr-Syre");
+ test_tag_from_language ("SYRE", "und-Syre");
+ test_tag_to_language ("SYRE", "und-Syre");
+
+ /* Western Syriac */
+ test_tag_from_language ("SYRJ", "aii-Syrj");
+ test_tag_from_language ("SYRJ", "de-Syrj");
+ test_tag_from_language ("SYRJ", "syr-Syrj");
+ test_tag_from_language ("SYRJ", "und-Syrj");
+ test_tag_to_language ("SYRJ", "und-Syrj");
+
+ /* Eastern Syriac */
+ test_tag_from_language ("SYRN", "aii-Syrn");
+ test_tag_from_language ("SYRN", "de-Syrn");
+ test_tag_from_language ("SYRN", "syr-Syrn");
+ test_tag_from_language ("SYRN", "und-Syrn");
+ test_tag_to_language ("SYRN", "und-Syrn");
+
/* Test that x-hbot overrides the base language */
test_tag_from_language ("ABC", "fa-x-hbotabc-zxc");
test_tag_from_language ("ABC", "fa-ir-x-hbotabc-zxc");
diff --git a/test/shaping/Makefile.am b/test/shaping/Makefile.am
index f2bb95b..89578e1 100644
--- a/test/shaping/Makefile.am
+++ b/test/shaping/Makefile.am
@@ -43,6 +43,8 @@
TESTS = \
tests/arabic-fallback-shaping.tests \
tests/arabic-feature-order.tests \
+ tests/arabic-like-joining.tests \
+ tests/automatic-fractions.tests \
tests/cluster.tests \
tests/color-fonts.tests \
tests/context-matching.tests \
diff --git a/test/shaping/fonts/sha1sum/15dfc433a135a658b9f4b1a861b5cdd9658ccbb9.ttf b/test/shaping/fonts/sha1sum/15dfc433a135a658b9f4b1a861b5cdd9658ccbb9.ttf
new file mode 100644
index 0000000..4b80f80
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/15dfc433a135a658b9f4b1a861b5cdd9658ccbb9.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/5dfad7735c6a67085f1b90d4d497e32907db4c78.ttf b/test/shaping/fonts/sha1sum/5dfad7735c6a67085f1b90d4d497e32907db4c78.ttf
new file mode 100644
index 0000000..45f16fc
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/5dfad7735c6a67085f1b90d4d497e32907db4c78.ttf
Binary files differ
diff --git a/test/shaping/tests/arabic-like-joining.tests b/test/shaping/tests/arabic-like-joining.tests
new file mode 100644
index 0000000..ec994d0
--- /dev/null
+++ b/test/shaping/tests/arabic-like-joining.tests
@@ -0,0 +1 @@
+fonts/sha1sum/5dfad7735c6a67085f1b90d4d497e32907db4c78.ttf::U+1E922,U+1E923,U+1E924,U+1E925,U+1E926,U+1E927,U+1E928,U+1E929,U+1E92A,U+1E92B,U+1E92C,U+1E92D,U+1E92E,U+1E92F,U+1E930,U+1E931,U+1E932,U+1E933,U+1E934,U+1E935,U+1E936,U+1E937,U+1E938,U+1E939,U+1E93A,U+1E93B,U+1E93C,U+1E93D,U+1E93E,U+1E93F,U+1E940,U+1E941,U+1E942,U+1E943:[sha_adlam.fina=33+711|kpo_adlam.medi=32+573|zal_adlam.medi=31+773|gbe_adlam.medi=30+594|kha_adlam.medi=29+686|va_adlam.medi=28+621|nha_adlam.medi=27+587|tu_adlam.medi=26+772|nya_adlam.medi=25+577|ga_adlam.medi=24+552|qaaf_adlam.medi=23+694|ha_adlam.medi=22+600|chi_adlam.medi=21+662|jiim_adlam.medi=20+781|u_adlam.medi=19+678|ya_adlam.medi=18+553|kaf_adlam.medi=17+808|nun_adlam.medi=16+561|waw_adlam.medi=15+651|yhe_adlam.medi=14+674|dha_adlam.medi=13+674|o_adlam.medi=12+640|i_adlam.medi=11+657|fa_adlam.medi=10+590|e_adlam.medi=9+628|ra_adlam.medi=8+599|bhe_adlam.medi=7+594|pe_adlam.medi=6+492|sinnyiiyhe_adlam.medi=5+777|ba_adlam.medi=4+655|miim_adlam.medi=3+525|laam_adlam.medi=2+554|daali_adlam.medi=1+600|alif_adlam.init=0+597]
diff --git a/test/shaping/tests/automatic-fractions.tests b/test/shaping/tests/automatic-fractions.tests
new file mode 100644
index 0000000..f9510e2
--- /dev/null
+++ b/test/shaping/tests/automatic-fractions.tests
@@ -0,0 +1,3 @@
+fonts/sha1sum/15dfc433a135a658b9f4b1a861b5cdd9658ccbb9.ttf::U+0031,U+0032,U+0033,U+2044,U+0034,U+0035,U+0036:[one.numr=0+600|two.numr=1+600|three.numr=2+600|fraction=3+252|four.small=4+600|five.small=5+600|six.small=6+600]
+fonts/sha1sum/15dfc433a135a658b9f4b1a861b5cdd9658ccbb9.ttf:--direction=l --script=arab:U+0031,U+0032,U+0033,U+2044,U+0034,U+0035,U+0036:[one.numr=0+600|two.numr=1+600|three.numr=2+600|fraction=3+252|four.small=4+600|five.small=5+600|six.small=6+600]
+fonts/sha1sum/15dfc433a135a658b9f4b1a861b5cdd9658ccbb9.ttf:--direction=l:U+0661,U+0662,U+0663,U+2044,U+0664,U+0665,U+0666:[uni0661.numr=0+600|uni0662.numr=1+600|uni0663.numr=2+600|fraction=3+252|uni0664.small=4+600|uni0665.small=5+600|uni0666.small=6+600]
diff --git a/util/hb-shape.cc b/util/hb-shape.cc
index 3bd2184..75c3793 100644
--- a/util/hb-shape.cc
+++ b/util/hb-shape.cc
@@ -35,7 +35,9 @@
format (parser),
gs (NULL),
line_no (0),
- font (NULL) {}
+ font (NULL),
+ output_format (HB_BUFFER_SERIALIZE_FORMAT_INVALID),
+ format_flags (HB_BUFFER_SERIALIZE_FLAG_DEFAULT) {}
void init (const font_options_t *font_opts)
{
diff --git a/util/helper-cairo.cc b/util/helper-cairo.cc
index 8f30eea..2e2952b 100644
--- a/util/helper-cairo.cc
+++ b/util/helper-cairo.cc
@@ -28,6 +28,7 @@
#include <cairo-ft.h>
#include <hb-ft.h>
+#include FT_MULTIPLE_MASTERS_H
#include "helper-cairo-ansi.hh"
#ifdef CAIRO_HAS_SVG_SURFACE
@@ -76,7 +77,8 @@
cairo_font_face_t *cairo_face;
/* We cannot use the FT_Face from hb_font_t, as doing so will confuse hb_font_t because
- * cairo will reset the face size. As such, create new face... */
+ * cairo will reset the face size. As such, create new face...
+ * TODO Perhaps add API to hb-ft to encapsulate this code. */
FT_Face ft_face = NULL;//hb_ft_font_get_face (font);
if (!ft_face)
{
@@ -100,7 +102,23 @@
CAIRO_FONT_WEIGHT_NORMAL);
}
else
+ {
+ 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);
+ }
+ }
+
cairo_face = cairo_ft_font_face_create_for_ft_face (ft_face, 0);
+ }
cairo_matrix_t ctm, font_matrix;
cairo_font_options_t *font_options;
diff --git a/util/options.cc b/util/options.cc
index bc699c1..0f2e207 100644
--- a/util/options.cc
+++ b/util/options.cc
@@ -254,6 +254,47 @@
return true;
}
+static gboolean
+parse_variations (const char *name G_GNUC_UNUSED,
+ const char *arg,
+ gpointer data,
+ GError **error G_GNUC_UNUSED)
+{
+ font_options_t *font_opts = (font_options_t *) data;
+ char *s = (char *) arg;
+ char *p;
+
+ font_opts->num_variations = 0;
+ g_free (font_opts->variations);
+ font_opts->variations = NULL;
+
+ if (!*s)
+ return true;
+
+ /* count the variations first, so we can allocate memory */
+ p = s;
+ do {
+ font_opts->num_variations++;
+ p = strchr (p, ',');
+ if (p)
+ p++;
+ } while (p);
+
+ font_opts->variations = (hb_variation_t *) calloc (font_opts->num_variations, sizeof (*font_opts->variations));
+
+ /* now do the actual parsing */
+ p = s;
+ font_opts->num_variations = 0;
+ while (p && *p) {
+ char *end = strchr (p, ',');
+ if (hb_variation_from_string (p, end ? end - p : -1, &font_opts->variations[font_opts->num_variations]))
+ font_opts->num_variations++;
+ p = end ? end + 1 : NULL;
+ }
+
+ return true;
+}
+
void
view_options_t::add_options (option_parser_t *parser)
@@ -270,7 +311,7 @@
parser->add_group (entries,
"view",
"View options:",
- "Options controlling output rendering",
+ "Options for output rendering",
this);
}
@@ -299,7 +340,7 @@
parser->add_group (entries,
"shape",
"Shape options:",
- "Options controlling the shaping process",
+ "Options for the shaping process",
this);
const gchar *features_help = "Comma-separated list of font features\n"
@@ -346,7 +387,7 @@
parser->add_group (entries2,
"features",
"Features options:",
- "Options controlling font features used",
+ "Options for font features used",
this);
}
@@ -413,7 +454,30 @@
parser->add_group (entries,
"font",
"Font options:",
- "Options controlling the font",
+ "Options for the font",
+ this);
+
+ const gchar *variations_help = "Comma-separated list of font variations\n"
+ "\n"
+ " Variations are set globally. The format for specifying variation settings\n"
+ " follows. All valid CSS font-variation-settings values other than 'normal'\n"
+ " and 'inherited' are also accepted, though, not documented below.\n"
+ "\n"
+ " The format is a tag, optionally followed by an equals sign, followed by a\n"
+ " number. For example:\n"
+ "\n"
+ " \"wght=500\"\n"
+ " \"slnt=-7.5\"\n";
+
+ GOptionEntry entries2[] =
+ {
+ {"variations", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_variations, variations_help, "list"},
+ {NULL}
+ };
+ parser->add_group (entries2,
+ "variations",
+ "Varitions options:",
+ "Options for font variations used",
this);
}
@@ -431,7 +495,7 @@
parser->add_group (entries,
"text",
"Text options:",
- "Options controlling the input text",
+ "Options for the input text",
this);
}
@@ -459,7 +523,7 @@
parser->add_group (entries,
"output",
"Output destination & format options:",
- "Options controlling the destination and form of the output",
+ "Options for the destination & form of the output",
this);
}
@@ -561,6 +625,8 @@
hb_font_set_scale (font, scale_x, scale_y);
hb_face_destroy (face);
+ hb_font_set_variations (font, variations, num_variations);
+
void (*set_font_funcs) (hb_font_t *) = NULL;
if (!font_funcs)
{
@@ -719,7 +785,7 @@
" text: [<glyph name or index>=<glyph cluster index within input>@<horizontal displacement>,<vertical displacement>+<horizontal advance>,<vertical advance>|...]\n"
" json: [{\"g\": <glyph name or index>, \"ax\": <horizontal advance>, \"ay\": <vertical advance>, \"dx\": <horizontal displacement>, \"dy\": <vertical displacement>, \"cl\": <glyph cluster index within input>}, ...]\n"
"\nOutput syntax options:",
- "Options controlling the syntax of the output",
+ "Options for the syntax of the output",
this);
}
diff --git a/util/options.hh b/util/options.hh
index 919e4f8..9ed4fd0 100644
--- a/util/options.hh
+++ b/util/options.hh
@@ -285,7 +285,10 @@
{
font_options_t (option_parser_t *parser,
int default_font_size_,
- unsigned int subpixel_bits_) {
+ unsigned int subpixel_bits_)
+ {
+ variations = NULL;
+ num_variations = 0;
default_font_size = default_font_size_;
subpixel_bits = subpixel_bits_;
font_file = NULL;
@@ -299,6 +302,7 @@
}
~font_options_t (void) {
g_free (font_file);
+ free (variations);
g_free (font_funcs);
hb_font_destroy (font);
}
@@ -309,6 +313,8 @@
char *font_file;
int face_index;
+ hb_variation_t *variations;
+ unsigned int num_variations;
int default_font_size;
unsigned int subpixel_bits;
mutable double font_size_x;
diff --git a/win32/config-msvc.mak b/win32/config-msvc.mak
index ecbbe92..4cffaea 100644
--- a/win32/config-msvc.mak
+++ b/win32/config-msvc.mak
@@ -184,9 +184,10 @@
HB_SOURCES = $(HB_SOURCES) $(HB_ICU_sources)
HB_HEADERS = $(HB_HEADERS) $(HB_ICU_headers)
HB_DEP_LIBS = $(HB_DEP_LIBS) $(HB_ICU_DEP_LIBS)
-!else
-# If there is no GLib support, use the built-in UCDN
-# and define some of the macros in GLib's msvc_recommended_pragmas.h
+!endif
+
+!if "$(UCDN)" != "0"
+# Define some of the macros in GLib's msvc_recommended_pragmas.h
# to reduce some unneeded build-time warnings
HB_DEFINES = $(HB_DEFINES) /DHAVE_UCDN=1
HB_CFLAGS = \