diff options
author | Seigo Nonaka <nona@google.com> | 2018-10-22 16:00:50 -0700 |
---|---|---|
committer | Seigo Nonaka <nona@google.com> | 2018-10-22 23:06:18 +0000 |
commit | 60868b2fef0c932f27d877d9a13b312e8565f44c (patch) | |
tree | e378d24436936e1cb001fdd0910c99e05d7d802f | |
parent | 710596947a8c534b1ddaa86419367ada5071fc21 (diff) | |
parent | 0a3b7a0fb0734a66926dfda5d95d3cacea8890ce (diff) | |
download | harfbuzz_ng-60868b2fef0c932f27d877d9a13b312e8565f44c.tar.gz |
Update HarfBuzz to 2.0.2
Merge commit '0a3b7a0fb0734a66926dfda5d95d3cacea8890ce'
Bug: 117953171
Change-Id: I3d3eb44406f826abde601f1aad7ed15c82930ca1
476 files changed, 14784 insertions, 7307 deletions
diff --git a/.circleci/config.yml b/.circleci/config.yml index 5ad1ae135..e73f53cac 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -27,15 +27,26 @@ jobs: # Ignoring assembler complains, https://stackoverflow.com/a/39867021 - run: make 2>&1 | grep -v -e '^/var/folders/*' -e '^[[:space:]]*\.section' -e '^[[:space:]]*\^[[:space:]]*~*' + macos-notest-ios: + macos: + xcode: "10.0.0" + steps: + - checkout + - run: brew update-reset + - run: brew install cmake + # not needed to be a framework but we like to test that also + - run: cmake -DBUILD_FRAMEWORK=ON -H. -Bbuild -GXcode -DHB_IOS=ON + - run: cd build && xcodebuild -sdk iphoneos12.0 -configuration Release build -arch arm64 + distcheck: docker: - image: ubuntu:17.10 steps: - checkout - - run: apt update && apt install -y ninja-build binutils libtool autoconf automake make cmake gcc g++ pkg-config ragel gtk-doc-tools libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python python-pip + - 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 - run: pip install fonttools - run: ./autogen.sh - - run: make + - run: make -j32 - run: make distcheck || .ci/fail.sh - 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 @@ -48,7 +59,7 @@ jobs: - run: apk update && apk add ragel make pkgconfig libtool autoconf automake gettext gcc g++ glib-dev freetype-dev cairo-dev # C??FLAGS are not needed for a regular build - run: CFLAGS="-O3" CXXFLAGS="-O3 -DHB_NO_MMAP" ./autogen.sh - - run: make + - run: make -j32 - run: make check || .ci/fail.sh archlinux-debug-O0-py3: @@ -60,7 +71,7 @@ jobs: - run: pip install fonttools # C??FLAGS are not needed for a regular build - run: CFLAGS="-O0" CXXFLAGS="-O0" CPPFLAGS="-DHB_DEBUG" ./autogen.sh --with-freetype --with-glib --with-gobject --with-cairo --with-icu --with-graphite2 - - run: make + - run: make -j32 - run: make check || .ci/fail.sh clang-O3-O0: @@ -69,16 +80,114 @@ jobs: steps: - checkout - run: apt update || true - - run: apt install -y ragel libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python python-pip + - run: apt install -y ragel libfreetype6-dev libfontconfig1-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python python-pip - run: pip install fonttools - - run: wget http://download.savannah.gnu.org/releases/freetype/freetype-2.9.tar.bz2 && tar xf freetype-2.9.tar.bz2 && cd freetype-2.9 && ./autogen.sh && ./configure && make -j4 && cd .. - - run: CFLAGS="-O3" CXXFLAGS="-O3" CC=clang CXX=clang++ ./autogen.sh --with-freetype --with-glib --with-cairo --with-icu --with-graphite2 - - run: make + - run: wget http://download.savannah.gnu.org/releases/freetype/freetype-2.9.tar.bz2 && tar xf freetype-2.9.tar.bz2 && cd freetype-2.9 && ./autogen.sh && ./configure && make -j32 && cd .. + - run: CFLAGS="-O3" CXXFLAGS="-O3" 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: CFLAGS="-O0" CXXFLAGS="-O0" CC=clang CXX=clang++ ./autogen.sh --with-freetype --with-glib --with-cairo --with-icu --with-graphite2 - - run: make + - 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 + gcc-valgrind: + docker: + - image: ubuntu:18.10 + steps: + - checkout + - run: apt update || true + - run: apt install -y gcc binutils libtool autoconf automake make pkg-config gtk-doc-tools ragel libfreetype6-dev libfontconfig1-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python python-pip valgrind + - run: pip install fonttools + - run: ./autogen.sh --with-freetype --with-glib --with-cairo --with-icu --with-graphite2 --with-fontconfig + - run: make -j32 + # run-shape-fuzzer-tests.py automatically runs valgrind if see available + # but test/api runs it by request, we probably should normalize the approaches + - run: RUN_VALGRIND=1 make check && make -Ctest/api check-valgrind || .ci/fail.sh + # informational for now + - run: make -Ctest/api check-symbols || true + + clang-everything: + docker: + - image: ubuntu:18.10 + steps: + - checkout + - run: apt update || true; apt install -y wget gnupg + - run: wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add - + - run: echo "deb http://apt.llvm.org/cosmic/ llvm-toolchain-cosmic main" > /etc/apt/sources.list.d/llvmdev.list + - run: echo "deb-src http://apt.llvm.org/cosmic/ llvm-toolchain-cosmic main" > /etc/apt/sources.list.d/llvmdevsrc.list + - run: apt update || true + - run: apt install -y clang lld binutils libtool autoconf automake make pkg-config gtk-doc-tools ragel libfreetype6-dev libfontconfig1-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python python-pip + - run: pip install fonttools + - run: CFLAGS="-Weverything -Wno-reserved-id-macro -Wno-conversion -Wno-padded -Wno-sign-conversion -Wno-cast-qual -Wno-documentation -Wno-documentation-unknown-command" CXXFLAGS="-Weverything -Wno-old-style-cast -Wno-documentation -Wno-documentation-unknown-command -Wno-c++98-compat -Wno-cast-qual -Wno-c++98-compat-pedantic -Wno-sign-conversion -Wno-padded -Wno-shorten-64-to-32 -Wno-extra-semi -Wno-reserved-id-macro -Wno-float-conversion -Wno-format-pedantic -Wno-shadow -Wno-conversion -Wno-zero-as-null-pointer-constant -Wno-missing-field-initializers -Wno-used-but-marked-unused -Wno-unused-macros -Wno-comma -Wno-float-equal -Wno-disabled-macro-expansion -Wno-weak-vtables -Wno-unused-parameter -Wno-covered-switch-default -Wno-unreachable-code" CC=clang CXX=clang++ ./autogen.sh --with-freetype --with-glib --with-cairo --with-icu --with-graphite2 --with-fontconfig + - run: make -j32 CPPFLAGS="-Werror" + - run: make check CPPFLAGS="-Werror" || .ci/fail.sh + + clang-asan: + docker: + - image: ubuntu:18.10 + steps: + - checkout + - run: apt update || true; apt install -y wget gnupg + - run: wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add - + - run: echo "deb http://apt.llvm.org/cosmic/ llvm-toolchain-cosmic main" > /etc/apt/sources.list.d/llvmdev.list + - run: echo "deb-src http://apt.llvm.org/cosmic/ llvm-toolchain-cosmic main" > /etc/apt/sources.list.d/llvmdevsrc.list + - run: apt update || true + - run: apt install -y clang lld binutils libtool autoconf automake make pkg-config gtk-doc-tools ragel libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python python-pip + - run: pip install fonttools + - run: CPPFLAGS="-fsanitize=address" LDFLAGS="-fsanitize=address -O1 -g -fno-omit-frame-pointer" CFLAGS="-fsanitize=address -O1 -g -fno-omit-frame-pointer" CXXFLAGS="-fsanitize=address -O1 -g -fno-omit-frame-pointer" LD=ld.lld CC=clang CXX=clang++ ./autogen.sh --with-freetype --with-glib --with-cairo --with-icu --with-graphite2 + - run: make -j32 + - run: make check || .ci/fail.sh | asan_symbolize | c++filt + + clang-msan: + docker: + - image: ubuntu:18.10 + steps: + - checkout + - run: apt update || true; apt install -y wget gnupg + - run: wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add - + - run: echo "deb http://apt.llvm.org/cosmic/ llvm-toolchain-cosmic main" > /etc/apt/sources.list.d/llvmdev.list + - run: echo "deb-src http://apt.llvm.org/cosmic/ llvm-toolchain-cosmic main" > /etc/apt/sources.list.d/llvmdevsrc.list + - run: apt update || true + - run: apt install -y clang lld binutils libtool autoconf automake gtk-doc-tools gettext make pkg-config ragel libcairo2-dev libicu-dev libmount-dev libgraphite2-dev python python-pip + - run: pip install fonttools + - run: update-alternatives --install "/usr/bin/ld" "ld" "/usr/bin/ld.lld" 10 + - run: wget https://ftp.gnome.org/pub/gnome/sources/glib/2.58/glib-2.58.1.tar.xz && tar xf glib-2.58.1.tar.xz && cd glib-2.58.1 && ./autogen.sh --with-pcre CPPFLAGS="-fsanitize=memory" LDFLAGS="-fsanitize=memory" CFLAGS="-fsanitize=memory" CXXFLAGS="-fsanitize=memory" LD=ld.lld CC=clang CXX=clang++ && make -j32 && make install && cd .. + - run: wget http://download.savannah.gnu.org/releases/freetype/freetype-2.9.tar.bz2 && tar xf freetype-2.9.tar.bz2 && cd freetype-2.9 && ./autogen.sh && ./configure CPPFLAGS="-fsanitize=memory" LDFLAGS="-fsanitize=memory -O1 -g -fno-omit-frame-pointer" CFLAGS="-fsanitize=memory -O1 -g -fno-omit-frame-pointer" CXXFLAGS="-fsanitize=memory -O1 -g -fno-omit-frame-pointer" LD=ld.lld CC=clang CXX=clang++ && make -j32 && make install && cd .. + - run: CPPFLAGS="-fsanitize=memory -fsanitize-memory-track-origins" LDFLAGS="-fsanitize=memory -fsanitize-memory-track-origins -O1 -g -fno-omit-frame-pointer" CFLAGS="-fsanitize=memory -fsanitize-memory-track-origins -O1 -g -fno-omit-frame-pointer" CXXFLAGS="-fsanitize=memory -fsanitize-memory-track-origins -O1 -g -fno-omit-frame-pointer" LD=ld.lld CC=clang CXX=clang++ ./autogen.sh --with-freetype --with-glib --without-icu + - run: make -j32 && MSAN_OPTIONS=exitcode=42 make check || .ci/fail.sh | asan_symbolize | c++filt + + clang-tsan: + docker: + - image: ubuntu:18.10 + steps: + - checkout + - run: apt update || true; apt install -y wget gnupg + - run: wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add - + - run: echo "deb http://apt.llvm.org/cosmic/ llvm-toolchain-cosmic main" > /etc/apt/sources.list.d/llvmdev.list + - run: echo "deb-src http://apt.llvm.org/cosmic/ llvm-toolchain-cosmic main" > /etc/apt/sources.list.d/llvmdevsrc.list + - run: apt update || true + - run: apt install -y clang lld binutils libtool autoconf automake make pkg-config ragel libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python python-pip + - run: pip install fonttools + - run: CPPFLAGS="-fsanitize=thread" LDFLAGS="-fsanitize=thread -O1 -g -fno-omit-frame-pointer" CFLAGS="-fsanitize=thread -O1 -g -fno-omit-frame-pointer" CXXFLAGS="-fsanitize=thread -O1 -g -fno-omit-frame-pointer" LD=ld.lld CC=clang CXX=clang++ ./autogen.sh --with-freetype --with-glib --with-cairo --with-icu --with-graphite2 + - run: make -j32 + - run: make check || .ci/fail.sh | asan_symbolize | c++filt + + clang-ubsan: + docker: + - image: ubuntu:18.10 + steps: + - checkout + - run: apt update || true; apt install -y wget gnupg + - run: wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add - + - run: echo "deb http://apt.llvm.org/cosmic/ llvm-toolchain-cosmic main" > /etc/apt/sources.list.d/llvmdev.list + - run: echo "deb-src http://apt.llvm.org/cosmic/ llvm-toolchain-cosmic main" > /etc/apt/sources.list.d/llvmdevsrc.list + - run: apt update || true + - run: apt install -y clang lld binutils libtool autoconf automake make pkg-config ragel libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python python-pip + - run: pip install fonttools + - run: CPPFLAGS="-fsanitize=undefined" LDFLAGS="-fsanitize=undefined -O1 -g -fno-omit-frame-pointer" CFLAGS="-fsanitize=undefined -O1 -g -fno-omit-frame-pointer" CXXFLAGS="-fsanitize=undefined -O1 -g -fno-omit-frame-pointer" LD=ld.lld CC=clang CXX=clang++ ./autogen.sh --with-freetype --with-glib --with-cairo --with-icu --with-graphite2 + - run: make -j32 + - run: make check || .ci/fail.sh | asan_symbolize | c++filt + fedora-outoftreebuild: docker: - image: fedora @@ -108,7 +217,7 @@ jobs: - 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 + - run: make -Cbuild -j32 - run: CTEST_OUTPUT_ON_FAILURE=1 make -Cbuild test - run: make -Cbuild install @@ -119,7 +228,7 @@ jobs: - checkout - run: apt update && apt install -y ragel pkg-config libtool autoconf - run: CFLAGS="-Wno-attributes" CXXFLAGS="-Wno-attributes" ./autogen.sh --prefix=/usr/local/djgpp --host=i586-pc-msdosdjgpp - - run: make + - run: make -j32 crosscompile-notest-freebsd9: docker: @@ -128,7 +237,7 @@ jobs: - checkout - run: apt update && apt install -y pkg-config ragel - run: ./autogen.sh --prefix=/freebsd --host=x86_64-pc-freebsd9 - - run: make + - run: make -j32 crosscompile-notest-psvita: docker: @@ -138,7 +247,7 @@ jobs: - run: apt update && apt install ragel - run: git clone https://github.com/vitasdk/vdpm && cd vdpm && ./bootstrap-vitasdk.sh - run: ./autogen.sh --prefix=/usr/local/vitasdk/arm-vita-eabi --host=arm-vita-eabi - - run: make + - run: make -j32 crosscompile-cmake-notest-android-arm: docker: @@ -192,6 +301,7 @@ workflows: # macOS - macos-llvm-gcc-4.2 - macos-notest-apple-gcc-i686-4.2 + - macos-notest-ios # both autotools and cmake - distcheck @@ -199,7 +309,13 @@ workflows: # autotools based builds - alpine-O3-NOMMAP - archlinux-debug-O0-py3 + - gcc-valgrind - clang-O3-O0 + - clang-everything + - clang-asan + - clang-msan + - clang-tsan + - clang-ubsan - fedora-outoftreebuild # cmake based builds diff --git a/.travis.yml b/.travis.yml index 83b479ee7..eadfa7679 100644 --- a/.travis.yml +++ b/.travis.yml @@ -47,8 +47,6 @@ matrix: - os: osx compiler: clang install: - # https://github.com/harfbuzz/harfbuzz/issues/345 - - export CXXFLAGS="$CXXFLAGS -Wno-deprecated-declarations" - brew update; # Workaround Travis/brew bug - brew uninstall libtool && brew install libtool @@ -1,9 +1,11 @@ Behdad Esfahbod -Simon Hausmann -Martin Hosken +David Turner +Ebrahim Byagowi Jonathan Kew +Khaled Hosny Lars Knoll -Werner Lemberg -Roozbeh Pournader +Martin Hosken Owen Taylor -David Turner +Roozbeh Pournader +Simon Hausmann +Werner Lemberg diff --git a/Android.bp b/Android.bp index a205af817..14cecf8fa 100644 --- a/Android.bp +++ b/Android.bp @@ -60,6 +60,7 @@ cc_library_shared { }, }, srcs: [ + "src/hb-aat-layout.cc", "src/hb-blob.cc", "src/hb-buffer-serialize.cc", "src/hb-buffer.cc", @@ -74,6 +75,7 @@ cc_library_shared { "src/hb-static.cc", "src/hb-unicode.cc", "src/hb-warning.cc", + "src/hb-ot-face.cc", "src/hb-ot-font.cc", "src/hb-ot-layout.cc", "src/hb-ot-map.cc", @@ -88,7 +90,6 @@ cc_library_shared { "src/hb-ot-shape-complex-khmer.cc", "src/hb-ot-shape-complex-myanmar.cc", "src/hb-ot-shape-complex-thai.cc", - "src/hb-ot-shape-complex-tibetan.cc", "src/hb-ot-shape-complex-use.cc", "src/hb-ot-shape-complex-use-table.cc", "src/hb-ot-shape-normalize.cc", @@ -26,7 +26,7 @@ as with any other standard package. That should leave you with a shared library in `src/`, and a few utility programs including `hb-view` and `hb-shape` under `util/`. -If you are bootstraping from git, you need a few more tools before you can +If you are bootstrapping from git, you need a few more tools before you can run `autogen.sh` for the first time. Namely, `pkg-config` and `ragel`. Again, on Ubuntu / Debian: diff --git a/CMakeLists.txt b/CMakeLists.txt index e881dbd1a..4eb23af4d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -82,12 +82,21 @@ if (HB_CHECK) endif () endif () +set (HB_DISABLE_SUBSET OFF) +set (HB_DISABLE_TESTS OFF) +option(HB_IOS "Apply iOS specific build flags" OFF) +if (HB_IOS) + # We should fix their issue and enable them + set (HB_DISABLE_SUBSET ON) + set (HB_DISABLE_TESTS ON) + set (HB_HAVE_CORETEXT OFF) +endif () + include_directories(AFTER ${PROJECT_SOURCE_DIR}/src ${PROJECT_BINARY_DIR}/src ) -add_definitions(-DHAVE_OT) add_definitions(-DHAVE_FALLBACK) # We need PYTHON_EXECUTABLE to be set for running the tests... @@ -98,10 +107,10 @@ include (CheckFunctionExists) include (CheckIncludeFile) macro (check_funcs) # Similar to AC_CHECK_FUNCS of autotools foreach (func_name ${ARGN}) - string(TOUPPER ${func_name} definiton_to_add) - check_function_exists(${func_name} HAVE_${definiton_to_add}) - if (${HAVE_${definiton_to_add}}) - add_definitions(-DHAVE_${definiton_to_add}) + string(TOUPPER ${func_name} definition_to_add) + check_function_exists(${func_name} HAVE_${definition_to_add}) + if (${HAVE_${definition_to_add}}) + add_definitions(-DHAVE_${definition_to_add}) endif () endforeach () endmacro () @@ -359,12 +368,32 @@ if (APPLE AND HB_HAVE_CORETEXT) list(APPEND project_sources ${PROJECT_SOURCE_DIR}/src/hb-coretext.cc) list(APPEND project_headers ${PROJECT_SOURCE_DIR}/src/hb-coretext.h) - find_library(APPLICATION_SERVICES_FRAMEWORK ApplicationServices) - if (APPLICATION_SERVICES_FRAMEWORK) - list(APPEND THIRD_PARTY_LIBS ${APPLICATION_SERVICES_FRAMEWORK}) - endif (APPLICATION_SERVICES_FRAMEWORK) + if (HB_IOS) + find_library(COREFOUNDATION CoreFoundation) + if (COREFOUNDATION) + list(APPEND THIRD_PARTY_LIBS ${COREFOUNDATION}) + endif () + mark_as_advanced(COREFOUNDATION) - mark_as_advanced(APPLICATION_SERVICES_FRAMEWORK) + find_library(CORETEXT CoreText) + if (CORETEXT) + list(APPEND THIRD_PARTY_LIBS ${CORETEXT}) + endif () + mark_as_advanced(CORETEXT) + + find_library(COREGRAPHICS CoreGraphics) + if (COREGRAPHICS) + list(APPEND THIRD_PARTY_LIBS ${COREGRAPHICS}) + endif () + mark_as_advanced(COREGRAPHICS) + else () + find_library(APPLICATION_SERVICES_FRAMEWORK ApplicationServices) + if (APPLICATION_SERVICES_FRAMEWORK) + list(APPEND THIRD_PARTY_LIBS ${APPLICATION_SERVICES_FRAMEWORK}) + endif () + + mark_as_advanced(APPLICATION_SERVICES_FRAMEWORK) + endif () endif () if (WIN32 AND HB_HAVE_UNISCRIBE) @@ -527,12 +556,14 @@ add_library(harfbuzz ${project_sources} ${project_extra_sources} ${project_heade target_link_libraries(harfbuzz ${THIRD_PARTY_LIBS}) ## Define harfbuzz-subset library -add_library(harfbuzz-subset ${subset_project_sources} ${subset_project_headers}) -add_dependencies(harfbuzz-subset harfbuzz) -target_link_libraries(harfbuzz-subset harfbuzz ${THIRD_PARTY_LIBS}) +if (NOT HB_DISABLE_SUBSET) + add_library(harfbuzz-subset ${subset_project_sources} ${subset_project_headers}) + add_dependencies(harfbuzz-subset harfbuzz) + target_link_libraries(harfbuzz-subset harfbuzz ${THIRD_PARTY_LIBS}) -if (BUILD_SHARED_LIBS) - set_target_properties(harfbuzz harfbuzz-subset PROPERTIES VISIBILITY_INLINES_HIDDEN TRUE) + if (BUILD_SHARED_LIBS) + set_target_properties(harfbuzz harfbuzz-subset PROPERTIES VISIBILITY_INLINES_HIDDEN TRUE) + endif () endif () if (UNIX OR MINGW) @@ -549,7 +580,9 @@ if (UNIX OR MINGW) set (CMAKE_CXX_IMPLICIT_LINK_LIBRARIES "m") # libm set (CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES "") set_target_properties(harfbuzz PROPERTIES LINKER_LANGUAGE C) - set_target_properties(harfbuzz-subset PROPERTIES LINKER_LANGUAGE C) + if (NOT HB_DISABLE_SUBSET) + set_target_properties(harfbuzz-subset PROPERTIES LINKER_LANGUAGE C) + endif () # No threadsafe statics as we do it ourselves set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-threadsafe-statics") @@ -574,7 +607,7 @@ if (HB_HAVE_GOBJECT) endif () if (BUILD_SHARED_LIBS AND WIN32 AND NOT MINGW) - add_definitions("-DHB_EXTERN=__declspec(dllexport) extern") + add_definitions("-DHB_DLL_EXPORT") endif () # On Windows, g-ir-scanner requires a DLL build in order for it to work @@ -761,12 +794,22 @@ endif () if (NOT SKIP_INSTALL_LIBRARIES AND NOT SKIP_INSTALL_ALL) install(TARGETS harfbuzz + EXPORT harfbuzzConfig ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} FRAMEWORK DESTINATION Library/Frameworks ) + install(EXPORT harfbuzzConfig + NAMESPACE harfbuzz:: + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/harfbuzz + ) if (HB_BUILD_UTILS) + if (WIN32 AND BUILD_SHARED_LIBS) + install(TARGETS harfbuzz-subset + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + ) + endif () install(TARGETS hb-view RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ) @@ -818,51 +861,53 @@ if (UNIX AND CMAKE_GENERATOR STREQUAL "Ninja") endif () -## src/ executables -foreach (prog main test test-would-substitute test-size-params test-buffer-serialize hb-ot-tag test-unicode-ranges) - 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 - set (prog_name test-test) - endif () - 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") - -## Tests -if (UNIX OR MINGW) - if (BUILD_SHARED_LIBS) - # generate harfbuzz.def after build completion - add_custom_command(TARGET harfbuzz POST_BUILD - COMMAND "${PYTHON_EXECUTABLE}" ${PROJECT_SOURCE_DIR}/src/gen-def.py ${PROJECT_BINARY_DIR}/harfbuzz.def ${project_headers} - WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/src) - - add_test(NAME check-static-inits.sh - COMMAND ${PROJECT_SOURCE_DIR}/src/check-static-inits.sh - WORKING_DIRECTORY ${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/harfbuzz.dir/src # ugly hack - ) - add_test(NAME check-libstdc++.sh COMMAND ${PROJECT_SOURCE_DIR}/src/check-libstdc++.sh) - add_test(NAME check-symbols.sh COMMAND ${PROJECT_SOURCE_DIR}/src/check-symbols.sh) +if (NOT HB_DISABLE_TESTS) + ## src/ executables + foreach (prog main test test-would-substitute test-size-params test-buffer-serialize hb-ot-tag test-unicode-ranges) + 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 + set (prog_name test-test) + endif () + 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") + + ## Tests + if (UNIX OR MINGW) + if (BUILD_SHARED_LIBS) + # generate harfbuzz.def after build completion + add_custom_command(TARGET harfbuzz POST_BUILD + COMMAND "${PYTHON_EXECUTABLE}" ${PROJECT_SOURCE_DIR}/src/gen-def.py ${PROJECT_BINARY_DIR}/harfbuzz.def ${project_headers} + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/src) + + add_test(NAME check-static-inits.sh + COMMAND ${PROJECT_SOURCE_DIR}/src/check-static-inits.sh + WORKING_DIRECTORY ${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/harfbuzz.dir/src # ugly hack + ) + add_test(NAME check-libstdc++.sh COMMAND ${PROJECT_SOURCE_DIR}/src/check-libstdc++.sh) + add_test(NAME check-symbols.sh COMMAND ${PROJECT_SOURCE_DIR}/src/check-symbols.sh) + + set_tests_properties( + check-static-inits.sh check-libstdc++.sh check-symbols.sh + PROPERTIES + ENVIRONMENT "libs=.;srcdir=${PROJECT_SOURCE_DIR}/src" + SKIP_RETURN_CODE 77) + endif () + add_test(NAME check-c-linkage-decls.sh COMMAND ./check-c-linkage-decls.sh) + add_test(NAME check-header-guards.sh COMMAND ./check-header-guards.sh) + add_test(NAME check-externs.sh COMMAND ./check-externs.sh) + add_test(NAME check-includes.sh COMMAND ./check-includes.sh) set_tests_properties( - check-static-inits.sh check-libstdc++.sh check-symbols.sh + check-c-linkage-decls.sh check-header-guards.sh check-externs.sh check-includes.sh PROPERTIES - ENVIRONMENT "libs=.;srcdir=${PROJECT_SOURCE_DIR}/src" + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/src SKIP_RETURN_CODE 77) endif () - add_test(NAME check-c-linkage-decls.sh COMMAND ./check-c-linkage-decls.sh) - add_test(NAME check-header-guards.sh COMMAND ./check-header-guards.sh) - add_test(NAME check-externs.sh COMMAND ./check-externs.sh) - add_test(NAME check-includes.sh COMMAND ./check-includes.sh) - set_tests_properties( - check-c-linkage-decls.sh check-header-guards.sh check-externs.sh check-includes.sh - PROPERTIES - WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/src - SKIP_RETURN_CODE 77) + # Needs to come last so that variables defined above are passed to + # subdirectories. + add_subdirectory(test) endif () - -# Needs to come last so that variables defined above are passed to -# subdirectories. -add_subdirectory(test) @@ -1,3 +1,109 @@ +Overview of changes leading to 2.0.2 +Saturday, October 20, 2018 +==================================== +- Fix two minor memory access issues in AAT tables. + + +Overview of changes leading to 2.0.1 +Friday, October 19, 2018 +==================================== +- Fix hb-version.h reported release version that went wrong (1.8.0) + with previous release. +- Fix extrapolation in 'trak' table. +- Fix hb-font infinite-recursion issue with some font funcs and + subclassed fonts. +- Implement variation-kerning format in kerx table, although without + variation. +- Fix return value of hb_map_is_empty(). + + +Overview of changes leading to 2.0.0 +Thursday, October 18, 2018 +==================================== +- Added AAT shaping support (morx/kerx/trak). + Automatically used if GSUB/GPOS are not available respectively. + Set HB_OPTIONS=aat env var to have morx/kerx preferred over + GSUB/GPOS. +- Apply TrueType kern table internally, instead of relying on + hb_font_t callbacks. +- Khmer shaper significantly rewritten to better match Uniscribe. +- Indic3 tags ('dev3', etc) are passed to USE shaper. +- .dfont Mac font containers implemented. +- Script- and language-mapping revamped to better use BCP 47. +- Misc USE and Indic fixes. +- Misc everything fixes. +- Too many things to list. Biggest release since 0.9.1, with + over 500 commits in just over 5 weeks! Didn't intend it to + be a big release. Just happened to become. +- hb-ft now locks underlying FT_Face during use. + +API changes: + +- Newly-created hb_font_t's now have our internal "hb-ot-font" + callbacks set on them, so they should work out of the box + without any callbacks set. If callbacks are set, everything + is back to what it was before, the fallback callbacks are + null. If you to get the internal implementation modified, + sub_font it. + +- New hb_font_funcs_set_nominal_glyphs_func() allows speeding + up character to glyph mapping. + +New API: ++HB_FEATURE_GLOBAL_START ++HB_FEATURE_GLOBAL_END ++hb_buffer_set_invisible_glyph() ++hb_buffer_get_invisible_glyph() ++hb_font_funcs_set_nominal_glyphs_func() ++hb_ot_layout_table_select_script() ++hb_ot_layout_script_select_language() ++hb_ot_layout_feature_get_name_ids() ++hb_ot_layout_feature_get_characters() ++hb_name_id_t ++HB_NAME_ID_INVALID ++HB_OT_MAX_TAGS_PER_SCRIPT ++hb_ot_tags_from_script_and_language() ++hb_ot_tags_to_script_and_language() + +Deprecated API: +-hb_font_funcs_set_glyph_func() +-hb_unicode_eastasian_width_func_t +-hb_unicode_funcs_set_eastasian_width_func() +-hb_unicode_eastasian_width() +-hb_unicode_decompose_compatibility_func_t +-HB_UNICODE_MAX_DECOMPOSITION_LEN +-hb_unicode_funcs_set_decompose_compatibility_func() +-hb_unicode_decompose_compatibility() +-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_v_kerning() +-hb_font_get_glyph_kerning_for_direction() +-hb_ot_layout_table_choose_script() +-hb_ot_layout_script_find_language() +-hb_ot_tags_from_script() +-hb_ot_tag_from_language() + + +Overview of changes leading to 1.9.0 +Monday, September 10, 2018 +==================================== +- Added 'cmap' API to hb_face_t. +- Face-builder API. +- hb-ot-font re-creation should be much leaner now, as the + font tables it uses are cached on hb_face_t now. +- Internal source header file name changes: + hb-*-private.hh is renamed to hb-*.hh. + +New API: ++HB_UNICODE_MAX ++hb_face_collect_unicodes() ++hb_face_collect_variation_selectors() ++hb_face_collect_variation_unicodes() ++hb_face_builder_create() ++hb_face_builder_add_table() + + Overview of changes leading to 1.8.8 Tuesday, August 14, 2018 ==================================== diff --git a/README.python.md b/README.python.md index 4c0ba9b27..7cf091a09 100644 --- a/README.python.md +++ b/README.python.md @@ -23,7 +23,7 @@ Then make sure you also have GI_TYPELIB_PATH pointing to the resulting $prefix/lib/girepository-* directory. Make sure you have pygobject installed. Then check that the following -import works in your Python interpretter: +import works in your Python interpreter: ```python from gi.repository import HarfBuzz diff --git a/README.version b/README.version index 457bf26d1..1781d2587 100644 --- a/README.version +++ b/README.version @@ -1,3 +1,3 @@ -URL: https://github.com/harfbuzz/harfbuzz/commit/63be5dcdde61275822d931b2924425478bc1dac1 -Version: 1.8.8 +URL: https://github.com/harfbuzz/harfbuzz/commit/0a3b7a0fb0734a66926dfda5d95d3cacea8890ce +Version: 2.0.2 BugComponent: 25699 diff --git a/README.wine.md b/README.wine.md index 851d2bf3d..799eb631f 100644 --- a/README.wine.md +++ b/README.wine.md @@ -1,6 +1,6 @@ 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 -implemenetation and that specially is important where OpenType specification +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: @@ -27,8 +27,8 @@ steps are recommended: 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 youself from `C:\Windows\SysWOW64\usp10.dll` of your - Windows installation (asuming you have a 64-bit installation, otherwise `C:\Windows\System32\usp10.dll`) +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. diff --git a/RELEASING.md b/RELEASING.md index d431871c0..4f5705e53 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -27,7 +27,10 @@ HarfBuzz release walk-through checklist: Otherwise, fix things and commit them separately before making release, Note: Check src/hb-version.h and make sure the new version number is there. Sometimes, it does not get updated. If that's the case, - "touch configure.ac" and rebuild. TODO: debug. + "touch configure.ac" and rebuild. Also check that there is no hb-version.h + in your build/src file. Typically it will fail the distcheck if there is. + That's what happened to 2.0.0 going out with 1.8.0 hb-version.h... So, that's + a clue. 7. "make release-files". Enter your GPG password. This creates a sha256 hash and signs it. @@ -1,9 +1,3 @@ -General fixes: -============= - -- Implement 'rand' feature. - - API issues: =========== @@ -19,11 +13,7 @@ API additions - Add hb-cairo glue -- Add sanitize API (and a cached version, that saves result on blob user-data) - -- BCP 47 language handling / API (language_matches?) - -- Add hb_font_create_unscaled()? +- Add sanitize API. - Add query / enumeration API for aalt-like features? diff --git a/appveyor.yml b/appveyor.yml index cc4acec1c..bf982199b 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -28,9 +28,19 @@ environment: MINGW_CHOST: i686-w64-mingw32 MSYS2_ARCH: i686 + - compiler: cygwin + CYGWIN_PREFIX: C:\Cygwin64 + CYGWIN_ARCH: x86_64 + # Lots of test failures here! + #- compiler: cygwin + # CYGWIN_PREFIX: C:\Cygwin + # CYGWIN_ARCH: x86 + + install: - - 'if "%compiler%"=="msys2" C:\msys64\usr\bin\bash -lc "pacman -Syu --noconfirm"' + - 'if "%compiler%"=="msys2" C:\msys64\usr\bin\bash -lc "pacman --force --noconfirm -Sy && pacman --noconfirm --force -S pacman-mirrors && pacman --force -Syu --noconfirm"' - C:\msys64\usr\bin\bash -lc "pacman --noconfirm -S mingw-w64-x86_64-ragel" + - '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' build_script: - 'if "%compiler%"=="msvc" if not "%platform%"=="ARM" vcpkg install glib:%triplet% freetype:%triplet% cairo:%triplet%' @@ -44,13 +54,18 @@ build_script: - '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%"=="msys2" C:\msys64\usr\bin\bash -lc "pacman --noconfirm -Syyu mingw-w64-$MSYS2_ARCH-gcc"' - - 'if "%compiler%"=="msys2" C:\msys64\usr\bin\bash -lc "pacman --noconfirm -S --needed mingw-w64-$MSYS2_ARCH-{freetype,cairo,icu,gettext,gobject-introspection,gcc,gcc-libs,glib2,graphite2,pkg-config,python2}"' + - 'if "%compiler%"=="msys2" C:\msys64\usr\bin\bash -lc "pacman --noconfirm --force -Syyu mingw-w64-$MSYS2_ARCH-gcc"' + - 'if "%compiler%"=="msys2" C:\msys64\usr\bin\bash -lc "pacman --noconfirm --force -S --needed mingw-w64-$MSYS2_ARCH-{freetype,cairo,icu,gettext,gobject-introspection,gcc,gcc-libs,glib2,graphite2,pkg-config,python2}"' - '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; make check || .ci/fail.sh"' + - 'if "%compiler%"=="cygwin" set PATH=%PATH%;c:\msys64\mingw64\bin' # msys2 is added just for having "ragel" on PATH + - 'if "%compiler%"=="cygwin" curl https://raw.githubusercontent.com/mirror/mingw-w64/023eb04c396d4e8d8fcf604cfababc53dae13398/mingw-w64-headers/include/dwrite_1.h -o %CYGWIN_PREFIX%\usr\include\dwrite_1.h' + - 'if "%compiler%"=="cygwin" %CYGWIN_PREFIX%\bin\bash -lc "cd $APPVEYOR_BUILD_FOLDER; ./autogen.sh --with-uniscribe --with-freetype --with-glib --with-gobject --with-cairo --with-icu --with-graphite2 --with-directwrite; make; make check || .ci/fail.sh"' + cache: - c:\tools\vcpkg\installed\ + - '%CYGWIN_PREFIX%\var\cache\setup' notifications: - provider: Email diff --git a/configure.ac b/configure.ac index 55cc12b3f..a2d0992a7 100644 --- a/configure.ac +++ b/configure.ac @@ -1,6 +1,6 @@ AC_PREREQ([2.64]) AC_INIT([HarfBuzz], - [1.8.8], + [2.0.2], [https://github.com/harfbuzz/harfbuzz/issues/new], [harfbuzz], [http://harfbuzz.org/]) @@ -12,6 +12,7 @@ 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_SILENT_RULES([yes]) AX_CODE_COVERAGE +AC_USE_SYSTEM_EXTENSIONS # Initialize libtool m4_ifdef([AM_PROG_AR], [AM_PROG_AR]) @@ -19,7 +20,6 @@ LT_PREREQ([2.2]) LT_INIT([disable-static]) # Check for programs -AC_USE_SYSTEM_EXTENSIONS AC_PROG_CC AC_PROG_CC_C99 AM_PROG_CC_C_O @@ -148,12 +148,6 @@ AM_CONDITIONAL(HAVE_PTHREAD, $have_pthread) dnl ========================================================================== -have_ot=true -if $have_ot; then - AC_DEFINE(HAVE_OT, 1, [Have native OpenType Layout backend]) -fi -AM_CONDITIONAL(HAVE_OT, $have_ot) - have_fallback=true if $have_fallback; then AC_DEFINE(HAVE_FALLBACK, 1, [Have simple TrueType Layout backend]) @@ -330,7 +324,7 @@ AC_ARG_WITH(graphite2, [Use the graphite2 library @<:@default=no@:>@])],, [with_graphite2=no]) have_graphite2=false -GRAPHITE2_DEPS="graphite2" +GRAPHITE2_DEPS="graphite2 >= 1.2.0" AC_SUBST(GRAPHITE2_DEPS) if test "x$with_graphite2" = "xyes" -o "x$with_graphite2" = "xauto"; then PKG_CHECK_MODULES(GRAPHITE2, $GRAPHITE2_DEPS, have_graphite2=true, :) diff --git a/docs/harfbuzz-sections.txt b/docs/harfbuzz-sections.txt index 16b662777..fccfcb0ed 100644 --- a/docs/harfbuzz-sections.txt +++ b/docs/harfbuzz-sections.txt @@ -67,6 +67,8 @@ hb_buffer_set_user_data hb_buffer_get_user_data hb_buffer_get_glyph_infos hb_buffer_get_glyph_positions +hb_buffer_get_invisible_glyph +hb_buffer_set_invisible_glyph hb_buffer_set_replacement_codepoint hb_buffer_get_replacement_codepoint hb_buffer_normalize_glyphs @@ -153,7 +155,26 @@ HB_BUFFER_SERIALIZE_FLAGS_DEFAULT HB_SCRIPT_CANADIAN_ABORIGINAL hb_font_funcs_set_glyph_func hb_font_get_glyph_func_t +hb_ot_layout_table_choose_script +hb_ot_layout_table_find_script +hb_ot_tag_from_language +hb_ot_tags_from_script hb_set_invert +hb_unicode_eastasian_width_func_t +hb_unicode_eastasian_width +hb_unicode_funcs_set_eastasian_width_func +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> <SECTION> @@ -170,6 +191,7 @@ hb_coretext_font_get_ct_font <SECTION> <FILE>hb-face</FILE> hb_face_count +hb_face_t hb_face_create hb_face_create_for_tables hb_face_destroy @@ -188,7 +210,11 @@ hb_face_set_glyph_count hb_face_set_index hb_face_set_upem hb_face_set_user_data -hb_face_t +hb_face_collect_unicodes +hb_face_collect_variation_selectors +hb_face_collect_variation_unicodes +hb_face_builder_create +hb_face_builder_add_table </SECTION> <SECTION> @@ -209,14 +235,13 @@ 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 hb_font_funcs_set_glyph_v_advances_func -hb_font_funcs_set_glyph_v_kerning_func hb_font_funcs_set_glyph_v_origin_func hb_font_funcs_set_nominal_glyph_func +hb_font_funcs_set_nominal_glyphs_func hb_font_funcs_set_user_data hb_font_funcs_set_variation_glyph_func hb_font_funcs_t @@ -226,6 +251,7 @@ hb_font_get_glyph hb_font_get_glyph_advance_for_direction hb_font_get_glyph_advance_func_t hb_font_get_glyph_advances_for_direction +hb_font_get_glyph_advances_func_t hb_font_get_glyph_contour_point hb_font_get_glyph_contour_point_for_origin hb_font_get_glyph_contour_point_func_t @@ -238,12 +264,8 @@ 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 @@ -252,12 +274,12 @@ hb_font_get_glyph_v_advance hb_font_get_glyph_v_advance_func_t hb_font_get_glyph_v_advances hb_font_get_glyph_v_advances_func_t -hb_font_get_glyph_v_kerning -hb_font_get_glyph_v_kerning_func_t hb_font_get_glyph_v_origin hb_font_get_glyph_v_origin_func_t hb_font_get_nominal_glyph hb_font_get_nominal_glyph_func_t +hb_font_get_nominal_glyphs +hb_font_get_nominal_glyphs_func_t hb_font_get_parent hb_font_get_ppem hb_font_get_ptem @@ -457,7 +479,9 @@ HB_OT_TAG_GSUB HB_OT_TAG_JSTF hb_ot_layout_collect_lookups hb_ot_layout_collect_features +hb_ot_layout_feature_get_characters hb_ot_layout_feature_get_lookups +hb_ot_layout_feature_get_name_ids hb_ot_layout_feature_with_variations_get_lookups hb_ot_layout_get_attach_points hb_ot_layout_get_glyph_class @@ -479,12 +503,12 @@ hb_ot_layout_lookups_substitute_closure hb_ot_layout_lookup_would_substitute hb_ot_layout_script_find_language hb_ot_layout_script_get_language_tags -hb_ot_layout_table_choose_script +hb_ot_layout_script_select_language hb_ot_layout_table_find_feature_variations -hb_ot_layout_table_find_script hb_ot_layout_table_get_feature_tags hb_ot_layout_table_get_script_tags hb_ot_layout_table_get_lookup_count +hb_ot_layout_table_select_script hb_ot_shape_plan_collect_lookups hb_ot_layout_language_get_required_feature_index <SUBSECTION Private> @@ -532,12 +556,14 @@ hb_ot_math_get_glyph_assembly <SECTION> <FILE>hb-ot-tag</FILE> +HB_OT_MAX_TAGS_PER_LANGUAGE +HB_OT_MAX_TAGS_PER_SCRIPT HB_OT_TAG_DEFAULT_LANGUAGE HB_OT_TAG_DEFAULT_SCRIPT -hb_ot_tag_from_language hb_ot_tag_to_language hb_ot_tag_to_script -hb_ot_tags_from_script +hb_ot_tags_from_script_and_language +hb_ot_tags_to_script_and_language </SECTION> <SECTION> @@ -576,6 +602,8 @@ hb_set_union <SECTION> <FILE>hb-shape</FILE> +HB_FEATURE_GLOBAL_END +HB_FEATURE_GLOBAL_START hb_feature_t hb_feature_from_string hb_feature_to_string @@ -602,16 +630,14 @@ hb_shape_plan_t <SECTION> <FILE>hb-unicode</FILE> -HB_UNICODE_MAX_DECOMPOSITION_LEN +HB_UNICODE_MAX hb_unicode_combining_class hb_unicode_combining_class_func_t hb_unicode_combining_class_t hb_unicode_compose hb_unicode_compose_func_t hb_unicode_decompose -hb_unicode_decompose_compatibility hb_unicode_decompose_func_t -hb_unicode_eastasian_width hb_unicode_funcs_create hb_unicode_funcs_destroy hb_unicode_funcs_get_default @@ -623,9 +649,7 @@ hb_unicode_funcs_make_immutable hb_unicode_funcs_reference hb_unicode_funcs_set_combining_class_func hb_unicode_funcs_set_compose_func -hb_unicode_funcs_set_decompose_compatibility_func hb_unicode_funcs_set_decompose_func -hb_unicode_funcs_set_eastasian_width_func hb_unicode_funcs_set_general_category_func hb_unicode_funcs_set_mirroring_func hb_unicode_funcs_set_script_func diff --git a/m4/pkg.m4 b/m4/pkg.m4 deleted file mode 100644 index 0048a3fa0..000000000 --- a/m4/pkg.m4 +++ /dev/null @@ -1,157 +0,0 @@ -# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- -# -# Copyright © 2004 Scott James Remnant <scott@netsplit.com>. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# -# As a special exception to the GNU General Public License, if you -# distribute this file as part of a program that contains a -# configuration script generated by Autoconf, you may include it under -# the same distribution terms that you use for the rest of that program. - -# PKG_PROG_PKG_CONFIG([MIN-VERSION]) -# ---------------------------------- -AC_DEFUN([PKG_PROG_PKG_CONFIG], -[m4_pattern_forbid([^_?PKG_[A-Z_]+$]) -m4_pattern_allow([^PKG_CONFIG(_PATH)?$]) -AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility])dnl -if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then - AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) -fi -if test -n "$PKG_CONFIG"; then - _pkg_min_version=m4_default([$1], [0.9.0]) - AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) - if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then - AC_MSG_RESULT([yes]) - else - AC_MSG_RESULT([no]) - PKG_CONFIG="" - fi - -fi[]dnl -])# PKG_PROG_PKG_CONFIG - -# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) -# -# Check to see whether a particular set of modules exists. Similar -# to PKG_CHECK_MODULES(), but does not set variables or print errors. -# -# -# Similar to PKG_CHECK_MODULES, make sure that the first instance of -# this or PKG_CHECK_MODULES is called, or make sure to call -# PKG_CHECK_EXISTS manually -# -------------------------------------------------------------- -AC_DEFUN([PKG_CHECK_EXISTS], -[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl -if test -n "$PKG_CONFIG" && \ - AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then - m4_ifval([$2], [$2], [:]) -m4_ifvaln([$3], [else - $3])dnl -fi]) - - -# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) -# --------------------------------------------- -m4_define([_PKG_CONFIG], -[if test -n "$PKG_CONFIG"; then - if test -n "$$1"; then - pkg_cv_[]$1="$$1" - else - PKG_CHECK_EXISTS([$3], - [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`], - [pkg_failed=yes]) - fi -else - pkg_failed=untried -fi[]dnl -])# _PKG_CONFIG - -# _PKG_SHORT_ERRORS_SUPPORTED -# ----------------------------- -AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], -[AC_REQUIRE([PKG_PROG_PKG_CONFIG]) -if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then - _pkg_short_errors_supported=yes -else - _pkg_short_errors_supported=no -fi[]dnl -])# _PKG_SHORT_ERRORS_SUPPORTED - - -# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], -# [ACTION-IF-NOT-FOUND]) -# -# -# Note that if there is a possibility the first call to -# PKG_CHECK_MODULES might not happen, you should be sure to include an -# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac -# -# -# -------------------------------------------------------------- -AC_DEFUN([PKG_CHECK_MODULES], -[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl -AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl -AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl - -pkg_failed=no -AC_MSG_CHECKING([for $1]) - -_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) -_PKG_CONFIG([$1][_LIBS], [libs], [$2]) - -m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS -and $1[]_LIBS to avoid the need to call pkg-config. -See the pkg-config man page for more details.]) - -if test $pkg_failed = yes; then - _PKG_SHORT_ERRORS_SUPPORTED - if test $_pkg_short_errors_supported = yes; then - $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "$2"` - else - $1[]_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "$2"` - fi - # Put the nasty error message in config.log where it belongs - echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD - - ifelse([$4], , [AC_MSG_ERROR(dnl -[Package requirements ($2) were not met: - -$$1_PKG_ERRORS - -Consider adjusting the PKG_CONFIG_PATH environment variable if you -installed software in a non-standard prefix. - -_PKG_TEXT -])], - [AC_MSG_RESULT([no]) - $4]) -elif test $pkg_failed = untried; then - ifelse([$4], , [AC_MSG_FAILURE(dnl -[The pkg-config script could not be found or is too old. Make sure it -is in your PATH or set the PKG_CONFIG environment variable to the full -path to pkg-config. - -_PKG_TEXT - -To get pkg-config, see <http://pkg-config.freedesktop.org/>.])], - [$4]) -else - $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS - $1[]_LIBS=$pkg_cv_[]$1[]_LIBS - AC_MSG_RESULT([yes]) - ifelse([$3], , :, [$3]) -fi[]dnl -])# PKG_CHECK_MODULES diff --git a/src/Makefile.am b/src/Makefile.am index 9e7fd2995..e0ea1c5de 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -13,7 +13,7 @@ TESTS = check_PROGRAMS = # Convenience targets: -lib: $(BUILT_SOURCES) libharfbuzz.la libharfbuzz-subset.la +lib: $(BUILT_SOURCES) libharfbuzz.la libs: $(BUILT_SOURCES) $(lib_LTLIBRARIES) fuzzing: $(BUILT_SOURCES) libharfbuzz-fuzzing.la libharfbuzz-subset-fuzzing.la @@ -29,11 +29,9 @@ HBSOURCES = $(HB_BASE_sources) HBSOURCES += $(HB_BASE_RAGEL_GENERATED_sources) HBHEADERS = $(HB_BASE_headers) -if HAVE_OT HBSOURCES += $(HB_OT_sources) HBSOURCES += $(HB_OT_RAGEL_GENERATED_sources) HBHEADERS += $(HB_OT_headers) -endif if HAVE_FALLBACK HBSOURCES += $(HB_FALLBACK_sources) @@ -271,7 +269,7 @@ EXTRA_DIST += \ CLEANFILES += $(pkgconfig_DATA) -DEF_FILES = harfbuzz.def harfbuzz-subset.def harfbuzz-icu.def +DEF_FILES = harfbuzz.def harfbuzz-subset.def harfbuzz-icu.def harfbuzz-deprecated.def if HAVE_GOBJECT DEF_FILES += harfbuzz-gobject.def endif @@ -285,17 +283,22 @@ harfbuzz-icu.def: $(HB_ICU_headers) $(AM_V_GEN) $(srcdir)/gen-def.py "$@" $^ harfbuzz-gobject.def: $(HB_GOBJECT_headers) $(AM_V_GEN) $(srcdir)/gen-def.py "$@" $^ +harfbuzz-deprecated.def: $(srcdir)/hb-deprecated.h + $(AM_V_GEN) $(srcdir)/gen-def.py "$@" $^ GENERATORS = \ gen-arabic-table.py \ + gen-def.py \ + gen-emoji-table.py \ gen-indic-table.py \ + gen-os2-unicode-ranges.py \ + gen-tag-table.py \ gen-use-table.py \ - gen-def.py \ $(NULL) EXTRA_DIST += $(GENERATORS) -unicode-tables: arabic-table indic-table use-table +unicode-tables: arabic-table indic-table tag-table use-table emoji-table arabic-table: gen-arabic-table.py ArabicShaping.txt UnicodeData.txt Blocks.txt $(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-ot-shape-complex-arabic-table.hh \ @@ -305,13 +308,21 @@ indic-table: gen-indic-table.py IndicSyllabicCategory.txt IndicPositionalCategor $(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) + 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) +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) -.PHONY: unicode-tables arabic-table indic-table use-table built-sources +.PHONY: unicode-tables arabic-table indic-table tag-table use-table emoji-table built-sources RAGEL_GENERATED = \ $(patsubst %,$(srcdir)/%,$(HB_BASE_RAGEL_GENERATED_sources)) \ diff --git a/src/Makefile.sources b/src/Makefile.sources index b981b0e26..59cde6bd1 100644 --- a/src/Makefile.sources +++ b/src/Makefile.sources @@ -1,28 +1,29 @@ # Base and default-included sources and headers HB_BASE_sources = \ - hb-atomic-private.hh \ - hb-blob-private.hh \ + hb-atomic.hh \ + hb-blob.hh \ hb-blob.cc \ - hb-buffer-private.hh \ + hb-buffer.hh \ hb-buffer-serialize.cc \ hb-buffer.cc \ + hb-cache.hh \ hb-common.cc \ hb-debug.hh \ hb-dsalgs.hh \ - hb-face-private.hh \ + hb-face.hh \ hb-face.cc \ - hb-font-private.hh \ + hb-font.hh \ hb-font.cc \ - hb-iter-private.hh \ - hb-map-private.hh \ + hb-iter.hh \ + hb-map.hh \ hb-map.cc \ - hb-machinery-private.hh \ - hb-mutex-private.hh \ + hb-machinery.hh \ + hb-mutex.hh \ hb-null.hh \ - hb-object-private.hh \ - hb-open-file-private.hh \ - hb-open-type-private.hh \ + hb-object.hh \ + hb-open-file.hh \ + hb-open-type.hh \ hb-ot-color-cbdt-table.hh \ hb-ot-cmap-table.hh \ hb-ot-glyf-table.hh \ @@ -37,24 +38,26 @@ HB_BASE_sources = \ hb-ot-os2-unicode-ranges.hh \ hb-ot-post-macroman.hh \ hb-ot-post-table.hh \ + hb-ot-tag-table.hh \ hb-ot-tag.cc \ - hb-private.hh \ - hb-set-digest-private.hh \ - hb-set-private.hh \ + hb.hh \ + hb-set-digest.hh \ + hb-set.hh \ hb-set.cc \ hb-shape.cc \ - hb-shape-plan-private.hh \ + hb-shape-plan.hh \ hb-shape-plan.cc \ hb-shaper-list.hh \ - hb-shaper-impl-private.hh \ - hb-shaper-private.hh \ + hb-shaper-impl.hh \ + hb-shaper.hh \ hb-shaper.cc \ hb-static.cc \ hb-string-array.hh \ - hb-unicode-private.hh \ + hb-unicode.hh \ + hb-unicode-emoji-table.hh \ hb-unicode.cc \ - hb-vector-private.hh \ - hb-utf-private.hh \ + hb-vector.hh \ + hb-utf.hh \ hb-warning.cc \ $(NULL) @@ -89,61 +92,62 @@ HB_FALLBACK_sources = \ HB_OT_sources = \ hb-aat-layout.cc \ - hb-aat-layout-common-private.hh \ + hb-aat-layout-common.hh \ hb-aat-layout-ankr-table.hh \ hb-aat-layout-bsln-table.hh \ hb-aat-layout-feat-table.hh \ hb-aat-layout-kerx-table.hh \ hb-aat-layout-morx-table.hh \ hb-aat-layout-trak-table.hh \ - hb-aat-layout-private.hh \ + hb-aat-layout.hh \ hb-aat-ltag-table.hh \ + hb-ot-face.hh \ + hb-ot-face.cc \ hb-ot-font.cc \ hb-ot-layout.cc \ hb-ot-layout-base-table.hh \ - hb-ot-layout-common-private.hh \ + hb-ot-layout-common.hh \ hb-ot-layout-gdef-table.hh \ hb-ot-layout-gpos-table.hh \ - hb-ot-layout-gsubgpos-private.hh \ + hb-ot-layout-gsubgpos.hh \ hb-ot-layout-gsub-table.hh \ hb-ot-layout-jstf-table.hh \ - hb-ot-layout-private.hh \ + hb-ot-layout.hh \ hb-ot-color.cc \ hb-ot-color-colr-table.hh \ hb-ot-color-cpal-table.hh \ hb-ot-color-sbix-table.hh \ hb-ot-color-svg-table.hh \ hb-ot-map.cc \ - hb-ot-map-private.hh \ + hb-ot-map.hh \ hb-ot-math.cc \ hb-ot-math-table.hh \ hb-ot-shape.cc \ hb-ot-shape-complex-arabic.cc \ hb-ot-shape-complex-arabic-fallback.hh \ - hb-ot-shape-complex-arabic-private.hh \ + hb-ot-shape-complex-arabic.hh \ hb-ot-shape-complex-arabic-table.hh \ hb-ot-shape-complex-arabic-win1256.hh \ hb-ot-shape-complex-default.cc \ hb-ot-shape-complex-hangul.cc \ hb-ot-shape-complex-hebrew.cc \ hb-ot-shape-complex-indic.cc \ - hb-ot-shape-complex-indic-private.hh \ + hb-ot-shape-complex-indic.hh \ hb-ot-shape-complex-indic-table.cc \ - hb-ot-shape-complex-khmer-private.hh \ + hb-ot-shape-complex-khmer.hh \ hb-ot-shape-complex-khmer.cc \ - hb-ot-shape-complex-myanmar-private.hh \ + hb-ot-shape-complex-myanmar.hh \ hb-ot-shape-complex-myanmar.cc \ hb-ot-shape-complex-thai.cc \ - hb-ot-shape-complex-tibetan.cc \ hb-ot-shape-complex-use.cc \ - hb-ot-shape-complex-use-private.hh \ + hb-ot-shape-complex-use.hh \ hb-ot-shape-complex-use-table.cc \ - hb-ot-shape-complex-private.hh \ - hb-ot-shape-normalize-private.hh \ + hb-ot-shape-complex.hh \ + hb-ot-shape-normalize.hh \ hb-ot-shape-normalize.cc \ - hb-ot-shape-fallback-private.hh \ + hb-ot-shape-fallback.hh \ hb-ot-shape-fallback.cc \ - hb-ot-shape-private.hh \ + hb-ot-shape.hh \ hb-ot-var.cc \ hb-ot-var-avar-table.hh \ hb-ot-var-fvar-table.hh \ @@ -169,6 +173,7 @@ HB_OT_headers = \ hb-ot-font.h \ hb-ot-layout.h \ hb-ot-math.h \ + hb-ot-name.h \ hb-ot-shape.h \ hb-ot-tag.h \ hb-ot-var.h \ @@ -207,16 +212,17 @@ HB_ICU_headers = hb-icu.h HB_SUBSET_sources = \ hb-static.cc \ hb-subset.cc \ + hb-subset.hh \ hb-subset-glyf.cc \ + hb-subset-glyf.hh \ hb-subset-input.cc \ + hb-subset-input.hh \ hb-subset-plan.cc \ + hb-subset-plan.hh \ $(NULL) HB_SUBSET_headers = \ hb-subset.h \ - hb-subset-glyf.hh \ - hb-subset-plan.hh \ - hb-subset-private.hh \ $(NULL) HB_GOBJECT_DIST_sources = hb-gobject-structs.cc diff --git a/src/check-includes.sh b/src/check-includes.sh index fd565da53..f938f706c 100755 --- a/src/check-includes.sh +++ b/src/check-includes.sh @@ -23,14 +23,14 @@ grep -v 'hb[.]h:' | grep . >&2 && stat=1 -echo 'Checking that source files #include "hb-*private.hh" first (or none)' +echo 'Checking that source files #include a private header first (or none)' for x in $HBSOURCES; do test -f "$srcdir/$x" -a ! -f "$x" && x="$srcdir/$x" - grep '#.*\<include\>' "$x" /dev/null | grep -v 'include _' | head -n 1 + grep '#.*\<include\>' "$x" /dev/null | head -n 1 done | -grep -v '"hb-.*private[.]hh"' | -grep -v 'hb-private[.]hh:' | +grep -v '"hb-.*[.]hh"' | +grep -v 'hb[.]hh' | grep . >&2 && stat=1 diff --git a/src/check-static-inits.sh b/src/check-static-inits.sh index 71551cbd4..def25c701 100755 --- a/src/check-static-inits.sh +++ b/src/check-static-inits.sh @@ -7,7 +7,6 @@ test -z "$srcdir" && srcdir=. test -z "$libs" && libs=.libs stat=0 - if which objdump 2>/dev/null >/dev/null; then : else @@ -31,7 +30,8 @@ done echo "Checking that no object file has lazy static C++ constructors/destructors or other such stuff" for obj in $OBJS; do - if objdump -t "$obj" | grep '__cxa_'; then + if objdump -t "$obj" | grep -q '__cxa_' && ! objdump -t "$obj" | grep -q __ubsan_handle; then + objdump -t "$obj" | grep '__cxa_' echo "Ouch, $obj has lazy static C++ constructors/destructors or other such stuff" stat=1 fi diff --git a/src/check-symbols.sh b/src/check-symbols.sh index d4eca5079..cea868488 100755 --- a/src/check-symbols.sh +++ b/src/check-symbols.sh @@ -26,7 +26,7 @@ for soname in harfbuzz harfbuzz-subset harfbuzz-icu harfbuzz-gobject; do symprefix= if test $suffix = dylib; then symprefix=_; fi - EXPORTED_SYMBOLS="`nm "$so" | grep ' [BCDGINRSTVW] .' | grep -v " $symprefix\\($IGNORED_SYMBOLS\\>\\)" | cut -d' ' -f3 | c++filt`" + EXPORTED_SYMBOLS="`nm "$so" | grep ' [BCDGINRST] .' | grep -v " $symprefix\\($IGNORED_SYMBOLS\\>\\)" | cut -d' ' -f3 | c++filt`" prefix=$symprefix`basename "$so" | sed 's/libharfbuzz/hb/; s/-/_/g; s/[.].*//'` diff --git a/src/dump-emoji.cc b/src/dump-emoji.cc index 65214692f..f45bc3106 100644 --- a/src/dump-emoji.cc +++ b/src/dump-emoji.cc @@ -45,8 +45,8 @@ #include <stdlib.h> #include <stdio.h> -void cbdt_callback (const uint8_t* data, unsigned int length, - unsigned int group, unsigned int gid) +static void cbdt_callback (const uint8_t* data, unsigned int length, + unsigned int group, unsigned int gid) { char output_path[255]; sprintf (output_path, "out/cbdt-%d-%d.png", group, gid); @@ -55,8 +55,8 @@ void cbdt_callback (const uint8_t* data, unsigned int length, fclose (f); } -void sbix_callback (const uint8_t* data, unsigned int length, - unsigned int group, unsigned int gid) +static void sbix_callback (const uint8_t* data, unsigned int length, + unsigned int group, unsigned int gid) { char output_path[255]; sprintf (output_path, "out/sbix-%d-%d.png", group, gid); @@ -65,8 +65,8 @@ void sbix_callback (const uint8_t* data, unsigned int length, fclose (f); } -void svg_callback (const uint8_t* data, unsigned int length, - unsigned int start_glyph, unsigned int end_glyph) +static void svg_callback (const uint8_t* data, unsigned int length, + unsigned int start_glyph, unsigned int end_glyph) { char output_path[255]; if (start_glyph == end_glyph) @@ -83,8 +83,8 @@ void svg_callback (const uint8_t* data, unsigned int length, fclose (f); } -void colr_cpal_rendering (cairo_font_face_t *cairo_face, unsigned int upem, unsigned int num_glyphs, - const OT::COLR *colr, const OT::CPAL *cpal) +static void colr_cpal_rendering (cairo_font_face_t *cairo_face, unsigned int upem, unsigned int num_glyphs, + const OT::COLR *colr, const OT::CPAL *cpal) { for (unsigned int i = 0; i < num_glyphs; ++i) { @@ -146,7 +146,7 @@ void colr_cpal_rendering (cairo_font_face_t *cairo_face, unsigned int upem, unsi int r = (color >> 8) & 0xFF; int g = (color >> 16) & 0xFF; int b = (color >> 24) & 0xFF; - cairo_set_source_rgba (cr, r / 255.f, g / 255.f, b / 255.f, alpha); + cairo_set_source_rgba (cr, r / 255., g / 255., b / 255., alpha); cairo_glyph_t glyph; glyph.index = glyph_id; @@ -162,7 +162,8 @@ void colr_cpal_rendering (cairo_font_face_t *cairo_face, unsigned int upem, unsi } } -void dump_glyphs (cairo_font_face_t *cairo_face, unsigned int upem, unsigned int num_glyphs) +static void dump_glyphs (cairo_font_face_t *cairo_face, unsigned int upem, + unsigned int num_glyphs) { // Dump every glyph available on the font return; // disabled for now @@ -210,10 +211,29 @@ void dump_glyphs (cairo_font_face_t *cairo_face, unsigned int upem, unsigned int int main (int argc, char **argv) { if (argc != 2) { - fprintf (stderr, "usage: %s font-file.ttf\n", argv[0]); + fprintf (stderr, "usage: %s font-file.ttf\n" + "run it like `rm -rf out && mkdir out && %s font-file.ttf`\n", + argv[0], argv[0]); exit (1); } + + FILE *font_name_file = fopen ("out/_font_name_file.txt", "r"); + if (font_name_file != nullptr) + { + fprintf (stderr, "Purge or move ./out folder in order to run a new dump\n"); + exit (1); + } + + font_name_file = fopen ("out/_font_name_file.txt", "w"); + if (font_name_file == nullptr) + { + fprintf (stderr, "./out is not accessible, create it please\n"); + exit (1); + } + fwrite (argv[1], 1, strlen (argv[1]), font_name_file); + fclose (font_name_file); + hb_blob_t *blob = hb_blob_create_from_file (argv[1]); hb_face_t *face = hb_face_create (blob, 0); hb_font_t *font = hb_font_create (face); diff --git a/src/dump-indic-data.cc b/src/dump-indic-data.cc index d57413884..a50688981 100644 --- a/src/dump-indic-data.cc +++ b/src/dump-indic-data.cc @@ -24,7 +24,7 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-ot-shape-complex-indic-private.hh" +#include "hb-ot-shape-complex-indic.hh" int main (void) diff --git a/src/dump-khmer-data.cc b/src/dump-khmer-data.cc index 7dd09b2b5..1e79a9767 100644 --- a/src/dump-khmer-data.cc +++ b/src/dump-khmer-data.cc @@ -24,7 +24,7 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-ot-shape-complex-khmer-private.hh" +#include "hb-ot-shape-complex-khmer.hh" int main (void) @@ -34,10 +34,8 @@ main (void) hb_glyph_info_t info; info.codepoint = u; set_khmer_properties (info); - if (info.khmer_category() != INDIC_SYLLABIC_CATEGORY_OTHER || - info.khmer_position() != INDIC_MATRA_CATEGORY_NOT_APPLICABLE) - printf("U+%04X %u %u\n", u, - info.khmer_category(), - info.khmer_position()); + if (info.khmer_category() != INDIC_SYLLABIC_CATEGORY_OTHER) + printf("U+%04X %u\n", u, + info.khmer_category()); } } diff --git a/src/dump-myanmar-data.cc b/src/dump-myanmar-data.cc index 2df9cd987..9f8b12ed2 100644 --- a/src/dump-myanmar-data.cc +++ b/src/dump-myanmar-data.cc @@ -24,7 +24,7 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-ot-shape-complex-myanmar-private.hh" +#include "hb-ot-shape-complex-myanmar.hh" int main (void) diff --git a/src/dump-use-data.cc b/src/dump-use-data.cc index 0e64688f1..4a8b25842 100644 --- a/src/dump-use-data.cc +++ b/src/dump-use-data.cc @@ -24,7 +24,7 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-ot-shape-complex-use-private.hh" +#include "hb-ot-shape-complex-use.hh" int main (void) diff --git a/src/gen-emoji-table.py b/src/gen-emoji-table.py new file mode 100755 index 000000000..278e0b2d4 --- /dev/null +++ b/src/gen-emoji-table.py @@ -0,0 +1,64 @@ +#!/usr/bin/python + +from __future__ import print_function, division, absolute_import +import sys +import os.path +from collections import OrderedDict + +if len (sys.argv) != 2: + print("usage: ./gen-emoji-table.py emoji-data.txt", file=sys.stderr) + sys.exit (1) + +f = open(sys.argv[1]) +header = [f.readline () for _ in range(10)] + +sets = OrderedDict() +for line in f.readlines(): + line = line.strip() + if not line or line[0] == '#': + continue + rang, typ = [s.strip() for s in line.split('#')[0].split(';')[:2]] + + rang = [int(s, 16) for s in rang.split('..')] + if len(rang) > 1: + start, end = rang + else: + start = end = rang[0] + + if typ not in sets: + sets[typ] = set() + sets[typ].add((start, end)) + + + +print ("/* == Start of generated table == */") +print ("/*") +print (" * The following tables are generated by running:") +print (" *") +print (" * ./gen-emoji-table.py emoji-data.txt") +print (" *") +print (" * on file with this header:") +print (" *") +for l in header: + print (" * %s" % (l.strip())) +print (" */") +print () +print ("#ifndef HB_UNICODE_EMOJI_TABLE_HH") +print ("#define HB_UNICODE_EMOJI_TABLE_HH") +print () +print ('#include "hb-unicode.hh"') +print () + +for typ,s in sets.items(): + if typ != "Extended_Pictographic": continue + 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 */") +print () +print ("/* == End of generated table == */") diff --git a/src/gen-indic-table.py b/src/gen-indic-table.py index 6252664ca..e65b9814a 100755 --- a/src/gen-indic-table.py +++ b/src/gen-indic-table.py @@ -102,7 +102,7 @@ for h in headers: print (" * %s" % (l.strip())) print (" */") print () -print ('#include "hb-ot-shape-complex-indic-private.hh"') +print ('#include "hb-ot-shape-complex-indic.hh"') print () # Shorten values diff --git a/src/gen-unicode-ranges.py b/src/gen-os2-unicode-ranges.py index 30249a8f8..d768313dd 100644 --- a/src/gen-unicode-ranges.py +++ b/src/gen-os2-unicode-ranges.py @@ -13,7 +13,7 @@ import sys reload(sys) sys.setdefaultencoding('utf-8') -print ("""static Range os2UnicodeRangesSorted[] = +print ("""static OS2Range _hb_os2_unicode_ranges[] = {""") args = sys.argv[1:] diff --git a/src/gen-tag-table.py b/src/gen-tag-table.py new file mode 100755 index 000000000..13004629d --- /dev/null +++ b/src/gen-tag-table.py @@ -0,0 +1,1126 @@ +#!/usr/bin/python + +"""Generator of the mapping from OpenType tags to BCP 47 tags and vice +versa. + +It creates a ``const LangTag[]``, matching the tags from the OpenType +languages system tag list to the language subtags of the BCP 47 language +subtag registry, with some manual adjustments. The mappings are +supplemented with macrolanguages' sublanguages and retired codes' +replacements, according to BCP 47 and some manual additions where BCP 47 +omits a retired code entirely. + +Also generated is a function, ``hb_ot_ambiguous_tag_to_language``, +intended for use by ``hb_ot_tag_to_language``. It maps OpenType tags +back to BCP 47 tags. Ambiguous OpenType tags (those that correspond to +multiple BCP 47 tags) are listed here, except when the alphabetically +first BCP 47 tag happens to be the chosen disambiguated tag. In that +case, the fallback behavior will choose the right tag anyway. +""" + +from __future__ import absolute_import, division, print_function, unicode_literals + +import collections +try: + from HTMLParser import HTMLParser + def write (s): + print (s.encode ('utf-8'), end='') +except ImportError: + from html.parser import HTMLParser + def write (s): + sys.stdout.flush () + sys.stdout.buffer.write (s.encode ('utf-8')) +import io +import itertools +import re +import sys +import unicodedata + +if len (sys.argv) != 3: + print ('usage: ./gen-tag-table.py languagetags language-subtag-registry', file=sys.stderr) + sys.exit (1) + +try: + from html import unescape + def html_unescape (parser, entity): + return unescape (entity) +except ImportError: + def html_unescape (parser, entity): + return parser.unescape (entity) + +def expect (condition, message=None): + if not condition: + if message is None: + raise AssertionError + raise AssertionError (message) + +# from http://www-01.sil.org/iso639-3/iso-639-3.tab +ISO_639_3_TO_1 = { + 'aar': 'aa', + 'abk': 'ab', + 'afr': 'af', + 'aka': 'ak', + 'amh': 'am', + 'ara': 'ar', + 'arg': 'an', + 'asm': 'as', + 'ava': 'av', + 'ave': 'ae', + 'aym': 'ay', + 'aze': 'az', + 'bak': 'ba', + 'bam': 'bm', + 'bel': 'be', + 'ben': 'bn', + 'bis': 'bi', + 'bod': 'bo', + 'bos': 'bs', + 'bre': 'br', + 'bul': 'bg', + 'cat': 'ca', + 'ces': 'cs', + 'cha': 'ch', + 'che': 'ce', + 'chu': 'cu', + 'chv': 'cv', + 'cor': 'kw', + 'cos': 'co', + 'cre': 'cr', + 'cym': 'cy', + 'dan': 'da', + 'deu': 'de', + 'div': 'dv', + 'dzo': 'dz', + 'ell': 'el', + 'eng': 'en', + 'epo': 'eo', + 'est': 'et', + 'eus': 'eu', + 'ewe': 'ee', + 'fao': 'fo', + 'fas': 'fa', + 'fij': 'fj', + 'fin': 'fi', + 'fra': 'fr', + 'fry': 'fy', + 'ful': 'ff', + 'gla': 'gd', + 'gle': 'ga', + 'glg': 'gl', + 'glv': 'gv', + 'grn': 'gn', + 'guj': 'gu', + 'hat': 'ht', + 'hau': 'ha', + 'hbs': 'sh', + 'heb': 'he', + 'her': 'hz', + 'hin': 'hi', + 'hmo': 'ho', + 'hrv': 'hr', + 'hun': 'hu', + 'hye': 'hy', + 'ibo': 'ig', + 'ido': 'io', + 'iii': 'ii', + 'iku': 'iu', + 'ile': 'ie', + 'ina': 'ia', + 'ind': 'id', + 'ipk': 'ik', + 'isl': 'is', + 'ita': 'it', + 'jav': 'jv', + 'jpn': 'ja', + 'kal': 'kl', + 'kan': 'kn', + 'kas': 'ks', + 'kat': 'ka', + 'kau': 'kr', + 'kaz': 'kk', + 'khm': 'km', + 'kik': 'ki', + 'kin': 'rw', + 'kir': 'ky', + 'kom': 'kv', + 'kon': 'kg', + 'kor': 'ko', + 'kua': 'kj', + 'kur': 'ku', + 'lao': 'lo', + 'lat': 'la', + 'lav': 'lv', + 'lim': 'li', + 'lin': 'ln', + 'lit': 'lt', + 'ltz': 'lb', + 'lub': 'lu', + 'lug': 'lg', + 'mah': 'mh', + 'mal': 'ml', + 'mar': 'mr', + 'mkd': 'mk', + 'mlg': 'mg', + 'mlt': 'mt', + 'mol': 'mo', + 'mon': 'mn', + 'mri': 'mi', + 'msa': 'ms', + 'mya': 'my', + 'nau': 'na', + 'nav': 'nv', + 'nbl': 'nr', + 'nde': 'nd', + 'ndo': 'ng', + 'nep': 'ne', + 'nld': 'nl', + 'nno': 'nn', + 'nob': 'nb', + 'nor': 'no', + 'nya': 'ny', + 'oci': 'oc', + 'oji': 'oj', + 'ori': 'or', + 'orm': 'om', + 'oss': 'os', + 'pan': 'pa', + 'pli': 'pi', + 'pol': 'pl', + 'por': 'pt', + 'pus': 'ps', + 'que': 'qu', + 'roh': 'rm', + 'ron': 'ro', + 'run': 'rn', + 'rus': 'ru', + 'sag': 'sg', + 'san': 'sa', + 'sin': 'si', + 'slk': 'sk', + 'slv': 'sl', + 'sme': 'se', + 'smo': 'sm', + 'sna': 'sn', + 'snd': 'sd', + 'som': 'so', + 'sot': 'st', + 'spa': 'es', + 'sqi': 'sq', + 'srd': 'sc', + 'srp': 'sr', + 'ssw': 'ss', + 'sun': 'su', + 'swa': 'sw', + 'swe': 'sv', + 'tah': 'ty', + 'tam': 'ta', + 'tat': 'tt', + 'tel': 'te', + 'tgk': 'tg', + 'tgl': 'tl', + 'tha': 'th', + 'tir': 'ti', + 'ton': 'to', + 'tsn': 'tn', + 'tso': 'ts', + 'tuk': 'tk', + 'tur': 'tr', + 'twi': 'tw', + 'uig': 'ug', + 'ukr': 'uk', + 'urd': 'ur', + 'uzb': 'uz', + 'ven': 've', + 'vie': 'vi', + 'vol': 'vo', + 'wln': 'wa', + 'wol': 'wo', + 'xho': 'xh', + 'yid': 'yi', + 'yor': 'yo', + 'zha': 'za', + 'zho': 'zh', + 'zul': 'zu', +} + +class LanguageTag (object): + """A BCP 47 language tag. + + Attributes: + subtags (List[str]): The list of subtags in this tag. + grandfathered (bool): Whether this tag is grandfathered. If + ``true``, the entire lowercased tag is the ``language`` + and the other subtag fields are empty. + language (str): The language subtag. + script (str): The script subtag. + region (str): The region subtag. + variant (str): The variant subtag. + + Args: + tag (str): A BCP 47 language tag. + + """ + def __init__ (self, tag): + global bcp_47 + self.subtags = tag.lower ().split ('-') + self.grandfathered = tag.lower () in bcp_47.grandfathered + if self.grandfathered: + self.language = tag.lower () + self.script = '' + self.region = '' + self.variant = '' + else: + self.language = self.subtags[0] + self.script = self._find_first (lambda s: len (s) == 4 and s[0] > '9', self.subtags) + self.region = self._find_first (lambda s: len (s) == 2 and s[0] > '9' or len (s) == 3 and s[0] <= '9', self.subtags[1:]) + self.variant = self._find_first (lambda s: len (s) > 4 or len (s) == 4 and s[0] <= '9', self.subtags) + + def __str__(self): + return '-'.join(self.subtags) + + def __repr__ (self): + return 'LanguageTag(%r)' % str(self) + + @staticmethod + def _find_first (function, sequence): + try: + return next (iter (filter (function, sequence))) + except StopIteration: + return None + + def is_complex (self): + """Return whether this tag is too complex to represent as a + ``LangTag`` in the generated code. + + Complex tags need to be handled in + ``hb_ot_tags_from_complex_language``. + + Returns: + Whether this tag is complex. + """ + return not (len (self.subtags) == 1 + or self.grandfathered + and len (self.subtags[1]) != 3 + and ot.from_bcp_47[self.subtags[0]] == ot.from_bcp_47[self.language]) + + def get_group (self): + """Return the group into which this tag should be categorized in + ``hb_ot_tags_from_complex_language``. + + The group is the first letter of the tag, or ``'und'`` if this tag + should not be matched in a ``switch`` statement in the generated + code. + + Returns: + This tag's group. + """ + return ('und' + if (self.language == 'und' + or self.variant in bcp_47.prefixes and len (bcp_47.prefixes[self.variant]) == 1) + else self.language[0]) + +class OpenTypeRegistryParser (HTMLParser): + """A parser for the OpenType language system tag registry. + + Attributes: + header (str): The "last updated" line of the registry. + names (Mapping[str, str]): A map of language system tags to the + names they are given in the registry. + ranks (DefaultDict[str, int]): A map of language system tags to + numbers. If a single BCP 47 tag corresponds to multiple + OpenType tags, the tags are ordered in increasing order by + rank. The rank is based on the number of BCP 47 tags + associated with a tag, though it may be manually modified. + to_bcp_47 (DefaultDict[str, AbstractSet[str]]): A map of + OpenType language system tags to sets of BCP 47 tags. + from_bcp_47 (DefaultDict[str, AbstractSet[str]]): ``to_bcp_47`` + inverted. Its values start as unsorted sets; + ``sort_languages`` converts them to sorted lists. + + """ + def __init__ (self): + HTMLParser.__init__ (self) + self.header = '' + self.names = {} + self.ranks = collections.defaultdict (int) + self.to_bcp_47 = collections.defaultdict (set) + self.from_bcp_47 = collections.defaultdict (set) + # Whether the parser is in a <td> element + self._td = False + # The text of the <td> elements of the current <tr> element. + self._current_tr = [] + + def handle_starttag (self, tag, attrs): + if tag == 'meta': + for attr, value in attrs: + if attr == 'name' and value == 'updated_at': + self.header = self.get_starttag_text () + break + elif tag == 'td': + self._td = True + self._current_tr.append ('') + elif tag == 'tr': + self._current_tr = [] + + def handle_endtag (self, tag): + if tag == 'td': + self._td = False + elif tag == 'tr' and self._current_tr: + expect (2 <= len (self._current_tr) <= 3) + name = self._current_tr[0].strip () + tag = self._current_tr[1].strip ("\t\n\v\f\r '") + rank = 0 + if len (tag) > 4: + expect (tag.endswith (' (deprecated)'), 'ill-formed OpenType tag: %s' % tag) + name += ' (deprecated)' + tag = tag.split (' ')[0] + rank = 1 + self.names[tag] = re.sub (' languages$', '', name) + if not self._current_tr[2]: + return + iso_codes = self._current_tr[2].strip () + self.to_bcp_47[tag].update (ISO_639_3_TO_1.get (code, code) for code in iso_codes.replace (' ', '').split (',')) + rank += 2 * len (self.to_bcp_47[tag]) + self.ranks[tag] = rank + + def handle_data (self, data): + if self._td: + self._current_tr[-1] += data + + def handle_charref (self, name): + self.handle_data (html_unescape (self, '&#%s;' % name)) + + def handle_entityref (self, name): + self.handle_data (html_unescape (self, '&%s;' % name)) + + def parse (self, filename): + """Parse the OpenType language system tag registry. + + Args: + filename (str): The file name of the registry. + """ + with io.open (filename, encoding='utf-8') as f: + self.feed (f.read ()) + expect (self.header) + for tag, iso_codes in self.to_bcp_47.items (): + for iso_code in iso_codes: + self.from_bcp_47[iso_code].add (tag) + + def add_language (self, bcp_47_tag, ot_tag): + """Add a language as if it were in the registry. + + Args: + bcp_47_tag (str): A BCP 47 tag. If the tag is more than just + a language subtag, and if the language subtag is a + macrolanguage, then new languages are added corresponding + to the macrolanguages' individual languages with the + remainder of the tag appended. + ot_tag (str): An OpenType language system tag. + """ + global bcp_47 + self.to_bcp_47[ot_tag].add (bcp_47_tag) + self.from_bcp_47[bcp_47_tag].add (ot_tag) + if bcp_47_tag.lower () not in bcp_47.grandfathered: + try: + [macrolanguage, suffix] = bcp_47_tag.split ('-', 1) + if macrolanguage in bcp_47.macrolanguages: + s = set () + for language in bcp_47.macrolanguages[macrolanguage]: + if language.lower () not in bcp_47.grandfathered: + s.add ('%s-%s' % (language, suffix)) + bcp_47.macrolanguages['%s-%s' % (macrolanguage, suffix)] = s + except ValueError: + pass + + @staticmethod + def _remove_language (tag_1, dict_1, dict_2): + for tag_2 in dict_1.pop (tag_1): + dict_2[tag_2].remove (tag_1) + if not dict_2[tag_2]: + del dict_2[tag_2] + + def remove_language_ot (self, ot_tag): + """Remove an OpenType tag from the registry. + + Args: + ot_tag (str): An OpenType tag. + """ + self._remove_language (ot_tag, self.to_bcp_47, self.from_bcp_47) + + def remove_language_bcp_47 (self, bcp_47_tag): + """Remove a BCP 47 tag from the registry. + + Args: + bcp_47_tag (str): A BCP 47 tag. + """ + self._remove_language (bcp_47_tag, self.from_bcp_47, self.to_bcp_47) + + def inherit_from_macrolanguages (self): + """Copy mappings from macrolanguages to individual languages. + + If a BCP 47 tag for an individual mapping has no OpenType + mapping but its macrolanguage does, the mapping is copied to + the individual language. For example, als (Tosk Albanian) has no + explicit mapping, so it inherits from sq (Albanian) the mapping + to SQI. + + If a BCP 47 tag for a macrolanguage has no OpenType mapping but + all of its individual languages do and they all map to the same + tags, the mapping is copied to the macrolanguage. + """ + global bcp_47 + original_ot_from_bcp_47 = dict (self.from_bcp_47) + for macrolanguage, languages in dict (bcp_47.macrolanguages).items (): + ot_macrolanguages = set (original_ot_from_bcp_47.get (macrolanguage, set ())) + if ot_macrolanguages: + for ot_macrolanguage in ot_macrolanguages: + for language in languages: + # Remove the following condition if e.g. nn should map to NYN,NOR + # instead of just NYN. + if language not in original_ot_from_bcp_47: + self.add_language (language, ot_macrolanguage) + self.ranks[ot_macrolanguage] += 1 + else: + for language in languages: + if language in original_ot_from_bcp_47: + if ot_macrolanguages: + ml = original_ot_from_bcp_47[language] + if ml: + ot_macrolanguages &= ml + else: + pass + else: + ot_macrolanguages |= original_ot_from_bcp_47[language] + else: + ot_macrolanguages.clear () + if not ot_macrolanguages: + break + for ot_macrolanguage in ot_macrolanguages: + self.add_language (macrolanguage, ot_macrolanguage) + + def sort_languages (self): + """Sort the values of ``from_bcp_47`` in ascending rank order.""" + for language, tags in self.from_bcp_47.items (): + self.from_bcp_47[language] = sorted (tags, + key=lambda t: (self.ranks[t] + rank_delta (language, t), t)) + +ot = OpenTypeRegistryParser () + +class BCP47Parser (object): + """A parser for the BCP 47 subtag registry. + + Attributes: + header (str): The "File-Date" line of the registry. + names (Mapping[str, str]): A map of subtags to the names they + are given in the registry. Each value is a + ``'\\n'``-separated list of names. + scopes (Mapping[str, str]): A map of language subtags to strings + suffixed to language names, including suffixes to explain + language scopes. + macrolanguages (DefaultDict[str, AbstractSet[str]]): A map of + language subtags to the sets of language subtags which + inherit from them. See + ``OpenTypeRegistryParser.inherit_from_macrolanguages``. + prefixes (DefaultDict[str, AbstractSet[str]]): A map of variant + subtags to their prefixes. + grandfathered (AbstractSet[str]): The set of grandfathered tags, + normalized to lowercase. + + """ + def __init__ (self): + self.header = '' + self.names = {} + self.scopes = {} + self.macrolanguages = collections.defaultdict (set) + self.prefixes = collections.defaultdict (set) + self.grandfathered = set () + + def parse (self, filename): + """Parse the BCP 47 subtag registry. + + Args: + filename (str): The file name of the registry. + """ + with io.open (filename, encoding='utf-8') as f: + subtag_type = None + subtag = None + deprecated = False + has_preferred_value = False + line_buffer = '' + for line in itertools.chain (f, ['']): + line = line.rstrip () + if line.startswith (' '): + line_buffer += line[1:] + continue + line, line_buffer = line_buffer, line + if line.startswith ('Type: '): + subtag_type = line.split (' ')[1] + deprecated = False + has_preferred_value = False + elif line.startswith ('Subtag: ') or line.startswith ('Tag: '): + subtag = line.split (' ')[1] + if subtag_type == 'grandfathered': + self.grandfathered.add (subtag.lower ()) + elif line.startswith ('Description: '): + description = line.split (' ', 1)[1].replace (' (individual language)', '') + description = re.sub (' (\((individual |macro)language\)|languages)$', '', + description) + if subtag in self.names: + self.names[subtag] += '\n' + description + else: + self.names[subtag] = description + elif subtag_type == 'language' or subtag_type == 'grandfathered': + if line.startswith ('Scope: '): + scope = line.split (' ')[1] + if scope == 'macrolanguage': + scope = ' [macrolanguage]' + elif scope == 'collection': + scope = ' [family]' + else: + continue + self.scopes[subtag] = scope + elif line.startswith ('Deprecated: '): + self.scopes[subtag] = ' (retired code)' + self.scopes.get (subtag, '') + deprecated = True + elif deprecated and line.startswith ('Comments: see '): + # If a subtag is split into multiple replacement subtags, + # it essentially represents a macrolanguage. + for language in line.replace (',', '').split (' ')[2:]: + self._add_macrolanguage (subtag, language) + elif line.startswith ('Preferred-Value: '): + # If a subtag is deprecated in favor of a single replacement subtag, + # it is either a dialect or synonym of the preferred subtag. Either + # way, it is close enough to the truth to consider the replacement + # the macrolanguage of the deprecated language. + has_preferred_value = True + macrolanguage = line.split (' ')[1] + self._add_macrolanguage (macrolanguage, subtag) + elif not has_preferred_value and line.startswith ('Macrolanguage: '): + self._add_macrolanguage (line.split (' ')[1], subtag) + elif subtag_type == 'variant': + if line.startswith ('Prefix: '): + self.prefixes[subtag].add (line.split (' ')[1]) + elif line.startswith ('File-Date: '): + self.header = line + expect (self.header) + + def _add_macrolanguage (self, macrolanguage, language): + global ot + if language not in ot.from_bcp_47: + for l in self.macrolanguages.get (language, set ()): + self._add_macrolanguage (macrolanguage, l) + if macrolanguage not in ot.from_bcp_47: + for ls in list (self.macrolanguages.values ()): + if macrolanguage in ls: + ls.add (language) + return + self.macrolanguages[macrolanguage].add (language) + + def remove_extra_macrolanguages (self): + """Make every language have at most one macrolanguage.""" + inverted = collections.defaultdict (list) + for macrolanguage, languages in self.macrolanguages.items (): + for language in languages: + inverted[language].append (macrolanguage) + for language, macrolanguages in inverted.items (): + if len (macrolanguages) > 1: + macrolanguages.sort (key=lambda ml: len (self.macrolanguages[ml])) + biggest_macrolanguage = macrolanguages.pop () + for macrolanguage in macrolanguages: + self._add_macrolanguage (biggest_macrolanguage, macrolanguage) + + def get_name (self, lt): + """Return the names of the subtags in a language tag. + + Args: + lt (LanguageTag): A BCP 47 language tag. + + Returns: + The name form of ``lt``. + """ + name = self.names[lt.language].split ('\n')[0] + if lt.script: + name += '; ' + self.names[lt.script.title ()].split ('\n')[0] + if lt.region: + name += '; ' + self.names[lt.region.upper ()].split ('\n')[0] + if lt.variant: + name += '; ' + self.names[lt.variant].split ('\n')[0] + return name + +bcp_47 = BCP47Parser () + +ot.parse (sys.argv[1]) +bcp_47.parse (sys.argv[2]) + +ot.add_language ('ary', 'MOR') + +ot.add_language ('ath', 'ATH') + +ot.add_language ('bai', 'BML') + +ot.ranks['BAL'] = ot.ranks['KAR'] + 1 + +ot.add_language ('ber', 'BBR') + +ot.remove_language_ot ('PGR') +ot.add_language ('el-polyton', 'PGR') + +bcp_47.macrolanguages['et'] = {'ekk'} + +bcp_47.names['flm'] = 'Falam Chin' +bcp_47.scopes['flm'] = ' (retired code)' +bcp_47.macrolanguages['flm'] = {'cfm'} + +ot.ranks['FNE'] = ot.ranks['TNE'] + 1 + +ot.add_language ('und-fonipa', 'IPPH') + +ot.add_language ('und-fonnapa', 'APPH') + +ot.remove_language_ot ('IRT') +ot.add_language ('ga-Latg', 'IRT') + +ot.remove_language_ot ('KGE') +ot.add_language ('und-Geok', 'KGE') + +ot.add_language ('guk', 'GUK') +ot.names['GUK'] = 'Gumuz (SIL fonts)' +ot.ranks['GUK'] = ot.ranks['GMZ'] + 1 + +bcp_47.macrolanguages['id'] = {'in'} + +bcp_47.macrolanguages['ijo'] = {'ijc'} + +ot.add_language ('kht', 'KHN') +ot.names['KHN'] = ot.names['KHT'] + ' (Microsoft fonts)' +ot.names['KHT'] = ot.names['KHT'] + ' (OpenType spec and SIL fonts)' +ot.ranks['KHN'] = ot.ranks['KHT'] +ot.ranks['KHT'] += 1 + +ot.ranks['LCR'] = ot.ranks['MCR'] + 1 + +ot.names['MAL'] = 'Malayalam Traditional' +ot.ranks['MLR'] += 1 + +bcp_47.names['mhv'] = 'Arakanese' +bcp_47.scopes['mhv'] = ' (retired code)' + +ot.add_language ('no', 'NOR') + +ot.add_language ('oc-provenc', 'PRO') + +ot.add_language ('qu', 'QUZ') +ot.add_language ('qub', 'QWH') +ot.add_language ('qud', 'QVI') +ot.add_language ('qug', 'QVI') +ot.add_language ('qup', 'QVI') +ot.add_language ('qur', 'QWH') +ot.add_language ('qus', 'QUH') +ot.add_language ('quw', 'QVI') +ot.add_language ('qux', 'QWH') +ot.add_language ('qva', 'QWH') +ot.add_language ('qvh', 'QWH') +ot.add_language ('qvj', 'QVI') +ot.add_language ('qvl', 'QWH') +ot.add_language ('qvm', 'QWH') +ot.add_language ('qvn', 'QWH') +ot.add_language ('qvo', 'QVI') +ot.add_language ('qvp', 'QWH') +ot.add_language ('qvw', 'QWH') +ot.add_language ('qvz', 'QVI') +ot.add_language ('qwa', 'QWH') +ot.add_language ('qws', 'QWH') +ot.add_language ('qxa', 'QWH') +ot.add_language ('qxc', 'QWH') +ot.add_language ('qxh', 'QWH') +ot.add_language ('qxl', 'QVI') +ot.add_language ('qxn', 'QWH') +ot.add_language ('qxo', 'QWH') +ot.add_language ('qxr', 'QVI') +ot.add_language ('qxt', 'QWH') +ot.add_language ('qxw', 'QWH') + +bcp_47.macrolanguages['ro'].remove ('mo') +bcp_47.macrolanguages['ro-MD'].add ('mo') + +ot.add_language ('sgw', 'SGW') +ot.names['SGW'] = ot.names['CHG'] + ' (SIL fonts)' +ot.ranks['SGW'] = ot.ranks['CHG'] + 1 + +ot.remove_language_ot ('SYRE') +ot.remove_language_ot ('SYRJ') +ot.remove_language_ot ('SYRN') +ot.add_language ('und-Syre', 'SYRE') +ot.add_language ('und-Syrj', 'SYRJ') +ot.add_language ('und-Syrn', 'SYRN') + +bcp_47.names['xst'] = u"Silt'e" +bcp_47.scopes['xst'] = ' (retired code)' +bcp_47.macrolanguages['xst'] = {'stv', 'wle'} + +ot.add_language ('xwo', 'TOD') + +ot.remove_language_ot ('ZHH') +ot.remove_language_ot ('ZHP') +ot.remove_language_ot ('ZHT') +bcp_47.macrolanguages['zh'].remove ('lzh') +bcp_47.macrolanguages['zh'].remove ('yue') +ot.add_language ('zh-Hant-MO', 'ZHH') +ot.add_language ('zh-Hant-HK', 'ZHH') +ot.add_language ('zh-Hans', 'ZHS') +ot.add_language ('zh-Hant', 'ZHT') +ot.add_language ('zh-HK', 'ZHH') +ot.add_language ('zh-MO', 'ZHH') +ot.add_language ('zh-TW', 'ZHT') +ot.add_language ('lzh', 'ZHT') +ot.add_language ('lzh-Hans', 'ZHS') +ot.add_language ('yue', 'ZHH') +ot.add_language ('yue-Hans', 'ZHS') + +bcp_47.macrolanguages['zom'] = {'yos'} + +def rank_delta (bcp_47, ot): + """Return a delta to apply to a BCP 47 tag's rank. + + Most OpenType tags have a constant rank, but a few have ranks that + depend on the BCP 47 tag. + + Args: + bcp_47 (str): A BCP 47 tag. + ot (str): An OpenType tag to. + + Returns: + A number to add to ``ot``'s rank when sorting ``bcp_47``'s + OpenType equivalents. + """ + if bcp_47 == 'ak' and ot == 'AKA': + return -1 + if bcp_47 == 'tw' and ot == 'TWI': + return -1 + return 0 + +disambiguation = { + 'ALT': 'alt', + 'ARK': 'rki', + 'BHI': 'bhb', + 'BLN': 'bjt', + 'BTI': 'beb', + 'CCHN': 'cco', + 'CMR': 'swb', + 'CPP': 'crp', + 'CRR': 'crx', + 'DUJ': 'dwu', + 'ECR': 'crj', + 'HAL': 'cfm', + 'HND': 'hnd', + 'KIS': 'kqs', + 'LRC': 'bqi', + 'NDB': 'nd', + 'NIS': 'njz', + 'PLG': 'pce', + 'PRO': 'pro', + 'QIN': 'bgr', + 'QUH': 'quh', + 'QVI': 'qvi', + 'QWH': 'qwh', + 'SIG': 'stv', + 'TNE': 'yrk', + 'ZHH': 'zh-HK', + 'ZHS': 'zh-Hans', + 'ZHT': 'zh-Hant', +} + +ot.inherit_from_macrolanguages () +bcp_47.remove_extra_macrolanguages () +ot.inherit_from_macrolanguages () +ot.sort_languages () + +print ('/* == Start of generated table == */') +print ('/*') +print (' * The following table is generated by running:') +print (' *') +print (' * %s languagetags language-subtag-registry' % sys.argv[0]) +print (' *') +print (' * on files with these headers:') +print (' *') +print (' * %s' % ot.header.strip ()) +print (' * %s' % bcp_47.header) +print (' */') +print () +print ('#ifndef HB_OT_TAG_TABLE_HH') +print ('#define HB_OT_TAG_TABLE_HH') +print () +print ('static const LangTag ot_languages[] = {') + +def hb_tag (tag): + """Convert a tag to ``HB_TAG`` form. + + Args: + tag (str): An OpenType tag. + + Returns: + A snippet of C++ representing ``tag``. + """ + return u"HB_TAG('%s','%s','%s','%s')" % tuple (('%-4s' % tag)[:4]) + +def get_variant_set (name): + """Return a set of variant language names from a name. + + Args: + name (str): A list of language names from the BCP 47 registry, + joined on ``'\\n'``. + + Returns: + A set of normalized language names. + """ + return set (unicodedata.normalize ('NFD', n.replace ('\u2019', u"'")) + .encode ('ASCII', 'ignore') + .strip () + for n in re.split ('[\n(),]', name) if n) + +def language_name_intersection (a, b): + """Return the names in common between two language names. + + Args: + a (str): A list of language names from the BCP 47 registry, + joined on ``'\\n'``. + b (str): A list of language names from the BCP 47 registry, + joined on ``'\\n'``. + + Returns: + The normalized language names shared by ``a`` and ``b``. + """ + return get_variant_set (a).intersection (get_variant_set (b)) + +def get_matching_language_name (intersection, candidates): + return next (iter (c for c in candidates if not intersection.isdisjoint (get_variant_set (c)))) + +maximum_tags = 0 +for language, tags in sorted (ot.from_bcp_47.items ()): + if language == '' or '-' in language: + continue + print (' {\"%s\",\t{' % language, end='') + maximum_tags = max (maximum_tags, len (tags)) + tag_count = len (tags) + for i, tag in enumerate (tags, start=1): + if i > 1: + print ('\t\t ', end='') + print (hb_tag (tag), end='') + if i == tag_count: + print ('}}', end='') + print (',\t/* ', end='') + bcp_47_name = bcp_47.names.get (language, '') + bcp_47_name_candidates = bcp_47_name.split ('\n') + intersection = language_name_intersection (bcp_47_name, ot.names[tag]) + scope = bcp_47.scopes.get (language, '') + if not intersection: + write ('%s%s -> %s' % (bcp_47_name_candidates[0], scope, ot.names[tag])) + else: + name = get_matching_language_name (intersection, bcp_47_name_candidates) + bcp_47.names[language] = name + write ('%s%s' % (name if len (name) > len (ot.names[tag]) else ot.names[tag], scope)) + print (' */') + +print ('};') +print () +print ('static_assert (HB_OT_MAX_TAGS_PER_LANGUAGE == %iu, "");' % maximum_tags) +print () + +print ('/**') +print (' * hb_ot_tags_from_complex_language:') +print (' * @lang_str: a BCP 47 language tag to convert.') +print (' * @limit: a pointer to the end of the substring of @lang_str to consider for') +print (' * conversion.') +print (' * @count: maximum number of language tags to retrieve (IN) and actual number of') +print (' * language tags retrieved (OUT). If no tags are retrieved, it is not modified.') +print (' * @tags: array of size at least @language_count to store the language tag') +print (' * results') +print (' *') +print (' * Converts a multi-subtag BCP 47 language tag to language tags.') +print (' *') +print (' * Return value: Whether any language systems were retrieved.') +print (' **/') +print ('static bool') +print ('hb_ot_tags_from_complex_language (const char *lang_str,') +print ('\t\t\t\t const char *limit,') +print ('\t\t\t\t unsigned int *count /* IN/OUT */,') +print ('\t\t\t\t hb_tag_t *tags /* OUT */)') +print ('{') + +def print_subtag_matches (subtag, new_line): + if subtag: + if new_line: + print () + print ('\t&& ', end='') + print ('subtag_matches (lang_str, limit, "-%s")' % subtag, end='') + +complex_tags = collections.defaultdict (list) +for initial, group in itertools.groupby ((lt_tags for lt_tags in [ + (LanguageTag (language), tags) + for language, tags in sorted (ot.from_bcp_47.items (), + key=lambda i: (-len (i[0]), i[0])) + ] if lt_tags[0].is_complex ()), + key=lambda lt_tags: lt_tags[0].get_group ()): + complex_tags[initial] += group + +for initial, items in sorted (complex_tags.items ()): + if initial != 'und': + continue + for lt, tags in items: + if lt.variant in bcp_47.prefixes: + expect (next (iter (bcp_47.prefixes[lt.variant])) == lt.language, + '%s is not a valid prefix of %s' % (lt.language, lt.variant)) + print (' if (', end='') + print_subtag_matches (lt.script, False) + print_subtag_matches (lt.region, False) + print_subtag_matches (lt.variant, False) + print (')') + print (' {') + write (' /* %s */' % bcp_47.get_name (lt)) + print () + if len (tags) == 1: + write (' tags[0] = %s; /* %s */' % (hb_tag (tags[0]), ot.names[tags[0]])) + print () + print (' *count = 1;') + else: + print (' hb_tag_t possible_tags[] = {') + for tag in tags: + write (' %s, /* %s */' % (hb_tag (tag), ot.names[tag])) + print () + print (' };') + print (' for (i = 0; i < %s && i < *count; i++)' % len (tags)) + print (' tags[i] = possible_tags[i];') + print (' *count = i;') + print (' return true;') + print (' }') + +print (' switch (lang_str[0])') +print (' {') +for initial, items in sorted (complex_tags.items ()): + if initial == 'und': + continue + print (" case '%s':" % initial) + for lt, tags in items: + print (' if (', end='') + if lt.grandfathered: + print ('0 == strcmp (&lang_str[1], "%s")' % lt.language[1:], end='') + else: + string_literal = lt.language[1:] + '-' + if lt.script: + string_literal += lt.script + lt.script = None + if lt.region: + string_literal += '-' + lt.region + lt.region = None + if string_literal[-1] == '-': + print ('0 == strncmp (&lang_str[1], "%s", %i)' % (string_literal, len (string_literal)), end='') + else: + print ('lang_matches (&lang_str[1], "%s")' % string_literal, end='') + print_subtag_matches (lt.script, True) + print_subtag_matches (lt.region, True) + print_subtag_matches (lt.variant, True) + print (')') + print (' {') + write (' /* %s */' % bcp_47.get_name (lt)) + print () + if len (tags) == 1: + write (' tags[0] = %s; /* %s */' % (hb_tag (tags[0]), ot.names[tags[0]])) + print () + print (' *count = 1;') + else: + print (' unsigned int i;') + print (' hb_tag_t possible_tags[] = {') + for tag in tags: + write ('\t%s, /* %s */' % (hb_tag (tag), ot.names[tag])) + print () + print (' };') + print (' for (i = 0; i < %s && i < *count; i++)' % len (tags)) + print ('\ttags[i] = possible_tags[i];') + print (' *count = i;') + print (' return true;') + print (' }') + print (' break;') + +print (' }') +print (' return false;') +print ('}') +print () +print ('/**') +print (' * hb_ot_ambiguous_tag_to_language') +print (' * @tag: A language tag.') +print (' *') +print (' * Converts @tag to a BCP 47 language tag if it is ambiguous (it corresponds to') +print (' * many language tags) and the best tag is not the alphabetically first, or if') +print (' * the best tag consists of multiple subtags.') +print (' *') +print (' * Return value: The #hb_language_t corresponding to the BCP 47 language tag,') +print (' * or #HB_LANGUAGE_INVALID if @tag is not ambiguous.') +print (' **/') +print ('static hb_language_t') +print ('hb_ot_ambiguous_tag_to_language (hb_tag_t tag)') +print ('{') +print (' switch (tag)') +print (' {') + +def verify_disambiguation_dict (): + """Verify and normalize ``disambiguation``. + + ``disambiguation`` is a map of ambiguous OpenType language system + tags to the particular BCP 47 tags they correspond to. This function + checks that all its keys really are ambiguous and that each key's + value is valid for that key. It checks that no ambiguous tag is + missing, except when it can figure out which BCP 47 tag is the best + by itself. + + It modifies ``disambiguation`` to remove keys whose values are the + same as those that the fallback would return anyway, and to add + ambiguous keys whose disambiguations it determined automatically. + + Raises: + AssertionError: Verification failed. + """ + global bcp_47 + global disambiguation + global ot + for ot_tag, bcp_47_tags in ot.to_bcp_47.items (): + primary_tags = list (t for t in bcp_47_tags if t not in bcp_47.grandfathered and ot.from_bcp_47.get (t)[0] == ot_tag) + if len (primary_tags) == 1: + expect (ot_tag not in disambiguation, 'unnecessary disambiguation for OT tag: %s' % ot_tag) + if '-' in primary_tags[0]: + disambiguation[ot_tag] = primary_tags[0] + elif len (primary_tags) == 0: + expect (ot_tag not in disambiguation, 'There is no possible valid disambiguation for %s' % ot_tag) + else: + macrolanguages = list (t for t in primary_tags if bcp_47.scopes.get (t) == ' [macrolanguage]') + if len (macrolanguages) != 1: + macrolanguages = list (t for t in primary_tags if bcp_47.scopes.get (t) == ' [family]') + if len (macrolanguages) != 1: + macrolanguages = list (t for t in primary_tags if 'retired code' not in bcp_47.scopes.get (t, '')) + if len (macrolanguages) != 1: + expect (ot_tag in disambiguation, 'ambiguous OT tag: %s %s' % (ot_tag, str (macrolanguages))) + expect (disambiguation[ot_tag] in bcp_47_tags, + '%s is not a valid disambiguation for %s' % (disambiguation[ot_tag], ot_tag)) + elif ot_tag not in disambiguation: + disambiguation[ot_tag] = macrolanguages[0] + if disambiguation[ot_tag] == sorted (primary_tags)[0] and '-' not in disambiguation[ot_tag]: + del disambiguation[ot_tag] + for ot_tag in disambiguation.keys (): + expect (ot_tag in ot.to_bcp_47, 'unknown OT tag: %s' % ot_tag) + +verify_disambiguation_dict () +for ot_tag, bcp_47_tag in sorted (disambiguation.items ()): + write (' case %s: /* %s */' % (hb_tag (ot_tag), ot.names[ot_tag])) + print () + write (' return hb_language_from_string (\"%s\", -1); /* %s */' % (bcp_47_tag, bcp_47.get_name (LanguageTag (bcp_47_tag)))) + print () + +print (' default:') +print (' return HB_LANGUAGE_INVALID;') +print (' }') +print ('}') + +print () +print ('#endif /* HB_OT_TAG_TABLE_HH */') +print () +print ('/* == End of generated table == */') + diff --git a/src/gen-use-table.py b/src/gen-use-table.py index c742ebaca..ebfae6fab 100755 --- a/src/gen-use-table.py +++ b/src/gen-use-table.py @@ -8,7 +8,7 @@ if len (sys.argv) != 5: print ("usage: ./gen-use-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt UnicodeData.txt Blocks.txt", file=sys.stderr) sys.exit (1) -BLACKLISTED_BLOCKS = ["Thai", "Lao", "Tibetan"] +BLACKLISTED_BLOCKS = ["Thai", "Lao"] files = [io.open (x, encoding='utf-8') for x in sys.argv[1:]] @@ -197,7 +197,10 @@ 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] + return UISC in [Virama, Invisible_Stacker] and not is_HALANT_OR_VOWEL_MODIFIER(U, UISC, UGC) +def is_HALANT_OR_VOWEL_MODIFIER(U, UISC, UGC): + # https://github.com/harfbuzz/harfbuzz/issues/1102 + return U == 0x11046 def is_HALANT_NUM(U, UISC, UGC): return UISC == Number_Joiner def is_ZWNJ(U, UISC, UGC): @@ -248,6 +251,7 @@ use_mapping = { 'SUB': is_CONS_SUB, 'CS': is_CONS_WITH_STACKER, 'H': is_HALANT, + 'HVM': is_HALANT_OR_VOWEL_MODIFIER, 'HN': is_HALANT_NUM, 'ZWNJ': is_ZWNJ, 'ZWJ': is_ZWJ, @@ -281,8 +285,8 @@ use_positions = { 'V': { 'Abv': [Top, Top_And_Bottom, Top_And_Bottom_And_Right, Top_And_Right], 'Blw': [Bottom, Overstruck, Bottom_And_Right], - 'Pst': [Right], - 'Pre': [Left, Top_And_Left, Top_And_Left_And_Right, Left_And_Right], + 'Pst': [Right, Top_And_Left, Top_And_Left_And_Right, Left_And_Right], + 'Pre': [Left], }, 'VM': { 'Abv': [Top], @@ -295,6 +299,7 @@ use_positions = { 'Blw': [Bottom], }, 'H': None, + 'HVM': None, 'B': None, 'FM': None, 'SUB': None, @@ -307,11 +312,28 @@ def map_to_use(data): # Resolve Indic_Syllabic_Category - # TODO: These don't have UISC assigned in Unicode 8.0, but - # have UIPC + # TODO: These don't have UISC assigned in Unicode 8.0, but have UIPC if U == 0x17DD: UISC = Vowel_Dependent if 0x1CE2 <= U <= 0x1CE8: UISC = Cantillation_Mark + # Tibetan: + # TODO: These don't have UISC assigned in Unicode 11.0, but have UIPC + if 0x0F18 <= U <= 0x0F19 or 0x0F3E <= U <= 0x0F3F: UISC = Vowel_Dependent + if 0x0F86 <= U <= 0x0F87: UISC = Tone_Mark + # Overrides to allow NFC order matching syllable + # https://github.com/harfbuzz/harfbuzz/issues/1012 + if UBlock == 'Tibetan' and is_VOWEL (U, UISC, UGC): + if UIPC == Top: + UIPC = Bottom + + # TODO: https://github.com/harfbuzz/harfbuzz/pull/982 + # also https://github.com/harfbuzz/harfbuzz/issues/1012 + if UBlock == 'Chakma' and is_VOWEL (U, UISC, UGC): + if UIPC == Top: + UIPC = Bottom + elif UIPC == Bottom: + UIPC = Top + # TODO: https://github.com/harfbuzz/harfbuzz/pull/627 if 0x1BF2 <= U <= 0x1BF3: UISC = Nukta; UIPC = Bottom @@ -359,13 +381,6 @@ def map_to_use(data): # https://github.com/roozbehp/unicode-data/issues/8 if U == 0x0A51: UIPC = Bottom - # TODO: https://github.com/harfbuzz/harfbuzz/pull/982 - if UBlock == 'Chakma' and is_VOWEL (U, UISC, UGC): - if UIPC == Top: - UIPC = Bottom - elif UIPC == Bottom: - UIPC = Top - assert (UIPC in [Not_Applicable, Visual_Order_Left] or USE in use_positions), "%s %s %s %s %s" % (hex(U), UIPC, USE, UISC, UGC) @@ -394,7 +409,7 @@ for h in headers: print (" * %s" % (l.strip())) print (" */") print () -print ('#include "hb-ot-shape-complex-use-private.hh"') +print ('#include "hb-ot-shape-complex-use.hh"') print () total = 0 diff --git a/src/harfbuzz-config.cmake.in b/src/harfbuzz-config.cmake.in index 87b15721a..304410d9b 100644 --- a/src/harfbuzz-config.cmake.in +++ b/src/harfbuzz-config.cmake.in @@ -12,7 +12,11 @@ set(_harfbuzz_libdir "@libdir@") string(REPLACE "${_harfbuzz_remove_string}/" "" _harfbuzz_libdir "${_harfbuzz_libdir}") set(_harfbuzz_libdir_iter "${_harfbuzz_libdir}") while (_harfbuzz_libdir_iter) + set(_harfbuzz_libdir_prev_iter "${_harfbuzz_libdir_iter}") get_filename_component(_harfbuzz_libdir_iter "${_harfbuzz_libdir_iter}" DIRECTORY) + if (_harfbuzz_libdir_prev_iter STREQUAL _harfbuzz_libdir_iter) + break() + endif () get_filename_component(_harfbuzz_prefix "${_harfbuzz_prefix}" DIRECTORY) endwhile () unset(_harfbuzz_libdir_iter) diff --git a/src/hb-aat-layout-ankr-table.hh b/src/hb-aat-layout-ankr-table.hh index 3b7912b9d..5f7656d2a 100644 --- a/src/hb-aat-layout-ankr-table.hh +++ b/src/hb-aat-layout-ankr-table.hh @@ -25,7 +25,7 @@ #ifndef HB_AAT_LAYOUT_ANKR_TABLE_HH #define HB_AAT_LAYOUT_ANKR_TABLE_HH -#include "hb-aat-layout-common-private.hh" +#include "hb-aat-layout-common.hh" /* * ankr -- Anchor Point @@ -45,32 +45,49 @@ struct Anchor return_trace (c->check_struct (this)); } + public: FWORD xCoordinate; FWORD yCoordinate; public: DEFINE_SIZE_STATIC (4); }; +typedef LArrayOf<Anchor> GlyphAnchors; + struct ankr { static const hb_tag_t tableTag = HB_AAT_TAG_ankr; + inline const Anchor &get_anchor (hb_codepoint_t glyph_id, + unsigned int i, + unsigned int num_glyphs, + const char *end) const + { + const Offset<HBUINT16, false> *offset = (this+lookupTable).get_value (glyph_id, num_glyphs); + if (!offset) + return Null(Anchor); + const GlyphAnchors &anchors = StructAtOffset<GlyphAnchors> (&(this+anchorData), *offset); + /* TODO Use sanitizer; to avoid overflows and more. */ + if (unlikely ((const char *) &anchors + anchors.get_size () > end)) + return Null(Anchor); + return anchors[i]; + } + inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (likely (c->check_struct (this) && version == 0 && - lookupTable.sanitize (c, this) && - anchors.sanitize (c, this))); + lookupTable.sanitize (c, this))); } protected: HBUINT16 version; /* Version number (set to zero) */ HBUINT16 flags; /* Flags (currently unused; set to zero) */ - LOffsetTo<Lookup<HBUINT16> > + LOffsetTo<Lookup<Offset<HBUINT16, false> >, false> lookupTable; /* Offset to the table's lookup table */ - LOffsetTo<LArrayOf<Anchor> > - anchors; /* Offset to the glyph data table */ + LOffsetTo<HBUINT8, false> + anchorData; /* Offset to the glyph data table */ public: DEFINE_SIZE_STATIC (12); diff --git a/src/hb-aat-layout-bsln-table.hh b/src/hb-aat-layout-bsln-table.hh index df2bf5b43..b86408626 100644 --- a/src/hb-aat-layout-bsln-table.hh +++ b/src/hb-aat-layout-bsln-table.hh @@ -25,7 +25,7 @@ #ifndef HB_AAT_LAYOUT_BSLN_TABLE_HH #define HB_AAT_LAYOUT_BSLN_TABLE_HH -#include "hb-aat-layout-common-private.hh" +#include "hb-aat-layout-common.hh" /* * bsln -- Baseline diff --git a/src/hb-aat-layout-common-private.hh b/src/hb-aat-layout-common.hh index d7f35052d..a99ccaf9f 100644 --- a/src/hb-aat-layout-common-private.hh +++ b/src/hb-aat-layout-common.hh @@ -24,10 +24,10 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_AAT_LAYOUT_COMMON_PRIVATE_HH -#define HB_AAT_LAYOUT_COMMON_PRIVATE_HH +#ifndef HB_AAT_LAYOUT_COMMON_HH +#define HB_AAT_LAYOUT_COMMON_HH -#include "hb-aat-layout-private.hh" +#include "hb-aat-layout.hh" namespace AAT { @@ -36,111 +36,6 @@ using namespace OT; /* - * Binary Searching Tables - */ - -struct BinSearchHeader -{ - - inline bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this)); - } - - HBUINT16 unitSize; /* Size of a lookup unit for this search in bytes. */ - HBUINT16 nUnits; /* Number of units of the preceding size to be searched. */ - HBUINT16 searchRange; /* The value of unitSize times the largest power of 2 - * that is less than or equal to the value of nUnits. */ - HBUINT16 entrySelector; /* The log base 2 of the largest power of 2 less than - * or equal to the value of nUnits. */ - HBUINT16 rangeShift; /* The value of unitSize times the difference of the - * value of nUnits minus the largest power of 2 less - * than or equal to the value of nUnits. */ - public: - DEFINE_SIZE_STATIC (10); -}; - -template <typename Type> -struct BinSearchArrayOf -{ - inline const Type& operator [] (unsigned int i) const - { - if (unlikely (i >= header.nUnits)) return Null(Type); - return StructAtOffset<Type> (bytesZ, i * header.unitSize); - } - inline Type& operator [] (unsigned int i) - { - return StructAtOffset<Type> (bytesZ, i * header.unitSize); - } - inline unsigned int get_size (void) const - { return header.static_size + header.nUnits * header.unitSize; } - - inline 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(), ie. they do not - * reference other structs via offsets. - */ - (void) (false && StructAtOffset<Type> (bytesZ, 0).sanitize (c)); - - return_trace (true); - } - inline bool sanitize (hb_sanitize_context_t *c, const void *base) const - { - TRACE_SANITIZE (this); - if (unlikely (!sanitize_shallow (c))) return_trace (false); - unsigned int count = header.nUnits; - for (unsigned int i = 0; i < count; i++) - if (unlikely (!(*this)[i].sanitize (c, base))) - return_trace (false); - return_trace (true); - } - - template <typename T> - inline const Type *bsearch (const T &key) const - { - unsigned int size = header.unitSize; - int min = 0, max = (int) header.nUnits - 1; - while (min <= max) - { - int mid = (min + max) / 2; - const Type *p = (const Type *) (((const char *) bytesZ) + (mid * size)); - int c = p->cmp (key); - if (c < 0) - max = mid - 1; - else if (c > 0) - min = mid + 1; - else - return p; - } - return nullptr; - } - - private: - inline bool sanitize_shallow (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (header.sanitize (c) && - Type::static_size >= header.unitSize && - c->check_array (bytesZ, header.unitSize, header.nUnits)); - } - - protected: - BinSearchHeader header; - HBUINT8 bytesZ[VAR]; - public: - DEFINE_SIZE_ARRAY (10, bytesZ); -}; - - -/* * Lookup Table */ @@ -213,7 +108,7 @@ struct LookupFormat2 protected: HBUINT16 format; /* Format identifier--format = 2 */ - BinSearchArrayOf<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). */ @@ -243,7 +138,7 @@ struct LookupSegmentArray GlyphID last; /* Last GlyphID in this segment */ GlyphID first; /* First GlyphID in this segment */ - OffsetTo<UnsizedArrayOf<T> > + OffsetTo<UnsizedArrayOf<T>, HBUINT16, false> valuesZ; /* A 16-bit offset from the start of * the table to the data. */ public: @@ -269,8 +164,8 @@ struct LookupFormat4 } protected: - HBUINT16 format; /* Format identifier--format = 2 */ - BinSearchArrayOf<LookupSegmentArray<T> > + HBUINT16 format; /* Format identifier--format = 4 */ + 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). */ @@ -292,7 +187,7 @@ struct LookupSingle GlyphID glyph; /* Last GlyphID */ T value; /* The lookup value (only one) */ public: - DEFINE_SIZE_STATIC (4 + T::static_size); + DEFINE_SIZE_STATIC (2 + T::static_size); }; template <typename T> @@ -315,7 +210,7 @@ struct LookupFormat6 protected: HBUINT16 format; /* Format identifier--format = 6 */ - BinSearchArrayOf<LookupSingle<T> > + VarSizedBinSearchArrayOf<LookupSingle<T> > entries; /* The actual entries, sorted by glyph index. */ public: DEFINE_SIZE_ARRAY (8, entries); @@ -329,7 +224,8 @@ struct LookupFormat8 private: inline const T* get_value (hb_codepoint_t glyph_id) const { - return firstGlyph <= glyph_id && glyph_id - firstGlyph < glyphCount ? &valueArrayZ[glyph_id - firstGlyph] : nullptr; + return firstGlyph <= glyph_id && glyph_id - firstGlyph < glyphCount ? + &valueArrayZ[glyph_id - firstGlyph] : nullptr; } inline bool sanitize (hb_sanitize_context_t *c) const @@ -339,7 +235,7 @@ struct LookupFormat8 } protected: - HBUINT16 format; /* Format identifier--format = 6 */ + HBUINT16 format; /* Format identifier--format = 8 */ GlyphID firstGlyph; /* First glyph index included in the trimmed array. */ HBUINT16 glyphCount; /* Total number of glyphs (equivalent to the last * glyph minus the value of firstGlyph plus 1). */ @@ -351,6 +247,48 @@ struct LookupFormat8 }; template <typename T> +struct LookupFormat10 +{ + friend struct Lookup<T>; + + private: + inline const typename T::type get_value_or_null (hb_codepoint_t glyph_id) const + { + if (!(firstGlyph <= glyph_id && glyph_id - firstGlyph < glyphCount)) + return Null(T); + + const HBUINT8 *p = &valueArrayZ[(glyph_id - firstGlyph) * valueSize]; + + unsigned int v = 0; + unsigned int count = valueSize; + for (unsigned int i = 0; i < count; i++) + v = (v << 8) | *p++; + + return v; + } + + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && + valueSize <= 4 && + valueArrayZ.sanitize (c, glyphCount * valueSize)); + } + + protected: + HBUINT16 format; /* Format identifier--format = 8 */ + HBUINT16 valueSize; /* Byte size of each value. */ + GlyphID firstGlyph; /* First glyph index included in the trimmed array. */ + HBUINT16 glyphCount; /* Total number of glyphs (equivalent to the last + * glyph minus the value of firstGlyph plus 1). */ + UnsizedArrayOf<HBUINT8> + valueArrayZ; /* The lookup values (indexed by the glyph index + * minus the value of firstGlyph). */ + public: + DEFINE_SIZE_ARRAY (8, valueArrayZ); +}; + +template <typename T> struct Lookup { inline const T* get_value (hb_codepoint_t glyph_id, unsigned int num_glyphs) const @@ -365,6 +303,17 @@ struct Lookup } } + inline const typename T::type get_value_or_null (hb_codepoint_t glyph_id, unsigned int num_glyphs) const + { + switch (u.format) { + /* Format 10 cannot return a pointer. */ + case 10: return u.format10.get_value_or_null (glyph_id); + default: + const T *v = get_value (glyph_id, num_glyphs); + return v ? *v : Null(T); + } + } + inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -375,6 +324,7 @@ struct Lookup case 4: return_trace (u.format4.sanitize (c)); case 6: return_trace (u.format6.sanitize (c)); case 8: return_trace (u.format8.sanitize (c)); + case 10: return_trace (u.format10.sanitize (c)); default:return_trace (true); } } @@ -387,10 +337,30 @@ struct Lookup LookupFormat4<T> format4; LookupFormat6<T> format6; LookupFormat8<T> format8; + LookupFormat10<T> format10; } u; public: DEFINE_SIZE_UNION (2, format); }; +/* Lookup 0 has unbounded size (dependant on num_glyphs). So we need to defined + * special NULL objects for Lookup<> objects, but since it's template our macros + * don't work. So we have to hand-code them here. UGLY. */ +} /* Close namespace. */ +/* Ugly hand-coded null objects for template Lookup<> :(. */ +extern HB_INTERNAL const unsigned char _hb_Null_AAT_Lookup[2]; +template <> +/*static*/ inline const AAT::Lookup<OT::HBUINT16>& Null<AAT::Lookup<OT::HBUINT16> > (void) { + return *reinterpret_cast<const AAT::Lookup<OT::HBUINT16> *> (_hb_Null_AAT_Lookup); +} +template <> +/*static*/ inline const AAT::Lookup<OT::HBUINT32>& Null<AAT::Lookup<OT::HBUINT32> > (void) { + return *reinterpret_cast<const AAT::Lookup<OT::HBUINT32> *> (_hb_Null_AAT_Lookup); +} +template <> +/*static*/ inline const AAT::Lookup<OT::Offset<OT::HBUINT16, false> >& Null<AAT::Lookup<OT::Offset<OT::HBUINT16, false> > > (void) { + return *reinterpret_cast<const AAT::Lookup<OT::Offset<OT::HBUINT16, false> > *> (_hb_Null_AAT_Lookup); +} +namespace AAT { /* @@ -439,10 +409,23 @@ struct Entry<void> template <typename Extra> struct StateTable { + enum State + { + STATE_START_OF_TEXT = 0, + STATE_START_OF_LINE = 1, + }; + enum Class + { + CLASS_END_OF_TEXT = 0, + CLASS_OUT_OF_BOUNDS = 1, + CLASS_DELETED_GLYPH = 2, + CLASS_END_OF_LINE = 3, + }; + inline unsigned int get_class (hb_codepoint_t glyph_id, unsigned int num_glyphs) const { const HBUINT16 *v = (this+classTable).get_value (glyph_id, num_glyphs); - return v ? *v : 1; + return v ? (unsigned) *v : (unsigned) CLASS_OUT_OF_BOUNDS; } inline const Entry<Extra> *get_entries () const @@ -472,6 +455,8 @@ struct StateTable const HBUINT16 *states = (this+stateArrayTable).arrayZ; const Entry<Extra> *entries = (this+entryTable).arrayZ; + unsigned int num_classes = nClasses; + unsigned int num_states = 1; unsigned int num_entries = 0; @@ -479,20 +464,25 @@ struct StateTable unsigned int entry = 0; while (state < num_states) { + if (unlikely (hb_unsigned_mul_overflows (num_classes, states[0].static_size))) + return_trace (false); + if (unlikely (!c->check_array (states, - states[0].static_size * nClasses, - num_states))) + num_states, + num_classes * states[0].static_size))) + return_trace (false); + if ((c->max_ops -= num_states - state) < 0) return_trace (false); { /* Sweep new states. */ - const HBUINT16 *stop = &states[num_states * nClasses]; - for (const HBUINT16 *p = &states[state * nClasses]; p < stop; p++) + const HBUINT16 *stop = &states[num_states * num_classes]; + for (const HBUINT16 *p = &states[state * num_classes]; p < stop; p++) num_entries = MAX<unsigned int> (num_entries, *p + 1); state = num_states; } - if (unlikely (!c->check_array (entries, - entries[0].static_size, - num_entries))) + if (unlikely (!c->check_array (entries, num_entries))) + return_trace (false); + if ((c->max_ops -= num_entries - entry) < 0) return_trace (false); { /* Sweep new entries. */ const Entry<Extra> *stop = &entries[num_entries]; @@ -511,11 +501,11 @@ struct StateTable protected: HBUINT32 nClasses; /* Number of classes, which is the number of indices * in a single line in the state array. */ - LOffsetTo<Lookup<HBUINT16> > + LOffsetTo<Lookup<HBUINT16>, false> classTable; /* Offset to the class table. */ - LOffsetTo<UnsizedArrayOf<HBUINT16> > + LOffsetTo<UnsizedArrayOf<HBUINT16>, false> stateArrayTable;/* Offset to the state array. */ - LOffsetTo<UnsizedArrayOf<Entry<Extra> > > + LOffsetTo<UnsizedArrayOf<Entry<Extra> >, false> entryTable; /* Offset to the entry array. */ public: @@ -535,31 +525,32 @@ struct StateTableDriver template <typename context_t> inline void drive (context_t *c) { - hb_glyph_info_t *info = buffer->info; - if (!c->in_place) buffer->clear_output (); - unsigned int state = 0; + unsigned int state = StateTable<EntryData>::STATE_START_OF_TEXT; bool last_was_dont_advance = false; for (buffer->idx = 0;;) { unsigned int klass = buffer->idx < buffer->len ? - machine.get_class (info[buffer->idx].codepoint, num_glyphs) : - 0 /* End of text */; + machine.get_class (buffer->info[buffer->idx].codepoint, num_glyphs) : + (unsigned) StateTable<EntryData>::CLASS_END_OF_TEXT; const Entry<EntryData> *entry = machine.get_entryZ (state, klass); if (unlikely (!entry)) break; /* Unsafe-to-break before this if not in state 0, as things might - * go differently if we start from state 0 here. */ - if (state && buffer->idx) + * go differently if we start from state 0 here. + * + * Ugh. The indexing here is ugly... */ + if (state && buffer->backtrack_len () && buffer->idx < buffer->len) { /* If there's no action and we're just epsilon-transitioning to state 0, * safe to break. */ if (c->is_actionable (this, entry) || - !(entry->newState == 0 && entry->flags == context_t::DontAdvance)) - buffer->unsafe_to_break (buffer->idx - 1, buffer->idx + 1); + !(entry->newState == StateTable<EntryData>::STATE_START_OF_TEXT && + entry->flags == context_t::DontAdvance)) + buffer->unsafe_to_break_from_outbuffer (buffer->backtrack_len () - 1, buffer->idx + 1); } /* Unsafe-to-break if end-of-text would kick in here. */ @@ -573,6 +564,8 @@ struct StateTableDriver if (unlikely (!c->transition (this, entry))) break; + if (unlikely (!buffer->successful)) return; + last_was_dont_advance = (entry->flags & context_t::DontAdvance) && buffer->max_ops-- > 0; state = entry->newState; @@ -586,9 +579,10 @@ struct StateTableDriver if (!c->in_place) { - for (; buffer->idx < buffer->len;) - buffer->next_glyph (); - buffer->swap_buffers (); + for (; buffer->successful && buffer->idx < buffer->len;) + buffer->next_glyph (); + if (likely (buffer->successful)) + buffer->swap_buffers (); } } @@ -599,6 +593,7 @@ struct StateTableDriver }; +struct ankr; struct hb_aat_apply_context_t : hb_dispatch_context_t<hb_aat_apply_context_t, bool, HB_DEBUG_APPLY> @@ -609,24 +604,33 @@ struct hb_aat_apply_context_t : static return_t default_return_value (void) { return false; } bool stop_sublookup_iteration (return_t r) const { return r; } + hb_ot_shape_plan_t *plan; hb_font_t *font; hb_face_t *face; hb_buffer_t *buffer; hb_sanitize_context_t sanitizer; + const ankr &ankr_table; + const char *ankr_end; /* Unused. For debug tracing only. */ unsigned int lookup_index; unsigned int debug_depth; - inline hb_aat_apply_context_t (hb_font_t *font_, + inline hb_aat_apply_context_t (hb_ot_shape_plan_t *plan_, + hb_font_t *font_, hb_buffer_t *buffer_, - hb_blob_t *table) : - font (font_), face (font->face), buffer (buffer_), - sanitizer (), lookup_index (0), debug_depth (0) - { - sanitizer.init (table); + hb_blob_t *blob = const_cast<hb_blob_t *> (&Null(hb_blob_t)), + const ankr &ankr_table_ = Null(ankr), + const char *ankr_end_ = nullptr) : + plan (plan_), font (font_), face (font->face), buffer (buffer_), + sanitizer (), + ankr_table (ankr_table_), ankr_end (ankr_end_), + 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); } inline void set_lookup_index (unsigned int i) { lookup_index = i; } @@ -641,4 +645,4 @@ struct hb_aat_apply_context_t : } /* namespace AAT */ -#endif /* HB_AAT_LAYOUT_COMMON_PRIVATE_HH */ +#endif /* HB_AAT_LAYOUT_COMMON_HH */ diff --git a/src/hb-aat-layout-feat-table.hh b/src/hb-aat-layout-feat-table.hh index 3e070d795..b670caab8 100644 --- a/src/hb-aat-layout-feat-table.hh +++ b/src/hb-aat-layout-feat-table.hh @@ -25,7 +25,7 @@ #ifndef HB_AAT_LAYOUT_FEAT_TABLE_HH #define HB_AAT_LAYOUT_FEAT_TABLE_HH -#include "hb-aat-layout-common-private.hh" +#include "hb-aat-layout-common.hh" /* * feat -- Feature Name @@ -78,7 +78,7 @@ struct FeatureName protected: HBUINT16 feature; /* Feature type. */ HBUINT16 nSettings; /* The number of records in the setting name array. */ - LOffsetTo<UnsizedArrayOf<SettingName> > + LOffsetTo<UnsizedArrayOf<SettingName>, false> settingTable; /* Offset in bytes from the beginning of this table to * this feature's setting name array. The actual type of * record this offset refers to will depend on the diff --git a/src/hb-aat-layout-kerx-table.hh b/src/hb-aat-layout-kerx-table.hh index cc03d6278..e8eb43b87 100644 --- a/src/hb-aat-layout-kerx-table.hh +++ b/src/hb-aat-layout-kerx-table.hh @@ -28,9 +28,10 @@ #ifndef HB_AAT_LAYOUT_KERX_TABLE_HH #define HB_AAT_LAYOUT_KERX_TABLE_HH -#include "hb-open-type-private.hh" -#include "hb-aat-layout-common-private.hh" -#include "hb-aat-layout-ankr-table.hh" +#include "hb-open-type.hh" +#include "hb-aat-layout-common.hh" +#include "hb-ot-layout-gpos-table.hh" +#include "hb-ot-kern-table.hh" /* * kerx -- Extended Kerning @@ -44,7 +45,22 @@ namespace AAT { using namespace OT; -struct KerxFormat0Records +static inline int +kerxTupleKern (int value, + unsigned int tupleCount, + const void *base, + hb_aat_apply_context_t *c) +{ + if (likely (!tupleCount)) return value; + + unsigned int offset = value; + const FWORD *pv = &StructAtOffset<FWORD> (base, offset); + if (unlikely (!pv->sanitize (&c->sanitizer))) return 0; + return *pv; +} + + +struct KerxSubTableHeader { inline bool sanitize (hb_sanitize_context_t *c) const { @@ -52,217 +68,573 @@ struct KerxFormat0Records return_trace (likely (c->check_struct (this))); } - protected: - GlyphID left; - GlyphID right; - FWORD value; public: - DEFINE_SIZE_STATIC (6); + HBUINT32 length; + HBUINT32 coverage; + HBUINT32 tupleCount; + public: + DEFINE_SIZE_STATIC (12); }; struct KerxSubTableFormat0 { - // TODO(ebraminio) Enable when we got suitable BinSearchArrayOf - // inline int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const - // { - // hb_glyph_pair_t pair = {left, right}; - // int i = pairs.bsearch (pair); - // if (i == -1) - // return 0; - // return pairs[i].get_kerning (); - // } + inline int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const + { + if (header.tupleCount) return 0; /* TODO kerxTupleKern */ + hb_glyph_pair_t pair = {left, right}; + int i = pairs.bsearch (pair); + return i == -1 ? 0 : pairs[i].get_kerning (); + } + + inline bool apply (hb_aat_apply_context_t *c) const + { + TRACE_APPLY (this); + + if (!c->plan->requested_kerning) + return false; + + hb_kern_machine_t<KerxSubTableFormat0> machine (*this); + + machine.kern (c->font, c->buffer, c->plan->kern_mask); + + return_trace (true); + } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (likely (c->check_struct (this) && - recordsZ.sanitize (c, nPairs))); + pairs.sanitize (c))); } protected: - // TODO(ebraminio): A custom version of "BinSearchArrayOf<KerxPair> pairs;" is - // needed here to use HBUINT32 instead - HBUINT32 nPairs; /* The number of kerning pairs in this subtable */ - HBUINT32 searchRange; /* The largest power of two less than or equal to the value of nPairs, - * multiplied by the size in bytes of an entry in the subtable. */ - HBUINT32 entrySelector; /* This is calculated as log2 of the largest power of two less - * than or equal to the value of nPairs. */ - HBUINT32 rangeShift; /* The value of nPairs minus the largest power of two less than or equal to nPairs. */ - UnsizedArrayOf<KerxFormat0Records> - recordsZ; /* VAR=nPairs */ + KerxSubTableHeader header; + BinSearchArrayOf<KernPair, HBUINT32> + pairs; /* Sorted kern records. */ public: - DEFINE_SIZE_ARRAY (16, recordsZ); + DEFINE_SIZE_ARRAY (28, pairs); }; struct KerxSubTableFormat1 { - inline bool sanitize (hb_sanitize_context_t *c) const + struct EntryData { - TRACE_SANITIZE (this); - return_trace (likely (c->check_struct (this) && - stateHeader.sanitize (c))); - } + HBUINT16 kernActionIndex;/* Index into the kerning value array. If + * this index is 0xFFFF, then no kerning + * is to be performed. */ + public: + DEFINE_SIZE_STATIC (2); + }; + + struct driver_context_t + { + static const bool in_place = true; + enum Flags + { + Push = 0x8000, /* If set, push this glyph on the kerning stack. */ + DontAdvance = 0x4000, /* If set, don't advance to the next glyph + * before going to the new state. */ + Reset = 0x2000, /* If set, reset the kerning data (clear the stack) */ + Reserved = 0x1FFF, /* Not used; set to 0. */ + }; + + inline driver_context_t (const KerxSubTableFormat1 *table, + hb_aat_apply_context_t *c_) : + c (c_), + /* Apparently the offset kernAction is from the beginning of the state-machine, + * similar to offsets in morx table, NOT from beginning of this table, like + * other subtables in kerx. Discovered via testing. */ + kernAction (&table->machine + table->kernAction), + depth (0) {} + + inline bool is_actionable (StateTableDriver<EntryData> *driver, + const Entry<EntryData> *entry) + { + return entry->data.kernActionIndex != 0xFFFF; + } + inline bool transition (StateTableDriver<EntryData> *driver, + const Entry<EntryData> *entry) + { + hb_buffer_t *buffer = driver->buffer; + unsigned int flags = entry->flags; + + if (flags & Reset) + { + depth = 0; + } + + if (flags & Push) + { + if (likely (depth < ARRAY_LENGTH (stack))) + stack[depth++] = buffer->idx; + else + depth = 0; /* Probably not what CoreText does, but better? */ + } + + if (entry->data.kernActionIndex != 0xFFFF) + { + const FWORD *actions = &kernAction[entry->data.kernActionIndex]; + if (!c->sanitizer.check_array (actions, depth)) + { + depth = 0; + return false; + } + + hb_mask_t kern_mask = c->plan->kern_mask; + for (unsigned int i = 0; i < depth; i++) + { + /* Apparently, when spec says "Each pops one glyph from the kerning stack + * and applies the kerning value to it.", it doesn't mean it in that order. + * The deepest item in the stack corresponds to the first item in the action + * list. Discovered by testing. */ + unsigned int idx = stack[i]; + int v = *actions++; + if (idx < buffer->len && buffer->info[idx].mask & kern_mask) + { + /* XXX Non-forward direction... */ + if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction)) + buffer->pos[idx].x_advance += c->font->em_scale_x (v); + else + buffer->pos[idx].y_advance += c->font->em_scale_y (v); + } + } + depth = 0; + } + + return true; + } - protected: - StateTable<HBUINT16> stateHeader; - LOffsetTo<ArrayOf<HBUINT16> > valueTable; - public: - DEFINE_SIZE_STATIC (20); -}; + private: + hb_aat_apply_context_t *c; + const UnsizedArrayOf<FWORD> &kernAction; + unsigned int stack[8]; + unsigned int depth; + }; -// TODO(ebraminio): Maybe this can be replaced with Lookup<HBUINT16>? -struct KerxClassTable -{ - inline unsigned int get_class (hb_codepoint_t g) const { return classes[g - firstGlyph]; } + inline bool apply (hb_aat_apply_context_t *c) const + { + TRACE_APPLY (this); + + if (!c->plan->requested_kerning) + return false; + + if (header.tupleCount) + return_trace (false); /* TODO kerxTupleKern */ + + driver_context_t dc (this, c); + + StateTableDriver<EntryData> driver (machine, c->buffer, c->font->face); + driver.drive (&dc); + + return_trace (true); + } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return_trace (likely (firstGlyph.sanitize (c) && - classes.sanitize (c))); + /* The rest of array sanitizations are done at run-time. */ + return_trace (likely (c->check_struct (this) && + machine.sanitize (c))); } protected: - HBUINT16 firstGlyph; /* First glyph in class range. */ - ArrayOf<HBUINT16> classes; /* Glyph classes. */ + KerxSubTableHeader header; + StateTable<EntryData> machine; + LOffsetTo<UnsizedArrayOf<FWORD>, false> kernAction; public: - DEFINE_SIZE_ARRAY (4, classes); + DEFINE_SIZE_STATIC (32); }; struct KerxSubTableFormat2 { - inline int get_kerning (hb_codepoint_t left, hb_codepoint_t right, const char *end) const + inline int get_kerning (hb_codepoint_t left, hb_codepoint_t right, + hb_aat_apply_context_t *c) const { - unsigned int l = (this+leftClassTable).get_class (left); - unsigned int r = (this+leftClassTable).get_class (left); - unsigned int offset = l * rowWidth + r * sizeof (FWORD); - const FWORD *arr = &(this+array); - if (unlikely ((const void *) arr < (const void *) this || (const void *) arr >= (const void *) end)) - return 0; - const FWORD *v = &StructAtOffset<FWORD> (arr, offset); - if (unlikely ((const void *) v < (const void *) arr || (const void *) (v + 1) > (const void *) end)) - return 0; - return *v; + unsigned int num_glyphs = c->sanitizer.get_num_glyphs (); + unsigned int l = (this+leftClassTable).get_value_or_null (left, num_glyphs); + unsigned int r = (this+rightClassTable).get_value_or_null (right, num_glyphs); + unsigned int offset = l + r; + const FWORD *v = &StructAtOffset<FWORD> (&(this+array), offset); + if (unlikely (!v->sanitize (&c->sanitizer))) return 0; + return kerxTupleKern (*v, header.tupleCount, this, c); + } + + inline bool apply (hb_aat_apply_context_t *c) const + { + TRACE_APPLY (this); + + if (!c->plan->requested_kerning) + return false; + + accelerator_t accel (*this, c); + hb_kern_machine_t<accelerator_t> machine (accel); + machine.kern (c->font, c->buffer, c->plan->kern_mask); + + return_trace (true); } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (likely (c->check_struct (this) && - rowWidth.sanitize (c) && leftClassTable.sanitize (c, this) && rightClassTable.sanitize (c, this) && - array.sanitize (c, this))); + c->check_range (this, array))); } + struct accelerator_t + { + const KerxSubTableFormat2 &table; + hb_aat_apply_context_t *c; + + inline accelerator_t (const KerxSubTableFormat2 &table_, + hb_aat_apply_context_t *c_) : + table (table_), c (c_) {} + + inline int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const + { return table.get_kerning (left, right, c); } + }; + protected: - HBUINT32 rowWidth; /* The width, in bytes, of a row in the table. */ - LOffsetTo<KerxClassTable> - leftClassTable; /* Offset from beginning of this subtable to - * left-hand class table. */ - LOffsetTo<KerxClassTable> - rightClassTable;/* Offset from beginning of this subtable to - * right-hand class table. */ - LOffsetTo<FWORD> - array; /* Offset from beginning of this subtable to - * the start of the kerning array. */ + KerxSubTableHeader header; + HBUINT32 rowWidth; /* The width, in bytes, of a row in the table. */ + LOffsetTo<Lookup<HBUINT16>, false> + leftClassTable; /* Offset from beginning of this subtable to + * left-hand class table. */ + LOffsetTo<Lookup<HBUINT16>, false> + rightClassTable;/* Offset from beginning of this subtable to + * right-hand class table. */ + LOffsetTo<UnsizedArrayOf<FWORD>, false> + array; /* Offset from beginning of this subtable to + * the start of the kerning array. */ public: - DEFINE_SIZE_STATIC (16); + DEFINE_SIZE_STATIC (28); }; struct KerxSubTableFormat4 { + struct EntryData + { + HBUINT16 ankrActionIndex;/* Either 0xFFFF (for no action) or the index of + * the action to perform. */ + public: + DEFINE_SIZE_STATIC (2); + }; + + struct driver_context_t + { + static const bool in_place = true; + enum Flags + { + Mark = 0x8000, /* If set, remember this glyph as the marked glyph. */ + DontAdvance = 0x4000, /* If set, don't advance to the next glyph before + * going to the new state. */ + Reserved = 0x3FFF, /* Not used; set to 0. */ + }; + + enum SubTableFlags + { + ActionType = 0xC0000000, /* A two-bit field containing the action type. */ + Unused = 0x3F000000, /* Unused - must be zero. */ + Offset = 0x00FFFFFF, /* Masks the offset in bytes from the beginning + * of the subtable to the beginning of the control + * point table. */ + }; + + inline driver_context_t (const KerxSubTableFormat4 *table, + hb_aat_apply_context_t *c_) : + c (c_), + action_type ((table->flags & ActionType) >> 30), + ankrData ((HBUINT16 *) ((const char *) &table->machine + (table->flags & Offset))), + mark_set (false), + mark (0) {} + + inline bool is_actionable (StateTableDriver<EntryData> *driver, + const Entry<EntryData> *entry) + { + return entry->data.ankrActionIndex != 0xFFFF; + } + inline bool transition (StateTableDriver<EntryData> *driver, + const Entry<EntryData> *entry) + { + hb_buffer_t *buffer = driver->buffer; + unsigned int flags = entry->flags; + + if (mark_set && entry->data.ankrActionIndex != 0xFFFF && buffer->idx < buffer->len) + { + hb_glyph_position_t &o = buffer->cur_pos(); + switch (action_type) + { + case 0: /* Control Point Actions.*/ + { + /* indexed into glyph outline. */ + const HBUINT16 *data = &ankrData[entry->data.ankrActionIndex]; + if (!c->sanitizer.check_array (data, 2)) + return false; + HB_UNUSED unsigned int markControlPoint = *data++; + HB_UNUSED unsigned int currControlPoint = *data++; + hb_position_t markX = 0; + hb_position_t markY = 0; + hb_position_t currX = 0; + hb_position_t currY = 0; + if (!c->font->get_glyph_contour_point_for_origin (c->buffer->info[mark].codepoint, + markControlPoint, + HB_DIRECTION_LTR /*XXX*/, + &markX, &markY) || + !c->font->get_glyph_contour_point_for_origin (c->buffer->cur ().codepoint, + currControlPoint, + HB_DIRECTION_LTR /*XXX*/, + &currX, &currY)) + return true; /* True, such that the machine continues. */ + + o.x_offset = markX - currX; + o.y_offset = markY - currY; + } + break; + + case 1: /* Anchor Point Actions. */ + { + /* Indexed into 'ankr' table. */ + const HBUINT16 *data = &ankrData[entry->data.ankrActionIndex]; + if (!c->sanitizer.check_array (data, 2)) + return false; + unsigned int markAnchorPoint = *data++; + unsigned int currAnchorPoint = *data++; + const Anchor markAnchor = c->ankr_table.get_anchor (c->buffer->info[mark].codepoint, + markAnchorPoint, + c->sanitizer.get_num_glyphs (), + c->ankr_end); + const Anchor currAnchor = c->ankr_table.get_anchor (c->buffer->cur ().codepoint, + currAnchorPoint, + c->sanitizer.get_num_glyphs (), + c->ankr_end); + + o.x_offset = c->font->em_scale_x (markAnchor.xCoordinate) - c->font->em_scale_x (currAnchor.xCoordinate); + o.y_offset = c->font->em_scale_y (markAnchor.yCoordinate) - c->font->em_scale_y (currAnchor.yCoordinate); + } + break; + + case 2: /* Control Point Coordinate Actions. */ + { + const FWORD *data = (const FWORD *) &ankrData[entry->data.ankrActionIndex]; + if (!c->sanitizer.check_array (data, 4)) + return false; + int markX = *data++; + int markY = *data++; + int currX = *data++; + int currY = *data++; + + o.x_offset = c->font->em_scale_x (markX) - c->font->em_scale_x (currX); + o.y_offset = c->font->em_scale_y (markY) - c->font->em_scale_y (currY); + } + break; + } + o.attach_type() = ATTACH_TYPE_MARK; + o.attach_chain() = (int) mark - (int) buffer->idx; + buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT; + } + + if (flags & Mark) + { + mark_set = true; + mark = buffer->idx; + } + + return true; + } + + private: + hb_aat_apply_context_t *c; + unsigned int action_type; + const HBUINT16 *ankrData; + bool mark_set; + unsigned int mark; + }; + + inline bool apply (hb_aat_apply_context_t *c) const + { + TRACE_APPLY (this); + + driver_context_t dc (this, c); + + StateTableDriver<EntryData> driver (machine, c->buffer, c->font->face); + driver.drive (&dc); + + return_trace (true); + } + inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); + /* The rest of array sanitizations are done at run-time. */ return_trace (likely (c->check_struct (this) && - rowWidth.sanitize (c) && - leftClassTable.sanitize (c, this) && - rightClassTable.sanitize (c, this) && - array.sanitize (c, this))); + machine.sanitize (c))); } protected: - HBUINT32 rowWidth; /* The width, in bytes, of a row in the table. */ - LOffsetTo<KerxClassTable> - leftClassTable; /* Offset from beginning of this subtable to - * left-hand class table. */ - LOffsetTo<KerxClassTable> - rightClassTable;/* Offset from beginning of this subtable to - * right-hand class table. */ - LOffsetTo<FWORD> - array; /* Offset from beginning of this subtable to - * the start of the kerning array. */ + KerxSubTableHeader header; + StateTable<EntryData> machine; + HBUINT32 flags; public: - DEFINE_SIZE_STATIC (16); + DEFINE_SIZE_STATIC (32); }; struct KerxSubTableFormat6 { + enum Flags + { + ValuesAreLong = 0x00000001, + }; + + inline bool is_long (void) const { return flags & ValuesAreLong; } + + inline int get_kerning (hb_codepoint_t left, hb_codepoint_t right, + hb_aat_apply_context_t *c) const + { + unsigned int num_glyphs = c->sanitizer.get_num_glyphs (); + if (is_long ()) + { + const U::Long &t = u.l; + unsigned int l = (this+t.rowIndexTable).get_value_or_null (left, num_glyphs); + unsigned int r = (this+t.columnIndexTable).get_value_or_null (right, num_glyphs); + unsigned int offset = l + r; + if (unlikely (offset < l)) return 0; /* Addition overflow. */ + if (unlikely (hb_unsigned_mul_overflows (offset, sizeof (FWORD32)))) return 0; + const FWORD32 *v = &StructAtOffset<FWORD32> (&(this+t.array), offset * sizeof (FWORD32)); + if (unlikely (!v->sanitize (&c->sanitizer))) return 0; + return kerxTupleKern (*v, header.tupleCount, &(this+vector), c); + } + else + { + const U::Short &t = u.s; + unsigned int l = (this+t.rowIndexTable).get_value_or_null (left, num_glyphs); + unsigned int r = (this+t.columnIndexTable).get_value_or_null (right, num_glyphs); + unsigned int offset = l + r; + const FWORD *v = &StructAtOffset<FWORD> (&(this+t.array), offset * sizeof (FWORD)); + if (unlikely (!v->sanitize (&c->sanitizer))) return 0; + return kerxTupleKern (*v, header.tupleCount, &(this+vector), c); + } + } + + inline bool apply (hb_aat_apply_context_t *c) const + { + TRACE_APPLY (this); + + if (!c->plan->requested_kerning) + return false; + + accelerator_t accel (*this, c); + hb_kern_machine_t<accelerator_t> machine (accel); + machine.kern (c->font, c->buffer, c->plan->kern_mask); + + return_trace (true); + } + inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (likely (c->check_struct (this) && - rowIndexTable.sanitize (c, this) && - columnIndexTable.sanitize (c, this) && - kerningArray.sanitize (c, this) && - kerningVector.sanitize (c, this))); + (is_long () ? + ( + u.l.rowIndexTable.sanitize (c, this) && + u.l.columnIndexTable.sanitize (c, this) && + c->check_range (this, u.l.array) + ) : ( + u.s.rowIndexTable.sanitize (c, this) && + u.s.columnIndexTable.sanitize (c, this) && + c->check_range (this, u.s.array) + )) && + (header.tupleCount == 0 || + c->check_range (this, vector)))); } + struct accelerator_t + { + const KerxSubTableFormat6 &table; + hb_aat_apply_context_t *c; + + inline accelerator_t (const KerxSubTableFormat6 &table_, + hb_aat_apply_context_t *c_) : + table (table_), c (c_) {} + + inline int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const + { return table.get_kerning (left, right, c); } + }; + protected: - HBUINT32 flags; - HBUINT16 rowCount; - HBUINT16 columnCount; - LOffsetTo<Lookup<HBUINT16> > rowIndexTable; - LOffsetTo<Lookup<HBUINT16> > columnIndexTable; - LOffsetTo<Lookup<HBUINT16> > kerningArray; - LOffsetTo<Lookup<HBUINT16> > kerningVector; + KerxSubTableHeader header; + HBUINT32 flags; + HBUINT16 rowCount; + HBUINT16 columnCount; + union U + { + struct Long + { + LOffsetTo<Lookup<HBUINT32>, false> rowIndexTable; + LOffsetTo<Lookup<HBUINT32>, false> columnIndexTable; + LOffsetTo<UnsizedArrayOf<FWORD32>, false> array; + } l; + struct Short + { + LOffsetTo<Lookup<HBUINT16>, false> rowIndexTable; + LOffsetTo<Lookup<HBUINT16>, false> columnIndexTable; + LOffsetTo<UnsizedArrayOf<FWORD>, false> array; + } s; + } u; + LOffsetTo<UnsizedArrayOf<FWORD>, false> vector; public: - DEFINE_SIZE_STATIC (24); -}; - -enum coverage_flags_t -{ - COVERAGE_VERTICAL_FLAG = 0x80u, - COVERAGE_CROSSSTREAM_FLAG = 0x40u, - COVERAGE_VARIATION_FLAG = 0x20u, - COVERAGE_PROCESS_DIRECTION = 0x10u, + DEFINE_SIZE_STATIC (36); }; struct KerxTable { - inline bool apply (hb_aat_apply_context_t *c, const AAT::ankr *ankr) const + friend struct kerx; + + inline unsigned int get_size (void) const { return u.header.length; } + inline unsigned int get_type (void) const { return u.header.coverage & SubtableType; } + + enum Coverage { - TRACE_APPLY (this); - /* TODO */ - return_trace (false); + Vertical = 0x80000000, /* Set if table has vertical kerning values. */ + CrossStream = 0x40000000, /* Set if table has cross-stream kerning values. */ + Variation = 0x20000000, /* Set if table has variation kerning values. */ + Backwards = 0x10000000, /* If clear, process the glyphs forwards, that + * is, from first to last in the glyph stream. + * If we, process them from last to first. + * This flag only applies to state-table based + * 'kerx' subtables (types 1 and 4). */ + Reserved = 0x0FFFFF00, /* Reserved, set to zero. */ + SubtableType = 0x000000FF, /* Subtable type. */ + }; + + template <typename context_t> + inline typename context_t::return_t dispatch (context_t *c) 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)); + default: return_trace (c->default_return_value ()); + } } - inline unsigned int get_size (void) const { return length; } - inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - if (unlikely (!c->check_struct (this))) + if (!u.header.sanitize (c) || + !c->check_range (this, u.header.length)) return_trace (false); - switch (format) { - case 0: return u.format0.sanitize (c); - case 1: return u.format1.sanitize (c); - case 2: return u.format2.sanitize (c); - case 4: return u.format4.sanitize (c); - case 6: return u.format6.sanitize (c); - default:return_trace (false); - } + return_trace (dispatch (c)); } protected: - HBUINT32 length; - HBUINT8 coverage; - HBUINT16 unused; - HBUINT8 format; - HBUINT32 tupleIndex; union { + KerxSubTableHeader header; KerxSubTableFormat0 format0; KerxSubTableFormat1 format1; KerxSubTableFormat2 format2; @@ -273,71 +645,90 @@ public: DEFINE_SIZE_MIN (12); }; -struct SubtableGlyphCoverageArray -{ - inline bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (likely (c->check_struct (this))); - } - protected: - HBUINT32 length; - HBUINT32 coverage; - HBUINT32 tupleCount; - public: - DEFINE_SIZE_STATIC (12); -}; +/* + * The 'kerx' Table + */ struct kerx { static const hb_tag_t tableTag = HB_AAT_TAG_kerx; - inline bool apply (hb_aat_apply_context_t *c, const AAT::ankr *ankr) const + inline bool has_data (void) const { return version != 0; } + + inline void apply (hb_aat_apply_context_t *c) const { - TRACE_APPLY (this); - const KerxTable &table = StructAfter<KerxTable> (*this); - return_trace (table.apply (c, ankr)); + c->set_lookup_index (0); + const KerxTable *table = &firstTable; + unsigned int count = tableCount; + for (unsigned int i = 0; i < count; i++) + { + bool reverse; + + if (table->u.header.coverage & (KerxTable::CrossStream)) + goto skip; /* We do NOT handle cross-stream. */ + + if (HB_DIRECTION_IS_VERTICAL (c->buffer->props.direction) != + bool (table->u.header.coverage & KerxTable::Vertical)) + goto skip; + + reverse = bool (table->u.header.coverage & KerxTable::Backwards) != + HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction); + + if (!c->buffer->message (c->font, "start kerx subtable %d", c->lookup_index)) + goto skip; + + if (reverse) + c->buffer->reverse (); + + c->sanitizer.set_object (*table); + + /* XXX Reverse-kern is not working yet... + * hb_kern_machine_t would need to know that it's reverse-kerning. + * Or better yet, make it work in reverse as well, so we don't have + * to reverse and reverse back? */ + table->dispatch (c); + + if (reverse) + c->buffer->reverse (); + + (void) c->buffer->message (c->font, "end kerx subtable %d", c->lookup_index); + + skip: + table = &StructAfter<KerxTable> (*table); + } } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - if (unlikely (!(c->check_struct (this)))) - return_trace (false); - - /* TODO: Something like `morx`s ChainSubtable should be done here instead */ - const KerxTable *table = &StructAfter<KerxTable> (*this); - if (unlikely (!(table->sanitize (c)))) + if (!version.sanitize (c) || version < 2 || + !tableCount.sanitize (c)) return_trace (false); - for (unsigned int i = 0; i < nTables - 1; ++i) + const KerxTable *table = &firstTable; + unsigned int count = tableCount; + for (unsigned int i = 0; i < count; i++) { + if (!table->sanitize (c)) + return_trace (false); table = &StructAfter<KerxTable> (*table); - if (unlikely (!(table->sanitize (c)))) - return_trace (false); } - // If version is less than 3, we are done here; otherwise better to check footer also - if (version < 3) - return_trace (true); - - // TODO: Investigate why this just work on some fonts no matter of version - // const SubtableGlyphCoverageArray &footer = - // StructAfter<SubtableGlyphCoverageArray> (*table); - // return_trace (footer.sanitize (c)); - return_trace (true); } protected: - HBUINT16 version; - HBUINT16 padding; - HBUINT32 nTables; -/*KerxTable tablesZ[VAR]; XXX ArrayOf??? */ -/*SubtableGlyphCoverageArray coverage_array;*/ + HBUINT16 version; /* The version number of the extended kerning table + * (currently 2, 3, or 4). */ + HBUINT16 unused; /* Set to 0. */ + HBUINT32 tableCount; /* The number of subtables included in the extended kerning + * table. */ + KerxTable firstTable; /* Subtables. */ +/*subtableGlyphCoverageArray*/ /* Only if version >= 3. We don't use. */ + public: - DEFINE_SIZE_STATIC (8); + DEFINE_SIZE_MIN (8); }; } /* namespace AAT */ diff --git a/src/hb-aat-layout-morx-table.hh b/src/hb-aat-layout-morx-table.hh index f25842457..651af2188 100644 --- a/src/hb-aat-layout-morx-table.hh +++ b/src/hb-aat-layout-morx-table.hh @@ -27,9 +27,9 @@ #ifndef HB_AAT_LAYOUT_MORX_TABLE_HH #define HB_AAT_LAYOUT_MORX_TABLE_HH -#include "hb-open-type-private.hh" -#include "hb-aat-layout-common-private.hh" -#include "hb-ot-layout-common-private.hh" +#include "hb-open-type.hh" +#include "hb-aat-layout-common.hh" +#include "hb-ot-layout-common.hh" /* * morx -- Extended Glyph Metamorphosis @@ -50,7 +50,8 @@ struct RearrangementSubtable struct driver_context_t { static const bool in_place = true; - enum Flags { + enum Flags + { MarkFirst = 0x8000, /* If set, make the current glyph the first * glyph to be rearranged. */ DontAdvance = 0x4000, /* If set, don't advance to the next glyph @@ -163,7 +164,7 @@ struct RearrangementSubtable driver_context_t dc (this); - StateTableDriver<void> driver (machine, c->buffer, c->face); + StateTableDriver<EntryData> driver (machine, c->buffer, c->face); driver.drive (&dc); return_trace (dc.ret); @@ -196,7 +197,8 @@ struct ContextualSubtable struct driver_context_t { static const bool in_place = true; - enum Flags { + enum Flags + { SetMark = 0x8000, /* If set, make the current glyph the marked glyph. */ DontAdvance = 0x4000, /* If set, don't advance to the next glyph before * going to the new state. */ @@ -268,7 +270,7 @@ struct ContextualSubtable private: bool mark_set; unsigned int mark; - const UnsizedOffsetListOf<Lookup<GlyphID>, HBUINT32> &subs; + const UnsizedOffsetListOf<Lookup<GlyphID>, HBUINT32, false> &subs; }; inline bool apply (hb_aat_apply_context_t *c) const @@ -309,7 +311,7 @@ struct ContextualSubtable protected: StateTable<EntryData> machine; - LOffsetTo<UnsizedOffsetListOf<Lookup<GlyphID>, HBUINT32> > + LOffsetTo<UnsizedOffsetListOf<Lookup<GlyphID>, HBUINT32, false>, false> substitutionTables; public: DEFINE_SIZE_STATIC (20); @@ -329,7 +331,8 @@ struct LigatureSubtable struct driver_context_t { static const bool in_place = false; - enum Flags { + enum Flags + { SetComponent = 0x8000, /* Push this glyph onto the component stack for * eventual processing. */ DontAdvance = 0x4000, /* Leave the glyph pointer at this glyph for the @@ -338,7 +341,8 @@ struct LigatureSubtable * group. */ Reserved = 0x1FFF, /* These bits are reserved and should be set to 0. */ }; - enum LigActionFlags { + enum LigActionFlags + { LigActionLast = 0x80000000, /* This is the last action in the list. This also * implies storage. */ LigActionStore = 0x40000000, /* Store the ligature at the current cumulated index @@ -361,7 +365,7 @@ struct LigatureSubtable inline bool is_actionable (StateTableDriver<EntryData> *driver, const Entry<EntryData> *entry) { - return !!(entry->flags & PerformAction); + return entry->flags & PerformAction; } inline bool transition (StateTableDriver<EntryData> *driver, const Entry<EntryData> *entry) @@ -387,12 +391,20 @@ struct LigatureSubtable unsigned int action_idx = entry->data.ligActionIndex; unsigned int action; unsigned int ligature_idx = 0; + + if (unlikely (!match_length)) + return true; + + /* TODO Only when ligation happens? */ + buffer->merge_out_clusters (match_positions[0], buffer->out_len); + + unsigned int cursor = match_length; do { - if (unlikely (!match_length)) - return false; + if (unlikely (!cursor)) + break; - buffer->move_to (match_positions[--match_length]); + buffer->move_to (match_positions[--cursor]); const HBUINT32 &actionData = ligAction[action_idx]; if (unlikely (!actionData.sanitize (&c->sanitizer))) return false; @@ -400,8 +412,10 @@ struct LigatureSubtable uint32_t uoffset = action & LigActionOffset; if (uoffset & 0x20000000) - uoffset += 0xC0000000; + uoffset |= 0xC0000000; /* Sign-extend. */ int32_t offset = (int32_t) uoffset; + if (buffer->idx >= buffer->len) + return false; // TODO Work on previous instead? unsigned int component_idx = buffer->cur().codepoint + offset; const HBUINT16 &componentData = component[component_idx]; @@ -414,21 +428,21 @@ struct LigatureSubtable if (unlikely (!ligatureData.sanitize (&c->sanitizer))) return false; hb_codepoint_t lig = ligatureData; - match_positions[match_length++] = buffer->out_len; buffer->replace_glyph (lig); - //ligature_idx = 0; // XXX Yes or no? - } - else - { - buffer->skip_glyph (); - end--; + /* Now go and delete all subsequent components. */ + while (match_length - 1 > cursor) + { + buffer->move_to (match_positions[--match_length]); + buffer->skip_glyph (); + end--; + } } - /* TODO merge_clusters / unsafe_to_break */ action_idx++; } while (!(action & LigActionLast)); + match_length = 0; buffer->move_to (end); } @@ -469,11 +483,11 @@ struct LigatureSubtable protected: StateTable<EntryData> machine; - LOffsetTo<UnsizedArrayOf<HBUINT32> > + LOffsetTo<UnsizedArrayOf<HBUINT32>, false> ligAction; /* Offset to the ligature action table. */ - LOffsetTo<UnsizedArrayOf<HBUINT16> > + LOffsetTo<UnsizedArrayOf<HBUINT16>, false> component; /* Offset to the component table. */ - LOffsetTo<UnsizedArrayOf<GlyphID> > + LOffsetTo<UnsizedArrayOf<GlyphID>, false> ligature; /* Offset to the actual ligature lists. */ public: DEFINE_SIZE_STATIC (28); @@ -517,19 +531,201 @@ struct NoncontextualSubtable struct InsertionSubtable { + struct EntryData + { + HBUINT16 currentInsertIndex; /* Zero-based index into the insertion glyph table. + * The number of glyphs to be inserted is contained + * in the currentInsertCount field in the flags. + * A value of 0xFFFF indicates no insertion is to + * be done. */ + HBUINT16 markedInsertIndex; /* Zero-based index into the insertion glyph table. + * The number of glyphs to be inserted is contained + * in the markedInsertCount field in the flags. + * A value of 0xFFFF indicates no insertion is to + * be done. */ + public: + DEFINE_SIZE_STATIC (4); + }; + + struct driver_context_t + { + static const bool in_place = false; + enum Flags + { + SetMark = 0x8000, /* If set, mark the current glyph. */ + DontAdvance = 0x4000, /* If set, don't advance to the next glyph before + * going to the new state. This does not mean + * that the glyph pointed to is the same one as + * before. If you've made insertions immediately + * downstream of the current glyph, the next glyph + * processed would in fact be the first one + * inserted. */ + CurrentIsKashidaLike= 0x2000, /* If set, and the currentInsertList is nonzero, + * then the specified glyph list will be inserted + * as a kashida-like insertion, either before or + * after the current glyph (depending on the state + * of the currentInsertBefore flag). If clear, and + * the currentInsertList is nonzero, then the + * specified glyph list will be inserted as a + * split-vowel-like insertion, either before or + * after the current glyph (depending on the state + * of the currentInsertBefore flag). */ + MarkedIsKashidaLike= 0x1000, /* If set, and the markedInsertList is nonzero, + * then the specified glyph list will be inserted + * as a kashida-like insertion, either before or + * after the marked glyph (depending on the state + * of the markedInsertBefore flag). If clear, and + * the markedInsertList is nonzero, then the + * specified glyph list will be inserted as a + * split-vowel-like insertion, either before or + * after the marked glyph (depending on the state + * of the markedInsertBefore flag). */ + CurrentInsertBefore= 0x0800, /* If set, specifies that insertions are to be made + * to the left of the current glyph. If clear, + * they're made to the right of the current glyph. */ + MarkedInsertBefore= 0x0400, /* If set, specifies that insertions are to be + * made to the left of the marked glyph. If clear, + * they're made to the right of the marked glyph. */ + CurrentInsertCount= 0x3E0, /* This 5-bit field is treated as a count of the + * number of glyphs to insert at the current + * position. Since zero means no insertions, the + * largest number of insertions at any given + * current location is 31 glyphs. */ + MarkedInsertCount= 0x001F, /* This 5-bit field is treated as a count of the + * number of glyphs to insert at the marked + * position. Since zero means no insertions, the + * largest number of insertions at any given + * marked location is 31 glyphs. */ + }; + + inline driver_context_t (const InsertionSubtable *table, + hb_aat_apply_context_t *c_) : + ret (false), + c (c_), + mark_set (false), + mark (0), + insertionAction (table+table->insertionAction) {} + + inline bool is_actionable (StateTableDriver<EntryData> *driver, + const Entry<EntryData> *entry) + { + return (entry->flags & (CurrentInsertCount | MarkedInsertCount)) && + (entry->data.currentInsertIndex != 0xFFFF ||entry->data.markedInsertIndex != 0xFFFF); + } + inline bool transition (StateTableDriver<EntryData> *driver, + const Entry<EntryData> *entry) + { + hb_buffer_t *buffer = driver->buffer; + unsigned int flags = entry->flags; + + if (entry->data.markedInsertIndex != 0xFFFF && mark_set) + { + unsigned int count = (flags & MarkedInsertCount); + unsigned int start = entry->data.markedInsertIndex; + const GlyphID *glyphs = &insertionAction[start]; + if (unlikely (!c->sanitizer.check_array (glyphs, count))) return false; + + bool before = flags & MarkedInsertBefore; + + unsigned int end = buffer->out_len; + buffer->move_to (mark); + + if (buffer->idx < buffer->len && !before) + buffer->copy_glyph (); + /* TODO We ignore KashidaLike setting. */ + for (unsigned int i = 0; i < count; i++) + buffer->output_glyph (glyphs[i]); + if (buffer->idx < buffer->len && !before) + buffer->skip_glyph (); + + buffer->move_to (end + count); + + buffer->unsafe_to_break_from_outbuffer (mark, MIN (buffer->idx + 1, buffer->len)); + } + + if (entry->data.currentInsertIndex != 0xFFFF) + { + unsigned int count = (flags & CurrentInsertCount) >> 5; + unsigned int start = entry->data.currentInsertIndex; + const GlyphID *glyphs = &insertionAction[start]; + if (unlikely (!c->sanitizer.check_array (glyphs, count))) return false; + + bool before = flags & CurrentInsertBefore; + + unsigned int end = buffer->out_len; + + if (buffer->idx < buffer->len && !before) + buffer->copy_glyph (); + /* TODO We ignore KashidaLike setting. */ + for (unsigned int i = 0; i < count; i++) + buffer->output_glyph (glyphs[i]); + if (buffer->idx < buffer->len && !before) + buffer->skip_glyph (); + + /* Humm. Not sure where to move to. There's this wording under + * DontAdvance flag: + * + * "If set, don't update the glyph index before going to the new state. + * This does not mean that the glyph pointed to is the same one as + * before. If you've made insertions immediately downstream of the + * current glyph, the next glyph processed would in fact be the first + * one inserted." + * + * This suggests that if DontAdvance is NOT set, we should move to + * end+count. If it *was*, then move to end, such that newly inserted + * glyphs are now visible. + * + * https://github.com/harfbuzz/harfbuzz/issues/1224#issuecomment-427691417 + */ + buffer->move_to ((flags & DontAdvance) ? end : end + count); + } + + if (flags & SetMark) + { + mark_set = true; + mark = buffer->out_len; + } + + return true; + } + + public: + bool ret; + private: + hb_aat_apply_context_t *c; + bool mark_set; + unsigned int mark; + const UnsizedArrayOf<GlyphID> &insertionAction; + }; + inline bool apply (hb_aat_apply_context_t *c) const { TRACE_APPLY (this); - /* TODO */ - return_trace (false); + + driver_context_t dc (this, c); + + StateTableDriver<EntryData> driver (machine, c->buffer, c->face); + driver.drive (&dc); + + return_trace (dc.ret); } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - /* TODO */ - return_trace (true); + /* The rest of array sanitizations are done at run-time. */ + return_trace (c->check_struct (this) && machine.sanitize (c) && + insertionAction); } + + protected: + StateTable<EntryData> + machine; + LOffsetTo<UnsizedArrayOf<GlyphID>, false> + insertionAction; /* Byte offset from stateHeader to the start of + * the insertion glyph table. */ + public: + DEFINE_SIZE_STATIC (20); }; @@ -559,9 +755,27 @@ struct ChainSubtable friend struct Chain; inline unsigned int get_size (void) const { return length; } - inline unsigned int get_type (void) const { return coverage & 0xFF; } + inline unsigned int get_type (void) const { return coverage & SubtableType; } - enum Type { + enum Coverage + { + Vertical = 0x80000000, /* If set, this subtable will only be applied + * to vertical text. If clear, this subtable + * will only be applied to horizontal text. */ + Backwards = 0x40000000, /* If set, this subtable will process glyphs + * in descending order. If clear, it will + * process the glyphs in ascending order. */ + AllDirections = 0x20000000, /* If set, this subtable will be applied to + * both horizontal and vertical text (i.e. + * the state of bit 0x80000000 is ignored). */ + Logical = 0x10000000, /* If set, this subtable will process glyphs + * in logical order (or reverse logical order, + * depending on the value of bit 0x80000000). */ + Reserved = 0x0FFFFF00, /* Reserved, set to zero. */ + SubtableType = 0x000000FF, /* Subtable type; see following table. */ + }; + enum Type + { Rearrangement = 0, Contextual = 1, Ligature = 2, @@ -569,11 +783,6 @@ struct ChainSubtable Insertion = 5 }; - inline void apply (hb_aat_apply_context_t *c) const - { - dispatch (c); - } - template <typename context_t> inline typename context_t::return_t dispatch (context_t *c) const { @@ -619,28 +828,94 @@ struct Chain { inline void apply (hb_aat_apply_context_t *c) const { - const ChainSubtable *subtable = &StructAtOffset<ChainSubtable> (featureZ, featureZ[0].static_size * featureCount); + uint32_t flags = defaultFlags; + { + /* Compute applicable flags. TODO Should move this to planning + * stage and take user-requested features into account. */ + unsigned int count = featureCount; + for (unsigned i = 0; i < count; i++) + { + const Feature &feature = featureZ[i]; + if (false) /* XXX Check if feature enabled... */ + { + flags &= feature.disableFlags; + flags |= feature.enableFlags; + } + } + } + + const ChainSubtable *subtable = &StructAtOffset<ChainSubtable> (&featureZ, featureZ[0].static_size * featureCount); unsigned int count = subtableCount; for (unsigned int i = 0; i < count; i++) { + bool reverse; + + if (!(subtable->subFeatureFlags & flags)) + goto skip; + + if (!(subtable->coverage & ChainSubtable::AllDirections) && + HB_DIRECTION_IS_VERTICAL (c->buffer->props.direction) != + bool (subtable->coverage & ChainSubtable::Vertical)) + goto skip; + + /* Buffer contents is always in logical direction. Determine if + * we need to reverse before applying this subtable. We reverse + * back after if we did reverse indeed. + * + * Quoting the spac: + * """ + * Bits 28 and 30 of the coverage field control the order in which + * glyphs are processed when the subtable is run by the layout engine. + * Bit 28 is used to indicate if the glyph processing direction is + * the same as logical order or layout order. Bit 30 is used to + * indicate whether glyphs are processed forwards or backwards within + * that order. + + Bit 30 Bit 28 Interpretation for Horizontal Text + 0 0 The subtable is processed in layout order + (the same order as the glyphs, which is + always left-to-right). + 1 0 The subtable is processed in reverse layout order + (the order opposite that of the glyphs, which is + always right-to-left). + 0 1 The subtable is processed in logical order + (the same order as the characters, which may be + left-to-right or right-to-left). + 1 1 The subtable is processed in reverse logical order + (the order opposite that of the characters, which + may be right-to-left or left-to-right). + */ + reverse = subtable->coverage & ChainSubtable::Logical ? + bool (subtable->coverage & ChainSubtable::Backwards) : + bool (subtable->coverage & ChainSubtable::Backwards) != + HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction); + if (!c->buffer->message (c->font, "start chain subtable %d", c->lookup_index)) - { - c->set_lookup_index (c->lookup_index + 1); - continue; - } + goto skip; - subtable->apply (c); - subtable = &StructAfter<ChainSubtable> (*subtable); + if (reverse) + c->buffer->reverse (); + + c->sanitizer.set_object (*subtable); + + subtable->dispatch (c); + + if (reverse) + c->buffer->reverse (); (void) c->buffer->message (c->font, "end chain subtable %d", c->lookup_index); + if (unlikely (!c->buffer->successful)) return; + + skip: + subtable = &StructAfter<ChainSubtable> (*subtable); c->set_lookup_index (c->lookup_index + 1); } } inline unsigned int get_size (void) const { return length; } - inline bool sanitize (hb_sanitize_context_t *c, unsigned int major) const + inline bool sanitize (hb_sanitize_context_t *c, unsigned int version) const { TRACE_SANITIZE (this); if (!length.sanitize (c) || @@ -648,10 +923,10 @@ struct Chain !c->check_range (this, length)) return_trace (false); - if (!c->check_array (featureZ, featureZ[0].static_size, featureCount)) + if (!c->check_array (featureZ.arrayZ, featureCount)) return_trace (false); - const ChainSubtable *subtable = &StructAtOffset<ChainSubtable> (featureZ, featureZ[0].static_size * featureCount); + const ChainSubtable *subtable = &StructAtOffset<ChainSubtable> (&featureZ, featureZ[0].static_size * featureCount); unsigned int count = subtableCount; for (unsigned int i = 0; i < count; i++) { @@ -669,9 +944,9 @@ struct Chain HBUINT32 featureCount; /* Number of feature subtable entries. */ HBUINT32 subtableCount; /* The number of subtables in the chain. */ - Feature featureZ[VAR]; /* Features. */ -/*ChainSubtable subtableX[VAR];*//* Subtables. */ -/*subtableGlyphCoverageArray*/ /* Only if major == 3. */ + UnsizedArrayOf<Feature> featureZ; /* Features. */ +/*ChainSubtable firstSubtable;*//* Subtables. */ +/*subtableGlyphCoverageArray*/ /* Only if version >= 3. We don't use. */ public: DEFINE_SIZE_MIN (16); @@ -679,21 +954,25 @@ struct Chain /* - * The 'mort'/'morx' Tables + * The 'morx' Table */ struct morx { static const hb_tag_t tableTag = HB_AAT_TAG_morx; + inline bool has_data (void) const { return version != 0; } + inline void apply (hb_aat_apply_context_t *c) const { + if (unlikely (!c->buffer->successful)) return; c->set_lookup_index (0); - const Chain *chain = chainsZ; + const Chain *chain = &firstChain; unsigned int count = chainCount; for (unsigned int i = 0; i < count; i++) { chain->apply (c); + if (unlikely (!c->buffer->successful)) return; chain = &StructAfter<Chain> (*chain); } } @@ -701,16 +980,15 @@ struct morx inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - if (!version.sanitize (c) || - (version.major >> (sizeof (HBUINT32) == 4 ? 1 : 0)) != 1 || + if (!version.sanitize (c) || version < 2 || !chainCount.sanitize (c)) return_trace (false); - const Chain *chain = chainsZ; + const Chain *chain = &firstChain; unsigned int count = chainCount; for (unsigned int i = 0; i < count; i++) { - if (!chain->sanitize (c, version.major)) + if (!chain->sanitize (c, version)) return_trace (false); chain = &StructAfter<Chain> (*chain); } @@ -719,11 +997,12 @@ struct morx } protected: - FixedVersion<>version; /* Version number of the glyph metamorphosis table. - * 1 for mort, 2 or 3 for morx. */ + HBUINT16 version; /* Version number of the glyph metamorphosis table. + * 2 or 3. */ + HBUINT16 unused; /* Set to 0. */ HBUINT32 chainCount; /* Number of metamorphosis chains contained in this * table. */ - Chain chainsZ[VAR]; /* Chains. */ + Chain firstChain; /* Chains. */ public: DEFINE_SIZE_MIN (8); diff --git a/src/hb-aat-layout-trak-table.hh b/src/hb-aat-layout-trak-table.hh index f5dc558c3..16729d16f 100644 --- a/src/hb-aat-layout-trak-table.hh +++ b/src/hb-aat-layout-trak-table.hh @@ -28,9 +28,9 @@ #ifndef HB_AAT_LAYOUT_TRAK_TABLE_HH #define HB_AAT_LAYOUT_TRAK_TABLE_HH -#include "hb-aat-layout-common-private.hh" -#include "hb-ot-layout-private.hh" -#include "hb-open-type-private.hh" +#include "hb-aat-layout-common.hh" +#include "hb-ot-layout.hh" +#include "hb-open-type.hh" /* * trak -- Tracking @@ -46,29 +46,33 @@ struct TrackTableEntry { friend struct TrackData; - inline bool sanitize (hb_sanitize_context_t *c, const void *base, - unsigned int size) const + inline float get_track_value () const { - TRACE_SANITIZE (this); - return_trace (likely (c->check_struct (this) && - (valuesZ.sanitize (c, base, size)))); + return track.to_float (); } - private: - inline float get_track_value () const + inline int get_value (const void *base, + unsigned int index, + unsigned int nSizes) const { - return track.to_float (); + return hb_array_t<FWORD> ((base+valuesZ).arrayZ, nSizes)[index]; } - inline int get_value (const void *base, unsigned int index) const + public: + inline bool sanitize (hb_sanitize_context_t *c, const void *base, + unsigned int nSizes) const { - return (base+valuesZ)[index]; + TRACE_SANITIZE (this); + return_trace (likely (c->check_struct (this) && + (valuesZ.sanitize (c, base, nSizes)))); } protected: Fixed track; /* Track value for this record. */ - NameID trackNameID; /* The 'name' table index for this track */ - OffsetTo<UnsizedArrayOf<FWORD> > + NameID trackNameID; /* The 'name' table index for this track. + * (a short word or phrase like "loose" + * or "very tight") */ + OffsetTo<UnsizedArrayOf<FWORD>, HBUINT16, false> valuesZ; /* Offset from start of tracking table to * per-size tracking values for this track. */ @@ -78,15 +82,22 @@ struct TrackTableEntry struct TrackData { - inline bool sanitize (hb_sanitize_context_t *c, const void *base) const + inline float interpolate_at (unsigned int idx, + float target_size, + const TrackTableEntry &trackTableEntry, + const void *base) const { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && - sizeTable.sanitize (c, base, nSizes) && - trackTable.sanitize (c, nTracks, base, nSizes)); + unsigned int sizes = nSizes; + hb_array_t<Fixed> size_table ((base+sizeTable).arrayZ, sizes); + + float s0 = size_table[idx].to_float (); + float s1 = size_table[idx + 1].to_float (); + float t = unlikely (s0 == s1) ? 0.f : (target_size - s0) / (s1 - s0); + return t * trackTableEntry.get_value (base, idx + 1, sizes) + + (1.f - t) * trackTableEntry.get_value (base, idx, sizes); } - inline float get_tracking (const void *base, float ptem) const + inline int get_tracking (const void *base, float ptem) const { /* CoreText points are CSS pixels (96 per inch), * NOT typographic points (72 per inch). @@ -94,48 +105,59 @@ struct TrackData * https://developer.apple.com/library/content/documentation/GraphicsAnimation/Conceptual/HighResolutionOSX/Explained/Explained.html */ float csspx = ptem * 96.f / 72.f; - Fixed fixed_size; - fixed_size.set_float (csspx); - /* XXX Clean this up. Make it work with nSizes==1 and 0. */ + /* + * Choose track. + */ + const TrackTableEntry *trackTableEntry = nullptr; + unsigned int count = nTracks; + for (unsigned int i = 0; i < count; i++) + { + /* Note: Seems like the track entries are sorted by values. But the + * spec doesn't explicitly say that. It just mentions it in the example. */ - unsigned int sizes = nSizes; + /* For now we only seek for track entries with zero tracking value */ - const TrackTableEntry *trackTableEntry = nullptr; - for (unsigned int i = 0; i < sizes; ++i) - // For now we only seek for track entries with zero tracking value if (trackTable[i].get_track_value () == 0.f) - trackTableEntry = &trackTable[0]; - - // We couldn't match any, exit + { + trackTableEntry = &trackTable[i]; + break; + } + } if (!trackTableEntry) return 0.; + /* + * Choose size. + */ + unsigned int sizes = nSizes; + if (!sizes) return 0.; + if (sizes == 1) return trackTableEntry->get_value (base, 0, sizes); + /* TODO bfind() */ + hb_array_t<Fixed> size_table ((base+sizeTable).arrayZ, sizes); unsigned int size_index; - UnsizedArrayOf<Fixed> size_table = base+sizeTable; - for (size_index = 0; size_index < sizes; ++size_index) - if (size_table[size_index] >= fixed_size) + for (size_index = 0; size_index < sizes - 1; size_index++) + if (size_table[size_index].to_float () >= csspx) break; - // TODO(ebraminio): We don't attempt to extrapolate to larger or - // smaller values for now but we should do, per spec - if (size_index == sizes) - return trackTableEntry->get_value (base, sizes - 1); - if (size_index == 0 || size_table[size_index] == fixed_size) - return trackTableEntry->get_value (base, size_index); - - float s0 = size_table[size_index - 1].to_float (); - float s1 = size_table[size_index].to_float (); - float t = (csspx - s0) / (s1 - s0); - return (float) t * trackTableEntry->get_value (base, size_index) + - ((float) 1.0 - t) * trackTableEntry->get_value (base, size_index - 1); + return round (interpolate_at (size_index ? size_index - 1 : 0, csspx, + *trackTableEntry, base)); + } + + inline bool sanitize (hb_sanitize_context_t *c, const void *base) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && + sizeTable.sanitize (c, base, nSizes) && + trackTable.sanitize (c, nTracks, base, nSizes)); } protected: HBUINT16 nTracks; /* Number of separate tracks included in this table. */ HBUINT16 nSizes; /* Number of point sizes included in this table. */ - LOffsetTo<UnsizedArrayOf<Fixed> > - sizeTable; /* Offset to array[nSizes] of size values. */ + LOffsetTo<UnsizedArrayOf<Fixed>, false> + sizeTable; /* Offset from start of the tracking table to + * Array[nSizes] of size values.. */ UnsizedArrayOf<TrackTableEntry> trackTable; /* Array[nTracks] of TrackTableEntry records. */ @@ -147,6 +169,8 @@ struct trak { static const hb_tag_t tableTag = HB_AAT_TAG_trak; + inline bool has_data (void) const { return version.to_int () != 0; } + inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -168,25 +192,25 @@ struct trak if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction)) { const TrackData &trackData = this+horizData; - float tracking = trackData.get_tracking (this, ptem); - hb_position_t advance_to_add = c->font->em_scalef_x (tracking / 2); + int tracking = trackData.get_tracking (this, ptem); + hb_position_t offset_to_add = c->font->em_scalef_x (tracking / 2); + hb_position_t advance_to_add = c->font->em_scalef_x (tracking); foreach_grapheme (buffer, start, end) { - buffer->pos[start].x_offset += advance_to_add; buffer->pos[start].x_advance += advance_to_add; - buffer->pos[end].x_advance += advance_to_add; + buffer->pos[start].x_offset += offset_to_add; } } else { const TrackData &trackData = this+vertData; - float tracking = trackData.get_tracking (this, ptem); - hb_position_t advance_to_add = c->font->em_scalef_y (tracking / 2); + int tracking = trackData.get_tracking (this, ptem); + hb_position_t offset_to_add = c->font->em_scalef_y (tracking / 2); + hb_position_t advance_to_add = c->font->em_scalef_y (tracking); foreach_grapheme (buffer, start, end) { - buffer->pos[start].y_offset += advance_to_add; buffer->pos[start].y_advance += advance_to_add; - buffer->pos[end].y_advance += advance_to_add; + buffer->pos[start].y_offset += offset_to_add; } } @@ -194,15 +218,17 @@ struct trak } protected: - FixedVersion<> version; /* Version of the tracking table--currently - * 0x00010000u for version 1.0. */ - HBUINT16 format; /* Format of the tracking table */ - OffsetTo<TrackData> horizData; /* TrackData for horizontal text */ - OffsetTo<TrackData> vertData; /* TrackData for vertical text */ + FixedVersion<> version; /* Version of the tracking table + * (0x00010000u for version 1.0). */ + HBUINT16 format; /* Format of the tracking table (set to 0). */ + OffsetTo<TrackData> horizData; /* Offset from start of tracking table to TrackData + * for horizontal text (or 0 if none). */ + OffsetTo<TrackData> vertData; /* Offset from start of tracking table to TrackData + * for vertical text (or 0 if none). */ HBUINT16 reserved; /* Reserved. Set to 0. */ public: - DEFINE_SIZE_MIN (12); + DEFINE_SIZE_STATIC (12); }; } /* namespace AAT */ diff --git a/src/hb-aat-layout.cc b/src/hb-aat-layout.cc index 36d4037ad..e9da850b3 100644 --- a/src/hb-aat-layout.cc +++ b/src/hb-aat-layout.cc @@ -24,12 +24,10 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-open-type-private.hh" +#include "hb-open-type.hh" -#include "hb-ot-layout-private.hh" -#include "hb-ot-layout-gsubgpos-private.hh" - -#include "hb-aat-layout-private.hh" +#include "hb-ot-face.hh" +#include "hb-aat-layout.hh" #include "hb-aat-layout-ankr-table.hh" #include "hb-aat-layout-bsln-table.hh" // Just so we compile it; unused otherwise. #include "hb-aat-layout-feat-table.hh" // Just so we compile it; unused otherwise. @@ -38,8 +36,101 @@ #include "hb-aat-layout-trak-table.hh" #include "hb-aat-ltag-table.hh" // Just so we compile it; unused otherwise. + +/* Table data courtesy of Apple. Converted from mnemonics to integers + * when moving to this file. */ +static const hb_aat_feature_mapping_t feature_mappings[] = +{ + {HB_TAG ('c','2','p','c'), 38/*kUpperCaseType*/, 2/*kUpperCasePetiteCapsSelector*/, 0/*kDefaultUpperCaseSelector*/}, + {HB_TAG ('c','2','s','c'), 38/*kUpperCaseType*/, 1/*kUpperCaseSmallCapsSelector*/, 0/*kDefaultUpperCaseSelector*/}, + {HB_TAG ('c','a','l','t'), 36/*kContextualAlternatesType*/, 0/*kContextualAlternatesOnSelector*/, 1/*kContextualAlternatesOffSelector*/}, + {HB_TAG ('c','a','s','e'), 33/*kCaseSensitiveLayoutType*/, 0/*kCaseSensitiveLayoutOnSelector*/, 1/*kCaseSensitiveLayoutOffSelector*/}, + {HB_TAG ('c','l','i','g'), 1/*kLigaturesType*/, 18/*kContextualLigaturesOnSelector*/, 19/*kContextualLigaturesOffSelector*/}, + {HB_TAG ('c','p','s','p'), 33/*kCaseSensitiveLayoutType*/, 2/*kCaseSensitiveSpacingOnSelector*/, 3/*kCaseSensitiveSpacingOffSelector*/}, + {HB_TAG ('c','s','w','h'), 36/*kContextualAlternatesType*/, 4/*kContextualSwashAlternatesOnSelector*/, 5/*kContextualSwashAlternatesOffSelector*/}, + {HB_TAG ('d','l','i','g'), 1/*kLigaturesType*/, 4/*kRareLigaturesOnSelector*/, 5/*kRareLigaturesOffSelector*/}, + {HB_TAG ('e','x','p','t'), 20/*kCharacterShapeType*/, 10/*kExpertCharactersSelector*/, 16}, + {HB_TAG ('f','r','a','c'), 11/*kFractionsType*/, 2/*kDiagonalFractionsSelector*/, 0/*kNoFractionsSelector*/}, + {HB_TAG ('f','w','i','d'), 22/*kTextSpacingType*/, 1/*kMonospacedTextSelector*/, 7}, + {HB_TAG ('h','a','l','t'), 22/*kTextSpacingType*/, 6/*kAltHalfWidthTextSelector*/, 7}, + {HB_TAG ('h','i','s','t'), 1/*kLigaturesType*/, 20/*kHistoricalLigaturesOnSelector*/, 21/*kHistoricalLigaturesOffSelector*/}, + {HB_TAG ('h','k','n','a'), 34/*kAlternateKanaType*/, 0/*kAlternateHorizKanaOnSelector*/, 1/*kAlternateHorizKanaOffSelector*/, }, + {HB_TAG ('h','l','i','g'), 1/*kLigaturesType*/, 20/*kHistoricalLigaturesOnSelector*/, 21/*kHistoricalLigaturesOffSelector*/}, + {HB_TAG ('h','n','g','l'), 23/*kTransliterationType*/, 1/*kHanjaToHangulSelector*/, 0/*kNoTransliterationSelector*/}, + {HB_TAG ('h','o','j','o'), 20/*kCharacterShapeType*/, 12/*kHojoCharactersSelector*/, 16}, + {HB_TAG ('h','w','i','d'), 22/*kTextSpacingType*/, 2/*kHalfWidthTextSelector*/, 7}, + {HB_TAG ('i','t','a','l'), 32/*kItalicCJKRomanType*/, 2/*kCJKItalicRomanOnSelector*/, 3/*kCJKItalicRomanOffSelector*/}, + {HB_TAG ('j','p','0','4'), 20/*kCharacterShapeType*/, 11/*kJIS2004CharactersSelector*/, 16}, + {HB_TAG ('j','p','7','8'), 20/*kCharacterShapeType*/, 2/*kJIS1978CharactersSelector*/, 16}, + {HB_TAG ('j','p','8','3'), 20/*kCharacterShapeType*/, 3/*kJIS1983CharactersSelector*/, 16}, + {HB_TAG ('j','p','9','0'), 20/*kCharacterShapeType*/, 4/*kJIS1990CharactersSelector*/, 16}, + {HB_TAG ('l','i','g','a'), 1/*kLigaturesType*/, 2/*kCommonLigaturesOnSelector*/, 3/*kCommonLigaturesOffSelector*/}, + {HB_TAG ('l','n','u','m'), 21/*kNumberCaseType*/, 1/*kUpperCaseNumbersSelector*/, 2}, + {HB_TAG ('m','g','r','k'), 15/*kMathematicalExtrasType*/, 10/*kMathematicalGreekOnSelector*/, 11/*kMathematicalGreekOffSelector*/}, + {HB_TAG ('n','l','c','k'), 20/*kCharacterShapeType*/, 13/*kNLCCharactersSelector*/, 16}, + {HB_TAG ('o','n','u','m'), 21/*kNumberCaseType*/, 0/*kLowerCaseNumbersSelector*/, 2}, + {HB_TAG ('o','r','d','n'), 10/*kVerticalPositionType*/, 3/*kOrdinalsSelector*/, 0/*kNormalPositionSelector*/}, + {HB_TAG ('p','a','l','t'), 22/*kTextSpacingType*/, 5/*kAltProportionalTextSelector*/, 7}, + {HB_TAG ('p','c','a','p'), 37/*kLowerCaseType*/, 2/*kLowerCasePetiteCapsSelector*/, 0/*kDefaultLowerCaseSelector*/}, + {HB_TAG ('p','k','n','a'), 22/*kTextSpacingType*/, 0/*kProportionalTextSelector*/, 7}, + {HB_TAG ('p','n','u','m'), 6/*kNumberSpacingType*/, 1/*kProportionalNumbersSelector*/, 4}, + {HB_TAG ('p','w','i','d'), 22/*kTextSpacingType*/, 0/*kProportionalTextSelector*/, 7}, + {HB_TAG ('q','w','i','d'), 22/*kTextSpacingType*/, 4/*kQuarterWidthTextSelector*/, 7}, + {HB_TAG ('r','u','b','y'), 28/*kRubyKanaType*/, 2/*kRubyKanaOnSelector*/, 3/*kRubyKanaOffSelector*/}, + {HB_TAG ('s','i','n','f'), 10/*kVerticalPositionType*/, 4/*kScientificInferiorsSelector*/, 0/*kNormalPositionSelector*/}, + {HB_TAG ('s','m','c','p'), 37/*kLowerCaseType*/, 1/*kLowerCaseSmallCapsSelector*/, 0/*kDefaultLowerCaseSelector*/}, + {HB_TAG ('s','m','p','l'), 20/*kCharacterShapeType*/, 1/*kSimplifiedCharactersSelector*/, 16}, + {HB_TAG ('s','s','0','1'), 35/*kStylisticAlternativesType*/, 2/*kStylisticAltOneOnSelector*/, 3/*kStylisticAltOneOffSelector*/}, + {HB_TAG ('s','s','0','2'), 35/*kStylisticAlternativesType*/, 4/*kStylisticAltTwoOnSelector*/, 5/*kStylisticAltTwoOffSelector*/}, + {HB_TAG ('s','s','0','3'), 35/*kStylisticAlternativesType*/, 6/*kStylisticAltThreeOnSelector*/, 7/*kStylisticAltThreeOffSelector*/}, + {HB_TAG ('s','s','0','4'), 35/*kStylisticAlternativesType*/, 8/*kStylisticAltFourOnSelector*/, 9/*kStylisticAltFourOffSelector*/}, + {HB_TAG ('s','s','0','5'), 35/*kStylisticAlternativesType*/, 10/*kStylisticAltFiveOnSelector*/, 11/*kStylisticAltFiveOffSelector*/}, + {HB_TAG ('s','s','0','6'), 35/*kStylisticAlternativesType*/, 12/*kStylisticAltSixOnSelector*/, 13/*kStylisticAltSixOffSelector*/}, + {HB_TAG ('s','s','0','7'), 35/*kStylisticAlternativesType*/, 14/*kStylisticAltSevenOnSelector*/, 15/*kStylisticAltSevenOffSelector*/}, + {HB_TAG ('s','s','0','8'), 35/*kStylisticAlternativesType*/, 16/*kStylisticAltEightOnSelector*/, 17/*kStylisticAltEightOffSelector*/}, + {HB_TAG ('s','s','0','9'), 35/*kStylisticAlternativesType*/, 18/*kStylisticAltNineOnSelector*/, 19/*kStylisticAltNineOffSelector*/}, + {HB_TAG ('s','s','1','0'), 35/*kStylisticAlternativesType*/, 20/*kStylisticAltTenOnSelector*/, 21/*kStylisticAltTenOffSelector*/}, + {HB_TAG ('s','s','1','1'), 35/*kStylisticAlternativesType*/, 22/*kStylisticAltElevenOnSelector*/, 23/*kStylisticAltElevenOffSelector*/}, + {HB_TAG ('s','s','1','2'), 35/*kStylisticAlternativesType*/, 24/*kStylisticAltTwelveOnSelector*/, 25/*kStylisticAltTwelveOffSelector*/}, + {HB_TAG ('s','s','1','3'), 35/*kStylisticAlternativesType*/, 26/*kStylisticAltThirteenOnSelector*/, 27/*kStylisticAltThirteenOffSelector*/}, + {HB_TAG ('s','s','1','4'), 35/*kStylisticAlternativesType*/, 28/*kStylisticAltFourteenOnSelector*/, 29/*kStylisticAltFourteenOffSelector*/}, + {HB_TAG ('s','s','1','5'), 35/*kStylisticAlternativesType*/, 30/*kStylisticAltFifteenOnSelector*/, 31/*kStylisticAltFifteenOffSelector*/}, + {HB_TAG ('s','s','1','6'), 35/*kStylisticAlternativesType*/, 32/*kStylisticAltSixteenOnSelector*/, 33/*kStylisticAltSixteenOffSelector*/}, + {HB_TAG ('s','s','1','7'), 35/*kStylisticAlternativesType*/, 34/*kStylisticAltSeventeenOnSelector*/, 35/*kStylisticAltSeventeenOffSelector*/}, + {HB_TAG ('s','s','1','8'), 35/*kStylisticAlternativesType*/, 36/*kStylisticAltEighteenOnSelector*/, 37/*kStylisticAltEighteenOffSelector*/}, + {HB_TAG ('s','s','1','9'), 35/*kStylisticAlternativesType*/, 38/*kStylisticAltNineteenOnSelector*/, 39/*kStylisticAltNineteenOffSelector*/}, + {HB_TAG ('s','s','2','0'), 35/*kStylisticAlternativesType*/, 40/*kStylisticAltTwentyOnSelector*/, 41/*kStylisticAltTwentyOffSelector*/}, + {HB_TAG ('s','u','b','s'), 10/*kVerticalPositionType*/, 2/*kInferiorsSelector*/, 0/*kNormalPositionSelector*/}, + {HB_TAG ('s','u','p','s'), 10/*kVerticalPositionType*/, 1/*kSuperiorsSelector*/, 0/*kNormalPositionSelector*/}, + {HB_TAG ('s','w','s','h'), 36/*kContextualAlternatesType*/, 2/*kSwashAlternatesOnSelector*/, 3/*kSwashAlternatesOffSelector*/}, + {HB_TAG ('t','i','t','l'), 19/*kStyleOptionsType*/, 4/*kTitlingCapsSelector*/, 0/*kNoStyleOptionsSelector*/}, + {HB_TAG ('t','n','a','m'), 20/*kCharacterShapeType*/, 14/*kTraditionalNamesCharactersSelector*/, 16}, + {HB_TAG ('t','n','u','m'), 6/*kNumberSpacingType*/, 0/*kMonospacedNumbersSelector*/, 4}, + {HB_TAG ('t','r','a','d'), 20/*kCharacterShapeType*/, 0/*kTraditionalCharactersSelector*/, 16}, + {HB_TAG ('t','w','i','d'), 22/*kTextSpacingType*/, 3/*kThirdWidthTextSelector*/, 7}, + {HB_TAG ('u','n','i','c'), 3/*kLetterCaseType*/, 14, 15}, + {HB_TAG ('v','a','l','t'), 22/*kTextSpacingType*/, 5/*kAltProportionalTextSelector*/, 7}, + {HB_TAG ('v','e','r','t'), 4/*kVerticalSubstitutionType*/, 0/*kSubstituteVerticalFormsOnSelector*/, 1/*kSubstituteVerticalFormsOffSelector*/}, + {HB_TAG ('v','h','a','l'), 22/*kTextSpacingType*/, 6/*kAltHalfWidthTextSelector*/, 7}, + {HB_TAG ('v','k','n','a'), 34/*kAlternateKanaType*/, 2/*kAlternateVertKanaOnSelector*/, 3/*kAlternateVertKanaOffSelector*/}, + {HB_TAG ('v','p','a','l'), 22/*kTextSpacingType*/, 5/*kAltProportionalTextSelector*/, 7}, + {HB_TAG ('v','r','t','2'), 4/*kVerticalSubstitutionType*/, 0/*kSubstituteVerticalFormsOnSelector*/, 1/*kSubstituteVerticalFormsOffSelector*/}, + {HB_TAG ('z','e','r','o'), 14/*kTypographicExtrasType*/, 4/*kSlashedZeroOnSelector*/, 5/*kSlashedZeroOffSelector*/}, +}; + +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); +} + + /* - * morx/kerx/trak/ankr + * morx/kerx/trak */ static inline const AAT::morx& @@ -51,46 +142,101 @@ _get_morx (hb_face_t *face, hb_blob_t **blob = nullptr) *blob = hb_blob_get_empty (); return Null(AAT::morx); } - hb_ot_layout_t * layout = hb_ot_layout_from_face (face); - const AAT::morx& morx = *(layout->table.morx.get ()); + const AAT::morx& morx = *(hb_ot_face_data (face)->morx.get ()); if (blob) - *blob = layout->table.morx.get_blob (); + *blob = hb_ot_face_data (face)->morx.get_blob (); return morx; } +static inline const AAT::kerx& +_get_kerx (hb_face_t *face, hb_blob_t **blob = nullptr) +{ + if (unlikely (!hb_ot_shaper_face_data_ensure (face))) + { + if (blob) + *blob = hb_blob_get_empty (); + return Null(AAT::kerx); + } + const AAT::kerx& kerx = *(hb_ot_face_data (face)->kerx.get ()); + if (blob) + *blob = hb_ot_face_data (face)->kerx.get_blob (); + return kerx; +} +static inline const AAT::ankr& +_get_ankr (hb_face_t *face, hb_blob_t **blob = nullptr) +{ + if (unlikely (!hb_ot_shaper_face_data_ensure (face))) + { + if (blob) + *blob = hb_blob_get_empty (); + return Null(AAT::ankr); + } + const AAT::ankr& ankr = *(hb_ot_face_data (face)->ankr.get ()); + if (blob) + *blob = hb_ot_face_data (face)->ankr.get_blob (); + return ankr; +} +static inline const AAT::trak& +_get_trak (hb_face_t *face) +{ + if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(AAT::trak); + return *(hb_ot_face_data (face)->trak.get ()); +} -// static inline void -// _hb_aat_layout_create (hb_face_t *face) -// { -// hb_blob_t *morx_blob = hb_sanitize_context_t ().reference_table<AAT::morx> (face); -// morx_blob->as<AAT::morx> (); -// if (0) -// { -// morx_blob->as<AAT::Lookup<OT::GlyphID> > ()->get_value (1, face->get_num_glyphs ()); -// } -// } +hb_bool_t +hb_aat_layout_has_substitution (hb_face_t *face) +{ + return _get_morx (face).has_data (); +} void -hb_aat_layout_substitute (hb_font_t *font, hb_buffer_t *buffer) +hb_aat_layout_substitute (hb_ot_shape_plan_t *plan, + hb_font_t *font, + hb_buffer_t *buffer) { hb_blob_t *blob; const AAT::morx& morx = _get_morx (font->face, &blob); - AAT::hb_aat_apply_context_t c (font, buffer, blob); + AAT::hb_aat_apply_context_t c (plan, font, buffer, blob); morx.apply (&c); } + +hb_bool_t +hb_aat_layout_has_positioning (hb_face_t *face) +{ + return _get_kerx (face).has_data (); +} + void -hb_aat_layout_position (hb_font_t *font, hb_buffer_t *buffer) +hb_aat_layout_position (hb_ot_shape_plan_t *plan, + hb_font_t *font, + hb_buffer_t *buffer) { -#if 0 hb_blob_t *blob; - const AAT::ankr& ankr = _get_ankr (font->face, &blob); const AAT::kerx& kerx = _get_kerx (font->face, &blob); - const AAT::trak& trak = _get_trak (font->face, &blob); - AAT::hb_aat_apply_context_t c (font, buffer, blob); - kerx.apply (&c, &ankr); + hb_blob_t *ankr_blob; + const AAT::ankr& ankr = _get_ankr (font->face, &ankr_blob); + + AAT::hb_aat_apply_context_t c (plan, font, buffer, blob, + ankr, ankr_blob->data + ankr_blob->length); + kerx.apply (&c); +} + +hb_bool_t +hb_aat_layout_has_tracking (hb_face_t *face) +{ + return _get_trak (face).has_data (); +} + +void +hb_aat_layout_track (hb_ot_shape_plan_t *plan, + hb_font_t *font, + hb_buffer_t *buffer) +{ + const AAT::trak& trak = _get_trak (font->face); + + AAT::hb_aat_apply_context_t c (plan, font, buffer); trak.apply (&c); -#endif } diff --git a/src/hb-aat-layout.hh b/src/hb-aat-layout.hh new file mode 100644 index 000000000..d0eb0190d --- /dev/null +++ b/src/hb-aat-layout.hh @@ -0,0 +1,80 @@ +/* + * Copyright © 2017 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Behdad Esfahbod + */ + +#ifndef HB_AAT_LAYOUT_HH +#define HB_AAT_LAYOUT_HH + +#include "hb.hh" + +#include "hb-ot-shape.hh" + + +struct hb_aat_feature_mapping_t +{ + hb_tag_t otFeatureTag; + uint16_t aatFeatureType; + uint16_t selectorToEnable; + uint16_t selectorToDisable; + + static inline int cmp (const void *key_, const void *entry_) + { + hb_tag_t key = * (unsigned int *) key_; + const hb_aat_feature_mapping_t * entry = (const hb_aat_feature_mapping_t *) entry_; + return key < entry->otFeatureTag ? -1 : + key > entry->otFeatureTag ? 1 : + 0; + } +}; + +HB_INTERNAL const hb_aat_feature_mapping_t * +hb_aat_layout_find_feature_mapping (hb_tag_t tag); + + +HB_INTERNAL hb_bool_t +hb_aat_layout_has_substitution (hb_face_t *face); + +HB_INTERNAL void +hb_aat_layout_substitute (hb_ot_shape_plan_t *plan, + hb_font_t *font, + hb_buffer_t *buffer); + +HB_INTERNAL hb_bool_t +hb_aat_layout_has_positioning (hb_face_t *face); + +HB_INTERNAL void +hb_aat_layout_position (hb_ot_shape_plan_t *plan, + hb_font_t *font, + hb_buffer_t *buffer); + +HB_INTERNAL hb_bool_t +hb_aat_layout_has_tracking (hb_face_t *face); + +HB_INTERNAL void +hb_aat_layout_track (hb_ot_shape_plan_t *plan, + hb_font_t *font, + hb_buffer_t *buffer); + +#endif /* HB_AAT_LAYOUT_HH */ diff --git a/src/hb-aat-ltag-table.hh b/src/hb-aat-ltag-table.hh index 15c4e89cb..08a1b51a9 100644 --- a/src/hb-aat-ltag-table.hh +++ b/src/hb-aat-ltag-table.hh @@ -25,7 +25,7 @@ #ifndef HB_AAT_LTAG_TABLE_HH #define HB_AAT_LTAG_TABLE_HH -#include "hb-aat-layout-common-private.hh" +#include "hb-aat-layout-common.hh" /* * ltag -- Language Tag @@ -46,7 +46,7 @@ struct FTStringRange } protected: - OffsetTo<UnsizedArrayOf<HBUINT8> > + OffsetTo<UnsizedArrayOf<HBUINT8>, HBUINT16, false> tag; /* Offset from the start of the table to * the beginning of the string */ HBUINT16 length; /* String length (in bytes) */ diff --git a/src/hb-atomic-private.hh b/src/hb-atomic.hh index 297c64698..5cb7ca5d5 100644 --- a/src/hb-atomic-private.hh +++ b/src/hb-atomic.hh @@ -29,10 +29,10 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_ATOMIC_PRIVATE_HH -#define HB_ATOMIC_PRIVATE_HH +#ifndef HB_ATOMIC_HH +#define HB_ATOMIC_HH -#include "hb-private.hh" +#include "hb.hh" /* @@ -49,17 +49,21 @@ /* Defined externally, i.e. in config.h. */ -#elif !defined(HB_NO_MT) && defined(__ATOMIC_CONSUME) +#elif !defined(HB_NO_MT) && defined(__ATOMIC_ACQUIRE) /* C++11-style GCC primitives. */ +#define _hb_memory_barrier() __sync_synchronize () + #define hb_atomic_int_impl_add(AI, V) __atomic_fetch_add ((AI), (V), __ATOMIC_ACQ_REL) #define hb_atomic_int_impl_set_relaxed(AI, V) __atomic_store_n ((AI), (V), __ATOMIC_RELAXED) +#define hb_atomic_int_impl_set(AI, V) __atomic_store_n ((AI), (V), __ATOMIC_RELEASE) #define hb_atomic_int_impl_get_relaxed(AI) __atomic_load_n ((AI), __ATOMIC_RELAXED) +#define hb_atomic_int_impl_get(AI) __atomic_load_n ((AI), __ATOMIC_ACQUIRE) #define hb_atomic_ptr_impl_set_relaxed(P, V) __atomic_store_n ((P), (V), __ATOMIC_RELAXED) #define hb_atomic_ptr_impl_get_relaxed(P) __atomic_load_n ((P), __ATOMIC_RELAXED) -#define hb_atomic_ptr_impl_get(P) __atomic_load_n ((P), __ATOMIC_CONSUME) +#define hb_atomic_ptr_impl_get(P) __atomic_load_n ((P), __ATOMIC_ACQUIRE) static inline bool _hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N) { @@ -74,13 +78,19 @@ _hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N) #include <atomic> +#define _hb_memory_barrier() std::atomic_thread_fence(std::memory_order_ack_rel) +#define _hb_memory_r_barrier() std::atomic_thread_fence(std::memory_order_acquire) +#define _hb_memory_w_barrier() std::atomic_thread_fence(std::memory_order_release) + #define hb_atomic_int_impl_add(AI, V) (reinterpret_cast<std::atomic<int> *> (AI)->fetch_add ((V), std::memory_order_acq_rel)) #define hb_atomic_int_impl_set_relaxed(AI, V) (reinterpret_cast<std::atomic<int> *> (AI)->store ((V), std::memory_order_relaxed)) +#define hb_atomic_int_impl_set(AI, V) (reinterpret_cast<std::atomic<int> *> (AI)->store ((V), std::memory_order_release)) #define hb_atomic_int_impl_get_relaxed(AI) (reinterpret_cast<std::atomic<int> *> (AI)->load (std::memory_order_relaxed)) +#define hb_atomic_int_impl_get(AI) (reinterpret_cast<std::atomic<int> *> (AI)->load (std::memory_order_acquire)) #define hb_atomic_ptr_impl_set_relaxed(P, V) (reinterpret_cast<std::atomic<void*> *> (P)->store ((V), std::memory_order_relaxed)) #define hb_atomic_ptr_impl_get_relaxed(P) (reinterpret_cast<std::atomic<void*> *> (P)->load (std::memory_order_relaxed)) -#define hb_atomic_ptr_impl_get(P) (reinterpret_cast<std::atomic<void*> *> (P)->load (std::memory_order_consume)) +#define hb_atomic_ptr_impl_get(P) (reinterpret_cast<std::atomic<void*> *> (P)->load (std::memory_order_acquire)) static inline bool _hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N) { @@ -98,7 +108,7 @@ static inline void _hb_memory_barrier (void) { #if !defined(MemoryBarrier) /* MinGW has a convoluted history of supporting MemoryBarrier. */ - long dummy = 0; + LONG dummy = 0; InterlockedExchange (&dummy, 1); #else MemoryBarrier (); @@ -106,9 +116,10 @@ static inline void _hb_memory_barrier (void) } #define _hb_memory_barrier() _hb_memory_barrier () -#define hb_atomic_int_impl_add(AI, V) InterlockedExchangeAdd ((unsigned *) (AI), (V)) +#define hb_atomic_int_impl_add(AI, V) InterlockedExchangeAdd ((LONG *) (AI), (V)) +static_assert ((sizeof (LONG) == sizeof (int)), ""); -#define hb_atomic_ptr_impl_cmpexch(P,O,N) (InterlockedCompareExchangePointer ((void **) (P), (void *) (N), (void *) (O)) == (void *) (O)) +#define hb_atomic_ptr_impl_cmpexch(P,O,N) (InterlockedCompareExchangePointer ((P), (N), (O)) == (O)) #elif !defined(HB_NO_MT) && defined(HAVE_INTEL_ATOMIC_PRIMITIVES) @@ -136,17 +147,17 @@ static inline int _hb_fetch_and_add (int *AI, int V) _hb_memory_r_barrier (); return result; } -static inline bool _hb_compare_and_swap_ptr (const void **P, const void *O, const void *N) +static inline bool _hb_compare_and_swap_ptr (void **P, void *O, void *N) { _hb_memory_w_barrier (); - int result = atomic_cas_ptr ((void **) P, (void *) O, (void *) N) == (void *) O; + bool result = atomic_cas_ptr (P, O, N) == O; _hb_memory_r_barrier (); return result; } #define hb_atomic_int_impl_add(AI, V) _hb_fetch_and_add ((AI), (V)) -#define hb_atomic_ptr_impl_cmpexch(P,O,N) _hb_compare_and_swap_ptr ((const void **) (P), (O), (N)) +#define hb_atomic_ptr_impl_cmpexch(P,O,N) _hb_compare_and_swap_ptr ((P), (O), (N)) #elif !defined(HB_NO_MT) && defined(__APPLE__) @@ -163,12 +174,12 @@ static inline bool _hb_compare_and_swap_ptr (const void **P, const void *O, cons #define hb_atomic_int_impl_add(AI, V) (OSAtomicAdd32Barrier ((V), (AI)) - (V)) #if (MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_4 || __IPHONE_VERSION_MIN_REQUIRED >= 20100) -#define hb_atomic_ptr_impl_cmpexch(P,O,N) OSAtomicCompareAndSwapPtrBarrier ((void *) (O), (void *) (N), (void **) (P)) +#define hb_atomic_ptr_impl_cmpexch(P,O,N) OSAtomicCompareAndSwapPtrBarrier ((O), (N), (P)) #else #if __ppc64__ || __x86_64__ || __aarch64__ -#define hb_atomic_ptr_impl_cmpexch(P,O,N) OSAtomicCompareAndSwap64Barrier ((int64_t) (void *) (O), (int64_t) (void *) (N), (int64_t*) (P)) +#define hb_atomic_ptr_impl_cmpexch(P,O,N) OSAtomicCompareAndSwap64Barrier ((int64_t) (O), (int64_t) (N), (int64_t*) (P)) #else -#define hb_atomic_ptr_impl_cmpexch(P,O,N) OSAtomicCompareAndSwap32Barrier ((int32_t) (void *) (O), (int32_t) (void *) (N), (int32_t*) (P)) +#define hb_atomic_ptr_impl_cmpexch(P,O,N) OSAtomicCompareAndSwap32Barrier ((int32_t) (O), (int32_t) (N), (int32_t*) (P)) #endif #endif @@ -242,6 +253,12 @@ static_assert ((sizeof (long) == sizeof (void *)), ""); #ifndef hb_atomic_ptr_impl_get_relaxed #define hb_atomic_ptr_impl_get_relaxed(P) (*(P)) #endif +#ifndef hb_atomic_int_impl_set +inline void hb_atomic_int_impl_set (int *AI, int v) { _hb_memory_w_barrier (); *AI = v; } +#endif +#ifndef hb_atomic_int_impl_get +inline int hb_atomic_int_impl_get (int *AI) { int v = *AI; _hb_memory_r_barrier (); return v; } +#endif #ifndef hb_atomic_ptr_impl_get inline void *hb_atomic_ptr_impl_get (void **P) { void *v = *P; _hb_memory_r_barrier (); return v; } #endif @@ -251,7 +268,9 @@ inline void *hb_atomic_ptr_impl_get (void **P) { void *v = *P; _hb_memory_r_barr struct hb_atomic_int_t { inline void set_relaxed (int v_) const { hb_atomic_int_impl_set_relaxed (&v, v_); } + inline void set (int v_) const { hb_atomic_int_impl_set (&v, v_); } inline int get_relaxed (void) const { return hb_atomic_int_impl_get_relaxed (&v); } + inline int get (void) const { return hb_atomic_int_impl_get (&v); } inline int inc (void) { return hb_atomic_int_impl_add (&v, 1); } inline int dec (void) { return hb_atomic_int_impl_add (&v, -1); } @@ -270,12 +289,12 @@ struct hb_atomic_ptr_t inline void init (T* v_ = nullptr) { set_relaxed (v_); } inline void set_relaxed (T* v_) const { hb_atomic_ptr_impl_set_relaxed (&v, v_); } - inline T *get_relaxed (void) const { return hb_atomic_ptr_impl_get_relaxed (&v); } + inline T *get_relaxed (void) const { return (T *) hb_atomic_ptr_impl_get_relaxed (&v); } inline T *get (void) const { return (T *) hb_atomic_ptr_impl_get ((void **) &v); } - inline bool cmpexch (const T *old, T *new_) const{ return hb_atomic_ptr_impl_cmpexch (&v, old, new_); } + inline bool cmpexch (const T *old, T *new_) const { return hb_atomic_ptr_impl_cmpexch ((void **) &v, (void *) old, (void *) new_); } mutable T *v; }; -#endif /* HB_ATOMIC_PRIVATE_HH */ +#endif /* HB_ATOMIC_HH */ diff --git a/src/hb-blob.cc b/src/hb-blob.cc index 25c3e05aa..368491c05 100644 --- a/src/hb-blob.cc +++ b/src/hb-blob.cc @@ -25,13 +25,8 @@ * Red Hat Author(s): Behdad Esfahbod */ -/* http://www.oracle.com/technetwork/articles/servers-storage-dev/standardheaderfiles-453865.html */ -#ifndef _POSIX_C_SOURCE -#define _POSIX_C_SOURCE 200809L -#endif - -#include "hb-private.hh" -#include "hb-blob-private.hh" +#include "hb.hh" +#include "hb-blob.hh" #ifdef HAVE_SYS_MMAN_H #ifdef HAVE_UNISTD_H @@ -293,6 +288,8 @@ hb_blob_make_immutable (hb_blob_t *blob) { if (hb_object_is_inert (blob)) return; + if (blob->immutable) + return; blob->immutable = true; } @@ -490,8 +487,8 @@ hb_blob_t::try_make_writable (void) #if defined(_WIN32) || defined(__CYGWIN__) # include <windows.h> #else -# ifndef _O_BINARY -# define _O_BINARY 0 +# ifndef O_BINARY +# define O_BINARY 0 # endif #endif @@ -510,8 +507,9 @@ struct hb_mapped_file_t #if (defined(HAVE_MMAP) || defined(_WIN32) || defined(__CYGWIN__)) && !defined(HB_NO_MMAP) static void -_hb_mapped_file_destroy (hb_mapped_file_t *file) +_hb_mapped_file_destroy (void *file_) { + hb_mapped_file_t *file = (hb_mapped_file_t *) file_; #ifdef HAVE_MMAP munmap (file->contents, file->length); #elif defined(_WIN32) || defined(__CYGWIN__) @@ -542,7 +540,7 @@ hb_blob_create_from_file (const char *file_name) hb_mapped_file_t *file = (hb_mapped_file_t *) calloc (1, sizeof (hb_mapped_file_t)); if (unlikely (!file)) return hb_blob_get_empty (); - int fd = open (file_name, O_RDONLY | _O_BINARY, 0); + int fd = open (file_name, O_RDONLY | O_BINARY, 0); if (unlikely (fd == -1)) goto fail_without_close; struct stat st; @@ -574,18 +572,45 @@ fail_without_close: wchar_t * wchar_file_name = (wchar_t *) malloc (sizeof (wchar_t) * size); if (unlikely (wchar_file_name == nullptr)) goto fail_without_close; mbstowcs (wchar_file_name, file_name, size); +#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP) + { + CREATEFILE2_EXTENDED_PARAMETERS ceparams = { 0 }; + ceparams.dwSize = sizeof(CREATEFILE2_EXTENDED_PARAMETERS); + ceparams.dwFileAttributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED & 0xFFFF; + ceparams.dwFileFlags = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED & 0xFFF00000; + ceparams.dwSecurityQosFlags = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED & 0x000F0000; + ceparams.lpSecurityAttributes = nullptr; + ceparams.hTemplateFile = nullptr; + fd = CreateFile2 (wchar_file_name, GENERIC_READ, FILE_SHARE_READ, + OPEN_EXISTING, &ceparams); + } +#else fd = CreateFileW (wchar_file_name, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, nullptr); +#endif free (wchar_file_name); if (unlikely (fd == INVALID_HANDLE_VALUE)) goto fail_without_close; +#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP) + { + LARGE_INTEGER length; + GetFileSizeEx (fd, &length); + file->length = length.LowPart; + file->mapping = CreateFileMappingFromApp (fd, nullptr, PAGE_READONLY, length.QuadPart, nullptr); + } +#else file->length = (unsigned long) GetFileSize (fd, nullptr); file->mapping = CreateFileMapping (fd, nullptr, PAGE_READONLY, 0, 0, nullptr); +#endif if (unlikely (file->mapping == nullptr)) goto fail; +#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP) + file->contents = (char *) MapViewOfFileFromApp (file->mapping, FILE_MAP_READ, 0, 0); +#else file->contents = (char *) MapViewOfFile (file->mapping, FILE_MAP_READ, 0, 0, 0); +#endif if (unlikely (file->contents == nullptr)) goto fail; CloseHandle (fd); diff --git a/src/hb-blob-private.hh b/src/hb-blob.hh index 49ad68ece..bee8c9794 100644 --- a/src/hb-blob-private.hh +++ b/src/hb-blob.hh @@ -26,10 +26,10 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_BLOB_PRIVATE_HH -#define HB_BLOB_PRIVATE_HH +#ifndef HB_BLOB_HH +#define HB_BLOB_HH -#include "hb-private.hh" +#include "hb.hh" /* @@ -62,6 +62,10 @@ struct hb_blob_t { return unlikely (!data) ? &Null(Type) : reinterpret_cast<const Type *> (data); } + inline hb_bytes_t as_bytes (void) const + { + return hb_bytes_t (data, length); + } public: hb_object_header_t header; @@ -79,4 +83,4 @@ struct hb_blob_t DECLARE_NULL_INSTANCE (hb_blob_t); -#endif /* HB_BLOB_PRIVATE_HH */ +#endif /* HB_BLOB_HH */ diff --git a/src/hb-buffer-deserialize-json.hh b/src/hb-buffer-deserialize-json.hh index 380f3c5fc..1f9e2e91d 100644 --- a/src/hb-buffer-deserialize-json.hh +++ b/src/hb-buffer-deserialize-json.hh @@ -29,7 +29,7 @@ #ifndef HB_BUFFER_DESERIALIZE_JSON_HH #define HB_BUFFER_DESERIALIZE_JSON_HH -#include "hb-private.hh" +#include "hb.hh" #line 36 "hb-buffer-deserialize-json.hh" diff --git a/src/hb-buffer-deserialize-json.rl b/src/hb-buffer-deserialize-json.rl index ec9bc7c9a..f3abb027b 100644 --- a/src/hb-buffer-deserialize-json.rl +++ b/src/hb-buffer-deserialize-json.rl @@ -27,7 +27,7 @@ #ifndef HB_BUFFER_DESERIALIZE_JSON_HH #define HB_BUFFER_DESERIALIZE_JSON_HH -#include "hb-private.hh" +#include "hb.hh" %%{ diff --git a/src/hb-buffer-deserialize-text.hh b/src/hb-buffer-deserialize-text.hh index 5bca369f8..67f0a1252 100644 --- a/src/hb-buffer-deserialize-text.hh +++ b/src/hb-buffer-deserialize-text.hh @@ -29,7 +29,7 @@ #ifndef HB_BUFFER_DESERIALIZE_TEXT_HH #define HB_BUFFER_DESERIALIZE_TEXT_HH -#include "hb-private.hh" +#include "hb.hh" #line 36 "hb-buffer-deserialize-text.hh" diff --git a/src/hb-buffer-deserialize-text.rl b/src/hb-buffer-deserialize-text.rl index 1d90979a9..6268a6c50 100644 --- a/src/hb-buffer-deserialize-text.rl +++ b/src/hb-buffer-deserialize-text.rl @@ -27,7 +27,7 @@ #ifndef HB_BUFFER_DESERIALIZE_TEXT_HH #define HB_BUFFER_DESERIALIZE_TEXT_HH -#include "hb-private.hh" +#include "hb.hh" %%{ diff --git a/src/hb-buffer-serialize.cc b/src/hb-buffer-serialize.cc index 11471941d..c1d82ab8d 100644 --- a/src/hb-buffer-serialize.cc +++ b/src/hb-buffer-serialize.cc @@ -24,7 +24,7 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-buffer-private.hh" +#include "hb-buffer.hh" static const char *serialize_formats[] = { @@ -440,8 +440,8 @@ hb_bool_t hb_buffer_deserialize_glyphs (hb_buffer_t *buffer, const char *buf, int buf_len, /* -1 means nul-terminated */ - const char **end_ptr, /* May be nullptr */ - hb_font_t *font, /* May be nullptr */ + const char **end_ptr, /* May be NULL */ + hb_font_t *font, /* May be NULL */ hb_buffer_serialize_format_t format) { const char *end; diff --git a/src/hb-buffer.cc b/src/hb-buffer.cc index eb7b01caa..ce9b0530c 100644 --- a/src/hb-buffer.cc +++ b/src/hb-buffer.cc @@ -27,8 +27,8 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-buffer-private.hh" -#include "hb-utf-private.hh" +#include "hb-buffer.hh" +#include "hb-utf.hh" /** @@ -182,7 +182,11 @@ hb_buffer_t::shift_forward (unsigned int count) if (idx + count > len) { /* Under memory failure we might expose this area. At least - * clean it up. Oh well... */ + * clean it up. Oh well... + * + * Ideally, we should at least set Default_Ignorable bits on + * these, as well as consistent cluster values. But the former + * is layering violation... */ memset (info + len, 0, (idx + count - len) * sizeof (info[0])); } len += count; @@ -219,6 +223,7 @@ hb_buffer_t::reset (void) unicode = hb_unicode_funcs_reference (hb_unicode_funcs_get_default ()); flags = HB_BUFFER_FLAG_DEFAULT; replacement = HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT; + invisible = 0; clear (); } @@ -354,6 +359,8 @@ hb_buffer_t::replace_glyphs (unsigned int num_in, { if (unlikely (!make_room_for (num_in, num_out))) return; + assert (idx + num_in <= len); + merge_clusters (idx, idx + num_in); hb_glyph_info_t orig_info = info[idx]; @@ -369,37 +376,6 @@ hb_buffer_t::replace_glyphs (unsigned int num_in, out_len += num_out; } -void -hb_buffer_t::output_glyph (hb_codepoint_t glyph_index) -{ - if (unlikely (!make_room_for (0, 1))) return; - - out_info[out_len] = info[idx]; - out_info[out_len].codepoint = glyph_index; - - out_len++; -} - -void -hb_buffer_t::output_info (const hb_glyph_info_t &glyph_info) -{ - if (unlikely (!make_room_for (0, 1))) return; - - out_info[out_len] = glyph_info; - - out_len++; -} - -void -hb_buffer_t::copy_glyph (void) -{ - if (unlikely (!make_room_for (0, 1))) return; - - out_info[out_len] = info[idx]; - - out_len++; -} - bool hb_buffer_t::move_to (unsigned int i) { @@ -429,8 +405,14 @@ hb_buffer_t::move_to (unsigned int i) unsigned int count = out_len - i; /* This will blow in our face if memory allocation fails later - * in this same lookup... */ - if (unlikely (idx < count && !shift_forward (count + 32))) return false; + * in this same lookup... + * + * We used to shift with extra 32 items, instead of the 0 below. + * But that would leave empty slots in the buffer in case of allocation + * failures. Setting to zero for now to avoid other problems (see + * comments in shift_forward(). This can cause O(N^2) behavior more + * severely than adding 32 empty slots can... */ + if (unlikely (idx < count && !shift_forward (count + 0))) return false; assert (idx >= count); @@ -442,19 +424,6 @@ hb_buffer_t::move_to (unsigned int i) return true; } -void -hb_buffer_t::replace_glyph (hb_codepoint_t glyph_index) -{ - if (unlikely (out_info != info || out_len != idx)) { - if (unlikely (!make_room_for (1, 1))) return; - out_info[out_len] = info[idx]; - } - out_info[out_len].codepoint = glyph_index; - - idx++; - out_len++; -} - void hb_buffer_t::set_masks (hb_mask_t value, @@ -709,6 +678,7 @@ DEFINE_NULL_INSTANCE (hb_buffer_t) = HB_BUFFER_FLAG_DEFAULT, HB_BUFFER_CLUSTER_LEVEL_DEFAULT, HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT, + 0, /* invisible */ HB_BUFFER_SCRATCH_FLAG_DEFAULT, HB_BUFFER_MAX_LEN_DEFAULT, HB_BUFFER_MAX_OPS_DEFAULT, @@ -1028,7 +998,7 @@ hb_buffer_get_script (hb_buffer_t *buffer) * are orthogonal to the scripts, and though they are related, they are * different concepts and should not be confused with each other. * - * Use hb_language_from_string() to convert from ISO 639 language codes to + * Use hb_language_from_string() to convert from BCP 47 language tags to * #hb_language_t. * * Since: 0.9.2 @@ -1211,6 +1181,46 @@ hb_buffer_get_replacement_codepoint (hb_buffer_t *buffer) /** + * hb_buffer_set_invisible_glyph: + * @buffer: an #hb_buffer_t. + * @invisible: the invisible #hb_codepoint_t + * + * Sets the #hb_codepoint_t that replaces invisible characters in + * the shaping result. If set to zero (default), the glyph for the + * U+0020 SPACE character is used. Otherwise, this value is used + * verbatim. + * + * Since: 2.0.0 + **/ +void +hb_buffer_set_invisible_glyph (hb_buffer_t *buffer, + hb_codepoint_t invisible) +{ + if (unlikely (hb_object_is_inert (buffer))) + return; + + buffer->invisible = invisible; +} + +/** + * hb_buffer_get_invisible_glyph: + * @buffer: an #hb_buffer_t. + * + * See hb_buffer_set_invisible_glyph(). + * + * Return value: + * The @buffer invisible #hb_codepoint_t. + * + * Since: 2.0.0 + **/ +hb_codepoint_t +hb_buffer_get_invisible_glyph (hb_buffer_t *buffer) +{ + return buffer->invisible; +} + + +/** * hb_buffer_reset: * @buffer: an #hb_buffer_t. * @@ -1499,6 +1509,8 @@ hb_buffer_reverse_clusters (hb_buffer_t *buffer) * it will be set to the process's default language as returned by * hb_language_get_default(). This may change in the future by * taking buffer script into consideration when choosing a language. + * Note that hb_language_get_default() is NOT threadsafe the first time + * it is called. See documentation for that function for details. * * Since: 0.9.7 **/ @@ -1887,6 +1899,10 @@ hb_buffer_t::sort (unsigned int start, unsigned int end, int(*compar)(const hb_g /** * hb_buffer_diff: + * @buffer: a buffer. + * @reference: other buffer to compare to. + * @dottedcircle_glyph: glyph id of U+25CC DOTTED CIRCLE, or (hb_codepont_t) -1. + * @position_fuzz: allowed absolute difference in position values. * * If dottedcircle_glyph is (hb_codepoint_t) -1 then %HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT * and %HB_BUFFER_DIFF_FLAG_NOTDEF_PRESENT are never returned. This should be used by most diff --git a/src/hb-buffer.h b/src/hb-buffer.h index 8a2d3e869..d0aed02d5 100644 --- a/src/hb-buffer.h +++ b/src/hb-buffer.h @@ -44,7 +44,6 @@ HB_BEGIN_DECLS * hb_glyph_info_t: * @codepoint: either a Unicode code point (before shaping) or a glyph index * (after shaping). - * @mask: * @cluster: the index of the character in the original text that corresponds * to this #hb_glyph_info_t, or whatever the client passes to * hb_buffer_add(). More than one #hb_glyph_info_t can have the same @@ -59,11 +58,13 @@ HB_BEGIN_DECLS * * The #hb_glyph_info_t is the structure that holds information about the * glyphs and their relation to input text. - * */ -typedef struct hb_glyph_info_t { +typedef struct hb_glyph_info_t +{ hb_codepoint_t codepoint; - hb_mask_t mask; /* Holds hb_glyph_flags_t after hb_shape(), plus other things. */ + /*< private >*/ + hb_mask_t mask; + /*< public >*/ uint32_t cluster; /*< private >*/ @@ -92,7 +93,7 @@ typedef struct hb_glyph_info_t { typedef enum { /*< flags >*/ HB_GLYPH_FLAG_UNSAFE_TO_BREAK = 0x00000001, - HB_GLYPH_FLAG_DEFINED = 0x00000001 /* OR of all defined flags */ + HB_GLYPH_FLAG_DEFINED = 0x00000001 /*< skip >*/ /* OR of all defined flags */ } hb_glyph_flags_t; HB_EXTERN hb_glyph_flags_t @@ -298,7 +299,15 @@ hb_buffer_set_flags (hb_buffer_t *buffer, HB_EXTERN hb_buffer_flags_t hb_buffer_get_flags (hb_buffer_t *buffer); -/* +/** + * hb_buffer_cluster_level_t: + * @HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES: Return cluster values grouped by graphemes into + * monotone order. + * @HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS: Return cluster values grouped into monotone order. + * @HB_BUFFER_CLUSTER_LEVEL_CHARACTERS: Don't group cluster values. + * @HB_BUFFER_CLUSTER_LEVEL_DEFAULT: Default cluster level, + * equal to @HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES. + * * Since: 0.9.42 */ typedef enum { @@ -332,6 +341,13 @@ hb_buffer_set_replacement_codepoint (hb_buffer_t *buffer, HB_EXTERN hb_codepoint_t hb_buffer_get_replacement_codepoint (hb_buffer_t *buffer); +HB_EXTERN void +hb_buffer_set_invisible_glyph (hb_buffer_t *buffer, + hb_codepoint_t invisible); + +HB_EXTERN hb_codepoint_t +hb_buffer_get_invisible_glyph (hb_buffer_t *buffer); + HB_EXTERN void hb_buffer_reset (hb_buffer_t *buffer); diff --git a/src/hb-buffer-private.hh b/src/hb-buffer.hh index a6c4b6963..0d888e1e0 100644 --- a/src/hb-buffer-private.hh +++ b/src/hb-buffer.hh @@ -27,11 +27,11 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_BUFFER_PRIVATE_HH -#define HB_BUFFER_PRIVATE_HH +#ifndef HB_BUFFER_HH +#define HB_BUFFER_HH -#include "hb-private.hh" -#include "hb-unicode-private.hh" +#include "hb.hh" +#include "hb-unicode.hh" #ifndef HB_BUFFER_MAX_LEN_FACTOR @@ -93,6 +93,7 @@ struct hb_buffer_t hb_buffer_flags_t flags; /* BOT / EOT / etc. */ hb_buffer_cluster_level_t cluster_level; hb_codepoint_t replacement; /* U+FFFD or something else. */ + hb_codepoint_t invisible; /* 0 or something else. */ hb_buffer_scratch_flags_t scratch_flags; /* Have space-fallback, etc. */ unsigned int max_len; /* Maximum allowed len. */ int max_ops; /* Maximum allowed operations. */ @@ -119,7 +120,7 @@ struct hb_buffer_t /* Text before / after the main buffer contents. * Always in Unicode, and ordered outward. * Index 0 is for "pre-context", 1 for "post-context". */ - static const unsigned int CONTEXT_LENGTH = 5; + enum { CONTEXT_LENGTH = 5 }; hb_codepoint_t context[2][CONTEXT_LENGTH]; unsigned int context_len[2]; @@ -212,13 +213,49 @@ struct hb_buffer_t unsigned int num_out, const hb_codepoint_t *glyph_data); - HB_INTERNAL void replace_glyph (hb_codepoint_t glyph_index); + inline void replace_glyph (hb_codepoint_t glyph_index) + { + if (unlikely (out_info != info || out_len != idx)) { + if (unlikely (!make_room_for (1, 1))) return; + out_info[out_len] = info[idx]; + } + out_info[out_len].codepoint = glyph_index; + + idx++; + out_len++; + } /* Makes a copy of the glyph at idx to output and replace glyph_index */ - HB_INTERNAL void output_glyph (hb_codepoint_t glyph_index); - HB_INTERNAL void output_info (const hb_glyph_info_t &glyph_info); + inline hb_glyph_info_t & output_glyph (hb_codepoint_t glyph_index) + { + if (unlikely (!make_room_for (0, 1))) return Crap(hb_glyph_info_t); + + if (unlikely (idx == len && !out_len)) + return Crap(hb_glyph_info_t); + + out_info[out_len] = idx < len ? info[idx] : out_info[out_len - 1]; + out_info[out_len].codepoint = glyph_index; + + out_len++; + + return out_info[out_len - 1]; + } + inline void output_info (const hb_glyph_info_t &glyph_info) + { + if (unlikely (!make_room_for (0, 1))) return; + + out_info[out_len] = glyph_info; + + out_len++; + } /* Copies glyph at idx to output but doesn't advance idx */ - HB_INTERNAL void copy_glyph (void); - HB_INTERNAL bool move_to (unsigned int i); /* i is output-buffer index. */ + inline void copy_glyph (void) + { + if (unlikely (!make_room_for (0, 1))) return; + + out_info[out_len] = info[idx]; + + out_len++; + } /* Copies glyph at idx to output and advance idx. * If there's no output, just advance idx. */ inline void @@ -226,7 +263,8 @@ struct hb_buffer_t { if (have_output) { - if (unlikely (out_info != info || out_len != idx)) { + if (out_info != info || out_len != idx) + { if (unlikely (!make_room_for (1, 1))) return; out_info[out_len] = info[idx]; } @@ -235,10 +273,28 @@ struct hb_buffer_t idx++; } + /* Copies n glyphs at idx to output and advance idx. + * If there's no output, just advance idx. */ + inline void + next_glyphs (unsigned int n) + { + if (have_output) + { + if (out_info != info || out_len != idx) + { + if (unlikely (!make_room_for (n, n))) return; + memmove (out_info + out_len, info + idx, n * sizeof (out_info[0])); + } + out_len += n; + } + idx += n; + } /* Advance idx without copying to output. */ - inline void skip_glyph (void) { idx++; } - + inline void skip_glyph (void) + { + idx++; + } inline void reset_masks (hb_mask_t mask) { for (unsigned int j = 0; j < len; j++) @@ -275,6 +331,8 @@ struct hb_buffer_t /* Internal methods */ + HB_INTERNAL bool move_to (unsigned int i); /* i is output-buffer index. */ + HB_INTERNAL bool enlarge (unsigned int size); inline bool ensure (unsigned int size) @@ -386,4 +444,4 @@ _next_cluster (hb_buffer_t *buffer, unsigned int start) #define HB_BUFFER_ASSERT_VAR(b, var) HB_BUFFER_XALLOCATE_VAR (b, assert_var, var ()) -#endif /* HB_BUFFER_PRIVATE_HH */ +#endif /* HB_BUFFER_HH */ diff --git a/src/hb-cache.hh b/src/hb-cache.hh new file mode 100644 index 000000000..eb48f18cf --- /dev/null +++ b/src/hb-cache.hh @@ -0,0 +1,80 @@ +/* + * Copyright © 2012 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Behdad Esfahbod + */ + +#ifndef HB_CACHE_HH +#define HB_CACHE_HH + +#include "hb.hh" + + +/* Implements a lock-free cache for int->int functions. */ + +template <unsigned int key_bits, unsigned int value_bits, unsigned int cache_bits> +struct hb_cache_t +{ + static_assert ((key_bits >= cache_bits), ""); + static_assert ((key_bits + value_bits - cache_bits <= 8 * sizeof (hb_atomic_int_t)), ""); + static_assert (sizeof (hb_atomic_int_t) == sizeof (unsigned int), ""); + + inline void init (void) { clear (); } + inline void fini (void) {} + + inline void clear (void) + { + for (unsigned i = 0; i < ARRAY_LENGTH (values); i++) + values[i].set_relaxed (-1); + } + + inline bool get (unsigned int key, unsigned int *value) const + { + unsigned int k = key & ((1u<<cache_bits)-1); + unsigned int v = values[k].get_relaxed (); + if ((key_bits + value_bits - cache_bits == 8 * sizeof (hb_atomic_int_t) && v == (unsigned int) -1) || + (v >> value_bits) != (key >> cache_bits)) + return false; + *value = v & ((1u<<value_bits)-1); + return true; + } + + inline bool set (unsigned int key, unsigned int value) + { + if (unlikely ((key >> key_bits) || (value >> value_bits))) + return false; /* Overflows */ + unsigned int k = key & ((1u<<cache_bits)-1); + unsigned int v = ((key>>cache_bits)<<value_bits) | value; + values[k].set_relaxed (v); + return true; + } + + private: + hb_atomic_int_t values[1u<<cache_bits]; +}; + +typedef hb_cache_t<21, 16, 8> hb_cmap_cache_t; +typedef hb_cache_t<16, 24, 8> hb_advance_cache_t; + + +#endif /* HB_CACHE_HH */ diff --git a/src/hb-common.cc b/src/hb-common.cc index 22dd52f49..ba48dd561 100644 --- a/src/hb-common.cc +++ b/src/hb-common.cc @@ -26,9 +26,9 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-private.hh" +#include "hb.hh" -#include "hb-machinery-private.hh" +#include "hb-machinery.hh" #include <locale.h> #ifdef HAVE_XLOCALE_H @@ -45,10 +45,29 @@ _hb_options_init (void) { hb_options_union_t u; u.i = 0; - u.opts.initialized = 1; + u.opts.initialized = true; - char *c = getenv ("HB_OPTIONS"); - u.opts.uniscribe_bug_compatible = c && strstr (c, "uniscribe-bug-compatible"); + const char *c = getenv ("HB_OPTIONS"); + if (c) + { + while (*c) + { + const char *p = strchr (c, ':'); + if (!p) + p = c + strlen (c); + +#define OPTION(name, symbol) \ + if (0 == strncmp (c, name, p - c) && strlen (name) == p - c) u.opts.symbol = true; + + OPTION ("uniscribe-bug-compatible", uniscribe_bug_compatible); + OPTION ("aat", aat); + +#undef OPTION + + c = *p ? p + 1 : p; + } + + } /* This is idempotent and threadsafe. */ _hb_options.set_relaxed (u.i); @@ -306,14 +325,14 @@ retry: /** * hb_language_from_string: * @str: (array length=len) (element-type uint8_t): a string representing - * ISO 639 language code + * a BCP 47 language tag * @len: length of the @str, or -1 if it is %NULL-terminated. * - * Converts @str representing an ISO 639 language code to the corresponding + * Converts @str representing a BCP 47 language tag to the corresponding * #hb_language_t. * * Return value: (transfer none): - * The #hb_language_t corresponding to the ISO 639 language code. + * The #hb_language_t corresponding to the BCP 47 language tag. * * Since: 0.9.2 **/ @@ -361,7 +380,14 @@ hb_language_to_string (hb_language_t language) /** * hb_language_get_default: * + * Get default language from current locale. * + * Note that the first time this function is called, it calls + * "setlocale (LC_CTYPE, nullptr)" to fetch current locale. The underlying + * setlocale function is, in many implementations, NOT threadsafe. To avoid + * problems, call this function once before multiple threads can call it. + * This function is only used from hb_buffer_guess_segment_properties() by + * HarfBuzz itself. * * Return value: (transfer none): * @@ -531,7 +557,6 @@ hb_script_get_horizontal_direction (hb_script_t script) /* Unicode-8.0 additions */ case HB_SCRIPT_HATRAN: - case HB_SCRIPT_OLD_HUNGARIAN: /* Unicode-9.0 additions */ case HB_SCRIPT_ADLAM: @@ -545,6 +570,7 @@ hb_script_get_horizontal_direction (hb_script_t script) /* https://github.com/harfbuzz/harfbuzz/issues/1000 */ + case HB_SCRIPT_OLD_HUNGARIAN: case HB_SCRIPT_OLD_ITALIC: case HB_SCRIPT_RUNIC: @@ -731,8 +757,9 @@ parse_uint32 (const char **pp, const char *end, uint32_t *pv) #ifdef USE_XLOCALE - +#ifdef HB_USE_ATEXIT static void free_static_C_locale (void); +#endif static struct hb_C_locale_lazy_loader_t : hb_lazy_loader_t<hb_remove_ptr_t<HB_LOCALE_T>::value, hb_C_locale_lazy_loader_t> @@ -876,8 +903,8 @@ parse_feature_indices (const char **pp, const char *end, hb_feature_t *feature) bool has_start; - feature->start = 0; - feature->end = (unsigned int) -1; + feature->start = HB_FEATURE_GLOBAL_START; + feature->end = HB_FEATURE_GLOBAL_END; if (!parse_char (pp, end, '[')) return true; @@ -1064,7 +1091,7 @@ 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", variation->value)); + len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%g", (double) variation->value)); assert (len < ARRAY_LENGTH (s)); len = MIN (len, size - 1); diff --git a/src/hb-common.h b/src/hb-common.h index 5dc1ebcd2..2f09f4318 100644 --- a/src/hb-common.h +++ b/src/hb-common.h @@ -63,6 +63,23 @@ typedef unsigned __int64 uint64_t; # include <stdint.h> #endif +#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1) +#define HB_DEPRECATED __attribute__((__deprecated__)) +#elif defined(_MSC_VER) && (_MSC_VER >= 1300) +#define HB_DEPRECATED __declspec(deprecated) +#else +#define HB_DEPRECATED +#endif + +#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) +#define HB_DEPRECATED_FOR(f) __attribute__((__deprecated__("Use '" #f "' instead"))) +#elif defined(_MSC_FULL_VER) && (_MSC_FULL_VER > 140050320) +#define HB_DEPRECATED_FOR(f) __declspec(deprecated("is deprecated. Use '" #f "' instead")) +#else +#define HB_DEPRECATED_FOR(f) HB_DEPRECATED +#endif + + HB_BEGIN_DECLS @@ -86,8 +103,8 @@ typedef union _hb_var_int_t { typedef uint32_t hb_tag_t; -#define HB_TAG(c1,c2,c3,c4) ((hb_tag_t)((((uint8_t)(c1))<<24)|(((uint8_t)(c2))<<16)|(((uint8_t)(c3))<<8)|((uint8_t)(c4)))) -#define HB_UNTAG(tag) ((uint8_t)((tag)>>24)), ((uint8_t)((tag)>>16)), ((uint8_t)((tag)>>8)), ((uint8_t)(tag)) +#define HB_TAG(c1,c2,c3,c4) ((hb_tag_t)((((uint32_t)(c1)&0xFF)<<24)|(((uint32_t)(c2)&0xFF)<<16)|(((uint32_t)(c3)&0xFF)<<8)|((uint32_t)(c4)&0xFF))) +#define HB_UNTAG(tag) (((tag)>>24)&0xFF), (((tag)>>16)&0xFF), (((tag)>>8)&0xFF), ((tag)&0xFF) #define HB_TAG_NONE HB_TAG(0,0,0,0) #define HB_TAG_MAX HB_TAG(0xff,0xff,0xff,0xff) @@ -340,13 +357,15 @@ typedef enum HB_SCRIPT_INVALID = HB_TAG_NONE, /* Dummy values to ensure any hb_tag_t value can be passed/stored as hb_script_t - * without risking undefined behavior. Include both a signed and unsigned max, - * since technically enums are int, and indeed, hb_script_t ends up being signed. + * without risking undefined behavior. We have two, for historical reasons. + * HB_TAG_MAX used to be unsigned, but that was invalid Ansi C, so was changed + * to _HB_SCRIPT_MAX_VALUE to be equal to HB_TAG_MAX_SIGNED as well. + * * See this thread for technicalities: * * https://lists.freedesktop.org/archives/harfbuzz/2014-March/004150.html */ - _HB_SCRIPT_MAX_VALUE = HB_TAG_MAX, /*< skip >*/ + _HB_SCRIPT_MAX_VALUE = HB_TAG_MAX_SIGNED, /*< skip >*/ _HB_SCRIPT_MAX_VALUE_SIGNED = HB_TAG_MAX_SIGNED /*< skip >*/ } hb_script_t; @@ -379,6 +398,19 @@ typedef void (*hb_destroy_func_t) (void *user_data); /* Font features and variations. */ +/** + * HB_FEATURE_GLOBAL_START + * + * Since: 2.0.0 + */ +#define HB_FEATURE_GLOBAL_START 0 +/** + * HB_FEATURE_GLOBAL_END + * + * Since: 2.0.0 + */ +#define HB_FEATURE_GLOBAL_END ((unsigned int) -1) + typedef struct hb_feature_t { hb_tag_t tag; uint32_t value; diff --git a/src/hb-coretext.cc b/src/hb-coretext.cc index 1b916a53d..9f7745dbf 100644 --- a/src/hb-coretext.cc +++ b/src/hb-coretext.cc @@ -28,10 +28,11 @@ #define HB_SHAPER coretext -#include "hb-private.hh" -#include "hb-shaper-impl-private.hh" +#include "hb.hh" +#include "hb-shaper-impl.hh" #include "hb-coretext.h" +#include "hb-aat-layout.hh" #include <math.h> /* https://developer.apple.com/documentation/coretext/1508745-ctfontcreatewithgraphicsfont */ @@ -210,7 +211,7 @@ create_ct_font (CGFontRef cg_font, CGFloat font_size) } CFURLRef original_url = nullptr; -#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060 +#if TARGET_OS_OSX && MAC_OS_X_VERSION_MIN_REQUIRED < 1060 ATSFontRef atsFont; FSRef fsref; OSStatus status; @@ -240,7 +241,7 @@ create_ct_font (CGFontRef cg_font, CGFloat font_size) * process in Blink. This can be detected by the new file URL location * that the newly found font points to. */ CFURLRef new_url = nullptr; -#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060 +#if TARGET_OS_OSX && MAC_OS_X_VERSION_MIN_REQUIRED < 1060 atsFont = CTFontGetPlatformFont (new_ct_font, NULL); status = ATSFontGetFileReference (atsFont, &fsref); if (status == noErr) @@ -431,183 +432,6 @@ struct range_record_t { }; -/* The following enum members are added in OS X 10.8. */ -#define kAltHalfWidthTextSelector 6 -#define kAltProportionalTextSelector 5 -#define kAlternateHorizKanaOffSelector 1 -#define kAlternateHorizKanaOnSelector 0 -#define kAlternateKanaType 34 -#define kAlternateVertKanaOffSelector 3 -#define kAlternateVertKanaOnSelector 2 -#define kCaseSensitiveLayoutOffSelector 1 -#define kCaseSensitiveLayoutOnSelector 0 -#define kCaseSensitiveLayoutType 33 -#define kCaseSensitiveSpacingOffSelector 3 -#define kCaseSensitiveSpacingOnSelector 2 -#define kContextualAlternatesOffSelector 1 -#define kContextualAlternatesOnSelector 0 -#define kContextualAlternatesType 36 -#define kContextualLigaturesOffSelector 19 -#define kContextualLigaturesOnSelector 18 -#define kContextualSwashAlternatesOffSelector 5 -#define kContextualSwashAlternatesOnSelector 4 -#define kDefaultLowerCaseSelector 0 -#define kDefaultUpperCaseSelector 0 -#define kHistoricalLigaturesOffSelector 21 -#define kHistoricalLigaturesOnSelector 20 -#define kHojoCharactersSelector 12 -#define kJIS2004CharactersSelector 11 -#define kLowerCasePetiteCapsSelector 2 -#define kLowerCaseSmallCapsSelector 1 -#define kLowerCaseType 37 -#define kMathematicalGreekOffSelector 11 -#define kMathematicalGreekOnSelector 10 -#define kNLCCharactersSelector 13 -#define kQuarterWidthTextSelector 4 -#define kScientificInferiorsSelector 4 -#define kStylisticAltEightOffSelector 17 -#define kStylisticAltEightOnSelector 16 -#define kStylisticAltEighteenOffSelector 37 -#define kStylisticAltEighteenOnSelector 36 -#define kStylisticAltElevenOffSelector 23 -#define kStylisticAltElevenOnSelector 22 -#define kStylisticAltFifteenOffSelector 31 -#define kStylisticAltFifteenOnSelector 30 -#define kStylisticAltFiveOffSelector 11 -#define kStylisticAltFiveOnSelector 10 -#define kStylisticAltFourOffSelector 9 -#define kStylisticAltFourOnSelector 8 -#define kStylisticAltFourteenOffSelector 29 -#define kStylisticAltFourteenOnSelector 28 -#define kStylisticAltNineOffSelector 19 -#define kStylisticAltNineOnSelector 18 -#define kStylisticAltNineteenOffSelector 39 -#define kStylisticAltNineteenOnSelector 38 -#define kStylisticAltOneOffSelector 3 -#define kStylisticAltOneOnSelector 2 -#define kStylisticAltSevenOffSelector 15 -#define kStylisticAltSevenOnSelector 14 -#define kStylisticAltSeventeenOffSelector 35 -#define kStylisticAltSeventeenOnSelector 34 -#define kStylisticAltSixOffSelector 13 -#define kStylisticAltSixOnSelector 12 -#define kStylisticAltSixteenOffSelector 33 -#define kStylisticAltSixteenOnSelector 32 -#define kStylisticAltTenOffSelector 21 -#define kStylisticAltTenOnSelector 20 -#define kStylisticAltThirteenOffSelector 27 -#define kStylisticAltThirteenOnSelector 26 -#define kStylisticAltThreeOffSelector 7 -#define kStylisticAltThreeOnSelector 6 -#define kStylisticAltTwelveOffSelector 25 -#define kStylisticAltTwelveOnSelector 24 -#define kStylisticAltTwentyOffSelector 41 -#define kStylisticAltTwentyOnSelector 40 -#define kStylisticAltTwoOffSelector 5 -#define kStylisticAltTwoOnSelector 4 -#define kStylisticAlternativesType 35 -#define kSwashAlternatesOffSelector 3 -#define kSwashAlternatesOnSelector 2 -#define kThirdWidthTextSelector 3 -#define kTraditionalNamesCharactersSelector 14 -#define kUpperCasePetiteCapsSelector 2 -#define kUpperCaseSmallCapsSelector 1 -#define kUpperCaseType 38 - -/* Table data courtesy of Apple. */ -static const struct feature_mapping_t { - FourCharCode otFeatureTag; - uint16_t aatFeatureType; - uint16_t selectorToEnable; - uint16_t selectorToDisable; -} feature_mappings[] = { - { 'c2pc', kUpperCaseType, kUpperCasePetiteCapsSelector, kDefaultUpperCaseSelector }, - { 'c2sc', kUpperCaseType, kUpperCaseSmallCapsSelector, kDefaultUpperCaseSelector }, - { 'calt', kContextualAlternatesType, kContextualAlternatesOnSelector, kContextualAlternatesOffSelector }, - { 'case', kCaseSensitiveLayoutType, kCaseSensitiveLayoutOnSelector, kCaseSensitiveLayoutOffSelector }, - { 'clig', kLigaturesType, kContextualLigaturesOnSelector, kContextualLigaturesOffSelector }, - { 'cpsp', kCaseSensitiveLayoutType, kCaseSensitiveSpacingOnSelector, kCaseSensitiveSpacingOffSelector }, - { 'cswh', kContextualAlternatesType, kContextualSwashAlternatesOnSelector, kContextualSwashAlternatesOffSelector }, - { 'dlig', kLigaturesType, kRareLigaturesOnSelector, kRareLigaturesOffSelector }, - { 'expt', kCharacterShapeType, kExpertCharactersSelector, 16 }, - { 'frac', kFractionsType, kDiagonalFractionsSelector, kNoFractionsSelector }, - { 'fwid', kTextSpacingType, kMonospacedTextSelector, 7 }, - { 'halt', kTextSpacingType, kAltHalfWidthTextSelector, 7 }, - { 'hist', kLigaturesType, kHistoricalLigaturesOnSelector, kHistoricalLigaturesOffSelector }, - { 'hkna', kAlternateKanaType, kAlternateHorizKanaOnSelector, kAlternateHorizKanaOffSelector, }, - { 'hlig', kLigaturesType, kHistoricalLigaturesOnSelector, kHistoricalLigaturesOffSelector }, - { 'hngl', kTransliterationType, kHanjaToHangulSelector, kNoTransliterationSelector }, - { 'hojo', kCharacterShapeType, kHojoCharactersSelector, 16 }, - { 'hwid', kTextSpacingType, kHalfWidthTextSelector, 7 }, - { 'ital', kItalicCJKRomanType, kCJKItalicRomanOnSelector, kCJKItalicRomanOffSelector }, - { 'jp04', kCharacterShapeType, kJIS2004CharactersSelector, 16 }, - { 'jp78', kCharacterShapeType, kJIS1978CharactersSelector, 16 }, - { 'jp83', kCharacterShapeType, kJIS1983CharactersSelector, 16 }, - { 'jp90', kCharacterShapeType, kJIS1990CharactersSelector, 16 }, - { 'liga', kLigaturesType, kCommonLigaturesOnSelector, kCommonLigaturesOffSelector }, - { 'lnum', kNumberCaseType, kUpperCaseNumbersSelector, 2 }, - { 'mgrk', kMathematicalExtrasType, kMathematicalGreekOnSelector, kMathematicalGreekOffSelector }, - { 'nlck', kCharacterShapeType, kNLCCharactersSelector, 16 }, - { 'onum', kNumberCaseType, kLowerCaseNumbersSelector, 2 }, - { 'ordn', kVerticalPositionType, kOrdinalsSelector, kNormalPositionSelector }, - { 'palt', kTextSpacingType, kAltProportionalTextSelector, 7 }, - { 'pcap', kLowerCaseType, kLowerCasePetiteCapsSelector, kDefaultLowerCaseSelector }, - { 'pkna', kTextSpacingType, kProportionalTextSelector, 7 }, - { 'pnum', kNumberSpacingType, kProportionalNumbersSelector, 4 }, - { 'pwid', kTextSpacingType, kProportionalTextSelector, 7 }, - { 'qwid', kTextSpacingType, kQuarterWidthTextSelector, 7 }, - { 'ruby', kRubyKanaType, kRubyKanaOnSelector, kRubyKanaOffSelector }, - { 'sinf', kVerticalPositionType, kScientificInferiorsSelector, kNormalPositionSelector }, - { 'smcp', kLowerCaseType, kLowerCaseSmallCapsSelector, kDefaultLowerCaseSelector }, - { 'smpl', kCharacterShapeType, kSimplifiedCharactersSelector, 16 }, - { 'ss01', kStylisticAlternativesType, kStylisticAltOneOnSelector, kStylisticAltOneOffSelector }, - { 'ss02', kStylisticAlternativesType, kStylisticAltTwoOnSelector, kStylisticAltTwoOffSelector }, - { 'ss03', kStylisticAlternativesType, kStylisticAltThreeOnSelector, kStylisticAltThreeOffSelector }, - { 'ss04', kStylisticAlternativesType, kStylisticAltFourOnSelector, kStylisticAltFourOffSelector }, - { 'ss05', kStylisticAlternativesType, kStylisticAltFiveOnSelector, kStylisticAltFiveOffSelector }, - { 'ss06', kStylisticAlternativesType, kStylisticAltSixOnSelector, kStylisticAltSixOffSelector }, - { 'ss07', kStylisticAlternativesType, kStylisticAltSevenOnSelector, kStylisticAltSevenOffSelector }, - { 'ss08', kStylisticAlternativesType, kStylisticAltEightOnSelector, kStylisticAltEightOffSelector }, - { 'ss09', kStylisticAlternativesType, kStylisticAltNineOnSelector, kStylisticAltNineOffSelector }, - { 'ss10', kStylisticAlternativesType, kStylisticAltTenOnSelector, kStylisticAltTenOffSelector }, - { 'ss11', kStylisticAlternativesType, kStylisticAltElevenOnSelector, kStylisticAltElevenOffSelector }, - { 'ss12', kStylisticAlternativesType, kStylisticAltTwelveOnSelector, kStylisticAltTwelveOffSelector }, - { 'ss13', kStylisticAlternativesType, kStylisticAltThirteenOnSelector, kStylisticAltThirteenOffSelector }, - { 'ss14', kStylisticAlternativesType, kStylisticAltFourteenOnSelector, kStylisticAltFourteenOffSelector }, - { 'ss15', kStylisticAlternativesType, kStylisticAltFifteenOnSelector, kStylisticAltFifteenOffSelector }, - { 'ss16', kStylisticAlternativesType, kStylisticAltSixteenOnSelector, kStylisticAltSixteenOffSelector }, - { 'ss17', kStylisticAlternativesType, kStylisticAltSeventeenOnSelector, kStylisticAltSeventeenOffSelector }, - { 'ss18', kStylisticAlternativesType, kStylisticAltEighteenOnSelector, kStylisticAltEighteenOffSelector }, - { 'ss19', kStylisticAlternativesType, kStylisticAltNineteenOnSelector, kStylisticAltNineteenOffSelector }, - { 'ss20', kStylisticAlternativesType, kStylisticAltTwentyOnSelector, kStylisticAltTwentyOffSelector }, - { 'subs', kVerticalPositionType, kInferiorsSelector, kNormalPositionSelector }, - { 'sups', kVerticalPositionType, kSuperiorsSelector, kNormalPositionSelector }, - { 'swsh', kContextualAlternatesType, kSwashAlternatesOnSelector, kSwashAlternatesOffSelector }, - { 'titl', kStyleOptionsType, kTitlingCapsSelector, kNoStyleOptionsSelector }, - { 'tnam', kCharacterShapeType, kTraditionalNamesCharactersSelector, 16 }, - { 'tnum', kNumberSpacingType, kMonospacedNumbersSelector, 4 }, - { 'trad', kCharacterShapeType, kTraditionalCharactersSelector, 16 }, - { 'twid', kTextSpacingType, kThirdWidthTextSelector, 7 }, - { 'unic', kLetterCaseType, 14, 15 }, - { 'valt', kTextSpacingType, kAltProportionalTextSelector, 7 }, - { 'vert', kVerticalSubstitutionType, kSubstituteVerticalFormsOnSelector, kSubstituteVerticalFormsOffSelector }, - { 'vhal', kTextSpacingType, kAltHalfWidthTextSelector, 7 }, - { 'vkna', kAlternateKanaType, kAlternateVertKanaOnSelector, kAlternateVertKanaOffSelector }, - { 'vpal', kTextSpacingType, kAltProportionalTextSelector, 7 }, - { 'vrt2', kVerticalSubstitutionType, kSubstituteVerticalFormsOnSelector, kSubstituteVerticalFormsOffSelector }, - { 'zero', kTypographicExtrasType, kSlashedZeroOnSelector, kSlashedZeroOffSelector }, -}; - -static int -_hb_feature_mapping_cmp (const void *key_, const void *entry_) -{ - unsigned int key = * (unsigned int *) key_; - const feature_mapping_t * entry = (const feature_mapping_t *) entry_; - return key < entry->otFeatureTag ? -1 : - key > entry->otFeatureTag ? 1 : - 0; -} - hb_bool_t _hb_coretext_shape (hb_shape_plan_t *shape_plan, hb_font_t *font, @@ -624,7 +448,7 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan, CGFloat y_mult = (CGFloat) font->y_scale / ct_font_size; /* Attach marks to their bases, to match the 'ot' shaper. - * Adapted from hb-ot-shape:hb_form_clusters(). + * Adapted from a very old version of hb-ot-shape:hb_form_clusters(). * Note that this only makes us be closer to the 'ot' shaper, * but by no means the same. For example, if there's * B1 M1 B2 M2, and B1-B2 form a ligature, M2's cluster will @@ -653,11 +477,7 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan, hb_auto_t<hb_vector_t<feature_event_t> > feature_events; for (unsigned int i = 0; i < num_features; i++) { - const feature_mapping_t * mapping = (const feature_mapping_t *) bsearch (&features[i].tag, - feature_mappings, - ARRAY_LENGTH (feature_mappings), - sizeof (feature_mappings[0]), - _hb_feature_mapping_cmp); + const hb_aat_feature_mapping_t * mapping = hb_aat_layout_find_feature_mapping (features[i].tag); if (!mapping) continue; @@ -766,7 +586,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()); } } } @@ -823,7 +643,7 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan, CFStringRef string_ref = nullptr; CTLineRef line = nullptr; - if (0) + if (false) { resize_and_retry: DEBUG_MSG (CORETEXT, buffer, "Buffer resize"); @@ -1234,7 +1054,7 @@ resize_and_retry: * * https://crbug.com/419769 */ - if (0) + if (false) { /* Make sure all runs had the expected direction. */ bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction); diff --git a/src/hb-debug.hh b/src/hb-debug.hh index 9056ffca2..58c190d27 100644 --- a/src/hb-debug.hh +++ b/src/hb-debug.hh @@ -27,8 +27,8 @@ #ifndef HB_DEBUG_HH #define HB_DEBUG_HH -#include "hb-private.hh" -#include "hb-atomic-private.hh" +#include "hb.hh" +#include "hb-atomic.hh" #include "hb-dsalgs.hh" @@ -43,9 +43,10 @@ struct hb_options_t { - unsigned int unused : 1; /* In-case sign bit is here. */ - unsigned int initialized : 1; - unsigned int uniscribe_bug_compatible : 1; + bool unused : 1; /* In-case sign bit is here. */ + bool initialized : 1; + bool uniscribe_bug_compatible : 1; + bool aat : 1; }; union hb_options_union_t { @@ -67,7 +68,10 @@ hb_options (void) u.i = _hb_options.get_relaxed (); if (unlikely (!u.i)) + { _hb_options_init (); + u.i = _hb_options.get_relaxed (); + } return u.opts; } diff --git a/src/hb-deprecated.h b/src/hb-deprecated.h index eac7efb42..5af9bdbd8 100644 --- a/src/hb-deprecated.h +++ b/src/hb-deprecated.h @@ -50,14 +50,191 @@ 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 void +HB_EXTERN HB_DEPRECATED_FOR(hb_font_funcs_set_nominal_glyph_func or 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); -HB_EXTERN void +HB_EXTERN HB_DEPRECATED void hb_set_invert (hb_set_t *set); +/** + * hb_unicode_eastasian_width_func_t: + * + * Deprecated: 2.0.0 + */ +typedef unsigned int (*hb_unicode_eastasian_width_func_t) (hb_unicode_funcs_t *ufuncs, + hb_codepoint_t unicode, + void *user_data); + +/** + * hb_unicode_funcs_set_eastasian_width_func: + * @ufuncs: a Unicode function structure + * @func: (closure user_data) (destroy destroy) (scope notified): + * @user_data: + * @destroy: + * + * + * + * Since: 0.9.2 + * Deprecated: 2.0.0 + **/ +HB_EXTERN HB_DEPRECATED void +hb_unicode_funcs_set_eastasian_width_func (hb_unicode_funcs_t *ufuncs, + hb_unicode_eastasian_width_func_t func, + void *user_data, hb_destroy_func_t destroy); + +/** + * hb_unicode_eastasian_width: + * + * Since: 0.9.2 + * Deprecated: 2.0.0 + **/ +HB_EXTERN HB_DEPRECATED unsigned int +hb_unicode_eastasian_width (hb_unicode_funcs_t *ufuncs, + hb_codepoint_t unicode); + + +/** + * hb_unicode_decompose_compatibility_func_t: + * @ufuncs: a Unicode function structure + * @u: codepoint to decompose + * @decomposed: address of codepoint array (of length %HB_UNICODE_MAX_DECOMPOSITION_LEN) to write decomposition into + * @user_data: user data pointer as passed to hb_unicode_funcs_set_decompose_compatibility_func() + * + * Fully decompose @u to its Unicode compatibility decomposition. The codepoints of the decomposition will be written to @decomposed. + * The complete length of the decomposition will be returned. + * + * If @u has no compatibility decomposition, zero should be returned. + * + * The Unicode standard guarantees that a buffer of length %HB_UNICODE_MAX_DECOMPOSITION_LEN codepoints will always be sufficient for any + * compatibility decomposition plus an terminating value of 0. Consequently, @decompose must be allocated by the caller to be at least this length. Implementations + * of this function type must ensure that they do not write past the provided array. + * + * Return value: number of codepoints in the full compatibility decomposition of @u, or 0 if no decomposition available. + * + * Deprecated: 2.0.0 + */ +typedef unsigned int (*hb_unicode_decompose_compatibility_func_t) (hb_unicode_funcs_t *ufuncs, + hb_codepoint_t u, + hb_codepoint_t *decomposed, + void *user_data); + +/** + * HB_UNICODE_MAX_DECOMPOSITION_LEN: + * + * See Unicode 6.1 for details on the maximum decomposition length. + * + * Deprecated: 2.0.0 + */ +#define HB_UNICODE_MAX_DECOMPOSITION_LEN (18+1) /* codepoints */ + +/** + * hb_unicode_funcs_set_decompose_compatibility_func: + * @ufuncs: a Unicode function structure + * @func: (closure user_data) (destroy destroy) (scope notified): + * @user_data: + * @destroy: + * + * + * + * Since: 0.9.2 + * Deprecated: 2.0.0 + **/ +HB_EXTERN HB_DEPRECATED void +hb_unicode_funcs_set_decompose_compatibility_func (hb_unicode_funcs_t *ufuncs, + hb_unicode_decompose_compatibility_func_t func, + void *user_data, hb_destroy_func_t destroy); + +/** + * hb_unicode_decompose_compatibility: + * + * + * Deprecated: 2.0.0 + **/ +HB_EXTERN HB_DEPRECATED unsigned int +hb_unicode_decompose_compatibility (hb_unicode_funcs_t *ufuncs, + hb_codepoint_t u, + 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. + * @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_v_kerning_func (hb_font_funcs_t *ffuncs, + hb_font_get_glyph_v_kerning_func_t func, + 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); + +/* Like hb_ot_layout_table_find_script, but takes zero-terminated array of scripts to test */ +HB_EXTERN HB_DEPRECATED_FOR (hb_ot_layout_table_select_script) hb_bool_t +hb_ot_layout_table_choose_script (hb_face_t *face, + hb_tag_t table_tag, + const hb_tag_t *script_tags, + unsigned int *script_index, + hb_tag_t *chosen_script); + +HB_EXTERN HB_DEPRECATED_FOR (hb_ot_layout_script_select_language) hb_bool_t +hb_ot_layout_script_find_language (hb_face_t *face, + hb_tag_t table_tag, + unsigned int script_index, + hb_tag_t language_tag, + unsigned int *language_index); + +HB_EXTERN HB_DEPRECATED_FOR (hb_ot_tags_from_script_and_language) void +hb_ot_tags_from_script (hb_script_t script, + hb_tag_t *script_tag_1, + hb_tag_t *script_tag_2); + +HB_EXTERN HB_DEPRECATED_FOR (hb_ot_tags_from_script_and_language) hb_tag_t +hb_ot_tag_from_language (hb_language_t language); + + #endif HB_END_DECLS diff --git a/src/hb-directwrite.cc b/src/hb-directwrite.cc index baad81884..35197c238 100644 --- a/src/hb-directwrite.cc +++ b/src/hb-directwrite.cc @@ -22,9 +22,9 @@ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. */ -#include "hb-private.hh" +#include "hb.hh" #define HB_SHAPER directwrite -#include "hb-shaper-impl-private.hh" +#include "hb-shaper-impl.hh" #include <DWrite_1.h> diff --git a/src/hb-dsalgs.hh b/src/hb-dsalgs.hh index 8cbe6584b..eb15c089e 100644 --- a/src/hb-dsalgs.hh +++ b/src/hb-dsalgs.hh @@ -27,7 +27,9 @@ #ifndef HB_DSALGS_HH #define HB_DSALGS_HH -#include "hb-private.hh" +#include "hb.hh" + +#include "hb-null.hh" /* Void! For when we need a expression-type of void. */ @@ -492,23 +494,55 @@ template <typename Type> struct hb_auto_t : Type { hb_auto_t (void) { Type::init (); } + /* Explicitly allow the following only for pointer and references, + * to avoid any accidental copies. + * + * Apparently if we template for all types, then gcc seems to + * capture a reference argument in the type, but clang doesn't, + * causing unwanted copies and bugs that come with it. Ideally + * we should use C++11-style rvalue reference &&t1. */ + template <typename T1> explicit hb_auto_t (T1 *t1) { Type::init (t1); } + template <typename T1> explicit hb_auto_t (T1 &t1) { Type::init (t1); } ~hb_auto_t (void) { Type::fini (); } private: /* Hide */ void init (void) {} void fini (void) {} }; +template <typename T> +struct hb_array_t +{ + inline hb_array_t (void) : arrayZ (nullptr), len (0) {} + inline hb_array_t (const T *array_, unsigned int len_) : arrayZ (array_), len (len_) {} + + inline const T& operator [] (unsigned int i) const + { + if (unlikely (i >= len)) return Null(T); + return arrayZ[i]; + } + + inline void free (void) { ::free ((void *) arrayZ); arrayZ = nullptr; len = 0; } + + const T *arrayZ; + unsigned int len; +}; + struct hb_bytes_t { - inline hb_bytes_t (void) : bytes (nullptr), len (0) {} - inline hb_bytes_t (const char *bytes_, unsigned int len_) : bytes (bytes_), len (len_) {} + inline hb_bytes_t (void) : arrayZ (nullptr), len (0) {} + inline hb_bytes_t (const char *bytes_, unsigned int len_) : arrayZ (bytes_), len (len_) {} + inline hb_bytes_t (const void *bytes_, unsigned int len_) : arrayZ ((const char *) bytes_), len (len_) {} + template <typename T> + inline hb_bytes_t (const T& array) : arrayZ ((const char *) array.arrayZ), len (array.len) {} + + inline void free (void) { ::free ((void *) arrayZ); arrayZ = nullptr; len = 0; } inline int cmp (const hb_bytes_t &a) const { if (len != a.len) return (int) a.len - (int) len; - return memcmp (a.bytes, bytes, len); + return memcmp (a.arrayZ, arrayZ, len); } static inline int cmp (const void *pa, const void *pb) { @@ -517,7 +551,7 @@ struct hb_bytes_t return b->cmp (*a); } - const char *bytes; + const char *arrayZ; unsigned int len; }; diff --git a/src/hb-face.cc b/src/hb-face.cc index 49f29d3fa..bba1ee3fa 100644 --- a/src/hb-face.cc +++ b/src/hb-face.cc @@ -26,20 +26,22 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-private.hh" +#include "hb.hh" -#include "hb-face-private.hh" -#include "hb-blob-private.hh" -#include "hb-open-file-private.hh" +#include "hb-face.hh" +#include "hb-blob.hh" +#include "hb-open-file.hh" +#include "hb-ot-face.hh" +#include "hb-ot-cmap-table.hh" /** - * hb_face_count: Get number of faces on the blob - * @blob: - * + * hb_face_count: + * @blob: a blob. * + * Get number of faces in a blob. * - * Return value: Number of faces on the blob + * Return value: Number of faces in @blob * * Since: 1.7.7 **/ @@ -161,11 +163,12 @@ _hb_face_for_data_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void return hb_blob_reference (data->blob); const OT::OpenTypeFontFile &ot_file = *data->blob->as<OT::OpenTypeFontFile> (); - const OT::OpenTypeFontFace &ot_face = ot_file.get_face (data->index); + unsigned int base_offset; + const OT::OpenTypeFontFace &ot_face = ot_file.get_face (data->index, &base_offset); const OT::OpenTypeTable &table = ot_face.get_table_by_tag (tag); - hb_blob_t *blob = hb_blob_create_sub_blob (data->blob, table.offset, table.length); + hb_blob_t *blob = hb_blob_create_sub_blob (data->blob, base_offset + table.offset, table.length); return blob; } @@ -322,6 +325,8 @@ hb_face_make_immutable (hb_face_t *face) { if (unlikely (hb_object_is_inert (face))) return; + if (face->immutable) + return; face->immutable = true; } @@ -485,6 +490,9 @@ hb_face_get_glyph_count (const hb_face_t *face) /** * hb_face_get_table_tags: * @face: a face. + * @start_offset: index of first tag to return. + * @table_count: input length of @table_tags array, output number of items written. + * @table_tags: array to write tags into. * * Retrieves table tags for a face, if possible. * @@ -512,3 +520,208 @@ hb_face_get_table_tags (const hb_face_t *face, return ot_face.get_table_tags (start_offset, table_count, table_tags); } + + +/* + * Character set. + */ + + +/** + * hb_face_collect_unicodes: + * @face: font face. + * @out: set to add Unicode characters covered by @face to. + * + * Since: 1.9.0 + */ +void +hb_face_collect_unicodes (hb_face_t *face, + hb_set_t *out) +{ + if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return; + hb_ot_face_data (face)->cmap->collect_unicodes (out); +} + +/** + * hb_face_collect_variation_selectors: + * @face: font face. + * @out: set to add Variation Selector characters covered by @face to. + * + * + * + * Since: 1.9.0 + */ +void +hb_face_collect_variation_selectors (hb_face_t *face, + hb_set_t *out) +{ + if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return; + hb_ot_face_data (face)->cmap->collect_variation_selectors (out); +} + +/** + * hb_face_collect_variation_unicodes: + * @face: font face. + * @out: set to add Unicode characters for @variation_selector covered by @face to. + * + * + * + * Since: 1.9.0 + */ +void +hb_face_collect_variation_unicodes (hb_face_t *face, + hb_codepoint_t variation_selector, + hb_set_t *out) +{ + if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return; + hb_ot_face_data (face)->cmap->collect_variation_unicodes (variation_selector, out); +} + + + +/* + * face-builder: A face that has add_table(). + */ + +struct hb_face_builder_data_t +{ + struct table_entry_t + { + inline int cmp (const hb_tag_t *t) const + { + if (*t < tag) return -1; + if (*t > tag) return -1; + return 0; + } + + hb_tag_t tag; + hb_blob_t *blob; + }; + + hb_vector_t<table_entry_t, 32> tables; +}; + +static hb_face_builder_data_t * +_hb_face_builder_data_create (void) +{ + hb_face_builder_data_t *data = (hb_face_builder_data_t *) calloc (1, sizeof (hb_face_builder_data_t)); + if (unlikely (!data)) + return nullptr; + + data->tables.init (); + + return data; +} + +static void +_hb_face_builder_data_destroy (void *user_data) +{ + hb_face_builder_data_t *data = (hb_face_builder_data_t *) user_data; + + for (unsigned int i = 0; i < data->tables.len; i++) + hb_blob_destroy (data->tables[i].blob); + + data->tables.fini (); + + free (data); +} + +static hb_blob_t * +_hb_face_builder_data_reference_blob (hb_face_builder_data_t *data) +{ + + unsigned int table_count = data->tables.len; + unsigned int face_length = table_count * 16 + 12; + + for (unsigned int i = 0; i < table_count; i++) + face_length += hb_ceil_to_4 (hb_blob_get_length (data->tables[i].blob)); + + char *buf = (char *) malloc (face_length); + if (unlikely (!buf)) + return nullptr; + + hb_serialize_context_t c (buf, face_length); + OT::OpenTypeFontFile *f = c.start_serialize<OT::OpenTypeFontFile> (); + + bool is_cff = data->tables.lsearch (HB_TAG ('C','F','F',' ')) || data->tables.lsearch (HB_TAG ('C','F','F','2')); + hb_tag_t sfnt_tag = is_cff ? OT::OpenTypeFontFile::CFFTag : OT::OpenTypeFontFile::TrueTypeTag; + + Supplier<hb_tag_t> tags_supplier (&data->tables[0].tag, table_count, sizeof (data->tables[0])); + Supplier<hb_blob_t *> blobs_supplier (&data->tables[0].blob, table_count, sizeof (data->tables[0])); + bool ret = f->serialize_single (&c, + sfnt_tag, + tags_supplier, + blobs_supplier, + table_count); + + c.end_serialize (); + + if (unlikely (!ret)) + { + free (buf); + return nullptr; + } + + return hb_blob_create (buf, face_length, HB_MEMORY_MODE_WRITABLE, buf, free); +} + +static hb_blob_t * +_hb_face_builder_reference_table (hb_face_t *face, hb_tag_t tag, void *user_data) +{ + hb_face_builder_data_t *data = (hb_face_builder_data_t *) user_data; + + if (!tag) + return _hb_face_builder_data_reference_blob (data); + + hb_face_builder_data_t::table_entry_t *entry = data->tables.lsearch (tag); + if (entry) + return hb_blob_reference (entry->blob); + + return nullptr; +} + + +/** + * hb_face_builder_create: + * + * Creates a #hb_face_t that can be used with hb_face_builder_add_table(). + * After tables are added to the face, it can be compiled to a binary + * font file by calling hb_face_reference_blob(). + * + * Return value: (transfer full): New face. + * + * Since: 1.9.0 + **/ +hb_face_t * +hb_face_builder_create (void) +{ + hb_face_builder_data_t *data = _hb_face_builder_data_create (); + if (unlikely (!data)) return hb_face_get_empty (); + + return hb_face_create_for_tables (_hb_face_builder_reference_table, + data, + _hb_face_builder_data_destroy); +} + +/** + * hb_face_builder_add_table: + * + * Add table for @tag with data provided by @blob to the face. @face must + * be created using hb_face_builder_create(). + * + * Since: 1.9.0 + **/ +hb_bool_t +hb_face_builder_add_table (hb_face_t *face, hb_tag_t tag, hb_blob_t *blob) +{ + if (unlikely (face->destroy != (hb_destroy_func_t) _hb_face_builder_data_destroy)) + return false; + + hb_face_builder_data_t *data = (hb_face_builder_data_t *) face->user_data; + hb_face_builder_data_t::table_entry_t *entry = data->tables.push (); + + entry->tag = tag; + entry->blob = hb_blob_reference (blob); + + return true; +} diff --git a/src/hb-face.h b/src/hb-face.h index 208092efc..e8ff090d5 100644 --- a/src/hb-face.h +++ b/src/hb-face.h @@ -33,6 +33,7 @@ #include "hb-common.h" #include "hb-blob.h" +#include "hb-set.h" HB_BEGIN_DECLS @@ -120,6 +121,38 @@ hb_face_get_table_tags (const hb_face_t *face, unsigned int *table_count, /* IN/OUT */ hb_tag_t *table_tags /* OUT */); + +/* + * Character set. + */ + +HB_EXTERN void +hb_face_collect_unicodes (hb_face_t *face, + hb_set_t *out); + +HB_EXTERN void +hb_face_collect_variation_selectors (hb_face_t *face, + hb_set_t *out); + +HB_EXTERN void +hb_face_collect_variation_unicodes (hb_face_t *face, + hb_codepoint_t variation_selector, + hb_set_t *out); + + +/* + * Builder face. + */ + +HB_EXTERN hb_face_t * +hb_face_builder_create (void); + +HB_EXTERN hb_bool_t +hb_face_builder_add_table (hb_face_t *face, + hb_tag_t tag, + hb_blob_t *blob); + + HB_END_DECLS #endif /* HB_FACE_H */ diff --git a/src/hb-face-private.hh b/src/hb-face.hh index 086ce6e96..f90453dbd 100644 --- a/src/hb-face-private.hh +++ b/src/hb-face.hh @@ -26,13 +26,13 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_FACE_PRIVATE_HH -#define HB_FACE_PRIVATE_HH +#ifndef HB_FACE_HH +#define HB_FACE_HH -#include "hb-private.hh" +#include "hb.hh" -#include "hb-shaper-private.hh" -#include "hb-shape-plan-private.hh" +#include "hb-shaper.hh" +#include "hb-shape-plan.hh" /* @@ -105,4 +105,4 @@ DECLARE_NULL_INSTANCE (hb_face_t); #undef HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS -#endif /* HB_FACE_PRIVATE_HH */ +#endif /* HB_FACE_HH */ diff --git a/src/hb-fallback-shape.cc b/src/hb-fallback-shape.cc index eff20f70c..dc8536c82 100644 --- a/src/hb-fallback-shape.cc +++ b/src/hb-fallback-shape.cc @@ -25,7 +25,7 @@ */ #define HB_SHAPER fallback -#include "hb-shaper-impl-private.hh" +#include "hb-shaper-impl.hh" HB_SHAPER_DATA_ENSURE_DEFINE(fallback, face) diff --git a/src/hb-font.cc b/src/hb-font.cc index 857b8f577..b6b668dd8 100644 --- a/src/hb-font.cc +++ b/src/hb-font.cc @@ -26,10 +26,12 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-private.hh" +#include "hb.hh" -#include "hb-font-private.hh" -#include "hb-machinery-private.hh" +#include "hb-font.hh" +#include "hb-machinery.hh" + +#include "hb-ot.h" /* @@ -101,9 +103,42 @@ hb_font_get_nominal_glyph_default (hb_font_t *font, hb_codepoint_t *glyph, void *user_data HB_UNUSED) { + if (font->has_nominal_glyphs_func_set ()) + { + return font->get_nominal_glyphs (1, &unicode, 0, glyph, 0); + } return font->parent->get_nominal_glyph (unicode, glyph); } +#define hb_font_get_nominal_glyphs_nil hb_font_get_nominal_glyphs_default +static unsigned int +hb_font_get_nominal_glyphs_default (hb_font_t *font, + void *font_data HB_UNUSED, + unsigned int count, + const hb_codepoint_t *first_unicode, + unsigned int unicode_stride, + hb_codepoint_t *first_glyph, + unsigned int glyph_stride, + void *user_data HB_UNUSED) +{ + if (font->has_nominal_glyph_func_set ()) + { + for (unsigned int i = 0; i < count; i++) + { + if (!font->get_nominal_glyph (*first_unicode, first_glyph)) + return i; + + first_unicode = &StructAtOffset<hb_codepoint_t> (first_unicode, unicode_stride); + first_glyph = &StructAtOffset<hb_codepoint_t> (first_glyph, glyph_stride); + } + return count; + } + + return font->parent->get_nominal_glyphs (count, + first_unicode, unicode_stride, + first_glyph, glyph_stride); +} + static hb_bool_t hb_font_get_variation_glyph_nil (hb_font_t *font HB_UNUSED, void *font_data HB_UNUSED, @@ -141,6 +176,12 @@ hb_font_get_glyph_h_advance_default (hb_font_t *font, hb_codepoint_t glyph, void *user_data HB_UNUSED) { + if (font->has_glyph_h_advances_func_set ()) + { + hb_position_t ret; + font->get_glyph_h_advances (1, &glyph, 0, &ret, 0); + return ret; + } return font->parent_scale_x_distance (font->parent->get_glyph_h_advance (glyph)); } @@ -159,6 +200,12 @@ hb_font_get_glyph_v_advance_default (hb_font_t *font, hb_codepoint_t glyph, void *user_data HB_UNUSED) { + if (font->has_glyph_v_advances_func_set ()) + { + hb_position_t ret; + font->get_glyph_v_advances (1, &glyph, 0, &ret, 0); + return ret; + } return font->parent_scale_y_distance (font->parent->get_glyph_v_advance (glyph)); } @@ -167,13 +214,13 @@ static void hb_font_get_glyph_h_advances_default (hb_font_t* font, void* font_data HB_UNUSED, unsigned int count, - hb_codepoint_t *first_glyph, + const hb_codepoint_t *first_glyph, unsigned int glyph_stride, hb_position_t *first_advance, unsigned int advance_stride, void *user_data HB_UNUSED) { - if (font->has_glyph_h_advance_func ()) + if (font->has_glyph_h_advance_func_set ()) { for (unsigned int i = 0; i < count; i++) { @@ -199,13 +246,13 @@ static void hb_font_get_glyph_v_advances_default (hb_font_t* font, void* font_data HB_UNUSED, unsigned int count, - hb_codepoint_t *first_glyph, + const hb_codepoint_t *first_glyph, unsigned int glyph_stride, hb_position_t *first_advance, unsigned int advance_stride, void *user_data HB_UNUSED) { - if (font->has_glyph_v_advance_func ()) + if (font->has_glyph_v_advance_func_set ()) { for (unsigned int i = 0; i < count; i++) { @@ -586,6 +633,8 @@ hb_font_funcs_make_immutable (hb_font_funcs_t *ffuncs) { if (unlikely (hb_object_is_inert (ffuncs))) return; + if (ffuncs->immutable) + return; ffuncs->immutable = true; } @@ -639,9 +688,15 @@ HB_FONT_FUNCS_IMPLEMENT_CALLBACKS #undef HB_FONT_FUNC_IMPLEMENT bool +hb_font_t::has_func_set (unsigned int i) +{ + return this->klass->get.array[i] != _hb_font_funcs_default.get.array[i]; +} + +bool hb_font_t::has_func (unsigned int i) { - return (this->klass->get.array[i] != _hb_font_funcs_default.get.array[i]) || + return has_func_set (i) || (parent && parent != &_hb_Null_hb_font_t && parent->has_func (i)); } @@ -793,8 +848,8 @@ hb_font_get_glyph_v_advance (hb_font_t *font, **/ void hb_font_get_glyph_h_advances (hb_font_t* font, - unsigned count, - hb_codepoint_t *first_glyph, + unsigned int count, + const hb_codepoint_t *first_glyph, unsigned glyph_stride, hb_position_t *first_advance, unsigned advance_stride) @@ -811,8 +866,8 @@ hb_font_get_glyph_h_advances (hb_font_t* font, **/ void hb_font_get_glyph_v_advances (hb_font_t* font, - unsigned count, - hb_codepoint_t *first_glyph, + unsigned int count, + const hb_codepoint_t *first_glyph, unsigned glyph_stride, hb_position_t *first_advance, unsigned advance_stride) @@ -873,6 +928,7 @@ 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, @@ -892,6 +948,7 @@ hb_font_get_glyph_h_kerning (hb_font_t *font, * Return value: * * Since: 0.9.2 + * Deprecated: 2.0.0 **/ hb_position_t hb_font_get_glyph_v_kerning (hb_font_t *font, @@ -991,7 +1048,7 @@ hb_font_get_glyph_from_name (hb_font_t *font, * hb_font_get_extents_for_direction: * @font: a font. * @direction: - * @extents: + * @extents: (out): * * * @@ -1036,8 +1093,8 @@ hb_font_get_glyph_advance_for_direction (hb_font_t *font, HB_EXTERN void hb_font_get_glyph_advances_for_direction (hb_font_t* font, hb_direction_t direction, - unsigned count, - hb_codepoint_t *first_glyph, + unsigned int count, + const hb_codepoint_t *first_glyph, unsigned glyph_stride, hb_position_t *first_advance, unsigned advance_stride) @@ -1120,6 +1177,7 @@ 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, @@ -1254,18 +1312,8 @@ DEFINE_NULL_INSTANCE (hb_font_t) = }; -/** - * hb_font_create: (Xconstructor) - * @face: a face. - * - * - * - * Return value: (transfer full): - * - * Since: 0.9.2 - **/ -hb_font_t * -hb_font_create (hb_face_t *face) +static hb_font_t * +_hb_font_create (hb_face_t *face) { hb_font_t *font; @@ -1285,6 +1333,27 @@ hb_font_create (hb_face_t *face) } /** + * hb_font_create: (Xconstructor) + * @face: a face. + * + * + * + * Return value: (transfer full): + * + * Since: 0.9.2 + **/ +hb_font_t * +hb_font_create (hb_face_t *face) +{ + hb_font_t *font = _hb_font_create (face); + + /* Install our in-house, very lightweight, funcs. */ + hb_ot_font_set_funcs (font); + + return font; +} + +/** * hb_font_create_sub_font: * @parent: parent font. * @@ -1300,7 +1369,7 @@ hb_font_create_sub_font (hb_font_t *parent) if (unlikely (!parent)) parent = hb_font_get_empty (); - hb_font_t *font = hb_font_create (parent->face); + hb_font_t *font = _hb_font_create (parent->face); if (unlikely (hb_object_is_inert (font))) return font; @@ -1444,6 +1513,8 @@ hb_font_make_immutable (hb_font_t *font) { if (unlikely (hb_object_is_inert (font))) return; + if (font->immutable) + return; if (font->parent) hb_font_make_immutable (font->parent); @@ -1703,9 +1774,11 @@ hb_font_get_ppem (hb_font_t *font, /** * hb_font_set_ptem: * @font: a font. - * @ptem: + * @ptem: font size in points. * - * Sets "point size" of the font. + * Sets "point size" of the font. Set to 0 to unset. + * + * There are 72 points in an inch. * * Since: 1.6.0 **/ @@ -1843,8 +1916,6 @@ hb_font_get_var_coords_normalized (hb_font_t *font, } -#ifndef HB_DISABLE_DEPRECATED - /* * Deprecated get_glyph_func(): */ @@ -1931,9 +2002,9 @@ hb_font_get_variation_glyph_trampoline (hb_font_t *font, /** * hb_font_funcs_set_glyph_func: * @ffuncs: font functions. - * @func: (closure user_data) (destroy destroy) (scope notified): - * @user_data: - * @destroy: + * @func: (closure user_data) (destroy destroy) (scope notified): callback function. + * @user_data: data to pass to @func. + * @destroy: function to call when @user_data is not needed anymore. * * Deprecated. Use hb_font_funcs_set_nominal_glyph_func() and * hb_font_funcs_set_variation_glyph_func() instead. @@ -1967,5 +2038,3 @@ hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs, trampoline, trampoline_destroy); } - -#endif /* HB_DISABLE_DEPRECATED */ diff --git a/src/hb-font.h b/src/hb-font.h index 6cd486979..74c61aba4 100644 --- a/src/hb-font.h +++ b/src/hb-font.h @@ -125,6 +125,14 @@ typedef hb_bool_t (*hb_font_get_variation_glyph_func_t) (hb_font_t *font, void * hb_codepoint_t *glyph, void *user_data); +typedef unsigned int (*hb_font_get_nominal_glyphs_func_t) (hb_font_t *font, void *font_data, + unsigned int count, + const hb_codepoint_t *first_unicode, + unsigned int unicode_stride, + hb_codepoint_t *first_glyph, + unsigned int glyph_stride, + void *user_data); + typedef hb_position_t (*hb_font_get_glyph_advance_func_t) (hb_font_t *font, void *font_data, hb_codepoint_t glyph, @@ -133,8 +141,8 @@ typedef hb_font_get_glyph_advance_func_t hb_font_get_glyph_h_advance_func_t; typedef hb_font_get_glyph_advance_func_t hb_font_get_glyph_v_advance_func_t; typedef void (*hb_font_get_glyph_advances_func_t) (hb_font_t* font, void* font_data, - unsigned count, - hb_codepoint_t *first_glyph, + unsigned int count, + const hb_codepoint_t *first_glyph, unsigned glyph_stride, hb_position_t *first_advance, unsigned advance_stride, @@ -149,12 +157,6 @@ 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_font_get_glyph_kerning_func_t hb_font_get_glyph_v_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, @@ -227,6 +229,22 @@ hb_font_funcs_set_nominal_glyph_func (hb_font_funcs_t *ffuncs, void *user_data, hb_destroy_func_t destroy); /** + * hb_font_funcs_set_nominal_glyphs_func: + * @ffuncs: font functions. + * @func: (closure user_data) (destroy destroy) (scope notified): + * @user_data: + * @destroy: + * + * + * + * Since: 2.0.0 + **/ +HB_EXTERN void +hb_font_funcs_set_nominal_glyphs_func (hb_font_funcs_t *ffuncs, + hb_font_get_nominal_glyphs_func_t func, + void *user_data, hb_destroy_func_t destroy); + +/** * hb_font_funcs_set_variation_glyph_func: * @ffuncs: font functions. * @func: (closure user_data) (destroy destroy) (scope notified): @@ -339,38 +357,6 @@ hb_font_funcs_set_glyph_v_origin_func (hb_font_funcs_t *ffuncs, 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_v_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_v_kerning_func (hb_font_funcs_t *ffuncs, - hb_font_get_glyph_v_kerning_func_t func, - void *user_data, hb_destroy_func_t destroy); - -/** * hb_font_funcs_set_glyph_extents_func: * @ffuncs: font functions. * @func: (closure user_data) (destroy destroy) (scope notified): @@ -461,15 +447,15 @@ hb_font_get_glyph_v_advance (hb_font_t *font, HB_EXTERN void hb_font_get_glyph_h_advances (hb_font_t* font, - unsigned count, - hb_codepoint_t *first_glyph, + unsigned int count, + const hb_codepoint_t *first_glyph, unsigned glyph_stride, hb_position_t *first_advance, unsigned advance_stride); HB_EXTERN void hb_font_get_glyph_v_advances (hb_font_t* font, - unsigned count, - hb_codepoint_t *first_glyph, + unsigned int count, + const hb_codepoint_t *first_glyph, unsigned glyph_stride, hb_position_t *first_advance, unsigned advance_stride); @@ -483,13 +469,6 @@ 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_position_t -hb_font_get_glyph_v_kerning (hb_font_t *font, - hb_codepoint_t top_glyph, hb_codepoint_t bottom_glyph); - HB_EXTERN hb_bool_t hb_font_get_glyph_extents (hb_font_t *font, hb_codepoint_t glyph, @@ -531,8 +510,8 @@ hb_font_get_glyph_advance_for_direction (hb_font_t *font, HB_EXTERN void hb_font_get_glyph_advances_for_direction (hb_font_t* font, hb_direction_t direction, - unsigned count, - hb_codepoint_t *first_glyph, + unsigned int count, + const hb_codepoint_t *first_glyph, unsigned glyph_stride, hb_position_t *first_advance, unsigned advance_stride); @@ -552,12 +531,6 @@ 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, diff --git a/src/hb-font-private.hh b/src/hb-font.hh index d3a413802..2df5e42ee 100644 --- a/src/hb-font-private.hh +++ b/src/hb-font.hh @@ -26,13 +26,13 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_FONT_PRIVATE_HH -#define HB_FONT_PRIVATE_HH +#ifndef HB_FONT_HH +#define HB_FONT_HH -#include "hb-private.hh" +#include "hb.hh" -#include "hb-face-private.hh" -#include "hb-shaper-private.hh" +#include "hb-face.hh" +#include "hb-shaper.hh" /* @@ -43,6 +43,7 @@ HB_FONT_FUNC_IMPLEMENT (font_h_extents) \ HB_FONT_FUNC_IMPLEMENT (font_v_extents) \ HB_FONT_FUNC_IMPLEMENT (nominal_glyph) \ + HB_FONT_FUNC_IMPLEMENT (nominal_glyphs) \ HB_FONT_FUNC_IMPLEMENT (variation_glyph) \ HB_FONT_FUNC_IMPLEMENT (glyph_h_advance) \ HB_FONT_FUNC_IMPLEMENT (glyph_v_advance) \ @@ -170,6 +171,7 @@ struct hb_font_t /* Public getters */ HB_INTERNAL bool has_func (unsigned int i); + HB_INTERNAL bool has_func_set (unsigned int i); /* has_* ... */ #define HB_FONT_FUNC_IMPLEMENT(name) \ @@ -179,6 +181,13 @@ struct hb_font_t hb_font_funcs_t *funcs = this->klass; \ unsigned int i = offsetof (hb_font_funcs_t::get_t::get_funcs_t, name) / sizeof (funcs->get.array[0]); \ return has_func (i); \ + } \ + bool \ + has_##name##_func_set (void) \ + { \ + hb_font_funcs_t *funcs = this->klass; \ + unsigned int i = offsetof (hb_font_funcs_t::get_t::get_funcs_t, name) / sizeof (funcs->get.array[0]); \ + return has_func_set (i); \ } HB_FONT_FUNCS_IMPLEMENT_CALLBACKS #undef HB_FONT_FUNC_IMPLEMENT @@ -212,6 +221,18 @@ struct hb_font_t unicode, glyph, klass->user_data.nominal_glyph); } + inline unsigned int get_nominal_glyphs (unsigned int count, + const hb_codepoint_t *first_unicode, + unsigned int unicode_stride, + hb_codepoint_t *first_glyph, + unsigned int glyph_stride) + { + return klass->get.f.nominal_glyphs (this, user_data, + count, + first_unicode, unicode_stride, + first_glyph, glyph_stride, + klass->user_data.nominal_glyphs); + } inline hb_bool_t get_variation_glyph (hb_codepoint_t unicode, hb_codepoint_t variation_selector, hb_codepoint_t *glyph) @@ -237,7 +258,7 @@ struct hb_font_t } inline void get_glyph_h_advances (unsigned int count, - hb_codepoint_t *first_glyph, + const hb_codepoint_t *first_glyph, unsigned int glyph_stride, hb_position_t *first_advance, unsigned int advance_stride) @@ -250,7 +271,7 @@ struct hb_font_t } inline void get_glyph_v_advances (unsigned int count, - hb_codepoint_t *first_glyph, + const hb_codepoint_t *first_glyph, unsigned int glyph_stride, hb_position_t *first_advance, unsigned int advance_stride) @@ -377,8 +398,8 @@ struct hb_font_t *y = get_glyph_v_advance (glyph); } inline void get_glyph_advances_for_direction (hb_direction_t direction, - unsigned count, - hb_codepoint_t *first_glyph, + unsigned int count, + const hb_codepoint_t *first_glyph, unsigned glyph_stride, hb_position_t *first_advance, unsigned advance_stride) @@ -502,8 +523,8 @@ struct hb_font_t hb_position_t *x, hb_position_t *y) { if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) { - *x = get_glyph_h_kerning (first_glyph, second_glyph); *y = 0; + *x = get_glyph_h_kerning (first_glyph, second_glyph); } else { *x = 0; *y = get_glyph_v_kerning (first_glyph, second_glyph); @@ -601,4 +622,4 @@ DECLARE_NULL_INSTANCE (hb_font_t); #undef HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS -#endif /* HB_FONT_PRIVATE_HH */ +#endif /* HB_FONT_HH */ diff --git a/src/hb-ft.cc b/src/hb-ft.cc index 01341b604..18fb72a73 100644 --- a/src/hb-ft.cc +++ b/src/hb-ft.cc @@ -27,12 +27,13 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-private.hh" +#include "hb.hh" #include "hb-ft.h" -#include "hb-font-private.hh" -#include "hb-machinery-private.hh" +#include "hb-font.hh" +#include "hb-machinery.hh" +#include "hb-cache.hh" #include FT_ADVANCES_H #include FT_MULTIPLE_MASTERS_H @@ -44,30 +45,29 @@ * In general, this file does a fine job of what it's supposed to do. * There are, however, things that need more work: * - * - I remember seeing FT_Get_Advance() without the NO_HINTING flag to be buggy. - * Have not investigated. - * * - FreeType works in 26.6 mode. Clients can decide to use that mode, and everything * would work fine. However, we also abuse this API for performing in font-space, * but don't pass the correct flags to FreeType. We just abuse the no-hinting mode * for that, such that no rounding etc happens. As such, we don't set ppem, and * pass NO_HINTING as load_flags. Would be much better to use NO_SCALE, and scale - * ourselves, like we do in uniscribe, etc. + * ourselves. * * - We don't handle / allow for emboldening / obliqueing. * * - In the future, we should add constructors to create fonts in font space? - * - * - FT_Load_Glyph() is extremely costly. Do something about it? */ struct hb_ft_font_t { + mutable hb_mutex_t lock; FT_Face ft_face; int load_flags; bool symbol; /* Whether selected cmap is symbol cmap. */ bool unref; /* Whether to destroy ft_face when done. */ + + mutable hb_atomic_int_t cached_x_scale; + mutable hb_advance_cache_t advance_cache; }; static hb_ft_font_t * @@ -78,12 +78,16 @@ _hb_ft_font_create (FT_Face ft_face, bool symbol, bool unref) if (unlikely (!ft_font)) return nullptr; + ft_font->lock.init (); ft_font->ft_face = ft_face; ft_font->symbol = symbol; ft_font->unref = unref; ft_font->load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING; + ft_font->cached_x_scale.set (0); + ft_font->advance_cache.init (); + return ft_font; } @@ -98,9 +102,13 @@ _hb_ft_font_destroy (void *data) { hb_ft_font_t *ft_font = (hb_ft_font_t *) data; + ft_font->advance_cache.fini (); + if (ft_font->unref) _hb_ft_face_destroy (ft_font->ft_face); + ft_font->lock.fini (); + free (ft_font); } @@ -168,6 +176,7 @@ hb_ft_get_nominal_glyph (hb_font_t *font HB_UNUSED, void *user_data HB_UNUSED) { const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; + hb_lock_t lock (ft_font->lock); unsigned int g = FT_Get_Char_Index (ft_font->ft_face, unicode); if (unlikely (!g)) @@ -191,6 +200,32 @@ hb_ft_get_nominal_glyph (hb_font_t *font HB_UNUSED, return true; } +static unsigned int +hb_ft_get_nominal_glyphs (hb_font_t *font HB_UNUSED, + void *font_data, + unsigned int count, + const hb_codepoint_t *first_unicode, + unsigned int unicode_stride, + hb_codepoint_t *first_glyph, + unsigned int glyph_stride, + void *user_data HB_UNUSED) +{ + const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; + hb_lock_t lock (ft_font->lock); + unsigned int done; + for (done = 0; + done < count && (*first_glyph = FT_Get_Char_Index (ft_font->ft_face, *first_unicode)); + done++) + { + first_unicode = &StructAtOffset<hb_codepoint_t> (first_unicode, unicode_stride); + first_glyph = &StructAtOffset<hb_codepoint_t> (first_glyph, glyph_stride); + } + /* We don't need to do ft_font->symbol dance here, since HB calls the singular + * nominal_glyph() for what we don't handle here. */ + return done; +} + + static hb_bool_t hb_ft_get_variation_glyph (hb_font_t *font HB_UNUSED, void *font_data, @@ -200,6 +235,7 @@ hb_ft_get_variation_glyph (hb_font_t *font HB_UNUSED, void *user_data HB_UNUSED) { const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; + hb_lock_t lock (ft_font->lock); unsigned int g = FT_Face_GetCharVariantIndex (ft_font->ft_face, unicode, variation_selector); if (unlikely (!g)) @@ -209,22 +245,45 @@ hb_ft_get_variation_glyph (hb_font_t *font HB_UNUSED, return true; } -static hb_position_t -hb_ft_get_glyph_h_advance (hb_font_t *font, - void *font_data, - hb_codepoint_t glyph, - void *user_data HB_UNUSED) +static void +hb_ft_get_glyph_h_advances (hb_font_t* font, void* font_data, + unsigned count, + const hb_codepoint_t *first_glyph, + unsigned glyph_stride, + hb_position_t *first_advance, + unsigned advance_stride, + void *user_data HB_UNUSED) { const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; - FT_Fixed v; + hb_lock_t lock (ft_font->lock); + FT_Face ft_face = ft_font->ft_face; + int load_flags = ft_font->load_flags; + int mult = font->x_scale < 0 ? -1 : +1; - if (unlikely (FT_Get_Advance (ft_font->ft_face, glyph, ft_font->load_flags, &v))) - return 0; + if (font->x_scale != ft_font->cached_x_scale.get ()) + { + ft_font->advance_cache.clear (); + ft_font->cached_x_scale.set (font->x_scale); + } - if (font->x_scale < 0) - v = -v; + for (unsigned int i = 0; i < count; i++) + { + FT_Fixed v = 0; + hb_codepoint_t glyph = *first_glyph; + + unsigned int cv; + if (ft_font->advance_cache.get (glyph, &cv)) + v = cv; + else + { + FT_Get_Advance (ft_face, glyph, load_flags, &v); + ft_font->advance_cache.set (glyph, v); + } - return (v + (1<<9)) >> 10; + *first_advance = (v * mult + (1<<9)) >> 10; + first_glyph = &StructAtOffset<hb_codepoint_t> (first_glyph, glyph_stride); + first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride); + } } static hb_position_t @@ -234,6 +293,7 @@ hb_ft_get_glyph_v_advance (hb_font_t *font, void *user_data HB_UNUSED) { const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; + hb_lock_t lock (ft_font->lock); FT_Fixed v; if (unlikely (FT_Get_Advance (ft_font->ft_face, glyph, ft_font->load_flags | FT_LOAD_VERTICAL_LAYOUT, &v))) @@ -256,6 +316,7 @@ hb_ft_get_glyph_v_origin (hb_font_t *font, void *user_data HB_UNUSED) { const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; + hb_lock_t lock (ft_font->lock); FT_Face ft_face = ft_font->ft_face; if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags))) @@ -274,23 +335,6 @@ hb_ft_get_glyph_v_origin (hb_font_t *font, return true; } -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; -} - static hb_bool_t hb_ft_get_glyph_extents (hb_font_t *font, void *font_data, @@ -299,6 +343,7 @@ hb_ft_get_glyph_extents (hb_font_t *font, void *user_data HB_UNUSED) { const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; + hb_lock_t lock (ft_font->lock); FT_Face ft_face = ft_font->ft_face; if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags))) @@ -331,6 +376,7 @@ hb_ft_get_glyph_contour_point (hb_font_t *font HB_UNUSED, void *user_data HB_UNUSED) { const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; + hb_lock_t lock (ft_font->lock); FT_Face ft_face = ft_font->ft_face; if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags))) @@ -356,8 +402,10 @@ hb_ft_get_glyph_name (hb_font_t *font HB_UNUSED, void *user_data HB_UNUSED) { const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; + hb_lock_t lock (ft_font->lock); + FT_Face ft_face = ft_font->ft_face; - hb_bool_t ret = !FT_Get_Glyph_Name (ft_font->ft_face, glyph, name, size); + hb_bool_t ret = !FT_Get_Glyph_Name (ft_face, glyph, name, size); if (ret && (size && !*name)) ret = false; @@ -372,6 +420,7 @@ hb_ft_get_glyph_from_name (hb_font_t *font HB_UNUSED, void *user_data HB_UNUSED) { const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; + hb_lock_t lock (ft_font->lock); FT_Face ft_face = ft_font->ft_face; if (len < 0) @@ -404,6 +453,7 @@ hb_ft_get_font_h_extents (hb_font_t *font HB_UNUSED, void *user_data HB_UNUSED) { const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; + hb_lock_t lock (ft_font->lock); FT_Face ft_face = ft_font->ft_face; metrics->ascender = ft_face->size->metrics.ascender; metrics->descender = ft_face->size->metrics.descender; @@ -417,7 +467,9 @@ hb_ft_get_font_h_extents (hb_font_t *font HB_UNUSED, return true; } +#ifdef HB_USE_ATEXIT static void free_static_ft_funcs (void); +#endif static struct hb_ft_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ft_font_funcs_lazy_loader_t> { @@ -428,13 +480,12 @@ static struct hb_ft_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ft hb_font_funcs_set_font_h_extents_func (funcs, hb_ft_get_font_h_extents, nullptr, nullptr); //hb_font_funcs_set_font_v_extents_func (funcs, hb_ft_get_font_v_extents, nullptr, nullptr); hb_font_funcs_set_nominal_glyph_func (funcs, hb_ft_get_nominal_glyph, nullptr, nullptr); + hb_font_funcs_set_nominal_glyphs_func (funcs, hb_ft_get_nominal_glyphs, nullptr, nullptr); hb_font_funcs_set_variation_glyph_func (funcs, hb_ft_get_variation_glyph, nullptr, nullptr); - hb_font_funcs_set_glyph_h_advance_func (funcs, hb_ft_get_glyph_h_advance, nullptr, nullptr); + hb_font_funcs_set_glyph_h_advances_func (funcs, hb_ft_get_glyph_h_advances, nullptr, nullptr); 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); - hb_font_funcs_set_glyph_h_kerning_func (funcs, hb_ft_get_glyph_h_kerning, nullptr, nullptr); - //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); @@ -682,8 +733,9 @@ hb_ft_font_create_referenced (FT_Face ft_face) return hb_ft_font_create (ft_face, _hb_ft_face_destroy); } - +#ifdef HB_USE_ATEXIT static void free_static_ft_library (void); +#endif static struct hb_ft_library_lazy_loader_t : hb_lazy_loader_t<hb_remove_ptr_t<FT_Library>::value, hb_ft_library_lazy_loader_t> diff --git a/src/hb-glib.cc b/src/hb-glib.cc index 809b22f6b..a34acbba1 100644 --- a/src/hb-glib.cc +++ b/src/hb-glib.cc @@ -26,12 +26,11 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-private.hh" +#include "hb.hh" #include "hb-glib.h" -#include "hb-unicode-private.hh" -#include "hb-machinery-private.hh" +#include "hb-machinery.hh" #if !GLIB_CHECK_VERSION(2,29,14) @@ -202,14 +201,6 @@ hb_glib_unicode_combining_class (hb_unicode_funcs_t *ufuncs HB_UNUSED, return (hb_unicode_combining_class_t) g_unichar_combining_class (unicode); } -static unsigned int -hb_glib_unicode_eastasian_width (hb_unicode_funcs_t *ufuncs HB_UNUSED, - hb_codepoint_t unicode, - void *user_data HB_UNUSED) -{ - return g_unichar_iswide (unicode) ? 2 : 1; -} - static hb_unicode_general_category_t hb_glib_unicode_general_category (hb_unicode_funcs_t *ufuncs HB_UNUSED, hb_codepoint_t unicode, @@ -334,40 +325,10 @@ hb_glib_unicode_decompose (hb_unicode_funcs_t *ufuncs HB_UNUSED, return ret; } -static unsigned int -hb_glib_unicode_decompose_compatibility (hb_unicode_funcs_t *ufuncs HB_UNUSED, - hb_codepoint_t u, - hb_codepoint_t *decomposed, - void *user_data HB_UNUSED) -{ -#if GLIB_CHECK_VERSION(2,29,12) - return g_unichar_fully_decompose (u, true, decomposed, HB_UNICODE_MAX_DECOMPOSITION_LEN); -#endif - - /* If the user doesn't have GLib >= 2.29.12 we have to perform - * a round trip to UTF-8 and the associated memory management dance. */ - gchar utf8[6]; - gchar *utf8_decomposed, *c; - gsize utf8_len, utf8_decomposed_len, i; - - /* Convert @u to UTF-8 and normalise it in NFKD mode. This performs the compatibility decomposition. */ - utf8_len = g_unichar_to_utf8 (u, utf8); - utf8_decomposed = g_utf8_normalize (utf8, utf8_len, G_NORMALIZE_NFKD); - utf8_decomposed_len = g_utf8_strlen (utf8_decomposed, -1); - - assert (utf8_decomposed_len <= HB_UNICODE_MAX_DECOMPOSITION_LEN); - - for (i = 0, c = utf8_decomposed; i < utf8_decomposed_len; i++, c = g_utf8_next_char (c)) - *decomposed++ = g_utf8_get_char (c); - - g_free (utf8_decomposed); - - return utf8_decomposed_len; -} - - +#ifdef HB_USE_ATEXIT static void free_static_glib_funcs (void); +#endif static struct hb_glib_unicode_funcs_lazy_loader_t : hb_unicode_funcs_lazy_loader_t<hb_glib_unicode_funcs_lazy_loader_t> { @@ -375,10 +336,12 @@ static struct hb_glib_unicode_funcs_lazy_loader_t : hb_unicode_funcs_lazy_loader { hb_unicode_funcs_t *funcs = hb_unicode_funcs_create (nullptr); -#define HB_UNICODE_FUNC_IMPLEMENT(name) \ - hb_unicode_funcs_set_##name##_func (funcs, hb_glib_unicode_##name, nullptr, nullptr); - HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS -#undef HB_UNICODE_FUNC_IMPLEMENT + hb_unicode_funcs_set_combining_class_func (funcs, hb_glib_unicode_combining_class, nullptr, nullptr); + hb_unicode_funcs_set_general_category_func (funcs, hb_glib_unicode_general_category, nullptr, nullptr); + hb_unicode_funcs_set_mirroring_func (funcs, hb_glib_unicode_mirroring, nullptr, nullptr); + hb_unicode_funcs_set_script_func (funcs, hb_glib_unicode_script, nullptr, nullptr); + hb_unicode_funcs_set_compose_func (funcs, hb_glib_unicode_compose, nullptr, nullptr); + hb_unicode_funcs_set_decompose_func (funcs, hb_glib_unicode_decompose, nullptr, nullptr); hb_unicode_funcs_make_immutable (funcs); diff --git a/src/hb-gobject-enums.cc.tmpl b/src/hb-gobject-enums.cc.tmpl index ca458a384..e056df478 100644 --- a/src/hb-gobject-enums.cc.tmpl +++ b/src/hb-gobject-enums.cc.tmpl @@ -25,7 +25,7 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-private.hh" +#include "hb.hh" /* g++ didn't like older gtype.h gcc-only code path. */ #include <glib.h> diff --git a/src/hb-gobject-structs.cc b/src/hb-gobject-structs.cc index 0c8e55733..1b8758583 100644 --- a/src/hb-gobject-structs.cc +++ b/src/hb-gobject-structs.cc @@ -24,7 +24,7 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-private.hh" +#include "hb.hh" /* g++ didn't like older gtype.h gcc-only code path. */ #include <glib.h> diff --git a/src/hb-graphite2.cc b/src/hb-graphite2.cc index 1f42a36f3..6b2b6f19d 100644 --- a/src/hb-graphite2.cc +++ b/src/hb-graphite2.cc @@ -27,12 +27,14 @@ */ #define HB_SHAPER graphite2 -#include "hb-shaper-impl-private.hh" +#include "hb-shaper-impl.hh" #include "hb-graphite2.h" #include <graphite2/Segment.h> +#include "hb-ot-tag.h" + HB_SHAPER_DATA_ENSURE_DEFINE(graphite2, face) HB_SHAPER_DATA_ENSURE_DEFINE(graphite2, font) @@ -95,6 +97,32 @@ retry: return d; } +static void hb_graphite2_release_table(const void *data, const void *table_buffer) +{ + hb_graphite2_face_data_t *face_data = (hb_graphite2_face_data_t *) data; + hb_graphite2_tablelist_t *tlist = face_data->tlist.get(); + + hb_graphite2_tablelist_t *prev = nullptr; + hb_graphite2_tablelist_t *curr = tlist; + while (curr) + { + if (hb_blob_get_data(curr->blob, nullptr) == table_buffer) + { + if (prev == nullptr) + face_data->tlist.cmpexch(tlist, curr->next); + else + prev->next = curr->next; + hb_blob_destroy(curr->blob); + free(curr); + break; + } + prev = curr; + curr = curr->next; + } +} + +static gr_face_ops hb_graphite2_face_ops = { sizeof(gr_face_ops), hb_graphite2_get_table, hb_graphite2_release_table }; + hb_graphite2_face_data_t * _hb_graphite2_shaper_face_data_create (hb_face_t *face) { @@ -113,7 +141,7 @@ _hb_graphite2_shaper_face_data_create (hb_face_t *face) return nullptr; data->face = face; - data->grface = gr_make_face (data, &hb_graphite2_get_table, gr_face_preloadAll); + data->grface = gr_make_face_with_ops (data, &hb_graphite2_face_ops, gr_face_preloadAll); if (unlikely (!data->grface)) { free (data); @@ -251,11 +279,16 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan, /* TODO ensure_native_direction. */ - hb_tag_t script_tag[2]; - hb_ot_tags_from_script (hb_buffer_get_script (buffer), &script_tag[0], &script_tag[1]); + hb_tag_t script_tag[HB_OT_MAX_TAGS_PER_SCRIPT]; + unsigned int count = HB_OT_MAX_TAGS_PER_SCRIPT; + hb_ot_tags_from_script_and_language (hb_buffer_get_script (buffer), + HB_LANGUAGE_INVALID, + &count, + script_tag, + nullptr, nullptr); seg = gr_make_seg (nullptr, grface, - script_tag[1] == HB_TAG_NONE ? script_tag[0] : script_tag[1], + count ? script_tag[count - 1] : HB_OT_TAG_DEFAULT_SCRIPT, feats, gr_utf32, chars, buffer->len, 2 | (hb_buffer_get_direction (buffer) == HB_DIRECTION_RTL ? 1 : 0)); diff --git a/src/hb-graphite2.h b/src/hb-graphite2.h index 05c55debe..1720191b4 100644 --- a/src/hb-graphite2.h +++ b/src/hb-graphite2.h @@ -41,7 +41,7 @@ hb_graphite2_face_get_gr_face (hb_face_t *face); #ifndef HB_DISABLE_DEPRECATED -HB_EXTERN gr_font * +HB_EXTERN HB_DEPRECATED_FOR (hb_graphite2_face_get_gr_face) gr_font * hb_graphite2_font_get_gr_font (hb_font_t *font); #endif diff --git a/src/hb-icu.cc b/src/hb-icu.cc index 2e3ad3675..e012314b5 100644 --- a/src/hb-icu.cc +++ b/src/hb-icu.cc @@ -27,12 +27,11 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-private.hh" +#include "hb.hh" #include "hb-icu.h" -#include "hb-unicode-private.hh" -#include "hb-machinery-private.hh" +#include "hb-machinery.hh" #include <unicode/uchar.h> #include <unicode/unorm2.h> @@ -73,25 +72,6 @@ hb_icu_unicode_combining_class (hb_unicode_funcs_t *ufuncs HB_UNUSED, return (hb_unicode_combining_class_t) u_getCombiningClass (unicode); } -static unsigned int -hb_icu_unicode_eastasian_width (hb_unicode_funcs_t *ufuncs HB_UNUSED, - hb_codepoint_t unicode, - void *user_data HB_UNUSED) -{ - switch (u_getIntPropertyValue(unicode, UCHAR_EAST_ASIAN_WIDTH)) - { - case U_EA_WIDE: - case U_EA_FULLWIDTH: - return 2; - case U_EA_NEUTRAL: - case U_EA_AMBIGUOUS: - case U_EA_HALFWIDTH: - case U_EA_NARROW: - return 1; - } - return 1; -} - static hb_unicode_general_category_t hb_icu_unicode_general_category (hb_unicode_funcs_t *ufuncs HB_UNUSED, hb_codepoint_t unicode, @@ -309,42 +289,10 @@ hb_icu_unicode_decompose (hb_unicode_funcs_t *ufuncs HB_UNUSED, return ret; } -static unsigned int -hb_icu_unicode_decompose_compatibility (hb_unicode_funcs_t *ufuncs HB_UNUSED, - hb_codepoint_t u, - hb_codepoint_t *decomposed, - void *user_data HB_UNUSED) -{ - UChar utf16[2], normalized[2 * HB_UNICODE_MAX_DECOMPOSITION_LEN + 1]; - unsigned int len; - int32_t utf32_len; - hb_bool_t err; - UErrorCode icu_err; - - /* Copy @u into a UTF-16 array to be passed to ICU. */ - len = 0; - err = false; - U16_APPEND (utf16, len, ARRAY_LENGTH (utf16), u, err); - if (err) - return 0; - - /* Normalise the codepoint using NFKD mode. */ - icu_err = U_ZERO_ERROR; - len = unorm2_normalize (unorm2_getNFKDInstance (&icu_err), utf16, len, normalized, ARRAY_LENGTH (normalized), &icu_err); - if (U_FAILURE (icu_err)) - return 0; - - /* Convert the decomposed form from UTF-16 to UTF-32. */ - icu_err = U_ZERO_ERROR; - u_strToUTF32 ((UChar32*) decomposed, HB_UNICODE_MAX_DECOMPOSITION_LEN, &utf32_len, normalized, len, &icu_err); - if (U_FAILURE (icu_err)) - return 0; - - return utf32_len; -} - +#ifdef HB_USE_ATEXIT static void free_static_icu_funcs (void); +#endif static struct hb_icu_unicode_funcs_lazy_loader_t : hb_unicode_funcs_lazy_loader_t<hb_icu_unicode_funcs_lazy_loader_t> { @@ -359,10 +307,12 @@ static struct hb_icu_unicode_funcs_lazy_loader_t : hb_unicode_funcs_lazy_loader_ hb_unicode_funcs_t *funcs = hb_unicode_funcs_create (nullptr); -#define HB_UNICODE_FUNC_IMPLEMENT(name) \ - hb_unicode_funcs_set_##name##_func (funcs, hb_icu_unicode_##name, user_data, nullptr); - HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS -#undef HB_UNICODE_FUNC_IMPLEMENT + hb_unicode_funcs_set_combining_class_func (funcs, hb_icu_unicode_combining_class, nullptr, nullptr); + hb_unicode_funcs_set_general_category_func (funcs, hb_icu_unicode_general_category, nullptr, nullptr); + hb_unicode_funcs_set_mirroring_func (funcs, hb_icu_unicode_mirroring, nullptr, nullptr); + hb_unicode_funcs_set_script_func (funcs, hb_icu_unicode_script, nullptr, nullptr); + hb_unicode_funcs_set_compose_func (funcs, hb_icu_unicode_compose, user_data, nullptr); + hb_unicode_funcs_set_decompose_func (funcs, hb_icu_unicode_decompose, user_data, nullptr); hb_unicode_funcs_make_immutable (funcs); diff --git a/src/hb-iter-private.hh b/src/hb-iter.hh index 314133ade..6fd6aed79 100644 --- a/src/hb-iter-private.hh +++ b/src/hb-iter.hh @@ -24,10 +24,10 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_ITER_PRIVATE_HH -#define HB_ITER_PRIVATE_HH +#ifndef HB_ITER_HH +#define HB_ITER_HH -#include "hb-private.hh" +#include "hb.hh" /* Unified iterator object. @@ -146,4 +146,4 @@ m (void) } } -#endif /* HB_ITER_PRIVATE_HH */ +#endif /* HB_ITER_HH */ diff --git a/src/hb-machinery-private.hh b/src/hb-machinery.hh index 99ef485a3..ae34c92f4 100644 --- a/src/hb-machinery-private.hh +++ b/src/hb-machinery.hh @@ -26,13 +26,14 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_MACHINERY_PRIVATE_HH -#define HB_MACHINERY_PRIVATE_HH +#ifndef HB_MACHINERY_HH +#define HB_MACHINERY_HH -#include "hb-private.hh" -#include "hb-blob-private.hh" +#include "hb.hh" +#include "hb-blob.hh" -#include "hb-iter-private.hh" +#include "hb-iter.hh" +#include "hb-vector.hh" /* @@ -98,8 +99,8 @@ static inline Type& StructAfter(TObject &X) #define DEFINE_SIZE_STATIC(size) \ DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size)); \ - static const unsigned int static_size = (size); \ - static const unsigned int min_size = (size); \ + enum { static_size = (size) }; \ + enum { min_size = (size) }; \ inline unsigned int get_size (void) const { return (size); } #define DEFINE_SIZE_UNION(size, _member) \ @@ -111,9 +112,13 @@ static inline Type& StructAfter(TObject &X) static const unsigned int min_size = (size) #define DEFINE_SIZE_ARRAY(size, array) \ - DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size) + sizeof (array[0])); \ + DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size) + VAR * sizeof (array[0])); \ DEFINE_COMPILES_ASSERTION ((void) array[0].static_size) \ - static const unsigned int min_size = (size) + enum { min_size = (size) }; \ + +#define DEFINE_SIZE_ARRAY_SIZED(size, array) \ + DEFINE_SIZE_ARRAY(size, array); \ + inline unsigned int get_size (void) const { return (size - array[0].min_size + array.get_size ()); } #define DEFINE_SIZE_ARRAY2(size, array1, array2) \ DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size) + sizeof (this->array1[0]) + sizeof (this->array2[0])); \ @@ -128,7 +133,7 @@ static inline Type& StructAfter(TObject &X) template <typename Context, typename Return, unsigned int MaxDebugDepth> struct hb_dispatch_context_t { - static const unsigned int max_debug_depth = MaxDebugDepth; + enum { max_debug_depth = MaxDebugDepth }; typedef Return return_t; template <typename T, typename F> inline bool may_dispatch (const T *obj, const F *format) { return true; } @@ -138,6 +143,68 @@ struct hb_dispatch_context_t /* * Sanitize + * + * + * === Introduction === + * + * The sanitize machinery is at the core of our zero-cost font loading. We + * mmap() font file into memory and create a blob out of it. Font subtables + * are returned as a readonly sub-blob of the main font blob. These table + * blobs are then sanitized before use, to ensure invalid memory access does + * not happen. The toplevel sanitize API use is like, eg. to load the 'head' + * table: + * + * hb_blob_t *head_blob = hb_sanitize_context_t ().reference_table<OT::head> (face); + * + * The blob then can be converted to a head table struct with: + * + * const head *head_table = head_blob->as<head> (); + * + * What the reference_table does is, to call hb_face_reference_table() to load + * the table blob, sanitize it and return either the sanitized blob, or empty + * blob if sanitization failed. The blob->as() function returns the null + * object of its template type argument if the blob is empty. Otherwise, it + * just casts the blob contents to the desired type. + * + * Sanitizing a blob of data with a type T works as follows (with minor + * simplification): + * + * - Cast blob content to T*, call sanitize() method of it, + * - If sanitize succeeded, return blob. + * - Otherwise, if blob is not writable, try making it writable, + * or copy if cannot be made writable in-place, + * - Call sanitize() again. Return blob if sanitize succeeded. + * - Return empty blob otherwise. + * + * + * === The sanitize() contract === + * + * The sanitize() method of each object type shall return true if it's safe to + * call other methods of the object, and false otherwise. + * + * Note that what sanitize() checks for might align with what the specification + * describes as valid table data, but does not have to be. In particular, we + * do NOT want to be pedantic and concern ourselves with validity checks that + * are irrelevant to our use of the table. On the contrary, we want to be + * lenient with error handling and accept invalid data to the extent that it + * does not impose extra burden on us. + * + * Based on the sanitize contract, one can see that what we check for depends + * on how we use the data in other table methods. Ie. if other table methods + * assume that offsets do NOT point out of the table data block, then that's + * something sanitize() must check for (GSUB/GPOS/GDEF/etc work this way). On + * the other hand, if other methods do such checks themselves, then sanitize() + * does not have to bother with them (glyf/local work this way). The choice + * depends on the table structure and sanitize() performance. For example, to + * check glyf/loca offsets in sanitize() would cost O(num-glyphs). We try hard + * to avoid such costs during font loading. By postponing such checks to the + * actual glyph loading, we reduce the sanitize cost to O(1) and total runtime + * cost to O(used-glyphs). As such, this is preferred. + * + * The same argument can be made re GSUB/GPOS/GDEF, but there, the table + * structure is so complicated that by checking all offsets at sanitize() time, + * we make the code much simpler in other methods, as offsets and referenced + * objects do not need to be validated at each use site. */ /* This limits sanitizing time on really broken fonts. */ @@ -150,6 +217,9 @@ struct hb_dispatch_context_t #ifndef HB_SANITIZE_MAX_OPS_MIN #define HB_SANITIZE_MAX_OPS_MIN 16384 #endif +#ifndef HB_SANITIZE_MAX_OPS_MAX +#define HB_SANITIZE_MAX_OPS_MAX 0x3FFFFFFF +#endif struct hb_sanitize_context_t : hb_dispatch_context_t<hb_sanitize_context_t, bool, HB_DEBUG_SANITIZE> @@ -157,7 +227,8 @@ struct hb_sanitize_context_t : inline hb_sanitize_context_t (void) : debug_depth (0), start (nullptr), end (nullptr), - writable (false), edit_count (0), max_ops (0), + max_ops (0), + writable (false), edit_count (0), blob (nullptr), num_glyphs (65536), num_glyphs_set (false) {} @@ -185,6 +256,23 @@ struct hb_sanitize_context_t : } inline unsigned int get_num_glyphs (void) { return num_glyphs; } + inline void set_max_ops (int max_ops_) { max_ops = max_ops_; } + + /* TODO + * This set_object() thing is to use sanitize at runtime lookup + * application time. This is very distinct from the regular + * sanitizer operation, so, eventually, separate into another + * type and make hb_aat_apply_context_t use that one instead + * of abusing this one. + */ + template <typename T> + inline void set_object (const T& obj) + { + this->start = (const char *) &obj; + this->end = (const char *) &obj + obj.get_size (); + assert (this->start <= this->end); /* Must not overflow. */ + } + inline void start_processing (void) { this->start = this->blob->data; @@ -215,10 +303,10 @@ struct hb_sanitize_context_t : inline bool check_range (const void *base, unsigned int len) const { const char *p = (const char *) base; - bool ok = this->max_ops-- > 0 && - this->start <= p && + bool ok = this->start <= p && p <= this->end && - (unsigned int) (this->end - p) >= len; + (unsigned int) (this->end - p) >= len && + this->max_ops-- > 0; DEBUG_MSG_LEVEL (SANITIZE, p, this->debug_depth+1, 0, "check_range [%p..%p] (%d bytes) in [%p..%p] -> %s", @@ -229,7 +317,8 @@ struct hb_sanitize_context_t : return likely (ok); } - inline bool check_array (const void *base, unsigned int record_size, unsigned int len) const + template <typename T> + inline bool check_array (const T *base, unsigned int len, unsigned int record_size = T::static_size) const { const char *p = (const char *) base; bool overflows = hb_unsigned_mul_overflows (len, record_size); @@ -355,10 +444,10 @@ struct hb_sanitize_context_t : mutable unsigned int debug_depth; const char *start, *end; + mutable int max_ops; private: bool writable; unsigned int edit_count; - mutable int max_ops; hb_blob_t *blob; unsigned int num_glyphs; bool num_glyphs_set; @@ -375,12 +464,19 @@ struct hb_serialize_context_t { this->start = (char *) start_; this->end = this->start + size; + reset (); + } + inline void reset (void) + { this->ran_out_of_room = false; this->head = this->start; this->debug_depth = 0; } + inline bool err (bool e) { return this->ran_out_of_room = this->ran_out_of_room || e; } + + /* To be called around main operation. */ template <typename Type> inline Type *start_serialize (void) { @@ -391,7 +487,6 @@ struct hb_serialize_context_t return start_embed<Type> (); } - inline void end_serialize (void) { DEBUG_MSG_LEVEL (SERIALIZE, this->start, 0, -1, @@ -401,15 +496,20 @@ struct hb_serialize_context_t this->ran_out_of_room ? "RAN OUT OF ROOM" : "did not ran out of room"); } + inline unsigned int length (void) const { return this->head - this->start; } + + inline void align (unsigned int alignment) + { + unsigned int l = length () % alignment; + if (l) + allocate_size<void> (alignment - l); + } + template <typename Type> - inline Type *copy (void) + inline Type *start_embed (void) const { - assert (!this->ran_out_of_room); - unsigned int len = this->head - this->start; - void *p = malloc (len); - if (p) - memcpy (p, this->start, len); - return reinterpret_cast<Type *> (p); + Type *ret = reinterpret_cast<Type *> (this->head); + return ret; } template <typename Type> @@ -432,19 +532,12 @@ struct hb_serialize_context_t } template <typename Type> - inline Type *start_embed (void) - { - Type *ret = reinterpret_cast<Type *> (this->head); - return ret; - } - - template <typename Type> inline Type *embed (const Type &obj) { unsigned int size = obj.get_size (); Type *ret = this->allocate_size<Type> (size); if (unlikely (!ret)) return nullptr; - memcpy (ret, obj, size); + memcpy (ret, &obj, size); return ret; } @@ -466,6 +559,38 @@ struct hb_serialize_context_t return reinterpret_cast<Type *> (&obj); } + /* Output routines. */ + template <typename Type> + inline Type *copy (void) const + { + assert (!this->ran_out_of_room); + unsigned int len = this->head - this->start; + void *p = malloc (len); + if (p) + memcpy (p, this->start, len); + return reinterpret_cast<Type *> (p); + } + inline hb_bytes_t copy_bytes (void) const + { + assert (!this->ran_out_of_room); + unsigned int len = this->head - this->start; + void *p = malloc (len); + if (p) + memcpy (p, this->start, len); + else + return hb_bytes_t (); + return hb_bytes_t (p, len); + } + inline hb_blob_t *copy_blob (void) const + { + assert (!this->ran_out_of_room); + return hb_blob_create (this->start, + this->head - this->start, + HB_MEMORY_MODE_DUPLICATE, + nullptr, nullptr); + } + + public: unsigned int debug_depth; char *start, *end, *head; bool ran_out_of_room; @@ -479,12 +604,19 @@ struct hb_serialize_context_t template <typename Type> struct Supplier { - inline Supplier (const Type *array, unsigned int len_, unsigned int stride_=sizeof(Type)) + inline Supplier (const Type *array, unsigned int len_, unsigned int stride_=sizeof (Type)) { head = array; len = len_; stride = stride_; } + inline Supplier (const hb_vector_t<Type> *v) + { + head = v->arrayZ(); + len = v->len; + stride = sizeof (Type); + } + inline const Type operator [] (unsigned int i) const { if (unlikely (i >= len)) return Type (); @@ -520,6 +652,7 @@ template <typename Type> struct BEInt<Type, 1> { public: + typedef Type type; inline void set (Type V) { v = V; @@ -534,6 +667,7 @@ template <typename Type> struct BEInt<Type, 2> { public: + typedef Type type; inline void set (Type V) { v[0] = (V >> 8) & 0xFF; @@ -550,6 +684,7 @@ template <typename Type> struct BEInt<Type, 3> { public: + typedef Type type; inline void set (Type V) { v[0] = (V >> 16) & 0xFF; @@ -568,6 +703,7 @@ template <typename Type> struct BEInt<Type, 4> { public: + typedef Type type; inline void set (Type V) { v[0] = (V >> 24) & 0xFF; @@ -682,6 +818,10 @@ struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData> } return p; } + inline Stored * get_stored_relaxed (void) const + { + return this->instance.get_relaxed (); + } inline void set_stored (Stored *instance_) { @@ -695,6 +835,7 @@ struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData> } inline const Returned * get (void) const { return Funcs::convert (get_stored ()); } + inline const Returned * get_relaxed (void) const { return Funcs::convert (get_stored_relaxed ()); } inline Returned * get_unconst (void) const { return const_cast<Returned *> (Funcs::convert (get_stored ())); } /* To be possibly overloaded by subclasses. */ @@ -729,9 +870,9 @@ struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData> /* Specializations. */ -template <unsigned int WheresFace, typename T> +template <typename T, unsigned int WheresFace> struct hb_face_lazy_loader_t : hb_lazy_loader_t<T, - hb_face_lazy_loader_t<WheresFace, T>, + hb_face_lazy_loader_t<T, WheresFace>, hb_face_t, WheresFace> {}; template <typename T, unsigned int WheresFace> @@ -789,4 +930,4 @@ struct hb_unicode_funcs_lazy_loader_t : hb_lazy_loader_t<hb_unicode_funcs_t, Sub }; -#endif /* HB_MACHINERY_PRIVATE_HH */ +#endif /* HB_MACHINERY_HH */ diff --git a/src/hb-map.cc b/src/hb-map.cc index 138a85612..225f37bc6 100644 --- a/src/hb-map.cc +++ b/src/hb-map.cc @@ -24,7 +24,7 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-map-private.hh" +#include "hb-map.hh" /* Public API */ diff --git a/src/hb-map-private.hh b/src/hb-map.hh index 00f089e81..b55e3a954 100644 --- a/src/hb-map-private.hh +++ b/src/hb-map.hh @@ -24,10 +24,10 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_MAP_PRIVATE_HH -#define HB_MAP_PRIVATE_HH +#ifndef HB_MAP_HH +#define HB_MAP_HH -#include "hb-private.hh" +#include "hb.hh" template <typename T> @@ -172,7 +172,7 @@ struct hb_map_t inline bool is_empty (void) const { - return population != 0; + return population == 0; } inline unsigned int get_population () const @@ -251,4 +251,4 @@ struct hb_map_t }; -#endif /* HB_MAP_PRIVATE_HH */ +#endif /* HB_MAP_HH */ diff --git a/src/hb-mutex-private.hh b/src/hb-mutex.hh index 14bde3103..75b89addb 100644 --- a/src/hb-mutex-private.hh +++ b/src/hb-mutex.hh @@ -29,10 +29,10 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_MUTEX_PRIVATE_HH -#define HB_MUTEX_PRIVATE_HH +#ifndef HB_MUTEX_HH +#define HB_MUTEX_HH -#include "hb-private.hh" +#include "hb.hh" /* mutex */ @@ -137,5 +137,13 @@ struct hb_mutex_t inline void fini (void) { hb_mutex_impl_finish (&m); } }; +struct hb_lock_t +{ + inline hb_lock_t (hb_mutex_t &mutex_) : mutex (mutex_) { mutex.lock (); } + inline ~hb_lock_t (void) { mutex.unlock (); } + private: + hb_mutex_t &mutex; +}; + -#endif /* HB_MUTEX_PRIVATE_HH */ +#endif /* HB_MUTEX_HH */ diff --git a/src/hb-null.hh b/src/hb-null.hh index 91efee644..87662265c 100644 --- a/src/hb-null.hh +++ b/src/hb-null.hh @@ -27,7 +27,7 @@ #ifndef HB_NULL_HH #define HB_NULL_HH -#include "hb-private.hh" +#include "hb.hh" /* @@ -36,7 +36,7 @@ /* Global nul-content Null pool. Enlarge as necessary. */ -#define HB_NULL_POOL_SIZE 264 +#define HB_NULL_POOL_SIZE 1024 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)]; @@ -49,29 +49,29 @@ static inline Type const & Null (void) { } #define Null(Type) Null<Type>() -/* Specializaitons for arbitrary-content Null objects expressed in bytes. */ +/* Specializations for arbitrary-content Null objects expressed in bytes. */ #define DECLARE_NULL_NAMESPACE_BYTES(Namespace, Type) \ -} /* Close namespace. */ \ -extern HB_INTERNAL const unsigned char _hb_Null_##Namespace##_##Type[Namespace::Type::min_size]; \ -template <> \ -/*static*/ inline const Namespace::Type& Null<Namespace::Type> (void) { \ - return *reinterpret_cast<const Namespace::Type *> (_hb_Null_##Namespace##_##Type); \ -} \ -namespace Namespace { \ -static_assert (true, "Just so we take semicolon after.") + } /* Close namespace. */ \ + extern HB_INTERNAL const unsigned char _hb_Null_##Namespace##_##Type[Namespace::Type::min_size]; \ + template <> \ + /*static*/ inline const Namespace::Type& Null<Namespace::Type> (void) { \ + return *reinterpret_cast<const Namespace::Type *> (_hb_Null_##Namespace##_##Type); \ + } \ + namespace Namespace { \ + static_assert (true, "Just so we take semicolon after.") #define DEFINE_NULL_NAMESPACE_BYTES(Namespace, Type) \ -const unsigned char _hb_Null_##Namespace##_##Type[Namespace::Type::min_size] + const unsigned char _hb_Null_##Namespace##_##Type[Namespace::Type::min_size] -/* Specializaitons for arbitrary-content Null objects expressed as struct initializer. */ +/* Specializations for arbitrary-content Null objects expressed as struct initializer. */ #define DECLARE_NULL_INSTANCE(Type) \ -extern HB_INTERNAL const Type _hb_Null_##Type; \ -template <> \ -/*static*/ inline const Type& Null<Type> (void) { \ - return _hb_Null_##Type; \ -} \ + extern HB_INTERNAL const Type _hb_Null_##Type; \ + template <> \ + /*static*/ inline const Type& Null<Type> (void) { \ + return _hb_Null_##Type; \ + } \ static_assert (true, "Just so we take semicolon after.") #define DEFINE_NULL_INSTANCE(Type) \ -const Type _hb_Null_##Type + const Type _hb_Null_##Type /* Global writable pool. Enlarge as necessary. */ diff --git a/src/hb-object-private.hh b/src/hb-object.hh index 4955a68dc..ca85af691 100644 --- a/src/hb-object-private.hh +++ b/src/hb-object.hh @@ -29,13 +29,13 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_OBJECT_PRIVATE_HH -#define HB_OBJECT_PRIVATE_HH +#ifndef HB_OBJECT_HH +#define HB_OBJECT_HH -#include "hb-private.hh" -#include "hb-atomic-private.hh" -#include "hb-mutex-private.hh" -#include "hb-vector-private.hh" +#include "hb.hh" +#include "hb-atomic.hh" +#include "hb-mutex.hh" +#include "hb-vector.hh" /* @@ -322,4 +322,4 @@ static inline void *hb_object_get_user_data (Type *obj, } -#endif /* HB_OBJECT_PRIVATE_HH */ +#endif /* HB_OBJECT_HH */ diff --git a/src/hb-open-file-private.hh b/src/hb-open-file.hh index d47bff66e..817791ab0 100644 --- a/src/hb-open-file-private.hh +++ b/src/hb-open-file.hh @@ -26,10 +26,10 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_OPEN_FILE_PRIVATE_HH -#define HB_OPEN_FILE_PRIVATE_HH +#ifndef HB_OPEN_FILE_HH +#define HB_OPEN_FILE_HH -#include "hb-open-type-private.hh" +#include "hb-open-type.hh" #include "hb-ot-head-table.hh" @@ -115,7 +115,7 @@ typedef struct OffsetTable * table list. */ int i = tables.len < 64 ? tables.lsearch (t) : tables.bsearch (t); if (table_index) - *table_index = i == -1 ? Index::NOT_FOUND_INDEX : (unsigned int) i; + *table_index = i == -1 ? (unsigned) Index::NOT_FOUND_INDEX : (unsigned) i; return i != -1; } inline const TableRecord& get_table_by_tag (hb_tag_t tag) const @@ -160,9 +160,8 @@ typedef struct OffsetTable memcpy (start, hb_blob_get_data (blob, nullptr), rec.length); - /* 4-byte allignment. */ - if (rec.length % 4) - c->allocate_size<void> (4 - rec.length % 4); + /* 4-byte alignment. */ + c->align (4); const char *end = (const char *) c->head; if (tags[i] == HB_OT_TAG_head && end - start >= head::static_size) @@ -288,188 +287,159 @@ struct TTCHeader /* * Mac Resource Fork + * + * http://mirror.informatimago.com/next/developer.apple.com/documentation/mac/MoreToolbox/MoreToolbox-99.html */ -struct ResourceRefItem +struct ResourceRecord { - inline bool sanitize (hb_sanitize_context_t *c) const + inline const OpenTypeFontFace & get_face (const void *data_base) const + { return CastR<OpenTypeFontFace> ((data_base+offset).arrayZ); } + + inline bool sanitize (hb_sanitize_context_t *c, + const void *data_base) const { TRACE_SANITIZE (this); - // actual data sanitization is done on ResourceForkHeader sanitizer - return_trace (likely (c->check_struct (this))); + return_trace (c->check_struct (this) && + offset.sanitize (c, data_base) && + get_face (data_base).sanitize (c)); } - HBINT16 id; /* Resource ID, is really should be signed? */ + protected: + HBUINT16 id; /* Resource ID. */ HBINT16 nameOffset; /* Offset from beginning of resource name list - * to resource name, minus means there is no */ - HBUINT8 attr; /* Resource attributes */ - HBUINT24 dataOffset; /* Offset from beginning of resource data to + * to resource name, -1 means there is none. */ + HBUINT8 attrs; /* Resource attributes */ + OffsetTo<LArrayOf<HBUINT8>, HBUINT24, false> + offset; /* Offset from beginning of data block to * data for this resource */ HBUINT32 reserved; /* Reserved for handle to resource */ public: DEFINE_SIZE_STATIC (12); }; -struct ResourceTypeItem +#define HB_TAG_sfnt HB_TAG ('s','f','n','t') + +struct ResourceTypeRecord { - inline bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - // RefList sanitization is done on ResourceMap sanitizer - return_trace (likely (c->check_struct (this))); - } + inline unsigned int get_resource_count (void) const + { return tag == HB_TAG_sfnt ? resCountM1 + 1 : 0; } - inline unsigned int get_resource_count () const - { - return numRes + 1; - } + inline bool is_sfnt (void) const { return tag == HB_TAG_sfnt; } - inline bool is_sfnt () const + inline const ResourceRecord& get_resource_record (unsigned int i, + const void *type_base) const { - return type == HB_TAG ('s','f','n','t'); + return hb_array_t<ResourceRecord> ((type_base+resourcesZ).arrayZ, + get_resource_count ()) [i]; } - inline const ResourceRefItem& get_ref_item (const void *base, - unsigned int i) const + inline bool sanitize (hb_sanitize_context_t *c, + const void *type_base, + const void *data_base) const { - return (base+refList)[i]; + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && + resourcesZ.sanitize (c, type_base, + get_resource_count (), + data_base)); } protected: - Tag type; /* Resource type */ - HBUINT16 numRes; /* Number of resource this type in map minus 1 */ - OffsetTo<UnsizedArrayOf<ResourceRefItem> > - refList; /* Offset from beginning of resource type list - * to reference list for this type */ + Tag tag; /* Resource type. */ + HBUINT16 resCountM1; /* Number of resources minus 1. */ + OffsetTo<UnsizedArrayOf<ResourceRecord>, HBUINT16, false> + resourcesZ; /* Offset from beginning of resource type list + * to reference item list for this type. */ public: DEFINE_SIZE_STATIC (8); }; struct ResourceMap { - inline bool sanitize (hb_sanitize_context_t *c) const + inline unsigned int get_face_count (void) const { - TRACE_SANITIZE (this); - if (unlikely (!c->check_struct (this))) - return_trace (false); - for (unsigned int i = 0; i < get_types_count (); ++i) + unsigned int count = get_type_count (); + for (unsigned int i = 0; i < count; i++) { - const ResourceTypeItem& type = get_type (i); - if (unlikely (!type.sanitize (c))) - return_trace (false); - for (unsigned int j = 0; j < type.get_resource_count (); ++j) - if (unlikely (!get_ref_item (type, j).sanitize (c))) - return_trace (false); + const ResourceTypeRecord& type = get_type_record (i); + if (type.is_sfnt ()) + return type.get_resource_count (); } - return_trace (true); - } - - inline const ResourceTypeItem& get_type (unsigned int i) const - { - // Why offset from the second byte of the object? I'm not sure - return ((&reserved[2])+typeList)[i]; + return 0; } - inline unsigned int get_types_count () const + inline const OpenTypeFontFace& get_face (unsigned int idx, + const void *data_base) const { - return nTypes + 1; + unsigned int count = get_type_count (); + for (unsigned int i = 0; i < count; i++) + { + const ResourceTypeRecord& type = get_type_record (i); + /* The check for idx < count is here because ResourceRecord is NOT null-safe. + * Because an offset of 0 there does NOT mean null. */ + if (type.is_sfnt () && idx < type.get_resource_count ()) + return type.get_resource_record (idx, &(this+typeList)).get_face (data_base); + } + return Null (OpenTypeFontFace); } - inline const ResourceRefItem &get_ref_item (const ResourceTypeItem &type, - unsigned int i) const + inline bool sanitize (hb_sanitize_context_t *c, const void *data_base) const { - return type.get_ref_item (&(this+typeList), i); + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && + typeList.sanitize (c, this, + &(this+typeList), + data_base)); } - inline const PString& get_name (const ResourceRefItem &item, - unsigned int i) const - { - if (item.nameOffset == -1) - return Null (PString); + private: + inline unsigned int get_type_count (void) const { return (this+typeList).lenM1 + 1; } - return StructAtOffset<PString> (this, nameList + item.nameOffset); - } + inline const ResourceTypeRecord& get_type_record (unsigned int i) const + { return (this+typeList)[i]; } protected: - HBUINT8 reserved[16]; /* Reserved for copy of resource header */ - LOffsetTo<ResourceMap> - reserved1; /* Reserved for handle to next resource map */ - HBUINT16 reserved2; /* Reserved for file reference number */ - HBUINT16 attr; /* Resource fork attribute */ - OffsetTo<UnsizedArrayOf<ResourceTypeItem> > + HBUINT8 reserved0[16]; /* Reserved for copy of resource header */ + HBUINT32 reserved1; /* Reserved for handle to next resource map */ + HBUINT16 resreved2; /* Reserved for file reference number */ + HBUINT16 attrs; /* Resource fork attribute */ + OffsetTo<ArrayOfM1<ResourceTypeRecord>, HBUINT16, false> typeList; /* Offset from beginning of map to * resource type list */ - HBUINT16 nameList; /* Offset from beginning of map to + Offset16 nameList; /* Offset from beginning of map to * resource name list */ - HBUINT16 nTypes; /* Number of types in the map minus 1 */ public: - DEFINE_SIZE_STATIC (30); + DEFINE_SIZE_STATIC (28); }; struct ResourceForkHeader { - inline unsigned int get_face_count () const - { - const ResourceMap &resource_map = this+map; - for (unsigned int i = 0; i < resource_map.get_types_count (); ++i) - { - const ResourceTypeItem& type = resource_map.get_type (i); - if (type.is_sfnt ()) - return type.get_resource_count (); - } - return 0; - } + inline unsigned int get_face_count (void) const + { return (this+map).get_face_count (); } - inline const LArrayOf<HBUINT8>& get_data (const ResourceTypeItem& type, - unsigned int idx) const + inline const OpenTypeFontFace& get_face (unsigned int idx, + unsigned int *base_offset = nullptr) const { - const ResourceMap &resource_map = this+map; - unsigned int offset = dataOffset; - offset += resource_map.get_ref_item (type, idx).dataOffset; - return StructAtOffset<LArrayOf<HBUINT8> > (this, offset); - } - - inline const OpenTypeFontFace& get_face (unsigned int idx) const - { - const ResourceMap &resource_map = this+map; - for (unsigned int i = 0; i < resource_map.get_types_count (); ++i) - { - const ResourceTypeItem& type = resource_map.get_type (i); - if (type.is_sfnt () && idx < type.get_resource_count ()) - return (OpenTypeFontFace&) get_data (type, idx).arrayZ; - } - return Null (OpenTypeFontFace); + const OpenTypeFontFace &face = (this+map).get_face (idx, &(this+data)); + if (base_offset) + *base_offset = (const char *) &face - (const char *) this; + return face; } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - if (unlikely (!c->check_struct (this))) - return_trace (false); - - const ResourceMap &resource_map = this+map; - if (unlikely (!resource_map.sanitize (c))) - return_trace (false); - - for (unsigned int i = 0; i < resource_map.get_types_count (); ++i) - { - const ResourceTypeItem& type = resource_map.get_type (i); - for (unsigned int j = 0; j < type.get_resource_count (); ++j) - { - const LArrayOf<HBUINT8>& data = get_data (type, j); - if (unlikely (!(data.sanitize (c) && - ((OpenTypeFontFace&) data.arrayZ).sanitize (c)))) - return_trace (false); - } - } - - return_trace (true); + return_trace (c->check_struct (this) && + data.sanitize (c, this, dataLen) && + map.sanitize (c, this, &(this+data))); } protected: - HBUINT32 dataOffset; /* Offset from beginning of resource fork + LOffsetTo<UnsizedArrayOf<HBUINT8>, false> + data; /* Offset from beginning of resource fork * to resource data */ - LOffsetTo<ResourceMap> + LOffsetTo<ResourceMap, false> map; /* Offset from beginning of resource fork * to resource map */ HBUINT32 dataLen; /* Length of resource data */ @@ -486,7 +456,7 @@ struct OpenTypeFontFile { enum { CFFTag = HB_TAG ('O','T','T','O'), /* OpenType with Postscript outlines */ - TrueTypeTag = HB_TAG ( 0 , 1 , 0 , 0 ), /* OpenType with TrueType outlines */ + TrueTypeTag = HB_TAG ( 0 , 1 , 0 , 0 ), /* OpenType with TrueType outlines */ TTCTag = HB_TAG ('t','t','c','f'), /* TrueType Collection */ DFontTag = HB_TAG ( 0 , 0 , 1 , 0 ), /* DFont Mac Resource Fork */ TrueTag = HB_TAG ('t','r','u','e'), /* Obsolete Apple TrueType */ @@ -503,12 +473,14 @@ struct OpenTypeFontFile case Typ1Tag: case TrueTypeTag: return 1; case TTCTag: return u.ttcHeader.get_face_count (); -// case DFontTag: return u.rfHeader.get_face_count (); + case DFontTag: return u.rfHeader.get_face_count (); default: return 0; } } - inline const OpenTypeFontFace& get_face (unsigned int i) const + inline const OpenTypeFontFace& get_face (unsigned int i, unsigned int *base_offset = nullptr) const { + if (base_offset) + *base_offset = 0; switch (u.tag) { /* Note: for non-collection SFNT data we ignore index. This is because * Apple dfont container is a container of SFNT's. So each SFNT is a @@ -518,7 +490,7 @@ struct OpenTypeFontFile case Typ1Tag: case TrueTypeTag: return u.fontFace; case TTCTag: return u.ttcHeader.get_face (i); -// case DFontTag: return u.rfHeader.get_face (i); + case DFontTag: return u.rfHeader.get_face (i, base_offset); default: return Null(OpenTypeFontFace); } } @@ -545,7 +517,7 @@ struct OpenTypeFontFile case Typ1Tag: case TrueTypeTag: return_trace (u.fontFace.sanitize (c)); case TTCTag: return_trace (u.ttcHeader.sanitize (c)); -// case DFontTag: return_trace (u.rfHeader.sanitize (c)); + case DFontTag: return_trace (u.rfHeader.sanitize (c)); default: return_trace (true); } } @@ -565,4 +537,4 @@ struct OpenTypeFontFile } /* namespace OT */ -#endif /* HB_OPEN_FILE_PRIVATE_HH */ +#endif /* HB_OPEN_FILE_HH */ diff --git a/src/hb-open-type-private.hh b/src/hb-open-type.hh index 5580565f1..08e72064a 100644 --- a/src/hb-open-type-private.hh +++ b/src/hb-open-type.hh @@ -26,13 +26,14 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_OPEN_TYPE_PRIVATE_HH -#define HB_OPEN_TYPE_PRIVATE_HH +#ifndef HB_OPEN_TYPE_HH +#define HB_OPEN_TYPE_HH -#include "hb-private.hh" -#include "hb-blob-private.hh" -#include "hb-face-private.hh" -#include "hb-machinery-private.hh" +#include "hb.hh" +#include "hb-blob.hh" +#include "hb-face.hh" +#include "hb-machinery.hh" +#include "hb-subset.hh" namespace OT { @@ -55,6 +56,7 @@ namespace OT { template <typename Type, unsigned int Size> struct IntType { + typedef Type type; inline void set (Type i) { v.set (i); } inline operator Type(void) const { return v; } inline bool operator == (const IntType<Type,Size> &o) const { return (Type) v == (Type) o.v; } @@ -91,6 +93,9 @@ typedef IntType<uint32_t, 3> HBUINT24; /* 24-bit unsigned integer. */ /* 16-bit signed integer (HBINT16) that describes a quantity in FUnits. */ typedef HBINT16 FWORD; +/* 32-bit signed integer (HBINT32) that describes a quantity in FUnits. */ +typedef HBINT32 FWORD32; + /* 16-bit unsigned integer (HBUINT16) that describes a quantity in FUnits. */ typedef HBUINT16 UFWORD; @@ -149,15 +154,17 @@ typedef HBUINT16 NameID; /* Script/language-system/feature index */ struct Index : HBUINT16 { - static const unsigned int NOT_FOUND_INDEX = 0xFFFFu; + enum { NOT_FOUND_INDEX = 0xFFFFu }; }; DECLARE_NULL_NAMESPACE_BYTES (OT, Index); /* Offset, Null offset = 0 */ -template <typename Type> +template <typename Type, bool has_null=true> struct Offset : Type { - inline bool is_null (void) const { return 0 == *this; } + typedef Type type; + + inline bool is_null (void) const { return has_null && 0 == *this; } inline void *serialize (hb_serialize_context_t *c, const void *base) { @@ -225,20 +232,23 @@ struct FixedVersion * Use: (base+offset) */ -template <typename Type, typename OffsetType=HBUINT16> -struct OffsetTo : Offset<OffsetType> +template <typename Type, bool has_null_> struct assert_has_min_size { static_assert (Type::min_size > 0, ""); }; +template <typename Type> struct assert_has_min_size<Type, false> {}; + +template <typename Type, typename OffsetType=HBUINT16, bool has_null=true> +struct OffsetTo : Offset<OffsetType, has_null> { + static_assert (sizeof (assert_has_min_size<Type, has_null>) || true, ""); + inline const Type& operator () (const void *base) const { - unsigned int offset = *this; - if (unlikely (!offset)) return Null(Type); - return StructAtOffset<const Type> (base, offset); + if (unlikely (this->is_null ())) return Null(Type); + return StructAtOffset<const Type> (base, *this); } inline Type& operator () (void *base) const { - unsigned int offset = *this; - if (unlikely (!offset)) return Crap(Type); - return StructAtOffset<Type> (base, offset); + if (unlikely (this->is_null ())) return Crap(Type); + return StructAtOffset<Type> (base, *this); } inline Type& serialize (hb_serialize_context_t *c, const void *base) @@ -246,46 +256,83 @@ struct OffsetTo : Offset<OffsetType> return * (Type *) Offset<OffsetType>::serialize (c, base); } - inline bool sanitize (hb_sanitize_context_t *c, const void *base) const + template <typename T> + inline void serialize_subset (hb_subset_context_t *c, const T &src, const void *base) + { + if (&src == &Null(T)) + { + this->set (0); + return; + } + serialize (c->serializer, base); + if (!src.subset (c)) + this->set (0); + } + + inline bool sanitize_shallow (hb_sanitize_context_t *c, const void *base) const { TRACE_SANITIZE (this); if (unlikely (!c->check_struct (this))) return_trace (false); - unsigned int offset = *this; - if (unlikely (!offset)) return_trace (true); - if (unlikely (!c->check_range (base, offset))) return_trace (false); - const Type &obj = StructAtOffset<Type> (base, offset); - return_trace (likely (obj.sanitize (c)) || neuter (c)); + if (unlikely (this->is_null ())) return_trace (true); + if (unlikely (!c->check_range (base, *this))) return_trace (false); + return_trace (true); } - template <typename T> - inline bool sanitize (hb_sanitize_context_t *c, const void *base, T user_data) const + + inline bool sanitize (hb_sanitize_context_t *c, const void *base) const { TRACE_SANITIZE (this); - if (unlikely (!c->check_struct (this))) return_trace (false); - unsigned int offset = *this; - if (unlikely (!offset)) return_trace (true); - if (unlikely (!c->check_range (base, offset))) return_trace (false); - const Type &obj = StructAtOffset<Type> (base, offset); - return_trace (likely (obj.sanitize (c, user_data)) || neuter (c)); + return_trace (sanitize_shallow (c, base) && + (this->is_null () || + StructAtOffset<Type> (base, *this).sanitize (c) || + neuter (c))); + } + template <typename T1> + inline bool sanitize (hb_sanitize_context_t *c, const void *base, T1 d1) const + { + TRACE_SANITIZE (this); + return_trace (sanitize_shallow (c, base) && + (this->is_null () || + StructAtOffset<Type> (base, *this).sanitize (c, d1) || + neuter (c))); + } + template <typename T1, typename T2> + inline bool sanitize (hb_sanitize_context_t *c, const void *base, T1 d1, T2 d2) const + { + TRACE_SANITIZE (this); + return_trace (sanitize_shallow (c, base) && + (this->is_null () || + StructAtOffset<Type> (base, *this).sanitize (c, d1, d2) || + neuter (c))); + } + template <typename T1, typename T2, typename T3> + inline bool sanitize (hb_sanitize_context_t *c, const void *base, T1 d1, T2 d2, T3 d3) const + { + TRACE_SANITIZE (this); + return_trace (sanitize_shallow (c, base) && + (this->is_null () || + StructAtOffset<Type> (base, *this).sanitize (c, d1, d2, d3) || + neuter (c))); } /* Set the offset to Null */ - inline bool neuter (hb_sanitize_context_t *c) const { + inline bool neuter (hb_sanitize_context_t *c) const + { + if (!has_null) return false; return c->try_set (this, 0); } DEFINE_SIZE_STATIC (sizeof(OffsetType)); }; -template <typename Type> struct LOffsetTo : OffsetTo<Type, HBUINT32> {}; -template <typename Base, typename OffsetType, typename Type> -static inline const Type& operator + (const Base &base, const OffsetTo<Type, OffsetType> &offset) { return offset (base); } -template <typename Base, typename OffsetType, typename Type> -static inline Type& operator + (Base &base, OffsetTo<Type, OffsetType> &offset) { return offset (base); } +template <typename Type, bool has_null=true> struct LOffsetTo : OffsetTo<Type, HBUINT32, has_null> {}; +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 */ -/* TODO Use it in ArrayOf, HeadlessArrayOf, and other places around the code base?? */ template <typename Type> struct UnsizedArrayOf { @@ -331,22 +378,22 @@ struct UnsizedArrayOf inline bool sanitize_shallow (hb_sanitize_context_t *c, unsigned int count) const { TRACE_SANITIZE (this); - return_trace (c->check_array (arrayZ, arrayZ[0].static_size, count)); + return_trace (c->check_array (arrayZ, count)); } public: - Type arrayZ[VAR]; + Type arrayZ[VAR]; public: DEFINE_SIZE_ARRAY (0, arrayZ); }; /* Unsized array of offset's */ -template <typename Type, typename OffsetType> -struct UnsizedOffsetArrayOf : UnsizedArrayOf<OffsetTo<Type, OffsetType> > {}; +template <typename Type, typename OffsetType, bool has_null=true> +struct UnsizedOffsetArrayOf : UnsizedArrayOf<OffsetTo<Type, OffsetType, has_null> > {}; /* Unsized array of offsets relative to the beginning of the array itself. */ -template <typename Type, typename OffsetType> -struct UnsizedOffsetListOf : UnsizedOffsetArrayOf<Type, OffsetType> +template <typename Type, typename OffsetType, bool has_null=true> +struct UnsizedOffsetListOf : UnsizedOffsetArrayOf<Type, OffsetType, has_null> { inline const Type& operator [] (unsigned int i) const { @@ -356,13 +403,13 @@ struct UnsizedOffsetListOf : UnsizedOffsetArrayOf<Type, OffsetType> inline bool sanitize (hb_sanitize_context_t *c, unsigned int count) const { TRACE_SANITIZE (this); - return_trace ((UnsizedOffsetArrayOf<Type, OffsetType>::sanitize (c, count, this))); + return_trace ((UnsizedOffsetArrayOf<Type, OffsetType, has_null>::sanitize (c, count, this))); } template <typename T> inline bool sanitize (hb_sanitize_context_t *c, unsigned int count, T user_data) const { TRACE_SANITIZE (this); - return_trace ((UnsizedOffsetArrayOf<Type, OffsetType>::sanitize (c, count, this, user_data))); + return_trace ((UnsizedOffsetArrayOf<Type, OffsetType, has_null>::sanitize (c, count, this, user_data))); } }; @@ -404,7 +451,6 @@ struct ArrayOf if (unlikely (!c->extend (*this))) return_trace (false); return_trace (true); } - inline bool serialize (hb_serialize_context_t *c, Supplier<Type> &items, unsigned int items_len) @@ -474,12 +520,12 @@ struct ArrayOf inline bool sanitize_shallow (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return_trace (len.sanitize (c) && c->check_array (arrayZ, Type::static_size, len)); + return_trace (len.sanitize (c) && c->check_array (arrayZ, len)); } public: - LenType len; - Type arrayZ[VAR]; + LenType len; + Type arrayZ[VAR]; public: DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ); }; @@ -505,6 +551,17 @@ struct OffsetListOf : OffsetArrayOf<Type> return this+this->arrayZ[i]; } + inline bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + struct OffsetListOf<Type> *out = c->serializer->embed (*this); + if (unlikely (!out)) return_trace (false); + unsigned int count = this->len; + for (unsigned int i = 0; i < count; i++) + out->arrayZ[i].serialize_subset (c, (*this)[i], out); + return_trace (true); + } + inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -524,16 +581,16 @@ struct HeadlessArrayOf { inline const Type& operator [] (unsigned int i) const { - if (unlikely (i >= len || !i)) return Null(Type); + if (unlikely (i >= lenP1 || !i)) return Null(Type); return arrayZ[i-1]; } inline Type& operator [] (unsigned int i) { - if (unlikely (i >= len || !i)) return Crap(Type); + if (unlikely (i >= lenP1 || !i)) return Crap(Type); return arrayZ[i-1]; } inline unsigned int get_size (void) const - { return len.static_size + (len ? len - 1 : 0) * Type::static_size; } + { return lenP1.static_size + (lenP1 ? lenP1 - 1 : 0) * Type::static_size; } inline bool serialize (hb_serialize_context_t *c, Supplier<Type> &items, @@ -541,7 +598,7 @@ struct HeadlessArrayOf { TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (*this))) return_trace (false); - len.set (items_len); /* TODO(serialize) Overflow? */ + lenP1.set (items_len); /* TODO(serialize) Overflow? */ if (unlikely (!items_len)) return_trace (true); if (unlikely (!c->extend (*this))) return_trace (false); for (unsigned int i = 0; i < items_len - 1; i++) @@ -571,13 +628,57 @@ struct HeadlessArrayOf inline bool sanitize_shallow (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return_trace (len.sanitize (c) && - (!len || c->check_array (arrayZ, Type::static_size, len - 1))); + return_trace (lenP1.sanitize (c) && + (!lenP1 || c->check_array (arrayZ, lenP1 - 1))); + } + + public: + LenType lenP1; + Type arrayZ[VAR]; + public: + DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ); +}; + +/* An array storing length-1. */ +template <typename Type, typename LenType=HBUINT16> +struct ArrayOfM1 +{ + inline const Type& operator [] (unsigned int i) const + { + if (unlikely (i > lenM1)) return Null(Type); + return arrayZ[i]; + } + inline Type& operator [] (unsigned int i) + { + if (unlikely (i > lenM1)) return Crap(Type); + return arrayZ[i]; + } + inline unsigned int get_size (void) const + { return lenM1.static_size + (lenM1 + 1) * Type::static_size; } + + template <typename T> + inline bool sanitize (hb_sanitize_context_t *c, const void *base, T user_data) 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, base, user_data))) + return_trace (false); + return_trace (true); + } + + private: + inline bool sanitize_shallow (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (lenM1.sanitize (c) && + (c->check_array (arrayZ, lenM1 + 1))); } public: - LenType len; - Type arrayZ[VAR]; + LenType lenM1; + Type arrayZ[VAR]; public: DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ); }; @@ -607,7 +708,11 @@ struct SortedArrayOf : ArrayOf<Type, LenType> } }; -/* Binary-search arrays */ +/* + * Binary-search arrays + */ + +template <typename LenType=HBUINT16> struct BinSearchHeader { inline operator uint32_t (void) const { return len; } @@ -630,20 +735,120 @@ struct BinSearchHeader } protected: - HBUINT16 len; - HBUINT16 searchRange; - HBUINT16 entrySelector; - HBUINT16 rangeShift; + LenType len; + LenType searchRange; + LenType entrySelector; + LenType rangeShift; public: DEFINE_SIZE_STATIC (8); }; +template <typename Type, typename LenType=HBUINT16> +struct BinSearchArrayOf : SortedArrayOf<Type, BinSearchHeader<LenType> > {}; + +struct VarSizedBinSearchHeader +{ + + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this)); + } + + HBUINT16 unitSize; /* Size of a lookup unit for this search in bytes. */ + HBUINT16 nUnits; /* Number of units of the preceding size to be searched. */ + HBUINT16 searchRange; /* The value of unitSize times the largest power of 2 + * that is less than or equal to the value of nUnits. */ + HBUINT16 entrySelector; /* The log base 2 of the largest power of 2 less than + * or equal to the value of nUnits. */ + HBUINT16 rangeShift; /* The value of unitSize times the difference of the + * value of nUnits minus the largest power of 2 less + * than or equal to the value of nUnits. */ + public: + DEFINE_SIZE_STATIC (10); +}; + template <typename Type> -struct BinSearchArrayOf : SortedArrayOf<Type, BinSearchHeader> {}; +struct VarSizedBinSearchArrayOf +{ + inline const Type& operator [] (unsigned int i) const + { + if (unlikely (i >= header.nUnits)) return Null(Type); + return StructAtOffset<Type> (&bytesZ, i * header.unitSize); + } + inline Type& operator [] (unsigned int i) + { + return StructAtOffset<Type> (&bytesZ, i * header.unitSize); + } + inline unsigned int get_size (void) const + { return header.static_size + header.nUnits * header.unitSize; } + + inline 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(), ie. they do not + * reference other structs via offsets. + */ + (void) (false && StructAtOffset<Type> (&bytesZ, 0).sanitize (c)); + + return_trace (true); + } + inline bool sanitize (hb_sanitize_context_t *c, const void *base) const + { + TRACE_SANITIZE (this); + if (unlikely (!sanitize_shallow (c))) return_trace (false); + unsigned int count = header.nUnits; + for (unsigned int i = 0; i < count; i++) + if (unlikely (!(*this)[i].sanitize (c, base))) + return_trace (false); + return_trace (true); + } + + template <typename T> + inline const Type *bsearch (const T &key) const + { + unsigned int size = header.unitSize; + int min = 0, max = (int) header.nUnits - 1; + while (min <= max) + { + int mid = (min + max) / 2; + const Type *p = (const Type *) (((const char *) &bytesZ) + (mid * size)); + int c = p->cmp (key); + if (c < 0) + max = mid - 1; + else if (c > 0) + min = mid + 1; + else + return p; + } + return nullptr; + } + + private: + inline bool sanitize_shallow (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (header.sanitize (c) && + Type::static_size <= header.unitSize && + c->check_array (bytesZ.arrayZ, header.nUnits, header.unitSize)); + } + + protected: + VarSizedBinSearchHeader header; + UnsizedArrayOf<HBUINT8> bytesZ; + public: + DEFINE_SIZE_ARRAY (10, bytesZ); +}; } /* namespace OT */ -#endif /* HB_OPEN_TYPE_PRIVATE_HH */ +#endif /* HB_OPEN_TYPE_HH */ diff --git a/src/hb-ot-cmap-table.hh b/src/hb-ot-cmap-table.hh index 67a9c7dd9..e5793c387 100644 --- a/src/hb-ot-cmap-table.hh +++ b/src/hb-ot-cmap-table.hh @@ -27,9 +27,8 @@ #ifndef HB_OT_CMAP_TABLE_HH #define HB_OT_CMAP_TABLE_HH -#include "hb-open-type-private.hh" -#include "hb-set-private.hh" -#include "hb-subset-plan.hh" +#include "hb-open-type.hh" +#include "hb-set.hh" /* * cmap -- Character to Glyph Index Mapping @@ -37,10 +36,6 @@ */ #define HB_OT_TAG_cmap HB_TAG('c','m','a','p') -#ifndef HB_MAX_UNICODE_CODEPOINT_VALUE -#define HB_MAX_UNICODE_CODEPOINT_VALUE 0x10FFFF -#endif - namespace OT { @@ -54,6 +49,12 @@ struct CmapSubtableFormat0 *glyph = gid; return true; } + inline void collect_unicodes (hb_set_t *out) const + { + for (unsigned int i = 0; i < 256; i++) + if (glyphIdArray[i]) + out->add (i); + } inline bool sanitize (hb_sanitize_context_t *c) const { @@ -230,22 +231,21 @@ struct CmapSubtableFormat4 inline void init (const CmapSubtableFormat4 *subtable) { segCount = subtable->segCountX2 / 2; - endCount = subtable->values; + endCount = subtable->values.arrayZ; startCount = endCount + segCount + 1; idDelta = startCount + segCount; idRangeOffset = idDelta + segCount; glyphIdArray = idRangeOffset + segCount; glyphIdArrayLength = (subtable->length - 16 - 8 * segCount) / 2; } + inline void fini (void) {} - static inline bool get_glyph_func (const void *obj, hb_codepoint_t codepoint, hb_codepoint_t *glyph) + inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const { - const accelerator_t *thiz = (const accelerator_t *) obj; - /* Custom two-array bsearch. */ - int min = 0, max = (int) thiz->segCount - 1; - const HBUINT16 *startCount = thiz->startCount; - const HBUINT16 *endCount = thiz->endCount; + int min = 0, max = (int) this->segCount - 1; + const HBUINT16 *startCount = this->startCount; + const HBUINT16 *endCount = this->endCount; unsigned int i; while (min <= max) { @@ -264,33 +264,55 @@ struct CmapSubtableFormat4 found: hb_codepoint_t gid; - unsigned int rangeOffset = thiz->idRangeOffset[i]; + unsigned int rangeOffset = this->idRangeOffset[i]; if (rangeOffset == 0) - gid = codepoint + thiz->idDelta[i]; + gid = codepoint + this->idDelta[i]; else { /* Somebody has been smoking... */ - unsigned int index = rangeOffset / 2 + (codepoint - thiz->startCount[i]) + i - thiz->segCount; - if (unlikely (index >= thiz->glyphIdArrayLength)) + unsigned int index = rangeOffset / 2 + (codepoint - this->startCount[i]) + i - this->segCount; + if (unlikely (index >= this->glyphIdArrayLength)) return false; - gid = thiz->glyphIdArray[index]; + gid = this->glyphIdArray[index]; if (unlikely (!gid)) return false; - gid += thiz->idDelta[i]; + gid += this->idDelta[i]; } - - *glyph = gid & 0xFFFFu; + gid &= 0xFFFFu; + if (!gid) + return false; + *glyph = gid; return true; } - - static inline void get_all_codepoints_func (const void *obj, hb_set_t *out) + static inline bool get_glyph_func (const void *obj, hb_codepoint_t codepoint, hb_codepoint_t *glyph) { - const accelerator_t *thiz = (const accelerator_t *) obj; - for (unsigned int i = 0; i < thiz->segCount; i++) + return ((const accelerator_t *) obj)->get_glyph (codepoint, glyph); + } + inline void collect_unicodes (hb_set_t *out) const + { + unsigned int count = this->segCount; + if (count && this->startCount[count - 1] == 0xFFFFu) + count--; /* Skip sentinel segment. */ + for (unsigned int i = 0; i < count; i++) { - if (thiz->startCount[i] != 0xFFFFu - || thiz->endCount[i] != 0xFFFFu) // Skip the last segment (0xFFFF) - hb_set_add_range (out, thiz->startCount[i], thiz->endCount[i]); + unsigned int rangeOffset = this->idRangeOffset[i]; + if (rangeOffset == 0) + out->add_range (this->startCount[i], this->endCount[i]); + else + { + for (hb_codepoint_t codepoint = this->startCount[i]; + codepoint <= this->endCount[i]; + codepoint++) + { + unsigned int index = rangeOffset / 2 + (codepoint - this->startCount[i]) + i - this->segCount; + if (unlikely (index >= this->glyphIdArrayLength)) + break; + hb_codepoint_t gid = this->glyphIdArray[index]; + if (unlikely (!gid)) + continue; + out->add (codepoint); + } + } } } @@ -305,10 +327,14 @@ struct CmapSubtableFormat4 inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const { - accelerator_t accel; - accel.init (this); + hb_auto_t<accelerator_t> accel (this); return accel.get_glyph_func (&accel, codepoint, glyph); } + inline void collect_unicodes (hb_set_t *out) const + { + hb_auto_t<accelerator_t> accel (this); + accel.collect_unicodes (out); + } inline bool sanitize (hb_sanitize_context_t *c) const { @@ -343,7 +369,8 @@ struct CmapSubtableFormat4 HBUINT16 entrySelector; /* log2(searchRange/2) */ HBUINT16 rangeShift; /* 2 x segCount - searchRange */ - HBUINT16 values[VAR]; + UnsizedArrayOf<HBUINT16> + values; #if 0 HBUINT16 endCount[segCount]; /* End characterCode for each segment, * last=0xFFFFu. */ @@ -351,7 +378,8 @@ struct CmapSubtableFormat4 HBUINT16 startCount[segCount]; /* Start character code for each segment. */ HBINT16 idDelta[segCount]; /* Delta for all character codes in segment. */ HBUINT16 idRangeOffset[segCount];/* Offsets into glyphIdArray or 0 */ - HBUINT16 glyphIdArray[VAR]; /* Glyph index array (arbitrary length) */ + UnsizedArrayOf<HBUINT16> + glyphIdArray; /* Glyph index array (arbitrary length) */ #endif public: @@ -383,7 +411,7 @@ struct CmapSubtableLongGroup HBUINT32 startCharCode; /* First character code in this group. */ HBUINT32 endCharCode; /* Last character code in this group. */ HBUINT32 glyphID; /* Glyph index; interpretation depends on - * subtable format. */ + * subtable format. */ public: DEFINE_SIZE_STATIC (12); }; @@ -400,6 +428,14 @@ struct CmapSubtableTrimmed *glyph = gid; return true; } + inline void collect_unicodes (hb_set_t *out) const + { + hb_codepoint_t start = startCharCode; + unsigned int count = glyphIdArray.len; + for (unsigned int i = 0; i < count; i++) + if (glyphIdArray[i]) + out->add (start + i); + } inline bool sanitize (hb_sanitize_context_t *c) const { @@ -432,18 +468,19 @@ struct CmapSubtableLongSegmented int i = groups.bsearch (codepoint); if (i == -1) return false; - *glyph = T::group_get_glyph (groups[i], codepoint); + hb_codepoint_t gid = T::group_get_glyph (groups[i], codepoint); + if (!gid) + return false; + *glyph = gid; return true; } - inline void get_all_codepoints (hb_set_t *out) const + inline void collect_unicodes (hb_set_t *out) const { for (unsigned int i = 0; i < this->groups.len; i++) { - hb_set_add_range (out, - MIN ((unsigned int) this->groups[i].startCharCode, - (unsigned int) HB_MAX_UNICODE_CODEPOINT_VALUE), - MIN ((unsigned int) this->groups[i].endCharCode, - (unsigned int) HB_MAX_UNICODE_CODEPOINT_VALUE)); + out->add_range (this->groups[i].startCharCode, + MIN ((hb_codepoint_t) this->groups[i].endCharCode, + (hb_codepoint_t) HB_UNICODE_MAX)); } } @@ -458,7 +495,7 @@ struct CmapSubtableLongSegmented { TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (*this))) return_trace (false); - Supplier<CmapSubtableLongGroup> supplier (group_data.arrayZ, group_data.len); + Supplier<CmapSubtableLongGroup> supplier (group_data.arrayZ(), group_data.len); if (unlikely (!groups.serialize (c, supplier, group_data.len))) return_trace (false); return true; } @@ -574,13 +611,29 @@ struct UnicodeValueRange } HBUINT24 startUnicodeValue; /* First value in this range. */ - HBUINT8 additionalCount; /* Number of additional values in this + HBUINT8 additionalCount; /* Number of additional values in this * range. */ public: DEFINE_SIZE_STATIC (4); }; -typedef SortedArrayOf<UnicodeValueRange, HBUINT32> DefaultUVS; +struct DefaultUVS : SortedArrayOf<UnicodeValueRange, HBUINT32> +{ + inline void collect_unicodes (hb_set_t *out) const + { + unsigned int count = len; + 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) HB_UNICODE_MAX); + out->add_range (first, last); + } + } + + public: + DEFINE_SIZE_ARRAY (4, arrayZ); +}; struct UVSMapping { @@ -601,7 +654,18 @@ struct UVSMapping DEFINE_SIZE_STATIC (5); }; -typedef SortedArrayOf<UVSMapping, HBUINT32> NonDefaultUVS; +struct NonDefaultUVS : SortedArrayOf<UVSMapping, HBUINT32> +{ + inline void collect_unicodes (hb_set_t *out) const + { + unsigned int count = len; + for (unsigned int i = 0; i < count; i++) + out->add (arrayZ[i].glyphID); + } + + public: + DEFINE_SIZE_ARRAY (4, arrayZ); +}; struct VariationSelectorRecord { @@ -616,7 +680,7 @@ struct VariationSelectorRecord return GLYPH_VARIANT_USE_DEFAULT; const NonDefaultUVS &nonDefaults = base+nonDefaultUVS; i = nonDefaults.bsearch (codepoint); - if (i != -1) + if (i != -1 && nonDefaults[i].glyphID) { *glyph = nonDefaults[i].glyphID; return GLYPH_VARIANT_FOUND; @@ -624,6 +688,12 @@ struct VariationSelectorRecord return GLYPH_VARIANT_NOT_FOUND; } + inline void collect_unicodes (hb_set_t *out, const void *base) const + { + (base+defaultUVS).collect_unicodes (out); + (base+nonDefaultUVS).collect_unicodes (out); + } + inline int cmp (const hb_codepoint_t &variation_selector) const { return varSelector.cmp (variation_selector); @@ -639,9 +709,9 @@ struct VariationSelectorRecord HBUINT24 varSelector; /* Variation selector. */ LOffsetTo<DefaultUVS> - defaultUVS; /* Offset to Default UVS Table. May be 0. */ + defaultUVS; /* Offset to Default UVS Table. May be 0. */ LOffsetTo<NonDefaultUVS> - nonDefaultUVS; /* Offset to Non-Default UVS Table. May be 0. */ + nonDefaultUVS; /* Offset to Non-Default UVS Table. May be 0. */ public: DEFINE_SIZE_STATIC (11); }; @@ -652,7 +722,19 @@ struct CmapSubtableFormat14 hb_codepoint_t variation_selector, hb_codepoint_t *glyph) const { - return record[record.bsearch(variation_selector)].get_glyph (codepoint, glyph, this); + return record[record.bsearch (variation_selector)].get_glyph (codepoint, glyph, this); + } + + inline void collect_variation_selectors (hb_set_t *out) const + { + unsigned int count = record.len; + for (unsigned int i = 0; i < count; i++) + out->add (record.arrayZ[i].varSelector); + } + inline void collect_variation_unicodes (hb_codepoint_t variation_selector, + hb_set_t *out) const + { + record[record.bsearch (variation_selector)].collect_unicodes (out, this); } inline bool sanitize (hb_sanitize_context_t *c) const @@ -690,6 +772,19 @@ struct CmapSubtable default: return false; } } + inline void collect_unicodes (hb_set_t *out) const + { + switch (u.format) { + 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; + case 12: u.format12.collect_unicodes (out); return; + case 13: u.format13.collect_unicodes (out); return; + case 14: + default: return; + } + } inline bool sanitize (hb_sanitize_context_t *c) const { @@ -754,7 +849,8 @@ struct cmap { static const hb_tag_t tableTag = HB_OT_TAG_cmap; - struct subset_plan { + struct subset_plan + { subset_plan(void) { format4_segments.init(); @@ -895,33 +991,44 @@ struct cmap return result; } + const CmapSubtable *find_best_subtable (bool *symbol = nullptr) const + { + if (symbol) *symbol = false; + + const CmapSubtable *subtable; + + /* 32-bit subtables. */ + if ((subtable = this->find_subtable (3, 10))) return subtable; + if ((subtable = this->find_subtable (0, 6))) return subtable; + if ((subtable = this->find_subtable (0, 4))) return subtable; + + /* 16-bit subtables. */ + if ((subtable = this->find_subtable (3, 1))) return subtable; + if ((subtable = this->find_subtable (0, 3))) return subtable; + if ((subtable = this->find_subtable (0, 2))) return subtable; + if ((subtable = this->find_subtable (0, 1))) return subtable; + if ((subtable = this->find_subtable (0, 0))) return subtable; + + /* Symbol subtable. */ + if ((subtable = this->find_subtable (3, 0))) + { + if (symbol) *symbol = true; + return subtable; + } + + /* Meh. */ + return &Null(CmapSubtable); + } + struct accelerator_t { inline void init (hb_face_t *face) { this->blob = hb_sanitize_context_t().reference_table<cmap> (face); const cmap *table = this->blob->as<cmap> (); - const CmapSubtable *subtable = nullptr; const CmapSubtableFormat14 *subtable_uvs = nullptr; - - bool symbol = false; - /* 32-bit subtables. */ - if (!subtable) subtable = table->find_subtable (3, 10); - if (!subtable) subtable = table->find_subtable (0, 6); - if (!subtable) subtable = table->find_subtable (0, 4); - /* 16-bit subtables. */ - if (!subtable) subtable = table->find_subtable (3, 1); - if (!subtable) subtable = table->find_subtable (0, 3); - if (!subtable) subtable = table->find_subtable (0, 2); - if (!subtable) subtable = table->find_subtable (0, 1); - if (!subtable) subtable = table->find_subtable (0, 0); - if (!subtable) - { - subtable = table->find_subtable (3, 0); - if (subtable) symbol = true; - } - /* Meh. */ - if (!subtable) subtable = &Null(CmapSubtable); + bool symbol; + subtable = table->find_best_subtable (&symbol); /* UVS subtable. */ if (!subtable_uvs) @@ -933,30 +1040,26 @@ struct cmap /* Meh. */ if (!subtable_uvs) subtable_uvs = &Null(CmapSubtableFormat14); - this->uvs_table = subtable_uvs; + this->subtable_uvs = subtable_uvs; this->get_glyph_data = subtable; if (unlikely (symbol)) { this->get_glyph_func = get_glyph_from_symbol<CmapSubtable>; - this->get_all_codepoints_func = null_get_all_codepoints_func; } else { switch (subtable->u.format) { /* Accelerate format 4 and format 12. */ default: this->get_glyph_func = get_glyph_from<CmapSubtable>; - this->get_all_codepoints_func = null_get_all_codepoints_func; break; case 12: this->get_glyph_func = get_glyph_from<CmapSubtableFormat12>; - this->get_all_codepoints_func = get_all_codepoints_from<CmapSubtableFormat12>; break; case 4: { this->format4_accel.init (&subtable->u.format4); this->get_glyph_data = &this->format4_accel; this->get_glyph_func = this->format4_accel.get_glyph_func; - this->get_all_codepoints_func = this->format4_accel.get_all_codepoints_func; } break; } @@ -978,9 +1081,9 @@ struct cmap hb_codepoint_t variation_selector, hb_codepoint_t *glyph) const { - switch (this->uvs_table->get_glyph_variant (unicode, - variation_selector, - glyph)) + switch (this->subtable_uvs->get_glyph_variant (unicode, + variation_selector, + glyph)) { case GLYPH_VARIANT_NOT_FOUND: return false; case GLYPH_VARIANT_FOUND: return true; @@ -990,22 +1093,24 @@ struct cmap return get_nominal_glyph (unicode, glyph); } - inline void get_all_codepoints (hb_set_t *out) const + inline void collect_unicodes (hb_set_t *out) const + { + subtable->collect_unicodes (out); + } + inline void collect_variation_selectors (hb_set_t *out) const + { + subtable_uvs->collect_variation_selectors (out); + } + inline void collect_variation_unicodes (hb_codepoint_t variation_selector, + hb_set_t *out) const { - this->get_all_codepoints_func (get_glyph_data, out); + subtable_uvs->collect_variation_unicodes (variation_selector, out); } protected: typedef bool (*hb_cmap_get_glyph_func_t) (const void *obj, hb_codepoint_t codepoint, hb_codepoint_t *glyph); - typedef void (*hb_cmap_get_all_codepoints_func_t) (const void *obj, - hb_set_t *out); - - static inline void null_get_all_codepoints_func (const void *obj, hb_set_t *out) - { - // NOOP - } template <typename Type> static inline bool get_glyph_from (const void *obj, @@ -1017,14 +1122,6 @@ struct cmap } template <typename Type> - static inline void get_all_codepoints_from (const void *obj, - hb_set_t *out) - { - const Type *typed_obj = (const Type *) obj; - typed_obj->get_all_codepoints (out); - } - - template <typename Type> static inline bool get_glyph_from_symbol (const void *obj, hb_codepoint_t codepoint, hb_codepoint_t *glyph) @@ -1047,13 +1144,14 @@ struct cmap } private: + const CmapSubtable *subtable; + const CmapSubtableFormat14 *subtable_uvs; + hb_cmap_get_glyph_func_t get_glyph_func; const void *get_glyph_data; - hb_cmap_get_all_codepoints_func_t get_all_codepoints_func; CmapSubtableFormat4::accelerator_t format4_accel; - const CmapSubtableFormat14 *uvs_table; hb_blob_t *blob; }; @@ -1066,10 +1164,7 @@ struct cmap key.platformID.set (platform_id); key.encodingID.set (encoding_id); - /* Note: We can use bsearch, but since it has no performance - * implications, we use lsearch and as such accept fonts with - * unsorted subtable list. */ - int result = encodingRecord./*bsearch*/lsearch (key); + int result = encodingRecord.bsearch (key); if (result == -1 || !encodingRecord[result].subtable) return nullptr; @@ -1084,6 +1179,7 @@ struct cmap DEFINE_SIZE_ARRAY (4, encodingRecord); }; +struct cmap_accelerator_t : cmap::accelerator_t {}; } /* namespace OT */ diff --git a/src/hb-ot-color-cbdt-table.hh b/src/hb-ot-color-cbdt-table.hh index 21c2f4773..1e1fe0956 100644 --- a/src/hb-ot-color-cbdt-table.hh +++ b/src/hb-ot-color-cbdt-table.hh @@ -27,7 +27,7 @@ #ifndef HB_OT_COLOR_CBDT_TABLE_HH #define HB_OT_COLOR_CBDT_TABLE_HH -#include "hb-open-type-private.hh" +#include "hb-open-type.hh" /* * CBLC -- Color Bitmap Location @@ -128,7 +128,7 @@ struct IndexSubtableFormat1Or3 { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && - c->check_array (offsetArrayZ, offsetArrayZ[0].static_size, glyph_count + 1)); + offsetArrayZ.sanitize (c, glyph_count + 1)); } bool get_image_data (unsigned int idx, @@ -144,7 +144,8 @@ struct IndexSubtableFormat1Or3 } IndexSubtableHeader header; - Offset<OffsetType> offsetArrayZ[VAR]; + UnsizedArrayOf<Offset<OffsetType> > + offsetArrayZ; public: DEFINE_SIZE_ARRAY(8, offsetArrayZ); }; @@ -205,24 +206,23 @@ struct IndexSubtableRecord TRACE_SANITIZE (this); return_trace (c->check_struct (this) && firstGlyphIndex <= lastGlyphIndex && - offsetToSubtable.sanitize (c, this, lastGlyphIndex - firstGlyphIndex + 1)); + offsetToSubtable.sanitize (c, base, lastGlyphIndex - firstGlyphIndex + 1)); } - inline bool get_extents (hb_glyph_extents_t *extents) const + inline bool get_extents (hb_glyph_extents_t *extents, + const void *base) const { - return (this+offsetToSubtable).get_extents (extents); + return (base+offsetToSubtable).get_extents (extents); } - bool get_image_data (unsigned int gid, + bool get_image_data (unsigned int gid, + const void *base, unsigned int *offset, unsigned int *length, unsigned int *format) const { - if (gid < firstGlyphIndex || gid > lastGlyphIndex) - { - return false; - } - return (this+offsetToSubtable).get_image_data (gid - firstGlyphIndex, + if (gid < firstGlyphIndex || gid > lastGlyphIndex) return false; + return (base+offsetToSubtable).get_image_data (gid - firstGlyphIndex, offset, length, format); } @@ -240,12 +240,7 @@ struct IndexSubtableArray inline bool sanitize (hb_sanitize_context_t *c, unsigned int count) const { TRACE_SANITIZE (this); - if (unlikely (!c->check_array (&indexSubtablesZ, indexSubtablesZ[0].static_size, count))) - return_trace (false); - for (unsigned int i = 0; i < count; i++) - if (unlikely (!indexSubtablesZ[i].sanitize (c, this))) - return_trace (false); - return_trace (true); + return_trace (indexSubtablesZ.sanitize (c, count, this)); } public: @@ -255,17 +250,14 @@ struct IndexSubtableArray { unsigned int firstGlyphIndex = indexSubtablesZ[i].firstGlyphIndex; unsigned int lastGlyphIndex = indexSubtablesZ[i].lastGlyphIndex; - if (firstGlyphIndex <= glyph && glyph <= lastGlyphIndex) { + if (firstGlyphIndex <= glyph && glyph <= lastGlyphIndex) return &indexSubtablesZ[i]; - } } return nullptr; } protected: - IndexSubtableRecord indexSubtablesZ[VAR]; - public: - DEFINE_SIZE_ARRAY(0, indexSubtablesZ); + UnsizedArrayOf<IndexSubtableRecord> indexSubtablesZ; }; struct BitmapSizeTable @@ -278,18 +270,20 @@ struct BitmapSizeTable TRACE_SANITIZE (this); return_trace (c->check_struct (this) && indexSubtableArrayOffset.sanitize (c, base, numberOfIndexSubtables) && - c->check_range (&(base+indexSubtableArrayOffset), indexTablesSize) && horizontal.sanitize (c) && vertical.sanitize (c)); } - const IndexSubtableRecord *find_table (hb_codepoint_t glyph, const void *base) const + const IndexSubtableRecord *find_table (hb_codepoint_t glyph, + const void *base, + const void **out_base) const { + *out_base = &(base+indexSubtableArrayOffset); return (base+indexSubtableArrayOffset).find_table (glyph, numberOfIndexSubtables); } protected: - LOffsetTo<IndexSubtableArray> + LOffsetTo<IndexSubtableArray, false> indexSubtableArrayOffset; HBUINT32 indexTablesSize; HBUINT32 numberOfIndexSubtables; @@ -350,7 +344,8 @@ struct CBLC protected: const IndexSubtableRecord *find_table (hb_codepoint_t glyph, - unsigned int *x_ppem, unsigned int *y_ppem) const + unsigned int *x_ppem, unsigned int *y_ppem, + const void **base) const { /* TODO: Make it possible to select strike. */ @@ -363,7 +358,7 @@ struct CBLC { *x_ppem = sizeTables[i].ppemX; *y_ppem = sizeTables[i].ppemY; - return sizeTables[i].find_table (glyph, this); + return sizeTables[i].find_table (glyph, this, base); } } @@ -421,15 +416,16 @@ struct CBDT if (!cblc) return false; // Not a color bitmap font. - const IndexSubtableRecord *subtable_record = this->cblc->find_table(glyph, &x_ppem, &y_ppem); + const void *base; + const IndexSubtableRecord *subtable_record = this->cblc->find_table (glyph, &x_ppem, &y_ppem, &base); if (!subtable_record || !x_ppem || !y_ppem) return false; - if (subtable_record->get_extents (extents)) + if (subtable_record->get_extents (extents, base)) return true; unsigned int image_offset = 0, image_length = 0, image_format = 0; - if (!subtable_record->get_image_data (glyph, &image_offset, &image_length, &image_format)) + if (!subtable_record->get_image_data (glyph, base, &image_offset, &image_length, &image_format)) return false; { @@ -480,7 +476,7 @@ struct CBDT { unsigned int image_offset = 0, image_length = 0, image_format = 0; - if (!subtable_record.get_image_data (gid, + if (!subtable_record.get_image_data (gid, &subtable_array, &image_offset, &image_length, &image_format)) continue; @@ -527,12 +523,14 @@ struct CBDT protected: - FixedVersion<> version; - HBUINT8 dataZ[VAR]; + FixedVersion<> version; + UnsizedArrayOf<HBUINT8> dataZ; public: DEFINE_SIZE_ARRAY(4, dataZ); }; +struct CBDT_accelerator_t : CBDT::accelerator_t {}; + } /* namespace OT */ #endif /* HB_OT_COLOR_CBDT_TABLE_HH */ diff --git a/src/hb-ot-color-colr-table.hh b/src/hb-ot-color-colr-table.hh index ce6702d2a..a59d2bfa9 100644 --- a/src/hb-ot-color-colr-table.hh +++ b/src/hb-ot-color-colr-table.hh @@ -25,7 +25,7 @@ #ifndef HB_OT_COLOR_COLR_TABLE_HH #define HB_OT_COLOR_COLR_TABLE_HH -#include "hb-open-type-private.hh" +#include "hb-open-type.hh" /* * COLR -- Color @@ -129,9 +129,9 @@ struct COLR protected: HBUINT16 version; /* Table version number */ HBUINT16 numBaseGlyphs; /* Number of Base Glyph Records */ - LOffsetTo<UnsizedArrayOf<BaseGlyphRecord> > + LOffsetTo<UnsizedArrayOf<BaseGlyphRecord>, false> baseGlyphsZ; /* Offset to Base Glyph records. */ - LOffsetTo<UnsizedArrayOf<LayerRecord> > + LOffsetTo<UnsizedArrayOf<LayerRecord>, false> layersZ; /* Offset to Layer Records */ HBUINT16 numLayers; /* Number of Layer Records */ public: diff --git a/src/hb-ot-color-cpal-table.hh b/src/hb-ot-color-cpal-table.hh index 2c312748d..e354ced5c 100644 --- a/src/hb-ot-color-cpal-table.hh +++ b/src/hb-ot-color-cpal-table.hh @@ -28,7 +28,7 @@ #ifndef HB_OT_COLOR_CPAL_TABLE_HH #define HB_OT_COLOR_CPAL_TABLE_HH -#include "hb-open-type-private.hh" +#include "hb-open-type.hh" /* @@ -118,15 +118,15 @@ struct CPALV1Tail } protected: - LOffsetTo<UnsizedArrayOf<HBUINT32> > + LOffsetTo<UnsizedArrayOf<HBUINT32>, false> paletteFlagsZ; /* Offset from the beginning of CPAL table to * the Palette Type Array. Set to 0 if no array * is provided. */ - LOffsetTo<UnsizedArrayOf<HBUINT16> > + LOffsetTo<UnsizedArrayOf<HBUINT16>, false> paletteLabelZ; /* Offset from the beginning of CPAL table to * the Palette Labels Array. Set to 0 if no * array is provided. */ - LOffsetTo<UnsizedArrayOf<HBUINT16> > + LOffsetTo<UnsizedArrayOf<HBUINT16>, false> paletteEntryLabelZ; /* Offset from the beginning of CPAL table to * the Palette Entry Label Array. Set to 0 * if no array is provided. */ @@ -207,7 +207,7 @@ struct CPAL HBUINT16 numPalettes; /* Number of palettes in the table. */ HBUINT16 numColorRecords; /* Total number of color records, combined for * all palettes. */ - LOffsetTo<UnsizedArrayOf<BGRAColor> > + LOffsetTo<UnsizedArrayOf<BGRAColor>, false> colorRecordsZ; /* Offset from the beginning of CPAL table to * the first ColorRecord. */ UnsizedArrayOf<HBUINT16> diff --git a/src/hb-ot-color-sbix-table.hh b/src/hb-ot-color-sbix-table.hh index 0461afa32..1b643c77a 100644 --- a/src/hb-ot-color-sbix-table.hh +++ b/src/hb-ot-color-sbix-table.hh @@ -25,7 +25,7 @@ #ifndef HB_OT_COLOR_SBIX_TABLE_HH #define HB_OT_COLOR_SBIX_TABLE_HH -#include "hb-open-type-private.hh" +#include "hb-open-type.hh" /* * sbix -- Standard Bitmap Graphics diff --git a/src/hb-ot-color-svg-table.hh b/src/hb-ot-color-svg-table.hh index 3976694f8..53d466846 100644 --- a/src/hb-ot-color-svg-table.hh +++ b/src/hb-ot-color-svg-table.hh @@ -25,7 +25,7 @@ #ifndef HB_OT_COLOR_SVG_TABLE_HH #define HB_OT_COLOR_SVG_TABLE_HH -#include "hb-open-type-private.hh" +#include "hb-open-type.hh" /* * SVG -- SVG (Scalable Vector Graphics) @@ -54,7 +54,7 @@ struct SVGDocumentIndexEntry * this index entry. */ HBUINT16 endGlyphID; /* The last glyph ID in the range described by * this index entry. Must be >= startGlyphID. */ - LOffsetTo<UnsizedArrayOf<HBUINT8> > + LOffsetTo<UnsizedArrayOf<HBUINT8>, false> 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. diff --git a/src/hb-ot-color.cc b/src/hb-ot-color.cc index 86171c633..7cdff380e 100644 --- a/src/hb-ot-color.cc +++ b/src/hb-ot-color.cc @@ -25,7 +25,7 @@ * Google Author(s): Sascha Brawer */ -#include "hb-open-type-private.hh" +#include "hb-open-type.hh" #include "hb-ot-color-colr-table.hh" #include "hb-ot-color-cpal-table.hh" #include "hb-ot.h" @@ -33,8 +33,8 @@ #include <stdlib.h> #include <string.h> -#include "hb-ot-layout-private.hh" -#include "hb-shaper-private.hh" +#include "hb-ot-layout.hh" +#include "hb-shaper.hh" #if 0 HB_MARK_AS_FLAG_T (hb_ot_color_palette_flags_t) @@ -45,16 +45,14 @@ static inline const OT::COLR& _get_colr (hb_face_t *face) { if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::COLR); - hb_ot_layout_t * layout = hb_ot_layout_from_face (face); - return *(layout->colr.get ()); + return *(hb_ot_face_data (face)->colr.get ()); } static inline const OT::CPAL& _get_cpal (hb_face_t *face) { if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::CPAL); - hb_ot_layout_t * layout = hb_ot_layout_from_face (face); - return *(layout->cpal.get ()); + return *(hb_ot_face_data (face)->cpal.get ()); } diff --git a/src/hb-ot-face.cc b/src/hb-ot-face.cc new file mode 100644 index 000000000..1bc68d366 --- /dev/null +++ b/src/hb-ot-face.cc @@ -0,0 +1,76 @@ +/* + * Copyright © 2018 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Behdad Esfahbod + */ + +#include "hb-ot-face.hh" + +#include "hb-ot-cmap-table.hh" +#include "hb-ot-glyf-table.hh" +#include "hb-ot-hmtx-table.hh" +#include "hb-ot-kern-table.hh" +#include "hb-ot-post-table.hh" +#include "hb-ot-color-cbdt-table.hh" +#include "hb-ot-layout-gdef-table.hh" +#include "hb-ot-layout-gsub-table.hh" +#include "hb-ot-layout-gpos-table.hh" + + +void hb_ot_face_data_t::init0 (hb_face_t *face) +{ + this->face = face; +#define HB_OT_TABLE(Namespace, Type) Type.init0 (); +#define HB_OT_ACCELERATOR(Namespace, Type) HB_OT_TABLE (Namespace, Type) + HB_OT_TABLES +#undef HB_OT_ACCELERATOR +#undef HB_OT_TABLE +} +void hb_ot_face_data_t::fini (void) +{ +#define HB_OT_TABLE(Namespace, Type) Type.fini (); +#define HB_OT_ACCELERATOR(Namespace, Type) HB_OT_TABLE (Namespace, Type) + HB_OT_TABLES +#undef HB_OT_ACCELERATOR +#undef HB_OT_TABLE +} + +hb_ot_face_data_t * +_hb_ot_face_data_create (hb_face_t *face) +{ + hb_ot_face_data_t *data = (hb_ot_face_data_t *) calloc (1, sizeof (hb_ot_face_data_t)); + if (unlikely (!data)) + return nullptr; + + data->init0 (face); + + return data; +} + +void +_hb_ot_face_data_destroy (hb_ot_face_data_t *data) +{ + data->fini (); + free (data); +} + diff --git a/src/hb-ot-face.hh b/src/hb-ot-face.hh new file mode 100644 index 000000000..e30592218 --- /dev/null +++ b/src/hb-ot-face.hh @@ -0,0 +1,116 @@ +/* + * Copyright © 2007,2008,2009 Red Hat, Inc. + * Copyright © 2012,2013 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Behdad Esfahbod + * Google Author(s): Behdad Esfahbod + */ + +#ifndef HB_OT_FACE_HH +#define HB_OT_FACE_HH + +#include "hb.hh" + +#include "hb-machinery.hh" + + +#define hb_ot_face_data(face) ((hb_ot_face_data_t *) face->shaper_data.ot.get_relaxed ()) + + +/* + * hb_ot_face_data_t + */ + +/* Most of these tables are NOT needed for shaping. But we need to hook them *somewhere*. + * This is as good as any place. */ +#define HB_OT_TABLES \ + /* OpenType shaping. */ \ + HB_OT_TABLE(OT, JSTF) \ + HB_OT_TABLE(OT, BASE) \ + /* AAT shaping. */ \ + HB_OT_TABLE(AAT, morx) \ + HB_OT_TABLE(AAT, kerx) \ + HB_OT_TABLE(AAT, ankr) \ + HB_OT_TABLE(AAT, trak) \ + /* OpenType variations. */ \ + HB_OT_TABLE(OT, fvar) \ + HB_OT_TABLE(OT, avar) \ + HB_OT_TABLE(OT, MVAR) \ + /* OpenType math. */ \ + HB_OT_TABLE(OT, MATH) \ + /* OpenType fundamentals. */ \ + HB_OT_ACCELERATOR(OT, GDEF) \ + HB_OT_ACCELERATOR(OT, GSUB) \ + HB_OT_ACCELERATOR(OT, GPOS) \ + HB_OT_ACCELERATOR(OT, cmap) \ + HB_OT_ACCELERATOR(OT, hmtx) \ + HB_OT_ACCELERATOR(OT, vmtx) \ + HB_OT_ACCELERATOR(OT, post) \ + HB_OT_ACCELERATOR(OT, kern) \ + HB_OT_ACCELERATOR(OT, glyf) \ + HB_OT_ACCELERATOR(OT, CBDT) \ + /* */ + +/* Declare tables. */ +#define HB_OT_TABLE(Namespace, Type) namespace Namespace { struct Type; } +#define HB_OT_ACCELERATOR(Namespace, Type) HB_OT_TABLE (Namespace, Type##_accelerator_t) +HB_OT_TABLES +#undef HB_OT_ACCELERATOR +#undef HB_OT_TABLE + +struct hb_ot_face_data_t +{ + HB_INTERNAL void init0 (hb_face_t *face); + HB_INTERNAL void fini (void); + +#define HB_OT_TABLE_ORDER(Namespace, Type) \ + HB_PASTE (ORDER_, HB_PASTE (Namespace, HB_PASTE (_, Type))) + enum order_t + { + ORDER_ZERO, +#define HB_OT_TABLE(Namespace, Type) HB_OT_TABLE_ORDER (Namespace, Type), +#define HB_OT_ACCELERATOR(Namespace, Type) HB_OT_TABLE (Namespace, Type) + HB_OT_TABLES +#undef HB_OT_ACCELERATOR +#undef HB_OT_TABLE + }; + + hb_face_t *face; /* MUST be JUST before the lazy loaders. */ +#define HB_OT_TABLE(Namespace, Type) \ + hb_table_lazy_loader_t<Namespace::Type, HB_OT_TABLE_ORDER (Namespace, Type)> Type; +#define HB_OT_ACCELERATOR(Namespace, Type) \ + hb_face_lazy_loader_t<Namespace::Type##_accelerator_t, HB_OT_TABLE_ORDER (Namespace, Type)> Type; + HB_OT_TABLES +#undef HB_OT_ACCELERATOR +#undef HB_OT_TABLE +}; + + +HB_INTERNAL hb_ot_face_data_t * +_hb_ot_face_data_create (hb_face_t *face); + +HB_INTERNAL void +_hb_ot_face_data_destroy (hb_ot_face_data_t *data); + + +#endif /* HB_OT_FACE_HH */ diff --git a/src/hb-ot-font.cc b/src/hb-ot-font.cc index 9da8fc7d4..e6df038d3 100644 --- a/src/hb-ot-font.cc +++ b/src/hb-ot-font.cc @@ -24,94 +24,54 @@ * Google Author(s): Behdad Esfahbod, Roozbeh Pournader */ -#include "hb-private.hh" +#include "hb.hh" #include "hb-ot.h" -#include "hb-font-private.hh" -#include "hb-machinery-private.hh" +#include "hb-font.hh" +#include "hb-machinery.hh" +#include "hb-ot-face.hh" #include "hb-ot-cmap-table.hh" -#include "hb-ot-glyf-table.hh" #include "hb-ot-hmtx-table.hh" #include "hb-ot-kern-table.hh" #include "hb-ot-post-table.hh" - +#include "hb-ot-glyf-table.hh" #include "hb-ot-color-cbdt-table.hh" -struct hb_ot_font_t -{ - inline void init (hb_face_t *face) - { - cmap.init (face); - h_metrics.init (face); - v_metrics.init (face, h_metrics.ascender - h_metrics.descender); /* TODO Can we do this lazily? */ - - this->face = face; - glyf.init (); - cbdt.init (); - post.init (); - kern.init (); - } - inline void fini (void) - { - cmap.fini (); - h_metrics.fini (); - v_metrics.fini (); - - glyf.fini (); - cbdt.fini (); - post.fini (); - kern.fini (); - } - - OT::cmap::accelerator_t cmap; - OT::hmtx::accelerator_t h_metrics; - OT::vmtx::accelerator_t v_metrics; - - hb_face_t *face; /* MUST be JUST before the lazy loaders. */ - hb_face_lazy_loader_t<1, OT::glyf::accelerator_t> glyf; - hb_face_lazy_loader_t<2, OT::CBDT::accelerator_t> cbdt; - hb_face_lazy_loader_t<3, OT::post::accelerator_t> post; - hb_face_lazy_loader_t<4, OT::kern::accelerator_t> kern; -}; - - -static hb_ot_font_t * -_hb_ot_font_create (hb_face_t *face) -{ - hb_ot_font_t *ot_font = (hb_ot_font_t *) calloc (1, sizeof (hb_ot_font_t)); - - if (unlikely (!ot_font)) - return nullptr; - - ot_font->init (face); - - return ot_font; -} - -static void -_hb_ot_font_destroy (void *data) -{ - hb_ot_font_t *ot_font = (hb_ot_font_t *) data; - - ot_font->fini (); - - free (ot_font); -} - - static hb_bool_t hb_ot_get_nominal_glyph (hb_font_t *font HB_UNUSED, void *font_data, hb_codepoint_t unicode, hb_codepoint_t *glyph, void *user_data HB_UNUSED) +{ + const hb_ot_face_data_t *ot_face = (const hb_ot_face_data_t *) font_data; + return ot_face->cmap.get ()->get_nominal_glyph (unicode, glyph); +} +static unsigned int +hb_ot_get_nominal_glyphs (hb_font_t *font HB_UNUSED, + void *font_data, + unsigned int count, + const hb_codepoint_t *first_unicode, + unsigned int unicode_stride, + hb_codepoint_t *first_glyph, + unsigned int glyph_stride, + void *user_data HB_UNUSED) { - const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; - return ot_font->cmap.get_nominal_glyph (unicode, glyph); + const hb_ot_face_data_t *ot_face = (const hb_ot_face_data_t *) font_data; + const OT::cmap_accelerator_t &cmap = *ot_face->cmap.get (); + unsigned int done; + for (done = 0; + done < count && cmap.get_nominal_glyph (*first_unicode, first_glyph); + done++) + { + first_unicode = &StructAtOffset<hb_codepoint_t> (first_unicode, unicode_stride); + first_glyph = &StructAtOffset<hb_codepoint_t> (first_glyph, glyph_stride); + } + return done; } static hb_bool_t @@ -122,39 +82,77 @@ hb_ot_get_variation_glyph (hb_font_t *font HB_UNUSED, hb_codepoint_t *glyph, void *user_data HB_UNUSED) { - const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; - return ot_font->cmap.get_variation_glyph (unicode, variation_selector, glyph); + const hb_ot_face_data_t *ot_face = (const hb_ot_face_data_t *) font_data; + return ot_face->cmap.get ()->get_variation_glyph (unicode, variation_selector, glyph); } -static hb_position_t -hb_ot_get_glyph_h_advance (hb_font_t *font, - void *font_data, - hb_codepoint_t glyph, - void *user_data HB_UNUSED) +static void +hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data, + unsigned count, + const hb_codepoint_t *first_glyph, + unsigned glyph_stride, + hb_position_t *first_advance, + unsigned advance_stride, + void *user_data HB_UNUSED) { - const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; - return font->em_scale_x (ot_font->h_metrics.get_advance (glyph, font)); + const hb_ot_face_data_t *ot_face = (const hb_ot_face_data_t *) font_data; + const OT::hmtx_accelerator_t &hmtx = *ot_face->hmtx.get (); + + for (unsigned int i = 0; i < count; i++) + { + *first_advance = font->em_scale_x (hmtx.get_advance (*first_glyph, font)); + first_glyph = &StructAtOffset<hb_codepoint_t> (first_glyph, glyph_stride); + first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride); + } } -static hb_position_t -hb_ot_get_glyph_v_advance (hb_font_t *font, - void *font_data, - hb_codepoint_t glyph, - void *user_data HB_UNUSED) +static void +hb_ot_get_glyph_v_advances (hb_font_t* font, void* font_data, + unsigned count, + const hb_codepoint_t *first_glyph, + unsigned glyph_stride, + hb_position_t *first_advance, + unsigned advance_stride, + void *user_data HB_UNUSED) { - const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; - return font->em_scale_y (-(int) ot_font->v_metrics.get_advance (glyph, font)); + const hb_ot_face_data_t *ot_face = (const hb_ot_face_data_t *) font_data; + const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx.get (); + + for (unsigned int i = 0; i < count; i++) + { + *first_advance = font->em_scale_y (-(int) vmtx.get_advance (*first_glyph, font)); + first_glyph = &StructAtOffset<hb_codepoint_t> (first_glyph, glyph_stride); + first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride); + } } -static hb_position_t -hb_ot_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) +static hb_bool_t +hb_ot_get_glyph_v_origin (hb_font_t *font, + void *font_data, + hb_codepoint_t glyph, + hb_position_t *x, + hb_position_t *y, + void *user_data HB_UNUSED) { - const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; - return font->em_scale_x (ot_font->kern->get_h_kerning (left_glyph, right_glyph)); + const hb_ot_face_data_t *ot_face = (const hb_ot_face_data_t *) font_data; + + *x = font->get_glyph_h_advance (glyph) / 2; + + hb_glyph_extents_t extents = {0}; + bool ret = ot_face->glyf->get_extents (glyph, &extents); + if (ret) + { + const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx.get (); + hb_position_t tsb = vmtx.get_side_bearing (glyph); + *y = font->em_scale_y (extents.y_bearing + tsb); + return true; + } + + hb_font_extents_t font_extents; + font->get_h_extents_with_fallback (&font_extents); + *y = font_extents.ascender; + + return true; } static hb_bool_t @@ -164,10 +162,10 @@ hb_ot_get_glyph_extents (hb_font_t *font, hb_glyph_extents_t *extents, void *user_data HB_UNUSED) { - const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; - bool ret = ot_font->glyf->get_extents (glyph, extents); + const hb_ot_face_data_t *ot_face = (const hb_ot_face_data_t *) font_data; + bool ret = ot_face->glyf->get_extents (glyph, extents); if (!ret) - ret = ot_font->cbdt->get_extents (glyph, extents); + ret = ot_face->CBDT->get_extents (glyph, extents); // TODO Hook up side-bearings variations. extents->x_bearing = font->em_scale_x (extents->x_bearing); extents->y_bearing = font->em_scale_y (extents->y_bearing); @@ -183,8 +181,8 @@ hb_ot_get_glyph_name (hb_font_t *font HB_UNUSED, char *name, unsigned int size, void *user_data HB_UNUSED) { - const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; - return ot_font->post->get_glyph_name (glyph, name, size); + const hb_ot_face_data_t *ot_face = (const hb_ot_face_data_t *) font_data; + return ot_face->post->get_glyph_name (glyph, name, size); } static hb_bool_t @@ -194,8 +192,8 @@ hb_ot_get_glyph_from_name (hb_font_t *font HB_UNUSED, hb_codepoint_t *glyph, void *user_data HB_UNUSED) { - const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; - return ot_font->post->get_glyph_from_name (name, len, glyph); + const hb_ot_face_data_t *ot_face = (const hb_ot_face_data_t *) font_data; + return ot_face->post->get_glyph_from_name (name, len, glyph); } static hb_bool_t @@ -204,12 +202,13 @@ hb_ot_get_font_h_extents (hb_font_t *font, hb_font_extents_t *metrics, void *user_data HB_UNUSED) { - const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; - metrics->ascender = font->em_scale_y (ot_font->h_metrics.ascender); - metrics->descender = font->em_scale_y (ot_font->h_metrics.descender); - metrics->line_gap = font->em_scale_y (ot_font->h_metrics.line_gap); + const hb_ot_face_data_t *ot_face = (const hb_ot_face_data_t *) font_data; + const OT::hmtx_accelerator_t &hmtx = *ot_face->hmtx.get (); + metrics->ascender = font->em_scale_y (hmtx.ascender); + metrics->descender = font->em_scale_y (hmtx.descender); + metrics->line_gap = font->em_scale_y (hmtx.line_gap); // TODO Hook up variations. - return ot_font->h_metrics.has_font_extents; + return hmtx.has_font_extents; } static hb_bool_t @@ -218,16 +217,18 @@ hb_ot_get_font_v_extents (hb_font_t *font, hb_font_extents_t *metrics, void *user_data HB_UNUSED) { - const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; - metrics->ascender = font->em_scale_x (ot_font->v_metrics.ascender); - metrics->descender = font->em_scale_x (ot_font->v_metrics.descender); - metrics->line_gap = font->em_scale_x (ot_font->v_metrics.line_gap); + const hb_ot_face_data_t *ot_face = (const hb_ot_face_data_t *) font_data; + const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx.get (); + metrics->ascender = font->em_scale_x (vmtx.ascender); + metrics->descender = font->em_scale_x (vmtx.descender); + metrics->line_gap = font->em_scale_x (vmtx.line_gap); // TODO Hook up variations. - return ot_font->v_metrics.has_font_extents; + return vmtx.has_font_extents; } - +#ifdef HB_USE_ATEXIT static void free_static_ot_funcs (void); +#endif static struct hb_ot_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ot_font_funcs_lazy_loader_t> { @@ -238,13 +239,12 @@ static struct hb_ot_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ot hb_font_funcs_set_font_h_extents_func (funcs, hb_ot_get_font_h_extents, nullptr, nullptr); hb_font_funcs_set_font_v_extents_func (funcs, hb_ot_get_font_v_extents, nullptr, nullptr); hb_font_funcs_set_nominal_glyph_func (funcs, hb_ot_get_nominal_glyph, nullptr, nullptr); + hb_font_funcs_set_nominal_glyphs_func (funcs, hb_ot_get_nominal_glyphs, nullptr, nullptr); hb_font_funcs_set_variation_glyph_func (funcs, hb_ot_get_variation_glyph, nullptr, nullptr); - hb_font_funcs_set_glyph_h_advance_func (funcs, hb_ot_get_glyph_h_advance, nullptr, nullptr); - hb_font_funcs_set_glyph_v_advance_func (funcs, hb_ot_get_glyph_v_advance, nullptr, nullptr); + hb_font_funcs_set_glyph_h_advances_func (funcs, hb_ot_get_glyph_h_advances, nullptr, nullptr); + hb_font_funcs_set_glyph_v_advances_func (funcs, hb_ot_get_glyph_v_advances, nullptr, nullptr); //hb_font_funcs_set_glyph_h_origin_func (funcs, hb_ot_get_glyph_h_origin, nullptr, nullptr); - //hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ot_get_glyph_v_origin, nullptr, nullptr); - hb_font_funcs_set_glyph_h_kerning_func (funcs, hb_ot_get_glyph_h_kerning, nullptr, nullptr); - //hb_font_funcs_set_glyph_v_kerning_func (funcs, hb_ot_get_glyph_v_kerning, nullptr, nullptr); + hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ot_get_glyph_v_origin, nullptr, nullptr); hb_font_funcs_set_glyph_extents_func (funcs, hb_ot_get_glyph_extents, nullptr, nullptr); //hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ot_get_glyph_contour_point, nullptr, nullptr); hb_font_funcs_set_glyph_name_func (funcs, hb_ot_get_glyph_name, nullptr, nullptr); @@ -283,12 +283,11 @@ _hb_ot_get_font_funcs (void) void hb_ot_font_set_funcs (hb_font_t *font) { - hb_ot_font_t *ot_font = _hb_ot_font_create (font->face); - if (unlikely (!ot_font)) - return; + if (unlikely (!hb_ot_shaper_face_data_ensure (font->face))) return; + hb_ot_face_data_t *ot_face = hb_ot_face_data (font->face); hb_font_set_funcs (font, _hb_ot_get_font_funcs (), - ot_font, - _hb_ot_font_destroy); + ot_face, + nullptr); } diff --git a/src/hb-ot-glyf-table.hh b/src/hb-ot-glyf-table.hh index bcf89e462..2145ac02b 100644 --- a/src/hb-ot-glyf-table.hh +++ b/src/hb-ot-glyf-table.hh @@ -27,11 +27,9 @@ #ifndef HB_OT_GLYF_TABLE_HH #define HB_OT_GLYF_TABLE_HH -#include "hb-open-type-private.hh" +#include "hb-open-type.hh" #include "hb-ot-head-table.hh" #include "hb-subset-glyf.hh" -#include "hb-subset-plan.hh" -#include "hb-subset-private.hh" namespace OT { @@ -56,7 +54,7 @@ struct loca } protected: - HBUINT8 dataZ[VAR]; /* Location data. */ + UnsizedArrayOf<HBUINT8> dataZ; /* Location data. */ DEFINE_SIZE_ARRAY (0, dataZ); }; @@ -377,13 +375,13 @@ struct glyf if (short_offset) { - const HBUINT16 *offsets = (const HBUINT16 *) loca_table->dataZ; + const HBUINT16 *offsets = (const HBUINT16 *) loca_table->dataZ.arrayZ; *start_offset = 2 * offsets[glyph]; *end_offset = 2 * offsets[glyph + 1]; } else { - const HBUINT32 *offsets = (const HBUINT32 *) loca_table->dataZ; + const HBUINT32 *offsets = (const HBUINT32 *) loca_table->dataZ.arrayZ; *start_offset = offsets[glyph]; *end_offset = offsets[glyph + 1]; @@ -420,7 +418,7 @@ struct glyf } while (composite_it.move_to_next()); if ( (uint16_t) last->flags & CompositeGlyphHeader::WE_HAVE_INSTRUCTIONS) - *instruction_start = ((char *) last - (char *) glyf_table->dataZ) + last->get_size(); + *instruction_start = ((char *) last - (char *) glyf_table->dataZ.arrayZ) + last->get_size(); else *instruction_start = end_offset; *instruction_end = end_offset; @@ -485,11 +483,13 @@ struct glyf }; protected: - HBUINT8 dataZ[VAR]; /* Glyphs data. */ + UnsizedArrayOf<HBUINT8> dataZ; /* Glyphs data. */ DEFINE_SIZE_ARRAY (0, dataZ); }; +struct glyf_accelerator_t : glyf::accelerator_t {}; + } /* namespace OT */ diff --git a/src/hb-ot-hdmx-table.hh b/src/hb-ot-hdmx-table.hh index 0951871ce..04511b5d0 100644 --- a/src/hb-ot-hdmx-table.hh +++ b/src/hb-ot-hdmx-table.hh @@ -27,8 +27,7 @@ #ifndef HB_OT_HDMX_TABLE_HH #define HB_OT_HDMX_TABLE_HH -#include "hb-open-type-private.hh" -#include "hb-subset-plan.hh" +#include "hb-open-type.hh" /* * hdmx -- Horizontal Device Metrics @@ -67,7 +66,7 @@ struct DeviceRecord if (unlikely (i >= len())) return nullptr; hb_codepoint_t gid = this->subset_plan->glyphs [i]; - const HBUINT8* width = &(this->source_device_record->widths[gid]); + const HBUINT8* width = &(this->source_device_record->widthsZ[gid]); if (width < ((const HBUINT8 *) this->source_device_record) + size_device_record) return width; @@ -78,19 +77,20 @@ struct DeviceRecord static inline unsigned int get_size (unsigned int count) { - unsigned int raw_size = min_size + count * HBUINT8::static_size; - if (raw_size % 4) - /* Align to 32 bits */ - return raw_size + (4 - (raw_size % 4)); - return raw_size; + return hb_ceil_to_4 (min_size + count * HBUINT8::static_size); } inline bool serialize (hb_serialize_context_t *c, const SubsetView &subset_view) { TRACE_SERIALIZE (this); - if (unlikely (!c->allocate_size<DeviceRecord> (get_size (subset_view.len())))) + unsigned int size = get_size (subset_view.len()); + if (unlikely (!c->allocate_size<DeviceRecord> (size))) + { + DEBUG_MSG (SUBSET, nullptr, "Couldn't allocate enough space for DeviceRecord: %d.", + size); return_trace (false); + } this->pixel_size.set (subset_view.source_device_record->pixel_size); this->max_width.set (subset_view.source_device_record->max_width); @@ -103,7 +103,7 @@ struct DeviceRecord DEBUG_MSG(SUBSET, nullptr, "HDMX width for new gid %d is missing.", i); return_trace (false); } - widths[i].set (*width); + widthsZ[i].set (*width); } return_trace (true); @@ -116,11 +116,11 @@ struct DeviceRecord c->check_range (this, size_device_record))); } - HBUINT8 pixel_size; /* Pixel size for following widths (as ppem). */ - HBUINT8 max_width; /* Maximum width. */ - HBUINT8 widths[VAR]; /* Array of widths (numGlyphs is from the 'maxp' table). */ + HBUINT8 pixel_size; /* Pixel size for following widths (as ppem). */ + HBUINT8 max_width; /* Maximum width. */ + UnsizedArrayOf<HBUINT8> widthsZ; /* Array of widths (numGlyphs is from the 'maxp' table). */ public: - DEFINE_SIZE_ARRAY (2, widths); + DEFINE_SIZE_ARRAY (2, widthsZ); }; @@ -136,7 +136,7 @@ struct hdmx inline const DeviceRecord& operator [] (unsigned int i) const { if (unlikely (i >= num_records)) return Null(DeviceRecord); - return StructAtOffset<DeviceRecord> (this->data, i * size_device_record); + return StructAtOffset<DeviceRecord> (&this->dataZ, i * size_device_record); } inline bool serialize (hb_serialize_context_t *c, const hdmx *source_hdmx, hb_subset_plan_t *plan) @@ -161,14 +161,14 @@ struct hdmx return_trace (true); } - static inline size_t get_subsetted_size (hb_subset_plan_t *plan) + static inline size_t get_subsetted_size (const hdmx *source_hdmx, hb_subset_plan_t *plan) { - return min_size + DeviceRecord::get_size (plan->glyphs.len); + return min_size + source_hdmx->num_records * DeviceRecord::get_size (plan->glyphs.len); } inline bool subset (hb_subset_plan_t *plan) const { - size_t dest_size = get_subsetted_size (plan); + size_t dest_size = get_subsetted_size (this, plan); hdmx *dest = (hdmx *) malloc (dest_size); if (unlikely (!dest)) { @@ -178,8 +178,10 @@ struct hdmx hb_serialize_context_t c (dest, dest_size); hdmx *hdmx_prime = c.start_serialize<hdmx> (); - if (!hdmx_prime || !hdmx_prime->serialize (&c, this, plan)) { + if (!hdmx_prime || !hdmx_prime->serialize (&c, this, plan)) + { free (dest); + DEBUG_MSG(SUBSET, nullptr, "Failed to serialize write new hdmx."); return false; } c.end_serialize (); @@ -205,12 +207,12 @@ struct hdmx } protected: - HBUINT16 version; /* Table version number (0) */ - HBUINT16 num_records; /* Number of device records. */ - HBUINT32 size_device_record; /* Size of a device record, 32-bit aligned. */ - HBUINT8 data[VAR]; /* Array of device records. */ + HBUINT16 version; /* Table version number (0) */ + HBUINT16 num_records; /* Number of device records. */ + HBUINT32 size_device_record; /* Size of a device record, 32-bit aligned. */ + UnsizedArrayOf<HBUINT8> dataZ; /* Array of device records. */ public: - DEFINE_SIZE_ARRAY (8, data); + DEFINE_SIZE_ARRAY (8, dataZ); }; } /* namespace OT */ diff --git a/src/hb-ot-head-table.hh b/src/hb-ot-head-table.hh index fded120be..602e365ce 100644 --- a/src/hb-ot-head-table.hh +++ b/src/hb-ot-head-table.hh @@ -29,7 +29,7 @@ #ifndef HB_OT_HEAD_TABLE_HH #define HB_OT_HEAD_TABLE_HH -#include "hb-open-type-private.hh" +#include "hb-open-type.hh" /* * head -- Font Header diff --git a/src/hb-ot-hhea-table.hh b/src/hb-ot-hhea-table.hh index efb42b616..3336cadd4 100644 --- a/src/hb-ot-hhea-table.hh +++ b/src/hb-ot-hhea-table.hh @@ -27,7 +27,7 @@ #ifndef HB_OT_HHEA_TABLE_HH #define HB_OT_HHEA_TABLE_HH -#include "hb-open-type-private.hh" +#include "hb-open-type.hh" /* * hhea -- Horizontal Header diff --git a/src/hb-ot-hmtx-table.hh b/src/hb-ot-hmtx-table.hh index 13fa9d6e0..5293fdada 100644 --- a/src/hb-ot-hmtx-table.hh +++ b/src/hb-ot-hmtx-table.hh @@ -27,11 +27,10 @@ #ifndef HB_OT_HMTX_TABLE_HH #define HB_OT_HMTX_TABLE_HH -#include "hb-open-type-private.hh" +#include "hb-open-type.hh" #include "hb-ot-hhea-table.hh" #include "hb-ot-os2-table.hh" #include "hb-ot-var-hvar-table.hh" -#include "hb-subset-plan.hh" /* * hmtx -- Horizontal Metrics @@ -49,7 +48,7 @@ namespace OT { struct LongMetric { UFWORD advance; /* Advance width/height. */ - FWORD lsb; /* Leading (left/top) side bearing. */ + FWORD sb; /* Leading (left/top) side bearing. */ public: DEFINE_SIZE_STATIC (4); }; @@ -135,8 +134,8 @@ struct hmtxvmtx } else { - /* dest just lsb */ - *((FWORD *) dest_pos) = src_metric->lsb; + /* dest just sb */ + *((FWORD *) dest_pos) = src_metric->sb; } } else @@ -148,18 +147,18 @@ struct hmtxvmtx failed = true; break; } - FWORD src_lsb = *(lsbs + gids[i] - _mtx.num_advances); + FWORD src_sb = *(lsbs + gids[i] - _mtx.num_advances); if (i < num_advances) { /* dest needs a full LongMetric */ LongMetric *metric = (LongMetric *)dest_pos; metric->advance = src_metric->advance; - metric->lsb = src_lsb; + metric->sb = src_sb; } else { - /* dest just needs an lsb */ - *((FWORD *) dest_pos) = src_lsb; + /* dest just needs an sb */ + *((FWORD *) dest_pos) = src_sb; } } dest_pos += (i < num_advances ? 4 : 2); @@ -250,20 +249,33 @@ struct hmtxvmtx hb_blob_destroy (var_blob); } - inline unsigned int get_advance (hb_codepoint_t glyph) const + /* TODO Add variations version. */ + inline unsigned int get_side_bearing (hb_codepoint_t glyph) const + { + if (glyph < num_advances) + return table->longMetricZ[glyph].sb; + + if (unlikely (glyph > num_metrics)) + return 0; + + const FWORD *bearings = (const FWORD *) &table->longMetricZ[num_advances]; + return bearings[glyph - num_advances]; + } + + inline unsigned int get_advance (hb_codepoint_t glyph) const { if (unlikely (glyph >= num_metrics)) { - /* If num_metrics is zero, it means we don't have the metrics table - * for this direction: return default advance. Otherwise, it means that the - * glyph index is out of bound: return zero. */ - if (num_metrics) - return 0; - else - return default_advance; + /* If num_metrics is zero, it means we don't have the metrics table + * for this direction: return default advance. Otherwise, it means that the + * glyph index is out of bound: return zero. */ + if (num_metrics) + return 0; + else + return default_advance; } - return table->longMetric[MIN (glyph, (uint32_t) num_advances - 1)].advance; + return table->longMetricZ[MIN (glyph, (uint32_t) num_advances - 1)].advance; } inline unsigned int get_advance (hb_codepoint_t glyph, @@ -272,7 +284,7 @@ struct hmtxvmtx unsigned int advance = get_advance (glyph); if (likely(glyph < num_metrics)) { - advance += (font->num_coords ? var_table->get_advance_var (glyph, font->coords, font->num_coords) : 0); // TODO Optimize?! + advance += (font->num_coords ? var_table->get_advance_var (glyph, font->coords, font->num_coords) : 0); // TODO Optimize?! } return advance; } @@ -296,7 +308,7 @@ struct hmtxvmtx }; protected: - LongMetric longMetric[VAR]; /* Paired advance width and leading + UnsizedArrayOf<LongMetric>longMetricZ;/* Paired advance width and leading * bearing values for each glyph. The * value numOfHMetrics comes from * the 'hhea' table. If the font is @@ -304,7 +316,7 @@ struct hmtxvmtx * be in the array, but that entry is * required. The last entry applies to * all subsequent glyphs. */ -/*FWORD leadingBearingX[VAR];*/ /* Here the advance is assumed +/*UnsizedArrayOf<FWORD> leadingBearingX;*//* Here the advance is assumed * to be the same as the advance * for the last entry above. The * number of entries in this array is @@ -318,7 +330,7 @@ struct hmtxvmtx * font to vary the side bearing * values for each glyph. */ public: - DEFINE_SIZE_ARRAY (0, longMetric); + DEFINE_SIZE_ARRAY (0, longMetricZ); }; struct hmtx : hmtxvmtx<hmtx, hhea> { @@ -332,6 +344,9 @@ struct vmtx : hmtxvmtx<vmtx, vhea> { static const hb_tag_t os2Tag = HB_TAG_NONE; }; +struct hmtx_accelerator_t : hmtx::accelerator_t {}; +struct vmtx_accelerator_t : vmtx::accelerator_t {}; + } /* namespace OT */ diff --git a/src/hb-ot-kern-table.hh b/src/hb-ot-kern-table.hh index b4d810952..63551d313 100644 --- a/src/hb-ot-kern-table.hh +++ b/src/hb-ot-kern-table.hh @@ -27,7 +27,89 @@ #ifndef HB_OT_KERN_TABLE_HH #define HB_OT_KERN_TABLE_HH -#include "hb-open-type-private.hh" +#include "hb-open-type.hh" +#include "hb-ot-shape.hh" +#include "hb-ot-layout-gsubgpos.hh" + + +template <typename Driver> +struct hb_kern_machine_t +{ + hb_kern_machine_t (const Driver &driver_) : driver (driver_) {} + + HB_NO_SANITIZE_SIGNED_INTEGER_OVERFLOW + inline void kern (hb_font_t *font, + hb_buffer_t *buffer, + hb_mask_t kern_mask, + bool scale = true) const + { + OT::hb_ot_apply_context_t c (1, font, buffer); + c.set_lookup_mask (kern_mask); + c.set_lookup_props (OT::LookupFlag::IgnoreMarks); + OT::hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c.iter_input; + skippy_iter.init (&c); + + bool horizontal = HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction); + unsigned int count = buffer->len; + hb_glyph_info_t *info = buffer->info; + hb_glyph_position_t *pos = buffer->pos; + for (unsigned int idx = 0; idx < count;) + { + if (!(info[idx].mask & kern_mask)) + { + idx++; + continue; + } + + skippy_iter.reset (idx, 1); + if (!skippy_iter.next ()) + { + idx++; + continue; + } + + unsigned int i = idx; + unsigned int j = skippy_iter.idx; + + hb_position_t kern = driver.get_kerning (info[i].codepoint, + info[j].codepoint); + + + if (likely (!kern)) + goto skip; + + + if (horizontal) + { + if (scale) + kern = font->em_scale_x (kern); + hb_position_t kern1 = kern >> 1; + hb_position_t kern2 = kern - kern1; + pos[i].x_advance += kern1; + pos[j].x_advance += kern2; + pos[j].x_offset += kern2; + } + else + { + if (scale) + kern = font->em_scale_y (kern); + hb_position_t kern1 = kern >> 1; + hb_position_t kern2 = kern - kern1; + pos[i].y_advance += kern1; + pos[j].y_advance += kern2; + pos[j].y_offset += kern2; + } + + buffer->unsafe_to_break (i, j + 1); + + skip: + idx = skippy_iter.idx; + } + } + + const Driver &driver; +}; + /* * kern -- Kerning @@ -116,14 +198,18 @@ struct KernSubTableFormat2 { inline int get_kerning (hb_codepoint_t left, hb_codepoint_t right, const char *end) const { + /* This subtable is disabled. It's not cleaer to me *exactly* where the offests are + * based from. I *think* they should be based from beginning of kern subtable wrapper, + * *NOT* "this". Since we know of no fonts that use this subtable, we are disabling + * it. Someday fix it and re-enable. Better yet, find fonts that use it... Meh, + * Windows doesn't implement it. Maybe just remove... */ + return 0; unsigned int l = (this+leftClassTable).get_class (left); unsigned int r = (this+rightClassTable).get_class (right); - unsigned int offset = l * rowWidth + r * sizeof (FWORD); - const FWORD *arr = &(this+array); - if (unlikely ((const void *) arr < (const void *) this || (const void *) arr >= (const void *) end)) - return 0; - const FWORD *v = &StructAtOffset<FWORD> (arr, offset); - if (unlikely ((const void *) v < (const void *) arr || (const void *) (v + 1) > (const void *) end)) + unsigned int offset = l + r; + const FWORD *v = &StructAtOffset<FWORD> (&(this+array), offset); + if (unlikely ((const char *) v < (const char *) &array || + (const char *) v > (const char *) end - 2)) return 0; return *v; } @@ -131,6 +217,7 @@ struct KernSubTableFormat2 inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); + return_trace (true); /* Disabled. See above. */ return_trace (rowWidth.sanitize (c) && leftClassTable.sanitize (c, this) && rightClassTable.sanitize (c, this) && @@ -190,10 +277,10 @@ struct KernSubTableWrapper inline const T* thiz (void) const { return static_cast<const T *> (this); } inline bool is_horizontal (void) const - { return (thiz()->coverage & T::COVERAGE_CHECK_FLAGS) == T::COVERAGE_CHECK_HORIZONTAL; } + { return (thiz()->coverage & T::CheckFlags) == T::CheckHorizontal; } inline bool is_override (void) const - { return bool (thiz()->coverage & T::COVERAGE_OVERRIDE_FLAG); } + { return bool (thiz()->coverage & T::Override); } inline int get_kerning (hb_codepoint_t left, hb_codepoint_t right, const char *end) const { return thiz()->subtable.get_kerning (left, right, end, thiz()->format); } @@ -208,7 +295,7 @@ struct KernSubTableWrapper TRACE_SANITIZE (this); return_trace (c->check_struct (thiz()) && thiz()->length >= T::min_size && - c->check_array (thiz(), 1, thiz()->length) && + c->check_range (thiz(), thiz()->length) && thiz()->subtable.sanitize (c, thiz()->format)); } }; @@ -219,16 +306,16 @@ struct KernTable /* https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern */ inline const T* thiz (void) const { return static_cast<const T *> (this); } - inline int get_h_kerning (hb_codepoint_t left, hb_codepoint_t right, unsigned int table_length) const + inline int get_h_kerning (hb_codepoint_t left, hb_codepoint_t right) const { int v = 0; - const typename T::SubTableWrapper *st = CastP<typename T::SubTableWrapper> (thiz()->data); + const typename T::SubTableWrapper *st = CastP<typename T::SubTableWrapper> (&thiz()->dataZ); unsigned int count = thiz()->nTables; for (unsigned int i = 0; i < count; i++) { if (st->is_override ()) v = 0; - v += st->get_h_kerning (left, right, table_length + (const char *) this); + v += st->get_h_kerning (left, right, st->length + (const char *) st); st = &StructAfter<typename T::SubTableWrapper> (*st); } return v; @@ -241,7 +328,7 @@ struct KernTable thiz()->version != T::VERSION)) return_trace (false); - const typename T::SubTableWrapper *st = CastP<typename T::SubTableWrapper> (thiz()->data); + const typename T::SubTableWrapper *st = CastP<typename T::SubTableWrapper> (&thiz()->dataZ); unsigned int count = thiz()->nTables; for (unsigned int i = 0; i < count; i++) { @@ -262,18 +349,20 @@ struct KernOT : KernTable<KernOT> struct SubTableWrapper : KernSubTableWrapper<SubTableWrapper> { + friend struct KernTable<KernOT>; friend struct KernSubTableWrapper<SubTableWrapper>; - enum coverage_flags_t { - COVERAGE_DIRECTION_FLAG = 0x01u, - COVERAGE_MINIMUM_FLAG = 0x02u, - COVERAGE_CROSSSTREAM_FLAG = 0x04u, - COVERAGE_OVERRIDE_FLAG = 0x08u, + enum Coverage + { + Direction = 0x01u, + Minimum = 0x02u, + CrossStream = 0x04u, + Override = 0x08u, - COVERAGE_VARIATION_FLAG = 0x00u, /* Not supported. */ + Variation = 0x00u, /* Not supported. */ - COVERAGE_CHECK_FLAGS = 0x07u, - COVERAGE_CHECK_HORIZONTAL = 0x01u + CheckFlags = 0x07u, + CheckHorizontal = 0x01u }; protected: @@ -287,11 +376,11 @@ struct KernOT : KernTable<KernOT> }; protected: - HBUINT16 version; /* Version--0x0000u */ - HBUINT16 nTables; /* Number of subtables in the kerning table. */ - HBUINT8 data[VAR]; + HBUINT16 version; /* Version--0x0000u */ + HBUINT16 nTables; /* Number of subtables in the kerning table. */ + UnsizedArrayOf<HBUINT8> dataZ; public: - DEFINE_SIZE_ARRAY (4, data); + DEFINE_SIZE_ARRAY (4, dataZ); }; struct KernAAT : KernTable<KernAAT> @@ -302,17 +391,19 @@ struct KernAAT : KernTable<KernAAT> struct SubTableWrapper : KernSubTableWrapper<SubTableWrapper> { + friend struct KernTable<KernAAT>; friend struct KernSubTableWrapper<SubTableWrapper>; - enum coverage_flags_t { - COVERAGE_DIRECTION_FLAG = 0x80u, - COVERAGE_CROSSSTREAM_FLAG = 0x40u, - COVERAGE_VARIATION_FLAG = 0x20u, + enum Coverage + { + Direction = 0x80u, + CrossStream = 0x40u, + Variation = 0x20u, - COVERAGE_OVERRIDE_FLAG = 0x00u, /* Not supported. */ + Override = 0x00u, /* Not supported. */ - COVERAGE_CHECK_FLAGS = 0xE0u, - COVERAGE_CHECK_HORIZONTAL = 0x00u + CheckFlags = 0xE0u, + CheckHorizontal = 0x00u }; protected: @@ -327,22 +418,25 @@ struct KernAAT : KernTable<KernAAT> }; protected: - HBUINT32 version; /* Version--0x00010000u */ - HBUINT32 nTables; /* Number of subtables in the kerning table. */ - HBUINT8 data[VAR]; + HBUINT32 version; /* Version--0x00010000u */ + HBUINT32 nTables; /* Number of subtables in the kerning table. */ + UnsizedArrayOf<HBUINT8> dataZ; public: - DEFINE_SIZE_ARRAY (8, data); + DEFINE_SIZE_ARRAY (8, dataZ); }; struct kern { static const hb_tag_t tableTag = HB_OT_TAG_kern; - inline int get_h_kerning (hb_codepoint_t left, hb_codepoint_t right, unsigned int table_length) const + inline bool has_data (void) const + { return u.version32 != 0; } + + inline int get_h_kerning (hb_codepoint_t left, hb_codepoint_t right) const { switch (u.major) { - case 0: return u.ot.get_h_kerning (left, right, table_length); - case 1: return u.aat.get_h_kerning (left, right, table_length); + case 0: return u.ot.get_h_kerning (left, right); + case 1: return u.aat.get_h_kerning (left, right); default:return 0; } } @@ -350,7 +444,7 @@ struct kern inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - if (!u.major.sanitize (c)) return_trace (false); + if (!u.version32.sanitize (c)) return_trace (false); switch (u.major) { case 0: return_trace (u.ot.sanitize (c)); case 1: return_trace (u.aat.sanitize (c)); @@ -364,32 +458,52 @@ struct kern { blob = hb_sanitize_context_t().reference_table<kern> (face); table = blob->as<kern> (); - table_length = blob->length; } inline void fini (void) { hb_blob_destroy (blob); } + inline bool has_data (void) const + { return table->has_data (); } + inline int get_h_kerning (hb_codepoint_t left, hb_codepoint_t right) const - { return table->get_h_kerning (left, right, table_length); } + { return table->get_h_kerning (left, right); } + + inline int get_kerning (hb_codepoint_t first, hb_codepoint_t second) const + { return get_h_kerning (first, second); } + + inline void apply (hb_font_t *font, + hb_buffer_t *buffer, + hb_mask_t kern_mask) const + { + /* We only apply horizontal kerning in this table. */ + if (!HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction)) + return; + + hb_kern_machine_t<accelerator_t> machine (*this); + + machine.kern (font, buffer, kern_mask); + } private: hb_blob_t *blob; const kern *table; - unsigned int table_length; }; protected: union { + HBUINT32 version32; HBUINT16 major; KernOT ot; KernAAT aat; } u; public: - DEFINE_SIZE_UNION (2, major); + DEFINE_SIZE_UNION (4, version32); }; +struct kern_accelerator_t : kern::accelerator_t {}; + } /* namespace OT */ diff --git a/src/hb-ot-layout-base-table.hh b/src/hb-ot-layout-base-table.hh index 96da07fb5..449e74550 100644 --- a/src/hb-ot-layout-base-table.hh +++ b/src/hb-ot-layout-base-table.hh @@ -28,8 +28,8 @@ #ifndef HB_OT_LAYOUT_BASE_TABLE_HH #define HB_OT_LAYOUT_BASE_TABLE_HH -#include "hb-open-type-private.hh" -#include "hb-ot-layout-common-private.hh" +#include "hb-open-type.hh" +#include "hb-ot-layout-common.hh" namespace OT { diff --git a/src/hb-ot-layout-common-private.hh b/src/hb-ot-layout-common.hh index 89d5eae49..98f6a079f 100644 --- a/src/hb-ot-layout-common-private.hh +++ b/src/hb-ot-layout-common.hh @@ -26,13 +26,13 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_OT_LAYOUT_COMMON_PRIVATE_HH -#define HB_OT_LAYOUT_COMMON_PRIVATE_HH +#ifndef HB_OT_LAYOUT_COMMON_HH +#define HB_OT_LAYOUT_COMMON_HH -#include "hb-private.hh" -#include "hb-ot-layout-private.hh" -#include "hb-open-type-private.hh" -#include "hb-set-private.hh" +#include "hb.hh" +#include "hb-ot-layout.hh" +#include "hb-open-type.hh" +#include "hb-set.hh" #ifndef HB_MAX_NESTING_LEVEL @@ -70,6 +70,11 @@ namespace OT { * Script, ScriptList, LangSys, Feature, FeatureList, Lookup, LookupList */ +struct Record_sanitize_closure_t { + hb_tag_t tag; + const void *list_base; +}; + template <typename Type> struct Record { @@ -77,14 +82,10 @@ struct Record return tag.cmp (a); } - struct sanitize_closure_t { - hb_tag_t tag; - const void *list_base; - }; inline bool sanitize (hb_sanitize_context_t *c, const void *base) const { TRACE_SANITIZE (this); - const sanitize_closure_t closure = {tag, base}; + const Record_sanitize_closure_t closure = {tag, base}; return_trace (c->check_struct (this) && offset.sanitize (c, base, &closure)); } @@ -97,15 +98,14 @@ struct Record }; template <typename Type> -struct RecordArrayOf : SortedArrayOf<Record<Type> > { +struct RecordArrayOf : SortedArrayOf<Record<Type> > +{ + inline const OffsetTo<Type>& get_offset (unsigned int i) const + { return (*this)[i].offset; } + inline OffsetTo<Type>& get_offset (unsigned int i) + { return (*this)[i].offset; } inline const Tag& get_tag (unsigned int i) const - { - /* We cheat slightly and don't define separate Null objects - * for Record types. Instead, we return the correct Null(Tag) - * here. */ - if (unlikely (i >= this->len)) return Null(Tag); - return (*this)[i].tag; - } + { return (*this)[i].tag; } inline unsigned int get_tags (unsigned int start_offset, unsigned int *record_count /* IN/OUT */, hb_tag_t *record_tags /* OUT */) const @@ -136,7 +136,18 @@ template <typename Type> struct RecordListOf : RecordArrayOf<Type> { inline const Type& operator [] (unsigned int i) const - { return this+RecordArrayOf<Type>::operator [](i).offset; } + { return this+this->get_offset (i); } + + inline bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + struct RecordListOf<Type> *out = c->serializer->embed (*this); + if (unlikely (!out)) return_trace (false); + unsigned int count = this->len; + for (unsigned int i = 0; i < count; i++) + out->get_offset (i).serialize_subset (c, (*this)[i], out); + return_trace (true); + } inline bool sanitize (hb_sanitize_context_t *c) const { @@ -158,9 +169,8 @@ struct RangeRecord return_trace (c->check_struct (this)); } - inline bool intersects (const hb_set_t *glyphs) const { - return glyphs->intersects (start, end); - } + inline bool intersects (const hb_set_t *glyphs) const + { return glyphs->intersects (start, end); } template <typename set_t> inline bool add_coverage (set_t *glyphs) const { @@ -224,8 +234,14 @@ struct LangSys return reqFeatureIndex;; } + inline bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + return_trace (c->serializer->embed (*this)); + } + inline bool sanitize (hb_sanitize_context_t *c, - const Record<LangSys>::sanitize_closure_t * = nullptr) const + const Record_sanitize_closure_t * = nullptr) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && featureIndex.sanitize (c)); @@ -238,7 +254,7 @@ struct LangSys * = 0xFFFFu */ IndexArray featureIndex; /* Array of indices into the FeatureList */ public: - DEFINE_SIZE_ARRAY (6, featureIndex); + DEFINE_SIZE_ARRAY_SIZED (6, featureIndex); }; DECLARE_NULL_NAMESPACE_BYTES (OT, LangSys); @@ -263,8 +279,20 @@ struct Script inline bool has_default_lang_sys (void) const { return defaultLangSys != 0; } inline const LangSys& get_default_lang_sys (void) const { return this+defaultLangSys; } + inline bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + struct Script *out = c->serializer->embed (*this); + if (unlikely (!out)) return_trace (false); + out->defaultLangSys.serialize_subset (c, this+defaultLangSys, out); + unsigned int count = langSys.len; + for (unsigned int i = 0; i < count; i++) + out->langSys.arrayZ[i].offset.serialize_subset (c, this+langSys[i].offset, out); + return_trace (true); + } + inline bool sanitize (hb_sanitize_context_t *c, - const Record<Script>::sanitize_closure_t * = nullptr) const + const Record_sanitize_closure_t * = nullptr) const { TRACE_SANITIZE (this); return_trace (defaultLangSys.sanitize (c, this) && langSys.sanitize (c, this)); @@ -278,7 +306,7 @@ struct Script langSys; /* Array of LangSysRecords--listed * alphabetically by LangSysTag */ public: - DEFINE_SIZE_ARRAY (4, langSys); + DEFINE_SIZE_ARRAY_SIZED (4, langSys); }; typedef RecordListOf<Script> ScriptList; @@ -372,7 +400,7 @@ struct FeatureParamsSize * same subfamily value. If this value is * zero, the remaining fields in the array * will be ignored. */ - HBUINT16 subfamilyNameID;/* If the preceding value is non-zero, this + NameID subfamilyNameID;/* If the preceding value is non-zero, this * value must be set in the range 256 - 32767 * (inclusive). It records the value of a * field in the name table, which must @@ -445,7 +473,7 @@ struct FeatureParamsCharacterVariants * specifies a string (or strings, * for multiple languages) for a * user-interface label for this - * feature. (May be nullptr.) */ + * feature. (May be NULL.) */ NameID featUITooltipTextNameID;/* The ‘name’ table name ID that * specifies a string (or strings, * for multiple languages) that an @@ -455,7 +483,7 @@ struct FeatureParamsCharacterVariants NameID sampleTextNameID; /* The ‘name’ table name ID that * specifies sample text that * illustrates the effect of this - * feature. (May be nullptr.) */ + * feature. (May be NULL.) */ HBUINT16 numNamedParameters; /* Number of named parameters. (May * be zero.) */ NameID firstParamUILabelNameID;/* The first ‘name’ table name ID @@ -493,12 +521,27 @@ struct FeatureParams return Null(FeatureParamsSize); } + inline const FeatureParamsStylisticSet& get_stylistic_set_params (hb_tag_t tag) const + { + if ((tag & 0xFFFF0000u) == HB_TAG ('s','s','\0','\0')) /* ssXX */ + return u.stylisticSet; + return Null(FeatureParamsStylisticSet); + } + + inline const FeatureParamsCharacterVariants& get_character_variants_params (hb_tag_t tag) const + { + if ((tag & 0xFFFF0000u) == HB_TAG ('c','v','\0','\0')) /* cvXX */ + return u.characterVariants; + return Null(FeatureParamsCharacterVariants); + } + private: union { FeatureParamsSize size; FeatureParamsStylisticSet stylisticSet; FeatureParamsCharacterVariants characterVariants; } u; + public: DEFINE_SIZE_STATIC (17); }; @@ -516,8 +559,17 @@ struct Feature inline const FeatureParams &get_feature_params (void) const { return this+featureParams; } + inline bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + struct Feature *out = c->serializer->embed (*this); + if (unlikely (!out)) return_trace (false); + out->featureParams.set (0); /* TODO(subset) FeatureParams. */ + return_trace (true); + } + inline bool sanitize (hb_sanitize_context_t *c, - const Record<Feature>::sanitize_closure_t *closure = nullptr) const + const Record_sanitize_closure_t *closure = nullptr) const { TRACE_SANITIZE (this); if (unlikely (!(c->check_struct (this) && lookupIndex.sanitize (c)))) @@ -567,7 +619,7 @@ struct Feature * if not required */ IndexArray lookupIndex; /* Array of LookupList indices */ public: - DEFINE_SIZE_ARRAY (4, lookupIndex); + DEFINE_SIZE_ARRAY_SIZED (4, lookupIndex); }; typedef RecordListOf<Feature> FeatureList; @@ -598,16 +650,16 @@ struct Lookup { inline unsigned int get_subtable_count (void) const { return subTable.len; } - template <typename SubTableType> - inline const SubTableType& get_subtable (unsigned int i) const - { return this+CastR<OffsetArrayOf<SubTableType> > (subTable)[i]; } + template <typename TSubTable> + inline const TSubTable& get_subtable (unsigned int i) const + { return this+CastR<OffsetArrayOf<TSubTable> > (subTable)[i]; } - template <typename SubTableType> - inline const OffsetArrayOf<SubTableType>& get_subtables (void) const - { return CastR<OffsetArrayOf<SubTableType> > (subTable); } - template <typename SubTableType> - inline OffsetArrayOf<SubTableType>& get_subtables (void) - { return CastR<OffsetArrayOf<SubTableType> > (subTable); } + template <typename TSubTable> + inline const OffsetArrayOf<TSubTable>& get_subtables (void) const + { return CastR<OffsetArrayOf<TSubTable> > (subTable); } + template <typename TSubTable> + inline OffsetArrayOf<TSubTable>& get_subtables (void) + { return CastR<OffsetArrayOf<TSubTable> > (subTable); } inline unsigned int get_size (void) const { @@ -633,14 +685,14 @@ struct Lookup return flag; } - template <typename SubTableType, typename context_t> + template <typename TSubTable, typename context_t> inline typename context_t::return_t dispatch (context_t *c) const { unsigned int lookup_type = get_type (); TRACE_DISPATCH (this, lookup_type); unsigned int count = get_subtable_count (); for (unsigned int i = 0; i < count; i++) { - typename context_t::return_t r = get_subtable<SubTableType> (i).dispatch (c, lookup_type); + typename context_t::return_t r = get_subtable<TSubTable> (i).dispatch (c, lookup_type); if (c->stop_sublookup_iteration (r)) return_trace (r); } @@ -666,16 +718,72 @@ struct Lookup return_trace (true); } + /* Older compilers need this to NOT be locally defined in a function. */ + template <typename TSubTable> + struct SubTableSubsetWrapper + { + inline SubTableSubsetWrapper (const TSubTable &subtable_, + unsigned int lookup_type_) : + subtable (subtable_), + lookup_type (lookup_type_) {} + + inline bool subset (hb_subset_context_t *c) const + { return subtable.dispatch (c, lookup_type); } + + private: + const TSubTable &subtable; + unsigned int lookup_type; + }; + + template <typename TSubTable> + inline bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + struct Lookup *out = c->serializer->embed (*this); + if (unlikely (!out)) return_trace (false); + + /* Subset the actual subtables. */ + /* TODO Drop empty ones, either by calling intersects() beforehand, + * or just dropping null offsets after. */ + const OffsetArrayOf<TSubTable>& subtables = get_subtables<TSubTable> (); + OffsetArrayOf<TSubTable>& out_subtables = out->get_subtables<TSubTable> (); + unsigned int count = subTable.len; + for (unsigned int i = 0; i < count; i++) + { + SubTableSubsetWrapper<TSubTable> wrapper (this+subtables[i], get_type ()); + + out_subtables[i].serialize_subset (c, wrapper, out); + } + + return_trace (true); + } + + template <typename TSubTable> inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - /* Real sanitize of the subtables is done by GSUB/GPOS/... */ if (!(c->check_struct (this) && subTable.sanitize (c))) return_trace (false); if (lookupFlag & LookupFlag::UseMarkFilteringSet) { const HBUINT16 &markFilteringSet = StructAfter<HBUINT16> (subTable); if (!markFilteringSet.sanitize (c)) return_trace (false); } + + if (unlikely (!dispatch<TSubTable> (c))) return_trace (false); + + if (unlikely (get_type () == TSubTable::Extension)) + { + /* The spec says all subtables of an Extension lookup should + * have the same type, which shall not be the Extension type + * itself (but we already checked for that). + * This is specially important if one has a reverse type! */ + unsigned int type = get_subtable<TSubTable> (0).u.extension.get_type (); + unsigned int count = get_subtable_count (); + for (unsigned int i = 1; i < count; i++) + if (get_subtable<TSubTable> (i).u.extension.get_type () != type) + return_trace (false); + } + return_trace (true); return_trace (true); } @@ -730,9 +838,17 @@ struct CoverageFormat1 return_trace (glyphArray.sanitize (c)); } - inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const { - return glyphs->has (glyphArray[index]); + inline bool intersects (const hb_set_t *glyphs) const + { + /* TODO Speed up, using hb_set_next() and bsearch()? */ + unsigned int count = glyphArray.len; + for (unsigned int i = 0; i < count; i++) + if (glyphs->has (glyphArray[i])) + return true; + return false; } + inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const + { return glyphs->has (glyphArray[index]); } template <typename set_t> inline bool add_coverage (set_t *glyphs) const { @@ -743,6 +859,7 @@ struct CoverageFormat1 /* Older compilers need this to be public. */ struct Iter { inline void init (const struct CoverageFormat1 &c_) { c = &c_; i = 0; }; + inline void fini (void) {}; inline bool more (void) { return i < c->glyphArray.len; } inline void next (void) { i++; } inline hb_codepoint_t get_glyph (void) { return c->glyphArray[i]; } @@ -819,7 +936,17 @@ struct CoverageFormat2 return_trace (rangeRecord.sanitize (c)); } - inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const { + inline bool intersects (const hb_set_t *glyphs) const + { + /* TODO Speed up, using hb_set_next() and bsearch()? */ + unsigned int count = rangeRecord.len; + for (unsigned int i = 0; i < count; i++) + if (rangeRecord[i].intersects (glyphs)) + return true; + return false; + } + inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const + { unsigned int i; unsigned int count = rangeRecord.len; for (i = 0; i < count; i++) { @@ -859,6 +986,7 @@ struct CoverageFormat2 i = c->rangeRecord.len; } } + inline void fini (void) {}; inline bool more (void) { return i < c->rangeRecord.len; } inline void next (void) { @@ -924,7 +1052,8 @@ struct Coverage if (glyphs[i - 1] + 1 != glyphs[i]) num_ranges++; u.format.set (num_glyphs * 2 < num_ranges * 3 ? 1 : 2); - switch (u.format) { + switch (u.format) + { case 1: return_trace (u.format1.serialize (c, glyphs, num_glyphs)); case 2: return_trace (u.format2.serialize (c, glyphs, num_glyphs)); default:return_trace (false); @@ -935,25 +1064,27 @@ struct Coverage { TRACE_SANITIZE (this); if (!u.format.sanitize (c)) return_trace (false); - switch (u.format) { + switch (u.format) + { case 1: return_trace (u.format1.sanitize (c)); case 2: return_trace (u.format2.sanitize (c)); default:return_trace (true); } } - inline bool intersects (const hb_set_t *glyphs) const { - /* TODO speed this up */ - Coverage::Iter iter; - for (iter.init (*this); iter.more (); iter.next ()) { - if (glyphs->has (iter.get_glyph ())) - return true; + inline bool intersects (const hb_set_t *glyphs) const + { + switch (u.format) + { + case 1: return u.format1.intersects (glyphs); + case 2: return u.format2.intersects (glyphs); + default:return false; } - return false; } - - inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const { - switch (u.format) { + inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const + { + switch (u.format) + { case 1: return u.format1.intersects_coverage (glyphs, index); case 2: return u.format2.intersects_coverage (glyphs, index); default:return false; @@ -963,47 +1094,61 @@ struct Coverage /* Might return false if array looks unsorted. * Used for faster rejection of corrupt data. */ template <typename set_t> - inline bool add_coverage (set_t *glyphs) const { - switch (u.format) { + inline bool add_coverage (set_t *glyphs) const + { + switch (u.format) + { case 1: return u.format1.add_coverage (glyphs); case 2: return u.format2.add_coverage (glyphs); default:return false; } } - struct Iter { + struct Iter + { Iter (void) : format (0), u () {}; - inline void init (const Coverage &c_) { + inline void init (const Coverage &c_) + { format = c_.u.format; - switch (format) { + switch (format) + { case 1: u.format1.init (c_.u.format1); return; case 2: u.format2.init (c_.u.format2); return; - default: return; + default: return; } } - inline bool more (void) { - switch (format) { + inline void fini (void) {} + inline bool more (void) + { + switch (format) + { case 1: return u.format1.more (); case 2: return u.format2.more (); default:return false; } } - inline void next (void) { - switch (format) { + inline void next (void) + { + switch (format) + { case 1: u.format1.next (); break; case 2: u.format2.next (); break; - default: break; + default: break; } } - inline hb_codepoint_t get_glyph (void) { - switch (format) { + inline hb_codepoint_t get_glyph (void) + { + switch (format) + { case 1: return u.format1.get_glyph (); case 2: return u.format2.get_glyph (); default:return 0; } } - inline unsigned int get_coverage (void) { - switch (format) { + inline unsigned int get_coverage (void) + { + switch (format) + { case 1: return u.format1.get_coverage (); case 2: return u.format2.get_coverage (); default:return -1; @@ -1085,6 +1230,17 @@ struct ClassDefFormat1 return true; } + inline bool intersects (const hb_set_t *glyphs) const + { + /* TODO Speed up, using hb_set_next()? */ + hb_codepoint_t start = startGlyph; + hb_codepoint_t end = startGlyph + classValue.len; + for (hb_codepoint_t iter = startGlyph - 1; + hb_set_next (glyphs, &iter) && iter < end;) + if (classValue[iter - start]) + return true; + return false; + } inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const { unsigned int count = classValue.len; if (klass == 0) @@ -1135,7 +1291,8 @@ struct ClassDefFormat2 } template <typename set_t> - inline bool add_coverage (set_t *glyphs) const { + inline bool add_coverage (set_t *glyphs) const + { unsigned int count = rangeRecord.len; for (unsigned int i = 0; i < count; i++) if (rangeRecord[i].value) @@ -1145,7 +1302,8 @@ struct ClassDefFormat2 } template <typename set_t> - inline bool add_class (set_t *glyphs, unsigned int klass) const { + inline bool add_class (set_t *glyphs, unsigned int klass) const + { unsigned int count = rangeRecord.len; for (unsigned int i = 0; i < count; i++) { @@ -1156,7 +1314,17 @@ struct ClassDefFormat2 return true; } - inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const { + inline bool intersects (const hb_set_t *glyphs) const + { + /* TODO Speed up, using hb_set_next() and bsearch()? */ + unsigned int count = rangeRecord.len; + for (unsigned int i = 0; i < count; i++) + if (rangeRecord[i].intersects (glyphs)) + return true; + return false; + } + inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const + { unsigned int count = rangeRecord.len; if (klass == 0) { @@ -1233,6 +1401,13 @@ struct ClassDef } } + inline bool intersects (const hb_set_t *glyphs) const { + switch (u.format) { + case 1: return u.format1.intersects (glyphs); + case 2: return u.format2.intersects (glyphs); + default:return false; + } + } inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const { switch (u.format) { case 1: return u.format1.intersects_class (glyphs, klass); @@ -1300,7 +1475,7 @@ struct VarRegionAxis struct VarRegionList { inline float evaluate (unsigned int region_index, - int *coords, unsigned int coord_len) const + const int *coords, unsigned int coord_len) const { if (unlikely (region_index >= regionCount)) return 0.; @@ -1345,7 +1520,7 @@ struct VarData { return itemCount * get_row_size (); } inline float get_delta (unsigned int inner, - int *coords, unsigned int coord_count, + const int *coords, unsigned int coord_count, const VarRegionList ®ions) const { if (unlikely (inner >= itemCount)) @@ -1383,14 +1558,14 @@ struct VarData regionIndices.sanitize(c) && shortCount <= regionIndices.len && c->check_array (&StructAfter<HBUINT8> (regionIndices), - get_row_size (), itemCount)); + itemCount, get_row_size ())); } protected: HBUINT16 itemCount; HBUINT16 shortCount; ArrayOf<HBUINT16> regionIndices; - HBUINT8 bytesX[VAR]; + UnsizedArrayOf<HBUINT8>bytesX; public: DEFINE_SIZE_ARRAY2 (6, regionIndices, bytesX); }; @@ -1398,7 +1573,7 @@ struct VarData struct VariationStore { inline float get_delta (unsigned int outer, unsigned int inner, - int *coords, unsigned int coord_count) const + const int *coords, unsigned int coord_count) const { if (unlikely (outer >= dataSets.len)) return 0.; @@ -1409,7 +1584,7 @@ struct VariationStore } inline float get_delta (unsigned int index, - int *coords, unsigned int coord_count) const + const int *coords, unsigned int coord_count) const { unsigned int outer = index >> 16; unsigned int inner = index & 0xFFFF; @@ -1584,7 +1759,7 @@ struct FeatureVariationRecord struct FeatureVariations { - static const unsigned int NOT_FOUND_INDEX = 0xFFFFFFFFu; + enum { NOT_FOUND_INDEX = 0xFFFFFFFFu }; inline bool find_index (const int *coords, unsigned int coord_len, unsigned int *index) const @@ -1610,6 +1785,12 @@ struct FeatureVariations return (this+record.substitutions).find_substitute (feature_index); } + inline bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + return_trace (c->serializer->embed (*this)); + } + inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -1623,7 +1804,7 @@ struct FeatureVariations LArrayOf<FeatureVariationRecord> varRecords; public: - DEFINE_SIZE_ARRAY (8, varRecords); + DEFINE_SIZE_ARRAY_SIZED (8, varRecords); }; @@ -1679,7 +1860,7 @@ struct HintingDevice unsigned int s = ppem_size - startSize; - unsigned int byte = deltaValue[s >> (4 - f)]; + unsigned int byte = deltaValueZ[s >> (4 - f)]; unsigned int bits = (byte >> (16 - (((s & ((1 << (4 - f)) - 1)) + 1) << f))); unsigned int mask = (0xFFFFu >> (16 - (1 << f))); @@ -1699,9 +1880,10 @@ struct HintingDevice * 2 Signed 4-bit value, 4 values per uint16 * 3 Signed 8-bit value, 2 values per uint16 */ - HBUINT16 deltaValue[VAR]; /* Array of compressed data */ + UnsizedArrayOf<HBUINT16> + deltaValueZ; /* Array of compressed data */ public: - DEFINE_SIZE_ARRAY (6, deltaValue); + DEFINE_SIZE_ARRAY (6, deltaValueZ); }; struct VariationDevice @@ -1803,4 +1985,4 @@ struct Device } /* namespace OT */ -#endif /* HB_OT_LAYOUT_COMMON_PRIVATE_HH */ +#endif /* HB_OT_LAYOUT_COMMON_HH */ diff --git a/src/hb-ot-layout-gdef-table.hh b/src/hb-ot-layout-gdef-table.hh index d2b41a8ef..757090861 100644 --- a/src/hb-ot-layout-gdef-table.hh +++ b/src/hb-ot-layout-gdef-table.hh @@ -29,9 +29,9 @@ #ifndef HB_OT_LAYOUT_GDEF_TABLE_HH #define HB_OT_LAYOUT_GDEF_TABLE_HH -#include "hb-ot-layout-common-private.hh" +#include "hb-ot-layout-common.hh" -#include "hb-font-private.hh" +#include "hb-font.hh" namespace OT { @@ -337,6 +337,7 @@ struct MarkGlyphSets * https://docs.microsoft.com/en-us/typography/opentype/spec/gdef */ + struct GDEF { static const hb_tag_t tableTag = HB_OT_TAG_GDEF; @@ -386,21 +387,8 @@ struct GDEF inline const VariationStore &get_var_store (void) const { return version.to_int () >= 0x00010003u ? this+varStore : Null(VariationStore); } - inline bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (version.sanitize (c) && - likely (version.major == 1) && - glyphClassDef.sanitize (c, this) && - attachList.sanitize (c, this) && - ligCaretList.sanitize (c, this) && - markAttachClassDef.sanitize (c, this) && - (version.to_int () < 0x00010002u || markGlyphSetsDef.sanitize (c, this)) && - (version.to_int () < 0x00010003u || varStore.sanitize (c, this))); - } - /* glyph_props is a 16-bit integer where the lower 8-bit have bits representing - * glyph class and other bits, and high 8-bit gthe mark attachment type (if any). + * glyph class and other bits, and high 8-bit the mark attachment type (if any). * Not to be confused with lookup_props which is very similar. */ inline unsigned int get_glyph_props (hb_codepoint_t glyph) const { @@ -420,6 +408,38 @@ struct GDEF } } + struct accelerator_t + { + HB_INTERNAL inline void init (hb_face_t *face); + + inline void fini (void) + { + hb_blob_destroy (this->blob); + } + + hb_blob_t *blob; + const GDEF *table; + }; + + inline unsigned int get_size (void) const + { + return min_size + + (version.to_int () >= 0x00010002u ? markGlyphSetsDef.static_size : 0) + + (version.to_int () >= 0x00010003u ? varStore.static_size : 0); + } + + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (version.sanitize (c) && + likely (version.major == 1) && + glyphClassDef.sanitize (c, this) && + attachList.sanitize (c, this) && + ligCaretList.sanitize (c, this) && + markAttachClassDef.sanitize (c, this) && + (version.to_int () < 0x00010002u || markGlyphSetsDef.sanitize (c, this)) && + (version.to_int () < 0x00010003u || varStore.sanitize (c, this))); + } protected: FixedVersion<>version; /* Version of the GDEF table--currently @@ -454,6 +474,7 @@ struct GDEF DEFINE_SIZE_MIN (12); }; +struct GDEF_accelerator_t : GDEF::accelerator_t {}; } /* namespace OT */ diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh index fe34a328b..dad6c4ea9 100644 --- a/src/hb-ot-layout-gpos-table.hh +++ b/src/hb-ot-layout-gpos-table.hh @@ -29,7 +29,7 @@ #ifndef HB_OT_LAYOUT_GPOS_TABLE_HH #define HB_OT_LAYOUT_GPOS_TABLE_HH -#include "hb-ot-layout-gsubgpos-private.hh" +#include "hb-ot-layout-gsubgpos.hh" namespace OT { @@ -199,7 +199,7 @@ struct ValueFormat : HBUINT16 TRACE_SANITIZE (this); unsigned int len = get_len (); - if (!c->check_array (values, get_size (), count)) return_trace (false); + if (!c->check_array (values, count, get_size ())) return_trace (false); if (!has_device ()) return_trace (true); @@ -376,7 +376,7 @@ struct AnchorMatrix if (!c->check_struct (this)) return_trace (false); if (unlikely (hb_unsigned_mul_overflows (rows, cols))) return_trace (false); unsigned int count = rows * cols; - if (!c->check_array (matrixZ, matrixZ[0].static_size, count)) return_trace (false); + if (!c->check_array (matrixZ.arrayZ, count)) return_trace (false); for (unsigned int i = 0; i < count; i++) if (!matrixZ[i].sanitize (c, this)) return_trace (false); return_trace (true); @@ -384,8 +384,8 @@ struct AnchorMatrix HBUINT16 rows; /* Number of rows */ protected: - OffsetTo<Anchor> - matrixZ[VAR]; /* Matrix of offsets to Anchor tables-- + UnsizedArrayOf<OffsetTo<Anchor> > + matrixZ; /* Matrix of offsets to Anchor tables-- * from beginning of AnchorMatrix table */ public: DEFINE_SIZE_ARRAY (2, matrixZ); @@ -459,6 +459,9 @@ struct MarkArray : ArrayOf<MarkRecord> /* Array of MarkRecords--in Coverage orde struct SinglePosFormat1 { + inline bool intersects (const hb_set_t *glyphs) const + { return (this+coverage).intersects (glyphs); } + inline void collect_glyphs (hb_collect_glyphs_context_t *c) const { TRACE_COLLECT_GLYPHS (this); @@ -466,9 +469,7 @@ struct SinglePosFormat1 } inline const Coverage &get_coverage (void) const - { - return this+coverage; - } + { return this+coverage; } inline bool apply (hb_ot_apply_context_t *c) const { @@ -483,6 +484,13 @@ struct SinglePosFormat1 return_trace (true); } + inline bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + // TODO(subset) + return_trace (false); + } + inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -507,6 +515,9 @@ struct SinglePosFormat1 struct SinglePosFormat2 { + inline bool intersects (const hb_set_t *glyphs) const + { return (this+coverage).intersects (glyphs); } + inline void collect_glyphs (hb_collect_glyphs_context_t *c) const { TRACE_COLLECT_GLYPHS (this); @@ -514,9 +525,7 @@ struct SinglePosFormat2 } inline const Coverage &get_coverage (void) const - { - return this+coverage; - } + { return this+coverage; } inline bool apply (hb_ot_apply_context_t *c) const { @@ -535,6 +544,13 @@ struct SinglePosFormat2 return_trace (true); } + inline bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + // TODO(subset) + return_trace (false); + } + inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -598,6 +614,24 @@ struct PairSet { friend struct PairPosFormat1; + inline bool intersects (const hb_set_t *glyphs, + const ValueFormat *valueFormats) const + { + unsigned int len1 = valueFormats[0].get_len (); + unsigned int len2 = valueFormats[1].get_len (); + unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2); + + const PairValueRecord *record = &firstPairValueRecord; + unsigned int count = len; + for (unsigned int i = 0; i < count; i++) + { + if (glyphs->has (record->secondGlyph)) + return true; + record = &StructAtOffset<const PairValueRecord> (record, record_size); + } + return false; + } + inline void collect_glyphs (hb_collect_glyphs_context_t *c, const ValueFormat *valueFormats) const { @@ -606,7 +640,7 @@ struct PairSet unsigned int len2 = valueFormats[1].get_len (); unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2); - const PairValueRecord *record = CastP<PairValueRecord> (arrayZ); + const PairValueRecord *record = &firstPairValueRecord; c->input->add_array (&record->secondGlyph, len, record_size); } @@ -620,7 +654,6 @@ struct PairSet unsigned int len2 = valueFormats[1].get_len (); unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2); - const PairValueRecord *record_array = CastP<PairValueRecord> (arrayZ); unsigned int count = len; /* Hand-coded bsearch. */ @@ -631,7 +664,7 @@ struct PairSet while (min <= max) { int mid = (min + max) / 2; - const PairValueRecord *record = &StructAtOffset<PairValueRecord> (record_array, record_size * mid); + const PairValueRecord *record = &StructAtOffset<PairValueRecord> (&firstPairValueRecord, record_size * mid); hb_codepoint_t mid_x = record->secondGlyph; if (x < mid_x) max = mid - 1; @@ -652,7 +685,8 @@ struct PairSet return_trace (false); } - struct sanitize_closure_t { + struct sanitize_closure_t + { const void *base; const ValueFormat *valueFormats; unsigned int len1; /* valueFormats[0].get_len() */ @@ -663,24 +697,39 @@ struct PairSet { TRACE_SANITIZE (this); if (!(c->check_struct (this) - && c->check_array (arrayZ, HBUINT16::static_size * closure->stride, len))) return_trace (false); + && c->check_array (&firstPairValueRecord, len, HBUINT16::static_size * closure->stride))) return_trace (false); unsigned int count = len; - const PairValueRecord *record = CastP<PairValueRecord> (arrayZ); + const PairValueRecord *record = &firstPairValueRecord; return_trace (closure->valueFormats[0].sanitize_values_stride_unsafe (c, closure->base, &record->values[0], count, closure->stride) && closure->valueFormats[1].sanitize_values_stride_unsafe (c, closure->base, &record->values[closure->len1], count, closure->stride)); } protected: - HBUINT16 len; /* Number of PairValueRecords */ - HBUINT16 arrayZ[VAR]; /* Array of PairValueRecords--ordered - * by GlyphID of the second glyph */ + HBUINT16 len; /* Number of PairValueRecords */ + PairValueRecord firstPairValueRecord; + /* Array of PairValueRecords--ordered + * by GlyphID of the second glyph */ public: - DEFINE_SIZE_ARRAY (2, arrayZ); + DEFINE_SIZE_MIN (2); }; struct PairPosFormat1 { + inline bool intersects (const hb_set_t *glyphs) const + { + unsigned int count = pairSet.len; + for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ()) + { + if (unlikely (iter.get_coverage () >= count)) + break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */ + if (glyphs->has (iter.get_glyph ()) && + (this+pairSet[iter.get_coverage ()]).intersects (glyphs, valueFormat)) + return true; + } + return false; + } + inline void collect_glyphs (hb_collect_glyphs_context_t *c) const { TRACE_COLLECT_GLYPHS (this); @@ -691,9 +740,7 @@ struct PairPosFormat1 } inline const Coverage &get_coverage (void) const - { - return this+coverage; - } + { return this+coverage; } inline bool apply (hb_ot_apply_context_t *c) const { @@ -709,6 +756,13 @@ struct PairPosFormat1 return_trace ((this+pairSet[index]).apply (c, valueFormat, skippy_iter.idx)); } + inline bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + // TODO(subset) + return_trace (false); + } + inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -717,7 +771,8 @@ struct PairPosFormat1 unsigned int len1 = valueFormat[0].get_len (); unsigned int len2 = valueFormat[1].get_len (); - PairSet::sanitize_closure_t closure = { + PairSet::sanitize_closure_t closure = + { this, valueFormat, len1, @@ -747,6 +802,12 @@ struct PairPosFormat1 struct PairPosFormat2 { + inline bool intersects (const hb_set_t *glyphs) const + { + return (this+coverage).intersects (glyphs) && + (this+classDef2).intersects (glyphs); + } + inline void collect_glyphs (hb_collect_glyphs_context_t *c) const { TRACE_COLLECT_GLYPHS (this); @@ -755,9 +816,7 @@ struct PairPosFormat2 } inline const Coverage &get_coverage (void) const - { - return this+coverage; - } + { return this+coverage; } inline bool apply (hb_ot_apply_context_t *c) const { @@ -790,6 +849,13 @@ struct PairPosFormat2 return_trace (true); } + inline bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + // TODO(subset) + return_trace (false); + } + inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -803,7 +869,7 @@ struct PairPosFormat2 unsigned int stride = len1 + len2; unsigned int record_size = valueFormat1.get_size () + valueFormat2.get_size (); unsigned int count = (unsigned int) class1Count * (unsigned int) class2Count; - return_trace (c->check_array (values, record_size, count) && + return_trace (c->check_array (values, count, record_size) && valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], count, stride) && valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride)); } @@ -889,6 +955,9 @@ reverse_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direc struct CursivePosFormat1 { + inline bool intersects (const hb_set_t *glyphs) const + { return (this+coverage).intersects (glyphs); } + inline void collect_glyphs (hb_collect_glyphs_context_t *c) const { TRACE_COLLECT_GLYPHS (this); @@ -896,9 +965,7 @@ struct CursivePosFormat1 } inline const Coverage &get_coverage (void) const - { - return this+coverage; - } + { return this+coverage; } inline bool apply (hb_ot_apply_context_t *c) const { @@ -906,22 +973,22 @@ struct CursivePosFormat1 hb_buffer_t *buffer = c->buffer; const EntryExitRecord &this_record = entryExitRecord[(this+coverage).get_coverage (buffer->cur().codepoint)]; - if (!this_record.exitAnchor) return_trace (false); + if (!this_record.entryAnchor) return_trace (false); hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; skippy_iter.reset (buffer->idx, 1); - if (!skippy_iter.next ()) return_trace (false); + if (!skippy_iter.prev ()) return_trace (false); - const EntryExitRecord &next_record = entryExitRecord[(this+coverage).get_coverage (buffer->info[skippy_iter.idx].codepoint)]; - if (!next_record.entryAnchor) return_trace (false); + const EntryExitRecord &prev_record = entryExitRecord[(this+coverage).get_coverage (buffer->info[skippy_iter.idx].codepoint)]; + if (!prev_record.exitAnchor) return_trace (false); - unsigned int i = buffer->idx; - unsigned int j = skippy_iter.idx; + unsigned int i = skippy_iter.idx; + unsigned int j = buffer->idx; buffer->unsafe_to_break (i, j); float entry_x, entry_y, exit_x, exit_y; - (this+this_record.exitAnchor).get_anchor (c, buffer->info[i].codepoint, &exit_x, &exit_y); - (this+next_record.entryAnchor).get_anchor (c, buffer->info[j].codepoint, &entry_x, &entry_y); + (this+prev_record.exitAnchor).get_anchor (c, buffer->info[i].codepoint, &exit_x, &exit_y); + (this+this_record.entryAnchor).get_anchor (c, buffer->info[j].codepoint, &entry_x, &entry_y); hb_glyph_position_t *pos = buffer->pos; @@ -968,7 +1035,7 @@ struct CursivePosFormat1 * parent. * * Optimize things for the case of RightToLeft, as that's most common in - * Arabinc. */ + * Arabic. */ unsigned int child = i; unsigned int parent = j; hb_position_t x_offset = entry_x - exit_x; @@ -997,10 +1064,17 @@ struct CursivePosFormat1 else pos[child].x_offset = x_offset; - buffer->idx = j; + buffer->idx++; return_trace (true); } + inline bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + // TODO(subset) + return_trace (false); + } + inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -1047,6 +1121,10 @@ typedef AnchorMatrix BaseArray; /* base-major-- struct MarkBasePosFormat1 { + inline bool intersects (const hb_set_t *glyphs) const + { return (this+markCoverage).intersects (glyphs) && + (this+baseCoverage).intersects (glyphs); } + inline void collect_glyphs (hb_collect_glyphs_context_t *c) const { TRACE_COLLECT_GLYPHS (this); @@ -1055,9 +1133,7 @@ struct MarkBasePosFormat1 } inline const Coverage &get_coverage (void) const - { - return this+markCoverage; - } + { return this+markCoverage; } inline bool apply (hb_ot_apply_context_t *c) const { @@ -1088,7 +1164,7 @@ struct MarkBasePosFormat1 )) break; skippy_iter.reject (); - } while (1); + } while (true); /* Checking that matched glyph is actually a base glyph by GDEF is too strong; disabled */ //if (!_hb_glyph_info_is_base_glyph (&buffer->info[skippy_iter.idx])) { return_trace (false); } @@ -1099,6 +1175,13 @@ struct MarkBasePosFormat1 return_trace ((this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, skippy_iter.idx)); } + inline bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + // TODO(subset) + return_trace (false); + } + inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -1161,6 +1244,10 @@ typedef OffsetListOf<LigatureAttach> LigatureArray; struct MarkLigPosFormat1 { + inline bool intersects (const hb_set_t *glyphs) const + { return (this+markCoverage).intersects (glyphs) && + (this+ligatureCoverage).intersects (glyphs); } + inline void collect_glyphs (hb_collect_glyphs_context_t *c) const { TRACE_COLLECT_GLYPHS (this); @@ -1169,9 +1256,7 @@ struct MarkLigPosFormat1 } inline const Coverage &get_coverage (void) const - { - return this+markCoverage; - } + { return this+markCoverage; } inline bool apply (hb_ot_apply_context_t *c) const { @@ -1216,6 +1301,13 @@ struct MarkLigPosFormat1 return_trace ((this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, j)); } + inline bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + // TODO(subset) + return_trace (false); + } + inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -1274,6 +1366,10 @@ typedef AnchorMatrix Mark2Array; /* mark2-major-- struct MarkMarkPosFormat1 { + inline bool intersects (const hb_set_t *glyphs) const + { return (this+mark1Coverage).intersects (glyphs) && + (this+mark2Coverage).intersects (glyphs); } + inline void collect_glyphs (hb_collect_glyphs_context_t *c) const { TRACE_COLLECT_GLYPHS (this); @@ -1282,9 +1378,7 @@ struct MarkMarkPosFormat1 } inline const Coverage &get_coverage (void) const - { - return this+mark1Coverage; - } + { return this+mark1Coverage; } inline bool apply (hb_ot_apply_context_t *c) const { @@ -1330,6 +1424,13 @@ struct MarkMarkPosFormat1 return_trace ((this+mark1Array).apply (c, mark1_index, mark2_index, this+mark2Array, classCount, j)); } + inline bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + // TODO(subset) + return_trace (false); + } + inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -1388,7 +1489,7 @@ struct ChainContextPos : ChainContext {}; struct ExtensionPos : Extension<ExtensionPos> { - typedef struct PosLookupSubTable LookupSubTable; + typedef struct PosLookupSubTable SubTable; }; @@ -1400,6 +1501,7 @@ struct ExtensionPos : Extension<ExtensionPos> struct PosLookupSubTable { + friend struct Lookup; friend struct PosLookup; enum Type { @@ -1453,8 +1555,10 @@ struct PosLookupSubTable struct PosLookup : Lookup { - inline const PosLookupSubTable& get_subtable (unsigned int i) const - { return Lookup::get_subtable<PosLookupSubTable> (i); } + typedef struct PosLookupSubTable SubTable; + + inline const SubTable& get_subtable (unsigned int i) const + { return Lookup::get_subtable<SubTable> (i); } inline bool is_reverse (void) const { @@ -1467,6 +1571,12 @@ struct PosLookup : Lookup return_trace (dispatch (c)); } + inline bool intersects (const hb_set_t *glyphs) const + { + hb_intersects_context_t c (glyphs); + return dispatch (&c); + } + inline hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const { TRACE_COLLECT_GLYPHS (this); @@ -1487,18 +1597,15 @@ struct PosLookup : Lookup template <typename context_t> inline typename context_t::return_t dispatch (context_t *c) const - { return Lookup::dispatch<PosLookupSubTable> (c); } + { return Lookup::dispatch<SubTable> (c); } + + inline bool subset (hb_subset_context_t *c) const + { return Lookup::subset<SubTable> (c); } inline bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - if (unlikely (!Lookup::sanitize (c))) return_trace (false); - return_trace (dispatch (c)); - } + { return Lookup::sanitize<SubTable> (c); } }; -typedef OffsetListOf<PosLookup> PosLookupList; - /* * GPOS -- Glyph Positioning * https://docs.microsoft.com/en-us/typography/opentype/spec/gpos @@ -1515,13 +1622,13 @@ struct GPOS : GSUBGPOS static inline void position_finish_advances (hb_font_t *font, hb_buffer_t *buffer); static inline void position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer); + inline bool subset (hb_subset_context_t *c) const + { return GSUBGPOS::subset<PosLookup> (c); } + inline bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - if (unlikely (!GSUBGPOS::sanitize (c))) return_trace (false); - const OffsetTo<PosLookupList> &list = CastR<OffsetTo<PosLookupList> > (lookupList); - return_trace (list.sanitize (c, this)); - } + { return GSUBGPOS::sanitize<PosLookup> (c); } + + typedef GSUBGPOS::accelerator_t<GPOS> accelerator_t; }; @@ -1551,7 +1658,10 @@ reverse_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direc pos[j].attach_type() = type; } static void -propagate_attachment_offsets (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction) +propagate_attachment_offsets (hb_glyph_position_t *pos, + unsigned int len, + unsigned int i, + hb_direction_t direction) { /* Adjusts offsets of attached glyphs (both cursive and mark) to accumulate * offset of glyph they are attached to. */ @@ -1559,11 +1669,14 @@ propagate_attachment_offsets (hb_glyph_position_t *pos, unsigned int i, hb_direc if (likely (!chain)) return; + pos[i].attach_chain() = 0; + unsigned int j = (int) i + chain; - pos[i].attach_chain() = 0; + if (unlikely (j >= len)) + return; - propagate_attachment_offsets (pos, j, direction); + propagate_attachment_offsets (pos, len, j, direction); assert (!!(type & ATTACH_TYPE_MARK) ^ !!(type & ATTACH_TYPE_CURSIVE)); @@ -1619,7 +1732,7 @@ GPOS::position_finish_offsets (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer) /* Handle attachments */ if (buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT) for (unsigned int i = 0; i < len; i++) - propagate_attachment_offsets (pos, i, direction); + propagate_attachment_offsets (pos, len, i, direction); } @@ -1628,15 +1741,13 @@ GPOS::position_finish_offsets (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer) template <typename context_t> /*static*/ inline typename context_t::return_t PosLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index) { - const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->table.GPOS); - const PosLookup &l = gpos.get_lookup (lookup_index); + const PosLookup &l = _get_gpos_relaxed (c->face)->get_lookup (lookup_index); return l.dispatch (c); } /*static*/ inline bool PosLookup::apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index) { - const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->table.GPOS); - const PosLookup &l = gpos.get_lookup (lookup_index); + const PosLookup &l = _get_gpos_relaxed (c->face).get_lookup (lookup_index); unsigned int saved_lookup_props = c->lookup_props; unsigned int saved_lookup_index = c->lookup_index; c->set_lookup_index (lookup_index); @@ -1647,9 +1758,7 @@ template <typename context_t> return ret; } - -#undef attach_chain -#undef attach_type +struct GPOS_accelerator_t : GPOS::accelerator_t {}; } /* namespace OT */ diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh index 1d5a02a02..2ce52a1b4 100644 --- a/src/hb-ot-layout-gsub-table.hh +++ b/src/hb-ot-layout-gsub-table.hh @@ -29,19 +29,26 @@ #ifndef HB_OT_LAYOUT_GSUB_TABLE_HH #define HB_OT_LAYOUT_GSUB_TABLE_HH -#include "hb-ot-layout-gsubgpos-private.hh" +#include "hb-ot-layout-gsubgpos.hh" namespace OT { +static inline void SingleSubst_serialize (hb_serialize_context_t *c, + Supplier<GlyphID> &glyphs, + Supplier<GlyphID> &substitutes, + unsigned int num_glyphs); + struct SingleSubstFormat1 { + inline bool intersects (const hb_set_t *glyphs) const + { return (this+coverage).intersects (glyphs); } + inline void closure (hb_closure_context_t *c) const { TRACE_CLOSURE (this); - Coverage::Iter iter; - for (iter.init (this+coverage); iter.more (); iter.next ()) + for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ()) { /* TODO Switch to range-based API to work around malicious fonts. * https://github.com/harfbuzz/harfbuzz/issues/363 */ @@ -55,8 +62,7 @@ struct SingleSubstFormat1 { TRACE_COLLECT_GLYPHS (this); if (unlikely (!(this+coverage).add_coverage (c->input))) return; - Coverage::Iter iter; - for (iter.init (this+coverage); iter.more (); iter.next ()) + for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ()) { /* TODO Switch to range-based API to work around malicious fonts. * https://github.com/harfbuzz/harfbuzz/issues/363 */ @@ -66,9 +72,7 @@ struct SingleSubstFormat1 } inline const Coverage &get_coverage (void) const - { - return this+coverage; - } + { return this+coverage; } inline bool would_apply (hb_would_apply_context_t *c) const { @@ -99,10 +103,34 @@ struct SingleSubstFormat1 TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (*this))) return_trace (false); if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false); - deltaGlyphID.set (delta); /* TODO(serilaize) overflow? */ + deltaGlyphID.set (delta); /* TODO(serialize) overflow? */ return_trace (true); } + inline bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + hb_auto_t<hb_vector_t<GlyphID> > from; + hb_auto_t<hb_vector_t<GlyphID> > to; + hb_codepoint_t delta = deltaGlyphID; + for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ()) + { + if (!c->plan->glyphset->has (iter.get_glyph ())) + continue; + from.push ()->set (iter.get_glyph ()); + to.push ()->set ((iter.get_glyph () + delta) & 0xFFFF); + } + c->serializer->err (from.in_error () || to.in_error ()); + + Supplier<GlyphID> from_supplier (&from); + Supplier<GlyphID> to_supplier (&to); + SingleSubst_serialize (c->serializer, + from_supplier, + to_supplier, + from.len); + return_trace (from.len); + } + inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -122,12 +150,14 @@ struct SingleSubstFormat1 struct SingleSubstFormat2 { + inline bool intersects (const hb_set_t *glyphs) const + { return (this+coverage).intersects (glyphs); } + inline void closure (hb_closure_context_t *c) const { TRACE_CLOSURE (this); - Coverage::Iter iter; unsigned int count = substitute.len; - for (iter.init (this+coverage); iter.more (); iter.next ()) + for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ()) { if (unlikely (iter.get_coverage () >= count)) break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */ @@ -140,9 +170,8 @@ struct SingleSubstFormat2 { TRACE_COLLECT_GLYPHS (this); if (unlikely (!(this+coverage).add_coverage (c->input))) return; - Coverage::Iter iter; unsigned int count = substitute.len; - for (iter.init (this+coverage); iter.more (); iter.next ()) + for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ()) { if (unlikely (iter.get_coverage () >= count)) break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */ @@ -151,9 +180,7 @@ struct SingleSubstFormat2 } inline const Coverage &get_coverage (void) const - { - return this+coverage; - } + { return this+coverage; } inline bool would_apply (hb_would_apply_context_t *c) const { @@ -164,14 +191,12 @@ struct SingleSubstFormat2 inline bool apply (hb_ot_apply_context_t *c) const { TRACE_APPLY (this); - hb_codepoint_t glyph_id = c->buffer->cur().codepoint; - unsigned int index = (this+coverage).get_coverage (glyph_id); + unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); if (likely (index == NOT_COVERED)) return_trace (false); if (unlikely (index >= substitute.len)) return_trace (false); - glyph_id = substitute[index]; - c->replace_glyph (glyph_id); + c->replace_glyph (substitute[index]); return_trace (true); } @@ -188,6 +213,29 @@ struct SingleSubstFormat2 return_trace (true); } + inline bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + hb_auto_t<hb_vector_t<GlyphID> > from; + hb_auto_t<hb_vector_t<GlyphID> > to; + for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ()) + { + if (!c->plan->glyphset->has (iter.get_glyph ())) + continue; + from.push ()->set (iter.get_glyph ()); + to.push ()->set (substitute[iter.get_coverage ()]); + } + c->serializer->err (from.in_error () || to.in_error ()); + + Supplier<GlyphID> from_supplier (&from); + Supplier<GlyphID> to_supplier (&to); + SingleSubst_serialize (c->serializer, + from_supplier, + to_supplier, + from.len); + return_trace (from.len); + } + inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -255,6 +303,17 @@ struct SingleSubst } u; }; +static inline void +SingleSubst_serialize (hb_serialize_context_t *c, + Supplier<GlyphID> &glyphs, + Supplier<GlyphID> &substitutes, + unsigned int num_glyphs) +{ + c->start_embed<SingleSubst> ()->serialize (c, + glyphs, + substitutes, + num_glyphs); +} struct Sequence { @@ -329,12 +388,14 @@ struct Sequence struct MultipleSubstFormat1 { + inline bool intersects (const hb_set_t *glyphs) const + { return (this+coverage).intersects (glyphs); } + inline void closure (hb_closure_context_t *c) const { TRACE_CLOSURE (this); - Coverage::Iter iter; unsigned int count = sequence.len; - for (iter.init (this+coverage); iter.more (); iter.next ()) + for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ()) { if (unlikely (iter.get_coverage () >= count)) break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */ @@ -349,13 +410,11 @@ struct MultipleSubstFormat1 if (unlikely (!(this+coverage).add_coverage (c->input))) return; unsigned int count = sequence.len; for (unsigned int i = 0; i < count; i++) - (this+sequence[i]).collect_glyphs (c); + (this+sequence[i]).collect_glyphs (c); } inline const Coverage &get_coverage (void) const - { - return this+coverage; - } + { return this+coverage; } inline bool would_apply (hb_would_apply_context_t *c) const { @@ -391,6 +450,13 @@ struct MultipleSubstFormat1 return_trace (true); } + inline bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + // TODO(subset) + return_trace (false); + } + inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -445,27 +511,86 @@ struct MultipleSubst } u; }; +struct AlternateSet +{ + inline void closure (hb_closure_context_t *c) const + { + TRACE_CLOSURE (this); + unsigned int count = alternates.len; + for (unsigned int i = 0; i < count; i++) + c->out->add (alternates[i]); + } + + inline void collect_glyphs (hb_collect_glyphs_context_t *c) const + { + TRACE_COLLECT_GLYPHS (this); + c->output->add_array (alternates.arrayZ, alternates.len); + } + + inline bool apply (hb_ot_apply_context_t *c) const + { + TRACE_APPLY (this); + unsigned int count = alternates.len; + + if (unlikely (!count)) return_trace (false); + + hb_mask_t glyph_mask = c->buffer->cur().mask; + hb_mask_t lookup_mask = c->lookup_mask; + + /* Note: This breaks badly if two features enabled this lookup together. */ + unsigned int shift = hb_ctz (lookup_mask); + unsigned int alt_index = ((lookup_mask & glyph_mask) >> shift); + + /* If alt_index is MAX, randomize feature if it is the rand feature. */ + if (alt_index == HB_OT_MAP_MAX_VALUE && c->random) + alt_index = c->random_number () % count + 1; + + if (unlikely (alt_index > count || alt_index == 0)) return_trace (false); + + c->replace_glyph (alternates[alt_index - 1]); + + return_trace (true); + } + + inline bool serialize (hb_serialize_context_t *c, + Supplier<GlyphID> &glyphs, + unsigned int num_glyphs) + { + TRACE_SERIALIZE (this); + if (unlikely (!c->extend_min (*this))) return_trace (false); + if (unlikely (!alternates.serialize (c, glyphs, num_glyphs))) return_trace (false); + return_trace (true); + } -typedef ArrayOf<GlyphID> AlternateSet; /* Array of alternate GlyphIDs--in + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (alternates.sanitize (c)); + } + + protected: + ArrayOf<GlyphID> + alternates; /* Array of alternate GlyphIDs--in * arbitrary order */ + public: + DEFINE_SIZE_ARRAY (2, alternates); +}; struct AlternateSubstFormat1 { + inline bool intersects (const hb_set_t *glyphs) const + { return (this+coverage).intersects (glyphs); } + inline void closure (hb_closure_context_t *c) const { TRACE_CLOSURE (this); - Coverage::Iter iter; unsigned int count = alternateSet.len; - for (iter.init (this+coverage); iter.more (); iter.next ()) + for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ()) { if (unlikely (iter.get_coverage () >= count)) break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */ - if (c->glyphs->has (iter.get_glyph ())) { - const AlternateSet &alt_set = this+alternateSet[iter.get_coverage ()]; - unsigned int count = alt_set.len; - for (unsigned int i = 0; i < count; i++) - c->out->add (alt_set[i]); - } + if (c->glyphs->has (iter.get_glyph ())) + (this+alternateSet[iter.get_coverage ()]).closure (c); } } @@ -473,21 +598,17 @@ struct AlternateSubstFormat1 { TRACE_COLLECT_GLYPHS (this); if (unlikely (!(this+coverage).add_coverage (c->input))) return; - Coverage::Iter iter; unsigned int count = alternateSet.len; - for (iter.init (this+coverage); iter.more (); iter.next ()) + for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ()) { if (unlikely (iter.get_coverage () >= count)) break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */ - const AlternateSet &alt_set = this+alternateSet[iter.get_coverage ()]; - c->output->add_array (alt_set.arrayZ, alt_set.len); + (this+alternateSet[iter.get_coverage ()]).collect_glyphs (c); } } inline const Coverage &get_coverage (void) const - { - return this+coverage; - } + { return this+coverage; } inline bool would_apply (hb_would_apply_context_t *c) const { @@ -498,29 +619,11 @@ struct AlternateSubstFormat1 inline bool apply (hb_ot_apply_context_t *c) const { TRACE_APPLY (this); - hb_codepoint_t glyph_id = c->buffer->cur().codepoint; - unsigned int index = (this+coverage).get_coverage (glyph_id); + unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); if (likely (index == NOT_COVERED)) return_trace (false); - const AlternateSet &alt_set = this+alternateSet[index]; - - if (unlikely (!alt_set.len)) return_trace (false); - - hb_mask_t glyph_mask = c->buffer->cur().mask; - hb_mask_t lookup_mask = c->lookup_mask; - - /* Note: This breaks badly if two features enabled this lookup together. */ - unsigned int shift = hb_ctz (lookup_mask); - unsigned int alt_index = ((lookup_mask & glyph_mask) >> shift); - - if (unlikely (alt_index > alt_set.len || alt_index == 0)) return_trace (false); - - glyph_id = alt_set[alt_index - 1]; - - c->replace_glyph (glyph_id); - - return_trace (true); + return_trace ((this+alternateSet[index]).apply (c)); } inline bool serialize (hb_serialize_context_t *c, @@ -541,6 +644,13 @@ struct AlternateSubstFormat1 return_trace (true); } + inline bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + // TODO(subset) + return_trace (false); + } + inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -598,10 +708,19 @@ struct AlternateSubst struct Ligature { + inline bool intersects (const hb_set_t *glyphs) const + { + unsigned int count = component.lenP1; + for (unsigned int i = 1; i < count; i++) + if (!glyphs->has (component[i])) + return false; + return true; + } + inline void closure (hb_closure_context_t *c) const { TRACE_CLOSURE (this); - unsigned int count = component.len; + unsigned int count = component.lenP1; for (unsigned int i = 1; i < count; i++) if (!c->glyphs->has (component[i])) return; @@ -611,14 +730,14 @@ struct Ligature inline void collect_glyphs (hb_collect_glyphs_context_t *c) const { TRACE_COLLECT_GLYPHS (this); - c->input->add_array (component.arrayZ, component.len ? component.len - 1 : 0); + c->input->add_array (component.arrayZ, component.lenP1 ? component.lenP1 - 1 : 0); c->output->add (ligGlyph); } inline bool would_apply (hb_would_apply_context_t *c) const { TRACE_WOULD_APPLY (this); - if (c->len != component.len) + if (c->len != component.lenP1) return_trace (false); for (unsigned int i = 1; i < c->len; i++) @@ -631,7 +750,7 @@ struct Ligature inline bool apply (hb_ot_apply_context_t *c) const { TRACE_APPLY (this); - unsigned int count = component.len; + unsigned int count = component.lenP1; if (unlikely (!count)) return_trace (false); @@ -643,7 +762,6 @@ struct Ligature return_trace (true); } - bool is_mark_ligature = false; unsigned int total_component_count = 0; unsigned int match_length = 0; @@ -655,7 +773,6 @@ struct Ligature nullptr, &match_length, match_positions, - &is_mark_ligature, &total_component_count))) return_trace (false); @@ -664,7 +781,6 @@ struct Ligature match_positions, match_length, ligGlyph, - is_mark_ligature, total_component_count); return_trace (true); @@ -701,6 +817,15 @@ struct Ligature struct LigatureSet { + inline bool intersects (const hb_set_t *glyphs) const + { + unsigned int num_ligs = ligature.len; + for (unsigned int i = 0; i < num_ligs; i++) + if ((this+ligature[i]).intersects (glyphs)) + return true; + return false; + } + inline void closure (hb_closure_context_t *c) const { TRACE_CLOSURE (this); @@ -778,12 +903,25 @@ struct LigatureSet struct LigatureSubstFormat1 { + inline bool intersects (const hb_set_t *glyphs) const + { + unsigned int count = ligatureSet.len; + for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ()) + { + if (unlikely (iter.get_coverage () >= count)) + break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */ + if (glyphs->has (iter.get_glyph ()) && + (this+ligatureSet[iter.get_coverage ()]).intersects (glyphs)) + return true; + } + return false; + } + inline void closure (hb_closure_context_t *c) const { TRACE_CLOSURE (this); - Coverage::Iter iter; unsigned int count = ligatureSet.len; - for (iter.init (this+coverage); iter.more (); iter.next ()) + for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ()) { if (unlikely (iter.get_coverage () >= count)) break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */ @@ -796,9 +934,8 @@ struct LigatureSubstFormat1 { TRACE_COLLECT_GLYPHS (this); if (unlikely (!(this+coverage).add_coverage (c->input))) return; - Coverage::Iter iter; unsigned int count = ligatureSet.len; - for (iter.init (this+coverage); iter.more (); iter.next ()) + for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ()) { if (unlikely (iter.get_coverage () >= count)) break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */ @@ -807,9 +944,7 @@ struct LigatureSubstFormat1 } inline const Coverage &get_coverage (void) const - { - return this+coverage; - } + { return this+coverage; } inline bool would_apply (hb_would_apply_context_t *c) const { @@ -824,9 +959,8 @@ struct LigatureSubstFormat1 inline bool apply (hb_ot_apply_context_t *c) const { TRACE_APPLY (this); - hb_codepoint_t glyph_id = c->buffer->cur().codepoint; - unsigned int index = (this+coverage).get_coverage (glyph_id); + unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); if (likely (index == NOT_COVERED)) return_trace (false); const LigatureSet &lig_set = this+ligatureSet[index]; @@ -855,6 +989,13 @@ struct LigatureSubstFormat1 return_trace (true); } + inline bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + // TODO(subset) + return_trace (false); + } + inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -924,7 +1065,7 @@ struct ChainContextSubst : ChainContext {}; struct ExtensionSubst : Extension<ExtensionSubst> { - typedef struct SubstLookupSubTable LookupSubTable; + typedef struct SubstLookupSubTable SubTable; inline bool is_reverse (void) const; }; @@ -932,6 +1073,28 @@ struct ExtensionSubst : Extension<ExtensionSubst> struct ReverseChainSingleSubstFormat1 { + inline bool intersects (const hb_set_t *glyphs) const + { + if (!(this+coverage).intersects (glyphs)) + return false; + + const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack); + + unsigned int count; + + count = backtrack.len; + for (unsigned int i = 0; i < count; i++) + if (!(this+backtrack[i]).intersects (glyphs)) + return false; + + count = lookahead.len; + for (unsigned int i = 0; i < count; i++) + if (!(this+lookahead[i]).intersects (glyphs)) + return false; + + return true; + } + inline void closure (hb_closure_context_t *c) const { TRACE_CLOSURE (this); @@ -950,9 +1113,8 @@ struct ReverseChainSingleSubstFormat1 return; const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead); - Coverage::Iter iter; count = substitute.len; - for (iter.init (this+coverage); iter.more (); iter.next ()) + for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ()) { if (unlikely (iter.get_coverage () >= count)) break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */ @@ -983,9 +1145,7 @@ struct ReverseChainSingleSubstFormat1 } inline const Coverage &get_coverage (void) const - { - return this+coverage; - } + { return this+coverage; } inline bool would_apply (hb_would_apply_context_t *c) const { @@ -1026,6 +1186,13 @@ struct ReverseChainSingleSubstFormat1 return_trace (false); } + inline bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + // TODO(subset) + return_trace (false); + } + inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -1045,7 +1212,7 @@ struct ReverseChainSingleSubstFormat1 * beginning of table */ OffsetArrayOf<Coverage> backtrack; /* Array of coverage tables - * in backtracking sequence, in glyph + * in backtracking sequence, in glyph * sequence order */ OffsetArrayOf<Coverage> lookaheadX; /* Array of coverage tables @@ -1086,6 +1253,7 @@ struct ReverseChainSingleSubst struct SubstLookupSubTable { + friend struct Lookup; friend struct SubstLookup; enum Type { @@ -1136,16 +1304,18 @@ struct SubstLookupSubTable struct SubstLookup : Lookup { - inline const SubstLookupSubTable& get_subtable (unsigned int i) const - { return Lookup::get_subtable<SubstLookupSubTable> (i); } + typedef SubstLookupSubTable SubTable; + + inline const SubTable& get_subtable (unsigned int i) const + { return Lookup::get_subtable<SubTable> (i); } inline static bool lookup_type_is_reverse (unsigned int lookup_type) - { return lookup_type == SubstLookupSubTable::ReverseChainSingle; } + { return lookup_type == SubTable::ReverseChainSingle; } inline bool is_reverse (void) const { unsigned int type = get_type (); - if (unlikely (type == SubstLookupSubTable::Extension)) + if (unlikely (type == SubTable::Extension)) return CastR<ExtensionSubst> (get_subtable(0)).is_reverse (); return lookup_type_is_reverse (type); } @@ -1156,6 +1326,12 @@ struct SubstLookup : Lookup return_trace (dispatch (c)); } + inline bool intersects (const hb_set_t *glyphs) const + { + hb_intersects_context_t c (glyphs); + return dispatch (&c); + } + inline hb_closure_context_t::return_t closure (hb_closure_context_t *c, unsigned int this_index) const { TRACE_CLOSURE (this); @@ -1196,9 +1372,9 @@ struct SubstLookup : Lookup static bool apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index); - inline SubstLookupSubTable& serialize_subtable (hb_serialize_context_t *c, - unsigned int i) - { return get_subtables<SubstLookupSubTable> ()[i].serialize (c, this); } + inline SubTable& serialize_subtable (hb_serialize_context_t *c, + unsigned int i) + { return get_subtables<SubTable> ()[i].serialize (c, this); } inline bool serialize_single (hb_serialize_context_t *c, uint32_t lookup_props, @@ -1207,7 +1383,7 @@ struct SubstLookup : Lookup unsigned int num_glyphs) { TRACE_SERIALIZE (this); - if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Single, lookup_props, 1))) return_trace (false); + if (unlikely (!Lookup::serialize (c, SubTable::Single, lookup_props, 1))) return_trace (false); return_trace (serialize_subtable (c, 0).u.single.serialize (c, glyphs, substitutes, num_glyphs)); } @@ -1219,7 +1395,7 @@ struct SubstLookup : Lookup Supplier<GlyphID> &substitute_glyphs_list) { TRACE_SERIALIZE (this); - if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Multiple, lookup_props, 1))) return_trace (false); + if (unlikely (!Lookup::serialize (c, SubTable::Multiple, lookup_props, 1))) return_trace (false); return_trace (serialize_subtable (c, 0).u.multiple.serialize (c, glyphs, substitute_len_list, @@ -1235,7 +1411,7 @@ struct SubstLookup : Lookup Supplier<GlyphID> &alternate_glyphs_list) { TRACE_SERIALIZE (this); - if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Alternate, lookup_props, 1))) return_trace (false); + if (unlikely (!Lookup::serialize (c, SubTable::Alternate, lookup_props, 1))) return_trace (false); return_trace (serialize_subtable (c, 0).u.alternate.serialize (c, glyphs, alternate_len_list, @@ -1253,7 +1429,7 @@ struct SubstLookup : Lookup Supplier<GlyphID> &component_list /* Starting from second for each ligature */) { TRACE_SERIALIZE (this); - if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Ligature, lookup_props, 1))) return_trace (false); + if (unlikely (!Lookup::serialize (c, SubTable::Ligature, lookup_props, 1))) return_trace (false); return_trace (serialize_subtable (c, 0).u.ligature.serialize (c, first_glyphs, ligature_per_first_glyph_count_list, @@ -1280,32 +1456,15 @@ struct SubstLookup : Lookup template <typename context_t> inline typename context_t::return_t dispatch (context_t *c) const - { return Lookup::dispatch<SubstLookupSubTable> (c); } + { return Lookup::dispatch<SubTable> (c); } - inline bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - if (unlikely (!Lookup::sanitize (c))) return_trace (false); - if (unlikely (!dispatch (c))) return_trace (false); + inline bool subset (hb_subset_context_t *c) const + { return Lookup::subset<SubTable> (c); } - if (unlikely (get_type () == SubstLookupSubTable::Extension)) - { - /* The spec says all subtables of an Extension lookup should - * have the same type, which shall not be the Extension type - * itself (but we already checked for that). - * This is specially important if one has a reverse type! */ - unsigned int type = get_subtable (0).u.extension.get_type (); - unsigned int count = get_subtable_count (); - for (unsigned int i = 1; i < count; i++) - if (get_subtable (i).u.extension.get_type () != type) - return_trace (false); - } - return_trace (true); - } + inline bool sanitize (hb_sanitize_context_t *c) const + { return Lookup::sanitize<SubTable> (c); } }; -typedef OffsetListOf<SubstLookup> SubstLookupList; - /* * GSUB -- Glyph Substitution * https://docs.microsoft.com/en-us/typography/opentype/spec/gsub @@ -1318,32 +1477,14 @@ struct GSUB : GSUBGPOS inline const SubstLookup& get_lookup (unsigned int i) const { return CastR<SubstLookup> (GSUBGPOS::get_lookup (i)); } - static inline void substitute_start (hb_font_t *font, hb_buffer_t *buffer); + inline bool subset (hb_subset_context_t *c) const + { return GSUBGPOS::subset<SubstLookup> (c); } inline bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - if (unlikely (!GSUBGPOS::sanitize (c))) return_trace (false); - const OffsetTo<SubstLookupList> &list = CastR<OffsetTo<SubstLookupList> > (lookupList); - return_trace (list.sanitize (c, this)); - } -}; - - -void -GSUB::substitute_start (hb_font_t *font, hb_buffer_t *buffer) -{ - _hb_buffer_assert_gsubgpos_vars (buffer); + { return GSUBGPOS::sanitize<SubstLookup> (c); } - const GDEF &gdef = *hb_ot_layout_from_face (font->face)->table.GDEF; - unsigned int count = buffer->len; - for (unsigned int i = 0; i < count; i++) - { - _hb_glyph_info_set_glyph_props (&buffer->info[i], gdef.get_glyph_props (buffer->info[i].codepoint)); - _hb_glyph_info_clear_lig_props (&buffer->info[i]); - buffer->info[i].syllable() = 0; - } -} + typedef GSUBGPOS::accelerator_t<GSUB> accelerator_t; +}; /* Out-of-class implementation for methods recursing */ @@ -1351,23 +1492,21 @@ GSUB::substitute_start (hb_font_t *font, hb_buffer_t *buffer) /*static*/ inline bool ExtensionSubst::is_reverse (void) const { unsigned int type = get_type (); - if (unlikely (type == SubstLookupSubTable::Extension)) - return CastR<ExtensionSubst> (get_subtable<LookupSubTable>()).is_reverse (); + if (unlikely (type == SubTable::Extension)) + return CastR<ExtensionSubst> (get_subtable<SubTable>()).is_reverse (); return SubstLookup::lookup_type_is_reverse (type); } template <typename context_t> /*static*/ inline typename context_t::return_t SubstLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index) { - const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->table.GSUB); - const SubstLookup &l = gsub.get_lookup (lookup_index); + const SubstLookup &l = _get_gsub_relaxed (c->face).get_lookup (lookup_index); return l.dispatch (c); } /*static*/ inline bool SubstLookup::apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index) { - const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->table.GSUB); - const SubstLookup &l = gsub.get_lookup (lookup_index); + const SubstLookup &l = _get_gsub_relaxed (c->face).get_lookup (lookup_index); unsigned int saved_lookup_props = c->lookup_props; unsigned int saved_lookup_index = c->lookup_index; c->set_lookup_index (lookup_index); @@ -1378,6 +1517,7 @@ template <typename context_t> return ret; } +struct GSUB_accelerator_t : GSUB::accelerator_t {}; } /* namespace OT */ diff --git a/src/hb-ot-layout-gsubgpos-private.hh b/src/hb-ot-layout-gsubgpos.hh index 40a2fc4cc..a4066265c 100644 --- a/src/hb-ot-layout-gsubgpos-private.hh +++ b/src/hb-ot-layout-gsubgpos.hh @@ -26,19 +26,38 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH -#define HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH - -#include "hb-private.hh" -#include "hb-buffer-private.hh" -#include "hb-map-private.hh" +#ifndef HB_OT_LAYOUT_GSUBGPOS_HH +#define HB_OT_LAYOUT_GSUBGPOS_HH + +#include "hb.hh" +#include "hb-buffer.hh" +#include "hb-map.hh" +#include "hb-set.hh" +#include "hb-ot-map.hh" +#include "hb-ot-layout-common.hh" #include "hb-ot-layout-gdef-table.hh" -#include "hb-set-private.hh" namespace OT { +struct hb_intersects_context_t : + hb_dispatch_context_t<hb_intersects_context_t, bool, 0> +{ + inline const char *get_name (void) { return "INTERSECTS"; } + template <typename T> + inline return_t dispatch (const T &obj) { return obj.intersects (this->glyphs); } + static return_t default_return_value (void) { return false; } + bool stop_sublookup_iteration (return_t r) const { return r; } + + const hb_set_t *glyphs; + unsigned int debug_depth; + + hb_intersects_context_t (const hb_set_t *glyphs_) : + glyphs (glyphs_), + debug_depth (0) {} +}; + struct hb_closure_context_t : hb_dispatch_context_t<hb_closure_context_t, hb_void_t, HB_DEBUG_CLOSURE> { @@ -48,15 +67,14 @@ struct hb_closure_context_t : inline return_t dispatch (const T &obj) { obj.closure (this); return HB_VOID; } static return_t default_return_value (void) { return HB_VOID; } bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return false; } - return_t recurse (unsigned int lookup_index) + void recurse (unsigned int lookup_index) { if (unlikely (nesting_level_left == 0 || !recurse_func)) - return default_return_value (); + return; nesting_level_left--; recurse_func (this, lookup_index); nesting_level_left++; - return HB_VOID; } bool should_visit_lookup (unsigned int lookup_index) @@ -145,10 +163,10 @@ struct hb_collect_glyphs_context_t : inline return_t dispatch (const T &obj) { obj.collect_glyphs (this); return HB_VOID; } static return_t default_return_value (void) { return HB_VOID; } bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return false; } - return_t recurse (unsigned int lookup_index) + void recurse (unsigned int lookup_index) { if (unlikely (nesting_level_left == 0 || !recurse_func)) - return default_return_value (); + return; /* Note that GPOS sets recurse_func to nullptr already, so it doesn't get * past the previous check. For GSUB, we only want to collect the output @@ -161,11 +179,11 @@ struct hb_collect_glyphs_context_t : */ if (output == hb_set_get_empty ()) - return HB_VOID; + return; /* Return if new lookup was recursed to before. */ if (recursed_lookups->has (lookup_index)) - return HB_VOID; + return; hb_set_t *old_before = before; hb_set_t *old_input = input; @@ -181,8 +199,6 @@ struct hb_collect_glyphs_context_t : after = old_after; recursed_lookups->add (lookup_index); - - return HB_VOID; } hb_face_t *face; @@ -196,10 +212,10 @@ struct hb_collect_glyphs_context_t : unsigned int debug_depth; hb_collect_glyphs_context_t (hb_face_t *face_, - hb_set_t *glyphs_before, /* OUT. May be nullptr */ - hb_set_t *glyphs_input, /* OUT. May be nullptr */ - hb_set_t *glyphs_after, /* OUT. May be nullptr */ - hb_set_t *glyphs_output, /* OUT. May be nullptr */ + hb_set_t *glyphs_before, /* OUT. May be NULL */ + hb_set_t *glyphs_input, /* OUT. May be NULL */ + hb_set_t *glyphs_after, /* OUT. May be NULL */ + hb_set_t *glyphs_output, /* OUT. May be NULL */ unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) : face (face_), before (glyphs_before ? glyphs_before : hb_set_get_empty ()), @@ -207,24 +223,16 @@ struct hb_collect_glyphs_context_t : after (glyphs_after ? glyphs_after : hb_set_get_empty ()), output (glyphs_output ? glyphs_output : hb_set_get_empty ()), recurse_func (nullptr), - recursed_lookups (nullptr), + recursed_lookups (hb_set_create ()), nesting_level_left (nesting_level_left_), - debug_depth (0) - { - recursed_lookups = hb_set_create (); - } - ~hb_collect_glyphs_context_t (void) - { - hb_set_destroy (recursed_lookups); - } + debug_depth (0) {} + ~hb_collect_glyphs_context_t (void) { hb_set_destroy (recursed_lookups); } void set_recurse_func (recurse_func_t func) { recurse_func = func; } }; -/* XXX Can we remove this? */ - template <typename set_t> struct hb_add_coverage_context_t : hb_dispatch_context_t<hb_add_coverage_context_t<set_t>, const Coverage &, HB_DEBUG_GET_COVERAGE> @@ -334,10 +342,10 @@ struct hb_ot_apply_context_t : match_glyph_data = nullptr; matcher.set_match_func (nullptr, nullptr); matcher.set_lookup_props (c->lookup_props); - /* Ignore ZWNJ if we are matching GSUB context, or matching GPOS. */ + /* Ignore ZWNJ if we are matching GPOS, or matching GSUB context and asked to. */ matcher.set_ignore_zwnj (c->table_index == 1 || (context_match && c->auto_zwnj)); - /* Ignore ZWJ if we are matching GSUB context, or matching GPOS, or if asked to. */ - matcher.set_ignore_zwj (c->table_index == 1 || (context_match || c->auto_zwj)); + /* Ignore ZWJ if we are matching context, or asked to. */ + matcher.set_ignore_zwj (context_match || c->auto_zwj); matcher.set_mask (context_match ? -1 : c->lookup_mask); } inline void set_lookup_props (unsigned int lookup_props) @@ -469,9 +477,12 @@ struct hb_ot_apply_context_t : unsigned int nesting_level_left; unsigned int debug_depth; + bool has_glyph_classes; bool auto_zwnj; bool auto_zwj; - bool has_glyph_classes; + bool random; + + uint32_t random_state; hb_ot_apply_context_t (unsigned int table_index_, @@ -480,7 +491,7 @@ struct hb_ot_apply_context_t : iter_input (), iter_context (), font (font_), face (font->face), buffer (buffer_), recurse_func (nullptr), - gdef (*hb_ot_layout_from_face (face)->table.GDEF), + gdef (_get_gdef (face)), var_store (gdef.get_var_store ()), direction (buffer_->props.direction), lookup_mask (1), @@ -489,22 +500,33 @@ struct hb_ot_apply_context_t : lookup_props (0), nesting_level_left (HB_MAX_NESTING_LEVEL), debug_depth (0), + has_glyph_classes (gdef.has_glyph_classes ()), auto_zwnj (true), auto_zwj (true), - has_glyph_classes (gdef.has_glyph_classes ()) {} + random (false), + random_state (1) { init_iters (); } - inline void set_lookup_mask (hb_mask_t mask) { lookup_mask = mask; } - inline void set_auto_zwj (bool auto_zwj_) { auto_zwj = auto_zwj_; } - inline void set_auto_zwnj (bool auto_zwnj_) { auto_zwnj = auto_zwnj_; } - inline void set_recurse_func (recurse_func_t func) { recurse_func = func; } - inline void set_lookup_index (unsigned int lookup_index_) { lookup_index = lookup_index_; } - inline void set_lookup_props (unsigned int lookup_props_) + inline void init_iters (void) { - lookup_props = lookup_props_; iter_input.init (this, false); iter_context.init (this, true); } + inline void set_lookup_mask (hb_mask_t mask) { lookup_mask = mask; init_iters (); } + inline void set_auto_zwj (bool auto_zwj_) { auto_zwj = auto_zwj_; init_iters (); } + inline void set_auto_zwnj (bool auto_zwnj_) { auto_zwnj = auto_zwnj_; init_iters (); } + inline void set_random (bool random_) { random = random_; } + inline void set_recurse_func (recurse_func_t func) { recurse_func = func; } + inline void set_lookup_index (unsigned int lookup_index_) { lookup_index = lookup_index_; } + inline void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; init_iters (); } + + inline uint32_t random_number (void) + { + /* http://www.cplusplus.com/reference/random/minstd_rand/ */ + random_state = random_state * 48271 % 2147483647; + return random_state; + } + inline bool match_properties_mark (hb_codepoint_t glyph, unsigned int glyph_props, @@ -558,7 +580,7 @@ struct hb_ot_apply_context_t : add_in |= HB_OT_LAYOUT_GLYPH_PROPS_LIGATED; /* In the only place that the MULTIPLIED bit is used, Uniscribe * seems to only care about the "last" transformation between - * Ligature and Multiple substitions. Ie. if you ligate, expand, + * Ligature and Multiple substitutions. Ie. if you ligate, expand, * and ligate again, it forgives the multiplication and acts as * if only ligation happened. As such, clear MULTIPLIED bit. */ @@ -597,8 +619,66 @@ struct hb_ot_apply_context_t : }; +struct hb_get_subtables_context_t : + hb_dispatch_context_t<hb_get_subtables_context_t, hb_void_t, HB_DEBUG_APPLY> +{ + template <typename Type> + static inline bool apply_to (const void *obj, OT::hb_ot_apply_context_t *c) + { + const Type *typed_obj = (const Type *) obj; + return typed_obj->apply (c); + } + + typedef bool (*hb_apply_func_t) (const void *obj, OT::hb_ot_apply_context_t *c); + + struct hb_applicable_t + { + template <typename T> + inline void init (const T &obj_, hb_apply_func_t apply_func_) + { + obj = &obj_; + apply_func = apply_func_; + digest.init (); + obj_.get_coverage ().add_coverage (&digest); + } + + inline bool apply (OT::hb_ot_apply_context_t *c) const + { + return digest.may_have (c->buffer->cur().codepoint) && apply_func (obj, c); + } + + private: + const void *obj; + hb_apply_func_t apply_func; + hb_set_digest_t digest; + }; + + typedef hb_vector_t<hb_applicable_t, 2> array_t; + + /* Dispatch interface. */ + inline const char *get_name (void) { return "GET_SUBTABLES"; } + template <typename T> + inline return_t dispatch (const T &obj) + { + hb_applicable_t *entry = array.push(); + entry->init (obj, apply_to<T>); + return HB_VOID; + } + static return_t default_return_value (void) { return HB_VOID; } + bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return false; } + + hb_get_subtables_context_t (array_t &array_) : + array (array_), + debug_depth (0) {} + + array_t &array; + unsigned int debug_depth; +}; + + -typedef bool (*intersects_func_t) (hb_set_t *glyphs, const HBUINT16 &value, const void *data); + +typedef bool (*intersects_func_t) (const hb_set_t *glyphs, const HBUINT16 &value, const void *data); typedef void (*collect_glyphs_func_t) (hb_set_t *glyphs, const HBUINT16 &value, const void *data); typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data); @@ -616,29 +696,29 @@ struct ContextApplyFuncs }; -static inline bool intersects_glyph (hb_set_t *glyphs, const HBUINT16 &value, const void *data HB_UNUSED) +static inline bool intersects_glyph (const hb_set_t *glyphs, const HBUINT16 &value, const void *data HB_UNUSED) { return glyphs->has (value); } -static inline bool intersects_class (hb_set_t *glyphs, const HBUINT16 &value, const void *data) +static inline bool intersects_class (const hb_set_t *glyphs, const HBUINT16 &value, const void *data) { const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data); return class_def.intersects_class (glyphs, value); } -static inline bool intersects_coverage (hb_set_t *glyphs, const HBUINT16 &value, const void *data) +static inline bool intersects_coverage (const hb_set_t *glyphs, const HBUINT16 &value, const void *data) { const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value; return (data+coverage).intersects (glyphs); } -static inline bool intersects_array (hb_closure_context_t *c, +static inline bool intersects_array (const hb_set_t *glyphs, unsigned int count, const HBUINT16 values[], intersects_func_t intersects_func, const void *intersects_data) { for (unsigned int i = 0; i < count; i++) - if (likely (!intersects_func (c->glyphs, values[i], intersects_data))) + if (likely (!intersects_func (glyphs, values[i], intersects_data))) return false; return true; } @@ -707,7 +787,6 @@ static inline bool match_input (hb_ot_apply_context_t *c, const void *match_data, unsigned int *end_offset, unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], - bool *p_is_mark_ligature = nullptr, unsigned int *p_total_component_count = nullptr) { TRACE_APPLY (nullptr); @@ -744,8 +823,6 @@ static inline bool match_input (hb_ot_apply_context_t *c, * https://github.com/harfbuzz/harfbuzz/issues/545 */ - bool is_mark_ligature = _hb_glyph_info_is_mark (&buffer->cur()); - unsigned int total_component_count = 0; total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->cur()); @@ -812,15 +889,11 @@ static inline bool match_input (hb_ot_apply_context_t *c, return_trace (false); } - is_mark_ligature = is_mark_ligature && _hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx]); total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->info[skippy_iter.idx]); } *end_offset = skippy_iter.idx - buffer->idx + 1; - if (p_is_mark_ligature) - *p_is_mark_ligature = is_mark_ligature; - if (p_total_component_count) *p_total_component_count = total_component_count; @@ -828,10 +901,9 @@ static inline bool match_input (hb_ot_apply_context_t *c, } static inline bool ligate_input (hb_ot_apply_context_t *c, unsigned int count, /* Including the first glyph */ - unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */ + const unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */ unsigned int match_length, hb_codepoint_t lig_glyph, - bool is_mark_ligature, unsigned int total_component_count) { TRACE_APPLY (nullptr); @@ -840,11 +912,15 @@ static inline bool ligate_input (hb_ot_apply_context_t *c, buffer->merge_clusters (buffer->idx, buffer->idx + match_length); - /* - * - If it *is* a mark ligature, we don't allocate a new ligature id, and leave + /* - If a base and one or more marks ligate, consider that as a base, NOT + * ligature, such that all following marks can still attach to it. + * https://github.com/harfbuzz/harfbuzz/issues/1109 + * + * - If all components of the ligature were marks, we call this a mark ligature. + * If it *is* a mark ligature, we don't allocate a new ligature id, and leave * the ligature to keep its old ligature id. This will allow it to attach to * a base ligature in GPOS. Eg. if the sequence is: LAM,LAM,SHADDA,FATHA,HEH, - * and LAM,LAM,HEH for a ligature, they will leave SHADDA and FATHA wit a + * and LAM,LAM,HEH for a ligature, they will leave SHADDA and FATHA with a * ligature id and component value of 2. Then if SHADDA,FATHA form a ligature * later, we don't want them to lose their ligature id/component, otherwise * GPOS will fail to correctly position the mark ligature on top of the @@ -868,13 +944,24 @@ static inline bool ligate_input (hb_ot_apply_context_t *c, * https://bugzilla.gnome.org/show_bug.cgi?id=437633 */ - unsigned int klass = is_mark_ligature ? 0 : HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE; - unsigned int lig_id = is_mark_ligature ? 0 : _hb_allocate_lig_id (buffer); + bool is_base_ligature = _hb_glyph_info_is_base_glyph (&buffer->info[match_positions[0]]); + bool is_mark_ligature = _hb_glyph_info_is_mark (&buffer->info[match_positions[0]]); + for (unsigned int i = 1; i < count; i++) + if (!_hb_glyph_info_is_mark (&buffer->info[match_positions[i]])) + { + is_base_ligature = false; + is_mark_ligature = false; + break; + } + bool is_ligature = !is_base_ligature && !is_mark_ligature; + + unsigned int klass = is_ligature ? HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE : 0; + unsigned int lig_id = is_ligature ? _hb_allocate_lig_id (buffer) : 0; unsigned int last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur()); unsigned int last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur()); unsigned int components_so_far = last_num_components; - if (!is_mark_ligature) + if (is_ligature) { _hb_glyph_info_set_lig_props_for_ligature (&buffer->cur(), lig_id, total_component_count); if (_hb_glyph_info_get_general_category (&buffer->cur()) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) @@ -888,7 +975,8 @@ static inline bool ligate_input (hb_ot_apply_context_t *c, { while (buffer->idx < match_positions[i] && buffer->successful) { - if (!is_mark_ligature) { + if (is_ligature) + { unsigned int this_comp = _hb_glyph_info_get_lig_comp (&buffer->cur()); if (this_comp == 0) this_comp = last_num_components; @@ -987,7 +1075,6 @@ struct LookupRecord DEFINE_SIZE_STATIC (4); }; - template <typename context_t> static inline void recurse_lookups (context_t *c, unsigned int lookupCount, @@ -1140,6 +1227,16 @@ struct ContextApplyLookupContext const void *match_data; }; +static inline bool context_intersects (const hb_set_t *glyphs, + unsigned int inputCount, /* Including the first glyph (not matched) */ + const HBUINT16 input[], /* Array of input values--start with second glyph */ + ContextClosureLookupContext &lookup_context) +{ + return intersects_array (glyphs, + inputCount ? inputCount - 1 : 0, input, + lookup_context.funcs.intersects, lookup_context.intersects_data); +} + static inline void context_closure_lookup (hb_closure_context_t *c, unsigned int inputCount, /* Including the first glyph (not matched) */ const HBUINT16 input[], /* Array of input values--start with second glyph */ @@ -1147,9 +1244,9 @@ static inline void context_closure_lookup (hb_closure_context_t *c, const LookupRecord lookupRecord[], ContextClosureLookupContext &lookup_context) { - if (intersects_array (c, - inputCount ? inputCount - 1 : 0, input, - lookup_context.funcs.intersects, lookup_context.intersects_data)) + if (context_intersects (c->glyphs, + inputCount, input, + lookup_context)) recurse_lookups (c, lookupCount, lookupRecord); } @@ -1201,38 +1298,45 @@ static inline bool context_apply_lookup (hb_ot_apply_context_t *c, struct Rule { + inline bool intersects (const hb_set_t *glyphs, ContextClosureLookupContext &lookup_context) const + { + return context_intersects (glyphs, + inputCount, inputZ.arrayZ, + lookup_context); + } + inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const { TRACE_CLOSURE (this); - const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (inputZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0)); + const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAtOffset<UnsizedArrayOf<LookupRecord> > (inputZ.arrayZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0)); context_closure_lookup (c, - inputCount, inputZ, - lookupCount, lookupRecord, + inputCount, inputZ.arrayZ, + lookupCount, lookupRecord.arrayZ, lookup_context); } inline void collect_glyphs (hb_collect_glyphs_context_t *c, ContextCollectGlyphsLookupContext &lookup_context) const { TRACE_COLLECT_GLYPHS (this); - const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (inputZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0)); + const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAtOffset<UnsizedArrayOf<LookupRecord> > (inputZ.arrayZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0)); context_collect_glyphs_lookup (c, - inputCount, inputZ, - lookupCount, lookupRecord, + inputCount, inputZ.arrayZ, + lookupCount, lookupRecord.arrayZ, lookup_context); } inline bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const { TRACE_WOULD_APPLY (this); - const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (inputZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0)); - return_trace (context_would_apply_lookup (c, inputCount, inputZ, lookupCount, lookupRecord, lookup_context)); + const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAtOffset<UnsizedArrayOf<LookupRecord> > (inputZ.arrayZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0)); + return_trace (context_would_apply_lookup (c, inputCount, inputZ.arrayZ, lookupCount, lookupRecord.arrayZ, lookup_context)); } inline bool apply (hb_ot_apply_context_t *c, ContextApplyLookupContext &lookup_context) const { TRACE_APPLY (this); - const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (inputZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0)); - return_trace (context_apply_lookup (c, inputCount, inputZ, lookupCount, lookupRecord, lookup_context)); + const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAtOffset<UnsizedArrayOf<LookupRecord> > (inputZ.arrayZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0)); + return_trace (context_apply_lookup (c, inputCount, inputZ.arrayZ, lookupCount, lookupRecord.arrayZ, lookup_context)); } public: @@ -1241,8 +1345,8 @@ struct Rule TRACE_SANITIZE (this); return_trace (inputCount.sanitize (c) && lookupCount.sanitize (c) && - c->check_range (inputZ, - inputZ[0].static_size * inputCount + + c->check_range (inputZ.arrayZ, + inputZ[0].static_size * (inputCount ? inputCount - 1 : 0) + LookupRecord::static_size * lookupCount)); } @@ -1251,9 +1355,11 @@ struct Rule * glyph sequence--includes the first * glyph */ HBUINT16 lookupCount; /* Number of LookupRecords */ - HBUINT16 inputZ[VAR]; /* Array of match inputs--start with + UnsizedArrayOf<HBUINT16> + inputZ; /* Array of match inputs--start with * second glyph */ -/*LookupRecord lookupRecordX[VAR];*/ /* Array of LookupRecords--in +/*UnsizedArrayOf<LookupRecord> + lookupRecordX;*/ /* Array of LookupRecords--in * design order */ public: DEFINE_SIZE_ARRAY (4, inputZ); @@ -1261,6 +1367,15 @@ struct Rule struct RuleSet { + inline bool intersects (const hb_set_t *glyphs, ContextClosureLookupContext &lookup_context) const + { + unsigned int num_rules = rule.len; + for (unsigned int i = 0; i < num_rules; i++) + if ((this+rule[i]).intersects (glyphs, lookup_context)) + return true; + return false; + } + inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const { TRACE_CLOSURE (this); @@ -1318,23 +1433,42 @@ struct RuleSet struct ContextFormat1 { + inline bool intersects (const hb_set_t *glyphs) const + { + struct ContextClosureLookupContext lookup_context = { + {intersects_glyph}, + nullptr + }; + + unsigned int count = ruleSet.len; + for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ()) + { + if (unlikely (iter.get_coverage () >= count)) + break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */ + if (glyphs->has (iter.get_glyph ()) && + (this+ruleSet[iter.get_coverage ()]).intersects (glyphs, lookup_context)) + return true; + } + return false; + } + inline void closure (hb_closure_context_t *c) const { TRACE_CLOSURE (this); - const Coverage &cov = (this+coverage); - struct ContextClosureLookupContext lookup_context = { {intersects_glyph}, nullptr }; unsigned int count = ruleSet.len; - for (unsigned int i = 0; i < count; i++) - if (cov.intersects_coverage (c->glyphs, i)) { - const RuleSet &rule_set = this+ruleSet[i]; - rule_set.closure (c, lookup_context); - } + for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ()) + { + if (unlikely (iter.get_coverage () >= count)) + break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */ + if (c->glyphs->has (iter.get_glyph ())) + (this+ruleSet[iter.get_coverage ()]).closure (c, lookup_context); + } } inline void collect_glyphs (hb_collect_glyphs_context_t *c) const @@ -1365,9 +1499,7 @@ struct ContextFormat1 } inline const Coverage &get_coverage (void) const - { - return this+coverage; - } + { return this+coverage; } inline bool apply (hb_ot_apply_context_t *c) const { @@ -1384,6 +1516,13 @@ struct ContextFormat1 return_trace (rule_set.apply (c, lookup_context)); } + inline bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + // TODO(subset) + return_trace (false); + } + inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -1405,6 +1544,27 @@ struct ContextFormat1 struct ContextFormat2 { + inline bool intersects (const hb_set_t *glyphs) const + { + if (!(this+coverage).intersects (glyphs)) + return false; + + const ClassDef &class_def = this+classDef; + + struct ContextClosureLookupContext lookup_context = { + {intersects_class}, + &class_def + }; + + unsigned int count = ruleSet.len; + for (unsigned int i = 0; i < count; i++) + if (class_def.intersects_class (glyphs, i) && + (this+ruleSet[i]).intersects (glyphs, lookup_context)) + return true; + + return false; + } + inline void closure (hb_closure_context_t *c) const { TRACE_CLOSURE (this); @@ -1457,9 +1617,7 @@ struct ContextFormat2 } inline const Coverage &get_coverage (void) const - { - return this+coverage; - } + { return this+coverage; } inline bool apply (hb_ot_apply_context_t *c) const { @@ -1477,6 +1635,13 @@ struct ContextFormat2 return_trace (rule_set.apply (c, lookup_context)); } + inline bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + // TODO(subset) + return_trace (false); + } + inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -1501,19 +1666,33 @@ struct ContextFormat2 struct ContextFormat3 { + inline bool intersects (const hb_set_t *glyphs) const + { + if (!(this+coverageZ[0]).intersects (glyphs)) + return false; + + struct ContextClosureLookupContext lookup_context = { + {intersects_coverage}, + this + }; + return context_intersects (glyphs, + glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1), + lookup_context); + } + inline void closure (hb_closure_context_t *c) const { TRACE_CLOSURE (this); if (!(this+coverageZ[0]).intersects (c->glyphs)) return; - const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * glyphCount); + const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ.arrayZ, coverageZ[0].static_size * glyphCount); struct ContextClosureLookupContext lookup_context = { {intersects_coverage}, this }; context_closure_lookup (c, - glyphCount, (const HBUINT16 *) (coverageZ + 1), + glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1), lookupCount, lookupRecord, lookup_context); } @@ -1523,14 +1702,14 @@ struct ContextFormat3 TRACE_COLLECT_GLYPHS (this); (this+coverageZ[0]).add_coverage (c->input); - const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * glyphCount); + const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ.arrayZ, coverageZ[0].static_size * glyphCount); struct ContextCollectGlyphsLookupContext lookup_context = { {collect_coverage}, this }; context_collect_glyphs_lookup (c, - glyphCount, (const HBUINT16 *) (coverageZ + 1), + glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1), lookupCount, lookupRecord, lookup_context); } @@ -1539,18 +1718,16 @@ struct ContextFormat3 { TRACE_WOULD_APPLY (this); - const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * glyphCount); + const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ.arrayZ, coverageZ[0].static_size * glyphCount); struct ContextApplyLookupContext lookup_context = { {match_coverage}, this }; - return_trace (context_would_apply_lookup (c, glyphCount, (const HBUINT16 *) (coverageZ + 1), lookupCount, lookupRecord, lookup_context)); + return_trace (context_would_apply_lookup (c, glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1), lookupCount, lookupRecord, lookup_context)); } inline const Coverage &get_coverage (void) const - { - return this+coverageZ[0]; - } + { return this+coverageZ[0]; } inline bool apply (hb_ot_apply_context_t *c) const { @@ -1558,12 +1735,19 @@ struct ContextFormat3 unsigned int index = (this+coverageZ[0]).get_coverage (c->buffer->cur().codepoint); if (likely (index == NOT_COVERED)) return_trace (false); - const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * glyphCount); + const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ.arrayZ, coverageZ[0].static_size * glyphCount); struct ContextApplyLookupContext lookup_context = { {match_coverage}, this }; - return_trace (context_apply_lookup (c, glyphCount, (const HBUINT16 *) (coverageZ + 1), lookupCount, lookupRecord, lookup_context)); + return_trace (context_apply_lookup (c, glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1), lookupCount, lookupRecord, lookup_context)); + } + + inline bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + // TODO(subset) + return_trace (false); } inline bool sanitize (hb_sanitize_context_t *c) const @@ -1572,11 +1756,11 @@ struct ContextFormat3 if (!c->check_struct (this)) return_trace (false); unsigned int count = glyphCount; if (!count) return_trace (false); /* We want to access coverageZ[0] freely. */ - if (!c->check_array (coverageZ, coverageZ[0].static_size, count)) return_trace (false); + if (!c->check_array (coverageZ.arrayZ, count)) return_trace (false); for (unsigned int i = 0; i < count; i++) if (!coverageZ[i].sanitize (c, this)) return_trace (false); - const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * count); - return_trace (c->check_array (lookupRecord, lookupRecord[0].static_size, lookupCount)); + const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ.arrayZ, coverageZ[0].static_size * count); + return_trace (c->check_array (lookupRecord, lookupCount)); } protected: @@ -1584,10 +1768,11 @@ struct ContextFormat3 HBUINT16 glyphCount; /* Number of glyphs in the input glyph * sequence */ HBUINT16 lookupCount; /* Number of LookupRecords */ - OffsetTo<Coverage> - coverageZ[VAR]; /* Array of offsets to Coverage + UnsizedArrayOf<OffsetTo<Coverage> > + coverageZ; /* Array of offsets to Coverage * table in glyph sequence order */ -/*LookupRecord lookupRecordX[VAR];*/ /* Array of LookupRecords--in +/*UnsizedArrayOf<LookupRecord> + lookupRecordX;*/ /* Array of LookupRecords--in * design order */ public: DEFINE_SIZE_ARRAY (6, coverageZ); @@ -1638,6 +1823,26 @@ struct ChainContextApplyLookupContext const void *match_data[3]; }; +static inline bool chain_context_intersects (const hb_set_t *glyphs, + unsigned int backtrackCount, + const HBUINT16 backtrack[], + unsigned int inputCount, /* Including the first glyph (not matched) */ + const HBUINT16 input[], /* Array of input values--start with second glyph */ + unsigned int lookaheadCount, + const HBUINT16 lookahead[], + ChainContextClosureLookupContext &lookup_context) +{ + return intersects_array (glyphs, + backtrackCount, backtrack, + lookup_context.funcs.intersects, lookup_context.intersects_data[0]) + && intersects_array (glyphs, + inputCount ? inputCount - 1 : 0, input, + lookup_context.funcs.intersects, lookup_context.intersects_data[1]) + && intersects_array (glyphs, + lookaheadCount, lookahead, + lookup_context.funcs.intersects, lookup_context.intersects_data[2]); +} + static inline void chain_context_closure_lookup (hb_closure_context_t *c, unsigned int backtrackCount, const HBUINT16 backtrack[], @@ -1649,15 +1854,11 @@ static inline void chain_context_closure_lookup (hb_closure_context_t *c, const LookupRecord lookupRecord[], ChainContextClosureLookupContext &lookup_context) { - if (intersects_array (c, - backtrackCount, backtrack, - lookup_context.funcs.intersects, lookup_context.intersects_data[0]) - && intersects_array (c, - inputCount ? inputCount - 1 : 0, input, - lookup_context.funcs.intersects, lookup_context.intersects_data[1]) - && intersects_array (c, - lookaheadCount, lookahead, - lookup_context.funcs.intersects, lookup_context.intersects_data[2])) + if (chain_context_intersects (c->glyphs, + backtrackCount, backtrack, + inputCount, input, + lookaheadCount, lookahead, + lookup_context)) recurse_lookups (c, lookupCount, lookupRecord); } @@ -1737,6 +1938,17 @@ static inline bool chain_context_apply_lookup (hb_ot_apply_context_t *c, struct ChainRule { + inline bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const + { + const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack); + const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input); + return chain_context_intersects (glyphs, + backtrack.len, backtrack.arrayZ, + input.lenP1, input.arrayZ, + lookahead.len, lookahead.arrayZ, + lookup_context); + } + inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const { TRACE_CLOSURE (this); @@ -1745,7 +1957,7 @@ struct ChainRule const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); chain_context_closure_lookup (c, backtrack.len, backtrack.arrayZ, - input.len, input.arrayZ, + input.lenP1, input.arrayZ, lookahead.len, lookahead.arrayZ, lookup.len, lookup.arrayZ, lookup_context); @@ -1759,7 +1971,7 @@ struct ChainRule const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); chain_context_collect_glyphs_lookup (c, backtrack.len, backtrack.arrayZ, - input.len, input.arrayZ, + input.lenP1, input.arrayZ, lookahead.len, lookahead.arrayZ, lookup.len, lookup.arrayZ, lookup_context); @@ -1773,7 +1985,7 @@ struct ChainRule const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); return_trace (chain_context_would_apply_lookup (c, backtrack.len, backtrack.arrayZ, - input.len, input.arrayZ, + input.lenP1, input.arrayZ, lookahead.len, lookahead.arrayZ, lookup.len, lookup.arrayZ, lookup_context)); } @@ -1786,7 +1998,7 @@ struct ChainRule const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); return_trace (chain_context_apply_lookup (c, backtrack.len, backtrack.arrayZ, - input.len, input.arrayZ, + input.lenP1, input.arrayZ, lookahead.len, lookahead.arrayZ, lookup.len, lookup.arrayZ, lookup_context)); } @@ -1823,6 +2035,14 @@ struct ChainRule struct ChainRuleSet { + inline bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const + { + unsigned int num_rules = rule.len; + for (unsigned int i = 0; i < num_rules; i++) + if ((this+rule[i]).intersects (glyphs, lookup_context)) + return true; + return false; + } inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const { TRACE_CLOSURE (this); @@ -1877,10 +2097,28 @@ struct ChainRuleSet struct ChainContextFormat1 { + inline bool intersects (const hb_set_t *glyphs) const + { + struct ChainContextClosureLookupContext lookup_context = { + {intersects_glyph}, + {nullptr, nullptr, nullptr} + }; + + unsigned int count = ruleSet.len; + for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ()) + { + if (unlikely (iter.get_coverage () >= count)) + break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */ + if (glyphs->has (iter.get_glyph ()) && + (this+ruleSet[iter.get_coverage ()]).intersects (glyphs, lookup_context)) + return true; + } + return false; + } + inline void closure (hb_closure_context_t *c) const { TRACE_CLOSURE (this); - const Coverage &cov = (this+coverage); struct ChainContextClosureLookupContext lookup_context = { {intersects_glyph}, @@ -1888,11 +2126,13 @@ struct ChainContextFormat1 }; unsigned int count = ruleSet.len; - for (unsigned int i = 0; i < count; i++) - if (cov.intersects_coverage (c->glyphs, i)) { - const ChainRuleSet &rule_set = this+ruleSet[i]; - rule_set.closure (c, lookup_context); - } + for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ()) + { + if (unlikely (iter.get_coverage () >= count)) + break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */ + if (c->glyphs->has (iter.get_glyph ())) + (this+ruleSet[iter.get_coverage ()]).closure (c, lookup_context); + } } inline void collect_glyphs (hb_collect_glyphs_context_t *c) const @@ -1923,9 +2163,7 @@ struct ChainContextFormat1 } inline const Coverage &get_coverage (void) const - { - return this+coverage; - } + { return this+coverage; } inline bool apply (hb_ot_apply_context_t *c) const { @@ -1941,6 +2179,13 @@ struct ChainContextFormat1 return_trace (rule_set.apply (c, lookup_context)); } + inline bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + // TODO(subset) + return_trace (false); + } + inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -1961,6 +2206,30 @@ struct ChainContextFormat1 struct ChainContextFormat2 { + inline bool intersects (const hb_set_t *glyphs) const + { + if (!(this+coverage).intersects (glyphs)) + return false; + + const ClassDef &backtrack_class_def = this+backtrackClassDef; + const ClassDef &input_class_def = this+inputClassDef; + const ClassDef &lookahead_class_def = this+lookaheadClassDef; + + struct ChainContextClosureLookupContext lookup_context = { + {intersects_class}, + {&backtrack_class_def, + &input_class_def, + &lookahead_class_def} + }; + + unsigned int count = ruleSet.len; + for (unsigned int i = 0; i < count; i++) + if (input_class_def.intersects_class (glyphs, i) && + (this+ruleSet[i]).intersects (glyphs, lookup_context)) + return true; + + return false; + } inline void closure (hb_closure_context_t *c) const { TRACE_CLOSURE (this); @@ -2027,9 +2296,7 @@ struct ChainContextFormat2 } inline const Coverage &get_coverage (void) const - { - return this+coverage; - } + { return this+coverage; } inline bool apply (hb_ot_apply_context_t *c) const { @@ -2052,6 +2319,13 @@ struct ChainContextFormat2 return_trace (rule_set.apply (c, lookup_context)); } + inline bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + // TODO(subset) + return_trace (false); + } + inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -2088,6 +2362,25 @@ struct ChainContextFormat2 struct ChainContextFormat3 { + inline bool intersects (const hb_set_t *glyphs) const + { + const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack); + + if (!(this+input[0]).intersects (glyphs)) + return false; + + const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input); + struct ChainContextClosureLookupContext lookup_context = { + {intersects_coverage}, + {this, this, this} + }; + return chain_context_intersects (glyphs, + backtrack.len, (const HBUINT16 *) backtrack.arrayZ, + input.len, (const HBUINT16 *) input.arrayZ + 1, + lookahead.len, (const HBUINT16 *) lookahead.arrayZ, + lookup_context); + } + inline void closure (hb_closure_context_t *c) const { TRACE_CLOSURE (this); @@ -2176,6 +2469,13 @@ struct ChainContextFormat3 lookup.len, lookup.arrayZ, lookup_context)); } + inline bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + // TODO(subset) + return_trace (false); + } + inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -2244,8 +2544,8 @@ struct ExtensionFormat1 inline const X& get_subtable (void) const { unsigned int offset = extensionOffset; - if (unlikely (!offset)) return Null(typename T::LookupSubTable); - return StructAtOffset<typename T::LookupSubTable> (this, offset); + if (unlikely (!offset)) return Null(typename T::SubTable); + return StructAtOffset<typename T::SubTable> (this, offset); } template <typename context_t> @@ -2253,7 +2553,7 @@ struct ExtensionFormat1 { TRACE_DISPATCH (this, format); if (unlikely (!c->may_dispatch (this, this))) return_trace (c->no_dispatch_return_value ()); - return_trace (get_subtable<typename T::LookupSubTable> ().dispatch (c, get_type ())); + return_trace (get_subtable<typename T::SubTable> ().dispatch (c, get_type ())); } /* This is called from may_dispatch() above with hb_sanitize_context_t. */ @@ -2262,7 +2562,7 @@ struct ExtensionFormat1 TRACE_SANITIZE (this); return_trace (c->check_struct (this) && extensionOffset != 0 && - extensionLookupType != T::LookupSubTable::Extension); + extensionLookupType != T::SubTable::Extension); } protected: @@ -2290,8 +2590,8 @@ struct Extension inline const X& get_subtable (void) const { switch (u.format) { - case 1: return u.format1.template get_subtable<typename T::LookupSubTable> (); - default:return Null(typename T::LookupSubTable); + case 1: return u.format1.template get_subtable<typename T::SubTable> (); + default:return Null(typename T::SubTable); } } @@ -2318,6 +2618,39 @@ struct Extension * GSUB/GPOS Common */ +struct hb_ot_layout_lookup_accelerator_t +{ + template <typename TLookup> + inline void init (const TLookup &lookup) + { + digest.init (); + lookup.add_coverage (&digest); + + subtables.init (); + OT::hb_get_subtables_context_t c_get_subtables (subtables); + lookup.dispatch (&c_get_subtables); + } + inline void fini (void) + { + subtables.fini (); + } + + inline bool may_have (hb_codepoint_t g) const + { return digest.may_have (g); } + + inline bool apply (hb_ot_apply_context_t *c) const + { + for (unsigned int i = 0; i < subtables.len; i++) + if (subtables[i].apply (c)) + return true; + return false; + } + + private: + hb_set_digest_t digest; + hb_get_subtables_context_t::array_t subtables; +}; + struct GSUBGPOS { inline bool has_data (void) const { return version.to_int () != 0; } @@ -2370,17 +2703,78 @@ struct GSUBGPOS return get_feature (feature_index); } + template <typename TLookup> + inline bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + struct GSUBGPOS *out = c->serializer->embed (*this); + if (unlikely (!out)) return_trace (false); + out->scriptList.serialize_subset (c, this+scriptList, out); + out->featureList.serialize_subset (c, this+featureList, out); + + typedef OffsetListOf<TLookup> TLookupList; + /* TODO Use intersects() to count how many subtables survive? */ + CastR<OffsetTo<TLookupList> > (out->lookupList) + .serialize_subset (c, + this+CastR<const OffsetTo<TLookupList> > (lookupList), + out); + + if (version.to_int () >= 0x00010001u) + out->featureVars.serialize_subset (c, this+featureVars, out); + return_trace (true); + } + + inline unsigned int get_size (void) const + { + return min_size + + (version.to_int () >= 0x00010001u ? featureVars.static_size : 0); + } + + template <typename TLookup> inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); + typedef OffsetListOf<TLookup> TLookupList; return_trace (version.sanitize (c) && likely (version.major == 1) && scriptList.sanitize (c, this) && featureList.sanitize (c, this) && - lookupList.sanitize (c, this) && + CastR<OffsetTo<TLookupList> > (lookupList).sanitize (c, this) && (version.to_int () < 0x00010001u || featureVars.sanitize (c, this))); } + template <typename T> + struct accelerator_t + { + inline void init (hb_face_t *face) + { + this->blob = hb_sanitize_context_t().reference_table<T> (face); + table = this->blob->template as<T> (); + + this->lookup_count = table->get_lookup_count (); + + this->accels = (hb_ot_layout_lookup_accelerator_t *) calloc (this->lookup_count, sizeof (hb_ot_layout_lookup_accelerator_t)); + if (unlikely (!this->accels)) + this->lookup_count = 0; + + for (unsigned int i = 0; i < this->lookup_count; i++) + this->accels[i].init (table->get_lookup (i)); + } + + inline void fini (void) + { + for (unsigned int i = 0; i < this->lookup_count; i++) + this->accels[i].fini (); + free (this->accels); + hb_blob_destroy (this->blob); + } + + hb_blob_t *blob; + const T *table; + unsigned int lookup_count; + hb_ot_layout_lookup_accelerator_t *accels; + }; + protected: FixedVersion<>version; /* Version of the GSUB/GPOS table--initially set * to 0x00010000u */ @@ -2403,4 +2797,4 @@ struct GSUBGPOS } /* namespace OT */ -#endif /* HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH */ +#endif /* HB_OT_LAYOUT_GSUBGPOS_HH */ diff --git a/src/hb-ot-layout-jstf-table.hh b/src/hb-ot-layout-jstf-table.hh index 7fabdebb2..2fb23cbc3 100644 --- a/src/hb-ot-layout-jstf-table.hh +++ b/src/hb-ot-layout-jstf-table.hh @@ -27,7 +27,7 @@ #ifndef HB_OT_LAYOUT_JSTF_TABLE_HH #define HB_OT_LAYOUT_JSTF_TABLE_HH -#include "hb-open-type-private.hh" +#include "hb-open-type.hh" #include "hb-ot-layout-gpos-table.hh" @@ -124,7 +124,7 @@ struct JstfPriority struct JstfLangSys : OffsetListOf<JstfPriority> { inline bool sanitize (hb_sanitize_context_t *c, - const Record<JstfLangSys>::sanitize_closure_t * = nullptr) const + const Record_sanitize_closure_t * = nullptr) const { TRACE_SANITIZE (this); return_trace (OffsetListOf<JstfPriority>::sanitize (c)); @@ -165,7 +165,7 @@ struct JstfScript inline const JstfLangSys& get_default_lang_sys (void) const { return this+defaultLangSys; } inline bool sanitize (hb_sanitize_context_t *c, - const Record<JstfScript>::sanitize_closure_t * = nullptr) const + const Record_sanitize_closure_t * = nullptr) const { TRACE_SANITIZE (this); return_trace (extenderGlyphs.sanitize (c, this) && diff --git a/src/hb-ot-layout.cc b/src/hb-ot-layout.cc index 09ff0e6c0..fb1d9b11f 100644 --- a/src/hb-ot-layout.cc +++ b/src/hb-ot-layout.cc @@ -28,10 +28,11 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-open-type-private.hh" -#include "hb-ot-layout-private.hh" -#include "hb-ot-map-private.hh" -#include "hb-map-private.hh" +#include "hb-open-type.hh" +#include "hb-ot-layout.hh" +#include "hb-ot-face.hh" +#include "hb-ot-map.hh" +#include "hb-map.hh" #include "hb-ot-layout-gdef-table.hh" #include "hb-ot-layout-gsub-table.hh" @@ -44,9 +45,73 @@ #include "hb-ot-color-cpal-table.hh" #include "hb-ot-color-sbix-table.hh" #include "hb-ot-color-svg-table.hh" +#include "hb-ot-kern-table.hh" #include "hb-ot-name-table.hh" +static const OT::kern::accelerator_t& _get_kern (hb_face_t *face) +{ + if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::kern::accelerator_t); + return *hb_ot_face_data (face)->kern; +} +const OT::GDEF& _get_gdef (hb_face_t *face) +{ + if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::GDEF); + return *hb_ot_face_data (face)->GDEF->table; +} +static hb_blob_t * _get_gsub_blob (hb_face_t *face) +{ + if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return hb_blob_get_empty (); + return hb_ot_face_data (face)->GSUB->blob; +} +static inline const OT::GSUB& _get_gsub (hb_face_t *face) +{ + if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::GSUB); + return *hb_ot_face_data (face)->GSUB->table; +} +const OT::GSUB& _get_gsub_relaxed (hb_face_t *face) +{ + return *hb_ot_face_data (face)->GSUB.get_relaxed ()->table; +} +static hb_blob_t * _get_gpos_blob (hb_face_t *face) +{ + if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return hb_blob_get_empty (); + return hb_ot_face_data (face)->GPOS->blob; +} +static inline const OT::GPOS& _get_gpos (hb_face_t *face) +{ + if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::GPOS); + return *hb_ot_face_data (face)->GPOS->table; +} +const OT::GPOS& _get_gpos_relaxed (hb_face_t *face) +{ + return *hb_ot_face_data (face)->GPOS.get_relaxed ()->table; +} + + +/* + * kern + */ + +hb_bool_t +hb_ot_layout_has_kerning (hb_face_t *face) +{ + return _get_kern (face).has_data (); +} + +void +hb_ot_layout_kern (hb_font_t *font, + hb_buffer_t *buffer, + hb_mask_t kern_mask) +{ + _get_kern (font->face).apply (font, buffer, kern_mask); +} + + +/* + * GDEF + */ + static bool _hb_ot_blacklist_gdef (unsigned int gdef_len, unsigned int gsub_len, @@ -149,106 +214,39 @@ _hb_ot_blacklist_gdef (unsigned int gdef_len, return false; } -void hb_ot_layout_t::tables_t::init0 (hb_face_t *face) +inline void +OT::GDEF::accelerator_t::init (hb_face_t *face) { - this->face = face; -#define HB_OT_LAYOUT_TABLE(Namespace, Type) Type.init0 (); - HB_OT_LAYOUT_TABLES -#undef HB_OT_LAYOUT_TABLE -} -void hb_ot_layout_t::tables_t::fini (void) -{ -#define HB_OT_LAYOUT_TABLE(Namespace, Type) Type.fini (); - HB_OT_LAYOUT_TABLES -#undef HB_OT_LAYOUT_TABLE -} + this->blob = hb_sanitize_context_t().reference_table<GDEF> (face); -hb_ot_layout_t * -_hb_ot_layout_create (hb_face_t *face) -{ - hb_ot_layout_t *layout = (hb_ot_layout_t *) calloc (1, sizeof (hb_ot_layout_t)); - if (unlikely (!layout)) - return nullptr; - - layout->table.init0 (face); - - const OT::GSUB &gsub = *layout->table.GSUB; - const OT::GPOS &gpos = *layout->table.GPOS; - - if (unlikely (_hb_ot_blacklist_gdef (layout->table.GDEF.get_blob ()->length, - layout->table.GSUB.get_blob ()->length, - layout->table.GPOS.get_blob ()->length))) - layout->table.GDEF.set_stored (hb_blob_get_empty ()); - - unsigned int gsub_lookup_count = layout->gsub_lookup_count = gsub.get_lookup_count (); - unsigned int gpos_lookup_count = layout->gpos_lookup_count = gpos.get_lookup_count (); - - layout->gsub_accels = (hb_ot_layout_lookup_accelerator_t *) calloc (gsub_lookup_count, sizeof (hb_ot_layout_lookup_accelerator_t)); - layout->gpos_accels = (hb_ot_layout_lookup_accelerator_t *) calloc (gpos_lookup_count, sizeof (hb_ot_layout_lookup_accelerator_t)); - - if (unlikely ((gsub_lookup_count && !layout->gsub_accels) || - (gpos_lookup_count && !layout->gpos_accels))) + if (unlikely (_hb_ot_blacklist_gdef (this->blob->length, + _get_gsub_blob (face)->length, + _get_gpos_blob (face)->length))) { - _hb_ot_layout_destroy (layout); - return nullptr; + hb_blob_destroy (this->blob); + this->blob = hb_blob_get_empty (); } - for (unsigned int i = 0; i < gsub_lookup_count; i++) - layout->gsub_accels[i].init (gsub.get_lookup (i)); - for (unsigned int i = 0; i < gpos_lookup_count; i++) - layout->gpos_accels[i].init (gpos.get_lookup (i)); - - return layout; + table = this->blob->as<GDEF> (); } -void -_hb_ot_layout_destroy (hb_ot_layout_t *layout) +static void +_hb_ot_layout_set_glyph_props (hb_font_t *font, + hb_buffer_t *buffer) { - if (layout->gsub_accels) - for (unsigned int i = 0; i < layout->gsub_lookup_count; i++) - layout->gsub_accels[i].fini (); - if (layout->gpos_accels) - for (unsigned int i = 0; i < layout->gpos_lookup_count; i++) - layout->gpos_accels[i].fini (); + _hb_buffer_assert_gsubgpos_vars (buffer); - free (layout->gsub_accels); - free (layout->gpos_accels); - - layout->table.fini (); - - free (layout); -} - -// static inline const OT::BASE& -// _get_base (hb_face_t *face) -// { -// if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::BASE); -// hb_ot_layout_t * layout = hb_ot_layout_from_face (face); -// return *(layout->base.get ()); -// } - -static inline const OT::GDEF& -_get_gdef (hb_face_t *face) -{ - if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::GDEF); - return *hb_ot_layout_from_face (face)->table.GDEF; -} -static inline const OT::GSUB& -_get_gsub (hb_face_t *face) -{ - if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::GSUB); - return *hb_ot_layout_from_face (face)->table.GSUB; -} -static inline const OT::GPOS& -_get_gpos (hb_face_t *face) -{ - if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::GPOS); - return *hb_ot_layout_from_face (face)->table.GPOS; + const OT::GDEF &gdef = _get_gdef (font->face); + unsigned int count = buffer->len; + for (unsigned int i = 0; i < count; i++) + { + _hb_glyph_info_set_glyph_props (&buffer->info[i], gdef.get_glyph_props (buffer->info[i].codepoint)); + _hb_glyph_info_clear_lig_props (&buffer->info[i]); + buffer->info[i].syllable() = 0; + } } -/* - * GDEF - */ +/* Public API */ hb_bool_t hb_ot_layout_has_glyph_classes (hb_face_t *face) @@ -324,7 +322,7 @@ hb_ot_layout_table_get_script_tags (hb_face_t *face, hb_tag_t table_tag, unsigned int start_offset, unsigned int *script_count /* IN/OUT */, - hb_tag_t *script_tags /* OUT */) + hb_tag_t *script_tags /* OUT */) { const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag); @@ -370,17 +368,36 @@ hb_ot_layout_table_choose_script (hb_face_t *face, unsigned int *script_index, hb_tag_t *chosen_script) { + const hb_tag_t *t; + for (t = script_tags; *t; t++); + return hb_ot_layout_table_select_script (face, table_tag, t - script_tags, script_tags, script_index, chosen_script); +} + +/** + * hb_ot_layout_table_select_script: + * + * Since: 2.0.0 + **/ +hb_bool_t +hb_ot_layout_table_select_script (hb_face_t *face, + hb_tag_t table_tag, + unsigned int script_count, + const hb_tag_t *script_tags, + unsigned int *script_index /* OUT */, + hb_tag_t *chosen_script /* OUT */) +{ static_assert ((OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX), ""); const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag); + unsigned int i; - while (*script_tags) + for (i = 0; i < script_count; i++) { - if (g.find_script_index (*script_tags, script_index)) { + if (g.find_script_index (script_tags[i], script_index)) + { if (chosen_script) - *chosen_script = *script_tags; + *chosen_script = script_tags[i]; return true; } - script_tags++; } /* try finding 'DFLT' */ @@ -416,7 +433,7 @@ hb_ot_layout_table_get_feature_tags (hb_face_t *face, hb_tag_t table_tag, unsigned int start_offset, unsigned int *feature_count /* IN/OUT */, - hb_tag_t *feature_tags /* OUT */) + hb_tag_t *feature_tags /* OUT */) { const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag); @@ -452,7 +469,7 @@ hb_ot_layout_script_get_language_tags (hb_face_t *face, unsigned int script_index, unsigned int start_offset, unsigned int *language_count /* IN/OUT */, - hb_tag_t *language_tags /* OUT */) + hb_tag_t *language_tags /* OUT */) { const OT::Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index); @@ -466,13 +483,33 @@ hb_ot_layout_script_find_language (hb_face_t *face, hb_tag_t language_tag, unsigned int *language_index) { + return hb_ot_layout_script_select_language (face, table_tag, script_index, 1, &language_tag, language_index); +} + +/** + * hb_ot_layout_script_select_language: + * + * Since: 2.0.0 + **/ +hb_bool_t +hb_ot_layout_script_select_language (hb_face_t *face, + hb_tag_t table_tag, + unsigned int script_index, + unsigned int language_count, + const hb_tag_t *language_tags, + unsigned int *language_index /* OUT */) +{ static_assert ((OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX), ""); const OT::Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index); + unsigned int i; - if (s.find_lang_sys_index (language_tag, language_index)) - return true; + for (i = 0; i < language_count; i++) + { + if (s.find_lang_sys_index (language_tags[i], language_index)) + return true; + } - /* try with 'dflt'; MS site has had typos and many fonts use it now :( */ + /* try finding 'dflt' */ if (s.find_lang_sys_index (HB_OT_TAG_DEFAULT_LANGUAGE, language_index)) return false; @@ -537,7 +574,7 @@ hb_ot_layout_language_get_feature_indexes (hb_face_t *face, unsigned int script_index, unsigned int language_index, unsigned int start_offset, - unsigned int *feature_count /* IN/OUT */, + unsigned int *feature_count /* IN/OUT */, unsigned int *feature_indexes /* OUT */) { const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag); @@ -553,7 +590,7 @@ hb_ot_layout_language_get_feature_tags (hb_face_t *face, unsigned int language_index, unsigned int start_offset, unsigned int *feature_count /* IN/OUT */, - hb_tag_t *feature_tags /* OUT */) + hb_tag_t *feature_tags /* OUT */) { const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag); const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index); @@ -607,7 +644,7 @@ hb_ot_layout_feature_get_lookups (hb_face_t *face, hb_tag_t table_tag, unsigned int feature_index, unsigned int start_offset, - unsigned int *lookup_count /* IN/OUT */, + unsigned int *lookup_count /* IN/OUT */, unsigned int *lookup_indexes /* OUT */) { return hb_ot_layout_feature_with_variations_get_lookups (face, @@ -633,11 +670,11 @@ hb_ot_layout_table_get_lookup_count (hb_face_t *face, { case HB_OT_TAG_GSUB: { - return hb_ot_layout_from_face (face)->gsub_lookup_count; + return hb_ot_face_data (face)->GSUB->lookup_count; } case HB_OT_TAG_GPOS: { - return hb_ot_layout_from_face (face)->gpos_lookup_count; + return hb_ot_face_data (face)->GPOS->lookup_count; } } return 0; @@ -745,11 +782,12 @@ _hb_ot_layout_collect_features_languages (hb_face_t *face, for (; *languages; languages++) { unsigned int language_index; - if (hb_ot_layout_script_find_language (face, - table_tag, - script_index, - *languages, - &language_index)) + if (hb_ot_layout_script_select_language (face, + table_tag, + script_index, + 1, + languages, + &language_index)) _hb_ot_layout_collect_features_features (face, table_tag, script_index, @@ -834,10 +872,10 @@ void hb_ot_layout_lookup_collect_glyphs (hb_face_t *face, hb_tag_t table_tag, unsigned int lookup_index, - hb_set_t *glyphs_before, /* OUT. May be nullptr */ - hb_set_t *glyphs_input, /* OUT. May be nullptr */ - hb_set_t *glyphs_after, /* OUT. May be nullptr */ - hb_set_t *glyphs_output /* OUT. May be nullptr */) + hb_set_t *glyphs_before, /* OUT. May be NULL */ + hb_set_t *glyphs_input, /* OUT. May be NULL */ + hb_set_t *glyphs_after, /* OUT. May be NULL */ + hb_set_t *glyphs_output /* OUT. May be NULL */) { if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return; @@ -851,13 +889,13 @@ hb_ot_layout_lookup_collect_glyphs (hb_face_t *face, { case HB_OT_TAG_GSUB: { - const OT::SubstLookup& l = hb_ot_layout_from_face (face)->table.GSUB->get_lookup (lookup_index); + const OT::SubstLookup& l = hb_ot_face_data (face)->GSUB->table->get_lookup (lookup_index); l.collect_glyphs (&c); return; } case HB_OT_TAG_GPOS: { - const OT::PosLookup& l = hb_ot_layout_from_face (face)->table.GPOS->get_lookup (lookup_index); + const OT::PosLookup& l = hb_ot_face_data (face)->GPOS->table->get_lookup (lookup_index); l.collect_glyphs (&c); return; } @@ -930,18 +968,19 @@ hb_ot_layout_lookup_would_substitute_fast (hb_face_t *face, unsigned int glyphs_length, hb_bool_t zero_context) { - if (unlikely (lookup_index >= hb_ot_layout_from_face (face)->gsub_lookup_count)) return false; + if (unlikely (lookup_index >= hb_ot_face_data (face)->GSUB->lookup_count)) return false; OT::hb_would_apply_context_t c (face, glyphs, glyphs_length, (bool) zero_context); - const OT::SubstLookup& l = hb_ot_layout_from_face (face)->table.GSUB->get_lookup (lookup_index); + const OT::SubstLookup& l = hb_ot_face_data (face)->GSUB->table->get_lookup (lookup_index); - return l.would_apply (&c, &hb_ot_layout_from_face (face)->gsub_accels[lookup_index]); + return l.would_apply (&c, &hb_ot_face_data (face)->GSUB->accels[lookup_index]); } void -hb_ot_layout_substitute_start (hb_font_t *font, hb_buffer_t *buffer) +hb_ot_layout_substitute_start (hb_font_t *font, + hb_buffer_t *buffer) { - OT::GSUB::substitute_start (font, buffer); +_hb_ot_layout_set_glyph_props (font, buffer); } /** @@ -1034,11 +1073,11 @@ hb_ot_layout_position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer) **/ hb_bool_t hb_ot_layout_get_size_params (hb_face_t *face, - unsigned int *design_size, /* OUT. May be nullptr */ - unsigned int *subfamily_id, /* OUT. May be nullptr */ - unsigned int *subfamily_name_id, /* OUT. May be nullptr */ - unsigned int *range_start, /* OUT. May be nullptr */ - unsigned int *range_end /* OUT. May be nullptr */) + unsigned int *design_size, /* OUT. May be NULL */ + unsigned int *subfamily_id, /* OUT. May be NULL */ + unsigned int *subfamily_name_id, /* OUT. May be NULL */ + unsigned int *range_start, /* OUT. May be NULL */ + unsigned int *range_end /* OUT. May be NULL */) { const OT::GPOS &gpos = _get_gpos (face); const hb_tag_t tag = HB_TAG ('s','i','z','e'); @@ -1053,30 +1092,152 @@ hb_ot_layout_get_size_params (hb_face_t *face, if (params.designSize) { -#define PARAM(a, A) if (a) *a = params.A - PARAM (design_size, designSize); - PARAM (subfamily_id, subfamilyID); - PARAM (subfamily_name_id, subfamilyNameID); - PARAM (range_start, rangeStart); - PARAM (range_end, rangeEnd); -#undef PARAM + if (design_size) *design_size = params.designSize; + if (subfamily_id) *subfamily_id = params.subfamilyID; + if (subfamily_name_id) *subfamily_name_id = params.subfamilyNameID; + if (range_start) *range_start = params.rangeStart; + if (range_end) *range_end = params.rangeEnd; return true; } } } -#define PARAM(a, A) if (a) *a = 0 - PARAM (design_size, designSize); - PARAM (subfamily_id, subfamilyID); - PARAM (subfamily_name_id, subfamilyNameID); - PARAM (range_start, rangeStart); - PARAM (range_end, rangeEnd); -#undef PARAM + if (design_size) *design_size = 0; + if (subfamily_id) *subfamily_id = 0; + if (subfamily_name_id) *subfamily_name_id = 0; + if (range_start) *range_start = 0; + if (range_end) *range_end = 0; return false; } +/** + * hb_ot_layout_feature_get_name_ids: + * @face: #hb_face_t to work upon + * @table_tag: + * @feature_index: + * @label_id: (out) (allow-none): The ‘name’ table name ID that specifies a string + * for a user-interface label for this feature. (May be NULL.) + * @tooltip_id: (out) (allow-none): The ‘name’ table name ID that specifies a string + * that an application can use for tooltip text for this + * feature. (May be NULL.) + * @sample_id: (out) (allow-none): The ‘name’ table name ID that specifies sample text + * that illustrates the effect of this feature. (May be NULL.) + * @num_named_parameters: (out) (allow-none): Number of named parameters. (May be zero.) + * @first_param_id: (out) (allow-none): The first ‘name’ table name ID used to specify + * strings for user-interface labels for the feature + * parameters. (Must be zero if numParameters is zero.) + * + * Fetches name indices from feature parameters for "Stylistic Set" ('ssXX') or + * "Character Variant" ('cvXX') features. + * + * Return value: true if data found, false otherwise + * + * Since: 2.0.0 + **/ +hb_bool_t +hb_ot_layout_feature_get_name_ids (hb_face_t *face, + hb_tag_t table_tag, + unsigned int feature_index, + hb_name_id_t *label_id, /* OUT. May be NULL */ + hb_name_id_t *tooltip_id, /* OUT. May be NULL */ + hb_name_id_t *sample_id, /* OUT. May be NULL */ + unsigned int *num_named_parameters, /* OUT. May be NULL */ + hb_name_id_t *first_param_id /* OUT. May be NULL */) +{ + const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag); + + hb_tag_t feature_tag = g.get_feature_tag (feature_index); + const OT::Feature &f = g.get_feature (feature_index); + + const OT::FeatureParams &feature_params = f.get_feature_params (); + if (&feature_params != &Null (OT::FeatureParams)) + { + const OT::FeatureParamsStylisticSet& ss_params = + feature_params.get_stylistic_set_params (feature_tag); + if (&ss_params != &Null (OT::FeatureParamsStylisticSet)) /* ssXX */ + { + if (label_id) *label_id = ss_params.uiNameID; + // ssXX features don't have the rest + if (tooltip_id) *tooltip_id = HB_NAME_ID_INVALID; + if (sample_id) *sample_id = HB_NAME_ID_INVALID; + if (num_named_parameters) *num_named_parameters = 0; + if (first_param_id) *first_param_id = HB_NAME_ID_INVALID; + return true; + } + const OT::FeatureParamsCharacterVariants& cv_params = + feature_params.get_character_variants_params (feature_tag); + if (&cv_params != &Null (OT::FeatureParamsCharacterVariants)) /* cvXX */ + { + if (label_id) *label_id = cv_params.featUILableNameID; + if (tooltip_id) *tooltip_id = cv_params.featUITooltipTextNameID; + if (sample_id) *sample_id = cv_params.sampleTextNameID; + if (num_named_parameters) *num_named_parameters = cv_params.numNamedParameters; + if (first_param_id) *first_param_id = cv_params.firstParamUILabelNameID; + return true; + } + } + + if (label_id) *label_id = HB_NAME_ID_INVALID; + if (tooltip_id) *tooltip_id = HB_NAME_ID_INVALID; + if (sample_id) *sample_id = HB_NAME_ID_INVALID; + if (num_named_parameters) *num_named_parameters = 0; + if (first_param_id) *first_param_id = HB_NAME_ID_INVALID; + return false; +} + +/** + * hb_ot_layout_feature_get_characters:: + * @face: #hb_face_t to work upon + * @table_tag: + * @feature_index: + * @start_offset: In case the resulting char_count was equal to its input value, there + * is a chance there were more characters on the tag so this API can be + * called with an offset till resulting char_count gets to a number + * lower than input buffer (or consider using just a bigger buffer for + * one shot copying). + * @char_count: (inout) (allow-none): The count of characters for which this feature + * provides glyph variants. (May be zero.) + * @characters: (out) (allow-none): A buffer pointer. The Unicode Scalar Value + * of the characters for which this feature provides glyph variants. + * + * Fetches characters listed by designer under feature parameters for "Character + * Variant" ("cvXX") features. + * + * Return value: Number of total sample characters in the cvXX feature. + * + * Since: 2.0.0 + **/ +unsigned int +hb_ot_layout_feature_get_characters (hb_face_t *face, + hb_tag_t table_tag, + unsigned int feature_index, + unsigned int start_offset, + unsigned int *char_count, /* IN/OUT. May be NULL */ + hb_codepoint_t *characters /* OUT. May be NULL */) +{ + const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag); + + hb_tag_t feature_tag = g.get_feature_tag (feature_index); + const OT::Feature &f = g.get_feature (feature_index); + + const OT::FeatureParams &feature_params = f.get_feature_params (); + + const OT::FeatureParamsCharacterVariants& cv_params = + feature_params.get_character_variants_params(feature_tag); + + unsigned int len = 0; + if (char_count && characters && start_offset < cv_params.characters.len) + { + len = MIN (cv_params.characters.len - start_offset, *char_count); + for (unsigned int i = 0; i < len; ++i) + characters[i] = cv_params.characters[start_offset + i]; + } + if (char_count) *char_count = len; + return cv_params.characters.len; +} + /* * Parts of different types are implemented here such that they have direct @@ -1086,86 +1247,36 @@ hb_ot_layout_get_size_params (hb_face_t *face, struct GSUBProxy { - static const unsigned int table_index = 0; + enum { table_index = 0 }; static const bool inplace = false; typedef OT::SubstLookup Lookup; GSUBProxy (hb_face_t *face) : - table (*hb_ot_layout_from_face (face)->table.GSUB), - accels (hb_ot_layout_from_face (face)->gsub_accels) {} + table (*hb_ot_face_data (face)->GSUB->table), + accels (hb_ot_face_data (face)->GSUB->accels) {} const OT::GSUB &table; - const hb_ot_layout_lookup_accelerator_t *accels; + const OT::hb_ot_layout_lookup_accelerator_t *accels; }; struct GPOSProxy { - static const unsigned int table_index = 1; + enum { table_index = 1 }; static const bool inplace = true; typedef OT::PosLookup Lookup; GPOSProxy (hb_face_t *face) : - table (*hb_ot_layout_from_face (face)->table.GPOS), - accels (hb_ot_layout_from_face (face)->gpos_accels) {} + table (*hb_ot_face_data (face)->GPOS->table), + accels (hb_ot_face_data (face)->GPOS->accels) {} const OT::GPOS &table; - const hb_ot_layout_lookup_accelerator_t *accels; + const OT::hb_ot_layout_lookup_accelerator_t *accels; }; -struct hb_get_subtables_context_t : - hb_dispatch_context_t<hb_get_subtables_context_t, hb_void_t, HB_DEBUG_APPLY> -{ - template <typename Type> - static inline bool apply_to (const void *obj, OT::hb_ot_apply_context_t *c) - { - const Type *typed_obj = (const Type *) obj; - return typed_obj->apply (c); - } - - typedef bool (*hb_apply_func_t) (const void *obj, OT::hb_ot_apply_context_t *c); - - struct hb_applicable_t - { - inline void init (const void *obj_, hb_apply_func_t apply_func_) - { - obj = obj_; - apply_func = apply_func_; - } - - inline bool apply (OT::hb_ot_apply_context_t *c) const { return apply_func (obj, c); } - - private: - const void *obj; - hb_apply_func_t apply_func; - }; - - typedef hb_auto_t<hb_vector_t<hb_applicable_t> > array_t; - - /* Dispatch interface. */ - inline const char *get_name (void) { return "GET_SUBTABLES"; } - template <typename T> - inline return_t dispatch (const T &obj) - { - hb_applicable_t *entry = array.push(); - entry->init (&obj, apply_to<T>); - return HB_VOID; - } - static return_t default_return_value (void) { return HB_VOID; } - bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return false; } - - hb_get_subtables_context_t (array_t &array_) : - array (array_), - debug_depth (0) {} - - array_t &array; - unsigned int debug_depth; -}; - static inline bool apply_forward (OT::hb_ot_apply_context_t *c, - const hb_ot_layout_lookup_accelerator_t &accel, - const hb_get_subtables_context_t::array_t &subtables) + const OT::hb_ot_layout_lookup_accelerator_t &accel) { bool ret = false; hb_buffer_t *buffer = c->buffer; @@ -1176,12 +1287,7 @@ apply_forward (OT::hb_ot_apply_context_t *c, (buffer->cur().mask & c->lookup_mask) && c->check_glyph_property (&buffer->cur(), c->lookup_props)) { - for (unsigned int i = 0; i < subtables.len; i++) - if (subtables[i].apply (c)) - { - applied = true; - break; - } + applied = accel.apply (c); } if (applied) @@ -1194,8 +1300,7 @@ apply_forward (OT::hb_ot_apply_context_t *c, static inline bool apply_backward (OT::hb_ot_apply_context_t *c, - const hb_ot_layout_lookup_accelerator_t &accel, - const hb_get_subtables_context_t::array_t &subtables) + const OT::hb_ot_layout_lookup_accelerator_t &accel) { bool ret = false; hb_buffer_t *buffer = c->buffer; @@ -1205,12 +1310,8 @@ apply_backward (OT::hb_ot_apply_context_t *c, (buffer->cur().mask & c->lookup_mask) && c->check_glyph_property (&buffer->cur(), c->lookup_props)) { - for (unsigned int i = 0; i < subtables.len; i++) - if (subtables[i].apply (c)) - { - ret = true; - break; - } + if (accel.apply (c)) + ret = true; } /* The reverse lookup doesn't "advance" cursor (for good reason). */ buffer->idx--; @@ -1224,7 +1325,7 @@ template <typename Proxy> static inline void apply_string (OT::hb_ot_apply_context_t *c, const typename Proxy::Lookup &lookup, - const hb_ot_layout_lookup_accelerator_t &accel) + const OT::hb_ot_layout_lookup_accelerator_t &accel) { hb_buffer_t *buffer = c->buffer; @@ -1233,10 +1334,6 @@ apply_string (OT::hb_ot_apply_context_t *c, c->set_lookup_props (lookup.get_props ()); - hb_get_subtables_context_t::array_t subtables; - hb_get_subtables_context_t c_get_subtables (subtables); - lookup.dispatch (&c_get_subtables); - if (likely (!lookup.is_reverse ())) { /* in/out forward substitution/positioning */ @@ -1245,7 +1342,7 @@ apply_string (OT::hb_ot_apply_context_t *c, buffer->idx = 0; bool ret; - ret = apply_forward (c, accel, subtables); + ret = apply_forward (c, accel); if (ret) { if (!Proxy::inplace) @@ -1261,7 +1358,7 @@ apply_string (OT::hb_ot_apply_context_t *c, buffer->remove_output (); buffer->idx = buffer->len - 1; - apply_backward (c, accel, subtables); + apply_backward (c, accel); } } @@ -1286,6 +1383,11 @@ inline void hb_ot_map_t::apply (const Proxy &proxy, c.set_lookup_mask (lookups[table_index][i].mask); c.set_auto_zwj (lookups[table_index][i].auto_zwj); c.set_auto_zwnj (lookups[table_index][i].auto_zwnj); + if (lookups[table_index][i].random) + { + c.set_random (true); + buffer->unsafe_to_break_all (); + } apply_string<Proxy> (&c, proxy.table.get_lookup (lookup_index), proxy.accels[lookup_index]); @@ -1315,31 +1417,7 @@ void hb_ot_map_t::position (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_ void hb_ot_layout_substitute_lookup (OT::hb_ot_apply_context_t *c, const OT::SubstLookup &lookup, - const hb_ot_layout_lookup_accelerator_t &accel) + const OT::hb_ot_layout_lookup_accelerator_t &accel) { apply_string<GSUBProxy> (c, lookup, accel); } - - - - -/* - * OT::BASE - */ - -// /** -// * hb_ot_base_has_data: -// * @face: #hb_face_t to test -// * -// * This function allows to verify the presence of an OpenType BASE table on the -// * face. -// * -// * Return value: true if face has a BASE table, false otherwise -// * -// * Since: XXX -// **/ -// hb_bool_t -// hb_ot_base_has_data (hb_face_t *face) -// { -// return _get_base (face).has_data (); -// } diff --git a/src/hb-ot-layout.h b/src/hb-ot-layout.h index 586fb1517..9bd18c8af 100644 --- a/src/hb-ot-layout.h +++ b/src/hb-ot-layout.h @@ -34,6 +34,7 @@ #include "hb.h" #include "hb-ot-tag.h" +#include "hb-ot-name.h" HB_BEGIN_DECLS @@ -111,13 +112,13 @@ hb_ot_layout_table_find_script (hb_face_t *face, hb_tag_t script_tag, unsigned int *script_index); -/* Like find_script, but takes zero-terminated array of scripts to test */ HB_EXTERN hb_bool_t -hb_ot_layout_table_choose_script (hb_face_t *face, +hb_ot_layout_table_select_script (hb_face_t *face, hb_tag_t table_tag, + unsigned int script_count, const hb_tag_t *script_tags, - unsigned int *script_index, - hb_tag_t *chosen_script); + unsigned int *script_index /* OUT */, + hb_tag_t *chosen_script /* OUT */); HB_EXTERN unsigned int hb_ot_layout_table_get_feature_tags (hb_face_t *face, @@ -135,11 +136,12 @@ hb_ot_layout_script_get_language_tags (hb_face_t *face, hb_tag_t *language_tags /* OUT */); HB_EXTERN hb_bool_t -hb_ot_layout_script_find_language (hb_face_t *face, - hb_tag_t table_tag, - unsigned int script_index, - hb_tag_t language_tag, - unsigned int *language_index); +hb_ot_layout_script_select_language (hb_face_t *face, + hb_tag_t table_tag, + unsigned int script_index, + unsigned int language_count, + const hb_tag_t *language_tags, + unsigned int *language_index /* OUT */); HB_EXTERN hb_bool_t hb_ot_layout_language_get_required_feature_index (hb_face_t *face, @@ -214,10 +216,10 @@ HB_EXTERN void hb_ot_layout_lookup_collect_glyphs (hb_face_t *face, hb_tag_t table_tag, unsigned int lookup_index, - hb_set_t *glyphs_before, /* OUT. May be NULL */ - hb_set_t *glyphs_input, /* OUT. May be NULL */ - hb_set_t *glyphs_after, /* OUT. May be NULL */ - hb_set_t *glyphs_output /* OUT. May be NULL */); + hb_set_t *glyphs_before, /* OUT. May be NULL */ + hb_set_t *glyphs_input, /* OUT. May be NULL */ + hb_set_t *glyphs_after, /* OUT. May be NULL */ + hb_set_t *glyphs_output /* OUT. May be NULL */); #ifdef HB_NOT_IMPLEMENTED typedef struct @@ -325,11 +327,30 @@ HB_EXTERN hb_bool_t hb_ot_layout_get_size_params (hb_face_t *face, unsigned int *design_size, /* OUT. May be NULL */ unsigned int *subfamily_id, /* OUT. May be NULL */ - unsigned int *subfamily_name_id, /* OUT. May be NULL */ + hb_name_id_t *subfamily_name_id, /* OUT. May be NULL */ unsigned int *range_start, /* OUT. May be NULL */ unsigned int *range_end /* OUT. May be NULL */); +HB_EXTERN hb_bool_t +hb_ot_layout_feature_get_name_ids (hb_face_t *face, + hb_tag_t table_tag, + unsigned int feature_index, + hb_name_id_t *label_id /* OUT. May be NULL */, + hb_name_id_t *tooltip_id /* OUT. May be NULL */, + hb_name_id_t *sample_id /* OUT. May be NULL */, + unsigned int *num_named_parameters /* OUT. May be NULL */, + hb_name_id_t *first_param_id /* OUT. May be NULL */); + + +HB_EXTERN unsigned int +hb_ot_layout_feature_get_characters (hb_face_t *face, + hb_tag_t table_tag, + unsigned int feature_index, + unsigned int start_offset, + unsigned int *char_count /* IN/OUT. May be NULL */, + hb_codepoint_t *characters /* OUT. May be NULL */); + /* * BASE */ diff --git a/src/hb-ot-layout-private.hh b/src/hb-ot-layout.hh index 612bc7fce..64b3d7480 100644 --- a/src/hb-ot-layout-private.hh +++ b/src/hb-ot-layout.hh @@ -26,15 +26,40 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_OT_LAYOUT_PRIVATE_HH -#define HB_OT_LAYOUT_PRIVATE_HH +#ifndef HB_OT_LAYOUT_HH +#define HB_OT_LAYOUT_HH -#include "hb-private.hh" +#include "hb.hh" -#include "hb-font-private.hh" -#include "hb-buffer-private.hh" -#include "hb-set-digest-private.hh" -#include "hb-open-type-private.hh" +#include "hb-font.hh" +#include "hb-buffer.hh" +#include "hb-open-type.hh" +#include "hb-set-digest.hh" + + +namespace OT +{ + struct GDEF; + struct GSUB; + struct GPOS; +} + +HB_INTERNAL const OT::GDEF& _get_gdef (hb_face_t *face); +HB_INTERNAL const OT::GSUB& _get_gsub_relaxed (hb_face_t *face); +HB_INTERNAL const OT::GPOS& _get_gpos_relaxed (hb_face_t *face); + + +/* + * kern + */ + +HB_INTERNAL hb_bool_t +hb_ot_layout_has_kerning (hb_face_t *face); + +HB_INTERNAL void +hb_ot_layout_kern (hb_font_t *font, + hb_buffer_t *buffer, + hb_mask_t kern_mask); /* Private API corresponding to hb-ot-layout.h: */ @@ -87,17 +112,16 @@ hb_ot_layout_substitute_start (hb_font_t *font, hb_buffer_t *buffer); -struct hb_ot_layout_lookup_accelerator_t; - namespace OT { struct hb_ot_apply_context_t; struct SubstLookup; + struct hb_ot_layout_lookup_accelerator_t; } HB_INTERNAL void hb_ot_layout_substitute_lookup (OT::hb_ot_apply_context_t *c, const OT::SubstLookup &lookup, - const hb_ot_layout_lookup_accelerator_t &accel); + const OT::hb_ot_layout_lookup_accelerator_t &accel); /* Should be called before all the position_lookup's are done. */ @@ -116,112 +140,6 @@ hb_ot_layout_position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer); - -/* - * hb_ot_layout_t - */ - -struct hb_ot_layout_lookup_accelerator_t -{ - template <typename TLookup> - inline void init (const TLookup &lookup) - { - digest.init (); - lookup.add_coverage (&digest); - } - - inline void fini (void) - { - } - - inline bool may_have (hb_codepoint_t g) const { - return digest.may_have (g); - } - - private: - hb_set_digest_t digest; -}; - -/* Most of these tables are NOT needed for shaping. But we need to hook them *somewhere*. - * This is as good as any place. */ -#define HB_OT_LAYOUT_TABLES \ - /* OpenType shaping. */ \ - HB_OT_LAYOUT_TABLE(OT, GDEF) \ - HB_OT_LAYOUT_TABLE(OT, GSUB) \ - HB_OT_LAYOUT_TABLE(OT, GPOS) \ - HB_OT_LAYOUT_TABLE(OT, JSTF) \ - HB_OT_LAYOUT_TABLE(OT, BASE) \ - /* AAT shaping. */ \ - HB_OT_LAYOUT_TABLE(AAT, morx) \ - HB_OT_LAYOUT_TABLE(AAT, kerx) \ - HB_OT_LAYOUT_TABLE(AAT, ankr) \ - HB_OT_LAYOUT_TABLE(AAT, trak) \ - /* OpenType variations. */ \ - HB_OT_LAYOUT_TABLE(OT, fvar) \ - HB_OT_LAYOUT_TABLE(OT, avar) \ - HB_OT_LAYOUT_TABLE(OT, MVAR) \ - /* OpenType color. */ \ - HB_OT_LAYOUT_TABLE(OT, COLR) \ - HB_OT_LAYOUT_TABLE(OT, CPAL) \ - HB_OT_LAYOUT_TABLE(OT, CBDT) \ - HB_OT_LAYOUT_TABLE(OT, CBLC) \ - HB_OT_LAYOUT_TABLE(OT, sbix) \ - HB_OT_LAYOUT_TABLE(OT, svg) \ - /* OpenType math. */ \ - HB_OT_LAYOUT_TABLE(OT, MATH) \ - /* OpenType fundamentals. */ \ - HB_OT_LAYOUT_TABLE(OT, post) \ - /* */ - -/* Declare tables. */ -#define HB_OT_LAYOUT_TABLE(Namespace, Type) namespace Namespace { struct Type; } -HB_OT_LAYOUT_TABLES -#undef HB_OT_LAYOUT_TABLE - -struct hb_ot_layout_t -{ - unsigned int gsub_lookup_count; - unsigned int gpos_lookup_count; - - hb_ot_layout_lookup_accelerator_t *gsub_accels; - hb_ot_layout_lookup_accelerator_t *gpos_accels; - - /* Various non-shaping tables. */ - struct tables_t - { - HB_INTERNAL void init0 (hb_face_t *face); - HB_INTERNAL void fini (void); - -#define HB_OT_LAYOUT_TABLE_ORDER(Namespace, Type) \ - HB_PASTE (ORDER_, HB_PASTE (Namespace, HB_PASTE (_, Type))) - enum order_t - { - ORDER_ZERO, -#define HB_OT_LAYOUT_TABLE(Namespace, Type) \ - HB_OT_LAYOUT_TABLE_ORDER (Namespace, Type), - HB_OT_LAYOUT_TABLES -#undef HB_OT_LAYOUT_TABLE - }; - - hb_face_t *face; /* MUST be JUST before the lazy loaders. */ -#define HB_OT_LAYOUT_TABLE(Namespace, Type) \ - hb_table_lazy_loader_t<struct Namespace::Type, HB_OT_LAYOUT_TABLE_ORDER (Namespace, Type)> Type; - HB_OT_LAYOUT_TABLES -#undef HB_OT_LAYOUT_TABLE - } table; -}; - - -HB_INTERNAL hb_ot_layout_t * -_hb_ot_layout_create (hb_face_t *face); - -HB_INTERNAL void -_hb_ot_layout_destroy (hb_ot_layout_t *layout); - - -#define hb_ot_layout_from_face(face) ((hb_ot_layout_t *) face->shaper_data.ot.get_relaxed ()) - - /* * Buffer var routines. */ @@ -239,12 +157,12 @@ _hb_ot_layout_destroy (hb_ot_layout_t *layout); #define foreach_syllable(buffer, start, end) \ for (unsigned int \ _count = buffer->len, \ - start = 0, end = _count ? _next_syllable (buffer, 0) : 0; \ + start = 0, end = _count ? _hb_next_syllable (buffer, 0) : 0; \ start < _count; \ - start = end, end = _next_syllable (buffer, start)) + start = end, end = _hb_next_syllable (buffer, start)) static inline unsigned int -_next_syllable (hb_buffer_t *buffer, unsigned int start) +_hb_next_syllable (hb_buffer_t *buffer, unsigned int start) { hb_glyph_info_t *info = buffer->info; unsigned int count = buffer->len; @@ -267,7 +185,7 @@ _next_syllable (hb_buffer_t *buffer, unsigned int start) * * Whether it's one of the three Mongolian Free Variation Selectors, * CGJ, or other characters that are hidden but should not be ignored * like most other Default_Ignorable()s do during matching. - * * One free bit right now. + * * Whether it's a grapheme continuation. * * The high-byte has different meanings, switched by the Gen-Cat: * - For Mn,Mc,Me: the modified Combining_Class. @@ -279,8 +197,8 @@ _next_syllable (hb_buffer_t *buffer, unsigned int start) enum hb_unicode_props_flags_t { UPROPS_MASK_GEN_CAT = 0x001Fu, UPROPS_MASK_IGNORABLE = 0x0020u, - UPROPS_MASK_HIDDEN = 0x0040u, /* MONGOLIAN FREE VARIATION SELECTOR 1..3, - * or TAG characters */ + UPROPS_MASK_HIDDEN = 0x0040u, /* MONGOLIAN FREE VARIATION SELECTOR 1..3, or TAG characters */ + UPROPS_MASK_CONTINUATION=0x0080u, /* If GEN_CAT=FORMAT, top byte masks: */ UPROPS_MASK_Cf_ZWJ = 0x0100u, @@ -299,6 +217,7 @@ _hb_glyph_info_set_unicode_props (hb_glyph_info_t *info, hb_buffer_t *buffer) if (u >= 0x80) { buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII; + if (unlikely (unicode->is_default_ignorable (u))) { buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES; @@ -324,35 +243,11 @@ _hb_glyph_info_set_unicode_props (hb_glyph_info_t *info, hb_buffer_t *buffer) props |= UPROPS_MASK_HIDDEN; } } - else if (unlikely (HB_UNICODE_GENERAL_CATEGORY_IS_NON_ENCLOSING_MARK_OR_MODIFIER_SYMBOL (gen_cat))) + + if (unlikely (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (gen_cat))) { - /* The above check is just an optimization to let in only things we need further - * processing on. */ - - /* Only Mn and Mc can have non-zero ccc: - * https://unicode.org/policies/stability_policy.html#Property_Value - * """ - * Canonical_Combining_Class, General_Category - * All characters other than those with General_Category property values - * Spacing_Mark (Mc) and Nonspacing_Mark (Mn) have the Canonical_Combining_Class - * property value 0. - * 1.1.5+ - * """ - * - * Also, all Mn's that are Default_Ignorable, have ccc=0, hence - * the "else if". - */ - props |= unicode->modified_combining_class (info->codepoint)<<8; - - /* Recategorize emoji skin-tone modifiers as Unicode mark, so they - * behave correctly in non-native directionality. They originally - * are MODIFIER_SYMBOL. Fixes: - * https://github.com/harfbuzz/harfbuzz/issues/169 - */ - if (unlikely (hb_in_range (u, 0x1F3FBu, 0x1F3FFu))) - { - props = gen_cat = HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK; - } + props |= UPROPS_MASK_CONTINUATION; + props |= unicode->modified_combining_class (u)<<8; } } @@ -391,29 +286,6 @@ _hb_glyph_info_get_modified_combining_class (const hb_glyph_info_t *info) { return _hb_glyph_info_is_unicode_mark (info) ? info->unicode_props()>>8 : 0; } - - -/* Loop over grapheme. Based on foreach_cluster(). */ -#define foreach_grapheme(buffer, start, end) \ - for (unsigned int \ - _count = buffer->len, \ - start = 0, end = _count ? _next_grapheme (buffer, 0) : 0; \ - start < _count; \ - start = end, end = _next_grapheme (buffer, start)) - -static inline unsigned int -_next_grapheme (hb_buffer_t *buffer, unsigned int start) -{ - hb_glyph_info_t *info = buffer->info; - unsigned int count = buffer->len; - - while (++start < count && _hb_glyph_info_is_unicode_mark (&info[start])) - ; - - return start; -} - - #define info_cc(info) (_hb_glyph_info_get_modified_combining_class (&(info))) static inline bool @@ -458,6 +330,41 @@ _hb_glyph_info_unhide (hb_glyph_info_t *info) info->unicode_props() &= ~ UPROPS_MASK_HIDDEN; } +static inline void +_hb_glyph_info_set_continuation (hb_glyph_info_t *info) +{ + info->unicode_props() |= UPROPS_MASK_CONTINUATION; +} +static inline void +_hb_glyph_info_reset_continuation (hb_glyph_info_t *info) +{ + info->unicode_props() &= ~ UPROPS_MASK_CONTINUATION; +} +static inline bool +_hb_glyph_info_is_continuation (const hb_glyph_info_t *info) +{ + return info->unicode_props() & UPROPS_MASK_CONTINUATION; +} +/* Loop over grapheme. Based on foreach_cluster(). */ +#define foreach_grapheme(buffer, start, end) \ + for (unsigned int \ + _count = buffer->len, \ + start = 0, end = _count ? _hb_next_grapheme (buffer, 0) : 0; \ + start < _count; \ + start = end, end = _hb_next_grapheme (buffer, start)) + +static inline unsigned int +_hb_next_grapheme (hb_buffer_t *buffer, unsigned int start) +{ + hb_glyph_info_t *info = buffer->info; + unsigned int count = buffer->len; + + while (++start < count && _hb_glyph_info_is_continuation (&info[start])) + ; + + return start; +} + static inline bool _hb_glyph_info_is_unicode_format (const hb_glyph_info_t *info) { @@ -701,4 +608,4 @@ _hb_buffer_assert_gsubgpos_vars (hb_buffer_t *buffer) #undef lig_props #undef glyph_props -#endif /* HB_OT_LAYOUT_PRIVATE_HH */ +#endif /* HB_OT_LAYOUT_HH */ diff --git a/src/hb-ot-map.cc b/src/hb-ot-map.cc index f26cac9b1..45d7dbdcf 100644 --- a/src/hb-ot-map.cc +++ b/src/hb-ot-map.cc @@ -26,9 +26,9 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-ot-map-private.hh" +#include "hb-ot-map.hh" -#include "hb-ot-layout-private.hh" +#include "hb-ot-layout.hh" void hb_ot_map_t::collect_lookups (unsigned int table_index, hb_set_t *lookups_out) const @@ -54,16 +54,17 @@ hb_ot_map_builder_t::hb_ot_map_builder_t (hb_face_t *face_, /* Fetch script/language indices for GSUB/GPOS. We need these later to skip * features not available in either table and not waste precious bits for them. */ - hb_tag_t script_tags[3] = {HB_TAG_NONE, HB_TAG_NONE, HB_TAG_NONE}; - hb_tag_t language_tag; + unsigned int script_count = HB_OT_MAX_TAGS_PER_SCRIPT; + unsigned int language_count = HB_OT_MAX_TAGS_PER_LANGUAGE; + hb_tag_t script_tags[HB_OT_MAX_TAGS_PER_SCRIPT]; + hb_tag_t language_tags[HB_OT_MAX_TAGS_PER_LANGUAGE]; - hb_ot_tags_from_script (props.script, &script_tags[0], &script_tags[1]); - language_tag = hb_ot_tag_from_language (props.language); + hb_ot_tags_from_script_and_language (props.script, props.language, &script_count, script_tags, &language_count, language_tags); for (unsigned int table_index = 0; table_index < 2; table_index++) { hb_tag_t table_tag = table_tags[table_index]; - found_script[table_index] = (bool) hb_ot_layout_table_choose_script (face, table_tag, script_tags, &script_index[table_index], &chosen_script[table_index]); - hb_ot_layout_script_find_language (face, table_tag, script_index[table_index], language_tag, &language_index[table_index]); + found_script[table_index] = (bool) hb_ot_layout_table_select_script (face, table_tag, script_count, script_tags, &script_index[table_index], &chosen_script[table_index]); + hb_ot_layout_script_select_language (face, table_tag, script_index[table_index], language_count, language_tags, &language_index[table_index]); } } @@ -74,8 +75,9 @@ hb_ot_map_builder_t::~hb_ot_map_builder_t (void) stages[table_index].fini (); } -void hb_ot_map_builder_t::add_feature (hb_tag_t tag, unsigned int value, - hb_ot_map_feature_flags_t flags) +void hb_ot_map_builder_t::add_feature (hb_tag_t tag, + hb_ot_map_feature_flags_t flags, + unsigned int value) { feature_info_t *info = feature_infos.push(); if (unlikely (!tag)) return; @@ -95,7 +97,8 @@ hb_ot_map_builder_t::add_lookups (hb_ot_map_t &m, unsigned int variations_index, hb_mask_t mask, bool auto_zwnj, - bool auto_zwj) + bool auto_zwj, + bool random) { unsigned int lookup_indices[32]; unsigned int offset, len; @@ -122,6 +125,7 @@ hb_ot_map_builder_t::add_lookups (hb_ot_map_t &m, lookup->index = lookup_indices[i]; lookup->auto_zwnj = auto_zwnj; lookup->auto_zwj = auto_zwj; + lookup->random = random; } offset += len; @@ -208,8 +212,8 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m, /* Uses the global bit */ bits_needed = 0; else - /* Limit to 8 bits per feature. */ - bits_needed = MIN(8u, hb_bit_storage (info->max_value)); + /* Limit bits per feature. */ + bits_needed = MIN(HB_OT_MAP_MAX_BITS, hb_bit_storage (info->max_value)); if (!info->max_value || next_bit + bits_needed > 8 * sizeof (hb_mask_t)) continue; /* Feature disabled, or not enough bits. */ @@ -252,6 +256,7 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m, map->stage[1] = info->stage[1]; map->auto_zwnj = !(info->flags & F_MANUAL_ZWNJ); map->auto_zwj = !(info->flags & F_MANUAL_ZWJ); + map->random = !!(info->flags & F_RANDOM); if ((info->flags & F_GLOBAL) && info->max_value == 1) { /* Uses the global bit */ map->shift = global_bit_shift; @@ -301,7 +306,8 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m, variations_index, m.features[i].mask, m.features[i].auto_zwnj, - m.features[i].auto_zwj); + m.features[i].auto_zwj, + m.features[i].random); /* Sort lookups and merge duplicates */ if (last_num_lookups < m.lookups[table_index].len) diff --git a/src/hb-ot-map-private.hh b/src/hb-ot-map.hh index 4aaf32831..40b9921fd 100644 --- a/src/hb-ot-map-private.hh +++ b/src/hb-ot-map.hh @@ -26,12 +26,15 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_OT_MAP_PRIVATE_HH -#define HB_OT_MAP_PRIVATE_HH +#ifndef HB_OT_MAP_HH +#define HB_OT_MAP_HH -#include "hb-buffer-private.hh" +#include "hb-buffer.hh" +#define HB_OT_MAP_MAX_BITS 8u +#define HB_OT_MAP_MAX_VALUE ((1u << HB_OT_MAP_MAX_BITS) - 1u) + struct hb_ot_shape_plan_t; static const hb_tag_t table_tags[2] = {HB_OT_TAG_GSUB, HB_OT_TAG_GPOS}; @@ -52,6 +55,7 @@ struct hb_ot_map_t unsigned int needs_fallback : 1; unsigned int auto_zwnj : 1; unsigned int auto_zwj : 1; + unsigned int random : 1; inline int cmp (const hb_tag_t *tag_) const { return *tag_ < tag ? -1 : *tag_ > tag ? 1 : 0; } @@ -61,6 +65,7 @@ struct hb_ot_map_t unsigned short index; unsigned short auto_zwnj : 1; unsigned short auto_zwj : 1; + unsigned short random : 1; hb_mask_t mask; static int cmp (const void *pa, const void *pb) @@ -161,17 +166,27 @@ struct hb_ot_map_t hb_vector_t<stage_map_t, 4> stages[2]; /* GSUB/GPOS */ }; -enum hb_ot_map_feature_flags_t { +enum hb_ot_map_feature_flags_t +{ F_NONE = 0x0000u, F_GLOBAL = 0x0001u, /* Feature applies to all characters; results in no mask allocated for it. */ F_HAS_FALLBACK = 0x0002u, /* Has fallback implementation, so include mask bit even if feature not found. */ F_MANUAL_ZWNJ = 0x0004u, /* Don't skip over ZWNJ when matching **context**. */ F_MANUAL_ZWJ = 0x0008u, /* Don't skip over ZWJ when matching **input**. */ - F_GLOBAL_SEARCH = 0x0010u /* If feature not found in LangSys, look for it in global feature list and pick one. */ + F_MANUAL_JOINERS = F_MANUAL_ZWNJ | F_MANUAL_ZWJ, + F_GLOBAL_MANUAL_JOINERS= F_GLOBAL | F_MANUAL_JOINERS, + F_GLOBAL_HAS_FALLBACK = F_GLOBAL | F_HAS_FALLBACK, + F_GLOBAL_SEARCH = 0x0010u, /* If feature not found in LangSys, look for it in global feature list and pick one. */ + F_RANDOM = 0x0020u /* Randomly select a glyph from an AlternateSubstFormat1 subtable. */ }; HB_MARK_AS_FLAG_T (hb_ot_map_feature_flags_t); -/* Macro version for where const is desired. */ -#define F_COMBINE(l,r) (hb_ot_map_feature_flags_t ((unsigned int) (l) | (unsigned int) (r))) + + +struct hb_ot_map_feature_t +{ + hb_tag_t tag; + hb_ot_map_feature_flags_t flags; +}; struct hb_ot_map_builder_t @@ -183,11 +198,20 @@ struct hb_ot_map_builder_t HB_INTERNAL ~hb_ot_map_builder_t (void); - HB_INTERNAL void add_feature (hb_tag_t tag, unsigned int value, - hb_ot_map_feature_flags_t flags); + HB_INTERNAL void add_feature (hb_tag_t tag, + hb_ot_map_feature_flags_t flags=F_NONE, + unsigned int value=1); + + inline void add_feature (const hb_ot_map_feature_t &feat) + { add_feature (feat.tag, feat.flags); } + + inline void enable_feature (hb_tag_t tag, + hb_ot_map_feature_flags_t flags=F_NONE, + unsigned int value=1) + { add_feature (tag, F_GLOBAL | flags, value); } - inline void add_global_bool_feature (hb_tag_t tag) - { add_feature (tag, 1, F_GLOBAL); } + inline void disable_feature (hb_tag_t tag) + { add_feature (tag, F_GLOBAL, 0); } inline void add_gsub_pause (hb_ot_map_t::pause_func_t pause_func) { add_pause (0, pause_func); } @@ -206,7 +230,8 @@ struct hb_ot_map_builder_t unsigned int variations_index, hb_mask_t mask, bool auto_zwnj = true, - bool auto_zwj = true); + bool auto_zwj = true, + bool random = false); struct feature_info_t { hb_tag_t tag; @@ -250,4 +275,4 @@ struct hb_ot_map_builder_t -#endif /* HB_OT_MAP_PRIVATE_HH */ +#endif /* HB_OT_MAP_HH */ diff --git a/src/hb-ot-math-table.hh b/src/hb-ot-math-table.hh index 2dd714580..2f871124c 100644 --- a/src/hb-ot-math-table.hh +++ b/src/hb-ot-math-table.hh @@ -27,8 +27,8 @@ #ifndef HB_OT_MATH_TABLE_HH #define HB_OT_MATH_TABLE_HH -#include "hb-open-type-private.hh" -#include "hb-ot-layout-common-private.hh" +#include "hb-open-type.hh" +#include "hb-ot-layout-common.hh" #include "hb-ot-math.h" namespace OT { @@ -50,7 +50,7 @@ struct MathValueRecord protected: HBINT16 value; /* The X or Y value in design units */ OffsetTo<Device> deviceTable; /* Offset to the device table - from the - * beginning of parent table. May be nullptr. + * beginning of parent table. May be NULL. * Suggested format for device table is 1. */ public: @@ -234,7 +234,7 @@ struct MathKern TRACE_SANITIZE (this); unsigned int count = 2 * heightCount + 1; for (unsigned int i = 0; i < count; i++) - if (!mathValueRecords[i].sanitize (c, this)) return_trace (false); + if (!mathValueRecordsZ.arrayZ[i].sanitize (c, this)) return_trace (false); return_trace (true); } @@ -242,16 +242,14 @@ struct MathKern { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && - c->check_array (mathValueRecords, - mathValueRecords[0].static_size, - 2 * heightCount + 1) && + c->check_array (mathValueRecordsZ.arrayZ, 2 * heightCount + 1) && sanitize_math_value_records (c)); } inline hb_position_t get_value (hb_position_t correction_height, hb_font_t *font) const { - const MathValueRecord* correctionHeight = mathValueRecords; - const MathValueRecord* kernValue = mathValueRecords + heightCount; + const MathValueRecord* correctionHeight = mathValueRecordsZ.arrayZ; + const MathValueRecord* kernValue = mathValueRecordsZ.arrayZ + heightCount; int sign = font->y_scale < 0 ? -1 : +1; /* The description of the MathKern table is a ambiguous, but interpreting @@ -279,18 +277,19 @@ struct MathKern } protected: - HBUINT16 heightCount; - MathValueRecord mathValueRecords[VAR]; /* Array of correction heights at - * which the kern value changes. - * Sorted by the height value in - * design units (heightCount entries), - * Followed by: - * Array of kern values corresponding - * to heights. (heightCount+1 entries). - */ + HBUINT16 heightCount; + UnsizedArrayOf<MathValueRecord> + mathValueRecordsZ; /* Array of correction heights at + * which the kern value changes. + * Sorted by the height value in + * design units (heightCount entries), + * Followed by: + * Array of kern values corresponding + * to heights. (heightCount+1 entries). + */ public: - DEFINE_SIZE_ARRAY (2, mathValueRecords); + DEFINE_SIZE_ARRAY (2, mathValueRecordsZ); }; struct MathKernInfoRecord @@ -319,7 +318,7 @@ struct MathKernInfoRecord protected: /* Offset to MathKern table for each corner - - * from the beginning of MathKernInfo table. May be nullptr. */ + * from the beginning of MathKernInfo table. May be NULL. */ OffsetTo<MathKern> mathKern[4]; public: @@ -402,7 +401,7 @@ struct MathGlyphInfo * from the beginning of MathGlyphInfo table. When the left or right glyph of * a box is an extended shape variant, the (ink) box (and not the default * position defined by values in MathConstants table) should be used for - * vertical positioning purposes. May be nullptr.. */ + * vertical positioning purposes. May be NULL.. */ OffsetTo<Coverage> extendedShapeCoverage; /* Offset to MathKernInfo table - @@ -571,7 +570,7 @@ struct MathGlyphConstruction protected: /* Offset to MathGlyphAssembly table for this shape - from the beginning of - MathGlyphConstruction table. May be nullptr. */ + MathGlyphConstruction table. May be NULL. */ OffsetTo<MathGlyphAssembly> glyphAssembly; /* MathGlyphVariantRecords for alternative variants of the glyphs. */ @@ -588,7 +587,7 @@ struct MathVariants TRACE_SANITIZE (this); unsigned int count = vertGlyphCount + horizGlyphCount; for (unsigned int i = 0; i < count; i++) - if (!glyphConstruction[i].sanitize (c, this)) return_trace (false); + if (!glyphConstruction.arrayZ[i].sanitize (c, this)) return_trace (false); return_trace (true); } @@ -598,9 +597,7 @@ struct MathVariants return_trace (c->check_struct (this) && vertGlyphCoverage.sanitize (c, this) && horizGlyphCoverage.sanitize (c, this) && - c->check_array (glyphConstruction, - glyphConstruction[0].static_size, - vertGlyphCount + horizGlyphCount) && + c->check_array (glyphConstruction.arrayZ, vertGlyphCount + horizGlyphCount) && sanitize_offsets (c)); } @@ -670,7 +667,8 @@ struct MathVariants /* Array of offsets to MathGlyphConstruction tables - from the beginning of the MathVariants table, for shapes growing in vertical/horizontal direction. */ - OffsetTo<MathGlyphConstruction> glyphConstruction[VAR]; + UnsizedArrayOf<OffsetTo<MathGlyphConstruction> > + glyphConstruction; public: DEFINE_SIZE_ARRAY (10, glyphConstruction); diff --git a/src/hb-ot-math.cc b/src/hb-ot-math.cc index 66ce207a7..c693f4807 100644 --- a/src/hb-ot-math.cc +++ b/src/hb-ot-math.cc @@ -24,17 +24,17 @@ * Igalia Author(s): Frédéric Wang */ -#include "hb-open-type-private.hh" +#include "hb-open-type.hh" -#include "hb-ot-layout-private.hh" +#include "hb-ot-face.hh" #include "hb-ot-math-table.hh" static inline const OT::MATH& _get_math (hb_face_t *face) { if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::MATH); - hb_ot_layout_t * layout = hb_ot_layout_from_face (face); - return *(layout->table.MATH.get ()); + hb_ot_face_data_t * data = hb_ot_face_data (face); + return *(data->MATH.get ()); } /* diff --git a/src/hb-ot-maxp-table.hh b/src/hb-ot-maxp-table.hh index 75aac4f44..2572ad288 100644 --- a/src/hb-ot-maxp-table.hh +++ b/src/hb-ot-maxp-table.hh @@ -27,8 +27,7 @@ #ifndef HB_OT_MAXP_TABLE_HH #define HB_OT_MAXP_TABLE_HH -#include "hb-open-type-private.hh" -#include "hb-subset-plan.hh" +#include "hb-open-type.hh" namespace OT { @@ -137,7 +136,7 @@ struct maxp FixedVersion<>version; /* Version of the maxp table (0.5 or 1.0), * 0x00005000u or 0x00010000u. */ HBUINT16 numGlyphs; /* The number of glyphs in the font. */ -/*maxpV1Tail v1Tail[VAR]; */ +/*maxpV1Tail v1Tail[VAR]; */ public: DEFINE_SIZE_STATIC (6); }; diff --git a/src/hb-ot-name-table.hh b/src/hb-ot-name-table.hh index bff85df27..bb49c2cb0 100644 --- a/src/hb-ot-name-table.hh +++ b/src/hb-ot-name-table.hh @@ -27,7 +27,7 @@ #ifndef HB_OT_NAME_TABLE_HH #define HB_OT_NAME_TABLE_HH -#include "hb-open-type-private.hh" +#include "hb-open-type.hh" namespace OT { @@ -91,7 +91,7 @@ struct name key.encodingID.set (encoding_id); key.languageID.set (language_id); key.nameID.set (name_id); - NameRecord *match = (NameRecord *) bsearch (&key, nameRecord, count, sizeof (nameRecord[0]), NameRecord::cmp); + NameRecord *match = (NameRecord *) bsearch (&key, nameRecordZ.arrayZ, count, sizeof (nameRecordZ[0]), NameRecord::cmp); if (!match) return 0; @@ -102,14 +102,14 @@ struct name } inline unsigned int get_size (void) const - { return min_size + count * nameRecord[0].min_size; } + { return min_size + count * nameRecordZ[0].min_size; } inline bool sanitize_records (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); char *string_pool = (char *) this + stringOffset; unsigned int _count = count; for (unsigned int i = 0; i < _count; i++) - if (!nameRecord[i].sanitize (c, string_pool)) return_trace (false); + if (!nameRecordZ[i].sanitize (c, string_pool)) return_trace (false); return_trace (true); } @@ -118,7 +118,7 @@ struct name TRACE_SANITIZE (this); return_trace (c->check_struct (this) && likely (format == 0 || format == 1) && - c->check_array (nameRecord, nameRecord[0].static_size, count) && + c->check_array (nameRecordZ.arrayZ, count) && sanitize_records (c)); } @@ -126,9 +126,10 @@ struct name HBUINT16 format; /* Format selector (=0/1). */ HBUINT16 count; /* Number of name records. */ Offset16 stringOffset; /* Offset to start of string storage (from start of table). */ - NameRecord nameRecord[VAR]; /* The name records where count is the number of records. */ + UnsizedArrayOf<NameRecord> + nameRecordZ; /* The name records where count is the number of records. */ public: - DEFINE_SIZE_ARRAY (6, nameRecord); + DEFINE_SIZE_ARRAY (6, nameRecordZ); }; diff --git a/src/hb-aat-layout-private.hh b/src/hb-ot-name.h index ce75c8e71..49423e87c 100644 --- a/src/hb-aat-layout-private.hh +++ b/src/hb-ot-name.h @@ -1,5 +1,5 @@ /* - * Copyright © 2017 Google, Inc. + * Copyright © 2018 Ebrahim Byagowi. * * This is part of HarfBuzz, a text shaping library. * @@ -20,24 +20,34 @@ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Google Author(s): Behdad Esfahbod */ -#ifndef HB_AAT_LAYOUT_PRIVATE_HH -#define HB_AAT_LAYOUT_PRIVATE_HH +#ifndef HB_OT_H_IN +#error "Include <hb-ot.h> instead." +#endif + +#ifndef HB_OT_NAME_H +#define HB_OT_NAME_H + +#include "hb.h" -#include "hb-private.hh" +HB_BEGIN_DECLS -#include "hb-font-private.hh" -#include "hb-buffer-private.hh" -#include "hb-open-type-private.hh" +/** + * hb_name_id_t: + * + * Since: 2.0.0 + */ +typedef unsigned int hb_name_id_t; -HB_INTERNAL void -hb_aat_layout_substitute (hb_font_t *font, hb_buffer_t *buffer); +/** + * HB_NAME_ID_INVALID + * + * Since: 2.0.0 + **/ +#define HB_NAME_ID_INVALID 0xFFFF -HB_INTERNAL void -hb_aat_layout_position (hb_font_t *font, hb_buffer_t *buffer); +HB_END_DECLS -#endif /* HB_AAT_LAYOUT_PRIVATE_HH */ +#endif /* HB_OT_NAME_H */ diff --git a/src/hb-ot-os2-table.hh b/src/hb-ot-os2-table.hh index 56bbab741..71d2bf59d 100644 --- a/src/hb-ot-os2-table.hh +++ b/src/hb-ot-os2-table.hh @@ -27,9 +27,8 @@ #ifndef HB_OT_OS2_TABLE_HH #define HB_OT_OS2_TABLE_HH -#include "hb-open-type-private.hh" +#include "hb-open-type.hh" #include "hb-ot-os2-unicode-ranges.hh" -#include "hb-subset-plan.hh" namespace OT { @@ -82,7 +81,7 @@ struct os2 hb_codepoint_t cp = HB_SET_VALUE_INVALID; while (codepoints->next (&cp)) { - unsigned int bit = hb_get_unicode_range_bit (cp); + unsigned int bit = _hb_ot_os2_get_unicode_range_bit (cp); if (bit < 128) { unsigned int block = bit / 32; diff --git a/src/hb-ot-os2-unicode-ranges.hh b/src/hb-ot-os2-unicode-ranges.hh index cb1260784..19780088a 100644 --- a/src/hb-ot-os2-unicode-ranges.hh +++ b/src/hb-ot-os2-unicode-ranges.hh @@ -27,18 +27,33 @@ #ifndef HB_OT_OS2_UNICODE_RANGES_HH #define HB_OT_OS2_UNICODE_RANGES_HH -#include "hb-private.hh" +#include "hb.hh" namespace OT { -struct Range { +struct OS2Range +{ + static int + cmp (const void *_key, const void *_item, void *_arg) + { + hb_codepoint_t cp = *((hb_codepoint_t *) _key); + const OS2Range *range = (OS2Range *) _item; + + if (cp < range->start) + return -1; + else if (cp <= range->end) + return 0; + else + return +1; + } + hb_codepoint_t start; hb_codepoint_t end; unsigned int bit; }; -/* Note: The contents of this array was generated using src/gen-unicode-ranges.py. */ -static Range os2UnicodeRangesSorted[] = +/* Note: The contents of this array was generated using gen-os2-unicode-ranges.py. */ +static const OS2Range _hb_os2_unicode_ranges[] = { { 0x0, 0x7F, 0}, // Basic Latin { 0x80, 0xFF, 1}, // Latin-1 Supplement @@ -211,31 +226,17 @@ static Range os2UnicodeRangesSorted[] = {0x100000, 0x10FFFD, 90}, // Private Use (plane 16) }; -static int -_compare_range (const void *_key, const void *_item, void *_arg) -{ - hb_codepoint_t cp = *((hb_codepoint_t *) _key); - const Range *range = (Range *) _item; - - if (cp < range->start) - return -1; - else if (cp <= range->end) - return 0; - else - return 1; -} - /** - * hb_get_unicode_range_bit: - * Returns the bit to be set in os/2 ulUnicodeRange for a given codepoint. + * _hb_ot_os2_get_unicode_range_bit: + * Returns the bit to be set in os/2 ulUnicodeOS2Range for a given codepoint. **/ static unsigned int -hb_get_unicode_range_bit (hb_codepoint_t cp) +_hb_ot_os2_get_unicode_range_bit (hb_codepoint_t cp) { - Range *range = (Range*) hb_bsearch_r (&cp, os2UnicodeRangesSorted, - sizeof (os2UnicodeRangesSorted) / sizeof(Range), - sizeof(Range), - _compare_range, nullptr); + OS2Range *range = (OS2Range*) hb_bsearch_r (&cp, _hb_os2_unicode_ranges, + ARRAY_LENGTH (_hb_os2_unicode_ranges), + sizeof (OS2Range), + OS2Range::cmp, nullptr); if (range != nullptr) return range->bit; return -1; diff --git a/src/hb-ot-post-macroman.hh b/src/hb-ot-post-macroman.hh index dbbb97e5a..b4df8aaee 100644 --- a/src/hb-ot-post-macroman.hh +++ b/src/hb-ot-post-macroman.hh @@ -27,7 +27,7 @@ #ifndef HB_OT_POST_MACROMAN_HH #if 0 /* Make checks happy. */ #define HB_OT_POST_MACROMAN_HH -#include "hb-private.hh" +#include "hb.hh" #endif diff --git a/src/hb-ot-post-table.hh b/src/hb-ot-post-table.hh index 4f08a51a2..bd049f9ab 100644 --- a/src/hb-ot-post-table.hh +++ b/src/hb-ot-post-table.hh @@ -27,8 +27,7 @@ #ifndef HB_OT_POST_TABLE_HH #define HB_OT_POST_TABLE_HH -#include "hb-open-type-private.hh" -#include "hb-subset-plan.hh" +#include "hb-open-type.hh" #define HB_STRING_ARRAY_NAME format1_names #define HB_STRING_ARRAY_LIST "hb-ot-post-macroman.hh" @@ -56,10 +55,11 @@ struct postV2Tail return_trace (glyphNameIndex.sanitize (c)); } - ArrayOf<HBUINT16>glyphNameIndex; /* This is not an offset, but is the + ArrayOf<HBUINT16> glyphNameIndex; /* This is not an offset, but is the * ordinal number of the glyph in 'post' * string tables. */ - HBUINT8 namesX[VAR]; /* Glyph names with length bytes [variable] + UnsizedArrayOf<HBUINT8> + namesX; /* Glyph names with length bytes [variable] * (a Pascal string). */ DEFINE_SIZE_ARRAY2 (2, glyphNameIndex, namesX); @@ -131,6 +131,7 @@ struct post { index_to_offset.fini (); free (gids_sorted_by_name.get ()); + hb_blob_destroy (blob); } inline bool get_glyph_name (hb_codepoint_t glyph, @@ -143,7 +144,7 @@ struct post return true; if (buf_len <= s.len) /* What to do with truncation? Returning false for now. */ return false; - strncpy (buf, s.bytes, s.len); + strncpy (buf, s.arrayZ, s.len); buf[s.len] = '\0'; return true; } @@ -241,7 +242,7 @@ struct post if (index >= index_to_offset.len) return hb_bytes_t (); - unsigned int offset = index_to_offset.arrayZ[index]; + unsigned int offset = index_to_offset[index]; const uint8_t *data = pool + offset; unsigned int name_length = *data; @@ -295,6 +296,8 @@ struct post DEFINE_SIZE_STATIC (32); }; +struct post_accelerator_t : post::accelerator_t {}; + } /* namespace OT */ diff --git a/src/hb-ot-shape-complex-arabic-fallback.hh b/src/hb-ot-shape-complex-arabic-fallback.hh index a55511aa0..2aa036728 100644 --- a/src/hb-ot-shape-complex-arabic-fallback.hh +++ b/src/hb-ot-shape-complex-arabic-fallback.hh @@ -27,9 +27,9 @@ #ifndef HB_OT_SHAPE_COMPLEX_ARABIC_FALLBACK_HH #define HB_OT_SHAPE_COMPLEX_ARABIC_FALLBACK_HH -#include "hb-private.hh" +#include "hb.hh" -#include "hb-ot-shape-private.hh" +#include "hb-ot-shape.hh" #include "hb-ot-layout-gsub-table.hh" @@ -173,7 +173,6 @@ arabic_fallback_synthesize_lookup_ligature (const hb_ot_shape_plan_t *plan HB_UN ligatures_supplier, component_count_supplier, component_supplier); - c.end_serialize (); /* TODO sanitize the results? */ @@ -202,7 +201,7 @@ struct arabic_fallback_plan_t hb_mask_t mask_array[ARABIC_FALLBACK_MAX_LOOKUPS]; OT::SubstLookup *lookup_array[ARABIC_FALLBACK_MAX_LOOKUPS]; - hb_ot_layout_lookup_accelerator_t accel_array[ARABIC_FALLBACK_MAX_LOOKUPS]; + OT::hb_ot_layout_lookup_accelerator_t accel_array[ARABIC_FALLBACK_MAX_LOOKUPS]; }; #if (defined(_WIN32) || defined(__CYGWIN__)) && !defined(HB_NO_WIN1256) diff --git a/src/hb-ot-shape-complex-arabic-win1256.hh b/src/hb-ot-shape-complex-arabic-win1256.hh index 54c6cdc24..b15e145f2 100644 --- a/src/hb-ot-shape-complex-arabic-win1256.hh +++ b/src/hb-ot-shape-complex-arabic-win1256.hh @@ -313,7 +313,7 @@ OT_TABLE_END * Include a second time to get the table data... */ #if 0 -#include "hb-private.hh" /* Make check-includes.sh happy. */ +#include "hb.hh" /* Make check-includes.sh happy. */ #endif #ifdef OT_MEASURE #include "hb-ot-shape-complex-arabic-win1256.hh" diff --git a/src/hb-ot-shape-complex-arabic.cc b/src/hb-ot-shape-complex-arabic.cc index f4b397b93..b56443910 100644 --- a/src/hb-ot-shape-complex-arabic.cc +++ b/src/hb-ot-shape-complex-arabic.cc @@ -24,9 +24,9 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-private.hh" -#include "hb-ot-shape-complex-arabic-private.hh" -#include "hb-ot-shape-private.hh" +#include "hb.hh" +#include "hb-ot-shape-complex-arabic.hh" +#include "hb-ot-shape.hh" /* buffer var allocations */ @@ -159,11 +159,6 @@ static const struct arabic_state_table_entry { static void -nuke_joiners (const hb_ot_shape_plan_t *plan, - hb_font_t *font, - hb_buffer_t *buffer); - -static void arabic_fallback_shape (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer); @@ -200,32 +195,38 @@ collect_features_arabic (hb_ot_shape_planner_t *plan) * work correctly. See https://github.com/harfbuzz/harfbuzz/issues/505 */ - map->add_gsub_pause (nuke_joiners); - map->add_global_bool_feature (HB_TAG('s','t','c','h')); + map->enable_feature (HB_TAG('s','t','c','h')); map->add_gsub_pause (record_stch); - map->add_global_bool_feature (HB_TAG('c','c','m','p')); - map->add_global_bool_feature (HB_TAG('l','o','c','l')); + map->enable_feature (HB_TAG('c','c','m','p')); + map->enable_feature (HB_TAG('l','o','c','l')); map->add_gsub_pause (nullptr); for (unsigned int i = 0; i < ARABIC_NUM_FEATURES; i++) { bool has_fallback = plan->props.script == HB_SCRIPT_ARABIC && !FEATURE_IS_SYRIAC (arabic_features[i]); - map->add_feature (arabic_features[i], 1, has_fallback ? F_HAS_FALLBACK : F_NONE); + map->add_feature (arabic_features[i], has_fallback ? F_HAS_FALLBACK : F_NONE); map->add_gsub_pause (nullptr); } - map->add_feature (HB_TAG('r','l','i','g'), 1, F_GLOBAL|F_HAS_FALLBACK); + /* Normally, Unicode says a ZWNJ means "don't ligate". In Arabic script + * however, it says a ZWJ should also mean "don't ligate". So we run + * the main ligating features as MANUAL_ZWJ. */ + + map->enable_feature (HB_TAG('r','l','i','g'), F_MANUAL_ZWJ | F_HAS_FALLBACK); + if (plan->props.script == HB_SCRIPT_ARABIC) map->add_gsub_pause (arabic_fallback_shape); /* No pause after rclt. See 98460779bae19e4d64d29461ff154b3527bf8420. */ - map->add_global_bool_feature (HB_TAG('r','c','l','t')); - map->add_global_bool_feature (HB_TAG('c','a','l','t')); + map->enable_feature (HB_TAG('r','c','l','t'), F_MANUAL_ZWJ); + map->enable_feature (HB_TAG('c','a','l','t'), F_MANUAL_ZWJ); map->add_gsub_pause (nullptr); + /* And undo here. */ + /* The spec includes 'cswh'. Earlier versions of Windows * used to enable this by default, but testing suggests * that Windows 8 and later do not enable it by default, @@ -234,8 +235,8 @@ collect_features_arabic (hb_ot_shape_planner_t *plan) * Note that IranNastaliq uses this feature extensively * to fixup broken glyph sequences. Oh well... * Test case: U+0643,U+0640,U+0631. */ - //map->add_global_bool_feature (HB_TAG('c','s','w','h')); - map->add_global_bool_feature (HB_TAG('m','s','e','t')); + //map->enable_feature (HB_TAG('c','s','w','h')); + map->enable_feature (HB_TAG('m','s','e','t')); } #include "hb-ot-shape-complex-arabic-fallback.hh" @@ -379,19 +380,6 @@ setup_masks_arabic (const hb_ot_shape_plan_t *plan, setup_masks_arabic_plan (arabic_plan, buffer, plan->props.script); } - -static void -nuke_joiners (const hb_ot_shape_plan_t *plan HB_UNUSED, - hb_font_t *font HB_UNUSED, - hb_buffer_t *buffer) -{ - unsigned int count = buffer->len; - hb_glyph_info_t *info = buffer->info; - for (unsigned int i = 0; i < count; i++) - if (_hb_glyph_info_is_zwj (&info[i])) - _hb_glyph_info_flip_joiners (&info[i]); -} - static void arabic_fallback_shape (const hb_ot_shape_plan_t *plan, hb_font_t *font, @@ -470,9 +458,9 @@ apply_stch (const hb_ot_shape_plan_t *plan, int sign = font->x_scale < 0 ? -1 : +1; unsigned int extra_glyphs_needed = 0; // Set during MEASURE, used during CUT - typedef enum { MEASURE, CUT } step_t; + enum { MEASURE, CUT } /* step_t */; - for (step_t step = MEASURE; step <= CUT; step = (step_t) (step + 1)) + for (unsigned int step = MEASURE; step <= CUT; step = step + 1) { unsigned int count = buffer->len; hb_glyph_info_t *info = buffer->info; @@ -611,7 +599,7 @@ postprocess_glyphs_arabic (const hb_ot_shape_plan_t *plan, HB_BUFFER_DEALLOCATE_VAR (buffer, arabic_shaping_action); } -/* https://unicode.org/reports/tr53/tr53-1.pdf */ +/* http://www.unicode.org/reports/tr53/ */ static hb_codepoint_t modifier_combining_marks[] = @@ -623,6 +611,7 @@ modifier_combining_marks[] = 0x06E3u, /* ARABIC SMALL LOW SEEN */ 0x06E7u, /* ARABIC SMALL HIGH YEH */ 0x06E8u, /* ARABIC SMALL HIGH NOON */ + 0x08D3u, /* ARABIC SMALL LOW WAW */ 0x08F3u, /* ARABIC SMALL HIGH WAW */ }; @@ -714,7 +703,7 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_arabic = nullptr, /* decompose */ nullptr, /* compose */ setup_masks_arabic, - nullptr, /* disable_otl */ + HB_TAG_NONE, /* gpos_tag */ reorder_marks_arabic, HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE, true, /* fallback_position */ diff --git a/src/hb-ot-shape-complex-arabic-private.hh b/src/hb-ot-shape-complex-arabic.hh index fcedc7d74..5bf6ff633 100644 --- a/src/hb-ot-shape-complex-arabic-private.hh +++ b/src/hb-ot-shape-complex-arabic.hh @@ -26,12 +26,12 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_OT_SHAPE_COMPLEX_ARABIC_PRIVATE_HH -#define HB_OT_SHAPE_COMPLEX_ARABIC_PRIVATE_HH +#ifndef HB_OT_SHAPE_COMPLEX_ARABIC_HH +#define HB_OT_SHAPE_COMPLEX_ARABIC_HH -#include "hb-private.hh" +#include "hb.hh" -#include "hb-ot-shape-complex-private.hh" +#include "hb-ot-shape-complex.hh" struct arabic_shape_plan_t; @@ -47,4 +47,4 @@ setup_masks_arabic_plan (const arabic_shape_plan_t *arabic_plan, hb_buffer_t *buffer, hb_script_t script); -#endif /* HB_OT_SHAPE_COMPLEX_ARABIC_PRIVATE_HH */ +#endif /* HB_OT_SHAPE_COMPLEX_ARABIC_HH */ diff --git a/src/hb-ot-shape-complex-default.cc b/src/hb-ot-shape-complex-default.cc index 68a62a10d..97923ecf6 100644 --- a/src/hb-ot-shape-complex-default.cc +++ b/src/hb-ot-shape-complex-default.cc @@ -24,7 +24,7 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-ot-shape-complex-private.hh" +#include "hb-ot-shape-complex.hh" const hb_ot_complex_shaper_t _hb_ot_complex_shaper_default = @@ -39,7 +39,7 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_default = nullptr, /* decompose */ nullptr, /* compose */ nullptr, /* setup_masks */ - nullptr, /* disable_otl */ + HB_TAG_NONE, /* gpos_tag */ nullptr, /* reorder_marks */ HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE, true, /* fallback_position */ diff --git a/src/hb-ot-shape-complex-hangul.cc b/src/hb-ot-shape-complex-hangul.cc index 7420c5d18..959540258 100644 --- a/src/hb-ot-shape-complex-hangul.cc +++ b/src/hb-ot-shape-complex-hangul.cc @@ -24,7 +24,7 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-ot-shape-complex-private.hh" +#include "hb-ot-shape-complex.hh" /* Hangul shaper */ @@ -56,7 +56,7 @@ collect_features_hangul (hb_ot_shape_planner_t *plan) hb_ot_map_builder_t *map = &plan->map; for (unsigned int i = FIRST_HANGUL_FEATURE; i < HANGUL_FEATURE_COUNT; i++) - map->add_feature (hangul_features[i], 1, F_NONE); + map->add_feature (hangul_features[i]); } static void @@ -65,7 +65,7 @@ override_features_hangul (hb_ot_shape_planner_t *plan) /* Uniscribe does not apply 'calt' for Hangul, and certain fonts * (Noto Sans CJK, Source Sans Han, etc) apply all of jamo lookups * in calt, which is not desirable. */ - plan->map.add_feature (HB_TAG('c','a','l','t'), 0, F_GLOBAL); + plan->map.disable_feature (HB_TAG('c','a','l','t')); } struct hangul_shape_plan_t @@ -345,13 +345,6 @@ preprocess_text_hangul (const hb_ot_shape_plan_t *plan, { unsigned int s_len = tindex ? 3 : 2; buffer->replace_glyphs (1, s_len, decomposed); - if (unlikely (!buffer->successful)) - return; - - /* We decomposed S: apply jamo features to the individual glyphs - * that are now in buffer->out_info. - */ - hb_glyph_info_t *info = buffer->out_info; /* If we decomposed an LV because of a non-combining T following, * we want to include this T in the syllable. @@ -361,6 +354,14 @@ preprocess_text_hangul (const hb_ot_shape_plan_t *plan, buffer->next_glyph (); s_len++; } + + if (unlikely (!buffer->successful)) + return; + + /* We decomposed S: apply jamo features to the individual glyphs + * that are now in buffer->out_info. + */ + hb_glyph_info_t *info = buffer->out_info; end = start + s_len; unsigned int i = start; @@ -368,6 +369,7 @@ preprocess_text_hangul (const hb_ot_shape_plan_t *plan, info[i++].hangul_shaping_feature() = VJMO; if (i < end) info[i++].hangul_shaping_feature() = TJMO; + if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES) buffer->merge_out_clusters (start, end); continue; @@ -424,7 +426,7 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_hangul = nullptr, /* decompose */ nullptr, /* compose */ setup_masks_hangul, - nullptr, /* disable_otl */ + HB_TAG_NONE, /* gpos_tag */ nullptr, /* reorder_marks */ HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE, false, /* fallback_position */ diff --git a/src/hb-ot-shape-complex-hebrew.cc b/src/hb-ot-shape-complex-hebrew.cc index 34cf28b8e..90c36c023 100644 --- a/src/hb-ot-shape-complex-hebrew.cc +++ b/src/hb-ot-shape-complex-hebrew.cc @@ -24,7 +24,7 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-ot-shape-complex-private.hh" +#include "hb-ot-shape-complex.hh" static bool @@ -70,7 +70,7 @@ compose_hebrew (const hb_ot_shape_normalize_context_t *c, bool found = (bool) c->unicode->compose (a, b, ab); - if (!found && !c->plan->has_mark) + if (!found && !c->plan->has_gpos_mark) { /* Special-case Hebrew presentation forms that are excluded from * standard normalization, but wanted for old fonts. */ @@ -154,18 +154,6 @@ compose_hebrew (const hb_ot_shape_normalize_context_t *c, return found; } -static bool -disable_otl_hebrew (const hb_ot_shape_plan_t *plan) -{ - /* For Hebrew shaper, use fallback if GPOS does not have 'hebr' - * script. This matches Uniscribe better, and makes fonts like - * Arial that have GSUB/GPOS/GDEF but no data for Hebrew work. - * See: - * https://github.com/harfbuzz/harfbuzz/issues/347#issuecomment-267838368 - */ - return plan->map.chosen_script[1] != HB_TAG ('h','e','b','r'); -} - const hb_ot_complex_shaper_t _hb_ot_complex_shaper_hebrew = { @@ -179,7 +167,7 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_hebrew = nullptr, /* decompose */ compose_hebrew, nullptr, /* setup_masks */ - disable_otl_hebrew, + HB_TAG ('h','e','b','r'), /* gpos_tag. https://github.com/harfbuzz/harfbuzz/issues/347#issuecomment-267838368 */ nullptr, /* reorder_marks */ HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE, true, /* fallback_position */ diff --git a/src/hb-ot-shape-complex-indic-machine.hh b/src/hb-ot-shape-complex-indic-machine.hh index 73f9d5871..e2ecfb89c 100644 --- a/src/hb-ot-shape-complex-indic-machine.hh +++ b/src/hb-ot-shape-complex-indic-machine.hh @@ -29,892 +29,714 @@ #ifndef HB_OT_SHAPE_COMPLEX_INDIC_MACHINE_HH #define HB_OT_SHAPE_COMPLEX_INDIC_MACHINE_HH -#include "hb-private.hh" +#include "hb.hh" #line 36 "hb-ot-shape-complex-indic-machine.hh" static const unsigned char _indic_syllable_machine_trans_keys[] = { - 8u, 8u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, + 8u, 8u, 4u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, - 16u, 16u, 4u, 8u, 4u, 13u, 4u, 8u, 4u, 13u, 4u, 8u, 4u, 13u, 4u, 8u, - 4u, 13u, 4u, 8u, 4u, 13u, 8u, 8u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, - 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, - 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, - 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 4u, 13u, 4u, 8u, 4u, 13u, - 4u, 8u, 4u, 13u, 4u, 8u, 4u, 13u, 4u, 8u, 4u, 13u, 8u, 8u, 5u, 8u, - 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, - 5u, 8u, 5u, 7u, 7u, 7u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, - 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, - 4u, 13u, 4u, 8u, 4u, 13u, 4u, 8u, 4u, 13u, 4u, 8u, 4u, 13u, 4u, 8u, - 8u, 8u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, - 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 4u, 8u, 6u, 6u, 16u, 16u, - 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, - 16u, 16u, 4u, 8u, 4u, 13u, 4u, 8u, 4u, 13u, 4u, 8u, 4u, 13u, 4u, 8u, - 4u, 13u, 4u, 8u, 4u, 13u, 4u, 13u, 5u, 8u, 5u, 8u, 5u, 7u, 5u, 8u, - 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, - 8u, 8u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, - 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 8u, 8u, 1u, 19u, 3u, 17u, - 3u, 17u, 4u, 17u, 1u, 16u, 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, 3u, 17u, - 3u, 17u, 4u, 17u, 1u, 16u, 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, 3u, 17u, - 3u, 17u, 4u, 17u, 5u, 10u, 5u, 10u, 5u, 10u, 10u, 10u, 10u, 10u, 10u, 10u, - 5u, 10u, 3u, 10u, 3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, 5u, 10u, - 3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, - 3u, 17u, 3u, 17u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 17u, 3u, 17u, - 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 17u, 3u, 17u, 1u, 16u, 1u, 16u, - 1u, 16u, 1u, 16u, 3u, 17u, 3u, 17u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, - 3u, 17u, 3u, 17u, 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, 3u, 17u, 3u, 17u, - 4u, 17u, 1u, 16u, 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, 3u, 17u, 3u, 17u, - 4u, 17u, 1u, 16u, 3u, 17u, 3u, 17u, 4u, 17u, 5u, 10u, 5u, 10u, 5u, 10u, - 10u, 10u, 10u, 10u, 10u, 10u, 5u, 10u, 3u, 10u, 3u, 10u, 4u, 10u, 5u, 10u, - 3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, - 5u, 10u, 3u, 10u, 4u, 10u, 3u, 17u, 3u, 17u, 1u, 16u, 1u, 16u, 1u, 16u, - 1u, 16u, 3u, 17u, 3u, 17u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 17u, - 3u, 17u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 17u, 3u, 17u, 1u, 16u, - 1u, 16u, 1u, 16u, 1u, 16u, 4u, 8u, 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, - 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, - 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, 3u, 17u, 3u, 17u, 4u, 17u, 5u, 10u, - 5u, 10u, 5u, 10u, 10u, 10u, 10u, 10u, 10u, 10u, 5u, 10u, 3u, 10u, 3u, 10u, + 16u, 16u, 4u, 13u, 4u, 8u, 4u, 13u, 4u, 8u, 4u, 13u, 4u, 8u, 4u, 13u, + 4u, 8u, 4u, 13u, 8u, 8u, 4u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, + 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 4u, 8u, + 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, + 4u, 8u, 6u, 6u, 16u, 16u, 4u, 13u, 4u, 8u, 4u, 13u, 4u, 8u, 4u, 13u, + 4u, 8u, 4u, 13u, 4u, 8u, 4u, 13u, 8u, 8u, 4u, 8u, 5u, 7u, 7u, 7u, + 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, + 7u, 7u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, + 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 13u, 4u, 8u, 4u, 13u, + 4u, 8u, 4u, 13u, 4u, 8u, 4u, 13u, 4u, 8u, 8u, 8u, 4u, 8u, 5u, 7u, + 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, + 5u, 7u, 7u, 7u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, + 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 13u, 4u, 8u, + 4u, 13u, 4u, 8u, 4u, 13u, 4u, 8u, 4u, 13u, 4u, 8u, 4u, 13u, 4u, 13u, + 5u, 8u, 8u, 8u, 1u, 19u, 3u, 13u, 3u, 10u, 4u, 10u, 1u, 16u, 3u, 13u, + 3u, 10u, 4u, 10u, 1u, 16u, 3u, 13u, 3u, 10u, 4u, 10u, 1u, 16u, 3u, 13u, + 3u, 10u, 4u, 10u, 1u, 16u, 3u, 13u, 3u, 10u, 4u, 10u, 5u, 10u, 5u, 10u, + 5u, 10u, 10u, 10u, 10u, 10u, 10u, 10u, 5u, 10u, 3u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, 5u, 10u, - 3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, 3u, 17u, 3u, 17u, 1u, 16u, - 1u, 16u, 1u, 16u, 1u, 16u, 3u, 17u, 3u, 17u, 1u, 16u, 1u, 16u, 1u, 16u, - 1u, 16u, 3u, 17u, 3u, 17u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 17u, - 3u, 17u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 4u, 13u, 3u, 17u, 4u, 8u, - 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, - 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, - 3u, 17u, 3u, 17u, 4u, 17u, 5u, 10u, 5u, 10u, 5u, 10u, 10u, 10u, 10u, 10u, - 10u, 10u, 5u, 10u, 3u, 10u, 3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, + 3u, 10u, 4u, 10u, 3u, 10u, 3u, 13u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 10u, + 3u, 13u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 10u, 3u, 13u, 1u, 16u, 1u, 16u, + 1u, 16u, 3u, 10u, 3u, 13u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 10u, 3u, 13u, + 3u, 13u, 3u, 10u, 4u, 10u, 1u, 16u, 3u, 13u, 3u, 10u, 4u, 10u, 1u, 16u, + 3u, 13u, 3u, 10u, 4u, 10u, 1u, 16u, 3u, 13u, 3u, 10u, 4u, 10u, 1u, 16u, + 3u, 13u, 3u, 10u, 4u, 10u, 5u, 10u, 5u, 10u, 5u, 10u, 10u, 10u, 10u, 10u, + 10u, 10u, 5u, 10u, 3u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u, + 4u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, 3u, 10u, + 3u, 13u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 10u, 3u, 13u, 1u, 16u, 1u, 16u, + 1u, 16u, 3u, 10u, 3u, 13u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 10u, 3u, 13u, + 1u, 16u, 1u, 16u, 1u, 16u, 4u, 8u, 3u, 10u, 3u, 10u, 4u, 10u, 1u, 16u, + 3u, 13u, 3u, 10u, 4u, 10u, 1u, 16u, 3u, 13u, 3u, 10u, 4u, 10u, 1u, 16u, + 3u, 13u, 3u, 10u, 4u, 10u, 1u, 16u, 3u, 13u, 3u, 10u, 4u, 10u, 5u, 10u, + 5u, 10u, 5u, 10u, 10u, 10u, 10u, 10u, 10u, 10u, 5u, 10u, 3u, 10u, 5u, 10u, + 3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, + 5u, 10u, 3u, 10u, 4u, 10u, 3u, 10u, 3u, 13u, 1u, 16u, 1u, 16u, 1u, 16u, + 3u, 10u, 3u, 13u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 10u, 3u, 13u, 1u, 16u, + 1u, 16u, 1u, 16u, 3u, 10u, 3u, 13u, 1u, 16u, 1u, 16u, 1u, 16u, 4u, 13u, + 3u, 10u, 4u, 8u, 3u, 13u, 3u, 10u, 4u, 10u, 1u, 16u, 3u, 13u, 3u, 10u, + 4u, 10u, 1u, 16u, 3u, 13u, 3u, 10u, 4u, 10u, 1u, 16u, 3u, 13u, 3u, 10u, + 4u, 10u, 1u, 16u, 3u, 13u, 3u, 10u, 4u, 10u, 5u, 10u, 5u, 10u, 5u, 10u, + 10u, 10u, 10u, 10u, 10u, 10u, 5u, 10u, 3u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u, - 4u, 10u, 3u, 17u, 3u, 17u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 17u, - 3u, 17u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 17u, 3u, 17u, 1u, 16u, - 1u, 16u, 1u, 16u, 1u, 16u, 3u, 17u, 3u, 17u, 1u, 16u, 1u, 16u, 1u, 16u, - 1u, 16u, 3u, 17u, 1u, 17u, 3u, 17u, 1u, 17u, 4u, 13u, 5u, 10u, 10u, 10u, - 10u, 10u, 10u, 10u, 5u, 10u, 1u, 16u, 3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u, - 4u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, 5u, 10u, + 4u, 10u, 3u, 10u, 3u, 13u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 10u, 3u, 13u, + 1u, 16u, 1u, 16u, 1u, 16u, 3u, 10u, 3u, 13u, 1u, 16u, 1u, 16u, 1u, 16u, + 3u, 10u, 3u, 13u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 10u, 1u, 16u, 3u, 13u, + 1u, 16u, 4u, 13u, 5u, 10u, 10u, 10u, 10u, 10u, 10u, 10u, 5u, 10u, 1u, 16u, 3u, 10u, 5u, 10u, 5u, 10u, 10u, 10u, 10u, 10u, 10u, 10u, 5u, 10u, 1u, 16u, 0 }; static const char _indic_syllable_machine_key_spans[] = { - 1, 4, 3, 1, 4, 3, 1, 4, + 1, 5, 3, 1, 4, 3, 1, 4, 3, 1, 4, 3, 1, 5, 1, 1, 5, 1, 1, 5, 1, 1, 5, 1, - 1, 5, 10, 5, 10, 5, 10, 5, - 10, 5, 10, 1, 4, 3, 1, 4, - 3, 1, 4, 3, 1, 4, 3, 1, - 5, 1, 1, 5, 1, 1, 5, 1, - 1, 5, 1, 1, 5, 10, 5, 10, - 5, 10, 5, 10, 5, 10, 1, 4, - 3, 1, 4, 3, 1, 4, 3, 1, - 4, 3, 1, 5, 1, 1, 5, 1, + 1, 10, 5, 10, 5, 10, 5, 10, + 5, 10, 1, 5, 3, 1, 4, 3, + 1, 4, 3, 1, 4, 3, 1, 5, + 1, 1, 5, 1, 1, 5, 1, 1, + 5, 1, 1, 10, 5, 10, 5, 10, + 5, 10, 5, 10, 1, 5, 3, 1, + 4, 3, 1, 4, 3, 1, 4, 3, 1, 5, 1, 1, 5, 1, 1, 5, - 10, 5, 10, 5, 10, 5, 10, 5, + 1, 1, 5, 1, 1, 10, 5, 10, + 5, 10, 5, 10, 5, 1, 5, 3, 1, 4, 3, 1, 4, 3, 1, 4, - 3, 1, 4, 3, 1, 5, 1, 1, - 5, 1, 1, 5, 1, 1, 5, 1, - 1, 5, 10, 5, 10, 5, 10, 5, - 10, 5, 10, 10, 4, 4, 3, 4, - 3, 1, 4, 3, 1, 4, 3, 1, - 1, 5, 1, 1, 5, 1, 1, 5, - 1, 1, 5, 1, 1, 1, 19, 15, - 15, 14, 16, 15, 15, 14, 16, 15, - 15, 14, 16, 15, 15, 14, 16, 15, - 15, 14, 6, 6, 6, 1, 1, 1, - 6, 8, 8, 7, 6, 8, 7, 6, - 8, 7, 6, 8, 7, 6, 8, 7, - 15, 15, 16, 16, 16, 16, 15, 15, - 16, 16, 16, 16, 15, 15, 16, 16, - 16, 16, 15, 15, 16, 16, 16, 16, - 15, 15, 15, 15, 14, 16, 15, 15, - 14, 16, 15, 15, 14, 16, 15, 15, - 14, 16, 15, 15, 14, 6, 6, 6, - 1, 1, 1, 6, 8, 8, 7, 6, - 8, 7, 6, 8, 7, 6, 8, 7, - 6, 8, 7, 15, 15, 16, 16, 16, - 16, 15, 15, 16, 16, 16, 16, 15, - 15, 16, 16, 16, 16, 15, 15, 16, - 16, 16, 16, 5, 15, 15, 14, 16, - 15, 15, 14, 16, 15, 15, 14, 16, - 15, 15, 14, 16, 15, 15, 14, 6, - 6, 6, 1, 1, 1, 6, 8, 8, + 3, 1, 5, 1, 1, 5, 1, 1, + 5, 1, 1, 5, 1, 1, 10, 5, + 10, 5, 10, 5, 10, 5, 10, 10, + 4, 1, 19, 11, 8, 7, 16, 11, + 8, 7, 16, 11, 8, 7, 16, 11, + 8, 7, 16, 11, 8, 7, 6, 6, + 6, 1, 1, 1, 6, 8, 6, 8, 7, 6, 8, 7, 6, 8, 7, 6, - 8, 7, 6, 8, 7, 15, 15, 16, - 16, 16, 16, 15, 15, 16, 16, 16, - 16, 15, 15, 16, 16, 16, 16, 15, - 15, 16, 16, 16, 16, 10, 15, 5, - 15, 15, 14, 16, 15, 15, 14, 16, - 15, 15, 14, 16, 15, 15, 14, 16, - 15, 15, 14, 6, 6, 6, 1, 1, - 1, 6, 8, 8, 7, 6, 8, 7, + 8, 7, 8, 11, 16, 16, 16, 8, + 11, 16, 16, 16, 8, 11, 16, 16, + 16, 8, 11, 16, 16, 16, 8, 11, + 11, 8, 7, 16, 11, 8, 7, 16, + 11, 8, 7, 16, 11, 8, 7, 16, + 11, 8, 7, 6, 6, 6, 1, 1, + 1, 6, 8, 6, 8, 7, 6, 8, + 7, 6, 8, 7, 6, 8, 7, 8, + 11, 16, 16, 16, 8, 11, 16, 16, + 16, 8, 11, 16, 16, 16, 8, 11, + 16, 16, 16, 5, 8, 8, 7, 16, + 11, 8, 7, 16, 11, 8, 7, 16, + 11, 8, 7, 16, 11, 8, 7, 6, + 6, 6, 1, 1, 1, 6, 8, 6, + 8, 7, 6, 8, 7, 6, 8, 7, + 6, 8, 7, 8, 11, 16, 16, 16, + 8, 11, 16, 16, 16, 8, 11, 16, + 16, 16, 8, 11, 16, 16, 16, 10, + 8, 5, 11, 8, 7, 16, 11, 8, + 7, 16, 11, 8, 7, 16, 11, 8, + 7, 16, 11, 8, 7, 6, 6, 6, + 1, 1, 1, 6, 8, 6, 8, 7, 6, 8, 7, 6, 8, 7, 6, 8, - 7, 15, 15, 16, 16, 16, 16, 15, - 15, 16, 16, 16, 16, 15, 15, 16, - 16, 16, 16, 15, 15, 16, 16, 16, - 16, 15, 17, 15, 17, 10, 6, 1, - 1, 1, 6, 16, 8, 7, 6, 8, - 7, 6, 8, 7, 6, 8, 7, 6, + 7, 8, 11, 16, 16, 16, 8, 11, + 16, 16, 16, 8, 11, 16, 16, 16, + 8, 11, 16, 16, 16, 8, 16, 11, + 16, 10, 6, 1, 1, 1, 6, 16, 8, 6, 6, 1, 1, 1, 6, 16 }; static const short _indic_syllable_machine_index_offsets[] = { - 0, 2, 7, 11, 13, 18, 22, 24, - 29, 33, 35, 40, 44, 46, 52, 54, - 56, 62, 64, 66, 72, 74, 76, 82, - 84, 86, 92, 103, 109, 120, 126, 137, - 143, 154, 160, 171, 173, 178, 182, 184, - 189, 193, 195, 200, 204, 206, 211, 215, - 217, 223, 225, 227, 233, 235, 237, 243, - 245, 247, 253, 255, 257, 263, 274, 280, - 291, 297, 308, 314, 325, 331, 342, 344, - 349, 353, 355, 360, 364, 366, 371, 375, - 377, 382, 386, 388, 394, 396, 398, 404, - 406, 408, 414, 416, 418, 424, 426, 428, - 434, 445, 451, 462, 468, 479, 485, 496, - 502, 504, 509, 513, 515, 520, 524, 526, - 531, 535, 537, 542, 546, 548, 554, 556, - 558, 564, 566, 568, 574, 576, 578, 584, - 586, 588, 594, 605, 611, 622, 628, 639, - 645, 656, 662, 673, 684, 689, 694, 698, - 703, 707, 709, 714, 718, 720, 725, 729, - 731, 733, 739, 741, 743, 749, 751, 753, - 759, 761, 763, 769, 771, 773, 775, 795, - 811, 827, 842, 859, 875, 891, 906, 923, - 939, 955, 970, 987, 1003, 1019, 1034, 1051, - 1067, 1083, 1098, 1105, 1112, 1119, 1121, 1123, - 1125, 1132, 1141, 1150, 1158, 1165, 1174, 1182, - 1189, 1198, 1206, 1213, 1222, 1230, 1237, 1246, - 1254, 1270, 1286, 1303, 1320, 1337, 1354, 1370, - 1386, 1403, 1420, 1437, 1454, 1470, 1486, 1503, - 1520, 1537, 1554, 1570, 1586, 1603, 1620, 1637, - 1654, 1670, 1686, 1702, 1718, 1733, 1750, 1766, - 1782, 1797, 1814, 1830, 1846, 1861, 1878, 1894, - 1910, 1925, 1942, 1958, 1974, 1989, 1996, 2003, - 2010, 2012, 2014, 2016, 2023, 2032, 2041, 2049, - 2056, 2065, 2073, 2080, 2089, 2097, 2104, 2113, - 2121, 2128, 2137, 2145, 2161, 2177, 2194, 2211, - 2228, 2245, 2261, 2277, 2294, 2311, 2328, 2345, - 2361, 2377, 2394, 2411, 2428, 2445, 2461, 2477, - 2494, 2511, 2528, 2545, 2551, 2567, 2583, 2598, - 2615, 2631, 2647, 2662, 2679, 2695, 2711, 2726, - 2743, 2759, 2775, 2790, 2807, 2823, 2839, 2854, - 2861, 2868, 2875, 2877, 2879, 2881, 2888, 2897, - 2906, 2914, 2921, 2930, 2938, 2945, 2954, 2962, - 2969, 2978, 2986, 2993, 3002, 3010, 3026, 3042, - 3059, 3076, 3093, 3110, 3126, 3142, 3159, 3176, - 3193, 3210, 3226, 3242, 3259, 3276, 3293, 3310, - 3326, 3342, 3359, 3376, 3393, 3410, 3421, 3437, - 3443, 3459, 3475, 3490, 3507, 3523, 3539, 3554, - 3571, 3587, 3603, 3618, 3635, 3651, 3667, 3682, - 3699, 3715, 3731, 3746, 3753, 3760, 3767, 3769, - 3771, 3773, 3780, 3789, 3798, 3806, 3813, 3822, - 3830, 3837, 3846, 3854, 3861, 3870, 3878, 3885, - 3894, 3902, 3918, 3934, 3951, 3968, 3985, 4002, - 4018, 4034, 4051, 4068, 4085, 4102, 4118, 4134, - 4151, 4168, 4185, 4202, 4218, 4234, 4251, 4268, - 4285, 4302, 4318, 4336, 4352, 4370, 4381, 4388, - 4390, 4392, 4394, 4401, 4418, 4427, 4435, 4442, - 4451, 4459, 4466, 4475, 4483, 4490, 4499, 4507, - 4514, 4523, 4530, 4537, 4539, 4541, 4543, 4550 + 0, 2, 8, 12, 14, 19, 23, 25, + 30, 34, 36, 41, 45, 47, 53, 55, + 57, 63, 65, 67, 73, 75, 77, 83, + 85, 87, 98, 104, 115, 121, 132, 138, + 149, 155, 166, 168, 174, 178, 180, 185, + 189, 191, 196, 200, 202, 207, 211, 213, + 219, 221, 223, 229, 231, 233, 239, 241, + 243, 249, 251, 253, 264, 270, 281, 287, + 298, 304, 315, 321, 332, 334, 340, 344, + 346, 351, 355, 357, 362, 366, 368, 373, + 377, 379, 385, 387, 389, 395, 397, 399, + 405, 407, 409, 415, 417, 419, 430, 436, + 447, 453, 464, 470, 481, 487, 489, 495, + 499, 501, 506, 510, 512, 517, 521, 523, + 528, 532, 534, 540, 542, 544, 550, 552, + 554, 560, 562, 564, 570, 572, 574, 585, + 591, 602, 608, 619, 625, 636, 642, 653, + 664, 669, 671, 691, 703, 712, 720, 737, + 749, 758, 766, 783, 795, 804, 812, 829, + 841, 850, 858, 875, 887, 896, 904, 911, + 918, 925, 927, 929, 931, 938, 947, 954, + 963, 971, 978, 987, 995, 1002, 1011, 1019, + 1026, 1035, 1043, 1052, 1064, 1081, 1098, 1115, + 1124, 1136, 1153, 1170, 1187, 1196, 1208, 1225, + 1242, 1259, 1268, 1280, 1297, 1314, 1331, 1340, + 1352, 1364, 1373, 1381, 1398, 1410, 1419, 1427, + 1444, 1456, 1465, 1473, 1490, 1502, 1511, 1519, + 1536, 1548, 1557, 1565, 1572, 1579, 1586, 1588, + 1590, 1592, 1599, 1608, 1615, 1624, 1632, 1639, + 1648, 1656, 1663, 1672, 1680, 1687, 1696, 1704, + 1713, 1725, 1742, 1759, 1776, 1785, 1797, 1814, + 1831, 1848, 1857, 1869, 1886, 1903, 1920, 1929, + 1941, 1958, 1975, 1992, 1998, 2007, 2016, 2024, + 2041, 2053, 2062, 2070, 2087, 2099, 2108, 2116, + 2133, 2145, 2154, 2162, 2179, 2191, 2200, 2208, + 2215, 2222, 2229, 2231, 2233, 2235, 2242, 2251, + 2258, 2267, 2275, 2282, 2291, 2299, 2306, 2315, + 2323, 2330, 2339, 2347, 2356, 2368, 2385, 2402, + 2419, 2428, 2440, 2457, 2474, 2491, 2500, 2512, + 2529, 2546, 2563, 2572, 2584, 2601, 2618, 2635, + 2646, 2655, 2661, 2673, 2682, 2690, 2707, 2719, + 2728, 2736, 2753, 2765, 2774, 2782, 2799, 2811, + 2820, 2828, 2845, 2857, 2866, 2874, 2881, 2888, + 2895, 2897, 2899, 2901, 2908, 2917, 2924, 2933, + 2941, 2948, 2957, 2965, 2972, 2981, 2989, 2996, + 3005, 3013, 3022, 3034, 3051, 3068, 3085, 3094, + 3106, 3123, 3140, 3157, 3166, 3178, 3195, 3212, + 3229, 3238, 3250, 3267, 3284, 3301, 3310, 3327, + 3339, 3356, 3367, 3374, 3376, 3378, 3380, 3387, + 3404, 3413, 3420, 3427, 3429, 3431, 3433, 3440 }; static const short _indic_syllable_machine_indicies[] = { - 1, 0, 2, 2, 3, 1, 0, 4, - 4, 3, 0, 3, 0, 5, 5, 6, - 1, 0, 7, 7, 6, 0, 6, 0, - 8, 8, 9, 1, 0, 10, 10, 9, - 0, 9, 0, 11, 11, 12, 1, 0, - 13, 13, 12, 0, 12, 0, 14, 0, - 0, 0, 1, 0, 15, 0, 16, 0, - 17, 11, 11, 12, 1, 0, 18, 0, - 19, 0, 20, 8, 8, 9, 1, 0, - 21, 0, 22, 0, 23, 5, 5, 6, - 1, 0, 24, 0, 25, 0, 26, 2, - 2, 3, 1, 0, 26, 2, 2, 3, - 1, 0, 0, 0, 0, 27, 0, 28, - 2, 2, 3, 1, 0, 28, 2, 2, - 3, 1, 0, 0, 0, 0, 29, 0, - 30, 2, 2, 3, 1, 0, 30, 2, - 2, 3, 1, 0, 0, 0, 0, 31, - 0, 32, 2, 2, 3, 1, 0, 32, - 2, 2, 3, 1, 0, 0, 0, 0, - 33, 0, 34, 2, 2, 3, 1, 0, - 34, 2, 2, 3, 1, 0, 0, 0, - 0, 35, 0, 37, 36, 38, 38, 39, - 37, 36, 40, 40, 39, 36, 39, 36, - 41, 41, 42, 37, 36, 43, 43, 42, - 36, 42, 36, 44, 44, 45, 37, 36, - 46, 46, 45, 36, 45, 36, 47, 47, - 48, 37, 36, 49, 49, 48, 36, 48, - 36, 50, 36, 36, 36, 37, 36, 51, - 36, 52, 36, 53, 47, 47, 48, 37, - 36, 54, 36, 55, 36, 56, 44, 44, - 45, 37, 36, 57, 36, 58, 36, 59, - 41, 41, 42, 37, 36, 60, 36, 61, - 36, 62, 38, 38, 39, 37, 36, 62, - 38, 38, 39, 37, 36, 36, 36, 36, - 63, 36, 64, 38, 38, 39, 37, 36, - 64, 38, 38, 39, 37, 36, 36, 36, - 36, 65, 36, 66, 38, 38, 39, 37, - 36, 66, 38, 38, 39, 37, 36, 36, - 36, 36, 67, 36, 68, 38, 38, 39, - 37, 36, 68, 38, 38, 39, 37, 36, - 36, 36, 36, 69, 36, 70, 38, 38, - 39, 37, 36, 70, 38, 38, 39, 37, - 36, 36, 36, 36, 71, 36, 73, 72, - 74, 74, 75, 73, 72, 77, 77, 75, - 76, 75, 76, 78, 78, 79, 73, 72, - 80, 80, 79, 72, 79, 72, 81, 81, - 82, 73, 72, 83, 83, 82, 72, 82, - 72, 84, 84, 85, 73, 72, 86, 86, - 85, 72, 85, 72, 87, 72, 72, 72, - 73, 72, 88, 72, 89, 72, 90, 84, - 84, 85, 73, 72, 91, 72, 92, 72, - 93, 81, 81, 82, 73, 72, 94, 72, - 95, 72, 96, 78, 78, 79, 73, 72, - 97, 72, 98, 72, 99, 74, 74, 75, - 73, 72, 99, 74, 74, 75, 73, 72, - 72, 72, 72, 100, 72, 101, 74, 74, - 75, 73, 72, 101, 74, 74, 75, 73, - 72, 72, 72, 72, 102, 72, 103, 74, - 74, 75, 73, 72, 103, 74, 74, 75, - 73, 72, 72, 72, 72, 104, 72, 105, - 74, 74, 75, 73, 72, 105, 74, 74, - 75, 73, 72, 72, 72, 72, 106, 72, - 107, 74, 74, 75, 73, 72, 109, 108, - 110, 110, 111, 109, 108, 112, 112, 111, - 108, 111, 108, 113, 113, 114, 109, 108, - 115, 115, 114, 108, 114, 108, 116, 116, - 117, 109, 108, 118, 118, 117, 108, 117, - 108, 119, 119, 120, 109, 108, 121, 121, - 120, 108, 120, 108, 122, 108, 108, 108, - 109, 108, 123, 108, 124, 108, 125, 119, - 119, 120, 109, 108, 126, 108, 127, 108, - 128, 116, 116, 117, 109, 108, 129, 108, - 130, 108, 131, 113, 113, 114, 109, 108, - 132, 108, 133, 108, 134, 110, 110, 111, - 109, 108, 134, 110, 110, 111, 109, 108, - 108, 108, 108, 135, 108, 136, 110, 110, - 111, 109, 108, 136, 110, 110, 111, 109, - 108, 108, 108, 108, 137, 108, 138, 110, - 110, 111, 109, 108, 138, 110, 110, 111, - 109, 108, 108, 108, 108, 139, 108, 140, - 110, 110, 111, 109, 108, 140, 110, 110, - 111, 109, 108, 108, 108, 108, 141, 108, - 142, 110, 110, 111, 109, 108, 142, 110, - 110, 111, 109, 108, 108, 108, 108, 143, - 108, 107, 74, 74, 75, 73, 72, 72, - 72, 72, 144, 72, 77, 77, 75, 1, - 0, 145, 145, 146, 1, 0, 4, 4, - 146, 0, 147, 147, 148, 149, 0, 150, - 150, 148, 0, 148, 0, 151, 151, 152, - 149, 0, 153, 153, 152, 0, 152, 0, - 154, 154, 155, 149, 0, 156, 156, 155, - 0, 155, 0, 149, 0, 157, 0, 0, - 0, 149, 0, 158, 0, 159, 0, 160, - 154, 154, 155, 149, 0, 161, 0, 162, - 0, 163, 151, 151, 152, 149, 0, 164, - 0, 165, 0, 166, 147, 147, 148, 149, - 0, 167, 0, 168, 0, 170, 169, 172, - 173, 174, 175, 176, 177, 75, 73, 171, - 178, 179, 179, 144, 171, 180, 181, 182, - 183, 184, 171, 186, 187, 188, 189, 3, - 1, 185, 190, 185, 185, 35, 185, 185, - 185, 191, 185, 192, 187, 193, 193, 3, - 1, 185, 190, 185, 185, 185, 185, 185, - 185, 191, 185, 187, 193, 193, 3, 1, - 185, 190, 185, 185, 185, 185, 185, 185, - 191, 185, 194, 185, 185, 185, 16, 195, - 185, 1, 185, 190, 185, 185, 185, 185, - 185, 194, 185, 196, 197, 198, 199, 3, - 1, 185, 190, 185, 185, 33, 185, 185, - 185, 191, 185, 200, 197, 201, 201, 3, - 1, 185, 190, 185, 185, 185, 185, 185, - 185, 191, 185, 197, 201, 201, 3, 1, - 185, 190, 185, 185, 185, 185, 185, 185, - 191, 185, 202, 185, 185, 185, 16, 203, - 185, 1, 185, 190, 185, 185, 185, 185, - 185, 202, 185, 204, 205, 206, 207, 3, - 1, 185, 190, 185, 185, 31, 185, 185, - 185, 191, 185, 208, 205, 209, 209, 3, - 1, 185, 190, 185, 185, 185, 185, 185, - 185, 191, 185, 205, 209, 209, 3, 1, - 185, 190, 185, 185, 185, 185, 185, 185, - 191, 185, 210, 185, 185, 185, 16, 211, - 185, 1, 185, 190, 185, 185, 185, 185, - 185, 210, 185, 212, 213, 214, 215, 3, - 1, 185, 190, 185, 185, 29, 185, 185, - 185, 191, 185, 216, 213, 217, 217, 3, - 1, 185, 190, 185, 185, 185, 185, 185, - 185, 191, 185, 213, 217, 217, 3, 1, - 185, 190, 185, 185, 185, 185, 185, 185, - 191, 185, 218, 185, 185, 185, 16, 219, - 185, 1, 185, 190, 185, 185, 185, 185, - 185, 218, 185, 220, 221, 222, 223, 3, - 1, 185, 190, 185, 185, 27, 185, 185, - 185, 191, 185, 224, 221, 225, 225, 3, - 1, 185, 190, 185, 185, 185, 185, 185, - 185, 191, 185, 221, 225, 225, 3, 1, - 185, 190, 185, 185, 185, 185, 185, 185, - 191, 185, 16, 226, 185, 1, 185, 190, - 185, 227, 227, 185, 1, 185, 190, 185, - 228, 185, 185, 229, 185, 190, 185, 190, - 185, 230, 185, 231, 185, 228, 185, 185, - 185, 185, 190, 185, 16, 185, 232, 232, - 3, 1, 185, 190, 185, 233, 25, 234, - 235, 6, 1, 185, 190, 185, 25, 234, - 235, 6, 1, 185, 190, 185, 234, 234, - 6, 1, 185, 190, 185, 236, 22, 237, - 238, 9, 1, 185, 190, 185, 22, 237, - 238, 9, 1, 185, 190, 185, 237, 237, - 9, 1, 185, 190, 185, 239, 19, 240, - 241, 12, 1, 185, 190, 185, 19, 240, - 241, 12, 1, 185, 190, 185, 240, 240, - 12, 1, 185, 190, 185, 242, 16, 227, - 243, 185, 1, 185, 190, 185, 16, 227, - 243, 185, 1, 185, 190, 185, 227, 244, - 185, 1, 185, 190, 185, 16, 185, 227, - 227, 185, 1, 185, 190, 185, 221, 225, - 225, 3, 1, 185, 190, 185, 220, 221, - 225, 225, 3, 1, 185, 190, 185, 185, - 185, 185, 185, 185, 191, 185, 220, 221, - 222, 225, 3, 1, 185, 190, 185, 185, - 27, 185, 185, 185, 191, 185, 218, 185, - 245, 185, 232, 232, 3, 1, 185, 190, - 185, 185, 185, 185, 185, 218, 185, 218, - 185, 185, 185, 227, 227, 185, 1, 185, - 190, 185, 185, 185, 185, 185, 218, 185, - 218, 185, 185, 185, 227, 246, 185, 1, - 185, 190, 185, 185, 185, 185, 185, 218, - 185, 218, 185, 245, 185, 227, 227, 185, - 1, 185, 190, 185, 185, 185, 185, 185, - 218, 185, 212, 213, 217, 217, 3, 1, - 185, 190, 185, 185, 185, 185, 185, 185, - 191, 185, 212, 213, 214, 217, 3, 1, - 185, 190, 185, 185, 29, 185, 185, 185, - 191, 185, 210, 185, 247, 185, 232, 232, - 3, 1, 185, 190, 185, 185, 185, 185, - 185, 210, 185, 210, 185, 185, 185, 227, - 227, 185, 1, 185, 190, 185, 185, 185, - 185, 185, 210, 185, 210, 185, 185, 185, - 227, 248, 185, 1, 185, 190, 185, 185, - 185, 185, 185, 210, 185, 210, 185, 247, - 185, 227, 227, 185, 1, 185, 190, 185, - 185, 185, 185, 185, 210, 185, 204, 205, - 209, 209, 3, 1, 185, 190, 185, 185, - 185, 185, 185, 185, 191, 185, 204, 205, - 206, 209, 3, 1, 185, 190, 185, 185, - 31, 185, 185, 185, 191, 185, 202, 185, - 249, 185, 232, 232, 3, 1, 185, 190, - 185, 185, 185, 185, 185, 202, 185, 202, - 185, 185, 185, 227, 227, 185, 1, 185, - 190, 185, 185, 185, 185, 185, 202, 185, - 202, 185, 185, 185, 227, 250, 185, 1, - 185, 190, 185, 185, 185, 185, 185, 202, - 185, 202, 185, 249, 185, 227, 227, 185, - 1, 185, 190, 185, 185, 185, 185, 185, - 202, 185, 196, 197, 201, 201, 3, 1, - 185, 190, 185, 185, 185, 185, 185, 185, - 191, 185, 196, 197, 198, 201, 3, 1, - 185, 190, 185, 185, 33, 185, 185, 185, - 191, 185, 194, 185, 251, 185, 232, 232, - 3, 1, 185, 190, 185, 185, 185, 185, - 185, 194, 185, 194, 185, 185, 185, 227, - 227, 185, 1, 185, 190, 185, 185, 185, - 185, 185, 194, 185, 194, 185, 185, 185, - 227, 252, 185, 1, 185, 190, 185, 185, - 185, 185, 185, 194, 185, 194, 185, 251, - 185, 227, 227, 185, 1, 185, 190, 185, - 185, 185, 185, 185, 194, 185, 186, 187, - 193, 193, 3, 1, 185, 190, 185, 185, - 185, 185, 185, 185, 191, 185, 186, 187, - 188, 193, 3, 1, 185, 190, 185, 185, - 35, 185, 185, 185, 191, 185, 254, 255, - 256, 257, 39, 37, 253, 258, 253, 253, - 71, 253, 253, 253, 259, 253, 260, 255, - 261, 257, 39, 37, 253, 258, 253, 253, - 253, 253, 253, 253, 259, 253, 255, 261, - 257, 39, 37, 253, 258, 253, 253, 253, - 253, 253, 253, 259, 253, 262, 253, 253, - 253, 52, 263, 253, 37, 253, 258, 253, - 253, 253, 253, 253, 262, 253, 264, 265, - 266, 267, 39, 37, 253, 258, 253, 253, - 69, 253, 253, 253, 259, 253, 268, 265, - 269, 269, 39, 37, 253, 258, 253, 253, - 253, 253, 253, 253, 259, 253, 265, 269, - 269, 39, 37, 253, 258, 253, 253, 253, - 253, 253, 253, 259, 253, 270, 253, 253, - 253, 52, 271, 253, 37, 253, 258, 253, - 253, 253, 253, 253, 270, 253, 272, 273, - 274, 275, 39, 37, 253, 258, 253, 253, - 67, 253, 253, 253, 259, 253, 276, 273, - 277, 277, 39, 37, 253, 258, 253, 253, - 253, 253, 253, 253, 259, 253, 273, 277, - 277, 39, 37, 253, 258, 253, 253, 253, - 253, 253, 253, 259, 253, 278, 253, 253, - 253, 52, 279, 253, 37, 253, 258, 253, - 253, 253, 253, 253, 278, 253, 280, 281, - 282, 283, 39, 37, 253, 258, 253, 253, - 65, 253, 253, 253, 259, 253, 284, 281, - 285, 285, 39, 37, 253, 258, 253, 253, - 253, 253, 253, 253, 259, 253, 281, 285, - 285, 39, 37, 253, 258, 253, 253, 253, - 253, 253, 253, 259, 253, 286, 253, 253, - 253, 52, 287, 253, 37, 253, 258, 253, - 253, 253, 253, 253, 286, 253, 288, 289, - 290, 291, 39, 37, 253, 258, 253, 253, - 63, 253, 253, 253, 259, 253, 292, 289, - 293, 293, 39, 37, 253, 258, 253, 253, - 253, 253, 253, 253, 259, 253, 289, 293, - 293, 39, 37, 253, 258, 253, 253, 253, - 253, 253, 253, 259, 253, 52, 294, 253, - 37, 253, 258, 253, 295, 295, 253, 37, - 253, 258, 253, 296, 253, 253, 297, 253, - 258, 253, 258, 253, 298, 253, 299, 253, - 296, 253, 253, 253, 253, 258, 253, 52, - 253, 300, 300, 39, 37, 253, 258, 253, - 301, 61, 302, 303, 42, 37, 253, 258, - 253, 61, 302, 303, 42, 37, 253, 258, - 253, 302, 302, 42, 37, 253, 258, 253, - 304, 58, 305, 306, 45, 37, 253, 258, - 253, 58, 305, 306, 45, 37, 253, 258, - 253, 305, 305, 45, 37, 253, 258, 253, - 307, 55, 308, 309, 48, 37, 253, 258, - 253, 55, 308, 309, 48, 37, 253, 258, - 253, 308, 308, 48, 37, 253, 258, 253, - 310, 52, 295, 311, 253, 37, 253, 258, - 253, 52, 295, 311, 253, 37, 253, 258, - 253, 295, 312, 253, 37, 253, 258, 253, - 52, 253, 295, 295, 253, 37, 253, 258, - 253, 289, 293, 293, 39, 37, 253, 258, - 253, 288, 289, 293, 293, 39, 37, 253, - 258, 253, 253, 253, 253, 253, 253, 259, - 253, 288, 289, 290, 293, 39, 37, 253, - 258, 253, 253, 63, 253, 253, 253, 259, - 253, 286, 253, 313, 253, 300, 300, 39, - 37, 253, 258, 253, 253, 253, 253, 253, - 286, 253, 286, 253, 253, 253, 295, 295, - 253, 37, 253, 258, 253, 253, 253, 253, - 253, 286, 253, 286, 253, 253, 253, 295, - 314, 253, 37, 253, 258, 253, 253, 253, - 253, 253, 286, 253, 286, 253, 313, 253, - 295, 295, 253, 37, 253, 258, 253, 253, - 253, 253, 253, 286, 253, 280, 281, 285, - 285, 39, 37, 253, 258, 253, 253, 253, - 253, 253, 253, 259, 253, 280, 281, 282, - 285, 39, 37, 253, 258, 253, 253, 65, - 253, 253, 253, 259, 253, 278, 253, 315, - 253, 300, 300, 39, 37, 253, 258, 253, - 253, 253, 253, 253, 278, 253, 278, 253, - 253, 253, 295, 295, 253, 37, 253, 258, - 253, 253, 253, 253, 253, 278, 253, 278, - 253, 253, 253, 295, 316, 253, 37, 253, - 258, 253, 253, 253, 253, 253, 278, 253, - 278, 253, 315, 253, 295, 295, 253, 37, - 253, 258, 253, 253, 253, 253, 253, 278, - 253, 272, 273, 277, 277, 39, 37, 253, - 258, 253, 253, 253, 253, 253, 253, 259, - 253, 272, 273, 274, 277, 39, 37, 253, - 258, 253, 253, 67, 253, 253, 253, 259, - 253, 270, 253, 317, 253, 300, 300, 39, - 37, 253, 258, 253, 253, 253, 253, 253, - 270, 253, 270, 253, 253, 253, 295, 295, - 253, 37, 253, 258, 253, 253, 253, 253, - 253, 270, 253, 270, 253, 253, 253, 295, - 318, 253, 37, 253, 258, 253, 253, 253, - 253, 253, 270, 253, 270, 253, 317, 253, - 295, 295, 253, 37, 253, 258, 253, 253, - 253, 253, 253, 270, 253, 264, 265, 269, - 269, 39, 37, 253, 258, 253, 253, 253, - 253, 253, 253, 259, 253, 264, 265, 266, - 269, 39, 37, 253, 258, 253, 253, 69, - 253, 253, 253, 259, 253, 262, 253, 319, - 253, 300, 300, 39, 37, 253, 258, 253, - 253, 253, 253, 253, 262, 253, 262, 253, - 253, 253, 295, 295, 253, 37, 253, 258, - 253, 253, 253, 253, 253, 262, 253, 262, - 253, 253, 253, 295, 320, 253, 37, 253, - 258, 253, 253, 253, 253, 253, 262, 253, - 262, 253, 319, 253, 295, 295, 253, 37, - 253, 258, 253, 253, 253, 253, 253, 262, - 253, 70, 38, 38, 39, 37, 253, 254, - 255, 261, 257, 39, 37, 253, 258, 253, - 253, 253, 253, 253, 253, 259, 253, 322, - 175, 323, 323, 75, 73, 321, 178, 321, - 321, 321, 321, 321, 321, 182, 321, 175, - 323, 323, 75, 73, 321, 178, 321, 321, - 321, 321, 321, 321, 182, 321, 324, 321, - 321, 321, 89, 325, 321, 73, 321, 178, - 321, 321, 321, 321, 321, 324, 321, 326, - 327, 328, 329, 75, 73, 321, 178, 321, - 321, 106, 321, 321, 321, 182, 321, 330, - 327, 331, 331, 75, 73, 321, 178, 321, - 321, 321, 321, 321, 321, 182, 321, 327, - 331, 331, 75, 73, 321, 178, 321, 321, - 321, 321, 321, 321, 182, 321, 332, 321, - 321, 321, 89, 333, 321, 73, 321, 178, - 321, 321, 321, 321, 321, 332, 321, 334, - 335, 336, 337, 75, 73, 321, 178, 321, - 321, 104, 321, 321, 321, 182, 321, 338, - 335, 339, 339, 75, 73, 321, 178, 321, - 321, 321, 321, 321, 321, 182, 321, 335, - 339, 339, 75, 73, 321, 178, 321, 321, - 321, 321, 321, 321, 182, 321, 340, 321, - 321, 321, 89, 341, 321, 73, 321, 178, - 321, 321, 321, 321, 321, 340, 321, 342, - 343, 344, 345, 75, 73, 321, 178, 321, - 321, 102, 321, 321, 321, 182, 321, 346, - 343, 347, 347, 75, 73, 321, 178, 321, - 321, 321, 321, 321, 321, 182, 321, 343, - 347, 347, 75, 73, 321, 178, 321, 321, - 321, 321, 321, 321, 182, 321, 348, 321, - 321, 321, 89, 349, 321, 73, 321, 178, - 321, 321, 321, 321, 321, 348, 321, 350, - 351, 352, 353, 75, 73, 321, 178, 321, - 321, 100, 321, 321, 321, 182, 321, 354, - 351, 355, 355, 75, 73, 321, 178, 321, - 321, 321, 321, 321, 321, 182, 321, 351, - 355, 355, 75, 73, 321, 178, 321, 321, - 321, 321, 321, 321, 182, 321, 89, 356, - 321, 73, 321, 178, 321, 357, 357, 321, - 73, 321, 178, 321, 358, 321, 321, 359, - 321, 178, 321, 178, 321, 360, 321, 361, - 321, 358, 321, 321, 321, 321, 178, 321, - 89, 321, 362, 362, 75, 73, 321, 178, - 321, 363, 98, 364, 365, 79, 73, 321, - 178, 321, 98, 364, 365, 79, 73, 321, - 178, 321, 364, 364, 79, 73, 321, 178, - 321, 366, 95, 367, 368, 82, 73, 321, - 178, 321, 95, 367, 368, 82, 73, 321, - 178, 321, 367, 367, 82, 73, 321, 178, - 321, 369, 92, 370, 371, 85, 73, 321, - 178, 321, 92, 370, 371, 85, 73, 321, - 178, 321, 370, 370, 85, 73, 321, 178, - 321, 372, 89, 357, 373, 321, 73, 321, - 178, 321, 89, 357, 373, 321, 73, 321, - 178, 321, 357, 374, 321, 73, 321, 178, - 321, 89, 321, 357, 357, 321, 73, 321, - 178, 321, 351, 355, 355, 75, 73, 321, - 178, 321, 350, 351, 355, 355, 75, 73, - 321, 178, 321, 321, 321, 321, 321, 321, - 182, 321, 350, 351, 352, 355, 75, 73, - 321, 178, 321, 321, 100, 321, 321, 321, - 182, 321, 348, 321, 375, 321, 362, 362, - 75, 73, 321, 178, 321, 321, 321, 321, - 321, 348, 321, 348, 321, 321, 321, 357, - 357, 321, 73, 321, 178, 321, 321, 321, - 321, 321, 348, 321, 348, 321, 321, 321, - 357, 376, 321, 73, 321, 178, 321, 321, - 321, 321, 321, 348, 321, 348, 321, 375, - 321, 357, 357, 321, 73, 321, 178, 321, - 321, 321, 321, 321, 348, 321, 342, 343, - 347, 347, 75, 73, 321, 178, 321, 321, - 321, 321, 321, 321, 182, 321, 342, 343, - 344, 347, 75, 73, 321, 178, 321, 321, - 102, 321, 321, 321, 182, 321, 340, 321, - 377, 321, 362, 362, 75, 73, 321, 178, - 321, 321, 321, 321, 321, 340, 321, 340, - 321, 321, 321, 357, 357, 321, 73, 321, - 178, 321, 321, 321, 321, 321, 340, 321, - 340, 321, 321, 321, 357, 378, 321, 73, - 321, 178, 321, 321, 321, 321, 321, 340, - 321, 340, 321, 377, 321, 357, 357, 321, - 73, 321, 178, 321, 321, 321, 321, 321, - 340, 321, 334, 335, 339, 339, 75, 73, - 321, 178, 321, 321, 321, 321, 321, 321, - 182, 321, 334, 335, 336, 339, 75, 73, - 321, 178, 321, 321, 104, 321, 321, 321, - 182, 321, 332, 321, 379, 321, 362, 362, - 75, 73, 321, 178, 321, 321, 321, 321, - 321, 332, 321, 332, 321, 321, 321, 357, - 357, 321, 73, 321, 178, 321, 321, 321, - 321, 321, 332, 321, 332, 321, 321, 321, - 357, 380, 321, 73, 321, 178, 321, 321, - 321, 321, 321, 332, 321, 332, 321, 379, - 321, 357, 357, 321, 73, 321, 178, 321, - 321, 321, 321, 321, 332, 321, 326, 327, - 331, 331, 75, 73, 321, 178, 321, 321, - 321, 321, 321, 321, 182, 321, 326, 327, - 328, 331, 75, 73, 321, 178, 321, 321, - 106, 321, 321, 321, 182, 321, 324, 321, - 381, 321, 362, 362, 75, 73, 321, 178, - 321, 321, 321, 321, 321, 324, 321, 324, - 321, 321, 321, 357, 357, 321, 73, 321, - 178, 321, 321, 321, 321, 321, 324, 321, - 324, 321, 321, 321, 357, 382, 321, 73, - 321, 178, 321, 321, 321, 321, 321, 324, - 321, 324, 321, 381, 321, 357, 357, 321, - 73, 321, 178, 321, 321, 321, 321, 321, - 324, 321, 107, 74, 74, 75, 73, 383, - 383, 383, 383, 144, 383, 174, 175, 323, - 323, 75, 73, 321, 178, 321, 321, 321, - 321, 321, 321, 182, 321, 107, 74, 74, - 75, 73, 383, 385, 386, 387, 388, 111, - 109, 384, 389, 384, 384, 143, 384, 384, - 384, 390, 384, 391, 386, 388, 388, 111, - 109, 384, 389, 384, 384, 384, 384, 384, - 384, 390, 384, 386, 388, 388, 111, 109, - 384, 389, 384, 384, 384, 384, 384, 384, - 390, 384, 392, 384, 384, 384, 124, 393, - 384, 109, 384, 389, 384, 384, 384, 384, - 384, 392, 384, 394, 395, 396, 397, 111, - 109, 384, 389, 384, 384, 141, 384, 384, - 384, 390, 384, 398, 395, 399, 399, 111, - 109, 384, 389, 384, 384, 384, 384, 384, - 384, 390, 384, 395, 399, 399, 111, 109, - 384, 389, 384, 384, 384, 384, 384, 384, - 390, 384, 400, 384, 384, 384, 124, 401, - 384, 109, 384, 389, 384, 384, 384, 384, - 384, 400, 384, 402, 403, 404, 405, 111, - 109, 384, 389, 384, 384, 139, 384, 384, - 384, 390, 384, 406, 403, 407, 407, 111, - 109, 384, 389, 384, 384, 384, 384, 384, - 384, 390, 384, 403, 407, 407, 111, 109, - 384, 389, 384, 384, 384, 384, 384, 384, - 390, 384, 408, 384, 384, 384, 124, 409, - 384, 109, 384, 389, 384, 384, 384, 384, - 384, 408, 384, 410, 411, 412, 413, 111, - 109, 384, 389, 384, 384, 137, 384, 384, - 384, 390, 384, 414, 411, 415, 415, 111, - 109, 384, 389, 384, 384, 384, 384, 384, - 384, 390, 384, 411, 415, 415, 111, 109, - 384, 389, 384, 384, 384, 384, 384, 384, - 390, 384, 416, 384, 384, 384, 124, 417, - 384, 109, 384, 389, 384, 384, 384, 384, - 384, 416, 384, 418, 419, 420, 421, 111, - 109, 384, 389, 384, 384, 135, 384, 384, - 384, 390, 384, 422, 419, 423, 423, 111, - 109, 384, 389, 384, 384, 384, 384, 384, - 384, 390, 384, 419, 423, 423, 111, 109, - 384, 389, 384, 384, 384, 384, 384, 384, - 390, 384, 124, 424, 384, 109, 384, 389, - 384, 425, 425, 384, 109, 384, 389, 384, - 426, 384, 384, 427, 384, 389, 384, 389, - 384, 428, 384, 429, 384, 426, 384, 384, - 384, 384, 389, 384, 124, 384, 430, 430, - 111, 109, 384, 389, 384, 431, 133, 432, - 433, 114, 109, 384, 389, 384, 133, 432, - 433, 114, 109, 384, 389, 384, 432, 432, - 114, 109, 384, 389, 384, 434, 130, 435, - 436, 117, 109, 384, 389, 384, 130, 435, - 436, 117, 109, 384, 389, 384, 435, 435, - 117, 109, 384, 389, 384, 437, 127, 438, - 439, 120, 109, 384, 389, 384, 127, 438, - 439, 120, 109, 384, 389, 384, 438, 438, - 120, 109, 384, 389, 384, 440, 124, 425, - 441, 384, 109, 384, 389, 384, 124, 425, - 441, 384, 109, 384, 389, 384, 425, 442, - 384, 109, 384, 389, 384, 124, 384, 425, - 425, 384, 109, 384, 389, 384, 419, 423, - 423, 111, 109, 384, 389, 384, 418, 419, - 423, 423, 111, 109, 384, 389, 384, 384, - 384, 384, 384, 384, 390, 384, 418, 419, - 420, 423, 111, 109, 384, 389, 384, 384, - 135, 384, 384, 384, 390, 384, 416, 384, - 443, 384, 430, 430, 111, 109, 384, 389, - 384, 384, 384, 384, 384, 416, 384, 416, - 384, 384, 384, 425, 425, 384, 109, 384, - 389, 384, 384, 384, 384, 384, 416, 384, - 416, 384, 384, 384, 425, 444, 384, 109, - 384, 389, 384, 384, 384, 384, 384, 416, - 384, 416, 384, 443, 384, 425, 425, 384, - 109, 384, 389, 384, 384, 384, 384, 384, - 416, 384, 410, 411, 415, 415, 111, 109, - 384, 389, 384, 384, 384, 384, 384, 384, - 390, 384, 410, 411, 412, 415, 111, 109, - 384, 389, 384, 384, 137, 384, 384, 384, - 390, 384, 408, 384, 445, 384, 430, 430, - 111, 109, 384, 389, 384, 384, 384, 384, - 384, 408, 384, 408, 384, 384, 384, 425, - 425, 384, 109, 384, 389, 384, 384, 384, - 384, 384, 408, 384, 408, 384, 384, 384, - 425, 446, 384, 109, 384, 389, 384, 384, - 384, 384, 384, 408, 384, 408, 384, 445, - 384, 425, 425, 384, 109, 384, 389, 384, - 384, 384, 384, 384, 408, 384, 402, 403, - 407, 407, 111, 109, 384, 389, 384, 384, - 384, 384, 384, 384, 390, 384, 402, 403, - 404, 407, 111, 109, 384, 389, 384, 384, - 139, 384, 384, 384, 390, 384, 400, 384, - 447, 384, 430, 430, 111, 109, 384, 389, - 384, 384, 384, 384, 384, 400, 384, 400, - 384, 384, 384, 425, 425, 384, 109, 384, - 389, 384, 384, 384, 384, 384, 400, 384, - 400, 384, 384, 384, 425, 448, 384, 109, - 384, 389, 384, 384, 384, 384, 384, 400, - 384, 400, 384, 447, 384, 425, 425, 384, - 109, 384, 389, 384, 384, 384, 384, 384, - 400, 384, 394, 395, 399, 399, 111, 109, - 384, 389, 384, 384, 384, 384, 384, 384, - 390, 384, 394, 395, 396, 399, 111, 109, - 384, 389, 384, 384, 141, 384, 384, 384, - 390, 384, 392, 384, 449, 384, 430, 430, - 111, 109, 384, 389, 384, 384, 384, 384, - 384, 392, 384, 392, 384, 384, 384, 425, - 425, 384, 109, 384, 389, 384, 384, 384, - 384, 384, 392, 384, 392, 384, 384, 384, - 425, 450, 384, 109, 384, 389, 384, 384, - 384, 384, 384, 392, 384, 392, 384, 449, - 384, 425, 425, 384, 109, 384, 389, 384, - 384, 384, 384, 384, 392, 384, 385, 386, - 388, 388, 111, 109, 384, 389, 384, 384, - 384, 384, 384, 384, 390, 384, 172, 173, - 174, 175, 451, 323, 75, 73, 321, 178, - 179, 179, 144, 321, 321, 172, 182, 321, - 186, 452, 188, 189, 3, 1, 185, 190, - 185, 185, 35, 185, 185, 185, 191, 185, - 194, 173, 174, 175, 453, 454, 75, 149, - 185, 455, 185, 179, 144, 185, 185, 194, - 182, 185, 107, 456, 456, 75, 149, 185, - 190, 185, 185, 144, 185, 457, 185, 185, - 458, 185, 455, 185, 455, 185, 459, 185, - 231, 185, 457, 185, 185, 185, 185, 455, - 185, 194, 185, 251, 107, 460, 460, 146, - 149, 185, 190, 185, 185, 185, 185, 185, - 194, 185, 461, 168, 462, 463, 148, 149, - 185, 455, 185, 168, 462, 463, 148, 149, - 185, 455, 185, 462, 462, 148, 149, 185, - 455, 185, 464, 165, 465, 466, 152, 149, - 185, 455, 185, 165, 465, 466, 152, 149, - 185, 455, 185, 465, 465, 152, 149, 185, - 455, 185, 467, 162, 468, 469, 155, 149, - 185, 455, 185, 162, 468, 469, 155, 149, - 185, 455, 185, 468, 468, 155, 149, 185, - 455, 185, 470, 159, 471, 472, 185, 149, - 185, 455, 185, 159, 471, 472, 185, 149, - 185, 455, 185, 471, 471, 185, 149, 185, - 455, 185, 474, 473, 475, 475, 473, 170, - 473, 476, 473, 475, 475, 473, 170, 473, - 476, 473, 477, 473, 473, 478, 473, 476, - 473, 476, 473, 479, 473, 480, 473, 477, - 473, 473, 473, 473, 476, 473, 172, 383, - 383, 383, 383, 383, 383, 383, 383, 383, - 179, 383, 383, 383, 383, 172, 383, 0 + 1, 0, 2, 3, 3, 4, 1, 0, + 5, 5, 4, 0, 4, 0, 6, 6, + 7, 1, 0, 8, 8, 7, 0, 7, + 0, 9, 9, 10, 1, 0, 11, 11, + 10, 0, 10, 0, 12, 12, 13, 1, + 0, 14, 14, 13, 0, 13, 0, 15, + 0, 0, 0, 1, 0, 16, 0, 17, + 0, 18, 12, 12, 13, 1, 0, 19, + 0, 20, 0, 21, 9, 9, 10, 1, + 0, 22, 0, 23, 0, 24, 6, 6, + 7, 1, 0, 25, 0, 26, 0, 2, + 3, 3, 4, 1, 0, 0, 0, 0, + 27, 0, 28, 3, 3, 4, 1, 0, + 28, 3, 3, 4, 1, 0, 0, 0, + 0, 29, 0, 30, 3, 3, 4, 1, + 0, 30, 3, 3, 4, 1, 0, 0, + 0, 0, 31, 0, 32, 3, 3, 4, + 1, 0, 32, 3, 3, 4, 1, 0, + 0, 0, 0, 33, 0, 34, 3, 3, + 4, 1, 0, 34, 3, 3, 4, 1, + 0, 0, 0, 0, 35, 0, 37, 36, + 38, 39, 39, 40, 37, 36, 41, 41, + 40, 36, 40, 36, 42, 42, 43, 37, + 36, 44, 44, 43, 36, 43, 36, 45, + 45, 46, 37, 36, 47, 47, 46, 36, + 46, 36, 48, 48, 49, 37, 36, 50, + 50, 49, 36, 49, 36, 51, 36, 36, + 36, 37, 36, 52, 36, 53, 36, 54, + 48, 48, 49, 37, 36, 55, 36, 56, + 36, 57, 45, 45, 46, 37, 36, 58, + 36, 59, 36, 60, 42, 42, 43, 37, + 36, 61, 36, 62, 36, 38, 39, 39, + 40, 37, 36, 36, 36, 36, 63, 36, + 64, 39, 39, 40, 37, 36, 64, 39, + 39, 40, 37, 36, 36, 36, 36, 65, + 36, 66, 39, 39, 40, 37, 36, 66, + 39, 39, 40, 37, 36, 36, 36, 36, + 67, 36, 68, 39, 39, 40, 37, 36, + 68, 39, 39, 40, 37, 36, 36, 36, + 36, 69, 36, 70, 39, 39, 40, 37, + 36, 70, 39, 39, 40, 37, 36, 36, + 36, 36, 71, 36, 73, 72, 74, 75, + 75, 76, 73, 72, 78, 78, 76, 77, + 76, 77, 79, 79, 80, 73, 72, 81, + 81, 80, 72, 80, 72, 82, 82, 83, + 73, 72, 84, 84, 83, 72, 83, 72, + 85, 85, 86, 73, 72, 87, 87, 86, + 72, 86, 72, 88, 72, 72, 72, 73, + 72, 89, 72, 90, 72, 91, 85, 85, + 86, 73, 72, 92, 72, 93, 72, 94, + 82, 82, 83, 73, 72, 95, 72, 96, + 72, 97, 79, 79, 80, 73, 72, 98, + 72, 99, 72, 74, 75, 75, 76, 73, + 72, 72, 72, 72, 100, 72, 101, 75, + 75, 76, 73, 72, 101, 75, 75, 76, + 73, 72, 72, 72, 72, 102, 72, 103, + 75, 75, 76, 73, 72, 103, 75, 75, + 76, 73, 72, 72, 72, 72, 104, 72, + 105, 75, 75, 76, 73, 72, 105, 75, + 75, 76, 73, 72, 72, 72, 72, 106, + 72, 107, 75, 75, 76, 73, 72, 109, + 108, 110, 111, 111, 112, 109, 108, 113, + 113, 112, 108, 112, 108, 114, 114, 115, + 109, 108, 116, 116, 115, 108, 115, 108, + 117, 117, 118, 109, 108, 119, 119, 118, + 108, 118, 108, 120, 120, 121, 109, 108, + 122, 122, 121, 108, 121, 108, 123, 108, + 108, 108, 109, 108, 124, 108, 125, 108, + 126, 120, 120, 121, 109, 108, 127, 108, + 128, 108, 129, 117, 117, 118, 109, 108, + 130, 108, 131, 108, 132, 114, 114, 115, + 109, 108, 133, 108, 134, 108, 110, 111, + 111, 112, 109, 108, 108, 108, 108, 135, + 108, 136, 111, 111, 112, 109, 108, 136, + 111, 111, 112, 109, 108, 108, 108, 108, + 137, 108, 138, 111, 111, 112, 109, 108, + 138, 111, 111, 112, 109, 108, 108, 108, + 108, 139, 108, 140, 111, 111, 112, 109, + 108, 140, 111, 111, 112, 109, 108, 108, + 108, 108, 141, 108, 142, 111, 111, 112, + 109, 108, 142, 111, 111, 112, 109, 108, + 108, 108, 108, 143, 108, 107, 75, 75, + 76, 73, 72, 72, 72, 72, 144, 72, + 78, 78, 76, 1, 0, 146, 145, 148, + 149, 150, 151, 152, 153, 76, 73, 147, + 154, 155, 155, 144, 147, 156, 157, 147, + 158, 159, 147, 161, 162, 163, 164, 4, + 1, 160, 165, 160, 160, 35, 160, 166, + 162, 167, 167, 4, 1, 160, 165, 160, + 162, 167, 167, 4, 1, 160, 165, 160, + 168, 160, 160, 160, 17, 169, 160, 1, + 160, 165, 160, 160, 160, 160, 160, 168, + 160, 170, 171, 172, 173, 4, 1, 160, + 165, 160, 160, 33, 160, 174, 171, 175, + 175, 4, 1, 160, 165, 160, 171, 175, + 175, 4, 1, 160, 165, 160, 176, 160, + 160, 160, 17, 177, 160, 1, 160, 165, + 160, 160, 160, 160, 160, 176, 160, 178, + 179, 180, 181, 4, 1, 160, 165, 160, + 160, 31, 160, 182, 179, 183, 183, 4, + 1, 160, 165, 160, 179, 183, 183, 4, + 1, 160, 165, 160, 184, 160, 160, 160, + 17, 185, 160, 1, 160, 165, 160, 160, + 160, 160, 160, 184, 160, 186, 187, 188, + 189, 4, 1, 160, 165, 160, 160, 29, + 160, 190, 187, 191, 191, 4, 1, 160, + 165, 160, 187, 191, 191, 4, 1, 160, + 165, 160, 192, 160, 160, 160, 17, 193, + 160, 1, 160, 165, 160, 160, 160, 160, + 160, 192, 160, 194, 195, 196, 197, 4, + 1, 160, 165, 160, 160, 27, 160, 198, + 195, 199, 199, 4, 1, 160, 165, 160, + 195, 199, 199, 4, 1, 160, 165, 160, + 17, 200, 160, 1, 160, 165, 160, 201, + 201, 160, 1, 160, 165, 160, 202, 160, + 160, 203, 160, 165, 160, 165, 160, 204, + 160, 205, 160, 202, 160, 160, 160, 160, + 165, 160, 17, 160, 201, 201, 160, 1, + 160, 165, 160, 201, 200, 160, 1, 160, + 165, 160, 206, 26, 207, 208, 7, 1, + 160, 165, 160, 26, 207, 208, 7, 1, + 160, 165, 160, 207, 207, 7, 1, 160, + 165, 160, 209, 23, 210, 211, 10, 1, + 160, 165, 160, 23, 210, 211, 10, 1, + 160, 165, 160, 210, 210, 10, 1, 160, + 165, 160, 212, 20, 213, 214, 13, 1, + 160, 165, 160, 20, 213, 214, 13, 1, + 160, 165, 160, 213, 213, 13, 1, 160, + 165, 160, 215, 17, 201, 216, 160, 1, + 160, 165, 160, 17, 201, 216, 160, 1, + 160, 165, 160, 194, 195, 199, 199, 4, + 1, 160, 165, 160, 194, 195, 196, 199, + 4, 1, 160, 165, 160, 160, 27, 160, + 192, 160, 217, 160, 201, 201, 160, 1, + 160, 165, 160, 160, 160, 160, 160, 192, + 160, 192, 160, 160, 160, 201, 201, 160, + 1, 160, 165, 160, 160, 160, 160, 160, + 192, 160, 192, 160, 160, 160, 201, 193, + 160, 1, 160, 165, 160, 160, 160, 160, + 160, 192, 160, 186, 187, 191, 191, 4, + 1, 160, 165, 160, 186, 187, 188, 191, + 4, 1, 160, 165, 160, 160, 29, 160, + 184, 160, 218, 160, 201, 201, 160, 1, + 160, 165, 160, 160, 160, 160, 160, 184, + 160, 184, 160, 160, 160, 201, 201, 160, + 1, 160, 165, 160, 160, 160, 160, 160, + 184, 160, 184, 160, 160, 160, 201, 185, + 160, 1, 160, 165, 160, 160, 160, 160, + 160, 184, 160, 178, 179, 183, 183, 4, + 1, 160, 165, 160, 178, 179, 180, 183, + 4, 1, 160, 165, 160, 160, 31, 160, + 176, 160, 219, 160, 201, 201, 160, 1, + 160, 165, 160, 160, 160, 160, 160, 176, + 160, 176, 160, 160, 160, 201, 201, 160, + 1, 160, 165, 160, 160, 160, 160, 160, + 176, 160, 176, 160, 160, 160, 201, 177, + 160, 1, 160, 165, 160, 160, 160, 160, + 160, 176, 160, 170, 171, 175, 175, 4, + 1, 160, 165, 160, 170, 171, 172, 175, + 4, 1, 160, 165, 160, 160, 33, 160, + 168, 160, 220, 160, 201, 201, 160, 1, + 160, 165, 160, 160, 160, 160, 160, 168, + 160, 168, 160, 160, 160, 201, 201, 160, + 1, 160, 165, 160, 160, 160, 160, 160, + 168, 160, 168, 160, 160, 160, 201, 169, + 160, 1, 160, 165, 160, 160, 160, 160, + 160, 168, 160, 161, 162, 167, 167, 4, + 1, 160, 165, 160, 161, 162, 163, 167, + 4, 1, 160, 165, 160, 160, 35, 160, + 222, 223, 224, 225, 40, 37, 221, 226, + 221, 221, 71, 221, 227, 223, 228, 225, + 40, 37, 221, 226, 221, 223, 228, 225, + 40, 37, 221, 226, 221, 229, 221, 221, + 221, 53, 230, 221, 37, 221, 226, 221, + 221, 221, 221, 221, 229, 221, 231, 232, + 233, 234, 40, 37, 221, 226, 221, 221, + 69, 221, 235, 232, 236, 236, 40, 37, + 221, 226, 221, 232, 236, 236, 40, 37, + 221, 226, 221, 237, 221, 221, 221, 53, + 238, 221, 37, 221, 226, 221, 221, 221, + 221, 221, 237, 221, 239, 240, 241, 242, + 40, 37, 221, 226, 221, 221, 67, 221, + 243, 240, 244, 244, 40, 37, 221, 226, + 221, 240, 244, 244, 40, 37, 221, 226, + 221, 245, 221, 221, 221, 53, 246, 221, + 37, 221, 226, 221, 221, 221, 221, 221, + 245, 221, 247, 248, 249, 250, 40, 37, + 221, 226, 221, 221, 65, 221, 251, 248, + 252, 252, 40, 37, 221, 226, 221, 248, + 252, 252, 40, 37, 221, 226, 221, 253, + 221, 221, 221, 53, 254, 221, 37, 221, + 226, 221, 221, 221, 221, 221, 253, 221, + 255, 256, 257, 258, 40, 37, 221, 226, + 221, 221, 63, 221, 259, 256, 260, 260, + 40, 37, 221, 226, 221, 256, 260, 260, + 40, 37, 221, 226, 221, 53, 261, 221, + 37, 221, 226, 221, 262, 262, 221, 37, + 221, 226, 221, 263, 221, 221, 264, 221, + 226, 221, 226, 221, 265, 221, 266, 221, + 263, 221, 221, 221, 221, 226, 221, 53, + 221, 262, 262, 221, 37, 221, 226, 221, + 262, 261, 221, 37, 221, 226, 221, 267, + 62, 268, 269, 43, 37, 221, 226, 221, + 62, 268, 269, 43, 37, 221, 226, 221, + 268, 268, 43, 37, 221, 226, 221, 270, + 59, 271, 272, 46, 37, 221, 226, 221, + 59, 271, 272, 46, 37, 221, 226, 221, + 271, 271, 46, 37, 221, 226, 221, 273, + 56, 274, 275, 49, 37, 221, 226, 221, + 56, 274, 275, 49, 37, 221, 226, 221, + 274, 274, 49, 37, 221, 226, 221, 276, + 53, 262, 277, 221, 37, 221, 226, 221, + 53, 262, 277, 221, 37, 221, 226, 221, + 255, 256, 260, 260, 40, 37, 221, 226, + 221, 255, 256, 257, 260, 40, 37, 221, + 226, 221, 221, 63, 221, 253, 221, 278, + 221, 262, 262, 221, 37, 221, 226, 221, + 221, 221, 221, 221, 253, 221, 253, 221, + 221, 221, 262, 262, 221, 37, 221, 226, + 221, 221, 221, 221, 221, 253, 221, 253, + 221, 221, 221, 262, 254, 221, 37, 221, + 226, 221, 221, 221, 221, 221, 253, 221, + 247, 248, 252, 252, 40, 37, 221, 226, + 221, 247, 248, 249, 252, 40, 37, 221, + 226, 221, 221, 65, 221, 245, 221, 279, + 221, 262, 262, 221, 37, 221, 226, 221, + 221, 221, 221, 221, 245, 221, 245, 221, + 221, 221, 262, 262, 221, 37, 221, 226, + 221, 221, 221, 221, 221, 245, 221, 245, + 221, 221, 221, 262, 246, 221, 37, 221, + 226, 221, 221, 221, 221, 221, 245, 221, + 239, 240, 244, 244, 40, 37, 221, 226, + 221, 239, 240, 241, 244, 40, 37, 221, + 226, 221, 221, 67, 221, 237, 221, 280, + 221, 262, 262, 221, 37, 221, 226, 221, + 221, 221, 221, 221, 237, 221, 237, 221, + 221, 221, 262, 262, 221, 37, 221, 226, + 221, 221, 221, 221, 221, 237, 221, 237, + 221, 221, 221, 262, 238, 221, 37, 221, + 226, 221, 221, 221, 221, 221, 237, 221, + 231, 232, 236, 236, 40, 37, 221, 226, + 221, 231, 232, 233, 236, 40, 37, 221, + 226, 221, 221, 69, 221, 229, 221, 281, + 221, 262, 262, 221, 37, 221, 226, 221, + 221, 221, 221, 221, 229, 221, 229, 221, + 221, 221, 262, 262, 221, 37, 221, 226, + 221, 221, 221, 221, 221, 229, 221, 229, + 221, 221, 221, 262, 230, 221, 37, 221, + 226, 221, 221, 221, 221, 221, 229, 221, + 70, 39, 39, 40, 37, 221, 222, 223, + 228, 225, 40, 37, 221, 226, 221, 283, + 151, 284, 284, 76, 73, 282, 154, 282, + 151, 284, 284, 76, 73, 282, 154, 282, + 285, 282, 282, 282, 90, 286, 282, 73, + 282, 154, 282, 282, 282, 282, 282, 285, + 282, 287, 288, 289, 290, 76, 73, 282, + 154, 282, 282, 106, 282, 291, 288, 292, + 292, 76, 73, 282, 154, 282, 288, 292, + 292, 76, 73, 282, 154, 282, 293, 282, + 282, 282, 90, 294, 282, 73, 282, 154, + 282, 282, 282, 282, 282, 293, 282, 295, + 296, 297, 298, 76, 73, 282, 154, 282, + 282, 104, 282, 299, 296, 300, 300, 76, + 73, 282, 154, 282, 296, 300, 300, 76, + 73, 282, 154, 282, 301, 282, 282, 282, + 90, 302, 282, 73, 282, 154, 282, 282, + 282, 282, 282, 301, 282, 303, 304, 305, + 306, 76, 73, 282, 154, 282, 282, 102, + 282, 307, 304, 308, 308, 76, 73, 282, + 154, 282, 304, 308, 308, 76, 73, 282, + 154, 282, 309, 282, 282, 282, 90, 310, + 282, 73, 282, 154, 282, 282, 282, 282, + 282, 309, 282, 311, 312, 313, 314, 76, + 73, 282, 154, 282, 282, 100, 282, 315, + 312, 316, 316, 76, 73, 282, 154, 282, + 312, 316, 316, 76, 73, 282, 154, 282, + 90, 317, 282, 73, 282, 154, 282, 318, + 318, 282, 73, 282, 154, 282, 319, 282, + 282, 320, 282, 154, 282, 154, 282, 321, + 282, 322, 282, 319, 282, 282, 282, 282, + 154, 282, 90, 282, 318, 318, 282, 73, + 282, 154, 282, 318, 317, 282, 73, 282, + 154, 282, 323, 99, 324, 325, 80, 73, + 282, 154, 282, 99, 324, 325, 80, 73, + 282, 154, 282, 324, 324, 80, 73, 282, + 154, 282, 326, 96, 327, 328, 83, 73, + 282, 154, 282, 96, 327, 328, 83, 73, + 282, 154, 282, 327, 327, 83, 73, 282, + 154, 282, 329, 93, 330, 331, 86, 73, + 282, 154, 282, 93, 330, 331, 86, 73, + 282, 154, 282, 330, 330, 86, 73, 282, + 154, 282, 332, 90, 318, 333, 282, 73, + 282, 154, 282, 90, 318, 333, 282, 73, + 282, 154, 282, 311, 312, 316, 316, 76, + 73, 282, 154, 282, 311, 312, 313, 316, + 76, 73, 282, 154, 282, 282, 100, 282, + 309, 282, 334, 282, 318, 318, 282, 73, + 282, 154, 282, 282, 282, 282, 282, 309, + 282, 309, 282, 282, 282, 318, 318, 282, + 73, 282, 154, 282, 282, 282, 282, 282, + 309, 282, 309, 282, 282, 282, 318, 310, + 282, 73, 282, 154, 282, 282, 282, 282, + 282, 309, 282, 303, 304, 308, 308, 76, + 73, 282, 154, 282, 303, 304, 305, 308, + 76, 73, 282, 154, 282, 282, 102, 282, + 301, 282, 335, 282, 318, 318, 282, 73, + 282, 154, 282, 282, 282, 282, 282, 301, + 282, 301, 282, 282, 282, 318, 318, 282, + 73, 282, 154, 282, 282, 282, 282, 282, + 301, 282, 301, 282, 282, 282, 318, 302, + 282, 73, 282, 154, 282, 282, 282, 282, + 282, 301, 282, 295, 296, 300, 300, 76, + 73, 282, 154, 282, 295, 296, 297, 300, + 76, 73, 282, 154, 282, 282, 104, 282, + 293, 282, 336, 282, 318, 318, 282, 73, + 282, 154, 282, 282, 282, 282, 282, 293, + 282, 293, 282, 282, 282, 318, 318, 282, + 73, 282, 154, 282, 282, 282, 282, 282, + 293, 282, 293, 282, 282, 282, 318, 294, + 282, 73, 282, 154, 282, 282, 282, 282, + 282, 293, 282, 287, 288, 292, 292, 76, + 73, 282, 154, 282, 287, 288, 289, 292, + 76, 73, 282, 154, 282, 282, 106, 282, + 285, 282, 337, 282, 318, 318, 282, 73, + 282, 154, 282, 282, 282, 282, 282, 285, + 282, 285, 282, 282, 282, 318, 318, 282, + 73, 282, 154, 282, 282, 282, 282, 282, + 285, 282, 285, 282, 282, 282, 318, 286, + 282, 73, 282, 154, 282, 282, 282, 282, + 282, 285, 282, 107, 75, 75, 76, 73, + 338, 338, 338, 338, 144, 338, 150, 151, + 284, 284, 76, 73, 282, 154, 282, 107, + 75, 75, 76, 73, 338, 340, 341, 342, + 343, 112, 109, 339, 344, 339, 339, 143, + 339, 345, 341, 343, 343, 112, 109, 339, + 344, 339, 341, 343, 343, 112, 109, 339, + 344, 339, 346, 339, 339, 339, 125, 347, + 339, 109, 339, 344, 339, 339, 339, 339, + 339, 346, 339, 348, 349, 350, 351, 112, + 109, 339, 344, 339, 339, 141, 339, 352, + 349, 353, 353, 112, 109, 339, 344, 339, + 349, 353, 353, 112, 109, 339, 344, 339, + 354, 339, 339, 339, 125, 355, 339, 109, + 339, 344, 339, 339, 339, 339, 339, 354, + 339, 356, 357, 358, 359, 112, 109, 339, + 344, 339, 339, 139, 339, 360, 357, 361, + 361, 112, 109, 339, 344, 339, 357, 361, + 361, 112, 109, 339, 344, 339, 362, 339, + 339, 339, 125, 363, 339, 109, 339, 344, + 339, 339, 339, 339, 339, 362, 339, 364, + 365, 366, 367, 112, 109, 339, 344, 339, + 339, 137, 339, 368, 365, 369, 369, 112, + 109, 339, 344, 339, 365, 369, 369, 112, + 109, 339, 344, 339, 370, 339, 339, 339, + 125, 371, 339, 109, 339, 344, 339, 339, + 339, 339, 339, 370, 339, 372, 373, 374, + 375, 112, 109, 339, 344, 339, 339, 135, + 339, 376, 373, 377, 377, 112, 109, 339, + 344, 339, 373, 377, 377, 112, 109, 339, + 344, 339, 125, 378, 339, 109, 339, 344, + 339, 379, 379, 339, 109, 339, 344, 339, + 380, 339, 339, 381, 339, 344, 339, 344, + 339, 382, 339, 383, 339, 380, 339, 339, + 339, 339, 344, 339, 125, 339, 379, 379, + 339, 109, 339, 344, 339, 379, 378, 339, + 109, 339, 344, 339, 384, 134, 385, 386, + 115, 109, 339, 344, 339, 134, 385, 386, + 115, 109, 339, 344, 339, 385, 385, 115, + 109, 339, 344, 339, 387, 131, 388, 389, + 118, 109, 339, 344, 339, 131, 388, 389, + 118, 109, 339, 344, 339, 388, 388, 118, + 109, 339, 344, 339, 390, 128, 391, 392, + 121, 109, 339, 344, 339, 128, 391, 392, + 121, 109, 339, 344, 339, 391, 391, 121, + 109, 339, 344, 339, 393, 125, 379, 394, + 339, 109, 339, 344, 339, 125, 379, 394, + 339, 109, 339, 344, 339, 372, 373, 377, + 377, 112, 109, 339, 344, 339, 372, 373, + 374, 377, 112, 109, 339, 344, 339, 339, + 135, 339, 370, 339, 395, 339, 379, 379, + 339, 109, 339, 344, 339, 339, 339, 339, + 339, 370, 339, 370, 339, 339, 339, 379, + 379, 339, 109, 339, 344, 339, 339, 339, + 339, 339, 370, 339, 370, 339, 339, 339, + 379, 371, 339, 109, 339, 344, 339, 339, + 339, 339, 339, 370, 339, 364, 365, 369, + 369, 112, 109, 339, 344, 339, 364, 365, + 366, 369, 112, 109, 339, 344, 339, 339, + 137, 339, 362, 339, 396, 339, 379, 379, + 339, 109, 339, 344, 339, 339, 339, 339, + 339, 362, 339, 362, 339, 339, 339, 379, + 379, 339, 109, 339, 344, 339, 339, 339, + 339, 339, 362, 339, 362, 339, 339, 339, + 379, 363, 339, 109, 339, 344, 339, 339, + 339, 339, 339, 362, 339, 356, 357, 361, + 361, 112, 109, 339, 344, 339, 356, 357, + 358, 361, 112, 109, 339, 344, 339, 339, + 139, 339, 354, 339, 397, 339, 379, 379, + 339, 109, 339, 344, 339, 339, 339, 339, + 339, 354, 339, 354, 339, 339, 339, 379, + 379, 339, 109, 339, 344, 339, 339, 339, + 339, 339, 354, 339, 354, 339, 339, 339, + 379, 355, 339, 109, 339, 344, 339, 339, + 339, 339, 339, 354, 339, 348, 349, 353, + 353, 112, 109, 339, 344, 339, 348, 349, + 350, 353, 112, 109, 339, 344, 339, 339, + 141, 339, 346, 339, 398, 339, 379, 379, + 339, 109, 339, 344, 339, 339, 339, 339, + 339, 346, 339, 346, 339, 339, 339, 379, + 379, 339, 109, 339, 344, 339, 339, 339, + 339, 339, 346, 339, 346, 339, 339, 339, + 379, 347, 339, 109, 339, 344, 339, 339, + 339, 339, 339, 346, 339, 340, 341, 343, + 343, 112, 109, 339, 344, 339, 148, 149, + 150, 151, 399, 284, 76, 73, 282, 154, + 155, 155, 144, 282, 282, 148, 282, 161, + 400, 163, 164, 4, 1, 160, 165, 160, + 160, 35, 160, 168, 149, 150, 151, 401, + 402, 76, 403, 160, 404, 160, 155, 144, + 160, 160, 168, 160, 107, 405, 405, 76, + 403, 160, 165, 160, 160, 144, 160, 406, + 160, 160, 407, 160, 404, 160, 404, 160, + 408, 160, 205, 160, 406, 160, 160, 160, + 160, 404, 160, 168, 160, 220, 107, 405, + 405, 76, 403, 160, 165, 160, 160, 160, + 160, 160, 168, 160, 410, 409, 411, 411, + 409, 146, 409, 412, 409, 411, 411, 409, + 146, 409, 412, 409, 413, 409, 409, 414, + 409, 412, 409, 412, 409, 415, 409, 416, + 409, 413, 409, 409, 409, 409, 412, 409, + 148, 338, 338, 338, 338, 338, 338, 338, + 338, 338, 155, 338, 338, 338, 338, 148, + 338, 0 }; static const short _indic_syllable_machine_trans_targs[] = { - 166, 188, 2, 194, 3, 5, 197, 6, - 8, 200, 9, 11, 203, 12, 14, 15, - 187, 17, 18, 202, 20, 21, 199, 23, - 24, 196, 205, 208, 212, 214, 218, 220, - 224, 226, 230, 232, 166, 255, 37, 261, - 38, 40, 264, 41, 43, 267, 44, 46, - 270, 47, 49, 50, 254, 52, 53, 269, - 55, 56, 266, 58, 59, 263, 272, 275, - 279, 281, 285, 287, 291, 293, 297, 300, - 166, 321, 72, 327, 166, 73, 75, 330, - 76, 78, 333, 79, 81, 336, 82, 84, - 85, 320, 87, 88, 335, 90, 91, 332, - 93, 94, 329, 338, 341, 345, 347, 351, - 353, 357, 359, 363, 166, 389, 106, 395, - 107, 109, 398, 110, 112, 401, 113, 115, - 404, 116, 118, 119, 388, 121, 122, 403, - 124, 125, 400, 127, 128, 397, 406, 409, - 413, 415, 419, 421, 425, 427, 431, 433, - 366, 142, 444, 144, 447, 438, 145, 147, - 450, 148, 150, 453, 151, 154, 155, 455, - 157, 158, 452, 160, 161, 449, 163, 164, - 446, 166, 458, 166, 167, 234, 301, 303, - 365, 367, 323, 368, 434, 435, 340, 456, - 463, 166, 168, 170, 34, 233, 190, 207, - 169, 33, 171, 228, 172, 174, 32, 227, - 173, 31, 175, 222, 176, 178, 30, 221, - 177, 29, 179, 216, 180, 182, 28, 215, - 181, 27, 183, 210, 184, 186, 26, 209, - 185, 25, 193, 0, 189, 192, 191, 166, - 1, 195, 4, 22, 198, 7, 19, 201, - 10, 16, 204, 13, 206, 211, 213, 217, - 219, 223, 225, 229, 231, 166, 235, 237, - 69, 299, 257, 274, 236, 68, 238, 295, - 239, 241, 67, 294, 240, 66, 242, 289, - 243, 245, 65, 288, 244, 64, 246, 283, - 247, 249, 63, 282, 248, 62, 250, 277, - 251, 253, 61, 276, 252, 60, 260, 35, - 256, 259, 258, 166, 36, 262, 39, 57, - 265, 42, 54, 268, 45, 51, 271, 48, - 273, 278, 280, 284, 286, 290, 292, 296, - 298, 166, 302, 103, 304, 361, 305, 307, - 102, 360, 306, 101, 308, 355, 309, 311, - 100, 354, 310, 99, 312, 349, 313, 315, - 98, 348, 314, 97, 316, 343, 317, 319, - 96, 342, 318, 95, 326, 70, 322, 325, - 324, 166, 71, 328, 74, 92, 331, 77, - 89, 334, 80, 86, 337, 83, 339, 344, - 346, 350, 352, 356, 358, 362, 364, 166, - 166, 369, 371, 138, 137, 391, 408, 370, - 372, 429, 373, 375, 136, 428, 374, 135, - 376, 423, 377, 379, 134, 422, 378, 133, - 380, 417, 381, 383, 132, 416, 382, 131, - 384, 411, 385, 387, 130, 410, 386, 129, - 394, 104, 390, 393, 392, 166, 105, 396, - 108, 126, 399, 111, 123, 402, 114, 120, - 405, 117, 407, 412, 414, 418, 420, 424, - 426, 430, 432, 139, 436, 437, 443, 440, - 140, 439, 442, 441, 141, 445, 143, 162, - 448, 146, 159, 451, 149, 156, 454, 152, - 153, 166, 457, 165, 460, 459, 462, 461, - 166 + 138, 160, 166, 2, 167, 3, 5, 170, + 6, 8, 173, 9, 11, 176, 12, 14, + 15, 159, 17, 18, 175, 20, 21, 172, + 23, 24, 169, 178, 182, 183, 187, 188, + 192, 193, 197, 198, 138, 221, 227, 36, + 228, 37, 39, 231, 40, 42, 234, 43, + 45, 237, 46, 48, 49, 220, 51, 52, + 236, 54, 55, 233, 57, 58, 230, 239, + 243, 244, 248, 249, 253, 254, 258, 260, + 138, 281, 287, 70, 288, 138, 71, 73, + 291, 74, 76, 294, 77, 79, 297, 80, + 82, 83, 280, 85, 86, 296, 88, 89, + 293, 91, 92, 290, 299, 303, 304, 308, + 309, 313, 314, 318, 138, 343, 349, 103, + 350, 104, 106, 353, 107, 109, 356, 110, + 112, 359, 113, 115, 116, 342, 118, 119, + 358, 121, 122, 355, 124, 125, 352, 361, + 365, 366, 370, 371, 375, 376, 380, 381, + 320, 138, 394, 138, 139, 200, 261, 263, + 319, 321, 283, 322, 382, 383, 392, 399, + 138, 140, 142, 33, 199, 162, 141, 32, + 143, 195, 144, 146, 31, 194, 145, 30, + 147, 190, 148, 150, 29, 189, 149, 28, + 151, 185, 152, 154, 27, 184, 153, 26, + 155, 180, 156, 158, 25, 179, 157, 1, + 165, 0, 161, 164, 163, 138, 168, 4, + 22, 171, 7, 19, 174, 10, 16, 177, + 13, 181, 186, 191, 196, 138, 201, 203, + 67, 259, 223, 202, 66, 204, 256, 205, + 207, 65, 255, 206, 64, 208, 251, 209, + 211, 63, 250, 210, 62, 212, 246, 213, + 215, 61, 245, 214, 60, 216, 241, 217, + 219, 59, 240, 218, 35, 226, 34, 222, + 225, 224, 138, 229, 38, 56, 232, 41, + 53, 235, 44, 50, 238, 47, 242, 247, + 252, 257, 138, 262, 100, 264, 316, 265, + 267, 99, 315, 266, 98, 268, 311, 269, + 271, 97, 310, 270, 96, 272, 306, 273, + 275, 95, 305, 274, 94, 276, 301, 277, + 279, 93, 300, 278, 69, 286, 68, 282, + 285, 284, 138, 289, 72, 90, 292, 75, + 87, 295, 78, 84, 298, 81, 302, 307, + 312, 317, 138, 138, 323, 325, 134, 133, + 345, 324, 326, 378, 327, 329, 132, 377, + 328, 131, 330, 373, 331, 333, 130, 372, + 332, 129, 334, 368, 335, 337, 128, 367, + 336, 127, 338, 363, 339, 341, 126, 362, + 340, 102, 348, 101, 344, 347, 346, 138, + 351, 105, 123, 354, 108, 120, 357, 111, + 117, 360, 114, 364, 369, 374, 379, 135, + 384, 385, 391, 386, 388, 136, 387, 390, + 389, 138, 393, 137, 396, 395, 398, 397, + 138 }; static const char _indic_syllable_machine_trans_actions[] = { - 1, 0, 0, 2, 0, 0, 2, 0, - 0, 2, 0, 0, 2, 0, 0, 0, - 2, 0, 0, 2, 0, 0, 2, 0, - 0, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 3, 0, 0, 2, - 0, 0, 2, 0, 0, 2, 0, 0, - 2, 0, 0, 0, 2, 0, 0, 2, - 0, 0, 2, 0, 0, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, - 4, 0, 0, 2, 5, 0, 0, 2, + 1, 0, 2, 0, 2, 0, 0, 2, 0, 0, 2, 0, 0, 2, 0, 0, 0, 2, 0, 0, 2, 0, 0, 2, - 0, 0, 2, 2, 6, 2, 6, 2, - 6, 2, 6, 2, 7, 0, 0, 2, - 0, 0, 2, 0, 0, 2, 0, 0, - 2, 0, 0, 0, 2, 0, 0, 2, - 0, 0, 2, 0, 0, 2, 2, 2, + 0, 0, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 3, 0, 2, 0, + 2, 0, 0, 2, 0, 0, 2, 0, + 0, 2, 0, 0, 0, 2, 0, 0, + 2, 0, 0, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 6, 0, 2, 0, 2, 0, 0, 0, - 2, 0, 0, 2, 0, 0, 0, 2, + 4, 0, 2, 0, 2, 5, 0, 0, + 2, 0, 0, 2, 0, 0, 2, 0, 0, 0, 2, 0, 0, 2, 0, 0, - 2, 8, 0, 11, 2, 2, 6, 0, - 12, 12, 0, 2, 6, 2, 6, 2, - 0, 13, 2, 0, 0, 2, 0, 2, - 2, 0, 2, 2, 2, 0, 0, 2, - 2, 0, 2, 2, 2, 0, 0, 2, - 2, 0, 2, 2, 2, 0, 0, 2, - 2, 0, 2, 2, 2, 0, 0, 2, - 2, 0, 2, 0, 0, 0, 0, 14, - 0, 2, 0, 0, 2, 0, 0, 2, - 0, 0, 2, 0, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 15, 2, 0, - 0, 2, 0, 2, 2, 0, 2, 2, - 2, 0, 0, 2, 2, 0, 2, 2, - 2, 0, 0, 2, 2, 0, 2, 2, - 2, 0, 0, 2, 2, 0, 2, 2, - 2, 0, 0, 2, 2, 0, 2, 0, - 0, 0, 0, 16, 0, 2, 0, 0, + 2, 0, 0, 2, 6, 2, 6, 2, + 6, 2, 6, 2, 7, 0, 2, 0, 2, 0, 0, 2, 0, 0, 2, 0, + 0, 2, 0, 0, 0, 2, 0, 0, + 2, 0, 0, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 17, 6, 0, 6, 6, 6, 0, - 0, 6, 6, 0, 6, 6, 6, 0, - 0, 6, 6, 0, 6, 6, 6, 0, - 0, 6, 6, 0, 6, 6, 6, 0, - 0, 6, 6, 0, 6, 0, 0, 0, - 0, 18, 0, 2, 0, 0, 2, 0, - 0, 2, 0, 0, 2, 0, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 19, - 20, 2, 0, 0, 0, 0, 2, 2, + 6, 8, 0, 11, 2, 2, 6, 0, + 12, 12, 0, 2, 6, 2, 2, 0, + 13, 2, 0, 0, 2, 0, 2, 0, 2, 2, 2, 0, 0, 2, 2, 0, 2, 2, 2, 0, 0, 2, 2, 0, 2, 2, 2, 0, 0, 2, 2, 0, 2, 2, 2, 0, 0, 2, 2, 0, - 2, 0, 0, 0, 0, 21, 0, 2, - 0, 0, 2, 0, 0, 2, 0, 0, - 2, 0, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 0, 0, 22, 2, 0, - 0, 0, 0, 0, 0, 2, 0, 0, + 2, 0, 0, 0, 0, 14, 2, 0, + 0, 2, 0, 0, 2, 0, 0, 2, + 0, 2, 2, 2, 2, 15, 2, 0, + 0, 2, 0, 2, 0, 2, 2, 2, + 0, 0, 2, 2, 0, 2, 2, 2, + 0, 0, 2, 2, 0, 2, 2, 2, + 0, 0, 2, 2, 0, 2, 2, 2, + 0, 0, 2, 2, 0, 2, 0, 0, + 0, 0, 16, 2, 0, 0, 2, 0, + 0, 2, 0, 0, 2, 0, 2, 2, + 2, 2, 17, 6, 0, 6, 2, 6, + 0, 0, 6, 6, 0, 6, 2, 6, + 0, 0, 6, 6, 0, 6, 2, 6, + 0, 0, 6, 6, 0, 6, 2, 6, + 0, 0, 6, 6, 0, 2, 0, 0, + 0, 0, 18, 2, 0, 0, 2, 0, + 0, 2, 0, 0, 2, 0, 2, 2, + 2, 2, 19, 20, 2, 0, 0, 0, + 0, 2, 2, 2, 2, 0, 0, 2, + 2, 0, 2, 2, 2, 0, 0, 2, + 2, 0, 2, 2, 2, 0, 0, 2, + 2, 0, 2, 2, 2, 0, 0, 2, + 2, 0, 2, 0, 0, 0, 0, 21, 2, 0, 0, 2, 0, 0, 2, 0, + 0, 2, 0, 2, 2, 2, 2, 0, + 0, 22, 22, 0, 0, 0, 0, 0, 0, 23, 2, 0, 0, 0, 0, 0, 24 }; @@ -937,15 +759,7 @@ static const char _indic_syllable_machine_to_state_actions[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 9, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -998,15 +812,7 @@ static const char _indic_syllable_machine_from_state_actions[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 10, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1046,67 +852,59 @@ static const short _indic_syllable_machine_eof_trans[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 37, 37, 37, 37, 37, + 1, 1, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, - 37, 37, 37, 37, 37, 37, 73, 73, - 77, 77, 73, 73, 73, 73, 73, 73, + 37, 37, 37, 37, 73, 73, 78, 78, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, + 73, 73, 73, 73, 73, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, - 109, 109, 109, 109, 109, 109, 109, 109, - 109, 109, 109, 73, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 170, 0, 186, - 186, 186, 186, 186, 186, 186, 186, 186, - 186, 186, 186, 186, 186, 186, 186, 186, - 186, 186, 186, 186, 186, 186, 186, 186, - 186, 186, 186, 186, 186, 186, 186, 186, - 186, 186, 186, 186, 186, 186, 186, 186, - 186, 186, 186, 186, 186, 186, 186, 186, - 186, 186, 186, 186, 186, 186, 186, 186, - 186, 186, 186, 186, 186, 186, 186, 186, - 186, 186, 254, 254, 254, 254, 254, 254, - 254, 254, 254, 254, 254, 254, 254, 254, - 254, 254, 254, 254, 254, 254, 254, 254, - 254, 254, 254, 254, 254, 254, 254, 254, - 254, 254, 254, 254, 254, 254, 254, 254, - 254, 254, 254, 254, 254, 254, 254, 254, - 254, 254, 254, 254, 254, 254, 254, 254, - 254, 254, 254, 254, 254, 254, 254, 254, - 254, 254, 254, 254, 254, 322, 322, 322, - 322, 322, 322, 322, 322, 322, 322, 322, - 322, 322, 322, 322, 322, 322, 322, 322, - 322, 322, 322, 322, 322, 322, 322, 322, - 322, 322, 322, 322, 322, 322, 322, 322, - 322, 322, 322, 322, 322, 322, 322, 322, - 322, 322, 322, 322, 322, 322, 322, 322, - 322, 322, 322, 322, 322, 322, 322, 322, - 322, 322, 322, 322, 322, 384, 322, 384, - 385, 385, 385, 385, 385, 385, 385, 385, - 385, 385, 385, 385, 385, 385, 385, 385, - 385, 385, 385, 385, 385, 385, 385, 385, - 385, 385, 385, 385, 385, 385, 385, 385, - 385, 385, 385, 385, 385, 385, 385, 385, - 385, 385, 385, 385, 385, 385, 385, 385, - 385, 385, 385, 385, 385, 385, 385, 385, - 385, 385, 385, 385, 385, 385, 385, 385, - 385, 385, 322, 186, 186, 186, 186, 186, - 186, 186, 186, 186, 186, 186, 186, 186, - 186, 186, 186, 186, 186, 186, 186, 186, - 474, 474, 474, 474, 474, 474, 474, 384 + 109, 109, 109, 109, 109, 109, 109, 73, + 1, 146, 0, 161, 161, 161, 161, 161, + 161, 161, 161, 161, 161, 161, 161, 161, + 161, 161, 161, 161, 161, 161, 161, 161, + 161, 161, 161, 161, 161, 161, 161, 161, + 161, 161, 161, 161, 161, 161, 161, 161, + 161, 161, 161, 161, 161, 161, 161, 161, + 161, 161, 161, 161, 161, 161, 161, 161, + 161, 161, 161, 161, 161, 161, 161, 161, + 222, 222, 222, 222, 222, 222, 222, 222, + 222, 222, 222, 222, 222, 222, 222, 222, + 222, 222, 222, 222, 222, 222, 222, 222, + 222, 222, 222, 222, 222, 222, 222, 222, + 222, 222, 222, 222, 222, 222, 222, 222, + 222, 222, 222, 222, 222, 222, 222, 222, + 222, 222, 222, 222, 222, 222, 222, 222, + 222, 222, 222, 222, 222, 283, 283, 283, + 283, 283, 283, 283, 283, 283, 283, 283, + 283, 283, 283, 283, 283, 283, 283, 283, + 283, 283, 283, 283, 283, 283, 283, 283, + 283, 283, 283, 283, 283, 283, 283, 283, + 283, 283, 283, 283, 283, 283, 283, 283, + 283, 283, 283, 283, 283, 283, 283, 283, + 283, 283, 283, 283, 283, 283, 283, 339, + 283, 339, 340, 340, 340, 340, 340, 340, + 340, 340, 340, 340, 340, 340, 340, 340, + 340, 340, 340, 340, 340, 340, 340, 340, + 340, 340, 340, 340, 340, 340, 340, 340, + 340, 340, 340, 340, 340, 340, 340, 340, + 340, 340, 340, 340, 340, 340, 340, 340, + 340, 340, 340, 340, 340, 340, 340, 340, + 340, 340, 340, 340, 340, 340, 283, 161, + 161, 161, 161, 161, 161, 161, 161, 161, + 410, 410, 410, 410, 410, 410, 410, 339 }; -static const int indic_syllable_machine_start = 166; -static const int indic_syllable_machine_first_final = 166; +static const int indic_syllable_machine_start = 138; +static const int indic_syllable_machine_first_final = 138; static const int indic_syllable_machine_error = -1; -static const int indic_syllable_machine_en_main = 166; +static const int indic_syllable_machine_en_main = 138; #line 36 "hb-ot-shape-complex-indic-machine.rl" @@ -1118,10 +916,9 @@ static const int indic_syllable_machine_en_main = 166; #define found_syllable(syllable_type) \ HB_STMT_START { \ - if (0) fprintf (stderr, "syllable %d..%d %s\n", last, p+1, #syllable_type); \ - for (unsigned int i = last; i < p+1; i++) \ + if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \ + for (unsigned int i = ts; i < te; i++) \ info[i].syllable() = (syllable_serial << 4) | syllable_type; \ - last = p+1; \ syllable_serial++; \ if (unlikely (syllable_serial == 16)) syllable_serial = 1; \ } HB_STMT_END @@ -1129,11 +926,11 @@ static const int indic_syllable_machine_en_main = 166; static void find_syllables (hb_buffer_t *buffer) { - unsigned int p, pe, eof, ts HB_UNUSED, te, act; + unsigned int p, pe, eof, ts, te, act; int cs; hb_glyph_info_t *info = buffer->info; -#line 1137 "hb-ot-shape-complex-indic-machine.hh" +#line 934 "hb-ot-shape-complex-indic-machine.hh" { cs = indic_syllable_machine_start; ts = 0; @@ -1141,16 +938,15 @@ find_syllables (hb_buffer_t *buffer) act = 0; } -#line 113 "hb-ot-shape-complex-indic-machine.rl" +#line 112 "hb-ot-shape-complex-indic-machine.rl" p = 0; pe = eof = buffer->len; - unsigned int last = 0; unsigned int syllable_serial = 1; -#line 1154 "hb-ot-shape-complex-indic-machine.hh" +#line 950 "hb-ot-shape-complex-indic-machine.hh" { int _slen; int _trans; @@ -1164,7 +960,7 @@ _resume: #line 1 "NONE" {ts = p;} break; -#line 1168 "hb-ot-shape-complex-indic-machine.hh" +#line 964 "hb-ot-shape-complex-indic-machine.hh" } _keys = _indic_syllable_machine_trans_keys + (cs<<1); @@ -1287,7 +1083,7 @@ _eof_trans: #line 88 "hb-ot-shape-complex-indic-machine.rl" {act = 6;} break; -#line 1291 "hb-ot-shape-complex-indic-machine.hh" +#line 1087 "hb-ot-shape-complex-indic-machine.hh" } _again: @@ -1296,7 +1092,7 @@ _again: #line 1 "NONE" {ts = 0;} break; -#line 1300 "hb-ot-shape-complex-indic-machine.hh" +#line 1096 "hb-ot-shape-complex-indic-machine.hh" } if ( ++p != pe ) @@ -1312,7 +1108,7 @@ _again: } -#line 122 "hb-ot-shape-complex-indic-machine.rl" +#line 120 "hb-ot-shape-complex-indic-machine.rl" } diff --git a/src/hb-ot-shape-complex-indic-machine.rl b/src/hb-ot-shape-complex-indic-machine.rl index 35e7ce906..c5d945d4e 100644 --- a/src/hb-ot-shape-complex-indic-machine.rl +++ b/src/hb-ot-shape-complex-indic-machine.rl @@ -27,7 +27,7 @@ #ifndef HB_OT_SHAPE_COMPLEX_INDIC_MACHINE_HH #define HB_OT_SHAPE_COMPLEX_INDIC_MACHINE_HH -#include "hb-private.hh" +#include "hb.hh" %%{ machine indic_syllable_machine; @@ -52,7 +52,6 @@ DOTTEDCIRCLE = 12; RS = 13; Repha = 15; Ra = 16; -CM = 17; Symbol= 18; CS = 19; @@ -68,15 +67,16 @@ matra_group = z{0,3}.M.N?.(H | forced_rakar)?; syllable_tail = (z?.SM.SM?.ZWNJ?)? A{0,3}?; halant_group = (z?.H.(ZWJ.N?)?); final_halant_group = halant_group | H.ZWNJ; -medial_group = CM?; -halant_or_matra_group = (final_halant_group | (H.ZWJ)? matra_group{0,4}); +halant_or_matra_group = (final_halant_group | matra_group{0,4}); +complex_syllable_tail = (halant_group.cn){0,4} halant_or_matra_group syllable_tail; -consonant_syllable = (Repha|CS)? (cn.halant_group){0,4} cn medial_group halant_or_matra_group syllable_tail; -vowel_syllable = reph? V.n? (ZWJ | (halant_group.cn){0,4} medial_group halant_or_matra_group syllable_tail); -standalone_cluster = ((Repha|CS)? PLACEHOLDER | reph? DOTTEDCIRCLE).n? (halant_group.cn){0,4} medial_group halant_or_matra_group syllable_tail; + +consonant_syllable = (Repha|CS)? cn complex_syllable_tail; +vowel_syllable = reph? V.n? (ZWJ | complex_syllable_tail); +standalone_cluster = ((Repha|CS)? PLACEHOLDER | reph? DOTTEDCIRCLE).n? complex_syllable_tail; symbol_cluster = symbol syllable_tail; -broken_cluster = reph? n? (halant_group.cn){0,4} medial_group halant_or_matra_group syllable_tail; +broken_cluster = reph? n? complex_syllable_tail; other = any; main := |* @@ -93,10 +93,9 @@ main := |* #define found_syllable(syllable_type) \ HB_STMT_START { \ - if (0) fprintf (stderr, "syllable %d..%d %s\n", last, p+1, #syllable_type); \ - for (unsigned int i = last; i < p+1; i++) \ + if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \ + for (unsigned int i = ts; i < te; i++) \ info[i].syllable() = (syllable_serial << 4) | syllable_type; \ - last = p+1; \ syllable_serial++; \ if (unlikely (syllable_serial == 16)) syllable_serial = 1; \ } HB_STMT_END @@ -104,7 +103,7 @@ main := |* static void find_syllables (hb_buffer_t *buffer) { - unsigned int p, pe, eof, ts HB_UNUSED, te, act; + unsigned int p, pe, eof, ts, te, act; int cs; hb_glyph_info_t *info = buffer->info; %%{ @@ -115,7 +114,6 @@ find_syllables (hb_buffer_t *buffer) p = 0; pe = eof = buffer->len; - unsigned int last = 0; unsigned int syllable_serial = 1; %%{ write exec; diff --git a/src/hb-ot-shape-complex-indic-table.cc b/src/hb-ot-shape-complex-indic-table.cc index 54291bc22..b7e4e7c7c 100644 --- a/src/hb-ot-shape-complex-indic-table.cc +++ b/src/hb-ot-shape-complex-indic-table.cc @@ -14,7 +14,7 @@ * # Date: 2017-10-16, 24:39:00 GMT [KW] */ -#include "hb-ot-shape-complex-indic-private.hh" +#include "hb-ot-shape-complex-indic.hh" #define ISC_A INDIC_SYLLABIC_CATEGORY_AVAGRAHA /* 16 chars; Avagraha */ diff --git a/src/hb-ot-shape-complex-indic.cc b/src/hb-ot-shape-complex-indic.cc index b52656f44..f1ae303ad 100644 --- a/src/hb-ot-shape-complex-indic.cc +++ b/src/hb-ot-shape-complex-indic.cc @@ -24,8 +24,8 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-ot-shape-complex-indic-private.hh" -#include "hb-ot-layout-private.hh" +#include "hb-ot-shape-complex-indic.hh" +#include "hb-ot-layout.hh" /* @@ -95,42 +95,40 @@ static const indic_config_t indic_configs[] = * Indic shaper. */ -struct feature_list_t { - hb_tag_t tag; - hb_ot_map_feature_flags_t flags; -}; - -static const feature_list_t +static const hb_ot_map_feature_t indic_features[] = { /* * Basic features. * These features are applied in order, one at a time, after initial_reordering. */ - {HB_TAG('n','u','k','t'), F_GLOBAL}, - {HB_TAG('a','k','h','n'), F_GLOBAL}, - {HB_TAG('r','p','h','f'), F_NONE}, - {HB_TAG('r','k','r','f'), F_GLOBAL}, - {HB_TAG('p','r','e','f'), F_NONE}, - {HB_TAG('b','l','w','f'), F_NONE}, - {HB_TAG('a','b','v','f'), F_NONE}, - {HB_TAG('h','a','l','f'), F_NONE}, - {HB_TAG('p','s','t','f'), F_NONE}, - {HB_TAG('v','a','t','u'), F_GLOBAL}, - {HB_TAG('c','j','c','t'), F_GLOBAL}, + {HB_TAG('n','u','k','t'), F_GLOBAL_MANUAL_JOINERS}, + {HB_TAG('a','k','h','n'), F_GLOBAL_MANUAL_JOINERS}, + {HB_TAG('r','p','h','f'), F_MANUAL_JOINERS}, + {HB_TAG('r','k','r','f'), F_GLOBAL_MANUAL_JOINERS}, + {HB_TAG('p','r','e','f'), F_MANUAL_JOINERS}, + {HB_TAG('b','l','w','f'), F_MANUAL_JOINERS}, + {HB_TAG('a','b','v','f'), F_MANUAL_JOINERS}, + {HB_TAG('h','a','l','f'), F_MANUAL_JOINERS}, + {HB_TAG('p','s','t','f'), F_MANUAL_JOINERS}, + {HB_TAG('v','a','t','u'), F_GLOBAL_MANUAL_JOINERS}, + {HB_TAG('c','j','c','t'), F_GLOBAL_MANUAL_JOINERS}, /* * Other features. * These features are applied all at once, after final_reordering. * Default Bengali font in Windows for example has intermixed * lookups for init,pres,abvs,blws features. */ - {HB_TAG('i','n','i','t'), F_NONE}, - {HB_TAG('p','r','e','s'), F_GLOBAL}, - {HB_TAG('a','b','v','s'), F_GLOBAL}, - {HB_TAG('b','l','w','s'), F_GLOBAL}, - {HB_TAG('p','s','t','s'), F_GLOBAL}, - {HB_TAG('h','a','l','n'), F_GLOBAL}, - /* Positioning features, though we don't care about the types. */ + {HB_TAG('i','n','i','t'), F_MANUAL_JOINERS}, + {HB_TAG('p','r','e','s'), F_GLOBAL_MANUAL_JOINERS}, + {HB_TAG('a','b','v','s'), F_GLOBAL_MANUAL_JOINERS}, + {HB_TAG('b','l','w','s'), F_GLOBAL_MANUAL_JOINERS}, + {HB_TAG('p','s','t','s'), F_GLOBAL_MANUAL_JOINERS}, + {HB_TAG('h','a','l','n'), F_GLOBAL_MANUAL_JOINERS}, + /* + * Positioning features. + * We don't care about the types. + */ {HB_TAG('d','i','s','t'), F_GLOBAL}, {HB_TAG('a','b','v','m'), F_GLOBAL}, {HB_TAG('b','l','w','m'), F_GLOBAL}, @@ -158,12 +156,13 @@ enum { _BLWS, _PSTS, _HALN, + _DIST, _ABVM, _BLWM, INDIC_NUM_FEATURES, - INDIC_BASIC_FEATURES = INIT /* Don't forget to update this! */ + INDIC_BASIC_FEATURES = INIT, /* Don't forget to update this! */ }; static void @@ -191,25 +190,27 @@ collect_features_indic (hb_ot_shape_planner_t *plan) /* Do this before any lookups have been applied. */ map->add_gsub_pause (setup_syllables); - map->add_global_bool_feature (HB_TAG('l','o','c','l')); + map->enable_feature (HB_TAG('l','o','c','l')); /* The Indic specs do not require ccmp, but we apply it here since if * there is a use of it, it's typically at the beginning. */ - map->add_global_bool_feature (HB_TAG('c','c','m','p')); + map->enable_feature (HB_TAG('c','c','m','p')); unsigned int i = 0; map->add_gsub_pause (initial_reordering); + for (; i < INDIC_BASIC_FEATURES; i++) { - map->add_feature (indic_features[i].tag, 1, indic_features[i].flags | F_MANUAL_ZWJ | F_MANUAL_ZWNJ); + map->add_feature (indic_features[i]); map->add_gsub_pause (nullptr); } + map->add_gsub_pause (final_reordering); - for (; i < INDIC_NUM_FEATURES; i++) { - map->add_feature (indic_features[i].tag, 1, indic_features[i].flags | F_MANUAL_ZWJ | F_MANUAL_ZWNJ); - } - map->add_global_bool_feature (HB_TAG('c','a','l','t')); - map->add_global_bool_feature (HB_TAG('c','l','i','g')); + for (; i < INDIC_NUM_FEATURES; i++) + map->add_feature (indic_features[i]); + + map->enable_feature (HB_TAG('c','a','l','t')); + map->enable_feature (HB_TAG('c','l','i','g')); map->add_gsub_pause (clear_syllables); } @@ -217,7 +218,7 @@ collect_features_indic (hb_ot_shape_planner_t *plan) static void override_features_indic (hb_ot_shape_planner_t *plan) { - plan->map.add_feature (HB_TAG('l','i','g','a'), 0, F_GLOBAL); + plan->map.disable_feature (HB_TAG('l','i','g','a')); } @@ -273,6 +274,7 @@ struct indic_shape_plan_t const indic_config_t *config; bool is_old_spec; + bool uniscribe_bug_compatible; mutable hb_atomic_int_t virama_glyph; would_substitute_feature_t rphf; @@ -298,6 +300,7 @@ data_create_indic (const hb_ot_shape_plan_t *plan) } indic_plan->is_old_spec = indic_plan->config->has_old_spec && ((plan->map.chosen_script[0] & 0x000000FFu) != '2'); + indic_plan->uniscribe_bug_compatible = hb_options ().uniscribe_bug_compatible; indic_plan->virama_glyph.set_relaxed (-1); /* Use zero-context would_substitute() matching for new-spec of the main @@ -328,6 +331,275 @@ data_destroy_indic (void *data) free (data); } +static void +_output_with_dotted_circle (hb_buffer_t *buffer) +{ + hb_glyph_info_t &dottedcircle = buffer->output_glyph (0x25CCu); + _hb_glyph_info_reset_continuation (&dottedcircle); + + buffer->next_glyph (); +} + +static void +preprocess_text_indic (const hb_ot_shape_plan_t *plan, + hb_buffer_t *buffer, + hb_font_t *font) +{ + /* UGLY UGLY UGLY business of adding dotted-circle in the middle of + * vowel-sequences that look like another vowel. Data for each script + * collected from Unicode 11 book, tables named "Vowel Letters" with + * "Use" and "Do Not Use" columns. + * + * https://github.com/harfbuzz/harfbuzz/issues/1019 + */ + bool processed = false; + buffer->clear_output (); + unsigned int count = buffer->len; + switch ((unsigned) buffer->props.script) + { + case HB_SCRIPT_DEVANAGARI: + for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;) + { + bool matched = false; + switch (buffer->cur().codepoint) + { + case 0x0905u: + switch (buffer->cur(1).codepoint) + { + case 0x093Au: case 0x093Bu: case 0x093Eu: case 0x0945u: + case 0x0946u: case 0x0949u: case 0x094Au: case 0x094Bu: + case 0x094Cu: case 0x094Fu: case 0x0956u: case 0x0957u: + matched = true; + break; + } + break; + case 0x0906u: + switch (buffer->cur(1).codepoint) + { + case 0x093Au: case 0x0945u: case 0x0946u: case 0x0947u: + case 0x0948u: + matched = true; + break; + } + break; + case 0x0909u: + switch (buffer->cur(1).codepoint) + { + case 0x0941u: + matched = true; + break; + } + break; + case 0x090Fu: + switch (buffer->cur(1).codepoint) + { + case 0x0945u: case 0x0946u: case 0x0947u: + matched = true; + break; + } + break; + case 0x0930u: + if (0x094Du == buffer->cur(1).codepoint && + buffer->idx + 2 < count && + 0x0907u == buffer->cur(2).codepoint) + { + buffer->next_glyph (); + buffer->next_glyph (); + buffer->output_glyph (0x25CCu); + } + break; + } + buffer->next_glyph (); + if (matched) _output_with_dotted_circle (buffer); + } + processed = true; + break; + + case HB_SCRIPT_BENGALI: + for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;) + { + bool matched = false; + switch (buffer->cur().codepoint) + { + case 0x0985u: + matched = 0x09BE == buffer->cur(1).codepoint; + break; + case 0x098Bu: + matched = 0x09C3 == buffer->cur(1).codepoint; + break; + case 0x098Cu: + matched = 0x09E2 == buffer->cur(1).codepoint; + break; + } + buffer->next_glyph (); + if (matched) _output_with_dotted_circle (buffer); + } + processed = true; + break; + + case HB_SCRIPT_GURMUKHI: + for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;) + { + bool matched = false; + switch (buffer->cur().codepoint) + { + case 0x0A05u: + switch (buffer->cur(1).codepoint) + { + case 0x0A3Eu: case 0x0A48u: case 0x0A4Cu: + matched = true; + break; + } + break; + case 0x0A72u: + switch (buffer->cur(1).codepoint) + { + case 0x0A3Fu: case 0x0A40u: case 0x0A47u: + matched = true; + break; + } + break; + case 0x0A73u: + switch (buffer->cur(1).codepoint) + { + case 0x0A41u: case 0x0A42u: case 0x0A4Bu: + matched = true; + break; + } + break; + } + buffer->next_glyph (); + if (matched) _output_with_dotted_circle (buffer); + } + processed = true; + break; + + case HB_SCRIPT_GUJARATI: + for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;) + { + bool matched = false; + switch (buffer->cur().codepoint) + { + case 0x0A85u: + switch (buffer->cur(1).codepoint) + { + case 0x0ABEu: case 0x0AC5u: case 0x0AC7u: case 0x0AC8u: + case 0x0AC9u: case 0x0ACBu: case 0x0ACCu: + matched = true; + break; + } + break; + case 0x0AC5u: + matched = 0x0ABE == buffer->cur(1).codepoint; + break; + } + buffer->next_glyph (); + if (matched) _output_with_dotted_circle (buffer); + } + processed = true; + break; + + case HB_SCRIPT_ORIYA: + for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;) + { + bool matched = false; + switch (buffer->cur().codepoint) + { + case 0x0B05u: + matched = 0x0B3E == buffer->cur(1).codepoint; + break; + case 0x0B0Fu: case 0x0B13u: + matched = 0x0B57 == buffer->cur(1).codepoint; + break; + } + buffer->next_glyph (); + if (matched) _output_with_dotted_circle (buffer); + } + processed = true; + break; + + case HB_SCRIPT_TELUGU: + for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;) + { + bool matched = false; + switch (buffer->cur().codepoint) + { + case 0x0C12u: + switch (buffer->cur(1).codepoint) + { + case 0x0C4Cu: case 0x0C55u: + matched = true; + break; + } + break; + case 0x0C3Fu: case 0x0C46u: case 0xC4Au: + matched = 0x0C55 == buffer->cur(1).codepoint; + break; + } + buffer->next_glyph (); + if (matched) _output_with_dotted_circle (buffer); + } + processed = true; + break; + + case HB_SCRIPT_KANNADA: + for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;) + { + bool matched = false; + switch (buffer->cur().codepoint) + { + case 0x0C89u: case 0x0C8Bu: + matched = 0x0CBE == buffer->cur(1).codepoint; + break; + case 0x0C92u: + matched = 0x0CCC == buffer->cur(1).codepoint; + break; + } + buffer->next_glyph (); + if (matched) _output_with_dotted_circle (buffer); + } + processed = true; + break; + + case HB_SCRIPT_MALAYALAM: + for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;) + { + bool matched = false; + switch (buffer->cur().codepoint) + { + case 0x0D07u: case 0x0D09u: + matched = 0x0D57 == buffer->cur(1).codepoint; + break; + case 0x0D0Eu: + matched = 0x0D46 == buffer->cur(1).codepoint; + break; + case 0x0D12u: + switch (buffer->cur(1).codepoint) + { + case 0x0D3Eu: case 0x0D57u: + matched = true; + break; + } + break; + } + buffer->next_glyph (); + if (matched) _output_with_dotted_circle (buffer); + } + processed = true; + break; + + default: + break; + } + if (processed) + { + if (buffer->idx < count) + buffer->next_glyph (); + if (likely (buffer->successful)) + buffer->swap_buffers (); + } +} + static indic_position_t consonant_position_from_face (const indic_shape_plan_t *indic_plan, const hb_codepoint_t consonant, @@ -717,7 +989,7 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, indic_position_t last_pos = POS_START; for (unsigned int i = start; i < end; i++) { - if ((FLAG_UNSAFE (info[i].indic_category()) & (JOINER_FLAGS | FLAG (OT_N) | FLAG (OT_RS) | MEDIAL_FLAGS | FLAG (OT_H)))) + if ((FLAG_UNSAFE (info[i].indic_category()) & (JOINER_FLAGS | FLAG (OT_N) | FLAG (OT_RS) | FLAG (OT_H)))) { info[i].indic_position() = last_pos; if (unlikely (info[i].indic_category() == OT_H && @@ -913,10 +1185,12 @@ initial_reordering_standalone_cluster (const hb_ot_shape_plan_t *plan, hb_buffer_t *buffer, unsigned int start, unsigned int end) { + const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data; + /* We treat placeholder/dotted-circle as if they are consonants, so we * should just chain. Only if not in compatibility mode that is... */ - if (hb_options ().uniscribe_bug_compatible) + if (indic_plan->uniscribe_bug_compatible) { /* For dotted-circle, this is what Uniscribe does: * If dotted-circle is the last glyph, it just does nothing. @@ -958,7 +1232,8 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED, hb_font_t *font, hb_buffer_t *buffer) { - /* Note: This loop is extra overhead, but should not be measurable. */ + /* Note: This loop is extra overhead, but should not be measurable. + * TODO Use a buffer scratch flag to remove the loop. */ bool has_broken_syllables = false; unsigned int count = buffer->len; hb_glyph_info_t *info = buffer->info; @@ -1356,7 +1631,7 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan, * Uniscribe doesn't do this. * TEST: U+0930,U+094D,U+0915,U+094B,U+094D */ - if (!hb_options ().uniscribe_bug_compatible && + if (!indic_plan->uniscribe_bug_compatible && unlikely (is_halant (info[new_reph_pos]))) { for (unsigned int i = base + 1; i < new_reph_pos; i++) if (info[i].indic_category() == OT_M) { @@ -1462,7 +1737,7 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan, /* * Finish off the clusters and go home! */ - if (hb_options ().uniscribe_bug_compatible) + if (indic_plan->uniscribe_bug_compatible) { switch ((hb_tag_t) plan->props.script) { @@ -1609,13 +1884,13 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_indic = override_features_indic, data_create_indic, data_destroy_indic, - nullptr, /* preprocess_text */ + preprocess_text_indic, nullptr, /* postprocess_glyphs */ HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT, decompose_indic, compose_indic, setup_masks_indic, - nullptr, /* disable_otl */ + HB_TAG_NONE, /* gpos_tag */ nullptr, /* reorder_marks */ HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE, false, /* fallback_position */ diff --git a/src/hb-ot-shape-complex-indic-private.hh b/src/hb-ot-shape-complex-indic.hh index bb7fff384..dcc2a7a6c 100644 --- a/src/hb-ot-shape-complex-indic-private.hh +++ b/src/hb-ot-shape-complex-indic.hh @@ -24,14 +24,12 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_OT_SHAPE_COMPLEX_INDIC_PRIVATE_HH -#define HB_OT_SHAPE_COMPLEX_INDIC_PRIVATE_HH +#ifndef HB_OT_SHAPE_COMPLEX_INDIC_HH +#define HB_OT_SHAPE_COMPLEX_INDIC_HH -#include "hb-private.hh" +#include "hb.hh" - -#include "hb-ot-shape-complex-private.hh" -#include "hb-ot-shape-private.hh" /* XXX Remove */ +#include "hb-ot-shape-complex.hh" /* buffer var allocations */ @@ -64,19 +62,17 @@ enum indic_category_t { OT_Coeng = 14, /* Khmer-style Virama. */ OT_Repha = 15, /* Atomically-encoded logical or visual repha. */ OT_Ra = 16, - OT_CM = 17, /* Consonant-Medial. */ + OT_CM = 17, /* Consonant-Medial; Unused by Indic shaper. */ OT_Symbol = 18, /* Avagraha, etc that take marks (SM,A,VD). */ OT_CS = 19 }; -#define MEDIAL_FLAGS (FLAG (OT_CM)) - /* Note: * * We treat Vowels and placeholders as if they were consonants. This is safe because Vowels * cannot happen in a consonant syllable. The plus side however is, we can call the * consonant syllable logic from the vowel syllable function and get it all right! */ -#define CONSONANT_FLAGS (FLAG (OT_C) | FLAG (OT_CS) | FLAG (OT_Ra) | MEDIAL_FLAGS | FLAG (OT_V) | FLAG (OT_PLACEHOLDER) | FLAG (OT_DOTTEDCIRCLE)) +#define CONSONANT_FLAGS (FLAG (OT_C) | FLAG (OT_CS) | FLAG (OT_Ra) | FLAG (OT_V) | FLAG (OT_PLACEHOLDER) | FLAG (OT_DOTTEDCIRCLE)) #define JOINER_FLAGS (FLAG (OT_ZWJ) | FLAG (OT_ZWNJ)) @@ -125,7 +121,7 @@ enum indic_syllabic_category_t { INDIC_SYLLABIC_CATEGORY_CONSONANT_PRECEDING_REPHA = OT_Repha, INDIC_SYLLABIC_CATEGORY_CONSONANT_PREFIXED = OT_X, /* Don't care. */ INDIC_SYLLABIC_CATEGORY_CONSONANT_SUBJOINED = OT_CM, - INDIC_SYLLABIC_CATEGORY_CONSONANT_SUCCEEDING_REPHA = OT_N, + INDIC_SYLLABIC_CATEGORY_CONSONANT_SUCCEEDING_REPHA = OT_CM, INDIC_SYLLABIC_CATEGORY_CONSONANT_WITH_STACKER = OT_CS, INDIC_SYLLABIC_CATEGORY_GEMINATION_MARK = OT_SM, /* https://github.com/harfbuzz/harfbuzz/issues/552 */ INDIC_SYLLABIC_CATEGORY_INVISIBLE_STACKER = OT_Coeng, @@ -400,4 +396,4 @@ set_indic_properties (hb_glyph_info_t &info) } -#endif /* HB_OT_SHAPE_COMPLEX_INDIC_PRIVATE_HH */ +#endif /* HB_OT_SHAPE_COMPLEX_INDIC_HH */ diff --git a/src/hb-ot-shape-complex-khmer-machine.hh b/src/hb-ot-shape-complex-khmer-machine.hh index d00102156..2bc8ca650 100644 --- a/src/hb-ot-shape-complex-khmer-machine.hh +++ b/src/hb-ot-shape-complex-khmer-machine.hh @@ -29,143 +29,212 @@ #ifndef HB_OT_SHAPE_COMPLEX_KHMER_MACHINE_HH #define HB_OT_SHAPE_COMPLEX_KHMER_MACHINE_HH -#include "hb-private.hh" +#include "hb.hh" #line 36 "hb-ot-shape-complex-khmer-machine.hh" static const unsigned char _khmer_syllable_machine_trans_keys[] = { - 7u, 7u, 1u, 16u, 13u, 13u, 1u, 16u, 7u, 13u, 7u, 7u, 1u, 16u, 13u, 13u, - 1u, 16u, 7u, 13u, 1u, 16u, 3u, 14u, 3u, 14u, 5u, 14u, 3u, 14u, 5u, 14u, - 8u, 8u, 3u, 13u, 3u, 8u, 8u, 8u, 3u, 8u, 3u, 14u, 3u, 14u, 5u, 14u, - 3u, 14u, 5u, 14u, 8u, 8u, 3u, 13u, 3u, 8u, 8u, 8u, 3u, 8u, 3u, 14u, - 3u, 14u, 7u, 13u, 7u, 7u, 1u, 16u, 0 + 5u, 26u, 5u, 21u, 5u, 26u, 5u, 21u, 1u, 16u, 5u, 21u, 5u, 26u, 5u, 21u, + 5u, 26u, 5u, 21u, 1u, 16u, 5u, 21u, 5u, 26u, 5u, 21u, 1u, 16u, 5u, 21u, + 5u, 26u, 5u, 21u, 5u, 26u, 5u, 21u, 5u, 26u, 1u, 16u, 1u, 29u, 5u, 29u, + 5u, 29u, 5u, 29u, 22u, 22u, 5u, 22u, 5u, 29u, 5u, 29u, 5u, 29u, 5u, 26u, + 5u, 29u, 5u, 29u, 22u, 22u, 5u, 22u, 5u, 29u, 5u, 29u, 1u, 16u, 5u, 29u, + 5u, 29u, 0 }; static const char _khmer_syllable_machine_key_spans[] = { - 1, 16, 1, 16, 7, 1, 16, 1, - 16, 7, 16, 12, 12, 10, 12, 10, - 1, 11, 6, 1, 6, 12, 12, 10, - 12, 10, 1, 11, 6, 1, 6, 12, - 12, 7, 1, 16 + 22, 17, 22, 17, 16, 17, 22, 17, + 22, 17, 16, 17, 22, 17, 16, 17, + 22, 17, 22, 17, 22, 16, 29, 25, + 25, 25, 1, 18, 25, 25, 25, 22, + 25, 25, 1, 18, 25, 25, 16, 25, + 25 }; static const short _khmer_syllable_machine_index_offsets[] = { - 0, 2, 19, 21, 38, 46, 48, 65, - 67, 84, 92, 109, 122, 135, 146, 159, - 170, 172, 184, 191, 193, 200, 213, 226, - 237, 250, 261, 263, 275, 282, 284, 291, - 304, 317, 325, 327 + 0, 23, 41, 64, 82, 99, 117, 140, + 158, 181, 199, 216, 234, 257, 275, 292, + 310, 333, 351, 374, 392, 415, 432, 462, + 488, 514, 540, 542, 561, 587, 613, 639, + 662, 688, 714, 716, 735, 761, 787, 804, + 830 }; static const char _khmer_syllable_machine_indicies[] = { - 1, 0, 2, 2, 0, 0, 0, 0, + 1, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 2, + 3, 0, 0, 0, 0, 4, 0, 1, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 3, + 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 2, 0, 3, 0, 4, 4, 0, + 0, 3, 0, 0, 0, 0, 4, 0, + 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 4, 0, 1, 0, - 0, 0, 0, 0, 5, 0, 7, 6, - 8, 8, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 8, - 6, 9, 6, 10, 10, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 10, 6, 7, 6, 6, 6, - 6, 6, 11, 6, 4, 4, 13, 12, - 14, 15, 7, 16, 12, 12, 4, 4, - 11, 17, 12, 4, 12, 19, 18, 20, - 21, 1, 22, 18, 18, 18, 18, 5, - 23, 18, 24, 18, 21, 21, 1, 22, - 18, 18, 18, 18, 18, 23, 18, 21, - 21, 1, 22, 18, 18, 18, 18, 18, - 23, 18, 25, 18, 21, 21, 1, 22, - 18, 18, 18, 18, 18, 26, 18, 21, - 21, 1, 22, 18, 18, 18, 18, 18, - 26, 18, 27, 18, 28, 18, 29, 18, - 18, 22, 18, 18, 18, 18, 3, 18, - 30, 18, 18, 18, 18, 22, 18, 22, - 18, 28, 18, 18, 18, 18, 22, 18, - 19, 18, 21, 21, 1, 22, 18, 18, - 18, 18, 18, 23, 18, 32, 31, 33, - 33, 7, 16, 31, 31, 31, 31, 31, - 34, 31, 33, 33, 7, 16, 31, 31, - 31, 31, 31, 34, 31, 35, 31, 33, - 33, 7, 16, 31, 31, 31, 31, 31, - 36, 31, 33, 33, 7, 16, 31, 31, - 31, 31, 31, 36, 31, 37, 31, 38, - 31, 39, 31, 31, 16, 31, 31, 31, - 31, 9, 31, 40, 31, 31, 31, 31, - 16, 31, 16, 31, 38, 31, 31, 31, - 31, 16, 31, 13, 31, 41, 33, 7, - 16, 31, 31, 31, 31, 11, 34, 31, - 13, 31, 33, 33, 7, 16, 31, 31, - 31, 31, 31, 34, 31, 7, 42, 42, - 42, 42, 42, 11, 42, 7, 42, 10, - 10, 42, 42, 42, 42, 42, 42, 42, - 42, 42, 42, 42, 42, 42, 10, 42, + 4, 0, 6, 6, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 6, 0, 7, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 8, 0, 9, 9, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 10, 0, 0, + 0, 0, 4, 0, 9, 9, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 10, 0, 11, 11, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 12, 0, + 0, 0, 0, 4, 0, 11, 11, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 12, 0, 13, + 13, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 13, 0, + 15, 15, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 16, 14, 15, 15, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 16, 17, 17, 17, 17, 18, + 17, 19, 19, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 18, 17, 20, 20, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 20, 17, 21, 21, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 22, 17, 23, 23, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 24, 17, + 17, 17, 17, 18, 17, 23, 23, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 24, 17, 25, + 25, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 26, + 17, 17, 17, 17, 18, 17, 25, 25, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 26, 17, + 15, 15, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 27, + 16, 17, 17, 17, 17, 18, 17, 28, + 28, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 28, 17, + 13, 13, 29, 29, 30, 30, 29, 29, + 29, 29, 2, 2, 29, 31, 29, 13, + 29, 29, 29, 29, 16, 20, 29, 29, + 29, 18, 24, 26, 22, 29, 33, 33, + 32, 32, 32, 32, 32, 32, 32, 34, + 32, 32, 32, 32, 32, 2, 3, 6, + 32, 32, 32, 4, 10, 12, 8, 32, + 35, 35, 32, 32, 32, 32, 32, 32, + 32, 36, 32, 32, 32, 32, 32, 32, + 3, 6, 32, 32, 32, 4, 10, 12, + 8, 32, 5, 5, 32, 32, 32, 32, + 32, 32, 32, 36, 32, 32, 32, 32, + 32, 32, 4, 6, 32, 32, 32, 32, + 32, 32, 8, 32, 6, 32, 7, 7, + 32, 32, 32, 32, 32, 32, 32, 36, + 32, 32, 32, 32, 32, 32, 8, 6, + 32, 37, 37, 32, 32, 32, 32, 32, + 32, 32, 36, 32, 32, 32, 32, 32, + 32, 10, 6, 32, 32, 32, 4, 32, + 32, 8, 32, 38, 38, 32, 32, 32, + 32, 32, 32, 32, 36, 32, 32, 32, + 32, 32, 32, 12, 6, 32, 32, 32, + 4, 10, 32, 8, 32, 35, 35, 32, + 32, 32, 32, 32, 32, 32, 34, 32, + 32, 32, 32, 32, 32, 3, 6, 32, + 32, 32, 4, 10, 12, 8, 32, 15, + 15, 39, 39, 39, 39, 39, 39, 39, + 39, 39, 39, 39, 39, 39, 39, 16, + 39, 39, 39, 39, 18, 39, 41, 41, + 40, 40, 40, 40, 40, 40, 40, 42, + 40, 40, 40, 40, 40, 40, 16, 20, + 40, 40, 40, 18, 24, 26, 22, 40, + 19, 19, 40, 40, 40, 40, 40, 40, + 40, 42, 40, 40, 40, 40, 40, 40, + 18, 20, 40, 40, 40, 40, 40, 40, + 22, 40, 20, 40, 21, 21, 40, 40, + 40, 40, 40, 40, 40, 42, 40, 40, + 40, 40, 40, 40, 22, 20, 40, 43, + 43, 40, 40, 40, 40, 40, 40, 40, + 42, 40, 40, 40, 40, 40, 40, 24, + 20, 40, 40, 40, 18, 40, 40, 22, + 40, 44, 44, 40, 40, 40, 40, 40, + 40, 40, 42, 40, 40, 40, 40, 40, + 40, 26, 20, 40, 40, 40, 18, 24, + 40, 22, 40, 28, 28, 39, 39, 39, + 39, 39, 39, 39, 39, 39, 39, 39, + 39, 39, 28, 39, 45, 45, 40, 40, + 40, 40, 40, 40, 40, 46, 40, 40, + 40, 40, 40, 27, 16, 20, 40, 40, + 40, 18, 24, 26, 22, 40, 41, 41, + 40, 40, 40, 40, 40, 40, 40, 46, + 40, 40, 40, 40, 40, 40, 16, 20, + 40, 40, 40, 18, 24, 26, 22, 40, 0 }; static const char _khmer_syllable_machine_trans_targs[] = { - 10, 14, 17, 20, 11, 21, 10, 24, - 27, 30, 31, 32, 10, 22, 33, 34, - 26, 35, 10, 12, 4, 0, 16, 3, - 13, 15, 1, 10, 18, 2, 19, 10, - 23, 5, 8, 25, 6, 10, 28, 7, - 29, 9, 10 + 22, 1, 30, 24, 25, 3, 26, 5, + 27, 7, 28, 9, 29, 23, 22, 11, + 32, 22, 33, 13, 34, 15, 35, 17, + 36, 19, 37, 40, 39, 22, 31, 38, + 22, 0, 10, 2, 4, 6, 8, 22, + 22, 12, 14, 16, 18, 20, 21 }; static const char _khmer_syllable_machine_trans_actions[] = { - 1, 2, 2, 0, 2, 2, 3, 2, - 2, 0, 2, 2, 6, 2, 0, 0, - 0, 0, 7, 2, 0, 0, 0, 0, - 2, 2, 0, 8, 0, 0, 0, 9, - 2, 0, 0, 2, 0, 10, 0, 0, - 0, 0, 11 + 1, 0, 2, 2, 2, 0, 0, 0, + 2, 0, 2, 0, 2, 2, 3, 0, + 4, 5, 2, 0, 0, 0, 2, 0, + 2, 0, 2, 4, 4, 8, 9, 0, + 10, 0, 0, 0, 0, 0, 0, 11, + 12, 0, 0, 0, 0, 0, 0 }; static const char _khmer_syllable_machine_to_state_actions[] = { 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, + 0 }; static const char _khmer_syllable_machine_from_state_actions[] = { 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 5, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0 + 0 }; static const unsigned char _khmer_syllable_machine_eof_trans[] = { - 1, 1, 1, 1, 1, 7, 7, 7, - 7, 7, 0, 19, 19, 19, 19, 19, - 19, 19, 19, 19, 19, 19, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, - 32, 43, 43, 43 + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 15, 18, 18, 18, 18, + 18, 18, 18, 18, 18, 18, 0, 33, + 33, 33, 33, 33, 33, 33, 33, 40, + 41, 41, 41, 41, 41, 41, 40, 41, + 41 }; -static const int khmer_syllable_machine_start = 10; -static const int khmer_syllable_machine_first_final = 10; +static const int khmer_syllable_machine_start = 22; +static const int khmer_syllable_machine_first_final = 22; static const int khmer_syllable_machine_error = -1; -static const int khmer_syllable_machine_en_main = 10; +static const int khmer_syllable_machine_en_main = 22; #line 36 "hb-ot-shape-complex-khmer-machine.rl" -#line 74 "hb-ot-shape-complex-khmer-machine.rl" +#line 80 "hb-ot-shape-complex-khmer-machine.rl" #define found_syllable(syllable_type) \ HB_STMT_START { \ - if (0) fprintf (stderr, "syllable %d..%d %s\n", last, p+1, #syllable_type); \ - for (unsigned int i = last; i < p+1; i++) \ + if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \ + for (unsigned int i = ts; i < te; i++) \ info[i].syllable() = (syllable_serial << 4) | syllable_type; \ - last = p+1; \ syllable_serial++; \ if (unlikely (syllable_serial == 16)) syllable_serial = 1; \ } HB_STMT_END @@ -173,11 +242,11 @@ static const int khmer_syllable_machine_en_main = 10; static void find_syllables (hb_buffer_t *buffer) { - unsigned int p, pe, eof, ts HB_UNUSED, te, act HB_UNUSED; + unsigned int p, pe, eof, ts, te, act HB_UNUSED; int cs; hb_glyph_info_t *info = buffer->info; -#line 181 "hb-ot-shape-complex-khmer-machine.hh" +#line 250 "hb-ot-shape-complex-khmer-machine.hh" { cs = khmer_syllable_machine_start; ts = 0; @@ -185,16 +254,15 @@ find_syllables (hb_buffer_t *buffer) act = 0; } -#line 95 "hb-ot-shape-complex-khmer-machine.rl" +#line 100 "hb-ot-shape-complex-khmer-machine.rl" p = 0; pe = eof = buffer->len; - unsigned int last = 0; unsigned int syllable_serial = 1; -#line 198 "hb-ot-shape-complex-khmer-machine.hh" +#line 266 "hb-ot-shape-complex-khmer-machine.hh" { int _slen; int _trans; @@ -204,11 +272,11 @@ find_syllables (hb_buffer_t *buffer) goto _test_eof; _resume: switch ( _khmer_syllable_machine_from_state_actions[cs] ) { - case 5: + case 7: #line 1 "NONE" {ts = p;} break; -#line 212 "hb-ot-shape-complex-khmer-machine.hh" +#line 280 "hb-ot-shape-complex-khmer-machine.hh" } _keys = _khmer_syllable_machine_trans_keys + (cs<<1); @@ -231,47 +299,63 @@ _eof_trans: {te = p+1;} break; case 8: -#line 68 "hb-ot-shape-complex-khmer-machine.rl" - {te = p+1;{ found_syllable (consonant_syllable); }} - break; - case 10: -#line 69 "hb-ot-shape-complex-khmer-machine.rl" - {te = p+1;{ found_syllable (broken_cluster); }} - break; - case 6: -#line 70 "hb-ot-shape-complex-khmer-machine.rl" +#line 76 "hb-ot-shape-complex-khmer-machine.rl" {te = p+1;{ found_syllable (non_khmer_cluster); }} break; - case 7: -#line 68 "hb-ot-shape-complex-khmer-machine.rl" + case 10: +#line 74 "hb-ot-shape-complex-khmer-machine.rl" {te = p;p--;{ found_syllable (consonant_syllable); }} break; - case 9: -#line 69 "hb-ot-shape-complex-khmer-machine.rl" + case 12: +#line 75 "hb-ot-shape-complex-khmer-machine.rl" {te = p;p--;{ found_syllable (broken_cluster); }} break; case 11: -#line 70 "hb-ot-shape-complex-khmer-machine.rl" +#line 76 "hb-ot-shape-complex-khmer-machine.rl" {te = p;p--;{ found_syllable (non_khmer_cluster); }} break; case 1: -#line 68 "hb-ot-shape-complex-khmer-machine.rl" +#line 74 "hb-ot-shape-complex-khmer-machine.rl" {{p = ((te))-1;}{ found_syllable (consonant_syllable); }} break; - case 3: -#line 69 "hb-ot-shape-complex-khmer-machine.rl" + case 5: +#line 75 "hb-ot-shape-complex-khmer-machine.rl" {{p = ((te))-1;}{ found_syllable (broken_cluster); }} break; -#line 266 "hb-ot-shape-complex-khmer-machine.hh" + case 3: +#line 1 "NONE" + { switch( act ) { + case 2: + {{p = ((te))-1;} found_syllable (broken_cluster); } + break; + case 3: + {{p = ((te))-1;} found_syllable (non_khmer_cluster); } + break; + } + } + break; + case 4: +#line 1 "NONE" + {te = p+1;} +#line 75 "hb-ot-shape-complex-khmer-machine.rl" + {act = 2;} + break; + case 9: +#line 1 "NONE" + {te = p+1;} +#line 76 "hb-ot-shape-complex-khmer-machine.rl" + {act = 3;} + break; +#line 350 "hb-ot-shape-complex-khmer-machine.hh" } _again: switch ( _khmer_syllable_machine_to_state_actions[cs] ) { - case 4: + case 6: #line 1 "NONE" {ts = 0;} break; -#line 275 "hb-ot-shape-complex-khmer-machine.hh" +#line 359 "hb-ot-shape-complex-khmer-machine.hh" } if ( ++p != pe ) @@ -287,7 +371,7 @@ _again: } -#line 104 "hb-ot-shape-complex-khmer-machine.rl" +#line 108 "hb-ot-shape-complex-khmer-machine.rl" } diff --git a/src/hb-ot-shape-complex-khmer-machine.rl b/src/hb-ot-shape-complex-khmer-machine.rl index 54644d8aa..4c596ab64 100644 --- a/src/hb-ot-shape-complex-khmer-machine.rl +++ b/src/hb-ot-shape-complex-khmer-machine.rl @@ -27,7 +27,7 @@ #ifndef HB_OT_SHAPE_COMPLEX_KHMER_MACHINE_HH #define HB_OT_SHAPE_COMPLEX_KHMER_MACHINE_HH -#include "hb-private.hh" +#include "hb.hh" %%{ machine khmer_syllable_machine; @@ -40,28 +40,34 @@ # Same order as enum khmer_category_t. Not sure how to avoid duplication. C = 1; V = 2; -N = 3; ZWNJ = 5; ZWJ = 6; -M = 7; -SM = 8; PLACEHOLDER = 11; DOTTEDCIRCLE = 12; -RS = 13; -Coeng = 14; -Ra = 16; - -c = (C | Ra | V); # is_consonant -n = ((ZWNJ?.RS)? (N.N?)?); # is_consonant_modifier -z = ZWJ|ZWNJ; # is_joiner - -cn = c.n?; -matra_group = z?.M.N?; -syllable_tail = (SM.SM?)?; - - -broken_cluster = n? (Coeng.cn)* matra_group* (Coeng.cn)? syllable_tail; -consonant_syllable = (c|PLACEHOLDER|DOTTEDCIRCLE) broken_cluster; +Coeng= 14; +Ra = 16; +Robatic = 20; +Xgroup = 21; +Ygroup = 22; +VAbv = 26; +VBlw = 27; +VPre = 28; +VPst = 29; + +c = (C | Ra | V); +cn = c.((ZWJ|ZWNJ)?.Robatic)?; +joiner = (ZWJ | ZWNJ); +xgroup = (joiner*.Xgroup)*; +ygroup = Ygroup*; + +# This grammar was experimentally extracted from what Uniscribe allows. + +matra_group = VPre? xgroup VBlw? xgroup (joiner?.VAbv)? xgroup VPst?; +syllable_tail = xgroup matra_group xgroup (Coeng.c)? ygroup; + + +broken_cluster = (Coeng.cn)* syllable_tail; +consonant_syllable = (cn|PLACEHOLDER|DOTTEDCIRCLE) broken_cluster; other = any; main := |* @@ -75,10 +81,9 @@ main := |* #define found_syllable(syllable_type) \ HB_STMT_START { \ - if (0) fprintf (stderr, "syllable %d..%d %s\n", last, p+1, #syllable_type); \ - for (unsigned int i = last; i < p+1; i++) \ + if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \ + for (unsigned int i = ts; i < te; i++) \ info[i].syllable() = (syllable_serial << 4) | syllable_type; \ - last = p+1; \ syllable_serial++; \ if (unlikely (syllable_serial == 16)) syllable_serial = 1; \ } HB_STMT_END @@ -86,7 +91,7 @@ main := |* static void find_syllables (hb_buffer_t *buffer) { - unsigned int p, pe, eof, ts HB_UNUSED, te, act HB_UNUSED; + unsigned int p, pe, eof, ts, te, act HB_UNUSED; int cs; hb_glyph_info_t *info = buffer->info; %%{ @@ -97,7 +102,6 @@ find_syllables (hb_buffer_t *buffer) p = 0; pe = eof = buffer->len; - unsigned int last = 0; unsigned int syllable_serial = 1; %%{ write exec; diff --git a/src/hb-ot-shape-complex-khmer-private.hh b/src/hb-ot-shape-complex-khmer-private.hh deleted file mode 100644 index f90ef9674..000000000 --- a/src/hb-ot-shape-complex-khmer-private.hh +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright © 2018 Google, Inc. - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Google Author(s): Behdad Esfahbod - */ - -#ifndef HB_OT_SHAPE_COMPLEX_KHMER_PRIVATE_HH -#define HB_OT_SHAPE_COMPLEX_KHMER_PRIVATE_HH - -#include "hb-private.hh" - -#include "hb-ot-shape-complex-indic-private.hh" - - -/* buffer var allocations */ -#define khmer_category() indic_category() /* khmer_category_t */ -#define khmer_position() indic_position() /* khmer_position_t */ - - -typedef indic_category_t khmer_category_t; -typedef indic_position_t khmer_position_t; - - -static inline khmer_position_t -matra_position_khmer (khmer_position_t side) -{ - switch ((int) side) - { - case POS_PRE_C: - return POS_PRE_M; - - case POS_POST_C: - case POS_ABOVE_C: - case POS_BELOW_C: - return POS_AFTER_POST; - - default: - return side; - }; -} - -static inline bool -is_consonant_or_vowel (const hb_glyph_info_t &info) -{ - return is_one_of (info, CONSONANT_FLAGS | FLAG (OT_V)); -} - -static inline bool -is_coeng (const hb_glyph_info_t &info) -{ - return is_one_of (info, FLAG (OT_Coeng)); -} - -static inline void -set_khmer_properties (hb_glyph_info_t &info) -{ - hb_codepoint_t u = info.codepoint; - unsigned int type = hb_indic_get_categories (u); - khmer_category_t cat = (khmer_category_t) (type & 0x7Fu); - khmer_position_t pos = (khmer_position_t) (type >> 8); - - - /* - * Re-assign category - */ - - if (unlikely (u == 0x17C6u)) cat = OT_N; /* Khmer Bindu doesn't like to be repositioned. */ - else if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x17CDu, 0x17D1u) || - u == 0x17CBu || u == 0x17D3u || u == 0x17DDu)) /* Khmer Various signs */ - { - /* These can occur mid-syllable (eg. before matras), even though Unicode marks them as Syllable_Modifier. - * https://github.com/roozbehp/unicode-data/issues/5 */ - cat = OT_M; - pos = POS_ABOVE_C; - } - else if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x2010u, 0x2011u))) cat = OT_PLACEHOLDER; - else if (unlikely (u == 0x25CCu)) cat = OT_DOTTEDCIRCLE; - - - /* - * Re-assign position. - */ - - if ((FLAG_UNSAFE (cat) & CONSONANT_FLAGS)) - { - pos = POS_BASE_C; - if (u == 0x179Au) - cat = OT_Ra; - } - else if (cat == OT_M) - { - pos = matra_position_khmer (pos); - } - else if ((FLAG_UNSAFE (cat) & (FLAG (OT_SM) | FLAG (OT_A) | FLAG (OT_Symbol)))) - { - pos = POS_SMVD; - } - - info.khmer_category() = cat; - info.khmer_position() = pos; -} - - -#endif /* HB_OT_SHAPE_COMPLEX_KHMER_PRIVATE_HH */ diff --git a/src/hb-ot-shape-complex-khmer.cc b/src/hb-ot-shape-complex-khmer.cc index 264515e86..88d16267b 100644 --- a/src/hb-ot-shape-complex-khmer.cc +++ b/src/hb-ot-shape-complex-khmer.cc @@ -24,40 +24,38 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-ot-shape-complex-khmer-private.hh" -#include "hb-ot-layout-private.hh" +#include "hb-ot-shape-complex-khmer.hh" +#include "hb-ot-layout.hh" /* * Khmer shaper. */ -struct feature_list_t { - hb_tag_t tag; - hb_ot_map_feature_flags_t flags; -}; - -static const feature_list_t +static const hb_ot_map_feature_t khmer_features[] = { /* * Basic features. * These features are applied in order, one at a time, after reordering. */ - {HB_TAG('p','r','e','f'), F_NONE}, - {HB_TAG('b','l','w','f'), F_NONE}, - {HB_TAG('a','b','v','f'), F_NONE}, - {HB_TAG('p','s','t','f'), F_NONE}, - {HB_TAG('c','f','a','r'), F_NONE}, + {HB_TAG('p','r','e','f'), F_MANUAL_JOINERS}, + {HB_TAG('b','l','w','f'), F_MANUAL_JOINERS}, + {HB_TAG('a','b','v','f'), F_MANUAL_JOINERS}, + {HB_TAG('p','s','t','f'), F_MANUAL_JOINERS}, + {HB_TAG('c','f','a','r'), F_MANUAL_JOINERS}, /* * Other features. * These features are applied all at once. */ - {HB_TAG('p','r','e','s'), F_GLOBAL}, - {HB_TAG('a','b','v','s'), F_GLOBAL}, - {HB_TAG('b','l','w','s'), F_GLOBAL}, - {HB_TAG('p','s','t','s'), F_GLOBAL}, - /* Positioning features, though we don't care about the types. */ + {HB_TAG('p','r','e','s'), F_GLOBAL_MANUAL_JOINERS}, + {HB_TAG('a','b','v','s'), F_GLOBAL_MANUAL_JOINERS}, + {HB_TAG('b','l','w','s'), F_GLOBAL_MANUAL_JOINERS}, + {HB_TAG('p','s','t','s'), F_GLOBAL_MANUAL_JOINERS}, + /* + * Positioning features. + * We don't care about the types. + */ {HB_TAG('d','i','s','t'), F_GLOBAL}, {HB_TAG('a','b','v','m'), F_GLOBAL}, {HB_TAG('b','l','w','m'), F_GLOBAL}, @@ -77,12 +75,13 @@ enum { _ABVS, _BLWS, _PSTS, + _DIST, _ABVM, _BLWM, KHMER_NUM_FEATURES, - KHMER_BASIC_FEATURES = _PRES /* Don't forget to update this! */ + KHMER_BASIC_FEATURES = _PRES, /* Don't forget to update this! */ }; static void @@ -117,22 +116,20 @@ collect_features_khmer (hb_ot_shape_planner_t *plan) * * https://github.com/harfbuzz/harfbuzz/issues/974 */ - map->add_global_bool_feature (HB_TAG('l','o','c','l')); - map->add_global_bool_feature (HB_TAG('c','c','m','p')); + map->enable_feature (HB_TAG('l','o','c','l')); + map->enable_feature (HB_TAG('c','c','m','p')); unsigned int i = 0; - for (; i < KHMER_BASIC_FEATURES; i++) { - map->add_feature (khmer_features[i].tag, 1, khmer_features[i].flags | F_MANUAL_ZWJ | F_MANUAL_ZWNJ); - } + for (; i < KHMER_BASIC_FEATURES; i++) + map->add_feature (khmer_features[i]); map->add_gsub_pause (clear_syllables); - for (; i < KHMER_NUM_FEATURES; i++) { - map->add_feature (khmer_features[i].tag, 1, khmer_features[i].flags | F_MANUAL_ZWJ | F_MANUAL_ZWNJ); - } + for (; i < KHMER_NUM_FEATURES; i++) + map->add_feature (khmer_features[i]); - map->add_global_bool_feature (HB_TAG('c','a','l','t')); - map->add_global_bool_feature (HB_TAG('c','l','i','g')); + map->enable_feature (HB_TAG('c','a','l','t')); + map->enable_feature (HB_TAG('c','l','i','g')); } @@ -142,10 +139,10 @@ override_features_khmer (hb_ot_shape_planner_t *plan) /* Uniscribe does not apply 'kern' in Khmer. */ if (hb_options ().uniscribe_bug_compatible) { - plan->map.add_feature (HB_TAG('k','e','r','n'), 0, F_GLOBAL); + plan->map.disable_feature (HB_TAG('k','e','r','n')); } - plan->map.add_feature (HB_TAG('l','i','g','a'), 0, F_GLOBAL); + plan->map.disable_feature (HB_TAG('l','i','g','a')); } @@ -244,7 +241,6 @@ setup_masks_khmer (const hb_ot_shape_plan_t *plan HB_UNUSED, hb_font_t *font HB_UNUSED) { HB_BUFFER_ALLOCATE_VAR (buffer, khmer_category); - HB_BUFFER_ALLOCATE_VAR (buffer, khmer_position); /* We cannot setup masks here. We save information about characters * and setup masks later on in a pause-callback. */ @@ -333,7 +329,7 @@ reorder_consonant_syllable (const hb_ot_shape_plan_t *plan, } /* Reorder left matra piece. */ - else if (info[i].khmer_position() == POS_PRE_M) + else if (info[i].khmer_category() == OT_VPre) { /* Move to the start. */ buffer->merge_clusters (start, i + 1); @@ -435,7 +431,6 @@ reorder (const hb_ot_shape_plan_t *plan, initial_reordering_syllable (plan, font->face, buffer, start, end); HB_BUFFER_DEALLOCATE_VAR (buffer, khmer_category); - HB_BUFFER_DEALLOCATE_VAR (buffer, khmer_position); } static void @@ -501,7 +496,7 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_khmer = decompose_khmer, compose_khmer, setup_masks_khmer, - nullptr, /* disable_otl */ + HB_TAG_NONE, /* gpos_tag */ nullptr, /* reorder_marks */ HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE, false, /* fallback_position */ diff --git a/src/hb-ot-shape-complex-khmer.hh b/src/hb-ot-shape-complex-khmer.hh new file mode 100644 index 000000000..622294588 --- /dev/null +++ b/src/hb-ot-shape-complex-khmer.hh @@ -0,0 +1,114 @@ +/* + * Copyright © 2018 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Behdad Esfahbod + */ + +#ifndef HB_OT_SHAPE_COMPLEX_KHMER_HH +#define HB_OT_SHAPE_COMPLEX_KHMER_HH + +#include "hb.hh" + +#include "hb-ot-shape-complex-indic.hh" + + +/* buffer var allocations */ +#define khmer_category() indic_category() /* khmer_category_t */ + + +/* Note: This enum is duplicated in the -machine.rl source file. + * Not sure how to avoid duplication. */ +enum khmer_category_t +{ + OT_Robatic = 20, + OT_Xgroup = 21, + OT_Ygroup = 22, + + OT_VAbv = 26, + OT_VBlw = 27, + OT_VPre = 28, + OT_VPst = 29, +}; + +static inline void +set_khmer_properties (hb_glyph_info_t &info) +{ + hb_codepoint_t u = info.codepoint; + unsigned int type = hb_indic_get_categories (u); + khmer_category_t cat = (khmer_category_t) (type & 0x7Fu); + indic_position_t pos = (indic_position_t) (type >> 8); + + + /* + * Re-assign category + * + * These categories are experimentally extracted from what Uniscribe allows. + */ + switch (u) + { + case 0x179Au: + cat = (khmer_category_t) OT_Ra; + break; + + case 0x17CCu: + case 0x17C9u: + case 0x17CAu: + cat = OT_Robatic; + break; + + case 0x17C6u: + case 0x17CBu: + case 0x17CDu: + case 0x17CEu: + case 0x17CFu: + case 0x17D0u: + case 0x17D1u: + cat = OT_Xgroup; + break; + + case 0x17C7u: + case 0x17C8u: + case 0x17DDu: + case 0x17D3u: /* Just guessing. Uniscribe doesn't categorize it. */ + cat = OT_Ygroup; + break; + } + + /* + * Re-assign position. + */ + if (cat == (khmer_category_t) OT_M) + switch ((int) pos) + { + case POS_PRE_C: cat = OT_VPre; break; + case POS_BELOW_C: cat = OT_VBlw; break; + case POS_ABOVE_C: cat = OT_VAbv; break; + case POS_POST_C: cat = OT_VPst; break; + default: assert (0); + }; + + info.khmer_category() = cat; +} + + +#endif /* HB_OT_SHAPE_COMPLEX_KHMER_HH */ diff --git a/src/hb-ot-shape-complex-myanmar-machine.hh b/src/hb-ot-shape-complex-myanmar-machine.hh index fb67dd42e..0c19e4f68 100644 --- a/src/hb-ot-shape-complex-myanmar-machine.hh +++ b/src/hb-ot-shape-complex-myanmar-machine.hh @@ -29,7 +29,7 @@ #ifndef HB_OT_SHAPE_COMPLEX_MYANMAR_MACHINE_HH #define HB_OT_SHAPE_COMPLEX_MYANMAR_MACHINE_HH -#include "hb-private.hh" +#include "hb.hh" #line 36 "hb-ot-shape-complex-myanmar-machine.hh" @@ -283,10 +283,9 @@ static const int myanmar_syllable_machine_en_main = 0; #define found_syllable(syllable_type) \ HB_STMT_START { \ - if (0) fprintf (stderr, "syllable %d..%d %s\n", last, p+1, #syllable_type); \ - for (unsigned int i = last; i < p+1; i++) \ + if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \ + for (unsigned int i = ts; i < te; i++) \ info[i].syllable() = (syllable_serial << 4) | syllable_type; \ - last = p+1; \ syllable_serial++; \ if (unlikely (syllable_serial == 16)) syllable_serial = 1; \ } HB_STMT_END @@ -294,11 +293,11 @@ static const int myanmar_syllable_machine_en_main = 0; static void find_syllables (hb_buffer_t *buffer) { - unsigned int p, pe, eof, ts HB_UNUSED, te HB_UNUSED, act HB_UNUSED; + unsigned int p, pe, eof, ts, te, act HB_UNUSED; int cs; hb_glyph_info_t *info = buffer->info; -#line 302 "hb-ot-shape-complex-myanmar-machine.hh" +#line 301 "hb-ot-shape-complex-myanmar-machine.hh" { cs = myanmar_syllable_machine_start; ts = 0; @@ -306,16 +305,15 @@ find_syllables (hb_buffer_t *buffer) act = 0; } -#line 115 "hb-ot-shape-complex-myanmar-machine.rl" +#line 114 "hb-ot-shape-complex-myanmar-machine.rl" p = 0; pe = eof = buffer->len; - unsigned int last = 0; unsigned int syllable_serial = 1; -#line 319 "hb-ot-shape-complex-myanmar-machine.hh" +#line 317 "hb-ot-shape-complex-myanmar-machine.hh" { int _slen; int _trans; @@ -329,7 +327,7 @@ _resume: #line 1 "NONE" {ts = p;} break; -#line 333 "hb-ot-shape-complex-myanmar-machine.hh" +#line 331 "hb-ot-shape-complex-myanmar-machine.hh" } _keys = _myanmar_syllable_machine_trans_keys + (cs<<1); @@ -379,7 +377,7 @@ _eof_trans: #line 90 "hb-ot-shape-complex-myanmar-machine.rl" {te = p;p--;{ found_syllable (non_myanmar_cluster); }} break; -#line 383 "hb-ot-shape-complex-myanmar-machine.hh" +#line 381 "hb-ot-shape-complex-myanmar-machine.hh" } _again: @@ -388,7 +386,7 @@ _again: #line 1 "NONE" {ts = 0;} break; -#line 392 "hb-ot-shape-complex-myanmar-machine.hh" +#line 390 "hb-ot-shape-complex-myanmar-machine.hh" } if ( ++p != pe ) @@ -404,7 +402,7 @@ _again: } -#line 124 "hb-ot-shape-complex-myanmar-machine.rl" +#line 122 "hb-ot-shape-complex-myanmar-machine.rl" } diff --git a/src/hb-ot-shape-complex-myanmar-machine.rl b/src/hb-ot-shape-complex-myanmar-machine.rl index 0cd84fa1b..7845a86d4 100644 --- a/src/hb-ot-shape-complex-myanmar-machine.rl +++ b/src/hb-ot-shape-complex-myanmar-machine.rl @@ -27,7 +27,7 @@ #ifndef HB_OT_SHAPE_COMPLEX_MYANMAR_MACHINE_HH #define HB_OT_SHAPE_COMPLEX_MYANMAR_MACHINE_HH -#include "hb-private.hh" +#include "hb.hh" %%{ machine myanmar_syllable_machine; @@ -95,10 +95,9 @@ main := |* #define found_syllable(syllable_type) \ HB_STMT_START { \ - if (0) fprintf (stderr, "syllable %d..%d %s\n", last, p+1, #syllable_type); \ - for (unsigned int i = last; i < p+1; i++) \ + if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \ + for (unsigned int i = ts; i < te; i++) \ info[i].syllable() = (syllable_serial << 4) | syllable_type; \ - last = p+1; \ syllable_serial++; \ if (unlikely (syllable_serial == 16)) syllable_serial = 1; \ } HB_STMT_END @@ -106,7 +105,7 @@ main := |* static void find_syllables (hb_buffer_t *buffer) { - unsigned int p, pe, eof, ts HB_UNUSED, te HB_UNUSED, act HB_UNUSED; + unsigned int p, pe, eof, ts, te, act HB_UNUSED; int cs; hb_glyph_info_t *info = buffer->info; %%{ @@ -117,7 +116,6 @@ find_syllables (hb_buffer_t *buffer) p = 0; pe = eof = buffer->len; - unsigned int last = 0; unsigned int syllable_serial = 1; %%{ write exec; diff --git a/src/hb-ot-shape-complex-myanmar.cc b/src/hb-ot-shape-complex-myanmar.cc index e4214b87e..e201a2309 100644 --- a/src/hb-ot-shape-complex-myanmar.cc +++ b/src/hb-ot-shape-complex-myanmar.cc @@ -24,7 +24,7 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-ot-shape-complex-myanmar-private.hh" +#include "hb-ot-shape-complex-myanmar.hh" /* @@ -54,7 +54,14 @@ other_features[] = HB_TAG('a','b','v','s'), HB_TAG('b','l','w','s'), HB_TAG('p','s','t','s'), - /* Positioning features, though we don't care about the types. */ +}; +static const hb_tag_t +positioning_features[] = +{ + /* + * Positioning features. + * We don't care about the types. + */ HB_TAG('d','i','s','t'), /* Pre-release version of Windows 8 Myanmar font had abvm,blwm * features. The released Windows 8 version of the font (as well @@ -89,27 +96,33 @@ collect_features_myanmar (hb_ot_shape_planner_t *plan) /* Do this before any lookups have been applied. */ map->add_gsub_pause (setup_syllables); - map->add_global_bool_feature (HB_TAG('l','o','c','l')); + map->enable_feature (HB_TAG('l','o','c','l')); /* The Indic specs do not require ccmp, but we apply it here since if * there is a use of it, it's typically at the beginning. */ - map->add_global_bool_feature (HB_TAG('c','c','m','p')); + map->enable_feature (HB_TAG('c','c','m','p')); map->add_gsub_pause (initial_reordering); + for (unsigned int i = 0; i < ARRAY_LENGTH (basic_features); i++) { - map->add_feature (basic_features[i], 1, F_GLOBAL | F_MANUAL_ZWJ); + map->enable_feature (basic_features[i], F_MANUAL_ZWJ); map->add_gsub_pause (nullptr); } + map->add_gsub_pause (final_reordering); + for (unsigned int i = 0; i < ARRAY_LENGTH (other_features); i++) - map->add_feature (other_features[i], 1, F_GLOBAL | F_MANUAL_ZWJ); + map->enable_feature (other_features[i], F_MANUAL_ZWJ); + + for (unsigned int i = 0; i < ARRAY_LENGTH (positioning_features); i++) + map->enable_feature (positioning_features[i]); } static void override_features_myanmar (hb_ot_shape_planner_t *plan) { - plan->map.add_feature (HB_TAG('l','i','g','a'), 0, F_GLOBAL); + plan->map.disable_feature (HB_TAG('l','i','g','a')); } @@ -362,6 +375,25 @@ final_reordering (const hb_ot_shape_plan_t *plan, } +const hb_ot_complex_shaper_t _hb_ot_complex_shaper_myanmar = +{ + collect_features_myanmar, + override_features_myanmar, + nullptr, /* data_create */ + nullptr, /* data_destroy */ + nullptr, /* preprocess_text */ + nullptr, /* postprocess_glyphs */ + HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT, + nullptr, /* decompose */ + nullptr, /* compose */ + setup_masks_myanmar, + HB_TAG_NONE, /* gpos_tag */ + nullptr, /* reorder_marks */ + HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY, + false, /* fallback_position */ +}; + + /* Uniscribe seems to have a shaper for 'mymr' that is like the * generic shaper, except that it zeros mark advances GDEF_LATE. */ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_myanmar_old = @@ -376,26 +408,30 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_myanmar_old = nullptr, /* decompose */ nullptr, /* compose */ nullptr, /* setup_masks */ - nullptr, /* disable_otl */ + HB_TAG_NONE, /* gpos_tag */ nullptr, /* reorder_marks */ HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE, true, /* fallback_position */ }; -const hb_ot_complex_shaper_t _hb_ot_complex_shaper_myanmar = + +/* Ugly Zawgyi encoding. + * Disable all auto processing. + * https://github.com/harfbuzz/harfbuzz/issues/1162 */ +const hb_ot_complex_shaper_t _hb_ot_complex_shaper_myanmar_zawgyi = { - collect_features_myanmar, - override_features_myanmar, + nullptr, /* collect_features */ + nullptr, /* override_features */ nullptr, /* data_create */ nullptr, /* data_destroy */ nullptr, /* preprocess_text */ nullptr, /* postprocess_glyphs */ - HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT, + HB_OT_SHAPE_NORMALIZATION_MODE_NONE, nullptr, /* decompose */ nullptr, /* compose */ - setup_masks_myanmar, - nullptr, /* disable_otl */ + nullptr, /* setup_masks */ + HB_TAG_NONE, /* gpos_tag */ nullptr, /* reorder_marks */ - HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY, + HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE, false, /* fallback_position */ }; diff --git a/src/hb-ot-shape-complex-myanmar-private.hh b/src/hb-ot-shape-complex-myanmar.hh index 14d011d67..3e9537a64 100644 --- a/src/hb-ot-shape-complex-myanmar-private.hh +++ b/src/hb-ot-shape-complex-myanmar.hh @@ -24,12 +24,12 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_OT_SHAPE_COMPLEX_MYANMAR_PRIVATE_HH -#define HB_OT_SHAPE_COMPLEX_MYANMAR_PRIVATE_HH +#ifndef HB_OT_SHAPE_COMPLEX_MYANMAR_HH +#define HB_OT_SHAPE_COMPLEX_MYANMAR_HH -#include "hb-private.hh" +#include "hb.hh" -#include "hb-ot-shape-complex-indic-private.hh" +#include "hb-ot-shape-complex-indic.hh" /* buffer var allocations */ @@ -64,42 +64,42 @@ set_myanmar_properties (hb_glyph_info_t &info) { hb_codepoint_t u = info.codepoint; unsigned int type = hb_indic_get_categories (u); - indic_category_t cat = (indic_category_t) (type & 0x7Fu); + unsigned int cat = type & 0x7Fu; indic_position_t pos = (indic_position_t) (type >> 8); /* Myanmar * https://docs.microsoft.com/en-us/typography/script-development/myanmar#analyze */ if (unlikely (hb_in_range<hb_codepoint_t> (u, 0xFE00u, 0xFE0Fu))) - cat = (indic_category_t) OT_VS; + cat = OT_VS; switch (u) { case 0x104Eu: - cat = (indic_category_t) OT_C; /* The spec says C, IndicSyllableCategory doesn't have. */ + cat = OT_C; /* The spec says C, IndicSyllableCategory doesn't have. */ break; case 0x002Du: case 0x00A0u: case 0x00D7u: case 0x2012u: case 0x2013u: case 0x2014u: case 0x2015u: case 0x2022u: case 0x25CCu: case 0x25FBu: case 0x25FCu: case 0x25FDu: case 0x25FEu: - cat = (indic_category_t) OT_GB; + cat = OT_GB; break; case 0x1004u: case 0x101Bu: case 0x105Au: - cat = (indic_category_t) OT_Ra; + cat = OT_Ra; break; case 0x1032u: case 0x1036u: - cat = (indic_category_t) OT_A; + cat = OT_A; break; case 0x1039u: - cat = (indic_category_t) OT_H; + cat = OT_H; break; case 0x103Au: - cat = (indic_category_t) OT_As; + cat = OT_As; break; case 0x1041u: case 0x1042u: case 0x1043u: case 0x1044u: @@ -107,47 +107,47 @@ set_myanmar_properties (hb_glyph_info_t &info) case 0x1049u: case 0x1090u: case 0x1091u: case 0x1092u: case 0x1093u: case 0x1094u: case 0x1095u: case 0x1096u: case 0x1097u: case 0x1098u: case 0x1099u: - cat = (indic_category_t) OT_D; + cat = OT_D; break; case 0x1040u: - cat = (indic_category_t) OT_D; /* XXX The spec says D0, but Uniscribe doesn't seem to do. */ + cat = OT_D; /* XXX The spec says D0, but Uniscribe doesn't seem to do. */ break; case 0x103Eu: case 0x1060u: - cat = (indic_category_t) OT_MH; + cat = OT_MH; break; case 0x103Cu: - cat = (indic_category_t) OT_MR; + cat = OT_MR; break; case 0x103Du: case 0x1082u: - cat = (indic_category_t) OT_MW; + cat = OT_MW; break; case 0x103Bu: case 0x105Eu: case 0x105Fu: - cat = (indic_category_t) OT_MY; + cat = OT_MY; break; case 0x1063u: case 0x1064u: case 0x1069u: case 0x106Au: case 0x106Bu: case 0x106Cu: case 0x106Du: case 0xAA7Bu: - cat = (indic_category_t) OT_PT; + cat = OT_PT; break; case 0x1038u: case 0x1087u: case 0x1088u: case 0x1089u: case 0x108Au: case 0x108Bu: case 0x108Cu: case 0x108Du: case 0x108Fu: case 0x109Au: case 0x109Bu: case 0x109Cu: - cat = (indic_category_t) OT_SM; + cat = OT_SM; break; case 0x104Au: case 0x104Bu: - cat = (indic_category_t) OT_P; + cat = OT_P; break; case 0xAA74u: case 0xAA75u: case 0xAA76u: /* https://github.com/roozbehp/unicode-data/issues/3 */ - cat = (indic_category_t) OT_C; + cat = OT_C; break; } @@ -155,17 +155,17 @@ set_myanmar_properties (hb_glyph_info_t &info) { switch ((int) pos) { - case POS_PRE_C: cat = (indic_category_t) OT_VPre; - pos = POS_PRE_M; break; - case POS_ABOVE_C: cat = (indic_category_t) OT_VAbv; break; - case POS_BELOW_C: cat = (indic_category_t) OT_VBlw; break; - case POS_POST_C: cat = (indic_category_t) OT_VPst; break; + case POS_PRE_C: cat = OT_VPre; + pos = POS_PRE_M; break; + case POS_ABOVE_C: cat = OT_VAbv; break; + case POS_BELOW_C: cat = OT_VBlw; break; + case POS_POST_C: cat = OT_VPst; break; } } - info.myanmar_category() = (myanmar_category_t) cat; + info.myanmar_category() = cat; info.myanmar_position() = pos; } -#endif /* HB_OT_SHAPE_COMPLEX_MYANMAR_PRIVATE_HH */ +#endif /* HB_OT_SHAPE_COMPLEX_MYANMAR_HH */ diff --git a/src/hb-ot-shape-complex-thai.cc b/src/hb-ot-shape-complex-thai.cc index 02d78ac04..b687fe61e 100644 --- a/src/hb-ot-shape-complex-thai.cc +++ b/src/hb-ot-shape-complex-thai.cc @@ -24,7 +24,7 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-ot-shape-complex-private.hh" +#include "hb-ot-shape-complex.hh" /* Thai / Lao shaper */ @@ -324,9 +324,9 @@ preprocess_text_thai (const hb_ot_shape_plan_t *plan, } /* Is SARA AM. Decompose and reorder. */ - hb_codepoint_t decomposed[2] = {hb_codepoint_t (NIKHAHIT_FROM_SARA_AM (u)), - hb_codepoint_t (SARA_AA_FROM_SARA_AM (u))}; - buffer->replace_glyphs (1, 2, decomposed); + hb_glyph_info_t &nikhahit = buffer->output_glyph (NIKHAHIT_FROM_SARA_AM (u)); + _hb_glyph_info_set_continuation (&nikhahit); + buffer->replace_glyph (SARA_AA_FROM_SARA_AM (u)); if (unlikely (!buffer->successful)) return; @@ -357,7 +357,8 @@ preprocess_text_thai (const hb_ot_shape_plan_t *plan, buffer->merge_out_clusters (start - 1, end); } } - buffer->swap_buffers (); + if (likely (buffer->successful)) + buffer->swap_buffers (); /* If font has Thai GSUB, we are done. */ if (plan->props.script == HB_SCRIPT_THAI && !plan->map.found_script[0]) @@ -376,7 +377,7 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_thai = nullptr, /* decompose */ nullptr, /* compose */ nullptr, /* setup_masks */ - nullptr, /* disable_otl */ + HB_TAG_NONE, /* gpos_tag */ nullptr, /* reorder_marks */ HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE, false,/* fallback_position */ diff --git a/src/hb-ot-shape-complex-tibetan.cc b/src/hb-ot-shape-complex-tibetan.cc deleted file mode 100644 index eaac0bf68..000000000 --- a/src/hb-ot-shape-complex-tibetan.cc +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright © 2010,2012 Google, Inc. - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Google Author(s): Behdad Esfahbod - */ - -#include "hb-ot-shape-complex-private.hh" - - -static const hb_tag_t tibetan_features[] = -{ - HB_TAG('a','b','v','s'), - HB_TAG('b','l','w','s'), - HB_TAG('a','b','v','m'), - HB_TAG('b','l','w','m'), - HB_TAG_NONE -}; - -static void -collect_features_tibetan (hb_ot_shape_planner_t *plan) -{ - for (const hb_tag_t *script_features = tibetan_features; script_features && *script_features; script_features++) - plan->map.add_global_bool_feature (*script_features); -} - - -const hb_ot_complex_shaper_t _hb_ot_complex_shaper_tibetan = -{ - collect_features_tibetan, - nullptr, /* override_features */ - nullptr, /* data_create */ - nullptr, /* data_destroy */ - nullptr, /* preprocess_text */ - nullptr, /* postprocess_glyphs */ - HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT, - nullptr, /* decompose */ - nullptr, /* compose */ - nullptr, /* setup_masks */ - nullptr, /* disable_otl */ - nullptr, /* reorder_marks */ - HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE, - true, /* fallback_position */ -}; diff --git a/src/hb-ot-shape-complex-use-machine.hh b/src/hb-ot-shape-complex-use-machine.hh index 0ec805afc..c9410e4e5 100644 --- a/src/hb-ot-shape-complex-use-machine.hh +++ b/src/hb-ot-shape-complex-use-machine.hh @@ -31,232 +31,271 @@ #ifndef HB_OT_SHAPE_COMPLEX_USE_MACHINE_HH #define HB_OT_SHAPE_COMPLEX_USE_MACHINE_HH -#include "hb-private.hh" +#include "hb.hh" #line 38 "hb-ot-shape-complex-use-machine.hh" static const unsigned char _use_syllable_machine_trans_keys[] = { - 12u, 12u, 1u, 15u, 1u, 1u, 12u, 12u, 0u, 43u, 21u, 21u, 8u, 39u, 8u, 39u, - 1u, 15u, 1u, 1u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 26u, 8u, 26u, 8u, 26u, - 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, - 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 13u, 21u, 4u, 4u, 13u, 13u, 8u, 39u, - 8u, 39u, 8u, 39u, 8u, 39u, 8u, 26u, 8u, 26u, 8u, 26u, 8u, 39u, 8u, 39u, - 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, - 8u, 39u, 1u, 15u, 12u, 12u, 1u, 39u, 8u, 39u, 21u, 42u, 41u, 42u, 42u, 42u, - 1u, 5u, 0 + 12u, 44u, 1u, 15u, 1u, 1u, 12u, 44u, 0u, 44u, 21u, 21u, 8u, 44u, 8u, 44u, + 1u, 15u, 1u, 1u, 8u, 44u, 8u, 44u, 8u, 39u, 8u, 26u, 8u, 26u, 8u, 26u, + 8u, 39u, 8u, 39u, 8u, 39u, 8u, 44u, 8u, 44u, 8u, 44u, 8u, 44u, 8u, 44u, + 8u, 44u, 8u, 44u, 8u, 44u, 1u, 39u, 8u, 44u, 13u, 21u, 4u, 4u, 13u, 13u, + 8u, 44u, 8u, 44u, 8u, 44u, 8u, 39u, 8u, 26u, 8u, 26u, 8u, 26u, 8u, 39u, + 8u, 39u, 8u, 39u, 8u, 44u, 8u, 44u, 8u, 44u, 8u, 44u, 8u, 44u, 8u, 44u, + 8u, 44u, 8u, 44u, 1u, 39u, 1u, 15u, 12u, 44u, 1u, 44u, 8u, 44u, 21u, 42u, + 41u, 42u, 42u, 42u, 1u, 5u, 0 }; static const char _use_syllable_machine_key_spans[] = { - 1, 15, 1, 1, 44, 1, 32, 32, - 15, 1, 32, 32, 32, 19, 19, 19, - 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 9, 1, 1, 32, - 32, 32, 32, 19, 19, 19, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, - 32, 15, 1, 39, 32, 22, 2, 1, - 5 + 33, 15, 1, 33, 45, 1, 37, 37, + 15, 1, 37, 37, 32, 19, 19, 19, + 32, 32, 32, 37, 37, 37, 37, 37, + 37, 37, 37, 39, 37, 9, 1, 1, + 37, 37, 37, 32, 19, 19, 19, 32, + 32, 32, 37, 37, 37, 37, 37, 37, + 37, 37, 39, 15, 33, 44, 37, 22, + 2, 1, 5 }; static const short _use_syllable_machine_index_offsets[] = { - 0, 2, 18, 20, 22, 67, 69, 102, - 135, 151, 153, 186, 219, 252, 272, 292, - 312, 345, 378, 411, 444, 477, 510, 543, - 576, 609, 642, 675, 708, 718, 720, 722, - 755, 788, 821, 854, 874, 894, 914, 947, - 980, 1013, 1046, 1079, 1112, 1145, 1178, 1211, - 1244, 1277, 1293, 1295, 1335, 1368, 1391, 1394, - 1396 + 0, 34, 50, 52, 86, 132, 134, 172, + 210, 226, 228, 266, 304, 337, 357, 377, + 397, 430, 463, 496, 534, 572, 610, 648, + 686, 724, 762, 800, 840, 878, 888, 890, + 892, 930, 968, 1006, 1039, 1059, 1079, 1099, + 1132, 1165, 1198, 1236, 1274, 1312, 1350, 1388, + 1426, 1464, 1502, 1542, 1558, 1592, 1637, 1675, + 1698, 1701, 1703 }; static const char _use_syllable_machine_indicies[] = { + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 4, 2, 3, 2, 6, 5, 7, 8, + 4, 2, 3, 2, 6, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 6, 5, 7, 8, 9, 7, 10, 8, 9, 9, 11, 9, 9, 3, 12, 9, 9, 13, 7, 7, 14, 15, 9, 9, 16, 17, 18, 19, 20, 21, 22, 16, 23, 24, 25, 26, 27, 28, 9, 29, 30, 31, 9, 9, - 9, 32, 9, 34, 33, 36, 35, 35, - 37, 1, 35, 35, 38, 35, 35, 35, - 35, 35, 39, 40, 41, 42, 43, 44, - 45, 46, 40, 47, 39, 48, 49, 50, - 51, 35, 52, 53, 54, 35, 36, 35, - 35, 37, 1, 35, 35, 38, 35, 35, - 35, 35, 35, 55, 40, 41, 42, 43, - 44, 45, 46, 40, 47, 48, 48, 49, - 50, 51, 35, 52, 53, 54, 35, 37, - 56, 56, 56, 56, 56, 56, 56, 56, - 56, 56, 56, 56, 56, 57, 56, 37, - 56, 36, 35, 35, 37, 1, 35, 35, - 38, 35, 35, 35, 35, 35, 35, 40, - 41, 42, 43, 44, 45, 46, 40, 47, - 48, 48, 49, 50, 51, 35, 52, 53, - 54, 35, 36, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, - 40, 41, 42, 43, 44, 35, 35, 35, - 35, 35, 35, 49, 50, 51, 35, 52, - 53, 54, 35, 36, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 41, 42, 43, 44, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, - 52, 53, 54, 35, 36, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 42, 43, 44, 35, - 36, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, - 35, 43, 44, 35, 36, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 44, 35, - 36, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, - 42, 43, 44, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 52, 53, 54, - 35, 36, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, - 35, 42, 43, 44, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 53, - 54, 35, 36, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 42, 43, 44, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, - 35, 54, 35, 36, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 41, 42, 43, 44, 35, 35, - 35, 35, 35, 35, 49, 50, 51, 35, - 52, 53, 54, 35, 36, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 41, 42, 43, 44, 35, - 35, 35, 35, 35, 35, 35, 50, 51, - 35, 52, 53, 54, 35, 36, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 41, 42, 43, 44, - 35, 35, 35, 35, 35, 35, 35, 35, - 51, 35, 52, 53, 54, 35, 36, 35, - 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 40, 41, 42, 43, - 44, 35, 46, 40, 35, 35, 35, 49, - 50, 51, 35, 52, 53, 54, 35, 36, - 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 40, 41, 42, - 43, 44, 35, 58, 40, 35, 35, 35, - 49, 50, 51, 35, 52, 53, 54, 35, - 36, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 40, 41, - 42, 43, 44, 35, 35, 40, 35, 35, - 35, 49, 50, 51, 35, 52, 53, 54, - 35, 36, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 40, - 41, 42, 43, 44, 45, 46, 40, 35, - 35, 35, 49, 50, 51, 35, 52, 53, - 54, 35, 36, 35, 35, 37, 1, 35, - 35, 38, 35, 35, 35, 35, 35, 35, - 40, 41, 42, 43, 44, 45, 46, 40, - 47, 35, 48, 49, 50, 51, 35, 52, - 53, 54, 35, 36, 35, 35, 37, 1, - 35, 35, 38, 35, 35, 35, 35, 35, - 35, 40, 41, 42, 43, 44, 45, 46, - 40, 47, 39, 48, 49, 50, 51, 35, - 52, 53, 54, 35, 60, 59, 59, 59, - 59, 59, 59, 59, 61, 59, 10, 62, - 60, 59, 11, 63, 63, 3, 6, 63, - 63, 64, 63, 63, 63, 63, 63, 65, + 9, 32, 33, 9, 35, 34, 37, 36, + 36, 38, 1, 36, 36, 39, 36, 36, + 36, 36, 36, 40, 41, 42, 43, 44, + 45, 46, 47, 41, 48, 40, 49, 50, + 51, 52, 36, 53, 54, 55, 36, 36, + 36, 36, 56, 36, 37, 36, 36, 38, + 1, 36, 36, 39, 36, 36, 36, 36, + 36, 57, 41, 42, 43, 44, 45, 46, + 47, 41, 48, 49, 49, 50, 51, 52, + 36, 53, 54, 55, 36, 36, 36, 36, + 56, 36, 38, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, + 59, 58, 38, 58, 37, 36, 36, 38, + 1, 36, 36, 39, 36, 36, 36, 36, + 36, 36, 41, 42, 43, 44, 45, 46, + 47, 41, 48, 49, 49, 50, 51, 52, + 36, 53, 54, 55, 36, 36, 36, 36, + 56, 36, 37, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, + 41, 42, 43, 44, 45, 36, 36, 36, + 36, 36, 36, 50, 51, 52, 36, 53, + 54, 55, 36, 36, 36, 36, 42, 36, + 37, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 42, + 43, 44, 45, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 53, 54, 55, + 36, 37, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, + 36, 43, 44, 45, 36, 37, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 44, 45, + 36, 37, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 45, 36, 37, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 43, 44, 45, + 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 53, 54, 55, 36, 37, 36, + 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 43, 44, + 45, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 54, 55, 36, 37, + 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 43, + 44, 45, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 55, 36, + 37, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 42, + 43, 44, 45, 36, 36, 36, 36, 36, + 36, 50, 51, 52, 36, 53, 54, 55, + 36, 36, 36, 36, 42, 36, 37, 36, + 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 42, 43, 44, + 45, 36, 36, 36, 36, 36, 36, 36, + 51, 52, 36, 53, 54, 55, 36, 36, + 36, 36, 42, 36, 37, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 42, 43, 44, 45, 36, + 36, 36, 36, 36, 36, 36, 36, 52, + 36, 53, 54, 55, 36, 36, 36, 36, + 42, 36, 37, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, + 41, 42, 43, 44, 45, 36, 47, 41, + 36, 36, 36, 50, 51, 52, 36, 53, + 54, 55, 36, 36, 36, 36, 42, 36, + 37, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 41, 42, + 43, 44, 45, 36, 60, 41, 36, 36, + 36, 50, 51, 52, 36, 53, 54, 55, + 36, 36, 36, 36, 42, 36, 37, 36, + 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 41, 42, 43, 44, + 45, 36, 36, 41, 36, 36, 36, 50, + 51, 52, 36, 53, 54, 55, 36, 36, + 36, 36, 42, 36, 37, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 41, 42, 43, 44, 45, 46, + 47, 41, 36, 36, 36, 50, 51, 52, + 36, 53, 54, 55, 36, 36, 36, 36, + 42, 36, 37, 36, 36, 38, 1, 36, + 36, 39, 36, 36, 36, 36, 36, 36, + 41, 42, 43, 44, 45, 46, 47, 41, + 48, 36, 49, 50, 51, 52, 36, 53, + 54, 55, 36, 36, 36, 36, 56, 36, + 38, 58, 58, 58, 58, 58, 58, 37, + 58, 58, 58, 58, 58, 58, 59, 58, + 58, 58, 58, 58, 58, 58, 42, 43, + 44, 45, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 53, 54, 55, 58, + 37, 36, 36, 38, 1, 36, 36, 39, + 36, 36, 36, 36, 36, 36, 41, 42, + 43, 44, 45, 46, 47, 41, 48, 40, + 49, 50, 51, 52, 36, 53, 54, 55, + 36, 36, 36, 36, 56, 36, 62, 61, + 61, 61, 61, 61, 61, 61, 63, 61, + 10, 64, 62, 61, 11, 65, 65, 3, + 6, 65, 65, 66, 65, 65, 65, 65, + 65, 67, 16, 17, 18, 19, 20, 21, + 22, 16, 23, 25, 25, 26, 27, 28, + 65, 29, 30, 31, 65, 65, 65, 65, + 33, 65, 11, 65, 65, 3, 6, 65, + 65, 66, 65, 65, 65, 65, 65, 65, 16, 17, 18, 19, 20, 21, 22, 16, - 23, 25, 25, 26, 27, 28, 63, 29, - 30, 31, 63, 11, 63, 63, 3, 6, - 63, 63, 64, 63, 63, 63, 63, 63, - 63, 16, 17, 18, 19, 20, 21, 22, - 16, 23, 25, 25, 26, 27, 28, 63, - 29, 30, 31, 63, 11, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 63, 63, - 63, 63, 16, 17, 18, 19, 20, 63, - 63, 63, 63, 63, 63, 26, 27, 28, - 63, 29, 30, 31, 63, 11, 63, 63, - 63, 63, 63, 63, 63, 63, 63, 63, - 63, 63, 63, 63, 17, 18, 19, 20, - 63, 63, 63, 63, 63, 63, 63, 63, - 63, 63, 29, 30, 31, 63, 11, 63, - 63, 63, 63, 63, 63, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 18, 19, - 20, 63, 11, 63, 63, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 63, 63, - 63, 63, 63, 19, 20, 63, 11, 63, - 63, 63, 63, 63, 63, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 63, 63, - 20, 63, 11, 63, 63, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 63, 63, - 63, 63, 18, 19, 20, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 63, 29, - 30, 31, 63, 11, 63, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 63, 63, - 63, 63, 63, 18, 19, 20, 63, 63, - 63, 63, 63, 63, 63, 63, 63, 63, - 63, 30, 31, 63, 11, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 63, 63, - 63, 63, 63, 63, 18, 19, 20, 63, - 63, 63, 63, 63, 63, 63, 63, 63, - 63, 63, 63, 31, 63, 11, 63, 63, - 63, 63, 63, 63, 63, 63, 63, 63, - 63, 63, 63, 63, 17, 18, 19, 20, - 63, 63, 63, 63, 63, 63, 26, 27, - 28, 63, 29, 30, 31, 63, 11, 63, - 63, 63, 63, 63, 63, 63, 63, 63, - 63, 63, 63, 63, 63, 17, 18, 19, - 20, 63, 63, 63, 63, 63, 63, 63, - 27, 28, 63, 29, 30, 31, 63, 11, - 63, 63, 63, 63, 63, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 17, 18, - 19, 20, 63, 63, 63, 63, 63, 63, - 63, 63, 28, 63, 29, 30, 31, 63, - 11, 63, 63, 63, 63, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 16, 17, - 18, 19, 20, 63, 22, 16, 63, 63, - 63, 26, 27, 28, 63, 29, 30, 31, - 63, 11, 63, 63, 63, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 63, 16, - 17, 18, 19, 20, 63, 66, 16, 63, - 63, 63, 26, 27, 28, 63, 29, 30, - 31, 63, 11, 63, 63, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 63, 63, - 16, 17, 18, 19, 20, 63, 63, 16, - 63, 63, 63, 26, 27, 28, 63, 29, - 30, 31, 63, 11, 63, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 63, 63, - 63, 16, 17, 18, 19, 20, 21, 22, - 16, 63, 63, 63, 26, 27, 28, 63, - 29, 30, 31, 63, 11, 63, 63, 3, - 6, 63, 63, 64, 63, 63, 63, 63, - 63, 63, 16, 17, 18, 19, 20, 21, - 22, 16, 23, 63, 25, 26, 27, 28, - 63, 29, 30, 31, 63, 3, 67, 67, - 67, 67, 67, 67, 67, 67, 67, 67, - 67, 67, 67, 4, 67, 6, 67, 8, - 63, 63, 63, 8, 63, 63, 11, 63, - 63, 3, 6, 63, 63, 64, 63, 63, - 63, 63, 63, 63, 16, 17, 18, 19, - 20, 21, 22, 16, 23, 24, 25, 26, - 27, 28, 63, 29, 30, 31, 63, 11, - 63, 63, 3, 6, 63, 63, 64, 63, - 63, 63, 63, 63, 63, 16, 17, 18, + 23, 25, 25, 26, 27, 28, 65, 29, + 30, 31, 65, 65, 65, 65, 33, 65, + 11, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 65, 65, 65, 65, 16, 17, + 18, 19, 20, 65, 65, 65, 65, 65, + 65, 26, 27, 28, 65, 29, 30, 31, + 65, 65, 65, 65, 17, 65, 11, 65, + 65, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 65, 65, 65, 17, 18, 19, + 20, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 65, 29, 30, 31, 65, 11, + 65, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 65, 65, 65, 65, 65, 18, + 19, 20, 65, 11, 65, 65, 65, 65, + 65, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 65, 65, 19, 20, 65, 11, + 65, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 65, 65, 65, 65, 65, 65, + 65, 20, 65, 11, 65, 65, 65, 65, + 65, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 65, 18, 19, 20, 65, 65, + 65, 65, 65, 65, 65, 65, 65, 65, + 29, 30, 31, 65, 11, 65, 65, 65, + 65, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 65, 65, 18, 19, 20, 65, + 65, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 30, 31, 65, 11, 65, 65, + 65, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 65, 65, 65, 18, 19, 20, + 65, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 65, 65, 31, 65, 11, 65, + 65, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 65, 65, 65, 17, 18, 19, + 20, 65, 65, 65, 65, 65, 65, 26, + 27, 28, 65, 29, 30, 31, 65, 65, + 65, 65, 17, 65, 11, 65, 65, 65, + 65, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 65, 17, 18, 19, 20, 65, + 65, 65, 65, 65, 65, 65, 27, 28, + 65, 29, 30, 31, 65, 65, 65, 65, + 17, 65, 11, 65, 65, 65, 65, 65, + 65, 65, 65, 65, 65, 65, 65, 65, + 65, 17, 18, 19, 20, 65, 65, 65, + 65, 65, 65, 65, 65, 28, 65, 29, + 30, 31, 65, 65, 65, 65, 17, 65, + 11, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 65, 65, 65, 65, 16, 17, + 18, 19, 20, 65, 22, 16, 65, 65, + 65, 26, 27, 28, 65, 29, 30, 31, + 65, 65, 65, 65, 17, 65, 11, 65, + 65, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 65, 65, 16, 17, 18, 19, + 20, 65, 68, 16, 65, 65, 65, 26, + 27, 28, 65, 29, 30, 31, 65, 65, + 65, 65, 17, 65, 11, 65, 65, 65, + 65, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 16, 17, 18, 19, 20, 65, + 65, 16, 65, 65, 65, 26, 27, 28, + 65, 29, 30, 31, 65, 65, 65, 65, + 17, 65, 11, 65, 65, 65, 65, 65, + 65, 65, 65, 65, 65, 65, 65, 65, + 16, 17, 18, 19, 20, 21, 22, 16, + 65, 65, 65, 26, 27, 28, 65, 29, + 30, 31, 65, 65, 65, 65, 17, 65, + 11, 65, 65, 3, 6, 65, 65, 66, + 65, 65, 65, 65, 65, 65, 16, 17, + 18, 19, 20, 21, 22, 16, 23, 65, + 25, 26, 27, 28, 65, 29, 30, 31, + 65, 65, 65, 65, 33, 65, 3, 65, + 65, 65, 65, 65, 65, 11, 65, 65, + 65, 65, 65, 65, 4, 65, 65, 65, + 65, 65, 65, 65, 17, 18, 19, 20, + 65, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 29, 30, 31, 65, 3, 69, + 69, 69, 69, 69, 69, 69, 69, 69, + 69, 69, 69, 69, 4, 69, 6, 69, + 69, 69, 69, 69, 69, 69, 69, 69, + 69, 69, 69, 69, 69, 69, 69, 69, + 69, 69, 69, 69, 69, 69, 69, 69, + 69, 69, 69, 69, 69, 69, 6, 69, + 8, 65, 65, 65, 8, 65, 65, 11, + 65, 65, 3, 6, 65, 65, 66, 65, + 65, 65, 65, 65, 65, 16, 17, 18, 19, 20, 21, 22, 16, 23, 24, 25, - 26, 27, 28, 63, 29, 30, 31, 63, - 69, 68, 68, 68, 68, 68, 68, 68, - 68, 68, 68, 68, 68, 68, 68, 68, - 68, 68, 68, 68, 69, 70, 68, 69, - 70, 68, 70, 68, 8, 67, 67, 67, - 8, 67, 0 + 26, 27, 28, 65, 29, 30, 31, 65, + 65, 65, 65, 33, 65, 11, 65, 65, + 3, 6, 65, 65, 66, 65, 65, 65, + 65, 65, 65, 16, 17, 18, 19, 20, + 21, 22, 16, 23, 24, 25, 26, 27, + 28, 65, 29, 30, 31, 65, 65, 65, + 65, 33, 65, 71, 70, 70, 70, 70, + 70, 70, 70, 70, 70, 70, 70, 70, + 70, 70, 70, 70, 70, 70, 70, 71, + 72, 70, 71, 72, 70, 72, 70, 8, + 69, 69, 69, 8, 69, 0 }; static const char _use_syllable_machine_trans_targs[] = { - 4, 8, 4, 31, 2, 4, 1, 5, - 6, 4, 28, 4, 49, 50, 51, 53, - 33, 34, 35, 36, 37, 44, 45, 47, - 52, 48, 41, 42, 43, 38, 39, 40, - 56, 4, 4, 4, 4, 7, 0, 27, - 11, 12, 13, 14, 15, 22, 23, 25, - 26, 19, 20, 21, 16, 17, 18, 10, - 4, 9, 24, 4, 29, 30, 4, 4, - 3, 32, 46, 4, 4, 54, 55 + 4, 8, 4, 32, 2, 4, 1, 5, + 6, 4, 29, 4, 51, 52, 53, 55, + 34, 35, 36, 37, 38, 45, 46, 48, + 54, 49, 42, 43, 44, 39, 40, 41, + 58, 50, 4, 4, 4, 4, 7, 0, + 28, 11, 12, 13, 14, 15, 22, 23, + 25, 26, 19, 20, 21, 16, 17, 18, + 27, 10, 4, 9, 24, 4, 30, 31, + 4, 4, 3, 33, 47, 4, 4, 56, + 57 }; static const char _use_syllable_machine_trans_actions[] = { @@ -264,11 +303,12 @@ static const char _use_syllable_machine_trans_actions[] = { 7, 8, 0, 9, 10, 10, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, - 0, 11, 12, 13, 14, 7, 0, 7, - 0, 0, 0, 0, 0, 0, 0, 0, - 7, 0, 0, 0, 0, 0, 0, 7, - 15, 0, 0, 16, 0, 0, 17, 18, - 0, 3, 0, 19, 20, 0, 0 + 0, 3, 11, 12, 13, 14, 7, 0, + 7, 0, 0, 0, 0, 0, 0, 0, + 0, 7, 0, 0, 0, 0, 0, 0, + 0, 7, 15, 0, 0, 16, 0, 0, + 17, 18, 0, 3, 0, 19, 20, 0, + 0 }; static const char _use_syllable_machine_to_state_actions[] = { @@ -279,7 +319,7 @@ static const char _use_syllable_machine_to_state_actions[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0 + 0, 0, 0 }; static const char _use_syllable_machine_from_state_actions[] = { @@ -290,18 +330,18 @@ static const char _use_syllable_machine_from_state_actions[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0 + 0, 0, 0 }; static const short _use_syllable_machine_eof_trans[] = { - 1, 3, 3, 6, 0, 34, 36, 36, - 57, 57, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 60, 63, 60, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 68, 68, 64, 64, 69, 69, 69, - 68 + 1, 3, 3, 6, 0, 35, 37, 37, + 59, 59, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 59, 37, 62, 65, 62, + 66, 66, 66, 66, 66, 66, 66, 66, + 66, 66, 66, 66, 66, 66, 66, 66, + 66, 66, 66, 70, 70, 66, 66, 71, + 71, 71, 70 }; static const int use_syllable_machine_start = 4; @@ -315,15 +355,14 @@ static const int use_syllable_machine_en_main = 4; -#line 141 "hb-ot-shape-complex-use-machine.rl" +#line 143 "hb-ot-shape-complex-use-machine.rl" #define found_syllable(syllable_type) \ HB_STMT_START { \ - if (0) fprintf (stderr, "syllable %d..%d %s\n", last, p+1, #syllable_type); \ - for (unsigned int i = last; i < p+1; i++) \ + if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \ + for (unsigned int i = ts; i < te; i++) \ info[i].syllable() = (syllable_serial << 4) | syllable_type; \ - last = p+1; \ syllable_serial++; \ if (unlikely (syllable_serial == 16)) syllable_serial = 1; \ } HB_STMT_END @@ -331,11 +370,11 @@ static const int use_syllable_machine_en_main = 4; static void find_syllables (hb_buffer_t *buffer) { - unsigned int p, pe, eof, ts HB_UNUSED, te, act; + unsigned int p, pe, eof, ts, te, act; int cs; hb_glyph_info_t *info = buffer->info; -#line 339 "hb-ot-shape-complex-use-machine.hh" +#line 378 "hb-ot-shape-complex-use-machine.hh" { cs = use_syllable_machine_start; ts = 0; @@ -343,16 +382,15 @@ find_syllables (hb_buffer_t *buffer) act = 0; } -#line 162 "hb-ot-shape-complex-use-machine.rl" +#line 163 "hb-ot-shape-complex-use-machine.rl" p = 0; pe = eof = buffer->len; - unsigned int last = 0; unsigned int syllable_serial = 1; -#line 356 "hb-ot-shape-complex-use-machine.hh" +#line 394 "hb-ot-shape-complex-use-machine.hh" { int _slen; int _trans; @@ -366,7 +404,7 @@ _resume: #line 1 "NONE" {ts = p;} break; -#line 370 "hb-ot-shape-complex-use-machine.hh" +#line 408 "hb-ot-shape-complex-use-machine.hh" } _keys = _use_syllable_machine_trans_keys + (cs<<1); @@ -389,59 +427,59 @@ _eof_trans: {te = p+1;} break; case 12: -#line 130 "hb-ot-shape-complex-use-machine.rl" +#line 132 "hb-ot-shape-complex-use-machine.rl" {te = p+1;{ found_syllable (independent_cluster); }} break; case 14: -#line 132 "hb-ot-shape-complex-use-machine.rl" +#line 134 "hb-ot-shape-complex-use-machine.rl" {te = p+1;{ found_syllable (standard_cluster); }} break; case 9: -#line 136 "hb-ot-shape-complex-use-machine.rl" +#line 138 "hb-ot-shape-complex-use-machine.rl" {te = p+1;{ found_syllable (broken_cluster); }} break; case 8: -#line 137 "hb-ot-shape-complex-use-machine.rl" +#line 139 "hb-ot-shape-complex-use-machine.rl" {te = p+1;{ found_syllable (non_cluster); }} break; case 11: -#line 130 "hb-ot-shape-complex-use-machine.rl" +#line 132 "hb-ot-shape-complex-use-machine.rl" {te = p;p--;{ found_syllable (independent_cluster); }} break; case 15: -#line 131 "hb-ot-shape-complex-use-machine.rl" +#line 133 "hb-ot-shape-complex-use-machine.rl" {te = p;p--;{ found_syllable (virama_terminated_cluster); }} break; case 13: -#line 132 "hb-ot-shape-complex-use-machine.rl" +#line 134 "hb-ot-shape-complex-use-machine.rl" {te = p;p--;{ found_syllable (standard_cluster); }} break; case 17: -#line 133 "hb-ot-shape-complex-use-machine.rl" +#line 135 "hb-ot-shape-complex-use-machine.rl" {te = p;p--;{ found_syllable (number_joiner_terminated_cluster); }} break; case 16: -#line 134 "hb-ot-shape-complex-use-machine.rl" +#line 136 "hb-ot-shape-complex-use-machine.rl" {te = p;p--;{ found_syllable (numeral_cluster); }} break; case 20: -#line 135 "hb-ot-shape-complex-use-machine.rl" +#line 137 "hb-ot-shape-complex-use-machine.rl" {te = p;p--;{ found_syllable (symbol_cluster); }} break; case 18: -#line 136 "hb-ot-shape-complex-use-machine.rl" +#line 138 "hb-ot-shape-complex-use-machine.rl" {te = p;p--;{ found_syllable (broken_cluster); }} break; case 19: -#line 137 "hb-ot-shape-complex-use-machine.rl" +#line 139 "hb-ot-shape-complex-use-machine.rl" {te = p;p--;{ found_syllable (non_cluster); }} break; case 1: -#line 132 "hb-ot-shape-complex-use-machine.rl" +#line 134 "hb-ot-shape-complex-use-machine.rl" {{p = ((te))-1;}{ found_syllable (standard_cluster); }} break; case 4: -#line 136 "hb-ot-shape-complex-use-machine.rl" +#line 138 "hb-ot-shape-complex-use-machine.rl" {{p = ((te))-1;}{ found_syllable (broken_cluster); }} break; case 2: @@ -459,16 +497,16 @@ _eof_trans: case 3: #line 1 "NONE" {te = p+1;} -#line 136 "hb-ot-shape-complex-use-machine.rl" +#line 138 "hb-ot-shape-complex-use-machine.rl" {act = 7;} break; case 10: #line 1 "NONE" {te = p+1;} -#line 137 "hb-ot-shape-complex-use-machine.rl" +#line 139 "hb-ot-shape-complex-use-machine.rl" {act = 8;} break; -#line 472 "hb-ot-shape-complex-use-machine.hh" +#line 510 "hb-ot-shape-complex-use-machine.hh" } _again: @@ -477,7 +515,7 @@ _again: #line 1 "NONE" {ts = 0;} break; -#line 481 "hb-ot-shape-complex-use-machine.hh" +#line 519 "hb-ot-shape-complex-use-machine.hh" } if ( ++p != pe ) diff --git a/src/hb-ot-shape-complex-use-machine.rl b/src/hb-ot-shape-complex-use-machine.rl index 7ec8a7fd1..7702cd94d 100644 --- a/src/hb-ot-shape-complex-use-machine.rl +++ b/src/hb-ot-shape-complex-use-machine.rl @@ -29,7 +29,7 @@ #ifndef HB_OT_SHAPE_COMPLEX_USE_MACHINE_HH #define HB_OT_SHAPE_COMPLEX_USE_MACHINE_HH -#include "hb-private.hh" +#include "hb.hh" %%{ machine use_syllable_machine; @@ -88,22 +88,19 @@ SMAbv = 41; # SYM_MOD_ABOVE SMBlw = 42; # SYM_MOD_BELOW CS = 43; # CONS_WITH_STACKER +HVM = 44; # HALANT_OR_VOWEL_MODIFIER + +h = H | HVM; # https://github.com/harfbuzz/harfbuzz/issues/1102 # Override: Adhoc ZWJ placement. https://github.com/harfbuzz/harfbuzz/issues/542#issuecomment-353169729 -consonant_modifiers = CMAbv* CMBlw* ((ZWJ?.H.ZWJ? B | SUB) VS? CMAbv? CMBlw*)*; +consonant_modifiers = CMAbv* CMBlw* ((ZWJ?.h.ZWJ? B | SUB) VS? CMAbv? CMBlw*)*; # Override: Allow two MBlw. https://github.com/harfbuzz/harfbuzz/issues/376 medial_consonants = MPre? MAbv? MBlw?.MBlw? MPst?; dependent_vowels = VPre* VAbv* VBlw* VPst*; -vowel_modifiers = VMPre* VMAbv* VMBlw* VMPst*; +vowel_modifiers = HVM? VMPre* VMAbv* VMBlw* VMPst*; final_consonants = FAbv* FBlw* FPst* FM?; -virama_terminated_cluster = - (R|CS)? (B | GB) VS? - consonant_modifiers - ZWJ?.H.ZWJ? -; -standard_cluster = - (R|CS)? (B | GB) VS? +complex_syllable_tail = consonant_modifiers medial_consonants dependent_vowels @@ -111,13 +108,18 @@ standard_cluster = final_consonants ; +virama_terminated_cluster = + (R|CS)? (B | GB) VS? + consonant_modifiers + ZWJ?.h.ZWJ? +; +standard_cluster = + (R|CS)? (B | GB) VS? + complex_syllable_tail +; broken_cluster = R? - consonant_modifiers - medial_consonants - dependent_vowels - vowel_modifiers - final_consonants + complex_syllable_tail ; number_joiner_terminated_cluster = N VS? (HN N VS?)* HN; @@ -142,10 +144,9 @@ main := |* #define found_syllable(syllable_type) \ HB_STMT_START { \ - if (0) fprintf (stderr, "syllable %d..%d %s\n", last, p+1, #syllable_type); \ - for (unsigned int i = last; i < p+1; i++) \ + if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \ + for (unsigned int i = ts; i < te; i++) \ info[i].syllable() = (syllable_serial << 4) | syllable_type; \ - last = p+1; \ syllable_serial++; \ if (unlikely (syllable_serial == 16)) syllable_serial = 1; \ } HB_STMT_END @@ -153,7 +154,7 @@ main := |* static void find_syllables (hb_buffer_t *buffer) { - unsigned int p, pe, eof, ts HB_UNUSED, te, act; + unsigned int p, pe, eof, ts, te, act; int cs; hb_glyph_info_t *info = buffer->info; %%{ @@ -164,7 +165,6 @@ find_syllables (hb_buffer_t *buffer) p = 0; pe = eof = buffer->len; - unsigned int last = 0; unsigned int syllable_serial = 1; %%{ write exec; diff --git a/src/hb-ot-shape-complex-use-table.cc b/src/hb-ot-shape-complex-use-table.cc index 9c796f051..e9c88aec4 100644 --- a/src/hb-ot-shape-complex-use-table.cc +++ b/src/hb-ot-shape-complex-use-table.cc @@ -15,7 +15,7 @@ * UnicodeData.txt does not have a header. */ -#include "hb-ot-shape-complex-use-private.hh" +#include "hb-ot-shape-complex-use.hh" #define B USE_B /* BASE */ #define CGJ USE_CGJ /* CGJ */ @@ -24,6 +24,7 @@ #define GB USE_GB /* BASE_OTHER */ #define H USE_H /* HALANT */ #define HN USE_HN /* HALANT_NUM */ +#define HVM USE_HVM /* HALANT_OR_VOWEL_MODIFIER */ #define IND USE_IND /* BASE_IND */ #define N USE_N /* BASE_NUM */ #define O USE_O /* OTHER */ @@ -101,7 +102,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 0990 */ B, O, O, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 09A0 */ B, B, B, B, B, B, B, B, B, O, B, B, B, B, B, B, /* 09B0 */ B, O, B, O, O, O, B, B, B, B, O, O, CMBlw, B, VPst, VPre, - /* 09C0 */ VPst, VBlw, VBlw, VBlw, VBlw, O, O, VPre, VPre, O, O, VPre, VPre, H, IND, O, + /* 09C0 */ VPst, VBlw, VBlw, VBlw, VBlw, O, O, VPre, VPre, O, O, VPst, VPst, H, IND, O, /* 09D0 */ O, O, O, O, O, O, O, VPst, O, O, O, O, B, B, O, B, /* 09E0 */ B, B, VBlw, VBlw, O, O, B, B, B, B, B, B, B, B, B, B, /* 09F0 */ B, B, O, O, O, O, O, O, O, O, O, O, B, O, FM, O, @@ -134,7 +135,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 0B10 */ B, O, O, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 0B20 */ B, B, B, B, B, B, B, B, B, O, B, B, B, B, B, B, /* 0B30 */ B, O, B, B, O, B, B, B, B, B, O, O, CMBlw, B, VPst, VAbv, - /* 0B40 */ VPst, VBlw, VBlw, VBlw, VBlw, O, O, VPre, VPre, O, O, VPre, VPre, H, O, O, + /* 0B40 */ VPst, VBlw, VBlw, VBlw, VBlw, O, O, VPre, VPst, O, O, VPst, VPst, H, O, O, /* 0B50 */ O, O, O, O, O, O, VAbv, VAbv, O, O, O, O, B, B, O, B, /* 0B60 */ B, B, VBlw, VBlw, O, O, B, B, B, B, B, B, B, B, B, B, /* 0B70 */ O, B, O, O, O, O, O, O, O, O, O, O, O, O, O, O, @@ -145,7 +146,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 0B90 */ B, O, B, B, B, B, O, O, O, B, B, O, B, O, B, B, /* 0BA0 */ O, O, O, B, B, O, O, O, B, B, B, O, O, O, B, B, /* 0BB0 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, VPst, VPst, - /* 0BC0 */ VAbv, VPst, VPst, O, O, O, VPre, VPre, VPre, O, VPre, VPre, VPre, H, O, O, + /* 0BC0 */ VAbv, VPst, VPst, O, O, O, VPre, VPre, VPre, O, VPst, VPst, VPst, H, O, O, /* 0BD0 */ O, O, O, O, O, O, O, VPst, O, O, O, O, O, O, O, O, /* 0BE0 */ O, O, O, O, O, O, B, B, B, B, B, B, B, B, B, B, /* 0BF0 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, @@ -178,7 +179,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 0D10 */ B, O, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 0D20 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 0D30 */ B, B, B, B, B, B, B, B, B, B, B, VAbv, VAbv, B, VPst, VPst, - /* 0D40 */ VPst, VPst, VPst, VBlw, VBlw, O, VPre, VPre, VPre, O, VPre, VPre, VPre, H, R, O, + /* 0D40 */ VPst, VPst, VPst, VBlw, VBlw, O, VPre, VPre, VPre, O, VPst, VPst, VPst, H, R, O, /* 0D50 */ O, O, O, O, IND, IND, IND, VPst, O, O, O, O, O, O, O, B, /* 0D60 */ B, B, VBlw, VBlw, O, O, B, B, B, B, B, B, B, B, B, B, /* 0D70 */ O, O, O, O, O, O, O, O, O, O, IND, IND, IND, IND, IND, IND, @@ -190,11 +191,28 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 0DA0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 0DB0 */ B, B, O, B, B, B, B, B, B, B, B, B, O, B, O, O, /* 0DC0 */ B, B, B, B, B, B, B, O, O, O, H, O, O, O, O, VPst, - /* 0DD0 */ VPst, VPst, VAbv, VAbv, VBlw, O, VBlw, O, VPst, VPre, VPre, VPre, VPre, VPre, VPre, VPst, + /* 0DD0 */ VPst, VPst, VAbv, VAbv, VBlw, O, VBlw, O, VPst, VPre, VPst, VPre, VPst, VPst, VPst, VPst, /* 0DE0 */ O, O, O, O, O, O, B, B, B, B, B, B, B, B, B, B, /* 0DF0 */ O, O, VPst, VPst, O, O, O, O, -#define use_offset_0x1000u 1360 +#define use_offset_0x0f18u 1360 + + + /* Tibetan */ + VBlw, VBlw, O, O, O, O, O, O, + /* 0F20 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, + /* 0F30 */ B, B, B, B, O, FM, O, FM, O, CMAbv, O, O, O, O, VPst, VPre, + /* 0F40 */ B, B, B, B, B, B, B, B, O, B, B, B, B, B, B, B, + /* 0F50 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, + /* 0F60 */ B, B, B, B, B, B, B, B, B, B, B, B, B, O, O, O, + /* 0F70 */ O, VBlw, VBlw, VAbv, VBlw, VBlw, VAbv, VAbv, VAbv, VAbv, VBlw, VBlw, VBlw, VBlw, VMAbv, VMPst, + /* 0F80 */ VBlw, VAbv, VMAbv, VMAbv, VBlw, IND, VMAbv, VMAbv, B, B, B, B, B, SUB, SUB, SUB, + /* 0F90 */ SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, O, SUB, SUB, SUB, SUB, SUB, SUB, SUB, + /* 0FA0 */ SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, + /* 0FB0 */ SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, O, O, O, + /* 0FC0 */ O, O, O, O, O, O, FM, O, + +#define use_offset_0x1000u 1536 /* Myanmar */ @@ -210,7 +228,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 1080 */ B, B, MBlw, VPst, VPre, VAbv, VAbv, VMPst, VMPst, VMPst, VMPst, VMPst, VMPst, VMBlw, B, VMPst, /* 1090 */ B, B, B, B, B, B, B, B, B, B, VMPst, VMPst, VPst, VAbv, O, O, -#define use_offset_0x1700u 1520 +#define use_offset_0x1700u 1696 /* Tagalog */ @@ -238,12 +256,12 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 1780 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 1790 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 17A0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, - /* 17B0 */ B, B, B, B, O, O, VPst, VAbv, VAbv, VAbv, VAbv, VBlw, VBlw, VBlw, VPre, VPre, - /* 17C0 */ VPre, VPre, VPre, VPre, VPre, VPre, VMAbv, VMPst, VPst, VMAbv, VMAbv, FM, FAbv, CMAbv, FM, FM, + /* 17B0 */ B, B, B, B, O, O, VPst, VAbv, VAbv, VAbv, VAbv, VBlw, VBlw, VBlw, VPst, VPst, + /* 17C0 */ VPst, VPre, VPre, VPre, VPst, VPst, VMAbv, VMPst, VPst, VMAbv, VMAbv, FM, FAbv, CMAbv, FM, FM, /* 17D0 */ FM, VAbv, H, FM, O, O, O, O, O, O, O, O, B, VAbv, O, O, /* 17E0 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O, -#define use_offset_0x1900u 1760 +#define use_offset_0x1900u 1936 /* Limbu */ @@ -287,7 +305,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 1A80 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O, /* 1A90 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O, -#define use_offset_0x1b00u 2176 +#define use_offset_0x1b00u 2352 /* Balinese */ @@ -296,7 +314,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 1B10 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 1B20 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 1B30 */ B, B, B, B, CMAbv, VPst, VAbv, VAbv, VBlw, VBlw, VBlw, VBlw, VAbv, VAbv, VPre, VPre, - /* 1B40 */ VPre, VPre, VAbv, VAbv, H, B, B, B, B, B, B, B, O, O, O, O, + /* 1B40 */ VPst, VPst, VAbv, VAbv, H, B, B, B, B, B, B, B, O, O, O, O, /* 1B50 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O, /* 1B60 */ O, O, O, O, O, O, O, O, O, O, O, SMAbv, SMBlw, SMAbv, SMAbv, SMAbv, /* 1B70 */ SMAbv, SMAbv, SMAbv, SMAbv, O, O, O, O, O, O, O, O, O, O, O, O, @@ -319,11 +337,11 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 1C00 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 1C10 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, - /* 1C20 */ B, B, B, B, SUB, SUB, VPst, VPre, VPre, VPre, VPst, VPst, VBlw, FAbv, FAbv, FAbv, + /* 1C20 */ B, B, B, B, SUB, SUB, VPst, VPre, VPre, VPst, VPst, VPst, VBlw, FAbv, FAbv, FAbv, /* 1C30 */ FAbv, FAbv, FAbv, FAbv, VMPre, VMPre, FM, CMBlw, O, O, O, O, O, O, O, O, /* 1C40 */ B, B, B, B, B, B, B, B, B, B, O, O, O, B, B, B, -#define use_offset_0x1cd0u 2512 +#define use_offset_0x1cd0u 2688 /* Vedic Extensions */ @@ -332,20 +350,20 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 1CE0 */ VMAbv, VMPst, VMBlw, VMBlw, VMBlw, VMBlw, VMBlw, VMBlw, VMBlw, O, O, O, O, VMBlw, O, O, /* 1CF0 */ O, O, VMPst, VMPst, VMAbv, CS, CS, VMPst, VMAbv, VMAbv, O, O, O, O, O, O, -#define use_offset_0x1df8u 2560 +#define use_offset_0x1df8u 2736 /* Combining Diacritical Marks Supplement */ O, O, O, FM, O, O, O, O, -#define use_offset_0x2008u 2568 +#define use_offset_0x2008u 2744 /* General Punctuation */ O, O, O, O, ZWNJ, ZWJ, O, O, /* 2010 */ GB, GB, GB, GB, GB, O, O, O, -#define use_offset_0x2060u 2584 +#define use_offset_0x2060u 2760 /* 2060 */ WJ, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, @@ -354,20 +372,20 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 2070 */ O, O, O, O, FM, O, O, O, O, O, O, O, O, O, O, O, /* 2080 */ O, O, FM, FM, FM, O, O, O, -#define use_offset_0x20f0u 2624 +#define use_offset_0x20f0u 2800 /* Combining Diacritical Marks for Symbols */ /* 20F0 */ VMAbv, O, O, O, O, O, O, O, -#define use_offset_0x25c8u 2632 +#define use_offset_0x25c8u 2808 /* Geometric Shapes */ O, O, O, O, GB, O, O, O, -#define use_offset_0xa800u 2640 +#define use_offset_0xa800u 2816 /* Syloti Nagri */ @@ -454,7 +472,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* AAE0 */ B, B, B, B, B, B, B, B, B, B, B, VPre, VBlw, VAbv, VPre, VPst, /* AAF0 */ O, O, O, O, O, VMPst, H, O, -#define use_offset_0xabc0u 3400 +#define use_offset_0xabc0u 3576 /* Meetei Mayek */ @@ -464,14 +482,14 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* ABE0 */ B, B, B, VPst, VPst, VAbv, VPst, VPst, VBlw, VPst, VPst, O, VMPst, VBlw, O, O, /* ABF0 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O, -#define use_offset_0xfe00u 3464 +#define use_offset_0xfe00u 3640 /* Variation Selectors */ /* FE00 */ VS, VS, VS, VS, VS, VS, VS, VS, VS, VS, VS, VS, VS, VS, VS, VS, -#define use_offset_0x10a00u 3480 +#define use_offset_0x10a00u 3656 /* Kharoshthi */ @@ -482,7 +500,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 10A30 */ B, B, B, B, B, B, O, O, CMAbv, CMBlw, CMBlw, O, O, O, O, H, /* 10A40 */ B, B, B, B, B, B, B, B, B, O, O, O, O, O, O, O, -#define use_offset_0x11000u 3560 +#define use_offset_0x11000u 3736 /* Brahmi */ @@ -491,7 +509,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 11010 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 11020 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 11030 */ B, B, B, B, B, B, B, B, VAbv, VAbv, VAbv, VAbv, VBlw, VBlw, VBlw, VBlw, - /* 11040 */ VBlw, VBlw, VAbv, VAbv, VAbv, VAbv, H, O, O, O, O, O, O, O, O, O, + /* 11040 */ VBlw, VBlw, VAbv, VAbv, VAbv, VAbv, HVM, O, O, O, O, O, O, O, O, O, /* 11050 */ O, O, N, N, N, N, N, N, N, N, N, N, N, N, N, N, /* 11060 */ N, N, N, N, N, N, B, B, B, B, B, B, B, B, B, B, /* 11070 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, HN, @@ -503,7 +521,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 110A0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 110B0 */ VPst, VPre, VPst, VBlw, VBlw, VAbv, VAbv, VPst, VPst, H, CMBlw, O, O, O, O, O, -#define use_offset_0x11100u 3752 +#define use_offset_0x11100u 3928 /* Chakma */ @@ -511,7 +529,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 11100 */ VMAbv, VMAbv, VMAbv, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 11110 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 11120 */ B, B, B, B, B, B, B, VBlw, VBlw, VBlw, VAbv, VAbv, VPre, VBlw, VAbv, VAbv, - /* 11130 */ VBlw, VAbv, VAbv, H, CMAbv, O, B, B, B, B, B, B, B, B, B, B, + /* 11130 */ VBlw, VAbv, VAbv, H, CMBlw, O, B, B, B, B, B, B, B, B, B, B, /* 11140 */ O, O, O, O, B, VPst, VPst, O, O, O, O, O, O, O, O, O, /* Mahajani */ @@ -541,7 +559,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 11220 */ B, B, B, B, B, B, B, B, B, B, B, B, VPst, VPst, VPst, VBlw, /* 11230 */ VAbv, VAbv, VAbv, VAbv, VMAbv, H, CMAbv, CMAbv, O, O, O, O, O, O, VMAbv, O, -#define use_offset_0x11280u 4072 +#define use_offset_0x11280u 4248 /* Multani */ @@ -564,12 +582,12 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 11310 */ B, O, O, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 11320 */ B, B, B, B, B, B, B, B, B, O, B, B, B, B, B, B, /* 11330 */ B, O, B, B, O, B, B, B, B, B, O, CMBlw, CMBlw, B, VPst, VPst, - /* 11340 */ VAbv, VPst, VPst, VPst, VPst, O, O, VPre, VPre, O, O, VPre, VPre, H, O, O, + /* 11340 */ VAbv, VPst, VPst, VPst, VPst, O, O, VPre, VPre, O, O, VPst, VPst, H, O, O, /* 11350 */ O, O, O, O, O, O, O, VPst, O, O, O, O, O, O, B, B, /* 11360 */ B, B, VPst, VPst, O, O, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, O, O, O, /* 11370 */ VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, O, O, O, -#define use_offset_0x11400u 4320 +#define use_offset_0x11400u 4496 /* Newa */ @@ -588,11 +606,11 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 11480 */ O, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 11490 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 114A0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, - /* 114B0 */ VPst, VPre, VPst, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VPre, VAbv, VPre, VPre, VPst, VPre, VMAbv, + /* 114B0 */ VPst, VPre, VPst, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VPre, VAbv, VPst, VPst, VPst, VPst, VMAbv, /* 114C0 */ VMAbv, VMPst, H, CMBlw, B, O, O, O, O, O, O, O, O, O, O, O, /* 114D0 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O, -#define use_offset_0x11580u 4544 +#define use_offset_0x11580u 4720 /* Siddham */ @@ -600,7 +618,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 11580 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 11590 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 115A0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, VPst, - /* 115B0 */ VPre, VPst, VBlw, VBlw, VBlw, VBlw, O, O, VPre, VPre, VPre, VPre, VMAbv, VMAbv, VMPst, H, + /* 115B0 */ VPre, VPst, VBlw, VBlw, VBlw, VBlw, O, O, VPre, VPst, VPst, VPst, VMAbv, VMAbv, VMPst, H, /* 115C0 */ CMBlw, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, /* 115D0 */ O, O, O, O, O, O, O, O, B, B, B, B, VBlw, VBlw, O, O, /* 115E0 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, @@ -635,7 +653,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 11720 */ VPst, VPst, VAbv, VAbv, VBlw, VBlw, VPre, VAbv, VBlw, VAbv, VAbv, VAbv, O, O, O, O, /* 11730 */ B, B, B, B, B, B, B, B, B, B, B, B, O, O, O, O, -#define use_offset_0x11800u 4992 +#define use_offset_0x11800u 5168 /* Dogra */ @@ -645,7 +663,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 11820 */ B, B, B, B, B, B, B, B, B, B, B, B, VPst, VPre, VPst, VBlw, /* 11830 */ VBlw, VBlw, VBlw, VAbv, VAbv, VAbv, VAbv, VMAbv, VMPst, H, CMBlw, O, O, O, O, O, -#define use_offset_0x11a00u 5056 +#define use_offset_0x11a00u 5232 /* Zanabazar Square */ @@ -664,7 +682,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 11A80 */ B, B, B, B, O, O, R, R, R, R, FBlw, FBlw, FBlw, FBlw, FBlw, FBlw, /* 11A90 */ FBlw, FBlw, FBlw, FBlw, FBlw, FBlw, VMAbv, VMPst, CMAbv, H, O, O, O, B, O, O, -#define use_offset_0x11c00u 5216 +#define use_offset_0x11c00u 5392 /* Bhaiksuki */ @@ -685,7 +703,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 11CA0 */ SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, O, SUB, SUB, SUB, SUB, SUB, SUB, SUB, /* 11CB0 */ VBlw, VPre, VBlw, VAbv, VPst, VMAbv, VMAbv, O, -#define use_offset_0x11d00u 5400 +#define use_offset_0x11d00u 5576 /* Masaram Gondi */ @@ -705,7 +723,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 11D90 */ VAbv, VAbv, O, VPst, VPst, VMAbv, VMPst, H, O, O, O, O, O, O, O, O, /* 11DA0 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O, -#define use_offset_0x11ee0u 5576 +#define use_offset_0x11ee0u 5752 /* Makasar */ @@ -713,7 +731,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 11EE0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 11EF0 */ B, B, GB, VAbv, VBlw, VPre, VPst, O, -}; /* Table items: 5600; occupancy: 73% */ +}; /* Table items: 5776; occupancy: 74% */ USE_TABLE_ELEMENT_TYPE hb_use_get_category (hb_codepoint_t u) @@ -725,6 +743,7 @@ hb_use_get_category (hb_codepoint_t u) if (hb_in_range<hb_codepoint_t> (u, 0x00A0u, 0x00D7u)) return use_table[u - 0x00A0u + use_offset_0x00a0u]; if (hb_in_range<hb_codepoint_t> (u, 0x0348u, 0x034Fu)) return use_table[u - 0x0348u + use_offset_0x0348u]; if (hb_in_range<hb_codepoint_t> (u, 0x0900u, 0x0DF7u)) return use_table[u - 0x0900u + use_offset_0x0900u]; + if (hb_in_range<hb_codepoint_t> (u, 0x0F18u, 0x0FC7u)) return use_table[u - 0x0F18u + use_offset_0x0f18u]; break; case 0x1u: @@ -782,6 +801,7 @@ hb_use_get_category (hb_codepoint_t u) #undef GB #undef H #undef HN +#undef HVM #undef IND #undef N #undef O diff --git a/src/hb-ot-shape-complex-use.cc b/src/hb-ot-shape-complex-use.cc index f8e86c9d6..f9a580ca2 100644 --- a/src/hb-ot-shape-complex-use.cc +++ b/src/hb-ot-shape-complex-use.cc @@ -26,8 +26,8 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-ot-shape-complex-use-private.hh" -#include "hb-ot-shape-complex-arabic-private.hh" +#include "hb-ot-shape-complex-use.hh" +#include "hb-ot-shape-complex-arabic.hh" /* buffer var allocations */ #define use_category() complex_var_u8_0() @@ -86,7 +86,14 @@ other_features[] = HB_TAG('h','a','l','n'), HB_TAG('p','r','e','s'), HB_TAG('p','s','t','s'), - /* Positioning features, though we don't care about the types. */ +}; +static const hb_tag_t +positioning_features[] = +{ + /* + * Positioning features. + * We don't care about the types. + */ HB_TAG('d','i','s','t'), HB_TAG('a','b','v','m'), HB_TAG('b','l','w','m'), @@ -122,33 +129,37 @@ collect_features_use (hb_ot_shape_planner_t *plan) map->add_gsub_pause (setup_syllables); /* "Default glyph pre-processing group" */ - map->add_global_bool_feature (HB_TAG('l','o','c','l')); - map->add_global_bool_feature (HB_TAG('c','c','m','p')); - map->add_global_bool_feature (HB_TAG('n','u','k','t')); - map->add_global_bool_feature (HB_TAG('a','k','h','n')); + map->enable_feature (HB_TAG('l','o','c','l')); + map->enable_feature (HB_TAG('c','c','m','p')); + map->enable_feature (HB_TAG('n','u','k','t')); + map->enable_feature (HB_TAG('a','k','h','n'), F_MANUAL_ZWJ); /* "Reordering group" */ map->add_gsub_pause (clear_substitution_flags); - map->add_feature (HB_TAG('r','p','h','f'), 1, F_MANUAL_ZWJ); + map->add_feature (HB_TAG('r','p','h','f'), F_MANUAL_ZWJ); map->add_gsub_pause (record_rphf); map->add_gsub_pause (clear_substitution_flags); - map->add_feature (HB_TAG('p','r','e','f'), 1, F_GLOBAL | F_MANUAL_ZWJ); + map->enable_feature (HB_TAG('p','r','e','f'), F_MANUAL_ZWJ); map->add_gsub_pause (record_pref); /* "Orthographic unit shaping group" */ for (unsigned int i = 0; i < ARRAY_LENGTH (basic_features); i++) - map->add_feature (basic_features[i], 1, F_GLOBAL | F_MANUAL_ZWJ); + map->enable_feature (basic_features[i], F_MANUAL_ZWJ); map->add_gsub_pause (reorder); /* "Topographical features" */ for (unsigned int i = 0; i < ARRAY_LENGTH (arabic_features); i++) - map->add_feature (arabic_features[i], 1, F_NONE); + map->add_feature (arabic_features[i]); map->add_gsub_pause (nullptr); - /* "Standard typographic presentation" and "Positional feature application" */ + /* "Standard typographic presentation" */ for (unsigned int i = 0; i < ARRAY_LENGTH (other_features); i++) - map->add_feature (other_features[i], 1, F_GLOBAL | F_MANUAL_ZWJ); + map->enable_feature (other_features[i], F_MANUAL_ZWJ); + + /* "Positional feature application" */ + for (unsigned int i = 0; i < ARRAY_LENGTH (positioning_features); i++) + map->enable_feature (positioning_features[i]); } struct use_shape_plan_t @@ -586,7 +597,7 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_use = nullptr, /* decompose */ compose_use, setup_masks_use, - nullptr, /* disable_otl */ + HB_TAG_NONE, /* gpos_tag */ nullptr, /* reorder_marks */ HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY, false, /* fallback_position */ diff --git a/src/hb-ot-shape-complex-use-private.hh b/src/hb-ot-shape-complex-use.hh index b4bda8bb7..ab56e1b8f 100644 --- a/src/hb-ot-shape-complex-use-private.hh +++ b/src/hb-ot-shape-complex-use.hh @@ -26,13 +26,13 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_OT_SHAPE_COMPLEX_USE_PRIVATE_HH -#define HB_OT_SHAPE_COMPLEX_USE_PRIVATE_HH +#ifndef HB_OT_SHAPE_COMPLEX_USE_HH +#define HB_OT_SHAPE_COMPLEX_USE_HH -#include "hb-private.hh" +#include "hb.hh" -#include "hb-ot-shape-complex-private.hh" +#include "hb-ot-shape-complex.hh" #define USE_TABLE_ELEMENT_TYPE uint8_t @@ -88,10 +88,13 @@ enum use_category_t { USE_VMPre = 23, /* VOWEL_MOD_PRE */ USE_SMAbv = 41, /* SYM_MOD_ABOVE */ USE_SMBlw = 42, /* SYM_MOD_BELOW */ - USE_CS = 43 /* CONS_WITH_STACKER */ + USE_CS = 43, /* CONS_WITH_STACKER */ + + /* https://github.com/harfbuzz/harfbuzz/issues/1102 */ + USE_HVM = 44, /* HALANT_OR_VOWEL_MODIFIER */ }; HB_INTERNAL USE_TABLE_ELEMENT_TYPE hb_use_get_category (hb_codepoint_t u); -#endif /* HB_OT_SHAPE_COMPLEX_USE_PRIVATE_HH */ +#endif /* HB_OT_SHAPE_COMPLEX_USE_HH */ diff --git a/src/hb-ot-shape-complex-private.hh b/src/hb-ot-shape-complex.hh index 37a4d918b..2944d745c 100644 --- a/src/hb-ot-shape-complex-private.hh +++ b/src/hb-ot-shape-complex.hh @@ -24,14 +24,14 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_OT_SHAPE_COMPLEX_PRIVATE_HH -#define HB_OT_SHAPE_COMPLEX_PRIVATE_HH +#ifndef HB_OT_SHAPE_COMPLEX_HH +#define HB_OT_SHAPE_COMPLEX_HH -#include "hb-private.hh" - -#include "hb-ot-shape-private.hh" -#include "hb-ot-shape-normalize-private.hh" +#include "hb.hh" +#include "hb-ot-layout.hh" +#include "hb-ot-shape.hh" +#include "hb-ot-shape-normalize.hh" /* buffer var allocations, used by complex shapers */ @@ -58,8 +58,8 @@ enum hb_ot_shape_zero_width_marks_type_t { HB_COMPLEX_SHAPER_IMPLEMENT (khmer) \ HB_COMPLEX_SHAPER_IMPLEMENT (myanmar) \ HB_COMPLEX_SHAPER_IMPLEMENT (myanmar_old) \ + HB_COMPLEX_SHAPER_IMPLEMENT (myanmar_zawgyi) \ HB_COMPLEX_SHAPER_IMPLEMENT (thai) \ - HB_COMPLEX_SHAPER_IMPLEMENT (tibetan) \ HB_COMPLEX_SHAPER_IMPLEMENT (use) \ /* ^--- Add new shapers here */ @@ -69,7 +69,7 @@ struct hb_ot_complex_shaper_t /* collect_features() * Called during shape_plan(). * Shapers should use plan->map to add their features and callbacks. - * May be nullptr. + * May be NULL. */ void (*collect_features) (hb_ot_shape_planner_t *plan); @@ -77,7 +77,7 @@ struct hb_ot_complex_shaper_t * Called during shape_plan(). * Shapers should use plan->map to override features and add callbacks after * common features are added. - * May be nullptr. + * May be NULL. */ void (*override_features) (hb_ot_shape_planner_t *plan); @@ -93,7 +93,7 @@ struct hb_ot_complex_shaper_t * Called when the shape_plan is being destroyed. * plan->data is passed here for destruction. * If nullptr is returned, means a plan failure. - * May be nullptr. + * May be NULL. */ void (*data_destroy) (void *data); @@ -101,7 +101,7 @@ struct hb_ot_complex_shaper_t /* preprocess_text() * Called during shape(). * Shapers can use to modify text before shaping starts. - * May be nullptr. + * May be NULL. */ void (*preprocess_text) (const hb_ot_shape_plan_t *plan, hb_buffer_t *buffer, @@ -110,7 +110,7 @@ struct hb_ot_complex_shaper_t /* postprocess_glyphs() * Called during shape(). * Shapers can use to modify glyphs after shaping ends. - * May be nullptr. + * May be NULL. */ void (*postprocess_glyphs) (const hb_ot_shape_plan_t *plan, hb_buffer_t *buffer, @@ -121,7 +121,7 @@ struct hb_ot_complex_shaper_t /* decompose() * Called during shape()'s normalization. - * May be nullptr. + * May be NULL. */ bool (*decompose) (const hb_ot_shape_normalize_context_t *c, hb_codepoint_t ab, @@ -130,7 +130,7 @@ struct hb_ot_complex_shaper_t /* compose() * Called during shape()'s normalization. - * May be nullptr. + * May be NULL. */ bool (*compose) (const hb_ot_shape_normalize_context_t *c, hb_codepoint_t a, @@ -141,24 +141,22 @@ struct hb_ot_complex_shaper_t * Called during shape(). * Shapers should use map to get feature masks and set on buffer. * Shapers may NOT modify characters. - * May be nullptr. + * May be NULL. */ void (*setup_masks) (const hb_ot_shape_plan_t *plan, hb_buffer_t *buffer, hb_font_t *font); - /* disable_otl() - * Called during shape(). - * If set and returns true, GDEF/GSUB/GPOS of the font are ignored - * and fallback operations used. - * May be nullptr. + /* gpos_tag() + * If not HB_TAG_NONE, then must match found GPOS script tag for + * GPOS to be applied. Otherwise, fallback positioning will be used. */ - bool (*disable_otl) (const hb_ot_shape_plan_t *plan); + hb_tag_t gpos_tag; /* reorder_marks() * Called during shape(). * Shapers can use to modify ordering of combining marks. - * May be nullptr. + * May be NULL. */ void (*reorder_marks) (const hb_ot_shape_plan_t *plan, hb_buffer_t *buffer, @@ -234,25 +232,12 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner) return &_hb_ot_complex_shaper_hangul; - /* Unicode-2.0 additions */ - case HB_SCRIPT_TIBETAN: - - return &_hb_ot_complex_shaper_tibetan; - - /* Unicode-1.1 additions */ case HB_SCRIPT_HEBREW: return &_hb_ot_complex_shaper_hebrew; - /* ^--- Add new shapers here */ - -#if 0 - /* Unicode-4.1 additions */ - case HB_SCRIPT_NEW_TAI_LUE: -#endif - /* Unicode-1.1 additions */ case HB_SCRIPT_BENGALI: case HB_SCRIPT_DEVANAGARI: @@ -270,11 +255,13 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner) /* If the designer designed the font for the 'DFLT' script, * (or we ended up arbitrarily pick 'latn'), use the default shaper. * Otherwise, use the specific shaper. - * Note that for some simple scripts, there may not be *any* - * GSUB/GPOS needed, so there may be no scripts found! */ + * + * If it's indy3 tag, send to USE. */ if (planner->map.chosen_script[0] == HB_TAG ('D','F','L','T') || planner->map.chosen_script[0] == HB_TAG ('l','a','t','n')) return &_hb_ot_complex_shaper_default; + else if ((planner->map.chosen_script[0] & 0x000000FF) == '3') + return &_hb_ot_complex_shaper_use; else return &_hb_ot_complex_shaper_indic; @@ -291,7 +278,7 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner) /* Unicode-2.0 additions */ - //case HB_SCRIPT_TIBETAN: + case HB_SCRIPT_TIBETAN: /* Unicode-3.0 additions */ //case HB_SCRIPT_MONGOLIAN: @@ -359,9 +346,9 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner) /* Unicode-8.0 additions */ case HB_SCRIPT_AHOM: - //case HB_SCRIPT_MULTANI: /* Unicode-9.0 additions */ + //case HB_SCRIPT_ADLAM: case HB_SCRIPT_BHAIKSUKI: case HB_SCRIPT_MARCHEN: case HB_SCRIPT_NEWA: @@ -374,7 +361,9 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner) /* Unicode-11.0 additions */ case HB_SCRIPT_DOGRA: case HB_SCRIPT_GUNJALA_GONDI: + //case HB_SCRIPT_HANIFI_ROHINGYA: case HB_SCRIPT_MAKASAR: + //case HB_SCRIPT_SOGDIAN: /* If the designer designed the font for the 'DFLT' script, * (or we ended up arbitrarily pick 'latn'), use the default shaper. @@ -386,8 +375,12 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner) return &_hb_ot_complex_shaper_default; else return &_hb_ot_complex_shaper_use; + + /* https://github.com/harfbuzz/harfbuzz/issues/1162 */ + case HB_SCRIPT_MYANMAR_ZAWGYI: + return &_hb_ot_complex_shaper_myanmar_zawgyi; } } -#endif /* HB_OT_SHAPE_COMPLEX_PRIVATE_HH */ +#endif /* HB_OT_SHAPE_COMPLEX_HH */ diff --git a/src/hb-ot-shape-fallback.cc b/src/hb-ot-shape-fallback.cc index fbf31ab24..4c5ccc974 100644 --- a/src/hb-ot-shape-fallback.cc +++ b/src/hb-ot-shape-fallback.cc @@ -24,8 +24,8 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-ot-shape-fallback-private.hh" -#include "hb-ot-layout-gsubgpos-private.hh" +#include "hb-ot-shape-fallback.hh" +#include "hb-ot-kern-table.hh" static unsigned int recategorize_combining_class (hb_codepoint_t u, @@ -162,9 +162,9 @@ recategorize_combining_class (hb_codepoint_t u, } void -_hb_ot_shape_fallback_position_recategorize_marks (const hb_ot_shape_plan_t *plan HB_UNUSED, - hb_font_t *font HB_UNUSED, - hb_buffer_t *buffer) +_hb_ot_shape_fallback_mark_position_recategorize_marks (const hb_ot_shape_plan_t *plan HB_UNUSED, + hb_font_t *font HB_UNUSED, + hb_buffer_t *buffer) { unsigned int count = buffer->len; hb_glyph_info_t *info = buffer->info; @@ -417,9 +417,9 @@ position_cluster (const hb_ot_shape_plan_t *plan, } void -_hb_ot_shape_fallback_position (const hb_ot_shape_plan_t *plan, - hb_font_t *font, - hb_buffer_t *buffer) +_hb_ot_shape_fallback_mark_position (const hb_ot_shape_plan_t *plan, + hb_font_t *font, + hb_buffer_t *buffer) { _hb_buffer_assert_gsubgpos_vars (buffer); @@ -435,60 +435,38 @@ _hb_ot_shape_fallback_position (const hb_ot_shape_plan_t *plan, } -/* Performs old-style TrueType kerning. */ -void -_hb_ot_shape_fallback_kern (const hb_ot_shape_plan_t *plan, - hb_font_t *font, - hb_buffer_t *buffer) +struct hb_ot_shape_fallback_kern_driver_t { - if (!plan->has_kern) return; + hb_ot_shape_fallback_kern_driver_t (hb_font_t *font_, + hb_buffer_t *buffer) : + font (font_), direction (buffer->props.direction) {} - OT::hb_ot_apply_context_t c (1, font, buffer); - c.set_lookup_mask (plan->kern_mask); - c.set_lookup_props (OT::LookupFlag::IgnoreMarks); - OT::hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c.iter_input; - skippy_iter.init (&c); - - unsigned int count = buffer->len; - hb_glyph_info_t *info = buffer->info; - hb_glyph_position_t *pos = buffer->pos; - for (unsigned int idx = 0; idx < count;) + hb_position_t get_kerning (hb_codepoint_t first, hb_codepoint_t second) const { - skippy_iter.reset (idx, 1); - if (!skippy_iter.next ()) - { - idx++; - continue; - } - - hb_position_t x_kern, y_kern; - font->get_glyph_kerning_for_direction (info[idx].codepoint, - info[skippy_iter.idx].codepoint, - buffer->props.direction, - &x_kern, &y_kern); - - if (x_kern) - { - hb_position_t kern1 = x_kern >> 1; - hb_position_t kern2 = x_kern - kern1; - pos[idx].x_advance += kern1; - pos[skippy_iter.idx].x_advance += kern2; - pos[skippy_iter.idx].x_offset += kern2; - buffer->unsafe_to_break (idx, skippy_iter.idx + 1); - } + hb_position_t kern = 0; + font->get_glyph_kerning_for_direction (first, second, + direction, + &kern, &kern); + return kern; + } - if (y_kern) - { - hb_position_t kern1 = y_kern >> 1; - hb_position_t kern2 = y_kern - kern1; - pos[idx].y_advance += kern1; - pos[skippy_iter.idx].y_advance += kern2; - pos[skippy_iter.idx].y_offset += kern2; - buffer->unsafe_to_break (idx, skippy_iter.idx + 1); - } + hb_font_t *font; + hb_direction_t direction; +}; - idx = skippy_iter.idx; - } +/* Performs font-assisted kerning. */ +void +_hb_ot_shape_fallback_kern (const hb_ot_shape_plan_t *plan, + hb_font_t *font, + hb_buffer_t *buffer) +{ + if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction) ? + !font->has_glyph_h_kerning_func () : + !font->has_glyph_v_kerning_func ()) + return; + hb_ot_shape_fallback_kern_driver_t driver (font, buffer); + hb_kern_machine_t<hb_ot_shape_fallback_kern_driver_t> machine (driver); + machine.kern (font, buffer, plan->kern_mask, false); } diff --git a/src/hb-ot-shape-fallback-private.hh b/src/hb-ot-shape-fallback.hh index e134224df..12f18ed12 100644 --- a/src/hb-ot-shape-fallback-private.hh +++ b/src/hb-ot-shape-fallback.hh @@ -24,21 +24,21 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_OT_SHAPE_FALLBACK_PRIVATE_HH -#define HB_OT_SHAPE_FALLBACK_PRIVATE_HH +#ifndef HB_OT_SHAPE_FALLBACK_HH +#define HB_OT_SHAPE_FALLBACK_HH -#include "hb-private.hh" +#include "hb.hh" -#include "hb-ot-shape-private.hh" +#include "hb-ot-shape.hh" -HB_INTERNAL void _hb_ot_shape_fallback_position (const hb_ot_shape_plan_t *plan, - hb_font_t *font, - hb_buffer_t *buffer); +HB_INTERNAL void _hb_ot_shape_fallback_mark_position (const hb_ot_shape_plan_t *plan, + hb_font_t *font, + hb_buffer_t *buffer); -HB_INTERNAL void _hb_ot_shape_fallback_position_recategorize_marks (const hb_ot_shape_plan_t *plan, - hb_font_t *font, - hb_buffer_t *buffer); +HB_INTERNAL void _hb_ot_shape_fallback_mark_position_recategorize_marks (const hb_ot_shape_plan_t *plan, + hb_font_t *font, + hb_buffer_t *buffer); HB_INTERNAL void _hb_ot_shape_fallback_kern (const hb_ot_shape_plan_t *plan, @@ -50,4 +50,4 @@ HB_INTERNAL void _hb_ot_shape_fallback_spaces (const hb_ot_shape_plan_t *plan, hb_buffer_t *buffer); -#endif /* HB_OT_SHAPE_FALLBACK_PRIVATE_HH */ +#endif /* HB_OT_SHAPE_FALLBACK_HH */ diff --git a/src/hb-ot-shape-normalize.cc b/src/hb-ot-shape-normalize.cc index 358450ee7..a8229a98d 100644 --- a/src/hb-ot-shape-normalize.cc +++ b/src/hb-ot-shape-normalize.cc @@ -24,9 +24,9 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-ot-shape-normalize-private.hh" -#include "hb-ot-shape-complex-private.hh" -#include "hb-ot-shape-private.hh" +#include "hb-ot-shape-normalize.hh" +#include "hb-ot-shape-complex.hh" +#include "hb-ot-shape.hh" /* @@ -264,15 +264,6 @@ decompose_multi_char_cluster (const hb_ot_shape_normalize_context_t *c, unsigned decompose_current_character (c, short_circuit); } -static inline void -decompose_cluster (const hb_ot_shape_normalize_context_t *c, unsigned int end, bool might_short_circuit, bool always_short_circuit) -{ - if (likely (c->buffer->idx + 1 == end)) - decompose_current_character (c, might_short_circuit); - else - decompose_multi_char_cluster (c, end, always_short_circuit); -} - static int compare_combining_class (const hb_glyph_info_t *pa, const hb_glyph_info_t *pb) @@ -294,6 +285,16 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan, _hb_buffer_assert_unicode_vars (buffer); hb_ot_shape_normalization_mode_t mode = plan->shaper->normalization_preference; + if (mode == HB_OT_SHAPE_NORMALIZATION_MODE_AUTO) + { + if (plan->has_gpos_mark) + // https://github.com/harfbuzz/harfbuzz/issues/653#issuecomment-423905920 + //mode = HB_OT_SHAPE_NORMALIZATION_MODE_DECOMPOSED; + mode = HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS; + else + mode = HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS; + } + const hb_ot_shape_normalize_context_t c = { plan, buffer, @@ -318,105 +319,81 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan, /* First round, decompose */ - buffer->clear_output (); - count = buffer->len; - for (buffer->idx = 0; buffer->idx < count && buffer->successful;) + bool all_simple = true; { - unsigned int end; - for (end = buffer->idx + 1; end < count; end++) - if (likely (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer->info[end])))) - break; + buffer->clear_output (); + count = buffer->len; + buffer->idx = 0; + do + { + unsigned int end; + for (end = buffer->idx + 1; end < count; end++) + if (unlikely (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer->info[end])))) + break; - decompose_cluster (&c, end, might_short_circuit, always_short_circuit); - } - buffer->swap_buffers (); + if (end < count) + end--; /* Leave one base for the marks to cluster with. */ + /* From idx to end are simple clusters. */ + if (might_short_circuit) + { + unsigned int done = font->get_nominal_glyphs (end - buffer->idx, + &buffer->cur().codepoint, + sizeof (buffer->info[0]), + &buffer->cur().glyph_index(), + sizeof (buffer->info[0])); + buffer->next_glyphs (done); + } + while (buffer->idx < end && buffer->successful) + decompose_current_character (&c, might_short_circuit); - /* Second round, reorder (inplace) */ + if (buffer->idx == count || !buffer->successful) + break; - count = buffer->len; - for (unsigned int i = 0; i < count; i++) - { - if (_hb_glyph_info_get_modified_combining_class (&buffer->info[i]) == 0) - continue; + all_simple = false; - unsigned int end; - for (end = i + 1; end < count; end++) - if (_hb_glyph_info_get_modified_combining_class (&buffer->info[end]) == 0) - break; + /* Find all the marks now. */ + for (end = buffer->idx + 1; end < count; end++) + if (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer->info[end]))) + break; - /* We are going to do a O(n^2). Only do this if the sequence is short. */ - if (end - i > HB_OT_SHAPE_COMPLEX_MAX_COMBINING_MARKS) { - i = end; - continue; + /* idx to end is one non-simple cluster. */ + decompose_multi_char_cluster (&c, end, always_short_circuit); } - - buffer->sort (i, end, compare_combining_class); - - if (plan->shaper->reorder_marks) - plan->shaper->reorder_marks (plan, buffer, i, end); - - i = end; + while (buffer->idx < count && buffer->successful); + buffer->swap_buffers (); } - if (mode == HB_OT_SHAPE_NORMALIZATION_MODE_NONE || - mode == HB_OT_SHAPE_NORMALIZATION_MODE_DECOMPOSED) - return; - - /* Third round, recompose */ - - /* As noted in the comment earlier, we don't try to combine - * ccc=0 chars with their previous Starter. */ + /* Second round, reorder (inplace) */ - buffer->clear_output (); - count = buffer->len; - unsigned int starter = 0; - buffer->next_glyph (); - while (buffer->idx < count && buffer->successful) + if (!all_simple) { - hb_codepoint_t composed, glyph; - if (/* We don't try to compose a non-mark character with it's preceding starter. - * This is both an optimization to avoid trying to compose every two neighboring - * glyphs in most scripts AND a desired feature for Hangul. Apparently Hangul - * fonts are not designed to mix-and-match pre-composed syllables and Jamo. */ - HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer->cur()))) + count = buffer->len; + for (unsigned int i = 0; i < count; i++) { - if (/* If there's anything between the starter and this char, they should have CCC - * smaller than this character's. */ - (starter == buffer->out_len - 1 || - info_cc (buffer->prev()) < info_cc (buffer->cur())) && - /* And compose. */ - c.compose (&c, - buffer->out_info[starter].codepoint, - buffer->cur().codepoint, - &composed) && - /* And the font has glyph for the composite. */ - font->get_nominal_glyph (composed, &glyph)) - { - /* Composes. */ - buffer->next_glyph (); /* Copy to out-buffer. */ - if (unlikely (!buffer->successful)) - return; - buffer->merge_out_clusters (starter, buffer->out_len); - buffer->out_len--; /* Remove the second composable. */ - /* Modify starter and carry on. */ - buffer->out_info[starter].codepoint = composed; - buffer->out_info[starter].glyph_index() = glyph; - _hb_glyph_info_set_unicode_props (&buffer->out_info[starter], buffer); + if (_hb_glyph_info_get_modified_combining_class (&buffer->info[i]) == 0) + continue; + + unsigned int end; + for (end = i + 1; end < count; end++) + if (_hb_glyph_info_get_modified_combining_class (&buffer->info[end]) == 0) + break; + /* We are going to do a O(n^2). Only do this if the sequence is short. */ + if (end - i > HB_OT_SHAPE_COMPLEX_MAX_COMBINING_MARKS) { + i = end; continue; } - } - /* Blocked, or doesn't compose. */ - buffer->next_glyph (); + buffer->sort (i, end, compare_combining_class); - if (info_cc (buffer->prev()) == 0) - starter = buffer->out_len - 1; - } - buffer->swap_buffers (); + if (plan->shaper->reorder_marks) + plan->shaper->reorder_marks (plan, buffer, i, end); + i = end; + } + } if (buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_CGJ) { /* For all CGJ, check if it prevented any reordering at all. @@ -430,4 +407,63 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan, _hb_glyph_info_unhide (&buffer->info[i]); } } + + + /* Third round, recompose */ + + if (!all_simple && + (mode == HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS || + mode == HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT)) + { + /* As noted in the comment earlier, we don't try to combine + * ccc=0 chars with their previous Starter. */ + + buffer->clear_output (); + count = buffer->len; + unsigned int starter = 0; + buffer->next_glyph (); + while (buffer->idx < count && buffer->successful) + { + hb_codepoint_t composed, glyph; + if (/* We don't try to compose a non-mark character with it's preceding starter. + * This is both an optimization to avoid trying to compose every two neighboring + * glyphs in most scripts AND a desired feature for Hangul. Apparently Hangul + * fonts are not designed to mix-and-match pre-composed syllables and Jamo. */ + HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer->cur()))) + { + if (/* If there's anything between the starter and this char, they should have CCC + * smaller than this character's. */ + (starter == buffer->out_len - 1 || + info_cc (buffer->prev()) < info_cc (buffer->cur())) && + /* And compose. */ + c.compose (&c, + buffer->out_info[starter].codepoint, + buffer->cur().codepoint, + &composed) && + /* And the font has glyph for the composite. */ + font->get_nominal_glyph (composed, &glyph)) + { + /* Composes. */ + buffer->next_glyph (); /* Copy to out-buffer. */ + if (unlikely (!buffer->successful)) + return; + buffer->merge_out_clusters (starter, buffer->out_len); + buffer->out_len--; /* Remove the second composable. */ + /* Modify starter and carry on. */ + buffer->out_info[starter].codepoint = composed; + buffer->out_info[starter].glyph_index() = glyph; + _hb_glyph_info_set_unicode_props (&buffer->out_info[starter], buffer); + + continue; + } + } + + /* Blocked, or doesn't compose. */ + buffer->next_glyph (); + + if (info_cc (buffer->prev()) == 0) + starter = buffer->out_len - 1; + } + buffer->swap_buffers (); + } } diff --git a/src/hb-ot-shape-normalize-private.hh b/src/hb-ot-shape-normalize.hh index c744e2645..04f1a8009 100644 --- a/src/hb-ot-shape-normalize-private.hh +++ b/src/hb-ot-shape-normalize.hh @@ -24,10 +24,10 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_OT_SHAPE_NORMALIZE_PRIVATE_HH -#define HB_OT_SHAPE_NORMALIZE_PRIVATE_HH +#ifndef HB_OT_SHAPE_NORMALIZE_HH +#define HB_OT_SHAPE_NORMALIZE_HH -#include "hb-private.hh" +#include "hb.hh" /* buffer var allocations, used during the normalization process */ @@ -38,10 +38,11 @@ struct hb_ot_shape_plan_t; enum hb_ot_shape_normalization_mode_t { HB_OT_SHAPE_NORMALIZATION_MODE_NONE, HB_OT_SHAPE_NORMALIZATION_MODE_DECOMPOSED, - HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS, /* never composes base-to-base */ - HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT, /* always fully decomposes and then recompose back */ + HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS, /* Never composes base-to-base */ + HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT, /* Always fully decomposes and then recompose back */ - HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT = HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS + HB_OT_SHAPE_NORMALIZATION_MODE_AUTO, /* See hb-ot-shape-normalize.cc for logic. */ + HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT = HB_OT_SHAPE_NORMALIZATION_MODE_AUTO }; HB_INTERNAL void _hb_ot_shape_normalize (const hb_ot_shape_plan_t *shaper, @@ -66,4 +67,4 @@ struct hb_ot_shape_normalize_context_t }; -#endif /* HB_OT_SHAPE_NORMALIZE_PRIVATE_HH */ +#endif /* HB_OT_SHAPE_NORMALIZE_HH */ diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc index 71632b563..a5538871b 100644 --- a/src/hb-ot-shape.cc +++ b/src/hb-ot-shape.cc @@ -27,41 +27,120 @@ */ #define HB_SHAPER ot -#define hb_ot_face_data_t hb_ot_layout_t #define hb_ot_shape_plan_data_t hb_ot_shape_plan_t -#include "hb-shaper-impl-private.hh" - -#include "hb-ot-shape-private.hh" -#include "hb-ot-shape-complex-private.hh" -#include "hb-ot-shape-fallback-private.hh" -#include "hb-ot-shape-normalize-private.hh" - -#include "hb-ot-layout-private.hh" -#include "hb-unicode-private.hh" -#include "hb-set-private.hh" - -#include "hb-ot-layout-gsubgpos-private.hh" -#include "hb-aat-layout-private.hh" - -static hb_tag_t common_features[] = { - HB_TAG('c','c','m','p'), - HB_TAG('l','o','c','l'), - HB_TAG('m','a','r','k'), - HB_TAG('m','k','m','k'), - HB_TAG('r','l','i','g'), -}; +#include "hb-shaper-impl.hh" + +#include "hb-ot-shape.hh" +#include "hb-ot-shape-complex.hh" +#include "hb-ot-shape-fallback.hh" +#include "hb-ot-shape-normalize.hh" + +#include "hb-ot-face.hh" + +#include "hb-set.hh" + +#include "hb-aat-layout.hh" + +static bool +_hb_apply_morx (hb_face_t *face) +{ + if (hb_options ().aat && + hb_aat_layout_has_substitution (face)) + return true; + + return !hb_ot_layout_has_substitution (face) && + hb_aat_layout_has_substitution (face); +} -static hb_tag_t horizontal_features[] = { - HB_TAG('c','a','l','t'), - HB_TAG('c','l','i','g'), - HB_TAG('c','u','r','s'), - HB_TAG('k','e','r','n'), - HB_TAG('l','i','g','a'), - HB_TAG('r','c','l','t'), +void +hb_ot_shape_planner_t::compile (hb_ot_shape_plan_t &plan, + const int *coords, + unsigned int num_coords) +{ + plan.props = props; + plan.shaper = shaper; + map.compile (plan.map, coords, num_coords); + + plan.rtlm_mask = plan.map.get_1_mask (HB_TAG ('r','t','l','m')); + plan.frac_mask = plan.map.get_1_mask (HB_TAG ('f','r','a','c')); + plan.numr_mask = plan.map.get_1_mask (HB_TAG ('n','u','m','r')); + plan.dnom_mask = plan.map.get_1_mask (HB_TAG ('d','n','o','m')); + plan.has_frac = plan.frac_mask || (plan.numr_mask && plan.dnom_mask); + hb_tag_t kern_tag = HB_DIRECTION_IS_HORIZONTAL (plan.props.direction) ? + HB_TAG ('k','e','r','n') : HB_TAG ('v','k','r','n'); + plan.kern_mask = plan.map.get_mask (kern_tag); + + plan.requested_kerning = !!plan.kern_mask; + bool has_gpos_kern = plan.map.get_feature_index (1, kern_tag) != HB_OT_LAYOUT_NO_FEATURE_INDEX; + bool disable_gpos = plan.shaper->gpos_tag && + plan.shaper->gpos_tag != plan.map.chosen_script[1]; + + /* + * Decide who provides glyph classes. GDEF or Unicode. + */ + + if (!hb_ot_layout_has_glyph_classes (face)) + plan.fallback_glyph_classes = true; + + /* + * Decide who does substitutions. GSUB, morx, or fallback. + */ + + plan.apply_morx = _hb_apply_morx (face); + + /* + * Decide who does positioning. GPOS, kerx, kern, or fallback. + */ + + if (hb_options ().aat && hb_aat_layout_has_positioning (face)) + plan.apply_kerx = true; + else if (!disable_gpos && hb_ot_layout_has_positioning (face)) + plan.apply_gpos = true; + else if (hb_aat_layout_has_positioning (face)) + plan.apply_kerx = true; + + if (plan.requested_kerning && !plan.apply_kerx && !has_gpos_kern) + { + /* Apparently Apple applies kerx if GPOS kern was not applied. */ + if (hb_aat_layout_has_positioning (face)) + plan.apply_kerx = true; + if (hb_ot_layout_has_kerning (face)) + plan.apply_kern = true; + else + plan.fallback_kerning = true; + } + + plan.has_gpos_mark = !!plan.map.get_1_mask (HB_TAG ('m','a','r','k')); + if (!plan.apply_gpos && !plan.apply_kerx) + plan.fallback_mark_positioning = true; + + /* Currently we always apply trak. */ + plan.apply_trak = hb_aat_layout_has_tracking (face); +} + + +static const hb_ot_map_feature_t +common_features[] = +{ + {HB_TAG('c','c','m','p'), F_GLOBAL}, + {HB_TAG('l','o','c','l'), F_GLOBAL}, + {HB_TAG('m','a','r','k'), F_GLOBAL_MANUAL_JOINERS}, + {HB_TAG('m','k','m','k'), F_GLOBAL_MANUAL_JOINERS}, + {HB_TAG('r','l','i','g'), F_GLOBAL}, }; +static const hb_ot_map_feature_t +horizontal_features[] = +{ + {HB_TAG('c','a','l','t'), F_GLOBAL}, + {HB_TAG('c','l','i','g'), F_GLOBAL}, + {HB_TAG('c','u','r','s'), F_GLOBAL}, + {HB_TAG('k','e','r','n'), F_GLOBAL_HAS_FALLBACK}, + {HB_TAG('l','i','g','a'), F_GLOBAL}, + {HB_TAG('r','c','l','t'), F_GLOBAL}, +}; static void hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner, @@ -71,17 +150,17 @@ hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner, { hb_ot_map_builder_t *map = &planner->map; - map->add_global_bool_feature (HB_TAG('r','v','r','n')); + map->enable_feature (HB_TAG('r','v','r','n')); map->add_gsub_pause (nullptr); switch (props->direction) { case HB_DIRECTION_LTR: - map->add_global_bool_feature (HB_TAG ('l','t','r','a')); - map->add_global_bool_feature (HB_TAG ('l','t','r','m')); + map->enable_feature (HB_TAG ('l','t','r','a')); + map->enable_feature (HB_TAG ('l','t','r','m')); break; case HB_DIRECTION_RTL: - map->add_global_bool_feature (HB_TAG ('r','t','l','a')); - map->add_feature (HB_TAG ('r','t','l','m'), 1, F_NONE); + map->enable_feature (HB_TAG ('r','t','l','a')); + map->add_feature (HB_TAG ('r','t','l','m')); break; case HB_DIRECTION_TTB: case HB_DIRECTION_BTT: @@ -90,38 +169,46 @@ hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner, break; } - map->add_feature (HB_TAG ('f','r','a','c'), 1, F_NONE); - map->add_feature (HB_TAG ('n','u','m','r'), 1, F_NONE); - map->add_feature (HB_TAG ('d','n','o','m'), 1, F_NONE); + /* Automatic fractions. */ + map->add_feature (HB_TAG ('f','r','a','c')); + map->add_feature (HB_TAG ('n','u','m','r')); + map->add_feature (HB_TAG ('d','n','o','m')); + + /* Random! */ + map->enable_feature (HB_TAG ('r','a','n','d'), F_RANDOM, HB_OT_MAP_MAX_VALUE); + + map->enable_feature (HB_TAG('H','A','R','F')); if (planner->shaper->collect_features) planner->shaper->collect_features (planner); + map->enable_feature (HB_TAG('B','U','Z','Z')); + for (unsigned int i = 0; i < ARRAY_LENGTH (common_features); i++) - map->add_global_bool_feature (common_features[i]); + map->add_feature (common_features[i]); if (HB_DIRECTION_IS_HORIZONTAL (props->direction)) for (unsigned int i = 0; i < ARRAY_LENGTH (horizontal_features); i++) - map->add_feature (horizontal_features[i], 1, F_GLOBAL | - (horizontal_features[i] == HB_TAG('k','e','r','n') ? - F_HAS_FALLBACK : F_NONE)); + map->add_feature (horizontal_features[i]); else { /* We really want to find a 'vert' feature if there's any in the font, no * matter which script/langsys it is listed (or not) under. * See various bugs referenced from: * https://github.com/harfbuzz/harfbuzz/issues/63 */ - map->add_feature (HB_TAG ('v','e','r','t'), 1, F_GLOBAL | F_GLOBAL_SEARCH); + map->enable_feature (HB_TAG ('v','e','r','t'), F_GLOBAL_SEARCH); } if (planner->shaper->override_features) planner->shaper->override_features (planner); - for (unsigned int i = 0; i < num_user_features; i++) { + for (unsigned int i = 0; i < num_user_features; i++) + { const hb_feature_t *feature = &user_features[i]; - map->add_feature (feature->tag, feature->value, - (feature->start == 0 && feature->end == (unsigned int) -1) ? - F_GLOBAL : F_NONE); + map->add_feature (feature->tag, + (feature->start == HB_FEATURE_GLOBAL_START && + feature->end == HB_FEATURE_GLOBAL_END) ? F_GLOBAL : F_NONE, + feature->value); } } @@ -135,13 +222,13 @@ HB_SHAPER_DATA_ENSURE_DEFINE(ot, face) hb_ot_face_data_t * _hb_ot_shaper_face_data_create (hb_face_t *face) { - return _hb_ot_layout_create (face); + return _hb_ot_face_data_create (face); } void _hb_ot_shaper_face_data_destroy (hb_ot_face_data_t *data) { - _hb_ot_layout_destroy (data); + _hb_ot_face_data_destroy (data); } @@ -184,7 +271,12 @@ _hb_ot_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan, hb_ot_shape_planner_t planner (shape_plan); - planner.shaper = hb_ot_shape_complex_categorize (&planner); + /* Ugly that we have to do this here... + * If we are going to apply morx, choose default shaper. */ + if (_hb_apply_morx (planner.face)) + planner.shaper = &_hb_ot_complex_shaper_default; + else + planner.shaper = hb_ot_shape_complex_categorize (&planner); hb_ot_shape_collect_features (&planner, &shape_plan->props, user_features, num_user_features); @@ -229,8 +321,6 @@ struct hb_ot_shape_context_t unsigned int num_user_features; /* Transient stuff */ - bool fallback_positioning; - bool fallback_glyph_classes; hb_direction_t target_direction; }; @@ -244,10 +334,39 @@ struct hb_ot_shape_context_t static void hb_set_unicode_props (hb_buffer_t *buffer) { + /* Implement enough of Unicode Graphemes here that shaping + * in reverse-direction wouldn't break graphemes. Namely, + * we mark all marks and ZWJ and ZWJ,Extended_Pictographic + * sequences as continuations. The foreach_grapheme() + * macro uses this bit. + * + * https://www.unicode.org/reports/tr29/#Regex_Definitions + */ unsigned int count = buffer->len; hb_glyph_info_t *info = buffer->info; for (unsigned int i = 0; i < count; i++) + { _hb_glyph_info_set_unicode_props (&info[i], buffer); + + /* Marks are already set as continuation by the above line. + * Handle Emoji_Modifier and ZWJ-continuation. */ + if (unlikely (_hb_glyph_info_get_general_category (&info[i]) == HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL && + hb_in_range<hb_codepoint_t> (info[i].codepoint, 0x1F3FBu, 0x1F3FFu))) + { + _hb_glyph_info_set_continuation (&info[i]); + } + else if (unlikely (_hb_glyph_info_is_zwj (&info[i]))) + { + _hb_glyph_info_set_continuation (&info[i]); + if (i + 1 < count && + _hb_unicode_is_emoji_Extended_Pictographic (info[i + 1].codepoint)) + { + i++; + _hb_glyph_info_set_unicode_props (&info[i], buffer); + _hb_glyph_info_set_continuation (&info[i]); + } + } + } } static void @@ -255,8 +374,7 @@ hb_insert_dotted_circle (hb_buffer_t *buffer, hb_font_t *font) { if (!(buffer->flags & HB_BUFFER_FLAG_BOT) || buffer->context_len[0] || - _hb_glyph_info_get_general_category (&buffer->info[0]) != - HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) + !_hb_glyph_info_is_unicode_mark (&buffer->info[0])) return; if (!font->has_glyph (0x25CCu)) @@ -285,26 +403,12 @@ hb_form_clusters (hb_buffer_t *buffer) if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII)) return; - /* Loop duplicated in hb_ensure_native_direction(), and in _hb-coretext.cc */ - unsigned int base = 0; - unsigned int count = buffer->len; - hb_glyph_info_t *info = buffer->info; - for (unsigned int i = 1; i < count; i++) - { - if (likely (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[i])) && - !_hb_glyph_info_is_joiner (&info[i]))) - { - if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES) - buffer->merge_clusters (base, i); - else - buffer->unsafe_to_break (base, i); - base = i; - } - } if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES) - buffer->merge_clusters (base, count); + foreach_grapheme (buffer, start, end) + buffer->merge_clusters (start, end); else - buffer->unsafe_to_break (base, count); + foreach_grapheme (buffer, start, end) + buffer->unsafe_to_break (start, end); } static void @@ -322,25 +426,17 @@ hb_ensure_native_direction (hb_buffer_t *buffer) (HB_DIRECTION_IS_VERTICAL (direction) && direction != HB_DIRECTION_TTB)) { - /* Same loop as hb_form_clusters(). - * Since form_clusters() merged clusters already, we don't merge. */ - unsigned int base = 0; - unsigned int count = buffer->len; - hb_glyph_info_t *info = buffer->info; - for (unsigned int i = 1; i < count; i++) - { - if (likely (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[i])))) - { - if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS) - buffer->merge_clusters (base, i); - buffer->reverse_range (base, i); - base = i; - } - } if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS) - buffer->merge_clusters (base, count); - buffer->reverse_range (base, count); + foreach_grapheme (buffer, start, end) + { + buffer->merge_clusters (start, end); + buffer->reverse_range (start, end); + } + else + foreach_grapheme (buffer, start, end) + /* form_clusters() merged clusters already, we don't merge. */ + buffer->reverse_range (start, end); buffer->reverse (); @@ -352,7 +448,7 @@ hb_ensure_native_direction (hb_buffer_t *buffer) /* Substitute */ static inline void -hb_ot_mirror_chars (hb_ot_shape_context_t *c) +hb_ot_mirror_chars (const hb_ot_shape_context_t *c) { if (HB_DIRECTION_IS_FORWARD (c->target_direction)) return; @@ -373,7 +469,7 @@ hb_ot_mirror_chars (hb_ot_shape_context_t *c) } static inline void -hb_ot_shape_setup_masks_fraction (hb_ot_shape_context_t *c) +hb_ot_shape_setup_masks_fraction (const hb_ot_shape_context_t *c) { if (!(c->buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII) || !c->plan->has_frac) @@ -423,7 +519,7 @@ hb_ot_shape_setup_masks_fraction (hb_ot_shape_context_t *c) } static inline void -hb_ot_shape_initialize_masks (hb_ot_shape_context_t *c) +hb_ot_shape_initialize_masks (const hb_ot_shape_context_t *c) { hb_ot_map_t *map = &c->plan->map; hb_buffer_t *buffer = c->buffer; @@ -433,7 +529,7 @@ hb_ot_shape_initialize_masks (hb_ot_shape_context_t *c) } static inline void -hb_ot_shape_setup_masks (hb_ot_shape_context_t *c) +hb_ot_shape_setup_masks (const hb_ot_shape_context_t *c) { hb_ot_map_t *map = &c->plan->map; hb_buffer_t *buffer = c->buffer; @@ -455,7 +551,7 @@ hb_ot_shape_setup_masks (hb_ot_shape_context_t *c) } static void -hb_ot_zero_width_default_ignorables (hb_ot_shape_context_t *c) +hb_ot_zero_width_default_ignorables (const hb_ot_shape_context_t *c) { hb_buffer_t *buffer = c->buffer; @@ -474,7 +570,7 @@ hb_ot_zero_width_default_ignorables (hb_ot_shape_context_t *c) } static void -hb_ot_hide_default_ignorables (hb_ot_shape_context_t *c) +hb_ot_hide_default_ignorables (const hb_ot_shape_context_t *c) { hb_buffer_t *buffer = c->buffer; @@ -485,34 +581,24 @@ hb_ot_hide_default_ignorables (hb_ot_shape_context_t *c) unsigned int count = buffer->len; hb_glyph_info_t *info = buffer->info; hb_glyph_position_t *pos = buffer->pos; - unsigned int i = 0; - for (i = 0; i < count; i++) - { - if (unlikely (_hb_glyph_info_is_default_ignorable (&info[i]))) - break; - } - - /* No default-ignorables found; return. */ - if (i == count) - return; - hb_codepoint_t space; + hb_codepoint_t invisible = c->buffer->invisible; if (!(buffer->flags & HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES) && - c->font->get_nominal_glyph (' ', &space)) + (invisible || c->font->get_nominal_glyph (' ', &invisible))) { - /* Replace default-ignorables with a zero-advance space glyph. */ - for (/*continue*/; i < count; i++) + /* Replace default-ignorables with a zero-advance invisible glyph. */ + for (unsigned int i = 0; i < count; i++) { if (_hb_glyph_info_is_default_ignorable (&info[i])) - info[i].codepoint = space; + info[i].codepoint = invisible; } } else { /* Merge clusters and delete default-ignorables. * NOTE! We can't use out-buffer as we have positioning data. */ - unsigned int j = i; - for (; i < count; i++) + unsigned int j = 0; + for (unsigned int i = 0; i < count; i++) { if (_hb_glyph_info_is_default_ignorable (&info[i])) { @@ -567,7 +653,7 @@ hb_ot_map_glyphs_fast (hb_buffer_t *buffer) } static inline void -hb_synthesize_glyph_classes (hb_ot_shape_context_t *c) +hb_synthesize_glyph_classes (const hb_ot_shape_context_t *c) { unsigned int count = c->buffer->len; hb_glyph_info_t *info = c->buffer->info; @@ -593,7 +679,7 @@ hb_synthesize_glyph_classes (hb_ot_shape_context_t *c) } static inline void -hb_ot_substitute_default (hb_ot_shape_context_t *c) +hb_ot_substitute_default (const hb_ot_shape_context_t *c) { hb_buffer_t *buffer = c->buffer; @@ -606,8 +692,8 @@ hb_ot_substitute_default (hb_ot_shape_context_t *c) hb_ot_shape_setup_masks (c); /* This is unfortunate to go here, but necessary... */ - if (c->fallback_positioning) - _hb_ot_shape_fallback_position_recategorize_marks (c->plan, c->font, buffer); + if (c->plan->fallback_mark_positioning) + _hb_ot_shape_fallback_mark_position_recategorize_marks (c->plan, c->font, buffer); hb_ot_map_glyphs_fast (buffer); @@ -615,23 +701,23 @@ hb_ot_substitute_default (hb_ot_shape_context_t *c) } static inline void -hb_ot_substitute_complex (hb_ot_shape_context_t *c) +hb_ot_substitute_complex (const hb_ot_shape_context_t *c) { hb_buffer_t *buffer = c->buffer; hb_ot_layout_substitute_start (c->font, buffer); - if (!hb_ot_layout_has_glyph_classes (c->face)) + if (c->plan->fallback_glyph_classes) hb_synthesize_glyph_classes (c); - c->plan->substitute (c->font, buffer); - - if (0) /* XXX Call morx instead. */ - hb_aat_layout_substitute (c->font, c->buffer); + if (unlikely (c->plan->apply_morx)) + hb_aat_layout_substitute (c->plan, c->font, c->buffer); + else + c->plan->substitute (c->font, buffer); } static inline void -hb_ot_substitute (hb_ot_shape_context_t *c) +hb_ot_substitute (const hb_ot_shape_context_t *c) { hb_ot_substitute_default (c); @@ -671,7 +757,7 @@ zero_mark_widths_by_gdef (hb_buffer_t *buffer, bool adjust_offsets) } static inline void -hb_ot_position_default (hb_ot_shape_context_t *c) +hb_ot_position_default (const hb_ot_shape_context_t *c) { hb_direction_t direction = c->buffer->props.direction; unsigned int count = c->buffer->len; @@ -705,7 +791,7 @@ hb_ot_position_default (hb_ot_shape_context_t *c) } static inline void -hb_ot_position_complex (hb_ot_shape_context_t *c) +hb_ot_position_complex (const hb_ot_shape_context_t *c) { unsigned int count = c->buffer->len; hb_glyph_info_t *info = c->buffer->info; @@ -720,7 +806,7 @@ hb_ot_position_complex (hb_ot_shape_context_t *c) * If fallback positinoing happens or GPOS is present, we don't * care. */ - bool adjust_offsets_when_zeroing = c->fallback_positioning && + bool adjust_offsets_when_zeroing = c->plan->fallback_mark_positioning && !c->plan->shaper->fallback_position && HB_DIRECTION_IS_FORWARD (c->buffer->props.direction); @@ -735,32 +821,39 @@ hb_ot_position_complex (hb_ot_shape_context_t *c) hb_ot_layout_position_start (c->font, c->buffer); - switch (c->plan->shaper->zero_width_marks) - { - case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY: - zero_mark_widths_by_gdef (c->buffer, adjust_offsets_when_zeroing); - break; - - default: - case HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE: - case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE: - break; - } + if (!c->plan->apply_kerx) + switch (c->plan->shaper->zero_width_marks) + { + case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY: + zero_mark_widths_by_gdef (c->buffer, adjust_offsets_when_zeroing); + break; + + default: + case HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE: + case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE: + break; + } - if (likely (!c->fallback_positioning)) + if (c->plan->apply_gpos) c->plan->position (c->font, c->buffer); + else if (c->plan->apply_kerx) + hb_aat_layout_position (c->plan, c->font, c->buffer); - switch (c->plan->shaper->zero_width_marks) - { - case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE: - zero_mark_widths_by_gdef (c->buffer, adjust_offsets_when_zeroing); - break; + if (c->plan->apply_trak) + hb_aat_layout_track (c->plan, c->font, c->buffer); - default: - case HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE: - case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY: - break; - } + if (!c->plan->apply_kerx) + switch (c->plan->shaper->zero_width_marks) + { + case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE: + zero_mark_widths_by_gdef (c->buffer, adjust_offsets_when_zeroing); + break; + + default: + case HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE: + case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY: + break; + } /* Finishing off GPOS has to follow a certain order. */ hb_ot_layout_position_finish_advances (c->font, c->buffer); @@ -776,7 +869,7 @@ hb_ot_position_complex (hb_ot_shape_context_t *c) } static inline void -hb_ot_position (hb_ot_shape_context_t *c) +hb_ot_position (const hb_ot_shape_context_t *c) { c->buffer->clear_positions (); @@ -784,20 +877,20 @@ hb_ot_position (hb_ot_shape_context_t *c) hb_ot_position_complex (c); - if (c->fallback_positioning && c->plan->shaper->fallback_position) - _hb_ot_shape_fallback_position (c->plan, c->font, c->buffer); + if (c->plan->fallback_mark_positioning && c->plan->shaper->fallback_position) + _hb_ot_shape_fallback_mark_position (c->plan, c->font, c->buffer); if (HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction)) hb_buffer_reverse (c->buffer); /* Visual fallback goes here. */ - if (c->fallback_positioning) + if (c->plan->apply_kern) + hb_ot_layout_kern (c->font, c->buffer, c->plan->kern_mask); + else if (c->plan->fallback_kerning) _hb_ot_shape_fallback_kern (c->plan, c->font, c->buffer); _hb_buffer_deallocate_gsubgpos_vars (c->buffer); - - //hb_aat_layout_position (c->font, c->buffer); } static inline void @@ -844,11 +937,6 @@ hb_ot_shape_internal (hb_ot_shape_context_t *c) (unsigned) HB_BUFFER_MAX_OPS_MIN); } - bool disable_otl = c->plan->shaper->disable_otl && c->plan->shaper->disable_otl (c->plan); - //c->fallback_substitute = disable_otl || !hb_ot_layout_has_substitution (c->face); - c->fallback_positioning = disable_otl || !hb_ot_layout_has_positioning (c->face); - c->fallback_glyph_classes = disable_otl || !hb_ot_layout_has_glyph_classes (c->face); - /* Save the original direction, we use it later. */ c->target_direction = c->buffer->props.direction; diff --git a/src/hb-ot-shape-private.hh b/src/hb-ot-shape.hh index d6898263f..c9c0d3e09 100644 --- a/src/hb-ot-shape-private.hh +++ b/src/hb-ot-shape.hh @@ -24,13 +24,13 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_OT_SHAPE_PRIVATE_HH -#define HB_OT_SHAPE_PRIVATE_HH +#ifndef HB_OT_SHAPE_HH +#define HB_OT_SHAPE_HH -#include "hb-private.hh" +#include "hb.hh" -#include "hb-ot-map-private.hh" -#include "hb-ot-layout-private.hh" +#include "hb-ot-map.hh" +#include "hb-shape-plan.hh" @@ -42,9 +42,20 @@ struct hb_ot_shape_plan_t const void *data; hb_mask_t rtlm_mask, frac_mask, numr_mask, dnom_mask; hb_mask_t kern_mask; - unsigned int has_frac : 1; - unsigned int has_kern : 1; - unsigned int has_mark : 1; + + bool requested_kerning : 1; + bool has_frac : 1; + bool has_gpos_mark : 1; + bool fallback_glyph_classes : 1; + bool fallback_kerning : 1; + bool fallback_mark_positioning : 1; + + bool apply_gpos : 1; + bool apply_kerx : 1; + bool apply_kern : 1; + bool apply_morx : 1; + bool apply_trak : 1; + inline void collect_lookups (hb_tag_t table_tag, hb_set_t *lookups) const { @@ -83,30 +94,13 @@ struct hb_ot_shape_planner_t shaper (nullptr), map (face, &props) {} - inline void compile (hb_ot_shape_plan_t &plan, - const int *coords, - unsigned int num_coords) - { - plan.props = props; - plan.shaper = shaper; - map.compile (plan.map, coords, num_coords); - - plan.rtlm_mask = plan.map.get_1_mask (HB_TAG ('r','t','l','m')); - plan.frac_mask = plan.map.get_1_mask (HB_TAG ('f','r','a','c')); - plan.numr_mask = plan.map.get_1_mask (HB_TAG ('n','u','m','r')); - plan.dnom_mask = plan.map.get_1_mask (HB_TAG ('d','n','o','m')); - - plan.kern_mask = plan.map.get_mask (HB_DIRECTION_IS_HORIZONTAL (plan.props.direction) ? - HB_TAG ('k','e','r','n') : HB_TAG ('v','k','r','n')); - - plan.has_frac = plan.frac_mask || (plan.numr_mask && plan.dnom_mask); - plan.has_kern = !!plan.kern_mask; - plan.has_mark = !!plan.map.get_1_mask (HB_TAG ('m','a','r','k')); - } + HB_INTERNAL void compile (hb_ot_shape_plan_t &plan, + const int *coords, + unsigned int num_coords); private: HB_DISALLOW_COPY_AND_ASSIGN (hb_ot_shape_planner_t); }; -#endif /* HB_OT_SHAPE_PRIVATE_HH */ +#endif /* HB_OT_SHAPE_HH */ diff --git a/src/hb-ot-tag-table.hh b/src/hb-ot-tag-table.hh new file mode 100644 index 000000000..b7090a0a7 --- /dev/null +++ b/src/hb-ot-tag-table.hh @@ -0,0 +1,2064 @@ +/* == Start of generated table == */ +/* + * The following table is generated by running: + * + * ./gen-tag-table.py languagetags language-subtag-registry + * + * on files with these headers: + * + * <meta name="updated_at" content="2018-09-07 07:45 PM" /> + * File-Date: 2018-08-08 + */ + +#ifndef HB_OT_TAG_TABLE_HH +#define HB_OT_TAG_TABLE_HH + +static const LangTag ot_languages[] = { + {"aa", {HB_TAG('A','F','R',' ')}}, /* Afar */ + {"aae", {HB_TAG('S','Q','I',' ')}}, /* Arbëreshë Albanian -> Albanian */ + {"aao", {HB_TAG('A','R','A',' ')}}, /* Algerian Saharan Arabic -> Arabic */ + {"aat", {HB_TAG('S','Q','I',' ')}}, /* Arvanitika Albanian -> Albanian */ + {"ab", {HB_TAG('A','B','K',' ')}}, /* Abkhazian */ + {"abh", {HB_TAG('A','R','A',' ')}}, /* Tajiki Arabic -> Arabic */ + {"abq", {HB_TAG('A','B','A',' ')}}, /* Abaza */ + {"abv", {HB_TAG('A','R','A',' ')}}, /* Baharna Arabic -> Arabic */ + {"acf", {HB_TAG('F','A','N',' ')}}, /* Saint Lucian Creole French -> French Antillean */ + {"ach", {HB_TAG('A','C','H',' ')}}, /* Acoli -> Acholi */ + {"acm", {HB_TAG('A','R','A',' ')}}, /* Mesopotamian Arabic -> Arabic */ + {"acq", {HB_TAG('A','R','A',' ')}}, /* Ta'izzi-Adeni Arabic -> Arabic */ + {"acr", {HB_TAG('A','C','R',' ')}}, /* Achi */ + {"acw", {HB_TAG('A','R','A',' ')}}, /* Hijazi Arabic -> Arabic */ + {"acx", {HB_TAG('A','R','A',' ')}}, /* Omani Arabic -> Arabic */ + {"acy", {HB_TAG('A','R','A',' ')}}, /* Cypriot Arabic -> Arabic */ + {"ada", {HB_TAG('D','N','G',' ')}}, /* Adangme -> Dangme */ + {"adf", {HB_TAG('A','R','A',' ')}}, /* Dhofari Arabic -> Arabic */ + {"adp", {HB_TAG('D','Z','N',' ')}}, /* Adap (retired code) -> Dzongkha */ + {"ady", {HB_TAG('A','D','Y',' ')}}, /* Adyghe */ + {"aeb", {HB_TAG('A','R','A',' ')}}, /* Tunisian Arabic -> Arabic */ + {"aec", {HB_TAG('A','R','A',' ')}}, /* Saidi Arabic -> Arabic */ + {"af", {HB_TAG('A','F','K',' ')}}, /* Afrikaans */ + {"afb", {HB_TAG('A','R','A',' ')}}, /* Gulf Arabic -> Arabic */ + {"ahg", {HB_TAG('A','G','W',' ')}}, /* Qimant -> Agaw */ + {"aht", {HB_TAG('A','T','H',' ')}}, /* Ahtena -> Athapaskan */ + {"aii", {HB_TAG('S','W','A',' '), /* Assyrian Neo-Aramaic -> Swadaya Aramaic */ + HB_TAG('S','Y','R',' ')}}, /* Assyrian Neo-Aramaic -> Syriac */ + {"aio", {HB_TAG('A','I','O',' ')}}, /* Aiton */ + {"aiw", {HB_TAG('A','R','I',' ')}}, /* Aari */ + {"ajp", {HB_TAG('A','R','A',' ')}}, /* South Levantine Arabic -> Arabic */ + {"ak", {HB_TAG('A','K','A',' '), /* Akan [macrolanguage] */ + HB_TAG('T','W','I',' ')}}, /* Akan [macrolanguage] -> Twi */ + {"aln", {HB_TAG('S','Q','I',' ')}}, /* Gheg Albanian -> Albanian */ + {"als", {HB_TAG('S','Q','I',' ')}}, /* Tosk Albanian -> Albanian */ + {"alt", {HB_TAG('A','L','T',' ')}}, /* Southern Altai -> Altai */ + {"am", {HB_TAG('A','M','H',' ')}}, /* Amharic */ + {"amf", {HB_TAG('H','B','N',' ')}}, /* Hamer-Banna -> Hammer-Banna */ + {"amw", {HB_TAG('S','Y','R',' ')}}, /* Western Neo-Aramaic -> Syriac */ + {"an", {HB_TAG('A','R','G',' ')}}, /* Aragonese */ + {"ang", {HB_TAG('A','N','G',' ')}}, /* Old English (ca. 450-1100) -> Anglo-Saxon */ + {"apc", {HB_TAG('A','R','A',' ')}}, /* North Levantine Arabic -> Arabic */ + {"apd", {HB_TAG('A','R','A',' ')}}, /* Sudanese Arabic -> Arabic */ + {"apj", {HB_TAG('A','T','H',' ')}}, /* Jicarilla Apache -> Athapaskan */ + {"apk", {HB_TAG('A','T','H',' ')}}, /* Kiowa Apache -> Athapaskan */ + {"apl", {HB_TAG('A','T','H',' ')}}, /* Lipan Apache -> Athapaskan */ + {"apm", {HB_TAG('A','T','H',' ')}}, /* Mescalero-Chiricahua Apache -> Athapaskan */ + {"apw", {HB_TAG('A','T','H',' ')}}, /* Western Apache -> Athapaskan */ + {"ar", {HB_TAG('A','R','A',' ')}}, /* Arabic [macrolanguage] */ + {"arb", {HB_TAG('A','R','A',' ')}}, /* Standard Arabic -> Arabic */ + {"arn", {HB_TAG('M','A','P',' ')}}, /* Mapudungun */ + {"arq", {HB_TAG('A','R','A',' ')}}, /* Algerian Arabic -> Arabic */ + {"ars", {HB_TAG('A','R','A',' ')}}, /* Najdi Arabic -> Arabic */ + {"ary", {HB_TAG('M','O','R',' ')}}, /* Moroccan Arabic -> Moroccan */ + {"arz", {HB_TAG('A','R','A',' ')}}, /* Egyptian Arabic -> Arabic */ + {"as", {HB_TAG('A','S','M',' ')}}, /* Assamese */ + {"ast", {HB_TAG('A','S','T',' ')}}, /* Asturian */ + {"ath", {HB_TAG('A','T','H',' ')}}, /* Athapascan [family] -> Athapaskan */ + {"atj", {HB_TAG('R','C','R',' ')}}, /* Atikamekw -> R-Cree */ + {"atv", {HB_TAG('A','L','T',' ')}}, /* Northern Altai -> Altai */ + {"auz", {HB_TAG('A','R','A',' ')}}, /* Uzbeki Arabic -> Arabic */ + {"av", {HB_TAG('A','V','R',' ')}}, /* Avaric -> Avar */ + {"avl", {HB_TAG('A','R','A',' ')}}, /* Eastern Egyptian Bedawi Arabic -> Arabic */ + {"awa", {HB_TAG('A','W','A',' ')}}, /* Awadhi */ + {"ay", {HB_TAG('A','Y','M',' ')}}, /* Aymara [macrolanguage] */ + {"ayc", {HB_TAG('A','Y','M',' ')}}, /* Southern Aymara -> Aymara */ + {"ayh", {HB_TAG('A','R','A',' ')}}, /* Hadrami Arabic -> Arabic */ + {"ayl", {HB_TAG('A','R','A',' ')}}, /* Libyan Arabic -> Arabic */ + {"ayn", {HB_TAG('A','R','A',' ')}}, /* Sanaani Arabic -> Arabic */ + {"ayp", {HB_TAG('A','R','A',' ')}}, /* North Mesopotamian Arabic -> Arabic */ + {"ayr", {HB_TAG('A','Y','M',' ')}}, /* Central Aymara -> Aymara */ + {"az", {HB_TAG('A','Z','E',' ')}}, /* Azerbaijani [macrolanguage] */ + {"azb", {HB_TAG('A','Z','B',' ')}}, /* South Azerbaijani -> Torki */ + {"azj", {HB_TAG('A','Z','E',' ')}}, /* North Azerbaijani -> Azerbaijani */ + {"ba", {HB_TAG('B','S','H',' ')}}, /* Bashkir */ + {"bad", {HB_TAG('B','A','D','0')}}, /* Banda [family] */ + {"bai", {HB_TAG('B','M','L',' ')}}, /* Bamileke [family] */ + {"bal", {HB_TAG('B','L','I',' ')}}, /* Baluchi [macrolanguage] */ + {"ban", {HB_TAG('B','A','N',' ')}}, /* Balinese */ + {"bar", {HB_TAG('B','A','R',' ')}}, /* Bavarian */ + {"bbc", {HB_TAG('B','B','C',' ')}}, /* Batak Toba */ + {"bbz", {HB_TAG('A','R','A',' ')}}, /* Babalia Creole Arabic -> Arabic */ + {"bcc", {HB_TAG('B','L','I',' ')}}, /* Southern Balochi -> Baluchi */ + {"bci", {HB_TAG('B','A','U',' ')}}, /* Baoulé -> Baulé */ + {"bcl", {HB_TAG('B','I','K',' ')}}, /* Central Bikol -> Bikol */ + {"bcq", {HB_TAG('B','C','H',' ')}}, /* Bench */ + {"bcr", {HB_TAG('A','T','H',' ')}}, /* Babine -> Athapaskan */ + {"bdy", {HB_TAG('B','D','Y',' ')}}, /* Bandjalang */ + {"be", {HB_TAG('B','E','L',' ')}}, /* Belarusian -> Belarussian */ + {"bea", {HB_TAG('A','T','H',' ')}}, /* Beaver -> Athapaskan */ + {"beb", {HB_TAG('B','T','I',' ')}}, /* Bebele -> Beti */ + {"bem", {HB_TAG('B','E','M',' ')}}, /* Bemba (Zambia) */ + {"ber", {HB_TAG('B','B','R',' ')}}, /* Berber [family] */ + {"bfq", {HB_TAG('B','A','D',' ')}}, /* Badaga */ + {"bft", {HB_TAG('B','L','T',' ')}}, /* Balti */ + {"bfu", {HB_TAG('L','A','H',' ')}}, /* Gahri -> Lahuli */ + {"bfy", {HB_TAG('B','A','G',' ')}}, /* Bagheli -> Baghelkhandi */ + {"bg", {HB_TAG('B','G','R',' ')}}, /* Bulgarian */ + {"bgc", {HB_TAG('B','G','C',' ')}}, /* Haryanvi */ + {"bgn", {HB_TAG('B','L','I',' ')}}, /* Western Balochi -> Baluchi */ + {"bgp", {HB_TAG('B','L','I',' ')}}, /* Eastern Balochi -> Baluchi */ + {"bgq", {HB_TAG('B','G','Q',' ')}}, /* Bagri */ + {"bgr", {HB_TAG('Q','I','N',' ')}}, /* Bawm Chin -> Chin */ + {"bhb", {HB_TAG('B','H','I',' ')}}, /* Bhili */ + {"bhi", {HB_TAG('B','H','I',' ')}}, /* Bhilali -> Bhili */ + {"bhk", {HB_TAG('B','I','K',' ')}}, /* Albay Bicolano (retired code) -> Bikol */ + {"bho", {HB_TAG('B','H','O',' ')}}, /* Bhojpuri */ + {"bhr", {HB_TAG('M','L','G',' ')}}, /* Bara Malagasy -> Malagasy */ + {"bi", {HB_TAG('B','I','S',' ')}}, /* Bislama */ + {"bik", {HB_TAG('B','I','K',' ')}}, /* Bikol [macrolanguage] */ + {"bin", {HB_TAG('E','D','O',' ')}}, /* Edo */ + {"bjj", {HB_TAG('B','J','J',' ')}}, /* Kanauji */ + {"bjn", {HB_TAG('M','L','Y',' ')}}, /* Banjar -> Malay */ + {"bjq", {HB_TAG('M','L','G',' ')}}, /* Southern Betsimisaraka Malagasy (retired code) -> Malagasy */ + {"bjt", {HB_TAG('B','L','N',' ')}}, /* Balanta-Ganja -> Balante */ + {"bla", {HB_TAG('B','K','F',' ')}}, /* Siksika -> Blackfoot */ + {"ble", {HB_TAG('B','L','N',' ')}}, /* Balanta-Kentohe -> Balante */ + {"blk", {HB_TAG('B','L','K',' ')}}, /* Pa'o Karen */ + {"bln", {HB_TAG('B','I','K',' ')}}, /* Southern Catanduanes Bikol -> Bikol */ + {"bm", {HB_TAG('B','M','B',' ')}}, /* Bambara (Bamanankan) */ + {"bmm", {HB_TAG('M','L','G',' ')}}, /* Northern Betsimisaraka Malagasy -> Malagasy */ + {"bn", {HB_TAG('B','E','N',' ')}}, /* Bengali */ + {"bo", {HB_TAG('T','I','B',' ')}}, /* Tibetan */ + {"bpy", {HB_TAG('B','P','Y',' ')}}, /* Bishnupriya -> Bishnupriya Manipuri */ + {"bqi", {HB_TAG('L','R','C',' ')}}, /* Bakhtiari -> Luri */ + {"br", {HB_TAG('B','R','E',' ')}}, /* Breton */ + {"bra", {HB_TAG('B','R','I',' ')}}, /* Braj -> Braj Bhasha */ + {"brh", {HB_TAG('B','R','H',' ')}}, /* Brahui */ + {"brx", {HB_TAG('B','R','X',' ')}}, /* Bodo (India) */ + {"bs", {HB_TAG('B','O','S',' ')}}, /* Bosnian */ + {"bsk", {HB_TAG('B','S','K',' ')}}, /* Burushaski */ + {"btb", {HB_TAG('B','T','I',' ')}}, /* Beti (Cameroon) (retired code) */ + {"btj", {HB_TAG('M','L','Y',' ')}}, /* Bacanese Malay -> Malay */ + {"bto", {HB_TAG('B','I','K',' ')}}, /* Rinconada Bikol -> Bikol */ + {"bts", {HB_TAG('B','T','S',' ')}}, /* Batak Simalungun */ + {"bug", {HB_TAG('B','U','G',' ')}}, /* Buginese -> Bugis */ + {"bum", {HB_TAG('B','T','I',' ')}}, /* Bulu (Cameroon) -> Beti */ + {"bve", {HB_TAG('M','L','Y',' ')}}, /* Berau Malay -> Malay */ + {"bvu", {HB_TAG('M','L','Y',' ')}}, /* Bukit Malay -> Malay */ + {"bxk", {HB_TAG('L','U','H',' ')}}, /* Bukusu -> Luyia */ + {"bxp", {HB_TAG('B','T','I',' ')}}, /* Bebil -> Beti */ + {"bxr", {HB_TAG('R','B','U',' ')}}, /* Russia Buriat -> Russian Buriat */ + {"byn", {HB_TAG('B','I','L',' ')}}, /* Bilin -> Bilen */ + {"byv", {HB_TAG('B','Y','V',' ')}}, /* Medumba */ + {"bzc", {HB_TAG('M','L','G',' ')}}, /* Southern Betsimisaraka Malagasy -> Malagasy */ + {"ca", {HB_TAG('C','A','T',' ')}}, /* Catalan */ + {"caf", {HB_TAG('C','R','R',' '), /* Southern Carrier -> Carrier */ + HB_TAG('A','T','H',' ')}}, /* Southern Carrier -> Athapaskan */ + {"cak", {HB_TAG('C','A','K',' ')}}, /* Kaqchikel */ + {"cbk", {HB_TAG('C','B','K',' ')}}, /* Chavacano -> Zamboanga Chavacano */ + {"cbl", {HB_TAG('Q','I','N',' ')}}, /* Bualkhaw Chin -> Chin */ + {"cco", {HB_TAG('C','C','H','N')}}, /* Comaltepec Chinantec -> Chinantec */ + {"ccq", {HB_TAG('A','R','K',' ')}}, /* Chaungtha (retired code) -> Rakhine */ + {"cdo", {HB_TAG('Z','H','S',' ')}}, /* Min Dong Chinese -> Chinese Simplified */ + {"ce", {HB_TAG('C','H','E',' ')}}, /* Chechen */ + {"ceb", {HB_TAG('C','E','B',' ')}}, /* Cebuano */ + {"cfm", {HB_TAG('H','A','L',' ')}}, /* Halam (Falam Chin) */ + {"cgg", {HB_TAG('C','G','G',' ')}}, /* Chiga */ + {"ch", {HB_TAG('C','H','A',' ')}}, /* Chamorro */ + {"chj", {HB_TAG('C','C','H','N')}}, /* Ojitlán Chinantec -> Chinantec */ + {"chk", {HB_TAG('C','H','K','0')}}, /* Chuukese */ + {"cho", {HB_TAG('C','H','O',' ')}}, /* Choctaw */ + {"chp", {HB_TAG('C','H','P',' '), /* Chipewyan */ + HB_TAG('S','A','Y',' '), /* Chipewyan -> Sayisi */ + HB_TAG('A','T','H',' ')}}, /* Chipewyan -> Athapaskan */ + {"chq", {HB_TAG('C','C','H','N')}}, /* Quiotepec Chinantec -> Chinantec */ + {"chr", {HB_TAG('C','H','R',' ')}}, /* Cherokee */ + {"chy", {HB_TAG('C','H','Y',' ')}}, /* Cheyenne */ + {"chz", {HB_TAG('C','C','H','N')}}, /* Ozumacín Chinantec -> Chinantec */ + {"ciw", {HB_TAG('O','J','B',' ')}}, /* Chippewa -> Ojibway */ + {"cja", {HB_TAG('C','J','A',' ')}}, /* Western Cham */ + {"cjm", {HB_TAG('C','J','M',' ')}}, /* Eastern Cham */ + {"cjy", {HB_TAG('Z','H','S',' ')}}, /* Jinyu Chinese -> Chinese Simplified */ + {"cka", {HB_TAG('Q','I','N',' ')}}, /* Khumi Awa Chin (retired code) -> Chin */ + {"ckb", {HB_TAG('K','U','R',' ')}}, /* Central Kurdish -> Kurdish */ + {"ckt", {HB_TAG('C','H','K',' ')}}, /* Chukot -> Chukchi */ + {"clc", {HB_TAG('A','T','H',' ')}}, /* Chilcotin -> Athapaskan */ + {"cld", {HB_TAG('S','Y','R',' ')}}, /* Chaldean Neo-Aramaic -> Syriac */ + {"cle", {HB_TAG('C','C','H','N')}}, /* Lealao Chinantec -> Chinantec */ + {"cmn", {HB_TAG('Z','H','S',' ')}}, /* Mandarin Chinese -> Chinese Simplified */ + {"cmr", {HB_TAG('Q','I','N',' ')}}, /* Mro-Khimi Chin -> Chin */ + {"cnb", {HB_TAG('Q','I','N',' ')}}, /* Chinbon Chin -> Chin */ + {"cnh", {HB_TAG('Q','I','N',' ')}}, /* Hakha Chin -> Chin */ + {"cnk", {HB_TAG('Q','I','N',' ')}}, /* Khumi Chin -> Chin */ + {"cnl", {HB_TAG('C','C','H','N')}}, /* Lalana Chinantec -> Chinantec */ + {"cnt", {HB_TAG('C','C','H','N')}}, /* Tepetotutla Chinantec -> Chinantec */ + {"cnw", {HB_TAG('Q','I','N',' ')}}, /* Ngawn Chin -> Chin */ + {"co", {HB_TAG('C','O','S',' ')}}, /* Corsican */ + {"coa", {HB_TAG('M','L','Y',' ')}}, /* Cocos Islands Malay -> Malay */ + {"cop", {HB_TAG('C','O','P',' ')}}, /* Coptic */ + {"coq", {HB_TAG('A','T','H',' ')}}, /* Coquille -> Athapaskan */ + {"cpa", {HB_TAG('C','C','H','N')}}, /* Palantla Chinantec -> Chinantec */ + {"cpe", {HB_TAG('C','P','P',' ')}}, /* English-based creoles and pidgins [family] -> Creoles */ + {"cpf", {HB_TAG('C','P','P',' ')}}, /* French-based creoles and pidgins [family] -> Creoles */ + {"cpp", {HB_TAG('C','P','P',' ')}}, /* Portuguese-based creoles and pidgins [family] -> Creoles */ + {"cpx", {HB_TAG('Z','H','S',' ')}}, /* Pu-Xian Chinese -> Chinese Simplified */ + {"cqd", {HB_TAG('H','M','N',' ')}}, /* Chuanqiandian Cluster Miao -> Hmong */ + {"cqu", {HB_TAG('Q','U','H',' ')}}, /* Chilean Quechua (retired code) -> Quechua (Bolivia) */ + {"cr", {HB_TAG('C','R','E',' '), /* Cree [macrolanguage] */ + HB_TAG('Y','C','R',' ')}}, /* Cree [macrolanguage] -> Y-Cree */ + {"crh", {HB_TAG('C','R','T',' ')}}, /* Crimean Tatar */ + {"crj", {HB_TAG('E','C','R',' ')}}, /* Southern East Cree -> Eastern Cree */ + {"crk", {HB_TAG('W','C','R',' ')}}, /* Plains Cree -> West-Cree */ + {"crl", {HB_TAG('E','C','R',' ')}}, /* Northern East Cree -> Eastern Cree */ + {"crm", {HB_TAG('M','C','R',' '), /* Moose Cree */ + HB_TAG('L','C','R',' ')}}, /* Moose Cree -> L-Cree */ + {"crp", {HB_TAG('C','P','P',' ')}}, /* Creoles and pidgins [family] -> Creoles */ + {"crx", {HB_TAG('C','R','R',' '), /* Carrier */ + HB_TAG('A','T','H',' ')}}, /* Carrier -> Athapaskan */ + {"cs", {HB_TAG('C','S','Y',' ')}}, /* Czech */ + {"csa", {HB_TAG('C','C','H','N')}}, /* Chiltepec Chinantec -> Chinantec */ + {"csb", {HB_TAG('C','S','B',' ')}}, /* Kashubian */ + {"csh", {HB_TAG('Q','I','N',' ')}}, /* Asho Chin -> Chin */ + {"cso", {HB_TAG('C','C','H','N')}}, /* Sochiapam Chinantec -> Chinantec */ + {"csw", {HB_TAG('N','C','R',' '), /* Swampy Cree -> N-Cree */ + HB_TAG('N','H','C',' ')}}, /* Swampy Cree -> Norway House Cree */ + {"csy", {HB_TAG('Q','I','N',' ')}}, /* Siyin Chin -> Chin */ + {"ctc", {HB_TAG('A','T','H',' ')}}, /* Chetco -> Athapaskan */ + {"ctd", {HB_TAG('Q','I','N',' ')}}, /* Tedim Chin -> Chin */ + {"cte", {HB_TAG('C','C','H','N')}}, /* Tepinapa Chinantec -> Chinantec */ + {"ctg", {HB_TAG('C','T','G',' ')}}, /* Chittagonian */ + {"ctl", {HB_TAG('C','C','H','N')}}, /* Tlacoatzintepec Chinantec -> Chinantec */ + {"cts", {HB_TAG('B','I','K',' ')}}, /* Northern Catanduanes Bikol -> Bikol */ + {"cu", {HB_TAG('C','S','L',' ')}}, /* Church Slavonic */ + {"cuc", {HB_TAG('C','C','H','N')}}, /* Usila Chinantec -> Chinantec */ + {"cuk", {HB_TAG('C','U','K',' ')}}, /* San Blas Kuna */ + {"cv", {HB_TAG('C','H','U',' ')}}, /* Chuvash */ + {"cvn", {HB_TAG('C','C','H','N')}}, /* Valle Nacional Chinantec -> Chinantec */ + {"cwd", {HB_TAG('D','C','R',' '), /* Woods Cree */ + HB_TAG('T','C','R',' ')}}, /* Woods Cree -> TH-Cree */ + {"cy", {HB_TAG('W','E','L',' ')}}, /* Welsh */ + {"czh", {HB_TAG('Z','H','S',' ')}}, /* Huizhou Chinese -> Chinese Simplified */ + {"czo", {HB_TAG('Z','H','S',' ')}}, /* Min Zhong Chinese -> Chinese Simplified */ + {"czt", {HB_TAG('Q','I','N',' ')}}, /* Zotung Chin -> Chin */ + {"da", {HB_TAG('D','A','N',' ')}}, /* Danish */ + {"dao", {HB_TAG('Q','I','N',' ')}}, /* Daai Chin -> Chin */ + {"dap", {HB_TAG('N','I','S',' ')}}, /* Nisi (India) (retired code) */ + {"dar", {HB_TAG('D','A','R',' ')}}, /* Dargwa */ + {"dax", {HB_TAG('D','A','X',' ')}}, /* Dayi */ + {"de", {HB_TAG('D','E','U',' ')}}, /* German */ + {"den", {HB_TAG('S','L','A',' '), /* Slave (Athapascan) [macrolanguage] -> Slavey */ + HB_TAG('A','T','H',' ')}}, /* Slave (Athapascan) [macrolanguage] -> Athapaskan */ + {"dgo", {HB_TAG('D','G','O',' ')}}, /* Dogri */ + {"dgr", {HB_TAG('A','T','H',' ')}}, /* Dogrib -> Athapaskan */ + {"dhd", {HB_TAG('M','A','W',' ')}}, /* Dhundari -> Marwari */ + {"dhg", {HB_TAG('D','H','G',' ')}}, /* Dhangu */ + {"dib", {HB_TAG('D','N','K',' ')}}, /* South Central Dinka -> Dinka */ + {"dik", {HB_TAG('D','N','K',' ')}}, /* Southwestern Dinka -> Dinka */ + {"din", {HB_TAG('D','N','K',' ')}}, /* Dinka [macrolanguage] */ + {"dip", {HB_TAG('D','N','K',' ')}}, /* Northeastern Dinka -> Dinka */ + {"diq", {HB_TAG('D','I','Q',' ')}}, /* Dimli */ + {"diw", {HB_TAG('D','N','K',' ')}}, /* Northwestern Dinka -> Dinka */ + {"dje", {HB_TAG('D','J','R',' ')}}, /* Zarma */ + {"djr", {HB_TAG('D','J','R','0')}}, /* Djambarrpuyngu */ + {"dks", {HB_TAG('D','N','K',' ')}}, /* Southeastern Dinka -> Dinka */ + {"dng", {HB_TAG('D','U','N',' ')}}, /* Dungan */ + {"dnj", {HB_TAG('D','N','J',' ')}}, /* Dan */ + {"doi", {HB_TAG('D','G','R',' ')}}, /* Dogri [macrolanguage] */ + {"drh", {HB_TAG('M','N','G',' ')}}, /* Darkhat (retired code) -> Mongolian */ + {"drw", {HB_TAG('D','R','I',' ')}}, /* Darwazi (retired code) -> Dari */ + {"dsb", {HB_TAG('L','S','B',' ')}}, /* Lower Sorbian */ + {"dty", {HB_TAG('N','E','P',' ')}}, /* Dotyali -> Nepali */ + {"duj", {HB_TAG('D','U','J',' ')}}, /* Dhuwal (retired code) */ + {"dup", {HB_TAG('M','L','Y',' ')}}, /* Duano -> Malay */ + {"dv", {HB_TAG('D','I','V',' '), /* Divehi (Dhivehi, Maldivian) */ + HB_TAG('D','H','V',' ')}}, /* Divehi (Dhivehi, Maldivian) (deprecated) */ + {"dwu", {HB_TAG('D','U','J',' ')}}, /* Dhuwal */ + {"dwy", {HB_TAG('D','U','J',' ')}}, /* Dhuwaya -> Dhuwal */ + {"dyu", {HB_TAG('J','U','L',' ')}}, /* Dyula -> Jula */ + {"dz", {HB_TAG('D','Z','N',' ')}}, /* Dzongkha */ + {"ee", {HB_TAG('E','W','E',' ')}}, /* Ewe */ + {"efi", {HB_TAG('E','F','I',' ')}}, /* Efik */ + {"ekk", {HB_TAG('E','T','I',' ')}}, /* Standard Estonian -> Estonian */ + {"el", {HB_TAG('E','L','L',' ')}}, /* Modern Greek (1453-) -> Greek */ + {"emk", {HB_TAG('E','M','K',' '), /* Eastern Maninkakan */ + HB_TAG('M','N','K',' ')}}, /* Eastern Maninkakan -> Maninka */ + {"en", {HB_TAG('E','N','G',' ')}}, /* English */ + {"enb", {HB_TAG('K','A','L',' ')}}, /* Markweeta -> Kalenjin */ + {"enf", {HB_TAG('F','N','E',' ')}}, /* Forest Enets -> Forest Nenets */ + {"enh", {HB_TAG('T','N','E',' ')}}, /* Tundra Enets -> Tundra Nenets */ + {"eo", {HB_TAG('N','T','O',' ')}}, /* Esperanto */ + {"es", {HB_TAG('E','S','P',' ')}}, /* Spanish */ + {"esg", {HB_TAG('G','O','N',' ')}}, /* Aheri Gondi -> Gondi */ + {"esi", {HB_TAG('I','P','K',' ')}}, /* North Alaskan Inupiatun -> Inupiat */ + {"esk", {HB_TAG('I','P','K',' ')}}, /* Northwest Alaska Inupiatun -> Inupiat */ + {"esu", {HB_TAG('E','S','U',' ')}}, /* Central Yupik */ + {"et", {HB_TAG('E','T','I',' ')}}, /* Estonian [macrolanguage] */ + {"eto", {HB_TAG('B','T','I',' ')}}, /* Eton (Cameroon) -> Beti */ + {"eu", {HB_TAG('E','U','Q',' ')}}, /* Basque */ + {"eve", {HB_TAG('E','V','N',' ')}}, /* Even */ + {"evn", {HB_TAG('E','V','K',' ')}}, /* Evenki */ + {"ewo", {HB_TAG('B','T','I',' ')}}, /* Ewondo -> Beti */ + {"eyo", {HB_TAG('K','A','L',' ')}}, /* Keiyo -> Kalenjin */ + {"fa", {HB_TAG('F','A','R',' ')}}, /* Persian [macrolanguage] */ + {"fan", {HB_TAG('F','A','N','0')}}, /* Fang (Equatorial Guinea) */ + {"fat", {HB_TAG('F','A','T',' ')}}, /* Fanti */ + {"fbl", {HB_TAG('B','I','K',' ')}}, /* West Albay Bikol -> Bikol */ + {"ff", {HB_TAG('F','U','L',' ')}}, /* Fulah [macrolanguage] */ + {"ffm", {HB_TAG('F','U','L',' ')}}, /* Maasina Fulfulde -> Fulah */ + {"fi", {HB_TAG('F','I','N',' ')}}, /* Finnish */ + {"fil", {HB_TAG('P','I','L',' ')}}, /* Filipino */ + {"fj", {HB_TAG('F','J','I',' ')}}, /* Fijian */ + {"flm", {HB_TAG('H','A','L',' '), /* Halam (Falam Chin) (retired code) */ + HB_TAG('Q','I','N',' ')}}, /* Falam Chin (retired code) -> Chin */ + {"fmp", {HB_TAG('F','M','P',' ')}}, /* Fe'fe' */ + {"fo", {HB_TAG('F','O','S',' ')}}, /* Faroese */ + {"fon", {HB_TAG('F','O','N',' ')}}, /* Fon */ + {"fr", {HB_TAG('F','R','A',' ')}}, /* French */ + {"frc", {HB_TAG('F','R','C',' ')}}, /* Cajun French */ + {"frp", {HB_TAG('F','R','P',' ')}}, /* Arpitan */ + {"fub", {HB_TAG('F','U','L',' ')}}, /* Adamawa Fulfulde -> Fulah */ + {"fuc", {HB_TAG('F','U','L',' ')}}, /* Pulaar -> Fulah */ + {"fue", {HB_TAG('F','U','L',' ')}}, /* Borgu Fulfulde -> Fulah */ + {"fuf", {HB_TAG('F','T','A',' ')}}, /* Pular -> Futa */ + {"fuh", {HB_TAG('F','U','L',' ')}}, /* Western Niger Fulfulde -> Fulah */ + {"fui", {HB_TAG('F','U','L',' ')}}, /* Bagirmi Fulfulde -> Fulah */ + {"fuq", {HB_TAG('F','U','L',' ')}}, /* Central-Eastern Niger Fulfulde -> Fulah */ + {"fur", {HB_TAG('F','R','L',' ')}}, /* Friulian */ + {"fuv", {HB_TAG('F','U','V',' ')}}, /* Nigerian Fulfulde */ + {"fy", {HB_TAG('F','R','I',' ')}}, /* Western Frisian -> Frisian */ + {"ga", {HB_TAG('I','R','I',' ')}}, /* Irish */ + {"gaa", {HB_TAG('G','A','D',' ')}}, /* Ga */ + {"gag", {HB_TAG('G','A','G',' ')}}, /* Gagauz */ + {"gan", {HB_TAG('Z','H','S',' ')}}, /* Gan Chinese -> Chinese Simplified */ + {"gax", {HB_TAG('O','R','O',' ')}}, /* Borana-Arsi-Guji Oromo -> Oromo */ + {"gaz", {HB_TAG('O','R','O',' ')}}, /* West Central Oromo -> Oromo */ + {"gbm", {HB_TAG('G','A','W',' ')}}, /* Garhwali */ + {"gce", {HB_TAG('A','T','H',' ')}}, /* Galice -> Athapaskan */ + {"gd", {HB_TAG('G','A','E',' ')}}, /* Scottish Gaelic (Gaelic) */ + {"gda", {HB_TAG('R','A','J',' ')}}, /* Gade Lohar -> Rajasthani */ + {"gez", {HB_TAG('G','E','Z',' ')}}, /* Geez */ + {"ggo", {HB_TAG('G','O','N',' ')}}, /* Southern Gondi (retired code) -> Gondi */ + {"gih", {HB_TAG('G','I','H',' ')}}, /* Githabul */ + {"gil", {HB_TAG('G','I','L','0')}}, /* Kiribati (Gilbertese) */ + {"gju", {HB_TAG('R','A','J',' ')}}, /* Gujari -> Rajasthani */ + {"gkp", {HB_TAG('G','K','P',' ')}}, /* Guinea Kpelle -> Kpelle (Guinea) */ + {"gl", {HB_TAG('G','A','L',' ')}}, /* Galician */ + {"gld", {HB_TAG('N','A','N',' ')}}, /* Nanai */ + {"glk", {HB_TAG('G','L','K',' ')}}, /* Gilaki */ + {"gn", {HB_TAG('G','U','A',' ')}}, /* Guarani [macrolanguage] */ + {"gnn", {HB_TAG('G','N','N',' ')}}, /* Gumatj */ + {"gno", {HB_TAG('G','O','N',' ')}}, /* Northern Gondi -> Gondi */ + {"gnw", {HB_TAG('G','U','A',' ')}}, /* Western Bolivian Guaraní -> Guarani */ + {"gog", {HB_TAG('G','O','G',' ')}}, /* Gogo */ + {"gom", {HB_TAG('K','O','K',' ')}}, /* Goan Konkani -> Konkani */ + {"gon", {HB_TAG('G','O','N',' ')}}, /* Gondi [macrolanguage] */ + {"grt", {HB_TAG('G','R','O',' ')}}, /* Garo */ + {"gru", {HB_TAG('S','O','G',' ')}}, /* Kistane -> Sodo Gurage */ + {"gsw", {HB_TAG('A','L','S',' ')}}, /* Alsatian */ + {"gu", {HB_TAG('G','U','J',' ')}}, /* Gujarati */ + {"guc", {HB_TAG('G','U','C',' ')}}, /* Wayuu */ + {"guf", {HB_TAG('G','U','F',' ')}}, /* Gupapuyngu */ + {"gug", {HB_TAG('G','U','A',' ')}}, /* Paraguayan Guaraní -> Guarani */ + {"gui", {HB_TAG('G','U','A',' ')}}, /* Eastern Bolivian Guaraní -> Guarani */ + {"guk", {HB_TAG('G','M','Z',' '), /* Gumuz */ + HB_TAG('G','U','K',' ')}}, /* Gumuz (SIL fonts) */ + {"gun", {HB_TAG('G','U','A',' ')}}, /* Mbyá Guaraní -> Guarani */ + {"guz", {HB_TAG('G','U','Z',' ')}}, /* Gusii */ + {"gv", {HB_TAG('M','N','X',' ')}}, /* Manx */ + {"gwi", {HB_TAG('A','T','H',' ')}}, /* Gwichʼin -> Athapaskan */ + {"ha", {HB_TAG('H','A','U',' ')}}, /* Hausa */ + {"haa", {HB_TAG('A','T','H',' ')}}, /* Han -> Athapaskan */ + {"hae", {HB_TAG('O','R','O',' ')}}, /* Eastern Oromo -> Oromo */ + {"hak", {HB_TAG('Z','H','S',' ')}}, /* Hakka Chinese -> Chinese Simplified */ + {"har", {HB_TAG('H','R','I',' ')}}, /* Harari */ + {"haw", {HB_TAG('H','A','W',' ')}}, /* Hawaiian */ + {"hay", {HB_TAG('H','A','Y',' ')}}, /* Haya */ + {"haz", {HB_TAG('H','A','Z',' ')}}, /* Hazaragi */ + {"he", {HB_TAG('I','W','R',' ')}}, /* Hebrew */ + {"hea", {HB_TAG('H','M','N',' ')}}, /* Northern Qiandong Miao -> Hmong */ + {"hi", {HB_TAG('H','I','N',' ')}}, /* Hindi */ + {"hil", {HB_TAG('H','I','L',' ')}}, /* Hiligaynon */ + {"hji", {HB_TAG('M','L','Y',' ')}}, /* Haji -> Malay */ + {"hlt", {HB_TAG('Q','I','N',' ')}}, /* Matu Chin -> Chin */ + {"hma", {HB_TAG('H','M','N',' ')}}, /* Southern Mashan Hmong -> Hmong */ + {"hmc", {HB_TAG('H','M','N',' ')}}, /* Central Huishui Hmong -> Hmong */ + {"hmd", {HB_TAG('H','M','N',' ')}}, /* Large Flowery Miao -> Hmong */ + {"hme", {HB_TAG('H','M','N',' ')}}, /* Eastern Huishui Hmong -> Hmong */ + {"hmg", {HB_TAG('H','M','N',' ')}}, /* Southwestern Guiyang Hmong -> Hmong */ + {"hmh", {HB_TAG('H','M','N',' ')}}, /* Southwestern Huishui Hmong -> Hmong */ + {"hmi", {HB_TAG('H','M','N',' ')}}, /* Northern Huishui Hmong -> Hmong */ + {"hmj", {HB_TAG('H','M','N',' ')}}, /* Ge -> Hmong */ + {"hml", {HB_TAG('H','M','N',' ')}}, /* Luopohe Hmong -> Hmong */ + {"hmm", {HB_TAG('H','M','N',' ')}}, /* Central Mashan Hmong -> Hmong */ + {"hmn", {HB_TAG('H','M','N',' ')}}, /* Hmong [macrolanguage] */ + {"hmp", {HB_TAG('H','M','N',' ')}}, /* Northern Mashan Hmong -> Hmong */ + {"hmq", {HB_TAG('H','M','N',' ')}}, /* Eastern Qiandong Miao -> Hmong */ + {"hms", {HB_TAG('H','M','N',' ')}}, /* Southern Qiandong Miao -> Hmong */ + {"hmw", {HB_TAG('H','M','N',' ')}}, /* Western Mashan Hmong -> Hmong */ + {"hmy", {HB_TAG('H','M','N',' ')}}, /* Southern Guiyang Hmong -> Hmong */ + {"hmz", {HB_TAG('H','M','N',' ')}}, /* Hmong Shua -> Hmong */ + {"hnd", {HB_TAG('H','N','D',' ')}}, /* Southern Hindko -> Hindko */ + {"hne", {HB_TAG('C','H','H',' ')}}, /* Chhattisgarhi -> Chattisgarhi */ + {"hnj", {HB_TAG('H','M','N',' ')}}, /* Hmong Njua -> Hmong */ + {"hno", {HB_TAG('H','N','D',' ')}}, /* Northern Hindko -> Hindko */ + {"ho", {HB_TAG('H','M','O',' ')}}, /* Hiri Motu */ + {"hoc", {HB_TAG('H','O',' ',' ')}}, /* Ho */ + {"hoi", {HB_TAG('A','T','H',' ')}}, /* Holikachuk -> Athapaskan */ + {"hoj", {HB_TAG('H','A','R',' ')}}, /* Hadothi -> Harauti */ + {"hr", {HB_TAG('H','R','V',' ')}}, /* Croatian */ + {"hrm", {HB_TAG('H','M','N',' ')}}, /* Horned Miao -> Hmong */ + {"hsb", {HB_TAG('U','S','B',' ')}}, /* Upper Sorbian */ + {"hsn", {HB_TAG('Z','H','S',' ')}}, /* Xiang Chinese -> Chinese Simplified */ + {"ht", {HB_TAG('H','A','I',' ')}}, /* Haitian (Haitian Creole) */ + {"hu", {HB_TAG('H','U','N',' ')}}, /* Hungarian */ + {"huj", {HB_TAG('H','M','N',' ')}}, /* Northern Guiyang Hmong -> Hmong */ + {"hup", {HB_TAG('A','T','H',' ')}}, /* Hupa -> Athapaskan */ + {"hy", {HB_TAG('H','Y','E','0'), /* Armenian -> Armenian East */ + HB_TAG('H','Y','E',' ')}}, /* Armenian */ + {"hyw", {HB_TAG('H','Y','E',' ')}}, /* Western Armenian -> Armenian */ + {"hz", {HB_TAG('H','E','R',' ')}}, /* Herero */ + {"ia", {HB_TAG('I','N','A',' ')}}, /* Interlingua (International Auxiliary Language Association) */ + {"iba", {HB_TAG('I','B','A',' ')}}, /* Iban */ + {"ibb", {HB_TAG('I','B','B',' ')}}, /* Ibibio */ + {"id", {HB_TAG('I','N','D',' ')}}, /* Indonesian */ + {"ida", {HB_TAG('L','U','H',' ')}}, /* Idakho-Isukha-Tiriki -> Luyia */ + {"ie", {HB_TAG('I','L','E',' ')}}, /* Interlingue */ + {"ig", {HB_TAG('I','B','O',' ')}}, /* Igbo */ + {"igb", {HB_TAG('E','B','I',' ')}}, /* Ebira */ + {"ii", {HB_TAG('Y','I','M',' ')}}, /* Sichuan Yi -> Yi Modern */ + {"ijc", {HB_TAG('I','J','O',' ')}}, /* Izon -> Ijo */ + {"ijo", {HB_TAG('I','J','O',' ')}}, /* Ijo [family] */ + {"ik", {HB_TAG('I','P','K',' ')}}, /* Inupiaq [macrolanguage] -> Inupiat */ + {"ike", {HB_TAG('I','N','U',' ')}}, /* Eastern Canadian Inuktitut -> Inuktitut */ + {"ikt", {HB_TAG('I','N','U',' ')}}, /* Inuinnaqtun -> Inuktitut */ + {"ilo", {HB_TAG('I','L','O',' ')}}, /* Iloko -> Ilokano */ + {"in", {HB_TAG('I','N','D',' ')}}, /* Indonesian (retired code) */ + {"ing", {HB_TAG('A','T','H',' ')}}, /* Degexit'an -> Athapaskan */ + {"inh", {HB_TAG('I','N','G',' ')}}, /* Ingush */ + {"io", {HB_TAG('I','D','O',' ')}}, /* Ido */ + {"is", {HB_TAG('I','S','L',' ')}}, /* Icelandic */ + {"it", {HB_TAG('I','T','A',' ')}}, /* Italian */ + {"iu", {HB_TAG('I','N','U',' ')}}, /* Inuktitut [macrolanguage] */ + {"iw", {HB_TAG('I','W','R',' ')}}, /* Hebrew (retired code) */ + {"ja", {HB_TAG('J','A','N',' ')}}, /* Japanese */ + {"jak", {HB_TAG('M','L','Y',' ')}}, /* Jakun -> Malay */ + {"jam", {HB_TAG('J','A','M',' ')}}, /* Jamaican Creole English -> Jamaican Creole */ + {"jax", {HB_TAG('M','L','Y',' ')}}, /* Jambi Malay -> Malay */ + {"jbo", {HB_TAG('J','B','O',' ')}}, /* Lojban */ + {"jct", {HB_TAG('J','C','T',' ')}}, /* Krymchak */ + {"ji", {HB_TAG('J','I','I',' ')}}, /* Yiddish (retired code) */ + {"jv", {HB_TAG('J','A','V',' ')}}, /* Javanese */ + {"jw", {HB_TAG('J','A','V',' ')}}, /* Javanese (retired code) */ + {"ka", {HB_TAG('K','A','T',' ')}}, /* Georgian */ + {"kaa", {HB_TAG('K','R','K',' ')}}, /* Kara-Kalpak -> Karakalpak */ + {"kab", {HB_TAG('K','A','B','0')}}, /* Kabyle */ + {"kam", {HB_TAG('K','M','B',' ')}}, /* Kamba (Kenya) */ + {"kar", {HB_TAG('K','R','N',' ')}}, /* Karen [family] */ + {"kbd", {HB_TAG('K','A','B',' ')}}, /* Kabardian */ + {"kby", {HB_TAG('K','N','R',' ')}}, /* Manga Kanuri -> Kanuri */ + {"kca", {HB_TAG('K','H','K',' '), /* Khanty -> Khanty-Kazim */ + HB_TAG('K','H','S',' '), /* Khanty -> Khanty-Shurishkar */ + HB_TAG('K','H','V',' ')}}, /* Khanty -> Khanty-Vakhi */ + {"kde", {HB_TAG('K','D','E',' ')}}, /* Makonde */ + {"kdr", {HB_TAG('K','R','M',' ')}}, /* Karaim */ + {"kdt", {HB_TAG('K','U','Y',' ')}}, /* Kuy */ + {"kea", {HB_TAG('K','E','A',' ')}}, /* Kabuverdianu (Crioulo) */ + {"kek", {HB_TAG('K','E','K',' ')}}, /* Kekchi */ + {"kex", {HB_TAG('K','K','N',' ')}}, /* Kukna -> Kokni */ + {"kfa", {HB_TAG('K','O','D',' ')}}, /* Kodava -> Kodagu */ + {"kfr", {HB_TAG('K','A','C',' ')}}, /* Kachhi -> Kachchi */ + {"kfx", {HB_TAG('K','U','L',' ')}}, /* Kullu Pahari -> Kulvi */ + {"kfy", {HB_TAG('K','M','N',' ')}}, /* Kumaoni */ + {"kg", {HB_TAG('K','O','N','0')}}, /* Kongo [macrolanguage] */ + {"kha", {HB_TAG('K','S','I',' ')}}, /* Khasi */ + {"khb", {HB_TAG('X','B','D',' ')}}, /* Lü */ + {"khk", {HB_TAG('M','N','G',' ')}}, /* Halh Mongolian -> Mongolian */ + {"kht", {HB_TAG('K','H','N',' '), /* Khamti -> Khamti Shan (Microsoft fonts) */ + HB_TAG('K','H','T',' ')}}, /* Khamti -> Khamti Shan (OpenType spec and SIL fonts) */ + {"khw", {HB_TAG('K','H','W',' ')}}, /* Khowar */ + {"ki", {HB_TAG('K','I','K',' ')}}, /* Kikuyu (Gikuyu) */ + {"kiu", {HB_TAG('K','I','U',' ')}}, /* Kirmanjki */ + {"kj", {HB_TAG('K','U','A',' ')}}, /* Kuanyama */ + {"kjd", {HB_TAG('K','J','D',' ')}}, /* Southern Kiwai */ + {"kjh", {HB_TAG('K','H','A',' ')}}, /* Khakas -> Khakass */ + {"kjp", {HB_TAG('K','J','P',' ')}}, /* Pwo Eastern Karen -> Eastern Pwo Karen */ + {"kjz", {HB_TAG('K','J','Z',' ')}}, /* Bumthangkha */ + {"kk", {HB_TAG('K','A','Z',' ')}}, /* Kazakh */ + {"kkz", {HB_TAG('A','T','H',' ')}}, /* Kaska -> Athapaskan */ + {"kl", {HB_TAG('G','R','N',' ')}}, /* Greenlandic */ + {"kln", {HB_TAG('K','A','L',' ')}}, /* Kalenjin [macrolanguage] */ + {"km", {HB_TAG('K','H','M',' ')}}, /* Khmer */ + {"kmb", {HB_TAG('M','B','N',' ')}}, /* Kimbundu -> Mbundu */ + {"kmr", {HB_TAG('K','U','R',' ')}}, /* Northern Kurdish -> Kurdish */ + {"kmw", {HB_TAG('K','M','O',' ')}}, /* Komo (Democratic Republic of Congo) */ + {"kmz", {HB_TAG('K','M','Z',' ')}}, /* Khorasani Turkish -> Khorasani Turkic */ + {"kn", {HB_TAG('K','A','N',' ')}}, /* Kannada */ + {"knc", {HB_TAG('K','N','R',' ')}}, /* Central Kanuri -> Kanuri */ + {"kng", {HB_TAG('K','O','N','0')}}, /* Koongo -> Kongo */ + {"knn", {HB_TAG('K','O','K',' ')}}, /* Konkani */ + {"ko", {HB_TAG('K','O','R',' ')}}, /* Korean */ + {"koi", {HB_TAG('K','O','P',' ')}}, /* Komi-Permyak */ + {"kok", {HB_TAG('K','O','K',' ')}}, /* Konkani [macrolanguage] */ + {"kos", {HB_TAG('K','O','S',' ')}}, /* Kosraean */ + {"koy", {HB_TAG('A','T','H',' ')}}, /* Koyukon -> Athapaskan */ + {"kpe", {HB_TAG('K','P','L',' ')}}, /* Kpelle [macrolanguage] */ + {"kpv", {HB_TAG('K','O','Z',' ')}}, /* Komi-Zyrian */ + {"kpy", {HB_TAG('K','Y','K',' ')}}, /* Koryak */ + {"kqs", {HB_TAG('K','I','S',' ')}}, /* Northern Kissi -> Kisii */ + {"kqy", {HB_TAG('K','R','T',' ')}}, /* Koorete */ + {"kr", {HB_TAG('K','N','R',' ')}}, /* Kanuri [macrolanguage] */ + {"krc", {HB_TAG('K','A','R',' '), /* Karachay-Balkar -> Karachay */ + HB_TAG('B','A','L',' ')}}, /* Karachay-Balkar -> Balkar */ + {"kri", {HB_TAG('K','R','I',' ')}}, /* Krio */ + {"krl", {HB_TAG('K','R','L',' ')}}, /* Karelian */ + {"krt", {HB_TAG('K','N','R',' ')}}, /* Tumari Kanuri -> Kanuri */ + {"kru", {HB_TAG('K','U','U',' ')}}, /* Kurukh */ + {"ks", {HB_TAG('K','S','H',' ')}}, /* Kashmiri */ + {"ksh", {HB_TAG('K','S','H','0')}}, /* Kölsch -> Ripuarian */ + {"kss", {HB_TAG('K','I','S',' ')}}, /* Southern Kisi -> Kisii */ + {"ksw", {HB_TAG('K','S','W',' ')}}, /* S’gaw Karen */ + {"ktb", {HB_TAG('K','E','B',' ')}}, /* Kambaata -> Kebena */ + {"ktu", {HB_TAG('K','O','N',' ')}}, /* Kituba (Democratic Republic of Congo) -> Kikongo */ + {"ktw", {HB_TAG('A','T','H',' ')}}, /* Kato -> Athapaskan */ + {"ku", {HB_TAG('K','U','R',' ')}}, /* Kurdish [macrolanguage] */ + {"kum", {HB_TAG('K','U','M',' ')}}, /* Kumyk */ + {"kuu", {HB_TAG('A','T','H',' ')}}, /* Upper Kuskokwim -> Athapaskan */ + {"kv", {HB_TAG('K','O','M',' ')}}, /* Komi [macrolanguage] */ + {"kvb", {HB_TAG('M','L','Y',' ')}}, /* Kubu -> Malay */ + {"kvr", {HB_TAG('M','L','Y',' ')}}, /* Kerinci -> Malay */ + {"kw", {HB_TAG('C','O','R',' ')}}, /* Cornish */ + {"kwy", {HB_TAG('K','O','N','0')}}, /* San Salvador Kongo -> Kongo */ + {"kxc", {HB_TAG('K','M','S',' ')}}, /* Konso -> Komso */ + {"kxd", {HB_TAG('M','L','Y',' ')}}, /* Brunei -> Malay */ + {"kxu", {HB_TAG('K','U','I',' ')}}, /* Kui (India) */ + {"ky", {HB_TAG('K','I','R',' ')}}, /* Kirghiz (Kyrgyz) */ + {"kyu", {HB_TAG('K','Y','U',' ')}}, /* Western Kayah */ + {"la", {HB_TAG('L','A','T',' ')}}, /* Latin */ + {"lad", {HB_TAG('J','U','D',' ')}}, /* Ladino */ + {"lb", {HB_TAG('L','T','Z',' ')}}, /* Luxembourgish */ + {"lbe", {HB_TAG('L','A','K',' ')}}, /* Lak */ + {"lbj", {HB_TAG('L','D','K',' ')}}, /* Ladakhi */ + {"lbl", {HB_TAG('B','I','K',' ')}}, /* Libon Bikol -> Bikol */ + {"lce", {HB_TAG('M','L','Y',' ')}}, /* Loncong -> Malay */ + {"lcf", {HB_TAG('M','L','Y',' ')}}, /* Lubu -> Malay */ + {"ldi", {HB_TAG('K','O','N','0')}}, /* Laari -> Kongo */ + {"lez", {HB_TAG('L','E','Z',' ')}}, /* Lezghian -> Lezgi */ + {"lg", {HB_TAG('L','U','G',' ')}}, /* Ganda */ + {"li", {HB_TAG('L','I','M',' ')}}, /* Limburgish */ + {"lif", {HB_TAG('L','M','B',' ')}}, /* Limbu */ + {"lij", {HB_TAG('L','I','J',' ')}}, /* Ligurian */ + {"lis", {HB_TAG('L','I','S',' ')}}, /* Lisu */ + {"liw", {HB_TAG('M','L','Y',' ')}}, /* Col -> Malay */ + {"ljp", {HB_TAG('L','J','P',' ')}}, /* Lampung Api -> Lampung */ + {"lkb", {HB_TAG('L','U','H',' ')}}, /* Kabras -> Luyia */ + {"lki", {HB_TAG('L','K','I',' ')}}, /* Laki */ + {"lko", {HB_TAG('L','U','H',' ')}}, /* Khayo -> Luyia */ + {"lks", {HB_TAG('L','U','H',' ')}}, /* Kisa -> Luyia */ + {"lld", {HB_TAG('L','A','D',' ')}}, /* Ladin */ + {"lmn", {HB_TAG('L','A','M',' ')}}, /* Lambadi -> Lambani */ + {"lmo", {HB_TAG('L','M','O',' ')}}, /* Lombard */ + {"ln", {HB_TAG('L','I','N',' ')}}, /* Lingala */ + {"lo", {HB_TAG('L','A','O',' ')}}, /* Lao */ + {"lom", {HB_TAG('L','O','M',' ')}}, /* Loma (Liberia) */ + {"lrc", {HB_TAG('L','R','C',' ')}}, /* Northern Luri -> Luri */ + {"lri", {HB_TAG('L','U','H',' ')}}, /* Marachi -> Luyia */ + {"lrm", {HB_TAG('L','U','H',' ')}}, /* Marama -> Luyia */ + {"lsm", {HB_TAG('L','U','H',' ')}}, /* Saamia -> Luyia */ + {"lt", {HB_TAG('L','T','H',' ')}}, /* Lithuanian */ + {"ltg", {HB_TAG('L','V','I',' ')}}, /* Latgalian -> Latvian */ + {"lto", {HB_TAG('L','U','H',' ')}}, /* Tsotso -> Luyia */ + {"lts", {HB_TAG('L','U','H',' ')}}, /* Tachoni -> Luyia */ + {"lu", {HB_TAG('L','U','B',' ')}}, /* Luba-Katanga */ + {"lua", {HB_TAG('L','U','A',' ')}}, /* Luba-Lulua */ + {"luo", {HB_TAG('L','U','O',' ')}}, /* Luo (Kenya and Tanzania) */ + {"lus", {HB_TAG('M','I','Z',' ')}}, /* Lushai -> Mizo */ + {"luy", {HB_TAG('L','U','H',' ')}}, /* Luyia [macrolanguage] */ + {"luz", {HB_TAG('L','R','C',' ')}}, /* Southern Luri -> Luri */ + {"lv", {HB_TAG('L','V','I',' ')}}, /* Latvian [macrolanguage] */ + {"lvs", {HB_TAG('L','V','I',' ')}}, /* Standard Latvian -> Latvian */ + {"lwg", {HB_TAG('L','U','H',' ')}}, /* Wanga -> Luyia */ + {"lzh", {HB_TAG('Z','H','T',' ')}}, /* Literary Chinese -> Chinese Traditional */ + {"lzz", {HB_TAG('L','A','Z',' ')}}, /* Laz */ + {"mad", {HB_TAG('M','A','D',' ')}}, /* Madurese -> Madura */ + {"mag", {HB_TAG('M','A','G',' ')}}, /* Magahi */ + {"mai", {HB_TAG('M','T','H',' ')}}, /* Maithili */ + {"mak", {HB_TAG('M','K','R',' ')}}, /* Makasar */ + {"mam", {HB_TAG('M','A','M',' ')}}, /* Mam */ + {"man", {HB_TAG('M','N','K',' ')}}, /* Mandingo [macrolanguage] -> Maninka */ + {"max", {HB_TAG('M','L','Y',' ')}}, /* North Moluccan Malay -> Malay */ + {"mbo", {HB_TAG('M','B','O',' ')}}, /* Mbo (Cameroon) */ + {"mct", {HB_TAG('B','T','I',' ')}}, /* Mengisa -> Beti */ + {"mdf", {HB_TAG('M','O','K',' ')}}, /* Moksha */ + {"mdr", {HB_TAG('M','D','R',' ')}}, /* Mandar */ + {"mdy", {HB_TAG('M','L','E',' ')}}, /* Male (Ethiopia) */ + {"men", {HB_TAG('M','D','E',' ')}}, /* Mende (Sierra Leone) */ + {"meo", {HB_TAG('M','L','Y',' ')}}, /* Kedah Malay -> Malay */ + {"mer", {HB_TAG('M','E','R',' ')}}, /* Meru */ + {"mfa", {HB_TAG('M','F','A',' ')}}, /* Pattani Malay */ + {"mfb", {HB_TAG('M','L','Y',' ')}}, /* Bangka -> Malay */ + {"mfe", {HB_TAG('M','F','E',' ')}}, /* Morisyen */ + {"mg", {HB_TAG('M','L','G',' ')}}, /* Malagasy [macrolanguage] */ + {"mh", {HB_TAG('M','A','H',' ')}}, /* Marshallese */ + {"mhr", {HB_TAG('L','M','A',' ')}}, /* Eastern Mari -> Low Mari */ + {"mhv", {HB_TAG('A','R','K',' ')}}, /* Arakanese (retired code) -> Rakhine */ + {"mi", {HB_TAG('M','R','I',' ')}}, /* Maori */ + {"min", {HB_TAG('M','I','N',' ')}}, /* Minangkabau */ + {"mk", {HB_TAG('M','K','D',' ')}}, /* Macedonian */ + {"mku", {HB_TAG('M','N','K',' ')}}, /* Konyanka Maninka -> Maninka */ + {"mkw", {HB_TAG('M','K','W',' ')}}, /* Kituba (Congo) */ + {"ml", {HB_TAG('M','A','L',' '), /* Malayalam -> Malayalam Traditional */ + HB_TAG('M','L','R',' ')}}, /* Malayalam -> Malayalam Reformed */ + {"mlq", {HB_TAG('M','L','N',' '), /* Western Maninkakan -> Malinke */ + HB_TAG('M','N','K',' ')}}, /* Western Maninkakan -> Maninka */ + {"mmr", {HB_TAG('H','M','N',' ')}}, /* Western Xiangxi Miao -> Hmong */ + {"mn", {HB_TAG('M','N','G',' ')}}, /* Mongolian [macrolanguage] */ + {"mnc", {HB_TAG('M','C','H',' ')}}, /* Manchu */ + {"mni", {HB_TAG('M','N','I',' ')}}, /* Manipuri */ + {"mnk", {HB_TAG('M','N','D',' '), /* Mandinka */ + HB_TAG('M','N','K',' ')}}, /* Mandinka -> Maninka */ + {"mnp", {HB_TAG('Z','H','S',' ')}}, /* Min Bei Chinese -> Chinese Simplified */ + {"mns", {HB_TAG('M','A','N',' ')}}, /* Mansi */ + {"mnw", {HB_TAG('M','O','N',' ')}}, /* Mon */ + {"mo", {HB_TAG('M','O','L',' ')}}, /* Moldavian (retired code) */ + {"moh", {HB_TAG('M','O','H',' ')}}, /* Mohawk */ + {"mos", {HB_TAG('M','O','S',' ')}}, /* Mossi */ + {"mpe", {HB_TAG('M','A','J',' ')}}, /* Majang */ + {"mqg", {HB_TAG('M','L','Y',' ')}}, /* Kota Bangun Kutai Malay -> Malay */ + {"mr", {HB_TAG('M','A','R',' ')}}, /* Marathi */ + {"mrh", {HB_TAG('Q','I','N',' ')}}, /* Mara Chin -> Chin */ + {"mrj", {HB_TAG('H','M','A',' ')}}, /* Western Mari -> High Mari */ + {"ms", {HB_TAG('M','L','Y',' ')}}, /* Malay [macrolanguage] */ + {"msc", {HB_TAG('M','N','K',' ')}}, /* Sankaran Maninka -> Maninka */ + {"msh", {HB_TAG('M','L','G',' ')}}, /* Masikoro Malagasy -> Malagasy */ + {"msi", {HB_TAG('M','L','Y',' ')}}, /* Sabah Malay -> Malay */ + {"mt", {HB_TAG('M','T','S',' ')}}, /* Maltese */ + {"mtr", {HB_TAG('M','A','W',' ')}}, /* Mewari -> Marwari */ + {"mui", {HB_TAG('M','L','Y',' ')}}, /* Musi -> Malay */ + {"mup", {HB_TAG('R','A','J',' ')}}, /* Malvi -> Rajasthani */ + {"muq", {HB_TAG('H','M','N',' ')}}, /* Eastern Xiangxi Miao -> Hmong */ + {"mus", {HB_TAG('M','U','S',' ')}}, /* Creek -> Muscogee */ + {"mvb", {HB_TAG('A','T','H',' ')}}, /* Mattole -> Athapaskan */ + {"mve", {HB_TAG('M','A','W',' ')}}, /* Marwari (Pakistan) */ + {"mvf", {HB_TAG('M','N','G',' ')}}, /* Peripheral Mongolian -> Mongolian */ + {"mwk", {HB_TAG('M','N','K',' ')}}, /* Kita Maninkakan -> Maninka */ + {"mwl", {HB_TAG('M','W','L',' ')}}, /* Mirandese */ + {"mwr", {HB_TAG('M','A','W',' ')}}, /* Marwari [macrolanguage] */ + {"mww", {HB_TAG('M','W','W',' ')}}, /* Hmong Daw */ + {"my", {HB_TAG('B','R','M',' ')}}, /* Burmese */ + {"mym", {HB_TAG('M','E','N',' ')}}, /* Me'en */ + {"myn", {HB_TAG('M','Y','N',' ')}}, /* Mayan [family] */ + {"myq", {HB_TAG('M','N','K',' ')}}, /* Forest Maninka (retired code) -> Maninka */ + {"myv", {HB_TAG('E','R','Z',' ')}}, /* Erzya */ + {"mzn", {HB_TAG('M','Z','N',' ')}}, /* Mazanderani */ + {"na", {HB_TAG('N','A','U',' ')}}, /* Nauru -> Nauruan */ + {"nag", {HB_TAG('N','A','G',' ')}}, /* Naga Pidgin -> Naga-Assamese */ + {"nah", {HB_TAG('N','A','H',' ')}}, /* Nahuatl [family] */ + {"nan", {HB_TAG('Z','H','S',' ')}}, /* Min Nan Chinese -> Chinese Simplified */ + {"nap", {HB_TAG('N','A','P',' ')}}, /* Neapolitan */ + {"nb", {HB_TAG('N','O','R',' ')}}, /* Norwegian Bokmål -> Norwegian */ + {"nd", {HB_TAG('N','D','B',' ')}}, /* North Ndebele -> Ndebele */ + {"ndc", {HB_TAG('N','D','C',' ')}}, /* Ndau */ + {"nds", {HB_TAG('N','D','S',' ')}}, /* Low Saxon */ + {"ne", {HB_TAG('N','E','P',' ')}}, /* Nepali [macrolanguage] */ + {"new", {HB_TAG('N','E','W',' ')}}, /* Newari */ + {"ng", {HB_TAG('N','D','G',' ')}}, /* Ndonga */ + {"nga", {HB_TAG('N','G','A',' ')}}, /* Ngbaka */ + {"ngl", {HB_TAG('L','M','W',' ')}}, /* Lomwe */ + {"ngo", {HB_TAG('S','X','T',' ')}}, /* Ngoni -> Sutu */ + {"nhd", {HB_TAG('G','U','A',' ')}}, /* Chiripá -> Guarani */ + {"niq", {HB_TAG('K','A','L',' ')}}, /* Nandi -> Kalenjin */ + {"niu", {HB_TAG('N','I','U',' ')}}, /* Niuean */ + {"niv", {HB_TAG('G','I','L',' ')}}, /* Gilyak */ + {"njz", {HB_TAG('N','I','S',' ')}}, /* Nyishi -> Nisi */ + {"nl", {HB_TAG('N','L','D',' ')}}, /* Dutch */ + {"nle", {HB_TAG('L','U','H',' ')}}, /* East Nyala -> Luyia */ + {"nn", {HB_TAG('N','Y','N',' ')}}, /* Norwegian Nynorsk (Nynorsk, Norwegian) */ + {"no", {HB_TAG('N','O','R',' ')}}, /* Norwegian [macrolanguage] */ + {"nod", {HB_TAG('N','T','A',' ')}}, /* Northern Thai -> Northern Tai */ + {"noe", {HB_TAG('N','O','E',' ')}}, /* Nimadi */ + {"nog", {HB_TAG('N','O','G',' ')}}, /* Nogai */ + {"nov", {HB_TAG('N','O','V',' ')}}, /* Novial */ + {"npi", {HB_TAG('N','E','P',' ')}}, /* Nepali */ + {"nqo", {HB_TAG('N','K','O',' ')}}, /* N'Ko */ + {"nr", {HB_TAG('N','D','B',' ')}}, /* South Ndebele -> Ndebele */ + {"nsk", {HB_TAG('N','A','S',' ')}}, /* Naskapi */ + {"nso", {HB_TAG('N','S','O',' ')}}, /* Pedi -> Sotho, Northern */ + {"nv", {HB_TAG('N','A','V',' '), /* Navajo */ + HB_TAG('A','T','H',' ')}}, /* Navajo -> Athapaskan */ + {"ny", {HB_TAG('C','H','I',' ')}}, /* Chichewa (Chewa, Nyanja) */ + {"nyd", {HB_TAG('L','U','H',' ')}}, /* Nyore -> Luyia */ + {"nym", {HB_TAG('N','Y','M',' ')}}, /* Nyamwezi */ + {"nyn", {HB_TAG('N','K','L',' ')}}, /* Nyankole */ + {"nza", {HB_TAG('N','Z','A',' ')}}, /* Tigon Mbembe -> Mbembe Tigon */ + {"oc", {HB_TAG('O','C','I',' ')}}, /* Occitan (post 1500) */ + {"oj", {HB_TAG('O','J','B',' ')}}, /* Ojibwa [macrolanguage] -> Ojibway */ + {"ojb", {HB_TAG('O','J','B',' ')}}, /* Northwestern Ojibwa -> Ojibway */ + {"ojc", {HB_TAG('O','J','B',' ')}}, /* Central Ojibwa -> Ojibway */ + {"ojg", {HB_TAG('O','J','B',' ')}}, /* Eastern Ojibwa -> Ojibway */ + {"ojs", {HB_TAG('O','C','R',' ')}}, /* Severn Ojibwa -> Oji-Cree */ + {"ojw", {HB_TAG('O','J','B',' ')}}, /* Western Ojibwa -> Ojibway */ + {"oki", {HB_TAG('K','A','L',' ')}}, /* Okiek -> Kalenjin */ + {"okm", {HB_TAG('K','O','H',' ')}}, /* Middle Korean (10th-16th cent.) -> Korean Old Hangul */ + {"om", {HB_TAG('O','R','O',' ')}}, /* Oromo [macrolanguage] */ + {"or", {HB_TAG('O','R','I',' ')}}, /* Odia (formerly Oriya) [macrolanguage] */ + {"orc", {HB_TAG('O','R','O',' ')}}, /* Orma -> Oromo */ + {"orn", {HB_TAG('M','L','Y',' ')}}, /* Orang Kanaq -> Malay */ + {"ors", {HB_TAG('M','L','Y',' ')}}, /* Orang Seletar -> Malay */ + {"ory", {HB_TAG('O','R','I',' ')}}, /* Odia (formerly Oriya) */ + {"os", {HB_TAG('O','S','S',' ')}}, /* Ossetian */ + {"otw", {HB_TAG('O','J','B',' ')}}, /* Ottawa -> Ojibway */ + {"pa", {HB_TAG('P','A','N',' ')}}, /* Punjabi */ + {"pag", {HB_TAG('P','A','G',' ')}}, /* Pangasinan */ + {"pam", {HB_TAG('P','A','M',' ')}}, /* Pampanga -> Pampangan */ + {"pap", {HB_TAG('P','A','P','0')}}, /* Papiamento -> Papiamentu */ + {"pau", {HB_TAG('P','A','U',' ')}}, /* Palauan */ + {"pbt", {HB_TAG('P','A','S',' ')}}, /* Southern Pashto -> Pashto */ + {"pbu", {HB_TAG('P','A','S',' ')}}, /* Northern Pashto -> Pashto */ + {"pcc", {HB_TAG('P','C','C',' ')}}, /* Bouyei */ + {"pcd", {HB_TAG('P','C','D',' ')}}, /* Picard */ + {"pce", {HB_TAG('P','L','G',' ')}}, /* Ruching Palaung -> Palaung */ + {"pck", {HB_TAG('Q','I','N',' ')}}, /* Paite Chin -> Chin */ + {"pdc", {HB_TAG('P','D','C',' ')}}, /* Pennsylvania German */ + {"pel", {HB_TAG('M','L','Y',' ')}}, /* Pekal -> Malay */ + {"pes", {HB_TAG('F','A','R',' ')}}, /* Iranian Persian -> Persian */ + {"pga", {HB_TAG('A','R','A',' ')}}, /* Sudanese Creole Arabic -> Arabic */ + {"phk", {HB_TAG('P','H','K',' ')}}, /* Phake */ + {"pi", {HB_TAG('P','A','L',' ')}}, /* Pali */ + {"pih", {HB_TAG('P','I','H',' ')}}, /* Pitcairn-Norfolk -> Norfolk */ + {"pko", {HB_TAG('K','A','L',' ')}}, /* Pökoot -> Kalenjin */ + {"pl", {HB_TAG('P','L','K',' ')}}, /* Polish */ + {"pll", {HB_TAG('P','L','G',' ')}}, /* Shwe Palaung -> Palaung */ + {"plp", {HB_TAG('P','A','P',' ')}}, /* Palpa */ + {"plt", {HB_TAG('M','L','G',' ')}}, /* Plateau Malagasy -> Malagasy */ + {"pms", {HB_TAG('P','M','S',' ')}}, /* Piemontese */ + {"pnb", {HB_TAG('P','N','B',' ')}}, /* Western Panjabi */ + {"poh", {HB_TAG('P','O','H',' ')}}, /* Poqomchi' -> Pocomchi */ + {"pon", {HB_TAG('P','O','N',' ')}}, /* Pohnpeian */ + {"ppa", {HB_TAG('B','A','G',' ')}}, /* Pao (retired code) -> Baghelkhandi */ + {"pro", {HB_TAG('P','R','O',' ')}}, /* Old Provençal (to 1500) -> Provençal / Old Provençal */ + {"prs", {HB_TAG('D','R','I',' ')}}, /* Dari */ + {"ps", {HB_TAG('P','A','S',' ')}}, /* Pashto [macrolanguage] */ + {"pse", {HB_TAG('M','L','Y',' ')}}, /* Central Malay -> Malay */ + {"pst", {HB_TAG('P','A','S',' ')}}, /* Central Pashto -> Pashto */ + {"pt", {HB_TAG('P','T','G',' ')}}, /* Portuguese */ + {"pwo", {HB_TAG('P','W','O',' ')}}, /* Pwo Western Karen -> Western Pwo Karen */ + {"qu", {HB_TAG('Q','U','Z',' ')}}, /* Quechua [macrolanguage] */ + {"qub", {HB_TAG('Q','W','H',' ')}}, /* Huallaga Huánuco Quechua -> Quechua (Peru) */ + {"quc", {HB_TAG('Q','U','C',' ')}}, /* K’iche’ */ + {"qud", {HB_TAG('Q','V','I',' ')}}, /* Calderón Highland Quichua -> Quechua (Ecuador) */ + {"quf", {HB_TAG('Q','U','Z',' ')}}, /* Lambayeque Quechua -> Quechua */ + {"qug", {HB_TAG('Q','V','I',' ')}}, /* Chimborazo Highland Quichua -> Quechua (Ecuador) */ + {"quh", {HB_TAG('Q','U','H',' ')}}, /* South Bolivian Quechua -> Quechua (Bolivia) */ + {"quk", {HB_TAG('Q','U','Z',' ')}}, /* Chachapoyas Quechua -> Quechua */ + {"qul", {HB_TAG('Q','U','Z',' ')}}, /* North Bolivian Quechua -> Quechua */ + {"qup", {HB_TAG('Q','V','I',' ')}}, /* Southern Pastaza Quechua -> Quechua (Ecuador) */ + {"qur", {HB_TAG('Q','W','H',' ')}}, /* Yanahuanca Pasco Quechua -> Quechua (Peru) */ + {"qus", {HB_TAG('Q','U','H',' ')}}, /* Santiago del Estero Quichua -> Quechua (Bolivia) */ + {"quw", {HB_TAG('Q','V','I',' ')}}, /* Tena Lowland Quichua -> Quechua (Ecuador) */ + {"qux", {HB_TAG('Q','W','H',' ')}}, /* Yauyos Quechua -> Quechua (Peru) */ + {"quy", {HB_TAG('Q','U','Z',' ')}}, /* Ayacucho Quechua -> Quechua */ + {"quz", {HB_TAG('Q','U','Z',' ')}}, /* Cusco Quechua -> Quechua */ + {"qva", {HB_TAG('Q','W','H',' ')}}, /* Ambo-Pasco Quechua -> Quechua (Peru) */ + {"qvc", {HB_TAG('Q','U','Z',' ')}}, /* Cajamarca Quechua -> Quechua */ + {"qve", {HB_TAG('Q','U','Z',' ')}}, /* Eastern Apurímac Quechua -> Quechua */ + {"qvh", {HB_TAG('Q','W','H',' ')}}, /* Huamalíes-Dos de Mayo Huánuco Quechua -> Quechua (Peru) */ + {"qvi", {HB_TAG('Q','V','I',' ')}}, /* Imbabura Highland Quichua -> Quechua (Ecuador) */ + {"qvj", {HB_TAG('Q','V','I',' ')}}, /* Loja Highland Quichua -> Quechua (Ecuador) */ + {"qvl", {HB_TAG('Q','W','H',' ')}}, /* Cajatambo North Lima Quechua -> Quechua (Peru) */ + {"qvm", {HB_TAG('Q','W','H',' ')}}, /* Margos-Yarowilca-Lauricocha Quechua -> Quechua (Peru) */ + {"qvn", {HB_TAG('Q','W','H',' ')}}, /* North Junín Quechua -> Quechua (Peru) */ + {"qvo", {HB_TAG('Q','V','I',' ')}}, /* Napo Lowland Quechua -> Quechua (Ecuador) */ + {"qvp", {HB_TAG('Q','W','H',' ')}}, /* Pacaraos Quechua -> Quechua (Peru) */ + {"qvs", {HB_TAG('Q','U','Z',' ')}}, /* San Martín Quechua -> Quechua */ + {"qvw", {HB_TAG('Q','W','H',' ')}}, /* Huaylla Wanca Quechua -> Quechua (Peru) */ + {"qvz", {HB_TAG('Q','V','I',' ')}}, /* Northern Pastaza Quichua -> Quechua (Ecuador) */ + {"qwa", {HB_TAG('Q','W','H',' ')}}, /* Corongo Ancash Quechua -> Quechua (Peru) */ + {"qwc", {HB_TAG('Q','U','Z',' ')}}, /* Classical Quechua -> Quechua */ + {"qwh", {HB_TAG('Q','W','H',' ')}}, /* Huaylas Ancash Quechua -> Quechua (Peru) */ + {"qws", {HB_TAG('Q','W','H',' ')}}, /* Sihuas Ancash Quechua -> Quechua (Peru) */ + {"qxa", {HB_TAG('Q','W','H',' ')}}, /* Chiquián Ancash Quechua -> Quechua (Peru) */ + {"qxc", {HB_TAG('Q','W','H',' ')}}, /* Chincha Quechua -> Quechua (Peru) */ + {"qxh", {HB_TAG('Q','W','H',' ')}}, /* Panao Huánuco Quechua -> Quechua (Peru) */ + {"qxl", {HB_TAG('Q','V','I',' ')}}, /* Salasaca Highland Quichua -> Quechua (Ecuador) */ + {"qxn", {HB_TAG('Q','W','H',' ')}}, /* Northern Conchucos Ancash Quechua -> Quechua (Peru) */ + {"qxo", {HB_TAG('Q','W','H',' ')}}, /* Southern Conchucos Ancash Quechua -> Quechua (Peru) */ + {"qxp", {HB_TAG('Q','U','Z',' ')}}, /* Puno Quechua -> Quechua */ + {"qxr", {HB_TAG('Q','V','I',' ')}}, /* Cañar Highland Quichua -> Quechua (Ecuador) */ + {"qxt", {HB_TAG('Q','W','H',' ')}}, /* Santa Ana de Tusi Pasco Quechua -> Quechua (Peru) */ + {"qxu", {HB_TAG('Q','U','Z',' ')}}, /* Arequipa-La Unión Quechua -> Quechua */ + {"qxw", {HB_TAG('Q','W','H',' ')}}, /* Jauja Wanca Quechua -> Quechua (Peru) */ + {"rag", {HB_TAG('L','U','H',' ')}}, /* Logooli -> Luyia */ + {"raj", {HB_TAG('R','A','J',' ')}}, /* Rajasthani [macrolanguage] */ + {"rar", {HB_TAG('R','A','R',' ')}}, /* Rarotongan */ + {"rbb", {HB_TAG('P','L','G',' ')}}, /* Rumai Palaung -> Palaung */ + {"rbl", {HB_TAG('B','I','K',' ')}}, /* Miraya Bikol -> Bikol */ + {"rej", {HB_TAG('R','E','J',' ')}}, /* Rejang */ + {"ria", {HB_TAG('R','I','A',' ')}}, /* Riang (India) */ + {"rif", {HB_TAG('R','I','F',' ')}}, /* Tarifit */ + {"rit", {HB_TAG('R','I','T',' ')}}, /* Ritarungo */ + {"rki", {HB_TAG('A','R','K',' ')}}, /* Rakhine */ + {"rkw", {HB_TAG('R','K','W',' ')}}, /* Arakwal */ + {"rm", {HB_TAG('R','M','S',' ')}}, /* Romansh */ + {"rmc", {HB_TAG('R','O','Y',' ')}}, /* Carpathian Romani -> Romany */ + {"rmf", {HB_TAG('R','O','Y',' ')}}, /* Kalo Finnish Romani -> Romany */ + {"rml", {HB_TAG('R','O','Y',' ')}}, /* Baltic Romani -> Romany */ + {"rmn", {HB_TAG('R','O','Y',' ')}}, /* Balkan Romani -> Romany */ + {"rmo", {HB_TAG('R','O','Y',' ')}}, /* Sinte Romani -> Romany */ + {"rmw", {HB_TAG('R','O','Y',' ')}}, /* Welsh Romani -> Romany */ + {"rmy", {HB_TAG('R','M','Y',' ')}}, /* Vlax Romani */ + {"rmz", {HB_TAG('A','R','K',' ')}}, /* Marma -> Rakhine */ + {"rn", {HB_TAG('R','U','N',' ')}}, /* Rundi */ + {"rnl", {HB_TAG('H','A','L',' ')}}, /* Ranglong -> Halam (Falam Chin) */ + {"ro", {HB_TAG('R','O','M',' ')}}, /* Romanian */ + {"rom", {HB_TAG('R','O','Y',' ')}}, /* Romany [macrolanguage] */ + {"rtm", {HB_TAG('R','T','M',' ')}}, /* Rotuman */ + {"ru", {HB_TAG('R','U','S',' ')}}, /* Russian */ + {"rue", {HB_TAG('R','S','Y',' ')}}, /* Rusyn */ + {"rup", {HB_TAG('R','U','P',' ')}}, /* Aromanian */ + {"rw", {HB_TAG('R','U','A',' ')}}, /* Kinyarwanda */ + {"rwr", {HB_TAG('M','A','W',' ')}}, /* Marwari (India) */ + {"sa", {HB_TAG('S','A','N',' ')}}, /* Sanskrit */ + {"sah", {HB_TAG('Y','A','K',' ')}}, /* Yakut -> Sakha */ + {"sam", {HB_TAG('P','A','A',' ')}}, /* Samaritan Aramaic -> Palestinian Aramaic */ + {"sas", {HB_TAG('S','A','S',' ')}}, /* Sasak */ + {"sat", {HB_TAG('S','A','T',' ')}}, /* Santali */ + {"sc", {HB_TAG('S','R','D',' ')}}, /* Sardinian [macrolanguage] */ + {"sck", {HB_TAG('S','A','D',' ')}}, /* Sadri */ + {"scn", {HB_TAG('S','C','N',' ')}}, /* Sicilian */ + {"sco", {HB_TAG('S','C','O',' ')}}, /* Scots */ + {"scs", {HB_TAG('S','C','S',' '), /* North Slavey */ + HB_TAG('S','L','A',' '), /* North Slavey -> Slavey */ + HB_TAG('A','T','H',' ')}}, /* North Slavey -> Athapaskan */ + {"sd", {HB_TAG('S','N','D',' ')}}, /* Sindhi */ + {"sdc", {HB_TAG('S','R','D',' ')}}, /* Sassarese Sardinian -> Sardinian */ + {"sdh", {HB_TAG('K','U','R',' ')}}, /* Southern Kurdish -> Kurdish */ + {"sdn", {HB_TAG('S','R','D',' ')}}, /* Gallurese Sardinian -> Sardinian */ + {"se", {HB_TAG('N','S','M',' ')}}, /* Northern Sami */ + {"seh", {HB_TAG('S','N','A',' ')}}, /* Sena */ + {"sek", {HB_TAG('A','T','H',' ')}}, /* Sekani -> Athapaskan */ + {"sel", {HB_TAG('S','E','L',' ')}}, /* Selkup */ + {"sez", {HB_TAG('Q','I','N',' ')}}, /* Senthang Chin -> Chin */ + {"sfm", {HB_TAG('H','M','N',' ')}}, /* Small Flowery Miao -> Hmong */ + {"sg", {HB_TAG('S','G','O',' ')}}, /* Sango */ + {"sga", {HB_TAG('S','G','A',' ')}}, /* Old Irish (to 900) */ + {"sgc", {HB_TAG('K','A','L',' ')}}, /* Kipsigis -> Kalenjin */ + {"sgs", {HB_TAG('S','G','S',' ')}}, /* Samogitian */ + {"sgw", {HB_TAG('C','H','G',' '), /* Sebat Bet Gurage -> Chaha Gurage */ + HB_TAG('S','G','W',' ')}}, /* Sebat Bet Gurage -> Chaha Gurage (SIL fonts) */ + {"shi", {HB_TAG('S','H','I',' ')}}, /* Tachelhit */ + {"shn", {HB_TAG('S','H','N',' ')}}, /* Shan */ + {"shu", {HB_TAG('A','R','A',' ')}}, /* Chadian Arabic -> Arabic */ + {"si", {HB_TAG('S','N','H',' ')}}, /* Sinhala (Sinhalese) */ + {"sid", {HB_TAG('S','I','D',' ')}}, /* Sidamo */ + {"sjd", {HB_TAG('K','S','M',' ')}}, /* Kildin Sami */ + {"sjo", {HB_TAG('S','I','B',' ')}}, /* Xibe -> Sibe */ + {"sk", {HB_TAG('S','K','Y',' ')}}, /* Slovak */ + {"skg", {HB_TAG('M','L','G',' ')}}, /* Sakalava Malagasy -> Malagasy */ + {"skr", {HB_TAG('S','R','K',' ')}}, /* Saraiki */ + {"sl", {HB_TAG('S','L','V',' ')}}, /* Slovenian */ + {"sm", {HB_TAG('S','M','O',' ')}}, /* Samoan */ + {"sma", {HB_TAG('S','S','M',' ')}}, /* Southern Sami */ + {"smj", {HB_TAG('L','S','M',' ')}}, /* Lule Sami */ + {"smn", {HB_TAG('I','S','M',' ')}}, /* Inari Sami */ + {"sms", {HB_TAG('S','K','S',' ')}}, /* Skolt Sami */ + {"sn", {HB_TAG('S','N','A','0')}}, /* Shona */ + {"snk", {HB_TAG('S','N','K',' ')}}, /* Soninke */ + {"so", {HB_TAG('S','M','L',' ')}}, /* Somali */ + {"sop", {HB_TAG('S','O','P',' ')}}, /* Songe */ + {"spv", {HB_TAG('O','R','I',' ')}}, /* Sambalpuri -> Odia (formerly Oriya) */ + {"spy", {HB_TAG('K','A','L',' ')}}, /* Sabaot -> Kalenjin */ + {"sq", {HB_TAG('S','Q','I',' ')}}, /* Albanian [macrolanguage] */ + {"sr", {HB_TAG('S','R','B',' ')}}, /* Serbian */ + {"src", {HB_TAG('S','R','D',' ')}}, /* Logudorese Sardinian -> Sardinian */ + {"sro", {HB_TAG('S','R','D',' ')}}, /* Campidanese Sardinian -> Sardinian */ + {"srr", {HB_TAG('S','R','R',' ')}}, /* Serer */ + {"srs", {HB_TAG('A','T','H',' ')}}, /* Sarsi -> Athapaskan */ + {"ss", {HB_TAG('S','W','Z',' ')}}, /* Swati */ + {"ssh", {HB_TAG('A','R','A',' ')}}, /* Shihhi Arabic -> Arabic */ + {"st", {HB_TAG('S','O','T',' ')}}, /* Southern Sotho -> Sotho, Southern */ + {"stq", {HB_TAG('S','T','Q',' ')}}, /* Saterfriesisch -> Saterland Frisian */ + {"stv", {HB_TAG('S','I','G',' ')}}, /* Silt'e -> Silte Gurage */ + {"su", {HB_TAG('S','U','N',' ')}}, /* Sundanese */ + {"suk", {HB_TAG('S','U','K',' ')}}, /* Sukuma */ + {"suq", {HB_TAG('S','U','R',' ')}}, /* Suri */ + {"sv", {HB_TAG('S','V','E',' ')}}, /* Swedish */ + {"sva", {HB_TAG('S','V','A',' ')}}, /* Svan */ + {"sw", {HB_TAG('S','W','K',' ')}}, /* Swahili [macrolanguage] */ + {"swb", {HB_TAG('C','M','R',' ')}}, /* Maore Comorian -> Comorian */ + {"swc", {HB_TAG('S','W','K',' ')}}, /* Congo Swahili -> Swahili */ + {"swh", {HB_TAG('S','W','K',' ')}}, /* Swahili */ + {"swv", {HB_TAG('M','A','W',' ')}}, /* Shekhawati -> Marwari */ + {"sxu", {HB_TAG('S','X','U',' ')}}, /* Upper Saxon */ + {"syc", {HB_TAG('S','Y','R',' ')}}, /* Classical Syriac -> Syriac */ + {"syl", {HB_TAG('S','Y','L',' ')}}, /* Sylheti */ + {"syr", {HB_TAG('S','Y','R',' ')}}, /* Syriac [macrolanguage] */ + {"szl", {HB_TAG('S','Z','L',' ')}}, /* Silesian */ + {"ta", {HB_TAG('T','A','M',' ')}}, /* Tamil */ + {"taa", {HB_TAG('A','T','H',' ')}}, /* Lower Tanana -> Athapaskan */ + {"tab", {HB_TAG('T','A','B',' ')}}, /* Tabassaran -> Tabasaran */ + {"taq", {HB_TAG('T','M','H',' ')}}, /* Tamasheq -> Tamashek */ + {"tau", {HB_TAG('A','T','H',' ')}}, /* Upper Tanana -> Athapaskan */ + {"tcb", {HB_TAG('A','T','H',' ')}}, /* Tanacross -> Athapaskan */ + {"tce", {HB_TAG('A','T','H',' ')}}, /* Southern Tutchone -> Athapaskan */ + {"tcp", {HB_TAG('Q','I','N',' ')}}, /* Tawr Chin -> Chin */ + {"tcy", {HB_TAG('T','U','L',' ')}}, /* Tulu -> Tumbuka */ + {"tcz", {HB_TAG('Q','I','N',' ')}}, /* Thado Chin -> Chin */ + {"tdd", {HB_TAG('T','D','D',' ')}}, /* Tai Nüa -> Dehong Dai */ + {"tdx", {HB_TAG('M','L','G',' ')}}, /* Tandroy-Mahafaly Malagasy -> Malagasy */ + {"te", {HB_TAG('T','E','L',' ')}}, /* Telugu */ + {"tec", {HB_TAG('K','A','L',' ')}}, /* Terik -> Kalenjin */ + {"tem", {HB_TAG('T','M','N',' ')}}, /* Timne -> Temne */ + {"tet", {HB_TAG('T','E','T',' ')}}, /* Tetum */ + {"tfn", {HB_TAG('A','T','H',' ')}}, /* Tanaina -> Athapaskan */ + {"tg", {HB_TAG('T','A','J',' ')}}, /* Tajik -> Tajiki */ + {"tgj", {HB_TAG('N','I','S',' ')}}, /* Tagin -> Nisi */ + {"tgx", {HB_TAG('A','T','H',' ')}}, /* Tagish -> Athapaskan */ + {"th", {HB_TAG('T','H','A',' ')}}, /* Thai */ + {"tht", {HB_TAG('A','T','H',' ')}}, /* Tahltan -> Athapaskan */ + {"thv", {HB_TAG('T','M','H',' ')}}, /* Tahaggart Tamahaq -> Tamashek */ + {"thz", {HB_TAG('T','M','H',' ')}}, /* Tayart Tamajeq -> Tamashek */ + {"ti", {HB_TAG('T','G','Y',' ')}}, /* Tigrinya */ + {"tig", {HB_TAG('T','G','R',' ')}}, /* Tigre */ + {"tiv", {HB_TAG('T','I','V',' ')}}, /* Tiv */ + {"tk", {HB_TAG('T','K','M',' ')}}, /* Turkmen */ + {"tkg", {HB_TAG('M','L','G',' ')}}, /* Tesaka Malagasy -> Malagasy */ + {"tl", {HB_TAG('T','G','L',' ')}}, /* Tagalog */ + {"tmh", {HB_TAG('T','M','H',' ')}}, /* Tamashek [macrolanguage] */ + {"tmw", {HB_TAG('M','L','Y',' ')}}, /* Temuan -> Malay */ + {"tn", {HB_TAG('T','N','A',' ')}}, /* Tswana */ + {"tnf", {HB_TAG('D','R','I',' ')}}, /* Tangshewi (retired code) -> Dari */ + {"to", {HB_TAG('T','G','N',' ')}}, /* Tonga (Tonga Islands) -> Tongan */ + {"tod", {HB_TAG('T','O','D','0')}}, /* Toma */ + {"toi", {HB_TAG('T','N','G',' ')}}, /* Tonga (Zambia) */ + {"tol", {HB_TAG('A','T','H',' ')}}, /* Tolowa -> Athapaskan */ + {"tpi", {HB_TAG('T','P','I',' ')}}, /* Tok Pisin */ + {"tr", {HB_TAG('T','R','K',' ')}}, /* Turkish */ + {"tru", {HB_TAG('T','U','A',' '), /* Turoyo -> Turoyo Aramaic */ + HB_TAG('S','Y','R',' ')}}, /* Turoyo -> Syriac */ + {"ts", {HB_TAG('T','S','G',' ')}}, /* Tsonga */ + {"tsj", {HB_TAG('T','S','J',' ')}}, /* Tshangla */ + {"tt", {HB_TAG('T','A','T',' ')}}, /* Tatar */ + {"ttm", {HB_TAG('A','T','H',' ')}}, /* Northern Tutchone -> Athapaskan */ + {"ttq", {HB_TAG('T','M','H',' ')}}, /* Tawallammat Tamajaq -> Tamashek */ + {"tum", {HB_TAG('T','U','M',' ')}}, /* Tumbuka -> Tulu */ + {"tuu", {HB_TAG('A','T','H',' ')}}, /* Tututni -> Athapaskan */ + {"tuy", {HB_TAG('K','A','L',' ')}}, /* Tugen -> Kalenjin */ + {"tvl", {HB_TAG('T','V','L',' ')}}, /* Tuvalu */ + {"tw", {HB_TAG('T','W','I',' '), /* Twi */ + HB_TAG('A','K','A',' ')}}, /* Twi -> Akan */ + {"txc", {HB_TAG('A','T','H',' ')}}, /* Tsetsaut -> Athapaskan */ + {"txy", {HB_TAG('M','L','G',' ')}}, /* Tanosy Malagasy -> Malagasy */ + {"ty", {HB_TAG('T','H','T',' ')}}, /* Tahitian */ + {"tyv", {HB_TAG('T','U','V',' ')}}, /* Tuvinian -> Tuvin */ + {"tyz", {HB_TAG('T','Y','Z',' ')}}, /* Tày */ + {"tzm", {HB_TAG('T','Z','M',' ')}}, /* Central Atlas Tamazight -> Tamazight */ + {"tzo", {HB_TAG('T','Z','O',' ')}}, /* Tzotzil */ + {"ubl", {HB_TAG('B','I','K',' ')}}, /* Buhi'non Bikol -> Bikol */ + {"udm", {HB_TAG('U','D','M',' ')}}, /* Udmurt */ + {"ug", {HB_TAG('U','Y','G',' ')}}, /* Uyghur */ + {"uk", {HB_TAG('U','K','R',' ')}}, /* Ukrainian */ + {"umb", {HB_TAG('U','M','B',' ')}}, /* Umbundu */ + {"unr", {HB_TAG('M','U','N',' ')}}, /* Mundari */ + {"ur", {HB_TAG('U','R','D',' ')}}, /* Urdu */ + {"urk", {HB_TAG('M','L','Y',' ')}}, /* Urak Lawoi' -> Malay */ + {"uz", {HB_TAG('U','Z','B',' ')}}, /* Uzbek [macrolanguage] */ + {"uzn", {HB_TAG('U','Z','B',' ')}}, /* Northern Uzbek -> Uzbek */ + {"uzs", {HB_TAG('U','Z','B',' ')}}, /* Southern Uzbek -> Uzbek */ + {"ve", {HB_TAG('V','E','N',' ')}}, /* Venda */ + {"vec", {HB_TAG('V','E','C',' ')}}, /* Venetian */ + {"vi", {HB_TAG('V','I','T',' ')}}, /* Vietnamese */ + {"vkk", {HB_TAG('M','L','Y',' ')}}, /* Kaur -> Malay */ + {"vkt", {HB_TAG('M','L','Y',' ')}}, /* Tenggarong Kutai Malay -> Malay */ + {"vls", {HB_TAG('F','L','E',' ')}}, /* Vlaams -> Dutch (Flemish) */ + {"vmw", {HB_TAG('M','A','K',' ')}}, /* Makhuwa */ + {"vo", {HB_TAG('V','O','L',' ')}}, /* Volapük */ + {"vro", {HB_TAG('V','R','O',' ')}}, /* Võro */ + {"wa", {HB_TAG('W','L','N',' ')}}, /* Walloon */ + {"war", {HB_TAG('W','A','R',' ')}}, /* Waray (Philippines) -> Waray-Waray */ + {"wbm", {HB_TAG('W','A',' ',' ')}}, /* Wa */ + {"wbr", {HB_TAG('W','A','G',' ')}}, /* Wagdi */ + {"wlc", {HB_TAG('C','M','R',' ')}}, /* Mwali Comorian -> Comorian */ + {"wle", {HB_TAG('S','I','G',' ')}}, /* Wolane -> Silte Gurage */ + {"wlk", {HB_TAG('A','T','H',' ')}}, /* Wailaki -> Athapaskan */ + {"wni", {HB_TAG('C','M','R',' ')}}, /* Ndzwani Comorian -> Comorian */ + {"wo", {HB_TAG('W','L','F',' ')}}, /* Wolof */ + {"wry", {HB_TAG('M','A','W',' ')}}, /* Merwari -> Marwari */ + {"wsg", {HB_TAG('G','O','N',' ')}}, /* Adilabad Gondi -> Gondi */ + {"wtm", {HB_TAG('W','T','M',' ')}}, /* Mewati */ + {"wuu", {HB_TAG('Z','H','S',' ')}}, /* Wu Chinese -> Chinese Simplified */ + {"xal", {HB_TAG('K','L','M',' '), /* Kalmyk */ + HB_TAG('T','O','D',' ')}}, /* Kalmyk -> Todo */ + {"xan", {HB_TAG('S','E','K',' ')}}, /* Xamtanga -> Sekota */ + {"xh", {HB_TAG('X','H','S',' ')}}, /* Xhosa */ + {"xjb", {HB_TAG('X','J','B',' ')}}, /* Minjungbal -> Minjangbal */ + {"xkf", {HB_TAG('X','K','F',' ')}}, /* Khengkha */ + {"xmm", {HB_TAG('M','L','Y',' ')}}, /* Manado Malay -> Malay */ + {"xmv", {HB_TAG('M','L','G',' ')}}, /* Antankarana Malagasy -> Malagasy */ + {"xmw", {HB_TAG('M','L','G',' ')}}, /* Tsimihety Malagasy -> Malagasy */ + {"xnr", {HB_TAG('D','G','R',' ')}}, /* Kangri -> Dogri */ + {"xog", {HB_TAG('X','O','G',' ')}}, /* Soga */ + {"xpe", {HB_TAG('X','P','E',' ')}}, /* Liberia Kpelle -> Kpelle (Liberia) */ + {"xsl", {HB_TAG('S','S','L',' '), /* South Slavey */ + HB_TAG('S','L','A',' '), /* South Slavey -> Slavey */ + HB_TAG('A','T','H',' ')}}, /* South Slavey -> Athapaskan */ + {"xst", {HB_TAG('S','I','G',' ')}}, /* Silt'e (retired code) -> Silte Gurage */ + {"xwo", {HB_TAG('T','O','D',' ')}}, /* Written Oirat -> Todo */ + {"yao", {HB_TAG('Y','A','O',' ')}}, /* Yao */ + {"yap", {HB_TAG('Y','A','P',' ')}}, /* Yapese */ + {"ybd", {HB_TAG('A','R','K',' ')}}, /* Yangbye (retired code) -> Rakhine */ + {"ydd", {HB_TAG('J','I','I',' ')}}, /* Eastern Yiddish -> Yiddish */ + {"yi", {HB_TAG('J','I','I',' ')}}, /* Yiddish [macrolanguage] */ + {"yih", {HB_TAG('J','I','I',' ')}}, /* Western Yiddish -> Yiddish */ + {"yo", {HB_TAG('Y','B','A',' ')}}, /* Yoruba */ + {"yos", {HB_TAG('Q','I','N',' ')}}, /* Yos (retired code) -> Chin */ + {"yrk", {HB_TAG('T','N','E',' '), /* Nenets -> Tundra Nenets */ + HB_TAG('F','N','E',' ')}}, /* Nenets -> Forest Nenets */ + {"yue", {HB_TAG('Z','H','H',' ')}}, /* Yue Chinese -> Chinese, Hong Kong SAR */ + {"za", {HB_TAG('Z','H','A',' ')}}, /* Zhuang [macrolanguage] */ + {"zch", {HB_TAG('Z','H','A',' ')}}, /* Central Hongshuihe Zhuang -> Zhuang */ + {"zdj", {HB_TAG('C','M','R',' ')}}, /* Ngazidja Comorian -> Comorian */ + {"zea", {HB_TAG('Z','E','A',' ')}}, /* Zeeuws -> Zealandic */ + {"zeh", {HB_TAG('Z','H','A',' ')}}, /* Eastern Hongshuihe Zhuang -> Zhuang */ + {"zgb", {HB_TAG('Z','H','A',' ')}}, /* Guibei Zhuang -> Zhuang */ + {"zgh", {HB_TAG('Z','G','H',' ')}}, /* Standard Moroccan Tamazight */ + {"zgm", {HB_TAG('Z','H','A',' ')}}, /* Minz Zhuang -> Zhuang */ + {"zgn", {HB_TAG('Z','H','A',' ')}}, /* Guibian Zhuang -> Zhuang */ + {"zh", {HB_TAG('Z','H','S',' ')}}, /* Chinese [macrolanguage] -> Chinese Simplified */ + {"zhd", {HB_TAG('Z','H','A',' ')}}, /* Dai Zhuang -> Zhuang */ + {"zhn", {HB_TAG('Z','H','A',' ')}}, /* Nong Zhuang -> Zhuang */ + {"zlj", {HB_TAG('Z','H','A',' ')}}, /* Liujiang Zhuang -> Zhuang */ + {"zlm", {HB_TAG('M','L','Y',' ')}}, /* Malay */ + {"zln", {HB_TAG('Z','H','A',' ')}}, /* Lianshan Zhuang -> Zhuang */ + {"zlq", {HB_TAG('Z','H','A',' ')}}, /* Liuqian Zhuang -> Zhuang */ + {"zmi", {HB_TAG('M','L','Y',' ')}}, /* Negeri Sembilan Malay -> Malay */ + {"zne", {HB_TAG('Z','N','D',' ')}}, /* Zande */ + {"zom", {HB_TAG('Q','I','N',' ')}}, /* Zou -> Chin */ + {"zqe", {HB_TAG('Z','H','A',' ')}}, /* Qiubei Zhuang -> Zhuang */ + {"zsm", {HB_TAG('M','L','Y',' ')}}, /* Standard Malay -> Malay */ + {"zu", {HB_TAG('Z','U','L',' ')}}, /* Zulu */ + {"zum", {HB_TAG('L','R','C',' ')}}, /* Kumzari -> Luri */ + {"zyb", {HB_TAG('Z','H','A',' ')}}, /* Yongbei Zhuang -> Zhuang */ + {"zyg", {HB_TAG('Z','H','A',' ')}}, /* Yang Zhuang -> Zhuang */ + {"zyj", {HB_TAG('Z','H','A',' ')}}, /* Youjiang Zhuang -> Zhuang */ + {"zyn", {HB_TAG('Z','H','A',' ')}}, /* Yongnan Zhuang -> Zhuang */ + {"zza", {HB_TAG('Z','Z','A',' ')}}, /* Zazaki [macrolanguage] */ + {"zzj", {HB_TAG('Z','H','A',' ')}}, /* Zuojiang Zhuang -> Zhuang */ +}; + +static_assert (HB_OT_MAX_TAGS_PER_LANGUAGE == 3u, ""); + +/** + * hb_ot_tags_from_complex_language: + * @lang_str: a BCP 47 language tag to convert. + * @limit: a pointer to the end of the substring of @lang_str to consider for + * conversion. + * @count: maximum number of language tags to retrieve (IN) and actual number of + * language tags retrieved (OUT). If no tags are retrieved, it is not modified. + * @tags: array of size at least @language_count to store the language tag + * results + * + * Converts a multi-subtag BCP 47 language tag to language tags. + * + * Return value: Whether any language systems were retrieved. + **/ +static bool +hb_ot_tags_from_complex_language (const char *lang_str, + const char *limit, + unsigned int *count /* IN/OUT */, + hb_tag_t *tags /* OUT */) +{ + if (subtag_matches (lang_str, limit, "-fonnapa")) + { + /* Undetermined; North American Phonetic Alphabet */ + tags[0] = HB_TAG('A','P','P','H'); /* Phonetic transcription—Americanist conventions */ + *count = 1; + return true; + } + if (subtag_matches (lang_str, limit, "-polyton")) + { + /* Modern Greek (1453-); Polytonic Greek */ + tags[0] = HB_TAG('P','G','R',' '); /* Polytonic Greek */ + *count = 1; + return true; + } + if (subtag_matches (lang_str, limit, "-provenc")) + { + /* Occitan (post 1500); Provençal */ + tags[0] = HB_TAG('P','R','O',' '); /* Provençal / Old Provençal */ + *count = 1; + return true; + } + if (subtag_matches (lang_str, limit, "-fonipa")) + { + /* Undetermined; International Phonetic Alphabet */ + tags[0] = HB_TAG('I','P','P','H'); /* Phonetic transcription—IPA conventions */ + *count = 1; + return true; + } + if (subtag_matches (lang_str, limit, "-geok")) + { + /* Undetermined; Khutsuri (Asomtavruli and Nuskhuri) */ + tags[0] = HB_TAG('K','G','E',' '); /* Khutsuri Georgian */ + *count = 1; + return true; + } + if (subtag_matches (lang_str, limit, "-syre")) + { + /* Undetermined; Syriac (Estrangelo variant) */ + tags[0] = HB_TAG('S','Y','R','E'); /* Syriac, Estrangela script-variant (equivalent to ISO 15924 'Syre') */ + *count = 1; + return true; + } + if (subtag_matches (lang_str, limit, "-syrj")) + { + /* Undetermined; Syriac (Western variant) */ + tags[0] = HB_TAG('S','Y','R','J'); /* Syriac, Western script-variant (equivalent to ISO 15924 'Syrj') */ + *count = 1; + return true; + } + if (subtag_matches (lang_str, limit, "-syrn")) + { + /* Undetermined; Syriac (Eastern variant) */ + tags[0] = HB_TAG('S','Y','R','N'); /* Syriac, Eastern script-variant (equivalent to ISO 15924 'Syrn') */ + *count = 1; + return true; + } + switch (lang_str[0]) + { + case 'a': + if (0 == strcmp (&lang_str[1], "rt-lojban")) + { + /* Lojban */ + tags[0] = HB_TAG('J','B','O',' '); /* Lojban */ + *count = 1; + return true; + } + break; + case 'c': + if (lang_matches (&lang_str[1], "do-hant-hk")) + { + /* Min Dong Chinese */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "do-hant-mo")) + { + /* Min Dong Chinese */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "jy-hant-hk")) + { + /* Jinyu Chinese */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "jy-hant-mo")) + { + /* Jinyu Chinese */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "mn-hant-hk")) + { + /* Mandarin Chinese */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "mn-hant-mo")) + { + /* Mandarin Chinese */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "px-hant-hk")) + { + /* Pu-Xian Chinese */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "px-hant-mo")) + { + /* Pu-Xian Chinese */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "zh-hant-hk")) + { + /* Huizhou Chinese */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "zh-hant-mo")) + { + /* Huizhou Chinese */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "zo-hant-hk")) + { + /* Min Zhong Chinese */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "zo-hant-mo")) + { + /* Min Zhong Chinese */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "do-hans")) + { + /* Min Dong Chinese */ + tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "do-hant")) + { + /* Min Dong Chinese */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "jy-hans")) + { + /* Jinyu Chinese */ + tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "jy-hant")) + { + /* Jinyu Chinese */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "mn-hans")) + { + /* Mandarin Chinese */ + tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "mn-hant")) + { + /* Mandarin Chinese */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "px-hans")) + { + /* Pu-Xian Chinese */ + tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "px-hant")) + { + /* Pu-Xian Chinese */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "zh-hans")) + { + /* Huizhou Chinese */ + tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "zh-hant")) + { + /* Huizhou Chinese */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "zo-hans")) + { + /* Min Zhong Chinese */ + tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "zo-hant")) + { + /* Min Zhong Chinese */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "do-", 3) + && subtag_matches (lang_str, limit, "-hk")) + { + /* Min Dong Chinese; Hong Kong */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "do-", 3) + && subtag_matches (lang_str, limit, "-mo")) + { + /* Min Dong Chinese; Macao */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "do-", 3) + && subtag_matches (lang_str, limit, "-tw")) + { + /* Min Dong Chinese; Taiwan, Province of China */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "jy-", 3) + && subtag_matches (lang_str, limit, "-hk")) + { + /* Jinyu Chinese; Hong Kong */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "jy-", 3) + && subtag_matches (lang_str, limit, "-mo")) + { + /* Jinyu Chinese; Macao */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "jy-", 3) + && subtag_matches (lang_str, limit, "-tw")) + { + /* Jinyu Chinese; Taiwan, Province of China */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "mn-", 3) + && subtag_matches (lang_str, limit, "-hk")) + { + /* Mandarin Chinese; Hong Kong */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "mn-", 3) + && subtag_matches (lang_str, limit, "-mo")) + { + /* Mandarin Chinese; Macao */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "mn-", 3) + && subtag_matches (lang_str, limit, "-tw")) + { + /* Mandarin Chinese; Taiwan, Province of China */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "px-", 3) + && subtag_matches (lang_str, limit, "-hk")) + { + /* Pu-Xian Chinese; Hong Kong */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "px-", 3) + && subtag_matches (lang_str, limit, "-mo")) + { + /* Pu-Xian Chinese; Macao */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "px-", 3) + && subtag_matches (lang_str, limit, "-tw")) + { + /* Pu-Xian Chinese; Taiwan, Province of China */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "zh-", 3) + && subtag_matches (lang_str, limit, "-hk")) + { + /* Huizhou Chinese; Hong Kong */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "zh-", 3) + && subtag_matches (lang_str, limit, "-mo")) + { + /* Huizhou Chinese; Macao */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "zh-", 3) + && subtag_matches (lang_str, limit, "-tw")) + { + /* Huizhou Chinese; Taiwan, Province of China */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "zo-", 3) + && subtag_matches (lang_str, limit, "-hk")) + { + /* Min Zhong Chinese; Hong Kong */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "zo-", 3) + && subtag_matches (lang_str, limit, "-mo")) + { + /* Min Zhong Chinese; Macao */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "zo-", 3) + && subtag_matches (lang_str, limit, "-tw")) + { + /* Min Zhong Chinese; Taiwan, Province of China */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + *count = 1; + return true; + } + break; + case 'g': + if (lang_matches (&lang_str[1], "an-hant-hk")) + { + /* Gan Chinese */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "an-hant-mo")) + { + /* Gan Chinese */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "an-hans")) + { + /* Gan Chinese */ + tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "an-hant")) + { + /* Gan Chinese */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "a-latg")) + { + /* Irish */ + tags[0] = HB_TAG('I','R','T',' '); /* Irish Traditional */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "an-", 3) + && subtag_matches (lang_str, limit, "-hk")) + { + /* Gan Chinese; Hong Kong */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "an-", 3) + && subtag_matches (lang_str, limit, "-mo")) + { + /* Gan Chinese; Macao */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "an-", 3) + && subtag_matches (lang_str, limit, "-tw")) + { + /* Gan Chinese; Taiwan, Province of China */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + *count = 1; + return true; + } + break; + case 'h': + if (lang_matches (&lang_str[1], "ak-hant-hk")) + { + /* Hakka Chinese */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "ak-hant-mo")) + { + /* Hakka Chinese */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "sn-hant-hk")) + { + /* Xiang Chinese */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "sn-hant-mo")) + { + /* Xiang Chinese */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "ak-hans")) + { + /* Hakka Chinese */ + tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "ak-hant")) + { + /* Hakka Chinese */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "sn-hans")) + { + /* Xiang Chinese */ + tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "sn-hant")) + { + /* Xiang Chinese */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "ak-", 3) + && subtag_matches (lang_str, limit, "-hk")) + { + /* Hakka Chinese; Hong Kong */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "ak-", 3) + && subtag_matches (lang_str, limit, "-mo")) + { + /* Hakka Chinese; Macao */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "ak-", 3) + && subtag_matches (lang_str, limit, "-tw")) + { + /* Hakka Chinese; Taiwan, Province of China */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "sn-", 3) + && subtag_matches (lang_str, limit, "-hk")) + { + /* Xiang Chinese; Hong Kong */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "sn-", 3) + && subtag_matches (lang_str, limit, "-mo")) + { + /* Xiang Chinese; Macao */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "sn-", 3) + && subtag_matches (lang_str, limit, "-tw")) + { + /* Xiang Chinese; Taiwan, Province of China */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + *count = 1; + return true; + } + break; + case 'i': + if (0 == strcmp (&lang_str[1], "-navajo")) + { + /* Navajo */ + unsigned int i; + hb_tag_t possible_tags[] = { + HB_TAG('N','A','V',' '), /* Navajo */ + HB_TAG('A','T','H',' '), /* Athapaskan */ + }; + for (i = 0; i < 2 && i < *count; i++) + tags[i] = possible_tags[i]; + *count = i; + return true; + } + if (0 == strcmp (&lang_str[1], "-hak")) + { + /* Hakka */ + tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */ + *count = 1; + return true; + } + if (0 == strcmp (&lang_str[1], "-lux")) + { + /* Luxembourgish */ + tags[0] = HB_TAG('L','T','Z',' '); /* Luxembourgish */ + *count = 1; + return true; + } + break; + case 'l': + if (lang_matches (&lang_str[1], "zh-hans")) + { + /* Literary Chinese */ + tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */ + *count = 1; + return true; + } + break; + case 'm': + if (lang_matches (&lang_str[1], "np-hant-hk")) + { + /* Min Bei Chinese */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "np-hant-mo")) + { + /* Min Bei Chinese */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "np-hans")) + { + /* Min Bei Chinese */ + tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "np-hant")) + { + /* Min Bei Chinese */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "np-", 3) + && subtag_matches (lang_str, limit, "-hk")) + { + /* Min Bei Chinese; Hong Kong */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "np-", 3) + && subtag_matches (lang_str, limit, "-mo")) + { + /* Min Bei Chinese; Macao */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "np-", 3) + && subtag_matches (lang_str, limit, "-tw")) + { + /* Min Bei Chinese; Taiwan, Province of China */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + *count = 1; + return true; + } + break; + case 'n': + if (lang_matches (&lang_str[1], "an-hant-hk")) + { + /* Min Nan Chinese */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "an-hant-mo")) + { + /* Min Nan Chinese */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "an-hans")) + { + /* Min Nan Chinese */ + tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "an-hant")) + { + /* Min Nan Chinese */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "an-", 3) + && subtag_matches (lang_str, limit, "-hk")) + { + /* Min Nan Chinese; Hong Kong */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "an-", 3) + && subtag_matches (lang_str, limit, "-mo")) + { + /* Min Nan Chinese; Macao */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "an-", 3) + && subtag_matches (lang_str, limit, "-tw")) + { + /* Min Nan Chinese; Taiwan, Province of China */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + *count = 1; + return true; + } + if (0 == strcmp (&lang_str[1], "o-bok")) + { + /* Norwegian Bokmal */ + tags[0] = HB_TAG('N','O','R',' '); /* Norwegian */ + *count = 1; + return true; + } + if (0 == strcmp (&lang_str[1], "o-nyn")) + { + /* Norwegian Nynorsk */ + tags[0] = HB_TAG('N','Y','N',' '); /* Norwegian Nynorsk (Nynorsk, Norwegian) */ + *count = 1; + return true; + } + break; + case 'r': + if (0 == strncmp (&lang_str[1], "o-", 2) + && subtag_matches (lang_str, limit, "-md")) + { + /* Romanian; Moldova */ + tags[0] = HB_TAG('M','O','L',' '); /* Moldavian */ + *count = 1; + return true; + } + break; + case 'w': + if (lang_matches (&lang_str[1], "uu-hant-hk")) + { + /* Wu Chinese */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "uu-hant-mo")) + { + /* Wu Chinese */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "uu-hans")) + { + /* Wu Chinese */ + tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "uu-hant")) + { + /* Wu Chinese */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "uu-", 3) + && subtag_matches (lang_str, limit, "-hk")) + { + /* Wu Chinese; Hong Kong */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "uu-", 3) + && subtag_matches (lang_str, limit, "-mo")) + { + /* Wu Chinese; Macao */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "uu-", 3) + && subtag_matches (lang_str, limit, "-tw")) + { + /* Wu Chinese; Taiwan, Province of China */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + *count = 1; + return true; + } + break; + case 'y': + if (lang_matches (&lang_str[1], "ue-hans")) + { + /* Yue Chinese */ + tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */ + *count = 1; + return true; + } + break; + case 'z': + if (lang_matches (&lang_str[1], "h-hant-hk")) + { + /* Chinese */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "h-hant-mo")) + { + /* Chinese */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (0 == strcmp (&lang_str[1], "h-min-nan")) + { + /* Minnan, Hokkien, Amoy, Taiwanese, Southern Min, Southern Fujian, Hoklo, Southern Fukien, Ho-lo */ + tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "h-hans")) + { + /* Chinese */ + tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "h-hant")) + { + /* Chinese */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + *count = 1; + return true; + } + if (0 == strcmp (&lang_str[1], "h-min")) + { + /* Min, Fuzhou, Hokkien, Amoy, or Taiwanese */ + tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "h-", 2) + && subtag_matches (lang_str, limit, "-hk")) + { + /* Chinese; Hong Kong */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "h-", 2) + && subtag_matches (lang_str, limit, "-mo")) + { + /* Chinese; Macao */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "h-", 2) + && subtag_matches (lang_str, limit, "-tw")) + { + /* Chinese; Taiwan, Province of China */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + *count = 1; + return true; + } + break; + } + return false; +} + +/** + * hb_ot_ambiguous_tag_to_language + * @tag: A language tag. + * + * Converts @tag to a BCP 47 language tag if it is ambiguous (it corresponds to + * many language tags) and the best tag is not the alphabetically first, or if + * the best tag consists of multiple subtags. + * + * Return value: The #hb_language_t corresponding to the BCP 47 language tag, + * or #HB_LANGUAGE_INVALID if @tag is not ambiguous. + **/ +static hb_language_t +hb_ot_ambiguous_tag_to_language (hb_tag_t tag) +{ + switch (tag) + { + case HB_TAG('A','P','P','H'): /* Phonetic transcription—Americanist conventions */ + return hb_language_from_string ("und-fonnapa", -1); /* Undetermined; North American Phonetic Alphabet */ + case HB_TAG('A','R','A',' '): /* Arabic */ + return hb_language_from_string ("ar", -1); /* Arabic */ + case HB_TAG('A','R','K',' '): /* Rakhine */ + return hb_language_from_string ("rki", -1); /* Rakhine */ + case HB_TAG('A','T','H',' '): /* Athapaskan */ + return hb_language_from_string ("ath", -1); /* Athapascan */ + case HB_TAG('B','I','K',' '): /* Bikol */ + return hb_language_from_string ("bik", -1); /* Bikol */ + case HB_TAG('C','P','P',' '): /* Creoles */ + return hb_language_from_string ("crp", -1); /* Creoles and pidgins */ + case HB_TAG('C','R','R',' '): /* Carrier */ + return hb_language_from_string ("crx", -1); /* Carrier */ + case HB_TAG('D','N','K',' '): /* Dinka */ + return hb_language_from_string ("din", -1); /* Dinka */ + case HB_TAG('D','R','I',' '): /* Dari */ + return hb_language_from_string ("prs", -1); /* Dari */ + case HB_TAG('D','U','J',' '): /* Dhuwal */ + return hb_language_from_string ("dwu", -1); /* Dhuwal */ + case HB_TAG('D','Z','N',' '): /* Dzongkha */ + return hb_language_from_string ("dz", -1); /* Dzongkha */ + case HB_TAG('E','T','I',' '): /* Estonian */ + return hb_language_from_string ("et", -1); /* Estonian */ + case HB_TAG('G','O','N',' '): /* Gondi */ + return hb_language_from_string ("gon", -1); /* Gondi */ + case HB_TAG('H','M','N',' '): /* Hmong */ + return hb_language_from_string ("hmn", -1); /* Hmong */ + case HB_TAG('I','J','O',' '): /* Ijo */ + return hb_language_from_string ("ijo", -1); /* Ijo */ + case HB_TAG('I','N','U',' '): /* Inuktitut */ + return hb_language_from_string ("iu", -1); /* Inuktitut */ + case HB_TAG('I','P','K',' '): /* Inupiat */ + return hb_language_from_string ("ik", -1); /* Inupiaq */ + case HB_TAG('I','P','P','H'): /* Phonetic transcription—IPA conventions */ + return hb_language_from_string ("und-fonipa", -1); /* Undetermined; International Phonetic Alphabet */ + case HB_TAG('I','R','T',' '): /* Irish Traditional */ + return hb_language_from_string ("ga-Latg", -1); /* Irish; Latin (Gaelic variant) */ + case HB_TAG('J','I','I',' '): /* Yiddish */ + return hb_language_from_string ("yi", -1); /* Yiddish */ + case HB_TAG('K','A','L',' '): /* Kalenjin */ + return hb_language_from_string ("kln", -1); /* Kalenjin */ + case HB_TAG('K','G','E',' '): /* Khutsuri Georgian */ + return hb_language_from_string ("und-Geok", -1); /* Undetermined; Khutsuri (Asomtavruli and Nuskhuri) */ + case HB_TAG('K','N','R',' '): /* Kanuri */ + return hb_language_from_string ("kr", -1); /* Kanuri */ + case HB_TAG('K','O','K',' '): /* Konkani */ + return hb_language_from_string ("kok", -1); /* Konkani */ + case HB_TAG('K','U','R',' '): /* Kurdish */ + return hb_language_from_string ("ku", -1); /* Kurdish */ + case HB_TAG('L','U','H',' '): /* Luyia */ + return hb_language_from_string ("luy", -1); /* Luyia */ + case HB_TAG('L','V','I',' '): /* Latvian */ + return hb_language_from_string ("lv", -1); /* Latvian */ + case HB_TAG('M','A','W',' '): /* Marwari */ + return hb_language_from_string ("mwr", -1); /* Marwari */ + case HB_TAG('M','L','G',' '): /* Malagasy */ + return hb_language_from_string ("mg", -1); /* Malagasy */ + case HB_TAG('M','L','Y',' '): /* Malay */ + return hb_language_from_string ("ms", -1); /* Malay */ + case HB_TAG('M','N','G',' '): /* Mongolian */ + return hb_language_from_string ("mn", -1); /* Mongolian */ + case HB_TAG('M','O','L',' '): /* Moldavian */ + return hb_language_from_string ("ro-MD", -1); /* Romanian; Moldova */ + case HB_TAG('N','E','P',' '): /* Nepali */ + return hb_language_from_string ("ne", -1); /* Nepali */ + case HB_TAG('N','I','S',' '): /* Nisi */ + return hb_language_from_string ("njz", -1); /* Nyishi */ + case HB_TAG('N','O','R',' '): /* Norwegian */ + return hb_language_from_string ("no", -1); /* Norwegian */ + case HB_TAG('O','J','B',' '): /* Ojibway */ + return hb_language_from_string ("oj", -1); /* Ojibwa */ + case HB_TAG('O','R','O',' '): /* Oromo */ + return hb_language_from_string ("om", -1); /* Oromo */ + case HB_TAG('P','A','S',' '): /* Pashto */ + return hb_language_from_string ("ps", -1); /* Pashto */ + case HB_TAG('P','G','R',' '): /* Polytonic Greek */ + return hb_language_from_string ("el-polyton", -1); /* Modern Greek (1453-); Polytonic Greek */ + case HB_TAG('P','R','O',' '): /* Provençal / Old Provençal */ + return hb_language_from_string ("pro", -1); /* Old Provençal (to 1500) */ + case HB_TAG('Q','U','H',' '): /* Quechua (Bolivia) */ + return hb_language_from_string ("quh", -1); /* South Bolivian Quechua */ + case HB_TAG('Q','V','I',' '): /* Quechua (Ecuador) */ + return hb_language_from_string ("qvi", -1); /* Imbabura Highland Quichua */ + case HB_TAG('Q','W','H',' '): /* Quechua (Peru) */ + return hb_language_from_string ("qwh", -1); /* Huaylas Ancash Quechua */ + case HB_TAG('R','A','J',' '): /* Rajasthani */ + return hb_language_from_string ("raj", -1); /* Rajasthani */ + case HB_TAG('R','O','Y',' '): /* Romany */ + return hb_language_from_string ("rom", -1); /* Romany */ + case HB_TAG('S','Q','I',' '): /* Albanian */ + return hb_language_from_string ("sq", -1); /* Albanian */ + case HB_TAG('S','Y','R',' '): /* Syriac */ + return hb_language_from_string ("syr", -1); /* Syriac */ + case HB_TAG('S','Y','R','E'): /* Syriac, Estrangela script-variant (equivalent to ISO 15924 'Syre') */ + return hb_language_from_string ("und-Syre", -1); /* Undetermined; Syriac (Estrangelo variant) */ + case HB_TAG('S','Y','R','J'): /* Syriac, Western script-variant (equivalent to ISO 15924 'Syrj') */ + return hb_language_from_string ("und-Syrj", -1); /* Undetermined; Syriac (Western variant) */ + case HB_TAG('S','Y','R','N'): /* Syriac, Eastern script-variant (equivalent to ISO 15924 'Syrn') */ + return hb_language_from_string ("und-Syrn", -1); /* Undetermined; Syriac (Eastern variant) */ + case HB_TAG('T','M','H',' '): /* Tamashek */ + return hb_language_from_string ("tmh", -1); /* Tamashek */ + case HB_TAG('T','N','E',' '): /* Tundra Nenets */ + return hb_language_from_string ("yrk", -1); /* Nenets */ + case HB_TAG('Z','H','H',' '): /* Chinese, Hong Kong SAR */ + return hb_language_from_string ("zh-HK", -1); /* Chinese; Hong Kong */ + case HB_TAG('Z','H','S',' '): /* Chinese Simplified */ + return hb_language_from_string ("zh-Hans", -1); /* Chinese; Han (Simplified variant) */ + case HB_TAG('Z','H','T',' '): /* Chinese Traditional */ + return hb_language_from_string ("zh-Hant", -1); /* Chinese; Han (Traditional variant) */ + default: + return HB_LANGUAGE_INVALID; + } +} + +#endif /* HB_OT_TAG_TABLE_HH */ + +/* == End of generated table == */ diff --git a/src/hb-ot-tag.cc b/src/hb-ot-tag.cc index 991d8e77a..4dba9c31a 100644 --- a/src/hb-ot-tag.cc +++ b/src/hb-ot-tag.cc @@ -26,7 +26,7 @@ * Google Author(s): Behdad Esfahbod, Roozbeh Pournader */ -#include "hb-private.hh" +#include "hb.hh" /* hb_script_t */ @@ -36,7 +36,8 @@ hb_ot_old_tag_from_script (hb_script_t script) { /* This seems to be accurate as of end of 2012. */ - switch ((hb_tag_t) script) { + switch ((hb_tag_t) script) + { case HB_SCRIPT_INVALID: return HB_OT_TAG_DEFAULT_SCRIPT; /* KATAKANA and HIRAGANA both map to 'kana' */ @@ -49,8 +50,6 @@ hb_ot_old_tag_from_script (hb_script_t script) case HB_SCRIPT_NKO: return HB_TAG('n','k','o',' '); /* Unicode-5.1 additions */ case HB_SCRIPT_VAI: return HB_TAG('v','a','i',' '); - /* Unicode-5.2 additions */ - /* Unicode-6.0 additions */ } /* Else, just change first char to lowercase and return */ @@ -114,6 +113,18 @@ hb_ot_new_tag_to_script (hb_tag_t tag) return HB_SCRIPT_UNKNOWN; } +void +hb_ot_tags_from_script (hb_script_t script, + hb_tag_t *script_tag_1, + hb_tag_t *script_tag_2) +{ + unsigned int count = 2; + hb_tag_t tags[2]; + hb_ot_tags_from_script_and_language (script, HB_LANGUAGE_INVALID, &count, tags, nullptr, nullptr); + *script_tag_1 = count > 0 ? tags[0] : HB_OT_TAG_DEFAULT_SCRIPT; + *script_tag_2 = count > 1 ? tags[1] : HB_OT_TAG_DEFAULT_SCRIPT; +} + /* * Complete list at: * https://docs.microsoft.com/en-us/typography/opentype/spec/scripttags @@ -122,28 +133,37 @@ hb_ot_new_tag_to_script (hb_tag_t tag) * So we just do that, and handle the exceptional cases in a switch. */ -void -hb_ot_tags_from_script (hb_script_t script, - hb_tag_t *script_tag_1, - hb_tag_t *script_tag_2) +static void +hb_ot_all_tags_from_script (hb_script_t script, + unsigned int *count /* IN/OUT */, + hb_tag_t *tags /* OUT */) { - hb_tag_t new_tag; + unsigned int i = 0; - *script_tag_2 = HB_OT_TAG_DEFAULT_SCRIPT; - *script_tag_1 = hb_ot_old_tag_from_script (script); + hb_tag_t new_tag = hb_ot_new_tag_from_script (script); + if (unlikely (new_tag != HB_OT_TAG_DEFAULT_SCRIPT)) + { + tags[i++] = new_tag | '3'; + if (*count > i) + tags[i++] = new_tag; + } - new_tag = hb_ot_new_tag_from_script (script); - if (unlikely (new_tag != HB_OT_TAG_DEFAULT_SCRIPT)) { - *script_tag_2 = *script_tag_1; - *script_tag_1 = new_tag; + if (*count > i) + { + hb_tag_t old_tag = hb_ot_old_tag_from_script (script); + if (old_tag != HB_OT_TAG_DEFAULT_SCRIPT) + tags[i++] = old_tag; } + + *count = i; } hb_script_t hb_ot_tag_to_script (hb_tag_t tag) { - if (unlikely ((tag & 0x000000FFu) == '2')) - return hb_ot_new_tag_to_script (tag); + unsigned char digit = tag & 0x000000FFu; + if (unlikely (digit == '2' || digit == '3')) + return hb_ot_new_tag_to_script (tag & 0xFFFFFF32); return hb_ot_old_tag_to_script (tag); } @@ -151,732 +171,6 @@ hb_ot_tag_to_script (hb_tag_t tag) /* hb_language_t */ -typedef struct { - char language[4]; - hb_tag_t tag; -} LangTag; - -/* - * Complete list at: - * https://docs.microsoft.com/en-us/typography/opentype/spec/languagetags - * - * Generated by intersecting the OpenType language tag list from - * Draft OpenType 1.5 spec, with with the ISO 639-3 codes from - * 2008-08-04, matching on name, and finally adjusted manually. - * - * Updated on 2012-12-07 with more research into remaining codes. - * - * Updated on 2013-11-23 based on usage in SIL and Microsoft fonts, - * the new proposal from Microsoft, and latest ISO 639-3 names. - * - * Some items still missing. Those are commented out at the end. - * Keep sorted for bsearch. - * - * Updated as of 2015-05-06: OT1.7 on MS website has some newer - * items that we don't have here, eg. Zazaki. This is the new - * items in OpenType 1.7 (red items), most of which we have: - * https://docs.microsoft.com/en-us/typography/opentype/spec/languagetags - */ - -static const LangTag ot_languages[] = { - {"aa", HB_TAG('A','F','R',' ')}, /* Afar */ - {"ab", HB_TAG('A','B','K',' ')}, /* Abkhazian */ - {"abq", HB_TAG('A','B','A',' ')}, /* Abaza */ - {"acf", HB_TAG('F','A','N',' ')}, /* French Antillean */ - {"ach", HB_TAG('A','C','H',' ')}, /* Acoli */ - {"acr", HB_TAG('A','C','R',' ')}, /* Achi */ - {"ada", HB_TAG('D','N','G',' ')}, /* Dangme */ - {"ady", HB_TAG('A','D','Y',' ')}, /* Adyghe */ - {"af", HB_TAG('A','F','K',' ')}, /* Afrikaans */ - {"ahg", HB_TAG('A','G','W',' ')}, /* Agaw */ - {"aii", HB_TAG('S','W','A',' ')}, /* Swadaya Aramaic */ - {"aio", HB_TAG('A','I','O',' ')}, /* Aiton */ - {"aiw", HB_TAG('A','R','I',' ')}, /* Aari */ - {"ak", HB_TAG('T','W','I',' ')}, /* Akan [macrolanguage] */ - {"aka", HB_TAG('A','K','A',' ')}, /* Akan */ - {"alt", HB_TAG('A','L','T',' ')}, /* [Southern] Altai */ - {"am", HB_TAG('A','M','H',' ')}, /* Amharic */ - {"amf", HB_TAG('H','B','N',' ')}, /* Hammer-Banna */ - {"amw", HB_TAG('S','Y','R',' ')}, /* Western Neo-Aramaic */ - {"an", HB_TAG('A','R','G',' ')}, /* Aragonese */ - {"ang", HB_TAG('A','N','G',' ')}, /* Old English (ca. 450-1100) */ - {"ar", HB_TAG('A','R','A',' ')}, /* Arabic [macrolanguage] */ - {"arb", HB_TAG('A','R','A',' ')}, /* Standard Arabic */ - {"arn", HB_TAG('M','A','P',' ')}, /* Mapudungun */ - {"ary", HB_TAG('M','O','R',' ')}, /* Moroccan Arabic */ - {"as", HB_TAG('A','S','M',' ')}, /* Assamese */ - {"ast", HB_TAG('A','S','T',' ')}, /* Asturian/Asturleonese/Bable/Leonese */ - {"ath", HB_TAG('A','T','H',' ')}, /* Athapaskan [family] */ - {"atj", HB_TAG('R','C','R',' ')}, /* R-Cree */ - {"atv", HB_TAG('A','L','T',' ')}, /* [Northern] Altai */ - {"av", HB_TAG('A','V','R',' ')}, /* Avaric */ - {"awa", HB_TAG('A','W','A',' ')}, /* Awadhi */ - {"ay", HB_TAG('A','Y','M',' ')}, /* Aymara [macrolanguage] */ - {"az", HB_TAG('A','Z','E',' ')}, /* Azerbaijani [macrolanguage] */ - {"azb", HB_TAG('A','Z','B',' ')}, /* South Azerbaijani */ - {"azj", HB_TAG('A','Z','E',' ')}, /* North Azerbaijani */ - {"ba", HB_TAG('B','S','H',' ')}, /* Bashkir */ - {"bad", HB_TAG('B','A','D','0')}, /* Banda */ - {"bai", HB_TAG('B','M','L',' ')}, /* Bamileke [family] */ - {"bal", HB_TAG('B','L','I',' ')}, /* Baluchi [macrolangauge] */ - {"ban", HB_TAG('B','A','N',' ')}, /* Balinese */ - {"bar", HB_TAG('B','A','R',' ')}, /* Bavarian */ - {"bbc", HB_TAG('B','B','C',' ')}, /* Batak Toba */ - {"bci", HB_TAG('B','A','U',' ')}, /* Baoulé */ - {"bcl", HB_TAG('B','I','K',' ')}, /* Central Bikol */ - {"bcq", HB_TAG('B','C','H',' ')}, /* Bench */ - {"bdy", HB_TAG('B','D','Y',' ')}, /* Bandjalang */ - {"be", HB_TAG('B','E','L',' ')}, /* Belarusian */ - {"bem", HB_TAG('B','E','M',' ')}, /* Bemba (Zambia) */ - {"ber", HB_TAG('B','E','R',' ')}, /* Berber [family] */ - {"bfq", HB_TAG('B','A','D',' ')}, /* Badaga */ - {"bft", HB_TAG('B','L','T',' ')}, /* Balti */ - {"bfu", HB_TAG('L','A','H',' ')}, /* Lahuli */ - {"bfy", HB_TAG('B','A','G',' ')}, /* Baghelkhandi */ - {"bg", HB_TAG('B','G','R',' ')}, /* Bulgarian */ - {"bgc", HB_TAG('B','G','C',' ')}, /* Haryanvi */ - {"bgq", HB_TAG('B','G','Q',' ')}, /* Bagri */ - {"bgr", HB_TAG('Q','I','N',' ')}, /* Bawm Chin */ - {"bhb", HB_TAG('B','H','I',' ')}, /* Bhili */ - {"bhk", HB_TAG('B','I','K',' ')}, /* Albay Bicolano (retired code) */ - {"bho", HB_TAG('B','H','O',' ')}, /* Bhojpuri */ - {"bi", HB_TAG('B','I','S',' ')}, /* Bislama */ - {"bik", HB_TAG('B','I','K',' ')}, /* Bikol [macrolanguage] */ - {"bin", HB_TAG('E','D','O',' ')}, /* Bini */ - {"bjj", HB_TAG('B','J','J',' ')}, /* Kanauji */ - {"bjt", HB_TAG('B','L','N',' ')}, /* Balanta-Ganja */ - {"bla", HB_TAG('B','K','F',' ')}, /* Blackfoot */ - {"ble", HB_TAG('B','L','N',' ')}, /* Balanta-Kentohe */ - {"blk", HB_TAG('B','L','K',' ')}, /* Pa'O/Pa'o Karen */ - {"bln", HB_TAG('B','I','K',' ')}, /* Southern Catanduanes Bikol */ - {"bm", HB_TAG('B','M','B',' ')}, /* Bambara */ - {"bn", HB_TAG('B','E','N',' ')}, /* Bengali */ - {"bo", HB_TAG('T','I','B',' ')}, /* Tibetan */ - {"bpy", HB_TAG('B','P','Y',' ')}, /* Bishnupriya */ - {"bqi", HB_TAG('L','R','C',' ')}, /* Bakhtiari */ - {"br", HB_TAG('B','R','E',' ')}, /* Breton */ - {"bra", HB_TAG('B','R','I',' ')}, /* Braj Bhasha */ - {"brh", HB_TAG('B','R','H',' ')}, /* Brahui */ - {"brx", HB_TAG('B','R','X',' ')}, /* Bodo (India) */ - {"bs", HB_TAG('B','O','S',' ')}, /* Bosnian */ - {"btb", HB_TAG('B','T','I',' ')}, /* Beti (Cameroon) */ - {"bto", HB_TAG('B','I','K',' ')}, /* Rinconada Bikol */ - {"bts", HB_TAG('B','T','S',' ')}, /* Batak Simalungun */ - {"bug", HB_TAG('B','U','G',' ')}, /* Buginese */ - {"bxr", HB_TAG('R','B','U',' ')}, /* Russian Buriat */ - {"byn", HB_TAG('B','I','L',' ')}, /* Bilen */ - {"ca", HB_TAG('C','A','T',' ')}, /* Catalan */ - {"cak", HB_TAG('C','A','K',' ')}, /* Kaqchikel */ - {"cbk", HB_TAG('C','B','K',' ')}, /* Chavacano */ - {"cbl", HB_TAG('Q','I','N',' ')}, /* Bualkhaw Chin */ - {"cco", HB_TAG('C','C','H','N')}, /* Chinantec */ - {"ce", HB_TAG('C','H','E',' ')}, /* Chechen */ - {"ceb", HB_TAG('C','E','B',' ')}, /* Cebuano */ - {"cfm", HB_TAG('H','A','L',' ')}, /* Halam/Falam Chin */ - {"cgg", HB_TAG('C','G','G',' ')}, /* Chiga */ - {"ch", HB_TAG('C','H','A',' ')}, /* Chamorro */ - {"chj", HB_TAG('C','C','H','N')}, /* Chinantec */ - {"chk", HB_TAG('C','H','K','0')}, /* Chuukese */ - {"cho", HB_TAG('C','H','O',' ')}, /* Choctaw */ - {"chp", HB_TAG('C','H','P',' ')}, /* Chipewyan */ - {"chq", HB_TAG('C','C','H','N')}, /* Chinantec */ - {"chr", HB_TAG('C','H','R',' ')}, /* Cherokee */ - {"chy", HB_TAG('C','H','Y',' ')}, /* Cheyenne */ - {"chz", HB_TAG('C','C','H','N')}, /* Chinantec */ - {"cja", HB_TAG('C','J','A',' ')}, /* Western Cham */ - {"cjm", HB_TAG('C','J','M',' ')}, /* Eastern Cham */ - {"cka", HB_TAG('Q','I','N',' ')}, /* Khumi Awa Chin */ - {"ckb", HB_TAG('K','U','R',' ')}, /* Central Kurdish (Sorani) */ - {"ckt", HB_TAG('C','H','K',' ')}, /* Chukchi */ - {"cld", HB_TAG('S','Y','R',' ')}, /* Chaldean Neo-Aramaic */ - {"cle", HB_TAG('C','C','H','N')}, /* Chinantec */ - {"cmr", HB_TAG('Q','I','N',' ')}, /* Mro-Khimi Chin */ - {"cnb", HB_TAG('Q','I','N',' ')}, /* Chinbon Chin */ - {"cnh", HB_TAG('Q','I','N',' ')}, /* Hakha Chin */ - {"cnk", HB_TAG('Q','I','N',' ')}, /* Khumi Chin */ - {"cnl", HB_TAG('C','C','H','N')}, /* Chinantec */ - {"cnt", HB_TAG('C','C','H','N')}, /* Chinantec */ - {"cnw", HB_TAG('Q','I','N',' ')}, /* Ngawn Chin */ - {"cop", HB_TAG('C','O','P',' ')}, /* Coptic */ - {"cpa", HB_TAG('C','C','H','N')}, /* Chinantec */ - {"cpp", HB_TAG('C','P','P',' ')}, /* Creoles */ - {"cr", HB_TAG('C','R','E',' ')}, /* Cree */ - {"cre", HB_TAG('Y','C','R',' ')}, /* Y-Cree */ - {"crh", HB_TAG('C','R','T',' ')}, /* Crimean Tatar */ - {"crj", HB_TAG('E','C','R',' ')}, /* [Southern] East Cree */ - {"crk", HB_TAG('W','C','R',' ')}, /* West-Cree */ - {"crl", HB_TAG('E','C','R',' ')}, /* [Northern] East Cree */ - {"crm", HB_TAG('M','C','R',' ')}, /* Moose Cree */ - {"crx", HB_TAG('C','R','R',' ')}, /* Carrier */ - {"cs", HB_TAG('C','S','Y',' ')}, /* Czech */ - {"csa", HB_TAG('C','C','H','N')}, /* Chinantec */ - {"csb", HB_TAG('C','S','B',' ')}, /* Kashubian */ - {"csh", HB_TAG('Q','I','N',' ')}, /* Asho Chin */ - {"cso", HB_TAG('C','C','H','N')}, /* Chinantec */ - {"csy", HB_TAG('Q','I','N',' ')}, /* Siyin Chin */ - {"ctd", HB_TAG('Q','I','N',' ')}, /* Tedim Chin */ - {"cte", HB_TAG('C','C','H','N')}, /* Chinantec */ - {"ctg", HB_TAG('C','T','G',' ')}, /* Chittagonian */ - {"ctl", HB_TAG('C','C','H','N')}, /* Chinantec */ - {"cts", HB_TAG('B','I','K',' ')}, /* Northern Catanduanes Bikol */ - {"cu", HB_TAG('C','S','L',' ')}, /* Church Slavic */ - {"cuc", HB_TAG('C','C','H','N')}, /* Chinantec */ - {"cuk", HB_TAG('C','U','K',' ')}, /* San Blas Kuna */ - {"cv", HB_TAG('C','H','U',' ')}, /* Chuvash */ - {"cvn", HB_TAG('C','C','H','N')}, /* Chinantec */ - {"cwd", HB_TAG('D','C','R',' ')}, /* Woods Cree */ - {"cy", HB_TAG('W','E','L',' ')}, /* Welsh */ - {"czt", HB_TAG('Q','I','N',' ')}, /* Zotung Chin */ - {"da", HB_TAG('D','A','N',' ')}, /* Danish */ - {"dao", HB_TAG('Q','I','N',' ')}, /* Daai Chin */ - {"dap", HB_TAG('N','I','S',' ')}, /* Nisi (India) */ - {"dar", HB_TAG('D','A','R',' ')}, /* Dargwa */ - {"dax", HB_TAG('D','A','X',' ')}, /* Dayi */ - {"de", HB_TAG('D','E','U',' ')}, /* German */ - {"dgo", HB_TAG('D','G','O',' ')}, /* Dogri */ - {"dhd", HB_TAG('M','A','W',' ')}, /* Dhundari */ - {"dhg", HB_TAG('D','H','G',' ')}, /* Dhangu */ - {"din", HB_TAG('D','N','K',' ')}, /* Dinka [macrolanguage] */ - {"diq", HB_TAG('D','I','Q',' ')}, /* Dimli */ - {"dje", HB_TAG('D','J','R',' ')}, /* Zarma */ - {"djr", HB_TAG('D','J','R','0')}, /* Djambarrpuyngu */ - {"dng", HB_TAG('D','U','N',' ')}, /* Dungan */ - {"dnj", HB_TAG('D','N','J',' ')}, /* Dan */ - {"doi", HB_TAG('D','G','R',' ')}, /* Dogri [macrolanguage] */ - {"dsb", HB_TAG('L','S','B',' ')}, /* Lower Sorbian */ - {"duj", HB_TAG('D','U','J',' ')}, /* Dhuwal */ - {"dv", HB_TAG('D','I','V',' ')}, /* Dhivehi/Divehi/Maldivian */ - {"dyu", HB_TAG('J','U','L',' ')}, /* Jula */ - {"dz", HB_TAG('D','Z','N',' ')}, /* Dzongkha */ - {"ee", HB_TAG('E','W','E',' ')}, /* Ewe */ - {"efi", HB_TAG('E','F','I',' ')}, /* Efik */ - {"ekk", HB_TAG('E','T','I',' ')}, /* Standard Estonian */ - {"el", HB_TAG('E','L','L',' ')}, /* Modern Greek (1453-) */ - {"emk", HB_TAG('M','N','K',' ')}, /* Eastern Maninkakan */ - {"en", HB_TAG('E','N','G',' ')}, /* English */ - {"enf", HB_TAG('F','N','E',' ')}, /* Forest Nenets */ - {"enh", HB_TAG('T','N','E',' ')}, /* Tundra Nenets */ - {"eo", HB_TAG('N','T','O',' ')}, /* Esperanto */ - {"eot", HB_TAG('B','T','I',' ')}, /* Beti (Côte d'Ivoire) */ - {"es", HB_TAG('E','S','P',' ')}, /* Spanish */ - {"esu", HB_TAG('E','S','U',' ')}, /* Central Yupik */ - {"et", HB_TAG('E','T','I',' ')}, /* Estonian [macrolanguage] */ - {"eu", HB_TAG('E','U','Q',' ')}, /* Basque */ - {"eve", HB_TAG('E','V','N',' ')}, /* Even */ - {"evn", HB_TAG('E','V','K',' ')}, /* Evenki */ - {"fa", HB_TAG('F','A','R',' ')}, /* Persian [macrolanguage] */ - {"fan", HB_TAG('F','A','N','0')}, /* Fang */ - {"fat", HB_TAG('F','A','T',' ')}, /* Fanti */ - {"ff", HB_TAG('F','U','L',' ')}, /* Fulah [macrolanguage] */ - {"fi", HB_TAG('F','I','N',' ')}, /* Finnish */ - {"fil", HB_TAG('P','I','L',' ')}, /* Filipino */ - {"fj", HB_TAG('F','J','I',' ')}, /* Fijian */ - {"flm", HB_TAG('H','A','L',' ')}, /* Halam/Falam Chin [retired ISO639 code] */ - {"fo", HB_TAG('F','O','S',' ')}, /* Faroese */ - {"fon", HB_TAG('F','O','N',' ')}, /* Fon */ - {"fr", HB_TAG('F','R','A',' ')}, /* French */ - {"frc", HB_TAG('F','R','C',' ')}, /* Cajun French */ - {"frp", HB_TAG('F','R','P',' ')}, /* Arpitan/Francoprovençal */ - {"fuf", HB_TAG('F','T','A',' ')}, /* Futa */ - {"fur", HB_TAG('F','R','L',' ')}, /* Friulian */ - {"fuv", HB_TAG('F','U','V',' ')}, /* Nigerian Fulfulde */ - {"fy", HB_TAG('F','R','I',' ')}, /* Western Frisian */ - {"ga", HB_TAG('I','R','I',' ')}, /* Irish */ - {"gaa", HB_TAG('G','A','D',' ')}, /* Ga */ - {"gag", HB_TAG('G','A','G',' ')}, /* Gagauz */ - {"gbm", HB_TAG('G','A','W',' ')}, /* Garhwali */ - {"gd", HB_TAG('G','A','E',' ')}, /* Scottish Gaelic */ - {"gez", HB_TAG('G','E','Z',' ')}, /* Ge'ez */ - {"ggo", HB_TAG('G','O','N',' ')}, /* Southern Gondi */ - {"gih", HB_TAG('G','I','H',' ')}, /* Githabul */ - {"gil", HB_TAG('G','I','L','0')}, /* Kiribati (Gilbertese) */ - {"gkp", HB_TAG('G','K','P',' ')}, /* Kpelle (Guinea) */ - {"gl", HB_TAG('G','A','L',' ')}, /* Galician */ - {"gld", HB_TAG('N','A','N',' ')}, /* Nanai */ - {"glk", HB_TAG('G','L','K',' ')}, /* Gilaki */ - {"gn", HB_TAG('G','U','A',' ')}, /* Guarani [macrolanguage] */ - {"gnn", HB_TAG('G','N','N',' ')}, /* Gumatj */ - {"gno", HB_TAG('G','O','N',' ')}, /* Northern Gondi */ - {"gog", HB_TAG('G','O','G',' ')}, /* Gogo */ - {"gon", HB_TAG('G','O','N',' ')}, /* Gondi [macrolanguage] */ - {"grt", HB_TAG('G','R','O',' ')}, /* Garo */ - {"gru", HB_TAG('S','O','G',' ')}, /* Sodo Gurage */ - {"gsw", HB_TAG('A','L','S',' ')}, /* Alsatian */ - {"gu", HB_TAG('G','U','J',' ')}, /* Gujarati */ - {"guc", HB_TAG('G','U','C',' ')}, /* Wayuu */ - {"guf", HB_TAG('G','U','F',' ')}, /* Gupapuyngu */ - {"guk", HB_TAG('G','M','Z',' ')}, /* Gumuz */ -/*{"guk", HB_TAG('G','U','K',' ')},*/ /* Gumuz (in SIL fonts) */ - {"guz", HB_TAG('G','U','Z',' ')}, /* Ekegusii/Gusii */ - {"gv", HB_TAG('M','N','X',' ')}, /* Manx */ - {"ha", HB_TAG('H','A','U',' ')}, /* Hausa */ - {"har", HB_TAG('H','R','I',' ')}, /* Harari */ - {"haw", HB_TAG('H','A','W',' ')}, /* Hawaiian */ - {"hay", HB_TAG('H','A','Y',' ')}, /* Haya */ - {"haz", HB_TAG('H','A','Z',' ')}, /* Hazaragi */ - {"he", HB_TAG('I','W','R',' ')}, /* Hebrew */ - {"hi", HB_TAG('H','I','N',' ')}, /* Hindi */ - {"hil", HB_TAG('H','I','L',' ')}, /* Hiligaynon */ - {"hlt", HB_TAG('Q','I','N',' ')}, /* Matu Chin */ - {"hmn", HB_TAG('H','M','N',' ')}, /* Hmong */ - {"hnd", HB_TAG('H','N','D',' ')}, /* [Southern] Hindko */ - {"hne", HB_TAG('C','H','H',' ')}, /* Chattisgarhi */ - {"hno", HB_TAG('H','N','D',' ')}, /* [Northern] Hindko */ - {"ho", HB_TAG('H','M','O',' ')}, /* Hiri Motu */ - {"hoc", HB_TAG('H','O',' ',' ')}, /* Ho */ - {"hoj", HB_TAG('H','A','R',' ')}, /* Harauti */ - {"hr", HB_TAG('H','R','V',' ')}, /* Croatian */ - {"hsb", HB_TAG('U','S','B',' ')}, /* Upper Sorbian */ - {"ht", HB_TAG('H','A','I',' ')}, /* Haitian/Haitian Creole */ - {"hu", HB_TAG('H','U','N',' ')}, /* Hungarian */ - {"hy", HB_TAG('H','Y','E',' ')}, /* Armenian */ - {"hz", HB_TAG('H','E','R',' ')}, /* Herero */ - {"ia", HB_TAG('I','N','A',' ')}, /* Interlingua (International Auxiliary Language Association) */ - {"iba", HB_TAG('I','B','A',' ')}, /* Iban */ - {"ibb", HB_TAG('I','B','B',' ')}, /* Ibibio */ - {"id", HB_TAG('I','N','D',' ')}, /* Indonesian */ - {"ie", HB_TAG('I','L','E',' ')}, /* Interlingue/Occidental */ - {"ig", HB_TAG('I','B','O',' ')}, /* Igbo */ - {"igb", HB_TAG('E','B','I',' ')}, /* Ebira */ - {"ii", HB_TAG('Y','I','M',' ')}, /* Yi Modern */ - {"ijc", HB_TAG('I','J','O',' ')}, /* Izon */ - {"ijo", HB_TAG('I','J','O',' ')}, /* Ijo [family] */ - {"ik", HB_TAG('I','P','K',' ')}, /* Inupiaq [macrolanguage] */ - {"ilo", HB_TAG('I','L','O',' ')}, /* Ilokano */ - {"inh", HB_TAG('I','N','G',' ')}, /* Ingush */ - {"io", HB_TAG('I','D','O',' ')}, /* Ido */ - {"is", HB_TAG('I','S','L',' ')}, /* Icelandic */ - {"it", HB_TAG('I','T','A',' ')}, /* Italian */ - {"iu", HB_TAG('I','N','U',' ')}, /* Inuktitut [macrolanguage] */ - {"ja", HB_TAG('J','A','N',' ')}, /* Japanese */ - {"jam", HB_TAG('J','A','M',' ')}, /* Jamaican Creole English */ - {"jbo", HB_TAG('J','B','O',' ')}, /* Lojban */ - {"jv", HB_TAG('J','A','V',' ')}, /* Javanese */ - {"ka", HB_TAG('K','A','T',' ')}, /* Georgian */ - {"kaa", HB_TAG('K','R','K',' ')}, /* Karakalpak */ - {"kab", HB_TAG('K','A','B','0')}, /* Kabyle */ - {"kam", HB_TAG('K','M','B',' ')}, /* Kamba (Kenya) */ - {"kar", HB_TAG('K','R','N',' ')}, /* Karen [family] */ - {"kat", HB_TAG('K','G','E',' ')}, /* Khutsuri Georgian */ - {"kbd", HB_TAG('K','A','B',' ')}, /* Kabardian */ - {"kde", HB_TAG('K','D','E',' ')}, /* Makonde */ - {"kdr", HB_TAG('K','R','M',' ')}, /* Karaim */ - {"kdt", HB_TAG('K','U','Y',' ')}, /* Kuy */ - {"kea", HB_TAG('K','E','A',' ')}, /* Kabuverdianu (Crioulo) */ - {"kek", HB_TAG('K','E','K',' ')}, /* Kekchi */ - {"kex", HB_TAG('K','K','N',' ')}, /* Kokni */ - {"kfa", HB_TAG('K','O','D',' ')}, /* Kodagu */ - {"kfr", HB_TAG('K','A','C',' ')}, /* Kachchi */ - {"kfx", HB_TAG('K','U','L',' ')}, /* Kulvi */ - {"kfy", HB_TAG('K','M','N',' ')}, /* Kumaoni */ - {"kg", HB_TAG('K','O','N',' ')}, /* Kongo [macrolanguage] */ - {"kha", HB_TAG('K','S','I',' ')}, /* Khasi */ - {"khb", HB_TAG('X','B','D',' ')}, /* Lü */ - {"kht", HB_TAG('K','H','N',' ')}, /* Khamti (Microsoft fonts) */ -/*{"kht", HB_TAG('K','H','T',' ')},*/ /* Khamti (OpenType spec and SIL fonts) */ - {"khw", HB_TAG('K','H','W',' ')}, /* Khowar */ - {"ki", HB_TAG('K','I','K',' ')}, /* Gikuyu/Kikuyu */ - {"kiu", HB_TAG('K','I','U',' ')}, /* Kirmanjki */ - {"kj", HB_TAG('K','U','A',' ')}, /* Kuanyama/Kwanyama */ - {"kjd", HB_TAG('K','J','D',' ')}, /* Southern Kiwai */ - {"kjh", HB_TAG('K','H','A',' ')}, /* Khakass */ - {"kjp", HB_TAG('K','J','P',' ')}, /* Pwo Eastern Karen */ - {"kk", HB_TAG('K','A','Z',' ')}, /* Kazakh */ - {"kl", HB_TAG('G','R','N',' ')}, /* Kalaallisut */ - {"kln", HB_TAG('K','A','L',' ')}, /* Kalenjin */ - {"km", HB_TAG('K','H','M',' ')}, /* Central Khmer */ - {"kmb", HB_TAG('M','B','N',' ')}, /* Kimbundu */ - {"kmw", HB_TAG('K','M','O',' ')}, /* Komo (Democratic Republic of Congo) */ - {"kn", HB_TAG('K','A','N',' ')}, /* Kannada */ - {"knn", HB_TAG('K','O','K',' ')}, /* Konkani */ - {"ko", HB_TAG('K','O','R',' ')}, /* Korean */ - {"koi", HB_TAG('K','O','P',' ')}, /* Komi-Permyak */ - {"kok", HB_TAG('K','O','K',' ')}, /* Konkani [macrolanguage] */ - {"kon", HB_TAG('K','O','N','0')}, /* Kongo */ - {"kos", HB_TAG('K','O','S',' ')}, /* Kosraean */ - {"kpe", HB_TAG('K','P','L',' ')}, /* Kpelle [macrolanguage] */ - {"kpv", HB_TAG('K','O','Z',' ')}, /* Komi-Zyrian */ - {"kpy", HB_TAG('K','Y','K',' ')}, /* Koryak */ - {"kqy", HB_TAG('K','R','T',' ')}, /* Koorete */ - {"kr", HB_TAG('K','N','R',' ')}, /* Kanuri [macrolanguage] */ - {"kri", HB_TAG('K','R','I',' ')}, /* Krio */ - {"krl", HB_TAG('K','R','L',' ')}, /* Karelian */ - {"kru", HB_TAG('K','U','U',' ')}, /* Kurukh */ - {"ks", HB_TAG('K','S','H',' ')}, /* Kashmiri */ - {"ksh", HB_TAG('K','S','H','0')}, /* Ripuarian, Kölsch */ -/*{"ksw", HB_TAG('K','R','N',' ')},*/ /* S'gaw Karen (Microsoft fonts?) */ - {"ksw", HB_TAG('K','S','W',' ')}, /* S'gaw Karen (OpenType spec and SIL fonts) */ - {"ktb", HB_TAG('K','E','B',' ')}, /* Kebena */ - {"ktu", HB_TAG('K','O','N',' ')}, /* Kikongo */ - {"ku", HB_TAG('K','U','R',' ')}, /* Kurdish [macrolanguage] */ - {"kum", HB_TAG('K','U','M',' ')}, /* Kumyk */ - {"kv", HB_TAG('K','O','M',' ')}, /* Komi [macrolanguage] */ - {"kvd", HB_TAG('K','U','I',' ')}, /* Kui (Indonesia) */ - {"kw", HB_TAG('C','O','R',' ')}, /* Cornish */ - {"kxc", HB_TAG('K','M','S',' ')}, /* Komso */ - {"kxu", HB_TAG('K','U','I',' ')}, /* Kui (India) */ - {"ky", HB_TAG('K','I','R',' ')}, /* Kirghiz/Kyrgyz */ - {"kyu", HB_TAG('K','Y','U',' ')}, /* Western Kayah */ - {"la", HB_TAG('L','A','T',' ')}, /* Latin */ - {"lad", HB_TAG('J','U','D',' ')}, /* Ladino */ - {"lb", HB_TAG('L','T','Z',' ')}, /* Luxembourgish */ - {"lbe", HB_TAG('L','A','K',' ')}, /* Lak */ - {"lbj", HB_TAG('L','D','K',' ')}, /* Ladakhi */ - {"lez", HB_TAG('L','E','Z',' ')}, /* Lezgi */ - {"lg", HB_TAG('L','U','G',' ')}, /* Ganda */ - {"li", HB_TAG('L','I','M',' ')}, /* Limburgan/Limburger/Limburgish */ - {"lif", HB_TAG('L','M','B',' ')}, /* Limbu */ - {"lij", HB_TAG('L','I','J',' ')}, /* Ligurian */ - {"lis", HB_TAG('L','I','S',' ')}, /* Lisu */ - {"ljp", HB_TAG('L','J','P',' ')}, /* Lampung Api */ - {"lki", HB_TAG('L','K','I',' ')}, /* Laki */ - {"lld", HB_TAG('L','A','D',' ')}, /* Ladin */ - {"lmn", HB_TAG('L','A','M',' ')}, /* Lambani */ - {"lmo", HB_TAG('L','M','O',' ')}, /* Lombard */ - {"ln", HB_TAG('L','I','N',' ')}, /* Lingala */ - {"lo", HB_TAG('L','A','O',' ')}, /* Lao */ - {"lom", HB_TAG('L','O','M',' ')}, /* Loma */ - {"lrc", HB_TAG('L','R','C',' ')}, /* Northern Luri */ - {"lt", HB_TAG('L','T','H',' ')}, /* Lithuanian */ - {"lu", HB_TAG('L','U','B',' ')}, /* Luba-Katanga */ - {"lua", HB_TAG('L','U','B',' ')}, /* Luba-Kasai */ - {"luo", HB_TAG('L','U','O',' ')}, /* Luo (Kenya and Tanzania) */ - {"lus", HB_TAG('M','I','Z',' ')}, /* Mizo */ - {"luy", HB_TAG('L','U','H',' ')}, /* Luyia/Oluluyia [macrolanguage] */ - {"luz", HB_TAG('L','R','C',' ')}, /* Southern Luri */ - {"lv", HB_TAG('L','V','I',' ')}, /* Latvian */ - {"lzz", HB_TAG('L','A','Z',' ')}, /* Laz */ - {"mad", HB_TAG('M','A','D',' ')}, /* Madurese */ - {"mag", HB_TAG('M','A','G',' ')}, /* Magahi */ - {"mai", HB_TAG('M','T','H',' ')}, /* Maithili */ - {"mak", HB_TAG('M','K','R',' ')}, /* Makasar */ - {"mam", HB_TAG('M','A','M',' ')}, /* Mam */ - {"man", HB_TAG('M','N','K',' ')}, /* Manding/Mandingo [macrolanguage] */ - {"mdc", HB_TAG('M','L','E',' ')}, /* Male (Papua New Guinea) */ - {"mdf", HB_TAG('M','O','K',' ')}, /* Moksha */ - {"mdr", HB_TAG('M','D','R',' ')}, /* Mandar */ - {"mdy", HB_TAG('M','L','E',' ')}, /* Male (Ethiopia) */ - {"men", HB_TAG('M','D','E',' ')}, /* Mende (Sierra Leone) */ - {"mer", HB_TAG('M','E','R',' ')}, /* Meru */ - {"mfe", HB_TAG('M','F','E',' ')}, /* Morisyen */ - {"mg", HB_TAG('M','L','G',' ')}, /* Malagasy [macrolanguage] */ - {"mh", HB_TAG('M','A','H',' ')}, /* Marshallese */ - {"mhr", HB_TAG('L','M','A',' ')}, /* Low Mari */ - {"mi", HB_TAG('M','R','I',' ')}, /* Maori */ - {"min", HB_TAG('M','I','N',' ')}, /* Minangkabau */ - {"mk", HB_TAG('M','K','D',' ')}, /* Macedonian */ - {"mku", HB_TAG('M','N','K',' ')}, /* Konyanka Maninka */ - {"mkw", HB_TAG('M','K','W',' ')}, /* Kituba (Congo) */ - {"ml", HB_TAG('M','L','R',' ')}, /* Malayalam */ - {"mlq", HB_TAG('M','N','K',' ')}, /* Western Maninkakan */ - {"mn", HB_TAG('M','N','G',' ')}, /* Mongolian [macrolanguage] */ - {"mnc", HB_TAG('M','C','H',' ')}, /* Manchu */ - {"mni", HB_TAG('M','N','I',' ')}, /* Manipuri */ - {"mnk", HB_TAG('M','N','D',' ')}, /* Mandinka */ - {"mns", HB_TAG('M','A','N',' ')}, /* Mansi */ - {"mnw", HB_TAG('M','O','N',' ')}, /* Mon */ - {"mo", HB_TAG('M','O','L',' ')}, /* Moldavian */ - {"moh", HB_TAG('M','O','H',' ')}, /* Mohawk */ - {"mos", HB_TAG('M','O','S',' ')}, /* Mossi */ - {"mpe", HB_TAG('M','A','J',' ')}, /* Majang */ - {"mr", HB_TAG('M','A','R',' ')}, /* Marathi */ - {"mrh", HB_TAG('Q','I','N',' ')}, /* Mara Chin */ - {"mrj", HB_TAG('H','M','A',' ')}, /* High Mari */ - {"ms", HB_TAG('M','L','Y',' ')}, /* Malay [macrolanguage] */ - {"msc", HB_TAG('M','N','K',' ')}, /* Sankaran Maninka */ - {"mt", HB_TAG('M','T','S',' ')}, /* Maltese */ - {"mtr", HB_TAG('M','A','W',' ')}, /* Mewari */ - {"mus", HB_TAG('M','U','S',' ')}, /* Creek */ - {"mve", HB_TAG('M','A','W',' ')}, /* Marwari (Pakistan) */ - {"mwk", HB_TAG('M','N','K',' ')}, /* Kita Maninkakan */ - {"mwl", HB_TAG('M','W','L',' ')}, /* Mirandese */ - {"mwr", HB_TAG('M','A','W',' ')}, /* Marwari [macrolanguage] */ - {"mww", HB_TAG('M','W','W',' ')}, /* Hmong Daw */ - {"my", HB_TAG('B','R','M',' ')}, /* Burmese */ - {"mym", HB_TAG('M','E','N',' ')}, /* Me'en */ - {"myn", HB_TAG('M','Y','N',' ')}, /* Mayan */ - {"myq", HB_TAG('M','N','K',' ')}, /* Forest Maninka (retired code) */ - {"myv", HB_TAG('E','R','Z',' ')}, /* Erzya */ - {"mzn", HB_TAG('M','Z','N',' ')}, /* Mazanderani */ - {"na", HB_TAG('N','A','U',' ')}, /* Nauru */ - {"nag", HB_TAG('N','A','G',' ')}, /* Naga-Assamese */ - {"nah", HB_TAG('N','A','H',' ')}, /* Nahuatl [family] */ - {"nap", HB_TAG('N','A','P',' ')}, /* Neapolitan */ - {"nb", HB_TAG('N','O','R',' ')}, /* Norwegian Bokmål */ - {"nco", HB_TAG('S','I','B',' ')}, /* Sibe */ - {"nd", HB_TAG('N','D','B',' ')}, /* [North] Ndebele */ - {"ndc", HB_TAG('N','D','C',' ')}, /* Ndau */ - {"nds", HB_TAG('N','D','S',' ')}, /* Low German/Low Saxon */ - {"ne", HB_TAG('N','E','P',' ')}, /* Nepali */ - {"new", HB_TAG('N','E','W',' ')}, /* Newari */ - {"ng", HB_TAG('N','D','G',' ')}, /* Ndonga */ - {"nga", HB_TAG('N','G','A',' ')}, /* Ngabaka */ - {"ngl", HB_TAG('L','M','W',' ')}, /* Lomwe */ - {"ngo", HB_TAG('S','X','T',' ')}, /* Sutu */ - {"niu", HB_TAG('N','I','U',' ')}, /* Niuean */ - {"niv", HB_TAG('G','I','L',' ')}, /* Gilyak */ - {"nl", HB_TAG('N','L','D',' ')}, /* Dutch */ - {"nn", HB_TAG('N','Y','N',' ')}, /* Norwegian Nynorsk */ - {"no", HB_TAG('N','O','R',' ')}, /* Norwegian [macrolanguage] */ - {"nod", HB_TAG('N','T','A',' ')}, /* Northern Thai */ - {"noe", HB_TAG('N','O','E',' ')}, /* Nimadi */ - {"nog", HB_TAG('N','O','G',' ')}, /* Nogai */ - {"nov", HB_TAG('N','O','V',' ')}, /* Novial */ - {"nqo", HB_TAG('N','K','O',' ')}, /* N'Ko */ - {"nr", HB_TAG('N','D','B',' ')}, /* [South] Ndebele */ - {"nsk", HB_TAG('N','A','S',' ')}, /* Naskapi */ - {"nso", HB_TAG('S','O','T',' ')}, /* [Northern] Sotho */ - {"nv", HB_TAG('N','A','V',' ')}, /* Navajo */ - {"ny", HB_TAG('C','H','I',' ')}, /* Chewa/Chichwa/Nyanja */ - {"nym", HB_TAG('N','Y','M',' ')}, /* Nyamwezi */ - {"nyn", HB_TAG('N','K','L',' ')}, /* Nyankole */ - {"oc", HB_TAG('O','C','I',' ')}, /* Occitan (post 1500) */ - {"oj", HB_TAG('O','J','B',' ')}, /* Ojibwa [macrolanguage] */ - {"ojs", HB_TAG('O','C','R',' ')}, /* Oji-Cree */ - {"okm", HB_TAG('K','O','H',' ')}, /* Korean Old Hangul */ - {"om", HB_TAG('O','R','O',' ')}, /* Oromo [macrolanguage] */ - {"or", HB_TAG('O','R','I',' ')}, /* Oriya */ - {"os", HB_TAG('O','S','S',' ')}, /* Ossetian */ - {"pa", HB_TAG('P','A','N',' ')}, /* Panjabi */ - {"pag", HB_TAG('P','A','G',' ')}, /* Pangasinan */ - {"pam", HB_TAG('P','A','M',' ')}, /* Kapampangan/Pampanga */ - {"pap", HB_TAG('P','A','P','0')}, /* Papiamento */ - {"pau", HB_TAG('P','A','U',' ')}, /* Palauan */ - {"pcc", HB_TAG('P','C','C',' ')}, /* Bouyei */ - {"pcd", HB_TAG('P','C','D',' ')}, /* Picard */ - {"pce", HB_TAG('P','L','G',' ')}, /* [Ruching] Palaung */ - {"pck", HB_TAG('Q','I','N',' ')}, /* Paite Chin */ - {"pdc", HB_TAG('P','D','C',' ')}, /* Pennsylvania German */ - {"pes", HB_TAG('F','A','R',' ')}, /* Iranian Persian */ - {"phk", HB_TAG('P','H','K',' ')}, /* Phake */ - {"pi", HB_TAG('P','A','L',' ')}, /* Pali */ - {"pih", HB_TAG('P','I','H',' ')}, /* Pitcairn-Norfolk */ - {"pl", HB_TAG('P','L','K',' ')}, /* Polish */ - {"pll", HB_TAG('P','L','G',' ')}, /* [Shwe] Palaung */ - {"plp", HB_TAG('P','A','P',' ')}, /* Palpa */ - {"pms", HB_TAG('P','M','S',' ')}, /* Piemontese */ - {"pnb", HB_TAG('P','N','B',' ')}, /* Western Panjabi */ - {"poh", HB_TAG('P','O','H',' ')}, /* Pocomchi */ - {"pon", HB_TAG('P','O','N',' ')}, /* Pohnpeian */ - {"prs", HB_TAG('D','R','I',' ')}, /* Afghan Persian/Dari */ - {"ps", HB_TAG('P','A','S',' ')}, /* Pashto/Pushto [macrolanguage] */ - {"pt", HB_TAG('P','T','G',' ')}, /* Portuguese */ - {"pwo", HB_TAG('P','W','O',' ')}, /* Pwo Western Karen */ - {"qu", HB_TAG('Q','U','Z',' ')}, /* Quechua [macrolanguage] */ - {"quc", HB_TAG('Q','U','C',' ')}, /* K'iche'/Quiché */ - {"quh", HB_TAG('Q','U','H',' ')}, /* Quechua (Bolivia) */ - {"quz", HB_TAG('Q','U','Z',' ')}, /* Cusco Quechua */ - {"qvi", HB_TAG('Q','V','I',' ')}, /* Quechua (Ecuador) */ - {"qwh", HB_TAG('Q','W','H',' ')}, /* Quechua (Peru) */ - {"raj", HB_TAG('R','A','J',' ')}, /* Rajasthani [macrolanguage] */ - {"rar", HB_TAG('R','A','R',' ')}, /* Rarotongan */ - {"rbb", HB_TAG('P','L','G',' ')}, /* Rumai Palaung */ - {"rej", HB_TAG('R','E','J',' ')}, /* Rejang */ - {"ria", HB_TAG('R','I','A',' ')}, /* Riang (India) */ - {"rif", HB_TAG('R','I','F',' ')}, /* Tarifit */ - {"ril", HB_TAG('R','I','A',' ')}, /* Riang (Myanmar) */ - {"rit", HB_TAG('R','I','T',' ')}, /* Ritarungo */ - {"rki", HB_TAG('A','R','K',' ')}, /* Rakhine */ - {"rkw", HB_TAG('R','K','W',' ')}, /* Arakwal */ - {"rm", HB_TAG('R','M','S',' ')}, /* Romansh */ - {"rmy", HB_TAG('R','M','Y',' ')}, /* Vlax Romani */ - {"rn", HB_TAG('R','U','N',' ')}, /* Rundi */ - {"ro", HB_TAG('R','O','M',' ')}, /* Romanian */ - {"rom", HB_TAG('R','O','Y',' ')}, /* Romany [macrolanguage] */ - {"rtm", HB_TAG('R','T','M',' ')}, /* Rotuman */ - {"ru", HB_TAG('R','U','S',' ')}, /* Russian */ - {"rue", HB_TAG('R','S','Y',' ')}, /* Rusyn */ - {"rup", HB_TAG('R','U','P',' ')}, /* Aromanian/Arumanian/Macedo-Romanian */ - {"rw", HB_TAG('R','U','A',' ')}, /* Kinyarwanda */ - {"rwr", HB_TAG('M','A','W',' ')}, /* Marwari (India) */ - {"sa", HB_TAG('S','A','N',' ')}, /* Sanskrit */ - {"sah", HB_TAG('Y','A','K',' ')}, /* Yakut */ - {"sam", HB_TAG('P','A','A',' ')}, /* Palestinian Aramaic */ - {"sas", HB_TAG('S','A','S',' ')}, /* Sasak */ - {"sat", HB_TAG('S','A','T',' ')}, /* Santali */ - {"sc", HB_TAG('S','R','D',' ')}, /* Sardinian [macrolanguage] */ - {"sck", HB_TAG('S','A','D',' ')}, /* Sadri */ - {"scn", HB_TAG('S','C','N',' ')}, /* Sicilian */ - {"sco", HB_TAG('S','C','O',' ')}, /* Scots */ - {"scs", HB_TAG('S','L','A',' ')}, /* [North] Slavey */ - {"sd", HB_TAG('S','N','D',' ')}, /* Sindhi */ - {"se", HB_TAG('N','S','M',' ')}, /* Northern Sami */ - {"seh", HB_TAG('S','N','A',' ')}, /* Sena */ - {"sel", HB_TAG('S','E','L',' ')}, /* Selkup */ - {"sez", HB_TAG('Q','I','N',' ')}, /* Senthang Chin */ - {"sg", HB_TAG('S','G','O',' ')}, /* Sango */ - {"sga", HB_TAG('S','G','A',' ')}, /* Old Irish (to 900) */ - {"sgs", HB_TAG('S','G','S',' ')}, /* Samogitian */ - {"sgw", HB_TAG('C','H','G',' ')}, /* Sebat Bet Gurage */ -/*{"sgw", HB_TAG('S','G','W',' ')},*/ /* Sebat Bet Gurage (in SIL fonts) */ - {"shi", HB_TAG('S','H','I',' ')}, /* Tachelhit */ - {"shn", HB_TAG('S','H','N',' ')}, /* Shan */ - {"si", HB_TAG('S','N','H',' ')}, /* Sinhala */ - {"sid", HB_TAG('S','I','D',' ')}, /* Sidamo */ - {"sjd", HB_TAG('K','S','M',' ')}, /* Kildin Sami */ - {"sk", HB_TAG('S','K','Y',' ')}, /* Slovak */ - {"skr", HB_TAG('S','R','K',' ')}, /* Seraiki */ - {"sl", HB_TAG('S','L','V',' ')}, /* Slovenian */ - {"sm", HB_TAG('S','M','O',' ')}, /* Samoan */ - {"sma", HB_TAG('S','S','M',' ')}, /* Southern Sami */ - {"smj", HB_TAG('L','S','M',' ')}, /* Lule Sami */ - {"smn", HB_TAG('I','S','M',' ')}, /* Inari Sami */ - {"sms", HB_TAG('S','K','S',' ')}, /* Skolt Sami */ - {"sn", HB_TAG('S','N','A','0')}, /* Shona */ - {"snk", HB_TAG('S','N','K',' ')}, /* Soninke */ - {"so", HB_TAG('S','M','L',' ')}, /* Somali */ - {"sop", HB_TAG('S','O','P',' ')}, /* Songe */ - {"sq", HB_TAG('S','Q','I',' ')}, /* Albanian [macrolanguage] */ - {"sr", HB_TAG('S','R','B',' ')}, /* Serbian */ - {"srr", HB_TAG('S','R','R',' ')}, /* Serer */ - {"ss", HB_TAG('S','W','Z',' ')}, /* Swati */ - {"st", HB_TAG('S','O','T',' ')}, /* [Southern] Sotho */ - {"stq", HB_TAG('S','T','Q',' ')}, /* Saterfriesisch */ - {"stv", HB_TAG('S','I','G',' ')}, /* Silt'e */ - {"su", HB_TAG('S','U','N',' ')}, /* Sundanese */ - {"suk", HB_TAG('S','U','K',' ')}, /* Sukama */ - {"suq", HB_TAG('S','U','R',' ')}, /* Suri */ - {"sv", HB_TAG('S','V','E',' ')}, /* Swedish */ - {"sva", HB_TAG('S','V','A',' ')}, /* Svan */ - {"sw", HB_TAG('S','W','K',' ')}, /* Swahili [macrolanguage] */ - {"swb", HB_TAG('C','M','R',' ')}, /* Comorian */ - {"swh", HB_TAG('S','W','K',' ')}, /* Kiswahili/Swahili */ - {"swv", HB_TAG('M','A','W',' ')}, /* Shekhawati */ - {"sxu", HB_TAG('S','X','U',' ')}, /* Upper Saxon */ - {"syc", HB_TAG('S','Y','R',' ')}, /* Classical Syriac */ - {"syl", HB_TAG('S','Y','L',' ')}, /* Sylheti */ - {"syr", HB_TAG('S','Y','R',' ')}, /* Syriac [macrolanguage] */ - {"szl", HB_TAG('S','Z','L',' ')}, /* Silesian */ - {"ta", HB_TAG('T','A','M',' ')}, /* Tamil */ - {"tab", HB_TAG('T','A','B',' ')}, /* Tabasaran */ - {"tcp", HB_TAG('Q','I','N',' ')}, /* Tawr Chin */ - {"tcy", HB_TAG('T','U','L',' ')}, /* Tulu */ - {"tcz", HB_TAG('Q','I','N',' ')}, /* Thado Chin */ - {"tdd", HB_TAG('T','D','D',' ')}, /* Tai Nüa */ - {"te", HB_TAG('T','E','L',' ')}, /* Telugu */ - {"tem", HB_TAG('T','M','N',' ')}, /* Temne */ - {"tet", HB_TAG('T','E','T',' ')}, /* Tetum */ - {"tg", HB_TAG('T','A','J',' ')}, /* Tajik */ - {"th", HB_TAG('T','H','A',' ')}, /* Thai */ - {"ti", HB_TAG('T','G','Y',' ')}, /* Tigrinya */ - {"tig", HB_TAG('T','G','R',' ')}, /* Tigre */ - {"tiv", HB_TAG('T','I','V',' ')}, /* Tiv */ - {"tk", HB_TAG('T','K','M',' ')}, /* Turkmen */ - {"tl", HB_TAG('T','G','L',' ')}, /* Tagalog */ - {"tmh", HB_TAG('T','M','H',' ')}, /* Tamashek */ - {"tn", HB_TAG('T','N','A',' ')}, /* Tswana */ - {"to", HB_TAG('T','G','N',' ')}, /* Tonga (Tonga Islands) */ - {"tod", HB_TAG('T','O','D','0')}, /* Toma */ - {"toi", HB_TAG('T','N','G',' ')}, /* Tonga */ - {"tpi", HB_TAG('T','P','I',' ')}, /* Tok Pisin */ - {"tr", HB_TAG('T','R','K',' ')}, /* Turkish */ - {"tru", HB_TAG('T','U','A',' ')}, /* Turoyo Aramaic */ - {"ts", HB_TAG('T','S','G',' ')}, /* Tsonga */ - {"tt", HB_TAG('T','A','T',' ')}, /* Tatar */ - {"tum", HB_TAG('T','U','M',' ')}, /* Tumbuka */ - {"tvl", HB_TAG('T','V','L',' ')}, /* Tuvalu */ - {"tw", HB_TAG('T','W','I',' ')}, /* Twi */ - {"ty", HB_TAG('T','H','T',' ')}, /* Tahitian */ - {"tyv", HB_TAG('T','U','V',' ')}, /* Tuvin */ - {"tyz", HB_TAG('T','Y','Z',' ')}, /* Tày */ - {"tzm", HB_TAG('T','Z','M',' ')}, /* Central Atlas Tamazight */ - {"tzo", HB_TAG('T','Z','O',' ')}, /* Tzotzil */ - {"udm", HB_TAG('U','D','M',' ')}, /* Udmurt */ - {"ug", HB_TAG('U','Y','G',' ')}, /* Uighur */ - {"uk", HB_TAG('U','K','R',' ')}, /* Ukrainian */ - {"umb", HB_TAG('U','M','B',' ')}, /* Umbundu */ - {"unr", HB_TAG('M','U','N',' ')}, /* Mundari */ - {"ur", HB_TAG('U','R','D',' ')}, /* Urdu */ - {"uz", HB_TAG('U','Z','B',' ')}, /* Uzbek [macrolanguage] */ - {"uzn", HB_TAG('U','Z','B',' ')}, /* Northern Uzbek */ - {"uzs", HB_TAG('U','Z','B',' ')}, /* Southern Uzbek */ - {"ve", HB_TAG('V','E','N',' ')}, /* Venda */ - {"vec", HB_TAG('V','E','C',' ')}, /* Venetian */ - {"vi", HB_TAG('V','I','T',' ')}, /* Vietnamese */ - {"vls", HB_TAG('F','L','E',' ')}, /* Vlaams */ - {"vmw", HB_TAG('M','A','K',' ')}, /* Makhuwa */ - {"vo", HB_TAG('V','O','L',' ')}, /* Volapük */ - {"vro", HB_TAG('V','R','O',' ')}, /* Võro */ - {"wa", HB_TAG('W','L','N',' ')}, /* Walloon */ - {"war", HB_TAG('W','A','R',' ')}, /* Waray (Philippines) */ - {"wbm", HB_TAG('W','A',' ',' ')}, /* Wa */ - {"wbr", HB_TAG('W','A','G',' ')}, /* Wagdi */ - {"wle", HB_TAG('S','I','G',' ')}, /* Wolane */ - {"wo", HB_TAG('W','L','F',' ')}, /* Wolof */ - {"wry", HB_TAG('M','A','W',' ')}, /* Merwari */ - {"wtm", HB_TAG('W','T','M',' ')}, /* Mewati */ - {"xal", HB_TAG('K','L','M',' ')}, /* Kalmyk */ - {"xan", HB_TAG('S','E','K',' ')}, /* Sekota */ - {"xh", HB_TAG('X','H','S',' ')}, /* Xhosa */ - {"xjb", HB_TAG('X','J','B',' ')}, /* Minjangbal */ - {"xog", HB_TAG('X','O','G',' ')}, /* Soga */ - {"xom", HB_TAG('K','M','O',' ')}, /* Komo (Sudan) */ - {"xpe", HB_TAG('X','P','E',' ')}, /* Kpelle (Liberia) */ - {"xsl", HB_TAG('S','S','L',' ')}, /* South Slavey */ - {"xst", HB_TAG('S','I','G',' ')}, /* Silt'e (retired code) */ - {"xwo", HB_TAG('T','O','D',' ')}, /* Written Oirat (Todo) */ - {"yao", HB_TAG('Y','A','O',' ')}, /* Yao */ - {"yap", HB_TAG('Y','A','P',' ')}, /* Yapese */ - {"yi", HB_TAG('J','I','I',' ')}, /* Yiddish [macrolanguage] */ - {"yo", HB_TAG('Y','B','A',' ')}, /* Yoruba */ - {"yos", HB_TAG('Q','I','N',' ')}, /* Yos, deprecated by IANA in favor of Zou [zom] */ - {"yso", HB_TAG('N','I','S',' ')}, /* Nisi (China) */ - {"za", HB_TAG('Z','H','A',' ')}, /* Chuang/Zhuang [macrolanguage] */ - {"zea", HB_TAG('Z','E','A',' ')}, /* Zeeuws */ - {"zgh", HB_TAG('Z','G','H',' ')}, /* Standard Morrocan Tamazigh */ - {"zne", HB_TAG('Z','N','D',' ')}, /* Zande */ - {"zom", HB_TAG('Q','I','N',' ')}, /* Zou */ - {"zu", HB_TAG('Z','U','L',' ')}, /* Zulu */ - {"zum", HB_TAG('L','R','C',' ')}, /* Kumzari */ - {"zza", HB_TAG('Z','Z','A',' ')}, /* Zazaki */ - - /* The corresponding languages IDs for the following IDs are unclear, - * overlap, or are architecturally weird. Needs more research. */ - -/*{"chp", HB_TAG('S','A','Y',' ')},*/ /* Sayisi */ -/*{"cwd", HB_TAG('T','C','R',' ')},*/ /* TH-Cree */ -/*{"emk", HB_TAG('E','M','K',' ')},*/ /* Eastern Maninkakan */ -/*{"krc", HB_TAG('B','A','L',' ')},*/ /* Balkar */ -/*{"??", HB_TAG('B','C','R',' ')},*/ /* Bible Cree */ -/*{"zh?", HB_TAG('C','H','N',' ')},*/ /* Chinese (seen in Microsoft fonts) */ -/*{"ar-Syrc?", HB_TAG('G','A','R',' ')},*/ /* Garshuni */ -/*{"hy?", HB_TAG('H','Y','E','0')},*/ /* Armenian East (ISO 639-3 hye according to Microsoft, but that’s equivalent to ISO 639-1 hy) */ -/*{"ga-Latg?/" HB_TAG('I','R','T',' ')},*/ /* Irish Traditional */ -/*{"krc", HB_TAG('K','A','R',' ')},*/ /* Karachay */ -/*{"ka-Geok?", HB_TAG('K','G','E',' ')},*/ /* Khutsuri Georgian */ -/*{"kca", HB_TAG('K','H','K',' ')},*/ /* Khanty-Kazim */ -/*{"kca", HB_TAG('K','H','S',' ')},*/ /* Khanty-Shurishkar */ -/*{"kca", HB_TAG('K','H','V',' ')},*/ /* Khanty-Vakhi */ -/*{"kqs, kss", HB_TAG('K','I','S',' ')},*/ /* Kisii */ -/*{"lua", HB_TAG('L','U','A',' ')},*/ /* Luba-Lulua */ -/*{"mlq", HB_TAG('M','L','N',' ')},*/ /* Malinke */ -/*{"nso", HB_TAG('N','S','O',' ')},*/ /* Sotho, Northern */ -/*{"??", HB_TAG('M','A','L',' ')},*/ /* Malayalam Traditional */ -/*{"csw", HB_TAG('N','C','R',' ')},*/ /* N-Cree */ -/*{"csw", HB_TAG('N','H','C',' ')},*/ /* Norway House Cree */ -/*{"el-polyton", HB_TAG('P','G','R',' ')},*/ /* Polytonic Greek */ -/*{"bgr, cnh, cnw, czt, sez, tcp, csy, ctd, flm, pck, tcz, zom, cmr, dao, hlt, cka, cnk, mrh, mwg, cbl, cnb, csh", HB_TAG('Q','I','N',' ')},*/ /* Chin */ -/*{"??", HB_TAG('Y','I','C',' ')},*/ /* Yi Classic */ -/*{"zh-Latn-pinyin", HB_TAG('Z','H','P',' ')},*/ /* Chinese Phonetic */ -}; - -typedef struct { - char language[11]; - hb_tag_t tag; -} LangTagLong; -static const LangTagLong ot_languages_zh[] = { - /* Store longest-first, if one is a prefix of another. */ - {"zh-cn", HB_TAG('Z','H','S',' ')}, /* Chinese (China) */ - {"zh-hk", HB_TAG('Z','H','H',' ')}, /* Chinese (Hong Kong) */ - {"zh-mo", HB_TAG('Z','H','H',' ')}, /* Chinese (Macao) */ - {"zh-sg", HB_TAG('Z','H','S',' ')}, /* Chinese (Singapore) */ - {"zh-tw", HB_TAG('Z','H','T',' ')}, /* Chinese (Taiwan) */ - {"zh-hans", HB_TAG('Z','H','S',' ')}, /* Chinese (Simplified) */ - {"zh-hant-hk",HB_TAG('Z','H','H',' ')}, /* Chinese (Hong Kong) */ - {"zh-hant-mo",HB_TAG('Z','H','H',' ')}, /* Chinese (Macao) */ - {"zh-hant", HB_TAG('Z','H','T',' ')}, /* Chinese (Traditional) */ -}; - static int lang_compare_first_component (const void *pa, const void *pb) @@ -895,6 +189,21 @@ lang_compare_first_component (const void *pa, return strncmp (a, b, MAX (da, db)); } +static bool +subtag_matches (const char *lang_str, + const char *limit, + const char *subtag) +{ + do { + const char *s = strstr (lang_str, subtag); + if (!s || s >= limit) + return false; + if (!ISALNUM (s[strlen (subtag)])) + return true; + lang_str = s + strlen (subtag); + } while (true); +} + static hb_bool_t lang_matches (const char *lang_str, const char *spec) { @@ -904,106 +213,187 @@ lang_matches (const char *lang_str, const char *spec) (lang_str[len] == '\0' || lang_str[len] == '-'); } +typedef struct { + char language[4]; + hb_tag_t tags[HB_OT_MAX_TAGS_PER_LANGUAGE]; +} LangTag; + +#include "hb-ot-tag-table.hh" + +/* The corresponding languages IDs for the following IDs are unclear, + * overlap, or are architecturally weird. Needs more research. */ + +/*{"??", {HB_TAG('B','C','R',' ')}},*/ /* Bible Cree */ +/*{"zh?", {HB_TAG('C','H','N',' ')}},*/ /* Chinese (seen in Microsoft fonts) */ +/*{"ar-Syrc?", {HB_TAG('G','A','R',' ')}},*/ /* Garshuni */ +/*{"??", {HB_TAG('N','G','R',' ')}},*/ /* Nagari */ +/*{"??", {HB_TAG('Y','I','C',' ')}},*/ /* Yi Classic */ +/*{"zh?", {HB_TAG('Z','H','P',' ')}},*/ /* Chinese Phonetic */ + hb_tag_t hb_ot_tag_from_language (hb_language_t language) { - const char *lang_str, *s; + unsigned int count = 1; + hb_tag_t tags[1]; + hb_ot_tags_from_script_and_language (HB_SCRIPT_UNKNOWN, language, nullptr, nullptr, &count, tags); + return count > 0 ? tags[0] : HB_OT_TAG_DEFAULT_LANGUAGE; +} - if (language == HB_LANGUAGE_INVALID) - return HB_OT_TAG_DEFAULT_LANGUAGE; +static void +hb_ot_tags_from_language (const char *lang_str, + const char *limit, + const char *private_use_subtag, + unsigned int *count, + hb_tag_t *tags) +{ + const char *s; - lang_str = hb_language_to_string (language); + /* Check for matches of multiple subtags. */ + if (hb_ot_tags_from_complex_language (lang_str, limit, count, tags)) + return; - s = strstr (lang_str, "x-hbot"); - if (s) { - char tag[4]; - int i; - s += 6; - for (i = 0; i < 4 && ISALNUM (s[i]); i++) - tag[i] = TOUPPER (s[i]); - if (i) { - for (; i < 4; i++) - tag[i] = ' '; - return HB_TAG (tag[0], tag[1], tag[2], tag[3]); + /* Find a language matching in the first component. */ + s = strchr (lang_str, '-'); + { + const LangTag *lang_tag; + if (s && limit - lang_str >= 6) + { + const char *extlang_end = strchr (s + 1, '-'); + /* If there is an extended language tag, use it. */ + if (3 == (extlang_end ? extlang_end - s - 1 : strlen (s + 1)) && + ISALPHA (s[1])) + lang_str = s + 1; + } + lang_tag = (LangTag *) bsearch (lang_str, ot_languages, + ARRAY_LENGTH (ot_languages), sizeof (LangTag), + lang_compare_first_component); + if (lang_tag) + { + unsigned int i; + for (i = 0; i < *count && lang_tag->tags[i] != HB_TAG_NONE; i++) + tags[i] = lang_tag->tags[i]; + *count = i; + return; } } - /* - * "fonipa" is a variant tag in BCP-47, meaning the International Phonetic Alphabet. - * It can be applied to any language. - */ - if (strstr (lang_str, "-fonipa")) { - return HB_TAG('I','P','P','H'); /* Phonetic transcription—IPA conventions */ - } - - /* - * "fonnapa" is a variant tag in BCP-47, meaning the North American Phonetic Alphabet - * also known as Americanist Phonetic Notation. It can be applied to any language. - */ - if (strstr (lang_str, "-fonnapa")) { - return HB_TAG('A','P','P','H'); /* Phonetic transcription—Americanist conventions */ + if (!s) + s = lang_str + strlen (lang_str); + if (s - lang_str == 3) { + /* Assume it's ISO-639-3 and upper-case and use it. */ + tags[0] = hb_tag_from_string (lang_str, s - lang_str) & ~0x20202000u; + *count = 1; + return; } - /* - * "Syre" is a BCP-47 script tag, meaning the Estrangela variant of the Syriac script. - * It can be applied to any language. - */ - if (strstr (lang_str, "-syre")) { - return HB_TAG('S','Y','R','E'); /* Estrangela Syriac */ - } + *count = 0; +} - /* - * "Syrj" is a BCP-47 script tag, meaning the Western variant of the Syriac script. - * It can be applied to any language. - */ - if (strstr (lang_str, "-syrj")) { - return HB_TAG('S','Y','R','J'); /* Western Syriac */ +static bool +parse_private_use_subtag (const char *private_use_subtag, + unsigned int *count, + hb_tag_t *tags, + const char *prefix, + unsigned char (*normalize) (unsigned char)) +{ + if (private_use_subtag && count && tags && *count) + { + const char *s = strstr (private_use_subtag, prefix); + if (s) + { + char tag[4]; + int i; + s += strlen (prefix); + for (i = 0; i < 4 && ISALNUM (s[i]); i++) + tag[i] = normalize (s[i]); + if (i) + { + for (; i < 4; i++) + tag[i] = ' '; + tags[0] = HB_TAG (tag[0], tag[1], tag[2], tag[3]); + if ((tags[0] & 0xDFDFDFDF) == HB_OT_TAG_DEFAULT_SCRIPT) + tags[0] ^= ~0xDFDFDFDF; + *count = 1; + return false; + } + } } + return true; +} - /* - * "Syrn" is a BCP-47 script tag, meaning the Eastern variant of the Syriac script. - * It can be applied to any language. - */ - if (strstr (lang_str, "-syrn")) { - return HB_TAG('S','Y','R','N'); /* Eastern Syriac */ - } +/** + * hb_ot_tags_from_script_and_language: + * @script: an #hb_script_t to convert. + * @language: an #hb_language_t to convert. + * @script_count: (allow-none): maximum number of script tags to retrieve (IN) + * and actual number of script tags retrieved (OUT) + * @script_tags: (out) (allow-none): array of size at least @script_count to store the + * script tag results + * @language_count: (allow-none): maximum number of language tags to retrieve + * (IN) and actual number of language tags retrieved (OUT) + * @language_tags: (out) (allow-none): array of size at least @language_count to store + * the language tag results + * + * Converts an #hb_script_t and an #hb_language_t to script and language tags. + * + * Since: 2.0.0 + **/ +void +hb_ot_tags_from_script_and_language (hb_script_t script, + hb_language_t language, + unsigned int *script_count /* IN/OUT */, + hb_tag_t *script_tags /* OUT */, + unsigned int *language_count /* IN/OUT */, + hb_tag_t *language_tags /* OUT */) +{ + bool needs_script = true; - /* Find a language matching in the first component */ + if (language == HB_LANGUAGE_INVALID) { - const LangTag *lang_tag; - lang_tag = (LangTag *) bsearch (lang_str, ot_languages, - ARRAY_LENGTH (ot_languages), sizeof (LangTag), - lang_compare_first_component); - if (lang_tag) - return lang_tag->tag; + if (language_count && language_tags && *language_count) + *language_count = 0; } - - /* Otherwise, check the Chinese ones */ - if (0 == lang_compare_first_component (lang_str, "zh")) + else { - unsigned int i; + const char *lang_str, *s, *limit, *private_use_subtag; + bool needs_language; - for (i = 0; i < ARRAY_LENGTH (ot_languages_zh); i++) + lang_str = hb_language_to_string (language); + limit = nullptr; + private_use_subtag = nullptr; + if (lang_str[0] == 'x' && lang_str[1] == '-') { - const LangTagLong *lang_tag; - lang_tag = &ot_languages_zh[i]; - if (lang_matches (lang_str, lang_tag->language)) - return lang_tag->tag; + private_use_subtag = lang_str; + } else { + for (s = lang_str + 1; *s; s++) + { + if (s[-1] == '-' && s[1] == '-') + { + if (s[0] == 'x') + { + private_use_subtag = s; + if (!limit) + limit = s - 1; + break; + } else if (!limit) + { + limit = s - 1; + } + } + } + if (!limit) + limit = s; } - /* Otherwise just return 'ZHS ' */ - return HB_TAG('Z','H','S',' '); - } + needs_script = parse_private_use_subtag (private_use_subtag, script_count, script_tags, "-hbsc", TOLOWER); + needs_language = parse_private_use_subtag (private_use_subtag, language_count, language_tags, "-hbot", TOUPPER); - s = strchr (lang_str, '-'); - if (!s) - s = lang_str + strlen (lang_str); - if (s - lang_str == 3) { - /* Assume it's ISO-639-3 and upper-case and use it. */ - return hb_tag_from_string (lang_str, s - lang_str) & ~0x20202000u; + if (needs_language && language_count && language_tags && *language_count) + hb_ot_tags_from_language (lang_str, limit, private_use_subtag, language_count, language_tags); } - return HB_OT_TAG_DEFAULT_LANGUAGE; + if (needs_script && script_count && script_tags && *script_count) + hb_ot_all_tags_from_script (script, script_count, script_tags); } /** @@ -1023,36 +413,16 @@ hb_ot_tag_to_language (hb_tag_t tag) if (tag == HB_OT_TAG_DEFAULT_LANGUAGE) return nullptr; - /* struct LangTag has only room for 3-letter language tags. */ - switch (tag) { - case HB_TAG('A','P','P','H'): /* Phonetic transcription—Americanist conventions */ - return hb_language_from_string ("und-fonnapa", -1); - case HB_TAG('I','P','P','H'): /* Phonetic transcription—IPA conventions */ - return hb_language_from_string ("und-fonipa", -1); - case HB_TAG('S','Y','R',' '): /* Syriac [macrolanguage] */ - return hb_language_from_string ("syr", -1); - case HB_TAG('S','Y','R','E'): /* Estrangela Syriac */ - return hb_language_from_string ("und-Syre", -1); - case HB_TAG('S','Y','R','J'): /* Western Syriac */ - return hb_language_from_string ("und-Syrj", -1); - case HB_TAG('S','Y','R','N'): /* Eastern Syriac */ - return hb_language_from_string ("und-Syrn", -1); + { + hb_language_t disambiguated_tag = hb_ot_ambiguous_tag_to_language (tag); + if (disambiguated_tag != HB_LANGUAGE_INVALID) + return disambiguated_tag; } for (i = 0; i < ARRAY_LENGTH (ot_languages); i++) - if (ot_languages[i].tag == tag) + if (ot_languages[i].tags[0] == tag) return hb_language_from_string (ot_languages[i].language, -1); - /* If tag starts with ZH, it's Chinese */ - if ((tag & 0xFFFF0000u) == 0x5A480000u) { - switch (tag) { - case HB_TAG('Z','H','H',' '): return hb_language_from_string ("zh-hk", -1); /* Hong Kong */ - case HB_TAG('Z','H','S',' '): return hb_language_from_string ("zh-Hans", -1); /* Simplified */ - case HB_TAG('Z','H','T',' '): return hb_language_from_string ("zh-Hant", -1); /* Traditional */ - default: break; /* Fall through */ - } - } - /* Else return a custom language in the form of "x-hbotABCD" */ { unsigned char buf[11] = "x-hbot"; @@ -1067,6 +437,71 @@ hb_ot_tag_to_language (hb_tag_t tag) } } +/** + * hb_ot_tags_to_script_and_language: + * @script_tag: a script tag + * @language_tag: a language tag + * @script: (allow-none): the #hb_script_t corresponding to @script_tag (OUT). + * @language: (allow-none): the #hb_language_t corresponding to @script_tag and + * @language_tag (OUT). + * + * Converts a script tag and a language tag to an #hb_script_t and an + * #hb_language_t. + * + * Since: 2.0.0 + **/ +void +hb_ot_tags_to_script_and_language (hb_tag_t script_tag, + hb_tag_t language_tag, + hb_script_t *script /* OUT */, + hb_language_t *language /* OUT */) +{ + hb_script_t script_out = hb_ot_tag_to_script (script_tag); + if (script) + *script = script_out; + if (language) + { + unsigned int script_count = 1; + hb_tag_t primary_script_tag[1]; + hb_ot_tags_from_script_and_language (script_out, + HB_LANGUAGE_INVALID, + &script_count, + primary_script_tag, + nullptr, nullptr); + *language = hb_ot_tag_to_language (language_tag); + if (script_count == 0 || primary_script_tag[0] != script_tag) + { + unsigned char *buf; + const char *lang_str = hb_language_to_string (*language); + size_t len = strlen (lang_str); + buf = (unsigned char *) malloc (len + 11); + if (unlikely (!buf)) + { + *language = nullptr; + } + else + { + memcpy (buf, lang_str, len); + if (lang_str[0] != 'x' || lang_str[1] != '-') { + buf[len++] = '-'; + buf[len++] = 'x'; + } + buf[len++] = '-'; + buf[len++] = 'h'; + buf[len++] = 'b'; + buf[len++] = 's'; + buf[len++] = 'c'; + buf[len++] = script_tag >> 24; + buf[len++] = (script_tag >> 16) & 0xFF; + buf[len++] = (script_tag >> 8) & 0xFF; + buf[len++] = script_tag & 0xFF; + *language = hb_language_from_string ((char *) buf, len); + free (buf); + } + } + } +} + #ifdef MAIN static inline void test_langs_sorted (void) diff --git a/src/hb-ot-tag.h b/src/hb-ot-tag.h index 54fb747f5..33a4dbdbc 100644 --- a/src/hb-ot-tag.h +++ b/src/hb-ot-tag.h @@ -39,20 +39,39 @@ HB_BEGIN_DECLS #define HB_OT_TAG_DEFAULT_SCRIPT HB_TAG ('D', 'F', 'L', 'T') #define HB_OT_TAG_DEFAULT_LANGUAGE HB_TAG ('d', 'f', 'l', 't') +/** + * HB_OT_MAX_TAGS_PER_SCRIPT: + * + * Since: 2.0.0 + **/ +#define HB_OT_MAX_TAGS_PER_SCRIPT 3u +/** + * HB_OT_MAX_TAGS_PER_LANGUAGE: + * + * Since: 2.0.0 + **/ +#define HB_OT_MAX_TAGS_PER_LANGUAGE 3u + HB_EXTERN void -hb_ot_tags_from_script (hb_script_t script, - hb_tag_t *script_tag_1, - hb_tag_t *script_tag_2); +hb_ot_tags_from_script_and_language (hb_script_t script, + hb_language_t language, + unsigned int *script_count /* IN/OUT */, + hb_tag_t *script_tags /* OUT */, + unsigned int *language_count /* IN/OUT */, + hb_tag_t *language_tags /* OUT */); HB_EXTERN hb_script_t hb_ot_tag_to_script (hb_tag_t tag); -HB_EXTERN hb_tag_t -hb_ot_tag_from_language (hb_language_t language); - HB_EXTERN hb_language_t hb_ot_tag_to_language (hb_tag_t tag); +HB_EXTERN void +hb_ot_tags_to_script_and_language (hb_tag_t script_tag, + hb_tag_t language_tag, + hb_script_t *script /* OUT */, + hb_language_t *language /* OUT */); + HB_END_DECLS diff --git a/src/hb-ot-var-avar-table.hh b/src/hb-ot-var-avar-table.hh index ad063d32d..d100ca21e 100644 --- a/src/hb-ot-var-avar-table.hh +++ b/src/hb-ot-var-avar-table.hh @@ -27,7 +27,7 @@ #ifndef HB_OT_VAR_AVAR_TABLE_HH #define HB_OT_VAR_AVAR_TABLE_HH -#include "hb-open-type-private.hh" +#include "hb-open-type.hh" /* * avar -- Axis Variations @@ -93,6 +93,7 @@ struct SegmentMaps : ArrayOf<AxisValueMap> (value - arrayZ[i-1].fromCoord) + denom/2) / denom; } + public: DEFINE_SIZE_ARRAY (2, arrayZ); }; @@ -108,7 +109,7 @@ struct avar c->check_struct (this)))) return_trace (false); - const SegmentMaps *map = axisSegmentMapsZ; + const SegmentMaps *map = axisSegmentMapsZ.arrayZ; unsigned int count = axisCount; for (unsigned int i = 0; i < count; i++) { @@ -124,7 +125,7 @@ struct avar { unsigned int count = MIN<unsigned int> (coords_length, axisCount); - const SegmentMaps *map = axisSegmentMapsZ; + const SegmentMaps *map = axisSegmentMapsZ.arrayZ; for (unsigned int i = 0; i < count; i++) { coords[i] = map->map (coords[i]); @@ -139,7 +140,8 @@ struct avar HBUINT16 axisCount; /* The number of variation axes in the font. This * must be the same number as axisCount in the * 'fvar' table. */ - SegmentMaps axisSegmentMapsZ[VAR]; + UnsizedArrayOf<SegmentMaps> + axisSegmentMapsZ; public: DEFINE_SIZE_MIN (8); diff --git a/src/hb-ot-var-fvar-table.hh b/src/hb-ot-var-fvar-table.hh index 101476ed3..96c39c109 100644 --- a/src/hb-ot-var-fvar-table.hh +++ b/src/hb-ot-var-fvar-table.hh @@ -27,7 +27,7 @@ #ifndef HB_OT_VAR_FVAR_TABLE_HH #define HB_OT_VAR_FVAR_TABLE_HH -#include "hb-open-type-private.hh" +#include "hb-open-type.hh" /* * fvar -- Font Variations @@ -46,20 +46,21 @@ struct InstanceRecord { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && - c->check_array (coordinates, coordinates[0].static_size, axis_count)); + c->check_array (coordinatesZ.arrayZ, axis_count)); } protected: NameID subfamilyNameID;/* The name ID for entries in the 'name' table * that provide subfamily names for this instance. */ HBUINT16 reserved; /* Reserved for future use — set to 0. */ - Fixed coordinates[VAR];/* The coordinates array for this instance. */ + UnsizedArrayOf<Fixed> + coordinatesZ; /* The coordinates array for this instance. */ //NameID postScriptNameIDX;/*Optional. The name ID for entries in the 'name' // * table that provide PostScript names for this // * instance. */ public: - DEFINE_SIZE_ARRAY (4, coordinates); + DEFINE_SIZE_ARRAY (4, coordinatesZ); }; struct AxisRecord @@ -176,7 +177,7 @@ struct fvar v = (v - axis.default_value) / (axis.default_value - axis.min_value); else v = (v - axis.default_value) / (axis.max_value - axis.default_value); - return (int) (v * 16384. + (v >= 0. ? .5 : -.5)); + return (int) (v * 16384.f + (v >= 0.f ? .5f : -.5f)); } protected: diff --git a/src/hb-ot-var-hvar-table.hh b/src/hb-ot-var-hvar-table.hh index 2b384db71..66e086e1d 100644 --- a/src/hb-ot-var-hvar-table.hh +++ b/src/hb-ot-var-hvar-table.hh @@ -27,7 +27,7 @@ #ifndef HB_OT_VAR_HVAR_TABLE_HH #define HB_OT_VAR_HVAR_TABLE_HH -#include "hb-ot-layout-common-private.hh" +#include "hb-ot-layout-common.hh" namespace OT { @@ -39,7 +39,7 @@ struct DeltaSetIndexMap { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && - c->check_array (mapData, get_width (), mapCount)); + c->check_array (mapDataZ.arrayZ, mapCount, get_width ())); } unsigned int map (unsigned int v) const /* Returns 16.16 outer.inner. */ @@ -55,7 +55,7 @@ struct DeltaSetIndexMap unsigned int u = 0; { /* Fetch it. */ unsigned int w = get_width (); - const HBUINT8 *p = mapData + w * v; + const HBUINT8 *p = mapDataZ.arrayZ + w * v; for (; w; w--) u = (u << 8) + *p++; } @@ -81,10 +81,11 @@ struct DeltaSetIndexMap HBUINT16 format; /* A packed field that describes the compressed * representation of delta-set indices. */ HBUINT16 mapCount; /* The number of mapping entries. */ - HBUINT8 mapData[VAR]; /* The delta-set index mapping data. */ + UnsizedArrayOf<HBUINT8> + mapDataZ; /* The delta-set index mapping data. */ public: - DEFINE_SIZE_ARRAY (4, mapData); + DEFINE_SIZE_ARRAY (4, mapDataZ); }; @@ -114,7 +115,7 @@ struct HVARVVAR } inline float get_advance_var (hb_codepoint_t glyph, - int *coords, unsigned int coord_count) const + const int *coords, unsigned int coord_count) const { unsigned int varidx = (this+advMap).map (glyph); return (this+varStore).get_delta (varidx, coords, coord_count); diff --git a/src/hb-ot-var-mvar-table.hh b/src/hb-ot-var-mvar-table.hh index dfde782f6..5d6b55954 100644 --- a/src/hb-ot-var-mvar-table.hh +++ b/src/hb-ot-var-mvar-table.hh @@ -27,7 +27,7 @@ #ifndef HB_OT_VAR_MVAR_TABLE_HH #define HB_OT_VAR_MVAR_TABLE_HH -#include "hb-ot-layout-common-private.hh" +#include "hb-ot-layout-common.hh" namespace OT { @@ -68,14 +68,14 @@ struct MVAR c->check_struct (this) && valueRecordSize >= VariationValueRecord::static_size && varStore.sanitize (c, this) && - c->check_array (values, valueRecordSize, valueRecordCount)); + c->check_array (valuesZ.arrayZ, valueRecordCount, valueRecordSize)); } inline float get_var (hb_tag_t tag, - int *coords, unsigned int coord_count) const + const int *coords, unsigned int coord_count) const { const VariationValueRecord *record; - record = (VariationValueRecord *) bsearch (&tag, values, + record = (VariationValueRecord *) bsearch (&tag, valuesZ.arrayZ, valueRecordCount, valueRecordSize, tag_compare); if (!record) @@ -101,11 +101,12 @@ protected: HBUINT16 valueRecordCount;/* The number of value records — may be zero. */ OffsetTo<VariationStore> varStore; /* Offset to item variation store table. */ - HBUINT8 values[VAR]; /* Array of value records. The records must be + UnsizedArrayOf<HBUINT8> + valuesZ; /* Array of value records. The records must be * in binary order of their valueTag field. */ public: - DEFINE_SIZE_ARRAY (12, values); + DEFINE_SIZE_ARRAY (12, valuesZ); }; } /* namespace OT */ diff --git a/src/hb-ot-var.cc b/src/hb-ot-var.cc index 6081ddfc3..472ee8452 100644 --- a/src/hb-ot-var.cc +++ b/src/hb-ot-var.cc @@ -24,9 +24,9 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-open-type-private.hh" +#include "hb-open-type.hh" -#include "hb-ot-layout-private.hh" +#include "hb-ot-face.hh" #include "hb-ot-var-avar-table.hh" #include "hb-ot-var-fvar-table.hh" #include "hb-ot-var-mvar-table.hh" @@ -40,15 +40,15 @@ static inline const OT::fvar& _get_fvar (hb_face_t *face) { if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::fvar); - hb_ot_layout_t * layout = hb_ot_layout_from_face (face); - return *(layout->table.fvar.get ()); + hb_ot_face_data_t *layout = hb_ot_face_data (face); + return *(layout->fvar.get ()); } static inline const OT::avar& _get_avar (hb_face_t *face) { if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::avar); - hb_ot_layout_t * layout = hb_ot_layout_from_face (face); - return *(layout->table.avar.get ()); + hb_ot_face_data_t *layout = hb_ot_face_data (face); + return *(layout->avar.get ()); } /** diff --git a/src/hb-ot.h b/src/hb-ot.h index 2120a3efa..4b6e3cf74 100644 --- a/src/hb-ot.h +++ b/src/hb-ot.h @@ -33,6 +33,7 @@ #include "hb-ot-font.h" #include "hb-ot-layout.h" #include "hb-ot-math.h" +#include "hb-ot-name.h" #include "hb-ot-tag.h" #include "hb-ot-shape.h" #include "hb-ot-var.h" diff --git a/src/hb-set-digest-private.hh b/src/hb-set-digest.hh index e099a8264..0f9329f62 100644 --- a/src/hb-set-digest-private.hh +++ b/src/hb-set-digest.hh @@ -24,10 +24,10 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_SET_DIGEST_PRIVATE_HH -#define HB_SET_DIGEST_PRIVATE_HH +#ifndef HB_SET_DIGEST_HH +#define HB_SET_DIGEST_HH -#include "hb-private.hh" +#include "hb.hh" /* * The set digests here implement various "filters" that support @@ -50,8 +50,8 @@ struct hb_set_digest_lowest_bits_t { ASSERT_POD (); - static const unsigned int mask_bytes = sizeof (mask_t); - static const unsigned int mask_bits = sizeof (mask_t) * 8; + enum { mask_bytes = sizeof (mask_t) }; + enum { mask_bits = sizeof (mask_t) * 8 }; static const unsigned int num_bits = 0 + (mask_bytes >= 1 ? 3 : 0) + (mask_bytes >= 2 ? 1 : 0) @@ -176,4 +176,4 @@ typedef hb_set_digest_combiner_t > hb_set_digest_t; -#endif /* HB_SET_DIGEST_PRIVATE_HH */ +#endif /* HB_SET_DIGEST_HH */ diff --git a/src/hb-set.cc b/src/hb-set.cc index 25027e6c2..09dc4b483 100644 --- a/src/hb-set.cc +++ b/src/hb-set.cc @@ -24,7 +24,7 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-set-private.hh" +#include "hb-set.hh" /* Public API */ diff --git a/src/hb-set-private.hh b/src/hb-set.hh index 032ddb1ee..7ca329761 100644 --- a/src/hb-set-private.hh +++ b/src/hb-set.hh @@ -24,10 +24,10 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_SET_PRIVATE_HH -#define HB_SET_PRIVATE_HH +#ifndef HB_SET_HH +#define HB_SET_HH -#include "hb-private.hh" +#include "hb.hh" /* @@ -157,7 +157,7 @@ struct hb_set_t } typedef unsigned long long elt_t; - static const unsigned int PAGE_BITS = 512; + enum { PAGE_BITS = 512 }; static_assert ((PAGE_BITS & ((PAGE_BITS) - 1)) == 0, ""); static inline unsigned int elt_get_min (const elt_t &elt) { return hb_ctz (elt); } @@ -165,11 +165,11 @@ struct hb_set_t typedef hb_vector_size_t<elt_t, PAGE_BITS / 8> vector_t; - static const unsigned int ELT_BITS = sizeof (elt_t) * 8; - static const unsigned int ELT_MASK = ELT_BITS - 1; - static const unsigned int BITS = sizeof (vector_t) * 8; - static const unsigned int MASK = BITS - 1; - static_assert (PAGE_BITS == BITS, ""); + enum { ELT_BITS = sizeof (elt_t) * 8 }; + enum { ELT_MASK = ELT_BITS - 1 }; + enum { BITS = sizeof (vector_t) * 8 }; + enum { MASK = BITS - 1 }; + static_assert ((unsigned) PAGE_BITS == (unsigned) BITS, ""); elt_t &elt (hb_codepoint_t g) { return v[(g & MASK) / ELT_BITS]; } elt_t const &elt (hb_codepoint_t g) const { return v[(g & MASK) / ELT_BITS]; } @@ -368,8 +368,8 @@ struct hb_set_t if (!resize (count)) return; population = other->population; - memcpy (pages.arrayZ, other->pages.arrayZ, count * sizeof (pages.arrayZ[0])); - memcpy (page_map.arrayZ, other->page_map.arrayZ, count * sizeof (page_map.arrayZ[0])); + memcpy (pages.arrayZ(), other->pages.arrayZ(), count * sizeof (pages.arrayZ()[0])); + memcpy (page_map.arrayZ(), other->page_map.arrayZ(), count * sizeof (page_map.arrayZ()[0])); } inline bool is_equal (const hb_set_t *other) const @@ -697,4 +697,4 @@ struct hb_set_t }; -#endif /* HB_SET_PRIVATE_HH */ +#endif /* HB_SET_HH */ diff --git a/src/hb-shape-plan.cc b/src/hb-shape-plan.cc index 0d61d9e1f..b2289f869 100644 --- a/src/hb-shape-plan.cc +++ b/src/hb-shape-plan.cc @@ -24,11 +24,11 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-private.hh" -#include "hb-shape-plan-private.hh" -#include "hb-shaper-private.hh" -#include "hb-font-private.hh" -#include "hb-buffer-private.hh" +#include "hb.hh" +#include "hb-shape-plan.hh" +#include "hb-shaper.hh" +#include "hb-font.hh" +#include "hb-buffer.hh" static void @@ -64,7 +64,7 @@ hb_shape_plan_plan (hb_shape_plan_t *shape_plan, if (likely (!shaper_list)) { for (unsigned int i = 0; i < HB_SHAPERS_COUNT; i++) - if (0) + if (false) ; #define HB_SHAPER_IMPLEMENT(shaper) \ else if (shapers[i].func == _hb_##shaper##_shape) \ @@ -73,7 +73,7 @@ hb_shape_plan_plan (hb_shape_plan_t *shape_plan, #undef HB_SHAPER_IMPLEMENT } else { for (; *shaper_list; shaper_list++) - if (0) + if (false) ; #define HB_SHAPER_IMPLEMENT(shaper) \ else if (0 == strcmp (*shaper_list, #shaper)) \ @@ -346,7 +346,7 @@ hb_shape_plan_execute (hb_shape_plan_t *shape_plan, _hb_##shaper##_shape (shape_plan, font, buffer, features, num_features); \ } HB_STMT_END - if (0) + if (false) ; #define HB_SHAPER_IMPLEMENT(shaper) \ else if (shape_plan->shaper_func == _hb_##shaper##_shape) \ @@ -501,7 +501,7 @@ hb_shape_plan_create_cached2 (hb_face_t *face, /* Choose shaper. Adapted from hb_shape_plan_plan(). * Must choose shaper exactly the same way as that function. */ for (const char * const *shaper_item = shaper_list; *shaper_item; shaper_item++) - if (0) + if (false) ; #define HB_SHAPER_IMPLEMENT(shaper) \ else if (0 == strcmp (*shaper_item, #shaper) && \ diff --git a/src/hb-shape-plan-private.hh b/src/hb-shape-plan.hh index 7d020ff16..bf82b912b 100644 --- a/src/hb-shape-plan-private.hh +++ b/src/hb-shape-plan.hh @@ -24,11 +24,11 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_SHAPE_PLAN_PRIVATE_HH -#define HB_SHAPE_PLAN_PRIVATE_HH +#ifndef HB_SHAPE_PLAN_HH +#define HB_SHAPE_PLAN_HH -#include "hb-private.hh" -#include "hb-shaper-private.hh" +#include "hb.hh" +#include "hb-shaper.hh" struct hb_shape_plan_t @@ -64,4 +64,4 @@ DECLARE_NULL_INSTANCE (hb_shape_plan_t); #undef HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS -#endif /* HB_SHAPE_PLAN_PRIVATE_HH */ +#endif /* HB_SHAPE_PLAN_HH */ diff --git a/src/hb-shape.cc b/src/hb-shape.cc index 3c2e6c4a9..e8eeff5b3 100644 --- a/src/hb-shape.cc +++ b/src/hb-shape.cc @@ -26,13 +26,13 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-private.hh" +#include "hb.hh" -#include "hb-shaper-private.hh" -#include "hb-shape-plan-private.hh" -#include "hb-buffer-private.hh" -#include "hb-font-private.hh" -#include "hb-machinery-private.hh" +#include "hb-shaper.hh" +#include "hb-shape-plan.hh" +#include "hb-buffer.hh" +#include "hb-font.hh" +#include "hb-machinery.hh" /** * SECTION:hb-shape @@ -46,8 +46,10 @@ * contains the output glyphs and their positions. **/ - +#ifdef HB_USE_ATEXIT static void free_static_shaper_list (void); +#endif + static const char *nil_shaper_list[] = {nullptr}; static struct hb_shaper_list_lazy_loader_t : hb_lazy_loader_t<const char *, diff --git a/src/hb-shaper-impl-private.hh b/src/hb-shaper-impl.hh index 4a10279c7..d40cb085a 100644 --- a/src/hb-shaper-impl-private.hh +++ b/src/hb-shaper-impl.hh @@ -24,15 +24,15 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_SHAPER_IMPL_PRIVATE_HH -#define HB_SHAPER_IMPL_PRIVATE_HH +#ifndef HB_SHAPER_IMPL_HH +#define HB_SHAPER_IMPL_HH -#include "hb-private.hh" +#include "hb.hh" -#include "hb-shaper-private.hh" -#include "hb-shape-plan-private.hh" -#include "hb-font-private.hh" -#include "hb-buffer-private.hh" +#include "hb-shaper.hh" +#include "hb-shape-plan.hh" +#include "hb-font.hh" +#include "hb-buffer.hh" #ifdef HB_SHAPER @@ -40,4 +40,4 @@ #endif -#endif /* HB_SHAPER_IMPL_PRIVATE_HH */ +#endif /* HB_SHAPER_IMPL_HH */ diff --git a/src/hb-shaper-list.hh b/src/hb-shaper-list.hh index b0835d31a..1fdb64810 100644 --- a/src/hb-shaper-list.hh +++ b/src/hb-shaper-list.hh @@ -39,9 +39,7 @@ HB_SHAPER_IMPLEMENT (graphite2) HB_SHAPER_IMPLEMENT (coretext_aat) #endif -#ifdef HAVE_OT HB_SHAPER_IMPLEMENT (ot) /* <--- This is our main OpenType shaper. */ -#endif #ifdef HAVE_UNISCRIBE HB_SHAPER_IMPLEMENT (uniscribe) diff --git a/src/hb-shaper.cc b/src/hb-shaper.cc index e423f2557..52418c082 100644 --- a/src/hb-shaper.cc +++ b/src/hb-shaper.cc @@ -24,9 +24,9 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-private.hh" -#include "hb-shaper-private.hh" -#include "hb-machinery-private.hh" +#include "hb.hh" +#include "hb-shaper.hh" +#include "hb-machinery.hh" static const hb_shaper_pair_t all_shapers[] = { @@ -35,8 +35,9 @@ static const hb_shaper_pair_t all_shapers[] = { #undef HB_SHAPER_IMPLEMENT }; - +#ifdef HB_USE_ATEXIT static void free_static_shapers (void); +#endif static struct hb_shapers_lazy_loader_t : hb_lazy_loader_t<const hb_shaper_pair_t, hb_shapers_lazy_loader_t> diff --git a/src/hb-shaper-private.hh b/src/hb-shaper.hh index fb04bbc3c..361165e4f 100644 --- a/src/hb-shaper-private.hh +++ b/src/hb-shaper.hh @@ -24,10 +24,10 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_SHAPER_PRIVATE_HH -#define HB_SHAPER_PRIVATE_HH +#ifndef HB_SHAPER_HH +#define HB_SHAPER_HH -#include "hb-private.hh" +#include "hb.hh" typedef hb_bool_t hb_shape_func_t (hb_shape_plan_t *shape_plan, hb_font_t *font, @@ -131,4 +131,4 @@ struct hb_shaper_data_t { #define HB_SHAPERS_COUNT (sizeof (hb_shaper_data_t) / sizeof (void *)) -#endif /* HB_SHAPER_PRIVATE_HH */ +#endif /* HB_SHAPER_HH */ diff --git a/src/hb-static.cc b/src/hb-static.cc index ddecbba11..e5507960d 100644 --- a/src/hb-static.cc +++ b/src/hb-static.cc @@ -24,12 +24,14 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-private.hh" +#include "hb.hh" -#include "hb-open-type-private.hh" -#include "hb-ot-layout-common-private.hh" +#include "hb-open-type.hh" +#include "hb-ot-layout-common.hh" +#include "hb-aat-layout-ankr-table.hh" /* I don't even want to know why... */ +#include "hb-aat-layout-common.hh" -#include "hb-face-private.hh" +#include "hb-face.hh" #include "hb-ot-head-table.hh" #include "hb-ot-maxp-table.hh" @@ -41,6 +43,8 @@ hb_vector_size_impl_t const _hb_NullPool[(HB_NULL_POOL_SIZE + sizeof (hb_vector_ DEFINE_NULL_NAMESPACE_BYTES (OT, Index) = {0xFF,0xFF}; DEFINE_NULL_NAMESPACE_BYTES (OT, LangSys) = {0x00,0x00, 0xFF,0xFF, 0x00,0x00}; DEFINE_NULL_NAMESPACE_BYTES (OT, RangeRecord) = {0x00,0x01, 0x00,0x00, 0x00, 0x00}; +/* Hand-coded because Lookup is a template. Sad. */ +const unsigned char _hb_Null_AAT_Lookup[2] = {0xFF, 0xFF}; void diff --git a/src/hb-string-array.hh b/src/hb-string-array.hh index 679841c87..c4cf666d7 100644 --- a/src/hb-string-array.hh +++ b/src/hb-string-array.hh @@ -29,7 +29,7 @@ #define HB_STRING_ARRAY_HH #endif -#include "hb-private.hh" +#include "hb.hh" /* Based on Bruno Haible's code in Appendix B of Ulrich Drepper's dsohowto.pdf: * https://software.intel.com/sites/default/files/m/a/1/e/dsohowto.pdf */ diff --git a/src/hb-subset-glyf.cc b/src/hb-subset-glyf.cc index 36af3beae..499380a97 100644 --- a/src/hb-subset-glyf.cc +++ b/src/hb-subset-glyf.cc @@ -24,11 +24,10 @@ * Google Author(s): Garret Rieger, Roderick Sheeter */ -#include "hb-open-type-private.hh" +#include "hb-open-type.hh" #include "hb-ot-glyf-table.hh" #include "hb-set.h" #include "hb-subset-glyf.hh" -#include "hb-subset-plan.hh" static bool _calculate_glyf_and_loca_prime_size (const OT::glyf::accelerator_t &glyf, diff --git a/src/hb-subset-glyf.hh b/src/hb-subset-glyf.hh index 99b76db9b..3109ecb64 100644 --- a/src/hb-subset-glyf.hh +++ b/src/hb-subset-glyf.hh @@ -27,9 +27,9 @@ #ifndef HB_SUBSET_GLYF_HH #define HB_SUBSET_GLYF_HH -#include "hb-private.hh" +#include "hb.hh" -#include "hb-subset-plan.hh" +#include "hb-subset.hh" HB_INTERNAL bool hb_subset_glyf_and_loca (hb_subset_plan_t *plan, diff --git a/src/hb-subset-input.cc b/src/hb-subset-input.cc index 74470fd1f..d59b5bae0 100644 --- a/src/hb-subset-input.cc +++ b/src/hb-subset-input.cc @@ -24,8 +24,8 @@ * Google Author(s): Garret Rieger, Rod Sheeter, Behdad Esfahbod */ -#include "hb-subset-private.hh" -#include "hb-set-private.hh" +#include "hb-subset.hh" +#include "hb-set.hh" /** * hb_subset_input_create_or_fail: @@ -44,7 +44,7 @@ hb_subset_input_create_or_fail (void) input->unicodes = hb_set_create (); input->glyphs = hb_set_create (); - input->drop_ot_layout = true; + input->drop_layout = true; return input; } @@ -106,30 +106,28 @@ hb_subset_input_glyph_set (hb_subset_input_t *subset_input) return subset_input->glyphs; } -/** - * hb_subset_input_drop_hints: - * @subset_input: a subset_input. - * - * Since: 1.8.0 - **/ -HB_EXTERN hb_bool_t * -hb_subset_input_drop_hints (hb_subset_input_t *subset_input) +HB_EXTERN void +hb_subset_input_set_drop_hints (hb_subset_input_t *subset_input, + hb_bool_t drop_hints) { - return &subset_input->drop_hints; + subset_input->drop_hints = drop_hints; } -/** - * hb_subset_input_drop_ot_layout: - * @subset_input: a subset_input. - * - * If enabled ot layout tables will be dropped as part of - * the subsetting operation. Currently this defaults to - * true. - * - * Since: REPLACEME - **/ -HB_EXTERN hb_bool_t * -hb_subset_input_drop_ot_layout (hb_subset_input_t *subset_input) +HB_EXTERN hb_bool_t +hb_subset_input_get_drop_hints (hb_subset_input_t *subset_input) +{ + return subset_input->drop_hints; +} + +HB_EXTERN void +hb_subset_input_set_drop_layout (hb_subset_input_t *subset_input, + hb_bool_t drop_layout) +{ + subset_input->drop_layout = drop_layout; +} + +HB_EXTERN hb_bool_t +hb_subset_input_get_drop_layout (hb_subset_input_t *subset_input) { - return &subset_input->drop_ot_layout; + return subset_input->drop_layout; } diff --git a/src/hb-subset-private.hh b/src/hb-subset-input.hh index 6b2b207ff..9fc86154e 100644 --- a/src/hb-subset-private.hh +++ b/src/hb-subset-input.hh @@ -24,27 +24,26 @@ * Google Author(s): Garret Rieger, Roderick Sheeter */ -#ifndef HB_SUBSET_PRIVATE_HH -#define HB_SUBSET_PRIVATE_HH +#ifndef HB_SUBSET_INPUT_HH +#define HB_SUBSET_INPUT_HH -#include "hb-private.hh" +#include "hb.hh" #include "hb-subset.h" -#include "hb-font-private.hh" +#include "hb-font.hh" -typedef struct hb_subset_face_data_t hb_subset_face_data_t; - -struct hb_subset_input_t { +struct hb_subset_input_t +{ hb_object_header_t header; ASSERT_POD (); hb_set_t *unicodes; hb_set_t *glyphs; - hb_bool_t drop_hints; - hb_bool_t drop_ot_layout; + bool drop_hints : 1; + bool drop_layout : 1; /* TODO * * features @@ -54,10 +53,5 @@ struct hb_subset_input_t { */ }; -HB_INTERNAL hb_face_t * -hb_subset_face_create (void); - -HB_INTERNAL hb_bool_t -hb_subset_face_add_table (hb_face_t *face, hb_tag_t tag, hb_blob_t *blob); -#endif /* HB_SUBSET_PRIVATE_HH */ +#endif /* HB_SUBSET_INPUT_HH */ diff --git a/src/hb-subset-plan.cc b/src/hb-subset-plan.cc index 125668272..057006039 100644 --- a/src/hb-subset-plan.cc +++ b/src/hb-subset-plan.cc @@ -24,11 +24,10 @@ * Google Author(s): Garret Rieger, Roderick Sheeter */ -#include "hb-map-private.hh" -#include "hb-subset-private.hh" -#include "hb-set-private.hh" - #include "hb-subset-plan.hh" +#include "hb-map.hh" +#include "hb-set.hh" + #include "hb-ot-cmap-table.hh" #include "hb-ot-glyf-table.hh" @@ -69,7 +68,7 @@ _gsub_closure (hb_face_t *face, hb_set_t *gids_to_retain) } -static void +static hb_set_t * _populate_gids_to_retain (hb_face_t *face, const hb_set_t *unicodes, bool close_over_gsub, @@ -118,9 +117,10 @@ _populate_gids_to_retain (hb_face_t *face, while (all_gids_to_retain->next (&gid)) glyphs->push (gid); - hb_set_destroy (all_gids_to_retain); glyf.fini (); cmap.fini (); + + return all_gids_to_retain; } static void @@ -135,7 +135,7 @@ _create_old_gid_to_new_gid_map (const hb_vector_t<hb_codepoint_t> &glyphs, /** * hb_subset_plan_create: * Computes a plan for subsetting the supplied face according - * to a provide profile and input. The plan describes + * to a provided input. The plan describes * which tables and glyphs should be retained. * * Return value: New subset plan. @@ -144,26 +144,24 @@ _create_old_gid_to_new_gid_map (const hb_vector_t<hb_codepoint_t> &glyphs, **/ hb_subset_plan_t * hb_subset_plan_create (hb_face_t *face, - hb_subset_profile_t *profile, hb_subset_input_t *input) { hb_subset_plan_t *plan = hb_object_create<hb_subset_plan_t> (); plan->drop_hints = input->drop_hints; - plan->drop_ot_layout = input->drop_ot_layout; + plan->drop_layout = input->drop_layout; plan->unicodes = hb_set_create(); plan->glyphs.init(); plan->source = hb_face_reference (face); - plan->dest = hb_subset_face_create (); + plan->dest = hb_face_builder_create (); plan->codepoint_to_glyph = hb_map_create(); plan->glyph_map = hb_map_create(); - - _populate_gids_to_retain (face, - input->unicodes, - !plan->drop_ot_layout, - plan->unicodes, - plan->codepoint_to_glyph, - &plan->glyphs); + plan->glyphset = _populate_gids_to_retain (face, + input->unicodes, + !plan->drop_layout, + plan->unicodes, + plan->codepoint_to_glyph, + &plan->glyphs); _create_old_gid_to_new_gid_map (plan->glyphs, plan->glyph_map); @@ -186,6 +184,7 @@ hb_subset_plan_destroy (hb_subset_plan_t *plan) hb_face_destroy (plan->dest); hb_map_destroy (plan->codepoint_to_glyph); hb_map_destroy (plan->glyph_map); + hb_set_destroy (plan->glyphset); free (plan); } diff --git a/src/hb-subset-plan.hh b/src/hb-subset-plan.hh index 7501294d7..c2c484a5b 100644 --- a/src/hb-subset-plan.hh +++ b/src/hb-subset-plan.hh @@ -27,27 +27,26 @@ #ifndef HB_SUBSET_PLAN_HH #define HB_SUBSET_PLAN_HH -#include "hb-private.hh" +#include "hb.hh" #include "hb-subset.h" -#include "hb-subset-private.hh" +#include "hb-subset-input.hh" -#include "hb-map-private.hh" +#include "hb-map.hh" struct hb_subset_plan_t { hb_object_header_t header; ASSERT_POD (); - hb_bool_t drop_hints; - hb_bool_t drop_ot_layout; + bool drop_hints : 1; + bool drop_layout : 1; // For each cp that we'd like to retain maps to the corresponding gid. hb_set_t *unicodes; - // This list contains the complete set of glyphs to retain and may contain - // more glyphs then the lists above. hb_vector_t<hb_codepoint_t> glyphs; + hb_set_t *glyphset; hb_map_t *codepoint_to_glyph; hb_map_t *glyph_map; @@ -56,7 +55,7 @@ struct hb_subset_plan_t hb_face_t *source; hb_face_t *dest; - inline hb_bool_t + inline bool new_gid_for_codepoint (hb_codepoint_t codepoint, hb_codepoint_t *new_gid) const { @@ -67,7 +66,7 @@ struct hb_subset_plan_t return new_gid_for_old_gid (old_gid, new_gid); } - inline hb_bool_t + inline bool new_gid_for_old_gid (hb_codepoint_t old_gid, hb_codepoint_t *new_gid) const { @@ -79,7 +78,7 @@ struct hb_subset_plan_t return true; } - inline hb_bool_t + inline bool add_table (hb_tag_t tag, hb_blob_t *contents) { @@ -89,7 +88,7 @@ struct hb_subset_plan_t hb_blob_get_length (contents), hb_blob_get_length (source_blob)); hb_blob_destroy (source_blob); - return hb_subset_face_add_table(dest, tag, contents); + return hb_face_builder_add_table (dest, tag, contents); } }; @@ -97,7 +96,6 @@ typedef struct hb_subset_plan_t hb_subset_plan_t; HB_INTERNAL hb_subset_plan_t * hb_subset_plan_create (hb_face_t *face, - hb_subset_profile_t *profile, hb_subset_input_t *input); HB_INTERNAL void diff --git a/src/hb-subset.cc b/src/hb-subset.cc index 411c6b861..9f14b89ba 100644 --- a/src/hb-subset.cc +++ b/src/hb-subset.cc @@ -24,14 +24,13 @@ * Google Author(s): Garret Rieger, Rod Sheeter, Behdad Esfahbod */ -#include "hb-private.hh" -#include "hb-open-type-private.hh" +#include "hb.hh" +#include "hb-open-type.hh" +#include "hb-subset.hh" #include "hb-subset-glyf.hh" -#include "hb-subset-private.hh" -#include "hb-subset-plan.hh" -#include "hb-open-file-private.hh" +#include "hb-open-file.hh" #include "hb-ot-cmap-table.hh" #include "hb-ot-glyf-table.hh" #include "hb-ot-hdmx-table.hh" @@ -41,42 +40,26 @@ #include "hb-ot-maxp-table.hh" #include "hb-ot-os2-table.hh" #include "hb-ot-post-table.hh" +#include "hb-ot-layout-gsub-table.hh" +#include "hb-ot-layout-gpos-table.hh" -struct hb_subset_profile_t { - hb_object_header_t header; - ASSERT_POD (); -}; - -/** - * hb_subset_profile_create: - * - * Return value: New profile with default settings. - * - * Since: 1.8.0 - **/ -hb_subset_profile_t * -hb_subset_profile_create () +static unsigned int +_plan_estimate_subset_table_size (hb_subset_plan_t *plan, + unsigned int table_len) { - return hb_object_create<hb_subset_profile_t>(); -} + unsigned int src_glyphs = plan->source->get_num_glyphs (); + unsigned int dst_glyphs = plan->glyphset->get_population (); -/** - * hb_subset_profile_destroy: - * - * Since: 1.8.0 - **/ -void -hb_subset_profile_destroy (hb_subset_profile_t *profile) -{ - if (!hb_object_destroy (profile)) return; + if (unlikely (!src_glyphs)) + return 512 + table_len; - free (profile); + return 512 + (unsigned int) (table_len * sqrt ((double) dst_glyphs / src_glyphs)); } template<typename TableType> static bool -_subset (hb_subset_plan_t *plan) +_subset2 (hb_subset_plan_t *plan) { hb_blob_t *source_blob = hb_sanitize_context_t ().reference_table<TableType> (plan->source); const TableType *table = source_blob->as<TableType> (); @@ -85,145 +68,69 @@ _subset (hb_subset_plan_t *plan) hb_bool_t result = false; if (source_blob->data) { - result = table->subset(plan); - } else { - DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c::subset sanitize failed on source table.", HB_UNTAG(tag)); + hb_auto_t<hb_vector_t<char> > buf; + unsigned int buf_size = _plan_estimate_subset_table_size (plan, source_blob->length); + DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c initial estimated table size: %u bytes.", HB_UNTAG(tag), buf_size); + if (unlikely (!buf.alloc (buf_size))) + { + DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c failed to allocate %u bytes.", HB_UNTAG(tag), buf_size); + return false; + } + retry: + hb_serialize_context_t serializer (buf.arrayZ(), buf_size); + hb_subset_context_t c (plan, &serializer); + result = table->subset (&c); + if (serializer.ran_out_of_room) + { + buf_size += (buf_size >> 1) + 32; + DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c ran out of room; reallocating to %u bytes.", HB_UNTAG(tag), buf_size); + if (unlikely (!buf.alloc (buf_size))) + { + DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c failed to reallocate %u bytes.", HB_UNTAG(tag), buf_size); + return false; + } + goto retry; + } + if (result) + { + hb_blob_t *dest_blob = serializer.copy_blob (); + DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c final subset table size: %u bytes.", HB_UNTAG(tag), dest_blob->length); + result = c.plan->add_table (tag, dest_blob); + hb_blob_destroy (dest_blob); + } + else + { + DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c::subset table subsetted to empty.", HB_UNTAG(tag)); + result = true; + } } + else + DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c::subset sanitize failed on source table.", HB_UNTAG(tag)); hb_blob_destroy (source_blob); DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c::subset %s", HB_UNTAG(tag), result ? "success" : "FAILED!"); return result; } - -/* - * A face that has add_table(). - */ - -struct hb_subset_face_data_t -{ - struct table_entry_t - { - inline int cmp (const hb_tag_t *t) const - { - if (*t < tag) return -1; - if (*t > tag) return -1; - return 0; - } - - hb_tag_t tag; - hb_blob_t *blob; - }; - - hb_vector_t<table_entry_t, 32> tables; -}; - -static hb_subset_face_data_t * -_hb_subset_face_data_create (void) -{ - hb_subset_face_data_t *data = (hb_subset_face_data_t *) calloc (1, sizeof (hb_subset_face_data_t)); - if (unlikely (!data)) - return nullptr; - - data->tables.init (); - - return data; -} - -static void -_hb_subset_face_data_destroy (void *user_data) -{ - hb_subset_face_data_t *data = (hb_subset_face_data_t *) user_data; - - for (unsigned int i = 0; i < data->tables.len; i++) - hb_blob_destroy (data->tables[i].blob); - - data->tables.fini (); - - free (data); -} - -static hb_blob_t * -_hb_subset_face_data_reference_blob (hb_subset_face_data_t *data) -{ - - unsigned int table_count = data->tables.len; - unsigned int face_length = table_count * 16 + 12; - - for (unsigned int i = 0; i < table_count; i++) - face_length += hb_ceil_to_4 (hb_blob_get_length (data->tables.arrayZ[i].blob)); - - char *buf = (char *) malloc (face_length); - if (unlikely (!buf)) - return nullptr; - - hb_serialize_context_t c (buf, face_length); - OT::OpenTypeFontFile *f = c.start_serialize<OT::OpenTypeFontFile> (); - - bool is_cff = data->tables.lsearch (HB_TAG ('C','F','F',' ')) || data->tables.lsearch (HB_TAG ('C','F','F','2')); - hb_tag_t sfnt_tag = is_cff ? OT::OpenTypeFontFile::CFFTag : OT::OpenTypeFontFile::TrueTypeTag; - - Supplier<hb_tag_t> tags_supplier (&data->tables[0].tag, table_count, sizeof (data->tables[0])); - Supplier<hb_blob_t *> blobs_supplier (&data->tables[0].blob, table_count, sizeof (data->tables[0])); - bool ret = f->serialize_single (&c, - sfnt_tag, - tags_supplier, - blobs_supplier, - table_count); - - c.end_serialize (); - - if (unlikely (!ret)) - { - free (buf); - return nullptr; - } - - return hb_blob_create (buf, face_length, HB_MEMORY_MODE_WRITABLE, buf, free); -} - -static hb_blob_t * -_hb_subset_face_reference_table (hb_face_t *face, hb_tag_t tag, void *user_data) +template<typename TableType> +static bool +_subset (hb_subset_plan_t *plan) { - hb_subset_face_data_t *data = (hb_subset_face_data_t *) user_data; - - if (!tag) - return _hb_subset_face_data_reference_blob (data); - - hb_subset_face_data_t::table_entry_t *entry = data->tables.lsearch (tag); - if (entry) - return hb_blob_reference (entry->blob); - - return nullptr; -} + hb_blob_t *source_blob = hb_sanitize_context_t ().reference_table<TableType> (plan->source); + const TableType *table = source_blob->as<TableType> (); -/* TODO: Move this to hb-face.h and rename to hb_face_builder_create() - * with hb_face_builder_add_table(). */ -hb_face_t * -hb_subset_face_create (void) -{ - hb_subset_face_data_t *data = _hb_subset_face_data_create (); - if (unlikely (!data)) return hb_face_get_empty (); + hb_tag_t tag = TableType::tableTag; + hb_bool_t result = false; + if (source_blob->data) + result = table->subset (plan); + else + DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c::subset sanitize failed on source table.", HB_UNTAG(tag)); - return hb_face_create_for_tables (_hb_subset_face_reference_table, - data, - _hb_subset_face_data_destroy); + hb_blob_destroy (source_blob); + DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c::subset %s", HB_UNTAG(tag), result ? "success" : "FAILED!"); + return result; } -hb_bool_t -hb_subset_face_add_table (hb_face_t *face, hb_tag_t tag, hb_blob_t *blob) -{ - if (unlikely (face->destroy != (hb_destroy_func_t) _hb_subset_face_data_destroy)) - return false; - - hb_subset_face_data_t *data = (hb_subset_face_data_t *) face->user_data; - hb_subset_face_data_t::table_entry_t *entry = data->tables.push (); - - entry->tag = tag; - entry->blob = hb_blob_reference (blob); - - return true; -} static bool _subset_table (hb_subset_plan_t *plan, @@ -270,6 +177,14 @@ _subset_table (hb_subset_plan_t *plan, case HB_OT_TAG_post: result = _subset<const OT::post> (plan); break; + + case HB_OT_TAG_GSUB: + result = _subset2<const OT::GSUB> (plan); + break; + case HB_OT_TAG_GPOS: + result = _subset2<const OT::GPOS> (plan); + break; + default: hb_blob_t *source_table = hb_face_reference_table(plan->source, tag); if (likely (source_table)) @@ -298,7 +213,7 @@ _should_drop_table(hb_subset_plan_t *plan, hb_tag_t tag) case HB_TAG ('G', 'D', 'E', 'F'): /* temporary */ case HB_TAG ('G', 'P', 'O', 'S'): /* temporary */ case HB_TAG ('G', 'S', 'U', 'B'): /* temporary */ - return plan->drop_ot_layout; + return plan->drop_layout; // Drop these tables below by default, list pulled // from fontTools: case HB_TAG ('B', 'A', 'S', 'E'): @@ -327,19 +242,17 @@ _should_drop_table(hb_subset_plan_t *plan, hb_tag_t tag) /** * hb_subset: * @source: font face data to be subset. - * @profile: profile to use for the subsetting. * @input: input to use for the subsetting. * - * Subsets a font according to provided profile and input. + * Subsets a font according to provided input. **/ hb_face_t * hb_subset (hb_face_t *source, - hb_subset_profile_t *profile, hb_subset_input_t *input) { - if (unlikely (!profile || !input || !source)) return hb_face_get_empty(); + if (unlikely (!input || !source)) return hb_face_get_empty(); - hb_subset_plan_t *plan = hb_subset_plan_create (source, profile, input); + hb_subset_plan_t *plan = hb_subset_plan_create (source, input); hb_tag_t table_tags[32]; unsigned int offset = 0, count; @@ -358,23 +271,9 @@ hb_subset (hb_face_t *source, success = success && _subset_table (plan, tag); } offset += count; - } while (count == ARRAY_LENGTH (table_tags)); + } while (success && count == ARRAY_LENGTH (table_tags)); hb_face_t *result = success ? hb_face_reference(plan->dest) : hb_face_get_empty(); hb_subset_plan_destroy (plan); return result; } - -/** - * hb_subset_get_all_codepoints: - * @source: font face data to load. - * @out: set to add the all codepoints covered by font face, source. - */ -void -hb_subset_get_all_codepoints (hb_face_t *source, hb_set_t *out) -{ - OT::cmap::accelerator_t cmap; - cmap.init (source); - cmap.get_all_codepoints (out); - cmap.fini(); -} diff --git a/src/hb-subset.h b/src/hb-subset.h index f6d2ae0a0..8b07a45e9 100644 --- a/src/hb-subset.h +++ b/src/hb-subset.h @@ -32,20 +32,6 @@ HB_BEGIN_DECLS /* - * hb_subset_profile_t - * Things that change based on target environment, e.g. OS. - * Threadsafe for multiple concurrent subset operations. - */ - -typedef struct hb_subset_profile_t hb_subset_profile_t; - -HB_EXTERN hb_subset_profile_t * -hb_subset_profile_create (void); - -HB_EXTERN void -hb_subset_profile_destroy (hb_subset_profile_t *profile); - -/* * hb_subset_input_t * * Things that change based on the input. Characters to keep, etc. @@ -68,21 +54,24 @@ hb_subset_input_unicode_set (hb_subset_input_t *subset_input); HB_EXTERN hb_set_t * hb_subset_input_glyph_set (hb_subset_input_t *subset_input); -HB_EXTERN hb_bool_t * -hb_subset_input_drop_hints (hb_subset_input_t *subset_input); +HB_EXTERN void +hb_subset_input_set_drop_hints (hb_subset_input_t *subset_input, + hb_bool_t drop_hints); +HB_EXTERN hb_bool_t +hb_subset_input_get_drop_hints (hb_subset_input_t *subset_input); + +HB_EXTERN void +hb_subset_input_set_drop_layout (hb_subset_input_t *subset_input, + hb_bool_t drop_layout); +HB_EXTERN hb_bool_t +hb_subset_input_get_drop_layout (hb_subset_input_t *subset_input); -HB_EXTERN hb_bool_t * -hb_subset_input_drop_ot_layout (hb_subset_input_t *subset_input); /* hb_subset() */ HB_EXTERN hb_face_t * hb_subset (hb_face_t *source, - hb_subset_profile_t *profile, hb_subset_input_t *input); -/* hb_subset_get_all_codepoints */ -HB_EXTERN void -hb_subset_get_all_codepoints (hb_face_t *source, hb_set_t *out); HB_END_DECLS diff --git a/src/hb-subset.hh b/src/hb-subset.hh new file mode 100644 index 000000000..9cdd388d7 --- /dev/null +++ b/src/hb-subset.hh @@ -0,0 +1,60 @@ +/* + * Copyright © 2018 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Garret Rieger, Roderick Sheeter + */ + +#ifndef HB_SUBSET_HH +#define HB_SUBSET_HH + + +#include "hb.hh" + +#include "hb-subset.h" + +#include "hb-machinery.hh" +#include "hb-subset-input.hh" +#include "hb-subset-plan.hh" + +struct hb_subset_context_t : + hb_dispatch_context_t<hb_subset_context_t, bool, HB_DEBUG_SUBSET> +{ + inline const char *get_name (void) { return "SUBSET"; } + template <typename T> + inline bool dispatch (const T &obj) { return obj.subset (this); } + static bool default_return_value (void) { return true; } + bool stop_sublookup_iteration (bool r) const { return false; } + + hb_subset_plan_t *plan; + hb_serialize_context_t *serializer; + unsigned int debug_depth; + + hb_subset_context_t (hb_subset_plan_t *plan_, + hb_serialize_context_t *serializer_) : + plan (plan_), + serializer (serializer_), + debug_depth (0) {} +}; + + +#endif /* HB_SUBSET_HH */ diff --git a/src/hb-ucdn.cc b/src/hb-ucdn.cc index 56d13e7cd..3179683c2 100644 --- a/src/hb-ucdn.cc +++ b/src/hb-ucdn.cc @@ -14,10 +14,9 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "hb-private.hh" +#include "hb.hh" -#include "hb-unicode-private.hh" -#include "hb-machinery-private.hh" +#include "hb-machinery.hh" #include "ucdn.h" @@ -182,15 +181,6 @@ hb_ucdn_combining_class(hb_unicode_funcs_t *ufuncs HB_UNUSED, return (hb_unicode_combining_class_t) ucdn_get_combining_class(unicode); } -static unsigned int -hb_ucdn_eastasian_width(hb_unicode_funcs_t *ufuncs HB_UNUSED, - hb_codepoint_t unicode, - void *user_data HB_UNUSED) -{ - int w = ucdn_get_east_asian_width(unicode); - return (w == UCDN_EAST_ASIAN_F || w == UCDN_EAST_ASIAN_W) ? 2 : 1; -} - static hb_unicode_general_category_t hb_ucdn_general_category(hb_unicode_funcs_t *ufuncs HB_UNUSED, hb_codepoint_t unicode, @@ -231,16 +221,10 @@ hb_ucdn_decompose(hb_unicode_funcs_t *ufuncs HB_UNUSED, return ucdn_decompose(ab, a, b); } -static unsigned int -hb_ucdn_decompose_compatibility(hb_unicode_funcs_t *ufuncs HB_UNUSED, - hb_codepoint_t u, hb_codepoint_t *decomposed, - void *user_data HB_UNUSED) -{ - return ucdn_compat_decompose(u, decomposed); -} - +#ifdef HB_USE_ATEXIT static void free_static_ucdn_funcs (void); +#endif static struct hb_ucdn_unicode_funcs_lazy_loader_t : hb_unicode_funcs_lazy_loader_t<hb_ucdn_unicode_funcs_lazy_loader_t> { @@ -248,10 +232,12 @@ static struct hb_ucdn_unicode_funcs_lazy_loader_t : hb_unicode_funcs_lazy_loader { hb_unicode_funcs_t *funcs = hb_unicode_funcs_create (nullptr); -#define HB_UNICODE_FUNC_IMPLEMENT(name) \ - hb_unicode_funcs_set_##name##_func (funcs, hb_ucdn_##name, nullptr, nullptr); - HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS -#undef HB_UNICODE_FUNC_IMPLEMENT + hb_unicode_funcs_set_combining_class_func (funcs, hb_ucdn_combining_class, nullptr, nullptr); + hb_unicode_funcs_set_general_category_func (funcs, hb_ucdn_general_category, nullptr, nullptr); + hb_unicode_funcs_set_mirroring_func (funcs, hb_ucdn_mirroring, nullptr, nullptr); + hb_unicode_funcs_set_script_func (funcs, hb_ucdn_script, nullptr, nullptr); + hb_unicode_funcs_set_compose_func (funcs, hb_ucdn_compose, nullptr, nullptr); + hb_unicode_funcs_set_decompose_func (funcs, hb_ucdn_decompose, nullptr, nullptr); hb_unicode_funcs_make_immutable (funcs); @@ -273,6 +259,9 @@ void free_static_ucdn_funcs (void) extern "C" HB_INTERNAL hb_unicode_funcs_t * +hb_ucdn_get_unicode_funcs (void); + +hb_unicode_funcs_t * hb_ucdn_get_unicode_funcs (void) { return static_ucdn_funcs.get_unconst (); diff --git a/src/hb-unicode-emoji-table.hh b/src/hb-unicode-emoji-table.hh new file mode 100644 index 000000000..41199de53 --- /dev/null +++ b/src/hb-unicode-emoji-table.hh @@ -0,0 +1,269 @@ +/* == Start of generated table == */ +/* + * The following tables are generated by running: + * + * ./gen-emoji-table.py emoji-data.txt + * + * on file with this header: + * + * # emoji-data.txt + * # Date: 2018-02-07, 07:55:18 GMT + * # © 2018 Unicode®, Inc. + * # Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. + * # For terms of use, see http://www.unicode.org/terms_of_use.html + * # + * # Emoji Data for UTS #51 + * # Version: 11.0 + * # + * # For documentation and usage, see http://www.unicode.org/reports/tr51 + */ + +#ifndef HB_UNICODE_EMOJI_TABLE_HH +#define HB_UNICODE_EMOJI_TABLE_HH + +#include "hb-unicode.hh" + + +static const struct hb_unicode_range_t _hb_unicode_emoji_Extended_Pictographic_table[] = +{ + {0x00A9, 0x00A9}, + {0x00AE, 0x00AE}, + {0x203C, 0x203C}, + {0x2049, 0x2049}, + {0x2122, 0x2122}, + {0x2139, 0x2139}, + {0x2194, 0x2199}, + {0x21A9, 0x21AA}, + {0x231A, 0x231B}, + {0x2328, 0x2328}, + {0x2388, 0x2388}, + {0x23CF, 0x23CF}, + {0x23E9, 0x23F3}, + {0x23F8, 0x23FA}, + {0x24C2, 0x24C2}, + {0x25AA, 0x25AB}, + {0x25B6, 0x25B6}, + {0x25C0, 0x25C0}, + {0x25FB, 0x25FE}, + {0x2600, 0x2605}, + {0x2607, 0x2612}, + {0x2614, 0x2615}, + {0x2616, 0x2617}, + {0x2618, 0x2618}, + {0x2619, 0x2619}, + {0x261A, 0x266F}, + {0x2670, 0x2671}, + {0x2672, 0x267D}, + {0x267E, 0x267F}, + {0x2680, 0x2685}, + {0x2690, 0x2691}, + {0x2692, 0x269C}, + {0x269D, 0x269D}, + {0x269E, 0x269F}, + {0x26A0, 0x26A1}, + {0x26A2, 0x26B1}, + {0x26B2, 0x26B2}, + {0x26B3, 0x26BC}, + {0x26BD, 0x26BF}, + {0x26C0, 0x26C3}, + {0x26C4, 0x26CD}, + {0x26CE, 0x26CE}, + {0x26CF, 0x26E1}, + {0x26E2, 0x26E2}, + {0x26E3, 0x26E3}, + {0x26E4, 0x26E7}, + {0x26E8, 0x26FF}, + {0x2700, 0x2700}, + {0x2701, 0x2704}, + {0x2705, 0x2705}, + {0x2708, 0x2709}, + {0x270A, 0x270B}, + {0x270C, 0x2712}, + {0x2714, 0x2714}, + {0x2716, 0x2716}, + {0x271D, 0x271D}, + {0x2721, 0x2721}, + {0x2728, 0x2728}, + {0x2733, 0x2734}, + {0x2744, 0x2744}, + {0x2747, 0x2747}, + {0x274C, 0x274C}, + {0x274E, 0x274E}, + {0x2753, 0x2755}, + {0x2757, 0x2757}, + {0x2763, 0x2767}, + {0x2795, 0x2797}, + {0x27A1, 0x27A1}, + {0x27B0, 0x27B0}, + {0x27BF, 0x27BF}, + {0x2934, 0x2935}, + {0x2B05, 0x2B07}, + {0x2B1B, 0x2B1C}, + {0x2B50, 0x2B50}, + {0x2B55, 0x2B55}, + {0x3030, 0x3030}, + {0x303D, 0x303D}, + {0x3297, 0x3297}, + {0x3299, 0x3299}, + {0x1F000, 0x1F02B}, + {0x1F02C, 0x1F02F}, + {0x1F030, 0x1F093}, + {0x1F094, 0x1F09F}, + {0x1F0A0, 0x1F0AE}, + {0x1F0AF, 0x1F0B0}, + {0x1F0B1, 0x1F0BE}, + {0x1F0BF, 0x1F0BF}, + {0x1F0C0, 0x1F0C0}, + {0x1F0C1, 0x1F0CF}, + {0x1F0D0, 0x1F0D0}, + {0x1F0D1, 0x1F0DF}, + {0x1F0E0, 0x1F0F5}, + {0x1F0F6, 0x1F0FF}, + {0x1F10D, 0x1F10F}, + {0x1F12F, 0x1F12F}, + {0x1F16C, 0x1F16F}, + {0x1F170, 0x1F171}, + {0x1F17E, 0x1F17E}, + {0x1F17F, 0x1F17F}, + {0x1F18E, 0x1F18E}, + {0x1F191, 0x1F19A}, + {0x1F1AD, 0x1F1E5}, + {0x1F201, 0x1F202}, + {0x1F203, 0x1F20F}, + {0x1F21A, 0x1F21A}, + {0x1F22F, 0x1F22F}, + {0x1F232, 0x1F23A}, + {0x1F23C, 0x1F23F}, + {0x1F249, 0x1F24F}, + {0x1F250, 0x1F251}, + {0x1F252, 0x1F25F}, + {0x1F260, 0x1F265}, + {0x1F266, 0x1F2FF}, + {0x1F300, 0x1F320}, + {0x1F321, 0x1F32C}, + {0x1F32D, 0x1F32F}, + {0x1F330, 0x1F335}, + {0x1F336, 0x1F336}, + {0x1F337, 0x1F37C}, + {0x1F37D, 0x1F37D}, + {0x1F37E, 0x1F37F}, + {0x1F380, 0x1F393}, + {0x1F394, 0x1F39F}, + {0x1F3A0, 0x1F3C4}, + {0x1F3C5, 0x1F3C5}, + {0x1F3C6, 0x1F3CA}, + {0x1F3CB, 0x1F3CE}, + {0x1F3CF, 0x1F3D3}, + {0x1F3D4, 0x1F3DF}, + {0x1F3E0, 0x1F3F0}, + {0x1F3F1, 0x1F3F7}, + {0x1F3F8, 0x1F3FA}, + {0x1F400, 0x1F43E}, + {0x1F43F, 0x1F43F}, + {0x1F440, 0x1F440}, + {0x1F441, 0x1F441}, + {0x1F442, 0x1F4F7}, + {0x1F4F8, 0x1F4F8}, + {0x1F4F9, 0x1F4FC}, + {0x1F4FD, 0x1F4FE}, + {0x1F4FF, 0x1F4FF}, + {0x1F500, 0x1F53D}, + {0x1F546, 0x1F54A}, + {0x1F54B, 0x1F54F}, + {0x1F550, 0x1F567}, + {0x1F568, 0x1F579}, + {0x1F57A, 0x1F57A}, + {0x1F57B, 0x1F5A3}, + {0x1F5A4, 0x1F5A4}, + {0x1F5A5, 0x1F5FA}, + {0x1F5FB, 0x1F5FF}, + {0x1F600, 0x1F600}, + {0x1F601, 0x1F610}, + {0x1F611, 0x1F611}, + {0x1F612, 0x1F614}, + {0x1F615, 0x1F615}, + {0x1F616, 0x1F616}, + {0x1F617, 0x1F617}, + {0x1F618, 0x1F618}, + {0x1F619, 0x1F619}, + {0x1F61A, 0x1F61A}, + {0x1F61B, 0x1F61B}, + {0x1F61C, 0x1F61E}, + {0x1F61F, 0x1F61F}, + {0x1F620, 0x1F625}, + {0x1F626, 0x1F627}, + {0x1F628, 0x1F62B}, + {0x1F62C, 0x1F62C}, + {0x1F62D, 0x1F62D}, + {0x1F62E, 0x1F62F}, + {0x1F630, 0x1F633}, + {0x1F634, 0x1F634}, + {0x1F635, 0x1F640}, + {0x1F641, 0x1F642}, + {0x1F643, 0x1F644}, + {0x1F645, 0x1F64F}, + {0x1F680, 0x1F6C5}, + {0x1F6C6, 0x1F6CF}, + {0x1F6D0, 0x1F6D0}, + {0x1F6D1, 0x1F6D2}, + {0x1F6D3, 0x1F6D4}, + {0x1F6D5, 0x1F6DF}, + {0x1F6E0, 0x1F6EC}, + {0x1F6ED, 0x1F6EF}, + {0x1F6F0, 0x1F6F3}, + {0x1F6F4, 0x1F6F6}, + {0x1F6F7, 0x1F6F8}, + {0x1F6F9, 0x1F6F9}, + {0x1F6FA, 0x1F6FF}, + {0x1F774, 0x1F77F}, + {0x1F7D5, 0x1F7D8}, + {0x1F7D9, 0x1F7FF}, + {0x1F80C, 0x1F80F}, + {0x1F848, 0x1F84F}, + {0x1F85A, 0x1F85F}, + {0x1F888, 0x1F88F}, + {0x1F8AE, 0x1F8FF}, + {0x1F90C, 0x1F90F}, + {0x1F910, 0x1F918}, + {0x1F919, 0x1F91E}, + {0x1F91F, 0x1F91F}, + {0x1F920, 0x1F927}, + {0x1F928, 0x1F92F}, + {0x1F930, 0x1F930}, + {0x1F931, 0x1F932}, + {0x1F933, 0x1F93A}, + {0x1F93C, 0x1F93E}, + {0x1F93F, 0x1F93F}, + {0x1F940, 0x1F945}, + {0x1F947, 0x1F94B}, + {0x1F94C, 0x1F94C}, + {0x1F94D, 0x1F94F}, + {0x1F950, 0x1F95E}, + {0x1F95F, 0x1F96B}, + {0x1F96C, 0x1F970}, + {0x1F971, 0x1F972}, + {0x1F973, 0x1F976}, + {0x1F977, 0x1F979}, + {0x1F97A, 0x1F97A}, + {0x1F97B, 0x1F97B}, + {0x1F97C, 0x1F97F}, + {0x1F980, 0x1F984}, + {0x1F985, 0x1F991}, + {0x1F992, 0x1F997}, + {0x1F998, 0x1F9A2}, + {0x1F9A3, 0x1F9AF}, + {0x1F9B0, 0x1F9B9}, + {0x1F9BA, 0x1F9BF}, + {0x1F9C0, 0x1F9C0}, + {0x1F9C1, 0x1F9C2}, + {0x1F9C3, 0x1F9CF}, + {0x1F9D0, 0x1F9E6}, + {0x1F9E7, 0x1F9FF}, + {0x1FA00, 0x1FA5F}, + {0x1FA60, 0x1FA6D}, + {0x1FA6E, 0x1FFFD}, +}; + +#endif /* HB_UNICODE_EMOJI_TABLE_HH */ + +/* == End of generated table == */ diff --git a/src/hb-unicode.cc b/src/hb-unicode.cc index 8cb417233..7b821b46d 100644 --- a/src/hb-unicode.cc +++ b/src/hb-unicode.cc @@ -28,9 +28,9 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-private.hh" +#include "hb.hh" -#include "hb-unicode-private.hh" +#include "hb-unicode.hh" @@ -308,6 +308,8 @@ hb_unicode_funcs_make_immutable (hb_unicode_funcs_t *ufuncs) { if (unlikely (hb_object_is_inert (ufuncs))) return; + if (ufuncs->immutable) + return; ufuncs->immutable = true; } @@ -450,7 +452,7 @@ hb_unicode_decompose_compatibility (hb_unicode_funcs_t *ufuncs, } -/* See hb-unicode-private.hh for details. */ +/* See hb-unicode.hh for details. */ const uint8_t _hb_modified_combining_class[256] = { @@ -562,3 +564,19 @@ _hb_modified_combining_class[256] = 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, /* HB_UNICODE_COMBINING_CLASS_INVALID */ }; + + +/* + * Emoji + */ + +#include "hb-unicode-emoji-table.hh" + +bool +_hb_unicode_is_emoji_Extended_Pictographic (hb_codepoint_t cp) +{ + return hb_bsearch_r (&cp, _hb_unicode_emoji_Extended_Pictographic_table, + ARRAY_LENGTH (_hb_unicode_emoji_Extended_Pictographic_table), + sizeof (hb_unicode_range_t), + hb_unicode_range_t::cmp, nullptr); +} diff --git a/src/hb-unicode.h b/src/hb-unicode.h index 2657f4813..df0b91f01 100644 --- a/src/hb-unicode.h +++ b/src/hb-unicode.h @@ -40,6 +40,14 @@ HB_BEGIN_DECLS +/** + * HB_UNICODE_MAX + * + * Since: 1.9.0 + **/ +#define HB_UNICODE_MAX 0x10FFFFu + + /* hb_unicode_general_category_t */ /* Unicode Character Database property: General_Category (gc) */ @@ -222,9 +230,6 @@ hb_unicode_funcs_get_parent (hb_unicode_funcs_t *ufuncs); typedef hb_unicode_combining_class_t (*hb_unicode_combining_class_func_t) (hb_unicode_funcs_t *ufuncs, hb_codepoint_t unicode, void *user_data); -typedef unsigned int (*hb_unicode_eastasian_width_func_t) (hb_unicode_funcs_t *ufuncs, - hb_codepoint_t unicode, - void *user_data); typedef hb_unicode_general_category_t (*hb_unicode_general_category_func_t) (hb_unicode_funcs_t *ufuncs, hb_codepoint_t unicode, void *user_data); @@ -246,32 +251,6 @@ typedef hb_bool_t (*hb_unicode_decompose_func_t) (hb_unicode_funcs_t *ufuncs, hb_codepoint_t *b, void *user_data); -/** - * hb_unicode_decompose_compatibility_func_t: - * @ufuncs: a Unicode function structure - * @u: codepoint to decompose - * @decomposed: address of codepoint array (of length %HB_UNICODE_MAX_DECOMPOSITION_LEN) to write decomposition into - * @user_data: user data pointer as passed to hb_unicode_funcs_set_decompose_compatibility_func() - * - * Fully decompose @u to its Unicode compatibility decomposition. The codepoints of the decomposition will be written to @decomposed. - * The complete length of the decomposition will be returned. - * - * If @u has no compatibility decomposition, zero should be returned. - * - * The Unicode standard guarantees that a buffer of length %HB_UNICODE_MAX_DECOMPOSITION_LEN codepoints will always be sufficient for any - * compatibility decomposition plus an terminating value of 0. Consequently, @decompose must be allocated by the caller to be at least this length. Implementations - * of this function type must ensure that they do not write past the provided array. - * - * Return value: number of codepoints in the full compatibility decomposition of @u, or 0 if no decomposition available. - */ -typedef unsigned int (*hb_unicode_decompose_compatibility_func_t) (hb_unicode_funcs_t *ufuncs, - hb_codepoint_t u, - hb_codepoint_t *decomposed, - void *user_data); - -/* See Unicode 6.1 for details on the maximum decomposition length. */ -#define HB_UNICODE_MAX_DECOMPOSITION_LEN (18+1) /* codepoints */ - /* setters */ /** @@ -291,22 +270,6 @@ hb_unicode_funcs_set_combining_class_func (hb_unicode_funcs_t *ufuncs, void *user_data, hb_destroy_func_t destroy); /** - * hb_unicode_funcs_set_eastasian_width_func: - * @ufuncs: a Unicode function structure - * @func: (closure user_data) (destroy destroy) (scope notified): - * @user_data: - * @destroy: - * - * - * - * Since: 0.9.2 - **/ -HB_EXTERN void -hb_unicode_funcs_set_eastasian_width_func (hb_unicode_funcs_t *ufuncs, - hb_unicode_eastasian_width_func_t func, - void *user_data, hb_destroy_func_t destroy); - -/** * hb_unicode_funcs_set_general_category_func: * @ufuncs: a Unicode function structure * @func: (closure user_data) (destroy destroy) (scope notified): @@ -386,22 +349,6 @@ hb_unicode_funcs_set_decompose_func (hb_unicode_funcs_t *ufuncs, hb_unicode_decompose_func_t func, void *user_data, hb_destroy_func_t destroy); -/** - * hb_unicode_funcs_set_decompose_compatibility_func: - * @ufuncs: a Unicode function structure - * @func: (closure user_data) (destroy destroy) (scope notified): - * @user_data: - * @destroy: - * - * - * - * Since: 0.9.2 - **/ -HB_EXTERN void -hb_unicode_funcs_set_decompose_compatibility_func (hb_unicode_funcs_t *ufuncs, - hb_unicode_decompose_compatibility_func_t func, - void *user_data, hb_destroy_func_t destroy); - /* accessors */ /** @@ -414,15 +361,6 @@ hb_unicode_combining_class (hb_unicode_funcs_t *ufuncs, hb_codepoint_t unicode); /** - * hb_unicode_eastasian_width: - * - * Since: 0.9.2 - **/ -HB_EXTERN unsigned int -hb_unicode_eastasian_width (hb_unicode_funcs_t *ufuncs, - hb_codepoint_t unicode); - -/** * hb_unicode_general_category: * * Since: 0.9.2 @@ -461,11 +399,6 @@ hb_unicode_decompose (hb_unicode_funcs_t *ufuncs, hb_codepoint_t *a, hb_codepoint_t *b); -HB_EXTERN unsigned int -hb_unicode_decompose_compatibility (hb_unicode_funcs_t *ufuncs, - hb_codepoint_t u, - hb_codepoint_t *decomposed); - HB_END_DECLS #endif /* HB_UNICODE_H */ diff --git a/src/hb-unicode-private.hh b/src/hb-unicode.hh index fb16ba437..6d6a4fa0c 100644 --- a/src/hb-unicode-private.hh +++ b/src/hb-unicode.hh @@ -28,10 +28,10 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_UNICODE_PRIVATE_HH -#define HB_UNICODE_PRIVATE_HH +#ifndef HB_UNICODE_HH +#define HB_UNICODE_HH -#include "hb-private.hh" +#include "hb.hh" extern HB_INTERNAL const uint8_t _hb_modified_combining_class[256]; @@ -101,24 +101,23 @@ HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE return ret; } - inline unsigned int - modified_combining_class (hb_codepoint_t unicode) + modified_combining_class (hb_codepoint_t u) { /* XXX This hack belongs to the Myanmar shaper. */ - if (unlikely (unicode == 0x1037u)) unicode = 0x103Au; + if (unlikely (u == 0x1037u)) u = 0x103Au; /* XXX This hack belongs to the USE shaper (for Tai Tham): * Reorder SAKOT to ensure it comes after any tone marks. */ - if (unlikely (unicode == 0x1A60u)) return 254; + if (unlikely (u == 0x1A60u)) return 254; /* XXX This hack belongs to the Tibetan shaper: * Reorder PADMA to ensure it comes after any vowel marks. */ - if (unlikely (unicode == 0x0FC6u)) return 254; + if (unlikely (u == 0x0FC6u)) return 254; /* Reorder TSA -PHRU to reorder before U+0F74 */ - if (unlikely (unicode == 0x0F39u)) return 127; + if (unlikely (u == 0x0F39u)) return 127; - return _hb_modified_combining_class[combining_class (unicode)]; + return _hb_modified_combining_class[combining_class (u)]; } static inline hb_bool_t @@ -267,7 +266,9 @@ HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE DECLARE_NULL_INSTANCE (hb_unicode_funcs_t); -/* Modified combining marks */ +/* + * Modified combining marks + */ /* Hebrew * @@ -360,10 +361,37 @@ DECLARE_NULL_INSTANCE (hb_unicode_funcs_t); FLAG (HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK) | \ FLAG (HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK))) -#define HB_UNICODE_GENERAL_CATEGORY_IS_NON_ENCLOSING_MARK_OR_MODIFIER_SYMBOL(gen_cat) \ - (FLAG_UNSAFE (gen_cat) & \ - (FLAG (HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK) | \ - FLAG (HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) | \ - FLAG (HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL))) -#endif /* HB_UNICODE_PRIVATE_HH */ +/* + * Ranges, used for bsearch tables. + */ + +struct hb_unicode_range_t +{ + static int + cmp (const void *_key, const void *_item, void *_arg) + { + hb_codepoint_t cp = *((hb_codepoint_t *) _key); + const hb_unicode_range_t *range = (hb_unicode_range_t *) _item; + + if (cp < range->start) + return -1; + else if (cp <= range->end) + return 0; + else + return +1; + } + + hb_codepoint_t start; + hb_codepoint_t end; +}; + +/* + * Emoji. + */ + +HB_INTERNAL bool +_hb_unicode_is_emoji_Extended_Pictographic (hb_codepoint_t cp); + + +#endif /* HB_UNICODE_HH */ diff --git a/src/hb-uniscribe.cc b/src/hb-uniscribe.cc index 11b7384fa..44a67ae4c 100644 --- a/src/hb-uniscribe.cc +++ b/src/hb-uniscribe.cc @@ -24,9 +24,9 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-private.hh" +#include "hb.hh" #define HB_SHAPER uniscribe -#include "hb-shaper-impl-private.hh" +#include "hb-shaper-impl.hh" #include <windows.h> #include <usp10.h> @@ -34,7 +34,7 @@ #include "hb-uniscribe.h" -#include "hb-open-file-private.hh" +#include "hb-open-file.hh" #include "hb-ot-name-table.hh" #include "hb-ot-tag.h" @@ -392,7 +392,7 @@ _hb_rename_font (hb_blob_t *blob, wchar_t *new_name) name.stringOffset.set (name.get_size ()); for (unsigned int i = 0; i < ARRAY_LENGTH (name_IDs); i++) { - OT::NameRecord &record = name.nameRecord[i]; + OT::NameRecord &record = name.nameRecordZ[i]; record.platformID.set (3); record.encodingID.set (1); record.languageID.set (0x0409u); /* English */ @@ -717,7 +717,7 @@ _hb_uniscribe_shape (hb_shape_plan_t *shape_plan, { 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()); } } @@ -728,7 +728,7 @@ _hb_uniscribe_shape (hb_shape_plan_t *shape_plan, for (unsigned int i = 0; i < range_records.len; i++) { range_record_t *range = &range_records[i]; - range->props.potfRecords = feature_records.arrayZ + reinterpret_cast<uintptr_t> (range->props.potfRecords); + range->props.potfRecords = feature_records.arrayZ() + reinterpret_cast<uintptr_t> (range->props.potfRecords); } } @@ -902,8 +902,8 @@ retry: &items[i].a, script_tags[i], language_tag, - range_char_counts.arrayZ, - range_properties.arrayZ, + range_char_counts.arrayZ(), + range_properties.arrayZ(), range_properties.len, pchars + chars_offset, item_chars_len, @@ -943,8 +943,8 @@ retry: &items[i].a, script_tags[i], language_tag, - range_char_counts.arrayZ, - range_properties.arrayZ, + range_char_counts.arrayZ(), + range_properties.arrayZ(), range_properties.len, pchars + chars_offset, log_clusters + chars_offset, diff --git a/src/hb-utf-private.hh b/src/hb-utf.hh index 211eb4dc0..eccb632e4 100644 --- a/src/hb-utf-private.hh +++ b/src/hb-utf.hh @@ -24,10 +24,10 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_UTF_PRIVATE_HH -#define HB_UTF_PRIVATE_HH +#ifndef HB_UTF_HH +#define HB_UTF_HH -#include "hb-private.hh" +#include "hb.hh" struct hb_utf8_t @@ -279,4 +279,4 @@ struct hb_latin1_t } }; -#endif /* HB_UTF_PRIVATE_HH */ +#endif /* HB_UTF_HH */ diff --git a/src/hb-vector-private.hh b/src/hb-vector.hh index 1ef20d438..766e5fb8e 100644 --- a/src/hb-vector-private.hh +++ b/src/hb-vector.hh @@ -25,45 +25,52 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_VECTOR_PRIVATE_HH -#define HB_VECTOR_PRIVATE_HH +#ifndef HB_VECTOR_HH +#define HB_VECTOR_HH -#include "hb-private.hh" +#include "hb.hh" template <typename Type, unsigned int StaticSize=8> struct hb_vector_t { unsigned int len; + private: unsigned int allocated; /* == 0 means allocation failed. */ - Type *arrayZ; + Type *arrayZ_; Type static_array[StaticSize]; + public: void init (void) { len = 0; allocated = ARRAY_LENGTH (static_array); - arrayZ = static_array; + arrayZ_ = nullptr; } + inline Type * arrayZ (void) + { return arrayZ_ ? arrayZ_ : static_array; } + inline const Type * arrayZ (void) const + { return arrayZ_ ? arrayZ_ : static_array; } + inline Type& operator [] (unsigned int i) { if (unlikely (i >= len)) return Crap (Type); - return arrayZ[i]; + return arrayZ()[i]; } inline const Type& operator [] (unsigned int i) const { if (unlikely (i >= len)) return Null(Type); - return arrayZ[i]; + return arrayZ()[i]; } inline Type *push (void) { if (unlikely (!resize (len + 1))) return &Crap(Type); - return &arrayZ[len - 1]; + return &arrayZ()[len - 1]; } inline Type *push (const Type& v) { @@ -72,6 +79,8 @@ struct hb_vector_t return p; } + inline bool in_error (void) const { return allocated == 0; } + /* Allocate for size but don't adjust len. */ inline bool alloc (unsigned int size) { @@ -89,17 +98,17 @@ struct hb_vector_t Type *new_array = nullptr; - if (arrayZ == static_array) + if (!arrayZ_) { new_array = (Type *) calloc (new_allocated, sizeof (Type)); if (new_array) - memcpy (new_array, arrayZ, len * sizeof (Type)); + memcpy (new_array, static_array, len * sizeof (Type)); } else { bool overflows = (new_allocated < allocated) || hb_unsigned_mul_overflows (new_allocated, sizeof (Type)); if (likely (!overflows)) - new_array = (Type *) realloc (arrayZ, new_allocated * sizeof (Type)); + new_array = (Type *) realloc (arrayZ_, new_allocated * sizeof (Type)); } if (unlikely (!new_array)) @@ -108,7 +117,7 @@ struct hb_vector_t return false; } - arrayZ = new_array; + arrayZ_ = new_array; allocated = new_allocated; return true; @@ -121,7 +130,7 @@ struct hb_vector_t return false; if (size > len) - memset (arrayZ + len, 0, (size - len) * sizeof (*arrayZ)); + memset (arrayZ() + len, 0, (size - len) * sizeof (*arrayZ())); len = size; return true; @@ -135,12 +144,13 @@ struct hb_vector_t inline void remove (unsigned int i) { - if (unlikely (i >= len)) - return; - memmove (static_cast<void *> (&arrayZ[i]), - static_cast<void *> (&arrayZ[i + 1]), - (len - i - 1) * sizeof (Type)); - len--; + if (unlikely (i >= len)) + return; + Type *array = arrayZ(); + memmove (static_cast<void *> (&array[i]), + static_cast<void *> (&array[i + 1]), + (len - i - 1) * sizeof (Type)); + len--; } inline void shrink (int size_) @@ -151,41 +161,55 @@ struct hb_vector_t } template <typename T> - inline Type *find (T v) { + inline Type *find (T v) + { + Type *array = arrayZ(); for (unsigned int i = 0; i < len; i++) - if (arrayZ[i] == v) - return &arrayZ[i]; + if (array[i] == v) + return &array[i]; return nullptr; } template <typename T> - inline const Type *find (T v) const { + inline const Type *find (T v) const + { + const Type *array = arrayZ(); for (unsigned int i = 0; i < len; i++) - if (arrayZ[i] == v) - return &arrayZ[i]; + if (array[i] == v) + return &array[i]; return nullptr; } inline void qsort (int (*cmp)(const void*, const void*)) { - ::qsort (arrayZ, len, sizeof (Type), cmp); + ::qsort (arrayZ(), len, sizeof (Type), cmp); } inline void qsort (void) { - ::qsort (arrayZ, len, sizeof (Type), Type::cmp); + ::qsort (arrayZ(), len, sizeof (Type), Type::cmp); } inline void qsort (unsigned int start, unsigned int end) { - ::qsort (arrayZ + start, end - start, sizeof (Type), Type::cmp); + ::qsort (arrayZ() + start, end - start, sizeof (Type), Type::cmp); } template <typename T> inline Type *lsearch (const T &x) { + Type *array = arrayZ(); + for (unsigned int i = 0; i < len; i++) + if (0 == array[i].cmp (&x)) + return &array[i]; + return nullptr; + } + template <typename T> + inline const Type *lsearch (const T &x) const + { + const Type *array = arrayZ(); for (unsigned int i = 0; i < len; i++) - if (0 == this->arrayZ[i].cmp (&x)) - return &arrayZ[i]; + if (0 == array[i].cmp (&x)) + return &array[i]; return nullptr; } @@ -193,22 +217,23 @@ struct hb_vector_t inline Type *bsearch (const T &x) { unsigned int i; - return bfind (x, &i) ? &arrayZ[i] : nullptr; + return bfind (x, &i) ? &arrayZ()[i] : nullptr; } template <typename T> inline const Type *bsearch (const T &x) const { unsigned int i; - return bfind (x, &i) ? &arrayZ[i] : nullptr; + return bfind (x, &i) ? &arrayZ()[i] : nullptr; } template <typename T> inline bool bfind (const T &x, unsigned int *i) const { int min = 0, max = (int) this->len - 1; + const Type *array = this->arrayZ(); while (min <= max) { int mid = (min + max) / 2; - int c = this->arrayZ[mid].cmp (&x); + int c = array[mid].cmp (&x); if (c < 0) max = mid - 1; else if (c > 0) @@ -219,20 +244,29 @@ struct hb_vector_t return true; } } - if (max < 0 || (max < (int) this->len && this->arrayZ[max].cmp (&x) > 0)) + if (max < 0 || (max < (int) this->len && array[max].cmp (&x) > 0)) max++; *i = max; return false; } + inline void fini_deep (void) + { + Type *array = arrayZ(); + unsigned int count = len; + for (unsigned int i = 0; i < count; i++) + array[i].fini (); + fini (); + } + inline void fini (void) { - if (arrayZ != static_array) - free (arrayZ); - arrayZ = nullptr; + if (arrayZ_) + free (arrayZ_); + arrayZ_ = nullptr; allocated = len = 0; } }; -#endif /* HB_VECTOR_PRIVATE_HH */ +#endif /* HB_VECTOR_HH */ diff --git a/src/hb-version.h b/src/hb-version.h index e0816d1e6..a8db51606 100644 --- a/src/hb-version.h +++ b/src/hb-version.h @@ -36,11 +36,11 @@ HB_BEGIN_DECLS -#define HB_VERSION_MAJOR 1 -#define HB_VERSION_MINOR 8 -#define HB_VERSION_MICRO 8 +#define HB_VERSION_MAJOR 2 +#define HB_VERSION_MINOR 0 +#define HB_VERSION_MICRO 2 -#define HB_VERSION_STRING "1.8.8" +#define HB_VERSION_STRING "2.0.2" #define HB_VERSION_ATLEAST(major,minor,micro) \ ((major)*10000+(minor)*100+(micro) <= \ diff --git a/src/hb-warning.cc b/src/hb-warning.cc index f7a87b5ab..9fb410038 100644 --- a/src/hb-warning.cc +++ b/src/hb-warning.cc @@ -24,14 +24,14 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-private.hh" +#include "hb.hh" #if defined(HB_ATOMIC_INT_NIL) #error "Could not find any system to define atomic_int macros, library WILL NOT be thread-safe" -#error "Check hb-atomic-private.hh for possible resolutions." +#error "Check hb-atomic.hh for possible resolutions." #endif #if defined(HB_MUTEX_IMPL_NIL) #error "Could not find any system to define mutex macros, library WILL NOT be thread-safe" -#error "Check hb-mutex-private.hh for possible resolutions." +#error "Check hb-mutex.hh for possible resolutions." #endif diff --git a/src/hb-private.hh b/src/hb.hh index efe7bda9e..098b56604 100644 --- a/src/hb-private.hh +++ b/src/hb.hh @@ -26,8 +26,8 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_PRIVATE_HH -#define HB_PRIVATE_HH +#ifndef HB_HH +#define HB_HH #define _GNU_SOURCE 1 @@ -35,12 +35,18 @@ #include "config.h" #endif +#ifndef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE 200809L +#endif + +#if defined (_MSC_VER) && defined (HB_DLL_EXPORT) +#define HB_EXTERN __declspec (dllexport) extern +#endif + #include "hb.h" #define HB_H_IN -#ifdef HAVE_OT #include "hb-ot.h" #define HB_OT_H_IN -#endif #include <math.h> #include <stdlib.h> @@ -174,8 +180,10 @@ struct _hb_alignof # if !defined(HB_NO_VISIBILITY) && !defined(__MINGW32__) && !defined(__CYGWIN__) && !defined(_MSC_VER) && !defined(__SUNPRO_CC) # define HB_INTERNAL __attribute__((__visibility__("hidden"))) # elif defined(__MINGW32__) - /* We use -export-symbols on mingw32, since it does not support visibility - * attribute. */ + /* We use -export-symbols on mingw32, since it does not support visibility attributes. */ +# define HB_INTERNAL +# elif defined (_MSC_VER) && defined (HB_DLL_EXPORT) + /* We do not try to export internal symbols on Visual Studio */ # define HB_INTERNAL #else # define HB_INTERNAL @@ -229,6 +237,15 @@ struct _hb_alignof # define HB_FALLTHROUGH /* FALLTHROUGH */ #endif +#if defined(__clang__) +/* Disable certain sanitizer errors. */ +/* https://github.com/harfbuzz/harfbuzz/issues/1247 */ +#define HB_NO_SANITIZE_SIGNED_INTEGER_OVERFLOW __attribute__((no_sanitize("signed-integer-overflow"))) +#else +#define HB_NO_SANITIZE_SIGNED_INTEGER_OVERFLOW +#endif + + #if defined(_WIN32) || defined(__CYGWIN__) /* We need Windows Vista for both Uniscribe backend and for * MemoryBarrier. We don't support compiling on Windows XP, @@ -237,7 +254,9 @@ struct _hb_alignof # undef _WIN32_WINNT # endif # ifndef _WIN32_WINNT -# define _WIN32_WINNT 0x0600 +# if !defined(WINAPI_FAMILY) || !(WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP) +# define _WIN32_WINNT 0x0600 +# endif # endif # ifndef WIN32_LEAN_AND_MEAN # define WIN32_LEAN_AND_MEAN 1 @@ -468,13 +487,21 @@ _hb_memalign(void **memptr, size_t alignment, size_t size) #endif +/* + * For lack of a better place, put Zawgyi script hack here. + * https://github.com/harfbuzz/harfbuzz/issues/1162 + */ + +#define HB_SCRIPT_MYANMAR_ZAWGYI ((hb_script_t) HB_TAG ('Q','a','a','g')) + + /* Headers we include for everyone. Keep sorted. They express dependency amongst * themselves, but no other file should include them.*/ -#include "hb-atomic-private.hh" +#include "hb-atomic.hh" #include "hb-debug.hh" #include "hb-dsalgs.hh" -#include "hb-mutex-private.hh" +#include "hb-mutex.hh" #include "hb-null.hh" -#include "hb-object-private.hh" +#include "hb-object.hh" -#endif /* HB_PRIVATE_HH */ +#endif /* HB_HH */ diff --git a/src/main.cc b/src/main.cc index 98a1320bf..490b76e5b 100644 --- a/src/main.cc +++ b/src/main.cc @@ -25,9 +25,9 @@ */ #include "hb-static.cc" -#include "hb-open-file-private.hh" +#include "hb-open-file.hh" #include "hb-ot-layout-gdef-table.hh" -#include "hb-ot-layout-gsubgpos-private.hh" +#include "hb-ot-layout-gsubgpos.hh" #ifdef HAVE_GLIB #include <glib.h> diff --git a/src/sample.py b/src/sample.py index 8f97195f2..5d65aa09e 100755 --- a/src/sample.py +++ b/src/sample.py @@ -54,11 +54,11 @@ if False: # buffer: hb.buffer_add_utf8 (buf, text.encode('utf-8'), 0, -1) # Otherwise, then following handles both narrow and wide - # Python builds: + # Python builds (the first item in the array is BOM, so we skip it): elif sys.maxunicode == 0x10FFFF: - hb.buffer_add_utf32 (buf, array.array('I', text.encode('utf-32')), 0, -1) + hb.buffer_add_utf32 (buf, array.array('I', text.encode('utf-32'))[1:], 0, -1) else: - hb.buffer_add_utf16 (buf, array.array('H', text.encode('utf-16')), 0, -1) + hb.buffer_add_utf16 (buf, array.array('H', text.encode('utf-16'))[1:], 0, -1) hb.buffer_guess_segment_properties (buf) diff --git a/src/test-buffer-serialize.cc b/src/test-buffer-serialize.cc index 39eb13da7..a91f4f7e9 100644 --- a/src/test-buffer-serialize.cc +++ b/src/test-buffer-serialize.cc @@ -24,7 +24,7 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-private.hh" +#include "hb.hh" #include "hb.h" #include "hb-ot.h" diff --git a/src/test-size-params.cc b/src/test-size-params.cc index 3c43852b3..e53a47d8d 100644 --- a/src/test-size-params.cc +++ b/src/test-size-params.cc @@ -24,7 +24,7 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-private.hh" +#include "hb.hh" #include "hb.h" #include "hb-ot.h" diff --git a/src/test-unicode-ranges.cc b/src/test-unicode-ranges.cc index dbc5fa426..d9342d7bb 100644 --- a/src/test-unicode-ranges.cc +++ b/src/test-unicode-ranges.cc @@ -24,24 +24,24 @@ * Google Author(s): Garret Rieger */ -#include "hb-private.hh" +#include "hb.hh" #include "hb-ot-os2-unicode-ranges.hh" -void +static void test (hb_codepoint_t cp, unsigned int bit) { - if (OT::hb_get_unicode_range_bit (cp) != bit) + if (OT::_hb_ot_os2_get_unicode_range_bit (cp) != bit) { fprintf (stderr, "got incorrect bit (%d) for cp 0x%X. Should have been %d.", - OT::hb_get_unicode_range_bit (cp), + OT::_hb_ot_os2_get_unicode_range_bit (cp), cp, bit); abort(); } } -void +static void test_get_unicode_range_bit (void) { test (0x0000, 0); diff --git a/src/test-would-substitute.cc b/src/test-would-substitute.cc index 1836d720c..268f7db98 100644 --- a/src/test-would-substitute.cc +++ b/src/test-would-substitute.cc @@ -24,7 +24,7 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-private.hh" +#include "hb.hh" #include "hb.h" #include "hb-ot.h" diff --git a/src/test.cc b/src/test.cc index cf59e00ac..f0eace8c4 100644 --- a/src/test.cc +++ b/src/test.cc @@ -24,7 +24,7 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-private.hh" +#include "hb.hh" #include "hb.h" diff --git a/test/api/CMakeLists.txt b/test/api/CMakeLists.txt index b540eb505..0c7337cb5 100644 --- a/test/api/CMakeLists.txt +++ b/test/api/CMakeLists.txt @@ -3,6 +3,8 @@ if (HB_HAVE_GLIB) extract_make_variable (TEST_PROGS ${MAKEFILEAM}) list (APPEND TEST_PROGS + test-ot-color + test-ot-name test-ot-tag test-c test-cplusplus diff --git a/test/api/Makefile.am b/test/api/Makefile.am index a20334498..45a34e64d 100644 --- a/test/api/Makefile.am +++ b/test/api/Makefile.am @@ -16,6 +16,8 @@ EXTRA_DIST += CMakeLists.txt EXTRA_DIST += fonts +LINK = $(CXXLINK) + if HAVE_GLIB AM_CPPFLAGS = -DSRCDIR="\"$(srcdir)\"" -I$(top_srcdir)/src/ -I$(top_builddir)/src/ $(GLIB_CFLAGS) LDADD = $(top_builddir)/src/libharfbuzz.la $(GLIB_LIBS) @@ -28,13 +30,14 @@ noinst_PROGRAMS = $(TEST_PROGS) TEST_PROGS = \ test-blob \ test-buffer \ + test-collect-unicodes \ test-common \ test-font \ + test-map \ test-object \ test-set \ test-shape \ test-subset \ - test-subset-codepoints \ test-subset-cmap \ test-subset-glyf \ test-subset-hdmx \ @@ -67,13 +70,24 @@ test_unicode_LDADD += $(top_builddir)/src/libharfbuzz-icu.la $(ICU_LIBS) endif -if HAVE_OT - TEST_PROGS += \ test-ot-color \ + test-ot-name \ test-ot-tag \ $(NULL) + +if HAVE_PTHREAD +if HAVE_FREETYPE +TEST_PROGS += test-multithread +test_multithread_CFLAGS = $(CFLAGS) $(PTHREAD_CFLAGS) $(FREETYPE_CFLAGS) +test_multithread_LDADD = $(LDADD) $(PTHREAD_LIBS) $(FREETYPE_LIBS) +# The auto-generated link rule somehow includes CFLAGS as well. Without +# it, pthread link fails, because, who knows why, $PTHREAD_LIBS is empty. +test_multithread_LINK = $(LINK) $(PTHREAD_CFLAGS) +endif +endif + if HAVE_FREETYPE TEST_PROGS += \ test-ot-math \ @@ -82,7 +96,6 @@ test_ot_math_LDADD = $(LDADD) $(FREETYPE_LIBS) test_ot_math_CPPFLAGS = $(AM_CPPFLAGS) $(FREETYPE_CFLAGS) endif # HAVE_FREETYPE -endif # HAVE_OT # Tests for header compilation TEST_PROGS += \ @@ -154,13 +167,18 @@ symbols-tested.txt: $(TEST_PROGS) $(AM_V_GEN)$(top_builddir)/libtool --mode=execute nm $^ \ | grep ' U hb_' | sed 's/.* U hb_/hb_/' \ | sort | uniq > $@.tmp && mv $@.tmp $@ +symbols-tested-or-deprecated.txt: symbols-tested.txt $(top_builddir)/src/harfbuzz-deprecated.def + $(AM_V_GEN)cat $^ | sort | uniq > $@.tmp; mv $@.tmp $@ symbols-exported.txt: $(top_builddir)/src/.libs/libharfbuzz.so $(AM_V_GEN)$(top_builddir)/libtool --mode=execute nm $^ \ | grep ' T ' | sed 's/.* T //' | grep -v '^\(_init\|_fini\)$$' \ | sort | uniq > $@.tmp && mv $@.tmp $@ -symbols-untested.txt: symbols-tested.txt symbols-exported.txt +symbols-untested.txt: symbols-tested-or-deprecated.txt symbols-exported.txt $(AM_V_GEN)diff $^ > $@.tmp; mv $@.tmp $@ -CLEANFILES += symbols-tested.txt symbols-exported.txt symbols-untested.txt +CLEANFILES += symbols-tested.txt \ + symbols-exported.txt \ + symbols-untested.txt \ + symbols-tested-or-deprecated.txt check-symbols: symbols-untested.txt @! cat $^ | grep . diff --git a/test/api/fonts/Roboto-Regular.multihdmx.a.ttf b/test/api/fonts/Roboto-Regular.multihdmx.a.ttf Binary files differnew file mode 100644 index 000000000..dd82178fd --- /dev/null +++ b/test/api/fonts/Roboto-Regular.multihdmx.a.ttf diff --git a/test/api/fonts/Roboto-Regular.multihdmx.abc.ttf b/test/api/fonts/Roboto-Regular.multihdmx.abc.ttf Binary files differnew file mode 100644 index 000000000..03dd8b6b7 --- /dev/null +++ b/test/api/fonts/Roboto-Regular.multihdmx.abc.ttf diff --git a/test/api/fonts/cv01.otf b/test/api/fonts/cv01.otf Binary files differnew file mode 100644 index 000000000..01dbf01f3 --- /dev/null +++ b/test/api/fonts/cv01.otf diff --git a/test/api/hb-subset-test.h b/test/api/hb-subset-test.h index c34f394b9..5f5cd8d00 100644 --- a/test/api/hb-subset-test.h +++ b/test/api/hb-subset-test.h @@ -51,12 +51,21 @@ static inline hb_face_t * hb_subset_test_open_font (const char *font_path) { #if GLIB_CHECK_VERSION(2,37,2) - char* path = g_test_build_filename(G_TEST_DIST, font_path, NULL); + char *path = g_test_build_filename (G_TEST_DIST, font_path, NULL); #else - char* path = g_strdup(font_path); + char *path = g_strdup (font_path); #endif - return hb_face_create (hb_blob_create_from_file (path), 0); + hb_blob_t *blob = hb_blob_create_from_file (path); + if (hb_blob_get_length (blob) == 0) + g_error ("Font not found."); + + hb_face_t *face = hb_face_create (blob, 0); + hb_blob_destroy (blob); + + g_free (path); + + return face; } static inline hb_subset_input_t * @@ -72,11 +81,9 @@ static inline hb_face_t * hb_subset_test_create_subset (hb_face_t *source, hb_subset_input_t *input) { - hb_subset_profile_t *profile = hb_subset_profile_create(); - hb_face_t *subset = hb_subset (source, profile, input); + hb_face_t *subset = hb_subset (source, input); g_assert (subset); - hb_subset_profile_destroy (profile); hb_subset_input_destroy (input); return subset; } diff --git a/test/api/hb-test.h b/test/api/hb-test.h index 307845f62..39d091b60 100644 --- a/test/api/hb-test.h +++ b/test/api/hb-test.h @@ -42,6 +42,7 @@ HB_BEGIN_DECLS /* Just in case */ #undef G_DISABLE_ASSERT +#define HB_UNUSED G_GNUC_UNUSED /* Misc */ diff --git a/test/api/test-blob.c b/test/api/test-blob.c index d566f4e9d..7914a26ce 100644 --- a/test/api/test-blob.c +++ b/test/api/test-blob.c @@ -195,7 +195,7 @@ fixture_init (fixture_t *fixture, gconstpointer user_data) } static void -fixture_finish (fixture_t *fixture, gconstpointer user_data) +fixture_finish (fixture_t *fixture, gconstpointer user_data HB_UNUSED) { hb_blob_destroy (fixture->blob); g_assert_cmpint (fixture->freed, ==, 1); diff --git a/test/api/test-buffer.c b/test/api/test-buffer.c index 5c98a9a16..5fba3b228 100644 --- a/test/api/test-buffer.c +++ b/test/api/test-buffer.c @@ -92,14 +92,14 @@ fixture_init (fixture_t *fixture, gconstpointer user_data) } static void -fixture_finish (fixture_t *fixture, gconstpointer user_data) +fixture_finish (fixture_t *fixture, gconstpointer user_data HB_UNUSED) { hb_buffer_destroy (fixture->buffer); } static void -test_buffer_properties (fixture_t *fixture, gconstpointer user_data) +test_buffer_properties (fixture_t *fixture, gconstpointer user_data HB_UNUSED) { hb_buffer_t *b = fixture->buffer; hb_unicode_funcs_t *ufuncs; @@ -294,7 +294,7 @@ test_buffer_contents (fixture_t *fixture, gconstpointer user_data) } static void -test_buffer_positions (fixture_t *fixture, gconstpointer user_data) +test_buffer_positions (fixture_t *fixture, gconstpointer user_data HB_UNUSED) { hb_buffer_t *b = fixture->buffer; unsigned int i, len, len2; @@ -319,7 +319,7 @@ test_buffer_positions (fixture_t *fixture, gconstpointer user_data) } static void -test_buffer_allocation (fixture_t *fixture, gconstpointer user_data) +test_buffer_allocation (fixture_t *fixture, gconstpointer user_data HB_UNUSED) { hb_buffer_t *b = fixture->buffer; diff --git a/test/api/test-c.c b/test/api/test-c.c index 4b43b8379..061f35cdc 100644 --- a/test/api/test-c.c +++ b/test/api/test-c.c @@ -32,6 +32,7 @@ #endif #include <hb.h> +#include <hb-ot.h> #ifdef HAVE_GLIB #include <hb-glib.h> @@ -45,10 +46,6 @@ #include <hb-ft.h> #endif -#ifdef HAVE_OT -#include <hb-ot.h> -#endif - #ifdef HAVE_UNISCRIBE #include <hb-uniscribe.h> #endif @@ -58,7 +55,7 @@ #endif int -main (int argc, char **argv) +main (void) { return !*hb_shape_list_shapers (); } diff --git a/test/api/test-subset-codepoints.c b/test/api/test-collect-unicodes.c index 3bd1fe062..f7a781302 100644 --- a/test/api/test-subset-codepoints.c +++ b/test/api/test-collect-unicodes.c @@ -28,14 +28,15 @@ #include "hb-subset-test.h" static void -test_get_all_codepoints_format4 (void) +test_collect_unicodes_format4 (void) { hb_face_t *face = hb_subset_test_open_font("fonts/Roboto-Regular.abc.format4.ttf"); hb_set_t *codepoints = hb_set_create(); + hb_codepoint_t cp; - hb_subset_get_all_codepoints (face, codepoints); + hb_face_collect_unicodes (face, codepoints); - hb_codepoint_t cp = HB_SET_VALUE_INVALID; + cp = HB_SET_VALUE_INVALID; g_assert (hb_set_next (codepoints, &cp)); g_assert_cmpuint (0x61, ==, cp); g_assert (hb_set_next (codepoints, &cp)); @@ -49,14 +50,15 @@ test_get_all_codepoints_format4 (void) } static void -test_get_all_codepoints_format12 (void) +test_collect_unicodes_format12 (void) { hb_face_t *face = hb_subset_test_open_font("fonts/Roboto-Regular.abc.format12.ttf"); hb_set_t *codepoints = hb_set_create(); + hb_codepoint_t cp; - hb_subset_get_all_codepoints (face, codepoints); + hb_face_collect_unicodes (face, codepoints); - hb_codepoint_t cp = HB_SET_VALUE_INVALID; + cp = HB_SET_VALUE_INVALID; g_assert (hb_set_next (codepoints, &cp)); g_assert_cmpuint (0x61, ==, cp); g_assert (hb_set_next (codepoints, &cp)); @@ -70,14 +72,15 @@ test_get_all_codepoints_format12 (void) } static void -test_get_all_codepoints (void) +test_collect_unicodes (void) { hb_face_t *face = hb_subset_test_open_font("fonts/Roboto-Regular.abc.ttf"); hb_set_t *codepoints = hb_set_create(); + hb_codepoint_t cp; - hb_subset_get_all_codepoints (face, codepoints); + hb_face_collect_unicodes (face, codepoints); - hb_codepoint_t cp = HB_SET_VALUE_INVALID; + cp = HB_SET_VALUE_INVALID; g_assert (hb_set_next (codepoints, &cp)); g_assert_cmpuint (0x61, ==, cp); g_assert (hb_set_next (codepoints, &cp)); @@ -95,9 +98,9 @@ main (int argc, char **argv) { hb_test_init (&argc, &argv); - hb_test_add (test_get_all_codepoints); - hb_test_add (test_get_all_codepoints_format4); - hb_test_add (test_get_all_codepoints_format12); + hb_test_add (test_collect_unicodes); + hb_test_add (test_collect_unicodes_format4); + hb_test_add (test_collect_unicodes_format12); return hb_test_run(); } diff --git a/test/api/test-common.c b/test/api/test-common.c index f6f0d4851..e9fae1351 100644 --- a/test/api/test-common.c +++ b/test/api/test-common.c @@ -32,7 +32,6 @@ static void test_types_int (void) { - /* We already ASSERT_STATIC these in hb-private.h, but anyway */ g_assert_cmpint (sizeof (int8_t), ==, 1); g_assert_cmpint (sizeof (uint8_t), ==, 1); g_assert_cmpint (sizeof (int16_t), ==, 2); diff --git a/test/api/test-font.c b/test/api/test-font.c index 527dfcdc1..3d81cf961 100644 --- a/test/api/test-font.c +++ b/test/api/test-font.c @@ -83,7 +83,7 @@ free_up (void *user_data) } static hb_blob_t * -get_table (hb_face_t *face, hb_tag_t tag, void *user_data) +get_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data HB_UNUSED) { if (tag == HB_TAG ('a','b','c','d')) return hb_blob_create (test_data, sizeof (test_data), HB_MEMORY_MODE_READONLY, NULL, NULL); @@ -210,10 +210,10 @@ test_fontfuncs_nil (void) } static hb_bool_t -contour_point_func1 (hb_font_t *font, void *font_data, - hb_codepoint_t glyph, unsigned int point_index, +contour_point_func1 (hb_font_t *font HB_UNUSED, void *font_data HB_UNUSED, + hb_codepoint_t glyph, unsigned int point_index HB_UNUSED, hb_position_t *x, hb_position_t *y, - void *user_data) + void *user_data HB_UNUSED) { if (glyph == 1) { *x = 2; @@ -230,10 +230,10 @@ contour_point_func1 (hb_font_t *font, void *font_data, } static hb_bool_t -contour_point_func2 (hb_font_t *font, void *font_data, +contour_point_func2 (hb_font_t *font, void *font_data HB_UNUSED, hb_codepoint_t glyph, unsigned int point_index, hb_position_t *x, hb_position_t *y, - void *user_data) + void *user_data HB_UNUSED) { if (glyph == 1) { *x = 6; @@ -246,9 +246,9 @@ contour_point_func2 (hb_font_t *font, void *font_data, } static hb_position_t -glyph_h_advance_func1 (hb_font_t *font, void *font_data, +glyph_h_advance_func1 (hb_font_t *font HB_UNUSED, void *font_data HB_UNUSED, hb_codepoint_t glyph, - void *user_data) + void *user_data HB_UNUSED) { if (glyph == 1) return 8; @@ -361,8 +361,74 @@ test_fontfuncs_subclassing (void) hb_font_destroy (font3); + hb_font_destroy (font2); +} + +static hb_bool_t +nominal_glyph_func (hb_font_t *font HB_UNUSED, + void *font_data HB_UNUSED, + hb_codepoint_t unicode HB_UNUSED, + hb_codepoint_t *glyph, + void *user_data HB_UNUSED) +{ + *glyph = 0; + return FALSE; +} + +static unsigned int +nominal_glyphs_func (hb_font_t *font HB_UNUSED, + void *font_data HB_UNUSED, + unsigned int count HB_UNUSED, + const hb_codepoint_t *first_unicode HB_UNUSED, + unsigned int unicode_stride HB_UNUSED, + hb_codepoint_t *first_glyph HB_UNUSED, + unsigned int glyph_stride HB_UNUSED, + void *user_data HB_UNUSED) +{ + return 0; } +static void +test_fontfuncs_parallels (void) +{ + hb_blob_t *blob; + hb_face_t *face; + + hb_font_funcs_t *ffuncs1; + hb_font_funcs_t *ffuncs2; + + hb_font_t *font0; + hb_font_t *font1; + hb_font_t *font2; + + blob = hb_blob_create (test_data, sizeof (test_data), HB_MEMORY_MODE_READONLY, NULL, NULL); + face = hb_face_create (blob, 0); + hb_blob_destroy (blob); + font0 = hb_font_create (face); + hb_face_destroy (face); + + /* setup sub-font1 */ + font1 = hb_font_create_sub_font (font0); + hb_font_destroy (font0); + ffuncs1 = hb_font_funcs_create (); + hb_font_funcs_set_nominal_glyph_func (ffuncs1, nominal_glyph_func, NULL, NULL); + hb_font_set_funcs (font1, ffuncs1, NULL, NULL); + hb_font_funcs_destroy (ffuncs1); + + /* setup sub-font2 */ + font2 = hb_font_create_sub_font (font1); + hb_font_destroy (font1); + ffuncs2 = hb_font_funcs_create (); + hb_font_funcs_set_nominal_glyphs_func (ffuncs1, nominal_glyphs_func, NULL, NULL); + hb_font_set_funcs (font2, ffuncs2, NULL, NULL); + hb_font_funcs_destroy (ffuncs2); + + /* Just test that calling get_nominal_glyph doesn't infinite-loop. */ + hb_codepoint_t glyph; + hb_font_get_nominal_glyph (font2, 0x0020u, &glyph); + + hb_font_destroy (font2); +} static void test_font_empty (void) @@ -542,6 +608,7 @@ main (int argc, char **argv) hb_test_add (test_fontfuncs_empty); hb_test_add (test_fontfuncs_nil); hb_test_add (test_fontfuncs_subclassing); + hb_test_add (test_fontfuncs_parallels); hb_test_add (test_font_empty); hb_test_add (test_font_properties); diff --git a/test/api/test-map.c b/test/api/test-map.c new file mode 100644 index 000000000..0d8be0bbb --- /dev/null +++ b/test/api/test-map.c @@ -0,0 +1,114 @@ +/* + * Copyright © 2018 Ebrahim Byagowi + * + * 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. + */ + +#include "hb-test.h" + +/* Unit tests for hb-map.h */ + + +static void +test_map_basic (void) +{ + hb_map_t *empty = hb_map_get_empty (); + g_assert (hb_map_is_empty (empty)); + g_assert (!hb_map_allocation_successful (empty)); + hb_map_destroy (empty); + + hb_map_t *m = hb_map_create (); + g_assert (hb_map_allocation_successful (m)); + g_assert (hb_map_is_empty (m)); + + hb_map_set (m, 213, 223); + hb_map_set (m, 643, 675); + g_assert_cmpint (hb_map_get_population (m), ==, 2); + + g_assert_cmpint (hb_map_get (m, 213), ==, 223); + g_assert (!hb_map_has (m, 123)); + g_assert (hb_map_has (m, 213)); + + hb_map_del (m, 213); + g_assert (!hb_map_has (m, 213)); + + g_assert_cmpint (hb_map_get (m, 643), ==, 675); + hb_map_set (m, 237, 673); + g_assert (hb_map_has (m, 237)); + hb_map_clear (m); + g_assert (!hb_map_has (m, 237)); + g_assert (!hb_map_has (m, 643)); + g_assert_cmpint (hb_map_get_population (m), ==, 0); + + hb_map_destroy (m); +} + +static void +test_map_userdata (void) +{ + hb_map_t *m = hb_map_create (); + + hb_user_data_key_t key[2]; + int *data = (int *) malloc (sizeof (int)); + *data = 3123; + hb_map_set_user_data (m, &key[0], data, free, TRUE); + g_assert_cmpint (*((int *) hb_map_get_user_data (m, &key[0])), ==, 3123); + + int *data2 = (int *) malloc (sizeof (int)); + *data2 = 6343; + hb_map_set_user_data (m, &key[0], data2, free, FALSE); + g_assert_cmpint (*((int *) hb_map_get_user_data (m, &key[0])), ==, 3123); + hb_map_set_user_data (m, &key[0], data2, free, TRUE); + g_assert_cmpint (*((int *) hb_map_get_user_data (m, &key[0])), ==, 6343); + + hb_map_destroy (m); +} + +static void +test_map_refcount (void) +{ + hb_map_t *m = hb_map_create (); + hb_map_set (m, 213, 223); + g_assert_cmpint (hb_map_get (m, 213), ==, 223); + + hb_map_t *m2 = hb_map_reference (m); + hb_map_destroy (m); + + /* We copied its reference so it is still usable after one destroy */ + g_assert (hb_map_has (m, 213)); + g_assert (hb_map_has (m2, 213)); + + hb_map_destroy (m2); + + /* Now you can't access them anymore */ +} + +int +main (int argc, char **argv) +{ + hb_test_init (&argc, &argv); + + hb_test_add (test_map_basic); + hb_test_add (test_map_userdata); + hb_test_add (test_map_refcount); + + return hb_test_run(); +} diff --git a/test/api/test-multithread.c b/test/api/test-multithread.c new file mode 100644 index 000000000..7b62a0298 --- /dev/null +++ b/test/api/test-multithread.c @@ -0,0 +1,178 @@ +/* + * Copyright © 2018 Ebrahim Byagowi + * + * 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. + * + */ + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> + +#include <pthread.h> + +#include <hb.h> +#include <hb-ft.h> +#include <hb-ot.h> +#include <glib.h> + +static const char *font_path = "fonts/Inconsolata-Regular.abc.ttf"; +static const char *text = "abc"; + +static int num_threads = 30; +static int num_iters = 200; + +static hb_font_t *font; +static hb_buffer_t *ref_buffer; + +static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + +static void +fill_the_buffer (hb_buffer_t *buffer) +{ + hb_buffer_add_utf8 (buffer, text, -1, 0, -1); + hb_buffer_guess_segment_properties (buffer); + hb_shape (font, buffer, NULL, 0); +} + +static void +validity_check (hb_buffer_t *buffer) { + if (hb_buffer_diff (ref_buffer, buffer, (hb_codepoint_t) -1, 0)) + { + fprintf (stderr, "One of the buffers was different from the reference.\n"); + char out[255]; + + hb_buffer_serialize_glyphs (buffer, 0, hb_buffer_get_length (ref_buffer), + out, sizeof (out), NULL, + font, HB_BUFFER_SERIALIZE_FORMAT_TEXT, + HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES); + fprintf (stderr, "Actual: %s\n", out); + + hb_buffer_serialize_glyphs (ref_buffer, 0, hb_buffer_get_length (ref_buffer), + out, sizeof (out), NULL, + font, HB_BUFFER_SERIALIZE_FORMAT_TEXT, + HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES); + fprintf (stderr, "Expected: %s\n", out); + + exit (1); + } +} + +static void * +thread_func (void *data) +{ + hb_buffer_t *buffer = (hb_buffer_t *) data; + + pthread_mutex_lock (&mutex); + pthread_mutex_unlock (&mutex); + + int i; + for (i = 0; i < num_iters; i++) + { + hb_buffer_clear_contents (buffer); + fill_the_buffer (buffer); + validity_check (buffer); + } + + return 0; +} + +static void +test_body (void) +{ + int i; + pthread_t *threads = calloc (num_threads, sizeof (pthread_t)); + hb_buffer_t **buffers = calloc (num_threads, sizeof (hb_buffer_t *)); + + pthread_mutex_lock (&mutex); + + for (i = 0; i < num_threads; i++) + { + hb_buffer_t *buffer = hb_buffer_create (); + buffers[i] = buffer; + pthread_create (&threads[i], NULL, thread_func, buffer); + } + + /* Let them loose! */ + pthread_mutex_unlock (&mutex); + + for (i = 0; i < num_threads; i++) + { + pthread_join (threads[i], NULL); + hb_buffer_destroy (buffers[i]); + } + + free (buffers); + free (threads); +} + +int +main (int argc, char **argv) +{ + g_test_init (&argc, &argv, NULL); + +#if GLIB_CHECK_VERSION(2,37,2) + gchar *default_path = g_test_build_filename (G_TEST_DIST, font_path, NULL); +#else + gchar *default_path = g_strdup (font_path); +#endif + + char *path = argc > 1 && *argv[1] ? argv[1] : (char *) default_path; + if (argc > 2) + num_threads = atoi (argv[2]); + if (argc > 3) + num_iters = atoi (argv[3]); + if (argc > 4) + text = argv[4]; + + /* Dummy call to alleviate _guess_segment_properties thread safety-ness + * https://github.com/harfbuzz/harfbuzz/issues/1191 */ + hb_language_get_default (); + + hb_blob_t *blob = hb_blob_create_from_file (path); + if (hb_blob_get_length (blob) == 0) + g_error ("Font not found."); + + hb_face_t *face = hb_face_create (blob, 0); + font = hb_font_create (face); + + /* Fill the reference */ + ref_buffer = hb_buffer_create (); + fill_the_buffer (ref_buffer); + + /* Unnecessary, since version 2 it is ot-font by default */ + hb_ot_font_set_funcs (font); + test_body (); + + /* Test hb-ft in multithread */ + hb_ft_font_set_funcs (font); + test_body (); + + hb_buffer_destroy (ref_buffer); + + hb_font_destroy (font); + hb_face_destroy (face); + hb_blob_destroy (blob); + + g_free (default_path); + + return 0; +} diff --git a/test/api/test-ot-color.c b/test/api/test-ot-color.c index 22584d20e..254f01556 100644 --- a/test/api/test-ot-color.c +++ b/test/api/test-ot-color.c @@ -99,6 +99,7 @@ static hb_face_t *cpal_v0 = NULL; static hb_face_t *cpal_v1 = NULL; +#if 0 #define assert_color_rgba(colors, i, r, g, b, a) G_STMT_START { \ const hb_ot_color_t *_colors = (colors); \ const size_t _i = (i); \ @@ -122,7 +123,6 @@ static hb_face_t *cpal_v1 = NULL; } G_STMT_END -#if 0 static void test_hb_ot_color_get_palette_count (void) { diff --git a/test/api/test-ot-math.c b/test/api/test-ot-math.c index d071c8895..7f500157e 100644 --- a/test/api/test-ot-math.c +++ b/test/api/test-ot-math.c @@ -100,10 +100,14 @@ test_has_data (void) hb_face = hb_face_get_empty (); hb_font = hb_font_create (hb_face); g_assert(!hb_ot_math_has_data (hb_face)); // MATH table not available + hb_font_destroy (hb_font); + hb_face_destroy (hb_face); hb_font = hb_font_get_empty (); hb_face = hb_font_get_face (hb_font); g_assert(!hb_ot_math_has_data (hb_face)); // MATH table not available + hb_font_destroy (hb_font); + hb_face_destroy (hb_face); cleanupFreeType(); } diff --git a/test/api/test-ot-name.c b/test/api/test-ot-name.c new file mode 100644 index 000000000..2da504acc --- /dev/null +++ b/test/api/test-ot-name.c @@ -0,0 +1,102 @@ +/* + * Copyright © 2018 Ebrahim Byagowi + * + * 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. + * + */ + +#include "hb-test.h" + +#include <hb-ot.h> + +static const char *font_path = "fonts/cv01.otf"; +static hb_face_t *face; + +static void +test_ot_layout_feature_get_name_ids_and_characters (void) +{ + hb_tag_t cv01 = HB_TAG ('c','v','0','1'); + unsigned int feature_index; + if (!hb_ot_layout_language_find_feature (face, + HB_OT_TAG_GSUB, + 0, + HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX, + cv01, + &feature_index)) + g_error ("Failed to find feature index"); + + hb_name_id_t label_id; + hb_name_id_t tooltip_id; + hb_name_id_t sample_id; + unsigned int num_named_parameters; + hb_name_id_t first_param_id; + if (!hb_ot_layout_feature_get_name_ids (face, HB_OT_TAG_GSUB, feature_index, + &label_id, &tooltip_id, &sample_id, + &num_named_parameters, &first_param_id)) + g_error ("Failed to get name ids"); + + g_assert_cmpint (label_id, ==, 256); + g_assert_cmpint (tooltip_id, ==, 257); + g_assert_cmpint (sample_id, ==, 258); + g_assert_cmpint (num_named_parameters, ==, 2); + g_assert_cmpint (first_param_id, ==, 259); + + hb_codepoint_t characters[100]; + unsigned int char_count = 100; + + unsigned int all_chars; + all_chars = hb_ot_layout_feature_get_characters (face, HB_OT_TAG_GSUB, feature_index, + 0, &char_count, characters); + + g_assert_cmpint (all_chars, ==, 2); + g_assert_cmpint (char_count, ==, 2); + g_assert_cmpint (characters[0], ==, 10); + g_assert_cmpint (characters[1], ==, 24030); +} + +int +main (int argc, char **argv) +{ + g_test_init (&argc, &argv, NULL); + +#if GLIB_CHECK_VERSION(2,37,2) + gchar *default_path = g_test_build_filename (G_TEST_DIST, font_path, NULL); +#else + gchar *default_path = g_strdup (font_path); +#endif + + hb_blob_t *blob; + + char *path = argc > 1 && *argv[1] ? argv[1] : (char *) default_path; + blob = hb_blob_create_from_file (path); + if (hb_blob_get_length (blob) == 0) + g_error ("Font not found."); + + face = hb_face_create (blob, 0); + + hb_test_add (test_ot_layout_feature_get_name_ids_and_characters); + + unsigned int result = hb_test_run (); + hb_face_destroy (face); + hb_blob_destroy (blob); + g_free (default_path); + return result; +} diff --git a/test/api/test-ot-tag.c b/test/api/test-ot-tag.c index e821b3625..f89c25deb 100644 --- a/test/api/test-ot-tag.c +++ b/test/api/test-ot-tag.c @@ -37,50 +37,86 @@ static void test_simple_tags (const char *s, hb_script_t script) { hb_script_t tag; - hb_tag_t t1, t2; + unsigned int count = 2; + hb_tag_t t[2]; g_test_message ("Testing script %c%c%c%c: tag %s", HB_UNTAG (hb_script_to_iso15924_tag (script)), s); tag = hb_tag_from_string (s, -1); - hb_ot_tags_from_script (script, &t1, &t2); + hb_ot_tags_from_script_and_language (script, + HB_LANGUAGE_INVALID, + &count, t, NULL, NULL); - g_assert_cmphex (t1, ==, tag); - g_assert_cmphex (t2, ==, HB_OT_TAG_DEFAULT_SCRIPT); + if (count) + g_assert_cmphex (t[0], ==, tag); + else + g_assert_cmphex (HB_TAG_CHAR4 ("DFLT"), ==, tag); g_assert_cmphex (hb_ot_tag_to_script (tag), ==, script); } static void -test_indic_tags (const char *s1, const char *s2, hb_script_t script) +test_script_tags_from_language (const char *s, const char *lang_s, hb_script_t script) { - hb_script_t tag1, tag2; - hb_script_t t1, t2; + hb_script_t tag; + unsigned int count = 1; + hb_script_t t; + + g_test_message ("Testing script %c%c%c%c: script tag %s, language tag %s", HB_UNTAG (hb_script_to_iso15924_tag (script)), s, lang_s); + tag = hb_tag_from_string (s, -1); + + hb_ot_tags_from_script_and_language (script, hb_language_from_string (lang_s, -1), &count, &t, NULL, NULL); - g_test_message ("Testing script %c%c%c%c: new tag %s, old tag %s", HB_UNTAG (hb_script_to_iso15924_tag (script)), s1, s2); + if (count != 0) + { + g_assert_cmpuint (count, ==, 1); + g_assert_cmphex (t, ==, tag); + } +} + +static void +test_indic_tags (const char *s1, const char *s2, const char *s3, hb_script_t script) +{ + hb_script_t tag1, tag2, tag3; + hb_script_t t[3]; + unsigned int count = 3; + + g_test_message ("Testing script %c%c%c%c: USE tag %s, new tag %s, old tag %s", HB_UNTAG (hb_script_to_iso15924_tag (script)), s1, s2, s3); tag1 = hb_tag_from_string (s1, -1); tag2 = hb_tag_from_string (s2, -1); + tag3 = hb_tag_from_string (s3, -1); - hb_ot_tags_from_script (script, &t1, &t2); + hb_ot_tags_from_script_and_language (script, + HB_LANGUAGE_INVALID, + &count, t, NULL, NULL); - g_assert_cmphex (t1, ==, tag1); - g_assert_cmphex (t2, ==, tag2); + g_assert_cmpuint (count, ==, 3); + g_assert_cmphex (t[0], ==, tag1); + g_assert_cmphex (t[1], ==, tag2); + g_assert_cmphex (t[2], ==, tag3); g_assert_cmphex (hb_ot_tag_to_script (tag1), ==, script); g_assert_cmphex (hb_ot_tag_to_script (tag2), ==, script); + g_assert_cmphex (hb_ot_tag_to_script (tag3), ==, script); } static void test_ot_tag_script_degenerate (void) { - hb_tag_t t1, t2; + hb_script_t t[2]; + unsigned int count = 2; g_assert_cmphex (HB_TAG_CHAR4 ("DFLT"), ==, HB_OT_TAG_DEFAULT_SCRIPT); /* HIRAGANA and KATAKANA both map to 'kana' */ test_simple_tags ("kana", HB_SCRIPT_KATAKANA); - hb_ot_tags_from_script (HB_SCRIPT_HIRAGANA, &t1, &t2); - g_assert_cmphex (t1, ==, HB_TAG_CHAR4 ("kana")); - g_assert_cmphex (t2, ==, HB_OT_TAG_DEFAULT_SCRIPT); + + hb_ot_tags_from_script_and_language (HB_SCRIPT_HIRAGANA, + HB_LANGUAGE_INVALID, + &count, t, NULL, NULL); + + g_assert_cmpuint (count, ==, 1); + g_assert_cmphex (t[0], ==, HB_TAG_CHAR4 ("kana")); test_simple_tags ("DFLT", HB_SCRIPT_INVALID); @@ -121,18 +157,40 @@ test_ot_tag_script_simple (void) } static void +test_ot_tag_script_from_language (void) +{ + test_script_tags_from_language (NULL, NULL, HB_SCRIPT_INVALID); + test_script_tags_from_language (NULL, "en", HB_SCRIPT_INVALID); + test_script_tags_from_language ("copt", "en", HB_SCRIPT_COPTIC); + test_script_tags_from_language (NULL, "x-hbsc", HB_SCRIPT_INVALID); + test_script_tags_from_language ("copt", "x-hbsc", HB_SCRIPT_COPTIC); + test_script_tags_from_language ("abc ", "x-hbscabc", HB_SCRIPT_INVALID); + test_script_tags_from_language ("deva", "x-hbscdeva", HB_SCRIPT_INVALID); + test_script_tags_from_language ("dev2", "x-hbscdev2", HB_SCRIPT_INVALID); + test_script_tags_from_language ("dev3", "x-hbscdev3", HB_SCRIPT_INVALID); + test_script_tags_from_language ("copt", "x-hbotpap0-hbsccopt", HB_SCRIPT_INVALID); + test_script_tags_from_language (NULL, "en-x-hbsc", HB_SCRIPT_INVALID); + test_script_tags_from_language ("copt", "en-x-hbsc", HB_SCRIPT_COPTIC); + test_script_tags_from_language ("abc ", "en-x-hbscabc", HB_SCRIPT_INVALID); + test_script_tags_from_language ("deva", "en-x-hbscdeva", HB_SCRIPT_INVALID); + test_script_tags_from_language ("dev2", "en-x-hbscdev2", HB_SCRIPT_INVALID); + test_script_tags_from_language ("dev3", "en-x-hbscdev3", HB_SCRIPT_INVALID); + test_script_tags_from_language ("copt", "en-x-hbotpap0-hbsccopt", HB_SCRIPT_INVALID); +} + +static void test_ot_tag_script_indic (void) { - test_indic_tags ("bng2", "beng", HB_SCRIPT_BENGALI); - test_indic_tags ("dev2", "deva", HB_SCRIPT_DEVANAGARI); - test_indic_tags ("gjr2", "gujr", HB_SCRIPT_GUJARATI); - test_indic_tags ("gur2", "guru", HB_SCRIPT_GURMUKHI); - test_indic_tags ("knd2", "knda", HB_SCRIPT_KANNADA); - test_indic_tags ("mlm2", "mlym", HB_SCRIPT_MALAYALAM); - test_indic_tags ("ory2", "orya", HB_SCRIPT_ORIYA); - test_indic_tags ("tml2", "taml", HB_SCRIPT_TAMIL); - test_indic_tags ("tel2", "telu", HB_SCRIPT_TELUGU); - test_indic_tags ("mym2", "mymr", HB_SCRIPT_MYANMAR); + test_indic_tags ("bng3", "bng2", "beng", HB_SCRIPT_BENGALI); + test_indic_tags ("dev3", "dev2", "deva", HB_SCRIPT_DEVANAGARI); + test_indic_tags ("gjr3", "gjr2", "gujr", HB_SCRIPT_GUJARATI); + test_indic_tags ("gur3", "gur2", "guru", HB_SCRIPT_GURMUKHI); + test_indic_tags ("knd3", "knd2", "knda", HB_SCRIPT_KANNADA); + test_indic_tags ("mlm3", "mlm2", "mlym", HB_SCRIPT_MALAYALAM); + test_indic_tags ("ory3", "ory2", "orya", HB_SCRIPT_ORIYA); + test_indic_tags ("tml3", "tml2", "taml", HB_SCRIPT_TAMIL); + test_indic_tags ("tel3", "tel2", "telu", HB_SCRIPT_TELUGU); + test_indic_tags ("mym3", "mym2", "mymr", HB_SCRIPT_MYANMAR); } @@ -147,7 +205,16 @@ test_language_two_way (const char *tag_s, const char *lang_s) g_test_message ("Testing language %s <-> tag %s", lang_s, tag_s); - g_assert_cmphex (tag, ==, hb_ot_tag_from_language (lang)); + hb_tag_t tag2; + unsigned int count = 1; + hb_ot_tags_from_script_and_language (HB_SCRIPT_INVALID, + lang, + NULL, NULL, &count, &tag2); + + if (count) + g_assert_cmphex (tag, ==, tag2); + else + g_assert_cmphex (tag, ==, HB_TAG_CHAR4 ("dflt")); g_assert (lang == hb_ot_tag_to_language (tag)); } @@ -159,7 +226,16 @@ test_tag_from_language (const char *tag_s, const char *lang_s) g_test_message ("Testing language %s -> tag %s", lang_s, tag_s); - g_assert_cmphex (tag, ==, hb_ot_tag_from_language (lang)); + hb_tag_t tag2; + unsigned int count = 1; + hb_ot_tags_from_script_and_language (HB_SCRIPT_INVALID, + lang, + NULL, NULL, &count, &tag2); + + if (count) + g_assert_cmphex (tag, ==, tag2); + else + g_assert_cmphex (tag, ==, HB_TAG_CHAR4 ("dflt")); } static void @@ -174,6 +250,32 @@ test_tag_to_language (const char *tag_s, const char *lang_s) } static void +test_tags_to_script_and_language (const char *script_tag_s, + const char *lang_tag_s, + const char *script_s, + const char *lang_s) +{ + hb_script_t actual_script[1]; + hb_language_t actual_lang[1]; + hb_tag_t script_tag = hb_tag_from_string (script_tag_s, -1); + hb_tag_t lang_tag = hb_tag_from_string (lang_tag_s, -1); + hb_ot_tags_to_script_and_language (script_tag, lang_tag, actual_script, actual_lang); + g_assert_cmphex (*actual_script, ==, hb_tag_from_string (script_s, -1)); + g_assert_cmpstr (hb_language_to_string (*actual_lang), ==, lang_s); +} + +static void +test_ot_tags_to_script_and_language (void) +{ + test_tags_to_script_and_language ("DFLT", "ENG", "", "en-x-hbscdflt"); + test_tags_to_script_and_language ("latn", "ENG", "Latn", "en"); + test_tags_to_script_and_language ("deva", "MAR", "Deva", "mr-x-hbscdeva"); + test_tags_to_script_and_language ("dev2", "MAR", "Deva", "mr-x-hbscdev2"); + test_tags_to_script_and_language ("dev3", "MAR", "Deva", "mr"); + test_tags_to_script_and_language ("qaa", "QTZ0", "Qaaa", "x-hbotqtz0-hbscqaa"); +} + +static void test_ot_tag_language (void) { g_assert_cmphex (HB_TAG_CHAR4 ("dflt"), ==, HB_OT_TAG_DEFAULT_LANGUAGE); @@ -230,27 +332,27 @@ test_ot_tag_language (void) test_language_two_way ("TUA", "tru"); /* Turoyo Aramaic */ - test_language_two_way ("ZHH", "zh-hk"); /* Chinese (Hong Kong) */ - test_tag_from_language ("ZHS", "zh"); /* Chinese */ test_tag_from_language ("ZHS", "zh-cn"); /* Chinese (China) */ test_tag_from_language ("ZHS", "zh-sg"); /* Chinese (Singapore) */ test_tag_from_language ("ZHH", "zh-mo"); /* Chinese (Macao) */ test_tag_from_language ("ZHH", "zh-hant-mo"); /* Chinese (Macao) */ - test_tag_from_language ("ZHH", "zh-hk"); /* Chinese (Hong Kong) */ + test_language_two_way ("ZHH", "zh-HK"); /* Chinese (Hong Kong) */ test_tag_from_language ("ZHH", "zH-HanT-hK"); /* Chinese (Hong Kong) */ test_tag_from_language ("ZHT", "zh-tw"); /* Chinese (Taiwan) */ - test_tag_from_language ("ZHS", "zh-Hans"); /* Chinese (Simplified) */ - test_tag_from_language ("ZHT", "zh-Hant"); /* Chinese (Traditional) */ + test_language_two_way ("ZHS", "zh-Hans"); /* Chinese (Simplified) */ + test_language_two_way ("ZHT", "zh-Hant"); /* Chinese (Traditional) */ test_tag_from_language ("ZHS", "zh-xx"); /* Chinese (Other) */ + test_tag_from_language ("ZHS", "zh-Hans-TW"); + + test_tag_from_language ("ZHH", "yue"); + test_tag_from_language ("ZHH", "yue-Hant"); + test_tag_from_language ("ZHS", "yue-Hans"); + test_tag_from_language ("ZHS", "zh"); /* Chinese */ test_tag_from_language ("ZHS", "zh-xx"); - test_tag_to_language ("ZHS", "zh-Hans"); - test_tag_to_language ("ZHT", "zh-Hant"); - test_tag_to_language ("ZHP", "x-hbotzhp"); - test_language_two_way ("ABC", "x-hbotabc"); test_tag_from_language ("ABC", "asdf-asdf-wer-x-hbotabc-zxc"); test_tag_from_language ("ABC", "asdf-asdf-wer-x-hbotabc"); @@ -262,39 +364,64 @@ test_ot_tag_language (void) test_tag_from_language ("XYZ", "xyz"); /* Unknown ISO 639-3 */ test_tag_from_language ("XYZ", "xyz-qw"); /* Unknown ISO 639-3 */ + /* + * Invalid input. The precise answer does not matter, as long as it + * does not crash or get into an infinite loop. + */ + test_tag_from_language ("IPPH", "-fonipa"); + + /* + * Tags that contain "-fonipa" as a substring but which do not contain + * the subtag "fonipa". + */ + test_tag_from_language ("ENG", "en-fonipax"); + test_tag_from_language ("ENG", "en-x-fonipa"); + test_tag_from_language ("ENG", "en-a-fonipa"); + test_tag_from_language ("ENG", "en-a-qwe-b-fonipa"); + /* International Phonetic Alphabet */ test_tag_from_language ("IPPH", "en-fonipa"); + test_tag_from_language ("IPPH", "en-fonipax-fonipa"); test_tag_from_language ("IPPH", "rm-CH-fonipa-sursilv-x-foobar"); - test_tag_from_language ("IPPH", "und-fonipa"); + test_language_two_way ("IPPH", "und-fonipa"); test_tag_from_language ("IPPH", "zh-fonipa"); - test_tag_to_language ("IPPH", "und-fonipa"); /* North American Phonetic Alphabet (Americanist Phonetic Notation) */ test_tag_from_language ("APPH", "en-fonnapa"); test_tag_from_language ("APPH", "chr-fonnapa"); - test_tag_from_language ("APPH", "und-fonnapa"); - test_tag_to_language ("APPH", "und-fonnapa"); + test_language_two_way ("APPH", "und-fonnapa"); + + /* Khutsuri Georgian */ + test_tag_from_language ("KGE", "ka-Geok"); + test_language_two_way ("KGE", "und-Geok"); + + /* Irish Traditional */ + test_language_two_way ("IRT", "ga-Latg"); + + /* Moldavian */ + test_language_two_way ("MOL", "ro-MD"); + + /* Polytonic Greek */ + test_language_two_way ("PGR", "el-polyton"); + test_tag_from_language ("PGR", "el-CY-polyton"); /* Estrangela Syriac */ test_tag_from_language ("SYRE", "aii-Syre"); test_tag_from_language ("SYRE", "de-Syre"); test_tag_from_language ("SYRE", "syr-Syre"); - test_tag_from_language ("SYRE", "und-Syre"); - test_tag_to_language ("SYRE", "und-Syre"); + test_language_two_way ("SYRE", "und-Syre"); /* Western Syriac */ test_tag_from_language ("SYRJ", "aii-Syrj"); test_tag_from_language ("SYRJ", "de-Syrj"); test_tag_from_language ("SYRJ", "syr-Syrj"); - test_tag_from_language ("SYRJ", "und-Syrj"); - test_tag_to_language ("SYRJ", "und-Syrj"); + test_language_two_way ("SYRJ", "und-Syrj"); /* Eastern Syriac */ test_tag_from_language ("SYRN", "aii-Syrn"); test_tag_from_language ("SYRN", "de-Syrn"); test_tag_from_language ("SYRN", "syr-Syrn"); - test_tag_from_language ("SYRN", "und-Syrn"); - test_tag_to_language ("SYRN", "und-Syrn"); + test_language_two_way ("SYRN", "und-Syrn"); /* Test that x-hbot overrides the base language */ test_tag_from_language ("ABC", "fa-x-hbotabc-zxc"); @@ -303,6 +430,77 @@ test_ot_tag_language (void) test_tag_from_language ("ABC", "zh-cn-x-hbotabc-zxc"); test_tag_from_language ("ABC", "zh-xy-x-hbotabc-zxc"); test_tag_from_language ("ABC", "xyz-xy-x-hbotabc-zxc"); + + /* Unnormalized BCP 47 tags */ + test_tag_from_language ("ARA", "ar-aao"); + test_tag_from_language ("JBO", "art-lojban"); + test_tag_from_language ("KOK", "kok-gom"); + test_tag_from_language ("LTZ", "i-lux"); + test_tag_from_language ("MNG", "drh"); + test_tag_from_language ("MOR", "ar-ary"); + test_tag_from_language ("MOR", "ar-ary-DZ"); + test_tag_from_language ("NOR", "no-bok"); + test_tag_from_language ("NYN", "no-nyn"); + test_tag_from_language ("ZHS", "i-hak"); + test_tag_from_language ("ZHS", "zh-guoyu"); + test_tag_from_language ("ZHS", "zh-min"); + test_tag_from_language ("ZHS", "zh-min-nan"); + test_tag_from_language ("ZHS", "zh-xiang"); + + /* A UN M.49 region code, not an extended language subtag */ + test_tag_from_language ("ARA", "ar-001"); +} + +static void +test_tags (hb_script_t script, + const char *lang_s, + unsigned int script_count, + unsigned int language_count, + unsigned int expected_script_count, + unsigned int expected_language_count, + ...) +{ + va_list expected_tags; + unsigned int i; + hb_tag_t *script_tags = malloc (script_count * sizeof (hb_tag_t)); + hb_tag_t *language_tags = malloc (language_count * sizeof (hb_tag_t)); + g_assert (script_tags); + g_assert (language_tags); + hb_language_t lang = hb_language_from_string (lang_s, -1); + va_start (expected_tags, expected_language_count); + + hb_ot_tags_from_script_and_language (script, lang, &script_count, script_tags, &language_count, language_tags); + + g_assert_cmpuint (script_count, ==, expected_script_count); + g_assert_cmpuint (language_count, ==, expected_language_count); + + for (i = 0; i < script_count + language_count; i++) + { + hb_tag_t expected_tag = hb_tag_from_string (va_arg (expected_tags, const char *), -1); + hb_tag_t actual_tag = i < script_count ? script_tags[i] : language_tags[i - script_count]; + g_assert_cmphex (actual_tag, ==, expected_tag); + } + + free (script_tags); + free (language_tags); + va_end (expected_tags); +} + +static void +test_ot_tag_full (void) +{ + test_tags (HB_SCRIPT_INVALID, "en", HB_OT_MAX_TAGS_PER_SCRIPT, HB_OT_MAX_TAGS_PER_LANGUAGE, 0, 1, "ENG"); + test_tags (HB_SCRIPT_INVALID, "en-x-hbscdflt", HB_OT_MAX_TAGS_PER_SCRIPT, HB_OT_MAX_TAGS_PER_LANGUAGE, 1, 1, "DFLT", "ENG"); + test_tags (HB_SCRIPT_LATIN, "en", HB_OT_MAX_TAGS_PER_SCRIPT, HB_OT_MAX_TAGS_PER_LANGUAGE, 1, 1, "latn", "ENG"); + test_tags (HB_SCRIPT_LATIN, "en", 0, 0, 0, 0); + test_tags (HB_SCRIPT_INVALID, "und-fonnapa", HB_OT_MAX_TAGS_PER_SCRIPT, HB_OT_MAX_TAGS_PER_LANGUAGE, 0, 1, "APPH"); + test_tags (HB_SCRIPT_INVALID, "en-fonnapa", HB_OT_MAX_TAGS_PER_SCRIPT, HB_OT_MAX_TAGS_PER_LANGUAGE, 0, 1, "APPH"); + test_tags (HB_SCRIPT_INVALID, "x-hbot1234-hbsc5678", HB_OT_MAX_TAGS_PER_SCRIPT, HB_OT_MAX_TAGS_PER_LANGUAGE, 1, 1, "5678", "1234"); + test_tags (HB_SCRIPT_INVALID, "x-hbsc5678-hbot1234", HB_OT_MAX_TAGS_PER_SCRIPT, HB_OT_MAX_TAGS_PER_LANGUAGE, 1, 1, "5678", "1234"); + test_tags (HB_SCRIPT_MALAYALAM, "ml", HB_OT_MAX_TAGS_PER_SCRIPT, HB_OT_MAX_TAGS_PER_LANGUAGE, 3, 2, "mlm3", "mlm2", "mlym", "MAL", "MLR"); + test_tags (HB_SCRIPT_MALAYALAM, "ml", 1, 1, 1, 1, "mlm3", "MAL"); + test_tags (HB_SCRIPT_INVALID, "xyz", HB_OT_MAX_TAGS_PER_SCRIPT, HB_OT_MAX_TAGS_PER_LANGUAGE, 0, 1, "XYZ"); + test_tags (HB_SCRIPT_INVALID, "xy", HB_OT_MAX_TAGS_PER_SCRIPT, HB_OT_MAX_TAGS_PER_LANGUAGE, 0, 0); } int @@ -312,9 +510,14 @@ main (int argc, char **argv) hb_test_add (test_ot_tag_script_degenerate); hb_test_add (test_ot_tag_script_simple); + hb_test_add (test_ot_tag_script_from_language); hb_test_add (test_ot_tag_script_indic); + hb_test_add (test_ot_tags_to_script_and_language); + hb_test_add (test_ot_tag_language); + hb_test_add (test_ot_tag_full); + return hb_test_run(); } diff --git a/test/api/test-set.c b/test/api/test-set.c index 338a610c9..aa2b388ea 100644 --- a/test/api/test-set.c +++ b/test/api/test-set.c @@ -118,6 +118,9 @@ test_set_basic (void) g_assert (!hb_set_has (s, 801)); g_assert (!hb_set_has (s, 802)); + hb_set_del (s, 800); + g_assert (!hb_set_has (s, 800)); + hb_set_destroy (s); } @@ -262,6 +265,7 @@ test_set_algebra (void) hb_set_destroy (s); hb_set_destroy (o); + hb_set_destroy (o2); } static void @@ -380,10 +384,6 @@ test_set_empty (void) test_empty (b); - hb_set_invert (b); - - test_empty (b); - g_assert (!hb_set_allocation_successful (b)); hb_set_clear (b); diff --git a/test/api/test-shape.c b/test/api/test-shape.c index 6232e7382..146cf0f4a 100644 --- a/test/api/test-shape.c +++ b/test/api/test-shape.c @@ -41,9 +41,9 @@ static const char test_data[] = "test\0data"; static hb_position_t -glyph_h_advance_func (hb_font_t *font, void *font_data, +glyph_h_advance_func (hb_font_t *font HB_UNUSED, void *font_data HB_UNUSED, hb_codepoint_t glyph, - void *user_data) + void *user_data HB_UNUSED) { switch (glyph) { case 1: return 10; @@ -54,10 +54,10 @@ glyph_h_advance_func (hb_font_t *font, void *font_data, } static hb_bool_t -glyph_func (hb_font_t *font, void *font_data, - hb_codepoint_t unicode, hb_codepoint_t variant_selector, +glyph_func (hb_font_t *font HB_UNUSED, void *font_data HB_UNUSED, + hb_codepoint_t unicode, hb_codepoint_t *glyph, - void *user_data) + void *user_data HB_UNUSED) { switch (unicode) { case 'T': *glyph = 1; return TRUE; @@ -68,9 +68,9 @@ glyph_func (hb_font_t *font, void *font_data, } static hb_position_t -glyph_h_kerning_func (hb_font_t *font, void *font_data, +glyph_h_kerning_func (hb_font_t *font HB_UNUSED, void *font_data HB_UNUSED, hb_codepoint_t left, hb_codepoint_t right, - void *user_data) + void *user_data HB_UNUSED) { if (left == 1 && right == 2) return -2; @@ -101,7 +101,7 @@ test_shape (void) ffuncs = hb_font_funcs_create (); hb_font_funcs_set_glyph_h_advance_func (ffuncs, glyph_h_advance_func, NULL, NULL); - hb_font_funcs_set_glyph_func (ffuncs, glyph_func, malloc (10), free); + hb_font_funcs_set_nominal_glyph_func (ffuncs, glyph_func, malloc (10), free); hb_font_funcs_set_glyph_h_kerning_func (ffuncs, glyph_h_kerning_func, NULL, NULL); hb_font_set_funcs (font, ffuncs, NULL, NULL); hb_font_funcs_destroy (ffuncs); diff --git a/test/api/test-subset-glyf.c b/test/api/test-subset-glyf.c index e4440e0fe..05c7f8cfe 100644 --- a/test/api/test-subset-glyf.c +++ b/test/api/test-subset-glyf.c @@ -105,16 +105,18 @@ test_subset_glyf_with_gsub (void) { hb_face_t *face_fil = hb_subset_test_open_font ("fonts/Roboto-Regular.gsub.fil.ttf"); hb_face_t *face_fi = hb_subset_test_open_font ("fonts/Roboto-Regular.gsub.fi.ttf"); + hb_subset_input_t *input; + hb_face_t *face_subset; hb_set_t *codepoints = hb_set_create(); hb_set_add (codepoints, 102); // f hb_set_add (codepoints, 105); // i - hb_subset_input_t *input = hb_subset_test_create_input (codepoints); + input = hb_subset_test_create_input (codepoints); hb_set_destroy (codepoints); - *hb_subset_input_drop_ot_layout (input) = false; + hb_subset_input_set_drop_layout (input, false); - hb_face_t *face_subset = hb_subset_test_create_subset (face_fil, input); + face_subset = hb_subset_test_create_subset (face_fil, input); hb_subset_test_check (face_fi, face_subset, HB_TAG ('g','l','y','f')); hb_subset_test_check (face_fi, face_subset, HB_TAG ('l','o','c', 'a')); @@ -130,16 +132,18 @@ test_subset_glyf_without_gsub (void) { hb_face_t *face_fil = hb_subset_test_open_font ("fonts/Roboto-Regular.gsub.fil.ttf"); hb_face_t *face_fi = hb_subset_test_open_font ("fonts/Roboto-Regular.nogsub.fi.ttf"); + hb_subset_input_t *input; + hb_face_t *face_subset; hb_set_t *codepoints = hb_set_create(); hb_set_add (codepoints, 102); // f hb_set_add (codepoints, 105); // i - hb_subset_input_t *input = hb_subset_test_create_input (codepoints); + input = hb_subset_test_create_input (codepoints); hb_set_destroy (codepoints); - *hb_subset_input_drop_ot_layout (input) = true; + hb_subset_input_set_drop_layout (input, true); - hb_face_t *face_subset = hb_subset_test_create_subset (face_fil, input); + face_subset = hb_subset_test_create_subset (face_fil, input); hb_subset_test_check (face_fi, face_subset, HB_TAG ('g','l','y','f')); hb_subset_test_check (face_fi, face_subset, HB_TAG ('l','o','c', 'a')); @@ -183,7 +187,7 @@ test_subset_glyf_strip_hints_simple (void) hb_set_add (codepoints, 'a'); hb_set_add (codepoints, 'c'); input = hb_subset_test_create_input (codepoints); - *hb_subset_input_drop_hints(input) = true; + hb_subset_input_set_drop_hints (input, true); face_abc_subset = hb_subset_test_create_subset (face_abc, input); hb_set_destroy (codepoints); @@ -207,7 +211,7 @@ test_subset_glyf_strip_hints_composite (void) hb_face_t *face_generated_subset; hb_set_add (codepoints, 0x1fc); input = hb_subset_test_create_input (codepoints); - *hb_subset_input_drop_hints(input) = true; + hb_subset_input_set_drop_hints (input, true); face_generated_subset = hb_subset_test_create_subset (face_components, input); hb_set_destroy (codepoints); @@ -224,7 +228,7 @@ test_subset_glyf_strip_hints_composite (void) static void test_subset_glyf_strip_hints_invalid (void) { - hb_face_t *face = hb_subset_test_open_font ("fonts/oom-ccc61c92d589f895174cdef6ff2e3b20e9999a1a"); + hb_face_t *face = hb_subset_test_open_font ("../fuzzing/fonts/oom-ccc61c92d589f895174cdef6ff2e3b20e9999a1a"); hb_set_t *codepoints = hb_set_create(); const hb_codepoint_t text[] = @@ -233,16 +237,19 @@ test_subset_glyf_strip_hints_invalid (void) '3', '@', '_', '%', '&', ')', '*', '$', '!' }; unsigned int i; + hb_subset_input_t *input; + hb_face_t *face_subset; + for (i = 0; i < sizeof (text) / sizeof (hb_codepoint_t); i++) { hb_set_add (codepoints, text[i]); } - hb_subset_input_t *input = hb_subset_test_create_input (codepoints); - *hb_subset_input_drop_hints(input) = true; + input = hb_subset_test_create_input (codepoints); + hb_subset_input_set_drop_hints (input, true); hb_set_destroy (codepoints); - hb_face_t *face_subset = hb_subset_test_create_subset (face, input); + face_subset = hb_subset_test_create_subset (face, input); g_assert (face_subset); g_assert (face_subset == hb_face_get_empty ()); diff --git a/test/api/test-subset-hdmx.c b/test/api/test-subset-hdmx.c index c78009b6b..8496f9e8f 100644 --- a/test/api/test-subset-hdmx.c +++ b/test/api/test-subset-hdmx.c @@ -51,23 +51,42 @@ test_subset_hdmx_simple_subset (void) } static void +test_subset_hdmx_multiple_device_records (void) +{ + hb_face_t *face_abc = hb_subset_test_open_font ("fonts/Roboto-Regular.multihdmx.abc.ttf"); + hb_face_t *face_a = hb_subset_test_open_font ("fonts/Roboto-Regular.multihdmx.a.ttf"); + + hb_set_t *codepoints = hb_set_create (); + hb_face_t *face_abc_subset; + hb_set_add (codepoints, 'a'); + face_abc_subset = hb_subset_test_create_subset (face_abc, hb_subset_test_create_input (codepoints)); + hb_set_destroy (codepoints); + + hb_subset_test_check (face_a, face_abc_subset, HB_TAG ('h','d','m','x')); + + hb_face_destroy (face_abc_subset); + hb_face_destroy (face_abc); + hb_face_destroy (face_a); +} + +static void test_subset_hdmx_invalid (void) { - hb_face_t *face = hb_subset_test_open_font("fonts/crash-ccc61c92d589f895174cdef6ff2e3b20e9999a1a"); + hb_face_t *face = hb_subset_test_open_font("../fuzzing/fonts/crash-ccc61c92d589f895174cdef6ff2e3b20e9999a1a"); hb_subset_input_t *input = hb_subset_input_create_or_fail (); hb_set_t *codepoints = hb_subset_input_unicode_set (input); + hb_face_t *subset; + hb_set_add (codepoints, 'a'); hb_set_add (codepoints, 'b'); hb_set_add (codepoints, 'c'); - hb_subset_profile_t *profile = hb_subset_profile_create(); - hb_face_t *subset = hb_subset (face, profile, input); + subset = hb_subset (face, input); g_assert (subset); g_assert (subset == hb_face_get_empty ()); hb_subset_input_destroy (input); - hb_subset_profile_destroy (profile); hb_face_destroy (subset); hb_face_destroy (face); } @@ -75,21 +94,21 @@ test_subset_hdmx_invalid (void) static void test_subset_hdmx_fails_sanitize (void) { - hb_face_t *face = hb_subset_test_open_font("fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5609911946838016"); + hb_face_t *face = hb_subset_test_open_font("../fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5609911946838016"); hb_subset_input_t *input = hb_subset_input_create_or_fail (); hb_set_t *codepoints = hb_subset_input_unicode_set (input); + hb_face_t *subset; + hb_set_add (codepoints, 'a'); hb_set_add (codepoints, 'b'); hb_set_add (codepoints, 'c'); - hb_subset_profile_t *profile = hb_subset_profile_create(); - hb_face_t *subset = hb_subset (face, profile, input); + subset = hb_subset (face, input); g_assert (subset); g_assert (subset == hb_face_get_empty ()); hb_subset_input_destroy (input); - hb_subset_profile_destroy (profile); hb_face_destroy (subset); hb_face_destroy (face); } @@ -119,6 +138,7 @@ main (int argc, char **argv) hb_test_init (&argc, &argv); hb_test_add (test_subset_hdmx_simple_subset); + hb_test_add (test_subset_hdmx_multiple_device_records); hb_test_add (test_subset_hdmx_invalid); hb_test_add (test_subset_hdmx_fails_sanitize); hb_test_add (test_subset_hdmx_noop); diff --git a/test/api/test-subset-hmtx.c b/test/api/test-subset-hmtx.c index 0ed62562b..1a5a44dc5 100644 --- a/test/api/test-subset-hmtx.c +++ b/test/api/test-subset-hmtx.c @@ -153,7 +153,8 @@ test_subset_hmtx_noop (void) static void test_subset_invalid_hmtx (void) { - hb_face_t *face = hb_subset_test_open_font("fonts/crash-e4e0bb1458a91b692eba492c907ae1f94e635480"); + hb_face_t *face = hb_subset_test_open_font("../fuzzing/fonts/crash-e4e0bb1458a91b692eba492c907ae1f94e635480"); + hb_face_t *subset; hb_subset_input_t *input = hb_subset_input_create_or_fail (); hb_set_t *codepoints = hb_subset_input_unicode_set (input); @@ -161,13 +162,11 @@ test_subset_invalid_hmtx (void) hb_set_add (codepoints, 'b'); hb_set_add (codepoints, 'c'); - hb_subset_profile_t *profile = hb_subset_profile_create(); - hb_face_t *subset = hb_subset (face, profile, input); + subset = hb_subset (face, input); g_assert (subset); g_assert (subset == hb_face_get_empty ()); hb_subset_input_destroy (input); - hb_subset_profile_destroy (profile); hb_face_destroy (subset); hb_face_destroy (face); } diff --git a/test/api/test-subset-post.c b/test/api/test-subset-post.c index 948b18a23..c14741e4a 100644 --- a/test/api/test-subset-post.c +++ b/test/api/test-subset-post.c @@ -34,11 +34,12 @@ test_post_drops_glyph_names (void) { hb_face_t *face_full = hb_subset_test_open_font ("fonts/Mplus1p-Regular.660E,6975,73E0,5EA6,8F38,6E05.ttf"); hb_face_t *face_subset = hb_subset_test_open_font ("fonts/Mplus1p-Regular.660E.ttf"); + hb_face_t *face_full_subset; hb_set_t *codepoints = hb_set_create (); hb_set_add (codepoints, 0x660E); - hb_face_t *face_full_subset = hb_subset_test_create_subset (face_full, hb_subset_test_create_input (codepoints)); + face_full_subset = hb_subset_test_create_subset (face_full, hb_subset_test_create_input (codepoints)); hb_set_destroy (codepoints); hb_subset_test_check (face_subset, face_full_subset, HB_TAG ('p','o','s','t')); diff --git a/test/api/test-subset-vmtx.c b/test/api/test-subset-vmtx.c index 437f0c2f5..40ea8f872 100644 --- a/test/api/test-subset-vmtx.c +++ b/test/api/test-subset-vmtx.c @@ -48,11 +48,12 @@ test_subset_vmtx_simple_subset (void) { hb_face_t *face_full = hb_subset_test_open_font ("fonts/Mplus1p-Regular.660E,6975,73E0,5EA6,8F38,6E05.ttf"); hb_face_t *face_subset = hb_subset_test_open_font ("fonts/Mplus1p-Regular.660E.ttf"); + hb_face_t *face_full_subset; hb_set_t *codepoints = hb_set_create (); hb_set_add (codepoints, 0x660E); - hb_face_t *face_full_subset = hb_subset_test_create_subset (face_full, hb_subset_test_create_input (codepoints)); + face_full_subset = hb_subset_test_create_subset (face_full, hb_subset_test_create_input (codepoints)); hb_set_destroy (codepoints); check_num_vmetrics(face_full_subset, 1); /* nothing has same width */ @@ -67,6 +68,7 @@ static void test_subset_vmtx_noop (void) { hb_face_t *face_full = hb_subset_test_open_font ("fonts/Mplus1p-Regular.660E,6975,73E0,5EA6,8F38,6E05.ttf"); + hb_face_t *face_full_subset; hb_set_t *codepoints = hb_set_create(); hb_set_add (codepoints, 0x660E); @@ -75,7 +77,7 @@ test_subset_vmtx_noop (void) hb_set_add (codepoints, 0x5EA6); hb_set_add (codepoints, 0x8F38); hb_set_add (codepoints, 0x6E05); - hb_face_t *face_full_subset = hb_subset_test_create_subset (face_full, hb_subset_test_create_input (codepoints)); + face_full_subset = hb_subset_test_create_subset (face_full, hb_subset_test_create_input (codepoints)); hb_set_destroy (codepoints); check_num_vmetrics(face_full_subset, 1); /* all have the same width */ diff --git a/test/api/test-subset.c b/test/api/test-subset.c index 6d2bf06e1..aaed03176 100644 --- a/test/api/test-subset.c +++ b/test/api/test-subset.c @@ -32,21 +32,21 @@ static void test_subset_32_tables (void) { - hb_face_t *face = hb_subset_test_open_font("fonts/oom-6ef8c96d3710262511bcc730dce9c00e722cb653"); + hb_face_t *face = hb_subset_test_open_font("../fuzzing/fonts/oom-6ef8c96d3710262511bcc730dce9c00e722cb653"); hb_subset_input_t *input = hb_subset_input_create_or_fail (); hb_set_t *codepoints = hb_subset_input_unicode_set (input); + hb_face_t *subset; + hb_set_add (codepoints, 'a'); hb_set_add (codepoints, 'b'); hb_set_add (codepoints, 'c'); - hb_subset_profile_t *profile = hb_subset_profile_create(); - hb_face_t *subset = hb_subset (face, profile, input); + subset = hb_subset (face, input); g_assert (subset); g_assert (subset != hb_face_get_empty ()); hb_subset_input_destroy (input); - hb_subset_profile_destroy (profile); hb_face_destroy (subset); hb_face_destroy (face); } @@ -54,21 +54,21 @@ test_subset_32_tables (void) static void test_subset_no_inf_loop (void) { - hb_face_t *face = hb_subset_test_open_font("fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5521982557782016"); + hb_face_t *face = hb_subset_test_open_font("../fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5521982557782016"); hb_subset_input_t *input = hb_subset_input_create_or_fail (); hb_set_t *codepoints = hb_subset_input_unicode_set (input); + hb_face_t *subset; + hb_set_add (codepoints, 'a'); hb_set_add (codepoints, 'b'); hb_set_add (codepoints, 'c'); - hb_subset_profile_t *profile = hb_subset_profile_create(); - hb_face_t *subset = hb_subset (face, profile, input); + subset = hb_subset (face, input); g_assert (subset); g_assert (subset == hb_face_get_empty ()); hb_subset_input_destroy (input); - hb_subset_profile_destroy (profile); hb_face_destroy (subset); hb_face_destroy (face); } @@ -76,21 +76,21 @@ test_subset_no_inf_loop (void) static void test_subset_crash (void) { - hb_face_t *face = hb_subset_test_open_font("fonts/crash-4b60576767ee4d9fe1cc10959d89baf73d4e8249"); + hb_face_t *face = hb_subset_test_open_font("../fuzzing/fonts/crash-4b60576767ee4d9fe1cc10959d89baf73d4e8249"); hb_subset_input_t *input = hb_subset_input_create_or_fail (); hb_set_t *codepoints = hb_subset_input_unicode_set (input); + hb_face_t *subset; + hb_set_add (codepoints, 'a'); hb_set_add (codepoints, 'b'); hb_set_add (codepoints, 'c'); - hb_subset_profile_t *profile = hb_subset_profile_create(); - hb_face_t *subset = hb_subset (face, profile, input); + subset = hb_subset (face, input); g_assert (subset); g_assert (subset == hb_face_get_empty ()); hb_subset_input_destroy (input); - hb_subset_profile_destroy (profile); hb_face_destroy (subset); hb_face_destroy (face); } diff --git a/test/api/test-unicode.c b/test/api/test-unicode.c index 88f12e779..6195bb286 100644 --- a/test/api/test-unicode.c +++ b/test/api/test-unicode.c @@ -160,69 +160,6 @@ static const test_pair_t combining_class_tests_more[] = { 0x111111, 0 } }; -static const test_pair_t eastasian_width_tests[] = -{ - /* Neutral */ - { 0x0000, 1 }, - { 0x0483, 1 }, - { 0x0641, 1 }, - { 0xFFFC, 1 }, - { 0x10000, 1 }, - { 0xE0001, 1 }, - - /* Narrow */ - { 0x0020, 1 }, - { 0x0041, 1 }, - { 0x27E6, 1 }, - - /* Halfwidth */ - { 0x20A9, 1 }, - { 0xFF61, 1 }, - { 0xFF69, 1 }, - { 0xFFEE, 1 }, - - /* Ambiguous */ - { 0x00A1, 1 }, - { 0x00D8, 1 }, - { 0x02DD, 1 }, - { 0xE0100, 1 }, - { 0x100000, 1 }, - - /* Fullwidth */ - { 0x3000, 2 }, - { 0xFF60, 2 }, - - /* Wide */ - { 0x2329, 2 }, - { 0x3001, 2 }, - { 0xFE69, 2 }, - { 0x30000, 2 }, - { 0x3FFFD, 2 }, - - { 0x111111, 1 } -}; -static const test_pair_t eastasian_width_tests_more[] = -{ - /* Default Wide blocks */ - { 0x4DBF, 2 }, - { 0x9FFF, 2 }, - { 0xFAFF, 2 }, - { 0x2A6DF, 2 }, - { 0x2B73F, 2 }, - { 0x2B81F, 2 }, - { 0x2FA1F, 2 }, - - /* Uniode-5.2 character additions */ - /* Wide */ - { 0x115F, 2 }, - - /* Uniode-6.0 character additions */ - /* Wide */ - { 0x2B740, 2 }, - { 0x1B000, 2 }, - - { 0x111111, 1 } -}; static const test_pair_t general_category_tests[] = { @@ -469,7 +406,6 @@ typedef struct { static const property_t properties[] = { PROPERTY (combining_class, 0), - PROPERTY (eastasian_width, 1), PROPERTY (general_category, (unsigned int) HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER), PROPERTY (mirroring, RETURNS_UNICODE_ITSELF), PROPERTY (script, (unsigned int) HB_SCRIPT_UNKNOWN) @@ -645,18 +581,18 @@ typedef struct { } data_fixture_t; static void -data_fixture_init (data_fixture_t *f, gconstpointer user_data) +data_fixture_init (data_fixture_t *f, gconstpointer user_data HB_UNUSED) { f->data[0].value = MAGIC0; f->data[1].value = MAGIC1; } static void -data_fixture_finish (data_fixture_t *f, gconstpointer user_data) +data_fixture_finish (data_fixture_t *f HB_UNUSED, gconstpointer user_data HB_UNUSED) { } static void -test_unicode_subclassing_nil (data_fixture_t *f, gconstpointer user_data) +test_unicode_subclassing_nil (data_fixture_t *f, gconstpointer user_data HB_UNUSED) { hb_unicode_funcs_t *uf, *aa; @@ -678,7 +614,7 @@ test_unicode_subclassing_nil (data_fixture_t *f, gconstpointer user_data) } static void -test_unicode_subclassing_default (data_fixture_t *f, gconstpointer user_data) +test_unicode_subclassing_default (data_fixture_t *f, gconstpointer user_data HB_UNUSED) { hb_unicode_funcs_t *uf, *aa; @@ -697,7 +633,7 @@ test_unicode_subclassing_default (data_fixture_t *f, gconstpointer user_data) } static void -test_unicode_subclassing_deep (data_fixture_t *f, gconstpointer user_data) +test_unicode_subclassing_deep (data_fixture_t *f, gconstpointer user_data HB_UNUSED) { hb_unicode_funcs_t *uf, *aa; @@ -786,7 +722,6 @@ test_unicode_normalization (gconstpointer user_data) { hb_unicode_funcs_t *uf = (hb_unicode_funcs_t *) user_data; gunichar a, b, ab; - hb_codepoint_t decomposed[HB_UNICODE_MAX_DECOMPOSITION_LEN]; /* Test compose() */ @@ -849,56 +784,6 @@ test_unicode_normalization (gconstpointer user_data) g_assert (hb_unicode_decompose (uf, 0xD4CC, &a, &b) && a == 0x1111 && b == 0x1171); g_assert (hb_unicode_decompose (uf, 0xCE31, &a, &b) && a == 0xCE20 && b == 0x11B8); g_assert (hb_unicode_decompose (uf, 0xCE20, &a, &b) && a == 0x110E && b == 0x1173); - - - /* Test decompose_compatibility() */ - - /* Not decomposable */ - g_assert (hb_unicode_decompose_compatibility (uf, 0x0041, decomposed) == 0); - g_assert (hb_unicode_decompose_compatibility (uf, 0x1F632, decomposed) == 0); - - /* Singletons */ - g_assert (hb_unicode_decompose_compatibility (uf, 0x00B5, decomposed) == 1 && decomposed[0] == 0x03BC); - g_assert (hb_unicode_decompose_compatibility (uf, 0x03D6, decomposed) == 1 && decomposed[0] == 0x03C0); - - /* Arabic compatibility */ - g_assert (hb_unicode_decompose_compatibility (uf, 0xFB54, decomposed) == 1 && decomposed[0] == 0x067B); - - /* Longest decomposition ever */ - g_assert (18 <= HB_UNICODE_MAX_DECOMPOSITION_LEN); - g_assert (hb_unicode_decompose_compatibility (uf, 0xFDFA, decomposed) == 18 && decomposed[17] == 0x0645); - - /* Note: we deliberately don't test characters that have canonical decompositions but no - * compatibility decomposition against the decompose_compatibility() function as that we - * leave up to implementations (for now). */ - - /* Spaces */ - g_assert (hb_unicode_decompose_compatibility (uf, 0x2002, decomposed) == 1 && decomposed[0] == 0x0020); - g_assert (hb_unicode_decompose_compatibility (uf, 0x2003, decomposed) == 1 && decomposed[0] == 0x0020); - g_assert (hb_unicode_decompose_compatibility (uf, 0x2004, decomposed) == 1 && decomposed[0] == 0x0020); - g_assert (hb_unicode_decompose_compatibility (uf, 0x2005, decomposed) == 1 && decomposed[0] == 0x0020); - g_assert (hb_unicode_decompose_compatibility (uf, 0x2006, decomposed) == 1 && decomposed[0] == 0x0020); - g_assert (hb_unicode_decompose_compatibility (uf, 0x2008, decomposed) == 1 && decomposed[0] == 0x0020); - g_assert (hb_unicode_decompose_compatibility (uf, 0x2009, decomposed) == 1 && decomposed[0] == 0x0020); - g_assert (hb_unicode_decompose_compatibility (uf, 0x200A, decomposed) == 1 && decomposed[0] == 0x0020); - - /* Pairs */ - g_assert (hb_unicode_decompose_compatibility (uf, 0x0587, decomposed) == 2 && - decomposed[0] == 0x0565 && decomposed[1] == 0x0582); - g_assert (hb_unicode_decompose_compatibility (uf, 0x2017, decomposed) == 2 && - decomposed[0] == 0x0020 && decomposed[1] == 0x0333); - g_assert (hb_unicode_decompose_compatibility (uf, 0x2025, decomposed) == 2 && - decomposed[0] == 0x002E && decomposed[1] == 0x002E); - g_assert (hb_unicode_decompose_compatibility (uf, 0x2033, decomposed) == 2 && - decomposed[0] == 0x2032 && decomposed[1] == 0x2032); - - /* Triples */ - g_assert (hb_unicode_decompose_compatibility (uf, 0x2026, decomposed) == 3 && - decomposed[0] == 0x002E && decomposed[1] == 0x002E && decomposed[2] == 0x002E); - g_assert (hb_unicode_decompose_compatibility (uf, 0x2034, decomposed) == 3 && - decomposed[0] == 0x2032 && decomposed[1] == 0x2032 && decomposed[2] == 0x2032); - g_assert (hb_unicode_decompose_compatibility (uf, 0x213B, decomposed) == 3 && - decomposed[0] == 0x0046 && decomposed[1] == 0x0041 && decomposed[2] == 0x0058); } diff --git a/test/fuzzing/CMakeLists.txt b/test/fuzzing/CMakeLists.txt index 2a45ef649..577d13cea 100644 --- a/test/fuzzing/CMakeLists.txt +++ b/test/fuzzing/CMakeLists.txt @@ -2,7 +2,6 @@ if (HB_CHECK) file (READ "${CMAKE_CURRENT_SOURCE_DIR}/Makefile.am" MAKEFILEAM) extract_make_variable (hb_shape_fuzzer_SOURCES ${MAKEFILEAM}) extract_make_variable (hb_subset_fuzzer_SOURCES ${MAKEFILEAM}) - extract_make_variable (hb_subset_get_codepoints_fuzzer_SOURCES ${MAKEFILEAM}) # TODO: enable these two #extract_make_variable (FUZZING_CPPFLAGS ${MAKEFILEAM}) # extracting regex fail @@ -16,17 +15,13 @@ if (HB_CHECK) add_executable (hb-subset-fuzzer ${hb_subset_fuzzer_SOURCES}) target_link_libraries (hb-subset-fuzzer harfbuzz-subset) - add_executable (hb-subset-get-codepoints-fuzzer ${hb_subset_get_codepoints_fuzzer_SOURCES}) - target_link_libraries (hb-subset-get-codepoints-fuzzer harfbuzz-subset) - target_compile_definitions(hb-shape-fuzzer PUBLIC ${FUZZING_CPPFLAGS}) target_compile_definitions(hb-subset-fuzzer PUBLIC ${FUZZING_CPPFLAGS}) - target_compile_definitions(hb-subset-get-codepoints-fuzzer PUBLIC ${FUZZING_CPPFLAGS}) add_test (NAME hb-shape-fuzzer COMMAND "${PYTHON_EXECUTABLE}" run-shape-fuzzer-tests.py $<TARGET_FILE:hb-shape-fuzzer> WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) add_test (NAME hb-subset-fuzzer - COMMAND "${PYTHON_EXECUTABLE}" run-subset-fuzzer-tests.py $<TARGET_FILE:hb-subset-fuzzer> $<TARGET_FILE:hb-subset-get-codepoints-fuzzer> + COMMAND "${PYTHON_EXECUTABLE}" run-subset-fuzzer-tests.py $<TARGET_FILE:hb-subset-fuzzer> WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) endif () diff --git a/test/fuzzing/Makefile.am b/test/fuzzing/Makefile.am index 5af5a7339..250608861 100644 --- a/test/fuzzing/Makefile.am +++ b/test/fuzzing/Makefile.am @@ -18,12 +18,12 @@ EXTRA_DIST += \ run-shape-fuzzer-tests.py \ run-subset-fuzzer-tests.py \ CMakeLists.txt \ + fonts \ $(NULL) check_PROGRAMS = \ hb-shape-fuzzer \ hb-subset-fuzzer \ - hb-subset-get-codepoints-fuzzer \ $(NULL) AM_CPPFLAGS = \ @@ -65,21 +65,6 @@ hb_subset_fuzzer_DEPENDENCIES = \ lib \ $(NULL) -hb_subset_get_codepoints_fuzzer_SOURCES = \ - hb-fuzzer.hh \ - hb-subset-get-codepoints-fuzzer.cc \ - main.cc \ - $(NULL) -hb_subset_get_codepoints_fuzzer_LDADD = \ - $(top_builddir)/src/libharfbuzz-subset-fuzzing.la \ - $(NULL) -hb_subset_get_codepoints_fuzzer_CPPFLAGS = \ - $(AM_CPPFLAGS) \ - $(NULL) -hb_subset_get_codepoints_fuzzer_DEPENDENCIES = \ - lib \ - $(NULL) - check: EXEEXT="$(EXEEXT)" srcdir="$(srcdir)" builddir="$(builddir)" $(srcdir)/run-shape-fuzzer-tests.py EXEEXT="$(EXEEXT)" srcdir="$(srcdir)" builddir="$(builddir)" $(srcdir)/run-subset-fuzzer-tests.py diff --git a/test/shaping/data/in-house/fonts/0509e80afb379d16560e9e47bdd7d888bebdebc6.ttf b/test/fuzzing/fonts/0509e80afb379d16560e9e47bdd7d888bebdebc6 Binary files differindex 203603110..203603110 100644 --- a/test/shaping/data/in-house/fonts/0509e80afb379d16560e9e47bdd7d888bebdebc6.ttf +++ b/test/fuzzing/fonts/0509e80afb379d16560e9e47bdd7d888bebdebc6 diff --git a/test/shaping/data/in-house/fonts/1a6f1687b7a221f9f2c834b0b360d3c8463b6daf.ttf b/test/fuzzing/fonts/1a6f1687b7a221f9f2c834b0b360d3c8463b6daf Binary files differindex c71e85a84..c71e85a84 100644 --- a/test/shaping/data/in-house/fonts/1a6f1687b7a221f9f2c834b0b360d3c8463b6daf.ttf +++ b/test/fuzzing/fonts/1a6f1687b7a221f9f2c834b0b360d3c8463b6daf diff --git a/test/shaping/data/in-house/fonts/205edd09bd3d141cc9580f650109556cc28b22cb.ttf b/test/fuzzing/fonts/205edd09bd3d141cc9580f650109556cc28b22cb Binary files differindex 4e0ce0a48..4e0ce0a48 100644 --- a/test/shaping/data/in-house/fonts/205edd09bd3d141cc9580f650109556cc28b22cb.ttf +++ b/test/fuzzing/fonts/205edd09bd3d141cc9580f650109556cc28b22cb diff --git a/test/shaping/data/in-house/fonts/217a934cfe15c548b572c203dceb2befdf026462.ttf b/test/fuzzing/fonts/217a934cfe15c548b572c203dceb2befdf026462 Binary files differindex 12b91a09f..12b91a09f 100644 --- a/test/shaping/data/in-house/fonts/217a934cfe15c548b572c203dceb2befdf026462.ttf +++ b/test/fuzzing/fonts/217a934cfe15c548b572c203dceb2befdf026462 diff --git a/test/shaping/data/in-house/fonts/3511ff5c1647150595846ac414c595cccac34f18.ttf b/test/fuzzing/fonts/3511ff5c1647150595846ac414c595cccac34f18 Binary files differindex 789abf7a8..789abf7a8 100644 --- a/test/shaping/data/in-house/fonts/3511ff5c1647150595846ac414c595cccac34f18.ttf +++ b/test/fuzzing/fonts/3511ff5c1647150595846ac414c595cccac34f18 diff --git a/test/shaping/data/in-house/fonts/375d6ae32a3cbe52fbf81a4e5777e3377675d5a3.ttf b/test/fuzzing/fonts/375d6ae32a3cbe52fbf81a4e5777e3377675d5a3 Binary files differindex b284c9864..b284c9864 100644 --- a/test/shaping/data/in-house/fonts/375d6ae32a3cbe52fbf81a4e5777e3377675d5a3.ttf +++ b/test/fuzzing/fonts/375d6ae32a3cbe52fbf81a4e5777e3377675d5a3 diff --git a/test/shaping/data/in-house/fonts/43979b90b2dd929723cf4fe1715990bcb9c9a56b.ttf b/test/fuzzing/fonts/43979b90b2dd929723cf4fe1715990bcb9c9a56b Binary files differindex a5c0156c1..a5c0156c1 100644 --- a/test/shaping/data/in-house/fonts/43979b90b2dd929723cf4fe1715990bcb9c9a56b.ttf +++ b/test/fuzzing/fonts/43979b90b2dd929723cf4fe1715990bcb9c9a56b diff --git a/test/shaping/data/in-house/fonts/558661aa659912f4d30ecd27bd09835171a8e2b0.ttf b/test/fuzzing/fonts/558661aa659912f4d30ecd27bd09835171a8e2b0 Binary files differindex 5d72fdfe3..5d72fdfe3 100644 --- a/test/shaping/data/in-house/fonts/558661aa659912f4d30ecd27bd09835171a8e2b0.ttf +++ b/test/fuzzing/fonts/558661aa659912f4d30ecd27bd09835171a8e2b0 diff --git a/test/shaping/data/in-house/fonts/5a5daf5eb5a4db77a2baa3ad9c7a6ed6e0655fa8.ttf b/test/fuzzing/fonts/5a5daf5eb5a4db77a2baa3ad9c7a6ed6e0655fa8 Binary files differindex 9b4d23f5a..9b4d23f5a 100644 --- a/test/shaping/data/in-house/fonts/5a5daf5eb5a4db77a2baa3ad9c7a6ed6e0655fa8.ttf +++ b/test/fuzzing/fonts/5a5daf5eb5a4db77a2baa3ad9c7a6ed6e0655fa8 diff --git a/test/shaping/data/in-house/fonts/641bd9db850193064d17575053ae2bf8ec149ddc.ttf b/test/fuzzing/fonts/641bd9db850193064d17575053ae2bf8ec149ddc Binary files differindex 66cefd4d8..66cefd4d8 100644 --- a/test/shaping/data/in-house/fonts/641bd9db850193064d17575053ae2bf8ec149ddc.ttf +++ b/test/fuzzing/fonts/641bd9db850193064d17575053ae2bf8ec149ddc diff --git a/test/shaping/data/in-house/fonts/8240789f6d12d4cfc4b5e8e6f246c3701bcf861f.ttf b/test/fuzzing/fonts/8240789f6d12d4cfc4b5e8e6f246c3701bcf861f Binary files differindex 8eed14d94..8eed14d94 100644 --- a/test/shaping/data/in-house/fonts/8240789f6d12d4cfc4b5e8e6f246c3701bcf861f.ttf +++ b/test/fuzzing/fonts/8240789f6d12d4cfc4b5e8e6f246c3701bcf861f diff --git a/test/shaping/data/in-house/fonts/a34a9191d9376bda419836effeef7e75c1386016.ttf b/test/fuzzing/fonts/a34a9191d9376bda419836effeef7e75c1386016 Binary files differindex a358833c2..a358833c2 100644 --- a/test/shaping/data/in-house/fonts/a34a9191d9376bda419836effeef7e75c1386016.ttf +++ b/test/fuzzing/fonts/a34a9191d9376bda419836effeef7e75c1386016 diff --git a/test/shaping/data/in-house/fonts/a69118c2c2ada48ff803d9149daa54c9ebdae30e.ttf b/test/fuzzing/fonts/a69118c2c2ada48ff803d9149daa54c9ebdae30e Binary files differindex 3cd5b5671..3cd5b5671 100644 --- a/test/shaping/data/in-house/fonts/a69118c2c2ada48ff803d9149daa54c9ebdae30e.ttf +++ b/test/fuzzing/fonts/a69118c2c2ada48ff803d9149daa54c9ebdae30e diff --git a/test/shaping/data/in-house/fonts/b9e2aaa0d75fcef6971ec3a96d806ba4a6b31fe2.ttf b/test/fuzzing/fonts/b9e2aaa0d75fcef6971ec3a96d806ba4a6b31fe2 Binary files differindex 500276df5..500276df5 100644 --- a/test/shaping/data/in-house/fonts/b9e2aaa0d75fcef6971ec3a96d806ba4a6b31fe2.ttf +++ b/test/fuzzing/fonts/b9e2aaa0d75fcef6971ec3a96d806ba4a6b31fe2 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-5517117891805184 b/test/fuzzing/fonts/clusterfuzz-testcase-5517117891805184 Binary files differnew file mode 100644 index 000000000..0c7b518ba --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-5517117891805184 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-6107935408390144 b/test/fuzzing/fonts/clusterfuzz-testcase-6107935408390144 Binary files differnew file mode 100644 index 000000000..4c81a8660 --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-6107935408390144 diff --git a/test/shaping/data/in-house/fonts/ef2511f215aa3ca847cbfffbf861793b42170875.ttf b/test/fuzzing/fonts/clusterfuzz-testcase-hb-fuzzer-4666056377368576 Binary files differindex 6a3af4657..6a3af4657 100644 --- a/test/shaping/data/in-house/fonts/ef2511f215aa3ca847cbfffbf861793b42170875.ttf +++ b/test/fuzzing/fonts/clusterfuzz-testcase-hb-fuzzer-4666056377368576 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-hb-fuzzer-5662671558934528 b/test/fuzzing/fonts/clusterfuzz-testcase-hb-fuzzer-5662671558934528 Binary files differnew file mode 100644 index 000000000..cbb81acba --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-hb-fuzzer-5662671558934528 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-hb-fuzzer-6243458541944832 b/test/fuzzing/fonts/clusterfuzz-testcase-hb-fuzzer-6243458541944832 Binary files differnew file mode 100644 index 000000000..64864aa5c --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-hb-fuzzer-6243458541944832 diff --git a/test/shaping/data/in-house/fonts/9d8a94a67932a3ab75a596fc8b5c6d0392ca9e49.ttf b/test/fuzzing/fonts/clusterfuzz-testcase-hb-fuzzer-6303297511096320 Binary files differindex 3fb9951bb..3fb9951bb 100644 --- a/test/shaping/data/in-house/fonts/9d8a94a67932a3ab75a596fc8b5c6d0392ca9e49.ttf +++ b/test/fuzzing/fonts/clusterfuzz-testcase-hb-fuzzer-6303297511096320 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-hb-fuzzer-6696647723581440 b/test/fuzzing/fonts/clusterfuzz-testcase-hb-fuzzer-6696647723581440 Binary files differnew file mode 100644 index 000000000..8b1c29305 --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-hb-fuzzer-6696647723581440 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5634395566768128 b/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5634395566768128 Binary files differnew file mode 100644 index 000000000..cd1a2934f --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5634395566768128 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5688420752424960 b/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5688420752424960 Binary files differnew file mode 100644 index 000000000..1fe962b85 --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5688420752424960 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5728971283496960 b/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5728971283496960 Binary files differnew file mode 100644 index 000000000..25d7bf1de --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5728971283496960 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5746142327865344 b/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5746142327865344 Binary files differnew file mode 100644 index 000000000..1c1607b73 --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5746142327865344 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5750379279548416 b/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5750379279548416 Binary files differnew file mode 100644 index 000000000..f014d4b68 --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5750379279548416 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-4884742786777088 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-4884742786777088 Binary files differnew file mode 100644 index 000000000..ac7da9f9a --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-4884742786777088 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-5255344882188288 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-5255344882188288 Binary files differnew file mode 100644 index 000000000..ab1aede1f --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-5255344882188288 diff --git a/test/shaping/data/in-house/fonts/233c1e252e737ca79e03a9fd56b71aaa4a230f2b.ttf b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-5720051798769664 Binary files differindex 999f29622..999f29622 100644 --- a/test/shaping/data/in-house/fonts/233c1e252e737ca79e03a9fd56b71aaa4a230f2b.ttf +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-5720051798769664 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-5924299061854208 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-5924299061854208 Binary files differnew file mode 100644 index 000000000..a8ea33283 --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-5924299061854208 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-6460279560863744 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-6460279560863744 Binary files differnew file mode 100644 index 000000000..1cbe75a51 --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-6460279560863744 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5973566991106048 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5973566991106048 Binary files differnew file mode 100644 index 000000000..984bb4bd5 --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5973566991106048 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-4523479581851648 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-4523479581851648 Binary files differnew file mode 100644 index 000000000..1d16d70bc --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-4523479581851648 diff --git a/test/shaping/data/in-house/fonts/dd9f0c7c7c36f75a18be0cab1cddf8f3ab0f366b.ttf b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-4535496598355968 Binary files differindex ba8092854..ba8092854 100644 --- a/test/shaping/data/in-house/fonts/dd9f0c7c7c36f75a18be0cab1cddf8f3ab0f366b.ttf +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-4535496598355968 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-4548492505645056 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-4548492505645056 Binary files differnew file mode 100644 index 000000000..065080f3a --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-4548492505645056 diff --git a/test/shaping/data/in-house/fonts/243798dd281c1c77c065958e1ff467420faa9bde.ttf b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-4595692015190016 Binary files differindex dd8506eff..dd8506eff 100644 --- a/test/shaping/data/in-house/fonts/243798dd281c1c77c065958e1ff467420faa9bde.ttf +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-4595692015190016 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-4687441845813248 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-4687441845813248 Binary files differnew file mode 100644 index 000000000..d3e9f4694 --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-4687441845813248 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-4706238090706944 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-4706238090706944 Binary files differnew file mode 100644 index 000000000..269813a61 --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-4706238090706944 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-4769173588672512 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-4769173588672512 Binary files differnew file mode 100644 index 000000000..5426914d0 --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-4769173588672512 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-4827735151083520 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-4827735151083520 Binary files differnew file mode 100644 index 000000000..f5f1255e0 --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-4827735151083520 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-4841745322868736 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-4841745322868736 Binary files differnew file mode 100644 index 000000000..5e0f74d4f --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-4841745322868736 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-4884742786777088 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-4884742786777088 Binary files differnew file mode 100644 index 000000000..ac7da9f9a --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-4884742786777088 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5216838347653120 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5216838347653120 Binary files differnew file mode 100644 index 000000000..23cc59087 --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5216838347653120 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5255344882188288 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5255344882188288 Binary files differnew file mode 100644 index 000000000..ab1aede1f --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5255344882188288 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5294584596791296 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5294584596791296 Binary files differnew file mode 100644 index 000000000..bc1657958 --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5294584596791296 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5303930168803328 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5303930168803328 Binary files differnew file mode 100644 index 000000000..805fe4d4d --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5303930168803328 diff --git a/test/shaping/data/in-house/fonts/b6acef662e0beb8d5fcf5b61c6b0ca69537b7402.ttf b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5331901587914752 Binary files differindex 41897b693..41897b693 100644 --- a/test/shaping/data/in-house/fonts/b6acef662e0beb8d5fcf5b61c6b0ca69537b7402.ttf +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5331901587914752 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5388906574905344 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5388906574905344 Binary files differnew file mode 100644 index 000000000..5f7ff7c72 --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5388906574905344 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5517117891805184 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5517117891805184 Binary files differnew file mode 100644 index 000000000..0c7b518ba --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5517117891805184 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5617496443846656 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5617496443846656 Binary files differnew file mode 100644 index 000000000..aeffab5db --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5617496443846656 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5672141338968064 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5672141338968064 Binary files differnew file mode 100644 index 000000000..3c8303fd6 --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5672141338968064 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5700697074958336 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5700697074958336 Binary files differnew file mode 100644 index 000000000..2664e3070 --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5700697074958336 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5713868010553344 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5713868010553344 Binary files differnew file mode 100644 index 000000000..ee0a721b5 --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5713868010553344 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5720051798769664 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5720051798769664 Binary files differnew file mode 100644 index 000000000..999f29622 --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5720051798769664 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5924299061854208 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5924299061854208 Binary files differnew file mode 100644 index 000000000..a8ea33283 --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5924299061854208 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6023178755244032 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6023178755244032 Binary files differnew file mode 100644 index 000000000..b0da1527d --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6023178755244032 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6111685556305920 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6111685556305920 Binary files differnew file mode 100644 index 000000000..8c1940d85 --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6111685556305920 diff --git a/test/shaping/data/in-house/fonts/bbf4a308c402f0678c3e82844892a4da2ebe598f.ttf b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6160439919509504 Binary files differindex eb374002d..eb374002d 100644 --- a/test/shaping/data/in-house/fonts/bbf4a308c402f0678c3e82844892a4da2ebe598f.ttf +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6160439919509504 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6210176798425088 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6210176798425088 Binary files differnew file mode 100644 index 000000000..1c62961ec --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6210176798425088 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6260579246276608 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6260579246276608 Binary files differnew file mode 100644 index 000000000..036a20611 --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6260579246276608 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6264625609834496 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6264625609834496 Binary files differnew file mode 100644 index 000000000..035dd72f1 --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6264625609834496 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6278851874258944 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6278851874258944 Binary files differnew file mode 100644 index 000000000..775c91886 --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6278851874258944 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6424351550210048 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6424351550210048 Binary files differnew file mode 100644 index 000000000..afb08c52d --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6424351550210048 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6460279560863744 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6460279560863744 Binary files differnew file mode 100644 index 000000000..1cbe75a51 --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6460279560863744 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6576177596596224 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6576177596596224 Binary files differnew file mode 100644 index 000000000..35171ee31 --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6576177596596224 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6595199411159040 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6595199411159040 Binary files differnew file mode 100644 index 000000000..a4d503d40 --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6595199411159040 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6624904746106880 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6624904746106880 Binary files differnew file mode 100644 index 000000000..fcc1b6435 --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6624904746106880 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6723367514144768 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6723367514144768 Binary files differnew file mode 100644 index 000000000..55b1ef885 --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6723367514144768 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5630246225707008 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5630246225707008 Binary files differnew file mode 100644 index 000000000..ab534e31f --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5630246225707008 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5633985665826816 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5633985665826816 Binary files differnew file mode 100644 index 000000000..387d7fd46 --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5633985665826816 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5635082459545600 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5635082459545600 Binary files differnew file mode 100644 index 000000000..6d0feff4d --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5635082459545600 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5649959857160192 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5649959857160192 Binary files differnew file mode 100644 index 000000000..72e702ec6 --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5649959857160192 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5650286710882304 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5650286710882304 Binary files differnew file mode 100644 index 000000000..95322e184 --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5650286710882304 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5652019562414080 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5652019562414080 Binary files differnew file mode 100644 index 000000000..8e859800f --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5652019562414080 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5656511058018304 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5656511058018304 Binary files differnew file mode 100644 index 000000000..bb68572e9 --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5656511058018304 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5659641787187200 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5659641787187200 Binary files differnew file mode 100644 index 000000000..8a63dc4c8 --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5659641787187200 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5664873493561344 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5664873493561344 Binary files differnew file mode 100644 index 000000000..dfc36d897 --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5664873493561344 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5668791174823936 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5668791174823936 Binary files differnew file mode 100644 index 000000000..1f750c11c --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5668791174823936 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5672261407735808 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5672261407735808 Binary files differnew file mode 100644 index 000000000..629754944 --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5672261407735808 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5674361600606208 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5674361600606208 Binary files differnew file mode 100644 index 000000000..1d4f84a98 --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5674361600606208 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5677421274071040 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5677421274071040 Binary files differnew file mode 100644 index 000000000..3be3b91c2 --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5677421274071040 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5679244475105280 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5679244475105280 Binary files differnew file mode 100644 index 000000000..2894bdc0f --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5679244475105280 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5685596677210112 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5685596677210112 Binary files differnew file mode 100644 index 000000000..d9937a347 --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5685596677210112 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5688420752424960 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5688420752424960 Binary files differnew file mode 100644 index 000000000..e9f01a232 --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5688420752424960 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5695615258853376 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5695615258853376 Binary files differnew file mode 100644 index 000000000..af43a4433 --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5695615258853376 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5696686572175360 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5696686572175360 Binary files differnew file mode 100644 index 000000000..c6e8bfd86 --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5696686572175360 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5718464350650368 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5718464350650368 Binary files differnew file mode 100644 index 000000000..d511e9d10 --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5718464350650368 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5718889451749376 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5718889451749376 Binary files differnew file mode 100644 index 000000000..6360579be --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5718889451749376 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5719982789361664 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5719982789361664 Binary files differnew file mode 100644 index 000000000..0515086a1 --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5719982789361664 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5725129603022848 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5725129603022848 Binary files differnew file mode 100644 index 000000000..8ba0f9df5 --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5725129603022848 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5726089628876800 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5726089628876800 Binary files differnew file mode 100644 index 000000000..61750d4a0 --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5726089628876800 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5729361857085440 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5729361857085440 Binary files differnew file mode 100644 index 000000000..a6ecc6107 --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5729361857085440 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5733166795456512 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5733166795456512 Binary files differnew file mode 100644 index 000000000..dfaf6d9d7 --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5733166795456512 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5734736291430400 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5734736291430400 Binary files differnew file mode 100644 index 000000000..31c805cbc --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5734736291430400 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5738888765636608 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5738888765636608 Binary files differnew file mode 100644 index 000000000..28e72df7d --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5738888765636608 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5740171484463104 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5740171484463104 Binary files differnew file mode 100644 index 000000000..aef0d924c --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5740171484463104 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5750379279548416 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5750379279548416 Binary files differnew file mode 100644 index 000000000..b4551bfc2 --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5750379279548416 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5762490181353472 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5762490181353472 Binary files differnew file mode 100644 index 000000000..db06a1ccd --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5762490181353472 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5762953198960640 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5762953198960640 Binary files differnew file mode 100644 index 000000000..9d64eafd9 --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5762953198960640 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5764636557705216 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5764636557705216 Binary files differnew file mode 100644 index 000000000..b07416b07 --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5764636557705216 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5359635656605696 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5359635656605696 Binary files differnew file mode 100644 index 000000000..8a659c654 --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5359635656605696 diff --git a/test/api/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5521982557782016 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5521982557782016 Binary files differindex 55541f749..55541f749 100644 --- a/test/api/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5521982557782016 +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5521982557782016 diff --git a/test/api/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5542653037903872 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5542653037903872 Binary files differindex 6307ddd4b..6307ddd4b 100644 --- a/test/api/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5542653037903872 +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5542653037903872 diff --git a/test/api/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5609911946838016 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5609911946838016 Binary files differindex 8c647a8a4..8c647a8a4 100644 --- a/test/api/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5609911946838016 +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5609911946838016 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5629878397829120 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5629878397829120 Binary files differnew file mode 100644 index 000000000..a055cdb42 --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5629878397829120 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5651059347816448 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5651059347816448 Binary files differnew file mode 100644 index 000000000..b2e4034c0 --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5651059347816448 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5669437462544384 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5669437462544384 Binary files differnew file mode 100644 index 000000000..c4eb9091c --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5669437462544384 diff --git a/test/api/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5670861909524480 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5670861909524480 Binary files differindex 49bcb3098..49bcb3098 100644 --- a/test/api/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5670861909524480 +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5670861909524480 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5690658895953920 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5690658895953920 Binary files differnew file mode 100644 index 000000000..abafa4bc4 --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5690658895953920 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5695279609675776 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5695279609675776 Binary files differnew file mode 100644 index 000000000..f01626233 --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5695279609675776 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5696607199166464 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5696607199166464 Binary files differnew file mode 100644 index 000000000..ca4fcd74e --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5696607199166464 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5711951464759296 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5711951464759296 Binary files differnew file mode 100644 index 000000000..b20e8496b --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5711951464759296 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5718215406125056 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5718215406125056 Binary files differnew file mode 100644 index 000000000..a6d87dafb --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5718215406125056 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5743250149736448 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5743250149736448 Binary files differnew file mode 100644 index 000000000..b17c94996 --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5743250149736448 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5747265633779712 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5747265633779712 Binary files differnew file mode 100644 index 000000000..463e0c14e --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5747265633779712 diff --git a/test/api/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5750092395970560 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5750092395970560 Binary files differindex d622c2563..d622c2563 100644 --- a/test/api/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5750092395970560 +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5750092395970560 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5758598970343424 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5758598970343424 Binary files differnew file mode 100644 index 000000000..7087f63eb --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5758598970343424 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5765071062958080 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5765071062958080 Binary files differnew file mode 100644 index 000000000..1f9be049a --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5765071062958080 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6543700493598720 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6543700493598720 Binary files differnew file mode 100644 index 000000000..c0e981197 --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6543700493598720 diff --git a/test/api/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6651660668502016 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6651660668502016 Binary files differindex 6206f0776..6206f0776 100644 --- a/test/api/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6651660668502016 +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6651660668502016 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-get-codepoints-fuzzer-5203067375976448 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-get-codepoints-fuzzer-5203067375976448 Binary files differnew file mode 100644 index 000000000..cf92d88a0 --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-get-codepoints-fuzzer-5203067375976448 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-get-codepoints-fuzzer-5630904853069824 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-get-codepoints-fuzzer-5630904853069824 Binary files differnew file mode 100644 index 000000000..7c242eef5 --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-get-codepoints-fuzzer-5630904853069824 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-get-codepoints-fuzzer-5687638085337088 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-get-codepoints-fuzzer-5687638085337088 Binary files differnew file mode 100644 index 000000000..e8706f39b --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-get-codepoints-fuzzer-5687638085337088 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-get-codepoints-fuzzer-5736539338833920 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-get-codepoints-fuzzer-5736539338833920 Binary files differnew file mode 100644 index 000000000..f57262179 --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-get-codepoints-fuzzer-5736539338833920 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-get-codepoints-fuzzer-5930139383758848 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-get-codepoints-fuzzer-5930139383758848 Binary files differnew file mode 100644 index 000000000..940fbd503 --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-get-codepoints-fuzzer-5930139383758848 diff --git a/test/api/fonts/clusterfuzz-testcase-minimized-hb-subset-get-codepoints-fuzzer-5973295416475648 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-get-codepoints-fuzzer-5973295416475648 Binary files differindex b506d2a5a..b506d2a5a 100644 --- a/test/api/fonts/clusterfuzz-testcase-minimized-hb-subset-get-codepoints-fuzzer-5973295416475648 +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-get-codepoints-fuzzer-5973295416475648 diff --git a/test/api/fonts/clusterfuzz-testcase-minimized-hb-subset-get-codepoints-fuzzer-6136125075750912 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-get-codepoints-fuzzer-6136125075750912 Binary files differindex ffcea6460..ffcea6460 100644 --- a/test/api/fonts/clusterfuzz-testcase-minimized-hb-subset-get-codepoints-fuzzer-6136125075750912 +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-get-codepoints-fuzzer-6136125075750912 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-get-codepoints-fuzzer-6394290358976512 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-get-codepoints-fuzzer-6394290358976512 Binary files differnew file mode 100644 index 000000000..8ee7752aa --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-get-codepoints-fuzzer-6394290358976512 diff --git a/test/api/fonts/crash-4b60576767ee4d9fe1cc10959d89baf73d4e8249 b/test/fuzzing/fonts/crash-4b60576767ee4d9fe1cc10959d89baf73d4e8249 Binary files differindex b6b47ffe3..b6b47ffe3 100644 --- a/test/api/fonts/crash-4b60576767ee4d9fe1cc10959d89baf73d4e8249 +++ b/test/fuzzing/fonts/crash-4b60576767ee4d9fe1cc10959d89baf73d4e8249 diff --git a/test/api/fonts/crash-b577db318b30f2851828a4c9ef97cb30678b1b54 b/test/fuzzing/fonts/crash-b577db318b30f2851828a4c9ef97cb30678b1b54 Binary files differindex 00be056e6..00be056e6 100644 --- a/test/api/fonts/crash-b577db318b30f2851828a4c9ef97cb30678b1b54 +++ b/test/fuzzing/fonts/crash-b577db318b30f2851828a4c9ef97cb30678b1b54 diff --git a/test/api/fonts/crash-ccc61c92d589f895174cdef6ff2e3b20e9999a1a b/test/fuzzing/fonts/crash-ccc61c92d589f895174cdef6ff2e3b20e9999a1a Binary files differindex 1af243ebc..1af243ebc 100644 --- a/test/api/fonts/crash-ccc61c92d589f895174cdef6ff2e3b20e9999a1a +++ b/test/fuzzing/fonts/crash-ccc61c92d589f895174cdef6ff2e3b20e9999a1a diff --git a/test/api/fonts/crash-e4e0bb1458a91b692eba492c907ae1f94e635480 b/test/fuzzing/fonts/crash-e4e0bb1458a91b692eba492c907ae1f94e635480 Binary files differindex 890c4498f..890c4498f 100644 --- a/test/api/fonts/crash-e4e0bb1458a91b692eba492c907ae1f94e635480 +++ b/test/fuzzing/fonts/crash-e4e0bb1458a91b692eba492c907ae1f94e635480 diff --git a/test/shaping/data/in-house/fonts/e88c339237f52d21e01c55f01b9c1b4cc14a0467.ttf b/test/fuzzing/fonts/e88c339237f52d21e01c55f01b9c1b4cc14a0467 Binary files differindex e9884ea85..e9884ea85 100644 --- a/test/shaping/data/in-house/fonts/e88c339237f52d21e01c55f01b9c1b4cc14a0467.ttf +++ b/test/fuzzing/fonts/e88c339237f52d21e01c55f01b9c1b4cc14a0467 diff --git a/test/shaping/data/in-house/fonts/fab39d60d758cb586db5a504f218442cd1395725.ttf b/test/fuzzing/fonts/fab39d60d758cb586db5a504f218442cd1395725 Binary files differindex 451ed0477..451ed0477 100644 --- a/test/shaping/data/in-house/fonts/fab39d60d758cb586db5a504f218442cd1395725.ttf +++ b/test/fuzzing/fonts/fab39d60d758cb586db5a504f218442cd1395725 diff --git a/test/api/fonts/oom-6ef8c96d3710262511bcc730dce9c00e722cb653 b/test/fuzzing/fonts/oom-6ef8c96d3710262511bcc730dce9c00e722cb653 Binary files differindex 0bb0f0f01..0bb0f0f01 100644 --- a/test/api/fonts/oom-6ef8c96d3710262511bcc730dce9c00e722cb653 +++ b/test/fuzzing/fonts/oom-6ef8c96d3710262511bcc730dce9c00e722cb653 diff --git a/test/api/fonts/oom-ccc61c92d589f895174cdef6ff2e3b20e9999a1a b/test/fuzzing/fonts/oom-ccc61c92d589f895174cdef6ff2e3b20e9999a1a Binary files differindex 1af243ebc..1af243ebc 100644 --- a/test/api/fonts/oom-ccc61c92d589f895174cdef6ff2e3b20e9999a1a +++ b/test/fuzzing/fonts/oom-ccc61c92d589f895174cdef6ff2e3b20e9999a1a diff --git a/test/fuzzing/hb-shape-fuzzer.cc b/test/fuzzing/hb-shape-fuzzer.cc index 79f322297..b5a6c12e0 100644 --- a/test/fuzzing/hb-shape-fuzzer.cc +++ b/test/fuzzing/hb-shape-fuzzer.cc @@ -5,29 +5,29 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { - hb_blob_t *blob = hb_blob_create((const char *)data, size, - HB_MEMORY_MODE_READONLY, NULL, NULL); - hb_face_t *face = hb_face_create(blob, 0); - hb_font_t *font = hb_font_create(face); - hb_ot_font_set_funcs(font); - hb_font_set_scale(font, 12, 12); + hb_blob_t *blob = hb_blob_create ((const char *)data, size, + HB_MEMORY_MODE_READONLY, NULL, NULL); + hb_face_t *face = hb_face_create (blob, 0); + hb_font_t *font = hb_font_create (face); + hb_ot_font_set_funcs (font); + hb_font_set_scale (font, 12, 12); { const char text[] = "ABCDEXYZ123@_%&)*$!"; - hb_buffer_t *buffer = hb_buffer_create(); - hb_buffer_add_utf8(buffer, text, -1, 0, -1); - hb_buffer_guess_segment_properties(buffer); - hb_shape(font, buffer, NULL, 0); - hb_buffer_destroy(buffer); + hb_buffer_t *buffer = hb_buffer_create (); + hb_buffer_add_utf8 (buffer, text, -1, 0, -1); + hb_buffer_guess_segment_properties (buffer); + hb_shape (font, buffer, NULL, 0); + hb_buffer_destroy (buffer); } uint32_t text32[16]; - if (size > sizeof(text32)) { - memcpy(text32, data + size - sizeof(text32), sizeof(text32)); - hb_buffer_t *buffer = hb_buffer_create(); - hb_buffer_add_utf32(buffer, text32, sizeof(text32)/sizeof(text32[0]), 0, -1); - hb_buffer_guess_segment_properties(buffer); - hb_shape(font, buffer, NULL, 0); + if (size > sizeof (text32)) { + memcpy(text32, data + size - sizeof (text32), sizeof (text32)); + hb_buffer_t *buffer = hb_buffer_create (); + hb_buffer_add_utf32 (buffer, text32, sizeof (text32) / sizeof (text32[0]), 0, -1); + hb_buffer_guess_segment_properties (buffer); + hb_shape (font, buffer, NULL, 0); unsigned int len = hb_buffer_get_length (buffer); hb_glyph_info_t *infos = hb_buffer_get_glyph_infos (buffer, NULL); @@ -41,12 +41,12 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) hb_font_get_glyph_extents (font, info.codepoint, &extents); } - hb_buffer_destroy(buffer); + hb_buffer_destroy (buffer); } - hb_font_destroy(font); - hb_face_destroy(face); - hb_blob_destroy(blob); + hb_font_destroy (font); + hb_face_destroy (face); + hb_blob_destroy (blob); return 0; } diff --git a/test/fuzzing/hb-subset-fuzzer.cc b/test/fuzzing/hb-subset-fuzzer.cc index 28ce921c8..3a71f221f 100644 --- a/test/fuzzing/hb-subset-fuzzer.cc +++ b/test/fuzzing/hb-subset-fuzzer.cc @@ -6,17 +6,16 @@ #include "hb-subset.h" -void trySubset (hb_face_t *face, - const hb_codepoint_t text[], - int text_length, - bool drop_hints, - bool drop_ot_layout) +static void +trySubset (hb_face_t *face, + const hb_codepoint_t text[], + int text_length, + bool drop_hints, + bool drop_layout) { - hb_subset_profile_t *profile = hb_subset_profile_create (); - hb_subset_input_t *input = hb_subset_input_create_or_fail (); - *hb_subset_input_drop_hints (input) = drop_hints; - *hb_subset_input_drop_ot_layout (input) = drop_ot_layout; + hb_subset_input_set_drop_hints (input, drop_hints); + hb_subset_input_set_drop_layout (input, drop_layout); hb_set_t *codepoints = hb_subset_input_unicode_set (input); for (int i = 0; i < text_length; i++) @@ -24,23 +23,23 @@ void trySubset (hb_face_t *face, hb_set_add (codepoints, text[i]); } - hb_face_t *result = hb_subset (face, profile, input); + hb_face_t *result = hb_subset (face, input); hb_face_destroy (result); hb_subset_input_destroy (input); - hb_subset_profile_destroy (profile); } -void trySubset (hb_face_t *face, - const hb_codepoint_t text[], - int text_length) +static void +trySubset (hb_face_t *face, + const hb_codepoint_t text[], + int text_length) { for (unsigned int drop_hints = 0; drop_hints < 2; drop_hints++) { - for (unsigned int drop_ot_layout = 0; drop_ot_layout < 2; drop_ot_layout++) + for (unsigned int drop_layout = 0; drop_layout < 2; drop_layout++) { trySubset (face, text, text_length, - (bool) drop_hints, (bool) drop_ot_layout); + (bool) drop_hints, (bool) drop_layout); } } } @@ -48,22 +47,27 @@ void trySubset (hb_face_t *face, extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { hb_blob_t *blob = hb_blob_create ((const char *)data, size, - HB_MEMORY_MODE_READONLY, NULL, NULL); + HB_MEMORY_MODE_READONLY, NULL, NULL); hb_face_t *face = hb_face_create (blob, 0); + /* Just test this API here quickly. */ + hb_set_t *output = hb_set_create(); + hb_face_collect_unicodes (face, output); + hb_set_destroy (output); + const hb_codepoint_t text[] = { - 'A', 'B', 'C', 'D', 'E', 'X', 'Y', 'Z', '1', '2', - '3', '@', '_', '%', '&', ')', '*', '$', '!' + 'A', 'B', 'C', 'D', 'E', 'X', 'Y', 'Z', '1', '2', + '3', '@', '_', '%', '&', ')', '*', '$', '!' }; trySubset (face, text, sizeof (text) / sizeof (hb_codepoint_t)); hb_codepoint_t text_from_data[16]; if (size > sizeof(text_from_data)) { - memcpy(text_from_data, - data + size - sizeof(text_from_data), - sizeof(text_from_data)); + memcpy (text_from_data, + data + size - sizeof(text_from_data), + sizeof(text_from_data)); unsigned int text_size = sizeof (text_from_data) / sizeof (hb_codepoint_t); trySubset (face, text_from_data, text_size); } diff --git a/test/fuzzing/hb-subset-get-codepoints-fuzzer.cc b/test/fuzzing/hb-subset-get-codepoints-fuzzer.cc deleted file mode 100644 index 38f338ba4..000000000 --- a/test/fuzzing/hb-subset-get-codepoints-fuzzer.cc +++ /dev/null @@ -1,23 +0,0 @@ -#include "hb-fuzzer.hh" - -#include <stdlib.h> -#include <stdio.h> -#include <string.h> - -#include "hb-subset.h" - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) -{ - hb_blob_t *blob = hb_blob_create ((const char *)data, size, - HB_MEMORY_MODE_READONLY, NULL, NULL); - hb_face_t *face = hb_face_create (blob, 0); - - hb_set_t *output = hb_set_create(); - hb_subset_get_all_codepoints (face, output); - - hb_set_destroy (output); - hb_face_destroy (face); - hb_blob_destroy (blob); - - return 0; -} diff --git a/test/fuzzing/main.cc b/test/fuzzing/main.cc index 4692f7b5f..f15247cdb 100644 --- a/test/fuzzing/main.cc +++ b/test/fuzzing/main.cc @@ -1,21 +1,23 @@ #include "hb-fuzzer.hh" -#include <iostream> -#include <iterator> -#include <fstream> +#include <stdio.h> +#include <stdlib.h> #include <assert.h> -std::string FileToString(const std::string &Path) { - /* TODO This silently passes if file does not exist. Fix it! */ - std::ifstream T(Path.c_str()); - return std::string((std::istreambuf_iterator<char>(T)), - std::istreambuf_iterator<char>()); -} - int main(int argc, char **argv) { + hb_blob_t *blob = hb_blob_create_from_file (argv[1]); + unsigned int len; + const char *font_data = hb_blob_get_data (blob, &len); + if (len == 0) + { + printf ("Font not found.\n"); + exit (1); + } + for (int i = 1; i < argc; i++) { - std::string s = FileToString(argv[i]); - std::cout << argv[i] << std::endl; - LLVMFuzzerTestOneInput((const unsigned char*)s.data(), s.size()); + printf ("%s\n", argv[i]); + LLVMFuzzerTestOneInput((const uint8_t *) font_data, len); } + + hb_blob_destroy (blob); } diff --git a/test/fuzzing/run-shape-fuzzer-tests.py b/test/fuzzing/run-shape-fuzzer-tests.py index fea0b01b4..53c4f501a 100755 --- a/test/fuzzing/run-shape-fuzzer-tests.py +++ b/test/fuzzing/run-shape-fuzzer-tests.py @@ -2,7 +2,54 @@ from __future__ import print_function, division, absolute_import -import sys, os, subprocess +import sys, os, subprocess, tempfile, threading + + +def which(program): + # https://stackoverflow.com/a/377028 + def is_exe(fpath): + return os.path.isfile(fpath) and os.access(fpath, os.X_OK) + + fpath, _ = os.path.split(program) + if fpath: + if is_exe(program): + return program + else: + for path in os.environ["PATH"].split(os.pathsep): + exe_file = os.path.join(path, program) + if is_exe(exe_file): + return exe_file + + return None + + +def cmd(command): + # https://stackoverflow.com/a/4408409 + # https://stackoverflow.com/a/10012262 + with tempfile.TemporaryFile() as tempf: + p = subprocess.Popen (command, stderr=tempf) + is_killed = {'value': False} + + def timeout(p, is_killed): + is_killed['value'] = True + p.kill() + timer = threading.Timer (2, timeout, [p, is_killed]) + + try: + timer.start() + p.wait () + tempf.seek (0) + text = tempf.read().decode ("utf-8").strip () + returncode = p.returncode + finally: + timer.cancel() + + if is_killed['value']: + text = 'error: timeout, ' + text + returncode = 1 + + return text, returncode + srcdir = os.environ.get ("srcdir", ".") EXEEXT = os.environ.get ("EXEEXT", "") @@ -20,14 +67,30 @@ please provide it as the first argument to the tool""") print ('hb_shape_fuzzer:', hb_shape_fuzzer) fails = 0 -parent_path = os.path.join (srcdir, "..", "shaping", "data", "in-house", "tests") -for line in open (os.path.join (parent_path, "fuzzed.tests")): - font = line.split (":")[0] - font_path = os.path.join (parent_path, font) +valgrind = None +if os.environ.get('RUN_VALGRIND', ''): + valgrind = which ('valgrind') + +parent_path = os.path.join (srcdir, "fonts") +for file in os.listdir (parent_path): + path = os.path.join(parent_path, file) + + text, returncode = cmd ([hb_shape_fuzzer, path]) + print (text) + + failed = False + if returncode != 0 or 'error' in text: + print ('failure on %s' % file) + failed = True - p = subprocess.Popen ([hb_shape_fuzzer, font_path]) + if valgrind: + text, returncode = cmd ([valgrind, '--error-exitcode=1', hb_shape_fuzzer, path]) + if returncode: + print (text) + print ('failure on %s' % file) + failed = True - if p.wait () != 0: + if failed: fails = fails + 1 if fails: diff --git a/test/fuzzing/run-subset-fuzzer-tests.py b/test/fuzzing/run-subset-fuzzer-tests.py index 013628860..d4e3487f0 100755 --- a/test/fuzzing/run-subset-fuzzer-tests.py +++ b/test/fuzzing/run-subset-fuzzer-tests.py @@ -8,7 +8,6 @@ srcdir = os.environ.get ("srcdir", ".") EXEEXT = os.environ.get ("EXEEXT", "") top_builddir = os.environ.get ("top_builddir", ".") hb_subset_fuzzer = os.path.join (top_builddir, "hb-subset-fuzzer" + EXEEXT) -hb_subset_get_codepoints_fuzzer = os.path.join (top_builddir, "hb-subset-get-codepoints-fuzzer" + EXEEXT) if not os.path.exists (hb_subset_fuzzer): if len (sys.argv) < 2 or not os.path.exists (sys.argv[1]): @@ -18,35 +17,29 @@ please provide it as the first argument to the tool""") hb_subset_fuzzer = sys.argv[1] -if not os.path.exists (hb_subset_get_codepoints_fuzzer): - if len (sys.argv) < 3 or not os.path.exists (sys.argv[2]): - print ("""Failed to find hb-subset-get-codepoints-fuzzer binary automatically, -please provide it as the second argument to the tool""") - sys.exit (1) - - hb_subset_get_codepoints_fuzzer = sys.argv[2] - print ('hb_subset_fuzzer:', hb_subset_fuzzer) fails = 0 -parent_path = os.path.join (srcdir, "..", "subset", "data", "fonts") -print ("running subset fuzzer against fonts in %s" % parent_path) -for file in os.listdir (parent_path): - path = os.path.join(parent_path, file) +def run_dir (parent_path): + global fails + print ("running subset fuzzer against fonts in %s" % parent_path) + for file in os.listdir (parent_path): + path = os.path.join(parent_path, file) - print ("running subset fuzzer against %s" % path) - p = subprocess.Popen ([hb_subset_fuzzer, path]) + print ("running subset fuzzer against %s" % path) + p = subprocess.Popen ([hb_subset_fuzzer, path]) - if p.wait () != 0: - print ("failed for %s" % path) - fails = fails + 1 + if p.wait () != 0: + print ("failed for %s" % path) + fails = fails + 1 - print ("running subset get codepoints fuzzer against %s" % path) - p = subprocess.Popen ([hb_subset_get_codepoints_fuzzer, path]) + if p.wait () != 0: + print ("failed for %s" % path) + fails = fails + 1 - if p.wait () != 0: - print ("failed for %s" % path) - fails = fails + 1 +run_dir (os.path.join (srcdir, "..", "subset", "data", "fonts")) +# TODO running these tests very slow tests. Fix and re-enable +#run_dir (os.path.join (srcdir, "fonts")) if fails: print ("%i subset fuzzer related tests failed." % fails) diff --git a/test/shaping/Makefile.am b/test/shaping/Makefile.am index 732033650..5ca9bc197 100644 --- a/test/shaping/Makefile.am +++ b/test/shaping/Makefile.am @@ -8,6 +8,8 @@ SUBDIRS = data # Convenience targets: lib: @$(MAKE) $(AM_MAKEFLAGS) -C $(top_builddir)/src lib +libs: + @$(MAKE) $(AM_MAKEFLAGS) -C $(top_builddir)/src libs EXTRA_DIST += \ README.md \ diff --git a/test/shaping/data/in-house/Makefile.sources b/test/shaping/data/in-house/Makefile.sources index ef16faed4..6e21ddd4c 100644 --- a/test/shaping/data/in-house/Makefile.sources +++ b/test/shaping/data/in-house/Makefile.sources @@ -1,18 +1,20 @@ TESTS = \ + tests/aat-trak.tests \ tests/arabic-fallback-shaping.tests \ tests/arabic-feature-order.tests \ tests/arabic-like-joining.tests \ + tests/arabic-mark-attach.tests \ tests/arabic-mark-order.tests \ tests/arabic-stch.tests \ tests/automatic-fractions.tests \ tests/cluster.tests \ + tests/collections.tests \ tests/color-fonts.tests \ tests/context-matching.tests \ tests/cursive-positioning.tests \ tests/default-ignorables.tests \ - tests/emoji-flag-tags.tests \ + tests/emoji.tests \ tests/fallback-positioning.tests \ - tests/fuzzed.tests \ tests/hangul-jamo.tests \ tests/hyphens.tests \ tests/indic-consonant-with-stacker.tests \ @@ -25,13 +27,18 @@ TESTS = \ tests/indic-script-extensions.tests \ tests/indic-special-cases.tests \ tests/indic-syllable.tests \ + tests/indic-vowel-letter-spoofing.tests \ + tests/khmer-mark-order.tests \ + tests/khmer-misc.tests \ tests/language-tags.tests \ tests/ligature-id.tests \ tests/mark-attachment.tests \ tests/mark-filtering-sets.tests \ tests/mongolian-variation-selector.tests \ tests/myanmar-syllable.tests \ + tests/myanmar-zawgyi.tests \ tests/none-directional.tests \ + tests/rand.tests \ tests/spaces.tests \ tests/simple.tests \ tests/sinhala.tests \ @@ -39,6 +46,7 @@ TESTS = \ tests/tibetan-contractions-2.tests \ tests/tibetan-vowels.tests \ tests/use.tests \ + tests/use-indic3.tests \ tests/use-marchen.tests \ tests/use-syllable.tests \ tests/variations-rvrn.tests \ diff --git a/test/shaping/data/in-house/fonts/03e3f463c3a985bc42096620cc415342818454fb.ttf b/test/shaping/data/in-house/fonts/03e3f463c3a985bc42096620cc415342818454fb.ttf Binary files differnew file mode 100644 index 000000000..ee540f3bd --- /dev/null +++ b/test/shaping/data/in-house/fonts/03e3f463c3a985bc42096620cc415342818454fb.ttf diff --git a/test/shaping/data/in-house/fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf b/test/shaping/data/in-house/fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf Binary files differnew file mode 100644 index 000000000..383aee66e --- /dev/null +++ b/test/shaping/data/in-house/fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf diff --git a/test/shaping/data/in-house/fonts/28f497629c04ceb15546c9a70e0730125ed6698d.ttf b/test/shaping/data/in-house/fonts/28f497629c04ceb15546c9a70e0730125ed6698d.ttf Binary files differnew file mode 100644 index 000000000..13c4d8a3b --- /dev/null +++ b/test/shaping/data/in-house/fonts/28f497629c04ceb15546c9a70e0730125ed6698d.ttf diff --git a/test/shaping/data/in-house/fonts/2c25beb56d9c556622d56b0b5d02b4670c034f89.ttf b/test/shaping/data/in-house/fonts/2c25beb56d9c556622d56b0b5d02b4670c034f89.ttf Binary files differnew file mode 100644 index 000000000..ef94d3fc5 --- /dev/null +++ b/test/shaping/data/in-house/fonts/2c25beb56d9c556622d56b0b5d02b4670c034f89.ttf diff --git a/test/shaping/data/in-house/fonts/3c96e7a303c58475a8c750bf4289bbe73784f37d.ttf b/test/shaping/data/in-house/fonts/3c96e7a303c58475a8c750bf4289bbe73784f37d.ttf Binary files differnew file mode 100644 index 000000000..cebd37571 --- /dev/null +++ b/test/shaping/data/in-house/fonts/3c96e7a303c58475a8c750bf4289bbe73784f37d.ttf diff --git a/test/shaping/data/in-house/fonts/3cf6f8ac6d647473a43a3100e7494b202b2cfafe.ttf b/test/shaping/data/in-house/fonts/3cf6f8ac6d647473a43a3100e7494b202b2cfafe.ttf Binary files differnew file mode 100644 index 000000000..63c0c71bd --- /dev/null +++ b/test/shaping/data/in-house/fonts/3cf6f8ac6d647473a43a3100e7494b202b2cfafe.ttf diff --git a/test/shaping/data/in-house/fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf b/test/shaping/data/in-house/fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf Binary files differnew file mode 100644 index 000000000..14de6a184 --- /dev/null +++ b/test/shaping/data/in-house/fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf diff --git a/test/shaping/data/in-house/fonts/5bb74492f5e0ffa1fbb72e4c881be035120b6513.ttf b/test/shaping/data/in-house/fonts/5bb74492f5e0ffa1fbb72e4c881be035120b6513.ttf Binary files differnew file mode 100644 index 000000000..588ce3b93 --- /dev/null +++ b/test/shaping/data/in-house/fonts/5bb74492f5e0ffa1fbb72e4c881be035120b6513.ttf diff --git a/test/shaping/data/in-house/fonts/604026ae5aaca83c49cd8416909d71ba3e1c1194.ttf b/test/shaping/data/in-house/fonts/604026ae5aaca83c49cd8416909d71ba3e1c1194.ttf Binary files differnew file mode 100644 index 000000000..a6f1c9df3 --- /dev/null +++ b/test/shaping/data/in-house/fonts/604026ae5aaca83c49cd8416909d71ba3e1c1194.ttf diff --git a/test/shaping/data/in-house/fonts/641ca9d7808b01cafa9a666c13811c9b56eb9c52.ttf b/test/shaping/data/in-house/fonts/641ca9d7808b01cafa9a666c13811c9b56eb9c52.ttf Binary files differnew file mode 100644 index 000000000..1328e13ca --- /dev/null +++ b/test/shaping/data/in-house/fonts/641ca9d7808b01cafa9a666c13811c9b56eb9c52.ttf diff --git a/test/shaping/data/in-house/fonts/738d9f3b8c2dfd03875bf35a61d28fd78faf17c8.ttf b/test/shaping/data/in-house/fonts/738d9f3b8c2dfd03875bf35a61d28fd78faf17c8.ttf Binary files differnew file mode 100644 index 000000000..c3e4167fe --- /dev/null +++ b/test/shaping/data/in-house/fonts/738d9f3b8c2dfd03875bf35a61d28fd78faf17c8.ttf diff --git a/test/shaping/data/in-house/fonts/7d18685e1529e4ceaad5b6095dfab2f9789e5bce.ttf b/test/shaping/data/in-house/fonts/7d18685e1529e4ceaad5b6095dfab2f9789e5bce.ttf Binary files differnew file mode 100644 index 000000000..ffdddf325 --- /dev/null +++ b/test/shaping/data/in-house/fonts/7d18685e1529e4ceaad5b6095dfab2f9789e5bce.ttf diff --git a/test/shaping/data/in-house/fonts/881642af1667ae30a54e58de8be904566d00508f.ttf b/test/shaping/data/in-house/fonts/881642af1667ae30a54e58de8be904566d00508f.ttf Binary files differnew file mode 100644 index 000000000..a749cdf42 --- /dev/null +++ b/test/shaping/data/in-house/fonts/881642af1667ae30a54e58de8be904566d00508f.ttf diff --git a/test/shaping/data/in-house/fonts/9fc3e6960b3520e5304033ef5fd540285f72f14d.ttf b/test/shaping/data/in-house/fonts/9fc3e6960b3520e5304033ef5fd540285f72f14d.ttf Binary files differnew file mode 100644 index 000000000..1841cf37b --- /dev/null +++ b/test/shaping/data/in-house/fonts/9fc3e6960b3520e5304033ef5fd540285f72f14d.ttf diff --git a/test/shaping/data/in-house/fonts/TestDFONT.dfont b/test/shaping/data/in-house/fonts/TestDFONT.dfont Binary files differnew file mode 100644 index 000000000..a6ea7009b --- /dev/null +++ b/test/shaping/data/in-house/fonts/TestDFONT.dfont diff --git a/test/shaping/data/in-house/fonts/TestTRAK.ttf b/test/shaping/data/in-house/fonts/TestTRAK.ttf Binary files differnew file mode 100644 index 000000000..07ae3afd8 --- /dev/null +++ b/test/shaping/data/in-house/fonts/TestTRAK.ttf diff --git a/test/shaping/data/in-house/fonts/TestTTC.ttc b/test/shaping/data/in-house/fonts/TestTTC.ttc Binary files differnew file mode 100644 index 000000000..a21fe89dc --- /dev/null +++ b/test/shaping/data/in-house/fonts/TestTTC.ttc diff --git a/test/shaping/data/in-house/fonts/ab14b4eb9d7a67e293f51d30d719add06c9d6e06.ttf b/test/shaping/data/in-house/fonts/ab14b4eb9d7a67e293f51d30d719add06c9d6e06.ttf Binary files differnew file mode 100644 index 000000000..a64eceac6 --- /dev/null +++ b/test/shaping/data/in-house/fonts/ab14b4eb9d7a67e293f51d30d719add06c9d6e06.ttf diff --git a/test/shaping/data/in-house/fonts/af85624080af5627fb050f570d148a62f04fda74.ttf b/test/shaping/data/in-house/fonts/af85624080af5627fb050f570d148a62f04fda74.ttf Binary files differnew file mode 100644 index 000000000..9cd40d4e7 --- /dev/null +++ b/test/shaping/data/in-house/fonts/af85624080af5627fb050f570d148a62f04fda74.ttf diff --git a/test/shaping/data/in-house/fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf b/test/shaping/data/in-house/fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf Binary files differnew file mode 100644 index 000000000..a9dc202b5 --- /dev/null +++ b/test/shaping/data/in-house/fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf diff --git a/test/shaping/data/in-house/fonts/bb29ce50df2bdba2d10726427c6b7609bf460e04.ttf b/test/shaping/data/in-house/fonts/bb29ce50df2bdba2d10726427c6b7609bf460e04.ttf Binary files differdeleted file mode 100644 index fba200f10..000000000 --- a/test/shaping/data/in-house/fonts/bb29ce50df2bdba2d10726427c6b7609bf460e04.ttf +++ /dev/null diff --git a/test/shaping/data/in-house/fonts/d3129450fafe5e5c98cfc25a4e71809b1b4d2855.ttf b/test/shaping/data/in-house/fonts/d3129450fafe5e5c98cfc25a4e71809b1b4d2855.ttf Binary files differnew file mode 100644 index 000000000..dbd928aa0 --- /dev/null +++ b/test/shaping/data/in-house/fonts/d3129450fafe5e5c98cfc25a4e71809b1b4d2855.ttf diff --git a/test/shaping/data/in-house/tests/aat-trak.tests b/test/shaping/data/in-house/tests/aat-trak.tests new file mode 100644 index 000000000..48b224f33 --- /dev/null +++ b/test/shaping/data/in-house/tests/aat-trak.tests @@ -0,0 +1,8 @@ +../fonts/TestTRAK.ttf::U+0041,U+0042,U+0043:[A.alt=0+1000|B=1+1000|C.alt=2+1000] +../fonts/TestTRAK.ttf:--font-ptem=.5:U+0041,U+0042,U+0043:[A.alt=0@100,0+1200|B=1@100,0+1200|C.alt=2@100,0+1200] +../fonts/TestTRAK.ttf:--font-ptem=1:U+0041,U+0042,U+0043:[A.alt=0@100,0+1200|B=1@100,0+1200|C.alt=2@100,0+1200] +../fonts/TestTRAK.ttf:--font-ptem=2:U+0041,U+0042,U+0043:[A.alt=0@93,0+1187|B=1@93,0+1187|C.alt=2@93,0+1187] +../fonts/TestTRAK.ttf:--font-ptem=9:U+0041,U+0042,U+0043:[A.alt=0+1000|B=1+1000|C.alt=2+1000] +../fonts/TestTRAK.ttf:--font-ptem=24:U+0041,U+0042,U+0043:[A.alt=0@-12,0+976|B=1@-12,0+976|C.alt=2@-12,0+976] +../fonts/TestTRAK.ttf:--font-ptem=72:U+0041,U+0042,U+0043:[A.alt=0@-50,0+900|B=1@-50,0+900|C.alt=2@-50,0+900] +../fonts/TestTRAK.ttf:--font-ptem=144:U+0041,U+0042,U+0043:[A.alt=0@-107,0+786|B=1@-107,0+786|C.alt=2@-107,0+786] diff --git a/test/shaping/data/in-house/tests/arabic-mark-attach.tests b/test/shaping/data/in-house/tests/arabic-mark-attach.tests new file mode 100644 index 000000000..a577e51ad --- /dev/null +++ b/test/shaping/data/in-house/tests/arabic-mark-attach.tests @@ -0,0 +1 @@ +../fonts/641ca9d7808b01cafa9a666c13811c9b56eb9c52.ttf::U+064A,U+0633,U+06E1,U+200D,U+0654,U+064E,U+0644:[afii57444.zz04=6+1091|afii57454=1@75,925+0|uni0654=1+0|space=1+0|uni06E1=1@950,1115+0|afii57427.zz03_calt=1+1847|afii57450.zz21=0+345] diff --git a/test/shaping/data/in-house/tests/collections.tests b/test/shaping/data/in-house/tests/collections.tests new file mode 100644 index 000000000..85653c543 --- /dev/null +++ b/test/shaping/data/in-house/tests/collections.tests @@ -0,0 +1,6 @@ +../fonts/TestDFONT.dfont:--face-index=0 --font-funcs=ot:U+2026,U+0020,U+002E:[ellipsis=0+723|space=1+250|period=2+241] +../fonts/TestDFONT.dfont:--face-index=1 --font-funcs=ot:U+2026,U+0020,U+002E:[gid0=0+1000|gid0=1+1000|gid0=2+1000] +../fonts/TestDFONT.dfont:--face-index=2 --font-funcs=ot:U+2026,U+0020,U+002E:[gid0=0+1000|gid0=1+1000|gid0=2+1000] +../fonts/TestTTC.ttc:--face-index=0 --font-funcs=ot:U+2026,U+0020,U+002E:[ellipsis=0+723|space=1+250|period=2+241] +../fonts/TestTTC.ttc:--face-index=1 --font-funcs=ot:U+2026,U+0020,U+002E:[ellipsis=0+723|space=1+250|period=2+241] +../fonts/TestTTC.ttc:--face-index=2 --font-funcs=ot:U+2026,U+0020,U+002E:[gid0=0+1000|gid0=1+1000|gid0=2+1000] diff --git a/test/shaping/data/in-house/tests/cursive-positioning.tests b/test/shaping/data/in-house/tests/cursive-positioning.tests index 74d283db8..15a1ffc9c 100644 --- a/test/shaping/data/in-house/tests/cursive-positioning.tests +++ b/test/shaping/data/in-house/tests/cursive-positioning.tests @@ -2,3 +2,4 @@ ../fonts/298c9e1d955f10f6f72c6915c3c6ff9bf9695cec.ttf::U+0643,U+0645,U+0645,U+062B,U+0644:[gid8=4+738|gid5=3@441,1197+0|gid6=3@0,432+405|gid9=2@0,477+500|gid9=1@0,577+452|gid10=0@20,1177+207] #../fonts/706c5d7b625f207bc0d874c67237aad6f1e9cd6f.ttf::U+0B1F,U+0B4D,U+0B1A,U+0B4D,U+0B1A:[ttaorya=0+1307|casubscriptorya=0@-242,104+-231|casubscriptnarroworya=0@20,104+507] ../fonts/07f054357ff8638bac3711b422a1e31180bba863.ttf:--font-funcs=ot --no-glyph-names:U+0606,U+06E1:[2=0@40,502+0|1=0+1000] +../fonts/9fc3e6960b3520e5304033ef5fd540285f72f14d.ttf::U+16F0A,U+16F57,U+16F8F:[u16F0A=0+422|u16F57=0@0,209+338|u16F8F=0+0] diff --git a/test/shaping/data/in-house/tests/emoji-flag-tags.tests b/test/shaping/data/in-house/tests/emoji-flag-tags.tests deleted file mode 100644 index 189de55a5..000000000 --- a/test/shaping/data/in-house/tests/emoji-flag-tags.tests +++ /dev/null @@ -1,2 +0,0 @@ -../fonts/53374c7ca3657be37efde7ed02ae34229a56ae1f.ttf::U+1F3F4,U+E0055,U+E0053,U+E0064,U+E0065,U+E007F:[u1F3F4=0+2126|space=1+0|space=2+0|space=3+0|space=4+0|space=5+0] -../fonts/53374c7ca3657be37efde7ed02ae34229a56ae1f.ttf::U+1F3F4,U+E0064,U+E0065,U+E007F:[de=0+3200] diff --git a/test/shaping/data/in-house/tests/emoji.tests b/test/shaping/data/in-house/tests/emoji.tests new file mode 100644 index 000000000..8d9b2541f --- /dev/null +++ b/test/shaping/data/in-house/tests/emoji.tests @@ -0,0 +1,4 @@ +../fonts/53374c7ca3657be37efde7ed02ae34229a56ae1f.ttf::U+1F3F4,U+E0055,U+E0053,U+E0064,U+E0065,U+E007F:[u1F3F4=0+2126|space=1+0|space=2+0|space=3+0|space=4+0|space=5+0] +../fonts/53374c7ca3657be37efde7ed02ae34229a56ae1f.ttf::U+1F3F4,U+E0064,U+E0065,U+E007F:[de=0+3200] +../fonts/3cf6f8ac6d647473a43a3100e7494b202b2cfafe.ttf:--font-funcs=ot --direction=l:U+1F481,U+1F3FB,U+200D,U+2642,U+FE0F:[gid7=0+2550] +../fonts/3cf6f8ac6d647473a43a3100e7494b202b2cfafe.ttf:--font-funcs=ot --direction=r:U+1F481,U+1F3FB,U+200D,U+2642,U+FE0F:[gid7=0+2550] diff --git a/test/shaping/data/in-house/tests/fuzzed.tests b/test/shaping/data/in-house/tests/fuzzed.tests deleted file mode 100644 index 43a193341..000000000 --- a/test/shaping/data/in-house/tests/fuzzed.tests +++ /dev/null @@ -1,23 +0,0 @@ -../fonts/1a6f1687b7a221f9f2c834b0b360d3c8463b6daf.ttf:--font-funcs=ot:U+0041:[gid0=0+1000] -../fonts/5a5daf5eb5a4db77a2baa3ad9c7a6ed6e0655fa8.ttf:--font-funcs=ot:U+0041:[gid0=0+1000] -../fonts/0509e80afb379d16560e9e47bdd7d888bebdebc6.ttf:--font-funcs=ot:U+0041:[gid0=0+1000] -../fonts/641bd9db850193064d17575053ae2bf8ec149ddc.ttf:--font-funcs=ot:U+0041:[gid0=0+1000] -../fonts/375d6ae32a3cbe52fbf81a4e5777e3377675d5a3.ttf:--font-funcs=ot:U+0041:[gid0=0+4352] -../fonts/8240789f6d12d4cfc4b5e8e6f246c3701bcf861f.ttf:--font-funcs=ot:U+0041:[gid0=0+1024] -../fonts/b9e2aaa0d75fcef6971ec3a96d806ba4a6b31fe2.ttf:--font-funcs=ot:U+0041:[gid0=0+1000|gid1=0+1000|gid8=0+1000|gid3=0+1000|gid0=0+1000|gid1=0+1000|gid1=0+1000|gid8=0+1000|gid3=0+1000|gid0=0+1000|gid1=0+1000|gid8=0+1000|gid3=0+1000|gid0=0+1000|gid1=0+1000|gid1=0+1000] -../fonts/43979b90b2dd929723cf4fe1715990bcb9c9a56b.ttf:--font-funcs=ot:U+0041:[gid0=0+1000] -../fonts/3511ff5c1647150595846ac414c595cccac34f18.ttf:--font-funcs=ot --no-positions --no-clusters --no-glyph-names:U+0041:[0|512|15104|11004|3408|18244|17872|17961|0|992|15616|0|14151|20559|20992|5440|256|0|10|8960|256|1024|1490|0|768|4096|256|2216|0|256|256|0|768|10752|11004|3408|18244|17734|53248|256|0|512|14848|10793|57344|768|18227|20285|20480|0|256|0|810|0|11004|3408|18244|17734|53289|57344|768|15667|71|0|20559|21248|256|0|2816|2776|0|51516|0|32|26209|28005|65249|29690|0|51548|0|2454|28783|29556|1291|3458|80|0|2804|210|28786|25968|45763|50546|0|59136|0|38144|256|0|2560|30208|52224|580|17996|21504|6734|108|116|24846|1024|0|255|65280|256|0|8704|1345|23109|8192|10823|21076|8192|12877|20300|8192|6738|20301|8192|16980|21067|8251|18944|255|65280|15360|256|255|65280|256|768|255|65280|256|768|255|65280|256|1024|12|65280|256|1280|255|65280|256|1536|1899|25970|110|11264|27502|29285|12907|25974|28160|14443|25970|28288|3|118|18259|21826|45716|46369|0|0|1|16|17|256|4|16|18244|17734|28|12|0|284|0|28|18256|20307|45114|47616|226|10296|0|57927|1|0|0|21248|5440|256|0|10|768|256|1024|512|0|297|16|24833|28774|10794|2304|29|32|42|64515|42|42|64525|20551|17477|18128|10720|3|61|3408|18244|17734|53289|57344|768|15616|512|55|10576|20307|0|255|56063|53504|42|42|64525|12288|18176|80|20307|1|0|62] -../fonts/fab39d60d758cb586db5a504f218442cd1395725.ttf:--font-funcs=ot:U+0041,U+0041:[gid0=0+1000|gid0=1+1000] -../fonts/205edd09bd3d141cc9580f650109556cc28b22cb.ttf:--font-funcs=ot:U+0041:[gid0=0+1000] -../fonts/217a934cfe15c548b572c203dceb2befdf026462.ttf:--font-funcs=ot:U+0061,U+0061,U+0061:[] -../fonts/558661aa659912f4d30ecd27bd09835171a8e2b0.ttf:--font-funcs=ot:U+FFFD,U+E0100,U+FFFD,U+E0010:[] -../fonts/a34a9191d9376bda419836effeef7e75c1386016.ttf:--font-funcs=ot:U+0041:[] -../fonts/a69118c2c2ada48ff803d9149daa54c9ebdae30e.ttf:--font-funcs=ot:U+0041:[gid0=0+1229] -../fonts/b6acef662e0beb8d5fcf5b61c6b0ca69537b7402.ttf:--font-funcs=ot:U+0041:[gid0=0+1000] -../fonts/e88c339237f52d21e01c55f01b9c1b4cc14a0467.ttf:--font-funcs=ot:U+0041:[gid0=0+1000] -../fonts/243798dd281c1c77c065958e1ff467420faa9bde.ttf:--font-funcs=ot:U+0041:[gid0=0+1000] -../fonts/dd9f0c7c7c36f75a18be0cab1cddf8f3ab0f366b.ttf:--font-funcs=ot --no-positions --no-clusters --no-glyph-names:U+0041:[0|0|2|0|0|2|0|0|2|0|0|2|0|0|2|0|0|2|0|0|0|2|0|0|0|2|0|0|2|0|0|2|0|0|2|0|0|2|0|0|0|2|0|0|2|0|0|2|0|0|2|0] -../fonts/ef2511f215aa3ca847cbfffbf861793b42170875.ttf:--font-funcs=ot:U+0041:[gid0=0+1000] -../fonts/9d8a94a67932a3ab75a596fc8b5c6d0392ca9e49.ttf:--font-funcs=ot:U+0041:[gid0=0+1000] -../fonts/bbf4a308c402f0678c3e82844892a4da2ebe598f.ttf:--font-funcs=ot:U+0041:[gid0=0+1000] -../fonts/233c1e252e737ca79e03a9fd56b71aaa4a230f2b.ttf:--font-funcs=ot:U+0041:[gid0=0+1000] diff --git a/test/shaping/data/in-house/tests/indic-joiner-candrabindu.tests b/test/shaping/data/in-house/tests/indic-joiner-candrabindu.tests index 87b36035a..6b75137fe 100644 --- a/test/shaping/data/in-house/tests/indic-joiner-candrabindu.tests +++ b/test/shaping/data/in-house/tests/indic-joiner-candrabindu.tests @@ -1,2 +1,2 @@ ../fonts/5028afb650b1bb718ed2131e872fbcce57828fff.ttf::U+0B13,U+200D,U+0B01:[omorya=0+1450] -../fonts/5028afb650b1bb718ed2131e872fbcce57828fff.ttf::U+0B13,U+200C,U+0B01:[oorya=0+1309|space=0+0|candrabinduorya=0+0] +../fonts/5028afb650b1bb718ed2131e872fbcce57828fff.ttf::U+0B13,U+200C,U+0B01:[oorya=0+1309|space=1+0|candrabinduorya=1+0] diff --git a/test/shaping/data/in-house/tests/indic-joiners.tests b/test/shaping/data/in-house/tests/indic-joiners.tests index dca83f87d..80e392cfc 100644 --- a/test/shaping/data/in-house/tests/indic-joiners.tests +++ b/test/shaping/data/in-house/tests/indic-joiners.tests @@ -1,6 +1,6 @@ -../fonts/f443753e8ffe8e8aae606cfba158e00334b6efb1.ttf::U+179A,U+1784,U+17D2,U+179F,U+200C,U+17CA,U+17B8,U+0020:[uni179a=0+775|uni1784=1+1550|uni179f.sub=1+775|space=1+0|uni17ca=1+0|uni17b8=1@0,300+0|space=7+600] +../fonts/f443753e8ffe8e8aae606cfba158e00334b6efb1.ttf::U+179A,U+1784,U+17D2,U+179F,U+200C,U+17CA,U+17B8,U+0020:[uni179a=0+775|uni1784=1+1550|uni179f.sub=1+775|space=4+0|uni17ca=4+0|uni17b8=4@0,300+0|space=7+600] ../fonts/f443753e8ffe8e8aae606cfba158e00334b6efb1.ttf::U+179A,U+1784,U+17D2,U+179F,U+17CA,U+17B8:[uni179a=0+775|uni1784=1+1550|uni179f.sub=1+775|uni17bb=1@-75,-700+0|uni17b8=1+0] -../fonts/8116e5d8fedfbec74e45dc350d2416d810bed8c4.ttf:--font-funcs=ft:U+091F,U+094D,U+200C,U+092F,U+093F:[uni091F=0+876|uni094D=0@4,0+0|space=0+0|uni093F.750=3+397|uni092F=3+924] +../fonts/8116e5d8fedfbec74e45dc350d2416d810bed8c4.ttf:--font-funcs=ft:U+091F,U+094D,U+200C,U+092F,U+093F:[uni091F=0+876|uni094D=0@4,0+0|space=2+0|uni093F.750=3+397|uni092F=3+924] ../fonts/8116e5d8fedfbec74e45dc350d2416d810bed8c4.ttf:--font-funcs=ft:U+091F,U+094D,U+200D,U+092F,U+093F:[uni093F=0+398|uni091F=0+876|uni094D=0@4,0+0|space=0+0|uni092F=0+924] -../fonts/8116e5d8fedfbec74e45dc350d2416d810bed8c4.ttf:--font-funcs=ft:U+091F,U+094D,U+200D,U+091F,U+094D,U+200C,U+091F,U+094D,U+200D,U+092F,U+093F:[uni091F=0+876|uni094D=0@4,0+0|space=0+0|uni091F=3+876|uni094D=3@4,0+0|space=3+0|uni093F=6+398|uni091F=6+876|uni094D=6@4,0+0|space=6+0|uni092F=6+924] +../fonts/8116e5d8fedfbec74e45dc350d2416d810bed8c4.ttf:--font-funcs=ft:U+091F,U+094D,U+200D,U+091F,U+094D,U+200C,U+091F,U+094D,U+200D,U+092F,U+093F:[uni091F=0+876|uni094D=0@4,0+0|space=0+0|uni091F=3+876|uni094D=3@4,0+0|space=5+0|uni093F=6+398|uni091F=6+876|uni094D=6@4,0+0|space=6+0|uni092F=6+924] ../fonts/8116e5d8fedfbec74e45dc350d2416d810bed8c4.ttf:--font-funcs=ft:U+091F,U+094D,U+200D,U+091F,U+094D,U+200D,U+091F,U+094D,U+200D,U+092F,U+093F:[uni093F=0+398|uni091F=0+876|uni094D=0@4,0+0|space=0+0|uni091F=0+876|uni094D=0@4,0+0|space=0+0|uni091F=0+876|uni094D=0@4,0+0|space=0+0|uni092F=0+924] diff --git a/test/shaping/data/in-house/tests/indic-vowel-letter-spoofing.tests b/test/shaping/data/in-house/tests/indic-vowel-letter-spoofing.tests new file mode 100644 index 000000000..f8305a312 --- /dev/null +++ b/test/shaping/data/in-house/tests/indic-vowel-letter-spoofing.tests @@ -0,0 +1,53 @@ +../fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf::U+0904,U+0020,U+0905,U+0946:[ashortdeva=0+764|space=1+260|adeva=2+764|uni25CC=2+510|eshortvowelsigndeva=2+0] +../fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf::U+0906,U+0020,U+0905,U+093E:[aadeva=0+1023|space=1+260|adeva=2+764|uni25CC=2+510|aavowelsigndeva=2+259] +../fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf::U+0908,U+0020,U+0930,U+094D,U+0907:[iideva=0+491|space=1+260|uni25CC=2+510|rephdeva=2+0|ideva=2+491] +../fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf::U+090A,U+0020,U+0909,U+0941:[uudeva=0+765|space=1+260|udeva=2+548|uni25CC=2+510|uvowelsigndeva=2+0] +../fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf::U+090D,U+0020,U+090F,U+0945:[ecandradeva=0+553|space=1+260|edeva=2+553|uni25CC=2+510|ecandravowelsigndeva=2+0] +../fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf::U+090E,U+0020,U+090F,U+0946:[eshortdeva=0+553|space=1+260|edeva=2+553|uni25CC=2+510|eshortvowelsigndeva=2+0] +../fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf::U+0910,U+0020,U+090F,U+0947:[aideva=0+553|space=1+260|edeva=2+553|uni25CC=2+510|evowelsigndeva=2+0] +../fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf::U+0911,U+0020,U+0905,U+0949,U+0020,U+0906,U+0945:[ocandradeva=0+1023|space=1+260|adeva=2+764|uni25CC=2+510|ocandravowelsigndeva=2+259|space=4+260|aadeva=5+1023|uni25CC=5+510|ecandravowelsigndeva=5+0] +../fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf::U+0912,U+0020,U+0905,U+094A,U+0020,U+0906,U+0946:[oshortdeva=0+1023|space=1+260|adeva=2+764|uni25CC=2+510|oshortvowelsigndeva=2+259|space=4+260|aadeva=5+1023|uni25CC=5+510|eshortvowelsigndeva=5+0] +../fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf::U+0913,U+0020,U+0905,U+094B,U+0020,U+0906,U+0947:[odeva=0+1023|space=1+260|adeva=2+764|uni25CC=2+510|ovowelsigndeva=2+259|space=4+260|aadeva=5+1023|uni25CC=5+510|evowelsigndeva=5+0] +../fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf::U+0914,U+0020,U+0905,U+094C,U+0020,U+0906,U+0948:[audeva=0+1023|space=1+260|adeva=2+764|uni25CC=2+510|auvowelsigndeva=2+259|space=4+260|aadeva=5+1023|uni25CC=5+510|aivowelsigndeva=5+0] +../fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf::U+0972,U+0020,U+0905,U+0945:[acandradeva=0+764|space=1+260|adeva=2+764|uni25CC=2+510|ecandravowelsigndeva=2+0] +../fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf::U+0973,U+0020,U+0905,U+093A:[oedeva=0+764|space=1+260|adeva=2+764|uni25CC=2+510|oevowelsigndeva=2+0] +../fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf::U+0974,U+0020,U+0905,U+093B,U+0020,U+0906,U+093A:[ooedeva=0+1023|space=1+260|adeva=2+764|uni25CC=2+510|ooevowelsigndeva=2+259|space=4+260|aadeva=5+1023|uni25CC=5+510|oevowelsigndeva=5+0] +../fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf::U+0975,U+0020,U+0905,U+094F:[awdeva=0+1023|space=1+260|adeva=2+764|uni25CC=2+510|awvowelsigndeva=2+259] +../fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf::U+0976,U+0020,U+0905,U+0956:[uedeva=0+764|space=1+260|adeva=2+764|uni25CC=2+510|uevowelsigndeva=2@50,0+0] +../fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf::U+0977,U+0020,U+0905,U+0957:[uuedeva=0+764|space=1+260|adeva=2+764|uni25CC=2+510|uuevowelsigndeva=2@50,0+0] +../fonts/881642af1667ae30a54e58de8be904566d00508f.ttf::U+0986,U+0020,U+0985,U+09BE:[aabeng=0+1158|space=1+260|abeng=2+893|uni25CC=2+510|aavowelsignbeng=2+266] +../fonts/881642af1667ae30a54e58de8be904566d00508f.ttf::U+09E0,U+0020,U+098B,U+09C3:[rrvocalicbeng=0+853|space=1+260|rvocalicbeng=2+853|uni25CC=2+510|rvocalicvowelsignbeng=2+0] +../fonts/881642af1667ae30a54e58de8be904566d00508f.ttf::U+09E1,U+0020,U+098C,U+09E2:[llvocalicbeng=0+639|space=1+260|lvocalicbeng=2+639|uni25CC=2+510|lvocalicvowelsignbeng=2+0] +../fonts/604026ae5aaca83c49cd8416909d71ba3e1c1194.ttf::U+0A06,U+0020,U+0A05,U+0A3E:[aaguru=0+2001|space=1+532|aguru=2+1520|uni25CC=2+1044|aamatraguru=2+481] +../fonts/604026ae5aaca83c49cd8416909d71ba3e1c1194.ttf::U+0A07,U+0020,U+0A72,U+0A3F:[iguru=0+1671|space=1+532|iriguru=2+1141|imatraguru=2+530|uni25CC=2+1044] +../fonts/604026ae5aaca83c49cd8416909d71ba3e1c1194.ttf::U+0A08,U+0020,U+0A72,U+0A40:[iiguru=0+1671|space=1+532|iriguru=2+1141|uni25CC=2+1044|iimatraguru=2+530] +../fonts/604026ae5aaca83c49cd8416909d71ba3e1c1194.ttf::U+0A09,U+0020,U+0A73,U+0A41:[uguru=0+1356|space=1+532|uraguru=2+1356|uni25CC=2+1044|umatraguru=2@102,0+0] +../fonts/604026ae5aaca83c49cd8416909d71ba3e1c1194.ttf::U+0A0A,U+0020,U+0A73,U+0A42:[uuguru=0+1356|space=1+532|uraguru=2+1356|uni25CC=2+1044|uumatraguru=2@102,0+0] +../fonts/604026ae5aaca83c49cd8416909d71ba3e1c1194.ttf::U+0A0F,U+0020,U+0A72,U+0A47:[eeguru=0+1141|space=1+532|iriguru=2+1141|uni25CC=2+1044|eematraguru=2+0] +../fonts/604026ae5aaca83c49cd8416909d71ba3e1c1194.ttf::U+0A10,U+0020,U+0A05,U+0A48:[aiguru=0+1520|space=1+532|aguru=2+1520|uni25CC=2+1044|aimatraguru=2+0] +../fonts/604026ae5aaca83c49cd8416909d71ba3e1c1194.ttf::U+0A13,U+0020,U+0A73,U+0A4B:[ooguru=0+1356|space=1+532|uraguru=2+1356|uni25CC=2+1044|oomatraguru=2+0] +../fonts/604026ae5aaca83c49cd8416909d71ba3e1c1194.ttf::U+0A14,U+0020,U+0A05,U+0A4C:[auguru=0+1520|space=1+532|aguru=2+1520|uni25CC=2+1044|aumatraguru=2+0] +../fonts/738d9f3b8c2dfd03875bf35a61d28fd78faf17c8.ttf::U+0A86,U+0020,U+0A85,U+0ABE:[gid3=0+2351|gid1=1+612|gid2=2+1808|gid17=2+1044|gid10=2+543] +../fonts/738d9f3b8c2dfd03875bf35a61d28fd78faf17c8.ttf::U+0A8D,U+0020,U+0A85,U+0AC5:[gid4=0+1808|gid1=1+612|gid2=2+1808|gid17=2+1044|gid11=2+0] +../fonts/738d9f3b8c2dfd03875bf35a61d28fd78faf17c8.ttf::U+0A8F,U+0020,U+0A85,U+0AC7:[gid5=0+1808|gid1=1+612|gid2=2+1808|gid17=2+1044|gid12=2+0] +../fonts/738d9f3b8c2dfd03875bf35a61d28fd78faf17c8.ttf::U+0A90,U+0020,U+0A85,U+0AC8:[gid6=0+1808|gid1=1+612|gid2=2+1808|gid17=2+1044|gid13=2+0] +../fonts/738d9f3b8c2dfd03875bf35a61d28fd78faf17c8.ttf::U+0A91,U+0020,U+0A85,U+0AC9:[gid7=0+2351|gid1=1+612|gid2=2+1808|gid17=2+1044|gid14=2+543] +../fonts/738d9f3b8c2dfd03875bf35a61d28fd78faf17c8.ttf::U+0A93,U+0020,U+0A85,U+0ACB,U+0020,U+0A85,U+0ABE,U+0AC5:[gid8=0+2351|gid1=1+612|gid2=2+1808|gid17=2+1044|gid15=2+543|gid1=4+612|gid2=5+1808|gid17=5+1044|gid11=5+0|gid10=5+543] +../fonts/738d9f3b8c2dfd03875bf35a61d28fd78faf17c8.ttf::U+0A94,U+0020,U+0A85,U+0ACC,U+0020,U+0A85,U+0ABE,U+0AC8:[gid9=0+2351|gid1=1+612|gid2=2+1808|gid17=2+1044|gid16=2+543|gid1=4+612|gid2=5+1808|gid17=5+1044|gid13=5+0|gid10=5+543] +../fonts/738d9f3b8c2dfd03875bf35a61d28fd78faf17c8.ttf::U+0AC9,U+0020,U+0AC5,U+0ABE:[gid17=0+1044|gid14=0+543|gid1=1+612|gid17=1+1044|gid11=1+0|gid17=1+1044|gid10=1+543] +../fonts/2c25beb56d9c556622d56b0b5d02b4670c034f89.ttf::U+0B06,U+0020,U+0B05,U+0B3E:[aaorya=0+1681|space=1+881|aorya=2+1284|uni25CC=2+1044|aavowelsignorya=2+387] +../fonts/2c25beb56d9c556622d56b0b5d02b4670c034f89.ttf::U+0B10,U+0020,U+0B0F,U+0B57:[aiorya=0+1681|space=1+881|eorya=2+1315|uni25CC=2+1044|aulengthmarkorya=2+387] +../fonts/2c25beb56d9c556622d56b0b5d02b4670c034f89.ttf::U+0B14,U+0020,U+0B13,U+0B57:[auorya=0+1679|space=1+881|oorya=2+1309|uni25CC=2+1044|aulengthmarkorya=2+387] +../fonts/03e3f463c3a985bc42096620cc415342818454fb.ttf::U+0C13,U+0020,U+0C12,U+0C55:[gid3=0+1497|gid1=1+580|gid2=2+1497|gid13=2+1184|gid12=2+0] +../fonts/03e3f463c3a985bc42096620cc415342818454fb.ttf::U+0C14,U+0020,U+0C12,U+0C4C:[gid4=0+1497|gid1=1+580|gid2=2+1497|gid13=2+1184|gid11=2+634] +../fonts/03e3f463c3a985bc42096620cc415342818454fb.ttf::U+0C40,U+0020,U+0C3F,U+0C55:[gid13=0+1184|gid6=0+0|gid1=1+580|gid13=1+1184|gid5=1+0|gid13=1+1184|gid12=1+0] +../fonts/03e3f463c3a985bc42096620cc415342818454fb.ttf::U+0C47,U+0020,U+0C46,U+0C55:[gid13=0+1184|gid8=0+0|gid1=1+580|gid13=1+1184|gid7=1+0|gid13=1+1184|gid12=1+0] +../fonts/03e3f463c3a985bc42096620cc415342818454fb.ttf::U+0C4B,U+0020,U+0C4A,U+0C55:[gid13=0+1184|gid10=0+634|gid1=1+580|gid13=1+1184|gid9=1+634|gid13=1+1184|gid12=1+0] +../fonts/7d18685e1529e4ceaad5b6095dfab2f9789e5bce.ttf::U+0C8A,U+0020,U+0C89,U+0CBE:[gid3=0+3269|gid1=1+590|gid2=2+2502|gid10=2+1184|gid7=2+919] +../fonts/7d18685e1529e4ceaad5b6095dfab2f9789e5bce.ttf::U+0C94,U+0020,U+0C92,U+0CCC:[gid6=0+1596|gid1=1+590|gid5=2+1590|gid10=2+1184|gid8=2+880] +../fonts/7d18685e1529e4ceaad5b6095dfab2f9789e5bce.ttf::U+0CE0,U+0020,U+0C8B,U+0CBE:[gid9=0+3214|gid1=1+590|gid4=2+2440|gid10=2+1184|gid7=2+919] +../fonts/af85624080af5627fb050f570d148a62f04fda74.ttf::U+0D08,U+0020,U+0D07,U+0D57:[gid3=0+3574|gid1=1+632|gid2=2+2019|gid14=2+1184|gid13=2+1555] +../fonts/af85624080af5627fb050f570d148a62f04fda74.ttf::U+0D0A,U+0020,U+0D09,U+0D57:[gid5=0+2972|gid1=1+632|gid4=2+1417|gid14=2+1184|gid13=2+1555] +../fonts/af85624080af5627fb050f570d148a62f04fda74.ttf::U+0D10,U+0020,U+0D0E,U+0D46:[gid7=0+4073|gid1=1+632|gid6=2+2608|gid12=2+1465|gid14=2+1184] +../fonts/af85624080af5627fb050f570d148a62f04fda74.ttf::U+0D13,U+0020,U+0D12,U+0D3E:[gid9=0+2557|gid1=1+632|gid8=2+1524|gid14=2+1184|gid11=2+1033] +../fonts/af85624080af5627fb050f570d148a62f04fda74.ttf::U+0D14,U+0020,U+0D12,U+0D57:[gid10=0+3073|gid1=1+632|gid8=2+1524|gid14=2+1184|gid13=2+1555] diff --git a/test/shaping/data/in-house/tests/khmer-mark-order.tests b/test/shaping/data/in-house/tests/khmer-mark-order.tests new file mode 100644 index 000000000..d581dd15b --- /dev/null +++ b/test/shaping/data/in-house/tests/khmer-mark-order.tests @@ -0,0 +1,25 @@ +../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17CA,U+17BE,U+1794:[uni17C1=0+288|uni179F=0+928|uni17BB=0@-6,-26+0|uni17B8=0@-32,-29+0|uni1794=3+635] +../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17C9,U+17BE,U+17BB,U+1794:[uni17C1=0+288|uni179F=0+928|uni17C9=0@-32,-29+0|uni17B8=0@-32,237+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=4+635] +../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17C9,U+17C1,U+17B8,U+17BB,U+1794:[uni17C1=0+288|uni179F=0+928|uni17C9=0@-32,-29+0|uni17B8=0@-32,237+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=5+635] +../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17C9,U+17B8,U+17C1,U+17BB,U+1794:[uni179F=0+928|uni17C9=0@-32,-29+0|uni17B8=0@-32,237+0|uni17C1=0+288|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=5+635] +../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17C9,U+17BE,U+17BB,U+17BB,U+1794:[uni17C1=0+288|uni179F=0+928|uni17C9=0@-32,-29+0|uni17B8=0@-32,237+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=5+635] +../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17C9,U+17C1,U+17B8,U+17BB,U+17BB,U+1794:[uni17C1=0+288|uni179F=0+928|uni17C9=0@-32,-29+0|uni17B8=0@-32,237+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=6+635] +../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17C9,U+17B8,U+17C1,U+17BB,U+17BB,U+1794:[uni179F=0+928|uni17C9=0@-32,-29+0|uni17B8=0@-32,237+0|uni17C1=0+288|uni25CC=0+635|uni17BB=0@-20,-26+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=6+635] +../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17CA,U+17BE,U+17BB,U+1794:[uni17C1=0+288|uni179F=0+928|uni17BB=0@-6,-26+0|uni17B8=0@-32,-29+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=4+635] +../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17CA,U+17C1,U+17B8,U+17BB,U+1794:[uni17C1=0+288|uni179F=0+928|uni17BB=0@-6,-26+0|uni17B8=0@-32,-29+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=5+635] +../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17CA,U+17B8,U+17C1,U+17BB,U+1794:[uni179F=0+928|uni17BB=0@-6,-26+0|uni17B8=0@-32,-29+0|uni17C1=0+288|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=5+635] +../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17CA,U+17BE,U+17BB,U+17BB,U+1794:[uni17C1=0+288|uni179F=0+928|uni17BB=0@-6,-26+0|uni17B8=0@-32,-29+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=5+635] +../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17CA,U+17C1,U+17B8,U+17BB,U+17BB,U+1794:[uni17C1=0+288|uni179F=0+928|uni17BB=0@-6,-26+0|uni17B8=0@-32,-29+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=6+635] +../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17CA,U+17B8,U+17C1,U+17BB,U+17BB,U+1794:[uni179F=0+928|uni17BB=0@-6,-26+0|uni17B8=0@-32,-29+0|uni17C1=0+288|uni25CC=0+635|uni17BB=0@-20,-26+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=6+635] +../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17C9,U+17BE,U+17B8,U+1794:[uni17C1=0+288|uni179F=0+928|uni17C9=0@-32,-29+0|uni17B8=0@-32,237+0|uni25CC=0+635|uni17B8=0@-20,-84+0|uni1794=4+635] +../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17C9,U+17B8,U+17BE,U+1794:[uni179F=0+928|uni17C9=0@-32,-29+0|uni17B8=0@-32,237+0|uni17C1=0+288|uni25CC=0+635|uni17B8=0@-20,-84+0|uni1794=4+635] +../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17C9,U+17BE,U+17B8,U+17BB,U+1794:[uni17C1=0+288|uni179F=0+928|uni17C9=0@-32,-29+0|uni17B8=0@-32,237+0|uni25CC=0+635|uni17B8=0@-20,-84+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=5+635] +../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17C9,U+17B8,U+17BE,U+17BB,U+1794:[uni179F=0+928|uni17C9=0@-32,-29+0|uni17B8=0@-32,237+0|uni17C1=0+288|uni25CC=0+635|uni17B8=0@-20,-84+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=5+635] +../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17CA,U+17BE,U+17B8,U+1794:[uni17C1=0+288|uni179F=0+928|uni17BB=0@-6,-26+0|uni17B8=0@-32,-29+0|uni25CC=0+635|uni17B8=0@-20,-84+0|uni1794=4+635] +../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17CA,U+17B8,U+17BE,U+1794:[uni179F=0+928|uni17BB=0@-6,-26+0|uni17B8=0@-32,-29+0|uni17C1=0+288|uni25CC=0+635|uni17B8=0@-20,-84+0|uni1794=4+635] +../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17CA,U+17BE,U+17B8,U+17BB,U+1794:[uni17C1=0+288|uni179F=0+928|uni17BB=0@-6,-26+0|uni17B8=0@-32,-29+0|uni25CC=0+635|uni17B8=0@-20,-84+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=5+635] +../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17CA,U+17B8,U+17BE,U+17BB,U+1794:[uni179F=0+928|uni17BB=0@-6,-26+0|uni17B8=0@-32,-29+0|uni17C1=0+288|uni25CC=0+635|uni17B8=0@-20,-84+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=5+635] +../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17BE,U+17B8,U+17BB,U+1794:[uni17C1=0+288|uni179F=0+928|uni17B8=0@-32,-29+0|uni25CC=0+635|uni17B8=0@-20,-84+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=4+635] +../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17BE,U+17BB,U+17B8,U+1794:[uni17C1=0+288|uni179F=0+928|uni17B8=0@-32,-29+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni17B8=0@-20,-84+0|uni1794=4+635] +../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17B8,U+17BE,U+17BB,U+1794:[uni179F=0+928|uni17B8=0@-32,-29+0|uni17C1=0+288|uni25CC=0+635|uni17B8=0@-20,-84+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=4+635] +../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17B8,U+17BB,U+17BE,U+1794:[uni179F=0+928|uni17B8=0@-32,-29+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni17C1=0+288|uni25CC=0+635|uni17B8=0@-20,-84+0|uni1794=4+635] diff --git a/test/shaping/data/in-house/tests/language-tags.tests b/test/shaping/data/in-house/tests/language-tags.tests index 4c62113f4..c7be1802b 100644 --- a/test/shaping/data/in-house/tests/language-tags.tests +++ b/test/shaping/data/in-house/tests/language-tags.tests @@ -10,3 +10,4 @@ ../fonts/6991b13ce889466be6de3f66e891de2bc0f117ee.ttf:--language=zh-HK:U+004A:[gid6=0+1000] ../fonts/6991b13ce889466be6de3f66e891de2bc0f117ee.ttf:--language=zh-mo:U+004A:[gid6=0+1000] ../fonts/6991b13ce889466be6de3f66e891de2bc0f117ee.ttf:--language=zh-Hant-mo:U+004A:[gid6=0+1000] +../fonts/d3129450fafe5e5c98cfc25a4e71809b1b4d2855.ttf:--language=dv --no-glyph-names:U+007C:[2=0+156] diff --git a/test/shaping/data/in-house/tests/mongolian-variation-selector.tests b/test/shaping/data/in-house/tests/mongolian-variation-selector.tests index efb4cf4eb..c5e35c890 100644 --- a/test/shaping/data/in-house/tests/mongolian-variation-selector.tests +++ b/test/shaping/data/in-house/tests/mongolian-variation-selector.tests @@ -1,4 +1,19 @@ ../fonts/37033cc5cf37bb223d7355153016b6ccece93b28.ttf::U+1826,U+180B,U+1826:[uni1826.E85E_ue.init1=0+599|uni1826.E856_ue.fina=2+750] ../fonts/ef86fe710cfea877bbe0dbb6946a1f88d0661031.ttf::U+1820,U+180B:[uni1820.E821_a.isol1=0+1199] -../fonts/bb29ce50df2bdba2d10726427c6b7609bf460e04.ttf::U+183A,U+1823,U+182E,U+182B,U+1822,U+1826,U+180B,U+1832,U+180B,U+1827,U+1837,U+0020,U+182D,U+182D,U+180B,U+0020,U+182D,U+180C,U+0020,U+182D,U+180D,U+200D,U+0020,U+182D,U+200D,U+182D,U+180B,U+200D,U+0020,U+182D,U+180C,U+200D,U+0020,U+182D,U+180D,U+200D,U+0020,U+200D,U+182D,U+200D,U+200D,U+182D,U+180B,U+200D,U+0020,U+200D,U+182D,U+180C,U+200D,U+0020,U+200D,U+182D,U+180D,U+200D,U+0020,U+200D,U+182D,U+200D,U+182D,U+180B,U+0020,U+200D,U+182D,U+180C,U+0020,U+1820,U+200C,U+182D,U+1820,U+1837,U+0020,U+1830,U+1824,U+1837,U+200D,U+200D,U+182D,U+1820,U+200D,U+0020,U+200D,U+182D,U+1824,U+182F,U+1822,U+0020,U+182A,U+1820,U+1822,U+182D,U+180E,U+1820,U+202F,U+1836,U+1822,U+1828:[uni183A1823.E971_ko.init=0+950|uni182E.E904_m.medi=2+400|uni182B1822.E8A6_pi.medi=3+1150|uni1826.E854_ue.medi1=5+1100|uni1832.E916_t.medi1=7+1000|uni1827.E85C_ee.medi=9+750|uni1837.E931_r.fina=10+750|space=11+500|uni182D.E8E2_g.init=12+1000|uni182D.E8E8_g.fina1=13+1250|space=15+500|uni182D.EA1B_g.isol2=16+1000|space=18+500|uni182D.EA1E_g.init3=19+650|space=19+0|space=22+500|uni182D.E8E2_g.init=23+1000|space=23+0|uni182D.E8E5_g.medi1=25+800|space=25+0|space=28+500|uni182D.EA1D_g.init2=29+950|space=29+0|space=32+500|uni182D.EA1E_g.init3=33+650|space=33+0|space=36+500|space=36+0|uni182D.E8E4_g.medi=38+800|space=38+0|space=38+0|uni182D.E8E5_g.medi1=41+800|space=41+0|space=44+500|space=44+0|uni182D.E8E6_g.medi2=46+650|space=46+0|space=49+500|space=49+0|uni182D.E8E6_g.medi2=51+650|space=51+0|space=54+500|space=54+0|uni182D.E8E4_g.medi=56+800|space=56+0|uni182D.E8E8_g.fina1=58+1250|space=60+500|space=60+0|uni182D.E8E9_g.fina2=62+1050|space=64+500|uni1820.E820_a.isol=65+1550|space=65+0|uni182D.E8E2_g.init=67+1000|uni1820.E823_a.medi=68+400|uni1837.E931_r.fina=69+750|space=70+500|uni1830.E90B_s.init=71+850|uni1824.E844_u.medi=72+600|uni1837.E930_r.medi=73+600|space=73+0|space=73+0|uni182D.E8E5_g.medi1=76+800|uni1820.E823_a.medi=77+400|space=77+0|space=79+500|space=79+0|uni182D.E8E5_g.medi1=81+800|uni1824.E844_u.medi=82+600|uni182F.E908_l.medi=83+400|uni1822.E837_i.fina=84+600|space=85+500|uni182A1820.E875_ba.init=86+1000|uni1822.E836_i.medi2=88+1000|uni182D.E8E8_g.fina1=89+1250|space=90+0|uni1820.E827_a.fina2=91+600|uni202F.nobreak=92+500|uni1836.E92B_y.init1=93+500|uni1822.E834_i.medi=94+500|uni1828.E866_n.fina=95+850] ../fonts/a34a7b00f22ffb5fd7eef6933b81c7e71bc2cdfb.ttf::U+180A,U+1868,U+180A,U+1868,U+180B,U+180A,U+1868,U+180C,U+180A,U+1868,U+180D,U+180A:[gid1=0+268|gid10=1+778|gid1=2+268|gid9=3+575|gid1=5+268|gid10=6+778|gid1=8+268|gid8=9+575|gid1=11+268] +../fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf::U+183A,U+1823,U+182E,U+182B,U+1822,U+1826,U+180B,U+1832,U+180B,U+1827,U+1837:[uni183A1823.E971_ko.init=0+950|uni182E.E904_m.medi=2+400|uni182B1822.E8A6_pi.medi=3+1150|uni1826.E854_ue.medi1=5+1100|uni1832.E916_t.medi1=7+1000|uni1827.E85C_ee.medi=9+750|uni1837.E931_r.fina=10+750] +../fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf::U+182D,U+182D,U+180B:[uni182D.E8E2_g.init=0+1000|uni182D.E8E8_g.fina1=1+1250] +../fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf::U+182D,U+180C:[uni182D.EA1B_g.isol2=0+1000] +../fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf::U+182D,U+180D,U+200D:[uni182D.EA1E_g.init3=0+650|space=0+0] +../fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf::U+182D,U+200D,U+182D,U+180B,U+200D:[uni182D.E8E2_g.init=0+1000|space=0+0|uni182D.E8E5_g.medi1=2+800|space=2+0] +../fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf::U+182D,U+180C,U+200D:[uni182D.EA1D_g.init2=0+950|space=0+0] +../fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf::U+182D,U+180D,U+200D:[uni182D.EA1E_g.init3=0+650|space=0+0] +../fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf::U+200D,U+182D,U+200D,U+200D,U+182D,U+180B,U+200D:[space=0+0|uni182D.E8E4_g.medi=1+800|space=1+0|space=1+0|uni182D.E8E5_g.medi1=4+800|space=4+0] +../fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf::U+200D,U+182D,U+180C,U+200D:[space=0+0|uni182D.E8E6_g.medi2=1+650|space=1+0] +../fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf::U+200D,U+182D,U+180D,U+200D:[space=0+0|uni182D.E8E6_g.medi2=1+650|space=1+0] +../fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf::U+200D,U+182D,U+200D,U+182D,U+180B:[space=0+0|uni182D.E8E4_g.medi=1+800|space=1+0|uni182D.E8E8_g.fina1=3+1250] +../fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf::U+200D,U+182D,U+180C:[space=0+0|uni182D.E8E9_g.fina2=1+1050] +../fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf::U+1820,U+200C,U+182D,U+1820,U+1837:[uni1820.E820_a.isol=0+1550|space=1+0|uni182D.E8E2_g.init=2+1000|uni1820.E823_a.medi=3+400|uni1837.E931_r.fina=4+750] +../fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf::U+1830,U+1824,U+1837,U+200D,U+200D,U+182D,U+1820,U+200D:[uni1830.E90B_s.init=0+850|uni1824.E844_u.medi=1+600|uni1837.E930_r.medi=2+600|space=2+0|space=2+0|uni182D.E8E5_g.medi1=5+800|uni1820.E823_a.medi=6+400|space=6+0] +../fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf::U+200D,U+182D,U+1824,U+182F,U+1822:[space=0+0|uni182D.E8E5_g.medi1=1+800|uni1824.E844_u.medi=2+600|uni182F.E908_l.medi=3+400|uni1822.E837_i.fina=4+600] +../fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf::U+182A,U+1820,U+1822,U+182D,U+180E,U+1820,U+202F,U+1836,U+1822,U+1828:[uni182A1820.E875_ba.init=0+1000|uni1822.E836_i.medi2=2+1000|uni182D.E8E8_g.fina1=3+1250|space=4+0|uni1820.E827_a.fina2=5+600|uni202F.nobreak=6+500|uni1836.E92B_y.init1=7+500|uni1822.E834_i.medi=8+500|uni1828.E866_n.fina=9+850] diff --git a/test/shaping/data/in-house/tests/myanmar-zawgyi.tests b/test/shaping/data/in-house/tests/myanmar-zawgyi.tests new file mode 100644 index 000000000..b79d4fb40 --- /dev/null +++ b/test/shaping/data/in-house/tests/myanmar-zawgyi.tests @@ -0,0 +1 @@ +../fonts/ab14b4eb9d7a67e293f51d30d719add06c9d6e06.ttf:--script=Qaag:U+1000,U+103A,U+1004,U+1037,U+1039,U+1041:[Ka=0+2217|Ya-Semivowel=0+286|Nga=2+1247|Dot Below=2+0|Virama-Killer=2+0|One-Myanmar=5+1247] diff --git a/test/shaping/data/in-house/tests/rand.tests b/test/shaping/data/in-house/tests/rand.tests new file mode 100644 index 000000000..df324b921 --- /dev/null +++ b/test/shaping/data/in-house/tests/rand.tests @@ -0,0 +1,3 @@ +../fonts/5bb74492f5e0ffa1fbb72e4c881be035120b6513.ttf:--no-glyph-names --features=-rand:U+0054,U+0055,U+0056:[1=0+560|2=1+602|3=2+602] +../fonts/5bb74492f5e0ffa1fbb72e4c881be035120b6513.ttf:--no-glyph-names --features=rand=2:U+0054,U+0055,U+0056:[5=0+560|8=1+602|11=2+602] +../fonts/5bb74492f5e0ffa1fbb72e4c881be035120b6513.ttf:--no-glyph-names:U+0054,U+0055,U+0056,U+0054,U+0055,U+0056,U+0054,U+0055,U+0056,U+0054,U+0055,U+0056:[5=0+560|7=1+602|10=2+602|4=3+560|7=4+602|10=5+602|6=6+560|9=7+602|10=8+602|5=9+560|8=10+602|12=11+602] diff --git a/test/shaping/data/in-house/tests/use-indic3.tests b/test/shaping/data/in-house/tests/use-indic3.tests new file mode 100644 index 000000000..8c3ae1398 --- /dev/null +++ b/test/shaping/data/in-house/tests/use-indic3.tests @@ -0,0 +1 @@ +../fonts/3c96e7a303c58475a8c750bf4289bbe73784f37d.ttf::U+0C95,U+0CCD,U+0CB0:[uni0C95=0+1176|uni0CB0_uni0CCD.blwf=0+275] diff --git a/test/shaping/data/in-house/tests/use-syllable.tests b/test/shaping/data/in-house/tests/use-syllable.tests index 5d2fab39c..d8f1dff14 100644 --- a/test/shaping/data/in-house/tests/use-syllable.tests +++ b/test/shaping/data/in-house/tests/use-syllable.tests @@ -6,3 +6,6 @@ ../fonts/373e67bf41ca264e260a9716162b71a23549e885.ttf:--no-glyph-names:U+A8AC,U+A8B4,U+A8B5:[2=0+377|3=0+242|4=0+210] ../fonts/59a585a63b3df608fbeef00956c8c108deec7de6.ttf:--no-glyph-names:U+1BC7,U+1BEA,U+1BF3:[1=0+749|2=0+402|4=0+535|3=0+401] ../fonts/1ed7e9064f008f62de6ff0207bb4dd29409597a5.ttf::U+11064,U+1107F,U+11052,U+11065,U+1107F,U+11053:[brm_num100.1=0+2224|brm_num1000.2=3+1834] +../fonts/28f497629c04ceb15546c9a70e0730125ed6698d.ttf::U+11013,U+11042,U+11046:[brm_KA=0+754|brm_vowelEE=0@-383,0+0|brm_virama=0@-524,0+0] +../fonts/28f497629c04ceb15546c9a70e0730125ed6698d.ttf::U+11013,U+11044,U+11046:[brm_KA=0+754|brm_vowelOO=0@-647,0+0|brm_virama=0@-524,0+0] +../fonts/28f497629c04ceb15546c9a70e0730125ed6698d.ttf::U+11013,U+1103C:[brm_KA=0+754|brm_vowelU=0@-403,0+0] diff --git a/test/shaping/data/in-house/tests/vertical.tests b/test/shaping/data/in-house/tests/vertical.tests index 17df28e6a..b18119225 100644 --- a/test/shaping/data/in-house/tests/vertical.tests +++ b/test/shaping/data/in-house/tests/vertical.tests @@ -1,3 +1,3 @@ ../fonts/191826b9643e3f124d865d617ae609db6a2ce203.ttf:--direction=t --font-funcs=ft:U+300C:[uni300C.vert=0@-512,-578+0,-1024] ../fonts/f9b1dd4dcb515e757789a22cb4241107746fd3d0.ttf:--direction=t --font-funcs=ft:U+0041,U+0042:[gid1=0@-654,-2128+0,-2789|gid2=1@-665,-2125+0,-2789] -../fonts/f9b1dd4dcb515e757789a22cb4241107746fd3d0.ttf:--direction=t --font-funcs=ot:U+0041,U+0042:[gid1=0@-654,-2189+0,-2789|gid2=1@-665,-2189+0,-2789] +../fonts/f9b1dd4dcb515e757789a22cb4241107746fd3d0.ttf:--direction=t --font-funcs=ot:U+0041,U+0042:[gid1=0@-654,-1468+0,-2048|gid2=1@-665,-1462+0,-2048] diff --git a/test/shaping/data/text-rendering-tests/DISABLED b/test/shaping/data/text-rendering-tests/DISABLED index 58de258f8..ef987a4df 100644 --- a/test/shaping/data/text-rendering-tests/DISABLED +++ b/test/shaping/data/text-rendering-tests/DISABLED @@ -1,34 +1,8 @@ +tests/MORX-41.tests + # Non-Unicode cmap tests/CMAP-3.tests -# Not hooked up -tests/MORX-1.tests -tests/MORX-2.tests -tests/MORX-3.tests -tests/MORX-4.tests -tests/MORX-5.tests -tests/MORX-6.tests -tests/MORX-7.tests -tests/MORX-8.tests -tests/MORX-9.tests -tests/MORX-10.tests -tests/MORX-11.tests -tests/MORX-12.tests -tests/MORX-13.tests -tests/MORX-14.tests -tests/MORX-16.tests -tests/MORX-17.tests -tests/MORX-18.tests -tests/MORX-19.tests -tests/MORX-20.tests -tests/MORX-21.tests -tests/MORX-22.tests -tests/MORX-23.tests -tests/MORX-25.tests -tests/MORX-26.tests -tests/MORX-27.tests -tests/MORX-28.tests - # Rounding differences tests/SHARAN-1.tests tests/SHBALI-1.tests diff --git a/test/shaping/data/text-rendering-tests/Makefile.sources b/test/shaping/data/text-rendering-tests/Makefile.sources index 4be9d05d7..5e0db6bd8 100644 --- a/test/shaping/data/text-rendering-tests/Makefile.sources +++ b/test/shaping/data/text-rendering-tests/Makefile.sources @@ -15,6 +15,7 @@ TESTS = \ tests/GPOS-5.tests \ tests/GSUB-1.tests \ tests/GSUB-2.tests \ + tests/GSUB-3.tests \ tests/GVAR-1.tests \ tests/GVAR-2.tests \ tests/GVAR-3.tests \ @@ -28,12 +29,6 @@ TESTS = \ tests/HVAR-2.tests \ tests/KERN-1.tests \ tests/KERN-2.tests \ - tests/SHBALI-3.tests \ - tests/SHKNDA-1.tests \ - $(NULL) - -DISBALED_TESTS = \ - tests/CMAP-3.tests \ tests/MORX-10.tests \ tests/MORX-11.tests \ tests/MORX-12.tests \ @@ -48,18 +43,38 @@ DISBALED_TESTS = \ tests/MORX-21.tests \ tests/MORX-22.tests \ tests/MORX-23.tests \ + tests/MORX-24.tests \ tests/MORX-25.tests \ tests/MORX-26.tests \ tests/MORX-27.tests \ tests/MORX-28.tests \ + tests/MORX-29.tests \ tests/MORX-2.tests \ + tests/MORX-30.tests \ + tests/MORX-31.tests \ + tests/MORX-32.tests \ + tests/MORX-33.tests \ + tests/MORX-34.tests \ + tests/MORX-35.tests \ + tests/MORX-36.tests \ + tests/MORX-37.tests \ + tests/MORX-38.tests \ + tests/MORX-39.tests \ tests/MORX-3.tests \ + tests/MORX-40.tests \ tests/MORX-4.tests \ tests/MORX-5.tests \ tests/MORX-6.tests \ tests/MORX-7.tests \ tests/MORX-8.tests \ tests/MORX-9.tests \ + tests/SHBALI-3.tests \ + tests/SHKNDA-1.tests \ + $(NULL) + +DISBALED_TESTS = \ + tests/MORX-41.tests \ + tests/CMAP-3.tests \ tests/SHARAN-1.tests \ tests/SHBALI-1.tests \ tests/SHBALI-2.tests \ diff --git a/test/shaping/data/text-rendering-tests/extract-tests.py b/test/shaping/data/text-rendering-tests/extract-tests.py index 36963e5e1..27d568615 100755 --- a/test/shaping/data/text-rendering-tests/extract-tests.py +++ b/test/shaping/data/text-rendering-tests/extract-tests.py @@ -28,12 +28,13 @@ def glyphstr(glyphs): html = ET.fromstring(sys.stdin.read()) found = False + for elt in html.findall(".//*[@class='expected'][@ft:id]", namespaces): found = True name = elt.get(ns('ft:id')) text = elt.get(ns('ft:render')) font = elt.get(ns('ft:font')) - vars = elt.get(ns('ft:var'), '').replace(':', '=').replace(';', ',') + variations = elt.get(ns('ft:var'), '').replace(':', '=').replace(';', ',') glyphs = [] for use in elt.findall(".//use"): x = int(use.get('x')) @@ -43,8 +44,19 @@ for elt in html.findall(".//*[@class='expected'][@ft:id]", namespaces): glyphname = '.'.join(href[1:].split('/')[1].split('.')[1:]) glyphs.append((glyphname, x, y)) opts = '--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft' - if vars: - opts = opts + ' --variations=%s' % vars + if variations: + opts = opts + ' --variations=%s' % variations print ("../fonts/%s:%s:%s:%s" % (font, opts, unistr(text), glyphstr(glyphs))) +for elt in html.findall(".//*[@class='should-not-crash'][@ft:id]", namespaces): + found = True + name = elt.get(ns('ft:id')) + text = elt.get(ns('ft:render')) + font = elt.get(ns('ft:font')) + variations = elt.get(ns('ft:var'), '').replace(':', '=').replace(';', ',') + opts = '' + if variations: + opts = '--variations=%s' % variations + print ("../fonts/%s:%s:%s:*" % (font, opts, unistr(text))) + sys.exit(0 if found else 1) diff --git a/test/shaping/data/text-rendering-tests/fonts/TestGSUBThree.ttf b/test/shaping/data/text-rendering-tests/fonts/TestGSUBThree.ttf Binary files differnew file mode 100644 index 000000000..8fce4ac4d --- /dev/null +++ b/test/shaping/data/text-rendering-tests/fonts/TestGSUBThree.ttf diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXForty.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXForty.ttf Binary files differnew file mode 100644 index 000000000..37d0b6377 --- /dev/null +++ b/test/shaping/data/text-rendering-tests/fonts/TestMORXForty.ttf diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXFourtyone.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXFourtyone.ttf Binary files differnew file mode 100644 index 000000000..98ebe3329 --- /dev/null +++ b/test/shaping/data/text-rendering-tests/fonts/TestMORXFourtyone.ttf diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyeight.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyeight.ttf Binary files differnew file mode 100644 index 000000000..29a41d0a3 --- /dev/null +++ b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyeight.ttf diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyfive.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyfive.ttf Binary files differnew file mode 100644 index 000000000..f15706317 --- /dev/null +++ b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyfive.ttf diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyfour.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyfour.ttf Binary files differnew file mode 100644 index 000000000..a70dadccf --- /dev/null +++ b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyfour.ttf diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtynine.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtynine.ttf Binary files differnew file mode 100644 index 000000000..c106ae945 --- /dev/null +++ b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtynine.ttf diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyone.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyone.ttf Binary files differnew file mode 100644 index 000000000..c64c12c06 --- /dev/null +++ b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyone.ttf diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyseven.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyseven.ttf Binary files differnew file mode 100644 index 000000000..22057f18c --- /dev/null +++ b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyseven.ttf diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtysix.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtysix.ttf Binary files differnew file mode 100644 index 000000000..6676e5274 --- /dev/null +++ b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtysix.ttf diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtythree.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtythree.ttf Binary files differnew file mode 100644 index 000000000..5cab73e5a --- /dev/null +++ b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtythree.ttf diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtytwo.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtytwo.ttf Binary files differnew file mode 100644 index 000000000..07ed76c1b --- /dev/null +++ b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtytwo.ttf diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentyfour.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentyfour.ttf Binary files differnew file mode 100644 index 000000000..271dddb01 --- /dev/null +++ b/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentyfour.ttf diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentynine.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentynine.ttf Binary files differnew file mode 100644 index 000000000..9f015ca59 --- /dev/null +++ b/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentynine.ttf diff --git a/test/shaping/data/text-rendering-tests/tests/GSUB-3.tests b/test/shaping/data/text-rendering-tests/tests/GSUB-3.tests new file mode 100644 index 000000000..c2f7e6ef2 --- /dev/null +++ b/test/shaping/data/text-rendering-tests/tests/GSUB-3.tests @@ -0,0 +1 @@ +../fonts/TestGSUBThree.ttf::U+006C,U+006F,U+006C:* diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-24.tests b/test/shaping/data/text-rendering-tests/tests/MORX-24.tests new file mode 100644 index 000000000..79a3d7bb1 --- /dev/null +++ b/test/shaping/data/text-rendering-tests/tests/MORX-24.tests @@ -0,0 +1 @@ +../fonts/TestMORXTwentyfour.ttf::U+0041,U+0042,U+0043,U+0044,U+0045:* diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-29.tests b/test/shaping/data/text-rendering-tests/tests/MORX-29.tests new file mode 100644 index 000000000..82fd96300 --- /dev/null +++ b/test/shaping/data/text-rendering-tests/tests/MORX-29.tests @@ -0,0 +1,4 @@ +../fonts/TestMORXTwentynine.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0050,U+0051,U+0052,U+004D,U+004D,U+0058,U+0058,U+004D,U+004D,U+0059,U+0059,U+0041,U+005A,U+005A:[P|Q@333,0|R@699,0|M@1050,0|M@1880,0|X@2710,0|X@3074,0|M@3438,0|I@4268,0|N@5098,0|S@5928,0|M@6758,0|Y@7588,0|Y@7920,0|A@8252,0|Z@9082,0|Z@9404,0] +../fonts/TestMORXTwentynine.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0050,U+0051,U+0052,U+004D,U+004D,U+0058,U+0058,U+004D,U+004D,U+0059,U+0059,U+0042,U+005A,U+005A:[P|Q@333,0|R@699,0|M@1050,0|M@1880,0|X@2710,0|X@3074,0|M@3438,0|M@4268,0|I@5098,0|N@5928,0|S@6758,0|Y@7588,0|Y@7920,0|B@8252,0|Z@9082,0|Z@9404,0] +../fonts/TestMORXTwentynine.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0050,U+0051,U+0052,U+004D,U+004D,U+0058,U+0058,U+004D,U+004D,U+0059,U+0059,U+0043,U+005A,U+005A:[P|Q@333,0|R@699,0|M@1050,0|M@1880,0|X@2710,0|X@3074,0|M@3438,0|M@4268,0|Y@5098,0|Y@5430,0|I@5762,0|N@6592,0|S@7422,0|C@8252,0|Z@9082,0|Z@9404,0] +../fonts/TestMORXTwentynine.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0050,U+0051,U+0052,U+004D,U+004D,U+0058,U+0058,U+004D,U+004D,U+0059,U+0059,U+0044,U+005A,U+005A:[P|Q@333,0|R@699,0|M@1050,0|M@1880,0|X@2710,0|X@3074,0|M@3438,0|M@4268,0|Y@5098,0|Y@5430,0|D@5762,0|I@6592,0|N@7422,0|S@8252,0|Z@9082,0|Z@9404,0] diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-30.tests b/test/shaping/data/text-rendering-tests/tests/MORX-30.tests new file mode 100644 index 000000000..ad4ab2170 --- /dev/null +++ b/test/shaping/data/text-rendering-tests/tests/MORX-30.tests @@ -0,0 +1,4 @@ +../fonts/TestMORXTwentynine.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0050,U+0051,U+0052,U+004D,U+004D,U+0058,U+0058,U+0058,U+0041,U+0059,U+0059,U+0041,U+005A,U+005A:[P|Q@333,0|R@699,0|M@1050,0|I@1880,0|N@2710,0|S@3540,0|I@4370,0|N@5200,0|S@6030,0|M@6860,0|X@7690,0|X@8054,0|X@8418,0|A@8782,0|Y@9612,0|Y@9944,0|A@10276,0|Z@11106,0|Z@11428,0] +../fonts/TestMORXTwentynine.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0050,U+0051,U+0052,U+004D,U+004D,U+0058,U+0058,U+0058,U+0041,U+0059,U+0059,U+0042,U+005A,U+005A:[P|Q@333,0|R@699,0|M@1050,0|I@1880,0|I@2710,0|N@3540,0|S@4370,0|N@5200,0|S@6030,0|M@6860,0|X@7690,0|X@8054,0|X@8418,0|A@8782,0|Y@9612,0|Y@9944,0|B@10276,0|Z@11106,0|Z@11428,0] +../fonts/TestMORXTwentynine.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0050,U+0051,U+0052,U+004D,U+004D,U+0058,U+0058,U+0058,U+0042,U+0059,U+0059,U+0041,U+005A,U+005A:[P|Q@333,0|R@699,0|M@1050,0|I@1880,0|N@2710,0|S@3540,0|M@4370,0|I@5200,0|N@6030,0|S@6860,0|X@7690,0|X@8054,0|X@8418,0|B@8782,0|Y@9612,0|Y@9944,0|A@10276,0|Z@11106,0|Z@11428,0] +../fonts/TestMORXTwentynine.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0050,U+0051,U+0052,U+004D,U+004D,U+0058,U+0058,U+0058,U+0042,U+0059,U+0059,U+0042,U+005A,U+005A:[P|Q@333,0|R@699,0|M@1050,0|M@1880,0|I@2710,0|N@3540,0|S@4370,0|I@5200,0|N@6030,0|S@6860,0|X@7690,0|X@8054,0|X@8418,0|B@8782,0|Y@9612,0|Y@9944,0|B@10276,0|Z@11106,0|Z@11428,0] diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-31.tests b/test/shaping/data/text-rendering-tests/tests/MORX-31.tests new file mode 100644 index 000000000..6cc40b6e1 --- /dev/null +++ b/test/shaping/data/text-rendering-tests/tests/MORX-31.tests @@ -0,0 +1,8 @@ +../fonts/TestMORXThirtyone.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0058,U+0058,U+0041,U+0059,U+0059,U+0041,U+005A,U+005A:[X|X@364,0|I@728,0|N@1558,0|S@2388,0|A@3218,0|Y@4048,0|Y@4380,0|A@4712,0|Z@5542,0|Z@5864,0] +../fonts/TestMORXThirtyone.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0058,U+0058,U+0041,U+0059,U+0059,U+0042,U+0059,U+0059:[X|X@364,0|A@728,0|I@1558,0|N@2388,0|S@3218,0|Y@4048,0|Y@4380,0|B@4712,0|Y@5542,0|Y@5874,0] +../fonts/TestMORXThirtyone.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0058,U+0058,U+0042,U+0059,U+0059,U+0041,U+005A,U+005A:[X|X@364,0|I@728,0|N@1558,0|S@2388,0|B@3218,0|Y@4048,0|Y@4380,0|A@4712,0|Z@5542,0|Z@5864,0] +../fonts/TestMORXThirtyone.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0058,U+0058,U+0042,U+0059,U+0059,U+0042,U+005A,U+005A:[X|X@364,0|B@728,0|I@1558,0|N@2388,0|S@3218,0|Y@4048,0|Y@4380,0|B@4712,0|Z@5542,0|Z@5864,0] +../fonts/TestMORXThirtyone.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+004D,U+0050,U+0051,U+0052,U+0041,U+0058,U+0059,U+005A,U+0041:[I|N@830,0|S@1660,0|M@2490,0|P@3320,0|Q@3653,0|R@4019,0|I@4370,0|N@5200,0|S@6030,0|A@6860,0|X@7690,0|Y@8054,0|Z@8386,0|A@8708,0] +../fonts/TestMORXThirtyone.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+004D,U+0050,U+0051,U+0052,U+0041,U+0058,U+0059,U+005A,U+0042:[I|N@830,0|S@1660,0|M@2490,0|P@3320,0|Q@3653,0|R@4019,0|A@4370,0|I@5200,0|N@6030,0|S@6860,0|X@7690,0|Y@8054,0|Z@8386,0|B@8708,0] +../fonts/TestMORXThirtyone.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+004D,U+0050,U+0051,U+0052,U+0042,U+0058,U+0059,U+005A,U+0041:[M|I@830,0|N@1660,0|S@2490,0|P@3320,0|Q@3653,0|R@4019,0|I@4370,0|N@5200,0|S@6030,0|B@6860,0|X@7690,0|Y@8054,0|Z@8386,0|A@8708,0] +../fonts/TestMORXThirtyone.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+004D,U+0050,U+0051,U+0052,U+0042,U+0058,U+0059,U+005A,U+0042:[M|I@830,0|N@1660,0|S@2490,0|P@3320,0|Q@3653,0|R@4019,0|B@4370,0|I@5200,0|N@6030,0|S@6860,0|X@7690,0|Y@8054,0|Z@8386,0|B@8708,0] diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-32.tests b/test/shaping/data/text-rendering-tests/tests/MORX-32.tests new file mode 100644 index 000000000..87c115252 --- /dev/null +++ b/test/shaping/data/text-rendering-tests/tests/MORX-32.tests @@ -0,0 +1,4 @@ +../fonts/TestMORXThirtytwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041:[A] +../fonts/TestMORXThirtytwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0058,U+0041,U+0059:[X|A@364,0|Y@1194,0] +../fonts/TestMORXThirtytwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0042:[B] +../fonts/TestMORXThirtytwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0058,U+0042,U+0059:[X|B@364,0|Y@1194,0] diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-33.tests b/test/shaping/data/text-rendering-tests/tests/MORX-33.tests new file mode 100644 index 000000000..17d080a60 --- /dev/null +++ b/test/shaping/data/text-rendering-tests/tests/MORX-33.tests @@ -0,0 +1,3 @@ +../fonts/TestMORXThirtythree.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0068,U+0061:[h|a@618,0|h@1179,0|a@1797,0] +../fonts/TestMORXThirtythree.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0068,U+0061,U+0068,U+0061:[h|a@618,0|h@1179,0|a@1797,0|h@2358,0|a@2976,0|h@3537,0|a@4155,0] +../fonts/TestMORXThirtythree.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0061,U+0068:[a|h@561,0] diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-34.tests b/test/shaping/data/text-rendering-tests/tests/MORX-34.tests new file mode 100644 index 000000000..8c309df84 --- /dev/null +++ b/test/shaping/data/text-rendering-tests/tests/MORX-34.tests @@ -0,0 +1 @@ +../fonts/TestMORXThirtyfour.ttf::U+0068,U+0061:* diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-35.tests b/test/shaping/data/text-rendering-tests/tests/MORX-35.tests new file mode 100644 index 000000000..a0331852e --- /dev/null +++ b/test/shaping/data/text-rendering-tests/tests/MORX-35.tests @@ -0,0 +1,2 @@ +../fonts/TestMORXThirtyfive.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041:[A|B@639,0|C@1265,0|E@1861,0] +../fonts/TestMORXThirtyfive.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0058,U+0041,U+0059:[X|A@586,0|B@1225,0|C@1851,0|E@2447,0|Y@3003,0] diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-36.tests b/test/shaping/data/text-rendering-tests/tests/MORX-36.tests new file mode 100644 index 000000000..6b2340e6d --- /dev/null +++ b/test/shaping/data/text-rendering-tests/tests/MORX-36.tests @@ -0,0 +1 @@ +../fonts/TestMORXThirtysix.ttf::U+0041:* diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-37.tests b/test/shaping/data/text-rendering-tests/tests/MORX-37.tests new file mode 100644 index 000000000..f28c5e2aa --- /dev/null +++ b/test/shaping/data/text-rendering-tests/tests/MORX-37.tests @@ -0,0 +1,4 @@ +../fonts/TestMORXThirtyseven.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041,U+0042:[A.alt|B.alt@1000,0] +../fonts/TestMORXThirtyseven.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0042,U+0041:[B|A@650,0] +../fonts/TestMORXThirtyseven.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+05D0,U+05D1:[uni05D1|uni05D0@542,0] +../fonts/TestMORXThirtyseven.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+05D1,U+05D0:[uni05D0.alt|uni05D1.alt@1000,0] diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-38.tests b/test/shaping/data/text-rendering-tests/tests/MORX-38.tests new file mode 100644 index 000000000..abefe29b4 --- /dev/null +++ b/test/shaping/data/text-rendering-tests/tests/MORX-38.tests @@ -0,0 +1,4 @@ +../fonts/TestMORXThirtyeight.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041,U+0042:[A.alt|B.alt@1000,0] +../fonts/TestMORXThirtyeight.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0042,U+0041:[B|A@650,0] +../fonts/TestMORXThirtyeight.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+05D0,U+05D1:[uni05D1.alt|uni05D0.alt@1000,0] +../fonts/TestMORXThirtyeight.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+05D1,U+05D0:[uni05D0|uni05D1@606,0] diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-39.tests b/test/shaping/data/text-rendering-tests/tests/MORX-39.tests new file mode 100644 index 000000000..83bfa52b9 --- /dev/null +++ b/test/shaping/data/text-rendering-tests/tests/MORX-39.tests @@ -0,0 +1,4 @@ +../fonts/TestMORXThirtynine.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041,U+0042:[A|B@639,0] +../fonts/TestMORXThirtynine.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0042,U+0041:[B.alt|A.alt@1000,0] +../fonts/TestMORXThirtynine.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+05D0,U+05D1:[uni05D1.alt|uni05D0.alt@1000,0] +../fonts/TestMORXThirtynine.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+05D1,U+05D0:[uni05D0|uni05D1@606,0] diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-40.tests b/test/shaping/data/text-rendering-tests/tests/MORX-40.tests new file mode 100644 index 000000000..c99155e2a --- /dev/null +++ b/test/shaping/data/text-rendering-tests/tests/MORX-40.tests @@ -0,0 +1,4 @@ +../fonts/TestMORXForty.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041,U+0042:[A|B@639,0] +../fonts/TestMORXForty.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0042,U+0041:[B.alt|A.alt@1000,0] +../fonts/TestMORXForty.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+05D0,U+05D1:[uni05D1|uni05D0@542,0] +../fonts/TestMORXForty.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+05D1,U+05D0:[uni05D0.alt|uni05D1.alt@1000,0] diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-41.tests b/test/shaping/data/text-rendering-tests/tests/MORX-41.tests new file mode 100644 index 000000000..84dca89ae --- /dev/null +++ b/test/shaping/data/text-rendering-tests/tests/MORX-41.tests @@ -0,0 +1,4 @@ +../fonts/TestMORXFourtyone.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0061,U+0063:[a_c] +../fonts/TestMORXFourtyone.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0062,U+0063:[b_c] +../fonts/TestMORXFourtyone.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0063,U+0063:[c] +../fonts/TestMORXFourtyone.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0061,U+0062,U+0063,U+0063:[a|b_c@561,0|c@1631,0] diff --git a/test/shaping/hb_test_tools.py b/test/shaping/hb_test_tools.py index 8348dc269..c9a44033b 100644 --- a/test/shaping/hb_test_tools.py +++ b/test/shaping/hb_test_tools.py @@ -4,6 +4,10 @@ from __future__ import print_function, division, absolute_import import sys, os, re, difflib, unicodedata, errno, cgi from itertools import * +try: + import unicodedata2 as unicodedata +except Exception: + pass diff_symbols = "-+=*&^%$#@!~/" diff_colors = ['red', 'green', 'blue'] diff --git a/test/shaping/record-test.sh b/test/shaping/record-test.sh index 93ebcfc99..4ab74f0f9 100755 --- a/test/shaping/record-test.sh +++ b/test/shaping/record-test.sh @@ -3,8 +3,9 @@ dir=`mktemp -d` out=/dev/stdout -if test "x${1:0:3}" == 'x-o='; then - out=${1:3} +if test "x$1" == 'x-o'; then + shift + out=$1 shift fi hb_shape=$1 diff --git a/test/shaping/run-tests.py b/test/shaping/run-tests.py index 73b61c21a..f77a17c3d 100755 --- a/test/shaping/run-tests.py +++ b/test/shaping/run-tests.py @@ -2,16 +2,16 @@ from __future__ import print_function, division, absolute_import -import sys, os, subprocess +import sys, os, subprocess, tempfile def cmd(command): - p = subprocess.Popen ( - command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - p.wait () - print (p.stderr.read (), end="") # file=sys.stderr - return p.stdout.read ().decode ("utf-8").strip (), p.returncode - + # https://stackoverflow.com/a/4408409 + with tempfile.TemporaryFile() as tempf: + p = subprocess.Popen (command, stdout=tempf, stderr=sys.stdout) + p.wait () + tempf.seek(0) + return tempf.read().decode ("utf-8").strip (), p.returncode args = sys.argv[1:] if not args or sys.argv[1].find('hb-shape') == -1 or not os.path.exists (sys.argv[1]): @@ -19,8 +19,6 @@ if not args or sys.argv[1].find('hb-shape') == -1 or not os.path.exists (sys.arg sys.exit (1) hb_shape, args = args[0], args[1:] -extra_options = "--verify" - fails = 0 reference = False @@ -48,6 +46,11 @@ for filename in args: cwd = os.path.dirname(filename) fontfile = os.path.normpath (os.path.join (cwd, fontfile)) + extra_options = ["--shaper=ot"] + glyphs_expected = glyphs_expected.strip() + if glyphs_expected != '*': + extra_options.append("--verify") + if line.startswith ("#"): if not reference: print ("# %s %s --unicodes %s" % (hb_shape, fontfile, unicodes)) @@ -55,19 +58,19 @@ for filename in args: if not reference: print ("%s %s %s %s --unicodes %s" % - (hb_shape, fontfile, extra_options, options, unicodes)) + (hb_shape, fontfile, ' '.join(extra_options), options, unicodes)) glyphs1, returncode = cmd ([hb_shape, "--font-funcs=ft", - fontfile, extra_options, "--unicodes", + fontfile] + extra_options + ["--unicodes", unicodes] + (options.split (' ') if options else [])) if returncode: - print ("hb-shape --font-funcs=ft failed.") # file=sys.stderr + print ("ERROR: hb-shape --font-funcs=ft failed.") # file=sys.stderr fails = fails + 1 #continue glyphs2, returncode = cmd ([hb_shape, "--font-funcs=ot", - fontfile, extra_options, "--unicodes", + fontfile] + extra_options + ["--unicodes", unicodes] + (options.split (' ') if options else [])) if returncode: @@ -75,7 +78,7 @@ for filename in args: fails = fails + 1 #continue - if glyphs1 != glyphs2: + if glyphs1 != glyphs2 and glyphs_expected != '*': print ("FT funcs: " + glyphs1) # file=sys.stderr print ("OT funcs: " + glyphs2) # file=sys.stderr fails = fails + 1 @@ -84,7 +87,7 @@ for filename in args: print (":".join ([fontfile, options, unicodes, glyphs1])) continue - if glyphs1.strip() != glyphs_expected.strip(): + if glyphs1.strip() != glyphs_expected and glyphs_expected != '*': print ("Actual: " + glyphs1) # file=sys.stderr print ("Expected: " + glyphs_expected) # file=sys.stderr fails = fails + 1 diff --git a/test/shaping/texts/in-house/shaper-indic/script-bengali/bengali-vowel-letters.txt b/test/shaping/texts/in-house/shaper-indic/script-bengali/bengali-vowel-letters.txt new file mode 100644 index 000000000..f09dbc8f5 --- /dev/null +++ b/test/shaping/texts/in-house/shaper-indic/script-bengali/bengali-vowel-letters.txt @@ -0,0 +1,3 @@ +আ অা +ৠ ঋৃ +ৡ ঌৢ diff --git a/test/shaping/texts/in-house/shaper-indic/script-devanagari/devanagari-atomic-consonants.txt b/test/shaping/texts/in-house/shaper-indic/script-devanagari/devanagari-atomic-consonants.txt new file mode 100644 index 000000000..426543658 --- /dev/null +++ b/test/shaping/texts/in-house/shaper-indic/script-devanagari/devanagari-atomic-consonants.txt @@ -0,0 +1,33 @@ +ख ख्ा ख्ा +ग ग्ा ग्ा +घ घ्ा घ्ा +च च्ा च्ा +ज ज्ा ज्ा +झ झ्ा झ्ा +ञ ञ्ा ञ्ा +ण ण्ा ण्ा +त त्ा त्ा +थ थ्ा थ्ा +ध ध्ा ध्ा +न न्ा न्ा +ऩ ऩ्ा ऩ्ा ऩ्ा ऩ्ा +प प्ा प्ा +ब ब्ा ब्ा +भ भ्ा भ्ा +म म्ा म्ा +य य्ा य्ा +ल ल्ा ल्ा +व व्ा व्ा +श श्ा श्ा +ष ष्ा ष्ा +स स्ा स्ा +ख़ ख़्ा ख़्ा ख़्ा ख़्ा +ग़ ग़्ा ग़्ा ग़्ा ग़्ा +ज़ ज़्ा ज़्ा ज़्ा ज़्ा +य़ य़्ा य़्ा य़्ा य़्ा +ॹ ॹ्ा ॹ्ा +ॺ ॺ्ा ॺ्ा +ज़ ॻ्ा ॻ्ा +ॼ ॼ्ा ॼ्ा +ॾ ॾ्ा ॾ्ा +ॿ ॿ्ा ॿ्ा diff --git a/test/shaping/texts/in-house/shaper-indic/script-devanagari/devanagari-vowel-letters.txt b/test/shaping/texts/in-house/shaper-indic/script-devanagari/devanagari-vowel-letters.txt new file mode 100644 index 000000000..5a41252f2 --- /dev/null +++ b/test/shaping/texts/in-house/shaper-indic/script-devanagari/devanagari-vowel-letters.txt @@ -0,0 +1,17 @@ +ऄ अॆ +आ अा +ई र्इ +ऊ उु +ऍ एॅ +ऎ एॆ +ऐ एे +ऑ अॉ आॅ +ऒ अॊ आॆ +ओ अो आे +औ अौ आै +ॲ अॅ +ॳ अऺ +ॴ अऻ आऺ +ॵ अॏ +ॶ अॖ +ॷ अॗ diff --git a/test/shaping/texts/in-house/shaper-indic/script-gujarati/gujarati-vowel-letters.txt b/test/shaping/texts/in-house/shaper-indic/script-gujarati/gujarati-vowel-letters.txt new file mode 100644 index 000000000..add4332b3 --- /dev/null +++ b/test/shaping/texts/in-house/shaper-indic/script-gujarati/gujarati-vowel-letters.txt @@ -0,0 +1,8 @@ +આ અા +ઍ અૅ +એ અે +ઐ અૈ +ઑ અૉ +ઓ અો અાૅ +ઔ અૌ અાૈ +ૉ ૅા diff --git a/test/shaping/texts/in-house/shaper-indic/script-gurmukhi/gurmukhi-vowel-letters.txt b/test/shaping/texts/in-house/shaper-indic/script-gurmukhi/gurmukhi-vowel-letters.txt new file mode 100644 index 000000000..b2adaabd2 --- /dev/null +++ b/test/shaping/texts/in-house/shaper-indic/script-gurmukhi/gurmukhi-vowel-letters.txt @@ -0,0 +1,9 @@ +ਆ ਅਾ +ਇ ੲਿ +ਈ ੲੀ +ਉ ੳੁ +ਊ ੳੂ +ਏ ੲੇ +ਐ ਅੈ +ਓ ੳੋ +ਔ ਅੌ diff --git a/test/shaping/texts/in-house/shaper-indic/script-kannada/kannada-vowel-letters.txt b/test/shaping/texts/in-house/shaper-indic/script-kannada/kannada-vowel-letters.txt new file mode 100644 index 000000000..cc05db93f --- /dev/null +++ b/test/shaping/texts/in-house/shaper-indic/script-kannada/kannada-vowel-letters.txt @@ -0,0 +1,3 @@ +ಊ ಉಾ +ಔ ಒೌ +ೠ ಋಾ diff --git a/test/shaping/texts/in-house/shaper-indic/script-malayalam/malayalam-vowel-letters.txt b/test/shaping/texts/in-house/shaper-indic/script-malayalam/malayalam-vowel-letters.txt new file mode 100644 index 000000000..061c642f7 --- /dev/null +++ b/test/shaping/texts/in-house/shaper-indic/script-malayalam/malayalam-vowel-letters.txt @@ -0,0 +1,5 @@ +ഈ ഇൗ +ഊ ഉൗ +ഐ എെ +ഓ ഒാ +ഔ ഒൗ diff --git a/test/shaping/texts/in-house/shaper-indic/script-oriya/oriya-vowel-letters.txt b/test/shaping/texts/in-house/shaper-indic/script-oriya/oriya-vowel-letters.txt new file mode 100644 index 000000000..e8d24cb57 --- /dev/null +++ b/test/shaping/texts/in-house/shaper-indic/script-oriya/oriya-vowel-letters.txt @@ -0,0 +1,3 @@ +ଆ ଅା +ଐ ଏୗ +ଔ ଓୗ diff --git a/test/shaping/texts/in-house/shaper-indic/script-telugu/telugu-vowel-letters.txt b/test/shaping/texts/in-house/shaper-indic/script-telugu/telugu-vowel-letters.txt new file mode 100644 index 000000000..c3cfc84cd --- /dev/null +++ b/test/shaping/texts/in-house/shaper-indic/script-telugu/telugu-vowel-letters.txt @@ -0,0 +1,5 @@ +ఓ ఒౕ +ఔ ఒౌ +ీ ిౕ +ే ెౕ +ో ొౕ diff --git a/test/subset/Makefile.am b/test/subset/Makefile.am index 336d33dfb..1673cfbd1 100644 --- a/test/subset/Makefile.am +++ b/test/subset/Makefile.am @@ -7,7 +7,7 @@ SUBDIRS = data # Convenience targets: lib: - @$(MAKE) $(AM_MAKEFLAGS) -C $(top_builddir)/src lib + @$(MAKE) $(AM_MAKEFLAGS) -C $(top_builddir)/src libs EXTRA_DIST += \ CMakeLists.txt \ diff --git a/util/Makefile.am b/util/Makefile.am index d4ab9cdc5..85f9edaa0 100644 --- a/util/Makefile.am +++ b/util/Makefile.am @@ -47,17 +47,16 @@ hb_shape_SOURCES = $(HB_SHAPE_sources) bin_PROGRAMS += hb-shape hb_subset_SOURCES = $(HB_SUBSET_CLI_sources) -hb_subset_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la +hb_subset_LDADD = \ + $(LDADD) \ + $(top_builddir)/src/libharfbuzz-subset.la bin_PROGRAMS += hb-subset -if HAVE_OT hb_ot_shape_closure_SOURCES = $(HB_OT_SHAPE_CLOSURE_sources) bin_PROGRAMS += hb-ot-shape-closure -endif # HAVE_OT endif # HAVE_GLIB -#if HAVE_OT #if HAVE_FONTCONFIG #hb_fc_list_SOURCES = \ # hb-fc.cc \ @@ -70,6 +69,5 @@ endif # HAVE_GLIB # $(NULL) #bin_PROGRAMS += hb-fc-list #endif # HAVE_FONTCONFIG -#endif # HAVE_OT -include $(top_srcdir)/git.mk diff --git a/util/ansi-print.cc b/util/ansi-print.cc index 0daee1f02..5e2845cf1 100644 --- a/util/ansi-print.cc +++ b/util/ansi-print.cc @@ -71,7 +71,7 @@ struct color_t { static color_t from_ansi (unsigned int x) { - color_t c = {(0xFF<<24) | ((0xFF*(x&1))<<16) | ((0xFF*((x >> 1)&1))<<8) | (0xFF*((x >> 2)&1))}; + color_t c = {(0xFFu<<24) | ((0xFFu*(x&1))<<16) | ((0xFFu*((x >> 1)&1))<<8) | (0xFFu*((x >> 2)&1))}; return c; } unsigned int to_ansi (void) @@ -223,7 +223,7 @@ struct biimage_t uint8_t * const data; }; -const char * +static const char * block_best (const biimage_t &bi, bool *inverse) { assert (bi.width <= CELL_W); diff --git a/util/ansi-print.hh b/util/ansi-print.hh index 1ea5b3742..9640d892d 100644 --- a/util/ansi-print.hh +++ b/util/ansi-print.hh @@ -27,8 +27,7 @@ #ifndef ANSI_PRINT_HH #define ANSI_PRINT_HH -#include "hb-private.hh" -#include <hb.h> /* for int types */ +#include "hb.hh" void ansi_print_image_rgb24 (const uint32_t *data, diff --git a/util/hb-subset.cc b/util/hb-subset.cc index 20617554c..3f0963c3f 100644 --- a/util/hb-subset.cc +++ b/util/hb-subset.cc @@ -29,7 +29,6 @@ #include "main-font-text.hh" #include "hb-subset.h" -#include "hb-subset-private.hh" /* * Command line interface to the harfbuzz font subsetter. @@ -90,19 +89,17 @@ struct subset_consumer_t void finish (const font_options_t *font_opts) { - input->drop_hints = subset_options.drop_hints; + hb_subset_input_set_drop_hints (input, subset_options.drop_hints); - hb_subset_profile_t *subset_profile = hb_subset_profile_create(); hb_face_t *face = hb_font_get_face (font); - hb_face_t *new_face = hb_subset(face, subset_profile, input); + hb_face_t *new_face = hb_subset(face, input); hb_blob_t *result = hb_face_reference_blob (new_face); failed = !hb_blob_get_length (result); if (!failed) write_file (options.output_file, result); - hb_subset_profile_destroy (subset_profile); hb_subset_input_destroy (input); hb_blob_destroy (result); hb_face_destroy (new_face); diff --git a/util/hb-view.cc b/util/hb-view.cc index ef75e6da7..69a4c9504 100644 --- a/util/hb-view.cc +++ b/util/hb-view.cc @@ -30,7 +30,7 @@ #include "view-cairo.hh" #define DEFAULT_FONT_SIZE 256 -#define SUBPIXEL_BITS 8 +#define SUBPIXEL_BITS 6 int main (int argc, char **argv) diff --git a/util/helper-cairo-ansi.hh b/util/helper-cairo-ansi.hh index cf18ea495..bc2313219 100644 --- a/util/helper-cairo-ansi.hh +++ b/util/helper-cairo-ansi.hh @@ -27,7 +27,7 @@ #ifndef HELPER_CAIRO_ANSI_HH #define HELPER_CAIRO_ANSI_HH -#include "hb-private.hh" +#include "hb.hh" #include <cairo.h> diff --git a/util/helper-cairo.cc b/util/helper-cairo.cc index 3eaf90a74..7a698f30b 100644 --- a/util/helper-cairo.cc +++ b/util/helper-cairo.cc @@ -64,11 +64,13 @@ _cairo_eps_surface_create_for_stream (cairo_write_func_t write_func, static FT_Library ft_library; +#ifdef HAVE_ATEXIT static inline void free_ft_library (void) { FT_Done_FreeType (ft_library); } +#endif cairo_scaled_font_t * helper_cairo_create_scaled_font (const font_options_t *font_opts) @@ -125,7 +127,7 @@ helper_cairo_create_scaled_font (const font_options_t *font_opts) } #endif - cairo_face = cairo_ft_font_face_create_for_ft_face (ft_face, 0); + cairo_face = cairo_ft_font_face_create_for_ft_face (ft_face, font_opts->ft_load_flags); } cairo_matrix_t ctm, font_matrix; cairo_font_options_t *font_options; diff --git a/util/helper-cairo.hh b/util/helper-cairo.hh index 50bc0af09..1613ce427 100644 --- a/util/helper-cairo.hh +++ b/util/helper-cairo.hh @@ -27,7 +27,7 @@ #ifndef HELPER_CAIRO_HH #define HELPER_CAIRO_HH -#include "hb-private.hh" +#include "hb.hh" #include "options.hh" #include <cairo.h> diff --git a/util/main-font-text.hh b/util/main-font-text.hh index 3390371c5..01bd2d4d9 100644 --- a/util/main-font-text.hh +++ b/util/main-font-text.hh @@ -27,7 +27,7 @@ #ifndef HB_MAIN_FONT_TEXT_HH #define HB_MAIN_FONT_TEXT_HH -#include "hb-private.hh" +#include "hb.hh" #include "options.hh" /* main() body for utilities taking font and processing text.*/ diff --git a/util/options.cc b/util/options.cc index 57cc4aa8d..5661cd059 100644 --- a/util/options.cc +++ b/util/options.cc @@ -29,11 +29,9 @@ #ifdef HAVE_FREETYPE #include <hb-ft.h> #endif -#ifdef HAVE_OT #include <hb-ot.h> -#endif -struct supported_font_funcs_t { +static struct supported_font_funcs_t { char name[4]; void (*func) (hb_font_t *); } supported_font_funcs[] = @@ -41,9 +39,7 @@ struct supported_font_funcs_t { #ifdef HAVE_FREETYPE {"ft", hb_ft_font_set_funcs}, #endif -#ifdef HAVE_OT {"ot", hb_ot_font_set_funcs}, -#endif }; @@ -172,9 +168,9 @@ parse_margin (const char *name G_GNUC_UNUSED, view_options_t *view_opts = (view_options_t *) data; view_options_t::margin_t &m = view_opts->margin; switch (sscanf (arg, "%lf%*[ ,]%lf%*[ ,]%lf%*[ ,]%lf", &m.t, &m.r, &m.b, &m.l)) { - case 1: m.r = m.t; - case 2: m.b = m.t; - case 3: m.l = m.r; + case 1: m.r = m.t; HB_FALLTHROUGH; + case 2: m.b = m.t; HB_FALLTHROUGH; + case 3: m.l = m.r; HB_FALLTHROUGH; case 4: return true; default: g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, @@ -415,11 +411,12 @@ shape_options_t::add_options (option_parser_t *parser) {"eot", 0, 0, G_OPTION_ARG_NONE, &this->eot, "Treat text as end-of-paragraph", nullptr}, {"preserve-default-ignorables",0, 0, G_OPTION_ARG_NONE, &this->preserve_default_ignorables, "Preserve Default-Ignorable characters", nullptr}, {"remove-default-ignorables",0, 0, G_OPTION_ARG_NONE, &this->remove_default_ignorables, "Remove Default-Ignorable characters", nullptr}, + {"invisible-glyph", 0, 0, G_OPTION_ARG_INT, &this->invisible_glyph, "Glyph value to replace Default-Ignorables with", nullptr}, {"utf8-clusters", 0, 0, G_OPTION_ARG_NONE, &this->utf8_clusters, "Use UTF8 byte indices, not char indices", nullptr}, {"cluster-level", 0, 0, G_OPTION_ARG_INT, &this->cluster_level, "Cluster merging level (default: 0)", "0/1/2"}, {"normalize-glyphs",0, 0, G_OPTION_ARG_NONE, &this->normalize_glyphs, "Rearrange glyph clusters in nominal order", nullptr}, {"verify", 0, 0, G_OPTION_ARG_NONE, &this->verify, "Perform sanity checks on shaping results", nullptr}, - {"num-iterations", 0, 0, G_OPTION_ARG_INT, &this->num_iterations, "Run shaper N times (default: 1)", "N"}, + {"num-iterations", 'n', 0, G_OPTION_ARG_INT, &this->num_iterations, "Run shaper N times (default: 1)", "N"}, {nullptr} }; parser->add_group (entries, @@ -489,7 +486,7 @@ parse_font_size (const char *name G_GNUC_UNUSED, return true; } switch (sscanf (arg, "%lf%*[ ,]%lf", &font_opts->font_size_x, &font_opts->font_size_y)) { - case 1: font_opts->font_size_y = font_opts->font_size_x; + case 1: font_opts->font_size_y = font_opts->font_size_x; HB_FALLTHROUGH; case 2: return true; default: g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, @@ -507,7 +504,7 @@ parse_font_ppem (const char *name G_GNUC_UNUSED, { font_options_t *font_opts = (font_options_t *) data; switch (sscanf (arg, "%d%*[ ,]%d", &font_opts->x_ppem, &font_opts->y_ppem)) { - case 1: font_opts->y_ppem = font_opts->x_ppem; + case 1: font_opts->y_ppem = font_opts->x_ppem; HB_FALLTHROUGH; case 2: return true; default: g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, @@ -556,6 +553,7 @@ font_options_t::add_options (option_parser_t *parser) {"font-ppem", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_font_ppem, "Set x,y pixels per EM (default: 0; disabled)", "1/2 integers"}, {"font-ptem", 0, 0, G_OPTION_ARG_DOUBLE, &this->ptem, "Set font point-size (default: 0; disabled)", "point-size"}, {"font-funcs", 0, 0, G_OPTION_ARG_STRING, &this->font_funcs, text, "impl"}, + {"ft-load-flags", 0, 0, G_OPTION_ARG_INT, &this->ft_load_flags, "Set FreeType load-flags (default: 2)", "integer"}, {nullptr} }; parser->add_group (entries, @@ -662,7 +660,7 @@ font_options_t::get_font (void) const blob = hb_blob_create_from_file (font_path); if (blob == hb_blob_get_empty ()) - fail (false, "No such file or directory"); + fail (false, "Couldn't read or find %s, or it was empty.", font_path); /* Create the face */ hb_face_t *face = hb_face_create (blob, face_index); @@ -717,6 +715,9 @@ font_options_t::get_font (void) const } } set_font_funcs (font); +#ifdef HAVE_FREETYPE + hb_ft_font_set_load_flags (font, ft_load_flags); +#endif return font; } diff --git a/util/options.hh b/util/options.hh index 2160d5ec3..dd628590e 100644 --- a/util/options.hh +++ b/util/options.hh @@ -27,7 +27,7 @@ #ifndef OPTIONS_HH #define OPTIONS_HH -#include "hb-private.hh" +#include "hb.hh" #include <stdlib.h> #include <stddef.h> @@ -46,9 +46,7 @@ #endif #include <hb.h> -#ifdef HAVE_OT #include <hb-ot.h> -#endif #include <glib.h> #include <glib/gprintf.h> @@ -56,16 +54,19 @@ void fail (hb_bool_t suggest_help, const char *format, ...) G_GNUC_NORETURN G_GN struct option_group_t { + virtual ~option_group_t (void) {} + virtual void add_options (struct option_parser_t *parser) = 0; - virtual void pre_parse (GError **error G_GNUC_UNUSED) {}; - virtual void post_parse (GError **error G_GNUC_UNUSED) {}; + virtual void pre_parse (GError **error G_GNUC_UNUSED) {} + virtual void post_parse (GError **error G_GNUC_UNUSED) {} }; struct option_parser_t { - option_parser_t (const char *usage) { + option_parser_t (const char *usage) + { memset (this, 0, sizeof (*this)); usage_str = usage; context = g_option_context_new (usage); @@ -73,7 +74,8 @@ struct option_parser_t add_main_options (); } - ~option_parser_t (void) { + ~option_parser_t (void) + { g_option_context_free (context); g_ptr_array_foreach (to_free, (GFunc) g_free, nullptr); g_ptr_array_free (to_free, TRUE); @@ -113,7 +115,8 @@ struct option_parser_t struct view_options_t : option_group_t { - view_options_t (option_parser_t *parser) { + view_options_t (option_parser_t *parser) + { annotate = false; fore = nullptr; back = nullptr; @@ -122,7 +125,7 @@ struct view_options_t : option_group_t add_options (parser); } - ~view_options_t (void) + virtual ~view_options_t (void) { g_free (fore); g_free (back); @@ -150,6 +153,7 @@ struct shape_options_t : option_group_t num_features = 0; shapers = nullptr; utf8_clusters = false; + invisible_glyph = 0; cluster_level = HB_BUFFER_CLUSTER_LEVEL_DEFAULT; normalize_glyphs = false; verify = false; @@ -157,7 +161,7 @@ struct shape_options_t : option_group_t add_options (parser); } - ~shape_options_t (void) + virtual ~shape_options_t (void) { g_free (direction); g_free (language); @@ -180,6 +184,7 @@ struct shape_options_t : option_group_t (preserve_default_ignorables ? HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES : 0) | (remove_default_ignorables ? HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES : 0) | 0)); + hb_buffer_set_invisible_glyph (buffer, invisible_glyph); hb_buffer_set_cluster_level (buffer, cluster_level); hb_buffer_guess_segment_properties (buffer); } @@ -430,6 +435,7 @@ struct shape_options_t : option_group_t unsigned int num_features; char **shapers; hb_bool_t utf8_clusters; + hb_codepoint_t invisible_glyph; hb_buffer_cluster_level_t cluster_level; hb_bool_t normalize_glyphs; hb_bool_t verify; @@ -454,13 +460,15 @@ struct font_options_t : option_group_t face_index = 0; font_size_x = font_size_y = default_font_size; font_funcs = nullptr; + ft_load_flags = 2; blob = nullptr; font = nullptr; add_options (parser); } - ~font_options_t (void) { + virtual ~font_options_t (void) + { g_free (font_file); free (variations); g_free (font_funcs); @@ -484,6 +492,7 @@ struct font_options_t : option_group_t mutable double font_size_x; mutable double font_size_y; char *font_funcs; + int ft_load_flags; private: mutable hb_font_t *font; @@ -492,7 +501,8 @@ struct font_options_t : option_group_t struct text_options_t : option_group_t { - text_options_t (option_parser_t *parser) { + text_options_t (option_parser_t *parser) + { text_before = nullptr; text_after = nullptr; @@ -506,7 +516,8 @@ struct text_options_t : option_group_t add_options (parser); } - ~text_options_t (void) { + virtual ~text_options_t (void) + { g_free (text_before); g_free (text_after); g_free (text); @@ -544,7 +555,8 @@ struct text_options_t : option_group_t struct output_options_t : option_group_t { output_options_t (option_parser_t *parser, - const char **supported_formats_ = nullptr) { + const char **supported_formats_ = nullptr) + { output_file = nullptr; output_format = nullptr; supported_formats = supported_formats_; @@ -554,7 +566,8 @@ struct output_options_t : option_group_t add_options (parser); } - ~output_options_t (void) { + virtual ~output_options_t (void) + { g_free (output_file); g_free (output_format); if (fp) @@ -573,7 +586,7 @@ struct output_options_t : option_group_t if (output_format) { output_format++; /* skip the dot */ - output_format = strdup (output_format); + output_format = g_strdup (output_format); } } diff --git a/util/shape-consumer.hh b/util/shape-consumer.hh index fa419f185..da0d88033 100644 --- a/util/shape-consumer.hh +++ b/util/shape-consumer.hh @@ -27,7 +27,7 @@ #ifndef HB_SHAPE_CONSUMER_HH #define HB_SHAPE_CONSUMER_HH -#include "hb-private.hh" +#include "hb.hh" #include "options.hh" diff --git a/util/view-cairo.hh b/util/view-cairo.hh index 00df68c29..5be3523ad 100644 --- a/util/view-cairo.hh +++ b/util/view-cairo.hh @@ -27,7 +27,7 @@ #ifndef VIEW_CAIRO_HH #define VIEW_CAIRO_HH -#include "hb-private.hh" +#include "hb.hh" #include "options.hh" #include "helper-cairo.hh" @@ -46,7 +46,7 @@ struct view_cairo_t void init (hb_buffer_t *buffer, const font_options_t *font_opts) { lines = g_array_new (false, false, sizeof (helper_cairo_line_t)); - scale_bits = -font_opts->subpixel_bits; + scale_bits = - (int) font_opts->subpixel_bits; } void new_line (void) { |