Merge branch 'master' into cff-subset
This commit is contained in:
commit
e600e5440b
|
@ -37,7 +37,7 @@ jobs:
|
|||
# not needed to be a framework but we like to test that also
|
||||
# TODO: wrong way of targeting iOS as it doesn't point to iOS headers thus building
|
||||
# CoreText support is not possible, after the fix feel free HB_IOS from CMake altogether
|
||||
- run: cmake -DBUILD_FRAMEWORK=ON -H. -Bbuild -GXcode -DHB_IOS=ON
|
||||
- run: cmake -DBUILD_FRAMEWORK=ON -H. -Bbuild -GXcode -DHB_HAVE_CORETEXT=OFF -DHB_BUILD_SUBSET=OFF -DHB_BUILD_TESTS=OFF
|
||||
- run: cd build && xcodebuild -sdk iphoneos12.0 -configuration Release build -arch arm64
|
||||
|
||||
distcheck:
|
||||
|
@ -120,7 +120,7 @@ jobs:
|
|||
- 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: 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-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
|
||||
|
||||
|
|
|
@ -52,6 +52,9 @@ if (HB_BUILD_UTILS)
|
|||
set (HB_HAVE_FREETYPE ON)
|
||||
endif ()
|
||||
|
||||
option(HB_BUILD_SUBSET "Build harfbuzz-subset" ON)
|
||||
option(HB_BUILD_TESTS "Build harfbuzz tests" ON)
|
||||
|
||||
option(HB_HAVE_GOBJECT "Enable GObject Bindings" OFF)
|
||||
if (HB_HAVE_GOBJECT)
|
||||
set (HB_HAVE_GLIB ON)
|
||||
|
@ -82,16 +85,6 @@ 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
|
||||
|
@ -556,7 +549,7 @@ add_library(harfbuzz ${project_sources} ${project_extra_sources} ${project_heade
|
|||
target_link_libraries(harfbuzz ${THIRD_PARTY_LIBS})
|
||||
|
||||
## Define harfbuzz-subset library
|
||||
if (NOT HB_DISABLE_SUBSET)
|
||||
if (HB_BUILD_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})
|
||||
|
@ -580,7 +573,7 @@ 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)
|
||||
if (NOT HB_DISABLE_SUBSET)
|
||||
if (HB_BUILD_SUBSET)
|
||||
set_target_properties(harfbuzz-subset PROPERTIES LINKER_LANGUAGE C)
|
||||
endif ()
|
||||
|
||||
|
@ -861,7 +854,7 @@ if (UNIX AND CMAKE_GENERATOR STREQUAL "Ninja")
|
|||
endif ()
|
||||
|
||||
|
||||
if (NOT HB_DISABLE_TESTS)
|
||||
if (HB_BUILD_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})
|
||||
|
|
81
NEWS
81
NEWS
|
@ -1,3 +1,84 @@
|
|||
Overview of changes leading to 2.1.0
|
||||
Tuesday, October 30, 2018
|
||||
====================================
|
||||
- AAT shaping improvements:
|
||||
o Allow user controlling AAT features, for whole buffer only currently.
|
||||
o Several 'morx' fixes.
|
||||
o Implement tuple-kerns in 'kerx'; Fixes kerning with Apple default
|
||||
San Francisco fonts.
|
||||
- Support for color fonts:
|
||||
o COLR/CPAL API to fetch color layers.
|
||||
o SVG table to fetch SVG documents.
|
||||
o CBDT/sbix API to fetch PNG images.
|
||||
- New 'name' table API.
|
||||
- hb-ot-font now uses 'VORG' table to correctly position CFF glyphs
|
||||
in vertical layout.
|
||||
- Various fuzzer-found bug fixes.
|
||||
|
||||
Changed API:
|
||||
|
||||
A type and a macro added in 2.0.0 were renamed:
|
||||
|
||||
hb_name_id_t -> hb_ot_name_id_t
|
||||
HB_NAME_ID_INVALID -> HB_OT_NAME_ID_INVALID
|
||||
|
||||
New API:
|
||||
|
||||
+hb_color_t
|
||||
+HB_COLOR
|
||||
+hb_color_get_alpha()
|
||||
+hb_color_get_red()
|
||||
+hb_color_get_green()
|
||||
+hb_color_get_blue()
|
||||
+hb_ot_color_has_palettes()
|
||||
+hb_ot_color_palette_get_count()
|
||||
+hb_ot_color_palette_get_name_id()
|
||||
+hb_ot_color_palette_color_get_name_id()
|
||||
+hb_ot_color_palette_flags_t
|
||||
+hb_ot_color_palette_get_flags()
|
||||
+hb_ot_color_palette_get_colors()
|
||||
+hb_ot_color_has_layers()
|
||||
+hb_ot_color_layer_t
|
||||
+hb_ot_color_glyph_get_layers()
|
||||
+hb_ot_color_has_svg()
|
||||
+hb_ot_color_glyph_reference_svg()
|
||||
+hb_ot_color_has_png()
|
||||
+hb_ot_color_glyph_reference_png()
|
||||
|
||||
+hb_ot_name_id_t
|
||||
+HB_OT_NAME_ID_INVALID
|
||||
+HB_OT_NAME_ID_COPYRIGHT
|
||||
+HB_OT_NAME_ID_FONT_FAMILY
|
||||
+HB_OT_NAME_ID_FONT_SUBFAMILY
|
||||
+HB_OT_NAME_ID_UNIQUE_ID
|
||||
+HB_OT_NAME_ID_FULL_NAME
|
||||
+HB_OT_NAME_ID_VERSION_STRING
|
||||
+HB_OT_NAME_ID_POSTSCRIPT_NAME
|
||||
+HB_OT_NAME_ID_TRADEMARK
|
||||
+HB_OT_NAME_ID_MANUFACTURER
|
||||
+HB_OT_NAME_ID_DESIGNER
|
||||
+HB_OT_NAME_ID_DESCRIPTION
|
||||
+HB_OT_NAME_ID_VENDOR_URL
|
||||
+HB_OT_NAME_ID_DESIGNER_URL
|
||||
+HB_OT_NAME_ID_LICENSE
|
||||
+HB_OT_NAME_ID_LICENSE_URL
|
||||
+HB_OT_NAME_ID_TYPOGRAPHIC_FAMILY
|
||||
+HB_OT_NAME_ID_TYPOGRAPHIC_SUBFAMILY
|
||||
+HB_OT_NAME_ID_MAC_FULL_NAME
|
||||
+HB_OT_NAME_ID_SAMPLE_TEXT
|
||||
+HB_OT_NAME_ID_CID_FINDFONT_NAME
|
||||
+HB_OT_NAME_ID_WWS_FAMILY
|
||||
+HB_OT_NAME_ID_WWS_SUBFAMILY
|
||||
+HB_OT_NAME_ID_LIGHT_BACKGROUND
|
||||
+HB_OT_NAME_ID_DARK_BACKGROUND
|
||||
+HB_OT_NAME_ID_VARIATIONS_PS_PREFIX
|
||||
+hb_ot_name_entry_t
|
||||
+hb_ot_name_list_names()
|
||||
+hb_ot_name_get_utf8()
|
||||
+hb_ot_name_get_utf16()
|
||||
+hb_ot_name_get_utf32()
|
||||
|
||||
|
||||
Overview of changes leading to 2.0.2
|
||||
Saturday, October 20, 2018
|
||||
====================================
|
||||
|
|
|
@ -8,7 +8,8 @@ HarfBuzz release walk-through checklist:
|
|||
Document them in NEWS. All API and API semantic changes should be clearly
|
||||
marked as API additions, API changes, or API deletions. Document
|
||||
deprecations. Ensure all new API / deprecations are in listed correctly in
|
||||
docs/harfbuzz-sections.txt
|
||||
docs/harfbuzz-sections.txt. If release added new API, add entry for new
|
||||
API index at the end of docs/harfbuzz-docs.xml.
|
||||
|
||||
If there's a backward-incompatible API change (including deletions for API
|
||||
used anywhere), that's a release blocker. Do NOT release.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
AC_PREREQ([2.64])
|
||||
AC_INIT([HarfBuzz],
|
||||
[2.0.2],
|
||||
[2.1.0],
|
||||
[https://github.com/harfbuzz/harfbuzz/issues/new],
|
||||
[harfbuzz],
|
||||
[http://harfbuzz.org/])
|
||||
|
|
|
@ -72,14 +72,15 @@ HTML_IMAGES= \
|
|||
# Extra SGML files that are included by $(DOC_MAIN_SGML_FILE).
|
||||
# e.g. content_files=running.sgml building.sgml changes-2.0.sgml
|
||||
content_files= \
|
||||
usermanual-buffers-language-script-and-direction.xml \
|
||||
usermanual-clusters.xml \
|
||||
usermanual-fonts-and-faces.xml \
|
||||
usermanual-glyph-information.xml \
|
||||
usermanual-hello-harfbuzz.xml \
|
||||
usermanual-install-harfbuzz.xml \
|
||||
usermanual-opentype-features.xml \
|
||||
usermanual-what-is-harfbuzz.xml \
|
||||
usermanual-install-harfbuzz.xml \
|
||||
usermanual-getting-started.xml \
|
||||
usermanual-shaping-concepts.xml \
|
||||
usermanual-buffers-language-script-and-direction.xml \
|
||||
usermanual-fonts-and-faces.xml \
|
||||
usermanual-clusters.xml \
|
||||
usermanual-opentype-features.xml \
|
||||
usermanual-glyph-information.xml \
|
||||
version.xml
|
||||
|
||||
# SGML files where gtk-doc abbrevations (#GtkWidget) are expanded
|
||||
|
|
|
@ -12,28 +12,21 @@
|
|||
<graphic fileref="HarfBuzz.png" format="PNG" align="center"/>
|
||||
<para>
|
||||
HarfBuzz is an <ulink url="http://www.microsoft.com/typography/otspec/">OpenType</ulink>
|
||||
text shaping engine.
|
||||
text shaping engine. Using the HarfBuzz library allows
|
||||
programs to convert a sequence of Unicode input into
|
||||
properly formatted and positioned glyph output—for any writing
|
||||
system and language.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The current HarfBuzz codebase, formerly known as harfbuzz-ng, is
|
||||
versioned 1.x.x and is stable and under active maintenance. This is
|
||||
what is used in latest versions of Firefox, GNOME, ChromeOS, Chrome,
|
||||
LibreOffice, XeTeX, Android, and KDE, among other places. The canonical
|
||||
source tree is available
|
||||
<ulink url="http://cgit.freedesktop.org/harfbuzz/">here</ulink>.
|
||||
Also available on
|
||||
<ulink url="https://github.com/harfbuzz/harfbuzz">github</ulink>.
|
||||
See <xref linkend="download" endterm="download.title"/> for release tarballs.
|
||||
</para>
|
||||
<para>
|
||||
The old HarfBuzz codebase, these days known as harfbuzz-old, was
|
||||
derived from <ulink url="http://freetype.org/">FreeType</ulink>,
|
||||
<ulink url="http://pango.org/">Pango</ulink>, and
|
||||
<ulink url="http://qt-project.org/">Qt</ulink> and is available
|
||||
<ulink url="http://cgit.freedesktop.org/harfbuzz.old/">here</ulink>.
|
||||
It is not actively developed or maintained, and is extremely buggy. All
|
||||
users are encouraged to switch over to the new HarfBuzz as soon as
|
||||
possible. There are no release tarballs of old HarfBuzz whatsoever.
|
||||
The canonical source-code tree is available at
|
||||
<ulink
|
||||
url="https://github.com/harfbuzz/harfbuzz">github.com/harfbuzz/harfbuzz</ulink>
|
||||
and is also available at
|
||||
<ulink
|
||||
url="http://cgit.freedesktop.org/harfbuzz/">cgit.freedesktop.org/harfbuzz</ulink>.
|
||||
See <xref linkend="download" endterm="download.title"/> for
|
||||
release tarballs.
|
||||
</para>
|
||||
</abstract>
|
||||
</bookinfo>
|
||||
|
@ -42,7 +35,8 @@
|
|||
<title>User's manual</title>
|
||||
<xi:include href="usermanual-what-is-harfbuzz.xml"/>
|
||||
<xi:include href="usermanual-install-harfbuzz.xml"/>
|
||||
<xi:include href="usermanual-hello-harfbuzz.xml"/>
|
||||
<xi:include href="usermanual-getting-started.xml"/>
|
||||
<xi:include href="usermanual-shaping-concepts.xml"/>
|
||||
<xi:include href="usermanual-buffers-language-script-and-direction.xml"/>
|
||||
<xi:include href="usermanual-fonts-and-faces.xml"/>
|
||||
<xi:include href="usermanual-clusters.xml"/>
|
||||
|
@ -58,152 +52,119 @@
|
|||
<ulink role="online-location" url="http://[SERVER]/libharfbuzz/index.html">http://[SERVER]/libharfbuzz/</ulink>.-->
|
||||
</releaseinfo>
|
||||
</partinfo>
|
||||
|
||||
<note>
|
||||
<para>
|
||||
The current HarfBuzz codebase is versioned 2.x.x and is stable
|
||||
and under active maintenance. This is what is used in latest
|
||||
versions of Firefox, GNOME, ChromeOS, Chrome, LibreOffice,
|
||||
XeTeX, Android, and KDE, among other places.
|
||||
</para>
|
||||
<para>
|
||||
Prior to 2012, the original HarfBuzz codebase (which, these
|
||||
days, is referred to as <emphasis>harfbuzz-old</emphasis>) was
|
||||
derived from code in <ulink
|
||||
url="http://freetype.org/">FreeType</ulink>, <ulink
|
||||
url="http://pango.org/">Pango</ulink>, and
|
||||
<ulink url="http://qt-project.org/">Qt</ulink>.
|
||||
It is <emphasis>not</emphasis> actively developed or
|
||||
maintained, and is extremely buggy. All users of harfbuzz-old
|
||||
are encouraged to switch over to the new HarfBuzz as soon as possible.
|
||||
</para>
|
||||
<para>
|
||||
To make this distinction clearer in discussions, the current
|
||||
HarfBuzz codebase is sometimes referred to as
|
||||
<emphasis>harfbuzz-ng</emphasis>.
|
||||
</para>
|
||||
<para>
|
||||
For reference purposes, the harfbuzz-old source tree is archived
|
||||
<ulink
|
||||
url="http://cgit.freedesktop.org/harfbuzz.old/">here</ulink>. There
|
||||
are no release tarballs of harfbuzz-old whatsoever.
|
||||
</para>
|
||||
</note>
|
||||
|
||||
<title>Reference manual</title>
|
||||
<chapter>
|
||||
<title>HarfBuzz API</title>
|
||||
<xi:include href="xml/hb.xml"/>
|
||||
<xi:include href="xml/hb-common.xml"/>
|
||||
<xi:include href="xml/hb-unicode.xml"/>
|
||||
<xi:include href="xml/hb-buffer.xml"/>
|
||||
<title>Core API</title>
|
||||
<xi:include href="xml/hb-blob.xml"/>
|
||||
<xi:include href="xml/hb-buffer.xml"/>
|
||||
<xi:include href="xml/hb-common.xml"/>
|
||||
<xi:include href="xml/hb-deprecated.xml"/>
|
||||
<xi:include href="xml/hb-face.xml"/>
|
||||
<xi:include href="xml/hb-font.xml"/>
|
||||
<xi:include href="xml/hb-shape.xml"/>
|
||||
|
||||
<xi:include href="xml/hb-version.xml"/>
|
||||
<xi:include href="xml/hb-deprecated.xml"/>
|
||||
|
||||
<xi:include href="xml/hb-map.xml"/>
|
||||
<xi:include href="xml/hb-set.xml"/>
|
||||
|
||||
<xi:include href="xml/hb-ot.xml"/>
|
||||
<xi:include href="xml/hb-ot-layout.xml"/>
|
||||
<xi:include href="xml/hb-ot-tag.xml"/>
|
||||
<xi:include href="xml/hb-ot-font.xml"/>
|
||||
<xi:include href="xml/hb-ot-shape.xml"/>
|
||||
<xi:include href="xml/hb-ot-math.xml"/>
|
||||
|
||||
<xi:include href="xml/hb-shape-plan.xml"/>
|
||||
|
||||
<xi:include href="xml/hb-glib.xml"/>
|
||||
<xi:include href="xml/hb-icu.xml"/>
|
||||
|
||||
<xi:include href="xml/hb-ft.xml"/>
|
||||
|
||||
<xi:include href="xml/hb-graphite2.xml"/>
|
||||
<xi:include href="xml/hb-uniscribe.xml"/>
|
||||
<xi:include href="xml/hb-coretext.xml"/>
|
||||
|
||||
<xi:include href="xml/hb-gobject.xml"/>
|
||||
|
||||
<xi:include href="xml/hb-shape.xml"/>
|
||||
<xi:include href="xml/hb-unicode.xml"/>
|
||||
<xi:include href="xml/hb-version.xml"/>
|
||||
</chapter>
|
||||
<chapter id="object-tree">
|
||||
|
||||
<chapter>
|
||||
<title>OpenType API</title>
|
||||
<xi:include href="xml/hb-ot-color.xml"/>
|
||||
<xi:include href="xml/hb-ot-font.xml"/>
|
||||
<xi:include href="xml/hb-ot-layout.xml"/>
|
||||
<xi:include href="xml/hb-ot-math.xml"/>
|
||||
<xi:include href="xml/hb-ot-name.xml"/>
|
||||
<xi:include href="xml/hb-ot-shape.xml"/>
|
||||
<xi:include href="xml/hb-ot-var.xml"/>
|
||||
</chapter>
|
||||
|
||||
<chapter>
|
||||
<title>Integration API</title>
|
||||
<xi:include href="xml/hb-coretext.xml"/>
|
||||
<xi:include href="xml/hb-ft.xml"/>
|
||||
<xi:include href="xml/hb-glib.xml"/>
|
||||
<xi:include href="xml/hb-gobject.xml"/>
|
||||
<xi:include href="xml/hb-graphite2.xml"/>
|
||||
<xi:include href="xml/hb-icu.xml"/>
|
||||
<xi:include href="xml/hb-uniscribe.xml"/>
|
||||
</chapter>
|
||||
|
||||
<!--chapter id="object-tree">
|
||||
<title>Object Hierarchy</title>
|
||||
<xi:include href="xml/tree_index.sgml"/>
|
||||
</chapter>
|
||||
<index id="api-index-full">
|
||||
<title>API Index</title>
|
||||
<xi:include href="xml/api-index-full.xml"><xi:fallback /></xi:include>
|
||||
</index>
|
||||
<index id="api-index-0-9-2" role="0.9.2">
|
||||
<title>Index of new symbols in 0.9.2</title>
|
||||
<xi:include href="xml/api-index-0.9.2.xml"><xi:fallback /></xi:include>
|
||||
</index>
|
||||
<index id="api-index-0-9-5" role="0.9.5">
|
||||
<title>Index of new symbols in 0.9.5</title>
|
||||
<xi:include href="xml/api-index-0.9.5.xml"><xi:fallback /></xi:include>
|
||||
</index>
|
||||
<index id="api-index-0-9-7" role="0.9.7">
|
||||
<title>Index of new symbols in 0.9.7</title>
|
||||
<xi:include href="xml/api-index-0.9.7.xml"><xi:fallback /></xi:include>
|
||||
</index>
|
||||
<index id="api-index-0-9-8" role="0.9.8">
|
||||
<title>Index of new symbols in 0.9.8</title>
|
||||
<xi:include href="xml/api-index-0.9.8.xml"><xi:fallback /></xi:include>
|
||||
</index>
|
||||
<index id="api-index-0-9-10" role="0.9.10">
|
||||
<title>Index of new symbols in 0.9.10</title>
|
||||
<xi:include href="xml/api-index-0.9.10.xml"><xi:fallback /></xi:include>
|
||||
</index>
|
||||
<index id="api-index-0-9-11" role="0.9.11">
|
||||
<title>Index of new symbols in 0.9.11</title>
|
||||
<xi:include href="xml/api-index-0.9.11.xml"><xi:fallback /></xi:include>
|
||||
</index>
|
||||
<index id="api-index-0-9-20" role="0.9.20">
|
||||
<title>Index of new symbols in 0.9.20</title>
|
||||
<xi:include href="xml/api-index-0.9.20.xml"><xi:fallback /></xi:include>
|
||||
</index>
|
||||
<index id="api-index-0-9-22" role="0.9.22">
|
||||
<title>Index of new symbols in 0.9.22</title>
|
||||
<xi:include href="xml/api-index-0.9.22.xml"><xi:fallback /></xi:include>
|
||||
</index>
|
||||
<index id="api-index-0-9-28" role="0.9.28">
|
||||
<title>Index of new symbols in 0.9.28</title>
|
||||
<xi:include href="xml/api-index-0.9.28.xml"><xi:fallback /></xi:include>
|
||||
</index>
|
||||
<index id="api-index-0-9-30" role="0.9.30">
|
||||
<title>Index of new symbols in 0.9.30</title>
|
||||
<xi:include href="xml/api-index-0.9.30.xml"><xi:fallback /></xi:include>
|
||||
</index>
|
||||
<index id="api-index-0-9-31" role="0.9.31">
|
||||
<title>Index of new symbols in 0.9.31</title>
|
||||
<xi:include href="xml/api-index-0.9.31.xml"><xi:fallback /></xi:include>
|
||||
</index>
|
||||
<index id="api-index-0-9-38" role="0.9.38">
|
||||
<title>Index of new symbols in 0.9.38</title>
|
||||
<xi:include href="xml/api-index-0.9.38.xml"><xi:fallback /></xi:include>
|
||||
</index>
|
||||
<index id="api-index-0-9-39" role="0.9.39">
|
||||
<title>Index of new symbols in 0.9.39</title>
|
||||
<xi:include href="xml/api-index-0.9.39.xml"><xi:fallback /></xi:include>
|
||||
</index>
|
||||
<index id="api-index-0-9-41" role="0.9.41">
|
||||
<title>Index of new symbols in 0.9.41</title>
|
||||
<xi:include href="xml/api-index-0.9.41.xml"><xi:fallback /></xi:include>
|
||||
</index>
|
||||
<index id="api-index-0-9-42" role="0.9.42">
|
||||
<title>Index of new symbols in 0.9.42</title>
|
||||
<xi:include href="xml/api-index-0.9.42.xml"><xi:fallback /></xi:include>
|
||||
</index>
|
||||
<index id="api-index-1-0-5" role="1.0.5">
|
||||
<title>Index of new symbols in 1.0.5</title>
|
||||
<xi:include href="xml/api-index-1.0.5.xml"><xi:fallback /></xi:include>
|
||||
</index>
|
||||
<index id="api-index-1-1-2" role="1.1.2">
|
||||
<title>Index of new symbols in 1.1.2</title>
|
||||
<xi:include href="xml/api-index-1.1.2.xml"><xi:fallback /></xi:include>
|
||||
</index>
|
||||
<index id="api-index-1-1-3" role="1.1.3">
|
||||
<title>Index of new symbols in 1.1.3</title>
|
||||
<xi:include href="xml/api-index-1.1.3.xml"><xi:fallback /></xi:include>
|
||||
</index>
|
||||
<index id="api-index-1-2-3" role="1.2.3">
|
||||
<title>Index of new symbols in 1.2.3</title>
|
||||
<xi:include href="xml/api-index-1.2.3.xml"><xi:fallback /></xi:include>
|
||||
</index>
|
||||
<index id="api-index-1-3-3" role="1.3.3">
|
||||
<title>Index of new symbols in 1.3.3</title>
|
||||
<xi:include href="xml/api-index-1.3.3.xml"><xi:fallback /></xi:include>
|
||||
</index>
|
||||
<index id="api-index-1-4-2" role="1.4.2">
|
||||
<title>Index of new symbols in 1.4.2</title>
|
||||
<xi:include href="xml/api-index-1.4.2.xml"><xi:fallback /></xi:include>
|
||||
</index>
|
||||
<index id="api-index-1-4-3" role="1.4.3">
|
||||
<title>Index of new symbols in 1.4.3</title>
|
||||
<xi:include href="xml/api-index-1.4.3.xml"><xi:fallback /></xi:include>
|
||||
</index>
|
||||
<index id="api-index-1-5-0" role="1.5.0">
|
||||
<title>Index of new symbols in 1.5.0</title>
|
||||
<xi:include href="xml/api-index-1.5.0.xml"><xi:fallback /></xi:include>
|
||||
</index>
|
||||
<index id="api-index-1-6-0" role="1.6.0">
|
||||
<title>Index of new symbols in 1.6.0</title>
|
||||
<xi:include href="xml/api-index-1.6.0.xml"><xi:fallback /></xi:include>
|
||||
</index>
|
||||
<index id="deprecated-api-index" role="deprecated">
|
||||
<title>Index of deprecated API</title>
|
||||
<xi:include href="xml/api-index-deprecated.xml"><xi:fallback /></xi:include>
|
||||
</index>
|
||||
</chapter-->
|
||||
|
||||
<index id="api-index-full"><title>API Index</title><xi:include href="xml/api-index-full.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="deprecated-api-index" role="deprecated"><title>Index of deprecated API</title><xi:include href="xml/api-index-deprecated.xml"><xi:fallback /></xi:include></index>
|
||||
|
||||
<index id="api-index-2-1-0" role="2.1.0"><title>Index of new symbols in 2.1.0</title><xi:include href="xml/api-index-2.1.0.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-2-0-0" role="2.0.0"><title>Index of new symbols in 2.0.0</title><xi:include href="xml/api-index-2.0.0.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-1-9-0" role="1.9.0"><title>Index of new symbols in 1.9.0</title><xi:include href="xml/api-index-1.9.0.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-1-8-6" role="1.8.6"><title>Index of new symbols in 1.8.6</title><xi:include href="xml/api-index-1.8.6.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-1-8-5" role="1.8.5"><title>Index of new symbols in 1.8.5</title><xi:include href="xml/api-index-1.8.5.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-1-8-1" role="1.8.1"><title>Index of new symbols in 1.8.1</title><xi:include href="xml/api-index-1.8.1.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-1-8-0" role="1.8.0"><title>Index of new symbols in 1.8.0</title><xi:include href="xml/api-index-1.8.0.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-1-7-7" role="1.7.7"><title>Index of new symbols in 1.7.7</title><xi:include href="xml/api-index-1.7.7.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-1-7-5" role="1.7.5"><title>Index of new symbols in 1.7.5</title><xi:include href="xml/api-index-1.7.5.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-1-6-0" role="1.6.0"><title>Index of new symbols in 1.6.0</title><xi:include href="xml/api-index-1.6.0.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-1-5-0" role="1.5.0"><title>Index of new symbols in 1.5.0</title><xi:include href="xml/api-index-1.5.0.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-1-4-3" role="1.4.3"><title>Index of new symbols in 1.4.3</title><xi:include href="xml/api-index-1.4.3.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-1-4-2" role="1.4.2"><title>Index of new symbols in 1.4.2</title><xi:include href="xml/api-index-1.4.2.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-1-4-0" role="1.4.0"><title>Index of new symbols in 1.4.0</title><xi:include href="xml/api-index-1.4.0.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-1-3-3" role="1.3.3"><title>Index of new symbols in 1.3.3</title><xi:include href="xml/api-index-1.3.3.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-1-2-3" role="1.2.3"><title>Index of new symbols in 1.2.3</title><xi:include href="xml/api-index-1.2.3.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-1-1-3" role="1.1.3"><title>Index of new symbols in 1.1.3</title><xi:include href="xml/api-index-1.1.3.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-1-1-2" role="1.1.2"><title>Index of new symbols in 1.1.2</title><xi:include href="xml/api-index-1.1.2.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-1-0-5" role="1.0.5"><title>Index of new symbols in 1.0.5</title><xi:include href="xml/api-index-1.0.5.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-0-9-42" role="0.9.42"><title>Index of new symbols in 0.9.42</title><xi:include href="xml/api-index-0.9.42.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-0-9-41" role="0.9.41"><title>Index of new symbols in 0.9.41</title><xi:include href="xml/api-index-0.9.41.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-0-9-39" role="0.9.39"><title>Index of new symbols in 0.9.39</title><xi:include href="xml/api-index-0.9.39.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-0-9-38" role="0.9.38"><title>Index of new symbols in 0.9.38</title><xi:include href="xml/api-index-0.9.38.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-0-9-31" role="0.9.31"><title>Index of new symbols in 0.9.31</title><xi:include href="xml/api-index-0.9.31.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-0-9-30" role="0.9.30"><title>Index of new symbols in 0.9.30</title><xi:include href="xml/api-index-0.9.30.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-0-9-28" role="0.9.28"><title>Index of new symbols in 0.9.28</title><xi:include href="xml/api-index-0.9.28.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-0-9-22" role="0.9.22"><title>Index of new symbols in 0.9.22</title><xi:include href="xml/api-index-0.9.22.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-0-9-20" role="0.9.20"><title>Index of new symbols in 0.9.20</title><xi:include href="xml/api-index-0.9.20.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-0-9-11" role="0.9.11"><title>Index of new symbols in 0.9.11</title><xi:include href="xml/api-index-0.9.11.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-0-9-10" role="0.9.10"><title>Index of new symbols in 0.9.10</title><xi:include href="xml/api-index-0.9.10.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-0-9-8" role="0.9.8"><title>Index of new symbols in 0.9.8</title><xi:include href="xml/api-index-0.9.8.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-0-9-7" role="0.9.7"><title>Index of new symbols in 0.9.7</title><xi:include href="xml/api-index-0.9.7.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-0-9-5" role="0.9.5"><title>Index of new symbols in 0.9.5</title><xi:include href="xml/api-index-0.9.5.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-0-9-2" role="0.9.2"><title>Index of new symbols in 0.9.2</title><xi:include href="xml/api-index-0.9.2.xml"><xi:fallback /></xi:include></index>
|
||||
|
||||
<xi:include href="xml/annotation-glossary.xml"><xi:fallback /></xi:include>
|
||||
</part>
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
<SECTION>
|
||||
<FILE>hb</FILE>
|
||||
<SUBSECTION Private>
|
||||
HB_H_IN
|
||||
HB_EXTERN
|
||||
HB_OT_H_IN
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
|
@ -146,6 +144,10 @@ uint16_t
|
|||
uint32_t
|
||||
uint64_t
|
||||
uint8_t
|
||||
<SUBSECTION Private>
|
||||
HB_EXTERN
|
||||
HB_DEPRECATED
|
||||
HB_DEPRECATED_FOR
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
|
@ -358,6 +360,7 @@ HB_GOBJECT_TYPE_FONT_FUNCS
|
|||
HB_GOBJECT_TYPE_GLYPH_FLAGS
|
||||
HB_GOBJECT_TYPE_MAP
|
||||
HB_GOBJECT_TYPE_MEMORY_MODE
|
||||
HB_GOBJECT_TYPE_OT_COLOR_PALETTE_FLAGS
|
||||
HB_GOBJECT_TYPE_OT_LAYOUT_GLYPH_CLASS
|
||||
HB_GOBJECT_TYPE_OT_MATH_CONSTANT
|
||||
HB_GOBJECT_TYPE_OT_MATH_GLYPH_PART
|
||||
|
@ -390,6 +393,7 @@ hb_gobject_font_get_type
|
|||
hb_gobject_glyph_flags_get_type
|
||||
hb_gobject_map_get_type
|
||||
hb_gobject_memory_mode_get_type
|
||||
hb_gobject_ot_color_palette_flags_get_type
|
||||
hb_gobject_ot_layout_glyph_class_get_type
|
||||
hb_gobject_ot_math_constant_get_type
|
||||
hb_gobject_ot_math_glyph_part_get_type
|
||||
|
@ -412,11 +416,6 @@ hb_gobject_user_data_key_get_type
|
|||
HB_GOBJECT_H_IN
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>hb-gobject</FILE>
|
||||
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>hb-graphite2</FILE>
|
||||
HB_GRAPHITE2_TAG_SILF
|
||||
|
@ -452,9 +451,27 @@ hb_map_t
|
|||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>hb-ot</FILE>
|
||||
<SUBSECTION Private>
|
||||
HB_OT_H_IN
|
||||
<FILE>hb-ot-color</FILE>
|
||||
hb_color_t
|
||||
HB_COLOR
|
||||
hb_color_get_alpha
|
||||
hb_color_get_blue
|
||||
hb_color_get_green
|
||||
hb_color_get_red
|
||||
hb_ot_color_glyph_get_layers
|
||||
hb_ot_color_glyph_reference_png
|
||||
hb_ot_color_glyph_reference_svg
|
||||
hb_ot_color_has_layers
|
||||
hb_ot_color_has_palettes
|
||||
hb_ot_color_has_png
|
||||
hb_ot_color_has_svg
|
||||
hb_ot_color_layer_t
|
||||
hb_ot_color_palette_color_get_name_id
|
||||
hb_ot_color_palette_flags_t
|
||||
hb_ot_color_palette_get_colors
|
||||
hb_ot_color_palette_get_count
|
||||
hb_ot_color_palette_get_flags
|
||||
hb_ot_color_palette_get_name_id
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
|
@ -463,16 +480,31 @@ hb_ot_font_set_funcs
|
|||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>hb-ot-shape</FILE>
|
||||
hb_ot_shape_glyphs_closure
|
||||
<FILE>hb-ot-name</FILE>
|
||||
hb_ot_name_id_t
|
||||
HB_OT_NAME_ID_INVALID
|
||||
hb_ot_name_entry_t
|
||||
hb_ot_name_list_names
|
||||
hb_ot_name_get_utf16
|
||||
hb_ot_name_get_utf32
|
||||
hb_ot_name_get_utf8
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>hb-ot-layout</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_to_language
|
||||
hb_ot_tag_to_script
|
||||
hb_ot_tags_from_script_and_language
|
||||
hb_ot_tags_to_script_and_language
|
||||
HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX
|
||||
HB_OT_LAYOUT_NO_FEATURE_INDEX
|
||||
HB_OT_LAYOUT_NO_SCRIPT_INDEX
|
||||
HB_OT_LAYOUT_NO_VARIATIONS_INDEX
|
||||
HB_OT_TAG_BASE
|
||||
HB_OT_TAG_GDEF
|
||||
HB_OT_TAG_GPOS
|
||||
HB_OT_TAG_GSUB
|
||||
|
@ -517,23 +549,6 @@ Xhb_ot_layout_lookup_position
|
|||
Xhb_ot_layout_lookup_substitute
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>hb-ot-var</FILE>
|
||||
HB_OT_TAG_VAR_AXIS_ITALIC
|
||||
HB_OT_TAG_VAR_AXIS_OPTICAL_SIZE
|
||||
HB_OT_TAG_VAR_AXIS_SLANT
|
||||
HB_OT_TAG_VAR_AXIS_WEIGHT
|
||||
HB_OT_TAG_VAR_AXIS_WIDTH
|
||||
HB_OT_VAR_NO_AXIS_INDEX
|
||||
hb_ot_var_axis_t
|
||||
hb_ot_var_has_data
|
||||
hb_ot_var_find_axis
|
||||
hb_ot_var_get_axis_count
|
||||
hb_ot_var_get_axes
|
||||
hb_ot_var_normalize_variations
|
||||
hb_ot_var_normalize_coords
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>hb-ot-math</FILE>
|
||||
HB_OT_TAG_MATH
|
||||
|
@ -555,15 +570,25 @@ hb_ot_math_get_glyph_assembly
|
|||
</SECTION>
|
||||
|
||||
<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_to_language
|
||||
hb_ot_tag_to_script
|
||||
hb_ot_tags_from_script_and_language
|
||||
hb_ot_tags_to_script_and_language
|
||||
<FILE>hb-ot-shape</FILE>
|
||||
hb_ot_shape_glyphs_closure
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>hb-ot-var</FILE>
|
||||
HB_OT_TAG_VAR_AXIS_ITALIC
|
||||
HB_OT_TAG_VAR_AXIS_OPTICAL_SIZE
|
||||
HB_OT_TAG_VAR_AXIS_SLANT
|
||||
HB_OT_TAG_VAR_AXIS_WEIGHT
|
||||
HB_OT_TAG_VAR_AXIS_WIDTH
|
||||
HB_OT_VAR_NO_AXIS_INDEX
|
||||
hb_ot_var_axis_t
|
||||
hb_ot_var_has_data
|
||||
hb_ot_var_find_axis
|
||||
hb_ot_var_get_axis_count
|
||||
hb_ot_var_get_axes
|
||||
hb_ot_var_normalize_variations
|
||||
hb_ot_var_normalize_coords
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
<?xml version="1.0"?>
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
|
||||
<!ENTITY % local.common.attrib "xmlns:xi CDATA #FIXED 'http://www.w3.org/2003/XInclude'">
|
||||
<!ENTITY version SYSTEM "version.xml">
|
||||
]>
|
||||
<chapter id="buffers-language-script-and-direction">
|
||||
<title>Buffers, language, script and direction</title>
|
||||
<para>
|
||||
|
@ -74,4 +80,4 @@ void somefunc(hb_buffer_t *buffer) {
|
|||
<para>
|
||||
</para>
|
||||
</section>
|
||||
</chapter>
|
||||
</chapter>
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
<?xml version="1.0"?>
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
|
||||
<!ENTITY % local.common.attrib "xmlns:xi CDATA #FIXED 'http://www.w3.org/2003/XInclude'">
|
||||
<!ENTITY version SYSTEM "version.xml">
|
||||
]>
|
||||
<chapter id="clusters">
|
||||
<sect1 id="clusters">
|
||||
<title>Clusters</title>
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
<?xml version="1.0"?>
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
|
||||
<!ENTITY % local.common.attrib "xmlns:xi CDATA #FIXED 'http://www.w3.org/2003/XInclude'">
|
||||
<!ENTITY version SYSTEM "version.xml">
|
||||
]>
|
||||
<chapter id="fonts-and-faces">
|
||||
<title>Fonts and faces</title>
|
||||
<section id="using-freetype">
|
||||
|
@ -15,4 +21,4 @@
|
|||
<para>
|
||||
</para>
|
||||
</section>
|
||||
</chapter>
|
||||
</chapter>
|
||||
|
|
|
@ -0,0 +1,222 @@
|
|||
<?xml version="1.0"?>
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
|
||||
<!ENTITY % local.common.attrib "xmlns:xi CDATA #FIXED 'http://www.w3.org/2003/XInclude'">
|
||||
<!ENTITY version SYSTEM "version.xml">
|
||||
]>
|
||||
<chapter id="getting-started">
|
||||
<title>Getting started with HarfBuzz</title>
|
||||
<section>
|
||||
<title>An overview of the HarfBuzz shaping API</title>
|
||||
<para>
|
||||
The core of the HarfBuzz shaping API is the function
|
||||
<function>hb_shape()</function>. This function takes a font, a
|
||||
buffer containing a string of Unicode codepoints and
|
||||
(optionally) a list of font features as its input. It replaces
|
||||
the codepoints in the buffer with the corresponding glyphs from
|
||||
the font, correctly ordered and positioned, and with any of the
|
||||
optional font features applied.
|
||||
</para>
|
||||
<para>
|
||||
In addition to holding the pre-shaping input (the Unicode
|
||||
codepoints that comprise the input string) and the post-shaping
|
||||
output (the glyphs and positions), a HarfBuzz buffer has several
|
||||
properties that affect shaping. The most important are the
|
||||
text-flow direction (e.g., left-to-right, right-to-left,
|
||||
top-to-bottom, or bottom-to-top), the script tag, and the
|
||||
language tag.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
For input string buffers, flags are available to denote when the
|
||||
buffer represents the beginning or end of a paragraph, to
|
||||
indicate whether or not to visibly render Unicode <literal>Default
|
||||
Ignorable</literal> codepoints, and to modify the cluster-merging
|
||||
behavior for the buffer. For shaped output buffers, the
|
||||
individual X and Y offsets and <literal>advances</literal>
|
||||
(the logical dimensions) of each glyph are
|
||||
accessible. HarfBuzz also flags glyphs as
|
||||
<literal>UNSAFE_TO_BREAK</literal> if breaking the string at
|
||||
that glyph (e.g., in a line-breaking or hyphenation process)
|
||||
would require re-shaping the text.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
HarfBuzz also provides methods to compare the contents of
|
||||
buffers, join buffers, normalize buffer contents, and handle
|
||||
invalid codepoints, as well as to determine the state of a
|
||||
buffer (e.g., input codepoints or output glyphs). Buffer
|
||||
lifecycles are managed and all buffers are reference-counted.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Although the default <function>hb_shape()</function> function is
|
||||
sufficient for most use cases, a variant is also provide that
|
||||
lets you specify which of HarfBuzz's shapers to use on a buffer.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
HarfBuzz can read TrueType fonts, TrueType collections, OpenType
|
||||
fonts, and OpenType collections. Functions are provided to query
|
||||
font objects about metrics, Unicode coverage, available tables and
|
||||
features, and variation selectors. Individual glyphs can also be
|
||||
queried for metrics, variations, and glyph names. OpenType
|
||||
variable fonts are supported, and HarfBuzz allows you to set
|
||||
variation-axis coordinates on font objects.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
HarfBuzz provides glue code to integrate with various other
|
||||
libraries, including FreeType, GObject, and CoreText. Support
|
||||
for integrating with Uniscribe and DirectWrite is experimental
|
||||
at present.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Terminology</title>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>shaper</term>
|
||||
<listitem>
|
||||
<para>
|
||||
In HarfBuzz, a <emphasis>shaper</emphasis> is a
|
||||
handler for a specific script shaping model. HarfBuzz
|
||||
implements separate shapers for Indic, Arabic, Thai and
|
||||
Lao, Khmer, Myanmar, Tibetan, Hangul, Hebrew, the
|
||||
Universal Shaping Engine (USE), and a default shaper for
|
||||
non-complex scripts.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>cluster</term>
|
||||
<listitem>
|
||||
<para>
|
||||
In text shaping, a <emphasis>cluster</emphasis> is a
|
||||
sequence of codepoints that must be handled as an
|
||||
indivisible unit. Clusters can include codepoint
|
||||
sequences that form a ligature or base-and-mark
|
||||
sequences. Tracking and preserving clusters is important
|
||||
when shaping operations might separate or reorder
|
||||
codepoints.
|
||||
</para>
|
||||
<para>
|
||||
HarfBuzz provides three cluster
|
||||
<emphasis>levels</emphasis> that implement different
|
||||
approaches to the problem of preserving clusters during
|
||||
shaping operations.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
|
||||
</variablelist>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
<section>
|
||||
<title>A simple shaping example</title>
|
||||
|
||||
<para>
|
||||
Below is the simplest HarfBuzz shaping example possible.
|
||||
</para>
|
||||
<orderedlist numeration="arabic">
|
||||
<listitem>
|
||||
<para>
|
||||
Create a buffer and put your text in it.
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
<programlisting language="C">
|
||||
#include <hb.h>
|
||||
hb_buffer_t *buf;
|
||||
buf = hb_buffer_create();
|
||||
hb_buffer_add_utf8(buf, text, -1, 0, -1);
|
||||
</programlisting>
|
||||
<orderedlist numeration="arabic">
|
||||
<listitem override="2">
|
||||
<para>
|
||||
Guess the script, language and direction of the buffer.
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
<programlisting language="C">
|
||||
hb_buffer_set_direction(buf, HB_DIRECTION_LTR);
|
||||
hb_buffer_set_script(buf, HB_SCRIPT_LATIN);
|
||||
hb_buffer_set_language(buf, hb_language_from_string("en", -1));
|
||||
</programlisting>
|
||||
<orderedlist numeration="arabic">
|
||||
<listitem override="3">
|
||||
<para>
|
||||
Create a face and a font, using FreeType for now.
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
<programlisting language="C">
|
||||
#include <hb-ft.h>
|
||||
FT_New_Face(ft_library, font_path, index, &face)
|
||||
hb_font_t *font = hb_ft_font_create(face);
|
||||
</programlisting>
|
||||
<orderedlist numeration="arabic">
|
||||
<listitem override="4">
|
||||
<para>
|
||||
Shape!
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
<programlisting>
|
||||
hb_shape(font, buf, NULL, 0);
|
||||
</programlisting>
|
||||
<orderedlist numeration="arabic">
|
||||
<listitem override="5">
|
||||
<para>
|
||||
Get the glyph and position information.
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
<programlisting language="C">
|
||||
hb_glyph_info_t *glyph_info = hb_buffer_get_glyph_infos(buf, &glyph_count);
|
||||
hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions(buf, &glyph_count);
|
||||
</programlisting>
|
||||
<orderedlist numeration="arabic">
|
||||
<listitem override="6">
|
||||
<para>
|
||||
Iterate over each glyph.
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
<programlisting language="C">
|
||||
for (i = 0; i < glyph_count; ++i) {
|
||||
glyphid = glyph_info[i].codepoint;
|
||||
x_offset = glyph_pos[i].x_offset / 64.0;
|
||||
y_offset = glyph_pos[i].y_offset / 64.0;
|
||||
x_advance = glyph_pos[i].x_advance / 64.0;
|
||||
y_advance = glyph_pos[i].y_advance / 64.0;
|
||||
draw_glyph(glyphid, cursor_x + x_offset, cursor_y + y_offset);
|
||||
cursor_x += x_advance;
|
||||
cursor_y += y_advance;
|
||||
}
|
||||
</programlisting>
|
||||
<orderedlist numeration="arabic">
|
||||
<listitem override="7">
|
||||
<para>
|
||||
Tidy up.
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
<programlisting language="C">
|
||||
hb_buffer_destroy(buf);
|
||||
hb_font_destroy(hb_ft_font);
|
||||
</programlisting>
|
||||
|
||||
<para>
|
||||
This example shows enough to get us started using HarfBuzz. In
|
||||
the sections that follow, we will use the remainder of
|
||||
HarfBuzz's API to refine and extend the example and improve its
|
||||
text-shaping capabilities.
|
||||
</para>
|
||||
</section>
|
||||
</chapter>
|
|
@ -1,3 +1,9 @@
|
|||
<?xml version="1.0"?>
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
|
||||
<!ENTITY % local.common.attrib "xmlns:xi CDATA #FIXED 'http://www.w3.org/2003/XInclude'">
|
||||
<!ENTITY version SYSTEM "version.xml">
|
||||
]>
|
||||
<sect1 id="glyph-information">
|
||||
<title>Glyph information</title>
|
||||
<sect2 id="names-and-numbers">
|
||||
|
@ -5,4 +11,4 @@
|
|||
<para>
|
||||
</para>
|
||||
</sect2>
|
||||
</sect1>
|
||||
</sect1>
|
||||
|
|
|
@ -1,183 +0,0 @@
|
|||
<chapter id="hello-harfbuzz">
|
||||
<title>Hello, HarfBuzz</title>
|
||||
<para>
|
||||
Here's the simplest HarfBuzz that can possibly work. We will improve
|
||||
it later.
|
||||
</para>
|
||||
<orderedlist numeration="arabic">
|
||||
<listitem>
|
||||
<para>
|
||||
Create a buffer and put your text in it.
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
<programlisting language="C">
|
||||
#include <hb.h>
|
||||
hb_buffer_t *buf;
|
||||
buf = hb_buffer_create();
|
||||
hb_buffer_add_utf8(buf, text, strlen(text), 0, strlen(text));
|
||||
</programlisting>
|
||||
<orderedlist numeration="arabic">
|
||||
<listitem override="2">
|
||||
<para>
|
||||
Guess the script, language and direction of the buffer.
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
<programlisting language="C">
|
||||
hb_buffer_guess_segment_properties(buf);
|
||||
</programlisting>
|
||||
<orderedlist numeration="arabic">
|
||||
<listitem override="3">
|
||||
<para>
|
||||
Create a face and a font, using FreeType for now.
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
<programlisting language="C">
|
||||
#include <hb-ft.h>
|
||||
FT_New_Face(ft_library, font_path, index, &face)
|
||||
hb_font_t *font = hb_ft_font_create(face);
|
||||
</programlisting>
|
||||
<orderedlist numeration="arabic">
|
||||
<listitem override="4">
|
||||
<para>
|
||||
Shape!
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
<programlisting>
|
||||
hb_shape(font, buf, NULL, 0);
|
||||
</programlisting>
|
||||
<orderedlist numeration="arabic">
|
||||
<listitem override="5">
|
||||
<para>
|
||||
Get the glyph and position information.
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
<programlisting language="C">
|
||||
hb_glyph_info_t *glyph_info = hb_buffer_get_glyph_infos(buf, &glyph_count);
|
||||
hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions(buf, &glyph_count);
|
||||
</programlisting>
|
||||
<orderedlist numeration="arabic">
|
||||
<listitem override="6">
|
||||
<para>
|
||||
Iterate over each glyph.
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
<programlisting language="C">
|
||||
for (i = 0; i < glyph_count; ++i) {
|
||||
glyphid = glyph_info[i].codepoint;
|
||||
x_offset = glyph_pos[i].x_offset / 64.0;
|
||||
y_offset = glyph_pos[i].y_offset / 64.0;
|
||||
x_advance = glyph_pos[i].x_advance / 64.0;
|
||||
y_advance = glyph_pos[i].y_advance / 64.0;
|
||||
draw_glyph(glyphid, cursor_x + x_offset, cursor_y + y_offset);
|
||||
cursor_x += x_advance;
|
||||
cursor_y += y_advance;
|
||||
}
|
||||
</programlisting>
|
||||
<orderedlist numeration="arabic">
|
||||
<listitem override="7">
|
||||
<para>
|
||||
Tidy up.
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
<programlisting language="C">
|
||||
hb_buffer_destroy(buf);
|
||||
hb_font_destroy(hb_ft_font);
|
||||
</programlisting>
|
||||
<section id="what-harfbuzz-doesnt-do">
|
||||
<title>What HarfBuzz doesn't do</title>
|
||||
<para>
|
||||
The code above will take a UTF8 string, shape it, and give you the
|
||||
information required to lay it out correctly on a single
|
||||
horizontal (or vertical) line using the font provided. That is the
|
||||
extent of HarfBuzz's responsibility.
|
||||
</para>
|
||||
<para>
|
||||
If you are implementing a text layout engine you may have other
|
||||
responsibilities, that HarfBuzz will not help you with:
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
HarfBuzz won't help you with bidirectionality. If you want to
|
||||
lay out text with mixed Hebrew and English, you will need to
|
||||
ensure that the buffer provided to HarfBuzz has those
|
||||
characters in the correct layout order. This will be different
|
||||
from the logical order in which the Unicode text is stored. In
|
||||
other words, the user will hit the keys in the following
|
||||
sequence:
|
||||
</para>
|
||||
<programlisting>
|
||||
A B C [space] ג ב א [space] D E F
|
||||
</programlisting>
|
||||
<para>
|
||||
but will expect to see in the output:
|
||||
</para>
|
||||
<programlisting>
|
||||
ABC אבג DEF
|
||||
</programlisting>
|
||||
<para>
|
||||
This reordering is called <emphasis>bidi processing</emphasis>
|
||||
("bidi" is short for bidirectional), and there's an
|
||||
algorithm as an annex to the Unicode Standard which tells you how
|
||||
to reorder a string from logical order into presentation order.
|
||||
Before sending your string to HarfBuzz, you may need to apply the
|
||||
bidi algorithm to it. Libraries such as ICU and fribidi can do
|
||||
this for you.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
HarfBuzz won't help you with text that contains different font
|
||||
properties. For instance, if you have the string "a
|
||||
<emphasis>huge</emphasis> breakfast", and you expect
|
||||
"huge" to be italic, you will need to send three
|
||||
strings to HarfBuzz: <literal>a</literal>, in your Roman font;
|
||||
<literal>huge</literal> using your italic font; and
|
||||
<literal>breakfast</literal> using your Roman font again.
|
||||
Similarly if you change font, font size, script, language or
|
||||
direction within your string, you will need to shape each run
|
||||
independently and then output them independently. HarfBuzz
|
||||
expects to shape a run of characters sharing the same
|
||||
properties.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
HarfBuzz won't help you with line breaking, hyphenation or
|
||||
justification. As mentioned above, it lays out the string
|
||||
along a <emphasis>single line</emphasis> of, notionally,
|
||||
infinite length. If you want to find out where the potential
|
||||
word, sentence and line break points are in your text, you
|
||||
could use the ICU library's break iterator functions.
|
||||
</para>
|
||||
<para>
|
||||
HarfBuzz can tell you how wide a shaped piece of text is, which is
|
||||
useful input to a justification algorithm, but it knows nothing
|
||||
about paragraphs, lines or line lengths. Nor will it adjust the
|
||||
space between words to fit them proportionally into a line. If you
|
||||
want to layout text in paragraphs, you will probably want to send
|
||||
each word of your text to HarfBuzz to determine its shaped width
|
||||
after glyph substitutions, then work out how many words will fit
|
||||
on a line, and then finally output each word of the line separated
|
||||
by a space of the correct size to fully justify the paragraph.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>
|
||||
As a layout engine implementor, HarfBuzz will help you with the
|
||||
interface between your text and your font, and that's something
|
||||
that you'll need - what you then do with the glyphs that your font
|
||||
returns is up to you. The example we saw above enough to get us
|
||||
started using HarfBuzz. Now we are going to use the remainder of
|
||||
HarfBuzz's API to refine that example and improve our text shaping
|
||||
capabilities.
|
||||
</para>
|
||||
</section>
|
||||
</chapter>
|
|
@ -1,70 +1,431 @@
|
|||
<?xml version="1.0"?>
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
|
||||
<!ENTITY % local.common.attrib "xmlns:xi CDATA #FIXED 'http://www.w3.org/2003/XInclude'">
|
||||
<!ENTITY version SYSTEM "version.xml">
|
||||
]>
|
||||
<chapter id="install-harfbuzz">
|
||||
<title>Install HarfBuzz</title>
|
||||
<title>Installing HarfBuzz</title>
|
||||
|
||||
<section id="download">
|
||||
<title id="download.title">Download</title>
|
||||
<title id="download.title">Downloading HarfBuzz</title>
|
||||
<para>
|
||||
For tarball releases of HarfBuzz, look
|
||||
<ulink url="http://www.freedesktop.org/software/harfbuzz/release/">here</ulink>.
|
||||
At the same place you will
|
||||
also find Win32 binary bundles that include libharfbuzz DLL, hb-view.exe,
|
||||
hb-shape.exe, and all dependencies.
|
||||
The HarfBuzz source code is hosted at <ulink
|
||||
url="https://github.com/harfbuzz/harfbuzz">github.com/harfbuzz/harfbuzz</ulink>. The
|
||||
same source tree is also available at the
|
||||
<ulink
|
||||
url="http://cgit.freedesktop.org/harfbuzz/">Freedesktop.org</ulink>
|
||||
site.
|
||||
</para>
|
||||
<para>
|
||||
The canonical source tree is available
|
||||
<ulink url="http://cgit.freedesktop.org/harfbuzz/">here</ulink>.
|
||||
Also available on <ulink url="https://github.com/harfbuzz/harfbuzz">github</ulink>.
|
||||
Tarball releases and Win32 binary bundles (which include the
|
||||
libharfbuzz DLL, hb-view.exe, hb-shape.exe, and all
|
||||
dependencies) of HarfBuzz can be downloaded from <ulink
|
||||
url="https://github.com/harfbuzz/harfbuzz">github.com/harfbuzz/harfbuzz/releases</ulink>
|
||||
or from
|
||||
<ulink url="http://www.freedesktop.org/software/harfbuzz/release/">Freedesktop.org</ulink>.
|
||||
</para>
|
||||
<para>
|
||||
The API that comes with <filename class='headerfile'>hb.h</filename> will
|
||||
not change incompatibly. Other, peripheral, headers are more likely to go
|
||||
through minor modifications, but again, will do our best to never change
|
||||
API in an incompatible way. We will never break the ABI.
|
||||
Release notes are posted with each new release to provide an
|
||||
overview of the changes. The project <ulink url="https://github.com/harfbuzz/harfbuzz/issues">tracks bug
|
||||
reports and other issues</ulink> on GitHub. Discussion and
|
||||
questions are welcome on the <ulink
|
||||
url="http://freedesktop.org/mailman/listinfo/harfbuzz/">HarfBuzz
|
||||
mailing list</ulink>.
|
||||
</para>
|
||||
<para>
|
||||
If you are not sure whether Pango or HarfBuzz is right for you, read
|
||||
<ulink url="http://mces.blogspot.in/2009/11/pango-vs-harfbuzz.html">this</ulink>.
|
||||
The API included in the <filename
|
||||
class='headerfile'>hb.h</filename> file will not change in a
|
||||
compatibility-breaking way in any release. However, other,
|
||||
peripheral headers are more likely to go through minor
|
||||
modifications. We will do our best to never change APIs in an
|
||||
incompatible way. We will <emphasis>never</emphasis> break the ABI.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="building">
|
||||
<title>Building</title>
|
||||
<title>Building HarfBuzz</title>
|
||||
|
||||
<section id="building.linux">
|
||||
<title>Building on Linux</title>
|
||||
<para>
|
||||
On Linux, install the development packages for FreeType, Cairo, and GLib.
|
||||
For example, on Ubuntu / Debian, you would do:
|
||||
<programlisting>
|
||||
<command>sudo apt-get install</command> <package>gcc g++ libfreetype6-dev libglib2.0-dev libcairo2-dev</package>
|
||||
</programlisting>
|
||||
whereas on Fedora, RHEL, CentOS, and other Red Hat based systems you would do:
|
||||
<programlisting>
|
||||
<command>sudo yum install</command> <package>gcc gcc-c++ freetype-devel glib2-devel cairo-devel</package>
|
||||
</programlisting>
|
||||
or using MacPorts:
|
||||
<programlisting>
|
||||
<command>sudo port install</command> <package>freetype glib2 cairo</package>
|
||||
</programlisting>
|
||||
<emphasis>(1)</emphasis> To build HarfBuzz on Linux, you must first install the
|
||||
development packages for FreeType, Cairo, and GLib. The exact
|
||||
commands required for this step will vary depending on
|
||||
the Linux distribution you use.
|
||||
</para>
|
||||
<para>
|
||||
If you are using a tarball, you can now proceed to running
|
||||
<command>configure</command> and <command>make</command> as with any
|
||||
other standard package. That should leave you with a shared library in
|
||||
<filename>src/</filename>, and a few utility programs including hb-view
|
||||
and hb-shape under <filename>util/</filename>.
|
||||
For example, on an Ubuntu or Debian system, you would run:
|
||||
<programlisting>
|
||||
<command>sudo apt install</command> <package>gcc g++
|
||||
libfreetype6-dev libglib2.0-dev libcairo2-dev</package>
|
||||
</programlisting>
|
||||
On Fedora, RHEL, CentOS, or other Red-Hat–based systems, you would run:
|
||||
<programlisting>
|
||||
<command>sudo yum install</command> <package>gcc gcc-c++ freetype-devel glib2-devel cairo-devel</package>
|
||||
</programlisting>
|
||||
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<emphasis>(2)</emphasis> The next step depends on whether you
|
||||
are building from the source in a downloaded release tarball or
|
||||
from the source directly from the git repository.
|
||||
</para>
|
||||
<para>
|
||||
If you are bootstrapping from git, you need a few more tools before you
|
||||
can run <filename>autogen.sh</filename> for the first time. Namely,
|
||||
pkg-config and <ulink url="http://www.complang.org/ragel/">ragel</ulink>.
|
||||
Again, on Ubuntu / Debian:
|
||||
<programlisting>
|
||||
<command>sudo apt-get install</command> <package>autoconf automake libtool pkg-config ragel gtk-doc-tools</package>
|
||||
</programlisting>
|
||||
and on Fedora, RHEL, CentOS:
|
||||
<programlisting>
|
||||
<command>sudo yum install</command> <package>autoconf automake libtool pkgconfig ragel gtk-doc</package>
|
||||
</programlisting>
|
||||
or using MacPorts:
|
||||
<programlisting>
|
||||
<command>sudo port install</command> <package>autoconf automake libtool pkgconfig ragel gtk-doc</package>
|
||||
</programlisting>
|
||||
<emphasis>(2)(a)</emphasis> If you downloaded the HarfBuzz
|
||||
source code in a tarball, you can now extract the source.
|
||||
</para>
|
||||
<para>
|
||||
From a shell in the top-level directory of the extracted source
|
||||
code, you can run <command>./configure</command> followed by
|
||||
<command>make</command> as with any other standard package.
|
||||
</para>
|
||||
<para>
|
||||
This should leave you with a shared
|
||||
library in the <filename>src/</filename> directory, and a few
|
||||
utility programs including <command>hb-view</command> and
|
||||
<command>hb-shape</command> under the <filename>util/</filename>
|
||||
directory.
|
||||
</para>
|
||||
<para>
|
||||
<emphasis>(2)(b)</emphasis> If you are building from the source in the HarfBuzz git
|
||||
repository, rather than installing from a downloaded tarball
|
||||
release, then you must install two more auxiliary tools before you
|
||||
can build for the first time: <package>pkg-config</package> and
|
||||
<ulink url="http://www.complang.org/ragel/">ragel</ulink>.
|
||||
</para>
|
||||
<para>
|
||||
On Ubuntu or Debian, run:
|
||||
<programlisting>
|
||||
<command>sudo apt-get install</command> <package>autoconf automake libtool pkg-config ragel gtk-doc-tools</package>
|
||||
</programlisting>
|
||||
On Fedora, RHEL, CentOS, run:
|
||||
<programlisting>
|
||||
<command>sudo yum install</command> <package>autoconf automake libtool pkgconfig ragel gtk-doc</package>
|
||||
</programlisting>
|
||||
|
||||
</para>
|
||||
<para>
|
||||
With <package>pkg-config</package> and <package>ragel</package>
|
||||
installed, you can now run <command>./autogen.sh</command>,
|
||||
followed by <command>./configure</command> and
|
||||
<command>make</command> to build HarfBuzz.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
|
||||
<section id="building.windows">
|
||||
<title>Building on Windows</title>
|
||||
|
||||
<para>
|
||||
On Windows, consider using Microsoft's free <ulink
|
||||
url="https://github.com/Microsoft/vcpkg">vcpkg</ulink> utility
|
||||
to build HarfBuzz, its dependencies, and other open-source
|
||||
libraries.
|
||||
</para>
|
||||
<para>
|
||||
If you need to build HarfBuzz from source, first put the
|
||||
<program>ragel</program> binary on your
|
||||
<literal>PATH</literal>, then follow the appveyor CI cmake
|
||||
<ulink
|
||||
url="https://github.com/harfbuzz/harfbuzz/blob/master/appveyor.yml">build
|
||||
instructions</ulink>.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
|
||||
<section id="building.macos">
|
||||
<title>Building on macOS</title>
|
||||
|
||||
<para>
|
||||
There are two ways to build HarfBuzz on Mac systems: MacPorts
|
||||
and Homebrew. The process is similar to the process used on a
|
||||
Linux system.
|
||||
</para>
|
||||
<para>
|
||||
<emphasis>(1)</emphasis> You must first install the
|
||||
development packages for FreeType, Cairo, and GLib. If you are
|
||||
using MacPorts, you should run:
|
||||
<programlisting>
|
||||
<command>sudo port install</command> <package>freetype glib2 cairo</package>
|
||||
</programlisting>
|
||||
</para>
|
||||
<para>
|
||||
If you are using Homebrew, you should run:
|
||||
<programlisting>
|
||||
<command>brew install</command> <package>freetype glib cairo</package>
|
||||
</programlisting>
|
||||
</para>
|
||||
<para>
|
||||
<emphasis>(2)</emphasis> The next step depends on whether you are building from the
|
||||
source in a downloaded release tarball or from the source directly
|
||||
from the git repository.
|
||||
</para>
|
||||
<para>
|
||||
<emphasis>(2)(a)</emphasis> If you are installing HarfBuzz
|
||||
from a downloaded tarball release, extract the tarball and
|
||||
open a Terminal in the extracted source-code directory. Run:
|
||||
<programlisting>
|
||||
<command>./configure</command>
|
||||
</programlisting>
|
||||
followed by:
|
||||
<programlisting>
|
||||
<command>make</command>
|
||||
</programlisting>
|
||||
to build HarfBuzz.
|
||||
</para>
|
||||
<para>
|
||||
<emphasis>(2)(b)</emphasis> Alternatively, if you are building
|
||||
HarfBuzz from the source in the HarfBuzz git repository, then
|
||||
you must install several built-time dependencies before
|
||||
proceeding.
|
||||
</para>
|
||||
<para>If you are
|
||||
using MacPorts, you should run:
|
||||
<programlisting>
|
||||
<command>sudo port install</command> <package>autoconf
|
||||
automake libtool pkgconfig ragel gtk-doc</package>
|
||||
</programlisting>
|
||||
to install the build dependencies.
|
||||
</para>
|
||||
<para>If you are using Homebrew, you should run:
|
||||
<programlisting>
|
||||
<command>brew install</command> <package>autoconf automake libtool pkgconfig ragel gtk-doc</package>
|
||||
</programlisting>
|
||||
Finally, you can run:
|
||||
<programlisting>
|
||||
<command>./autogen.sh</command>
|
||||
</programlisting>
|
||||
</para>
|
||||
<para>
|
||||
<emphasis>(3)</emphasis> You can now build HarfBuzz (on either
|
||||
a MacPorts or a Homebrew system) by running:
|
||||
<programlisting>
|
||||
<command>./configure</command>
|
||||
</programlisting>
|
||||
followed by:
|
||||
<programlisting>
|
||||
<command>make</command>
|
||||
</programlisting>
|
||||
</para>
|
||||
<para>
|
||||
This should leave you with a shared
|
||||
library in the <filename>src/</filename> directory, and a few
|
||||
utility programs including <command>hb-view</command> and
|
||||
<command>hb-shape</command> under the <filename>util/</filename>
|
||||
directory.
|
||||
</para>
|
||||
|
||||
</section>
|
||||
|
||||
<section id="configuration">
|
||||
<title>Configuration options</title>
|
||||
|
||||
<para>
|
||||
The instructions in the "Building HarfBuzz" section will build
|
||||
the source code under its default configuration. If needed,
|
||||
the following additional configuration options are available.
|
||||
</para>
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>--with-libstdc++</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Allow linking with libstdc++. <emphasis>(Default = no)</emphasis>
|
||||
</para>
|
||||
<para>
|
||||
This option enables or disables linking HarfBuzz to the
|
||||
system's libstdc++ library.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>--with-glib</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Use <ulink url="https://developer.gnome.org/glib/">GLib</ulink>. <emphasis>(Default = auto)</emphasis>
|
||||
</para>
|
||||
<para>
|
||||
This option enables or disables usage of the GLib
|
||||
library. The default setting is to check for the
|
||||
presence of GLib and, if it is found, build with
|
||||
GLib support. GLib is native to GNU/Linux systems but is
|
||||
available on other operating system as well.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>--with-gobject</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Use <ulink url="https://developer.gnome.org/gobject/stable/">GObject</ulink>. <emphasis>(Default = no)</emphasis>
|
||||
</para>
|
||||
<para>
|
||||
This option enables or disables usage of the GObject
|
||||
library. The default setting is to check for the
|
||||
presence of GObject and, if it is found, build with
|
||||
GObject support. GObject is native to GNU/Linux systems but is
|
||||
available on other operating system as well.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>--with-cairo</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Use <ulink url="https://cairographics.org/">Cairo</ulink>. <emphasis>(Default = auto)</emphasis>
|
||||
</para>
|
||||
<para>
|
||||
This option enables or disables usage of the Cairo
|
||||
graphics-rendering library. The default setting is to
|
||||
check for the presence of Cairo and, if it is found,
|
||||
build with Cairo support.
|
||||
</para>
|
||||
<para>
|
||||
Note: Cairo is used only by the HarfBuzz
|
||||
command-line utilities, and not by the HarfBuzz library.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>--with-fontconfig</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Use <ulink url="https://www.freedesktop.org/wiki/Software/fontconfig/">Fontconfig</ulink>. <emphasis>(Default = auto)</emphasis>
|
||||
</para>
|
||||
<para>
|
||||
This option enables or disables usage of the Fontconfig
|
||||
library, which provides font-matching functions and
|
||||
provides access to font properties. The default setting
|
||||
is to check for the presence of Fontconfig and, if it is
|
||||
found, build with Fontconfig support.
|
||||
</para>
|
||||
<para>
|
||||
Note: Fontconfig is used only by the HarfBuzz
|
||||
command-line utilities, and not by the HarfBuzz library.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>--with-icu</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Use the <ulink url="http://site.icu-project.org/home">ICU</ulink> library. <emphasis>(Default = auto)</emphasis>
|
||||
</para>
|
||||
<para>
|
||||
This option enables or disables usage of the
|
||||
<emphasis>International Components for
|
||||
Unicode</emphasis> (ICU) library, which provides access
|
||||
to Unicode Character Database (UCD) properties as well
|
||||
as normalization and conversion functions. The default
|
||||
setting is to check for the presence of ICU and, if it
|
||||
is found, build with ICU support.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>--with-ucdn</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Use HarfBuzz's <ulink url="https://github.com/harfbuzz/harfbuzz/tree/master/src/hb-ucdn">built-in UCDN library</ulink>. <emphasis>(Default = auto)</emphasis>
|
||||
</para>
|
||||
<para>
|
||||
The HarfBuzz source tree includes a <emphasis>Unicode
|
||||
Database and Normalization</emphasis> (UCDN) library
|
||||
that provides access to basic character properties in
|
||||
the Unicode Character Database (UCD) as well as low-level
|
||||
normalization functions. HarfBuzz can be built without
|
||||
this UCDN support if the usage of a different UCDN
|
||||
library is desired.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>--with-graphite2</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Use the <ulink url="http://graphite.sil.org/">Graphite2</ulink> library. <emphasis>(Default = no)</emphasis>
|
||||
</para>
|
||||
<para>
|
||||
This option enables or disables usage of the Graphite2
|
||||
library, which provides support for the Graphite shaping
|
||||
model.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>--with-freetype</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Use the <ulink url="https://www.freetype.org/">FreeType</ulink> library. <emphasis>(Default = auto)</emphasis>
|
||||
</para>
|
||||
<para>
|
||||
This option enables or disables usage of the FreeType
|
||||
font-rendering library. The default setting is to check for the
|
||||
presence of FreeType and, if it is found, build with
|
||||
FreeType support.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>--with-uniscribe</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Use the <ulink
|
||||
url="https://docs.microsoft.com/en-us/windows/desktop/intl/uniscribe">Uniscribe</ulink>
|
||||
library (experimental). <emphasis>(Default = no)</emphasis>
|
||||
</para>
|
||||
<para>
|
||||
This option enables or disables usage of the Uniscribe
|
||||
font-rendering library. Uniscribe is available on
|
||||
Windows systems. Uniscribe support is used only for
|
||||
testing purposes and does not need to be enabled for
|
||||
HarfBuzz to run on Windows systems.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>--with-directwrite</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Use the <ulink url="https://docs.microsoft.com/en-us/windows/desktop/directwrite/direct-write-portal">DirectWrite</ulink> library (experimental). <emphasis>(Default = no)</emphasis>
|
||||
</para>
|
||||
<para>
|
||||
This option enables or disables usage of the DirectWrite
|
||||
font-rendering library. DirectWrite is available on
|
||||
Windows systems. DirectWrite support is used only for
|
||||
testing purposes and does not need to be enabled for
|
||||
HarfBuzz to run on Windows systems.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>--with-coretext</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Use the <ulink url="https://developer.apple.com/documentation/coretext">CoreText</ulink> library. <emphasis>(Default = no)</emphasis>
|
||||
</para>
|
||||
<para>
|
||||
This option enables or disables usage of the CoreText
|
||||
library. CoreText is available on macOS and iOS systems.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</section>
|
||||
|
||||
</section>
|
||||
</chapter>
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
<?xml version="1.0"?>
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
|
||||
<!ENTITY % local.common.attrib "xmlns:xi CDATA #FIXED 'http://www.w3.org/2003/XInclude'">
|
||||
<!ENTITY version SYSTEM "version.xml">
|
||||
]>
|
||||
<chapter id="shaping-and-shape-plans">
|
||||
<title>Shaping and shape plans</title>
|
||||
<section id="opentype-features">
|
||||
|
@ -10,4 +16,4 @@
|
|||
<para>
|
||||
</para>
|
||||
</section>
|
||||
</chapter>
|
||||
</chapter>
|
||||
|
|
|
@ -0,0 +1,374 @@
|
|||
<?xml version="1.0"?>
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
|
||||
<!ENTITY % local.common.attrib "xmlns:xi CDATA #FIXED 'http://www.w3.org/2003/XInclude'">
|
||||
<!ENTITY version SYSTEM "version.xml">
|
||||
]>
|
||||
<chapter id="shaping-concepts">
|
||||
<title>Shaping concepts</title>
|
||||
<section id="text-shaping-concepts">
|
||||
<title>Text shaping</title>
|
||||
<para>
|
||||
Text shaping is the process of transforming a sequence of Unicode
|
||||
codepoints that represent individual characters (letters,
|
||||
diacritics, tone marks, numbers, symbols, etc.) into the
|
||||
orthographically and linguistically correct two-dimensional layout
|
||||
of glyph shapes taken from a specified font.
|
||||
</para>
|
||||
<para>
|
||||
For some writing systems (or <emphasis>scripts</emphasis>) and
|
||||
languages, the process is simple, requiring the shaper to do
|
||||
little more than advance the horizontal position forward by the
|
||||
correct amount for each successive glyph.
|
||||
</para>
|
||||
<para>
|
||||
But, for <emphasis>complex scripts</emphasis>, any combination of
|
||||
several shaping operations may be required, and the rules for how
|
||||
and when they are applied vary from script to script. HarfBuzz and
|
||||
other shaping engines implement these rules.
|
||||
</para>
|
||||
<para>
|
||||
The exact rules and necessary operations for a particular script
|
||||
constitute a shaping <emphasis>model</emphasis>. OpenType
|
||||
specifies a set of shaping models that covers all of
|
||||
Unicode. Other shaping models are available, however, including
|
||||
Graphite and Apple Advanced Typography (AAT).
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="complex-scripts">
|
||||
<title>Complex scripts</title>
|
||||
<para>
|
||||
In text-shaping terminology, scripts are generally classified as
|
||||
either <emphasis>complex</emphasis> or <emphasis>non-complex</emphasis>.
|
||||
</para>
|
||||
<para>
|
||||
Complex scripts are those for which transforming the input
|
||||
sequence into the final layout requires some combination of
|
||||
operations—such as context-dependent substitutions,
|
||||
context-dependent mark positioning, glyph-to-glyph joining,
|
||||
glyph reordering, or glyph stacking.
|
||||
</para>
|
||||
<para>
|
||||
In some complex scripts, the shaping rules require that a text
|
||||
run be divided into syllables before the operations can be
|
||||
applied. Other complex scripts may apply shaping operations over
|
||||
entire words or over the entire text run, with no subdivision
|
||||
required.
|
||||
</para>
|
||||
<para>
|
||||
Non-complex scripts, by definition, do not require these
|
||||
operations. However, correctly shaping a text run in a
|
||||
non-complex script may still involve Unicode normalization,
|
||||
ligature substitutions, mark positioning, kerning, and applying
|
||||
other font features. The key difference is that a text run in a
|
||||
non-complex script can be processed sequentially and in the same
|
||||
order as the input sequence of Unicode codepoints, without
|
||||
requiring an analysis stage.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="shaping-operations">
|
||||
<title>Shaping operations</title>
|
||||
<para>
|
||||
Shaping a complex-script text run involves transforming the
|
||||
input sequence of Unicode codepoints with some combination of
|
||||
operations that is specified in the shaping model for the
|
||||
script.
|
||||
</para>
|
||||
<para>
|
||||
The specific conditions that trigger a given operation for a
|
||||
text run varies from script to script, as do the order that the
|
||||
operations are performed in and which codepoints are
|
||||
affected. However, the same general set of shaping operations is
|
||||
common to all of the complex-script shaping models.
|
||||
</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
A <emphasis>reordering</emphasis> operation moves a glyph
|
||||
from its original ("logical") position in the sequence to
|
||||
some other ("visual") position.
|
||||
</para>
|
||||
<para>
|
||||
The shaping model for a given complex script might involve
|
||||
more than one reordering step.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
A <emphasis>joining</emphasis> operation replaces a glyph
|
||||
with an alternate form that is designed to connect with one
|
||||
or more of the adjacent glyphs in the sequence.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
A contextual <emphasis>substitution</emphasis> operation
|
||||
replaces either a single glyph or a subsequence of several
|
||||
glyphs with an alternate glyph. This substitution is
|
||||
performed when the original glyph or subsequence of glyphs
|
||||
occurs in a specified position with respect to the
|
||||
surrounding sequence. For example, one substitution might be
|
||||
performed only when the target glyph is the first glyph in
|
||||
the sequence, while another substitution is performed only
|
||||
when a different target glyph occurs immediately after a
|
||||
particular string pattern.
|
||||
</para>
|
||||
<para>
|
||||
The shaping model for a given complex script might involve
|
||||
multiple contextual-substitution operations, each applying
|
||||
to different target glyphs and patterns, and which are
|
||||
performed in separate steps.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
A contextual <emphasis>positioning</emphasis> operation
|
||||
moves the horizontal and/or vertical position of a
|
||||
glyph. This positioning move is performed when the glyph
|
||||
occurs in a specified position with respect to the
|
||||
surrounding sequence.
|
||||
</para>
|
||||
<para>
|
||||
Many contextual positioning operations are used to place
|
||||
<emphasis>mark</emphasis> glyphs (such as diacritics, vowel
|
||||
signs, and tone markers) with respect to
|
||||
<emphasis>base</emphasis> glyphs. However, some complex
|
||||
scripts may use contextual positioning operations to
|
||||
correctly place base glyphs as well, such as
|
||||
when the script uses <emphasis>stacking</emphasis> characters.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
</itemizedlist>
|
||||
</section>
|
||||
|
||||
<section id="unicode-character-categories">
|
||||
<title>Unicode character categories</title>
|
||||
<para>
|
||||
Shaping models are typically specified with respect to how
|
||||
scripts are defined in the Unicode standard.
|
||||
</para>
|
||||
<para>
|
||||
Every codepoint in the Unicode Character Database (UCD) is
|
||||
assigned a <emphasis>Unicode General Category</emphasis> (UGC),
|
||||
which provides the most fundamental information about the
|
||||
codepoint: whether the codepoint represents a
|
||||
<emphasis>Letter</emphasis>, a <emphasis>Mark</emphasis>, a
|
||||
<emphasis>Number</emphasis>, <emphasis>Punctuation</emphasis>, a
|
||||
<emphasis>Symbol</emphasis>, a <emphasis>Separator</emphasis>,
|
||||
or something else (<emphasis>Other</emphasis>).
|
||||
</para>
|
||||
<para>
|
||||
These UGC properties are "Major" categories. Each codepoint is
|
||||
further assigned to a "minor" category within its Major
|
||||
category, such as "Letter, uppercase" (<literal>Lu</literal>) or
|
||||
"Letter, modifier" (<literal>Lm</literal>).
|
||||
</para>
|
||||
<para>
|
||||
Shaping models are concerned primarily with Letter and Mark
|
||||
codepoints. The minor categories of Mark codepoints are
|
||||
particularly important for shaping. Marks can be nonspacing
|
||||
(<literal>Mn</literal>), spacing combining
|
||||
(<literal>Mc</literal>), or enclosing (<literal>Me</literal>).
|
||||
</para>
|
||||
<para>
|
||||
In addition to the UGC property, codepoints in the Indic and
|
||||
Southeast Asian scripts are also assigned
|
||||
<emphasis>Unicode Indic Syllabic Category</emphasis> (UISC) and
|
||||
<emphasis>Unicode Indic Positional Category</emphasis> (UIPC)
|
||||
property that provides more detailed information needed for
|
||||
shaping.
|
||||
</para>
|
||||
<para>
|
||||
The UISC property sub-categorizes Letters and Marks according to
|
||||
common script-shaping behaviors. For example, UISC distinguishes
|
||||
between consonant letters, vowel letters, and vowel marks. The
|
||||
UIPC property sub-categorizes Mark codepoints by the visual
|
||||
position that they occupy (above, below, right, left, or in
|
||||
multiple positions).
|
||||
</para>
|
||||
<para>
|
||||
Some complex scripts require that the text run be split into
|
||||
syllables, and what constitutes a valid syllable in these
|
||||
scripts is specified in regular expressions of the Letter and
|
||||
Mark codepoints that take the UISC and UIPC properties into account.
|
||||
</para>
|
||||
|
||||
</section>
|
||||
|
||||
<section id="text-runs">
|
||||
<title>Text runs</title>
|
||||
<para>
|
||||
Real-world text usually contains codepoints from a mixture of
|
||||
different Unicode scripts (including punctuation, numbers, symbols,
|
||||
white-space characters, and other codepoints that do not belong
|
||||
to any script). Real-world text may also be marked up with
|
||||
formatting that changes font properties (including the font,
|
||||
font style, and font size).
|
||||
</para>
|
||||
<para>
|
||||
For shaping purposes, all real-world text streams must be first
|
||||
segmented into runs that have a uniform set of properties.
|
||||
</para>
|
||||
<para>
|
||||
In particular, shaping models always assume that every codepoint
|
||||
in a text run has the same <emphasis>direction</emphasis>,
|
||||
<emphasis>script</emphasis> tag, and
|
||||
<emphasis>language</emphasis> tag.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="opentype-shaping-models">
|
||||
<title>OpenType shaping models</title>
|
||||
<para>
|
||||
OpenType provides shaping models for the following scripts:
|
||||
</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
The <emphasis>default</emphasis> shaping model handles all
|
||||
non-complex scripts, and may also be used as a fallback for
|
||||
handling unrecognized scripts.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
The <emphasis>Indic</emphasis> shaping model handles the Indic
|
||||
scripts Bengali, Devanagari, Gujarati, Gurmukhi, Kannada,
|
||||
Malayalam, Oriya, Tamil, Telugu, and Sinhala.
|
||||
</para>
|
||||
<para>
|
||||
The Indic shaping model was revised significantly in
|
||||
2005. To denote the change, a new set of <emphasis>script
|
||||
tags</emphasis> was assigned for Bengali, Devanagari,
|
||||
Gujarati, Gurmukhi, Kannada, Malayalam, Oriya, Tamil, and
|
||||
Telugu. For the sake of clarity, the term "Indic2" is
|
||||
sometimes used to refer to the current, revised shaping
|
||||
model.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
The <emphasis>Arabic</emphasis> shaping model supports
|
||||
Arabic, Mongolian, N'Ko, Syriac, and several other connected
|
||||
or cursive scripts.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
The <emphasis>Thai/Lao</emphasis> shaping model supports
|
||||
the Thai and Lao scripts.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
The <emphasis>Khmer</emphasis> shaping model supports the
|
||||
Khmer script.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
The <emphasis>Myanmar</emphasis> shaping model supports the
|
||||
Myanmar (or Burmese) script.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
The <emphasis>Tibetan</emphasis> shaping model supports the
|
||||
Tibetan script.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
The <emphasis>Hangul</emphasis> shaping model supports the
|
||||
Hangul script.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
The <emphasis>Hebrew</emphasis> shaping model supports the
|
||||
Hebrew script.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
The <emphasis>Universal Shaping Engine</emphasis> (USE)
|
||||
shaping model supports complex scripts not covered by one of
|
||||
the above, script-specific shaping models, including
|
||||
Javanese, Balinese, Buginese, Batak, Chakma, Lepcha, Modi,
|
||||
Phags-pa, Tagalog, Siddham, Sundanese, Tai Le, Tai Tham, Tai
|
||||
Viet, and many others.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
Text runs that do not fall under one of the above shaping
|
||||
models may still require processing by a shaping engine. Of
|
||||
particular note is <emphasis>Emoji</emphasis> shaping, which
|
||||
may involve variation-selector sequences and glyph
|
||||
substitution. Emoji shaping is handled by the default
|
||||
shaping model.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
</itemizedlist>
|
||||
|
||||
</section>
|
||||
|
||||
<section id="graphite-shaping">
|
||||
<title>Graphite shaping</title>
|
||||
<para>
|
||||
In contrast to OpenType shaping, Graphite shaping does not
|
||||
specify a predefined set of shaping models or a set of supported
|
||||
scripts.
|
||||
</para>
|
||||
<para>
|
||||
Instead, each Graphite font contains a complete set of rules that
|
||||
implement the required shaping model for the intended
|
||||
script. These rules include finite-state machines to match
|
||||
sequences of codepoints to the shaping operations to perform.
|
||||
</para>
|
||||
<para>
|
||||
Graphite shaping can perform the same shaping operations used in
|
||||
OpenType shaping, as well as other functions that have not been
|
||||
defined for OpenType shaping.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="aat-shaping">
|
||||
<title>AAT shaping</title>
|
||||
<para>
|
||||
In contrast to OpenType shaping, AAT shaping does not specify a
|
||||
predefined set of shaping models or a set of supported scripts.
|
||||
</para>
|
||||
<para>
|
||||
Instead, each AAT font includes a complete set of rules that
|
||||
implement the desired shaping model for the intended
|
||||
script. These rules include finite-state machines to match glyph
|
||||
sequences and the shaping operations to perform.
|
||||
</para>
|
||||
<para>
|
||||
Notably, AAT shaping rules are expressed for glyphs in the font,
|
||||
not for Unicode codepoints. AAT shaping can perform the same
|
||||
shaping operations used in OpenType shaping, as well as other
|
||||
functions that have not been defined for OpenType shaping.
|
||||
</para>
|
||||
</section>
|
||||
</chapter>
|
|
@ -1,115 +1,441 @@
|
|||
<?xml version="1.0"?>
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
|
||||
<!ENTITY % local.common.attrib "xmlns:xi CDATA #FIXED 'http://www.w3.org/2003/XInclude'">
|
||||
<!ENTITY version SYSTEM "version.xml">
|
||||
]>
|
||||
<chapter id="what-is-harfbuzz">
|
||||
<title>What is HarfBuzz?</title>
|
||||
<para>
|
||||
HarfBuzz is a <emphasis>text shaping engine</emphasis>. It solves
|
||||
the problem of selecting and positioning glyphs from a font given a
|
||||
Unicode string.
|
||||
HarfBuzz is a <emphasis>text-shaping engine</emphasis>. If you
|
||||
give HarfBuzz a font and a string containing a sequence of Unicode
|
||||
codepoints, HarfBuzz selects and positions the corresponding
|
||||
glyphs from the font, applying all of the necessary layout rules
|
||||
and font features. HarfBuzz then returns the string to you in the
|
||||
form that is correctly arranged for the language and writing
|
||||
system.
|
||||
</para>
|
||||
<section id="why-do-i-need-it">
|
||||
<title>Why do I need it?</title>
|
||||
<para>
|
||||
HarfBuzz can properly shape all of the world's major writing
|
||||
systems. It runs on all major operating systems and software
|
||||
platforms and it supports the modern font formats in use
|
||||
today.
|
||||
</para>
|
||||
<section id="what-is-text-shaping">
|
||||
<title>What is text shaping?</title>
|
||||
<para>
|
||||
Text shaping is an integral part of preparing text for display. It
|
||||
is a fairly low level operation; HarfBuzz is used directly by
|
||||
graphic rendering libraries such as Pango, and the layout engines
|
||||
in Firefox, LibreOffice and Chromium. Unless you are
|
||||
<emphasis>writing</emphasis> one of these layout engines yourself,
|
||||
you will probably not need to use HarfBuzz - normally higher level
|
||||
libraries will turn text into glyphs for you.
|
||||
Text shaping is the process of translating a string of character
|
||||
codes (such as Unicode codepoints) into a properly arranged
|
||||
sequence of glyphs that can be rendered onto a screen or into
|
||||
final output form for inclusion in a document.
|
||||
</para>
|
||||
<para>
|
||||
The shaping process is dependent on the input string, the active
|
||||
font, the script (or writing system) that the string is in, and
|
||||
the language that the string is in.
|
||||
</para>
|
||||
<para>
|
||||
Modern software systems generally only deal with strings in the
|
||||
Unicode encoding scheme (although legacy systems and documents may
|
||||
involve other encodings).
|
||||
</para>
|
||||
<para>
|
||||
There are several font formats that a program might
|
||||
encounter, each of which has a set of standard text-shaping
|
||||
rules.
|
||||
</para>
|
||||
<para>The dominant format is <ulink
|
||||
url="http://www.microsoft.com/typography/otspec/">OpenType</ulink>. The
|
||||
OpenType specification defines a series of <ulink url="https://github.com/n8willis/opentype-shaping-documents">shaping models</ulink> for
|
||||
various scripts from around the world. These shaping models depend on
|
||||
the font including certain features in its <literal>GSUB</literal>
|
||||
and <literal>GPOS</literal> tables.
|
||||
</para>
|
||||
<para>
|
||||
Alternatively, OpenType fonts can include shaping features for
|
||||
the <ulink url="https://graphite.sil.org/">Graphite</ulink> shaping model.
|
||||
</para>
|
||||
<para>
|
||||
TrueType fonts can also include OpenType shaping
|
||||
features. Alternatively, TrueType fonts can also include <ulink url="https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html">Apple
|
||||
Advanced Typography</ulink> (AAT) tables to implement shaping
|
||||
support. AAT fonts are generally only found on macOS and iOS systems.
|
||||
</para>
|
||||
<para>
|
||||
Text strings will usually be tagged with a script and language
|
||||
tag that provide the context needed to perform text shaping
|
||||
correctly. The necessary <ulink
|
||||
url="https://docs.microsoft.com/en-us/typography/opentype/spec/scripttags">Script</ulink>
|
||||
and <ulink
|
||||
url="https://docs.microsoft.com/en-us/typography/opentype/spec/languagetags">language</ulink>
|
||||
tags are defined by OpenType.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="why-do-i-need-a-shaping-engine">
|
||||
<title>Why do I need a shaping engine?</title>
|
||||
<para>
|
||||
Text shaping is an integral part of preparing text for
|
||||
display. Before a Unicode sequence can be rendered, the
|
||||
codepoints in the sequence must be mapped to the corresponding
|
||||
glyphs provided in the font, and those glyphs must be positioned
|
||||
correctly relative to each other. For many of the scripts
|
||||
supported in Unicode, these steps involve script-specific layout
|
||||
rules, including complex joining, reordering, and positioning
|
||||
behavior. Implementing these rules is the job of the shaping engine.
|
||||
</para>
|
||||
<para>
|
||||
Text shaping is a fairly low-level operation. HarfBuzz is
|
||||
used directly by text-handling libraries like <ulink
|
||||
url="https://www.pango.org/">Pango</ulink>, as well as by the layout
|
||||
engines in Firefox, LibreOffice, and Chromium. Unless you are
|
||||
<emphasis>writing</emphasis> one of these layout engines
|
||||
yourself, you will probably not need to use HarfBuzz: normally,
|
||||
a layout engine, toolkit, or other library will turn text into
|
||||
glyphs for you.
|
||||
</para>
|
||||
<para>
|
||||
However, if you <emphasis>are</emphasis> writing a layout engine
|
||||
or graphics library yourself, you will need to perform text
|
||||
shaping, and this is where HarfBuzz can help you. Here are some
|
||||
reasons why you need it:
|
||||
or graphics library yourself, then you will need to perform text
|
||||
shaping, and this is where HarfBuzz can help you.
|
||||
</para>
|
||||
<para>
|
||||
Here are some specific scenarios where a text-shaping engine
|
||||
like HarfBuzz helps you:
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
OpenType fonts contain a set of glyphs, indexed by glyph ID.
|
||||
The glyph ID within the font does not necessarily relate to a
|
||||
Unicode codepoint. For instance, some fonts have the letter
|
||||
"a" as glyph ID 1. To pull the right glyph out of
|
||||
the font in order to display it, you need to consult a table
|
||||
within the font (the "cmap" table) which maps
|
||||
Unicode codepoints to glyph IDs. Text shaping turns codepoints
|
||||
into glyph IDs.
|
||||
OpenType fonts contain a set of glyphs (that is, shapes
|
||||
to represent the letters, numbers, punctuation marks, and
|
||||
all other symbols), which are indexed by a <literal>glyph ID</literal>.
|
||||
</para>
|
||||
<para>
|
||||
A particular glyph ID within the font does not necessarily
|
||||
correlate to a predictable Unicode codepoint. For instance,
|
||||
some fonts have the letter "a" as glyph ID 1, but
|
||||
many others do not. In order to retrieve the right glyph
|
||||
from the font to display "a", you need to consult
|
||||
the table inside the font (the <literal>cmap</literal>
|
||||
table) that maps Unicode codepoints to glyph IDs. In other
|
||||
words, <emphasis>text shaping turns codepoints into glyph
|
||||
IDs</emphasis>.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Many OpenType fonts contain ligatures: combinations of
|
||||
characters which are rendered together. For instance, it's
|
||||
common for the <literal>fi</literal> combination to appear in
|
||||
print as the single ligature "fi". Whether you should
|
||||
render text as <literal>fi</literal> or "fi" does not
|
||||
depend on the input text, but on the capabilities of the font
|
||||
and the level of ligature application you wish to perform.
|
||||
Text shaping involves querying the font's ligature tables and
|
||||
determining what substitutions should be made.
|
||||
characters that are rendered as a single unit. For instance,
|
||||
it is common for the <literal>fi</literal> letter
|
||||
combination to appear in print as the single ligature glyph
|
||||
"fi".
|
||||
</para>
|
||||
<para>
|
||||
Whether you should render an "f, i" sequence
|
||||
as <literal>fi</literal> or as "fi" does not
|
||||
depend on the input text. Instead, it depends on the whether
|
||||
or not the font includes an "fi" glyph and on the
|
||||
level of ligature application you wish to perform. The font
|
||||
and the amount of ligature application used are under your
|
||||
control. In other words, <emphasis>text shaping involves
|
||||
querying the font's ligature tables and determining what
|
||||
substitutions should be made</emphasis>.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
While ligatures like "fi" are typographic
|
||||
refinements, some languages <emphasis>require</emphasis> such
|
||||
While ligatures like "fi" are optional typographic
|
||||
refinements, some languages <emphasis>require</emphasis> certain
|
||||
substitutions to be made in order to display text correctly.
|
||||
In Tamil, when the letter "TTA" (ட) letter is
|
||||
followed by "U" (உ), the combination should appear
|
||||
as the single glyph "டு". The sequence of Unicode
|
||||
characters "டஉ" needs to be rendered as a single
|
||||
glyph from the font - text shaping chooses the correct glyph
|
||||
from the sequence of characters provided.
|
||||
</para>
|
||||
<para>
|
||||
For example, in Tamil, when the letter "TTA" (ட)
|
||||
letter is followed by "U" (உ), the pair
|
||||
must be replaced by the single glyph "டு". The
|
||||
sequence of Unicode characters "டஉ" needs to be
|
||||
substituted with a single "டு" glyph from the
|
||||
font.
|
||||
</para>
|
||||
<para>
|
||||
But "டு" does not have a Unicode codepoint. To
|
||||
find this glyph, you need to consult the table inside
|
||||
the font (the <literal>GSUB</literal> table) that contains
|
||||
substitution information. In other words, <emphasis>text shaping
|
||||
chooses the correct glyph for a sequence of characters
|
||||
provided</emphasis>.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Similarly, each Arabic character has four different variants:
|
||||
within a font, there will be glyphs for the initial, medial,
|
||||
final, and isolated forms of each letter. Unicode only encodes
|
||||
one codepoint per character, and so a Unicode string will not
|
||||
tell you which glyph to use. Text shaping chooses the correct
|
||||
form of the letter and returns the correct glyph from the font
|
||||
that you need to render.
|
||||
Similarly, each Arabic character has four different variants
|
||||
corresponding to the different positions it might appear in
|
||||
within a sequence. Inside a font, there will be separate
|
||||
glyphs for the initial, medial, final, and isolated forms of
|
||||
each letter, each at a different glyph ID.
|
||||
</para>
|
||||
<para>
|
||||
Unicode only assigns one codepoint per character, so a
|
||||
Unicode string will not tell you which glyph variant to use
|
||||
for each character. To decide, you need to analyze the whole
|
||||
string and determine the appropriate glyph for each character
|
||||
based on its position. In other words, <emphasis>text
|
||||
shaping chooses the correct form of the letter by its
|
||||
position and returns the correct glyph from the font</emphasis>.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Other languages have marks and accents which need to be
|
||||
rendered in certain positions around a base character. For
|
||||
instance, the Moldovan language has the Cyrillic letter
|
||||
"zhe" (ж) with a breve accent, like so: ӂ. Some
|
||||
fonts will contain this character as an individual glyph,
|
||||
whereas other fonts will not contain a zhe-with-breve glyph
|
||||
but expect the rendering engine to form the character by
|
||||
overlaying the two glyphs ж and ˘. Where you should draw the
|
||||
combining breve depends on the height of the preceding glyph.
|
||||
Again, for Arabic, the correct positioning of vowel marks
|
||||
depends on the height of the character on which you are
|
||||
placing the mark. Text shaping tells you whether you have a
|
||||
precomposed glyph within your font or if you need to compose a
|
||||
glyph yourself out of combining marks, and if so, where to
|
||||
position those marks.
|
||||
Other languages involve marks and accents that need to be
|
||||
rendered in specific positions relative a base character. For
|
||||
instance, the Moldovan language includes the Cyrillic letter
|
||||
"zhe" (ж) with a breve accent, like so: "ӂ".
|
||||
</para>
|
||||
<para>
|
||||
Some fonts will provide this character as a single
|
||||
zhe-with-breve glyph, but other fonts will not and, instead,
|
||||
will expect the rendering engine to form the character by
|
||||
superimposing the separate "ж" and "˘"
|
||||
glyphs.
|
||||
</para>
|
||||
<para>
|
||||
But exactly where you should draw the breve depends on the
|
||||
height and width of the preceding zhe glyph. To find the
|
||||
right position, you need to consult the table inside
|
||||
the font (the <literal>GPOS</literal> table) that contains
|
||||
positioning information.
|
||||
In other words, <emphasis>text shaping tells you whether you
|
||||
have a precomposed glyph within your font or if you need to
|
||||
compose a glyph yourself out of combining marks—and,
|
||||
if so, where to position those marks.</emphasis>
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>
|
||||
If this is something that you need to do, then you need a text
|
||||
shaping engine: you could use Uniscribe if you are using Windows;
|
||||
you could use CoreText on OS X; or you could use HarfBuzz. In the
|
||||
rest of this manual, we are going to assume that you are the
|
||||
implementor of a text layout engine.
|
||||
If tasks like these are something that you need to do, then you
|
||||
need a text shaping engine. You could use Uniscribe if you are
|
||||
writing Windows software; you could use CoreText on macOS; or
|
||||
you could use HarfBuzz.
|
||||
</para>
|
||||
<note>
|
||||
<para>
|
||||
In the rest of this manual, the text will assume that the reader
|
||||
is that implementor of a text-layout engine.
|
||||
</para>
|
||||
</note>
|
||||
</section>
|
||||
|
||||
|
||||
<section>
|
||||
<title>What does HarfBuzz do?</title>
|
||||
<para>
|
||||
HarfBuzz provides text shaping through a cross-platform
|
||||
C API that accepts sequences of Unicode codepoints as input. Currently,
|
||||
the following OpenType shaping models are supported:
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
Indic (covering Devanagari, Bengali, Gujarati,
|
||||
Gurmukhi, Kannada, Malayalam, Oriya, Tamil, Telugu, and
|
||||
Sinhala)
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Arabic (covering Arabic, N'Ko, Syriac, and Mongolian)
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Thai and Lao
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Khmer
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Myanmar
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
Tibetan
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
Hangul
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
Hebrew
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
The Universal Shaping Engine or <emphasis>USE</emphasis>
|
||||
(covering complex scripts not covered by the above shaping
|
||||
models)
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
A default shaping model for non-complex scripts
|
||||
(covering Latin, Cyrillic, Greek, Armenian, Georgian, Tifinagh,
|
||||
and many others)
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Emoji (including emoji modifier sequences, flag sequences,
|
||||
and ZWJ sequences)
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>
|
||||
In addition to OpenType shaping, HarfBuzz supports the latest
|
||||
version of Graphite shaping (the "Graphite 2" model) and AAT
|
||||
shaping.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
HarfBuzz can read and understand TrueType fonts (.ttf), TrueType
|
||||
collections (.ttc), and OpenType fonts (.otf, including those
|
||||
fonts that contain TrueType-style outlines and those that
|
||||
contain PostScript CFF or CFF2 outlines).
|
||||
</para>
|
||||
|
||||
<para>
|
||||
HarfBuzz is designed and tested to run on top of the FreeType
|
||||
font renderer. It can run on Linux, Android, Windows, macOS, and
|
||||
iOS systems.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
In addition to its core shaping functionality, HarfBuzz provides
|
||||
functions for accessing other font features, including optional
|
||||
GSUB and GPOS OpenType features, as well as
|
||||
all color-font formats (<literal>CBDT</literal>,
|
||||
<literal>sbix</literal>, <literal>COLR/CPAL</literal>, and
|
||||
<literal>SVG-OT</literal>) and OpenType variable fonts. HarfBuzz
|
||||
also includes a font-subsetting feature. HarfBuzz can perform
|
||||
some low-level math-shaping operations, although it does not
|
||||
currently perform full shaping for mathematical typesetting.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
A suite of command-line utilities is also provided in the
|
||||
source-code tree, designed to help users test and debug
|
||||
HarfBuzz's features on real-world fonts and input.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="what-harfbuzz-doesnt-do">
|
||||
<title>What HarfBuzz doesn't do</title>
|
||||
<para>
|
||||
HarfBuzz will take a Unicode string, shape it, and give you the
|
||||
information required to lay it out correctly on a single
|
||||
horizontal (or vertical) line using the font provided. That is the
|
||||
extent of HarfBuzz's responsibility.
|
||||
</para>
|
||||
<para>
|
||||
It is important to note that if you are implementing a complete
|
||||
text-layout engine you may have other responsibilities that
|
||||
HarfBuzz will <emphasis>not</emphasis> help you with. For example:
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
HarfBuzz won't help you with bidirectionality. If you want to
|
||||
lay out text that includes a mix of Hebrew and English, you
|
||||
will need to ensure that each buffer provided to HarfBuzz
|
||||
has all of its characters in the same order and that the
|
||||
directionality of the buffer is set correctly. This may mean
|
||||
segmenting the text before it is placed into HarfBuzz buffers. In
|
||||
other words, the user will hit the keys in the following
|
||||
sequence:
|
||||
</para>
|
||||
<programlisting>
|
||||
A B C [space] ג ב א [space] D E F
|
||||
</programlisting>
|
||||
<para>
|
||||
but will expect to see in the output:
|
||||
</para>
|
||||
<programlisting>
|
||||
ABC אבג DEF
|
||||
</programlisting>
|
||||
<para>
|
||||
This reordering is called <emphasis>bidi processing</emphasis>
|
||||
("bidi" is short for bidirectional), and there's an
|
||||
algorithm as an annex to the Unicode Standard which tells you how
|
||||
to process a string of mixed directionality.
|
||||
Before sending your string to HarfBuzz, you may need to apply the
|
||||
bidi algorithm to it. Libraries such as <ulink
|
||||
url="http://icu-project.org/">ICU</ulink> and <ulink
|
||||
url="http://fribidi.org/">fribidi</ulink> can do this for you.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
HarfBuzz won't help you with text that contains different font
|
||||
properties. For instance, if you have the string "a
|
||||
<emphasis>huge</emphasis> breakfast", and you expect
|
||||
"huge" to be italic, then you will need to send three
|
||||
strings to HarfBuzz: <literal>a</literal>, in your Roman font;
|
||||
<literal>huge</literal> using your italic font; and
|
||||
<literal>breakfast</literal> using your Roman font again.
|
||||
</para>
|
||||
<para>
|
||||
Similarly, if you change the font, font size, script,
|
||||
language, or direction within your string, then you will
|
||||
need to shape each run independently and output them
|
||||
independently. HarfBuzz expects to shape a run of characters
|
||||
that all share the same properties.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
HarfBuzz won't help you with line breaking, hyphenation, or
|
||||
justification. As mentioned above, HarfBuzz lays out the string
|
||||
along a <emphasis>single line</emphasis> of, notionally,
|
||||
infinite length. If you want to find out where the potential
|
||||
word, sentence and line break points are in your text, you
|
||||
could use the ICU library's break iterator functions.
|
||||
</para>
|
||||
<para>
|
||||
HarfBuzz can tell you how wide a shaped piece of text is, which is
|
||||
useful input to a justification algorithm, but it knows nothing
|
||||
about paragraphs, lines or line lengths. Nor will it adjust the
|
||||
space between words to fit them proportionally into a line.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>
|
||||
As a layout-engine implementor, HarfBuzz will help you with the
|
||||
interface between your text and your font, and that's something
|
||||
that you'll need—what you then do with the glyphs that your font
|
||||
returns is up to you.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="why-is-it-called-harfbuzz">
|
||||
<title>Why is it called HarfBuzz?</title>
|
||||
<para>
|
||||
HarfBuzz began its life as text shaping code within the FreeType
|
||||
project, (and you will see references to the FreeType authors
|
||||
within the source code copyright declarations) but was then
|
||||
abstracted out to its own project. This project is maintained by
|
||||
Behdad Esfahbod, and named HarfBuzz. Originally, it was a shaping
|
||||
engine for OpenType fonts - "HarfBuzz" is the Persian
|
||||
for "open type".
|
||||
HarfBuzz began its life as text-shaping code within the FreeType
|
||||
project (and you will see references to the FreeType authors
|
||||
within the source code copyright declarations), but was then
|
||||
extracted out to its own project. This project is maintained by
|
||||
Behdad Esfahbod, who named it HarfBuzz. Originally, it was a
|
||||
shaping engine for OpenType fonts—"HarfBuzz" is
|
||||
the Persian for "open type".
|
||||
</para>
|
||||
</section>
|
||||
</chapter>
|
||||
</chapter>
|
||||
|
|
|
@ -170,7 +170,6 @@ pkgconfig_DATA += harfbuzz-subset.pc
|
|||
EXTRA_DIST += harfbuzz-subset.pc.in
|
||||
|
||||
FUZZING_CPPFLAGS = \
|
||||
-DHB_NDEBUG \
|
||||
-DHB_MAX_NESTING_LEVEL=3 \
|
||||
-DHB_SANITIZE_MAX_EDITS=3 \
|
||||
-DHB_SANITIZE_MAX_OPS_FACTOR=3 \
|
||||
|
@ -269,7 +268,7 @@ EXTRA_DIST += \
|
|||
CLEANFILES += $(pkgconfig_DATA)
|
||||
|
||||
|
||||
DEF_FILES = harfbuzz.def harfbuzz-subset.def harfbuzz-icu.def harfbuzz-deprecated.def
|
||||
DEF_FILES = harfbuzz.def harfbuzz-subset.def harfbuzz-icu.def harfbuzz-deprecated-symbols.txt
|
||||
if HAVE_GOBJECT
|
||||
DEF_FILES += harfbuzz-gobject.def
|
||||
endif
|
||||
|
@ -283,8 +282,8 @@ 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 "$@" $^
|
||||
harfbuzz-deprecated-symbols.txt: $(srcdir)/hb-deprecated.h
|
||||
$(AM_V_GEN) PLAIN_LIST=1 $(srcdir)/gen-def.py "$@" $^
|
||||
|
||||
|
||||
GENERATORS = \
|
||||
|
@ -348,6 +347,7 @@ noinst_PROGRAMS = \
|
|||
main \
|
||||
test \
|
||||
test-buffer-serialize \
|
||||
test-name-table \
|
||||
test-size-params \
|
||||
test-would-substitute \
|
||||
$(NULL)
|
||||
|
@ -361,17 +361,30 @@ test_SOURCES = test.cc
|
|||
test_CPPFLAGS = $(HBCFLAGS) $(FREETYPE_CFLAGS)
|
||||
test_LDADD = libharfbuzz.la $(HBLIBS) $(FREETYPE_LIBS)
|
||||
|
||||
test_would_substitute_SOURCES = test-would-substitute.cc
|
||||
test_would_substitute_CPPFLAGS = $(HBCFLAGS) $(FREETYPE_CFLAGS)
|
||||
test_would_substitute_LDADD = libharfbuzz.la $(HBLIBS) $(FREETYPE_LIBS)
|
||||
test_buffer_serialize_SOURCES = test-buffer-serialize.cc
|
||||
test_buffer_serialize_CPPFLAGS = $(HBCFLAGS)
|
||||
test_buffer_serialize_LDADD = libharfbuzz.la $(HBLIBS)
|
||||
|
||||
test_name_table_SOURCES = test-name-table.cc
|
||||
test_name_table_CPPFLAGS = $(HBCFLAGS)
|
||||
test_name_table_LDADD = libharfbuzz.la $(HBLIBS)
|
||||
|
||||
test_size_params_SOURCES = test-size-params.cc
|
||||
test_size_params_CPPFLAGS = $(HBCFLAGS)
|
||||
test_size_params_LDADD = libharfbuzz.la $(HBLIBS)
|
||||
|
||||
test_buffer_serialize_SOURCES = test-buffer-serialize.cc
|
||||
test_buffer_serialize_CPPFLAGS = $(HBCFLAGS)
|
||||
test_buffer_serialize_LDADD = libharfbuzz.la $(HBLIBS)
|
||||
test_would_substitute_SOURCES = test-would-substitute.cc
|
||||
test_would_substitute_CPPFLAGS = $(HBCFLAGS) $(FREETYPE_CFLAGS)
|
||||
test_would_substitute_LDADD = libharfbuzz.la $(HBLIBS) $(FREETYPE_LIBS)
|
||||
|
||||
if HAVE_FREETYPE
|
||||
if HAVE_CAIRO_FT
|
||||
noinst_PROGRAMS += test-ot-color
|
||||
test_ot_color_SOURCES = test-ot-color.cc
|
||||
test_ot_color_CPPFLAGS = $(HBCFLAGS) $(FREETYPE_CFLAGS) $(CAIRO_FT_CFLAGS)
|
||||
test_ot_color_LDADD = libharfbuzz.la $(HBLIBS) $(FREETYPE_LIBS) $(CAIRO_LIBS) $(CAIRO_FT_LIBS)
|
||||
endif # HAVE_CAIRO_FT
|
||||
endif # HAVE_FREETYPE
|
||||
|
||||
dist_check_SCRIPTS = \
|
||||
check-c-linkage-decls.sh \
|
||||
|
@ -408,15 +421,6 @@ dump_use_data_SOURCES = dump-use-data.cc hb-ot-shape-complex-use-table.cc
|
|||
dump_use_data_CPPFLAGS = $(HBCFLAGS)
|
||||
dump_use_data_LDADD = libharfbuzz.la $(HBLIBS)
|
||||
|
||||
if HAVE_FREETYPE
|
||||
if HAVE_CAIRO_FT
|
||||
check_PROGRAMS += dump-emoji
|
||||
dump_emoji_SOURCES = dump-emoji.cc
|
||||
dump_emoji_CPPFLAGS = $(HBCFLAGS) $(FREETYPE_CFLAGS) $(CAIRO_FT_CFLAGS)
|
||||
dump_emoji_LDADD = libharfbuzz.la $(HBLIBS) $(FREETYPE_LIBS) $(CAIRO_LIBS) $(CAIRO_FT_LIBS)
|
||||
endif # HAVE_CAIRO_FT
|
||||
endif # HAVE_FREETYPE
|
||||
|
||||
check_PROGRAMS += test-ot-tag test-unicode-ranges
|
||||
TESTS += test-ot-tag test-unicode-ranges
|
||||
|
||||
|
|
|
@ -38,7 +38,10 @@ HB_BASE_sources = \
|
|||
hb-ot-hmtx-table.hh \
|
||||
hb-ot-kern-table.hh \
|
||||
hb-ot-maxp-table.hh \
|
||||
hb-ot-name-language.cc \
|
||||
hb-ot-name-language.hh \
|
||||
hb-ot-name-table.hh \
|
||||
hb-ot-name.cc \
|
||||
hb-ot-os2-table.hh \
|
||||
hb-ot-os2-unicode-ranges.hh \
|
||||
hb-ot-post-macroman.hh \
|
||||
|
@ -192,7 +195,6 @@ HB_OT_headers = \
|
|||
hb-ot-math.h \
|
||||
hb-ot-name.h \
|
||||
hb-ot-shape.h \
|
||||
hb-ot-tag.h \
|
||||
hb-ot-var.h \
|
||||
$(NULL)
|
||||
|
||||
|
|
|
@ -15,11 +15,10 @@ for h in header_paths:
|
|||
if h.endswith (".h"):
|
||||
with io.open (h, encoding='utf-8') as f: headers_content.append (f.read ())
|
||||
|
||||
result = """EXPORTS
|
||||
symbols = "\n".join (sorted (re.findall (r"^hb_\w+(?= \()", "\n".join (headers_content), re.M)))
|
||||
|
||||
result = symbols if os.environ.get('PLAIN_LIST', '') else """EXPORTS
|
||||
%s
|
||||
LIBRARY lib%s-0.dll""" % (
|
||||
"\n".join (sorted (re.findall (r"^hb_\w+(?= \()", "\n".join (headers_content), re.M))),
|
||||
output_file.replace ('.def', '')
|
||||
)
|
||||
LIBRARY lib%s-0.dll""" % (symbols, output_file.replace ('.def', ''))
|
||||
|
||||
with open (output_file, "w") as f: f.write (result)
|
||||
|
|
|
@ -176,9 +176,9 @@ print ('}')
|
|||
print ()
|
||||
|
||||
print ('void')
|
||||
print ('_hb_preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan,')
|
||||
print ('_hb_preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan HB_UNUSED,')
|
||||
print ('\t\t\t\t hb_buffer_t *buffer,')
|
||||
print ('\t\t\t\t hb_font_t *font)')
|
||||
print ('\t\t\t\t hb_font_t *font HB_UNUSED)')
|
||||
print ('{')
|
||||
print (' /* UGLY UGLY UGLY business of adding dotted-circle in the middle of')
|
||||
print (' * vowel-sequences that look like another vowel. Data for each script')
|
||||
|
|
|
@ -362,6 +362,7 @@ template <>
|
|||
}
|
||||
namespace AAT {
|
||||
|
||||
enum { DELETED_GLYPH = 0xFFFF };
|
||||
|
||||
/*
|
||||
* Extended State Table
|
||||
|
@ -376,7 +377,10 @@ struct Entry
|
|||
/* Note, we don't recurse-sanitize data because we don't access it.
|
||||
* That said, in our DEFINE_SIZE_STATIC we access T::static_size,
|
||||
* which ensures that data has a simple sanitize(). To be determined
|
||||
* if I need to remove that as well. */
|
||||
* if I need to remove that as well.
|
||||
*
|
||||
* XXX Because we are a template, our DEFINE_SIZE_STATIC assertion
|
||||
* wouldn't be checked. */
|
||||
return_trace (c->check_struct (this));
|
||||
}
|
||||
|
||||
|
@ -393,7 +397,7 @@ struct Entry
|
|||
template <>
|
||||
struct Entry<void>
|
||||
{
|
||||
inline bool sanitize (hb_sanitize_context_t *c, unsigned int count) const
|
||||
inline bool sanitize (hb_sanitize_context_t *c, unsigned int count /*XXX Unused?*/) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (c->check_struct (this));
|
||||
|
@ -406,9 +410,13 @@ struct Entry<void>
|
|||
DEFINE_SIZE_STATIC (4);
|
||||
};
|
||||
|
||||
template <typename Extra>
|
||||
template <typename Types, typename Extra>
|
||||
struct StateTable
|
||||
{
|
||||
typedef typename Types::HBUINT HBUINT;
|
||||
typedef typename Types::HBUSHORT HBUSHORT;
|
||||
typedef typename Types::ClassType ClassType;
|
||||
|
||||
enum State
|
||||
{
|
||||
STATE_START_OF_TEXT = 0,
|
||||
|
@ -422,10 +430,13 @@ struct StateTable
|
|||
CLASS_END_OF_LINE = 3,
|
||||
};
|
||||
|
||||
inline unsigned int new_state (unsigned int newState) const
|
||||
{ return Types::extended ? newState : (newState - stateArrayTable) / nClasses; }
|
||||
|
||||
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 ? (unsigned) *v : (unsigned) CLASS_OUT_OF_BOUNDS;
|
||||
if (unlikely (glyph_id == DELETED_GLYPH)) return CLASS_DELETED_GLYPH;
|
||||
return (this+classTable).get_class (glyph_id, num_glyphs);
|
||||
}
|
||||
|
||||
inline const Entry<Extra> *get_entries () const
|
||||
|
@ -437,7 +448,7 @@ struct StateTable
|
|||
{
|
||||
if (unlikely (klass >= nClasses)) return nullptr;
|
||||
|
||||
const HBUINT16 *states = (this+stateArrayTable).arrayZ;
|
||||
const HBUSHORT *states = (this+stateArrayTable).arrayZ;
|
||||
const Entry<Extra> *entries = (this+entryTable).arrayZ;
|
||||
|
||||
unsigned int entry = states[state * nClasses + klass];
|
||||
|
@ -452,7 +463,7 @@ struct StateTable
|
|||
if (unlikely (!(c->check_struct (this) &&
|
||||
classTable.sanitize (c, this)))) return_trace (false);
|
||||
|
||||
const HBUINT16 *states = (this+stateArrayTable).arrayZ;
|
||||
const HBUSHORT *states = (this+stateArrayTable).arrayZ;
|
||||
const Entry<Extra> *entries = (this+entryTable).arrayZ;
|
||||
|
||||
unsigned int num_classes = nClasses;
|
||||
|
@ -474,8 +485,8 @@ struct StateTable
|
|||
if ((c->max_ops -= num_states - state) < 0)
|
||||
return_trace (false);
|
||||
{ /* Sweep new states. */
|
||||
const HBUINT16 *stop = &states[num_states * num_classes];
|
||||
for (const HBUINT16 *p = &states[state * num_classes]; p < stop; p++)
|
||||
const HBUSHORT *stop = &states[num_states * num_classes];
|
||||
for (const HBUSHORT *p = &states[state * num_classes]; p < stop; p++)
|
||||
num_entries = MAX<unsigned int> (num_entries, *p + 1);
|
||||
state = num_states;
|
||||
}
|
||||
|
@ -487,7 +498,10 @@ struct StateTable
|
|||
{ /* Sweep new entries. */
|
||||
const Entry<Extra> *stop = &entries[num_entries];
|
||||
for (const Entry<Extra> *p = &entries[entry]; p < stop; p++)
|
||||
num_states = MAX<unsigned int> (num_states, p->newState + 1);
|
||||
{
|
||||
unsigned int newState = new_state (p->newState);
|
||||
num_states = MAX<unsigned int> (num_states, newState + 1);
|
||||
}
|
||||
entry = num_entries;
|
||||
}
|
||||
}
|
||||
|
@ -499,23 +513,101 @@ struct StateTable
|
|||
}
|
||||
|
||||
protected:
|
||||
HBUINT32 nClasses; /* Number of classes, which is the number of indices
|
||||
HBUINT nClasses; /* Number of classes, which is the number of indices
|
||||
* in a single line in the state array. */
|
||||
LOffsetTo<Lookup<HBUINT16>, false>
|
||||
OffsetTo<ClassType, HBUINT, false>
|
||||
classTable; /* Offset to the class table. */
|
||||
LOffsetTo<UnsizedArrayOf<HBUINT16>, false>
|
||||
OffsetTo<UnsizedArrayOf<HBUSHORT>, HBUINT, false>
|
||||
stateArrayTable;/* Offset to the state array. */
|
||||
LOffsetTo<UnsizedArrayOf<Entry<Extra> >, false>
|
||||
OffsetTo<UnsizedArrayOf<Entry<Extra> >, HBUINT, false>
|
||||
entryTable; /* Offset to the entry array. */
|
||||
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (16);
|
||||
DEFINE_SIZE_STATIC (4 * sizeof (HBUINT));
|
||||
};
|
||||
|
||||
template <typename EntryData>
|
||||
struct ClassTable
|
||||
{
|
||||
inline unsigned int get_class (hb_codepoint_t glyph_id) const
|
||||
{
|
||||
return firstGlyph <= glyph_id && glyph_id - firstGlyph < glyphCount ? classArrayZ[glyph_id - firstGlyph] : 1;
|
||||
}
|
||||
inline bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (c->check_struct (this) && classArrayZ.sanitize (c, glyphCount));
|
||||
}
|
||||
protected:
|
||||
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>
|
||||
classArrayZ; /* The class codes (indexed by glyph index minus
|
||||
* firstGlyph). */
|
||||
public:
|
||||
DEFINE_SIZE_ARRAY (4, classArrayZ);
|
||||
};
|
||||
|
||||
struct MortTypes
|
||||
{
|
||||
static const bool extended = false;
|
||||
typedef HBUINT16 HBUINT;
|
||||
typedef HBUINT8 HBUSHORT;
|
||||
struct ClassType : ClassTable
|
||||
{
|
||||
inline unsigned int get_class (hb_codepoint_t glyph_id, unsigned int num_glyphs HB_UNUSED) const
|
||||
{
|
||||
return ClassTable::get_class (glyph_id);
|
||||
}
|
||||
};
|
||||
template <typename T>
|
||||
static inline unsigned int offsetToIndex (unsigned int offset,
|
||||
const void *base,
|
||||
const T *array)
|
||||
{
|
||||
return (offset - ((const char *) array - (const char *) base)) / sizeof (T);
|
||||
}
|
||||
template <typename T>
|
||||
static inline unsigned int wordOffsetToIndex (unsigned int offset,
|
||||
const void *base,
|
||||
const T *array)
|
||||
{
|
||||
return offsetToIndex (2 * offset, base, array);
|
||||
}
|
||||
};
|
||||
struct MorxTypes
|
||||
{
|
||||
static const bool extended = true;
|
||||
typedef HBUINT32 HBUINT;
|
||||
typedef HBUINT16 HBUSHORT;
|
||||
struct ClassType : Lookup<HBUINT16>
|
||||
{
|
||||
inline unsigned int get_class (hb_codepoint_t glyph_id, unsigned int num_glyphs) const
|
||||
{
|
||||
const HBUINT16 *v = get_value (glyph_id, num_glyphs);
|
||||
return v ? *v : 1;
|
||||
}
|
||||
};
|
||||
template <typename T>
|
||||
static inline unsigned int offsetToIndex (unsigned int offset,
|
||||
const void *base,
|
||||
const T *array)
|
||||
{
|
||||
return offset;
|
||||
}
|
||||
template <typename T>
|
||||
static inline unsigned int wordOffsetToIndex (unsigned int offset,
|
||||
const void *base,
|
||||
const T *array)
|
||||
{
|
||||
return offset;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Types, typename EntryData>
|
||||
struct StateTableDriver
|
||||
{
|
||||
inline StateTableDriver (const StateTable<EntryData> &machine_,
|
||||
inline StateTableDriver (const StateTable<Types, EntryData> &machine_,
|
||||
hb_buffer_t *buffer_,
|
||||
hb_face_t *face_) :
|
||||
machine (machine_),
|
||||
|
@ -528,13 +620,13 @@ struct StateTableDriver
|
|||
if (!c->in_place)
|
||||
buffer->clear_output ();
|
||||
|
||||
unsigned int state = StateTable<EntryData>::STATE_START_OF_TEXT;
|
||||
unsigned int state = StateTable<Types, EntryData>::STATE_START_OF_TEXT;
|
||||
bool last_was_dont_advance = false;
|
||||
for (buffer->idx = 0;;)
|
||||
for (buffer->idx = 0; buffer->successful;)
|
||||
{
|
||||
unsigned int klass = buffer->idx < buffer->len ?
|
||||
machine.get_class (buffer->info[buffer->idx].codepoint, num_glyphs) :
|
||||
(unsigned) StateTable<EntryData>::CLASS_END_OF_TEXT;
|
||||
(unsigned) StateTable<Types, EntryData>::CLASS_END_OF_TEXT;
|
||||
const Entry<EntryData> *entry = machine.get_entryZ (state, klass);
|
||||
if (unlikely (!entry))
|
||||
break;
|
||||
|
@ -548,7 +640,7 @@ struct StateTableDriver
|
|||
/* 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 == StateTable<EntryData>::STATE_START_OF_TEXT &&
|
||||
!(entry->newState == StateTable<Types, EntryData>::STATE_START_OF_TEXT &&
|
||||
entry->flags == context_t::DontAdvance))
|
||||
buffer->unsafe_to_break_from_outbuffer (buffer->backtrack_len () - 1, buffer->idx + 1);
|
||||
}
|
||||
|
@ -562,19 +654,17 @@ struct StateTableDriver
|
|||
}
|
||||
|
||||
if (unlikely (!c->transition (this, entry)))
|
||||
break;
|
||||
|
||||
if (unlikely (!buffer->successful)) return;
|
||||
break;
|
||||
|
||||
last_was_dont_advance = (entry->flags & context_t::DontAdvance) && buffer->max_ops-- > 0;
|
||||
|
||||
state = entry->newState;
|
||||
state = machine.new_state (entry->newState);
|
||||
|
||||
if (buffer->idx == buffer->len)
|
||||
break;
|
||||
break;
|
||||
|
||||
if (!last_was_dont_advance)
|
||||
buffer->next_glyph ();
|
||||
buffer->next_glyph ();
|
||||
}
|
||||
|
||||
if (!c->in_place)
|
||||
|
@ -587,7 +677,7 @@ struct StateTableDriver
|
|||
}
|
||||
|
||||
public:
|
||||
const StateTable<EntryData> &machine;
|
||||
const StateTable<Types, EntryData> &machine;
|
||||
hb_buffer_t *buffer;
|
||||
unsigned int num_glyphs;
|
||||
};
|
||||
|
|
|
@ -163,12 +163,12 @@ struct KerxSubTableFormat1
|
|||
kernAction (&table->machine + table->kernAction),
|
||||
depth (0) {}
|
||||
|
||||
inline bool is_actionable (StateTableDriver<EntryData> *driver,
|
||||
inline bool is_actionable (StateTableDriver<MorxTypes, EntryData> *driver HB_UNUSED,
|
||||
const Entry<EntryData> *entry)
|
||||
{
|
||||
return entry->data.kernActionIndex != 0xFFFF;
|
||||
}
|
||||
inline bool transition (StateTableDriver<EntryData> *driver,
|
||||
inline bool transition (StateTableDriver<MorxTypes, EntryData> *driver,
|
||||
const Entry<EntryData> *entry)
|
||||
{
|
||||
hb_buffer_t *buffer = driver->buffer;
|
||||
|
@ -239,7 +239,7 @@ struct KerxSubTableFormat1
|
|||
|
||||
driver_context_t dc (this, c);
|
||||
|
||||
StateTableDriver<EntryData> driver (machine, c->buffer, c->font->face);
|
||||
StateTableDriver<MorxTypes, EntryData> driver (machine, c->buffer, c->font->face);
|
||||
driver.drive (&dc);
|
||||
|
||||
return_trace (true);
|
||||
|
@ -255,7 +255,7 @@ struct KerxSubTableFormat1
|
|||
|
||||
protected:
|
||||
KerxSubTableHeader header;
|
||||
StateTable<EntryData> machine;
|
||||
StateTable<MorxTypes, EntryData> machine;
|
||||
LOffsetTo<UnsizedArrayOf<FWORD>, false> kernAction;
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (32);
|
||||
|
@ -365,12 +365,12 @@ struct KerxSubTableFormat4
|
|||
mark_set (false),
|
||||
mark (0) {}
|
||||
|
||||
inline bool is_actionable (StateTableDriver<EntryData> *driver,
|
||||
inline bool is_actionable (StateTableDriver<MorxTypes, EntryData> *driver HB_UNUSED,
|
||||
const Entry<EntryData> *entry)
|
||||
{
|
||||
return entry->data.ankrActionIndex != 0xFFFF;
|
||||
}
|
||||
inline bool transition (StateTableDriver<EntryData> *driver,
|
||||
inline bool transition (StateTableDriver<MorxTypes, EntryData> *driver,
|
||||
const Entry<EntryData> *entry)
|
||||
{
|
||||
hb_buffer_t *buffer = driver->buffer;
|
||||
|
@ -473,7 +473,7 @@ struct KerxSubTableFormat4
|
|||
|
||||
driver_context_t dc (this, c);
|
||||
|
||||
StateTableDriver<EntryData> driver (machine, c->buffer, c->font->face);
|
||||
StateTableDriver<MorxTypes, EntryData> driver (machine, c->buffer, c->font->face);
|
||||
driver.drive (&dc);
|
||||
|
||||
return_trace (true);
|
||||
|
@ -489,7 +489,8 @@ struct KerxSubTableFormat4
|
|||
|
||||
protected:
|
||||
KerxSubTableHeader header;
|
||||
StateTable<EntryData> machine;
|
||||
StateTable<MorxTypes, EntryData>
|
||||
machine;
|
||||
HBUINT32 flags;
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (32);
|
||||
|
|
|
@ -35,17 +35,21 @@
|
|||
/*
|
||||
* morx -- Extended Glyph Metamorphosis
|
||||
* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6morx.html
|
||||
* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6mort.html
|
||||
*/
|
||||
#define HB_AAT_TAG_morx HB_TAG('m','o','r','x')
|
||||
#define HB_AAT_TAG_mort HB_TAG('m','o','r','t')
|
||||
|
||||
|
||||
namespace AAT {
|
||||
|
||||
using namespace OT;
|
||||
|
||||
|
||||
template <typename Types>
|
||||
struct RearrangementSubtable
|
||||
{
|
||||
typedef typename Types::HBUINT HBUINT;
|
||||
|
||||
typedef void EntryData;
|
||||
|
||||
struct driver_context_t
|
||||
|
@ -65,16 +69,16 @@ struct RearrangementSubtable
|
|||
Verb = 0x000F, /* The type of rearrangement specified. */
|
||||
};
|
||||
|
||||
inline driver_context_t (const RearrangementSubtable *table) :
|
||||
inline driver_context_t (const RearrangementSubtable *table HB_UNUSED) :
|
||||
ret (false),
|
||||
start (0), end (0) {}
|
||||
|
||||
inline bool is_actionable (StateTableDriver<EntryData> *driver,
|
||||
inline bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED,
|
||||
const Entry<EntryData> *entry)
|
||||
{
|
||||
return (entry->flags & Verb) && start < end;
|
||||
}
|
||||
inline bool transition (StateTableDriver<EntryData> *driver,
|
||||
inline bool transition (StateTableDriver<Types, EntryData> *driver,
|
||||
const Entry<EntryData> *entry)
|
||||
{
|
||||
hb_buffer_t *buffer = driver->buffer;
|
||||
|
@ -165,7 +169,7 @@ struct RearrangementSubtable
|
|||
|
||||
driver_context_t dc (this);
|
||||
|
||||
StateTableDriver<EntryData> driver (machine, c->buffer, c->face);
|
||||
StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
|
||||
driver.drive (&dc);
|
||||
|
||||
return_trace (dc.ret);
|
||||
|
@ -178,13 +182,16 @@ struct RearrangementSubtable
|
|||
}
|
||||
|
||||
protected:
|
||||
StateTable<EntryData> machine;
|
||||
StateTable<Types, EntryData> machine;
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (16);
|
||||
};
|
||||
|
||||
template <typename Types>
|
||||
struct ContextualSubtable
|
||||
{
|
||||
typedef typename Types::HBUINT HBUINT;
|
||||
|
||||
struct EntryData
|
||||
{
|
||||
HBUINT16 markIndex; /* Index of the substitution table for the
|
||||
|
@ -206,13 +213,16 @@ struct ContextualSubtable
|
|||
Reserved = 0x3FFF, /* These bits are reserved and should be set to 0. */
|
||||
};
|
||||
|
||||
inline driver_context_t (const ContextualSubtable *table) :
|
||||
inline driver_context_t (const ContextualSubtable *table_,
|
||||
hb_aat_apply_context_t *c_) :
|
||||
ret (false),
|
||||
c (c_),
|
||||
mark_set (false),
|
||||
mark (0),
|
||||
table (table_),
|
||||
subs (table+table->substitutionTables) {}
|
||||
|
||||
inline bool is_actionable (StateTableDriver<EntryData> *driver,
|
||||
inline bool is_actionable (StateTableDriver<Types, EntryData> *driver,
|
||||
const Entry<EntryData> *entry)
|
||||
{
|
||||
hb_buffer_t *buffer = driver->buffer;
|
||||
|
@ -222,7 +232,7 @@ struct ContextualSubtable
|
|||
|
||||
return entry->data.markIndex != 0xFFFF || entry->data.currentIndex != 0xFFFF;
|
||||
}
|
||||
inline bool transition (StateTableDriver<EntryData> *driver,
|
||||
inline bool transition (StateTableDriver<Types, EntryData> *driver,
|
||||
const Entry<EntryData> *entry)
|
||||
{
|
||||
hb_buffer_t *buffer = driver->buffer;
|
||||
|
@ -232,30 +242,55 @@ struct ContextualSubtable
|
|||
if (buffer->idx == buffer->len && !mark_set)
|
||||
return true;
|
||||
|
||||
if (entry->data.markIndex != 0xFFFF)
|
||||
const GlyphID *replacement;
|
||||
|
||||
replacement = nullptr;
|
||||
if (Types::extended)
|
||||
{
|
||||
const Lookup<GlyphID> &lookup = subs[entry->data.markIndex];
|
||||
hb_glyph_info_t *info = buffer->info;
|
||||
const GlyphID *replacement = lookup.get_value (info[mark].codepoint, driver->num_glyphs);
|
||||
if (replacement)
|
||||
if (entry->data.markIndex != 0xFFFF)
|
||||
{
|
||||
buffer->unsafe_to_break (mark, MIN (buffer->idx + 1, buffer->len));
|
||||
info[mark].codepoint = *replacement;
|
||||
ret = true;
|
||||
const Lookup<GlyphID> &lookup = subs[entry->data.markIndex];
|
||||
replacement = lookup.get_value (buffer->info[mark].codepoint, driver->num_glyphs);
|
||||
}
|
||||
}
|
||||
if (entry->data.currentIndex != 0xFFFF)
|
||||
else
|
||||
{
|
||||
unsigned int idx = MIN (buffer->idx, buffer->len - 1);
|
||||
const Lookup<GlyphID> &lookup = subs[entry->data.currentIndex];
|
||||
hb_glyph_info_t *info = buffer->info;
|
||||
const GlyphID *replacement = lookup.get_value (info[idx].codepoint, driver->num_glyphs);
|
||||
if (replacement)
|
||||
unsigned int offset = entry->data.markIndex + buffer->info[mark].codepoint;
|
||||
const UnsizedArrayOf<GlyphID> &subs_old = (const UnsizedArrayOf<GlyphID> &) subs;
|
||||
replacement = &subs_old[Types::wordOffsetToIndex (offset, table, subs_old.arrayZ)];
|
||||
if (!replacement->sanitize (&c->sanitizer) || !*replacement)
|
||||
replacement = nullptr;
|
||||
}
|
||||
if (replacement)
|
||||
{
|
||||
buffer->unsafe_to_break (mark, MIN (buffer->idx + 1, buffer->len));
|
||||
buffer->info[mark].codepoint = *replacement;
|
||||
ret = true;
|
||||
}
|
||||
|
||||
replacement = nullptr;
|
||||
unsigned int idx = MIN (buffer->idx, buffer->len - 1);
|
||||
if (Types::extended)
|
||||
{
|
||||
if (entry->data.currentIndex != 0xFFFF)
|
||||
{
|
||||
info[idx].codepoint = *replacement;
|
||||
ret = true;
|
||||
const Lookup<GlyphID> &lookup = subs[entry->data.currentIndex];
|
||||
replacement = lookup.get_value (buffer->info[idx].codepoint, driver->num_glyphs);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned int offset = entry->data.currentIndex + buffer->info[idx].codepoint;
|
||||
const UnsizedArrayOf<GlyphID> &subs_old = (const UnsizedArrayOf<GlyphID> &) subs;
|
||||
replacement = &subs_old[Types::wordOffsetToIndex (offset, table, subs_old.arrayZ)];
|
||||
if (!replacement->sanitize (&c->sanitizer) || !*replacement)
|
||||
replacement = nullptr;
|
||||
}
|
||||
if (replacement)
|
||||
{
|
||||
buffer->info[idx].codepoint = *replacement;
|
||||
ret = true;
|
||||
}
|
||||
|
||||
if (entry->flags & SetMark)
|
||||
{
|
||||
|
@ -269,18 +304,20 @@ struct ContextualSubtable
|
|||
public:
|
||||
bool ret;
|
||||
private:
|
||||
hb_aat_apply_context_t *c;
|
||||
bool mark_set;
|
||||
unsigned int mark;
|
||||
const UnsizedOffsetListOf<Lookup<GlyphID>, HBUINT32, false> &subs;
|
||||
const ContextualSubtable *table;
|
||||
const UnsizedOffsetListOf<Lookup<GlyphID>, HBUINT, false> &subs;
|
||||
};
|
||||
|
||||
inline bool apply (hb_aat_apply_context_t *c) const
|
||||
{
|
||||
TRACE_APPLY (this);
|
||||
|
||||
driver_context_t dc (this);
|
||||
driver_context_t dc (this, c);
|
||||
|
||||
StateTableDriver<EntryData> driver (machine, c->buffer, c->face);
|
||||
StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
|
||||
driver.drive (&dc);
|
||||
|
||||
return_trace (dc.ret);
|
||||
|
@ -293,6 +330,8 @@ struct ContextualSubtable
|
|||
unsigned int num_entries = 0;
|
||||
if (unlikely (!machine.sanitize (c, &num_entries))) return_trace (false);
|
||||
|
||||
if (!Types::extended) return_trace (true);
|
||||
|
||||
unsigned int num_lookups = 0;
|
||||
|
||||
const Entry<EntryData> *entries = machine.get_entries ();
|
||||
|
@ -310,38 +349,90 @@ struct ContextualSubtable
|
|||
}
|
||||
|
||||
protected:
|
||||
StateTable<EntryData>
|
||||
StateTable<Types, EntryData>
|
||||
machine;
|
||||
LOffsetTo<UnsizedOffsetListOf<Lookup<GlyphID>, HBUINT32, false>, false>
|
||||
OffsetTo<UnsizedOffsetListOf<Lookup<GlyphID>, HBUINT, false>, HBUINT, false>
|
||||
substitutionTables;
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (20);
|
||||
};
|
||||
|
||||
struct LigatureSubtable
|
||||
|
||||
template <bool extended>
|
||||
struct LigatureEntry;
|
||||
|
||||
template <>
|
||||
struct LigatureEntry<true>
|
||||
{
|
||||
struct EntryData
|
||||
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
|
||||
next iteration. */
|
||||
PerformAction = 0x2000, /* Use the ligActionIndex to process a ligature
|
||||
* group. */
|
||||
Reserved = 0x1FFF, /* These bits are reserved and should be set to 0. */
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
HBUINT16 ligActionIndex; /* Index to the first ligActionTable entry
|
||||
* for processing this group, if indicated
|
||||
* by the flags. */
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (2);
|
||||
} EntryData;
|
||||
|
||||
template <typename Flags>
|
||||
static inline bool performAction (Flags flags)
|
||||
{ return flags & PerformAction; }
|
||||
|
||||
template <typename Entry, typename Flags>
|
||||
static inline unsigned int ligActionIndex (Entry &entry, Flags flags)
|
||||
{ return entry->data.ligActionIndex; }
|
||||
};
|
||||
template <>
|
||||
struct LigatureEntry<false>
|
||||
{
|
||||
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
|
||||
next iteration. */
|
||||
Offset = 0x3FFF, /* Byte offset from beginning of subtable to the
|
||||
* ligature action list. This value must be a
|
||||
* multiple of 4. */
|
||||
};
|
||||
|
||||
typedef void EntryData;
|
||||
|
||||
template <typename Flags>
|
||||
static inline bool performAction (Flags flags)
|
||||
{ return flags & Offset; }
|
||||
|
||||
template <typename Entry, typename Flags>
|
||||
static inline unsigned int ligActionIndex (Entry &entry, Flags flags)
|
||||
{ return flags & 0x3FFF; }
|
||||
};
|
||||
|
||||
|
||||
template <typename Types>
|
||||
struct LigatureSubtable
|
||||
{
|
||||
typedef typename Types::HBUINT HBUINT;
|
||||
|
||||
typedef LigatureEntry<Types::extended> LigatureEntryT;
|
||||
typedef typename LigatureEntryT::EntryData EntryData;
|
||||
|
||||
struct driver_context_t
|
||||
{
|
||||
static const bool in_place = false;
|
||||
enum Flags
|
||||
enum
|
||||
{
|
||||
SetComponent = 0x8000, /* Push this glyph onto the component stack for
|
||||
* eventual processing. */
|
||||
DontAdvance = 0x4000, /* Leave the glyph pointer at this glyph for the
|
||||
next iteration. */
|
||||
PerformAction = 0x2000, /* Use the ligActionIndex to process a ligature
|
||||
* group. */
|
||||
Reserved = 0x1FFF, /* These bits are reserved and should be set to 0. */
|
||||
DontAdvance = LigatureEntryT::DontAdvance,
|
||||
};
|
||||
static const bool in_place = false;
|
||||
enum LigActionFlags
|
||||
{
|
||||
LigActionLast = 0x80000000, /* This is the last action in the list. This also
|
||||
|
@ -354,28 +445,29 @@ struct LigatureSubtable
|
|||
* into the component table. */
|
||||
};
|
||||
|
||||
inline driver_context_t (const LigatureSubtable *table,
|
||||
inline driver_context_t (const LigatureSubtable *table_,
|
||||
hb_aat_apply_context_t *c_) :
|
||||
ret (false),
|
||||
c (c_),
|
||||
table (table_),
|
||||
ligAction (table+table->ligAction),
|
||||
component (table+table->component),
|
||||
ligature (table+table->ligature),
|
||||
match_length (0) {}
|
||||
|
||||
inline bool is_actionable (StateTableDriver<EntryData> *driver,
|
||||
inline bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED,
|
||||
const Entry<EntryData> *entry)
|
||||
{
|
||||
return entry->flags & PerformAction;
|
||||
return LigatureEntryT::performAction (entry->flags);
|
||||
}
|
||||
inline bool transition (StateTableDriver<EntryData> *driver,
|
||||
inline bool transition (StateTableDriver<Types, EntryData> *driver,
|
||||
const Entry<EntryData> *entry)
|
||||
{
|
||||
hb_buffer_t *buffer = driver->buffer;
|
||||
unsigned int flags = entry->flags;
|
||||
|
||||
DEBUG_MSG (APPLY, nullptr, "Ligature transition at %d", buffer->idx);
|
||||
if (flags & SetComponent)
|
||||
if (flags & LigatureEntryT::SetComponent)
|
||||
{
|
||||
if (unlikely (match_length >= ARRAY_LENGTH (match_positions)))
|
||||
return false;
|
||||
|
@ -388,18 +480,23 @@ struct LigatureSubtable
|
|||
DEBUG_MSG (APPLY, nullptr, "Set component at %d", buffer->out_len);
|
||||
}
|
||||
|
||||
if (flags & PerformAction)
|
||||
if (LigatureEntryT::performAction (flags))
|
||||
{
|
||||
DEBUG_MSG (APPLY, nullptr, "Perform action with %d", match_length);
|
||||
unsigned int end = buffer->out_len;
|
||||
unsigned int action_idx = entry->data.ligActionIndex;
|
||||
unsigned int action_idx = LigatureEntryT::ligActionIndex (entry, flags);
|
||||
unsigned int action;
|
||||
unsigned int ligature_idx = 0;
|
||||
|
||||
if (unlikely (!match_length))
|
||||
return true;
|
||||
|
||||
if (buffer->idx >= buffer->len)
|
||||
return false; // TODO Work on previous instead?
|
||||
|
||||
unsigned int cursor = match_length;
|
||||
action_idx = Types::offsetToIndex (action_idx, table, ligAction.arrayZ);
|
||||
const HBUINT32 *actionData = &ligAction[action_idx];
|
||||
do
|
||||
{
|
||||
if (unlikely (!cursor))
|
||||
|
@ -413,18 +510,15 @@ struct LigatureSubtable
|
|||
DEBUG_MSG (APPLY, nullptr, "Moving to stack position %d", cursor - 1);
|
||||
buffer->move_to (match_positions[--cursor]);
|
||||
|
||||
const HBUINT32 &actionData = ligAction[action_idx];
|
||||
if (unlikely (!actionData.sanitize (&c->sanitizer))) return false;
|
||||
action = actionData;
|
||||
if (unlikely (!actionData->sanitize (&c->sanitizer))) return false;
|
||||
action = *actionData;
|
||||
|
||||
uint32_t uoffset = action & LigActionOffset;
|
||||
if (uoffset & 0x20000000)
|
||||
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;
|
||||
|
||||
component_idx = Types::wordOffsetToIndex (component_idx, table, component.arrayZ);
|
||||
const HBUINT16 &componentData = component[component_idx];
|
||||
if (unlikely (!componentData.sanitize (&c->sanitizer))) return false;
|
||||
ligature_idx += componentData;
|
||||
|
@ -434,7 +528,7 @@ struct LigatureSubtable
|
|||
bool (action & LigActionLast));
|
||||
if (action & (LigActionStore | LigActionLast))
|
||||
{
|
||||
|
||||
ligature_idx = Types::offsetToIndex (ligature_idx, table, ligature.arrayZ);
|
||||
const GlyphID &ligatureData = ligature[ligature_idx];
|
||||
if (unlikely (!ligatureData.sanitize (&c->sanitizer))) return false;
|
||||
hb_codepoint_t lig = ligatureData;
|
||||
|
@ -442,20 +536,20 @@ struct LigatureSubtable
|
|||
DEBUG_MSG (APPLY, nullptr, "Produced ligature %d", lig);
|
||||
buffer->replace_glyph (lig);
|
||||
|
||||
unsigned int lig_end = match_positions[match_length - 1] + 1;
|
||||
/* Now go and delete all subsequent components. */
|
||||
while (match_length - 1 > cursor)
|
||||
{
|
||||
DEBUG_MSG (APPLY, nullptr, "Skipping ligature component");
|
||||
buffer->move_to (match_positions[--match_length]);
|
||||
buffer->skip_glyph ();
|
||||
end--;
|
||||
buffer->replace_glyph (DELETED_GLYPH);
|
||||
}
|
||||
|
||||
buffer->move_to (end + 1);
|
||||
buffer->move_to (lig_end);
|
||||
buffer->merge_out_clusters (match_positions[cursor], buffer->out_len);
|
||||
}
|
||||
|
||||
action_idx++;
|
||||
actionData++;
|
||||
}
|
||||
while (!(action & LigActionLast));
|
||||
buffer->move_to (end);
|
||||
|
@ -468,6 +562,7 @@ struct LigatureSubtable
|
|||
bool ret;
|
||||
private:
|
||||
hb_aat_apply_context_t *c;
|
||||
const LigatureSubtable *table;
|
||||
const UnsizedArrayOf<HBUINT32> &ligAction;
|
||||
const UnsizedArrayOf<HBUINT16> &component;
|
||||
const UnsizedArrayOf<GlyphID> &ligature;
|
||||
|
@ -481,7 +576,7 @@ struct LigatureSubtable
|
|||
|
||||
driver_context_t dc (this, c);
|
||||
|
||||
StateTableDriver<EntryData> driver (machine, c->buffer, c->face);
|
||||
StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
|
||||
driver.drive (&dc);
|
||||
|
||||
return_trace (dc.ret);
|
||||
|
@ -496,18 +591,19 @@ struct LigatureSubtable
|
|||
}
|
||||
|
||||
protected:
|
||||
StateTable<EntryData>
|
||||
StateTable<Types, EntryData>
|
||||
machine;
|
||||
LOffsetTo<UnsizedArrayOf<HBUINT32>, false>
|
||||
OffsetTo<UnsizedArrayOf<HBUINT32>, HBUINT, false>
|
||||
ligAction; /* Offset to the ligature action table. */
|
||||
LOffsetTo<UnsizedArrayOf<HBUINT16>, false>
|
||||
OffsetTo<UnsizedArrayOf<HBUINT16>, HBUINT, false>
|
||||
component; /* Offset to the component table. */
|
||||
LOffsetTo<UnsizedArrayOf<GlyphID>, false>
|
||||
OffsetTo<UnsizedArrayOf<GlyphID>, HBUINT, false>
|
||||
ligature; /* Offset to the actual ligature lists. */
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (28);
|
||||
};
|
||||
|
||||
template <typename Types>
|
||||
struct NoncontextualSubtable
|
||||
{
|
||||
inline bool apply (hb_aat_apply_context_t *c) const
|
||||
|
@ -544,8 +640,11 @@ struct NoncontextualSubtable
|
|||
DEFINE_SIZE_MIN (2);
|
||||
};
|
||||
|
||||
template <typename Types>
|
||||
struct InsertionSubtable
|
||||
{
|
||||
typedef typename Types::HBUINT HBUINT;
|
||||
|
||||
struct EntryData
|
||||
{
|
||||
HBUINT16 currentInsertIndex; /* Zero-based index into the insertion glyph table.
|
||||
|
@ -621,13 +720,13 @@ struct InsertionSubtable
|
|||
mark (0),
|
||||
insertionAction (table+table->insertionAction) {}
|
||||
|
||||
inline bool is_actionable (StateTableDriver<EntryData> *driver,
|
||||
inline bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED,
|
||||
const Entry<EntryData> *entry)
|
||||
{
|
||||
return (entry->flags & (CurrentInsertCount | MarkedInsertCount)) &&
|
||||
(entry->data.currentInsertIndex != 0xFFFF ||entry->data.markedInsertIndex != 0xFFFF);
|
||||
}
|
||||
inline bool transition (StateTableDriver<EntryData> *driver,
|
||||
inline bool transition (StateTableDriver<Types, EntryData> *driver,
|
||||
const Entry<EntryData> *entry)
|
||||
{
|
||||
hb_buffer_t *buffer = driver->buffer;
|
||||
|
@ -719,7 +818,7 @@ struct InsertionSubtable
|
|||
|
||||
driver_context_t dc (this, c);
|
||||
|
||||
StateTableDriver<EntryData> driver (machine, c->buffer, c->face);
|
||||
StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
|
||||
driver.drive (&dc);
|
||||
|
||||
return_trace (dc.ret);
|
||||
|
@ -734,9 +833,9 @@ struct InsertionSubtable
|
|||
}
|
||||
|
||||
protected:
|
||||
StateTable<EntryData>
|
||||
StateTable<Types, EntryData>
|
||||
machine;
|
||||
LOffsetTo<UnsizedArrayOf<GlyphID>, false>
|
||||
OffsetTo<UnsizedArrayOf<GlyphID>, HBUINT, false>
|
||||
insertionAction; /* Byte offset from stateHeader to the start of
|
||||
* the insertion glyph table. */
|
||||
public:
|
||||
|
@ -764,30 +863,32 @@ struct Feature
|
|||
DEFINE_SIZE_STATIC (12);
|
||||
};
|
||||
|
||||
|
||||
template <typename Types>
|
||||
struct ChainSubtable
|
||||
{
|
||||
typedef typename Types::HBUINT HBUINT;
|
||||
|
||||
template <typename T>
|
||||
friend struct Chain;
|
||||
|
||||
inline unsigned int get_size (void) const { return length; }
|
||||
inline unsigned int get_type (void) const { return coverage & SubtableType; }
|
||||
inline unsigned int get_type (void) const { return coverage & 0xFF; }
|
||||
inline unsigned int get_coverage (void) const { return coverage >> (sizeof (HBUINT) * 8 - 8); }
|
||||
|
||||
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. */
|
||||
Vertical = 0x80, /* If set, this subtable will only be applied
|
||||
* to vertical text. If clear, this subtable
|
||||
* will only be applied to horizontal text. */
|
||||
Backwards = 0x40, /* If set, this subtable will process glyphs
|
||||
* in descending order. If clear, it will
|
||||
* process the glyphs in ascending order. */
|
||||
AllDirections = 0x20, /* If set, this subtable will be applied to
|
||||
* both horizontal and vertical text (i.e.
|
||||
* the state of bit 0x80000000 is ignored). */
|
||||
Logical = 0x10, /* If set, this subtable will process glyphs
|
||||
* in logical order (or reverse logical order,
|
||||
* depending on the value of bit 0x80000000). */
|
||||
};
|
||||
enum Type
|
||||
{
|
||||
|
@ -825,40 +926,49 @@ struct ChainSubtable
|
|||
}
|
||||
|
||||
protected:
|
||||
HBUINT32 length; /* Total subtable length, including this header. */
|
||||
HBUINT32 coverage; /* Coverage flags and subtable type. */
|
||||
HBUINT length; /* Total subtable length, including this header. */
|
||||
HBUINT coverage; /* Coverage flags and subtable type. */
|
||||
HBUINT32 subFeatureFlags;/* The 32-bit mask identifying which subtable this is. */
|
||||
union {
|
||||
RearrangementSubtable rearrangement;
|
||||
ContextualSubtable contextual;
|
||||
LigatureSubtable ligature;
|
||||
NoncontextualSubtable noncontextual;
|
||||
InsertionSubtable insertion;
|
||||
RearrangementSubtable<Types> rearrangement;
|
||||
ContextualSubtable<Types> contextual;
|
||||
LigatureSubtable<Types> ligature;
|
||||
NoncontextualSubtable<Types> noncontextual;
|
||||
InsertionSubtable<Types> insertion;
|
||||
} u;
|
||||
public:
|
||||
DEFINE_SIZE_MIN (12);
|
||||
DEFINE_SIZE_MIN (2 * sizeof (HBUINT) + 4);
|
||||
};
|
||||
|
||||
template <typename Types>
|
||||
struct Chain
|
||||
{
|
||||
typedef typename Types::HBUINT HBUINT;
|
||||
|
||||
inline hb_mask_t compile_flags (const hb_aat_map_builder_t *map) const
|
||||
{
|
||||
hb_mask_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];
|
||||
uint16_t type = feature.featureType;
|
||||
uint16_t setting = feature.featureSetting;
|
||||
retry:
|
||||
const hb_aat_map_builder_t::feature_info_t *info = map->features.bsearch (type);
|
||||
if (info && info->setting == setting)
|
||||
{
|
||||
flags &= feature.disableFlags;
|
||||
flags |= feature.enableFlags;
|
||||
}
|
||||
else if (type == 3/*kLetterCaseType*/ && setting == 3/*kSmallCapsSelector*/)
|
||||
{
|
||||
/* Deprecated. https://github.com/harfbuzz/harfbuzz/issues/1342 */
|
||||
type = 37/*kLowerCaseType*/;
|
||||
setting = 1/*kLowerCaseSmallCapsSelector*/;
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
}
|
||||
return flags;
|
||||
|
@ -867,7 +977,7 @@ struct Chain
|
|||
inline void apply (hb_aat_apply_context_t *c,
|
||||
hb_mask_t flags) const
|
||||
{
|
||||
const ChainSubtable *subtable = &StructAtOffset<ChainSubtable> (&featureZ, featureZ[0].static_size * featureCount);
|
||||
const ChainSubtable<Types> *subtable = &StructAtOffset<ChainSubtable<Types> > (&featureZ, featureZ[0].static_size * featureCount);
|
||||
unsigned int count = subtableCount;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
|
@ -876,9 +986,9 @@ struct Chain
|
|||
if (!(subtable->subFeatureFlags & flags))
|
||||
goto skip;
|
||||
|
||||
if (!(subtable->coverage & ChainSubtable::AllDirections) &&
|
||||
if (!(subtable->get_coverage() & ChainSubtable<Types>::AllDirections) &&
|
||||
HB_DIRECTION_IS_VERTICAL (c->buffer->props.direction) !=
|
||||
bool (subtable->coverage & ChainSubtable::Vertical))
|
||||
bool (subtable->get_coverage() & ChainSubtable<Types>::Vertical))
|
||||
goto skip;
|
||||
|
||||
/* Buffer contents is always in logical direction. Determine if
|
||||
|
@ -908,9 +1018,9 @@ struct Chain
|
|||
(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) !=
|
||||
reverse = subtable->get_coverage () & ChainSubtable<Types>::Logical ?
|
||||
bool (subtable->get_coverage () & ChainSubtable<Types>::Backwards) :
|
||||
bool (subtable->get_coverage () & ChainSubtable<Types>::Backwards) !=
|
||||
HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction);
|
||||
|
||||
if (!c->buffer->message (c->font, "start chain subtable %d", c->lookup_index))
|
||||
|
@ -931,14 +1041,14 @@ struct Chain
|
|||
if (unlikely (!c->buffer->successful)) return;
|
||||
|
||||
skip:
|
||||
subtable = &StructAfter<ChainSubtable> (*subtable);
|
||||
subtable = &StructAfter<ChainSubtable<Types> > (*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 version) const
|
||||
inline bool sanitize (hb_sanitize_context_t *c, unsigned int version HB_UNUSED) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
if (!length.sanitize (c) ||
|
||||
|
@ -949,13 +1059,13 @@ struct Chain
|
|||
if (!c->check_array (featureZ.arrayZ, featureCount))
|
||||
return_trace (false);
|
||||
|
||||
const ChainSubtable *subtable = &StructAtOffset<ChainSubtable> (&featureZ, featureZ[0].static_size * featureCount);
|
||||
const ChainSubtable<Types> *subtable = &StructAtOffset<ChainSubtable<Types> > (&featureZ, featureZ[0].static_size * featureCount);
|
||||
unsigned int count = subtableCount;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
if (!subtable->sanitize (c))
|
||||
return_trace (false);
|
||||
subtable = &StructAfter<ChainSubtable> (*subtable);
|
||||
subtable = &StructAfter<ChainSubtable<Types> > (*subtable);
|
||||
}
|
||||
|
||||
return_trace (true);
|
||||
|
@ -964,23 +1074,24 @@ struct Chain
|
|||
protected:
|
||||
HBUINT32 defaultFlags; /* The default specification for subtables. */
|
||||
HBUINT32 length; /* Total byte count, including this header. */
|
||||
HBUINT32 featureCount; /* Number of feature subtable entries. */
|
||||
HBUINT32 subtableCount; /* The number of subtables in the chain. */
|
||||
HBUINT featureCount; /* Number of feature subtable entries. */
|
||||
HBUINT subtableCount; /* The number of subtables in the chain. */
|
||||
|
||||
UnsizedArrayOf<Feature> featureZ; /* Features. */
|
||||
/*ChainSubtable firstSubtable;*//* Subtables. */
|
||||
/*subtableGlyphCoverageArray*/ /* Only if version >= 3. We don't use. */
|
||||
|
||||
public:
|
||||
DEFINE_SIZE_MIN (16);
|
||||
DEFINE_SIZE_MIN (8 + 2 * sizeof (HBUINT));
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* The 'morx' Table
|
||||
* The 'mort'/'morx' Table
|
||||
*/
|
||||
|
||||
struct morx
|
||||
template <typename Types>
|
||||
struct mortmorx
|
||||
{
|
||||
static const hb_tag_t tableTag = HB_AAT_TAG_morx;
|
||||
|
||||
|
@ -989,43 +1100,59 @@ struct morx
|
|||
inline void compile_flags (const hb_aat_map_builder_t *mapper,
|
||||
hb_aat_map_t *map) const
|
||||
{
|
||||
const Chain *chain = &firstChain;
|
||||
const Chain<Types> *chain = &firstChain;
|
||||
unsigned int count = chainCount;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
map->chain_flags.push (chain->compile_flags (mapper));
|
||||
chain = &StructAfter<Chain> (*chain);
|
||||
chain = &StructAfter<Chain<Types> > (*chain);
|
||||
}
|
||||
}
|
||||
|
||||
inline static void remove_deleted_glyphs (hb_buffer_t *buffer)
|
||||
{
|
||||
if (unlikely (!buffer->successful)) return;
|
||||
|
||||
buffer->clear_output ();
|
||||
for (buffer->idx = 0; buffer->idx < buffer->len && buffer->successful;)
|
||||
{
|
||||
if (unlikely (buffer->cur().codepoint == DELETED_GLYPH))
|
||||
buffer->skip_glyph ();
|
||||
else
|
||||
buffer->next_glyph ();
|
||||
}
|
||||
if (likely (buffer->successful))
|
||||
buffer->swap_buffers ();
|
||||
}
|
||||
|
||||
inline void apply (hb_aat_apply_context_t *c) const
|
||||
{
|
||||
if (unlikely (!c->buffer->successful)) return;
|
||||
c->set_lookup_index (0);
|
||||
const Chain *chain = &firstChain;
|
||||
const Chain<Types> *chain = &firstChain;
|
||||
unsigned int count = chainCount;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
chain->apply (c, c->plan->aat_map.chain_flags[i]);
|
||||
if (unlikely (!c->buffer->successful)) return;
|
||||
chain = &StructAfter<Chain> (*chain);
|
||||
chain = &StructAfter<Chain<Types> > (*chain);
|
||||
}
|
||||
remove_deleted_glyphs (c->buffer);
|
||||
}
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
if (!version.sanitize (c) || version < 2 ||
|
||||
!chainCount.sanitize (c))
|
||||
if (!version.sanitize (c) || !version || !chainCount.sanitize (c))
|
||||
return_trace (false);
|
||||
|
||||
const Chain *chain = &firstChain;
|
||||
const Chain<Types> *chain = &firstChain;
|
||||
unsigned int count = chainCount;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
if (!chain->sanitize (c, version))
|
||||
return_trace (false);
|
||||
chain = &StructAfter<Chain> (*chain);
|
||||
chain = &StructAfter<Chain<Types> > (*chain);
|
||||
}
|
||||
|
||||
return_trace (true);
|
||||
|
@ -1033,16 +1160,26 @@ struct morx
|
|||
|
||||
protected:
|
||||
HBUINT16 version; /* Version number of the glyph metamorphosis table.
|
||||
* 2 or 3. */
|
||||
* 1, 2, or 3. */
|
||||
HBUINT16 unused; /* Set to 0. */
|
||||
HBUINT32 chainCount; /* Number of metamorphosis chains contained in this
|
||||
* table. */
|
||||
Chain firstChain; /* Chains. */
|
||||
Chain<Types> firstChain; /* Chains. */
|
||||
|
||||
public:
|
||||
DEFINE_SIZE_MIN (8);
|
||||
};
|
||||
|
||||
struct morx : mortmorx<MorxTypes>
|
||||
{
|
||||
static const hb_tag_t tableTag = HB_AAT_TAG_morx;
|
||||
};
|
||||
struct mort : mortmorx<MortTypes>
|
||||
{
|
||||
static const hb_tag_t tableTag = HB_AAT_TAG_mort;
|
||||
};
|
||||
|
||||
|
||||
} /* namespace AAT */
|
||||
|
||||
|
||||
|
|
|
@ -34,13 +34,14 @@
|
|||
#include "hb-aat-layout-kerx-table.hh"
|
||||
#include "hb-aat-layout-morx-table.hh"
|
||||
#include "hb-aat-layout-trak-table.hh"
|
||||
#include "hb-aat-ltag-table.hh" // Just so we compile it; unused otherwise.
|
||||
#include "hb-aat-ltag-table.hh"
|
||||
|
||||
|
||||
/* 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 ('a','f','r','c'), 11/*kFractionsType*/, 1/*kVerticalFractionsSelector*/, 0/*kNoFractionsSelector*/},
|
||||
{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*/},
|
||||
|
@ -130,9 +131,23 @@ hb_aat_layout_find_feature_mapping (hb_tag_t tag)
|
|||
|
||||
|
||||
/*
|
||||
* morx/kerx/trak
|
||||
* mort/morx/kerx/trak
|
||||
*/
|
||||
|
||||
static inline const AAT::mort&
|
||||
_get_mort (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::mort);
|
||||
}
|
||||
const AAT::mort& mort = *(hb_ot_face_data (face)->mort.get ());
|
||||
if (blob)
|
||||
*blob = hb_ot_face_data (face)->mort.get_blob ();
|
||||
return mort;
|
||||
}
|
||||
static inline const AAT::morx&
|
||||
_get_morx (hb_face_t *face, hb_blob_t **blob = nullptr)
|
||||
{
|
||||
|
@ -181,20 +196,39 @@ _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 const AAT::ltag&
|
||||
_get_ltag (hb_face_t *face)
|
||||
{
|
||||
if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(AAT::ltag);
|
||||
return *(hb_ot_face_data (face)->ltag.get ());
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
hb_aat_layout_compile_map (const hb_aat_map_builder_t *mapper,
|
||||
hb_aat_map_t *map)
|
||||
{
|
||||
_get_morx (mapper->face).compile_flags (mapper, map);
|
||||
const AAT::morx& morx = _get_morx (mapper->face, nullptr);
|
||||
if (morx.has_data ())
|
||||
{
|
||||
morx.compile_flags (mapper, map);
|
||||
return;
|
||||
}
|
||||
|
||||
const AAT::mort& mort = _get_mort (mapper->face, nullptr);
|
||||
if (mort.has_data ())
|
||||
{
|
||||
mort.compile_flags (mapper, map);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
hb_bool_t
|
||||
hb_aat_layout_has_substitution (hb_face_t *face)
|
||||
{
|
||||
return _get_morx (face).has_data ();
|
||||
return _get_morx (face).has_data () ||
|
||||
_get_mort (face).has_data ();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -203,10 +237,22 @@ hb_aat_layout_substitute (hb_ot_shape_plan_t *plan,
|
|||
hb_buffer_t *buffer)
|
||||
{
|
||||
hb_blob_t *blob;
|
||||
const AAT::morx& morx = _get_morx (font->face, &blob);
|
||||
|
||||
AAT::hb_aat_apply_context_t c (plan, font, buffer, blob);
|
||||
morx.apply (&c);
|
||||
const AAT::morx& morx = _get_morx (font->face, &blob);
|
||||
if (morx.has_data ())
|
||||
{
|
||||
AAT::hb_aat_apply_context_t c (plan, font, buffer, blob);
|
||||
morx.apply (&c);
|
||||
return;
|
||||
}
|
||||
|
||||
const AAT::mort& mort = _get_mort (font->face, &blob);
|
||||
if (mort.has_data ())
|
||||
{
|
||||
AAT::hb_aat_apply_context_t c (plan, font, buffer, blob);
|
||||
mort.apply (&c);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -248,3 +294,10 @@ hb_aat_layout_track (hb_ot_shape_plan_t *plan,
|
|||
AAT::hb_aat_apply_context_t c (plan, font, buffer);
|
||||
trak.apply (&c);
|
||||
}
|
||||
|
||||
hb_language_t
|
||||
_hb_aat_language_get (hb_face_t *face,
|
||||
unsigned int i)
|
||||
{
|
||||
return _get_ltag (face).get_language (i);
|
||||
}
|
||||
|
|
|
@ -80,4 +80,9 @@ hb_aat_layout_track (hb_ot_shape_plan_t *plan,
|
|||
hb_font_t *font,
|
||||
hb_buffer_t *buffer);
|
||||
|
||||
HB_INTERNAL hb_language_t
|
||||
_hb_aat_language_get (hb_face_t *face,
|
||||
unsigned int i);
|
||||
|
||||
|
||||
#endif /* HB_AAT_LAYOUT_HH */
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
#ifndef HB_AAT_LTAG_TABLE_HH
|
||||
#define HB_AAT_LTAG_TABLE_HH
|
||||
|
||||
#include "hb-aat-layout-common.hh"
|
||||
#include "hb-open-type.hh"
|
||||
|
||||
/*
|
||||
* ltag -- Language Tag
|
||||
|
@ -36,9 +36,13 @@
|
|||
|
||||
namespace AAT {
|
||||
|
||||
using namespace OT;
|
||||
|
||||
|
||||
struct FTStringRange
|
||||
{
|
||||
friend struct ltag;
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
|
@ -58,10 +62,19 @@ struct ltag
|
|||
{
|
||||
static const hb_tag_t tableTag = HB_AAT_TAG_ltag;
|
||||
|
||||
inline hb_language_t get_language (unsigned int i) const
|
||||
{
|
||||
const FTStringRange &range = tagRanges[i];
|
||||
return hb_language_from_string ((const char *) (this+range.tag).arrayZ,
|
||||
range.length);
|
||||
}
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (likely (c->check_struct (this) && tagRanges.sanitize (c, this)));
|
||||
return_trace (likely (c->check_struct (this) &&
|
||||
version >= 1 &&
|
||||
tagRanges.sanitize (c, this)));
|
||||
}
|
||||
|
||||
protected:
|
||||
|
|
|
@ -34,6 +34,14 @@
|
|||
void hb_aat_map_builder_t::add_feature (hb_tag_t tag,
|
||||
unsigned int value)
|
||||
{
|
||||
if (tag == HB_TAG ('a','a','l','t'))
|
||||
{
|
||||
feature_info_t *info = features.push();
|
||||
info->type = 17/*kCharacterAlternativesType*/;
|
||||
info->setting = value;
|
||||
return;
|
||||
}
|
||||
|
||||
const hb_aat_feature_mapping_t *mapping = hb_aat_layout_find_feature_mapping (tag);
|
||||
if (!mapping) return;
|
||||
|
||||
|
|
|
@ -30,8 +30,6 @@
|
|||
#include "hb.hh"
|
||||
|
||||
|
||||
struct hb_ot_shape_plan_t;
|
||||
|
||||
struct hb_aat_map_t
|
||||
{
|
||||
friend struct hb_aat_map_builder_t;
|
||||
|
@ -58,15 +56,7 @@ struct hb_aat_map_builder_t
|
|||
|
||||
HB_INTERNAL hb_aat_map_builder_t (hb_face_t *face_,
|
||||
const hb_segment_properties_t *props_ HB_UNUSED) :
|
||||
face (face_)
|
||||
{
|
||||
features.init ();
|
||||
}
|
||||
|
||||
~hb_aat_map_builder_t (void)
|
||||
{
|
||||
features.fini ();
|
||||
}
|
||||
face (face_) {}
|
||||
|
||||
HB_INTERNAL void add_feature (hb_tag_t tag, unsigned int value=1);
|
||||
|
||||
|
|
|
@ -40,6 +40,19 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
|
||||
/**
|
||||
* SECTION: hb-blob
|
||||
* @title: hb-blob
|
||||
* @short_description: Binary data containers
|
||||
* @include: hb.h
|
||||
*
|
||||
* Blobs wrap a chunk of binary data to handle lifecycle management of data
|
||||
* while it is passed between client and HarfBuzz. Blobs are primarily used
|
||||
* to create font faces, but also to access font face tables, as well as
|
||||
* pass around other binary data.
|
||||
**/
|
||||
|
||||
|
||||
DEFINE_NULL_INSTANCE (hb_blob_t) =
|
||||
{
|
||||
HB_OBJECT_HEADER_STATIC,
|
||||
|
|
|
@ -60,7 +60,7 @@ struct hb_blob_t
|
|||
template <typename Type>
|
||||
inline const Type* as (void) const
|
||||
{
|
||||
return unlikely (!data) ? &Null(Type) : reinterpret_cast<const Type *> (data);
|
||||
return length < Type::min_size ? &Null(Type) : reinterpret_cast<const Type *> (data);
|
||||
}
|
||||
inline hb_bytes_t as_bytes (void) const
|
||||
{
|
||||
|
@ -69,7 +69,6 @@ struct hb_blob_t
|
|||
|
||||
public:
|
||||
hb_object_header_t header;
|
||||
ASSERT_POD ();
|
||||
|
||||
bool immutable;
|
||||
|
||||
|
|
|
@ -33,14 +33,15 @@
|
|||
|
||||
/**
|
||||
* SECTION: hb-buffer
|
||||
* @title: Buffers
|
||||
* @title: hb-buffer
|
||||
* @short_description: Input and output buffers
|
||||
* @include: hb.h
|
||||
*
|
||||
* Buffers serve dual role in HarfBuzz; they hold the input characters that are
|
||||
* passed hb_shape(), and after shaping they hold the output glyphs.
|
||||
* passed to hb_shape(), and after shaping they hold the output glyphs.
|
||||
**/
|
||||
|
||||
|
||||
/**
|
||||
* hb_segment_properties_equal:
|
||||
* @a: first #hb_segment_properties_t to compare.
|
||||
|
@ -1665,7 +1666,7 @@ hb_buffer_add_utf32 (hb_buffer_t *buffer,
|
|||
unsigned int item_offset,
|
||||
int item_length)
|
||||
{
|
||||
hb_buffer_add_utf<hb_utf32_t<> > (buffer, text, text_length, item_offset, item_length);
|
||||
hb_buffer_add_utf<hb_utf32_t> (buffer, text, text_length, item_offset, item_length);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1726,7 +1727,7 @@ hb_buffer_add_codepoints (hb_buffer_t *buffer,
|
|||
unsigned int item_offset,
|
||||
int item_length)
|
||||
{
|
||||
hb_buffer_add_utf<hb_utf32_t<false> > (buffer, text, text_length, item_offset, item_length);
|
||||
hb_buffer_add_utf<hb_utf32_novalidate_t> (buffer, text, text_length, item_offset, item_length);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -86,7 +86,6 @@ HB_MARK_AS_FLAG_T (hb_buffer_scratch_flags_t);
|
|||
struct hb_buffer_t
|
||||
{
|
||||
hb_object_header_t header;
|
||||
ASSERT_POD ();
|
||||
|
||||
/* Information about how the text in the buffer should be treated */
|
||||
hb_unicode_funcs_t *unicode; /* Unicode functions */
|
||||
|
|
|
@ -36,6 +36,16 @@
|
|||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* SECTION:hb-common
|
||||
* @title: hb-common
|
||||
* @short_description: Common data types
|
||||
* @include: hb.h
|
||||
*
|
||||
* Common data types used across HarfBuzz are defined here.
|
||||
**/
|
||||
|
||||
|
||||
/* hb_options_t */
|
||||
|
||||
hb_atomic_int_t _hb_options;
|
||||
|
@ -615,6 +625,19 @@ hb_user_data_array_t::get (hb_user_data_key_t *key)
|
|||
|
||||
/* hb_version */
|
||||
|
||||
|
||||
/**
|
||||
* SECTION:hb-version
|
||||
* @title: hb-version
|
||||
* @short_description: Information about the version of HarfBuzz in use
|
||||
* @include: hb.h
|
||||
*
|
||||
* These functions and macros allow accessing version of the HarfBuzz
|
||||
* library used at compile- as well as run-time, and to direct code
|
||||
* conditionally based on those versions, again, at compile- or run-time.
|
||||
**/
|
||||
|
||||
|
||||
/**
|
||||
* hb_version:
|
||||
* @major: (out): Library major version component.
|
||||
|
|
|
@ -33,6 +33,10 @@
|
|||
#ifndef HB_COMMON_H
|
||||
#define HB_COMMON_H
|
||||
|
||||
#ifndef HB_EXTERN
|
||||
#define HB_EXTERN extern
|
||||
#endif
|
||||
|
||||
#ifndef HB_BEGIN_DECLS
|
||||
# ifdef __cplusplus
|
||||
# define HB_BEGIN_DECLS extern "C" {
|
||||
|
@ -449,15 +453,43 @@ hb_variation_to_string (hb_variation_t *variation,
|
|||
*
|
||||
* Data type for holding color values.
|
||||
*
|
||||
* Since: REPLACEME
|
||||
* Since: 2.1.0
|
||||
*/
|
||||
typedef uint32_t hb_color_t;
|
||||
|
||||
#define HB_COLOR(b,g,r,a) ((hb_color_t) HB_TAG ((b),(g),(r),(a)))
|
||||
|
||||
/**
|
||||
* hb_color_get_alpha:
|
||||
*
|
||||
*
|
||||
*
|
||||
* Since: 2.1.0
|
||||
*/
|
||||
#define hb_color_get_alpha(color) ((color) & 0xFF)
|
||||
/**
|
||||
* hb_color_get_red:
|
||||
*
|
||||
*
|
||||
*
|
||||
* Since: 2.1.0
|
||||
*/
|
||||
#define hb_color_get_red(color) (((color) >> 8) & 0xFF)
|
||||
/**
|
||||
* hb_color_get_green:
|
||||
*
|
||||
*
|
||||
*
|
||||
* Since: 2.1.0
|
||||
*/
|
||||
#define hb_color_get_green(color) (((color) >> 16) & 0xFF)
|
||||
/**
|
||||
* hb_color_get_blue:
|
||||
*
|
||||
*
|
||||
*
|
||||
* Since: 2.1.0
|
||||
*/
|
||||
#define hb_color_get_blue(color) (((color) >> 24) & 0xFF)
|
||||
|
||||
|
||||
|
|
|
@ -35,6 +35,16 @@
|
|||
#include "hb-aat-layout.hh"
|
||||
#include <math.h>
|
||||
|
||||
|
||||
/**
|
||||
* SECTION:hb-coretext
|
||||
* @title: hb-coretext
|
||||
* @short_description: CoreText integration
|
||||
* @include: hb-coretext.h
|
||||
*
|
||||
* Functions for using HarfBuzz with the CoreText fonts.
|
||||
**/
|
||||
|
||||
/* https://developer.apple.com/documentation/coretext/1508745-ctfontcreatewithgraphicsfont */
|
||||
#define HB_CORETEXT_DEFAULT_FONT_SIZE 12.f
|
||||
|
||||
|
@ -464,8 +474,8 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
|
|||
buffer->merge_clusters (i - 1, i + 1);
|
||||
}
|
||||
|
||||
hb_auto_t<hb_vector_t<feature_record_t> > feature_records;
|
||||
hb_auto_t<hb_vector_t<range_record_t> > range_records;
|
||||
hb_vector_t<feature_record_t> feature_records;
|
||||
hb_vector_t<range_record_t> range_records;
|
||||
|
||||
/*
|
||||
* Set up features.
|
||||
|
@ -474,7 +484,7 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
|
|||
if (num_features)
|
||||
{
|
||||
/* Sort features by start/end events. */
|
||||
hb_auto_t<hb_vector_t<feature_event_t> > feature_events;
|
||||
hb_vector_t<feature_event_t> feature_events;
|
||||
for (unsigned int i = 0; i < num_features; i++)
|
||||
{
|
||||
const hb_aat_feature_mapping_t * mapping = hb_aat_layout_find_feature_mapping (features[i].tag);
|
||||
|
@ -513,7 +523,7 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
|
|||
}
|
||||
|
||||
/* Scan events and save features for each range. */
|
||||
hb_auto_t<hb_vector_t<active_feature_t> > active_features;
|
||||
hb_vector_t<active_feature_t> active_features;
|
||||
unsigned int last_index = 0;
|
||||
for (unsigned int i = 0; i < feature_events.len; i++)
|
||||
{
|
||||
|
@ -586,7 +596,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -173,7 +173,7 @@ _hb_debug_msg_va (const char *what,
|
|||
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
template <> inline void
|
||||
template <> inline void HB_PRINTF_FUNC(7, 0)
|
||||
_hb_debug_msg_va<0> (const char *what HB_UNUSED,
|
||||
const void *obj HB_UNUSED,
|
||||
const char *func HB_UNUSED,
|
||||
|
@ -192,7 +192,7 @@ _hb_debug_msg (const char *what,
|
|||
int level_dir,
|
||||
const char *message,
|
||||
...) HB_PRINTF_FUNC(7, 8);
|
||||
template <int max_level> static inline void
|
||||
template <int max_level> static inline void HB_PRINTF_FUNC(7, 8)
|
||||
_hb_debug_msg (const char *what,
|
||||
const void *obj,
|
||||
const char *func,
|
||||
|
@ -216,7 +216,7 @@ _hb_debug_msg<0> (const char *what HB_UNUSED,
|
|||
int level_dir HB_UNUSED,
|
||||
const char *message HB_UNUSED,
|
||||
...) HB_PRINTF_FUNC(7, 8);
|
||||
template <> inline void
|
||||
template <> inline void HB_PRINTF_FUNC(7, 8)
|
||||
_hb_debug_msg<0> (const char *what HB_UNUSED,
|
||||
const void *obj HB_UNUSED,
|
||||
const char *func HB_UNUSED,
|
||||
|
|
|
@ -36,6 +36,18 @@
|
|||
#include "hb-font.h"
|
||||
#include "hb-set.h"
|
||||
|
||||
|
||||
/**
|
||||
* SECTION:hb-deprecated
|
||||
* @title: hb-deprecated
|
||||
* @short_description: Deprecated API
|
||||
* @include: hb.h
|
||||
*
|
||||
* These API have been deprecated in favor of newer API, or because they
|
||||
* were deemed unnecessary.
|
||||
**/
|
||||
|
||||
|
||||
HB_BEGIN_DECLS
|
||||
|
||||
#ifndef HB_DISABLE_DEPRECATED
|
||||
|
|
115
src/hb-dsalgs.hh
115
src/hb-dsalgs.hh
|
@ -312,6 +312,27 @@ hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2, T lo3, T hi3)
|
|||
* Sort and search.
|
||||
*/
|
||||
|
||||
static inline void *
|
||||
hb_bsearch (const void *key, const void *base,
|
||||
size_t nmemb, size_t size,
|
||||
int (*compar)(const void *_key, const void *_item))
|
||||
{
|
||||
int min = 0, max = (int) nmemb - 1;
|
||||
while (min <= max)
|
||||
{
|
||||
int mid = (min + max) / 2;
|
||||
const void *p = (const void *) (((const char *) base) + (mid * size));
|
||||
int c = compar (key, p);
|
||||
if (c < 0)
|
||||
max = mid - 1;
|
||||
else if (c > 0)
|
||||
min = mid + 1;
|
||||
else
|
||||
return (void *) p;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static inline void *
|
||||
hb_bsearch_r (const void *key, const void *base,
|
||||
size_t nmemb, size_t size,
|
||||
|
@ -321,7 +342,7 @@ hb_bsearch_r (const void *key, const void *base,
|
|||
int min = 0, max = (int) nmemb - 1;
|
||||
while (min <= max)
|
||||
{
|
||||
int mid = (min + max) / 2;
|
||||
int mid = ((unsigned int) min + (unsigned int) max) / 2;
|
||||
const void *p = (const void *) (((const char *) base) + (mid * size));
|
||||
int c = compar (key, p, arg);
|
||||
if (c < 0)
|
||||
|
@ -490,56 +511,6 @@ hb_codepoint_parse (const char *s, unsigned int len, int base, hb_codepoint_t *o
|
|||
}
|
||||
|
||||
|
||||
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 (T *array_, unsigned int len_) : arrayZ (array_), len (len_) {}
|
||||
|
||||
inline T& operator [] (unsigned int i) const
|
||||
{
|
||||
if (unlikely (i >= len)) return Null(T);
|
||||
return arrayZ[i];
|
||||
}
|
||||
|
||||
inline hb_array_t<T> sub_array (unsigned int start_offset, unsigned int seg_count) const
|
||||
{
|
||||
unsigned int count = len;
|
||||
if (unlikely (start_offset > count))
|
||||
count = 0;
|
||||
else
|
||||
count -= start_offset;
|
||||
count = MIN (count, seg_count);
|
||||
return hb_array_t<T> (arrayZ + start_offset, count);
|
||||
}
|
||||
|
||||
inline void free (void) { ::free ((void *) arrayZ); arrayZ = nullptr; len = 0; }
|
||||
|
||||
T *arrayZ;
|
||||
unsigned int len;
|
||||
};
|
||||
template <typename T> static inline
|
||||
hb_array_t<T> hb_array (T *array, unsigned int len) { return hb_array_t<T> (array, len); }
|
||||
|
||||
struct hb_bytes_t
|
||||
{
|
||||
inline hb_bytes_t (void) : arrayZ (nullptr), len (0) {}
|
||||
|
@ -568,6 +539,42 @@ struct hb_bytes_t
|
|||
unsigned int len;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct hb_array_t
|
||||
{
|
||||
inline hb_array_t (void) : arrayZ (nullptr), len (0) {}
|
||||
inline hb_array_t (T *array_, unsigned int len_) : arrayZ (array_), len (len_) {}
|
||||
|
||||
inline T& operator [] (unsigned int i) const
|
||||
{
|
||||
if (unlikely (i >= len)) return Null(T);
|
||||
return arrayZ[i];
|
||||
}
|
||||
|
||||
inline hb_array_t<T> sub_array (unsigned int start_offset, unsigned int seg_count) const
|
||||
{
|
||||
unsigned int count = len;
|
||||
if (unlikely (start_offset > count))
|
||||
count = 0;
|
||||
else
|
||||
count -= start_offset;
|
||||
count = MIN (count, seg_count);
|
||||
return hb_array_t<T> (arrayZ + start_offset, count);
|
||||
}
|
||||
|
||||
inline hb_bytes_t as_bytes (void) const
|
||||
{
|
||||
return hb_bytes_t (arrayZ, len * sizeof (T));
|
||||
}
|
||||
|
||||
inline void free (void) { ::free ((void *) arrayZ); arrayZ = nullptr; len = 0; }
|
||||
|
||||
T *arrayZ;
|
||||
unsigned int len;
|
||||
};
|
||||
template <typename T> static inline
|
||||
hb_array_t<T> hb_array (T *array, unsigned int len) { return hb_array_t<T> (array, len); }
|
||||
|
||||
|
||||
struct HbOpOr
|
||||
{
|
||||
|
@ -603,8 +610,10 @@ struct HbOpXor
|
|||
template <typename elt_t, unsigned int byte_size>
|
||||
struct hb_vector_size_t
|
||||
{
|
||||
elt_t& operator [] (unsigned int i) { return u.v[i]; }
|
||||
const elt_t& operator [] (unsigned int i) const { return u.v[i]; }
|
||||
inline elt_t& operator [] (unsigned int i) { return u.v[i]; }
|
||||
inline const elt_t& operator [] (unsigned int i) const { return u.v[i]; }
|
||||
|
||||
inline void clear (unsigned char v = 0) { memset (this, v, sizeof (*this)); }
|
||||
|
||||
template <class Op>
|
||||
inline hb_vector_size_t process (const hb_vector_size_t &o) const
|
||||
|
|
|
@ -35,6 +35,19 @@
|
|||
#include "hb-ot-cmap-table.hh"
|
||||
|
||||
|
||||
/**
|
||||
* SECTION:hb-face
|
||||
* @title: hb-face
|
||||
* @short_description: Font face objects
|
||||
* @include: hb.h
|
||||
*
|
||||
* Font face is objects represent a single face in a font family.
|
||||
* More exactly, a font face represents a single face in a binary font file.
|
||||
* Font faces are typically built from a binary blob and a face index.
|
||||
* Font faces are used to create fonts.
|
||||
**/
|
||||
|
||||
|
||||
/**
|
||||
* hb_face_count:
|
||||
* @blob: a blob.
|
||||
|
@ -666,7 +679,7 @@ _hb_face_builder_data_reference_blob (hb_face_builder_data_t *data)
|
|||
}
|
||||
|
||||
static hb_blob_t *
|
||||
_hb_face_builder_reference_table (hb_face_t *face, hb_tag_t tag, void *user_data)
|
||||
_hb_face_builder_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
|
||||
{
|
||||
hb_face_builder_data_t *data = (hb_face_builder_data_t *) user_data;
|
||||
|
||||
|
|
|
@ -42,7 +42,6 @@
|
|||
struct hb_face_t
|
||||
{
|
||||
hb_object_header_t header;
|
||||
ASSERT_POD ();
|
||||
|
||||
hb_bool_t immutable;
|
||||
|
||||
|
|
|
@ -34,6 +34,19 @@
|
|||
#include "hb-ot.h"
|
||||
|
||||
|
||||
/**
|
||||
* SECTION:hb-font
|
||||
* @title: hb-font
|
||||
* @short_description: Font objects
|
||||
* @include: hb.h
|
||||
*
|
||||
* Font objects represent a font face at a certain size and other
|
||||
* parameters (pixels per EM, points per EM, variation settings.)
|
||||
* Fonts are created from font faces, and are used as input to
|
||||
* hb_shape() among other things.
|
||||
**/
|
||||
|
||||
|
||||
/*
|
||||
* hb_font_funcs_t
|
||||
*/
|
||||
|
@ -41,23 +54,23 @@
|
|||
static hb_bool_t
|
||||
hb_font_get_font_h_extents_nil (hb_font_t *font HB_UNUSED,
|
||||
void *font_data HB_UNUSED,
|
||||
hb_font_extents_t *metrics,
|
||||
hb_font_extents_t *extents,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
memset (metrics, 0, sizeof (*metrics));
|
||||
memset (extents, 0, sizeof (*extents));
|
||||
return false;
|
||||
}
|
||||
static hb_bool_t
|
||||
hb_font_get_font_h_extents_default (hb_font_t *font,
|
||||
void *font_data HB_UNUSED,
|
||||
hb_font_extents_t *metrics,
|
||||
hb_font_extents_t *extents,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
hb_bool_t ret = font->parent->get_font_h_extents (metrics);
|
||||
hb_bool_t ret = font->parent->get_font_h_extents (extents);
|
||||
if (ret) {
|
||||
metrics->ascender = font->parent_scale_y_distance (metrics->ascender);
|
||||
metrics->descender = font->parent_scale_y_distance (metrics->descender);
|
||||
metrics->line_gap = font->parent_scale_y_distance (metrics->line_gap);
|
||||
extents->ascender = font->parent_scale_y_distance (extents->ascender);
|
||||
extents->descender = font->parent_scale_y_distance (extents->descender);
|
||||
extents->line_gap = font->parent_scale_y_distance (extents->line_gap);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
@ -65,23 +78,23 @@ hb_font_get_font_h_extents_default (hb_font_t *font,
|
|||
static hb_bool_t
|
||||
hb_font_get_font_v_extents_nil (hb_font_t *font HB_UNUSED,
|
||||
void *font_data HB_UNUSED,
|
||||
hb_font_extents_t *metrics,
|
||||
hb_font_extents_t *extents,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
memset (metrics, 0, sizeof (*metrics));
|
||||
memset (extents, 0, sizeof (*extents));
|
||||
return false;
|
||||
}
|
||||
static hb_bool_t
|
||||
hb_font_get_font_v_extents_default (hb_font_t *font,
|
||||
void *font_data HB_UNUSED,
|
||||
hb_font_extents_t *metrics,
|
||||
hb_font_extents_t *extents,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
hb_bool_t ret = font->parent->get_font_v_extents (metrics);
|
||||
hb_bool_t ret = font->parent->get_font_v_extents (extents);
|
||||
if (ret) {
|
||||
metrics->ascender = font->parent_scale_x_distance (metrics->ascender);
|
||||
metrics->descender = font->parent_scale_x_distance (metrics->descender);
|
||||
metrics->line_gap = font->parent_scale_x_distance (metrics->line_gap);
|
||||
extents->ascender = font->parent_scale_x_distance (extents->ascender);
|
||||
extents->descender = font->parent_scale_x_distance (extents->descender);
|
||||
extents->line_gap = font->parent_scale_x_distance (extents->line_gap);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
@ -89,7 +102,7 @@ hb_font_get_font_v_extents_default (hb_font_t *font,
|
|||
static hb_bool_t
|
||||
hb_font_get_nominal_glyph_nil (hb_font_t *font HB_UNUSED,
|
||||
void *font_data HB_UNUSED,
|
||||
hb_codepoint_t unicode,
|
||||
hb_codepoint_t unicode HB_UNUSED,
|
||||
hb_codepoint_t *glyph,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
|
@ -142,8 +155,8 @@ hb_font_get_nominal_glyphs_default (hb_font_t *font,
|
|||
static hb_bool_t
|
||||
hb_font_get_variation_glyph_nil (hb_font_t *font HB_UNUSED,
|
||||
void *font_data HB_UNUSED,
|
||||
hb_codepoint_t unicode,
|
||||
hb_codepoint_t variation_selector,
|
||||
hb_codepoint_t unicode HB_UNUSED,
|
||||
hb_codepoint_t variation_selector HB_UNUSED,
|
||||
hb_codepoint_t *glyph,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
|
@ -276,7 +289,7 @@ hb_font_get_glyph_v_advances_default (hb_font_t* font,
|
|||
static hb_bool_t
|
||||
hb_font_get_glyph_h_origin_nil (hb_font_t *font HB_UNUSED,
|
||||
void *font_data HB_UNUSED,
|
||||
hb_codepoint_t glyph,
|
||||
hb_codepoint_t glyph HB_UNUSED,
|
||||
hb_position_t *x,
|
||||
hb_position_t *y,
|
||||
void *user_data HB_UNUSED)
|
||||
|
@ -301,7 +314,7 @@ hb_font_get_glyph_h_origin_default (hb_font_t *font,
|
|||
static hb_bool_t
|
||||
hb_font_get_glyph_v_origin_nil (hb_font_t *font HB_UNUSED,
|
||||
void *font_data HB_UNUSED,
|
||||
hb_codepoint_t glyph,
|
||||
hb_codepoint_t glyph HB_UNUSED,
|
||||
hb_position_t *x,
|
||||
hb_position_t *y,
|
||||
void *user_data HB_UNUSED)
|
||||
|
@ -326,8 +339,8 @@ hb_font_get_glyph_v_origin_default (hb_font_t *font,
|
|||
static hb_position_t
|
||||
hb_font_get_glyph_h_kerning_nil (hb_font_t *font HB_UNUSED,
|
||||
void *font_data HB_UNUSED,
|
||||
hb_codepoint_t left_glyph,
|
||||
hb_codepoint_t right_glyph,
|
||||
hb_codepoint_t left_glyph HB_UNUSED,
|
||||
hb_codepoint_t right_glyph HB_UNUSED,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
return 0;
|
||||
|
@ -345,8 +358,8 @@ hb_font_get_glyph_h_kerning_default (hb_font_t *font,
|
|||
static hb_position_t
|
||||
hb_font_get_glyph_v_kerning_nil (hb_font_t *font HB_UNUSED,
|
||||
void *font_data HB_UNUSED,
|
||||
hb_codepoint_t top_glyph,
|
||||
hb_codepoint_t bottom_glyph,
|
||||
hb_codepoint_t top_glyph HB_UNUSED,
|
||||
hb_codepoint_t bottom_glyph HB_UNUSED,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
return 0;
|
||||
|
@ -364,7 +377,7 @@ hb_font_get_glyph_v_kerning_default (hb_font_t *font,
|
|||
static hb_bool_t
|
||||
hb_font_get_glyph_extents_nil (hb_font_t *font HB_UNUSED,
|
||||
void *font_data HB_UNUSED,
|
||||
hb_codepoint_t glyph,
|
||||
hb_codepoint_t glyph HB_UNUSED,
|
||||
hb_glyph_extents_t *extents,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
|
@ -389,8 +402,8 @@ hb_font_get_glyph_extents_default (hb_font_t *font,
|
|||
static hb_bool_t
|
||||
hb_font_get_glyph_contour_point_nil (hb_font_t *font HB_UNUSED,
|
||||
void *font_data HB_UNUSED,
|
||||
hb_codepoint_t glyph,
|
||||
unsigned int point_index,
|
||||
hb_codepoint_t glyph HB_UNUSED,
|
||||
unsigned int point_index HB_UNUSED,
|
||||
hb_position_t *x,
|
||||
hb_position_t *y,
|
||||
void *user_data HB_UNUSED)
|
||||
|
@ -416,7 +429,7 @@ hb_font_get_glyph_contour_point_default (hb_font_t *font,
|
|||
static hb_bool_t
|
||||
hb_font_get_glyph_name_nil (hb_font_t *font HB_UNUSED,
|
||||
void *font_data HB_UNUSED,
|
||||
hb_codepoint_t glyph,
|
||||
hb_codepoint_t glyph HB_UNUSED,
|
||||
char *name, unsigned int size,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
|
@ -436,7 +449,8 @@ hb_font_get_glyph_name_default (hb_font_t *font,
|
|||
static hb_bool_t
|
||||
hb_font_get_glyph_from_name_nil (hb_font_t *font HB_UNUSED,
|
||||
void *font_data HB_UNUSED,
|
||||
const char *name, int len, /* -1 means nul-terminated */
|
||||
const char *name HB_UNUSED,
|
||||
int len HB_UNUSED, /* -1 means nul-terminated */
|
||||
hb_codepoint_t *glyph,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
|
|
|
@ -110,7 +110,7 @@ typedef struct hb_glyph_extents_t
|
|||
/* func types */
|
||||
|
||||
typedef hb_bool_t (*hb_font_get_font_extents_func_t) (hb_font_t *font, void *font_data,
|
||||
hb_font_extents_t *metrics,
|
||||
hb_font_extents_t *extents,
|
||||
void *user_data);
|
||||
typedef hb_font_get_font_extents_func_t hb_font_get_font_h_extents_func_t;
|
||||
typedef hb_font_get_font_extents_func_t hb_font_get_font_v_extents_func_t;
|
||||
|
|
|
@ -62,7 +62,6 @@
|
|||
struct hb_font_funcs_t
|
||||
{
|
||||
hb_object_header_t header;
|
||||
ASSERT_POD ();
|
||||
|
||||
hb_bool_t immutable;
|
||||
|
||||
|
@ -102,7 +101,6 @@ DECLARE_NULL_INSTANCE (hb_font_funcs_t);
|
|||
struct hb_font_t
|
||||
{
|
||||
hb_object_header_t header;
|
||||
ASSERT_POD ();
|
||||
|
||||
hb_bool_t immutable;
|
||||
|
||||
|
|
11
src/hb-ft.cc
11
src/hb-ft.cc
|
@ -40,6 +40,17 @@
|
|||
#include FT_TRUETYPE_TABLES_H
|
||||
|
||||
|
||||
/**
|
||||
* SECTION:hb-ft
|
||||
* @title: hb-ft
|
||||
* @short_description: FreeType integration
|
||||
* @include: hb-ft.h
|
||||
*
|
||||
* Functions for using HarfBuzz with the FreeType library to provide face and
|
||||
* font data.
|
||||
**/
|
||||
|
||||
|
||||
/* TODO:
|
||||
*
|
||||
* In general, this file does a fine job of what it's supposed to do.
|
||||
|
|
|
@ -33,6 +33,16 @@
|
|||
#include "hb-machinery.hh"
|
||||
|
||||
|
||||
/**
|
||||
* SECTION:hb-glib
|
||||
* @title: hb-glib
|
||||
* @short_description: GLib integration
|
||||
* @include: hb-glib.h
|
||||
*
|
||||
* Functions for using HarfBuzz with the GLib library to provide Unicode data.
|
||||
**/
|
||||
|
||||
|
||||
#if !GLIB_CHECK_VERSION(2,29,14)
|
||||
static const hb_script_t
|
||||
glib_script_to_script[] =
|
||||
|
|
|
@ -26,6 +26,18 @@
|
|||
|
||||
#include "hb.hh"
|
||||
|
||||
|
||||
/**
|
||||
* SECTION:hb-gobject
|
||||
* @title: hb-gobject
|
||||
* @short_description: GObject integration
|
||||
* @include: hb-gobject.h
|
||||
*
|
||||
* Functions for using HarfBuzz with the GObject library to provide
|
||||
* type data.
|
||||
**/
|
||||
|
||||
|
||||
/* g++ didn't like older gtype.h gcc-only code path. */
|
||||
#include <glib.h>
|
||||
#if !GLIB_CHECK_VERSION(2,29,16)
|
||||
|
|
|
@ -33,7 +33,17 @@
|
|||
|
||||
#include <graphite2/Segment.h>
|
||||
|
||||
#include "hb-ot-tag.h"
|
||||
#include "hb-ot-layout.h"
|
||||
|
||||
|
||||
/**
|
||||
* SECTION:hb-graphite2
|
||||
* @title: hb-graphite2
|
||||
* @short_description: Graphite2 integration
|
||||
* @include: hb-graphite2.h
|
||||
*
|
||||
* Functions for using HarfBuzz with the Graphite2 fonts.
|
||||
**/
|
||||
|
||||
|
||||
HB_SHAPER_DATA_ENSURE_DEFINE(graphite2, face)
|
||||
|
@ -197,11 +207,14 @@ _hb_graphite2_shaper_font_data_destroy (hb_graphite2_font_data_t *data HB_UNUSED
|
|||
{
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* hb_graphite2_font_get_gr_font:
|
||||
*
|
||||
* Since: 0.9.10
|
||||
* Deprecated: 1.4.2
|
||||
*/
|
||||
gr_font *
|
||||
hb_graphite2_font_get_gr_font (hb_font_t *font)
|
||||
hb_graphite2_font_get_gr_font (hb_font_t *font HB_UNUSED)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -243,7 +256,7 @@ struct hb_graphite2_cluster_t {
|
|||
};
|
||||
|
||||
hb_bool_t
|
||||
_hb_graphite2_shape (hb_shape_plan_t *shape_plan,
|
||||
_hb_graphite2_shape (hb_shape_plan_t *shape_plan HB_UNUSED,
|
||||
hb_font_t *font,
|
||||
hb_buffer_t *buffer,
|
||||
const hb_feature_t *features,
|
||||
|
|
|
@ -40,6 +40,16 @@
|
|||
#include <unicode/uversion.h>
|
||||
|
||||
|
||||
/**
|
||||
* SECTION:hb-icu
|
||||
* @title: hb-icu
|
||||
* @short_description: ICU integration
|
||||
* @include: hb-icu.h
|
||||
*
|
||||
* Functions for using HarfBuzz with the ICU library to provide Unicode data.
|
||||
**/
|
||||
|
||||
|
||||
hb_script_t
|
||||
hb_icu_script_to_script (UScriptCode script)
|
||||
{
|
||||
|
|
|
@ -82,10 +82,8 @@ static inline Type& StructAfter(TObject &X)
|
|||
/* Check _assertion in a method environment */
|
||||
#define _DEFINE_INSTANCE_ASSERTION1(_line, _assertion) \
|
||||
inline void _instance_assertion_on_line_##_line (void) const \
|
||||
{ \
|
||||
static_assert ((_assertion), ""); \
|
||||
ASSERT_INSTANCE_POD (*this); /* Make sure it's POD. */ \
|
||||
}
|
||||
{ static_assert ((_assertion), ""); } \
|
||||
static_assert (true, "") /* So we require semicolon here. */
|
||||
# define _DEFINE_INSTANCE_ASSERTION0(_line, _assertion) _DEFINE_INSTANCE_ASSERTION1 (_line, _assertion)
|
||||
# define DEFINE_INSTANCE_ASSERTION(_assertion) _DEFINE_INSTANCE_ASSERTION0 (__LINE__, _assertion)
|
||||
|
||||
|
@ -99,9 +97,9 @@ static inline Type& StructAfter(TObject &X)
|
|||
|
||||
#define DEFINE_SIZE_STATIC(size) \
|
||||
DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size)); \
|
||||
inline unsigned int get_size (void) const { return (size); } \
|
||||
enum { static_size = (size) }; \
|
||||
enum { min_size = (size) }; \
|
||||
inline unsigned int get_size (void) const { return (size); }
|
||||
enum { min_size = (size) }
|
||||
|
||||
#define DEFINE_SIZE_UNION(size, _member) \
|
||||
DEFINE_INSTANCE_ASSERTION (0*sizeof(this->u._member.static_size) + sizeof(this->u._member) == (size)); \
|
||||
|
@ -114,11 +112,11 @@ static inline Type& StructAfter(TObject &X)
|
|||
#define DEFINE_SIZE_ARRAY(size, array) \
|
||||
DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size) + VAR * sizeof (array[0])); \
|
||||
DEFINE_COMPILES_ASSERTION ((void) array[0].static_size) \
|
||||
enum { 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.min_size + array.get_size ()); }
|
||||
inline unsigned int get_size (void) const { return (size - array.min_size + array.get_size ()); } \
|
||||
DEFINE_SIZE_ARRAY(size, array)
|
||||
|
||||
#define DEFINE_SIZE_ARRAY2(size, array1, array2) \
|
||||
DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size) + sizeof (this->array1[0]) + sizeof (this->array2[0])); \
|
||||
|
@ -136,7 +134,7 @@ struct hb_dispatch_context_t
|
|||
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; }
|
||||
inline bool may_dispatch (const T *obj HB_UNUSED, const F *format HB_UNUSED) { return true; }
|
||||
static return_t no_dispatch_return_value (void) { return Context::default_return_value (); }
|
||||
};
|
||||
|
||||
|
@ -235,7 +233,7 @@ struct hb_sanitize_context_t :
|
|||
|
||||
inline const char *get_name (void) { return "SANITIZE"; }
|
||||
template <typename T, typename F>
|
||||
inline bool may_dispatch (const T *obj, const F *format)
|
||||
inline bool may_dispatch (const T *obj HB_UNUSED, const F *format)
|
||||
{ return format->sanitize (this); }
|
||||
template <typename T>
|
||||
inline return_t dispatch (const T &obj) { return obj.sanitize (this); }
|
||||
|
@ -612,7 +610,7 @@ struct Supplier
|
|||
}
|
||||
inline Supplier (const hb_vector_t<Type> *v)
|
||||
{
|
||||
head = v->arrayZ();
|
||||
head = *v;
|
||||
len = v->len;
|
||||
stride = sizeof (Type);
|
||||
}
|
||||
|
|
|
@ -27,7 +27,16 @@
|
|||
#include "hb-map.hh"
|
||||
|
||||
|
||||
/* Public API */
|
||||
/**
|
||||
* SECTION:hb-map
|
||||
* @title: hb-map
|
||||
* @short_description: Object representing integer to integer mapping
|
||||
* @include: hb.h
|
||||
*
|
||||
* Map objects are integer-to-integer hash-maps. Currently they are
|
||||
* not used in the HarfBuzz public API, but are provided for client's
|
||||
* use if desired.
|
||||
**/
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
@ -44,6 +44,10 @@ inline uint32_t Hash (const T &v)
|
|||
|
||||
struct hb_map_t
|
||||
{
|
||||
HB_NO_COPY_ASSIGN (hb_map_t);
|
||||
inline hb_map_t (void) { init (); }
|
||||
inline ~hb_map_t (void) { fini (); }
|
||||
|
||||
struct item_t
|
||||
{
|
||||
hb_codepoint_t key;
|
||||
|
@ -77,9 +81,11 @@ struct hb_map_t
|
|||
inline void fini_shallow (void)
|
||||
{
|
||||
free (items);
|
||||
items = nullptr;
|
||||
}
|
||||
inline void fini (void)
|
||||
{
|
||||
population = occupancy = 0;
|
||||
hb_object_fini (this);
|
||||
fini_shallow ();
|
||||
}
|
||||
|
|
|
@ -87,7 +87,7 @@ template <typename Type>
|
|||
static inline Type& Crap (void) {
|
||||
static_assert (sizeof (Type) <= HB_NULL_POOL_SIZE, "Increase HB_NULL_POOL_SIZE.");
|
||||
Type *obj = reinterpret_cast<Type *> (_hb_CrapPool);
|
||||
*obj = Null(Type);
|
||||
memcpy (obj, &Null(Type), sizeof (*obj));
|
||||
return *obj;
|
||||
}
|
||||
#define Crap(Type) Crap<typename hb_remove_const<typename hb_remove_reference<Type>::value>::value>()
|
||||
|
|
|
@ -195,12 +195,8 @@ struct hb_object_header_t
|
|||
{
|
||||
hb_reference_count_t ref_count;
|
||||
hb_atomic_ptr_t<hb_user_data_array_t> user_data;
|
||||
|
||||
#define HB_OBJECT_HEADER_STATIC {HB_REFERENCE_COUNT_INIT, HB_ATOMIC_PTR_INIT (nullptr)}
|
||||
|
||||
private:
|
||||
ASSERT_POD ();
|
||||
};
|
||||
#define HB_OBJECT_HEADER_STATIC {HB_REFERENCE_COUNT_INIT, HB_ATOMIC_PTR_INIT (nullptr)}
|
||||
|
||||
|
||||
/*
|
||||
|
@ -276,6 +272,7 @@ static inline void hb_object_fini (Type *obj)
|
|||
{
|
||||
user_data->fini ();
|
||||
free (user_data);
|
||||
user_data = nullptr;
|
||||
}
|
||||
}
|
||||
template <typename Type>
|
||||
|
|
|
@ -335,9 +335,14 @@ static inline Type& operator + (Base &base, OffsetTo<Type, OffsetType, has_null>
|
|||
template <typename Type>
|
||||
struct UnsizedArrayOf
|
||||
{
|
||||
HB_NO_CREATE_COPY_ASSIGN_TEMPLATE (UnsizedArrayOf, Type);
|
||||
|
||||
inline const Type& operator [] (unsigned int i) const { return arrayZ[i]; }
|
||||
inline Type& operator [] (unsigned int i) { return arrayZ[i]; }
|
||||
|
||||
template <typename T> inline operator T * (void) { return arrayZ; }
|
||||
template <typename T> inline operator const T * (void) const { return arrayZ; }
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c, unsigned int count) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
|
@ -424,6 +429,8 @@ struct UnsizedOffsetListOf : UnsizedOffsetArrayOf<Type, OffsetType, has_null>
|
|||
template <typename Type, typename LenType=HBUINT16>
|
||||
struct ArrayOf
|
||||
{
|
||||
HB_NO_CREATE_COPY_ASSIGN_TEMPLATE2 (ArrayOf, Type, LenType);
|
||||
|
||||
inline const Type *sub_array (unsigned int start_offset, unsigned int *pcount /* IN/OUT */) const
|
||||
{
|
||||
unsigned int count = len;
|
||||
|
@ -446,6 +453,10 @@ struct ArrayOf
|
|||
if (unlikely (i >= len)) return Crap(Type);
|
||||
return arrayZ[i];
|
||||
}
|
||||
|
||||
template <typename T> inline operator T * (void) { return arrayZ; }
|
||||
template <typename T> inline operator const T * (void) const { return arrayZ; }
|
||||
|
||||
inline unsigned int get_size (void) const
|
||||
{ return len.static_size + len * Type::static_size; }
|
||||
|
||||
|
@ -523,7 +534,6 @@ struct ArrayOf
|
|||
::qsort (arrayZ, len, sizeof (Type), Type::cmp);
|
||||
}
|
||||
|
||||
private:
|
||||
inline bool sanitize_shallow (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
|
@ -540,8 +550,12 @@ template <typename Type> struct LArrayOf : ArrayOf<Type, HBUINT32> {};
|
|||
typedef ArrayOf<HBUINT8, HBUINT8> PString;
|
||||
|
||||
/* Array of Offset's */
|
||||
template <typename Type, typename OffsetType=HBUINT16>
|
||||
struct OffsetArrayOf : ArrayOf<OffsetTo<Type, OffsetType> > {};
|
||||
template <typename Type>
|
||||
struct OffsetArrayOf : ArrayOf<OffsetTo<Type, HBUINT16> > {};
|
||||
template <typename Type>
|
||||
struct LOffsetArrayOf : ArrayOf<OffsetTo<Type, HBUINT32> > {};
|
||||
template <typename Type>
|
||||
struct LOffsetLArrayOf : ArrayOf<OffsetTo<Type, HBUINT32>, HBUINT32> {};
|
||||
|
||||
/* Array of offsets relative to the beginning of the array itself. */
|
||||
template <typename Type>
|
||||
|
@ -586,6 +600,8 @@ struct OffsetListOf : OffsetArrayOf<Type>
|
|||
template <typename Type, typename LenType=HBUINT16>
|
||||
struct HeadlessArrayOf
|
||||
{
|
||||
HB_NO_CREATE_COPY_ASSIGN_TEMPLATE2 (HeadlessArrayOf, Type, LenType);
|
||||
|
||||
inline const Type& operator [] (unsigned int i) const
|
||||
{
|
||||
if (unlikely (i >= lenP1 || !i)) return Null(Type);
|
||||
|
@ -650,6 +666,8 @@ struct HeadlessArrayOf
|
|||
template <typename Type, typename LenType=HBUINT16>
|
||||
struct ArrayOfM1
|
||||
{
|
||||
HB_NO_CREATE_COPY_ASSIGN_TEMPLATE2 (ArrayOfM1, Type, LenType);
|
||||
|
||||
inline const Type& operator [] (unsigned int i) const
|
||||
{
|
||||
if (unlikely (i > lenM1)) return Null(Type);
|
||||
|
@ -702,7 +720,7 @@ struct SortedArrayOf : ArrayOf<Type, LenType>
|
|||
int min = 0, max = (int) this->len - 1;
|
||||
while (min <= max)
|
||||
{
|
||||
int mid = (min + max) / 2;
|
||||
int mid = ((unsigned int) min + (unsigned int) max) / 2;
|
||||
int c = arr[mid].cmp (x);
|
||||
if (c < 0)
|
||||
max = mid - 1;
|
||||
|
@ -754,6 +772,7 @@ struct BinSearchHeader
|
|||
template <typename Type, typename LenType=HBUINT16>
|
||||
struct BinSearchArrayOf : SortedArrayOf<Type, BinSearchHeader<LenType> > {};
|
||||
|
||||
|
||||
struct VarSizedBinSearchHeader
|
||||
{
|
||||
|
||||
|
@ -779,6 +798,8 @@ struct VarSizedBinSearchHeader
|
|||
template <typename Type>
|
||||
struct VarSizedBinSearchArrayOf
|
||||
{
|
||||
HB_NO_CREATE_COPY_ASSIGN_TEMPLATE (VarSizedBinSearchArrayOf, Type);
|
||||
|
||||
inline const Type& operator [] (unsigned int i) const
|
||||
{
|
||||
if (unlikely (i >= header.nUnits)) return Null(Type);
|
||||
|
@ -825,7 +846,7 @@ struct VarSizedBinSearchArrayOf
|
|||
int min = 0, max = (int) header.nUnits - 1;
|
||||
while (min <= max)
|
||||
{
|
||||
int mid = (min + max) / 2;
|
||||
int mid = ((unsigned int) min + (unsigned int) max) / 2;
|
||||
const Type *p = (const Type *) (((const char *) &bytesZ) + (mid * size));
|
||||
int c = p->cmp (key);
|
||||
if (c < 0)
|
||||
|
|
|
@ -228,6 +228,10 @@ struct CmapSubtableFormat4
|
|||
|
||||
struct accelerator_t
|
||||
{
|
||||
inline accelerator_t (void) {}
|
||||
inline accelerator_t (const CmapSubtableFormat4 *subtable) { init (subtable); }
|
||||
inline ~accelerator_t (void) { fini (); }
|
||||
|
||||
inline void init (const CmapSubtableFormat4 *subtable)
|
||||
{
|
||||
segCount = subtable->segCountX2 / 2;
|
||||
|
@ -249,7 +253,7 @@ struct CmapSubtableFormat4
|
|||
unsigned int i;
|
||||
while (min <= max)
|
||||
{
|
||||
int mid = (min + max) / 2;
|
||||
int mid = ((unsigned int) min + (unsigned int) max) / 2;
|
||||
if (codepoint < startCount[mid])
|
||||
max = mid - 1;
|
||||
else if (codepoint > endCount[mid])
|
||||
|
@ -327,12 +331,12 @@ struct CmapSubtableFormat4
|
|||
|
||||
inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
|
||||
{
|
||||
hb_auto_t<accelerator_t> accel (this);
|
||||
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);
|
||||
accelerator_t accel (this);
|
||||
accel.collect_unicodes (out);
|
||||
}
|
||||
|
||||
|
@ -495,7 +499,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, group_data.len);
|
||||
if (unlikely (!groups.serialize (c, supplier, group_data.len))) return_trace (false);
|
||||
return true;
|
||||
}
|
||||
|
@ -851,18 +855,6 @@ struct cmap
|
|||
|
||||
struct subset_plan
|
||||
{
|
||||
subset_plan(void)
|
||||
{
|
||||
format4_segments.init();
|
||||
format12_groups.init();
|
||||
}
|
||||
|
||||
~subset_plan(void)
|
||||
{
|
||||
format4_segments.fini();
|
||||
format12_groups.fini();
|
||||
}
|
||||
|
||||
inline size_t final_size() const
|
||||
{
|
||||
return 4 // header
|
||||
|
@ -871,9 +863,7 @@ struct cmap
|
|||
+ CmapSubtableFormat12::get_sub_table_size (this->format12_groups);
|
||||
}
|
||||
|
||||
// Format 4
|
||||
hb_vector_t<CmapSubtableFormat4::segment_plan> format4_segments;
|
||||
// Format 12
|
||||
hb_vector_t<CmapSubtableLongGroup> format12_groups;
|
||||
};
|
||||
|
||||
|
|
|
@ -166,7 +166,7 @@ struct IndexSubtable
|
|||
}
|
||||
}
|
||||
|
||||
inline bool get_extents (hb_glyph_extents_t *extents) const
|
||||
inline bool get_extents (hb_glyph_extents_t *extents HB_UNUSED) const
|
||||
{
|
||||
switch (u.header.indexFormat) {
|
||||
case 2: case 5: /* TODO */
|
||||
|
@ -343,26 +343,30 @@ struct CBLC
|
|||
}
|
||||
|
||||
protected:
|
||||
const IndexSubtableRecord *find_table (hb_codepoint_t glyph,
|
||||
unsigned int *x_ppem, unsigned int *y_ppem,
|
||||
const void **base) const
|
||||
const BitmapSizeTable &choose_strike (hb_font_t *font) const
|
||||
{
|
||||
/* TODO: Make it possible to select strike. */
|
||||
unsigned count = sizeTables.len;
|
||||
if (unlikely (!count))
|
||||
return Null(BitmapSizeTable);
|
||||
|
||||
unsigned int count = sizeTables.len;
|
||||
for (uint32_t i = 0; i < count; ++i)
|
||||
unsigned int requested_ppem = MAX (font->x_ppem, font->y_ppem);
|
||||
if (!requested_ppem)
|
||||
requested_ppem = 1<<30; /* Choose largest strike. */
|
||||
unsigned int best_i = 0;
|
||||
unsigned int best_ppem = MAX (sizeTables[0].ppemX, sizeTables[0].ppemY);
|
||||
|
||||
for (unsigned int i = 1; i < count; i++)
|
||||
{
|
||||
unsigned int startGlyphIndex = sizeTables.arrayZ[i].startGlyphIndex;
|
||||
unsigned int endGlyphIndex = sizeTables.arrayZ[i].endGlyphIndex;
|
||||
if (startGlyphIndex <= glyph && glyph <= endGlyphIndex)
|
||||
unsigned int ppem = MAX (sizeTables[i].ppemX, sizeTables[i].ppemY);
|
||||
if ((requested_ppem <= ppem && ppem < best_ppem) ||
|
||||
(requested_ppem > best_ppem && ppem > best_ppem))
|
||||
{
|
||||
*x_ppem = sizeTables[i].ppemX;
|
||||
*y_ppem = sizeTables[i].ppemY;
|
||||
return sizeTables[i].find_table (glyph, this, base);
|
||||
best_i = i;
|
||||
best_ppem = ppem;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
return sizeTables[best_i];
|
||||
}
|
||||
|
||||
protected:
|
||||
|
@ -376,13 +380,6 @@ struct CBDT
|
|||
{
|
||||
static const hb_tag_t tableTag = HB_OT_TAG_CBDT;
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (c->check_struct (this) &&
|
||||
likely (version.major == 2 || version.major == 3));
|
||||
}
|
||||
|
||||
struct accelerator_t
|
||||
{
|
||||
inline void init (hb_face_t *face)
|
||||
|
@ -409,16 +406,16 @@ struct CBDT
|
|||
hb_blob_destroy (this->cbdt_blob);
|
||||
}
|
||||
|
||||
inline bool get_extents (hb_codepoint_t glyph, hb_glyph_extents_t *extents) const
|
||||
inline bool get_extents (hb_font_t *font, hb_codepoint_t glyph,
|
||||
hb_glyph_extents_t *extents) const
|
||||
{
|
||||
unsigned int x_ppem = upem, y_ppem = upem; /* TODO Use font ppem if available. */
|
||||
|
||||
if (!cblc)
|
||||
return false; // Not a color bitmap font.
|
||||
return false;
|
||||
|
||||
const void *base;
|
||||
const IndexSubtableRecord *subtable_record = this->cblc->find_table (glyph, &x_ppem, &y_ppem, &base);
|
||||
if (!subtable_record || !x_ppem || !y_ppem)
|
||||
const BitmapSizeTable &strike = this->cblc->choose_strike (font);
|
||||
const IndexSubtableRecord *subtable_record = strike.find_table (glyph, cblc, &base);
|
||||
if (!subtable_record || !strike.ppemX || !strike.ppemY)
|
||||
return false;
|
||||
|
||||
if (subtable_record->get_extents (extents, base))
|
||||
|
@ -437,80 +434,94 @@ struct CBDT
|
|||
case 17: {
|
||||
if (unlikely (image_length < GlyphBitmapDataFormat17::min_size))
|
||||
return false;
|
||||
|
||||
const GlyphBitmapDataFormat17& glyphFormat17 =
|
||||
StructAtOffset<GlyphBitmapDataFormat17> (this->cbdt, image_offset);
|
||||
glyphFormat17.glyphMetrics.get_extents (extents);
|
||||
break;
|
||||
}
|
||||
case 18: {
|
||||
if (unlikely (image_length < GlyphBitmapDataFormat18::min_size))
|
||||
return false;
|
||||
const GlyphBitmapDataFormat18& glyphFormat18 =
|
||||
StructAtOffset<GlyphBitmapDataFormat18> (this->cbdt, image_offset);
|
||||
glyphFormat18.glyphMetrics.get_extents (extents);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// TODO: Support other image formats.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Convert to the font units. */
|
||||
extents->x_bearing *= upem / (float) x_ppem;
|
||||
extents->y_bearing *= upem / (float) y_ppem;
|
||||
extents->width *= upem / (float) x_ppem;
|
||||
extents->height *= upem / (float) y_ppem;
|
||||
/* Convert to font units. */
|
||||
double x_scale = upem / (double) strike.ppemX;
|
||||
double y_scale = upem / (double) strike.ppemY;
|
||||
extents->x_bearing = round (extents->x_bearing * x_scale);
|
||||
extents->y_bearing = round (extents->y_bearing * y_scale);
|
||||
extents->width = round (extents->width * x_scale);
|
||||
extents->height = round (extents->height * y_scale);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void dump (void (*callback) (const uint8_t* data, unsigned int length,
|
||||
unsigned int group, unsigned int gid)) const
|
||||
inline hb_blob_t* reference_png (hb_font_t *font,
|
||||
hb_codepoint_t glyph) const
|
||||
{
|
||||
if (!cblc)
|
||||
return; // Not a color bitmap font.
|
||||
return hb_blob_get_empty ();
|
||||
|
||||
const void *base;
|
||||
const BitmapSizeTable &strike = this->cblc->choose_strike (font);
|
||||
const IndexSubtableRecord *subtable_record = strike.find_table (glyph, cblc, &base);
|
||||
if (!subtable_record || !strike.ppemX || !strike.ppemY)
|
||||
return hb_blob_get_empty ();
|
||||
|
||||
unsigned int image_offset = 0, image_length = 0, image_format = 0;
|
||||
if (!subtable_record->get_image_data (glyph, base, &image_offset, &image_length, &image_format))
|
||||
return hb_blob_get_empty ();
|
||||
|
||||
for (unsigned int i = 0; i < cblc->sizeTables.len; ++i)
|
||||
{
|
||||
const BitmapSizeTable &sizeTable = cblc->sizeTables[i];
|
||||
const IndexSubtableArray &subtable_array = cblc+sizeTable.indexSubtableArrayOffset;
|
||||
for (unsigned int j = 0; j < sizeTable.numberOfIndexSubtables; ++j)
|
||||
{
|
||||
const IndexSubtableRecord &subtable_record = subtable_array.indexSubtablesZ[j];
|
||||
for (unsigned int gid = subtable_record.firstGlyphIndex;
|
||||
gid <= subtable_record.lastGlyphIndex; ++gid)
|
||||
{
|
||||
unsigned int image_offset = 0, image_length = 0, image_format = 0;
|
||||
if (unlikely (image_offset > cbdt_len || cbdt_len - image_offset < image_length))
|
||||
return hb_blob_get_empty ();
|
||||
|
||||
if (!subtable_record.get_image_data (gid, &subtable_array,
|
||||
&image_offset, &image_length, &image_format))
|
||||
continue;
|
||||
|
||||
switch (image_format)
|
||||
{
|
||||
case 17: {
|
||||
const GlyphBitmapDataFormat17& glyphFormat17 =
|
||||
StructAtOffset<GlyphBitmapDataFormat17> (this->cbdt, image_offset);
|
||||
callback ((const uint8_t *) &glyphFormat17.data.arrayZ,
|
||||
glyphFormat17.data.len, i, gid);
|
||||
}
|
||||
break;
|
||||
case 18: {
|
||||
const GlyphBitmapDataFormat18& glyphFormat18 =
|
||||
StructAtOffset<GlyphBitmapDataFormat18> (this->cbdt, image_offset);
|
||||
callback ((const uint8_t *) &glyphFormat18.data.arrayZ,
|
||||
glyphFormat18.data.len, i, gid);
|
||||
}
|
||||
break;
|
||||
case 19: {
|
||||
const GlyphBitmapDataFormat19& glyphFormat19 =
|
||||
StructAtOffset<GlyphBitmapDataFormat19> (this->cbdt, image_offset);
|
||||
callback ((const uint8_t *) &glyphFormat19.data.arrayZ,
|
||||
glyphFormat19.data.len, i, gid);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
switch (image_format)
|
||||
{
|
||||
case 17: {
|
||||
if (unlikely (image_length < GlyphBitmapDataFormat17::min_size))
|
||||
return hb_blob_get_empty ();
|
||||
const GlyphBitmapDataFormat17& glyphFormat17 =
|
||||
StructAtOffset<GlyphBitmapDataFormat17> (this->cbdt, image_offset);
|
||||
return hb_blob_create_sub_blob (cbdt_blob,
|
||||
image_offset + GlyphBitmapDataFormat17::min_size,
|
||||
glyphFormat17.data.len);
|
||||
}
|
||||
case 18: {
|
||||
if (unlikely (image_length < GlyphBitmapDataFormat18::min_size))
|
||||
return hb_blob_get_empty ();
|
||||
const GlyphBitmapDataFormat18& glyphFormat18 =
|
||||
StructAtOffset<GlyphBitmapDataFormat18> (this->cbdt, image_offset);
|
||||
return hb_blob_create_sub_blob (cbdt_blob,
|
||||
image_offset + GlyphBitmapDataFormat18::min_size,
|
||||
glyphFormat18.data.len);
|
||||
}
|
||||
case 19: {
|
||||
if (unlikely (image_length < GlyphBitmapDataFormat19::min_size))
|
||||
return hb_blob_get_empty ();
|
||||
const GlyphBitmapDataFormat19& glyphFormat19 =
|
||||
StructAtOffset<GlyphBitmapDataFormat19> (this->cbdt, image_offset);
|
||||
return hb_blob_create_sub_blob (cbdt_blob,
|
||||
image_offset + GlyphBitmapDataFormat19::min_size,
|
||||
glyphFormat19.data.len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return hb_blob_get_empty ();
|
||||
}
|
||||
|
||||
inline bool has_data () const
|
||||
{ return cbdt_len; }
|
||||
|
||||
private:
|
||||
hb_blob_t *cblc_blob;
|
||||
hb_blob_t *cbdt_blob;
|
||||
|
@ -521,6 +532,12 @@ struct CBDT
|
|||
unsigned int upem;
|
||||
};
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (c->check_struct (this) &&
|
||||
likely (version.major == 2 || version.major == 3));
|
||||
}
|
||||
|
||||
protected:
|
||||
FixedVersion<> version;
|
||||
|
|
|
@ -58,21 +58,21 @@ struct CPALV1Tail
|
|||
hb_array (base+paletteFlagsZ, palette_count)[palette_index];
|
||||
}
|
||||
|
||||
inline unsigned int
|
||||
inline hb_ot_name_id_t
|
||||
get_palette_name_id (const void *base,
|
||||
unsigned int palette_index,
|
||||
unsigned int palette_count) const
|
||||
{
|
||||
if (!paletteLabelsZ) return HB_NAME_ID_INVALID;
|
||||
if (!paletteLabelsZ) return HB_OT_NAME_ID_INVALID;
|
||||
return hb_array (base+paletteLabelsZ, palette_count)[palette_index];
|
||||
}
|
||||
|
||||
inline unsigned int
|
||||
inline hb_ot_name_id_t
|
||||
get_color_name_id (const void *base,
|
||||
unsigned int color_index,
|
||||
unsigned int color_count) const
|
||||
{
|
||||
if (!colorLabelsZ) return HB_NAME_ID_INVALID;
|
||||
if (!colorLabelsZ) return HB_OT_NAME_ID_INVALID;
|
||||
return hb_array (base+colorLabelsZ, color_count)[color_index];
|
||||
}
|
||||
|
||||
|
@ -123,10 +123,10 @@ struct CPAL
|
|||
inline hb_ot_color_palette_flags_t get_palette_flags (unsigned int palette_index) const
|
||||
{ return v1 ().get_palette_flags (this, palette_index, numPalettes); }
|
||||
|
||||
inline unsigned int get_palette_name_id (unsigned int palette_index) const
|
||||
inline hb_ot_name_id_t get_palette_name_id (unsigned int palette_index) const
|
||||
{ return v1 ().get_palette_name_id (this, palette_index, numPalettes); }
|
||||
|
||||
inline unsigned int get_color_name_id (unsigned int color_index) const
|
||||
inline hb_ot_name_id_t get_color_name_id (unsigned int color_index) const
|
||||
{ return v1 ().get_color_name_id (this, color_index, numColors); }
|
||||
|
||||
inline unsigned int get_palette_colors (unsigned int palette_index,
|
||||
|
|
|
@ -62,8 +62,6 @@ struct SBIXGlyph
|
|||
|
||||
struct SBIXStrike
|
||||
{
|
||||
friend struct sbix;
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
|
@ -71,10 +69,58 @@ struct SBIXStrike
|
|||
imageOffsetsZ.sanitize_shallow (c, c->get_num_glyphs () + 1));
|
||||
}
|
||||
|
||||
protected:
|
||||
inline hb_blob_t *get_glyph_blob (unsigned int glyph_id,
|
||||
hb_blob_t *sbix_blob,
|
||||
hb_tag_t file_type,
|
||||
int *x_offset,
|
||||
int *y_offset,
|
||||
unsigned int num_glyphs,
|
||||
unsigned int *strike_ppem) const
|
||||
{
|
||||
if (unlikely (!ppem)) return hb_blob_get_empty (); /* To get Null() object out of the way. */
|
||||
|
||||
unsigned int retry_count = 8;
|
||||
unsigned int sbix_len = sbix_blob->length;
|
||||
unsigned int strike_offset = (const char *) this - (const char *) sbix_blob->data;
|
||||
assert (strike_offset < sbix_len);
|
||||
|
||||
retry:
|
||||
if (unlikely (glyph_id >= num_glyphs ||
|
||||
imageOffsetsZ[glyph_id + 1] <= imageOffsetsZ[glyph_id] ||
|
||||
imageOffsetsZ[glyph_id + 1] - imageOffsetsZ[glyph_id] <= SBIXGlyph::min_size ||
|
||||
(unsigned int) imageOffsetsZ[glyph_id + 1] > sbix_len - strike_offset))
|
||||
return hb_blob_get_empty ();
|
||||
|
||||
unsigned int glyph_offset = strike_offset + (unsigned int) imageOffsetsZ[glyph_id] + SBIXGlyph::min_size;
|
||||
unsigned int glyph_length = imageOffsetsZ[glyph_id + 1] - imageOffsetsZ[glyph_id] - SBIXGlyph::min_size;
|
||||
|
||||
const SBIXGlyph *glyph = &(this+imageOffsetsZ[glyph_id]);
|
||||
|
||||
if (glyph->graphicType == HB_TAG ('d','u','p','e'))
|
||||
{
|
||||
if (glyph_length >= 2)
|
||||
{
|
||||
glyph_id = *((HBUINT16 *) &glyph->data);
|
||||
if (retry_count--)
|
||||
goto retry;
|
||||
}
|
||||
return hb_blob_get_empty ();
|
||||
}
|
||||
|
||||
if (unlikely (file_type != glyph->graphicType))
|
||||
return hb_blob_get_empty ();
|
||||
|
||||
if (strike_ppem) *strike_ppem = ppem;
|
||||
if (x_offset) *x_offset = glyph->xOffset;
|
||||
if (y_offset) *y_offset = glyph->yOffset;
|
||||
return hb_blob_create_sub_blob (sbix_blob, glyph_offset, glyph_length);
|
||||
}
|
||||
|
||||
public:
|
||||
HBUINT16 ppem; /* The PPEM size for which this strike was designed. */
|
||||
HBUINT16 resolution; /* The device pixel density (in PPI) for which this
|
||||
* strike was designed. (E.g., 96 PPI, 192 PPI.) */
|
||||
protected:
|
||||
UnsizedArrayOf<LOffsetTo<SBIXGlyph> >
|
||||
imageOffsetsZ; /* Offset from the beginning of the strike data header
|
||||
* to bitmap data for an individual glyph ID. */
|
||||
|
@ -86,19 +132,17 @@ struct sbix
|
|||
{
|
||||
static const hb_tag_t tableTag = HB_OT_TAG_sbix;
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (likely (c->check_struct (this) && strikes.sanitize (c, this)));
|
||||
}
|
||||
inline bool has_data (void) const { return version; }
|
||||
|
||||
inline const SBIXStrike &get_strike (unsigned int i) const { return this+strikes[i]; }
|
||||
|
||||
struct accelerator_t
|
||||
{
|
||||
inline void init (hb_face_t *face)
|
||||
{
|
||||
sbix_blob = hb_sanitize_context_t().reference_table<sbix> (face);
|
||||
sbix_len = hb_blob_get_length (sbix_blob);
|
||||
sbix_table = sbix_blob->as<sbix> ();
|
||||
table = sbix_blob->as<sbix> ();
|
||||
num_glyphs = face->get_num_glyphs ();
|
||||
}
|
||||
|
||||
inline void fini (void)
|
||||
|
@ -106,42 +150,149 @@ struct sbix
|
|||
hb_blob_destroy (sbix_blob);
|
||||
}
|
||||
|
||||
inline void dump (void (*callback) (const uint8_t* data, unsigned int length,
|
||||
unsigned int group, unsigned int gid)) const
|
||||
inline bool has_data () const
|
||||
{
|
||||
for (unsigned group = 0; group < sbix_table->strikes.len; ++group)
|
||||
/* XXX Fix somehow and remove next line.
|
||||
* https://github.com/harfbuzz/harfbuzz/issues/1146 */
|
||||
if (!num_glyphs) return false;
|
||||
return table->has_data ();
|
||||
}
|
||||
|
||||
inline bool get_extents (hb_font_t *font,
|
||||
hb_codepoint_t glyph,
|
||||
hb_glyph_extents_t *extents) const
|
||||
{
|
||||
/* We only support PNG right now, and following function checks type. */
|
||||
return get_png_extents (font, glyph, extents);
|
||||
}
|
||||
|
||||
inline hb_blob_t *reference_png (hb_font_t *font,
|
||||
hb_codepoint_t glyph_id,
|
||||
int *x_offset,
|
||||
int *y_offset,
|
||||
unsigned int *available_ppem) const
|
||||
{
|
||||
return choose_strike (font).get_glyph_blob (glyph_id, sbix_blob,
|
||||
HB_TAG ('p','n','g',' '),
|
||||
x_offset, y_offset,
|
||||
num_glyphs, available_ppem);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
inline const SBIXStrike &choose_strike (hb_font_t *font) const
|
||||
{
|
||||
unsigned count = table->strikes.len;
|
||||
if (unlikely (!count))
|
||||
return Null(SBIXStrike);
|
||||
|
||||
unsigned int requested_ppem = MAX (font->x_ppem, font->y_ppem);
|
||||
if (!requested_ppem)
|
||||
requested_ppem = 1<<30; /* Choose largest strike. */
|
||||
/* TODO Add DPI sensitivity as well? */
|
||||
unsigned int best_i = 0;
|
||||
unsigned int best_ppem = table->get_strike (0).ppem;
|
||||
|
||||
for (unsigned int i = 1; i < count; i++)
|
||||
{
|
||||
const SBIXStrike &strike = sbix_table->strikes[group](sbix_table);
|
||||
for (unsigned int glyph = 0; glyph < num_glyphs; ++glyph)
|
||||
if (strike.imageOffsetsZ[glyph + 1] - strike.imageOffsetsZ[glyph] > 0)
|
||||
{
|
||||
const SBIXGlyph &sbixGlyph = strike.imageOffsetsZ[glyph]((const void *) &strike);
|
||||
callback ((const uint8_t*) &sbixGlyph.data,
|
||||
strike.imageOffsetsZ[glyph + 1] - strike.imageOffsetsZ[glyph] - 8,
|
||||
group, glyph);
|
||||
}
|
||||
unsigned int ppem = (table->get_strike (i)).ppem;
|
||||
if ((requested_ppem <= ppem && ppem < best_ppem) ||
|
||||
(requested_ppem > best_ppem && ppem > best_ppem))
|
||||
{
|
||||
best_i = i;
|
||||
best_ppem = ppem;
|
||||
}
|
||||
}
|
||||
|
||||
return table->get_strike (best_i);
|
||||
}
|
||||
|
||||
struct PNGHeader
|
||||
{
|
||||
HBUINT8 signature[8];
|
||||
struct
|
||||
{
|
||||
struct
|
||||
{
|
||||
HBUINT32 length;
|
||||
Tag type;
|
||||
} header;
|
||||
HBUINT32 width;
|
||||
HBUINT32 height;
|
||||
HBUINT8 bitDepth;
|
||||
HBUINT8 colorType;
|
||||
HBUINT8 compressionMethod;
|
||||
HBUINT8 filterMethod;
|
||||
HBUINT8 interlaceMethod;
|
||||
} IHDR;
|
||||
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (29);
|
||||
};
|
||||
|
||||
inline bool get_png_extents (hb_font_t *font,
|
||||
hb_codepoint_t glyph,
|
||||
hb_glyph_extents_t *extents) const
|
||||
{
|
||||
/* Following code is safe to call even without data (XXX currently
|
||||
* isn't. See has_data()), but faster to short-circuit. */
|
||||
if (!has_data ())
|
||||
return false;
|
||||
|
||||
int x_offset = 0, y_offset = 0;
|
||||
unsigned int strike_ppem = 0;
|
||||
hb_blob_t *blob = reference_png (font, glyph, &x_offset, &y_offset, &strike_ppem);
|
||||
|
||||
const PNGHeader &png = *blob->as<PNGHeader>();
|
||||
|
||||
extents->x_bearing = x_offset;
|
||||
extents->y_bearing = y_offset;
|
||||
extents->width = png.IHDR.width;
|
||||
extents->height = png.IHDR.height;
|
||||
|
||||
/* Convert to font units. */
|
||||
if (strike_ppem)
|
||||
{
|
||||
double scale = font->face->upem / (double) strike_ppem;
|
||||
extents->x_bearing = round (extents->x_bearing * scale);
|
||||
extents->y_bearing = round (extents->y_bearing * scale);
|
||||
extents->width = round (extents->width * scale);
|
||||
extents->height = round (extents->height * scale);
|
||||
}
|
||||
|
||||
hb_blob_destroy (blob);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
hb_blob_t *sbix_blob;
|
||||
const sbix *sbix_table;
|
||||
const sbix *table;
|
||||
|
||||
unsigned int sbix_len;
|
||||
unsigned int num_glyphs;
|
||||
};
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (likely (c->check_struct (this) &&
|
||||
version >= 1 &&
|
||||
strikes.sanitize (c, this)));
|
||||
}
|
||||
|
||||
protected:
|
||||
HBUINT16 version; /* Table version number — set to 1 */
|
||||
HBUINT16 flags; /* Bit 0: Set to 1. Bit 1: Draw outlines.
|
||||
* Bits 2 to 15: reserved (set to 0). */
|
||||
LArrayOf<LOffsetTo<SBIXStrike> >
|
||||
LOffsetLArrayOf<SBIXStrike>
|
||||
strikes; /* Offsets from the beginning of the 'sbix'
|
||||
* table to data for each individual bitmap strike. */
|
||||
public:
|
||||
DEFINE_SIZE_ARRAY (8, strikes);
|
||||
};
|
||||
|
||||
struct sbix_accelerator_t : sbix::accelerator_t {};
|
||||
|
||||
} /* namespace OT */
|
||||
|
||||
#endif /* HB_OT_COLOR_SBIX_TABLE_HH */
|
||||
|
|
|
@ -40,13 +40,21 @@ namespace OT {
|
|||
|
||||
struct SVGDocumentIndexEntry
|
||||
{
|
||||
friend struct SVG;
|
||||
inline int cmp (hb_codepoint_t g) const
|
||||
{ return g < startGlyphID ? -1 : g > endGlyphID ? 1 : 0; }
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c, const void* base) const
|
||||
inline hb_blob_t *reference_blob (hb_blob_t *svg_blob, unsigned int index_offset) const
|
||||
{
|
||||
return hb_blob_create_sub_blob (svg_blob,
|
||||
index_offset + (unsigned int) svgDoc,
|
||||
svgDocLength);
|
||||
}
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (c->check_struct (this) &&
|
||||
(base+svgDoc).sanitize (c, svgDocLength));
|
||||
svgDoc.sanitize (c, base, svgDocLength));
|
||||
}
|
||||
|
||||
protected:
|
||||
|
@ -57,48 +65,23 @@ struct SVGDocumentIndexEntry
|
|||
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.
|
||||
HBUINT32 svgDocLength; /* Length of the SVG document.
|
||||
* Must be non-zero. */
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (12);
|
||||
};
|
||||
|
||||
struct SVGDocumentIndex
|
||||
{
|
||||
friend struct SVG;
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (c->check_struct (this) &&
|
||||
entries.sanitize (c, this));
|
||||
}
|
||||
|
||||
protected:
|
||||
ArrayOf<SVGDocumentIndexEntry>
|
||||
entries; /* Array of SVG Document Index Entries. */
|
||||
public:
|
||||
DEFINE_SIZE_ARRAY (2, entries);
|
||||
};
|
||||
|
||||
struct SVG
|
||||
{
|
||||
static const hb_tag_t tableTag = HB_OT_TAG_SVG;
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (likely (c->check_struct (this) &&
|
||||
(this+svgDocIndex).sanitize (c)));
|
||||
}
|
||||
|
||||
struct accelerator_t
|
||||
{
|
||||
inline void init (hb_face_t *face)
|
||||
{
|
||||
svg_blob = hb_sanitize_context_t().reference_table<SVG> (face);
|
||||
svg_len = hb_blob_get_length (svg_blob);
|
||||
svg = svg_blob->as<SVG> ();
|
||||
table = svg_blob->as<SVG> ();
|
||||
}
|
||||
|
||||
inline void fini (void)
|
||||
|
@ -106,37 +89,48 @@ struct SVG
|
|||
hb_blob_destroy (svg_blob);
|
||||
}
|
||||
|
||||
inline void
|
||||
dump (void (*callback) (const uint8_t* data, unsigned int length,
|
||||
unsigned int start_glyph, unsigned int end_glyph)) const
|
||||
inline hb_blob_t *reference_blob_for_glyph (hb_codepoint_t glyph_id) const
|
||||
{
|
||||
const SVGDocumentIndex &index = svg+svg->svgDocIndex;
|
||||
const ArrayOf<SVGDocumentIndexEntry> &entries = index.entries;
|
||||
for (unsigned int i = 0; i < entries.len; ++i)
|
||||
{
|
||||
const SVGDocumentIndexEntry &entry = entries[i];
|
||||
callback ((const uint8_t*) &entry.svgDoc (&index), entry.svgDocLength,
|
||||
entry.startGlyphID, entry.endGlyphID);
|
||||
}
|
||||
if (unlikely (!svg_len))
|
||||
return hb_blob_get_empty ();
|
||||
return table->get_glyph_entry (glyph_id).reference_blob (svg_blob, table->svgDocEntries);
|
||||
}
|
||||
|
||||
inline bool has_data () const { return svg_len; }
|
||||
|
||||
private:
|
||||
hb_blob_t *svg_blob;
|
||||
const SVG *svg;
|
||||
const SVG *table;
|
||||
|
||||
unsigned int svg_len;
|
||||
};
|
||||
|
||||
inline const SVGDocumentIndexEntry &get_glyph_entry (hb_codepoint_t glyph_id) const
|
||||
{
|
||||
const SortedArrayOf<SVGDocumentIndexEntry> &docs = this+svgDocEntries;
|
||||
return docs[docs.bsearch (glyph_id)];
|
||||
}
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (likely (c->check_struct (this) &&
|
||||
(this+svgDocEntries).sanitize_shallow (c)));
|
||||
}
|
||||
|
||||
protected:
|
||||
HBUINT16 version; /* Table version (starting at 0). */
|
||||
LOffsetTo<SVGDocumentIndex>
|
||||
svgDocIndex; /* Offset (relative to the start of the SVG table) to the
|
||||
LOffsetTo<SortedArrayOf<SVGDocumentIndexEntry> >
|
||||
svgDocEntries; /* Offset (relative to the start of the SVG table) to the
|
||||
* SVG Documents Index. Must be non-zero. */
|
||||
/* Array of SVG Document Index Entries. */
|
||||
HBUINT32 reserved; /* Set to 0. */
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (10);
|
||||
};
|
||||
|
||||
struct SVG_accelerator_t : SVG::accelerator_t {};
|
||||
|
||||
} /* namespace OT */
|
||||
|
||||
|
||||
|
|
|
@ -40,6 +40,16 @@
|
|||
#include "hb-ot-layout.hh"
|
||||
|
||||
|
||||
/**
|
||||
* SECTION:hb-ot-color
|
||||
* @title: hb-ot-color
|
||||
* @short_description: OpenType Color Fonts
|
||||
* @include: hb-ot.h
|
||||
*
|
||||
* Functions for fetching color-font information from OpenType font faces.
|
||||
**/
|
||||
|
||||
|
||||
static inline const OT::COLR&
|
||||
_get_colr (hb_face_t *face)
|
||||
{
|
||||
|
@ -47,6 +57,13 @@ _get_colr (hb_face_t *face)
|
|||
return *(hb_ot_face_data (face)->COLR.get ());
|
||||
}
|
||||
|
||||
static inline const OT::CBDT_accelerator_t&
|
||||
_get_cbdt (hb_face_t *face)
|
||||
{
|
||||
if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::CBDT_accelerator_t);
|
||||
return *(hb_ot_face_data (face)->CBDT.get ());
|
||||
}
|
||||
|
||||
static inline const OT::CPAL&
|
||||
_get_cpal (hb_face_t *face)
|
||||
{
|
||||
|
@ -54,28 +71,19 @@ _get_cpal (hb_face_t *face)
|
|||
return *(hb_ot_face_data (face)->CPAL.get ());
|
||||
}
|
||||
|
||||
#if 0
|
||||
static inline const OT::CBDT_accelerator_t&
|
||||
_get_cbdt (hb_face_t *face)
|
||||
{
|
||||
if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::CBDT_accelerator_t);
|
||||
return *(hb_ot_face_data (face)->CBDT.get ());
|
||||
}
|
||||
|
||||
static inline const OT::sbix&
|
||||
static inline const OT::sbix_accelerator_t&
|
||||
_get_sbix (hb_face_t *face)
|
||||
{
|
||||
if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::sbix);
|
||||
if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::sbix_accelerator_t);
|
||||
return *(hb_ot_face_data (face)->sbix.get ());
|
||||
}
|
||||
|
||||
static inline const OT::SVG&
|
||||
static inline const OT::SVG_accelerator_t&
|
||||
_get_svg (hb_face_t *face)
|
||||
{
|
||||
if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::SVG);
|
||||
if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::SVG_accelerator_t);
|
||||
return *(hb_ot_face_data (face)->SVG.get ());
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
|
@ -89,7 +97,7 @@ _get_svg (hb_face_t *face)
|
|||
*
|
||||
* Returns: whether CPAL table is available.
|
||||
*
|
||||
* Since: REPLACEME
|
||||
* Since: 2.1.0
|
||||
*/
|
||||
hb_bool_t
|
||||
hb_ot_color_has_palettes (hb_face_t *face)
|
||||
|
@ -104,7 +112,7 @@ hb_ot_color_has_palettes (hb_face_t *face)
|
|||
* Returns: the number of color palettes in @face, or zero if @face has
|
||||
* no colors.
|
||||
*
|
||||
* Since: REPLACEME
|
||||
* Since: 2.1.0
|
||||
*/
|
||||
unsigned int
|
||||
hb_ot_color_palette_get_count (hb_face_t *face)
|
||||
|
@ -115,17 +123,17 @@ hb_ot_color_palette_get_count (hb_face_t *face)
|
|||
/**
|
||||
* hb_ot_color_palette_get_name_id:
|
||||
* @face: a font face.
|
||||
* @palette: the index of the color palette whose name is being requested.
|
||||
* @palette_index: the index of the color palette whose name is being requested.
|
||||
*
|
||||
* Retrieves the name id of a color palette. For example, a color font can
|
||||
* have themed palettes like "Spring", "Summer", "Fall", and "Winter".
|
||||
*
|
||||
* Returns: an identifier within @face's `name` table.
|
||||
* If the requested palette has no name the result is #HB_NAME_ID_INVALID.
|
||||
* If the requested palette has no name the result is #HB_OT_NAME_ID_INVALID.
|
||||
*
|
||||
* Since: REPLACEME
|
||||
* Since: 2.1.0
|
||||
*/
|
||||
hb_name_id_t
|
||||
hb_ot_name_id_t
|
||||
hb_ot_color_palette_get_name_id (hb_face_t *face,
|
||||
unsigned int palette_index)
|
||||
{
|
||||
|
@ -134,14 +142,14 @@ hb_ot_color_palette_get_name_id (hb_face_t *face,
|
|||
|
||||
/**
|
||||
* hb_ot_color_palette_color_get_name_id:
|
||||
* @face: a font face.
|
||||
* @color_index:
|
||||
* @face: a font face.
|
||||
* @color_index: palette entry index.
|
||||
*
|
||||
* Returns: Name ID associated with a palette entry, e.g. eye color
|
||||
*
|
||||
* Since: REPLACEME
|
||||
* Since: 2.1.0
|
||||
*/
|
||||
hb_name_id_t
|
||||
hb_ot_name_id_t
|
||||
hb_ot_color_palette_color_get_name_id (hb_face_t *face,
|
||||
unsigned int color_index)
|
||||
{
|
||||
|
@ -150,12 +158,12 @@ hb_ot_color_palette_color_get_name_id (hb_face_t *face,
|
|||
|
||||
/**
|
||||
* hb_ot_color_palette_get_flags:
|
||||
* @face: a font face
|
||||
* @face: a font face
|
||||
* @palette_index: the index of the color palette whose flags are being requested
|
||||
*
|
||||
* Returns: the flags for the requested color palette.
|
||||
*
|
||||
* Since: REPLACEME
|
||||
* Since: 2.1.0
|
||||
*/
|
||||
hb_ot_color_palette_flags_t
|
||||
hb_ot_color_palette_get_flags (hb_face_t *face,
|
||||
|
@ -186,7 +194,7 @@ hb_ot_color_palette_get_flags (hb_face_t *face,
|
|||
*
|
||||
* Returns: the total number of colors in the palette.
|
||||
*
|
||||
* Since: REPLACEME
|
||||
* Since: 2.1.0
|
||||
*/
|
||||
unsigned int
|
||||
hb_ot_color_palette_get_colors (hb_face_t *face,
|
||||
|
@ -209,7 +217,7 @@ hb_ot_color_palette_get_colors (hb_face_t *face,
|
|||
*
|
||||
* Returns: whether COLR table is available.
|
||||
*
|
||||
* Since: REPLACEME
|
||||
* Since: 2.1.0
|
||||
*/
|
||||
hb_bool_t
|
||||
hb_ot_color_has_layers (hb_face_t *face)
|
||||
|
@ -219,15 +227,16 @@ hb_ot_color_has_layers (hb_face_t *face)
|
|||
|
||||
/**
|
||||
* hb_ot_color_glyph_get_layers:
|
||||
* @face: a font face.
|
||||
* @glyph:
|
||||
* @start_offset:
|
||||
* @count: (inout) (optional):
|
||||
* @layers: (array length=count) (out) (optional):
|
||||
* @face: a font face.
|
||||
* @glyph: a layered color glyph id.
|
||||
* @start_offset: starting offset of layers.
|
||||
* @count: (inout) (optional): gets number of layers available to be written on buffer
|
||||
* and returns number of written layers.
|
||||
* @layers: (array length=count) (out) (optional): layers buffer to buffer.
|
||||
*
|
||||
* Returns:
|
||||
* Returns: Total number of layers a layered color glyph have.
|
||||
*
|
||||
* Since: REPLACEME
|
||||
* Since: 2.1.0
|
||||
*/
|
||||
unsigned int
|
||||
hb_ot_color_glyph_get_layers (hb_face_t *face,
|
||||
|
@ -238,3 +247,89 @@ hb_ot_color_glyph_get_layers (hb_face_t *face,
|
|||
{
|
||||
return _get_colr (face).get_glyph_layers (glyph, start_offset, count, layers);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* SVG
|
||||
*/
|
||||
|
||||
/**
|
||||
* hb_ot_color_has_svg:
|
||||
* @face: a font face.
|
||||
*
|
||||
* Check whether @face has SVG glyph images.
|
||||
*
|
||||
* Returns true if available, false otherwise.
|
||||
*
|
||||
* Since: 2.1.0
|
||||
*/
|
||||
hb_bool_t
|
||||
hb_ot_color_has_svg (hb_face_t *face)
|
||||
{
|
||||
return _get_svg (face).has_data ();
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_ot_color_glyph_reference_svg:
|
||||
* @face: a font face.
|
||||
* @glyph: a svg glyph index.
|
||||
*
|
||||
* Get SVG document for a glyph.
|
||||
*
|
||||
* Returns: (transfer full): respective svg blob of the glyph, if available.
|
||||
*
|
||||
* Since: 2.1.0
|
||||
*/
|
||||
hb_blob_t *
|
||||
hb_ot_color_glyph_reference_svg (hb_face_t *face, hb_codepoint_t glyph)
|
||||
{
|
||||
return _get_svg (face).reference_blob_for_glyph (glyph);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* PNG: CBDT or sbix
|
||||
*/
|
||||
|
||||
/**
|
||||
* hb_ot_color_has_png:
|
||||
* @face: a font face.
|
||||
*
|
||||
* Check whether @face has PNG glyph images (either CBDT or sbix tables).
|
||||
*
|
||||
* Returns true if available, false otherwise.
|
||||
*
|
||||
* Since: 2.1.0
|
||||
*/
|
||||
hb_bool_t
|
||||
hb_ot_color_has_png (hb_face_t *face)
|
||||
{
|
||||
return _get_cbdt (face).has_data () || _get_sbix (face).has_data ();
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_ot_color_glyph_reference_png:
|
||||
* @font: a font object, not face. upem should be set on
|
||||
* that font object if one wants to get optimal png blob, otherwise
|
||||
* return the biggest one
|
||||
* @glyph: a glyph index.
|
||||
*
|
||||
* Get PNG image for a glyph.
|
||||
*
|
||||
* Returns: (transfer full): respective PNG blob of the glyph, if available.
|
||||
*
|
||||
* Since: 2.1.0
|
||||
*/
|
||||
hb_blob_t *
|
||||
hb_ot_color_glyph_reference_png (hb_font_t *font, hb_codepoint_t glyph)
|
||||
{
|
||||
hb_blob_t *blob = hb_blob_get_empty ();
|
||||
|
||||
if (_get_sbix (font->face).has_data ())
|
||||
blob = _get_sbix (font->face).reference_png (font, glyph, nullptr, nullptr, nullptr);
|
||||
|
||||
if (!blob->length && _get_cbdt (font->face).has_data ())
|
||||
blob = _get_cbdt (font->face).reference_png (font, glyph);
|
||||
|
||||
return blob;
|
||||
}
|
||||
|
|
|
@ -49,11 +49,11 @@ hb_ot_color_has_palettes (hb_face_t *face);
|
|||
HB_EXTERN unsigned int
|
||||
hb_ot_color_palette_get_count (hb_face_t *face);
|
||||
|
||||
HB_EXTERN hb_name_id_t
|
||||
HB_EXTERN hb_ot_name_id_t
|
||||
hb_ot_color_palette_get_name_id (hb_face_t *face,
|
||||
unsigned int palette_index);
|
||||
|
||||
HB_EXTERN hb_name_id_t
|
||||
HB_EXTERN hb_ot_name_id_t
|
||||
hb_ot_color_palette_color_get_name_id (hb_face_t *face,
|
||||
unsigned int color_index);
|
||||
|
||||
|
@ -66,7 +66,7 @@ hb_ot_color_palette_color_get_name_id (hb_face_t *face,
|
|||
* @HB_OT_COLOR_PALETTE_FLAG_USABLE_WITH_DARK_BACKGROUND: flag indicating that the color
|
||||
* palette is appropriate to use when displaying the font on a dark background such as black.
|
||||
*
|
||||
* Since: REPLACEME
|
||||
* Since: 2.1.0
|
||||
*/
|
||||
typedef enum { /*< flags >*/
|
||||
HB_OT_COLOR_PALETTE_FLAG_DEFAULT = 0x00000000u,
|
||||
|
@ -96,7 +96,9 @@ hb_ot_color_has_layers (hb_face_t *face);
|
|||
/**
|
||||
* hb_ot_color_layer_t:
|
||||
*
|
||||
* Since: REPLACEME
|
||||
* Pairs of glyph and color index.
|
||||
*
|
||||
* Since: 2.1.0
|
||||
**/
|
||||
typedef struct hb_ot_color_layer_t
|
||||
{
|
||||
|
@ -111,6 +113,26 @@ hb_ot_color_glyph_get_layers (hb_face_t *face,
|
|||
unsigned int *count, /* IN/OUT. May be NULL. */
|
||||
hb_ot_color_layer_t *layers /* OUT. May be NULL. */);
|
||||
|
||||
/*
|
||||
* SVG
|
||||
*/
|
||||
|
||||
HB_EXTERN hb_bool_t
|
||||
hb_ot_color_has_svg (hb_face_t *face);
|
||||
|
||||
HB_EXTERN hb_blob_t *
|
||||
hb_ot_color_glyph_reference_svg (hb_face_t *face, hb_codepoint_t glyph);
|
||||
|
||||
/*
|
||||
* PNG: CBDT or sbix
|
||||
*/
|
||||
|
||||
HB_EXTERN hb_bool_t
|
||||
hb_ot_color_has_png (hb_face_t *face);
|
||||
|
||||
HB_EXTERN hb_blob_t *
|
||||
hb_ot_color_glyph_reference_png (hb_font_t *font, hb_codepoint_t glyph);
|
||||
|
||||
|
||||
HB_END_DECLS
|
||||
|
||||
|
|
|
@ -32,8 +32,11 @@
|
|||
#include "hb-ot-cff2-table.hh"
|
||||
#include "hb-ot-hmtx-table.hh"
|
||||
#include "hb-ot-kern-table.hh"
|
||||
#include "hb-ot-name-table.hh"
|
||||
#include "hb-ot-post-table.hh"
|
||||
#include "hb-ot-color-cbdt-table.hh"
|
||||
#include "hb-ot-color-sbix-table.hh"
|
||||
#include "hb-ot-color-svg-table.hh"
|
||||
#include "hb-ot-layout-gdef-table.hh"
|
||||
#include "hb-ot-layout-gsub-table.hh"
|
||||
#include "hb-ot-layout-gpos-table.hh"
|
||||
|
|
|
@ -45,10 +45,14 @@
|
|||
* This is as good as any place. */
|
||||
#define HB_OT_TABLES \
|
||||
/* OpenType shaping. */ \
|
||||
HB_OT_ACCELERATOR(OT, GDEF) \
|
||||
HB_OT_ACCELERATOR(OT, GSUB) \
|
||||
HB_OT_ACCELERATOR(OT, GPOS) \
|
||||
HB_OT_TABLE(OT, JSTF) \
|
||||
HB_OT_TABLE(OT, BASE) \
|
||||
/* AAT shaping. */ \
|
||||
HB_OT_TABLE(AAT, morx) \
|
||||
HB_OT_TABLE(AAT, mort) \
|
||||
HB_OT_TABLE(AAT, kerx) \
|
||||
HB_OT_TABLE(AAT, ankr) \
|
||||
HB_OT_TABLE(AAT, trak) \
|
||||
|
@ -59,9 +63,6 @@
|
|||
/* 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) \
|
||||
|
@ -71,12 +72,14 @@
|
|||
HB_OT_ACCELERATOR(OT, cff1) \
|
||||
HB_OT_ACCELERATOR(OT, cff2) \
|
||||
HB_OT_TABLE(OT, VORG) \
|
||||
HB_OT_ACCELERATOR(OT, name) \
|
||||
HB_OT_TABLE(AAT, ltag) \
|
||||
/* OpenType color fonts. */ \
|
||||
HB_OT_TABLE(OT, COLR) \
|
||||
HB_OT_TABLE(OT, CPAL) \
|
||||
HB_OT_ACCELERATOR(OT, CBDT) \
|
||||
HB_OT_TABLE(OT, sbix) \
|
||||
HB_OT_TABLE(OT, SVG) \
|
||||
HB_OT_ACCELERATOR(OT, sbix) \
|
||||
HB_OT_ACCELERATOR(OT, SVG) \
|
||||
/* */
|
||||
|
||||
/* Declare tables. */
|
||||
|
|
|
@ -41,6 +41,19 @@
|
|||
#include "hb-ot-cff2-table.hh"
|
||||
#include "hb-ot-vorg-table.hh"
|
||||
#include "hb-ot-color-cbdt-table.hh"
|
||||
#include "hb-ot-color-sbix-table.hh"
|
||||
|
||||
|
||||
/**
|
||||
* SECTION:hb-ot-font
|
||||
* @title: hb-ot-font
|
||||
* @short_description: OpenType font implementation
|
||||
* @include: hb-ot.h
|
||||
*
|
||||
* Functions for using OpenType fonts with hb_shape(). Not that fonts returned
|
||||
* by hb_font_create() default to using these functions, so most clients would
|
||||
* never need to call these functions directly.
|
||||
**/
|
||||
|
||||
|
||||
static hb_bool_t
|
||||
|
@ -172,15 +185,15 @@ hb_ot_get_glyph_extents (hb_font_t *font,
|
|||
void *user_data HB_UNUSED)
|
||||
{
|
||||
const hb_ot_face_data_t *ot_face = (const hb_ot_face_data_t *) font_data;
|
||||
unsigned int num_coords;
|
||||
const int *coords = hb_font_get_var_coords_normalized (font, &num_coords);
|
||||
bool ret = ot_face->glyf->get_extents (glyph, extents);
|
||||
bool ret = ot_face->sbix->get_extents (font, glyph, extents);
|
||||
if (!ret)
|
||||
ret = ot_face->glyf->get_extents (glyph, extents);
|
||||
if (!ret)
|
||||
ret = ot_face->cff1->get_extents (glyph, extents);
|
||||
if (!ret)
|
||||
ret = ot_face->cff2->get_extents (glyph, extents, coords, num_coords);
|
||||
ret = ot_face->cff2->get_extents (font, glyph, extents);
|
||||
if (!ret)
|
||||
ret = ot_face->CBDT->get_extents (glyph, extents);
|
||||
ret = ot_face->CBDT->get_extents (font, 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);
|
||||
|
|
|
@ -47,7 +47,7 @@ struct loca
|
|||
|
||||
static const hb_tag_t tableTag = HB_OT_TAG_loca;
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c) const
|
||||
inline bool sanitize (hb_sanitize_context_t *c HB_UNUSED) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (true);
|
||||
|
@ -55,6 +55,7 @@ struct loca
|
|||
|
||||
protected:
|
||||
UnsizedArrayOf<HBUINT8> dataZ; /* Location data. */
|
||||
public:
|
||||
DEFINE_SIZE_ARRAY (0, dataZ);
|
||||
};
|
||||
|
||||
|
@ -70,7 +71,7 @@ struct glyf
|
|||
{
|
||||
static const hb_tag_t tableTag = HB_OT_TAG_glyf;
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c) const
|
||||
inline bool sanitize (hb_sanitize_context_t *c HB_UNUSED) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
/* We don't check for anything specific here. The users of the
|
||||
|
@ -484,7 +485,7 @@ struct glyf
|
|||
|
||||
protected:
|
||||
UnsizedArrayOf<HBUINT8> dataZ; /* Glyphs data. */
|
||||
|
||||
public:
|
||||
DEFINE_SIZE_ARRAY (0, dataZ);
|
||||
};
|
||||
|
||||
|
|
|
@ -56,7 +56,7 @@ struct LongMetric
|
|||
template <typename T, typename H>
|
||||
struct hmtxvmtx
|
||||
{
|
||||
inline bool sanitize (hb_sanitize_context_t *c) const
|
||||
inline bool sanitize (hb_sanitize_context_t *c HB_UNUSED) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
/* We don't check for anything specific here. The users of the
|
||||
|
@ -255,7 +255,7 @@ struct hmtxvmtx
|
|||
if (glyph < num_advances)
|
||||
return table->longMetricZ[glyph].sb;
|
||||
|
||||
if (unlikely (glyph > num_metrics))
|
||||
if (unlikely (glyph >= num_metrics))
|
||||
return 0;
|
||||
|
||||
const FWORD *bearings = (const FWORD *) &table->longMetricZ[num_advances];
|
||||
|
|
|
@ -51,6 +51,14 @@
|
|||
#define HB_CLOSURE_MAX_STAGES 32
|
||||
#endif
|
||||
|
||||
#ifndef HB_MAX_SCRIPTS
|
||||
#define HB_MAX_SCRIPTS 500
|
||||
#endif
|
||||
|
||||
#ifndef HB_MAX_LANGSYS
|
||||
#define HB_MAX_LANGSYS 2000
|
||||
#endif
|
||||
|
||||
|
||||
namespace OT {
|
||||
|
||||
|
@ -555,6 +563,8 @@ struct Feature
|
|||
unsigned int *lookup_count /* IN/OUT */,
|
||||
unsigned int *lookup_tags /* OUT */) const
|
||||
{ return lookupIndex.get_indexes (start_index, lookup_count, lookup_tags); }
|
||||
inline void add_lookup_indexes_to (hb_set_t *lookup_indexes) const
|
||||
{ lookupIndex.add_indexes_to (lookup_indexes); }
|
||||
|
||||
inline const FeatureParams &get_feature_params (void) const
|
||||
{ return this+featureParams; }
|
||||
|
@ -858,8 +868,8 @@ struct CoverageFormat1
|
|||
public:
|
||||
/* 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 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]; }
|
||||
|
@ -986,7 +996,7 @@ struct CoverageFormat2
|
|||
i = c->rangeRecord.len;
|
||||
}
|
||||
}
|
||||
inline void fini (void) {};
|
||||
inline void fini (void) {}
|
||||
inline bool more (void) { return i < c->rangeRecord.len; }
|
||||
inline void next (void)
|
||||
{
|
||||
|
@ -1106,9 +1116,9 @@ struct Coverage
|
|||
|
||||
struct Iter
|
||||
{
|
||||
Iter (void) : format (0), u () {};
|
||||
inline void init (const Coverage &c_)
|
||||
inline Iter (const Coverage &c_)
|
||||
{
|
||||
memset (this, 0, sizeof (*this));
|
||||
format = c_.u.format;
|
||||
switch (format)
|
||||
{
|
||||
|
@ -1117,7 +1127,6 @@ struct Coverage
|
|||
default: return;
|
||||
}
|
||||
}
|
||||
inline void fini (void) {}
|
||||
inline bool more (void)
|
||||
{
|
||||
switch (format)
|
||||
|
@ -1633,7 +1642,7 @@ struct VariationStore
|
|||
protected:
|
||||
HBUINT16 format;
|
||||
LOffsetTo<VarRegionList> regions;
|
||||
OffsetArrayOf<VarData, HBUINT32> dataSets;
|
||||
LOffsetArrayOf<VarData> dataSets;
|
||||
public:
|
||||
DEFINE_SIZE_ARRAY (8, dataSets);
|
||||
};
|
||||
|
@ -1715,7 +1724,7 @@ struct ConditionSet
|
|||
}
|
||||
|
||||
protected:
|
||||
OffsetArrayOf<Condition, HBUINT32> conditions;
|
||||
LOffsetArrayOf<Condition> conditions;
|
||||
public:
|
||||
DEFINE_SIZE_ARRAY (2, conditions);
|
||||
};
|
||||
|
|
|
@ -663,7 +663,7 @@ struct PairSet
|
|||
int min = 0, max = (int) count - 1;
|
||||
while (min <= max)
|
||||
{
|
||||
int mid = (min + max) / 2;
|
||||
int mid = ((unsigned int) min + (unsigned int) max) / 2;
|
||||
const PairValueRecord *record = &StructAtOffset<PairValueRecord> (&firstPairValueRecord, record_size * mid);
|
||||
hb_codepoint_t mid_x = record->secondGlyph;
|
||||
if (x < mid_x)
|
||||
|
@ -719,7 +719,7 @@ 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 ())
|
||||
for (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 */
|
||||
|
@ -1715,7 +1715,7 @@ GPOS::position_start (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
|
|||
}
|
||||
|
||||
void
|
||||
GPOS::position_finish_advances (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
|
||||
GPOS::position_finish_advances (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer HB_UNUSED)
|
||||
{
|
||||
//_hb_buffer_assert_gsubgpos_vars (buffer);
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ struct SingleSubstFormat1
|
|||
inline void closure (hb_closure_context_t *c) const
|
||||
{
|
||||
TRACE_CLOSURE (this);
|
||||
for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
|
||||
for (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 */
|
||||
|
@ -62,7 +62,7 @@ struct SingleSubstFormat1
|
|||
{
|
||||
TRACE_COLLECT_GLYPHS (this);
|
||||
if (unlikely (!(this+coverage).add_coverage (c->input))) return;
|
||||
for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
|
||||
for (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 */
|
||||
|
@ -110,10 +110,10 @@ struct SingleSubstFormat1
|
|||
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_vector_t<GlyphID> from;
|
||||
hb_vector_t<GlyphID> to;
|
||||
hb_codepoint_t delta = deltaGlyphID;
|
||||
for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
|
||||
for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
|
||||
{
|
||||
if (!c->plan->glyphset->has (iter.get_glyph ()))
|
||||
continue;
|
||||
|
@ -157,7 +157,7 @@ struct SingleSubstFormat2
|
|||
{
|
||||
TRACE_CLOSURE (this);
|
||||
unsigned int count = substitute.len;
|
||||
for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
|
||||
for (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 */
|
||||
|
@ -171,7 +171,7 @@ struct SingleSubstFormat2
|
|||
TRACE_COLLECT_GLYPHS (this);
|
||||
if (unlikely (!(this+coverage).add_coverage (c->input))) return;
|
||||
unsigned int count = substitute.len;
|
||||
for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
|
||||
for (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 */
|
||||
|
@ -216,9 +216,9 @@ struct SingleSubstFormat2
|
|||
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 ())
|
||||
hb_vector_t<GlyphID> from;
|
||||
hb_vector_t<GlyphID> to;
|
||||
for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
|
||||
{
|
||||
if (!c->plan->glyphset->has (iter.get_glyph ()))
|
||||
continue;
|
||||
|
@ -395,7 +395,7 @@ struct MultipleSubstFormat1
|
|||
{
|
||||
TRACE_CLOSURE (this);
|
||||
unsigned int count = sequence.len;
|
||||
for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
|
||||
for (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 */
|
||||
|
@ -585,7 +585,7 @@ struct AlternateSubstFormat1
|
|||
{
|
||||
TRACE_CLOSURE (this);
|
||||
unsigned int count = alternateSet.len;
|
||||
for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
|
||||
for (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 */
|
||||
|
@ -599,7 +599,7 @@ struct AlternateSubstFormat1
|
|||
TRACE_COLLECT_GLYPHS (this);
|
||||
if (unlikely (!(this+coverage).add_coverage (c->input))) return;
|
||||
unsigned int count = alternateSet.len;
|
||||
for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
|
||||
for (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 */
|
||||
|
@ -906,7 +906,7 @@ 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 ())
|
||||
for (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 */
|
||||
|
@ -921,7 +921,7 @@ struct LigatureSubstFormat1
|
|||
{
|
||||
TRACE_CLOSURE (this);
|
||||
unsigned int count = ligatureSet.len;
|
||||
for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
|
||||
for (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 */
|
||||
|
@ -935,7 +935,7 @@ struct LigatureSubstFormat1
|
|||
TRACE_COLLECT_GLYPHS (this);
|
||||
if (unlikely (!(this+coverage).add_coverage (c->input))) return;
|
||||
unsigned int count = ligatureSet.len;
|
||||
for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
|
||||
for (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 */
|
||||
|
@ -1114,7 +1114,7 @@ struct ReverseChainSingleSubstFormat1
|
|||
|
||||
const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
|
||||
count = substitute.len;
|
||||
for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
|
||||
for (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 */
|
||||
|
|
|
@ -93,7 +93,7 @@ struct hb_closure_context_t :
|
|||
|
||||
hb_face_t *face;
|
||||
hb_set_t *glyphs;
|
||||
hb_auto_t<hb_set_t> out[1];
|
||||
hb_set_t out[1];
|
||||
recurse_func_t recurse_func;
|
||||
unsigned int nesting_level_left;
|
||||
unsigned int debug_depth;
|
||||
|
@ -271,7 +271,7 @@ struct hb_ot_apply_context_t :
|
|||
syllable arg1(0),
|
||||
#undef arg1
|
||||
match_func (nullptr),
|
||||
match_data (nullptr) {};
|
||||
match_data (nullptr) {}
|
||||
|
||||
typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data);
|
||||
|
||||
|
@ -1441,7 +1441,7 @@ struct ContextFormat1
|
|||
};
|
||||
|
||||
unsigned int count = ruleSet.len;
|
||||
for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
|
||||
for (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 */
|
||||
|
@ -1462,7 +1462,7 @@ struct ContextFormat1
|
|||
};
|
||||
|
||||
unsigned int count = ruleSet.len;
|
||||
for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
|
||||
for (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 */
|
||||
|
@ -2105,7 +2105,7 @@ struct ChainContextFormat1
|
|||
};
|
||||
|
||||
unsigned int count = ruleSet.len;
|
||||
for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
|
||||
for (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 */
|
||||
|
@ -2126,7 +2126,7 @@ struct ChainContextFormat1
|
|||
};
|
||||
|
||||
unsigned int count = ruleSet.len;
|
||||
for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
|
||||
for (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 */
|
||||
|
|
|
@ -38,17 +38,23 @@
|
|||
#include "hb-ot-layout-gsub-table.hh"
|
||||
#include "hb-ot-layout-gpos-table.hh"
|
||||
|
||||
// Just so we compile them; unused otherwise:
|
||||
#include "hb-ot-layout-base-table.hh"
|
||||
#include "hb-ot-layout-jstf-table.hh"
|
||||
#include "hb-ot-color-colr-table.hh"
|
||||
#include "hb-ot-color-cpal-table.hh"
|
||||
#include "hb-ot-color-sbix-table.hh"
|
||||
#include "hb-ot-color-svg-table.hh"
|
||||
#include "hb-ot-layout-base-table.hh" // Just so we compile them; unused otherwise
|
||||
#include "hb-ot-layout-jstf-table.hh" // Just so we compile them; unused otherwise
|
||||
|
||||
#include "hb-ot-kern-table.hh"
|
||||
#include "hb-ot-name-table.hh"
|
||||
|
||||
|
||||
/**
|
||||
* SECTION:hb-ot-layout
|
||||
* @title: hb-ot-layout
|
||||
* @short_description: OpenType Layout
|
||||
* @include: hb-ot.h
|
||||
*
|
||||
* Functions for querying OpenType Layout features in the font face.
|
||||
**/
|
||||
|
||||
|
||||
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);
|
||||
|
@ -555,19 +561,6 @@ hb_ot_layout_language_get_required_feature (hb_face_t *face,
|
|||
return l.has_required_feature ();
|
||||
}
|
||||
|
||||
static void
|
||||
_hb_ot_layout_language_add_feature_indexes_to (hb_face_t *face,
|
||||
hb_tag_t table_tag,
|
||||
unsigned int script_index,
|
||||
unsigned int language_index,
|
||||
hb_set_t *feature_indexes /* 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);
|
||||
l.add_feature_indexes_to (feature_indexes);
|
||||
}
|
||||
|
||||
|
||||
unsigned int
|
||||
hb_ot_layout_language_get_feature_indexes (hb_face_t *face,
|
||||
hb_tag_t table_tag,
|
||||
|
@ -665,135 +658,136 @@ unsigned int
|
|||
hb_ot_layout_table_get_lookup_count (hb_face_t *face,
|
||||
hb_tag_t table_tag)
|
||||
{
|
||||
if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return 0;
|
||||
switch (table_tag)
|
||||
return get_gsubgpos_table (face, table_tag).get_lookup_count ();
|
||||
}
|
||||
|
||||
|
||||
struct hb_collect_features_context_t
|
||||
{
|
||||
hb_collect_features_context_t (hb_face_t *face,
|
||||
hb_tag_t table_tag,
|
||||
hb_set_t *feature_indexes_)
|
||||
: g (get_gsubgpos_table (face, table_tag)),
|
||||
feature_indexes (feature_indexes_),
|
||||
script_count(0),langsys_count(0) {}
|
||||
|
||||
bool inline visited (const OT::Script &s)
|
||||
{
|
||||
case HB_OT_TAG_GSUB:
|
||||
{
|
||||
return hb_ot_face_data (face)->GSUB->lookup_count;
|
||||
}
|
||||
case HB_OT_TAG_GPOS:
|
||||
{
|
||||
return hb_ot_face_data (face)->GPOS->lookup_count;
|
||||
}
|
||||
/* We might have Null() object here. Don't want to involve
|
||||
* that in the memoize. So, detect empty objects and return. */
|
||||
if (unlikely (!s.has_default_lang_sys () &&
|
||||
!s.get_lang_sys_count ()))
|
||||
return true;
|
||||
|
||||
if (script_count++ > HB_MAX_SCRIPTS)
|
||||
return true;
|
||||
|
||||
return visited (s, visited_script);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
bool inline visited (const OT::LangSys &l)
|
||||
{
|
||||
/* We might have Null() object here. Don't want to involve
|
||||
* that in the memoize. So, detect empty objects and return. */
|
||||
if (unlikely (!l.has_required_feature () &&
|
||||
!l.get_feature_count ()))
|
||||
return true;
|
||||
|
||||
if (langsys_count++ > HB_MAX_LANGSYS)
|
||||
return true;
|
||||
|
||||
return visited (l, visited_langsys);
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
bool inline visited (const T &p, hb_set_t &visited_set)
|
||||
{
|
||||
hb_codepoint_t delta = (hb_codepoint_t) ((uintptr_t) &p - (uintptr_t) &g);
|
||||
if (visited_set.has (delta))
|
||||
return true;
|
||||
|
||||
visited_set.add (delta);
|
||||
return false;
|
||||
}
|
||||
|
||||
public:
|
||||
const OT::GSUBGPOS &g;
|
||||
hb_set_t *feature_indexes;
|
||||
|
||||
private:
|
||||
hb_set_t visited_script;
|
||||
hb_set_t visited_langsys;
|
||||
unsigned int script_count;
|
||||
unsigned int langsys_count;
|
||||
};
|
||||
|
||||
static void
|
||||
_hb_ot_layout_collect_lookups_lookups (hb_face_t *face,
|
||||
hb_tag_t table_tag,
|
||||
unsigned int feature_index,
|
||||
hb_set_t *lookup_indexes /* OUT */)
|
||||
langsys_collect_features (hb_collect_features_context_t *c,
|
||||
const OT::LangSys &l,
|
||||
const hb_tag_t *features)
|
||||
{
|
||||
unsigned int lookup_indices[32];
|
||||
unsigned int offset, len;
|
||||
if (c->visited (l)) return;
|
||||
|
||||
offset = 0;
|
||||
do {
|
||||
len = ARRAY_LENGTH (lookup_indices);
|
||||
hb_ot_layout_feature_get_lookups (face,
|
||||
table_tag,
|
||||
feature_index,
|
||||
offset, &len,
|
||||
lookup_indices);
|
||||
|
||||
for (unsigned int i = 0; i < len; i++)
|
||||
lookup_indexes->add (lookup_indices[i]);
|
||||
|
||||
offset += len;
|
||||
} while (len == ARRAY_LENGTH (lookup_indices));
|
||||
}
|
||||
|
||||
static void
|
||||
_hb_ot_layout_collect_features_features (hb_face_t *face,
|
||||
hb_tag_t table_tag,
|
||||
unsigned int script_index,
|
||||
unsigned int language_index,
|
||||
const hb_tag_t *features,
|
||||
hb_set_t *feature_indexes /* OUT */)
|
||||
{
|
||||
if (!features)
|
||||
{
|
||||
unsigned int required_feature_index;
|
||||
if (hb_ot_layout_language_get_required_feature (face,
|
||||
table_tag,
|
||||
script_index,
|
||||
language_index,
|
||||
&required_feature_index,
|
||||
nullptr))
|
||||
feature_indexes->add (required_feature_index);
|
||||
/* All features. */
|
||||
if (l.has_required_feature ())
|
||||
c->feature_indexes->add (l.get_required_feature_index ());
|
||||
|
||||
/* All features */
|
||||
_hb_ot_layout_language_add_feature_indexes_to (face,
|
||||
table_tag,
|
||||
script_index,
|
||||
language_index,
|
||||
feature_indexes);
|
||||
l.add_feature_indexes_to (c->feature_indexes);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Ugh. Any faster way? */
|
||||
for (; *features; features++)
|
||||
{
|
||||
unsigned int feature_index;
|
||||
if (hb_ot_layout_language_find_feature (face,
|
||||
table_tag,
|
||||
script_index,
|
||||
language_index,
|
||||
*features,
|
||||
&feature_index))
|
||||
feature_indexes->add (feature_index);
|
||||
hb_tag_t feature_tag = *features;
|
||||
unsigned int num_features = l.get_feature_count ();
|
||||
for (unsigned int i = 0; i < num_features; i++)
|
||||
{
|
||||
unsigned int feature_index = l.get_feature_index (i);
|
||||
|
||||
if (feature_tag == c->g.get_feature_tag (feature_index))
|
||||
{
|
||||
c->feature_indexes->add (feature_index);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_hb_ot_layout_collect_features_languages (hb_face_t *face,
|
||||
hb_tag_t table_tag,
|
||||
unsigned int script_index,
|
||||
const hb_tag_t *languages,
|
||||
const hb_tag_t *features,
|
||||
hb_set_t *feature_indexes /* OUT */)
|
||||
script_collect_features (hb_collect_features_context_t *c,
|
||||
const OT::Script &s,
|
||||
const hb_tag_t *languages,
|
||||
const hb_tag_t *features)
|
||||
{
|
||||
_hb_ot_layout_collect_features_features (face,
|
||||
table_tag,
|
||||
script_index,
|
||||
HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX,
|
||||
features,
|
||||
feature_indexes);
|
||||
if (c->visited (s)) return;
|
||||
|
||||
if (!languages)
|
||||
{
|
||||
/* All languages */
|
||||
unsigned int count = hb_ot_layout_script_get_language_tags (face,
|
||||
table_tag,
|
||||
script_index,
|
||||
0, nullptr, nullptr);
|
||||
/* All languages. */
|
||||
if (s.has_default_lang_sys ())
|
||||
langsys_collect_features (c,
|
||||
s.get_default_lang_sys (),
|
||||
features);
|
||||
|
||||
unsigned int count = s.get_lang_sys_count ();
|
||||
for (unsigned int language_index = 0; language_index < count; language_index++)
|
||||
_hb_ot_layout_collect_features_features (face,
|
||||
table_tag,
|
||||
script_index,
|
||||
language_index,
|
||||
features,
|
||||
feature_indexes);
|
||||
langsys_collect_features (c,
|
||||
s.get_lang_sys (language_index),
|
||||
features);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (; *languages; languages++)
|
||||
{
|
||||
unsigned int 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,
|
||||
language_index,
|
||||
features,
|
||||
feature_indexes);
|
||||
if (s.find_lang_sys_index (*languages, &language_index))
|
||||
langsys_collect_features (c,
|
||||
s.get_lang_sys (language_index),
|
||||
features);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -811,35 +805,27 @@ hb_ot_layout_collect_features (hb_face_t *face,
|
|||
const hb_tag_t *features,
|
||||
hb_set_t *feature_indexes /* OUT */)
|
||||
{
|
||||
hb_collect_features_context_t c (face, table_tag, feature_indexes);
|
||||
if (!scripts)
|
||||
{
|
||||
/* All scripts */
|
||||
unsigned int count = hb_ot_layout_table_get_script_tags (face,
|
||||
table_tag,
|
||||
0, nullptr, nullptr);
|
||||
/* All scripts. */
|
||||
unsigned int count = c.g.get_script_count ();
|
||||
for (unsigned int script_index = 0; script_index < count; script_index++)
|
||||
_hb_ot_layout_collect_features_languages (face,
|
||||
table_tag,
|
||||
script_index,
|
||||
languages,
|
||||
features,
|
||||
feature_indexes);
|
||||
script_collect_features (&c,
|
||||
c.g.get_script (script_index),
|
||||
languages,
|
||||
features);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (; *scripts; scripts++)
|
||||
{
|
||||
unsigned int script_index;
|
||||
if (hb_ot_layout_table_find_script (face,
|
||||
table_tag,
|
||||
*scripts,
|
||||
&script_index))
|
||||
_hb_ot_layout_collect_features_languages (face,
|
||||
table_tag,
|
||||
script_index,
|
||||
languages,
|
||||
features,
|
||||
feature_indexes);
|
||||
if (c.g.find_script_index (*scripts, &script_index))
|
||||
script_collect_features (&c,
|
||||
c.g.get_script (script_index),
|
||||
languages,
|
||||
features);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -857,10 +843,14 @@ hb_ot_layout_collect_lookups (hb_face_t *face,
|
|||
const hb_tag_t *features,
|
||||
hb_set_t *lookup_indexes /* OUT */)
|
||||
{
|
||||
hb_auto_t<hb_set_t> feature_indexes;
|
||||
const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
|
||||
|
||||
hb_set_t feature_indexes;
|
||||
hb_ot_layout_collect_features (face, table_tag, scripts, languages, features, &feature_indexes);
|
||||
for (hb_codepoint_t feature_index = HB_SET_VALUE_INVALID; hb_set_next (&feature_indexes, &feature_index);)
|
||||
_hb_ot_layout_collect_lookups_lookups (face, table_tag, feature_index, lookup_indexes);
|
||||
|
||||
for (hb_codepoint_t feature_index = HB_SET_VALUE_INVALID;
|
||||
hb_set_next (&feature_indexes, &feature_index);)
|
||||
g.get_feature (feature_index).add_lookup_indexes_to (lookup_indexes);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -993,7 +983,7 @@ hb_ot_layout_lookup_substitute_closure (hb_face_t *face,
|
|||
unsigned int lookup_index,
|
||||
hb_set_t *glyphs)
|
||||
{
|
||||
hb_auto_t<hb_map_t> done_lookups;
|
||||
hb_map_t done_lookups;
|
||||
OT::hb_closure_context_t c (face, glyphs, &done_lookups);
|
||||
|
||||
const OT::SubstLookup& l = _get_gsub (face).get_lookup (lookup_index);
|
||||
|
@ -1014,7 +1004,7 @@ hb_ot_layout_lookups_substitute_closure (hb_face_t *face,
|
|||
const hb_set_t *lookups,
|
||||
hb_set_t *glyphs)
|
||||
{
|
||||
hb_auto_t<hb_map_t> done_lookups;
|
||||
hb_map_t done_lookups;
|
||||
OT::hb_closure_context_t c (face, glyphs, &done_lookups);
|
||||
const OT::GSUB& gsub = _get_gsub (face);
|
||||
|
||||
|
@ -1072,12 +1062,12 @@ hb_ot_layout_position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer)
|
|||
* Since: 0.9.10
|
||||
**/
|
||||
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 */
|
||||
unsigned int *range_start, /* OUT. May be NULL */
|
||||
unsigned int *range_end /* OUT. May be NULL */)
|
||||
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 */
|
||||
hb_ot_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 */)
|
||||
{
|
||||
const OT::GPOS &gpos = _get_gpos (face);
|
||||
const hb_tag_t tag = HB_TAG ('s','i','z','e');
|
||||
|
@ -1105,7 +1095,7 @@ hb_ot_layout_get_size_params (hb_face_t *face,
|
|||
|
||||
if (design_size) *design_size = 0;
|
||||
if (subfamily_id) *subfamily_id = 0;
|
||||
if (subfamily_name_id) *subfamily_name_id = 0;
|
||||
if (subfamily_name_id) *subfamily_name_id = HB_OT_NAME_ID_INVALID;
|
||||
if (range_start) *range_start = 0;
|
||||
if (range_end) *range_end = 0;
|
||||
|
||||
|
@ -1137,14 +1127,14 @@ hb_ot_layout_get_size_params (hb_face_t *face,
|
|||
* 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 */)
|
||||
hb_ot_layout_feature_get_name_ids (hb_face_t *face,
|
||||
hb_tag_t table_tag,
|
||||
unsigned int feature_index,
|
||||
hb_ot_name_id_t *label_id, /* OUT. May be NULL */
|
||||
hb_ot_name_id_t *tooltip_id, /* OUT. May be NULL */
|
||||
hb_ot_name_id_t *sample_id, /* OUT. May be NULL */
|
||||
unsigned int *num_named_parameters, /* OUT. May be NULL */
|
||||
hb_ot_name_id_t *first_param_id /* OUT. May be NULL */)
|
||||
{
|
||||
const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
|
||||
|
||||
|
@ -1160,10 +1150,10 @@ hb_ot_layout_feature_get_name_ids (hb_face_t *face,
|
|||
{
|
||||
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 (tooltip_id) *tooltip_id = HB_OT_NAME_ID_INVALID;
|
||||
if (sample_id) *sample_id = HB_OT_NAME_ID_INVALID;
|
||||
if (num_named_parameters) *num_named_parameters = 0;
|
||||
if (first_param_id) *first_param_id = HB_NAME_ID_INVALID;
|
||||
if (first_param_id) *first_param_id = HB_OT_NAME_ID_INVALID;
|
||||
return true;
|
||||
}
|
||||
const OT::FeatureParamsCharacterVariants& cv_params =
|
||||
|
@ -1179,11 +1169,11 @@ hb_ot_layout_feature_get_name_ids (hb_face_t *face,
|
|||
}
|
||||
}
|
||||
|
||||
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 (label_id) *label_id = HB_OT_NAME_ID_INVALID;
|
||||
if (tooltip_id) *tooltip_id = HB_OT_NAME_ID_INVALID;
|
||||
if (sample_id) *sample_id = HB_OT_NAME_ID_INVALID;
|
||||
if (num_named_parameters) *num_named_parameters = 0;
|
||||
if (first_param_id) *first_param_id = HB_NAME_ID_INVALID;
|
||||
if (first_param_id) *first_param_id = HB_OT_NAME_ID_INVALID;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1199,7 +1189,7 @@ hb_ot_layout_feature_get_name_ids (hb_face_t *face,
|
|||
* 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
|
||||
* @characters: (out caller-allocates) (array length=char_count): A buffer pointer. The Unicode codepoints
|
||||
* of the characters for which this feature provides glyph variants.
|
||||
*
|
||||
* Fetches characters listed by designer under feature parameters for "Character
|
||||
|
|
|
@ -33,7 +33,6 @@
|
|||
|
||||
#include "hb.h"
|
||||
|
||||
#include "hb-ot-tag.h"
|
||||
#include "hb-ot-name.h"
|
||||
|
||||
HB_BEGIN_DECLS
|
||||
|
@ -46,6 +45,47 @@ HB_BEGIN_DECLS
|
|||
#define HB_OT_TAG_JSTF HB_TAG('J','S','T','F')
|
||||
|
||||
|
||||
/*
|
||||
* Script & Language tags.
|
||||
*/
|
||||
|
||||
#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_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_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 */);
|
||||
|
||||
|
||||
/*
|
||||
* GDEF
|
||||
*/
|
||||
|
@ -324,23 +364,23 @@ Xhb_ot_layout_lookup_position (hb_font_t *font,
|
|||
/* Optical 'size' feature info. Returns true if found.
|
||||
* https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#size */
|
||||
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 */
|
||||
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_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 */
|
||||
hb_ot_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_ot_layout_feature_get_name_ids (hb_face_t *face,
|
||||
hb_tag_t table_tag,
|
||||
unsigned int feature_index,
|
||||
hb_ot_name_id_t *label_id /* OUT. May be NULL */,
|
||||
hb_ot_name_id_t *tooltip_id /* OUT. May be NULL */,
|
||||
hb_ot_name_id_t *sample_id /* OUT. May be NULL */,
|
||||
unsigned int *num_named_parameters /* OUT. May be NULL */,
|
||||
hb_ot_name_id_t *first_param_id /* OUT. May be NULL */);
|
||||
|
||||
|
||||
HB_EXTERN unsigned int
|
||||
|
|
|
@ -631,7 +631,7 @@ struct MathVariants
|
|||
inline const MathGlyphConstruction &
|
||||
get_glyph_construction (hb_codepoint_t glyph,
|
||||
hb_direction_t direction,
|
||||
hb_font_t *font) const
|
||||
hb_font_t *font HB_UNUSED) const
|
||||
{
|
||||
bool vertical = HB_DIRECTION_IS_VERTICAL (direction);
|
||||
unsigned int count = vertical ? vertGlyphCount : horizGlyphCount;
|
||||
|
|
|
@ -29,6 +29,17 @@
|
|||
#include "hb-ot-face.hh"
|
||||
#include "hb-ot-math-table.hh"
|
||||
|
||||
|
||||
/**
|
||||
* SECTION:hb-ot-math
|
||||
* @title: hb-ot-math
|
||||
* @short_description: OpenType Math information
|
||||
* @include: hb-ot.h
|
||||
*
|
||||
* Functions for fetching mathematics layout data from OpenType fonts.
|
||||
**/
|
||||
|
||||
|
||||
static inline const OT::MATH&
|
||||
_get_math (hb_face_t *face)
|
||||
{
|
||||
|
|
|
@ -92,7 +92,7 @@ struct maxp
|
|||
if (version.major == 1)
|
||||
{
|
||||
const maxpV1Tail &v1 = StructAfter<maxpV1Tail> (*this);
|
||||
return v1.sanitize (c);
|
||||
return_trace (v1.sanitize (c));
|
||||
}
|
||||
return_trace (likely (version.major == 0 && version.minor == 0x5000u));
|
||||
}
|
||||
|
@ -117,7 +117,7 @@ struct maxp
|
|||
return result;
|
||||
}
|
||||
|
||||
static inline void drop_hint_fields (hb_subset_plan_t *plan, maxp *maxp_prime)
|
||||
static inline void drop_hint_fields (hb_subset_plan_t *plan HB_UNUSED, maxp *maxp_prime)
|
||||
{
|
||||
if (maxp_prime->version.major == 1)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,457 @@
|
|||
/*
|
||||
* 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-name-language.hh"
|
||||
|
||||
/* Following two tables were generated by joining FreeType, FontConfig,
|
||||
* and OpenType specification language lists, then filled in missing
|
||||
* entries using:
|
||||
* https://docs.microsoft.com/en-us/windows/desktop/intl/language-identifier-constants-and-strings
|
||||
*/
|
||||
|
||||
struct hb_ot_language_map_t
|
||||
{
|
||||
static int cmp (const void *key, const void *item)
|
||||
{
|
||||
unsigned int a = * (unsigned int *) key;
|
||||
unsigned int b = ((const hb_ot_language_map_t *) item)->code;
|
||||
return a < b ? -1 : a > b ? +1 : 0;
|
||||
}
|
||||
|
||||
uint16_t code;
|
||||
char lang[6];
|
||||
};
|
||||
|
||||
static const hb_ot_language_map_t
|
||||
hb_ms_language_map[] =
|
||||
{
|
||||
{0x0001, "ar"}, /* ??? */
|
||||
{0x0004, "zh"}, /* ??? */
|
||||
{0x0009, "en"}, /* ??? */
|
||||
{0x0401, "ar"}, /* Arabic (Saudi Arabia) */
|
||||
{0x0402, "bg"}, /* Bulgarian (Bulgaria) */
|
||||
{0x0403, "ca"}, /* Catalan (Catalan) */
|
||||
{0x0404, "zh-tw"}, /* Chinese (Taiwan) */
|
||||
{0x0405, "cs"}, /* Czech (Czech Republic) */
|
||||
{0x0406, "da"}, /* Danish (Denmark) */
|
||||
{0x0407, "de"}, /* German (Germany) */
|
||||
{0x0408, "el"}, /* Greek (Greece) */
|
||||
{0x0409, "en"}, /* English (United States) */
|
||||
{0x040A, "es"}, /* Spanish (Traditional Sort) (Spain) */
|
||||
{0x040B, "fi"}, /* Finnish (Finland) */
|
||||
{0x040C, "fr"}, /* French (France) */
|
||||
{0x040D, "he"}, /* Hebrew (Israel) */
|
||||
{0x040E, "hu"}, /* Hungarian (Hungary) */
|
||||
{0x040F, "is"}, /* Icelandic (Iceland) */
|
||||
{0x0410, "it"}, /* Italian (Italy) */
|
||||
{0x0411, "ja"}, /* Japanese (Japan) */
|
||||
{0x0412, "ko"}, /* Korean (Korea) */
|
||||
{0x0413, "nl"}, /* Dutch (Netherlands) */
|
||||
{0x0414, "no"}, /* Norwegian (Bokmal) (Norway) */
|
||||
{0x0415, "pl"}, /* Polish (Poland) */
|
||||
{0x0416, "pt"}, /* Portuguese (Brazil) */
|
||||
{0x0417, "rm"}, /* Romansh (Switzerland) */
|
||||
{0x0418, "ro"}, /* Romanian (Romania) */
|
||||
{0x0419, "ru"}, /* Russian (Russia) */
|
||||
{0x041A, "hr"}, /* Croatian (Croatia) */
|
||||
{0x041B, "sk"}, /* Slovak (Slovakia) */
|
||||
{0x041C, "sq"}, /* Albanian (Albania) */
|
||||
{0x041D, "sv"}, /* Swedish (Sweden) */
|
||||
{0x041E, "th"}, /* Thai (Thailand) */
|
||||
{0x041F, "tr"}, /* Turkish (Turkey) */
|
||||
{0x0420, "ur"}, /* Urdu (Islamic Republic of Pakistan) */
|
||||
{0x0421, "id"}, /* Indonesian (Indonesia) */
|
||||
{0x0422, "uk"}, /* Ukrainian (Ukraine) */
|
||||
{0x0423, "be"}, /* Belarusian (Belarus) */
|
||||
{0x0424, "sl"}, /* Slovenian (Slovenia) */
|
||||
{0x0425, "et"}, /* Estonian (Estonia) */
|
||||
{0x0426, "lv"}, /* Latvian (Latvia) */
|
||||
{0x0427, "lt"}, /* Lithuanian (Lithuania) */
|
||||
{0x0428, "tg"}, /* Tajik (Cyrillic) (Tajikistan) */
|
||||
{0x0429, "fa"}, /* Persian (Iran) */
|
||||
{0x042A, "vi"}, /* Vietnamese (Vietnam) */
|
||||
{0x042B, "hy"}, /* Armenian (Armenia) */
|
||||
{0x042C, "az"}, /* Azeri (Latin) (Azerbaijan) */
|
||||
{0x042D, "eu"}, /* Basque (Basque) */
|
||||
{0x042E, "hsb"}, /* Upper Sorbian (Germany) */
|
||||
{0x042F, "mk"}, /* Macedonian (FYROM) (Former Yugoslav Republic of Macedonia) */
|
||||
{0x0430, "st"}, /* ??? */
|
||||
{0x0431, "ts"}, /* ??? */
|
||||
{0x0432, "tn"}, /* Setswana (South Africa) */
|
||||
{0x0433, "ven"}, /* ??? */
|
||||
{0x0434, "xh"}, /* isiXhosa (South Africa) */
|
||||
{0x0435, "zu"}, /* isiZulu (South Africa) */
|
||||
{0x0436, "af"}, /* Afrikaans (South Africa) */
|
||||
{0x0437, "ka"}, /* Georgian (Georgia) */
|
||||
{0x0438, "fo"}, /* Faroese (Faroe Islands) */
|
||||
{0x0439, "hi"}, /* Hindi (India) */
|
||||
{0x043A, "mt"}, /* Maltese (Malta) */
|
||||
{0x043B, "se"}, /* Sami (Northern) (Norway) */
|
||||
{0x043C, "ga"}, /* ??? */
|
||||
{0x043D, "yi"}, /* ??? */
|
||||
{0x043E, "ms"}, /* Malay (Malaysia) */
|
||||
{0x043F, "kk"}, /* Kazakh (Kazakhstan) */
|
||||
{0x0440, "ky"}, /* Kyrgyz (Kyrgyzstan) */
|
||||
{0x0441, "sw"}, /* Kiswahili (Kenya) */
|
||||
{0x0442, "tk"}, /* Turkmen (Turkmenistan) */
|
||||
{0x0443, "uz"}, /* Uzbek (Latin) (Uzbekistan) */
|
||||
{0x0444, "tt"}, /* Tatar (Russia) */
|
||||
{0x0445, "bn"}, /* Bengali (India) */
|
||||
{0x0446, "pa"}, /* Punjabi (India) */
|
||||
{0x0447, "gu"}, /* Gujarati (India) */
|
||||
{0x0448, "or"}, /* Odia (formerly Oriya) (India) */
|
||||
{0x0449, "ta"}, /* Tamil (India) */
|
||||
{0x044A, "te"}, /* Telugu (India) */
|
||||
{0x044B, "kn"}, /* Kannada (India) */
|
||||
{0x044C, "ml"}, /* Malayalam (India) */
|
||||
{0x044D, "as"}, /* Assamese (India) */
|
||||
{0x044E, "mr"}, /* Marathi (India) */
|
||||
{0x044F, "sa"}, /* Sanskrit (India) */
|
||||
{0x0450, "mn"}, /* Mongolian (Cyrillic) (Mongolia) */
|
||||
{0x0451, "bo"}, /* Tibetan (PRC) */
|
||||
{0x0452, "cy"}, /* Welsh (United Kingdom) */
|
||||
{0x0453, "km"}, /* Khmer (Cambodia) */
|
||||
{0x0454, "lo"}, /* Lao (Lao P.D.R.) */
|
||||
{0x0455, "my"}, /* ??? */
|
||||
{0x0456, "gl"}, /* Galician (Galician) */
|
||||
{0x0457, "kok"}, /* Konkani (India) */
|
||||
{0x0458, "mni"}, /* ??? */
|
||||
{0x0459, "sd"}, /* ??? */
|
||||
{0x045A, "syr"}, /* Syriac (Syria) */
|
||||
{0x045B, "si"}, /* Sinhala (Sri Lanka) */
|
||||
{0x045C, "chr"}, /* ??? */
|
||||
{0x045D, "iu"}, /* Inuktitut (Canada) */
|
||||
{0x045E, "am"}, /* Amharic (Ethiopia) */
|
||||
{0x0460, "ks"}, /* ??? */
|
||||
{0x0461, "ne"}, /* Nepali (Nepal) */
|
||||
{0x0462, "fy"}, /* Frisian (Netherlands) */
|
||||
{0x0463, "ps"}, /* Pashto (Afghanistan) */
|
||||
{0x0464, "phi"}, /* Filipino (Philippines) */
|
||||
{0x0465, "div"}, /* Divehi (Maldives) */
|
||||
{0x0468, "ha"}, /* Hausa (Latin) (Nigeria) */
|
||||
{0x046A, "yo"}, /* Yoruba (Nigeria) */
|
||||
{0x046B, "quz"}, /* Quechua (Bolivia) */
|
||||
{0x046C, "nso"}, /* Sesotho sa Leboa (South Africa) */
|
||||
{0x046D, "ba"}, /* Bashkir (Russia) */
|
||||
{0x046E, "lb"}, /* Luxembourgish (Luxembourg) */
|
||||
{0x046F, "kl"}, /* Greenlandic (Greenland) */
|
||||
{0x0470, "ibo"}, /* Igbo (Nigeria) */
|
||||
{0x0471, "kau"}, /* ??? */
|
||||
{0x0472, "om"}, /* ??? */
|
||||
{0x0473, "ti"}, /* ??? */
|
||||
{0x0474, "gn"}, /* ??? */
|
||||
{0x0475, "haw"}, /* ??? */
|
||||
{0x0476, "la"}, /* ??? */
|
||||
{0x0477, "so"}, /* ??? */
|
||||
{0x0478, "ii"}, /* Yi (PRC) */
|
||||
{0x0479, "pap"}, /* ??? */
|
||||
{0x047A, "arn"}, /* Mapudungun (Chile) */
|
||||
{0x047C, "moh"}, /* Mohawk (Mohawk) */
|
||||
{0x047E, "br"}, /* Breton (France) */
|
||||
{0x0480, "ug"}, /* Uighur (PRC) */
|
||||
{0x0481, "mi"}, /* Maori (New Zealand) */
|
||||
{0x0482, "oc"}, /* Occitan (France) */
|
||||
{0x0483, "co"}, /* Corsican (France) */
|
||||
{0x0484, "gsw"}, /* Alsatian (France) */
|
||||
{0x0485, "sah"}, /* Yakut (Russia) */
|
||||
{0x0486, "qut"}, /* K'iche (Guatemala) */
|
||||
{0x0487, "rw"}, /* Kinyarwanda (Rwanda) */
|
||||
{0x0488, "wo"}, /* Wolof (Senegal) */
|
||||
{0x048C, "fa"}, /* Dari (Afghanistan) */
|
||||
{0x0801, "ar"}, /* Arabic (Iraq) */
|
||||
{0x0804, "zh-cn"}, /* Chinese (People’s Republic of China) */
|
||||
{0x0807, "de"}, /* German (Switzerland) */
|
||||
{0x0809, "en"}, /* English (United Kingdom) */
|
||||
{0x080A, "es"}, /* Spanish (Mexico) */
|
||||
{0x080C, "fr"}, /* French (Belgium) */
|
||||
{0x0810, "it"}, /* Italian (Switzerland) */
|
||||
{0x0812, "ko"}, /* ??? */
|
||||
{0x0813, "nl"}, /* Dutch (Belgium) */
|
||||
{0x0814, "nn"}, /* Norwegian (Nynorsk) (Norway) */
|
||||
{0x0816, "pt"}, /* Portuguese (Portugal) */
|
||||
{0x0818, "mo"}, /* ??? */
|
||||
{0x0819, "ru"}, /* ??? */
|
||||
{0x081A, "sr"}, /* Serbian (Latin) (Serbia) */
|
||||
{0x081D, "sv"}, /* Sweden (Finland) */
|
||||
{0x0820, "ur"}, /* ??? */
|
||||
{0x0827, "lt"}, /* ??? */
|
||||
{0x082C, "az"}, /* Azeri (Cyrillic) (Azerbaijan) */
|
||||
{0x082E, "dsb"}, /* Lower Sorbian (Germany) */
|
||||
//{0x083B, ""}, /* Sami (Northern) (Sweden) */
|
||||
{0x083C, "gd"}, /* Irish (Ireland) */
|
||||
{0x083E, "ms"}, /* Malay (Brunei Darussalam) */
|
||||
{0x0843, "uz"}, /* Uzbek (Cyrillic) (Uzbekistan) */
|
||||
{0x0845, "bn"}, /* Bengali (Bangladesh) */
|
||||
{0x0846, "ar"}, /* ??? */
|
||||
{0x0850, "mn"}, /* Mongolian (Traditional) (People’s Republic of China) */
|
||||
{0x0851, "dz"}, /* ??? */
|
||||
{0x085D, "iu"}, /* Inuktitut (Latin) (Canada) */
|
||||
{0x085F, "tzm"}, /* Tamazight (Latin) (Algeria) */
|
||||
{0x0861, "ne"}, /* ??? */
|
||||
//{0x086B, ""}, /* Quechua (Ecuador) */
|
||||
{0x0873, "ti"}, /* ??? */
|
||||
{0x0C01, "ar"}, /* Arabic (Egypt) */
|
||||
{0x0C04, "zh-hk"}, /* Chinese (Hong Kong S.A.R.) */
|
||||
{0x0C07, "de"}, /* German (Austria) */
|
||||
{0x0C09, "en"}, /* English (Australia) */
|
||||
{0x0C0A, "es"}, /* Spanish (Modern Sort) (Spain) */
|
||||
{0x0C0C, "fr"}, /* French (Canada) */
|
||||
{0x0C1A, "sr"}, /* Serbian (Cyrillic) (Serbia) */
|
||||
{0x0C3B, "se"}, /* Sami (Northern) (Finland) */
|
||||
//{0x0C6B, ""}, /* Quechua (Peru) */
|
||||
{0x1001, "ar"}, /* Arabic (Libya) */
|
||||
{0x1004, "zh-sg"}, /* Chinese (Singapore) */
|
||||
{0x1007, "de"}, /* German (Luxembourg) */
|
||||
{0x1009, "en"}, /* English (Canada) */
|
||||
{0x100A, "es"}, /* Spanish (Guatemala) */
|
||||
{0x100C, "fr"}, /* French (Switzerland) */
|
||||
{0x101A, "hr"}, /* Croatian (Latin) (Bosnia and Herzegovina) */
|
||||
{0x103B, "smj"}, /* Sami (Lule) (Norway) */
|
||||
{0x1401, "ar"}, /* Arabic (Algeria) */
|
||||
//{0x1404, ""}, /* Chinese (Macao S.A.R.) */
|
||||
{0x1407, "de"}, /* German (Liechtenstein) */
|
||||
{0x1409, "en"}, /* English (New Zealand) */
|
||||
{0x140A, "es"}, /* Spanish (Costa Rica) */
|
||||
{0x140C, "fr"}, /* French (Luxembourg) */
|
||||
{0x141A, "bs"}, /* Bosnian (Latin) (Bosnia and Herzegovina) */
|
||||
//{0x143B, ""}, /* Sami (Lule) (Sweden) */
|
||||
{0x1801, "ar"}, /* Arabic (Morocco) */
|
||||
{0x1809, "en"}, /* English (Ireland) */
|
||||
{0x180A, "es"}, /* Spanish (Panama) */
|
||||
{0x180C, "fr"}, /* French (Principality of Monaco) */
|
||||
//{0x181A, ""}, /* Serbian (Latin) (Bosnia and Herzegovina) */
|
||||
{0x183B, "sma"}, /* Sami (Southern) (Norway) */
|
||||
{0x1C01, "ar"}, /* Arabic (Tunisia) */
|
||||
{0x1C09, "en"}, /* English (South Africa) */
|
||||
{0x1C0A, "es"}, /* Spanish (Dominican Republic) */
|
||||
{0x1C0C, "fr"}, /* ??? */
|
||||
//{0x1C1A, ""}, /* Serbian (Cyrillic) (Bosnia and Herzegovina) */
|
||||
//{0x1C3B, ""}, /* Sami (Southern) (Sweden) */
|
||||
{0x2001, "ar"}, /* Arabic (Oman) */
|
||||
{0x2009, "en"}, /* English (Jamaica) */
|
||||
{0x200A, "es"}, /* Spanish (Venezuela) */
|
||||
{0x200C, "fr"}, /* ??? */
|
||||
{0x201A, "bs"}, /* Bosnian (Cyrillic) (Bosnia and Herzegovina) */
|
||||
{0x203B, "sms"}, /* Sami (Skolt) (Finland) */
|
||||
{0x2401, "ar"}, /* Arabic (Yemen) */
|
||||
{0x2409, "en"}, /* English (Caribbean) */
|
||||
{0x240A, "es"}, /* Spanish (Colombia) */
|
||||
{0x240C, "fr"}, /* ??? */
|
||||
{0x243B, "smn"}, /* Sami (Inari) (Finland) */
|
||||
{0x2801, "ar"}, /* Arabic (Syria) */
|
||||
{0x2809, "en"}, /* English (Belize) */
|
||||
{0x280A, "es"}, /* Spanish (Peru) */
|
||||
{0x280C, "fr"}, /* ??? */
|
||||
{0x2C01, "ar"}, /* Arabic (Jordan) */
|
||||
{0x2C09, "en"}, /* English (Trinidad and Tobago) */
|
||||
{0x2C0A, "es"}, /* Spanish (Argentina) */
|
||||
{0x2C0C, "fr"}, /* ??? */
|
||||
{0x3001, "ar"}, /* Arabic (Lebanon) */
|
||||
{0x3009, "en"}, /* English (Zimbabwe) */
|
||||
{0x300A, "es"}, /* Spanish (Ecuador) */
|
||||
{0x300C, "fr"}, /* ??? */
|
||||
{0x3401, "ar"}, /* Arabic (Kuwait) */
|
||||
{0x3409, "en"}, /* English (Republic of the Philippines) */
|
||||
{0x340A, "es"}, /* Spanish (Chile) */
|
||||
{0x340C, "fr"}, /* ??? */
|
||||
{0x3801, "ar"}, /* Arabic (U.A.E.) */
|
||||
{0x380A, "es"}, /* Spanish (Uruguay) */
|
||||
{0x380C, "fr"}, /* ??? */
|
||||
{0x3C01, "ar"}, /* Arabic (Bahrain) */
|
||||
{0x3C09, "en"}, /* ??? */
|
||||
{0x3C0A, "es"}, /* Spanish (Paraguay) */
|
||||
{0x3C0C, "fr"}, /* ??? */
|
||||
{0x4001, "ar"}, /* Arabic (Qatar) */
|
||||
{0x4009, "en"}, /* English (India) */
|
||||
{0x400A, "es"}, /* Spanish (Bolivia) */
|
||||
{0x4409, "en"}, /* English (Malaysia) */
|
||||
{0x440A, "es"}, /* Spanish (El Salvador) */
|
||||
{0x4809, "en"}, /* English (Singapore) */
|
||||
{0x480A, "es"}, /* Spanish (Honduras) */
|
||||
{0x4C0A, "es"}, /* Spanish (Nicaragua) */
|
||||
{0x500A, "es"}, /* Spanish (Puerto Rico) */
|
||||
{0x540A, "es"}, /* Spanish (United States) */
|
||||
{0xE40A, "es"}, /* ??? */
|
||||
{0xE40C, "fr"}, /* ??? */
|
||||
};
|
||||
|
||||
static const hb_ot_language_map_t
|
||||
hb_mac_language_map[] =
|
||||
{
|
||||
{ 0, "en"}, /* English */
|
||||
{ 1, "fr"}, /* French */
|
||||
{ 2, "de"}, /* German */
|
||||
{ 3, "it"}, /* Italian */
|
||||
{ 4, "nl"}, /* Dutch */
|
||||
{ 5, "sv"}, /* Swedish */
|
||||
{ 6, "es"}, /* Spanish */
|
||||
{ 7, "da"}, /* Danish */
|
||||
{ 8, "pt"}, /* Portuguese */
|
||||
{ 9, "no"}, /* Norwegian */
|
||||
{ 10, "he"}, /* Hebrew */
|
||||
{ 11, "ja"}, /* Japanese */
|
||||
{ 12, "ar"}, /* Arabic */
|
||||
{ 13, "fi"}, /* Finnish */
|
||||
{ 14, "el"}, /* Greek */
|
||||
{ 15, "is"}, /* Icelandic */
|
||||
{ 16, "mt"}, /* Maltese */
|
||||
{ 17, "tr"}, /* Turkish */
|
||||
{ 18, "hr"}, /* Croatian */
|
||||
{ 19, "zh-tw"}, /* Chinese (Traditional) */
|
||||
{ 20, "ur"}, /* Urdu */
|
||||
{ 21, "hi"}, /* Hindi */
|
||||
{ 22, "th"}, /* Thai */
|
||||
{ 23, "ko"}, /* Korean */
|
||||
{ 24, "lt"}, /* Lithuanian */
|
||||
{ 25, "pl"}, /* Polish */
|
||||
{ 26, "hu"}, /* Hungarian */
|
||||
{ 27, "et"}, /* Estonian */
|
||||
{ 28, "lv"}, /* Latvian */
|
||||
//{ 29, ""}, /* Sami */
|
||||
{ 30, "fo"}, /* Faroese */
|
||||
{ 31, "fa"}, /* Farsi/Persian */
|
||||
{ 32, "ru"}, /* Russian */
|
||||
{ 33, "zh-cn"}, /* Chinese (Simplified) */
|
||||
{ 34, "nl"}, /* Flemish */
|
||||
{ 35, "ga"}, /* Irish Gaelic */
|
||||
{ 36, "sq"}, /* Albanian */
|
||||
{ 37, "ro"}, /* Romanian */
|
||||
{ 38, "cs"}, /* Czech */
|
||||
{ 39, "sk"}, /* Slovak */
|
||||
{ 40, "sl"}, /* Slovenian */
|
||||
{ 41, "yi"}, /* Yiddish */
|
||||
{ 42, "sr"}, /* Serbian */
|
||||
{ 43, "mk"}, /* Macedonian */
|
||||
{ 44, "bg"}, /* Bulgarian */
|
||||
{ 45, "uk"}, /* Ukrainian */
|
||||
{ 46, "be"}, /* Byelorussian */
|
||||
{ 47, "uz"}, /* Uzbek */
|
||||
{ 48, "kk"}, /* Kazakh */
|
||||
{ 49, "az"}, /* Azerbaijani (Cyrillic script) */
|
||||
{ 50, "az"}, /* Azerbaijani (Arabic script) */
|
||||
{ 51, "hy"}, /* Armenian */
|
||||
{ 52, "ka"}, /* Georgian */
|
||||
{ 53, "mo"}, /* Moldavian */
|
||||
{ 54, "ky"}, /* Kirghiz */
|
||||
{ 55, "tg"}, /* Tajiki */
|
||||
{ 56, "tk"}, /* Turkmen */
|
||||
{ 57, "mn"}, /* Mongolian (Mongolian script) */
|
||||
{ 58, "mn"}, /* Mongolian (Cyrillic script) */
|
||||
{ 59, "ps"}, /* Pashto */
|
||||
{ 60, "ku"}, /* Kurdish */
|
||||
{ 61, "ks"}, /* Kashmiri */
|
||||
{ 62, "sd"}, /* Sindhi */
|
||||
{ 63, "bo"}, /* Tibetan */
|
||||
{ 64, "ne"}, /* Nepali */
|
||||
{ 65, "sa"}, /* Sanskrit */
|
||||
{ 66, "mr"}, /* Marathi */
|
||||
{ 67, "bn"}, /* Bengali */
|
||||
{ 68, "as"}, /* Assamese */
|
||||
{ 69, "gu"}, /* Gujarati */
|
||||
{ 70, "pa"}, /* Punjabi */
|
||||
{ 71, "or"}, /* Oriya */
|
||||
{ 72, "ml"}, /* Malayalam */
|
||||
{ 73, "kn"}, /* Kannada */
|
||||
{ 74, "ta"}, /* Tamil */
|
||||
{ 75, "te"}, /* Telugu */
|
||||
{ 76, "si"}, /* Sinhalese */
|
||||
{ 77, "my"}, /* Burmese */
|
||||
{ 78, "km"}, /* Khmer */
|
||||
{ 79, "lo"}, /* Lao */
|
||||
{ 80, "vi"}, /* Vietnamese */
|
||||
{ 81, "id"}, /* Indonesian */
|
||||
{ 82, "tl"}, /* Tagalog */
|
||||
{ 83, "ms"}, /* Malay (Roman script) */
|
||||
{ 84, "ms"}, /* Malay (Arabic script) */
|
||||
{ 85, "am"}, /* Amharic */
|
||||
{ 86, "ti"}, /* Tigrinya */
|
||||
{ 87, "om"}, /* Galla */
|
||||
{ 88, "so"}, /* Somali */
|
||||
{ 89, "sw"}, /* Swahili */
|
||||
{ 90, "rw"}, /* Kinyarwanda/Ruanda */
|
||||
{ 91, "rn"}, /* Rundi */
|
||||
{ 92, "ny"}, /* Nyanja/Chewa */
|
||||
{ 93, "mg"}, /* Malagasy */
|
||||
{ 94, "eo"}, /* Esperanto */
|
||||
{128, "cy"}, /* Welsh */
|
||||
{129, "eu"}, /* Basque */
|
||||
{130, "ca"}, /* Catalan */
|
||||
{131, "la"}, /* Latin */
|
||||
{132, "qu"}, /* Quechua */
|
||||
{133, "gn"}, /* Guarani */
|
||||
{134, "ay"}, /* Aymara */
|
||||
{135, "tt"}, /* Tatar */
|
||||
{136, "ug"}, /* Uighur */
|
||||
{137, "dz"}, /* Dzongkha */
|
||||
{138, "jw"}, /* Javanese (Roman script) */
|
||||
{139, "su"}, /* Sundanese (Roman script) */
|
||||
{140, "gl"}, /* Galician */
|
||||
{141, "af"}, /* Afrikaans */
|
||||
{142, "br"}, /* Breton */
|
||||
{143, "iu"}, /* Inuktitut */
|
||||
{144, "gd"}, /* Scottish Gaelic */
|
||||
{145, "gv"}, /* Manx Gaelic */
|
||||
{146, "ga"}, /* Irish Gaelic (with dot above) */
|
||||
{147, "to"}, /* Tongan */
|
||||
{148, "el"}, /* Greek (polytonic) */
|
||||
{149, "ik"}, /* Greenlandic */
|
||||
{150, "az"}, /* Azerbaijani (Roman script) */
|
||||
};
|
||||
|
||||
|
||||
static hb_language_t
|
||||
_hb_ot_name_language_for (unsigned int code,
|
||||
const hb_ot_language_map_t *array,
|
||||
unsigned int len)
|
||||
{
|
||||
const hb_ot_language_map_t *entry = (const hb_ot_language_map_t *)
|
||||
hb_bsearch (&code,
|
||||
array,
|
||||
len,
|
||||
sizeof (array[0]),
|
||||
hb_ot_language_map_t::cmp);
|
||||
|
||||
if (entry)
|
||||
return hb_language_from_string (entry->lang, -1);
|
||||
|
||||
return HB_LANGUAGE_INVALID;
|
||||
}
|
||||
|
||||
hb_language_t
|
||||
_hb_ot_name_language_for_ms_code (unsigned int code)
|
||||
{
|
||||
return _hb_ot_name_language_for (code,
|
||||
hb_ms_language_map,
|
||||
ARRAY_LENGTH (hb_ms_language_map));
|
||||
}
|
||||
|
||||
hb_language_t
|
||||
_hb_ot_name_language_for_mac_code (unsigned int code)
|
||||
{
|
||||
return _hb_ot_name_language_for (code,
|
||||
hb_mac_language_map,
|
||||
ARRAY_LENGTH (hb_mac_language_map));
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* 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_NAME_LANGUAGE_HH
|
||||
#define HB_OT_NAME_LANGUAGE_HH
|
||||
|
||||
#include "hb.hh"
|
||||
|
||||
|
||||
HB_INTERNAL hb_language_t
|
||||
_hb_ot_name_language_for_ms_code (unsigned int code);
|
||||
|
||||
HB_INTERNAL hb_language_t
|
||||
_hb_ot_name_language_for_mac_code (unsigned int code);
|
||||
|
||||
|
||||
#endif /* HB_OT_NAME_LANGUAGE_HH */
|
|
@ -28,34 +28,69 @@
|
|||
#define HB_OT_NAME_TABLE_HH
|
||||
|
||||
#include "hb-open-type.hh"
|
||||
#include "hb-ot-name-language.hh"
|
||||
#include "hb-aat-layout.hh"
|
||||
|
||||
|
||||
namespace OT {
|
||||
|
||||
|
||||
#define entry_score var.u16[0]
|
||||
#define entry_index var.u16[1]
|
||||
|
||||
|
||||
/*
|
||||
* name -- Naming
|
||||
* https://docs.microsoft.com/en-us/typography/opentype/spec/name
|
||||
*/
|
||||
#define HB_OT_TAG_name HB_TAG('n','a','m','e')
|
||||
|
||||
#define UNSUPPORTED 42
|
||||
|
||||
struct NameRecord
|
||||
{
|
||||
static int cmp (const void *pa, const void *pb)
|
||||
inline hb_language_t language (hb_face_t *face) const
|
||||
{
|
||||
const NameRecord *a = (const NameRecord *) pa;
|
||||
const NameRecord *b = (const NameRecord *) pb;
|
||||
int ret;
|
||||
ret = b->platformID.cmp (a->platformID);
|
||||
if (ret) return ret;
|
||||
ret = b->encodingID.cmp (a->encodingID);
|
||||
if (ret) return ret;
|
||||
ret = b->languageID.cmp (a->languageID);
|
||||
if (ret) return ret;
|
||||
ret = b->nameID.cmp (a->nameID);
|
||||
if (ret) return ret;
|
||||
return 0;
|
||||
unsigned int p = platformID;
|
||||
unsigned int l = languageID;
|
||||
|
||||
if (p == 3)
|
||||
return _hb_ot_name_language_for_ms_code (l);
|
||||
|
||||
if (p == 1)
|
||||
return _hb_ot_name_language_for_mac_code (l);
|
||||
|
||||
if (p == 0)
|
||||
return _hb_aat_language_get (face, l);
|
||||
|
||||
return HB_LANGUAGE_INVALID;
|
||||
}
|
||||
|
||||
inline uint16_t score (void) const
|
||||
{
|
||||
/* Same order as in cmap::find_best_subtable(). */
|
||||
unsigned int p = platformID;
|
||||
unsigned int e = encodingID;
|
||||
|
||||
/* 32-bit. */
|
||||
if (p == 3 && e == 10) return 0;
|
||||
if (p == 0 && e == 6) return 1;
|
||||
if (p == 0 && e == 4) return 2;
|
||||
|
||||
/* 16-bit. */
|
||||
if (p == 3 && e == 1) return 3;
|
||||
if (p == 0 && e == 3) return 4;
|
||||
if (p == 0 && e == 2) return 5;
|
||||
if (p == 0 && e == 1) return 6;
|
||||
if (p == 0 && e == 0) return 7;
|
||||
|
||||
/* Symbol. */
|
||||
if (p == 3 && e == 0) return 8;
|
||||
|
||||
/* We treat all Mac Latin names as ASCII only. */
|
||||
if (p == 1 && e == 0) return 10; /* 10 is magic number :| */
|
||||
|
||||
return UNSUPPORTED;
|
||||
}
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
|
||||
|
@ -75,39 +110,57 @@ struct NameRecord
|
|||
DEFINE_SIZE_STATIC (12);
|
||||
};
|
||||
|
||||
static int
|
||||
_hb_ot_name_entry_cmp_key (const void *pa, const void *pb)
|
||||
{
|
||||
const hb_ot_name_entry_t *a = (const hb_ot_name_entry_t *) pa;
|
||||
const hb_ot_name_entry_t *b = (const hb_ot_name_entry_t *) pb;
|
||||
|
||||
/* Compare by name_id, then language. */
|
||||
|
||||
if (a->name_id != b->name_id)
|
||||
return a->name_id < b->name_id ? -1 : +1;
|
||||
|
||||
if (a->language == b->language) return 0;
|
||||
if (!a->language) return -1;
|
||||
if (!b->language) return +1;
|
||||
return strcmp (hb_language_to_string (a->language),
|
||||
hb_language_to_string (b->language));
|
||||
}
|
||||
|
||||
static int
|
||||
_hb_ot_name_entry_cmp (const void *pa, const void *pb)
|
||||
{
|
||||
/* Compare by name_id, then language, then score, then index. */
|
||||
|
||||
int v = _hb_ot_name_entry_cmp_key (pa, pb);
|
||||
if (v)
|
||||
return v;
|
||||
|
||||
const hb_ot_name_entry_t *a = (const hb_ot_name_entry_t *) pa;
|
||||
const hb_ot_name_entry_t *b = (const hb_ot_name_entry_t *) pb;
|
||||
|
||||
if (a->entry_score != b->entry_score)
|
||||
return a->entry_score < b->entry_score ? -1 : +1;
|
||||
|
||||
if (a->entry_index != b->entry_index)
|
||||
return a->entry_index < b->entry_index ? -1 : +1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct name
|
||||
{
|
||||
static const hb_tag_t tableTag = HB_OT_TAG_name;
|
||||
|
||||
inline unsigned int get_name (unsigned int platform_id,
|
||||
unsigned int encoding_id,
|
||||
unsigned int language_id,
|
||||
unsigned int name_id,
|
||||
void *buffer,
|
||||
unsigned int buffer_length) const
|
||||
{
|
||||
NameRecord key;
|
||||
key.platformID.set (platform_id);
|
||||
key.encodingID.set (encoding_id);
|
||||
key.languageID.set (language_id);
|
||||
key.nameID.set (name_id);
|
||||
NameRecord *match = (NameRecord *) bsearch (&key, nameRecordZ.arrayZ, count, sizeof (nameRecordZ[0]), NameRecord::cmp);
|
||||
|
||||
if (!match)
|
||||
return 0;
|
||||
|
||||
unsigned int length = MIN (buffer_length, (unsigned int) match->length);
|
||||
memcpy (buffer, (char *) this + stringOffset + match->offset, length);
|
||||
return length;
|
||||
}
|
||||
|
||||
inline unsigned int get_size (void) const
|
||||
{ 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;
|
||||
const void *string_pool = (this+stringOffset).arrayZ;
|
||||
unsigned int _count = count;
|
||||
/* Move to run-time?! */
|
||||
for (unsigned int i = 0; i < _count; i++)
|
||||
if (!nameRecordZ[i].sanitize (c, string_pool)) return_trace (false);
|
||||
return_trace (true);
|
||||
|
@ -119,19 +172,107 @@ struct name
|
|||
return_trace (c->check_struct (this) &&
|
||||
likely (format == 0 || format == 1) &&
|
||||
c->check_array (nameRecordZ.arrayZ, count) &&
|
||||
sanitize_records (c));
|
||||
c->check_range (this, stringOffset));
|
||||
}
|
||||
|
||||
struct accelerator_t
|
||||
{
|
||||
inline void init (hb_face_t *face)
|
||||
{
|
||||
this->blob = hb_sanitize_context_t().reference_table<name> (face);
|
||||
this->table = this->blob->as<name> ();
|
||||
assert (this->blob->length >= this->table->stringOffset);
|
||||
this->pool = (this->table+this->table->stringOffset).arrayZ;
|
||||
this->pool_len = this->blob->length - this->table->stringOffset;
|
||||
const hb_array_t<const NameRecord> all_names (this->table->nameRecordZ.arrayZ,
|
||||
this->table->count);
|
||||
|
||||
this->names.init ();
|
||||
this->names.alloc (all_names.len);
|
||||
|
||||
for (uint16_t i = 0; i < all_names.len; i++)
|
||||
{
|
||||
hb_ot_name_entry_t *entry = this->names.push ();
|
||||
|
||||
entry->name_id = all_names[i].nameID;
|
||||
entry->language = all_names[i].language (face);
|
||||
entry->entry_score = all_names[i].score ();
|
||||
entry->entry_index = i;
|
||||
}
|
||||
|
||||
this->names.qsort (_hb_ot_name_entry_cmp);
|
||||
/* Walk and pick best only for each name_id,language pair,
|
||||
* while dropping unsupported encodings. */
|
||||
unsigned int j = 0;
|
||||
for (unsigned int i = 0; i < this->names.len; i++)
|
||||
{
|
||||
if (this->names[i].entry_score == UNSUPPORTED ||
|
||||
this->names[i].language == HB_LANGUAGE_INVALID)
|
||||
continue;
|
||||
if (i &&
|
||||
this->names[i - 1].name_id == this->names[i].name_id &&
|
||||
this->names[i - 1].language == this->names[i].language)
|
||||
continue;
|
||||
this->names[j++] = this->names[i];
|
||||
}
|
||||
this->names.resize (j);
|
||||
}
|
||||
|
||||
inline void fini (void)
|
||||
{
|
||||
this->names.fini ();
|
||||
hb_blob_destroy (this->blob);
|
||||
}
|
||||
|
||||
inline int get_index (hb_ot_name_id_t name_id,
|
||||
hb_language_t language,
|
||||
unsigned int *width=nullptr) const
|
||||
{
|
||||
const hb_ot_name_entry_t key = {name_id, {0}, language};
|
||||
const hb_ot_name_entry_t *entry = (const hb_ot_name_entry_t *)
|
||||
hb_bsearch (&key,
|
||||
this->names.arrayZ(),
|
||||
this->names.len,
|
||||
sizeof (key),
|
||||
_hb_ot_name_entry_cmp_key);
|
||||
if (!entry)
|
||||
return -1;
|
||||
|
||||
if (width)
|
||||
*width = entry->entry_score < 10 ? 2 : 1;
|
||||
|
||||
return entry->entry_index;
|
||||
}
|
||||
|
||||
inline hb_bytes_t get_name (unsigned int idx) const
|
||||
{
|
||||
const hb_array_t<const NameRecord> all_names (table->nameRecordZ.arrayZ, table->count);
|
||||
const NameRecord &record = all_names[idx];
|
||||
const hb_array_t<const char> string_pool ((const char *) pool, pool_len);
|
||||
return string_pool.sub_array (record.offset, record.length).as_bytes ();
|
||||
}
|
||||
|
||||
private:
|
||||
hb_blob_t *blob;
|
||||
const void *pool;
|
||||
unsigned int pool_len;
|
||||
public:
|
||||
const name *table;
|
||||
hb_vector_t<hb_ot_name_entry_t> names;
|
||||
};
|
||||
|
||||
/* We only implement format 0 for now. */
|
||||
HBUINT16 format; /* Format selector (=0/1). */
|
||||
HBUINT16 count; /* Number of name records. */
|
||||
Offset16 stringOffset; /* Offset to start of string storage (from start of table). */
|
||||
OffsetTo<UnsizedArrayOf<HBUINT8>, HBUINT16, false>
|
||||
stringOffset; /* Offset to start of string storage (from start of table). */
|
||||
UnsizedArrayOf<NameRecord>
|
||||
nameRecordZ; /* The name records where count is the number of records. */
|
||||
public:
|
||||
DEFINE_SIZE_ARRAY (6, nameRecordZ);
|
||||
};
|
||||
|
||||
struct name_accelerator_t : name::accelerator_t {};
|
||||
|
||||
} /* namespace OT */
|
||||
|
||||
|
|
|
@ -0,0 +1,231 @@
|
|||
/*
|
||||
* 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.hh"
|
||||
|
||||
#include "hb-ot-name-table.hh"
|
||||
|
||||
#include "hb-ot-face.hh"
|
||||
#include "hb-utf.hh"
|
||||
|
||||
|
||||
/**
|
||||
* SECTION:hb-ot-name
|
||||
* @title: hb-ot-name
|
||||
* @short_description: OpenType font name information
|
||||
* @include: hb-ot.h
|
||||
*
|
||||
* Functions for fetching name strings from OpenType fonts.
|
||||
**/
|
||||
|
||||
|
||||
static inline const OT::name_accelerator_t&
|
||||
_get_name (hb_face_t *face)
|
||||
{
|
||||
if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::name_accelerator_t);
|
||||
return *(hb_ot_face_data (face)->name.get ());
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_ot_name_list_names:
|
||||
* @face: font face.
|
||||
* @num_entries: (out): number of returned entries.
|
||||
*
|
||||
* Enumerates all available name IDs and language combinations. Returned
|
||||
* array is owned by the @face and should not be modified. It can be
|
||||
* used as long as @face is alive.
|
||||
*
|
||||
* Returns: (out) (transfer none) (array length=num_entries): Array of available name entries.
|
||||
* Since: 2.1.0
|
||||
**/
|
||||
const hb_ot_name_entry_t *
|
||||
hb_ot_name_list_names (hb_face_t *face,
|
||||
unsigned int *num_entries /* OUT */)
|
||||
{
|
||||
const OT::name_accelerator_t &name = _get_name (face);
|
||||
*num_entries = name.names.len;
|
||||
return name.names.arrayZ();
|
||||
}
|
||||
|
||||
|
||||
template <typename in_utf_t, typename out_utf_t>
|
||||
static inline unsigned int
|
||||
hb_ot_name_convert_utf (const hb_bytes_t *bytes,
|
||||
unsigned int *text_size /* IN/OUT */,
|
||||
typename out_utf_t::codepoint_t *text /* OUT */)
|
||||
{
|
||||
unsigned int src_len = bytes->len / sizeof (typename in_utf_t::codepoint_t);
|
||||
const typename in_utf_t::codepoint_t *src = (const typename in_utf_t::codepoint_t *) bytes->arrayZ;
|
||||
const typename in_utf_t::codepoint_t *src_end = src + src_len;
|
||||
|
||||
typename out_utf_t::codepoint_t *dst = text;
|
||||
|
||||
hb_codepoint_t unicode;
|
||||
const hb_codepoint_t replacement = HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT;
|
||||
|
||||
if (text_size && *text_size)
|
||||
{
|
||||
(*text_size)--; /* Same room for NUL-termination. */
|
||||
const typename out_utf_t::codepoint_t *dst_end = text + *text_size;
|
||||
|
||||
while (src < src_end && dst < dst_end)
|
||||
{
|
||||
const typename in_utf_t::codepoint_t *src_next = in_utf_t::next (src, src_end, &unicode, replacement);
|
||||
typename out_utf_t::codepoint_t *dst_next = out_utf_t::encode (dst, dst_end, unicode);
|
||||
if (dst_next == dst)
|
||||
break; /* Out-of-room. */
|
||||
|
||||
dst = dst_next;
|
||||
src = src_next;
|
||||
};
|
||||
|
||||
*text_size = dst - text;
|
||||
*dst = 0; /* NUL-terminate. */
|
||||
}
|
||||
|
||||
/* Accumulate length of rest. */
|
||||
unsigned int dst_len = dst - text;
|
||||
while (src < src_end)
|
||||
{
|
||||
src = in_utf_t::next (src, src_end, &unicode, replacement);
|
||||
dst_len += out_utf_t::encode_len (unicode);
|
||||
};
|
||||
return dst_len;
|
||||
}
|
||||
|
||||
template <typename utf_t>
|
||||
static inline unsigned int
|
||||
hb_ot_name_get_utf (hb_face_t *face,
|
||||
hb_ot_name_id_t name_id,
|
||||
hb_language_t language,
|
||||
unsigned int *text_size /* IN/OUT */,
|
||||
typename utf_t::codepoint_t *text /* OUT */)
|
||||
{
|
||||
const OT::name_accelerator_t &name = _get_name (face);
|
||||
|
||||
if (!language)
|
||||
language = hb_language_from_string ("en", 2);
|
||||
|
||||
unsigned int width;
|
||||
int idx = name.get_index (name_id, language, &width);
|
||||
if (idx != -1)
|
||||
{
|
||||
hb_bytes_t bytes = name.get_name (idx);
|
||||
|
||||
if (width == 2) /* UTF16-BE */
|
||||
return hb_ot_name_convert_utf<hb_utf16_be_t, utf_t> (&bytes, text_size, text);
|
||||
|
||||
if (width == 1) /* ASCII */
|
||||
return hb_ot_name_convert_utf<hb_ascii_t, utf_t> (&bytes, text_size, text);
|
||||
}
|
||||
|
||||
if (text_size)
|
||||
{
|
||||
if (*text_size)
|
||||
*text = 0;
|
||||
*text_size = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_ot_name_get_utf8:
|
||||
* @face: font face.
|
||||
* @name_id: OpenType name identifier to fetch.
|
||||
* @language: language to fetch the name for.
|
||||
* @text_size: (inout) (allow-none): input size of @text buffer, and output size of
|
||||
* text written to buffer.
|
||||
* @text: (out caller-allocates) (array length=text_size): buffer to write fetched name into.
|
||||
*
|
||||
* Fetches a font name from the OpenType 'name' table.
|
||||
* If @language is #HB_LANGUAGE_INVALID, English ("en") is assumed.
|
||||
* Returns string in UTF-8 encoding.
|
||||
*
|
||||
* Returns: full length of the requested string, or 0 if not found.
|
||||
* Since: 2.1.0
|
||||
**/
|
||||
unsigned int
|
||||
hb_ot_name_get_utf8 (hb_face_t *face,
|
||||
hb_ot_name_id_t name_id,
|
||||
hb_language_t language,
|
||||
unsigned int *text_size /* IN/OUT */,
|
||||
char *text /* OUT */)
|
||||
{
|
||||
return hb_ot_name_get_utf<hb_utf8_t> (face, name_id, language, text_size,
|
||||
(hb_utf8_t::codepoint_t *) text);
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_ot_name_get_utf16:
|
||||
* @face: font face.
|
||||
* @name_id: OpenType name identifier to fetch.
|
||||
* @language: language to fetch the name for.
|
||||
* @text_size: (inout) (allow-none): input size of @text buffer, and output size of
|
||||
* text written to buffer.
|
||||
* @text: (out caller-allocates) (array length=text_size): buffer to write fetched name into.
|
||||
*
|
||||
* Fetches a font name from the OpenType 'name' table.
|
||||
* If @language is #HB_LANGUAGE_INVALID, English ("en") is assumed.
|
||||
* Returns string in UTF-16 encoding.
|
||||
*
|
||||
* Returns: full length of the requested string, or 0 if not found.
|
||||
* Since: 2.1.0
|
||||
**/
|
||||
unsigned int
|
||||
hb_ot_name_get_utf16 (hb_face_t *face,
|
||||
hb_ot_name_id_t name_id,
|
||||
hb_language_t language,
|
||||
unsigned int *text_size /* IN/OUT */,
|
||||
uint16_t *text /* OUT */)
|
||||
{
|
||||
return hb_ot_name_get_utf<hb_utf16_t> (face, name_id, language, text_size, text);
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_ot_name_get_utf32:
|
||||
* @face: font face.
|
||||
* @name_id: OpenType name identifier to fetch.
|
||||
* @language: language to fetch the name for.
|
||||
* @text_size: (inout) (allow-none): input size of @text buffer, and output size of
|
||||
* text written to buffer.
|
||||
* @text: (out caller-allocates) (array length=text_size): buffer to write fetched name into.
|
||||
*
|
||||
* Fetches a font name from the OpenType 'name' table.
|
||||
* If @language is #HB_LANGUAGE_INVALID, English ("en") is assumed.
|
||||
* Returns string in UTF-32 encoding.
|
||||
*
|
||||
* Returns: full length of the requested string, or 0 if not found.
|
||||
* Since: 2.1.0
|
||||
**/
|
||||
unsigned int
|
||||
hb_ot_name_get_utf32 (hb_face_t *face,
|
||||
hb_ot_name_id_t name_id,
|
||||
hb_language_t language,
|
||||
unsigned int *text_size /* IN/OUT */,
|
||||
uint32_t *text /* OUT */)
|
||||
{
|
||||
return hb_ot_name_get_utf<hb_utf32_t> (face, name_id, language, text_size, text);
|
||||
}
|
|
@ -35,18 +35,94 @@ HB_BEGIN_DECLS
|
|||
|
||||
|
||||
/**
|
||||
* hb_name_id_t:
|
||||
* hb_ot_name_id_t:
|
||||
* @HB_OT_NAME_ID_INVALID: Value to represent a nonexistent name ID.
|
||||
*
|
||||
* Since: 2.0.0
|
||||
*/
|
||||
typedef unsigned int hb_name_id_t;
|
||||
|
||||
/**
|
||||
* HB_NAME_ID_INVALID
|
||||
* An integral type representing an OpenType 'name' table name identifier.
|
||||
* There are predefined name IDs, as well as name IDs return from other
|
||||
* API. These can be used to fetch name strings from a font face.
|
||||
*
|
||||
* Since: 2.0.0
|
||||
**/
|
||||
#define HB_NAME_ID_INVALID 0xFFFF
|
||||
enum
|
||||
{
|
||||
HB_OT_NAME_ID_COPYRIGHT = 0,
|
||||
HB_OT_NAME_ID_FONT_FAMILY = 1,
|
||||
HB_OT_NAME_ID_FONT_SUBFAMILY = 2,
|
||||
HB_OT_NAME_ID_UNIQUE_ID = 3,
|
||||
HB_OT_NAME_ID_FULL_NAME = 4,
|
||||
HB_OT_NAME_ID_VERSION_STRING = 5,
|
||||
HB_OT_NAME_ID_POSTSCRIPT_NAME = 6,
|
||||
HB_OT_NAME_ID_TRADEMARK = 7,
|
||||
HB_OT_NAME_ID_MANUFACTURER = 8,
|
||||
HB_OT_NAME_ID_DESIGNER = 9,
|
||||
HB_OT_NAME_ID_DESCRIPTION = 10,
|
||||
HB_OT_NAME_ID_VENDOR_URL = 11,
|
||||
HB_OT_NAME_ID_DESIGNER_URL = 12,
|
||||
HB_OT_NAME_ID_LICENSE = 13,
|
||||
HB_OT_NAME_ID_LICENSE_URL = 14,
|
||||
/*HB_OT_NAME_ID_RESERVED = 15,*/
|
||||
HB_OT_NAME_ID_TYPOGRAPHIC_FAMILY = 16,
|
||||
HB_OT_NAME_ID_TYPOGRAPHIC_SUBFAMILY = 17,
|
||||
HB_OT_NAME_ID_MAC_FULL_NAME = 18,
|
||||
HB_OT_NAME_ID_SAMPLE_TEXT = 19,
|
||||
HB_OT_NAME_ID_CID_FINDFONT_NAME = 20,
|
||||
HB_OT_NAME_ID_WWS_FAMILY = 21,
|
||||
HB_OT_NAME_ID_WWS_SUBFAMILY = 22,
|
||||
HB_OT_NAME_ID_LIGHT_BACKGROUND = 23,
|
||||
HB_OT_NAME_ID_DARK_BACKGROUND = 24,
|
||||
HB_OT_NAME_ID_VARIATIONS_PS_PREFIX = 25,
|
||||
|
||||
HB_OT_NAME_ID_INVALID = 0xFFFF,
|
||||
};
|
||||
|
||||
typedef unsigned int hb_ot_name_id_t;
|
||||
|
||||
|
||||
/**
|
||||
* hb_ot_name_entry_t:
|
||||
* @name_id: name ID
|
||||
* @language: language
|
||||
*
|
||||
* Structure representing a name ID in a particular language.
|
||||
*
|
||||
* Since: 2.1.0
|
||||
**/
|
||||
typedef struct hb_ot_name_entry_t
|
||||
{
|
||||
hb_ot_name_id_t name_id;
|
||||
/*< private >*/
|
||||
hb_var_int_t var;
|
||||
/*< public >*/
|
||||
hb_language_t language;
|
||||
} hb_ot_name_entry_t;
|
||||
|
||||
HB_EXTERN const hb_ot_name_entry_t *
|
||||
hb_ot_name_list_names (hb_face_t *face,
|
||||
unsigned int *num_entries /* OUT */);
|
||||
|
||||
|
||||
HB_EXTERN unsigned int
|
||||
hb_ot_name_get_utf8 (hb_face_t *face,
|
||||
hb_ot_name_id_t name_id,
|
||||
hb_language_t language,
|
||||
unsigned int *text_size /* IN/OUT */,
|
||||
char *text /* OUT */);
|
||||
|
||||
HB_EXTERN unsigned int
|
||||
hb_ot_name_get_utf16 (hb_face_t *face,
|
||||
hb_ot_name_id_t name_id,
|
||||
hb_language_t language,
|
||||
unsigned int *text_size /* IN/OUT */,
|
||||
uint16_t *text /* OUT */);
|
||||
|
||||
HB_EXTERN unsigned int
|
||||
hb_ot_name_get_utf32 (hb_face_t *face,
|
||||
hb_ot_name_id_t name_id,
|
||||
hb_language_t language,
|
||||
unsigned int *text_size /* IN/OUT */,
|
||||
uint32_t *text /* OUT */);
|
||||
|
||||
|
||||
HB_END_DECLS
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ namespace OT {
|
|||
struct OS2Range
|
||||
{
|
||||
static int
|
||||
cmp (const void *_key, const void *_item, void *_arg)
|
||||
cmp (const void *_key, const void *_item)
|
||||
{
|
||||
hb_codepoint_t cp = *((hb_codepoint_t *) _key);
|
||||
const OS2Range *range = (OS2Range *) _item;
|
||||
|
@ -233,10 +233,10 @@ static const OS2Range _hb_os2_unicode_ranges[] =
|
|||
static unsigned int
|
||||
_hb_ot_os2_get_unicode_range_bit (hb_codepoint_t cp)
|
||||
{
|
||||
OS2Range *range = (OS2Range*) hb_bsearch_r (&cp, _hb_os2_unicode_ranges,
|
||||
ARRAY_LENGTH (_hb_os2_unicode_ranges),
|
||||
sizeof (OS2Range),
|
||||
OS2Range::cmp, nullptr);
|
||||
OS2Range *range = (OS2Range*) hb_bsearch (&cp, _hb_os2_unicode_ranges,
|
||||
ARRAY_LENGTH (_hb_os2_unicode_ranges),
|
||||
sizeof (OS2Range),
|
||||
OS2Range::cmp);
|
||||
if (range != nullptr)
|
||||
return range->bit;
|
||||
return -1;
|
||||
|
|
|
@ -194,8 +194,6 @@ arabic_fallback_synthesize_lookup (const hb_ot_shape_plan_t *plan,
|
|||
|
||||
struct arabic_fallback_plan_t
|
||||
{
|
||||
ASSERT_POD ();
|
||||
|
||||
unsigned int num_lookups;
|
||||
bool free_lookups;
|
||||
|
||||
|
@ -220,9 +218,9 @@ struct ManifestLookup
|
|||
typedef OT::ArrayOf<ManifestLookup> Manifest;
|
||||
|
||||
static bool
|
||||
arabic_fallback_plan_init_win1256 (arabic_fallback_plan_t *fallback_plan,
|
||||
const hb_ot_shape_plan_t *plan,
|
||||
hb_font_t *font)
|
||||
arabic_fallback_plan_init_win1256 (arabic_fallback_plan_t *fallback_plan HB_UNUSED,
|
||||
const hb_ot_shape_plan_t *plan HB_UNUSED,
|
||||
hb_font_t *font HB_UNUSED)
|
||||
{
|
||||
#ifdef HB_WITH_WIN1256
|
||||
/* Does this font look like it's Windows-1256-encoded? */
|
||||
|
|
|
@ -243,8 +243,6 @@ collect_features_arabic (hb_ot_shape_planner_t *plan)
|
|||
|
||||
struct arabic_shape_plan_t
|
||||
{
|
||||
ASSERT_POD ();
|
||||
|
||||
/* The "+ 1" in the next array is to accommodate for the "NONE" command,
|
||||
* which is not an OpenType feature, but this simplifies the code by not
|
||||
* having to do a "if (... < NONE) ..." and just rely on the fact that
|
||||
|
@ -416,7 +414,7 @@ retry:
|
|||
|
||||
static void
|
||||
record_stch (const hb_ot_shape_plan_t *plan,
|
||||
hb_font_t *font,
|
||||
hb_font_t *font HB_UNUSED,
|
||||
hb_buffer_t *buffer)
|
||||
{
|
||||
const arabic_shape_plan_t *arabic_plan = (const arabic_shape_plan_t *) plan->data;
|
||||
|
@ -440,7 +438,7 @@ record_stch (const hb_ot_shape_plan_t *plan,
|
|||
}
|
||||
|
||||
static void
|
||||
apply_stch (const hb_ot_shape_plan_t *plan,
|
||||
apply_stch (const hb_ot_shape_plan_t *plan HB_UNUSED,
|
||||
hb_buffer_t *buffer,
|
||||
hb_font_t *font)
|
||||
{
|
||||
|
@ -626,7 +624,7 @@ info_is_mcm (const hb_glyph_info_t &info)
|
|||
}
|
||||
|
||||
static void
|
||||
reorder_marks_arabic (const hb_ot_shape_plan_t *plan,
|
||||
reorder_marks_arabic (const hb_ot_shape_plan_t *plan HB_UNUSED,
|
||||
hb_buffer_t *buffer,
|
||||
unsigned int start,
|
||||
unsigned int end)
|
||||
|
|
|
@ -70,8 +70,6 @@ override_features_hangul (hb_ot_shape_planner_t *plan)
|
|||
|
||||
struct hangul_shape_plan_t
|
||||
{
|
||||
ASSERT_POD ();
|
||||
|
||||
hb_mask_t mask_array[HANGUL_FEATURE_COUNT];
|
||||
};
|
||||
|
||||
|
@ -128,7 +126,7 @@ is_zero_width_char (hb_font_t *font,
|
|||
}
|
||||
|
||||
static void
|
||||
preprocess_text_hangul (const hb_ot_shape_plan_t *plan,
|
||||
preprocess_text_hangul (const hb_ot_shape_plan_t *plan HB_UNUSED,
|
||||
hb_buffer_t *buffer,
|
||||
hb_font_t *font)
|
||||
{
|
||||
|
|
|
@ -116,7 +116,8 @@ indic_features[] =
|
|||
{HB_TAG('c','j','c','t'), F_GLOBAL_MANUAL_JOINERS},
|
||||
/*
|
||||
* Other features.
|
||||
* These features are applied all at once, after final_reordering.
|
||||
* These features are applied all at once, after final_reordering
|
||||
* but before clearing syllables.
|
||||
* Default Bengali font in Windows for example has intermixed
|
||||
* lookups for init,pres,abvs,blws features.
|
||||
*/
|
||||
|
@ -251,8 +252,6 @@ struct would_substitute_feature_t
|
|||
|
||||
struct indic_shape_plan_t
|
||||
{
|
||||
ASSERT_POD ();
|
||||
|
||||
inline bool load_virama_glyph (hb_font_t *font, hb_codepoint_t *pglyph) const
|
||||
{
|
||||
hb_codepoint_t glyph = virama_glyph.get_relaxed ();
|
||||
|
@ -787,8 +786,10 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
|
|||
*
|
||||
* We could use buffer->sort() for this, if there was no special
|
||||
* reordering of pre-base stuff happening later...
|
||||
* We don't want to merge_clusters all of that, which buffer->sort()
|
||||
* would.
|
||||
*/
|
||||
if (indic_plan->is_old_spec || end - base > 127)
|
||||
if (indic_plan->is_old_spec || end - start > 127)
|
||||
buffer->merge_clusters (base, end);
|
||||
else
|
||||
{
|
||||
|
|
|
@ -46,7 +46,7 @@ khmer_features[] =
|
|||
{HB_TAG('c','f','a','r'), F_MANUAL_JOINERS},
|
||||
/*
|
||||
* Other features.
|
||||
* These features are applied all at once.
|
||||
* These features are applied all at once after clearing syllables.
|
||||
*/
|
||||
{HB_TAG('p','r','e','s'), F_GLOBAL_MANUAL_JOINERS},
|
||||
{HB_TAG('a','b','v','s'), F_GLOBAL_MANUAL_JOINERS},
|
||||
|
@ -174,8 +174,6 @@ struct would_substitute_feature_t
|
|||
|
||||
struct khmer_shape_plan_t
|
||||
{
|
||||
ASSERT_POD ();
|
||||
|
||||
inline bool get_virama_glyph (hb_font_t *font, hb_codepoint_t *pglyph) const
|
||||
{
|
||||
hb_codepoint_t glyph = virama_glyph;
|
||||
|
@ -267,7 +265,7 @@ setup_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED,
|
|||
|
||||
static void
|
||||
reorder_consonant_syllable (const hb_ot_shape_plan_t *plan,
|
||||
hb_face_t *face,
|
||||
hb_face_t *face HB_UNUSED,
|
||||
hb_buffer_t *buffer,
|
||||
unsigned int start, unsigned int end)
|
||||
{
|
||||
|
@ -438,8 +436,6 @@ clear_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED,
|
|||
hb_font_t *font HB_UNUSED,
|
||||
hb_buffer_t *buffer)
|
||||
{
|
||||
/* TODO: In USE, we clear syllables right after reorder. Figure out
|
||||
* what Uniscribe does. */
|
||||
hb_glyph_info_t *info = buffer->info;
|
||||
unsigned int count = buffer->len;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
|
|
|
@ -36,7 +36,7 @@ basic_features[] =
|
|||
{
|
||||
/*
|
||||
* Basic features.
|
||||
* These features are applied in order, one at a time, after initial_reordering.
|
||||
* These features are applied in order, one at a time, after reordering.
|
||||
*/
|
||||
HB_TAG('r','p','h','f'),
|
||||
HB_TAG('p','r','e','f'),
|
||||
|
@ -48,7 +48,7 @@ other_features[] =
|
|||
{
|
||||
/*
|
||||
* Other features.
|
||||
* These features are applied all at once, after final_reordering.
|
||||
* These features are applied all at once, after clearing syllables.
|
||||
*/
|
||||
HB_TAG('p','r','e','s'),
|
||||
HB_TAG('a','b','v','s'),
|
||||
|
@ -80,13 +80,13 @@ setup_syllables (const hb_ot_shape_plan_t *plan,
|
|||
hb_font_t *font,
|
||||
hb_buffer_t *buffer);
|
||||
static void
|
||||
initial_reordering (const hb_ot_shape_plan_t *plan,
|
||||
hb_font_t *font,
|
||||
hb_buffer_t *buffer);
|
||||
reorder (const hb_ot_shape_plan_t *plan,
|
||||
hb_font_t *font,
|
||||
hb_buffer_t *buffer);
|
||||
static void
|
||||
final_reordering (const hb_ot_shape_plan_t *plan,
|
||||
hb_font_t *font,
|
||||
hb_buffer_t *buffer);
|
||||
clear_syllables (const hb_ot_shape_plan_t *plan,
|
||||
hb_font_t *font,
|
||||
hb_buffer_t *buffer);
|
||||
|
||||
static void
|
||||
collect_features_myanmar (hb_ot_shape_planner_t *plan)
|
||||
|
@ -102,7 +102,7 @@ collect_features_myanmar (hb_ot_shape_planner_t *plan)
|
|||
map->enable_feature (HB_TAG('c','c','m','p'));
|
||||
|
||||
|
||||
map->add_gsub_pause (initial_reordering);
|
||||
map->add_gsub_pause (reorder);
|
||||
|
||||
for (unsigned int i = 0; i < ARRAY_LENGTH (basic_features); i++)
|
||||
{
|
||||
|
@ -110,7 +110,7 @@ collect_features_myanmar (hb_ot_shape_planner_t *plan)
|
|||
map->add_gsub_pause (nullptr);
|
||||
}
|
||||
|
||||
map->add_gsub_pause (final_reordering);
|
||||
map->add_gsub_pause (clear_syllables);
|
||||
|
||||
for (unsigned int i = 0; i < ARRAY_LENGTH (other_features); i++)
|
||||
map->enable_feature (other_features[i], F_MANUAL_ZWJ);
|
||||
|
@ -274,8 +274,8 @@ initial_reordering_consonant_syllable (hb_buffer_t *buffer,
|
|||
}
|
||||
|
||||
static void
|
||||
initial_reordering_syllable (const hb_ot_shape_plan_t *plan,
|
||||
hb_face_t *face,
|
||||
initial_reordering_syllable (const hb_ot_shape_plan_t *plan HB_UNUSED,
|
||||
hb_face_t *face HB_UNUSED,
|
||||
hb_buffer_t *buffer,
|
||||
unsigned int start, unsigned int end)
|
||||
{
|
||||
|
@ -348,32 +348,30 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED,
|
|||
}
|
||||
|
||||
static void
|
||||
initial_reordering (const hb_ot_shape_plan_t *plan,
|
||||
hb_font_t *font,
|
||||
hb_buffer_t *buffer)
|
||||
reorder (const hb_ot_shape_plan_t *plan,
|
||||
hb_font_t *font,
|
||||
hb_buffer_t *buffer)
|
||||
{
|
||||
insert_dotted_circles (plan, font, buffer);
|
||||
|
||||
foreach_syllable (buffer, start, end)
|
||||
initial_reordering_syllable (plan, font->face, buffer, start, end);
|
||||
}
|
||||
|
||||
static void
|
||||
final_reordering (const hb_ot_shape_plan_t *plan,
|
||||
hb_font_t *font HB_UNUSED,
|
||||
hb_buffer_t *buffer)
|
||||
{
|
||||
hb_glyph_info_t *info = buffer->info;
|
||||
unsigned int count = buffer->len;
|
||||
|
||||
/* Zero syllables now... */
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
info[i].syllable() = 0;
|
||||
|
||||
HB_BUFFER_DEALLOCATE_VAR (buffer, myanmar_category);
|
||||
HB_BUFFER_DEALLOCATE_VAR (buffer, myanmar_position);
|
||||
}
|
||||
|
||||
static void
|
||||
clear_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED,
|
||||
hb_font_t *font HB_UNUSED,
|
||||
hb_buffer_t *buffer)
|
||||
{
|
||||
hb_glyph_info_t *info = buffer->info;
|
||||
unsigned int count = buffer->len;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
info[i].syllable() = 0;
|
||||
}
|
||||
|
||||
|
||||
const hb_ot_complex_shaper_t _hb_ot_complex_shaper_myanmar =
|
||||
{
|
||||
|
|
|
@ -80,7 +80,8 @@ other_features[] =
|
|||
{
|
||||
/*
|
||||
* Other features.
|
||||
* These features are applied all at once, after reordering.
|
||||
* These features are applied all at once, after reordering and
|
||||
* clearing syllables.
|
||||
*/
|
||||
HB_TAG('a','b','v','s'),
|
||||
HB_TAG('b','l','w','s'),
|
||||
|
@ -120,6 +121,10 @@ static void
|
|||
reorder (const hb_ot_shape_plan_t *plan,
|
||||
hb_font_t *font,
|
||||
hb_buffer_t *buffer);
|
||||
static void
|
||||
clear_syllables (const hb_ot_shape_plan_t *plan,
|
||||
hb_font_t *font,
|
||||
hb_buffer_t *buffer);
|
||||
|
||||
static void
|
||||
collect_features_use (hb_ot_shape_planner_t *plan)
|
||||
|
@ -148,6 +153,7 @@ collect_features_use (hb_ot_shape_planner_t *plan)
|
|||
map->enable_feature (basic_features[i], F_MANUAL_ZWJ);
|
||||
|
||||
map->add_gsub_pause (reorder);
|
||||
map->add_gsub_pause (clear_syllables);
|
||||
|
||||
/* "Topographical features" */
|
||||
for (unsigned int i = 0; i < ARRAY_LENGTH (arabic_features); i++)
|
||||
|
@ -165,8 +171,6 @@ collect_features_use (hb_ot_shape_planner_t *plan)
|
|||
|
||||
struct use_shape_plan_t
|
||||
{
|
||||
ASSERT_POD ();
|
||||
|
||||
hb_mask_t rphf_mask;
|
||||
|
||||
arabic_shape_plan_t *arabic_plan;
|
||||
|
@ -373,7 +377,7 @@ setup_syllables (const hb_ot_shape_plan_t *plan,
|
|||
}
|
||||
|
||||
static void
|
||||
clear_substitution_flags (const hb_ot_shape_plan_t *plan,
|
||||
clear_substitution_flags (const hb_ot_shape_plan_t *plan HB_UNUSED,
|
||||
hb_font_t *font HB_UNUSED,
|
||||
hb_buffer_t *buffer)
|
||||
{
|
||||
|
@ -385,7 +389,7 @@ clear_substitution_flags (const hb_ot_shape_plan_t *plan,
|
|||
|
||||
static void
|
||||
record_rphf (const hb_ot_shape_plan_t *plan,
|
||||
hb_font_t *font,
|
||||
hb_font_t *font HB_UNUSED,
|
||||
hb_buffer_t *buffer)
|
||||
{
|
||||
const use_shape_plan_t *use_plan = (const use_shape_plan_t *) plan->data;
|
||||
|
@ -407,8 +411,8 @@ record_rphf (const hb_ot_shape_plan_t *plan,
|
|||
}
|
||||
|
||||
static void
|
||||
record_pref (const hb_ot_shape_plan_t *plan,
|
||||
hb_font_t *font,
|
||||
record_pref (const hb_ot_shape_plan_t *plan HB_UNUSED,
|
||||
hb_font_t *font HB_UNUSED,
|
||||
hb_buffer_t *buffer)
|
||||
{
|
||||
hb_glyph_info_t *info = buffer->info;
|
||||
|
@ -559,17 +563,21 @@ reorder (const hb_ot_shape_plan_t *plan,
|
|||
{
|
||||
insert_dotted_circles (plan, font, buffer);
|
||||
|
||||
hb_glyph_info_t *info = buffer->info;
|
||||
|
||||
foreach_syllable (buffer, start, end)
|
||||
reorder_syllable (buffer, start, end);
|
||||
|
||||
/* Zero syllables now... */
|
||||
HB_BUFFER_DEALLOCATE_VAR (buffer, use_category);
|
||||
}
|
||||
|
||||
static void
|
||||
clear_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED,
|
||||
hb_font_t *font HB_UNUSED,
|
||||
hb_buffer_t *buffer)
|
||||
{
|
||||
hb_glyph_info_t *info = buffer->info;
|
||||
unsigned int count = buffer->len;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
info[i].syllable() = 0;
|
||||
|
||||
HB_BUFFER_DEALLOCATE_VAR (buffer, use_category);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -30,9 +30,9 @@ _output_with_dotted_circle (hb_buffer_t *buffer)
|
|||
}
|
||||
|
||||
void
|
||||
_hb_preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan,
|
||||
_hb_preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan HB_UNUSED,
|
||||
hb_buffer_t *buffer,
|
||||
hb_font_t *font)
|
||||
hb_font_t *font HB_UNUSED)
|
||||
{
|
||||
/* UGLY UGLY UGLY business of adding dotted-circle in the middle of
|
||||
* vowel-sequences that look like another vowel. Data for each script
|
||||
|
|
|
@ -192,7 +192,7 @@ zero_mark_advances (hb_buffer_t *buffer,
|
|||
}
|
||||
|
||||
static inline void
|
||||
position_mark (const hb_ot_shape_plan_t *plan,
|
||||
position_mark (const hb_ot_shape_plan_t *plan HB_UNUSED,
|
||||
hb_font_t *font,
|
||||
hb_buffer_t *buffer,
|
||||
hb_glyph_extents_t &base_extents,
|
||||
|
@ -472,15 +472,13 @@ _hb_ot_shape_fallback_kern (const hb_ot_shape_plan_t *plan,
|
|||
|
||||
/* Adjusts width of various spaces. */
|
||||
void
|
||||
_hb_ot_shape_fallback_spaces (const hb_ot_shape_plan_t *plan,
|
||||
_hb_ot_shape_fallback_spaces (const hb_ot_shape_plan_t *plan HB_UNUSED,
|
||||
hb_font_t *font,
|
||||
hb_buffer_t *buffer)
|
||||
{
|
||||
if (!HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction))
|
||||
return;
|
||||
|
||||
hb_glyph_info_t *info = buffer->info;
|
||||
hb_glyph_position_t *pos = buffer->pos;
|
||||
bool horizontal = HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction);
|
||||
unsigned int count = buffer->len;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
if (_hb_glyph_info_is_unicode_space (&info[i]) && !_hb_glyph_info_ligated (&info[i]))
|
||||
|
@ -501,27 +499,40 @@ _hb_ot_shape_fallback_spaces (const hb_ot_shape_plan_t *plan,
|
|||
case t::SPACE_EM_5:
|
||||
case t::SPACE_EM_6:
|
||||
case t::SPACE_EM_16:
|
||||
pos[i].x_advance = (font->x_scale + ((int) space_type)/2) / (int) space_type;
|
||||
if (horizontal)
|
||||
pos[i].x_advance = (font->x_scale + ((int) space_type)/2) / (int) space_type;
|
||||
else
|
||||
pos[i].y_advance = (font->y_scale + ((int) space_type)/2) / (int) space_type;
|
||||
break;
|
||||
|
||||
case t::SPACE_4_EM_18:
|
||||
pos[i].x_advance = (int64_t) font->x_scale * 4 / 18;
|
||||
if (horizontal)
|
||||
pos[i].x_advance = (int64_t) font->x_scale * 4 / 18;
|
||||
else
|
||||
pos[i].y_advance = (int64_t) font->y_scale * 4 / 18;
|
||||
break;
|
||||
|
||||
case t::SPACE_FIGURE:
|
||||
for (char u = '0'; u <= '9'; u++)
|
||||
if (font->get_nominal_glyph (u, &glyph))
|
||||
{
|
||||
pos[i].x_advance = font->get_glyph_h_advance (glyph);
|
||||
if (horizontal)
|
||||
pos[i].x_advance = font->get_glyph_h_advance (glyph);
|
||||
else
|
||||
pos[i].y_advance = font->get_glyph_v_advance (glyph);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case t::SPACE_PUNCTUATION:
|
||||
if (font->get_nominal_glyph ('.', &glyph))
|
||||
pos[i].x_advance = font->get_glyph_h_advance (glyph);
|
||||
else if (font->get_nominal_glyph (',', &glyph))
|
||||
pos[i].x_advance = font->get_glyph_h_advance (glyph);
|
||||
if (font->get_nominal_glyph ('.', &glyph) ||
|
||||
font->get_nominal_glyph (',', &glyph))
|
||||
{
|
||||
if (horizontal)
|
||||
pos[i].x_advance = font->get_glyph_h_advance (glyph);
|
||||
else
|
||||
pos[i].y_advance = font->get_glyph_v_advance (glyph);
|
||||
}
|
||||
break;
|
||||
|
||||
case t::SPACE_NARROW:
|
||||
|
@ -530,7 +541,10 @@ _hb_ot_shape_fallback_spaces (const hb_ot_shape_plan_t *plan,
|
|||
* However, in my testing, many fonts have their regular space being about that
|
||||
* size. To me, a percentage of the space width makes more sense. Half is as
|
||||
* good as any. */
|
||||
pos[i].x_advance /= 2;
|
||||
if (horizontal)
|
||||
pos[i].x_advance /= 2;
|
||||
else
|
||||
pos[i].y_advance /= 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -213,17 +213,19 @@ decompose_current_character (const hb_ot_shape_normalize_context_t *c, bool shor
|
|||
}
|
||||
|
||||
static inline void
|
||||
handle_variation_selector_cluster (const hb_ot_shape_normalize_context_t *c, unsigned int end, bool short_circuit)
|
||||
handle_variation_selector_cluster (const hb_ot_shape_normalize_context_t *c,
|
||||
unsigned int end,
|
||||
bool short_circuit HB_UNUSED)
|
||||
{
|
||||
/* TODO Currently if there's a variation-selector we give-up, it's just too hard. */
|
||||
hb_buffer_t * const buffer = c->buffer;
|
||||
hb_font_t * const font = c->font;
|
||||
for (; buffer->idx < end - 1 && buffer->successful;) {
|
||||
if (unlikely (buffer->unicode->is_variation_selector (buffer->cur(+1).codepoint))) {
|
||||
/* The next two lines are some ugly lines... But work. */
|
||||
if (font->get_variation_glyph (buffer->cur().codepoint, buffer->cur(+1).codepoint, &buffer->cur().glyph_index()))
|
||||
{
|
||||
buffer->replace_glyphs (2, 1, &buffer->cur().codepoint);
|
||||
hb_codepoint_t unicode = buffer->cur().codepoint;
|
||||
buffer->replace_glyphs (2, 1, &unicode);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -42,6 +42,16 @@
|
|||
#include "hb-aat-layout.hh"
|
||||
|
||||
|
||||
/**
|
||||
* SECTION:hb-ot-shape
|
||||
* @title: hb-ot-shape
|
||||
* @short_description: OpenType shaping support
|
||||
* @include: hb-ot.h
|
||||
*
|
||||
* Support functions for OpenType shaping related queries.
|
||||
**/
|
||||
|
||||
|
||||
static bool
|
||||
_hb_apply_morx (hb_face_t *face)
|
||||
{
|
||||
|
@ -276,7 +286,7 @@ _hb_ot_shaper_font_data_create (hb_font_t *font HB_UNUSED)
|
|||
}
|
||||
|
||||
void
|
||||
_hb_ot_shaper_font_data_destroy (hb_ot_font_data_t *data)
|
||||
_hb_ot_shaper_font_data_destroy (hb_ot_font_data_t *data HB_UNUSED)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -102,9 +102,6 @@ struct hb_ot_shape_planner_t
|
|||
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);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -242,7 +242,6 @@ hb_ot_tag_from_language (hb_language_t 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)
|
||||
{
|
||||
|
@ -389,7 +388,7 @@ hb_ot_tags_from_script_and_language (hb_script_t script,
|
|||
needs_language = parse_private_use_subtag (private_use_subtag, language_count, language_tags, "-hbot", TOUPPER);
|
||||
|
||||
if (needs_language && language_count && language_tags && *language_count)
|
||||
hb_ot_tags_from_language (lang_str, limit, private_use_subtag, language_count, language_tags);
|
||||
hb_ot_tags_from_language (lang_str, limit, language_count, language_tags);
|
||||
}
|
||||
|
||||
if (needs_script && script_count && script_tags && *script_count)
|
||||
|
|
|
@ -1,78 +0,0 @@
|
|||
/*
|
||||
* Copyright © 2009 Red Hat, Inc.
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*
|
||||
* Red Hat Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
#ifndef HB_OT_H_IN
|
||||
#error "Include <hb-ot.h> instead."
|
||||
#endif
|
||||
|
||||
#ifndef HB_OT_TAG_H
|
||||
#define HB_OT_TAG_H
|
||||
|
||||
#include "hb.h"
|
||||
|
||||
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_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_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
|
||||
|
||||
#endif /* HB_OT_TAG_H */
|
|
@ -32,6 +32,17 @@
|
|||
#include "hb-ot-var-mvar-table.hh"
|
||||
#include "hb-ot-var.h"
|
||||
|
||||
|
||||
/**
|
||||
* SECTION:hb-ot-var
|
||||
* @title: hb-ot-var
|
||||
* @short_description: OpenType Font Variations
|
||||
* @include: hb-ot.h
|
||||
*
|
||||
* Functions for fetching information about OpenType Variable Fonts.
|
||||
**/
|
||||
|
||||
|
||||
/*
|
||||
* fvar/avar
|
||||
*/
|
||||
|
|
|
@ -70,7 +70,7 @@ struct VORG
|
|||
return defaultVertOriginY;
|
||||
}
|
||||
|
||||
inline bool _subset (const hb_subset_plan_t *plan,
|
||||
inline bool _subset (const hb_subset_plan_t *plan HB_UNUSED,
|
||||
const VORG *vorg_table,
|
||||
const hb_vector_t<VertOriginMetric> &subset_metrics,
|
||||
unsigned int dest_sz,
|
||||
|
|
|
@ -35,7 +35,6 @@
|
|||
#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"
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue