Merge branch 'var-subset' of https://github.com/harfbuzz/harfbuzz into var-subset

This commit is contained in:
Michiharu Ariza 2019-07-09 10:25:54 -07:00
commit a87fbb872b
392 changed files with 16771 additions and 13073 deletions

View File

@ -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
@ -45,7 +45,7 @@ jobs:
- run: rm -rf harfbuzz-*
- run: make distdir && cd harfbuzz-* && cmake -DHB_CHECK=ON -Bbuild -H. -GNinja && ninja -Cbuild && CTEST_OUTPUT_ON_FAILURE=1 ninja -Cbuild test && ninja -Cbuild install
alpine-O3-NOMMAP:
alpine-O3-Os-NOMMAP:
docker:
- image: alpine
steps:
@ -55,6 +55,10 @@ jobs:
- run: CFLAGS="-O3" CXXFLAGS="-O3 -DHB_NO_MMAP" ./autogen.sh
- run: make -j32
- run: make check || .ci/fail.sh
- run: make clean
- run: CFLAGS="-Os -DHB_OPTIMIZE_SIZE" CXXFLAGS="-Os -DHB_NO_MMAP -DHB_OPTIMIZE_SIZE" ./autogen.sh
- run: make -j32
- run: make check || .ci/fail.sh
archlinux-py3-all:
docker:
@ -78,7 +82,7 @@ jobs:
# - run: xbps-install -Suy freetype gettext gcc glib graphite pkg-config ragel libtool autoconf automake make
# - run: ./autogen.sh && make -j32 && make check
clang-O3-O0:
clang-O3-O0-and-nobuildsystem:
docker:
- image: ubuntu:18.10
steps:
@ -93,6 +97,7 @@ jobs:
- run: CFLAGS="-O0" CXXFLAGS="-O0" CC=clang CXX=clang++ ./autogen.sh --with-freetype --with-fontconfig --with-glib --with-cairo --with-icu --with-graphite2
- run: make -j32
- run: LD_LIBRARY_PATH="$PWD/freetype-2.9/objs/.libs" make check || .ci/fail.sh
- run: make clean && cd src && clang++ -c hb-*.cc
gcc-valgrind:
docker:
@ -192,18 +197,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 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 +227,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:
@ -250,15 +264,15 @@ jobs:
- image: dockcross/android-arm
steps:
- checkout
- run: cmake -Bbuild -H. -GNinja
- run: cmake -Bbuild -H. -GNinja -DHB_BUILD_TESTS=OFF
- 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" -DHB_BUILD_TESTS=OFF
- run: ninja -Cbuild
crosscompile-cmake-notest-linux-arm64:
@ -266,7 +280,7 @@ jobs:
- image: dockcross/linux-arm64
steps:
- checkout
- run: cmake -Bbuild -H. -GNinja
- run: cmake -Bbuild -H. -GNinja -DHB_BUILD_TESTS=OFF
- run: ninja -Cbuild
crosscompile-cmake-notest-linux-mips:
@ -274,7 +288,7 @@ jobs:
- image: dockcross/linux-mips
steps:
- checkout
- run: cmake -Bbuild -H. -GNinja
- run: cmake -Bbuild -H. -GNinja -DHB_BUILD_TESTS=OFF
- run: ninja -Cbuild
#crosscompile-cmake-notest-windows-x64:
@ -298,17 +312,17 @@ workflows:
- distcheck
# autotools based builds
- alpine-O3-NOMMAP
- alpine-O3-Os-NOMMAP
- archlinux-py3-all
#- void-notest
- gcc-valgrind
- clang-O3-O0
- clang-O3-O0-and-nobuildsystem
- clang-everything
- clang-asan
- clang-msan
- clang-tsan
- clang-ubsan
- fedora-O0-debug-outoftreebuild
- fedora-O0-debug-outoftreebuild-mingw
# cmake based builds
- cmake-gcc
@ -322,7 +336,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
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
*.plist

View File

@ -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)
@ -90,8 +88,6 @@ include_directories(AFTER
${PROJECT_BINARY_DIR}/src
)
add_definitions(-DHAVE_FALLBACK)
# We need PYTHON_EXECUTABLE to be set for running the tests...
include (FindPythonInterp)
@ -110,7 +106,7 @@ endmacro ()
if (UNIX)
list(APPEND CMAKE_REQUIRED_LIBRARIES m)
endif ()
check_funcs(atexit mprotect sysconf getpagesize mmap isatty newlocale strtod_l round)
check_funcs(atexit mprotect sysconf getpagesize mmap isatty newlocale strtod_l)
check_include_file(unistd.h HAVE_UNISTD_H)
if (${HAVE_UNISTD_H})
add_definitions(-DHAVE_UNISTD_H)
@ -160,14 +156,9 @@ 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/")
extract_make_variable(HB_BASE_headers ${SRCSOURCES})
add_prefix_to_list(HB_BASE_headers "${PROJECT_SOURCE_DIR}/src/")
extract_make_variable(HB_FALLBACK_sources ${SRCSOURCES})
add_prefix_to_list(HB_FALLBACK_sources "${PROJECT_SOURCE_DIR}/src/")
extract_make_variable(HB_SUBSET_sources ${SRCSOURCES})
add_prefix_to_list(HB_SUBSET_sources "${PROJECT_SOURCE_DIR}/src/")
@ -191,9 +182,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})
@ -202,61 +190,12 @@ set (HB_VERSION_MAJOR ${CMAKE_MATCH_2})
set (HB_VERSION_MINOR ${CMAKE_MATCH_3})
set (HB_VERSION_MICRO ${CMAKE_MATCH_4})
## Define ragel tasks
# if (NOT IN_HB_DIST)
# foreach (ragel_output IN ITEMS ${HB_BASE_RAGEL_GENERATED_sources})
# string(REGEX MATCH "([^/]+)\\.hh" temp ${ragel_output})
# set (target_name ${CMAKE_MATCH_1})
# add_custom_command(OUTPUT ${ragel_output}
# COMMAND ${RAGEL} -G2 -o ${ragel_output} ${PROJECT_SOURCE_DIR}/src/${target_name}.rl -I ${PROJECT_SOURCE_DIR} ${ARGN}
# DEPENDS ${PROJECT_SOURCE_DIR}/src/${target_name}.rl
# )
# add_custom_target(harfbuzz_${target_name} DEPENDS ${PROJECT_BINARY_DIR}/src/${target_name})
# endforeach ()
# mark_as_advanced(RAGEL)
# endif ()
## Generate hb-version.h
# if (NOT IN_HB_DIST)
# set (HB_VERSION_H_IN "${PROJECT_SOURCE_DIR}/src/hb-version.h.in")
# set (HB_VERSION_H "${PROJECT_BINARY_DIR}/src/hb-version.h")
# set_source_files_properties("${HB_VERSION_H}" PROPERTIES GENERATED true)
# configure_file("${HB_VERSION_H_IN}" "${HB_VERSION_H}.tmp" @ONLY)
# execute_process(COMMAND "${CMAKE_COMMAND}" -E copy_if_different
# "${HB_VERSION_H}.tmp"
# "${HB_VERSION_H}"
# )
# file(REMOVE "${HB_VERSION_H}.tmp")
# endif ()
## Define sources and headers of the project
set (project_sources
${HB_BASE_sources}
${HB_BASE_RAGEL_GENERATED_sources}
${HB_FALLBACK_sources}
)
set (subset_project_sources
${HB_SUBSET_sources}
)
set (project_sources ${PROJECT_SOURCE_DIR}/src/harfbuzz.cc) # use amalgam source
set (subset_project_sources ${HB_SUBSET_sources})
set (project_extra_sources)
set (project_headers
#${HB_VERSION_H}
${HB_BASE_headers}
)
set (subset_project_headers
${HB_SUBSET_headers}
)
set (project_headers ${HB_BASE_headers})
set (subset_project_headers ${HB_SUBSET_headers})
## Find and include needed header folders and libraries
if (HB_HAVE_FREETYPE)
@ -269,7 +208,6 @@ if (HB_HAVE_FREETYPE)
include_directories(AFTER ${FREETYPE_INCLUDE_DIRS})
add_definitions(-DHAVE_FREETYPE=1)
list(APPEND project_sources ${PROJECT_SOURCE_DIR}/src/hb-ft.cc)
list(APPEND project_headers ${PROJECT_SOURCE_DIR}/src/hb-ft.h)
# So check_funcs can find its headers
@ -287,7 +225,6 @@ if (HB_HAVE_GRAPHITE2)
include_directories(${GRAPHITE2_INCLUDE_DIR})
list(APPEND project_sources ${PROJECT_SOURCE_DIR}/src/hb-graphite2.cc)
list(APPEND project_headers ${PROJECT_SOURCE_DIR}/src/hb-graphite2.h)
list(APPEND THIRD_PARTY_LIBS ${GRAPHITE2_LIBRARY})
@ -295,14 +232,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)
@ -316,7 +245,6 @@ if (HB_HAVE_GLIB)
include_directories(${GLIBCONFIG_INCLUDE_DIR} ${GLIB_INCLUDE_DIR})
list(APPEND project_sources ${PROJECT_SOURCE_DIR}/src/hb-glib.cc)
list(APPEND project_headers ${PROJECT_SOURCE_DIR}/src/hb-glib.h)
list(APPEND THIRD_PARTY_LIBS ${GLIB_LIBRARIES})
@ -336,7 +264,6 @@ if (HB_HAVE_ICU)
include_directories(${ICU_INCLUDE_DIR})
list(APPEND project_sources ${PROJECT_SOURCE_DIR}/src/hb-icu.cc)
list(APPEND project_headers ${PROJECT_SOURCE_DIR}/src/hb-icu.h)
list(APPEND THIRD_PARTY_LIBS ${ICU_LIBRARY})
@ -348,7 +275,6 @@ if (APPLE AND HB_HAVE_CORETEXT)
# Apple Advanced Typography
add_definitions(-DHAVE_CORETEXT)
list(APPEND project_sources ${PROJECT_SOURCE_DIR}/src/hb-coretext.cc)
list(APPEND project_headers ${PROJECT_SOURCE_DIR}/src/hb-coretext.h)
if (HB_IOS)
@ -381,19 +307,13 @@ endif ()
if (WIN32 AND HB_HAVE_UNISCRIBE)
add_definitions(-DHAVE_UNISCRIBE)
list(APPEND project_sources ${PROJECT_SOURCE_DIR}/src/hb-uniscribe.cc)
list(APPEND project_headers ${PROJECT_SOURCE_DIR}/src/hb-uniscribe.h)
list(APPEND THIRD_PARTY_LIBS usp10 gdi32 rpcrt4)
endif ()
if (WIN32 AND HB_HAVE_DIRECTWRITE)
add_definitions(-DHAVE_DIRECTWRITE)
list(APPEND project_sources ${PROJECT_SOURCE_DIR}/src/hb-directwrite.cc)
list(APPEND project_headers ${PROJECT_SOURCE_DIR}/src/hb-directwrite.h)
list(APPEND THIRD_PARTY_LIBS dwrite rpcrt4)
endif ()
@ -501,7 +421,6 @@ if (HB_HAVE_GOBJECT)
)
endif ()
## Atomic ops availability detection
file(WRITE "${PROJECT_BINARY_DIR}/try_compile_intel_atomic_primitives.c"
" void memory_barrier (void) { __sync_synchronize (); }
@ -610,7 +529,6 @@ if (WIN32)
endif ()
if (HB_HAVE_INTROSPECTION)
find_package(PkgConfig)
pkg_check_modules(PC_GI QUIET gobject-introspection-1.0)
@ -844,7 +762,7 @@ endif ()
if (HB_BUILD_TESTS)
## src/ executables
foreach (prog main test test-gsub-would-substitute test-gpos-size-params test-buffer-serialize hb-ot-tag test-unicode-ranges)
foreach (prog main test test-gsub-would-substitute test-gpos-size-params test-buffer-serialize test-unicode-ranges) # hb-ot-tag
set (prog_name ${prog})
if (${prog_name} STREQUAL "test")
# test can not be used as a valid executable name on cmake, lets special case it
@ -853,7 +771,7 @@ if (HB_BUILD_TESTS)
add_executable(${prog_name} ${PROJECT_SOURCE_DIR}/src/${prog}.cc)
target_link_libraries(${prog_name} harfbuzz ${THIRD_PARTY_LIBS})
endforeach ()
set_target_properties(hb-ot-tag PROPERTIES COMPILE_FLAGS "-DMAIN")
# set_target_properties(hb-ot-tag PROPERTIES COMPILE_FLAGS "-DMAIN")
## Tests
if (UNIX OR MINGW)

151
CONFIG.md Normal file
View File

@ -0,0 +1,151 @@
# Configuring HarfBuzz
Most of the time you will not need any custom configuration. The configuration
options provided by `configure` or `cmake` should be enough. In particular,
if you just want HarfBuzz library plus hb-shape / hb-view utilities, make sure
FreeType and Cairo are available and found during configuration.
If you are building for distribution, you should more carefully consider whether
you need Glib, ICU, Graphite2, as well as CoreText / Uniscribe / DWrite. Make
sure the relevant ones are enabled.
If you are building for custom environment (embedded, downloadable app, etc)
where you mostly just want to call `hb_shape()` and the binary size of the
resulting library is very important to you, the rest of this file guides you
through your options to disable features you may not need, in exchange for
binary size savings.
## Compiler Options
Make sure you build with your compiler's "optimize for size" option. On `gcc`
this is `-Os`, and can be enabled by passing `CXXFLAGS=-Os` either to `configure`
(sticky) or to `make` (non-sticky). On clang there is an even more extreme flag,
`-Oz`.
HarfBuzz heavily uses inline functions and the optimize-size flag can make the
library smaller by 20% or more. Moreover, sometimes, based on the target CPU,
the optimize-size builds perform *faster* as well, thanks to lower code
footprint and caching effects. So, definitely try that even if size is not
extremely tight but you have a huge application. For example, Chrome does
that. Note that this configuration also automatically enables certain internal
optimizations. Search for `HB_OPTIMIZE_SIZE` for details, if you are using
other compilers, or continue reading.
Another compiler option to consider is "link-time optimization", also known as
'lto'. To enable that, with `gcc` or `clang`, add `-flto` to both `CXXFLAGS`
and `LDFLAGS`, either on `configure` invocation (sticky) or on `make` (non-sticky).
This, also, can have a huge impact on the final size, 20% or more.
Finally, if you are making a static library build or otherwise linking the
library into your app, make sure your linker removes unused functions. This
can be tricky and differ from environment to environment, but you definitely
want to make sure this happens. Otherwise, every unused public function will
be adding unneeded bytes to your binary. The following pointers might come
handy:
* https://lwn.net/Articles/741494/ (all of the four-part series)
* https://elinux.org/images/2/2d/ELC2010-gc-sections_Denys_Vlasenko.pdf
Combining the above three build options should already shrink your library a lot.
The rest of this file shows you ways to shrink the library even further at the
expense of removing functionality (that may not be needed). The remaining
options are all enabled by defining pre-processor macros, which can be done
via `CXXFLAGS` or `CPPFLAGS` similarly.
## Unicode-functions
Access to Unicode data can be configured at compile time as well as run-time.
By default, HarfBuzz ships with its own compact subset of properties from
Unicode Character Database that it needs. This is a highly-optimized
implementation that depending on compile settings (optimize-size or not)
takes around ~40kb or ~60kb. Using this implementation (default) is highly
recommended, as HarfBuzz always ships with data from latest version of Unicode.
This implementation can be disabled by defining `HB_NO_UCD`.
For example, if you are enabling ICU as a built-in option, or GLib, those
can provide Unicode data as well, so defining `HB_NO_UCD` might save you
space without reducing functionality (to the extent that the Unicode version
of those implementations is recent.)
If, however, you provide your own Unicode data to HarfBuzz at run-time by
calling `hb_buffer_set_unicode_funcs` on every buffer you create, and you do
not rely on `hb_unicode_funcs_get_default()` results, you can disable the
internal implementation by defining both `HB_NO_UCD` and `HB_NO_UNICODE_FUNCS`.
The latter is needed to guard against accidentally building a library without
any default Unicode implementations.
## Font-functions
Access to certain font functionalities can also be configured at run-time. By
default, HarfBuzz uses an efficient internal implementation of OpenType
functionality for this. This internal implementation is called `hb-ot-font`.
All newly-created `hb_font_t` objects by default use `hb-ot-font`. Using this
is highly recommended, and is what fonts use by default when they are created.
Most embedded uses will probably use HarfBuzz with FreeType using `hb-ft.h`.
In that case, or if you otherwise provide those functions by calling
`hb_font_set_funcs()` on every font you create, you can disable `hb-ot-font`
without loss of functionality by defining `HB_NO_OT_FONT`.
## Shapers
Most HarfBuzz clients use it for the main shaper, called "ot". However, it
is legitimate to want to compile HarfBuzz with only another backend, eg.
CoreText, for example for an iOS app. For that, you want `HB_NO_OT_SHAPE`.
If you are going down that route, check if you want `HB_NO_OT`.
This is very rarely what you need. Make sure you understand exactly what you
are doing.
Defining `HB_NO_FALLBACK_SHAPE` however is pretty harmless. That removes the
(unused) "fallback" shaper.
## Thread-safety
By default HarfBuzz builds as a thread-safe library. The exception is that
the `HB_TINY` predefined configuring (more below) disables thread-safety.
If you do /not/ need thread-safety in the library (eg. you always call into
HarfBuzz from the same thread), you can disable thread-safety by defining
`HB_NO_MT`. As noted already, this is enabled by `HB_TINY`.
## Pre-defined configurations
The [`hb-config.hh`](src/hb-config.hh) internal header supports three
pre-defined configurations as well grouping of various configuration options.
The pre-defined configurations are:
* `HB_MINI`: Disables shaping of AAT as well as legacy fonts. Ie. it produces
a capable OpenType shaper only.
* `HB_LEAN`: Disables various non-shaping functionality in the library, as well
as esoteric or rarely-used shaping features. See the definition for details.
* `HB_TINY`: Enables both `HB_MINI` and `HB_LEAN` configurations, as well as
disabling thread-safety and debugging, and use even more size-optimized data
tables.
## Tailoring configuration
Most of the time, one of the pre-defined configuration is exactly what one needs.
Sometimes, however, the pre-defined configuration cuts out features that might
be desired in the library. Unfortunately there is no quick way to undo those
configurations from the command-line. But one can add a header file called
`config-override.h` to undefine certain `HB_NO_*` symbols as desired. Then
define `HAVE_CONFIG_OVERRIDE_H` to make `hb-config.hh` include your configuration
overrides at the end.
## Notes
Note that the config option `HB_NO_CFF`, which is enabled by `HB_LEAN` and
`HB_TINY` does /not/ mean that the resulting library won't work with CFF fonts.
The library can shape valid CFF fonts just fine, with or without this option.
This option disables (among other things) the code to calculate glyph exntents
for CFF fonts.

View File

@ -9,12 +9,19 @@ SUBDIRS = src util test docs
EXTRA_DIST = \
autogen.sh \
harfbuzz.doap \
README.md \
README.mingw.md \
README.python.md \
README.wine.md \
BUILD.md \
CONFIG.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 +67,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 +75,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 +86,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

44
NEWS
View File

@ -1,3 +1,47 @@
Overview of changes leading to 2.5.3
Wednesday, June 26, 2019
====================================
- Fix UCD script data for Unicode 10+ scripts. This was broken since 2.5.0.
- More optimizations for HB_TINY.
Overview of changes leading to 2.5.2
Thursday, June 20, 2019
====================================
- More hb-config.hh facilities to shrink library size, namely when built as
HB_TINY.
- New documentation of custom configurations in CONFIG.md.
- Fix build on gcc 4.8. That's supported again.
- Universal Shaping Engine improvements thanks to David Corbett.
- API Changes: Undeprecate some horizontal-kerning API and re-enable in hb-ft,
such that Type1 fonts will continue kerning.
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
====================================

View File

@ -13,6 +13,12 @@ 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 custom configurations, see [CONFIG.md](CONFIG.md).
For test execution, see [TESTING.md](TESTING.md).
Documentation: https://harfbuzz.github.io

48
README.mingw.md Normal file
View 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.

View File

@ -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)

