Merge branch 'master' into var-subset
This commit is contained in:
commit
4ddab6facc
@ -34,7 +34,7 @@ jobs:
|
||||
|
||||
distcheck:
|
||||
docker:
|
||||
- image: ubuntu:17.10
|
||||
- image: ubuntu:19.04
|
||||
steps:
|
||||
- checkout
|
||||
- run: apt update && apt install -y ninja-build binutils libtool autoconf automake make cmake gcc g++ pkg-config ragel gtk-doc-tools libfontconfig1-dev libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python python-pip
|
||||
@ -192,18 +192,27 @@ jobs:
|
||||
- run: make -j32
|
||||
- run: make check || .ci/fail.sh | asan_symbolize | c++filt
|
||||
|
||||
fedora-O0-debug-outoftreebuild:
|
||||
fedora-O0-debug-outoftreebuild-mingw:
|
||||
docker:
|
||||
- image: fedora
|
||||
steps:
|
||||
- checkout
|
||||
- run: dnf install -y pkg-config ragel gcc gcc-c++ automake autoconf libtool make which glib2-devel freetype-devel cairo-devel libicu-devel gobject-introspection-devel graphite2-devel redhat-rpm-config python || true
|
||||
- run: dnf install -y pkg-config ragel gcc gcc-c++ automake autoconf libtool make which glib2-devel freetype-devel cairo-devel libicu-devel gobject-introspection-devel graphite2-devel redhat-rpm-config python wine mingw32-gcc-c++ mingw64-gcc-c++ mingw32-glib2 mingw32-cairo mingw32-freetype mingw64-glib2 mingw64-cairo mingw64-freetype glibc-devel.i686 || true
|
||||
- run: CFLAGS="-O0" CXXFLAGS="-O0" CPPFLAGS="-DHB_DEBUG" NOCONFIGURE=1 ./autogen.sh --with-freetype --with-glib --with-gobject --with-cairo --with-icu --with-graphite2
|
||||
- run: mkdir build && cd build && ../configure && make && (make check || ../.ci/fail.sh)
|
||||
- run: mkdir build && cd build && ../configure && make -j32 && (make check || ../.ci/fail.sh)
|
||||
- run: pip install pefile
|
||||
- run: mkdir winbuild32 && cd winbuild32 && ../mingw32.sh && make -j32 && make dist-win && cp harfbuzz-*-win32.zip harfbuzz-win32.zip
|
||||
- run: mkdir winbuild64 && cd winbuild64 && ../mingw64.sh && make -j32 && make dist-win && cp harfbuzz-*-win64.zip harfbuzz-win64.zip
|
||||
- store_artifacts:
|
||||
path: winbuild32/harfbuzz-win32.zip
|
||||
destination: harfbuzz-win32.zip
|
||||
- store_artifacts:
|
||||
path: winbuild64/harfbuzz-win64.zip
|
||||
destination: harfbuzz-win64.zip
|
||||
|
||||
cmake-gcc:
|
||||
docker:
|
||||
- image: ubuntu:17.10
|
||||
- image: ubuntu:19.04
|
||||
steps:
|
||||
- checkout
|
||||
- run: apt update && apt install -y ninja-build binutils cmake gcc g++ pkg-config ragel gtk-doc-tools libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python python-pip
|
||||
@ -213,17 +222,17 @@ jobs:
|
||||
- run: CTEST_OUTPUT_ON_FAILURE=1 ninja -Cbuild test
|
||||
- run: ninja -Cbuild install
|
||||
|
||||
cmake-oracledeveloperstudio:
|
||||
docker:
|
||||
- image: fedora
|
||||
steps:
|
||||
- checkout
|
||||
- run: dnf install -y gcc ragel cmake make which glib2-devel freetype-devel cairo-devel libicu-devel graphite2-devel wget tar bzip2 python libnsl || true
|
||||
- run: wget http://$ODSUSER:$ODSPASS@behdad.org/harfbuzz-private/OracleDeveloperStudio12.6-linux-x86-bin.tar.bz2 && tar xf OracleDeveloperStudio12.6-linux-x86-bin.tar.bz2 --owner root --group root --no-same-owner
|
||||
- run: CC=/root/project/OracleDeveloperStudio12.6-linux-x86-bin/developerstudio12.6/bin/suncc CXX=/root/project/OracleDeveloperStudio12.6-linux-x86-bin/developerstudio12.6/bin/sunCC cmake -DHB_HAVE_GRAPHITE2=ON -DHB_BUILTIN_UCDN=ON -DHB_HAVE_GLIB=ON -DHB_HAVE_FREETYPE=ON -Bbuild -H.
|
||||
- run: make -Cbuild -j32
|
||||
- run: CTEST_OUTPUT_ON_FAILURE=1 make -Cbuild test
|
||||
- run: make -Cbuild install
|
||||
#cmake-oracledeveloperstudio:
|
||||
# docker:
|
||||
# - image: fedora
|
||||
# steps:
|
||||
# - checkout
|
||||
# - run: dnf install -y gcc ragel cmake make which glib2-devel freetype-devel cairo-devel libicu-devel graphite2-devel wget tar bzip2 python libnsl || true
|
||||
# - run: wget http://$ODSUSER:$ODSPASS@behdad.org/harfbuzz-private/OracleDeveloperStudio12.6-linux-x86-bin.tar.bz2 && tar xf OracleDeveloperStudio12.6-linux-x86-bin.tar.bz2 --owner root --group root --no-same-owner
|
||||
# - run: CC=/root/project/OracleDeveloperStudio12.6-linux-x86-bin/developerstudio12.6/bin/suncc CXX=/root/project/OracleDeveloperStudio12.6-linux-x86-bin/developerstudio12.6/bin/sunCC cmake -DHB_HAVE_GRAPHITE2=ON -DHB_HAVE_GLIB=ON -DHB_HAVE_FREETYPE=ON -Bbuild -H.
|
||||
# - run: make -Cbuild -j32
|
||||
# - run: CTEST_OUTPUT_ON_FAILURE=1 make -Cbuild test
|
||||
# - run: make -Cbuild install
|
||||
|
||||
crosscompile-notest-djgpp:
|
||||
docker:
|
||||
@ -253,12 +262,12 @@ jobs:
|
||||
- run: cmake -Bbuild -H. -GNinja
|
||||
- run: ninja -Cbuild
|
||||
|
||||
crosscompile-cmake-notest-browser-asmjs:
|
||||
crosscompile-cmake-notest-browser-asmjs-hb_tiny:
|
||||
docker:
|
||||
- image: dockcross/browser-asmjs
|
||||
steps:
|
||||
- checkout
|
||||
- run: cmake -Bbuild -H. -GNinja
|
||||
- run: cmake -Bbuild -H. -GNinja -DCMAKE_CXX_FLAGS="-DHB_TINY"
|
||||
- run: ninja -Cbuild
|
||||
|
||||
crosscompile-cmake-notest-linux-arm64:
|
||||
@ -308,7 +317,7 @@ workflows:
|
||||
- clang-msan
|
||||
- clang-tsan
|
||||
- clang-ubsan
|
||||
- fedora-O0-debug-outoftreebuild
|
||||
- fedora-O0-debug-outoftreebuild-mingw
|
||||
|
||||
# cmake based builds
|
||||
- cmake-gcc
|
||||
@ -322,7 +331,7 @@ workflows:
|
||||
|
||||
## cmake
|
||||
- crosscompile-cmake-notest-android-arm
|
||||
- crosscompile-cmake-notest-browser-asmjs
|
||||
- crosscompile-cmake-notest-browser-asmjs-hb_tiny
|
||||
- crosscompile-cmake-notest-linux-arm64
|
||||
- crosscompile-cmake-notest-linux-mips
|
||||
#- crosscompile-cmake-notest-windows-x64
|
||||
|
@ -1,5 +1,5 @@
|
||||
# Build Configuration for Travis
|
||||
dist: trusty
|
||||
dist: xenial
|
||||
|
||||
language: cpp
|
||||
|
||||
|
@ -35,7 +35,6 @@ endif ()
|
||||
## HarfBuzz build configurations
|
||||
option(HB_HAVE_FREETYPE "Enable freetype interop helpers" OFF)
|
||||
option(HB_HAVE_GRAPHITE2 "Enable Graphite2 complementary shaper" OFF)
|
||||
option(HB_BUILTIN_UCDN "Use HarfBuzz provided UCDN" ON)
|
||||
option(HB_HAVE_GLIB "Enable glib unicode functions" OFF)
|
||||
option(HB_HAVE_ICU "Enable icu unicode functions" OFF)
|
||||
if (APPLE)
|
||||
@ -70,7 +69,6 @@ option(HB_CHECK OFF "Do a configuration suitable for testing (shared library and
|
||||
if (HB_CHECK)
|
||||
set (BUILD_SHARED_LIBS ON)
|
||||
set (HB_BUILD_UTILS ON)
|
||||
set (HB_BUILTIN_UCDN ON)
|
||||
set (HB_HAVE_ICU)
|
||||
set (HB_HAVE_GLIB ON)
|
||||
#set (HB_HAVE_GOBJECT ON)
|
||||
@ -160,7 +158,6 @@ endfunction ()
|
||||
|
||||
file(READ ${PROJECT_SOURCE_DIR}/src/Makefile.sources SRCSOURCES)
|
||||
file(READ ${PROJECT_SOURCE_DIR}/util/Makefile.sources UTILSOURCES)
|
||||
file(READ ${PROJECT_SOURCE_DIR}/src/hb-ucdn/Makefile.sources UCDNSOURCES)
|
||||
|
||||
extract_make_variable(HB_BASE_sources ${SRCSOURCES})
|
||||
add_prefix_to_list(HB_BASE_sources "${PROJECT_SOURCE_DIR}/src/")
|
||||
@ -191,9 +188,6 @@ add_prefix_to_list(HB_SUBSET_CLI_sources "${PROJECT_SOURCE_DIR}/util/")
|
||||
extract_make_variable(HB_OT_SHAPE_CLOSURE_sources ${UTILSOURCES})
|
||||
add_prefix_to_list(HB_OT_SHAPE_CLOSURE_sources "${PROJECT_SOURCE_DIR}/util/")
|
||||
|
||||
extract_make_variable(LIBHB_UCDN_sources ${UCDNSOURCES})
|
||||
add_prefix_to_list(LIBHB_UCDN_sources "${PROJECT_SOURCE_DIR}/src/hb-ucdn/")
|
||||
|
||||
|
||||
file(READ configure.ac CONFIGUREAC)
|
||||
string(REGEX MATCH "\\[(([0-9]+)\\.([0-9]+)\\.([0-9]+))\\]" HB_VERSION_MATCH ${CONFIGUREAC})
|
||||
@ -295,14 +289,6 @@ if (HB_HAVE_GRAPHITE2)
|
||||
mark_as_advanced(GRAPHITE2_INCLUDE_DIR GRAPHITE2_LIBRARY)
|
||||
endif ()
|
||||
|
||||
if (HB_BUILTIN_UCDN)
|
||||
include_directories(src/hb-ucdn)
|
||||
add_definitions(-DHAVE_UCDN)
|
||||
|
||||
list(APPEND project_sources ${PROJECT_SOURCE_DIR}/src/hb-ucdn.cc)
|
||||
list(APPEND project_extra_sources ${LIBHB_UCDN_sources})
|
||||
endif ()
|
||||
|
||||
if (HB_HAVE_GLIB)
|
||||
add_definitions(-DHAVE_GLIB)
|
||||
|
||||
|
26
Makefile.am
26
Makefile.am
@ -9,12 +9,18 @@ SUBDIRS = src util test docs
|
||||
EXTRA_DIST = \
|
||||
autogen.sh \
|
||||
harfbuzz.doap \
|
||||
README.md \
|
||||
README.mingw.md \
|
||||
README.python.md \
|
||||
README.wine.md \
|
||||
BUILD.md \
|
||||
RELEASING.md \
|
||||
TESTING.md \
|
||||
CMakeLists.txt \
|
||||
replace-enum-strings.cmake \
|
||||
mingw-configure.sh \
|
||||
mingw-ldd.py \
|
||||
mingw32.sh \
|
||||
mingw64.sh \
|
||||
$(NULL)
|
||||
|
||||
MAINTAINERCLEANFILES = \
|
||||
@ -60,8 +66,6 @@ DISTCHECK_CONFIGURE_FLAGS = \
|
||||
--enable-introspection \
|
||||
$(NULL)
|
||||
|
||||
# TODO: Copy infrastructure from cairo
|
||||
|
||||
# TAR_OPTIONS is not set as env var for 'make dist'. How to fix that?
|
||||
TAR_OPTIONS = --owner=0 --group=0
|
||||
|
||||
@ -70,8 +74,7 @@ dist-hook: dist-clear-sticky-bits
|
||||
dist-clear-sticky-bits:
|
||||
chmod -R a-s $(distdir)
|
||||
|
||||
|
||||
tar_file = $(PACKAGE_TARNAME)-$(VERSION).tar.bz2
|
||||
tar_file = $(PACKAGE_TARNAME)-$(VERSION).tar.xz
|
||||
sha256_file = $(tar_file).sha256
|
||||
gpg_file = $(sha256_file).asc
|
||||
$(sha256_file): $(tar_file)
|
||||
@ -82,5 +85,18 @@ $(gpg_file): $(sha256_file)
|
||||
|
||||
release-files: $(tar_file) $(sha256_file) $(gpg_file)
|
||||
|
||||
dist-win:
|
||||
@case $(host_triplet) in *-w64-mingw32) ;; *) echo "Error: Requires mingw build. See README.mingw.md.">&2; exit 1 ;; esac
|
||||
@DIR=$(PACKAGE_TARNAME)-$(VERSION)-win`case $(host_triplet) in i686-*) echo 32 ;; x86_64-*) echo 64 ;; esac`; \
|
||||
$(RM) -r $$DIR; $(MKDIR_P) $$DIR || exit 1; \
|
||||
cp util/.libs/hb-{shape,view,subset}.exe $$DIR && \
|
||||
$(top_srcdir)/mingw-ldd.py $$DIR/hb-view.exe | grep -v 'not found' | cut -d '>' -f 2 | xargs cp -t $$DIR && \
|
||||
cp src/.libs/libharfbuzz{,-subset}-0.dll $$DIR && \
|
||||
chmod a+x $$DIR/*.{exe,dll} && \
|
||||
$(STRIP) $$DIR/*.{exe,dll} && \
|
||||
zip -r $$DIR.zip $$DIR && \
|
||||
$(RM) -r $$DIR && \
|
||||
echo "$$DIR.zip is ready."
|
||||
|
||||
|
||||
-include $(top_srcdir)/git.mk
|
||||
|
25
NEWS
25
NEWS
@ -1,3 +1,28 @@
|
||||
Overview of changes leading to 2.5.1
|
||||
Friday, May 31, 2019
|
||||
====================================
|
||||
- Fix build with various versions of Visual Studio.
|
||||
- Improved documentation, thanks to Nathan Willis.
|
||||
- Bugfix in subsetting glyf table.
|
||||
- Improved scripts for cross-compiling for Windows using mingw.
|
||||
- Rename HB_MATH_GLYPH_PART_FLAG_EXTENDER to HB_OT_MATH_GLYPH_PART_FLAG_EXTENDER.
|
||||
A deprecated macro is added for backwards-compatibility.
|
||||
|
||||
|
||||
Overview of changes leading to 2.5.0
|
||||
Friday, May 24, 2019
|
||||
====================================
|
||||
- This release does not include much functional changes, but includes major internal
|
||||
code-base changes. We now require C++11. Support for gcc 4.8 and earlier has been
|
||||
dropped.
|
||||
- New hb-config.hh facility for compiling smaller library for embedded and web usecases.
|
||||
- New Unicode Character Databse implementation that is half the size of previously-used
|
||||
UCDN.
|
||||
- Subsetter improvements.
|
||||
- Improved documentation, thanks to Nathan Willis.
|
||||
- Misc shaping fixes.
|
||||
|
||||
|
||||
Overview of changes leading to 2.4.0
|
||||
Monday, March 25, 2019
|
||||
====================================
|
||||
|
@ -13,6 +13,10 @@ For bug reports, mailing list, and other information please visit:
|
||||
|
||||
http://harfbuzz.org/
|
||||
|
||||
For license information, see the file COPYING.
|
||||
For license information, see [COPYING](COPYING).
|
||||
|
||||
For build information, see [BUILD.md](BUILD.md).
|
||||
|
||||
For test execution, see [TESTING.md](TESTING.md).
|
||||
|
||||
Documentation: https://harfbuzz.github.io
|
||||
|
48
README.mingw.md
Normal file
48
README.mingw.md
Normal file
@ -0,0 +1,48 @@
|
||||
For the development of HarfBuzz, the Microsoft shaping technology, Uniscribe,
|
||||
as a widely used and tested shaper is used as more-or-less OpenType reference
|
||||
implementation and that specially is important where OpenType specification
|
||||
is or wasn't that clear. For having access to Uniscribe on Linux/macOS these
|
||||
steps are recommended:
|
||||
|
||||
1. Install Wine from your favorite package manager. On Fedora that's `dnf install wine`.
|
||||
|
||||
2. And `mingw-w64` compiler.
|
||||
With `brew` on macOS, you can have it like `brew install mingw-w64`.
|
||||
On Fedora, with `dnf install mingw32-gcc-c++`, or `dnf install mingw64-gcc-c++` for the
|
||||
64-bit Windows.
|
||||
|
||||
3. Install cross-compiled dependency packages. Alternatively see [^1] below.
|
||||
On Fedora that would be `dnf install mingw32-glib2 mingw32-cairo mingw32-freetype`
|
||||
for 32-bit, or `dnf install mingw64-glib2 mingw64-cairo mingw64-freetype` for 64-bit.
|
||||
|
||||
5. `NOCONFIGURE=1 ./autogen.sh && mkdir winbuild && cd winbuild`
|
||||
|
||||
6. Run `../mingw32.sh` for 32-bit build, or `../mingw64.sh` for 64-bit. This configures
|
||||
HarfBuzz for cross-compiling. It enables Uniscribe backend as well.
|
||||
|
||||
7. `make`
|
||||
|
||||
Now you can use hb-shape using `wine util/hb-shape.exe` but if you like to shape with
|
||||
the Microsoft Uniscribe,
|
||||
|
||||
8. Bring a 32bit version of `usp10.dll` for yourself from `C:\Windows\SysWOW64\usp10.dll` of your
|
||||
Windows installation (assuming you have a 64-bit installation, otherwise
|
||||
`C:\Windows\System32\usp10.dll`) that it is not a DirectWrite proxy
|
||||
([for more info](https://en.wikipedia.org/wiki/Uniscribe)).
|
||||
Rule of thumb, your `usp10.dll` should have a size more than 500kb, otherwise
|
||||
it is designed to work with DirectWrite which Wine can't work with its original one.
|
||||
You want a Uniscribe from Windows 7 or older.
|
||||
|
||||
Put the DLL in the folder you are going to run the next command,
|
||||
|
||||
9. `WINEDLLOVERRIDES="usp10=n" wine util/hb-shape.exe fontname.ttf -u 0061,0062,0063 --shaper=uniscribe`
|
||||
|
||||
(`0061,0062,0063` means `abc`, use test/shaping/hb-unicode-decode to generate ones you need)
|
||||
|
||||
|
||||
[^1] Download and put [this](https://drive.google.com/open?id=0B3_fQkxDZZXXbWltRGd5bjVrUDQ)
|
||||
in your `~/.local/i686-w64-mingw32`. Then replace all the instances of
|
||||
`/home/behdad/.local/i586-mingw32msvc` and `/home/behdad/.local/i686-w64-mingw32`
|
||||
with `<$HOME>/.local/i686-w64-mingw32` on that folder.
|
||||
(`<$HOME>` replace it with `/home/XXX` or `/Users/XXX` on macOS)
|
||||
You shouldn't replace the instances of those inside binary files.
|
@ -1,40 +0,0 @@
|
||||
For the development of HarfBuzz, the Microsoft shaping technology, Uniscribe,
|
||||
as a widely used and tested shaper is used as more-or-less OpenType reference
|
||||
implementation and that specially is important where OpenType specification
|
||||
is or wasn't that clear. For having access to Uniscribe on Linux/macOS these
|
||||
steps are recommended:
|
||||
|
||||
1. Install Wine from your favorite package manager.
|
||||
|
||||
2. And `mingw-w64` compiler.
|
||||
With `brew` on macOS, you can have it like `brew install mingw-w64`
|
||||
|
||||
3. Download and put [this](https://drive.google.com/open?id=0B3_fQkxDZZXXbWltRGd5bjVrUDQ)
|
||||
on your `~/.local/i686-w64-mingw32`.
|
||||
|
||||
4. Replace all the instances of `/home/behdad/.local/i586-mingw32msvc`
|
||||
and `/home/behdad/.local/i686-w64-mingw32` with `<$HOME>/.local/i686-w64-mingw32`
|
||||
on that folder. (`<$HOME>` replace it with `/home/XXX` or `/Users/XXX` on macOS)
|
||||
|
||||
Probably you shouldn't replace the ones are inside binaries.
|
||||
|
||||
5. `NOCONFIGURE=1 ./autogen.sh && mkdir winbuild && cd winbuild`
|
||||
|
||||
6. `../mingw32.sh --with-uniscribe && cd ..`
|
||||
|
||||
7. `make -Cwinbuild`
|
||||
|
||||
Now you can use hb-shape using `wine winbuild/util/hb-shape.exe` but if you like to
|
||||
to use the original Uniscribe,
|
||||
|
||||
8. Bring a 32bit version of `usp10.dll` for yourself from `C:\Windows\SysWOW64\usp10.dll` of your
|
||||
Windows installation (assuming you have a 64-bit installation, otherwise `C:\Windows\System32\usp10.dll`)
|
||||
that it is not a DirectWrite proxy ([for more info](https://en.wikipedia.org/wiki/Uniscribe)).
|
||||
Rule of thumb, your `usp10.dll` should have a size more than 500kb, otherwise
|
||||
it is designed to work with DirectWrite which Wine can't work with its original one.
|
||||
|
||||
Put the dll on the folder you are going to run the next command,
|
||||
|
||||
9. `WINEDLLOVERRIDES="usp10=n" wine winbuild/util/hb-shape.exe fontname.ttf -u 0061,0062,0063 --shaper=uniscribe`
|
||||
|
||||
(`0061,0062,0063` means `abc`, use test/shaping/hb-unicode-decode to generate ones you need)
|
54
RELEASING.md
54
RELEASING.md
@ -46,27 +46,21 @@ HarfBuzz release walk-through checklist:
|
||||
|
||||
10. Build win32 bundle.
|
||||
|
||||
a. Put contents of [this](https://drive.google.com/open?id=0B3_fQkxDZZXXbWltRGd5bjVrUDQ) on your `~/.local/i686-w64-mingw32`,
|
||||
a. Build Win32 binaries. See [README.mingw.md](README.mingw.md).
|
||||
|
||||
b. Run `../mingw32.sh --with-uniscribe` script to configure harfbuzz with mingw
|
||||
in a subdirector (eg. winbuild/),
|
||||
|
||||
c. make
|
||||
|
||||
d. Back in the parent directory, run `./UPDATE.sh`(available below) to build win32
|
||||
bundle.
|
||||
b. Run "make dist-win" to build Win32 bundle.
|
||||
|
||||
11. Copy all artefacts to users.freedesktop.org and move them into
|
||||
`/srv/www.freedesktop.org/www/software/harfbuzz/release` There should be four
|
||||
files. Eg.:
|
||||
```
|
||||
-rw-r--r-- 1 behdad eng 1592693 Jul 18 11:25 harfbuzz-1.4.7.tar.bz2
|
||||
-rw-r--r-- 1 behdad eng 89 Jul 18 11:34 harfbuzz-1.4.7.tar.bz2.sha256
|
||||
-rw-r--r-- 1 behdad eng 339 Jul 18 11:34 harfbuzz-1.4.7.tar.bz2.sha256.asc
|
||||
-rw-r--r-- 1 behdad eng 1592693 Jul 18 11:25 harfbuzz-1.4.7.tar.xz
|
||||
-rw-r--r-- 1 behdad eng 89 Jul 18 11:34 harfbuzz-1.4.7.tar.xz.sha256
|
||||
-rw-r--r-- 1 behdad eng 339 Jul 18 11:34 harfbuzz-1.4.7.tar.xz.sha256.asc
|
||||
-rw-r--r-- 1 behdad eng 2895619 Jul 18 11:34 harfbuzz-1.4.7-win32.zip
|
||||
```
|
||||
|
||||
12. While doing that, quickly double-check the size of the .tar.bz2 and .zip
|
||||
12. While doing that, quickly double-check the size of the .tar.xz and .zip
|
||||
files against their previous releases to make sure nothing bad happened.
|
||||
They should be in the ballpark, perhaps slightly larger. Sometimes they
|
||||
do shrink, that's not by itself a stopper.
|
||||
@ -76,39 +70,3 @@ HarfBuzz release walk-through checklist:
|
||||
|
||||
14. Go to GitHub release page [here](https://github.com/harfbuzz/harfbuzz/releases),
|
||||
edit the tag, upload artefacts and NEWS entry and save.
|
||||
|
||||
|
||||
## UPDATE.sh
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
v=$1
|
||||
|
||||
if test "x$v" = x; then
|
||||
echo "usage: UPDATE.sh micro-version"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
dir_prefix=harfbuzz-1.4.
|
||||
dir_suffix=-win32
|
||||
dir=$dir_prefix$v$dir_suffix
|
||||
dir_old=$dir_prefix$((v-1))$dir_suffix
|
||||
if test -d "$dir"; then
|
||||
echo "New dir $dir exists; not overwriting"
|
||||
exit 1
|
||||
fi
|
||||
if ! test -d "$dir_old"; then
|
||||
echo "Old dir $dir_old does NOT exist; aborting"
|
||||
exit 1
|
||||
fi
|
||||
set -ex
|
||||
cp -a "$dir_old" "$dir.tmp"
|
||||
rm -f "$dir.tmp"/GDX32.dll
|
||||
rm -f "$dir.tmp"/usp10.dll
|
||||
cp ../winbuild/src/.libs/libharfbuzz-0.dll{,.def} $dir.tmp/
|
||||
cp ../winbuild/util/.libs/hb-{shape,view}.exe $dir.tmp/
|
||||
i686-w64-mingw32-strip $dir.tmp/{hb-shape.exe,hb-view.exe,libharfbuzz-0.dll}
|
||||
mv $dir.tmp $dir
|
||||
zip -r $dir.zip $dir
|
||||
echo Bundle $dir.zip ready
|
||||
```
|
||||
|
75
TESTING.md
Normal file
75
TESTING.md
Normal file
@ -0,0 +1,75 @@
|
||||
## Build & Run
|
||||
|
||||
Depending on what area you are working in change or add `HB_DEBUG_<whatever>`.
|
||||
Values defined in `hb-debug.hh`.
|
||||
|
||||
```shell
|
||||
# quick sanity check
|
||||
time (make -j4 CPPFLAGS='-DHB_DEBUG_SUBSET=100' \
|
||||
&& (make -j4 -C test/api check || cat test/api/test-suite.log))
|
||||
|
||||
# slower sanity check
|
||||
time (make -j4 CPPFLAGS='-DHB_DEBUG_SUBSET=100' \
|
||||
&& make -j4 -C src check \
|
||||
&& make -j4 -C test/api check \
|
||||
&& make -j4 -C test/subset check)
|
||||
|
||||
# confirm you didn't break anything else
|
||||
time (make -j4 CPPFLAGS='-DHB_DEBUG_SUBSET=100' \
|
||||
&& make -j4 check)
|
||||
|
||||
# often catches files you didn't add, e.g. test fonts to EXTRA_DIST
|
||||
make distcheck
|
||||
```
|
||||
|
||||
### Run tests with asan
|
||||
|
||||
**NOTE**: this sometimes yields harder to read results than the full fuzzer
|
||||
|
||||
```shell
|
||||
# For nice symbols tell asan how to symoblize. Note that it doesn't like versioned copies like llvm-symbolizer-3.8
|
||||
# export ASAN_SYMBOLIZER_PATH=path to version-less llvm-symbolizer
|
||||
# ex
|
||||
export ASAN_SYMBOLIZER_PATH=/usr/lib/llvm-3.8/bin/llvm-symbolizer
|
||||
|
||||
./configure CC=clang CXX=clang++ CPPFLAGS=-fsanitize=address LDFLAGS=-fsanitize=address
|
||||
# make/run tests as usual
|
||||
```
|
||||
|
||||
### Debug with GDB
|
||||
|
||||
```
|
||||
cd ./util
|
||||
../libtool --mode=execute gdb --args ./hb-subset ...
|
||||
```
|
||||
|
||||
### Enable Debug Logging
|
||||
|
||||
```shell
|
||||
# make clean if you previously build w/o debug logging
|
||||
make CPPFLAGS=-DHB_DEBUG_SUBSET=100
|
||||
```
|
||||
|
||||
## Build and Test via CMake
|
||||
|
||||
Note: You'll need to first install ninja-build via apt-get.
|
||||
|
||||
```shell
|
||||
cd harfbuzz
|
||||
mkdir buid
|
||||
cmake -DHB_CHECK=ON -Bbuild -H. -GNinja && ninja -Cbuild && CTEST_OUTPUT_ON_FAILURE=1 ninja -Cbuild test
|
||||
```
|
||||
## Test with the Fuzzer
|
||||
|
||||
```shell
|
||||
# push your changs to a branch on googlefonts/harfbuzz
|
||||
# In a local copy of oss-fuzz, edit projects/harfbuzz/Dockerfile
|
||||
# Change the git clone to pull your branch
|
||||
|
||||
# Do this periodically
|
||||
sudo python infra/helper.py build_image harfbuzz
|
||||
|
||||
# Do these to update/run
|
||||
sudo python infra/helper.py build_fuzzers --sanitizer address harfbuzz
|
||||
sudo python infra/helper.py run_fuzzer harfbuzz hb-subset-fuzzer
|
||||
```
|
47
appveyor.yml
47
appveyor.yml
@ -2,11 +2,13 @@ platform: x64
|
||||
|
||||
environment:
|
||||
matrix:
|
||||
|
||||
- compiler: msvc
|
||||
generator: Visual Studio 14
|
||||
platform: Win32
|
||||
configuration: Debug
|
||||
triplet: x86-windows
|
||||
|
||||
- compiler: msvc
|
||||
generator: Visual Studio 14 Win64
|
||||
platform: x64
|
||||
@ -19,10 +21,35 @@ environment:
|
||||
configuration: Debug
|
||||
|
||||
|
||||
# Build only
|
||||
|
||||
#- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2013
|
||||
# compiler: msvc2
|
||||
# generator: Visual Studio 12
|
||||
# platform: Win32
|
||||
# configuration: Release
|
||||
# triplet: x86-windows
|
||||
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
compiler: msvc2
|
||||
generator: Visual Studio 15
|
||||
platform: Win32
|
||||
configuration: Release
|
||||
triplet: x86-windows
|
||||
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
||||
compiler: msvc2
|
||||
generator: Visual Studio 16
|
||||
platform: Win32
|
||||
configuration: Release
|
||||
triplet: x86-windows
|
||||
|
||||
|
||||
- compiler: msys2
|
||||
MINGW_PREFIX: /mingw64
|
||||
MINGW_CHOST: x86_64-w64-mingw32
|
||||
MSYS2_ARCH: x86_64
|
||||
|
||||
- compiler: msys2
|
||||
MINGW_PREFIX: /mingw32
|
||||
MINGW_CHOST: i686-w64-mingw32
|
||||
@ -30,30 +57,26 @@ environment:
|
||||
|
||||
|
||||
install:
|
||||
# - 'if "%compiler%"=="msys2" C:\msys64\usr\bin\bash -lc "pacman --noconfirm --force -Sy && pacman --noconfirm --force -S pacman-mirrors && pacman --force -Syu --noconfirm"'
|
||||
- 'if "%compiler%"=="msys2" C:\msys64\usr\bin\bash -lc "pacman --noconfirm --force -S --needed mingw-w64-$MSYS2_ARCH-{gcc,freetype,cairo,icu,gettext,gobject-introspection,gcc,gcc-libs,glib2,graphite2,pkg-config,python2}"'
|
||||
- C:\msys64\usr\bin\bash -lc "pacman --noconfirm -S mingw-w64-x86_64-ragel"
|
||||
- set PATH=%PATH%;C:\msys64\mingw64\bin # msys2 is added just for having "ragel" on PATH
|
||||
- 'if "%compiler%"=="cygwin" %CYGWIN_PREFIX%\setup-%CYGWIN_ARCH%.exe -g -q -P cygwin-devel,libfreetype-devel,libcairo-devel,libicu-devel,gcc,gcc-g++,gobject-introspection,libglib2.0-devel,libgraphite2-devel,pkg-config,python2'
|
||||
- 'if "%compiler%"=="msys2" C:\msys64\usr\bin\bash -lc "pacman --noconfirm --force -S --needed mingw-w64-$MSYS2_ARCH-{gcc,freetype,cairo,icu,gettext,gobject-introspection,gcc,gcc-libs,glib2,graphite2,pkg-config,python2,ragel}"'
|
||||
- 'if "%compiler%"=="msvc" if not "%platform%"=="ARM" vcpkg install glib:%triplet% freetype:%triplet% cairo:%triplet%'
|
||||
|
||||
build_script:
|
||||
- 'if "%compiler%"=="msvc" md build'
|
||||
- 'if "%compiler%"=="msvc" cd build'
|
||||
- 'if "%compiler%"=="msvc" if "%platform%"=="ARM" cmake -Bbuild -H. -DHB_HAVE_UNISCRIBE=ON -DHB_HAVE_DIRECTWRITE=ON -G "%generator%"'
|
||||
- 'if "%compiler%"=="msvc" if not "%platform%"=="ARM" cmake -Bbuild -H. -DHB_HAVE_UNISCRIBE=ON -DHB_HAVE_DIRECTWRITE=ON -DHB_HAVE_GLIB=ON -DHB_HAVE_FREETYPE=ON -DHB_BUILD_UTILS=ON -G "%generator%" -DCMAKE_TOOLCHAIN_FILE=c:/tools/vcpkg/scripts/buildsystems/vcpkg.cmake'
|
||||
|
||||
- 'if "%compiler%"=="msvc" set PATH=%PATH%;C:\Program Files (x86)\MSBuild\14.0\Bin'
|
||||
|
||||
- 'if "%compiler%"=="msvc" if "%platform%"=="ARM" cmake -DHB_HAVE_UNISCRIBE=ON -DHB_HAVE_DIRECTWRITE=ON -G "%generator%" ../'
|
||||
- 'if "%compiler%"=="msvc" if not "%platform%"=="ARM" cmake -DHB_HAVE_UNISCRIBE=ON -DHB_HAVE_DIRECTWRITE=ON -DHB_HAVE_GLIB=ON -DHB_HAVE_FREETYPE=ON -DHB_BUILD_UTILS=ON -G "%generator%" -DCMAKE_TOOLCHAIN_FILE=c:/tools/vcpkg/scripts/buildsystems/vcpkg.cmake ../'
|
||||
|
||||
- 'if "%compiler%"=="msvc" cd build'
|
||||
- 'if "%compiler%"=="msvc" msbuild harfbuzz.sln /p:Configuration=%configuration% /p:Platform=%platform%'
|
||||
- 'if "%compiler%"=="msvc" if not "%platform%"=="ARM" ctest --output-on-failure -C %configuration%'
|
||||
|
||||
- 'if "%compiler%"=="msvc2" cmake -G "%generator%" -Bbuild -H.'
|
||||
- 'if "%compiler%"=="msvc2" cmake --build build --config %configuration%'
|
||||
|
||||
- 'if "%compiler%"=="msys2" C:\msys64\usr\bin\bash -lc "curl https://raw.githubusercontent.com/mirror/mingw-w64/023eb04c396d4e8d8fcf604cfababc53dae13398/mingw-w64-headers/include/dwrite_1.h > %MINGW_PREFIX%/%MINGW_CHOST%/include/dwrite_1.h"'
|
||||
- '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 --with-directwrite --build=%MINGW_CHOST% --host=%MINGW_CHOST% --prefix=%MINGW_PREFIX%; make -j3 check || .ci/fail.sh"'
|
||||
|
||||
cache:
|
||||
- c:\tools\vcpkg\installed\
|
||||
- '%CYGWIN_PREFIX%\var\cache\setup'
|
||||
|
||||
notifications:
|
||||
- provider: Email
|
||||
|
26
configure.ac
26
configure.ac
@ -1,6 +1,6 @@
|
||||
AC_PREREQ([2.64])
|
||||
AC_INIT([HarfBuzz],
|
||||
[2.4.0],
|
||||
[2.5.1],
|
||||
[https://github.com/harfbuzz/harfbuzz/issues/new],
|
||||
[harfbuzz],
|
||||
[http://harfbuzz.org/])
|
||||
@ -9,7 +9,7 @@ AC_CONFIG_MACRO_DIR([m4])
|
||||
AC_CONFIG_SRCDIR([src/harfbuzz.pc.in])
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
|
||||
AM_INIT_AUTOMAKE([1.13.0 gnits tar-ustar dist-bzip2 no-dist-gzip -Wall no-define color-tests -Wno-portability])
|
||||
AM_INIT_AUTOMAKE([1.13.0 gnits tar-ustar dist-xz no-dist-gzip -Wall no-define color-tests -Wno-portability])
|
||||
AM_SILENT_RULES([yes])
|
||||
AX_CODE_COVERAGE
|
||||
|
||||
@ -134,9 +134,7 @@ AC_MSG_RESULT([$hb_os_win32])
|
||||
AM_CONDITIONAL(OS_WIN32, test "$hb_os_win32" = "yes")
|
||||
|
||||
have_pthread=false
|
||||
if test "$hb_os_win32" = no; then
|
||||
AX_PTHREAD([have_pthread=true])
|
||||
fi
|
||||
AX_PTHREAD([have_pthread=true])
|
||||
if $have_pthread; then
|
||||
AC_DEFINE(HAVE_PTHREAD, 1, [Have POSIX threads])
|
||||
fi
|
||||
@ -300,21 +298,6 @@ AM_CONDITIONAL(HAVE_ICU_BUILTIN, $have_icu && test "x$with_icu" = "xbuiltin")
|
||||
|
||||
dnl ===========================================================================
|
||||
|
||||
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])
|
||||
fi
|
||||
AM_CONDITIONAL(HAVE_UCDN, $have_ucdn)
|
||||
|
||||
dnl ==========================================================================
|
||||
|
||||
AC_ARG_WITH(graphite2,
|
||||
[AS_HELP_STRING([--with-graphite2=@<:@yes/no/auto@:>@],
|
||||
[Use the graphite2 library @<:@default=no@:>@])],,
|
||||
@ -497,7 +480,6 @@ AC_CONFIG_FILES([
|
||||
Makefile
|
||||
src/Makefile
|
||||
src/harfbuzz-config.cmake
|
||||
src/hb-ucdn/Makefile
|
||||
util/Makefile
|
||||
test/Makefile
|
||||
test/api/Makefile
|
||||
@ -525,7 +507,7 @@ AC_MSG_NOTICE([
|
||||
Build configuration:
|
||||
|
||||
Unicode callbacks (you want at least one):
|
||||
Builtin (UCDN): ${have_ucdn}
|
||||
Builtin true
|
||||
Glib: ${have_glib}
|
||||
ICU: ${have_icu}
|
||||
|
||||
|
@ -33,7 +33,7 @@ SCAN_OPTIONS=--rebuild-types --deprecated-guards="HB_DISABLE_DEPRECATED" \
|
||||
|
||||
# Header files or dirs to ignore when scanning. Use base file/dir names
|
||||
# e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h private_code
|
||||
IGNORE_HFILES=`cd $(top_srcdir)/src; find . -path './hb-*/*.h' | sed 's@^.*/@@'`
|
||||
IGNORE_HFILES=`cd $(top_srcdir)/src; find . -path './*/*.h' | sed 's@^.*/@@'`
|
||||
if HAVE_GOBJECT
|
||||
else
|
||||
IGNORE_HFILES+=hb-gobject.h hb-gobject-enums.h hb-gobject-structs.h
|
||||
@ -75,12 +75,14 @@ content_files= \
|
||||
usermanual-what-is-harfbuzz.xml \
|
||||
usermanual-install-harfbuzz.xml \
|
||||
usermanual-getting-started.xml \
|
||||
usermanual-glyph-information.xml \
|
||||
usermanual-shaping-concepts.xml \
|
||||
usermanual-object-model.xml \
|
||||
usermanual-buffers-language-script-and-direction.xml \
|
||||
usermanual-fonts-and-faces.xml \
|
||||
usermanual-clusters.xml \
|
||||
usermanual-opentype-features.xml \
|
||||
usermanual-glyph-information.xml \
|
||||
usermanual-clusters.xml \
|
||||
usermanual-utilities.xml \
|
||||
version.xml
|
||||
|
||||
# SGML files where gtk-doc abbrevations (#GtkWidget) are expanded
|
||||
|
@ -33,11 +33,12 @@
|
||||
<xi:include href="usermanual-install-harfbuzz.xml"/>
|
||||
<xi:include href="usermanual-getting-started.xml"/>
|
||||
<xi:include href="usermanual-shaping-concepts.xml"/>
|
||||
<xi:include href="usermanual-object-model.xml"/>
|
||||
<xi:include href="usermanual-buffers-language-script-and-direction.xml"/>
|
||||
<xi:include href="usermanual-fonts-and-faces.xml"/>
|
||||
<xi:include href="usermanual-clusters.xml"/>
|
||||
<xi:include href="usermanual-opentype-features.xml"/>
|
||||
<xi:include href="usermanual-glyph-information.xml"/>
|
||||
<xi:include href="usermanual-clusters.xml"/>
|
||||
<xi:include href="usermanual-utilities.xml"/>
|
||||
</part>
|
||||
|
||||
<part>
|
||||
|
@ -7,30 +7,38 @@
|
||||
<chapter id="buffers-language-script-and-direction">
|
||||
<title>Buffers, language, script and direction</title>
|
||||
<para>
|
||||
The input to HarfBuzz is a series of Unicode characters, stored in a
|
||||
The input to the HarfBuzz shaper is a series of Unicode characters, stored in a
|
||||
buffer. In this chapter, we'll look at how to set up a buffer with
|
||||
the text that we want and then customize the properties of the
|
||||
buffer.
|
||||
the text that we want and how to customize the properties of the
|
||||
buffer. We'll also look at a piece of lower-level machinery that
|
||||
you will need to understand before proceeding: the functions that
|
||||
HarfBuzz uses to retrieve Unicode information.
|
||||
</para>
|
||||
<para>
|
||||
After shaping is complete, HarfBuzz puts its output back
|
||||
into the buffer. But getting that output requires setting up a
|
||||
face and a font first, so we will look at that in the next chapter
|
||||
instead of here.
|
||||
</para>
|
||||
<section id="creating-and-destroying-buffers">
|
||||
<title>Creating and destroying buffers</title>
|
||||
<para>
|
||||
As we saw in our <emphasis>Getting Started</emphasis> example, a
|
||||
buffer is created and
|
||||
initialized with <literal>hb_buffer_create()</literal>. This
|
||||
initialized with <function>hb_buffer_create()</function>. This
|
||||
produces a new, empty buffer object, instantiated with some
|
||||
default values and ready to accept your Unicode strings.
|
||||
</para>
|
||||
<para>
|
||||
HarfBuzz manages the memory of objects (such as buffers) that it
|
||||
creates, so you don't have to. When you have finished working on
|
||||
a buffer, you can call <literal>hb_buffer_destroy()</literal>:
|
||||
a buffer, you can call <function>hb_buffer_destroy()</function>:
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_buffer_t *buffer = hb_buffer_create();
|
||||
...
|
||||
hb_buffer_destroy(buffer);
|
||||
</programlisting>
|
||||
hb_buffer_t *buf = hb_buffer_create();
|
||||
...
|
||||
hb_buffer_destroy(buf);
|
||||
</programlisting>
|
||||
<para>
|
||||
This will destroy the object and free its associated memory -
|
||||
unless some other part of the program holds a reference to this
|
||||
@ -39,46 +47,364 @@
|
||||
else destroying it, you should increase its reference count:
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
void somefunc(hb_buffer_t *buffer) {
|
||||
buffer = hb_buffer_reference(buffer);
|
||||
...
|
||||
</programlisting>
|
||||
void somefunc(hb_buffer_t *buf) {
|
||||
buf = hb_buffer_reference(buf);
|
||||
...
|
||||
</programlisting>
|
||||
<para>
|
||||
And then decrease it once you're done with it:
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_buffer_destroy(buffer);
|
||||
}
|
||||
</programlisting>
|
||||
hb_buffer_destroy(buf);
|
||||
}
|
||||
</programlisting>
|
||||
<para>
|
||||
While we are on the subject of reference-counting buffers, it is
|
||||
worth noting that an individual buffer can only meaningfully be
|
||||
used by one thread at a time.
|
||||
</para>
|
||||
<para>
|
||||
To throw away all the data in your buffer and start from scratch,
|
||||
call <literal>hb_buffer_reset(buffer)</literal>. If you want to
|
||||
call <function>hb_buffer_reset(buf)</function>. If you want to
|
||||
throw away the string in the buffer but keep the options, you can
|
||||
instead call <literal>hb_buffer_clear_contents(buffer)</literal>.
|
||||
instead call <function>hb_buffer_clear_contents(buf)</function>.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="adding-text-to-the-buffer">
|
||||
<title>Adding text to the buffer</title>
|
||||
<para>
|
||||
Now we have a brand new HarfBuzz buffer. Let's start filling it
|
||||
with text! From HarfBuzz's perspective, a buffer is just a stream
|
||||
of Unicode codepoints, but your input string is probably in one of
|
||||
the standard Unicode character encodings (UTF-8, UTF-16, UTF-32)
|
||||
of Unicode code points, but your input string is probably in one of
|
||||
the standard Unicode character encodings (UTF-8, UTF-16, or
|
||||
UTF-32). HarfBuzz provides convenience functions that accept
|
||||
each of these encodings:
|
||||
<function>hb_buffer_add_utf8()</function>,
|
||||
<function>hb_buffer_add_utf16()</function>, and
|
||||
<function>hb_buffer_add_utf32()</function>. Other than the
|
||||
character encoding they accept, they function identically.
|
||||
</para>
|
||||
<para>
|
||||
You can add UTF-8 text to a buffer by passing in the text array,
|
||||
the array's length, an offset into the array for the first
|
||||
character to add, and the length of the segment to add:
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_buffer_add_utf8 (hb_buffer_t *buf,
|
||||
const char *text,
|
||||
int text_length,
|
||||
unsigned int item_offset,
|
||||
int item_length)
|
||||
</programlisting>
|
||||
<para>
|
||||
So, in practice, you can say:
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_buffer_add_utf8(buf, text, strlen(text), 0, strlen(text));
|
||||
</programlisting>
|
||||
<para>
|
||||
This will append your new characters to
|
||||
<parameter>buf</parameter>, not replace its existing
|
||||
contents. Also, note that you can use <literal>-1</literal> in
|
||||
place of the first instance of <function>strlen(text)</function>
|
||||
if your text array is NULL-terminated. Similarly, you can also use
|
||||
<literal>-1</literal> as the final argument want to add its full
|
||||
contents.
|
||||
</para>
|
||||
<para>
|
||||
Whatever start <parameter>item_offset</parameter> and
|
||||
<parameter>item_length</parameter> you provide, HarfBuzz will also
|
||||
attempt to grab the five characters <emphasis>before</emphasis>
|
||||
the offset point and the five characters
|
||||
<emphasis>after</emphasis> the designated end. These are the
|
||||
before and after "context" segments, which are used internally
|
||||
for HarfBuzz to make shaping decisions. They will not be part of
|
||||
the final output, but they ensure that HarfBuzz's
|
||||
script-specific shaping operations are correct. If there are
|
||||
fewer than five characters available for the before or after
|
||||
contexts, HarfBuzz will just grab what is there.
|
||||
</para>
|
||||
<para>
|
||||
For longer text runs, such as full paragraphs, it might be
|
||||
tempting to only add smaller sub-segments to a buffer and
|
||||
shape them in piecemeal fashion. Generally, this is not a good
|
||||
idea, however, because a lot of shaping decisions are
|
||||
dependent on this context information. For example, in Arabic
|
||||
and other connected scripts, HarfBuzz needs to know the code
|
||||
points before and after each character in order to correctly
|
||||
determine which glyph to return.
|
||||
</para>
|
||||
<para>
|
||||
The safest approach is to add all of the text available, then
|
||||
use <parameter>item_offset</parameter> and
|
||||
<parameter>item_length</parameter> to indicate which characters you
|
||||
want shaped, so that HarfBuzz has access to any context.
|
||||
</para>
|
||||
<para>
|
||||
You can also add Unicode code points directly with
|
||||
<function>hb_buffer_add_codepoints()</function>. The arguments
|
||||
to this function are the same as those for the UTF
|
||||
encodings. But it is particularly important to note that
|
||||
HarfBuzz does not do validity checking on the text that is added
|
||||
to a buffer. Invalid code points will be replaced, but it is up
|
||||
to you to do any deep-sanity checking necessary.
|
||||
</para>
|
||||
|
||||
</section>
|
||||
|
||||
<section id="setting-buffer-properties">
|
||||
<title>Setting buffer properties</title>
|
||||
<para>
|
||||
Buffers containing input characters still need several
|
||||
properties set before HarfBuzz can shape their text correctly.
|
||||
</para>
|
||||
</section>
|
||||
<section id="what-about-the-other-scripts">
|
||||
<title>What about the other scripts?</title>
|
||||
<para>
|
||||
Initially, all buffers are set to the
|
||||
<literal>HB_BUFFER_CONTENT_TYPE_INVALID</literal> content
|
||||
type. After adding text, the buffer should be set to
|
||||
<literal>HB_BUFFER_CONTENT_TYPE_UNICODE</literal> instead, which
|
||||
indicates that it contains un-shaped input
|
||||
characters. After shaping, the buffer will have the
|
||||
<literal>HB_BUFFER_CONTENT_TYPE_GLYPHS</literal> content type.
|
||||
</para>
|
||||
<para>
|
||||
<function>hb_buffer_add_utf8()</function> and the
|
||||
other UTF functions set the content type of their buffer
|
||||
automatically. But if you are reusing a buffer you may want to
|
||||
check its state with
|
||||
<function>hb_buffer_get_content_type(buffer)</function>. If
|
||||
necessary you can set the content type with
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_buffer_set_content_type(buf, HB_BUFFER_CONTENT_TYPE_UNICODE);
|
||||
</programlisting>
|
||||
<para>
|
||||
to prepare for shaping.
|
||||
</para>
|
||||
<para>
|
||||
Buffers also need to carry information about the script,
|
||||
language, and text direction of their contents. You can set
|
||||
these properties individually:
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_buffer_set_direction(buf, HB_DIRECTION_LTR);
|
||||
hb_buffer_set_script(buf, HB_SCRIPT_LATIN);
|
||||
hb_buffer_set_language(buf, hb_language_from_string("en", -1));
|
||||
</programlisting>
|
||||
<para>
|
||||
However, since these properties are often the repeated for
|
||||
multiple text runs, you can also save them in a
|
||||
<literal>hb_segment_properties_t</literal> for reuse:
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_segment_properties_t *savedprops;
|
||||
hb_buffer_get_segment_properties (buf, savedprops);
|
||||
...
|
||||
hb_buffer_set_segment_properties (buf2, savedprops);
|
||||
</programlisting>
|
||||
<para>
|
||||
HarfBuzz also provides getter functions to retrieve a buffer's
|
||||
direction, script, and language properties individually.
|
||||
</para>
|
||||
<para>
|
||||
HarfBuzz recognizes four text directions in
|
||||
<type>hb_direction_t</type>: left-to-right
|
||||
(<literal>HB_DIRECTION_LTR</literal>), right-to-left (<literal>HB_DIRECTION_RTL</literal>),
|
||||
top-to-bottom (<literal>HB_DIRECTION_TTB</literal>), and
|
||||
bottom-to-top (<literal>HB_DIRECTION_BTT</literal>). For the
|
||||
script property, HarfBuzz uses identifiers based on the
|
||||
<ulink
|
||||
url="https://unicode.org/iso15924/">ISO 15924
|
||||
standard</ulink>. For languages, HarfBuzz uses tags based on the
|
||||
<ulink url="https://tools.ietf.org/html/bcp47">IETF BCP 47</ulink> standard.
|
||||
</para>
|
||||
<para>
|
||||
Helper functions are provided to convert character strings into
|
||||
the necessary script and language tag types.
|
||||
</para>
|
||||
<para>
|
||||
Two additional buffer properties to be aware of are the
|
||||
"invisible glyph" and the replacement code point. The
|
||||
replacement code point is inserted into buffer output in place of
|
||||
any invalid code points encountered in the input. By default, it
|
||||
is the Unicode <literal>REPLACEMENT CHARACTER</literal> code
|
||||
point, <literal>U+FFFD</literal> "�". You can change this with
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_buffer_set_replacement_codepoint(buf, replacement);
|
||||
</programlisting>
|
||||
<para>
|
||||
passing in the replacement Unicode code point as the
|
||||
<parameter>replacement</parameter> parameter.
|
||||
</para>
|
||||
<para>
|
||||
The invisible glyph is used to replace all output glyphs that
|
||||
are invisible. By default, the standard space character
|
||||
<literal>U+0020</literal> is used; you can replace this (for
|
||||
example, when using a font that provides script-specific
|
||||
spaces) with
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_buffer_set_invisible_glyph(buf, replacement_glyph);
|
||||
</programlisting>
|
||||
<para>
|
||||
Do note that in the <parameter>replacement_glyph</parameter>
|
||||
parameter, you must provide the glyph ID of the replacement you
|
||||
wish to use, not the Unicode code point.
|
||||
</para>
|
||||
<para>
|
||||
HarfBuzz supports a few additional flags you might want to set
|
||||
on your buffer under certain circumstances. The
|
||||
<literal>HB_BUFFER_FLAG_BOT</literal> and
|
||||
<literal>HB_BUFFER_FLAG_EOT</literal> flags tell HarfBuzz
|
||||
that the buffer represents the beginning or end (respectively)
|
||||
of a text element (such as a paragraph or other block). Knowing
|
||||
this allows HarfBuzz to apply certain contextual font features
|
||||
when shaping, such as initial or final variants in connected
|
||||
scripts.
|
||||
</para>
|
||||
<para>
|
||||
<literal>HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES</literal>
|
||||
tells HarfBuzz not to hide glyphs with the
|
||||
<literal>Default_Ignorable</literal> property in Unicode. This
|
||||
property designates control characters and other non-printing
|
||||
code points, such as joiners and variation selectors. Normally
|
||||
HarfBuzz replaces them in the output buffer with zero-width
|
||||
space glyphs (using the "invisible glyph" property discussed
|
||||
above); setting this flag causes them to be printed, which can
|
||||
be helpful for troubleshooting.
|
||||
</para>
|
||||
<para>
|
||||
Conversely, setting the
|
||||
<literal>HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES</literal> flag
|
||||
tells HarfBuzz to remove <literal>Default_Ignorable</literal>
|
||||
glyphs from the output buffer entirely. Finally, setting the
|
||||
<literal>HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE</literal>
|
||||
flag tells HarfBuzz not to insert the dotted-circle glyph
|
||||
(<literal>U+25CC</literal>, "◌"), which is normally
|
||||
inserted into buffer output when broken character sequences are
|
||||
encountered (such as combining marks that are not attached to a
|
||||
base character).
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="customizing-unicode-functions">
|
||||
<title>Customizing Unicode functions</title>
|
||||
<para>
|
||||
HarfBuzz requires some simple functions for accessing
|
||||
information from the Unicode Character Database (such as the
|
||||
<literal>General_Category</literal> (gc) and
|
||||
<literal>Script</literal> (sc) properties) that is useful
|
||||
for shaping, as well as some useful operations like composing and
|
||||
decomposing code points.
|
||||
</para>
|
||||
<para>
|
||||
HarfBuzz includes its own internal, lightweight set of Unicode
|
||||
functions. At build time, it is also possible to compile support
|
||||
for some other options, such as the Unicode functions provided
|
||||
by GLib or the International Components for Unicode (ICU)
|
||||
library. Generally, this option is only of interest for client
|
||||
programs that have specific integration requirements or that do
|
||||
a significant amount of customization.
|
||||
</para>
|
||||
<para>
|
||||
If your program has access to other Unicode functions, however,
|
||||
such as through a system library or application framework, you
|
||||
might prefer to use those instead of the built-in
|
||||
options. HarfBuzz supports this by implementing its Unicode
|
||||
functions as a set of virtual methods that you can replace —
|
||||
without otherwise affecting HarfBuzz's functionality.
|
||||
</para>
|
||||
<para>
|
||||
The Unicode functions are specified in a structure called
|
||||
<literal>unicode_funcs</literal> which is attached to each
|
||||
buffer. But even though <literal>unicode_funcs</literal> is
|
||||
associated with a <type>hb_buffer_t</type>, the functions
|
||||
themselves are called by other HarfBuzz APIs that access
|
||||
buffers, so it would be unwise for you to hook different
|
||||
functions into different buffers.
|
||||
</para>
|
||||
<para>
|
||||
In addition, you can mark your <literal>unicode_funcs</literal>
|
||||
as immutable by calling
|
||||
<function>hb_unicode_funcs_make_immutable (ufuncs)</function>.
|
||||
This is especially useful if your code is a
|
||||
library or framework that will have its own client programs. By
|
||||
marking your Unicode function choices as immutable, you prevent
|
||||
your own client programs from changing the
|
||||
<literal>unicode_funcs</literal> configuration and introducing
|
||||
inconsistencies and errors downstream.
|
||||
</para>
|
||||
<para>
|
||||
You can retrieve the Unicode-functions configuration for
|
||||
your buffer by calling <function>hb_buffer_get_unicode_funcs()</function>:
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_unicode_funcs_t *ufunctions;
|
||||
ufunctions = hb_buffer_get_unicode_funcs(buf);
|
||||
</programlisting>
|
||||
<para>
|
||||
The current version of <literal>unicode_funcs</literal> uses six functions:
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_unicode_combining_class_func_t</function>:
|
||||
returns the Canonical Combining Class of a code point.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_unicode_general_category_func_t</function>:
|
||||
returns the General Category (gc) of a code point.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_unicode_mirroring_func_t</function>: returns
|
||||
the Mirroring Glyph code point (for bi-directional
|
||||
replacement) of a code point.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_unicode_script_func_t</function>: returns the
|
||||
Script (sc) property of a code point.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_unicode_compose_func_t</function>: returns the
|
||||
canonical composition of a sequence of two code points.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_unicode_decompose_func_t</function>: returns
|
||||
the canonical decomposition of a code point.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>
|
||||
Note, however, that future HarfBuzz releases may alter this set.
|
||||
</para>
|
||||
<para>
|
||||
Each Unicode function has a corresponding setter, with which you
|
||||
can assign a callback to your replacement function. For example,
|
||||
to replace
|
||||
<function>hb_unicode_general_category_func_t</function>, you can call
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_unicode_funcs_set_general_category_func (*ufuncs, func, *user_data, destroy)
|
||||
</programlisting>
|
||||
<para>
|
||||
Virtualizing this set of Unicode functions is primarily intended
|
||||
to improve portability. There is no need for every client
|
||||
program to make the effort to replace the default options, so if
|
||||
you are unsure, do not feel any pressure to customize
|
||||
<literal>unicode_funcs</literal>.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
</chapter>
|
||||
|
@ -158,7 +158,7 @@
|
||||
<para>
|
||||
For left-to-right scripts (LTR) and top-to-bottom scripts (TTB),
|
||||
HarfBuzz will preserve the monotonic property: client programs
|
||||
are guaranteed that monotonically increasing initial clulster
|
||||
are guaranteed that monotonically increasing initial cluster
|
||||
values will be returned as monotonically increasing final
|
||||
cluster values.
|
||||
</para>
|
||||
@ -167,7 +167,7 @@
|
||||
the directionality of the buffer itself is reversed for final
|
||||
output as a matter of design. Therefore, HarfBuzz inverts the
|
||||
monotonic property: client programs are guaranteed that
|
||||
monotonically increasing initial clulster values will be
|
||||
monotonically increasing initial cluster values will be
|
||||
returned as monotonically <emphasis>decreasing</emphasis> final
|
||||
cluster values.
|
||||
</para>
|
||||
|
@ -5,20 +5,449 @@
|
||||
<!ENTITY version SYSTEM "version.xml">
|
||||
]>
|
||||
<chapter id="fonts-and-faces">
|
||||
<title>Fonts and faces</title>
|
||||
<section id="using-freetype">
|
||||
<title>Fonts, faces, and output</title>
|
||||
<para>
|
||||
In the previous chapter, we saw how to set up a buffer and fill
|
||||
it with text as Unicode code points. In order to shape this
|
||||
buffer text with HarfBuzz, you will need also need a font
|
||||
object.
|
||||
</para>
|
||||
<para>
|
||||
HarfBuzz provides abstractions to help you cache and reuse the
|
||||
heavier parts of working with binary fonts, so we will look at
|
||||
how to do that. We will also look at how to work with the
|
||||
FreeType font-rendering library and at how you can customize
|
||||
HarfBuzz to work with other libraries.
|
||||
</para>
|
||||
<para>
|
||||
Finally, we will look at how to work with OpenType variable
|
||||
fonts, the latest update to the OpenType font format, and at
|
||||
some other recent additions to OpenType.
|
||||
</para>
|
||||
|
||||
<section id="fonts-and-faces-objects">
|
||||
<title>Font and face objects</title>
|
||||
<para>
|
||||
The outcome of shaping a run of text depends on the contents of
|
||||
a specific font file (such as the substitutions and positioning
|
||||
moves in the 'GSUB' and 'GPOS' tables), so HarfBuzz makes
|
||||
accessing those internals fast.
|
||||
</para>
|
||||
<para>
|
||||
An <type>hb_face_t</type> represents a <emphasis>face</emphasis>
|
||||
in HarfBuzz. This data type is a wrapper around an
|
||||
<type>hb_blob_t</type> blob that holds the contents of a binary
|
||||
font file. Since HarfBuzz supports TrueType Collections and
|
||||
OpenType Collections (each of which can include multiple
|
||||
typefaces), a HarfBuzz face also requires an index number
|
||||
specifying which typeface in the file you want to use. Most of
|
||||
the font files you will encounter in the wild include just a
|
||||
single face, however, so most of the time you would pass in
|
||||
<literal>0</literal> as the index when you create a face:
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_blob_t* blob = hb_blob_create_from_file(file);
|
||||
...
|
||||
hb_face_t* face = hb_face_create(blob, 0);
|
||||
</programlisting>
|
||||
<para>
|
||||
On its own, a face object is not quite ready to use for
|
||||
shaping. The typeface must be set to a specific point size in
|
||||
order for some details (such as hinting) to work. In addition,
|
||||
if the font file in question is an OpenType Variable Font, then
|
||||
you may need to specify one or variation-axis settings (or a
|
||||
named instance) in order to get the output you need.
|
||||
</para>
|
||||
<para>
|
||||
In HarfBuzz, you do this by creating a <emphasis>font</emphasis>
|
||||
object from your face.
|
||||
</para>
|
||||
<para>
|
||||
Font objects also have the advantage of being considerably
|
||||
lighter-weight than face objects (remember that a face contains
|
||||
the contents of a binary font file mapped into memory). As a
|
||||
result, you can cache and reuse a font object, but you could
|
||||
also create a new one for each additional size you needed.
|
||||
Creating new fonts incurs some additional overhead, of course,
|
||||
but whether or not it is excessive is your call in the end. In
|
||||
contrast, face objects are substantially larger, and you really
|
||||
should cache them and reuse them whenever possible.
|
||||
</para>
|
||||
<para>
|
||||
You can create a font object from a face object:
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_font_t* hb_font = hb_font_create(hb_face);
|
||||
</programlisting>
|
||||
<para>
|
||||
After creating a font, there are a few properties you should
|
||||
set. Many fonts enable and disable hints based on the size it
|
||||
is used at, so setting this is important for font
|
||||
objects. <function>hb_font_set_ppem(font, x_ppem,
|
||||
y_ppem)</function> sets the pixels-per-EM value of the font. You
|
||||
can also set the point size of the font with
|
||||
<function>hb_font_set_ppem(font, ptem)</function>. HarfBuzz uses the
|
||||
industry standard 72 points per inch.
|
||||
</para>
|
||||
<para>
|
||||
HarfBuzz lets you specify the degree subpixel precision you want
|
||||
through a scaling factor. You can set horizontal and
|
||||
vertical scaling factors on the
|
||||
font by calling <function>hb_font_set_scale(font, x_scale,
|
||||
y_scale)</function>.
|
||||
</para>
|
||||
<para>
|
||||
There may be times when you are handed a font object and need to
|
||||
access the face object that it comes from. For that, you can call
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_face = hb_font_get_face(hb_font);
|
||||
</programlisting>
|
||||
<para>
|
||||
You can also create a font object from an existing font object
|
||||
using the <function>hb_font_create_sub_font()</function>
|
||||
function. This creates a child font object that is initiated
|
||||
with the same attributes as its parent; it can be used to
|
||||
quickly set up a new font for the purpose of overriding a specific
|
||||
font-functions method.
|
||||
</para>
|
||||
<para>
|
||||
All face objects and font objects are lifecycle-managed by
|
||||
HarfBuzz. After creating a face, you increase its reference
|
||||
count with <function>hb_face_reference(face)</function> and
|
||||
decrease it with
|
||||
<function>hb_face_destroy(face)</function>. Likewise, you
|
||||
increase the reference count on a font with
|
||||
<function>hb_font_reference(font)</function> and decrease it
|
||||
with <function>hb_font_destroy(font)</function>.
|
||||
</para>
|
||||
<para>
|
||||
You can also attach user data to face objects and font objects.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="fonts-and-faces-custom-functions">
|
||||
<title>Customizing font functions</title>
|
||||
<para>
|
||||
During shaping, HarfBuzz frequently needs to query font objects
|
||||
to get at the contents and parameters of the glyphs in a font
|
||||
file. It includes a built-in set of functions that is tailored
|
||||
to working with OpenType fonts. However, as was the case with
|
||||
Unicode functions in the buffers chapter, HarfBuzz also wants to
|
||||
make it easy for you to assign a substitute set of font
|
||||
functions if you are developing a program to work with a library
|
||||
or platform that provides its own font functions.
|
||||
</para>
|
||||
<para>
|
||||
Therefore, the HarfBuzz API defines a set of virtual
|
||||
methods for accessing font-object properties, and you can
|
||||
replace the defaults with your own selections without
|
||||
interfering with the shaping process. Each font object in
|
||||
HarfBuzz includes a structure called
|
||||
<literal>font_funcs</literal> that serves as a vtable for the
|
||||
font object. The virtual methods in
|
||||
<literal>font_funcs</literal> are:
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_font_get_font_h_extents_func_t</function>: returns
|
||||
the extents of the font for horizontal text.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_font_get_font_v_extents_func_t</function>: returns
|
||||
the extents of the font for vertical text.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_font_get_nominal_glyph_func_t</function>: returns
|
||||
the font's nominal glyph for a given code point.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_font_get_variation_glyph_func_t</function>: returns
|
||||
the font's glyph for a given code point when it is followed by a
|
||||
given Variation Selector.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_font_get_nominal_glyphs_func_t</function>: returns
|
||||
the font's nominal glyphs for a series of code points.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_font_get_glyph_advance_func_t</function>: returns
|
||||
the advance for a glyph.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_font_get_glyph_h_advance_func_t</function>: returns
|
||||
the advance for a glyph for horizontal text.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_font_get_glyph_v_advance_func_t</function>:returns
|
||||
the advance for a glyph for vertical text.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_font_get_glyph_advances_func_t</function>: returns
|
||||
the advances for a series of glyphs.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_font_get_glyph_h_advances_func_t</function>: returns
|
||||
the advances for a series of glyphs for horizontal text .
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_font_get_glyph_v_advances_func_t</function>: returns
|
||||
the advances for a series of glyphs for vertical text.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_font_get_glyph_origin_func_t</function>: returns
|
||||
the origin coordinates of a glyph.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_font_get_glyph_h_origin_func_t</function>: returns
|
||||
the origin coordinates of a glyph for horizontal text.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_font_get_glyph_v_origin_func_t</function>: returns
|
||||
the origin coordinates of a glyph for vertical text.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_font_get_glyph_extents_func_t</function>: returns
|
||||
the extents for a glyph.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_font_get_glyph_contour_point_func_t</function>:
|
||||
returns the coordinates of a specific contour point from a glyph.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_font_get_glyph_name_func_t</function>: returns the
|
||||
name of a glyph (from its glyph index).
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_font_get_glyph_from_name_func_t</function>: returns
|
||||
the glyph index that corresponds to a given glyph name.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>
|
||||
You can fetch the font-functions configuration for a font object
|
||||
by calling <function>hb_font_get_font_funcs()</function>:
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_font_funcs_t *ffunctions;
|
||||
ffunctions = hb_font_get_font_funcs (font);
|
||||
</programlisting>
|
||||
<para>
|
||||
The individual methods can each be replaced with their own setter
|
||||
function, such as
|
||||
<function>hb_font_funcs_set_nominal_glyph_func(*ffunctions,
|
||||
func, *user_data, destroy)</function>.
|
||||
</para>
|
||||
<para>
|
||||
Font-functions structures can be reused for multiple font
|
||||
objects, and can be reference counted with
|
||||
<function>hb_font_funcs_reference()</function> and
|
||||
<function>hb_font_funcs_destroy()</function>. Just like other
|
||||
objects in HarfBuzz, you can set user-data for each
|
||||
font-functions structure and assign a destroy callback for
|
||||
it.
|
||||
</para>
|
||||
<para>
|
||||
You can also mark a font-functions structure as immutable,
|
||||
with <function>hb_font_funcs_make_immutable()</function>. This
|
||||
is especially useful if your code is a library or framework that
|
||||
will have its own client programs. By marking your
|
||||
font-functions structures as immutable, you prevent your client
|
||||
programs from changing the configuration and introducing
|
||||
inconsistencies and errors downstream.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="fonts-and-faces-native-opentype">
|
||||
<title>Font objects and HarfBuzz's native OpenType implementation</title>
|
||||
<para>
|
||||
By default, whenever HarfBuzz creates a font object, it will
|
||||
configure the font to use a built-in set of font functions that
|
||||
supports contemporary OpenType font internals. If you want to
|
||||
work with OpenType or TrueType fonts, you should be able to use
|
||||
these functions without difficulty.
|
||||
</para>
|
||||
<para>
|
||||
Many of the methods in the font-functions structure deal with
|
||||
the fundamental properties of glyphs that are required for
|
||||
shaping text: extents (the maximums and minimums on each axis),
|
||||
origins (the <literal>(0,0)</literal> coordinate point which
|
||||
glyphs are drawn in reference to), and advances (the amount that
|
||||
the cursor needs to be moved after drawing each glyph, including
|
||||
any empty space for the glyph's side bearings).
|
||||
</para>
|
||||
<para>
|
||||
As you can see in the list of functions, there are separate "horizontal"
|
||||
and "vertical" variants depending on whether the text is set in
|
||||
the horizontal or vertical direction. For some scripts, fonts
|
||||
that are designed to support text set horizontally or vertically (for
|
||||
example, in Japanese) may include metrics for both text
|
||||
directions. When fonts don't include this information, HarfBuzz
|
||||
does its best to transform what the font provides.
|
||||
</para>
|
||||
<para>
|
||||
In addition to the direction-specific functions, HarfBuzz
|
||||
provides some higher-level functions for fetching information
|
||||
like extents and advances for a glyph. If you call
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_font_get_glyph_advance_for_direction(font, direction, extents);
|
||||
</programlisting>
|
||||
<para>
|
||||
then you can provide any <type>hb_direction_t</type> as the
|
||||
<parameter>direction</parameter> parameter, and HarfBuzz will
|
||||
use the correct function variant for the text direction. There
|
||||
are similar higher-level versions of the functions for fetching
|
||||
extents, origin coordinates, and contour-point
|
||||
coordinates. There are also addition and subtraction functions
|
||||
for moving points with respect to the origin.
|
||||
</para>
|
||||
<para>
|
||||
There are also methods for fetching the glyph ID that
|
||||
corresponds to a Unicode code point (possibly when followed by a
|
||||
variation-selector code point), fetching the glyph name from the
|
||||
font, and fetching the glyph ID that corresponds to a glyph name
|
||||
you already have.
|
||||
</para>
|
||||
<para>
|
||||
HarfBuzz also provides functions for converting between glyph
|
||||
names and string
|
||||
variables. <function>hb_font_glyph_to_string(font, glyph, s,
|
||||
size)</function> retrieves the name for the glyph ID
|
||||
<parameter>glyph</parameter> from the font object. It generates a
|
||||
generic name of the form <literal>gidDDD</literal> (where DDD is
|
||||
the glyph index) if there is no name for the glyph in the
|
||||
font. The <function>hb_font_glyph_from_string(font, s, len,
|
||||
glyph)</function> takes an input string <parameter>s</parameter>
|
||||
and looks for a glyph with that name in the font, returning its
|
||||
glyph ID in the <parameter>glyph</parameter>
|
||||
output parameter. It automatically parses
|
||||
<literal>gidDDD</literal> and <literal>uniUUUU</literal> strings.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
|
||||
<!-- Commenting out FreeType integration section-holder for now. May move
|
||||
to the full-blown Integration Chapter. -->
|
||||
|
||||
<!-- <section id="fonts-and-faces-freetype">
|
||||
<title>Using FreeType</title>
|
||||
<para>
|
||||
|
||||
</para>
|
||||
</section>
|
||||
<section id="using-harfbuzzs-native-opentype-implementation">
|
||||
<title>Using HarfBuzz's native OpenType implementation</title>
|
||||
<para>
|
||||
|
||||
</para>
|
||||
</section>
|
||||
<section id="using-your-own-font-functions">
|
||||
<title>Using your own font functions</title>
|
||||
</section> -->
|
||||
|
||||
<section id="fonts-and-faces-variable">
|
||||
<title>Working with OpenType Variable Fonts</title>
|
||||
<para>
|
||||
If you are working with OpenType Variable Fonts, there are a few
|
||||
additional functions you should use to specify the
|
||||
variation-axis settings of your font object. Without doing so,
|
||||
your variable font's font object can still be used, but only at
|
||||
the default setting for every axis (which, of course, is
|
||||
sometimes what you want, but does not cover general usage).
|
||||
</para>
|
||||
<para>
|
||||
HarfBuzz manages variation settings in the
|
||||
<type>hb_variation_t</type> data type, which holds a <property>tag</property> for the
|
||||
variation-axis identifier tag and a <property>value</property> for its
|
||||
setting. You can retrieve the list of variation axes in a font
|
||||
binary from the face object (not from a font object, notably) by
|
||||
calling <function>hb_ot_var_get_axis_count(face)</function> to
|
||||
find the number of axes, then using
|
||||
<function>hb_ot_var_get_axis_infos()</function> to collect the
|
||||
axis structures:
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
axes = hb_ot_var_get_axis_count(face);
|
||||
...
|
||||
hb_ot_var_get_axis_infos(face, 0, axes, axes_array);
|
||||
</programlisting>
|
||||
<para>
|
||||
For each axis returned in the array, you can can access the
|
||||
identifier in its <property>tag</property>. HarfBuzz also has
|
||||
tag definitions predefined for the five standard axes specified
|
||||
in OpenType (<literal>ital</literal> for italic,
|
||||
<literal>opsz</literal> for optical size,
|
||||
<literal>slnt</literal> for slant, <literal>wdth</literal> for
|
||||
width, and <literal>wght</literal> for weight). Each axis also
|
||||
has a <property>min_value</property>, a
|
||||
<property>default_value</property>, and a <property>max_value</property>.
|
||||
</para>
|
||||
<para>
|
||||
To set your font object's variation settings, you call the
|
||||
<function>hb_font_set_variations()</function> function with an
|
||||
array of <type>hb_variation_t</type> variation settings. Let's
|
||||
say our font has weight and width axes. We need to specify each
|
||||
of the axes by tag and assign a value on the axis:
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
unsigned int variation_count = 2;
|
||||
hb_variation_t variation_data[variation_count];
|
||||
variation_data[0].tag = HB_OT_TAG_VAR_AXIS_WIDTH;
|
||||
variation_data[1].tag = HB_OT_TAG_VAR_AXIS_WEIGHT;
|
||||
variation_data[0].value = 80;
|
||||
variation_data[1].value = 750;
|
||||
...
|
||||
hb_font_set_variations(font, variation_data, variation_count);
|
||||
</programlisting>
|
||||
<para>
|
||||
That should give us a slightly condensed font ("normal" on the
|
||||
<literal>wdth</literal> axis is 100) at a noticeably bolder
|
||||
weight ("regular" is 400 on the <literal>wght</literal> axis).
|
||||
</para>
|
||||
<para>
|
||||
In practice, though, you should always check that the value you
|
||||
want to set on the axis is within the
|
||||
[<property>min_value</property>,<property>max_value</property>]
|
||||
range actually implemented in the font's variation axis. After
|
||||
all, a font might only provide lighter-than-regular weights, and
|
||||
setting a heavier value on the <literal>wght</literal> axis will
|
||||
not change that.
|
||||
</para>
|
||||
<para>
|
||||
Once your variation settings are specified on your font object,
|
||||
however, shaping with a variable font is just like shaping a
|
||||
static font.
|
||||
</para>
|
||||
</section>
|
||||
</chapter>
|
||||
|
||||
</chapter>
|
||||
|
@ -246,7 +246,7 @@
|
||||
<listitem>
|
||||
<para>
|
||||
Use <ulink url="https://developer.gnome.org/glib/">GLib</ulink>. <emphasis>(Default = auto)</emphasis>
|
||||
</para>
|
||||
</para>
|
||||
<para>
|
||||
This option enables or disables usage of the GLib
|
||||
library. The default setting is to check for the
|
||||
@ -297,7 +297,7 @@
|
||||
<listitem>
|
||||
<para>
|
||||
Use <ulink url="https://www.freedesktop.org/wiki/Software/fontconfig/">Fontconfig</ulink>. <emphasis>(Default = auto)</emphasis>
|
||||
</para>
|
||||
</para>
|
||||
<para>
|
||||
This option enables or disables usage of the Fontconfig
|
||||
library, which provides font-matching functions and
|
||||
@ -317,7 +317,7 @@
|
||||
<listitem>
|
||||
<para>
|
||||
Use the <ulink url="http://site.icu-project.org/home">ICU</ulink> library. <emphasis>(Default = auto)</emphasis>
|
||||
</para>
|
||||
</para>
|
||||
<para>
|
||||
This option enables or disables usage of the
|
||||
<emphasis>International Components for
|
||||
@ -330,30 +330,12 @@
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><command>--with-ucdn</command></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Use HarfBuzz's <ulink url="https://github.com/harfbuzz/harfbuzz/tree/master/src/hb-ucdn">built-in UCDN library</ulink>. <emphasis>(Default = auto)</emphasis>
|
||||
</para>
|
||||
<para>
|
||||
The HarfBuzz source tree includes a <emphasis>Unicode
|
||||
Database and Normalization</emphasis> (UCDN) library
|
||||
that provides access to basic character properties in
|
||||
the Unicode Character Database (UCD) as well as low-level
|
||||
normalization functions. HarfBuzz can be built without
|
||||
this UCDN support if the usage of a different UCDN
|
||||
library is desired.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><command>--with-graphite2</command></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Use the <ulink url="http://graphite.sil.org/">Graphite2</ulink> library. <emphasis>(Default = no)</emphasis>
|
||||
</para>
|
||||
</para>
|
||||
<para>
|
||||
This option enables or disables usage of the Graphite2
|
||||
library, which provides support for the Graphite shaping
|
||||
@ -367,7 +349,7 @@
|
||||
<listitem>
|
||||
<para>
|
||||
Use the <ulink url="https://www.freetype.org/">FreeType</ulink> library. <emphasis>(Default = auto)</emphasis>
|
||||
</para>
|
||||
</para>
|
||||
<para>
|
||||
This option enables or disables usage of the FreeType
|
||||
font-rendering library. The default setting is to check for the
|
||||
@ -384,7 +366,7 @@
|
||||
Use the <ulink
|
||||
url="https://docs.microsoft.com/en-us/windows/desktop/intl/uniscribe">Uniscribe</ulink>
|
||||
library (experimental). <emphasis>(Default = no)</emphasis>
|
||||
</para>
|
||||
</para>
|
||||
<para>
|
||||
This option enables or disables usage of the Uniscribe
|
||||
font-rendering library. Uniscribe is available on
|
||||
@ -400,7 +382,7 @@
|
||||
<listitem>
|
||||
<para>
|
||||
Use the <ulink url="https://docs.microsoft.com/en-us/windows/desktop/directwrite/direct-write-portal">DirectWrite</ulink> library (experimental). <emphasis>(Default = no)</emphasis>
|
||||
</para>
|
||||
</para>
|
||||
<para>
|
||||
This option enables or disables usage of the DirectWrite
|
||||
font-rendering library. DirectWrite is available on
|
||||
@ -416,7 +398,7 @@
|
||||
<listitem>
|
||||
<para>
|
||||
Use the <ulink url="https://developer.apple.com/documentation/coretext">CoreText</ulink> library. <emphasis>(Default = no)</emphasis>
|
||||
</para>
|
||||
</para>
|
||||
<para>
|
||||
This option enables or disables usage of the CoreText
|
||||
library. CoreText is available on macOS and iOS systems.
|
||||
|
258
docs/usermanual-object-model.xml
Normal file
258
docs/usermanual-object-model.xml
Normal file
@ -0,0 +1,258 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
|
||||
<!ENTITY % local.common.attrib "xmlns:xi CDATA #FIXED 'http://www.w3.org/2003/XInclude'">
|
||||
<!ENTITY version SYSTEM "version.xml">
|
||||
]>
|
||||
<chapter id="object-model">
|
||||
<title>The HarfBuzz object model</title>
|
||||
<section id="object-model-intro">
|
||||
<title>An overview of data types in HarfBuzz</title>
|
||||
<para>
|
||||
HarfBuzz features two kinds of data types: non-opaque,
|
||||
pass-by-value types and opaque, heap-allocated types. This kind
|
||||
of separation is common in C libraries that have to provide
|
||||
API/ABI compatibility (almost) indefinitely.
|
||||
</para>
|
||||
<para>
|
||||
<emphasis>Value types:</emphasis> The non-opaque, pass-by-value
|
||||
types include integer types, enums, and small structs. Exposing
|
||||
a struct in the public API makes it impossible to expand the
|
||||
struct in the future. As such, exposing structs is reserved for
|
||||
cases where it’s extremely inefficient to do otherwise.
|
||||
</para>
|
||||
<para>
|
||||
In HarfBuzz, several structs, like <literal>hb_glyph_info_t</literal> and
|
||||
<literal>hb_glyph_position_t</literal>, fall into that efficiency-sensitive
|
||||
category and are non-opaque.
|
||||
</para>
|
||||
<para>
|
||||
For all non-opaque structs where future extensibility may be
|
||||
necessary, reserved members are included to hold space for
|
||||
possible future members. As such, it’s important to provide
|
||||
<function>equal()</function>, and <function>hash()</function>
|
||||
methods for such structs, allowing users of the API do
|
||||
effectively deal with the type without having to
|
||||
adapt their code to future changes.
|
||||
</para>
|
||||
<para>
|
||||
Important value types provided by HarfBuzz include the structs
|
||||
for working with Unicode code points, glyphs, and tags for font
|
||||
tables and features, as well as the enums for many Unicode and
|
||||
OpenType properties.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="object-model-object-types">
|
||||
<title>Objects in HarfBuzz</title>
|
||||
<para>
|
||||
<emphasis>Object types:</emphasis> Opaque struct types are used
|
||||
for what HarfBuzz loosely calls "objects." This doesn’t have
|
||||
much to do with the terminology from object-oriented programming
|
||||
(OOP), although some of the concepts are similar.
|
||||
</para>
|
||||
<para>
|
||||
In HarfBuzz, all object types provide certain
|
||||
lifecycle-management APIs. Objects are reference-counted, and
|
||||
constructed with various <function>create()</function> methods, referenced via
|
||||
<function>reference()</function> and dereferenced using
|
||||
<function>destroy()</function>.
|
||||
</para>
|
||||
<para>
|
||||
For example,
|
||||
the <literal>hb_buffer_t</literal> object has
|
||||
<function>hb_buffer_create()</function> as its constructor,
|
||||
<function>hb_buffer_reference()</function> to reference, and
|
||||
<function>hb_buffer_destroy()</function> to dereference.
|
||||
</para>
|
||||
<para>
|
||||
After construction, each object's properties are accessible only
|
||||
through the setter and getter functions described in the API
|
||||
Reference manual.
|
||||
</para>
|
||||
<para>
|
||||
Key object types provided by HarfBuzz include:
|
||||
</para>
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>
|
||||
<emphasis>blobs</emphasis>, which act as low-level wrappers around binary
|
||||
data. Blobs are typically used to hold the contents of a
|
||||
binary font file.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<emphasis>faces</emphasis>, which represent typefaces from a
|
||||
font file, but without specific parameters (such as size) set.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<emphasis>fonts</emphasis>, which represent instances of a
|
||||
face with all of their parameters specified.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<emphasis>buffers</emphasis>, which hold Unicode code points
|
||||
for characters (before shaping) and the shaped glyph output
|
||||
(after shaping).
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<emphasis>shape plans</emphasis>, which store the settings
|
||||
that HarfBuzz will use when shaping a particular text
|
||||
segment. Shape plans are not generally used by client
|
||||
programs directly, but as we will see in a later chapter,
|
||||
they are still valuable to understand.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
<section id="object-model-lifecycle">
|
||||
<title>Object lifecycle management</title>
|
||||
<para>
|
||||
Each object type in HarfBuzz provides a
|
||||
<function>create()</function> method. Some object types provide
|
||||
additional variants of <function>create()</function> to handle
|
||||
special cases or to speed up common tasks; those variants are
|
||||
documented in the API reference. For example,
|
||||
<function>hb_blob_create_from_file()</function> constructs a new
|
||||
blob directly from the contents of a file.
|
||||
</para>
|
||||
<para>
|
||||
All objects are created with an initial reference count of
|
||||
<literal>1</literal>. Client programs can increase the reference
|
||||
count on an object by calling its
|
||||
<function>reference()</function> method. Whenever a client
|
||||
program is finished with an object, it should call its
|
||||
corresponding <function>destroy()</function> method. The destroy
|
||||
method will decrease the reference count on the object and,
|
||||
whenever the reference count reaches zero, it will also destroy
|
||||
the object and free all of the associated memory.
|
||||
</para>
|
||||
<para>
|
||||
All of HarfBuzz's object-lifecycle-management APIs are
|
||||
thread-safe (unless you compiled HarfBuzz from source with the
|
||||
<literal>HB_NO_MT</literal> configuration flag), even when the
|
||||
object as a whole is not thread-safe.
|
||||
It is also permissible to <function>reference()</function> or to
|
||||
<function>destroy()</function> the <literal>NULL</literal>
|
||||
value.
|
||||
</para>
|
||||
<para>
|
||||
Some objects are thread-safe after they have been constructed
|
||||
and set up. The general pattern is to
|
||||
<function>create()</function> the object, make a few
|
||||
<function>set_*()</function> calls to set up the
|
||||
object, and then use it without further modification.
|
||||
</para>
|
||||
<para>
|
||||
To ensure that such an object is not modified, client programs
|
||||
can explicitly mark an object as immutable. HarfBuzz provides
|
||||
<function>make_immutable()</function> methods to mark an object
|
||||
as immutable and <function>is_immutable()</function> methods to
|
||||
test whether or not an object is immutable. Attempts to use
|
||||
setter functions on immutable objects will fail silently; see the API
|
||||
Reference manual for specifics.
|
||||
</para>
|
||||
<para>
|
||||
Note also that there are no "make mutable" methods. If client
|
||||
programs need to alter an object previously marked as immutable,
|
||||
they will need to make a duplicate of the original.
|
||||
</para>
|
||||
<para>
|
||||
Finally, object constructors (and, indeed, as much of the
|
||||
shaping API as possible) will never return
|
||||
<literal>NULL</literal>. Instead, if there is an allocation
|
||||
error, each constructor will return an “empty” object
|
||||
singleton.
|
||||
</para>
|
||||
<para>
|
||||
These empty-object singletons are inert and safe (although
|
||||
typically useless) to pass around. This design choice avoids
|
||||
having to check for <literal>NULL</literal> pointers all
|
||||
throughout the code.
|
||||
</para>
|
||||
<para>
|
||||
In addition, this “empty” object singleton can also be accessed
|
||||
using the <function>get_empty()</function> method of the object
|
||||
type in question.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
|
||||
<section id="object-model-user-data">
|
||||
<title>User data</title>
|
||||
<para>
|
||||
To better integrate with client programs, HarfBuzz's objects
|
||||
offer a "user data" mechanism that can be used to attach
|
||||
arbitrary data to the object. User-data attachment can be
|
||||
useful for tying the lifecycles of various pieces of data
|
||||
together, or for creating language bindings.
|
||||
</para>
|
||||
<para>
|
||||
Each object type has a <function>set_user_data()</function>
|
||||
method and a <function>get_user_data()</function> method. The
|
||||
<function>set_user_data()</function> methods take a client-provided
|
||||
<literal>key</literal> and a pointer,
|
||||
<literal>user_data</literal>, pointing to the data itself. Once
|
||||
the key-data pair has been attached to the object, the
|
||||
<function>get_user_data()</function> method can be called with
|
||||
the key, returning the <function>user_data</function> pointer.
|
||||
</para>
|
||||
<para>
|
||||
The <function>set_user_data()</function> methods also support an
|
||||
optional <function>destroy</function> callback. Client programs
|
||||
can set the <function>destroy</function> callback and receive
|
||||
notification from HarfBuzz whenever the object is destructed.
|
||||
</para>
|
||||
<para>
|
||||
Finally, each <function>set_user_data()</function> method allows
|
||||
the client program to set a <literal>replace</literal> Boolean
|
||||
indicating whether or not the function call should replace any
|
||||
existing <literal>user_data</literal>
|
||||
associated with the specified key.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
<section id="object-model-blobs">
|
||||
<title>Blobs</title>
|
||||
<para>
|
||||
While most of HarfBuzz's object types are specific to the
|
||||
shaping process, <emphasis>blobs</emphasis> are somewhat
|
||||
different.
|
||||
</para>
|
||||
<para>
|
||||
Blobs are an abstraction desgined to negotiate lifecycle and
|
||||
permissions for raw pieces of data. For example, when you load
|
||||
the raw font data into memory and want to pass it to HarfBuzz,
|
||||
you do so in a <literal>hb_blob_t</literal> wrapper.
|
||||
</para>
|
||||
<para>
|
||||
This allows you to take advantage of HarffBuzz's
|
||||
reference-counting and <function>destroy</function>
|
||||
callbacks. If you allocated the memory for the data using
|
||||
<function>malloc()</function>, you would create the blob using
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_blob_create (data, length, HB_MEMORY_MODE_WRITABLE, NULL, free)
|
||||
</programlisting>
|
||||
<para>
|
||||
That way, HarfBuzz will call <function>free()</function> on the
|
||||
allocated memory whenever the blob drops its last reference and
|
||||
is deconstructed. Consequently, the user code can stop worrying
|
||||
about freeing memory and let the reference-counting machinery
|
||||
take care of that.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
</chapter>
|
@ -6,14 +6,299 @@
|
||||
]>
|
||||
<chapter id="shaping-and-shape-plans">
|
||||
<title>Shaping and shape plans</title>
|
||||
<section id="opentype-features">
|
||||
<para>
|
||||
Once you have your face and font objects configured as desired and
|
||||
your input buffer is filled with the characters you need to shape,
|
||||
all you need to do is call <function>hb_shape()</function>.
|
||||
</para>
|
||||
<para>
|
||||
HarfBuzz will return the shaped version of the text in the same
|
||||
buffer that you provided, but it will be in output mode. At that
|
||||
point, you can iterate through the glyphs in the buffer, drawing
|
||||
each one at the specified position or handing them off to the
|
||||
appropriate graphics library.
|
||||
</para>
|
||||
<para>
|
||||
For the most part, HarfBuzz's shaping step is straightforward from
|
||||
the outside. But that doesn't mean there will never be cases where
|
||||
you want to look under the hood and see what is happening on the
|
||||
inside. HarfBuzz provides facilities for doing that, too.
|
||||
</para>
|
||||
|
||||
<section id="shaping-buffer-output">
|
||||
<title>Shaping and buffer output</title>
|
||||
<para>
|
||||
The <function>hb_shape()</function> function call takes four arguments: the font
|
||||
object to use, the buffer of characters to shape, an array of
|
||||
user-specified features to apply, and the length of that feature
|
||||
array. The feature array can be NULL, so for the sake of
|
||||
simplicity we will start with that case.
|
||||
</para>
|
||||
<para>
|
||||
Internally, HarfBuzz looks at the tables of the font file to
|
||||
determine where glyph classes, substitutions, and positioning
|
||||
are defined, using that information to decide which
|
||||
<emphasis>shaper</emphasis> to use (<literal>ot</literal> for
|
||||
OpenType fonts, <literal>aat</literal> for Apple Advanced
|
||||
Typography fonts, and so on). It also looks at the direction,
|
||||
script, and language properties of the segment to figure out
|
||||
which script-specific shaping model is needed (at least, in
|
||||
shapers that support multiple options).
|
||||
</para>
|
||||
<para>
|
||||
If a font has a GDEF table, then that is used for
|
||||
glyph classes; if not, HarfBuzz will fall back to Unicode
|
||||
categorization by code point. If a font has an AAT "morx" table,
|
||||
then it is used for substitutions; if not, but there is a GSUB
|
||||
table, then the GSUB table is used. If the font has an AAT
|
||||
"kerx" table, then it is used for positioning; if not, but
|
||||
there is a GPOS table, then the GPOS table is used. If neither
|
||||
table is found, but there is a "kern" table, then HarfBuzz will
|
||||
use the "kern" table. If there is no "kerx", no GPOS, and no
|
||||
"kern", HarfBuzz will fall back to positioning marks itself.
|
||||
</para>
|
||||
<para>
|
||||
With a well-behaved OpenType font, you expect GDEF, GSUB, and
|
||||
GPOS tables to all be applied. HarfBuzz implements the
|
||||
script-specific shaping models in internal functions, rather
|
||||
than in the public API.
|
||||
</para>
|
||||
<para>
|
||||
The algorithms
|
||||
used for complex scripts can be quite involved; HarfBuzz tries
|
||||
to be compatible with the OpenType Layout specification
|
||||
and, wherever there is any ambiguity, HarfBuzz attempts to replicate the
|
||||
output of Microsoft's Uniscribe engine. See the <ulink
|
||||
url="https://docs.microsoft.com/en-us/typography/script-development/standard">Microsoft
|
||||
Typography pages</ulink> for more detail.
|
||||
</para>
|
||||
<para>
|
||||
In general, though, all that you need to know is that
|
||||
<function>hb_shape()</function> returns the results of shaping
|
||||
in the same buffer that you provided. The buffer's content type
|
||||
will now be set to
|
||||
<literal>HB_BUFFER_CONTENT_TYPE_GLYPHS</literal>, indicating
|
||||
that it contains shaped output, rather than input text. You can
|
||||
now extract the glyph information and positioning arrays:
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_glyph_info_t *glyph_info = hb_buffer_get_glyph_infos(buf, &glyph_count);
|
||||
hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions(buf, &glyph_count);
|
||||
</programlisting>
|
||||
<para>
|
||||
The glyph information array holds a <type>hb_glyph_info_t</type>
|
||||
for each output glyph, which has two fields:
|
||||
<parameter>codepoint</parameter> and
|
||||
<parameter>cluster</parameter>. Whereas, in the input buffer,
|
||||
the <parameter>codepoint</parameter> field contained the Unicode
|
||||
code point, it now contains the glyph ID of the corresponding
|
||||
glyph in the font. The <parameter>cluster</parameter> field is
|
||||
an integer that you can use to help identify when shaping has
|
||||
reordered, split, or combined code points; we will say more
|
||||
about that in the next chapter.
|
||||
</para>
|
||||
<para>
|
||||
The glyph positions array holds a corresponding
|
||||
<type>hb_glyph_position_t</type> for each output glyph,
|
||||
containing four fields: <parameter>x_advance</parameter>,
|
||||
<parameter>y_advance</parameter>,
|
||||
<parameter>x_offset</parameter>, and
|
||||
<parameter>y_offset</parameter>. The advances tell you how far
|
||||
you need to move the drawing point after drawing this glyph,
|
||||
depending on whether you are setting horizontal text (in which
|
||||
case you will have x advances) or vertical text (for which you
|
||||
will have y advances). The x and y offsets tell you where to
|
||||
move to start drawing the glyph; usually you will have both and
|
||||
x and a y offset, regardless of the text direction.
|
||||
</para>
|
||||
<para>
|
||||
Most of the time, you will rely on a font-rendering library or
|
||||
other graphics library to do the actual drawing of glyphs, so
|
||||
you will need to iterate through the glyphs in the buffer and
|
||||
pass the corresponding values off.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="shaping-opentype-features">
|
||||
<title>OpenType features</title>
|
||||
<para>
|
||||
OpenType features enable fonts to include smart behavior,
|
||||
implemented as "lookup" rules stored in the GSUB and GPOS
|
||||
tables. The OpenType specification defines a long list of
|
||||
standard features that fonts can use for these behaviors; each
|
||||
feature has a four-character reserved name and a well-defined
|
||||
semantic meaning.
|
||||
</para>
|
||||
<para>
|
||||
Some OpenType features are defined for the purpose of supporting
|
||||
complex-script shaping, and are automatically activated, but
|
||||
only when a buffer's script property is set to a script that the
|
||||
feature supports.
|
||||
</para>
|
||||
<para>
|
||||
Other features are more generic and can apply to several (or
|
||||
any) script, and shaping engines are expected to implement
|
||||
them. By default, HarfBuzz activates several of these features
|
||||
on every text run. They include <literal>ccmp</literal>,
|
||||
<literal>locl</literal>, <literal>mark</literal>,
|
||||
<literal>mkmk</literal>, and <literal>rlig</literal>.
|
||||
</para>
|
||||
<para>
|
||||
In addition, if the text direction is horizontal, HarfBuzz
|
||||
also applies the <literal>calt</literal>,
|
||||
<literal>clig</literal>, <literal>curs</literal>,
|
||||
<literal>kern</literal>, <literal>liga</literal>,
|
||||
<literal>rclt</literal>, and <literal>frac</literal> features.
|
||||
</para>
|
||||
<para>
|
||||
If the text direction is vertical, HarfBuzz applies
|
||||
the <literal>vert</literal> feature by default.
|
||||
</para>
|
||||
<para>
|
||||
Still other features are designed to be purely optional and left
|
||||
up to the application or the end user to enable or disable as desired.
|
||||
</para>
|
||||
<para>
|
||||
You can adjust the set of features that HarfBuzz applies to a
|
||||
buffer by supplying an array of <type>hb_feature_t</type>
|
||||
features as the third argument to
|
||||
<function>hb_shape()</function>. For a simple case, let's just
|
||||
enable the <literal>dlig</literal> feature, which turns on any
|
||||
"discretionary" ligatures in the font:
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_feature_t userfeatures[1];
|
||||
userfeatures[0].tag = HB_TAG('d','l','i','g');
|
||||
userfeatures[0].value = 1;
|
||||
userfeatures[0].start = HB_FEATURE_GLOBAL_START;
|
||||
userfeatures[0].end = HB_FEATURE_GLOBAL_END;
|
||||
</programlisting>
|
||||
<para>
|
||||
<literal>HB_FEATURE_GLOBAL_END</literal> and
|
||||
<literal>HB_FEATURE_GLOBAL_END</literal> are macros we can use
|
||||
to indicate that the features will be applied to the entire
|
||||
buffer. We could also have used a literal <literal>0</literal>
|
||||
for the start and a <literal>-1</literal> to indicate the end of
|
||||
the buffer (or have selected other start and end positions, if needed).
|
||||
</para>
|
||||
<para>
|
||||
When we pass the <varname>userfeatures</varname> array to
|
||||
<function>hb_shape()</function>, any discretionary ligature
|
||||
substitutions from our font that match the text in our buffer
|
||||
will get performed:
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_shape(font, buf, userfeatures, num_features);
|
||||
</programlisting>
|
||||
<para>
|
||||
Just like we enabled the <literal>dlig</literal> feature by
|
||||
setting its <parameter>value</parameter> to
|
||||
<literal>1</literal>, you would disable a feature by setting its
|
||||
<parameter>value</parameter> to <literal>0</literal>. Some
|
||||
features can take other <parameter>value</parameter> settings;
|
||||
be sure you read the full specification of each feature tag to
|
||||
understand what it does and how to control it.
|
||||
</para>
|
||||
</section>
|
||||
<section id="plans-and-caching">
|
||||
|
||||
<section id="shaping-shaper-selection">
|
||||
<title>Shaper selection</title>
|
||||
<para>
|
||||
The basic version of <function>hb_shape()</function> determines
|
||||
its shaping strategy based on examining the capabilities of the
|
||||
font file. OpenType font tables cause HarfBuzz to try the
|
||||
<literal>ot</literal> shaper, while AAT font tables cause HarfBuzz to try the
|
||||
<literal>aat</literal> shaper.
|
||||
</para>
|
||||
<para>
|
||||
In the real world, however, a font might include some unusual
|
||||
mix of tables, or one of the tables might simply be broken for
|
||||
the script you need to shape. So, sometimes, you might not
|
||||
want to rely on HarfBuzz's process for deciding what to do, and
|
||||
just tell <function>hb_shape()</function> what you want it to try.
|
||||
</para>
|
||||
<para>
|
||||
<function>hb_shape_full()</function> is an alternate shaping
|
||||
function that lets you supply a list of shapers for HarfBuzz to
|
||||
try, in order, when shaping your buffer. For example, if you
|
||||
have determined that HarfBuzz's attempts to work around broken
|
||||
tables gives you better results than the AAT shaper itself does,
|
||||
you might move the AAT shaper to the end of your list of
|
||||
preferences and call <function>hb_shape_full()</function>
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
char *shaperprefs[3] = {"ot", "default", "aat"};
|
||||
...
|
||||
hb_shape_full(font, buf, userfeatures, num_features, shaperprefs);
|
||||
</programlisting>
|
||||
<para>
|
||||
to get results you are happier with.
|
||||
</para>
|
||||
<para>
|
||||
You may also want to call
|
||||
<function>hb_shape_list_shapers()</function> to get a list of
|
||||
the shapers that were built at compile time in your copy of HarfBuzz.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="shaping-plans-and-caching">
|
||||
<title>Plans and caching</title>
|
||||
<para>
|
||||
Internally, HarfBuzz uses a structure called a shape plan to
|
||||
track its decisions about how to shape the contents of a
|
||||
buffer. The <function>hb_shape()</function> function builds up the shape plan by
|
||||
examining segment properties and by inspecting the contents of
|
||||
the font.
|
||||
</para>
|
||||
<para>
|
||||
This process can involve some decision-making and
|
||||
trade-offs — for example, HarfBuzz inspects the GSUB and GPOS
|
||||
lookups for the script and language tags set on the segment
|
||||
properties, but it falls back on the lookups under the
|
||||
<literal>DFLT</literal> tag (and sometimes other common tags)
|
||||
if there are actually no lookups for the tag requested.
|
||||
</para>
|
||||
<para>
|
||||
HarfBuzz also includes some work-arounds for
|
||||
handling well-known older font conventions that do not follow
|
||||
OpenType or Unicode specifications, for buggy system fonts, and for
|
||||
peculiarities of Microsoft Uniscribe. All of that means that a
|
||||
shape plan, while not something that you should edit directly in
|
||||
client code, still might be an object that you want to
|
||||
inspect. Furthermore, if resources are tight, you might want to
|
||||
cache the shape plan that HarfBuzz builds for your buffer and
|
||||
font, so that you do not have to rebuild it for every shaping call.
|
||||
</para>
|
||||
<para>
|
||||
You can create a cacheable shape plan with
|
||||
<function>hb_shape_plan_create_cached(face, props,
|
||||
user_features, num_user_features, shaper_list)</function>, where
|
||||
<parameter>face</parameter> is a face object (not a font object,
|
||||
notably), <parameter>props</parameter> is an
|
||||
<type>hb_segment_properties_t</type>,
|
||||
<parameter>user_features</parameter> is an array of
|
||||
<type>hb_feature_t</type>s (with length
|
||||
<parameter>num_user_features</parameter>), and
|
||||
<parameter>shaper_list</parameter> is a list of shapers to try.
|
||||
</para>
|
||||
<para>
|
||||
Shape plans are objects in HarfBuzz, so there are
|
||||
reference-counting functions and user-data attachment functions
|
||||
you can
|
||||
use. <function>hb_shape_plan_reference(shape_plan)</function>
|
||||
increases the reference count on a shape plan, while
|
||||
<function>hb_shape_plan_destroy(shape_plan)</function> decreases
|
||||
the reference count, destroying the shape plan when the last
|
||||
reference is dropped.
|
||||
</para>
|
||||
<para>
|
||||
You can attach user data to a shaper (with a key) using the
|
||||
<function>hb_shape_plan_set_user_data(shape_plan,key,data,destroy,replace)</function>
|
||||
function, optionally supplying a <function>destroy</function>
|
||||
callback to use. You can then fetch the user data attached to a
|
||||
shape plan with
|
||||
<function>hb_shape_plan_get_user_data(shape_plan, key)</function>.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
</chapter>
|
||||
|
244
docs/usermanual-utilities.xml
Normal file
244
docs/usermanual-utilities.xml
Normal file
@ -0,0 +1,244 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
|
||||
<!ENTITY % local.common.attrib "xmlns:xi CDATA #FIXED 'http://www.w3.org/2003/XInclude'">
|
||||
<!ENTITY version SYSTEM "version.xml">
|
||||
]>
|
||||
<chapter id="utilities">
|
||||
<title>Utilities</title>
|
||||
<para>
|
||||
HarfBuzz includes several auxiliary components in addition to the
|
||||
main APIs. These include a set of command-line tools, a set of
|
||||
lower-level APIs for common data types that may be of interest to
|
||||
client programs, and an embedded library for working with
|
||||
Unicode Character Database (UCD) data.
|
||||
</para>
|
||||
|
||||
<section id="utilities-command-line-tools">
|
||||
<title>Command-line tools</title>
|
||||
<para>
|
||||
HarfBuzz include three command-line tools:
|
||||
<program>hb-shape</program>, <program>hb-view</program>, and
|
||||
<program>hb-subset</program>. They can be used to examine
|
||||
HarfBuzz's functionality, debug font binaries, or explore the
|
||||
various shaping models and features from a terminal.
|
||||
</para>
|
||||
|
||||
<section id="utilities-command-line-hbshape">
|
||||
<title>hb-shape</title>
|
||||
<para>
|
||||
<emphasis><program>hb-shape</program></emphasis> allows you to run HarfBuzz's
|
||||
<function>hb_shape()</function> function on an input string and
|
||||
to examine the outcome, in human-readable form, as terminal
|
||||
output. <program>hb-shape</program> does
|
||||
<emphasis>not</emphasis> render the results of the shaping call
|
||||
into rendered text (you can use <program>hb-view</program>, below, for
|
||||
that). Instead, it prints out the final glyph indices and
|
||||
positions, taking all shaping operations into account, as if the
|
||||
input string were a HarfBuzz input buffer.
|
||||
</para>
|
||||
<para>
|
||||
You can specify the font to be used for shaping and, with
|
||||
command-line options, you can add various aspects of the
|
||||
internal state to the output that is sent to the terminal. The
|
||||
general format is
|
||||
</para>
|
||||
<programlisting>
|
||||
<command>hb-shape</command> <optional>[OPTIONS]</optional>
|
||||
<parameter>path/to/font/file.ttf</parameter>
|
||||
<parameter>yourinputtext</parameter>
|
||||
</programlisting>
|
||||
<para>
|
||||
The default output format is plain text (although JSON output
|
||||
can be selected instead by specifying the option
|
||||
<optional>--output-format=json</optional>). The default output
|
||||
syntax reports each glyph name (or glyph index if there is no
|
||||
name) followed by its cluster value, its horizontal and vertical
|
||||
position displacement, and its horizontal and vertical advances.
|
||||
</para>
|
||||
<para>
|
||||
Output options exist to skip any of these elements in the
|
||||
output, and to include additional data, such as Unicode
|
||||
code-point values, glyph extents, glyph flags, or interim
|
||||
shaping results.
|
||||
</para>
|
||||
<para>
|
||||
Output can also be redirected to a file, or input read from a
|
||||
file. Additional options enable you to enable or disable
|
||||
specific font features, to set variation-font axis values, to
|
||||
alter the language, script, direction, and clustering settings
|
||||
used, to enable sanity checks, or to change which shaping engine is used.
|
||||
</para>
|
||||
<para>
|
||||
For a complete explanation of the options available, run
|
||||
</para>
|
||||
<programlisting>
|
||||
<command>hb-shape</command> <parameter>--help</parameter>
|
||||
</programlisting>
|
||||
</section>
|
||||
|
||||
<section id="utilities-command-line-hbview">
|
||||
<title>hb-view</title>
|
||||
<para>
|
||||
<emphasis><program>hb-view</program></emphasis> allows you to
|
||||
see the shaped output of an input string in rendered
|
||||
form. Like <program>hb-shape</program>,
|
||||
<program>hb-view</program> takes a font file and a text string
|
||||
as its arguments:
|
||||
</para>
|
||||
<programlisting>
|
||||
<command>hb-view</command> <optional>[OPTIONS]</optional>
|
||||
<parameter>path/to/font/file.ttf</parameter>
|
||||
<parameter>yourinputtext</parameter>
|
||||
</programlisting>
|
||||
<para>
|
||||
By default, <program>hb-view</program> renders the shaped
|
||||
text in ASCII block-character images as terminal output. By
|
||||
appending the
|
||||
<command>--output-file=<optional>filename</optional></command>
|
||||
switch, you can write the output to a PNG, SVG, or PDF file
|
||||
(among other formats).
|
||||
</para>
|
||||
<para>
|
||||
As with <program>hb-shape</program>, a lengthy set of options
|
||||
is available, with which you can enable or disable
|
||||
specific font features, set variation-font axis values,
|
||||
alter the language, script, direction, and clustering settings
|
||||
used, enable sanity checks, or change which shaping engine is
|
||||
used.
|
||||
</para>
|
||||
<para>
|
||||
You can also set the foreground and background colors used for
|
||||
the output, independently control the width of all four
|
||||
margins, alter the line spacing, and annotate the output image
|
||||
with
|
||||
</para>
|
||||
<para>
|
||||
In general, <program>hb-view</program> is a quick way to
|
||||
verify that the output of HarfBuzz's shaping operation looks
|
||||
correct for a given text-and-font combination, but you may
|
||||
want to use <program>hb-shape</program> to figure out exactly
|
||||
why something does not appear as expected.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="utilities-command-line-hbsubset">
|
||||
<title>hb-subset</title>
|
||||
<para>
|
||||
<emphasis><program>hb-subset</program></emphasis> allows you
|
||||
to generate a subset of a given font, with a limited set of
|
||||
supported characters, features, and variation settings.
|
||||
</para>
|
||||
<para>
|
||||
By default, you provide an input font and an input text string
|
||||
as the arguments to <program>hb-subset</program>, and it will
|
||||
generate a font that covers the input text exactly like the
|
||||
input font does, but includes no other characters or features.
|
||||
</para>
|
||||
<programlisting>
|
||||
<command>hb-subset</command> <optional>[OPTIONS]</optional>
|
||||
<parameter>path/to/font/file.ttf</parameter>
|
||||
<parameter>yourinputtext</parameter>
|
||||
</programlisting>
|
||||
<para>
|
||||
For example, to create a subset of Noto Serif that just includes the
|
||||
numerals and the lowercase Latin alphabet, you could run
|
||||
</para>
|
||||
<programlisting>
|
||||
<command>hb-subset</command> <optional>[OPTIONS]</optional>
|
||||
<parameter>NotoSerif-Regular.ttf</parameter>
|
||||
<parameter>0123456789abcdefghijklmnopqrstuvwxyz</parameter>
|
||||
</programlisting>
|
||||
<para>
|
||||
There are options available to remove hinting from the
|
||||
subsetted font and to specify a list of variation-axis settings.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
</section>
|
||||
|
||||
<section id="utilities-common-types-apis">
|
||||
<title>Common data types and APIs</title>
|
||||
<para>
|
||||
HarfBuzz includes several APIs for working with general-purpose
|
||||
data that you may find convenient to leverage in your own
|
||||
software. They include set operations and integer-to-integer
|
||||
mapping operations.
|
||||
</para>
|
||||
<para>
|
||||
HarfBuzz uses set operations for internal bookkeeping, such as
|
||||
when it collects all of the glyph IDs covered by a particular
|
||||
font feature. You can also use the set API to build sets, add
|
||||
and remove elements, test whether or not sets contain particular
|
||||
elements, or compute the unions, intersections, or differences
|
||||
between sets.
|
||||
</para>
|
||||
<para>
|
||||
All set elements are integers (specifically,
|
||||
<type>hb_codepoint_t</type> 32-bit unsigned ints), and there are
|
||||
functions for fetching the minimum and maximum element from a
|
||||
set. The set API also includes some functions that might not
|
||||
be part of a generic set facility, such as the ability to add a
|
||||
contiguous range of integer elements to a set in bulk, and the
|
||||
ability to fetch the next-smallest or next-largest element.
|
||||
</para>
|
||||
<para>
|
||||
The HarfBuzz set API includes some conveniences as well. All
|
||||
sets are lifecycle-managed, just like other HarfBuzz
|
||||
objects. You increase the reference count on a set with
|
||||
<function>hb_set_reference()</function> and decrease it with
|
||||
<function>hb_set_destroy()</function>. You can also attach
|
||||
user data to a set, just like you can to blobs, buffers, faces,
|
||||
fonts, and other objects, and set destroy callbacks.
|
||||
</para>
|
||||
<para>
|
||||
HarfBuzz also provides an API for keeping track of
|
||||
integer-to-integer mappings. As with the set API, each integer is
|
||||
stored as an unsigned 32-bit <type>hb_codepoint_t</type>
|
||||
element. Maps, like other objects, are reference counted with
|
||||
reference and destroy functions, and you can attach user data to
|
||||
them. The mapping operations include adding and deleting
|
||||
integer-to-integer key:value pairs to the map, testing for the
|
||||
presence of a key, fetching the population of the map, and so on.
|
||||
</para>
|
||||
<para>
|
||||
There are several other internal HarfBuzz facilities that are
|
||||
exposed publicly and which you may want to take advantage of
|
||||
while processing text. HarfBuzz uses a common
|
||||
<type>hb_tag_t</type> for a variety of OpenType tag identifiers (for
|
||||
scripts, languages, font features, table names, variation-axis
|
||||
names, and more), and provides functions for converting strings
|
||||
to tags and vice-versa.
|
||||
</para>
|
||||
<para>
|
||||
Finally, HarfBuzz also includes data type for Booleans, bit
|
||||
masks, and other simple types.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="utilities-ucdn">
|
||||
<title>UCDN</title>
|
||||
<para>
|
||||
HarfBuzz includes a copy of the <ulink
|
||||
url="https://github.com/grigorig/ucdn">UCDN</ulink> (Unicode
|
||||
Database and Normalization) library, which provides functions
|
||||
for accessing basic Unicode character properties, performing
|
||||
canonical composition, and performing both canonical and
|
||||
compatibility decomposition.
|
||||
</para>
|
||||
<para>
|
||||
Currently, UCDN supports direct queries for several more character
|
||||
properties than HarfBuzz's built-in set of Unicode functions
|
||||
does, such as the BiDirectional Class, East Asian Width, Paired
|
||||
Bracket and Resolved Linebreak properties. If you need to access
|
||||
more properties than HarfBuzz's internal implementation
|
||||
provides, using the built-in UCDN functions may be a useful solution.
|
||||
</para>
|
||||
<para>
|
||||
The built-in UCDN functions are compiled by default when
|
||||
building HarfBuzz from source, but this can be disabled with a
|
||||
compile-time switch.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
</chapter>
|
28
mingw-configure.sh
Executable file
28
mingw-configure.sh
Executable file
@ -0,0 +1,28 @@
|
||||
#!/bin/sh
|
||||
|
||||
case $1 in
|
||||
i686 | x86_64) ;;
|
||||
*) echo "Usage: $0 i686|x86_64" >&2; exit 1 ;;
|
||||
esac
|
||||
|
||||
target=$1-w64-mingw32
|
||||
shift
|
||||
|
||||
exec "$(dirname "$0")"/configure \
|
||||
--build=`../config.guess` \
|
||||
--host=$target \
|
||||
--prefix=$HOME/.local/$target \
|
||||
CC= \
|
||||
CXX= \
|
||||
CPP= \
|
||||
LD= \
|
||||
CFLAGS="-static-libgcc" \
|
||||
CXXFLAGS="-static-libgcc -static-libstdc++" \
|
||||
CPPFLAGS="-I$HOME/.local/$target/include" \
|
||||
LDFLAGS=-L$HOME/.local/$target/lib \
|
||||
PKG_CONFIG_LIBDIR=$HOME/.local/$target/lib/pkgconfig:/usr/$target/sys-root/mingw/lib/pkgconfig/ \
|
||||
PKG_CONFIG_PATH=$HOME/.local/$target/share/pkgconfig:/usr/$target/sys-root/mingw/share/pkgconfig/ \
|
||||
PATH=$HOME/.local/$target/bin:/usr/$target/sys-root/mingw/bin:/usr/$target/bin:$PATH \
|
||||
--without-icu \
|
||||
--with-uniscribe \
|
||||
"$@"
|
58
mingw-ldd.py
Executable file
58
mingw-ldd.py
Executable file
@ -0,0 +1,58 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# Copied from https://github.com/xantares/mingw-ldd/blob/master/mingw-ldd.py
|
||||
# Modified to point to right prefix location on Fedora.
|
||||
|
||||
# WTFPL - Do What the Fuck You Want to Public License
|
||||
from __future__ import print_function
|
||||
import pefile
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
def get_dependency(filename):
|
||||
deps = []
|
||||
pe = pefile.PE(filename)
|
||||
for imp in pe.DIRECTORY_ENTRY_IMPORT:
|
||||
deps.append(imp.dll.decode())
|
||||
return deps
|
||||
|
||||
|
||||
def dep_tree(root, prefix=None):
|
||||
if not prefix:
|
||||
arch = get_arch(root)
|
||||
#print('Arch =', arch)
|
||||
prefix = '/usr/'+arch+'-w64-mingw32/sys-root/mingw/bin'
|
||||
#print('Using default prefix', prefix)
|
||||
dep_dlls = dict()
|
||||
|
||||
def dep_tree_impl(root, prefix):
|
||||
for dll in get_dependency(root):
|
||||
if dll in dep_dlls:
|
||||
continue
|
||||
full_path = os.path.join(prefix, dll)
|
||||
if os.path.exists(full_path):
|
||||
dep_dlls[dll] = full_path
|
||||
dep_tree_impl(full_path, prefix=prefix)
|
||||
else:
|
||||
dep_dlls[dll] = 'not found'
|
||||
|
||||
dep_tree_impl(root, prefix)
|
||||
return (dep_dlls)
|
||||
|
||||
|
||||
def get_arch(filename):
|
||||
type2arch= {pefile.OPTIONAL_HEADER_MAGIC_PE: 'i686',
|
||||
pefile.OPTIONAL_HEADER_MAGIC_PE_PLUS: 'x86_64'}
|
||||
pe = pefile.PE(filename)
|
||||
try:
|
||||
return type2arch[pe.PE_TYPE]
|
||||
except KeyError:
|
||||
sys.stderr.write('Error: unknown architecture')
|
||||
sys.exit(1)
|
||||
|
||||
if __name__ == '__main__':
|
||||
filename = sys.argv[1]
|
||||
for dll, full_path in dep_tree(filename).items():
|
||||
print(' ' * 7, dll, '=>', full_path)
|
||||
|
24
mingw32.sh
24
mingw32.sh
@ -1,22 +1,2 @@
|
||||
#!/bin/bash
|
||||
|
||||
target=i686-w64-mingw32
|
||||
|
||||
unset CC
|
||||
unset CXX
|
||||
unset CPP
|
||||
unset LD
|
||||
unset LDFLAGS
|
||||
unset CFLAGS
|
||||
unset CXXFLAGS
|
||||
unset PKG_CONFIG_PATH
|
||||
|
||||
# Removed -static from the following
|
||||
export CFLAGS="-static-libgcc"
|
||||
export CXXFLAGS="-static-libgcc -static-libstdc++"
|
||||
export CPPFLAGS="-I$HOME/.local/$target/include -O2"
|
||||
export LDFLAGS=-L$HOME/.local/$target/lib
|
||||
export PKG_CONFIG_LIBDIR=$HOME/.local/$target/lib/pkgconfig
|
||||
export PATH=$HOME/.local/$target/bin:$PATH
|
||||
|
||||
../configure --build=`../config.guess` --host=$target --prefix=$HOME/.local/$target "$@"
|
||||
#!/bin/sh
|
||||
exec "$(dirname "$0")"/mingw-configure.sh i686 "$@"
|
||||
|
24
mingw64.sh
24
mingw64.sh
@ -1,22 +1,2 @@
|
||||
#!/bin/bash
|
||||
|
||||
target=x86_64-w64-mingw32
|
||||
|
||||
unset CC
|
||||
unset CXX
|
||||
unset CPP
|
||||
unset LD
|
||||
unset LDFLAGS
|
||||
unset CFLAGS
|
||||
unset CXXFLAGS
|
||||
unset PKG_CONFIG_PATH
|
||||
|
||||
# Removed -static from the following
|
||||
export CFLAGS="-static-libgcc"
|
||||
export CXXFLAGS="-static-libgcc -static-libstdc++"
|
||||
export CPPFLAGS="-I$HOME/.local/$target/include -O2"
|
||||
export LDFLAGS=-L$HOME/.local/$target/lib
|
||||
export PKG_CONFIG_LIBDIR=$HOME/.local/$target/lib/pkgconfig
|
||||
export PATH=$HOME/.local/$target/bin:$PATH
|
||||
|
||||
../configure --build=`../config.guess` --host=$target --prefix=$HOME/.local/$target "$@"
|
||||
#!/bin/sh
|
||||
exec "$(dirname "$0")"/mingw-configure.sh x86_64 "$@"
|
||||
|
@ -87,17 +87,6 @@ HBSOURCES += $(HB_CORETEXT_sources)
|
||||
HBHEADERS += $(HB_CORETEXT_headers)
|
||||
endif
|
||||
|
||||
if HAVE_UCDN
|
||||
SUBDIRS += hb-ucdn
|
||||
HBCFLAGS += -I$(srcdir)/hb-ucdn
|
||||
HBLIBS += hb-ucdn/libhb-ucdn.la
|
||||
HBSOURCES += $(HB_UCDN_sources)
|
||||
hb-ucdn/libhb-ucdn.la: ucdn
|
||||
ucdn:
|
||||
@$(MAKE) $(AM_MAKEFLAGS) -C hb-ucdn
|
||||
endif
|
||||
DIST_SUBDIRS += hb-ucdn
|
||||
|
||||
|
||||
BUILT_SOURCES += \
|
||||
hb-version.h
|
||||
@ -258,6 +247,7 @@ GENERATORS = \
|
||||
gen-indic-table.py \
|
||||
gen-os2-unicode-ranges.py \
|
||||
gen-tag-table.py \
|
||||
gen-ucd-table.py \
|
||||
gen-use-table.py \
|
||||
gen-vowel-constraints.py \
|
||||
$(NULL)
|
||||
@ -384,7 +374,7 @@ dump_use_data_SOURCES = dump-use-data.cc hb-ot-shape-complex-use-table.cc
|
||||
dump_use_data_CPPFLAGS = $(HBCFLAGS)
|
||||
dump_use_data_LDADD = libharfbuzz.la $(HBLIBS)
|
||||
|
||||
COMPILED_TESTS = test-algs test-iter test-ot-tag test-unicode-ranges
|
||||
COMPILED_TESTS = test-algs test-iter test-meta test-ot-tag test-unicode-ranges
|
||||
COMPILED_TESTS_CPPFLAGS = $(HBCFLAGS) -DMAIN -UNDEBUG
|
||||
COMPILED_TESTS_LDADD = libharfbuzz.la $(HBLIBS)
|
||||
check_PROGRAMS += $(COMPILED_TESTS)
|
||||
@ -398,6 +388,10 @@ test_iter_SOURCES = test-iter.cc hb-static.cc
|
||||
test_iter_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
|
||||
test_iter_LDADD = $(COMPILED_TESTS_LDADD)
|
||||
|
||||
test_meta_SOURCES = test-meta.cc hb-static.cc
|
||||
test_meta_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
|
||||
test_meta_LDADD = $(COMPILED_TESTS_LDADD)
|
||||
|
||||
test_ot_tag_SOURCES = hb-ot-tag.cc
|
||||
test_ot_tag_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
|
||||
test_ot_tag_LDADD = $(COMPILED_TESTS_LDADD)
|
||||
|
@ -31,6 +31,7 @@ HB_BASE_sources = \
|
||||
hb-cff1-interp-cs.hh \
|
||||
hb-cff2-interp-cs.hh \
|
||||
hb-common.cc \
|
||||
hb-config.hh \
|
||||
hb-debug.hh \
|
||||
hb-dispatch.hh \
|
||||
hb-face.cc \
|
||||
@ -147,6 +148,8 @@ HB_BASE_sources = \
|
||||
hb-shaper.hh \
|
||||
hb-static.cc \
|
||||
hb-string-array.hh \
|
||||
hb-ucd-table.hh \
|
||||
hb-ucd.cc \
|
||||
hb-unicode-emoji-table.hh \
|
||||
hb-unicode.cc \
|
||||
hb-unicode.hh \
|
||||
@ -226,9 +229,6 @@ HB_DIRECTWRITE_headers = hb-directwrite.h
|
||||
HB_UNISCRIBE_sources = hb-uniscribe.cc
|
||||
HB_UNISCRIBE_headers = hb-uniscribe.h
|
||||
|
||||
# Additional supplemental sources
|
||||
HB_UCDN_sources = hb-ucdn.cc
|
||||
|
||||
# Sources for libharfbuzz-gobject and libharfbuzz-icu
|
||||
HB_ICU_sources = hb-icu.cc
|
||||
HB_ICU_headers = hb-icu.h
|
||||
@ -244,9 +244,6 @@ HB_SUBSET_sources = \
|
||||
hb-subset-cff1.hh \
|
||||
hb-subset-cff2.cc \
|
||||
hb-subset-cff2.hh \
|
||||
hb-subset-glyf.cc \
|
||||
hb-subset-glyf.hh \
|
||||
hb-subset-glyf.hh \
|
||||
hb-subset-input.cc \
|
||||
hb-subset-input.hh \
|
||||
hb-subset-plan.cc \
|
||||
|
@ -7,7 +7,7 @@ test -z "$srcdir" && srcdir=.
|
||||
test -z "$libs" && libs=.libs
|
||||
stat=0
|
||||
|
||||
IGNORED_SYMBOLS='_fini\|_init\|_fdata\|_ftext\|_fbss\|__bss_start\|__bss_start__\|__bss_end__\|_edata\|_end\|_bss_end__\|__end__\|__gcov_flush\|llvm_.*'
|
||||
IGNORED_SYMBOLS='_fini\|_init\|_fdata\|_ftext\|_fbss\|__bss_start\|__bss_start__\|__bss_end__\|_edata\|_end\|_bss_end__\|__end__\|__gcov_.*\|llvm_.*'
|
||||
|
||||
if which nm 2>/dev/null >/dev/null; then
|
||||
:
|
||||
|
4
src/gen-os2-unicode-ranges.py
Normal file → Executable file
4
src/gen-os2-unicode-ranges.py
Normal file → Executable file
@ -1,8 +1,10 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Generates the code for a sorted unicode range array as used in hb-ot-os2-unicode-ranges.hh
|
||||
# Input is a tab seperated list of unicode ranges from the otspec
|
||||
# (https://docs.microsoft.com/en-us/typography/opentype/spec/os2#ulunicoderange1).
|
||||
# (https://docs.microsoft.com/en-us/typography/opentype/spec/os2#ur).
|
||||
|
||||
from __future__ import print_function, division, absolute_import
|
||||
|
||||
|
123
src/gen-ucd-table.py
Executable file
123
src/gen-ucd-table.py
Executable file
@ -0,0 +1,123 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
from __future__ import print_function, division, absolute_import
|
||||
|
||||
import io, os.path, sys, re
|
||||
|
||||
if len (sys.argv) != 2:
|
||||
print("usage: ./gen-ucd-table ucd.nonunihan.grouped.xml", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
# https://github.com/harfbuzz/packtab
|
||||
import packTab
|
||||
import packTab.ucdxml
|
||||
|
||||
ucdxml = packTab.ucdxml.load_ucdxml(sys.argv[1])
|
||||
ucd = packTab.ucdxml.ucdxml_get_repertoire(ucdxml)
|
||||
|
||||
|
||||
gc = [u['gc'] for u in ucd]
|
||||
ccc = [int(u['ccc']) for u in ucd]
|
||||
bmg = [int(v, 16) - int(u) if v else 0 for u,v in enumerate(u['bmg'] for u in ucd)]
|
||||
#gc_ccc_non0 = set((cat,klass) for cat,klass in zip(gc,ccc) if klass)
|
||||
#gc_bmg_non0 = set((cat,mirr) for cat,mirr in zip(gc, bmg) if mirr)
|
||||
|
||||
sc = [u['sc'] for u in ucd]
|
||||
|
||||
dm = {i:tuple(int(v, 16) for v in u['dm'].split()) for i,u in enumerate(ucd)
|
||||
if u['dm'] != '#' and u['dt'] == 'can' and not (0xAC00 <= i < 0xAC00+11172)}
|
||||
ce = {i for i,u in enumerate(ucd) if u['Comp_Ex'] == 'Y'}
|
||||
|
||||
assert not any(v for v in dm.values() if len(v) not in (1,2))
|
||||
dm1 = sorted(set(v for v in dm.values() if len(v) == 1))
|
||||
dm1_array = ['0x%04Xu' % v for v in dm1]
|
||||
dm1_order = {v:i+1 for i,v in enumerate(dm1)}
|
||||
dm2 = sorted((v, i) for i,v in dm.items() if len(v) == 2)
|
||||
dm2 = [("HB_CODEPOINT_ENCODE3 (0x%04Xu, 0x%04Xu, 0x%04Xu)" %
|
||||
(v+(i if i not in ce and not ccc[i] else 0,)), v)
|
||||
for v,i in dm2]
|
||||
dm2_array = [s for s,v in dm2]
|
||||
l = 1 + len(dm1_array)
|
||||
dm2_order = {v[1]:i+l for i,v in enumerate(dm2)}
|
||||
dm_order = {None: 0}
|
||||
dm_order.update(dm1_order)
|
||||
dm_order.update(dm2_order)
|
||||
|
||||
gc_order = packTab.AutoMapping()
|
||||
for _ in ('Cc', 'Cf', 'Cn', 'Co', 'Cs', 'Ll', 'Lm', 'Lo', 'Lt', 'Lu',
|
||||
'Mc', 'Me', 'Mn', 'Nd', 'Nl', 'No', 'Pc', 'Pd', 'Pe', 'Pf',
|
||||
'Pi', 'Po', 'Ps', 'Sc', 'Sk', 'Sm', 'So', 'Zl', 'Zp', 'Zs',):
|
||||
gc_order[_]
|
||||
|
||||
sc_order = packTab.AutoMapping()
|
||||
sc_array = []
|
||||
sc_re = re.compile(" (HB_SCRIPT_[_A-Z]*).*HB_TAG [(]'(.)','(.)','(.)','(.)'[)]")
|
||||
for line in open('hb-common.h'):
|
||||
m = sc_re.search (line)
|
||||
if not m: continue
|
||||
name = m.group(1)
|
||||
tag = ''.join(m.group(i) for i in range(2, 6))
|
||||
i = sc_order[tag]
|
||||
assert i == len(sc_array)
|
||||
sc_array.append(name)
|
||||
|
||||
# TODO Currently if gc_order or sc_order do not capture all values, we get in
|
||||
# trouble because they silently add new values. We should be able to "freeze"
|
||||
# them, or just do the mapping ourselves.
|
||||
|
||||
DEFAULT = 1
|
||||
COMPACT = 3
|
||||
|
||||
|
||||
print("/* == Start of generated table == */")
|
||||
print("/*")
|
||||
print(" * The following table is generated by running:")
|
||||
print(" *")
|
||||
print(" * ./gen-ucd-table.py ucd.nonunihan.grouped.xml")
|
||||
print(" *")
|
||||
print(" * on file with this description:", ucdxml.description)
|
||||
print(" */")
|
||||
print()
|
||||
print("#ifndef HB_UCD_TABLE_HH")
|
||||
print("#define HB_UCD_TABLE_HH")
|
||||
print()
|
||||
|
||||
print()
|
||||
print('#include "hb.hh"')
|
||||
print()
|
||||
|
||||
code = packTab.Code('_hb_ucd')
|
||||
sc_array, _ = code.addArray('hb_script_t', 'sc_map', sc_array)
|
||||
dm1_array, _ = code.addArray('hb_codepoint_t', 'dm1_map', dm1_array)
|
||||
dm2_array, _ = code.addArray('uint64_t', 'dm2_map', dm2_array)
|
||||
code.print_c(linkage='static inline')
|
||||
|
||||
for compression in (DEFAULT, COMPACT):
|
||||
print()
|
||||
if compression == DEFAULT:
|
||||
print('#ifndef HB_OPTIMIZE_SIZE')
|
||||
else:
|
||||
print('#else')
|
||||
print()
|
||||
|
||||
code = packTab.Code('_hb_ucd')
|
||||
|
||||
packTab.pack_table(gc, 'Cn', mapping=gc_order, compression=compression).genCode(code, 'gc')
|
||||
packTab.pack_table(ccc, 0, compression=compression).genCode(code, 'ccc')
|
||||
packTab.pack_table(bmg, 0, compression=compression).genCode(code, 'bmg')
|
||||
packTab.pack_table(sc, 'Zzzz', mapping=sc_order, compression=compression).genCode(code, 'sc')
|
||||
packTab.pack_table(dm, None, mapping=dm_order, compression=compression).genCode(code, 'dm')
|
||||
|
||||
code.print_c(linkage='static inline')
|
||||
|
||||
|
||||
if compression != DEFAULT:
|
||||
print()
|
||||
print('#endif')
|
||||
print()
|
||||
|
||||
print()
|
||||
print("#endif /* HB_UCD_TABLE_HH */")
|
||||
print()
|
||||
print("/* == End of generated table == */")
|
@ -47,6 +47,14 @@ defaults = ('Other', 'Not_Applicable', 'Cn', 'No_Block')
|
||||
|
||||
# TODO Characters that are not in Unicode Indic files, but used in USE
|
||||
data[0][0x034F] = defaults[0]
|
||||
data[0][0x1B61] = defaults[0]
|
||||
data[0][0x1B63] = defaults[0]
|
||||
data[0][0x1B64] = defaults[0]
|
||||
data[0][0x1B65] = defaults[0]
|
||||
data[0][0x1B66] = defaults[0]
|
||||
data[0][0x1B67] = defaults[0]
|
||||
data[0][0x1B69] = defaults[0]
|
||||
data[0][0x1B6A] = defaults[0]
|
||||
data[0][0x2060] = defaults[0]
|
||||
# TODO https://github.com/harfbuzz/harfbuzz/pull/1685
|
||||
data[0][0x1B5B] = 'Consonant_Placeholder'
|
||||
@ -54,7 +62,7 @@ data[0][0x1B5C] = 'Consonant_Placeholder'
|
||||
data[0][0x1B5F] = 'Consonant_Placeholder'
|
||||
data[0][0x1B62] = 'Consonant_Placeholder'
|
||||
data[0][0x1B68] = 'Consonant_Placeholder'
|
||||
# TODO https://github.com/roozbehp/unicode-data/issues/9
|
||||
# TODO https://github.com/harfbuzz/harfbuzz/issues/1035
|
||||
data[0][0x11C44] = 'Consonant_Placeholder'
|
||||
data[0][0x11C45] = 'Consonant_Placeholder'
|
||||
# TODO https://github.com/harfbuzz/harfbuzz/pull/1399
|
||||
@ -189,15 +197,15 @@ def is_BASE_OTHER(U, UISC, UGC):
|
||||
def is_CGJ(U, UISC, UGC):
|
||||
return U == 0x034F
|
||||
def is_CONS_FINAL(U, UISC, UGC):
|
||||
# Consonant_Initial_Postfixed is new in Unicode 11; not in the spec.
|
||||
return ((UISC == Consonant_Final and UGC != Lo) or
|
||||
UISC == Consonant_Initial_Postfixed or
|
||||
UISC == Consonant_Succeeding_Repha)
|
||||
def is_CONS_FINAL_MOD(U, UISC, UGC):
|
||||
#SPEC-DRAFT return UISC in [Consonant_Final_Modifier, Syllable_Modifier]
|
||||
return UISC == Syllable_Modifier
|
||||
def is_CONS_MED(U, UISC, UGC):
|
||||
return UISC == Consonant_Medial and UGC != Lo
|
||||
# Consonant_Initial_Postfixed is new in Unicode 11; not in the spec.
|
||||
return (UISC == Consonant_Medial and UGC != Lo or
|
||||
UISC == Consonant_Initial_Postfixed)
|
||||
def is_CONS_MOD(U, UISC, UGC):
|
||||
return UISC in [Nukta, Gemination_Mark, Consonant_Killer]
|
||||
def is_CONS_SUB(U, UISC, UGC):
|
||||
@ -206,7 +214,9 @@ def is_CONS_SUB(U, UISC, UGC):
|
||||
def is_CONS_WITH_STACKER(U, UISC, UGC):
|
||||
return UISC == Consonant_With_Stacker
|
||||
def is_HALANT(U, UISC, UGC):
|
||||
return UISC in [Virama, Invisible_Stacker] and not is_HALANT_OR_VOWEL_MODIFIER(U, UISC, UGC)
|
||||
return (UISC in [Virama, Invisible_Stacker]
|
||||
and not is_HALANT_OR_VOWEL_MODIFIER(U, UISC, UGC)
|
||||
and not is_SAKOT(U, UISC, UGC))
|
||||
def is_HALANT_OR_VOWEL_MODIFIER(U, UISC, UGC):
|
||||
# https://github.com/harfbuzz/harfbuzz/issues/1102
|
||||
# https://github.com/harfbuzz/harfbuzz/issues/1379
|
||||
@ -222,6 +232,7 @@ def is_Word_Joiner(U, UISC, UGC):
|
||||
def is_OTHER(U, UISC, UGC):
|
||||
#SPEC-OUTDATED return UGC == Zs # or any other SCRIPT_COMMON characters
|
||||
return (UISC == Other
|
||||
and not is_SYM(U, UISC, UGC)
|
||||
and not is_SYM_MOD(U, UISC, UGC)
|
||||
and not is_CGJ(U, UISC, UGC)
|
||||
and not is_Word_Joiner(U, UISC, UGC)
|
||||
@ -231,6 +242,8 @@ def is_Reserved(U, UISC, UGC):
|
||||
return UGC == 'Cn'
|
||||
def is_REPHA(U, UISC, UGC):
|
||||
return UISC in [Consonant_Preceding_Repha, Consonant_Prefixed]
|
||||
def is_SAKOT(U, UISC, UGC):
|
||||
return U == 0x1A60
|
||||
def is_SYM(U, UISC, UGC):
|
||||
if U == 0x25CC: return False #SPEC-DRAFT
|
||||
#SPEC-DRAFT return UGC in [So, Sc] or UISC == Symbol_Letter
|
||||
@ -240,11 +253,11 @@ def is_SYM_MOD(U, UISC, UGC):
|
||||
def is_VARIATION_SELECTOR(U, UISC, UGC):
|
||||
return 0xFE00 <= U <= 0xFE0F
|
||||
def is_VOWEL(U, UISC, UGC):
|
||||
# https://github.com/roozbehp/unicode-data/issues/6
|
||||
# https://github.com/harfbuzz/harfbuzz/issues/376
|
||||
return (UISC == Pure_Killer or
|
||||
(UGC != Lo and UISC in [Vowel, Vowel_Dependent] and U not in [0xAA29]))
|
||||
def is_VOWEL_MOD(U, UISC, UGC):
|
||||
# https://github.com/roozbehp/unicode-data/issues/6
|
||||
# https://github.com/harfbuzz/harfbuzz/issues/376
|
||||
return (UISC in [Tone_Mark, Cantillation_Mark, Register_Shifter, Visarga] or
|
||||
(UGC != Lo and (UISC == Bindu or U in [0xAA29])))
|
||||
|
||||
@ -270,6 +283,7 @@ use_mapping = {
|
||||
'Rsv': is_Reserved,
|
||||
'R': is_REPHA,
|
||||
'S': is_SYM,
|
||||
'Sk': is_SAKOT,
|
||||
'SM': is_SYM_MOD,
|
||||
'VS': is_VARIATION_SELECTOR,
|
||||
'V': is_VOWEL,
|
||||
@ -311,7 +325,11 @@ use_positions = {
|
||||
'H': None,
|
||||
'HVM': None,
|
||||
'B': None,
|
||||
'FM': None,
|
||||
'FM': {
|
||||
'Abv': [Top],
|
||||
'Blw': [Bottom],
|
||||
'Pst': [Not_Applicable],
|
||||
},
|
||||
'SUB': None,
|
||||
}
|
||||
|
||||
@ -350,15 +368,9 @@ def map_to_use(data):
|
||||
# the nasalization marks, maybe only for U+1CE9..U+1CF1.
|
||||
if U == 0x1CED: UISC = Tone_Mark
|
||||
|
||||
# TODO: https://github.com/harfbuzz/harfbuzz/issues/525
|
||||
if U == 0x1A7F: UISC = Consonant_Final
|
||||
|
||||
# TODO: https://github.com/harfbuzz/harfbuzz/issues/1105
|
||||
if U == 0x11134: UISC = Gemination_Mark
|
||||
|
||||
# TODO: https://github.com/harfbuzz/harfbuzz/pull/1399
|
||||
if U == 0x111C9: UISC = Consonant_Final
|
||||
|
||||
values = [k for k,v in items if v(U,UISC,UGC)]
|
||||
assert len(values) == 1, "%s %s %s %s" % (hex(U), UISC, UGC, values)
|
||||
USE = values[0]
|
||||
|
@ -180,6 +180,9 @@ print ('_hb_preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan HB
|
||||
print ('\t\t\t\t hb_buffer_t *buffer,')
|
||||
print ('\t\t\t\t hb_font_t *font HB_UNUSED)')
|
||||
print ('{')
|
||||
print ('#if defined(HB_NO_OT_SHAPE_COMPLEX_VOWEL_CONSTRAINTS)')
|
||||
print (' return;')
|
||||
print ('#endif')
|
||||
print (' if (buffer->flags & HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE)')
|
||||
print (' return;')
|
||||
print ()
|
||||
|
@ -83,7 +83,7 @@ struct ankr
|
||||
protected:
|
||||
HBUINT16 version; /* Version number (set to zero) */
|
||||
HBUINT16 flags; /* Flags (currently unused; set to zero) */
|
||||
LOffsetTo<Lookup<NNOffsetTo<GlyphAnchors> > >
|
||||
LOffsetTo<Lookup<NNOffsetTo<GlyphAnchors>>>
|
||||
lookupTable; /* Offset to the table's lookup table */
|
||||
LNNOffsetTo<HBUINT8>
|
||||
anchorData; /* Offset to the glyph data table */
|
||||
|
@ -125,7 +125,7 @@ struct LookupFormat2
|
||||
|
||||
protected:
|
||||
HBUINT16 format; /* Format identifier--format = 2 */
|
||||
VarSizedBinSearchArrayOf<LookupSegmentSingle<T> >
|
||||
VarSizedBinSearchArrayOf<LookupSegmentSingle<T>>
|
||||
segments; /* The actual segments. These must already be sorted,
|
||||
* according to the first word in each one (the last
|
||||
* glyph in each segment). */
|
||||
@ -154,7 +154,7 @@ struct LookupSegmentArray
|
||||
valuesZ.sanitize (c, base, last - first + 1));
|
||||
}
|
||||
template <typename ...Ts>
|
||||
bool sanitize (hb_sanitize_context_t *c, const void *base, Ts &&...ds) const
|
||||
bool sanitize (hb_sanitize_context_t *c, const void *base, Ts&&... ds) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (c->check_struct (this) &&
|
||||
@ -164,7 +164,7 @@ struct LookupSegmentArray
|
||||
|
||||
GlyphID last; /* Last GlyphID in this segment */
|
||||
GlyphID first; /* First GlyphID in this segment */
|
||||
NNOffsetTo<UnsizedArrayOf<T> >
|
||||
NNOffsetTo<UnsizedArrayOf<T>>
|
||||
valuesZ; /* A 16-bit offset from the start of
|
||||
* the table to the data. */
|
||||
public:
|
||||
@ -196,7 +196,7 @@ struct LookupFormat4
|
||||
|
||||
protected:
|
||||
HBUINT16 format; /* Format identifier--format = 4 */
|
||||
VarSizedBinSearchArrayOf<LookupSegmentArray<T> >
|
||||
VarSizedBinSearchArrayOf<LookupSegmentArray<T>>
|
||||
segments; /* The actual segments. These must already be sorted,
|
||||
* according to the first word in each one (the last
|
||||
* glyph in each segment). */
|
||||
@ -253,7 +253,7 @@ struct LookupFormat6
|
||||
|
||||
protected:
|
||||
HBUINT16 format; /* Format identifier--format = 6 */
|
||||
VarSizedBinSearchArrayOf<LookupSingle<T> >
|
||||
VarSizedBinSearchArrayOf<LookupSingle<T>>
|
||||
entries; /* The actual entries, sorted by glyph index. */
|
||||
public:
|
||||
DEFINE_SIZE_ARRAY (8, entries);
|
||||
@ -419,7 +419,7 @@ struct Lookup
|
||||
/* Ugly hand-coded null objects for template Lookup<> :(. */
|
||||
extern HB_INTERNAL const unsigned char _hb_Null_AAT_Lookup[2];
|
||||
template <typename T>
|
||||
struct Null<AAT::Lookup<T> > {
|
||||
struct Null<AAT::Lookup<T>> {
|
||||
static AAT::Lookup<T> const & get_null ()
|
||||
{ return *reinterpret_cast<const AAT::Lookup<T> *> (_hb_Null_AAT_Lookup); }
|
||||
};
|
||||
@ -510,7 +510,7 @@ struct StateTable
|
||||
const Entry<Extra> &get_entry (int state, unsigned int klass) const
|
||||
{
|
||||
if (unlikely (klass >= nClasses))
|
||||
klass = StateTable<Types, Entry<Extra> >::CLASS_OUT_OF_BOUNDS;
|
||||
klass = StateTable<Types, Entry<Extra>>::CLASS_OUT_OF_BOUNDS;
|
||||
|
||||
const HBUSHORT *states = (this+stateArrayTable).arrayZ;
|
||||
const Entry<Extra> *entries = (this+entryTable).arrayZ;
|
||||
@ -576,7 +576,7 @@ struct StateTable
|
||||
if (unlikely (stop > states))
|
||||
return_trace (false);
|
||||
for (const HBUSHORT *p = states; stop < p; p--)
|
||||
num_entries = MAX<unsigned int> (num_entries, *(p - 1) + 1);
|
||||
num_entries = hb_max (num_entries, *(p - 1) + 1);
|
||||
state_neg = min_state;
|
||||
}
|
||||
}
|
||||
@ -597,7 +597,7 @@ struct StateTable
|
||||
if (unlikely (stop < states))
|
||||
return_trace (false);
|
||||
for (const HBUSHORT *p = &states[state_pos * num_classes]; p < stop; p++)
|
||||
num_entries = MAX<unsigned int> (num_entries, *p + 1);
|
||||
num_entries = hb_max (num_entries, *p + 1);
|
||||
state_pos = max_state + 1;
|
||||
}
|
||||
}
|
||||
@ -611,8 +611,8 @@ struct StateTable
|
||||
for (const Entry<Extra> *p = &entries[entry]; p < stop; p++)
|
||||
{
|
||||
int newState = new_state (p->newState);
|
||||
min_state = MIN (min_state, newState);
|
||||
max_state = MAX (max_state, newState);
|
||||
min_state = hb_min (min_state, newState);
|
||||
max_state = hb_max (max_state, newState);
|
||||
}
|
||||
entry = num_entries;
|
||||
}
|
||||
@ -631,7 +631,7 @@ struct StateTable
|
||||
classTable; /* Offset to the class table. */
|
||||
NNOffsetTo<UnsizedArrayOf<HBUSHORT>, HBUINT>
|
||||
stateArrayTable;/* Offset to the state array. */
|
||||
NNOffsetTo<UnsizedArrayOf<Entry<Extra> >, HBUINT>
|
||||
NNOffsetTo<UnsizedArrayOf<Entry<Extra>>, HBUINT>
|
||||
entryTable; /* Offset to the entry array. */
|
||||
|
||||
public:
|
||||
|
@ -165,7 +165,7 @@ struct feat
|
||||
unsigned int feature_count = featureNameCount;
|
||||
if (count && *count)
|
||||
{
|
||||
unsigned int len = MIN (feature_count - start_offset, *count);
|
||||
unsigned int len = hb_min (feature_count - start_offset, *count);
|
||||
for (unsigned int i = 0; i < len; i++)
|
||||
features[i] = namesZ[i + start_offset].get_feature_type ();
|
||||
*count = len;
|
||||
|
@ -309,7 +309,7 @@ struct WidthDeltaPair
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (24);
|
||||
};
|
||||
|
||||
|
||||
typedef OT::LArrayOf<WidthDeltaPair> WidthDeltaCluster;
|
||||
|
||||
struct JustificationCategory
|
||||
@ -371,7 +371,7 @@ struct JustificationHeader
|
||||
* of postcompensation subtable (set to zero if none).
|
||||
*
|
||||
* The postcompensation subtable, if present in the font. */
|
||||
Lookup<OffsetTo<WidthDeltaCluster> >
|
||||
Lookup<OffsetTo<WidthDeltaCluster>>
|
||||
lookupTable; /* Lookup table associating glyphs with width delta
|
||||
* clusters. See the description of Width Delta Clusters
|
||||
* table for details on how to interpret the lookup values. */
|
||||
|
@ -251,7 +251,7 @@ struct KerxSubTableFormat1
|
||||
|
||||
if (Format1EntryT::performAction (entry) && depth)
|
||||
{
|
||||
unsigned int tuple_count = MAX (1u, table->header.tuple_count ());
|
||||
unsigned int tuple_count = hb_max (1u, table->header.tuple_count ());
|
||||
|
||||
unsigned int kern_idx = Format1EntryT::kernActionIndex (entry);
|
||||
kern_idx = Types::byteOffsetToIndex (kern_idx, &table->machine, kernAction.arrayZ);
|
||||
@ -712,18 +712,18 @@ struct KerxSubTableFormat6
|
||||
{
|
||||
struct Long
|
||||
{
|
||||
LNNOffsetTo<Lookup<HBUINT32> > rowIndexTable;
|
||||
LNNOffsetTo<Lookup<HBUINT32> > columnIndexTable;
|
||||
LNNOffsetTo<UnsizedArrayOf<FWORD32> > array;
|
||||
LNNOffsetTo<Lookup<HBUINT32>> rowIndexTable;
|
||||
LNNOffsetTo<Lookup<HBUINT32>> columnIndexTable;
|
||||
LNNOffsetTo<UnsizedArrayOf<FWORD32>> array;
|
||||
} l;
|
||||
struct Short
|
||||
{
|
||||
LNNOffsetTo<Lookup<HBUINT16> > rowIndexTable;
|
||||
LNNOffsetTo<Lookup<HBUINT16> > columnIndexTable;
|
||||
LNNOffsetTo<UnsizedArrayOf<FWORD> > array;
|
||||
LNNOffsetTo<Lookup<HBUINT16>> rowIndexTable;
|
||||
LNNOffsetTo<Lookup<HBUINT16>> columnIndexTable;
|
||||
LNNOffsetTo<UnsizedArrayOf<FWORD>> array;
|
||||
} s;
|
||||
} u;
|
||||
LNNOffsetTo<UnsizedArrayOf<FWORD> > vector;
|
||||
LNNOffsetTo<UnsizedArrayOf<FWORD>> vector;
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (KernSubTableHeader::static_size + 24);
|
||||
};
|
||||
@ -771,17 +771,17 @@ struct KerxSubTable
|
||||
unsigned int get_size () const { return u.header.length; }
|
||||
unsigned int get_type () const { return u.header.coverage & u.header.SubtableType; }
|
||||
|
||||
template <typename context_t>
|
||||
typename context_t::return_t dispatch (context_t *c) const
|
||||
template <typename context_t, typename ...Ts>
|
||||
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
|
||||
{
|
||||
unsigned int subtable_type = get_type ();
|
||||
TRACE_DISPATCH (this, subtable_type);
|
||||
switch (subtable_type) {
|
||||
case 0: return_trace (c->dispatch (u.format0));
|
||||
case 1: return_trace (c->dispatch (u.format1));
|
||||
case 2: return_trace (c->dispatch (u.format2));
|
||||
case 4: return_trace (c->dispatch (u.format4));
|
||||
case 6: return_trace (c->dispatch (u.format6));
|
||||
case 0: return_trace (c->dispatch (u.format0, hb_forward<Ts> (ds)...));
|
||||
case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
|
||||
case 2: return_trace (c->dispatch (u.format2, hb_forward<Ts> (ds)...));
|
||||
case 4: return_trace (c->dispatch (u.format4, hb_forward<Ts> (ds)...));
|
||||
case 6: return_trace (c->dispatch (u.format6, hb_forward<Ts> (ds)...));
|
||||
default: return_trace (c->default_return_value ());
|
||||
}
|
||||
}
|
||||
|
@ -81,7 +81,7 @@ struct lcar
|
||||
protected:
|
||||
FixedVersion<>version; /* Version number of the ligature caret table */
|
||||
HBUINT16 format; /* Format of the ligature caret table. */
|
||||
Lookup<OffsetTo<LigCaretClassEntry> >
|
||||
Lookup<OffsetTo<LigCaretClassEntry>>
|
||||
lookup; /* data Lookup table associating glyphs */
|
||||
|
||||
public:
|
||||
|
@ -88,7 +88,7 @@ struct RearrangementSubtable
|
||||
start = buffer->idx;
|
||||
|
||||
if (flags & MarkLast)
|
||||
end = MIN (buffer->idx + 1, buffer->len);
|
||||
end = hb_min (buffer->idx + 1, buffer->len);
|
||||
|
||||
if ((flags & Verb) && start < end)
|
||||
{
|
||||
@ -117,14 +117,14 @@ struct RearrangementSubtable
|
||||
};
|
||||
|
||||
unsigned int m = map[flags & Verb];
|
||||
unsigned int l = MIN<unsigned int> (2, m >> 4);
|
||||
unsigned int r = MIN<unsigned int> (2, m & 0x0F);
|
||||
unsigned int l = hb_min (2u, m >> 4);
|
||||
unsigned int r = hb_min (2u, m & 0x0F);
|
||||
bool reverse_l = 3 == (m >> 4);
|
||||
bool reverse_r = 3 == (m & 0x0F);
|
||||
|
||||
if (end - start >= l + r)
|
||||
{
|
||||
buffer->merge_clusters (start, MIN (buffer->idx + 1, buffer->len));
|
||||
buffer->merge_clusters (start, hb_min (buffer->idx + 1, buffer->len));
|
||||
buffer->merge_clusters (start, end);
|
||||
|
||||
hb_glyph_info_t *info = buffer->info;
|
||||
@ -261,13 +261,13 @@ struct ContextualSubtable
|
||||
}
|
||||
if (replacement)
|
||||
{
|
||||
buffer->unsafe_to_break (mark, MIN (buffer->idx + 1, buffer->len));
|
||||
buffer->unsafe_to_break (mark, hb_min (buffer->idx + 1, buffer->len));
|
||||
buffer->info[mark].codepoint = *replacement;
|
||||
ret = true;
|
||||
}
|
||||
|
||||
replacement = nullptr;
|
||||
unsigned int idx = MIN (buffer->idx, buffer->len - 1);
|
||||
unsigned int idx = hb_min (buffer->idx, buffer->len - 1);
|
||||
if (Types::extended)
|
||||
{
|
||||
if (entry.data.currentIndex != 0xFFFF)
|
||||
@ -337,9 +337,9 @@ struct ContextualSubtable
|
||||
const EntryData &data = entries[i].data;
|
||||
|
||||
if (data.markIndex != 0xFFFF)
|
||||
num_lookups = MAX<unsigned int> (num_lookups, 1 + data.markIndex);
|
||||
num_lookups = hb_max (num_lookups, 1 + data.markIndex);
|
||||
if (data.currentIndex != 0xFFFF)
|
||||
num_lookups = MAX<unsigned int> (num_lookups, 1 + data.currentIndex);
|
||||
num_lookups = hb_max (num_lookups, 1 + data.currentIndex);
|
||||
}
|
||||
|
||||
return_trace (substitutionTables.sanitize (c, this, num_lookups));
|
||||
@ -744,7 +744,7 @@ struct InsertionSubtable
|
||||
|
||||
buffer->move_to (end + count);
|
||||
|
||||
buffer->unsafe_to_break_from_outbuffer (mark, MIN (buffer->idx + 1, buffer->len));
|
||||
buffer->unsafe_to_break_from_outbuffer (mark, hb_min (buffer->idx + 1, buffer->len));
|
||||
}
|
||||
|
||||
if (flags & SetMark)
|
||||
@ -883,17 +883,17 @@ struct ChainSubtable
|
||||
Insertion = 5
|
||||
};
|
||||
|
||||
template <typename context_t>
|
||||
typename context_t::return_t dispatch (context_t *c) const
|
||||
template <typename context_t, typename ...Ts>
|
||||
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
|
||||
{
|
||||
unsigned int subtable_type = get_type ();
|
||||
TRACE_DISPATCH (this, subtable_type);
|
||||
switch (subtable_type) {
|
||||
case Rearrangement: return_trace (c->dispatch (u.rearrangement));
|
||||
case Contextual: return_trace (c->dispatch (u.contextual));
|
||||
case Ligature: return_trace (c->dispatch (u.ligature));
|
||||
case Noncontextual: return_trace (c->dispatch (u.noncontextual));
|
||||
case Insertion: return_trace (c->dispatch (u.insertion));
|
||||
case Rearrangement: return_trace (c->dispatch (u.rearrangement, hb_forward<Ts> (ds)...));
|
||||
case Contextual: return_trace (c->dispatch (u.contextual, hb_forward<Ts> (ds)...));
|
||||
case Ligature: return_trace (c->dispatch (u.ligature, hb_forward<Ts> (ds)...));
|
||||
case Noncontextual: return_trace (c->dispatch (u.noncontextual, hb_forward<Ts> (ds)...));
|
||||
case Insertion: return_trace (c->dispatch (u.insertion, hb_forward<Ts> (ds)...));
|
||||
default: return_trace (c->default_return_value ());
|
||||
}
|
||||
}
|
||||
@ -969,7 +969,7 @@ struct Chain
|
||||
void apply (hb_aat_apply_context_t *c,
|
||||
hb_mask_t flags) const
|
||||
{
|
||||
const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types> > (featureZ.as_array (featureCount));
|
||||
const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types>> (featureZ.as_array (featureCount));
|
||||
unsigned int count = subtableCount;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
@ -1031,7 +1031,7 @@ struct Chain
|
||||
if (unlikely (!c->buffer->successful)) return;
|
||||
|
||||
skip:
|
||||
subtable = &StructAfter<ChainSubtable<Types> > (*subtable);
|
||||
subtable = &StructAfter<ChainSubtable<Types>> (*subtable);
|
||||
c->set_lookup_index (c->lookup_index + 1);
|
||||
}
|
||||
}
|
||||
@ -1049,13 +1049,13 @@ struct Chain
|
||||
if (!c->check_array (featureZ.arrayZ, featureCount))
|
||||
return_trace (false);
|
||||
|
||||
const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types> > (featureZ.as_array (featureCount));
|
||||
const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types>> (featureZ.as_array (featureCount));
|
||||
unsigned int count = subtableCount;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
if (!subtable->sanitize (c))
|
||||
return_trace (false);
|
||||
subtable = &StructAfter<ChainSubtable<Types> > (*subtable);
|
||||
subtable = &StructAfter<ChainSubtable<Types>> (*subtable);
|
||||
}
|
||||
|
||||
return_trace (true);
|
||||
@ -1095,7 +1095,7 @@ struct mortmorx
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
map->chain_flags.push (chain->compile_flags (mapper));
|
||||
chain = &StructAfter<Chain<Types> > (*chain);
|
||||
chain = &StructAfter<Chain<Types>> (*chain);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1109,7 +1109,7 @@ struct mortmorx
|
||||
{
|
||||
chain->apply (c, c->plan->aat_map.chain_flags[i]);
|
||||
if (unlikely (!c->buffer->successful)) return;
|
||||
chain = &StructAfter<Chain<Types> > (*chain);
|
||||
chain = &StructAfter<Chain<Types>> (*chain);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1125,7 +1125,7 @@ struct mortmorx
|
||||
{
|
||||
if (!chain->sanitize (c, version))
|
||||
return_trace (false);
|
||||
chain = &StructAfter<Chain<Types> > (*chain);
|
||||
chain = &StructAfter<Chain<Types>> (*chain);
|
||||
}
|
||||
|
||||
return_trace (true);
|
||||
|
@ -66,7 +66,7 @@ struct TrackTableEntry
|
||||
NameID trackNameID; /* The 'name' table index for this track.
|
||||
* (a short word or phrase like "loose"
|
||||
* or "very tight") */
|
||||
NNOffsetTo<UnsizedArrayOf<FWORD> >
|
||||
NNOffsetTo<UnsizedArrayOf<FWORD>>
|
||||
valuesZ; /* Offset from start of tracking table to
|
||||
* per-size tracking values for this track. */
|
||||
|
||||
@ -133,8 +133,8 @@ struct TrackData
|
||||
if (size_table[size_index].to_float () >= csspx)
|
||||
break;
|
||||
|
||||
return round (interpolate_at (size_index ? size_index - 1 : 0, csspx,
|
||||
*trackTableEntry, base));
|
||||
return roundf (interpolate_at (size_index ? size_index - 1 : 0, csspx,
|
||||
*trackTableEntry, base));
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c, const void *base) const
|
||||
|
@ -135,11 +135,15 @@ static const hb_aat_feature_mapping_t feature_mappings[] =
|
||||
const hb_aat_feature_mapping_t *
|
||||
hb_aat_layout_find_feature_mapping (hb_tag_t tag)
|
||||
{
|
||||
return (const hb_aat_feature_mapping_t *) bsearch (&tag,
|
||||
feature_mappings,
|
||||
ARRAY_LENGTH (feature_mappings),
|
||||
sizeof (feature_mappings[0]),
|
||||
hb_aat_feature_mapping_t::cmp);
|
||||
#ifdef HB_NO_SHAPE_AAT
|
||||
return nullptr;
|
||||
#endif
|
||||
|
||||
return (const hb_aat_feature_mapping_t *) hb_bsearch (&tag,
|
||||
feature_mappings,
|
||||
ARRAY_LENGTH (feature_mappings),
|
||||
sizeof (feature_mappings[0]),
|
||||
hb_aat_feature_mapping_t::cmp);
|
||||
}
|
||||
|
||||
|
||||
@ -147,6 +151,8 @@ hb_aat_layout_find_feature_mapping (hb_tag_t tag)
|
||||
* hb_aat_apply_context_t
|
||||
*/
|
||||
|
||||
/* Note: This context is used for kerning, even without AAT. */
|
||||
|
||||
AAT::hb_aat_apply_context_t::hb_aat_apply_context_t (const hb_ot_shape_plan_t *plan_,
|
||||
hb_font_t *font_,
|
||||
hb_buffer_t *buffer_,
|
||||
@ -183,6 +189,10 @@ void
|
||||
hb_aat_layout_compile_map (const hb_aat_map_builder_t *mapper,
|
||||
hb_aat_map_t *map)
|
||||
{
|
||||
#ifdef HB_NO_SHAPE_AAT
|
||||
return;
|
||||
#endif
|
||||
|
||||
const AAT::morx& morx = *mapper->face->table.morx;
|
||||
if (morx.has_data ())
|
||||
{
|
||||
@ -209,6 +219,10 @@ hb_aat_layout_compile_map (const hb_aat_map_builder_t *mapper,
|
||||
hb_bool_t
|
||||
hb_aat_layout_has_substitution (hb_face_t *face)
|
||||
{
|
||||
#ifdef HB_NO_SHAPE_AAT
|
||||
return false;
|
||||
#endif
|
||||
|
||||
return face->table.morx->has_data () ||
|
||||
face->table.mort->has_data ();
|
||||
}
|
||||
@ -218,6 +232,10 @@ hb_aat_layout_substitute (const hb_ot_shape_plan_t *plan,
|
||||
hb_font_t *font,
|
||||
hb_buffer_t *buffer)
|
||||
{
|
||||
#ifdef HB_NO_SHAPE_AAT
|
||||
return;
|
||||
#endif
|
||||
|
||||
hb_blob_t *morx_blob = font->face->table.morx.get_blob ();
|
||||
const AAT::morx& morx = *morx_blob->as<AAT::morx> ();
|
||||
if (morx.has_data ())
|
||||
@ -240,6 +258,10 @@ hb_aat_layout_substitute (const hb_ot_shape_plan_t *plan,
|
||||
void
|
||||
hb_aat_layout_zero_width_deleted_glyphs (hb_buffer_t *buffer)
|
||||
{
|
||||
#ifdef HB_NO_SHAPE_AAT
|
||||
return;
|
||||
#endif
|
||||
|
||||
unsigned int count = buffer->len;
|
||||
hb_glyph_info_t *info = buffer->info;
|
||||
hb_glyph_position_t *pos = buffer->pos;
|
||||
@ -257,6 +279,10 @@ is_deleted_glyph (const hb_glyph_info_t *info)
|
||||
void
|
||||
hb_aat_layout_remove_deleted_glyphs (hb_buffer_t *buffer)
|
||||
{
|
||||
#ifdef HB_NO_SHAPE_AAT
|
||||
return;
|
||||
#endif
|
||||
|
||||
hb_ot_layout_delete_glyphs_inplace (buffer, is_deleted_glyph);
|
||||
}
|
||||
|
||||
@ -270,6 +296,10 @@ hb_aat_layout_remove_deleted_glyphs (hb_buffer_t *buffer)
|
||||
hb_bool_t
|
||||
hb_aat_layout_has_positioning (hb_face_t *face)
|
||||
{
|
||||
#ifdef HB_NO_SHAPE_AAT
|
||||
return false;
|
||||
#endif
|
||||
|
||||
return face->table.kerx->has_data ();
|
||||
}
|
||||
|
||||
@ -278,6 +308,10 @@ hb_aat_layout_position (const hb_ot_shape_plan_t *plan,
|
||||
hb_font_t *font,
|
||||
hb_buffer_t *buffer)
|
||||
{
|
||||
#ifdef HB_NO_SHAPE_AAT
|
||||
return;
|
||||
#endif
|
||||
|
||||
hb_blob_t *kerx_blob = font->face->table.kerx.get_blob ();
|
||||
const AAT::kerx& kerx = *kerx_blob->as<AAT::kerx> ();
|
||||
|
||||
@ -297,6 +331,10 @@ hb_aat_layout_position (const hb_ot_shape_plan_t *plan,
|
||||
hb_bool_t
|
||||
hb_aat_layout_has_tracking (hb_face_t *face)
|
||||
{
|
||||
#ifdef HB_NO_SHAPE_AAT
|
||||
return false;
|
||||
#endif
|
||||
|
||||
return face->table.trak->has_data ();
|
||||
}
|
||||
|
||||
@ -305,6 +343,10 @@ hb_aat_layout_track (const hb_ot_shape_plan_t *plan,
|
||||
hb_font_t *font,
|
||||
hb_buffer_t *buffer)
|
||||
{
|
||||
#ifdef HB_NO_SHAPE_AAT
|
||||
return;
|
||||
#endif
|
||||
|
||||
const AAT::trak& trak = *font->face->table.trak;
|
||||
|
||||
AAT::hb_aat_apply_context_t c (plan, font, buffer);
|
||||
@ -328,6 +370,12 @@ hb_aat_layout_get_feature_types (hb_face_t *face,
|
||||
unsigned int *feature_count, /* IN/OUT. May be NULL. */
|
||||
hb_aat_layout_feature_type_t *features /* OUT. May be NULL. */)
|
||||
{
|
||||
#ifdef HB_NO_SHAPE_AAT
|
||||
if (feature_count)
|
||||
*feature_count = 0;
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
return face->table.feat->get_feature_types (start_offset, feature_count, features);
|
||||
}
|
||||
|
||||
@ -344,6 +392,10 @@ hb_ot_name_id_t
|
||||
hb_aat_layout_feature_type_get_name_id (hb_face_t *face,
|
||||
hb_aat_layout_feature_type_t feature_type)
|
||||
{
|
||||
#ifdef HB_NO_SHAPE_AAT
|
||||
return HB_OT_NAME_ID_INVALID;
|
||||
#endif
|
||||
|
||||
return face->table.feat->get_feature_name_id (feature_type);
|
||||
}
|
||||
|
||||
@ -372,5 +424,11 @@ hb_aat_layout_feature_type_get_selector_infos (hb_face_t
|
||||
hb_aat_layout_feature_selector_info_t *selectors, /* OUT. May be NULL. */
|
||||
unsigned int *default_index /* OUT. May be NULL. */)
|
||||
{
|
||||
#ifdef HB_NO_SHAPE_AAT
|
||||
if (selector_count)
|
||||
*selector_count = 0;
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
return face->table.feat->get_selector_infos (feature_type, start_offset, selector_count, selectors, default_index);
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ struct FTStringRange
|
||||
}
|
||||
|
||||
protected:
|
||||
NNOffsetTo<UnsizedArrayOf<HBUINT8> >
|
||||
NNOffsetTo<UnsizedArrayOf<HBUINT8>>
|
||||
tag; /* Offset from the start of the table to
|
||||
* the beginning of the string */
|
||||
HBUINT16 length; /* String length (in bytes) */
|
||||
|
@ -34,6 +34,10 @@
|
||||
void hb_aat_map_builder_t::add_feature (hb_tag_t tag,
|
||||
unsigned int value)
|
||||
{
|
||||
#ifdef HB_NO_SHAPE_AAT
|
||||
return;
|
||||
#endif
|
||||
|
||||
if (tag == HB_TAG ('a','a','l','t'))
|
||||
{
|
||||
feature_info_t *info = features.push();
|
||||
@ -53,6 +57,10 @@ void hb_aat_map_builder_t::add_feature (hb_tag_t tag,
|
||||
void
|
||||
hb_aat_map_builder_t::compile (hb_aat_map_t &m)
|
||||
{
|
||||
#ifdef HB_NO_SHAPE_AAT
|
||||
return;
|
||||
#endif
|
||||
|
||||
/* Sort features and merge duplicates */
|
||||
if (features.length)
|
||||
{
|
||||
|
372
src/hb-algs.hh
372
src/hb-algs.hh
@ -34,26 +34,54 @@
|
||||
#include "hb-null.hh"
|
||||
|
||||
|
||||
/* Encodes three unsigned integers in one 64-bit number. If the inputs have more than 21 bits,
|
||||
* values will be truncated / overlap, and might not decode exactly. */
|
||||
#define HB_CODEPOINT_ENCODE3(x,y,z) (((uint64_t) (x) << 42) | ((uint64_t) (y) << 21) | (uint64_t) (z))
|
||||
#define HB_CODEPOINT_DECODE3_1(v) ((hb_codepoint_t) ((v) >> 42))
|
||||
#define HB_CODEPOINT_DECODE3_2(v) ((hb_codepoint_t) ((v) >> 21) & 0x1FFFFFu)
|
||||
#define HB_CODEPOINT_DECODE3_3(v) ((hb_codepoint_t) (v) & 0x1FFFFFu)
|
||||
|
||||
|
||||
struct
|
||||
{
|
||||
template <typename T> T
|
||||
operator () (const T& v) const { return v; }
|
||||
} HB_FUNCOBJ (hb_identity);
|
||||
/* Note. This is dangerous in that if it's passed an rvalue, it returns rvalue-reference. */
|
||||
template <typename T> auto
|
||||
operator () (T&& v) const HB_AUTO_RETURN ( hb_forward<T> (v) )
|
||||
}
|
||||
HB_FUNCOBJ (hb_identity);
|
||||
struct
|
||||
{
|
||||
/* Like identity(), but only retains lvalue-references. Rvalues are returned as rvalues. */
|
||||
template <typename T> T&
|
||||
operator () (T& v) const { return v; }
|
||||
|
||||
template <typename T> hb_remove_reference<T>
|
||||
operator () (T&& v) const { return v; }
|
||||
}
|
||||
HB_FUNCOBJ (hb_lidentity);
|
||||
struct
|
||||
{
|
||||
/* Like identity(), but always returns rvalue. */
|
||||
template <typename T> hb_remove_reference<T>
|
||||
operator () (T&& v) const { return v; }
|
||||
}
|
||||
HB_FUNCOBJ (hb_ridentity);
|
||||
|
||||
struct
|
||||
{
|
||||
template <typename T> bool
|
||||
operator () (const T& v) const { return bool (v); }
|
||||
} HB_FUNCOBJ (hb_bool);
|
||||
operator () (T&& v) const { return bool (hb_forward<T> (v)); }
|
||||
}
|
||||
HB_FUNCOBJ (hb_bool);
|
||||
|
||||
struct
|
||||
{
|
||||
private:
|
||||
template <typename T> auto
|
||||
impl (const T& v, hb_priority<1>) const HB_RETURN (uint32_t, hb_deref_pointer (v).hash ())
|
||||
impl (const T& v, hb_priority<1>) const HB_RETURN (uint32_t, hb_deref (v).hash ())
|
||||
|
||||
template <typename T,
|
||||
hb_enable_if (hb_is_integer (T))> auto
|
||||
hb_enable_if (hb_is_integral (T))> auto
|
||||
impl (const T& v, hb_priority<0>) const HB_AUTO_RETURN
|
||||
(
|
||||
/* Knuth's multiplicative method: */
|
||||
@ -64,40 +92,97 @@ struct
|
||||
|
||||
template <typename T> auto
|
||||
operator () (const T& v) const HB_RETURN (uint32_t, impl (v, hb_prioritize))
|
||||
} HB_FUNCOBJ (hb_hash);
|
||||
}
|
||||
HB_FUNCOBJ (hb_hash);
|
||||
|
||||
|
||||
struct
|
||||
{
|
||||
private:
|
||||
|
||||
/* Pointer-to-member-function. */
|
||||
template <typename Appl, typename Val1, typename ...Vals> auto
|
||||
impl (Appl&& a, hb_priority<2>, Val1 &&v1, Vals &&...vs) const HB_AUTO_RETURN
|
||||
((hb_deref_pointer (hb_forward<Val1> (v1)).*hb_forward<Appl> (a)) (hb_forward<Vals> (vs)...))
|
||||
template <typename Appl, typename T, typename ...Ts> auto
|
||||
impl (Appl&& a, hb_priority<2>, T &&v, Ts&&... ds) const HB_AUTO_RETURN
|
||||
((hb_deref (hb_forward<T> (v)).*hb_forward<Appl> (a)) (hb_forward<Ts> (ds)...))
|
||||
|
||||
/* Pointer-to-member. */
|
||||
template <typename Appl, typename Val> auto
|
||||
impl (Appl&& a, hb_priority<1>, Val &&v) const HB_AUTO_RETURN
|
||||
((hb_deref_pointer (hb_forward<Val> (v))).*hb_forward<Appl> (a))
|
||||
template <typename Appl, typename T> auto
|
||||
impl (Appl&& a, hb_priority<1>, T &&v) const HB_AUTO_RETURN
|
||||
((hb_deref (hb_forward<T> (v))).*hb_forward<Appl> (a))
|
||||
|
||||
/* Operator(). */
|
||||
template <typename Appl, typename ...Vals> auto
|
||||
impl (Appl&& a, hb_priority<0>, Vals &&...vs) const HB_AUTO_RETURN
|
||||
(hb_deref_pointer (hb_forward<Appl> (a)) (hb_forward<Vals> (vs)...))
|
||||
template <typename Appl, typename ...Ts> auto
|
||||
impl (Appl&& a, hb_priority<0>, Ts&&... ds) const HB_AUTO_RETURN
|
||||
(hb_deref (hb_forward<Appl> (a)) (hb_forward<Ts> (ds)...))
|
||||
|
||||
public:
|
||||
template <typename Appl, typename Val1, typename ...Vals> auto
|
||||
impl2 (Appl&& a, hb_priority<2>, Val1 &&v1, Vals &&...vs) const HB_AUTO_RETURN
|
||||
(hb_deref_pointer (hb_forward<Val1> (v1)).*hb_forward<Appl> (a) (hb_forward<Vals> (vs)...))
|
||||
|
||||
template <typename Appl, typename ...Vals> auto
|
||||
operator () (Appl&& a, Vals &&...vs) const HB_AUTO_RETURN
|
||||
template <typename Appl, typename ...Ts> auto
|
||||
operator () (Appl&& a, Ts&&... ds) const HB_AUTO_RETURN
|
||||
(
|
||||
impl (hb_forward<Appl> (a),
|
||||
hb_prioritize,
|
||||
hb_forward<Vals> (vs)...)
|
||||
hb_forward<Ts> (ds)...)
|
||||
)
|
||||
} HB_FUNCOBJ (hb_invoke);
|
||||
}
|
||||
HB_FUNCOBJ (hb_invoke);
|
||||
|
||||
template <unsigned Pos, typename Appl, typename V>
|
||||
struct hb_partial_t
|
||||
{
|
||||
hb_partial_t (Appl a, V v) : a (a), v (v) {}
|
||||
|
||||
static_assert (Pos > 0, "");
|
||||
|
||||
template <typename ...Ts,
|
||||
unsigned P = Pos,
|
||||
hb_enable_if (P == 1)> auto
|
||||
operator () (Ts&& ...ds) -> decltype (hb_invoke (hb_declval (Appl),
|
||||
hb_declval (V),
|
||||
hb_declval (Ts)...))
|
||||
{
|
||||
return hb_invoke (hb_forward<Appl> (a),
|
||||
hb_forward<V> (v),
|
||||
hb_forward<Ts> (ds)...);
|
||||
}
|
||||
template <typename T0, typename ...Ts,
|
||||
unsigned P = Pos,
|
||||
hb_enable_if (P == 2)> auto
|
||||
operator () (T0&& d0, Ts&& ...ds) -> decltype (hb_invoke (hb_declval (Appl),
|
||||
hb_declval (T0),
|
||||
hb_declval (V),
|
||||
hb_declval (Ts)...))
|
||||
{
|
||||
return hb_invoke (hb_forward<Appl> (a),
|
||||
hb_forward<T0> (d0),
|
||||
hb_forward<V> (v),
|
||||
hb_forward<Ts> (ds)...);
|
||||
}
|
||||
|
||||
private:
|
||||
hb_reference_wrapper<Appl> a;
|
||||
V v;
|
||||
};
|
||||
template <unsigned Pos=1, typename Appl, typename V>
|
||||
auto hb_partial (Appl&& a, V&& v) HB_AUTO_RETURN
|
||||
(( hb_partial_t<Pos, Appl, V> (a, v) ))
|
||||
|
||||
/* The following hacky replacement version is to make Visual Stuiod build:. */ \
|
||||
/* https://github.com/harfbuzz/harfbuzz/issues/1730 */ \
|
||||
#ifdef _MSC_VER
|
||||
#define HB_PARTIALIZE(Pos) \
|
||||
template <typename _T> \
|
||||
decltype(auto) operator () (_T&& _v) const \
|
||||
{ return hb_partial<Pos> (this, hb_forward<_T> (_v)); } \
|
||||
static_assert (true, "")
|
||||
#else
|
||||
#define HB_PARTIALIZE(Pos) \
|
||||
template <typename _T> \
|
||||
auto operator () (_T&& _v) const HB_AUTO_RETURN \
|
||||
(hb_partial<Pos> (this, hb_forward<_T> (_v))) \
|
||||
static_assert (true, "")
|
||||
#endif
|
||||
|
||||
|
||||
struct
|
||||
{
|
||||
@ -105,7 +190,7 @@ struct
|
||||
|
||||
template <typename Pred, typename Val> auto
|
||||
impl (Pred&& p, Val &&v, hb_priority<1>) const HB_AUTO_RETURN
|
||||
(hb_deref_pointer (hb_forward<Pred> (p)).has (v))
|
||||
(hb_deref (hb_forward<Pred> (p)).has (hb_forward<Val> (v)))
|
||||
|
||||
template <typename Pred, typename Val> auto
|
||||
impl (Pred&& p, Val &&v, hb_priority<0>) const HB_AUTO_RETURN
|
||||
@ -122,21 +207,56 @@ struct
|
||||
hb_forward<Val> (v),
|
||||
hb_prioritize)
|
||||
)
|
||||
} HB_FUNCOBJ (hb_has);
|
||||
}
|
||||
HB_FUNCOBJ (hb_has);
|
||||
|
||||
struct
|
||||
{
|
||||
private:
|
||||
|
||||
template <typename Pred, typename Val> auto
|
||||
impl (Pred&& p, Val &&v, hb_priority<1>) const HB_AUTO_RETURN
|
||||
(
|
||||
hb_has (hb_forward<Pred> (p),
|
||||
hb_forward<Val> (v))
|
||||
)
|
||||
|
||||
template <typename Pred, typename Val> auto
|
||||
impl (Pred&& p, Val &&v, hb_priority<0>) const HB_AUTO_RETURN
|
||||
(
|
||||
hb_forward<Pred> (p) == hb_forward<Val> (v)
|
||||
)
|
||||
|
||||
public:
|
||||
|
||||
template <typename Pred, typename Val> auto
|
||||
operator () (Pred&& p, Val &&v) const HB_RETURN (bool,
|
||||
impl (hb_forward<Pred> (p),
|
||||
hb_forward<Val> (v),
|
||||
hb_prioritize)
|
||||
)
|
||||
}
|
||||
HB_FUNCOBJ (hb_match);
|
||||
|
||||
struct
|
||||
{
|
||||
private:
|
||||
|
||||
template <typename Proj, typename Val> auto
|
||||
impl (Proj&& f, Val &&v, hb_priority<2>) const HB_AUTO_RETURN
|
||||
(hb_deref (hb_forward<Proj> (f)).get (hb_forward<Val> (v)))
|
||||
|
||||
template <typename Proj, typename Val> auto
|
||||
impl (Proj&& f, Val &&v, hb_priority<1>) const HB_AUTO_RETURN
|
||||
(hb_deref_pointer (hb_forward<Proj> (f)).get (hb_forward<Val> (v)))
|
||||
(
|
||||
hb_invoke (hb_forward<Proj> (f),
|
||||
hb_forward<Val> (v))
|
||||
)
|
||||
|
||||
template <typename Proj, typename Val> auto
|
||||
impl (Proj&& f, Val &&v, hb_priority<0>) const HB_AUTO_RETURN
|
||||
(
|
||||
hb_invoke (hb_forward<Proj> (f),
|
||||
hb_forward<Val> (v))
|
||||
hb_forward<Proj> (f)[hb_forward<Val> (v)]
|
||||
)
|
||||
|
||||
public:
|
||||
@ -148,7 +268,8 @@ struct
|
||||
hb_forward<Val> (v),
|
||||
hb_prioritize)
|
||||
)
|
||||
} HB_FUNCOBJ (hb_get);
|
||||
}
|
||||
HB_FUNCOBJ (hb_get);
|
||||
|
||||
|
||||
template <typename T1, typename T2>
|
||||
@ -159,38 +280,61 @@ struct hb_pair_t
|
||||
typedef hb_pair_t<T1, T2> pair_t;
|
||||
|
||||
hb_pair_t (T1 a, T2 b) : first (a), second (b) {}
|
||||
hb_pair_t (const pair_t& o) : first (o.first), second (o.second) {}
|
||||
|
||||
template <typename Q1, typename Q2,
|
||||
hb_enable_if (hb_is_convertible (T1, Q1) &&
|
||||
hb_is_convertible (T2, T2))>
|
||||
operator hb_pair_t<Q1, Q2> () { return hb_pair_t<Q1, Q2> (first, second); }
|
||||
|
||||
hb_pair_t<T1, T2> reverse () const
|
||||
{ return hb_pair_t<T1, T2> (second, first); }
|
||||
|
||||
bool operator == (const pair_t& o) const { return first == o.first && second == o.second; }
|
||||
bool operator != (const pair_t& o) const { return !(*this == o); }
|
||||
bool operator < (const pair_t& o) const { return first < o.first || (first == o.first && second < o.second); }
|
||||
bool operator >= (const pair_t& o) const { return !(*this < o); }
|
||||
bool operator > (const pair_t& o) const { return first > o.first || (first == o.first && second > o.second); }
|
||||
bool operator <= (const pair_t& o) const { return !(*this > o); }
|
||||
|
||||
T1 first;
|
||||
T2 second;
|
||||
};
|
||||
#define hb_pair_t(T1,T2) hb_pair_t<T1, T2>
|
||||
template <typename T1, typename T2> static inline hb_pair_t<T1, T2>
|
||||
hb_pair (T1&& a, T2&& b) { return hb_pair_t<T1, T2> (a, b); }
|
||||
|
||||
struct
|
||||
{
|
||||
template <typename Pair> auto
|
||||
operator () (const Pair& pair) const HB_AUTO_RETURN (pair.first)
|
||||
} HB_FUNCOBJ (hb_first);
|
||||
template <typename Pair> typename Pair::first_t
|
||||
operator () (const Pair& pair) const { return pair.first; }
|
||||
}
|
||||
HB_FUNCOBJ (hb_first);
|
||||
|
||||
struct
|
||||
{
|
||||
template <typename Pair> auto
|
||||
operator () (const Pair& pair) const HB_AUTO_RETURN (pair.second)
|
||||
} HB_FUNCOBJ (hb_second);
|
||||
template <typename Pair> typename Pair::second_t
|
||||
operator () (const Pair& pair) const { return pair.second; }
|
||||
}
|
||||
HB_FUNCOBJ (hb_second);
|
||||
|
||||
/* Note. In min/max impl, we can use hb_type_identity<T> for second argument.
|
||||
* However, that would silently convert between different-signedness integers.
|
||||
* Instead we accept two different types, such that compiler can err if
|
||||
* comparing integers of different signedness. */
|
||||
struct
|
||||
{
|
||||
template <typename T, typename T2> auto
|
||||
operator () (const T& a, const T2& b) const HB_AUTO_RETURN (a <= b ? a : b)
|
||||
} HB_FUNCOBJ (hb_min);
|
||||
operator () (T&& a, T2&& b) const HB_AUTO_RETURN
|
||||
(hb_forward<T> (a) <= hb_forward<T2> (b) ? hb_forward<T> (a) : hb_forward<T2> (b))
|
||||
}
|
||||
HB_FUNCOBJ (hb_min);
|
||||
struct
|
||||
{
|
||||
template <typename T, typename T2> auto
|
||||
operator () (const T& a, const T2& b) const HB_AUTO_RETURN (a >= b ? a : b)
|
||||
} HB_FUNCOBJ (hb_max);
|
||||
operator () (T&& a, T2&& b) const HB_AUTO_RETURN
|
||||
(hb_forward<T> (a) >= hb_forward<T2> (b) ? hb_forward<T> (a) : hb_forward<T2> (b))
|
||||
}
|
||||
HB_FUNCOBJ (hb_max);
|
||||
|
||||
|
||||
/*
|
||||
@ -402,14 +546,6 @@ static inline unsigned char TOUPPER (unsigned char c)
|
||||
static inline unsigned char TOLOWER (unsigned char c)
|
||||
{ return (c >= 'A' && c <= 'Z') ? c - 'A' + 'a' : c; }
|
||||
|
||||
#undef MIN
|
||||
template <typename Type>
|
||||
static inline Type MIN (const Type &a, const Type &b) { return a < b ? a : b; }
|
||||
|
||||
#undef MAX
|
||||
template <typename Type>
|
||||
static inline Type MAX (const Type &a, const Type &b) { return a > b ? a : b; }
|
||||
|
||||
static inline unsigned int DIV_CEIL (const unsigned int a, unsigned int b)
|
||||
{ return (a + (b - 1)) / b; }
|
||||
|
||||
@ -467,40 +603,19 @@ hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2, T lo3, T hi3)
|
||||
/*
|
||||
* Sort and search.
|
||||
*/
|
||||
|
||||
template <typename ...Ts>
|
||||
static inline void *
|
||||
hb_bsearch (const void *key, const void *base,
|
||||
size_t nmemb, size_t size,
|
||||
int (*compar)(const void *_key, const void *_item))
|
||||
{
|
||||
int min = 0, max = (int) nmemb - 1;
|
||||
while (min <= max)
|
||||
{
|
||||
int mid = (min + max) / 2;
|
||||
const void *p = (const void *) (((const char *) base) + (mid * size));
|
||||
int c = compar (key, p);
|
||||
if (c < 0)
|
||||
max = mid - 1;
|
||||
else if (c > 0)
|
||||
min = mid + 1;
|
||||
else
|
||||
return (void *) p;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static inline void *
|
||||
hb_bsearch_r (const void *key, const void *base,
|
||||
size_t nmemb, size_t size,
|
||||
int (*compar)(const void *_key, const void *_item, void *_arg),
|
||||
void *arg)
|
||||
int (*compar)(const void *_key, const void *_item, Ts... _ds),
|
||||
Ts... ds)
|
||||
{
|
||||
int min = 0, max = (int) nmemb - 1;
|
||||
while (min <= max)
|
||||
{
|
||||
int mid = ((unsigned int) min + (unsigned int) max) / 2;
|
||||
const void *p = (const void *) (((const char *) base) + (mid * size));
|
||||
int c = compar (key, p, arg);
|
||||
int c = compar (key, p, ds...);
|
||||
if (c < 0)
|
||||
max = mid - 1;
|
||||
else if (c > 0)
|
||||
@ -661,7 +776,7 @@ hb_codepoint_parse (const char *s, unsigned int len, int base, hb_codepoint_t *o
|
||||
{
|
||||
/* Pain because we don't know whether s is nul-terminated. */
|
||||
char buf[64];
|
||||
len = MIN (ARRAY_LENGTH (buf) - 1, len);
|
||||
len = hb_min (ARRAY_LENGTH (buf) - 1, len);
|
||||
strncpy (buf, s, len);
|
||||
buf[len] = '\0';
|
||||
|
||||
@ -675,30 +790,83 @@ hb_codepoint_parse (const char *s, unsigned int len, int base, hb_codepoint_t *o
|
||||
}
|
||||
|
||||
|
||||
struct HbOpOr
|
||||
{
|
||||
static constexpr bool passthru_left = true;
|
||||
static constexpr bool passthru_right = true;
|
||||
template <typename T> static void process (T &o, const T &a, const T &b) { o = a | b; }
|
||||
};
|
||||
struct HbOpAnd
|
||||
{
|
||||
/* Operators. */
|
||||
|
||||
struct hb_bitwise_and
|
||||
{ HB_PARTIALIZE(2);
|
||||
static constexpr bool passthru_left = false;
|
||||
static constexpr bool passthru_right = false;
|
||||
template <typename T> static void process (T &o, const T &a, const T &b) { o = a & b; }
|
||||
};
|
||||
struct HbOpMinus
|
||||
{
|
||||
static constexpr bool passthru_left = true;
|
||||
static constexpr bool passthru_right = false;
|
||||
template <typename T> static void process (T &o, const T &a, const T &b) { o = a & ~b; }
|
||||
};
|
||||
struct HbOpXor
|
||||
{
|
||||
template <typename T> auto
|
||||
operator () (const T &a, const T &b) const HB_AUTO_RETURN (a & b)
|
||||
}
|
||||
HB_FUNCOBJ (hb_bitwise_and);
|
||||
struct hb_bitwise_or
|
||||
{ HB_PARTIALIZE(2);
|
||||
static constexpr bool passthru_left = true;
|
||||
static constexpr bool passthru_right = true;
|
||||
template <typename T> static void process (T &o, const T &a, const T &b) { o = a ^ b; }
|
||||
};
|
||||
template <typename T> auto
|
||||
operator () (const T &a, const T &b) const HB_AUTO_RETURN (a | b)
|
||||
}
|
||||
HB_FUNCOBJ (hb_bitwise_or);
|
||||
struct hb_bitwise_xor
|
||||
{ HB_PARTIALIZE(2);
|
||||
static constexpr bool passthru_left = true;
|
||||
static constexpr bool passthru_right = true;
|
||||
template <typename T> auto
|
||||
operator () (const T &a, const T &b) const HB_AUTO_RETURN (a ^ b)
|
||||
}
|
||||
HB_FUNCOBJ (hb_bitwise_xor);
|
||||
struct hb_bitwise_sub
|
||||
{ HB_PARTIALIZE(2);
|
||||
static constexpr bool passthru_left = true;
|
||||
static constexpr bool passthru_right = false;
|
||||
template <typename T> auto
|
||||
operator () (const T &a, const T &b) const HB_AUTO_RETURN (a & ~b)
|
||||
}
|
||||
HB_FUNCOBJ (hb_bitwise_sub);
|
||||
|
||||
struct
|
||||
{ HB_PARTIALIZE(2);
|
||||
template <typename T, typename T2> auto
|
||||
operator () (const T &a, const T2 &b) const HB_AUTO_RETURN (a + b)
|
||||
}
|
||||
HB_FUNCOBJ (hb_add);
|
||||
struct
|
||||
{ HB_PARTIALIZE(2);
|
||||
template <typename T, typename T2> auto
|
||||
operator () (const T &a, const T2 &b) const HB_AUTO_RETURN (a - b)
|
||||
}
|
||||
HB_FUNCOBJ (hb_sub);
|
||||
struct
|
||||
{ HB_PARTIALIZE(2);
|
||||
template <typename T, typename T2> auto
|
||||
operator () (const T &a, const T2 &b) const HB_AUTO_RETURN (a * b)
|
||||
}
|
||||
HB_FUNCOBJ (hb_mul);
|
||||
struct
|
||||
{ HB_PARTIALIZE(2);
|
||||
template <typename T, typename T2> auto
|
||||
operator () (const T &a, const T2 &b) const HB_AUTO_RETURN (a / b)
|
||||
}
|
||||
HB_FUNCOBJ (hb_div);
|
||||
struct
|
||||
{ HB_PARTIALIZE(2);
|
||||
template <typename T, typename T2> auto
|
||||
operator () (const T &a, const T2 &b) const HB_AUTO_RETURN (a % b)
|
||||
}
|
||||
HB_FUNCOBJ (hb_mod);
|
||||
struct
|
||||
{
|
||||
template <typename T> auto
|
||||
operator () (const T &a) const HB_AUTO_RETURN (+a)
|
||||
}
|
||||
HB_FUNCOBJ (hb_pos);
|
||||
struct
|
||||
{
|
||||
template <typename T> auto
|
||||
operator () (const T &a) const HB_AUTO_RETURN (-a)
|
||||
}
|
||||
HB_FUNCOBJ (hb_neg);
|
||||
|
||||
|
||||
/* Compiler-assisted vectorization. */
|
||||
@ -714,26 +882,26 @@ struct hb_vector_size_t
|
||||
|
||||
void clear (unsigned char v = 0) { memset (this, v, sizeof (*this)); }
|
||||
|
||||
template <class Op>
|
||||
hb_vector_size_t process (const hb_vector_size_t &o) const
|
||||
template <typename Op>
|
||||
hb_vector_size_t process (const Op& op, const hb_vector_size_t &o) const
|
||||
{
|
||||
hb_vector_size_t r;
|
||||
#if HB_VECTOR_SIZE
|
||||
if (HB_VECTOR_SIZE && 0 == (byte_size * 8) % HB_VECTOR_SIZE)
|
||||
for (unsigned int i = 0; i < ARRAY_LENGTH (u.vec); i++)
|
||||
Op::process (r.u.vec[i], u.vec[i], o.u.vec[i]);
|
||||
r.u.vec[i] = op (u.vec[i], o.u.vec[i]);
|
||||
else
|
||||
#endif
|
||||
for (unsigned int i = 0; i < ARRAY_LENGTH (u.v); i++)
|
||||
Op::process (r.u.v[i], u.v[i], o.u.v[i]);
|
||||
r.u.v[i] = op (u.v[i], o.u.v[i]);
|
||||
return r;
|
||||
}
|
||||
hb_vector_size_t operator | (const hb_vector_size_t &o) const
|
||||
{ return process<HbOpOr> (o); }
|
||||
{ return process (hb_bitwise_or, o); }
|
||||
hb_vector_size_t operator & (const hb_vector_size_t &o) const
|
||||
{ return process<HbOpAnd> (o); }
|
||||
{ return process (hb_bitwise_and, o); }
|
||||
hb_vector_size_t operator ^ (const hb_vector_size_t &o) const
|
||||
{ return process<HbOpXor> (o); }
|
||||
{ return process (hb_bitwise_xor, o); }
|
||||
hb_vector_size_t operator ~ () const
|
||||
{
|
||||
hb_vector_size_t r;
|
||||
|
@ -42,19 +42,20 @@ struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
|
||||
/*
|
||||
* Constructors.
|
||||
*/
|
||||
hb_array_t () : arrayZ (nullptr), length (0) {}
|
||||
hb_array_t (Type *array_, unsigned int length_) : arrayZ (array_), length (length_) {}
|
||||
template <unsigned int length_> hb_array_t (Type (&array_)[length_]) : arrayZ (array_), length (length_) {}
|
||||
hb_array_t () : arrayZ (nullptr), length (0), backwards_length (0) {}
|
||||
hb_array_t (Type *array_, unsigned int length_) : arrayZ (array_), length (length_), backwards_length (0) {}
|
||||
template <unsigned int length_>
|
||||
hb_array_t (Type (&array_)[length_]) : arrayZ (array_), length (length_), backwards_length (0) {}
|
||||
|
||||
template <typename U,
|
||||
hb_enable_if (hb_is_cr_convertible_to(U, Type))>
|
||||
hb_enable_if (hb_is_cr_convertible(U, Type))>
|
||||
hb_array_t (const hb_array_t<U> &o) :
|
||||
hb_iter_with_fallback_t<hb_array_t<Type>, Type&> (),
|
||||
arrayZ (o.arrayZ), length (o.length) {}
|
||||
arrayZ (o.arrayZ), length (o.length), backwards_length (o.backwards_length) {}
|
||||
template <typename U,
|
||||
hb_enable_if (hb_is_cr_convertible_to(U, Type))>
|
||||
hb_enable_if (hb_is_cr_convertible(U, Type))>
|
||||
hb_array_t& operator = (const hb_array_t<U> &o)
|
||||
{ arrayZ = o.arrayZ; length = o.length; return *this; }
|
||||
{ arrayZ = o.arrayZ; length = o.length; backwards_length = o.backwards_length; return *this; }
|
||||
|
||||
/*
|
||||
* Iterator implementation.
|
||||
@ -71,15 +72,25 @@ struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
|
||||
if (unlikely (n > length))
|
||||
n = length;
|
||||
length -= n;
|
||||
backwards_length += n;
|
||||
arrayZ += n;
|
||||
}
|
||||
void __rewind__ (unsigned n)
|
||||
{
|
||||
if (unlikely (n > length))
|
||||
n = length;
|
||||
length -= n;
|
||||
if (unlikely (n > backwards_length))
|
||||
n = backwards_length;
|
||||
length += n;
|
||||
backwards_length -= n;
|
||||
arrayZ -= n;
|
||||
}
|
||||
unsigned __len__ () const { return length; }
|
||||
/* Ouch. The operator== compares the contents of the array. For range-based for loops,
|
||||
* it's best if we can just compare arrayZ, though comparing contents is still fast,
|
||||
* but also would require that Type has operator==. As such, we optimize this operator
|
||||
* for range-based for loop and just compare arrayZ. No need to compare length, as we
|
||||
* assume we're only compared to .end(). */
|
||||
bool operator != (const hb_array_t& o) const
|
||||
{ return arrayZ != o.arrayZ; }
|
||||
|
||||
/* Extra operators.
|
||||
*/
|
||||
@ -141,7 +152,7 @@ struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
|
||||
}
|
||||
void qsort (unsigned int start, unsigned int end)
|
||||
{
|
||||
end = MIN (end, length);
|
||||
end = hb_min (end, length);
|
||||
assert (start <= end);
|
||||
if (likely (start < end))
|
||||
::qsort (arrayZ + start, end - start, this->item_size, Type::cmp);
|
||||
@ -164,7 +175,7 @@ struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
|
||||
else
|
||||
count -= start_offset;
|
||||
if (seg_count)
|
||||
count = *seg_count = MIN (count, *seg_count);
|
||||
count = *seg_count = hb_min (count, *seg_count);
|
||||
return hb_array_t<Type> (arrayZ + start_offset, count);
|
||||
}
|
||||
hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int seg_count) const
|
||||
@ -174,6 +185,17 @@ struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
|
||||
void free ()
|
||||
{ ::free ((void *) arrayZ); arrayZ = nullptr; length = 0; }
|
||||
|
||||
template <typename hb_serialize_context_t>
|
||||
hb_array_t copy (hb_serialize_context_t *c) const
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
auto* out = c->start_embed (arrayZ);
|
||||
if (unlikely (!c->extend_size (out, get_size ()))) return_trace (hb_array_t ());
|
||||
for (unsigned i = 0; i < length; i++)
|
||||
out[i] = arrayZ[i]; /* TODO: add version that calls c->copy() */
|
||||
return_trace (hb_array_t (out, length));
|
||||
}
|
||||
|
||||
template <typename hb_sanitize_context_t>
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{ return c->check_array (arrayZ, length); }
|
||||
@ -185,6 +207,7 @@ struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
|
||||
public:
|
||||
Type *arrayZ;
|
||||
unsigned int length;
|
||||
unsigned int backwards_length;
|
||||
};
|
||||
template <typename T> inline hb_array_t<T>
|
||||
hb_array (T *array, unsigned int length)
|
||||
@ -212,18 +235,23 @@ struct hb_sorted_array_t :
|
||||
|
||||
hb_sorted_array_t () : hb_array_t<Type> () {}
|
||||
hb_sorted_array_t (Type *array_, unsigned int length_) : hb_array_t<Type> (array_, length_) {}
|
||||
template <unsigned int length_> hb_sorted_array_t (Type (&array_)[length_]) : hb_array_t<Type> (array_) {}
|
||||
template <unsigned int length_>
|
||||
hb_sorted_array_t (Type (&array_)[length_]) : hb_array_t<Type> (array_) {}
|
||||
|
||||
template <typename U,
|
||||
hb_enable_if (hb_is_cr_convertible_to(U, Type))>
|
||||
hb_enable_if (hb_is_cr_convertible(U, Type))>
|
||||
hb_sorted_array_t (const hb_array_t<U> &o) :
|
||||
hb_iter_t<hb_sorted_array_t<Type>, Type&> (),
|
||||
hb_array_t<Type> (o) {}
|
||||
template <typename U,
|
||||
hb_enable_if (hb_is_cr_convertible_to(U, Type))>
|
||||
hb_enable_if (hb_is_cr_convertible(U, Type))>
|
||||
hb_sorted_array_t& operator = (const hb_array_t<U> &o)
|
||||
{ hb_array_t<Type> (*this) = o; return *this; }
|
||||
|
||||
/* Iterator implementation. */
|
||||
bool operator != (const hb_sorted_array_t& o) const
|
||||
{ return this->arrayZ != o.arrayZ || this->length != o.length; }
|
||||
|
||||
hb_sorted_array_t<Type> sub_array (unsigned int start_offset, unsigned int *seg_count /* IN/OUT */) const
|
||||
{ return hb_sorted_array_t<Type> (((const hb_array_t<Type> *) (this))->sub_array (start_offset, seg_count)); }
|
||||
hb_sorted_array_t<Type> sub_array (unsigned int start_offset, unsigned int seg_count) const
|
||||
@ -296,7 +324,7 @@ bool hb_array_t<T>::operator == (const hb_array_t<T> &o) const
|
||||
{
|
||||
return length == o.length &&
|
||||
+ hb_zip (*this, o)
|
||||
| hb_map ([] (hb_pair_t<T&, T&> &&_) -> bool { return _.first == _.second; })
|
||||
| hb_map ([] (hb_pair_t<T&, T&> &&_) { return _.first == _.second; })
|
||||
| hb_all
|
||||
;
|
||||
}
|
||||
@ -306,7 +334,7 @@ uint32_t hb_array_t<T>::hash () const
|
||||
return
|
||||
+ hb_iter (*this)
|
||||
| hb_map (hb_hash)
|
||||
| hb_reduce ([] (uint32_t a, uint32_t b) -> uint32_t { return a * 31 + b; }, 0)
|
||||
| hb_reduce ([] (uint32_t a, uint32_t b) { return a * 31 + b; }, 0)
|
||||
;
|
||||
}
|
||||
|
||||
|
@ -107,7 +107,7 @@ _hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N)
|
||||
|
||||
static inline void _hb_memory_barrier ()
|
||||
{
|
||||
#if !defined(MemoryBarrier)
|
||||
#ifndef MemoryBarrier
|
||||
/* MinGW has a convoluted history of supporting MemoryBarrier. */
|
||||
LONG dummy = 0;
|
||||
InterlockedExchange (&dummy, 1);
|
||||
@ -216,7 +216,7 @@ static_assert ((sizeof (long) == sizeof (void *)), "");
|
||||
|
||||
#define HB_ATOMIC_INT_NIL 1 /* Warn that fallback implementation is in use. */
|
||||
|
||||
#define _hb_memory_barrier()
|
||||
#define _hb_memory_barrier() do {} while (0)
|
||||
|
||||
#define hb_atomic_int_impl_add(AI, V) ((*(AI) += (V)) - (V))
|
||||
|
||||
@ -227,7 +227,7 @@ static_assert ((sizeof (long) == sizeof (void *)), "");
|
||||
|
||||
#define hb_atomic_int_impl_add(AI, V) ((*(AI) += (V)) - (V))
|
||||
|
||||
#define _hb_memory_barrier()
|
||||
#define _hb_memory_barrier() do {} while (0)
|
||||
|
||||
#define hb_atomic_ptr_impl_cmpexch(P,O,N) (* (void **) (P) == (void *) (O) ? (* (void **) (P) = (void *) (N), true) : false)
|
||||
|
||||
|
@ -30,7 +30,7 @@
|
||||
* http://www.gnu.org/software/libc/manual/html_node/Feature-Test-Macros.html
|
||||
* https://www.oracle.com/technetwork/articles/servers-storage-dev/standardheaderfiles-453865.html
|
||||
*/
|
||||
#if !defined(_POSIX_C_SOURCE) && !defined(_MSC_VER)
|
||||
#if !defined(_POSIX_C_SOURCE) && !defined(_MSC_VER) && !defined(__NetBSD__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-macros"
|
||||
#define _POSIX_C_SOURCE 200809L
|
||||
@ -155,7 +155,7 @@ hb_blob_create_sub_blob (hb_blob_t *parent,
|
||||
hb_blob_make_immutable (parent);
|
||||
|
||||
blob = hb_blob_create (parent->data + offset,
|
||||
MIN (length, parent->length - offset),
|
||||
hb_min (length, parent->length - offset),
|
||||
HB_MEMORY_MODE_READONLY,
|
||||
hb_blob_reference (parent),
|
||||
_hb_blob_destroy);
|
||||
|
@ -71,6 +71,9 @@ hb_blob_create (const char *data,
|
||||
void *user_data,
|
||||
hb_destroy_func_t destroy);
|
||||
|
||||
HB_EXTERN hb_blob_t *
|
||||
hb_blob_create_from_file (const char *file_name);
|
||||
|
||||
/* Always creates with MEMORY_MODE_READONLY.
|
||||
* Even if the parent blob is writable, we don't
|
||||
* want the user of the sub-blob to be able to
|
||||
@ -123,9 +126,6 @@ hb_blob_get_data (hb_blob_t *blob, unsigned int *length);
|
||||
HB_EXTERN char *
|
||||
hb_blob_get_data_writable (hb_blob_t *blob, unsigned int *length);
|
||||
|
||||
HB_EXTERN hb_blob_t *
|
||||
hb_blob_create_from_file (const char *file_name);
|
||||
|
||||
HB_END_DECLS
|
||||
|
||||
#endif /* HB_BLOB_H */
|
||||
|
@ -28,8 +28,10 @@
|
||||
|
||||
|
||||
static const char *serialize_formats[] = {
|
||||
#ifndef HB_NO_BUFFER_SERIALIZE
|
||||
"text",
|
||||
"json",
|
||||
#endif
|
||||
nullptr
|
||||
};
|
||||
|
||||
@ -85,10 +87,12 @@ hb_buffer_serialize_format_from_string (const char *str, int len)
|
||||
const char *
|
||||
hb_buffer_serialize_format_to_string (hb_buffer_serialize_format_t format)
|
||||
{
|
||||
switch (format)
|
||||
switch ((unsigned) format)
|
||||
{
|
||||
#ifndef HB_NO_BUFFER_SERIALIZE
|
||||
case HB_BUFFER_SERIALIZE_FORMAT_TEXT: return serialize_formats[0];
|
||||
case HB_BUFFER_SERIALIZE_FORMAT_JSON: return serialize_formats[1];
|
||||
#endif
|
||||
default:
|
||||
case HB_BUFFER_SERIALIZE_FORMAT_INVALID: return nullptr;
|
||||
}
|
||||
@ -138,34 +142,34 @@ _hb_buffer_serialize_glyphs_json (hb_buffer_t *buffer,
|
||||
*p++ = '"';
|
||||
}
|
||||
else
|
||||
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint));
|
||||
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint));
|
||||
|
||||
if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) {
|
||||
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"cl\":%u", info[i].cluster));
|
||||
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"cl\":%u", info[i].cluster));
|
||||
}
|
||||
|
||||
if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS))
|
||||
{
|
||||
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"dx\":%d,\"dy\":%d",
|
||||
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"dx\":%d,\"dy\":%d",
|
||||
x+pos[i].x_offset, y+pos[i].y_offset));
|
||||
if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES))
|
||||
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"ax\":%d,\"ay\":%d",
|
||||
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"ax\":%d,\"ay\":%d",
|
||||
pos[i].x_advance, pos[i].y_advance));
|
||||
}
|
||||
|
||||
if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS)
|
||||
{
|
||||
if (info[i].mask & HB_GLYPH_FLAG_DEFINED)
|
||||
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"fl\":%u", info[i].mask & HB_GLYPH_FLAG_DEFINED));
|
||||
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"fl\":%u", info[i].mask & HB_GLYPH_FLAG_DEFINED));
|
||||
}
|
||||
|
||||
if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS)
|
||||
{
|
||||
hb_glyph_extents_t extents;
|
||||
hb_font_get_glyph_extents(font, info[i].codepoint, &extents);
|
||||
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"xb\":%d,\"yb\":%d",
|
||||
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"xb\":%d,\"yb\":%d",
|
||||
extents.x_bearing, extents.y_bearing));
|
||||
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"w\":%d,\"h\":%d",
|
||||
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"w\":%d,\"h\":%d",
|
||||
extents.width, extents.height));
|
||||
}
|
||||
|
||||
@ -224,37 +228,37 @@ _hb_buffer_serialize_glyphs_text (hb_buffer_t *buffer,
|
||||
p += strlen (p);
|
||||
}
|
||||
else
|
||||
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint));
|
||||
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint));
|
||||
|
||||
if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) {
|
||||
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "=%u", info[i].cluster));
|
||||
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "=%u", info[i].cluster));
|
||||
}
|
||||
|
||||
if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS))
|
||||
{
|
||||
if (x+pos[i].x_offset || y+pos[i].y_offset)
|
||||
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "@%d,%d", x+pos[i].x_offset, y+pos[i].y_offset));
|
||||
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "@%d,%d", x+pos[i].x_offset, y+pos[i].y_offset));
|
||||
|
||||
if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES))
|
||||
{
|
||||
*p++ = '+';
|
||||
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%d", pos[i].x_advance));
|
||||
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%d", pos[i].x_advance));
|
||||
if (pos[i].y_advance)
|
||||
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",%d", pos[i].y_advance));
|
||||
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",%d", pos[i].y_advance));
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS)
|
||||
{
|
||||
if (info[i].mask & HB_GLYPH_FLAG_DEFINED)
|
||||
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "#%X", info[i].mask &HB_GLYPH_FLAG_DEFINED));
|
||||
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "#%X", info[i].mask &HB_GLYPH_FLAG_DEFINED));
|
||||
}
|
||||
|
||||
if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS)
|
||||
{
|
||||
hb_glyph_extents_t extents;
|
||||
hb_font_get_glyph_extents(font, info[i].codepoint, &extents);
|
||||
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "<%d,%d,%d,%d>", extents.x_bearing, extents.y_bearing, extents.width, extents.height));
|
||||
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "<%d,%d,%d,%d>", extents.x_bearing, extents.y_bearing, extents.width, extents.height));
|
||||
}
|
||||
|
||||
unsigned int l = p - b;
|
||||
@ -344,6 +348,10 @@ hb_buffer_serialize_glyphs (hb_buffer_t *buffer,
|
||||
if (buf_size)
|
||||
*buf = '\0';
|
||||
|
||||
#ifdef HB_NO_BUFFER_SERIALIZE
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
assert ((!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID) ||
|
||||
buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS);
|
||||
|
||||
@ -380,7 +388,7 @@ static hb_bool_t
|
||||
parse_uint (const char *pp, const char *end, uint32_t *pv)
|
||||
{
|
||||
char buf[32];
|
||||
unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - pp));
|
||||
unsigned int len = hb_min (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - pp));
|
||||
strncpy (buf, pp, len);
|
||||
buf[len] = '\0';
|
||||
|
||||
@ -401,7 +409,7 @@ static hb_bool_t
|
||||
parse_int (const char *pp, const char *end, int32_t *pv)
|
||||
{
|
||||
char buf[32];
|
||||
unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - pp));
|
||||
unsigned int len = hb_min (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - pp));
|
||||
strncpy (buf, pp, len);
|
||||
buf[len] = '\0';
|
||||
|
||||
@ -449,6 +457,10 @@ hb_buffer_deserialize_glyphs (hb_buffer_t *buffer,
|
||||
end_ptr = &end;
|
||||
*end_ptr = buf;
|
||||
|
||||
#ifdef HB_NO_BUFFER_SERIALIZE
|
||||
return false;
|
||||
#endif
|
||||
|
||||
assert ((!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID) ||
|
||||
buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS);
|
||||
|
||||
|
@ -524,7 +524,7 @@ hb_buffer_t::merge_clusters_impl (unsigned int start,
|
||||
unsigned int cluster = info[start].cluster;
|
||||
|
||||
for (unsigned int i = start + 1; i < end; i++)
|
||||
cluster = MIN<unsigned int> (cluster, info[i].cluster);
|
||||
cluster = hb_min (cluster, info[i].cluster);
|
||||
|
||||
/* Extend end */
|
||||
while (end < len && info[end - 1].cluster == info[end].cluster)
|
||||
@ -555,7 +555,7 @@ hb_buffer_t::merge_out_clusters (unsigned int start,
|
||||
unsigned int cluster = out_info[start].cluster;
|
||||
|
||||
for (unsigned int i = start + 1; i < end; i++)
|
||||
cluster = MIN<unsigned int> (cluster, out_info[i].cluster);
|
||||
cluster = hb_min (cluster, out_info[i].cluster);
|
||||
|
||||
/* Extend start */
|
||||
while (start && out_info[start - 1].cluster == out_info[start].cluster)
|
||||
@ -2026,7 +2026,10 @@ hb_buffer_set_message_func (hb_buffer_t *buffer,
|
||||
bool
|
||||
hb_buffer_t::message_impl (hb_font_t *font, const char *fmt, va_list ap)
|
||||
{
|
||||
#ifdef HB_NO_BUFFER_MESSAGE
|
||||
return false;
|
||||
#endif
|
||||
char buf[100];
|
||||
vsnprintf (buf, sizeof (buf), fmt, ap);
|
||||
vsnprintf (buf, sizeof (buf), fmt, ap);
|
||||
return (bool) this->message_func (this, font, buf, this->message_data);
|
||||
}
|
||||
|
@ -379,7 +379,7 @@ struct hb_buffer_t
|
||||
unsigned int cluster) const
|
||||
{
|
||||
for (unsigned int i = start; i < end; i++)
|
||||
cluster = MIN<unsigned int> (cluster, infos[i].cluster);
|
||||
cluster = hb_min (cluster, infos[i].cluster);
|
||||
return cluster;
|
||||
}
|
||||
void
|
||||
|
@ -147,8 +147,9 @@ struct cs_interp_env_t : interp_env_t<ARG>
|
||||
return callStack.in_error () || SUPER::in_error ();
|
||||
}
|
||||
|
||||
bool popSubrNum (const biased_subrs_t<SUBRS>& biasedSubrs, unsigned int &subr_num)
|
||||
bool pop_subr_num (const biased_subrs_t<SUBRS>& biasedSubrs, unsigned int &subr_num)
|
||||
{
|
||||
subr_num = 0;
|
||||
int n = SUPER::argStack.pop_int ();
|
||||
n += biasedSubrs.get_bias ();
|
||||
if (unlikely ((n < 0) || ((unsigned int)n >= biasedSubrs.get_count ())))
|
||||
@ -158,11 +159,11 @@ struct cs_interp_env_t : interp_env_t<ARG>
|
||||
return true;
|
||||
}
|
||||
|
||||
void callSubr (const biased_subrs_t<SUBRS>& biasedSubrs, cs_type_t type)
|
||||
void call_subr (const biased_subrs_t<SUBRS>& biasedSubrs, cs_type_t type)
|
||||
{
|
||||
unsigned int subr_num;
|
||||
unsigned int subr_num = 0;
|
||||
|
||||
if (unlikely (!popSubrNum (biasedSubrs, subr_num)
|
||||
if (unlikely (!pop_subr_num (biasedSubrs, subr_num)
|
||||
|| callStack.get_count () >= kMaxCallLimit))
|
||||
{
|
||||
SUPER::set_error ();
|
||||
@ -175,7 +176,7 @@ struct cs_interp_env_t : interp_env_t<ARG>
|
||||
SUPER::str_ref = context.str_ref;
|
||||
}
|
||||
|
||||
void returnFromSubr ()
|
||||
void return_from_subr ()
|
||||
{
|
||||
if (unlikely (SUPER::str_ref.in_error ()))
|
||||
SUPER::set_error ();
|
||||
@ -246,7 +247,7 @@ struct path_procs_null_t
|
||||
static void flex1 (ENV &env, PARAM& param) {}
|
||||
};
|
||||
|
||||
template <typename ARG, typename OPSET, typename ENV, typename PARAM, typename PATH=path_procs_null_t<ENV, PARAM> >
|
||||
template <typename ARG, typename OPSET, typename ENV, typename PARAM, typename PATH=path_procs_null_t<ENV, PARAM>>
|
||||
struct cs_opset_t : opset_t<ARG>
|
||||
{
|
||||
static void process_op (op_code_t op, ENV &env, PARAM& param)
|
||||
@ -254,7 +255,7 @@ struct cs_opset_t : opset_t<ARG>
|
||||
switch (op) {
|
||||
|
||||
case OpCode_return:
|
||||
env.returnFromSubr ();
|
||||
env.return_from_subr ();
|
||||
break;
|
||||
case OpCode_endchar:
|
||||
OPSET::check_width (op, env, param);
|
||||
@ -267,11 +268,11 @@ struct cs_opset_t : opset_t<ARG>
|
||||
break;
|
||||
|
||||
case OpCode_callsubr:
|
||||
env.callSubr (env.localSubrs, CSType_LocalSubr);
|
||||
env.call_subr (env.localSubrs, CSType_LocalSubr);
|
||||
break;
|
||||
|
||||
case OpCode_callgsubr:
|
||||
env.callSubr (env.globalSubrs, CSType_GlobalSubr);
|
||||
env.call_subr (env.globalSubrs, CSType_GlobalSubr);
|
||||
break;
|
||||
|
||||
case OpCode_hstem:
|
||||
|
@ -81,7 +81,7 @@ struct cff1_cs_interp_env_t : cs_interp_env_t<number_t, CFF1Subrs>
|
||||
typedef cs_interp_env_t<number_t, CFF1Subrs> SUPER;
|
||||
};
|
||||
|
||||
template <typename OPSET, typename PARAM, typename PATH=path_procs_null_t<cff1_cs_interp_env_t, PARAM> >
|
||||
template <typename OPSET, typename PARAM, typename PATH=path_procs_null_t<cff1_cs_interp_env_t, PARAM>>
|
||||
struct cff1_cs_opset_t : cs_opset_t<number_t, OPSET, cff1_cs_interp_env_t, PARAM, PATH>
|
||||
{
|
||||
/* PostScript-originated legacy opcodes (OpCode_add etc) are unsupported */
|
||||
|
@ -193,7 +193,7 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<blend_arg_t, CFF2Subrs>
|
||||
|
||||
typedef cs_interp_env_t<blend_arg_t, CFF2Subrs> SUPER;
|
||||
};
|
||||
template <typename OPSET, typename PARAM, typename PATH=path_procs_null_t<cff2_cs_interp_env_t, PARAM> >
|
||||
template <typename OPSET, typename PARAM, typename PATH=path_procs_null_t<cff2_cs_interp_env_t, PARAM>>
|
||||
struct cff2_cs_opset_t : cs_opset_t<blend_arg_t, OPSET, cff2_cs_interp_env_t, PARAM, PATH>
|
||||
{
|
||||
static void process_op (op_code_t op, cff2_cs_interp_env_t &env, PARAM& param)
|
||||
|
@ -67,7 +67,7 @@ _hb_options_init ()
|
||||
p = c + strlen (c);
|
||||
|
||||
#define OPTION(name, symbol) \
|
||||
if (0 == strncmp (c, name, p - c) && strlen (name) == p - c) u.opts.symbol = true;
|
||||
if (0 == strncmp (c, name, p - c) && strlen (name) == p - c) do { u.opts.symbol = true; } while (0)
|
||||
|
||||
OPTION ("uniscribe-bug-compatible", uniscribe_bug_compatible);
|
||||
OPTION ("aat", aat);
|
||||
@ -356,7 +356,7 @@ hb_language_from_string (const char *str, int len)
|
||||
{
|
||||
/* NUL-terminate it. */
|
||||
char strbuf[64];
|
||||
len = MIN (len, (int) sizeof (strbuf) - 1);
|
||||
len = hb_min (len, (int) sizeof (strbuf) - 1);
|
||||
memcpy (strbuf, str, len);
|
||||
strbuf[len] = '\0';
|
||||
item = lang_find_or_insert (strbuf);
|
||||
@ -720,7 +720,7 @@ 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));
|
||||
unsigned int len = hb_min (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - *pp));
|
||||
strncpy (buf, *pp, len);
|
||||
buf[len] = '\0';
|
||||
|
||||
@ -744,7 +744,7 @@ static bool
|
||||
parse_uint32 (const char **pp, const char *end, uint32_t *pv)
|
||||
{
|
||||
char buf[32];
|
||||
unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - *pp));
|
||||
unsigned int len = hb_min (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - *pp));
|
||||
strncpy (buf, *pp, len);
|
||||
buf[len] = '\0';
|
||||
|
||||
@ -825,7 +825,7 @@ 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));
|
||||
unsigned int len = hb_min (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - *pp));
|
||||
strncpy (buf, *pp, len);
|
||||
buf[len] = '\0';
|
||||
|
||||
@ -1071,21 +1071,21 @@ hb_feature_to_string (hb_feature_t *feature,
|
||||
{
|
||||
s[len++] = '[';
|
||||
if (feature->start)
|
||||
len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->start));
|
||||
len += hb_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));
|
||||
len += hb_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));
|
||||
len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->value));
|
||||
}
|
||||
assert (len < ARRAY_LENGTH (s));
|
||||
len = MIN (len, size - 1);
|
||||
len = hb_min (len, size - 1);
|
||||
memcpy (buf, s, len);
|
||||
buf[len] = '\0';
|
||||
}
|
||||
@ -1152,20 +1152,21 @@ hb_variation_to_string (hb_variation_t *variation,
|
||||
while (len && s[len - 1] == ' ')
|
||||
len--;
|
||||
s[len++] = '=';
|
||||
len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%g", (double) variation->value));
|
||||
len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%g", (double) variation->value));
|
||||
|
||||
assert (len < ARRAY_LENGTH (s));
|
||||
len = MIN (len, size - 1);
|
||||
len = hb_min (len, size - 1);
|
||||
memcpy (buf, s, len);
|
||||
buf[len] = '\0';
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_color_get_alpha:
|
||||
* color: a #hb_color_t we are interested in its channels.
|
||||
*
|
||||
* Return value: Alpha channel value of the given color
|
||||
*
|
||||
*
|
||||
* Since: REPLACEME
|
||||
* Since: 2.1.0
|
||||
*/
|
||||
uint8_t
|
||||
(hb_color_get_alpha) (hb_color_t color)
|
||||
@ -1175,10 +1176,11 @@ uint8_t
|
||||
|
||||
/**
|
||||
* hb_color_get_red:
|
||||
* color: a #hb_color_t we are interested in its channels.
|
||||
*
|
||||
* Return value: Red channel value of the given color
|
||||
*
|
||||
*
|
||||
* Since: REPLACEME
|
||||
* Since: 2.1.0
|
||||
*/
|
||||
uint8_t
|
||||
(hb_color_get_red) (hb_color_t color)
|
||||
@ -1188,10 +1190,11 @@ uint8_t
|
||||
|
||||
/**
|
||||
* hb_color_get_green:
|
||||
* color: a #hb_color_t we are interested in its channels.
|
||||
*
|
||||
* Return value: Green channel value of the given color
|
||||
*
|
||||
*
|
||||
* Since: REPLACEME
|
||||
* Since: 2.1.0
|
||||
*/
|
||||
uint8_t
|
||||
(hb_color_get_green) (hb_color_t color)
|
||||
@ -1201,10 +1204,11 @@ uint8_t
|
||||
|
||||
/**
|
||||
* hb_color_get_blue:
|
||||
* color: a #hb_color_t we are interested in its channels.
|
||||
*
|
||||
* Return value: Blue channel value of the given color
|
||||
*
|
||||
*
|
||||
* Since: REPLACEME
|
||||
* Since: 2.1.0
|
||||
*/
|
||||
uint8_t
|
||||
(hb_color_get_blue) (hb_color_t color)
|
||||
|
131
src/hb-config.hh
Normal file
131
src/hb-config.hh
Normal file
@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright © 2019 Facebook, 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.
|
||||
*
|
||||
* Facebook Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
#ifndef HB_CONFIG_HH
|
||||
#define HB_CONFIG_HH
|
||||
|
||||
#if 0 /* Make test happy. */
|
||||
#include "hb.hh"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef HB_TINY
|
||||
#define HB_LEAN
|
||||
#define HB_MINI
|
||||
#define HB_NO_MT
|
||||
#ifndef NDEBUG
|
||||
#define NDEBUG
|
||||
#endif
|
||||
#ifndef __OPTIMIZE_SIZE__
|
||||
#define __OPTIMIZE_SIZE__
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef HB_LEAN
|
||||
#define HB_DISABLE_DEPRECATED
|
||||
#define HB_NDEBUG
|
||||
#define HB_NO_ATEXIT
|
||||
#define HB_NO_BUFFER_MESSAGE
|
||||
#define HB_NO_BUFFER_SERIALIZE
|
||||
#define HB_NO_BITMAP
|
||||
#define HB_NO_CFF
|
||||
#define HB_NO_COLOR
|
||||
#define HB_NO_GETENV
|
||||
#define HB_NO_LAYOUT_UNUSED
|
||||
#define HB_NO_MATH
|
||||
#define HB_NO_NAME
|
||||
#define HB_NO_SUBSET_LAYOUT
|
||||
#endif
|
||||
|
||||
#ifdef HB_MINI
|
||||
#define HB_NO_AAT
|
||||
#define HB_NO_LEGACY
|
||||
#endif
|
||||
|
||||
/* Closure. */
|
||||
|
||||
#ifdef HB_DISABLE_DEPRECATED
|
||||
#define HB_IF_NOT_DEPRECATED(x)
|
||||
#else
|
||||
#define HB_IF_NOT_DEPRECATED(x) x
|
||||
#endif
|
||||
|
||||
#ifdef HB_NO_AAT
|
||||
#define HB_NO_OT_NAME_LANGUAGE_AAT
|
||||
#define HB_NO_SHAPE_AAT
|
||||
#endif
|
||||
|
||||
#ifdef HB_NO_BITMAP
|
||||
#define HB_NO_OT_FONT_BITMAP
|
||||
#endif
|
||||
|
||||
#ifdef HB_NO_CFF
|
||||
#define HB_NO_OT_FONT_CFF
|
||||
#define HB_NO_SUBSET_CFF
|
||||
#endif
|
||||
|
||||
#ifdef HB_NO_GETENV
|
||||
#define HB_NO_UNISCRIBE_BUG_COMPATIBLE
|
||||
#endif
|
||||
|
||||
#ifdef HB_NO_LEGACY
|
||||
#define HB_NO_OT_LAYOUT_BLACKLIST
|
||||
#define HB_NO_OT_SHAPE_FALLBACK
|
||||
#endif
|
||||
|
||||
#ifdef HB_NO_NAME
|
||||
#define HB_NO_OT_NAME_LANGUAGE
|
||||
#endif
|
||||
|
||||
#ifdef HB_NO_OT_SHAPE_FALLBACK
|
||||
#define HB_NO_OT_SHAPE_COMPLEX_ARABIC_FALLBACK
|
||||
#define HB_NO_OT_SHAPE_COMPLEX_HEBREW_FALLBACK
|
||||
#define HB_NO_OT_SHAPE_COMPLEX_THAI_FALLBACK
|
||||
#define HB_NO_OT_SHAPE_COMPLEX_VOWEL_CONSTRAINTS
|
||||
#endif
|
||||
|
||||
#ifdef NDEBUG
|
||||
#ifndef HB_NDEBUG
|
||||
#define HB_NDEBUG
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __OPTIMIZE_SIZE__
|
||||
#ifndef HB_OPTIMIZE_SIZE
|
||||
#define HB_OPTIMIZE_SIZE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CONFIG_OVERRIDE_H
|
||||
#include "config-override.h"
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* HB_CONFIG_HH */
|
@ -55,13 +55,13 @@ coretext_font_size_from_ptem (float ptem)
|
||||
* https://developer.apple.com/library/content/documentation/GraphicsAnimation/Conceptual/HighResolutionOSX/Explained/Explained.html
|
||||
*/
|
||||
ptem *= 96.f / 72.f;
|
||||
return ptem <= 0.f ? HB_CORETEXT_DEFAULT_FONT_SIZE : ptem;
|
||||
return (CGFloat) (ptem <= 0.f ? HB_CORETEXT_DEFAULT_FONT_SIZE : ptem);
|
||||
}
|
||||
static float
|
||||
coretext_font_size_to_ptem (CGFloat size)
|
||||
{
|
||||
size *= 72.f / 96.f;
|
||||
return size <= 0.f ? 0 : size;
|
||||
size *= 72. / 96.;
|
||||
return size <= 0 ? 0 : size;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -598,7 +598,7 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
|
||||
} else {
|
||||
active_feature_t *feature = active_features.find (&event->feature);
|
||||
if (feature)
|
||||
active_features.remove (feature - active_features.arrayZ ());
|
||||
active_features.remove (feature - active_features.arrayZ);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -608,7 +608,7 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
|
||||
|
||||
#define ALLOCATE_ARRAY(Type, name, len, on_no_room) \
|
||||
Type *name = (Type *) scratch; \
|
||||
{ \
|
||||
do { \
|
||||
unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch)); \
|
||||
if (unlikely (_consumed > scratch_size)) \
|
||||
{ \
|
||||
@ -617,7 +617,7 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
|
||||
} \
|
||||
scratch += _consumed; \
|
||||
scratch_size -= _consumed; \
|
||||
}
|
||||
} while (0)
|
||||
|
||||
ALLOCATE_ARRAY (UniChar, pchars, buffer->len * 2, /*nothing*/);
|
||||
unsigned int chars_len = 0;
|
||||
@ -771,7 +771,7 @@ resize_and_retry:
|
||||
feature.start < chars_len && feature.start < feature.end)
|
||||
{
|
||||
CFRange feature_range = CFRangeMake (feature.start,
|
||||
MIN (feature.end, chars_len) - feature.start);
|
||||
hb_min (feature.end, chars_len) - feature.start);
|
||||
if (feature.value)
|
||||
CFAttributedStringRemoveAttribute (attr_string, feature_range, kCTKernAttributeName);
|
||||
else
|
||||
@ -1116,7 +1116,7 @@ resize_and_retry:
|
||||
unsigned int cluster = info[count - 1].cluster;
|
||||
for (unsigned int i = count - 1; i > 0; i--)
|
||||
{
|
||||
cluster = MIN (cluster, info[i - 1].cluster);
|
||||
cluster = hb_min (cluster, info[i - 1].cluster);
|
||||
info[i - 1].cluster = cluster;
|
||||
}
|
||||
}
|
||||
@ -1125,7 +1125,7 @@ resize_and_retry:
|
||||
unsigned int cluster = info[0].cluster;
|
||||
for (unsigned int i = 1; i < count; i++)
|
||||
{
|
||||
cluster = MIN (cluster, info[i].cluster);
|
||||
cluster = hb_min (cluster, info[i].cluster);
|
||||
info[i].cluster = cluster;
|
||||
}
|
||||
}
|
||||
|
@ -63,7 +63,7 @@ extern HB_INTERNAL hb_atomic_int_t _hb_options;
|
||||
static inline hb_options_t
|
||||
hb_options ()
|
||||
{
|
||||
#if defined(HB_NO_OPTIONS)
|
||||
#ifdef HB_NO_GETENV
|
||||
return hb_options_t ();
|
||||
#endif
|
||||
/* Make a local copy, so we can access bitfield threadsafely. */
|
||||
@ -161,7 +161,7 @@ _hb_debug_msg_va (const char *what,
|
||||
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) - 1, (unsigned int) (sizeof (VBAR) - 1) * level),
|
||||
bars + sizeof (bars) - 1 - hb_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);
|
||||
@ -249,8 +249,8 @@ struct hb_printer_t<bool> {
|
||||
};
|
||||
|
||||
template <>
|
||||
struct hb_printer_t<hb_void_t> {
|
||||
const char *print (hb_void_t) { return ""; }
|
||||
struct hb_printer_t<hb_empty_t> {
|
||||
const char *print (hb_empty_t) { return ""; }
|
||||
};
|
||||
|
||||
|
||||
@ -266,7 +266,7 @@ static inline void _hb_warn_no_return (bool returned)
|
||||
}
|
||||
}
|
||||
template <>
|
||||
/*static*/ inline void _hb_warn_no_return<hb_void_t> (bool returned HB_UNUSED)
|
||||
/*static*/ inline void _hb_warn_no_return<hb_empty_t> (bool returned HB_UNUSED)
|
||||
{}
|
||||
|
||||
template <int max_level, typename ret_t>
|
||||
@ -330,18 +330,20 @@ struct hb_auto_trace_t<0, ret_t>
|
||||
const char *message,
|
||||
...) HB_PRINTF_FUNC(6, 7) {}
|
||||
|
||||
ret_t ret (ret_t v,
|
||||
const char *func HB_UNUSED = nullptr,
|
||||
unsigned int line HB_UNUSED = 0) { return v; }
|
||||
template <typename T>
|
||||
T ret (T&& v,
|
||||
const char *func HB_UNUSED = nullptr,
|
||||
unsigned int line HB_UNUSED = 0) { return hb_forward<T> (v); }
|
||||
};
|
||||
|
||||
/* For disabled tracing; optimize out everything.
|
||||
* https://github.com/harfbuzz/harfbuzz/pull/605 */
|
||||
template <typename ret_t>
|
||||
struct hb_no_trace_t {
|
||||
ret_t ret (ret_t v,
|
||||
const char *func HB_UNUSED = "",
|
||||
unsigned int line HB_UNUSED = 0) { return v; }
|
||||
template <typename T>
|
||||
T ret (T&& v,
|
||||
const char *func HB_UNUSED = nullptr,
|
||||
unsigned int line HB_UNUSED = 0) { return hb_forward<T> (v); }
|
||||
};
|
||||
|
||||
#define return_trace(RET) return trace.ret (RET, HB_FUNC, __LINE__)
|
||||
|
@ -63,7 +63,7 @@ typedef hb_bool_t (*hb_font_get_glyph_func_t) (hb_font_t *font, void *font_data,
|
||||
hb_codepoint_t *glyph,
|
||||
void *user_data);
|
||||
|
||||
HB_EXTERN HB_DEPRECATED_FOR(hb_font_funcs_set_nominal_glyph_func or hb_font_funcs_set_variation_glyph_func) void
|
||||
HB_EXTERN HB_DEPRECATED_FOR(hb_font_funcs_set_nominal_glyph_func and hb_font_funcs_set_variation_glyph_func) void
|
||||
hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs,
|
||||
hb_font_get_glyph_func_t func,
|
||||
void *user_data, hb_destroy_func_t destroy);
|
||||
|
@ -530,12 +530,12 @@ _hb_directwrite_shape_full (hb_shape_plan_t *shape_plan,
|
||||
hb_buffer_t::scratch_buffer_t *scratch = buffer->get_scratch_buffer (&scratch_size);
|
||||
#define ALLOCATE_ARRAY(Type, name, len) \
|
||||
Type *name = (Type *) scratch; \
|
||||
{ \
|
||||
do { \
|
||||
unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch)); \
|
||||
assert (_consumed <= scratch_size); \
|
||||
scratch += _consumed; \
|
||||
scratch_size -= _consumed; \
|
||||
}
|
||||
} while (0)
|
||||
|
||||
#define utf16_index() var1.u32
|
||||
|
||||
@ -778,7 +778,7 @@ retry_getglyphs:
|
||||
{
|
||||
uint32_t *p =
|
||||
&vis_clusters[log_clusters[buffer->info[i].utf16_index ()]];
|
||||
*p = MIN (*p, buffer->info[i].cluster);
|
||||
*p = hb_min (*p, buffer->info[i].cluster);
|
||||
}
|
||||
for (unsigned int i = 1; i < glyphCount; i++)
|
||||
if (vis_clusters[i] == (uint32_t) -1)
|
||||
@ -930,7 +930,9 @@ _hb_directwrite_font_release (void *data)
|
||||
|
||||
/**
|
||||
* hb_directwrite_face_create:
|
||||
* @font_face:
|
||||
* @font_face: a DirectWrite IDWriteFontFace object.
|
||||
*
|
||||
* Return value: #hb_face_t object corresponding to the given input
|
||||
*
|
||||
* Since: 2.4.0
|
||||
**/
|
||||
@ -945,9 +947,11 @@ hb_directwrite_face_create (IDWriteFontFace *font_face)
|
||||
|
||||
/**
|
||||
* hb_directwrite_face_get_font_face:
|
||||
* @face:
|
||||
* @face: a #hb_face_t object
|
||||
*
|
||||
* Since: REPLACEME
|
||||
* Return value: DirectWrite IDWriteFontFace object corresponding to the given input
|
||||
*
|
||||
* Since: 2.5.0
|
||||
**/
|
||||
IDWriteFontFace *
|
||||
hb_directwrite_face_get_font_face (hb_face_t *face)
|
||||
|
@ -38,10 +38,18 @@
|
||||
template <typename Context, typename Return, unsigned int MaxDebugDepth>
|
||||
struct hb_dispatch_context_t
|
||||
{
|
||||
private:
|
||||
/* https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern */
|
||||
const Context* thiz () const { return static_cast<const Context *> (this); }
|
||||
Context* thiz () { return static_cast< Context *> (this); }
|
||||
public:
|
||||
static constexpr unsigned max_debug_depth = MaxDebugDepth;
|
||||
typedef Return return_t;
|
||||
template <typename T, typename F>
|
||||
bool may_dispatch (const T *obj HB_UNUSED, const F *format HB_UNUSED) { return true; }
|
||||
template <typename T, typename ...Ts>
|
||||
return_t dispatch (const T &obj, Ts&&... ds)
|
||||
{ return obj.dispatch (thiz (), hb_forward<Ts> (ds)...); }
|
||||
static return_t no_dispatch_return_value () { return Context::default_return_value (); }
|
||||
static bool stop_sublookup_iteration (const return_t r HB_UNUSED) { return false; }
|
||||
};
|
||||
|
@ -336,6 +336,7 @@ hb_font_get_glyph_v_origin_default (hb_font_t *font,
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifndef HB_DISABLE_DEPRECATED
|
||||
static hb_position_t
|
||||
hb_font_get_glyph_h_kerning_nil (hb_font_t *font HB_UNUSED,
|
||||
void *font_data HB_UNUSED,
|
||||
@ -373,6 +374,7 @@ hb_font_get_glyph_v_kerning_default (hb_font_t *font,
|
||||
{
|
||||
return font->parent_scale_y_distance (font->parent->get_glyph_v_kerning (top_glyph, bottom_glyph));
|
||||
}
|
||||
#endif
|
||||
|
||||
static hb_bool_t
|
||||
hb_font_get_glyph_extents_nil (hb_font_t *font HB_UNUSED,
|
||||
@ -925,6 +927,7 @@ hb_font_get_glyph_v_origin (hb_font_t *font,
|
||||
return font->get_glyph_v_origin (glyph, x, y);
|
||||
}
|
||||
|
||||
#ifndef HB_DISABLE_DEPRECATED
|
||||
/**
|
||||
* hb_font_get_glyph_h_kerning:
|
||||
* @font: a font.
|
||||
@ -964,6 +967,7 @@ hb_font_get_glyph_v_kerning (hb_font_t *font,
|
||||
{
|
||||
return font->get_glyph_v_kerning (top_glyph, bottom_glyph);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* hb_font_get_glyph_extents:
|
||||
@ -1173,6 +1177,7 @@ hb_font_subtract_glyph_origin_for_direction (hb_font_t *font,
|
||||
return font->subtract_glyph_origin_for_direction (glyph, direction, x, y);
|
||||
}
|
||||
|
||||
#ifndef HB_DISABLE_DEPRECATED
|
||||
/**
|
||||
* hb_font_get_glyph_kerning_for_direction:
|
||||
* @font: a font.
|
||||
@ -1195,6 +1200,7 @@ hb_font_get_glyph_kerning_for_direction (hb_font_t *font,
|
||||
{
|
||||
return font->get_glyph_kerning_for_direction (first_glyph, second_glyph, direction, x, y);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* hb_font_get_glyph_extents_for_origin:
|
||||
@ -1347,7 +1353,7 @@ hb_font_create (hb_face_t *face)
|
||||
{
|
||||
hb_font_t *font = _hb_font_create (face);
|
||||
|
||||
#if !defined(HB_NO_OT_FONT)
|
||||
#ifndef HB_NO_OT_FONT
|
||||
/* Install our in-house, very lightweight, funcs. */
|
||||
hb_ot_font_set_funcs (font);
|
||||
#endif
|
||||
@ -1916,6 +1922,7 @@ hb_font_get_var_coords_normalized (hb_font_t *font,
|
||||
}
|
||||
|
||||
|
||||
#ifndef HB_DISABLE_DEPRECATED
|
||||
/*
|
||||
* Deprecated get_glyph_func():
|
||||
*/
|
||||
@ -2038,3 +2045,4 @@ hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs,
|
||||
trampoline,
|
||||
trampoline_destroy);
|
||||
}
|
||||
#endif
|
||||
|
@ -51,8 +51,8 @@
|
||||
HB_FONT_FUNC_IMPLEMENT (glyph_v_advances) \
|
||||
HB_FONT_FUNC_IMPLEMENT (glyph_h_origin) \
|
||||
HB_FONT_FUNC_IMPLEMENT (glyph_v_origin) \
|
||||
HB_FONT_FUNC_IMPLEMENT (glyph_h_kerning) \
|
||||
HB_FONT_FUNC_IMPLEMENT (glyph_v_kerning) \
|
||||
HB_IF_NOT_DEPRECATED (HB_FONT_FUNC_IMPLEMENT (glyph_h_kerning)) \
|
||||
HB_IF_NOT_DEPRECATED (HB_FONT_FUNC_IMPLEMENT (glyph_v_kerning)) \
|
||||
HB_FONT_FUNC_IMPLEMENT (glyph_extents) \
|
||||
HB_FONT_FUNC_IMPLEMENT (glyph_contour_point) \
|
||||
HB_FONT_FUNC_IMPLEMENT (glyph_name) \
|
||||
@ -304,17 +304,25 @@ struct hb_font_t
|
||||
hb_position_t get_glyph_h_kerning (hb_codepoint_t left_glyph,
|
||||
hb_codepoint_t right_glyph)
|
||||
{
|
||||
#ifdef HB_DISABLE_DEPRECATED
|
||||
return 0;
|
||||
#else
|
||||
return klass->get.f.glyph_h_kerning (this, user_data,
|
||||
left_glyph, right_glyph,
|
||||
klass->user_data.glyph_h_kerning);
|
||||
#endif
|
||||
}
|
||||
|
||||
hb_position_t get_glyph_v_kerning (hb_codepoint_t top_glyph,
|
||||
hb_codepoint_t bottom_glyph)
|
||||
{
|
||||
#ifdef HB_DISABLE_DEPRECATED
|
||||
return 0;
|
||||
#else
|
||||
return klass->get.f.glyph_v_kerning (this, user_data,
|
||||
top_glyph, bottom_glyph,
|
||||
klass->user_data.glyph_v_kerning);
|
||||
#endif
|
||||
}
|
||||
|
||||
hb_bool_t get_glyph_extents (hb_codepoint_t glyph,
|
||||
@ -607,7 +615,7 @@ struct hb_font_t
|
||||
return (hb_position_t) (scaled / upem);
|
||||
}
|
||||
hb_position_t em_scalef (float v, int scale)
|
||||
{ return (hb_position_t) round (v * scale / face->get_upem ()); }
|
||||
{ return (hb_position_t) roundf (v * scale / face->get_upem ()); }
|
||||
float em_fscale (int16_t v, int scale)
|
||||
{ return (float) v * scale / face->get_upem (); }
|
||||
};
|
||||
|
@ -439,7 +439,7 @@ hb_ft_get_glyph_from_name (hb_font_t *font HB_UNUSED,
|
||||
else {
|
||||
/* Make a nul-terminated version. */
|
||||
char buf[128];
|
||||
len = MIN (len, (int) sizeof (buf) - 1);
|
||||
len = hb_min (len, (int) sizeof (buf) - 1);
|
||||
strncpy (buf, name, len);
|
||||
buf[len] = '\0';
|
||||
*glyph = FT_Get_Name_Index (ft_face, buf);
|
||||
|
@ -202,6 +202,7 @@ _hb_graphite2_shaper_font_data_destroy (hb_graphite2_font_data_t *data HB_UNUSED
|
||||
{
|
||||
}
|
||||
|
||||
#ifndef HB_DISABLE_DEPRECATED
|
||||
/**
|
||||
* hb_graphite2_font_get_gr_font:
|
||||
*
|
||||
@ -213,6 +214,7 @@ hb_graphite2_font_get_gr_font (hb_font_t *font HB_UNUSED)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
@ -308,12 +310,12 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan HB_UNUSED,
|
||||
|
||||
#define ALLOCATE_ARRAY(Type, name, len) \
|
||||
Type *name = (Type *) scratch; \
|
||||
{ \
|
||||
do { \
|
||||
unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch)); \
|
||||
assert (_consumed <= scratch_size); \
|
||||
scratch += _consumed; \
|
||||
scratch_size -= _consumed; \
|
||||
}
|
||||
} while (0)
|
||||
|
||||
ALLOCATE_ARRAY (hb_graphite2_cluster_t, clusters, buffer->len);
|
||||
ALLOCATE_ARRAY (hb_codepoint_t, gids, glyph_count);
|
||||
|
@ -49,6 +49,9 @@
|
||||
* Functions for using HarfBuzz with the ICU library to provide Unicode data.
|
||||
**/
|
||||
|
||||
/* ICU doesn't do-while(0) around their statements. Ugh!
|
||||
* https://unicode-org.atlassian.net/browse/CLDR-13027 */
|
||||
#define HB_ICU_STMT(S) do { S } while (0)
|
||||
|
||||
hb_script_t
|
||||
hb_icu_script_to_script (UScriptCode script)
|
||||
@ -183,9 +186,9 @@ hb_icu_unicode_compose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
|
||||
|
||||
len = 0;
|
||||
err = false;
|
||||
U16_APPEND (utf16, len, ARRAY_LENGTH (utf16), a, err);
|
||||
HB_ICU_STMT (U16_APPEND (utf16, len, ARRAY_LENGTH (utf16), a, err));
|
||||
if (err) return false;
|
||||
U16_APPEND (utf16, len, ARRAY_LENGTH (utf16), b, err);
|
||||
HB_ICU_STMT (U16_APPEND (utf16, len, ARRAY_LENGTH (utf16), b, err));
|
||||
if (err) return false;
|
||||
|
||||
icu_err = U_ZERO_ERROR;
|
||||
@ -193,7 +196,7 @@ hb_icu_unicode_compose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
|
||||
if (U_FAILURE (icu_err))
|
||||
return false;
|
||||
if (u_countChar32 (normalized, len) == 1) {
|
||||
U16_GET_UNSAFE (normalized, 0, *ab);
|
||||
HB_ICU_STMT (U16_GET_UNSAFE (normalized, 0, *ab));
|
||||
ret = true;
|
||||
} else {
|
||||
ret = false;
|
||||
@ -221,13 +224,13 @@ hb_icu_unicode_decompose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
|
||||
|
||||
len = u_countChar32 (decomposed, len);
|
||||
if (len == 1) {
|
||||
U16_GET_UNSAFE (decomposed, 0, *a);
|
||||
HB_ICU_STMT (U16_GET_UNSAFE (decomposed, 0, *a));
|
||||
*b = 0;
|
||||
return *a != ab;
|
||||
} else if (len == 2) {
|
||||
len =0;
|
||||
U16_NEXT_UNSAFE (decomposed, len, *a);
|
||||
U16_NEXT_UNSAFE (decomposed, len, *b);
|
||||
HB_ICU_STMT (U16_NEXT_UNSAFE (decomposed, len, *a));
|
||||
HB_ICU_STMT (U16_NEXT_UNSAFE (decomposed, len, *b));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -236,7 +239,7 @@ hb_icu_unicode_decompose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
|
||||
/* We don't ifdef-out the fallback code such that compiler always
|
||||
* sees it and makes sure it's compilable. */
|
||||
|
||||
UChar utf16[2], normalized[2 * HB_UNICODE_MAX_DECOMPOSITION_LEN + 1];
|
||||
UChar utf16[2], normalized[2 * 19/*HB_UNICODE_MAX_DECOMPOSITION_LEN*/ + 1];
|
||||
unsigned int len;
|
||||
hb_bool_t ret, err;
|
||||
UErrorCode icu_err;
|
||||
@ -247,7 +250,7 @@ hb_icu_unicode_decompose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
|
||||
|
||||
len = 0;
|
||||
err = false;
|
||||
U16_APPEND (utf16, len, ARRAY_LENGTH (utf16), ab, err);
|
||||
HB_ICU_STMT (U16_APPEND (utf16, len, ARRAY_LENGTH (utf16), ab, err));
|
||||
if (err) return false;
|
||||
|
||||
icu_err = U_ZERO_ERROR;
|
||||
@ -258,13 +261,13 @@ hb_icu_unicode_decompose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
|
||||
len = u_countChar32 (normalized, len);
|
||||
|
||||
if (len == 1) {
|
||||
U16_GET_UNSAFE (normalized, 0, *a);
|
||||
HB_ICU_STMT (U16_GET_UNSAFE (normalized, 0, *a));
|
||||
*b = 0;
|
||||
ret = *a != ab;
|
||||
} else if (len == 2) {
|
||||
len =0;
|
||||
U16_NEXT_UNSAFE (normalized, len, *a);
|
||||
U16_NEXT_UNSAFE (normalized, len, *b);
|
||||
HB_ICU_STMT (U16_NEXT_UNSAFE (normalized, len, *a));
|
||||
HB_ICU_STMT (U16_NEXT_UNSAFE (normalized, len, *b));
|
||||
|
||||
/* Here's the ugly part: if ab decomposes to a single character and
|
||||
* that character decomposes again, we have to detect that and undo
|
||||
@ -275,7 +278,7 @@ hb_icu_unicode_decompose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
|
||||
if (U_FAILURE (icu_err))
|
||||
return false;
|
||||
hb_codepoint_t c;
|
||||
U16_GET_UNSAFE (recomposed, 0, c);
|
||||
HB_ICU_STMT (U16_GET_UNSAFE (recomposed, 0, c));
|
||||
if (c != *a && c != ab) {
|
||||
*a = c;
|
||||
*b = 0;
|
||||
@ -284,7 +287,7 @@ hb_icu_unicode_decompose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
|
||||
} else {
|
||||
/* If decomposed to more than two characters, take the last one,
|
||||
* and recompose the rest to get the first component. */
|
||||
U16_PREV_UNSAFE (normalized, len, *b); /* Changes len in-place. */
|
||||
HB_ICU_STMT (U16_PREV_UNSAFE (normalized, len, *b)); /* Changes len in-place. */
|
||||
UChar recomposed[18 * 2];
|
||||
icu_err = U_ZERO_ERROR;
|
||||
len = unorm2_normalize (unorm2_getNFCInstance (&icu_err), normalized, len, recomposed, ARRAY_LENGTH (recomposed), &icu_err);
|
||||
@ -293,7 +296,7 @@ hb_icu_unicode_decompose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
|
||||
/* We expect that recomposed has exactly one character now. */
|
||||
if (unlikely (u_countChar32 (recomposed, len) != 1))
|
||||
return false;
|
||||
U16_GET_UNSAFE (recomposed, 0, *a);
|
||||
HB_ICU_STMT (U16_GET_UNSAFE (recomposed, 0, *a));
|
||||
ret = true;
|
||||
}
|
||||
|
||||
|
550
src/hb-iter.hh
550
src/hb-iter.hh
@ -42,9 +42,19 @@
|
||||
* copied by value. If the collection / object being iterated on
|
||||
* is writable, then the iterator returns lvalues, otherwise it
|
||||
* returns rvalues.
|
||||
*
|
||||
* TODO Document more.
|
||||
*
|
||||
* If iterator implementation implements operator!=, then can be
|
||||
* used in range-based for loop. That comes free if the iterator
|
||||
* is random-access. Otherwise, the range-based for loop incurs
|
||||
* one traversal to find end(), which can be avoided if written
|
||||
* as a while-style for loop, or if iterator implements a faster
|
||||
* __end__() method.
|
||||
* TODO When opting in for C++17, address this by changing return
|
||||
* type of .end()?
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Base classes for iterators.
|
||||
*/
|
||||
@ -72,10 +82,13 @@ struct hb_iter_t
|
||||
/* Operators. */
|
||||
iter_t iter () const { return *thiz(); }
|
||||
iter_t operator + () const { return *thiz(); }
|
||||
iter_t begin () const { return *thiz(); }
|
||||
iter_t end () const { return thiz()->__end__ (); }
|
||||
explicit operator bool () const { return thiz()->__more__ (); }
|
||||
unsigned len () const { return thiz()->__len__ (); }
|
||||
/* The following can only be enabled if item_t is reference type. Otherwise
|
||||
* it will be returning pointer to temporary rvalue. */
|
||||
* it will be returning pointer to temporary rvalue.
|
||||
* TODO Use a wrapper return type to fix for non-reference type. */
|
||||
template <typename T = item_t,
|
||||
hb_enable_if (hb_is_reference (T))>
|
||||
hb_remove_reference<item_t>* operator -> () const { return hb_addressof (**thiz()); }
|
||||
@ -83,30 +96,40 @@ struct hb_iter_t
|
||||
item_t operator * () { return thiz()->__item__ (); }
|
||||
item_t operator [] (unsigned i) const { return thiz()->__item_at__ (i); }
|
||||
item_t operator [] (unsigned i) { return thiz()->__item_at__ (i); }
|
||||
iter_t& operator += (unsigned count) { thiz()->__forward__ (count); return *thiz(); }
|
||||
iter_t& operator ++ () { thiz()->__next__ (); return *thiz(); }
|
||||
iter_t& operator -= (unsigned count) { thiz()->__rewind__ (count); return *thiz(); }
|
||||
iter_t& operator -- () { thiz()->__prev__ (); return *thiz(); }
|
||||
iter_t& operator += (unsigned count) & { thiz()->__forward__ (count); return *thiz(); }
|
||||
iter_t operator += (unsigned count) && { thiz()->__forward__ (count); return *thiz(); }
|
||||
iter_t& operator ++ () & { thiz()->__next__ (); return *thiz(); }
|
||||
iter_t operator ++ () && { thiz()->__next__ (); return *thiz(); }
|
||||
iter_t& operator -= (unsigned count) & { thiz()->__rewind__ (count); return *thiz(); }
|
||||
iter_t operator -= (unsigned count) && { thiz()->__rewind__ (count); return *thiz(); }
|
||||
iter_t& operator -- () & { thiz()->__prev__ (); return *thiz(); }
|
||||
iter_t operator -- () && { thiz()->__prev__ (); return *thiz(); }
|
||||
iter_t operator + (unsigned count) const { auto c = thiz()->iter (); c += count; return c; }
|
||||
friend iter_t operator + (unsigned count, const iter_t &it) { return it + count; }
|
||||
iter_t operator ++ (int) { iter_t c (*thiz()); ++*thiz(); return c; }
|
||||
iter_t operator - (unsigned count) const { auto c = thiz()->iter (); c -= count; return c; }
|
||||
iter_t operator -- (int) { iter_t c (*thiz()); --*thiz(); return c; }
|
||||
template <typename T>
|
||||
iter_t& operator >> (T &v) { v = **thiz(); ++*thiz(); return *thiz(); }
|
||||
iter_t& operator >> (T &v) & { v = **thiz(); ++*thiz(); return *thiz(); }
|
||||
template <typename T>
|
||||
iter_t& operator >> (T &v) const { v = **thiz(); ++*thiz(); return *thiz(); }
|
||||
iter_t operator >> (T &v) && { v = **thiz(); ++*thiz(); return *thiz(); }
|
||||
template <typename T>
|
||||
iter_t& operator << (const T v) { **thiz() = v; ++*thiz(); return *thiz(); }
|
||||
iter_t& operator << (const T v) & { **thiz() = v; ++*thiz(); return *thiz(); }
|
||||
template <typename T>
|
||||
iter_t operator << (const T v) && { **thiz() = v; ++*thiz(); return *thiz(); }
|
||||
|
||||
protected:
|
||||
hb_iter_t () {}
|
||||
hb_iter_t (const hb_iter_t &o HB_UNUSED) {}
|
||||
void operator = (const hb_iter_t &o HB_UNUSED) {}
|
||||
hb_iter_t () = default;
|
||||
hb_iter_t (const hb_iter_t &o HB_UNUSED) = default;
|
||||
hb_iter_t (hb_iter_t &&o HB_UNUSED) = default;
|
||||
hb_iter_t& operator = (const hb_iter_t &o HB_UNUSED) = default;
|
||||
hb_iter_t& operator = (hb_iter_t &&o HB_UNUSED) = default;
|
||||
};
|
||||
|
||||
#define HB_ITER_USING(Name) \
|
||||
using item_t = typename Name::item_t; \
|
||||
using Name::begin; \
|
||||
using Name::end; \
|
||||
using Name::item_size; \
|
||||
using Name::is_iterator; \
|
||||
using Name::iter; \
|
||||
@ -125,18 +148,20 @@ struct hb_iter_t
|
||||
using Name::operator <<; \
|
||||
static_assert (true, "")
|
||||
|
||||
/* Returns iterator type of a type. */
|
||||
#define hb_iter_t(Iterable) decltype (hb_declval (Iterable).iter ())
|
||||
/* Returns iterator / item type of a type. */
|
||||
template <typename Iterable>
|
||||
using hb_iter_type = decltype (hb_deref (hb_declval (Iterable)).iter ());
|
||||
template <typename Iterable>
|
||||
using hb_item_type = decltype (*hb_deref (hb_declval (Iterable)).iter ());
|
||||
|
||||
|
||||
template <typename> struct hb_array_t;
|
||||
|
||||
struct
|
||||
{
|
||||
template <typename T>
|
||||
hb_iter_t (T)
|
||||
template <typename T> hb_iter_type<T>
|
||||
operator () (T&& c) const
|
||||
{ return c.iter (); }
|
||||
{ return hb_deref (hb_forward<T> (c)).iter (); }
|
||||
|
||||
/* Specialization for C arrays. */
|
||||
|
||||
@ -148,8 +173,8 @@ struct
|
||||
operator () (Type (&array)[length]) const
|
||||
{ return hb_array_t<Type> (array, length); }
|
||||
|
||||
} HB_FUNCOBJ (hb_iter);
|
||||
|
||||
}
|
||||
HB_FUNCOBJ (hb_iter);
|
||||
|
||||
/* Mixin to fill in what the subclass doesn't provide. */
|
||||
template <typename iter_t, typename item_t = typename iter_t::__item_t__>
|
||||
@ -166,22 +191,36 @@ struct hb_iter_fallback_mixin_t
|
||||
item_t __item_at__ (unsigned i) const { return *(*thiz() + i); }
|
||||
|
||||
/* Termination: Implement __more__(), or __len__() if random-access. */
|
||||
bool __more__ () const { return thiz()->len (); }
|
||||
bool __more__ () const { return bool (thiz()->len ()); }
|
||||
unsigned __len__ () const
|
||||
{ iter_t c (*thiz()); unsigned l = 0; while (c) { c++; l++; }; return l; }
|
||||
{ iter_t c (*thiz()); unsigned l = 0; while (c) { c++; l++; } return l; }
|
||||
|
||||
/* Advancing: Implement __next__(), or __forward__() if random-access. */
|
||||
void __next__ () { *thiz() += 1; }
|
||||
void __forward__ (unsigned n) { while (n--) ++*thiz(); }
|
||||
void __forward__ (unsigned n) { while (*thiz() && n--) ++*thiz(); }
|
||||
|
||||
/* Rewinding: Implement __prev__() or __rewind__() if bidirectional. */
|
||||
void __prev__ () { *thiz() -= 1; }
|
||||
void __rewind__ (unsigned n) { while (n--) --*thiz(); }
|
||||
void __rewind__ (unsigned n) { while (*thiz() && n--) --*thiz(); }
|
||||
|
||||
/* Range-based for: Implement __end__() if can be done faster,
|
||||
* and operator!=. */
|
||||
iter_t __end__ () const
|
||||
{
|
||||
if (thiz()->is_random_access_iterator)
|
||||
return *thiz() + thiz()->len ();
|
||||
/* Above expression loops twice. Following loops once. */
|
||||
auto it = *thiz();
|
||||
while (it) ++it;
|
||||
return it;
|
||||
}
|
||||
|
||||
protected:
|
||||
hb_iter_fallback_mixin_t () {}
|
||||
hb_iter_fallback_mixin_t (const hb_iter_fallback_mixin_t &o HB_UNUSED) {}
|
||||
void operator = (const hb_iter_fallback_mixin_t &o HB_UNUSED) {}
|
||||
hb_iter_fallback_mixin_t () = default;
|
||||
hb_iter_fallback_mixin_t (const hb_iter_fallback_mixin_t &o HB_UNUSED) = default;
|
||||
hb_iter_fallback_mixin_t (hb_iter_fallback_mixin_t &&o HB_UNUSED) = default;
|
||||
hb_iter_fallback_mixin_t& operator = (const hb_iter_fallback_mixin_t &o HB_UNUSED) = default;
|
||||
hb_iter_fallback_mixin_t& operator = (hb_iter_fallback_mixin_t &&o HB_UNUSED) = default;
|
||||
};
|
||||
|
||||
template <typename iter_t, typename item_t = typename iter_t::__item_t__>
|
||||
@ -190,17 +229,32 @@ struct hb_iter_with_fallback_t :
|
||||
hb_iter_fallback_mixin_t<iter_t, item_t>
|
||||
{
|
||||
protected:
|
||||
hb_iter_with_fallback_t () {}
|
||||
hb_iter_with_fallback_t (const hb_iter_with_fallback_t &o HB_UNUSED) :
|
||||
hb_iter_t<iter_t, item_t> (o),
|
||||
hb_iter_fallback_mixin_t<iter_t, item_t> (o) {}
|
||||
void operator = (const hb_iter_with_fallback_t &o HB_UNUSED) {}
|
||||
hb_iter_with_fallback_t () = default;
|
||||
hb_iter_with_fallback_t (const hb_iter_with_fallback_t &o HB_UNUSED) = default;
|
||||
hb_iter_with_fallback_t (hb_iter_with_fallback_t &&o HB_UNUSED) = default;
|
||||
hb_iter_with_fallback_t& operator = (const hb_iter_with_fallback_t &o HB_UNUSED) = default;
|
||||
hb_iter_with_fallback_t& operator = (hb_iter_with_fallback_t &&o HB_UNUSED) = default;
|
||||
};
|
||||
|
||||
/*
|
||||
* Meta-programming predicates.
|
||||
*/
|
||||
|
||||
/* hb_is_iterator() / hb_is_iterator_of() */
|
||||
|
||||
template<typename Iter, typename Item>
|
||||
struct hb_is_iterator_of
|
||||
{
|
||||
template <typename Item2 = Item>
|
||||
static hb_true_type impl (hb_priority<2>, hb_iter_t<Iter, hb_type_identity<Item2>> *);
|
||||
static hb_false_type impl (hb_priority<0>, const void *);
|
||||
|
||||
public:
|
||||
static constexpr bool value = decltype (impl (hb_prioritize, hb_declval (Iter*)))::value;
|
||||
};
|
||||
#define hb_is_iterator_of(Iter, Item) hb_is_iterator_of<Iter, Item>::value
|
||||
#define hb_is_iterator(Iter) hb_is_iterator_of (Iter, typename Iter::item_t)
|
||||
|
||||
/* hb_is_iterable() */
|
||||
|
||||
template <typename T>
|
||||
@ -209,45 +263,78 @@ struct hb_is_iterable
|
||||
private:
|
||||
|
||||
template <typename U>
|
||||
static auto impl (hb_priority<1>) -> decltype (hb_declval (U).iter (), hb_true_t ());
|
||||
static auto impl (hb_priority<1>) -> decltype (hb_declval (U).iter (), hb_true_type ());
|
||||
|
||||
template <typename>
|
||||
static hb_false_t impl (hb_priority<0>);
|
||||
static hb_false_type impl (hb_priority<0>);
|
||||
|
||||
public:
|
||||
|
||||
enum { value = decltype (impl<T> (hb_prioritize))::value };
|
||||
static constexpr bool value = decltype (impl<T> (hb_prioritize))::value;
|
||||
};
|
||||
#define hb_is_iterable(Iterable) hb_is_iterable<Iterable>::value
|
||||
|
||||
/* TODO Add hb_is_iterable_of().
|
||||
* TODO Add random_access / sorted variants. */
|
||||
|
||||
/* hb_is_iterator() / hb_is_random_access_iterator() / hb_is_sorted_iterator() */
|
||||
|
||||
template <typename Iter, typename Item>
|
||||
static inline char _hb_is_iterator_of (hb_priority<0>, const void *) { return 0; }
|
||||
template <typename Iter,
|
||||
typename Item,
|
||||
typename Item2 = typename Iter::item_t,
|
||||
hb_enable_if (hb_is_cr_convertible_to (Item2, Item))>
|
||||
static inline int _hb_is_iterator_of (hb_priority<2>, hb_iter_t<Iter, Item2> *) { return 0; }
|
||||
/* hb_is_source_of() / hb_is_sink_of() */
|
||||
|
||||
template<typename Iter, typename Item>
|
||||
struct hb_is_iterator_of { enum {
|
||||
value = sizeof (int) == sizeof (_hb_is_iterator_of<Iter, Item> (hb_prioritize, hb_declval (Iter*))) }; };
|
||||
#define hb_is_iterator_of(Iter, Item) hb_is_iterator_of<Iter, Item>::value
|
||||
#define hb_is_iterator(Iter) hb_is_iterator_of (Iter, typename Iter::item_t)
|
||||
struct hb_is_source_of
|
||||
{
|
||||
private:
|
||||
template <typename Iter2 = Iter,
|
||||
hb_enable_if (hb_is_convertible (typename Iter2::item_t, hb_add_lvalue_reference<hb_add_const<Item>>))>
|
||||
static hb_true_type impl (hb_priority<2>);
|
||||
template <typename Iter2 = Iter>
|
||||
static auto impl (hb_priority<1>) -> decltype (hb_declval (Iter2) >> hb_declval (Item &), hb_true_type ());
|
||||
static hb_false_type impl (hb_priority<0>);
|
||||
|
||||
#define hb_is_random_access_iterator_of(Iter, Item) \
|
||||
hb_is_iterator_of (Iter, Item) && Iter::is_random_access_iterator
|
||||
#define hb_is_random_access_iterator(Iter) \
|
||||
hb_is_random_access_iterator_of (Iter, typename Iter::item_t)
|
||||
public:
|
||||
static constexpr bool value = decltype (impl (hb_prioritize))::value;
|
||||
};
|
||||
#define hb_is_source_of(Iter, Item) hb_is_source_of<Iter, Item>::value
|
||||
|
||||
#define hb_is_sorted_iterator_of(Iter, Item) \
|
||||
hb_is_iterator_of (Iter, Item) && Iter::is_sorted_iterator
|
||||
#define hb_is_sorted_iterator(Iter) \
|
||||
hb_is_sorted_iterator_of (Iter, typename Iter::item_t)
|
||||
template<typename Iter, typename Item>
|
||||
struct hb_is_sink_of
|
||||
{
|
||||
private:
|
||||
template <typename Iter2 = Iter,
|
||||
hb_enable_if (hb_is_convertible (typename Iter2::item_t, hb_add_lvalue_reference<Item>))>
|
||||
static hb_true_type impl (hb_priority<2>);
|
||||
template <typename Iter2 = Iter>
|
||||
static auto impl (hb_priority<1>) -> decltype (hb_declval (Iter2) << hb_declval (Item), hb_true_type ());
|
||||
static hb_false_type impl (hb_priority<0>);
|
||||
|
||||
public:
|
||||
static constexpr bool value = decltype (impl (hb_prioritize))::value;
|
||||
};
|
||||
#define hb_is_sink_of(Iter, Item) hb_is_sink_of<Iter, Item>::value
|
||||
|
||||
/* This is commonly used, so define: */
|
||||
#define hb_is_sorted_source_of(Iter, Item) \
|
||||
(hb_is_source_of(Iter, Item) && Iter::is_sorted_iterator)
|
||||
|
||||
|
||||
/* Range-based 'for' for iterables. */
|
||||
|
||||
template <typename Iterable,
|
||||
hb_requires (hb_is_iterable (Iterable))>
|
||||
static inline auto begin (Iterable&& iterable) HB_AUTO_RETURN (hb_iter (iterable).begin ())
|
||||
|
||||
template <typename Iterable,
|
||||
hb_requires (hb_is_iterable (Iterable))>
|
||||
static inline auto end (Iterable&& iterable) HB_AUTO_RETURN (hb_iter (iterable).end ())
|
||||
|
||||
/* begin()/end() are NOT looked up non-ADL. So each namespace must declare them.
|
||||
* Do it for namespace OT. */
|
||||
namespace OT {
|
||||
|
||||
template <typename Iterable,
|
||||
hb_requires (hb_is_iterable (Iterable))>
|
||||
static inline auto begin (Iterable&& iterable) HB_AUTO_RETURN (hb_iter (iterable).begin ())
|
||||
|
||||
template <typename Iterable,
|
||||
hb_requires (hb_is_iterable (Iterable))>
|
||||
static inline auto end (Iterable&& iterable) HB_AUTO_RETURN (hb_iter (iterable).end ())
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
@ -255,46 +342,59 @@ struct hb_is_iterator_of { enum {
|
||||
*/
|
||||
|
||||
template <typename Lhs, typename Rhs,
|
||||
hb_enable_if (hb_is_iterator (Lhs))>
|
||||
hb_requires (hb_is_iterator (Lhs))>
|
||||
static inline auto
|
||||
operator | (Lhs lhs, const Rhs &rhs) HB_AUTO_RETURN (rhs (lhs))
|
||||
operator | (Lhs&& lhs, Rhs&& rhs) HB_AUTO_RETURN (hb_forward<Rhs> (rhs) (hb_forward<Lhs> (lhs)))
|
||||
|
||||
/* hb_map(), hb_filter(), hb_reduce() */
|
||||
|
||||
template <typename Iter, typename Proj,
|
||||
hb_enable_if (hb_is_iterator (Iter))>
|
||||
struct hb_map_iter_t :
|
||||
hb_iter_t<hb_map_iter_t<Iter, Proj>,
|
||||
decltype (hb_declval (Proj) (hb_declval (typename Iter::item_t)))>
|
||||
{
|
||||
hb_map_iter_t (const Iter& it, Proj f) : it (it), f (f) {}
|
||||
enum class hb_function_sortedness_t {
|
||||
NOT_SORTED,
|
||||
RETAINS_SORTING,
|
||||
SORTED,
|
||||
};
|
||||
|
||||
typedef decltype (hb_declval (Proj) (hb_declval (typename Iter::item_t))) __item_t__;
|
||||
template <typename Iter, typename Proj, hb_function_sortedness_t Sorted,
|
||||
hb_requires (hb_is_iterator (Iter))>
|
||||
struct hb_map_iter_t :
|
||||
hb_iter_t<hb_map_iter_t<Iter, Proj, Sorted>,
|
||||
decltype (hb_get (hb_declval (Proj), *hb_declval (Iter)))>
|
||||
{
|
||||
hb_map_iter_t (const Iter& it, Proj f_) : it (it), f (f_) {}
|
||||
|
||||
typedef decltype (hb_get (hb_declval (Proj), *hb_declval (Iter))) __item_t__;
|
||||
static constexpr bool is_random_access_iterator = Iter::is_random_access_iterator;
|
||||
__item_t__ __item__ () const { return hb_get (f, *it); }
|
||||
__item_t__ __item_at__ (unsigned i) const { return hb_get (f, it[i]); }
|
||||
static constexpr bool is_sorted_iterator =
|
||||
Sorted == hb_function_sortedness_t::SORTED ? true :
|
||||
Sorted == hb_function_sortedness_t::RETAINS_SORTING ? Iter::is_sorted_iterator :
|
||||
false;
|
||||
__item_t__ __item__ () const { return hb_get (f.get (), *it); }
|
||||
__item_t__ __item_at__ (unsigned i) const { return hb_get (f.get (), it[i]); }
|
||||
bool __more__ () const { return bool (it); }
|
||||
unsigned __len__ () const { return it.len (); }
|
||||
void __next__ () { ++it; }
|
||||
void __forward__ (unsigned n) { it += n; }
|
||||
void __prev__ () { --it; }
|
||||
void __rewind__ (unsigned n) { it -= n; }
|
||||
hb_map_iter_t __end__ () const { return hb_map_iter_t (it.end (), f); }
|
||||
bool operator != (const hb_map_iter_t& o) const
|
||||
{ return it != o.it; }
|
||||
|
||||
private:
|
||||
Iter it;
|
||||
Proj f;
|
||||
hb_reference_wrapper<Proj> f;
|
||||
};
|
||||
|
||||
template <typename Proj>
|
||||
template <typename Proj, hb_function_sortedness_t Sorted>
|
||||
struct hb_map_iter_factory_t
|
||||
{
|
||||
hb_map_iter_factory_t (Proj f) : f (f) {}
|
||||
|
||||
template <typename Iter,
|
||||
hb_enable_if (hb_is_iterator (Iter))>
|
||||
hb_map_iter_t<Iter, Proj>
|
||||
operator () (Iter it) const
|
||||
{ return hb_map_iter_t<Iter, Proj> (it, f); }
|
||||
hb_requires (hb_is_iterator (Iter))>
|
||||
hb_map_iter_t<Iter, Proj, Sorted>
|
||||
operator () (Iter it)
|
||||
{ return hb_map_iter_t<Iter, Proj, Sorted> (it, f); }
|
||||
|
||||
private:
|
||||
Proj f;
|
||||
@ -302,31 +402,51 @@ struct hb_map_iter_factory_t
|
||||
struct
|
||||
{
|
||||
template <typename Proj>
|
||||
hb_map_iter_factory_t<Proj>
|
||||
hb_map_iter_factory_t<Proj, hb_function_sortedness_t::NOT_SORTED>
|
||||
operator () (Proj&& f) const
|
||||
{ return hb_map_iter_factory_t<Proj> (f); }
|
||||
} HB_FUNCOBJ (hb_map);
|
||||
{ return hb_map_iter_factory_t<Proj, hb_function_sortedness_t::NOT_SORTED> (f); }
|
||||
}
|
||||
HB_FUNCOBJ (hb_map);
|
||||
struct
|
||||
{
|
||||
template <typename Proj>
|
||||
hb_map_iter_factory_t<Proj, hb_function_sortedness_t::RETAINS_SORTING>
|
||||
operator () (Proj&& f) const
|
||||
{ return hb_map_iter_factory_t<Proj, hb_function_sortedness_t::RETAINS_SORTING> (f); }
|
||||
}
|
||||
HB_FUNCOBJ (hb_map_retains_sorting);
|
||||
struct
|
||||
{
|
||||
template <typename Proj>
|
||||
hb_map_iter_factory_t<Proj, hb_function_sortedness_t::SORTED>
|
||||
operator () (Proj&& f) const
|
||||
{ return hb_map_iter_factory_t<Proj, hb_function_sortedness_t::SORTED> (f); }
|
||||
}
|
||||
HB_FUNCOBJ (hb_map_sorted);
|
||||
|
||||
template <typename Iter, typename Pred, typename Proj,
|
||||
hb_enable_if (hb_is_iterator (Iter))>
|
||||
hb_requires (hb_is_iterator (Iter))>
|
||||
struct hb_filter_iter_t :
|
||||
hb_iter_with_fallback_t<hb_filter_iter_t<Iter, Pred, Proj>,
|
||||
typename Iter::item_t>
|
||||
{
|
||||
hb_filter_iter_t (const Iter& it_, Pred p, Proj f) : it (it_), p (p), f (f)
|
||||
{ while (it && !hb_has (p, hb_get (f, *it))) ++it; }
|
||||
hb_filter_iter_t (const Iter& it_, Pred p_, Proj f_) : it (it_), p (p_), f (f_)
|
||||
{ while (it && !hb_has (p.get (), hb_get (f.get (), *it))) ++it; }
|
||||
|
||||
typedef typename Iter::item_t __item_t__;
|
||||
static constexpr bool is_sorted_iterator = Iter::is_sorted_iterator;
|
||||
__item_t__ __item__ () const { return *it; }
|
||||
bool __more__ () const { return bool (it); }
|
||||
void __next__ () { do ++it; while (it && !p (f (*it))); }
|
||||
void __prev__ () { --it; }
|
||||
void __next__ () { do ++it; while (it && !hb_has (p.get (), hb_get (f.get (), *it))); }
|
||||
void __prev__ () { do --it; while (it && !hb_has (p.get (), hb_get (f.get (), *it))); }
|
||||
hb_filter_iter_t __end__ () const { return hb_filter_iter_t (it.end (), p, f); }
|
||||
bool operator != (const hb_filter_iter_t& o) const
|
||||
{ return it != o.it; }
|
||||
|
||||
private:
|
||||
Iter it;
|
||||
Pred p;
|
||||
Proj f;
|
||||
hb_reference_wrapper<Pred> p;
|
||||
hb_reference_wrapper<Proj> f;
|
||||
};
|
||||
template <typename Pred, typename Proj>
|
||||
struct hb_filter_iter_factory_t
|
||||
@ -334,9 +454,9 @@ struct hb_filter_iter_factory_t
|
||||
hb_filter_iter_factory_t (Pred p, Proj f) : p (p), f (f) {}
|
||||
|
||||
template <typename Iter,
|
||||
hb_enable_if (hb_is_iterator (Iter))>
|
||||
hb_requires (hb_is_iterator (Iter))>
|
||||
hb_filter_iter_t<Iter, Pred, Proj>
|
||||
operator () (Iter it) const
|
||||
operator () (Iter it)
|
||||
{ return hb_filter_iter_t<Iter, Pred, Proj> (it, p, f); }
|
||||
|
||||
private:
|
||||
@ -345,12 +465,13 @@ struct hb_filter_iter_factory_t
|
||||
};
|
||||
struct
|
||||
{
|
||||
template <typename Pred = decltype ((hb_bool)),
|
||||
template <typename Pred = decltype ((hb_identity)),
|
||||
typename Proj = decltype ((hb_identity))>
|
||||
hb_filter_iter_factory_t<Pred, Proj>
|
||||
operator () (Pred&& p = hb_bool, Proj&& f = hb_identity) const
|
||||
operator () (Pred&& p = hb_identity, Proj&& f = hb_identity) const
|
||||
{ return hb_filter_iter_factory_t<Pred, Proj> (p, f); }
|
||||
} HB_FUNCOBJ (hb_filter);
|
||||
}
|
||||
HB_FUNCOBJ (hb_filter);
|
||||
|
||||
template <typename Redu, typename InitT>
|
||||
struct hb_reduce_t
|
||||
@ -358,10 +479,10 @@ struct hb_reduce_t
|
||||
hb_reduce_t (Redu r, InitT init_value) : r (r), init_value (init_value) {}
|
||||
|
||||
template <typename Iter,
|
||||
hb_enable_if (hb_is_iterator (Iter)),
|
||||
hb_requires (hb_is_iterator (Iter)),
|
||||
typename AccuT = decltype (hb_declval (Redu) (hb_declval (InitT), hb_declval (typename Iter::item_t)))>
|
||||
AccuT
|
||||
operator () (Iter it) const
|
||||
operator () (Iter it)
|
||||
{
|
||||
AccuT value = init_value;
|
||||
for (; it; ++it)
|
||||
@ -379,7 +500,8 @@ struct
|
||||
hb_reduce_t<Redu, InitT>
|
||||
operator () (Redu&& r, InitT init_value) const
|
||||
{ return hb_reduce_t<Redu, InitT> (r, init_value); }
|
||||
} HB_FUNCOBJ (hb_reduce);
|
||||
}
|
||||
HB_FUNCOBJ (hb_reduce);
|
||||
|
||||
|
||||
/* hb_zip() */
|
||||
@ -387,7 +509,7 @@ struct
|
||||
template <typename A, typename B>
|
||||
struct hb_zip_iter_t :
|
||||
hb_iter_t<hb_zip_iter_t<A, B>,
|
||||
hb_pair_t<typename A::item_t, typename B::item_t> >
|
||||
hb_pair_t<typename A::item_t, typename B::item_t>>
|
||||
{
|
||||
hb_zip_iter_t () {}
|
||||
hb_zip_iter_t (const A& a, const B& b) : a (a), b (b) {}
|
||||
@ -396,17 +518,45 @@ struct hb_zip_iter_t :
|
||||
static constexpr bool is_random_access_iterator =
|
||||
A::is_random_access_iterator &&
|
||||
B::is_random_access_iterator;
|
||||
static constexpr bool is_sorted_iterator =
|
||||
A::is_sorted_iterator &&
|
||||
B::is_sorted_iterator;
|
||||
/* Note. The following categorization is only valid if A is strictly sorted,
|
||||
* ie. does NOT have duplicates. Previously I tried to categorize sortedness
|
||||
* more granularly, see commits:
|
||||
*
|
||||
* 513762849a683914fc266a17ddf38f133cccf072
|
||||
* 4d3cf2adb669c345cc43832d11689271995e160a
|
||||
*
|
||||
* However, that was not enough, since hb_sorted_array_t, hb_sorted_vector_t,
|
||||
* SortedArrayOf, etc all needed to be updated to add more variants. At that
|
||||
* point I saw it not worth the effort, and instead we now deem all sorted
|
||||
* collections as essentially strictly-sorted for the purposes of zip.
|
||||
*
|
||||
* The above assumption is not as bad as it sounds. Our "sorted" comes with
|
||||
* no guarantees. It's just a contract, put in place to help you remember,
|
||||
* and think about, whether an iterator you receive is expected to be
|
||||
* sorted or not. As such, it's not perfect by definition, and should not
|
||||
* be treated so. The inaccuracy here just errs in the direction of being
|
||||
* more permissive, so your code compiles instead of erring on the side of
|
||||
* marking your zipped iterator unsorted in which case your code won't
|
||||
* compile.
|
||||
*
|
||||
* This semantical limitation does NOT affect logic in any other place I
|
||||
* know of as of this writing.
|
||||
*/
|
||||
static constexpr bool is_sorted_iterator = A::is_sorted_iterator;
|
||||
|
||||
__item_t__ __item__ () const { return __item_t__ (*a, *b); }
|
||||
__item_t__ __item_at__ (unsigned i) const { return __item_t__ (a[i], b[i]); }
|
||||
bool __more__ () const { return a && b; }
|
||||
unsigned __len__ () const { return MIN (a.len (), b.len ()); }
|
||||
bool __more__ () const { return bool (a) && bool (b); }
|
||||
unsigned __len__ () const { return hb_min (a.len (), b.len ()); }
|
||||
void __next__ () { ++a; ++b; }
|
||||
void __forward__ (unsigned n) { a += n; b += n; }
|
||||
void __prev__ () { --a; --b; }
|
||||
void __rewind__ (unsigned n) { a -= n; b -= n; }
|
||||
hb_zip_iter_t __end__ () const { return hb_zip_iter_t (a.end (), b.end ()); }
|
||||
/* Note, we should stop if ANY of the iters reaches end. As such two compare
|
||||
* unequal if both items are unequal, NOT if either is unequal. */
|
||||
bool operator != (const hb_zip_iter_t& o) const
|
||||
{ return a != o.a && b != o.b; }
|
||||
|
||||
private:
|
||||
A a;
|
||||
@ -415,46 +565,12 @@ struct hb_zip_iter_t :
|
||||
struct
|
||||
{
|
||||
template <typename A, typename B,
|
||||
hb_enable_if (hb_is_iterable (A) && hb_is_iterable (B))>
|
||||
hb_zip_iter_t<hb_iter_t (A), hb_iter_t (B)>
|
||||
operator () (A& a, B &b) const
|
||||
{ return hb_zip_iter_t<hb_iter_t (A), hb_iter_t (B)> (hb_iter (a), hb_iter (b)); }
|
||||
} HB_FUNCOBJ (hb_zip);
|
||||
|
||||
/* hb_enumerate */
|
||||
|
||||
template <typename Iter,
|
||||
hb_enable_if (hb_is_iterator (Iter))>
|
||||
struct hb_enumerate_iter_t :
|
||||
hb_iter_t<hb_enumerate_iter_t<Iter>,
|
||||
hb_pair_t<unsigned, typename Iter::item_t> >
|
||||
{
|
||||
hb_enumerate_iter_t (const Iter& it) : i (0), it (it) {}
|
||||
|
||||
typedef hb_pair_t<unsigned, typename Iter::item_t> __item_t__;
|
||||
static constexpr bool is_random_access_iterator = Iter::is_random_access_iterator;
|
||||
static constexpr bool is_sorted_iterator = true;
|
||||
__item_t__ __item__ () const { return __item_t__ (+i, *it); }
|
||||
__item_t__ __item_at__ (unsigned j) const { return __item_t__ (i + j, it[j]); }
|
||||
bool __more__ () const { return bool (it); }
|
||||
unsigned __len__ () const { return it.len (); }
|
||||
void __next__ () { ++i; ++it; }
|
||||
void __forward__ (unsigned n) { i += n; it += n; }
|
||||
void __prev__ () { --i; --it; }
|
||||
void __rewind__ (unsigned n) { i -= n; it -= n; }
|
||||
|
||||
private:
|
||||
unsigned i;
|
||||
Iter it;
|
||||
};
|
||||
struct
|
||||
{
|
||||
template <typename Iterable,
|
||||
hb_enable_if (hb_is_iterable (Iterable))>
|
||||
hb_enumerate_iter_t<hb_iter_t (Iterable)>
|
||||
operator () (Iterable& it) const
|
||||
{ return hb_enumerate_iter_t<hb_iter_t (Iterable)> (hb_iter (it)); }
|
||||
} HB_FUNCOBJ (hb_enumerate);
|
||||
hb_requires (hb_is_iterable (A) && hb_is_iterable (B))>
|
||||
hb_zip_iter_t<hb_iter_type<A>, hb_iter_type<B>>
|
||||
operator () (A&& a, B&& b) const
|
||||
{ return hb_zip_iter_t<hb_iter_type<A>, hb_iter_type<B>> (hb_iter (a), hb_iter (b)); }
|
||||
}
|
||||
HB_FUNCOBJ (hb_zip);
|
||||
|
||||
/* hb_apply() */
|
||||
|
||||
@ -464,9 +580,8 @@ struct hb_apply_t
|
||||
hb_apply_t (Appl a) : a (a) {}
|
||||
|
||||
template <typename Iter,
|
||||
hb_enable_if (hb_is_iterator (Iter))>
|
||||
void
|
||||
operator () (Iter it) const
|
||||
hb_requires (hb_is_iterator (Iter))>
|
||||
void operator () (Iter it)
|
||||
{
|
||||
for (; it; ++it)
|
||||
(void) hb_invoke (a, *it);
|
||||
@ -484,19 +599,91 @@ struct
|
||||
template <typename Appl> hb_apply_t<Appl&>
|
||||
operator () (Appl *a) const
|
||||
{ return hb_apply_t<Appl&> (*a); }
|
||||
} HB_FUNCOBJ (hb_apply);
|
||||
}
|
||||
HB_FUNCOBJ (hb_apply);
|
||||
|
||||
/* hb_iota()/hb_range() */
|
||||
|
||||
template <typename T, typename S>
|
||||
struct hb_counter_iter_t :
|
||||
hb_iter_t<hb_counter_iter_t<T, S>, T>
|
||||
{
|
||||
hb_counter_iter_t (T start, T end_, S step) : v (start), end_ (end_for (start, end_, step)), step (step) {}
|
||||
|
||||
typedef T __item_t__;
|
||||
static constexpr bool is_random_access_iterator = true;
|
||||
static constexpr bool is_sorted_iterator = true;
|
||||
__item_t__ __item__ () const { return +v; }
|
||||
__item_t__ __item_at__ (unsigned j) const { return v + j * step; }
|
||||
bool __more__ () const { return v != end_; }
|
||||
unsigned __len__ () const { return !step ? UINT_MAX : (end_ - v) / step; }
|
||||
void __next__ () { v += step; }
|
||||
void __forward__ (unsigned n) { v += n * step; }
|
||||
void __prev__ () { v -= step; }
|
||||
void __rewind__ (unsigned n) { v -= n * step; }
|
||||
hb_counter_iter_t __end__ () const { return hb_counter_iter_t (end_, end_, step); }
|
||||
bool operator != (const hb_counter_iter_t& o) const
|
||||
{ return v != o.v; }
|
||||
|
||||
private:
|
||||
static inline T end_for (T start, T end_, S step)
|
||||
{
|
||||
if (!step)
|
||||
return end_;
|
||||
auto res = (end_ - start) % step;
|
||||
if (!res)
|
||||
return end_;
|
||||
end_ += step - res;
|
||||
return end_;
|
||||
}
|
||||
|
||||
private:
|
||||
T v;
|
||||
T end_;
|
||||
S step;
|
||||
};
|
||||
struct
|
||||
{
|
||||
template <typename T = unsigned, typename S = unsigned> hb_counter_iter_t<T, S>
|
||||
operator () (T start = 0u, S&& step = 1u) const
|
||||
{ return hb_counter_iter_t<T, S> (start, step >= 0 ? hb_int_max (T) : hb_int_min (T), step); }
|
||||
}
|
||||
HB_FUNCOBJ (hb_iota);
|
||||
struct
|
||||
{
|
||||
template <typename T = unsigned> hb_counter_iter_t<T, unsigned>
|
||||
operator () (T end = (unsigned) -1) const
|
||||
{ return hb_counter_iter_t<T, unsigned> (0, end, 1u); }
|
||||
|
||||
template <typename T, typename S = unsigned> hb_counter_iter_t<T, S>
|
||||
operator () (T start, T end, S&& step = 1u) const
|
||||
{ return hb_counter_iter_t<T, S> (start, end, step); }
|
||||
}
|
||||
HB_FUNCOBJ (hb_range);
|
||||
|
||||
/* hb_enumerate */
|
||||
|
||||
struct
|
||||
{
|
||||
template <typename Iterable,
|
||||
typename Index = unsigned,
|
||||
hb_requires (hb_is_iterable (Iterable))>
|
||||
auto operator () (Iterable&& it, Index start = 0u) const HB_AUTO_RETURN
|
||||
( hb_zip (hb_iota (start), it) )
|
||||
}
|
||||
HB_FUNCOBJ (hb_enumerate);
|
||||
|
||||
|
||||
/* hb_sink() */
|
||||
|
||||
template <typename Sink>
|
||||
struct hb_sink_t
|
||||
{
|
||||
hb_sink_t (Sink&& s) : s (s) {}
|
||||
hb_sink_t (Sink s) : s (s) {}
|
||||
|
||||
template <typename Iter,
|
||||
hb_enable_if (hb_is_iterator (Iter))>
|
||||
void
|
||||
operator () (Iter it) const
|
||||
hb_requires (hb_is_iterator (Iter))>
|
||||
void operator () (Iter it)
|
||||
{
|
||||
for (; it; ++it)
|
||||
s << *it;
|
||||
@ -514,33 +701,33 @@ struct
|
||||
template <typename Sink> hb_sink_t<Sink&>
|
||||
operator () (Sink *s) const
|
||||
{ return hb_sink_t<Sink&> (*s); }
|
||||
} HB_FUNCOBJ (hb_sink);
|
||||
}
|
||||
HB_FUNCOBJ (hb_sink);
|
||||
|
||||
/* hb-drain: hb_sink to void / blackhole / /dev/null. */
|
||||
|
||||
struct
|
||||
{
|
||||
template <typename Iter,
|
||||
hb_enable_if (hb_is_iterator (Iter))>
|
||||
void
|
||||
operator () (Iter it) const
|
||||
hb_requires (hb_is_iterator (Iter))>
|
||||
void operator () (Iter it) const
|
||||
{
|
||||
for (; it; ++it)
|
||||
(void) *it;
|
||||
}
|
||||
} HB_FUNCOBJ (hb_drain);
|
||||
}
|
||||
HB_FUNCOBJ (hb_drain);
|
||||
|
||||
/* hb_unzip(): unzip and sink to two sinks. */
|
||||
|
||||
template <typename Sink1, typename Sink2>
|
||||
struct hb_unzip_t
|
||||
{
|
||||
hb_unzip_t (Sink1&& s1, Sink2&& s2) : s1 (s1), s2 (s2) {}
|
||||
hb_unzip_t (Sink1 s1, Sink2 s2) : s1 (s1), s2 (s2) {}
|
||||
|
||||
template <typename Iter,
|
||||
hb_enable_if (hb_is_iterator (Iter))>
|
||||
void
|
||||
operator () (Iter it) const
|
||||
hb_requires (hb_is_iterator (Iter))>
|
||||
void operator () (Iter it)
|
||||
{
|
||||
for (; it; ++it)
|
||||
{
|
||||
@ -563,7 +750,8 @@ struct
|
||||
template <typename Sink1, typename Sink2> hb_unzip_t<Sink1&, Sink2&>
|
||||
operator () (Sink1 *s1, Sink2 *s2) const
|
||||
{ return hb_unzip_t<Sink1&, Sink2&> (*s1, *s2); }
|
||||
} HB_FUNCOBJ (hb_unzip);
|
||||
}
|
||||
HB_FUNCOBJ (hb_unzip);
|
||||
|
||||
|
||||
/* hb-all, hb-any, hb-none. */
|
||||
@ -571,49 +759,61 @@ struct
|
||||
struct
|
||||
{
|
||||
template <typename Iterable,
|
||||
hb_enable_if (hb_is_iterable (Iterable))>
|
||||
bool
|
||||
operator () (Iterable&& c) const
|
||||
typename Pred = decltype ((hb_identity)),
|
||||
typename Proj = decltype ((hb_identity)),
|
||||
hb_requires (hb_is_iterable (Iterable))>
|
||||
bool operator () (Iterable&& c,
|
||||
Pred&& p = hb_identity,
|
||||
Proj&& f = hb_identity) const
|
||||
{
|
||||
for (auto it = hb_iter (c); it; ++it)
|
||||
if (!*it)
|
||||
if (!hb_match (hb_forward<Pred> (p), hb_get (hb_forward<Proj> (f), *it)))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
} HB_FUNCOBJ (hb_all);
|
||||
}
|
||||
HB_FUNCOBJ (hb_all);
|
||||
struct
|
||||
{
|
||||
template <typename Iterable,
|
||||
hb_enable_if (hb_is_iterable (Iterable))>
|
||||
bool
|
||||
operator () (Iterable&& c) const
|
||||
typename Pred = decltype ((hb_identity)),
|
||||
typename Proj = decltype ((hb_identity)),
|
||||
hb_requires (hb_is_iterable (Iterable))>
|
||||
bool operator () (Iterable&& c,
|
||||
Pred&& p = hb_identity,
|
||||
Proj&& f = hb_identity) const
|
||||
{
|
||||
for (auto it = hb_iter (c); it; ++it)
|
||||
if (*it)
|
||||
if (hb_match (hb_forward<Pred> (p), hb_get (hb_forward<Proj> (f), *it)))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
} HB_FUNCOBJ (hb_any);
|
||||
}
|
||||
HB_FUNCOBJ (hb_any);
|
||||
struct
|
||||
{
|
||||
template <typename Iterable,
|
||||
hb_enable_if (hb_is_iterable (Iterable))>
|
||||
bool
|
||||
operator () (Iterable&& c) const
|
||||
typename Pred = decltype ((hb_identity)),
|
||||
typename Proj = decltype ((hb_identity)),
|
||||
hb_requires (hb_is_iterable (Iterable))>
|
||||
bool operator () (Iterable&& c,
|
||||
Pred&& p = hb_identity,
|
||||
Proj&& f = hb_identity) const
|
||||
{
|
||||
for (auto it = hb_iter (c); it; ++it)
|
||||
if (*it)
|
||||
if (hb_match (hb_forward<Pred> (p), hb_get (hb_forward<Proj> (f), *it)))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
} HB_FUNCOBJ (hb_none);
|
||||
}
|
||||
HB_FUNCOBJ (hb_none);
|
||||
|
||||
/*
|
||||
* Algorithms operating on iterators.
|
||||
*/
|
||||
|
||||
template <typename C, typename V,
|
||||
hb_enable_if (hb_is_iterable (C))>
|
||||
hb_requires (hb_is_iterable (C))>
|
||||
inline void
|
||||
hb_fill (C& c, const V &v)
|
||||
{
|
||||
|
@ -43,8 +43,8 @@ struct hb_hashmap_t
|
||||
hb_hashmap_t () { init (); }
|
||||
~hb_hashmap_t () { fini (); }
|
||||
|
||||
static_assert (hb_is_integer (K) || hb_is_pointer (K), "");
|
||||
static_assert (hb_is_integer (V) || hb_is_pointer (V), "");
|
||||
static_assert (hb_is_integral (K) || hb_is_pointer (K), "");
|
||||
static_assert (hb_is_integral (V) || hb_is_pointer (V), "");
|
||||
|
||||
/* TODO If key type is a pointer, keep hash in item_t and use to:
|
||||
* 1. avoid rehashing when resizing table, and
|
||||
@ -57,11 +57,12 @@ struct hb_hashmap_t
|
||||
|
||||
void clear () { key = kINVALID; value = vINVALID; }
|
||||
|
||||
bool operator == (K o) { return hb_deref_pointer (key) == hb_deref_pointer (o); }
|
||||
bool operator == (K o) { return hb_deref (key) == hb_deref (o); }
|
||||
bool operator == (const item_t &o) { return *this == o.key; }
|
||||
bool is_unused () const { return key == kINVALID; }
|
||||
bool is_tombstone () const { return key != kINVALID && value == vINVALID; }
|
||||
bool is_real () const { return key != kINVALID && value != vINVALID; }
|
||||
hb_pair_t<K, V> get_pair() const { return hb_pair_t<K, V> (key, value); }
|
||||
};
|
||||
|
||||
hb_object_header_t header;
|
||||
@ -181,7 +182,12 @@ struct hb_hashmap_t
|
||||
static constexpr V SENTINEL = vINVALID;
|
||||
typedef V value_t;
|
||||
value_t operator [] (K k) const { return get (k); }
|
||||
bool has (K k) const { return (*this)[k] != SENTINEL; }
|
||||
bool has (K k, V *vp = nullptr) const
|
||||
{
|
||||
V v = (*this)[k];
|
||||
if (vp) *vp = v;
|
||||
return v != SENTINEL;
|
||||
}
|
||||
/* Projection. */
|
||||
V operator () (K k) const { return get (k); }
|
||||
|
||||
@ -201,6 +207,34 @@ struct hb_hashmap_t
|
||||
|
||||
unsigned int get_population () const { return population; }
|
||||
|
||||
/*
|
||||
* Iterator
|
||||
*/
|
||||
auto iter () const HB_AUTO_RETURN
|
||||
(
|
||||
+ hb_array (items, mask ? mask + 1 : 0)
|
||||
| hb_filter (&item_t::is_real)
|
||||
| hb_map (&item_t::get_pair)
|
||||
)
|
||||
auto keys () const HB_AUTO_RETURN
|
||||
(
|
||||
+ hb_array (items, mask ? mask + 1 : 0)
|
||||
| hb_filter (&item_t::is_real)
|
||||
| hb_map (&item_t::key)
|
||||
| hb_map (hb_ridentity)
|
||||
)
|
||||
auto values () const HB_AUTO_RETURN
|
||||
(
|
||||
+ hb_array (items, mask ? mask + 1 : 0)
|
||||
| hb_filter (&item_t::is_real)
|
||||
| hb_map (&item_t::value)
|
||||
| hb_map (hb_ridentity)
|
||||
)
|
||||
|
||||
/* Sink interface. */
|
||||
hb_hashmap_t<K, V, kINVALID, vINVALID>& operator << (const hb_pair_t<K, V>& v)
|
||||
{ set (v.first, v.second); return *this; }
|
||||
|
||||
protected:
|
||||
|
||||
unsigned int bucket_for (K key) const
|
||||
@ -211,9 +245,9 @@ struct hb_hashmap_t
|
||||
while (!items[i].is_unused ())
|
||||
{
|
||||
if (items[i] == key)
|
||||
return i;
|
||||
return i;
|
||||
if (tombstone == (unsigned) -1 && items[i].is_tombstone ())
|
||||
tombstone = i;
|
||||
tombstone = i;
|
||||
i = (i + ++step) & mask;
|
||||
}
|
||||
return tombstone == (unsigned) -1 ? i : tombstone;
|
||||
|
356
src/hb-meta.hh
356
src/hb-meta.hh
@ -35,28 +35,38 @@
|
||||
*/
|
||||
|
||||
/* Void! For when we need a expression-type of void. */
|
||||
struct hb_void_t { typedef void value; };
|
||||
struct hb_empty_t {};
|
||||
|
||||
/* Void meta-function ala std::void_t
|
||||
* https://en.cppreference.com/w/cpp/types/void_t */
|
||||
template<typename... Ts> struct _hb_void_tt { typedef void type; };
|
||||
template<typename... Ts> using hb_void_tt = typename _hb_void_tt<Ts...>::type;
|
||||
/* https://en.cppreference.com/w/cpp/types/void_t */
|
||||
template<typename... Ts> struct _hb_void_t { typedef void type; };
|
||||
template<typename... Ts> using hb_void_t = typename _hb_void_t<Ts...>::type;
|
||||
|
||||
template<typename Head, typename... Ts> struct _hb_head_tt { typedef Head type; };
|
||||
template<typename... Ts> using hb_head_tt = typename _hb_head_tt<Ts...>::type;
|
||||
template<typename Head, typename... Ts> struct _hb_head_t { typedef Head type; };
|
||||
template<typename... Ts> using hb_head_t = typename _hb_head_t<Ts...>::type;
|
||||
|
||||
/* Bool! For when we need to evaluate type-dependent expressions
|
||||
* in a template argument. */
|
||||
template <bool b> struct hb_bool_tt { enum { value = b }; };
|
||||
typedef hb_bool_tt<true> hb_true_t;
|
||||
typedef hb_bool_tt<false> hb_false_t;
|
||||
template <typename T, T v> struct hb_integral_constant { static constexpr T value = v; };
|
||||
template <bool b> using hb_bool_constant = hb_integral_constant<bool, b>;
|
||||
using hb_true_type = hb_bool_constant<true>;
|
||||
using hb_false_type = hb_bool_constant<false>;
|
||||
|
||||
|
||||
/* Basic type SFINAE. */
|
||||
|
||||
template <bool B, typename T = void> struct hb_enable_if {};
|
||||
template <typename T> struct hb_enable_if<true, T> { typedef T type; };
|
||||
#define hb_enable_if(Cond) typename hb_enable_if<(Cond)>::type* = nullptr
|
||||
/* Concepts/Requires alias: */
|
||||
#define hb_requires(Cond) hb_enable_if((Cond))
|
||||
|
||||
template <typename T, typename T2> struct hb_is_same : hb_false_type {};
|
||||
template <typename T> struct hb_is_same<T, T> : hb_true_type {};
|
||||
#define hb_is_same(T, T2) hb_is_same<T, T2>::value
|
||||
|
||||
/* Function overloading SFINAE and priority. */
|
||||
|
||||
#define HB_RETURN(Ret, E) -> hb_head_tt<Ret, decltype ((E))> { return (E); }
|
||||
#define HB_RETURN(Ret, E) -> hb_head_t<Ret, decltype ((E))> { return (E); }
|
||||
#define HB_AUTO_RETURN(E) -> decltype ((E)) { return (E); }
|
||||
#define HB_VOID_RETURN(E) -> hb_void_tt<decltype ((E))> { (E); }
|
||||
#define HB_VOID_RETURN(E) -> hb_void_t<decltype ((E))> { (E); }
|
||||
|
||||
template <unsigned Pri> struct hb_priority : hb_priority<Pri - 1> {};
|
||||
template <> struct hb_priority<0> {};
|
||||
@ -65,13 +75,13 @@ template <> struct hb_priority<0> {};
|
||||
#define HB_FUNCOBJ(x) static_const x HB_UNUSED
|
||||
|
||||
|
||||
template <typename T> struct hb_match_identity { typedef T type; };
|
||||
template <typename T> using hb_type_identity = typename hb_match_identity<T>::type;
|
||||
template <typename T> struct hb_type_identity_t { typedef T type; };
|
||||
template <typename T> using hb_type_identity = typename hb_type_identity_t<T>::type;
|
||||
|
||||
struct
|
||||
{
|
||||
template <typename T>
|
||||
T* operator () (const T& arg) const
|
||||
T* operator () (T& arg) const
|
||||
{
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wcast-align"
|
||||
@ -81,32 +91,82 @@ struct
|
||||
reinterpret_cast<const volatile char&> (arg)));
|
||||
#pragma GCC diagnostic pop
|
||||
}
|
||||
} HB_FUNCOBJ (hb_addressof);
|
||||
}
|
||||
HB_FUNCOBJ (hb_addressof);
|
||||
|
||||
template <typename T> static inline T hb_declval ();
|
||||
#define hb_declval(T) (hb_declval<T> ())
|
||||
|
||||
template <typename T> struct hb_match_const { typedef T type; enum { value = false }; };
|
||||
template <typename T> struct hb_match_const<const T> { typedef T type; enum { value = true }; };
|
||||
template <typename T> struct hb_match_const : hb_type_identity_t<T>, hb_bool_constant<false>{};
|
||||
template <typename T> struct hb_match_const<const T> : hb_type_identity_t<T>, hb_bool_constant<true> {};
|
||||
template <typename T> using hb_remove_const = typename hb_match_const<T>::type;
|
||||
template <typename T> using hb_add_const = const T;
|
||||
#define hb_is_const(T) hb_match_const<T>::value
|
||||
template <typename T> struct hb_match_reference { typedef T type; enum { value = false }; };
|
||||
template <typename T> struct hb_match_reference<T &> { typedef T type; enum { value = true }; };
|
||||
template <typename T> struct hb_match_reference : hb_type_identity_t<T>, hb_bool_constant<false>{};
|
||||
template <typename T> struct hb_match_reference<T &> : hb_type_identity_t<T>, hb_bool_constant<true> {};
|
||||
template <typename T> struct hb_match_reference<T &&> : hb_type_identity_t<T>, hb_bool_constant<true> {};
|
||||
template <typename T> using hb_remove_reference = typename hb_match_reference<T>::type;
|
||||
template <typename T> auto _hb_try_add_lvalue_reference (hb_priority<1>) -> hb_type_identity<T&>;
|
||||
template <typename T> auto _hb_try_add_lvalue_reference (hb_priority<0>) -> hb_type_identity<T>;
|
||||
template <typename T> using hb_add_lvalue_reference = decltype (_hb_try_add_lvalue_reference<T> (hb_prioritize));
|
||||
template <typename T> auto _hb_try_add_rvalue_reference (hb_priority<1>) -> hb_type_identity<T&&>;
|
||||
template <typename T> auto _hb_try_add_rvalue_reference (hb_priority<0>) -> hb_type_identity<T>;
|
||||
template <typename T> using hb_add_rvalue_reference = decltype (_hb_try_add_rvalue_reference<T> (hb_prioritize));
|
||||
#define hb_is_reference(T) hb_match_reference<T>::value
|
||||
template <typename T> struct hb_match_pointer { typedef T type; enum { value = false }; };
|
||||
template <typename T> struct hb_match_pointer<T *> { typedef T type; enum { value = true }; };
|
||||
template <typename T> struct hb_match_pointer : hb_type_identity_t<T>, hb_bool_constant<false>{};
|
||||
template <typename T> struct hb_match_pointer<T *> : hb_type_identity_t<T>, hb_bool_constant<true> {};
|
||||
template <typename T> using hb_remove_pointer = typename hb_match_pointer<T>::type;
|
||||
template <typename T> auto _hb_try_add_pointer (hb_priority<1>) -> hb_type_identity<hb_remove_reference<T>*>;
|
||||
template <typename T> auto _hb_try_add_pointer (hb_priority<1>) -> hb_type_identity<T>;
|
||||
template <typename T> using hb_add_pointer = decltype (_hb_try_add_pointer<T> (hb_prioritize));
|
||||
#define hb_is_pointer(T) hb_match_pointer<T>::value
|
||||
|
||||
|
||||
/* TODO Add feature-parity to std::decay. */
|
||||
template <typename T> using hb_decay = hb_remove_const<hb_remove_reference<T>>;
|
||||
|
||||
#define hb_is_cr_convertible_to(A, B) ( \
|
||||
hb_is_same (hb_decay<A>, hb_decay<B>) && \
|
||||
hb_is_const (A) <= hb_is_const (B) && \
|
||||
hb_is_reference (A) >= hb_is_reference (B))
|
||||
|
||||
template<bool B, class T, class F>
|
||||
struct _hb_conditional { typedef T type; };
|
||||
template<class T, class F>
|
||||
struct _hb_conditional<false, T, F> { typedef F type; };
|
||||
template<bool B, class T, class F>
|
||||
using hb_conditional = typename _hb_conditional<B, T, F>::type;
|
||||
|
||||
|
||||
template <typename From, typename To>
|
||||
struct hb_is_convertible
|
||||
{
|
||||
private:
|
||||
static constexpr bool from_void = hb_is_same (void, hb_decay<From>);
|
||||
static constexpr bool to_void = hb_is_same (void, hb_decay<To> );
|
||||
static constexpr bool either_void = from_void || to_void;
|
||||
static constexpr bool both_void = from_void && to_void;
|
||||
|
||||
static hb_true_type impl2 (hb_conditional<to_void, int, To>);
|
||||
|
||||
template <typename T>
|
||||
static auto impl (hb_priority<1>) -> decltype (impl2 (hb_declval (T)));
|
||||
template <typename T>
|
||||
static hb_false_type impl (hb_priority<0>);
|
||||
public:
|
||||
static constexpr bool value = both_void ||
|
||||
(!either_void &&
|
||||
decltype (impl<hb_conditional<from_void, int, From>> (hb_prioritize))::value);
|
||||
};
|
||||
#define hb_is_convertible(From,To) hb_is_convertible<From, To>::value
|
||||
|
||||
template <typename Base, typename Derived>
|
||||
using hb_is_base_of = hb_is_convertible<hb_decay<Derived> *, hb_decay<Base> *>;
|
||||
#define hb_is_base_of(Base,Derived) hb_is_base_of<Base, Derived>::value
|
||||
|
||||
template <typename From, typename To>
|
||||
using hb_is_cr_convertible = hb_bool_constant<
|
||||
hb_is_same (hb_decay<From>, hb_decay<To>) &&
|
||||
(!hb_is_const (From) || hb_is_const (To)) &&
|
||||
(!hb_is_reference (To) || hb_is_const (To) || hb_is_reference (To))
|
||||
>;
|
||||
#define hb_is_cr_convertible(From,To) hb_is_cr_convertible<From, To>::value
|
||||
|
||||
/* std::move and std::forward */
|
||||
|
||||
@ -125,56 +185,216 @@ struct
|
||||
|
||||
template <typename T> auto
|
||||
operator () (T *v) const HB_AUTO_RETURN (*v)
|
||||
}
|
||||
HB_FUNCOBJ (hb_deref);
|
||||
|
||||
} HB_FUNCOBJ (hb_deref_pointer);
|
||||
struct
|
||||
{
|
||||
template <typename T> auto
|
||||
operator () (T&& v) const HB_AUTO_RETURN (hb_forward<T> (v))
|
||||
|
||||
template <typename T> auto
|
||||
operator () (T& v) const HB_AUTO_RETURN (hb_addressof (v))
|
||||
}
|
||||
HB_FUNCOBJ (hb_ref);
|
||||
|
||||
template <typename T>
|
||||
struct hb_reference_wrapper
|
||||
{
|
||||
hb_reference_wrapper (T v) : v (v) {}
|
||||
bool operator == (const hb_reference_wrapper& o) const { return v == o.v; }
|
||||
bool operator != (const hb_reference_wrapper& o) const { return v != o.v; }
|
||||
operator T () const { return v; }
|
||||
T get () const { return v; }
|
||||
T v;
|
||||
};
|
||||
template <typename T>
|
||||
struct hb_reference_wrapper<T&>
|
||||
{
|
||||
hb_reference_wrapper (T& v) : v (hb_addressof (v)) {}
|
||||
bool operator == (const hb_reference_wrapper& o) const { return v == o.v; }
|
||||
bool operator != (const hb_reference_wrapper& o) const { return v != o.v; }
|
||||
operator T& () const { return *v; }
|
||||
T& get () const { return *v; }
|
||||
T* v;
|
||||
};
|
||||
|
||||
|
||||
template<bool B, typename T = void> struct hb_enable_if {};
|
||||
template<typename T> struct hb_enable_if<true, T> { typedef T type; };
|
||||
#define hb_enable_if(Cond) typename hb_enable_if<(Cond)>::type* = nullptr
|
||||
template <typename T>
|
||||
using hb_is_integral = hb_bool_constant<
|
||||
hb_is_same (hb_decay<T>, char) ||
|
||||
hb_is_same (hb_decay<T>, signed char) ||
|
||||
hb_is_same (hb_decay<T>, unsigned char) ||
|
||||
hb_is_same (hb_decay<T>, signed int) ||
|
||||
hb_is_same (hb_decay<T>, unsigned int) ||
|
||||
hb_is_same (hb_decay<T>, signed short) ||
|
||||
hb_is_same (hb_decay<T>, unsigned short) ||
|
||||
hb_is_same (hb_decay<T>, signed long) ||
|
||||
hb_is_same (hb_decay<T>, unsigned long) ||
|
||||
hb_is_same (hb_decay<T>, signed long long) ||
|
||||
hb_is_same (hb_decay<T>, unsigned long long) ||
|
||||
false
|
||||
>;
|
||||
#define hb_is_integral(T) hb_is_integral<T>::value
|
||||
template <typename T>
|
||||
using hb_is_floating_point = hb_bool_constant<
|
||||
hb_is_same (hb_decay<T>, float) ||
|
||||
hb_is_same (hb_decay<T>, double) ||
|
||||
hb_is_same (hb_decay<T>, long double) ||
|
||||
false
|
||||
>;
|
||||
#define hb_is_floating_point(T) hb_is_floating_point<T>::value
|
||||
template <typename T>
|
||||
using hb_is_arithmetic = hb_bool_constant<
|
||||
hb_is_integral (T) ||
|
||||
hb_is_floating_point (T) ||
|
||||
false
|
||||
>;
|
||||
#define hb_is_arithmetic(T) hb_is_arithmetic<T>::value
|
||||
|
||||
template <typename T, typename T2> struct hb_is_same : hb_false_t {};
|
||||
template <typename T> struct hb_is_same<T, T> : hb_true_t {};
|
||||
#define hb_is_same(T, T2) hb_is_same<T, T2>::value
|
||||
|
||||
template <typename T> struct hb_is_signed;
|
||||
template <> struct hb_is_signed<char> { enum { value = CHAR_MIN < 0 }; };
|
||||
template <> struct hb_is_signed<signed char> { enum { value = true }; };
|
||||
template <> struct hb_is_signed<unsigned char> { enum { value = false }; };
|
||||
template <> struct hb_is_signed<signed short> { enum { value = true }; };
|
||||
template <> struct hb_is_signed<unsigned short> { enum { value = false }; };
|
||||
template <> struct hb_is_signed<signed int> { enum { value = true }; };
|
||||
template <> struct hb_is_signed<unsigned int> { enum { value = false }; };
|
||||
template <> struct hb_is_signed<signed long> { enum { value = true }; };
|
||||
template <> struct hb_is_signed<unsigned long> { enum { value = false }; };
|
||||
template <> struct hb_is_signed<signed long long> { enum { value = true }; };
|
||||
template <> struct hb_is_signed<unsigned long long> { enum { value = false }; };
|
||||
template <typename T>
|
||||
using hb_is_signed = hb_conditional<hb_is_arithmetic (T),
|
||||
hb_bool_constant<(T) -1 < (T) 0>,
|
||||
hb_false_type>;
|
||||
#define hb_is_signed(T) hb_is_signed<T>::value
|
||||
template <typename T>
|
||||
using hb_is_unsigned = hb_conditional<hb_is_arithmetic (T),
|
||||
hb_bool_constant<(T) 0 < (T) -1>,
|
||||
hb_false_type>;
|
||||
#define hb_is_unsigned(T) hb_is_unsigned<T>::value
|
||||
|
||||
template <typename T> struct hb_int_min { static constexpr T value = 0; };
|
||||
template <> struct hb_int_min<char> { static constexpr char value = CHAR_MIN; };
|
||||
template <> struct hb_int_min<int> { static constexpr int value = INT_MIN; };
|
||||
template <> struct hb_int_min<long> { static constexpr long value = LONG_MIN; };
|
||||
template <typename T> struct hb_int_min;
|
||||
template <> struct hb_int_min<char> : hb_integral_constant<char, CHAR_MIN> {};
|
||||
template <> struct hb_int_min<signed char> : hb_integral_constant<signed char, SCHAR_MIN> {};
|
||||
template <> struct hb_int_min<unsigned char> : hb_integral_constant<unsigned char, 0> {};
|
||||
template <> struct hb_int_min<signed short> : hb_integral_constant<signed short, SHRT_MIN> {};
|
||||
template <> struct hb_int_min<unsigned short> : hb_integral_constant<unsigned short, 0> {};
|
||||
template <> struct hb_int_min<signed int> : hb_integral_constant<signed int, INT_MIN> {};
|
||||
template <> struct hb_int_min<unsigned int> : hb_integral_constant<unsigned int, 0> {};
|
||||
template <> struct hb_int_min<signed long> : hb_integral_constant<signed long, LONG_MIN> {};
|
||||
template <> struct hb_int_min<unsigned long> : hb_integral_constant<unsigned long, 0> {};
|
||||
template <> struct hb_int_min<signed long long> : hb_integral_constant<signed long long, LLONG_MIN> {};
|
||||
template <> struct hb_int_min<unsigned long long> : hb_integral_constant<unsigned long long, 0> {};
|
||||
#define hb_int_min(T) hb_int_min<T>::value
|
||||
template <typename T> struct hb_int_max;
|
||||
template <> struct hb_int_max<char> : hb_integral_constant<char, CHAR_MAX> {};
|
||||
template <> struct hb_int_max<signed char> : hb_integral_constant<signed char, SCHAR_MAX> {};
|
||||
template <> struct hb_int_max<unsigned char> : hb_integral_constant<unsigned char, UCHAR_MAX> {};
|
||||
template <> struct hb_int_max<signed short> : hb_integral_constant<signed short, SHRT_MAX> {};
|
||||
template <> struct hb_int_max<unsigned short> : hb_integral_constant<unsigned short, USHRT_MAX> {};
|
||||
template <> struct hb_int_max<signed int> : hb_integral_constant<signed int, INT_MAX> {};
|
||||
template <> struct hb_int_max<unsigned int> : hb_integral_constant<unsigned int, UINT_MAX> {};
|
||||
template <> struct hb_int_max<signed long> : hb_integral_constant<signed long, LONG_MAX> {};
|
||||
template <> struct hb_int_max<unsigned long> : hb_integral_constant<unsigned long, ULONG_MAX> {};
|
||||
template <> struct hb_int_max<signed long long> : hb_integral_constant<signed long long, LLONG_MAX> {};
|
||||
template <> struct hb_int_max<unsigned long long> : hb_integral_constant<unsigned long long, ULLONG_MAX> {};
|
||||
#define hb_int_max(T) hb_int_max<T>::value
|
||||
|
||||
template <bool is_signed> struct hb_signedness_int;
|
||||
template <> struct hb_signedness_int<false> { typedef unsigned int value; };
|
||||
template <> struct hb_signedness_int<true> { typedef signed int value; };
|
||||
#define hb_signedness_int(T) hb_signedness_int<T>::value
|
||||
|
||||
template <typename T> struct hb_is_integer { enum { value = false }; };
|
||||
template <> struct hb_is_integer<char> { enum { value = true }; };
|
||||
template <> struct hb_is_integer<signed char> { enum { value = true }; };
|
||||
template <> struct hb_is_integer<unsigned char> { enum { value = true }; };
|
||||
template <> struct hb_is_integer<signed short> { enum { value = true }; };
|
||||
template <> struct hb_is_integer<unsigned short> { enum { value = true }; };
|
||||
template <> struct hb_is_integer<signed int> { enum { value = true }; };
|
||||
template <> struct hb_is_integer<unsigned int> { enum { value = true }; };
|
||||
template <> struct hb_is_integer<signed long> { enum { value = true }; };
|
||||
template <> struct hb_is_integer<unsigned long> { enum { value = true }; };
|
||||
template <> struct hb_is_integer<signed long long> { enum { value = true }; };
|
||||
template <> struct hb_is_integer<unsigned long long> { enum { value = true }; };
|
||||
#define hb_is_integer(T) hb_is_integer<T>::value
|
||||
|
||||
template <typename T, typename>
|
||||
struct _hb_is_destructible : hb_false_type {};
|
||||
template <typename T>
|
||||
struct _hb_is_destructible<T, hb_void_t<decltype (hb_declval (T).~T ())>> : hb_true_type {};
|
||||
template <typename T>
|
||||
using hb_is_destructible = _hb_is_destructible<T, void>;
|
||||
#define hb_is_destructible(T) hb_is_destructible<T>::value
|
||||
|
||||
template <typename T, typename, typename ...Ts>
|
||||
struct _hb_is_constructible : hb_false_type {};
|
||||
template <typename T, typename ...Ts>
|
||||
struct _hb_is_constructible<T, hb_void_t<decltype (T (hb_declval (Ts)...))>, Ts...> : hb_true_type {};
|
||||
template <typename T, typename ...Ts>
|
||||
using hb_is_constructible = _hb_is_constructible<T, void, Ts...>;
|
||||
#define hb_is_constructible(...) hb_is_constructible<__VA_ARGS__>::value
|
||||
|
||||
template <typename T>
|
||||
using hb_is_default_constructible = hb_is_constructible<T>;
|
||||
#define hb_is_default_constructible(T) hb_is_default_constructible<T>::value
|
||||
|
||||
template <typename T>
|
||||
using hb_is_copy_constructible = hb_is_constructible<T, hb_add_lvalue_reference<hb_add_const<T>>>;
|
||||
#define hb_is_copy_constructible(T) hb_is_copy_constructible<T>::value
|
||||
|
||||
template <typename T>
|
||||
using hb_is_move_constructible = hb_is_constructible<T, hb_add_rvalue_reference<hb_add_const<T>>>;
|
||||
#define hb_is_move_constructible(T) hb_is_move_constructible<T>::value
|
||||
|
||||
template <typename T, typename U, typename>
|
||||
struct _hb_is_assignable : hb_false_type {};
|
||||
template <typename T, typename U>
|
||||
struct _hb_is_assignable<T, U, hb_void_t<decltype (hb_declval (T) = hb_declval (U))>> : hb_true_type {};
|
||||
template <typename T, typename U>
|
||||
using hb_is_assignable = _hb_is_assignable<T, U, void>;
|
||||
#define hb_is_assignable(T,U) hb_is_assignable<T, U>::value
|
||||
|
||||
template <typename T>
|
||||
using hb_is_copy_assignable = hb_is_assignable<hb_add_lvalue_reference<T>,
|
||||
hb_add_lvalue_reference<hb_add_const<T>>>;
|
||||
#define hb_is_copy_assignable(T) hb_is_copy_assignable<T>::value
|
||||
|
||||
template <typename T>
|
||||
using hb_is_move_assignable = hb_is_assignable<hb_add_lvalue_reference<T>,
|
||||
hb_add_rvalue_reference<T>>;
|
||||
#define hb_is_move_assignable(T) hb_is_move_assignable<T>::value
|
||||
|
||||
/* Trivial versions. */
|
||||
|
||||
template <typename T> union hb_trivial { T value; };
|
||||
|
||||
/* Don't know how to do the following. */
|
||||
template <typename T>
|
||||
using hb_is_trivially_destructible= hb_is_destructible<hb_trivial<T>>;
|
||||
#define hb_is_trivially_destructible(T) hb_is_trivially_destructible<T>::value
|
||||
|
||||
/* Don't know how to do the following. */
|
||||
//template <typename T, typename ...Ts>
|
||||
//using hb_is_trivially_constructible= hb_is_constructible<hb_trivial<T>, hb_trivial<Ts>...>;
|
||||
//#define hb_is_trivially_constructible(...) hb_is_trivially_constructible<__VA_ARGS__>::value
|
||||
|
||||
template <typename T>
|
||||
using hb_is_trivially_default_constructible= hb_is_default_constructible<hb_trivial<T>>;
|
||||
#define hb_is_trivially_default_constructible(T) hb_is_trivially_default_constructible<T>::value
|
||||
|
||||
template <typename T>
|
||||
using hb_is_trivially_copy_constructible= hb_is_copy_constructible<hb_trivial<T>>;
|
||||
#define hb_is_trivially_copy_constructible(T) hb_is_trivially_copy_constructible<T>::value
|
||||
|
||||
template <typename T>
|
||||
using hb_is_trivially_move_constructible= hb_is_move_constructible<hb_trivial<T>>;
|
||||
#define hb_is_trivially_move_constructible(T) hb_is_trivially_move_constructible<T>::value
|
||||
|
||||
/* Don't know how to do the following. */
|
||||
//template <typename T, typename U>
|
||||
//using hb_is_trivially_assignable= hb_is_assignable<hb_trivial<T>, hb_trivial<U>>;
|
||||
//#define hb_is_trivially_assignable(T,U) hb_is_trivially_assignable<T, U>::value
|
||||
|
||||
template <typename T>
|
||||
using hb_is_trivially_copy_assignable= hb_is_copy_assignable<hb_trivial<T>>;
|
||||
#define hb_is_trivially_copy_assignable(T) hb_is_trivially_copy_assignable<T>::value
|
||||
|
||||
template <typename T>
|
||||
using hb_is_trivially_move_assignable= hb_is_move_assignable<hb_trivial<T>>;
|
||||
#define hb_is_trivially_move_assignable(T) hb_is_trivially_move_assignable<T>::value
|
||||
|
||||
template <typename T>
|
||||
using hb_is_trivially_copyable= hb_bool_constant<
|
||||
hb_is_trivially_destructible (T) &&
|
||||
(!hb_is_move_assignable (T) || hb_is_trivially_move_assignable (T)) &&
|
||||
(!hb_is_move_constructible (T) || hb_is_trivially_move_constructible (T)) &&
|
||||
(!hb_is_copy_assignable (T) || hb_is_trivially_copy_assignable (T)) &&
|
||||
(!hb_is_copy_constructible (T) || hb_is_trivially_copy_constructible (T)) &&
|
||||
true
|
||||
>;
|
||||
#define hb_is_trivially_copyable(T) hb_is_trivially_copyable<T>::value
|
||||
|
||||
template <typename T>
|
||||
using hb_is_trivial= hb_bool_constant<
|
||||
hb_is_trivially_copyable (T) &&
|
||||
hb_is_trivially_default_constructible (T)
|
||||
>;
|
||||
#define hb_is_trivial(T) hb_is_trivial<T>::value
|
||||
|
||||
|
||||
#endif /* HB_META_HH */
|
||||
|
@ -48,6 +48,17 @@
|
||||
/* Defined externally, i.e. in config.h; must have typedef'ed hb_mutex_impl_t as well. */
|
||||
|
||||
|
||||
#elif !defined(HB_NO_MT) && (defined(HAVE_PTHREAD) || defined(__APPLE__))
|
||||
|
||||
#include <pthread.h>
|
||||
typedef pthread_mutex_t hb_mutex_impl_t;
|
||||
#define HB_MUTEX_IMPL_INIT PTHREAD_MUTEX_INITIALIZER
|
||||
#define hb_mutex_impl_init(M) pthread_mutex_init (M, nullptr)
|
||||
#define hb_mutex_impl_lock(M) pthread_mutex_lock (M)
|
||||
#define hb_mutex_impl_unlock(M) pthread_mutex_unlock (M)
|
||||
#define hb_mutex_impl_finish(M) pthread_mutex_destroy (M)
|
||||
|
||||
|
||||
#elif !defined(HB_NO_MT) && defined(_WIN32)
|
||||
|
||||
#include <windows.h>
|
||||
@ -63,17 +74,6 @@ typedef CRITICAL_SECTION hb_mutex_impl_t;
|
||||
#define hb_mutex_impl_finish(M) DeleteCriticalSection (M)
|
||||
|
||||
|
||||
#elif !defined(HB_NO_MT) && (defined(HAVE_PTHREAD) || defined(__APPLE__))
|
||||
|
||||
#include <pthread.h>
|
||||
typedef pthread_mutex_t hb_mutex_impl_t;
|
||||
#define HB_MUTEX_IMPL_INIT PTHREAD_MUTEX_INITIALIZER
|
||||
#define hb_mutex_impl_init(M) pthread_mutex_init (M, nullptr)
|
||||
#define hb_mutex_impl_lock(M) pthread_mutex_lock (M)
|
||||
#define hb_mutex_impl_unlock(M) pthread_mutex_unlock (M)
|
||||
#define hb_mutex_impl_finish(M) pthread_mutex_destroy (M)
|
||||
|
||||
|
||||
#elif !defined(HB_NO_MT) && defined(HAVE_INTEL_ATOMIC_PRIMITIVES)
|
||||
|
||||
#if defined(HAVE_SCHED_H) && defined(HAVE_SCHED_YIELD)
|
||||
|
@ -46,16 +46,13 @@
|
||||
* https://stackoverflow.com/questions/7776448/sfinae-tried-with-bool-gives-compiler-error-template-argument-tvalue-invol
|
||||
*/
|
||||
|
||||
template <typename T, typename B>
|
||||
struct _hb_null_size
|
||||
{ enum { value = sizeof (T) }; };
|
||||
template <typename T, typename>
|
||||
struct _hb_null_size : hb_integral_constant<unsigned, sizeof (T)> {};
|
||||
template <typename T>
|
||||
struct _hb_null_size<T, hb_bool_tt<true || sizeof (T::min_size)> >
|
||||
{ enum { value = T::null_size }; };
|
||||
struct _hb_null_size<T, hb_void_t<decltype (T::min_size)>> : hb_integral_constant<unsigned, T::null_size> {};
|
||||
|
||||
template <typename T>
|
||||
struct hb_null_size
|
||||
{ enum { value = _hb_null_size<T, hb_true_t>::value }; };
|
||||
using hb_null_size = _hb_null_size<T, void>;
|
||||
#define hb_null_size(T) hb_null_size<T>::value
|
||||
|
||||
/* These doesn't belong here, but since is copy/paste from above, put it here. */
|
||||
@ -63,16 +60,12 @@ struct hb_null_size
|
||||
/* hb_static_size (T)
|
||||
* Returns T::static_size if T::min_size is defined, or sizeof (T) otherwise. */
|
||||
|
||||
template <typename T, typename B>
|
||||
struct _hb_static_size
|
||||
{ enum { value = sizeof (T) }; };
|
||||
template <typename T, typename>
|
||||
struct _hb_static_size : hb_integral_constant<unsigned, sizeof (T)> {};
|
||||
template <typename T>
|
||||
struct _hb_static_size<T, hb_bool_tt<true || sizeof (T::min_size)> >
|
||||
{ enum { value = T::static_size }; };
|
||||
|
||||
struct _hb_static_size<T, hb_void_t<decltype (T::min_size)>> : hb_integral_constant<unsigned, T::static_size> {};
|
||||
template <typename T>
|
||||
struct hb_static_size
|
||||
{ enum { value = _hb_static_size<T, hb_true_t>::value }; };
|
||||
using hb_static_size = _hb_static_size<T, void>;
|
||||
#define hb_static_size(T) hb_static_size<T>::value
|
||||
|
||||
|
||||
@ -95,7 +88,7 @@ struct Null {
|
||||
template <typename QType>
|
||||
struct NullHelper
|
||||
{
|
||||
typedef hb_remove_const<hb_remove_reference<QType> > Type;
|
||||
typedef hb_remove_const<hb_remove_reference<QType>> Type;
|
||||
static const Type & get_null () { return Null<Type>::get_null (); }
|
||||
};
|
||||
#define Null(Type) NullHelper<Type>::get_null ()
|
||||
@ -148,7 +141,7 @@ static inline Type& Crap () {
|
||||
template <typename QType>
|
||||
struct CrapHelper
|
||||
{
|
||||
typedef hb_remove_const<hb_remove_reference<QType> > Type;
|
||||
typedef hb_remove_const<hb_remove_reference<QType>> Type;
|
||||
static Type & get_crap () { return Crap<Type> (); }
|
||||
};
|
||||
#define Crap(Type) CrapHelper<Type>::get_crap ()
|
||||
|
@ -94,7 +94,7 @@ typedef struct OffsetTable
|
||||
if (start_offset >= tables.len)
|
||||
*table_count = 0;
|
||||
else
|
||||
*table_count = MIN<unsigned int> (*table_count, tables.len - start_offset);
|
||||
*table_count = hb_min (*table_count, tables.len - start_offset);
|
||||
|
||||
const TableRecord *sub_tables = tables.arrayZ + start_offset;
|
||||
unsigned int count = *table_count;
|
||||
@ -222,7 +222,7 @@ struct TTCHeaderVersion1
|
||||
Tag ttcTag; /* TrueType Collection ID string: 'ttcf' */
|
||||
FixedVersion<>version; /* Version of the TTC Header (1.0),
|
||||
* 0x00010000u */
|
||||
LArrayOf<LOffsetTo<OffsetTable> >
|
||||
LArrayOf<LOffsetTo<OffsetTable>>
|
||||
table; /* Array of offsets to the OffsetTable for each font
|
||||
* from the beginning of the file */
|
||||
public:
|
||||
@ -334,7 +334,7 @@ struct ResourceTypeRecord
|
||||
protected:
|
||||
Tag tag; /* Resource type. */
|
||||
HBUINT16 resCountM1; /* Number of resources minus 1. */
|
||||
NNOffsetTo<UnsizedArrayOf<ResourceRecord> >
|
||||
NNOffsetTo<UnsizedArrayOf<ResourceRecord>>
|
||||
resourcesZ; /* Offset from beginning of resource type list
|
||||
* to reference item list for this type. */
|
||||
public:
|
||||
@ -390,7 +390,7 @@ struct ResourceMap
|
||||
HBUINT32 reserved1; /* Reserved for handle to next resource map */
|
||||
HBUINT16 resreved2; /* Reserved for file reference number */
|
||||
HBUINT16 attrs; /* Resource fork attribute */
|
||||
NNOffsetTo<ArrayOfM1<ResourceTypeRecord> >
|
||||
NNOffsetTo<ArrayOfM1<ResourceTypeRecord>>
|
||||
typeList; /* Offset from beginning of map to
|
||||
* resource type list */
|
||||
Offset16 nameList; /* Offset from beginning of map to
|
||||
@ -422,7 +422,7 @@ struct ResourceForkHeader
|
||||
}
|
||||
|
||||
protected:
|
||||
LNNOffsetTo<UnsizedArrayOf<HBUINT8> >
|
||||
LNNOffsetTo<UnsizedArrayOf<HBUINT8>>
|
||||
data; /* Offset from beginning of resource fork
|
||||
* to resource data */
|
||||
LNNOffsetTo<ResourceMap >
|
||||
|
@ -57,7 +57,7 @@ template <typename Type, unsigned int Size>
|
||||
struct IntType
|
||||
{
|
||||
typedef Type type;
|
||||
typedef typename hb_signedness_int (hb_is_signed (Type)) wide_type;
|
||||
typedef hb_conditional<hb_is_signed (Type), signed, unsigned> wide_type;
|
||||
|
||||
IntType<Type, Size>& operator = (wide_type i) { v = i; return *this; }
|
||||
operator wide_type () const { return v; }
|
||||
@ -110,7 +110,7 @@ struct F2DOT14 : HBINT16
|
||||
F2DOT14& operator = (uint16_t i ) { HBINT16::operator= (i); return *this; }
|
||||
// 16384 means 1<<14
|
||||
float to_float () const { return ((int32_t) v) / 16384.f; }
|
||||
void set_float (float f) { v = round (f * 16384.f); }
|
||||
void set_float (float f) { v = roundf (f * 16384.f); }
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (2);
|
||||
};
|
||||
@ -121,7 +121,7 @@ struct Fixed : HBINT32
|
||||
Fixed& operator = (uint32_t i) { HBINT32::operator= (i); return *this; }
|
||||
// 65536 means 1<<16
|
||||
float to_float () const { return ((int32_t) v) / 65536.f; }
|
||||
void set_float (float f) { v = round (f * 65536.f); }
|
||||
void set_float (float f) { v = roundf (f * 65536.f); }
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (4);
|
||||
};
|
||||
@ -279,32 +279,70 @@ struct OffsetTo : Offset<OffsetType, has_null>
|
||||
return StructAtOffset<Type> (base, *this);
|
||||
}
|
||||
|
||||
template <typename Base,
|
||||
hb_enable_if (hb_is_convertible (const Base, const void *))>
|
||||
friend const Type& operator + (const Base &base, const OffsetTo &offset) { return offset ((const void *) base); }
|
||||
template <typename Base,
|
||||
hb_enable_if (hb_is_convertible (const Base, const void *))>
|
||||
friend const Type& operator + (const OffsetTo &offset, const Base &base) { return offset ((const void *) base); }
|
||||
template <typename Base,
|
||||
hb_enable_if (hb_is_convertible (Base, void *))>
|
||||
friend Type& operator + (Base &&base, OffsetTo &offset) { return offset ((void *) base); }
|
||||
template <typename Base,
|
||||
hb_enable_if (hb_is_convertible (Base, void *))>
|
||||
friend Type& operator + (OffsetTo &offset, Base &&base) { return offset ((void *) base); }
|
||||
|
||||
Type& serialize (hb_serialize_context_t *c, const void *base)
|
||||
{
|
||||
return * (Type *) Offset<OffsetType>::serialize (c, base);
|
||||
}
|
||||
|
||||
template <typename T, typename ...Ts>
|
||||
bool serialize_subset (hb_subset_context_t *c, const T &src, const void *base, Ts &&...ds)
|
||||
template <typename ...Ts>
|
||||
bool serialize_subset (hb_subset_context_t *c,
|
||||
const OffsetTo& src,
|
||||
const void *src_base,
|
||||
const void *dst_base,
|
||||
Ts&&... ds)
|
||||
{
|
||||
*this = 0;
|
||||
if (has_null && &src == &Null (T))
|
||||
if (src.is_null ())
|
||||
return false;
|
||||
|
||||
auto *s = c->serializer;
|
||||
|
||||
s->push ();
|
||||
|
||||
bool ret = src.subset (c, hb_forward<Ts> (ds)...);
|
||||
bool ret = c->dispatch (src_base+src, hb_forward<Ts> (ds)...);
|
||||
|
||||
if (ret || !has_null)
|
||||
s->add_link (*this, s->pop_pack (), base);
|
||||
s->add_link (*this, s->pop_pack (), dst_base);
|
||||
else
|
||||
s->pop_discard ();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* TODO: Somehow merge this with previous function into a serialize_dispatch(). */
|
||||
template <typename ...Ts>
|
||||
bool serialize_copy (hb_serialize_context_t *c,
|
||||
const OffsetTo& src,
|
||||
const void *src_base,
|
||||
const void *dst_base,
|
||||
Ts&&... ds)
|
||||
{
|
||||
*this = 0;
|
||||
if (src.is_null ())
|
||||
return false;
|
||||
|
||||
c->push ();
|
||||
|
||||
bool ret = c->copy (src_base+src, hb_forward<Ts> (ds)...);
|
||||
|
||||
c->add_link (*this, c->pop_pack (), dst_base);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool sanitize_shallow (hb_sanitize_context_t *c, const void *base) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
@ -315,12 +353,12 @@ struct OffsetTo : Offset<OffsetType, has_null>
|
||||
}
|
||||
|
||||
template <typename ...Ts>
|
||||
bool sanitize (hb_sanitize_context_t *c, const void *base, Ts &&...ds) const
|
||||
bool sanitize (hb_sanitize_context_t *c, const void *base, Ts&&... ds) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (sanitize_shallow (c, base) &&
|
||||
(this->is_null () ||
|
||||
StructAtOffset<Type> (base, *this).sanitize (c, hb_forward<Ts> (ds)...) ||
|
||||
c->dispatch (StructAtOffset<Type> (base, *this), hb_forward<Ts> (ds)...) ||
|
||||
neuter (c)));
|
||||
}
|
||||
|
||||
@ -340,11 +378,6 @@ using NNOffsetTo = OffsetTo<Type, OffsetType, false>;
|
||||
template <typename Type>
|
||||
using LNNOffsetTo = LOffsetTo<Type, false>;
|
||||
|
||||
template <typename Base, typename OffsetType, bool has_null, typename Type>
|
||||
static inline const Type& operator + (const Base &base, const OffsetTo<Type, OffsetType, has_null> &offset) { return offset (base); }
|
||||
template <typename Base, typename OffsetType, bool has_null, typename Type>
|
||||
static inline Type& operator + (Base &base, OffsetTo<Type, OffsetType, has_null> &offset) { return offset (base); }
|
||||
|
||||
|
||||
/*
|
||||
* Array Types
|
||||
@ -395,35 +428,42 @@ struct UnsizedArrayOf
|
||||
void qsort (unsigned int len, unsigned int start = 0, unsigned int end = (unsigned int) -1)
|
||||
{ as_array (len).qsort (start, end); }
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c, unsigned int count) const
|
||||
bool serialize (hb_serialize_context_t *c, unsigned int items_len)
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
if (unlikely (!sanitize_shallow (c, count))) return_trace (false);
|
||||
|
||||
/* Note: for structs that do not reference other structs,
|
||||
* we do not need to call their sanitize() as we already did
|
||||
* a bound check on the aggregate array size. We just include
|
||||
* a small unreachable expression to make sure the structs
|
||||
* pointed to do have a simple sanitize() as well as an
|
||||
* assignment opreator. This ensures that they do not
|
||||
* reference other structs via offsets.
|
||||
*/
|
||||
if (false)
|
||||
{
|
||||
arrayZ[0].sanitize (c);
|
||||
Type v;
|
||||
v = arrayZ[0];
|
||||
}
|
||||
|
||||
TRACE_SERIALIZE (this);
|
||||
if (unlikely (!c->extend (*this, items_len))) return_trace (false);
|
||||
return_trace (true);
|
||||
}
|
||||
template <typename Iterator,
|
||||
hb_requires (hb_is_source_of (Iterator, Type))>
|
||||
bool serialize (hb_serialize_context_t *c, Iterator items)
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
unsigned count = items.len ();
|
||||
if (unlikely (!serialize (c, count))) return_trace (false);
|
||||
/* TODO Umm. Just exhaust the iterator instead? Being extra
|
||||
* cautious right now.. */
|
||||
for (unsigned i = 0; i < count; i++, ++items)
|
||||
arrayZ[i] = *items;
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
UnsizedArrayOf* copy (hb_serialize_context_t *c, unsigned count) const
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
auto *out = c->start_embed (this);
|
||||
if (unlikely (!as_array (count).copy (c))) return_trace (nullptr);
|
||||
return_trace (out);
|
||||
}
|
||||
|
||||
template <typename ...Ts>
|
||||
bool sanitize (hb_sanitize_context_t *c, unsigned int count, Ts &&...ds) const
|
||||
bool sanitize (hb_sanitize_context_t *c, unsigned int count, Ts&&... ds) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
if (unlikely (!sanitize_shallow (c, count))) return_trace (false);
|
||||
if (!sizeof... (Ts) && hb_is_trivially_copyable (Type)) return_trace (true);
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
if (unlikely (!arrayZ[i].sanitize (c, hb_forward<Ts> (ds)...)))
|
||||
if (unlikely (!c->dispatch (arrayZ[i], hb_forward<Ts> (ds)...)))
|
||||
return_trace (false);
|
||||
return_trace (true);
|
||||
}
|
||||
@ -442,7 +482,7 @@ struct UnsizedArrayOf
|
||||
|
||||
/* Unsized array of offset's */
|
||||
template <typename Type, typename OffsetType, bool has_null=true>
|
||||
using UnsizedOffsetArrayOf = UnsizedArrayOf<OffsetTo<Type, OffsetType, has_null> >;
|
||||
using UnsizedOffsetArrayOf = UnsizedArrayOf<OffsetTo<Type, OffsetType, has_null>>;
|
||||
|
||||
/* Unsized array of offsets relative to the beginning of the array itself. */
|
||||
template <typename Type, typename OffsetType, bool has_null=true>
|
||||
@ -464,7 +504,7 @@ struct UnsizedOffsetListOf : UnsizedOffsetArrayOf<Type, OffsetType, has_null>
|
||||
}
|
||||
|
||||
template <typename ...Ts>
|
||||
bool sanitize (hb_sanitize_context_t *c, unsigned int count, Ts &&...ds) const
|
||||
bool sanitize (hb_sanitize_context_t *c, unsigned int count, Ts&&... ds) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace ((UnsizedOffsetArrayOf<Type, OffsetType, has_null>
|
||||
@ -553,7 +593,7 @@ struct ArrayOf
|
||||
return_trace (true);
|
||||
}
|
||||
template <typename Iterator,
|
||||
hb_enable_if (hb_is_iterator_of (Iterator, const Type))>
|
||||
hb_requires (hb_is_source_of (Iterator, Type))>
|
||||
bool serialize (hb_serialize_context_t *c, Iterator items)
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
@ -561,41 +601,30 @@ struct ArrayOf
|
||||
if (unlikely (!serialize (c, count))) return_trace (false);
|
||||
/* TODO Umm. Just exhaust the iterator instead? Being extra
|
||||
* cautious right now.. */
|
||||
for (unsigned i = 0; i < count; i++, items++)
|
||||
for (unsigned i = 0; i < count; i++, ++items)
|
||||
arrayZ[i] = *items;
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
ArrayOf* copy (hb_serialize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
if (unlikely (!sanitize_shallow (c))) return_trace (false);
|
||||
|
||||
/* Note: for structs that do not reference other structs,
|
||||
* we do not need to call their sanitize() as we already did
|
||||
* a bound check on the aggregate array size. We just include
|
||||
* a small unreachable expression to make sure the structs
|
||||
* pointed to do have a simple sanitize() as well as an
|
||||
* assignment opreator. This ensures that they do not
|
||||
* reference other structs via offsets.
|
||||
*/
|
||||
if (false)
|
||||
{
|
||||
arrayZ[0].sanitize (c);
|
||||
Type v;
|
||||
v = arrayZ[0];
|
||||
}
|
||||
|
||||
return_trace (true);
|
||||
TRACE_SERIALIZE (this);
|
||||
auto *out = c->start_embed (this);
|
||||
if (unlikely (!c->extend_min (out))) return_trace (nullptr);
|
||||
c->check_assign (out->len, len);
|
||||
if (unlikely (!as_array ().copy (c))) return_trace (nullptr);
|
||||
return_trace (out);
|
||||
}
|
||||
|
||||
template <typename ...Ts>
|
||||
bool sanitize (hb_sanitize_context_t *c, Ts &&...ds) const
|
||||
bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
if (unlikely (!sanitize_shallow (c))) return_trace (false);
|
||||
if (!sizeof... (Ts) && hb_is_trivially_copyable (Type)) return_trace (true);
|
||||
unsigned int count = len;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
if (unlikely (!arrayZ[i].sanitize (c, hb_forward<Ts> (ds)...)))
|
||||
if (unlikely (!c->dispatch (arrayZ[i], hb_forward<Ts> (ds)...)))
|
||||
return_trace (false);
|
||||
return_trace (true);
|
||||
}
|
||||
@ -628,9 +657,9 @@ using PString = ArrayOf<HBUINT8, HBUINT8>;
|
||||
|
||||
/* Array of Offset's */
|
||||
template <typename Type>
|
||||
using OffsetArrayOf = ArrayOf<OffsetTo<Type, HBUINT16> >;
|
||||
using OffsetArrayOf = ArrayOf<OffsetTo<Type, HBUINT16>>;
|
||||
template <typename Type>
|
||||
using LOffsetArrayOf = ArrayOf<OffsetTo<Type, HBUINT32> >;
|
||||
using LOffsetArrayOf = ArrayOf<OffsetTo<Type, HBUINT32>>;
|
||||
template <typename Type>
|
||||
using LOffsetLArrayOf = ArrayOf<OffsetTo<Type, HBUINT32>, HBUINT32>;
|
||||
|
||||
@ -658,12 +687,12 @@ struct OffsetListOf : OffsetArrayOf<Type>
|
||||
if (unlikely (!out)) return_trace (false);
|
||||
unsigned int count = this->len;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
out->arrayZ[i].serialize_subset (c, (*this)[i], out);
|
||||
out->arrayZ[i].serialize_subset (c, this->arrayZ[i], this, out);
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
template <typename ...Ts>
|
||||
bool sanitize (hb_sanitize_context_t *c, Ts &&...ds) const
|
||||
bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (OffsetArrayOf<Type>::sanitize (c, this, hb_forward<Ts> (ds)...));
|
||||
@ -705,26 +734,16 @@ struct HeadlessArrayOf
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
template <typename ...Ts>
|
||||
bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
if (unlikely (!sanitize_shallow (c))) return_trace (false);
|
||||
|
||||
/* Note: for structs that do not reference other structs,
|
||||
* we do not need to call their sanitize() as we already did
|
||||
* a bound check on the aggregate array size. We just include
|
||||
* a small unreachable expression to make sure the structs
|
||||
* pointed to do have a simple sanitize() as well as an
|
||||
* assignment opreator. This ensures that they do not
|
||||
* reference other structs via offsets.
|
||||
*/
|
||||
if (false)
|
||||
{
|
||||
arrayZ[0].sanitize (c);
|
||||
Type v;
|
||||
v = arrayZ[0];
|
||||
}
|
||||
|
||||
if (!sizeof... (Ts) && hb_is_trivially_copyable (Type)) return_trace (true);
|
||||
unsigned int count = lenP1 ? lenP1 - 1 : 0;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
if (unlikely (!c->dispatch (arrayZ[i], hb_forward<Ts> (ds)...)))
|
||||
return_trace (false);
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
@ -765,13 +784,13 @@ struct ArrayOfM1
|
||||
{ return lenM1.static_size + (lenM1 + 1) * Type::static_size; }
|
||||
|
||||
template <typename ...Ts>
|
||||
bool sanitize (hb_sanitize_context_t *c, Ts &&...ds) const
|
||||
bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
if (unlikely (!sanitize_shallow (c))) return_trace (false);
|
||||
unsigned int count = lenM1 + 1;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
if (unlikely (!arrayZ[i].sanitize (c, hb_forward<Ts> (ds)...)))
|
||||
if (unlikely (!c->dispatch (arrayZ[i], hb_forward<Ts> (ds)...)))
|
||||
return_trace (false);
|
||||
return_trace (true);
|
||||
}
|
||||
@ -822,7 +841,7 @@ struct SortedArrayOf : ArrayOf<Type, LenType>
|
||||
return_trace (ret);
|
||||
}
|
||||
template <typename Iterator,
|
||||
hb_enable_if (hb_is_sorted_iterator_of (Iterator, const Type))>
|
||||
hb_requires (hb_is_sorted_source_of (Iterator, Type))>
|
||||
bool serialize (hb_serialize_context_t *c, Iterator items)
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
@ -830,7 +849,6 @@ struct SortedArrayOf : ArrayOf<Type, LenType>
|
||||
return_trace (ret);
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
Type &bsearch (const T &x, Type ¬_found = Crap (Type))
|
||||
{ return *as_array ().bsearch (x, ¬_found); }
|
||||
@ -863,7 +881,7 @@ struct BinSearchHeader
|
||||
{
|
||||
len = v;
|
||||
assert (len == v);
|
||||
entrySelector = MAX (1u, hb_bit_storage (v)) - 1;
|
||||
entrySelector = hb_max (1u, hb_bit_storage (v)) - 1;
|
||||
searchRange = 16 * (1u << entrySelector);
|
||||
rangeShift = v * 16 > searchRange
|
||||
? 16 * v - searchRange
|
||||
@ -882,7 +900,7 @@ struct BinSearchHeader
|
||||
};
|
||||
|
||||
template <typename Type, typename LenType=HBUINT16>
|
||||
using BinSearchArrayOf = SortedArrayOf<Type, BinSearchHeader<LenType> >;
|
||||
using BinSearchArrayOf = SortedArrayOf<Type, BinSearchHeader<LenType>>;
|
||||
|
||||
|
||||
struct VarSizedBinSearchHeader
|
||||
@ -947,33 +965,12 @@ struct VarSizedBinSearchArrayOf
|
||||
unsigned int get_size () const
|
||||
{ return header.static_size + header.nUnits * header.unitSize; }
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
if (unlikely (!sanitize_shallow (c))) return_trace (false);
|
||||
|
||||
/* Note: for structs that do not reference other structs,
|
||||
* we do not need to call their sanitize() as we already did
|
||||
* a bound check on the aggregate array size. We just include
|
||||
* a small unreachable expression to make sure the structs
|
||||
* pointed to do have a simple sanitize() as well as an
|
||||
* assignment opreator. This ensures that they do not
|
||||
* reference other structs via offsets.
|
||||
*/
|
||||
if (false)
|
||||
{
|
||||
(*this)[0].sanitize (c);
|
||||
Type v;
|
||||
v = (*this)[0];
|
||||
}
|
||||
|
||||
return_trace (true);
|
||||
}
|
||||
template <typename ...Ts>
|
||||
bool sanitize (hb_sanitize_context_t *c, Ts &&...ds) const
|
||||
bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
if (unlikely (!sanitize_shallow (c))) return_trace (false);
|
||||
if (!sizeof... (Ts) && hb_is_trivially_copyable (Type)) return_trace (true);
|
||||
unsigned int count = get_length ();
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
if (unlikely (!(*this)[i].sanitize (c, hb_forward<Ts> (ds)...)))
|
||||
|
@ -97,12 +97,12 @@ struct CFFIndex
|
||||
unsigned int offset_array_size () const
|
||||
{ return calculate_offset_array_size (offSize, count); }
|
||||
|
||||
static unsigned int calculate_serialized_size (unsigned int offSize, unsigned int count, unsigned int dataSize)
|
||||
static unsigned int calculate_serialized_size (unsigned int offSize_, unsigned int count, unsigned int dataSize)
|
||||
{
|
||||
if (count == 0)
|
||||
return COUNT::static_size;
|
||||
else
|
||||
return min_size + calculate_offset_array_size (offSize, count) + dataSize;
|
||||
return min_size + calculate_offset_array_size (offSize_, count) + dataSize;
|
||||
}
|
||||
|
||||
bool serialize (hb_serialize_context_t *c, const CFFIndex &src)
|
||||
@ -132,7 +132,7 @@ struct CFFIndex
|
||||
if (unlikely (!c->extend_min (*this))) return_trace (false);
|
||||
this->count = byteArray.length;
|
||||
this->offSize = offSize_;
|
||||
if (!unlikely (c->allocate_size<HBUINT8> (offSize_ * (byteArray.length + 1))))
|
||||
if (unlikely (!c->allocate_size<HBUINT8> (offSize_ * (byteArray.length + 1))))
|
||||
return_trace (false);
|
||||
|
||||
/* serialize indices */
|
||||
@ -167,7 +167,7 @@ struct CFFIndex
|
||||
byteArray.resize (buffArray.length);
|
||||
for (unsigned int i = 0; i < byteArray.length; i++)
|
||||
{
|
||||
byteArray[i] = byte_str_t (buffArray[i].arrayZ (), buffArray[i].length);
|
||||
byteArray[i] = byte_str_t (buffArray[i].arrayZ, buffArray[i].length);
|
||||
}
|
||||
bool result = this->serialize (c, offSize_, byteArray);
|
||||
byteArray.fini ();
|
||||
@ -277,7 +277,7 @@ struct CFFIndexOf : CFFIndex<COUNT>
|
||||
if (unlikely (!c->extend_min (*this))) return_trace (false);
|
||||
this->count = dataArrayLen;
|
||||
this->offSize = offSize_;
|
||||
if (!unlikely (c->allocate_size<HBUINT8> (offSize_ * (dataArrayLen + 1))))
|
||||
if (unlikely (!c->allocate_size<HBUINT8> (offSize_ * (dataArrayLen + 1))))
|
||||
return_trace (false);
|
||||
|
||||
/* serialize indices */
|
||||
@ -428,7 +428,7 @@ struct FDArray : CFFIndexOf<COUNT, FontDict>
|
||||
if (unlikely (!c->extend_min (*this))) return_trace (false);
|
||||
this->count = fontDicts.length;
|
||||
this->offSize = offSize_;
|
||||
if (!unlikely (c->allocate_size<HBUINT8> (offSize_ * (fontDicts.length + 1))))
|
||||
if (unlikely (!c->allocate_size<HBUINT8> (offSize_ * (fontDicts.length + 1))))
|
||||
return_trace (false);
|
||||
|
||||
/* serialize font dict offsets */
|
||||
@ -465,7 +465,7 @@ struct FDArray : CFFIndexOf<COUNT, FontDict>
|
||||
if (unlikely (!c->extend_min (*this))) return_trace (false);
|
||||
this->count = fdCount;
|
||||
this->offSize = offSize_;
|
||||
if (!unlikely (c->allocate_size<HBUINT8> (offSize_ * (fdCount + 1))))
|
||||
if (unlikely (!c->allocate_size<HBUINT8> (offSize_ * (fdCount + 1))))
|
||||
return_trace (false);
|
||||
|
||||
/* serialize font dict offsets */
|
||||
@ -604,9 +604,9 @@ struct FDSelect {
|
||||
TRACE_SANITIZE (this);
|
||||
|
||||
return_trace (likely (c->check_struct (this) && (format == 0 || format == 3) &&
|
||||
(format == 0)?
|
||||
((format == 0)?
|
||||
u.format0.sanitize (c, fdcount):
|
||||
u.format3.sanitize (c, fdcount)));
|
||||
u.format3.sanitize (c, fdcount))));
|
||||
}
|
||||
|
||||
bool serialize (hb_serialize_context_t *c, const FDSelect &src, unsigned int num_glyphs)
|
||||
|
@ -27,6 +27,8 @@
|
||||
#include "hb-ot-cff1-table.hh"
|
||||
#include "hb-cff1-interp-cs.hh"
|
||||
|
||||
#ifndef HB_NO_CFF
|
||||
|
||||
using namespace CFF;
|
||||
|
||||
/* SID to code */
|
||||
@ -305,6 +307,11 @@ bool _get_bounds (const OT::cff1::accelerator_t *cff, hb_codepoint_t glyph, boun
|
||||
|
||||
bool OT::cff1::accelerator_t::get_extents (hb_codepoint_t glyph, hb_glyph_extents_t *extents) const
|
||||
{
|
||||
#ifdef HB_NO_OT_FONT_CFF
|
||||
/* XXX Remove check when this code moves to .hh file. */
|
||||
return true;
|
||||
#endif
|
||||
|
||||
bounds_t bounds;
|
||||
|
||||
if (!_get_bounds (this, glyph, bounds))
|
||||
@ -383,3 +390,5 @@ bool OT::cff1::accelerator_t::get_seac_components (hb_codepoint_t glyph, hb_code
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -576,7 +576,7 @@ struct CFF1StringIndex : CFF1Index
|
||||
TRACE_SERIALIZE (this);
|
||||
if (unlikely ((strings.count == 0) || (sidmap.get_count () == 0)))
|
||||
{
|
||||
if (!unlikely (c->extend_min (this->count)))
|
||||
if (unlikely (!c->extend_min (this->count)))
|
||||
return_trace (false);
|
||||
count = 0;
|
||||
return_trace (true);
|
||||
@ -599,9 +599,9 @@ struct CFF1StringIndex : CFF1Index
|
||||
}
|
||||
|
||||
/* in parallel to above */
|
||||
unsigned int calculate_serialized_size (unsigned int &offSize /*OUT*/, const hb_bimap_t &sidmap) const
|
||||
unsigned int calculate_serialized_size (unsigned int &offSize_ /*OUT*/, const hb_bimap_t &sidmap) const
|
||||
{
|
||||
offSize = 0;
|
||||
offSize_ = 0;
|
||||
if ((count == 0) || (sidmap.get_count () == 0))
|
||||
return count.static_size;
|
||||
|
||||
@ -610,8 +610,8 @@ struct CFF1StringIndex : CFF1Index
|
||||
if (sidmap[i] != HB_MAP_VALUE_INVALID)
|
||||
dataSize += length_at (i);
|
||||
|
||||
offSize = calcOffSize(dataSize);
|
||||
return CFF1Index::calculate_serialized_size (offSize, sidmap.get_count (), dataSize);
|
||||
offSize_ = calcOffSize(dataSize);
|
||||
return CFF1Index::calculate_serialized_size (offSize_, sidmap.get_count (), dataSize);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -27,6 +27,8 @@
|
||||
#include "hb-ot-cff2-table.hh"
|
||||
#include "hb-cff2-interp-cs.hh"
|
||||
|
||||
#ifndef HB_NO_OT_FONT_CFF
|
||||
|
||||
using namespace CFF;
|
||||
|
||||
struct extents_param_t
|
||||
@ -99,6 +101,11 @@ bool OT::cff2::accelerator_t::get_extents (hb_font_t *font,
|
||||
hb_codepoint_t glyph,
|
||||
hb_glyph_extents_t *extents) const
|
||||
{
|
||||
#ifdef HB_NO_OT_FONT_CFF
|
||||
/* XXX Remove check when this code moves to .hh file. */
|
||||
return true;
|
||||
#endif
|
||||
|
||||
if (unlikely (!is_valid () || (glyph >= num_glyphs))) return false;
|
||||
|
||||
unsigned int num_coords;
|
||||
@ -134,3 +141,5 @@ bool OT::cff2::accelerator_t::get_extents (hb_font_t *font,
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -56,11 +56,11 @@ struct CFF2FDSelect
|
||||
TRACE_SANITIZE (this);
|
||||
|
||||
return_trace (likely (c->check_struct (this) && (format == 0 || format == 3 || format == 4) &&
|
||||
(format == 0)?
|
||||
((format == 0)?
|
||||
u.format0.sanitize (c, fdcount):
|
||||
((format == 3)?
|
||||
u.format3.sanitize (c, fdcount):
|
||||
u.format4.sanitize (c, fdcount))));
|
||||
u.format4.sanitize (c, fdcount)))));
|
||||
}
|
||||
|
||||
bool serialize (hb_serialize_context_t *c, const CFF2FDSelect &src, unsigned int num_glyphs)
|
||||
|
@ -93,7 +93,7 @@ struct CmapSubtableFormat4
|
||||
this->length = get_sub_table_size (segments);
|
||||
|
||||
this->segCountX2 = segments.length * 2;
|
||||
this->entrySelector = MAX (1u, hb_bit_storage (segments.length)) - 1;
|
||||
this->entrySelector = hb_max (1u, hb_bit_storage (segments.length)) - 1;
|
||||
this->searchRange = 2 * (1u << this->entrySelector);
|
||||
this->rangeShift = segments.length * 2 > this->searchRange
|
||||
? 2 * segments.length - this->searchRange
|
||||
@ -142,7 +142,7 @@ struct CmapSubtableFormat4
|
||||
for (unsigned int j = 0; j < num_codepoints; j++)
|
||||
{
|
||||
hb_codepoint_t cp = segments[i].start_code + j;
|
||||
hb_codepoint_t new_gid;
|
||||
hb_codepoint_t new_gid = 0;
|
||||
if (unlikely (!plan->new_gid_for_codepoint (cp, &new_gid)))
|
||||
return_trace (false);
|
||||
glyph_id_array[j] = new_gid;
|
||||
@ -183,7 +183,7 @@ struct CmapSubtableFormat4
|
||||
|
||||
hb_codepoint_t cp = HB_SET_VALUE_INVALID;
|
||||
while (plan->unicodes->next (&cp)) {
|
||||
hb_codepoint_t new_gid;
|
||||
hb_codepoint_t new_gid = 0;
|
||||
if (unlikely (!plan->new_gid_for_codepoint (cp, &new_gid)))
|
||||
{
|
||||
DEBUG_MSG(SUBSET, nullptr, "Unable to find new gid for %04x", cp);
|
||||
@ -348,7 +348,7 @@ struct CmapSubtableFormat4
|
||||
/* Some broken fonts have too long of a "length" value.
|
||||
* If that is the case, just change the value to truncate
|
||||
* the subtable at the end of the blob. */
|
||||
uint16_t new_length = (uint16_t) MIN ((uintptr_t) 65535,
|
||||
uint16_t new_length = (uint16_t) hb_min ((uintptr_t) 65535,
|
||||
(uintptr_t) (c->end -
|
||||
(char *) this));
|
||||
if (!c->try_set (&length, new_length))
|
||||
@ -478,7 +478,7 @@ struct CmapSubtableLongSegmented
|
||||
{
|
||||
for (unsigned int i = 0; i < this->groups.len; i++) {
|
||||
out->add_range (this->groups[i].startCharCode,
|
||||
MIN ((hb_codepoint_t) this->groups[i].endCharCode,
|
||||
hb_min ((hb_codepoint_t) this->groups[i].endCharCode,
|
||||
(hb_codepoint_t) HB_UNICODE_MAX));
|
||||
}
|
||||
}
|
||||
@ -518,31 +518,31 @@ struct CmapSubtableFormat12 : CmapSubtableLongSegmented<CmapSubtableFormat12>
|
||||
|
||||
|
||||
bool serialize (hb_serialize_context_t *c,
|
||||
const hb_sorted_vector_t<CmapSubtableLongGroup> &groups)
|
||||
const hb_sorted_vector_t<CmapSubtableLongGroup> &groups_data)
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
if (unlikely (!c->extend_min (*this))) return_trace (false);
|
||||
|
||||
this->format = 12;
|
||||
this->reserved = 0;
|
||||
this->length = get_sub_table_size (groups);
|
||||
this->length = get_sub_table_size (groups_data);
|
||||
|
||||
return_trace (CmapSubtableLongSegmented<CmapSubtableFormat12>::serialize (c, groups));
|
||||
return_trace (CmapSubtableLongSegmented<CmapSubtableFormat12>::serialize (c, groups_data));
|
||||
}
|
||||
|
||||
static size_t get_sub_table_size (const hb_sorted_vector_t<CmapSubtableLongGroup> &groups)
|
||||
static size_t get_sub_table_size (const hb_sorted_vector_t<CmapSubtableLongGroup> &groups_data)
|
||||
{
|
||||
return 16 + 12 * groups.length;
|
||||
return 16 + 12 * groups_data.length;
|
||||
}
|
||||
|
||||
static bool create_sub_table_plan (const hb_subset_plan_t *plan,
|
||||
hb_sorted_vector_t<CmapSubtableLongGroup> *groups)
|
||||
hb_sorted_vector_t<CmapSubtableLongGroup> *groups_out)
|
||||
{
|
||||
CmapSubtableLongGroup *group = nullptr;
|
||||
|
||||
hb_codepoint_t cp = HB_SET_VALUE_INVALID;
|
||||
while (plan->unicodes->next (&cp)) {
|
||||
hb_codepoint_t new_gid;
|
||||
hb_codepoint_t new_gid = 0;
|
||||
if (unlikely (!plan->new_gid_for_codepoint (cp, &new_gid)))
|
||||
{
|
||||
DEBUG_MSG(SUBSET, nullptr, "Unable to find new gid for %04x", cp);
|
||||
@ -551,7 +551,7 @@ struct CmapSubtableFormat12 : CmapSubtableLongSegmented<CmapSubtableFormat12>
|
||||
|
||||
if (!group || !_is_gid_consecutive (group, cp, new_gid))
|
||||
{
|
||||
group = groups->push ();
|
||||
group = groups_out->push ();
|
||||
group->startCharCode = cp;
|
||||
group->endCharCode = cp;
|
||||
group->glyphID = new_gid;
|
||||
@ -560,8 +560,8 @@ struct CmapSubtableFormat12 : CmapSubtableLongSegmented<CmapSubtableFormat12>
|
||||
}
|
||||
|
||||
DEBUG_MSG(SUBSET, nullptr, "cmap");
|
||||
for (unsigned int i = 0; i < groups->length; i++) {
|
||||
CmapSubtableLongGroup& group = (*groups)[i];
|
||||
for (unsigned int i = 0; i < groups_out->length; i++) {
|
||||
CmapSubtableLongGroup& group = (*groups_out)[i];
|
||||
DEBUG_MSG(SUBSET, nullptr, " %d: U+%04X-U+%04X, gid %d-%d", i, (uint32_t) group.startCharCode, (uint32_t) group.endCharCode, (uint32_t) group.glyphID, (uint32_t) group.glyphID + ((uint32_t) group.endCharCode - (uint32_t) group.startCharCode));
|
||||
}
|
||||
|
||||
@ -623,7 +623,7 @@ struct DefaultUVS : SortedArrayOf<UnicodeValueRange, HBUINT32>
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
hb_codepoint_t first = arrayZ[i].startUnicodeValue;
|
||||
hb_codepoint_t last = MIN ((hb_codepoint_t) (first + arrayZ[i].additionalCount),
|
||||
hb_codepoint_t last = hb_min ((hb_codepoint_t) (first + arrayZ[i].additionalCount),
|
||||
(hb_codepoint_t) HB_UNICODE_MAX);
|
||||
out->add_range (first, last);
|
||||
}
|
||||
@ -863,6 +863,7 @@ struct cmap
|
||||
if (unlikely (!CmapSubtableFormat4::create_sub_table_plan (plan, &cmap_plan->format4_segments)))
|
||||
return false;
|
||||
|
||||
if (!find_subtable (12)) return true;
|
||||
return CmapSubtableFormat12::create_sub_table_plan (plan, &cmap_plan->format12_groups);
|
||||
}
|
||||
|
||||
@ -881,8 +882,7 @@ struct cmap
|
||||
|
||||
table->version = 0;
|
||||
|
||||
if (unlikely (!table->encodingRecord.serialize (&c, /* numTables */ 3)))
|
||||
return false;
|
||||
if (unlikely (!table->encodingRecord.serialize (&c, /* numTables */ cmap_subset_plan.format12_groups ? 3 : 2))) return false;
|
||||
|
||||
// TODO(grieger): Convert the below to a for loop
|
||||
|
||||
@ -897,9 +897,12 @@ struct cmap
|
||||
format4_plat3_rec.encodingID = 1; // Unicode BMP
|
||||
|
||||
// Format 12 Encoding Record
|
||||
EncodingRecord &format12_rec = table->encodingRecord[2];
|
||||
format12_rec.platformID = 3; // Windows
|
||||
format12_rec.encodingID = 10; // Unicode UCS-4
|
||||
if (cmap_subset_plan.format12_groups)
|
||||
{
|
||||
EncodingRecord &format12_rec = table->encodingRecord[2];
|
||||
format12_rec.platformID = 3; // Windows
|
||||
format12_rec.encodingID = 10; // Unicode UCS-4
|
||||
}
|
||||
|
||||
// Write out format 4 sub table
|
||||
{
|
||||
@ -913,7 +916,9 @@ struct cmap
|
||||
}
|
||||
|
||||
// Write out format 12 sub table.
|
||||
if (cmap_subset_plan.format12_groups)
|
||||
{
|
||||
EncodingRecord &format12_rec = table->encodingRecord[2];
|
||||
CmapSubtable &subtable = format12_rec.subtable.serialize (&c, table);
|
||||
subtable.u.format = 12;
|
||||
|
||||
@ -1154,6 +1159,18 @@ struct cmap
|
||||
return &(this+result.subtable);
|
||||
}
|
||||
|
||||
bool find_subtable (unsigned format) const
|
||||
{
|
||||
auto it =
|
||||
+ hb_iter (encodingRecord)
|
||||
| hb_map (&EncodingRecord::subtable)
|
||||
| hb_map (hb_add (this))
|
||||
| hb_filter ([&] (const CmapSubtable& _) { return _.u.format == format; })
|
||||
;
|
||||
|
||||
return it.len ();
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
|
@ -144,7 +144,7 @@ struct IndexSubtableFormat1Or3
|
||||
}
|
||||
|
||||
IndexSubtableHeader header;
|
||||
UnsizedArrayOf<Offset<OffsetType> >
|
||||
UnsizedArrayOf<Offset<OffsetType>>
|
||||
offsetArrayZ;
|
||||
public:
|
||||
DEFINE_SIZE_ARRAY(8, offsetArrayZ);
|
||||
@ -349,15 +349,15 @@ struct CBLC
|
||||
if (unlikely (!count))
|
||||
return Null(BitmapSizeTable);
|
||||
|
||||
unsigned int requested_ppem = MAX (font->x_ppem, font->y_ppem);
|
||||
unsigned int requested_ppem = hb_max (font->x_ppem, font->y_ppem);
|
||||
if (!requested_ppem)
|
||||
requested_ppem = 1<<30; /* Choose largest strike. */
|
||||
unsigned int best_i = 0;
|
||||
unsigned int best_ppem = MAX (sizeTables[0].ppemX, sizeTables[0].ppemY);
|
||||
unsigned int best_ppem = hb_max (sizeTables[0].ppemX, sizeTables[0].ppemY);
|
||||
|
||||
for (unsigned int i = 1; i < count; i++)
|
||||
{
|
||||
unsigned int ppem = MAX (sizeTables[i].ppemX, sizeTables[i].ppemY);
|
||||
unsigned int ppem = hb_max (sizeTables[i].ppemX, sizeTables[i].ppemY);
|
||||
if ((requested_ppem <= ppem && ppem < best_ppem) ||
|
||||
(requested_ppem > best_ppem && ppem > best_ppem))
|
||||
{
|
||||
@ -442,12 +442,12 @@ struct CBDT
|
||||
}
|
||||
|
||||
/* Convert to font units. */
|
||||
double x_scale = upem / (double) strike.ppemX;
|
||||
double y_scale = upem / (double) strike.ppemY;
|
||||
extents->x_bearing = round (extents->x_bearing * x_scale);
|
||||
extents->y_bearing = round (extents->y_bearing * y_scale);
|
||||
extents->width = round (extents->width * x_scale);
|
||||
extents->height = round (extents->height * y_scale);
|
||||
float x_scale = upem / (float) strike.ppemX;
|
||||
float y_scale = upem / (float) strike.ppemY;
|
||||
extents->x_bearing = roundf (extents->x_bearing * x_scale);
|
||||
extents->y_bearing = roundf (extents->y_bearing * y_scale);
|
||||
extents->width = roundf (extents->width * x_scale);
|
||||
extents->height = roundf (extents->height * y_scale);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -125,9 +125,9 @@ struct COLR
|
||||
protected:
|
||||
HBUINT16 version; /* Table version number (starts at 0). */
|
||||
HBUINT16 numBaseGlyphs; /* Number of Base Glyph Records. */
|
||||
LNNOffsetTo<SortedUnsizedArrayOf<BaseGlyphRecord> >
|
||||
LNNOffsetTo<SortedUnsizedArrayOf<BaseGlyphRecord>>
|
||||
baseGlyphsZ; /* Offset to Base Glyph records. */
|
||||
LNNOffsetTo<UnsizedArrayOf<LayerRecord> >
|
||||
LNNOffsetTo<UnsizedArrayOf<LayerRecord>>
|
||||
layersZ; /* Offset to Layer Records. */
|
||||
HBUINT16 numLayers; /* Number of Layer Records. */
|
||||
public:
|
||||
|
@ -87,15 +87,15 @@ struct CPALV1Tail
|
||||
}
|
||||
|
||||
protected:
|
||||
LNNOffsetTo<UnsizedArrayOf<HBUINT32> >
|
||||
LNNOffsetTo<UnsizedArrayOf<HBUINT32>>
|
||||
paletteFlagsZ; /* Offset from the beginning of CPAL table to
|
||||
* the Palette Type Array. Set to 0 if no array
|
||||
* is provided. */
|
||||
LNNOffsetTo<UnsizedArrayOf<NameID> >
|
||||
LNNOffsetTo<UnsizedArrayOf<NameID>>
|
||||
paletteLabelsZ; /* Offset from the beginning of CPAL table to
|
||||
* the palette labels array. Set to 0 if no
|
||||
* array is provided. */
|
||||
LNNOffsetTo<UnsizedArrayOf<NameID> >
|
||||
LNNOffsetTo<UnsizedArrayOf<NameID>>
|
||||
colorLabelsZ; /* Offset from the beginning of CPAL table to
|
||||
* the color labels array. Set to 0
|
||||
* if no array is provided. */
|
||||
@ -144,7 +144,7 @@ struct CPAL
|
||||
{
|
||||
hb_array_t<const BGRAColor> segment_colors = palette_colors.sub_array (start_offset, *color_count);
|
||||
/* Always return numColors colors per palette even if it has out-of-bounds start index. */
|
||||
unsigned int count = MIN<unsigned int> (MAX<int> (numColors - start_offset, 0), *color_count);
|
||||
unsigned int count = hb_min ((unsigned) hb_max ((int) (numColors - start_offset), 0), *color_count);
|
||||
*color_count = count;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
colors[i] = segment_colors[i]; /* Bound-checked read. */
|
||||
@ -176,7 +176,7 @@ struct CPAL
|
||||
HBUINT16 numPalettes; /* Number of palettes in the table. */
|
||||
HBUINT16 numColorRecords; /* Total number of color records, combined for
|
||||
* all palettes. */
|
||||
LNNOffsetTo<UnsizedArrayOf<BGRAColor> >
|
||||
LNNOffsetTo<UnsizedArrayOf<BGRAColor>>
|
||||
colorRecordsZ; /* Offset from the beginning of CPAL table to
|
||||
* the first ColorRecord. */
|
||||
UnsizedArrayOf<HBUINT16>
|
||||
|
@ -121,7 +121,7 @@ struct SBIXStrike
|
||||
HBUINT16 resolution; /* The device pixel density (in PPI) for which this
|
||||
* strike was designed. (E.g., 96 PPI, 192 PPI.) */
|
||||
protected:
|
||||
UnsizedArrayOf<LOffsetTo<SBIXGlyph> >
|
||||
UnsizedArrayOf<LOffsetTo<SBIXGlyph>>
|
||||
imageOffsetsZ; /* Offset from the beginning of the strike data header
|
||||
* to bitmap data for an individual glyph ID. */
|
||||
public:
|
||||
@ -175,7 +175,7 @@ struct sbix
|
||||
if (unlikely (!count))
|
||||
return Null(SBIXStrike);
|
||||
|
||||
unsigned int requested_ppem = MAX (font->x_ppem, font->y_ppem);
|
||||
unsigned int requested_ppem = hb_max (font->x_ppem, font->y_ppem);
|
||||
if (!requested_ppem)
|
||||
requested_ppem = 1<<30; /* Choose largest strike. */
|
||||
/* TODO Add DPI sensitivity as well? */
|
||||
@ -242,11 +242,11 @@ struct sbix
|
||||
/* Convert to font units. */
|
||||
if (strike_ppem)
|
||||
{
|
||||
double scale = font->face->get_upem () / (double) strike_ppem;
|
||||
extents->x_bearing = round (extents->x_bearing * scale);
|
||||
extents->y_bearing = round (extents->y_bearing * scale);
|
||||
extents->width = round (extents->width * scale);
|
||||
extents->height = round (extents->height * scale);
|
||||
float scale = font->face->get_upem () / (float) strike_ppem;
|
||||
extents->x_bearing = roundf (extents->x_bearing * scale);
|
||||
extents->y_bearing = roundf (extents->y_bearing * scale);
|
||||
extents->width = roundf (extents->width * scale);
|
||||
extents->height = roundf (extents->height * scale);
|
||||
}
|
||||
|
||||
hb_blob_destroy (blob);
|
||||
|
@ -62,7 +62,7 @@ struct SVGDocumentIndexEntry
|
||||
* this index entry. */
|
||||
HBUINT16 endGlyphID; /* The last glyph ID in the range described by
|
||||
* this index entry. Must be >= startGlyphID. */
|
||||
LNNOffsetTo<UnsizedArrayOf<HBUINT8> >
|
||||
LNNOffsetTo<UnsizedArrayOf<HBUINT8>>
|
||||
svgDoc; /* Offset from the beginning of the SVG Document Index
|
||||
* to an SVG document. Must be non-zero. */
|
||||
HBUINT32 svgDocLength; /* Length of the SVG document.
|
||||
@ -107,7 +107,7 @@ struct SVG
|
||||
|
||||
protected:
|
||||
HBUINT16 version; /* Table version (starting at 0). */
|
||||
LOffsetTo<SortedArrayOf<SVGDocumentIndexEntry> >
|
||||
LOffsetTo<SortedArrayOf<SVGDocumentIndexEntry>>
|
||||
svgDocEntries; /* Offset (relative to the start of the SVG table) to the
|
||||
* SVG Documents Index. Must be non-zero. */
|
||||
/* Array of SVG Document Index Entries. */
|
||||
|
@ -47,6 +47,8 @@
|
||||
* @include: hb-ot.h
|
||||
*
|
||||
* Functions for fetching color-font information from OpenType font faces.
|
||||
*
|
||||
* HarfBuzz supports `COLR`/`CPAL`, `sbix`, `CBDT`, and `SVG` color fonts.
|
||||
**/
|
||||
|
||||
|
||||
@ -57,42 +59,54 @@
|
||||
|
||||
/**
|
||||
* hb_ot_color_has_palettes:
|
||||
* @face: a font face.
|
||||
* @face: #hb_face_t to work upon
|
||||
*
|
||||
* Returns: whether CPAL table is available.
|
||||
* Tests whether a face includes a `CPAL` color-palette table.
|
||||
*
|
||||
* Return value: true if data found, false otherwise
|
||||
*
|
||||
* Since: 2.1.0
|
||||
*/
|
||||
hb_bool_t
|
||||
hb_ot_color_has_palettes (hb_face_t *face)
|
||||
{
|
||||
#ifdef HB_NO_COLOR
|
||||
return false;
|
||||
#endif
|
||||
return face->table.CPAL->has_data ();
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_ot_color_palette_get_count:
|
||||
* @face: a font face.
|
||||
* @face: #hb_face_t to work upon
|
||||
*
|
||||
* Returns: the number of color palettes in @face, or zero if @face has
|
||||
* no colors.
|
||||
* Fetches the number of color palettes in a face.
|
||||
*
|
||||
* Return value: the number of palettes found
|
||||
*
|
||||
* Since: 2.1.0
|
||||
*/
|
||||
unsigned int
|
||||
hb_ot_color_palette_get_count (hb_face_t *face)
|
||||
{
|
||||
#ifdef HB_NO_COLOR
|
||||
return 0;
|
||||
#endif
|
||||
return face->table.CPAL->get_palette_count ();
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_ot_color_palette_get_name_id:
|
||||
* @face: a font face.
|
||||
* @palette_index: the index of the color palette whose name is being requested.
|
||||
* @face: #hb_face_t to work upon
|
||||
* @palette_index: The index of the color palette
|
||||
*
|
||||
* Retrieves the name id of a color palette. For example, a color font can
|
||||
* have themed palettes like "Spring", "Summer", "Fall", and "Winter".
|
||||
* Fetches the `name` table Name ID that provides display names for
|
||||
* a `CPAL` color palette.
|
||||
*
|
||||
* Returns: an identifier within @face's `name` table.
|
||||
* Palette display names can be generic (e.g., "Default") or provide
|
||||
* specific, themed names (e.g., "Spring", "Summer", "Fall", and "Winter").
|
||||
*
|
||||
* Return value: the Named ID found for the palette.
|
||||
* If the requested palette has no name the result is #HB_OT_NAME_ID_INVALID.
|
||||
*
|
||||
* Since: 2.1.0
|
||||
@ -101,15 +115,24 @@ hb_ot_name_id_t
|
||||
hb_ot_color_palette_get_name_id (hb_face_t *face,
|
||||
unsigned int palette_index)
|
||||
{
|
||||
#ifdef HB_NO_COLOR
|
||||
return HB_OT_NAME_ID_INVALID;
|
||||
#endif
|
||||
return face->table.CPAL->get_palette_name_id (palette_index);
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_ot_color_palette_color_get_name_id:
|
||||
* @face: a font face.
|
||||
* @color_index: palette entry index.
|
||||
* @face: #hb_face_t to work upon
|
||||
* @color_index: The index of the color
|
||||
*
|
||||
* Returns: Name ID associated with a palette entry, e.g. eye color
|
||||
* Fetches the `name` table Name ID that provides display names for
|
||||
* the specificed color in a face's `CPAL` color palette.
|
||||
*
|
||||
* Display names can be generic (e.g., "Background") or specific
|
||||
* (e.g., "Eye color").
|
||||
*
|
||||
* Return value: the Name ID found for the color.
|
||||
*
|
||||
* Since: 2.1.0
|
||||
*/
|
||||
@ -117,15 +140,20 @@ hb_ot_name_id_t
|
||||
hb_ot_color_palette_color_get_name_id (hb_face_t *face,
|
||||
unsigned int color_index)
|
||||
{
|
||||
#ifdef HB_NO_COLOR
|
||||
return HB_OT_NAME_ID_INVALID;
|
||||
#endif
|
||||
return face->table.CPAL->get_color_name_id (color_index);
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_ot_color_palette_get_flags:
|
||||
* @face: a font face
|
||||
* @palette_index: the index of the color palette whose flags are being requested
|
||||
* @face: #hb_face_t to work upon
|
||||
* @palette_index: The index of the color palette
|
||||
*
|
||||
* Returns: the flags for the requested color palette.
|
||||
* Fetches the flags defined for a color palette.
|
||||
*
|
||||
* Return value: the #hb_ot_color_palette_flags_t of the requested color palette
|
||||
*
|
||||
* Since: 2.1.0
|
||||
*/
|
||||
@ -133,30 +161,30 @@ hb_ot_color_palette_flags_t
|
||||
hb_ot_color_palette_get_flags (hb_face_t *face,
|
||||
unsigned int palette_index)
|
||||
{
|
||||
#ifdef HB_NO_COLOR
|
||||
return HB_OT_COLOR_PALETTE_FLAG_DEFAULT;
|
||||
#endif
|
||||
return face->table.CPAL->get_palette_flags (palette_index);
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_ot_color_palette_get_colors:
|
||||
* @face: a font face.
|
||||
* @palette_index:the index of the color palette whose colors
|
||||
* are being requested.
|
||||
* @start_offset: the index of the first color being requested.
|
||||
* @color_count: (inout) (optional): on input, how many colors
|
||||
* can be maximally stored into the @colors array;
|
||||
* on output, how many colors were actually stored.
|
||||
* @colors: (array length=color_count) (out) (optional):
|
||||
* an array of #hb_color_t records. After calling
|
||||
* this function, @colors will be filled with
|
||||
* the palette colors. If @colors is NULL, the function
|
||||
* will just return the number of total colors
|
||||
* without storing any actual colors; this can be used
|
||||
* for allocating a buffer of suitable size before calling
|
||||
* hb_ot_color_palette_get_colors() a second time.
|
||||
* @face: #hb_face_t to work upon
|
||||
* @palette_index: the index of the color palette to query
|
||||
* @start_offset: offset of the first color to retrieve
|
||||
* @color_count: (inout) (optional): Input = the maximum number of colors to return;
|
||||
* Output = the actual number of colors returned (may be zero)
|
||||
* @colors: (out) (array length=color_count) (nullable): The array of #hb_color_t records found
|
||||
*
|
||||
* Retrieves the colors in a color palette.
|
||||
* Fetches a list of the colors in a color palette.
|
||||
*
|
||||
* Returns: the total number of colors in the palette.
|
||||
* After calling this function, @colors will be filled with the palette
|
||||
* colors. If @colors is NULL, the function will just return the number
|
||||
* of total colors without storing any actual colors; this can be used
|
||||
* for allocating a buffer of suitable size before calling
|
||||
* hb_ot_color_palette_get_colors() a second time.
|
||||
*
|
||||
* Return value: the total number of colors in the palette
|
||||
*
|
||||
* Since: 2.1.0
|
||||
*/
|
||||
@ -167,6 +195,11 @@ hb_ot_color_palette_get_colors (hb_face_t *face,
|
||||
unsigned int *colors_count /* IN/OUT. May be NULL. */,
|
||||
hb_color_t *colors /* OUT. May be NULL. */)
|
||||
{
|
||||
#ifdef HB_NO_COLOR
|
||||
if (colors_count)
|
||||
*colors_count = 0;
|
||||
return 0;
|
||||
#endif
|
||||
return face->table.CPAL->get_palette_colors (palette_index, start_offset, colors_count, colors);
|
||||
}
|
||||
|
||||
@ -177,28 +210,36 @@ hb_ot_color_palette_get_colors (hb_face_t *face,
|
||||
|
||||
/**
|
||||
* hb_ot_color_has_layers:
|
||||
* @face: a font face.
|
||||
* @face: #hb_face_t to work upon
|
||||
*
|
||||
* Returns: whether COLR table is available.
|
||||
* Tests whether a face includes any `COLR` color layers.
|
||||
*
|
||||
* Return value: true if data found, false otherwise
|
||||
*
|
||||
* Since: 2.1.0
|
||||
*/
|
||||
hb_bool_t
|
||||
hb_ot_color_has_layers (hb_face_t *face)
|
||||
{
|
||||
#ifdef HB_NO_COLOR
|
||||
return false;
|
||||
#endif
|
||||
return face->table.COLR->has_data ();
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_ot_color_glyph_get_layers:
|
||||
* @face: a font face.
|
||||
* @glyph: a layered color glyph id.
|
||||
* @start_offset: starting offset of layers.
|
||||
* @count: (inout) (optional): gets number of layers available to be written on buffer
|
||||
* and returns number of written layers.
|
||||
* @layers: (array length=count) (out) (optional): layers buffer to buffer.
|
||||
* @face: #hb_face_t to work upon
|
||||
* @glyph: The glyph index to query
|
||||
* @start_offset: offset of the first layer to retrieve
|
||||
* @layer_count: (inout) (optional): Input = the maximum number of layers to return;
|
||||
* Output = the actual number of layers returned (may be zero)
|
||||
* @layers: (out) (array length=layer_count) (nullable): The array of layers found
|
||||
*
|
||||
* Returns: Total number of layers a layered color glyph have.
|
||||
* Fetches a list of all color layers for the specified glyph index in the specified
|
||||
* face. The list returned will begin at the offset provided.
|
||||
*
|
||||
* Return value: Total number of layers available for the glyph index queried
|
||||
*
|
||||
* Since: 2.1.0
|
||||
*/
|
||||
@ -206,10 +247,15 @@ unsigned int
|
||||
hb_ot_color_glyph_get_layers (hb_face_t *face,
|
||||
hb_codepoint_t glyph,
|
||||
unsigned int start_offset,
|
||||
unsigned int *count, /* IN/OUT. May be NULL. */
|
||||
unsigned int *layer_count, /* IN/OUT. May be NULL. */
|
||||
hb_ot_color_layer_t *layers /* OUT. May be NULL. */)
|
||||
{
|
||||
return face->table.COLR->get_glyph_layers (glyph, start_offset, count, layers);
|
||||
#ifdef HB_NO_COLOR
|
||||
if (layer_count)
|
||||
*layer_count = 0;
|
||||
return 0;
|
||||
#endif
|
||||
return face->table.COLR->get_glyph_layers (glyph, start_offset, layer_count, layers);
|
||||
}
|
||||
|
||||
|
||||
@ -219,34 +265,40 @@ hb_ot_color_glyph_get_layers (hb_face_t *face,
|
||||
|
||||
/**
|
||||
* hb_ot_color_has_svg:
|
||||
* @face: a font face.
|
||||
* @face: #hb_face_t to work upon.
|
||||
*
|
||||
* Check whether @face has SVG glyph images.
|
||||
* Tests whether a face includes any `SVG` glyph images.
|
||||
*
|
||||
* Returns true if available, false otherwise.
|
||||
* Return value: true if data found, false otherwise.
|
||||
*
|
||||
* Since: 2.1.0
|
||||
*/
|
||||
hb_bool_t
|
||||
hb_ot_color_has_svg (hb_face_t *face)
|
||||
{
|
||||
#ifdef HB_NO_COLOR
|
||||
return false;
|
||||
#endif
|
||||
return face->table.SVG->has_data ();
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_ot_color_glyph_reference_svg:
|
||||
* @face: a font face.
|
||||
* @glyph: a svg glyph index.
|
||||
* @face: #hb_face_t to work upon
|
||||
* @glyph: a svg glyph index
|
||||
*
|
||||
* Get SVG document for a glyph. The blob may be either plain text or gzip-encoded.
|
||||
* Fetches the SVG document for a glyph. The blob may be either plain text or gzip-encoded.
|
||||
*
|
||||
* Returns: (transfer full): respective svg blob of the glyph, if available.
|
||||
* Return value: (transfer full): An #hb_blob_t containing the SVG document of the glyph, if available
|
||||
*
|
||||
* Since: 2.1.0
|
||||
*/
|
||||
hb_blob_t *
|
||||
hb_ot_color_glyph_reference_svg (hb_face_t *face, hb_codepoint_t glyph)
|
||||
{
|
||||
#ifdef HB_NO_COLOR
|
||||
return hb_blob_get_empty ();
|
||||
#endif
|
||||
return face->table.SVG->reference_blob_for_glyph (glyph);
|
||||
}
|
||||
|
||||
@ -257,36 +309,43 @@ hb_ot_color_glyph_reference_svg (hb_face_t *face, hb_codepoint_t glyph)
|
||||
|
||||
/**
|
||||
* hb_ot_color_has_png:
|
||||
* @face: a font face.
|
||||
* @face: #hb_face_t to work upon
|
||||
*
|
||||
* Check whether @face has PNG glyph images (either CBDT or sbix tables).
|
||||
* Tests whether a face has PNG glyph images (either in `CBDT` or `sbix` tables).
|
||||
*
|
||||
* Returns true if available, false otherwise.
|
||||
* Return value: true if data found, false otherwise
|
||||
*
|
||||
* Since: 2.1.0
|
||||
*/
|
||||
hb_bool_t
|
||||
hb_ot_color_has_png (hb_face_t *face)
|
||||
{
|
||||
#ifdef HB_NO_COLOR
|
||||
return false;
|
||||
#endif
|
||||
return face->table.CBDT->has_data () || face->table.sbix->has_data ();
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_ot_color_glyph_reference_png:
|
||||
* @font: a font object, not face. upem should be set on
|
||||
* that font object if one wants to get optimal png blob, otherwise
|
||||
* return the biggest one
|
||||
* @glyph: a glyph index.
|
||||
* @font: #hb_font_t to work upon
|
||||
* @glyph: a glyph index
|
||||
*
|
||||
* Get PNG image for a glyph.
|
||||
* Fetches the PNG image for a glyph. This function takes a font object, not a face object,
|
||||
* as input. To get an optimally sized PNG blob, the UPEM value must be set on the @font
|
||||
* object. If UPEM is unset, the blob returned will be the largest PNG available.
|
||||
*
|
||||
* Returns: (transfer full): respective PNG blob of the glyph, if available.
|
||||
* Return value: (transfer full): An #hb_blob_t containing the PNG image for the glyph, if available
|
||||
*
|
||||
* Since: 2.1.0
|
||||
*/
|
||||
hb_blob_t *
|
||||
hb_ot_color_glyph_reference_png (hb_font_t *font, hb_codepoint_t glyph)
|
||||
{
|
||||
#ifdef HB_NO_COLOR
|
||||
return hb_blob_get_empty ();
|
||||
#endif
|
||||
|
||||
hb_blob_t *blob = hb_blob_get_empty ();
|
||||
|
||||
if (font->face->table.sbix->has_data ())
|
||||
|
@ -59,11 +59,11 @@ hb_ot_color_palette_color_get_name_id (hb_face_t *face,
|
||||
|
||||
/**
|
||||
* hb_ot_color_palette_flags_t:
|
||||
* @HB_OT_COLOR_PALETTE_FLAG_DEFAULT: default indicating that there is nothing special
|
||||
* @HB_OT_COLOR_PALETTE_FLAG_DEFAULT: Default indicating that there is nothing special
|
||||
* to note about a color palette.
|
||||
* @HB_OT_COLOR_PALETTE_FLAG_USABLE_WITH_LIGHT_BACKGROUND: flag indicating that the color
|
||||
* @HB_OT_COLOR_PALETTE_FLAG_USABLE_WITH_LIGHT_BACKGROUND: Flag indicating that the color
|
||||
* palette is appropriate to use when displaying the font on a light background such as white.
|
||||
* @HB_OT_COLOR_PALETTE_FLAG_USABLE_WITH_DARK_BACKGROUND: flag indicating that the color
|
||||
* @HB_OT_COLOR_PALETTE_FLAG_USABLE_WITH_DARK_BACKGROUND: Flag indicating that the color
|
||||
* palette is appropriate to use when displaying the font on a dark background such as black.
|
||||
*
|
||||
* Since: 2.1.0
|
||||
@ -110,7 +110,7 @@ HB_EXTERN unsigned int
|
||||
hb_ot_color_glyph_get_layers (hb_face_t *face,
|
||||
hb_codepoint_t glyph,
|
||||
unsigned int start_offset,
|
||||
unsigned int *count, /* IN/OUT. May be NULL. */
|
||||
unsigned int *layer_count, /* IN/OUT. May be NULL. */
|
||||
hb_ot_color_layer_t *layers /* OUT. May be NULL. */);
|
||||
|
||||
/*
|
||||
|
@ -40,6 +40,10 @@ HB_BEGIN_DECLS
|
||||
#ifndef HB_DISABLE_DEPRECATED
|
||||
|
||||
|
||||
/* https://github.com/harfbuzz/harfbuzz/issues/1734 */
|
||||
#define HB_MATH_GLYPH_PART_FLAG_EXTENDER HB_OT_MATH_GLYPH_PART_FLAG_EXTENDER
|
||||
|
||||
|
||||
/* Like hb_ot_layout_table_find_script, but takes zero-terminated array of scripts to test */
|
||||
HB_EXTERN HB_DEPRECATED_FOR (hb_ot_layout_table_select_script) hb_bool_t
|
||||
hb_ot_layout_table_choose_script (hb_face_t *face,
|
||||
|
@ -181,19 +181,20 @@ hb_ot_get_glyph_extents (hb_font_t *font,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data;
|
||||
bool ret = ot_face->sbix->get_extents (font, glyph, extents);
|
||||
if (!ret)
|
||||
ret = ot_face->glyf->get_extents (font, glyph, extents);
|
||||
#if !defined(HB_NO_OT_FONT_CFF)
|
||||
if (!ret)
|
||||
ret = ot_face->cff1->get_extents (glyph, extents);
|
||||
if (!ret)
|
||||
ret = ot_face->cff2->get_extents (font, glyph, extents);
|
||||
bool ret = false;
|
||||
|
||||
#if !defined(HB_NO_OT_FONT_BITMAP) && !defined(HB_NO_COLOR)
|
||||
if (!ret) ret = ot_face->sbix->get_extents (font, glyph, extents);
|
||||
#endif
|
||||
#if !defined(HB_NO_OT_FONT_BITMAP)
|
||||
if (!ret)
|
||||
ret = ot_face->CBDT->get_extents (font, glyph, extents);
|
||||
if (!ret) ret = ot_face->glyf->get_extents (glyph, extents);
|
||||
#ifndef HB_NO_OT_FONT_CFF
|
||||
if (!ret) ret = ot_face->cff1->get_extents (glyph, extents);
|
||||
if (!ret) ret = ot_face->cff2->get_extents (font, glyph, extents);
|
||||
#endif
|
||||
#if !defined(HB_NO_OT_FONT_BITMAP) && !defined(HB_NO_COLOR)
|
||||
if (!ret) ret = ot_face->CBDT->get_extents (font, glyph, extents);
|
||||
#endif
|
||||
|
||||
// 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);
|
||||
|
@ -21,7 +21,7 @@
|
||||
* 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
|
||||
* Google Author(s): Behdad Esfahbod, Garret Rieger, Roderick Sheeter
|
||||
* Adobe Author(s): Michiharu Ariza
|
||||
*/
|
||||
|
||||
@ -32,7 +32,6 @@
|
||||
#include "hb-ot-head-table.hh"
|
||||
#include "hb-ot-hmtx-table.hh"
|
||||
#include "hb-ot-var-gvar-table.hh"
|
||||
#include "hb-subset-glyf.hh"
|
||||
|
||||
#include <float.h>
|
||||
|
||||
@ -63,7 +62,7 @@ struct loca
|
||||
public:
|
||||
DEFINE_SIZE_MIN (0); /* In reality, this is UNBOUNDED() type; but since we always
|
||||
* check the size externally, allow Null() object of it by
|
||||
* defining it MIN() instead. */
|
||||
* defining it _MIN instead. */
|
||||
};
|
||||
|
||||
|
||||
@ -86,26 +85,172 @@ struct glyf
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
bool subset (hb_subset_plan_t *plan) const
|
||||
template<typename Iterator,
|
||||
hb_requires (hb_is_source_of (Iterator, unsigned int))>
|
||||
static bool
|
||||
_add_loca_and_head (hb_subset_plan_t * plan, Iterator padded_offsets)
|
||||
{
|
||||
hb_blob_t *glyf_prime = nullptr;
|
||||
hb_blob_t *loca_prime = nullptr;
|
||||
unsigned max_offset = + padded_offsets | hb_reduce(hb_add, 0);
|
||||
unsigned num_offsets = padded_offsets.len () + 1;
|
||||
bool use_short_loca = max_offset < 0x1FFFF;
|
||||
unsigned entry_size = use_short_loca ? 2 : 4;
|
||||
char *loca_prime_data = (char *) calloc (entry_size, num_offsets);
|
||||
|
||||
bool success = true;
|
||||
bool use_short_loca = false;
|
||||
if (hb_subset_glyf_and_loca (plan, &use_short_loca, &glyf_prime, &loca_prime)) {
|
||||
success = success && plan->add_table (HB_OT_TAG_glyf, glyf_prime);
|
||||
success = success && plan->add_table (HB_OT_TAG_loca, loca_prime);
|
||||
success = success && _add_head_and_set_loca_version (plan, use_short_loca);
|
||||
} else {
|
||||
success = false;
|
||||
}
|
||||
hb_blob_destroy (loca_prime);
|
||||
hb_blob_destroy (glyf_prime);
|
||||
if (unlikely (!loca_prime_data)) return false;
|
||||
|
||||
return success;
|
||||
DEBUG_MSG(SUBSET, nullptr, "loca entry_size %d num_offsets %d max_offset %d size %d", entry_size, num_offsets, max_offset, entry_size * num_offsets);
|
||||
|
||||
if (use_short_loca)
|
||||
_write_loca (padded_offsets, 1, hb_array ((HBUINT16*) loca_prime_data, num_offsets));
|
||||
else
|
||||
_write_loca (padded_offsets, 0, hb_array ((HBUINT32*) loca_prime_data, num_offsets));
|
||||
|
||||
hb_blob_t * loca_blob = hb_blob_create (loca_prime_data,
|
||||
entry_size * num_offsets,
|
||||
HB_MEMORY_MODE_WRITABLE,
|
||||
loca_prime_data,
|
||||
free);
|
||||
|
||||
bool result = plan->add_table (HB_OT_TAG_loca, loca_blob)
|
||||
&& _add_head_and_set_loca_version(plan, use_short_loca);
|
||||
|
||||
hb_blob_destroy (loca_blob);
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename IteratorIn, typename IteratorOut,
|
||||
hb_requires (hb_is_source_of (IteratorIn, unsigned int)),
|
||||
hb_requires (hb_is_sink_of (IteratorOut, unsigned))>
|
||||
static void
|
||||
_write_loca (IteratorIn it, unsigned right_shift, IteratorOut dest)
|
||||
{
|
||||
unsigned int offset = 0;
|
||||
dest << 0;
|
||||
+ it
|
||||
| hb_map ([=, &offset] (unsigned int padded_size) {
|
||||
offset += padded_size;
|
||||
DEBUG_MSG(SUBSET, nullptr, "loca entry offset %d", offset);
|
||||
return offset >> right_shift;
|
||||
})
|
||||
| hb_sink (dest)
|
||||
;
|
||||
}
|
||||
|
||||
// requires source of SubsetGlyph complains the identifier isn't declared
|
||||
template <typename Iterator>
|
||||
bool serialize(hb_serialize_context_t *c,
|
||||
Iterator it,
|
||||
const hb_subset_plan_t *plan)
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
|
||||
+ it
|
||||
| hb_apply ([=] (const SubsetGlyph& _) { _.serialize (c, plan); })
|
||||
;
|
||||
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
bool subset (hb_subset_context_t *c) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
|
||||
glyf *glyf_prime = c->serializer->start_embed <glyf> ();
|
||||
if (unlikely (!c->serializer->check_success (glyf_prime))) return_trace (false);
|
||||
|
||||
// Byte region(s) per glyph to output
|
||||
// unpadded, hints removed if so requested
|
||||
// If we fail to process a glyph we produce an empty (0-length) glyph
|
||||
hb_vector_t<SubsetGlyph> glyphs;
|
||||
_populate_subset_glyphs (c->plan, &glyphs);
|
||||
|
||||
glyf_prime->serialize (c->serializer, hb_iter (glyphs), c->plan);
|
||||
|
||||
auto padded_offsets =
|
||||
+ hb_iter (glyphs)
|
||||
| hb_map (&SubsetGlyph::padded_size)
|
||||
;
|
||||
|
||||
if (c->serializer->in_error ()) return_trace (false);
|
||||
return_trace (c->serializer->check_success (_add_loca_and_head (c->plan, padded_offsets)));
|
||||
}
|
||||
|
||||
template <typename SubsetGlyph>
|
||||
void
|
||||
_populate_subset_glyphs (const hb_subset_plan_t * plan,
|
||||
hb_vector_t<SubsetGlyph> * glyphs /* OUT */) const
|
||||
{
|
||||
OT::glyf::accelerator_t glyf;
|
||||
glyf.init (plan->source);
|
||||
|
||||
+ hb_range (plan->num_output_glyphs ())
|
||||
| hb_map ([&] (hb_codepoint_t new_gid) {
|
||||
SubsetGlyph subset_glyph;
|
||||
subset_glyph.new_gid = new_gid;
|
||||
|
||||
// should never fail: all old gids should be mapped
|
||||
if (!plan->old_gid_for_new_gid (new_gid, &subset_glyph.old_gid)) return subset_glyph;
|
||||
|
||||
subset_glyph.source_glyph = glyf.bytes_for_glyph ((const char *) this, subset_glyph.old_gid);
|
||||
if (plan->drop_hints) subset_glyph.drop_hints (glyf);
|
||||
else subset_glyph.dest_start = subset_glyph.source_glyph;
|
||||
|
||||
return subset_glyph;
|
||||
})
|
||||
| hb_sink (glyphs)
|
||||
;
|
||||
|
||||
glyf.fini();
|
||||
}
|
||||
|
||||
static void
|
||||
_fix_component_gids (const hb_subset_plan_t *plan,
|
||||
hb_bytes_t glyph)
|
||||
{
|
||||
OT::glyf::CompositeGlyphHeader::Iterator iterator;
|
||||
if (OT::glyf::CompositeGlyphHeader::get_iterator (&glyph,
|
||||
glyph.length,
|
||||
&iterator))
|
||||
{
|
||||
do
|
||||
{
|
||||
hb_codepoint_t new_gid;
|
||||
if (!plan->new_gid_for_old_gid (iterator.current->glyphIndex,
|
||||
&new_gid))
|
||||
continue;
|
||||
((OT::glyf::CompositeGlyphHeader *) iterator.current)->glyphIndex = new_gid;
|
||||
} while (iterator.move_to_next ());
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_zero_instruction_length (hb_bytes_t glyph)
|
||||
{
|
||||
const GlyphHeader &glyph_header = StructAtOffset<GlyphHeader> (&glyph, 0);
|
||||
int16_t num_contours = (int16_t) glyph_header.numberOfContours;
|
||||
if (num_contours <= 0) return; // only for simple glyphs
|
||||
|
||||
const HBUINT16 &instruction_length = StructAtOffset<HBUINT16> (&glyph, GlyphHeader::static_size + 2 * num_contours);
|
||||
(HBUINT16 &) instruction_length = 0;
|
||||
}
|
||||
|
||||
static bool _remove_composite_instruction_flag (hb_bytes_t glyph)
|
||||
{
|
||||
const GlyphHeader &glyph_header = StructAtOffset<GlyphHeader> (&glyph, 0);
|
||||
if (glyph_header.numberOfContours >= 0) return true; // only for composites
|
||||
|
||||
/* remove WE_HAVE_INSTRUCTIONS from flags in dest */
|
||||
OT::glyf::CompositeGlyphHeader::Iterator composite_it;
|
||||
if (unlikely (!OT::glyf::CompositeGlyphHeader::get_iterator (&glyph, glyph.length, &composite_it))) return false;
|
||||
const OT::glyf::CompositeGlyphHeader *composite_header;
|
||||
do {
|
||||
composite_header = composite_it.current;
|
||||
OT::HBUINT16 *flags = const_cast<OT::HBUINT16 *> (&composite_header->flags);
|
||||
*flags = (uint16_t) *flags & ~OT::glyf::CompositeGlyphHeader::WE_HAVE_INSTRUCTIONS;
|
||||
} while (composite_it.move_to_next ());
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
_add_head_and_set_loca_version (hb_subset_plan_t *plan, bool use_short_loca)
|
||||
{
|
||||
@ -261,6 +406,7 @@ struct glyf
|
||||
}
|
||||
|
||||
public:
|
||||
// TODO rewrite using new iterator framework if possible
|
||||
struct Iterator
|
||||
{
|
||||
const char *glyph_start;
|
||||
@ -330,7 +476,7 @@ struct glyf
|
||||
loca_table = hb_sanitize_context_t ().reference_table<loca> (face);
|
||||
glyf_table = hb_sanitize_context_t ().reference_table<glyf> (face);
|
||||
|
||||
num_glyphs = MAX (1u, loca_table.get_length () / (short_offset ? 2 : 4)) - 1;
|
||||
num_glyphs = hb_max (1u, loca_table.get_length () / (short_offset ? 2 : 4)) - 1;
|
||||
|
||||
gvar_accel.init (face);
|
||||
hmtx_accel.init (face);
|
||||
@ -690,7 +836,7 @@ struct glyf
|
||||
public:
|
||||
/* based on FontTools _g_l_y_f.py::trim */
|
||||
bool remove_padding (unsigned int start_offset,
|
||||
unsigned int *end_offset) const
|
||||
unsigned int *end_offset) const
|
||||
{
|
||||
if (*end_offset - start_offset < GlyphHeader::static_size) return true;
|
||||
|
||||
@ -788,61 +934,55 @@ struct glyf
|
||||
return true;
|
||||
}
|
||||
|
||||
bool get_instruction_offsets (unsigned int start_offset,
|
||||
unsigned int end_offset,
|
||||
unsigned int *instruction_start /* OUT */,
|
||||
unsigned int *instruction_end /* OUT */) const
|
||||
bool get_instruction_length (hb_bytes_t glyph,
|
||||
unsigned int * length /* OUT */) const
|
||||
{
|
||||
if (end_offset - start_offset < GlyphHeader::static_size)
|
||||
/* Empty glyph; no instructions. */
|
||||
if (glyph.length < GlyphHeader::static_size)
|
||||
{
|
||||
*instruction_start = 0;
|
||||
*instruction_end = 0;
|
||||
return true; /* Empty glyph; no instructions. */
|
||||
*length = 0;
|
||||
// only 0 byte glyphs are healthy when missing GlyphHeader
|
||||
return glyph.length == 0;
|
||||
}
|
||||
const GlyphHeader &glyph_header = StructAtOffset<GlyphHeader> (glyf_table, start_offset);
|
||||
const GlyphHeader &glyph_header = StructAtOffset<GlyphHeader> (&glyph, 0);
|
||||
int16_t num_contours = (int16_t) glyph_header.numberOfContours;
|
||||
if (num_contours < 0)
|
||||
{
|
||||
unsigned int start = glyph.length;
|
||||
unsigned int end = glyph.length;
|
||||
unsigned int glyph_offset = &glyph - glyf_table;
|
||||
CompositeGlyphHeader::Iterator composite_it;
|
||||
if (unlikely (!CompositeGlyphHeader::get_iterator (
|
||||
(const char*) this->glyf_table + start_offset,
|
||||
end_offset - start_offset, &composite_it))) return false;
|
||||
if (unlikely (!CompositeGlyphHeader::get_iterator (&glyph, glyph.length, &composite_it))) return false;
|
||||
const CompositeGlyphHeader *last;
|
||||
do {
|
||||
last = composite_it.current;
|
||||
} while (composite_it.move_to_next ());
|
||||
|
||||
if ((uint16_t) last->flags & CompositeGlyphHeader::WE_HAVE_INSTRUCTIONS)
|
||||
*instruction_start = ((char *) last - (char *) glyf_table->dataZ.arrayZ) + last->get_size ();
|
||||
else
|
||||
*instruction_start = end_offset;
|
||||
*instruction_end = end_offset;
|
||||
if (unlikely (*instruction_start > *instruction_end))
|
||||
start = ((char *) last - (char *) glyf_table->dataZ.arrayZ) + last->get_size () - glyph_offset;
|
||||
if (unlikely (start > end))
|
||||
{
|
||||
DEBUG_MSG(SUBSET, nullptr, "Invalid instruction offset, %d is outside [%d, %d]", *instruction_start, start_offset, end_offset);
|
||||
DEBUG_MSG(SUBSET, nullptr, "Invalid instruction offset, %d is outside %d byte buffer", start, glyph.length);
|
||||
return false;
|
||||
}
|
||||
*length = end - start;
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned int instruction_length_offset = start_offset + GlyphHeader::static_size + 2 * num_contours;
|
||||
if (unlikely (instruction_length_offset + 2 > end_offset))
|
||||
unsigned int instruction_length_offset = GlyphHeader::static_size + 2 * num_contours;
|
||||
if (unlikely (instruction_length_offset + 2 > glyph.length))
|
||||
{
|
||||
DEBUG_MSG(SUBSET, nullptr, "Glyph size is too short, missing field instructionLength.");
|
||||
return false;
|
||||
}
|
||||
|
||||
const HBUINT16 &instruction_length = StructAtOffset<HBUINT16> (glyf_table, instruction_length_offset);
|
||||
unsigned int start = instruction_length_offset + 2;
|
||||
unsigned int end = start + (uint16_t) instruction_length;
|
||||
if (unlikely (end > end_offset)) // Out of bounds of the current glyph
|
||||
const HBUINT16 &instruction_length = StructAtOffset<HBUINT16> (&glyph, instruction_length_offset);
|
||||
if (unlikely (instruction_length_offset + instruction_length > glyph.length)) // Out of bounds of the current glyph
|
||||
{
|
||||
DEBUG_MSG(SUBSET, nullptr, "The instructions array overruns the glyph's boundaries.");
|
||||
return false;
|
||||
}
|
||||
|
||||
*instruction_start = start;
|
||||
*instruction_end = end;
|
||||
*length = (uint16_t) instruction_length;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -896,15 +1036,34 @@ struct glyf
|
||||
const GlyphHeader &glyph_header = StructAtOffset<GlyphHeader> (glyf_table, start_offset);
|
||||
|
||||
/* Undocumented rasterizer behavior: shift glyph to the left by (lsb - xMin), i.e., xMin = lsb */
|
||||
/* extents->x_bearing = MIN (glyph_header.xMin, glyph_header.xMax); */
|
||||
/* extents->x_bearing = hb_min (glyph_header.xMin, glyph_header.xMax); */
|
||||
extents->x_bearing = hmtx_accel.get_side_bearing (glyph);
|
||||
extents->y_bearing = MAX (glyph_header.yMin, glyph_header.yMax);
|
||||
extents->width = MAX (glyph_header.xMin, glyph_header.xMax) - MIN (glyph_header.xMin, glyph_header.xMax);
|
||||
extents->height = MIN (glyph_header.yMin, glyph_header.yMax) - extents->y_bearing;
|
||||
extents->y_bearing = hb_max (glyph_header.yMin, glyph_header.yMax);
|
||||
extents->width = hb_max (glyph_header.xMin, glyph_header.xMax) - hb_min (glyph_header.xMin, glyph_header.xMax);
|
||||
extents->height = hb_min (glyph_header.yMin, glyph_header.yMax) - extents->y_bearing;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
hb_bytes_t bytes_for_glyph (const char * glyf, hb_codepoint_t gid)
|
||||
{
|
||||
unsigned int start_offset, end_offset;
|
||||
if (unlikely (!(get_offsets (gid, &start_offset, &end_offset) &&
|
||||
remove_padding (start_offset, &end_offset))))
|
||||
{
|
||||
DEBUG_MSG(SUBSET, nullptr, "Unable to get offset or remove padding for %d", gid);
|
||||
return hb_bytes_t ();
|
||||
}
|
||||
hb_bytes_t glyph = hb_bytes_t (glyf + start_offset, end_offset - start_offset);
|
||||
if (glyph.length == 0) return glyph;
|
||||
if (unlikely (glyph.length < GlyphHeader::static_size))
|
||||
{
|
||||
DEBUG_MSG(SUBSET, nullptr, "Glyph size smaller than minimum header %d", gid);
|
||||
return hb_bytes_t ();
|
||||
}
|
||||
return glyph;
|
||||
}
|
||||
|
||||
private:
|
||||
bool short_offset;
|
||||
unsigned int num_glyphs;
|
||||
@ -917,12 +1076,99 @@ struct glyf
|
||||
vmtx::accelerator_t vmtx_accel;
|
||||
};
|
||||
|
||||
|
||||
struct SubsetGlyph
|
||||
{
|
||||
hb_codepoint_t new_gid;
|
||||
hb_codepoint_t old_gid;
|
||||
hb_bytes_t source_glyph;
|
||||
hb_bytes_t dest_start; // region of source_glyph to copy first
|
||||
hb_bytes_t dest_end; // region of source_glyph to copy second
|
||||
|
||||
|
||||
bool serialize (hb_serialize_context_t *c,
|
||||
const hb_subset_plan_t *plan) const
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
|
||||
hb_bytes_t dest_glyph = dest_start.copy(c);
|
||||
dest_glyph = hb_bytes_t (&dest_glyph, dest_glyph.length + dest_end.copy(c).length);
|
||||
unsigned int pad_length = padding ();
|
||||
DEBUG_MSG(SUBSET, nullptr, "serialize %d byte glyph, width %d pad %d", dest_glyph.length, dest_glyph.length + pad_length, pad_length);
|
||||
|
||||
HBUINT8 pad;
|
||||
pad = 0;
|
||||
while (pad_length > 0)
|
||||
{
|
||||
c->embed(pad);
|
||||
pad_length--;
|
||||
}
|
||||
|
||||
if (dest_glyph.length)
|
||||
{
|
||||
_fix_component_gids (plan, dest_glyph);
|
||||
if (plan->drop_hints)
|
||||
{
|
||||
_zero_instruction_length (dest_glyph);
|
||||
c->check_success (_remove_composite_instruction_flag (dest_glyph));
|
||||
}
|
||||
}
|
||||
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
void drop_hints (const OT::glyf::accelerator_t& glyf)
|
||||
{
|
||||
if (source_glyph.length == 0) return;
|
||||
|
||||
unsigned int instruction_length = 0;
|
||||
if (!glyf.get_instruction_length (source_glyph, &instruction_length))
|
||||
{
|
||||
DEBUG_MSG(SUBSET, nullptr, "Unable to read instruction length for new_gid %d", new_gid);
|
||||
return ;
|
||||
}
|
||||
|
||||
const GlyphHeader& header = StructAtOffset<GlyphHeader> (&source_glyph, 0);
|
||||
int16_t num_contours = (int16_t) header.numberOfContours;
|
||||
DEBUG_MSG(SUBSET, nullptr, "new_gid %d (%d contours) drop %d instruction bytes from %d byte source glyph", new_gid, num_contours, instruction_length, source_glyph.length);
|
||||
if (num_contours < 0)
|
||||
{
|
||||
// composite, just chop instructions off the end
|
||||
dest_start = hb_bytes_t (&source_glyph, source_glyph.length - instruction_length);
|
||||
}
|
||||
else
|
||||
{
|
||||
// simple glyph
|
||||
dest_start = hb_bytes_t (&source_glyph, GlyphHeader::static_size + 2 * header.numberOfContours + 2);
|
||||
dest_end = hb_bytes_t (&source_glyph + dest_start.length + instruction_length,
|
||||
source_glyph.length - dest_start.length - instruction_length);
|
||||
DEBUG_MSG(SUBSET, nullptr, "source_len %d start len %d instruction_len %d end len %d", source_glyph.length, dest_start.length, instruction_length, dest_end.length);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int length () const
|
||||
{
|
||||
return dest_start.length + dest_end.length;
|
||||
}
|
||||
|
||||
// pad to 2 to ensure 2-byte loca will be ok
|
||||
unsigned int padding () const
|
||||
{
|
||||
return length () % 2;
|
||||
}
|
||||
|
||||
unsigned int padded_size () const
|
||||
{
|
||||
return length () + padding ();
|
||||
}
|
||||
};
|
||||
|
||||
protected:
|
||||
UnsizedArrayOf<HBUINT8> dataZ; /* Glyphs data. */
|
||||
public:
|
||||
DEFINE_SIZE_MIN (0); /* In reality, this is UNBOUNDED() type; but since we always
|
||||
* check the size externally, allow Null() object of it by
|
||||
* defining it MIN() instead. */
|
||||
* defining it _MIN instead. */
|
||||
};
|
||||
|
||||
struct glyf_accelerator_t : glyf::accelerator_t {};
|
||||
|
@ -41,71 +41,31 @@ namespace OT {
|
||||
|
||||
struct DeviceRecord
|
||||
{
|
||||
struct SubsetView
|
||||
{
|
||||
const DeviceRecord *source_device_record;
|
||||
unsigned int sizeDeviceRecord;
|
||||
hb_subset_plan_t *subset_plan;
|
||||
|
||||
void init (const DeviceRecord *source_device_record,
|
||||
unsigned int sizeDeviceRecord,
|
||||
hb_subset_plan_t *subset_plan)
|
||||
{
|
||||
this->source_device_record = source_device_record;
|
||||
this->sizeDeviceRecord = sizeDeviceRecord;
|
||||
this->subset_plan = subset_plan;
|
||||
}
|
||||
|
||||
unsigned int len () const
|
||||
{ return this->subset_plan->num_output_glyphs (); }
|
||||
|
||||
const HBUINT8* operator [] (unsigned int new_gid) const
|
||||
{
|
||||
if (unlikely (new_gid >= len ())) return nullptr;
|
||||
|
||||
hb_codepoint_t old_gid;
|
||||
if (!this->subset_plan->old_gid_for_new_gid (new_gid, &old_gid))
|
||||
return &Null(HBUINT8);
|
||||
|
||||
if (old_gid >= sizeDeviceRecord - DeviceRecord::min_size)
|
||||
return nullptr;
|
||||
return &(this->source_device_record->widthsZ[old_gid]);
|
||||
}
|
||||
};
|
||||
|
||||
static unsigned int get_size (unsigned int count)
|
||||
static unsigned int get_size (unsigned count)
|
||||
{ return hb_ceil_to_4 (min_size + count * HBUINT8::static_size); }
|
||||
|
||||
bool serialize (hb_serialize_context_t *c, const SubsetView &subset_view)
|
||||
template<typename Iterator,
|
||||
hb_requires (hb_is_iterator (Iterator))>
|
||||
bool serialize (hb_serialize_context_t *c, unsigned pixelSize, Iterator it)
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
|
||||
unsigned int size = get_size (subset_view.len ());
|
||||
if (unlikely (!c->allocate_size<DeviceRecord> (size)))
|
||||
{
|
||||
DEBUG_MSG(SUBSET, nullptr, "Couldn't allocate enough space for DeviceRecord: %d.",
|
||||
size);
|
||||
return_trace (false);
|
||||
}
|
||||
unsigned length = it.len ();
|
||||
|
||||
this->pixelSize = subset_view.source_device_record->pixelSize;
|
||||
this->maxWidth = subset_view.source_device_record->maxWidth;
|
||||
if (unlikely (!c->extend (*this, length))) return_trace (false);
|
||||
|
||||
for (unsigned int i = 0; i < subset_view.len (); i++)
|
||||
{
|
||||
const HBUINT8 *width = subset_view[i];
|
||||
if (!width)
|
||||
{
|
||||
DEBUG_MSG(SUBSET, nullptr, "HDMX width for new gid %d is missing.", i);
|
||||
return_trace (false);
|
||||
}
|
||||
widthsZ[i] = *width;
|
||||
}
|
||||
this->pixelSize = pixelSize;
|
||||
this->maxWidth =
|
||||
+ it
|
||||
| hb_reduce (hb_max, 0u);
|
||||
|
||||
+ it
|
||||
| hb_sink (widthsZ.as_array (length));
|
||||
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c, unsigned int sizeDeviceRecord) const
|
||||
bool sanitize (hb_sanitize_context_t *c, unsigned sizeDeviceRecord) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (likely (c->check_struct (this) &&
|
||||
@ -135,62 +95,63 @@ struct hdmx
|
||||
return StructAtOffset<DeviceRecord> (&this->firstDeviceRecord, i * sizeDeviceRecord);
|
||||
}
|
||||
|
||||
bool serialize (hb_serialize_context_t *c, const hdmx *source_hdmx, hb_subset_plan_t *plan)
|
||||
template<typename Iterator,
|
||||
hb_requires (hb_is_iterator (Iterator))>
|
||||
bool serialize (hb_serialize_context_t *c, unsigned version, Iterator it)
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
|
||||
if (unlikely (!c->extend_min ((*this)))) return_trace (false);
|
||||
|
||||
this->version = source_hdmx->version;
|
||||
this->numRecords = source_hdmx->numRecords;
|
||||
this->sizeDeviceRecord = DeviceRecord::get_size (plan->num_output_glyphs ());
|
||||
this->version = version;
|
||||
this->numRecords = it.len ();
|
||||
this->sizeDeviceRecord = DeviceRecord::get_size (it ? (*it).second.len () : 0);
|
||||
|
||||
for (unsigned int i = 0; i < source_hdmx->numRecords; i++)
|
||||
{
|
||||
DeviceRecord::SubsetView subset_view;
|
||||
subset_view.init (&(*source_hdmx)[i], source_hdmx->sizeDeviceRecord, plan);
|
||||
+ it
|
||||
| hb_apply ([c] (const hb_item_type<Iterator>& _) {
|
||||
c->start_embed<DeviceRecord> ()->serialize (c, _.first, _.second);
|
||||
})
|
||||
;
|
||||
|
||||
if (!c->start_embed<DeviceRecord> ()->serialize (c, subset_view))
|
||||
return_trace (false);
|
||||
}
|
||||
return_trace (c->successful);
|
||||
}
|
||||
|
||||
|
||||
bool subset (hb_subset_context_t *c) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
|
||||
hdmx *hdmx_prime = c->serializer->start_embed <hdmx> ();
|
||||
if (unlikely (!hdmx_prime)) return_trace (false);
|
||||
|
||||
auto it =
|
||||
+ hb_range ((unsigned) numRecords)
|
||||
| hb_map ([c, this] (unsigned _)
|
||||
{
|
||||
const DeviceRecord *device_record =
|
||||
&StructAtOffset<DeviceRecord> (&firstDeviceRecord,
|
||||
_ * sizeDeviceRecord);
|
||||
auto row =
|
||||
+ hb_range (c->plan->num_output_glyphs ())
|
||||
| hb_map (c->plan->reverse_glyph_map)
|
||||
| hb_map ([=] (hb_codepoint_t _)
|
||||
{
|
||||
if (c->plan->is_empty_glyph (_))
|
||||
return Null(HBUINT8);
|
||||
return device_record->widthsZ.as_array (get_num_glyphs ()) [_];
|
||||
})
|
||||
;
|
||||
return hb_pair ((unsigned) device_record->pixelSize, +row);
|
||||
})
|
||||
;
|
||||
|
||||
hdmx_prime->serialize (c->serializer, version, it);
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
static size_t get_subsetted_size (const hdmx *source_hdmx, hb_subset_plan_t *plan)
|
||||
unsigned get_num_glyphs () const
|
||||
{
|
||||
return min_size + source_hdmx->numRecords * DeviceRecord::get_size (plan->num_output_glyphs ());
|
||||
}
|
||||
|
||||
bool subset (hb_subset_plan_t *plan) const
|
||||
{
|
||||
size_t dest_size = get_subsetted_size (this, plan);
|
||||
hdmx *dest = (hdmx *) malloc (dest_size);
|
||||
if (unlikely (!dest))
|
||||
{
|
||||
DEBUG_MSG(SUBSET, nullptr, "Unable to alloc %lu for hdmx subset output.", (unsigned long) dest_size);
|
||||
return false;
|
||||
}
|
||||
|
||||
hb_serialize_context_t c (dest, dest_size);
|
||||
hdmx *hdmx_prime = c.start_serialize<hdmx> ();
|
||||
if (!hdmx_prime || !hdmx_prime->serialize (&c, this, plan))
|
||||
{
|
||||
free (dest);
|
||||
DEBUG_MSG(SUBSET, nullptr, "Failed to serialize write new hdmx.");
|
||||
return false;
|
||||
}
|
||||
c.end_serialize ();
|
||||
|
||||
hb_blob_t *hdmx_prime_blob = hb_blob_create ((const char *) dest,
|
||||
dest_size,
|
||||
HB_MEMORY_MODE_READONLY,
|
||||
dest,
|
||||
free);
|
||||
bool result = plan->add_table (HB_OT_TAG_hdmx, hdmx_prime_blob);
|
||||
hb_blob_destroy (hdmx_prime_blob);
|
||||
|
||||
return result;
|
||||
return sizeDeviceRecord - DeviceRecord::min_size;
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
|
@ -92,74 +92,71 @@ struct hmtxvmtx
|
||||
return result;
|
||||
}
|
||||
|
||||
bool subset (hb_subset_plan_t *plan) const
|
||||
template<typename Iterator,
|
||||
hb_requires (hb_is_iterator (Iterator))>
|
||||
void serialize (hb_serialize_context_t *c,
|
||||
Iterator it,
|
||||
unsigned num_advances)
|
||||
{
|
||||
typename T::accelerator_t _mtx;
|
||||
_mtx.init (plan->source);
|
||||
unsigned idx = 0;
|
||||
+ it
|
||||
| hb_apply ([c, &idx, num_advances] (const hb_item_type<Iterator>& _)
|
||||
{
|
||||
if (idx < num_advances)
|
||||
{
|
||||
LongMetric lm;
|
||||
lm.advance = _.first;
|
||||
lm.sb = _.second;
|
||||
if (unlikely (!c->embed<LongMetric> (&lm))) return;
|
||||
}
|
||||
else
|
||||
{
|
||||
FWORD *sb = c->allocate_size<FWORD> (FWORD::static_size);
|
||||
if (unlikely (!sb)) return;
|
||||
*sb = _.second;
|
||||
}
|
||||
idx++;
|
||||
})
|
||||
;
|
||||
}
|
||||
|
||||
/* All the trailing glyphs with the same advance can use one LongMetric
|
||||
* and just keep LSB */
|
||||
unsigned int num_output_glyphs = plan->num_output_glyphs ();
|
||||
unsigned int num_advances = _mtx.num_advances_for_subset (plan);
|
||||
bool subset (hb_subset_context_t *c) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
|
||||
/* alloc the new table */
|
||||
size_t dest_sz = num_advances * 4
|
||||
+ (num_output_glyphs - num_advances) * 2;
|
||||
void *dest = (void *) malloc (dest_sz);
|
||||
if (unlikely (!dest))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
DEBUG_MSG(SUBSET, nullptr, "%c%c%c%c in src has %d advances, %d lsbs", HB_UNTAG(T::tableTag), _mtx.num_advances, _mtx.num_metrics - _mtx.num_advances);
|
||||
DEBUG_MSG(SUBSET, nullptr, "%c%c%c%c in dest has %d advances, %d lsbs, %u bytes",
|
||||
HB_UNTAG(T::tableTag), num_advances, num_output_glyphs - num_advances, (unsigned int) dest_sz);
|
||||
T *table_prime = c->serializer->start_embed <T> ();
|
||||
if (unlikely (!table_prime)) return_trace (false);
|
||||
|
||||
// Copy everything over
|
||||
char * dest_pos = (char *) dest;
|
||||
accelerator_t _mtx;
|
||||
_mtx.init (c->plan->source);
|
||||
unsigned num_advances = _mtx.num_advances_for_subset (c->plan);
|
||||
|
||||
bool failed = false;
|
||||
for (unsigned int i = 0; i < num_output_glyphs; i++)
|
||||
{
|
||||
int side_bearing = 0;
|
||||
unsigned int advance = 0;
|
||||
hb_codepoint_t old_gid;
|
||||
if (plan->old_gid_for_new_gid (i, &old_gid))
|
||||
{
|
||||
// Glyph is not an empty glyph so copy advance and side bearing
|
||||
// from the input font.
|
||||
side_bearing = _mtx.get_side_bearing (old_gid);
|
||||
advance = _mtx.get_advance (old_gid);
|
||||
}
|
||||
auto it =
|
||||
+ hb_range (c->plan->num_output_glyphs ())
|
||||
| hb_map ([c, &_mtx] (unsigned _)
|
||||
{
|
||||
hb_codepoint_t old_gid;
|
||||
if (c->plan->old_gid_for_new_gid (_, &old_gid))
|
||||
return hb_pair (_mtx.get_advance (old_gid), _mtx.get_side_bearing (old_gid));
|
||||
else
|
||||
return hb_pair (0u, 0u);
|
||||
})
|
||||
;
|
||||
|
||||
table_prime->serialize (c->serializer, it, num_advances);
|
||||
|
||||
bool has_advance = i < num_advances;
|
||||
if (has_advance)
|
||||
{
|
||||
((LongMetric *) dest_pos)->advance = advance;
|
||||
((LongMetric *) dest_pos)->sb = side_bearing;
|
||||
}
|
||||
else
|
||||
{
|
||||
*((FWORD *) dest_pos) = side_bearing;
|
||||
}
|
||||
dest_pos += (has_advance ? 4 : 2);
|
||||
}
|
||||
_mtx.fini ();
|
||||
|
||||
if (unlikely (c->serializer->ran_out_of_room || c->serializer->in_error ()))
|
||||
return_trace (false);
|
||||
|
||||
// Amend header num hmetrics
|
||||
if (failed || unlikely (!subset_update_header (plan, num_advances)))
|
||||
if (unlikely (!subset_update_header (c->plan, num_advances)))
|
||||
{
|
||||
free (dest);
|
||||
return false;
|
||||
return_trace (false);
|
||||
}
|
||||
|
||||
hb_blob_t *result = hb_blob_create ((const char *)dest,
|
||||
dest_sz,
|
||||
HB_MEMORY_MODE_READONLY,
|
||||
dest,
|
||||
free);
|
||||
bool success = plan->add_table (T::tableTag, result);
|
||||
hb_blob_destroy (result);
|
||||
return success;
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
struct accelerator_t : hmtxvmtx_accelerator_base_t
|
||||
@ -264,7 +261,7 @@ struct hmtxvmtx
|
||||
return default_advance;
|
||||
}
|
||||
|
||||
return table->longMetricZ[MIN (glyph, (uint32_t) num_advances - 1)].advance;
|
||||
return table->longMetricZ[hb_min (glyph, (uint32_t) num_advances - 1)].advance;
|
||||
}
|
||||
|
||||
unsigned int get_advance (hb_codepoint_t glyph,
|
||||
|
@ -47,9 +47,9 @@ struct KernSubTableFormat3
|
||||
int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const
|
||||
{
|
||||
hb_array_t<const FWORD> kernValue = kernValueZ.as_array (kernValueCount);
|
||||
hb_array_t<const HBUINT8> leftClass = StructAfter<const UnsizedArrayOf<HBUINT8> > (kernValue).as_array (glyphCount);
|
||||
hb_array_t<const HBUINT8> rightClass = StructAfter<const UnsizedArrayOf<HBUINT8> > (leftClass).as_array (glyphCount);
|
||||
hb_array_t<const HBUINT8> kernIndex = StructAfter<const UnsizedArrayOf<HBUINT8> > (rightClass).as_array (leftClassCount * rightClassCount);
|
||||
hb_array_t<const HBUINT8> leftClass = StructAfter<const UnsizedArrayOf<HBUINT8>> (kernValue).as_array (glyphCount);
|
||||
hb_array_t<const HBUINT8> rightClass = StructAfter<const UnsizedArrayOf<HBUINT8>> (leftClass).as_array (glyphCount);
|
||||
hb_array_t<const HBUINT8> kernIndex = StructAfter<const UnsizedArrayOf<HBUINT8>> (rightClass).as_array (leftClassCount * rightClassCount);
|
||||
|
||||
unsigned int leftC = leftClass[left];
|
||||
unsigned int rightC = rightClass[right];
|
||||
@ -121,16 +121,20 @@ struct KernSubTable
|
||||
}
|
||||
}
|
||||
|
||||
template <typename context_t>
|
||||
typename context_t::return_t dispatch (context_t *c) const
|
||||
template <typename context_t, typename ...Ts>
|
||||
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
|
||||
{
|
||||
unsigned int subtable_type = get_type ();
|
||||
TRACE_DISPATCH (this, subtable_type);
|
||||
switch (subtable_type) {
|
||||
case 0: return_trace (c->dispatch (u.format0));
|
||||
case 1: return_trace (u.header.apple ? c->dispatch (u.format1) : c->default_return_value ());
|
||||
#ifndef HB_NO_SHAPE_AAT
|
||||
case 1: return_trace (u.header.apple ? c->dispatch (u.format1, hb_forward<Ts> (ds)...) : c->default_return_value ());
|
||||
#endif
|
||||
case 2: return_trace (c->dispatch (u.format2));
|
||||
case 3: return_trace (u.header.apple ? c->dispatch (u.format3) : c->default_return_value ());
|
||||
#ifndef HB_NO_SHAPE_AAT
|
||||
case 3: return_trace (u.header.apple ? c->dispatch (u.format3, hb_forward<Ts> (ds)...) : c->default_return_value ());
|
||||
#endif
|
||||
default: return_trace (c->default_return_value ());
|
||||
}
|
||||
}
|
||||
@ -278,7 +282,9 @@ struct kern
|
||||
{
|
||||
switch (get_type ()) {
|
||||
case 0: return u.ot.has_state_machine ();
|
||||
#ifndef HB_NO_SHAPE_AAT
|
||||
case 1: return u.aat.has_state_machine ();
|
||||
#endif
|
||||
default:return false;
|
||||
}
|
||||
}
|
||||
@ -287,7 +293,9 @@ struct kern
|
||||
{
|
||||
switch (get_type ()) {
|
||||
case 0: return u.ot.has_cross_stream ();
|
||||
#ifndef HB_NO_SHAPE_AAT
|
||||
case 1: return u.aat.has_cross_stream ();
|
||||
#endif
|
||||
default:return false;
|
||||
}
|
||||
}
|
||||
@ -296,7 +304,9 @@ struct kern
|
||||
{
|
||||
switch (get_type ()) {
|
||||
case 0: return u.ot.get_h_kerning (left, right);
|
||||
#ifndef HB_NO_SHAPE_AAT
|
||||
case 1: return u.aat.get_h_kerning (left, right);
|
||||
#endif
|
||||
default:return 0;
|
||||
}
|
||||
}
|
||||
@ -304,14 +314,16 @@ struct kern
|
||||
bool apply (AAT::hb_aat_apply_context_t *c) const
|
||||
{ return dispatch (c); }
|
||||
|
||||
template <typename context_t>
|
||||
typename context_t::return_t dispatch (context_t *c) const
|
||||
template <typename context_t, typename ...Ts>
|
||||
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
|
||||
{
|
||||
unsigned int subtable_type = get_type ();
|
||||
TRACE_DISPATCH (this, subtable_type);
|
||||
switch (subtable_type) {
|
||||
case 0: return_trace (c->dispatch (u.ot));
|
||||
case 1: return_trace (c->dispatch (u.aat));
|
||||
case 0: return_trace (c->dispatch (u.ot, hb_forward<Ts> (ds)...));
|
||||
#ifndef HB_NO_SHAPE_AAT
|
||||
case 1: return_trace (c->dispatch (u.aat, hb_forward<Ts> (ds)...));
|
||||
#endif
|
||||
default: return_trace (c->default_return_value ());
|
||||
}
|
||||
}
|
||||
@ -328,7 +340,9 @@ struct kern
|
||||
HBUINT32 version32;
|
||||
HBUINT16 major;
|
||||
KernOT ot;
|
||||
#ifndef HB_NO_SHAPE_AAT
|
||||
KernAAT aat;
|
||||
#endif
|
||||
} u;
|
||||
public:
|
||||
DEFINE_SIZE_UNION (4, version32);
|
||||
|
@ -447,7 +447,7 @@ struct Axis
|
||||
}
|
||||
|
||||
protected:
|
||||
OffsetTo<SortedArrayOf<Tag> >
|
||||
OffsetTo<SortedArrayOf<Tag>>
|
||||
baseTagList; /* Offset to BaseTagList table, from beginning
|
||||
* of Axis table (may be NULL)
|
||||
* Array of 4-byte baseline identification tags — must
|
||||
|
@ -104,7 +104,7 @@ struct Record
|
||||
};
|
||||
|
||||
template <typename Type>
|
||||
struct RecordArrayOf : SortedArrayOf<Record<Type> >
|
||||
struct RecordArrayOf : SortedArrayOf<Record<Type>>
|
||||
{
|
||||
const OffsetTo<Type>& get_offset (unsigned int i) const
|
||||
{ return (*this)[i].offset; }
|
||||
@ -139,11 +139,11 @@ struct RecordListOf : RecordArrayOf<Type>
|
||||
bool subset (hb_subset_context_t *c) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
struct RecordListOf<Type> *out = c->serializer->embed (*this);
|
||||
auto *out = c->serializer->embed (*this);
|
||||
if (unlikely (!out)) return_trace (false);
|
||||
unsigned int count = this->len;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
out->get_offset (i).serialize_subset (c, (*this)[i], out);
|
||||
out->get_offset (i).serialize_subset (c, this->get_offset (i), this, out);
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
@ -227,13 +227,13 @@ struct LangSys
|
||||
{
|
||||
if (reqFeatureIndex == 0xFFFFu)
|
||||
return Index::NOT_FOUND_INDEX;
|
||||
return reqFeatureIndex;;
|
||||
return reqFeatureIndex;
|
||||
}
|
||||
|
||||
bool subset (hb_subset_context_t *c) const
|
||||
LangSys* copy (hb_serialize_context_t *c) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
return_trace (c->serializer->embed (*this));
|
||||
TRACE_SERIALIZE (this);
|
||||
return_trace (c->embed (*this));
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c,
|
||||
@ -278,12 +278,12 @@ struct Script
|
||||
bool subset (hb_subset_context_t *c) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
struct Script *out = c->serializer->embed (*this);
|
||||
auto *out = c->serializer->embed (*this);
|
||||
if (unlikely (!out)) return_trace (false);
|
||||
out->defaultLangSys.serialize_subset (c, this+defaultLangSys, out);
|
||||
out->defaultLangSys.serialize_copy (c->serializer, defaultLangSys, this, out);
|
||||
unsigned int count = langSys.len;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
out->langSys.arrayZ[i].offset.serialize_subset (c, this+langSys[i].offset, out);
|
||||
out->langSys.arrayZ[i].offset.serialize_copy (c->serializer, langSys[i].offset, this, out);
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
@ -560,7 +560,7 @@ struct Feature
|
||||
bool subset (hb_subset_context_t *c) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
struct Feature *out = c->serializer->embed (*this);
|
||||
auto *out = c->serializer->embed (*this);
|
||||
if (unlikely (!out)) return_trace (false);
|
||||
out->featureParams = 0; /* TODO(subset) FeatureParams. */
|
||||
return_trace (true);
|
||||
@ -648,16 +648,19 @@ struct Lookup
|
||||
{
|
||||
unsigned int get_subtable_count () const { return subTable.len; }
|
||||
|
||||
template <typename TSubTable>
|
||||
const TSubTable& get_subtable (unsigned int i) const
|
||||
{ return this+CastR<OffsetArrayOf<TSubTable> > (subTable)[i]; }
|
||||
|
||||
template <typename TSubTable>
|
||||
const OffsetArrayOf<TSubTable>& get_subtables () const
|
||||
{ return CastR<OffsetArrayOf<TSubTable> > (subTable); }
|
||||
{ return CastR<OffsetArrayOf<TSubTable>> (subTable); }
|
||||
template <typename TSubTable>
|
||||
OffsetArrayOf<TSubTable>& get_subtables ()
|
||||
{ return CastR<OffsetArrayOf<TSubTable> > (subTable); }
|
||||
{ return CastR<OffsetArrayOf<TSubTable>> (subTable); }
|
||||
|
||||
template <typename TSubTable>
|
||||
const TSubTable& get_subtable (unsigned int i) const
|
||||
{ return this+get_subtables<TSubTable> ()[i]; }
|
||||
template <typename TSubTable>
|
||||
TSubTable& get_subtable (unsigned int i)
|
||||
{ return this+get_subtables<TSubTable> ()[i]; }
|
||||
|
||||
unsigned int get_size () const
|
||||
{
|
||||
@ -683,14 +686,14 @@ struct Lookup
|
||||
return flag;
|
||||
}
|
||||
|
||||
template <typename TSubTable, typename context_t>
|
||||
typename context_t::return_t dispatch (context_t *c) const
|
||||
template <typename TSubTable, typename context_t, typename ...Ts>
|
||||
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
|
||||
{
|
||||
unsigned int lookup_type = get_type ();
|
||||
TRACE_DISPATCH (this, lookup_type);
|
||||
unsigned int count = get_subtable_count ();
|
||||
for (unsigned int i = 0; i < count; i++) {
|
||||
typename context_t::return_t r = get_subtable<TSubTable> (i).dispatch (c, lookup_type);
|
||||
typename context_t::return_t r = get_subtable<TSubTable> (i).dispatch (c, lookup_type, hb_forward<Ts> (ds)...);
|
||||
if (c->stop_sublookup_iteration (r))
|
||||
return_trace (r);
|
||||
}
|
||||
@ -716,28 +719,11 @@ struct Lookup
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
/* Older compilers need this to NOT be locally defined in a function. */
|
||||
template <typename TSubTable>
|
||||
struct SubTableSubsetWrapper
|
||||
{
|
||||
SubTableSubsetWrapper (const TSubTable &subtable_,
|
||||
unsigned int lookup_type_) :
|
||||
subtable (subtable_),
|
||||
lookup_type (lookup_type_) {}
|
||||
|
||||
bool subset (hb_subset_context_t *c) const
|
||||
{ return subtable.dispatch (c, lookup_type); }
|
||||
|
||||
private:
|
||||
const TSubTable &subtable;
|
||||
unsigned int lookup_type;
|
||||
};
|
||||
|
||||
template <typename TSubTable>
|
||||
bool subset (hb_subset_context_t *c) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
struct Lookup *out = c->serializer->embed (*this);
|
||||
auto *out = c->serializer->embed (*this);
|
||||
if (unlikely (!out)) return_trace (false);
|
||||
|
||||
/* Subset the actual subtables. */
|
||||
@ -747,23 +733,11 @@ struct Lookup
|
||||
OffsetArrayOf<TSubTable>& out_subtables = out->get_subtables<TSubTable> ();
|
||||
unsigned int count = subTable.len;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
SubTableSubsetWrapper<TSubTable> wrapper (this+subtables[i], get_type ());
|
||||
|
||||
out_subtables[i].serialize_subset (c, wrapper, out);
|
||||
}
|
||||
out_subtables[i].serialize_subset (c, subtables[i], this, out, get_type ());
|
||||
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
/* Older compilers need this to NOT be locally defined in a function. */
|
||||
template <typename TSubTable>
|
||||
struct SubTableSanitizeWrapper : TSubTable
|
||||
{
|
||||
bool sanitize (hb_sanitize_context_t *c, unsigned int lookup_type) const
|
||||
{ return this->dispatch (c, lookup_type); }
|
||||
};
|
||||
|
||||
template <typename TSubTable>
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
@ -775,16 +749,21 @@ struct Lookup
|
||||
if (!markFilteringSet.sanitize (c)) return_trace (false);
|
||||
}
|
||||
|
||||
if (unlikely (!CastR<OffsetArrayOf<SubTableSanitizeWrapper<TSubTable> > > (subTable)
|
||||
.sanitize (c, this, get_type ())))
|
||||
if (unlikely (!get_subtables<TSubTable> ().sanitize (c, this, get_type ())))
|
||||
return_trace (false);
|
||||
|
||||
if (unlikely (get_type () == TSubTable::Extension))
|
||||
if (unlikely (get_type () == TSubTable::Extension && !c->get_edit_count ()))
|
||||
{
|
||||
/* The spec says all subtables of an Extension lookup should
|
||||
* have the same type, which shall not be the Extension type
|
||||
* itself (but we already checked for that).
|
||||
* This is specially important if one has a reverse type! */
|
||||
* This is specially important if one has a reverse type!
|
||||
*
|
||||
* We only do this if sanitizer edit_count is zero. Otherwise,
|
||||
* some of the subtables might have become insane after they
|
||||
* were sanity-checked by the edits of subsequent subtables.
|
||||
* https://bugs.chromium.org/p/chromium/issues/detail?id=960331
|
||||
*/
|
||||
unsigned int type = get_subtable<TSubTable> (0).u.extension.get_type ();
|
||||
unsigned int count = get_subtable_count ();
|
||||
for (unsigned int i = 1; i < count; i++)
|
||||
@ -792,7 +771,6 @@ struct Lookup
|
||||
return_trace (false);
|
||||
}
|
||||
return_trace (true);
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
private:
|
||||
@ -827,7 +805,7 @@ struct CoverageFormat1
|
||||
}
|
||||
|
||||
template <typename Iterator,
|
||||
hb_enable_if (hb_is_sorted_iterator_of (Iterator, const GlyphID))>
|
||||
hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))>
|
||||
bool serialize (hb_serialize_context_t *c, Iterator glyphs)
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
@ -865,6 +843,8 @@ struct CoverageFormat1
|
||||
bool more () const { return i < c->glyphArray.len; }
|
||||
void next () { i++; }
|
||||
hb_codepoint_t get_glyph () const { return c->glyphArray[i]; }
|
||||
bool operator != (const iter_t& o) const
|
||||
{ return i != o.i || c != o.c; }
|
||||
|
||||
private:
|
||||
const struct CoverageFormat1 *c;
|
||||
@ -894,7 +874,7 @@ struct CoverageFormat2
|
||||
}
|
||||
|
||||
template <typename Iterator,
|
||||
hb_enable_if (hb_is_sorted_iterator_of (Iterator, const GlyphID))>
|
||||
hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))>
|
||||
bool serialize (hb_serialize_context_t *c, Iterator glyphs)
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
@ -905,30 +885,36 @@ struct CoverageFormat2
|
||||
rangeRecord.len = 0;
|
||||
return_trace (true);
|
||||
}
|
||||
/* TODO(iter) Port to non-random-access iterator interface. */
|
||||
unsigned int count = glyphs.len ();
|
||||
|
||||
unsigned int num_ranges = 1;
|
||||
for (unsigned int i = 1; i < count; i++)
|
||||
if (glyphs[i - 1] + 1 != glyphs[i])
|
||||
num_ranges++;
|
||||
rangeRecord.len = num_ranges;
|
||||
if (unlikely (!c->extend (rangeRecord))) return_trace (false);
|
||||
/* TODO(iter) Write more efficiently? */
|
||||
|
||||
unsigned int range = 0;
|
||||
rangeRecord[range].start = glyphs[0];
|
||||
rangeRecord[range].value = 0;
|
||||
for (unsigned int i = 1; i < count; i++)
|
||||
unsigned num_ranges = 0;
|
||||
hb_codepoint_t last = (hb_codepoint_t) -2;
|
||||
for (auto g: glyphs)
|
||||
{
|
||||
if (glyphs[i - 1] + 1 != glyphs[i])
|
||||
{
|
||||
rangeRecord[range].end = glyphs[i - 1];
|
||||
range++;
|
||||
rangeRecord[range].start = glyphs[i];
|
||||
rangeRecord[range].value = i;
|
||||
}
|
||||
if (last + 1 != g)
|
||||
num_ranges++;
|
||||
last = g;
|
||||
}
|
||||
rangeRecord[range].end = glyphs[count - 1];
|
||||
|
||||
if (unlikely (!rangeRecord.serialize (c, num_ranges))) return_trace (false);
|
||||
|
||||
unsigned count = 0;
|
||||
unsigned range = (unsigned) -1;
|
||||
last = (hb_codepoint_t) -2;
|
||||
for (auto g: glyphs)
|
||||
{
|
||||
if (last + 1 != g)
|
||||
{
|
||||
range++;
|
||||
rangeRecord[range].start = g;
|
||||
rangeRecord[range].value = count;
|
||||
}
|
||||
rangeRecord[range].end = g;
|
||||
last = g;
|
||||
count++;
|
||||
}
|
||||
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
@ -1017,6 +1003,8 @@ struct CoverageFormat2
|
||||
j++;
|
||||
}
|
||||
hb_codepoint_t get_glyph () const { return j; }
|
||||
bool operator != (const iter_t& o) const
|
||||
{ return i != o.i || j != o.j || c != o.c; }
|
||||
|
||||
private:
|
||||
const struct CoverageFormat2 *c;
|
||||
@ -1056,18 +1044,22 @@ struct Coverage
|
||||
}
|
||||
|
||||
template <typename Iterator,
|
||||
hb_enable_if (hb_is_sorted_iterator_of (Iterator, const GlyphID))>
|
||||
hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))>
|
||||
bool serialize (hb_serialize_context_t *c, Iterator glyphs)
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
if (unlikely (!c->extend_min (*this))) return_trace (false);
|
||||
|
||||
/* TODO(iter) Port to non-random-access iterator interface. */
|
||||
unsigned int count = glyphs.len ();
|
||||
unsigned int num_ranges = 1;
|
||||
for (unsigned int i = 1; i < count; i++)
|
||||
if (glyphs[i - 1] + 1 != glyphs[i])
|
||||
num_ranges++;
|
||||
unsigned count = 0;
|
||||
unsigned num_ranges = 0;
|
||||
hb_codepoint_t last = (hb_codepoint_t) -2;
|
||||
for (auto g: glyphs)
|
||||
{
|
||||
if (last + 1 != g)
|
||||
num_ranges++;
|
||||
last = g;
|
||||
count++;
|
||||
}
|
||||
u.format = count * 2 < num_ranges * 3 ? 1 : 2;
|
||||
|
||||
switch (u.format)
|
||||
@ -1166,6 +1158,16 @@ struct Coverage
|
||||
default:return 0;
|
||||
}
|
||||
}
|
||||
bool operator != (const iter_t& o) const
|
||||
{
|
||||
if (format != o.format) return true;
|
||||
switch (format)
|
||||
{
|
||||
case 1: return u.format1 != o.u.format1;
|
||||
case 2: return u.format2 != o.u.format2;
|
||||
default:return false;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned int format;
|
||||
@ -1223,7 +1225,7 @@ struct ClassDefFormat1
|
||||
hb_codepoint_t glyph_max = +glyphs | hb_reduce (hb_max, 0u);
|
||||
|
||||
startGlyph = glyph_min;
|
||||
classValue.len = glyph_max - glyph_min + 1;
|
||||
c->check_assign (classValue.len, glyph_max - glyph_min + 1);
|
||||
if (unlikely (!c->extend (classValue))) return_trace (false);
|
||||
|
||||
for (unsigned int i = 0; i < glyphs.length; i++)
|
||||
@ -2163,10 +2165,10 @@ struct FeatureVariations
|
||||
return (this+record.substitutions).find_substitute (feature_index);
|
||||
}
|
||||
|
||||
bool subset (hb_subset_context_t *c) const
|
||||
FeatureVariations* copy (hb_serialize_context_t *c) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
return_trace (c->serializer->embed (*this));
|
||||
TRACE_SERIALIZE (this);
|
||||
return_trace (c->embed (*this));
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
|
@ -220,7 +220,7 @@ struct LigGlyph
|
||||
{
|
||||
if (caret_count)
|
||||
{
|
||||
hb_array_t <const OffsetTo<CaretValue> > array = carets.sub_array (start_offset, caret_count);
|
||||
hb_array_t <const OffsetTo<CaretValue>> array = carets.sub_array (start_offset, caret_count);
|
||||
unsigned int count = array.length;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
caret_array[i] = (this+array[i]).get_caret_value (font, direction, glyph_id, var_store);
|
||||
@ -296,7 +296,7 @@ struct MarkGlyphSetsFormat1
|
||||
|
||||
protected:
|
||||
HBUINT16 format; /* Format identifier--format = 1 */
|
||||
ArrayOf<LOffsetTo<Coverage> >
|
||||
ArrayOf<LOffsetTo<Coverage>>
|
||||
coverage; /* Array of long offsets to mark set
|
||||
* coverage tables */
|
||||
public:
|
||||
@ -439,19 +439,19 @@ struct GDEF
|
||||
bool subset (hb_subset_context_t *c) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
struct GDEF *out = c->serializer->embed (*this);
|
||||
auto *out = c->serializer->embed (*this);
|
||||
if (unlikely (!out)) return_trace (false);
|
||||
|
||||
out->glyphClassDef.serialize_subset (c, this+glyphClassDef, out);
|
||||
out->attachList = 0;//TODO(subset) serialize_subset (c, this+attachList, out);
|
||||
out->ligCaretList = 0;//TODO(subset) serialize_subset (c, this+ligCaretList, out);
|
||||
out->markAttachClassDef.serialize_subset (c, this+markAttachClassDef, out);
|
||||
out->glyphClassDef.serialize_subset (c, glyphClassDef, this, out);
|
||||
out->attachList = 0;//TODO(subset) serialize_subset (c, attachList, this, out);
|
||||
out->ligCaretList = 0;//TODO(subset) serialize_subset (c, ligCaretList, this, out);
|
||||
out->markAttachClassDef.serialize_subset (c, markAttachClassDef, this, out);
|
||||
|
||||
if (version.to_int () >= 0x00010002u)
|
||||
out->markGlyphSetsDef = 0;// TODO(subset) serialize_subset (c, this+markGlyphSetsDef, out);
|
||||
out->markGlyphSetsDef = 0;// TODO(subset) serialize_subset (c, markGlyphSetsDef, this, out);
|
||||
|
||||
if (version.to_int () >= 0x00010003u)
|
||||
out->varStore = 0;// TODO(subset) serialize_subset (c, this+varStore, out);
|
||||
out->varStore = 0;// TODO(subset) serialize_subset (c, varStore, this, out);
|
||||
|
||||
return_trace (true);
|
||||
}
|
||||
|
@ -174,11 +174,11 @@ struct ValueFormat : HBUINT16
|
||||
}
|
||||
|
||||
HB_INTERNAL static OffsetTo<Device>& get_device (Value* value)
|
||||
{ return *CastP<OffsetTo<Device> > (value); }
|
||||
{ return *CastP<OffsetTo<Device>> (value); }
|
||||
HB_INTERNAL static const OffsetTo<Device>& get_device (const Value* value, bool *worked=nullptr)
|
||||
{
|
||||
if (worked) *worked |= bool (*value);
|
||||
return *CastP<OffsetTo<Device> > (value);
|
||||
return *CastP<OffsetTo<Device>> (value);
|
||||
}
|
||||
|
||||
HB_INTERNAL static const HBINT16& get_short (const Value* value, bool *worked=nullptr)
|
||||
@ -393,7 +393,7 @@ struct AnchorMatrix
|
||||
|
||||
HBUINT16 rows; /* Number of rows */
|
||||
protected:
|
||||
UnsizedArrayOf<OffsetTo<Anchor> >
|
||||
UnsizedArrayOf<OffsetTo<Anchor>>
|
||||
matrixZ; /* Matrix of offsets to Anchor tables--
|
||||
* from beginning of AnchorMatrix table */
|
||||
public:
|
||||
@ -446,8 +446,8 @@ struct MarkArray : ArrayOf<MarkRecord> /* Array of MarkRecords--in Coverage orde
|
||||
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 = round (base_x - mark_x);
|
||||
o.y_offset = round (base_y - mark_y);
|
||||
o.x_offset = roundf (base_x - mark_x);
|
||||
o.y_offset = roundf (base_y - mark_y);
|
||||
o.attach_type() = ATTACH_TYPE_MARK;
|
||||
o.attach_chain() = (int) glyph_pos - (int) buffer->idx;
|
||||
buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
|
||||
@ -576,14 +576,14 @@ struct SinglePosFormat2
|
||||
|
||||
struct SinglePos
|
||||
{
|
||||
template <typename context_t>
|
||||
typename context_t::return_t dispatch (context_t *c) const
|
||||
template <typename context_t, typename ...Ts>
|
||||
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
|
||||
{
|
||||
TRACE_DISPATCH (this, u.format);
|
||||
if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
|
||||
switch (u.format) {
|
||||
case 1: return_trace (c->dispatch (u.format1));
|
||||
case 2: return_trace (c->dispatch (u.format2));
|
||||
case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
|
||||
case 2: return_trace (c->dispatch (u.format2, hb_forward<Ts> (ds)...));
|
||||
default:return_trace (c->default_return_value ());
|
||||
}
|
||||
}
|
||||
@ -726,7 +726,7 @@ struct PairPosFormat1
|
||||
+ hb_zip (this+coverage, pairSet)
|
||||
| hb_filter (*glyphs, hb_first)
|
||||
| hb_map (hb_second)
|
||||
| hb_map ([&] (const OffsetTo<PairSet> &_) -> bool
|
||||
| hb_map ([=] (const OffsetTo<PairSet> &_)
|
||||
{ return (this+_).intersects (glyphs, valueFormat); })
|
||||
| hb_any
|
||||
;
|
||||
@ -907,14 +907,14 @@ struct PairPosFormat2
|
||||
|
||||
struct PairPos
|
||||
{
|
||||
template <typename context_t>
|
||||
typename context_t::return_t dispatch (context_t *c) const
|
||||
template <typename context_t, typename ...Ts>
|
||||
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
|
||||
{
|
||||
TRACE_DISPATCH (this, u.format);
|
||||
if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
|
||||
switch (u.format) {
|
||||
case 1: return_trace (c->dispatch (u.format1));
|
||||
case 2: return_trace (c->dispatch (u.format2));
|
||||
case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
|
||||
case 2: return_trace (c->dispatch (u.format2, hb_forward<Ts> (ds)...));
|
||||
default:return_trace (c->default_return_value ());
|
||||
}
|
||||
}
|
||||
@ -993,32 +993,32 @@ struct CursivePosFormat1
|
||||
/* Main-direction adjustment */
|
||||
switch (c->direction) {
|
||||
case HB_DIRECTION_LTR:
|
||||
pos[i].x_advance = round (exit_x) + pos[i].x_offset;
|
||||
pos[i].x_advance = roundf (exit_x) + pos[i].x_offset;
|
||||
|
||||
d = round (entry_x) + pos[j].x_offset;
|
||||
d = roundf (entry_x) + pos[j].x_offset;
|
||||
pos[j].x_advance -= d;
|
||||
pos[j].x_offset -= d;
|
||||
break;
|
||||
case HB_DIRECTION_RTL:
|
||||
d = round (exit_x) + pos[i].x_offset;
|
||||
d = roundf (exit_x) + pos[i].x_offset;
|
||||
pos[i].x_advance -= d;
|
||||
pos[i].x_offset -= d;
|
||||
|
||||
pos[j].x_advance = round (entry_x) + pos[j].x_offset;
|
||||
pos[j].x_advance = roundf (entry_x) + pos[j].x_offset;
|
||||
break;
|
||||
case HB_DIRECTION_TTB:
|
||||
pos[i].y_advance = round (exit_y) + pos[i].y_offset;
|
||||
pos[i].y_advance = roundf (exit_y) + pos[i].y_offset;
|
||||
|
||||
d = round (entry_y) + pos[j].y_offset;
|
||||
d = roundf (entry_y) + pos[j].y_offset;
|
||||
pos[j].y_advance -= d;
|
||||
pos[j].y_offset -= d;
|
||||
break;
|
||||
case HB_DIRECTION_BTT:
|
||||
d = round (exit_y) + pos[i].y_offset;
|
||||
d = roundf (exit_y) + pos[i].y_offset;
|
||||
pos[i].y_advance -= d;
|
||||
pos[i].y_offset -= d;
|
||||
|
||||
pos[j].y_advance = round (entry_y);
|
||||
pos[j].y_advance = roundf (entry_y);
|
||||
break;
|
||||
case HB_DIRECTION_INVALID:
|
||||
default:
|
||||
@ -1092,13 +1092,13 @@ struct CursivePosFormat1
|
||||
|
||||
struct CursivePos
|
||||
{
|
||||
template <typename context_t>
|
||||
typename context_t::return_t dispatch (context_t *c) const
|
||||
template <typename context_t, typename ...Ts>
|
||||
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
|
||||
{
|
||||
TRACE_DISPATCH (this, u.format);
|
||||
if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
|
||||
switch (u.format) {
|
||||
case 1: return_trace (c->dispatch (u.format1));
|
||||
case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
|
||||
default:return_trace (c->default_return_value ());
|
||||
}
|
||||
}
|
||||
@ -1208,13 +1208,13 @@ struct MarkBasePosFormat1
|
||||
|
||||
struct MarkBasePos
|
||||
{
|
||||
template <typename context_t>
|
||||
typename context_t::return_t dispatch (context_t *c) const
|
||||
template <typename context_t, typename ...Ts>
|
||||
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
|
||||
{
|
||||
TRACE_DISPATCH (this, u.format);
|
||||
if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
|
||||
switch (u.format) {
|
||||
case 1: return_trace (c->dispatch (u.format1));
|
||||
case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
|
||||
default:return_trace (c->default_return_value ());
|
||||
}
|
||||
}
|
||||
@ -1287,7 +1287,7 @@ struct MarkLigPosFormat1
|
||||
unsigned int mark_id = _hb_glyph_info_get_lig_id (&buffer->cur());
|
||||
unsigned int mark_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
|
||||
if (lig_id && lig_id == mark_id && mark_comp > 0)
|
||||
comp_index = MIN (comp_count, _hb_glyph_info_get_lig_comp (&buffer->cur())) - 1;
|
||||
comp_index = hb_min (comp_count, _hb_glyph_info_get_lig_comp (&buffer->cur())) - 1;
|
||||
else
|
||||
comp_index = comp_count - 1;
|
||||
|
||||
@ -1333,13 +1333,13 @@ struct MarkLigPosFormat1
|
||||
|
||||
struct MarkLigPos
|
||||
{
|
||||
template <typename context_t>
|
||||
typename context_t::return_t dispatch (context_t *c) const
|
||||
template <typename context_t, typename ...Ts>
|
||||
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
|
||||
{
|
||||
TRACE_DISPATCH (this, u.format);
|
||||
if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
|
||||
switch (u.format) {
|
||||
case 1: return_trace (c->dispatch (u.format1));
|
||||
case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
|
||||
default:return_trace (c->default_return_value ());
|
||||
}
|
||||
}
|
||||
@ -1455,13 +1455,13 @@ struct MarkMarkPosFormat1
|
||||
|
||||
struct MarkMarkPos
|
||||
{
|
||||
template <typename context_t>
|
||||
typename context_t::return_t dispatch (context_t *c) const
|
||||
template <typename context_t, typename ...Ts>
|
||||
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
|
||||
{
|
||||
TRACE_DISPATCH (this, u.format);
|
||||
if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
|
||||
switch (u.format) {
|
||||
case 1: return_trace (c->dispatch (u.format1));
|
||||
case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
|
||||
default:return_trace (c->default_return_value ());
|
||||
}
|
||||
}
|
||||
@ -1507,20 +1507,20 @@ struct PosLookupSubTable
|
||||
Extension = 9
|
||||
};
|
||||
|
||||
template <typename context_t>
|
||||
typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const
|
||||
template <typename context_t, typename ...Ts>
|
||||
typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type, Ts&&... ds) const
|
||||
{
|
||||
TRACE_DISPATCH (this, lookup_type);
|
||||
switch (lookup_type) {
|
||||
case Single: return_trace (u.single.dispatch (c));
|
||||
case Pair: return_trace (u.pair.dispatch (c));
|
||||
case Cursive: return_trace (u.cursive.dispatch (c));
|
||||
case MarkBase: return_trace (u.markBase.dispatch (c));
|
||||
case MarkLig: return_trace (u.markLig.dispatch (c));
|
||||
case MarkMark: return_trace (u.markMark.dispatch (c));
|
||||
case Context: return_trace (u.context.dispatch (c));
|
||||
case ChainContext: return_trace (u.chainContext.dispatch (c));
|
||||
case Extension: return_trace (u.extension.dispatch (c));
|
||||
case Single: return_trace (u.single.dispatch (c, hb_forward<Ts> (ds)...));
|
||||
case Pair: return_trace (u.pair.dispatch (c, hb_forward<Ts> (ds)...));
|
||||
case Cursive: return_trace (u.cursive.dispatch (c, hb_forward<Ts> (ds)...));
|
||||
case MarkBase: return_trace (u.markBase.dispatch (c, hb_forward<Ts> (ds)...));
|
||||
case MarkLig: return_trace (u.markLig.dispatch (c, hb_forward<Ts> (ds)...));
|
||||
case MarkMark: return_trace (u.markMark.dispatch (c, hb_forward<Ts> (ds)...));
|
||||
case Context: return_trace (u.context.dispatch (c, hb_forward<Ts> (ds)...));
|
||||
case ChainContext: return_trace (u.chainContext.dispatch (c, hb_forward<Ts> (ds)...));
|
||||
case Extension: return_trace (u.extension.dispatch (c, hb_forward<Ts> (ds)...));
|
||||
default: return_trace (c->default_return_value ());
|
||||
}
|
||||
}
|
||||
@ -1581,9 +1581,9 @@ struct PosLookup : Lookup
|
||||
template <typename context_t>
|
||||
static typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index);
|
||||
|
||||
template <typename context_t>
|
||||
typename context_t::return_t dispatch (context_t *c) const
|
||||
{ return Lookup::dispatch<SubTable> (c); }
|
||||
template <typename context_t, typename ...Ts>
|
||||
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
|
||||
{ return Lookup::dispatch<SubTable> (c, hb_forward<Ts> (ds)...); }
|
||||
|
||||
bool subset (hb_subset_context_t *c) const
|
||||
{ return Lookup::subset<SubTable> (c); }
|
||||
|
@ -34,10 +34,12 @@
|
||||
|
||||
namespace OT {
|
||||
|
||||
typedef hb_pair_t<hb_codepoint_t, hb_codepoint_t> hb_codepoint_pair_t;
|
||||
|
||||
template<typename Iterator>
|
||||
static inline void SingleSubst_serialize (hb_serialize_context_t *c,
|
||||
hb_sorted_array_t<const GlyphID> glyphs,
|
||||
hb_array_t<const GlyphID> substitutes);
|
||||
Iterator it);
|
||||
|
||||
|
||||
struct SingleSubstFormat1
|
||||
{
|
||||
@ -46,9 +48,10 @@ struct SingleSubstFormat1
|
||||
|
||||
void closure (hb_closure_context_t *c) const
|
||||
{
|
||||
unsigned d = deltaGlyphID;
|
||||
+ hb_iter (this+coverage)
|
||||
| hb_filter (*c->glyphs)
|
||||
| hb_map ([&] (hb_codepoint_t g) -> hb_codepoint_t { return (g + deltaGlyphID) & 0xFFFFu; })
|
||||
| hb_map ([d] (hb_codepoint_t g) { return (g + d) & 0xFFFFu; })
|
||||
| hb_sink (c->output)
|
||||
;
|
||||
}
|
||||
@ -56,9 +59,9 @@ struct SingleSubstFormat1
|
||||
void collect_glyphs (hb_collect_glyphs_context_t *c) const
|
||||
{
|
||||
if (unlikely (!(this+coverage).add_coverage (c->input))) return;
|
||||
|
||||
unsigned d = deltaGlyphID;
|
||||
+ hb_iter (this+coverage)
|
||||
| hb_map ([&] (hb_codepoint_t g) -> hb_codepoint_t { return (g + deltaGlyphID) & 0xFFFFu; })
|
||||
| hb_map ([d] (hb_codepoint_t g) { return (g + d) & 0xFFFFu; })
|
||||
| hb_sink (c->output)
|
||||
;
|
||||
}
|
||||
@ -83,8 +86,10 @@ struct SingleSubstFormat1
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
template<typename Iterator,
|
||||
hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))>
|
||||
bool serialize (hb_serialize_context_t *c,
|
||||
hb_sorted_array_t<const GlyphID> glyphs,
|
||||
Iterator glyphs,
|
||||
unsigned delta)
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
@ -97,23 +102,22 @@ struct SingleSubstFormat1
|
||||
bool subset (hb_subset_context_t *c) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
const hb_set_t &glyphset = *c->plan->glyphset ();
|
||||
const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
|
||||
const hb_map_t &glyph_map = *c->plan->glyph_map;
|
||||
|
||||
hb_sorted_vector_t<GlyphID> from;
|
||||
hb_vector_t<GlyphID> to;
|
||||
hb_codepoint_t delta = deltaGlyphID;
|
||||
|
||||
auto it =
|
||||
+ hb_iter (this+coverage)
|
||||
| hb_filter (glyphset)
|
||||
| hb_map ([&] (hb_codepoint_t g) -> hb_pair_t<hb_codepoint_t, hb_codepoint_t>
|
||||
{ return hb_pair<hb_codepoint_t, hb_codepoint_t> (glyph_map[g],
|
||||
glyph_map[(g + delta) & 0xFFFF]); })
|
||||
| hb_unzip (from, to);
|
||||
| hb_map_retains_sorting ([&] (hb_codepoint_t g) {
|
||||
return hb_codepoint_pair_t (glyph_map[g],
|
||||
glyph_map[(g + delta) & 0xFFFF]); })
|
||||
;
|
||||
|
||||
c->serializer->propagate_error (from, to);
|
||||
SingleSubst_serialize (c->serializer, from, to);
|
||||
return_trace (from.length);
|
||||
bool ret = bool (it);
|
||||
SingleSubst_serialize (c->serializer, it);
|
||||
return_trace (ret);
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
@ -174,11 +178,21 @@ struct SingleSubstFormat2
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
template<typename Iterator,
|
||||
hb_requires (hb_is_sorted_source_of (Iterator,
|
||||
hb_codepoint_pair_t))>
|
||||
bool serialize (hb_serialize_context_t *c,
|
||||
hb_sorted_array_t<const GlyphID> glyphs,
|
||||
hb_array_t<const GlyphID> substitutes)
|
||||
Iterator it)
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
auto substitutes =
|
||||
+ it
|
||||
| hb_map (hb_second)
|
||||
;
|
||||
auto glyphs =
|
||||
+ it
|
||||
| hb_map_retains_sorting (hb_first)
|
||||
;
|
||||
if (unlikely (!c->extend_min (*this))) return_trace (false);
|
||||
if (unlikely (!substitute.serialize (c, substitutes))) return_trace (false);
|
||||
if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs))) return_trace (false);
|
||||
@ -188,21 +202,19 @@ struct SingleSubstFormat2
|
||||
bool subset (hb_subset_context_t *c) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
const hb_set_t &glyphset = *c->plan->glyphset ();
|
||||
const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
|
||||
const hb_map_t &glyph_map = *c->plan->glyph_map;
|
||||
|
||||
hb_sorted_vector_t<GlyphID> from;
|
||||
hb_vector_t<GlyphID> to;
|
||||
|
||||
auto it =
|
||||
+ hb_zip (this+coverage, substitute)
|
||||
| hb_filter (glyphset, hb_first)
|
||||
| hb_map ([&] (hb_pair_t<hb_codepoint_t, const GlyphID &> p) -> hb_pair_t<hb_codepoint_t, hb_codepoint_t>
|
||||
{ return hb_pair (glyph_map[p.first], glyph_map[p.second]); })
|
||||
| hb_unzip (from, to);
|
||||
| hb_map_retains_sorting ([&] (hb_pair_t<hb_codepoint_t, const GlyphID &> p) -> hb_codepoint_pair_t
|
||||
{ return hb_pair (glyph_map[p.first], glyph_map[p.second]); })
|
||||
;
|
||||
|
||||
c->serializer->propagate_error (from, to);
|
||||
SingleSubst_serialize (c->serializer, from, to);
|
||||
return_trace (from.length);
|
||||
bool ret = bool (it);
|
||||
SingleSubst_serialize (c->serializer, it);
|
||||
return_trace (ret);
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
@ -225,40 +237,45 @@ struct SingleSubstFormat2
|
||||
|
||||
struct SingleSubst
|
||||
{
|
||||
|
||||
template<typename Iterator,
|
||||
hb_requires (hb_is_sorted_source_of (Iterator,
|
||||
const hb_codepoint_pair_t))>
|
||||
bool serialize (hb_serialize_context_t *c,
|
||||
hb_sorted_array_t<const GlyphID> glyphs,
|
||||
hb_array_t<const GlyphID> substitutes)
|
||||
Iterator glyphs)
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
if (unlikely (!c->extend_min (u.format))) return_trace (false);
|
||||
unsigned format = 2;
|
||||
unsigned delta = 0;
|
||||
if (glyphs.length)
|
||||
if (glyphs.len ())
|
||||
{
|
||||
format = 1;
|
||||
delta = (unsigned) (substitutes[0] - glyphs[0]) & 0xFFFF;
|
||||
for (unsigned int i = 1; i < glyphs.length; i++)
|
||||
if (delta != ((unsigned) (substitutes[i] - glyphs[i]) & 0xFFFF)) {
|
||||
format = 2;
|
||||
break;
|
||||
}
|
||||
auto get_delta = [=] (hb_codepoint_pair_t _) {
|
||||
return (unsigned) (_.second - _.first) & 0xFFFF;
|
||||
};
|
||||
delta = get_delta (*glyphs);
|
||||
if (!hb_all (++(+glyphs), delta, get_delta)) format = 2;
|
||||
}
|
||||
u.format = format;
|
||||
switch (u.format) {
|
||||
case 1: return_trace (u.format1.serialize (c, glyphs, delta));
|
||||
case 2: return_trace (u.format2.serialize (c, glyphs, substitutes));
|
||||
case 1: return_trace (u.format1.serialize (c,
|
||||
+ glyphs
|
||||
| hb_map_retains_sorting (hb_first),
|
||||
delta));
|
||||
case 2: return_trace (u.format2.serialize (c, glyphs));
|
||||
default:return_trace (false);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename context_t>
|
||||
typename context_t::return_t dispatch (context_t *c) const
|
||||
template <typename context_t, typename ...Ts>
|
||||
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
|
||||
{
|
||||
TRACE_DISPATCH (this, u.format);
|
||||
if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
|
||||
switch (u.format) {
|
||||
case 1: return_trace (c->dispatch (u.format1));
|
||||
case 2: return_trace (c->dispatch (u.format2));
|
||||
case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
|
||||
case 2: return_trace (c->dispatch (u.format2, hb_forward<Ts> (ds)...));
|
||||
default:return_trace (c->default_return_value ());
|
||||
}
|
||||
}
|
||||
@ -271,11 +288,11 @@ struct SingleSubst
|
||||
} u;
|
||||
};
|
||||
|
||||
template<typename Iterator>
|
||||
static inline void
|
||||
SingleSubst_serialize (hb_serialize_context_t *c,
|
||||
hb_sorted_array_t<const GlyphID> glyphs,
|
||||
hb_array_t<const GlyphID> substitutes)
|
||||
{ c->start_embed<SingleSubst> ()->serialize (c, glyphs, substitutes); }
|
||||
Iterator it)
|
||||
{ c->start_embed<SingleSubst> ()->serialize (c, it); }
|
||||
|
||||
struct Sequence
|
||||
{
|
||||
@ -321,8 +338,10 @@ struct Sequence
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
template <typename Iterator,
|
||||
hb_requires (hb_is_source_of (Iterator, hb_codepoint_t))>
|
||||
bool serialize (hb_serialize_context_t *c,
|
||||
hb_array_t<const GlyphID> subst)
|
||||
Iterator subst)
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
return_trace (substitute.serialize (c, subst));
|
||||
@ -351,7 +370,8 @@ struct MultipleSubstFormat1
|
||||
+ hb_zip (this+coverage, sequence)
|
||||
| hb_filter (*c->glyphs, hb_first)
|
||||
| hb_map (hb_second)
|
||||
| hb_apply ([&] (const OffsetTo<Sequence> &_) { (this+_).closure (c); })
|
||||
| hb_map (hb_add (this))
|
||||
| hb_apply ([c] (const Sequence &_) { _.closure (c); })
|
||||
;
|
||||
}
|
||||
|
||||
@ -360,7 +380,8 @@ struct MultipleSubstFormat1
|
||||
if (unlikely (!(this+coverage).add_coverage (c->input))) return;
|
||||
+ hb_zip (this+coverage, sequence)
|
||||
| hb_map (hb_second)
|
||||
| hb_apply ([&] (const OffsetTo<Sequence> &_) { (this+_).collect_glyphs (c); })
|
||||
| hb_map (hb_add (this))
|
||||
| hb_apply ([c] (const Sequence &_) { _.collect_glyphs (c); })
|
||||
;
|
||||
}
|
||||
|
||||
@ -440,13 +461,13 @@ struct MultipleSubst
|
||||
}
|
||||
}
|
||||
|
||||
template <typename context_t>
|
||||
typename context_t::return_t dispatch (context_t *c) const
|
||||
template <typename context_t, typename ...Ts>
|
||||
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
|
||||
{
|
||||
TRACE_DISPATCH (this, u.format);
|
||||
if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
|
||||
switch (u.format) {
|
||||
case 1: return_trace (c->dispatch (u.format1));
|
||||
case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
|
||||
default:return_trace (c->default_return_value ());
|
||||
}
|
||||
}
|
||||
@ -484,7 +505,7 @@ struct AlternateSet
|
||||
unsigned int shift = hb_ctz (lookup_mask);
|
||||
unsigned int alt_index = ((lookup_mask & glyph_mask) >> shift);
|
||||
|
||||
/* If alt_index is MAX, randomize feature if it is the rand feature. */
|
||||
/* If alt_index is MAX_VALUE, randomize feature if it is the rand feature. */
|
||||
if (alt_index == HB_OT_MAP_MAX_VALUE && c->random)
|
||||
alt_index = c->random_number () % count + 1;
|
||||
|
||||
@ -495,8 +516,10 @@ struct AlternateSet
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
template <typename Iterator,
|
||||
hb_requires (hb_is_source_of (Iterator, hb_codepoint_t))>
|
||||
bool serialize (hb_serialize_context_t *c,
|
||||
hb_array_t<const GlyphID> alts)
|
||||
Iterator alts)
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
return_trace (alternates.serialize (c, alts));
|
||||
@ -525,7 +548,8 @@ struct AlternateSubstFormat1
|
||||
{
|
||||
+ hb_zip (this+coverage, alternateSet)
|
||||
| hb_map (hb_second)
|
||||
| hb_apply ([&] (const OffsetTo<AlternateSet> &_) { (this+_).closure (c); })
|
||||
| hb_map (hb_add (this))
|
||||
| hb_apply ([c] (const AlternateSet &_) { _.closure (c); })
|
||||
;
|
||||
}
|
||||
|
||||
@ -534,7 +558,8 @@ struct AlternateSubstFormat1
|
||||
if (unlikely (!(this+coverage).add_coverage (c->input))) return;
|
||||
+ hb_zip (this+coverage, alternateSet)
|
||||
| hb_map (hb_second)
|
||||
| hb_apply ([&] (const OffsetTo<AlternateSet> &_) { (this+_).collect_glyphs (c); })
|
||||
| hb_map (hb_add (this))
|
||||
| hb_apply ([c] (const AlternateSet &_) { _.collect_glyphs (c); })
|
||||
;
|
||||
}
|
||||
|
||||
@ -614,13 +639,13 @@ struct AlternateSubst
|
||||
}
|
||||
}
|
||||
|
||||
template <typename context_t>
|
||||
typename context_t::return_t dispatch (context_t *c) const
|
||||
template <typename context_t, typename ...Ts>
|
||||
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
|
||||
{
|
||||
TRACE_DISPATCH (this, u.format);
|
||||
if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
|
||||
switch (u.format) {
|
||||
case 1: return_trace (c->dispatch (u.format1));
|
||||
case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
|
||||
default:return_trace (c->default_return_value ());
|
||||
}
|
||||
}
|
||||
@ -640,7 +665,7 @@ struct Ligature
|
||||
unsigned int count = component.lenP1;
|
||||
for (unsigned int i = 1; i < count; i++)
|
||||
if (!glyphs->has (component[i]))
|
||||
return false;
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -707,9 +732,11 @@ struct Ligature
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
template <typename Iterator,
|
||||
hb_requires (hb_is_source_of (Iterator, hb_codepoint_t))>
|
||||
bool serialize (hb_serialize_context_t *c,
|
||||
GlyphID ligature,
|
||||
hb_array_t<const GlyphID> components /* Starting from second */)
|
||||
Iterator components /* Starting from second */)
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
if (unlikely (!c->extend_min (*this))) return_trace (false);
|
||||
@ -741,7 +768,8 @@ struct LigatureSet
|
||||
{
|
||||
return
|
||||
+ hb_iter (ligature)
|
||||
| hb_map ([&] (const OffsetTo<Ligature> &_) -> bool { return (this+_).intersects (glyphs); })
|
||||
| hb_map (hb_add (this))
|
||||
| hb_map ([glyphs] (const Ligature &_) { return _.intersects (glyphs); })
|
||||
| hb_any
|
||||
;
|
||||
}
|
||||
@ -749,14 +777,16 @@ struct LigatureSet
|
||||
void closure (hb_closure_context_t *c) const
|
||||
{
|
||||
+ hb_iter (ligature)
|
||||
| hb_apply ([&] (const OffsetTo<Ligature> &_) { (this+_).closure (c); })
|
||||
| hb_map (hb_add (this))
|
||||
| hb_apply ([c] (const Ligature &_) { _.closure (c); })
|
||||
;
|
||||
}
|
||||
|
||||
void collect_glyphs (hb_collect_glyphs_context_t *c) const
|
||||
{
|
||||
+ hb_iter (ligature)
|
||||
| hb_apply ([&] (const OffsetTo<Ligature> &_) { (this+_).collect_glyphs (c); })
|
||||
| hb_map (hb_add (this))
|
||||
| hb_apply ([c] (const Ligature &_) { _.collect_glyphs (c); })
|
||||
;
|
||||
}
|
||||
|
||||
@ -764,7 +794,8 @@ struct LigatureSet
|
||||
{
|
||||
return
|
||||
+ hb_iter (ligature)
|
||||
| hb_map ([&] (const OffsetTo<Ligature> &_) -> bool { return (this+_).would_apply (c); })
|
||||
| hb_map (hb_add (this))
|
||||
| hb_map ([c] (const Ligature &_) { return _.would_apply (c); })
|
||||
| hb_any
|
||||
;
|
||||
}
|
||||
@ -792,7 +823,7 @@ struct LigatureSet
|
||||
if (unlikely (!ligature.serialize (c, ligatures.length))) return_trace (false);
|
||||
for (unsigned int i = 0; i < ligatures.length; i++)
|
||||
{
|
||||
unsigned int component_count = MAX<int> (component_count_list[i] - 1, 0);
|
||||
unsigned int component_count = (unsigned) hb_max ((int) component_count_list[i] - 1, 0);
|
||||
if (unlikely (!ligature[i].serialize (c, this)
|
||||
.serialize (c,
|
||||
ligatures[i],
|
||||
@ -825,7 +856,7 @@ struct LigatureSubstFormat1
|
||||
+ hb_zip (this+coverage, ligatureSet)
|
||||
| hb_filter (*glyphs, hb_first)
|
||||
| hb_map (hb_second)
|
||||
| hb_map ([&] (const OffsetTo<LigatureSet> &_) -> bool
|
||||
| hb_map ([this, glyphs] (const OffsetTo<LigatureSet> &_)
|
||||
{ return (this+_).intersects (glyphs); })
|
||||
| hb_any
|
||||
;
|
||||
@ -836,7 +867,8 @@ struct LigatureSubstFormat1
|
||||
+ hb_zip (this+coverage, ligatureSet)
|
||||
| hb_filter (*c->glyphs, hb_first)
|
||||
| hb_map (hb_second)
|
||||
| hb_apply ([&] (const OffsetTo<LigatureSet> &_) { (this+_).closure (c); })
|
||||
| hb_map (hb_add (this))
|
||||
| hb_apply ([c] (const LigatureSet &_) { _.closure (c); })
|
||||
;
|
||||
}
|
||||
|
||||
@ -846,7 +878,8 @@ struct LigatureSubstFormat1
|
||||
|
||||
+ hb_zip (this+coverage, ligatureSet)
|
||||
| hb_map (hb_second)
|
||||
| hb_apply ([&] (const OffsetTo<LigatureSet> &_) { (this+_).collect_glyphs (c); })
|
||||
| hb_map (hb_add (this))
|
||||
| hb_apply ([c] (const LigatureSet &_) { _.collect_glyphs (c); })
|
||||
;
|
||||
}
|
||||
|
||||
@ -945,13 +978,13 @@ struct LigatureSubst
|
||||
}
|
||||
}
|
||||
|
||||
template <typename context_t>
|
||||
typename context_t::return_t dispatch (context_t *c) const
|
||||
template <typename context_t, typename ...Ts>
|
||||
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
|
||||
{
|
||||
TRACE_DISPATCH (this, u.format);
|
||||
if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
|
||||
switch (u.format) {
|
||||
case 1: return_trace (c->dispatch (u.format1));
|
||||
case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
|
||||
default:return_trace (c->default_return_value ());
|
||||
}
|
||||
}
|
||||
@ -983,19 +1016,19 @@ struct ReverseChainSingleSubstFormat1
|
||||
if (!(this+coverage).intersects (glyphs))
|
||||
return false;
|
||||
|
||||
const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
|
||||
const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
|
||||
|
||||
unsigned int count;
|
||||
|
||||
count = backtrack.len;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
if (!(this+backtrack[i]).intersects (glyphs))
|
||||
return false;
|
||||
return false;
|
||||
|
||||
count = lookahead.len;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
if (!(this+lookahead[i]).intersects (glyphs))
|
||||
return false;
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -1004,8 +1037,8 @@ struct ReverseChainSingleSubstFormat1
|
||||
{
|
||||
if (!intersects (c->glyphs)) return;
|
||||
|
||||
const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
|
||||
const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
|
||||
const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
|
||||
const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID>> (lookahead);
|
||||
|
||||
+ hb_zip (this+coverage, substitute)
|
||||
| hb_filter (*c->glyphs, hb_first)
|
||||
@ -1024,12 +1057,12 @@ struct ReverseChainSingleSubstFormat1
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
if (unlikely (!(this+backtrack[i]).add_coverage (c->before))) return;
|
||||
|
||||
const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
|
||||
const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
|
||||
count = lookahead.len;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
if (unlikely (!(this+lookahead[i]).add_coverage (c->after))) return;
|
||||
|
||||
const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
|
||||
const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID>> (lookahead);
|
||||
count = substitute.len;
|
||||
c->output->add_array (substitute.arrayZ, substitute.len);
|
||||
}
|
||||
@ -1048,15 +1081,15 @@ struct ReverseChainSingleSubstFormat1
|
||||
unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
|
||||
if (likely (index == NOT_COVERED)) return_trace (false);
|
||||
|
||||
const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
|
||||
const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
|
||||
const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
|
||||
const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID>> (lookahead);
|
||||
|
||||
unsigned int start_index = 0, end_index = 0;
|
||||
if (match_backtrack (c,
|
||||
backtrack.len, (HBUINT16 *) backtrack.arrayZ,
|
||||
match_coverage, this,
|
||||
&start_index) &&
|
||||
match_lookahead (c,
|
||||
match_lookahead (c,
|
||||
lookahead.len, (HBUINT16 *) lookahead.arrayZ,
|
||||
match_coverage, this,
|
||||
1, &end_index))
|
||||
@ -1084,10 +1117,10 @@ struct ReverseChainSingleSubstFormat1
|
||||
TRACE_SANITIZE (this);
|
||||
if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this)))
|
||||
return_trace (false);
|
||||
const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
|
||||
const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
|
||||
if (!lookahead.sanitize (c, this))
|
||||
return_trace (false);
|
||||
const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
|
||||
const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID>> (lookahead);
|
||||
return_trace (substitute.sanitize (c));
|
||||
}
|
||||
|
||||
@ -1113,13 +1146,13 @@ struct ReverseChainSingleSubstFormat1
|
||||
|
||||
struct ReverseChainSingleSubst
|
||||
{
|
||||
template <typename context_t>
|
||||
typename context_t::return_t dispatch (context_t *c) const
|
||||
template <typename context_t, typename ...Ts>
|
||||
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
|
||||
{
|
||||
TRACE_DISPATCH (this, u.format);
|
||||
if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
|
||||
switch (u.format) {
|
||||
case 1: return_trace (c->dispatch (u.format1));
|
||||
case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
|
||||
default:return_trace (c->default_return_value ());
|
||||
}
|
||||
}
|
||||
@ -1153,19 +1186,19 @@ struct SubstLookupSubTable
|
||||
ReverseChainSingle = 8
|
||||
};
|
||||
|
||||
template <typename context_t>
|
||||
typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const
|
||||
template <typename context_t, typename ...Ts>
|
||||
typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type, Ts&&... ds) const
|
||||
{
|
||||
TRACE_DISPATCH (this, lookup_type);
|
||||
switch (lookup_type) {
|
||||
case Single: return_trace (u.single.dispatch (c));
|
||||
case Multiple: return_trace (u.multiple.dispatch (c));
|
||||
case Alternate: return_trace (u.alternate.dispatch (c));
|
||||
case Ligature: return_trace (u.ligature.dispatch (c));
|
||||
case Context: return_trace (u.context.dispatch (c));
|
||||
case ChainContext: return_trace (u.chainContext.dispatch (c));
|
||||
case Extension: return_trace (u.extension.dispatch (c));
|
||||
case ReverseChainSingle: return_trace (u.reverseChainContextSingle.dispatch (c));
|
||||
case Single: return_trace (u.single.dispatch (c, hb_forward<Ts> (ds)...));
|
||||
case Multiple: return_trace (u.multiple.dispatch (c, hb_forward<Ts> (ds)...));
|
||||
case Alternate: return_trace (u.alternate.dispatch (c, hb_forward<Ts> (ds)...));
|
||||
case Ligature: return_trace (u.ligature.dispatch (c, hb_forward<Ts> (ds)...));
|
||||
case Context: return_trace (u.context.dispatch (c, hb_forward<Ts> (ds)...));
|
||||
case ChainContext: return_trace (u.chainContext.dispatch (c, hb_forward<Ts> (ds)...));
|
||||
case Extension: return_trace (u.extension.dispatch (c, hb_forward<Ts> (ds)...));
|
||||
case ReverseChainSingle: return_trace (u.reverseChainContextSingle.dispatch (c, hb_forward<Ts> (ds)...));
|
||||
default: return_trace (c->default_return_value ());
|
||||
}
|
||||
}
|
||||
@ -1254,17 +1287,18 @@ struct SubstLookup : Lookup
|
||||
HB_INTERNAL static bool apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index);
|
||||
|
||||
SubTable& serialize_subtable (hb_serialize_context_t *c,
|
||||
unsigned int i)
|
||||
unsigned int i)
|
||||
{ return get_subtables<SubTable> ()[i].serialize (c, this); }
|
||||
|
||||
bool serialize_single (hb_serialize_context_t *c,
|
||||
uint32_t lookup_props,
|
||||
hb_sorted_array_t<const GlyphID> glyphs,
|
||||
hb_array_t<const GlyphID> substitutes)
|
||||
hb_sorted_array_t<const GlyphID> glyphs,
|
||||
hb_array_t<const GlyphID> substitutes)
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
if (unlikely (!Lookup::serialize (c, SubTable::Single, lookup_props, 1))) return_trace (false);
|
||||
return_trace (serialize_subtable (c, 0).u.single.serialize (c, glyphs, substitutes));
|
||||
return_trace (serialize_subtable (c, 0).u.single.
|
||||
serialize (c, hb_zip (glyphs, substitutes)));
|
||||
}
|
||||
|
||||
bool serialize_multiple (hb_serialize_context_t *c,
|
||||
@ -1275,10 +1309,11 @@ struct SubstLookup : Lookup
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
if (unlikely (!Lookup::serialize (c, SubTable::Multiple, lookup_props, 1))) return_trace (false);
|
||||
return_trace (serialize_subtable (c, 0).u.multiple.serialize (c,
|
||||
glyphs,
|
||||
substitute_len_list,
|
||||
substitute_glyphs_list));
|
||||
return_trace (serialize_subtable (c, 0).u.multiple.
|
||||
serialize (c,
|
||||
glyphs,
|
||||
substitute_len_list,
|
||||
substitute_glyphs_list));
|
||||
}
|
||||
|
||||
bool serialize_alternate (hb_serialize_context_t *c,
|
||||
@ -1289,10 +1324,11 @@ struct SubstLookup : Lookup
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
if (unlikely (!Lookup::serialize (c, SubTable::Alternate, lookup_props, 1))) return_trace (false);
|
||||
return_trace (serialize_subtable (c, 0).u.alternate.serialize (c,
|
||||
glyphs,
|
||||
alternate_len_list,
|
||||
alternate_glyphs_list));
|
||||
return_trace (serialize_subtable (c, 0).u.alternate.
|
||||
serialize (c,
|
||||
glyphs,
|
||||
alternate_len_list,
|
||||
alternate_glyphs_list));
|
||||
}
|
||||
|
||||
bool serialize_ligature (hb_serialize_context_t *c,
|
||||
@ -1305,12 +1341,13 @@ struct SubstLookup : Lookup
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
if (unlikely (!Lookup::serialize (c, SubTable::Ligature, lookup_props, 1))) return_trace (false);
|
||||
return_trace (serialize_subtable (c, 0).u.ligature.serialize (c,
|
||||
first_glyphs,
|
||||
ligature_per_first_glyph_count_list,
|
||||
ligatures_list,
|
||||
component_count_list,
|
||||
component_list));
|
||||
return_trace (serialize_subtable (c, 0).u.ligature.
|
||||
serialize (c,
|
||||
first_glyphs,
|
||||
ligature_per_first_glyph_count_list,
|
||||
ligatures_list,
|
||||
component_count_list,
|
||||
component_list));
|
||||
}
|
||||
|
||||
template <typename context_t>
|
||||
@ -1319,7 +1356,7 @@ struct SubstLookup : Lookup
|
||||
HB_INTERNAL static hb_closure_context_t::return_t dispatch_closure_recurse_func (hb_closure_context_t *c, unsigned int lookup_index)
|
||||
{
|
||||
if (!c->should_visit_lookup (lookup_index))
|
||||
return hb_void_t ();
|
||||
return hb_empty_t ();
|
||||
|
||||
hb_closure_context_t::return_t ret = dispatch_recurse_func (c, lookup_index);
|
||||
|
||||
@ -1331,9 +1368,9 @@ struct SubstLookup : Lookup
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename context_t>
|
||||
typename context_t::return_t dispatch (context_t *c) const
|
||||
{ return Lookup::dispatch<SubTable> (c); }
|
||||
template <typename context_t, typename ...Ts>
|
||||
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
|
||||
{ return Lookup::dispatch<SubTable> (c, hb_forward<Ts> (ds)...); }
|
||||
|
||||
bool subset (hb_subset_context_t *c) const
|
||||
{ return Lookup::subset<SubTable> (c); }
|
||||
|
@ -59,13 +59,13 @@ struct hb_intersects_context_t :
|
||||
};
|
||||
|
||||
struct hb_closure_context_t :
|
||||
hb_dispatch_context_t<hb_closure_context_t, hb_void_t, 0>
|
||||
hb_dispatch_context_t<hb_closure_context_t, hb_empty_t, 0>
|
||||
{
|
||||
const char *get_name () { return "CLOSURE"; }
|
||||
typedef return_t (*recurse_func_t) (hb_closure_context_t *c, unsigned int lookup_index);
|
||||
template <typename T>
|
||||
return_t dispatch (const T &obj) { obj.closure (this); return hb_void_t (); }
|
||||
static return_t default_return_value () { return hb_void_t (); }
|
||||
return_t dispatch (const T &obj) { obj.closure (this); return hb_empty_t (); }
|
||||
static return_t default_return_value () { return hb_empty_t (); }
|
||||
void recurse (unsigned int lookup_index)
|
||||
{
|
||||
if (unlikely (nesting_level_left == 0 || !recurse_func))
|
||||
@ -151,13 +151,13 @@ struct hb_would_apply_context_t :
|
||||
|
||||
|
||||
struct hb_collect_glyphs_context_t :
|
||||
hb_dispatch_context_t<hb_collect_glyphs_context_t, hb_void_t, 0>
|
||||
hb_dispatch_context_t<hb_collect_glyphs_context_t, hb_empty_t, 0>
|
||||
{
|
||||
const char *get_name () { return "COLLECT_GLYPHS"; }
|
||||
typedef return_t (*recurse_func_t) (hb_collect_glyphs_context_t *c, unsigned int lookup_index);
|
||||
template <typename T>
|
||||
return_t dispatch (const T &obj) { obj.collect_glyphs (this); return hb_void_t (); }
|
||||
static return_t default_return_value () { return hb_void_t (); }
|
||||
return_t dispatch (const T &obj) { obj.collect_glyphs (this); return hb_empty_t (); }
|
||||
static return_t default_return_value () { return hb_empty_t (); }
|
||||
void recurse (unsigned int lookup_index)
|
||||
{
|
||||
if (unlikely (nesting_level_left == 0 || !recurse_func))
|
||||
@ -610,7 +610,7 @@ struct hb_ot_apply_context_t :
|
||||
|
||||
|
||||
struct hb_get_subtables_context_t :
|
||||
hb_dispatch_context_t<hb_get_subtables_context_t, hb_void_t, HB_DEBUG_APPLY>
|
||||
hb_dispatch_context_t<hb_get_subtables_context_t, hb_empty_t, HB_DEBUG_APPLY>
|
||||
{
|
||||
template <typename Type>
|
||||
HB_INTERNAL static bool apply_to (const void *obj, OT::hb_ot_apply_context_t *c)
|
||||
@ -652,9 +652,9 @@ struct hb_get_subtables_context_t :
|
||||
{
|
||||
hb_applicable_t *entry = array.push();
|
||||
entry->init (obj, apply_to<T>);
|
||||
return hb_void_t ();
|
||||
return hb_empty_t ();
|
||||
}
|
||||
static return_t default_return_value () { return hb_void_t (); }
|
||||
static return_t default_return_value () { return hb_empty_t (); }
|
||||
|
||||
hb_get_subtables_context_t (array_t &array_) :
|
||||
array (array_),
|
||||
@ -708,7 +708,7 @@ static inline bool intersects_array (const hb_set_t *glyphs,
|
||||
{
|
||||
return
|
||||
+ hb_iter (values, count)
|
||||
| hb_map ([&] (const HBUINT16 &_) -> bool { return intersects_func (glyphs, _, intersects_data); })
|
||||
| hb_map ([&] (const HBUINT16 &_) { return intersects_func (glyphs, _, intersects_data); })
|
||||
| hb_any
|
||||
;
|
||||
}
|
||||
@ -849,7 +849,7 @@ static inline bool match_input (hb_ot_apply_context_t *c,
|
||||
if (ligbase == LIGBASE_NOT_CHECKED)
|
||||
{
|
||||
bool found = false;
|
||||
const hb_glyph_info_t *out = buffer->out_info;
|
||||
const auto *out = buffer->out_info;
|
||||
unsigned int j = buffer->out_len;
|
||||
while (j && _hb_glyph_info_get_lig_id (&out[j - 1]) == first_lig_id)
|
||||
{
|
||||
@ -973,7 +973,7 @@ static inline bool ligate_input (hb_ot_apply_context_t *c,
|
||||
if (this_comp == 0)
|
||||
this_comp = last_num_components;
|
||||
unsigned int new_lig_comp = components_so_far - last_num_components +
|
||||
MIN (this_comp, last_num_components);
|
||||
hb_min (this_comp, last_num_components);
|
||||
_hb_glyph_info_set_lig_props_for_mark (&buffer->cur(), lig_id, new_lig_comp);
|
||||
}
|
||||
buffer->next_glyph ();
|
||||
@ -995,7 +995,7 @@ static inline bool ligate_input (hb_ot_apply_context_t *c,
|
||||
if (!this_comp)
|
||||
break;
|
||||
unsigned int new_lig_comp = components_so_far - last_num_components +
|
||||
MIN (this_comp, last_num_components);
|
||||
hb_min (this_comp, last_num_components);
|
||||
_hb_glyph_info_set_lig_props_for_mark (&buffer->info[i], lig_id, new_lig_comp);
|
||||
} else
|
||||
break;
|
||||
@ -1173,7 +1173,7 @@ static inline bool apply_lookup (hb_ot_apply_context_t *c,
|
||||
else
|
||||
{
|
||||
/* NOTE: delta is negative. */
|
||||
delta = MAX (delta, (int) next - (int) count);
|
||||
delta = hb_max (delta, (int) next - (int) count);
|
||||
next -= delta;
|
||||
}
|
||||
|
||||
@ -1299,7 +1299,7 @@ struct Rule
|
||||
|
||||
void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
|
||||
{
|
||||
const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord> >
|
||||
const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
|
||||
(inputZ.as_array ((inputCount ? inputCount - 1 : 0)));
|
||||
context_closure_lookup (c,
|
||||
inputCount, inputZ.arrayZ,
|
||||
@ -1310,7 +1310,7 @@ struct Rule
|
||||
void collect_glyphs (hb_collect_glyphs_context_t *c,
|
||||
ContextCollectGlyphsLookupContext &lookup_context) const
|
||||
{
|
||||
const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord> >
|
||||
const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
|
||||
(inputZ.as_array (inputCount ? inputCount - 1 : 0));
|
||||
context_collect_glyphs_lookup (c,
|
||||
inputCount, inputZ.arrayZ,
|
||||
@ -1321,7 +1321,7 @@ struct Rule
|
||||
bool would_apply (hb_would_apply_context_t *c,
|
||||
ContextApplyLookupContext &lookup_context) const
|
||||
{
|
||||
const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord> >
|
||||
const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
|
||||
(inputZ.as_array (inputCount ? inputCount - 1 : 0));
|
||||
return context_would_apply_lookup (c,
|
||||
inputCount, inputZ.arrayZ,
|
||||
@ -1333,7 +1333,7 @@ struct Rule
|
||||
ContextApplyLookupContext &lookup_context) const
|
||||
{
|
||||
TRACE_APPLY (this);
|
||||
const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord> >
|
||||
const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
|
||||
(inputZ.as_array (inputCount ? inputCount - 1 : 0));
|
||||
return_trace (context_apply_lookup (c, inputCount, inputZ.arrayZ, lookupCount, lookupRecord.arrayZ, lookup_context));
|
||||
}
|
||||
@ -1371,7 +1371,8 @@ struct RuleSet
|
||||
{
|
||||
return
|
||||
+ hb_iter (rule)
|
||||
| hb_map ([&] (const OffsetTo<Rule> &_) -> bool { return (this+_).intersects (glyphs, lookup_context); })
|
||||
| hb_map (hb_add (this))
|
||||
| hb_map ([&] (const Rule &_) { return _.intersects (glyphs, lookup_context); })
|
||||
| hb_any
|
||||
;
|
||||
}
|
||||
@ -1381,7 +1382,8 @@ struct RuleSet
|
||||
{
|
||||
return
|
||||
+ hb_iter (rule)
|
||||
| hb_apply ([&] (const OffsetTo<Rule> &_) { (this+_).closure (c, lookup_context); })
|
||||
| hb_map (hb_add (this))
|
||||
| hb_apply ([&] (const Rule &_) { _.closure (c, lookup_context); })
|
||||
;
|
||||
}
|
||||
|
||||
@ -1390,7 +1392,8 @@ struct RuleSet
|
||||
{
|
||||
return
|
||||
+ hb_iter (rule)
|
||||
| hb_apply ([&] (const OffsetTo<Rule> &_) { (this+_).collect_glyphs (c, lookup_context); })
|
||||
| hb_map (hb_add (this))
|
||||
| hb_apply ([&] (const Rule &_) { _.collect_glyphs (c, lookup_context); })
|
||||
;
|
||||
}
|
||||
|
||||
@ -1399,7 +1402,8 @@ struct RuleSet
|
||||
{
|
||||
return
|
||||
+ hb_iter (rule)
|
||||
| hb_map ([&] (const OffsetTo<Rule> &_) -> bool { return (this+_).would_apply (c, lookup_context); })
|
||||
| hb_map (hb_add (this))
|
||||
| hb_map ([&] (const Rule &_) { return _.would_apply (c, lookup_context); })
|
||||
| hb_any
|
||||
;
|
||||
}
|
||||
@ -1410,7 +1414,8 @@ struct RuleSet
|
||||
TRACE_APPLY (this);
|
||||
return_trace (
|
||||
+ hb_iter (rule)
|
||||
| hb_map ([&] (const OffsetTo<Rule> &_) -> bool { return (this+_).apply (c, lookup_context); })
|
||||
| hb_map (hb_add (this))
|
||||
| hb_map ([&] (const Rule &_) { return _.apply (c, lookup_context); })
|
||||
| hb_any
|
||||
)
|
||||
;
|
||||
@ -1444,7 +1449,8 @@ struct ContextFormat1
|
||||
+ hb_zip (this+coverage, ruleSet)
|
||||
| hb_filter (*glyphs, hb_first)
|
||||
| hb_map (hb_second)
|
||||
| hb_map ([&] (const OffsetTo<RuleSet> &_) -> bool { return (this+_).intersects (glyphs, lookup_context); })
|
||||
| hb_map (hb_add (this))
|
||||
| hb_map ([&] (const RuleSet &_) { return _.intersects (glyphs, lookup_context); })
|
||||
| hb_any
|
||||
;
|
||||
}
|
||||
@ -1459,7 +1465,8 @@ struct ContextFormat1
|
||||
+ hb_zip (this+coverage, ruleSet)
|
||||
| hb_filter (*c->glyphs, hb_first)
|
||||
| hb_map (hb_second)
|
||||
| hb_apply ([&] (const OffsetTo<RuleSet> &_) { (this+_).closure (c, lookup_context); })
|
||||
| hb_map (hb_add (this))
|
||||
| hb_apply ([&] (const RuleSet &_) { _.closure (c, lookup_context); })
|
||||
;
|
||||
}
|
||||
|
||||
@ -1473,7 +1480,8 @@ struct ContextFormat1
|
||||
};
|
||||
|
||||
+ hb_iter (ruleSet)
|
||||
| hb_apply ([&] (const OffsetTo<RuleSet> &_) { (this+_).collect_glyphs (c, lookup_context); })
|
||||
| hb_map (hb_add (this))
|
||||
| hb_apply ([&] (const RuleSet &_) { _.collect_glyphs (c, lookup_context); })
|
||||
;
|
||||
}
|
||||
|
||||
@ -1546,7 +1554,7 @@ struct ContextFormat2
|
||||
|
||||
return
|
||||
+ hb_enumerate (ruleSet)
|
||||
| hb_map ([&] (const hb_pair_t<unsigned, const OffsetTo<RuleSet> &> p) -> bool
|
||||
| hb_map ([&] (const hb_pair_t<unsigned, const OffsetTo<RuleSet> &> p)
|
||||
{ return class_def.intersects_class (glyphs, p.first) &&
|
||||
(this+p.second).intersects (glyphs, lookup_context); })
|
||||
| hb_any
|
||||
@ -1567,11 +1575,12 @@ struct ContextFormat2
|
||||
|
||||
return
|
||||
+ hb_enumerate (ruleSet)
|
||||
| hb_filter ([&] (unsigned _) -> bool
|
||||
| hb_filter ([&] (unsigned _)
|
||||
{ return class_def.intersects_class (c->glyphs, _); },
|
||||
hb_first)
|
||||
| hb_map (hb_second)
|
||||
| hb_apply ([&] (const OffsetTo<RuleSet> &_) { (this+_).closure (c, lookup_context); })
|
||||
| hb_map (hb_add (this))
|
||||
| hb_apply ([&] (const RuleSet &_) { _.closure (c, lookup_context); })
|
||||
;
|
||||
}
|
||||
|
||||
@ -1586,7 +1595,8 @@ struct ContextFormat2
|
||||
};
|
||||
|
||||
+ hb_iter (ruleSet)
|
||||
| hb_apply ([&] (const OffsetTo<RuleSet> &_) { (this+_).collect_glyphs (c, lookup_context); })
|
||||
| hb_map (hb_add (this))
|
||||
| hb_apply ([&] (const RuleSet &_) { _.collect_glyphs (c, lookup_context); })
|
||||
;
|
||||
}
|
||||
|
||||
@ -1751,7 +1761,7 @@ struct ContextFormat3
|
||||
HBUINT16 glyphCount; /* Number of glyphs in the input glyph
|
||||
* sequence */
|
||||
HBUINT16 lookupCount; /* Number of LookupRecords */
|
||||
UnsizedArrayOf<OffsetTo<Coverage> >
|
||||
UnsizedArrayOf<OffsetTo<Coverage>>
|
||||
coverageZ; /* Array of offsets to Coverage
|
||||
* table in glyph sequence order */
|
||||
/*UnsizedArrayOf<LookupRecord>
|
||||
@ -1763,15 +1773,15 @@ struct ContextFormat3
|
||||
|
||||
struct Context
|
||||
{
|
||||
template <typename context_t>
|
||||
typename context_t::return_t dispatch (context_t *c) const
|
||||
template <typename context_t, typename ...Ts>
|
||||
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
|
||||
{
|
||||
TRACE_DISPATCH (this, u.format);
|
||||
if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
|
||||
switch (u.format) {
|
||||
case 1: return_trace (c->dispatch (u.format1));
|
||||
case 2: return_trace (c->dispatch (u.format2));
|
||||
case 3: return_trace (c->dispatch (u.format3));
|
||||
case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
|
||||
case 2: return_trace (c->dispatch (u.format2, hb_forward<Ts> (ds)...));
|
||||
case 3: return_trace (c->dispatch (u.format3, hb_forward<Ts> (ds)...));
|
||||
default:return_trace (c->default_return_value ());
|
||||
}
|
||||
}
|
||||
@ -1923,8 +1933,8 @@ struct ChainRule
|
||||
{
|
||||
bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const
|
||||
{
|
||||
const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
|
||||
const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
|
||||
const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
|
||||
const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
|
||||
return chain_context_intersects (glyphs,
|
||||
backtrack.len, backtrack.arrayZ,
|
||||
input.lenP1, input.arrayZ,
|
||||
@ -1935,9 +1945,9 @@ struct ChainRule
|
||||
void closure (hb_closure_context_t *c,
|
||||
ChainContextClosureLookupContext &lookup_context) const
|
||||
{
|
||||
const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
|
||||
const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
|
||||
const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
|
||||
const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
|
||||
const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
|
||||
const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
|
||||
chain_context_closure_lookup (c,
|
||||
backtrack.len, backtrack.arrayZ,
|
||||
input.lenP1, input.arrayZ,
|
||||
@ -1949,9 +1959,9 @@ struct ChainRule
|
||||
void collect_glyphs (hb_collect_glyphs_context_t *c,
|
||||
ChainContextCollectGlyphsLookupContext &lookup_context) const
|
||||
{
|
||||
const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
|
||||
const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
|
||||
const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
|
||||
const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
|
||||
const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
|
||||
const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
|
||||
chain_context_collect_glyphs_lookup (c,
|
||||
backtrack.len, backtrack.arrayZ,
|
||||
input.lenP1, input.arrayZ,
|
||||
@ -1963,9 +1973,9 @@ struct ChainRule
|
||||
bool would_apply (hb_would_apply_context_t *c,
|
||||
ChainContextApplyLookupContext &lookup_context) const
|
||||
{
|
||||
const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
|
||||
const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
|
||||
const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
|
||||
const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
|
||||
const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
|
||||
const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
|
||||
return chain_context_would_apply_lookup (c,
|
||||
backtrack.len, backtrack.arrayZ,
|
||||
input.lenP1, input.arrayZ,
|
||||
@ -1976,9 +1986,9 @@ struct ChainRule
|
||||
bool apply (hb_ot_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
|
||||
{
|
||||
TRACE_APPLY (this);
|
||||
const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
|
||||
const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
|
||||
const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
|
||||
const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
|
||||
const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
|
||||
const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
|
||||
return_trace (chain_context_apply_lookup (c,
|
||||
backtrack.len, backtrack.arrayZ,
|
||||
input.lenP1, input.arrayZ,
|
||||
@ -1990,11 +2000,11 @@ struct ChainRule
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
if (!backtrack.sanitize (c)) return_trace (false);
|
||||
const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
|
||||
const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
|
||||
if (!input.sanitize (c)) return_trace (false);
|
||||
const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
|
||||
const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
|
||||
if (!lookahead.sanitize (c)) return_trace (false);
|
||||
const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
|
||||
const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
|
||||
return_trace (lookup.sanitize (c));
|
||||
}
|
||||
|
||||
@ -2022,7 +2032,8 @@ struct ChainRuleSet
|
||||
{
|
||||
return
|
||||
+ hb_iter (rule)
|
||||
| hb_map ([&] (const OffsetTo<ChainRule> &_) -> bool { return (this+_).intersects (glyphs, lookup_context); })
|
||||
| hb_map (hb_add (this))
|
||||
| hb_map ([&] (const ChainRule &_) { return _.intersects (glyphs, lookup_context); })
|
||||
| hb_any
|
||||
;
|
||||
}
|
||||
@ -2030,7 +2041,8 @@ struct ChainRuleSet
|
||||
{
|
||||
return
|
||||
+ hb_iter (rule)
|
||||
| hb_apply ([&] (const OffsetTo<ChainRule> &_) { (this+_).closure (c, lookup_context); })
|
||||
| hb_map (hb_add (this))
|
||||
| hb_apply ([&] (const ChainRule &_) { _.closure (c, lookup_context); })
|
||||
;
|
||||
}
|
||||
|
||||
@ -2038,7 +2050,8 @@ struct ChainRuleSet
|
||||
{
|
||||
return
|
||||
+ hb_iter (rule)
|
||||
| hb_apply ([&] (const OffsetTo<ChainRule> &_) { (this+_).collect_glyphs (c, lookup_context); })
|
||||
| hb_map (hb_add (this))
|
||||
| hb_apply ([&] (const ChainRule &_) { _.collect_glyphs (c, lookup_context); })
|
||||
;
|
||||
}
|
||||
|
||||
@ -2046,7 +2059,8 @@ struct ChainRuleSet
|
||||
{
|
||||
return
|
||||
+ hb_iter (rule)
|
||||
| hb_map ([&] (const OffsetTo<ChainRule> &_) -> bool { return (this+_).would_apply (c, lookup_context); })
|
||||
| hb_map (hb_add (this))
|
||||
| hb_map ([&] (const ChainRule &_) { return _.would_apply (c, lookup_context); })
|
||||
| hb_any
|
||||
;
|
||||
}
|
||||
@ -2056,7 +2070,8 @@ struct ChainRuleSet
|
||||
TRACE_APPLY (this);
|
||||
return_trace (
|
||||
+ hb_iter (rule)
|
||||
| hb_map ([&] (const OffsetTo<ChainRule> &_) -> bool { return (this+_).apply (c, lookup_context); })
|
||||
| hb_map (hb_add (this))
|
||||
| hb_map ([&] (const ChainRule &_) { return _.apply (c, lookup_context); })
|
||||
| hb_any
|
||||
)
|
||||
;
|
||||
@ -2089,7 +2104,8 @@ struct ChainContextFormat1
|
||||
+ hb_zip (this+coverage, ruleSet)
|
||||
| hb_filter (*glyphs, hb_first)
|
||||
| hb_map (hb_second)
|
||||
| hb_map ([&] (const OffsetTo<ChainRuleSet> &_) -> bool { return (this+_).intersects (glyphs, lookup_context); })
|
||||
| hb_map (hb_add (this))
|
||||
| hb_map ([&] (const ChainRuleSet &_) { return _.intersects (glyphs, lookup_context); })
|
||||
| hb_any
|
||||
;
|
||||
}
|
||||
@ -2104,7 +2120,8 @@ struct ChainContextFormat1
|
||||
+ hb_zip (this+coverage, ruleSet)
|
||||
| hb_filter (*c->glyphs, hb_first)
|
||||
| hb_map (hb_second)
|
||||
| hb_apply ([&] (const OffsetTo<ChainRuleSet> &_) { (this+_).closure (c, lookup_context); })
|
||||
| hb_map (hb_add (this))
|
||||
| hb_apply ([&] (const ChainRuleSet &_) { _.closure (c, lookup_context); })
|
||||
;
|
||||
}
|
||||
|
||||
@ -2118,7 +2135,8 @@ struct ChainContextFormat1
|
||||
};
|
||||
|
||||
+ hb_iter (ruleSet)
|
||||
| hb_apply ([&] (const OffsetTo<ChainRuleSet> &_) { (this+_).collect_glyphs (c, lookup_context); })
|
||||
| hb_map (hb_add (this))
|
||||
| hb_apply ([&] (const ChainRuleSet &_) { _.collect_glyphs (c, lookup_context); })
|
||||
;
|
||||
}
|
||||
|
||||
@ -2193,9 +2211,9 @@ struct ChainContextFormat2
|
||||
|
||||
return
|
||||
+ hb_enumerate (ruleSet)
|
||||
| hb_map ([&] (const hb_pair_t<unsigned, const OffsetTo<ChainRuleSet> &> p) -> bool
|
||||
{ return input_class_def.intersects_class (glyphs, p.first) &&
|
||||
(this+p.second).intersects (glyphs, lookup_context); })
|
||||
| hb_map ([&] (const hb_pair_t<unsigned, const OffsetTo<ChainRuleSet> &> p)
|
||||
{ return input_class_def.intersects_class (glyphs, p.first) &&
|
||||
(this+p.second).intersects (glyphs, lookup_context); })
|
||||
| hb_any
|
||||
;
|
||||
}
|
||||
@ -2217,11 +2235,12 @@ struct ChainContextFormat2
|
||||
|
||||
return
|
||||
+ hb_enumerate (ruleSet)
|
||||
| hb_filter ([&] (unsigned _) -> bool
|
||||
| hb_filter ([&] (unsigned _)
|
||||
{ return input_class_def.intersects_class (c->glyphs, _); },
|
||||
hb_first)
|
||||
| hb_map (hb_second)
|
||||
| hb_apply ([&] (const OffsetTo<ChainRuleSet> &_) { (this+_).closure (c, lookup_context); })
|
||||
| hb_map (hb_add (this))
|
||||
| hb_apply ([&] (const ChainRuleSet &_) { _.closure (c, lookup_context); })
|
||||
;
|
||||
}
|
||||
|
||||
@ -2241,7 +2260,8 @@ struct ChainContextFormat2
|
||||
};
|
||||
|
||||
+ hb_iter (ruleSet)
|
||||
| hb_apply ([&] (const OffsetTo<ChainRuleSet> &_) { (this+_).collect_glyphs (c, lookup_context); })
|
||||
| hb_map (hb_add (this))
|
||||
| hb_apply ([&] (const ChainRuleSet &_) { _.collect_glyphs (c, lookup_context); })
|
||||
;
|
||||
}
|
||||
|
||||
@ -2330,12 +2350,12 @@ struct ChainContextFormat3
|
||||
{
|
||||
bool intersects (const hb_set_t *glyphs) const
|
||||
{
|
||||
const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
|
||||
const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
|
||||
|
||||
if (!(this+input[0]).intersects (glyphs))
|
||||
return false;
|
||||
|
||||
const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
|
||||
const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
|
||||
struct ChainContextClosureLookupContext lookup_context = {
|
||||
{intersects_coverage},
|
||||
{this, this, this}
|
||||
@ -2349,13 +2369,13 @@ struct ChainContextFormat3
|
||||
|
||||
void closure (hb_closure_context_t *c) const
|
||||
{
|
||||
const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
|
||||
const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
|
||||
|
||||
if (!(this+input[0]).intersects (c->glyphs))
|
||||
return;
|
||||
|
||||
const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
|
||||
const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
|
||||
const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
|
||||
const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
|
||||
struct ChainContextClosureLookupContext lookup_context = {
|
||||
{intersects_coverage},
|
||||
{this, this, this}
|
||||
@ -2370,12 +2390,12 @@ struct ChainContextFormat3
|
||||
|
||||
void collect_glyphs (hb_collect_glyphs_context_t *c) const
|
||||
{
|
||||
const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
|
||||
const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
|
||||
|
||||
(this+input[0]).add_coverage (c->input);
|
||||
|
||||
const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
|
||||
const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
|
||||
const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
|
||||
const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
|
||||
struct ChainContextCollectGlyphsLookupContext lookup_context = {
|
||||
{collect_coverage},
|
||||
{this, this, this}
|
||||
@ -2390,9 +2410,9 @@ struct ChainContextFormat3
|
||||
|
||||
bool would_apply (hb_would_apply_context_t *c) const
|
||||
{
|
||||
const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
|
||||
const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
|
||||
const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
|
||||
const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
|
||||
const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
|
||||
const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
|
||||
struct ChainContextApplyLookupContext lookup_context = {
|
||||
{match_coverage},
|
||||
{this, this, this}
|
||||
@ -2406,20 +2426,20 @@ struct ChainContextFormat3
|
||||
|
||||
const Coverage &get_coverage () const
|
||||
{
|
||||
const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
|
||||
const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
|
||||
return this+input[0];
|
||||
}
|
||||
|
||||
bool apply (hb_ot_apply_context_t *c) const
|
||||
{
|
||||
TRACE_APPLY (this);
|
||||
const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
|
||||
const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
|
||||
|
||||
unsigned int index = (this+input[0]).get_coverage (c->buffer->cur().codepoint);
|
||||
if (likely (index == NOT_COVERED)) return_trace (false);
|
||||
|
||||
const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
|
||||
const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
|
||||
const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
|
||||
const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
|
||||
struct ChainContextApplyLookupContext lookup_context = {
|
||||
{match_coverage},
|
||||
{this, this, this}
|
||||
@ -2442,12 +2462,12 @@ struct ChainContextFormat3
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
if (!backtrack.sanitize (c, this)) return_trace (false);
|
||||
const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
|
||||
const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
|
||||
if (!input.sanitize (c, this)) return_trace (false);
|
||||
if (!input.len) return_trace (false); /* To be consistent with Context. */
|
||||
const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
|
||||
const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
|
||||
if (!lookahead.sanitize (c, this)) return_trace (false);
|
||||
const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
|
||||
const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
|
||||
return_trace (lookup.sanitize (c));
|
||||
}
|
||||
|
||||
@ -2474,15 +2494,15 @@ struct ChainContextFormat3
|
||||
|
||||
struct ChainContext
|
||||
{
|
||||
template <typename context_t>
|
||||
typename context_t::return_t dispatch (context_t *c) const
|
||||
template <typename context_t, typename ...Ts>
|
||||
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
|
||||
{
|
||||
TRACE_DISPATCH (this, u.format);
|
||||
if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
|
||||
switch (u.format) {
|
||||
case 1: return_trace (c->dispatch (u.format1));
|
||||
case 2: return_trace (c->dispatch (u.format2));
|
||||
case 3: return_trace (c->dispatch (u.format3));
|
||||
case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
|
||||
case 2: return_trace (c->dispatch (u.format2, hb_forward<Ts> (ds)...));
|
||||
case 3: return_trace (c->dispatch (u.format3, hb_forward<Ts> (ds)...));
|
||||
default:return_trace (c->default_return_value ());
|
||||
}
|
||||
}
|
||||
@ -2504,18 +2524,14 @@ struct ExtensionFormat1
|
||||
|
||||
template <typename X>
|
||||
const X& get_subtable () const
|
||||
{
|
||||
unsigned int offset = extensionOffset;
|
||||
if (unlikely (!offset)) return Null(typename T::SubTable);
|
||||
return StructAtOffset<typename T::SubTable> (this, offset);
|
||||
}
|
||||
{ return this + CastR<LOffsetTo<typename T::SubTable>> (extensionOffset); }
|
||||
|
||||
template <typename context_t>
|
||||
typename context_t::return_t dispatch (context_t *c) const
|
||||
template <typename context_t, typename ...Ts>
|
||||
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
|
||||
{
|
||||
TRACE_DISPATCH (this, format);
|
||||
if (unlikely (!c->may_dispatch (this, this))) return_trace (c->no_dispatch_return_value ());
|
||||
return_trace (get_subtable<typename T::SubTable> ().dispatch (c, get_type ()));
|
||||
return_trace (get_subtable<typename T::SubTable> ().dispatch (c, get_type (), hb_forward<Ts> (ds)...));
|
||||
}
|
||||
|
||||
/* This is called from may_dispatch() above with hb_sanitize_context_t. */
|
||||
@ -2523,7 +2539,6 @@ struct ExtensionFormat1
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (c->check_struct (this) &&
|
||||
extensionOffset != 0 &&
|
||||
extensionLookupType != T::SubTable::Extension);
|
||||
}
|
||||
|
||||
@ -2532,7 +2547,7 @@ struct ExtensionFormat1
|
||||
HBUINT16 extensionLookupType; /* Lookup type of subtable referenced
|
||||
* by ExtensionOffset (i.e. the
|
||||
* extension subtable). */
|
||||
HBUINT32 extensionOffset; /* Offset to the extension subtable,
|
||||
Offset32 extensionOffset; /* Offset to the extension subtable,
|
||||
* of lookup type subtable. */
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (8);
|
||||
@ -2557,13 +2572,13 @@ struct Extension
|
||||
}
|
||||
}
|
||||
|
||||
template <typename context_t>
|
||||
typename context_t::return_t dispatch (context_t *c) const
|
||||
template <typename context_t, typename ...Ts>
|
||||
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
|
||||
{
|
||||
TRACE_DISPATCH (this, u.format);
|
||||
if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
|
||||
switch (u.format) {
|
||||
case 1: return_trace (u.format1.dispatch (c));
|
||||
case 1: return_trace (u.format1.dispatch (c, hb_forward<Ts> (ds)...));
|
||||
default:return_trace (c->default_return_value ());
|
||||
}
|
||||
}
|
||||
@ -2666,21 +2681,22 @@ struct GSUBGPOS
|
||||
bool subset (hb_subset_context_t *c) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
struct GSUBGPOS *out = c->serializer->embed (*this);
|
||||
auto *out = c->serializer->embed (*this);
|
||||
if (unlikely (!out)) return_trace (false);
|
||||
|
||||
out->scriptList.serialize_subset (c, this+scriptList, out);
|
||||
out->featureList.serialize_subset (c, this+featureList, out);
|
||||
out->scriptList.serialize_subset (c, scriptList, this, out);
|
||||
out->featureList.serialize_subset (c, featureList, this, out);
|
||||
|
||||
typedef OffsetListOf<TLookup> TLookupList;
|
||||
/* TODO Use intersects() to count how many subtables survive? */
|
||||
CastR<OffsetTo<TLookupList> > (out->lookupList)
|
||||
CastR<OffsetTo<TLookupList>> (out->lookupList)
|
||||
.serialize_subset (c,
|
||||
this+CastR<const OffsetTo<TLookupList> > (lookupList),
|
||||
CastR<OffsetTo<TLookupList>> (lookupList),
|
||||
this,
|
||||
out);
|
||||
|
||||
if (version.to_int () >= 0x00010001u)
|
||||
out->featureVars.serialize_subset (c, this+featureVars, out);
|
||||
out->featureVars.serialize_copy (c->serializer, featureVars, this, out);
|
||||
|
||||
return_trace (true);
|
||||
}
|
||||
@ -2700,7 +2716,7 @@ struct GSUBGPOS
|
||||
likely (version.major == 1) &&
|
||||
scriptList.sanitize (c, this) &&
|
||||
featureList.sanitize (c, this) &&
|
||||
CastR<OffsetTo<TLookupList> > (lookupList).sanitize (c, this) &&
|
||||
CastR<OffsetTo<TLookupList>> (lookupList).sanitize (c, this) &&
|
||||
(version.to_int () < 0x00010001u || featureVars.sanitize (c, this)));
|
||||
}
|
||||
|
||||
|
@ -138,7 +138,7 @@ bool
|
||||
OT::GDEF::is_blacklisted (hb_blob_t *blob,
|
||||
hb_face_t *face) const
|
||||
{
|
||||
#if defined(HB_NO_OT_LAYOUT_BLACKLIST)
|
||||
#ifdef HB_NO_OT_LAYOUT_BLACKLIST
|
||||
return false;
|
||||
#endif
|
||||
/* The ugly business of blacklisting individual fonts' tables happen here!
|
||||
@ -158,84 +158,82 @@ OT::GDEF::is_blacklisted (hb_blob_t *blob,
|
||||
* https://bugzilla.mozilla.org/show_bug.cgi?id=1279693
|
||||
* https://bugzilla.mozilla.org/show_bug.cgi?id=1279875
|
||||
*/
|
||||
#define ENCODE(x,y,z) (((uint64_t) (x) << 48) | ((uint64_t) (y) << 24) | (uint64_t) (z))
|
||||
switch ENCODE(blob->length,
|
||||
face->table.GSUB->table.get_length (),
|
||||
face->table.GPOS->table.get_length ())
|
||||
switch HB_CODEPOINT_ENCODE3(blob->length,
|
||||
face->table.GSUB->table.get_length (),
|
||||
face->table.GPOS->table.get_length ())
|
||||
{
|
||||
/* sha1sum:c5ee92f0bca4bfb7d06c4d03e8cf9f9cf75d2e8a Windows 7? timesi.ttf */
|
||||
case ENCODE (442, 2874, 42038):
|
||||
case HB_CODEPOINT_ENCODE3 (442, 2874, 42038):
|
||||
/* sha1sum:37fc8c16a0894ab7b749e35579856c73c840867b Windows 7? timesbi.ttf */
|
||||
case ENCODE (430, 2874, 40662):
|
||||
case HB_CODEPOINT_ENCODE3 (430, 2874, 40662):
|
||||
/* sha1sum:19fc45110ea6cd3cdd0a5faca256a3797a069a80 Windows 7 timesi.ttf */
|
||||
case ENCODE (442, 2874, 39116):
|
||||
case HB_CODEPOINT_ENCODE3 (442, 2874, 39116):
|
||||
/* sha1sum:6d2d3c9ed5b7de87bc84eae0df95ee5232ecde26 Windows 7 timesbi.ttf */
|
||||
case ENCODE (430, 2874, 39374):
|
||||
case HB_CODEPOINT_ENCODE3 (430, 2874, 39374):
|
||||
/* sha1sum:8583225a8b49667c077b3525333f84af08c6bcd8 OS X 10.11.3 Times New Roman Italic.ttf */
|
||||
case ENCODE (490, 3046, 41638):
|
||||
case HB_CODEPOINT_ENCODE3 (490, 3046, 41638):
|
||||
/* sha1sum:ec0f5a8751845355b7c3271d11f9918a966cb8c9 OS X 10.11.3 Times New Roman Bold Italic.ttf */
|
||||
case ENCODE (478, 3046, 41902):
|
||||
case HB_CODEPOINT_ENCODE3 (478, 3046, 41902):
|
||||
/* sha1sum:96eda93f7d33e79962451c6c39a6b51ee893ce8c tahoma.ttf from Windows 8 */
|
||||
case ENCODE (898, 12554, 46470):
|
||||
case HB_CODEPOINT_ENCODE3 (898, 12554, 46470):
|
||||
/* sha1sum:20928dc06014e0cd120b6fc942d0c3b1a46ac2bc tahomabd.ttf from Windows 8 */
|
||||
case ENCODE (910, 12566, 47732):
|
||||
case HB_CODEPOINT_ENCODE3 (910, 12566, 47732):
|
||||
/* sha1sum:4f95b7e4878f60fa3a39ca269618dfde9721a79e tahoma.ttf from Windows 8.1 */
|
||||
case ENCODE (928, 23298, 59332):
|
||||
case HB_CODEPOINT_ENCODE3 (928, 23298, 59332):
|
||||
/* sha1sum:6d400781948517c3c0441ba42acb309584b73033 tahomabd.ttf from Windows 8.1 */
|
||||
case ENCODE (940, 23310, 60732):
|
||||
case HB_CODEPOINT_ENCODE3 (940, 23310, 60732):
|
||||
/* tahoma.ttf v6.04 from Windows 8.1 x64, see https://bugzilla.mozilla.org/show_bug.cgi?id=1279925 */
|
||||
case ENCODE (964, 23836, 60072):
|
||||
case HB_CODEPOINT_ENCODE3 (964, 23836, 60072):
|
||||
/* tahomabd.ttf v6.04 from Windows 8.1 x64, see https://bugzilla.mozilla.org/show_bug.cgi?id=1279925 */
|
||||
case ENCODE (976, 23832, 61456):
|
||||
case HB_CODEPOINT_ENCODE3 (976, 23832, 61456):
|
||||
/* sha1sum:e55fa2dfe957a9f7ec26be516a0e30b0c925f846 tahoma.ttf from Windows 10 */
|
||||
case ENCODE (994, 24474, 60336):
|
||||
case HB_CODEPOINT_ENCODE3 (994, 24474, 60336):
|
||||
/* sha1sum:7199385abb4c2cc81c83a151a7599b6368e92343 tahomabd.ttf from Windows 10 */
|
||||
case ENCODE (1006, 24470, 61740):
|
||||
case HB_CODEPOINT_ENCODE3 (1006, 24470, 61740):
|
||||
/* tahoma.ttf v6.91 from Windows 10 x64, see https://bugzilla.mozilla.org/show_bug.cgi?id=1279925 */
|
||||
case ENCODE (1006, 24576, 61346):
|
||||
case HB_CODEPOINT_ENCODE3 (1006, 24576, 61346):
|
||||
/* tahomabd.ttf v6.91 from Windows 10 x64, see https://bugzilla.mozilla.org/show_bug.cgi?id=1279925 */
|
||||
case ENCODE (1018, 24572, 62828):
|
||||
case HB_CODEPOINT_ENCODE3 (1018, 24572, 62828):
|
||||
/* sha1sum:b9c84d820c49850d3d27ec498be93955b82772b5 tahoma.ttf from Windows 10 AU */
|
||||
case ENCODE (1006, 24576, 61352):
|
||||
case HB_CODEPOINT_ENCODE3 (1006, 24576, 61352):
|
||||
/* sha1sum:2bdfaab28174bdadd2f3d4200a30a7ae31db79d2 tahomabd.ttf from Windows 10 AU */
|
||||
case ENCODE (1018, 24572, 62834):
|
||||
case HB_CODEPOINT_ENCODE3 (1018, 24572, 62834):
|
||||
/* sha1sum:b0d36cf5a2fbe746a3dd277bffc6756a820807a7 Tahoma.ttf from Mac OS X 10.9 */
|
||||
case ENCODE (832, 7324, 47162):
|
||||
case HB_CODEPOINT_ENCODE3 (832, 7324, 47162):
|
||||
/* sha1sum:12fc4538e84d461771b30c18b5eb6bd434e30fba Tahoma Bold.ttf from Mac OS X 10.9 */
|
||||
case ENCODE (844, 7302, 45474):
|
||||
case HB_CODEPOINT_ENCODE3 (844, 7302, 45474):
|
||||
/* sha1sum:eb8afadd28e9cf963e886b23a30b44ab4fd83acc himalaya.ttf from Windows 7 */
|
||||
case ENCODE (180, 13054, 7254):
|
||||
case HB_CODEPOINT_ENCODE3 (180, 13054, 7254):
|
||||
/* sha1sum:73da7f025b238a3f737aa1fde22577a6370f77b0 himalaya.ttf from Windows 8 */
|
||||
case ENCODE (192, 12638, 7254):
|
||||
case HB_CODEPOINT_ENCODE3 (192, 12638, 7254):
|
||||
/* sha1sum:6e80fd1c0b059bbee49272401583160dc1e6a427 himalaya.ttf from Windows 8.1 */
|
||||
case ENCODE (192, 12690, 7254):
|
||||
case HB_CODEPOINT_ENCODE3 (192, 12690, 7254):
|
||||
/* 8d9267aea9cd2c852ecfb9f12a6e834bfaeafe44 cantarell-fonts-0.0.21/otf/Cantarell-Regular.otf */
|
||||
/* 983988ff7b47439ab79aeaf9a45bd4a2c5b9d371 cantarell-fonts-0.0.21/otf/Cantarell-Oblique.otf */
|
||||
case ENCODE (188, 248, 3852):
|
||||
case HB_CODEPOINT_ENCODE3 (188, 248, 3852):
|
||||
/* 2c0c90c6f6087ffbfea76589c93113a9cbb0e75f cantarell-fonts-0.0.21/otf/Cantarell-Bold.otf */
|
||||
/* 55461f5b853c6da88069ffcdf7f4dd3f8d7e3e6b cantarell-fonts-0.0.21/otf/Cantarell-Bold-Oblique.otf */
|
||||
case ENCODE (188, 264, 3426):
|
||||
case HB_CODEPOINT_ENCODE3 (188, 264, 3426):
|
||||
/* d125afa82a77a6475ac0e74e7c207914af84b37a padauk-2.80/Padauk.ttf RHEL 7.2 */
|
||||
case ENCODE (1058, 47032, 11818):
|
||||
case HB_CODEPOINT_ENCODE3 (1058, 47032, 11818):
|
||||
/* 0f7b80437227b90a577cc078c0216160ae61b031 padauk-2.80/Padauk-Bold.ttf RHEL 7.2*/
|
||||
case ENCODE (1046, 47030, 12600):
|
||||
case HB_CODEPOINT_ENCODE3 (1046, 47030, 12600):
|
||||
/* d3dde9aa0a6b7f8f6a89ef1002e9aaa11b882290 padauk-2.80/Padauk.ttf Ubuntu 16.04 */
|
||||
case ENCODE (1058, 71796, 16770):
|
||||
case HB_CODEPOINT_ENCODE3 (1058, 71796, 16770):
|
||||
/* 5f3c98ccccae8a953be2d122c1b3a77fd805093f padauk-2.80/Padauk-Bold.ttf Ubuntu 16.04 */
|
||||
case ENCODE (1046, 71790, 17862):
|
||||
case HB_CODEPOINT_ENCODE3 (1046, 71790, 17862):
|
||||
/* 6c93b63b64e8b2c93f5e824e78caca555dc887c7 padauk-2.80/Padauk-book.ttf */
|
||||
case ENCODE (1046, 71788, 17112):
|
||||
case HB_CODEPOINT_ENCODE3 (1046, 71788, 17112):
|
||||
/* d89b1664058359b8ec82e35d3531931125991fb9 padauk-2.80/Padauk-bookbold.ttf */
|
||||
case ENCODE (1058, 71794, 17514):
|
||||
case HB_CODEPOINT_ENCODE3 (1058, 71794, 17514):
|
||||
/* 824cfd193aaf6234b2b4dc0cf3c6ef576c0d00ef padauk-3.0/Padauk-book.ttf */
|
||||
case ENCODE (1330, 109904, 57938):
|
||||
case HB_CODEPOINT_ENCODE3 (1330, 109904, 57938):
|
||||
/* 91fcc10cf15e012d27571e075b3b4dfe31754a8a padauk-3.0/Padauk-bookbold.ttf */
|
||||
case ENCODE (1330, 109904, 58972):
|
||||
case HB_CODEPOINT_ENCODE3 (1330, 109904, 58972):
|
||||
/* sha1sum: c26e41d567ed821bed997e937bc0c41435689e85 Padauk.ttf
|
||||
* "Padauk Regular" "Version 2.5", see https://crbug.com/681813 */
|
||||
case ENCODE (1004, 59092, 14836):
|
||||
case HB_CODEPOINT_ENCODE3 (1004, 59092, 14836):
|
||||
return true;
|
||||
#undef ENCODE
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -335,6 +333,12 @@ hb_ot_layout_get_attach_points (hb_face_t *face,
|
||||
unsigned int *point_count /* IN/OUT */,
|
||||
unsigned int *point_array /* OUT */)
|
||||
{
|
||||
#ifdef HB_NO_LAYOUT_UNUSED
|
||||
if (point_count)
|
||||
*point_count = 0;
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
return face->table.GDEF->table->get_attach_points (glyph,
|
||||
start_offset,
|
||||
point_count,
|
||||
@ -364,6 +368,12 @@ hb_ot_layout_get_ligature_carets (hb_font_t *font,
|
||||
unsigned int *caret_count /* IN/OUT */,
|
||||
hb_position_t *caret_array /* OUT */)
|
||||
{
|
||||
#ifdef HB_NO_LAYOUT_UNUSED
|
||||
if (caret_count)
|
||||
*caret_count = 0;
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
unsigned int result_caret_count = 0;
|
||||
unsigned int result = font->face->table.GDEF->table->get_lig_carets (font, direction, glyph, start_offset, &result_caret_count, caret_array);
|
||||
if (result)
|
||||
@ -384,7 +394,7 @@ bool
|
||||
OT::GSUB::is_blacklisted (hb_blob_t *blob HB_UNUSED,
|
||||
hb_face_t *face) const
|
||||
{
|
||||
#if defined(HB_NO_OT_LAYOUT_BLACKLIST)
|
||||
#ifdef HB_NO_OT_LAYOUT_BLACKLIST
|
||||
return false;
|
||||
#endif
|
||||
/* Mac OS X prefers morx over GSUB. It also ships with various Indic fonts,
|
||||
@ -412,7 +422,7 @@ bool
|
||||
OT::GPOS::is_blacklisted (hb_blob_t *blob HB_UNUSED,
|
||||
hb_face_t *face HB_UNUSED) const
|
||||
{
|
||||
#if defined(HB_NO_OT_LAYOUT_BLACKLIST)
|
||||
#ifdef HB_NO_OT_LAYOUT_BLACKLIST
|
||||
return false;
|
||||
#endif
|
||||
return false;
|
||||
@ -500,6 +510,7 @@ hb_ot_layout_table_find_script (hb_face_t *face,
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifndef HB_DISABLE_DEPRECATED
|
||||
/**
|
||||
* hb_ot_layout_table_choose_script:
|
||||
* @face: #hb_face_t to work upon
|
||||
@ -521,6 +532,7 @@ hb_ot_layout_table_choose_script (hb_face_t *face,
|
||||
for (t = script_tags; *t; t++);
|
||||
return hb_ot_layout_table_select_script (face, table_tag, t - script_tags, script_tags, script_index, chosen_script);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* hb_ot_layout_table_select_script:
|
||||
@ -672,6 +684,7 @@ hb_ot_layout_script_get_language_tags (hb_face_t *face,
|
||||
}
|
||||
|
||||
|
||||
#ifndef HB_DISABLE_DEPRECATED
|
||||
/**
|
||||
* hb_ot_layout_script_find_language:
|
||||
* @face: #hb_face_t to work upon
|
||||
@ -685,6 +698,8 @@ hb_ot_layout_script_get_language_tags (hb_face_t *face,
|
||||
*
|
||||
* Return value: true if the language tag is found, false otherwise
|
||||
*
|
||||
* Since: ??
|
||||
* Deprecated: ??
|
||||
**/
|
||||
hb_bool_t
|
||||
hb_ot_layout_script_find_language (hb_face_t *face,
|
||||
@ -700,6 +715,7 @@ hb_ot_layout_script_find_language (hb_face_t *face,
|
||||
&language_tag,
|
||||
language_index);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
@ -716,7 +732,6 @@ hb_ot_layout_script_find_language (hb_face_t *face,
|
||||
*
|
||||
* Return value: true if the language tag is found, false otherwise
|
||||
*
|
||||
*
|
||||
* Since: 2.0.0
|
||||
**/
|
||||
hb_bool_t
|
||||
@ -1735,7 +1750,7 @@ hb_ot_layout_feature_get_characters (hb_face_t *face,
|
||||
unsigned int len = 0;
|
||||
if (char_count && characters && start_offset < cv_params.characters.len)
|
||||
{
|
||||
len = MIN (cv_params.characters.len - start_offset, *char_count);
|
||||
len = hb_min (cv_params.characters.len - start_offset, *char_count);
|
||||
for (unsigned int i = 0; i < len; ++i)
|
||||
characters[i] = cv_params.characters[start_offset + i];
|
||||
}
|
||||
|
@ -94,7 +94,7 @@ HB_EXTERN hb_bool_t
|
||||
hb_ot_layout_has_glyph_classes (hb_face_t *face);
|
||||
|
||||
/**
|
||||
* hb_ot_layout_get_glyph_class:
|
||||
* hb_ot_layout_glyph_class_t:
|
||||
* @HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED: Glyphs not matching the other classifications
|
||||
* @HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH: Spacing, single characters, capable of accepting marks
|
||||
* @HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE: Glyphs that represent ligation of multiple characters
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user