Merge branch 'master' into cff-subset

This commit is contained in:
Michiharu Ariza 2018-11-01 16:13:56 -07:00
commit e600e5440b
144 changed files with 5233 additions and 1848 deletions

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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 &lt;hb.h&gt;
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 &lt;hb-ft.h&gt;
FT_New_Face(ft_library, font_path, index, &amp;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, &amp;glyph_count);
hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions(buf, &amp;glyph_count);
</programlisting>
<orderedlist numeration="arabic">
<listitem override="6">
<para>
Iterate over each glyph.
</para>
</listitem>
</orderedlist>
<programlisting language="C">
for (i = 0; i &lt; 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>

View File

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

View File

@ -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 &lt;hb.h&gt;
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 &lt;hb-ft.h&gt;
FT_New_Face(ft_library, font_path, index, &amp;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, &amp;glyph_count);
hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions(buf, &amp;glyph_count);
</programlisting>
<orderedlist numeration="arabic">
<listitem override="6">
<para>
Iterate over each glyph.
</para>
</listitem>
</orderedlist>
<programlisting language="C">
for (i = 0; i &lt; 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>
(&quot;bidi&quot; 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 &quot;a
<emphasis>huge</emphasis> breakfast&quot;, and you expect
&quot;huge&quot; 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>

View File

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

View File

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

View File

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

View File

@ -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
&quot;a&quot; 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 &quot;cmap&quot; 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 &quot;a&quot; as glyph ID 1, but
many others do not. In order to retrieve the right glyph
from the font to display &quot;a&quot;, 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 &quot;&quot;. Whether you should
render text as <literal>fi</literal> or &quot;&quot; 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
&quot;&quot;.
</para>
<para>
Whether you should render an &quot;f, i&quot; sequence
as <literal>fi</literal> or as &quot;&quot; does not
depend on the input text. Instead, it depends on the whether
or not the font includes an &quot;&quot; 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 &quot;&quot; are typographic
refinements, some languages <emphasis>require</emphasis> such
While ligatures like &quot;&quot; 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 &quot;TTA&quot; (ட) letter is
followed by &quot;U&quot; (உ), the combination should appear
as the single glyph &quot;டு&quot;. The sequence of Unicode
characters &quot;டஉ&quot; 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 &quot;TTA&quot; (ட)
letter is followed by &quot;U&quot; (உ), the pair
must be replaced by the single glyph &quot;டு&quot;. The
sequence of Unicode characters &quot;டஉ&quot; needs to be
substituted with a single &quot;டு&quot; glyph from the
font.
</para>
<para>
But &quot;டு&quot; 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
&quot;zhe&quot; (ж) 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
&quot;zhe&quot; (ж) with a breve accent, like so: &quot;ӂ&quot;.
</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 &quot;ж&quot; and &quot;˘&quot;
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&mdash;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>
(&quot;bidi&quot; 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 &quot;a
<emphasis>huge</emphasis> breakfast&quot;, and you expect
&quot;huge&quot; 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&mdash;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 - &quot;HarfBuzz&quot; is the Persian
for &quot;open type&quot;.
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&mdash;&quot;HarfBuzz&quot; is
the Persian for &quot;open type&quot;.
</para>
</section>
</chapter>
</chapter>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -42,7 +42,6 @@
struct hb_face_t
{
hb_object_header_t header;
ASSERT_POD ();
hb_bool_t immutable;

View File

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

View File

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

View File

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

View File

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

View File

@ -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[] =

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

457
src/hb-ot-name-language.cc Normal file
View File

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

View File

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

View File

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

231
src/hb-ot-name.cc Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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