aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJungshik Shin <jungshik@google.com>2017-01-26 12:39:49 -0800
committerjungshik <jungshik@google.com>2017-01-27 23:52:25 +0000
commitff95bda99dd20923ad72dca752dc39abdf787329 (patch)
treef383e8c957445ae7df533cdfadcdf7fe03d59ec2
parent7be7f017f265081e78892428b162f3ece8e29c96 (diff)
parent6af6c1114a3495584ac4197c62592741c407b5a2 (diff)
downloadharfbuzz_ng-ff95bda99dd20923ad72dca752dc39abdf787329.tar.gz
Merge Harfbuzz 1.4.2 from the upstream
Changes from 1.3.2 include Opentype 1.8 (variation font support) amd Math layout support. The list of changes between 1.3.2 and 1.4.2 is available at https://goo.gl/Qhml2Z Update src/hb-version.h and Android.bp (hb-ot-var.cc and hb-ot-math.cc added). No need to update hh files derived from rl files because there's no change in rl files. Test: Try Arabic, Hindi UI to see if there's any anomaly. Bug: 34742506 Change-Id: I0692bf2103f4987204338343851647c1240a5e34
-rw-r--r--Android.bp2
-rw-r--r--Makefile.am1
-rw-r--r--NEWS107
-rw-r--r--README.version4
-rw-r--r--appveyor.yml16
-rw-r--r--configure.ac25
-rw-r--r--docs/harfbuzz-docs.xml9
-rw-r--r--docs/harfbuzz-sections.txt71
-rw-r--r--src/Makefile.am2
-rw-r--r--src/Makefile.sources9
-rwxr-xr-xsrc/check-symbols.sh4
-rw-r--r--src/hb-common.cc344
-rw-r--r--src/hb-common.h36
-rw-r--r--src/hb-coretext.cc8
-rw-r--r--src/hb-directwrite.cc58
-rw-r--r--src/hb-directwrite.h4
-rw-r--r--src/hb-face-private.hh12
-rw-r--r--src/hb-face.cc6
-rw-r--r--src/hb-fallback-shape.cc4
-rw-r--r--src/hb-font-private.hh115
-rw-r--r--src/hb-font.cc122
-rw-r--r--src/hb-font.h18
-rw-r--r--src/hb-ft.cc37
-rw-r--r--src/hb-glib.cc2
-rw-r--r--src/hb-glib.h3
-rw-r--r--src/hb-gobject-structs.cc3
-rw-r--r--src/hb-graphite2.cc4
-rw-r--r--src/hb-open-file-private.hh2
-rw-r--r--src/hb-open-type-private.hh111
-rw-r--r--src/hb-ot-cbdt-table.hh384
-rw-r--r--src/hb-ot-cmap-table.hh6
-rw-r--r--src/hb-ot-font.cc194
-rw-r--r--src/hb-ot-hmtx-table.hh8
-rw-r--r--src/hb-ot-layout-common-private.hh505
-rw-r--r--src/hb-ot-layout-gdef-table.hh54
-rw-r--r--src/hb-ot-layout-gpos-table.hh117
-rw-r--r--src/hb-ot-layout-gsub-table.hh82
-rw-r--r--src/hb-ot-layout-gsubgpos-private.hh36
-rw-r--r--src/hb-ot-layout-private.hh9
-rw-r--r--src/hb-ot-layout.cc57
-rw-r--r--src/hb-ot-layout.h19
-rw-r--r--src/hb-ot-map-private.hh18
-rw-r--r--src/hb-ot-map.cc111
-rw-r--r--src/hb-ot-math-table.hh722
-rw-r--r--src/hb-ot-math.cc254
-rw-r--r--src/hb-ot-math.h209
-rw-r--r--src/hb-ot-shape-complex-arabic.cc1
-rw-r--r--src/hb-ot-shape-complex-default.cc1
-rw-r--r--src/hb-ot-shape-complex-hangul.cc3
-rw-r--r--src/hb-ot-shape-complex-hebrew.cc13
-rw-r--r--src/hb-ot-shape-complex-indic.cc20
-rw-r--r--src/hb-ot-shape-complex-myanmar.cc2
-rw-r--r--src/hb-ot-shape-complex-private.hh8
-rw-r--r--src/hb-ot-shape-complex-thai.cc1
-rw-r--r--src/hb-ot-shape-complex-tibetan.cc1
-rw-r--r--src/hb-ot-shape-complex-use.cc22
-rw-r--r--src/hb-ot-shape-private.hh6
-rw-r--r--src/hb-ot-shape.cc86
-rw-r--r--src/hb-ot-tag.cc80
-rw-r--r--src/hb-ot-var-avar-table.hh144
-rw-r--r--src/hb-ot-var-fvar-table.hh209
-rw-r--r--src/hb-ot-var-hvar-table.hh165
-rw-r--r--src/hb-ot-var.cc160
-rw-r--r--src/hb-ot-var.h105
-rw-r--r--src/hb-ot.h2
-rw-r--r--src/hb-private.hh11
-rw-r--r--src/hb-set.cc2
-rw-r--r--src/hb-shape-plan-private.hh9
-rw-r--r--src/hb-shape-plan.cc102
-rw-r--r--src/hb-shape-plan.h19
-rw-r--r--src/hb-shape.cc255
-rw-r--r--src/hb-shape.h16
-rw-r--r--src/hb-unicode.cc6
-rw-r--r--src/hb-uniscribe.cc4
-rw-r--r--src/hb-version.h4
-rw-r--r--test/api/Makefile.am23
-rw-r--r--test/api/fonts/MathTestFontEmpty.otfbin0 -> 14320 bytes
-rw-r--r--test/api/fonts/MathTestFontFull.otfbin0 -> 25412 bytes
-rw-r--r--test/api/fonts/MathTestFontNone.otfbin0 -> 14284 bytes
-rw-r--r--test/api/fonts/MathTestFontPartial1.otfbin0 -> 14348 bytes
-rw-r--r--test/api/fonts/MathTestFontPartial2.otfbin0 -> 14356 bytes
-rw-r--r--test/api/fonts/MathTestFontPartial3.otfbin0 -> 14380 bytes
-rw-r--r--test/api/fonts/MathTestFontPartial4.otfbin0 -> 14360 bytes
-rw-r--r--test/api/test-ot-math.c712
-rw-r--r--test/api/test-ot-tag.c58
-rw-r--r--test/fuzzing/Makefile.am3
-rw-r--r--test/fuzzing/hb-fuzzer.cc43
-rw-r--r--test/fuzzing/hb-fuzzer.hh4
-rw-r--r--test/fuzzing/main.cc21
-rw-r--r--test/shaping/Makefile.am3
-rw-r--r--test/shaping/fonts/sha1sum/15dfc433a135a658b9f4b1a861b5cdd9658ccbb9.ttfbin0 -> 4936 bytes
-rw-r--r--test/shaping/fonts/sha1sum/217a934cfe15c548b572c203dceb2befdf026462.ttfbin0 -> 1384 bytes
-rw-r--r--test/shaping/fonts/sha1sum/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttfbin0 -> 66936 bytes
-rw-r--r--test/shaping/fonts/sha1sum/ee39587d13b2afa5499cc79e45780aa79293bbd4.ttfbin0 -> 3724 bytes
-rw-r--r--test/shaping/fonts/sha1sum/f9b1dd4dcb515e757789a22cb4241107746fd3d0.ttfbin0 -> 1004 bytes
-rw-r--r--test/shaping/tests/automatic-fractions.tests3
-rw-r--r--test/shaping/tests/color-fonts.tests1
-rw-r--r--test/shaping/tests/fuzzed.tests1
-rw-r--r--test/shaping/tests/use-marchen.tests35
-rw-r--r--test/shaping/tests/vertical.tests2
-rw-r--r--util/helper-cairo.cc20
-rw-r--r--util/options.cc80
-rw-r--r--util/options.hh8
-rw-r--r--win32/README.txt17
-rw-r--r--win32/build-rules-msvc.mak13
-rw-r--r--win32/config-msvc.mak67
-rw-r--r--win32/config.h.win32.in2
-rw-r--r--win32/create-lists-msvc.mak13
-rw-r--r--win32/detectenv-msvc.mak9
-rw-r--r--win32/generate-msvc.mak4
-rw-r--r--win32/info-msvc.mak23
-rw-r--r--win32/install.mak4
112 files changed, 5743 insertions, 807 deletions
diff --git a/Android.bp b/Android.bp
index f04873741..ff6b4301d 100644
--- a/Android.bp
+++ b/Android.bp
@@ -75,6 +75,7 @@ cc_library_shared {
"src/hb-ot-font.cc",
"src/hb-ot-layout.cc",
"src/hb-ot-map.cc",
+ "src/hb-ot-math.cc",
"src/hb-ot-shape.cc",
"src/hb-ot-shape-complex-arabic.cc",
"src/hb-ot-shape-complex-default.cc",
@@ -89,6 +90,7 @@ cc_library_shared {
"src/hb-ot-shape-complex-use-table.cc",
"src/hb-ot-shape-normalize.cc",
"src/hb-ot-shape-fallback.cc",
+ "src/hb-ot-var.cc",
"src/hb-icu.cc",
],
diff --git a/Makefile.am b/Makefile.am
index d56a151a3..8dc8a4b93 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -9,7 +9,6 @@ SUBDIRS = src util test docs win32
EXTRA_DIST = \
autogen.sh \
harfbuzz.doap \
- Android.mk \
README.python \
BUILD.md \
$(NULL)
diff --git a/NEWS b/NEWS
index ae0926e63..43a3bacea 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,110 @@
+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
+====================================
+
+- Always build and use UCDN for Unicode data by default.
+ Reduces dependence on version of Unicode data in glib,
+ specially in the Windows bundles we are shipping, which
+ have very old glib.
+
+
+Overview of changes leading to 1.4.0
+Thursday, January 5, 2017
+====================================
+
+- Merged "OpenType GX" branch which adds core of support for
+ OpenType 1.8 Font Variations. To that extent, the relevant
+ new API is:
+
+New API:
+hb_font_set_var_coords_normalized()
+
+ with supporting API:
+
+New API:
+HB_OT_LAYOUT_NO_VARIATIONS_INDEX
+hb_ot_layout_table_find_feature_variations()
+hb_ot_layout_feature_with_variations_get_lookups()
+hb_shape_plan_create2()
+hb_shape_plan_create_cached2()
+
+ Currently variations in GSUB/GPOS/GDEF are fully supported,
+ and no other tables are supported. In particular, fvar/avar
+ are NOT supported, hence the hb_font_set_var_coords_normalized()
+ taking normalized coordinates. API to take design coordinates
+ will be added in the future.
+
+ HVAR/VVAR/MVAR support will also be added to hb-ot-font in the
+ future.
+
+- Fix regression in GDEF glyph class processing.
+- Add decompositions for Chakma, Limbu, and Balinese in USE shaper.
+- Misc fixes.
+
+
+Overview of changes leading to 1.3.4
+Monday, December 5, 2016
+====================================
+
+- Fix vertical glyph origin in hb-ot-font.
+- Implement CBDT/CBLC color font glyph extents in hb-ot-font.
+
+
+Overview of changes leading to 1.3.3
+Wednesday, September 28, 2016
+====================================
+
+- Implement parsing of OpenType MATH table.
+New API:
+HB_OT_TAG_MATH
+HB_OT_MATH_SCRIPT
+hb_ot_math_constant_t
+hb_ot_math_kern_t
+hb_ot_math_glyph_variant_t
+hb_ot_math_glyph_part_flags_t
+hb_ot_math_glyph_part_t
+hb_ot_math_has_data
+hb_ot_math_get_constant
+hb_ot_math_get_glyph_italics_correction
+hb_ot_math_get_glyph_top_accent_attachment
+hb_ot_math_get_glyph_kerning
+hb_ot_math_is_glyph_extended_shape
+hb_ot_math_get_glyph_variants
+hb_ot_math_get_min_connector_overlap
+hb_ot_math_get_glyph_assembly
+
+
Overview of changes leading to 1.3.2
Wednesday, September 27, 2016
====================================
diff --git a/README.version b/README.version
index 126e130ba..93200eec5 100644
--- a/README.version
+++ b/README.version
@@ -1,3 +1,3 @@
-URL: http://www.freedesktop.org/software/harfbuzz/release/harfbuzz-1.3.2.tar.bz2
-Version: 1.3.2
+URL: http://www.freedesktop.org/software/harfbuzz/release/harfbuzz-1.4.2.tar.bz2
+Version: 1.4.2
BugComponent: 25699
diff --git a/appveyor.yml b/appveyor.yml
index 4677a2774..2a0e7c59f 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -4,15 +4,19 @@ environment:
matrix:
- compiler: msvc
ARCH: amd64
+ VCPKG_ARCH: x64-windows
CFG: release
- compiler: msvc
ARCH: x86
+ VCPKG_ARCH: x86-windows
CFG: release
- compiler: msvc
ARCH: amd64
+ VCPKG_ARCH: x64-windows
CFG: debug
- compiler: msvc
ARCH: x86
+ VCPKG_ARCH: x86-windows
CFG: debug
- compiler: msys2
@@ -27,11 +31,19 @@ environment:
install:
- C:\msys64\usr\bin\bash -lc "pacman --noconfirm -S mingw-w64-x86_64-ragel"
-build_script:
- 'if "%compiler%"=="msvc" call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" %ARCH%'
+ - 'if "%compiler%"=="msvc" git clone https://github.com/Microsoft/vcpkg'
+ - 'if "%compiler%"=="msvc" cd vcpkg'
+ - 'if "%compiler%"=="msvc" powershell -exec bypass scripts\bootstrap.ps1'
+ - 'if "%compiler%"=="msvc" vcpkg install freetype:%VCPKG_ARCH%'
+ - 'if "%compiler%"=="msvc" copy installed\%VCPKG_ARCH%\debug\lib\freetyped.lib installed\%VCPKG_ARCH%\lib'
+ - 'if "%compiler%"=="msvc" cd ..'
+
+build_script:
- 'if "%compiler%"=="msvc" C:\msys64\usr\bin\bash -lc "cd $APPVEYOR_BUILD_FOLDER; PATH=$PATH:/mingw64/bin:/mingw32/bin; ./autogen.sh; make distdir"'
- 'if "%compiler%"=="msvc" cd harfbuzz-*\win32'
- - 'if "%compiler%"=="msvc" nmake /f Makefile.vc CFG=%CFG% DIRECTWRITE=1'
+ - 'if "%compiler%"=="msvc" nmake /f Makefile.vc CFG=%CFG% UNISCRIBE=1 DIRECTWRITE=1 FREETYPE=1 FREETYPE_DIR=..\..\vcpkg\installed\%VCPKG_ARCH%\include ADDITIONAL_LIB_DIR=..\..\vcpkg\installed\%VCPKG_ARCH%\lib'
+ - 'if "%compiler%"=="msvc" nmake /f Makefile.vc CFG=%CFG% UNISCRIBE=1 DIRECTWRITE=1 FREETYPE=1 install'
- 'if "%compiler%"=="msys2" C:\msys64\usr\bin\bash -lc "pacman --noconfirm -S mingw-w64-$MSYS2_ARCH-{freetype,cairo,icu,gettext,gobject-introspection,gcc,gcc-libs,glib2,graphite2,pkg-config}"'
- 'if "%compiler%"=="msys2" C:\msys64\usr\bin\bash -lc "cd $APPVEYOR_BUILD_FOLDER; PATH=$PATH:/mingw64/bin:/mingw32/bin; ./autogen.sh --with-uniscribe --with-freetype --with-glib --with-gobject --with-cairo --with-icu --with-graphite2 --build=$MINGW_CHOST --host=$MINGW_CHOST --prefix=$MINGW_PREFIX; make; make check"'
diff --git a/configure.ac b/configure.ac
index 57e9e6db6..31fa97d3b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,6 +1,6 @@
AC_PREREQ([2.64])
AC_INIT([HarfBuzz],
- [1.3.2],
+ [1.4.2],
[https://github.com/behdad/harfbuzz/issues/new],
[harfbuzz],
[http://harfbuzz.org/])
@@ -19,9 +19,11 @@ LT_PREREQ([2.2])
LT_INIT([disable-static])
# Check for programs
+AC_USE_SYSTEM_EXTENSIONS
AC_PROG_CC
AM_PROG_CC_C_O
AC_PROG_CXX
+AC_SYS_LARGEFILE
PKG_PROG_PKG_CONFIG([0.20])
AM_MISSING_PROG([RAGEL], [ragel])
AM_MISSING_PROG([GIT], [git])
@@ -145,7 +147,7 @@ AC_ARG_WITH(glib,
[Use glib @<:@default=auto@:>@])],,
[with_glib=auto])
have_glib=false
-GLIB_DEPS="glib-2.0 >= 2.16"
+GLIB_DEPS="glib-2.0 >= 2.19.1"
AC_SUBST(GLIB_DEPS)
if test "x$with_glib" = "xyes" -o "x$with_glib" = "xauto"; then
PKG_CHECK_MODULES(GLIB, $GLIB_DEPS, have_glib=true, :)
@@ -287,9 +289,13 @@ AM_CONDITIONAL(HAVE_ICU_BUILTIN, $have_icu && test "x$with_icu" = "xbuiltin")
dnl ===========================================================================
-have_ucdn=true
-if $have_glib || test \( $have_icu -a "x$with_icu" = "xbuiltin" \); then
- have_ucdn=false
+AC_ARG_WITH(ucdn,
+ [AS_HELP_STRING([--with-ucdn=@<:@yes/no@:>@],
+ [Use builtin UCDN library @<:@default=yes@:>@])],,
+ [with_ucdn=yes])
+have_ucdn=false
+if test "x$with_ucdn" = "xyes"; then
+ have_ucdn=true
fi
if $have_ucdn; then
AC_DEFINE(HAVE_UCDN, 1, [Have UCDN Unicode functions])
@@ -344,6 +350,10 @@ if test "x$with_freetype" = "xyes" -a "x$have_freetype" != "xtrue"; then
fi
if $have_freetype; then
AC_DEFINE(HAVE_FREETYPE, 1, [Have FreeType 2 library])
+ save_libs=$LIBS
+ LIBS="$LIBS $FREETYPE_LIBS"
+ AC_CHECK_FUNCS(FT_Get_Var_Blend_Coordinates)
+ LIBS=$save_libs
fi
AM_CONDITIONAL(HAVE_FREETYPE, $have_freetype)
@@ -411,7 +421,8 @@ if test "x$with_coretext" = "xyes" -o "x$with_coretext" = "xauto"; then
else
# On iOS CoreText and CoreGraphics are stand-alone frameworks
if test "x$have_coretext" != "xtrue"; then
- AC_CHECK_TYPE(CTFontRef, have_coretext=true,, [#include <CoreText/CoreText.h>])
+ # Check for a different symbol to avoid getting cached result.
+ AC_CHECK_TYPE(CTRunRef, have_coretext=true,, [#include <CoreText/CoreText.h>])
fi
if $have_coretext; then
@@ -494,9 +505,9 @@ AC_MSG_NOTICE([
Build configuration:
Unicode callbacks (you want at least one):
+ Builtin (UCDN): ${have_ucdn}
Glib: ${have_glib}
ICU: ${have_icu}
- UCDN: ${have_ucdn}
Font callbacks (the more the better):
FreeType: ${have_freetype}
diff --git a/docs/harfbuzz-docs.xml b/docs/harfbuzz-docs.xml
index 2c43c4687..00113e985 100644
--- a/docs/harfbuzz-docs.xml
+++ b/docs/harfbuzz-docs.xml
@@ -80,6 +80,7 @@
<xi:include href="xml/hb-ot-tag.xml"/>
<xi:include href="xml/hb-ot-font.xml"/>
<xi:include href="xml/hb-ot-shape.xml"/>
+ <xi:include href="xml/hb-ot-math.xml"/>
<xi:include href="xml/hb-shape-plan.xml"/>
@@ -175,6 +176,14 @@
<title>Index of new symbols in 1.1.3</title>
<xi:include href="xml/api-index-1.1.3.xml"><xi:fallback /></xi:include>
</index>
+ <index id="api-index-1-2-3" role="1.2.3">
+ <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">
+ <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>
<index id="deprecated-api-index" role="deprecated">
<title>Index of deprecated API</title>
<xi:include href="xml/api-index-deprecated.xml"><xi:fallback /></xi:include>
diff --git a/docs/harfbuzz-sections.txt b/docs/harfbuzz-sections.txt
index e0dc23d9c..a91eb4c2c 100644
--- a/docs/harfbuzz-sections.txt
+++ b/docs/harfbuzz-sections.txt
@@ -144,6 +144,8 @@ uint8_t
HB_BUFFER_FLAGS_DEFAULT
HB_BUFFER_SERIALIZE_FLAGS_DEFAULT
HB_SCRIPT_CANADIAN_ABORIGINAL
+hb_font_funcs_set_glyph_func
+hb_font_get_glyph_func_t
</SECTION>
<SECTION>
@@ -193,7 +195,6 @@ hb_font_funcs_reference
hb_font_funcs_set_glyph_contour_point_func
hb_font_funcs_set_glyph_extents_func
hb_font_funcs_set_glyph_from_name_func
-hb_font_funcs_set_glyph_func
hb_font_funcs_set_glyph_h_advance_func
hb_font_funcs_set_glyph_h_kerning_func
hb_font_funcs_set_glyph_h_origin_func
@@ -201,7 +202,9 @@ hb_font_funcs_set_glyph_name_func
hb_font_funcs_set_glyph_v_advance_func
hb_font_funcs_set_glyph_v_kerning_func
hb_font_funcs_set_glyph_v_origin_func
+hb_font_funcs_set_nominal_glyph_func
hb_font_funcs_set_user_data
+hb_font_funcs_set_variation_glyph_func
hb_font_funcs_t
hb_font_get_empty
hb_font_get_face
@@ -216,7 +219,6 @@ hb_font_get_glyph_extents_for_origin
hb_font_get_glyph_extents_func_t
hb_font_get_glyph_from_name
hb_font_get_glyph_from_name_func_t
-hb_font_get_glyph_func_t
hb_font_get_glyph_h_advance
hb_font_get_glyph_h_advance_func_t
hb_font_get_glyph_h_kerning
@@ -235,10 +237,15 @@ hb_font_get_glyph_v_kerning
hb_font_get_glyph_v_kerning_func_t
hb_font_get_glyph_v_origin
hb_font_get_glyph_v_origin_func_t
+hb_font_get_nominal_glyph
+hb_font_get_nominal_glyph_func_t
hb_font_get_parent
hb_font_get_ppem
hb_font_get_scale
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
@@ -246,9 +253,16 @@ hb_font_make_immutable
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
@@ -260,7 +274,6 @@ hb_font_get_font_h_extents_func_t
hb_font_get_font_v_extents_func_t
hb_font_get_h_extents
hb_font_get_v_extents
-hb_font_set_parent
</SECTION>
<SECTION>
@@ -298,6 +311,9 @@ HB_GOBJECT_TYPE_FONT
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
@@ -322,6 +338,9 @@ hb_gobject_font_funcs_get_type
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
@@ -378,12 +397,14 @@ hb_ot_shape_glyphs_closure
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
@@ -404,6 +425,7 @@ hb_ot_layout_lookup_would_substitute
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
@@ -417,6 +439,43 @@ Xhb_ot_layout_lookup_substitute
</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
+hb_ot_math_constant_t
+hb_ot_math_kern_t
+hb_ot_math_glyph_variant_t
+hb_ot_math_glyph_part_flags_t
+hb_ot_math_glyph_part_t
+hb_ot_math_has_data
+hb_ot_math_get_constant
+hb_ot_math_get_glyph_italics_correction
+hb_ot_math_get_glyph_top_accent_attachment
+hb_ot_math_get_glyph_kerning
+hb_ot_math_is_glyph_extended_shape
+hb_ot_math_get_glyph_variants
+hb_ot_math_get_min_connector_overlap
+hb_ot_math_get_glyph_assembly
+</SECTION>
+
+<SECTION>
<FILE>hb-ot-tag</FILE>
HB_OT_TAG_DEFAULT_LANGUAGE
HB_OT_TAG_DEFAULT_SCRIPT
@@ -460,8 +519,8 @@ hb_set_union
<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
@@ -472,6 +531,8 @@ hb_shape_list_shapers
<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
@@ -526,6 +587,8 @@ hb_unicode_script_func_t
<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/src/Makefile.am b/src/Makefile.am
index 8cfe4ac7c..d7420a090 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -299,6 +299,8 @@ test_buffer_serialize_SOURCES = test-buffer-serialize.cc
test_buffer_serialize_CPPFLAGS = $(HBCFLAGS)
test_buffer_serialize_LDADD = libharfbuzz.la $(HBLIBS)
+check: harfbuzz.def # For check-defs.sh
+
dist_check_SCRIPTS = \
check-c-linkage-decls.sh \
check-defs.sh \
diff --git a/src/Makefile.sources b/src/Makefile.sources
index ac806838c..8d7f1a05d 100644
--- a/src/Makefile.sources
+++ b/src/Makefile.sources
@@ -20,6 +20,7 @@ HB_BASE_sources = \
hb-object-private.hh \
hb-open-file-private.hh \
hb-open-type-private.hh \
+ hb-ot-cbdt-table.hh \
hb-ot-cmap-table.hh \
hb-ot-glyf-table.hh \
hb-ot-head-table.hh \
@@ -78,6 +79,8 @@ HB_OT_sources = \
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 \
@@ -105,14 +108,20 @@ HB_OT_sources = \
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 \
$(NULL)
HB_OT_headers = \
hb-ot.h \
hb-ot-font.h \
hb-ot-layout.h \
+ 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/check-symbols.sh b/src/check-symbols.sh
index b2bf43fce..ba09ba1cc 100755
--- a/src/check-symbols.sh
+++ b/src/check-symbols.sh
@@ -19,8 +19,8 @@ tested=false
for suffix in so dylib; do
so=.libs/libharfbuzz.$suffix
if ! test -f "$so"; then continue; fi
-
- EXPORTED_SYMBOLS="`nm "$so" | grep ' [BCDGINRSTVW] ' | grep -v ' _fini\>\| _init\>\| _fdata\>\| _ftext\>\| _fbss\>\| __bss_start\>\| __bss_start__\>\| __bss_end__\>\| _edata\>\| _end\>\| _bss_end__\>\| __end__\>\| __gcov_flush\>\| llvm_' | cut -d' ' -f3`"
+
+ EXPORTED_SYMBOLS="`nm "$so" | grep ' [BCDGINRSTVW] ' | grep -v ' _fini\>\| _init\>\| _fdata\>\| _ftext\>\| _fbss\>\| __bss_start\>\| __bss_start__\>\| __bss_end__\>\| _edata\>\| _end\>\| _bss_end__\>\| __end__\>\| __gcov_flush\>\| ___gcov_flush\>\| llvm_\| _llvm_' | cut -d' ' -f3`"
prefix=`basename "$so" | sed 's/libharfbuzz/hb/; s/-/_/g; s/[.].*//'`
diff --git a/src/hb-common.cc b/src/hb-common.cc
index 3564e4355..64e77d434 100644
--- a/src/hb-common.cc
+++ b/src/hb-common.cc
@@ -605,3 +605,347 @@ hb_version_atleast (unsigned int major,
{
return HB_VERSION_ATLEAST (major, minor, micro);
}
+
+
+
+/* hb_feature_t and hb_variation_t */
+
+static bool
+parse_space (const char **pp, const char *end)
+{
+ while (*pp < end && ISSPACE (**pp))
+ (*pp)++;
+ return true;
+}
+
+static bool
+parse_char (const char **pp, const char *end, char c)
+{
+ parse_space (pp, end);
+
+ if (*pp == end || **pp != c)
+ return false;
+
+ (*pp)++;
+ return true;
+}
+
+static bool
+parse_uint (const char **pp, const char *end, unsigned int *pv)
+{
+ char buf[32];
+ unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - *pp));
+ strncpy (buf, *pp, len);
+ buf[len] = '\0';
+
+ char *p = buf;
+ char *pend = p;
+ unsigned int v;
+
+ /* Intentionally use strtol instead of strtoul, such that
+ * -1 turns into "big number"... */
+ errno = 0;
+ v = strtol (p, &pend, 0);
+ if (errno || p == pend)
+ return false;
+
+ *pv = v;
+ *pp += pend - p;
+ return true;
+}
+
+static bool
+parse_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 2cbee76a8..634cb96a6 100644
--- a/src/hb-common.h
+++ b/src/hb-common.h
@@ -362,6 +362,42 @@ typedef struct hb_user_data_key_t {
typedef void (*hb_destroy_func_t) (void *user_data);
+/* Font features and variations. */
+
+typedef struct hb_feature_t {
+ hb_tag_t tag;
+ uint32_t value;
+ unsigned int start;
+ unsigned int end;
+} hb_feature_t;
+
+HB_EXTERN hb_bool_t
+hb_feature_from_string (const char *str, int len,
+ hb_feature_t *feature);
+
+HB_EXTERN void
+hb_feature_to_string (hb_feature_t *feature,
+ char *buf, unsigned int size);
+
+/**
+ * hb_variation_t:
+ *
+ * Since: 1.4.2
+ */
+typedef struct hb_variation_t {
+ hb_tag_t tag;
+ float value;
+} hb_variation_t;
+
+HB_EXTERN hb_bool_t
+hb_variation_from_string (const char *str, int len,
+ hb_variation_t *variation);
+
+HB_EXTERN void
+hb_variation_to_string (hb_variation_t *variation,
+ char *buf, unsigned int size);
+
+
HB_END_DECLS
#endif /* HB_COMMON_H */
diff --git a/src/hb-coretext.cc b/src/hb-coretext.cc
index 507581bd7..e857dfae0 100644
--- a/src/hb-coretext.cc
+++ b/src/hb-coretext.cc
@@ -288,7 +288,9 @@ struct hb_coretext_shaper_shape_plan_data_t {};
hb_coretext_shaper_shape_plan_data_t *
_hb_coretext_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan HB_UNUSED,
const hb_feature_t *user_features HB_UNUSED,
- unsigned int num_user_features HB_UNUSED)
+ unsigned int num_user_features HB_UNUSED,
+ const int *coords HB_UNUSED,
+ unsigned int num_coords HB_UNUSED)
{
return (hb_coretext_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
}
@@ -1280,7 +1282,9 @@ struct hb_coretext_aat_shaper_shape_plan_data_t {};
hb_coretext_aat_shaper_shape_plan_data_t *
_hb_coretext_aat_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan HB_UNUSED,
const hb_feature_t *user_features HB_UNUSED,
- unsigned int num_user_features HB_UNUSED)
+ unsigned int num_user_features HB_UNUSED,
+ const int *coords HB_UNUSED,
+ unsigned int num_coords HB_UNUSED)
{
return (hb_coretext_aat_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
}
diff --git a/src/hb-directwrite.cc b/src/hb-directwrite.cc
index 76482acd3..d63bc0473 100644
--- a/src/hb-directwrite.cc
+++ b/src/hb-directwrite.cc
@@ -209,8 +209,8 @@ _hb_directwrite_shaper_face_data_destroy(hb_directwrite_shaper_face_data_t *data
data->fontFile->Release ();
if (data->dwriteFactory) {
if (data->fontFileLoader)
- data->dwriteFactory->UnregisterFontFileLoader(data->fontFileLoader);
- data->dwriteFactory->Release();
+ data->dwriteFactory->UnregisterFontFileLoader (data->fontFileLoader);
+ data->dwriteFactory->Release ();
}
if (data->fontFileLoader)
delete data->fontFileLoader;
@@ -258,8 +258,10 @@ struct hb_directwrite_shaper_shape_plan_data_t {};
hb_directwrite_shaper_shape_plan_data_t *
_hb_directwrite_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan HB_UNUSED,
- const hb_feature_t *user_features HB_UNUSED,
- unsigned int num_user_features HB_UNUSED)
+ const hb_feature_t *user_features HB_UNUSED,
+ unsigned int num_user_features HB_UNUSED,
+ const int *coords HB_UNUSED,
+ unsigned int num_coords HB_UNUSED)
{
return (hb_directwrite_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
}
@@ -540,12 +542,13 @@ static inline uint32_t hb_uint32_swap (const uint32_t v)
* shaper
*/
-hb_bool_t
-_hb_directwrite_shape(hb_shape_plan_t *shape_plan,
+static hb_bool_t
+_hb_directwrite_shape_full(hb_shape_plan_t *shape_plan,
hb_font_t *font,
hb_buffer_t *buffer,
const hb_feature_t *features,
- unsigned int num_features)
+ unsigned int num_features,
+ float lineWidth)
{
hb_face_t *face = font->face;
hb_directwrite_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
@@ -668,7 +671,7 @@ retry_getglyphs:
DWRITE_SHAPING_GLYPH_PROPERTIES* glyphProperties = (DWRITE_SHAPING_GLYPH_PROPERTIES*)
malloc (maxGlyphCount * sizeof (DWRITE_SHAPING_GLYPH_PROPERTIES));
- hr = analyzer->GetGlyphs (textString, textLength, fontFace, FALSE,
+ hr = analyzer->GetGlyphs (textString, textLength, fontFace, false,
isRightToLeft, &runHead->mScript, localeName, NULL, &dwFeatures,
featureRangeLengths, 1, maxGlyphCount, clusterMap, textProperties, glyphIndices,
glyphProperties, &glyphCount);
@@ -716,7 +719,7 @@ retry_getglyphs:
hr = analyzer->GetGlyphPlacements (textString,
clusterMap, textProperties, textLength, glyphIndices,
glyphProperties, glyphCount, fontFace, fontEmSize,
- FALSE, isRightToLeft, &runHead->mScript, localeName,
+ false, isRightToLeft, &runHead->mScript, localeName,
&dwFeatures, featureRangeLengths, 1,
glyphAdvances, glyphOffsets);
@@ -726,9 +729,6 @@ retry_getglyphs:
return false;
}
- // TODO: get lineWith from somewhere
- float lineWidth = 0;
-
IDWriteTextAnalyzer1* analyzer1;
analyzer->QueryInterface (&analyzer1);
@@ -898,3 +898,37 @@ retry_getglyphs:
/* Wow, done! */
return true;
}
+
+hb_bool_t
+_hb_directwrite_shape(hb_shape_plan_t *shape_plan,
+ hb_font_t *font,
+ hb_buffer_t *buffer,
+ const hb_feature_t *features,
+ unsigned int num_features)
+{
+ return _hb_directwrite_shape_full(shape_plan, font, buffer,
+ features, num_features, 0);
+}
+
+/*
+ * Public [experimental] API
+ */
+
+hb_bool_t
+hb_directwrite_shape_experimental_width(hb_font_t *font,
+ hb_buffer_t *buffer,
+ const hb_feature_t *features,
+ unsigned int num_features,
+ float width)
+{
+ static char *shapers = "directwrite";
+ hb_shape_plan_t *shape_plan = hb_shape_plan_create_cached (font->face,
+ &buffer->props, features, num_features, &shapers);
+ hb_bool_t res = _hb_directwrite_shape_full (shape_plan, font, buffer,
+ features, num_features, width);
+
+ if (res)
+ buffer->content_type = HB_BUFFER_CONTENT_TYPE_GLYPHS;
+
+ return res;
+}
diff --git a/src/hb-directwrite.h b/src/hb-directwrite.h
index 0e1b4799d..e743af214 100644
--- a/src/hb-directwrite.h
+++ b/src/hb-directwrite.h
@@ -29,6 +29,10 @@
HB_BEGIN_DECLS
+HB_EXTERN hb_bool_t
+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
#endif /* HB_DIRECTWRITE_H */
diff --git a/src/hb-face-private.hh b/src/hb-face-private.hh
index c4266fff4..43e7b1cb3 100644
--- a/src/hb-face-private.hh
+++ b/src/hb-face-private.hh
@@ -50,12 +50,16 @@ struct hb_face_t {
void *user_data;
hb_destroy_func_t destroy;
- unsigned int index;
- mutable unsigned int upem;
- mutable unsigned int num_glyphs;
+ unsigned int index; /* Face index in a collection, zero-based. */
+ mutable unsigned int upem; /* Units-per-EM. */
+ mutable unsigned int num_glyphs; /* Number of glyphs. */
- struct hb_shaper_data_t shaper_data;
+ 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;
diff --git a/src/hb-face.cc b/src/hb-face.cc
index 6b563bc8f..1ba970707 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
diff --git a/src/hb-fallback-shape.cc b/src/hb-fallback-shape.cc
index e2ad24001..ac6d4b00f 100644
--- a/src/hb-fallback-shape.cc
+++ b/src/hb-fallback-shape.cc
@@ -73,7 +73,9 @@ struct hb_fallback_shaper_shape_plan_data_t {};
hb_fallback_shaper_shape_plan_data_t *
_hb_fallback_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan HB_UNUSED,
const hb_feature_t *user_features HB_UNUSED,
- unsigned int num_user_features HB_UNUSED)
+ unsigned int num_user_features HB_UNUSED,
+ const int *coords HB_UNUSED,
+ unsigned int num_coords HB_UNUSED)
{
return (hb_fallback_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
}
diff --git a/src/hb-font-private.hh b/src/hb-font-private.hh
index 0b7557794..53671d78d 100644
--- a/src/hb-font-private.hh
+++ b/src/hb-font-private.hh
@@ -108,6 +108,10 @@ struct hb_font_t {
unsigned int x_ppem;
unsigned int y_ppem;
+ /* Font variation coordinates. */
+ unsigned int num_coords;
+ int *coords;
+
hb_font_funcs_t *klass;
void *user_data;
hb_destroy_func_t destroy;
@@ -116,8 +120,14 @@ struct hb_font_t {
/* Convert from font-space to user-space */
- inline hb_position_t em_scale_x (int16_t v) { return em_scale (v, this->x_scale); }
- inline hb_position_t em_scale_y (int16_t v) { return em_scale (v, this->y_scale); }
+ inline int dir_scale (hb_direction_t direction)
+ { return HB_DIRECTION_IS_VERTICAL(direction) ? y_scale : x_scale; }
+ inline hb_position_t em_scale_x (int16_t v) { return em_scale (v, x_scale); }
+ inline hb_position_t em_scale_y (int16_t v) { return em_scale (v, y_scale); }
+ inline hb_position_t em_scalef_x (float v) { return em_scalef (v, this->x_scale); }
+ inline hb_position_t em_scalef_y (float v) { return em_scalef (v, this->y_scale); }
+ inline hb_position_t em_scale_dir (int16_t v, hb_direction_t direction)
+ { return em_scale (v, dir_scale (direction)); }
/* Convert from parent-font user-space to our user-space */
inline hb_position_t parent_scale_x_distance (hb_position_t v) {
@@ -292,24 +302,32 @@ struct hb_font_t {
/* A bit higher-level, and with fallback */
+ inline void get_h_extents_with_fallback (hb_font_extents_t *extents)
+ {
+ if (!get_font_h_extents (extents))
+ {
+ extents->ascender = y_scale * .8;
+ extents->descender = extents->ascender - y_scale;
+ extents->line_gap = 0;
+ }
+ }
+ inline void get_v_extents_with_fallback (hb_font_extents_t *extents)
+ {
+ if (!get_font_v_extents (extents))
+ {
+ extents->ascender = x_scale / 2;
+ extents->descender = extents->ascender - x_scale;
+ extents->line_gap = 0;
+ }
+ }
+
inline void get_extents_for_direction (hb_direction_t direction,
hb_font_extents_t *extents)
{
- if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) {
- if (!get_font_h_extents (extents))
- {
- extents->ascender = y_scale * .8;
- extents->descender = y_scale - extents->ascender;
- extents->line_gap = 0;
- }
- } else {
- if (!get_font_v_extents (extents))
- {
- extents->ascender = x_scale / 2;
- extents->descender = x_scale - extents->ascender;
- extents->line_gap = 0;
- }
- }
+ if (likely (HB_DIRECTION_IS_HORIZONTAL (direction)))
+ get_h_extents_with_fallback (extents);
+ else
+ get_v_extents_with_fallback (extents);
}
inline void get_glyph_advance_for_direction (hb_codepoint_t glyph,
@@ -325,14 +343,38 @@ struct hb_font_t {
}
}
- /* Internal only */
inline void guess_v_origin_minus_h_origin (hb_codepoint_t glyph,
hb_position_t *x, hb_position_t *y)
{
*x = get_glyph_h_advance (glyph) / 2;
- /* TODO use font_extents.ascender */
- *y = y_scale;
+ /* TODO cache this somehow?! */
+ hb_font_extents_t extents;
+ get_h_extents_with_fallback (&extents);
+ *y = extents.ascender;
+ }
+
+ inline void get_glyph_h_origin_with_fallback (hb_codepoint_t glyph,
+ hb_position_t *x, hb_position_t *y)
+ {
+ if (!get_glyph_h_origin (glyph, x, y) &&
+ get_glyph_v_origin (glyph, x, y))
+ {
+ hb_position_t dx, dy;
+ guess_v_origin_minus_h_origin (glyph, &dx, &dy);
+ *x -= dx; *y -= dy;
+ }
+ }
+ inline void get_glyph_v_origin_with_fallback (hb_codepoint_t glyph,
+ hb_position_t *x, hb_position_t *y)
+ {
+ if (!get_glyph_v_origin (glyph, x, y) &&
+ get_glyph_h_origin (glyph, x, y))
+ {
+ hb_position_t dx, dy;
+ guess_v_origin_minus_h_origin (glyph, &dx, &dy);
+ *x += dx; *y += dy;
+ }
}
inline void get_glyph_origin_for_direction (hb_codepoint_t glyph,
@@ -340,25 +382,9 @@ struct hb_font_t {
hb_position_t *x, hb_position_t *y)
{
if (likely (HB_DIRECTION_IS_HORIZONTAL (direction)))
- {
- if (!get_glyph_h_origin (glyph, x, y) &&
- get_glyph_v_origin (glyph, x, y))
- {
- hb_position_t dx, dy;
- guess_v_origin_minus_h_origin (glyph, &dx, &dy);
- *x -= dx; *y -= dy;
- }
- }
+ get_glyph_h_origin_with_fallback (glyph, x, y);
else
- {
- if (!get_glyph_v_origin (glyph, x, y) &&
- get_glyph_h_origin (glyph, x, y))
- {
- hb_position_t dx, dy;
- guess_v_origin_minus_h_origin (glyph, &dx, &dy);
- *x += dx; *y += dy;
- }
- }
+ get_glyph_v_origin_with_fallback (glyph, x, y);
}
inline void add_glyph_h_origin (hb_codepoint_t glyph,
@@ -366,7 +392,7 @@ struct hb_font_t {
{
hb_position_t origin_x, origin_y;
- get_glyph_h_origin (glyph, &origin_x, &origin_y);
+ get_glyph_h_origin_with_fallback (glyph, &origin_x, &origin_y);
*x += origin_x;
*y += origin_y;
@@ -376,7 +402,7 @@ struct hb_font_t {
{
hb_position_t origin_x, origin_y;
- get_glyph_v_origin (glyph, &origin_x, &origin_y);
+ get_glyph_v_origin_with_fallback (glyph, &origin_x, &origin_y);
*x += origin_x;
*y += origin_y;
@@ -398,7 +424,7 @@ struct hb_font_t {
{
hb_position_t origin_x, origin_y;
- get_glyph_h_origin (glyph, &origin_x, &origin_y);
+ get_glyph_h_origin_with_fallback (glyph, &origin_x, &origin_y);
*x -= origin_x;
*y -= origin_y;
@@ -408,7 +434,7 @@ struct hb_font_t {
{
hb_position_t origin_x, origin_y;
- get_glyph_v_origin (glyph, &origin_x, &origin_y);
+ get_glyph_v_origin_with_fallback (glyph, &origin_x, &origin_y);
*x -= origin_x;
*y -= origin_y;
@@ -504,7 +530,6 @@ struct hb_font_t {
return false;
}
- private:
inline hb_position_t em_scale (int16_t v, int scale)
{
int upem = face->get_upem ();
@@ -512,6 +537,10 @@ struct hb_font_t {
scaled += scaled >= 0 ? upem/2 : -upem/2; /* Round. */
return (hb_position_t) (scaled / upem);
}
+ inline hb_position_t em_scalef (float v, int scale)
+ {
+ return (hb_position_t) (v * scale / face->get_upem ());
+ }
};
#define HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS
diff --git a/src/hb-font.cc b/src/hb-font.cc
index 08fcd6475..ea4550126 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>
/*
@@ -1165,6 +1158,8 @@ hb_font_create_sub_font (hb_font_t *parent)
font->x_ppem = parent->x_ppem;
font->y_ppem = parent->y_ppem;
+ /* TODO: copy variation coordinates. */
+
return font;
}
@@ -1194,6 +1189,9 @@ hb_font_get_empty (void)
0, /* x_ppem */
0, /* y_ppem */
+ 0, /* num_coords */
+ NULL, /* coords */
+
const_cast<hb_font_funcs_t *> (&_hb_font_funcs_nil), /* klass */
NULL, /* user_data */
NULL, /* destroy */
@@ -1248,6 +1246,8 @@ hb_font_destroy (hb_font_t *font)
hb_face_destroy (font->face);
hb_font_funcs_destroy (font->klass);
+ free (font->coords);
+
free (font);
}
@@ -1536,6 +1536,114 @@ hb_font_get_ppem (hb_font_t *font,
if (y_ppem) *y_ppem = font->y_ppem;
}
+/*
+ * Variations
+ */
+
+static void
+_hb_font_adopt_var_coords_normalized (hb_font_t *font,
+ int *coords, /* 2.14 normalized */
+ unsigned int coords_length)
+{
+ 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,
+ const int *coords, /* 2.14 normalized */
+ unsigned int coords_length)
+{
+ if (font->immutable)
+ return;
+
+ int *copy = coords_length ? (int *) calloc (coords_length, sizeof (coords[0])) : NULL;
+ if (unlikely (coords_length && !copy))
+ return;
+
+ if (coords_length)
+ memcpy (copy, coords, coords_length * sizeof (coords[0]));
+
+ _hb_font_adopt_var_coords_normalized (font, copy, coords_length);
+}
+
+/**
+ * hb_font_set_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;
+}
+
#ifndef HB_DISABLE_DEPRECATED
diff --git a/src/hb-font.h b/src/hb-font.h
index 2b6ab5088..e2e59796f 100644
--- a/src/hb-font.h
+++ b/src/hb-font.h
@@ -603,6 +603,24 @@ hb_font_get_ppem (hb_font_t *font,
unsigned int *x_ppem,
unsigned int *y_ppem);
+HB_EXTERN void
+hb_font_set_variations (hb_font_t *font,
+ const hb_variation_t *variations,
+ unsigned int variations_length);
+
+HB_EXTERN void
+hb_font_set_var_coords_design (hb_font_t *font,
+ const float *coords,
+ unsigned int coords_length);
+
+HB_EXTERN void
+hb_font_set_var_coords_normalized (hb_font_t *font,
+ 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
diff --git a/src/hb-ft.cc b/src/hb-ft.cc
index 2b06c59be..48d6a0efb 100644
--- a/src/hb-ft.cc
+++ b/src/hb-ft.cc
@@ -36,6 +36,7 @@
#include "hb-cache-private.hh" // Maybe use in the future?
#include FT_ADVANCES_H
+#include FT_MULTIPLE_MASTERS_H
#include FT_TRUETYPE_TABLES_H
@@ -616,6 +617,28 @@ hb_ft_font_create (FT_Face ft_face,
ft_face->size->metrics.y_ppem);
#endif
+#ifdef HAVE_FT_GET_VAR_BLEND_COORDINATES
+ FT_MM_Var *mm_var = NULL;
+ if (!FT_Get_MM_Var (ft_face, &mm_var))
+ {
+ 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)
+ {
+ 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, coords, mm_var->num_axis);
+ }
+ free (coords);
+ free (ft_coords);
+ }
+ free (mm_var);
+ }
+#endif
+
return font;
}
@@ -718,6 +741,20 @@ hb_ft_font_set_funcs (hb_font_t *font)
FT_Set_Transform (ft_face, &matrix, NULL);
}
+ unsigned int num_coords;
+ const int *coords = hb_font_get_var_coords_normalized (font, &num_coords);
+ if (num_coords)
+ {
+ FT_Fixed *ft_coords = (FT_Fixed *) calloc (num_coords, sizeof (FT_Fixed));
+ if (ft_coords)
+ {
+ for (unsigned int i = 0; i < num_coords; i++)
+ ft_coords[i] = coords[i] << 2;
+ FT_Set_Var_Blend_Coordinates (ft_face, num_coords, ft_coords);
+ free (ft_coords);
+ }
+ }
+
ft_face->generic.data = blob;
ft_face->generic.finalizer = (FT_Generic_Finalizer) _release_blob;
diff --git a/src/hb-glib.cc b/src/hb-glib.cc
index e20352475..2b91b5b65 100644
--- a/src/hb-glib.cc
+++ b/src/hb-glib.cc
@@ -382,6 +382,7 @@ hb_glib_get_unicode_funcs (void)
return const_cast<hb_unicode_funcs_t *> (&_hb_glib_unicode_funcs);
}
+#if GLIB_CHECK_VERSION(2,31,10)
/**
* hb_glib_blob_create:
*
@@ -398,3 +399,4 @@ hb_glib_blob_create (GBytes *gbytes)
g_bytes_ref (gbytes),
(hb_destroy_func_t) g_bytes_unref);
}
+#endif
diff --git a/src/hb-glib.h b/src/hb-glib.h
index 12c3e3b3a..5f04183ba 100644
--- a/src/hb-glib.h
+++ b/src/hb-glib.h
@@ -46,9 +46,10 @@ hb_glib_script_from_script (hb_script_t script);
HB_EXTERN hb_unicode_funcs_t *
hb_glib_get_unicode_funcs (void);
+#if GLIB_CHECK_VERSION(2,31,10)
HB_EXTERN hb_blob_t *
hb_glib_blob_create (GBytes *gbytes);
-
+#endif
HB_END_DECLS
diff --git a/src/hb-gobject-structs.cc b/src/hb-gobject-structs.cc
index 6bd63368b..fef00245b 100644
--- a/src/hb-gobject-structs.cc
+++ b/src/hb-gobject-structs.cc
@@ -78,3 +78,6 @@ HB_DEFINE_VALUE_TYPE (glyph_info)
HB_DEFINE_VALUE_TYPE (glyph_position)
HB_DEFINE_VALUE_TYPE (segment_properties)
HB_DEFINE_VALUE_TYPE (user_data_key)
+
+HB_DEFINE_VALUE_TYPE (ot_math_glyph_variant)
+HB_DEFINE_VALUE_TYPE (ot_math_glyph_part)
diff --git a/src/hb-graphite2.cc b/src/hb-graphite2.cc
index c32318d27..a2d90db87 100644
--- a/src/hb-graphite2.cc
+++ b/src/hb-graphite2.cc
@@ -195,7 +195,9 @@ struct hb_graphite2_shaper_shape_plan_data_t {};
hb_graphite2_shaper_shape_plan_data_t *
_hb_graphite2_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan HB_UNUSED,
const hb_feature_t *user_features HB_UNUSED,
- unsigned int num_user_features HB_UNUSED)
+ unsigned int num_user_features HB_UNUSED,
+ const int *coords HB_UNUSED,
+ unsigned int num_coords HB_UNUSED)
{
return (hb_graphite2_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
}
diff --git a/src/hb-open-file-private.hh b/src/hb-open-file-private.hh
index 5357ddcf5..f208419aa 100644
--- a/src/hb-open-file-private.hh
+++ b/src/hb-open-file-private.hh
@@ -142,7 +142,7 @@ struct TTCHeaderVersion1
Tag ttcTag; /* TrueType Collection ID string: 'ttcf' */
FixedVersion<>version; /* Version of the TTC Header (1.0),
* 0x00010000u */
- ArrayOf<OffsetTo<OffsetTable, ULONG>, ULONG>
+ ArrayOf<LOffsetTo<OffsetTable>, ULONG>
table; /* Array of offsets to the OffsetTable for each font
* from the beginning of the file */
public:
diff --git a/src/hb-open-type-private.hh b/src/hb-open-type-private.hh
index df683ca4b..d90d68c59 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 {
@@ -105,7 +106,7 @@ static inline Type& StructAfter(TObject &X)
inline unsigned int get_size (void) const { return (size); }
#define DEFINE_SIZE_UNION(size, _member) \
- DEFINE_INSTANCE_ASSERTION (this->u._member.static_size == (size)); \
+ DEFINE_INSTANCE_ASSERTION (0*sizeof(this->u._member.static_size) + sizeof(this->u._member) == (size)); \
static const unsigned int min_size = (size)
#define DEFINE_SIZE_MIN(size) \
@@ -650,7 +651,9 @@ struct IntType
DEFINE_SIZE_STATIC (Size);
};
+typedef IntType<int8_t , 1> CHAR; /* 8-bit signed integer. */
typedef IntType<uint8_t , 1> BYTE; /* 8-bit unsigned integer. */
+typedef IntType<int8_t , 1> INT8; /* 8-bit signed integer. */
typedef IntType<uint16_t, 2> USHORT; /* 16-bit unsigned integer. */
typedef IntType<int16_t, 2> SHORT; /* 16-bit signed integer. */
typedef IntType<uint32_t, 4> ULONG; /* 32-bit unsigned integer. */
@@ -805,6 +808,7 @@ struct OffsetTo : Offset<OffsetType>
if (unlikely (!c->check_struct (this))) return_trace (false);
unsigned int offset = *this;
if (unlikely (!offset)) return_trace (true);
+ if (unlikely (!c->check_range (base, offset))) return_trace (false);
const Type &obj = StructAtOffset<Type> (base, offset);
return_trace (likely (obj.sanitize (c)) || neuter (c));
}
@@ -815,6 +819,7 @@ struct OffsetTo : Offset<OffsetType>
if (unlikely (!c->check_struct (this))) return_trace (false);
unsigned int offset = *this;
if (unlikely (!offset)) return_trace (true);
+ if (unlikely (!c->check_range (base, offset))) return_trace (false);
const Type &obj = StructAtOffset<Type> (base, offset);
return_trace (likely (obj.sanitize (c, user_data)) || neuter (c));
}
@@ -825,6 +830,7 @@ struct OffsetTo : Offset<OffsetType>
}
DEFINE_SIZE_STATIC (sizeof(OffsetType));
};
+template <typename Type> struct LOffsetTo : OffsetTo<Type, ULONG> {};
template <typename Base, typename OffsetType, typename Type>
static inline const Type& operator + (const Base &base, const OffsetTo<Type, OffsetType> &offset) { return offset (base); }
template <typename Base, typename OffsetType, typename Type>
@@ -946,10 +952,11 @@ struct ArrayOf
public:
DEFINE_SIZE_ARRAY (sizeof (LenType), array);
};
+template <typename Type> struct LArrayOf : ArrayOf<Type, ULONG> {};
/* Array of Offset's */
-template <typename Type>
-struct OffsetArrayOf : ArrayOf<OffsetTo<Type> > {};
+template <typename Type, typename OffsetType=USHORT>
+struct OffsetArrayOf : ArrayOf<OffsetTo<Type, OffsetType> > {};
/* Array of offsets relative to the beginning of the array itself. */
template <typename Type>
@@ -1057,6 +1064,104 @@ struct SortedArrayOf : ArrayOf<Type, LenType>
};
+/* Lazy struct and blob loaders. */
+
+/* Logic is shared between hb_lazy_loader_t and hb_lazy_table_loader_t */
+template <typename T>
+struct hb_lazy_loader_t
+{
+ inline void init (hb_face_t *face_)
+ {
+ face = face_;
+ instance = NULL;
+ }
+
+ inline void fini (void)
+ {
+ if (instance && instance != &OT::Null(T))
+ {
+ instance->fini();
+ free (instance);
+ }
+ }
+
+ inline const T* get (void) const
+ {
+ retry:
+ T *p = (T *) hb_atomic_ptr_get (&instance);
+ if (unlikely (!p))
+ {
+ p = (T *) calloc (1, sizeof (T));
+ if (unlikely (!p))
+ p = const_cast<T *> (&OT::Null(T));
+ else
+ p->init (face);
+ if (unlikely (!hb_atomic_ptr_cmpexch (const_cast<T **>(&instance), NULL, p)))
+ {
+ if (p != &OT::Null(T))
+ p->fini ();
+ goto retry;
+ }
+ }
+ return p;
+ }
+
+ inline const T* operator-> (void) const
+ {
+ return get ();
+ }
+
+ private:
+ hb_face_t *face;
+ T *instance;
+};
+
+/* Logic is shared between hb_lazy_loader_t and hb_lazy_table_loader_t */
+template <typename T>
+struct hb_lazy_table_loader_t
+{
+ inline void init (hb_face_t *face_)
+ {
+ face = face_;
+ instance = NULL;
+ blob = NULL;
+ }
+
+ inline void fini (void)
+ {
+ hb_blob_destroy (blob);
+ }
+
+ inline const T* get (void) const
+ {
+ retry:
+ T *p = (T *) hb_atomic_ptr_get (&instance);
+ if (unlikely (!p))
+ {
+ hb_blob_t *blob_ = OT::Sanitizer<T>::sanitize (face->reference_table (T::tableTag));
+ p = const_cast<T *>(OT::Sanitizer<T>::lock_instance (blob_));
+ if (!hb_atomic_ptr_cmpexch (const_cast<T **>(&instance), NULL, p))
+ {
+ hb_blob_destroy (blob_);
+ goto retry;
+ }
+ blob = blob_;
+ }
+ return p;
+ }
+
+ inline const T* operator-> (void) const
+ {
+ return get();
+ }
+
+ private:
+ hb_face_t *face;
+ T *instance;
+ mutable hb_blob_t *blob;
+};
+
+
} /* namespace OT */
diff --git a/src/hb-ot-cbdt-table.hh b/src/hb-ot-cbdt-table.hh
new file mode 100644
index 000000000..0a7fbf5b7
--- /dev/null
+++ b/src/hb-ot-cbdt-table.hh
@@ -0,0 +1,384 @@
+/*
+ * Copyright © 2016 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): Seigo Nonaka
+ */
+
+#ifndef HB_OT_CBDT_TABLE_HH
+#define HB_OT_CBDT_TABLE_HH
+
+#include "hb-open-type-private.hh"
+
+namespace OT {
+
+struct SmallGlyphMetrics
+{
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this));
+ }
+
+ inline void get_extents (hb_glyph_extents_t *extents) const
+ {
+ extents->x_bearing = bearingX;
+ extents->y_bearing = bearingY;
+ extents->width = width;
+ extents->height = -height;
+ }
+
+ BYTE height;
+ BYTE width;
+ CHAR bearingX;
+ CHAR bearingY;
+ BYTE advance;
+
+ DEFINE_SIZE_STATIC(5);
+};
+
+struct BigGlyphMetrics : SmallGlyphMetrics
+{
+ CHAR vertBearingX;
+ CHAR vertBearingY;
+ BYTE vertAdvance;
+
+ DEFINE_SIZE_STATIC(8);
+};
+
+struct SBitLineMetrics
+{
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this));
+ }
+
+ CHAR ascender;
+ CHAR decender;
+ BYTE widthMax;
+ CHAR caretSlopeNumerator;
+ CHAR caretSlopeDenominator;
+ CHAR caretOffset;
+ CHAR minOriginSB;
+ CHAR minAdvanceSB;
+ CHAR maxBeforeBL;
+ CHAR minAfterBL;
+ CHAR padding1;
+ CHAR padding2;
+
+ DEFINE_SIZE_STATIC(12);
+};
+
+
+/*
+ * Index Subtables.
+ */
+
+struct IndexSubtableHeader
+{
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this));
+ }
+
+ USHORT indexFormat;
+ USHORT imageFormat;
+ ULONG imageDataOffset;
+
+ DEFINE_SIZE_STATIC(8);
+};
+
+template <typename OffsetType>
+struct IndexSubtableFormat1Or3
+{
+ inline bool sanitize (hb_sanitize_context_t *c, unsigned int glyph_count) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this) &&
+ c->check_array (offsetArrayZ, offsetArrayZ[0].static_size, glyph_count + 1));
+ }
+
+ bool get_image_data (unsigned int idx,
+ unsigned int *offset,
+ unsigned int *length) const
+ {
+ if (unlikely (offsetArrayZ[idx + 1] <= offsetArrayZ[idx]))
+ return false;
+
+ *offset = header.imageDataOffset + offsetArrayZ[idx];
+ *length = offsetArrayZ[idx + 1] - offsetArrayZ[idx];
+ return true;
+ }
+
+ IndexSubtableHeader header;
+ Offset<OffsetType> offsetArrayZ[VAR];
+
+ DEFINE_SIZE_ARRAY(8, offsetArrayZ);
+};
+
+struct IndexSubtableFormat1 : IndexSubtableFormat1Or3<ULONG> {};
+struct IndexSubtableFormat3 : IndexSubtableFormat1Or3<USHORT> {};
+
+struct IndexSubtable
+{
+ inline bool sanitize (hb_sanitize_context_t *c, unsigned int glyph_count) const
+ {
+ TRACE_SANITIZE (this);
+ if (!u.header.sanitize (c)) return_trace (false);
+ switch (u.header.indexFormat) {
+ case 1: return_trace (u.format1.sanitize (c, glyph_count));
+ case 3: return_trace (u.format3.sanitize (c, glyph_count));
+ default:return_trace (true);
+ }
+ }
+
+ inline bool get_extents (hb_glyph_extents_t *extents) const
+ {
+ switch (u.header.indexFormat) {
+ case 2: case 5: /* TODO */
+ case 1: case 3: case 4: /* Variable-metrics formats do not have metrics here. */
+ default:return (false);
+ }
+ }
+
+ bool get_image_data (unsigned int idx,
+ unsigned int *offset,
+ unsigned int *length,
+ unsigned int *format) const
+ {
+ *format = u.header.imageFormat;
+ switch (u.header.indexFormat) {
+ case 1: return u.format1.get_image_data (idx, offset, length);
+ case 3: return u.format3.get_image_data (idx, offset, length);
+ default: return false;
+ }
+ }
+
+ protected:
+ union {
+ IndexSubtableHeader header;
+ IndexSubtableFormat1 format1;
+ IndexSubtableFormat3 format3;
+ /* TODO: Format 2, 4, 5. */
+ } u;
+ public:
+ DEFINE_SIZE_UNION (8, header);
+};
+
+struct IndexSubtableRecord
+{
+ inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this) &&
+ firstGlyphIndex <= lastGlyphIndex &&
+ offsetToSubtable.sanitize (c, this, lastGlyphIndex - firstGlyphIndex + 1));
+ }
+
+ inline bool get_extents (hb_glyph_extents_t *extents) const
+ {
+ return (this+offsetToSubtable).get_extents (extents);
+ }
+
+ bool get_image_data (unsigned int gid,
+ unsigned int *offset,
+ unsigned int *length,
+ unsigned int *format) const
+ {
+ if (gid < firstGlyphIndex || gid > lastGlyphIndex)
+ {
+ return false;
+ }
+ return (this+offsetToSubtable).get_image_data (gid - firstGlyphIndex,
+ offset, length, format);
+ }
+
+ USHORT firstGlyphIndex;
+ USHORT lastGlyphIndex;
+ LOffsetTo<IndexSubtable> offsetToSubtable;
+
+ DEFINE_SIZE_STATIC(8);
+};
+
+struct IndexSubtableArray
+{
+ inline bool sanitize (hb_sanitize_context_t *c, unsigned int count) const
+ {
+ TRACE_SANITIZE (this);
+ if (unlikely (!c->check_array (&indexSubtablesZ, indexSubtablesZ[0].static_size, count)))
+ return_trace (false);
+ for (unsigned int i = 0; i < count; i++)
+ if (unlikely (!indexSubtablesZ[i].sanitize (c, this)))
+ return_trace (false);
+ return_trace (true);
+ }
+
+ public:
+ const IndexSubtableRecord* find_table (hb_codepoint_t glyph, unsigned int numTables) const
+ {
+ for (unsigned int i = 0; i < numTables; ++i)
+ {
+ unsigned int firstGlyphIndex = indexSubtablesZ[i].firstGlyphIndex;
+ unsigned int lastGlyphIndex = indexSubtablesZ[i].lastGlyphIndex;
+ if (firstGlyphIndex <= glyph && glyph <= lastGlyphIndex) {
+ return &indexSubtablesZ[i];
+ }
+ }
+ return NULL;
+ }
+
+ protected:
+ IndexSubtableRecord indexSubtablesZ[VAR];
+
+ public:
+ DEFINE_SIZE_ARRAY(0, indexSubtablesZ);
+};
+
+struct BitmapSizeTable
+{
+ friend struct CBLC;
+
+ inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this) &&
+ indexSubtableArrayOffset.sanitize (c, base, numberOfIndexSubtables) &&
+ c->check_range (&(base+indexSubtableArrayOffset), indexTablesSize) &&
+ horizontal.sanitize (c) &&
+ vertical.sanitize (c));
+ }
+
+ const IndexSubtableRecord *find_table (hb_codepoint_t glyph, const void *base) const
+ {
+ return (base+indexSubtableArrayOffset).find_table (glyph, numberOfIndexSubtables);
+ }
+
+ protected:
+ LOffsetTo<IndexSubtableArray> indexSubtableArrayOffset;
+ ULONG indexTablesSize;
+ ULONG numberOfIndexSubtables;
+ ULONG colorRef;
+ SBitLineMetrics horizontal;
+ SBitLineMetrics vertical;
+ USHORT startGlyphIndex;
+ USHORT endGlyphIndex;
+ BYTE ppemX;
+ BYTE ppemY;
+ BYTE bitDepth;
+ CHAR flags;
+
+public:
+ DEFINE_SIZE_STATIC(48);
+};
+
+
+/*
+ * Glyph Bitmap Data Formats.
+ */
+
+struct GlyphBitmapDataFormat17
+{
+ SmallGlyphMetrics glyphMetrics;
+ ULONG dataLen;
+ BYTE dataZ[VAR];
+
+ DEFINE_SIZE_ARRAY(9, dataZ);
+};
+
+
+/*
+ * CBLC -- Color Bitmap Location Table
+ */
+
+#define HB_OT_TAG_CBLC HB_TAG('C','B','L','C')
+
+struct CBLC
+{
+ static const hb_tag_t tableTag = HB_OT_TAG_CBLC;
+
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this) &&
+ likely (version.major == 2 || version.major == 3) &&
+ sizeTables.sanitize (c, this));
+ }
+
+ public:
+ const IndexSubtableRecord *find_table (hb_codepoint_t glyph,
+ unsigned int *x_ppem, unsigned int *y_ppem) const
+ {
+ /* TODO: Make it possible to select strike. */
+
+ unsigned int count = sizeTables.len;
+ for (uint32_t i = 0; i < count; ++i)
+ {
+ unsigned int startGlyphIndex = sizeTables.array[i].startGlyphIndex;
+ unsigned int endGlyphIndex = sizeTables.array[i].endGlyphIndex;
+ if (startGlyphIndex <= glyph && glyph <= endGlyphIndex)
+ {
+ *x_ppem = sizeTables[i].ppemX;
+ *y_ppem = sizeTables[i].ppemY;
+ return sizeTables[i].find_table (glyph, this);
+ }
+ }
+
+ return NULL;
+ }
+
+ protected:
+ FixedVersion<> version;
+ LArrayOf<BitmapSizeTable> sizeTables;
+
+ public:
+ DEFINE_SIZE_ARRAY(8, sizeTables);
+};
+
+/*
+ * CBDT -- Color Bitmap Data Table
+ */
+#define HB_OT_TAG_CBDT HB_TAG('C','B','D','T')
+
+struct CBDT
+{
+ static const hb_tag_t tableTag = HB_OT_TAG_CBDT;
+
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this) &&
+ likely (version.major == 2 || version.major == 3));
+ }
+
+ protected:
+ FixedVersion<>version;
+ BYTE dataZ[VAR];
+
+ public:
+ DEFINE_SIZE_ARRAY(4, dataZ);
+};
+
+} /* namespace OT */
+
+#endif /* HB_OT_CBDT_TABLE_HH */
diff --git a/src/hb-ot-cmap-table.hh b/src/hb-ot-cmap-table.hh
index d7a94a1ef..3a53a1cb5 100644
--- a/src/hb-ot-cmap-table.hh
+++ b/src/hb-ot-cmap-table.hh
@@ -380,9 +380,9 @@ struct VariationSelectorRecord
}
UINT24 varSelector; /* Variation selector. */
- OffsetTo<DefaultUVS, ULONG>
+ LOffsetTo<DefaultUVS>
defaultUVS; /* Offset to Default UVS Table. May be 0. */
- OffsetTo<NonDefaultUVS, ULONG>
+ LOffsetTo<NonDefaultUVS>
nonDefaultUVS; /* Offset to Non-Default UVS Table. May be 0. */
public:
DEFINE_SIZE_STATIC (11);
@@ -486,7 +486,7 @@ struct EncodingRecord
USHORT platformID; /* Platform ID. */
USHORT encodingID; /* Platform-specific encoding ID. */
- OffsetTo<CmapSubtable, ULONG>
+ LOffsetTo<CmapSubtable>
subtable; /* Byte offset from beginning of table to the subtable for this encoding. */
public:
DEFINE_SIZE_STATIC (8);
diff --git a/src/hb-ot-font.cc b/src/hb-ot-font.cc
index 0b7e31b2d..009db20ae 100644
--- a/src/hb-ot-font.cc
+++ b/src/hb-ot-font.cc
@@ -31,11 +31,13 @@
#include "hb-font-private.hh"
#include "hb-ot-cmap-table.hh"
+#include "hb-ot-cbdt-table.hh"
#include "hb-ot-glyf-table.hh"
#include "hb-ot-head-table.hh"
#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"
@@ -47,16 +49,22 @@ struct hb_ot_face_metrics_accelerator_t
unsigned short ascender;
unsigned short descender;
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 os2_tag)
+ hb_tag_t _var_tag,
+ hb_tag_t os2_tag,
+ unsigned int default_advance = 0)
{
- this->default_advance = face->get_upem ();
+ this->default_advance = default_advance ? default_advance : face->get_upem ();
bool got_font_extents = false;
if (os2_tag)
@@ -82,10 +90,13 @@ struct hb_ot_face_metrics_accelerator_t
this->ascender = _hea->ascender;
this->descender = _hea->descender;
this->line_gap = _hea->lineGap;
+ got_font_extents = (this->ascender | this->descender) != 0;
}
hb_blob_destroy (_hea_blob);
- this->blob = OT::Sanitizer<OT::_mtx>::sanitize (face->reference_table (_mtx_tag));
+ this->has_font_extents = got_font_extents;
+
+ 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);
@@ -101,15 +112,20 @@ struct hb_ot_face_metrics_accelerator_t
hb_blob_destroy (this->blob);
this->blob = hb_blob_get_empty ();
}
- this->table = OT::Sanitizer<OT::_mtx>::lock_instance (this->blob);
+ this->table = OT::Sanitizer<OT::hmtxvmtx>::lock_instance (this->blob);
+
+ this->var_blob = OT::Sanitizer<OT::HVARVVAR>::sanitize (face->reference_table (_var_tag));
+ this->var = OT::Sanitizer<OT::HVARVVAR>::lock_instance (this->var_blob);
}
inline void fini (void)
{
hb_blob_destroy (this->blob);
+ hb_blob_destroy (this->var_blob);
}
- inline unsigned int get_advance (hb_codepoint_t glyph) const
+ inline unsigned int get_advance (hb_codepoint_t glyph,
+ hb_font_t *font) const
{
if (unlikely (glyph >= this->num_metrics))
{
@@ -122,10 +138,8 @@ struct hb_ot_face_metrics_accelerator_t
return this->default_advance;
}
- if (glyph >= this->num_advances)
- glyph = this->num_advances - 1;
-
- return this->table->longMetric[glyph].advance;
+ return this->table->longMetric[MIN (glyph, this->num_advances - 1)].advance
+ + this->var->get_advance_var (glyph, font->coords, font->num_coords); // TODO Optimize?!
}
};
@@ -202,6 +216,91 @@ struct hb_ot_face_glyf_accelerator_t
}
};
+struct hb_ot_face_cbdt_accelerator_t
+{
+ hb_blob_t *cblc_blob;
+ hb_blob_t *cbdt_blob;
+ const OT::CBLC *cblc;
+ const OT::CBDT *cbdt;
+
+ unsigned int cbdt_len;
+ float upem;
+
+ inline void init (hb_face_t *face)
+ {
+ upem = face->get_upem();
+
+ cblc_blob = OT::Sanitizer<OT::CBLC>::sanitize (face->reference_table (HB_OT_TAG_CBLC));
+ cbdt_blob = OT::Sanitizer<OT::CBDT>::sanitize (face->reference_table (HB_OT_TAG_CBDT));
+ cbdt_len = hb_blob_get_length (cbdt_blob);
+
+ if (hb_blob_get_length (cblc_blob) == 0) {
+ cblc = NULL;
+ cbdt = NULL;
+ return; /* Not a bitmap font. */
+ }
+ cblc = OT::Sanitizer<OT::CBLC>::lock_instance (cblc_blob);
+ cbdt = OT::Sanitizer<OT::CBDT>::lock_instance (cbdt_blob);
+
+ }
+
+ inline void fini (void)
+ {
+ hb_blob_destroy (this->cblc_blob);
+ hb_blob_destroy (this->cbdt_blob);
+ }
+
+ inline bool get_extents (hb_codepoint_t glyph, hb_glyph_extents_t *extents) const
+ {
+ unsigned int x_ppem = upem, y_ppem = upem; /* TODO Use font ppem if available. */
+
+ if (cblc == NULL)
+ return false; // Not a color bitmap font.
+
+ const OT::IndexSubtableRecord *subtable_record = this->cblc->find_table(glyph, &x_ppem, &y_ppem);
+ if (subtable_record == NULL)
+ return false;
+
+ if (subtable_record->get_extents (extents))
+ return true;
+
+ unsigned int image_offset = 0, image_length = 0, image_format = 0;
+ if (!subtable_record->get_image_data (glyph, &image_offset, &image_length, &image_format))
+ return false;
+
+ {
+ /* TODO Move the following into CBDT struct when adding more formats. */
+
+ if (unlikely (image_offset > cbdt_len || cbdt_len - image_offset < image_length))
+ return false;
+
+ switch (image_format)
+ {
+ case 17: {
+ if (unlikely (image_length < OT::GlyphBitmapDataFormat17::min_size))
+ return false;
+
+ const OT::GlyphBitmapDataFormat17& glyphFormat17 =
+ OT::StructAtOffset<OT::GlyphBitmapDataFormat17> (this->cbdt, image_offset);
+ glyphFormat17.glyphMetrics.get_extents (extents);
+ }
+ break;
+ default:
+ // TODO: Support other image formats.
+ return false;
+ }
+ }
+
+ /* Convert to the font units. */
+ extents->x_bearing *= upem / (float) x_ppem;
+ extents->y_bearing *= upem / (float) y_ppem;
+ extents->width *= upem / (float) x_ppem;
+ extents->height *= upem / (float) y_ppem;
+
+ return true;
+ }
+};
+
typedef bool (*hb_cmap_get_glyph_func_t) (const void *obj,
hb_codepoint_t codepoint,
hb_codepoint_t *glyph);
@@ -264,7 +363,11 @@ struct hb_ot_face_cmap_accelerator_t
if (!subtable) subtable = cmap->find_subtable (0, 2);
if (!subtable) subtable = cmap->find_subtable (0, 1);
if (!subtable) subtable = cmap->find_subtable (0, 0);
- if (!subtable)(subtable = cmap->find_subtable (3, 0)) && (symbol = true);
+ if (!subtable)
+ {
+ subtable = cmap->find_subtable (3, 0);
+ if (subtable) symbol = true;
+ }
/* Meh. */
if (!subtable) subtable = &OT::Null(OT::CmapSubtable);
@@ -326,54 +429,13 @@ struct hb_ot_face_cmap_accelerator_t
}
};
-template <typename T>
-struct hb_lazy_loader_t
-{
- inline void init (hb_face_t *face_)
- {
- face = face_;
- instance = NULL;
- }
-
- inline void fini (void)
- {
- if (instance && instance != &OT::Null(T))
- {
- instance->fini();
- free (instance);
- }
- }
-
- inline const T* operator-> (void) const
- {
- retry:
- T *p = (T *) hb_atomic_ptr_get (&instance);
- if (unlikely (!p))
- {
- p = (T *) calloc (1, sizeof (T));
- if (unlikely (!p))
- return &OT::Null(T);
- p->init (face);
- if (unlikely (!hb_atomic_ptr_cmpexch (const_cast<T **>(&instance), NULL, p)))
- {
- p->fini ();
- goto retry;
- }
- }
- return p;
- }
-
- private:
- hb_face_t *face;
- T *instance;
-};
-
struct hb_ot_font_t
{
hb_ot_face_cmap_accelerator_t cmap;
hb_ot_face_metrics_accelerator_t h_metrics;
hb_ot_face_metrics_accelerator_t v_metrics;
- hb_lazy_loader_t<hb_ot_face_glyf_accelerator_t> glyf;
+ OT::hb_lazy_loader_t<hb_ot_face_glyf_accelerator_t> glyf;
+ OT::hb_lazy_loader_t<hb_ot_face_cbdt_accelerator_t> cbdt;
};
@@ -386,9 +448,11 @@ _hb_ot_font_create (hb_face_t *face)
return NULL;
ot_font->cmap.init (face);
- ot_font->h_metrics.init (face, HB_OT_TAG_hhea, HB_OT_TAG_hmtx, HB_OT_TAG_os2);
- ot_font->v_metrics.init (face, HB_OT_TAG_vhea, HB_OT_TAG_vmtx, HB_TAG_NONE); /* TODO Can we do this lazily? */
+ 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);
return ot_font;
}
@@ -400,6 +464,7 @@ _hb_ot_font_destroy (hb_ot_font_t *ot_font)
ot_font->h_metrics.fini ();
ot_font->v_metrics.fini ();
ot_font->glyf.fini ();
+ ot_font->cbdt.fini ();
free (ot_font);
}
@@ -430,23 +495,23 @@ hb_ot_get_variation_glyph (hb_font_t *font HB_UNUSED,
}
static hb_position_t
-hb_ot_get_glyph_h_advance (hb_font_t *font HB_UNUSED,
+hb_ot_get_glyph_h_advance (hb_font_t *font,
void *font_data,
hb_codepoint_t glyph,
void *user_data HB_UNUSED)
{
const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
- return font->em_scale_x (ot_font->h_metrics.get_advance (glyph));
+ return font->em_scale_x (ot_font->h_metrics.get_advance (glyph, font));
}
static hb_position_t
-hb_ot_get_glyph_v_advance (hb_font_t *font HB_UNUSED,
+hb_ot_get_glyph_v_advance (hb_font_t *font,
void *font_data,
hb_codepoint_t glyph,
void *user_data HB_UNUSED)
{
const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
- return font->em_scale_y (-(int) ot_font->v_metrics.get_advance (glyph));
+ return font->em_scale_y (-(int) ot_font->v_metrics.get_advance (glyph, font));
}
static hb_bool_t
@@ -458,6 +523,9 @@ hb_ot_get_glyph_extents (hb_font_t *font HB_UNUSED,
{
const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
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);
@@ -475,7 +543,8 @@ hb_ot_get_font_h_extents (hb_font_t *font HB_UNUSED,
metrics->ascender = font->em_scale_y (ot_font->h_metrics.ascender);
metrics->descender = font->em_scale_y (ot_font->h_metrics.descender);
metrics->line_gap = font->em_scale_y (ot_font->h_metrics.line_gap);
- return true;
+ // TODO Hook up variations.
+ return ot_font->h_metrics.has_font_extents;
}
static hb_bool_t
@@ -488,7 +557,8 @@ hb_ot_get_font_v_extents (hb_font_t *font HB_UNUSED,
metrics->ascender = font->em_scale_x (ot_font->v_metrics.ascender);
metrics->descender = font->em_scale_x (ot_font->v_metrics.descender);
metrics->line_gap = font->em_scale_x (ot_font->v_metrics.line_gap);
- return true;
+ // TODO Hook up variations.
+ return ot_font->v_metrics.has_font_extents;
}
static hb_font_funcs_t *static_ot_funcs = NULL;
diff --git a/src/hb-ot-hmtx-table.hh b/src/hb-ot-hmtx-table.hh
index a9606b3d2..30aa62534 100644
--- a/src/hb-ot-hmtx-table.hh
+++ b/src/hb-ot-hmtx-table.hh
@@ -50,10 +50,8 @@ struct LongMetric
DEFINE_SIZE_STATIC (4);
};
-struct _mtx
+struct hmtxvmtx
{
- static const hb_tag_t tableTag = HB_TAG('_','m','t','x');
-
static const hb_tag_t hmtxTag = HB_OT_TAG_hmtx;
static const hb_tag_t vmtxTag = HB_OT_TAG_vmtx;
@@ -91,10 +89,10 @@ struct _mtx
DEFINE_SIZE_ARRAY2 (0, longMetric, leadingBearingX);
};
-struct hmtx : _mtx {
+struct hmtx : hmtxvmtx {
static const hb_tag_t tableTag = HB_OT_TAG_hmtx;
};
-struct vmtx : _mtx {
+struct vmtx : hmtxvmtx {
static const hb_tag_t tableTag = HB_OT_TAG_vmtx;
};
diff --git a/src/hb-ot-layout-common-private.hh b/src/hb-ot-layout-common-private.hh
index 34fa1b773..180e5f086 100644
--- a/src/hb-ot-layout-common-private.hh
+++ b/src/hb-ot-layout-common-private.hh
@@ -507,7 +507,7 @@ struct Feature
{ return this+featureParams; }
inline bool sanitize (hb_sanitize_context_t *c,
- const Record<Feature>::sanitize_closure_t *closure) const
+ const Record<Feature>::sanitize_closure_t *closure = NULL) const
{
TRACE_SANITIZE (this);
if (unlikely (!(c->check_struct (this) && lookupIndex.sanitize (c))))
@@ -731,8 +731,8 @@ struct CoverageFormat1
inline void init (const struct CoverageFormat1 &c_) { c = &c_; i = 0; };
inline bool more (void) { return i < c->glyphArray.len; }
inline void next (void) { i++; }
- inline uint16_t get_glyph (void) { return c->glyphArray[i]; }
- inline uint16_t get_coverage (void) { return i; }
+ inline hb_codepoint_t get_glyph (void) { return c->glyphArray[i]; }
+ inline unsigned int get_coverage (void) { return i; }
private:
const struct CoverageFormat1 *c;
@@ -829,26 +829,33 @@ struct CoverageFormat2
public:
/* Older compilers need this to be public. */
- struct Iter {
- inline void init (const CoverageFormat2 &c_) {
+ struct Iter
+ {
+ inline void init (const CoverageFormat2 &c_)
+ {
c = &c_;
coverage = 0;
i = 0;
j = c->rangeRecord.len ? c_.rangeRecord[0].start : 0;
}
inline bool more (void) { return i < c->rangeRecord.len; }
- inline void next (void) {
- coverage++;
- if (j == c->rangeRecord[i].end) {
+ inline void next (void)
+ {
+ if (j >= c->rangeRecord[i].end)
+ {
i++;
if (more ())
+ {
j = c->rangeRecord[i].start;
+ coverage = c->rangeRecord[i].value;
+ }
return;
}
+ coverage++;
j++;
}
- inline uint16_t get_glyph (void) { return j; }
- inline uint16_t get_coverage (void) { return coverage; }
+ inline hb_codepoint_t get_glyph (void) { return j; }
+ inline unsigned int get_coverage (void) { return coverage; }
private:
const struct CoverageFormat2 *c;
@@ -957,14 +964,14 @@ struct Coverage
default: break;
}
}
- inline uint16_t get_glyph (void) {
+ inline hb_codepoint_t get_glyph (void) {
switch (format) {
case 1: return u.format1.get_glyph ();
case 2: return u.format2.get_glyph ();
default:return 0;
}
}
- inline uint16_t get_coverage (void) {
+ inline unsigned int get_coverage (void) {
switch (format) {
case 1: return u.format1.get_coverage ();
case 2: return u.format2.get_coverage ();
@@ -1162,11 +1169,388 @@ struct ClassDef
/*
+ * Item Variation Store
+ */
+
+struct VarRegionAxis
+{
+ inline float evaluate (int coord) const
+ {
+ int start = startCoord, peak = peakCoord, end = endCoord;
+
+ /* TODO Move these to sanitize(). */
+ if (unlikely (start > peak || peak > end))
+ return 1.;
+ if (unlikely (start < 0 && end > 0 && peak != 0))
+ return 1.;
+
+ if (peak == 0 || coord == peak)
+ return 1.;
+
+ if (coord <= start || end <= coord)
+ return 0.;
+
+ /* Interpolate */
+ if (coord < peak)
+ return float (coord - start) / (peak - start);
+ else
+ return float (end - coord) / (end - peak);
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this));
+ /* TODO Handle invalid start/peak/end configs, so we don't
+ * have to do that at runtime. */
+ }
+
+ public:
+ F2DOT14 startCoord;
+ F2DOT14 peakCoord;
+ F2DOT14 endCoord;
+ public:
+ DEFINE_SIZE_STATIC (6);
+};
+
+struct VarRegionList
+{
+ inline float evaluate (unsigned int region_index,
+ int *coords, unsigned int coord_len) const
+ {
+ if (unlikely (region_index >= regionCount))
+ return 0.;
+
+ const VarRegionAxis *axes = axesZ + (region_index * axisCount);
+
+ float v = 1.;
+ unsigned int count = MIN (coord_len, (unsigned int) axisCount);
+ for (unsigned int i = 0; i < count; i++)
+ {
+ float factor = axes[i].evaluate (coords[i]);
+ if (factor == 0.)
+ return 0.;
+ v *= factor;
+ }
+ return v;
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this) &&
+ c->check_array (axesZ, axesZ[0].static_size,
+ (unsigned int) axisCount * (unsigned int) regionCount));
+ }
+
+ protected:
+ USHORT axisCount;
+ USHORT regionCount;
+ VarRegionAxis axesZ[VAR];
+ public:
+ DEFINE_SIZE_ARRAY (4, axesZ);
+};
+
+struct VarData
+{
+ inline unsigned int get_row_size (void) const
+ { return shortCount + regionIndices.len; }
+
+ inline unsigned int get_size (void) const
+ { return itemCount * get_row_size (); }
+
+ inline float get_delta (unsigned int inner,
+ int *coords, unsigned int coord_count,
+ const VarRegionList &regions) const
+ {
+ if (unlikely (inner >= itemCount))
+ return 0.;
+
+ unsigned int count = regionIndices.len;
+ unsigned int scount = shortCount;
+
+ const BYTE *bytes = &StructAfter<BYTE> (regionIndices);
+ const BYTE *row = bytes + inner * (scount + count);
+
+ float delta = 0.;
+ unsigned int i = 0;
+
+ const SHORT *scursor = reinterpret_cast<const SHORT *> (row);
+ for (; i < scount; i++)
+ {
+ float scalar = regions.evaluate (regionIndices.array[i], coords, coord_count);
+ delta += scalar * *scursor++;
+ }
+ const INT8 *bcursor = reinterpret_cast<const INT8 *> (scursor);
+ for (; i < count; i++)
+ {
+ float scalar = regions.evaluate (regionIndices.array[i], coords, coord_count);
+ delta += scalar * *bcursor++;
+ }
+
+ return delta;
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this) &&
+ regionIndices.sanitize(c) &&
+ shortCount <= regionIndices.len &&
+ c->check_array (&StructAfter<BYTE> (regionIndices),
+ get_row_size (), itemCount));
+ }
+
+ protected:
+ USHORT itemCount;
+ USHORT shortCount;
+ ArrayOf<USHORT> regionIndices;
+ BYTE bytesX[VAR];
+ public:
+ DEFINE_SIZE_ARRAY2 (6, regionIndices, bytesX);
+};
+
+struct VariationStore
+{
+ inline float get_delta (unsigned int outer, unsigned int inner,
+ int *coords, unsigned int coord_count) const
+ {
+ if (unlikely (outer >= dataSets.len))
+ return 0.;
+
+ return (this+dataSets[outer]).get_delta (inner,
+ coords, coord_count,
+ 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);
+ return_trace (c->check_struct (this) &&
+ format == 1 &&
+ regions.sanitize (c, this) &&
+ dataSets.sanitize (c, this));
+ }
+
+ protected:
+ USHORT format;
+ LOffsetTo<VarRegionList> regions;
+ OffsetArrayOf<VarData, ULONG> dataSets;
+ public:
+ DEFINE_SIZE_ARRAY (8, dataSets);
+};
+
+/*
+ * Feature Variations
+ */
+
+struct ConditionFormat1
+{
+ friend struct Condition;
+
+ private:
+ inline bool evaluate (const int *coords, unsigned int coord_len) const
+ {
+ int coord = axisIndex < coord_len ? coords[axisIndex] : 0;
+ return filterRangeMinValue <= coord && coord <= filterRangeMaxValue;
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this));
+ }
+
+ protected:
+ USHORT format; /* Format identifier--format = 1 */
+ USHORT axisIndex;
+ F2DOT14 filterRangeMinValue;
+ F2DOT14 filterRangeMaxValue;
+ public:
+ DEFINE_SIZE_STATIC (8);
+};
+
+struct Condition
+{
+ inline bool evaluate (const int *coords, unsigned int coord_len) const
+ {
+ switch (u.format) {
+ case 1: return u.format1.evaluate (coords, coord_len);
+ default:return false;
+ }
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ if (!u.format.sanitize (c)) return_trace (false);
+ switch (u.format) {
+ case 1: return_trace (u.format1.sanitize (c));
+ default:return_trace (true);
+ }
+ }
+
+ protected:
+ union {
+ USHORT format; /* Format identifier */
+ ConditionFormat1 format1;
+ } u;
+ public:
+ DEFINE_SIZE_UNION (2, format);
+};
+
+struct ConditionSet
+{
+ inline bool evaluate (const int *coords, unsigned int coord_len) const
+ {
+ unsigned int count = conditions.len;
+ for (unsigned int i = 0; i < count; i++)
+ if (!(this+conditions.array[i]).evaluate (coords, coord_len))
+ return false;
+ return true;
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (conditions.sanitize (c, this));
+ }
+
+ protected:
+ OffsetArrayOf<Condition, ULONG> conditions;
+ public:
+ DEFINE_SIZE_ARRAY (2, conditions);
+};
+
+struct FeatureTableSubstitutionRecord
+{
+ friend struct FeatureTableSubstitution;
+
+ inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this) && feature.sanitize (c, base));
+ }
+
+ protected:
+ USHORT featureIndex;
+ LOffsetTo<Feature> feature;
+ public:
+ DEFINE_SIZE_STATIC (6);
+};
+
+struct FeatureTableSubstitution
+{
+ inline const Feature *find_substitute (unsigned int feature_index) const
+ {
+ unsigned int count = substitutions.len;
+ for (unsigned int i = 0; i < count; i++)
+ {
+ const FeatureTableSubstitutionRecord &record = substitutions.array[i];
+ if (record.featureIndex == feature_index)
+ return &(this+record.feature);
+ }
+ return NULL;
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (version.sanitize (c) &&
+ likely (version.major == 1) &&
+ substitutions.sanitize (c, this));
+ }
+
+ protected:
+ FixedVersion<> version; /* Version--0x00010000u */
+ ArrayOf<FeatureTableSubstitutionRecord>
+ substitutions;
+ public:
+ DEFINE_SIZE_ARRAY (6, substitutions);
+};
+
+struct FeatureVariationRecord
+{
+ friend struct FeatureVariations;
+
+ inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (conditions.sanitize (c, base) &&
+ substitutions.sanitize (c, base));
+ }
+
+ protected:
+ LOffsetTo<ConditionSet>
+ conditions;
+ LOffsetTo<FeatureTableSubstitution>
+ substitutions;
+ public:
+ DEFINE_SIZE_STATIC (8);
+};
+
+struct FeatureVariations
+{
+ static const unsigned int NOT_FOUND_INDEX = 0xFFFFFFFFu;
+
+ inline bool find_index (const int *coords, unsigned int coord_len,
+ unsigned int *index) const
+ {
+ unsigned int count = varRecords.len;
+ for (unsigned int i = 0; i < count; i++)
+ {
+ const FeatureVariationRecord &record = varRecords.array[i];
+ if ((this+record.conditions).evaluate (coords, coord_len))
+ {
+ *index = i;
+ return true;
+ }
+ }
+ *index = NOT_FOUND_INDEX;
+ return false;
+ }
+
+ inline const Feature *find_substitute (unsigned int variations_index,
+ unsigned int feature_index) const
+ {
+ const FeatureVariationRecord &record = varRecords[variations_index];
+ return (this+record.substitutions).find_substitute (feature_index);
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (version.sanitize (c) &&
+ likely (version.major == 1) &&
+ varRecords.sanitize (c, this));
+ }
+
+ protected:
+ FixedVersion<> version; /* Version--0x00010000u */
+ LArrayOf<FeatureVariationRecord>
+ varRecords;
+ public:
+ DEFINE_SIZE_ARRAY (8, varRecords);
+};
+
+
+/*
* Device Tables
*/
-struct Device
+struct HintingDevice
{
+ friend struct Device;
+
+ private:
inline hb_position_t get_x_delta (hb_font_t *font) const
{ return get_delta (font->x_ppem, font->x_scale); }
@@ -1235,6 +1619,101 @@ struct Device
DEFINE_SIZE_ARRAY (6, deltaValue);
};
+struct VariationDevice
+{
+ friend struct Device;
+
+ private:
+
+ inline hb_position_t get_x_delta (hb_font_t *font, const VariationStore &store) const
+ { return font->em_scalef_x (get_delta (font, store)); }
+
+ inline hb_position_t get_y_delta (hb_font_t *font, const VariationStore &store) const
+ { return font->em_scalef_y (get_delta (font, store)); }
+
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this));
+ }
+
+ private:
+
+ inline float get_delta (hb_font_t *font, const VariationStore &store) const
+ {
+ return store.get_delta (outerIndex, innerIndex, font->coords, font->num_coords);
+ }
+
+ protected:
+ USHORT outerIndex;
+ USHORT innerIndex;
+ USHORT deltaFormat; /* Format identifier for this table: 0x0x8000 */
+ public:
+ DEFINE_SIZE_STATIC (6);
+};
+
+struct DeviceHeader
+{
+ protected:
+ USHORT reserved1;
+ USHORT reserved2;
+ public:
+ USHORT format; /* Format identifier */
+ public:
+ DEFINE_SIZE_STATIC (6);
+};
+
+struct Device
+{
+ inline hb_position_t get_x_delta (hb_font_t *font, const VariationStore &store=Null(VariationStore)) const
+ {
+ switch (u.b.format)
+ {
+ case 1: case 2: case 3:
+ return u.hinting.get_x_delta (font);
+ case 0x8000:
+ return u.variation.get_x_delta (font, store);
+ default:
+ return 0;
+ }
+ }
+ inline hb_position_t get_y_delta (hb_font_t *font, const VariationStore &store=Null(VariationStore)) const
+ {
+ switch (u.b.format)
+ {
+ case 1: case 2: case 3:
+ return u.hinting.get_y_delta (font);
+ case 0x8000:
+ return u.variation.get_y_delta (font, store);
+ default:
+ return 0;
+ }
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ if (!u.b.format.sanitize (c)) return_trace (false);
+ switch (u.b.format) {
+ case 1: case 2: case 3:
+ return_trace (u.hinting.sanitize (c));
+ case 0x8000:
+ return_trace (u.variation.sanitize (c));
+ default:
+ return_trace (true);
+ }
+ }
+
+ protected:
+ union {
+ DeviceHeader b;
+ HintingDevice hinting;
+ VariationDevice variation;
+ } u;
+ public:
+ DEFINE_SIZE_UNION (6, b);
+};
+
} /* namespace OT */
diff --git a/src/hb-ot-layout-gdef-table.hh b/src/hb-ot-layout-gdef-table.hh
index 2b4bc5a02..552df0fd8 100644
--- a/src/hb-ot-layout-gdef-table.hh
+++ b/src/hb-ot-layout-gdef-table.hh
@@ -97,7 +97,7 @@ struct CaretValueFormat1
friend struct CaretValue;
private:
- inline hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction, hb_codepoint_t glyph_id HB_UNUSED) const
+ inline hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction) const
{
return HB_DIRECTION_IS_HORIZONTAL (direction) ? font->em_scale_x (coordinate) : font->em_scale_y (coordinate);
}
@@ -146,11 +146,11 @@ struct CaretValueFormat3
{
friend struct CaretValue;
- inline hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction, hb_codepoint_t glyph_id HB_UNUSED) const
+ inline hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction, const VariationStore &var_store) const
{
return HB_DIRECTION_IS_HORIZONTAL (direction) ?
- font->em_scale_x (coordinate) + (this+deviceTable).get_x_delta (font) :
- font->em_scale_y (coordinate) + (this+deviceTable).get_y_delta (font);
+ font->em_scale_x (coordinate) + (this+deviceTable).get_x_delta (font, var_store) :
+ font->em_scale_y (coordinate) + (this+deviceTable).get_y_delta (font, var_store);
}
inline bool sanitize (hb_sanitize_context_t *c) const
@@ -172,12 +172,15 @@ struct CaretValueFormat3
struct CaretValue
{
- inline hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction, hb_codepoint_t glyph_id) const
+ inline hb_position_t get_caret_value (hb_font_t *font,
+ hb_direction_t direction,
+ hb_codepoint_t glyph_id,
+ const VariationStore &var_store) const
{
switch (u.format) {
- case 1: return u.format1.get_caret_value (font, direction, glyph_id);
+ case 1: return u.format1.get_caret_value (font, direction);
case 2: return u.format2.get_caret_value (font, direction, glyph_id);
- case 3: return u.format3.get_caret_value (font, direction, glyph_id);
+ case 3: return u.format3.get_caret_value (font, direction, var_store);
default:return 0;
}
}
@@ -210,6 +213,7 @@ struct LigGlyph
inline unsigned int get_lig_carets (hb_font_t *font,
hb_direction_t direction,
hb_codepoint_t glyph_id,
+ const VariationStore &var_store,
unsigned int start_offset,
unsigned int *caret_count /* IN/OUT */,
hb_position_t *caret_array /* OUT */) const
@@ -218,7 +222,7 @@ struct LigGlyph
const OffsetTo<CaretValue> *array = carets.sub_array (start_offset, caret_count);
unsigned int count = *caret_count;
for (unsigned int i = 0; i < count; i++)
- caret_array[i] = (this+array[i]).get_caret_value (font, direction, glyph_id);
+ caret_array[i] = (this+array[i]).get_caret_value (font, direction, glyph_id, var_store);
}
return carets.len;
@@ -244,6 +248,7 @@ struct LigCaretList
inline unsigned int get_lig_carets (hb_font_t *font,
hb_direction_t direction,
hb_codepoint_t glyph_id,
+ const VariationStore &var_store,
unsigned int start_offset,
unsigned int *caret_count /* IN/OUT */,
hb_position_t *caret_array /* OUT */) const
@@ -256,7 +261,7 @@ struct LigCaretList
return 0;
}
const LigGlyph &lig_glyph = this+ligGlyph[index];
- return lig_glyph.get_lig_carets (font, direction, glyph_id, start_offset, caret_count, caret_array);
+ return lig_glyph.get_lig_carets (font, direction, glyph_id, var_store, start_offset, caret_count, caret_array);
}
inline bool sanitize (hb_sanitize_context_t *c) const
@@ -290,7 +295,7 @@ struct MarkGlyphSetsFormat1
protected:
USHORT format; /* Format identifier--format = 1 */
- ArrayOf<OffsetTo<Coverage, ULONG> >
+ ArrayOf<LOffsetTo<Coverage> >
coverage; /* Array of long offsets to mark set
* coverage tables */
public:
@@ -367,11 +372,17 @@ struct GDEF
unsigned int start_offset,
unsigned int *caret_count /* IN/OUT */,
hb_position_t *caret_array /* OUT */) const
- { return (this+ligCaretList).get_lig_carets (font, direction, glyph_id, start_offset, caret_count, caret_array); }
+ { return (this+ligCaretList).get_lig_carets (font,
+ direction, glyph_id, get_var_store(),
+ start_offset, caret_count, caret_array); }
- inline bool has_mark_sets (void) const { return version.to_int () >= 0x00010002u && markGlyphSetsDef[0] != 0; }
+ inline bool has_mark_sets (void) const { return version.to_int () >= 0x00010002u && markGlyphSetsDef != 0; }
inline bool mark_set_covers (unsigned int set_index, hb_codepoint_t glyph_id) const
- { return version.to_int () >= 0x00010002u && (this+markGlyphSetsDef[0]).covers (set_index, glyph_id); }
+ { return version.to_int () >= 0x00010002u && (this+markGlyphSetsDef).covers (set_index, glyph_id); }
+
+ inline bool has_var_store (void) const { return version.to_int () >= 0x00010003u && varStore != 0; }
+ inline const VariationStore &get_var_store (void) const
+ { return version.to_int () >= 0x00010003u ? this+varStore : Null(VariationStore); }
inline bool sanitize (hb_sanitize_context_t *c) const
{
@@ -382,10 +393,10 @@ struct GDEF
attachList.sanitize (c, this) &&
ligCaretList.sanitize (c, this) &&
markAttachClassDef.sanitize (c, this) &&
- (version.to_int () < 0x00010002u || markGlyphSetsDef[0].sanitize (c, this)));
+ (version.to_int () < 0x00010002u || markGlyphSetsDef.sanitize (c, this)) &&
+ (version.to_int () < 0x00010003u || varStore.sanitize (c, this)));
}
-
/* glyph_props is a 16-bit integer where the lower 8-bit have bits representing
* glyph class and other bits, and high 8-bit gthe mark attachment type (if any).
* Not to be confused with lookup_props which is very similar. */
@@ -410,7 +421,7 @@ struct GDEF
protected:
FixedVersion<>version; /* Version of the GDEF table--currently
- * 0x00010002u */
+ * 0x00010003u */
OffsetTo<ClassDef>
glyphClassDef; /* Offset to class definition table
* for glyph type--from beginning of
@@ -428,12 +439,17 @@ struct GDEF
* mark attachment type--from beginning
* of GDEF header (may be Null) */
OffsetTo<MarkGlyphSets>
- markGlyphSetsDef[VAR]; /* Offset to the table of mark set
+ markGlyphSetsDef; /* Offset to the table of mark set
* definitions--from beginning of GDEF
* header (may be NULL). Introduced
- * in version 00010002. */
+ * in version 0x00010002. */
+ LOffsetTo<VariationStore>
+ varStore; /* Offset to the table of Item Variation
+ * Store--from beginning of GDEF
+ * header (may be NULL). Introduced
+ * in version 0x00010003. */
public:
- DEFINE_SIZE_ARRAY (12, markGlyphSetsDef);
+ DEFINE_SIZE_MIN (12);
};
diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh
index bbe390cf7..952fd60fe 100644
--- a/src/hb-ot-layout-gpos-table.hh
+++ b/src/hb-ot-layout-gpos-table.hh
@@ -103,18 +103,17 @@ struct ValueFormat : USHORT
inline unsigned int get_size (void) const
{ return get_len () * Value::static_size; }
- void apply_value (hb_font_t *font,
- hb_direction_t direction,
+ void apply_value (hb_apply_context_t *c,
const void *base,
const Value *values,
hb_glyph_position_t &glyph_pos) const
{
- unsigned int x_ppem, y_ppem;
unsigned int format = *this;
- hb_bool_t horizontal = HB_DIRECTION_IS_HORIZONTAL (direction);
-
if (!format) return;
+ hb_font_t *font = c->font;
+ hb_bool_t horizontal = HB_DIRECTION_IS_HORIZONTAL (c->direction);
+
if (format & xPlacement) glyph_pos.x_offset += font->em_scale_x (get_short (values++));
if (format & yPlacement) glyph_pos.y_offset += font->em_scale_y (get_short (values++));
if (format & xAdvance) {
@@ -129,27 +128,29 @@ struct ValueFormat : USHORT
if (!has_device ()) return;
- x_ppem = font->x_ppem;
- y_ppem = font->y_ppem;
+ bool use_x_device = font->x_ppem || font->num_coords;
+ bool use_y_device = font->y_ppem || font->num_coords;
- if (!x_ppem && !y_ppem) return;
+ if (!use_x_device && !use_y_device) return;
+
+ const VariationStore &store = c->var_store;
/* pixel -> fractional pixel */
if (format & xPlaDevice) {
- if (x_ppem) glyph_pos.x_offset += (base + get_device (values)).get_x_delta (font);
+ if (use_x_device) glyph_pos.x_offset += (base + get_device (values)).get_x_delta (font, store);
values++;
}
if (format & yPlaDevice) {
- if (y_ppem) glyph_pos.y_offset += (base + get_device (values)).get_y_delta (font);
+ if (use_y_device) glyph_pos.y_offset += (base + get_device (values)).get_y_delta (font, store);
values++;
}
if (format & xAdvDevice) {
- if (horizontal && x_ppem) glyph_pos.x_advance += (base + get_device (values)).get_x_delta (font);
+ if (horizontal && use_x_device) glyph_pos.x_advance += (base + get_device (values)).get_x_delta (font, store);
values++;
}
if (format & yAdvDevice) {
/* y_advance values grow downward but font-space grows upward, hence negation */
- if (!horizontal && y_ppem) glyph_pos.y_advance -= (base + get_device (values)).get_y_delta (font);
+ if (!horizontal && use_y_device) glyph_pos.y_advance -= (base + get_device (values)).get_y_delta (font, store);
values++;
}
}
@@ -231,11 +232,12 @@ struct ValueFormat : USHORT
struct AnchorFormat1
{
- inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id HB_UNUSED,
+ inline void get_anchor (hb_apply_context_t *c, hb_codepoint_t glyph_id HB_UNUSED,
hb_position_t *x, hb_position_t *y) const
{
- *x = font->em_scale_x (xCoordinate);
- *y = font->em_scale_y (yCoordinate);
+ hb_font_t *font = c->font;
+ *x = font->em_scale_x (xCoordinate);
+ *y = font->em_scale_y (yCoordinate);
}
inline bool sanitize (hb_sanitize_context_t *c) const
@@ -254,18 +256,19 @@ struct AnchorFormat1
struct AnchorFormat2
{
- inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id,
+ inline void get_anchor (hb_apply_context_t *c, hb_codepoint_t glyph_id,
hb_position_t *x, hb_position_t *y) const
{
- unsigned int x_ppem = font->x_ppem;
- unsigned int y_ppem = font->y_ppem;
- hb_position_t cx, cy;
- hb_bool_t ret;
+ hb_font_t *font = c->font;
+ unsigned int x_ppem = font->x_ppem;
+ unsigned int y_ppem = font->y_ppem;
+ hb_position_t cx, cy;
+ hb_bool_t ret;
- ret = (x_ppem || y_ppem) &&
- font->get_glyph_contour_point_for_origin (glyph_id, anchorPoint, HB_DIRECTION_LTR, &cx, &cy);
- *x = ret && x_ppem ? cx : font->em_scale_x (xCoordinate);
- *y = ret && y_ppem ? cy : font->em_scale_y (yCoordinate);
+ ret = (x_ppem || y_ppem) &&
+ font->get_glyph_contour_point_for_origin (glyph_id, anchorPoint, HB_DIRECTION_LTR, &cx, &cy);
+ *x = ret && x_ppem ? cx : font->em_scale_x (xCoordinate);
+ *y = ret && y_ppem ? cy : font->em_scale_y (yCoordinate);
}
inline bool sanitize (hb_sanitize_context_t *c) const
@@ -285,16 +288,17 @@ struct AnchorFormat2
struct AnchorFormat3
{
- inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id HB_UNUSED,
+ inline void get_anchor (hb_apply_context_t *c, hb_codepoint_t glyph_id HB_UNUSED,
hb_position_t *x, hb_position_t *y) const
{
- *x = font->em_scale_x (xCoordinate);
- *y = font->em_scale_y (yCoordinate);
+ hb_font_t *font = c->font;
+ *x = font->em_scale_x (xCoordinate);
+ *y = font->em_scale_y (yCoordinate);
- if (font->x_ppem)
- *x += (this+xDeviceTable).get_x_delta (font);
- if (font->y_ppem)
- *y += (this+yDeviceTable).get_x_delta (font);
+ if (font->x_ppem || font->num_coords)
+ *x += (this+xDeviceTable).get_x_delta (font, c->var_store);
+ if (font->y_ppem || font->num_coords)
+ *y += (this+yDeviceTable).get_y_delta (font, c->var_store);
}
inline bool sanitize (hb_sanitize_context_t *c) const
@@ -321,14 +325,14 @@ struct AnchorFormat3
struct Anchor
{
- inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id,
+ inline void get_anchor (hb_apply_context_t *c, hb_codepoint_t glyph_id,
hb_position_t *x, hb_position_t *y) const
{
*x = *y = 0;
switch (u.format) {
- case 1: u.format1.get_anchor (font, glyph_id, x, y); return;
- case 2: u.format2.get_anchor (font, glyph_id, x, y); return;
- case 3: u.format3.get_anchor (font, glyph_id, x, y); return;
+ case 1: u.format1.get_anchor (c, glyph_id, x, y); return;
+ case 2: u.format2.get_anchor (c, glyph_id, x, y); return;
+ case 3: u.format3.get_anchor (c, glyph_id, x, y); return;
default: return;
}
}
@@ -370,7 +374,7 @@ struct AnchorMatrix
{
TRACE_SANITIZE (this);
if (!c->check_struct (this)) return_trace (false);
- if (unlikely (rows > 0 && cols >= ((unsigned int) -1) / rows)) return_trace (false);
+ if (unlikely (_hb_unsigned_int_mul_overflows (rows, cols))) return_trace (false);
unsigned int count = rows * cols;
if (!c->check_array (matrixZ, matrixZ[0].static_size, count)) return_trace (false);
for (unsigned int i = 0; i < count; i++)
@@ -428,8 +432,8 @@ struct MarkArray : ArrayOf<MarkRecord> /* Array of MarkRecords--in Coverage orde
hb_position_t mark_x, mark_y, base_x, base_y;
- mark_anchor.get_anchor (c->font, buffer->cur().codepoint, &mark_x, &mark_y);
- glyph_anchor.get_anchor (c->font, buffer->info[glyph_pos].codepoint, &base_x, &base_y);
+ mark_anchor.get_anchor (c, buffer->cur().codepoint, &mark_x, &mark_y);
+ glyph_anchor.get_anchor (c, buffer->info[glyph_pos].codepoint, &base_x, &base_y);
hb_glyph_position_t &o = buffer->cur_pos();
o.x_offset = base_x - mark_x;
@@ -472,8 +476,7 @@ struct SinglePosFormat1
unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint);
if (likely (index == NOT_COVERED)) return_trace (false);
- valueFormat.apply_value (c->font, c->direction, this,
- values, buffer->cur_pos());
+ valueFormat.apply_value (c, this, values, buffer->cur_pos());
buffer->idx++;
return_trace (true);
@@ -523,7 +526,7 @@ struct SinglePosFormat2
if (likely (index >= valueCount)) return_trace (false);
- valueFormat.apply_value (c->font, c->direction, this,
+ valueFormat.apply_value (c, this,
&values[index * valueFormat.get_len ()],
buffer->cur_pos());
@@ -640,10 +643,8 @@ struct PairSet
min = mid + 1;
else
{
- valueFormats[0].apply_value (c->font, c->direction, this,
- &record->values[0], buffer->cur_pos());
- valueFormats[1].apply_value (c->font, c->direction, this,
- &record->values[len1], buffer->pos[pos]);
+ valueFormats[0].apply_value (c, this, &record->values[0], buffer->cur_pos());
+ valueFormats[1].apply_value (c, this, &record->values[len1], buffer->pos[pos]);
if (len2)
pos++;
buffer->idx = pos;
@@ -689,7 +690,7 @@ struct PairPosFormat1
(this+coverage).add_coverage (c->input);
unsigned int count = pairSet.len;
for (unsigned int i = 0; i < count; i++)
- (this+pairSet[i]).collect_glyphs (c, &valueFormat1);
+ (this+pairSet[i]).collect_glyphs (c, valueFormat);
}
inline const Coverage &get_coverage (void) const
@@ -708,7 +709,7 @@ struct PairPosFormat1
skippy_iter.reset (buffer->idx, 1);
if (!skippy_iter.next ()) return_trace (false);
- return_trace ((this+pairSet[index]).apply (c, &valueFormat1, skippy_iter.idx));
+ return_trace ((this+pairSet[index]).apply (c, valueFormat, skippy_iter.idx));
}
inline bool sanitize (hb_sanitize_context_t *c) const
@@ -717,11 +718,11 @@ struct PairPosFormat1
if (!c->check_struct (this)) return_trace (false);
- unsigned int len1 = valueFormat1.get_len ();
- unsigned int len2 = valueFormat2.get_len ();
+ unsigned int len1 = valueFormat[0].get_len ();
+ unsigned int len2 = valueFormat[1].get_len ();
PairSet::sanitize_closure_t closure = {
this,
- &valueFormat1,
+ valueFormat,
len1,
1 + len1 + len2
};
@@ -734,10 +735,10 @@ struct PairPosFormat1
OffsetTo<Coverage>
coverage; /* Offset to Coverage table--from
* beginning of subtable */
- ValueFormat valueFormat1; /* Defines the types of data in
+ ValueFormat valueFormat[2]; /* [0] Defines the types of data in
* ValueRecord1--for the first glyph
* in the pair--may be zero (0) */
- ValueFormat valueFormat2; /* Defines the types of data in
+ /* [1] Defines the types of data in
* ValueRecord2--for the second glyph
* in the pair--may be zero (0) */
OffsetArrayOf<PairSet>
@@ -790,10 +791,8 @@ struct PairPosFormat2
if (unlikely (klass1 >= class1Count || klass2 >= class2Count)) return_trace (false);
const Value *v = &values[record_len * (klass1 * class2Count + klass2)];
- valueFormat1.apply_value (c->font, c->direction, this,
- v, buffer->cur_pos());
- valueFormat2.apply_value (c->font, c->direction, this,
- v + len1, buffer->pos[skippy_iter.idx]);
+ valueFormat1.apply_value (c, this, v, buffer->cur_pos());
+ valueFormat2.apply_value (c, this, v + len1, buffer->pos[skippy_iter.idx]);
buffer->idx = skippy_iter.idx;
if (len2)
@@ -931,8 +930,8 @@ struct CursivePosFormat1
unsigned int j = skippy_iter.idx;
hb_position_t entry_x, entry_y, exit_x, exit_y;
- (this+this_record.exitAnchor).get_anchor (c->font, buffer->info[i].codepoint, &exit_x, &exit_y);
- (this+next_record.entryAnchor).get_anchor (c->font, buffer->info[j].codepoint, &entry_x, &entry_y);
+ (this+this_record.exitAnchor).get_anchor (c, buffer->info[i].codepoint, &exit_x, &exit_y);
+ (this+next_record.entryAnchor).get_anchor (c, buffer->info[j].codepoint, &entry_x, &entry_y);
hb_glyph_position_t *pos = buffer->pos;
@@ -1519,8 +1518,6 @@ struct GPOS : GSUBGPOS
const OffsetTo<PosLookupList> &list = CastR<OffsetTo<PosLookupList> > (lookupList);
return_trace (list.sanitize (c, this));
}
- public:
- DEFINE_SIZE_STATIC (10);
};
diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh
index 22031f43c..66fcb3f3a 100644
--- a/src/hb-ot-layout-gsub-table.hh
+++ b/src/hb-ot-layout-gsub-table.hh
@@ -41,7 +41,10 @@ struct SingleSubstFormat1
{
TRACE_CLOSURE (this);
Coverage::Iter iter;
- for (iter.init (this+coverage); iter.more (); iter.next ()) {
+ for (iter.init (this+coverage); iter.more (); iter.next ())
+ {
+ /* TODO Switch to range-based API to work around malicious fonts.
+ * https://github.com/behdad/harfbuzz/issues/363 */
hb_codepoint_t glyph_id = iter.get_glyph ();
if (c->glyphs->has (glyph_id))
c->glyphs->add ((glyph_id + deltaGlyphID) & 0xFFFFu);
@@ -52,7 +55,10 @@ struct SingleSubstFormat1
{
TRACE_COLLECT_GLYPHS (this);
Coverage::Iter iter;
- for (iter.init (this+coverage); iter.more (); iter.next ()) {
+ for (iter.init (this+coverage); iter.more (); iter.next ())
+ {
+ /* TODO Switch to range-based API to work around malicious fonts.
+ * https://github.com/behdad/harfbuzz/issues/363 */
hb_codepoint_t glyph_id = iter.get_glyph ();
c->input->add (glyph_id);
c->output->add ((glyph_id + deltaGlyphID) & 0xFFFFu);
@@ -120,7 +126,11 @@ struct SingleSubstFormat2
{
TRACE_CLOSURE (this);
Coverage::Iter iter;
- for (iter.init (this+coverage); iter.more (); iter.next ()) {
+ unsigned int count = substitute.len;
+ for (iter.init (this+coverage); iter.more (); iter.next ())
+ {
+ if (unlikely (iter.get_coverage () >= count))
+ break; /* Work around malicious fonts. https://github.com/behdad/harfbuzz/issues/363 */
if (c->glyphs->has (iter.get_glyph ()))
c->glyphs->add (substitute[iter.get_coverage ()]);
}
@@ -130,7 +140,11 @@ struct SingleSubstFormat2
{
TRACE_COLLECT_GLYPHS (this);
Coverage::Iter iter;
- for (iter.init (this+coverage); iter.more (); iter.next ()) {
+ unsigned int count = substitute.len;
+ for (iter.init (this+coverage); iter.more (); iter.next ())
+ {
+ if (unlikely (iter.get_coverage () >= count))
+ break; /* Work around malicious fonts. https://github.com/behdad/harfbuzz/issues/363 */
c->input->add (iter.get_glyph ());
c->output->add (substitute[iter.get_coverage ()]);
}
@@ -321,7 +335,11 @@ struct MultipleSubstFormat1
{
TRACE_CLOSURE (this);
Coverage::Iter iter;
- for (iter.init (this+coverage); iter.more (); iter.next ()) {
+ unsigned int count = sequence.len;
+ for (iter.init (this+coverage); iter.more (); iter.next ())
+ {
+ if (unlikely (iter.get_coverage () >= count))
+ break; /* Work around malicious fonts. https://github.com/behdad/harfbuzz/issues/363 */
if (c->glyphs->has (iter.get_glyph ()))
(this+sequence[iter.get_coverage ()]).closure (c);
}
@@ -439,7 +457,11 @@ struct AlternateSubstFormat1
{
TRACE_CLOSURE (this);
Coverage::Iter iter;
- for (iter.init (this+coverage); iter.more (); iter.next ()) {
+ unsigned int count = alternateSet.len;
+ for (iter.init (this+coverage); iter.more (); iter.next ())
+ {
+ if (unlikely (iter.get_coverage () >= count))
+ break; /* Work around malicious fonts. https://github.com/behdad/harfbuzz/issues/363 */
if (c->glyphs->has (iter.get_glyph ())) {
const AlternateSet &alt_set = this+alternateSet[iter.get_coverage ()];
unsigned int count = alt_set.len;
@@ -453,7 +475,11 @@ struct AlternateSubstFormat1
{
TRACE_COLLECT_GLYPHS (this);
Coverage::Iter iter;
- for (iter.init (this+coverage); iter.more (); iter.next ()) {
+ unsigned int count = alternateSet.len;
+ for (iter.init (this+coverage); iter.more (); iter.next ())
+ {
+ if (unlikely (iter.get_coverage () >= count))
+ break; /* Work around malicious fonts. https://github.com/behdad/harfbuzz/issues/363 */
c->input->add (iter.get_glyph ());
const AlternateSet &alt_set = this+alternateSet[iter.get_coverage ()];
unsigned int count = alt_set.len;
@@ -762,7 +788,11 @@ struct LigatureSubstFormat1
{
TRACE_CLOSURE (this);
Coverage::Iter iter;
- for (iter.init (this+coverage); iter.more (); iter.next ()) {
+ unsigned int count = ligatureSet.len;
+ for (iter.init (this+coverage); iter.more (); iter.next ())
+ {
+ if (unlikely (iter.get_coverage () >= count))
+ break; /* Work around malicious fonts. https://github.com/behdad/harfbuzz/issues/363 */
if (c->glyphs->has (iter.get_glyph ()))
(this+ligatureSet[iter.get_coverage ()]).closure (c);
}
@@ -772,7 +802,11 @@ struct LigatureSubstFormat1
{
TRACE_COLLECT_GLYPHS (this);
Coverage::Iter iter;
- for (iter.init (this+coverage); iter.more (); iter.next ()) {
+ unsigned int count = ligatureSet.len;
+ for (iter.init (this+coverage); iter.more (); iter.next ())
+ {
+ if (unlikely (iter.get_coverage () >= count))
+ break; /* Work around malicious fonts. https://github.com/behdad/harfbuzz/issues/363 */
c->input->add (iter.get_glyph ());
(this+ligatureSet[iter.get_coverage ()]).collect_glyphs (c);
}
@@ -923,7 +957,11 @@ struct ReverseChainSingleSubstFormat1
const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
Coverage::Iter iter;
- for (iter.init (this+coverage); iter.more (); iter.next ()) {
+ count = substitute.len;
+ for (iter.init (this+coverage); iter.more (); iter.next ())
+ {
+ if (unlikely (iter.get_coverage () >= count))
+ break; /* Work around malicious fonts. https://github.com/behdad/harfbuzz/issues/363 */
if (c->glyphs->has (iter.get_glyph ()))
c->glyphs->add (substitute[iter.get_coverage ()]);
}
@@ -1273,8 +1311,6 @@ struct GSUB : GSUBGPOS
const OffsetTo<SubstLookupList> &list = CastR<OffsetTo<SubstLookupList> > (lookupList);
return_trace (list.sanitize (c, this));
}
- public:
- DEFINE_SIZE_STATIC (10);
};
@@ -1285,28 +1321,10 @@ GSUB::substitute_start (hb_font_t *font, hb_buffer_t *buffer)
const GDEF &gdef = *hb_ot_layout_from_face (font->face)->gdef;
unsigned int count = buffer->len;
- hb_glyph_info_t *info = buffer->info;
for (unsigned int i = 0; i < count; i++)
{
- unsigned int props = gdef.get_glyph_props (info[i].codepoint);
- if (!props)
- {
- /* Never mark default-ignorables as marks.
- * They won't get in the way of lookups anyway,
- * but having them as mark will cause them to be skipped
- * over if the lookup-flag says so, but at least for the
- * Mongolian variation selectors, looks like Uniscribe
- * marks them as non-mark. Some Mongolian fonts without
- * GDEF rely on this. Another notable character that
- * this applies to is COMBINING GRAPHEME JOINER. */
- props = (_hb_glyph_info_get_general_category (&info[i]) !=
- HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK ||
- _hb_glyph_info_is_default_ignorable (&info[i])) ?
- HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH :
- HB_OT_LAYOUT_GLYPH_PROPS_MARK;
- }
- _hb_glyph_info_set_glyph_props (&info[i], props);
- _hb_glyph_info_clear_lig_props (&info[i]);
+ _hb_glyph_info_set_glyph_props (&buffer->info[i], gdef.get_glyph_props (buffer->info[i].codepoint));
+ _hb_glyph_info_clear_lig_props (&buffer->info[i]);
buffer->info[i].syllable() = 0;
}
}
diff --git a/src/hb-ot-layout-gsubgpos-private.hh b/src/hb-ot-layout-gsubgpos-private.hh
index 997d22550..b7a0122a3 100644
--- a/src/hb-ot-layout-gsubgpos-private.hh
+++ b/src/hb-ot-layout-gsubgpos-private.hh
@@ -469,6 +469,7 @@ struct hb_apply_context_t :
unsigned int lookup_props;
const GDEF &gdef;
bool has_glyph_classes;
+ const VariationStore &var_store;
skipping_iterator_t iter_input, iter_context;
unsigned int lookup_index;
unsigned int debug_depth;
@@ -487,6 +488,7 @@ struct hb_apply_context_t :
lookup_props (0),
gdef (*hb_ot_layout_from_face (face)->gdef),
has_glyph_classes (gdef.has_glyph_classes ()),
+ var_store (gdef.get_var_store ()),
iter_input (),
iter_context (),
lookup_index ((unsigned int) -1),
@@ -999,8 +1001,12 @@ static inline bool apply_lookup (hb_apply_context_t *c,
end = int (end) + delta;
if (end <= match_positions[idx])
{
+ /* End might end up being smaller than match_positions[idx] if the recursed
+ * lookup ended up removing many items, more than we have had matched.
+ * Just never rewind end back and get out of here.
+ * https://bugs.chromium.org/p/chromium/issues/detail?id=659496 */
+ end = match_positions[idx];
/* There can't be any further changes. */
- assert (end == match_positions[idx]);
break;
}
@@ -2269,6 +2275,24 @@ struct GSUBGPOS
inline const Lookup& get_lookup (unsigned int i) const
{ return (this+lookupList)[i]; }
+ inline bool find_variations_index (const int *coords, unsigned int num_coords,
+ unsigned int *index) const
+ { return (version.to_int () >= 0x00010001u ? this+featureVars : Null(FeatureVariations))
+ .find_index (coords, num_coords, index); }
+ inline const Feature& get_feature_variation (unsigned int feature_index,
+ unsigned int variations_index) const
+ {
+ if (FeatureVariations::NOT_FOUND_INDEX != variations_index &&
+ version.to_int () >= 0x00010001u)
+ {
+ const Feature *feature = (this+featureVars).find_substitute (variations_index,
+ feature_index);
+ if (feature)
+ return *feature;
+ }
+ return get_feature (feature_index);
+ }
+
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@@ -2276,7 +2300,8 @@ struct GSUBGPOS
likely (version.major == 1) &&
scriptList.sanitize (c, this) &&
featureList.sanitize (c, this) &&
- lookupList.sanitize (c, this));
+ lookupList.sanitize (c, this) &&
+ (version.to_int () < 0x00010001u || featureVars.sanitize (c, this)));
}
protected:
@@ -2288,8 +2313,13 @@ struct GSUBGPOS
featureList; /* FeatureList table */
OffsetTo<LookupList>
lookupList; /* LookupList table */
+ LOffsetTo<FeatureVariations>
+ featureVars; /* Offset to Feature Variations
+ table--from beginning of table
+ * (may be NULL). Introduced
+ * in version 0x00010001. */
public:
- DEFINE_SIZE_STATIC (10);
+ DEFINE_SIZE_MIN (10);
};
diff --git a/src/hb-ot-layout-private.hh b/src/hb-ot-layout-private.hh
index 778b2c442..8c348beb1 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: */
@@ -124,6 +125,9 @@ namespace OT {
struct GDEF;
struct GSUB;
struct GPOS;
+ struct MATH;
+ struct fvar;
+ struct avar;
}
struct hb_ot_layout_lookup_accelerator_t
@@ -157,6 +161,11 @@ struct hb_ot_layout_t
const struct OT::GSUB *gsub;
const struct OT::GPOS *gpos;
+ /* 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;
diff --git a/src/hb-ot-layout.cc b/src/hb-ot-layout.cc
index 5cb1491c3..d7ededd8d 100644
--- a/src/hb-ot-layout.cc
+++ b/src/hb-ot-layout.cc
@@ -34,13 +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)
@@ -60,6 +57,10 @@ _hb_ot_layout_create (hb_face_t *face)
layout->gpos_blob = OT::Sanitizer<OT::GPOS>::sanitize (face->reference_table (HB_OT_TAG_GPOS));
layout->gpos = OT::Sanitizer<OT::GPOS>::lock_instance (layout->gpos_blob);
+ layout->math.init (face);
+ layout->fvar.init (face);
+ layout->avar.init (face);
+
{
/*
* The ugly business of blacklisting individual fonts' tables happen here!
@@ -178,6 +179,10 @@ _hb_ot_layout_destroy (hb_ot_layout_t *layout)
hb_blob_destroy (layout->gsub_blob);
hb_blob_destroy (layout->gpos_blob);
+ layout->math.fini ();
+ layout->fvar.fini ();
+ layout->avar.fini ();
+
free (layout);
}
@@ -200,7 +205,6 @@ _get_gpos (hb_face_t *face)
return *hb_ot_layout_from_face (face)->gpos;
}
-
/*
* GDEF
*/
@@ -552,10 +556,13 @@ hb_ot_layout_feature_get_lookups (hb_face_t *face,
unsigned int *lookup_count /* IN/OUT */,
unsigned int *lookup_indexes /* OUT */)
{
- const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
- const OT::Feature &f = g.get_feature (feature_index);
-
- return f.get_lookup_indexes (start_offset, lookup_count, lookup_indexes);
+ return hb_ot_layout_feature_with_variations_get_lookups (face,
+ table_tag,
+ feature_index,
+ HB_OT_LAYOUT_NO_VARIATIONS_INDEX,
+ start_offset,
+ lookup_count,
+ lookup_indexes);
}
/**
@@ -806,6 +813,38 @@ hb_ot_layout_lookup_collect_glyphs (hb_face_t *face,
}
+/* Variations support */
+
+hb_bool_t
+hb_ot_layout_table_find_feature_variations (hb_face_t *face,
+ hb_tag_t table_tag,
+ const int *coords,
+ unsigned int num_coords,
+ unsigned int *variations_index /* out */)
+{
+ const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
+
+ return g.find_variations_index (coords, num_coords, variations_index);
+}
+
+unsigned int
+hb_ot_layout_feature_with_variations_get_lookups (hb_face_t *face,
+ hb_tag_t table_tag,
+ unsigned int feature_index,
+ unsigned int variations_index,
+ unsigned int start_offset,
+ unsigned int *lookup_count /* IN/OUT */,
+ unsigned int *lookup_indexes /* OUT */)
+{
+ ASSERT_STATIC (OT::FeatureVariations::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_VARIATIONS_INDEX);
+ const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
+
+ const OT::Feature &f = g.get_feature_variation (feature_index, variations_index);
+
+ return f.get_lookup_indexes (start_offset, lookup_count, lookup_indexes);
+}
+
+
/*
* OT::GSUB
*/
diff --git a/src/hb-ot-layout.h b/src/hb-ot-layout.h
index eb23d45b6..9861f0fc7 100644
--- a/src/hb-ot-layout.h
+++ b/src/hb-ot-layout.h
@@ -95,6 +95,7 @@ hb_ot_layout_get_ligature_carets (hb_font_t *font,
#define HB_OT_LAYOUT_NO_SCRIPT_INDEX 0xFFFFu
#define HB_OT_LAYOUT_NO_FEATURE_INDEX 0xFFFFu
#define HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX 0xFFFFu
+#define HB_OT_LAYOUT_NO_VARIATIONS_INDEX 0xFFFFFFFFu
HB_EXTERN unsigned int
hb_ot_layout_table_get_script_tags (hb_face_t *face,
@@ -236,6 +237,24 @@ Xhb_ot_layout_lookup_enumerate_sequences (hb_face_t *face,
void *user_data);
#endif
+/* Variations support */
+
+HB_EXTERN hb_bool_t
+hb_ot_layout_table_find_feature_variations (hb_face_t *face,
+ hb_tag_t table_tag,
+ const int *coords,
+ unsigned int num_coords,
+ unsigned int *variations_index /* out */);
+
+HB_EXTERN unsigned int
+hb_ot_layout_feature_with_variations_get_lookups (hb_face_t *face,
+ hb_tag_t table_tag,
+ unsigned int feature_index,
+ unsigned int variations_index,
+ unsigned int start_offset,
+ unsigned int *lookup_count /* IN/OUT */,
+ unsigned int *lookup_indexes /* OUT */);
+
/*
* GSUB
diff --git a/src/hb-ot-map-private.hh b/src/hb-ot-map-private.hh
index 8692caa93..0395c9c22 100644
--- a/src/hb-ot-map-private.hh
+++ b/src/hb-ot-map-private.hh
@@ -139,12 +139,6 @@ struct hb_ot_map_t
private:
- HB_INTERNAL void add_lookups (hb_face_t *face,
- unsigned int table_index,
- unsigned int feature_index,
- hb_mask_t mask,
- bool auto_zwj);
-
hb_mask_t global_mask;
hb_prealloced_array_t<feature_map_t, 8> features;
@@ -182,7 +176,9 @@ struct hb_ot_map_builder_t
inline void add_gpos_pause (hb_ot_map_t::pause_func_t pause_func)
{ add_pause (1, pause_func); }
- HB_INTERNAL void compile (struct hb_ot_map_t &m);
+ HB_INTERNAL void compile (hb_ot_map_t &m,
+ const int *coords,
+ unsigned int num_coords);
inline void finish (void) {
feature_infos.finish ();
@@ -194,6 +190,14 @@ struct hb_ot_map_builder_t
private:
+ HB_INTERNAL void add_lookups (hb_ot_map_t &m,
+ hb_face_t *face,
+ unsigned int table_index,
+ unsigned int feature_index,
+ unsigned int variations_index,
+ hb_mask_t mask,
+ bool auto_zwj);
+
struct feature_info_t {
hb_tag_t tag;
unsigned int seq; /* sequence#, used for stable sorting only */
diff --git a/src/hb-ot-map.cc b/src/hb-ot-map.cc
index 17e3f4065..9b331d521 100644
--- a/src/hb-ot-map.cc
+++ b/src/hb-ot-map.cc
@@ -31,44 +31,13 @@
#include "hb-ot-layout-private.hh"
-void
-hb_ot_map_t::add_lookups (hb_face_t *face,
- unsigned int table_index,
- unsigned int feature_index,
- hb_mask_t mask,
- bool auto_zwj)
+void hb_ot_map_t::collect_lookups (unsigned int table_index, hb_set_t *lookups_out) const
{
- unsigned int lookup_indices[32];
- unsigned int offset, len;
- unsigned int table_lookup_count;
-
- table_lookup_count = hb_ot_layout_table_get_lookup_count (face, table_tags[table_index]);
-
- offset = 0;
- do {
- len = ARRAY_LENGTH (lookup_indices);
- hb_ot_layout_feature_get_lookups (face,
- table_tags[table_index],
- feature_index,
- offset, &len,
- lookup_indices);
-
- for (unsigned int i = 0; i < len; i++)
- {
- if (lookup_indices[i] >= table_lookup_count)
- continue;
- hb_ot_map_t::lookup_map_t *lookup = lookups[table_index].push ();
- if (unlikely (!lookup))
- return;
- lookup->mask = mask;
- lookup->index = lookup_indices[i];
- lookup->auto_zwj = auto_zwj;
- }
-
- offset += len;
- } while (len == ARRAY_LENGTH (lookup_indices));
+ for (unsigned int i = 0; i < lookups[table_index].len; i++)
+ hb_set_add (lookups_out, lookups[table_index][i].index);
}
+
hb_ot_map_builder_t::hb_ot_map_builder_t (hb_face_t *face_,
const hb_segment_properties_t *props_)
{
@@ -109,13 +78,48 @@ void hb_ot_map_builder_t::add_feature (hb_tag_t tag, unsigned int value,
info->stage[1] = current_stage[1];
}
-
-void hb_ot_map_t::collect_lookups (unsigned int table_index, hb_set_t *lookups_out) const
+void
+hb_ot_map_builder_t::add_lookups (hb_ot_map_t &m,
+ hb_face_t *face,
+ unsigned int table_index,
+ unsigned int feature_index,
+ unsigned int variations_index,
+ hb_mask_t mask,
+ bool auto_zwj)
{
- for (unsigned int i = 0; i < lookups[table_index].len; i++)
- hb_set_add (lookups_out, lookups[table_index][i].index);
+ unsigned int lookup_indices[32];
+ unsigned int offset, len;
+ unsigned int table_lookup_count;
+
+ table_lookup_count = hb_ot_layout_table_get_lookup_count (face, table_tags[table_index]);
+
+ offset = 0;
+ do {
+ len = ARRAY_LENGTH (lookup_indices);
+ hb_ot_layout_feature_with_variations_get_lookups (face,
+ table_tags[table_index],
+ feature_index,
+ variations_index,
+ offset, &len,
+ lookup_indices);
+
+ for (unsigned int i = 0; i < len; i++)
+ {
+ if (lookup_indices[i] >= table_lookup_count)
+ continue;
+ hb_ot_map_t::lookup_map_t *lookup = m.lookups[table_index].push ();
+ if (unlikely (!lookup))
+ return;
+ lookup->mask = mask;
+ lookup->index = lookup_indices[i];
+ lookup->auto_zwj = auto_zwj;
+ }
+
+ offset += len;
+ } while (len == ARRAY_LENGTH (lookup_indices));
}
+
void hb_ot_map_builder_t::add_pause (unsigned int table_index, hb_ot_map_t::pause_func_t pause_func)
{
stage_info_t *s = stages[table_index].push ();
@@ -128,7 +132,9 @@ void hb_ot_map_builder_t::add_pause (unsigned int table_index, hb_ot_map_t::paus
}
void
-hb_ot_map_builder_t::compile (hb_ot_map_t &m)
+hb_ot_map_builder_t::compile (hb_ot_map_t &m,
+ const int *coords,
+ unsigned int num_coords)
{
m.global_mask = 1;
@@ -262,23 +268,32 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m)
{
/* Collect lookup indices for features */
+ unsigned int variations_index;
+ hb_ot_layout_table_find_feature_variations (face,
+ table_tags[table_index],
+ coords,
+ num_coords,
+ &variations_index);
+
unsigned int stage_index = 0;
unsigned int last_num_lookups = 0;
for (unsigned stage = 0; stage < current_stage[table_index]; stage++)
{
if (required_feature_index[table_index] != HB_OT_LAYOUT_NO_FEATURE_INDEX &&
required_feature_stage[table_index] == stage)
- m.add_lookups (face, table_index,
- required_feature_index[table_index],
- 1 /* mask */,
- true /* auto_zwj */);
+ add_lookups (m, face, table_index,
+ required_feature_index[table_index],
+ variations_index,
+ 1 /* mask */,
+ true /* auto_zwj */);
for (unsigned i = 0; i < m.features.len; i++)
if (m.features[i].stage[table_index] == stage)
- m.add_lookups (face, table_index,
- m.features[i].index[table_index],
- m.features[i].mask,
- m.features[i].auto_zwj);
+ add_lookups (m, face, table_index,
+ m.features[i].index[table_index],
+ variations_index,
+ m.features[i].mask,
+ m.features[i].auto_zwj);
/* Sort lookups and merge duplicates */
if (last_num_lookups < m.lookups[table_index].len)
diff --git a/src/hb-ot-math-table.hh b/src/hb-ot-math-table.hh
new file mode 100644
index 000000000..191d79e98
--- /dev/null
+++ b/src/hb-ot-math-table.hh
@@ -0,0 +1,722 @@
+/*
+ * Copyright © 2016 Igalia S.L.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Igalia Author(s): Frédéric Wang
+ */
+
+#ifndef HB_OT_MATH_TABLE_HH
+#define HB_OT_MATH_TABLE_HH
+
+#include "hb-open-type-private.hh"
+#include "hb-ot-layout-common-private.hh"
+#include "hb-ot-math.h"
+
+namespace OT {
+
+
+struct MathValueRecord
+{
+ inline hb_position_t get_x_value (hb_font_t *font, const void *base) const
+ { return font->em_scale_x (value) + (base+deviceTable).get_x_delta (font); }
+ inline hb_position_t get_y_value (hb_font_t *font, const void *base) const
+ { return font->em_scale_y (value) + (base+deviceTable).get_y_delta (font); }
+
+ inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this) && deviceTable.sanitize (c, base));
+ }
+
+ protected:
+ SHORT value; /* The X or Y value in design units */
+ OffsetTo<Device> deviceTable; /* Offset to the device table - from the
+ * beginning of parent table. May be NULL.
+ * Suggested format for device table is 1. */
+
+ public:
+ DEFINE_SIZE_STATIC (4);
+};
+
+struct MathConstants
+{
+ inline bool sanitize_math_value_records (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+
+ unsigned int count = ARRAY_LENGTH (mathValueRecords);
+ for (unsigned int i = 0; i < count; i++)
+ if (!mathValueRecords[i].sanitize (c, this))
+ return_trace (false);
+
+ return_trace (true);
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this) && sanitize_math_value_records(c));
+ }
+
+ inline hb_position_t get_value (hb_ot_math_constant_t constant,
+ hb_font_t *font) const
+ {
+ switch (constant) {
+
+ case HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN:
+ case HB_OT_MATH_CONSTANT_SCRIPT_SCRIPT_PERCENT_SCALE_DOWN:
+ return percentScaleDown[constant - HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN];
+
+ case HB_OT_MATH_CONSTANT_DELIMITED_SUB_FORMULA_MIN_HEIGHT:
+ case HB_OT_MATH_CONSTANT_DISPLAY_OPERATOR_MIN_HEIGHT:
+ return font->em_scale_y (minHeight[constant - HB_OT_MATH_CONSTANT_DELIMITED_SUB_FORMULA_MIN_HEIGHT]);
+
+ case HB_OT_MATH_CONSTANT_RADICAL_KERN_AFTER_DEGREE:
+ case HB_OT_MATH_CONSTANT_RADICAL_KERN_BEFORE_DEGREE:
+ case HB_OT_MATH_CONSTANT_SKEWED_FRACTION_HORIZONTAL_GAP:
+ case HB_OT_MATH_CONSTANT_SPACE_AFTER_SCRIPT:
+ return mathValueRecords[constant - HB_OT_MATH_CONSTANT_MATH_LEADING].get_x_value(font, this);
+
+ case HB_OT_MATH_CONSTANT_ACCENT_BASE_HEIGHT:
+ case HB_OT_MATH_CONSTANT_AXIS_HEIGHT:
+ case HB_OT_MATH_CONSTANT_FLATTENED_ACCENT_BASE_HEIGHT:
+ case HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_DISPLAY_STYLE_SHIFT_DOWN:
+ case HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_GAP_MIN:
+ case HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_SHIFT_DOWN:
+ case HB_OT_MATH_CONSTANT_FRACTION_DENOM_DISPLAY_STYLE_GAP_MIN:
+ case HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_DISPLAY_STYLE_SHIFT_UP:
+ case HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_GAP_MIN:
+ case HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_SHIFT_UP:
+ case HB_OT_MATH_CONSTANT_FRACTION_NUM_DISPLAY_STYLE_GAP_MIN:
+ case HB_OT_MATH_CONSTANT_FRACTION_RULE_THICKNESS:
+ case HB_OT_MATH_CONSTANT_LOWER_LIMIT_BASELINE_DROP_MIN:
+ case HB_OT_MATH_CONSTANT_LOWER_LIMIT_GAP_MIN:
+ case HB_OT_MATH_CONSTANT_MATH_LEADING:
+ case HB_OT_MATH_CONSTANT_OVERBAR_EXTRA_ASCENDER:
+ case HB_OT_MATH_CONSTANT_OVERBAR_RULE_THICKNESS:
+ case HB_OT_MATH_CONSTANT_OVERBAR_VERTICAL_GAP:
+ case HB_OT_MATH_CONSTANT_RADICAL_DISPLAY_STYLE_VERTICAL_GAP:
+ case HB_OT_MATH_CONSTANT_RADICAL_EXTRA_ASCENDER:
+ case HB_OT_MATH_CONSTANT_RADICAL_RULE_THICKNESS:
+ case HB_OT_MATH_CONSTANT_RADICAL_VERTICAL_GAP:
+ case HB_OT_MATH_CONSTANT_SKEWED_FRACTION_VERTICAL_GAP:
+ case HB_OT_MATH_CONSTANT_STACK_BOTTOM_DISPLAY_STYLE_SHIFT_DOWN:
+ case HB_OT_MATH_CONSTANT_STACK_BOTTOM_SHIFT_DOWN:
+ case HB_OT_MATH_CONSTANT_STACK_DISPLAY_STYLE_GAP_MIN:
+ case HB_OT_MATH_CONSTANT_STACK_GAP_MIN:
+ case HB_OT_MATH_CONSTANT_STACK_TOP_DISPLAY_STYLE_SHIFT_UP:
+ case HB_OT_MATH_CONSTANT_STACK_TOP_SHIFT_UP:
+ case HB_OT_MATH_CONSTANT_STRETCH_STACK_BOTTOM_SHIFT_DOWN:
+ case HB_OT_MATH_CONSTANT_STRETCH_STACK_GAP_ABOVE_MIN:
+ case HB_OT_MATH_CONSTANT_STRETCH_STACK_GAP_BELOW_MIN:
+ case HB_OT_MATH_CONSTANT_STRETCH_STACK_TOP_SHIFT_UP:
+ case HB_OT_MATH_CONSTANT_SUBSCRIPT_BASELINE_DROP_MIN:
+ case HB_OT_MATH_CONSTANT_SUBSCRIPT_SHIFT_DOWN:
+ case HB_OT_MATH_CONSTANT_SUBSCRIPT_TOP_MAX:
+ case HB_OT_MATH_CONSTANT_SUB_SUPERSCRIPT_GAP_MIN:
+ case HB_OT_MATH_CONSTANT_SUPERSCRIPT_BASELINE_DROP_MAX:
+ case HB_OT_MATH_CONSTANT_SUPERSCRIPT_BOTTOM_MAX_WITH_SUBSCRIPT:
+ case HB_OT_MATH_CONSTANT_SUPERSCRIPT_BOTTOM_MIN:
+ case HB_OT_MATH_CONSTANT_SUPERSCRIPT_SHIFT_UP:
+ case HB_OT_MATH_CONSTANT_SUPERSCRIPT_SHIFT_UP_CRAMPED:
+ case HB_OT_MATH_CONSTANT_UNDERBAR_EXTRA_DESCENDER:
+ case HB_OT_MATH_CONSTANT_UNDERBAR_RULE_THICKNESS:
+ case HB_OT_MATH_CONSTANT_UNDERBAR_VERTICAL_GAP:
+ case HB_OT_MATH_CONSTANT_UPPER_LIMIT_BASELINE_RISE_MIN:
+ case HB_OT_MATH_CONSTANT_UPPER_LIMIT_GAP_MIN:
+ return mathValueRecords[constant - HB_OT_MATH_CONSTANT_MATH_LEADING].get_y_value(font, this);
+
+ case HB_OT_MATH_CONSTANT_RADICAL_DEGREE_BOTTOM_RAISE_PERCENT:
+ return radicalDegreeBottomRaisePercent;
+
+ default:
+ return 0;
+ }
+ }
+
+ protected:
+ SHORT percentScaleDown[2];
+ USHORT minHeight[2];
+ MathValueRecord mathValueRecords[51];
+ SHORT radicalDegreeBottomRaisePercent;
+
+ public:
+ DEFINE_SIZE_STATIC (214);
+};
+
+struct MathItalicsCorrectionInfo
+{
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this) &&
+ coverage.sanitize (c, this) &&
+ italicsCorrection.sanitize (c, this));
+ }
+
+ inline hb_position_t get_value (hb_codepoint_t glyph,
+ hb_font_t *font) const
+ {
+ unsigned int index = (this+coverage).get_coverage (glyph);
+ return italicsCorrection[index].get_x_value (font, this);
+ }
+
+ protected:
+ OffsetTo<Coverage> coverage; /* Offset to Coverage table -
+ * from the beginning of
+ * MathItalicsCorrectionInfo
+ * table. */
+ ArrayOf<MathValueRecord> italicsCorrection; /* Array of MathValueRecords
+ * defining italics correction
+ * values for each
+ * covered glyph. */
+
+ public:
+ DEFINE_SIZE_ARRAY (4, italicsCorrection);
+};
+
+struct MathTopAccentAttachment
+{
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this) &&
+ topAccentCoverage.sanitize (c, this) &&
+ topAccentAttachment.sanitize (c, this));
+ }
+
+ inline hb_position_t get_value (hb_codepoint_t glyph,
+ hb_font_t *font) const
+ {
+ unsigned int index = (this+topAccentCoverage).get_coverage (glyph);
+ if (index == NOT_COVERED)
+ return font->get_glyph_h_advance (glyph) / 2;
+ return topAccentAttachment[index].get_x_value(font, this);
+ }
+
+ protected:
+ OffsetTo<Coverage> topAccentCoverage; /* Offset to Coverage table -
+ * from the beginning of
+ * MathTopAccentAttachment
+ * table. */
+ ArrayOf<MathValueRecord> topAccentAttachment; /* Array of MathValueRecords
+ * defining top accent
+ * attachment points for each
+ * covered glyph. */
+
+ public:
+ DEFINE_SIZE_ARRAY (2 + 2, topAccentAttachment);
+};
+
+struct MathKern
+{
+ inline bool sanitize_math_value_records (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ unsigned int count = 2 * heightCount + 1;
+ for (unsigned int i = 0; i < count; i++)
+ if (!mathValueRecords[i].sanitize (c, this)) return_trace (false);
+ return_trace (true);
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this) &&
+ c->check_array (mathValueRecords,
+ mathValueRecords[0].static_size,
+ 2 * heightCount + 1) &&
+ sanitize_math_value_records (c));
+ }
+
+ inline hb_position_t get_value (hb_position_t correction_height, hb_font_t *font) const
+ {
+ const MathValueRecord* correctionHeight = mathValueRecords;
+ const MathValueRecord* kernValue = mathValueRecords + heightCount;
+ int sign = font->y_scale < 0 ? -1 : +1;
+
+ /* The description of the MathKern table is a ambiguous, but interpreting
+ * "between the two heights found at those indexes" for 0 < i < len as
+ *
+ * correctionHeight[i-1] < correction_height <= correctionHeight[i]
+ *
+ * makes the result consistent with the limit cases and we can just use the
+ * binary search algorithm of std::upper_bound:
+ */
+ unsigned int i = 0;
+ unsigned int count = heightCount;
+ while (count > 0)
+ {
+ unsigned int half = count / 2;
+ hb_position_t height = correctionHeight[i + half].get_y_value(font, this);
+ if (sign * height < sign * correction_height)
+ {
+ i += half + 1;
+ count -= half + 1;
+ } else
+ count = half;
+ }
+ return kernValue[i].get_x_value(font, this);
+ }
+
+ protected:
+ USHORT heightCount;
+ MathValueRecord mathValueRecords[VAR]; /* Array of correction heights at
+ * which the kern value changes.
+ * Sorted by the height value in
+ * design units (heightCount entries),
+ * Followed by:
+ * Array of kern values corresponding
+ * to heights. (heightCount+1 entries).
+ */
+
+ public:
+ DEFINE_SIZE_ARRAY (2, mathValueRecords);
+};
+
+struct MathKernInfoRecord
+{
+ inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
+ {
+ TRACE_SANITIZE (this);
+
+ unsigned int count = ARRAY_LENGTH (mathKern);
+ for (unsigned int i = 0; i < count; i++)
+ if (unlikely (!mathKern[i].sanitize (c, base)))
+ return_trace (false);
+
+ return_trace (true);
+ }
+
+ inline hb_position_t get_kerning (hb_ot_math_kern_t kern,
+ hb_position_t correction_height,
+ hb_font_t *font,
+ const void *base) const
+ {
+ unsigned int idx = kern;
+ if (unlikely (idx >= ARRAY_LENGTH (mathKern))) return 0;
+ return (base+mathKern[idx]).get_value (correction_height, font);
+ }
+
+ protected:
+ /* Offset to MathKern table for each corner -
+ * from the beginning of MathKernInfo table. May be NULL. */
+ OffsetTo<MathKern> mathKern[4];
+
+ public:
+ DEFINE_SIZE_STATIC (8);
+};
+
+struct MathKernInfo
+{
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this) &&
+ mathKernCoverage.sanitize (c, this) &&
+ mathKernInfoRecords.sanitize (c, this));
+ }
+
+ inline hb_position_t get_kerning (hb_codepoint_t glyph,
+ hb_ot_math_kern_t kern,
+ hb_position_t correction_height,
+ hb_font_t *font) const
+ {
+ unsigned int index = (this+mathKernCoverage).get_coverage (glyph);
+ return mathKernInfoRecords[index].get_kerning (kern, correction_height, font, this);
+ }
+
+ protected:
+ OffsetTo<Coverage> mathKernCoverage; /* Offset to Coverage table -
+ * from the beginning of the
+ * MathKernInfo table. */
+ ArrayOf<MathKernInfoRecord> mathKernInfoRecords; /* Array of
+ * MathKernInfoRecords,
+ * per-glyph information for
+ * mathematical positioning
+ * of subscripts and
+ * superscripts. */
+
+ public:
+ DEFINE_SIZE_ARRAY (4, mathKernInfoRecords);
+};
+
+struct MathGlyphInfo
+{
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this) &&
+ mathItalicsCorrectionInfo.sanitize (c, this) &&
+ mathTopAccentAttachment.sanitize (c, this) &&
+ extendedShapeCoverage.sanitize (c, this) &&
+ mathKernInfo.sanitize(c, this));
+ }
+
+ inline hb_position_t
+ get_italics_correction (hb_codepoint_t glyph, hb_font_t *font) const
+ { return (this+mathItalicsCorrectionInfo).get_value (glyph, font); }
+
+ inline hb_position_t
+ get_top_accent_attachment (hb_codepoint_t glyph, hb_font_t *font) const
+ { return (this+mathTopAccentAttachment).get_value (glyph, font); }
+
+ inline bool is_extended_shape (hb_codepoint_t glyph) const
+ { return (this+extendedShapeCoverage).get_coverage (glyph) != NOT_COVERED; }
+
+ inline hb_position_t get_kerning (hb_codepoint_t glyph,
+ hb_ot_math_kern_t kern,
+ hb_position_t correction_height,
+ hb_font_t *font) const
+ { return (this+mathKernInfo).get_kerning (glyph, kern, correction_height, font); }
+
+ protected:
+ /* Offset to MathItalicsCorrectionInfo table -
+ * from the beginning of MathGlyphInfo table. */
+ OffsetTo<MathItalicsCorrectionInfo> mathItalicsCorrectionInfo;
+
+ /* Offset to MathTopAccentAttachment table -
+ * from the beginning of MathGlyphInfo table. */
+ OffsetTo<MathTopAccentAttachment> mathTopAccentAttachment;
+
+ /* Offset to coverage table for Extended Shape glyphs -
+ * from the beginning of MathGlyphInfo table. When the left or right glyph of
+ * a box is an extended shape variant, the (ink) box (and not the default
+ * position defined by values in MathConstants table) should be used for
+ * vertical positioning purposes. May be NULL.. */
+ OffsetTo<Coverage> extendedShapeCoverage;
+
+ /* Offset to MathKernInfo table -
+ * from the beginning of MathGlyphInfo table. */
+ OffsetTo<MathKernInfo> mathKernInfo;
+
+ public:
+ DEFINE_SIZE_STATIC (8);
+};
+
+struct MathGlyphVariantRecord
+{
+ friend struct MathGlyphConstruction;
+
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this));
+ }
+
+ protected:
+ GlyphID variantGlyph; /* Glyph ID for the variant. */
+ USHORT advanceMeasurement; /* Advance width/height, in design units, of the
+ * variant, in the direction of requested
+ * glyph extension. */
+
+ public:
+ DEFINE_SIZE_STATIC (4);
+};
+
+struct PartFlags : USHORT
+{
+ enum Flags {
+ Extender = 0x0001u, /* If set, the part can be skipped or repeated. */
+
+ Defined = 0x0001u, /* All defined flags. */
+ };
+
+ public:
+ DEFINE_SIZE_STATIC (2);
+};
+
+struct MathGlyphPartRecord
+{
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this));
+ }
+
+ inline void extract (hb_ot_math_glyph_part_t &out,
+ int scale,
+ hb_font_t *font) const
+ {
+ out.glyph = glyph;
+
+ out.start_connector_length = font->em_scale (startConnectorLength, scale);
+ out.end_connector_length = font->em_scale (endConnectorLength, scale);
+ out.full_advance = font->em_scale (fullAdvance, scale);
+
+ ASSERT_STATIC ((unsigned int) HB_MATH_GLYPH_PART_FLAG_EXTENDER ==
+ (unsigned int) PartFlags::Extender);
+
+ out.flags = (hb_ot_math_glyph_part_flags_t)
+ (unsigned int)
+ (partFlags & PartFlags::Defined);
+ }
+
+ protected:
+ GlyphID glyph; /* Glyph ID for the part. */
+ USHORT startConnectorLength; /* Advance width/ height of the straight bar
+ * connector material, in design units, is at
+ * the beginning of the glyph, in the
+ * direction of the extension. */
+ USHORT endConnectorLength; /* Advance width/ height of the straight bar
+ * connector material, in design units, is at
+ * the end of the glyph, in the direction of
+ * the extension. */
+ USHORT fullAdvance; /* Full advance width/height for this part,
+ * in the direction of the extension.
+ * In design units. */
+ PartFlags partFlags; /* Part qualifiers. */
+
+ public:
+ DEFINE_SIZE_STATIC (10);
+};
+
+struct MathGlyphAssembly
+{
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this) &&
+ italicsCorrection.sanitize(c, this) &&
+ partRecords.sanitize(c));
+ }
+
+ inline unsigned int get_parts (hb_direction_t direction,
+ hb_font_t *font,
+ unsigned int start_offset,
+ unsigned int *parts_count, /* IN/OUT */
+ hb_ot_math_glyph_part_t *parts /* OUT */,
+ hb_position_t *italics_correction /* OUT */) const
+ {
+ if (parts_count)
+ {
+ int scale = font->dir_scale (direction);
+ const MathGlyphPartRecord *arr =
+ partRecords.sub_array (start_offset, parts_count);
+ unsigned int count = *parts_count;
+ for (unsigned int i = 0; i < count; i++)
+ arr[i].extract (parts[i], scale, font);
+ }
+
+ if (italics_correction)
+ *italics_correction = italicsCorrection.get_x_value (font, this);
+
+ return partRecords.len;
+ }
+
+ protected:
+ MathValueRecord italicsCorrection; /* Italics correction of this
+ * MathGlyphAssembly. Should not
+ * depend on the assembly size. */
+ ArrayOf<MathGlyphPartRecord> partRecords; /* Array of part records, from
+ * left to right and bottom to
+ * top. */
+
+ public:
+ DEFINE_SIZE_ARRAY (6, partRecords);
+};
+
+struct MathGlyphConstruction
+{
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this) &&
+ glyphAssembly.sanitize(c, this) &&
+ mathGlyphVariantRecord.sanitize(c));
+ }
+
+ inline const MathGlyphAssembly &get_assembly (void) const
+ { return this+glyphAssembly; }
+
+ inline unsigned int get_variants (hb_direction_t direction,
+ hb_font_t *font,
+ unsigned int start_offset,
+ unsigned int *variants_count, /* IN/OUT */
+ hb_ot_math_glyph_variant_t *variants /* OUT */) const
+ {
+ if (variants_count)
+ {
+ int scale = font->dir_scale (direction);
+ const MathGlyphVariantRecord *arr =
+ mathGlyphVariantRecord.sub_array (start_offset, variants_count);
+ unsigned int count = *variants_count;
+ for (unsigned int i = 0; i < count; i++)
+ {
+ variants[i].glyph = arr[i].variantGlyph;
+ variants[i].advance = font->em_scale (arr[i].advanceMeasurement, scale);
+ }
+ }
+ return mathGlyphVariantRecord.len;
+ }
+
+ protected:
+ /* Offset to MathGlyphAssembly table for this shape - from the beginning of
+ MathGlyphConstruction table. May be NULL. */
+ OffsetTo<MathGlyphAssembly> glyphAssembly;
+
+ /* MathGlyphVariantRecords for alternative variants of the glyphs. */
+ ArrayOf<MathGlyphVariantRecord> mathGlyphVariantRecord;
+
+ public:
+ DEFINE_SIZE_ARRAY (4, mathGlyphVariantRecord);
+};
+
+struct MathVariants
+{
+ inline bool sanitize_offsets (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ unsigned int count = vertGlyphCount + horizGlyphCount;
+ for (unsigned int i = 0; i < count; i++)
+ if (!glyphConstruction[i].sanitize (c, this)) return_trace (false);
+ return_trace (true);
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this) &&
+ vertGlyphCoverage.sanitize (c, this) &&
+ horizGlyphCoverage.sanitize (c, this) &&
+ c->check_array (glyphConstruction,
+ glyphConstruction[0].static_size,
+ vertGlyphCount + horizGlyphCount) &&
+ sanitize_offsets (c));
+ }
+
+ inline hb_position_t get_min_connector_overlap (hb_direction_t direction,
+ hb_font_t *font) const
+ { return font->em_scale_dir (minConnectorOverlap, direction); }
+
+ inline unsigned int get_glyph_variants (hb_codepoint_t glyph,
+ hb_direction_t direction,
+ hb_font_t *font,
+ unsigned int start_offset,
+ unsigned int *variants_count, /* IN/OUT */
+ hb_ot_math_glyph_variant_t *variants /* OUT */) const
+ { return get_glyph_construction (glyph, direction, font)
+ .get_variants (direction, font, start_offset, variants_count, variants); }
+
+ inline unsigned int get_glyph_parts (hb_codepoint_t glyph,
+ hb_direction_t direction,
+ hb_font_t *font,
+ unsigned int start_offset,
+ unsigned int *parts_count, /* IN/OUT */
+ hb_ot_math_glyph_part_t *parts /* OUT */,
+ hb_position_t *italics_correction /* OUT */) const
+ { return get_glyph_construction (glyph, direction, font)
+ .get_assembly ()
+ .get_parts (direction, font,
+ start_offset, parts_count, parts,
+ italics_correction); }
+
+ private:
+ inline const MathGlyphConstruction &
+ get_glyph_construction (hb_codepoint_t glyph,
+ hb_direction_t direction,
+ hb_font_t *font) const
+ {
+ bool vertical = HB_DIRECTION_IS_VERTICAL (direction);
+ unsigned int count = vertical ? vertGlyphCount : horizGlyphCount;
+ const OffsetTo<Coverage> &coverage = vertical ? vertGlyphCoverage
+ : horizGlyphCoverage;
+
+ unsigned int index = (this+coverage).get_coverage (glyph);
+ if (unlikely (index >= count)) return Null(MathGlyphConstruction);
+
+ if (!vertical)
+ index += vertGlyphCount;
+
+ return this+glyphConstruction[index];
+ }
+
+ protected:
+ USHORT minConnectorOverlap; /* Minimum overlap of connecting
+ * glyphs during glyph construction,
+ * in design units. */
+ OffsetTo<Coverage> vertGlyphCoverage; /* Offset to Coverage table -
+ * from the beginning of MathVariants
+ * table. */
+ OffsetTo<Coverage> horizGlyphCoverage; /* Offset to Coverage table -
+ * from the beginning of MathVariants
+ * table. */
+ USHORT vertGlyphCount; /* Number of glyphs for which
+ * information is provided for
+ * vertically growing variants. */
+ USHORT horizGlyphCount; /* Number of glyphs for which
+ * information is provided for
+ * horizontally growing variants. */
+
+ /* Array of offsets to MathGlyphConstruction tables - from the beginning of
+ the MathVariants table, for shapes growing in vertical/horizontal
+ direction. */
+ OffsetTo<MathGlyphConstruction> glyphConstruction[VAR];
+
+ public:
+ DEFINE_SIZE_ARRAY (10, glyphConstruction);
+};
+
+
+/*
+ * MATH -- The MATH Table
+ */
+
+struct MATH
+{
+ static const hb_tag_t tableTag = HB_OT_TAG_MATH;
+
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (version.sanitize (c) &&
+ likely (version.major == 1) &&
+ mathConstants.sanitize (c, this) &&
+ mathGlyphInfo.sanitize (c, this) &&
+ mathVariants.sanitize (c, this));
+ }
+
+ inline hb_position_t get_constant (hb_ot_math_constant_t constant,
+ hb_font_t *font) const
+ { return (this+mathConstants).get_value (constant, font); }
+
+ inline const MathGlyphInfo &get_math_glyph_info (void) const
+ { return this+mathGlyphInfo; }
+
+ inline const MathVariants &get_math_variants (void) const
+ { return this+mathVariants; }
+
+ protected:
+ FixedVersion<>version; /* Version of the MATH table
+ * initially set to 0x00010000u */
+ OffsetTo<MathConstants> mathConstants;/* MathConstants table */
+ OffsetTo<MathGlyphInfo> mathGlyphInfo;/* MathGlyphInfo table */
+ OffsetTo<MathVariants> mathVariants; /* MathVariants table */
+
+ public:
+ DEFINE_SIZE_STATIC (10);
+};
+
+} /* namespace OT */
+
+
+#endif /* HB_OT_MATH_TABLE_HH */
diff --git a/src/hb-ot-math.cc b/src/hb-ot-math.cc
new file mode 100644
index 000000000..2d7e6792a
--- /dev/null
+++ b/src/hb-ot-math.cc
@@ -0,0 +1,254 @@
+/*
+ * Copyright © 2016 Igalia S.L.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Igalia Author(s): Frédéric Wang
+ */
+
+#include "hb-open-type-private.hh"
+
+#include "hb-ot-math-table.hh"
+
+HB_SHAPER_DATA_ENSURE_DECLARE(ot, face)
+
+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);
+ return *(layout->math.get ());
+}
+
+/*
+ * OT::MATH
+ */
+
+/**
+ * hb_ot_math_has_data:
+ * @face: #hb_face_t to test
+ *
+ * This function allows to verify the presence of an OpenType MATH table on the
+ * face.
+ *
+ * Return value: true if face has a MATH table, false otherwise
+ *
+ * Since: 1.3.3
+ **/
+hb_bool_t
+hb_ot_math_has_data (hb_face_t *face)
+{
+ return &_get_math (face) != &OT::Null(OT::MATH);
+}
+
+/**
+ * hb_ot_math_get_constant:
+ * @font: #hb_font_t from which to retrieve the value
+ * @constant: #hb_ot_math_constant_t the constant to retrieve
+ *
+ * This function returns the requested math constants as a #hb_position_t.
+ * If the request constant is HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN,
+ * HB_OT_MATH_CONSTANT_SCRIPT_SCRIPT_PERCENT_SCALE_DOWN or
+ * HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN then the return value is
+ * actually an integer between 0 and 100 representing that percentage.
+ *
+ * Return value: the requested constant or 0
+ *
+ * Since: 1.3.3
+ **/
+hb_position_t
+hb_ot_math_get_constant (hb_font_t *font,
+ hb_ot_math_constant_t constant)
+{
+ const OT::MATH &math = _get_math (font->face);
+ return math.get_constant(constant, font);
+}
+
+/**
+ * hb_ot_math_get_glyph_italics_correction:
+ * @font: #hb_font_t from which to retrieve the value
+ * @glyph: glyph index from which to retrieve the value
+ *
+ * Return value: the italics correction of the glyph or 0
+ *
+ * Since: 1.3.3
+ **/
+hb_position_t
+hb_ot_math_get_glyph_italics_correction (hb_font_t *font,
+ hb_codepoint_t glyph)
+{
+ const OT::MATH &math = _get_math (font->face);
+ return math.get_math_glyph_info().get_italics_correction (glyph, font);
+}
+
+/**
+ * hb_ot_math_get_glyph_top_accent_attachment:
+ * @font: #hb_font_t from which to retrieve the value
+ * @glyph: glyph index from which to retrieve the value
+ *
+ * Return value: the top accent attachment of the glyph or 0
+ *
+ * Since: 1.3.3
+ **/
+hb_position_t
+hb_ot_math_get_glyph_top_accent_attachment (hb_font_t *font,
+ hb_codepoint_t glyph)
+{
+ const OT::MATH &math = _get_math (font->face);
+ return math.get_math_glyph_info().get_top_accent_attachment (glyph, font);
+}
+
+/**
+ * hb_ot_math_is_glyph_extended_shape:
+ * @face: a #hb_face_t to test
+ * @glyph: a glyph index to test
+ *
+ * Return value: true if the glyph is an extended shape, false otherwise
+ *
+ * Since: 1.3.3
+ **/
+hb_bool_t
+hb_ot_math_is_glyph_extended_shape (hb_face_t *face,
+ hb_codepoint_t glyph)
+{
+ const OT::MATH &math = _get_math (face);
+ return math.get_math_glyph_info().is_extended_shape (glyph);
+}
+
+/**
+ * hb_ot_math_get_glyph_kerning:
+ * @font: #hb_font_t from which to retrieve the value
+ * @glyph: glyph index from which to retrieve the value
+ * @kern: the #hb_ot_math_kern_t from which to retrieve the value
+ * @correction_height: the correction height to use to determine the kerning.
+ *
+ * This function tries to retrieve the MathKern table for the specified font,
+ * glyph and #hb_ot_math_kern_t. Then it browses the list of heights from the
+ * MathKern table to find one value that is greater or equal to specified
+ * correction_height. If one is found the corresponding value from the list of
+ * kerns is returned and otherwise the last kern value is returned.
+ *
+ * Return value: requested kerning or 0
+ *
+ * Since: 1.3.3
+ **/
+hb_position_t
+hb_ot_math_get_glyph_kerning (hb_font_t *font,
+ hb_codepoint_t glyph,
+ hb_ot_math_kern_t kern,
+ hb_position_t correction_height)
+{
+ const OT::MATH &math = _get_math (font->face);
+ return math.get_math_glyph_info().get_kerning (glyph, kern, correction_height, font);
+}
+
+/**
+ * hb_ot_math_get_glyph_variants:
+ * @font: #hb_font_t from which to retrieve the values
+ * @glyph: index of the glyph to stretch
+ * @direction: direction of the stretching
+ * @start_offset: offset of the first variant to retrieve
+ * @variants_count: maximum number of variants to retrieve after start_offset
+ * (IN) and actual number of variants retrieved (OUT)
+ * @variants: array of size at least @variants_count to store the result
+ *
+ * This function tries to retrieve the MathGlyphConstruction for the specified
+ * font, glyph and direction. Note that only the value of
+ * #HB_DIRECTION_IS_HORIZONTAL is considered. It provides the corresponding list
+ * of size variants as an array of hb_ot_math_glyph_variant_t structs.
+ *
+ * Return value: the total number of size variants available or 0
+ *
+ * Since: 1.3.3
+ **/
+unsigned int
+hb_ot_math_get_glyph_variants (hb_font_t *font,
+ hb_codepoint_t glyph,
+ hb_direction_t direction,
+ unsigned int start_offset,
+ unsigned int *variants_count, /* IN/OUT */
+ hb_ot_math_glyph_variant_t *variants /* OUT */)
+{
+ const OT::MATH &math = _get_math (font->face);
+ return math.get_math_variants().get_glyph_variants (glyph, direction, font,
+ start_offset,
+ variants_count,
+ variants);
+}
+
+/**
+ * hb_ot_math_get_min_connector_overlap:
+ * @font: #hb_font_t from which to retrieve the value
+ * @direction: direction of the stretching
+ *
+ * This function tries to retrieve the MathVariants table for the specified
+ * font and returns the minimum overlap of connecting glyphs to draw a glyph
+ * assembly in the specified direction. Note that only the value of
+ * #HB_DIRECTION_IS_HORIZONTAL is considered.
+ *
+ * Return value: requested min connector overlap or 0
+ *
+ * Since: 1.3.3
+ **/
+hb_position_t
+hb_ot_math_get_min_connector_overlap (hb_font_t *font,
+ hb_direction_t direction)
+{
+ const OT::MATH &math = _get_math (font->face);
+ return math.get_math_variants().get_min_connector_overlap (direction, font);
+}
+
+/**
+ * hb_ot_math_get_glyph_assembly:
+ * @font: #hb_font_t from which to retrieve the values
+ * @glyph: index of the glyph to stretch
+ * @direction: direction of the stretching
+ * @start_offset: offset of the first glyph part to retrieve
+ * @parts_count: maximum number of glyph parts to retrieve after start_offset
+ * (IN) and actual number of parts retrieved (OUT)
+ * @parts: array of size at least @parts_count to store the result
+ * @italics_correction: italic correction of the glyph assembly
+ *
+ * This function tries to retrieve the GlyphAssembly for the specified font,
+ * glyph and direction. Note that only the value of #HB_DIRECTION_IS_HORIZONTAL
+ * is considered. It provides the information necessary to draw the glyph
+ * assembly as an array of #hb_ot_math_glyph_part_t.
+ *
+ * Return value: the total number of parts in the glyph assembly
+ *
+ * Since: 1.3.3
+ **/
+unsigned int
+hb_ot_math_get_glyph_assembly (hb_font_t *font,
+ hb_codepoint_t glyph,
+ hb_direction_t direction,
+ unsigned int start_offset,
+ unsigned int *parts_count, /* IN/OUT */
+ hb_ot_math_glyph_part_t *parts, /* OUT */
+ hb_position_t *italics_correction /* OUT */)
+{
+ const OT::MATH &math = _get_math (font->face);
+ return math.get_math_variants().get_glyph_parts (glyph, direction, font,
+ start_offset,
+ parts_count,
+ parts,
+ italics_correction);
+}
diff --git a/src/hb-ot-math.h b/src/hb-ot-math.h
new file mode 100644
index 000000000..521a5ca03
--- /dev/null
+++ b/src/hb-ot-math.h
@@ -0,0 +1,209 @@
+/*
+ * Copyright © 2016 Igalia S.L.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Igalia Author(s): Frédéric Wang
+ */
+
+#ifndef HB_OT_H_IN
+#error "Include <hb-ot.h> instead."
+#endif
+
+#ifndef HB_OT_MATH_H
+#define HB_OT_MATH_H
+
+#include "hb.h"
+
+HB_BEGIN_DECLS
+
+
+/*
+ * MATH
+ */
+
+#define HB_OT_TAG_MATH HB_TAG('M','A','T','H')
+
+/* Use with hb_buffer_set_script() for math shaping. */
+#define HB_OT_MATH_SCRIPT HB_TAG('m','a','t','h')
+
+/* Types */
+
+/**
+ * hb_ot_math_constant_t:
+ *
+ * Since: 1.3.3
+ */
+typedef enum {
+ HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN = 0,
+ HB_OT_MATH_CONSTANT_SCRIPT_SCRIPT_PERCENT_SCALE_DOWN = 1,
+ HB_OT_MATH_CONSTANT_DELIMITED_SUB_FORMULA_MIN_HEIGHT = 2,
+ HB_OT_MATH_CONSTANT_DISPLAY_OPERATOR_MIN_HEIGHT = 3,
+ HB_OT_MATH_CONSTANT_MATH_LEADING = 4,
+ HB_OT_MATH_CONSTANT_AXIS_HEIGHT = 5,
+ HB_OT_MATH_CONSTANT_ACCENT_BASE_HEIGHT = 6,
+ HB_OT_MATH_CONSTANT_FLATTENED_ACCENT_BASE_HEIGHT = 7,
+ HB_OT_MATH_CONSTANT_SUBSCRIPT_SHIFT_DOWN = 8,
+ HB_OT_MATH_CONSTANT_SUBSCRIPT_TOP_MAX = 9,
+ HB_OT_MATH_CONSTANT_SUBSCRIPT_BASELINE_DROP_MIN = 10,
+ HB_OT_MATH_CONSTANT_SUPERSCRIPT_SHIFT_UP = 11,
+ HB_OT_MATH_CONSTANT_SUPERSCRIPT_SHIFT_UP_CRAMPED = 12,
+ HB_OT_MATH_CONSTANT_SUPERSCRIPT_BOTTOM_MIN = 13,
+ HB_OT_MATH_CONSTANT_SUPERSCRIPT_BASELINE_DROP_MAX = 14,
+ HB_OT_MATH_CONSTANT_SUB_SUPERSCRIPT_GAP_MIN = 15,
+ HB_OT_MATH_CONSTANT_SUPERSCRIPT_BOTTOM_MAX_WITH_SUBSCRIPT = 16,
+ HB_OT_MATH_CONSTANT_SPACE_AFTER_SCRIPT = 17,
+ HB_OT_MATH_CONSTANT_UPPER_LIMIT_GAP_MIN = 18,
+ HB_OT_MATH_CONSTANT_UPPER_LIMIT_BASELINE_RISE_MIN = 19,
+ HB_OT_MATH_CONSTANT_LOWER_LIMIT_GAP_MIN = 20,
+ HB_OT_MATH_CONSTANT_LOWER_LIMIT_BASELINE_DROP_MIN = 21,
+ HB_OT_MATH_CONSTANT_STACK_TOP_SHIFT_UP = 22,
+ HB_OT_MATH_CONSTANT_STACK_TOP_DISPLAY_STYLE_SHIFT_UP = 23,
+ HB_OT_MATH_CONSTANT_STACK_BOTTOM_SHIFT_DOWN = 24,
+ HB_OT_MATH_CONSTANT_STACK_BOTTOM_DISPLAY_STYLE_SHIFT_DOWN = 25,
+ HB_OT_MATH_CONSTANT_STACK_GAP_MIN = 26,
+ HB_OT_MATH_CONSTANT_STACK_DISPLAY_STYLE_GAP_MIN = 27,
+ HB_OT_MATH_CONSTANT_STRETCH_STACK_TOP_SHIFT_UP = 28,
+ HB_OT_MATH_CONSTANT_STRETCH_STACK_BOTTOM_SHIFT_DOWN = 29,
+ HB_OT_MATH_CONSTANT_STRETCH_STACK_GAP_ABOVE_MIN = 30,
+ HB_OT_MATH_CONSTANT_STRETCH_STACK_GAP_BELOW_MIN = 31,
+ HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_SHIFT_UP = 32,
+ HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_DISPLAY_STYLE_SHIFT_UP = 33,
+ HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_SHIFT_DOWN = 34,
+ HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_DISPLAY_STYLE_SHIFT_DOWN = 35,
+ HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_GAP_MIN = 36,
+ HB_OT_MATH_CONSTANT_FRACTION_NUM_DISPLAY_STYLE_GAP_MIN = 37,
+ HB_OT_MATH_CONSTANT_FRACTION_RULE_THICKNESS = 38,
+ HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_GAP_MIN = 39,
+ HB_OT_MATH_CONSTANT_FRACTION_DENOM_DISPLAY_STYLE_GAP_MIN = 40,
+ HB_OT_MATH_CONSTANT_SKEWED_FRACTION_HORIZONTAL_GAP = 41,
+ HB_OT_MATH_CONSTANT_SKEWED_FRACTION_VERTICAL_GAP = 42,
+ HB_OT_MATH_CONSTANT_OVERBAR_VERTICAL_GAP = 43,
+ HB_OT_MATH_CONSTANT_OVERBAR_RULE_THICKNESS = 44,
+ HB_OT_MATH_CONSTANT_OVERBAR_EXTRA_ASCENDER = 45,
+ HB_OT_MATH_CONSTANT_UNDERBAR_VERTICAL_GAP = 46,
+ HB_OT_MATH_CONSTANT_UNDERBAR_RULE_THICKNESS = 47,
+ HB_OT_MATH_CONSTANT_UNDERBAR_EXTRA_DESCENDER = 48,
+ HB_OT_MATH_CONSTANT_RADICAL_VERTICAL_GAP = 49,
+ HB_OT_MATH_CONSTANT_RADICAL_DISPLAY_STYLE_VERTICAL_GAP = 50,
+ HB_OT_MATH_CONSTANT_RADICAL_RULE_THICKNESS = 51,
+ HB_OT_MATH_CONSTANT_RADICAL_EXTRA_ASCENDER = 52,
+ HB_OT_MATH_CONSTANT_RADICAL_KERN_BEFORE_DEGREE = 53,
+ HB_OT_MATH_CONSTANT_RADICAL_KERN_AFTER_DEGREE = 54,
+ HB_OT_MATH_CONSTANT_RADICAL_DEGREE_BOTTOM_RAISE_PERCENT = 55
+} hb_ot_math_constant_t;
+
+/**
+ * hb_ot_math_kern_t:
+ *
+ * Since: 1.3.3
+ */
+typedef enum {
+ HB_OT_MATH_KERN_TOP_RIGHT = 0,
+ HB_OT_MATH_KERN_TOP_LEFT = 1,
+ HB_OT_MATH_KERN_BOTTOM_RIGHT = 2,
+ HB_OT_MATH_KERN_BOTTOM_LEFT = 3
+} hb_ot_math_kern_t;
+
+/**
+ * hb_ot_math_glyph_variant_t:
+ *
+ * Since: 1.3.3
+ */
+typedef struct hb_ot_math_glyph_variant_t {
+ hb_codepoint_t glyph;
+ hb_position_t advance;
+} hb_ot_math_glyph_variant_t;
+
+/**
+ * hb_ot_math_glyph_part_flags_t:
+ *
+ * Since: 1.3.3
+ */
+typedef enum { /*< flags >*/
+ HB_MATH_GLYPH_PART_FLAG_EXTENDER = 0x00000001u /* Extender glyph */
+} hb_ot_math_glyph_part_flags_t;
+
+/**
+ * hb_ot_math_glyph_part_t:
+ *
+ * Since: 1.3.3
+ */
+typedef struct hb_ot_math_glyph_part_t {
+ hb_codepoint_t glyph;
+ hb_position_t start_connector_length;
+ hb_position_t end_connector_length;
+ hb_position_t full_advance;
+ hb_ot_math_glyph_part_flags_t flags;
+} hb_ot_math_glyph_part_t;
+
+/* Methods */
+
+HB_EXTERN hb_bool_t
+hb_ot_math_has_data (hb_face_t *face);
+
+HB_EXTERN hb_position_t
+hb_ot_math_get_constant (hb_font_t *font,
+ hb_ot_math_constant_t constant);
+
+HB_EXTERN hb_position_t
+hb_ot_math_get_glyph_italics_correction (hb_font_t *font,
+ hb_codepoint_t glyph);
+
+HB_EXTERN hb_position_t
+hb_ot_math_get_glyph_top_accent_attachment (hb_font_t *font,
+ hb_codepoint_t glyph);
+
+HB_EXTERN hb_bool_t
+hb_ot_math_is_glyph_extended_shape (hb_face_t *face,
+ hb_codepoint_t glyph);
+
+HB_EXTERN hb_position_t
+hb_ot_math_get_glyph_kerning (hb_font_t *font,
+ hb_codepoint_t glyph,
+ hb_ot_math_kern_t kern,
+ hb_position_t correction_height);
+
+HB_EXTERN unsigned int
+hb_ot_math_get_glyph_variants (hb_font_t *font,
+ hb_codepoint_t glyph,
+ hb_direction_t direction,
+ unsigned int start_offset,
+ unsigned int *variants_count, /* IN/OUT */
+ hb_ot_math_glyph_variant_t *variants /* OUT */);
+
+HB_EXTERN hb_position_t
+hb_ot_math_get_min_connector_overlap (hb_font_t *font,
+ hb_direction_t direction);
+
+HB_EXTERN unsigned int
+hb_ot_math_get_glyph_assembly (hb_font_t *font,
+ hb_codepoint_t glyph,
+ hb_direction_t direction,
+ unsigned int start_offset,
+ unsigned int *parts_count, /* IN/OUT */
+ hb_ot_math_glyph_part_t *parts, /* OUT */
+ hb_position_t *italics_correction /* OUT */);
+
+
+HB_END_DECLS
+
+#endif /* HB_OT_MATH_H */
diff --git a/src/hb-ot-shape-complex-arabic.cc b/src/hb-ot-shape-complex-arabic.cc
index 4da899055..56ec5cd65 100644
--- a/src/hb-ot-shape-complex-arabic.cc
+++ b/src/hb-ot-shape-complex-arabic.cc
@@ -618,6 +618,7 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_arabic =
NULL, /* decompose */
NULL, /* compose */
setup_masks_arabic,
+ NULL, /* disable_otl */
HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
true, /* fallback_position */
};
diff --git a/src/hb-ot-shape-complex-default.cc b/src/hb-ot-shape-complex-default.cc
index be60e56fe..42830ab61 100644
--- a/src/hb-ot-shape-complex-default.cc
+++ b/src/hb-ot-shape-complex-default.cc
@@ -40,6 +40,7 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_default =
NULL, /* decompose */
NULL, /* compose */
NULL, /* setup_masks */
+ NULL, /* disable_otl */
HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
true, /* fallback_position */
};
diff --git a/src/hb-ot-shape-complex-hangul.cc b/src/hb-ot-shape-complex-hangul.cc
index 5f4d98b70..af5056522 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,
@@ -419,6 +419,7 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_hangul =
NULL, /* decompose */
NULL, /* compose */
setup_masks_hangul,
+ NULL, /* disable_otl */
HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
false, /* fallback_position */
};
diff --git a/src/hb-ot-shape-complex-hebrew.cc b/src/hb-ot-shape-complex-hebrew.cc
index 32159002e..96f249461 100644
--- a/src/hb-ot-shape-complex-hebrew.cc
+++ b/src/hb-ot-shape-complex-hebrew.cc
@@ -154,6 +154,18 @@ compose_hebrew (const hb_ot_shape_normalize_context_t *c,
return found;
}
+static bool
+disable_otl_hebrew (const hb_ot_shape_plan_t *plan)
+{
+ /* For Hebrew shaper, use fallback if GPOS does not have 'hebr'
+ * script. This matches Uniscribe better, and makes fonts like
+ * Arial that have GSUB/GPOS/GDEF but no data for Hebrew work.
+ * See:
+ * https://github.com/behdad/harfbuzz/issues/347#issuecomment-267838368
+ */
+ return plan->map.chosen_script[1] != HB_TAG ('h','e','b','r');
+}
+
const hb_ot_complex_shaper_t _hb_ot_complex_shaper_hebrew =
{
@@ -168,6 +180,7 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_hebrew =
NULL, /* decompose */
compose_hebrew,
NULL, /* setup_masks */
+ disable_otl_hebrew,
HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
true, /* fallback_position */
};
diff --git a/src/hb-ot-shape-complex-indic.cc b/src/hb-ot-shape-complex-indic.cc
index 94556f654..b48fb561c 100644
--- a/src/hb-ot-shape-complex-indic.cc
+++ b/src/hb-ot-shape-complex-indic.cc
@@ -1713,33 +1713,28 @@ decompose_indic (const hb_ot_shape_normalize_context_t *c,
switch (ab)
{
/* Don't decompose these. */
- case 0x0931u : return false;
- case 0x0B94u : return false;
+ case 0x0931u : return false; /* DEVANAGARI LETTER RRA */
+ case 0x0B94u : return false; /* TAMIL LETTER AU */
/*
* Decompose split matras that don't have Unicode decompositions.
*/
- case 0x0F77u : *a = 0x0FB2u; *b= 0x0F81u; return true;
- case 0x0F79u : *a = 0x0FB3u; *b= 0x0F81u; return true;
+ /* Khmer */
case 0x17BEu : *a = 0x17C1u; *b= 0x17BEu; return true;
case 0x17BFu : *a = 0x17C1u; *b= 0x17BFu; return true;
case 0x17C0u : *a = 0x17C1u; *b= 0x17C0u; return true;
case 0x17C4u : *a = 0x17C1u; *b= 0x17C4u; return true;
case 0x17C5u : *a = 0x17C1u; *b= 0x17C5u; return true;
- case 0x1925u : *a = 0x1920u; *b= 0x1923u; return true;
- case 0x1926u : *a = 0x1920u; *b= 0x1924u; return true;
- case 0x1B3Cu : *a = 0x1B42u; *b= 0x1B3Cu; return true;
- case 0x1112Eu : *a = 0x11127u; *b= 0x11131u; return true;
- case 0x1112Fu : *a = 0x11127u; *b= 0x11132u; return true;
+
#if 0
+ /* Gujarati */
/* This one has no decomposition in Unicode, but needs no decomposition either. */
/* case 0x0AC9u : return false; */
+
+ /* Oriya */
case 0x0B57u : *a = no decomp, -> RIGHT; return true;
- case 0x1C29u : *a = no decomp, -> LEFT; return true;
- case 0xA9C0u : *a = no decomp, -> RIGHT; return true;
- case 0x111BuF : *a = no decomp, -> ABOVE; return true;
#endif
}
@@ -1819,6 +1814,7 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_indic =
decompose_indic,
compose_indic,
setup_masks_indic,
+ NULL, /* disable_otl */
HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
false, /* fallback_position */
};
diff --git a/src/hb-ot-shape-complex-myanmar.cc b/src/hb-ot-shape-complex-myanmar.cc
index 577d790c7..bb68622e2 100644
--- a/src/hb-ot-shape-complex-myanmar.cc
+++ b/src/hb-ot-shape-complex-myanmar.cc
@@ -521,6 +521,7 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_myanmar_old =
NULL, /* decompose */
NULL, /* compose */
NULL, /* setup_masks */
+ NULL, /* disable_otl */
HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
true, /* fallback_position */
};
@@ -538,6 +539,7 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_myanmar =
NULL, /* decompose */
NULL, /* compose */
setup_masks_myanmar,
+ NULL, /* disable_otl */
HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY,
false, /* fallback_position */
};
diff --git a/src/hb-ot-shape-complex-private.hh b/src/hb-ot-shape-complex-private.hh
index fb0c70406..39572dfe0 100644
--- a/src/hb-ot-shape-complex-private.hh
+++ b/src/hb-ot-shape-complex-private.hh
@@ -146,6 +146,14 @@ struct hb_ot_complex_shaper_t
hb_buffer_t *buffer,
hb_font_t *font);
+ /* disable_otl()
+ * Called during shape().
+ * If set and returns true, GDEF/GSUB/GPOS of the font are ignored
+ * and fallback operations used.
+ * May be NULL.
+ */
+ bool (*disable_otl) (const hb_ot_shape_plan_t *plan);
+
hb_ot_shape_zero_width_marks_type_t zero_width_marks;
bool fallback_position;
diff --git a/src/hb-ot-shape-complex-thai.cc b/src/hb-ot-shape-complex-thai.cc
index 4322b0d1d..e6f80f59e 100644
--- a/src/hb-ot-shape-complex-thai.cc
+++ b/src/hb-ot-shape-complex-thai.cc
@@ -376,6 +376,7 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_thai =
NULL, /* decompose */
NULL, /* compose */
NULL, /* setup_masks */
+ NULL, /* disable_otl */
HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
false,/* fallback_position */
};
diff --git a/src/hb-ot-shape-complex-tibetan.cc b/src/hb-ot-shape-complex-tibetan.cc
index a77b531da..aadf59f5a 100644
--- a/src/hb-ot-shape-complex-tibetan.cc
+++ b/src/hb-ot-shape-complex-tibetan.cc
@@ -57,6 +57,7 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_tibetan =
NULL, /* decompose */
NULL, /* compose */
NULL, /* setup_masks */
+ NULL, /* disable_otl */
HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
true, /* fallback_position */
};
diff --git a/src/hb-ot-shape-complex-use.cc b/src/hb-ot-shape-complex-use.cc
index 045ead52f..af6870686 100644
--- a/src/hb-ot-shape-complex-use.cc
+++ b/src/hb-ot-shape-complex-use.cc
@@ -559,6 +559,25 @@ reorder (const hb_ot_shape_plan_t *plan,
}
static bool
+decompose_use (const hb_ot_shape_normalize_context_t *c,
+ hb_codepoint_t ab,
+ hb_codepoint_t *a,
+ hb_codepoint_t *b)
+{
+ switch (ab)
+ {
+ /* Chakma:
+ * Special case where the Unicode decomp gives matras in the wrong order
+ * for cluster validation.
+ */
+ case 0x1112Eu : *a = 0x11127u; *b= 0x11131u; return true;
+ case 0x1112Fu : *a = 0x11127u; *b= 0x11132u; return true;
+ }
+
+ return (bool) c->unicode->decompose (ab, a, b);
+}
+
+static bool
compose_use (const hb_ot_shape_normalize_context_t *c,
hb_codepoint_t a,
hb_codepoint_t b,
@@ -582,9 +601,10 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_use =
NULL, /* preprocess_text */
NULL, /* postprocess_glyphs */
HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
- NULL, /* decompose */
+ decompose_use,
compose_use,
setup_masks_use,
+ NULL, /* disable_otl */
HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY,
false, /* fallback_position */
};
diff --git a/src/hb-ot-shape-private.hh b/src/hb-ot-shape-private.hh
index 54ac2c3cf..594e54c02 100644
--- a/src/hb-ot-shape-private.hh
+++ b/src/hb-ot-shape-private.hh
@@ -77,11 +77,13 @@ struct hb_ot_shape_planner_t
map (face, &props) {}
~hb_ot_shape_planner_t (void) { map.finish (); }
- inline void compile (hb_ot_shape_plan_t &plan)
+ inline void compile (hb_ot_shape_plan_t &plan,
+ const int *coords,
+ unsigned int num_coords)
{
plan.props = props;
plan.shaper = shaper;
- map.compile (plan.map);
+ map.compile (plan.map, coords, num_coords);
plan.rtlm_mask = plan.map.get_1_mask (HB_TAG ('r','t','l','m'));
plan.frac_mask = plan.map.get_1_mask (HB_TAG ('f','r','a','c'));
diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc
index 7811cb7f8..6b38739c9 100644
--- a/src/hb-ot-shape.cc
+++ b/src/hb-ot-shape.cc
@@ -69,6 +69,9 @@ hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner,
{
hb_ot_map_builder_t *map = &planner->map;
+ map->add_global_bool_feature (HB_TAG('r','v','r','n'));
+ map->add_gsub_pause (NULL);
+
switch (props->direction) {
case HB_DIRECTION_LTR:
map->add_global_bool_feature (HB_TAG ('l','t','r','a'));
@@ -163,7 +166,9 @@ _hb_ot_shaper_font_data_destroy (hb_ot_shaper_font_data_t *data)
hb_ot_shaper_shape_plan_data_t *
_hb_ot_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan,
const hb_feature_t *user_features,
- unsigned int num_user_features)
+ unsigned int num_user_features,
+ const int *coords,
+ unsigned int num_coords)
{
hb_ot_shape_plan_t *plan = (hb_ot_shape_plan_t *) calloc (1, sizeof (hb_ot_shape_plan_t));
if (unlikely (!plan))
@@ -173,9 +178,10 @@ _hb_ot_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan,
planner.shaper = hb_ot_shape_complex_categorize (&planner);
- hb_ot_shape_collect_features (&planner, &shape_plan->props, user_features, num_user_features);
+ hb_ot_shape_collect_features (&planner, &shape_plan->props,
+ user_features, num_user_features);
- planner.compile (*plan);
+ planner.compile (*plan, coords, num_coords);
if (plan->shaper->data_create) {
plan->data = plan->shaper->data_create (plan);
@@ -212,6 +218,8 @@ struct hb_ot_shape_context_t
unsigned int num_user_features;
/* Transient stuff */
+ bool fallback_positioning;
+ bool fallback_glyph_classes;
hb_direction_t target_direction;
};
@@ -354,6 +362,18 @@ hb_ot_shape_setup_masks_fraction (hb_ot_shape_context_t *c)
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;
@@ -372,10 +392,10 @@ hb_ot_shape_setup_masks_fraction (hb_ot_shape_context_t *c)
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;
}
@@ -524,6 +544,32 @@ hb_ot_map_glyphs_fast (hb_buffer_t *buffer)
}
static inline void
+hb_synthesize_glyph_classes (hb_ot_shape_context_t *c)
+{
+ unsigned int count = c->buffer->len;
+ hb_glyph_info_t *info = c->buffer->info;
+ for (unsigned int i = 0; i < count; i++)
+ {
+ hb_ot_layout_glyph_props_flags_t klass;
+
+ /* Never mark default-ignorables as marks.
+ * They won't get in the way of lookups anyway,
+ * but having them as mark will cause them to be skipped
+ * over if the lookup-flag says so, but at least for the
+ * Mongolian variation selectors, looks like Uniscribe
+ * marks them as non-mark. Some Mongolian fonts without
+ * GDEF rely on this. Another notable character that
+ * this applies to is COMBINING GRAPHEME JOINER. */
+ klass = (_hb_glyph_info_get_general_category (&info[i]) !=
+ HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK ||
+ _hb_glyph_info_is_default_ignorable (&info[i])) ?
+ HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH :
+ HB_OT_LAYOUT_GLYPH_PROPS_MARK;
+ _hb_glyph_info_set_glyph_props (&info[i], klass);
+ }
+}
+
+static inline void
hb_ot_substitute_default (hb_ot_shape_context_t *c)
{
hb_buffer_t *buffer = c->buffer;
@@ -539,7 +585,7 @@ hb_ot_substitute_default (hb_ot_shape_context_t *c)
hb_ot_shape_setup_masks (c);
/* This is unfortunate to go here, but necessary... */
- if (!hb_ot_layout_has_positioning (c->face))
+ if (c->fallback_positioning)
_hb_ot_shape_fallback_position_recategorize_marks (c->plan, c->font, buffer);
hb_ot_map_glyphs_fast (buffer);
@@ -554,6 +600,9 @@ hb_ot_substitute_complex (hb_ot_shape_context_t *c)
hb_ot_layout_substitute_start (c->font, buffer);
+ if (!hb_ot_layout_has_glyph_classes (c->face))
+ hb_synthesize_glyph_classes (c);
+
c->plan->substitute (c->font, buffer);
return;
@@ -632,14 +681,12 @@ hb_ot_position_default (hb_ot_shape_context_t *c)
_hb_ot_shape_fallback_spaces (c->plan, c->font, c->buffer);
}
-static inline bool
+static inline void
hb_ot_position_complex (hb_ot_shape_context_t *c)
{
hb_ot_layout_position_start (c->font, c->buffer);
- bool ret = false;
unsigned int count = c->buffer->len;
- bool has_positioning = (bool) hb_ot_layout_has_positioning (c->face);
/* If the font has no GPOS, AND, no fallback positioning will
* happen, AND, direction is forward, then when zeroing mark
@@ -650,8 +697,9 @@ hb_ot_position_complex (hb_ot_shape_context_t *c)
* If fallback positinoing happens or GPOS is present, we don't
* care.
*/
- bool adjust_offsets_when_zeroing = !(has_positioning || c->plan->shaper->fallback_position ||
- HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction));
+ bool adjust_offsets_when_zeroing = c->fallback_positioning &&
+ !c->plan->shaper->fallback_position &&
+ HB_DIRECTION_IS_FORWARD (c->buffer->props.direction);
switch (c->plan->shaper->zero_width_marks)
{
@@ -665,7 +713,7 @@ hb_ot_position_complex (hb_ot_shape_context_t *c)
break;
}
- if (has_positioning)
+ if (likely (!c->fallback_positioning))
{
hb_glyph_info_t *info = c->buffer->info;
hb_glyph_position_t *pos = c->buffer->pos;
@@ -688,7 +736,6 @@ hb_ot_position_complex (hb_ot_shape_context_t *c)
&pos[i].x_offset,
&pos[i].y_offset);
- ret = true;
}
switch (c->plan->shaper->zero_width_marks)
@@ -707,8 +754,6 @@ hb_ot_position_complex (hb_ot_shape_context_t *c)
hb_ot_layout_position_finish_advances (c->font, c->buffer);
hb_ot_zero_width_default_ignorables (c);
hb_ot_layout_position_finish_offsets (c->font, c->buffer);
-
- return ret;
}
static inline void
@@ -718,9 +763,9 @@ hb_ot_position (hb_ot_shape_context_t *c)
hb_ot_position_default (c);
- hb_bool_t fallback = !hb_ot_position_complex (c);
+ hb_ot_position_complex (c);
- if (fallback && c->plan->shaper->fallback_position)
+ if (c->fallback_positioning && c->plan->shaper->fallback_position)
_hb_ot_shape_fallback_position (c->plan, c->font, c->buffer);
if (HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction))
@@ -728,7 +773,7 @@ hb_ot_position (hb_ot_shape_context_t *c)
/* Visual fallback goes here. */
- if (fallback)
+ if (c->fallback_positioning)
_hb_ot_shape_fallback_kern (c->plan, c->font, c->buffer);
_hb_buffer_deallocate_gsubgpos_vars (c->buffer);
@@ -748,6 +793,11 @@ hb_ot_shape_internal (hb_ot_shape_context_t *c)
(unsigned) HB_BUFFER_MAX_LEN_MIN);
}
+ bool disable_otl = c->plan->shaper->disable_otl && c->plan->shaper->disable_otl (c->plan);
+ //c->fallback_substitute = disable_otl || !hb_ot_layout_has_substitution (c->face);
+ c->fallback_positioning = disable_otl || !hb_ot_layout_has_positioning (c->face);
+ c->fallback_glyph_classes = disable_otl || !hb_ot_layout_has_glyph_classes (c->face);
+
/* Save the original direction, we use it later. */
c->target_direction = c->buffer->props.direction;
diff --git a/src/hb-ot-tag.cc b/src/hb-ot-tag.cc
index 5f21ac096..9b0db507b 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 @@ static const LangTag ot_languages[] = {
{"alt", HB_TAG('A','L','T',' ')}, /* [Southern] Altai */
{"am", HB_TAG('A','M','H',' ')}, /* Amharic */
{"amf", HB_TAG('H','B','N',' ')}, /* Hammer-Banna */
+ {"amw", HB_TAG('S','Y','R',' ')}, /* Western Neo-Aramaic */
{"an", HB_TAG('A','R','G',' ')}, /* Aragonese */
{"ang", HB_TAG('A','N','G',' ')}, /* Old English (ca. 450-1100) */
{"ar", HB_TAG('A','R','A',' ')}, /* Arabic [macrolanguage] */
@@ -239,6 +237,7 @@ static const LangTag ot_languages[] = {
{"bg", HB_TAG('B','G','R',' ')}, /* Bulgarian */
{"bgc", HB_TAG('B','G','C',' ')}, /* Haryanvi */
{"bgq", HB_TAG('B','G','Q',' ')}, /* Bagri */
+ {"bgr", HB_TAG('Q','I','N',' ')}, /* Bawm Chin */
{"bhb", HB_TAG('B','H','I',' ')}, /* Bhili */
{"bhk", HB_TAG('B','I','K',' ')}, /* Albay Bicolano (retired code) */
{"bho", HB_TAG('B','H','O',' ')}, /* Bhojpuri */
@@ -270,8 +269,10 @@ static const LangTag ot_languages[] = {
{"ca", HB_TAG('C','A','T',' ')}, /* Catalan */
{"cak", HB_TAG('C','A','K',' ')}, /* Kaqchikel */
{"cbk", HB_TAG('C','B','K',' ')}, /* Chavacano */
+ {"cbl", HB_TAG('Q','I','N',' ')}, /* Bualkhaw Chin */
{"ce", HB_TAG('C','H','E',' ')}, /* Chechen */
{"ceb", HB_TAG('C','E','B',' ')}, /* Cebuano */
+ {"cfm", HB_TAG('H','A','L',' ')}, /* Halam/Falam Chin */
{"cgg", HB_TAG('C','G','G',' ')}, /* Chiga */
{"ch", HB_TAG('C','H','A',' ')}, /* Chamorro */
{"chk", HB_TAG('C','H','K','0')}, /* Chuukese */
@@ -279,8 +280,17 @@ static const LangTag ot_languages[] = {
{"chp", HB_TAG('C','H','P',' ')}, /* Chipewyan */
{"chr", HB_TAG('C','H','R',' ')}, /* Cherokee */
{"chy", HB_TAG('C','H','Y',' ')}, /* Cheyenne */
+ {"cja", HB_TAG('C','J','A',' ')}, /* Western Cham */
+ {"cjm", HB_TAG('C','J','M',' ')}, /* Eastern Cham */
+ {"cka", HB_TAG('Q','I','N',' ')}, /* Khumi Awa Chin */
{"ckb", HB_TAG('K','U','R',' ')}, /* Central Kurdish (Sorani) */
{"ckt", HB_TAG('C','H','K',' ')}, /* Chukchi */
+ {"cld", HB_TAG('S','Y','R',' ')}, /* Chaldean Neo-Aramaic */
+ {"cmr", HB_TAG('Q','I','N',' ')}, /* Mro-Khimi Chin */
+ {"cnb", HB_TAG('Q','I','N',' ')}, /* Chinbon Chin */
+ {"cnh", HB_TAG('Q','I','N',' ')}, /* Hakha Chin */
+ {"cnk", HB_TAG('Q','I','N',' ')}, /* Khumi Chin */
+ {"cnw", HB_TAG('Q','I','N',' ')}, /* Ngawn Chin */
{"cop", HB_TAG('C','O','P',' ')}, /* Coptic */
{"cpp", HB_TAG('C','P','P',' ')}, /* Creoles */
{"cr", HB_TAG('C','R','E',' ')}, /* Cree */
@@ -293,6 +303,9 @@ static const LangTag ot_languages[] = {
{"crx", HB_TAG('C','R','R',' ')}, /* Carrier */
{"cs", HB_TAG('C','S','Y',' ')}, /* Czech */
{"csb", HB_TAG('C','S','B',' ')}, /* Kashubian */
+ {"csh", HB_TAG('Q','I','N',' ')}, /* Asho Chin */
+ {"csy", HB_TAG('Q','I','N',' ')}, /* Siyin Chin */
+ {"ctd", HB_TAG('Q','I','N',' ')}, /* Tedim Chin */
{"ctg", HB_TAG('C','T','G',' ')}, /* Chittagonian */
{"cts", HB_TAG('B','I','K',' ')}, /* Northern Catanduanes Bikol */
{"cu", HB_TAG('C','S','L',' ')}, /* Church Slavic */
@@ -300,7 +313,9 @@ static const LangTag ot_languages[] = {
{"cv", HB_TAG('C','H','U',' ')}, /* Chuvash */
{"cwd", HB_TAG('D','C','R',' ')}, /* Woods Cree */
{"cy", HB_TAG('W','E','L',' ')}, /* Welsh */
+ {"czt", HB_TAG('Q','I','N',' ')}, /* Zotung Chin */
{"da", HB_TAG('D','A','N',' ')}, /* Danish */
+ {"dao", HB_TAG('Q','I','N',' ')}, /* Daai Chin */
{"dap", HB_TAG('N','I','S',' ')}, /* Nisi (India) */
{"dar", HB_TAG('D','A','R',' ')}, /* Dargwa */
{"dax", HB_TAG('D','A','X',' ')}, /* Dayi */
@@ -343,7 +358,7 @@ static const LangTag ot_languages[] = {
{"fi", HB_TAG('F','I','N',' ')}, /* Finnish */
{"fil", HB_TAG('P','I','L',' ')}, /* Filipino */
{"fj", HB_TAG('F','J','I',' ')}, /* Fijian */
- {"flm", HB_TAG('H','A','L',' ')}, /* Halam */
+ {"flm", HB_TAG('H','A','L',' ')}, /* Halam/Falam Chin [retired ISO639 code] */
{"fo", HB_TAG('F','O','S',' ')}, /* Faroese */
{"fon", HB_TAG('F','O','N',' ')}, /* Fon */
{"fr", HB_TAG('F','R','A',' ')}, /* French */
@@ -390,6 +405,7 @@ static const LangTag ot_languages[] = {
{"he", HB_TAG('I','W','R',' ')}, /* Hebrew */
{"hi", HB_TAG('H','I','N',' ')}, /* Hindi */
{"hil", HB_TAG('H','I','L',' ')}, /* Hiligaynon */
+ {"hlt", HB_TAG('Q','I','N',' ')}, /* Matu Chin */
{"hmn", HB_TAG('H','M','N',' ')}, /* Hmong */
{"hnd", HB_TAG('H','N','D',' ')}, /* [Southern] Hindko */
{"hne", HB_TAG('C','H','H',' ')}, /* Chattisgarhi */
@@ -553,6 +569,7 @@ static const LangTag ot_languages[] = {
{"mos", HB_TAG('M','O','S',' ')}, /* Mossi */
{"mpe", HB_TAG('M','A','J',' ')}, /* Majang */
{"mr", HB_TAG('M','A','R',' ')}, /* Marathi */
+ {"mrh", HB_TAG('Q','I','N',' ')}, /* Mara Chin */
{"mrj", HB_TAG('H','M','A',' ')}, /* High Mari */
{"ms", HB_TAG('M','L','Y',' ')}, /* Malay [macrolanguage] */
{"msc", HB_TAG('M','N','K',' ')}, /* Sankaran Maninka */
@@ -617,6 +634,7 @@ static const LangTag ot_languages[] = {
{"pcc", HB_TAG('P','C','C',' ')}, /* Bouyei */
{"pcd", HB_TAG('P','C','D',' ')}, /* Picard */
{"pce", HB_TAG('P','L','G',' ')}, /* [Ruching] Palaung */
+ {"pck", HB_TAG('Q','I','N',' ')}, /* Paite Chin */
{"pdc", HB_TAG('P','D','C',' ')}, /* Pennsylvania German */
{"pes", HB_TAG('F','A','R',' ')}, /* Iranian Persian */
{"phk", HB_TAG('P','H','K',' ')}, /* Phake */
@@ -674,6 +692,7 @@ static const LangTag ot_languages[] = {
{"se", HB_TAG('N','S','M',' ')}, /* Northern Sami */
{"seh", HB_TAG('S','N','A',' ')}, /* Sena */
{"sel", HB_TAG('S','E','L',' ')}, /* Selkup */
+ {"sez", HB_TAG('Q','I','N',' ')}, /* Senthang Chin */
{"sg", HB_TAG('S','G','O',' ')}, /* Sango */
{"sga", HB_TAG('S','G','A',' ')}, /* Old Irish (to 900) */
{"sgs", HB_TAG('S','G','S',' ')}, /* Samogitian */
@@ -713,12 +732,15 @@ static const LangTag ot_languages[] = {
{"swh", HB_TAG('S','W','K',' ')}, /* Kiswahili/Swahili */
{"swv", HB_TAG('M','A','W',' ')}, /* Shekhawati */
{"sxu", HB_TAG('S','X','U',' ')}, /* Upper Saxon */
+ {"syc", HB_TAG('S','Y','R',' ')}, /* Classical Syriac */
{"syl", HB_TAG('S','Y','L',' ')}, /* Sylheti */
{"syr", HB_TAG('S','Y','R',' ')}, /* Syriac [macrolanguage] */
{"szl", HB_TAG('S','Z','L',' ')}, /* Silesian */
{"ta", HB_TAG('T','A','M',' ')}, /* Tamil */
{"tab", HB_TAG('T','A','B',' ')}, /* Tabasaran */
+ {"tcp", HB_TAG('Q','I','N',' ')}, /* Tawr Chin */
{"tcy", HB_TAG('T','U','L',' ')}, /* Tulu */
+ {"tcz", HB_TAG('Q','I','N',' ')}, /* Thado Chin */
{"tdd", HB_TAG('T','D','D',' ')}, /* Tai Nüa */
{"te", HB_TAG('T','E','L',' ')}, /* Telugu */
{"tem", HB_TAG('T','M','N',' ')}, /* Temne */
@@ -786,11 +808,13 @@ static const LangTag ot_languages[] = {
{"yap", HB_TAG('Y','A','P',' ')}, /* Yapese */
{"yi", HB_TAG('J','I','I',' ')}, /* Yiddish [macrolanguage] */
{"yo", HB_TAG('Y','B','A',' ')}, /* Yoruba */
+ {"yos", HB_TAG('Q','I','N',' ')}, /* Yos, deprecated by IANA in favor of Zou [zom] */
{"yso", HB_TAG('N','I','S',' ')}, /* Nisi (China) */
{"za", HB_TAG('Z','H','A',' ')}, /* Chuang/Zhuang [macrolanguage] */
{"zea", HB_TAG('Z','E','A',' ')}, /* Zeeuws */
{"zgh", HB_TAG('Z','G','H',' ')}, /* Standard Morrocan Tamazigh */
{"zne", HB_TAG('Z','N','D',' ')}, /* Zande */
+ {"zom", HB_TAG('Q','I','N',' ')}, /* Zou */
{"zu", HB_TAG('Z','U','L',' ')}, /* Zulu */
{"zum", HB_TAG('L','R','C',' ')}, /* Kumzari */
{"zza", HB_TAG('Z','Z','A',' ')}, /* Zazaki */
@@ -907,6 +931,30 @@ hb_ot_tag_from_language (hb_language_t language)
return HB_TAG('A','P','P','H'); /* Phonetic transcription—Americanist conventions */
}
+ /*
+ * "Syre" is a BCP-47 script tag, meaning the Estrangela variant of the Syriac script.
+ * It can be applied to any language.
+ */
+ if (strstr (lang_str, "-syre")) {
+ return HB_TAG('S','Y','R','E'); /* Estrangela Syriac */
+ }
+
+ /*
+ * "Syrj" is a BCP-47 script tag, meaning the Western variant of the Syriac script.
+ * It can be applied to any language.
+ */
+ if (strstr (lang_str, "-syrj")) {
+ return HB_TAG('S','Y','R','J'); /* Western Syriac */
+ }
+
+ /*
+ * "Syrn" is a BCP-47 script tag, meaning the Eastern variant of the Syriac script.
+ * It can be applied to any language.
+ */
+ if (strstr (lang_str, "-syrn")) {
+ return HB_TAG('S','Y','R','N'); /* Eastern Syriac */
+ }
+
/* Find a language matching in the first component */
{
const LangTag *lang_tag;
@@ -962,6 +1010,22 @@ hb_ot_tag_to_language (hb_tag_t tag)
if (tag == HB_OT_TAG_DEFAULT_LANGUAGE)
return NULL;
+ /* struct LangTag has only room for 3-letter language tags. */
+ switch (tag) {
+ case HB_TAG('A','P','P','H'): /* Phonetic transcription—Americanist conventions */
+ return hb_language_from_string ("und-fonnapa", -1);
+ case HB_TAG('I','P','P','H'): /* Phonetic transcription—IPA conventions */
+ return hb_language_from_string ("und-fonipa", -1);
+ case HB_TAG('S','Y','R',' '): /* Syriac [macrolanguage] */
+ return hb_language_from_string ("syr", -1);
+ case HB_TAG('S','Y','R','E'): /* Estrangela Syriac */
+ return hb_language_from_string ("und-Syre", -1);
+ case HB_TAG('S','Y','R','J'): /* Western Syriac */
+ return hb_language_from_string ("und-Syrj", -1);
+ case HB_TAG('S','Y','R','N'): /* Eastern Syriac */
+ return hb_language_from_string ("und-Syrn", -1);
+ }
+
for (i = 0; i < ARRAY_LENGTH (ot_languages); i++)
if (ot_languages[i].tag == tag)
return hb_language_from_string (ot_languages[i].language, -1);
@@ -976,14 +1040,6 @@ hb_ot_tag_to_language (hb_tag_t tag)
}
}
- /* struct LangTag has only room for 3-letter language tags. */
- switch (tag) {
- case HB_TAG('A','P','P','H'): /* Phonetic transcription—Americanist conventions */
- return hb_language_from_string ("und-fonnapa", -1);
- case HB_TAG('I','P','P','H'): /* Phonetic transcription—IPA conventions */
- return hb_language_from_string ("und-fonipa", -1);
- }
-
/* Else return a custom language in the form of "x-hbotABCD" */
{
unsigned char buf[11] = "x-hbot";
diff --git a/src/hb-ot-var-avar-table.hh b/src/hb-ot-var-avar-table.hh
new file mode 100644
index 000000000..ace0f5f28
--- /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 000000000..9f6fb3250
--- /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 000000000..3a2a82037
--- /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.cc b/src/hb-ot-var.cc
new file mode 100644
index 000000000..d4d16dfff
--- /dev/null
+++ b/src/hb-ot-var.cc
@@ -0,0 +1,160 @@
+/*
+ * 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.h"
+
+HB_SHAPER_DATA_ENSURE_DECLARE(ot, face)
+
+/*
+ * 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 000000000..a2c0c5f2b
--- /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 47c92a58e..2120a3efa 100644
--- a/src/hb-ot.h
+++ b/src/hb-ot.h
@@ -32,8 +32,10 @@
#include "hb-ot-font.h"
#include "hb-ot-layout.h"
+#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-private.hh b/src/hb-private.hh
index c45be6f2f..666af6260 100644
--- a/src/hb-private.hh
+++ b/src/hb-private.hh
@@ -689,17 +689,20 @@ _hb_debug_msg_va (const char *what,
fprintf (stderr, " %*s ", (unsigned int) (2 * sizeof (void *)), "");
if (indented) {
-/* One may want to add ASCII version of these. See:
- * https://bugs.freedesktop.org/show_bug.cgi?id=50970 */
#define VBAR "\342\224\202" /* U+2502 BOX DRAWINGS LIGHT VERTICAL */
#define VRBAR "\342\224\234" /* U+251C BOX DRAWINGS LIGHT VERTICAL AND RIGHT */
#define DLBAR "\342\225\256" /* U+256E BOX DRAWINGS LIGHT ARC DOWN AND LEFT */
#define ULBAR "\342\225\257" /* U+256F BOX DRAWINGS LIGHT ARC UP AND LEFT */
#define LBAR "\342\225\264" /* U+2574 BOX DRAWINGS LIGHT LEFT */
- static const char bars[] = VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR;
+ static const char bars[] =
+ VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR
+ VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR
+ VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR
+ VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR
+ VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR;
fprintf (stderr, "%2u %s" VRBAR "%s",
level,
- bars + sizeof (bars) - 1 - MIN ((unsigned int) sizeof (bars), (unsigned int) (sizeof (VBAR) - 1) * level),
+ bars + sizeof (bars) - 1 - MIN ((unsigned int) sizeof (bars) - 1, (unsigned int) (sizeof (VBAR) - 1) * level),
level_dir ? (level_dir > 0 ? DLBAR : ULBAR) : LBAR);
} else
fprintf (stderr, " " VRBAR LBAR);
diff --git a/src/hb-set.cc b/src/hb-set.cc
index cb7fcdbf6..f3fe1ba43 100644
--- a/src/hb-set.cc
+++ b/src/hb-set.cc
@@ -105,7 +105,7 @@ hb_set_destroy (hb_set_t *set)
* @set: a set.
* @key:
* @data:
- * @destroy (closure data):
+ * @destroy:
* @replace:
*
* Return value:
diff --git a/src/hb-shape-plan-private.hh b/src/hb-shape-plan-private.hh
index 607da5e77..aa0413a27 100644
--- a/src/hb-shape-plan-private.hh
+++ b/src/hb-shape-plan-private.hh
@@ -47,12 +47,17 @@ struct hb_shape_plan_t
hb_feature_t *user_features;
unsigned int num_user_features;
+ int *coords;
+ unsigned int num_coords;
+
struct hb_shaper_data_t shaper_data;
};
#define HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS \
- , const hb_feature_t *user_features \
- , unsigned int num_user_features
+ , const hb_feature_t *user_features \
+ , unsigned int num_user_features \
+ , const int *coords \
+ , unsigned int num_coords
#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_PROTOTYPE(shaper, shape_plan);
#include "hb-shaper-list.hh"
#undef HB_SHAPER_IMPLEMENT
diff --git a/src/hb-shape-plan.cc b/src/hb-shape-plan.cc
index 87231fb33..600faaeb1 100644
--- a/src/hb-shape-plan.cc
+++ b/src/hb-shape-plan.cc
@@ -46,11 +46,14 @@ static void
hb_shape_plan_plan (hb_shape_plan_t *shape_plan,
const hb_feature_t *user_features,
unsigned int num_user_features,
+ const int *coords,
+ unsigned int num_coords,
const char * const *shaper_list)
{
DEBUG_MSG_FUNC (SHAPE_PLAN, shape_plan,
- "num_features=%d shaper_list=%p",
+ "num_features=%d num_coords=%d shaper_list=%p",
num_user_features,
+ num_coords,
shaper_list);
const hb_shaper_pair_t *shapers = _hb_shapers_get ();
@@ -59,7 +62,9 @@ hb_shape_plan_plan (hb_shape_plan_t *shape_plan,
HB_STMT_START { \
if (hb_##shaper##_shaper_face_data_ensure (shape_plan->face_unsafe)) { \
HB_SHAPER_DATA (shaper, shape_plan) = \
- HB_SHAPER_DATA_CREATE_FUNC (shaper, shape_plan) (shape_plan, user_features, num_user_features); \
+ HB_SHAPER_DATA_CREATE_FUNC (shaper, shape_plan) (shape_plan, \
+ user_features, num_user_features, \
+ coords, num_coords); \
shape_plan->shaper_func = _hb_##shaper##_shape; \
shape_plan->shaper_name = #shaper; \
return; \
@@ -115,14 +120,31 @@ hb_shape_plan_create (hb_face_t *face,
unsigned int num_user_features,
const char * const *shaper_list)
{
+ return hb_shape_plan_create2 (face, props,
+ user_features, num_user_features,
+ NULL, 0,
+ shaper_list);
+}
+
+hb_shape_plan_t *
+hb_shape_plan_create2 (hb_face_t *face,
+ const hb_segment_properties_t *props,
+ const hb_feature_t *user_features,
+ unsigned int num_user_features,
+ const int *orig_coords,
+ unsigned int num_coords,
+ const char * const *shaper_list)
+{
DEBUG_MSG_FUNC (SHAPE_PLAN, NULL,
- "face=%p num_features=%d shaper_list=%p",
+ "face=%p num_features=%d num_coords=%d shaper_list=%p",
face,
num_user_features,
+ num_coords,
shaper_list);
hb_shape_plan_t *shape_plan;
hb_feature_t *features = NULL;
+ int *coords = NULL;
if (unlikely (!face))
face = hb_face_get_empty ();
@@ -130,7 +152,14 @@ hb_shape_plan_create (hb_face_t *face,
return hb_shape_plan_get_empty ();
if (num_user_features && !(features = (hb_feature_t *) calloc (num_user_features, sizeof (hb_feature_t))))
return hb_shape_plan_get_empty ();
- if (!(shape_plan = hb_object_create<hb_shape_plan_t> ())) {
+ if (num_coords && !(coords = (int *) calloc (num_coords, sizeof (int))))
+ {
+ free (features);
+ return hb_shape_plan_get_empty ();
+ }
+ if (!(shape_plan = hb_object_create<hb_shape_plan_t> ()))
+ {
+ free (coords);
free (features);
return hb_shape_plan_get_empty ();
}
@@ -145,8 +174,15 @@ hb_shape_plan_create (hb_face_t *face,
shape_plan->user_features = features;
if (num_user_features)
memcpy (features, user_features, num_user_features * sizeof (hb_feature_t));
+ shape_plan->num_coords = num_coords;
+ shape_plan->coords = coords;
+ if (num_coords)
+ memcpy (coords, orig_coords, num_coords * sizeof (int));
- hb_shape_plan_plan (shape_plan, user_features, num_user_features, shaper_list);
+ hb_shape_plan_plan (shape_plan,
+ user_features, num_user_features,
+ coords, num_coords,
+ shaper_list);
return shape_plan;
}
@@ -176,6 +212,9 @@ hb_shape_plan_get_empty (void)
NULL, /* user_features */
0, /* num_user_featurs */
+ NULL, /* coords */
+ 0, /* num_coords */
+
{
#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INVALID,
#include "hb-shaper-list.hh"
@@ -220,6 +259,7 @@ hb_shape_plan_destroy (hb_shape_plan_t *shape_plan)
#undef HB_SHAPER_IMPLEMENT
free (shape_plan->user_features);
+ free (shape_plan->coords);
free (shape_plan);
}
@@ -351,6 +391,8 @@ struct hb_shape_plan_proposal_t
const char * const *shaper_list;
const hb_feature_t *user_features;
unsigned int num_user_features;
+ const int *coords;
+ unsigned int num_coords;
hb_shape_func_t *shaper_func;
};
@@ -358,12 +400,26 @@ static inline hb_bool_t
hb_shape_plan_user_features_match (const hb_shape_plan_t *shape_plan,
const hb_shape_plan_proposal_t *proposal)
{
- if (proposal->num_user_features != shape_plan->num_user_features) return false;
+ if (proposal->num_user_features != shape_plan->num_user_features)
+ return false;
for (unsigned int i = 0, n = proposal->num_user_features; i < n; i++)
if (proposal->user_features[i].tag != shape_plan->user_features[i].tag ||
proposal->user_features[i].value != shape_plan->user_features[i].value ||
proposal->user_features[i].start != shape_plan->user_features[i].start ||
- proposal->user_features[i].end != shape_plan->user_features[i].end) return false;
+ proposal->user_features[i].end != shape_plan->user_features[i].end)
+ return false;
+ return true;
+}
+
+static inline hb_bool_t
+hb_shape_plan_coords_match (const hb_shape_plan_t *shape_plan,
+ const hb_shape_plan_proposal_t *proposal)
+{
+ if (proposal->num_coords != shape_plan->num_coords)
+ return false;
+ for (unsigned int i = 0, n = proposal->num_coords; i < n; i++)
+ if (proposal->coords[i] != shape_plan->coords[i])
+ return false;
return true;
}
@@ -373,6 +429,7 @@ hb_shape_plan_matches (const hb_shape_plan_t *shape_plan,
{
return hb_segment_properties_equal (&shape_plan->props, &proposal->props) &&
hb_shape_plan_user_features_match (shape_plan, proposal) &&
+ hb_shape_plan_coords_match (shape_plan, proposal) &&
((shape_plan->default_shaper_list && proposal->shaper_list == NULL) ||
(shape_plan->shaper_func == proposal->shaper_func));
}
@@ -389,6 +446,13 @@ hb_non_global_user_features_present (const hb_feature_t *user_features,
return false;
}
+static inline hb_bool_t
+hb_coords_present (const int *coords,
+ unsigned int num_coords)
+{
+ return num_coords != 0;
+}
+
/**
* hb_shape_plan_create_cached:
* @face:
@@ -410,6 +474,21 @@ hb_shape_plan_create_cached (hb_face_t *face,
unsigned int num_user_features,
const char * const *shaper_list)
{
+ return hb_shape_plan_create_cached2 (face, props,
+ user_features, num_user_features,
+ NULL, 0,
+ shaper_list);
+}
+
+hb_shape_plan_t *
+hb_shape_plan_create_cached2 (hb_face_t *face,
+ const hb_segment_properties_t *props,
+ const hb_feature_t *user_features,
+ unsigned int num_user_features,
+ const int *coords,
+ unsigned int num_coords,
+ const char * const *shaper_list)
+{
DEBUG_MSG_FUNC (SHAPE_PLAN, NULL,
"face=%p num_features=%d shaper_list=%p",
face,
@@ -456,16 +535,21 @@ retry:
/* Not found. */
- hb_shape_plan_t *shape_plan = hb_shape_plan_create (face, props, user_features, num_user_features, shaper_list);
+ hb_shape_plan_t *shape_plan = hb_shape_plan_create2 (face, props,
+ user_features, num_user_features,
+ coords, num_coords,
+ shaper_list);
/* Don't add to the cache if face is inert. */
if (unlikely (hb_object_is_inert (face)))
return shape_plan;
/* Don't add the plan to the cache if there were user features with non-global ranges */
-
if (hb_non_global_user_features_present (user_features, num_user_features))
return shape_plan;
+ /* Don't add the plan to the cache if there were variation coordinates XXX Fix me. */
+ if (hb_coords_present (coords, num_coords))
+ return shape_plan;
hb_face_t::plan_node_t *node = (hb_face_t::plan_node_t *) calloc (1, sizeof (hb_face_t::plan_node_t));
if (unlikely (!node))
diff --git a/src/hb-shape-plan.h b/src/hb-shape-plan.h
index aa5e0c7d6..b62ae7ca3 100644
--- a/src/hb-shape-plan.h
+++ b/src/hb-shape-plan.h
@@ -53,6 +53,25 @@ hb_shape_plan_create_cached (hb_face_t *face,
const char * const *shaper_list);
HB_EXTERN hb_shape_plan_t *
+hb_shape_plan_create2 (hb_face_t *face,
+ const hb_segment_properties_t *props,
+ const hb_feature_t *user_features,
+ unsigned int num_user_features,
+ const int *coords,
+ unsigned int num_coords,
+ const char * const *shaper_list);
+
+HB_EXTERN hb_shape_plan_t *
+hb_shape_plan_create_cached2 (hb_face_t *face,
+ const hb_segment_properties_t *props,
+ const hb_feature_t *user_features,
+ unsigned int num_user_features,
+ const int *coords,
+ unsigned int num_coords,
+ const char * const *shaper_list);
+
+
+HB_EXTERN hb_shape_plan_t *
hb_shape_plan_get_empty (void);
HB_EXTERN hb_shape_plan_t *
diff --git a/src/hb-shape.cc b/src/hb-shape.cc
index 41a4fc500..f080a15e3 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 @@ retry:
* shapers will be used in the given order, otherwise the default shapers list
* will be used.
*
- * Return value: %FALSE if all shapers failed, %TRUE otherwise
+ * Return value: false if all shapers failed, true otherwise
*
* Since: 0.9.2
**/
@@ -373,7 +125,10 @@ hb_shape_full (hb_font_t *font,
unsigned int num_features,
const char * const *shaper_list)
{
- hb_shape_plan_t *shape_plan = hb_shape_plan_create_cached (font->face, &buffer->props, features, num_features, shaper_list);
+ hb_shape_plan_t *shape_plan = hb_shape_plan_create_cached2 (font->face, &buffer->props,
+ features, num_features,
+ font->coords, font->num_coords,
+ shaper_list);
hb_bool_t res = hb_shape_plan_execute (shape_plan, font, buffer, features, num_features);
hb_shape_plan_destroy (shape_plan);
diff --git a/src/hb-shape.h b/src/hb-shape.h
index 53bb845bf..39507ff74 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-unicode.cc b/src/hb-unicode.cc
index 487d10b93..d553a7172 100644
--- a/src/hb-unicode.cc
+++ b/src/hb-unicode.cc
@@ -131,12 +131,12 @@ hb_unicode_funcs_get_default (void)
#define HB_UNICODE_FUNCS_IMPLEMENT(set) \
return hb_##set##_get_unicode_funcs ();
-#ifdef HAVE_GLIB
+#if defined(HAVE_UCDN)
+ HB_UNICODE_FUNCS_IMPLEMENT(ucdn)
+#elif defined(HAVE_GLIB)
HB_UNICODE_FUNCS_IMPLEMENT(glib)
#elif defined(HAVE_ICU) && defined(HAVE_ICU_BUILTIN)
HB_UNICODE_FUNCS_IMPLEMENT(icu)
-#elif defined(HAVE_UCDN)
- HB_UNICODE_FUNCS_IMPLEMENT(ucdn)
#else
#define HB_UNICODE_FUNCS_NIL 1
HB_UNICODE_FUNCS_IMPLEMENT(nil)
diff --git a/src/hb-uniscribe.cc b/src/hb-uniscribe.cc
index 07007a640..6e4db0149 100644
--- a/src/hb-uniscribe.cc
+++ b/src/hb-uniscribe.cc
@@ -587,7 +587,9 @@ struct hb_uniscribe_shaper_shape_plan_data_t {};
hb_uniscribe_shaper_shape_plan_data_t *
_hb_uniscribe_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan HB_UNUSED,
const hb_feature_t *user_features HB_UNUSED,
- unsigned int num_user_features HB_UNUSED)
+ unsigned int num_user_features HB_UNUSED,
+ const int *coords HB_UNUSED,
+ unsigned int num_coords HB_UNUSED)
{
return (hb_uniscribe_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
}
diff --git a/src/hb-version.h b/src/hb-version.h
index bf199ce62..df83a8afe 100644
--- a/src/hb-version.h
+++ b/src/hb-version.h
@@ -37,10 +37,10 @@ HB_BEGIN_DECLS
#define HB_VERSION_MAJOR 1
-#define HB_VERSION_MINOR 3
+#define HB_VERSION_MINOR 4
#define HB_VERSION_MICRO 2
-#define HB_VERSION_STRING "1.3.2"
+#define HB_VERSION_STRING "1.4.2"
#define HB_VERSION_ATLEAST(major,minor,micro) \
((major)*10000+(minor)*100+(micro) <= \
diff --git a/test/api/Makefile.am b/test/api/Makefile.am
index d7d40af39..530bf3ede 100644
--- a/test/api/Makefile.am
+++ b/test/api/Makefile.am
@@ -43,10 +43,29 @@ endif
if HAVE_OT
+
TEST_PROGS += \
test-ot-tag \
$(NULL)
-endif
+
+if HAVE_FREETYPE
+TEST_PROGS += \
+ test-ot-math \
+ $(NULL)
+test_ot_math_LDADD = $(LDADD) $(FREETYPE_LIBS)
+test_ot_math_CPPFLAGS = $(AM_CPPFLAGS) $(FREETYPE_CFLAGS)
+EXTRA_DIST += \
+ fonts/MathTestFontEmpty.otf \
+ fonts/MathTestFontFull.otf \
+ fonts/MathTestFontNone.otf \
+ fonts/MathTestFontPartial1.otf \
+ fonts/MathTestFontPartial2.otf \
+ fonts/MathTestFontPartial3.otf \
+ fonts/MathTestFontPartial4.otf \
+ $(NULL)
+endif # HAVE_FREETYPE
+
+endif # HAVE_OT
# Tests for header compilation
TEST_PROGS += \
@@ -73,6 +92,8 @@ TESTS_ENVIRONMENT = \
G_DEBUG=gc-friendly \
G_SLICE=always-malloc \
srcdir=$(srcdir) \
+ G_TEST_SRCDIR=$(abs_srcdir) \
+ G_TEST_BUILDDIR=$(abs_builddir) \
$(NULL)
diff --git a/test/api/fonts/MathTestFontEmpty.otf b/test/api/fonts/MathTestFontEmpty.otf
new file mode 100644
index 000000000..6b50d66fc
--- /dev/null
+++ b/test/api/fonts/MathTestFontEmpty.otf
Binary files differ
diff --git a/test/api/fonts/MathTestFontFull.otf b/test/api/fonts/MathTestFontFull.otf
new file mode 100644
index 000000000..6c7c9a951
--- /dev/null
+++ b/test/api/fonts/MathTestFontFull.otf
Binary files differ
diff --git a/test/api/fonts/MathTestFontNone.otf b/test/api/fonts/MathTestFontNone.otf
new file mode 100644
index 000000000..52984eecc
--- /dev/null
+++ b/test/api/fonts/MathTestFontNone.otf
Binary files differ
diff --git a/test/api/fonts/MathTestFontPartial1.otf b/test/api/fonts/MathTestFontPartial1.otf
new file mode 100644
index 000000000..b3bf36e33
--- /dev/null
+++ b/test/api/fonts/MathTestFontPartial1.otf
Binary files differ
diff --git a/test/api/fonts/MathTestFontPartial2.otf b/test/api/fonts/MathTestFontPartial2.otf
new file mode 100644
index 000000000..4607c1128
--- /dev/null
+++ b/test/api/fonts/MathTestFontPartial2.otf
Binary files differ
diff --git a/test/api/fonts/MathTestFontPartial3.otf b/test/api/fonts/MathTestFontPartial3.otf
new file mode 100644
index 000000000..ca18a9a22
--- /dev/null
+++ b/test/api/fonts/MathTestFontPartial3.otf
Binary files differ
diff --git a/test/api/fonts/MathTestFontPartial4.otf b/test/api/fonts/MathTestFontPartial4.otf
new file mode 100644
index 000000000..cda3057f8
--- /dev/null
+++ b/test/api/fonts/MathTestFontPartial4.otf
Binary files differ
diff --git a/test/api/test-ot-math.c b/test/api/test-ot-math.c
new file mode 100644
index 000000000..0ca5566df
--- /dev/null
+++ b/test/api/test-ot-math.c
@@ -0,0 +1,712 @@
+/*
+ * Copyright © 2016 Igalia S.L.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Igalia Author(s): Frédéric Wang
+ */
+
+
+#include "hb-test.h"
+
+#include "hb-ft.h"
+#include "hb-ot.h"
+
+/* Unit tests for hb-ot-math.h - OpenType MATH table */
+
+static FT_Library ft_library;
+static FT_Face ft_face;
+static hb_font_t *hb_font;
+static hb_face_t *hb_face;
+
+static inline void
+initFreeType (void)
+{
+ FT_Error ft_error;
+ if ((ft_error = FT_Init_FreeType (&ft_library)))
+ abort();
+}
+
+static inline void
+cleanupFreeType (void)
+{
+ FT_Done_FreeType (ft_library);
+}
+
+static void
+openFont(const char* fontFile)
+{
+#if GLIB_CHECK_VERSION(2,37,2)
+ gchar* path = g_test_build_filename(G_TEST_DIST, fontFile, NULL);
+#else
+ gchar* path = g_strdup(fontFile);
+#endif
+
+ FT_Error ft_error;
+ if ((ft_error = FT_New_Face (ft_library, path, 0, &ft_face))) {
+ g_free(path);
+ abort();
+ }
+ g_free(path);
+
+ 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_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
+test_has_data (void)
+{
+ initFreeType();
+
+ openFont("fonts/MathTestFontNone.otf");
+ g_assert(!hb_ot_math_has_data (hb_face)); // MATH table not available
+ closeFont();
+
+ openFont("fonts/MathTestFontEmpty.otf");
+ 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();
+}
+
+static void
+test_get_constant (void)
+{
+ initFreeType();
+
+ openFont("fonts/MathTestFontEmpty.otf");
+ g_assert_cmpint(hb_ot_math_get_constant (hb_font, HB_OT_MATH_CONSTANT_DELIMITED_SUB_FORMULA_MIN_HEIGHT), ==, 0); // MathConstants not available
+ closeFont();
+
+ openFont("fonts/MathTestFontFull.otf");
+ g_assert_cmpint((hb_ot_math_get_constant (hb_font, HB_OT_MATH_CONSTANT_DELIMITED_SUB_FORMULA_MIN_HEIGHT)), ==, 100);
+ g_assert_cmpint((hb_ot_math_get_constant (hb_font, HB_OT_MATH_CONSTANT_DISPLAY_OPERATOR_MIN_HEIGHT)), ==, 200);
+ g_assert_cmpint((hb_ot_math_get_constant (hb_font, HB_OT_MATH_CONSTANT_MATH_LEADING)), ==, 300);
+ g_assert_cmpint((hb_ot_math_get_constant (hb_font, HB_OT_MATH_CONSTANT_AXIS_HEIGHT)), ==, 400);
+ g_assert_cmpint((hb_ot_math_get_constant (hb_font, HB_OT_MATH_CONSTANT_ACCENT_BASE_HEIGHT)), ==, 500);
+ g_assert_cmpint((hb_ot_math_get_constant (hb_font, HB_OT_MATH_CONSTANT_FLATTENED_ACCENT_BASE_HEIGHT)), ==, 600);
+ g_assert_cmpint((hb_ot_math_get_constant (hb_font, HB_OT_MATH_CONSTANT_SUBSCRIPT_SHIFT_DOWN)), ==, 700);
+ g_assert_cmpint((hb_ot_math_get_constant (hb_font, HB_OT_MATH_CONSTANT_SUBSCRIPT_TOP_MAX)), ==, 800);
+ g_assert_cmpint((hb_ot_math_get_constant (hb_font, HB_OT_MATH_CONSTANT_SUBSCRIPT_BASELINE_DROP_MIN)), ==, 900);
+ g_assert_cmpint((hb_ot_math_get_constant (hb_font, HB_OT_MATH_CONSTANT_SUPERSCRIPT_SHIFT_UP)), ==, 1100);
+ g_assert_cmpint((hb_ot_math_get_constant (hb_font, HB_OT_MATH_CONSTANT_SUPERSCRIPT_SHIFT_UP_CRAMPED)), ==, 1200);
+ g_assert_cmpint((hb_ot_math_get_constant (hb_font, HB_OT_MATH_CONSTANT_SUPERSCRIPT_BOTTOM_MIN)), ==, 1300);
+ g_assert_cmpint((hb_ot_math_get_constant (hb_font, HB_OT_MATH_CONSTANT_SUPERSCRIPT_BASELINE_DROP_MAX)), ==, 1400);
+ g_assert_cmpint((hb_ot_math_get_constant (hb_font, HB_OT_MATH_CONSTANT_SUB_SUPERSCRIPT_GAP_MIN)), ==, 1500);
+ g_assert_cmpint((hb_ot_math_get_constant (hb_font, HB_OT_MATH_CONSTANT_SUPERSCRIPT_BOTTOM_MAX_WITH_SUBSCRIPT)), ==, 1600);
+ g_assert_cmpint((hb_ot_math_get_constant (hb_font, HB_OT_MATH_CONSTANT_SPACE_AFTER_SCRIPT)), ==, 3400);
+ g_assert_cmpint((hb_ot_math_get_constant (hb_font, HB_OT_MATH_CONSTANT_UPPER_LIMIT_GAP_MIN)), ==, 1800);
+ g_assert_cmpint((hb_ot_math_get_constant (hb_font, HB_OT_MATH_CONSTANT_UPPER_LIMIT_BASELINE_RISE_MIN)), ==, 1900);
+ g_assert_cmpint((hb_ot_math_get_constant (hb_font, HB_OT_MATH_CONSTANT_LOWER_LIMIT_GAP_MIN)), ==, 2200);
+ g_assert_cmpint((hb_ot_math_get_constant (hb_font, HB_OT_MATH_CONSTANT_LOWER_LIMIT_BASELINE_DROP_MIN)), ==, 2300);
+ g_assert_cmpint((hb_ot_math_get_constant (hb_font, HB_OT_MATH_CONSTANT_STACK_TOP_SHIFT_UP)), ==, 2400);
+ g_assert_cmpint((hb_ot_math_get_constant (hb_font, HB_OT_MATH_CONSTANT_STACK_TOP_DISPLAY_STYLE_SHIFT_UP)), ==, 2500);
+ g_assert_cmpint((hb_ot_math_get_constant (hb_font, HB_OT_MATH_CONSTANT_STACK_BOTTOM_SHIFT_DOWN)), ==, 2600);
+ g_assert_cmpint((hb_ot_math_get_constant (hb_font, HB_OT_MATH_CONSTANT_STACK_BOTTOM_DISPLAY_STYLE_SHIFT_DOWN)), ==, 2700);
+ g_assert_cmpint((hb_ot_math_get_constant (hb_font, HB_OT_MATH_CONSTANT_STACK_GAP_MIN)), ==, 2800);
+ g_assert_cmpint((hb_ot_math_get_constant (hb_font, HB_OT_MATH_CONSTANT_STACK_DISPLAY_STYLE_GAP_MIN)), ==, 2900);
+ g_assert_cmpint((hb_ot_math_get_constant (hb_font, HB_OT_MATH_CONSTANT_STRETCH_STACK_TOP_SHIFT_UP)), ==, 3000);
+ g_assert_cmpint((hb_ot_math_get_constant (hb_font, HB_OT_MATH_CONSTANT_STRETCH_STACK_BOTTOM_SHIFT_DOWN)), ==, 3100);
+ g_assert_cmpint((hb_ot_math_get_constant (hb_font, HB_OT_MATH_CONSTANT_STRETCH_STACK_GAP_ABOVE_MIN)), ==, 3200);
+ g_assert_cmpint((hb_ot_math_get_constant (hb_font, HB_OT_MATH_CONSTANT_STRETCH_STACK_GAP_BELOW_MIN)), ==, 3300);
+ g_assert_cmpint((hb_ot_math_get_constant (hb_font, HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_SHIFT_UP)), ==, 3400);
+ g_assert_cmpint((hb_ot_math_get_constant (hb_font, HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_DISPLAY_STYLE_SHIFT_UP)), ==, 3500);
+ g_assert_cmpint((hb_ot_math_get_constant (hb_font, HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_SHIFT_DOWN)), ==, 3600);
+ g_assert_cmpint((hb_ot_math_get_constant (hb_font, HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_DISPLAY_STYLE_SHIFT_DOWN)), ==, 3700);
+ g_assert_cmpint((hb_ot_math_get_constant (hb_font, HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_GAP_MIN)), ==, 3800);
+ g_assert_cmpint((hb_ot_math_get_constant (hb_font, HB_OT_MATH_CONSTANT_FRACTION_NUM_DISPLAY_STYLE_GAP_MIN)), ==, 3900);
+ g_assert_cmpint((hb_ot_math_get_constant (hb_font, HB_OT_MATH_CONSTANT_FRACTION_RULE_THICKNESS)), ==, 4000);
+ g_assert_cmpint((hb_ot_math_get_constant (hb_font, HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_GAP_MIN)), ==, 4100);
+ g_assert_cmpint((hb_ot_math_get_constant (hb_font, HB_OT_MATH_CONSTANT_FRACTION_DENOM_DISPLAY_STYLE_GAP_MIN)), ==, 4200);
+ g_assert_cmpint((hb_ot_math_get_constant (hb_font, HB_OT_MATH_CONSTANT_SKEWED_FRACTION_HORIZONTAL_GAP)), ==, 8600);
+ g_assert_cmpint((hb_ot_math_get_constant (hb_font, HB_OT_MATH_CONSTANT_SKEWED_FRACTION_VERTICAL_GAP)), ==, 4400);
+ g_assert_cmpint((hb_ot_math_get_constant (hb_font, HB_OT_MATH_CONSTANT_OVERBAR_VERTICAL_GAP)), ==, 4500);
+ g_assert_cmpint((hb_ot_math_get_constant (hb_font, HB_OT_MATH_CONSTANT_OVERBAR_RULE_THICKNESS)), ==, 4600);
+ g_assert_cmpint((hb_ot_math_get_constant (hb_font, HB_OT_MATH_CONSTANT_OVERBAR_EXTRA_ASCENDER)), ==, 4700);
+ g_assert_cmpint((hb_ot_math_get_constant (hb_font, HB_OT_MATH_CONSTANT_UNDERBAR_VERTICAL_GAP)), ==, 4800);
+ g_assert_cmpint((hb_ot_math_get_constant (hb_font, HB_OT_MATH_CONSTANT_UNDERBAR_RULE_THICKNESS)), ==, 4900);
+ g_assert_cmpint((hb_ot_math_get_constant (hb_font, HB_OT_MATH_CONSTANT_UNDERBAR_EXTRA_DESCENDER)), ==, 5000);
+ g_assert_cmpint((hb_ot_math_get_constant (hb_font, HB_OT_MATH_CONSTANT_RADICAL_VERTICAL_GAP)), ==, 5100);
+ g_assert_cmpint((hb_ot_math_get_constant (hb_font, HB_OT_MATH_CONSTANT_RADICAL_DISPLAY_STYLE_VERTICAL_GAP)), ==, 5200);
+ g_assert_cmpint((hb_ot_math_get_constant (hb_font, HB_OT_MATH_CONSTANT_RADICAL_RULE_THICKNESS)), ==, 5300);
+ g_assert_cmpint((hb_ot_math_get_constant (hb_font, HB_OT_MATH_CONSTANT_RADICAL_EXTRA_ASCENDER)), ==, 5400);
+ g_assert_cmpint((hb_ot_math_get_constant (hb_font, HB_OT_MATH_CONSTANT_RADICAL_KERN_BEFORE_DEGREE)), ==, 11000);
+ g_assert_cmpint((hb_ot_math_get_constant (hb_font, HB_OT_MATH_CONSTANT_RADICAL_KERN_AFTER_DEGREE)), ==, 11200);
+ g_assert_cmpint((hb_ot_math_get_constant (hb_font, HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN)), ==, 87);
+ g_assert_cmpint((hb_ot_math_get_constant (hb_font, HB_OT_MATH_CONSTANT_SCRIPT_SCRIPT_PERCENT_SCALE_DOWN)), ==, 76);
+ g_assert_cmpint((hb_ot_math_get_constant (hb_font, HB_OT_MATH_CONSTANT_RADICAL_DEGREE_BOTTOM_RAISE_PERCENT)), ==, 65);
+ closeFont();
+
+ cleanupFreeType();
+}
+
+static void
+test_get_glyph_italics_correction (void)
+{
+ hb_codepoint_t glyph;
+ initFreeType();
+
+ openFont("fonts/MathTestFontEmpty.otf");
+ g_assert(hb_font_get_glyph_from_name (hb_font, "space", -1, &glyph));
+ g_assert_cmpint(hb_ot_math_get_glyph_italics_correction (hb_font, glyph), ==, 0); // MathGlyphInfo not available
+ closeFont();
+
+ openFont("fonts/MathTestFontPartial1.otf");
+ g_assert(hb_font_get_glyph_from_name (hb_font, "space", -1, &glyph));
+ g_assert_cmpint(hb_ot_math_get_glyph_italics_correction (hb_font, glyph), ==, 0); // MathGlyphInfo empty
+ closeFont();
+
+ openFont("fonts/MathTestFontPartial2.otf");
+ g_assert(hb_font_get_glyph_from_name (hb_font, "space", -1, &glyph));
+ g_assert_cmpint(hb_ot_math_get_glyph_italics_correction (hb_font, glyph), ==, 0); // MathItalicsCorrectionInfo empty
+ closeFont();
+
+ openFont("fonts/MathTestFontFull.otf");
+ g_assert(hb_font_get_glyph_from_name (hb_font, "space", -1, &glyph));
+ g_assert_cmpint(hb_ot_math_get_glyph_italics_correction (hb_font, glyph), ==, 0); // Glyph without italic correction.
+ g_assert(hb_font_get_glyph_from_name (hb_font, "A", -1, &glyph));
+ g_assert_cmpint(hb_ot_math_get_glyph_italics_correction (hb_font, glyph), ==, 394);
+ g_assert(hb_font_get_glyph_from_name (hb_font, "B", -1, &glyph));
+ g_assert_cmpint(hb_ot_math_get_glyph_italics_correction (hb_font, glyph), ==, 300);
+ g_assert(hb_font_get_glyph_from_name (hb_font, "C", -1, &glyph));
+ g_assert_cmpint(hb_ot_math_get_glyph_italics_correction (hb_font, glyph), ==, 904);
+ closeFont();
+
+ cleanupFreeType();
+}
+
+static void
+test_get_glyph_top_accent_attachment (void)
+{
+ hb_codepoint_t glyph;
+ initFreeType();
+
+ openFont("fonts/MathTestFontEmpty.otf");
+ g_assert(hb_font_get_glyph_from_name (hb_font, "space", -1, &glyph));
+ g_assert_cmpint(hb_ot_math_get_glyph_top_accent_attachment (hb_font, glyph), ==, 1000); // MathGlyphInfo not available
+ closeFont();
+
+ openFont("fonts/MathTestFontPartial1.otf");
+ g_assert(hb_font_get_glyph_from_name (hb_font, "space", -1, &glyph));
+ g_assert_cmpint(hb_ot_math_get_glyph_top_accent_attachment (hb_font, glyph), ==, 1000); // MathGlyphInfo empty
+ closeFont();
+
+ openFont("fonts/MathTestFontPartial2.otf");
+ g_assert(hb_font_get_glyph_from_name (hb_font, "space", -1, &glyph));
+ g_assert_cmpint(hb_ot_math_get_glyph_top_accent_attachment (hb_font, glyph), ==, 1000); // MathTopAccentAttachment empty
+ closeFont();
+
+ openFont("fonts/MathTestFontFull.otf");
+ g_assert(hb_font_get_glyph_from_name (hb_font, "space", -1, &glyph));
+ g_assert_cmpint(hb_ot_math_get_glyph_top_accent_attachment (hb_font, glyph), ==, 1000); // Glyph without top accent attachment.
+ g_assert(hb_font_get_glyph_from_name (hb_font, "D", -1, &glyph));
+ g_assert_cmpint(hb_ot_math_get_glyph_top_accent_attachment (hb_font, glyph), ==, 748);
+ g_assert(hb_font_get_glyph_from_name (hb_font, "E", -1, &glyph));
+ g_assert_cmpint(hb_ot_math_get_glyph_top_accent_attachment (hb_font, glyph), ==, 692);
+ g_assert(hb_font_get_glyph_from_name (hb_font, "F", -1, &glyph));
+ g_assert_cmpint(hb_ot_math_get_glyph_top_accent_attachment (hb_font, glyph), ==, 636);
+ closeFont();
+
+ cleanupFreeType();
+}
+
+static void
+test_is_glyph_extended_shape (void)
+{
+ hb_codepoint_t glyph;
+ initFreeType();
+
+ openFont("fonts/MathTestFontEmpty.otf");
+ g_assert(hb_font_get_glyph_from_name (hb_font, "space", -1, &glyph));
+ g_assert(!hb_ot_math_is_glyph_extended_shape (hb_face, glyph)); // MathGlyphInfo not available
+ closeFont();
+
+ openFont("fonts/MathTestFontPartial1.otf");
+ g_assert(hb_font_get_glyph_from_name (hb_font, "space", -1, &glyph));
+ g_assert(!hb_ot_math_is_glyph_extended_shape (hb_face, glyph)); // MathGlyphInfo empty
+ closeFont();
+
+ openFont("fonts/MathTestFontFull.otf");
+ g_assert(hb_font_get_glyph_from_name (hb_font, "G", -1, &glyph));
+ g_assert(!hb_ot_math_is_glyph_extended_shape (hb_face, glyph));
+ g_assert(hb_font_get_glyph_from_name (hb_font, "H", -1, &glyph));
+ g_assert(hb_ot_math_is_glyph_extended_shape (hb_face, glyph));
+ closeFont();
+
+ cleanupFreeType();
+}
+
+static void
+test_get_glyph_kerning (void)
+{
+ hb_codepoint_t glyph;
+ initFreeType();
+
+ openFont("fonts/MathTestFontEmpty.otf");
+ g_assert(hb_font_get_glyph_from_name (hb_font, "space", -1, &glyph));
+ g_assert_cmpint(hb_ot_math_get_glyph_kerning (hb_font, glyph, HB_OT_MATH_KERN_TOP_RIGHT, 0), ==, 0); // MathGlyphInfo not available
+ g_assert_cmpint(hb_ot_math_get_glyph_kerning (hb_font, glyph, HB_OT_MATH_KERN_TOP_LEFT, 0), ==, 0); // MathGlyphInfo not available
+ g_assert_cmpint(hb_ot_math_get_glyph_kerning (hb_font, glyph, HB_OT_MATH_KERN_BOTTOM_RIGHT, 0), ==, 0); // MathGlyphInfo not available
+ g_assert_cmpint(hb_ot_math_get_glyph_kerning (hb_font, glyph, HB_OT_MATH_KERN_BOTTOM_LEFT, 0), ==, 0); // MathGlyphInfo not available
+ closeFont();
+
+ openFont("fonts/MathTestFontPartial2.otf");
+ g_assert(hb_font_get_glyph_from_name (hb_font, "space", -1, &glyph));
+ g_assert_cmpint(hb_ot_math_get_glyph_kerning (hb_font, glyph, HB_OT_MATH_KERN_TOP_RIGHT, 0), ==, 0); // MathKernInfo empty
+ g_assert_cmpint(hb_ot_math_get_glyph_kerning (hb_font, glyph, HB_OT_MATH_KERN_TOP_LEFT, 0), ==, 0); // MathKernInfo empty
+ g_assert_cmpint(hb_ot_math_get_glyph_kerning (hb_font, glyph, HB_OT_MATH_KERN_BOTTOM_RIGHT, 0), ==, 0); // MathKernInfo empty
+ g_assert_cmpint(hb_ot_math_get_glyph_kerning (hb_font, glyph, HB_OT_MATH_KERN_BOTTOM_LEFT, 0), ==, 0); // MathKernInfo empty
+ closeFont();
+
+ openFont("fonts/MathTestFontPartial3.otf");
+ g_assert(hb_font_get_glyph_from_name (hb_font, "space", -1, &glyph));
+ g_assert_cmpint(hb_ot_math_get_glyph_kerning (hb_font, glyph, HB_OT_MATH_KERN_TOP_RIGHT, 0), ==, 0); // MathKernInfoRecords empty
+ g_assert_cmpint(hb_ot_math_get_glyph_kerning (hb_font, glyph, HB_OT_MATH_KERN_TOP_LEFT, 0), ==, 0); // MathKernInfoRecords empty
+ g_assert_cmpint(hb_ot_math_get_glyph_kerning (hb_font, glyph, HB_OT_MATH_KERN_BOTTOM_RIGHT, 0), ==, 0); // MathKernInfoRecords empty
+ g_assert_cmpint(hb_ot_math_get_glyph_kerning (hb_font, glyph, HB_OT_MATH_KERN_BOTTOM_LEFT, 0), ==, 0); // MathKernInfoRecords empty
+ closeFont();
+
+ openFont("fonts/MathTestFontFull.otf");
+ g_assert(hb_font_get_glyph_from_name (hb_font, "I", -1, &glyph));
+
+ g_assert_cmpint(hb_ot_math_get_glyph_kerning (hb_font, glyph, HB_OT_MATH_KERN_TOP_RIGHT, 7), ==, 62); // lower than min heigth
+ g_assert_cmpint(hb_ot_math_get_glyph_kerning (hb_font, glyph, HB_OT_MATH_KERN_TOP_RIGHT, 14), ==, 62); // equal to min height
+ g_assert_cmpint(hb_ot_math_get_glyph_kerning (hb_font, glyph, HB_OT_MATH_KERN_TOP_RIGHT, 20), ==, 104);
+ g_assert_cmpint(hb_ot_math_get_glyph_kerning (hb_font, glyph, HB_OT_MATH_KERN_TOP_RIGHT, 23), ==, 104);
+ g_assert_cmpint(hb_ot_math_get_glyph_kerning (hb_font, glyph, HB_OT_MATH_KERN_TOP_RIGHT, 31), ==, 146);
+ g_assert_cmpint(hb_ot_math_get_glyph_kerning (hb_font, glyph, HB_OT_MATH_KERN_TOP_RIGHT, 32), ==, 146);
+ g_assert_cmpint(hb_ot_math_get_glyph_kerning (hb_font, glyph, HB_OT_MATH_KERN_TOP_RIGHT, 86), ==, 398); // equal to max height
+ g_assert_cmpint(hb_ot_math_get_glyph_kerning (hb_font, glyph, HB_OT_MATH_KERN_TOP_RIGHT, 91), ==, 440); // larger than max height
+ g_assert_cmpint(hb_ot_math_get_glyph_kerning (hb_font, glyph, HB_OT_MATH_KERN_TOP_RIGHT, 96), ==, 440); // larger than max height
+
+ g_assert_cmpint(hb_ot_math_get_glyph_kerning (hb_font, glyph, HB_OT_MATH_KERN_TOP_RIGHT, 39), ==, 188); // top right
+ g_assert_cmpint(hb_ot_math_get_glyph_kerning (hb_font, glyph, HB_OT_MATH_KERN_TOP_LEFT, 39), ==, 110); // top left
+ g_assert_cmpint(hb_ot_math_get_glyph_kerning (hb_font, glyph, HB_OT_MATH_KERN_BOTTOM_RIGHT, 39), ==, 44); // bottom right
+ g_assert_cmpint(hb_ot_math_get_glyph_kerning (hb_font, glyph, HB_OT_MATH_KERN_BOTTOM_LEFT, 39), ==, 100); // bottom left
+
+ closeFont();
+
+ cleanupFreeType();
+}
+
+
+static hb_position_t
+get_glyph_assembly_italics_correction (hb_font_t *font,
+ hb_codepoint_t glyph,
+ hb_bool_t horizontal)
+{
+ hb_position_t corr;
+ hb_ot_math_get_glyph_assembly (font, glyph,
+ horizontal ? HB_DIRECTION_LTR : HB_DIRECTION_TTB,
+ 0, NULL, NULL,
+ &corr);
+ return corr;
+}
+
+static void
+test_get_glyph_assembly_italics_correction (void)
+{
+ hb_codepoint_t glyph;
+ initFreeType();
+
+ openFont("fonts/MathTestFontEmpty.otf");
+ g_assert(hb_font_get_glyph_from_name (hb_font, "space", -1, &glyph));
+ g_assert_cmpint(get_glyph_assembly_italics_correction (hb_font, glyph, TRUE), ==, 0); // MathVariants not available
+ g_assert_cmpint(get_glyph_assembly_italics_correction (hb_font, glyph, FALSE), ==, 0); // MathVariants not available
+ closeFont();
+
+ openFont("fonts/MathTestFontPartial1.otf");
+ g_assert(hb_font_get_glyph_from_name (hb_font, "space", -1, &glyph));
+ g_assert_cmpint(get_glyph_assembly_italics_correction (hb_font, glyph, TRUE), ==, 0); // VertGlyphCoverage and HorizGlyphCoverage absent
+ g_assert_cmpint(get_glyph_assembly_italics_correction (hb_font, glyph, FALSE), ==, 0); // VertGlyphCoverage and HorizGlyphCoverage absent
+ closeFont();
+
+ openFont("fonts/MathTestFontPartial2.otf");
+ g_assert(hb_font_get_glyph_from_name (hb_font, "space", -1, &glyph));
+ g_assert_cmpint(get_glyph_assembly_italics_correction (hb_font, glyph, TRUE), ==, 0); // VertGlyphCoverage and HorizGlyphCoverage empty
+ g_assert_cmpint(get_glyph_assembly_italics_correction (hb_font, glyph, FALSE), ==, 0); // VertGlyphCoverage and HorizGlyphCoverage empty
+ closeFont();
+
+ openFont("fonts/MathTestFontPartial3.otf");
+ g_assert(hb_font_get_glyph_from_name (hb_font, "space", -1, &glyph));
+ g_assert_cmpint(get_glyph_assembly_italics_correction (hb_font, glyph, TRUE), ==, 0); // HorizGlyphConstruction and VertGlyphConstruction empty
+ g_assert_cmpint(get_glyph_assembly_italics_correction (hb_font, glyph, FALSE), ==, 0); // HorizGlyphConstruction and VertGlyphConstruction empty
+ closeFont();
+
+ openFont("fonts/MathTestFontPartial4.otf");
+ g_assert(hb_font_get_glyph_from_name (hb_font, "space", -1, &glyph));
+ g_assert_cmpint(get_glyph_assembly_italics_correction (hb_font, glyph, TRUE), ==, 0);
+ g_assert_cmpint(get_glyph_assembly_italics_correction (hb_font, glyph, FALSE), ==, 0);
+ closeFont();
+
+ openFont("fonts/MathTestFontFull.otf");
+ g_assert(hb_font_get_glyph_from_name (hb_font, "arrowleft", -1, &glyph));
+ g_assert_cmpint(get_glyph_assembly_italics_correction (hb_font, glyph, TRUE), ==, 248);
+ g_assert_cmpint(get_glyph_assembly_italics_correction (hb_font, glyph, FALSE), ==, 0);
+ g_assert(hb_font_get_glyph_from_name (hb_font, "arrowup", -1, &glyph));
+ g_assert_cmpint(get_glyph_assembly_italics_correction (hb_font, glyph, TRUE), ==, 0);
+ g_assert_cmpint(get_glyph_assembly_italics_correction (hb_font, glyph, FALSE), ==, 662);
+ closeFont();
+
+ cleanupFreeType();
+}
+
+static void
+test_get_min_connector_overlap (void)
+{
+ initFreeType();
+
+ openFont("fonts/MathTestFontEmpty.otf");
+ g_assert_cmpint(hb_ot_math_get_min_connector_overlap(hb_font, FALSE), ==, 0); // MathVariants not available
+ g_assert_cmpint(hb_ot_math_get_min_connector_overlap(hb_font, TRUE), ==, 0); // MathVariants not available
+ closeFont();
+
+ openFont("fonts/MathTestFontPartial1.otf");
+ g_assert_cmpint(hb_ot_math_get_min_connector_overlap(hb_font, HB_DIRECTION_LTR), ==, 108);
+ g_assert_cmpint(hb_ot_math_get_min_connector_overlap(hb_font, HB_DIRECTION_TTB), ==, 54);
+ closeFont();
+
+ cleanupFreeType();
+}
+
+static void
+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");
+ g_assert(hb_font_get_glyph_from_name (hb_font, "space", -1, &glyph));
+ g_assert_cmpint(hb_ot_math_get_glyph_variants (hb_font, glyph, HB_DIRECTION_RTL, 0, NULL, NULL), ==, 0);
+ g_assert_cmpint(hb_ot_math_get_glyph_variants (hb_font, glyph, HB_DIRECTION_BTT, 0, NULL, NULL), ==, 0);
+ closeFont();
+
+ openFont("fonts/MathTestFontPartial1.otf");
+ g_assert(hb_font_get_glyph_from_name (hb_font, "space", -1, &glyph));
+ g_assert_cmpint(hb_ot_math_get_glyph_variants (hb_font, glyph, HB_DIRECTION_RTL, 0, NULL, NULL), ==, 0);
+ g_assert_cmpint(hb_ot_math_get_glyph_variants (hb_font, glyph, HB_DIRECTION_BTT, 0, NULL, NULL), ==, 0);
+ closeFont();
+
+ openFont("fonts/MathTestFontPartial2.otf");
+ g_assert(hb_font_get_glyph_from_name (hb_font, "space", -1, &glyph));
+ g_assert_cmpint(hb_ot_math_get_glyph_variants (hb_font, glyph, HB_DIRECTION_RTL, 0, NULL, NULL), ==, 0);
+ g_assert_cmpint(hb_ot_math_get_glyph_variants (hb_font, glyph, HB_DIRECTION_BTT, 0, NULL, NULL), ==, 0);
+ closeFont();
+
+ openFont("fonts/MathTestFontPartial3.otf");
+ g_assert(hb_font_get_glyph_from_name (hb_font, "space", -1, &glyph));
+ g_assert_cmpint(hb_ot_math_get_glyph_variants (hb_font, glyph, HB_DIRECTION_RTL, 0, NULL, NULL), ==, 0);
+ g_assert_cmpint(hb_ot_math_get_glyph_variants (hb_font, glyph, HB_DIRECTION_BTT, 0, NULL, NULL), ==, 0);
+ closeFont();
+
+ openFont("fonts/MathTestFontPartial4.otf");
+ g_assert(hb_font_get_glyph_from_name (hb_font, "space", -1, &glyph));
+ g_assert_cmpint(hb_ot_math_get_glyph_variants (hb_font, glyph, HB_DIRECTION_RTL, 0, NULL, NULL), ==, 0);
+ g_assert_cmpint(hb_ot_math_get_glyph_variants (hb_font, glyph, HB_DIRECTION_BTT, 0, NULL, NULL), ==, 0);
+ closeFont();
+
+ openFont("fonts/MathTestFontFull.otf");
+
+ g_assert(hb_font_get_glyph_from_name (hb_font, "arrowleft", -1, &glyph));
+ g_assert_cmpint(hb_ot_math_get_glyph_variants (hb_font,
+ glyph,
+ HB_DIRECTION_BTT,
+ 0,
+ NULL,
+ NULL), ==, 0);
+ g_assert_cmpint(hb_ot_math_get_glyph_variants (hb_font,
+ glyph,
+ HB_DIRECTION_RTL,
+ 0,
+ NULL,
+ NULL), ==, 3);
+
+ g_assert(hb_font_get_glyph_from_name (hb_font, "arrowup", -1, &glyph));
+ g_assert_cmpint(hb_ot_math_get_glyph_variants (hb_font,
+ glyph,
+ HB_DIRECTION_BTT,
+ 0,
+ NULL,
+ NULL), ==, 4);
+ g_assert_cmpint(hb_ot_math_get_glyph_variants (hb_font,
+ glyph,
+ HB_DIRECTION_RTL,
+ 0,
+ NULL,
+ NULL), ==, 0);
+
+ g_assert(hb_font_get_glyph_from_name (hb_font, "arrowleft", -1, &glyph));
+ do {
+ count = variantsSize;
+ hb_ot_math_get_glyph_variants (hb_font,
+ glyph,
+ HB_DIRECTION_RTL,
+ offset,
+ &count,
+ variants);
+ offset += count;
+ } while (count == variantsSize);
+ g_assert_cmpint(offset, ==, 3);
+ g_assert(hb_font_get_glyph_from_name (hb_font, "uni2190_size2", -1, &glyph));
+ g_assert_cmpint(variants[0].glyph, ==, glyph);
+ g_assert_cmpint(variants[0].advance, ==, 4302);
+ g_assert(hb_font_get_glyph_from_name (hb_font, "uni2190_size3", -1, &glyph));
+ g_assert_cmpint(variants[1].glyph, ==, glyph);
+ g_assert_cmpint(variants[1].advance, ==, 4802);
+ g_assert(hb_font_get_glyph_from_name (hb_font, "uni2190_size4", -1, &glyph));
+ g_assert_cmpint(variants[2].glyph, ==, glyph);
+ g_assert_cmpint(variants[2].advance, ==, 5802);
+
+ g_assert(hb_font_get_glyph_from_name (hb_font, "arrowup", -1, &glyph));
+ offset = 0;
+ do {
+ count = variantsSize;
+ hb_ot_math_get_glyph_variants (hb_font,
+ glyph,
+ HB_DIRECTION_BTT,
+ offset,
+ &count,
+ variants);
+ offset += count;
+ } while (count == variantsSize);
+ g_assert_cmpint(offset, ==, 4);
+ g_assert(hb_font_get_glyph_from_name (hb_font, "uni2191_size2", -1, &glyph));
+ g_assert_cmpint(variants[0].glyph, ==, glyph);
+ g_assert_cmpint(variants[0].advance, ==, 2251);
+ g_assert(hb_font_get_glyph_from_name (hb_font, "uni2191_size3", -1, &glyph));
+ g_assert_cmpint(variants[1].glyph, ==, glyph);
+ g_assert_cmpint(variants[1].advance, ==, 2501);
+ g_assert(hb_font_get_glyph_from_name (hb_font, "uni2191_size4", -1, &glyph));
+ g_assert_cmpint(variants[2].glyph, ==, glyph);
+ g_assert_cmpint(variants[2].advance, ==, 3001);
+ g_assert(hb_font_get_glyph_from_name (hb_font, "uni2191_size5", -1, &glyph));
+ g_assert_cmpint(variants[3].glyph, ==, glyph);
+ g_assert_cmpint(variants[3].advance, ==, 3751);
+
+ closeFont();
+
+ cleanupFreeType();
+}
+
+static void
+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");
+ g_assert(hb_font_get_glyph_from_name (hb_font, "space", -1, &glyph));
+ g_assert_cmpint(hb_ot_math_get_glyph_assembly (hb_font, glyph, HB_DIRECTION_RTL, 0, NULL, NULL, NULL), ==, 0);
+ g_assert_cmpint(hb_ot_math_get_glyph_assembly (hb_font, glyph, HB_DIRECTION_BTT, 0, NULL, NULL, NULL), ==, 0);
+ closeFont();
+
+ openFont("fonts/MathTestFontPartial1.otf");
+ g_assert(hb_font_get_glyph_from_name (hb_font, "space", -1, &glyph));
+ g_assert_cmpint(hb_ot_math_get_glyph_assembly (hb_font, glyph, HB_DIRECTION_RTL, 0, NULL, NULL, NULL), ==, 0);
+ g_assert_cmpint(hb_ot_math_get_glyph_assembly (hb_font, glyph, HB_DIRECTION_BTT, 0, NULL, NULL, NULL), ==, 0);
+ closeFont();
+
+ openFont("fonts/MathTestFontPartial2.otf");
+ g_assert(hb_font_get_glyph_from_name (hb_font, "space", -1, &glyph));
+ g_assert_cmpint(hb_ot_math_get_glyph_assembly (hb_font, glyph, HB_DIRECTION_RTL, 0, NULL, NULL, NULL), ==, 0);
+ g_assert_cmpint(hb_ot_math_get_glyph_assembly (hb_font, glyph, HB_DIRECTION_BTT, 0, NULL, NULL, NULL), ==, 0);
+ closeFont();
+
+ openFont("fonts/MathTestFontPartial3.otf");
+ g_assert(hb_font_get_glyph_from_name (hb_font, "space", -1, &glyph));
+ g_assert_cmpint(hb_ot_math_get_glyph_assembly (hb_font, glyph, HB_DIRECTION_RTL, 0, NULL, NULL, NULL), ==, 0);
+ g_assert_cmpint(hb_ot_math_get_glyph_assembly (hb_font, glyph, HB_DIRECTION_BTT, 0, NULL, NULL, NULL), ==, 0);
+ closeFont();
+
+ openFont("fonts/MathTestFontPartial4.otf");
+ g_assert(hb_font_get_glyph_from_name (hb_font, "space", -1, &glyph));
+ g_assert_cmpint(hb_ot_math_get_glyph_assembly (hb_font, glyph, HB_DIRECTION_RTL, 0, NULL, NULL, NULL), ==, 0);
+ g_assert_cmpint(hb_ot_math_get_glyph_assembly (hb_font, glyph, HB_DIRECTION_BTT, 0, NULL, NULL, NULL), ==, 0);
+ closeFont();
+
+ openFont("fonts/MathTestFontFull.otf");
+
+ g_assert(hb_font_get_glyph_from_name (hb_font, "arrowright", -1, &glyph));
+ g_assert_cmpint(hb_ot_math_get_glyph_assembly (hb_font,
+ glyph,
+ HB_DIRECTION_BTT,
+ 0,
+ NULL,
+ NULL,
+ NULL), ==, 0);
+ g_assert_cmpint(hb_ot_math_get_glyph_assembly (hb_font,
+ glyph,
+ HB_DIRECTION_RTL,
+ 0,
+ NULL,
+ NULL,
+ NULL), ==, 3);
+
+ g_assert(hb_font_get_glyph_from_name (hb_font, "arrowdown", -1, &glyph));
+ g_assert_cmpint(hb_ot_math_get_glyph_assembly (hb_font,
+ glyph,
+ HB_DIRECTION_BTT,
+ 0,
+ NULL,
+ NULL,
+ NULL), ==, 5);
+ g_assert_cmpint(hb_ot_math_get_glyph_assembly (hb_font,
+ glyph,
+ HB_DIRECTION_RTL,
+ 0,
+ NULL,
+ NULL,
+ NULL), ==, 0);
+
+ g_assert(hb_font_get_glyph_from_name (hb_font, "arrowright", -1, &glyph));
+ do {
+ count = partsSize;
+ hb_ot_math_get_glyph_assembly (hb_font,
+ glyph,
+ HB_DIRECTION_RTL,
+ offset,
+ &count,
+ parts,
+ NULL);
+ offset += count;
+ } while (count == partsSize);
+ g_assert_cmpint(offset, ==, 3);
+ g_assert(hb_font_get_glyph_from_name (hb_font, "left", -1, &glyph));
+ g_assert_cmpint(parts[0].glyph, ==, glyph);
+ g_assert_cmpint(parts[0].start_connector_length, ==, 800);
+ g_assert_cmpint(parts[0].end_connector_length, ==, 384);
+ g_assert_cmpint(parts[0].full_advance, ==, 2000);
+ g_assert(!(parts[0].flags & HB_MATH_GLYPH_PART_FLAG_EXTENDER));
+ g_assert(hb_font_get_glyph_from_name (hb_font, "horizontal", -1, &glyph));
+ g_assert_cmpint(parts[1].glyph, ==, glyph);
+ g_assert_cmpint(parts[1].start_connector_length, ==, 524);
+ g_assert_cmpint(parts[1].end_connector_length, ==, 800);
+ g_assert_cmpint(parts[1].full_advance, ==, 2000);
+ g_assert(parts[1].flags & HB_MATH_GLYPH_PART_FLAG_EXTENDER);
+ g_assert(hb_font_get_glyph_from_name (hb_font, "right", -1, &glyph));
+ g_assert_cmpint(parts[2].glyph, ==, glyph);
+ g_assert_cmpint(parts[2].start_connector_length, ==, 316);
+ g_assert_cmpint(parts[2].end_connector_length, ==, 454);
+ g_assert_cmpint(parts[2].full_advance, ==, 2000);
+ g_assert(!(parts[2].flags & HB_MATH_GLYPH_PART_FLAG_EXTENDER));
+
+ g_assert(hb_font_get_glyph_from_name (hb_font, "arrowdown", -1, &glyph));
+ offset = 0;
+ do {
+ count = partsSize;
+ hb_ot_math_get_glyph_assembly (hb_font,
+ glyph,
+ HB_DIRECTION_BTT,
+ offset,
+ &count,
+ parts,
+ NULL);
+ offset += count;
+ } while (count == partsSize);
+ g_assert_cmpint(offset, ==, 5);
+ g_assert(hb_font_get_glyph_from_name (hb_font, "bottom", -1, &glyph));
+ g_assert_cmpint(parts[0].glyph, ==, glyph);
+ g_assert_cmpint(parts[0].start_connector_length, ==, 365);
+ g_assert_cmpint(parts[0].end_connector_length, ==, 158);
+ g_assert_cmpint(parts[0].full_advance, ==, 1000);
+ g_assert(!(parts[0].flags & HB_MATH_GLYPH_PART_FLAG_EXTENDER));
+ g_assert(hb_font_get_glyph_from_name (hb_font, "vertical", -1, &glyph));
+ g_assert_cmpint(parts[1].glyph, ==, glyph);
+ g_assert_cmpint(parts[1].glyph, ==, glyph);
+ g_assert_cmpint(parts[1].start_connector_length, ==, 227);
+ g_assert_cmpint(parts[1].end_connector_length, ==, 365);
+ g_assert_cmpint(parts[1].full_advance, ==, 1000);
+ g_assert(parts[1].flags & HB_MATH_GLYPH_PART_FLAG_EXTENDER);
+ g_assert(hb_font_get_glyph_from_name (hb_font, "center", -1, &glyph));
+ g_assert_cmpint(parts[2].glyph, ==, glyph);
+ g_assert_cmpint(parts[2].start_connector_length, ==, 54);
+ g_assert_cmpint(parts[2].end_connector_length, ==, 158);
+ g_assert_cmpint(parts[2].full_advance, ==, 1000);
+ g_assert(!(parts[2].flags & HB_MATH_GLYPH_PART_FLAG_EXTENDER));
+ g_assert(hb_font_get_glyph_from_name (hb_font, "vertical", -1, &glyph));
+ g_assert_cmpint(parts[3].glyph, ==, glyph);
+ g_assert_cmpint(parts[3].glyph, ==, glyph);
+ g_assert_cmpint(parts[3].glyph, ==, glyph);
+ g_assert_cmpint(parts[3].start_connector_length, ==, 400);
+ g_assert_cmpint(parts[3].end_connector_length, ==, 296);
+ g_assert_cmpint(parts[3].full_advance, ==, 1000);
+ g_assert(parts[1].flags & HB_MATH_GLYPH_PART_FLAG_EXTENDER);
+ g_assert(hb_font_get_glyph_from_name (hb_font, "top", -1, &glyph));
+ g_assert_cmpint(parts[4].glyph, ==, glyph);
+ g_assert_cmpint(parts[4].start_connector_length, ==, 123);
+ g_assert_cmpint(parts[4].end_connector_length, ==, 192);
+ g_assert_cmpint(parts[4].full_advance, ==, 1000);
+ g_assert(!(parts[4].flags & HB_MATH_GLYPH_PART_FLAG_EXTENDER));
+
+ closeFont();
+
+ cleanupFreeType();
+}
+
+int
+main (int argc, char **argv)
+{
+ hb_test_init (&argc, &argv);
+
+ hb_test_add (test_has_data);
+ hb_test_add (test_get_constant);
+ hb_test_add (test_get_glyph_italics_correction);
+ hb_test_add (test_get_glyph_top_accent_attachment);
+ hb_test_add (test_is_glyph_extended_shape);
+ hb_test_add (test_get_glyph_kerning);
+ hb_test_add (test_get_glyph_assembly_italics_correction);
+ hb_test_add (test_get_min_connector_overlap);
+ hb_test_add (test_get_glyph_variants);
+ hb_test_add (test_get_glyph_assembly);
+
+ return hb_test_run();
+}
diff --git a/test/api/test-ot-tag.c b/test/api/test-ot-tag.c
index e54e55269..f5cbd9d12 100644
--- a/test/api/test-ot-tag.c
+++ b/test/api/test-ot-tag.c
@@ -188,11 +188,48 @@ test_ot_tag_language (void)
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_ot_tag_language (void)
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/fuzzing/Makefile.am b/test/fuzzing/Makefile.am
index 7b0eb9452..3ea8605bd 100644
--- a/test/fuzzing/Makefile.am
+++ b/test/fuzzing/Makefile.am
@@ -30,14 +30,15 @@ LDADD = \
$(NULL)
hb_fuzzer_SOURCES = \
+ hb-fuzzer.hh \
hb-fuzzer.cc \
+ main.cc \
$(NULL)
hb_fuzzer_LDADD = \
$(LDADD) \
$(NULL)
hb_fuzzer_CPPFLAGS = \
$(AM_CPPFLAGS) \
- -DMAIN \
$(NULL)
hb_fuzzer_DEPENDENCIES = \
lib \
diff --git a/test/fuzzing/hb-fuzzer.cc b/test/fuzzing/hb-fuzzer.cc
index b319a715a..79f322297 100644
--- a/test/fuzzing/hb-fuzzer.cc
+++ b/test/fuzzing/hb-fuzzer.cc
@@ -1,10 +1,10 @@
-#include <stddef.h>
-#include <hb.h>
+#include "hb-fuzzer.hh"
+
#include <hb-ot.h>
#include <string.h>
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
-
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+{
hb_blob_t *blob = hb_blob_create((const char *)data, size,
HB_MEMORY_MODE_READONLY, NULL, NULL);
hb_face_t *face = hb_face_create(blob, 0);
@@ -28,6 +28,19 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
hb_buffer_add_utf32(buffer, text32, sizeof(text32)/sizeof(text32[0]), 0, -1);
hb_buffer_guess_segment_properties(buffer);
hb_shape(font, buffer, NULL, 0);
+
+ unsigned int len = hb_buffer_get_length (buffer);
+ hb_glyph_info_t *infos = hb_buffer_get_glyph_infos (buffer, NULL);
+ //hb_glyph_position_t *positions = hb_buffer_get_glyph_positions (buffer, NULL);
+ for (unsigned int i = 0; i < len; i++)
+ {
+ hb_glyph_info_t info = infos[i];
+ //hb_glyph_position_t pos = positions[i];
+
+ hb_glyph_extents_t extents;
+ hb_font_get_glyph_extents (font, info.codepoint, &extents);
+ }
+
hb_buffer_destroy(buffer);
}
@@ -37,25 +50,3 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
hb_blob_destroy(blob);
return 0;
}
-
-#ifdef MAIN
-#include <iostream>
-#include <iterator>
-#include <fstream>
-#include <assert.h>
-
-std::string FileToString(const std::string &Path) {
- /* TODO This silently passes if file does not exist. Fix it! */
- std::ifstream T(Path.c_str());
- return std::string((std::istreambuf_iterator<char>(T)),
- std::istreambuf_iterator<char>());
-}
-
-int main(int argc, char **argv) {
- for (int i = 1; i < argc; i++) {
- std::string s = FileToString(argv[i]);
- std::cout << argv[i] << std::endl;
- LLVMFuzzerTestOneInput((const unsigned char*)s.data(), s.size());
- }
-}
-#endif
diff --git a/test/fuzzing/hb-fuzzer.hh b/test/fuzzing/hb-fuzzer.hh
new file mode 100644
index 000000000..d0c617e09
--- /dev/null
+++ b/test/fuzzing/hb-fuzzer.hh
@@ -0,0 +1,4 @@
+#include <hb.h>
+#include <stddef.h>
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
diff --git a/test/fuzzing/main.cc b/test/fuzzing/main.cc
new file mode 100644
index 000000000..4692f7b5f
--- /dev/null
+++ b/test/fuzzing/main.cc
@@ -0,0 +1,21 @@
+#include "hb-fuzzer.hh"
+
+#include <iostream>
+#include <iterator>
+#include <fstream>
+#include <assert.h>
+
+std::string FileToString(const std::string &Path) {
+ /* TODO This silently passes if file does not exist. Fix it! */
+ std::ifstream T(Path.c_str());
+ return std::string((std::istreambuf_iterator<char>(T)),
+ std::istreambuf_iterator<char>());
+}
+
+int main(int argc, char **argv) {
+ for (int i = 1; i < argc; i++) {
+ std::string s = FileToString(argv[i]);
+ std::cout << argv[i] << std::endl;
+ LLVMFuzzerTestOneInput((const unsigned char*)s.data(), s.size());
+ }
+}
diff --git a/test/shaping/Makefile.am b/test/shaping/Makefile.am
index c5efe6251..ea0b28a7e 100644
--- a/test/shaping/Makefile.am
+++ b/test/shaping/Makefile.am
@@ -43,7 +43,9 @@ CLEANFILES += \
TESTS = \
tests/arabic-fallback-shaping.tests \
tests/arabic-feature-order.tests \
+ tests/automatic-fractions.tests \
tests/cluster.tests \
+ tests/color-fonts.tests \
tests/context-matching.tests \
tests/cursive-positioning.tests \
tests/default-ignorables.tests \
@@ -61,6 +63,7 @@ TESTS = \
tests/spaces.tests \
tests/simple.tests \
tests/use.tests \
+ tests/use-marchen.tests \
tests/vertical.tests \
tests/zero-width-marks.tests \
$(NULL)
diff --git a/test/shaping/fonts/sha1sum/15dfc433a135a658b9f4b1a861b5cdd9658ccbb9.ttf b/test/shaping/fonts/sha1sum/15dfc433a135a658b9f4b1a861b5cdd9658ccbb9.ttf
new file mode 100644
index 000000000..4b80f8044
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/15dfc433a135a658b9f4b1a861b5cdd9658ccbb9.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/217a934cfe15c548b572c203dceb2befdf026462.ttf b/test/shaping/fonts/sha1sum/217a934cfe15c548b572c203dceb2befdf026462.ttf
new file mode 100644
index 000000000..12b91a09f
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/217a934cfe15c548b572c203dceb2befdf026462.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf b/test/shaping/fonts/sha1sum/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf
new file mode 100644
index 000000000..18881fe49
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/ee39587d13b2afa5499cc79e45780aa79293bbd4.ttf b/test/shaping/fonts/sha1sum/ee39587d13b2afa5499cc79e45780aa79293bbd4.ttf
new file mode 100644
index 000000000..fa2d0e136
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/ee39587d13b2afa5499cc79e45780aa79293bbd4.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/f9b1dd4dcb515e757789a22cb4241107746fd3d0.ttf b/test/shaping/fonts/sha1sum/f9b1dd4dcb515e757789a22cb4241107746fd3d0.ttf
new file mode 100644
index 000000000..ed2fab9ef
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/f9b1dd4dcb515e757789a22cb4241107746fd3d0.ttf
Binary files differ
diff --git a/test/shaping/tests/automatic-fractions.tests b/test/shaping/tests/automatic-fractions.tests
new file mode 100644
index 000000000..f9510e26c
--- /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/test/shaping/tests/color-fonts.tests b/test/shaping/tests/color-fonts.tests
new file mode 100644
index 000000000..397796a06
--- /dev/null
+++ b/test/shaping/tests/color-fonts.tests
@@ -0,0 +1 @@
+fonts/sha1sum/ee39587d13b2afa5499cc79e45780aa79293bbd4.ttf:--font-funcs=ot --show-extents:U+1F42F:[gid1=0+2963<0,2178,2963,-2788>]
diff --git a/test/shaping/tests/fuzzed.tests b/test/shaping/tests/fuzzed.tests
index 7a5d395a9..771ac2b45 100644
--- a/test/shaping/tests/fuzzed.tests
+++ b/test/shaping/tests/fuzzed.tests
@@ -9,3 +9,4 @@ fonts/sha1sum/43979b90b2dd929723cf4fe1715990bcb9c9a56b.ttf:--font-funcs=ot:U+004
fonts/sha1sum/3511ff5c1647150595846ac414c595cccac34f18.ttf:--font-funcs=ot:U+0041:[gid0=0+1000|gid512=0+1000|gid15104=0+1000|gid11004=0+1000|gid3408=0+1000|gid18244=0+1000|gid17872=0+1000|gid17961=0+1000|gid0=0+1000|gid992=0+1000|gid15616=0+1000|gid0=0+1000|gid14151=0+1000|gid20559=0+1000|gid20992=0+1000|gid5440=0+1000|gid256=0+1000|gid0=0+1000|gid10=0+1000|gid8960=0+1000|gid256=0+1000|gid1024=0+1000|gid1490=0+1000|gid0=0+1000|gid768=0+1000|gid4096=0+1000|gid256=0+1000|gid2216=0+1000|gid0=0+1000|gid256=0+1000|gid256=0+1000|gid0=0+1000|gid768=0+1000|gid10752=0+1000|gid11004=0+1000|gid3408=0+1000|gid18244=0+1000|gid17734=0+1000|gid53248=0+1000|gid256=0+1000|gid0=0+1000|gid512=0+1000|gid14848=0+1000|gid10793=0+1000|gid57344=0+1000|gid768=0+1000|gid18227=0+1000|gid20285=0+1000|gid20480=0+1000|gid0=0+1000|gid256=0+1000|gid0=0+1000|gid810=0+1000|gid0=0+1000|gid11004=0+1000|gid3408=0+1000|gid18244=0+1000|gid17734=0+1000|gid53289=0+1000|gid57344=0+1000|gid768=0+1000|gid15667=0+1000|gid71=0+1000|gid0=0+1000|gid20559=0+1000|gid21248=0+1000|gid256=0+1000|gid0=0+1000|gid2816=0+1000|gid2776=0+1000|gid0=0+1000|gid51516=0+1000|gid0=0+1000|gid32=0+1000|gid26209=0+1000|gid28005=0+1000|gid65249=0+1000|gid29690=0+1000|gid0=0+1000|gid51548=0+1000|gid0=0+1000|gid2454=0+1000|gid28783=0+1000|gid29556=0+1000|gid1291=0+1000|gid3458=0+1000|gid80=0+1000|gid0=0+1000|gid2804=0+1000|gid210=0+1000|gid28786=0+1000|gid25968=0+1000|gid45763=0+1000|gid50546=0+1000|gid0=0+1000|gid59136=0+1000|gid0=0+1000|gid38144=0+1000|gid256=0+1000|gid0=0+1000|gid2560=0+1000|gid30208=0+1000|gid52224=0+1000|gid580=0+1000|gid17996=0+1000|gid21504=0+1000|gid6734=0+1000|gid108=0+1000|gid116=0+1000|gid24846=0+1000|gid1024=0+1000|gid0=0+1000|gid255=0+1000|gid65280=0+1000|gid256=0+1000|gid0=0+1000|gid8704=0+1000|gid1345=0+1000|gid23109=0+1000|gid8192=0+1000|gid10823=0+1000|gid21076=0+1000|gid8192=0+1000|gid12877=0+1000|gid20300=0+1000|gid8192=0+1000|gid6738=0+1000|gid20301=0+1000|gid8192=0+1000|gid16980=0+1000|gid21067=0+1000|gid8251=0+1000|gid18944=0+1000|gid255=0+1000|gid65280=0+1000|gid15360=0+1000|gid256=0+1000|gid255=0+1000|gid65280=0+1000|gid256=0+1000|gid768=0+1000|gid255=0+1000|gid65280=0+1000|gid256=0+1000|gid768=0+1000|gid255=0+1000|gid65280=0+1000|gid256=0+1000|gid1024=0+1000|gid12=0+1000|gid65280=0+1000|gid256=0+1000|gid1280=0+1000|gid255=0+1000|gid65280=0+1000|gid256=0+1000|gid1536=0+1000|gid1899=0+1000|gid25970=0+1000|gid110=0+1000|gid11264=0+1000|gid27502=0+1000|gid29285=0+1000|gid12907=0+1000|gid25974=0+1000|gid28160=0+1000|gid14443=0+1000|gid25970=0+1000|gid28288=0+1000|gid3=0+1000|gid118=0+1000|gid18259=0+1000|gid21826=0+1000|gid45716=0+1000|gid46369=0+1000|gid0=0+1000|gid0=0+1000|gid1=0+1000|gid16=0+1000|gid17=0+1000|gid256=0+1000|gid4=0+1000|gid16=0+1000|gid18244=0+1000|gid17734=0+1000|gid28=0+1000|gid12=0+1000|gid0=0+1000|gid284=0+1000|gid0=0+1000|gid28=0+1000|gid18256=0+1000|gid20307=0+1000|gid45114=0+1000|gid47616=0+1000|gid226=0+1000|gid10296=0+1000|gid0=0+1000|gid57927=0+1000|gid1=0+1000|gid0=0+1000|gid0=0+1000|gid21248=0+1000|gid5440=0+1000|gid256=0+1000|gid0=0+1000|gid10=0+1000|gid768=0+1000|gid256=0+1000|gid1024=0+1000|gid512=0+1000|gid0=0+1000|gid297=0+1000|gid16=0+1000|gid24833=0+1000|gid28774=0+1000|gid10794=0+1000|gid2304=0+1000|gid29=0+1000|gid32=0+1000|gid42=0+1000|gid64515=0+1000|gid42=0+1000|gid42=0+1000|gid64525=0+1000|gid20551=0+1000|gid17477=0+1000|gid18128=0+1000|gid10720=0+1000|gid3=0+1000|gid61=0+1000|gid3408=0+1000|gid18244=0+1000|gid17734=0+1000|gid53289=0+1000|gid57344=0+1000|gid768=0+1000|gid15616=0+1000|gid512=0+1000|gid55=0+1000|gid10576=0+1000|gid20307=0+1000|gid0=0+1000|gid255=0+1000|gid56063=0+1000|gid53504=0+1000|gid42=0+1000|gid42=0+1000|gid64525=0+1000|gid12288=0+1000|gid18176=0+1000|gid80=0+1000|gid20307=0+1000|gid1=0+1000|gid0=0+1000|gid62=0+1000]
fonts/sha1sum/fab39d60d758cb586db5a504f218442cd1395725.ttf:--font-funcs=ot:U+0041,U+0041:[gid0=0+1000|gid0=1+1000]
fonts/sha1sum/205edd09bd3d141cc9580f650109556cc28b22cb.ttf:--font-funcs=ot:U+0041:[gid0=0+1000]
+fonts/sha1sum/217a934cfe15c548b572c203dceb2befdf026462.ttf:--font-funcs=ot:U+0061,U+0061,U+0061:[]
diff --git a/test/shaping/tests/use-marchen.tests b/test/shaping/tests/use-marchen.tests
new file mode 100644
index 000000000..6497178ab
--- /dev/null
+++ b/test/shaping/tests/use-marchen.tests
@@ -0,0 +1,35 @@
+fonts/sha1sum/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf::U+11C8F:[u11C8F=0+3000]
+fonts/sha1sum/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf::U+11C71:[u11C71=0+1600]
+fonts/sha1sum/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf::U+11C8A,U+11CB5:[u11C8A=0+2000|u11CB5=0@-2000,0+0]
+fonts/sha1sum/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf::U+11C84,U+11C71:[u11C84=0+2200|u11C71=1+1600]
+fonts/sha1sum/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf::U+11C7E,U+11C8A:[u11C7E=0+2600|u11C8A=1+2000]
+fonts/sha1sum/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf::U+11C8A,U+11C92,U+11CA9:[u11C8A.11C92.11CA9=0+2600]
+fonts/sha1sum/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf::U+11C8A,U+11C94,U+11CA9:[u11C8A.11C94.11CA9=0+2600]
+fonts/sha1sum/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf::U+11C8D,U+11C92,U+11CA9:[u11C8D.11C92.11CA9=0+2600]
+fonts/sha1sum/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf::U+11C8D,U+11C94,U+11CA9:[u11C8D.11C94.11CA9=0+2600]
+fonts/sha1sum/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf::U+11C8D,U+11C9E,U+11CA9:[u11C8D.11C9E.11CA9=0+3200]
+fonts/sha1sum/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf::U+11C8D,U+11CA0,U+11CA9:[u11C8D.11CA0.11CA9=0+3000]
+fonts/sha1sum/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf::U+11C8D,U+11C92,U+11CAA:[u11C8D.11C92.11CAA=0+2000]
+fonts/sha1sum/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf::U+11C8D,U+11C94,U+11CAA:[u11C8D.11C94.11CAA=0+2000]
+fonts/sha1sum/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf::U+11C8D,U+11C9D,U+11CAA:[u11C8D.11C9D.11CAA=0+2000]
+fonts/sha1sum/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf::U+11C8D,U+11C9E,U+11CAA:[u11C8D.11C9E.11CAA=0+2600]
+fonts/sha1sum/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf::U+11C8D,U+11CA0,U+11CAA:[u11C8D.11CA0.11CAA=0+2400]
+fonts/sha1sum/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf::U+11C80,U+11C72,U+11CAA:[u11C80=0+2400|u11C72.11CAA=1+2000]
+fonts/sha1sum/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf::U+11C8C,U+11CB1,U+11C8D:[u11C8C.11CB1=0+2793|u11C8D=2+2000]
+fonts/sha1sum/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf::U+11C80,U+11C7C,U+11CB3:[u11C80=0+2400|u11C7C.11CB3=1+2200]
+fonts/sha1sum/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf::U+11C7F,U+11CB2,U+11C7D:[u11C7F.11CB2=0+2400|u11C7D=2+2000]
+fonts/sha1sum/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf::U+11C8D,U+11CB2,U+11C81:[u11C8D.11CB2=0+2000|u11C81=2+2400]
+fonts/sha1sum/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf::U+11C8C,U+11CB4,U+11C74:[u11C8C.11CB4=0+2800|u11C74=2+2000]
+fonts/sha1sum/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf::U+11C8A,U+11CA1,U+11CA9,U+11C71:[u11C8A.11CA1.11CA9=0+3000|u11C71=3+1600]
+fonts/sha1sum/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf::U+11C8D,U+11CA1,U+11CA9,U+11C71:[u11C8D.11CA1.11CA9=0+3000|u11C71=3+1600]
+fonts/sha1sum/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf::U+11C8D,U+11CA1,U+11CAA,U+11C71:[u11C8D.11CA1.11CAA=0+2400|u11C71=3+1600]
+fonts/sha1sum/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf::U+11C8F,U+11CB0,U+11CB4,U+11CB6:[u11C8F.11CB0.11CB4=0+3600|u11CB6=0@-3200,0+0]
+fonts/sha1sum/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf::U+11C8E,U+11CB0,U+11CB2,U+11CB5:[u11C8E.11CB0.11CB2=0+2000|u11CB5=0@-2000,0+0]
+fonts/sha1sum/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf::U+11C74,U+11C89,U+11CB2,U+11C75:[u11C74=0+2000|u11C89.11CB2=1+2000|u11C75=3+2000]
+fonts/sha1sum/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf::U+11C7C,U+11CAA,U+11CB2,U+11C75:[u11C7C.11CAA.11CB2=0+2200|u11C75=3+2000]
+fonts/sha1sum/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf::U+11C81,U+11C74,U+11CB2,U+11C8B:[u11C81=0+2400|u11C74.11CB2=1+2000|u11C8B=3+2400]
+fonts/sha1sum/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf::U+11C8B,U+11CB3,U+11C74,U+11C8D:[u11C8B.11CB3=0+2400|u11C74=2+2000|u11C8D=3+2000]
+fonts/sha1sum/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf::U+11C83,U+11CB4,U+11C74,U+11C8D:[u11C83.11CB4=0+2800|u11C74=2+2000|u11C8D=3+2000]
+fonts/sha1sum/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf::U+11C8B,U+11CB3,U+11C74,U+11C8D,U+11C71:[u11C8B.11CB3=0+2400|u11C74=2+2000|u11C8D=3+2000|u11C71=4+1600]
+fonts/sha1sum/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf::U+11C80,U+11C76,U+11CB1,U+11C75,U+11C8D:[u11C80=0+2400|u11C76.11CB1=1+3200|u11C75=3+2000|u11C8D=4+2000]
+fonts/sha1sum/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf::U+11C80,U+11C8D,U+11C94,U+11CAA,U+11CB1,U+11C74,U+11C8D:[u11C80=0+2400|u11C8D.11C94.11CAA.11CB1.shorti=1+2600|u11C74=5+2000|u11C8D=6+2000]
diff --git a/test/shaping/tests/vertical.tests b/test/shaping/tests/vertical.tests
index 827689088..3586080f8 100644
--- a/test/shaping/tests/vertical.tests
+++ b/test/shaping/tests/vertical.tests
@@ -1 +1,3 @@
fonts/sha1sum/191826b9643e3f124d865d617ae609db6a2ce203.ttf:--direction=t:U+300C:[uni300C.vert=0@-512,-578+0,-1024]
+fonts/sha1sum/f9b1dd4dcb515e757789a22cb4241107746fd3d0.ttf:--direction=t --font-funcs=ft:U+0041,U+0042:[gid1=0@-654,-2128+0,-2789|gid2=1@-665,-2125+0,-2789]
+fonts/sha1sum/f9b1dd4dcb515e757789a22cb4241107746fd3d0.ttf:--direction=t --font-funcs=ot:U+0041,U+0042:[gid1=0@-654,-2189+0,-2789|gid2=1@-665,-2189+0,-2789]
diff --git a/util/helper-cairo.cc b/util/helper-cairo.cc
index 8f30eea14..2e2952b28 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 @@ helper_cairo_create_scaled_font (const font_options_t *font_opts)
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 @@ helper_cairo_create_scaled_font (const font_options_t *font_opts)
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 bc699c1d1..0f2e207d0 100644
--- a/util/options.cc
+++ b/util/options.cc
@@ -254,6 +254,47 @@ parse_features (const char *name G_GNUC_UNUSED,
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 @@ view_options_t::add_options (option_parser_t *parser)
parser->add_group (entries,
"view",
"View options:",
- "Options controlling output rendering",
+ "Options for output rendering",
this);
}
@@ -299,7 +340,7 @@ shape_options_t::add_options (option_parser_t *parser)
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 @@ shape_options_t::add_options (option_parser_t *parser)
parser->add_group (entries2,
"features",
"Features options:",
- "Options controlling font features used",
+ "Options for font features used",
this);
}
@@ -413,7 +454,30 @@ font_options_t::add_options (option_parser_t *parser)
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 @@ text_options_t::add_options (option_parser_t *parser)
parser->add_group (entries,
"text",
"Text options:",
- "Options controlling the input text",
+ "Options for the input text",
this);
}
@@ -459,7 +523,7 @@ output_options_t::add_options (option_parser_t *parser)
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 @@ font_options_t::get_font (void) const
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 @@ format_options_t::add_options (option_parser_t *parser)
" 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 919e4f8b2..9ed4fd0e2 100644
--- a/util/options.hh
+++ b/util/options.hh
@@ -285,7 +285,10 @@ struct font_options_t : option_group_t
{
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 @@ struct font_options_t : option_group_t
}
~font_options_t (void) {
g_free (font_file);
+ free (variations);
g_free (font_funcs);
hb_font_destroy (font);
}
@@ -309,6 +313,8 @@ struct font_options_t : option_group_t
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/README.txt b/win32/README.txt
index e2ead01d0..af0dc15c1 100644
--- a/win32/README.txt
+++ b/win32/README.txt
@@ -7,11 +7,10 @@ Makefiles.
The following are instructions for performing such a build, as there is a
number of build configurations supported for the build. Note that for all
build configurations, the OpenType and Simple TrueType layout (fallback)
-backends are enabled, as well as the Uniscribe platform shaper, and this
-is the base configuration that is built if no options (see below) are
-specified. A 'clean' target is provided-it is recommended that one cleans
-the build and redo the build if any configuration option changed. An
-'install' target is also provided to copy the built items in their appropriate
+backends are enabled, and this is the base configuration that is built if no
+options (see below) are specified. A 'clean' target is provided-it is recommended
+that one cleans the build and redo the build if any configuration option changed.
+An 'install' target is also provided to copy the built items in their appropriate
locations under $(PREFIX), which is described below.
Invoke the build by issuing the command:
@@ -64,11 +63,11 @@ CAIRO_FT: Enable the build of the hb-view tool, which makes use of Cairo, and
GRAPHITE2: Enable the Graphite2 shaper, requires the SIL Graphite2 library.
-ICU: Enables the build HarfBuzz-ICU, which is now the recommended layout engine
- for ICU (International Components for Unicode), which deprecated ICU LE.
- Requires the ICU libraries.
+ICU: Enables the build of ICU Unicode functions. Requires the ICU libraries.
-DIRECTWRITE: Enable (experimental) DirectWrite platform shaper support,
+UNISCRIBE: Enable Uniscribe platform shaper support.
+
+DIRECTWRITE: Enable DirectWrite platform shaper support,
requires a rather recent Windows SDK, and at least Windows Vista/
Server 2008 with SP2 and platform update.
diff --git a/win32/build-rules-msvc.mak b/win32/build-rules-msvc.mak
index 03b383373..bfe02864a 100644
--- a/win32/build-rules-msvc.mak
+++ b/win32/build-rules-msvc.mak
@@ -23,11 +23,6 @@ $<
$<
<<
-{..\src\}.cc{$(CFG)\$(PLAT)\harfbuzz-icu\}.obj::
- $(CXX) $(CFLAGS) $(HB_LIB_CFLAGS) $(HB_ICU_CFLAGS) /Fo$(CFG)\$(PLAT)\harfbuzz-icu\ /c @<<
-$<
-<<
-
{..\util\}.cc{$(CFG)\$(PLAT)\util\}.obj::
$(CXX) $(CFLAGS) $(HB_DEFINES) $(HB_CFLAGS) /Fo$(CFG)\$(PLAT)\util\ /c @<<
$<
@@ -48,7 +43,6 @@ $<
# Rules for building .lib files
$(CFG)\$(PLAT)\harfbuzz.lib: $(HARFBUZZ_DLL_FILENAME).dll
-$(CFG)\$(PLAT)\harfbuzz-icu.lib: $(HARFBUZZ_ICU_DLL_FILENAME).dll
$(CFG)\$(PLAT)\harfbuzz-gobject.lib: $(HARFBUZZ_GOBJECT_DLL_FILENAME).dll
# Rules for linking DLLs
@@ -64,12 +58,6 @@ $(harfbuzz_dll_OBJS)
<<
@-if exist $@.manifest mt /manifest $@.manifest /outputresource:$@;2
-$(HARFBUZZ_ICU_DLL_FILENAME).dll: $(CFG)\$(PLAT)\harfbuzz.lib $(harfbuzz_icu_OBJS) $(CFG)\$(PLAT)\harfbuzz-icu
- link /DLL $(LDFLAGS) $(CFG)\$(PLAT)\harfbuzz.lib $(HB_ICU_DEP_LIBS) /implib:$(CFG)\$(PLAT)\harfbuzz-icu.lib -out:$@ @<<
-$(harfbuzz_icu_OBJS)
-<<
- @-if exist $@.manifest mt /manifest $@.manifest /outputresource:$@;2
-
$(HARFBUZZ_GOBJECT_DLL_FILENAME).dll: $(CFG)\$(PLAT)\harfbuzz.lib $(harfbuzz_gobject_OBJS) $(CFG)\$(PLAT)\harfbuzz-gobject
link /DLL $(LDFLAGS) $(CFG)\$(PLAT)\harfbuzz.lib $(HB_GOBJECT_DEP_LIBS) /implib:$(CFG)\$(PLAT)\harfbuzz-gobject.lib -out:$@ @<<
$(harfbuzz_gobject_OBJS)
@@ -131,7 +119,6 @@ clean:
@-del /f /q $(CFG)\$(PLAT)\*.obj
@-if exist $(CFG)\$(PLAT)\util del /f /q $(CFG)\$(PLAT)\util\*.obj
@-if exist $(CFG)\$(PLAT)\harfbuzz-gobject del /f /q $(CFG)\$(PLAT)\harfbuzz-gobject\*.obj
- @-if exist $(CFG)\$(PLAT)\harfbuzz-icu del /f /q $(CFG)\$(PLAT)\harfbuzz-icu\*.obj
@-del /f /q $(CFG)\$(PLAT)\harfbuzz\*.obj
@-rmdir /s /q $(CFG)\$(PLAT)
@-if exist $(CFG)\$(PLAT)\harfbuzz-gobject\hb-gobject-enums.h del $(CFG)\$(PLAT)\harfbuzz-gobject\hb-gobject-enums.h
diff --git a/win32/config-msvc.mak b/win32/config-msvc.mak
index e0c6468e3..4cffaeacc 100644
--- a/win32/config-msvc.mak
+++ b/win32/config-msvc.mak
@@ -12,7 +12,11 @@ HB_GLIB_LIBS = glib-2.0.lib
HB_GOBJECT_DEP_LIBS = gobject-2.0.lib $(HB_GLIB_LIBS)
# Freetype is needed for building FreeType support and hb-view
+!if "$(CFG)" == "debug"
+FREETYPE_LIB = freetyped.lib
+!else
FREETYPE_LIB = freetype.lib
+!endif
# Cairo is needed for building hb-view
CAIRO_LIB = cairo.lib
@@ -20,6 +24,9 @@ CAIRO_LIB = cairo.lib
# Graphite2 is needed for building SIL Graphite2 support
GRAPHITE2_LIB = graphite2.lib
+# Uniscribe is needed for Uniscribe shaping support
+UNISCRIBE_LIB = usp10.lib gdi32.lib rpcrt4.lib user32.lib
+
# Directwrite is needed for DirectWrite shaping support
DIRECTWRITE_LIB = dwrite.lib
@@ -31,17 +38,15 @@ HB_UCDN_CFLAGS = /I..\src\hb-ucdn
HB_SOURCES = \
$(HB_BASE_sources) \
$(HB_FALLBACK_sources) \
- $(HB_OT_sources) \
- $(HB_UNISCRIBE_sources) \
+ $(HB_OT_sources)
HB_HEADERS = \
$(HB_BASE_headers) \
$(HB_NODIST_headers) \
- $(HB_OT_headers) \
- $(HB_UNISCRIBE_headers)
+ $(HB_OT_headers)
# Minimal set of (system) libraries needed for the HarfBuzz DLL
-HB_DEP_LIBS = usp10.lib gdi32.lib rpcrt4.lib user32.lib
+HB_DEP_LIBS =
# We build the HarfBuzz DLL/LIB at least
HB_LIBS = $(CFG)\$(PLAT)\harfbuzz.lib
@@ -55,29 +60,12 @@ HB_TESTS_DEP_LIBS = $(HB_GLIB_LIBS)
# Use libtool-style DLL names, if desired
!if "$(LIBTOOL_DLL_NAME)" == "1"
HARFBUZZ_DLL_FILENAME = $(CFG)\$(PLAT)\libharfbuzz-0
-HARFBUZZ_ICU_DLL_FILENAME = $(CFG)\$(PLAT)\libharfbuzz-icu-0
HARFBUZZ_GOBJECT_DLL_FILENAME = $(CFG)\$(PLAT)\libharfbuzz-gobject-0
!else
HARFBUZZ_DLL_FILENAME = $(CFG)\$(PLAT)\harfbuzz-vs$(VSVER)
-HARFBUZZ_ICU_DLL_FILENAME = $(CFG)\$(PLAT)\harfbuzz-icu-vs$(VSVER)
HARFBUZZ_GOBJECT_DLL_FILENAME = $(CFG)\$(PLAT)\harfbuzz-gobject-vs$(VSVER)
!endif
-# Enable HarfBuzz-ICU, if desired
-!if "$(ICU)" == "1"
-HB_ICU_CFLAGS =
-HB_LIBS = \
- $(HB_LIBS) \
- $(CFG)\$(PLAT)\harfbuzz-icu.lib
-
-# We don't want to re-define int8_t Visual Studio 2008, will cause build breakage
-# as we define it in hb-common.h, and we ought to use the definitions there.
-!if "$(VSVER)" == "9"
-HB_ICU_CFLAGS = /DU_HAVE_INT8_T
-!endif
-
-!endif
-
# Enable Introspection (enables HarfBuzz-Gobject as well)
!if "$(INTROSPECTION)" == "1"
GOBJECT = 1
@@ -124,6 +112,9 @@ HB_DEFINES = $(HB_DEFINES) /DHAVE_CAIRO=1
# Enable freetype if desired
!if "$(FREETYPE)" == "1"
+!if "$(FREETYPE_DIR)" != ""
+HB_CFLAGS = $(HB_CFLAGS) /I$(FREETYPE_DIR)
+!endif
HB_DEFINES = $(HB_DEFINES) /DHAVE_FREETYPE=1
HB_SOURCES = $(HB_SOURCES) $(HB_FT_sources)
HB_HEADERS = $(HB_HEADERS) $(HB_FT_headers)
@@ -173,10 +164,31 @@ HB_TESTS = \
$(CFG)\$(PLAT)\test-unicode.exe \
$(CFG)\$(PLAT)\test-version.exe
-!else
-# If there is no GLib support, use the built-in UCDN
+!elseif "$(ICU)" == "1"
+# use ICU for Unicode functions
# and define some of the macros in GLib's msvc_recommended_pragmas.h
# to reduce some unneeded build-time warnings
+HB_DEFINES = $(HB_DEFINES) /DHAVE_ICU=1 /DHAVE_ICU_BUILTIN=1
+HB_CFLAGS = \
+ $(HB_CFLAGS) \
+ /wd4244 \
+ /D_CRT_SECURE_NO_WARNINGS \
+ /D_CRT_NONSTDC_NO_WARNINGS
+
+# We don't want ICU to re-define int8_t in VS 2008, will cause build breakage
+# as we define it in hb-common.h, and we ought to use the definitions there.
+!if "$(VSVER)" == "9"
+HB_CFLAGS = $(HB_CFLAGS) /DU_HAVE_INT8_T
+!endif
+
+HB_SOURCES = $(HB_SOURCES) $(HB_ICU_sources)
+HB_HEADERS = $(HB_HEADERS) $(HB_ICU_headers)
+HB_DEP_LIBS = $(HB_DEP_LIBS) $(HB_ICU_DEP_LIBS)
+!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 = \
$(HB_CFLAGS) \
@@ -188,6 +200,13 @@ HB_CFLAGS = \
HB_SOURCES = $(HB_SOURCES) $(LIBHB_UCDN_sources) $(HB_UCDN_sources)
!endif
+!if "$(UNISCRIBE)" == "1"
+HB_CFLAGS = $(HB_CFLAGS) /DHAVE_UNISCRIBE
+HB_SOURCES = $(HB_SOURCES) $(HB_UNISCRIBE_sources)
+HB_HEADERS = $(HB_HEADERS) $(HB_UNISCRIBE_headers)
+HB_DEP_LIBS = $(HB_DEP_LIBS) $(UNISCRIBE_LIB)
+!endif
+
!if "$(DIRECTWRITE)" == "1"
HB_CFLAGS = $(HB_CFLAGS) /DHAVE_DIRECTWRITE
HB_SOURCES = $(HB_SOURCES) $(HB_DIRECTWRITE_sources)
diff --git a/win32/config.h.win32.in b/win32/config.h.win32.in
index 73ad205d5..d45cefb5e 100644
--- a/win32/config.h.win32.in
+++ b/win32/config.h.win32.in
@@ -115,7 +115,7 @@
#define HAVE_UCDN 1
/* Have Uniscribe library */
-#define HAVE_UNISCRIBE 1
+/* #undef HAVE_UNISCRIBE */
/* Define to 1 if you have the <unistd.h> header file. */
#ifndef _MSC_VER
diff --git a/win32/create-lists-msvc.mak b/win32/create-lists-msvc.mak
index 9b5574bf9..dbd2a579c 100644
--- a/win32/create-lists-msvc.mak
+++ b/win32/create-lists-msvc.mak
@@ -59,19 +59,6 @@ NULL=
!endif
!endif
-# For HarfBuzz-ICU
-!if "$(ICU)" == "1"
-
-!if [call create-lists.bat header hb_objs.mak harfbuzz_icu_OBJS]
-!endif
-
-!if [for %c in ($(HB_ICU_sources)) do @if "%~xc" == ".cc" @call create-lists.bat file hb_objs.mak ^$(CFG)\^$(PLAT)\harfbuzz-icu\%~nc.obj]
-!endif
-
-!if [call create-lists.bat footer hb_objs.mak]
-!endif
-!endif
-
# For the utility programs (GLib support is required)
!if "$(GLIB)" == "1"
diff --git a/win32/detectenv-msvc.mak b/win32/detectenv-msvc.mak
index 83d87862c..ca09793cb 100644
--- a/win32/detectenv-msvc.mak
+++ b/win32/detectenv-msvc.mak
@@ -110,7 +110,9 @@ VALID_CFGSET = TRUE
# the resulting binaries
!if "$(CFG)" == "release"
CFLAGS_ADD = /MD /O2 /GL /MP
-!if "$(VSVER)" != "9"
+!if $(VSVER) > 9 && $(VSVER) < 14
+# Undocumented "enhance optimized debugging" switch. Became documented
+# as "/Zo" in VS 2013 Update 3, and is turned on by default in VS 2015.
CFLAGS_ADD = $(CFLAGS_ADD) /d2Zi+
!endif
!else
@@ -129,7 +131,10 @@ LDFLAGS_ARCH = /machine:x86
!if "$(VALID_CFGSET)" == "TRUE"
CFLAGS = $(CFLAGS_ADD) /W3 /Zi /I.. /I..\src /I. /I$(PREFIX)\include
-LDFLAGS_BASE = $(LDFLAGS_ARCH) /libpath:$(PREFIX)\lib /DEBUG
+!if "$(ADDITIONAL_LIB_DIR)" != ""
+ADDITIONAL_LIB_ARG = /libpath:$(ADDITIONAL_LIB_DIR)
+!endif
+LDFLAGS_BASE = $(LDFLAGS_ARCH) /libpath:$(PREFIX)\lib $(ADDITIONAL_LIB_ARG) /DEBUG
!if "$(CFG)" == "debug"
LDFLAGS = $(LDFLAGS_BASE)
diff --git a/win32/generate-msvc.mak b/win32/generate-msvc.mak
index 7c17a9465..32214ebbf 100644
--- a/win32/generate-msvc.mak
+++ b/win32/generate-msvc.mak
@@ -22,5 +22,5 @@ $(HB_GOBJECT_ENUM_GENERATED_SOURCES): ..\src\hb-gobject-enums.h.tmpl ..\src\hb-g
!endif
# Create the build directories
-$(CFG)\$(PLAT)\harfbuzz $(CFG)\$(PLAT)\harfbuzz-icu $(CFG)\$(PLAT)\harfbuzz-gobject $(CFG)\$(PLAT)\util:
- @-mkdir -p $@
+$(CFG)\$(PLAT)\harfbuzz $(CFG)\$(PLAT)\harfbuzz-gobject $(CFG)\$(PLAT)\util:
+ @-md $@
diff --git a/win32/info-msvc.mak b/win32/info-msvc.mak
index bc85dc9c9..3ec11d4dc 100644
--- a/win32/info-msvc.mak
+++ b/win32/info-msvc.mak
@@ -1,6 +1,6 @@
# NMake Makefile portion for displaying config info
-INC_FEATURES = Uniscribe Fallback OT
+INC_FEATURES = Fallback OT
BUILT_TOOLS =
BUILT_LIBRARIES = HarfBuzz
@@ -11,6 +11,8 @@ BUILT_TOOLS = hb-shape.exe hb-ot-shape-closure.exe
!if "$(CAIRO_FT)" == "1"
BUILT_TOOLS = hb-view.exe $(BUILT_TOOLS)
!endif
+!elseif "$(ICU)" == "1"
+UNICODE_IMPL = ICU
!else
UNICODE_IMPL = ucdn
!endif
@@ -23,12 +25,12 @@ INC_FEATURES = $(INC_FEATURES) FreeType
INC_FEATURES = $(INC_FEATURES) Graphite2
!endif
-!if "$(DIRECTWRITE)" == "1"
-INC_FEATURES = $(INC_FEATURES) DirectWrite
+!if "$(UNISCRIBE)" == "1"
+INC_FEATURES = $(INC_FEATURES) Uniscribe
!endif
-!if "$(ICU)" == "1"
-BUILT_LIBRARIES = $(BUILT_LIBRARIES) HarfBuzz-ICU
+!if "$(DIRECTWRITE)" == "1"
+INC_FEATURES = $(INC_FEATURES) DirectWrite
!endif
!if "$(GOBJECT)" == "1"
@@ -77,9 +79,12 @@ help:
@echo.
@echo OPTION: Optional, may be any of the following, use OPTION=1 to enable;
@echo multiple OPTION's may be used. If no OPTION is specified, a default
- @echo HarfBuzz DLL is built with OpenType, fallback and Uniscribe support
+ @echo HarfBuzz DLL is built with OpenType and fallback support
@echo with a bundled Unicode implementation (UCDN).
@echo ======
+ @echo UNISCRIBE:
+ @echo Enable Uniscribe support.
+ @echo.
@echo DIRECTWRITE:
@echo Enable DirectWrite support, requires a recent enough Windows SDK.
@echo.
@@ -94,20 +99,20 @@ help:
@echo library. Enables the build of utility programs.
@echo.
@echo ICU:
- @echo Enable the HarfBuzz-ICU layout library, requires the International
+ @echo Enable build with ICU Unicode functions, requires the International
@echo Components for Unicode (ICU) libraries.
@echo.
@echo GOBJECT:
@echo Enable the HarfBuzz-GObject library, also implies GLib2 support,
@echo requires the GNOME GLib2 libraries and tools, notably the glib-mkenums
- @echo tool script, which will require a PERL interpretor (use
+ @echo tool script, which will require a PERL interpreter (use
@echo PERL=^$(PATH_TO_PERL_INTERPRETOR)) if it is not already in your PATH).
@echo.
@echo INTROSPECTION:
@echo Enable the build of introspection files, also implies GObject/GLib2 support,
@echo requires the GNOME gobject-introspection libraries and tools. You will need
@echo to ensure the pkg-config (.pc) files can be found for GObject-2.0 and the
- @echo Python interpretor (that was used to build the gobject-introsoection tools)
+ @echo Python interpreter (that was used to build the gobject-introspection tools)
@echo can be found by setting PKG_CONFIG_PATH beforehand, and passing in PYTHON=
@echo ^$(PATH_TO_PYTHON_INTERPRETOR) respectively, if python.exe is not already
@echo in your PATH.
diff --git a/win32/install.mak b/win32/install.mak
index fa239eaac..e0a38e316 100644
--- a/win32/install.mak
+++ b/win32/install.mak
@@ -8,9 +8,6 @@ install: all
@copy /b $(HARFBUZZ_DLL_FILENAME).dll $(PREFIX)\bin
@copy /b $(HARFBUZZ_DLL_FILENAME).pdb $(PREFIX)\bin
@copy /b $(CFG)\$(PLAT)\harfbuzz.lib $(PREFIX)\lib
- @if exist $(HARFBUZZ_ICU_DLL_FILENAME).dll copy /b $(HARFBUZZ_ICU_DLL_FILENAME).dll $(PREFIX)\bin
- @if exist $(HARFBUZZ_ICU_DLL_FILENAME).dll copy /b $(HARFBUZZ_ICU_DLL_FILENAME).pdb $(PREFIX)\bin
- @if exist $(HARFBUZZ_ICU_DLL_FILENAME).dll copy /b $(CFG)\$(PLAT)\harfbuzz-icu.lib $(PREFIX)\lib
@if exist $(HARFBUZZ_GOBJECT_DLL_FILENAME).dll copy /b $(HARFBUZZ_GOBJECT_DLL_FILENAME).dll $(PREFIX)\bin
@if exist $(HARFBUZZ_GOBJECT_DLL_FILENAME).dll copy /b $(HARFBUZZ_GOBJECT_DLL_FILENAME).pdb $(PREFIX)\bin
@if exist $(HARFBUZZ_GOBJECT_DLL_FILENAME).dll copy /b $(CFG)\$(PLAT)\harfbuzz-gobject.lib $(PREFIX)\lib
@@ -21,7 +18,6 @@ install: all
@if exist $(CFG)\$(PLAT)\hb-shape.exe copy /b $(CFG)\$(PLAT)\hb-shape.exe $(PREFIX)\bin
@if exist $(CFG)\$(PLAT)\hb-shape.exe copy /b $(CFG)\$(PLAT)\hb-shape.pdb $(PREFIX)\bin
@for %h in ($(HB_ACTUAL_HEADERS)) do @copy %h $(PREFIX)\include\harfbuzz
- @if exist $(HARFBUZZ_ICU_DLL_FILENAME).dll for %h in ($(HB_ICU_headers)) do @copy ..\src\%h $(PREFIX)\include\harfbuzz
@if exist $(HARFBUZZ_GOBJECT_DLL_FILENAME).dll for %h in ($(HB_GOBJECT_headers)) do @copy ..\src\%h $(PREFIX)\include\harfbuzz
@if exist $(HARFBUZZ_GOBJECT_DLL_FILENAME).dll copy $(CFG)\$(PLAT)\harfbuzz-gobject\hb-gobject-enums.h $(PREFIX)\include\harfbuzz
@rem Copy the generated introspection files