diff --git a/.circleci/config.yml b/.circleci/config.yml index 46fb65b2e..90c094059 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -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 diff --git a/CMakeLists.txt b/CMakeLists.txt index 4eb23af4d..019e205bc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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}) diff --git a/NEWS b/NEWS index b8d364081..cb8a28ff0 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,84 @@ +Overview of changes leading to 2.1.0 +Tuesday, October 30, 2018 +==================================== +- AAT shaping improvements: + o Allow user controlling AAT features, for whole buffer only currently. + o Several 'morx' fixes. + o Implement tuple-kerns in 'kerx'; Fixes kerning with Apple default + San Francisco fonts. +- Support for color fonts: + o COLR/CPAL API to fetch color layers. + o SVG table to fetch SVG documents. + o CBDT/sbix API to fetch PNG images. +- New 'name' table API. +- hb-ot-font now uses 'VORG' table to correctly position CFF glyphs + in vertical layout. +- Various fuzzer-found bug fixes. + +Changed API: + +A type and a macro added in 2.0.0 were renamed: + +hb_name_id_t -> hb_ot_name_id_t +HB_NAME_ID_INVALID -> HB_OT_NAME_ID_INVALID + +New API: + ++hb_color_t ++HB_COLOR ++hb_color_get_alpha() ++hb_color_get_red() ++hb_color_get_green() ++hb_color_get_blue() ++hb_ot_color_has_palettes() ++hb_ot_color_palette_get_count() ++hb_ot_color_palette_get_name_id() ++hb_ot_color_palette_color_get_name_id() ++hb_ot_color_palette_flags_t ++hb_ot_color_palette_get_flags() ++hb_ot_color_palette_get_colors() ++hb_ot_color_has_layers() ++hb_ot_color_layer_t ++hb_ot_color_glyph_get_layers() ++hb_ot_color_has_svg() ++hb_ot_color_glyph_reference_svg() ++hb_ot_color_has_png() ++hb_ot_color_glyph_reference_png() + ++hb_ot_name_id_t ++HB_OT_NAME_ID_INVALID ++HB_OT_NAME_ID_COPYRIGHT ++HB_OT_NAME_ID_FONT_FAMILY ++HB_OT_NAME_ID_FONT_SUBFAMILY ++HB_OT_NAME_ID_UNIQUE_ID ++HB_OT_NAME_ID_FULL_NAME ++HB_OT_NAME_ID_VERSION_STRING ++HB_OT_NAME_ID_POSTSCRIPT_NAME ++HB_OT_NAME_ID_TRADEMARK ++HB_OT_NAME_ID_MANUFACTURER ++HB_OT_NAME_ID_DESIGNER ++HB_OT_NAME_ID_DESCRIPTION ++HB_OT_NAME_ID_VENDOR_URL ++HB_OT_NAME_ID_DESIGNER_URL ++HB_OT_NAME_ID_LICENSE ++HB_OT_NAME_ID_LICENSE_URL ++HB_OT_NAME_ID_TYPOGRAPHIC_FAMILY ++HB_OT_NAME_ID_TYPOGRAPHIC_SUBFAMILY ++HB_OT_NAME_ID_MAC_FULL_NAME ++HB_OT_NAME_ID_SAMPLE_TEXT ++HB_OT_NAME_ID_CID_FINDFONT_NAME ++HB_OT_NAME_ID_WWS_FAMILY ++HB_OT_NAME_ID_WWS_SUBFAMILY ++HB_OT_NAME_ID_LIGHT_BACKGROUND ++HB_OT_NAME_ID_DARK_BACKGROUND ++HB_OT_NAME_ID_VARIATIONS_PS_PREFIX ++hb_ot_name_entry_t ++hb_ot_name_list_names() ++hb_ot_name_get_utf8() ++hb_ot_name_get_utf16() ++hb_ot_name_get_utf32() + + Overview of changes leading to 2.0.2 Saturday, October 20, 2018 ==================================== diff --git a/RELEASING.md b/RELEASING.md index 4f5705e53..1fd836545 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -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. diff --git a/configure.ac b/configure.ac index a2d0992a7..21d48f39a 100644 --- a/configure.ac +++ b/configure.ac @@ -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/]) diff --git a/docs/Makefile.am b/docs/Makefile.am index e48b9ccd8..9b54b40e1 100644 --- a/docs/Makefile.am +++ b/docs/Makefile.am @@ -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 diff --git a/docs/harfbuzz-docs.xml b/docs/harfbuzz-docs.xml index 9452a92af..66a64d8f9 100644 --- a/docs/harfbuzz-docs.xml +++ b/docs/harfbuzz-docs.xml @@ -12,28 +12,21 @@ HarfBuzz is an OpenType - text shaping engine. + text shaping engine. Using the HarfBuzz library allows + programs to convert a sequence of Unicode input into + properly formatted and positioned glyph output—for any writing + system and language. + - 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 - here. - Also available on - github. - See for release tarballs. - - - The old HarfBuzz codebase, these days known as harfbuzz-old, was - derived from FreeType, - Pango, and - Qt and is available - here. - 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 + github.com/harfbuzz/harfbuzz + and is also available at + cgit.freedesktop.org/harfbuzz. + See for + release tarballs. @@ -42,7 +35,8 @@ User's manual - + + @@ -58,152 +52,119 @@ http://[SERVER]/libharfbuzz/.--> + + + + 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. + + + Prior to 2012, the original HarfBuzz codebase (which, these + days, is referred to as harfbuzz-old) was + derived from code in FreeType, Pango, and + Qt. + It is not 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. + + + To make this distinction clearer in discussions, the current + HarfBuzz codebase is sometimes referred to as + harfbuzz-ng. + + + For reference purposes, the harfbuzz-old source tree is archived + here. There + are no release tarballs of harfbuzz-old whatsoever. + + + Reference manual - HarfBuzz API - - - - + Core API + + + - - - - - + - - - - - - - - - - - - - - - - - - - - + + + - + + + OpenType API + + + + + + + + + + + Integration API + + + + + + + + + + + + API Index + Index of deprecated API + + Index of new symbols in 2.1.0 + Index of new symbols in 2.0.0 + Index of new symbols in 1.9.0 + Index of new symbols in 1.8.6 + Index of new symbols in 1.8.5 + Index of new symbols in 1.8.1 + Index of new symbols in 1.8.0 + Index of new symbols in 1.7.7 + Index of new symbols in 1.7.5 + Index of new symbols in 1.6.0 + Index of new symbols in 1.5.0 + Index of new symbols in 1.4.3 + Index of new symbols in 1.4.2 + Index of new symbols in 1.4.0 + Index of new symbols in 1.3.3 + Index of new symbols in 1.2.3 + Index of new symbols in 1.1.3 + Index of new symbols in 1.1.2 + Index of new symbols in 1.0.5 + Index of new symbols in 0.9.42 + Index of new symbols in 0.9.41 + Index of new symbols in 0.9.39 + Index of new symbols in 0.9.38 + Index of new symbols in 0.9.31 + Index of new symbols in 0.9.30 + Index of new symbols in 0.9.28 + Index of new symbols in 0.9.22 + Index of new symbols in 0.9.20 + Index of new symbols in 0.9.11 + Index of new symbols in 0.9.10 + Index of new symbols in 0.9.8 + Index of new symbols in 0.9.7 + Index of new symbols in 0.9.5 + Index of new symbols in 0.9.2 diff --git a/docs/harfbuzz-sections.txt b/docs/harfbuzz-sections.txt index fccfcb0ed..6a498e940 100644 --- a/docs/harfbuzz-sections.txt +++ b/docs/harfbuzz-sections.txt @@ -1,8 +1,6 @@ -
-hb HB_H_IN -HB_EXTERN +HB_OT_H_IN
@@ -146,6 +144,10 @@ uint16_t uint32_t uint64_t uint8_t + +HB_EXTERN +HB_DEPRECATED +HB_DEPRECATED_FOR
@@ -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
-
-hb-gobject - -
-
hb-graphite2 HB_GRAPHITE2_TAG_SILF @@ -452,9 +451,27 @@ hb_map_t
-hb-ot - -HB_OT_H_IN +hb-ot-color +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
@@ -463,16 +480,31 @@ hb_ot_font_set_funcs
-hb-ot-shape -hb_ot_shape_glyphs_closure +hb-ot-name +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
hb-ot-layout +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
-
-hb-ot-var -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 -
-
hb-ot-math HB_OT_TAG_MATH @@ -555,15 +570,25 @@ hb_ot_math_get_glyph_assembly
-hb-ot-tag -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-shape +hb_ot_shape_glyphs_closure +
+ +
+hb-ot-var +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
diff --git a/docs/usermanual-buffers-language-script-and-direction.xml b/docs/usermanual-buffers-language-script-and-direction.xml index 9eddb71a9..68ce9bd0b 100644 --- a/docs/usermanual-buffers-language-script-and-direction.xml +++ b/docs/usermanual-buffers-language-script-and-direction.xml @@ -1,3 +1,9 @@ + + + +]> Buffers, language, script and direction @@ -74,4 +80,4 @@ void somefunc(hb_buffer_t *buffer) {
-
\ No newline at end of file + diff --git a/docs/usermanual-clusters.xml b/docs/usermanual-clusters.xml index 608371b00..7b2c7adc7 100644 --- a/docs/usermanual-clusters.xml +++ b/docs/usermanual-clusters.xml @@ -1,3 +1,9 @@ + + + +]> Clusters diff --git a/docs/usermanual-fonts-and-faces.xml b/docs/usermanual-fonts-and-faces.xml index 7de0f051a..553600439 100644 --- a/docs/usermanual-fonts-and-faces.xml +++ b/docs/usermanual-fonts-and-faces.xml @@ -1,3 +1,9 @@ + + + +]> Fonts and faces
@@ -15,4 +21,4 @@
-
\ No newline at end of file +
diff --git a/docs/usermanual-getting-started.xml b/docs/usermanual-getting-started.xml new file mode 100644 index 000000000..9e16ecbf2 --- /dev/null +++ b/docs/usermanual-getting-started.xml @@ -0,0 +1,222 @@ + + + +]> + + Getting started with HarfBuzz +
+ An overview of the HarfBuzz shaping API + + The core of the HarfBuzz shaping API is the function + hb_shape(). 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. + + + 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. + + + + 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 Default + Ignorable codepoints, and to modify the cluster-merging + behavior for the buffer. For shaped output buffers, the + individual X and Y offsets and advances + (the logical dimensions) of each glyph are + accessible. HarfBuzz also flags glyphs as + UNSAFE_TO_BREAK if breaking the string at + that glyph (e.g., in a line-breaking or hyphenation process) + would require re-shaping the text. + + + + 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. + + + + Although the default hb_shape() 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. + + + + 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. + + + + 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. + +
+ +
+ Terminology + + + shaper + + + In HarfBuzz, a shaper 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. + + + + + + cluster + + + In text shaping, a cluster 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. + + + HarfBuzz provides three cluster + levels that implement different + approaches to the problem of preserving clusters during + shaping operations. + + + + + + + +
+ + +
+ A simple shaping example + + + Below is the simplest HarfBuzz shaping example possible. + + + + + Create a buffer and put your text in it. + + + + + #include <hb.h> + hb_buffer_t *buf; + buf = hb_buffer_create(); + hb_buffer_add_utf8(buf, text, -1, 0, -1); + + + + + Guess the script, language and direction of the buffer. + + + + + 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)); + + + + + Create a face and a font, using FreeType for now. + + + + + #include <hb-ft.h> + FT_New_Face(ft_library, font_path, index, &face) + hb_font_t *font = hb_ft_font_create(face); + + + + + Shape! + + + + + hb_shape(font, buf, NULL, 0); + + + + + Get the glyph and position information. + + + + + hb_glyph_info_t *glyph_info = hb_buffer_get_glyph_infos(buf, &glyph_count); + hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions(buf, &glyph_count); + + + + + Iterate over each glyph. + + + + + for (i = 0; i < glyph_count; ++i) { + glyphid = glyph_info[i].codepoint; + x_offset = glyph_pos[i].x_offset / 64.0; + y_offset = glyph_pos[i].y_offset / 64.0; + x_advance = glyph_pos[i].x_advance / 64.0; + y_advance = glyph_pos[i].y_advance / 64.0; + draw_glyph(glyphid, cursor_x + x_offset, cursor_y + y_offset); + cursor_x += x_advance; + cursor_y += y_advance; + } + + + + + Tidy up. + + + + + hb_buffer_destroy(buf); + hb_font_destroy(hb_ft_font); + + + + 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. + +
+
diff --git a/docs/usermanual-glyph-information.xml b/docs/usermanual-glyph-information.xml index ca674c0c5..78f06c739 100644 --- a/docs/usermanual-glyph-information.xml +++ b/docs/usermanual-glyph-information.xml @@ -1,3 +1,9 @@ + + + +]> Glyph information @@ -5,4 +11,4 @@ - \ No newline at end of file + diff --git a/docs/usermanual-hello-harfbuzz.xml b/docs/usermanual-hello-harfbuzz.xml deleted file mode 100644 index 716b2f2dd..000000000 --- a/docs/usermanual-hello-harfbuzz.xml +++ /dev/null @@ -1,183 +0,0 @@ - - Hello, HarfBuzz - - Here's the simplest HarfBuzz that can possibly work. We will improve - it later. - - - - - Create a buffer and put your text in it. - - - - - #include <hb.h> - hb_buffer_t *buf; - buf = hb_buffer_create(); - hb_buffer_add_utf8(buf, text, strlen(text), 0, strlen(text)); - - - - - Guess the script, language and direction of the buffer. - - - - - hb_buffer_guess_segment_properties(buf); - - - - - Create a face and a font, using FreeType for now. - - - - - #include <hb-ft.h> - FT_New_Face(ft_library, font_path, index, &face) - hb_font_t *font = hb_ft_font_create(face); - - - - - Shape! - - - - - hb_shape(font, buf, NULL, 0); - - - - - Get the glyph and position information. - - - - - hb_glyph_info_t *glyph_info = hb_buffer_get_glyph_infos(buf, &glyph_count); - hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions(buf, &glyph_count); - - - - - Iterate over each glyph. - - - - - for (i = 0; i < glyph_count; ++i) { - glyphid = glyph_info[i].codepoint; - x_offset = glyph_pos[i].x_offset / 64.0; - y_offset = glyph_pos[i].y_offset / 64.0; - x_advance = glyph_pos[i].x_advance / 64.0; - y_advance = glyph_pos[i].y_advance / 64.0; - draw_glyph(glyphid, cursor_x + x_offset, cursor_y + y_offset); - cursor_x += x_advance; - cursor_y += y_advance; - } - - - - - Tidy up. - - - - - hb_buffer_destroy(buf); - hb_font_destroy(hb_ft_font); - -
- What HarfBuzz doesn't do - - 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. - - - If you are implementing a text layout engine you may have other - responsibilities, that HarfBuzz will not help you with: - - - - - 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: - - -A B C [space] ג ב א [space] D E F - - - but will expect to see in the output: - - -ABC אבג DEF - - - This reordering is called bidi processing - ("bidi" is short for bidirectional), and there's an - algorithm as an annex to the Unicode Standard which tells you how - to reorder a string from logical order into presentation order. - Before sending your string to HarfBuzz, you may need to apply the - bidi algorithm to it. Libraries such as ICU and fribidi can do - this for you. - - - - - HarfBuzz won't help you with text that contains different font - properties. For instance, if you have the string "a - huge breakfast", and you expect - "huge" to be italic, you will need to send three - strings to HarfBuzz: a, in your Roman font; - huge using your italic font; and - breakfast 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. - - - - - HarfBuzz won't help you with line breaking, hyphenation or - justification. As mentioned above, it lays out the string - along a single line 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. - - - 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. - - - - - 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. - -
-
\ No newline at end of file diff --git a/docs/usermanual-install-harfbuzz.xml b/docs/usermanual-install-harfbuzz.xml index 899cc5bd6..a6484fc5a 100644 --- a/docs/usermanual-install-harfbuzz.xml +++ b/docs/usermanual-install-harfbuzz.xml @@ -1,70 +1,431 @@ + + + +]> - Install HarfBuzz + Installing HarfBuzz +
- Download + Downloading HarfBuzz - For tarball releases of HarfBuzz, look - here. - 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 github.com/harfbuzz/harfbuzz. The + same source tree is also available at the + Freedesktop.org + site. - The canonical source tree is available - here. - Also available on github. + 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 github.com/harfbuzz/harfbuzz/releases + or from + Freedesktop.org. - The API that comes with hb.h 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 tracks bug + reports and other issues on GitHub. Discussion and + questions are welcome on the HarfBuzz + mailing list. - If you are not sure whether Pango or HarfBuzz is right for you, read - this. + The API included in the hb.h 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 never break the ABI.
+
- Building + Building HarfBuzz + +
+ Building on Linux - On Linux, install the development packages for FreeType, Cairo, and GLib. - For example, on Ubuntu / Debian, you would do: - -sudo apt-get install gcc g++ libfreetype6-dev libglib2.0-dev libcairo2-dev - - whereas on Fedora, RHEL, CentOS, and other Red Hat based systems you would do: - -sudo yum install gcc gcc-c++ freetype-devel glib2-devel cairo-devel - - or using MacPorts: - -sudo port install freetype glib2 cairo - + (1) 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. - If you are using a tarball, you can now proceed to running - configure and make as with any - other standard package. That should leave you with a shared library in - src/, and a few utility programs including hb-view - and hb-shape under util/. + For example, on an Ubuntu or Debian system, you would run: + + sudo apt install gcc g++ + libfreetype6-dev libglib2.0-dev libcairo2-dev + + On Fedora, RHEL, CentOS, or other Red-Hat–based systems, you would run: + + sudo yum install gcc gcc-c++ freetype-devel glib2-devel cairo-devel + + + + + + (2) 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. - If you are bootstrapping from git, you need a few more tools before you - can run autogen.sh for the first time. Namely, - pkg-config and ragel. - Again, on Ubuntu / Debian: - -sudo apt-get install autoconf automake libtool pkg-config ragel gtk-doc-tools - - and on Fedora, RHEL, CentOS: - -sudo yum install autoconf automake libtool pkgconfig ragel gtk-doc - - or using MacPorts: - -sudo port install autoconf automake libtool pkgconfig ragel gtk-doc - + (2)(a) If you downloaded the HarfBuzz + source code in a tarball, you can now extract the source. + + From a shell in the top-level directory of the extracted source + code, you can run ./configure followed by + make as with any other standard package. + + + This should leave you with a shared + library in the src/ directory, and a few + utility programs including hb-view and + hb-shape under the util/ + directory. + + + (2)(b) 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: pkg-config and + ragel. + + + On Ubuntu or Debian, run: + + sudo apt-get install autoconf automake libtool pkg-config ragel gtk-doc-tools + + On Fedora, RHEL, CentOS, run: + + sudo yum install autoconf automake libtool pkgconfig ragel gtk-doc + + + + + With pkg-config and ragel + installed, you can now run ./autogen.sh, + followed by ./configure and + make to build HarfBuzz. + +
+ + +
+ Building on Windows + + + On Windows, consider using Microsoft's free vcpkg utility + to build HarfBuzz, its dependencies, and other open-source + libraries. + + + If you need to build HarfBuzz from source, first put the + ragel binary on your + PATH, then follow the appveyor CI cmake + build + instructions. + +
+ + +
+ Building on macOS + + + 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. + + + (1) You must first install the + development packages for FreeType, Cairo, and GLib. If you are + using MacPorts, you should run: + + sudo port install freetype glib2 cairo + + + + If you are using Homebrew, you should run: + + brew install freetype glib cairo + + + + (2) 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. + + + (2)(a) If you are installing HarfBuzz + from a downloaded tarball release, extract the tarball and + open a Terminal in the extracted source-code directory. Run: + + ./configure + + followed by: + + make + + to build HarfBuzz. + + + (2)(b) Alternatively, if you are building + HarfBuzz from the source in the HarfBuzz git repository, then + you must install several built-time dependencies before + proceeding. + + If you are + using MacPorts, you should run: + + sudo port install autoconf + automake libtool pkgconfig ragel gtk-doc + + to install the build dependencies. + + If you are using Homebrew, you should run: + + brew install autoconf automake libtool pkgconfig ragel gtk-doc + + Finally, you can run: + + ./autogen.sh + + + + (3) You can now build HarfBuzz (on either + a MacPorts or a Homebrew system) by running: + + ./configure + + followed by: + + make + + + + This should leave you with a shared + library in the src/ directory, and a few + utility programs including hb-view and + hb-shape under the util/ + directory. + + +
+ +
+ Configuration options + + + 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. + + + + + --with-libstdc++ + + + Allow linking with libstdc++. (Default = no) + + + This option enables or disables linking HarfBuzz to the + system's libstdc++ library. + + + + + + --with-glib + + + Use GLib. (Default = auto) + + + 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. + + + + + + --with-gobject + + + Use GObject. (Default = no) + + + 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. + + + + + + --with-cairo + + + Use Cairo. (Default = auto) + + + 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. + + + Note: Cairo is used only by the HarfBuzz + command-line utilities, and not by the HarfBuzz library. + + + + + + --with-fontconfig + + + Use Fontconfig. (Default = auto) + + + 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. + + + Note: Fontconfig is used only by the HarfBuzz + command-line utilities, and not by the HarfBuzz library. + + + + + + --with-icu + + + Use the ICU library. (Default = auto) + + + This option enables or disables usage of the + International Components for + Unicode (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. + + + + + + --with-ucdn + + + Use HarfBuzz's built-in UCDN library. (Default = auto) + + + The HarfBuzz source tree includes a Unicode + Database and Normalization (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. + + + + + + --with-graphite2 + + + Use the Graphite2 library. (Default = no) + + + This option enables or disables usage of the Graphite2 + library, which provides support for the Graphite shaping + model. + + + + + + --with-freetype + + + Use the FreeType library. (Default = auto) + + + 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. + + + + + + --with-uniscribe + + + Use the Uniscribe + library (experimental). (Default = no) + + + 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. + + + + + + --with-directwrite + + + Use the DirectWrite library (experimental). (Default = no) + + + 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. + + + + + + --with-coretext + + + Use the CoreText library. (Default = no) + + + This option enables or disables usage of the CoreText + library. CoreText is available on macOS and iOS systems. + + + + +
+
diff --git a/docs/usermanual-opentype-features.xml b/docs/usermanual-opentype-features.xml index 470bab8d1..51ff55a77 100644 --- a/docs/usermanual-opentype-features.xml +++ b/docs/usermanual-opentype-features.xml @@ -1,3 +1,9 @@ + + + +]> Shaping and shape plans
@@ -10,4 +16,4 @@
-
\ No newline at end of file + diff --git a/docs/usermanual-shaping-concepts.xml b/docs/usermanual-shaping-concepts.xml new file mode 100644 index 000000000..bc9f1b830 --- /dev/null +++ b/docs/usermanual-shaping-concepts.xml @@ -0,0 +1,374 @@ + + + +]> + + Shaping concepts +
+ Text shaping + + 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. + + + For some writing systems (or scripts) 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. + + + But, for complex scripts, 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. + + + The exact rules and necessary operations for a particular script + constitute a shaping model. 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). + +
+ +
+ Complex scripts + + In text-shaping terminology, scripts are generally classified as + either complex or non-complex. + + + Complex scripts are those for which transforming the input + sequence into the final layout requires some combination of + operations—such as context-dependent substitutions, + context-dependent mark positioning, glyph-to-glyph joining, + glyph reordering, or glyph stacking. + + + 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. + + + 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. + +
+ +
+ Shaping operations + + 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. + + + 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. + + + + + + A reordering operation moves a glyph + from its original ("logical") position in the sequence to + some other ("visual") position. + + + The shaping model for a given complex script might involve + more than one reordering step. + + + + + + A joining operation replaces a glyph + with an alternate form that is designed to connect with one + or more of the adjacent glyphs in the sequence. + + + + + + A contextual substitution 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. + + + 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. + + + + + + A contextual positioning 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. + + + Many contextual positioning operations are used to place + mark glyphs (such as diacritics, vowel + signs, and tone markers) with respect to + base glyphs. However, some complex + scripts may use contextual positioning operations to + correctly place base glyphs as well, such as + when the script uses stacking characters. + + + + +
+ +
+ Unicode character categories + + Shaping models are typically specified with respect to how + scripts are defined in the Unicode standard. + + + Every codepoint in the Unicode Character Database (UCD) is + assigned a Unicode General Category (UGC), + which provides the most fundamental information about the + codepoint: whether the codepoint represents a + Letter, a Mark, a + Number, Punctuation, a + Symbol, a Separator, + or something else (Other). + + + These UGC properties are "Major" categories. Each codepoint is + further assigned to a "minor" category within its Major + category, such as "Letter, uppercase" (Lu) or + "Letter, modifier" (Lm). + + + 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 + (Mn), spacing combining + (Mc), or enclosing (Me). + + + In addition to the UGC property, codepoints in the Indic and + Southeast Asian scripts are also assigned + Unicode Indic Syllabic Category (UISC) and + Unicode Indic Positional Category (UIPC) + property that provides more detailed information needed for + shaping. + + + 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). + + + 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. + + +
+ +
+ Text runs + + 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). + + + For shaping purposes, all real-world text streams must be first + segmented into runs that have a uniform set of properties. + + + In particular, shaping models always assume that every codepoint + in a text run has the same direction, + script tag, and + language tag. + +
+ +
+ OpenType shaping models + + OpenType provides shaping models for the following scripts: + + + + + + The default shaping model handles all + non-complex scripts, and may also be used as a fallback for + handling unrecognized scripts. + + + + + + The Indic shaping model handles the Indic + scripts Bengali, Devanagari, Gujarati, Gurmukhi, Kannada, + Malayalam, Oriya, Tamil, Telugu, and Sinhala. + + + The Indic shaping model was revised significantly in + 2005. To denote the change, a new set of script + tags 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. + + + + + + The Arabic shaping model supports + Arabic, Mongolian, N'Ko, Syriac, and several other connected + or cursive scripts. + + + + + + The Thai/Lao shaping model supports + the Thai and Lao scripts. + + + + + + The Khmer shaping model supports the + Khmer script. + + + + + + The Myanmar shaping model supports the + Myanmar (or Burmese) script. + + + + + + The Tibetan shaping model supports the + Tibetan script. + + + + + + The Hangul shaping model supports the + Hangul script. + + + + + + The Hebrew shaping model supports the + Hebrew script. + + + + + + The Universal Shaping Engine (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. + + + + + + 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 Emoji shaping, which + may involve variation-selector sequences and glyph + substitution. Emoji shaping is handled by the default + shaping model. + + + + + +
+ +
+ Graphite shaping + + In contrast to OpenType shaping, Graphite shaping does not + specify a predefined set of shaping models or a set of supported + scripts. + + + 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. + + + 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. + +
+ +
+ AAT shaping + + In contrast to OpenType shaping, AAT shaping does not specify a + predefined set of shaping models or a set of supported scripts. + + + 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. + + + 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. + +
+
diff --git a/docs/usermanual-what-is-harfbuzz.xml b/docs/usermanual-what-is-harfbuzz.xml index 38f40cf11..8532d7cc2 100644 --- a/docs/usermanual-what-is-harfbuzz.xml +++ b/docs/usermanual-what-is-harfbuzz.xml @@ -1,115 +1,441 @@ + + + +]> What is HarfBuzz? - HarfBuzz is a text shaping engine. It solves - the problem of selecting and positioning glyphs from a font given a - Unicode string. + HarfBuzz is a text-shaping engine. 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. -
- Why do I need it? + + 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. + +
+ What is text shaping? - 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 - writing 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. + + + 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. + + + Modern software systems generally only deal with strings in the + Unicode encoding scheme (although legacy systems and documents may + involve other encodings). + + + There are several font formats that a program might + encounter, each of which has a set of standard text-shaping + rules. + + The dominant format is OpenType. The + OpenType specification defines a series of shaping models for + various scripts from around the world. These shaping models depend on + the font including certain features in its GSUB + and GPOS tables. + + + Alternatively, OpenType fonts can include shaping features for + the Graphite shaping model. + + + TrueType fonts can also include OpenType shaping + features. Alternatively, TrueType fonts can also include Apple + Advanced Typography (AAT) tables to implement shaping + support. AAT fonts are generally only found on macOS and iOS systems. + + + Text strings will usually be tagged with a script and language + tag that provide the context needed to perform text shaping + correctly. The necessary Script + and language + tags are defined by OpenType. + +
+ +
+ Why do I need a shaping engine? + + 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. + + + Text shaping is a fairly low-level operation. HarfBuzz is + used directly by text-handling libraries like Pango, as well as by the layout + engines in Firefox, LibreOffice, and Chromium. Unless you are + writing 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. However, if you are 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. + + + Here are some specific scenarios where a text-shaping engine + like HarfBuzz helps you: - OpenType fonts contain a set of glyphs, indexed by glyph ID. - The glyph ID within the font does not necessarily relate to a - Unicode codepoint. For instance, some fonts have the letter - "a" as glyph ID 1. To pull the right glyph out of - the font in order to display it, you need to consult a table - within the font (the "cmap" table) which maps - Unicode codepoints to glyph IDs. Text shaping turns codepoints - into glyph IDs. + OpenType fonts contain a set of glyphs (that is, shapes + to represent the letters, numbers, punctuation marks, and + all other symbols), which are indexed by a glyph ID. + + + A particular glyph ID within the font does not necessarily + correlate to a predictable Unicode codepoint. For instance, + some fonts have the letter "a" as glyph ID 1, but + many others do not. In order to retrieve the right glyph + from the font to display "a", you need to consult + the table inside the font (the cmap + table) that maps Unicode codepoints to glyph IDs. In other + words, text shaping turns codepoints into glyph + IDs. Many OpenType fonts contain ligatures: combinations of - characters which are rendered together. For instance, it's - common for the fi combination to appear in - print as the single ligature "fi". Whether you should - render text as fi or "fi" does not - depend on the input text, but on the capabilities of the font - and the level of ligature application you wish to perform. - Text shaping involves querying the font's ligature tables and - determining what substitutions should be made. + characters that are rendered as a single unit. For instance, + it is common for the fi letter + combination to appear in print as the single ligature glyph + "fi". + + + Whether you should render an "f, i" sequence + as fi or as "fi" does not + depend on the input text. Instead, it depends on the whether + or not the font includes an "fi" glyph and on the + level of ligature application you wish to perform. The font + and the amount of ligature application used are under your + control. In other words, text shaping involves + querying the font's ligature tables and determining what + substitutions should be made. - While ligatures like "fi" are typographic - refinements, some languages require such + While ligatures like "fi" are optional typographic + refinements, some languages require certain substitutions to be made in order to display text correctly. - In Tamil, when the letter "TTA" (ட) letter is - followed by "U" (உ), the combination should appear - as the single glyph "டு". The sequence of Unicode - characters "டஉ" needs to be rendered as a single - glyph from the font - text shaping chooses the correct glyph - from the sequence of characters provided. + + + For example, in Tamil, when the letter "TTA" (ட) + letter is followed by "U" (உ), the pair + must be replaced by the single glyph "டு". The + sequence of Unicode characters "டஉ" needs to be + substituted with a single "டு" glyph from the + font. + + + But "டு" does not have a Unicode codepoint. To + find this glyph, you need to consult the table inside + the font (the GSUB table) that contains + substitution information. In other words, text shaping + chooses the correct glyph for a sequence of characters + provided. - 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. + + + 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, text + shaping chooses the correct form of the letter by its + position and returns the correct glyph from the font. - Other languages have marks and accents which need to be - rendered in certain positions around a base character. For - instance, the Moldovan language has the Cyrillic letter - "zhe" (ж) with a breve accent, like so: ӂ. Some - fonts will contain this character as an individual glyph, - whereas other fonts will not contain a zhe-with-breve glyph - but expect the rendering engine to form the character by - overlaying the two glyphs ж and ˘. Where you should draw the - combining breve depends on the height of the preceding glyph. - Again, for Arabic, the correct positioning of vowel marks - depends on the height of the character on which you are - placing the mark. Text shaping tells you whether you have a - precomposed glyph within your font or if you need to compose a - glyph yourself out of combining marks, and if so, where to - position those marks. + Other languages involve marks and accents that need to be + rendered in specific positions relative a base character. For + instance, the Moldovan language includes the Cyrillic letter + "zhe" (ж) with a breve accent, like so: "ӂ". + + + Some fonts will provide this character as a single + zhe-with-breve glyph, but other fonts will not and, instead, + will expect the rendering engine to form the character by + superimposing the separate "ж" and "˘" + glyphs. + + + 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 GPOS table) that contains + positioning information. + In other words, 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. - 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. + + + + In the rest of this manual, the text will assume that the reader + is that implementor of a text-layout engine. + + +
+ + +
+ What does HarfBuzz do? + + 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: + + + + + Indic (covering Devanagari, Bengali, Gujarati, + Gurmukhi, Kannada, Malayalam, Oriya, Tamil, Telugu, and + Sinhala) + + + + + Arabic (covering Arabic, N'Ko, Syriac, and Mongolian) + + + + + Thai and Lao + + + + + Khmer + + + + + Myanmar + + + + + + Tibetan + + + + + + Hangul + + + + + + Hebrew + + + + + The Universal Shaping Engine or USE + (covering complex scripts not covered by the above shaping + models) + + + + + A default shaping model for non-complex scripts + (covering Latin, Cyrillic, Greek, Armenian, Georgian, Tifinagh, + and many others) + + + + + Emoji (including emoji modifier sequences, flag sequences, + and ZWJ sequences) + + + + + + In addition to OpenType shaping, HarfBuzz supports the latest + version of Graphite shaping (the "Graphite 2" model) and AAT + shaping. + + + + 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). + + + + 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. + + + + 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 (CBDT, + sbix, COLR/CPAL, and + SVG-OT) 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. + + + + 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.
+ +
+ What HarfBuzz doesn't do + + 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. + + + It is important to note that if you are implementing a complete + text-layout engine you may have other responsibilities that + HarfBuzz will not help you with. For example: + + + + + 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: + + + A B C [space] ג ב א [space] D E F + + + but will expect to see in the output: + + + ABC אבג DEF + + + This reordering is called bidi processing + ("bidi" is short for bidirectional), and there's an + algorithm as an annex to the Unicode Standard which tells you how + to process a string of mixed directionality. + Before sending your string to HarfBuzz, you may need to apply the + bidi algorithm to it. Libraries such as ICU and fribidi can do this for you. + + + + + HarfBuzz won't help you with text that contains different font + properties. For instance, if you have the string "a + huge breakfast", and you expect + "huge" to be italic, then you will need to send three + strings to HarfBuzz: a, in your Roman font; + huge using your italic font; and + breakfast using your Roman font again. + + + 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. + + + + + HarfBuzz won't help you with line breaking, hyphenation, or + justification. As mentioned above, HarfBuzz lays out the string + along a single line 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. + + + 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. + + + + + 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. + +
+
Why is it called HarfBuzz? - HarfBuzz began its life as text shaping code within the FreeType - project, (and you will see references to the FreeType authors - within the source code copyright declarations) but was then - abstracted out to its own project. This project is maintained by - Behdad Esfahbod, and named HarfBuzz. Originally, it was a shaping - engine for OpenType fonts - "HarfBuzz" is the Persian - for "open type". + HarfBuzz began its life as text-shaping code within the FreeType + project (and you will see references to the FreeType authors + within the source code copyright declarations), but was then + extracted out to its own project. This project is maintained by + Behdad Esfahbod, who named it HarfBuzz. Originally, it was a + shaping engine for OpenType fonts—"HarfBuzz" is + the Persian for "open type".
- \ No newline at end of file + diff --git a/src/Makefile.am b/src/Makefile.am index ac03890b3..fbd8f6023 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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 diff --git a/src/Makefile.sources b/src/Makefile.sources index 07713cc84..324ad0906 100644 --- a/src/Makefile.sources +++ b/src/Makefile.sources @@ -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) diff --git a/src/gen-def.py b/src/gen-def.py index ba39eaae5..9111c698c 100755 --- a/src/gen-def.py +++ b/src/gen-def.py @@ -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) diff --git a/src/gen-vowel-constraints.py b/src/gen-vowel-constraints.py index 02a338fa5..c4e75aa96 100755 --- a/src/gen-vowel-constraints.py +++ b/src/gen-vowel-constraints.py @@ -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') diff --git a/src/hb-aat-layout-common.hh b/src/hb-aat-layout-common.hh index a99ccaf9f..51add2213 100644 --- a/src/hb-aat-layout-common.hh +++ b/src/hb-aat-layout-common.hh @@ -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 { - 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 DEFINE_SIZE_STATIC (4); }; -template +template 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 *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 *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 *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 (num_entries, *p + 1); state = num_states; } @@ -487,7 +498,10 @@ struct StateTable { /* Sweep new entries. */ const Entry *stop = &entries[num_entries]; for (const Entry *p = &entries[entry]; p < stop; p++) - num_states = MAX (num_states, p->newState + 1); + { + unsigned int newState = new_state (p->newState); + num_states = MAX (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, false> + OffsetTo classTable; /* Offset to the class table. */ - LOffsetTo, false> + OffsetTo, HBUINT, false> stateArrayTable;/* Offset to the state array. */ - LOffsetTo >, false> + OffsetTo >, HBUINT, false> entryTable; /* Offset to the entry array. */ public: - DEFINE_SIZE_STATIC (16); + DEFINE_SIZE_STATIC (4 * sizeof (HBUINT)); }; -template +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 + 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 + 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 + 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 + { + 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 + static inline unsigned int offsetToIndex (unsigned int offset, + const void *base, + const T *array) + { + return offset; + } + template + static inline unsigned int wordOffsetToIndex (unsigned int offset, + const void *base, + const T *array) + { + return offset; + } +}; + +template struct StateTableDriver { - inline StateTableDriver (const StateTable &machine_, + inline StateTableDriver (const StateTable &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::STATE_START_OF_TEXT; + unsigned int state = StateTable::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::CLASS_END_OF_TEXT; + (unsigned) StateTable::CLASS_END_OF_TEXT; const Entry *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::STATE_START_OF_TEXT && + !(entry->newState == StateTable::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 &machine; + const StateTable &machine; hb_buffer_t *buffer; unsigned int num_glyphs; }; diff --git a/src/hb-aat-layout-kerx-table.hh b/src/hb-aat-layout-kerx-table.hh index 960c37e11..94e0a9b62 100644 --- a/src/hb-aat-layout-kerx-table.hh +++ b/src/hb-aat-layout-kerx-table.hh @@ -163,12 +163,12 @@ struct KerxSubTableFormat1 kernAction (&table->machine + table->kernAction), depth (0) {} - inline bool is_actionable (StateTableDriver *driver, + inline bool is_actionable (StateTableDriver *driver HB_UNUSED, const Entry *entry) { return entry->data.kernActionIndex != 0xFFFF; } - inline bool transition (StateTableDriver *driver, + inline bool transition (StateTableDriver *driver, const Entry *entry) { hb_buffer_t *buffer = driver->buffer; @@ -239,7 +239,7 @@ struct KerxSubTableFormat1 driver_context_t dc (this, c); - StateTableDriver driver (machine, c->buffer, c->font->face); + StateTableDriver driver (machine, c->buffer, c->font->face); driver.drive (&dc); return_trace (true); @@ -255,7 +255,7 @@ struct KerxSubTableFormat1 protected: KerxSubTableHeader header; - StateTable machine; + StateTable machine; LOffsetTo, false> kernAction; public: DEFINE_SIZE_STATIC (32); @@ -365,12 +365,12 @@ struct KerxSubTableFormat4 mark_set (false), mark (0) {} - inline bool is_actionable (StateTableDriver *driver, + inline bool is_actionable (StateTableDriver *driver HB_UNUSED, const Entry *entry) { return entry->data.ankrActionIndex != 0xFFFF; } - inline bool transition (StateTableDriver *driver, + inline bool transition (StateTableDriver *driver, const Entry *entry) { hb_buffer_t *buffer = driver->buffer; @@ -473,7 +473,7 @@ struct KerxSubTableFormat4 driver_context_t dc (this, c); - StateTableDriver driver (machine, c->buffer, c->font->face); + StateTableDriver driver (machine, c->buffer, c->font->face); driver.drive (&dc); return_trace (true); @@ -489,7 +489,8 @@ struct KerxSubTableFormat4 protected: KerxSubTableHeader header; - StateTable machine; + StateTable + machine; HBUINT32 flags; public: DEFINE_SIZE_STATIC (32); diff --git a/src/hb-aat-layout-morx-table.hh b/src/hb-aat-layout-morx-table.hh index c663fcc84..d56af7bfe 100644 --- a/src/hb-aat-layout-morx-table.hh +++ b/src/hb-aat-layout-morx-table.hh @@ -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 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 *driver, + inline bool is_actionable (StateTableDriver *driver HB_UNUSED, const Entry *entry) { return (entry->flags & Verb) && start < end; } - inline bool transition (StateTableDriver *driver, + inline bool transition (StateTableDriver *driver, const Entry *entry) { hb_buffer_t *buffer = driver->buffer; @@ -165,7 +169,7 @@ struct RearrangementSubtable driver_context_t dc (this); - StateTableDriver driver (machine, c->buffer, c->face); + StateTableDriver driver (machine, c->buffer, c->face); driver.drive (&dc); return_trace (dc.ret); @@ -178,13 +182,16 @@ struct RearrangementSubtable } protected: - StateTable machine; + StateTable machine; public: DEFINE_SIZE_STATIC (16); }; +template 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 *driver, + inline bool is_actionable (StateTableDriver *driver, const Entry *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 *driver, + inline bool transition (StateTableDriver *driver, const Entry *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 &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 &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 &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 &subs_old = (const UnsizedArrayOf &) 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 &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 &subs_old = (const UnsizedArrayOf &) 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, HBUINT32, false> &subs; + const ContextualSubtable *table; + const UnsizedOffsetListOf, 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 driver (machine, c->buffer, c->face); + StateTableDriver 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 *entries = machine.get_entries (); @@ -310,38 +349,90 @@ struct ContextualSubtable } protected: - StateTable + StateTable machine; - LOffsetTo, HBUINT32, false>, false> + OffsetTo, HBUINT, false>, HBUINT, false> substitutionTables; public: DEFINE_SIZE_STATIC (20); }; -struct LigatureSubtable + +template +struct LigatureEntry; + +template <> +struct LigatureEntry { - 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 + static inline bool performAction (Flags flags) + { return flags & PerformAction; } + + template + static inline unsigned int ligActionIndex (Entry &entry, Flags flags) + { return entry->data.ligActionIndex; } +}; +template <> +struct LigatureEntry +{ + 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 + static inline bool performAction (Flags flags) + { return flags & Offset; } + + template + static inline unsigned int ligActionIndex (Entry &entry, Flags flags) + { return flags & 0x3FFF; } +}; + + +template +struct LigatureSubtable +{ + typedef typename Types::HBUINT HBUINT; + + typedef LigatureEntry 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 *driver, + inline bool is_actionable (StateTableDriver *driver HB_UNUSED, const Entry *entry) { - return entry->flags & PerformAction; + return LigatureEntryT::performAction (entry->flags); } - inline bool transition (StateTableDriver *driver, + inline bool transition (StateTableDriver *driver, const Entry *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 &ligAction; const UnsizedArrayOf &component; const UnsizedArrayOf &ligature; @@ -481,7 +576,7 @@ struct LigatureSubtable driver_context_t dc (this, c); - StateTableDriver driver (machine, c->buffer, c->face); + StateTableDriver driver (machine, c->buffer, c->face); driver.drive (&dc); return_trace (dc.ret); @@ -496,18 +591,19 @@ struct LigatureSubtable } protected: - StateTable + StateTable machine; - LOffsetTo, false> + OffsetTo, HBUINT, false> ligAction; /* Offset to the ligature action table. */ - LOffsetTo, false> + OffsetTo, HBUINT, false> component; /* Offset to the component table. */ - LOffsetTo, false> + OffsetTo, HBUINT, false> ligature; /* Offset to the actual ligature lists. */ public: DEFINE_SIZE_STATIC (28); }; +template struct NoncontextualSubtable { inline bool apply (hb_aat_apply_context_t *c) const @@ -544,8 +640,11 @@ struct NoncontextualSubtable DEFINE_SIZE_MIN (2); }; +template 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 *driver, + inline bool is_actionable (StateTableDriver *driver HB_UNUSED, const Entry *entry) { return (entry->flags & (CurrentInsertCount | MarkedInsertCount)) && (entry->data.currentInsertIndex != 0xFFFF ||entry->data.markedInsertIndex != 0xFFFF); } - inline bool transition (StateTableDriver *driver, + inline bool transition (StateTableDriver *driver, const Entry *entry) { hb_buffer_t *buffer = driver->buffer; @@ -719,7 +818,7 @@ struct InsertionSubtable driver_context_t dc (this, c); - StateTableDriver driver (machine, c->buffer, c->face); + StateTableDriver driver (machine, c->buffer, c->face); driver.drive (&dc); return_trace (dc.ret); @@ -734,9 +833,9 @@ struct InsertionSubtable } protected: - StateTable + StateTable machine; - LOffsetTo, false> + OffsetTo, 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 struct ChainSubtable { + typedef typename Types::HBUINT HBUINT; + + template 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 rearrangement; + ContextualSubtable contextual; + LigatureSubtable ligature; + NoncontextualSubtable noncontextual; + InsertionSubtable insertion; } u; public: - DEFINE_SIZE_MIN (12); + DEFINE_SIZE_MIN (2 * sizeof (HBUINT) + 4); }; +template 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 (&featureZ, featureZ[0].static_size * featureCount); + const ChainSubtable *subtable = &StructAtOffset > (&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::AllDirections) && HB_DIRECTION_IS_VERTICAL (c->buffer->props.direction) != - bool (subtable->coverage & ChainSubtable::Vertical)) + bool (subtable->get_coverage() & ChainSubtable::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::Logical ? + bool (subtable->get_coverage () & ChainSubtable::Backwards) : + bool (subtable->get_coverage () & ChainSubtable::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 (*subtable); + subtable = &StructAfter > (*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 (&featureZ, featureZ[0].static_size * featureCount); + const ChainSubtable *subtable = &StructAtOffset > (&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 (*subtable); + subtable = &StructAfter > (*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 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 +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 *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 = &StructAfter > (*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 *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 = &StructAfter > (*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 *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 = &StructAfter > (*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 firstChain; /* Chains. */ public: DEFINE_SIZE_MIN (8); }; +struct morx : mortmorx +{ + static const hb_tag_t tableTag = HB_AAT_TAG_morx; +}; +struct mort : mortmorx +{ + static const hb_tag_t tableTag = HB_AAT_TAG_mort; +}; + + } /* namespace AAT */ diff --git a/src/hb-aat-layout.cc b/src/hb-aat-layout.cc index 1e1c7b4f4..d917c29c6 100644 --- a/src/hb-aat-layout.cc +++ b/src/hb-aat-layout.cc @@ -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); +} diff --git a/src/hb-aat-layout.hh b/src/hb-aat-layout.hh index aea545689..8a558e6aa 100644 --- a/src/hb-aat-layout.hh +++ b/src/hb-aat-layout.hh @@ -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 */ diff --git a/src/hb-aat-ltag-table.hh b/src/hb-aat-ltag-table.hh index 08a1b51a9..8a42b3510 100644 --- a/src/hb-aat-ltag-table.hh +++ b/src/hb-aat-ltag-table.hh @@ -25,7 +25,7 @@ #ifndef HB_AAT_LTAG_TABLE_HH #define HB_AAT_LTAG_TABLE_HH -#include "hb-aat-layout-common.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: diff --git a/src/hb-aat-map.cc b/src/hb-aat-map.cc index f2736bfd1..1ce1b12b0 100644 --- a/src/hb-aat-map.cc +++ b/src/hb-aat-map.cc @@ -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; diff --git a/src/hb-aat-map.hh b/src/hb-aat-map.hh index 846cdc1a9..6fd3fa1ea 100644 --- a/src/hb-aat-map.hh +++ b/src/hb-aat-map.hh @@ -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); diff --git a/src/hb-blob.cc b/src/hb-blob.cc index 368491c05..51f22ce4d 100644 --- a/src/hb-blob.cc +++ b/src/hb-blob.cc @@ -40,6 +40,19 @@ #include +/** + * 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, diff --git a/src/hb-blob.hh b/src/hb-blob.hh index bee8c9794..0181e94a4 100644 --- a/src/hb-blob.hh +++ b/src/hb-blob.hh @@ -60,7 +60,7 @@ struct hb_blob_t template inline const Type* as (void) const { - return unlikely (!data) ? &Null(Type) : reinterpret_cast (data); + return length < Type::min_size ? &Null(Type) : reinterpret_cast (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; diff --git a/src/hb-buffer.cc b/src/hb-buffer.cc index ce9b0530c..5a8152ed4 100644 --- a/src/hb-buffer.cc +++ b/src/hb-buffer.cc @@ -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 > (buffer, text, text_length, item_offset, item_length); + hb_buffer_add_utf (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 > (buffer, text, text_length, item_offset, item_length); + hb_buffer_add_utf (buffer, text, text_length, item_offset, item_length); } diff --git a/src/hb-buffer.hh b/src/hb-buffer.hh index 0d888e1e0..37adeb083 100644 --- a/src/hb-buffer.hh +++ b/src/hb-buffer.hh @@ -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 */ diff --git a/src/hb-common.cc b/src/hb-common.cc index 86d07cf16..d7c1921f3 100644 --- a/src/hb-common.cc +++ b/src/hb-common.cc @@ -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. diff --git a/src/hb-common.h b/src/hb-common.h index 0858c0e29..ae23698a5 100644 --- a/src/hb-common.h +++ b/src/hb-common.h @@ -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) diff --git a/src/hb-coretext.cc b/src/hb-coretext.cc index 9f7745dbf..184db4944 100644 --- a/src/hb-coretext.cc +++ b/src/hb-coretext.cc @@ -35,6 +35,16 @@ #include "hb-aat-layout.hh" #include + +/** + * 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 > feature_records; - hb_auto_t > range_records; + hb_vector_t feature_records; + hb_vector_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 > feature_events; + hb_vector_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 > active_features; + hb_vector_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); } } } diff --git a/src/hb-debug.hh b/src/hb-debug.hh index 58c190d27..d218e4328 100644 --- a/src/hb-debug.hh +++ b/src/hb-debug.hh @@ -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 static inline void +template 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, diff --git a/src/hb-deprecated.h b/src/hb-deprecated.h index 369d07361..e39b79f74 100644 --- a/src/hb-deprecated.h +++ b/src/hb-deprecated.h @@ -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 diff --git a/src/hb-dsalgs.hh b/src/hb-dsalgs.hh index 7e846161d..59df860df 100644 --- a/src/hb-dsalgs.hh +++ b/src/hb-dsalgs.hh @@ -312,6 +312,27 @@ hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2, T lo3, T hi3) * Sort and search. */ +static inline void * +hb_bsearch (const void *key, const void *base, + size_t nmemb, size_t size, + int (*compar)(const void *_key, const void *_item)) +{ + int min = 0, max = (int) nmemb - 1; + while (min <= max) + { + int mid = (min + max) / 2; + const void *p = (const void *) (((const char *) base) + (mid * size)); + int c = compar (key, p); + if (c < 0) + max = mid - 1; + else if (c > 0) + min = mid + 1; + else + return (void *) p; + } + return nullptr; +} + static inline void * hb_bsearch_r (const void *key, const void *base, size_t nmemb, size_t size, @@ -321,7 +342,7 @@ hb_bsearch_r (const void *key, const void *base, int min = 0, max = (int) nmemb - 1; while (min <= max) { - int mid = (min + max) / 2; + int mid = ((unsigned int) min + (unsigned int) max) / 2; const void *p = (const void *) (((const char *) base) + (mid * size)); int c = compar (key, p, arg); if (c < 0) @@ -490,56 +511,6 @@ hb_codepoint_parse (const char *s, unsigned int len, int base, hb_codepoint_t *o } -template -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 explicit hb_auto_t (T1 *t1) { Type::init (t1); } - template explicit hb_auto_t (T1 &t1) { Type::init (t1); } - ~hb_auto_t (void) { Type::fini (); } - private: /* Hide */ - void init (void) {} - void fini (void) {} -}; - -template -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 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 (arrayZ + start_offset, count); - } - - inline void free (void) { ::free ((void *) arrayZ); arrayZ = nullptr; len = 0; } - - T *arrayZ; - unsigned int len; -}; -template static inline -hb_array_t hb_array (T *array, unsigned int len) { return hb_array_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 +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 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 (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 static inline +hb_array_t hb_array (T *array, unsigned int len) { return hb_array_t (array, len); } + struct HbOpOr { @@ -603,8 +610,10 @@ struct HbOpXor template 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 inline hb_vector_size_t process (const hb_vector_size_t &o) const diff --git a/src/hb-face.cc b/src/hb-face.cc index bba1ee3fa..7ca4b1ba2 100644 --- a/src/hb-face.cc +++ b/src/hb-face.cc @@ -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; diff --git a/src/hb-face.hh b/src/hb-face.hh index f90453dbd..89673ff84 100644 --- a/src/hb-face.hh +++ b/src/hb-face.hh @@ -42,7 +42,6 @@ struct hb_face_t { hb_object_header_t header; - ASSERT_POD (); hb_bool_t immutable; diff --git a/src/hb-font.cc b/src/hb-font.cc index b6b668dd8..86b03f4b6 100644 --- a/src/hb-font.cc +++ b/src/hb-font.cc @@ -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) { diff --git a/src/hb-font.h b/src/hb-font.h index 74c61aba4..e2086d818 100644 --- a/src/hb-font.h +++ b/src/hb-font.h @@ -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; diff --git a/src/hb-font.hh b/src/hb-font.hh index 2df5e42ee..3dce233db 100644 --- a/src/hb-font.hh +++ b/src/hb-font.hh @@ -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; diff --git a/src/hb-ft.cc b/src/hb-ft.cc index fbf362688..5e0511052 100644 --- a/src/hb-ft.cc +++ b/src/hb-ft.cc @@ -40,6 +40,17 @@ #include FT_TRUETYPE_TABLES_H +/** + * SECTION:hb-ft + * @title: hb-ft + * @short_description: FreeType integration + * @include: hb-ft.h + * + * Functions for using HarfBuzz with the FreeType library to provide face and + * font data. + **/ + + /* TODO: * * In general, this file does a fine job of what it's supposed to do. diff --git a/src/hb-glib.cc b/src/hb-glib.cc index a34acbba1..23a0d89c8 100644 --- a/src/hb-glib.cc +++ b/src/hb-glib.cc @@ -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[] = diff --git a/src/hb-gobject-structs.cc b/src/hb-gobject-structs.cc index 1b8758583..23ca43656 100644 --- a/src/hb-gobject-structs.cc +++ b/src/hb-gobject-structs.cc @@ -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 #if !GLIB_CHECK_VERSION(2,29,16) diff --git a/src/hb-graphite2.cc b/src/hb-graphite2.cc index 6b2b6f19d..971241f92 100644 --- a/src/hb-graphite2.cc +++ b/src/hb-graphite2.cc @@ -33,7 +33,17 @@ #include -#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, diff --git a/src/hb-icu.cc b/src/hb-icu.cc index e012314b5..12864677c 100644 --- a/src/hb-icu.cc +++ b/src/hb-icu.cc @@ -40,6 +40,16 @@ #include +/** + * 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) { diff --git a/src/hb-machinery.hh b/src/hb-machinery.hh index 19245e89b..465bbb14f 100644 --- a/src/hb-machinery.hh +++ b/src/hb-machinery.hh @@ -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 - 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 - 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 inline return_t dispatch (const T &obj) { return obj.sanitize (this); } @@ -612,7 +610,7 @@ struct Supplier } inline Supplier (const hb_vector_t *v) { - head = v->arrayZ(); + head = *v; len = v->len; stride = sizeof (Type); } diff --git a/src/hb-map.cc b/src/hb-map.cc index 225f37bc6..067a2b371 100644 --- a/src/hb-map.cc +++ b/src/hb-map.cc @@ -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. + **/ /** diff --git a/src/hb-map.hh b/src/hb-map.hh index b55e3a954..c54c9d7b6 100644 --- a/src/hb-map.hh +++ b/src/hb-map.hh @@ -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 (); } diff --git a/src/hb-null.hh b/src/hb-null.hh index 6906555e3..204689bd7 100644 --- a/src/hb-null.hh +++ b/src/hb-null.hh @@ -87,7 +87,7 @@ template static inline Type& Crap (void) { static_assert (sizeof (Type) <= HB_NULL_POOL_SIZE, "Increase HB_NULL_POOL_SIZE."); Type *obj = reinterpret_cast (_hb_CrapPool); - *obj = Null(Type); + memcpy (obj, &Null(Type), sizeof (*obj)); return *obj; } #define Crap(Type) Crap::value>::value>() diff --git a/src/hb-object.hh b/src/hb-object.hh index ca85af691..106f59206 100644 --- a/src/hb-object.hh +++ b/src/hb-object.hh @@ -195,12 +195,8 @@ struct hb_object_header_t { hb_reference_count_t ref_count; hb_atomic_ptr_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 diff --git a/src/hb-open-type.hh b/src/hb-open-type.hh index 2b1b432ba..00bd134dd 100644 --- a/src/hb-open-type.hh +++ b/src/hb-open-type.hh @@ -335,9 +335,14 @@ static inline Type& operator + (Base &base, OffsetTo template 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 inline operator T * (void) { return arrayZ; } + template 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 template 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 inline operator T * (void) { return arrayZ; } + template 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 struct LArrayOf : ArrayOf {}; typedef ArrayOf PString; /* Array of Offset's */ -template -struct OffsetArrayOf : ArrayOf > {}; +template +struct OffsetArrayOf : ArrayOf > {}; +template +struct LOffsetArrayOf : ArrayOf > {}; +template +struct LOffsetLArrayOf : ArrayOf, HBUINT32> {}; /* Array of offsets relative to the beginning of the array itself. */ template @@ -586,6 +600,8 @@ struct OffsetListOf : OffsetArrayOf template 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 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 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 struct BinSearchArrayOf : SortedArrayOf > {}; + struct VarSizedBinSearchHeader { @@ -779,6 +798,8 @@ struct VarSizedBinSearchHeader template 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) diff --git a/src/hb-ot-cmap-table.hh b/src/hb-ot-cmap-table.hh index e5793c387..a1c5a9747 100644 --- a/src/hb-ot-cmap-table.hh +++ b/src/hb-ot-cmap-table.hh @@ -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 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 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 supplier (group_data.arrayZ(), group_data.len); + Supplier 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 format4_segments; - // Format 12 hb_vector_t format12_groups; }; diff --git a/src/hb-ot-color-cbdt-table.hh b/src/hb-ot-color-cbdt-table.hh index 1e1fe0956..614cc80ce 100644 --- a/src/hb-ot-color-cbdt-table.hh +++ b/src/hb-ot-color-cbdt-table.hh @@ -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 (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 (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 (this->cbdt, image_offset); - callback ((const uint8_t *) &glyphFormat17.data.arrayZ, - glyphFormat17.data.len, i, gid); - } - break; - case 18: { - const GlyphBitmapDataFormat18& glyphFormat18 = - StructAtOffset (this->cbdt, image_offset); - callback ((const uint8_t *) &glyphFormat18.data.arrayZ, - glyphFormat18.data.len, i, gid); - } - break; - case 19: { - const GlyphBitmapDataFormat19& glyphFormat19 = - StructAtOffset (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 (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 (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 (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; diff --git a/src/hb-ot-color-cpal-table.hh b/src/hb-ot-color-cpal-table.hh index 7d3733d3f..df4d9b4e7 100644 --- a/src/hb-ot-color-cpal-table.hh +++ b/src/hb-ot-color-cpal-table.hh @@ -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, diff --git a/src/hb-ot-color-sbix-table.hh b/src/hb-ot-color-sbix-table.hh index 1b643c77a..065c0dd18 100644 --- a/src/hb-ot-color-sbix-table.hh +++ b/src/hb-ot-color-sbix-table.hh @@ -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 > 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 (face); - sbix_len = hb_blob_get_length (sbix_blob); - sbix_table = sbix_blob->as (); + table = sbix_blob->as (); + 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(); + + 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 > + LOffsetLArrayOf 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 */ diff --git a/src/hb-ot-color-svg-table.hh b/src/hb-ot-color-svg-table.hh index 53d466846..bb4c4f757 100644 --- a/src/hb-ot-color-svg-table.hh +++ b/src/hb-ot-color-svg-table.hh @@ -40,13 +40,21 @@ namespace OT { struct SVGDocumentIndexEntry { - friend struct SVG; + inline int cmp (hb_codepoint_t g) const + { return g < startGlyphID ? -1 : g > endGlyphID ? 1 : 0; } - inline bool sanitize (hb_sanitize_context_t *c, const void* base) const + inline hb_blob_t *reference_blob (hb_blob_t *svg_blob, unsigned int index_offset) const + { + return hb_blob_create_sub_blob (svg_blob, + index_offset + (unsigned int) svgDoc, + svgDocLength); + } + + inline bool sanitize (hb_sanitize_context_t *c, const void *base) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && - (base+svgDoc).sanitize (c, svgDocLength)); + svgDoc.sanitize (c, base, svgDocLength)); } protected: @@ -57,48 +65,23 @@ struct SVGDocumentIndexEntry LOffsetTo, 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 - 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 (face); svg_len = hb_blob_get_length (svg_blob); - svg = svg_blob->as (); + table = svg_blob->as (); } 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 &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 &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 - svgDocIndex; /* Offset (relative to the start of the SVG table) to the + LOffsetTo > + 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 */ diff --git a/src/hb-ot-color.cc b/src/hb-ot-color.cc index 229b6e66f..b87ed56fa 100644 --- a/src/hb-ot-color.cc +++ b/src/hb-ot-color.cc @@ -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; +} diff --git a/src/hb-ot-color.h b/src/hb-ot-color.h index 02b76bffc..a4f205329 100644 --- a/src/hb-ot-color.h +++ b/src/hb-ot-color.h @@ -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 diff --git a/src/hb-ot-face.cc b/src/hb-ot-face.cc index fb10f5174..1c6370d97 100644 --- a/src/hb-ot-face.cc +++ b/src/hb-ot-face.cc @@ -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" diff --git a/src/hb-ot-face.hh b/src/hb-ot-face.hh index 589baa564..72e449515 100644 --- a/src/hb-ot-face.hh +++ b/src/hb-ot-face.hh @@ -45,10 +45,14 @@ * This is as good as any place. */ #define HB_OT_TABLES \ /* OpenType shaping. */ \ + HB_OT_ACCELERATOR(OT, GDEF) \ + HB_OT_ACCELERATOR(OT, GSUB) \ + HB_OT_ACCELERATOR(OT, GPOS) \ HB_OT_TABLE(OT, JSTF) \ HB_OT_TABLE(OT, BASE) \ /* AAT shaping. */ \ HB_OT_TABLE(AAT, morx) \ + HB_OT_TABLE(AAT, mort) \ HB_OT_TABLE(AAT, kerx) \ HB_OT_TABLE(AAT, ankr) \ HB_OT_TABLE(AAT, trak) \ @@ -59,9 +63,6 @@ /* OpenType math. */ \ HB_OT_TABLE(OT, MATH) \ /* OpenType fundamentals. */ \ - HB_OT_ACCELERATOR(OT, GDEF) \ - HB_OT_ACCELERATOR(OT, GSUB) \ - HB_OT_ACCELERATOR(OT, GPOS) \ HB_OT_ACCELERATOR(OT, cmap) \ HB_OT_ACCELERATOR(OT, hmtx) \ HB_OT_ACCELERATOR(OT, vmtx) \ @@ -71,12 +72,14 @@ HB_OT_ACCELERATOR(OT, cff1) \ HB_OT_ACCELERATOR(OT, cff2) \ HB_OT_TABLE(OT, VORG) \ + HB_OT_ACCELERATOR(OT, name) \ + HB_OT_TABLE(AAT, ltag) \ /* OpenType color fonts. */ \ HB_OT_TABLE(OT, COLR) \ HB_OT_TABLE(OT, CPAL) \ HB_OT_ACCELERATOR(OT, CBDT) \ - HB_OT_TABLE(OT, sbix) \ - HB_OT_TABLE(OT, SVG) \ + HB_OT_ACCELERATOR(OT, sbix) \ + HB_OT_ACCELERATOR(OT, SVG) \ /* */ /* Declare tables. */ diff --git a/src/hb-ot-font.cc b/src/hb-ot-font.cc index 1789f0204..d41f32255 100644 --- a/src/hb-ot-font.cc +++ b/src/hb-ot-font.cc @@ -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); diff --git a/src/hb-ot-glyf-table.hh b/src/hb-ot-glyf-table.hh index 2145ac02b..7bd175e39 100644 --- a/src/hb-ot-glyf-table.hh +++ b/src/hb-ot-glyf-table.hh @@ -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 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 dataZ; /* Glyphs data. */ - + public: DEFINE_SIZE_ARRAY (0, dataZ); }; diff --git a/src/hb-ot-hmtx-table.hh b/src/hb-ot-hmtx-table.hh index 935ddd720..1eb6cc68f 100644 --- a/src/hb-ot-hmtx-table.hh +++ b/src/hb-ot-hmtx-table.hh @@ -56,7 +56,7 @@ struct LongMetric template 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]; diff --git a/src/hb-ot-layout-common.hh b/src/hb-ot-layout-common.hh index e4c788658..ef4a9bf21 100644 --- a/src/hb-ot-layout-common.hh +++ b/src/hb-ot-layout-common.hh @@ -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 regions; - OffsetArrayOf dataSets; + LOffsetArrayOf dataSets; public: DEFINE_SIZE_ARRAY (8, dataSets); }; @@ -1715,7 +1724,7 @@ struct ConditionSet } protected: - OffsetArrayOf conditions; + LOffsetArrayOf conditions; public: DEFINE_SIZE_ARRAY (2, conditions); }; diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh index dad6c4ea9..399ede434 100644 --- a/src/hb-ot-layout-gpos-table.hh +++ b/src/hb-ot-layout-gpos-table.hh @@ -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 (&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 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); } diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh index 2ce52a1b4..d24ea59af 100644 --- a/src/hb-ot-layout-gsub-table.hh +++ b/src/hb-ot-layout-gsub-table.hh @@ -48,7 +48,7 @@ struct SingleSubstFormat1 inline void closure (hb_closure_context_t *c) const { TRACE_CLOSURE (this); - for (hb_auto_t 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 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 > from; - hb_auto_t > to; + hb_vector_t from; + hb_vector_t to; hb_codepoint_t delta = deltaGlyphID; - for (hb_auto_t 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 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 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 > from; - hb_auto_t > to; - for (hb_auto_t iter (this+coverage); iter.more (); iter.next ()) + hb_vector_t from; + hb_vector_t 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 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 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 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 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 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 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 &substitute = StructAfter > (lookahead); count = substitute.len; - for (hb_auto_t 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 */ diff --git a/src/hb-ot-layout-gsubgpos.hh b/src/hb-ot-layout-gsubgpos.hh index a4066265c..c4af42048 100644 --- a/src/hb-ot-layout-gsubgpos.hh +++ b/src/hb-ot-layout-gsubgpos.hh @@ -93,7 +93,7 @@ struct hb_closure_context_t : hb_face_t *face; hb_set_t *glyphs; - hb_auto_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 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 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 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 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 */ diff --git a/src/hb-ot-layout.cc b/src/hb-ot-layout.cc index 128253da9..e1b6b2e30 100644 --- a/src/hb-ot-layout.cc +++ b/src/hb-ot-layout.cc @@ -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 + 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 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 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 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 diff --git a/src/hb-ot-layout.h b/src/hb-ot-layout.h index 9bd18c8af..7a016c390 100644 --- a/src/hb-ot-layout.h +++ b/src/hb-ot-layout.h @@ -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 diff --git a/src/hb-ot-math-table.hh b/src/hb-ot-math-table.hh index 2f871124c..e20935972 100644 --- a/src/hb-ot-math-table.hh +++ b/src/hb-ot-math-table.hh @@ -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; diff --git a/src/hb-ot-math.cc b/src/hb-ot-math.cc index c693f4807..92c29480d 100644 --- a/src/hb-ot-math.cc +++ b/src/hb-ot-math.cc @@ -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) { diff --git a/src/hb-ot-maxp-table.hh b/src/hb-ot-maxp-table.hh index 2572ad288..198dd2518 100644 --- a/src/hb-ot-maxp-table.hh +++ b/src/hb-ot-maxp-table.hh @@ -92,7 +92,7 @@ struct maxp if (version.major == 1) { const maxpV1Tail &v1 = StructAfter (*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) { diff --git a/src/hb-ot-name-language.cc b/src/hb-ot-name-language.cc new file mode 100644 index 000000000..0e37e0acb --- /dev/null +++ b/src/hb-ot-name-language.cc @@ -0,0 +1,457 @@ +/* + * Copyright © 2018 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Behdad Esfahbod + */ + +#include "hb-ot-name-language.hh" + +/* Following two tables were generated by joining FreeType, FontConfig, + * and OpenType specification language lists, then filled in missing + * entries using: + * https://docs.microsoft.com/en-us/windows/desktop/intl/language-identifier-constants-and-strings + */ + +struct hb_ot_language_map_t +{ + static int cmp (const void *key, const void *item) + { + unsigned int a = * (unsigned int *) key; + unsigned int b = ((const hb_ot_language_map_t *) item)->code; + return a < b ? -1 : a > b ? +1 : 0; + } + + uint16_t code; + char lang[6]; +}; + +static const hb_ot_language_map_t +hb_ms_language_map[] = +{ + {0x0001, "ar"}, /* ??? */ + {0x0004, "zh"}, /* ??? */ + {0x0009, "en"}, /* ??? */ + {0x0401, "ar"}, /* Arabic (Saudi Arabia) */ + {0x0402, "bg"}, /* Bulgarian (Bulgaria) */ + {0x0403, "ca"}, /* Catalan (Catalan) */ + {0x0404, "zh-tw"}, /* Chinese (Taiwan) */ + {0x0405, "cs"}, /* Czech (Czech Republic) */ + {0x0406, "da"}, /* Danish (Denmark) */ + {0x0407, "de"}, /* German (Germany) */ + {0x0408, "el"}, /* Greek (Greece) */ + {0x0409, "en"}, /* English (United States) */ + {0x040A, "es"}, /* Spanish (Traditional Sort) (Spain) */ + {0x040B, "fi"}, /* Finnish (Finland) */ + {0x040C, "fr"}, /* French (France) */ + {0x040D, "he"}, /* Hebrew (Israel) */ + {0x040E, "hu"}, /* Hungarian (Hungary) */ + {0x040F, "is"}, /* Icelandic (Iceland) */ + {0x0410, "it"}, /* Italian (Italy) */ + {0x0411, "ja"}, /* Japanese (Japan) */ + {0x0412, "ko"}, /* Korean (Korea) */ + {0x0413, "nl"}, /* Dutch (Netherlands) */ + {0x0414, "no"}, /* Norwegian (Bokmal) (Norway) */ + {0x0415, "pl"}, /* Polish (Poland) */ + {0x0416, "pt"}, /* Portuguese (Brazil) */ + {0x0417, "rm"}, /* Romansh (Switzerland) */ + {0x0418, "ro"}, /* Romanian (Romania) */ + {0x0419, "ru"}, /* Russian (Russia) */ + {0x041A, "hr"}, /* Croatian (Croatia) */ + {0x041B, "sk"}, /* Slovak (Slovakia) */ + {0x041C, "sq"}, /* Albanian (Albania) */ + {0x041D, "sv"}, /* Swedish (Sweden) */ + {0x041E, "th"}, /* Thai (Thailand) */ + {0x041F, "tr"}, /* Turkish (Turkey) */ + {0x0420, "ur"}, /* Urdu (Islamic Republic of Pakistan) */ + {0x0421, "id"}, /* Indonesian (Indonesia) */ + {0x0422, "uk"}, /* Ukrainian (Ukraine) */ + {0x0423, "be"}, /* Belarusian (Belarus) */ + {0x0424, "sl"}, /* Slovenian (Slovenia) */ + {0x0425, "et"}, /* Estonian (Estonia) */ + {0x0426, "lv"}, /* Latvian (Latvia) */ + {0x0427, "lt"}, /* Lithuanian (Lithuania) */ + {0x0428, "tg"}, /* Tajik (Cyrillic) (Tajikistan) */ + {0x0429, "fa"}, /* Persian (Iran) */ + {0x042A, "vi"}, /* Vietnamese (Vietnam) */ + {0x042B, "hy"}, /* Armenian (Armenia) */ + {0x042C, "az"}, /* Azeri (Latin) (Azerbaijan) */ + {0x042D, "eu"}, /* Basque (Basque) */ + {0x042E, "hsb"}, /* Upper Sorbian (Germany) */ + {0x042F, "mk"}, /* Macedonian (FYROM) (Former Yugoslav Republic of Macedonia) */ + {0x0430, "st"}, /* ??? */ + {0x0431, "ts"}, /* ??? */ + {0x0432, "tn"}, /* Setswana (South Africa) */ + {0x0433, "ven"}, /* ??? */ + {0x0434, "xh"}, /* isiXhosa (South Africa) */ + {0x0435, "zu"}, /* isiZulu (South Africa) */ + {0x0436, "af"}, /* Afrikaans (South Africa) */ + {0x0437, "ka"}, /* Georgian (Georgia) */ + {0x0438, "fo"}, /* Faroese (Faroe Islands) */ + {0x0439, "hi"}, /* Hindi (India) */ + {0x043A, "mt"}, /* Maltese (Malta) */ + {0x043B, "se"}, /* Sami (Northern) (Norway) */ + {0x043C, "ga"}, /* ??? */ + {0x043D, "yi"}, /* ??? */ + {0x043E, "ms"}, /* Malay (Malaysia) */ + {0x043F, "kk"}, /* Kazakh (Kazakhstan) */ + {0x0440, "ky"}, /* Kyrgyz (Kyrgyzstan) */ + {0x0441, "sw"}, /* Kiswahili (Kenya) */ + {0x0442, "tk"}, /* Turkmen (Turkmenistan) */ + {0x0443, "uz"}, /* Uzbek (Latin) (Uzbekistan) */ + {0x0444, "tt"}, /* Tatar (Russia) */ + {0x0445, "bn"}, /* Bengali (India) */ + {0x0446, "pa"}, /* Punjabi (India) */ + {0x0447, "gu"}, /* Gujarati (India) */ + {0x0448, "or"}, /* Odia (formerly Oriya) (India) */ + {0x0449, "ta"}, /* Tamil (India) */ + {0x044A, "te"}, /* Telugu (India) */ + {0x044B, "kn"}, /* Kannada (India) */ + {0x044C, "ml"}, /* Malayalam (India) */ + {0x044D, "as"}, /* Assamese (India) */ + {0x044E, "mr"}, /* Marathi (India) */ + {0x044F, "sa"}, /* Sanskrit (India) */ + {0x0450, "mn"}, /* Mongolian (Cyrillic) (Mongolia) */ + {0x0451, "bo"}, /* Tibetan (PRC) */ + {0x0452, "cy"}, /* Welsh (United Kingdom) */ + {0x0453, "km"}, /* Khmer (Cambodia) */ + {0x0454, "lo"}, /* Lao (Lao P.D.R.) */ + {0x0455, "my"}, /* ??? */ + {0x0456, "gl"}, /* Galician (Galician) */ + {0x0457, "kok"}, /* Konkani (India) */ + {0x0458, "mni"}, /* ??? */ + {0x0459, "sd"}, /* ??? */ + {0x045A, "syr"}, /* Syriac (Syria) */ + {0x045B, "si"}, /* Sinhala (Sri Lanka) */ + {0x045C, "chr"}, /* ??? */ + {0x045D, "iu"}, /* Inuktitut (Canada) */ + {0x045E, "am"}, /* Amharic (Ethiopia) */ + {0x0460, "ks"}, /* ??? */ + {0x0461, "ne"}, /* Nepali (Nepal) */ + {0x0462, "fy"}, /* Frisian (Netherlands) */ + {0x0463, "ps"}, /* Pashto (Afghanistan) */ + {0x0464, "phi"}, /* Filipino (Philippines) */ + {0x0465, "div"}, /* Divehi (Maldives) */ + {0x0468, "ha"}, /* Hausa (Latin) (Nigeria) */ + {0x046A, "yo"}, /* Yoruba (Nigeria) */ + {0x046B, "quz"}, /* Quechua (Bolivia) */ + {0x046C, "nso"}, /* Sesotho sa Leboa (South Africa) */ + {0x046D, "ba"}, /* Bashkir (Russia) */ + {0x046E, "lb"}, /* Luxembourgish (Luxembourg) */ + {0x046F, "kl"}, /* Greenlandic (Greenland) */ + {0x0470, "ibo"}, /* Igbo (Nigeria) */ + {0x0471, "kau"}, /* ??? */ + {0x0472, "om"}, /* ??? */ + {0x0473, "ti"}, /* ??? */ + {0x0474, "gn"}, /* ??? */ + {0x0475, "haw"}, /* ??? */ + {0x0476, "la"}, /* ??? */ + {0x0477, "so"}, /* ??? */ + {0x0478, "ii"}, /* Yi (PRC) */ + {0x0479, "pap"}, /* ??? */ + {0x047A, "arn"}, /* Mapudungun (Chile) */ + {0x047C, "moh"}, /* Mohawk (Mohawk) */ + {0x047E, "br"}, /* Breton (France) */ + {0x0480, "ug"}, /* Uighur (PRC) */ + {0x0481, "mi"}, /* Maori (New Zealand) */ + {0x0482, "oc"}, /* Occitan (France) */ + {0x0483, "co"}, /* Corsican (France) */ + {0x0484, "gsw"}, /* Alsatian (France) */ + {0x0485, "sah"}, /* Yakut (Russia) */ + {0x0486, "qut"}, /* K'iche (Guatemala) */ + {0x0487, "rw"}, /* Kinyarwanda (Rwanda) */ + {0x0488, "wo"}, /* Wolof (Senegal) */ + {0x048C, "fa"}, /* Dari (Afghanistan) */ + {0x0801, "ar"}, /* Arabic (Iraq) */ + {0x0804, "zh-cn"}, /* Chinese (People’s Republic of China) */ + {0x0807, "de"}, /* German (Switzerland) */ + {0x0809, "en"}, /* English (United Kingdom) */ + {0x080A, "es"}, /* Spanish (Mexico) */ + {0x080C, "fr"}, /* French (Belgium) */ + {0x0810, "it"}, /* Italian (Switzerland) */ + {0x0812, "ko"}, /* ??? */ + {0x0813, "nl"}, /* Dutch (Belgium) */ + {0x0814, "nn"}, /* Norwegian (Nynorsk) (Norway) */ + {0x0816, "pt"}, /* Portuguese (Portugal) */ + {0x0818, "mo"}, /* ??? */ + {0x0819, "ru"}, /* ??? */ + {0x081A, "sr"}, /* Serbian (Latin) (Serbia) */ + {0x081D, "sv"}, /* Sweden (Finland) */ + {0x0820, "ur"}, /* ??? */ + {0x0827, "lt"}, /* ??? */ + {0x082C, "az"}, /* Azeri (Cyrillic) (Azerbaijan) */ + {0x082E, "dsb"}, /* Lower Sorbian (Germany) */ +//{0x083B, ""}, /* Sami (Northern) (Sweden) */ + {0x083C, "gd"}, /* Irish (Ireland) */ + {0x083E, "ms"}, /* Malay (Brunei Darussalam) */ + {0x0843, "uz"}, /* Uzbek (Cyrillic) (Uzbekistan) */ + {0x0845, "bn"}, /* Bengali (Bangladesh) */ + {0x0846, "ar"}, /* ??? */ + {0x0850, "mn"}, /* Mongolian (Traditional) (People’s Republic of China) */ + {0x0851, "dz"}, /* ??? */ + {0x085D, "iu"}, /* Inuktitut (Latin) (Canada) */ + {0x085F, "tzm"}, /* Tamazight (Latin) (Algeria) */ + {0x0861, "ne"}, /* ??? */ +//{0x086B, ""}, /* Quechua (Ecuador) */ + {0x0873, "ti"}, /* ??? */ + {0x0C01, "ar"}, /* Arabic (Egypt) */ + {0x0C04, "zh-hk"}, /* Chinese (Hong Kong S.A.R.) */ + {0x0C07, "de"}, /* German (Austria) */ + {0x0C09, "en"}, /* English (Australia) */ + {0x0C0A, "es"}, /* Spanish (Modern Sort) (Spain) */ + {0x0C0C, "fr"}, /* French (Canada) */ + {0x0C1A, "sr"}, /* Serbian (Cyrillic) (Serbia) */ + {0x0C3B, "se"}, /* Sami (Northern) (Finland) */ +//{0x0C6B, ""}, /* Quechua (Peru) */ + {0x1001, "ar"}, /* Arabic (Libya) */ + {0x1004, "zh-sg"}, /* Chinese (Singapore) */ + {0x1007, "de"}, /* German (Luxembourg) */ + {0x1009, "en"}, /* English (Canada) */ + {0x100A, "es"}, /* Spanish (Guatemala) */ + {0x100C, "fr"}, /* French (Switzerland) */ + {0x101A, "hr"}, /* Croatian (Latin) (Bosnia and Herzegovina) */ + {0x103B, "smj"}, /* Sami (Lule) (Norway) */ + {0x1401, "ar"}, /* Arabic (Algeria) */ +//{0x1404, ""}, /* Chinese (Macao S.A.R.) */ + {0x1407, "de"}, /* German (Liechtenstein) */ + {0x1409, "en"}, /* English (New Zealand) */ + {0x140A, "es"}, /* Spanish (Costa Rica) */ + {0x140C, "fr"}, /* French (Luxembourg) */ + {0x141A, "bs"}, /* Bosnian (Latin) (Bosnia and Herzegovina) */ +//{0x143B, ""}, /* Sami (Lule) (Sweden) */ + {0x1801, "ar"}, /* Arabic (Morocco) */ + {0x1809, "en"}, /* English (Ireland) */ + {0x180A, "es"}, /* Spanish (Panama) */ + {0x180C, "fr"}, /* French (Principality of Monaco) */ +//{0x181A, ""}, /* Serbian (Latin) (Bosnia and Herzegovina) */ + {0x183B, "sma"}, /* Sami (Southern) (Norway) */ + {0x1C01, "ar"}, /* Arabic (Tunisia) */ + {0x1C09, "en"}, /* English (South Africa) */ + {0x1C0A, "es"}, /* Spanish (Dominican Republic) */ + {0x1C0C, "fr"}, /* ??? */ +//{0x1C1A, ""}, /* Serbian (Cyrillic) (Bosnia and Herzegovina) */ +//{0x1C3B, ""}, /* Sami (Southern) (Sweden) */ + {0x2001, "ar"}, /* Arabic (Oman) */ + {0x2009, "en"}, /* English (Jamaica) */ + {0x200A, "es"}, /* Spanish (Venezuela) */ + {0x200C, "fr"}, /* ??? */ + {0x201A, "bs"}, /* Bosnian (Cyrillic) (Bosnia and Herzegovina) */ + {0x203B, "sms"}, /* Sami (Skolt) (Finland) */ + {0x2401, "ar"}, /* Arabic (Yemen) */ + {0x2409, "en"}, /* English (Caribbean) */ + {0x240A, "es"}, /* Spanish (Colombia) */ + {0x240C, "fr"}, /* ??? */ + {0x243B, "smn"}, /* Sami (Inari) (Finland) */ + {0x2801, "ar"}, /* Arabic (Syria) */ + {0x2809, "en"}, /* English (Belize) */ + {0x280A, "es"}, /* Spanish (Peru) */ + {0x280C, "fr"}, /* ??? */ + {0x2C01, "ar"}, /* Arabic (Jordan) */ + {0x2C09, "en"}, /* English (Trinidad and Tobago) */ + {0x2C0A, "es"}, /* Spanish (Argentina) */ + {0x2C0C, "fr"}, /* ??? */ + {0x3001, "ar"}, /* Arabic (Lebanon) */ + {0x3009, "en"}, /* English (Zimbabwe) */ + {0x300A, "es"}, /* Spanish (Ecuador) */ + {0x300C, "fr"}, /* ??? */ + {0x3401, "ar"}, /* Arabic (Kuwait) */ + {0x3409, "en"}, /* English (Republic of the Philippines) */ + {0x340A, "es"}, /* Spanish (Chile) */ + {0x340C, "fr"}, /* ??? */ + {0x3801, "ar"}, /* Arabic (U.A.E.) */ + {0x380A, "es"}, /* Spanish (Uruguay) */ + {0x380C, "fr"}, /* ??? */ + {0x3C01, "ar"}, /* Arabic (Bahrain) */ + {0x3C09, "en"}, /* ??? */ + {0x3C0A, "es"}, /* Spanish (Paraguay) */ + {0x3C0C, "fr"}, /* ??? */ + {0x4001, "ar"}, /* Arabic (Qatar) */ + {0x4009, "en"}, /* English (India) */ + {0x400A, "es"}, /* Spanish (Bolivia) */ + {0x4409, "en"}, /* English (Malaysia) */ + {0x440A, "es"}, /* Spanish (El Salvador) */ + {0x4809, "en"}, /* English (Singapore) */ + {0x480A, "es"}, /* Spanish (Honduras) */ + {0x4C0A, "es"}, /* Spanish (Nicaragua) */ + {0x500A, "es"}, /* Spanish (Puerto Rico) */ + {0x540A, "es"}, /* Spanish (United States) */ + {0xE40A, "es"}, /* ??? */ + {0xE40C, "fr"}, /* ??? */ +}; + +static const hb_ot_language_map_t +hb_mac_language_map[] = +{ + { 0, "en"}, /* English */ + { 1, "fr"}, /* French */ + { 2, "de"}, /* German */ + { 3, "it"}, /* Italian */ + { 4, "nl"}, /* Dutch */ + { 5, "sv"}, /* Swedish */ + { 6, "es"}, /* Spanish */ + { 7, "da"}, /* Danish */ + { 8, "pt"}, /* Portuguese */ + { 9, "no"}, /* Norwegian */ + { 10, "he"}, /* Hebrew */ + { 11, "ja"}, /* Japanese */ + { 12, "ar"}, /* Arabic */ + { 13, "fi"}, /* Finnish */ + { 14, "el"}, /* Greek */ + { 15, "is"}, /* Icelandic */ + { 16, "mt"}, /* Maltese */ + { 17, "tr"}, /* Turkish */ + { 18, "hr"}, /* Croatian */ + { 19, "zh-tw"}, /* Chinese (Traditional) */ + { 20, "ur"}, /* Urdu */ + { 21, "hi"}, /* Hindi */ + { 22, "th"}, /* Thai */ + { 23, "ko"}, /* Korean */ + { 24, "lt"}, /* Lithuanian */ + { 25, "pl"}, /* Polish */ + { 26, "hu"}, /* Hungarian */ + { 27, "et"}, /* Estonian */ + { 28, "lv"}, /* Latvian */ +//{ 29, ""}, /* Sami */ + { 30, "fo"}, /* Faroese */ + { 31, "fa"}, /* Farsi/Persian */ + { 32, "ru"}, /* Russian */ + { 33, "zh-cn"}, /* Chinese (Simplified) */ + { 34, "nl"}, /* Flemish */ + { 35, "ga"}, /* Irish Gaelic */ + { 36, "sq"}, /* Albanian */ + { 37, "ro"}, /* Romanian */ + { 38, "cs"}, /* Czech */ + { 39, "sk"}, /* Slovak */ + { 40, "sl"}, /* Slovenian */ + { 41, "yi"}, /* Yiddish */ + { 42, "sr"}, /* Serbian */ + { 43, "mk"}, /* Macedonian */ + { 44, "bg"}, /* Bulgarian */ + { 45, "uk"}, /* Ukrainian */ + { 46, "be"}, /* Byelorussian */ + { 47, "uz"}, /* Uzbek */ + { 48, "kk"}, /* Kazakh */ + { 49, "az"}, /* Azerbaijani (Cyrillic script) */ + { 50, "az"}, /* Azerbaijani (Arabic script) */ + { 51, "hy"}, /* Armenian */ + { 52, "ka"}, /* Georgian */ + { 53, "mo"}, /* Moldavian */ + { 54, "ky"}, /* Kirghiz */ + { 55, "tg"}, /* Tajiki */ + { 56, "tk"}, /* Turkmen */ + { 57, "mn"}, /* Mongolian (Mongolian script) */ + { 58, "mn"}, /* Mongolian (Cyrillic script) */ + { 59, "ps"}, /* Pashto */ + { 60, "ku"}, /* Kurdish */ + { 61, "ks"}, /* Kashmiri */ + { 62, "sd"}, /* Sindhi */ + { 63, "bo"}, /* Tibetan */ + { 64, "ne"}, /* Nepali */ + { 65, "sa"}, /* Sanskrit */ + { 66, "mr"}, /* Marathi */ + { 67, "bn"}, /* Bengali */ + { 68, "as"}, /* Assamese */ + { 69, "gu"}, /* Gujarati */ + { 70, "pa"}, /* Punjabi */ + { 71, "or"}, /* Oriya */ + { 72, "ml"}, /* Malayalam */ + { 73, "kn"}, /* Kannada */ + { 74, "ta"}, /* Tamil */ + { 75, "te"}, /* Telugu */ + { 76, "si"}, /* Sinhalese */ + { 77, "my"}, /* Burmese */ + { 78, "km"}, /* Khmer */ + { 79, "lo"}, /* Lao */ + { 80, "vi"}, /* Vietnamese */ + { 81, "id"}, /* Indonesian */ + { 82, "tl"}, /* Tagalog */ + { 83, "ms"}, /* Malay (Roman script) */ + { 84, "ms"}, /* Malay (Arabic script) */ + { 85, "am"}, /* Amharic */ + { 86, "ti"}, /* Tigrinya */ + { 87, "om"}, /* Galla */ + { 88, "so"}, /* Somali */ + { 89, "sw"}, /* Swahili */ + { 90, "rw"}, /* Kinyarwanda/Ruanda */ + { 91, "rn"}, /* Rundi */ + { 92, "ny"}, /* Nyanja/Chewa */ + { 93, "mg"}, /* Malagasy */ + { 94, "eo"}, /* Esperanto */ + {128, "cy"}, /* Welsh */ + {129, "eu"}, /* Basque */ + {130, "ca"}, /* Catalan */ + {131, "la"}, /* Latin */ + {132, "qu"}, /* Quechua */ + {133, "gn"}, /* Guarani */ + {134, "ay"}, /* Aymara */ + {135, "tt"}, /* Tatar */ + {136, "ug"}, /* Uighur */ + {137, "dz"}, /* Dzongkha */ + {138, "jw"}, /* Javanese (Roman script) */ + {139, "su"}, /* Sundanese (Roman script) */ + {140, "gl"}, /* Galician */ + {141, "af"}, /* Afrikaans */ + {142, "br"}, /* Breton */ + {143, "iu"}, /* Inuktitut */ + {144, "gd"}, /* Scottish Gaelic */ + {145, "gv"}, /* Manx Gaelic */ + {146, "ga"}, /* Irish Gaelic (with dot above) */ + {147, "to"}, /* Tongan */ + {148, "el"}, /* Greek (polytonic) */ + {149, "ik"}, /* Greenlandic */ + {150, "az"}, /* Azerbaijani (Roman script) */ +}; + + +static hb_language_t +_hb_ot_name_language_for (unsigned int code, + const hb_ot_language_map_t *array, + unsigned int len) +{ + const hb_ot_language_map_t *entry = (const hb_ot_language_map_t *) + hb_bsearch (&code, + array, + len, + sizeof (array[0]), + hb_ot_language_map_t::cmp); + + if (entry) + return hb_language_from_string (entry->lang, -1); + + return HB_LANGUAGE_INVALID; +} + +hb_language_t +_hb_ot_name_language_for_ms_code (unsigned int code) +{ + return _hb_ot_name_language_for (code, + hb_ms_language_map, + ARRAY_LENGTH (hb_ms_language_map)); +} + +hb_language_t +_hb_ot_name_language_for_mac_code (unsigned int code) +{ + return _hb_ot_name_language_for (code, + hb_mac_language_map, + ARRAY_LENGTH (hb_mac_language_map)); +} diff --git a/src/hb-ot-name-language.hh b/src/hb-ot-name-language.hh new file mode 100644 index 000000000..903076c0d --- /dev/null +++ b/src/hb-ot-name-language.hh @@ -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 */ diff --git a/src/hb-ot-name-table.hh b/src/hb-ot-name-table.hh index bb49c2cb0..9f67b5745 100644 --- a/src/hb-ot-name-table.hh +++ b/src/hb-ot-name-table.hh @@ -28,34 +28,69 @@ #define HB_OT_NAME_TABLE_HH #include "hb-open-type.hh" +#include "hb-ot-name-language.hh" +#include "hb-aat-layout.hh" namespace OT { +#define entry_score var.u16[0] +#define entry_index var.u16[1] + + /* * name -- Naming * https://docs.microsoft.com/en-us/typography/opentype/spec/name */ #define HB_OT_TAG_name HB_TAG('n','a','m','e') +#define UNSUPPORTED 42 struct NameRecord { - static int cmp (const void *pa, const void *pb) + inline hb_language_t language (hb_face_t *face) const { - const NameRecord *a = (const NameRecord *) pa; - const NameRecord *b = (const NameRecord *) pb; - int ret; - ret = b->platformID.cmp (a->platformID); - if (ret) return ret; - ret = b->encodingID.cmp (a->encodingID); - if (ret) return ret; - ret = b->languageID.cmp (a->languageID); - if (ret) return ret; - ret = b->nameID.cmp (a->nameID); - if (ret) return ret; - return 0; + unsigned int p = platformID; + unsigned int l = languageID; + + if (p == 3) + return _hb_ot_name_language_for_ms_code (l); + + if (p == 1) + return _hb_ot_name_language_for_mac_code (l); + + if (p == 0) + return _hb_aat_language_get (face, l); + + return HB_LANGUAGE_INVALID; + } + + inline uint16_t score (void) const + { + /* Same order as in cmap::find_best_subtable(). */ + unsigned int p = platformID; + unsigned int e = encodingID; + + /* 32-bit. */ + if (p == 3 && e == 10) return 0; + if (p == 0 && e == 6) return 1; + if (p == 0 && e == 4) return 2; + + /* 16-bit. */ + if (p == 3 && e == 1) return 3; + if (p == 0 && e == 3) return 4; + if (p == 0 && e == 2) return 5; + if (p == 0 && e == 1) return 6; + if (p == 0 && e == 0) return 7; + + /* Symbol. */ + if (p == 3 && e == 0) return 8; + + /* We treat all Mac Latin names as ASCII only. */ + if (p == 1 && e == 0) return 10; /* 10 is magic number :| */ + + return UNSUPPORTED; } inline bool sanitize (hb_sanitize_context_t *c, const void *base) const @@ -75,39 +110,57 @@ struct NameRecord DEFINE_SIZE_STATIC (12); }; +static int +_hb_ot_name_entry_cmp_key (const void *pa, const void *pb) +{ + const hb_ot_name_entry_t *a = (const hb_ot_name_entry_t *) pa; + const hb_ot_name_entry_t *b = (const hb_ot_name_entry_t *) pb; + + /* Compare by name_id, then language. */ + + if (a->name_id != b->name_id) + return a->name_id < b->name_id ? -1 : +1; + + if (a->language == b->language) return 0; + if (!a->language) return -1; + if (!b->language) return +1; + return strcmp (hb_language_to_string (a->language), + hb_language_to_string (b->language)); +} + +static int +_hb_ot_name_entry_cmp (const void *pa, const void *pb) +{ + /* Compare by name_id, then language, then score, then index. */ + + int v = _hb_ot_name_entry_cmp_key (pa, pb); + if (v) + return v; + + const hb_ot_name_entry_t *a = (const hb_ot_name_entry_t *) pa; + const hb_ot_name_entry_t *b = (const hb_ot_name_entry_t *) pb; + + if (a->entry_score != b->entry_score) + return a->entry_score < b->entry_score ? -1 : +1; + + if (a->entry_index != b->entry_index) + return a->entry_index < b->entry_index ? -1 : +1; + + return 0; +} + struct name { static const hb_tag_t tableTag = HB_OT_TAG_name; - inline unsigned int get_name (unsigned int platform_id, - unsigned int encoding_id, - unsigned int language_id, - unsigned int name_id, - void *buffer, - unsigned int buffer_length) const - { - NameRecord key; - key.platformID.set (platform_id); - key.encodingID.set (encoding_id); - key.languageID.set (language_id); - key.nameID.set (name_id); - NameRecord *match = (NameRecord *) bsearch (&key, nameRecordZ.arrayZ, count, sizeof (nameRecordZ[0]), NameRecord::cmp); - - if (!match) - return 0; - - unsigned int length = MIN (buffer_length, (unsigned int) match->length); - memcpy (buffer, (char *) this + stringOffset + match->offset, length); - return length; - } - inline unsigned int get_size (void) const { return min_size + count * nameRecordZ[0].min_size; } inline bool sanitize_records (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - char *string_pool = (char *) this + stringOffset; + const void *string_pool = (this+stringOffset).arrayZ; unsigned int _count = count; + /* Move to run-time?! */ for (unsigned int i = 0; i < _count; i++) if (!nameRecordZ[i].sanitize (c, string_pool)) return_trace (false); return_trace (true); @@ -119,19 +172,107 @@ struct name return_trace (c->check_struct (this) && likely (format == 0 || format == 1) && c->check_array (nameRecordZ.arrayZ, count) && - sanitize_records (c)); + c->check_range (this, stringOffset)); } + struct accelerator_t + { + inline void init (hb_face_t *face) + { + this->blob = hb_sanitize_context_t().reference_table (face); + this->table = this->blob->as (); + 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 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 all_names (table->nameRecordZ.arrayZ, table->count); + const NameRecord &record = all_names[idx]; + const hb_array_t 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 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, HBUINT16, false> + stringOffset; /* Offset to start of string storage (from start of table). */ UnsizedArrayOf 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 */ diff --git a/src/hb-ot-name.cc b/src/hb-ot-name.cc new file mode 100644 index 000000000..e0c971087 --- /dev/null +++ b/src/hb-ot-name.cc @@ -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 +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 +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 (&bytes, text_size, text); + + if (width == 1) /* ASCII */ + return hb_ot_name_convert_utf (&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 (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 (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 (face, name_id, language, text_size, text); +} diff --git a/src/hb-ot-name.h b/src/hb-ot-name.h index 49423e87c..8b8316884 100644 --- a/src/hb-ot-name.h +++ b/src/hb-ot-name.h @@ -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 diff --git a/src/hb-ot-os2-unicode-ranges.hh b/src/hb-ot-os2-unicode-ranges.hh index 19780088a..b0ccd00d7 100644 --- a/src/hb-ot-os2-unicode-ranges.hh +++ b/src/hb-ot-os2-unicode-ranges.hh @@ -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; diff --git a/src/hb-ot-shape-complex-arabic-fallback.hh b/src/hb-ot-shape-complex-arabic-fallback.hh index 2aa036728..eeb2da85f 100644 --- a/src/hb-ot-shape-complex-arabic-fallback.hh +++ b/src/hb-ot-shape-complex-arabic-fallback.hh @@ -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 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? */ diff --git a/src/hb-ot-shape-complex-arabic.cc b/src/hb-ot-shape-complex-arabic.cc index b56443910..8e56dde3d 100644 --- a/src/hb-ot-shape-complex-arabic.cc +++ b/src/hb-ot-shape-complex-arabic.cc @@ -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) diff --git a/src/hb-ot-shape-complex-hangul.cc b/src/hb-ot-shape-complex-hangul.cc index 959540258..e143867e1 100644 --- a/src/hb-ot-shape-complex-hangul.cc +++ b/src/hb-ot-shape-complex-hangul.cc @@ -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) { diff --git a/src/hb-ot-shape-complex-indic.cc b/src/hb-ot-shape-complex-indic.cc index 3babbfec6..4f98f7480 100644 --- a/src/hb-ot-shape-complex-indic.cc +++ b/src/hb-ot-shape-complex-indic.cc @@ -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 { diff --git a/src/hb-ot-shape-complex-khmer.cc b/src/hb-ot-shape-complex-khmer.cc index 88d16267b..1142da3ec 100644 --- a/src/hb-ot-shape-complex-khmer.cc +++ b/src/hb-ot-shape-complex-khmer.cc @@ -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++) diff --git a/src/hb-ot-shape-complex-myanmar.cc b/src/hb-ot-shape-complex-myanmar.cc index e201a2309..dcada261c 100644 --- a/src/hb-ot-shape-complex-myanmar.cc +++ b/src/hb-ot-shape-complex-myanmar.cc @@ -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 = { diff --git a/src/hb-ot-shape-complex-use.cc b/src/hb-ot-shape-complex-use.cc index addfb87ba..3ab77fc58 100644 --- a/src/hb-ot-shape-complex-use.cc +++ b/src/hb-ot-shape-complex-use.cc @@ -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); } diff --git a/src/hb-ot-shape-complex-vowel-constraints.cc b/src/hb-ot-shape-complex-vowel-constraints.cc index aae5936a2..20af8711e 100644 --- a/src/hb-ot-shape-complex-vowel-constraints.cc +++ b/src/hb-ot-shape-complex-vowel-constraints.cc @@ -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 diff --git a/src/hb-ot-shape-fallback.cc b/src/hb-ot-shape-fallback.cc index 4c5ccc974..766efe20d 100644 --- a/src/hb-ot-shape-fallback.cc +++ b/src/hb-ot-shape-fallback.cc @@ -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; } } diff --git a/src/hb-ot-shape-normalize.cc b/src/hb-ot-shape-normalize.cc index a8229a98d..82bb24b7d 100644 --- a/src/hb-ot-shape-normalize.cc +++ b/src/hb-ot-shape-normalize.cc @@ -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 { diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc index 065b4d4bf..c55d8dcb8 100644 --- a/src/hb-ot-shape.cc +++ b/src/hb-ot-shape.cc @@ -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) { } diff --git a/src/hb-ot-shape.hh b/src/hb-ot-shape.hh index e7d6204a8..1cb9e24d7 100644 --- a/src/hb-ot-shape.hh +++ b/src/hb-ot-shape.hh @@ -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); }; diff --git a/src/hb-ot-tag.cc b/src/hb-ot-tag.cc index 4dba9c31a..a569b8c22 100644 --- a/src/hb-ot-tag.cc +++ b/src/hb-ot-tag.cc @@ -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) diff --git a/src/hb-ot-tag.h b/src/hb-ot-tag.h deleted file mode 100644 index 33a4dbdbc..000000000 --- a/src/hb-ot-tag.h +++ /dev/null @@ -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 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 */ diff --git a/src/hb-ot-var.cc b/src/hb-ot-var.cc index 472ee8452..64087be81 100644 --- a/src/hb-ot-var.cc +++ b/src/hb-ot-var.cc @@ -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 */ diff --git a/src/hb-ot-vorg-table.hh b/src/hb-ot-vorg-table.hh index b6494b51f..98af00e14 100644 --- a/src/hb-ot-vorg-table.hh +++ b/src/hb-ot-vorg-table.hh @@ -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 &subset_metrics, unsigned int dest_sz, diff --git a/src/hb-ot.h b/src/hb-ot.h index 47508d67c..c168175ac 100644 --- a/src/hb-ot.h +++ b/src/hb-ot.h @@ -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" diff --git a/src/hb-set-digest.hh b/src/hb-set-digest.hh index 0f9329f62..4e99df0eb 100644 --- a/src/hb-set-digest.hh +++ b/src/hb-set-digest.hh @@ -48,8 +48,6 @@ template struct hb_set_digest_lowest_bits_t { - ASSERT_POD (); - enum { mask_bytes = sizeof (mask_t) }; enum { mask_bits = sizeof (mask_t) * 8 }; static const unsigned int num_bits = 0 @@ -117,8 +115,6 @@ struct hb_set_digest_lowest_bits_t template struct hb_set_digest_combiner_t { - ASSERT_POD (); - inline void init (void) { head.init (); tail.init (); diff --git a/src/hb-set.cc b/src/hb-set.cc index 09dc4b483..67ec56180 100644 --- a/src/hb-set.cc +++ b/src/hb-set.cc @@ -27,7 +27,16 @@ #include "hb-set.hh" -/* Public API */ +/** + * SECTION:hb-set + * @title: hb-set + * @short_description: Object representing a set of integers + * @include: hb.h + * + * Set objects represent a mathematical set of integer values. They are + * used in non-shaping API to query certain set of characters or glyphs, + * or other integer values. + **/ /** @@ -391,7 +400,7 @@ hb_set_symmetric_difference (hb_set_t *set, * Deprecated: 1.6.1 **/ void -hb_set_invert (hb_set_t *set) +hb_set_invert (hb_set_t *set HB_UNUSED) { } diff --git a/src/hb-set.hh b/src/hb-set.hh index 5fdad2b71..947e8d9d1 100644 --- a/src/hb-set.hh +++ b/src/hb-set.hh @@ -39,6 +39,10 @@ struct hb_set_t { + HB_NO_COPY_ASSIGN (hb_set_t); + inline hb_set_t (void) { init (); } + inline ~hb_set_t (void) { fini (); } + struct page_map_t { inline int cmp (const page_map_t *o) const { return (int) o->major - (int) major; } @@ -49,8 +53,8 @@ struct hb_set_t struct page_t { - inline void init0 (void) { memset (&v, 0, sizeof (v)); } - inline void init1 (void) { memset (&v, 0xff, sizeof (v)); } + inline void init0 (void) { v.clear (); } + inline void init1 (void) { v.clear (0xFF); } inline unsigned int len (void) const { return ARRAY_LENGTH_CONST (v); } @@ -199,6 +203,7 @@ struct hb_set_t } inline void fini_shallow (void) { + population = 0; page_map.fini (); pages.fini (); } @@ -368,8 +373,8 @@ struct hb_set_t if (!resize (count)) return; population = other->population; - memcpy (pages.arrayZ(), other->pages.arrayZ(), count * sizeof (pages.arrayZ()[0])); - memcpy (page_map.arrayZ(), other->page_map.arrayZ(), count * sizeof (page_map.arrayZ()[0])); + memcpy (pages, other->pages, count * sizeof (pages[0])); + memcpy (page_map, other->page_map, count * sizeof (page_map[0])); } inline bool is_equal (const hb_set_t *other) const @@ -669,7 +674,9 @@ struct hb_set_t return nullptr; pages[map.index].init0 (); - memmove (&page_map[i] + 1, &page_map[i], (page_map.len - 1 - i) * sizeof (page_map[0])); + memmove (page_map + i + 1, + page_map + i, + (page_map.len - 1 - i) * sizeof (page_map[0])); page_map[i] = map; } return &pages[page_map[i].index]; diff --git a/src/hb-shape-plan.cc b/src/hb-shape-plan.cc index b2289f869..4648cc757 100644 --- a/src/hb-shape-plan.cc +++ b/src/hb-shape-plan.cc @@ -31,6 +31,19 @@ #include "hb-buffer.hh" +/** + * SECTION:hb-shape-plan + * @title: hb-shape-plan + * @short_description: Object representing a shaping plan + * @include: hb.h + * + * Shape plans are not used for shaping directly, but can be access to query + * certain information about how shaping will perform given a set of input + * parameters (script, language, direction, features, etc.) + * Most client would not need to deal with shape plans directly. + **/ + + static void hb_shape_plan_plan (hb_shape_plan_t *shape_plan, const hb_feature_t *user_features, @@ -441,7 +454,7 @@ hb_non_global_user_features_present (const hb_feature_t *user_features, } static inline hb_bool_t -hb_coords_present (const int *coords, +hb_coords_present (const int *coords HB_UNUSED, unsigned int num_coords) { return num_coords != 0; diff --git a/src/hb-shape-plan.hh b/src/hb-shape-plan.hh index bf82b912b..403c3ebdf 100644 --- a/src/hb-shape-plan.hh +++ b/src/hb-shape-plan.hh @@ -34,7 +34,6 @@ struct hb_shape_plan_t { hb_object_header_t header; - ASSERT_POD (); hb_bool_t default_shaper_list; hb_face_t *face_unsafe; /* We don't carry a reference to face. */ diff --git a/src/hb-shape.cc b/src/hb-shape.cc index e8eeff5b3..f98bc6e51 100644 --- a/src/hb-shape.cc +++ b/src/hb-shape.cc @@ -34,18 +34,20 @@ #include "hb-font.hh" #include "hb-machinery.hh" + /** * SECTION:hb-shape - * @title: Shaping + * @title: hb-shape * @short_description: Conversion of text strings into positioned glyphs * @include: hb.h * * Shaping is the central operation of HarfBuzz. Shaping operates on buffers, * which are sequences of Unicode characters that use the same font and have - * the same text direction, script and language. After shaping the buffer + * the same text direction, script, and language. After shaping the buffer * contains the output glyphs and their positions. **/ + #ifdef HB_USE_ATEXIT static void free_static_shaper_list (void); #endif diff --git a/src/hb-subset-input.hh b/src/hb-subset-input.hh index 75edd5d5e..8dad94f58 100644 --- a/src/hb-subset-input.hh +++ b/src/hb-subset-input.hh @@ -37,7 +37,6 @@ struct hb_subset_input_t { hb_object_header_t header; - ASSERT_POD (); hb_set_t *unicodes; hb_set_t *glyphs; diff --git a/src/hb-subset-plan.cc b/src/hb-subset-plan.cc index 71c4a4667..115aa5871 100644 --- a/src/hb-subset-plan.cc +++ b/src/hb-subset-plan.cc @@ -55,7 +55,7 @@ _add_gid_and_children (const OT::glyf::accelerator_t &glyf, static void _gsub_closure (hb_face_t *face, hb_set_t *gids_to_retain) { - hb_auto_t lookup_indices; + hb_set_t lookup_indices; hb_ot_layout_collect_lookups (face, HB_OT_TAG_GSUB, nullptr, diff --git a/src/hb-subset-plan.hh b/src/hb-subset-plan.hh index c14f1bbb3..afca81e8d 100644 --- a/src/hb-subset-plan.hh +++ b/src/hb-subset-plan.hh @@ -37,7 +37,6 @@ struct hb_subset_plan_t { hb_object_header_t header; - ASSERT_POD (); bool drop_hints : 1; bool drop_layout : 1; diff --git a/src/hb-subset.cc b/src/hb-subset.cc index c988dd56d..990dadf02 100644 --- a/src/hb-subset.cc +++ b/src/hb-subset.cc @@ -71,7 +71,7 @@ _subset2 (hb_subset_plan_t *plan) hb_bool_t result = false; if (source_blob->data) { - hb_auto_t > buf; + hb_vector_t buf; unsigned int buf_size = _plan_estimate_subset_table_size (plan, source_blob->length); DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c initial estimated table size: %u bytes.", HB_UNTAG(tag), buf_size); if (unlikely (!buf.alloc (buf_size))) @@ -80,7 +80,7 @@ _subset2 (hb_subset_plan_t *plan) return false; } retry: - hb_serialize_context_t serializer (buf.arrayZ(), buf_size); + hb_serialize_context_t serializer (buf, buf_size); hb_subset_context_t c (plan, &serializer); result = table->subset (&c); if (serializer.ran_out_of_room) diff --git a/src/hb-subset.hh b/src/hb-subset.hh index 9cdd388d7..e43c79f5e 100644 --- a/src/hb-subset.hh +++ b/src/hb-subset.hh @@ -43,7 +43,7 @@ struct hb_subset_context_t : template inline bool dispatch (const T &obj) { return obj.subset (this); } static bool default_return_value (void) { return true; } - bool stop_sublookup_iteration (bool r) const { return false; } + bool stop_sublookup_iteration (bool r HB_UNUSED) const { return false; } hb_subset_plan_t *plan; hb_serialize_context_t *serializer; diff --git a/src/hb-unicode.cc b/src/hb-unicode.cc index 596e76d05..8cf7898a1 100644 --- a/src/hb-unicode.cc +++ b/src/hb-unicode.cc @@ -33,6 +33,20 @@ #include "hb-unicode.hh" +/** + * SECTION: hb-unicode + * @title: hb-unicode + * @short_description: Unicode character property access + * @include: hb.h + * + * Unicode functions are used to access Unicode character properties. + * Client can pass its own Unicode functions to HarfBuzz, or access + * the built-in Unicode functions that come with HarfBuzz. + * + * With the Unicode functions, one can query variour Unicode character + * properties, such as General Category, Script, Combining Class, etc. + **/ + /* * hb_unicode_funcs_t @@ -109,40 +123,23 @@ hb_unicode_decompose_compatibility_nil (hb_unicode_funcs_t *ufuncs HB_UNUSED } -#define HB_UNICODE_FUNCS_IMPLEMENT_SET \ - HB_UNICODE_FUNCS_IMPLEMENT (glib) \ - HB_UNICODE_FUNCS_IMPLEMENT (icu) \ - HB_UNICODE_FUNCS_IMPLEMENT (ucdn) \ - HB_UNICODE_FUNCS_IMPLEMENT (nil) \ - /* ^--- Add new callbacks before nil */ - -#define hb_nil_get_unicode_funcs hb_unicode_funcs_get_empty - -/* Prototype them all */ -#define HB_UNICODE_FUNCS_IMPLEMENT(set) \ -extern "C" hb_unicode_funcs_t *hb_##set##_get_unicode_funcs (void); -HB_UNICODE_FUNCS_IMPLEMENT_SET -#undef HB_UNICODE_FUNCS_IMPLEMENT - +extern "C" hb_unicode_funcs_t *hb_glib_get_unicode_funcs (void); +extern "C" hb_unicode_funcs_t *hb_icu_get_unicode_funcs (void); +extern "C" hb_unicode_funcs_t *hb_ucdn_get_unicode_funcs (void); hb_unicode_funcs_t * hb_unicode_funcs_get_default (void) { -#define HB_UNICODE_FUNCS_IMPLEMENT(set) \ - return hb_##set##_get_unicode_funcs (); - #if defined(HAVE_UCDN) - HB_UNICODE_FUNCS_IMPLEMENT(ucdn) + return hb_ucdn_get_unicode_funcs (); #elif defined(HAVE_GLIB) - HB_UNICODE_FUNCS_IMPLEMENT(glib) + return hb_glib_get_unicode_funcs (); #elif defined(HAVE_ICU) && defined(HAVE_ICU_BUILTIN) - HB_UNICODE_FUNCS_IMPLEMENT(icu) + return hb_icu_get_unicode_funcs (); #else #define HB_UNICODE_FUNCS_NIL 1 - HB_UNICODE_FUNCS_IMPLEMENT(nil) + return hb_unicode_funcs_get_empty (); #endif - -#undef HB_UNICODE_FUNCS_IMPLEMENT } #if !defined(HB_NO_UNICODE_FUNCS) && defined(HB_UNICODE_FUNCS_NIL) @@ -576,8 +573,8 @@ _hb_modified_combining_class[256] = bool _hb_unicode_is_emoji_Extended_Pictographic (hb_codepoint_t cp) { - return hb_bsearch_r (&cp, _hb_unicode_emoji_Extended_Pictographic_table, - ARRAY_LENGTH (_hb_unicode_emoji_Extended_Pictographic_table), - sizeof (hb_unicode_range_t), - hb_unicode_range_t::cmp, nullptr); + return hb_bsearch (&cp, _hb_unicode_emoji_Extended_Pictographic_table, + ARRAY_LENGTH (_hb_unicode_emoji_Extended_Pictographic_table), + sizeof (hb_unicode_range_t), + hb_unicode_range_t::cmp); } diff --git a/src/hb-unicode.hh b/src/hb-unicode.hh index 6d6a4fa0c..0b66ce8a1 100644 --- a/src/hb-unicode.hh +++ b/src/hb-unicode.hh @@ -63,7 +63,6 @@ extern HB_INTERNAL const uint8_t _hb_modified_combining_class[256]; struct hb_unicode_funcs_t { hb_object_header_t header; - ASSERT_POD (); hb_unicode_funcs_t *parent; @@ -369,7 +368,7 @@ DECLARE_NULL_INSTANCE (hb_unicode_funcs_t); struct hb_unicode_range_t { 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 hb_unicode_range_t *range = (hb_unicode_range_t *) _item; diff --git a/src/hb-uniscribe.cc b/src/hb-uniscribe.cc index 44a67ae4c..26b99ed15 100644 --- a/src/hb-uniscribe.cc +++ b/src/hb-uniscribe.cc @@ -36,7 +36,17 @@ #include "hb-open-file.hh" #include "hb-ot-name-table.hh" -#include "hb-ot-tag.h" +#include "hb-ot-layout.h" + + +/** + * SECTION:hb-uniscribe + * @title: hb-uniscribe + * @short_description: Windows integration + * @include: hb-uniscribe.h + * + * Functions for using HarfBuzz with the Windows fonts. + **/ static inline uint16_t hb_uint16_swap (const uint16_t v) @@ -632,12 +642,12 @@ _hb_uniscribe_shape (hb_shape_plan_t *shape_plan, /* * Set up features. */ - hb_auto_t > feature_records; - hb_auto_t > range_records; + hb_vector_t feature_records; + hb_vector_t range_records; if (num_features) { /* Sort features by start/end events. */ - hb_auto_t > feature_events; + hb_vector_t feature_events; for (unsigned int i = 0; i < num_features; i++) { active_feature_t feature; @@ -672,7 +682,7 @@ _hb_uniscribe_shape (hb_shape_plan_t *shape_plan, } /* Scan events and save features for each range. */ - hb_auto_t > active_features; + hb_vector_t active_features; unsigned int last_index = 0; for (unsigned int i = 0; i < feature_events.len; i++) { @@ -717,7 +727,7 @@ _hb_uniscribe_shape (hb_shape_plan_t *shape_plan, { active_feature_t *feature = active_features.find (&event->feature); if (feature) - active_features.remove (feature - active_features.arrayZ()); + active_features.remove (feature - active_features); } } @@ -728,7 +738,7 @@ _hb_uniscribe_shape (hb_shape_plan_t *shape_plan, for (unsigned int i = 0; i < range_records.len; i++) { range_record_t *range = &range_records[i]; - range->props.potfRecords = feature_records.arrayZ() + reinterpret_cast (range->props.potfRecords); + range->props.potfRecords = feature_records + reinterpret_cast (range->props.potfRecords); } } @@ -844,8 +854,8 @@ retry: #undef MAX_ITEMS OPENTYPE_TAG language_tag = hb_uint32_swap (hb_ot_tag_from_language (buffer->props.language)); - hb_auto_t > range_properties; - hb_auto_t > range_char_counts; + hb_vector_t range_properties; + hb_vector_t range_char_counts; unsigned int glyphs_offset = 0; unsigned int glyphs_len; @@ -902,8 +912,8 @@ retry: &items[i].a, script_tags[i], language_tag, - range_char_counts.arrayZ(), - range_properties.arrayZ(), + range_char_counts, + range_properties, range_properties.len, pchars + chars_offset, item_chars_len, @@ -943,8 +953,8 @@ retry: &items[i].a, script_tags[i], language_tag, - range_char_counts.arrayZ(), - range_properties.arrayZ(), + range_char_counts, + range_properties, range_properties.len, pchars + chars_offset, log_clusters + chars_offset, diff --git a/src/hb-utf.hh b/src/hb-utf.hh index eccb632e4..54ede3c16 100644 --- a/src/hb-utf.hh +++ b/src/hb-utf.hh @@ -29,14 +29,16 @@ #include "hb.hh" +#include "hb-open-type.hh" + struct hb_utf8_t { typedef uint8_t codepoint_t; - static inline const uint8_t * - next (const uint8_t *text, - const uint8_t *end, + static inline const codepoint_t * + next (const codepoint_t *text, + const codepoint_t *end, hb_codepoint_t *unicode, hb_codepoint_t replacement) { @@ -103,13 +105,13 @@ struct hb_utf8_t return text; } - static inline const uint8_t * - prev (const uint8_t *text, - const uint8_t *start, + static inline const codepoint_t * + prev (const codepoint_t *text, + const codepoint_t *start, hb_codepoint_t *unicode, hb_codepoint_t replacement) { - const uint8_t *end = text--; + const codepoint_t *end = text--; while (start < text && (*text & 0xc0) == 0x80 && end - text < 4) text--; @@ -121,20 +123,71 @@ struct hb_utf8_t } static inline unsigned int - strlen (const uint8_t *text) + strlen (const codepoint_t *text) { return ::strlen ((const char *) text); } + + static inline unsigned int + encode_len (hb_codepoint_t unicode) + { + if (unicode < 0x0080u) return 1; + if (unicode < 0x0800u) return 2; + if (unicode < 0x10000u) return 3; + if (unicode < 0x110000u) return 4; + return 3; + } + + static inline codepoint_t * + encode (codepoint_t *text, + const codepoint_t *end, + hb_codepoint_t unicode) + { + if (unlikely (unicode >= 0xD800u && (unicode <= 0xDFFFu || unicode > 0x10FFFFu))) + unicode = 0xFFFDu; + if (unicode < 0x0080u) + *text++ = unicode; + else if (unicode < 0x0800u) + { + if (end - text >= 2) + { + *text++ = 0xC0u + (0x1Fu & (unicode >> 6)); + *text++ = 0x80u + (0x3Fu & (unicode )); + } + } + else if (unicode < 0x10000u) + { + if (end - text >= 3) + { + *text++ = 0xE0u + (0x0Fu & (unicode >> 12)); + *text++ = 0x80u + (0x3Fu & (unicode >> 6)); + *text++ = 0x80u + (0x3Fu & (unicode )); + } + } + else + { + if (end - text >= 4) + { + *text++ = 0xF0u + (0x07u & (unicode >> 18)); + *text++ = 0x80u + (0x3Fu & (unicode >> 12)); + *text++ = 0x80u + (0x3Fu & (unicode >> 6)); + *text++ = 0x80u + (0x3Fu & (unicode )); + } + } + return text; + } }; -struct hb_utf16_t +template +struct hb_utf16_xe_t { - typedef uint16_t codepoint_t; + static_assert (sizeof (TCodepoint) == 2, ""); + typedef TCodepoint codepoint_t; - static inline const uint16_t * - next (const uint16_t *text, - const uint16_t *end, + static inline const codepoint_t * + next (const codepoint_t *text, + const codepoint_t *end, hb_codepoint_t *unicode, hb_codepoint_t replacement) { @@ -164,9 +217,9 @@ struct hb_utf16_t return text; } - static inline const uint16_t * - prev (const uint16_t *text, - const uint16_t *start, + static inline const codepoint_t * + prev (const codepoint_t *text, + const codepoint_t *start, hb_codepoint_t *unicode, hb_codepoint_t replacement) { @@ -198,23 +251,51 @@ struct hb_utf16_t static inline unsigned int - strlen (const uint16_t *text) + strlen (const codepoint_t *text) { unsigned int l = 0; while (*text++) l++; return l; } + + static inline unsigned int + encode_len (hb_codepoint_t unicode) + { + return unicode < 0x10000 ? 1 : 2; + } + + static inline codepoint_t * + encode (codepoint_t *text, + const codepoint_t *end, + hb_codepoint_t unicode) + { + if (unlikely (unicode >= 0xD800u && (unicode <= 0xDFFFu || unicode > 0x10FFFFu))) + unicode = 0xFFFDu; + if (unicode < 0x10000u) + *text++ = unicode; + else if (end - text >= 2) + { + unicode -= 0x10000u; + *text++ = 0xD800u + (unicode >> 10); + *text++ = 0xDC00u + (unicode & 0x03FFu); + } + return text; + } }; +typedef hb_utf16_xe_t hb_utf16_t; +typedef hb_utf16_xe_t hb_utf16_be_t; -template -struct hb_utf32_t + +template +struct hb_utf32_xe_t { - typedef uint32_t codepoint_t; + static_assert (sizeof (TCodepoint) == 4, ""); + typedef TCodepoint codepoint_t; - static inline const uint32_t * - next (const uint32_t *text, - const uint32_t *end HB_UNUSED, + static inline const TCodepoint * + next (const TCodepoint *text, + const TCodepoint *end HB_UNUSED, hb_codepoint_t *unicode, hb_codepoint_t replacement) { @@ -224,9 +305,9 @@ struct hb_utf32_t return text; } - static inline const uint32_t * - prev (const uint32_t *text, - const uint32_t *start HB_UNUSED, + static inline const TCodepoint * + prev (const TCodepoint *text, + const TCodepoint *start HB_UNUSED, hb_codepoint_t *unicode, hb_codepoint_t replacement) { @@ -237,22 +318,42 @@ struct hb_utf32_t } static inline unsigned int - strlen (const uint32_t *text) + strlen (const TCodepoint *text) { unsigned int l = 0; while (*text++) l++; return l; } + + static inline unsigned int + encode_len (hb_codepoint_t unicode HB_UNUSED) + { + return 1; + } + + static inline codepoint_t * + encode (codepoint_t *text, + const codepoint_t *end HB_UNUSED, + hb_codepoint_t unicode) + { + if (validate && unlikely (unicode >= 0xD800u && (unicode <= 0xDFFFu || unicode > 0x10FFFFu))) + unicode = 0xFFFDu; + *text++ = unicode; + return text; + } }; +typedef hb_utf32_xe_t hb_utf32_t; +typedef hb_utf32_xe_t hb_utf32_novalidate_t; + struct hb_latin1_t { typedef uint8_t codepoint_t; - static inline const uint8_t * - next (const uint8_t *text, - const uint8_t *end HB_UNUSED, + static inline const codepoint_t * + next (const codepoint_t *text, + const codepoint_t *end HB_UNUSED, hb_codepoint_t *unicode, hb_codepoint_t replacement HB_UNUSED) { @@ -260,23 +361,95 @@ struct hb_latin1_t return text; } - static inline const uint8_t * - prev (const uint8_t *text, - const uint8_t *start HB_UNUSED, + static inline const codepoint_t * + prev (const codepoint_t *text, + const codepoint_t *start HB_UNUSED, hb_codepoint_t *unicode, - hb_codepoint_t replacement) + hb_codepoint_t replacement HB_UNUSED) { *unicode = *--text; return text; } static inline unsigned int - strlen (const uint8_t *text) + strlen (const codepoint_t *text) { unsigned int l = 0; while (*text++) l++; return l; } + + static inline unsigned int + encode_len (hb_codepoint_t unicode HB_UNUSED) + { + return 1; + } + + static inline codepoint_t * + encode (codepoint_t *text, + const codepoint_t *end HB_UNUSED, + hb_codepoint_t unicode) + { + if (unlikely (unicode >= 0x0100u)) + unicode = '?'; + *text++ = unicode; + return text; + } +}; + + +struct hb_ascii_t +{ + typedef uint8_t codepoint_t; + + static inline const codepoint_t * + next (const codepoint_t *text, + const codepoint_t *end HB_UNUSED, + hb_codepoint_t *unicode, + hb_codepoint_t replacement HB_UNUSED) + { + *unicode = *text++; + if (*unicode >= 0x0080u) + *unicode = replacement; + return text; + } + + static inline const codepoint_t * + prev (const codepoint_t *text, + const codepoint_t *start HB_UNUSED, + hb_codepoint_t *unicode, + hb_codepoint_t replacement) + { + *unicode = *--text; + if (*unicode >= 0x0080u) + *unicode = replacement; + return text; + } + + static inline unsigned int + strlen (const codepoint_t *text) + { + unsigned int l = 0; + while (*text++) l++; + return l; + } + + static inline unsigned int + encode_len (hb_codepoint_t unicode HB_UNUSED) + { + return 1; + } + + static inline codepoint_t * + encode (codepoint_t *text, + const codepoint_t *end HB_UNUSED, + hb_codepoint_t unicode) + { + if (unlikely (unicode >= 0x0080u)) + unicode = '?'; + *text++ = unicode; + return text; + } }; #endif /* HB_UTF_HH */ diff --git a/src/hb-vector.hh b/src/hb-vector.hh index 766e5fb8e..fe06addf7 100644 --- a/src/hb-vector.hh +++ b/src/hb-vector.hh @@ -34,6 +34,10 @@ template struct hb_vector_t { + HB_NO_COPY_ASSIGN_TEMPLATE2 (hb_vector_t, Type, StaticSize); + inline hb_vector_t (void) { init (); } + inline ~hb_vector_t (void) { fini (); } + unsigned int len; private: unsigned int allocated; /* == 0 means allocation failed. */ @@ -48,6 +52,22 @@ struct hb_vector_t arrayZ_ = nullptr; } + inline void fini (void) + { + if (arrayZ_) + free (arrayZ_); + arrayZ_ = nullptr; + allocated = len = 0; + } + inline void fini_deep (void) + { + Type *array = arrayZ(); + unsigned int count = len; + for (unsigned int i = 0; i < count; i++) + array[i].fini (); + fini (); + } + inline Type * arrayZ (void) { return arrayZ_ ? arrayZ_ : static_array; } inline const Type * arrayZ (void) const @@ -66,6 +86,12 @@ struct hb_vector_t return arrayZ()[i]; } + template inline operator T * (void) { return arrayZ(); } + template inline operator const T * (void) const { return arrayZ(); } + + inline Type * operator + (unsigned int i) { return arrayZ() + i; } + inline const Type * operator + (unsigned int i) const { return arrayZ() + i; } + inline Type *push (void) { if (unlikely (!resize (len + 1))) @@ -232,7 +258,7 @@ struct hb_vector_t const Type *array = this->arrayZ(); while (min <= max) { - int mid = (min + max) / 2; + int mid = ((unsigned int) min + (unsigned int) max) / 2; int c = array[mid].cmp (&x); if (c < 0) max = mid - 1; @@ -249,23 +275,6 @@ struct hb_vector_t *i = max; return false; } - - inline void fini_deep (void) - { - Type *array = arrayZ(); - unsigned int count = len; - for (unsigned int i = 0; i < count; i++) - array[i].fini (); - fini (); - } - - inline void fini (void) - { - if (arrayZ_) - free (arrayZ_); - arrayZ_ = nullptr; - allocated = len = 0; - } }; diff --git a/src/hb-version.h b/src/hb-version.h index a8db51606..68af8f864 100644 --- a/src/hb-version.h +++ b/src/hb-version.h @@ -37,10 +37,10 @@ HB_BEGIN_DECLS #define HB_VERSION_MAJOR 2 -#define HB_VERSION_MINOR 0 -#define HB_VERSION_MICRO 2 +#define HB_VERSION_MINOR 1 +#define HB_VERSION_MICRO 0 -#define HB_VERSION_STRING "2.0.2" +#define HB_VERSION_STRING "2.1.0" #define HB_VERSION_ATLEAST(major,minor,micro) \ ((major)*10000+(minor)*100+(micro) <= \ diff --git a/src/hb.h b/src/hb.h index fc75a6918..c5e7072fb 100644 --- a/src/hb.h +++ b/src/hb.h @@ -28,10 +28,6 @@ #define HB_H #define HB_H_IN -#ifndef HB_EXTERN -#define HB_EXTERN extern -#endif - #include "hb-blob.h" #include "hb-buffer.h" #include "hb-common.h" diff --git a/src/hb.hh b/src/hb.hh index ea474298f..fa6a7404d 100644 --- a/src/hb.hh +++ b/src/hb.hh @@ -337,35 +337,40 @@ static_assert ((sizeof (hb_mask_t) == 4), ""); static_assert ((sizeof (hb_var_int_t) == 4), ""); -/* We like our types POD */ +#if __cplusplus >= 201103L -#define _ASSERT_TYPE_POD1(_line, _type) union _type_##_type##_on_line_##_line##_is_not_POD { _type instance; } -#define _ASSERT_TYPE_POD0(_line, _type) _ASSERT_TYPE_POD1 (_line, _type) -#define ASSERT_TYPE_POD(_type) _ASSERT_TYPE_POD0 (__LINE__, _type) +/* We only enable these with C++11 or later, since earlier language + * does not allow structs with constructors in unions, and we need + * those. */ -#ifdef __GNUC__ -# define _ASSERT_INSTANCE_POD1(_line, _instance) \ - HB_STMT_START { \ - typedef __typeof__(_instance) _type_##_line; \ - _ASSERT_TYPE_POD1 (_line, _type_##_line); \ - } HB_STMT_END -#else -# define _ASSERT_INSTANCE_POD1(_line, _instance) typedef int _assertion_on_line_##_line##_not_tested -#endif -# define _ASSERT_INSTANCE_POD0(_line, _instance) _ASSERT_INSTANCE_POD1 (_line, _instance) -# define ASSERT_INSTANCE_POD(_instance) _ASSERT_INSTANCE_POD0 (__LINE__, _instance) - -/* Check _assertion in a method environment */ -#define _ASSERT_POD1(_line) \ - HB_UNUSED inline void _static_assertion_on_line_##_line (void) const \ - { _ASSERT_INSTANCE_POD1 (_line, *this); /* Make sure it's POD. */ } -# define _ASSERT_POD0(_line) _ASSERT_POD1 (_line) -# define ASSERT_POD() _ASSERT_POD0 (__LINE__) - - -#define HB_DISALLOW_COPY_AND_ASSIGN(TypeName) \ +#define HB_NO_COPY_ASSIGN(TypeName) \ TypeName(const TypeName&); \ void operator=(const TypeName&) +#define HB_NO_COPY_ASSIGN_TEMPLATE2(TypeName, T1, T2) \ + TypeName(const TypeName&); \ + void operator=(const TypeName&) +#define HB_NO_CREATE_COPY_ASSIGN(TypeName) \ + TypeName(void); \ + TypeName(const TypeName&); \ + void operator=(const TypeName&) +#define HB_NO_CREATE_COPY_ASSIGN_TEMPLATE(TypeName, T) \ + TypeName(void); \ + TypeName(const TypeName&); \ + void operator=(const TypeName&) +#define HB_NO_CREATE_COPY_ASSIGN_TEMPLATE2(TypeName, T1, T2) \ + TypeName(void); \ + TypeName(const TypeName&); \ + void operator=(const TypeName&) + +#else /* __cpluspplus >= 201103L */ + +#define HB_NO_COPY_ASSIGN(TypeName) +#define HB_NO_COPY_ASSIGN_TEMPLATE2(TypeName, T1, T2) +#define HB_NO_CREATE_COPY_ASSIGN(TypeName) +#define HB_NO_CREATE_COPY_ASSIGN_TEMPLATE(TypeName, T) +#define HB_NO_CREATE_COPY_ASSIGN_TEMPLATE2(TypeName, T1, T2) + +#endif /* __cpluspplus >= 201103L */ /* diff --git a/src/test-name-table.cc b/src/test-name-table.cc new file mode 100644 index 000000000..333052729 --- /dev/null +++ b/src/test-name-table.cc @@ -0,0 +1,67 @@ +/* + * 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.h" +#include "hb-ot.h" + +#include +#include + +int +main (int argc, char **argv) +{ + if (argc != 2) { + fprintf (stderr, "usage: %s font-file\n", argv[0]); + exit (1); + } + + hb_blob_t *blob = hb_blob_create_from_file (argv[1]); + hb_face_t *face = hb_face_create (blob, 0 /* first face */); + hb_blob_destroy (blob); + blob = NULL; + + unsigned int count; + const hb_ot_name_entry_t *entries = hb_ot_name_list_names (face, &count); + + for (unsigned int i = 0; i < count; i++) + { + printf ("%d %s ", + entries[i].name_id, + hb_language_to_string (entries[i].language)); + + char buf[64]; + unsigned int buf_size = sizeof (buf); + hb_ot_name_get_utf8 (face, + entries[i].name_id, + entries[i].language, + &buf_size, + buf); + + printf ("%s\n", buf); + } + + return count ? 0 : 1; +} diff --git a/src/dump-emoji.cc b/src/test-ot-color.cc similarity index 57% rename from src/dump-emoji.cc rename to src/test-ot-color.cc index 2f79fc69d..4b10e0177 100644 --- a/src/dump-emoji.cc +++ b/src/test-ot-color.cc @@ -23,12 +23,8 @@ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. */ -#include "hb-static.cc" -#include "hb-ot-color-cbdt-table.hh" -#include "hb-ot-color-colr-table.hh" -#include "hb-ot-color-cpal-table.hh" -#include "hb-ot-color-sbix-table.hh" -#include "hb-ot-color-svg-table.hh" +#include "hb.h" +#include "hb-ot.h" #include "hb-ft.h" @@ -40,62 +36,104 @@ #include #include -#ifdef HAVE_GLIB -#include -#endif #include #include static void -cbdt_callback (const uint8_t* data, unsigned int length, - unsigned int group, unsigned int gid) +svg_dump (hb_face_t *face, unsigned int face_index) { - char output_path[255]; - sprintf (output_path, "out/cbdt-%d-%d.png", group, gid); - FILE *f = fopen (output_path, "wb"); - fwrite (data, 1, length, f); - fclose (f); + unsigned glyph_count = hb_face_get_glyph_count (face); + + for (unsigned int glyph_id = 0; glyph_id < glyph_count; glyph_id++) + { + hb_blob_t *blob = hb_ot_color_glyph_reference_svg (face, glyph_id); + + if (hb_blob_get_length (blob) == 0) continue; + + unsigned int length; + const char *data = hb_blob_get_data (blob, &length); + + char output_path[255]; + sprintf (output_path, "out/svg-%d-%d.svg%s", + glyph_id, + face_index, + // append "z" if the content is gzipped, https://stackoverflow.com/a/6059405 + (length > 2 && (data[0] == '\x1F') && (data[1] == '\x8B')) ? "z" : ""); + + FILE *f = fopen (output_path, "wb"); + fwrite (data, 1, length, f); + fclose (f); + + hb_blob_destroy (blob); + } +} + +/* _png API is so easy to use unlike the below code, don't get confused */ +static void +png_dump (hb_face_t *face, unsigned int face_index) +{ + unsigned glyph_count = hb_face_get_glyph_count (face); + hb_font_t *font = hb_font_create (face); + + /* scans the font for strikes */ + unsigned int sample_glyph_id; + /* we don't care about different strikes for different glyphs at this point */ + for (sample_glyph_id = 0; sample_glyph_id < glyph_count; sample_glyph_id++) + { + hb_blob_t *blob = hb_ot_color_glyph_reference_png (font, sample_glyph_id); + unsigned int blob_length = hb_blob_get_length (blob); + hb_blob_destroy (blob); + if (blob_length != 0) + break; + } + + unsigned int upem = hb_face_get_upem (face); + unsigned int blob_length = 0; + unsigned int strike = 0; + for (unsigned int ppem = 1; ppem < upem; ppem++) + { + hb_font_set_ppem (font, ppem, ppem); + hb_blob_t *blob = hb_ot_color_glyph_reference_png (font, sample_glyph_id); + unsigned int new_blob_length = hb_blob_get_length (blob); + hb_blob_destroy (blob); + if (new_blob_length != blob_length) + { + for (unsigned int glyph_id = 0; glyph_id < glyph_count; glyph_id++) + { + hb_blob_t *blob = hb_ot_color_glyph_reference_png (font, glyph_id); + + if (hb_blob_get_length (blob) == 0) continue; + + unsigned int length; + const char *data = hb_blob_get_data (blob, &length); + + char output_path[255]; + sprintf (output_path, "out/png-%d-%d-%d.png", glyph_id, strike, face_index); + + FILE *f = fopen (output_path, "wb"); + fwrite (data, 1, length, f); + fclose (f); + + hb_blob_destroy (blob); + } + + strike++; + blob_length = new_blob_length; + } + } + + hb_font_destroy (font); } static void -sbix_callback (const uint8_t* data, unsigned int length, - unsigned int group, unsigned int gid) -{ - char output_path[255]; - sprintf (output_path, "out/sbix-%d-%d.png", group, gid); - FILE *f = fopen (output_path, "wb"); - fwrite (data, 1, length, f); - fclose (f); -} - -static void -svg_callback (const uint8_t* data, unsigned int length, - unsigned int start_glyph, unsigned int end_glyph) -{ - char output_path[255]; - if (start_glyph == end_glyph) - sprintf (output_path, "out/svg-%d.svg", start_glyph); - else - sprintf (output_path, "out/svg-%d-%d.svg", start_glyph, end_glyph); - - // append "z" if the content is gzipped - if ((data[0] == 0x1F) && (data[1] == 0x8B)) - strcat (output_path, "z"); - - FILE *f = fopen (output_path, "wb"); - fwrite (data, 1, length, f); - fclose (f); -} - -static void -colr_cpal_rendering (hb_face_t *face, cairo_font_face_t *cairo_face) +layered_glyph_dump (hb_face_t *face, cairo_font_face_t *cairo_face, unsigned int face_index) { unsigned int upem = hb_face_get_upem (face); unsigned glyph_count = hb_face_get_glyph_count (face); for (hb_codepoint_t gid = 0; gid < glyph_count; ++gid) { - unsigned int num_layers = hb_ot_color_glyph_get_layers (face, gid, 0, nullptr, nullptr); + unsigned int num_layers = hb_ot_color_glyph_get_layers (face, gid, 0, NULL, NULL); if (!num_layers) continue; @@ -132,7 +170,7 @@ colr_cpal_rendering (hb_face_t *face, cairo_font_face_t *cairo_face) for (unsigned int palette = 0; palette < palette_count; palette++) { char output_path[255]; - unsigned int num_colors = hb_ot_color_palette_get_colors (face, palette, 0, nullptr, nullptr); + unsigned int num_colors = hb_ot_color_palette_get_colors (face, palette, 0, NULL, NULL); if (!num_colors) continue; @@ -140,11 +178,7 @@ colr_cpal_rendering (hb_face_t *face, cairo_font_face_t *cairo_face) hb_ot_color_palette_get_colors (face, palette, 0, &num_colors, colors); if (num_colors) { - // If we have more than one palette, use a simpler naming - if (palette_count == 1) - sprintf (output_path, "out/colr-%d.svg", gid); - else - sprintf (output_path, "out/colr-%d-%d.svg", gid, palette); + sprintf (output_path, "out/colr-%d-%d-%d.svg", gid, palette, face_index); cairo_surface_t *surface = cairo_svg_surface_create (output_path, extents.width, extents.height); cairo_t *cr = cairo_create (surface); @@ -182,10 +216,8 @@ colr_cpal_rendering (hb_face_t *face, cairo_font_face_t *cairo_face) static void dump_glyphs (cairo_font_face_t *cairo_face, unsigned int upem, - unsigned int num_glyphs) + unsigned int num_glyphs, unsigned int face_index) { - // Dump every glyph available on the font - return; // disabled for now for (unsigned int i = 0; i < num_glyphs; ++i) { cairo_text_extents_t extents; @@ -213,7 +245,7 @@ dump_glyphs (cairo_font_face_t *cairo_face, unsigned int upem, // Render { char output_path[255]; - sprintf (output_path, "out/%d.svg", i); + sprintf (output_path, "out/%d-%d.svg", face_index, i); cairo_surface_t *surface = cairo_svg_surface_create (output_path, extents.width, extents.height); cairo_t *cr = cairo_create (surface); cairo_set_font_face (cr, cairo_face); @@ -238,15 +270,15 @@ main (int argc, char **argv) } - FILE *font_name_file = fopen ("out/_font_name_file.txt", "r"); - if (font_name_file != nullptr) + FILE *font_name_file = fopen ("out/.dumped_font_name", "r"); + if (font_name_file != NULL) { fprintf (stderr, "Purge or move ./out folder in order to run a new dump\n"); exit (1); } - font_name_file = fopen ("out/_font_name_file.txt", "w"); - if (font_name_file == nullptr) + font_name_file = fopen ("out/.dumped_font_name", "w"); + if (font_name_file == NULL) { fprintf (stderr, "./out is not accessible as a folder, create it please\n"); exit (1); @@ -255,40 +287,49 @@ main (int argc, char **argv) fclose (font_name_file); hb_blob_t *blob = hb_blob_create_from_file (argv[1]); - hb_face_t *face = hb_face_create (blob, 0); - hb_font_t *font = hb_font_create (face); - - OT::CBDT::accelerator_t cbdt; - cbdt.init (face); - cbdt.dump (cbdt_callback); - cbdt.fini (); - - OT::sbix::accelerator_t sbix; - sbix.init (face); - sbix.dump (sbix_callback); - sbix.fini (); - - OT::SVG::accelerator_t svg; - svg.init (face); - svg.dump (svg_callback); - svg.fini (); - - cairo_font_face_t *cairo_face; + unsigned int num_faces = hb_face_count (blob); + if (num_faces == 0) { - FT_Library library; - FT_Init_FreeType (&library); - FT_Face ftface; - FT_New_Face (library, argv[1], 0, &ftface); - cairo_face = cairo_ft_font_face_create_for_ft_face (ftface, 0); + fprintf (stderr, "error: The file (%s) was corrupted, empty or not found", argv[1]); + exit (1); } - colr_cpal_rendering (face, cairo_face); - unsigned int num_glyphs = hb_face_get_glyph_count (face); - unsigned int upem = hb_face_get_upem (face); - dump_glyphs (cairo_face, upem, num_glyphs); + for (unsigned int face_index = 0; face_index < hb_face_count (blob); face_index++) + { + hb_face_t *face = hb_face_create (blob, face_index); + hb_font_t *font = hb_font_create (face); + + if (hb_ot_color_has_png (face)) printf ("Dumping png (cbdt/sbix)...\n"); + png_dump (face, face_index); + + if (hb_ot_color_has_svg (face)) printf ("Dumping svg...\n"); + svg_dump (face, face_index); + + cairo_font_face_t *cairo_face; + { + FT_Library library; + FT_Init_FreeType (&library); + FT_Face ft_face; + FT_New_Face (library, argv[1], 0, &ft_face); + cairo_face = cairo_ft_font_face_create_for_ft_face (ft_face, 0); + } + if (hb_ot_color_has_layers (face) && hb_ot_color_has_palettes (face)) + printf ("Dumping layered color glyphs...\n"); + layered_glyph_dump (face, cairo_face, face_index); + + unsigned int num_glyphs = hb_face_get_glyph_count (face); + unsigned int upem = hb_face_get_upem (face); + + // disabled when color font as cairo rendering of NotoColorEmoji is soooo slow + if (!hb_ot_color_has_layers (face) && + !hb_ot_color_has_png (face) && + !hb_ot_color_has_svg (face)) + dump_glyphs (cairo_face, upem, num_glyphs, face_index); + + hb_font_destroy (font); + hb_face_destroy (face); + } - hb_font_destroy (font); - hb_face_destroy (face); hb_blob_destroy (blob); return 0; diff --git a/src/test-size-params.cc b/src/test-size-params.cc index e53a47d8d..12eec6188 100644 --- a/src/test-size-params.cc +++ b/src/test-size-params.cc @@ -46,7 +46,7 @@ main (int argc, char **argv) blob = nullptr; unsigned int p[5]; - bool ret = hb_ot_layout_get_size_params (face, p, p+1, p+2, p+3, p+4); + bool ret = hb_ot_layout_get_size_params (face, p, p+1, (p+2), p+3, p+4); printf ("%g %u %u %g %g\n", p[0]/10., p[1], p[2], p[3]/10., p[4]/10.); diff --git a/test/api/Makefile.am b/test/api/Makefile.am index 26d8eb02d..f7d61f3e2 100644 --- a/test/api/Makefile.am +++ b/test/api/Makefile.am @@ -172,7 +172,7 @@ symbols-tested.txt: $(TEST_PROGS) $(AM_V_GEN)$(top_builddir)/libtool --mode=execute nm $^ \ | grep ' U hb_' | sed 's/.* U hb_/hb_/' \ | sort | uniq > $@.tmp && mv $@.tmp $@ -symbols-tested-or-deprecated.txt: symbols-tested.txt $(top_builddir)/src/harfbuzz-deprecated.def +symbols-tested-or-deprecated.txt: symbols-tested.txt $(top_builddir)/src/harfbuzz-deprecated-symbols.txt $(AM_V_GEN)cat $^ | sort | uniq > $@.tmp; mv $@.tmp $@ symbols-exported.txt: $(top_builddir)/src/.libs/libharfbuzz.so $(AM_V_GEN)$(top_builddir)/libtool --mode=execute nm $^ \ diff --git a/test/api/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5658272078495744 b/test/api/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5658272078495744 new file mode 100644 index 000000000..f3fa938e5 Binary files /dev/null and b/test/api/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5658272078495744 differ diff --git a/test/api/test-ot-color.c b/test/api/test-ot-color.c index a514c6aa9..fdea16258 100644 --- a/test/api/test-ot-color.c +++ b/test/api/test-ot-color.c @@ -28,8 +28,6 @@ #include "hb-test.h" #include -#include -#include /* Unit tests for hb-ot-color.h */ @@ -103,6 +101,7 @@ static hb_face_t *cpal = NULL; static hb_face_t *cbdt = NULL; static hb_face_t *sbix = NULL; static hb_face_t *svg = NULL; +static hb_face_t *empty = NULL; #define assert_color_rgba(colors, i, r, g, b, a) G_STMT_START { \ const hb_color_t *_colors = (colors); \ @@ -140,19 +139,19 @@ static void test_hb_ot_color_palette_get_name_id_empty (void) { /* numPalettes=0, so all calls are for out-of-bounds palette indices */ - g_assert_cmpint (hb_ot_color_palette_get_name_id (hb_face_get_empty(), 0), ==, HB_NAME_ID_INVALID); - g_assert_cmpint (hb_ot_color_palette_get_name_id (hb_face_get_empty(), 1), ==, HB_NAME_ID_INVALID); + g_assert_cmpint (hb_ot_color_palette_get_name_id (hb_face_get_empty(), 0), ==, HB_OT_NAME_ID_INVALID); + g_assert_cmpint (hb_ot_color_palette_get_name_id (hb_face_get_empty(), 1), ==, HB_OT_NAME_ID_INVALID); } static void test_hb_ot_color_palette_get_name_id_v0 (void) { - g_assert_cmpint (hb_ot_color_palette_get_name_id (cpal_v0, 0), ==, HB_NAME_ID_INVALID); - g_assert_cmpint (hb_ot_color_palette_get_name_id (cpal_v0, 1), ==, HB_NAME_ID_INVALID); + g_assert_cmpint (hb_ot_color_palette_get_name_id (cpal_v0, 0), ==, HB_OT_NAME_ID_INVALID); + g_assert_cmpint (hb_ot_color_palette_get_name_id (cpal_v0, 1), ==, HB_OT_NAME_ID_INVALID); /* numPalettes=2, so palette #2 is out of bounds */ - g_assert_cmpint (hb_ot_color_palette_get_name_id (cpal_v0, 2), ==, HB_NAME_ID_INVALID); + g_assert_cmpint (hb_ot_color_palette_get_name_id (cpal_v0, 2), ==, HB_OT_NAME_ID_INVALID); } @@ -160,11 +159,11 @@ static void test_hb_ot_color_palette_get_name_id_v1 (void) { g_assert_cmpint (hb_ot_color_palette_get_name_id (cpal_v1, 0), ==, 257); - g_assert_cmpint (hb_ot_color_palette_get_name_id (cpal_v1, 1), ==, HB_NAME_ID_INVALID); + g_assert_cmpint (hb_ot_color_palette_get_name_id (cpal_v1, 1), ==, HB_OT_NAME_ID_INVALID); g_assert_cmpint (hb_ot_color_palette_get_name_id (cpal_v1, 2), ==, 258); /* numPalettes=3, so palette #3 is out of bounds */ - g_assert_cmpint (hb_ot_color_palette_get_name_id (cpal_v1, 3), ==, HB_NAME_ID_INVALID); + g_assert_cmpint (hb_ot_color_palette_get_name_id (cpal_v1, 3), ==, HB_OT_NAME_ID_INVALID); } @@ -203,7 +202,6 @@ test_hb_ot_color_palette_get_flags_v1 (void) static void test_hb_ot_color_palette_get_colors_empty (void) { - hb_face_t *empty = hb_face_get_empty (); g_assert_cmpint (hb_ot_color_palette_get_colors (empty, 0, 0, NULL, NULL), ==, 0); } @@ -302,17 +300,15 @@ test_hb_ot_color_palette_get_colors_v1 (void) static void test_hb_ot_color_palette_color_get_name_id (void) { - hb_face_t *empty = hb_face_get_empty (); - - g_assert_cmpuint (hb_ot_color_palette_color_get_name_id (empty, 0), ==, HB_NAME_ID_INVALID); - g_assert_cmpuint (hb_ot_color_palette_color_get_name_id (empty, 1), ==, HB_NAME_ID_INVALID); - g_assert_cmpuint (hb_ot_color_palette_color_get_name_id (empty, 2), ==, HB_NAME_ID_INVALID); - g_assert_cmpuint (hb_ot_color_palette_color_get_name_id (cpal_v0, 0), ==, HB_NAME_ID_INVALID); - g_assert_cmpuint (hb_ot_color_palette_color_get_name_id (cpal_v0, 1), ==, HB_NAME_ID_INVALID); - g_assert_cmpuint (hb_ot_color_palette_color_get_name_id (cpal_v0, 2), ==, HB_NAME_ID_INVALID); - g_assert_cmpuint (hb_ot_color_palette_color_get_name_id (cpal_v1, 0), ==, HB_NAME_ID_INVALID); + g_assert_cmpuint (hb_ot_color_palette_color_get_name_id (empty, 0), ==, HB_OT_NAME_ID_INVALID); + g_assert_cmpuint (hb_ot_color_palette_color_get_name_id (empty, 1), ==, HB_OT_NAME_ID_INVALID); + g_assert_cmpuint (hb_ot_color_palette_color_get_name_id (empty, 2), ==, HB_OT_NAME_ID_INVALID); + g_assert_cmpuint (hb_ot_color_palette_color_get_name_id (cpal_v0, 0), ==, HB_OT_NAME_ID_INVALID); + g_assert_cmpuint (hb_ot_color_palette_color_get_name_id (cpal_v0, 1), ==, HB_OT_NAME_ID_INVALID); + g_assert_cmpuint (hb_ot_color_palette_color_get_name_id (cpal_v0, 2), ==, HB_OT_NAME_ID_INVALID); + g_assert_cmpuint (hb_ot_color_palette_color_get_name_id (cpal_v1, 0), ==, HB_OT_NAME_ID_INVALID); g_assert_cmpuint (hb_ot_color_palette_color_get_name_id (cpal_v1, 1), ==, 256); - g_assert_cmpuint (hb_ot_color_palette_color_get_name_id (cpal_v1, 2), ==, HB_NAME_ID_INVALID); + g_assert_cmpuint (hb_ot_color_palette_color_get_name_id (cpal_v1, 2), ==, HB_OT_NAME_ID_INVALID); } @@ -349,8 +345,6 @@ test_hb_ot_color_glyph_get_layers (void) static void test_hb_ot_color_has_data (void) { - hb_face_t *empty = hb_face_get_empty (); - g_assert (hb_ot_color_has_layers (empty) == FALSE); g_assert (hb_ot_color_has_layers (cpal_v0) == TRUE); g_assert (hb_ot_color_has_layers (cpal_v1) == TRUE); @@ -366,6 +360,93 @@ test_hb_ot_color_has_data (void) g_assert (hb_ot_color_has_palettes (cbdt) == FALSE); g_assert (hb_ot_color_has_palettes (sbix) == FALSE); g_assert (hb_ot_color_has_palettes (svg) == FALSE); + + g_assert (hb_ot_color_has_svg (empty) == FALSE); + g_assert (hb_ot_color_has_svg (cpal_v0) == FALSE); + g_assert (hb_ot_color_has_svg (cpal_v1) == FALSE); + g_assert (hb_ot_color_has_svg (cpal) == FALSE); + g_assert (hb_ot_color_has_svg (cbdt) == FALSE); + g_assert (hb_ot_color_has_svg (sbix) == FALSE); + g_assert (hb_ot_color_has_svg (svg) == TRUE); + + g_assert (hb_ot_color_has_png (empty) == FALSE); + g_assert (hb_ot_color_has_png (cpal_v0) == FALSE); + g_assert (hb_ot_color_has_png (cpal_v1) == FALSE); + g_assert (hb_ot_color_has_png (cpal) == FALSE); + g_assert (hb_ot_color_has_png (cbdt) == TRUE); + g_assert (hb_ot_color_has_png (sbix) == TRUE); + g_assert (hb_ot_color_has_png (svg) == FALSE); +} + +static void +test_hb_ot_color_svg (void) +{ + hb_blob_t *blob; + + blob = hb_ot_color_glyph_reference_svg (svg, 0); + g_assert (hb_blob_get_length (blob) == 0); + + blob = hb_ot_color_glyph_reference_svg (svg, 1); + unsigned int length; + const char *data = hb_blob_get_data (blob, &length); + g_assert_cmpuint (length, ==, 146); + g_assert (strncmp (data, "", 5) == 0); + hb_blob_destroy (blob); + + blob = hb_ot_color_glyph_reference_svg (empty, 0); + g_assert (hb_blob_get_length (blob) == 0); +} + + +static void +test_hb_ot_color_png (void) +{ + hb_blob_t *blob; + unsigned int length; + const char *data; + hb_glyph_extents_t extents; + + /* sbix */ + hb_font_t *sbix_font; + sbix_font = hb_font_create (sbix); + blob = hb_ot_color_glyph_reference_png (sbix_font, 0); + hb_font_get_glyph_extents (sbix_font, 0, &extents); + g_assert_cmpint (extents.x_bearing, ==, 0); + g_assert_cmpint (extents.y_bearing, ==, 0); + g_assert_cmpint (extents.width, ==, 0); + g_assert_cmpint (extents.height, ==, 0); + g_assert (hb_blob_get_length (blob) == 0); + + blob = hb_ot_color_glyph_reference_png (sbix_font, 1); + data = hb_blob_get_data (blob, &length); + g_assert_cmpuint (length, ==, 224); + g_assert (strncmp (data + 1, "PNG", 3) == 0); + hb_font_get_glyph_extents (sbix_font, 1, &extents); + g_assert_cmpint (extents.x_bearing, ==, 0); + g_assert_cmpint (extents.y_bearing, ==, 0); + g_assert_cmpint (extents.width, ==, 800); + g_assert_cmpint (extents.height, ==, 800); + hb_blob_destroy (blob); + hb_font_destroy (sbix_font); + + /* cbdt */ + hb_font_t *cbdt_font; + cbdt_font = hb_font_create (cbdt); + blob = hb_ot_color_glyph_reference_png (cbdt_font, 0); + g_assert (hb_blob_get_length (blob) == 0); + + blob = hb_ot_color_glyph_reference_png (cbdt_font, 1); + data = hb_blob_get_data (blob, &length); + g_assert_cmpuint (length, ==, 88); + g_assert (strncmp (data + 1, "PNG", 3) == 0); + hb_font_get_glyph_extents (cbdt_font, 1, &extents); + g_assert_cmpint (extents.x_bearing, ==, 0); + g_assert_cmpint (extents.y_bearing, ==, 1024); + g_assert_cmpint (extents.width, ==, 1024); + g_assert_cmpint (extents.height, ==, -1024); + hb_blob_destroy (blob); + hb_font_destroy (cbdt_font); } int @@ -380,6 +461,7 @@ main (int argc, char **argv) cbdt = hb_test_open_font_file ("fonts/chromacheck-cbdt.ttf"); sbix = hb_test_open_font_file ("fonts/chromacheck-sbix.ttf"); svg = hb_test_open_font_file ("fonts/chromacheck-svg.ttf"); + empty = hb_face_get_empty (); hb_test_add (test_hb_ot_color_palette_get_count); hb_test_add (test_hb_ot_color_palette_get_name_id_empty); hb_test_add (test_hb_ot_color_palette_get_name_id_v0); @@ -393,6 +475,8 @@ main (int argc, char **argv) hb_test_add (test_hb_ot_color_palette_color_get_name_id); hb_test_add (test_hb_ot_color_glyph_get_layers); hb_test_add (test_hb_ot_color_has_data); + hb_test_add (test_hb_ot_color_png); + hb_test_add (test_hb_ot_color_svg); status = hb_test_run(); hb_face_destroy (cpal_v0); hb_face_destroy (cpal_v1); diff --git a/test/api/test-ot-name.c b/test/api/test-ot-name.c index d73339785..431ee3a20 100644 --- a/test/api/test-ot-name.c +++ b/test/api/test-ot-name.c @@ -41,11 +41,11 @@ test_ot_layout_feature_get_name_ids_and_characters (void) &feature_index)) g_error ("Failed to find feature index"); - hb_name_id_t label_id; - hb_name_id_t tooltip_id; - hb_name_id_t sample_id; + hb_ot_name_id_t label_id; + hb_ot_name_id_t tooltip_id; + hb_ot_name_id_t sample_id; unsigned int num_named_parameters; - hb_name_id_t first_param_id; + hb_ot_name_id_t first_param_id; if (!hb_ot_layout_feature_get_name_ids (face, HB_OT_TAG_GSUB, feature_index, &label_id, &tooltip_id, &sample_id, &num_named_parameters, &first_param_id)) diff --git a/test/api/test-ot-tag.c b/test/api/test-ot-tag.c index f89c25deb..c0329bffc 100644 --- a/test/api/test-ot-tag.c +++ b/test/api/test-ot-tag.c @@ -60,7 +60,7 @@ test_script_tags_from_language (const char *s, const char *lang_s, hb_script_t s { hb_script_t tag; unsigned int count = 1; - hb_script_t t; + hb_tag_t t; g_test_message ("Testing script %c%c%c%c: script tag %s, language tag %s", HB_UNTAG (hb_script_to_iso15924_tag (script)), s, lang_s); tag = hb_tag_from_string (s, -1); @@ -78,7 +78,7 @@ static void test_indic_tags (const char *s1, const char *s2, const char *s3, hb_script_t script) { hb_script_t tag1, tag2, tag3; - hb_script_t t[3]; + hb_tag_t t[3]; unsigned int count = 3; g_test_message ("Testing script %c%c%c%c: USE tag %s, new tag %s, old tag %s", HB_UNTAG (hb_script_to_iso15924_tag (script)), s1, s2, s3); @@ -103,7 +103,7 @@ test_indic_tags (const char *s1, const char *s2, const char *s3, hb_script_t scr static void test_ot_tag_script_degenerate (void) { - hb_script_t t[2]; + hb_tag_t t[2]; unsigned int count = 2; g_assert_cmphex (HB_TAG_CHAR4 ("DFLT"), ==, HB_OT_TAG_DEFAULT_SCRIPT); diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5659690013556736 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5659690013556736 new file mode 100644 index 000000000..9293c46cf Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5659690013556736 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5768601332613120 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5768601332613120 new file mode 100644 index 000000000..385e67079 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5768601332613120 differ diff --git a/test/fuzzing/hb-shape-fuzzer.cc b/test/fuzzing/hb-shape-fuzzer.cc index b5a6c12e0..e8bc186b1 100644 --- a/test/fuzzing/hb-shape-fuzzer.cc +++ b/test/fuzzing/hb-shape-fuzzer.cc @@ -39,6 +39,10 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) hb_glyph_extents_t extents; hb_font_get_glyph_extents (font, info.codepoint, &extents); + + hb_ot_color_glyph_get_layers (face, info.codepoint, 0, nullptr, nullptr); + hb_blob_destroy (hb_ot_color_glyph_reference_svg (face, info.codepoint)); + hb_blob_destroy (hb_ot_color_glyph_reference_png (font, info.codepoint)); } hb_buffer_destroy (buffer); diff --git a/test/fuzzing/run-shape-fuzzer-tests.py b/test/fuzzing/run-shape-fuzzer-tests.py index 53c4f501a..e3d180f2b 100755 --- a/test/fuzzing/run-shape-fuzzer-tests.py +++ b/test/fuzzing/run-shape-fuzzer-tests.py @@ -76,7 +76,8 @@ for file in os.listdir (parent_path): path = os.path.join(parent_path, file) text, returncode = cmd ([hb_shape_fuzzer, path]) - print (text) + if text.strip (): + print (text) failed = False if returncode != 0 or 'error' in text: diff --git a/test/fuzzing/run-subset-fuzzer-tests.py b/test/fuzzing/run-subset-fuzzer-tests.py index d4e3487f0..7392a92ec 100755 --- a/test/fuzzing/run-subset-fuzzer-tests.py +++ b/test/fuzzing/run-subset-fuzzer-tests.py @@ -22,7 +22,6 @@ fails = 0 def run_dir (parent_path): global fails - print ("running subset fuzzer against fonts in %s" % parent_path) for file in os.listdir (parent_path): path = os.path.join(parent_path, file) diff --git a/test/shaping/data/in-house/fonts/TestDFONT.dfont b/test/shaping/data/in-house/fonts/DFONT.dfont similarity index 100% rename from test/shaping/data/in-house/fonts/TestDFONT.dfont rename to test/shaping/data/in-house/fonts/DFONT.dfont diff --git a/test/shaping/data/in-house/fonts/TestMORXTwentyeight.ttf b/test/shaping/data/in-house/fonts/MORXTwentyeight.ttf similarity index 100% rename from test/shaping/data/in-house/fonts/TestMORXTwentyeight.ttf rename to test/shaping/data/in-house/fonts/MORXTwentyeight.ttf diff --git a/test/shaping/data/in-house/fonts/TestTRAK.ttf b/test/shaping/data/in-house/fonts/TRAK.ttf similarity index 100% rename from test/shaping/data/in-house/fonts/TestTRAK.ttf rename to test/shaping/data/in-house/fonts/TRAK.ttf diff --git a/test/shaping/data/in-house/fonts/TestTTC.ttc b/test/shaping/data/in-house/fonts/TTC.ttc similarity index 100% rename from test/shaping/data/in-house/fonts/TestTTC.ttc rename to test/shaping/data/in-house/fonts/TTC.ttc diff --git a/test/shaping/data/in-house/tests/aat-morx.tests b/test/shaping/data/in-house/tests/aat-morx.tests index 4153091d0..27f5bccc9 100644 --- a/test/shaping/data/in-house/tests/aat-morx.tests +++ b/test/shaping/data/in-house/tests/aat-morx.tests @@ -1 +1 @@ -../fonts/TestMORXTwentyeight.ttf::U+0041,U+0078,U+0045,U+0079,U+0044,U+0079,U+0079:[A_E_D=0+1394|x=0+529|y=0+510|y=5+510|y=6+510] +../fonts/MORXTwentyeight.ttf::U+0041,U+0078,U+0045,U+0079,U+0044,U+0079,U+0079:[A_E_D=0+1394|x=0+529|y=0+510|y=5+510|y=6+510] diff --git a/test/shaping/data/in-house/tests/aat-trak.tests b/test/shaping/data/in-house/tests/aat-trak.tests index 3c558e60e..4bbe72939 100644 --- a/test/shaping/data/in-house/tests/aat-trak.tests +++ b/test/shaping/data/in-house/tests/aat-trak.tests @@ -1,11 +1,11 @@ -../fonts/TestTRAK.ttf::U+0041,U+0042,U+0043:[A.alt=0+1000|B=1+1000|C.alt=2+1000] -../fonts/TestTRAK.ttf:--font-ptem=.5:U+0041,U+0042,U+0043:[A.alt=0@100,0+1200|B=1@100,0+1200|C.alt=2@100,0+1200] -../fonts/TestTRAK.ttf:--font-ptem=1:U+0041,U+0042,U+0043:[A.alt=0@100,0+1200|B=1@100,0+1200|C.alt=2@100,0+1200] -../fonts/TestTRAK.ttf:--font-ptem=2:U+0041,U+0042,U+0043:[A.alt=0@93,0+1187|B=1@93,0+1187|C.alt=2@93,0+1187] -../fonts/TestTRAK.ttf:--font-ptem=9:U+0041,U+0042,U+0043:[A.alt=0+1000|B=1+1000|C.alt=2+1000] -../fonts/TestTRAK.ttf:--font-ptem=24:U+0041,U+0042,U+0043:[A.alt=0@-12,0+976|B=1@-12,0+976|C.alt=2@-12,0+976] -../fonts/TestTRAK.ttf:--font-ptem=72:U+0041,U+0042,U+0043:[A.alt=0@-50,0+900|B=1@-50,0+900|C.alt=2@-50,0+900] -../fonts/TestTRAK.ttf:--font-ptem=144:U+0041,U+0042,U+0043:[A.alt=0@-107,0+786|B=1@-107,0+786|C.alt=2@-107,0+786] -../fonts/TestTRAK.ttf:--font-ptem=144:U+0041,U+0042,U+0043:[A.alt=0@-107,0+786|B=1@-107,0+786|C.alt=2@-107,0+786] -../fonts/TestTRAK.ttf:--font-ptem=144 --features=-trak:U+0041,U+0042,U+0043:[A.alt=0+1000|B=1+1000|C.alt=2+1000] -../fonts/TestTRAK.ttf:--font-ptem=144 --features=-trak[1;3]:U+0041,U+0042,U+0043,U+0041,U+0042,U+0043:[A.alt=0@-107,0+786|B=1+1000|C.alt=2+1000|A.alt=3@-107,0+786|B=4@-107,0+786|C.alt=5@-107,0+786] +../fonts/TRAK.ttf::U+0041,U+0042,U+0043:[A.alt=0+1000|B=1+1000|C.alt=2+1000] +../fonts/TRAK.ttf:--font-ptem=.5:U+0041,U+0042,U+0043:[A.alt=0@100,0+1200|B=1@100,0+1200|C.alt=2@100,0+1200] +../fonts/TRAK.ttf:--font-ptem=1:U+0041,U+0042,U+0043:[A.alt=0@100,0+1200|B=1@100,0+1200|C.alt=2@100,0+1200] +../fonts/TRAK.ttf:--font-ptem=2:U+0041,U+0042,U+0043:[A.alt=0@93,0+1187|B=1@93,0+1187|C.alt=2@93,0+1187] +../fonts/TRAK.ttf:--font-ptem=9:U+0041,U+0042,U+0043:[A.alt=0+1000|B=1+1000|C.alt=2+1000] +../fonts/TRAK.ttf:--font-ptem=24:U+0041,U+0042,U+0043:[A.alt=0@-12,0+976|B=1@-12,0+976|C.alt=2@-12,0+976] +../fonts/TRAK.ttf:--font-ptem=72:U+0041,U+0042,U+0043:[A.alt=0@-50,0+900|B=1@-50,0+900|C.alt=2@-50,0+900] +../fonts/TRAK.ttf:--font-ptem=144:U+0041,U+0042,U+0043:[A.alt=0@-107,0+786|B=1@-107,0+786|C.alt=2@-107,0+786] +../fonts/TRAK.ttf:--font-ptem=144:U+0041,U+0042,U+0043:[A.alt=0@-107,0+786|B=1@-107,0+786|C.alt=2@-107,0+786] +../fonts/TRAK.ttf:--font-ptem=144 --features=-trak:U+0041,U+0042,U+0043:[A.alt=0+1000|B=1+1000|C.alt=2+1000] +../fonts/TRAK.ttf:--font-ptem=144 --features=-trak[1;3]:U+0041,U+0042,U+0043,U+0041,U+0042,U+0043:[A.alt=0@-107,0+786|B=1+1000|C.alt=2+1000|A.alt=3@-107,0+786|B=4@-107,0+786|C.alt=5@-107,0+786] diff --git a/test/shaping/data/in-house/tests/collections.tests b/test/shaping/data/in-house/tests/collections.tests index 85653c543..07dac9dd4 100644 --- a/test/shaping/data/in-house/tests/collections.tests +++ b/test/shaping/data/in-house/tests/collections.tests @@ -1,6 +1,6 @@ -../fonts/TestDFONT.dfont:--face-index=0 --font-funcs=ot:U+2026,U+0020,U+002E:[ellipsis=0+723|space=1+250|period=2+241] -../fonts/TestDFONT.dfont:--face-index=1 --font-funcs=ot:U+2026,U+0020,U+002E:[gid0=0+1000|gid0=1+1000|gid0=2+1000] -../fonts/TestDFONT.dfont:--face-index=2 --font-funcs=ot:U+2026,U+0020,U+002E:[gid0=0+1000|gid0=1+1000|gid0=2+1000] -../fonts/TestTTC.ttc:--face-index=0 --font-funcs=ot:U+2026,U+0020,U+002E:[ellipsis=0+723|space=1+250|period=2+241] -../fonts/TestTTC.ttc:--face-index=1 --font-funcs=ot:U+2026,U+0020,U+002E:[ellipsis=0+723|space=1+250|period=2+241] -../fonts/TestTTC.ttc:--face-index=2 --font-funcs=ot:U+2026,U+0020,U+002E:[gid0=0+1000|gid0=1+1000|gid0=2+1000] +../fonts/DFONT.dfont:--face-index=0 --font-funcs=ot:U+2026,U+0020,U+002E:[ellipsis=0+723|space=1+250|period=2+241] +../fonts/DFONT.dfont:--face-index=1 --font-funcs=ot:U+2026,U+0020,U+002E:[gid0=0+1000|gid0=1+1000|gid0=2+1000] +../fonts/DFONT.dfont:--face-index=2 --font-funcs=ot:U+2026,U+0020,U+002E:[gid0=0+1000|gid0=1+1000|gid0=2+1000] +../fonts/TTC.ttc:--face-index=0 --font-funcs=ot:U+2026,U+0020,U+002E:[ellipsis=0+723|space=1+250|period=2+241] +../fonts/TTC.ttc:--face-index=1 --font-funcs=ot:U+2026,U+0020,U+002E:[ellipsis=0+723|space=1+250|period=2+241] +../fonts/TTC.ttc:--face-index=2 --font-funcs=ot:U+2026,U+0020,U+002E:[gid0=0+1000|gid0=1+1000|gid0=2+1000] diff --git a/test/shaping/data/in-house/tests/color-fonts.tests b/test/shaping/data/in-house/tests/color-fonts.tests index e7311bc33..b325d78c1 100644 --- a/test/shaping/data/in-house/tests/color-fonts.tests +++ b/test/shaping/data/in-house/tests/color-fonts.tests @@ -1 +1 @@ -../fonts/ee39587d13b2afa5499cc79e45780aa79293bbd4.ttf:--font-funcs=ot --show-extents:U+1F42F:[gid1=0+2963<0,2178,2963,-2788>] +../fonts/ee39587d13b2afa5499cc79e45780aa79293bbd4.ttf:--font-funcs=ot --show-extents:U+1F42F:[gid1=0+2963<0,2179,2963,-2789>] diff --git a/test/shaping/data/in-house/tests/spaces.tests b/test/shaping/data/in-house/tests/spaces.tests index 3ebaac51c..526d158b1 100644 --- a/test/shaping/data/in-house/tests/spaces.tests +++ b/test/shaping/data/in-house/tests/spaces.tests @@ -15,3 +15,20 @@ ../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot:U+202F:[gid1=0+280] ../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot:U+205F:[gid1=0+455] ../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot:U+3000:[gid1=0+2048] +../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot --direction=ttb:U+0020:[gid1=0@-280,0+0,-2048] +../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot --direction=ttb:U+00A0:[gid1=0@-280,0+0,-2048] +../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot --direction=ttb:U+1680:[gid0=0@-346,0+0,-2048] +../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot --direction=ttb:U+2000:[gid1=0@-280,0+0,1024] +../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot --direction=ttb:U+2001:[gid1=0@-280,0+0,2048] +../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot --direction=ttb:U+2002:[gid1=0@-280,0+0,1024] +../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot --direction=ttb:U+2003:[gid1=0@-280,0+0,2048] +../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot --direction=ttb:U+2004:[gid1=0@-280,0+0,683] +../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot --direction=ttb:U+2005:[gid1=0@-280,0+0,512] +../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot --direction=ttb:U+2006:[gid1=0@-280,0+0,341] +../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot --direction=ttb:U+2007:[gid1=0@-280,0+0,-2048] +../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot --direction=ttb:U+2008:[gid1=0@-280,0+0,-2048] +../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot --direction=ttb:U+2009:[gid1=0@-280,0+0,410] +../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot --direction=ttb:U+200A:[gid1=0@-280,0+0,128] +../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot --direction=ttb:U+202F:[gid1=0@-280,0+0,-1024] +../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot --direction=ttb:U+205F:[gid1=0@-280,0+0,455] +../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot --direction=ttb:U+3000:[gid1=0@-280,0+0,2048] diff --git a/test/shaping/run-tests.py b/test/shaping/run-tests.py index f77a17c3d..abb25ab3e 100755 --- a/test/shaping/run-tests.py +++ b/test/shaping/run-tests.py @@ -2,30 +2,33 @@ from __future__ import print_function, division, absolute_import -import sys, os, subprocess, tempfile - +import sys, os, subprocess def cmd(command): - # https://stackoverflow.com/a/4408409 - with tempfile.TemporaryFile() as tempf: - p = subprocess.Popen (command, stdout=tempf, stderr=sys.stdout) - p.wait () - tempf.seek(0) - return tempf.read().decode ("utf-8").strip (), p.returncode + global process + process.stdin.write ((' '.join (command) + '\n').encode ("utf-8")) + process.stdin.flush () + return process.stdout.readline().decode ("utf-8").strip () args = sys.argv[1:] -if not args or sys.argv[1].find('hb-shape') == -1 or not os.path.exists (sys.argv[1]): - print ("""First argument does not seem to point to usable hb-shape.""") - sys.exit (1) -hb_shape, args = args[0], args[1:] - -fails = 0 reference = False if len (args) and args[0] == "--reference": reference = True args = args[1:] +if not args or args[0].find('hb-shape') == -1 or not os.path.exists (args[0]): + print ("""First argument does not seem to point to usable hb-shape.""") + sys.exit (1) +hb_shape, args = args[0], args[1:] + +process = subprocess.Popen ([hb_shape, '--batch'], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=sys.stdout) + +fails = 0 + if not len (args): args = ['-'] @@ -60,24 +63,14 @@ for filename in args: print ("%s %s %s %s --unicodes %s" % (hb_shape, fontfile, ' '.join(extra_options), options, unicodes)) - glyphs1, returncode = cmd ([hb_shape, "--font-funcs=ft", + glyphs1 = cmd ([hb_shape, "--font-funcs=ft", fontfile] + extra_options + ["--unicodes", unicodes] + (options.split (' ') if options else [])) - if returncode: - print ("ERROR: hb-shape --font-funcs=ft failed.") # file=sys.stderr - fails = fails + 1 - #continue - - glyphs2, returncode = cmd ([hb_shape, "--font-funcs=ot", + glyphs2 = cmd ([hb_shape, "--font-funcs=ot", fontfile] + extra_options + ["--unicodes", unicodes] + (options.split (' ') if options else [])) - if returncode: - print ("ERROR: hb-shape --font-funcs=ot failed.") # file=sys.stderr - fails = fails + 1 - #continue - if glyphs1 != glyphs2 and glyphs_expected != '*': print ("FT funcs: " + glyphs1) # file=sys.stderr print ("OT funcs: " + glyphs2) # file=sys.stderr diff --git a/util/hb-shape.cc b/util/hb-shape.cc index 337cd4319..1a671230d 100644 --- a/util/hb-shape.cc +++ b/util/hb-shape.cc @@ -160,6 +160,34 @@ struct output_buffer_t int main (int argc, char **argv) { + if (argc == 2 && !strcmp (argv[1], "--batch")) + { + unsigned int ret = 0; + char buf[4092]; + while (fgets (buf, sizeof (buf), stdin)) + { + size_t l = strlen (buf); + if (l && buf[l - 1] == '\n') buf[l - 1] = '\0'; + main_font_text_t, FONT_SIZE_UPEM, 0> driver; + char *args[32]; + argc = 0; + char *p = buf, *e; + args[argc++] = p; + while ((e = strchr (p, ' ')) && argc < (int) (int) ARRAY_LENGTH (args)) + { + *e++ = '\0'; + while (*e == ' ') + e++; + args[argc++] = p = e; + } + ret |= driver.main (argc, args); + fflush (stdout); + + if (ret) + break; + } + return ret; + } main_font_text_t, FONT_SIZE_UPEM, 0> driver; return driver.main (argc, argv); } diff --git a/util/options.hh b/util/options.hh index f90b22f08..b185ed965 100644 --- a/util/options.hh +++ b/util/options.hh @@ -524,7 +524,7 @@ struct text_options_t : option_group_t g_free (text_file); if (gs) g_string_free (gs, true); - if (fp) + if (fp && fp != stdin) fclose (fp); } @@ -535,7 +535,7 @@ struct text_options_t : option_group_t g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, "Only one of text and text-file can be set"); - }; + } const char *get_line (unsigned int *len); @@ -570,7 +570,7 @@ struct output_options_t : option_group_t { g_free (output_file); g_free (output_format); - if (fp) + if (fp && fp != stdout) fclose (fp); }