Merge branch 'var-subset' of https://github.com/harfbuzz/harfbuzz into var-subset
This commit is contained in:
commit
a87fbb872b
|
@ -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
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
*.plist
|
|
@ -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)
|
||||
|
|
|
@ -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.
|
27
Makefile.am
27
Makefile.am
|
@ -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
44
NEWS
|
@ -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
|
||||
====================================
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
For the development of HarfBuzz, the Microsoft shaping technology, Uniscribe,
|
||||
as a widely used and tested shaper is used as more-or-less OpenType reference
|
||||
implementation and that specially is important where OpenType specification
|
||||
is or wasn't that clear. For having access to Uniscribe on Linux/macOS these
|
||||
steps are recommended:
|
||||
|
||||
1. Install Wine from your favorite package manager. On Fedora that's `dnf install wine`.
|
||||
|
||||
2. And `mingw-w64` compiler.
|
||||
With `brew` on macOS, you can have it like `brew install mingw-w64`.
|
||||
On Fedora, with `dnf install mingw32-gcc-c++`, or `dnf install mingw64-gcc-c++` for the
|
||||
64-bit Windows.
|
||||
|
||||
3. Install cross-compiled dependency packages. Alternatively see [^1] below.
|
||||
On Fedora that would be `dnf install mingw32-glib2 mingw32-cairo mingw32-freetype`
|
||||
for 32-bit, or `dnf install mingw64-glib2 mingw64-cairo mingw64-freetype` for 64-bit.
|
||||
|
||||
5. `NOCONFIGURE=1 ./autogen.sh && mkdir winbuild && cd winbuild`
|
||||
|
||||
6. Run `../mingw32.sh` for 32-bit build, or `../mingw64.sh` for 64-bit. This configures
|
||||
HarfBuzz for cross-compiling. It enables Uniscribe backend as well.
|
||||
|
||||
7. `make`
|
||||
|
||||
Now you can use hb-shape using `wine util/hb-shape.exe` but if you like to shape with
|
||||
the Microsoft Uniscribe,
|
||||
|
||||
8. Bring a 32bit version of `usp10.dll` for yourself from `C:\Windows\SysWOW64\usp10.dll` of your
|
||||
Windows installation (assuming you have a 64-bit installation, otherwise
|
||||
`C:\Windows\System32\usp10.dll`) that it is not a DirectWrite proxy
|
||||
([for more info](https://en.wikipedia.org/wiki/Uniscribe)).
|
||||
Rule of thumb, your `usp10.dll` should have a size more than 500kb, otherwise
|
||||
it is designed to work with DirectWrite which Wine can't work with its original one.
|
||||
You want a Uniscribe from Windows 7 or older.
|
||||
|
||||
Put the DLL in the folder you are going to run the next command,
|
||||
|
||||
9. `WINEDLLOVERRIDES="usp10=n" wine util/hb-shape.exe fontname.ttf -u 0061,0062,0063 --shaper=uniscribe`
|
||||
|
||||
(`0061,0062,0063` means `abc`, use test/shaping/hb-unicode-decode to generate ones you need)
|
||||
|
||||
|
||||
[^1] Download and put [this](https://drive.google.com/open?id=0B3_fQkxDZZXXbWltRGd5bjVrUDQ)
|
||||
in your `~/.local/i686-w64-mingw32`. Then replace all the instances of
|
||||
`/home/behdad/.local/i586-mingw32msvc` and `/home/behdad/.local/i686-w64-mingw32`
|
||||
with `<$HOME>/.local/i686-w64-mingw32` on that folder.
|
||||
(`<$HOME>` replace it with `/home/XXX` or `/Users/XXX` on macOS)
|
||||
You shouldn't replace the instances of those inside binary files.
|
|
@ -1,40 +0,0 @@
|
|||
For the development of HarfBuzz, the Microsoft shaping technology, Uniscribe,
|
||||
as a widely used and tested shaper is used as more-or-less OpenType reference
|
||||
implementation and that specially is important where OpenType specification
|
||||
is or wasn't that clear. For having access to Uniscribe on Linux/macOS these
|
||||
steps are recommended:
|
||||
|
||||
1. Install Wine from your favorite package manager.
|
||||
|
||||
2. And `mingw-w64` compiler.
|
||||
With `brew` on macOS, you can have it like `brew install mingw-w64`
|
||||
|
||||
3. Download and put [this](https://drive.google.com/open?id=0B3_fQkxDZZXXbWltRGd5bjVrUDQ)
|
||||
on your `~/.local/i686-w64-mingw32`.
|
||||
|
||||
4. Replace all the instances of `/home/behdad/.local/i586-mingw32msvc`
|
||||
and `/home/behdad/.local/i686-w64-mingw32` with `<$HOME>/.local/i686-w64-mingw32`
|
||||
on that folder. (`<$HOME>` replace it with `/home/XXX` or `/Users/XXX` on macOS)
|
||||
|
||||
Probably you shouldn't replace the ones are inside binaries.
|
||||
|
||||
5. `NOCONFIGURE=1 ./autogen.sh && mkdir winbuild && cd winbuild`
|
||||
|
||||
6. `../mingw32.sh --with-uniscribe && cd ..`
|
||||
|
||||
7. `make -Cwinbuild`
|
||||
|
||||
Now you can use hb-shape using `wine winbuild/util/hb-shape.exe` but if you like to
|
||||
to use the original Uniscribe,
|
||||
|
||||
8. Bring a 32bit version of `usp10.dll` for yourself from `C:\Windows\SysWOW64\usp10.dll` of your
|
||||
Windows installation (assuming you have a 64-bit installation, otherwise `C:\Windows\System32\usp10.dll`)
|
||||
that it is not a DirectWrite proxy ([for more info](https://en.wikipedia.org/wiki/Uniscribe)).
|
||||
Rule of thumb, your `usp10.dll` should have a size more than 500kb, otherwise
|
||||
it is designed to work with DirectWrite which Wine can't work with its original one.
|
||||
|
||||
Put the dll on the folder you are going to run the next command,
|
||||
|
||||
9. `WINEDLLOVERRIDES="usp10=n" wine winbuild/util/hb-shape.exe fontname.ttf -u 0061,0062,0063 --shaper=uniscribe`
|
||||
|
||||
(`0061,0062,0063` means `abc`, use test/shaping/hb-unicode-decode to generate ones you need)
|
54
RELEASING.md
54
RELEASING.md
|
@ -46,27 +46,21 @@ HarfBuzz release walk-through checklist:
|
|||
|
||||
10. Build win32 bundle.
|
||||
|
||||
a. Put contents of [this](https://drive.google.com/open?id=0B3_fQkxDZZXXbWltRGd5bjVrUDQ) on your `~/.local/i686-w64-mingw32`,
|
||||
a. Build Win32 binaries. See [README.mingw.md](README.mingw.md).
|
||||
|
||||
b. Run `../mingw32.sh --with-uniscribe` script to configure harfbuzz with mingw
|
||||
in a subdirector (eg. winbuild/),
|
||||
|
||||
c. make
|
||||
|
||||
d. Back in the parent directory, run `./UPDATE.sh`(available below) to build win32
|
||||
bundle.
|
||||
b. Run "make dist-win" to build Win32 bundle.
|
||||
|
||||
11. Copy all artefacts to users.freedesktop.org and move them into
|
||||
`/srv/www.freedesktop.org/www/software/harfbuzz/release` There should be four
|
||||
files. Eg.:
|
||||
```
|
||||
-rw-r--r-- 1 behdad eng 1592693 Jul 18 11:25 harfbuzz-1.4.7.tar.bz2
|
||||
-rw-r--r-- 1 behdad eng 89 Jul 18 11:34 harfbuzz-1.4.7.tar.bz2.sha256
|
||||
-rw-r--r-- 1 behdad eng 339 Jul 18 11:34 harfbuzz-1.4.7.tar.bz2.sha256.asc
|
||||
-rw-r--r-- 1 behdad eng 1592693 Jul 18 11:25 harfbuzz-1.4.7.tar.xz
|
||||
-rw-r--r-- 1 behdad eng 89 Jul 18 11:34 harfbuzz-1.4.7.tar.xz.sha256
|
||||
-rw-r--r-- 1 behdad eng 339 Jul 18 11:34 harfbuzz-1.4.7.tar.xz.sha256.asc
|
||||
-rw-r--r-- 1 behdad eng 2895619 Jul 18 11:34 harfbuzz-1.4.7-win32.zip
|
||||
```
|
||||
|
||||
12. While doing that, quickly double-check the size of the .tar.bz2 and .zip
|
||||
12. While doing that, quickly double-check the size of the .tar.xz and .zip
|
||||
files against their previous releases to make sure nothing bad happened.
|
||||
They should be in the ballpark, perhaps slightly larger. Sometimes they
|
||||
do shrink, that's not by itself a stopper.
|
||||
|
@ -76,39 +70,3 @@ HarfBuzz release walk-through checklist:
|
|||
|
||||
14. Go to GitHub release page [here](https://github.com/harfbuzz/harfbuzz/releases),
|
||||
edit the tag, upload artefacts and NEWS entry and save.
|
||||
|
||||
|
||||
## UPDATE.sh
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
v=$1
|
||||
|
||||
if test "x$v" = x; then
|
||||
echo "usage: UPDATE.sh micro-version"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
dir_prefix=harfbuzz-1.4.
|
||||
dir_suffix=-win32
|
||||
dir=$dir_prefix$v$dir_suffix
|
||||
dir_old=$dir_prefix$((v-1))$dir_suffix
|
||||
if test -d "$dir"; then
|
||||
echo "New dir $dir exists; not overwriting"
|
||||
exit 1
|
||||
fi
|
||||
if ! test -d "$dir_old"; then
|
||||
echo "Old dir $dir_old does NOT exist; aborting"
|
||||
exit 1
|
||||
fi
|
||||
set -ex
|
||||
cp -a "$dir_old" "$dir.tmp"
|
||||
rm -f "$dir.tmp"/GDX32.dll
|
||||
rm -f "$dir.tmp"/usp10.dll
|
||||
cp ../winbuild/src/.libs/libharfbuzz-0.dll{,.def} $dir.tmp/
|
||||
cp ../winbuild/util/.libs/hb-{shape,view}.exe $dir.tmp/
|
||||
i686-w64-mingw32-strip $dir.tmp/{hb-shape.exe,hb-view.exe,libharfbuzz-0.dll}
|
||||
mv $dir.tmp $dir
|
||||
zip -r $dir.zip $dir
|
||||
echo Bundle $dir.zip ready
|
||||
```
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
## Build & Run
|
||||
|
||||
Depending on what area you are working in change or add `HB_DEBUG_<whatever>`.
|
||||
Values defined in `hb-debug.hh`.
|
||||
|
||||
```shell
|
||||
# quick sanity check
|
||||
time (make -j4 CPPFLAGS='-DHB_DEBUG_SUBSET=100' \
|
||||
&& (make -j4 -C test/api check || cat test/api/test-suite.log))
|
||||
|
||||
# slower sanity check
|
||||
time (make -j4 CPPFLAGS='-DHB_DEBUG_SUBSET=100' \
|
||||
&& make -j4 -C src check \
|
||||
&& make -j4 -C test/api check \
|
||||
&& make -j4 -C test/subset check)
|
||||
|
||||
# confirm you didn't break anything else
|
||||
time (make -j4 CPPFLAGS='-DHB_DEBUG_SUBSET=100' \
|
||||
&& make -j4 check)
|
||||
|
||||
# often catches files you didn't add, e.g. test fonts to EXTRA_DIST
|
||||
make distcheck
|
||||
```
|
||||
|
||||
### Run tests with asan
|
||||
|
||||
**NOTE**: this sometimes yields harder to read results than the full fuzzer
|
||||
|
||||
```shell
|
||||
# For nice symbols tell asan how to symoblize. Note that it doesn't like versioned copies like llvm-symbolizer-3.8
|
||||
# export ASAN_SYMBOLIZER_PATH=path to version-less llvm-symbolizer
|
||||
# ex
|
||||
export ASAN_SYMBOLIZER_PATH=/usr/lib/llvm-3.8/bin/llvm-symbolizer
|
||||
|
||||
./configure CC=clang CXX=clang++ CPPFLAGS=-fsanitize=address LDFLAGS=-fsanitize=address
|
||||
# make/run tests as usual
|
||||
```
|
||||
|
||||
### Debug with GDB
|
||||
|
||||
```
|
||||
cd ./util
|
||||
../libtool --mode=execute gdb --args ./hb-subset ...
|
||||
```
|
||||
|
||||
### Enable Debug Logging
|
||||
|
||||
```shell
|
||||
# make clean if you previously build w/o debug logging
|
||||
make CPPFLAGS=-DHB_DEBUG_SUBSET=100
|
||||
```
|
||||
|
||||
## Build and Test via CMake
|
||||
|
||||
Note: You'll need to first install ninja-build via apt-get.
|
||||
|
||||
```shell
|
||||
cd harfbuzz
|
||||
mkdir buid
|
||||
cmake -DHB_CHECK=ON -Bbuild -H. -GNinja && ninja -Cbuild && CTEST_OUTPUT_ON_FAILURE=1 ninja -Cbuild test
|
||||
```
|
||||
## Test with the Fuzzer
|
||||
|
||||
```shell
|
||||
# push your changs to a branch on googlefonts/harfbuzz
|
||||
# In a local copy of oss-fuzz, edit projects/harfbuzz/Dockerfile
|
||||
# Change the git clone to pull your branch
|
||||
|
||||
# Do this periodically
|
||||
sudo python infra/helper.py build_image harfbuzz
|
||||
|
||||
# Do these to update/run
|
||||
sudo python infra/helper.py build_fuzzers --sanitizer address harfbuzz
|
||||
sudo python infra/helper.py run_fuzzer harfbuzz hb-subset-fuzzer
|
||||
```
|
47
appveyor.yml
47
appveyor.yml
|
@ -2,11 +2,13 @@ platform: x64
|
|||
|
||||
environment:
|
||||
matrix:
|
||||
|
||||
- compiler: msvc
|
||||
generator: Visual Studio 14
|
||||
platform: Win32
|
||||
configuration: Debug
|
||||
triplet: x86-windows
|
||||
|
||||
- compiler: msvc
|
||||
generator: Visual Studio 14 Win64
|
||||
platform: x64
|
||||
|
@ -19,10 +21,35 @@ environment:
|
|||
configuration: Debug
|
||||
|
||||
|
||||
# Build only
|
||||
|
||||
#- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2013
|
||||
# compiler: msvc2
|
||||
# generator: Visual Studio 12
|
||||
# platform: Win32
|
||||
# configuration: Release
|
||||
# triplet: x86-windows
|
||||
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
compiler: msvc2
|
||||
generator: Visual Studio 15
|
||||
platform: Win32
|
||||
configuration: Release
|
||||
triplet: x86-windows
|
||||
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
||||
compiler: msvc2
|
||||
generator: Visual Studio 16
|
||||
platform: Win32
|
||||
configuration: Release
|
||||
triplet: x86-windows
|
||||
|
||||
|
||||
- compiler: msys2
|
||||
MINGW_PREFIX: /mingw64
|
||||
MINGW_CHOST: x86_64-w64-mingw32
|
||||
MSYS2_ARCH: x86_64
|
||||
|
||||
- compiler: msys2
|
||||
MINGW_PREFIX: /mingw32
|
||||
MINGW_CHOST: i686-w64-mingw32
|
||||
|
@ -30,30 +57,26 @@ environment:
|
|||
|
||||
|
||||
install:
|
||||
# - 'if "%compiler%"=="msys2" C:\msys64\usr\bin\bash -lc "pacman --noconfirm --force -Sy && pacman --noconfirm --force -S pacman-mirrors && pacman --force -Syu --noconfirm"'
|
||||
- 'if "%compiler%"=="msys2" C:\msys64\usr\bin\bash -lc "pacman --noconfirm --force -S --needed mingw-w64-$MSYS2_ARCH-{gcc,freetype,cairo,icu,gettext,gobject-introspection,gcc,gcc-libs,glib2,graphite2,pkg-config,python2}"'
|
||||
- C:\msys64\usr\bin\bash -lc "pacman --noconfirm -S mingw-w64-x86_64-ragel"
|
||||
- set PATH=%PATH%;C:\msys64\mingw64\bin # msys2 is added just for having "ragel" on PATH
|
||||
- 'if "%compiler%"=="cygwin" %CYGWIN_PREFIX%\setup-%CYGWIN_ARCH%.exe -g -q -P cygwin-devel,libfreetype-devel,libcairo-devel,libicu-devel,gcc,gcc-g++,gobject-introspection,libglib2.0-devel,libgraphite2-devel,pkg-config,python2'
|
||||
- 'if "%compiler%"=="msys2" C:\msys64\usr\bin\bash -lc "pacman --noconfirm --force -S --needed mingw-w64-$MSYS2_ARCH-{gcc,freetype,cairo,icu,gettext,gobject-introspection,gcc,gcc-libs,glib2,graphite2,pkg-config,python2,ragel}"'
|
||||
- 'if "%compiler%"=="msvc" if not "%platform%"=="ARM" vcpkg install glib:%triplet% freetype:%triplet% cairo:%triplet%'
|
||||
|
||||
build_script:
|
||||
- 'if "%compiler%"=="msvc" md build'
|
||||
- 'if "%compiler%"=="msvc" cd build'
|
||||
- 'if "%compiler%"=="msvc" if "%platform%"=="ARM" cmake -Bbuild -H. -DHB_HAVE_UNISCRIBE=ON -DHB_HAVE_DIRECTWRITE=ON -G "%generator%"'
|
||||
- 'if "%compiler%"=="msvc" if not "%platform%"=="ARM" cmake -Bbuild -H. -DHB_HAVE_UNISCRIBE=ON -DHB_HAVE_DIRECTWRITE=ON -DHB_HAVE_GLIB=ON -DHB_HAVE_FREETYPE=ON -DHB_BUILD_UTILS=ON -G "%generator%" -DCMAKE_TOOLCHAIN_FILE=c:/tools/vcpkg/scripts/buildsystems/vcpkg.cmake'
|
||||
|
||||
- 'if "%compiler%"=="msvc" set PATH=%PATH%;C:\Program Files (x86)\MSBuild\14.0\Bin'
|
||||
|
||||
- 'if "%compiler%"=="msvc" if "%platform%"=="ARM" cmake -DHB_HAVE_UNISCRIBE=ON -DHB_HAVE_DIRECTWRITE=ON -G "%generator%" ../'
|
||||
- 'if "%compiler%"=="msvc" if not "%platform%"=="ARM" cmake -DHB_HAVE_UNISCRIBE=ON -DHB_HAVE_DIRECTWRITE=ON -DHB_HAVE_GLIB=ON -DHB_HAVE_FREETYPE=ON -DHB_BUILD_UTILS=ON -G "%generator%" -DCMAKE_TOOLCHAIN_FILE=c:/tools/vcpkg/scripts/buildsystems/vcpkg.cmake ../'
|
||||
|
||||
- 'if "%compiler%"=="msvc" cd build'
|
||||
- 'if "%compiler%"=="msvc" msbuild harfbuzz.sln /p:Configuration=%configuration% /p:Platform=%platform%'
|
||||
- 'if "%compiler%"=="msvc" if not "%platform%"=="ARM" ctest --output-on-failure -C %configuration%'
|
||||
|
||||
- 'if "%compiler%"=="msvc2" cmake -G "%generator%" -Bbuild -H.'
|
||||
- 'if "%compiler%"=="msvc2" cmake --build build --config %configuration%'
|
||||
|
||||
- 'if "%compiler%"=="msys2" C:\msys64\usr\bin\bash -lc "curl https://raw.githubusercontent.com/mirror/mingw-w64/023eb04c396d4e8d8fcf604cfababc53dae13398/mingw-w64-headers/include/dwrite_1.h > %MINGW_PREFIX%/%MINGW_CHOST%/include/dwrite_1.h"'
|
||||
- 'if "%compiler%"=="msys2" C:\msys64\usr\bin\bash -lc "cd $APPVEYOR_BUILD_FOLDER; PATH=$PATH:/mingw64/bin:/mingw32/bin; ./autogen.sh --with-uniscribe --with-freetype --with-glib --with-gobject --with-cairo --with-icu --with-graphite2 --with-directwrite --build=%MINGW_CHOST% --host=%MINGW_CHOST% --prefix=%MINGW_PREFIX%; make -j3 check || .ci/fail.sh"'
|
||||
|
||||
cache:
|
||||
- c:\tools\vcpkg\installed\
|
||||
- '%CYGWIN_PREFIX%\var\cache\setup'
|
||||
|
||||
notifications:
|
||||
- provider: Email
|
||||
|
|
44
configure.ac
44
configure.ac
|
@ -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}
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ SCAN_OPTIONS=--rebuild-types --deprecated-guards="HB_DISABLE_DEPRECATED" \
|
|||
|
||||
# Header files or dirs to ignore when scanning. Use base file/dir names
|
||||
# e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h private_code
|
||||
IGNORE_HFILES=`cd $(top_srcdir)/src; find . -path './hb-*/*.h' | sed 's@^.*/@@'`
|
||||
IGNORE_HFILES=`cd $(top_srcdir)/src; find . -path './*/*.h' | sed 's@^.*/@@'`
|
||||
if HAVE_GOBJECT
|
||||
else
|
||||
IGNORE_HFILES+=hb-gobject.h hb-gobject-enums.h hb-gobject-structs.h
|
||||
|
@ -75,12 +75,14 @@ content_files= \
|
|||
usermanual-what-is-harfbuzz.xml \
|
||||
usermanual-install-harfbuzz.xml \
|
||||
usermanual-getting-started.xml \
|
||||
usermanual-glyph-information.xml \
|
||||
usermanual-shaping-concepts.xml \
|
||||
usermanual-object-model.xml \
|
||||
usermanual-buffers-language-script-and-direction.xml \
|
||||
usermanual-fonts-and-faces.xml \
|
||||
usermanual-clusters.xml \
|
||||
usermanual-opentype-features.xml \
|
||||
usermanual-glyph-information.xml \
|
||||
usermanual-clusters.xml \
|
||||
usermanual-utilities.xml \
|
||||
version.xml
|
||||
|
||||
# SGML files where gtk-doc abbrevations (#GtkWidget) are expanded
|
||||
|
|
|
@ -33,11 +33,12 @@
|
|||
<xi:include href="usermanual-install-harfbuzz.xml"/>
|
||||
<xi:include href="usermanual-getting-started.xml"/>
|
||||
<xi:include href="usermanual-shaping-concepts.xml"/>
|
||||
<xi:include href="usermanual-object-model.xml"/>
|
||||
<xi:include href="usermanual-buffers-language-script-and-direction.xml"/>
|
||||
<xi:include href="usermanual-fonts-and-faces.xml"/>
|
||||
<xi:include href="usermanual-clusters.xml"/>
|
||||
<xi:include href="usermanual-opentype-features.xml"/>
|
||||
<xi:include href="usermanual-glyph-information.xml"/>
|
||||
<xi:include href="usermanual-clusters.xml"/>
|
||||
<xi:include href="usermanual-utilities.xml"/>
|
||||
</part>
|
||||
|
||||
<part>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -7,30 +7,38 @@
|
|||
<chapter id="buffers-language-script-and-direction">
|
||||
<title>Buffers, language, script and direction</title>
|
||||
<para>
|
||||
The input to HarfBuzz is a series of Unicode characters, stored in a
|
||||
The input to the HarfBuzz shaper is a series of Unicode characters, stored in a
|
||||
buffer. In this chapter, we'll look at how to set up a buffer with
|
||||
the text that we want and then customize the properties of the
|
||||
buffer.
|
||||
the text that we want and how to customize the properties of the
|
||||
buffer. We'll also look at a piece of lower-level machinery that
|
||||
you will need to understand before proceeding: the functions that
|
||||
HarfBuzz uses to retrieve Unicode information.
|
||||
</para>
|
||||
<para>
|
||||
After shaping is complete, HarfBuzz puts its output back
|
||||
into the buffer. But getting that output requires setting up a
|
||||
face and a font first, so we will look at that in the next chapter
|
||||
instead of here.
|
||||
</para>
|
||||
<section id="creating-and-destroying-buffers">
|
||||
<title>Creating and destroying buffers</title>
|
||||
<para>
|
||||
As we saw in our <emphasis>Getting Started</emphasis> example, a
|
||||
buffer is created and
|
||||
initialized with <literal>hb_buffer_create()</literal>. This
|
||||
initialized with <function>hb_buffer_create()</function>. This
|
||||
produces a new, empty buffer object, instantiated with some
|
||||
default values and ready to accept your Unicode strings.
|
||||
</para>
|
||||
<para>
|
||||
HarfBuzz manages the memory of objects (such as buffers) that it
|
||||
creates, so you don't have to. When you have finished working on
|
||||
a buffer, you can call <literal>hb_buffer_destroy()</literal>:
|
||||
a buffer, you can call <function>hb_buffer_destroy()</function>:
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_buffer_t *buffer = hb_buffer_create();
|
||||
...
|
||||
hb_buffer_destroy(buffer);
|
||||
</programlisting>
|
||||
hb_buffer_t *buf = hb_buffer_create();
|
||||
...
|
||||
hb_buffer_destroy(buf);
|
||||
</programlisting>
|
||||
<para>
|
||||
This will destroy the object and free its associated memory -
|
||||
unless some other part of the program holds a reference to this
|
||||
|
@ -39,46 +47,364 @@
|
|||
else destroying it, you should increase its reference count:
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
void somefunc(hb_buffer_t *buffer) {
|
||||
buffer = hb_buffer_reference(buffer);
|
||||
...
|
||||
</programlisting>
|
||||
void somefunc(hb_buffer_t *buf) {
|
||||
buf = hb_buffer_reference(buf);
|
||||
...
|
||||
</programlisting>
|
||||
<para>
|
||||
And then decrease it once you're done with it:
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_buffer_destroy(buffer);
|
||||
}
|
||||
</programlisting>
|
||||
hb_buffer_destroy(buf);
|
||||
}
|
||||
</programlisting>
|
||||
<para>
|
||||
While we are on the subject of reference-counting buffers, it is
|
||||
worth noting that an individual buffer can only meaningfully be
|
||||
used by one thread at a time.
|
||||
</para>
|
||||
<para>
|
||||
To throw away all the data in your buffer and start from scratch,
|
||||
call <literal>hb_buffer_reset(buffer)</literal>. If you want to
|
||||
call <function>hb_buffer_reset(buf)</function>. If you want to
|
||||
throw away the string in the buffer but keep the options, you can
|
||||
instead call <literal>hb_buffer_clear_contents(buffer)</literal>.
|
||||
instead call <function>hb_buffer_clear_contents(buf)</function>.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="adding-text-to-the-buffer">
|
||||
<title>Adding text to the buffer</title>
|
||||
<para>
|
||||
Now we have a brand new HarfBuzz buffer. Let's start filling it
|
||||
with text! From HarfBuzz's perspective, a buffer is just a stream
|
||||
of Unicode codepoints, but your input string is probably in one of
|
||||
the standard Unicode character encodings (UTF-8, UTF-16, UTF-32)
|
||||
of Unicode code points, but your input string is probably in one of
|
||||
the standard Unicode character encodings (UTF-8, UTF-16, or
|
||||
UTF-32). HarfBuzz provides convenience functions that accept
|
||||
each of these encodings:
|
||||
<function>hb_buffer_add_utf8()</function>,
|
||||
<function>hb_buffer_add_utf16()</function>, and
|
||||
<function>hb_buffer_add_utf32()</function>. Other than the
|
||||
character encoding they accept, they function identically.
|
||||
</para>
|
||||
<para>
|
||||
You can add UTF-8 text to a buffer by passing in the text array,
|
||||
the array's length, an offset into the array for the first
|
||||
character to add, and the length of the segment to add:
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_buffer_add_utf8 (hb_buffer_t *buf,
|
||||
const char *text,
|
||||
int text_length,
|
||||
unsigned int item_offset,
|
||||
int item_length)
|
||||
</programlisting>
|
||||
<para>
|
||||
So, in practice, you can say:
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_buffer_add_utf8(buf, text, strlen(text), 0, strlen(text));
|
||||
</programlisting>
|
||||
<para>
|
||||
This will append your new characters to
|
||||
<parameter>buf</parameter>, not replace its existing
|
||||
contents. Also, note that you can use <literal>-1</literal> in
|
||||
place of the first instance of <function>strlen(text)</function>
|
||||
if your text array is NULL-terminated. Similarly, you can also use
|
||||
<literal>-1</literal> as the final argument want to add its full
|
||||
contents.
|
||||
</para>
|
||||
<para>
|
||||
Whatever start <parameter>item_offset</parameter> and
|
||||
<parameter>item_length</parameter> you provide, HarfBuzz will also
|
||||
attempt to grab the five characters <emphasis>before</emphasis>
|
||||
the offset point and the five characters
|
||||
<emphasis>after</emphasis> the designated end. These are the
|
||||
before and after "context" segments, which are used internally
|
||||
for HarfBuzz to make shaping decisions. They will not be part of
|
||||
the final output, but they ensure that HarfBuzz's
|
||||
script-specific shaping operations are correct. If there are
|
||||
fewer than five characters available for the before or after
|
||||
contexts, HarfBuzz will just grab what is there.
|
||||
</para>
|
||||
<para>
|
||||
For longer text runs, such as full paragraphs, it might be
|
||||
tempting to only add smaller sub-segments to a buffer and
|
||||
shape them in piecemeal fashion. Generally, this is not a good
|
||||
idea, however, because a lot of shaping decisions are
|
||||
dependent on this context information. For example, in Arabic
|
||||
and other connected scripts, HarfBuzz needs to know the code
|
||||
points before and after each character in order to correctly
|
||||
determine which glyph to return.
|
||||
</para>
|
||||
<para>
|
||||
The safest approach is to add all of the text available, then
|
||||
use <parameter>item_offset</parameter> and
|
||||
<parameter>item_length</parameter> to indicate which characters you
|
||||
want shaped, so that HarfBuzz has access to any context.
|
||||
</para>
|
||||
<para>
|
||||
You can also add Unicode code points directly with
|
||||
<function>hb_buffer_add_codepoints()</function>. The arguments
|
||||
to this function are the same as those for the UTF
|
||||
encodings. But it is particularly important to note that
|
||||
HarfBuzz does not do validity checking on the text that is added
|
||||
to a buffer. Invalid code points will be replaced, but it is up
|
||||
to you to do any deep-sanity checking necessary.
|
||||
</para>
|
||||
|
||||
</section>
|
||||
|
||||
<section id="setting-buffer-properties">
|
||||
<title>Setting buffer properties</title>
|
||||
<para>
|
||||
Buffers containing input characters still need several
|
||||
properties set before HarfBuzz can shape their text correctly.
|
||||
</para>
|
||||
</section>
|
||||
<section id="what-about-the-other-scripts">
|
||||
<title>What about the other scripts?</title>
|
||||
<para>
|
||||
Initially, all buffers are set to the
|
||||
<literal>HB_BUFFER_CONTENT_TYPE_INVALID</literal> content
|
||||
type. After adding text, the buffer should be set to
|
||||
<literal>HB_BUFFER_CONTENT_TYPE_UNICODE</literal> instead, which
|
||||
indicates that it contains un-shaped input
|
||||
characters. After shaping, the buffer will have the
|
||||
<literal>HB_BUFFER_CONTENT_TYPE_GLYPHS</literal> content type.
|
||||
</para>
|
||||
<para>
|
||||
<function>hb_buffer_add_utf8()</function> and the
|
||||
other UTF functions set the content type of their buffer
|
||||
automatically. But if you are reusing a buffer you may want to
|
||||
check its state with
|
||||
<function>hb_buffer_get_content_type(buffer)</function>. If
|
||||
necessary you can set the content type with
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_buffer_set_content_type(buf, HB_BUFFER_CONTENT_TYPE_UNICODE);
|
||||
</programlisting>
|
||||
<para>
|
||||
to prepare for shaping.
|
||||
</para>
|
||||
<para>
|
||||
Buffers also need to carry information about the script,
|
||||
language, and text direction of their contents. You can set
|
||||
these properties individually:
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_buffer_set_direction(buf, HB_DIRECTION_LTR);
|
||||
hb_buffer_set_script(buf, HB_SCRIPT_LATIN);
|
||||
hb_buffer_set_language(buf, hb_language_from_string("en", -1));
|
||||
</programlisting>
|
||||
<para>
|
||||
However, since these properties are often the repeated for
|
||||
multiple text runs, you can also save them in a
|
||||
<literal>hb_segment_properties_t</literal> for reuse:
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_segment_properties_t *savedprops;
|
||||
hb_buffer_get_segment_properties (buf, savedprops);
|
||||
...
|
||||
hb_buffer_set_segment_properties (buf2, savedprops);
|
||||
</programlisting>
|
||||
<para>
|
||||
HarfBuzz also provides getter functions to retrieve a buffer's
|
||||
direction, script, and language properties individually.
|
||||
</para>
|
||||
<para>
|
||||
HarfBuzz recognizes four text directions in
|
||||
<type>hb_direction_t</type>: left-to-right
|
||||
(<literal>HB_DIRECTION_LTR</literal>), right-to-left (<literal>HB_DIRECTION_RTL</literal>),
|
||||
top-to-bottom (<literal>HB_DIRECTION_TTB</literal>), and
|
||||
bottom-to-top (<literal>HB_DIRECTION_BTT</literal>). For the
|
||||
script property, HarfBuzz uses identifiers based on the
|
||||
<ulink
|
||||
url="https://unicode.org/iso15924/">ISO 15924
|
||||
standard</ulink>. For languages, HarfBuzz uses tags based on the
|
||||
<ulink url="https://tools.ietf.org/html/bcp47">IETF BCP 47</ulink> standard.
|
||||
</para>
|
||||
<para>
|
||||
Helper functions are provided to convert character strings into
|
||||
the necessary script and language tag types.
|
||||
</para>
|
||||
<para>
|
||||
Two additional buffer properties to be aware of are the
|
||||
"invisible glyph" and the replacement code point. The
|
||||
replacement code point is inserted into buffer output in place of
|
||||
any invalid code points encountered in the input. By default, it
|
||||
is the Unicode <literal>REPLACEMENT CHARACTER</literal> code
|
||||
point, <literal>U+FFFD</literal> "�". You can change this with
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_buffer_set_replacement_codepoint(buf, replacement);
|
||||
</programlisting>
|
||||
<para>
|
||||
passing in the replacement Unicode code point as the
|
||||
<parameter>replacement</parameter> parameter.
|
||||
</para>
|
||||
<para>
|
||||
The invisible glyph is used to replace all output glyphs that
|
||||
are invisible. By default, the standard space character
|
||||
<literal>U+0020</literal> is used; you can replace this (for
|
||||
example, when using a font that provides script-specific
|
||||
spaces) with
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_buffer_set_invisible_glyph(buf, replacement_glyph);
|
||||
</programlisting>
|
||||
<para>
|
||||
Do note that in the <parameter>replacement_glyph</parameter>
|
||||
parameter, you must provide the glyph ID of the replacement you
|
||||
wish to use, not the Unicode code point.
|
||||
</para>
|
||||
<para>
|
||||
HarfBuzz supports a few additional flags you might want to set
|
||||
on your buffer under certain circumstances. The
|
||||
<literal>HB_BUFFER_FLAG_BOT</literal> and
|
||||
<literal>HB_BUFFER_FLAG_EOT</literal> flags tell HarfBuzz
|
||||
that the buffer represents the beginning or end (respectively)
|
||||
of a text element (such as a paragraph or other block). Knowing
|
||||
this allows HarfBuzz to apply certain contextual font features
|
||||
when shaping, such as initial or final variants in connected
|
||||
scripts.
|
||||
</para>
|
||||
<para>
|
||||
<literal>HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES</literal>
|
||||
tells HarfBuzz not to hide glyphs with the
|
||||
<literal>Default_Ignorable</literal> property in Unicode. This
|
||||
property designates control characters and other non-printing
|
||||
code points, such as joiners and variation selectors. Normally
|
||||
HarfBuzz replaces them in the output buffer with zero-width
|
||||
space glyphs (using the "invisible glyph" property discussed
|
||||
above); setting this flag causes them to be printed, which can
|
||||
be helpful for troubleshooting.
|
||||
</para>
|
||||
<para>
|
||||
Conversely, setting the
|
||||
<literal>HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES</literal> flag
|
||||
tells HarfBuzz to remove <literal>Default_Ignorable</literal>
|
||||
glyphs from the output buffer entirely. Finally, setting the
|
||||
<literal>HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE</literal>
|
||||
flag tells HarfBuzz not to insert the dotted-circle glyph
|
||||
(<literal>U+25CC</literal>, "◌"), which is normally
|
||||
inserted into buffer output when broken character sequences are
|
||||
encountered (such as combining marks that are not attached to a
|
||||
base character).
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="customizing-unicode-functions">
|
||||
<title>Customizing Unicode functions</title>
|
||||
<para>
|
||||
HarfBuzz requires some simple functions for accessing
|
||||
information from the Unicode Character Database (such as the
|
||||
<literal>General_Category</literal> (gc) and
|
||||
<literal>Script</literal> (sc) properties) that is useful
|
||||
for shaping, as well as some useful operations like composing and
|
||||
decomposing code points.
|
||||
</para>
|
||||
<para>
|
||||
HarfBuzz includes its own internal, lightweight set of Unicode
|
||||
functions. At build time, it is also possible to compile support
|
||||
for some other options, such as the Unicode functions provided
|
||||
by GLib or the International Components for Unicode (ICU)
|
||||
library. Generally, this option is only of interest for client
|
||||
programs that have specific integration requirements or that do
|
||||
a significant amount of customization.
|
||||
</para>
|
||||
<para>
|
||||
If your program has access to other Unicode functions, however,
|
||||
such as through a system library or application framework, you
|
||||
might prefer to use those instead of the built-in
|
||||
options. HarfBuzz supports this by implementing its Unicode
|
||||
functions as a set of virtual methods that you can replace —
|
||||
without otherwise affecting HarfBuzz's functionality.
|
||||
</para>
|
||||
<para>
|
||||
The Unicode functions are specified in a structure called
|
||||
<literal>unicode_funcs</literal> which is attached to each
|
||||
buffer. But even though <literal>unicode_funcs</literal> is
|
||||
associated with a <type>hb_buffer_t</type>, the functions
|
||||
themselves are called by other HarfBuzz APIs that access
|
||||
buffers, so it would be unwise for you to hook different
|
||||
functions into different buffers.
|
||||
</para>
|
||||
<para>
|
||||
In addition, you can mark your <literal>unicode_funcs</literal>
|
||||
as immutable by calling
|
||||
<function>hb_unicode_funcs_make_immutable (ufuncs)</function>.
|
||||
This is especially useful if your code is a
|
||||
library or framework that will have its own client programs. By
|
||||
marking your Unicode function choices as immutable, you prevent
|
||||
your own client programs from changing the
|
||||
<literal>unicode_funcs</literal> configuration and introducing
|
||||
inconsistencies and errors downstream.
|
||||
</para>
|
||||
<para>
|
||||
You can retrieve the Unicode-functions configuration for
|
||||
your buffer by calling <function>hb_buffer_get_unicode_funcs()</function>:
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_unicode_funcs_t *ufunctions;
|
||||
ufunctions = hb_buffer_get_unicode_funcs(buf);
|
||||
</programlisting>
|
||||
<para>
|
||||
The current version of <literal>unicode_funcs</literal> uses six functions:
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_unicode_combining_class_func_t</function>:
|
||||
returns the Canonical Combining Class of a code point.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_unicode_general_category_func_t</function>:
|
||||
returns the General Category (gc) of a code point.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_unicode_mirroring_func_t</function>: returns
|
||||
the Mirroring Glyph code point (for bi-directional
|
||||
replacement) of a code point.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_unicode_script_func_t</function>: returns the
|
||||
Script (sc) property of a code point.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_unicode_compose_func_t</function>: returns the
|
||||
canonical composition of a sequence of two code points.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_unicode_decompose_func_t</function>: returns
|
||||
the canonical decomposition of a code point.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>
|
||||
Note, however, that future HarfBuzz releases may alter this set.
|
||||
</para>
|
||||
<para>
|
||||
Each Unicode function has a corresponding setter, with which you
|
||||
can assign a callback to your replacement function. For example,
|
||||
to replace
|
||||
<function>hb_unicode_general_category_func_t</function>, you can call
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_unicode_funcs_set_general_category_func (*ufuncs, func, *user_data, destroy)
|
||||
</programlisting>
|
||||
<para>
|
||||
Virtualizing this set of Unicode functions is primarily intended
|
||||
to improve portability. There is no need for every client
|
||||
program to make the effort to replace the default options, so if
|
||||
you are unsure, do not feel any pressure to customize
|
||||
<literal>unicode_funcs</literal>.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
</chapter>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -246,7 +246,7 @@
|
|||
<listitem>
|
||||
<para>
|
||||
Use <ulink url="https://developer.gnome.org/glib/">GLib</ulink>. <emphasis>(Default = auto)</emphasis>
|
||||
</para>
|
||||
</para>
|
||||
<para>
|
||||
This option enables or disables usage of the GLib
|
||||
library. The default setting is to check for the
|
||||
|
@ -297,7 +297,7 @@
|
|||
<listitem>
|
||||
<para>
|
||||
Use <ulink url="https://www.freedesktop.org/wiki/Software/fontconfig/">Fontconfig</ulink>. <emphasis>(Default = auto)</emphasis>
|
||||
</para>
|
||||
</para>
|
||||
<para>
|
||||
This option enables or disables usage of the Fontconfig
|
||||
library, which provides font-matching functions and
|
||||
|
@ -317,7 +317,7 @@
|
|||
<listitem>
|
||||
<para>
|
||||
Use the <ulink url="http://site.icu-project.org/home">ICU</ulink> library. <emphasis>(Default = auto)</emphasis>
|
||||
</para>
|
||||
</para>
|
||||
<para>
|
||||
This option enables or disables usage of the
|
||||
<emphasis>International Components for
|
||||
|
@ -330,30 +330,12 @@
|
|||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><command>--with-ucdn</command></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Use HarfBuzz's <ulink url="https://github.com/harfbuzz/harfbuzz/tree/master/src/hb-ucdn">built-in UCDN library</ulink>. <emphasis>(Default = auto)</emphasis>
|
||||
</para>
|
||||
<para>
|
||||
The HarfBuzz source tree includes a <emphasis>Unicode
|
||||
Database and Normalization</emphasis> (UCDN) library
|
||||
that provides access to basic character properties in
|
||||
the Unicode Character Database (UCD) as well as low-level
|
||||
normalization functions. HarfBuzz can be built without
|
||||
this UCDN support if the usage of a different UCDN
|
||||
library is desired.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><command>--with-graphite2</command></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Use the <ulink url="http://graphite.sil.org/">Graphite2</ulink> library. <emphasis>(Default = no)</emphasis>
|
||||
</para>
|
||||
</para>
|
||||
<para>
|
||||
This option enables or disables usage of the Graphite2
|
||||
library, which provides support for the Graphite shaping
|
||||
|
@ -367,7 +349,7 @@
|
|||
<listitem>
|
||||
<para>
|
||||
Use the <ulink url="https://www.freetype.org/">FreeType</ulink> library. <emphasis>(Default = auto)</emphasis>
|
||||
</para>
|
||||
</para>
|
||||
<para>
|
||||
This option enables or disables usage of the FreeType
|
||||
font-rendering library. The default setting is to check for the
|
||||
|
@ -384,7 +366,7 @@
|
|||
Use the <ulink
|
||||
url="https://docs.microsoft.com/en-us/windows/desktop/intl/uniscribe">Uniscribe</ulink>
|
||||
library (experimental). <emphasis>(Default = no)</emphasis>
|
||||
</para>
|
||||
</para>
|
||||
<para>
|
||||
This option enables or disables usage of the Uniscribe
|
||||
font-rendering library. Uniscribe is available on
|
||||
|
@ -400,7 +382,7 @@
|
|||
<listitem>
|
||||
<para>
|
||||
Use the <ulink url="https://docs.microsoft.com/en-us/windows/desktop/directwrite/direct-write-portal">DirectWrite</ulink> library (experimental). <emphasis>(Default = no)</emphasis>
|
||||
</para>
|
||||
</para>
|
||||
<para>
|
||||
This option enables or disables usage of the DirectWrite
|
||||
font-rendering library. DirectWrite is available on
|
||||
|
@ -416,7 +398,7 @@
|
|||
<listitem>
|
||||
<para>
|
||||
Use the <ulink url="https://developer.apple.com/documentation/coretext">CoreText</ulink> library. <emphasis>(Default = no)</emphasis>
|
||||
</para>
|
||||
</para>
|
||||
<para>
|
||||
This option enables or disables usage of the CoreText
|
||||
library. CoreText is available on macOS and iOS systems.
|
||||
|
|
|
@ -0,0 +1,258 @@
|
|||
<?xml version="1.0"?>
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
|
||||
<!ENTITY % local.common.attrib "xmlns:xi CDATA #FIXED 'http://www.w3.org/2003/XInclude'">
|
||||
<!ENTITY version SYSTEM "version.xml">
|
||||
]>
|
||||
<chapter id="object-model">
|
||||
<title>The HarfBuzz object model</title>
|
||||
<section id="object-model-intro">
|
||||
<title>An overview of data types in HarfBuzz</title>
|
||||
<para>
|
||||
HarfBuzz features two kinds of data types: non-opaque,
|
||||
pass-by-value types and opaque, heap-allocated types. This kind
|
||||
of separation is common in C libraries that have to provide
|
||||
API/ABI compatibility (almost) indefinitely.
|
||||
</para>
|
||||
<para>
|
||||
<emphasis>Value types:</emphasis> The non-opaque, pass-by-value
|
||||
types include integer types, enums, and small structs. Exposing
|
||||
a struct in the public API makes it impossible to expand the
|
||||
struct in the future. As such, exposing structs is reserved for
|
||||
cases where it’s extremely inefficient to do otherwise.
|
||||
</para>
|
||||
<para>
|
||||
In HarfBuzz, several structs, like <literal>hb_glyph_info_t</literal> and
|
||||
<literal>hb_glyph_position_t</literal>, fall into that efficiency-sensitive
|
||||
category and are non-opaque.
|
||||
</para>
|
||||
<para>
|
||||
For all non-opaque structs where future extensibility may be
|
||||
necessary, reserved members are included to hold space for
|
||||
possible future members. As such, it’s important to provide
|
||||
<function>equal()</function>, and <function>hash()</function>
|
||||
methods for such structs, allowing users of the API do
|
||||
effectively deal with the type without having to
|
||||
adapt their code to future changes.
|
||||
</para>
|
||||
<para>
|
||||
Important value types provided by HarfBuzz include the structs
|
||||
for working with Unicode code points, glyphs, and tags for font
|
||||
tables and features, as well as the enums for many Unicode and
|
||||
OpenType properties.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="object-model-object-types">
|
||||
<title>Objects in HarfBuzz</title>
|
||||
<para>
|
||||
<emphasis>Object types:</emphasis> Opaque struct types are used
|
||||
for what HarfBuzz loosely calls "objects." This doesn’t have
|
||||
much to do with the terminology from object-oriented programming
|
||||
(OOP), although some of the concepts are similar.
|
||||
</para>
|
||||
<para>
|
||||
In HarfBuzz, all object types provide certain
|
||||
lifecycle-management APIs. Objects are reference-counted, and
|
||||
constructed with various <function>create()</function> methods, referenced via
|
||||
<function>reference()</function> and dereferenced using
|
||||
<function>destroy()</function>.
|
||||
</para>
|
||||
<para>
|
||||
For example,
|
||||
the <literal>hb_buffer_t</literal> object has
|
||||
<function>hb_buffer_create()</function> as its constructor,
|
||||
<function>hb_buffer_reference()</function> to reference, and
|
||||
<function>hb_buffer_destroy()</function> to dereference.
|
||||
</para>
|
||||
<para>
|
||||
After construction, each object's properties are accessible only
|
||||
through the setter and getter functions described in the API
|
||||
Reference manual.
|
||||
</para>
|
||||
<para>
|
||||
Key object types provided by HarfBuzz include:
|
||||
</para>
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>
|
||||
<emphasis>blobs</emphasis>, which act as low-level wrappers around binary
|
||||
data. Blobs are typically used to hold the contents of a
|
||||
binary font file.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<emphasis>faces</emphasis>, which represent typefaces from a
|
||||
font file, but without specific parameters (such as size) set.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<emphasis>fonts</emphasis>, which represent instances of a
|
||||
face with all of their parameters specified.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<emphasis>buffers</emphasis>, which hold Unicode code points
|
||||
for characters (before shaping) and the shaped glyph output
|
||||
(after shaping).
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<emphasis>shape plans</emphasis>, which store the settings
|
||||
that HarfBuzz will use when shaping a particular text
|
||||
segment. Shape plans are not generally used by client
|
||||
programs directly, but as we will see in a later chapter,
|
||||
they are still valuable to understand.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
<section id="object-model-lifecycle">
|
||||
<title>Object lifecycle management</title>
|
||||
<para>
|
||||
Each object type in HarfBuzz provides a
|
||||
<function>create()</function> method. Some object types provide
|
||||
additional variants of <function>create()</function> to handle
|
||||
special cases or to speed up common tasks; those variants are
|
||||
documented in the API reference. For example,
|
||||
<function>hb_blob_create_from_file()</function> constructs a new
|
||||
blob directly from the contents of a file.
|
||||
</para>
|
||||
<para>
|
||||
All objects are created with an initial reference count of
|
||||
<literal>1</literal>. Client programs can increase the reference
|
||||
count on an object by calling its
|
||||
<function>reference()</function> method. Whenever a client
|
||||
program is finished with an object, it should call its
|
||||
corresponding <function>destroy()</function> method. The destroy
|
||||
method will decrease the reference count on the object and,
|
||||
whenever the reference count reaches zero, it will also destroy
|
||||
the object and free all of the associated memory.
|
||||
</para>
|
||||
<para>
|
||||
All of HarfBuzz's object-lifecycle-management APIs are
|
||||
thread-safe (unless you compiled HarfBuzz from source with the
|
||||
<literal>HB_NO_MT</literal> configuration flag), even when the
|
||||
object as a whole is not thread-safe.
|
||||
It is also permissible to <function>reference()</function> or to
|
||||
<function>destroy()</function> the <literal>NULL</literal>
|
||||
value.
|
||||
</para>
|
||||
<para>
|
||||
Some objects are thread-safe after they have been constructed
|
||||
and set up. The general pattern is to
|
||||
<function>create()</function> the object, make a few
|
||||
<function>set_*()</function> calls to set up the
|
||||
object, and then use it without further modification.
|
||||
</para>
|
||||
<para>
|
||||
To ensure that such an object is not modified, client programs
|
||||
can explicitly mark an object as immutable. HarfBuzz provides
|
||||
<function>make_immutable()</function> methods to mark an object
|
||||
as immutable and <function>is_immutable()</function> methods to
|
||||
test whether or not an object is immutable. Attempts to use
|
||||
setter functions on immutable objects will fail silently; see the API
|
||||
Reference manual for specifics.
|
||||
</para>
|
||||
<para>
|
||||
Note also that there are no "make mutable" methods. If client
|
||||
programs need to alter an object previously marked as immutable,
|
||||
they will need to make a duplicate of the original.
|
||||
</para>
|
||||
<para>
|
||||
Finally, object constructors (and, indeed, as much of the
|
||||
shaping API as possible) will never return
|
||||
<literal>NULL</literal>. Instead, if there is an allocation
|
||||
error, each constructor will return an “empty” object
|
||||
singleton.
|
||||
</para>
|
||||
<para>
|
||||
These empty-object singletons are inert and safe (although
|
||||
typically useless) to pass around. This design choice avoids
|
||||
having to check for <literal>NULL</literal> pointers all
|
||||
throughout the code.
|
||||
</para>
|
||||
<para>
|
||||
In addition, this “empty” object singleton can also be accessed
|
||||
using the <function>get_empty()</function> method of the object
|
||||
type in question.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
|
||||
<section id="object-model-user-data">
|
||||
<title>User data</title>
|
||||
<para>
|
||||
To better integrate with client programs, HarfBuzz's objects
|
||||
offer a "user data" mechanism that can be used to attach
|
||||
arbitrary data to the object. User-data attachment can be
|
||||
useful for tying the lifecycles of various pieces of data
|
||||
together, or for creating language bindings.
|
||||
</para>
|
||||
<para>
|
||||
Each object type has a <function>set_user_data()</function>
|
||||
method and a <function>get_user_data()</function> method. The
|
||||
<function>set_user_data()</function> methods take a client-provided
|
||||
<literal>key</literal> and a pointer,
|
||||
<literal>user_data</literal>, pointing to the data itself. Once
|
||||
the key-data pair has been attached to the object, the
|
||||
<function>get_user_data()</function> method can be called with
|
||||
the key, returning the <function>user_data</function> pointer.
|
||||
</para>
|
||||
<para>
|
||||
The <function>set_user_data()</function> methods also support an
|
||||
optional <function>destroy</function> callback. Client programs
|
||||
can set the <function>destroy</function> callback and receive
|
||||
notification from HarfBuzz whenever the object is destructed.
|
||||
</para>
|
||||
<para>
|
||||
Finally, each <function>set_user_data()</function> method allows
|
||||
the client program to set a <literal>replace</literal> Boolean
|
||||
indicating whether or not the function call should replace any
|
||||
existing <literal>user_data</literal>
|
||||
associated with the specified key.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
<section id="object-model-blobs">
|
||||
<title>Blobs</title>
|
||||
<para>
|
||||
While most of HarfBuzz's object types are specific to the
|
||||
shaping process, <emphasis>blobs</emphasis> are somewhat
|
||||
different.
|
||||
</para>
|
||||
<para>
|
||||
Blobs are an abstraction desgined to negotiate lifecycle and
|
||||
permissions for raw pieces of data. For example, when you load
|
||||
the raw font data into memory and want to pass it to HarfBuzz,
|
||||
you do so in a <literal>hb_blob_t</literal> wrapper.
|
||||
</para>
|
||||
<para>
|
||||
This allows you to take advantage of HarffBuzz's
|
||||
reference-counting and <function>destroy</function>
|
||||
callbacks. If you allocated the memory for the data using
|
||||
<function>malloc()</function>, you would create the blob using
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_blob_create (data, length, HB_MEMORY_MODE_WRITABLE, NULL, free)
|
||||
</programlisting>
|
||||
<para>
|
||||
That way, HarfBuzz will call <function>free()</function> on the
|
||||
allocated memory whenever the blob drops its last reference and
|
||||
is deconstructed. Consequently, the user code can stop worrying
|
||||
about freeing memory and let the reference-counting machinery
|
||||
take care of that.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
</chapter>
|
|
@ -6,14 +6,299 @@
|
|||
]>
|
||||
<chapter id="shaping-and-shape-plans">
|
||||
<title>Shaping and shape plans</title>
|
||||
<section id="opentype-features">
|
||||
<para>
|
||||
Once you have your face and font objects configured as desired and
|
||||
your input buffer is filled with the characters you need to shape,
|
||||
all you need to do is call <function>hb_shape()</function>.
|
||||
</para>
|
||||
<para>
|
||||
HarfBuzz will return the shaped version of the text in the same
|
||||
buffer that you provided, but it will be in output mode. At that
|
||||
point, you can iterate through the glyphs in the buffer, drawing
|
||||
each one at the specified position or handing them off to the
|
||||
appropriate graphics library.
|
||||
</para>
|
||||
<para>
|
||||
For the most part, HarfBuzz's shaping step is straightforward from
|
||||
the outside. But that doesn't mean there will never be cases where
|
||||
you want to look under the hood and see what is happening on the
|
||||
inside. HarfBuzz provides facilities for doing that, too.
|
||||
</para>
|
||||
|
||||
<section id="shaping-buffer-output">
|
||||
<title>Shaping and buffer output</title>
|
||||
<para>
|
||||
The <function>hb_shape()</function> function call takes four arguments: the font
|
||||
object to use, the buffer of characters to shape, an array of
|
||||
user-specified features to apply, and the length of that feature
|
||||
array. The feature array can be NULL, so for the sake of
|
||||
simplicity we will start with that case.
|
||||
</para>
|
||||
<para>
|
||||
Internally, HarfBuzz looks at the tables of the font file to
|
||||
determine where glyph classes, substitutions, and positioning
|
||||
are defined, using that information to decide which
|
||||
<emphasis>shaper</emphasis> to use (<literal>ot</literal> for
|
||||
OpenType fonts, <literal>aat</literal> for Apple Advanced
|
||||
Typography fonts, and so on). It also looks at the direction,
|
||||
script, and language properties of the segment to figure out
|
||||
which script-specific shaping model is needed (at least, in
|
||||
shapers that support multiple options).
|
||||
</para>
|
||||
<para>
|
||||
If a font has a GDEF table, then that is used for
|
||||
glyph classes; if not, HarfBuzz will fall back to Unicode
|
||||
categorization by code point. If a font has an AAT "morx" table,
|
||||
then it is used for substitutions; if not, but there is a GSUB
|
||||
table, then the GSUB table is used. If the font has an AAT
|
||||
"kerx" table, then it is used for positioning; if not, but
|
||||
there is a GPOS table, then the GPOS table is used. If neither
|
||||
table is found, but there is a "kern" table, then HarfBuzz will
|
||||
use the "kern" table. If there is no "kerx", no GPOS, and no
|
||||
"kern", HarfBuzz will fall back to positioning marks itself.
|
||||
</para>
|
||||
<para>
|
||||
With a well-behaved OpenType font, you expect GDEF, GSUB, and
|
||||
GPOS tables to all be applied. HarfBuzz implements the
|
||||
script-specific shaping models in internal functions, rather
|
||||
than in the public API.
|
||||
</para>
|
||||
<para>
|
||||
The algorithms
|
||||
used for complex scripts can be quite involved; HarfBuzz tries
|
||||
to be compatible with the OpenType Layout specification
|
||||
and, wherever there is any ambiguity, HarfBuzz attempts to replicate the
|
||||
output of Microsoft's Uniscribe engine. See the <ulink
|
||||
url="https://docs.microsoft.com/en-us/typography/script-development/standard">Microsoft
|
||||
Typography pages</ulink> for more detail.
|
||||
</para>
|
||||
<para>
|
||||
In general, though, all that you need to know is that
|
||||
<function>hb_shape()</function> returns the results of shaping
|
||||
in the same buffer that you provided. The buffer's content type
|
||||
will now be set to
|
||||
<literal>HB_BUFFER_CONTENT_TYPE_GLYPHS</literal>, indicating
|
||||
that it contains shaped output, rather than input text. You can
|
||||
now extract the glyph information and positioning arrays:
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_glyph_info_t *glyph_info = hb_buffer_get_glyph_infos(buf, &glyph_count);
|
||||
hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions(buf, &glyph_count);
|
||||
</programlisting>
|
||||
<para>
|
||||
The glyph information array holds a <type>hb_glyph_info_t</type>
|
||||
for each output glyph, which has two fields:
|
||||
<parameter>codepoint</parameter> and
|
||||
<parameter>cluster</parameter>. Whereas, in the input buffer,
|
||||
the <parameter>codepoint</parameter> field contained the Unicode
|
||||
code point, it now contains the glyph ID of the corresponding
|
||||
glyph in the font. The <parameter>cluster</parameter> field is
|
||||
an integer that you can use to help identify when shaping has
|
||||
reordered, split, or combined code points; we will say more
|
||||
about that in the next chapter.
|
||||
</para>
|
||||
<para>
|
||||
The glyph positions array holds a corresponding
|
||||
<type>hb_glyph_position_t</type> for each output glyph,
|
||||
containing four fields: <parameter>x_advance</parameter>,
|
||||
<parameter>y_advance</parameter>,
|
||||
<parameter>x_offset</parameter>, and
|
||||
<parameter>y_offset</parameter>. The advances tell you how far
|
||||
you need to move the drawing point after drawing this glyph,
|
||||
depending on whether you are setting horizontal text (in which
|
||||
case you will have x advances) or vertical text (for which you
|
||||
will have y advances). The x and y offsets tell you where to
|
||||
move to start drawing the glyph; usually you will have both and
|
||||
x and a y offset, regardless of the text direction.
|
||||
</para>
|
||||
<para>
|
||||
Most of the time, you will rely on a font-rendering library or
|
||||
other graphics library to do the actual drawing of glyphs, so
|
||||
you will need to iterate through the glyphs in the buffer and
|
||||
pass the corresponding values off.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="shaping-opentype-features">
|
||||
<title>OpenType features</title>
|
||||
<para>
|
||||
OpenType features enable fonts to include smart behavior,
|
||||
implemented as "lookup" rules stored in the GSUB and GPOS
|
||||
tables. The OpenType specification defines a long list of
|
||||
standard features that fonts can use for these behaviors; each
|
||||
feature has a four-character reserved name and a well-defined
|
||||
semantic meaning.
|
||||
</para>
|
||||
<para>
|
||||
Some OpenType features are defined for the purpose of supporting
|
||||
complex-script shaping, and are automatically activated, but
|
||||
only when a buffer's script property is set to a script that the
|
||||
feature supports.
|
||||
</para>
|
||||
<para>
|
||||
Other features are more generic and can apply to several (or
|
||||
any) script, and shaping engines are expected to implement
|
||||
them. By default, HarfBuzz activates several of these features
|
||||
on every text run. They include <literal>ccmp</literal>,
|
||||
<literal>locl</literal>, <literal>mark</literal>,
|
||||
<literal>mkmk</literal>, and <literal>rlig</literal>.
|
||||
</para>
|
||||
<para>
|
||||
In addition, if the text direction is horizontal, HarfBuzz
|
||||
also applies the <literal>calt</literal>,
|
||||
<literal>clig</literal>, <literal>curs</literal>,
|
||||
<literal>kern</literal>, <literal>liga</literal>,
|
||||
<literal>rclt</literal>, and <literal>frac</literal> features.
|
||||
</para>
|
||||
<para>
|
||||
If the text direction is vertical, HarfBuzz applies
|
||||
the <literal>vert</literal> feature by default.
|
||||
</para>
|
||||
<para>
|
||||
Still other features are designed to be purely optional and left
|
||||
up to the application or the end user to enable or disable as desired.
|
||||
</para>
|
||||
<para>
|
||||
You can adjust the set of features that HarfBuzz applies to a
|
||||
buffer by supplying an array of <type>hb_feature_t</type>
|
||||
features as the third argument to
|
||||
<function>hb_shape()</function>. For a simple case, let's just
|
||||
enable the <literal>dlig</literal> feature, which turns on any
|
||||
"discretionary" ligatures in the font:
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_feature_t userfeatures[1];
|
||||
userfeatures[0].tag = HB_TAG('d','l','i','g');
|
||||
userfeatures[0].value = 1;
|
||||
userfeatures[0].start = HB_FEATURE_GLOBAL_START;
|
||||
userfeatures[0].end = HB_FEATURE_GLOBAL_END;
|
||||
</programlisting>
|
||||
<para>
|
||||
<literal>HB_FEATURE_GLOBAL_END</literal> and
|
||||
<literal>HB_FEATURE_GLOBAL_END</literal> are macros we can use
|
||||
to indicate that the features will be applied to the entire
|
||||
buffer. We could also have used a literal <literal>0</literal>
|
||||
for the start and a <literal>-1</literal> to indicate the end of
|
||||
the buffer (or have selected other start and end positions, if needed).
|
||||
</para>
|
||||
<para>
|
||||
When we pass the <varname>userfeatures</varname> array to
|
||||
<function>hb_shape()</function>, any discretionary ligature
|
||||
substitutions from our font that match the text in our buffer
|
||||
will get performed:
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_shape(font, buf, userfeatures, num_features);
|
||||
</programlisting>
|
||||
<para>
|
||||
Just like we enabled the <literal>dlig</literal> feature by
|
||||
setting its <parameter>value</parameter> to
|
||||
<literal>1</literal>, you would disable a feature by setting its
|
||||
<parameter>value</parameter> to <literal>0</literal>. Some
|
||||
features can take other <parameter>value</parameter> settings;
|
||||
be sure you read the full specification of each feature tag to
|
||||
understand what it does and how to control it.
|
||||
</para>
|
||||
</section>
|
||||
<section id="plans-and-caching">
|
||||
|
||||
<section id="shaping-shaper-selection">
|
||||
<title>Shaper selection</title>
|
||||
<para>
|
||||
The basic version of <function>hb_shape()</function> determines
|
||||
its shaping strategy based on examining the capabilities of the
|
||||
font file. OpenType font tables cause HarfBuzz to try the
|
||||
<literal>ot</literal> shaper, while AAT font tables cause HarfBuzz to try the
|
||||
<literal>aat</literal> shaper.
|
||||
</para>
|
||||
<para>
|
||||
In the real world, however, a font might include some unusual
|
||||
mix of tables, or one of the tables might simply be broken for
|
||||
the script you need to shape. So, sometimes, you might not
|
||||
want to rely on HarfBuzz's process for deciding what to do, and
|
||||
just tell <function>hb_shape()</function> what you want it to try.
|
||||
</para>
|
||||
<para>
|
||||
<function>hb_shape_full()</function> is an alternate shaping
|
||||
function that lets you supply a list of shapers for HarfBuzz to
|
||||
try, in order, when shaping your buffer. For example, if you
|
||||
have determined that HarfBuzz's attempts to work around broken
|
||||
tables gives you better results than the AAT shaper itself does,
|
||||
you might move the AAT shaper to the end of your list of
|
||||
preferences and call <function>hb_shape_full()</function>
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
char *shaperprefs[3] = {"ot", "default", "aat"};
|
||||
...
|
||||
hb_shape_full(font, buf, userfeatures, num_features, shaperprefs);
|
||||
</programlisting>
|
||||
<para>
|
||||
to get results you are happier with.
|
||||
</para>
|
||||
<para>
|
||||
You may also want to call
|
||||
<function>hb_shape_list_shapers()</function> to get a list of
|
||||
the shapers that were built at compile time in your copy of HarfBuzz.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="shaping-plans-and-caching">
|
||||
<title>Plans and caching</title>
|
||||
<para>
|
||||
Internally, HarfBuzz uses a structure called a shape plan to
|
||||
track its decisions about how to shape the contents of a
|
||||
buffer. The <function>hb_shape()</function> function builds up the shape plan by
|
||||
examining segment properties and by inspecting the contents of
|
||||
the font.
|
||||
</para>
|
||||
<para>
|
||||
This process can involve some decision-making and
|
||||
trade-offs — for example, HarfBuzz inspects the GSUB and GPOS
|
||||
lookups for the script and language tags set on the segment
|
||||
properties, but it falls back on the lookups under the
|
||||
<literal>DFLT</literal> tag (and sometimes other common tags)
|
||||
if there are actually no lookups for the tag requested.
|
||||
</para>
|
||||
<para>
|
||||
HarfBuzz also includes some work-arounds for
|
||||
handling well-known older font conventions that do not follow
|
||||
OpenType or Unicode specifications, for buggy system fonts, and for
|
||||
peculiarities of Microsoft Uniscribe. All of that means that a
|
||||
shape plan, while not something that you should edit directly in
|
||||
client code, still might be an object that you want to
|
||||
inspect. Furthermore, if resources are tight, you might want to
|
||||
cache the shape plan that HarfBuzz builds for your buffer and
|
||||
font, so that you do not have to rebuild it for every shaping call.
|
||||
</para>
|
||||
<para>
|
||||
You can create a cacheable shape plan with
|
||||
<function>hb_shape_plan_create_cached(face, props,
|
||||
user_features, num_user_features, shaper_list)</function>, where
|
||||
<parameter>face</parameter> is a face object (not a font object,
|
||||
notably), <parameter>props</parameter> is an
|
||||
<type>hb_segment_properties_t</type>,
|
||||
<parameter>user_features</parameter> is an array of
|
||||
<type>hb_feature_t</type>s (with length
|
||||
<parameter>num_user_features</parameter>), and
|
||||
<parameter>shaper_list</parameter> is a list of shapers to try.
|
||||
</para>
|
||||
<para>
|
||||
Shape plans are objects in HarfBuzz, so there are
|
||||
reference-counting functions and user-data attachment functions
|
||||
you can
|
||||
use. <function>hb_shape_plan_reference(shape_plan)</function>
|
||||
increases the reference count on a shape plan, while
|
||||
<function>hb_shape_plan_destroy(shape_plan)</function> decreases
|
||||
the reference count, destroying the shape plan when the last
|
||||
reference is dropped.
|
||||
</para>
|
||||
<para>
|
||||
You can attach user data to a shaper (with a key) using the
|
||||
<function>hb_shape_plan_set_user_data(shape_plan,key,data,destroy,replace)</function>
|
||||
function, optionally supplying a <function>destroy</function>
|
||||
callback to use. You can then fetch the user data attached to a
|
||||
shape plan with
|
||||
<function>hb_shape_plan_get_user_data(shape_plan, key)</function>.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
</chapter>
|
||||
|
|
|
@ -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>
|
|
@ -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 \
|
||||
"$@"
|
|
@ -0,0 +1,58 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# Copied from https://github.com/xantares/mingw-ldd/blob/master/mingw-ldd.py
|
||||
# Modified to point to right prefix location on Fedora.
|
||||
|
||||
# WTFPL - Do What the Fuck You Want to Public License
|
||||
from __future__ import print_function
|
||||
import pefile
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
def get_dependency(filename):
|
||||
deps = []
|
||||
pe = pefile.PE(filename)
|
||||
for imp in pe.DIRECTORY_ENTRY_IMPORT:
|
||||
deps.append(imp.dll.decode())
|
||||
return deps
|
||||
|
||||
|
||||
def dep_tree(root, prefix=None):
|
||||
if not prefix:
|
||||
arch = get_arch(root)
|
||||
#print('Arch =', arch)
|
||||
prefix = '/usr/'+arch+'-w64-mingw32/sys-root/mingw/bin'
|
||||
#print('Using default prefix', prefix)
|
||||
dep_dlls = dict()
|
||||
|
||||
def dep_tree_impl(root, prefix):
|
||||
for dll in get_dependency(root):
|
||||
if dll in dep_dlls:
|
||||
continue
|
||||
full_path = os.path.join(prefix, dll)
|
||||
if os.path.exists(full_path):
|
||||
dep_dlls[dll] = full_path
|
||||
dep_tree_impl(full_path, prefix=prefix)
|
||||
else:
|
||||
dep_dlls[dll] = 'not found'
|
||||
|
||||
dep_tree_impl(root, prefix)
|
||||
return (dep_dlls)
|
||||
|
||||
|
||||
def get_arch(filename):
|
||||
type2arch= {pefile.OPTIONAL_HEADER_MAGIC_PE: 'i686',
|
||||
pefile.OPTIONAL_HEADER_MAGIC_PE_PLUS: 'x86_64'}
|
||||
pe = pefile.PE(filename)
|
||||
try:
|
||||
return type2arch[pe.PE_TYPE]
|
||||
except KeyError:
|
||||
sys.stderr.write('Error: unknown architecture')
|
||||
sys.exit(1)
|
||||
|
||||
if __name__ == '__main__':
|
||||
filename = sys.argv[1]
|
||||
for dll, full_path in dep_tree(filename).items():
|
||||
print(' ' * 7, dll, '=>', full_path)
|
||||
|
24
mingw32.sh
24
mingw32.sh
|
@ -1,22 +1,2 @@
|
|||
#!/bin/bash
|
||||
|
||||
target=i686-w64-mingw32
|
||||
|
||||
unset CC
|
||||
unset CXX
|
||||
unset CPP
|
||||
unset LD
|
||||
unset LDFLAGS
|
||||
unset CFLAGS
|
||||
unset CXXFLAGS
|
||||
unset PKG_CONFIG_PATH
|
||||
|
||||
# Removed -static from the following
|
||||
export CFLAGS="-static-libgcc"
|
||||
export CXXFLAGS="-static-libgcc -static-libstdc++"
|
||||
export CPPFLAGS="-I$HOME/.local/$target/include -O2"
|
||||
export LDFLAGS=-L$HOME/.local/$target/lib
|
||||
export PKG_CONFIG_LIBDIR=$HOME/.local/$target/lib/pkgconfig
|
||||
export PATH=$HOME/.local/$target/bin:$PATH
|
||||
|
||||
../configure --build=`../config.guess` --host=$target --prefix=$HOME/.local/$target "$@"
|
||||
#!/bin/sh
|
||||
exec "$(dirname "$0")"/mingw-configure.sh i686 "$@"
|
||||
|
|
24
mingw64.sh
24
mingw64.sh
|
@ -1,22 +1,2 @@
|
|||
#!/bin/bash
|
||||
|
||||
target=x86_64-w64-mingw32
|
||||
|
||||
unset CC
|
||||
unset CXX
|
||||
unset CPP
|
||||
unset LD
|
||||
unset LDFLAGS
|
||||
unset CFLAGS
|
||||
unset CXXFLAGS
|
||||
unset PKG_CONFIG_PATH
|
||||
|
||||
# Removed -static from the following
|
||||
export CFLAGS="-static-libgcc"
|
||||
export CXXFLAGS="-static-libgcc -static-libstdc++"
|
||||
export CPPFLAGS="-I$HOME/.local/$target/include -O2"
|
||||
export LDFLAGS=-L$HOME/.local/$target/lib
|
||||
export PKG_CONFIG_LIBDIR=$HOME/.local/$target/lib/pkgconfig
|
||||
export PATH=$HOME/.local/$target/bin:$PATH
|
||||
|
||||
../configure --build=`../config.guess` --host=$target --prefix=$HOME/.local/$target "$@"
|
||||
#!/bin/sh
|
||||
exec "$(dirname "$0")"/mingw-configure.sh x86_64 "$@"
|
||||
|
|
|
@ -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 = \
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -7,7 +7,7 @@ test -z "$srcdir" && srcdir=.
|
|||
test -z "$libs" && libs=.libs
|
||||
stat=0
|
||||
|
||||
IGNORED_SYMBOLS='_fini\|_init\|_fdata\|_ftext\|_fbss\|__bss_start\|__bss_start__\|__bss_end__\|_edata\|_end\|_bss_end__\|__end__\|__gcov_flush\|llvm_.*'
|
||||
IGNORED_SYMBOLS='_fini\|_init\|_fdata\|_ftext\|_fbss\|__bss_start\|__bss_start__\|__bss_end__\|_edata\|_end\|_bss_end__\|__end__\|__gcov_.*\|llvm_.*'
|
||||
|
||||
if which nm 2>/dev/null >/dev/null; then
|
||||
:
|
||||
|
|
|
@ -4,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 */")
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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.')
|
|
@ -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 */
|
||||
|
|
|
@ -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 == */')
|
||||
|
|
|
@ -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"
|
|
@ -83,7 +83,7 @@ struct ankr
|
|||
protected:
|
||||
HBUINT16 version; /* Version number (set to zero) */
|
||||
HBUINT16 flags; /* Flags (currently unused; set to zero) */
|
||||
LOffsetTo<Lookup<NNOffsetTo<GlyphAnchors> > >
|
||||
LOffsetTo<Lookup<NNOffsetTo<GlyphAnchors>>>
|
||||
lookupTable; /* Offset to the table's lookup table */
|
||||
LNNOffsetTo<HBUINT8>
|
||||
anchorData; /* Offset to the glyph data table */
|
||||
|
|
|
@ -125,7 +125,7 @@ struct LookupFormat2
|
|||
|
||||
protected:
|
||||
HBUINT16 format; /* Format identifier--format = 2 */
|
||||
VarSizedBinSearchArrayOf<LookupSegmentSingle<T> >
|
||||
VarSizedBinSearchArrayOf<LookupSegmentSingle<T>>
|
||||
segments; /* The actual segments. These must already be sorted,
|
||||
* according to the first word in each one (the last
|
||||
* glyph in each segment). */
|
||||
|
@ -154,7 +154,7 @@ struct LookupSegmentArray
|
|||
valuesZ.sanitize (c, base, last - first + 1));
|
||||
}
|
||||
template <typename ...Ts>
|
||||
bool sanitize (hb_sanitize_context_t *c, const void *base, Ts &&...ds) const
|
||||
bool sanitize (hb_sanitize_context_t *c, const void *base, Ts&&... ds) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (c->check_struct (this) &&
|
||||
|
@ -164,7 +164,7 @@ struct LookupSegmentArray
|
|||
|
||||
GlyphID last; /* Last GlyphID in this segment */
|
||||
GlyphID first; /* First GlyphID in this segment */
|
||||
NNOffsetTo<UnsizedArrayOf<T> >
|
||||
NNOffsetTo<UnsizedArrayOf<T>>
|
||||
valuesZ; /* A 16-bit offset from the start of
|
||||
* the table to the data. */
|
||||
public:
|
||||
|
@ -196,7 +196,7 @@ struct LookupFormat4
|
|||
|
||||
protected:
|
||||
HBUINT16 format; /* Format identifier--format = 4 */
|
||||
VarSizedBinSearchArrayOf<LookupSegmentArray<T> >
|
||||
VarSizedBinSearchArrayOf<LookupSegmentArray<T>>
|
||||
segments; /* The actual segments. These must already be sorted,
|
||||
* according to the first word in each one (the last
|
||||
* glyph in each segment). */
|
||||
|
@ -253,7 +253,7 @@ struct LookupFormat6
|
|||
|
||||
protected:
|
||||
HBUINT16 format; /* Format identifier--format = 6 */
|
||||
VarSizedBinSearchArrayOf<LookupSingle<T> >
|
||||
VarSizedBinSearchArrayOf<LookupSingle<T>>
|
||||
entries; /* The actual entries, sorted by glyph index. */
|
||||
public:
|
||||
DEFINE_SIZE_ARRAY (8, entries);
|
||||
|
@ -419,7 +419,7 @@ struct Lookup
|
|||
/* Ugly hand-coded null objects for template Lookup<> :(. */
|
||||
extern HB_INTERNAL const unsigned char _hb_Null_AAT_Lookup[2];
|
||||
template <typename T>
|
||||
struct Null<AAT::Lookup<T> > {
|
||||
struct Null<AAT::Lookup<T>> {
|
||||
static AAT::Lookup<T> const & get_null ()
|
||||
{ return *reinterpret_cast<const AAT::Lookup<T> *> (_hb_Null_AAT_Lookup); }
|
||||
};
|
||||
|
@ -510,7 +510,7 @@ struct StateTable
|
|||
const Entry<Extra> &get_entry (int state, unsigned int klass) const
|
||||
{
|
||||
if (unlikely (klass >= nClasses))
|
||||
klass = StateTable<Types, Entry<Extra> >::CLASS_OUT_OF_BOUNDS;
|
||||
klass = StateTable<Types, Entry<Extra>>::CLASS_OUT_OF_BOUNDS;
|
||||
|
||||
const HBUSHORT *states = (this+stateArrayTable).arrayZ;
|
||||
const Entry<Extra> *entries = (this+entryTable).arrayZ;
|
||||
|
@ -576,7 +576,7 @@ struct StateTable
|
|||
if (unlikely (stop > states))
|
||||
return_trace (false);
|
||||
for (const HBUSHORT *p = states; stop < p; p--)
|
||||
num_entries = MAX<unsigned int> (num_entries, *(p - 1) + 1);
|
||||
num_entries = hb_max (num_entries, *(p - 1) + 1);
|
||||
state_neg = min_state;
|
||||
}
|
||||
}
|
||||
|
@ -597,7 +597,7 @@ struct StateTable
|
|||
if (unlikely (stop < states))
|
||||
return_trace (false);
|
||||
for (const HBUSHORT *p = &states[state_pos * num_classes]; p < stop; p++)
|
||||
num_entries = MAX<unsigned int> (num_entries, *p + 1);
|
||||
num_entries = hb_max (num_entries, *p + 1);
|
||||
state_pos = max_state + 1;
|
||||
}
|
||||
}
|
||||
|
@ -611,8 +611,8 @@ struct StateTable
|
|||
for (const Entry<Extra> *p = &entries[entry]; p < stop; p++)
|
||||
{
|
||||
int newState = new_state (p->newState);
|
||||
min_state = MIN (min_state, newState);
|
||||
max_state = MAX (max_state, newState);
|
||||
min_state = hb_min (min_state, newState);
|
||||
max_state = hb_max (max_state, newState);
|
||||
}
|
||||
entry = num_entries;
|
||||
}
|
||||
|
@ -631,7 +631,7 @@ struct StateTable
|
|||
classTable; /* Offset to the class table. */
|
||||
NNOffsetTo<UnsizedArrayOf<HBUSHORT>, HBUINT>
|
||||
stateArrayTable;/* Offset to the state array. */
|
||||
NNOffsetTo<UnsizedArrayOf<Entry<Extra> >, HBUINT>
|
||||
NNOffsetTo<UnsizedArrayOf<Entry<Extra>>, HBUINT>
|
||||
entryTable; /* Offset to the entry array. */
|
||||
|
||||
public:
|
||||
|
|
|
@ -165,7 +165,7 @@ struct feat
|
|||
unsigned int feature_count = featureNameCount;
|
||||
if (count && *count)
|
||||
{
|
||||
unsigned int len = MIN (feature_count - start_offset, *count);
|
||||
unsigned int len = hb_min (feature_count - start_offset, *count);
|
||||
for (unsigned int i = 0; i < len; i++)
|
||||
features[i] = namesZ[i + start_offset].get_feature_type ();
|
||||
*count = len;
|
||||
|
|
|
@ -309,7 +309,7 @@ struct WidthDeltaPair
|
|||
public:
|
||||
DEFINE_SIZE_STATIC (24);
|
||||
};
|
||||
|
||||
|
||||
typedef OT::LArrayOf<WidthDeltaPair> WidthDeltaCluster;
|
||||
|
||||
struct JustificationCategory
|
||||
|
@ -371,7 +371,7 @@ struct JustificationHeader
|
|||
* of postcompensation subtable (set to zero if none).
|
||||
*
|
||||
* The postcompensation subtable, if present in the font. */
|
||||
Lookup<OffsetTo<WidthDeltaCluster> >
|
||||
Lookup<OffsetTo<WidthDeltaCluster>>
|
||||
lookupTable; /* Lookup table associating glyphs with width delta
|
||||
* clusters. See the description of Width Delta Clusters
|
||||
* table for details on how to interpret the lookup values. */
|
||||
|
|
|
@ -251,7 +251,7 @@ struct KerxSubTableFormat1
|
|||
|
||||
if (Format1EntryT::performAction (entry) && depth)
|
||||
{
|
||||
unsigned int tuple_count = MAX (1u, table->header.tuple_count ());
|
||||
unsigned int tuple_count = hb_max (1u, table->header.tuple_count ());
|
||||
|
||||
unsigned int kern_idx = Format1EntryT::kernActionIndex (entry);
|
||||
kern_idx = Types::byteOffsetToIndex (kern_idx, &table->machine, kernAction.arrayZ);
|
||||
|
@ -712,18 +712,18 @@ struct KerxSubTableFormat6
|
|||
{
|
||||
struct Long
|
||||
{
|
||||
LNNOffsetTo<Lookup<HBUINT32> > rowIndexTable;
|
||||
LNNOffsetTo<Lookup<HBUINT32> > columnIndexTable;
|
||||
LNNOffsetTo<UnsizedArrayOf<FWORD32> > array;
|
||||
LNNOffsetTo<Lookup<HBUINT32>> rowIndexTable;
|
||||
LNNOffsetTo<Lookup<HBUINT32>> columnIndexTable;
|
||||
LNNOffsetTo<UnsizedArrayOf<FWORD32>> array;
|
||||
} l;
|
||||
struct Short
|
||||
{
|
||||
LNNOffsetTo<Lookup<HBUINT16> > rowIndexTable;
|
||||
LNNOffsetTo<Lookup<HBUINT16> > columnIndexTable;
|
||||
LNNOffsetTo<UnsizedArrayOf<FWORD> > array;
|
||||
LNNOffsetTo<Lookup<HBUINT16>> rowIndexTable;
|
||||
LNNOffsetTo<Lookup<HBUINT16>> columnIndexTable;
|
||||
LNNOffsetTo<UnsizedArrayOf<FWORD>> array;
|
||||
} s;
|
||||
} u;
|
||||
LNNOffsetTo<UnsizedArrayOf<FWORD> > vector;
|
||||
LNNOffsetTo<UnsizedArrayOf<FWORD>> vector;
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (KernSubTableHeader::static_size + 24);
|
||||
};
|
||||
|
@ -771,17 +771,17 @@ struct KerxSubTable
|
|||
unsigned int get_size () const { return u.header.length; }
|
||||
unsigned int get_type () const { return u.header.coverage & u.header.SubtableType; }
|
||||
|
||||
template <typename context_t>
|
||||
typename context_t::return_t dispatch (context_t *c) const
|
||||
template <typename context_t, typename ...Ts>
|
||||
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
|
||||
{
|
||||
unsigned int subtable_type = get_type ();
|
||||
TRACE_DISPATCH (this, subtable_type);
|
||||
switch (subtable_type) {
|
||||
case 0: return_trace (c->dispatch (u.format0));
|
||||
case 1: return_trace (c->dispatch (u.format1));
|
||||
case 2: return_trace (c->dispatch (u.format2));
|
||||
case 4: return_trace (c->dispatch (u.format4));
|
||||
case 6: return_trace (c->dispatch (u.format6));
|
||||
case 0: return_trace (c->dispatch (u.format0, hb_forward<Ts> (ds)...));
|
||||
case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
|
||||
case 2: return_trace (c->dispatch (u.format2, hb_forward<Ts> (ds)...));
|
||||
case 4: return_trace (c->dispatch (u.format4, hb_forward<Ts> (ds)...));
|
||||
case 6: return_trace (c->dispatch (u.format6, hb_forward<Ts> (ds)...));
|
||||
default: return_trace (c->default_return_value ());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -81,7 +81,7 @@ struct lcar
|
|||
protected:
|
||||
FixedVersion<>version; /* Version number of the ligature caret table */
|
||||
HBUINT16 format; /* Format of the ligature caret table. */
|
||||
Lookup<OffsetTo<LigCaretClassEntry> >
|
||||
Lookup<OffsetTo<LigCaretClassEntry>>
|
||||
lookup; /* data Lookup table associating glyphs */
|
||||
|
||||
public:
|
||||
|
|
|
@ -88,7 +88,7 @@ struct RearrangementSubtable
|
|||
start = buffer->idx;
|
||||
|
||||
if (flags & MarkLast)
|
||||
end = MIN (buffer->idx + 1, buffer->len);
|
||||
end = hb_min (buffer->idx + 1, buffer->len);
|
||||
|
||||
if ((flags & Verb) && start < end)
|
||||
{
|
||||
|
@ -117,14 +117,14 @@ struct RearrangementSubtable
|
|||
};
|
||||
|
||||
unsigned int m = map[flags & Verb];
|
||||
unsigned int l = MIN<unsigned int> (2, m >> 4);
|
||||
unsigned int r = MIN<unsigned int> (2, m & 0x0F);
|
||||
unsigned int l = hb_min (2u, m >> 4);
|
||||
unsigned int r = hb_min (2u, m & 0x0F);
|
||||
bool reverse_l = 3 == (m >> 4);
|
||||
bool reverse_r = 3 == (m & 0x0F);
|
||||
|
||||
if (end - start >= l + r)
|
||||
{
|
||||
buffer->merge_clusters (start, MIN (buffer->idx + 1, buffer->len));
|
||||
buffer->merge_clusters (start, hb_min (buffer->idx + 1, buffer->len));
|
||||
buffer->merge_clusters (start, end);
|
||||
|
||||
hb_glyph_info_t *info = buffer->info;
|
||||
|
@ -261,13 +261,13 @@ struct ContextualSubtable
|
|||
}
|
||||
if (replacement)
|
||||
{
|
||||
buffer->unsafe_to_break (mark, MIN (buffer->idx + 1, buffer->len));
|
||||
buffer->unsafe_to_break (mark, hb_min (buffer->idx + 1, buffer->len));
|
||||
buffer->info[mark].codepoint = *replacement;
|
||||
ret = true;
|
||||
}
|
||||
|
||||
replacement = nullptr;
|
||||
unsigned int idx = MIN (buffer->idx, buffer->len - 1);
|
||||
unsigned int idx = hb_min (buffer->idx, buffer->len - 1);
|
||||
if (Types::extended)
|
||||
{
|
||||
if (entry.data.currentIndex != 0xFFFF)
|
||||
|
@ -337,9 +337,9 @@ struct ContextualSubtable
|
|||
const EntryData &data = entries[i].data;
|
||||
|
||||
if (data.markIndex != 0xFFFF)
|
||||
num_lookups = MAX<unsigned int> (num_lookups, 1 + data.markIndex);
|
||||
num_lookups = hb_max (num_lookups, 1 + data.markIndex);
|
||||
if (data.currentIndex != 0xFFFF)
|
||||
num_lookups = MAX<unsigned int> (num_lookups, 1 + data.currentIndex);
|
||||
num_lookups = hb_max (num_lookups, 1 + data.currentIndex);
|
||||
}
|
||||
|
||||
return_trace (substitutionTables.sanitize (c, this, num_lookups));
|
||||
|
@ -744,7 +744,7 @@ struct InsertionSubtable
|
|||
|
||||
buffer->move_to (end + count);
|
||||
|
||||
buffer->unsafe_to_break_from_outbuffer (mark, MIN (buffer->idx + 1, buffer->len));
|
||||
buffer->unsafe_to_break_from_outbuffer (mark, hb_min (buffer->idx + 1, buffer->len));
|
||||
}
|
||||
|
||||
if (flags & SetMark)
|
||||
|
@ -883,17 +883,17 @@ struct ChainSubtable
|
|||
Insertion = 5
|
||||
};
|
||||
|
||||
template <typename context_t>
|
||||
typename context_t::return_t dispatch (context_t *c) const
|
||||
template <typename context_t, typename ...Ts>
|
||||
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
|
||||
{
|
||||
unsigned int subtable_type = get_type ();
|
||||
TRACE_DISPATCH (this, subtable_type);
|
||||
switch (subtable_type) {
|
||||
case Rearrangement: return_trace (c->dispatch (u.rearrangement));
|
||||
case Contextual: return_trace (c->dispatch (u.contextual));
|
||||
case Ligature: return_trace (c->dispatch (u.ligature));
|
||||
case Noncontextual: return_trace (c->dispatch (u.noncontextual));
|
||||
case Insertion: return_trace (c->dispatch (u.insertion));
|
||||
case Rearrangement: return_trace (c->dispatch (u.rearrangement, hb_forward<Ts> (ds)...));
|
||||
case Contextual: return_trace (c->dispatch (u.contextual, hb_forward<Ts> (ds)...));
|
||||
case Ligature: return_trace (c->dispatch (u.ligature, hb_forward<Ts> (ds)...));
|
||||
case Noncontextual: return_trace (c->dispatch (u.noncontextual, hb_forward<Ts> (ds)...));
|
||||
case Insertion: return_trace (c->dispatch (u.insertion, hb_forward<Ts> (ds)...));
|
||||
default: return_trace (c->default_return_value ());
|
||||
}
|
||||
}
|
||||
|
@ -969,7 +969,7 @@ struct Chain
|
|||
void apply (hb_aat_apply_context_t *c,
|
||||
hb_mask_t flags) const
|
||||
{
|
||||
const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types> > (featureZ.as_array (featureCount));
|
||||
const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types>> (featureZ.as_array (featureCount));
|
||||
unsigned int count = subtableCount;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
|
@ -1031,7 +1031,7 @@ struct Chain
|
|||
if (unlikely (!c->buffer->successful)) return;
|
||||
|
||||
skip:
|
||||
subtable = &StructAfter<ChainSubtable<Types> > (*subtable);
|
||||
subtable = &StructAfter<ChainSubtable<Types>> (*subtable);
|
||||
c->set_lookup_index (c->lookup_index + 1);
|
||||
}
|
||||
}
|
||||
|
@ -1049,13 +1049,13 @@ struct Chain
|
|||
if (!c->check_array (featureZ.arrayZ, featureCount))
|
||||
return_trace (false);
|
||||
|
||||
const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types> > (featureZ.as_array (featureCount));
|
||||
const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types>> (featureZ.as_array (featureCount));
|
||||
unsigned int count = subtableCount;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
if (!subtable->sanitize (c))
|
||||
return_trace (false);
|
||||
subtable = &StructAfter<ChainSubtable<Types> > (*subtable);
|
||||
subtable = &StructAfter<ChainSubtable<Types>> (*subtable);
|
||||
}
|
||||
|
||||
return_trace (true);
|
||||
|
@ -1095,7 +1095,7 @@ struct mortmorx
|
|||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
map->chain_flags.push (chain->compile_flags (mapper));
|
||||
chain = &StructAfter<Chain<Types> > (*chain);
|
||||
chain = &StructAfter<Chain<Types>> (*chain);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1109,7 +1109,7 @@ struct mortmorx
|
|||
{
|
||||
chain->apply (c, c->plan->aat_map.chain_flags[i]);
|
||||
if (unlikely (!c->buffer->successful)) return;
|
||||
chain = &StructAfter<Chain<Types> > (*chain);
|
||||
chain = &StructAfter<Chain<Types>> (*chain);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1125,7 +1125,7 @@ struct mortmorx
|
|||
{
|
||||
if (!chain->sanitize (c, version))
|
||||
return_trace (false);
|
||||
chain = &StructAfter<Chain<Types> > (*chain);
|
||||
chain = &StructAfter<Chain<Types>> (*chain);
|
||||
}
|
||||
|
||||
return_trace (true);
|
||||
|
|
|
@ -66,7 +66,7 @@ struct TrackTableEntry
|
|||
NameID trackNameID; /* The 'name' table index for this track.
|
||||
* (a short word or phrase like "loose"
|
||||
* or "very tight") */
|
||||
NNOffsetTo<UnsizedArrayOf<FWORD> >
|
||||
NNOffsetTo<UnsizedArrayOf<FWORD>>
|
||||
valuesZ; /* Offset from start of tracking table to
|
||||
* per-size tracking values for this track. */
|
||||
|
||||
|
@ -133,8 +133,8 @@ struct TrackData
|
|||
if (size_table[size_index].to_float () >= csspx)
|
||||
break;
|
||||
|
||||
return round (interpolate_at (size_index ? size_index - 1 : 0, csspx,
|
||||
*trackTableEntry, base));
|
||||
return roundf (interpolate_at (size_index ? size_index - 1 : 0, csspx,
|
||||
*trackTableEntry, base));
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c, const void *base) const
|
||||
|
|
|
@ -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,
|
||||
feature_mappings,
|
||||
ARRAY_LENGTH (feature_mappings),
|
||||
sizeof (feature_mappings[0]),
|
||||
hb_aat_feature_mapping_t::cmp);
|
||||
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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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) */
|
||||
|
|
|
@ -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
|
||||
|
|
674
src/hb-algs.hh
674
src/hb-algs.hh
|
@ -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,
|
||||
int (*compar)(const void *_a, const void *_b, void *_arg),
|
||||
void *arg)
|
||||
hb_qsort (void *base, size_t nel, size_t width,
|
||||
int (*compar)(const void *_a, const void *_b))
|
||||
{
|
||||
sort_r_simple(base, nel, width, compar, arg);
|
||||
#if defined(__OPTIMIZE_SIZE__) && !defined(HB_USE_INTERNAL_QSORT)
|
||||
qsort (base, nel, width, compar);
|
||||
#else
|
||||
sort_r_simple (base, nel, width, compar);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void
|
||||
hb_qsort (void *base, size_t nel, size_t width,
|
||||
int (*compar)(const void *_a, const void *_b, void *_arg),
|
||||
void *arg)
|
||||
{
|
||||
#ifdef HAVE_GNU_QSORT_R
|
||||
qsort_r (base, nel, width, compar, arg);
|
||||
#else
|
||||
sort_r_simple (base, nel, width, compar, arg);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
@ -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 {
|
||||
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;
|
||||
static_assert (0 == byte_size % sizeof (elt_t), "");
|
||||
elt_t v[byte_size / sizeof (elt_t)];
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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)
|
||||
;
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
130
src/hb-bimap.hh
130
src/hb-bimap.hh
|
@ -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)
|
||||
{
|
||||
_new = count++;
|
||||
old_to_new.set (_old, _new);
|
||||
new_to_old.resize (count);
|
||||
new_to_old[_new] = _old;
|
||||
}
|
||||
return _new;
|
||||
forw_map.reset ();
|
||||
back_map.reset ();
|
||||
}
|
||||
|
||||
/* 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]; }
|
||||
bool in_error () const { return forw_map.in_error () || back_map.in_error (); }
|
||||
|
||||
void set (hb_codepoint_t lhs, hb_codepoint_t rhs)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,11 +2023,11 @@ 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)
|
||||
{
|
||||
char buf[100];
|
||||
vsnprintf (buf, sizeof (buf), fmt, ap);
|
||||
vsnprintf (buf, sizeof (buf), fmt, ap);
|
||||
return (bool) this->message_func (this, font, buf, this->message_data);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -226,7 +226,7 @@ struct number_t
|
|||
void set_fixed (int32_t v) { value = v / 65536.0; }
|
||||
int32_t to_fixed () const { return (int32_t) (value * 65536.0); }
|
||||
|
||||
void set_real (double v) { value = v; }
|
||||
void set_real (double v) { value = v; }
|
||||
double to_real () const { return value; }
|
||||
|
||||
int ceil () const { return (int) ::ceil (value); }
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -255,7 +248,7 @@ struct number_t
|
|||
}
|
||||
|
||||
protected:
|
||||
double value;
|
||||
double value;
|
||||
};
|
||||
|
||||
/* byte string */
|
||||
|
@ -308,7 +301,7 @@ struct byte_str_t : hb_ubytes_t
|
|||
: hb_ubytes_t (s, l) {}
|
||||
byte_str_t (const hb_ubytes_t &ub) /* conversion from hb_ubytes_t */
|
||||
: hb_ubytes_t (ub) {}
|
||||
|
||||
|
||||
/* sub-string */
|
||||
byte_str_t sub_str (unsigned int offset, unsigned int len_) const
|
||||
{ return byte_str_t (hb_ubytes_t::sub_array (offset, len_)); }
|
||||
|
@ -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,13 +335,12 @@ 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];
|
||||
return str[offset + i];
|
||||
}
|
||||
|
||||
/* Conversion to byte_str_t */
|
||||
|
@ -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 */
|
||||
|
@ -605,7 +585,7 @@ struct parsed_values_t
|
|||
}
|
||||
|
||||
unsigned get_count () const { return values.length; }
|
||||
const VAL &get_value (unsigned int i) const { return values[i]; }
|
||||
const VAL &get_value (unsigned int i) const { return values[i]; }
|
||||
const VAL &operator [] (unsigned int i) const { return get_value (i); }
|
||||
|
||||
unsigned int opStart;
|
||||
|
@ -644,30 +624,19 @@ 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;
|
||||
bool error;
|
||||
};
|
||||
|
||||
typedef interp_env_t<> num_interp_env_t;
|
||||
|
@ -711,8 +680,8 @@ struct opset_t
|
|||
};
|
||||
|
||||
template <typename ENV>
|
||||
struct interpreter_t {
|
||||
|
||||
struct interpreter_t
|
||||
{
|
||||
~interpreter_t() { fini (); }
|
||||
|
||||
void fini () { env.fini (); }
|
||||
|
|
|
@ -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,8 +76,8 @@ struct biased_subrs_t
|
|||
|
||||
void fini () {}
|
||||
|
||||
unsigned int get_count () const { return (subrs == nullptr)? 0: subrs->count; }
|
||||
unsigned int get_bias () const { return bias; }
|
||||
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:
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 */
|
|
@ -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
|
||||
|
|
|
@ -63,7 +63,7 @@ extern HB_INTERNAL hb_atomic_int_t _hb_options;
|
|||
static inline hb_options_t
|
||||
hb_options ()
|
||||
{
|
||||
#if defined(HB_NO_OPTIONS)
|
||||
#ifdef HB_NO_GETENV
|
||||
return hb_options_t ();
|
||||
#endif
|
||||
/* Make a local copy, so we can access bitfield threadsafely. */
|
||||
|
@ -161,7 +161,7 @@ _hb_debug_msg_va (const char *what,
|
|||
VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR;
|
||||
fprintf (stderr, "%2u %s" VRBAR "%s",
|
||||
level,
|
||||
bars + sizeof (bars) - 1 - MIN ((unsigned int) sizeof (bars) - 1, (unsigned int) (sizeof (VBAR) - 1) * level),
|
||||
bars + sizeof (bars) - 1 - hb_min ((unsigned int) sizeof (bars) - 1, (unsigned int) (sizeof (VBAR) - 1) * level),
|
||||
level_dir ? (level_dir > 0 ? DLBAR : ULBAR) : LBAR);
|
||||
} else
|
||||
fprintf (stderr, " " VRBAR LBAR);
|
||||
|
@ -249,8 +249,8 @@ struct hb_printer_t<bool> {
|
|||
};
|
||||
|
||||
template <>
|
||||
struct hb_printer_t<hb_void_t> {
|
||||
const char *print (hb_void_t) { return ""; }
|
||||
struct hb_printer_t<hb_empty_t> {
|
||||
const char *print (hb_empty_t) { return ""; }
|
||||
};
|
||||
|
||||
|
||||
|
@ -266,7 +266,7 @@ static inline void _hb_warn_no_return (bool returned)
|
|||
}
|
||||
}
|
||||
template <>
|
||||
/*static*/ inline void _hb_warn_no_return<hb_void_t> (bool returned HB_UNUSED)
|
||||
/*static*/ inline void _hb_warn_no_return<hb_empty_t> (bool returned HB_UNUSED)
|
||||
{}
|
||||
|
||||
template <int max_level, typename ret_t>
|
||||
|
@ -330,18 +330,20 @@ struct hb_auto_trace_t<0, ret_t>
|
|||
const char *message,
|
||||
...) HB_PRINTF_FUNC(6, 7) {}
|
||||
|
||||
ret_t ret (ret_t v,
|
||||
const char *func HB_UNUSED = nullptr,
|
||||
unsigned int line HB_UNUSED = 0) { return v; }
|
||||
template <typename T>
|
||||
T ret (T&& v,
|
||||
const char *func HB_UNUSED = nullptr,
|
||||
unsigned int line HB_UNUSED = 0) { return hb_forward<T> (v); }
|
||||
};
|
||||
|
||||
/* For disabled tracing; optimize out everything.
|
||||
* https://github.com/harfbuzz/harfbuzz/pull/605 */
|
||||
template <typename ret_t>
|
||||
struct hb_no_trace_t {
|
||||
ret_t ret (ret_t v,
|
||||
const char *func HB_UNUSED = "",
|
||||
unsigned int line HB_UNUSED = 0) { return v; }
|
||||
template <typename T>
|
||||
T ret (T&& v,
|
||||
const char *func HB_UNUSED = nullptr,
|
||||
unsigned int line HB_UNUSED = 0) { return hb_forward<T> (v); }
|
||||
};
|
||||
|
||||
#define return_trace(RET) return trace.ret (RET, HB_FUNC, __LINE__)
|
||||
|
|
|
@ -63,7 +63,7 @@ typedef hb_bool_t (*hb_font_get_glyph_func_t) (hb_font_t *font, void *font_data,
|
|||
hb_codepoint_t *glyph,
|
||||
void *user_data);
|
||||
|
||||
HB_EXTERN HB_DEPRECATED_FOR(hb_font_funcs_set_nominal_glyph_func or hb_font_funcs_set_variation_glyph_func) void
|
||||
HB_EXTERN HB_DEPRECATED_FOR(hb_font_funcs_set_nominal_glyph_func and hb_font_funcs_set_variation_glyph_func) void
|
||||
hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs,
|
||||
hb_font_get_glyph_func_t func,
|
||||
void *user_data, hb_destroy_func_t destroy);
|
||||
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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; }
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
/*
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 (); }
|
||||
};
|
||||
|
|
34
src/hb-ft.cc
34
src/hb-ft.cc
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 ()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
550
src/hb-iter.hh
550
src/hb-iter.hh
|
@ -42,9 +42,19 @@
|
|||
* copied by value. If the collection / object being iterated on
|
||||
* is writable, then the iterator returns lvalues, otherwise it
|
||||
* returns rvalues.
|
||||
*
|
||||
* TODO Document more.
|
||||
*
|
||||
* If iterator implementation implements operator!=, then can be
|
||||
* used in range-based for loop. That comes free if the iterator
|
||||
* is random-access. Otherwise, the range-based for loop incurs
|
||||
* one traversal to find end(), which can be avoided if written
|
||||
* as a while-style for loop, or if iterator implements a faster
|
||||
* __end__() method.
|
||||
* TODO When opting in for C++17, address this by changing return
|
||||
* type of .end()?
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Base classes for iterators.
|
||||
*/
|
||||
|
@ -72,10 +82,13 @@ struct hb_iter_t
|
|||
/* Operators. */
|
||||
iter_t iter () const { return *thiz(); }
|
||||
iter_t operator + () const { return *thiz(); }
|
||||
iter_t begin () const { return *thiz(); }
|
||||
iter_t end () const { return thiz()->__end__ (); }
|
||||
explicit operator bool () const { return thiz()->__more__ (); }
|
||||
unsigned len () const { return thiz()->__len__ (); }
|
||||
/* The following can only be enabled if item_t is reference type. Otherwise
|
||||
* it will be returning pointer to temporary rvalue. */
|
||||
* it will be returning pointer to temporary rvalue.
|
||||
* TODO Use a wrapper return type to fix for non-reference type. */
|
||||
template <typename T = item_t,
|
||||
hb_enable_if (hb_is_reference (T))>
|
||||
hb_remove_reference<item_t>* operator -> () const { return hb_addressof (**thiz()); }
|
||||
|
@ -83,30 +96,40 @@ struct hb_iter_t
|
|||
item_t operator * () { return thiz()->__item__ (); }
|
||||
item_t operator [] (unsigned i) const { return thiz()->__item_at__ (i); }
|
||||
item_t operator [] (unsigned i) { return thiz()->__item_at__ (i); }
|
||||
iter_t& operator += (unsigned count) { thiz()->__forward__ (count); return *thiz(); }
|
||||
iter_t& operator ++ () { thiz()->__next__ (); return *thiz(); }
|
||||
iter_t& operator -= (unsigned count) { thiz()->__rewind__ (count); return *thiz(); }
|
||||
iter_t& operator -- () { thiz()->__prev__ (); return *thiz(); }
|
||||
iter_t& operator += (unsigned count) & { thiz()->__forward__ (count); return *thiz(); }
|
||||
iter_t operator += (unsigned count) && { thiz()->__forward__ (count); return *thiz(); }
|
||||
iter_t& operator ++ () & { thiz()->__next__ (); return *thiz(); }
|
||||
iter_t operator ++ () && { thiz()->__next__ (); return *thiz(); }
|
||||
iter_t& operator -= (unsigned count) & { thiz()->__rewind__ (count); return *thiz(); }
|
||||
iter_t operator -= (unsigned count) && { thiz()->__rewind__ (count); return *thiz(); }
|
||||
iter_t& operator -- () & { thiz()->__prev__ (); return *thiz(); }
|
||||
iter_t operator -- () && { thiz()->__prev__ (); return *thiz(); }
|
||||
iter_t operator + (unsigned count) const { auto c = thiz()->iter (); c += count; return c; }
|
||||
friend iter_t operator + (unsigned count, const iter_t &it) { return it + count; }
|
||||
iter_t operator ++ (int) { iter_t c (*thiz()); ++*thiz(); return c; }
|
||||
iter_t operator - (unsigned count) const { auto c = thiz()->iter (); c -= count; return c; }
|
||||
iter_t operator -- (int) { iter_t c (*thiz()); --*thiz(); return c; }
|
||||
template <typename T>
|
||||
iter_t& operator >> (T &v) { v = **thiz(); ++*thiz(); return *thiz(); }
|
||||
iter_t& operator >> (T &v) & { v = **thiz(); ++*thiz(); return *thiz(); }
|
||||
template <typename T>
|
||||
iter_t& operator >> (T &v) const { v = **thiz(); ++*thiz(); return *thiz(); }
|
||||
iter_t operator >> (T &v) && { v = **thiz(); ++*thiz(); return *thiz(); }
|
||||
template <typename T>
|
||||
iter_t& operator << (const T v) { **thiz() = v; ++*thiz(); return *thiz(); }
|
||||
iter_t& operator << (const T v) & { **thiz() = v; ++*thiz(); return *thiz(); }
|
||||
template <typename T>
|
||||
iter_t operator << (const T v) && { **thiz() = v; ++*thiz(); return *thiz(); }
|
||||
|
||||
protected:
|
||||
hb_iter_t () {}
|
||||
hb_iter_t (const hb_iter_t &o HB_UNUSED) {}
|
||||
void operator = (const hb_iter_t &o HB_UNUSED) {}
|
||||
hb_iter_t () = default;
|
||||
hb_iter_t (const hb_iter_t &o HB_UNUSED) = default;
|
||||
hb_iter_t (hb_iter_t &&o HB_UNUSED) = default;
|
||||
hb_iter_t& operator = (const hb_iter_t &o HB_UNUSED) = default;
|
||||
hb_iter_t& operator = (hb_iter_t &&o HB_UNUSED) = default;
|
||||
};
|
||||
|
||||
#define HB_ITER_USING(Name) \
|
||||
using item_t = typename Name::item_t; \
|
||||
using Name::begin; \
|
||||
using Name::end; \
|
||||
using Name::item_size; \
|
||||
using Name::is_iterator; \
|
||||
using Name::iter; \
|
||||
|
@ -125,18 +148,20 @@ struct hb_iter_t
|
|||
using Name::operator <<; \
|
||||
static_assert (true, "")
|
||||
|
||||
/* Returns iterator type of a type. */
|
||||
#define hb_iter_t(Iterable) decltype (hb_declval (Iterable).iter ())
|
||||
/* Returns iterator / item type of a type. */
|
||||
template <typename Iterable>
|
||||
using hb_iter_type = decltype (hb_deref (hb_declval (Iterable)).iter ());
|
||||
template <typename Iterable>
|
||||
using hb_item_type = decltype (*hb_deref (hb_declval (Iterable)).iter ());
|
||||
|
||||
|
||||
template <typename> struct hb_array_t;
|
||||
|
||||
struct
|
||||
{
|
||||
template <typename T>
|
||||
hb_iter_t (T)
|
||||
template <typename T> hb_iter_type<T>
|
||||
operator () (T&& c) const
|
||||
{ return c.iter (); }
|
||||
{ return hb_deref (hb_forward<T> (c)).iter (); }
|
||||
|
||||
/* Specialization for C arrays. */
|
||||
|
||||
|
@ -148,8 +173,8 @@ struct
|
|||
operator () (Type (&array)[length]) const
|
||||
{ return hb_array_t<Type> (array, length); }
|
||||
|
||||
} HB_FUNCOBJ (hb_iter);
|
||||
|
||||
}
|
||||
HB_FUNCOBJ (hb_iter);
|
||||
|
||||
/* Mixin to fill in what the subclass doesn't provide. */
|
||||
template <typename iter_t, typename item_t = typename iter_t::__item_t__>
|
||||
|
@ -166,22 +191,36 @@ struct hb_iter_fallback_mixin_t
|
|||
item_t __item_at__ (unsigned i) const { return *(*thiz() + i); }
|
||||
|
||||
/* Termination: Implement __more__(), or __len__() if random-access. */
|
||||
bool __more__ () const { return thiz()->len (); }
|
||||
bool __more__ () const { return bool (thiz()->len ()); }
|
||||
unsigned __len__ () const
|
||||
{ iter_t c (*thiz()); unsigned l = 0; while (c) { c++; l++; }; return l; }
|
||||
{ iter_t c (*thiz()); unsigned l = 0; while (c) { c++; l++; } return l; }
|
||||
|
||||
/* Advancing: Implement __next__(), or __forward__() if random-access. */
|
||||
void __next__ () { *thiz() += 1; }
|
||||
void __forward__ (unsigned n) { while (n--) ++*thiz(); }
|
||||
void __forward__ (unsigned n) { while (*thiz() && n--) ++*thiz(); }
|
||||
|
||||
/* Rewinding: Implement __prev__() or __rewind__() if bidirectional. */
|
||||
void __prev__ () { *thiz() -= 1; }
|
||||
void __rewind__ (unsigned n) { while (n--) --*thiz(); }
|
||||
void __rewind__ (unsigned n) { while (*thiz() && n--) --*thiz(); }
|
||||
|
||||
/* Range-based for: Implement __end__() if can be done faster,
|
||||
* and operator!=. */
|
||||
iter_t __end__ () const
|
||||
{
|
||||
if (thiz()->is_random_access_iterator)
|
||||
return *thiz() + thiz()->len ();
|
||||
/* Above expression loops twice. Following loops once. */
|
||||
auto it = *thiz();
|
||||
while (it) ++it;
|
||||
return it;
|
||||
}
|
||||
|
||||
protected:
|
||||
hb_iter_fallback_mixin_t () {}
|
||||
hb_iter_fallback_mixin_t (const hb_iter_fallback_mixin_t &o HB_UNUSED) {}
|
||||
void operator = (const hb_iter_fallback_mixin_t &o HB_UNUSED) {}
|
||||
hb_iter_fallback_mixin_t () = default;
|
||||
hb_iter_fallback_mixin_t (const hb_iter_fallback_mixin_t &o HB_UNUSED) = default;
|
||||
hb_iter_fallback_mixin_t (hb_iter_fallback_mixin_t &&o HB_UNUSED) = default;
|
||||
hb_iter_fallback_mixin_t& operator = (const hb_iter_fallback_mixin_t &o HB_UNUSED) = default;
|
||||
hb_iter_fallback_mixin_t& operator = (hb_iter_fallback_mixin_t &&o HB_UNUSED) = default;
|
||||
};
|
||||
|
||||
template <typename iter_t, typename item_t = typename iter_t::__item_t__>
|
||||
|
@ -190,17 +229,32 @@ struct hb_iter_with_fallback_t :
|
|||
hb_iter_fallback_mixin_t<iter_t, item_t>
|
||||
{
|
||||
protected:
|
||||
hb_iter_with_fallback_t () {}
|
||||
hb_iter_with_fallback_t (const hb_iter_with_fallback_t &o HB_UNUSED) :
|
||||
hb_iter_t<iter_t, item_t> (o),
|
||||
hb_iter_fallback_mixin_t<iter_t, item_t> (o) {}
|
||||
void operator = (const hb_iter_with_fallback_t &o HB_UNUSED) {}
|
||||
hb_iter_with_fallback_t () = default;
|
||||
hb_iter_with_fallback_t (const hb_iter_with_fallback_t &o HB_UNUSED) = default;
|
||||
hb_iter_with_fallback_t (hb_iter_with_fallback_t &&o HB_UNUSED) = default;
|
||||
hb_iter_with_fallback_t& operator = (const hb_iter_with_fallback_t &o HB_UNUSED) = default;
|
||||
hb_iter_with_fallback_t& operator = (hb_iter_with_fallback_t &&o HB_UNUSED) = default;
|
||||
};
|
||||
|
||||
/*
|
||||
* Meta-programming predicates.
|
||||
*/
|
||||
|
||||
/* hb_is_iterator() / hb_is_iterator_of() */
|
||||
|
||||
template<typename Iter, typename Item>
|
||||
struct hb_is_iterator_of
|
||||
{
|
||||
template <typename Item2 = Item>
|
||||
static hb_true_type impl (hb_priority<2>, hb_iter_t<Iter, hb_type_identity<Item2>> *);
|
||||
static hb_false_type impl (hb_priority<0>, const void *);
|
||||
|
||||
public:
|
||||
static constexpr bool value = decltype (impl (hb_prioritize, hb_declval (Iter*)))::value;
|
||||
};
|
||||
#define hb_is_iterator_of(Iter, Item) hb_is_iterator_of<Iter, Item>::value
|
||||
#define hb_is_iterator(Iter) hb_is_iterator_of (Iter, typename Iter::item_t)
|
||||
|
||||
/* hb_is_iterable() */
|
||||
|
||||
template <typename T>
|
||||
|
@ -209,45 +263,78 @@ struct hb_is_iterable
|
|||
private:
|
||||
|
||||
template <typename U>
|
||||
static auto impl (hb_priority<1>) -> decltype (hb_declval (U).iter (), hb_true_t ());
|
||||
static auto impl (hb_priority<1>) -> decltype (hb_declval (U).iter (), hb_true_type ());
|
||||
|
||||
template <typename>
|
||||
static hb_false_t impl (hb_priority<0>);
|
||||
static hb_false_type impl (hb_priority<0>);
|
||||
|
||||
public:
|
||||
|
||||
enum { value = decltype (impl<T> (hb_prioritize))::value };
|
||||
static constexpr bool value = decltype (impl<T> (hb_prioritize))::value;
|
||||
};
|
||||
#define hb_is_iterable(Iterable) hb_is_iterable<Iterable>::value
|
||||
|
||||
/* TODO Add hb_is_iterable_of().
|
||||
* TODO Add random_access / sorted variants. */
|
||||
|
||||
/* hb_is_iterator() / hb_is_random_access_iterator() / hb_is_sorted_iterator() */
|
||||
|
||||
template <typename Iter, typename Item>
|
||||
static inline char _hb_is_iterator_of (hb_priority<0>, const void *) { return 0; }
|
||||
template <typename Iter,
|
||||
typename Item,
|
||||
typename Item2 = typename Iter::item_t,
|
||||
hb_enable_if (hb_is_cr_convertible_to (Item2, Item))>
|
||||
static inline int _hb_is_iterator_of (hb_priority<2>, hb_iter_t<Iter, Item2> *) { return 0; }
|
||||
/* hb_is_source_of() / hb_is_sink_of() */
|
||||
|
||||
template<typename Iter, typename Item>
|
||||
struct hb_is_iterator_of { enum {
|
||||
value = sizeof (int) == sizeof (_hb_is_iterator_of<Iter, Item> (hb_prioritize, hb_declval (Iter*))) }; };
|
||||
#define hb_is_iterator_of(Iter, Item) hb_is_iterator_of<Iter, Item>::value
|
||||
#define hb_is_iterator(Iter) hb_is_iterator_of (Iter, typename Iter::item_t)
|
||||
struct hb_is_source_of
|
||||
{
|
||||
private:
|
||||
template <typename Iter2 = Iter,
|
||||
hb_enable_if (hb_is_convertible (typename Iter2::item_t, hb_add_lvalue_reference<hb_add_const<Item>>))>
|
||||
static hb_true_type impl (hb_priority<2>);
|
||||
template <typename Iter2 = Iter>
|
||||
static auto impl (hb_priority<1>) -> decltype (hb_declval (Iter2) >> hb_declval (Item &), hb_true_type ());
|
||||
static hb_false_type impl (hb_priority<0>);
|
||||
|
||||
#define hb_is_random_access_iterator_of(Iter, Item) \
|
||||
hb_is_iterator_of (Iter, Item) && Iter::is_random_access_iterator
|
||||
#define hb_is_random_access_iterator(Iter) \
|
||||
hb_is_random_access_iterator_of (Iter, typename Iter::item_t)
|
||||
public:
|
||||
static constexpr bool value = decltype (impl (hb_prioritize))::value;
|
||||
};
|
||||
#define hb_is_source_of(Iter, Item) hb_is_source_of<Iter, Item>::value
|
||||
|
||||
#define hb_is_sorted_iterator_of(Iter, Item) \
|
||||
hb_is_iterator_of (Iter, Item) && Iter::is_sorted_iterator
|
||||
#define hb_is_sorted_iterator(Iter) \
|
||||
hb_is_sorted_iterator_of (Iter, typename Iter::item_t)
|
||||
template<typename Iter, typename Item>
|
||||
struct hb_is_sink_of
|
||||
{
|
||||
private:
|
||||
template <typename Iter2 = Iter,
|
||||
hb_enable_if (hb_is_convertible (typename Iter2::item_t, hb_add_lvalue_reference<Item>))>
|
||||
static hb_true_type impl (hb_priority<2>);
|
||||
template <typename Iter2 = Iter>
|
||||
static auto impl (hb_priority<1>) -> decltype (hb_declval (Iter2) << hb_declval (Item), hb_true_type ());
|
||||
static hb_false_type impl (hb_priority<0>);
|
||||
|
||||
public:
|
||||
static constexpr bool value = decltype (impl (hb_prioritize))::value;
|
||||
};
|
||||
#define hb_is_sink_of(Iter, Item) hb_is_sink_of<Iter, Item>::value
|
||||
|
||||
/* This is commonly used, so define: */
|
||||
#define hb_is_sorted_source_of(Iter, Item) \
|
||||
(hb_is_source_of(Iter, Item) && Iter::is_sorted_iterator)
|
||||
|
||||
|
||||
/* Range-based 'for' for iterables. */
|
||||
|
||||
template <typename Iterable,
|
||||
hb_requires (hb_is_iterable (Iterable))>
|
||||
static inline auto begin (Iterable&& iterable) HB_AUTO_RETURN (hb_iter (iterable).begin ())
|
||||
|
||||
template <typename Iterable,
|
||||
hb_requires (hb_is_iterable (Iterable))>
|
||||
static inline auto end (Iterable&& iterable) HB_AUTO_RETURN (hb_iter (iterable).end ())
|
||||
|
||||
/* begin()/end() are NOT looked up non-ADL. So each namespace must declare them.
|
||||
* Do it for namespace OT. */
|
||||
namespace OT {
|
||||
|
||||
template <typename Iterable,
|
||||
hb_requires (hb_is_iterable (Iterable))>
|
||||
static inline auto begin (Iterable&& iterable) HB_AUTO_RETURN (hb_iter (iterable).begin ())
|
||||
|
||||
template <typename Iterable,
|
||||
hb_requires (hb_is_iterable (Iterable))>
|
||||
static inline auto end (Iterable&& iterable) HB_AUTO_RETURN (hb_iter (iterable).end ())
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
|
@ -255,46 +342,59 @@ struct hb_is_iterator_of { enum {
|
|||
*/
|
||||
|
||||
template <typename Lhs, typename Rhs,
|
||||
hb_enable_if (hb_is_iterator (Lhs))>
|
||||
hb_requires (hb_is_iterator (Lhs))>
|
||||
static inline auto
|
||||
operator | (Lhs lhs, const Rhs &rhs) HB_AUTO_RETURN (rhs (lhs))
|
||||
operator | (Lhs&& lhs, Rhs&& rhs) HB_AUTO_RETURN (hb_forward<Rhs> (rhs) (hb_forward<Lhs> (lhs)))
|
||||
|
||||
/* hb_map(), hb_filter(), hb_reduce() */
|
||||
|
||||
template <typename Iter, typename Proj,
|
||||
hb_enable_if (hb_is_iterator (Iter))>
|
||||
struct hb_map_iter_t :
|
||||
hb_iter_t<hb_map_iter_t<Iter, Proj>,
|
||||
decltype (hb_declval (Proj) (hb_declval (typename Iter::item_t)))>
|
||||
{
|
||||
hb_map_iter_t (const Iter& it, Proj f) : it (it), f (f) {}
|
||||
enum class hb_function_sortedness_t {
|
||||
NOT_SORTED,
|
||||
RETAINS_SORTING,
|
||||
SORTED,
|
||||
};
|
||||
|
||||
typedef decltype (hb_declval (Proj) (hb_declval (typename Iter::item_t))) __item_t__;
|
||||
template <typename Iter, typename Proj, hb_function_sortedness_t Sorted,
|
||||
hb_requires (hb_is_iterator (Iter))>
|
||||
struct hb_map_iter_t :
|
||||
hb_iter_t<hb_map_iter_t<Iter, Proj, Sorted>,
|
||||
decltype (hb_get (hb_declval (Proj), *hb_declval (Iter)))>
|
||||
{
|
||||
hb_map_iter_t (const Iter& it, Proj f_) : it (it), f (f_) {}
|
||||
|
||||
typedef decltype (hb_get (hb_declval (Proj), *hb_declval (Iter))) __item_t__;
|
||||
static constexpr bool is_random_access_iterator = Iter::is_random_access_iterator;
|
||||
__item_t__ __item__ () const { return hb_get (f, *it); }
|
||||
__item_t__ __item_at__ (unsigned i) const { return hb_get (f, it[i]); }
|
||||
static constexpr bool is_sorted_iterator =
|
||||
Sorted == hb_function_sortedness_t::SORTED ? true :
|
||||
Sorted == hb_function_sortedness_t::RETAINS_SORTING ? Iter::is_sorted_iterator :
|
||||
false;
|
||||
__item_t__ __item__ () const { return hb_get (f.get (), *it); }
|
||||
__item_t__ __item_at__ (unsigned i) const { return hb_get (f.get (), it[i]); }
|
||||
bool __more__ () const { return bool (it); }
|
||||
unsigned __len__ () const { return it.len (); }
|
||||
void __next__ () { ++it; }
|
||||
void __forward__ (unsigned n) { it += n; }
|
||||
void __prev__ () { --it; }
|
||||
void __rewind__ (unsigned n) { it -= n; }
|
||||
hb_map_iter_t __end__ () const { return hb_map_iter_t (it.end (), f); }
|
||||
bool operator != (const hb_map_iter_t& o) const
|
||||
{ return it != o.it; }
|
||||
|
||||
private:
|
||||
Iter it;
|
||||
Proj f;
|
||||
hb_reference_wrapper<Proj> f;
|
||||
};
|
||||
|
||||
template <typename Proj>
|
||||
template <typename Proj, hb_function_sortedness_t Sorted>
|
||||
struct hb_map_iter_factory_t
|
||||
{
|
||||
hb_map_iter_factory_t (Proj f) : f (f) {}
|
||||
|
||||
template <typename Iter,
|
||||
hb_enable_if (hb_is_iterator (Iter))>
|
||||
hb_map_iter_t<Iter, Proj>
|
||||
operator () (Iter it) const
|
||||
{ return hb_map_iter_t<Iter, Proj> (it, f); }
|
||||
hb_requires (hb_is_iterator (Iter))>
|
||||
hb_map_iter_t<Iter, Proj, Sorted>
|
||||
operator () (Iter it)
|
||||
{ return hb_map_iter_t<Iter, Proj, Sorted> (it, f); }
|
||||
|
||||
private:
|
||||
Proj f;
|
||||
|
@ -302,31 +402,51 @@ struct hb_map_iter_factory_t
|
|||
struct
|
||||
{
|
||||
template <typename Proj>
|
||||
hb_map_iter_factory_t<Proj>
|
||||
hb_map_iter_factory_t<Proj, hb_function_sortedness_t::NOT_SORTED>
|
||||
operator () (Proj&& f) const
|
||||
{ return hb_map_iter_factory_t<Proj> (f); }
|
||||
} HB_FUNCOBJ (hb_map);
|
||||
{ return hb_map_iter_factory_t<Proj, hb_function_sortedness_t::NOT_SORTED> (f); }
|
||||
}
|
||||
HB_FUNCOBJ (hb_map);
|
||||
struct
|
||||
{
|
||||
template <typename Proj>
|
||||
hb_map_iter_factory_t<Proj, hb_function_sortedness_t::RETAINS_SORTING>
|
||||
operator () (Proj&& f) const
|
||||
{ return hb_map_iter_factory_t<Proj, hb_function_sortedness_t::RETAINS_SORTING> (f); }
|
||||
}
|
||||
HB_FUNCOBJ (hb_map_retains_sorting);
|
||||
struct
|
||||
{
|
||||
template <typename Proj>
|
||||
hb_map_iter_factory_t<Proj, hb_function_sortedness_t::SORTED>
|
||||
operator () (Proj&& f) const
|
||||
{ return hb_map_iter_factory_t<Proj, hb_function_sortedness_t::SORTED> (f); }
|
||||
}
|
||||
HB_FUNCOBJ (hb_map_sorted);
|
||||
|
||||
template <typename Iter, typename Pred, typename Proj,
|
||||
hb_enable_if (hb_is_iterator (Iter))>
|
||||
hb_requires (hb_is_iterator (Iter))>
|
||||
struct hb_filter_iter_t :
|
||||
hb_iter_with_fallback_t<hb_filter_iter_t<Iter, Pred, Proj>,
|
||||
typename Iter::item_t>
|
||||
{
|
||||
hb_filter_iter_t (const Iter& it_, Pred p, Proj f) : it (it_), p (p), f (f)
|
||||
{ while (it && !hb_has (p, hb_get (f, *it))) ++it; }
|
||||
hb_filter_iter_t (const Iter& it_, Pred p_, Proj f_) : it (it_), p (p_), f (f_)
|
||||
{ while (it && !hb_has (p.get (), hb_get (f.get (), *it))) ++it; }
|
||||
|
||||
typedef typename Iter::item_t __item_t__;
|
||||
static constexpr bool is_sorted_iterator = Iter::is_sorted_iterator;
|
||||
__item_t__ __item__ () const { return *it; }
|
||||
bool __more__ () const { return bool (it); }
|
||||
void __next__ () { do ++it; while (it && !p (f (*it))); }
|
||||
void __prev__ () { --it; }
|
||||
void __next__ () { do ++it; while (it && !hb_has (p.get (), hb_get (f.get (), *it))); }
|
||||
void __prev__ () { do --it; while (it && !hb_has (p.get (), hb_get (f.get (), *it))); }
|
||||
hb_filter_iter_t __end__ () const { return hb_filter_iter_t (it.end (), p, f); }
|
||||
bool operator != (const hb_filter_iter_t& o) const
|
||||
{ return it != o.it; }
|
||||
|
||||
private:
|
||||
Iter it;
|
||||
Pred p;
|
||||
Proj f;
|
||||
hb_reference_wrapper<Pred> p;
|
||||
hb_reference_wrapper<Proj> f;
|
||||
};
|
||||
template <typename Pred, typename Proj>
|
||||
struct hb_filter_iter_factory_t
|
||||
|
@ -334,9 +454,9 @@ struct hb_filter_iter_factory_t
|
|||
hb_filter_iter_factory_t (Pred p, Proj f) : p (p), f (f) {}
|
||||
|
||||
template <typename Iter,
|
||||
hb_enable_if (hb_is_iterator (Iter))>
|
||||
hb_requires (hb_is_iterator (Iter))>
|
||||
hb_filter_iter_t<Iter, Pred, Proj>
|
||||
operator () (Iter it) const
|
||||
operator () (Iter it)
|
||||
{ return hb_filter_iter_t<Iter, Pred, Proj> (it, p, f); }
|
||||
|
||||
private:
|
||||
|
@ -345,12 +465,13 @@ struct hb_filter_iter_factory_t
|
|||
};
|
||||
struct
|
||||
{
|
||||
template <typename Pred = decltype ((hb_bool)),
|
||||
template <typename Pred = decltype ((hb_identity)),
|
||||
typename Proj = decltype ((hb_identity))>
|
||||
hb_filter_iter_factory_t<Pred, Proj>
|
||||
operator () (Pred&& p = hb_bool, Proj&& f = hb_identity) const
|
||||
operator () (Pred&& p = hb_identity, Proj&& f = hb_identity) const
|
||||
{ return hb_filter_iter_factory_t<Pred, Proj> (p, f); }
|
||||
} HB_FUNCOBJ (hb_filter);
|
||||
}
|
||||
HB_FUNCOBJ (hb_filter);
|
||||
|
||||
template <typename Redu, typename InitT>
|
||||
struct hb_reduce_t
|
||||
|
@ -358,10 +479,10 @@ struct hb_reduce_t
|
|||
hb_reduce_t (Redu r, InitT init_value) : r (r), init_value (init_value) {}
|
||||
|
||||
template <typename Iter,
|
||||
hb_enable_if (hb_is_iterator (Iter)),
|
||||
hb_requires (hb_is_iterator (Iter)),
|
||||
typename AccuT = decltype (hb_declval (Redu) (hb_declval (InitT), hb_declval (typename Iter::item_t)))>
|
||||
AccuT
|
||||
operator () (Iter it) const
|
||||
operator () (Iter it)
|
||||
{
|
||||
AccuT value = init_value;
|
||||
for (; it; ++it)
|
||||
|
@ -379,7 +500,8 @@ struct
|
|||
hb_reduce_t<Redu, InitT>
|
||||
operator () (Redu&& r, InitT init_value) const
|
||||
{ return hb_reduce_t<Redu, InitT> (r, init_value); }
|
||||
} HB_FUNCOBJ (hb_reduce);
|
||||
}
|
||||
HB_FUNCOBJ (hb_reduce);
|
||||
|
||||
|
||||
/* hb_zip() */
|
||||
|
@ -387,7 +509,7 @@ struct
|
|||
template <typename A, typename B>
|
||||
struct hb_zip_iter_t :
|
||||
hb_iter_t<hb_zip_iter_t<A, B>,
|
||||
hb_pair_t<typename A::item_t, typename B::item_t> >
|
||||
hb_pair_t<typename A::item_t, typename B::item_t>>
|
||||
{
|
||||
hb_zip_iter_t () {}
|
||||
hb_zip_iter_t (const A& a, const B& b) : a (a), b (b) {}
|
||||
|
@ -396,17 +518,45 @@ struct hb_zip_iter_t :
|
|||
static constexpr bool is_random_access_iterator =
|
||||
A::is_random_access_iterator &&
|
||||
B::is_random_access_iterator;
|
||||
static constexpr bool is_sorted_iterator =
|
||||
A::is_sorted_iterator &&
|
||||
B::is_sorted_iterator;
|
||||
/* Note. The following categorization is only valid if A is strictly sorted,
|
||||
* ie. does NOT have duplicates. Previously I tried to categorize sortedness
|
||||
* more granularly, see commits:
|
||||
*
|
||||
* 513762849a683914fc266a17ddf38f133cccf072
|
||||
* 4d3cf2adb669c345cc43832d11689271995e160a
|
||||
*
|
||||
* However, that was not enough, since hb_sorted_array_t, hb_sorted_vector_t,
|
||||
* SortedArrayOf, etc all needed to be updated to add more variants. At that
|
||||
* point I saw it not worth the effort, and instead we now deem all sorted
|
||||
* collections as essentially strictly-sorted for the purposes of zip.
|
||||
*
|
||||
* The above assumption is not as bad as it sounds. Our "sorted" comes with
|
||||
* no guarantees. It's just a contract, put in place to help you remember,
|
||||
* and think about, whether an iterator you receive is expected to be
|
||||
* sorted or not. As such, it's not perfect by definition, and should not
|
||||
* be treated so. The inaccuracy here just errs in the direction of being
|
||||
* more permissive, so your code compiles instead of erring on the side of
|
||||
* marking your zipped iterator unsorted in which case your code won't
|
||||
* compile.
|
||||
*
|
||||
* This semantical limitation does NOT affect logic in any other place I
|
||||
* know of as of this writing.
|
||||
*/
|
||||
static constexpr bool is_sorted_iterator = A::is_sorted_iterator;
|
||||
|
||||
__item_t__ __item__ () const { return __item_t__ (*a, *b); }
|
||||
__item_t__ __item_at__ (unsigned i) const { return __item_t__ (a[i], b[i]); }
|
||||
bool __more__ () const { return a && b; }
|
||||
unsigned __len__ () const { return MIN (a.len (), b.len ()); }
|
||||
bool __more__ () const { return bool (a) && bool (b); }
|
||||
unsigned __len__ () const { return hb_min (a.len (), b.len ()); }
|
||||
void __next__ () { ++a; ++b; }
|
||||
void __forward__ (unsigned n) { a += n; b += n; }
|
||||
void __prev__ () { --a; --b; }
|
||||
void __rewind__ (unsigned n) { a -= n; b -= n; }
|
||||
hb_zip_iter_t __end__ () const { return hb_zip_iter_t (a.end (), b.end ()); }
|
||||
/* Note, we should stop if ANY of the iters reaches end. As such two compare
|
||||
* unequal if both items are unequal, NOT if either is unequal. */
|
||||
bool operator != (const hb_zip_iter_t& o) const
|
||||
{ return a != o.a && b != o.b; }
|
||||
|
||||
private:
|
||||
A a;
|
||||
|
@ -415,46 +565,12 @@ struct hb_zip_iter_t :
|
|||
struct
|
||||
{
|
||||
template <typename A, typename B,
|
||||
hb_enable_if (hb_is_iterable (A) && hb_is_iterable (B))>
|
||||
hb_zip_iter_t<hb_iter_t (A), hb_iter_t (B)>
|
||||
operator () (A& a, B &b) const
|
||||
{ return hb_zip_iter_t<hb_iter_t (A), hb_iter_t (B)> (hb_iter (a), hb_iter (b)); }
|
||||
} HB_FUNCOBJ (hb_zip);
|
||||
|
||||
/* hb_enumerate */
|
||||
|
||||
template <typename Iter,
|
||||
hb_enable_if (hb_is_iterator (Iter))>
|
||||
struct hb_enumerate_iter_t :
|
||||
hb_iter_t<hb_enumerate_iter_t<Iter>,
|
||||
hb_pair_t<unsigned, typename Iter::item_t> >
|
||||
{
|
||||
hb_enumerate_iter_t (const Iter& it) : i (0), it (it) {}
|
||||
|
||||
typedef hb_pair_t<unsigned, typename Iter::item_t> __item_t__;
|
||||
static constexpr bool is_random_access_iterator = Iter::is_random_access_iterator;
|
||||
static constexpr bool is_sorted_iterator = true;
|
||||
__item_t__ __item__ () const { return __item_t__ (+i, *it); }
|
||||
__item_t__ __item_at__ (unsigned j) const { return __item_t__ (i + j, it[j]); }
|
||||
bool __more__ () const { return bool (it); }
|
||||
unsigned __len__ () const { return it.len (); }
|
||||
void __next__ () { ++i; ++it; }
|
||||
void __forward__ (unsigned n) { i += n; it += n; }
|
||||
void __prev__ () { --i; --it; }
|
||||
void __rewind__ (unsigned n) { i -= n; it -= n; }
|
||||
|
||||
private:
|
||||
unsigned i;
|
||||
Iter it;
|
||||
};
|
||||
struct
|
||||
{
|
||||
template <typename Iterable,
|
||||
hb_enable_if (hb_is_iterable (Iterable))>
|
||||
hb_enumerate_iter_t<hb_iter_t (Iterable)>
|
||||
operator () (Iterable& it) const
|
||||
{ return hb_enumerate_iter_t<hb_iter_t (Iterable)> (hb_iter (it)); }
|
||||
} HB_FUNCOBJ (hb_enumerate);
|
||||
hb_requires (hb_is_iterable (A) && hb_is_iterable (B))>
|
||||
hb_zip_iter_t<hb_iter_type<A>, hb_iter_type<B>>
|
||||
operator () (A&& a, B&& b) const
|
||||
{ return hb_zip_iter_t<hb_iter_type<A>, hb_iter_type<B>> (hb_iter (a), hb_iter (b)); }
|
||||
}
|
||||
HB_FUNCOBJ (hb_zip);
|
||||
|
||||
/* hb_apply() */
|
||||
|
||||
|
@ -464,9 +580,8 @@ struct hb_apply_t
|
|||
hb_apply_t (Appl a) : a (a) {}
|
||||
|
||||
template <typename Iter,
|
||||
hb_enable_if (hb_is_iterator (Iter))>
|
||||
void
|
||||
operator () (Iter it) const
|
||||
hb_requires (hb_is_iterator (Iter))>
|
||||
void operator () (Iter it)
|
||||
{
|
||||
for (; it; ++it)
|
||||
(void) hb_invoke (a, *it);
|
||||
|
@ -484,19 +599,91 @@ struct
|
|||
template <typename Appl> hb_apply_t<Appl&>
|
||||
operator () (Appl *a) const
|
||||
{ return hb_apply_t<Appl&> (*a); }
|
||||
} HB_FUNCOBJ (hb_apply);
|
||||
}
|
||||
HB_FUNCOBJ (hb_apply);
|
||||
|
||||
/* hb_iota()/hb_range() */
|
||||
|
||||
template <typename T, typename S>
|
||||
struct hb_counter_iter_t :
|
||||
hb_iter_t<hb_counter_iter_t<T, S>, T>
|
||||
{
|
||||
hb_counter_iter_t (T start, T end_, S step) : v (start), end_ (end_for (start, end_, step)), step (step) {}
|
||||
|
||||
typedef T __item_t__;
|
||||
static constexpr bool is_random_access_iterator = true;
|
||||
static constexpr bool is_sorted_iterator = true;
|
||||
__item_t__ __item__ () const { return +v; }
|
||||
__item_t__ __item_at__ (unsigned j) const { return v + j * step; }
|
||||
bool __more__ () const { return v != end_; }
|
||||
unsigned __len__ () const { return !step ? UINT_MAX : (end_ - v) / step; }
|
||||
void __next__ () { v += step; }
|
||||
void __forward__ (unsigned n) { v += n * step; }
|
||||
void __prev__ () { v -= step; }
|
||||
void __rewind__ (unsigned n) { v -= n * step; }
|
||||
hb_counter_iter_t __end__ () const { return hb_counter_iter_t (end_, end_, step); }
|
||||
bool operator != (const hb_counter_iter_t& o) const
|
||||
{ return v != o.v; }
|
||||
|
||||
private:
|
||||
static inline T end_for (T start, T end_, S step)
|
||||
{
|
||||
if (!step)
|
||||
return end_;
|
||||
auto res = (end_ - start) % step;
|
||||
if (!res)
|
||||
return end_;
|
||||
end_ += step - res;
|
||||
return end_;
|
||||
}
|
||||
|
||||
private:
|
||||
T v;
|
||||
T end_;
|
||||
S step;
|
||||
};
|
||||
struct
|
||||
{
|
||||
template <typename T = unsigned, typename S = unsigned> hb_counter_iter_t<T, S>
|
||||
operator () (T start = 0u, S&& step = 1u) const
|
||||
{ return hb_counter_iter_t<T, S> (start, step >= 0 ? hb_int_max (T) : hb_int_min (T), step); }
|
||||
}
|
||||
HB_FUNCOBJ (hb_iota);
|
||||
struct
|
||||
{
|
||||
template <typename T = unsigned> hb_counter_iter_t<T, unsigned>
|
||||
operator () (T end = (unsigned) -1) const
|
||||
{ return hb_counter_iter_t<T, unsigned> (0, end, 1u); }
|
||||
|
||||
template <typename T, typename S = unsigned> hb_counter_iter_t<T, S>
|
||||
operator () (T start, T end, S&& step = 1u) const
|
||||
{ return hb_counter_iter_t<T, S> (start, end, step); }
|
||||
}
|
||||
HB_FUNCOBJ (hb_range);
|
||||
|
||||
/* hb_enumerate */
|
||||
|
||||
struct
|
||||
{
|
||||
template <typename Iterable,
|
||||
typename Index = unsigned,
|
||||
hb_requires (hb_is_iterable (Iterable))>
|
||||
auto operator () (Iterable&& it, Index start = 0u) const HB_AUTO_RETURN
|
||||
( hb_zip (hb_iota (start), it) )
|
||||
}
|
||||
HB_FUNCOBJ (hb_enumerate);
|
||||
|
||||
|
||||
/* hb_sink() */
|
||||
|
||||
template <typename Sink>
|
||||
struct hb_sink_t
|
||||
{
|
||||
hb_sink_t (Sink&& s) : s (s) {}
|
||||
hb_sink_t (Sink s) : s (s) {}
|
||||
|
||||
template <typename Iter,
|
||||
hb_enable_if (hb_is_iterator (Iter))>
|
||||
void
|
||||
operator () (Iter it) const
|
||||
hb_requires (hb_is_iterator (Iter))>
|
||||
void operator () (Iter it)
|
||||
{
|
||||
for (; it; ++it)
|
||||
s << *it;
|
||||
|
@ -514,33 +701,33 @@ struct
|
|||
template <typename Sink> hb_sink_t<Sink&>
|
||||
operator () (Sink *s) const
|
||||
{ return hb_sink_t<Sink&> (*s); }
|
||||
} HB_FUNCOBJ (hb_sink);
|
||||
}
|
||||
HB_FUNCOBJ (hb_sink);
|
||||
|
||||
/* hb-drain: hb_sink to void / blackhole / /dev/null. */
|
||||
|
||||
struct
|
||||
{
|
||||
template <typename Iter,
|
||||
hb_enable_if (hb_is_iterator (Iter))>
|
||||
void
|
||||
operator () (Iter it) const
|
||||
hb_requires (hb_is_iterator (Iter))>
|
||||
void operator () (Iter it) const
|
||||
{
|
||||
for (; it; ++it)
|
||||
(void) *it;
|
||||
}
|
||||
} HB_FUNCOBJ (hb_drain);
|
||||
}
|
||||
HB_FUNCOBJ (hb_drain);
|
||||
|
||||
/* hb_unzip(): unzip and sink to two sinks. */
|
||||
|
||||
template <typename Sink1, typename Sink2>
|
||||
struct hb_unzip_t
|
||||
{
|
||||
hb_unzip_t (Sink1&& s1, Sink2&& s2) : s1 (s1), s2 (s2) {}
|
||||
hb_unzip_t (Sink1 s1, Sink2 s2) : s1 (s1), s2 (s2) {}
|
||||
|
||||
template <typename Iter,
|
||||
hb_enable_if (hb_is_iterator (Iter))>
|
||||
void
|
||||
operator () (Iter it) const
|
||||
hb_requires (hb_is_iterator (Iter))>
|
||||
void operator () (Iter it)
|
||||
{
|
||||
for (; it; ++it)
|
||||
{
|
||||
|
@ -563,7 +750,8 @@ struct
|
|||
template <typename Sink1, typename Sink2> hb_unzip_t<Sink1&, Sink2&>
|
||||
operator () (Sink1 *s1, Sink2 *s2) const
|
||||
{ return hb_unzip_t<Sink1&, Sink2&> (*s1, *s2); }
|
||||
} HB_FUNCOBJ (hb_unzip);
|
||||
}
|
||||
HB_FUNCOBJ (hb_unzip);
|
||||
|
||||
|
||||
/* hb-all, hb-any, hb-none. */
|
||||
|
@ -571,49 +759,61 @@ struct
|
|||
struct
|
||||
{
|
||||
template <typename Iterable,
|
||||
hb_enable_if (hb_is_iterable (Iterable))>
|
||||
bool
|
||||
operator () (Iterable&& c) const
|
||||
typename Pred = decltype ((hb_identity)),
|
||||
typename Proj = decltype ((hb_identity)),
|
||||
hb_requires (hb_is_iterable (Iterable))>
|
||||
bool operator () (Iterable&& c,
|
||||
Pred&& p = hb_identity,
|
||||
Proj&& f = hb_identity) const
|
||||
{
|
||||
for (auto it = hb_iter (c); it; ++it)
|
||||
if (!*it)
|
||||
if (!hb_match (hb_forward<Pred> (p), hb_get (hb_forward<Proj> (f), *it)))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
} HB_FUNCOBJ (hb_all);
|
||||
}
|
||||
HB_FUNCOBJ (hb_all);
|
||||
struct
|
||||
{
|
||||
template <typename Iterable,
|
||||
hb_enable_if (hb_is_iterable (Iterable))>
|
||||
bool
|
||||
operator () (Iterable&& c) const
|
||||
typename Pred = decltype ((hb_identity)),
|
||||
typename Proj = decltype ((hb_identity)),
|
||||
hb_requires (hb_is_iterable (Iterable))>
|
||||
bool operator () (Iterable&& c,
|
||||
Pred&& p = hb_identity,
|
||||
Proj&& f = hb_identity) const
|
||||
{
|
||||
for (auto it = hb_iter (c); it; ++it)
|
||||
if (*it)
|
||||
if (hb_match (hb_forward<Pred> (p), hb_get (hb_forward<Proj> (f), *it)))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
} HB_FUNCOBJ (hb_any);
|
||||
}
|
||||
HB_FUNCOBJ (hb_any);
|
||||
struct
|
||||
{
|
||||
template <typename Iterable,
|
||||
hb_enable_if (hb_is_iterable (Iterable))>
|
||||
bool
|
||||
operator () (Iterable&& c) const
|
||||
typename Pred = decltype ((hb_identity)),
|
||||
typename Proj = decltype ((hb_identity)),
|
||||
hb_requires (hb_is_iterable (Iterable))>
|
||||
bool operator () (Iterable&& c,
|
||||
Pred&& p = hb_identity,
|
||||
Proj&& f = hb_identity) const
|
||||
{
|
||||
for (auto it = hb_iter (c); it; ++it)
|
||||
if (*it)
|
||||
if (hb_match (hb_forward<Pred> (p), hb_get (hb_forward<Proj> (f), *it)))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
} HB_FUNCOBJ (hb_none);
|
||||
}
|
||||
HB_FUNCOBJ (hb_none);
|
||||
|
||||
/*
|
||||
* Algorithms operating on iterators.
|
||||
*/
|
||||
|
||||
template <typename C, typename V,
|
||||
hb_enable_if (hb_is_iterable (C))>
|
||||
hb_requires (hb_is_iterable (C))>
|
||||
inline void
|
||||
hb_fill (C& c, const V &v)
|
||||
{
|
||||
|
|
|
@ -43,8 +43,8 @@ struct hb_hashmap_t
|
|||
hb_hashmap_t () { init (); }
|
||||
~hb_hashmap_t () { fini (); }
|
||||
|
||||
static_assert (hb_is_integer (K) || hb_is_pointer (K), "");
|
||||
static_assert (hb_is_integer (V) || hb_is_pointer (V), "");
|
||||
static_assert (hb_is_integral (K) || hb_is_pointer (K), "");
|
||||
static_assert (hb_is_integral (V) || hb_is_pointer (V), "");
|
||||
|
||||
/* TODO If key type is a pointer, keep hash in item_t and use to:
|
||||
* 1. avoid rehashing when resizing table, and
|
||||
|
@ -57,11 +57,12 @@ struct hb_hashmap_t
|
|||
|
||||
void clear () { key = kINVALID; value = vINVALID; }
|
||||
|
||||
bool operator == (K o) { return hb_deref_pointer (key) == hb_deref_pointer (o); }
|
||||
bool operator == (K o) { return hb_deref (key) == hb_deref (o); }
|
||||
bool operator == (const item_t &o) { return *this == o.key; }
|
||||
bool is_unused () const { return key == kINVALID; }
|
||||
bool is_tombstone () const { return key != kINVALID && value == vINVALID; }
|
||||
bool is_real () const { return key != kINVALID && value != vINVALID; }
|
||||
hb_pair_t<K, V> get_pair() const { return hb_pair_t<K, V> (key, value); }
|
||||
};
|
||||
|
||||
hb_object_header_t header;
|
||||
|
@ -181,7 +182,12 @@ struct hb_hashmap_t
|
|||
static constexpr V SENTINEL = vINVALID;
|
||||
typedef V value_t;
|
||||
value_t operator [] (K k) const { return get (k); }
|
||||
bool has (K k) const { return (*this)[k] != SENTINEL; }
|
||||
bool has (K k, V *vp = nullptr) const
|
||||
{
|
||||
V v = (*this)[k];
|
||||
if (vp) *vp = v;
|
||||
return v != SENTINEL;
|
||||
}
|
||||
/* Projection. */
|
||||
V operator () (K k) const { return get (k); }
|
||||
|
||||
|
@ -201,6 +207,34 @@ struct hb_hashmap_t
|
|||
|
||||
unsigned int get_population () const { return population; }
|
||||
|
||||
/*
|
||||
* Iterator
|
||||
*/
|
||||
auto iter () const HB_AUTO_RETURN
|
||||
(
|
||||
+ hb_array (items, mask ? mask + 1 : 0)
|
||||
| hb_filter (&item_t::is_real)
|
||||
| hb_map (&item_t::get_pair)
|
||||
)
|
||||
auto keys () const HB_AUTO_RETURN
|
||||
(
|
||||
+ hb_array (items, mask ? mask + 1 : 0)
|
||||
| hb_filter (&item_t::is_real)
|
||||
| hb_map (&item_t::key)
|
||||
| hb_map (hb_ridentity)
|
||||
)
|
||||
auto values () const HB_AUTO_RETURN
|
||||
(
|
||||
+ hb_array (items, mask ? mask + 1 : 0)
|
||||
| hb_filter (&item_t::is_real)
|
||||
| hb_map (&item_t::value)
|
||||
| hb_map (hb_ridentity)
|
||||
)
|
||||
|
||||
/* Sink interface. */
|
||||
hb_hashmap_t<K, V, kINVALID, vINVALID>& operator << (const hb_pair_t<K, V>& v)
|
||||
{ set (v.first, v.second); return *this; }
|
||||
|
||||
protected:
|
||||
|
||||
unsigned int bucket_for (K key) const
|
||||
|
@ -211,9 +245,9 @@ struct hb_hashmap_t
|
|||
while (!items[i].is_unused ())
|
||||
{
|
||||
if (items[i] == key)
|
||||
return i;
|
||||
return i;
|
||||
if (tombstone == (unsigned) -1 && items[i].is_tombstone ())
|
||||
tombstone = i;
|
||||
tombstone = i;
|
||||
i = (i + ++step) & mask;
|
||||
}
|
||||
return tombstone == (unsigned) -1 ? i : tombstone;
|
||||
|
|
368
src/hb-meta.hh
368
src/hb-meta.hh
|
@ -35,28 +35,38 @@
|
|||
*/
|
||||
|
||||
/* Void! For when we need a expression-type of void. */
|
||||
struct hb_void_t { typedef void value; };
|
||||
struct hb_empty_t {};
|
||||
|
||||
/* Void meta-function ala std::void_t
|
||||
* https://en.cppreference.com/w/cpp/types/void_t */
|
||||
template<typename... Ts> struct _hb_void_tt { typedef void type; };
|
||||
template<typename... Ts> using hb_void_tt = typename _hb_void_tt<Ts...>::type;
|
||||
/* https://en.cppreference.com/w/cpp/types/void_t */
|
||||
template<typename... Ts> struct _hb_void_t { typedef void type; };
|
||||
template<typename... Ts> using hb_void_t = typename _hb_void_t<Ts...>::type;
|
||||
|
||||
template<typename Head, typename... Ts> struct _hb_head_tt { typedef Head type; };
|
||||
template<typename... Ts> using hb_head_tt = typename _hb_head_tt<Ts...>::type;
|
||||
template<typename Head, typename... Ts> struct _hb_head_t { typedef Head type; };
|
||||
template<typename... Ts> using hb_head_t = typename _hb_head_t<Ts...>::type;
|
||||
|
||||
/* Bool! For when we need to evaluate type-dependent expressions
|
||||
* in a template argument. */
|
||||
template <bool b> struct hb_bool_tt { enum { value = b }; };
|
||||
typedef hb_bool_tt<true> hb_true_t;
|
||||
typedef hb_bool_tt<false> hb_false_t;
|
||||
template <typename T, T v> struct hb_integral_constant { static constexpr T value = v; };
|
||||
template <bool b> using hb_bool_constant = hb_integral_constant<bool, b>;
|
||||
using hb_true_type = hb_bool_constant<true>;
|
||||
using hb_false_type = hb_bool_constant<false>;
|
||||
|
||||
|
||||
/* Basic type SFINAE. */
|
||||
|
||||
template <bool B, typename T = void> struct hb_enable_if {};
|
||||
template <typename T> struct hb_enable_if<true, T> { typedef T type; };
|
||||
#define hb_enable_if(Cond) typename hb_enable_if<(Cond)>::type* = nullptr
|
||||
/* Concepts/Requires alias: */
|
||||
#define hb_requires(Cond) hb_enable_if((Cond))
|
||||
|
||||
template <typename T, typename T2> struct hb_is_same : hb_false_type {};
|
||||
template <typename T> struct hb_is_same<T, T> : hb_true_type {};
|
||||
#define hb_is_same(T, T2) hb_is_same<T, T2>::value
|
||||
|
||||
/* Function overloading SFINAE and priority. */
|
||||
|
||||
#define HB_RETURN(Ret, E) -> hb_head_tt<Ret, decltype ((E))> { return (E); }
|
||||
#define HB_RETURN(Ret, E) -> hb_head_t<Ret, decltype ((E))> { return (E); }
|
||||
#define HB_AUTO_RETURN(E) -> decltype ((E)) { return (E); }
|
||||
#define HB_VOID_RETURN(E) -> hb_void_tt<decltype ((E))> { (E); }
|
||||
#define HB_VOID_RETURN(E) -> hb_void_t<decltype ((E))> { (E); }
|
||||
|
||||
template <unsigned Pri> struct hb_priority : hb_priority<Pri - 1> {};
|
||||
template <> struct hb_priority<0> {};
|
||||
|
@ -65,13 +75,13 @@ template <> struct hb_priority<0> {};
|
|||
#define HB_FUNCOBJ(x) static_const x HB_UNUSED
|
||||
|
||||
|
||||
template <typename T> struct hb_match_identity { typedef T type; };
|
||||
template <typename T> using hb_type_identity = typename hb_match_identity<T>::type;
|
||||
template <typename T> struct hb_type_identity_t { typedef T type; };
|
||||
template <typename T> using hb_type_identity = typename hb_type_identity_t<T>::type;
|
||||
|
||||
struct
|
||||
{
|
||||
template <typename T>
|
||||
T* operator () (const T& arg) const
|
||||
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 */
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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 ()
|
||||
|
|
|
@ -94,7 +94,7 @@ typedef struct OffsetTable
|
|||
if (start_offset >= tables.len)
|
||||
*table_count = 0;
|
||||
else
|
||||
*table_count = MIN<unsigned int> (*table_count, tables.len - start_offset);
|
||||
*table_count = hb_min (*table_count, tables.len - start_offset);
|
||||
|
||||
const TableRecord *sub_tables = tables.arrayZ + start_offset;
|
||||
unsigned int count = *table_count;
|
||||
|
@ -222,7 +222,7 @@ struct TTCHeaderVersion1
|
|||
Tag ttcTag; /* TrueType Collection ID string: 'ttcf' */
|
||||
FixedVersion<>version; /* Version of the TTC Header (1.0),
|
||||
* 0x00010000u */
|
||||
LArrayOf<LOffsetTo<OffsetTable> >
|
||||
LArrayOf<LOffsetTo<OffsetTable>>
|
||||
table; /* Array of offsets to the OffsetTable for each font
|
||||
* from the beginning of the file */
|
||||
public:
|
||||
|
@ -334,7 +334,7 @@ struct ResourceTypeRecord
|
|||
protected:
|
||||
Tag tag; /* Resource type. */
|
||||
HBUINT16 resCountM1; /* Number of resources minus 1. */
|
||||
NNOffsetTo<UnsizedArrayOf<ResourceRecord> >
|
||||
NNOffsetTo<UnsizedArrayOf<ResourceRecord>>
|
||||
resourcesZ; /* Offset from beginning of resource type list
|
||||
* to reference item list for this type. */
|
||||
public:
|
||||
|
@ -390,7 +390,7 @@ struct ResourceMap
|
|||
HBUINT32 reserved1; /* Reserved for handle to next resource map */
|
||||
HBUINT16 resreved2; /* Reserved for file reference number */
|
||||
HBUINT16 attrs; /* Resource fork attribute */
|
||||
NNOffsetTo<ArrayOfM1<ResourceTypeRecord> >
|
||||
NNOffsetTo<ArrayOfM1<ResourceTypeRecord>>
|
||||
typeList; /* Offset from beginning of map to
|
||||
* resource type list */
|
||||
Offset16 nameList; /* Offset from beginning of map to
|
||||
|
@ -422,7 +422,7 @@ struct ResourceForkHeader
|
|||
}
|
||||
|
||||
protected:
|
||||
LNNOffsetTo<UnsizedArrayOf<HBUINT8> >
|
||||
LNNOffsetTo<UnsizedArrayOf<HBUINT8>>
|
||||
data; /* Offset from beginning of resource fork
|
||||
* to resource data */
|
||||
LNNOffsetTo<ResourceMap >
|
||||
|
|
|
@ -57,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];
|
||||
}
|
||||
|
||||
return_trace (true);
|
||||
TRACE_SERIALIZE (this);
|
||||
auto *out = c->start_embed (this);
|
||||
if (unlikely (!c->extend_min (out))) return_trace (nullptr);
|
||||
c->check_assign (out->len, len);
|
||||
if (unlikely (!as_array ().copy (c))) return_trace (nullptr);
|
||||
return_trace (out);
|
||||
}
|
||||
|
||||
template <typename ...Ts>
|
||||
bool sanitize (hb_sanitize_context_t *c, Ts &&...ds) const
|
||||
bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
if (unlikely (!sanitize_shallow (c))) return_trace (false);
|
||||
if (!sizeof... (Ts) && hb_is_trivially_copyable (Type)) return_trace (true);
|
||||
unsigned int count = len;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
if (unlikely (!arrayZ[i].sanitize (c, hb_forward<Ts> (ds)...)))
|
||||
if (unlikely (!c->dispatch (arrayZ[i], hb_forward<Ts> (ds)...)))
|
||||
return_trace (false);
|
||||
return_trace (true);
|
||||
}
|
||||
|
@ -628,9 +657,9 @@ using PString = ArrayOf<HBUINT8, HBUINT8>;
|
|||
|
||||
/* Array of Offset's */
|
||||
template <typename Type>
|
||||
using OffsetArrayOf = ArrayOf<OffsetTo<Type, HBUINT16> >;
|
||||
using OffsetArrayOf = ArrayOf<OffsetTo<Type, HBUINT16>>;
|
||||
template <typename Type>
|
||||
using LOffsetArrayOf = ArrayOf<OffsetTo<Type, HBUINT32> >;
|
||||
using LOffsetArrayOf = ArrayOf<OffsetTo<Type, HBUINT32>>;
|
||||
template <typename Type>
|
||||
using LOffsetLArrayOf = ArrayOf<OffsetTo<Type, HBUINT32>, HBUINT32>;
|
||||
|
||||
|
@ -658,12 +687,12 @@ struct OffsetListOf : OffsetArrayOf<Type>
|
|||
if (unlikely (!out)) return_trace (false);
|
||||
unsigned int count = this->len;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
out->arrayZ[i].serialize_subset (c, (*this)[i], out);
|
||||
out->arrayZ[i].serialize_subset (c, this->arrayZ[i], this, out);
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
template <typename ...Ts>
|
||||
bool sanitize (hb_sanitize_context_t *c, Ts &&...ds) const
|
||||
bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (OffsetArrayOf<Type>::sanitize (c, this, hb_forward<Ts> (ds)...));
|
||||
|
@ -705,26 +734,16 @@ struct HeadlessArrayOf
|
|||
return_trace (true);
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
template <typename ...Ts>
|
||||
bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
if (unlikely (!sanitize_shallow (c))) return_trace (false);
|
||||
|
||||
/* Note: for structs that do not reference other structs,
|
||||
* we do not need to call their sanitize() as we already did
|
||||
* a bound check on the aggregate array size. We just include
|
||||
* a small unreachable expression to make sure the structs
|
||||
* pointed to do have a simple sanitize() as well as an
|
||||
* assignment opreator. This ensures that they do not
|
||||
* reference other structs via offsets.
|
||||
*/
|
||||
if (false)
|
||||
{
|
||||
arrayZ[0].sanitize (c);
|
||||
Type v;
|
||||
v = arrayZ[0];
|
||||
}
|
||||
|
||||
if (!sizeof... (Ts) && hb_is_trivially_copyable (Type)) return_trace (true);
|
||||
unsigned int count = lenP1 ? lenP1 - 1 : 0;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
if (unlikely (!c->dispatch (arrayZ[i], hb_forward<Ts> (ds)...)))
|
||||
return_trace (false);
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
|
@ -765,13 +784,13 @@ struct ArrayOfM1
|
|||
{ return lenM1.static_size + (lenM1 + 1) * Type::static_size; }
|
||||
|
||||
template <typename ...Ts>
|
||||
bool sanitize (hb_sanitize_context_t *c, Ts &&...ds) const
|
||||
bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
if (unlikely (!sanitize_shallow (c))) return_trace (false);
|
||||
unsigned int count = lenM1 + 1;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
if (unlikely (!arrayZ[i].sanitize (c, hb_forward<Ts> (ds)...)))
|
||||
if (unlikely (!c->dispatch (arrayZ[i], hb_forward<Ts> (ds)...)))
|
||||
return_trace (false);
|
||||
return_trace (true);
|
||||
}
|
||||
|
@ -822,7 +841,7 @@ struct SortedArrayOf : ArrayOf<Type, LenType>
|
|||
return_trace (ret);
|
||||
}
|
||||
template <typename Iterator,
|
||||
hb_enable_if (hb_is_sorted_iterator_of (Iterator, const Type))>
|
||||
hb_requires (hb_is_sorted_source_of (Iterator, Type))>
|
||||
bool serialize (hb_serialize_context_t *c, Iterator items)
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
|
@ -830,7 +849,6 @@ struct SortedArrayOf : ArrayOf<Type, LenType>
|
|||
return_trace (ret);
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
Type &bsearch (const T &x, Type ¬_found = Crap (Type))
|
||||
{ return *as_array ().bsearch (x, ¬_found); }
|
||||
|
@ -863,7 +881,7 @@ struct BinSearchHeader
|
|||
{
|
||||
len = v;
|
||||
assert (len == v);
|
||||
entrySelector = MAX (1u, hb_bit_storage (v)) - 1;
|
||||
entrySelector = hb_max (1u, hb_bit_storage (v)) - 1;
|
||||
searchRange = 16 * (1u << entrySelector);
|
||||
rangeShift = v * 16 > searchRange
|
||||
? 16 * v - searchRange
|
||||
|
@ -882,7 +900,7 @@ struct BinSearchHeader
|
|||
};
|
||||
|
||||
template <typename Type, typename LenType=HBUINT16>
|
||||
using BinSearchArrayOf = SortedArrayOf<Type, BinSearchHeader<LenType> >;
|
||||
using BinSearchArrayOf = SortedArrayOf<Type, BinSearchHeader<LenType>>;
|
||||
|
||||
|
||||
struct VarSizedBinSearchHeader
|
||||
|
@ -947,33 +965,12 @@ struct VarSizedBinSearchArrayOf
|
|||
unsigned int get_size () const
|
||||
{ return header.static_size + header.nUnits * header.unitSize; }
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
if (unlikely (!sanitize_shallow (c))) return_trace (false);
|
||||
|
||||
/* Note: for structs that do not reference other structs,
|
||||
* we do not need to call their sanitize() as we already did
|
||||
* a bound check on the aggregate array size. We just include
|
||||
* a small unreachable expression to make sure the structs
|
||||
* pointed to do have a simple sanitize() as well as an
|
||||
* assignment opreator. This ensures that they do not
|
||||
* reference other structs via offsets.
|
||||
*/
|
||||
if (false)
|
||||
{
|
||||
(*this)[0].sanitize (c);
|
||||
Type v;
|
||||
v = (*this)[0];
|
||||
}
|
||||
|
||||
return_trace (true);
|
||||
}
|
||||
template <typename ...Ts>
|
||||
bool sanitize (hb_sanitize_context_t *c, Ts &&...ds) const
|
||||
bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
if (unlikely (!sanitize_shallow (c))) return_trace (false);
|
||||
if (!sizeof... (Ts) && hb_is_trivially_copyable (Type)) return_trace (true);
|
||||
unsigned int count = get_length ();
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
if (unlikely (!(*this)[i].sanitize (c, hb_forward<Ts> (ds)...)))
|
||||
|
|
|
@ -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;
|
||||
|
@ -57,8 +58,8 @@ inline unsigned int calcOffSize(unsigned int dataSize)
|
|||
|
||||
struct code_pair_t
|
||||
{
|
||||
hb_codepoint_t code;
|
||||
hb_codepoint_t glyph;
|
||||
hb_codepoint_t code;
|
||||
hb_codepoint_t glyph;
|
||||
};
|
||||
|
||||
typedef hb_vector_t<unsigned char> str_buff_t;
|
||||
|
@ -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
|
||||
return 0;
|
||||
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))
|
||||
return byte_str_t (data_base () + offset_at (index) - 1, length_at (index));
|
||||
else
|
||||
return Null(byte_str_t);
|
||||
if (unlikely (index >= count)) return Null (byte_str_t);
|
||||
return byte_str_t (data_base () + offset_at (index) - 1, length_at (index));
|
||||
}
|
||||
|
||||
unsigned int get_size () const
|
||||
{
|
||||
if (this != &Null(CFFIndex))
|
||||
{
|
||||
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;
|
||||
if (this == &Null (CFFIndex)) return 0;
|
||||
if (count > 0)
|
||||
return min_size + offset_array_size () + (offset_at (count) - 1);
|
||||
return count.static_size; /* empty CFFIndex contains count only */
|
||||
}
|
||||
|
||||
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:
|
||||
|
@ -245,10 +235,10 @@ struct CFFIndex
|
|||
}
|
||||
|
||||
public:
|
||||
COUNT count; /* Number of object data. Note there are (count+1) offsets */
|
||||
HBUINT8 offSize; /* The byte size of each offset in the offsets array. */
|
||||
HBUINT8 offsets[VAR]; /* The array of (count + 1) offsets into objects array (1-base). */
|
||||
/* HBUINT8 data[VAR]; Object data */
|
||||
COUNT count; /* Number of object data. Note there are (count+1) offsets */
|
||||
HBUINT8 offSize; /* The byte size of each offset in the offsets array. */
|
||||
HBUINT8 offsets[VAR]; /* The array of (count + 1) offsets into objects array (1-base). */
|
||||
/* HBUINT8 data[VAR]; Object data */
|
||||
public:
|
||||
DEFINE_SIZE_ARRAY (COUNT::static_size + HBUINT8::static_size, offsets);
|
||||
};
|
||||
|
@ -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 */
|
||||
|
@ -293,7 +283,7 @@ struct CFFIndexOf : CFFIndex<COUNT>
|
|||
/* serialize data */
|
||||
for (unsigned int i = 0; i < dataArrayLen; i++)
|
||||
{
|
||||
TYPE *dest = c->start_embed<TYPE> ();
|
||||
TYPE *dest = c->start_embed<TYPE> ();
|
||||
if (unlikely (dest == nullptr ||
|
||||
!dest->serialize (c, dataArray[i], param1, param2)))
|
||||
return_trace (false);
|
||||
|
@ -310,7 +300,7 @@ struct CFFIndexOf : CFFIndex<COUNT>
|
|||
const PARAM ¶m)
|
||||
{
|
||||
/* determine offset size */
|
||||
unsigned int totalDataSize = 0;
|
||||
unsigned int totalDataSize = 0;
|
||||
for (unsigned int i = 0; i < dataArrayLen; i++)
|
||||
{
|
||||
unsigned int dataSize = TYPE::calculate_serialized_size (dataArray[i], param);
|
||||
|
@ -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,11 +413,11 @@ 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 */
|
||||
unsigned int offset = 1;
|
||||
unsigned int offset = 1;
|
||||
unsigned int fid = 0;
|
||||
for (; fid < fontDicts.length; fid++)
|
||||
{
|
||||
|
@ -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);
|
||||
}
|
||||
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,30 +598,46 @@ 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;
|
||||
}
|
||||
}
|
||||
|
||||
HBUINT8 format;
|
||||
union {
|
||||
FDSelect0 format0;
|
||||
FDSelect3 format3;
|
||||
} u;
|
||||
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;
|
||||
union {
|
||||
FDSelect0 format0;
|
||||
FDSelect3 format3;
|
||||
} u;
|
||||
public:
|
||||
DEFINE_SIZE_MIN (1);
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,11 +184,12 @@ 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);
|
||||
if (unlikely (fmt0 == nullptr)) return_trace (false);
|
||||
fmt0->nCodes () = enc_count;
|
||||
unsigned int glyph = 0;
|
||||
for (unsigned int i = 0; i < code_ranges.length; i++)
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -245,11 +240,13 @@ struct Encoding {
|
|||
unsigned int enc_count,
|
||||
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;
|
||||
unsigned int size = min_size;
|
||||
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,21 +285,37 @@ 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;
|
||||
|
||||
HBUINT8 format;
|
||||
union {
|
||||
Encoding0 format0;
|
||||
Encoding1 format1;
|
||||
Encoding0 format0;
|
||||
Encoding1 format1;
|
||||
} u;
|
||||
/* CFF1SuppEncData suppEncData; */
|
||||
|
||||
|
@ -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,10 +472,12 @@ 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);
|
||||
if (unlikely (fmt0 == nullptr)) return_trace (false);
|
||||
unsigned int glyph = 0;
|
||||
for (unsigned int i = 0; i < sid_ranges.length; i++)
|
||||
{
|
||||
|
@ -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,
|
||||
unsigned int count)
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,35 +66,51 @@ 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;
|
||||
}
|
||||
}
|
||||
|
||||
HBUINT8 format;
|
||||
union {
|
||||
FDSelect0 format0;
|
||||
FDSelect3 format3;
|
||||
FDSelect4 format4;
|
||||
} u;
|
||||
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;
|
||||
union {
|
||||
FDSelect0 format0;
|
||||
FDSelect3 format3;
|
||||
FDSelect4 format4;
|
||||
} u;
|
||||
public:
|
||||
DEFINE_SIZE_MIN (2);
|
||||
};
|
||||
|
||||
|
|
|
@ -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];
|
||||
format4_plat0_rec.platformID = 0; // Unicode
|
||||
format4_plat0_rec.encodingID = 3;
|
||||
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];
|
||||
format4_plat3_rec.platformID = 3; // Windows
|
||||
format4_plat3_rec.encodingID = 1; // Unicode BMP
|
||||
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];
|
||||
format12_rec.platformID = 3; // Windows
|
||||
format12_rec.encodingID = 10; // Unicode UCS-4
|
||||
// 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
|
||||
|
|
|
@ -144,7 +144,7 @@ struct IndexSubtableFormat1Or3
|
|||
}
|
||||
|
||||
IndexSubtableHeader header;
|
||||
UnsizedArrayOf<Offset<OffsetType> >
|
||||
UnsizedArrayOf<Offset<OffsetType>>
|
||||
offsetArrayZ;
|
||||
public:
|
||||
DEFINE_SIZE_ARRAY(8, offsetArrayZ);
|
||||
|
@ -349,15 +349,15 @@ struct CBLC
|
|||
if (unlikely (!count))
|
||||
return Null(BitmapSizeTable);
|
||||
|
||||
unsigned int requested_ppem = MAX (font->x_ppem, font->y_ppem);
|
||||
unsigned int requested_ppem = hb_max (font->x_ppem, font->y_ppem);
|
||||
if (!requested_ppem)
|
||||
requested_ppem = 1<<30; /* Choose largest strike. */
|
||||
unsigned int best_i = 0;
|
||||
unsigned int best_ppem = MAX (sizeTables[0].ppemX, sizeTables[0].ppemY);
|
||||
unsigned int best_ppem = hb_max (sizeTables[0].ppemX, sizeTables[0].ppemY);
|
||||
|
||||
for (unsigned int i = 1; i < count; i++)
|
||||
{
|
||||
unsigned int ppem = MAX (sizeTables[i].ppemX, sizeTables[i].ppemY);
|
||||
unsigned int ppem = hb_max (sizeTables[i].ppemX, sizeTables[i].ppemY);
|
||||
if ((requested_ppem <= ppem && ppem < best_ppem) ||
|
||||
(requested_ppem > best_ppem && ppem > best_ppem))
|
||||
{
|
||||
|
@ -442,12 +442,12 @@ struct CBDT
|
|||
}
|
||||
|
||||
/* Convert to font units. */
|
||||
double x_scale = upem / (double) strike.ppemX;
|
||||
double y_scale = upem / (double) strike.ppemY;
|
||||
extents->x_bearing = round (extents->x_bearing * x_scale);
|
||||
extents->y_bearing = round (extents->y_bearing * y_scale);
|
||||
extents->width = round (extents->width * x_scale);
|
||||
extents->height = round (extents->height * y_scale);
|
||||
float x_scale = upem / (float) strike.ppemX;
|
||||
float y_scale = upem / (float) strike.ppemY;
|
||||
extents->x_bearing = roundf (extents->x_bearing * x_scale);
|
||||
extents->y_bearing = roundf (extents->y_bearing * y_scale);
|
||||
extents->width = roundf (extents->width * x_scale);
|
||||
extents->height = roundf (extents->height * y_scale);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -125,9 +125,9 @@ struct COLR
|
|||
protected:
|
||||
HBUINT16 version; /* Table version number (starts at 0). */
|
||||
HBUINT16 numBaseGlyphs; /* Number of Base Glyph Records. */
|
||||
LNNOffsetTo<SortedUnsizedArrayOf<BaseGlyphRecord> >
|
||||
LNNOffsetTo<SortedUnsizedArrayOf<BaseGlyphRecord>>
|
||||
baseGlyphsZ; /* Offset to Base Glyph records. */
|
||||
LNNOffsetTo<UnsizedArrayOf<LayerRecord> >
|
||||
LNNOffsetTo<UnsizedArrayOf<LayerRecord>>
|
||||
layersZ; /* Offset to Layer Records. */
|
||||
HBUINT16 numLayers; /* Number of Layer Records. */
|
||||
public:
|
||||
|
|
|
@ -87,15 +87,15 @@ struct CPALV1Tail
|
|||
}
|
||||
|
||||
protected:
|
||||
LNNOffsetTo<UnsizedArrayOf<HBUINT32> >
|
||||
LNNOffsetTo<UnsizedArrayOf<HBUINT32>>
|
||||
paletteFlagsZ; /* Offset from the beginning of CPAL table to
|
||||
* the Palette Type Array. Set to 0 if no array
|
||||
* is provided. */
|
||||
LNNOffsetTo<UnsizedArrayOf<NameID> >
|
||||
LNNOffsetTo<UnsizedArrayOf<NameID>>
|
||||
paletteLabelsZ; /* Offset from the beginning of CPAL table to
|
||||
* the palette labels array. Set to 0 if no
|
||||
* array is provided. */
|
||||
LNNOffsetTo<UnsizedArrayOf<NameID> >
|
||||
LNNOffsetTo<UnsizedArrayOf<NameID>>
|
||||
colorLabelsZ; /* Offset from the beginning of CPAL table to
|
||||
* the color labels array. Set to 0
|
||||
* if no array is provided. */
|
||||
|
@ -144,7 +144,7 @@ struct CPAL
|
|||
{
|
||||
hb_array_t<const BGRAColor> segment_colors = palette_colors.sub_array (start_offset, *color_count);
|
||||
/* Always return numColors colors per palette even if it has out-of-bounds start index. */
|
||||
unsigned int count = MIN<unsigned int> (MAX<int> (numColors - start_offset, 0), *color_count);
|
||||
unsigned int count = hb_min ((unsigned) hb_max ((int) (numColors - start_offset), 0), *color_count);
|
||||
*color_count = count;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
colors[i] = segment_colors[i]; /* Bound-checked read. */
|
||||
|
@ -176,7 +176,7 @@ struct CPAL
|
|||
HBUINT16 numPalettes; /* Number of palettes in the table. */
|
||||
HBUINT16 numColorRecords; /* Total number of color records, combined for
|
||||
* all palettes. */
|
||||
LNNOffsetTo<UnsizedArrayOf<BGRAColor> >
|
||||
LNNOffsetTo<UnsizedArrayOf<BGRAColor>>
|
||||
colorRecordsZ; /* Offset from the beginning of CPAL table to
|
||||
* the first ColorRecord. */
|
||||
UnsizedArrayOf<HBUINT16>
|
||||
|
|
|
@ -121,7 +121,7 @@ struct SBIXStrike
|
|||
HBUINT16 resolution; /* The device pixel density (in PPI) for which this
|
||||
* strike was designed. (E.g., 96 PPI, 192 PPI.) */
|
||||
protected:
|
||||
UnsizedArrayOf<LOffsetTo<SBIXGlyph> >
|
||||
UnsizedArrayOf<LOffsetTo<SBIXGlyph>>
|
||||
imageOffsetsZ; /* Offset from the beginning of the strike data header
|
||||
* to bitmap data for an individual glyph ID. */
|
||||
public:
|
||||
|
@ -175,7 +175,7 @@ struct sbix
|
|||
if (unlikely (!count))
|
||||
return Null(SBIXStrike);
|
||||
|
||||
unsigned int requested_ppem = MAX (font->x_ppem, font->y_ppem);
|
||||
unsigned int requested_ppem = hb_max (font->x_ppem, font->y_ppem);
|
||||
if (!requested_ppem)
|
||||
requested_ppem = 1<<30; /* Choose largest strike. */
|
||||
/* TODO Add DPI sensitivity as well? */
|
||||
|
@ -242,11 +242,11 @@ struct sbix
|
|||
/* Convert to font units. */
|
||||
if (strike_ppem)
|
||||
{
|
||||
double scale = font->face->get_upem () / (double) strike_ppem;
|
||||
extents->x_bearing = round (extents->x_bearing * scale);
|
||||
extents->y_bearing = round (extents->y_bearing * scale);
|
||||
extents->width = round (extents->width * scale);
|
||||
extents->height = round (extents->height * scale);
|
||||
float scale = font->face->get_upem () / (float) strike_ppem;
|
||||
extents->x_bearing = roundf (extents->x_bearing * scale);
|
||||
extents->y_bearing = roundf (extents->y_bearing * scale);
|
||||
extents->width = roundf (extents->width * scale);
|
||||
extents->height = roundf (extents->height * scale);
|
||||
}
|
||||
|
||||
hb_blob_destroy (blob);
|
||||
|
|
|
@ -62,7 +62,7 @@ struct SVGDocumentIndexEntry
|
|||
* this index entry. */
|
||||
HBUINT16 endGlyphID; /* The last glyph ID in the range described by
|
||||
* this index entry. Must be >= startGlyphID. */
|
||||
LNNOffsetTo<UnsizedArrayOf<HBUINT8> >
|
||||
LNNOffsetTo<UnsizedArrayOf<HBUINT8>>
|
||||
svgDoc; /* Offset from the beginning of the SVG Document Index
|
||||
* to an SVG document. Must be non-zero. */
|
||||
HBUINT32 svgDocLength; /* Length of the SVG document.
|
||||
|
@ -107,7 +107,7 @@ struct SVG
|
|||
|
||||
protected:
|
||||
HBUINT16 version; /* Table version (starting at 0). */
|
||||
LOffsetTo<SortedArrayOf<SVGDocumentIndexEntry> >
|
||||
LOffsetTo<SortedArrayOf<SVGDocumentIndexEntry>>
|
||||
svgDocEntries; /* Offset (relative to the start of the SVG table) to the
|
||||
* SVG Documents Index. Must be non-zero. */
|
||||
/* Array of SVG Document Index Entries. */
|
||||
|
|
|
@ -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
|
||||
* for allocating a buffer of suitable size before calling
|
||||
* hb_ot_color_palette_get_colors() a second time.
|
||||
* @face: #hb_face_t to work upon
|
||||
* @palette_index: the index of the color palette to query
|
||||
* @start_offset: offset of the first color to retrieve
|
||||
* @color_count: (inout) (optional): Input = the maximum number of colors to return;
|
||||
* Output = the actual number of colors returned (may be zero)
|
||||
* @colors: (out) (array length=color_count) (nullable): The array of #hb_color_t records found
|
||||
*
|
||||
* Retrieves the colors in a color palette.
|
||||
* Fetches a list of the colors in a color palette.
|
||||
*
|
||||
* Returns: the total number of colors in the palette.
|
||||
* After calling this function, @colors will be filled with the palette
|
||||
* colors. If @colors is NULL, the function will just return the number
|
||||
* of total colors without storing any actual colors; this can be used
|
||||
* for allocating a buffer of suitable size before calling
|
||||
* hb_ot_color_palette_get_colors() a second time.
|
||||
*
|
||||
* Return value: the total number of colors in the palette
|
||||
*
|
||||
* Since: 2.1.0
|
||||
*/
|
||||
|
@ -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
Loading…
Reference in New Issue