View File

@ -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
View 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
```

View File

@ -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

View File

@ -1,6 +1,6 @@
AC_PREREQ([2.64])
AC_INIT([HarfBuzz],
[2.4.0],
[2.5.3],
[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
@ -77,13 +77,7 @@ GTK_DOC_CHECK([1.15],[--flavour no-tmpl])
])
# Functions and headers
AC_CHECK_FUNCS(atexit mprotect sysconf getpagesize mmap isatty newlocale strtod_l posix_memalign)
save_libs="$LIBS"
LIBS="$LIBS -lm"
AC_CHECK_FUNCS([round], ,[AC_CHECK_DECLS([round], , ,[#include <math.h>])])
LIBS="$save_libs"
AC_CHECK_FUNCS(atexit mprotect sysconf getpagesize mmap isatty newlocale strtod_l)
AC_CHECK_HEADERS(unistd.h sys/mman.h xlocale.h stdbool.h)
# Compiler flags
@ -134,9 +128,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
@ -144,14 +136,6 @@ AM_CONDITIONAL(HAVE_PTHREAD, $have_pthread)
dnl ==========================================================================
have_fallback=true
if $have_fallback; then
AC_DEFINE(HAVE_FALLBACK, 1, [Have simple TrueType Layout backend])
fi
AM_CONDITIONAL(HAVE_FALLBACK, $have_fallback)
dnl ===========================================================================
AC_ARG_WITH(glib,
[AS_HELP_STRING([--with-glib=@<:@yes/no/auto@:>@],
[Use glib @<:@default=auto@:>@])],,
@ -300,21 +284,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@:>@])],,
@ -407,7 +376,7 @@ if test "x$with_directwrite" = "xyes" -a "x$have_directwrite" != "xtrue"; then
fi
if $have_directwrite; then
DIRECTWRITE_CXXFLAGS=
DIRECTWRITE_LIBS="-ldwrite"
DIRECTWRITE_LIBS=
AC_SUBST(DIRECTWRITE_CXXFLAGS)
AC_SUBST(DIRECTWRITE_LIBS)
AC_DEFINE(HAVE_DIRECTWRITE, 1, [Have DirectWrite library])
@ -497,7 +466,6 @@ AC_CONFIG_FILES([
Makefile
src/Makefile
src/harfbuzz-config.cmake
src/hb-ucdn/Makefile
util/Makefile
test/Makefile
test/api/Makefile
@ -525,7 +493,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}

View File

@ -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

View File

@ -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>

View File

@ -195,12 +195,7 @@ HB_UNICODE_MAX_DECOMPOSITION_LEN
hb_unicode_decompose_compatibility_func_t
hb_unicode_decompose_compatibility
hb_unicode_funcs_set_decompose_compatibility_func
hb_font_funcs_set_glyph_h_kerning_func
hb_font_funcs_set_glyph_v_kerning_func
hb_font_get_glyph_h_kerning
hb_font_get_glyph_h_kerning_func_t
hb_font_get_glyph_kerning_for_direction
hb_font_get_glyph_kerning_func_t
hb_font_get_glyph_v_kerning
hb_font_get_glyph_v_kerning_func_t
</SECTION>
@ -271,6 +266,7 @@ hb_font_funcs_set_glyph_extents_func
hb_font_funcs_set_glyph_from_name_func
hb_font_funcs_set_glyph_h_advance_func
hb_font_funcs_set_glyph_h_advances_func
hb_font_funcs_set_glyph_h_kerning_func
hb_font_funcs_set_glyph_h_origin_func
hb_font_funcs_set_glyph_name_func
hb_font_funcs_set_glyph_v_advance_func
@ -300,8 +296,12 @@ hb_font_get_glyph_h_advance
hb_font_get_glyph_h_advance_func_t
hb_font_get_glyph_h_advances
hb_font_get_glyph_h_advances_func_t
hb_font_get_glyph_h_kerning
hb_font_get_glyph_h_kerning_func_t
hb_font_get_glyph_h_origin
hb_font_get_glyph_h_origin_func_t
hb_font_get_glyph_kerning_for_direction
hb_font_get_glyph_kerning_func_t
hb_font_get_glyph_name
hb_font_get_glyph_name_func_t
hb_font_get_glyph_origin_for_direction

View File

@ -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_t *buf = hb_buffer_create();
...
hb_buffer_destroy(buffer);
</programlisting>
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);
void somefunc(hb_buffer_t *buf) {
buf = hb_buffer_reference(buf);
...
</programlisting>
</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> "&#xFFFD;". 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>, "&#x25CC;"), 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>

View File

@ -156,18 +156,20 @@
order.
</para>
<para>
For left-to-right scripts (LTR) and top-to-bottom scripts (TTB),
For buffers in the left-to-right (LTR)
or top-to-bottom (TTB) text flow direction,
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>
<para>
For right-to-left scripts (RTL) and bottom-to-top scripts (BTT),
For buffers in the right-to-left (RTL)
or bottom-to-top (BTT) text flow direction,
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>

View File

@ -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_ptem(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>

View File

@ -330,24 +330,6 @@
</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>

View 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 its 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, its 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 doesnt 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>

View File

@ -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, &amp;glyph_count);
hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions(buf, &amp;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>

View 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
View 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
View 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)

View File

@ -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 "$@"

View File

@ -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 "$@"

View File

@ -12,9 +12,15 @@ DISTCHECK_CONFIGURE_FLAGS = --enable-introspection
TESTS =
check_PROGRAMS =
EXTRA_DIST += harfbuzz.cc
# Convenience targets:
lib: $(BUILT_SOURCES) libharfbuzz.la
libs: $(BUILT_SOURCES) $(lib_LTLIBRARIES)
tiny:
$(MAKE) $(AM_MAKEFLAGS) CPPFLAGS="-Os -DHB_TINY $(CPPFLAGS)" libs
tinyz:
$(MAKE) $(AM_MAKEFLAGS) CPPFLAGS="-Oz -DHB_TINY $(CPPFLAGS)" libs
lib_LTLIBRARIES = libharfbuzz.la
@ -28,10 +34,6 @@ HBSOURCES = $(HB_BASE_sources)
HBSOURCES += $(HB_BASE_RAGEL_GENERATED_sources)
HBHEADERS = $(HB_BASE_headers)
if HAVE_FALLBACK
HBSOURCES += $(HB_FALLBACK_sources)
endif
if HAVE_PTHREAD
HBCFLAGS += $(PTHREAD_CFLAGS)
HBNONPCLIBS += $(PTHREAD_LIBS)
@ -87,17 +89,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,36 +249,44 @@ 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)
EXTRA_DIST += $(GENERATORS)
unicode-tables: arabic-table indic-table tag-table use-table emoji-table
unicode-tables: \
arabic-table \
emoji-table \
indic-table \
tag-table \
ucd-table \
use-table \
emoji-table \
$(NULL)
arabic-table: gen-arabic-table.py ArabicShaping.txt UnicodeData.txt Blocks.txt
$(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-ot-shape-complex-arabic-table.hh \
|| ($(RM) $(srcdir)/hb-ot-shape-complex-arabic-table.hh; false)
emoji-table: gen-emoji-table.py emoji-data.txt
$(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-unicode-emoji-table.hh \
|| ($(RM) $(srcdir)/hb-unicode-emoji-table.hh; false)
indic-table: gen-indic-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt Blocks.txt
$(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-ot-shape-complex-indic-table.cc \
|| ($(RM) $(srcdir)/hb-ot-shape-complex-indic-table.cc; false)
tag-table: gen-tag-table.py languagetags language-subtag-registry
$(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-ot-tag-table.hh \
|| ($(RM) $(srcdir)/hb-ot-tag-table.hh; false)
ucd-table: gen-ucd-table.py ucd.nounihan.grouped.zip hb-common.h
$(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-ucd-table.hh \
|| ($(RM) $(srcdir)/hb-ucd-table.hh; false)
use-table: gen-use-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt UnicodeData.txt Blocks.txt
$(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-ot-shape-complex-use-table.cc \
|| ($(RM) $(srcdir)/hb-ot-shape-complex-use-table.cc; false)
vowel-constraints: gen-vowel-constraints.py HBIndicVowelConstraints.txt Scripts.txt
$(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-ot-shape-complex-vowel-constraints.cc \
|| ($(RM) $(srcdir)/hb-ot-shape-complex-vowel-constraints.cc; false)
emoji-table: gen-emoji-table.py emoji-data.txt
$(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-unicode-emoji-table.hh \
|| ($(RM) $(srcdir)/hb-unicode-emoji-table.hh; false)
built-sources: $(BUILT_SOURCES)
@ -306,6 +305,21 @@ $(srcdir)/%.hh: $(srcdir)/%.rl
$(AM_V_GEN)(cd $(srcdir) && $(RAGEL) -e -F1 -o "$*.hh" "$*.rl") \
|| ($(RM) "$@"; false)
harfbuzz.cc: Makefile.sources
$(AM_V_GEN) \
for f in \
$(HB_BASE_sources) \
$(HB_GLIB_sources) \
$(HB_FT_sources) \
$(HB_GRAPHITE2_sources) \
$(HB_UNISCRIBE_sources) \
$(HB_DIRECTWRITE_sources) \
$(HB_CORETEXT_sources) \
; do echo '#include "'$$f'"'; done | \
grep '[.]cc"' > $(srcdir)/harfbuzz.cc \
|| ($(RM) $(srcdir)/harfbuzz.cc; false)
BUILT_SOURCES += harfbuzz.cc
noinst_PROGRAMS = \
main \
test \
@ -384,7 +398,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 test-bimap
COMPILED_TESTS_CPPFLAGS = $(HBCFLAGS) -DMAIN -UNDEBUG
COMPILED_TESTS_LDADD = libharfbuzz.la $(HBLIBS)
check_PROGRAMS += $(COMPILED_TESTS)
@ -398,6 +412,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)
@ -406,6 +424,10 @@ test_unicode_ranges_SOURCES = test-unicode-ranges.cc
test_unicode_ranges_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
test_unicode_ranges_LDADD = $(COMPILED_TESTS_LDADD)
test_bimap_SOURCES = test-bimap.cc hb-static.cc
test_bimap_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
test_bimap_LDADD = $(COMPILED_TESTS_LDADD)
TESTS_ENVIRONMENT = \
srcdir="$(srcdir)" \
MAKE="$(MAKE) $(AM_MAKEFLAGS)" \
@ -434,6 +456,7 @@ HarfBuzz_0_0_gir_CFLAGS = \
-DHB_AAT_H_IN \
-DHB_GOBJECT_H \
-DHB_GOBJECT_H_IN \
-DHAVE_GOBJECT \
-DHB_EXTERN= \
$(NULL)
HarfBuzz_0_0_gir_LIBS = \

View File

@ -31,10 +31,12 @@ 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 \
hb-face.hh \
hb-fallback-shape.cc \
hb-font.cc \
hb-font.hh \
hb-iter.hh \
@ -63,6 +65,7 @@ HB_BASE_sources = \
hb-ot-color.cc \
hb-ot-face.cc \
hb-ot-face.hh \
hb-ot-face-table-list.hh \
hb-ot-font.cc \
hb-ot-gasp-table.hh \
hb-ot-glyf-table.hh \
@ -147,6 +150,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 \
@ -200,10 +205,6 @@ HB_BASE_headers = \
hb.h \
$(NULL)
HB_FALLBACK_sources = \
hb-fallback-shape.cc \
$(NULL)
# Optional Sources and Headers with external deps
HB_FT_sources = hb-ft.cc
@ -226,9 +227,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 +242,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 \

View File

@ -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
:

View File

@ -4,6 +4,7 @@ from __future__ import print_function, division, absolute_import
import sys
import os.path
from collections import OrderedDict
import packTab
if len (sys.argv) != 2:
print("usage: ./gen-emoji-table.py emoji-data.txt", file=sys.stderr)
@ -52,14 +53,19 @@ print ()
print ('#include "hb-unicode.hh"')
print ()
for typ,s in ranges.items():
for typ, s in ranges.items():
if typ != "Extended_Pictographic": continue
arr = dict()
for start,end in s:
for i in range(start,end):
arr[i] = 1
sol = packTab.pack_table(arr, 0, compression=3)
code = packTab.Code('_hb_emoji')
sol.genCode(code, 'is_'+typ)
code.print_c(linkage='static inline')
print()
print("static const struct hb_unicode_range_t _hb_unicode_emoji_%s_table[] =" % typ)
print("{")
for pair in sorted(s):
print(" {0x%04X, 0x%04X}," % pair)
print("};")
print ()
print ("#endif /* HB_UNICODE_EMOJI_TABLE_HH */")

View File

@ -98,6 +98,10 @@ for h in headers:
print (" * %s" % (l.strip()))
print (" */")
print ()
print ('#include "hb.hh"')
print ()
print ('#ifndef HB_NO_OT_SHAPE')
print ()
print ('#include "hb-ot-shape-complex-indic.hh"')
print ()
@ -251,6 +255,8 @@ for i in range (2):
print ("#undef %s_%s" %
(what_short[i], short[i][v]))
print ()
print ()
print ('#endif')
print ("/* == End of generated table == */")
# Maintain at least 30% occupancy in the table */

4
src/gen-os2-unicode-ranges.py Normal file → Executable file
View 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

164
src/gen-ucd-table.py Executable file
View File

@ -0,0 +1,164 @@
#!/usr/bin/env python
from __future__ import print_function, division, absolute_import
import io, os.path, sys, re
import logging
logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.INFO)
if len (sys.argv) not in (2, 3):
print("usage: ./gen-ucd-table ucd.nounihan.grouped.xml [/path/to/hb-common.h]", file=sys.stderr)
sys.exit(1)
# https://github.com/harfbuzz/packtab
import packTab
import packTab.ucdxml
logging.info('Loading UCDXML...')
ucdxml = packTab.ucdxml.load_ucdxml(sys.argv[1])
ucd = packTab.ucdxml.ucdxml_get_repertoire(ucdxml)
hb_common_h = 'hb-common.h' if len (sys.argv) < 3 else sys.argv[2]
logging.info('Preparing data tables...')
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))
assert all((v[0] >> 16) in (0,2) for v in dm1)
dm1_p0_array = ['0x%04Xu' % (v[0] & 0xFFFF) for v in dm1 if (v[0] >> 16) == 0]
dm1_p2_array = ['0x%04Xu' % (v[0] & 0xFFFF) for v in dm1 if (v[0] >> 16) == 2]
dm1_order = {v:i+1 for i,v in enumerate(dm1)}
dm2 = sorted((v+(i if i not in ce and not ccc[i] else 0,), v)
for i,v in dm.items() if len(v) == 2)
filt = lambda v: ((v[0] & 0xFFFFF800) == 0x0000 and
(v[1] & 0xFFFFFF80) == 0x0300 and
(v[2] & 0xFFF0C000) == 0x0000)
dm2_u32_array = [v for v in dm2 if filt(v[0])]
dm2_u64_array = [v for v in dm2 if not filt(v[0])]
assert dm2_u32_array + dm2_u64_array == dm2
dm2_u32_array = ["HB_CODEPOINT_ENCODE3_11_7_14 (0x%04Xu, 0x%04Xu, 0x%04Xu)" % v[0] for v in dm2_u32_array]
dm2_u64_array = ["HB_CODEPOINT_ENCODE3 (0x%04Xu, 0x%04Xu, 0x%04Xu)" % v[0] for v in dm2_u64_array]
l = 1 + len(dm1_p0_array) + len(dm1_p2_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 = dict()
for i,v in enumerate(('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[i] = v
gc_order[v] = i
sc_order = dict()
sc_array = []
sc_re = re.compile(r"\b(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 = len(sc_array)
sc_order[tag] = i
sc_order[i] = tag
sc_array.append(name)
DEFAULT = 1
COMPACT = 3
SLOPPY = 5
logging.info('Generating output...')
print("/* == Start of generated table == */")
print("/*")
print(" * The following table is generated by running:")
print(" *")
print(" * ./gen-ucd-table.py ucd.nounihan.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('#include "hb.hh"')
print()
code = packTab.Code('_hb_ucd')
sc_array, _ = code.addArray('hb_script_t', 'sc_map', sc_array)
dm1_p0_array, _ = code.addArray('uint16_t', 'dm1_p0_map', dm1_p0_array)
dm1_p2_array, _ = code.addArray('uint16_t', 'dm1_p2_map', dm1_p2_array)
dm2_u32_array, _ = code.addArray('uint32_t', 'dm2_u32_map', dm2_u32_array)
dm2_u64_array, _ = code.addArray('uint64_t', 'dm2_u64_map', dm2_u64_array)
code.print_c(linkage='static inline')
datasets = [
('gc', gc, 'Cn', gc_order),
('ccc', ccc, 0, None),
('bmg', bmg, 0, None),
('sc', sc, 'Zzzz', sc_order),
('dm', dm, None, dm_order),
]
for compression in (DEFAULT, COMPACT, SLOPPY):
logging.info(' Compression=%d:' % compression)
print()
if compression == DEFAULT:
print('#ifndef HB_OPTIMIZE_SIZE')
elif compression == COMPACT:
print('#elif !defined(HB_NO_UCD_UNASSIGNED)')
else:
print('#else')
print()
if compression == SLOPPY:
for i in range(len(gc)):
if (i % 128) and gc[i] == 'Cn':
gc[i] = gc[i - 1]
for i in range(len(gc) - 2, -1, -1):
if ((i + 1) % 128) and gc[i] == 'Cn':
gc[i] = gc[i + 1]
for i in range(len(sc)):
if (i % 128) and sc[i] == 'Zzzz':
sc[i] = sc[i - 1]
for i in range(len(sc) - 2, -1, -1):
if ((i + 1) % 128) and sc[i] == 'Zzzz':
sc[i] = sc[i + 1]
code = packTab.Code('_hb_ucd')
for name,data,default,mapping in datasets:
sol = packTab.pack_table(data, default, mapping=mapping, compression=compression)
logging.info(' Dataset=%-8s FullCost=%d' % (name, sol.fullCost))
sol.genCode(code, name)
code.print_c(linkage='static inline')
print()
print('#endif')
print()
print()
print("#endif /* HB_UCD_TABLE_HH */")
print()
print("/* == End of generated table == */")
logging.info('Done.')

View File

@ -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]
@ -407,6 +419,10 @@ for h in headers:
print (" * %s" % (l.strip()))
print (" */")
print ()
print ('#include "hb.hh"')
print ()
print ('#ifndef HB_NO_OT_SHAPE')
print ()
print ('#include "hb-ot-shape-complex-use.hh"')
print ()
@ -521,6 +537,8 @@ for k,v in sorted(use_positions.items()):
tag = k + suf
print ("#undef %s" % tag)
print ()
print ()
print ('#endif')
print ("/* == End of generated table == */")
# Maintain at least 50% occupancy in the table */

View File

@ -157,6 +157,11 @@ print (' *')
for line in scripts_header:
print (' * %s' % line.strip ())
print (' */')
print ()
print ('#include "hb.hh"')
print ()
print ('#ifndef HB_NO_OT_SHAPE')
print ()
print ('#include "hb-ot-shape-complex-vowel-constraints.hh"')
print ()
@ -180,6 +185,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 ()
@ -220,4 +228,6 @@ print (' }')
print ('}')
print ()
print ()
print ('#endif')
print ('/* == End of generated functions == */')

51
src/harfbuzz.cc Normal file
View File

@ -0,0 +1,51 @@
#include "hb-aat-layout.cc"
#include "hb-aat-map.cc"
#include "hb-blob.cc"
#include "hb-buffer-serialize.cc"
#include "hb-buffer.cc"
#include "hb-common.cc"
#include "hb-face.cc"
#include "hb-fallback-shape.cc"
#include "hb-font.cc"
#include "hb-map.cc"
#include "hb-ot-cff1-table.cc"
#include "hb-ot-cff2-table.cc"
#include "hb-ot-color.cc"
#include "hb-ot-face.cc"
#include "hb-ot-font.cc"
#include "hb-ot-hmtx-table.cc"
#include "hb-ot-layout.cc"
#include "hb-ot-map.cc"
#include "hb-ot-math.cc"
#include "hb-ot-name.cc"
#include "hb-ot-shape-complex-arabic.cc"
#include "hb-ot-shape-complex-default.cc"
#include "hb-ot-shape-complex-hangul.cc"
#include "hb-ot-shape-complex-hebrew.cc"
#include "hb-ot-shape-complex-indic-table.cc"
#include "hb-ot-shape-complex-indic.cc"
#include "hb-ot-shape-complex-khmer.cc"
#include "hb-ot-shape-complex-myanmar.cc"
#include "hb-ot-shape-complex-thai.cc"
#include "hb-ot-shape-complex-use-table.cc"
#include "hb-ot-shape-complex-use.cc"
#include "hb-ot-shape-complex-vowel-constraints.cc"
#include "hb-ot-shape-fallback.cc"
#include "hb-ot-shape-normalize.cc"
#include "hb-ot-shape.cc"
#include "hb-ot-tag.cc"
#include "hb-ot-var.cc"
#include "hb-set.cc"
#include "hb-shape-plan.cc"
#include "hb-shape.cc"
#include "hb-shaper.cc"
#include "hb-static.cc"
#include "hb-ucd.cc"
#include "hb-unicode.cc"
#include "hb-warning.cc"
#include "hb-glib.cc"
#include "hb-ft.cc"
#include "hb-graphite2.cc"
#include "hb-uniscribe.cc"
#include "hb-directwrite.cc"
#include "hb-coretext.cc"

View File

@ -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 */

View File

@ -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:

View File

@ -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;

View File

@ -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. */

View File

@ -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 ());
}
}

View File

@ -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:

View File

@ -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);

View File

@ -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,7 +133,7 @@ struct TrackData
if (size_table[size_index].to_float () >= csspx)
break;
return round (interpolate_at (size_index ? size_index - 1 : 0, csspx,
return roundf (interpolate_at (size_index ? size_index - 1 : 0, csspx,
*trackTableEntry, base));
}

View File

@ -25,9 +25,8 @@
* Google Author(s): Behdad Esfahbod
*/
#include "hb-open-type.hh"
#include "hb.hh"
#include "hb-ot-face.hh"
#include "hb-aat-layout.hh"
#include "hb-aat-fdsc-table.hh" // Just so we compile it; unused otherwise.
#include "hb-aat-layout-ankr-table.hh"
@ -40,6 +39,42 @@
#include "hb-aat-ltag-table.hh"
/*
* hb_aat_apply_context_t
*/
/* Note: This context is used for kerning, even without AAT, hence the condition. */
#if !defined(HB_NO_AAT) || !defined(HB_NO_OT_KERN)
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_,
hb_blob_t *blob) :
plan (plan_),
font (font_),
face (font->face),
buffer (buffer_),
sanitizer (),
ankr_table (&Null(AAT::ankr)),
lookup_index (0),
debug_depth (0)
{
sanitizer.init (blob);
sanitizer.set_num_glyphs (face->get_num_glyphs ());
sanitizer.start_processing ();
sanitizer.set_max_ops (HB_SANITIZE_MAX_OPS_MAX);
}
AAT::hb_aat_apply_context_t::~hb_aat_apply_context_t ()
{ sanitizer.end_processing (); }
void
AAT::hb_aat_apply_context_t::set_ankr_table (const AAT::ankr *ankr_table_)
{ ankr_table = ankr_table_; }
#endif
/**
* SECTION:hb-aat-layout
* @title: hb-aat-layout
@ -50,6 +85,8 @@
**/
#if !defined(HB_NO_AAT) || defined(HAVE_CORETEXT)
/* Table data courtesy of Apple. Converted from mnemonics to integers
* when moving to this file. */
static const hb_aat_feature_mapping_t feature_mappings[] =
@ -135,44 +172,16 @@ 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,
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);
}
#endif
/*
* hb_aat_apply_context_t
*/
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_,
hb_blob_t *blob) :
plan (plan_),
font (font_),
face (font->face),
buffer (buffer_),
sanitizer (),
ankr_table (&Null(AAT::ankr)),
lookup_index (0),
debug_depth (0)
{
sanitizer.init (blob);
sanitizer.set_num_glyphs (face->get_num_glyphs ());
sanitizer.start_processing ();
sanitizer.set_max_ops (HB_SANITIZE_MAX_OPS_MAX);
}
AAT::hb_aat_apply_context_t::~hb_aat_apply_context_t ()
{ sanitizer.end_processing (); }
void
AAT::hb_aat_apply_context_t::set_ankr_table (const AAT::ankr *ankr_table_)
{ ankr_table = ankr_table_; }
#ifndef HB_NO_AAT
/*
* mort/morx/kerx/trak
@ -374,3 +383,6 @@ hb_aat_layout_feature_type_get_selector_infos (hb_face_t
{
return face->table.feat->get_selector_infos (feature_type, start_offset, selector_count, selectors, default_index);
}
#endif

View File

@ -78,12 +78,4 @@ hb_aat_layout_track (const hb_ot_shape_plan_t *plan,
hb_buffer_t *buffer);
inline hb_language_t
_hb_aat_language_get (hb_face_t *face,
unsigned int i)
{
return face->table.ltag->get_language (i);
}
#endif /* HB_AAT_LAYOUT_HH */

View File

@ -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) */

View File

@ -26,6 +26,10 @@
* Google Author(s): Behdad Esfahbod
*/
#include "hb.hh"
#ifndef HB_NO_AAT_SHAPE
#include "hb-aat-map.hh"
#include "hb-aat-layout.hh"
@ -66,3 +70,6 @@ hb_aat_map_builder_t::compile (hb_aat_map_t &m)
hb_aat_layout_compile_map (this, &m);
}
#endif

View File

@ -1,6 +1,6 @@
/*
* Copyright © 2017 Google, Inc.
* Copyright © 2019 Google, Inc.
* Copyright © 2019 Facebook, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
@ -34,26 +34,59 @@
#include "hb-null.hh"
struct
{
template <typename T> T
operator () (const T& v) const { return v; }
} HB_FUNCOBJ (hb_identity);
/* 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)
/* Custom encoding used by hb-ucd. */
#define HB_CODEPOINT_ENCODE3_11_7_14(x,y,z) (((uint32_t) ((x) & 0x07FFu) << 21) | (((uint32_t) (y) & 0x007Fu) << 14) | (uint32_t) ((z) & 0x3FFFu))
#define HB_CODEPOINT_DECODE3_11_7_14_1(v) ((hb_codepoint_t) ((v) >> 21))
#define HB_CODEPOINT_DECODE3_11_7_14_2(v) ((hb_codepoint_t) (((v) >> 14) & 0x007Fu) | 0x0300)
#define HB_CODEPOINT_DECODE3_11_7_14_3(v) ((hb_codepoint_t) (v) & 0x3FFFu)
struct
{
template <typename T> bool
operator () (const T& v) const { return bool (v); }
} HB_FUNCOBJ (hb_bool);
/* Note. This is dangerous in that if it's passed an rvalue, it returns rvalue-reference. */
template <typename T> constexpr 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> constexpr T&
operator () (T& v) const { return v; }
template <typename T> constexpr hb_remove_reference<T>
operator () (T&& v) const { return v; }
}
HB_FUNCOBJ (hb_lidentity);
struct
{
/* Like identity(), but always returns rvalue. */
template <typename T> constexpr hb_remove_reference<T>
operator () (T&& v) const { return v; }
}
HB_FUNCOBJ (hb_ridentity);
struct
{
template <typename T> constexpr 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 ())
template <typename T> constexpr auto
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))> constexpr auto
impl (const T& v, hb_priority<0>) const HB_AUTO_RETURN
(
/* Knuth's multiplicative method: */
@ -62,42 +95,117 @@ struct
public:
template <typename T> auto
template <typename T> constexpr 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, HB_PARTIALIZE, macro uses a particular corner-case
* of C++11 that is not particularly well-supported by all compilers.
* What's happening is that it's using "this" in a trailing return-type
* via decltype(). Broken compilers deduce the type of "this" pointer
* in that context differently from what it resolves to in the body
* of the function.
*
* One probable cause of this is that at the time of trailing return
* type declaration, "this" points to an incomplete type, whereas in
* the function body the type is complete. That doesn't justify the
* error in any way, but is probably what's happening.
*
* In the case of MSVC, we get around this by using C++14 "decltype(auto)"
* which deduces the type from the actual return statement. For gcc 4.8
* we use "+this" instead of "this" which produces an rvalue that seems
* to be deduced as the same type with this particular compiler, and seem
* to be fine as default code path as well.
*/
#ifdef _MSC_VER
/* https://github.com/harfbuzz/harfbuzz/issues/1730 */ \
#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
/* https://github.com/harfbuzz/harfbuzz/issues/1724 */
#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 +213,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 +230,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 +291,8 @@ struct
hb_forward<Val> (v),
hb_prioritize)
)
} HB_FUNCOBJ (hb_get);
}
HB_FUNCOBJ (hb_get);
template <typename T1, typename T2>
@ -159,38 +303,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> constexpr 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> constexpr 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);
template <typename T, typename T2> constexpr auto
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);
template <typename T, typename T2> constexpr auto
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);
/*
@ -256,7 +423,7 @@ hb_bit_storage (T v)
return sizeof (unsigned long long) * 8 - __builtin_clzll (v);
#endif
#if (defined(_MSC_VER) && _MSC_VER >= 1500) || defined(__MINGW32__)
#if (defined(_MSC_VER) && _MSC_VER >= 1500) || (defined(__MINGW32__) && (__GNUC__ < 4))
if (sizeof (T) <= sizeof (unsigned int))
{
unsigned long where;
@ -330,7 +497,7 @@ hb_ctz (T v)
return __builtin_ctzll (v);
#endif
#if (defined(_MSC_VER) && _MSC_VER >= 1500) || defined(__MINGW32__)
#if (defined(_MSC_VER) && _MSC_VER >= 1500) || (defined(__MINGW32__) && (__GNUC__ < 4))
if (sizeof (T) <= sizeof (unsigned int))
{
unsigned long where;
@ -402,14 +569,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 +626,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)
@ -513,115 +651,213 @@ hb_bsearch_r (const void *key, const void *base,
/* From https://github.com/noporpoise/sort_r
* With following modifications:
*
* 10 November 2018:
* https://github.com/noporpoise/sort_r/issues/7
*/
Feb 5, 2019 (c8c65c1e)
Modified to support optional argument using templates */
/* Isaac Turner 29 April 2014 Public Domain */
/*
hb_sort_r function to be exported.
hb_qsort function to be exported.
Parameters:
base is the array to be sorted
nel is the number of elements in the array
width is the size in bytes of each element of the array
compar is the comparison function
arg is a pointer to be passed to the comparison function
arg (optional) is a pointer to be passed to the comparison function
void hb_sort_r(void *base, size_t nel, size_t width,
int (*compar)(const void *_a, const void *_b, void *_arg),
void *arg);
void hb_qsort(void *base, size_t nel, size_t width,
int (*compar)(const void *_a, const void *_b, [void *_arg]),
[void *arg]);
*/
#define SORT_R_SWAP(a,b,tmp) ((tmp) = (a), (a) = (b), (b) = (tmp))
/* swap a, b iff a>b */
/* __restrict is same as restrict but better support on old machines */
static int sort_r_cmpswap(char *__restrict a, char *__restrict b, size_t w,
int (*compar)(const void *_a, const void *_b,
void *_arg),
void *arg)
/* swap a and b */
/* a and b must not be equal! */
static inline void sort_r_swap(char *__restrict a, char *__restrict b,
size_t w)
{
char tmp, *end = a+w;
if(compar(a, b, arg) > 0) {
for(; a < end; a++, b++) { tmp = *a; *a = *b; *b = tmp; }
for(; a < end; a++, b++) { SORT_R_SWAP(*a, *b, tmp); }
}
/* swap a, b iff a>b */
/* a and b must not be equal! */
/* __restrict is same as restrict but better support on old machines */
template <typename ...Ts>
static inline int sort_r_cmpswap(char *__restrict a,
char *__restrict b, size_t w,
int (*compar)(const void *_a,
const void *_b,
Ts... _ds),
Ts... ds)
{
if(compar(a, b, ds...) > 0) {
sort_r_swap(a, b, w);
return 1;
}
return 0;
}
/*
Swap consecutive blocks of bytes of size na and nb starting at memory addr ptr,
with the smallest swap so that the blocks are in the opposite order. Blocks may
be internally re-ordered e.g.
12345ab -> ab34512
123abc -> abc123
12abcde -> deabc12
*/
static inline void sort_r_swap_blocks(char *ptr, size_t na, size_t nb)
{
if(na > 0 && nb > 0) {
if(na > nb) { sort_r_swap(ptr, ptr+na, nb); }
else { sort_r_swap(ptr, ptr+nb, na); }
}
}
/* Implement recursive quicksort ourselves */
/* Note: quicksort is not stable, equivalent values may be swapped */
template <typename ...Ts>
static inline void sort_r_simple(void *base, size_t nel, size_t w,
int (*compar)(const void *_a, const void *_b,
void *_arg),
void *arg)
int (*compar)(const void *_a,
const void *_b,
Ts... _ds),
Ts... ds)
{
char *b = (char *)base, *end = b + nel*w;
if(nel < 7) {
/* for(size_t i=0; i<nel; i++) {printf("%4i", *(int*)(b + i*sizeof(int)));}
printf("\n"); */
if(nel < 10) {
/* Insertion sort for arbitrarily small inputs */
char *pi, *pj;
for(pi = b+w; pi < end; pi += w) {
for(pj = pi; pj > b && sort_r_cmpswap(pj-w,pj,w,compar,arg); pj -= w) {}
for(pj = pi; pj > b && sort_r_cmpswap(pj-w,pj,w,compar,ds...); pj -= w) {}
}
}
else
{
/* nel > 6; Quicksort */
/* nel > 9; Quicksort */
/* Use median of first, middle and last items as pivot */
char *x, *y, *xend, ch;
char *pl, *pm, *pr;
int cmp;
char *pl, *ple, *pr, *pre, *pivot;
char *last = b+w*(nel-1), *tmp;
/*
Use median of second, middle and second-last items as pivot.
First and last may have been swapped with pivot and therefore be extreme
*/
char *l[3];
l[0] = b;
l[0] = b + w;
l[1] = b+w*(nel/2);
l[2] = last;
l[2] = last - w;
if(compar(l[0],l[1],arg) > 0) { tmp=l[0]; l[0]=l[1]; l[1]=tmp; }
if(compar(l[1],l[2],arg) > 0) {
tmp=l[1]; l[1]=l[2]; l[2]=tmp; /* swap(l[1],l[2]) */
if(compar(l[0],l[1],arg) > 0) { tmp=l[0]; l[0]=l[1]; l[1]=tmp; }
/* printf("pivots: %i, %i, %i\n", *(int*)l[0], *(int*)l[1], *(int*)l[2]); */
if(compar(l[0],l[1],ds...) > 0) { SORT_R_SWAP(l[0], l[1], tmp); }
if(compar(l[1],l[2],ds...) > 0) {
SORT_R_SWAP(l[1], l[2], tmp);
if(compar(l[0],l[1],ds...) > 0) { SORT_R_SWAP(l[0], l[1], tmp); }
}
/* swap l[id], l[2] to put pivot as last element */
for(x = l[1], y = last, xend = x+w; x<xend; x++, y++) {
ch = *x; *x = *y; *y = ch;
}
/* swap mid value (l[1]), and last element to put pivot as last element */
if(l[1] != last) { sort_r_swap(l[1], last, w); }
pl = b;
pr = last;
/*
pl is the next item on the left to be compared to the pivot
pr is the last item on the right that was compared to the pivot
ple is the left position to put the next item that equals the pivot
ple is the last right position where we put an item that equals the pivot
v- end (beyond the array)
EEEEEELLLLLLLLuuuuuuuuGGGGGGGEEEEEEEE.
^- b ^- ple ^- pl ^- pr ^- pre ^- last (where the pivot is)
Pivot comparison key:
E = equal, L = less than, u = unknown, G = greater than, E = equal
*/
pivot = last;
ple = pl = b;
pre = pr = last;
/*
Strategy:
Loop into the list from the left and right at the same time to find:
- an item on the left that is greater than the pivot
- an item on the right that is less than the pivot
Once found, they are swapped and the loop continues.
Meanwhile items that are equal to the pivot are moved to the edges of the
array.
*/
while(pl < pr) {
pm = pl+((pr-pl+1)>>1);
for(; pl < pm; pl += w) {
if(sort_r_cmpswap(pl, pr, w, compar, arg)) {
pr -= w; /* pivot now at pl */
break;
/* Move left hand items which are equal to the pivot to the far left.
break when we find an item that is greater than the pivot */
for(; pl < pr; pl += w) {
cmp = compar(pl, pivot, ds...);
if(cmp > 0) { break; }
else if(cmp == 0) {
if(ple < pl) { sort_r_swap(ple, pl, w); }
ple += w;
}
}
pm = pl+((pr-pl)>>1);
for(; pm < pr; pr -= w) {
if(sort_r_cmpswap(pl, pr, w, compar, arg)) {
pl += w; /* pivot now at pr */
/* break if last batch of left hand items were equal to pivot */
if(pl >= pr) { break; }
/* Move right hand items which are equal to the pivot to the far right.
break when we find an item that is less than the pivot */
for(; pl < pr; ) {
pr -= w; /* Move right pointer onto an unprocessed item */
cmp = compar(pr, pivot, ds...);
if(cmp == 0) {
pre -= w;
if(pr < pre) { sort_r_swap(pr, pre, w); }
}
else if(cmp < 0) {
if(pl < pr) { sort_r_swap(pl, pr, w); }
pl += w;
break;
}
}
}
sort_r_simple(b, (pl-b)/w, w, compar, arg);
sort_r_simple(pl+w, (end-(pl+w))/w, w, compar, arg);
pl = pr; /* pr may have gone below pl */
/*
Now we need to go from: EEELLLGGGGEEEE
to: LLLEEEEEEEGGGG
Pivot comparison key:
E = equal, L = less than, u = unknown, G = greater than, E = equal
*/
sort_r_swap_blocks(b, ple-b, pl-ple);
sort_r_swap_blocks(pr, pre-pr, end-pre);
/*for(size_t i=0; i<nel; i++) {printf("%4i", *(int*)(b + i*sizeof(int)));}
printf("\n");*/
sort_r_simple(b, (pl-ple)/w, w, compar, ds...);
sort_r_simple(end-(pre-pr), (pre-pr)/w, w, compar, ds...);
}
}
static inline void
hb_sort_r (void *base, size_t nel, size_t width,
hb_qsort (void *base, size_t nel, size_t width,
int (*compar)(const void *_a, const void *_b))
{
#if defined(__OPTIMIZE_SIZE__) && !defined(HB_USE_INTERNAL_QSORT)
qsort (base, nel, width, compar);
#else
sort_r_simple (base, nel, width, compar);
#endif
}
static inline void
hb_qsort (void *base, size_t nel, size_t width,
int (*compar)(const void *_a, const void *_b, void *_arg),
void *arg)
{
sort_r_simple(base, nel, width, compar, arg);
#ifdef HAVE_GNU_QSORT_R
qsort_r (base, nel, width, compar, arg);
#else
sort_r_simple (base, nel, width, compar, arg);
#endif
}
@ -661,7 +897,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,87 +911,131 @@ 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> constexpr 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> constexpr 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> constexpr 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> constexpr auto
operator () (const T &a, const T &b) const HB_AUTO_RETURN (a & ~b)
}
HB_FUNCOBJ (hb_bitwise_sub);
struct
{
template <typename T> constexpr auto
operator () (const T &a) const HB_AUTO_RETURN (~a)
}
HB_FUNCOBJ (hb_bitwise_neg);
struct
{ HB_PARTIALIZE(2);
template <typename T, typename T2> constexpr 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> constexpr 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> constexpr 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> constexpr 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> constexpr auto
operator () (const T &a, const T2 &b) const HB_AUTO_RETURN (a % b)
}
HB_FUNCOBJ (hb_mod);
struct
{
template <typename T> constexpr auto
operator () (const T &a) const HB_AUTO_RETURN (+a)
}
HB_FUNCOBJ (hb_pos);
struct
{
template <typename T> constexpr auto
operator () (const T &a) const HB_AUTO_RETURN (-a)
}
HB_FUNCOBJ (hb_neg);
/* Compiler-assisted vectorization. */
/* Type behaving similar to vectorized vars defined using __attribute__((vector_size(...))),
* using vectorized operations if HB_VECTOR_SIZE is set to **bit** numbers (eg 128).
* Define that to 0 to disable. */
* basically a fixed-size bitset. */
template <typename elt_t, unsigned int byte_size>
struct hb_vector_size_t
{
elt_t& operator [] (unsigned int i) { return u.v[i]; }
const elt_t& operator [] (unsigned int i) const { return u.v[i]; }
elt_t& operator [] (unsigned int i) { return v[i]; }
const elt_t& operator [] (unsigned int i) const { return v[i]; }
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 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]);
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]);
for (unsigned int i = 0; i < ARRAY_LENGTH (v); i++)
r.v[i] = op (v[i]);
return r;
}
template <typename Op>
hb_vector_size_t process (const Op& op, const hb_vector_size_t &o) const
{
hb_vector_size_t r;
for (unsigned int i = 0; i < ARRAY_LENGTH (v); i++)
r.v[i] = op (v[i], o.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;
#if HB_VECTOR_SIZE && 0
if (HB_VECTOR_SIZE && 0 == (byte_size * 8) % HB_VECTOR_SIZE)
for (unsigned int i = 0; i < ARRAY_LENGTH (u.vec); i++)
r.u.vec[i] = ~u.vec[i];
else
#endif
for (unsigned int i = 0; i < ARRAY_LENGTH (u.v); i++)
r.u.v[i] = ~u.v[i];
return r;
}
{ return process (hb_bitwise_neg); }
private:
static_assert (byte_size / sizeof (elt_t) * sizeof (elt_t) == byte_size, "");
union {
static_assert (0 == byte_size % sizeof (elt_t), "");
elt_t v[byte_size / sizeof (elt_t)];
#if HB_VECTOR_SIZE
hb_vector_size_impl_t vec[byte_size / sizeof (hb_vector_size_impl_t)];
#endif
} u;
};

View File

@ -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.
*/
@ -130,21 +141,21 @@ struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
hb_sorted_array_t<Type> qsort (int (*cmp_)(const void*, const void*))
{
if (likely (length))
::qsort (arrayZ, length, this->item_size, cmp_);
hb_qsort (arrayZ, length, this->item_size, cmp_);
return hb_sorted_array_t<Type> (*this);
}
hb_sorted_array_t<Type> qsort ()
{
if (likely (length))
::qsort (arrayZ, length, this->item_size, Type::cmp);
hb_qsort (arrayZ, length, this->item_size, Type::cmp);
return hb_sorted_array_t<Type> (*this);
}
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);
hb_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)
;
}

View File

@ -107,7 +107,7 @@ _hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N)
static inline void _hb_memory_barrier ()
{
#if !defined(MemoryBarrier)
#if !defined(MemoryBarrier) && !defined(__MINGW32_VERSION)
/* 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)

View File

@ -28,11 +28,9 @@
#define HB_BIMAP_HH
#include "hb.hh"
#include "hb-map.hh"
/* Bi-directional map.
* new ids are assigned incrementally & contiguously to old ids
* which may be added randomly & sparsely
* all mappings are 1-to-1 in both directions */
/* Bi-directional map */
struct hb_bimap_t
{
hb_bimap_t () { init (); }
@ -40,70 +38,106 @@ struct hb_bimap_t
void init ()
{
count = 0;
old_to_new.init ();
new_to_old.init ();
forw_map.init ();
back_map.init ();
}
void fini ()
{
old_to_new.fini ();
new_to_old.fini ();
forw_map.fini ();
back_map.fini ();
}
bool has (hb_codepoint_t _old) const { return old_to_new.has (_old); }
hb_codepoint_t add (hb_codepoint_t _old)
void reset ()
{
hb_codepoint_t _new = old_to_new[_old];
if (_new == HB_MAP_VALUE_INVALID)
forw_map.reset ();
back_map.reset ();
}
bool in_error () const { return forw_map.in_error () || back_map.in_error (); }
void set (hb_codepoint_t lhs, hb_codepoint_t rhs)
{
_new = count++;
old_to_new.set (_old, _new);
new_to_old.resize (count);
new_to_old[_new] = _old;
}
return _new;
if (unlikely (lhs == HB_MAP_VALUE_INVALID)) return;
if (unlikely (rhs == HB_MAP_VALUE_INVALID)) { del (lhs); return; }
forw_map.set (lhs, rhs);
back_map.set (rhs, lhs);
}
/* returns HB_MAP_VALUE_INVALID if unmapped */
hb_codepoint_t operator [] (hb_codepoint_t _old) const { return to_new (_old); }
hb_codepoint_t to_new (hb_codepoint_t _old) const { return old_to_new[_old]; }
hb_codepoint_t to_old (hb_codepoint_t _new) const { return (_new >= count)? HB_MAP_VALUE_INVALID: new_to_old[_new]; }
hb_codepoint_t get (hb_codepoint_t lhs) const { return forw_map.get (lhs); }
hb_codepoint_t backward (hb_codepoint_t rhs) const { return back_map.get (rhs); }
hb_codepoint_t operator [] (hb_codepoint_t lhs) const { return get (lhs); }
bool has (hb_codepoint_t lhs, hb_codepoint_t *vp = nullptr) const { return forw_map.has (lhs, vp); }
void del (hb_codepoint_t lhs)
{
back_map.del (get (lhs));
forw_map.del (lhs);
}
void clear ()
{
forw_map.clear ();
back_map.clear ();
}
bool is_empty () const { return get_population () == 0; }
unsigned int get_population () const { return forw_map.get_population (); }
protected:
hb_map_t forw_map;
hb_map_t back_map;
};
/* Inremental bimap: only lhs is given, rhs is incrementally assigned */
struct hb_inc_bimap_t : hb_bimap_t
{
/* Add a mapping from lhs to rhs with a unique value if lhs is unknown.
* Return the rhs value as the result.
*/
hb_codepoint_t add (hb_codepoint_t lhs)
{
hb_codepoint_t rhs = forw_map[lhs];
if (rhs == HB_MAP_VALUE_INVALID)
{
rhs = get_population ();
set (lhs, rhs);
}
return rhs;
}
/* Create an identity map. */
bool identity (unsigned int size)
{
hb_codepoint_t i;
old_to_new.clear ();
new_to_old.resize (size);
for (i = 0; i < size; i++)
{
old_to_new.set (i, i);
new_to_old[i] = i;
}
count = i;
return old_to_new.successful && !new_to_old.in_error ();
clear ();
for (hb_codepoint_t i = 0; i < size; i++) set (i, i);
return !in_error ();
}
protected:
static int cmp_id (const void* a, const void* b)
{ return (int)*(const hb_codepoint_t *)a - (int)*(const hb_codepoint_t *)b; }
public:
/* Optional: after finished adding all mappings in a random order,
* reassign new ids to old ids so that both are in the same order. */
void reorder ()
* reassign rhs to lhs so that they are in the same order. */
void sort ()
{
new_to_old.qsort (cmp_id);
for (hb_codepoint_t _new = 0; _new < count; _new++)
old_to_new.set (to_old (_new), _new);
hb_codepoint_t count = get_population ();
hb_vector_t <hb_codepoint_t> work;
work.resize (count);
for (hb_codepoint_t rhs = 0; rhs < count; rhs++)
work[rhs] = back_map[rhs];
work.qsort (cmp_id);
clear ();
for (hb_codepoint_t rhs = 0; rhs < count; rhs++)
set (work[rhs], rhs);
}
unsigned int get_count () const { return count; }
protected:
unsigned int count;
hb_map_t old_to_new;
hb_vector_t<hb_codepoint_t>
new_to_old;
};
#endif /* HB_BIMAP_HH */

View File

@ -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);
@ -487,6 +487,7 @@ hb_blob_t::try_make_writable ()
* Mmap
*/
#ifndef HB_NO_OPEN
#ifdef HAVE_MMAP
# include <sys/types.h>
# include <sys/stat.h>
@ -676,3 +677,4 @@ fread_fail_without_close:
free (data);
return hb_blob_get_empty ();
}
#endif /* !HB_NO_OPEN */

View File

@ -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 */

View File

@ -24,6 +24,10 @@
* Google Author(s): Behdad Esfahbod
*/
#include "hb.hh"
#ifndef HB_NO_BUFFER_SERIALIZE
#include "hb-buffer.hh"
@ -85,7 +89,7 @@ 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)
{
case HB_BUFFER_SERIALIZE_FORMAT_TEXT: return serialize_formats[0];
case HB_BUFFER_SERIALIZE_FORMAT_JSON: return serialize_formats[1];
@ -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;
@ -380,7 +384,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 +405,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';
@ -484,3 +488,6 @@ hb_buffer_deserialize_glyphs (hb_buffer_t *buffer,
}
}
#endif

View File

@ -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)
@ -1993,6 +1993,7 @@ hb_buffer_diff (hb_buffer_t *buffer,
* Debugging.
*/
#ifndef HB_NO_BUFFER_MESSAGE
/**
* hb_buffer_set_message_func:
* @buffer: an #hb_buffer_t.
@ -2022,7 +2023,6 @@ hb_buffer_set_message_func (hb_buffer_t *buffer,
buffer->message_destroy = nullptr;
}
}
bool
hb_buffer_t::message_impl (hb_font_t *font, const char *fmt, va_list ap)
{
@ -2030,3 +2030,4 @@ hb_buffer_t::message_impl (hb_font_t *font, const char *fmt, va_list ap)
vsnprintf (buf, sizeof (buf), fmt, ap);
return (bool) this->message_func (this, font, buf, this->message_data);
}
#endif

View File

@ -124,7 +124,9 @@ struct hb_buffer_t
unsigned int context_len[2];
/* Debugging API */
#ifndef HB_NO_BUFFER_MESSAGE
hb_buffer_message_func_t message_func;
#endif
void *message_data;
hb_destroy_func_t message_destroy;
@ -347,9 +349,19 @@ struct hb_buffer_t
HB_INTERNAL void sort (unsigned int start, unsigned int end, int(*compar)(const hb_glyph_info_t *, const hb_glyph_info_t *));
bool messaging () { return unlikely (message_func); }
bool messaging ()
{
#ifdef HB_NO_BUFFER_MESSAGE
return false;
#else
return unlikely (message_func);
#endif
}
bool message (hb_font_t *font, const char *fmt, ...) HB_PRINTF_FUNC(3, 4)
{
#ifdef HB_NO_BUFFER_MESSAGE
return true;
#else
if (!messaging ())
return true;
va_list ap;
@ -357,6 +369,7 @@ struct hb_buffer_t
bool ret = message_impl (font, fmt, ap);
va_end (ap);
return ret;
#endif
}
HB_INTERNAL bool message_impl (hb_font_t *font, const char *fmt, va_list ap) HB_PRINTF_FUNC(3, 0);
@ -379,7 +392,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

View File

@ -235,17 +235,10 @@ struct number_t
bool in_int_range () const
{ return ((double) (int16_t) to_int () == value); }
bool operator > (const number_t &n) const
{ return value > n.to_real (); }
bool operator < (const number_t &n) const
{ return n > *this; }
bool operator >= (const number_t &n) const
{ return !(*this < n); }
bool operator <= (const number_t &n) const
{ return !(*this > n); }
bool operator > (const number_t &n) const { return value > n.to_real (); }
bool operator < (const number_t &n) const { return n > *this; }
bool operator >= (const number_t &n) const { return !(*this < n); }
bool operator <= (const number_t &n) const { return !(*this > n); }
const number_t &operator += (const number_t &n)
{
@ -320,8 +313,7 @@ struct byte_str_t : hb_ubytes_t
/* A byte string associated with the current offset and an error condition */
struct byte_str_ref_t
{
byte_str_ref_t ()
{ init (); }
byte_str_ref_t () { init (); }
void init ()
{
@ -343,12 +335,11 @@ struct byte_str_ref_t
}
const unsigned char& operator [] (int i) {
if (unlikely ((unsigned int)(offset + i) >= str.length))
if (unlikely ((unsigned int) (offset + i) >= str.length))
{
set_error ();
return Null(unsigned char);
return Null (unsigned char);
}
else
return str[offset + i];
}
@ -359,9 +350,7 @@ struct byte_str_ref_t
{ return str.sub_str (offset_, len_); }
bool avail (unsigned int count=1) const
{
return (!in_error () && str.check_limit (offset, count));
}
{ return (!in_error () && str.check_limit (offset, count)); }
void inc (unsigned int count=1)
{
if (likely (!in_error () && (offset <= str.length) && (offset + count <= str.length)))
@ -389,7 +378,7 @@ typedef hb_vector_t<byte_str_t> byte_str_array_t;
/* stack */
template <typename ELEM, int LIMIT>
struct stack_t
struct cff_stack_t
{
void init ()
{
@ -400,11 +389,7 @@ struct stack_t
for (unsigned int i = 0; i < elements.length; i++)
elements[i].init ();
}
void fini ()
{
elements.fini_deep ();
}
void fini () { elements.fini_deep (); }
ELEM& operator [] (unsigned int i)
{
@ -419,7 +404,6 @@ struct stack_t
else
set_error ();
}
ELEM &push ()
{
if (likely (count < elements.length))
@ -441,7 +425,6 @@ struct stack_t
return Crap(ELEM);
}
}
void pop (unsigned int n)
{
if (likely (count >= n))
@ -452,13 +435,12 @@ struct stack_t
const ELEM& peek ()
{
if (likely (count > 0))
return elements[count-1];
else
if (unlikely (count < 0))
{
set_error ();
return Null(ELEM);
}
return elements[count - 1];
}
void unpop ()
@ -475,7 +457,7 @@ struct stack_t
void set_error () { error = true; }
unsigned int get_count () const { return count; }
bool is_empty () const { return count == 0; }
bool is_empty () const { return !count; }
static constexpr unsigned kSizeLimit = LIMIT;
@ -487,7 +469,7 @@ struct stack_t
/* argument stack */
template <typename ARG=number_t>
struct arg_stack_t : stack_t<ARG, 513>
struct arg_stack_t : cff_stack_t<ARG, 513>
{
void push_int (int v)
{
@ -519,7 +501,7 @@ struct arg_stack_t : stack_t<ARG, 513>
i = 0;
S::set_error ();
}
return (unsigned)i;
return (unsigned) i;
}
void push_longint_from_substr (byte_str_ref_t& str_ref)
@ -538,12 +520,10 @@ struct arg_stack_t : stack_t<ARG, 513>
}
hb_array_t<const ARG> get_subarray (unsigned int start) const
{
return S::elements.sub_array (start);
}
{ return S::elements.sub_array (start); }
private:
typedef stack_t<ARG, 513> S;
typedef cff_stack_t<ARG, 513> S;
};
/* an operator prefixed by its operands in a byte string */
@ -644,28 +624,17 @@ struct interp_env_t
return op;
}
const ARG& eval_arg (unsigned int i)
{
return argStack[i];
}
const ARG& eval_arg (unsigned int i) { return argStack[i]; }
ARG& pop_arg ()
{
return argStack.pop ();
}
ARG& pop_arg () { return argStack.pop (); }
void pop_n_args (unsigned int n) { argStack.pop (n); }
void pop_n_args (unsigned int n)
{
argStack.pop (n);
}
void clear_args () { pop_n_args (argStack.get_count ()); }
void clear_args ()
{
pop_n_args (argStack.get_count ());
}
byte_str_ref_t str_ref;
arg_stack_t<ARG> argStack;
byte_str_ref_t
str_ref;
arg_stack_t<ARG>
argStack;
protected:
bool error;
};
@ -711,8 +680,8 @@ struct opset_t
};
template <typename ENV>
struct interpreter_t {
struct interpreter_t
{
~interpreter_t() { fini (); }
void fini () { env.fini (); }

View File

@ -57,14 +57,14 @@ struct call_context_t
/* call stack */
const unsigned int kMaxCallLimit = 10;
struct call_stack_t : stack_t<call_context_t, kMaxCallLimit> {};
struct call_stack_t : cff_stack_t<call_context_t, kMaxCallLimit> {};
template <typename SUBRS>
struct biased_subrs_t
{
void init (const SUBRS &subrs_)
void init (const SUBRS *subrs_)
{
subrs = &subrs_;
subrs = subrs_;
unsigned int nSubrs = get_count ();
if (nSubrs < 1240)
bias = 107;
@ -76,7 +76,7 @@ struct biased_subrs_t
void fini () {}
unsigned int get_count () const { return (subrs == nullptr)? 0: subrs->count; }
unsigned int get_count () const { return (subrs == nullptr) ? 0 : subrs->count; }
unsigned int get_bias () const { return bias; }
byte_str_t operator [] (unsigned int index) const
@ -118,7 +118,7 @@ struct point_t
template <typename ARG, typename SUBRS>
struct cs_interp_env_t : interp_env_t<ARG>
{
void init (const byte_str_t &str, const SUBRS &globalSubrs_, const SUBRS &localSubrs_)
void init (const byte_str_t &str, const SUBRS *globalSubrs_, const SUBRS *localSubrs_)
{
interp_env_t<ARG>::init (str);
@ -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:

View File

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

View File

@ -40,7 +40,7 @@ struct cff1_cs_interp_env_t : cs_interp_env_t<number_t, CFF1Subrs>
template <typename ACC>
void init (const byte_str_t &str, ACC &acc, unsigned int fd)
{
SUPER::init (str, *acc.globalSubrs, *acc.privateDicts[fd].localSubrs);
SUPER::init (str, acc.globalSubrs, acc.privateDicts[fd].localSubrs);
processed_width = false;
has_width = false;
arg_start = 0;
@ -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 */

View File

@ -82,7 +82,7 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<blend_arg_t, CFF2Subrs>
void init (const byte_str_t &str, ACC &acc, unsigned int fd,
const int *coords_=nullptr, unsigned int num_coords_=0)
{
SUPER::init (str, *acc.globalSubrs, *acc.privateDicts[fd].localSubrs);
SUPER::init (str, acc.globalSubrs, acc.privateDicts[fd].localSubrs);
coords = coords_;
num_coords = num_coords_;
@ -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)

View File

@ -35,6 +35,9 @@
#include <xlocale.h>
#endif
#ifdef HB_NO_SETLOCALE
#define setlocale(Category, Locale) "C"
#endif
/**
* SECTION:hb-common
@ -67,7 +70,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) == static_cast<size_t>(p - c)) do { u.opts.symbol = true; } while (0)
OPTION ("uniscribe-bug-compatible", uniscribe_bug_compatible);
OPTION ("aat", aat);
@ -356,7 +359,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 +723,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 +747,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 +828,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 +1074,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 +1155,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 +1179,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 +1193,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 +1207,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)

159
src/hb-config.hh Normal file
View File

@ -0,0 +1,159 @@
/*
* 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
#define HB_NO_UCD_UNASSIGNED
#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_FACE_COLLECT_UNICODES
#define HB_NO_GETENV
#define HB_NO_HINTING
#define HB_NO_LANGUAGE_PRIVATE_SUBTAG
#define HB_NO_LAYOUT_FEATURE_PARAMS
#define HB_NO_LAYOUT_COLLECT_GLYPHS
#define HB_NO_LAYOUT_UNUSED
#define HB_NO_MATH
#define HB_NO_MMAP
#define HB_NO_NAME
#define HB_NO_OPEN
#define HB_NO_SETLOCALE
#define HB_NO_OT_FONT_GLYPH_NAMES
#define HB_NO_OT_SHAPE_FRACTIONS
#define HB_NO_STAT
#define HB_NO_SUBSET_LAYOUT
#define HB_NO_VAR
#endif
#ifdef HB_MINI
#define HB_NO_AAT
#define HB_NO_LEGACY
#endif
/* Closure of options. */
#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_AAT_SHAPE
#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_CMAP_LEGACY_SUBTABLES
#define HB_NO_FALLBACK_SHAPE
#define HB_NO_OT_KERN
#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
#define HB_NO_OT_FONT
#define HB_NO_OT_LAYOUT
#define HB_NO_OT_TAG
#define HB_NO_OT_SHAPE
#endif
#ifdef HB_NO_OT_SHAPE
#define HB_NO_AAT_SHAPE
#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 */

View File

@ -27,6 +27,9 @@
*/
#include "hb.hh"
#ifdef HAVE_CORETEXT
#include "hb-shaper-impl.hh"
#include "hb-coretext.h"
@ -55,13 +58,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
@ -72,7 +75,7 @@ release_table_data (void *user_data)
}
static hb_blob_t *
reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
_hb_cg_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
{
CGFontRef cg_font = reinterpret_cast<CGFontRef> (user_data);
CFDataRef cf_data = CGFontCopyTableForTag (cg_font, tag);
@ -296,7 +299,7 @@ _hb_coretext_shaper_face_data_destroy (hb_coretext_face_data_t *data)
hb_face_t *
hb_coretext_face_create (CGFontRef cg_font)
{
return hb_face_create_for_tables (reference_table, CGFontRetain (cg_font), _hb_cg_font_release);
return hb_face_create_for_tables (_hb_cg_reference_table, CGFontRetain (cg_font), _hb_cg_font_release);
}
/*
@ -598,7 +601,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 +611,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 +620,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;
@ -649,7 +652,7 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
DEBUG_MSG (CORETEXT, nullptr, __VA_ARGS__); \
ret = false; \
goto fail; \
} HB_STMT_END;
} HB_STMT_END
bool ret = true;
CFStringRef string_ref = nullptr;
@ -771,7 +774,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
@ -977,7 +980,7 @@ resize_and_retry:
#define SCRATCH_RESTORE() \
scratch_size = scratch_size_saved; \
scratch = scratch_saved;
scratch = scratch_saved
{ /* Setup glyphs */
SCRATCH_SAVE();
@ -1116,7 +1119,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 +1128,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;
}
}
@ -1148,3 +1151,6 @@ fail:
return ret;
}
#endif

View File

@ -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,
template <typename T>
T ret (T&& v,
const char *func HB_UNUSED = nullptr,
unsigned int line HB_UNUSED = 0) { return v; }
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__)

View File

@ -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);
@ -165,29 +165,8 @@ hb_unicode_decompose_compatibility (hb_unicode_funcs_t *ufuncs,
hb_codepoint_t *decomposed);
typedef hb_position_t (*hb_font_get_glyph_kerning_func_t) (hb_font_t *font, void *font_data,
hb_codepoint_t first_glyph, hb_codepoint_t second_glyph,
void *user_data);
typedef hb_font_get_glyph_kerning_func_t hb_font_get_glyph_h_kerning_func_t;
typedef hb_font_get_glyph_kerning_func_t hb_font_get_glyph_v_kerning_func_t;
/**
* hb_font_funcs_set_glyph_h_kerning_func:
* @ffuncs: font functions.
* @func: (closure user_data) (destroy destroy) (scope notified):
* @user_data:
* @destroy:
*
*
*
* Since: 0.9.2
* Deprecated: 2.0.0
**/
HB_EXTERN void
hb_font_funcs_set_glyph_h_kerning_func (hb_font_funcs_t *ffuncs,
hb_font_get_glyph_h_kerning_func_t func,
void *user_data, hb_destroy_func_t destroy);
/**
* hb_font_funcs_set_glyph_v_kerning_func:
* @ffuncs: font functions.
@ -206,19 +185,9 @@ hb_font_funcs_set_glyph_v_kerning_func (hb_font_funcs_t *ffuncs,
void *user_data, hb_destroy_func_t destroy);
HB_EXTERN hb_position_t
hb_font_get_glyph_h_kerning (hb_font_t *font,
hb_codepoint_t left_glyph, hb_codepoint_t right_glyph);
HB_EXTERN hb_position_t
hb_font_get_glyph_v_kerning (hb_font_t *font,
hb_codepoint_t top_glyph, hb_codepoint_t bottom_glyph);
HB_EXTERN void
hb_font_get_glyph_kerning_for_direction (hb_font_t *font,
hb_codepoint_t first_glyph, hb_codepoint_t second_glyph,
hb_direction_t direction,
hb_position_t *x, hb_position_t *y);
#endif
HB_END_DECLS

View File

@ -23,13 +23,23 @@
*/
#include "hb.hh"
#ifdef HAVE_DIRECTWRITE
#include "hb-shaper-impl.hh"
#include <DWrite_1.h>
#include <dwrite_1.h>
#include "hb-directwrite.h"
/* Declare object creator for dynamic support of DWRITE */
typedef HRESULT (* WINAPI t_DWriteCreateFactory)(
DWRITE_FACTORY_TYPE factoryType,
REFIID iid,
IUnknown **factory
);
/*
* hb-directwrite uses new/delete syntatically but as we let users
* to override malloc/free, we will redefine new/delete so users
@ -135,6 +145,7 @@ public:
struct hb_directwrite_face_data_t
{
HMODULE dwrite_dll;
IDWriteFactory *dwriteFactory;
IDWriteFontFile *fontFile;
DWriteFontFileStream *fontFileStream;
@ -150,12 +161,43 @@ _hb_directwrite_shaper_face_data_create (hb_face_t *face)
if (unlikely (!data))
return nullptr;
// TODO: factory and fontFileLoader should be cached separately
IDWriteFactory* dwriteFactory;
DWriteCreateFactory (DWRITE_FACTORY_TYPE_SHARED, __uuidof (IDWriteFactory),
(IUnknown**) &dwriteFactory);
#define FAIL(...) \
HB_STMT_START { \
DEBUG_MSG (DIRECTWRITE, nullptr, __VA_ARGS__); \
return nullptr; \
} HB_STMT_END
data->dwrite_dll = LoadLibrary (TEXT ("DWRITE"));
if (unlikely (!data->dwrite_dll))
FAIL ("Cannot find DWrite.DLL");
t_DWriteCreateFactory p_DWriteCreateFactory;
#if defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-function-type"
#endif
p_DWriteCreateFactory = (t_DWriteCreateFactory)
GetProcAddress (data->dwrite_dll, "DWriteCreateFactory");
#if defined(__GNUC__)
#pragma GCC diagnostic pop
#endif
if (unlikely (!p_DWriteCreateFactory))
FAIL ("Cannot find DWriteCreateFactory().");
HRESULT hr;
// TODO: factory and fontFileLoader should be cached separately
IDWriteFactory* dwriteFactory;
hr = p_DWriteCreateFactory (DWRITE_FACTORY_TYPE_SHARED, __uuidof (IDWriteFactory),
(IUnknown**) &dwriteFactory);
if (unlikely (hr != S_OK))
FAIL ("Failed to run DWriteCreateFactory().");
hb_blob_t *blob = hb_face_reference_blob (face);
DWriteFontFileStream *fontFileStream;
fontFileStream = new DWriteFontFileStream ((uint8_t *) hb_blob_get_data (blob, nullptr),
@ -169,12 +211,6 @@ _hb_directwrite_shaper_face_data_create (hb_face_t *face)
hr = dwriteFactory->CreateCustomFontFileReference (&fontFileKey, sizeof (fontFileKey),
fontFileLoader, &fontFile);
#define FAIL(...) \
HB_STMT_START { \
DEBUG_MSG (DIRECTWRITE, nullptr, __VA_ARGS__); \
return nullptr; \
} HB_STMT_END;
if (FAILED (hr))
FAIL ("Failed to load font file from data!");
@ -221,6 +257,8 @@ _hb_directwrite_shaper_face_data_destroy (hb_directwrite_face_data_t *data)
delete data->fontFileStream;
if (data->faceBlob)
hb_blob_destroy (data->faceBlob);
if (data->dwrite_dll)
FreeLibrary (data->dwrite_dll);
if (data)
delete data;
}
@ -501,10 +539,10 @@ protected:
Run mRunHead;
};
static inline uint16_t hb_uint16_swap (const uint16_t v)
static inline uint16_t hb_dw_uint16_swap (const uint16_t v)
{ return (v >> 8) | (v << 8); }
static inline uint32_t hb_uint32_swap (const uint32_t v)
{ return (hb_uint16_swap (v) << 16) | hb_uint16_swap (v >> 16); }
static inline uint32_t hb_dw_uint32_swap (const uint32_t v)
{ return (hb_dw_uint16_swap (v) << 16) | hb_dw_uint16_swap (v >> 16); }
/*
* shaper
@ -530,12 +568,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
@ -615,7 +653,7 @@ _hb_directwrite_shape_full (hb_shape_plan_t *shape_plan,
for (unsigned int i = 0; i < num_features; ++i)
{
typographic_features.features[i].nameTag = (DWRITE_FONT_FEATURE_TAG)
hb_uint32_swap (features[i].tag);
hb_dw_uint32_swap (features[i].tag);
typographic_features.features[i].parameter = features[i].value;
}
}
@ -778,7 +816,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)
@ -896,14 +934,14 @@ _hb_directwrite_table_data_release (void *data)
}
static hb_blob_t *
reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
_hb_directwrite_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
{
IDWriteFontFace *dw_face = ((IDWriteFontFace *) user_data);
const void *data;
uint32_t length;
void *table_context;
BOOL exists;
if (!dw_face || FAILED (dw_face->TryGetFontTable (hb_uint32_swap (tag), &data,
if (!dw_face || FAILED (dw_face->TryGetFontTable (hb_dw_uint32_swap (tag), &data,
&length, &table_context, &exists)))
return nullptr;
@ -930,7 +968,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
**/
@ -939,18 +979,23 @@ hb_directwrite_face_create (IDWriteFontFace *font_face)
{
if (font_face)
font_face->AddRef ();
return hb_face_create_for_tables (reference_table, font_face,
return hb_face_create_for_tables (_hb_directwrite_reference_table, font_face,
_hb_directwrite_font_release);
}
/**
* 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)
{
return face->data.directwrite->fontFace;
}
#endif

View File

@ -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; }
};

View File

@ -531,6 +531,7 @@ hb_face_get_table_tags (const hb_face_t *face,
*/
#ifndef HB_NO_FACE_COLLECT_UNICODES
/**
* hb_face_collect_unicodes:
* @face: font face.
@ -544,7 +545,6 @@ hb_face_collect_unicodes (hb_face_t *face,
{
face->table.cmap->collect_unicodes (out);
}
/**
* hb_face_collect_variation_selectors:
* @face: font face.
@ -560,7 +560,6 @@ hb_face_collect_variation_selectors (hb_face_t *face,
{
face->table.cmap->collect_variation_selectors (out);
}
/**
* hb_face_collect_variation_unicodes:
* @face: font face.
@ -577,7 +576,7 @@ hb_face_collect_variation_unicodes (hb_face_t *face,
{
face->table.cmap->collect_variation_unicodes (variation_selector, out);
}
#endif
/*

View File

@ -26,6 +26,7 @@
#include "hb-shaper-impl.hh"
#ifndef HB_NO_FALLBACK_SHAPE
/*
* shaper face data
@ -120,3 +121,5 @@ _hb_fallback_shape (hb_shape_plan_t *shape_plan HB_UNUSED,
return true;
}
#endif

View File

@ -355,6 +355,7 @@ hb_font_get_glyph_h_kerning_default (hb_font_t *font,
return font->parent_scale_x_distance (font->parent->get_glyph_h_kerning (left_glyph, right_glyph));
}
#ifndef HB_DISABLE_DEPRECATED
static hb_position_t
hb_font_get_glyph_v_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,
@ -936,7 +938,6 @@ hb_font_get_glyph_v_origin (hb_font_t *font,
* Return value:
*
* Since: 0.9.2
* Deprecated: 2.0.0
**/
hb_position_t
hb_font_get_glyph_h_kerning (hb_font_t *font,
@ -945,6 +946,7 @@ hb_font_get_glyph_h_kerning (hb_font_t *font,
return font->get_glyph_h_kerning (left_glyph, right_glyph);
}
#ifndef HB_DISABLE_DEPRECATED
/**
* hb_font_get_glyph_v_kerning:
* @font: a font.
@ -964,6 +966,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:
@ -1185,7 +1188,6 @@ hb_font_subtract_glyph_origin_for_direction (hb_font_t *font,
*
*
* Since: 0.9.2
* Deprecated: 2.0.0
**/
void
hb_font_get_glyph_kerning_for_direction (hb_font_t *font,
@ -1298,6 +1300,8 @@ DEFINE_NULL_INSTANCE (hb_font_t) =
1000, /* x_scale */
1000, /* y_scale */
1<<16, /* x_mult */
1<<16, /* y_mult */
0, /* x_ppem */
0, /* y_ppem */
@ -1328,6 +1332,7 @@ _hb_font_create (hb_face_t *face)
font->klass = hb_font_funcs_get_empty ();
font->data.init0 (font);
font->x_scale = font->y_scale = hb_face_get_upem (face);
font->x_mult = font->y_mult = 1 << 16;
return font;
}
@ -1347,7 +1352,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
@ -1599,7 +1604,9 @@ hb_font_set_face (hb_font_t *font,
hb_face_t *old = font->face;
hb_face_make_immutable (face);
font->face = hb_face_reference (face);
font->mults_changed ();
hb_face_destroy (old);
}
@ -1709,6 +1716,7 @@ hb_font_set_scale (hb_font_t *font,
font->x_scale = x_scale;
font->y_scale = y_scale;
font->mults_changed ();
}
/**
@ -1822,6 +1830,7 @@ _hb_font_adopt_var_coords_normalized (hb_font_t *font,
font->num_coords = coords_length;
}
#ifndef HB_NO_VAR
/**
* hb_font_set_variations:
*
@ -1852,7 +1861,6 @@ hb_font_set_variations (hb_font_t *font,
normalized, coords_length);
_hb_font_adopt_var_coords_normalized (font, normalized, coords_length);
}
/**
* hb_font_set_var_coords_design:
*
@ -1873,6 +1881,7 @@ hb_font_set_var_coords_design (hb_font_t *font,
hb_ot_var_normalize_coords (font->face, coords_length, coords, normalized);
_hb_font_adopt_var_coords_normalized (font, normalized, coords_length);
}
#endif
/**
* hb_font_set_var_coords_normalized:
@ -1916,6 +1925,7 @@ hb_font_get_var_coords_normalized (hb_font_t *font,
}
#ifndef HB_DISABLE_DEPRECATED
/*
* Deprecated get_glyph_func():
*/
@ -2038,3 +2048,4 @@ hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs,
trampoline,
trampoline_destroy);
}
#endif

View File

@ -157,6 +157,11 @@ typedef hb_bool_t (*hb_font_get_glyph_origin_func_t) (hb_font_t *font, void *fon
typedef hb_font_get_glyph_origin_func_t hb_font_get_glyph_h_origin_func_t;
typedef hb_font_get_glyph_origin_func_t hb_font_get_glyph_v_origin_func_t;
typedef hb_position_t (*hb_font_get_glyph_kerning_func_t) (hb_font_t *font, void *font_data,
hb_codepoint_t first_glyph, hb_codepoint_t second_glyph,
void *user_data);
typedef hb_font_get_glyph_kerning_func_t hb_font_get_glyph_h_kerning_func_t;
typedef hb_bool_t (*hb_font_get_glyph_extents_func_t) (hb_font_t *font, void *font_data,
hb_codepoint_t glyph,
@ -356,6 +361,22 @@ hb_font_funcs_set_glyph_v_origin_func (hb_font_funcs_t *ffuncs,
hb_font_get_glyph_v_origin_func_t func,
void *user_data, hb_destroy_func_t destroy);
/**
* hb_font_funcs_set_glyph_h_kerning_func:
* @ffuncs: font functions.
* @func: (closure user_data) (destroy destroy) (scope notified):
* @user_data:
* @destroy:
*
*
*
* Since: 0.9.2
**/
HB_EXTERN void
hb_font_funcs_set_glyph_h_kerning_func (hb_font_funcs_t *ffuncs,
hb_font_get_glyph_h_kerning_func_t func,
void *user_data, hb_destroy_func_t destroy);
/**
* hb_font_funcs_set_glyph_extents_func:
* @ffuncs: font functions.
@ -469,6 +490,10 @@ hb_font_get_glyph_v_origin (hb_font_t *font,
hb_codepoint_t glyph,
hb_position_t *x, hb_position_t *y);
HB_EXTERN hb_position_t
hb_font_get_glyph_h_kerning (hb_font_t *font,
hb_codepoint_t left_glyph, hb_codepoint_t right_glyph);
HB_EXTERN hb_bool_t
hb_font_get_glyph_extents (hb_font_t *font,
hb_codepoint_t glyph,
@ -531,6 +556,12 @@ hb_font_subtract_glyph_origin_for_direction (hb_font_t *font,
hb_direction_t direction,
hb_position_t *x, hb_position_t *y);
HB_EXTERN void
hb_font_get_glyph_kerning_for_direction (hb_font_t *font,
hb_codepoint_t first_glyph, hb_codepoint_t second_glyph,
hb_direction_t direction,
hb_position_t *x, hb_position_t *y);
HB_EXTERN hb_bool_t
hb_font_get_glyph_extents_for_origin (hb_font_t *font,
hb_codepoint_t glyph,

View File

@ -52,7 +52,7 @@
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_v_kerning)) \
HB_FONT_FUNC_IMPLEMENT (glyph_extents) \
HB_FONT_FUNC_IMPLEMENT (glyph_contour_point) \
HB_FONT_FUNC_IMPLEMENT (glyph_name) \
@ -107,8 +107,10 @@ struct hb_font_t
hb_font_t *parent;
hb_face_t *face;
int x_scale;
int y_scale;
int32_t x_scale;
int32_t y_scale;
int64_t x_mult;
int64_t y_mult;
unsigned int x_ppem;
unsigned int y_ppem;
@ -127,16 +129,16 @@ struct hb_font_t
/* Convert from font-space to user-space */
int dir_scale (hb_direction_t direction)
{ return HB_DIRECTION_IS_VERTICAL(direction) ? y_scale : x_scale; }
hb_position_t em_scale_x (int16_t v) { return em_scale (v, x_scale); }
hb_position_t em_scale_y (int16_t v) { return em_scale (v, y_scale); }
hb_position_t em_scalef_x (float v) { return em_scalef (v, this->x_scale); }
hb_position_t em_scalef_y (float v) { return em_scalef (v, this->y_scale); }
int64_t dir_mult (hb_direction_t direction)
{ return HB_DIRECTION_IS_VERTICAL(direction) ? y_mult : x_mult; }
hb_position_t em_scale_x (int16_t v) { return em_mult (v, x_mult); }
hb_position_t em_scale_y (int16_t v) { return em_mult (v, y_mult); }
hb_position_t em_scalef_x (float v) { return em_scalef (v, x_scale); }
hb_position_t em_scalef_y (float v) { return em_scalef (v, y_scale); }
float em_fscale_x (int16_t v) { return em_fscale (v, x_scale); }
float em_fscale_y (int16_t v) { return em_fscale (v, y_scale); }
hb_position_t em_scale_dir (int16_t v, hb_direction_t direction)
{ return em_scale (v, dir_scale (direction)); }
{ return em_mult (v, dir_mult (direction)); }
/* Convert from parent-font user-space to our user-space */
hb_position_t parent_scale_x_distance (hb_position_t v)
@ -304,17 +306,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,
@ -599,15 +609,19 @@ struct hb_font_t
return false;
}
hb_position_t em_scale (int16_t v, int scale)
void mults_changed ()
{
int upem = face->get_upem ();
int64_t scaled = v * (int64_t) scale;
scaled += scaled >= 0 ? upem/2 : -upem/2; /* Round. */
return (hb_position_t) (scaled / upem);
signed upem = face->get_upem ();
x_mult = ((int64_t) x_scale << 16) / upem;
y_mult = ((int64_t) y_scale << 16) / upem;
}
hb_position_t em_mult (int16_t v, int64_t mult)
{
return (hb_position_t) ((v * mult) >> 16);
}
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 (); }
};

View File

@ -29,6 +29,8 @@
#include "hb.hh"
#ifdef HAVE_FREETYPE
#include "hb-ft.h"
#include "hb-font.hh"
@ -346,6 +348,25 @@ hb_ft_get_glyph_v_origin (hb_font_t *font,
return true;
}
#ifndef HB_NO_OT_SHAPE_FALLBACK
static hb_position_t
hb_ft_get_glyph_h_kerning (hb_font_t *font,
void *font_data,
hb_codepoint_t left_glyph,
hb_codepoint_t right_glyph,
void *user_data HB_UNUSED)
{
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
FT_Vector kerningv;
FT_Kerning_Mode mode = font->x_ppem ? FT_KERNING_DEFAULT : FT_KERNING_UNFITTED;
if (FT_Get_Kerning (ft_font->ft_face, left_glyph, right_glyph, mode, &kerningv))
return 0;
return kerningv.x;
}
#endif
static hb_bool_t
hb_ft_get_glyph_extents (hb_font_t *font,
void *font_data,
@ -439,7 +460,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);
@ -497,6 +518,10 @@ static struct hb_ft_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ft
hb_font_funcs_set_glyph_v_advance_func (funcs, hb_ft_get_glyph_v_advance, nullptr, nullptr);
//hb_font_funcs_set_glyph_h_origin_func (funcs, hb_ft_get_glyph_h_origin, nullptr, nullptr);
hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ft_get_glyph_v_origin, nullptr, nullptr);
#ifndef HB_NO_OT_SHAPE_FALLBACK
hb_font_funcs_set_glyph_h_kerning_func (funcs, hb_ft_get_glyph_h_kerning, nullptr, nullptr);
#endif
//hb_font_funcs_set_glyph_v_kerning_func (funcs, hb_ft_get_glyph_v_kerning, nullptr, nullptr);
hb_font_funcs_set_glyph_extents_func (funcs, hb_ft_get_glyph_extents, nullptr, nullptr);
hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ft_get_glyph_contour_point, nullptr, nullptr);
hb_font_funcs_set_glyph_name_func (funcs, hb_ft_get_glyph_name, nullptr, nullptr);
@ -539,7 +564,7 @@ _hb_ft_font_set_funcs (hb_font_t *font, FT_Face ft_face, bool unref)
static hb_blob_t *
reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
_hb_ft_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
{
FT_Face ft_face = (FT_Face) user_data;
FT_Byte *buffer;
@ -594,7 +619,7 @@ hb_ft_face_create (FT_Face ft_face,
face = hb_face_create (blob, ft_face->face_index);
hb_blob_destroy (blob);
} else {
face = hb_face_create_for_tables (reference_table, ft_face, destroy);
face = hb_face_create_for_tables (_hb_ft_reference_table, ft_face, destroy);
}
hb_face_set_index (face, ft_face->face_index);
@ -854,3 +879,6 @@ hb_ft_font_set_funcs (hb_font_t *font)
_hb_ft_font_set_funcs (font, ft_face, true);
hb_ft_font_set_load_flags (font, FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING);
}
#endif

View File

@ -28,6 +28,8 @@
#include "hb.hh"
#ifdef HAVE_GLIB
#include "hb-glib.h"
#include "hb-machinery.hh"
@ -404,3 +406,6 @@ hb_glib_blob_create (GBytes *gbytes)
_hb_g_bytes_unref);
}
#endif
#endif

View File

@ -27,6 +27,8 @@
#include "hb.hh"
#ifdef HAVE_GOBJECT
/* g++ didn't like older gtype.h gcc-only code path. */
#include <glib.h>
#if !GLIB_CHECK_VERSION(2,29,16)
@ -44,6 +46,11 @@
/* enumerations from "@filename@" */
/*** END file-production ***/
/*** BEGIN file-tail ***/
#endif
/*** END file-tail ***/
/*** BEGIN value-header ***/
GType
@enum_name@_get_type ()

View File

@ -26,6 +26,8 @@
#include "hb.hh"
#ifdef HAVE_GOBJECT
/**
* SECTION:hb-gobject
@ -94,3 +96,6 @@ HB_DEFINE_VALUE_TYPE (user_data_key)
HB_DEFINE_VALUE_TYPE (ot_math_glyph_variant)
HB_DEFINE_VALUE_TYPE (ot_math_glyph_part)
#endif

View File

@ -26,6 +26,10 @@
* Google Author(s): Behdad Esfahbod
*/
#include "hb.hh"
#ifdef HAVE_GRAPHITE2
#include "hb-shaper-impl.hh"
#include "hb-graphite2.h"
@ -202,6 +206,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 +218,7 @@ hb_graphite2_font_get_gr_font (hb_font_t *font HB_UNUSED)
{
return nullptr;
}
#endif
/*
@ -308,12 +314,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);
@ -445,3 +451,6 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan HB_UNUSED,
return true;
}
#endif

View File

@ -29,6 +29,8 @@
#include "hb.hh"
#ifdef HAVE_ICU
#include "hb-icu.h"
#include "hb-machinery.hh"
@ -49,6 +51,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 +188,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 +198,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 +226,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 +241,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 +252,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 +263,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 +280,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 +289,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 +298,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;
}
@ -348,3 +353,6 @@ hb_icu_get_unicode_funcs ()
{
return static_icu_funcs.get_unconst ();
}
#endif

View File

@ -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)
{

View File

@ -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

View File

@ -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
template <typename T> constexpr T*
operator () (T& arg) const
{
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-align"
@ -81,100 +91,310 @@ 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 */
template <typename T>
static hb_remove_reference<T>&& hb_move (T&& t) { return (hb_remove_reference<T>&&) (t); }
static constexpr hb_remove_reference<T>&& hb_move (T&& t) { return (hb_remove_reference<T>&&) (t); }
template <typename T>
static T&& hb_forward (hb_remove_reference<T>& t) { return (T&&) t; }
static constexpr T&& hb_forward (hb_remove_reference<T>& t) { return (T&&) t; }
template <typename T>
static T&& hb_forward (hb_remove_reference<T>&& t) { return (T&&) t; }
static constexpr T&& hb_forward (hb_remove_reference<T>&& t) { return (T&&) t; }
struct
{
template <typename T> auto
template <typename T> constexpr auto
operator () (T&& v) const HB_AUTO_RETURN (hb_forward<T> (v))
template <typename T> auto
template <typename T> constexpr auto
operator () (T *v) const HB_AUTO_RETURN (*v)
}
HB_FUNCOBJ (hb_deref);
} HB_FUNCOBJ (hb_deref_pointer);
struct
{
template <typename T> constexpr auto
operator () (T&& v) const HB_AUTO_RETURN (hb_forward<T> (v))
template <typename T> constexpr 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 */

View File

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

View File

@ -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
@ -81,7 +74,7 @@ struct hb_static_size
*/
extern HB_INTERNAL
hb_vector_size_impl_t const _hb_NullPool[(HB_NULL_POOL_SIZE + sizeof (hb_vector_size_impl_t) - 1) / sizeof (hb_vector_size_impl_t)];
uint64_t const _hb_NullPool[(HB_NULL_POOL_SIZE + sizeof (uint64_t) - 1) / sizeof (uint64_t)];
/* Generic nul-content Null objects. */
template <typename Type>
@ -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 ()
@ -135,7 +128,7 @@ struct NullHelper
* causing bad memory access. So, races there are not actually introducing incorrectness
* in the code. Has ~12kb binary size overhead to have it, also clang build fails with it. */
extern HB_INTERNAL
/*thread_local*/ hb_vector_size_impl_t _hb_CrapPool[(HB_NULL_POOL_SIZE + sizeof (hb_vector_size_impl_t) - 1) / sizeof (hb_vector_size_impl_t)];
/*thread_local*/ uint64_t _hb_CrapPool[(HB_NULL_POOL_SIZE + sizeof (uint64_t) - 1) / sizeof (uint64_t)];
/* CRAP pool: Common Region for Access Protection. */
template <typename Type>
@ -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 ()

View File

@ -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 >

View File

@ -57,13 +57,13 @@ 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; }
IntType& operator = (wide_type i) { v = i; return *this; }
operator wide_type () const { return v; }
bool operator == (const IntType<Type,Size> &o) const { return (Type) v == (Type) o.v; }
bool operator != (const IntType<Type,Size> &o) const { return !(*this == o); }
HB_INTERNAL static int cmp (const IntType<Type,Size> *a, const IntType<Type,Size> *b)
bool operator == (const IntType &o) const { return (Type) v == (Type) o.v; }
bool operator != (const IntType &o) const { return !(*this == o); }
HB_INTERNAL static int cmp (const IntType *a, const IntType *b)
{ return b->cmp (*a); }
template <typename Type2>
int cmp (Type2 a) const
@ -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);
};
@ -146,7 +146,7 @@ struct LONGDATETIME
* system, feature, or baseline */
struct Tag : HBUINT32
{
Tag& operator = (uint32_t i) { HBUINT32::operator= (i); return *this; }
Tag& operator = (hb_tag_t i) { HBUINT32::operator= (i); return *this; }
/* What the char* converters return is NOT nul-terminated. Print using "%.4s" */
operator const char* () const { return reinterpret_cast<const char *> (&this->v); }
operator char* () { return reinterpret_cast<char *> (&this->v); }
@ -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];
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);
}
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 = 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 &not_found = Crap (Type))
{ return *as_array ().bsearch (x, &not_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)...)))

View File

@ -27,6 +27,7 @@
#define HB_OT_CFF_COMMON_HH
#include "hb-open-type.hh"
#include "hb-bimap.hh"
#include "hb-ot-layout-common.hh"
#include "hb-cff-interp-dict-common.hh"
#include "hb-subset-plan.hh"
@ -39,14 +40,14 @@ using namespace OT;
/* utility macro */
template<typename Type>
static inline const Type& StructAtOffsetOrNull(const void *P, unsigned int offset)
{ return offset? (* reinterpret_cast<const Type*> ((const char *) P + offset)): Null(Type); }
static inline const Type& StructAtOffsetOrNull (const void *P, unsigned int offset)
{ return offset ? StructAtOffset<Type> (P, offset) : Null (Type); }
inline unsigned int calcOffSize(unsigned int dataSize)
inline unsigned int calcOffSize (unsigned int dataSize)
{
unsigned int size = 1;
unsigned int offset = dataSize + 1;
while ((offset & ~0xFF) != 0)
while (offset & ~0xFF)
{
size++;
offset >>= 8;
@ -82,27 +83,17 @@ struct str_buff_vec_t : hb_vector_t<str_buff_t>
template <typename COUNT>
struct CFFIndex
{
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (likely ((count.sanitize (c) && count == 0) || /* empty INDEX */
(c->check_struct (this) && offSize >= 1 && offSize <= 4 &&
c->check_array (offsets, offSize, count + 1) &&
c->check_array ((const HBUINT8*)data_base (), 1, max_offset () - 1))));
}
static unsigned int calculate_offset_array_size (unsigned int offSize, unsigned int count)
{ return offSize * (count + 1); }
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;
if (count == 0) return COUNT::static_size;
return min_size + calculate_offset_array_size (offSize_, count) + dataSize;
}
bool serialize (hb_serialize_context_t *c, const CFFIndex &src)
@ -132,7 +123,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 */
@ -166,9 +157,7 @@ struct CFFIndex
byteArray.init ();
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 ();
return result;
@ -199,37 +188,38 @@ struct CFFIndex
unsigned int length_at (unsigned int index) const
{
if (likely ((offset_at (index + 1) >= offset_at (index)) &&
(offset_at (index + 1) <= offset_at (count))))
return offset_at (index + 1) - offset_at (index);
else
if (unlikely ((offset_at (index + 1) < offset_at (index)) ||
(offset_at (index + 1) > offset_at (count))))
return 0;
return offset_at (index + 1) - offset_at (index);
}
const unsigned char *data_base () const
{ return (const unsigned char *)this + min_size + offset_array_size (); }
{ return (const unsigned char *) this + min_size + offset_array_size (); }
unsigned int data_size () const { return HBINT8::static_size; }
byte_str_t operator [] (unsigned int index) const
{
if (likely (index < count))
if (unlikely (index >= count)) return Null (byte_str_t);
return byte_str_t (data_base () + offset_at (index) - 1, length_at (index));
else
return Null(byte_str_t);
}
unsigned int get_size () const
{
if (this != &Null(CFFIndex))
{
if (this == &Null (CFFIndex)) return 0;
if (count > 0)
return min_size + offset_array_size () + (offset_at (count) - 1);
else
return count.static_size; /* empty CFFIndex contains count only */
}
else
return 0;
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (likely ((c->check_struct (this) && count == 0) || /* empty INDEX */
(c->check_struct (this) && offSize >= 1 && offSize <= 4 &&
c->check_array (offsets, offSize, count + 1) &&
c->check_array ((const HBUINT8*) data_base (), 1, max_offset () - 1))));
}
protected:
@ -277,7 +267,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 */
@ -334,10 +324,9 @@ struct Dict : UnsizedByteStr
{
TRACE_SERIALIZE (this);
for (unsigned int i = 0; i < dictval.get_count (); i++)
{
if (unlikely (!opszr.serialize (c, dictval[i], param)))
return_trace (false);
}
return_trace (true);
}
@ -391,14 +380,10 @@ struct Dict : UnsizedByteStr
{ return serialize_int_op<HBUINT16, 0, 0x7FFF> (c, op, value, OpCode_shortint); }
static bool serialize_offset4_op (hb_serialize_context_t *c, op_code_t op, int value)
{
return serialize_uint4_op (c, op, value);
}
{ return serialize_uint4_op (c, op, value); }
static bool serialize_offset2_op (hb_serialize_context_t *c, op_code_t op, int value)
{
return serialize_uint2_op (c, op, value);
}
{ return serialize_uint2_op (c, op, value); }
};
struct TopDict : Dict {};
@ -428,7 +413,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 */
@ -457,7 +442,7 @@ struct FDArray : CFFIndexOf<COUNT, FontDict>
unsigned int offSize_,
const hb_vector_t<DICTVAL> &fontDicts,
unsigned int fdCount,
const hb_bimap_t &fdmap,
const hb_inc_bimap_t &fdmap,
OP_SERIALIZER& opszr,
const hb_vector_t<table_info_t> &privateInfos)
{
@ -465,7 +450,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 */
@ -496,7 +481,7 @@ struct FDArray : CFFIndexOf<COUNT, FontDict>
static unsigned int calculate_serialized_size (unsigned int &offSize_ /* OUT */,
const hb_vector_t<DICTVAL> &fontDicts,
unsigned int fdCount,
const hb_bimap_t &fdmap,
const hb_inc_bimap_t &fdmap,
OP_SERIALIZER& opszr)
{
unsigned int dictsSize = 0;
@ -524,9 +509,7 @@ struct FDSelect0 {
}
hb_codepoint_t get_fd (hb_codepoint_t glyph) const
{
return (hb_codepoint_t)fds[glyph];
}
{ return (hb_codepoint_t) fds[glyph]; }
unsigned int get_size (unsigned int num_glyphs) const
{ return HBUINT8::static_size * num_glyphs; }
@ -537,7 +520,8 @@ struct FDSelect0 {
};
template <typename GID_TYPE, typename FD_TYPE>
struct FDSelect3_4_Range {
struct FDSelect3_4_Range
{
bool sanitize (hb_sanitize_context_t *c, const void * /*nullptr*/, unsigned int fdcount) const
{
TRACE_SANITIZE (this);
@ -546,12 +530,13 @@ struct FDSelect3_4_Range {
GID_TYPE first;
FD_TYPE fd;
public:
DEFINE_SIZE_STATIC (GID_TYPE::static_size + FD_TYPE::static_size);
};
template <typename GID_TYPE, typename FD_TYPE>
struct FDSelect3_4 {
struct FDSelect3_4
{
unsigned int get_size () const
{ return GID_TYPE::static_size * 2 + ranges.get_size (); }
@ -563,10 +548,8 @@ struct FDSelect3_4 {
return_trace (false);
for (unsigned int i = 1; i < nRanges (); i++)
{
if (unlikely (ranges[i - 1].first >= ranges[i].first))
return_trace (false);
}
if (unlikely (!sentinel().sanitize (c) || (sentinel() != c->get_num_glyphs ())))
return_trace (false);
@ -598,17 +581,8 @@ struct FDSelect3_4 {
typedef FDSelect3_4<HBUINT16, HBUINT8> FDSelect3;
typedef FDSelect3_4_Range<HBUINT16, HBUINT8> FDSelect3_Range;
struct FDSelect {
bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) && (format == 0 || format == 3) &&
(format == 0)?
u.format0.sanitize (c, fdcount):
u.format3.sanitize (c, fdcount)));
}
struct FDSelect
{
bool serialize (hb_serialize_context_t *c, const FDSelect &src, unsigned int num_glyphs)
{
TRACE_SERIALIZE (this);
@ -624,22 +598,38 @@ struct FDSelect {
unsigned int get_size (unsigned int num_glyphs) const
{
unsigned int size = format.static_size;
if (format == 0)
size += u.format0.get_size (num_glyphs);
else
size += u.format3.get_size ();
return size;
switch (format)
{
case 0: return format.static_size + u.format0.get_size (num_glyphs);
case 3: return format.static_size + u.format3.get_size ();
default:return 0;
}
}
hb_codepoint_t get_fd (hb_codepoint_t glyph) const
{
if (this == &Null(FDSelect))
if (this == &Null (FDSelect))
return 0;
if (format == 0)
return u.format0.get_fd (glyph);
else
return u.format3.get_fd (glyph);
switch (format)
{
case 0: return u.format0.get_fd (glyph);
case 3: return u.format3.get_fd (glyph);
default:return 0;
}
}
bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const
{
TRACE_SANITIZE (this);
if (unlikely (!c->check_struct (this)))
return_trace (false);
switch (format)
{
case 0: return_trace (u.format0.sanitize (c, fdcount));
case 3: return_trace (u.format3.sanitize (c, fdcount));
default:return_trace (false);
}
}
HBUINT8 format;
@ -647,7 +637,7 @@ struct FDSelect {
FDSelect0 format0;
FDSelect3 format3;
} u;
public:
DEFINE_SIZE_MIN (1);
};

View File

@ -24,6 +24,10 @@
* Adobe Author(s): Michiharu Ariza
*/
#include "hb.hh"
#ifndef HB_NO_CFF
#include "hb-ot-cff1-table.hh"
#include "hb-cff1-interp-cs.hh"
@ -206,7 +210,7 @@ struct bounds_t
point_t max;
};
struct extents_param_t
struct cff1_extents_param_t
{
void init (const OT::cff1::accelerator_t *_cff)
{
@ -225,15 +229,15 @@ struct extents_param_t
const OT::cff1::accelerator_t *cff;
};
struct cff1_path_procs_extents_t : path_procs_t<cff1_path_procs_extents_t, cff1_cs_interp_env_t, extents_param_t>
struct cff1_path_procs_extents_t : path_procs_t<cff1_path_procs_extents_t, cff1_cs_interp_env_t, cff1_extents_param_t>
{
static void moveto (cff1_cs_interp_env_t &env, extents_param_t& param, const point_t &pt)
static void moveto (cff1_cs_interp_env_t &env, cff1_extents_param_t& param, const point_t &pt)
{
param.end_path ();
env.moveto (pt);
}
static void line (cff1_cs_interp_env_t &env, extents_param_t& param, const point_t &pt1)
static void line (cff1_cs_interp_env_t &env, cff1_extents_param_t& param, const point_t &pt1)
{
if (!param.is_path_open ())
{
@ -244,7 +248,7 @@ struct cff1_path_procs_extents_t : path_procs_t<cff1_path_procs_extents_t, cff1_
param.bounds.update (env.get_pt ());
}
static void curve (cff1_cs_interp_env_t &env, extents_param_t& param, const point_t &pt1, const point_t &pt2, const point_t &pt3)
static void curve (cff1_cs_interp_env_t &env, cff1_extents_param_t& param, const point_t &pt1, const point_t &pt2, const point_t &pt3)
{
if (!param.is_path_open ())
{
@ -261,9 +265,9 @@ struct cff1_path_procs_extents_t : path_procs_t<cff1_path_procs_extents_t, cff1_
static bool _get_bounds (const OT::cff1::accelerator_t *cff, hb_codepoint_t glyph, bounds_t &bounds, bool in_seac=false);
struct cff1_cs_opset_extents_t : cff1_cs_opset_t<cff1_cs_opset_extents_t, extents_param_t, cff1_path_procs_extents_t>
struct cff1_cs_opset_extents_t : cff1_cs_opset_t<cff1_cs_opset_extents_t, cff1_extents_param_t, cff1_path_procs_extents_t>
{
static void process_seac (cff1_cs_interp_env_t &env, extents_param_t& param)
static void process_seac (cff1_cs_interp_env_t &env, cff1_extents_param_t& param)
{
unsigned int n = env.argStack.get_count ();
point_t delta;
@ -292,11 +296,11 @@ bool _get_bounds (const OT::cff1::accelerator_t *cff, hb_codepoint_t glyph, boun
if (unlikely (!cff->is_valid () || (glyph >= cff->num_glyphs))) return false;
unsigned int fd = cff->fdSelect->get_fd (glyph);
cff1_cs_interpreter_t<cff1_cs_opset_extents_t, extents_param_t> interp;
cff1_cs_interpreter_t<cff1_cs_opset_extents_t, cff1_extents_param_t> interp;
const byte_str_t str = (*cff->charStrings)[glyph];
interp.env.init (str, *cff, fd);
interp.env.set_in_seac (in_seac);
extents_param_t param;
cff1_extents_param_t param;
param.init (cff);
if (unlikely (!interp.interpret (param))) return false;
bounds = param.bounds;
@ -305,6 +309,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 +392,6 @@ bool OT::cff1::accelerator_t::get_seac_components (hb_codepoint_t glyph, hb_code
}
return false;
}
#endif

View File

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

View File

@ -24,12 +24,16 @@
* Adobe Author(s): Michiharu Ariza
*/
#include "hb.hh"
#ifndef HB_NO_OT_FONT_CFF
#include "hb-ot-cff2-table.hh"
#include "hb-cff2-interp-cs.hh"
using namespace CFF;
struct extents_param_t
struct cff2_extents_param_t
{
void init ()
{
@ -59,15 +63,15 @@ struct extents_param_t
number_t max_y;
};
struct cff2_path_procs_extents_t : path_procs_t<cff2_path_procs_extents_t, cff2_cs_interp_env_t, extents_param_t>
struct cff2_path_procs_extents_t : path_procs_t<cff2_path_procs_extents_t, cff2_cs_interp_env_t, cff2_extents_param_t>
{
static void moveto (cff2_cs_interp_env_t &env, extents_param_t& param, const point_t &pt)
static void moveto (cff2_cs_interp_env_t &env, cff2_extents_param_t& param, const point_t &pt)
{
param.end_path ();
env.moveto (pt);
}
static void line (cff2_cs_interp_env_t &env, extents_param_t& param, const point_t &pt1)
static void line (cff2_cs_interp_env_t &env, cff2_extents_param_t& param, const point_t &pt1)
{
if (!param.is_path_open ())
{
@ -78,7 +82,7 @@ struct cff2_path_procs_extents_t : path_procs_t<cff2_path_procs_extents_t, cff2_
param.update_bounds (env.get_pt ());
}
static void curve (cff2_cs_interp_env_t &env, extents_param_t& param, const point_t &pt1, const point_t &pt2, const point_t &pt3)
static void curve (cff2_cs_interp_env_t &env, cff2_extents_param_t& param, const point_t &pt1, const point_t &pt2, const point_t &pt3)
{
if (!param.is_path_open ())
{
@ -93,21 +97,26 @@ struct cff2_path_procs_extents_t : path_procs_t<cff2_path_procs_extents_t, cff2_
}
};
struct cff2_cs_opset_extents_t : cff2_cs_opset_t<cff2_cs_opset_extents_t, extents_param_t, cff2_path_procs_extents_t> {};
struct cff2_cs_opset_extents_t : cff2_cs_opset_t<cff2_cs_opset_extents_t, cff2_extents_param_t, cff2_path_procs_extents_t> {};
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;
const int *coords = hb_font_get_var_coords_normalized (font, &num_coords);
unsigned int fd = fdSelect->get_fd (glyph);
cff2_cs_interpreter_t<cff2_cs_opset_extents_t, extents_param_t> interp;
cff2_cs_interpreter_t<cff2_cs_opset_extents_t, cff2_extents_param_t> interp;
const byte_str_t str = (*charStrings)[glyph];
interp.env.init (str, *this, fd, coords, num_coords);
extents_param_t param;
cff2_extents_param_t param;
param.init ();
if (unlikely (!interp.interpret (param))) return false;
@ -134,3 +143,6 @@ bool OT::cff2::accelerator_t::get_extents (hb_font_t *font,
return true;
}
#endif

View File

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

View File

@ -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);
}
@ -756,10 +756,12 @@ struct CmapSubtable
hb_codepoint_t *glyph) const
{
switch (u.format) {
#ifndef HB_NO_CMAP_LEGACY_SUBTABLES
case 0: return u.format0 .get_glyph (codepoint, glyph);
case 4: return u.format4 .get_glyph (codepoint, glyph);
case 6: return u.format6 .get_glyph (codepoint, glyph);
case 10: return u.format10.get_glyph (codepoint, glyph);
#endif
case 4: return u.format4 .get_glyph (codepoint, glyph);
case 12: return u.format12.get_glyph (codepoint, glyph);
case 13: return u.format13.get_glyph (codepoint, glyph);
case 14:
@ -769,10 +771,12 @@ struct CmapSubtable
void collect_unicodes (hb_set_t *out) const
{
switch (u.format) {
#ifndef HB_NO_CMAP_LEGACY_SUBTABLES
case 0: u.format0 .collect_unicodes (out); return;
case 4: u.format4 .collect_unicodes (out); return;
case 6: u.format6 .collect_unicodes (out); return;
case 10: u.format10.collect_unicodes (out); return;
#endif
case 4: u.format4 .collect_unicodes (out); return;
case 12: u.format12.collect_unicodes (out); return;
case 13: u.format13.collect_unicodes (out); return;
case 14:
@ -785,10 +789,12 @@ struct CmapSubtable
TRACE_SANITIZE (this);
if (!u.format.sanitize (c)) return_trace (false);
switch (u.format) {
#ifndef HB_NO_CMAP_LEGACY_SUBTABLES
case 0: return_trace (u.format0 .sanitize (c));
case 4: return_trace (u.format4 .sanitize (c));
case 6: return_trace (u.format6 .sanitize (c));
case 10: return_trace (u.format10.sanitize (c));
#endif
case 4: return_trace (u.format4 .sanitize (c));
case 12: return_trace (u.format12.sanitize (c));
case 13: return_trace (u.format13.sanitize (c));
case 14: return_trace (u.format14.sanitize (c));
@ -799,10 +805,12 @@ struct CmapSubtable
public:
union {
HBUINT16 format; /* Format identifier */
#ifndef HB_NO_CMAP_LEGACY_SUBTABLES
CmapSubtableFormat0 format0;
CmapSubtableFormat4 format4;
CmapSubtableFormat6 format6;
CmapSubtableFormat10 format10;
#endif
CmapSubtableFormat4 format4;
CmapSubtableFormat12 format12;
CmapSubtableFormat13 format13;
CmapSubtableFormat14 format14;
@ -848,11 +856,16 @@ struct cmap
size_t final_size () const
{
return 4 // header
+ 8 * 3 // 3 EncodingRecord
+ 8 * num_enc_records
+ CmapSubtableFormat4::get_sub_table_size (this->format4_segments)
+ CmapSubtableFormat12::get_sub_table_size (this->format12_groups);
}
unsigned int num_enc_records;
bool has_unicode_bmp;
bool has_unicode_ucs4;
bool has_ms_bmp;
bool has_ms_ucs4;
hb_sorted_vector_t<CmapSubtableFormat4::segment_plan> format4_segments;
hb_sorted_vector_t<CmapSubtableLongGroup> format12_groups;
};
@ -860,9 +873,16 @@ struct cmap
bool _create_plan (const hb_subset_plan_t *plan,
subset_plan *cmap_plan) const
{
cmap_plan->has_unicode_bmp = find_subtable (0, 3);
cmap_plan->has_unicode_ucs4 = find_subtable (0, 4);
cmap_plan->has_ms_bmp = find_subtable (3, 1);
cmap_plan->has_ms_ucs4 = find_subtable (3, 10);
cmap_plan->num_enc_records = cmap_plan->has_unicode_bmp + cmap_plan->has_unicode_ucs4 + cmap_plan->has_ms_bmp + cmap_plan->has_ms_ucs4;
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,30 +901,60 @@ struct cmap
table->version = 0;
if (unlikely (!table->encodingRecord.serialize (&c, /* numTables */ 3)))
return false;
if (unlikely (!table->encodingRecord.serialize (&c, cmap_subset_plan.num_enc_records))) return false;
// TODO(grieger): Convert the below to a for loop
int enc_index = 0;
int unicode_bmp_index = 0;
int unicode_ucs4_index = 0;
int ms_bmp_index = 0;
int ms_ucs4_index = 0;
// Format 4, Plat 0 Encoding Record
EncodingRecord &format4_plat0_rec = table->encodingRecord[0];
if (cmap_subset_plan.has_unicode_bmp)
{
unicode_bmp_index = enc_index;
EncodingRecord &format4_plat0_rec = table->encodingRecord[enc_index++];
format4_plat0_rec.platformID = 0; // Unicode
format4_plat0_rec.encodingID = 3;
}
// Format 12, Plat 0 Encoding Record
if (cmap_subset_plan.has_unicode_ucs4)
{
unicode_ucs4_index = enc_index;
EncodingRecord &format12_rec = table->encodingRecord[enc_index++];
format12_rec.platformID = 0; // Unicode
format12_rec.encodingID = 4; // Unicode UCS-4
}
// Format 4, Plat 3 Encoding Record
EncodingRecord &format4_plat3_rec = table->encodingRecord[1];
if (cmap_subset_plan.has_ms_bmp)
{
ms_bmp_index = enc_index;
EncodingRecord &format4_plat3_rec = table->encodingRecord[enc_index++];
format4_plat3_rec.platformID = 3; // Windows
format4_plat3_rec.encodingID = 1; // Unicode BMP
}
// Format 12 Encoding Record
EncodingRecord &format12_rec = table->encodingRecord[2];
// Format 12, Plat 3 Encoding Record
if (cmap_subset_plan.has_ms_ucs4)
{
ms_ucs4_index = enc_index;
EncodingRecord &format12_rec = table->encodingRecord[enc_index++];
format12_rec.platformID = 3; // Windows
format12_rec.encodingID = 10; // Unicode UCS-4
}
// Write out format 4 sub table
{
CmapSubtable &subtable = format4_plat0_rec.subtable.serialize (&c, table);
format4_plat3_rec.subtable = (unsigned int) format4_plat0_rec.subtable;
if (unlikely (!cmap_subset_plan.has_unicode_bmp && !cmap_subset_plan.has_ms_bmp)) return false;
EncodingRecord &format4_rec = cmap_subset_plan.has_unicode_bmp?
table->encodingRecord[unicode_bmp_index]:
table->encodingRecord[ms_bmp_index];
CmapSubtable &subtable = format4_rec.subtable.serialize (&c, table);
if (cmap_subset_plan.has_unicode_bmp && cmap_subset_plan.has_ms_bmp)
table->encodingRecord[ms_bmp_index].subtable = (unsigned int) format4_rec.subtable;
subtable.u.format = 4;
CmapSubtableFormat4 &format4 = subtable.u.format4;
@ -913,8 +963,16 @@ struct cmap
}
// Write out format 12 sub table.
if (cmap_subset_plan.format12_groups)
{
if (unlikely (!cmap_subset_plan.has_unicode_ucs4 && !cmap_subset_plan.has_ms_ucs4)) return false;
EncodingRecord &format12_rec = cmap_subset_plan.has_unicode_ucs4?
table->encodingRecord[unicode_ucs4_index]:
table->encodingRecord[ms_ucs4_index];
CmapSubtable &subtable = format12_rec.subtable.serialize (&c, table);
if (cmap_subset_plan.has_unicode_ucs4 && cmap_subset_plan.has_ms_ucs4)
table->encodingRecord[ms_ucs4_index].subtable = (unsigned int) format12_rec.subtable;
subtable.u.format = 12;
CmapSubtableFormat12 &format12 = subtable.u.format12;
@ -1154,6 +1212,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

View File

@ -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;
}

View File

@ -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:

View File

@ -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>

View File

@ -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);

View File

@ -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. */

View File

@ -25,20 +25,21 @@
* Google Author(s): Sascha Brawer, Behdad Esfahbod
*/
#include "hb-open-type.hh"
#include "hb.hh"
#ifndef HB_NO_COLOR
#include "hb-ot.h"
#include "hb-ot-color-cbdt-table.hh"
#include "hb-ot-color-colr-table.hh"
#include "hb-ot-color-cpal-table.hh"
#include "hb-ot-color-sbix-table.hh"
#include "hb-ot-color-svg-table.hh"
#include "hb-ot-face.hh"
#include "hb-ot.h"
#include <stdlib.h>
#include <string.h>
#include "hb-ot-layout.hh"
/**
* SECTION:hb-ot-color
@ -47,6 +48,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,9 +60,11 @@
/**
* 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
*/
@ -71,10 +76,11 @@ hb_ot_color_has_palettes (hb_face_t *face)
/**
* 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
*/
@ -86,13 +92,16 @@ hb_ot_color_palette_get_count (hb_face_t *face)
/**
* 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
@ -106,10 +115,16 @@ hb_ot_color_palette_get_name_id (hb_face_t *face,
/**
* 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
*/
@ -122,10 +137,12 @@ hb_ot_color_palette_color_get_name_id (hb_face_t *face,
/**
* 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
*/
@ -138,25 +155,22 @@ hb_ot_color_palette_get_flags (hb_face_t *face,
/**
* 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
* @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
*
* Fetches a list of the colors in a color 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.
*
* Retrieves the colors in a color palette.
*
* Returns: the total number of colors in the palette.
* Return value: the total number of colors in the palette
*
* Since: 2.1.0
*/
@ -177,9 +191,11 @@ 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
*/
@ -191,14 +207,17 @@ hb_ot_color_has_layers (hb_face_t *face)
/**
* 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 +225,10 @@ 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);
return face->table.COLR->get_glyph_layers (glyph, start_offset, layer_count, layers);
}
@ -219,11 +238,11 @@ 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
*/
@ -235,12 +254,12 @@ hb_ot_color_has_svg (hb_face_t *face)
/**
* 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
*/
@ -257,11 +276,11 @@ 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
*/
@ -273,14 +292,14 @@ hb_ot_color_has_png (hb_face_t *face)
/**
* 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
*/
@ -297,3 +316,6 @@ hb_ot_color_glyph_reference_png (hb_font_t *font, hb_codepoint_t glyph)
return blob;
}
#endif

Some files were not shown because too many files have changed in this diff Show More