diff --git a/.ci/fail.sh b/.ci/fail.sh index 91701d33c..4e0069e3f 100755 --- a/.ci/fail.sh +++ b/.ci/fail.sh @@ -2,11 +2,17 @@ for f in $(find . -name '*.log' -not -name 'config.log'); do last=$(tail -1 $f) - if [[ $last = FAIL* || $last = *failed* ]]; then + if [[ $last = FAIL* ]]; then echo '====' $f '====' cat $f + elif [[ $last = PASS* ]]; then + # Do nothing. + true + else + # Travis Linux images has an old automake that does not match the + # patterns above, so in case of doubt just print the file. + cat $f fi done -# Intentionally exiting with non-zero. exit 1 diff --git a/.circleci/config.yml b/.circleci/config.yml index e30b5b45b..d804afce9 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -37,6 +37,21 @@ jobs: - run: make - run: make check || .ci/fail.sh + clang-O3-O0: + docker: + - image: multiarch/crossbuild + steps: + - checkout + - run: apt update && apt install -y ragel libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python python-pip + - run: pip install fonttools + - run: wget http://download.savannah.gnu.org/releases/freetype/freetype-2.9.tar.bz2 && tar xf freetype-2.9.tar.bz2 && cd freetype-2.9 && ./autogen.sh && ./configure && make -j4 && cd .. + - run: CFLAGS="-O3" CXXFLAGS="-O3" CC=clang CXX=clang++ ./autogen.sh --with-freetype --with-glib --with-cairo --with-icu --with-graphite2 + - run: make + - run: LD_LIBRARY_PATH="$PWD/freetype-2.9/objs/.libs" make check || .ci/fail.sh + - run: CFLAGS="-O0" CXXFLAGS="-O0" CC=clang CXX=clang++ ./autogen.sh --with-freetype --with-glib --with-cairo --with-icu --with-graphite2 + - run: make + - run: LD_LIBRARY_PATH="$PWD/freetype-2.9/objs/.libs" make check || .ci/fail.sh + fedora-outoftreebuild: docker: - image: fedora @@ -153,6 +168,7 @@ workflows: # autotools based builds - alpine-O3 - archlinux-debug-O0 + - clang-O3-O0 - fedora-outoftreebuild # cmake based builds diff --git a/.travis.yml b/.travis.yml index 662fab59b..02accdc94 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,8 +6,8 @@ language: cpp env: global: - CPPFLAGS="" - - CFLAGS="-Werror --coverage" - - CXXFLAGS="-Werror -Wno-deprecated-register --coverage" # glib uses register and clang raises a warning + - CFLAGS="-Werror -Werror=unused-function --coverage" + - CXXFLAGS="-Werror -Werror=unused-function -Wno-deprecated-register --coverage" # glib uses register and clang raises a warning - LDFLAGS="--coverage" - CONFIGURE_OPTS="--with-freetype --with-glib --with-gobject --with-cairo --with-icu --with-graphite2" - NOCONFIGURE=1 diff --git a/CMakeLists.txt b/CMakeLists.txt index 6b4e10899..660da5a1f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -137,7 +137,7 @@ set (IN_HB_DIST FALSE) if (EXISTS "${PROJECT_SOURCE_DIR}/ChangeLog") # perhaps we are on dist directory set (IN_HB_DIST TRUE) - set (HB_VERSION_H "${PROJECT_SOURCE_DIR}/src/hb-version.h") + #set (HB_VERSION_H "${PROJECT_SOURCE_DIR}/src/hb-version.h") endif () @@ -180,13 +180,13 @@ add_prefix_to_list(HB_SUBSET_headers "${PROJECT_SOURCE_DIR}/src/") extract_make_variable(HB_BASE_RAGEL_GENERATED_sources ${SRCSOURCES}) extract_make_variable(HB_OT_RAGEL_GENERATED_sources ${SRCSOURCES}) -if (IN_HB_DIST) +#if (IN_HB_DIST) add_prefix_to_list(HB_BASE_RAGEL_GENERATED_sources "${PROJECT_SOURCE_DIR}/src/") add_prefix_to_list(HB_OT_RAGEL_GENERATED_sources "${PROJECT_SOURCE_DIR}/src/") -else () - add_prefix_to_list(HB_BASE_RAGEL_GENERATED_sources "${PROJECT_BINARY_DIR}/src/") - add_prefix_to_list(HB_OT_RAGEL_GENERATED_sources "${PROJECT_BINARY_DIR}/src/") -endif () +#else () +# add_prefix_to_list(HB_BASE_RAGEL_GENERATED_sources "${PROJECT_BINARY_DIR}/src/") +# add_prefix_to_list(HB_OT_RAGEL_GENERATED_sources "${PROJECT_BINARY_DIR}/src/") +#endif () extract_make_variable(HB_VIEW_sources ${UTILSOURCES}) add_prefix_to_list(HB_VIEW_sources "${PROJECT_SOURCE_DIR}/util/") @@ -234,17 +234,17 @@ endif () ## Generate hb-version.h -if (NOT IN_HB_DIST) - set (HB_VERSION_H_IN "${PROJECT_SOURCE_DIR}/src/hb-version.h.in") - set (HB_VERSION_H "${PROJECT_BINARY_DIR}/src/hb-version.h") - set_source_files_properties("${HB_VERSION_H}" PROPERTIES GENERATED true) - configure_file("${HB_VERSION_H_IN}" "${HB_VERSION_H}.tmp" @ONLY) - execute_process(COMMAND "${CMAKE_COMMAND}" -E copy_if_different - "${HB_VERSION_H}.tmp" - "${HB_VERSION_H}" - ) - file(REMOVE "${HB_VERSION_H}.tmp") -endif () +#if (NOT IN_HB_DIST) +# set (HB_VERSION_H_IN "${PROJECT_SOURCE_DIR}/src/hb-version.h.in") +# set (HB_VERSION_H "${PROJECT_BINARY_DIR}/src/hb-version.h") +# set_source_files_properties("${HB_VERSION_H}" PROPERTIES GENERATED true) +# configure_file("${HB_VERSION_H_IN}" "${HB_VERSION_H}.tmp" @ONLY) +# execute_process(COMMAND "${CMAKE_COMMAND}" -E copy_if_different +# "${HB_VERSION_H}.tmp" +# "${HB_VERSION_H}" +# ) +# file(REMOVE "${HB_VERSION_H}.tmp") +#endif () ## Define sources and headers of the project @@ -264,7 +264,7 @@ set (subset_project_sources set (project_extra_sources) set (project_headers - ${HB_VERSION_H} + #${HB_VERSION_H} ${HB_BASE_headers} ${HB_OT_headers} @@ -809,7 +809,7 @@ endif () ## src/ executables if (NOT HB_DISABLE_TEST_PROGS) - foreach (prog main test test-would-substitute test-size-params test-buffer-serialize hb-ot-tag) + foreach (prog main test test-would-substitute test-size-params test-buffer-serialize hb-ot-tag test-unicode-ranges) set (prog_name ${prog}) if (${prog_name} STREQUAL "test") # test can not be used as a valid executable name on cmake, lets special case it diff --git a/src/Makefile.am b/src/Makefile.am index c4d5fb85b..2871f30f4 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -30,7 +30,6 @@ HBDEPS = HBSOURCES = $(HB_BASE_sources) HBSOURCES += $(HB_BASE_RAGEL_GENERATED_sources) HBHEADERS = $(HB_BASE_headers) -HBNODISTHEADERS = $(HB_NODIST_headers) if WITH_LIBSTDCXX HBNOLIBCXXCFLAGS = @@ -147,13 +146,13 @@ endif base_link_flags = $(AM_LDFLAGS) -lm -version-info $(HB_LIBTOOL_VERSION_INFO) -no-undefined libharfbuzz_la_LINK = $(chosen_linker) $(libharfbuzz_la_LDFLAGS) -libharfbuzz_la_SOURCES = $(HBSOURCES) $(HBHEADERS) $(HBNODISTHEADERS) +libharfbuzz_la_SOURCES = $(HBSOURCES) $(HBHEADERS) libharfbuzz_la_CPPFLAGS = $(HBCFLAGS) $(HBNOLIBCXXFLAGS) libharfbuzz_la_LDFLAGS = $(base_link_flags) $(export_symbols) libharfbuzz_la_LIBADD = $(HBLIBS) EXTRA_libharfbuzz_la_DEPENDENCIES = $(harfbuzz_def_dependency) pkginclude_HEADERS = $(HBHEADERS) -nodist_pkginclude_HEADERS = $(HBNODISTHEADERS) +nodist_pkginclude_HEADERS = pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = harfbuzz.pc cmakedir = $(libdir)/cmake/harfbuzz @@ -382,17 +381,21 @@ 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) -check_PROGRAMS += test-ot-tag -TESTS += test-ot-tag +check_PROGRAMS += test-ot-tag test-unicode-ranges +TESTS += test-ot-tag test-unicode-ranges + test_ot_tag_SOURCES = hb-ot-tag.cc test_ot_tag_CPPFLAGS = $(HBCFLAGS) -DMAIN test_ot_tag_LDADD = libharfbuzz.la $(HBLIBS) +test_unicode_ranges_SOURCES = test-unicode-ranges.cc +test_unicode_ranges_LDADD = libharfbuzz.la $(HBLIBS) + TESTS_ENVIRONMENT = \ srcdir="$(srcdir)" \ MAKE="$(MAKE) $(AM_MAKEFLAGS)" \ HBSOURCES="$(HBSOURCES)" \ - HBHEADERS="$(HBHEADERS) $(HBNODISTHEADERS)" \ + HBHEADERS="$(HBHEADERS)" \ $(NULL) if HAVE_INTROSPECTION @@ -422,7 +425,6 @@ HarfBuzz_0_0_gir_LIBS = \ $(NULL) HarfBuzz_0_0_gir_FILES = \ $(HBHEADERS) \ - $(HBNODISTHEADERS) \ $(HBSOURCES) \ $(HB_GOBJECT_sources) \ $(HB_GOBJECT_headers) \ diff --git a/src/Makefile.sources b/src/Makefile.sources index 2bb56b4f9..b45cd9276 100644 --- a/src/Makefile.sources +++ b/src/Makefile.sources @@ -28,6 +28,7 @@ HB_BASE_sources = \ hb-ot-maxp-table.hh \ hb-ot-name-table.hh \ hb-ot-os2-table.hh \ + hb-ot-os2-unicode-ranges.hh \ hb-ot-post-macroman.hh \ hb-ot-post-table.hh \ hb-ot-tag.cc \ @@ -70,9 +71,6 @@ HB_BASE_headers = \ hb-shape.h \ hb-shape-plan.h \ hb-unicode.h \ - $(NULL) - -HB_NODIST_headers = \ hb-version.h \ $(NULL) @@ -83,12 +81,14 @@ HB_FALLBACK_sources = \ HB_OT_sources = \ hb-aat-layout.cc \ hb-aat-layout-common-private.hh \ - hb-aat-layout-morx-table.hh \ + hb-aat-layout-ankr-table.hh \ hb-aat-layout-kerx-table.hh \ + hb-aat-layout-morx-table.hh \ hb-aat-layout-trak-table.hh \ hb-aat-layout-private.hh \ hb-ot-font.cc \ hb-ot-layout.cc \ + hb-ot-layout-base-table.hh \ hb-ot-layout-common-private.hh \ hb-ot-layout-gdef-table.hh \ hb-ot-layout-gpos-table.hh \ @@ -152,6 +152,7 @@ HB_OT_headers = \ hb-ot-font.h \ hb-ot-layout.h \ hb-ot-math.h \ + hb-ot-base.h \ hb-ot-shape.h \ hb-ot-tag.h \ hb-ot-var.h \ diff --git a/src/dev-run.sh b/src/dev-run.sh index 3b2257b1d..9c82db0b8 100755 --- a/src/dev-run.sh +++ b/src/dev-run.sh @@ -9,14 +9,28 @@ # $ cmake -DHB_CHECK=ON -Bbuild -H. -GNinja && ninja -Cbuild # $ src/dev-run.sh [FONT-FILE] [TEXT] # +# If you are using iTerm2, issue the script like this: +# $ src/dev-run.sh img [FONT-FILE] [TEXT] +# [ $# = 0 ] && echo Usage: "src/dev-run.sh [FONT-FILE] [TEXT]" && exit command -v entr >/dev/null 2>&1 || { echo >&2 "This script needs `entr` be installed"; exit 1; } + GDB=gdb # if gdb doesn't exist, hopefully lldb exist command -v $GDB >/dev/null 2>&1 || export GDB="lldb" + +[ $1 = "img" ] && img=1 && shift +# http://iterm2.com/documentation-images.html +osc="\033]" +if [[ $TERM == screen* ]]; then osc="\033Ptmux;\033\033]"; fi +st="\a" +if [[ $TERM == screen* ]]; then st="\a"; fi + + +tmp=$(mktemp) [ -f 'build/build.ninja' ] && CMAKENINJA=TRUE # or "fswatch -0 . -e build/ -e .git" find src/ | entr printf '\0' | while read -d ""; do @@ -25,19 +39,29 @@ find src/ | entr printf '\0' | while read -d ""; do if [[ $CMAKENINJA ]]; then ninja -Cbuild hb-shape hb-view && { build/hb-shape $@ - build/hb-view $@ + if [ $img ]; then + build/hb-view $@ -O png -o $tmp + printf "\n${osc}1337;File=;inline=1:`cat $tmp | base64`${st}\n" + else + build/hb-view $@ + fi } else make -Cbuild/src -j5 -s lib && { build/util/hb-shape $@ - build/util/hb-view $@ + if [ $img ]; then + build/util/hb-view $@ -O png -o $tmp + printf "\n${osc}1337;File=;inline=1:`cat $tmp | base64`${st}\n" + else + build/util/hb-view $@ + fi } fi done -read -n 1 -p "[T]est, [D]ebug, [R]estart, [Q]uit?" answer +read -n 1 -p "[C]heck, [D]ebug, [R]estart, [Q]uit? " answer case "$answer" in -t|T ) +c|C ) if [[ $CMAKENINJA ]]; then CTEST_OUTPUT_ON_FAILURE=1 CTEST_PARALLEL_LEVEL=5 ninja -Cbuild test else @@ -48,7 +72,7 @@ d|D ) if [[ $CMAKENINJA ]]; then echo "Not supported on cmake builds yet" else - build/libtool --mode=execute $GDB build/util/hb-shape $@ + build/libtool --mode=execute $GDB -- build/util/hb-shape $@ fi ;; r|R ) diff --git a/src/gen-unicode-ranges.py b/src/gen-unicode-ranges.py new file mode 100644 index 000000000..3b59cd862 --- /dev/null +++ b/src/gen-unicode-ranges.py @@ -0,0 +1,52 @@ +# -*- coding: utf-8 -*- + +# Generates the code for a sorted unicode range array as used in hb-ot-os2-unicode-ranges.hh +# Input is a tab seperated list of unicode ranges from the otspec +# (https://docs.microsoft.com/en-us/typography/opentype/spec/os2#ulunicoderange1). + +import io +import re +import sys + +reload(sys) +sys.setdefaultencoding('utf-8') + +print (u"""static Range os2UnicodeRangesSorted[] = +{""") + +args = sys.argv[1:] +input_file = args[0] + +with io.open(input_file, mode="r", encoding="utf-8") as f: + + all_ranges = []; + current_bit = 0 + while True: + line = f.readline().strip() + if not line: + break + fields = re.split(r'\t+', line) + if len(fields) == 3: + current_bit = fields[0] + fields = fields[1:] + elif len(fields) > 3: + raise Error("bad input :(.") + + name = fields[0] + ranges = re.split("-", fields[1]) + if len(ranges) != 2: + raise Error("bad input :(.") + + v = tuple((int(ranges[0], 16), int(ranges[1], 16), int(current_bit), name)) + all_ranges.append(v) + +all_ranges = sorted(all_ranges, key=lambda t: t[0]) + +for ranges in all_ranges: + start = ("0x%X" % ranges[0]).rjust(8) + end = ("0x%X" % ranges[1]).rjust(8) + bit = ("%s" % ranges[2]).rjust(3) + + print " {%s, %s, %s}, // %s" % (start, end, bit, ranges[3]) + +print (u"""};"""); diff --git a/src/hb-aat-layout-ankr-table.hh b/src/hb-aat-layout-ankr-table.hh new file mode 100644 index 000000000..d0453bd88 --- /dev/null +++ b/src/hb-aat-layout-ankr-table.hh @@ -0,0 +1,80 @@ +/* + * Copyright © 2018 Ebrahim Byagowi + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ + +#ifndef HB_AAT_LAYOUT_ANKR_TABLE_HH +#define HB_AAT_LAYOUT_ANKR_TABLE_HH + +#include "hb-aat-layout-common-private.hh" + +#define HB_AAT_TAG_ankr HB_TAG('a','n','k','r') + + +namespace AAT { + + +/* + * ankr -- Anchor point + */ + +struct Anchor +{ + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this)); + } + + FWORD xCoordinate; + FWORD yCoordinate; + public: + DEFINE_SIZE_STATIC (4); +}; + +struct ankr +{ + static const hb_tag_t tableTag = HB_AAT_TAG_ankr; + + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && version == 0 && + lookupTable.sanitize (c, this) && + anchors.sanitize (c, this)); + } + + protected: + HBUINT16 version; /* Version number (set to zero) */ + HBUINT16 flags; /* Flags (currently unused; set to zero) */ + LOffsetTo > lookupTable; /* Offset to the table's lookup table */ + LOffsetTo > + anchors; /* Offset to the glyph data table */ + + public: + DEFINE_SIZE_STATIC (12); +}; + +} /* namespace AAT */ + + +#endif /* HB_AAT_LAYOUT_ANKR_TABLE_HH */ diff --git a/src/hb-aat-layout-kerx-table.hh b/src/hb-aat-layout-kerx-table.hh index b061f11d2..505e5084b 100644 --- a/src/hb-aat-layout-kerx-table.hh +++ b/src/hb-aat-layout-kerx-table.hh @@ -263,6 +263,13 @@ struct kerx { static const hb_tag_t tableTag = HB_AAT_TAG_kerx; + inline bool apply (hb_aat_apply_context_t *c, const AAT::ankr *ankr) const + { + TRACE_APPLY (this); + /* TODO */ + return_trace (false); + } + struct SubTableWrapper { enum coverage_flags_t { diff --git a/src/hb-aat-layout-private.hh b/src/hb-aat-layout-private.hh index c1c607a2f..ce75c8e71 100644 --- a/src/hb-aat-layout-private.hh +++ b/src/hb-aat-layout-private.hh @@ -37,4 +37,7 @@ HB_INTERNAL void hb_aat_layout_substitute (hb_font_t *font, hb_buffer_t *buffer); +HB_INTERNAL void +hb_aat_layout_position (hb_font_t *font, hb_buffer_t *buffer); + #endif /* HB_AAT_LAYOUT_PRIVATE_HH */ diff --git a/src/hb-aat-layout-trak-table.hh b/src/hb-aat-layout-trak-table.hh index 6dbd05ab5..5767b116c 100644 --- a/src/hb-aat-layout-trak-table.hh +++ b/src/hb-aat-layout-trak-table.hh @@ -1,6 +1,6 @@ /* - * Copyright © 2018 Google, Inc. * Copyright © 2018 Ebrahim Byagowi + * Copyright © 2018 Google, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -39,16 +39,26 @@ namespace AAT { struct TrackTableEntry { - inline bool sanitize (hb_sanitize_context_t *c) const + inline bool sanitize (hb_sanitize_context_t *c, const void *base, unsigned int size) const { TRACE_SANITIZE (this); - return_trace (c->check_struct (this)); + return_trace (c->check_struct (this) && (values.sanitize (c, base, size))); + } + + inline float get_track_value () const + { + return track.to_float (); + } + + inline int get_value (const void *base, unsigned int index) const + { + return (base+values)[index]; } protected: Fixed track; /* Track value for this record. */ HBUINT16 trackNameID; /* The 'name' table index for this track */ - OffsetTo > + OffsetTo > values; /* Offset from start of tracking table to * per-size tracking values for this track. */ @@ -58,18 +68,66 @@ struct TrackTableEntry struct TrackData { - inline bool sanitize (hb_sanitize_context_t *c) const + inline bool sanitize (hb_sanitize_context_t *c, const void *base) const { TRACE_SANITIZE (this); - return_trace (c->check_struct (this)); + return_trace (c->check_struct (this) && + sizeTable.sanitize (c, base, nSizes) && + trackTable.sanitize (c, nTracks, base, nSizes)); + } + + inline float get_tracking (const void *base, float ptem) const + { + /* CoreText points are CSS pixels (96 per inch), + * NOT typographic points (72 per inch). + * + * https://developer.apple.com/library/content/documentation/GraphicsAnimation/Conceptual/HighResolutionOSX/Explained/Explained.html + */ + float csspx = ptem * 96.f / 72.f; + Fixed fixed_size; + fixed_size.set_float (csspx); + + /* XXX Clean this up. Make it work with nSizes==1 and 0. */ + + unsigned int sizes = nSizes; + + const TrackTableEntry *trackTableEntry = nullptr; + for (unsigned int i = 0; i < sizes; ++i) + // For now we only seek for track entries with zero tracking value + if (trackTable[i].get_track_value () == 0.) + trackTableEntry = &trackTable[0]; + + // We couldn't match any, exit + if (!trackTableEntry) return 0.; + + /* TODO bfind() */ + unsigned int size_index; + UnsizedArrayOf size_table = base+sizeTable; + for (size_index = 0; size_index < sizes; ++size_index) + if (size_table[size_index] >= fixed_size) + break; + + // TODO(ebraminio): We don't attempt to extrapolate to larger or + // smaller values for now but we should do, per spec + if (size_index == sizes) + return trackTableEntry->get_value (base, sizes - 1); + if (size_index == 0 || size_table[size_index] == fixed_size) + return trackTableEntry->get_value (base, size_index); + + float s0 = size_table[size_index - 1].to_float (); + float s1 = size_table[size_index].to_float (); + float t = (csspx - s0) / (s1 - s0); + return t * trackTableEntry->get_value (base, size_index) + + (1.0 - t) * trackTableEntry->get_value (base, size_index - 1); } protected: HBUINT16 nTracks; /* Number of separate tracks included in this table. */ HBUINT16 nSizes; /* Number of point sizes included in this table. */ - LOffsetTo > + LOffsetTo > /* Offset to array[nSizes] of size values. */ sizeTable; - TrackTableEntry trackTable[VAR];/* Array[nSizes] of size values. */ + UnsizedArrayOf + trackTable; /* Array[nTracks] of TrackTableEntry records. */ public: DEFINE_SIZE_ARRAY (8, trackTable); @@ -82,15 +140,55 @@ struct trak inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return_trace (c->check_struct (this)); + + return_trace (c->check_struct (this) && + horizData.sanitize (c, this, this) && + vertData.sanitize (c, this, this)); + } + + inline bool apply (hb_aat_apply_context_t *c) const + { + TRACE_APPLY (this); + + const float ptem = c->font->ptem; + if (ptem <= 0.f) + return_trace (false); + + hb_buffer_t *buffer = c->buffer; + if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction)) + { + const TrackData &trackData = this+horizData; + float tracking = trackData.get_tracking (this, ptem); + hb_position_t advance_to_add = c->font->em_scalef_x (tracking / 2); + foreach_grapheme (buffer, start, end) + { + /* TODO This is wrong. */ + buffer->pos[start].x_advance += advance_to_add; + buffer->pos[end].x_advance += advance_to_add; + } + } + else + { + const TrackData &trackData = this+vertData; + float tracking = trackData.get_tracking (this, ptem); + hb_position_t advance_to_add = c->font->em_scalef_y (tracking / 2); + foreach_grapheme (buffer, start, end) + { + /* TODO This is wrong. */ + buffer->pos[start].y_advance += advance_to_add; + buffer->pos[end].y_advance += advance_to_add; + } + } + + return_trace (true); } protected: FixedVersion<> version; /* Version of the tracking table--currently * 0x00010000u for version 1.0. */ HBUINT16 format; /* Format of the tracking table */ - OffsetTo horizOffset; /* TrackData for horizontal text */ - OffsetTo vertOffset; /* TrackData for vertical text */ + OffsetTo horizData; /* TrackData for horizontal text */ + OffsetTo vertData; /* TrackData for vertical text */ HBUINT16 reserved; /* Reserved. Set to 0. */ public: diff --git a/src/hb-aat-layout.cc b/src/hb-aat-layout.cc index 3b967c6b7..45268e3e7 100644 --- a/src/hb-aat-layout.cc +++ b/src/hb-aat-layout.cc @@ -30,14 +30,48 @@ #include "hb-ot-layout-gsubgpos-private.hh" #include "hb-aat-layout-private.hh" -#include "hb-aat-layout-morx-table.hh" +#include "hb-aat-layout-ankr-table.hh" #include "hb-aat-layout-kerx-table.hh" +#include "hb-aat-layout-morx-table.hh" #include "hb-aat-layout-trak-table.hh" /* - * mort/morx + * morx/kerx/trak */ +static inline const AAT::ankr& +_get_ankr (hb_face_t *face, hb_blob_t **blob = nullptr) +{ + if (unlikely (!hb_ot_shaper_face_data_ensure (face))) + { + if (blob) + *blob = hb_blob_get_empty (); + return OT::Null(AAT::ankr); + } + hb_ot_layout_t * layout = hb_ot_layout_from_face (face); + const AAT::ankr& ankr = *(layout->ankr.get ()); + if (blob) + *blob = layout->ankr.blob; + return ankr; +} + +static inline const AAT::kerx& +_get_kerx (hb_face_t *face, hb_blob_t **blob = nullptr) +{ + if (unlikely (!hb_ot_shaper_face_data_ensure (face))) + { + if (blob) + *blob = hb_blob_get_empty (); + return OT::Null(AAT::kerx); + } + hb_ot_layout_t * layout = hb_ot_layout_from_face (face); + /* XXX this doesn't call set_num_glyphs on sanitizer. */ + const AAT::kerx& kerx = *(layout->kerx.get ()); + if (blob) + *blob = layout->kerx.blob; + return kerx; +} + static inline const AAT::morx& _get_morx (hb_face_t *face, hb_blob_t **blob = nullptr) { @@ -55,20 +89,36 @@ _get_morx (hb_face_t *face, hb_blob_t **blob = nullptr) return morx; } -static inline void -_hb_aat_layout_create (hb_face_t *face) +static inline const AAT::trak& +_get_trak (hb_face_t *face, hb_blob_t **blob = nullptr) { - OT::Sanitizer sanitizer; - sanitizer.set_num_glyphs (face->get_num_glyphs ()); - hb_blob_t *morx_blob = sanitizer.sanitize (face->reference_table (HB_AAT_TAG_MORX)); - OT::Sanitizer::lock_instance (morx_blob); - - if (0) + if (unlikely (!hb_ot_shaper_face_data_ensure (face))) { - OT::Sanitizer >::lock_instance (morx_blob)->get_value (1, face->get_num_glyphs ()); + if (blob) + *blob = hb_blob_get_empty (); + return OT::Null(AAT::trak); } + hb_ot_layout_t * layout = hb_ot_layout_from_face (face); + const AAT::trak& trak = *(layout->trak.get ()); + if (blob) + *blob = layout->trak.blob; + return trak; } +// static inline void +// _hb_aat_layout_create (hb_face_t *face) +// { +// OT::Sanitizer sanitizer; +// sanitizer.set_num_glyphs (face->get_num_glyphs ()); +// hb_blob_t *morx_blob = sanitizer.sanitize (face->reference_table (HB_AAT_TAG_MORX)); +// OT::Sanitizer::lock_instance (morx_blob); + +// if (0) +// { +// OT::Sanitizer >::lock_instance (morx_blob)->get_value (1, face->get_num_glyphs ()); +// } +// } + void hb_aat_layout_substitute (hb_font_t *font, hb_buffer_t *buffer) { @@ -78,3 +128,16 @@ hb_aat_layout_substitute (hb_font_t *font, hb_buffer_t *buffer) AAT::hb_aat_apply_context_t c (font, buffer, blob); morx.apply (&c); } + +void +hb_aat_layout_position (hb_font_t *font, hb_buffer_t *buffer) +{ + hb_blob_t *blob; + const AAT::ankr& ankr = _get_ankr (font->face, &blob); + const AAT::kerx& kerx = _get_kerx (font->face, &blob); + const AAT::trak& trak = _get_trak (font->face, &blob); + + AAT::hb_aat_apply_context_t c (font, buffer, blob); + kerx.apply (&c, &ankr); + trak.apply (&c); +} diff --git a/src/hb-open-type-private.hh b/src/hb-open-type-private.hh index f5c20bcb6..5d33199e1 100644 --- a/src/hb-open-type-private.hh +++ b/src/hb-open-type-private.hh @@ -692,8 +692,8 @@ struct F2DOT14 : HBINT16 /* 32-bit signed fixed-point number (16.16). */ struct Fixed: HBINT32 { - //inline float to_float (void) const { return ???; } - //inline void set_float (float f) { v.set (f * ???); } + inline float to_float (void) const { return ((int32_t) v) / 65536.0; } + inline void set_float (float f) { v.set (round (f * 65536.0)); } public: DEFINE_SIZE_STATIC (4); }; @@ -740,8 +740,6 @@ template struct Offset : Type { inline bool is_null (void) const { return 0 == *this; } - public: - DEFINE_SIZE_STATIC (sizeof(Type)); inline void *serialize (hb_serialize_context_t *c, const void *base) { @@ -749,6 +747,9 @@ struct Offset : Type this->set ((char *) t - (char *) base); /* TODO(serialize) Overflow? */ return t; } + + public: + DEFINE_SIZE_STATIC (sizeof(Type)); }; typedef Offset Offset16; diff --git a/src/hb-ot-base.h b/src/hb-ot-base.h new file mode 100644 index 000000000..0437c1689 --- /dev/null +++ b/src/hb-ot-base.h @@ -0,0 +1,56 @@ +/* + * Copyright © 2017 Elie Roux + * + * 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. + * + */ + +#ifndef HB_OT_H_IN +#error "Include instead." +#endif + +#ifndef HB_OT_BASE_H +#define HB_OT_BASE_H + +#include "hb.h" + +HB_BEGIN_DECLS + +#define HB_OT_TAG_BASE HB_TAG('B','A','S','E') + +// https://www.microsoft.com/typography/otspec/baselinetags.htm + +#define HB_OT_TAG_BASE_HANG HB_TAG('h','a','n','g') +#define HB_OT_TAG_BASE_ICFB HB_TAG('i','c','f','b') +#define HB_OT_TAG_BASE_ICFT HB_TAG('i','c','f','t') +#define HB_OT_TAG_BASE_IDEO HB_TAG('i','d','e','o') +#define HB_OT_TAG_BASE_IDTB HB_TAG('i','d','t','b') +#define HB_OT_TAG_BASE_MATH HB_TAG('m','a','t','h') +#define HB_OT_TAG_BASE_ROMN HB_TAG('r','o','m','n') + +/* Methods */ + +// HB_EXTERN hb_bool_t +// hb_ot_base_has_data (hb_face_t *face); + +HB_END_DECLS + +#endif /* HB_OT_BASE_H */ diff --git a/src/hb-ot-layout-base-table.hh b/src/hb-ot-layout-base-table.hh new file mode 100644 index 000000000..811ef4020 --- /dev/null +++ b/src/hb-ot-layout-base-table.hh @@ -0,0 +1,656 @@ +/* + * Copyright © 2016 Elie Roux + * 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_LAYOUT_BASE_TABLE_HH +#define HB_OT_LAYOUT_BASE_TABLE_HH + +#include "hb-open-type-private.hh" +#include "hb-ot-layout-common-private.hh" +#include "hb-ot-base.h" + +namespace OT { + +#define NOT_INDEXED ((unsigned int) -1) + +/* + * BASE -- The BASE Table + */ + +struct BaseCoordFormat1 +{ + inline int get_coord (void) const { return coordinate; } + + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this)); + } + + protected: + HBUINT16 format; /* Format identifier--format = 1 */ + HBINT16 coordinate; /* X or Y value, in design units */ + public: + DEFINE_SIZE_STATIC (4); +}; + +struct BaseCoordFormat2 +{ + inline int get_coord (void) const + { + /* TODO */ + return coordinate; + } + + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this)); + } + + protected: + HBUINT16 format; /* Format identifier--format = 2 */ + HBINT16 coordinate; /* X or Y value, in design units */ + GlyphID referenceGlyph; /* Glyph ID of control glyph */ + HBUINT16 coordPoint; /* Index of contour point on the + * reference glyph */ + public: + DEFINE_SIZE_STATIC (8); +}; + +struct BaseCoordFormat3 +{ + inline int get_coord (void) const + { + /* TODO */ + return coordinate; + } + + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && deviceTable.sanitize (c, this)); + } + + protected: + HBUINT16 format; /* Format identifier--format = 3 */ + HBINT16 coordinate; /* X or Y value, in design units */ + OffsetTo deviceTable; /* Offset to Device table for X or + * Y value, from beginning of + * BaseCoord table (may be NULL). */ + public: + DEFINE_SIZE_STATIC (6); +}; + +struct BaseCoord +{ + inline int get_coord (void) const + { + switch (u.format) { + case 1: return u.format1.get_coord (); + case 2: return u.format2.get_coord (); + case 3: return u.format3.get_coord (); + default:return 0; + } + } + + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + if (!u.format.sanitize (c)) return_trace (false); + switch (u.format) { + case 1: return_trace (u.format1.sanitize (c)); + case 2: return_trace (u.format2.sanitize (c)); + case 3: return_trace (u.format3.sanitize (c)); + default:return_trace (false); + } + } + + protected: + union { + HBUINT16 format; + BaseCoordFormat1 format1; + BaseCoordFormat2 format2; + BaseCoordFormat3 format3; + } u; + public: + DEFINE_SIZE_UNION (2, format); +}; + +struct FeatMinMaxRecord +{ + inline int get_min_value (void) const + { return (this+minCoord).get_coord(); } + + inline int get_max_value (void) const + { return (this+maxCoord).get_coord(); } + + inline const Tag &get_tag () const + { return tag; } + + inline bool sanitize (hb_sanitize_context_t *c, const void *base) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && + minCoord.sanitize (c, base) && + maxCoord.sanitize (c, base)); + } + + protected: + Tag tag; /* 4-byte feature identification tag--must + * match feature tag in FeatureList */ + OffsetTo minCoord; /* Offset to BaseCoord table that defines + * the minimum extent value, from beginning + * of MinMax table (may be NULL) */ + OffsetTo maxCoord; /* Offset to BaseCoord table that defines + * the maximum extent value, from beginning + * of MinMax table (may be NULL) */ + public: + DEFINE_SIZE_STATIC (8); + +}; + +struct MinMax +{ + inline unsigned int get_feature_tag_index (Tag featureTableTag) const + { + /* TODO bsearch */ + unsigned int count = featMinMaxRecords.len; + for (unsigned int i = 0; i < count; i++) + { + Tag tag = featMinMaxRecords[i].get_tag(); + int cmp = tag.cmp(featureTableTag); + if (cmp == 0) return i; + if (cmp > 0) return NOT_INDEXED; + } + return NOT_INDEXED; + } + + inline int get_min_value (unsigned int featureTableTagIndex) const + { + if (featureTableTagIndex == NOT_INDEXED) + return (this+minCoord).get_coord(); + return featMinMaxRecords[featureTableTagIndex].get_min_value(); + } + + inline int get_max_value (unsigned int featureTableTagIndex) const + { + if (featureTableTagIndex == NOT_INDEXED) + return (this+maxCoord).get_coord(); + return featMinMaxRecords[featureTableTagIndex].get_max_value(); + } + + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && + minCoord.sanitize (c, this) && + maxCoord.sanitize (c, this) && + featMinMaxRecords.sanitize (c, this)); + } + + protected: + OffsetTo minCoord; /* Offset to BaseCoord table that defines + * minimum extent value, from the beginning + * of MinMax table (may be NULL) */ + OffsetTo maxCoord; /* Offset to BaseCoord table that defines + * maximum extent value, from the beginning + * of MinMax table (may be NULL) */ + ArrayOf + featMinMaxRecords; /* Array of FeatMinMaxRecords, in alphabetical + * order by featureTableTag */ + public: + DEFINE_SIZE_ARRAY (6, featMinMaxRecords); +}; + +/* TODO... */ +struct BaseLangSysRecord +{ + inline const Tag& get_tag(void) const + { return baseLangSysTag; } + + inline unsigned int get_feature_tag_index (Tag featureTableTag) const + { return (this+minMax).get_feature_tag_index(featureTableTag); } + + inline int get_min_value (unsigned int featureTableTagIndex) const + { return (this+minMax).get_min_value(featureTableTagIndex); } + + inline int get_max_value (unsigned int featureTableTagIndex) const + { return (this+minMax).get_max_value(featureTableTagIndex); } + + inline bool sanitize (hb_sanitize_context_t *c, const void *base) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && + minMax.sanitize (c, base)); + } + + protected: + Tag baseLangSysTag; + OffsetTo minMax; + public: + DEFINE_SIZE_STATIC (6); + +}; + +struct BaseValues +{ + inline unsigned int get_default_base_tag_index (void) const + { return defaultIndex; } + + inline int get_base_coord (unsigned int baselineTagIndex) const + { + return (this+baseCoords[baselineTagIndex]).get_coord(); + } + + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && + defaultIndex <= baseCoordCount && + baseCoords.sanitize (c, this)); + } + + protected: + Index defaultIndex; + HBUINT16 baseCoordCount; + OffsetArrayOf baseCoords; + public: + DEFINE_SIZE_ARRAY (6, baseCoords); + +}; + +struct BaseScript { + + inline unsigned int get_lang_tag_index (Tag baseLangSysTag) const + { + Tag tag; + int cmp; + for (unsigned int i = 0; i < baseLangSysCount; i++) { + tag = baseLangSysRecords[i].get_tag(); + // taking advantage of alphabetical order + cmp = tag.cmp(baseLangSysTag); + if (cmp == 0) return i; + if (cmp > 0) return NOT_INDEXED; + } + return NOT_INDEXED; + } + + inline unsigned int get_feature_tag_index (unsigned int baseLangSysIndex, Tag featureTableTag) const + { + if (baseLangSysIndex == NOT_INDEXED) { + if (unlikely(defaultMinMax)) return NOT_INDEXED; + return (this+defaultMinMax).get_feature_tag_index(featureTableTag); + } + if (unlikely(baseLangSysIndex >= baseLangSysCount)) return NOT_INDEXED; + return baseLangSysRecords[baseLangSysIndex].get_feature_tag_index(featureTableTag); + } + + inline int get_min_value (unsigned int baseLangSysIndex, unsigned int featureTableTagIndex) const + { + if (baseLangSysIndex == NOT_INDEXED) + return (this+defaultMinMax).get_min_value(featureTableTagIndex); + return baseLangSysRecords[baseLangSysIndex].get_max_value(featureTableTagIndex); + } + + inline int get_max_value (unsigned int baseLangSysIndex, unsigned int featureTableTagIndex) const + { + if (baseLangSysIndex == NOT_INDEXED) + return (this+defaultMinMax).get_min_value(featureTableTagIndex); + return baseLangSysRecords[baseLangSysIndex].get_max_value(featureTableTagIndex); + } + + inline unsigned int get_default_base_tag_index (void) const + { return (this+baseValues).get_default_base_tag_index(); } + + inline int get_base_coord (unsigned int baselineTagIndex) const + { return (this+baseValues).get_base_coord(baselineTagIndex); } + + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && + baseValues.sanitize (c, this) && + defaultMinMax.sanitize (c, this) && + baseLangSysRecords.sanitize (c, this)); + } + + protected: + OffsetTo baseValues; + OffsetTo defaultMinMax; + HBUINT16 baseLangSysCount; + ArrayOf baseLangSysRecords; + + public: + DEFINE_SIZE_ARRAY (8, baseLangSysRecords); +}; + + +struct BaseScriptRecord { + + inline const Tag& get_tag (void) const + { return baseScriptTag; } + + inline unsigned int get_default_base_tag_index(void) const + { return (this+baseScript).get_default_base_tag_index(); } + + inline int get_base_coord(unsigned int baselineTagIndex) const + { return (this+baseScript).get_base_coord(baselineTagIndex); } + + inline unsigned int get_lang_tag_index (Tag baseLangSysTag) const + { return (this+baseScript).get_lang_tag_index(baseLangSysTag); } + + inline unsigned int get_feature_tag_index (unsigned int baseLangSysIndex, Tag featureTableTag) const + { return (this+baseScript).get_feature_tag_index(baseLangSysIndex, featureTableTag); } + + inline int get_max_value (unsigned int baseLangSysIndex, unsigned int featureTableTagIndex) const + { return (this+baseScript).get_max_value(baseLangSysIndex, featureTableTagIndex); } + + inline int get_min_value (unsigned int baseLangSysIndex, unsigned int featureTableTagIndex) const + { return (this+baseScript).get_min_value(baseLangSysIndex, featureTableTagIndex); } + + inline bool sanitize (hb_sanitize_context_t *c, const void *base) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && + baseScript != Null(OffsetTo) && + baseScript.sanitize (c, base)); + } + + protected: + Tag baseScriptTag; + OffsetTo baseScript; + + public: + DEFINE_SIZE_STATIC (6); +}; + +struct BaseScriptList { + + inline unsigned int get_base_script_index (Tag baseScriptTag) const + { + for (unsigned int i = 0; i < baseScriptCount; i++) + if (baseScriptRecords[i].get_tag() == baseScriptTag) + return i; + return NOT_INDEXED; + } + + inline unsigned int get_default_base_tag_index (unsigned int baseScriptIndex) const + { + if (unlikely(baseScriptIndex >= baseScriptCount)) return NOT_INDEXED; + return baseScriptRecords[baseScriptIndex].get_default_base_tag_index(); + } + + inline int get_base_coord(unsigned int baseScriptIndex, unsigned int baselineTagIndex) const + { + return baseScriptRecords[baseScriptIndex].get_base_coord(baselineTagIndex); + } + + inline unsigned int get_lang_tag_index (unsigned int baseScriptIndex, Tag baseLangSysTag) const + { + if (unlikely(baseScriptIndex >= baseScriptCount)) return NOT_INDEXED; + return baseScriptRecords[baseScriptIndex].get_lang_tag_index(baseLangSysTag); + } + + inline unsigned int get_feature_tag_index (unsigned int baseScriptIndex, unsigned int baseLangSysIndex, Tag featureTableTag) const + { + if (unlikely(baseScriptIndex >= baseScriptCount)) return NOT_INDEXED; + return baseScriptRecords[baseScriptIndex].get_feature_tag_index(baseLangSysIndex, featureTableTag); + } + + inline int get_max_value (unsigned int baseScriptIndex, unsigned int baseLangSysIndex, unsigned int featureTableTagIndex) const + { + return baseScriptRecords[baseScriptIndex].get_max_value(baseLangSysIndex, featureTableTagIndex); + } + + inline int get_min_value (unsigned int baseScriptIndex, unsigned int baseLangSysIndex, unsigned int featureTableTagIndex) const + { + return baseScriptRecords[baseScriptIndex].get_min_value(baseLangSysIndex, featureTableTagIndex); + } + + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && + baseScriptRecords.sanitize (c, this)); + } + + protected: + HBUINT16 baseScriptCount; + ArrayOf baseScriptRecords; + + public: + DEFINE_SIZE_ARRAY (4, baseScriptRecords); + +}; + +struct BaseTagList +{ + + inline unsigned int get_tag_index(Tag baselineTag) const + { + for (unsigned int i = 0; i < baseTagCount; i++) + if (baselineTags[i] == baselineTag) + return i; + return NOT_INDEXED; + } + + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this)); + } + + protected: + HBUINT16 baseTagCount; + SortedArrayOf baselineTags; + + public: + DEFINE_SIZE_ARRAY (4, baselineTags); +}; + +struct Axis +{ + + inline unsigned int get_base_tag_index(Tag baselineTag) const + { + if (unlikely(baseTagList == Null(OffsetTo))) return NOT_INDEXED; + return (this+baseTagList).get_tag_index(baselineTag); + } + + inline unsigned int get_default_base_tag_index_for_script_index (unsigned int baseScriptIndex) const + { + if (unlikely(baseScriptList == Null(OffsetTo))) return NOT_INDEXED; + return (this+baseScriptList).get_default_base_tag_index(baseScriptIndex); + } + + inline int get_base_coord(unsigned int baseScriptIndex, unsigned int baselineTagIndex) const + { + return (this+baseScriptList).get_base_coord(baseScriptIndex, baselineTagIndex); + } + + inline unsigned int get_lang_tag_index (unsigned int baseScriptIndex, Tag baseLangSysTag) const + { + if (unlikely(baseScriptList == Null(OffsetTo))) return NOT_INDEXED; + return (this+baseScriptList).get_lang_tag_index(baseScriptIndex, baseLangSysTag); + } + + inline unsigned int get_feature_tag_index (unsigned int baseScriptIndex, unsigned int baseLangSysIndex, Tag featureTableTag) const + { + if (unlikely(baseScriptList == Null(OffsetTo))) return NOT_INDEXED; + return (this+baseScriptList).get_feature_tag_index(baseScriptIndex, baseLangSysIndex, featureTableTag); + } + + inline int get_max_value (unsigned int baseScriptIndex, unsigned int baseLangSysIndex, unsigned int featureTableTagIndex) const + { + return (this+baseScriptList).get_max_value(baseScriptIndex, baseLangSysIndex, featureTableTagIndex); + } + + inline int get_min_value (unsigned int baseScriptIndex, unsigned int baseLangSysIndex, unsigned int featureTableTagIndex) const + { + return (this+baseScriptList).get_min_value(baseScriptIndex, baseLangSysIndex, featureTableTagIndex); + } + + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && + baseTagList.sanitize (c, this) && + baseScriptList.sanitize (c, this)); + } + + protected: + OffsetTo baseTagList; + OffsetTo baseScriptList; + + public: + DEFINE_SIZE_STATIC (4); +}; + +struct BASE +{ + static const hb_tag_t tableTag = HB_OT_TAG_BASE; + + inline bool has_vert_axis(void) + { return vertAxis != Null(OffsetTo); } + + inline bool has_horiz_axis(void) + { return horizAxis != Null(OffsetTo); } + + // horizontal axis base coords: + + inline unsigned int get_horiz_base_tag_index(Tag baselineTag) const + { + if (unlikely(horizAxis == Null(OffsetTo))) return NOT_INDEXED; + return (this+horizAxis).get_base_tag_index(baselineTag); + } + + inline unsigned int get_horiz_default_base_tag_index_for_script_index (unsigned int baseScriptIndex) const + { + if (unlikely(horizAxis == Null(OffsetTo))) return NOT_INDEXED; + return (this+horizAxis).get_default_base_tag_index_for_script_index(baseScriptIndex); + } + + inline int get_horiz_base_coord(unsigned int baseScriptIndex, unsigned int baselineTagIndex) const + { + return (this+horizAxis).get_base_coord(baseScriptIndex, baselineTagIndex); + } + + // vertical axis base coords: + + inline unsigned int get_vert_base_tag_index(Tag baselineTag) const + { + if (unlikely(vertAxis == Null(OffsetTo))) return NOT_INDEXED; + return (this+vertAxis).get_base_tag_index(baselineTag); + } + + inline unsigned int get_vert_default_base_tag_index_for_script_index (unsigned int baseScriptIndex) const + { + if (unlikely(vertAxis == Null(OffsetTo))) return NOT_INDEXED; + return (this+vertAxis).get_default_base_tag_index_for_script_index(baseScriptIndex); + } + + inline int get_vert_base_coord(unsigned int baseScriptIndex, unsigned int baselineTagIndex) const + { + return (this+vertAxis).get_base_coord(baseScriptIndex, baselineTagIndex); + } + + // horizontal axis min/max coords: + + inline unsigned int get_horiz_lang_tag_index (unsigned int baseScriptIndex, Tag baseLangSysTag) const + { + if (unlikely(horizAxis == Null(OffsetTo))) return NOT_INDEXED; + return (this+horizAxis).get_lang_tag_index (baseScriptIndex, baseLangSysTag); + } + + inline unsigned int get_horiz_feature_tag_index (unsigned int baseScriptIndex, unsigned int baseLangSysIndex, Tag featureTableTag) const + { + if (unlikely(horizAxis == Null(OffsetTo))) return NOT_INDEXED; + return (this+horizAxis).get_feature_tag_index (baseScriptIndex, baseLangSysIndex, featureTableTag); + } + + inline int get_horiz_max_value (unsigned int baseScriptIndex, unsigned int baseLangSysIndex, unsigned int featureTableTagIndex) const + { + return (this+horizAxis).get_max_value (baseScriptIndex, baseLangSysIndex, featureTableTagIndex); + } + + inline int get_horiz_min_value (unsigned int baseScriptIndex, unsigned int baseLangSysIndex, unsigned int featureTableTagIndex) const + { + return (this+horizAxis).get_min_value (baseScriptIndex, baseLangSysIndex, featureTableTagIndex); + } + + // vertical axis min/max coords: + + inline unsigned int get_vert_lang_tag_index (unsigned int baseScriptIndex, Tag baseLangSysTag) const + { + if (unlikely(vertAxis == Null(OffsetTo))) return NOT_INDEXED; + return (this+vertAxis).get_lang_tag_index (baseScriptIndex, baseLangSysTag); + } + + inline unsigned int get_vert_feature_tag_index (unsigned int baseScriptIndex, unsigned int baseLangSysIndex, Tag featureTableTag) const + { + if (unlikely(vertAxis == Null(OffsetTo))) return NOT_INDEXED; + return (this+vertAxis).get_feature_tag_index (baseScriptIndex, baseLangSysIndex, featureTableTag); + } + + inline int get_vert_max_value (unsigned int baseScriptIndex, unsigned int baseLangSysIndex, unsigned int featureTableTagIndex) const + { + return (this+vertAxis).get_max_value (baseScriptIndex, baseLangSysIndex, featureTableTagIndex); + } + + inline int get_vert_min_value (unsigned int baseScriptIndex, unsigned int baseLangSysIndex, unsigned int featureTableTagIndex) const + { + return (this+vertAxis).get_min_value (baseScriptIndex, baseLangSysIndex, featureTableTagIndex); + } + + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && + likely (version.major == 1) && + horizAxis.sanitize (c, this) && + vertAxis.sanitize (c, this) && + (version.to_int () < 0x00010001u || varStore.sanitize (c, this))); + } + + protected: + FixedVersion<> version; + OffsetTo horizAxis; + OffsetTo vertAxis; + LOffsetTo + varStore; /* Offset to the table of Item Variation + * Store--from beginning of BASE + * header (may be NULL). Introduced + * in version 0x00010001. */ + public: + DEFINE_SIZE_MIN (8); +}; + + +} /* namespace OT */ + + +#endif /* HB_OT_LAYOUT_BASE_TABLE_HH */ diff --git a/src/hb-ot-layout-gdef-table.hh b/src/hb-ot-layout-gdef-table.hh index aad7d6029..2d6c66e6c 100644 --- a/src/hb-ot-layout-gdef-table.hh +++ b/src/hb-ot-layout-gdef-table.hh @@ -110,7 +110,7 @@ struct CaretValueFormat1 protected: HBUINT16 caretValueFormat; /* Format identifier--format = 1 */ - HBINT16 coordinate; /* X or Y value, in design units */ + FWORD coordinate; /* X or Y value, in design units */ public: DEFINE_SIZE_STATIC (4); }; @@ -161,7 +161,7 @@ struct CaretValueFormat3 protected: HBUINT16 caretValueFormat; /* Format identifier--format = 3 */ - HBINT16 coordinate; /* X or Y value, in design units */ + FWORD coordinate; /* X or Y value, in design units */ OffsetTo deviceTable; /* Offset to Device table for X or Y * value--from beginning of CaretValue diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh index 4e1a10d77..46ffcc668 100644 --- a/src/hb-ot-layout-gpos-table.hh +++ b/src/hb-ot-layout-gpos-table.hh @@ -248,8 +248,8 @@ struct AnchorFormat1 protected: HBUINT16 format; /* Format identifier--format = 1 */ - HBINT16 xCoordinate; /* Horizontal value--in design units */ - HBINT16 yCoordinate; /* Vertical value--in design units */ + FWORD xCoordinate; /* Horizontal value--in design units */ + FWORD yCoordinate; /* Vertical value--in design units */ public: DEFINE_SIZE_STATIC (6); }; @@ -279,8 +279,8 @@ struct AnchorFormat2 protected: HBUINT16 format; /* Format identifier--format = 2 */ - HBINT16 xCoordinate; /* Horizontal value--in design units */ - HBINT16 yCoordinate; /* Vertical value--in design units */ + FWORD xCoordinate; /* Horizontal value--in design units */ + FWORD yCoordinate; /* Vertical value--in design units */ HBUINT16 anchorPoint; /* Index to glyph contour point */ public: DEFINE_SIZE_STATIC (8); @@ -309,8 +309,8 @@ struct AnchorFormat3 protected: HBUINT16 format; /* Format identifier--format = 3 */ - HBINT16 xCoordinate; /* Horizontal value--in design units */ - HBINT16 yCoordinate; /* Vertical value--in design units */ + FWORD xCoordinate; /* Horizontal value--in design units */ + FWORD yCoordinate; /* Vertical value--in design units */ OffsetTo xDeviceTable; /* Offset to Device table for X * coordinate-- from beginning of diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh index 97f1d21a5..5f67aed21 100644 --- a/src/hb-ot-layout-gsub-table.hh +++ b/src/hb-ot-layout-gsub-table.hh @@ -114,7 +114,7 @@ struct SingleSubstFormat1 OffsetTo coverage; /* Offset to Coverage table--from * beginning of Substitution table */ - HBINT16 deltaGlyphID; /* Add to original GlyphID to get + HBINT16 deltaGlyphID; /* Add to original GlyphID to get * substitute GlyphID */ public: DEFINE_SIZE_STATIC (6); diff --git a/src/hb-ot-layout-private.hh b/src/hb-ot-layout-private.hh index 0c3bcbc5b..fdaa41ee8 100644 --- a/src/hb-ot-layout-private.hh +++ b/src/hb-ot-layout-private.hh @@ -122,6 +122,7 @@ hb_ot_layout_position_finish_offsets (hb_font_t *font, */ namespace OT { + struct BASE; struct GDEF; struct GSUB; struct GPOS; @@ -131,8 +132,9 @@ namespace OT { } namespace AAT { - struct morx; + struct ankr; struct kerx; + struct morx; struct trak; } @@ -168,11 +170,13 @@ struct hb_ot_layout_t const struct OT::GPOS *gpos; /* TODO Move the following out of this struct. */ + OT::hb_lazy_table_loader_t base; OT::hb_lazy_table_loader_t math; OT::hb_lazy_table_loader_t fvar; OT::hb_lazy_table_loader_t avar; - OT::hb_lazy_table_loader_t morx; + OT::hb_lazy_table_loader_t ankr; OT::hb_lazy_table_loader_t kerx; + OT::hb_lazy_table_loader_t morx; OT::hb_lazy_table_loader_t trak; unsigned int gsub_lookup_count; @@ -363,6 +367,28 @@ _hb_glyph_info_get_modified_combining_class (const hb_glyph_info_t *info) return _hb_glyph_info_is_unicode_mark (info) ? info->unicode_props()>>8 : 0; } + +/* Loop over grapheme. Based on foreach_cluster(). */ +#define foreach_grapheme(buffer, start, end) \ + for (unsigned int \ + _count = buffer->len, \ + start = 0, end = _count ? _next_grapheme (buffer, 0) : 0; \ + start < _count; \ + start = end, end = _next_grapheme (buffer, start)) + +static inline unsigned int +_next_grapheme (hb_buffer_t *buffer, unsigned int start) +{ + hb_glyph_info_t *info = buffer->info; + unsigned int count = buffer->len; + + while (++start < count && _hb_glyph_info_is_unicode_mark (&info[start])) + ; + + return start; +} + + #define info_cc(info) (_hb_glyph_info_get_modified_combining_class (&(info))) static inline bool diff --git a/src/hb-ot-layout.cc b/src/hb-ot-layout.cc index 4cf6c722c..42802e2ba 100644 --- a/src/hb-ot-layout.cc +++ b/src/hb-ot-layout.cc @@ -31,6 +31,7 @@ #include "hb-open-type-private.hh" #include "hb-ot-layout-private.hh" +#include "hb-ot-layout-base-table.hh" #include "hb-ot-layout-gdef-table.hh" #include "hb-ot-layout-gsub-table.hh" #include "hb-ot-layout-gpos-table.hh" @@ -62,9 +63,13 @@ _hb_ot_layout_create (hb_face_t *face) layout->gpos = OT::Sanitizer::lock_instance (layout->gpos_blob); layout->math.init (face); + layout->base.init (face); layout->fvar.init (face); layout->avar.init (face); + layout->ankr.init (face); + layout->kerx.init (face); layout->morx.init (face); + layout->trak.init (face); { /* @@ -212,13 +217,25 @@ _hb_ot_layout_destroy (hb_ot_layout_t *layout) hb_blob_destroy (layout->gpos_blob); layout->math.fini (); + layout->base.fini (); layout->fvar.fini (); layout->avar.fini (); + layout->ankr.fini (); + layout->kerx.fini (); layout->morx.fini (); + layout->trak.fini (); free (layout); } +// static inline const OT::BASE& +// _get_base (hb_face_t *face) +// { +// if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return OT::Null(OT::BASE); +// hb_ot_layout_t * layout = hb_ot_layout_from_face (face); +// return *(layout->base.get ()); +// } + static inline const OT::GDEF& _get_gdef (hb_face_t *face) { @@ -1264,3 +1281,27 @@ hb_ot_layout_substitute_lookup (OT::hb_ot_apply_context_t *c, { apply_string (c, lookup, accel); } + + + + +/* + * OT::BASE + */ + +// /** +// * hb_ot_base_has_data: +// * @face: #hb_face_t to test +// * +// * This function allows to verify the presence of an OpenType BASE table on the +// * face. +// * +// * Return value: true if face has a BASE table, false otherwise +// * +// * Since: XXX +// **/ +// hb_bool_t +// hb_ot_base_has_data (hb_face_t *face) +// { +// return &_get_base (face) != &OT::Null(OT::BASE); +// } diff --git a/src/hb-ot-layout.h b/src/hb-ot-layout.h index 9861f0fc7..077644c55 100644 --- a/src/hb-ot-layout.h +++ b/src/hb-ot-layout.h @@ -38,6 +38,7 @@ HB_BEGIN_DECLS +#define HB_OT_TAG_BASE HB_TAG('B','A','S','E') #define HB_OT_TAG_GDEF HB_TAG('G','D','E','F') #define HB_OT_TAG_GSUB HB_TAG('G','S','U','B') #define HB_OT_TAG_GPOS HB_TAG('G','P','O','S') diff --git a/src/hb-ot-maxp-table.hh b/src/hb-ot-maxp-table.hh index 129292296..881dedad5 100644 --- a/src/hb-ot-maxp-table.hh +++ b/src/hb-ot-maxp-table.hh @@ -39,9 +39,39 @@ namespace OT { #define HB_OT_TAG_maxp HB_TAG('m','a','x','p') +struct maxpV1Tail +{ + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this)); + } + + HBUINT16 maxPoints; /* Maximum points in a non-composite glyph. */ + HBUINT16 maxContours; /* Maximum contours in a non-composite glyph. */ + HBUINT16 maxCompositePoints; /* Maximum points in a composite glyph. */ + HBUINT16 maxCompositeContours; /* Maximum contours in a composite glyph. */ + HBUINT16 maxZones; /* 1 if instructions do not use the twilight zone (Z0), + * or 2 if instructions do use Z0; should be set to 2 in + * most cases. */ + HBUINT16 maxTwilightPoints; /* Maximum points used in Z0. */ + HBUINT16 maxStorage; /* Number of Storage Area locations. */ + HBUINT16 maxFunctionDefs; /* Number of FDEFs, equal to the highest function number + 1. */ + HBUINT16 maxInstructionDefs; /* Number of IDEFs. */ + HBUINT16 maxStackElements; /* Maximum stack depth. (This includes Font and CVT + * Programs, as well as the instructions for each glyph.) */ + HBUINT16 maxSizeOfInstructions; /* Maximum byte count for glyph instructions. */ + HBUINT16 maxComponentElements; /* Maximum number of components referenced at + * "top level" for any composite glyph. */ + HBUINT16 maxComponentDepth; /* Maximum levels of recursion; 1 for simple components. */ + public: + DEFINE_SIZE_STATIC (26); +}; + + struct maxp { - static const hb_tag_t tableTag = HB_OT_TAG_maxp; + static const hb_tag_t tableTag = HB_OT_TAG_maxp; inline unsigned int get_num_glyphs (void) const { @@ -56,9 +86,15 @@ struct maxp inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && - likely (version.major == 1 || - (version.major == 0 && version.minor == 0x5000u))); + if (unlikely (!c->check_struct (this))) + return_trace (false); + + if (version.major == 1) + { + const maxpV1Tail &v1 = StructAfter (*this); + return v1.sanitize (c); + } + return_trace (likely (version.major == 0 && version.minor == 0x5000u)); } inline bool subset (hb_subset_plan_t *plan) const @@ -73,17 +109,34 @@ struct maxp OT::maxp *maxp_prime = (OT::maxp *) hb_blob_get_data (maxp_prime_blob, nullptr); maxp_prime->set_num_glyphs (plan->gids_to_retain_sorted.len); + if (plan->drop_hints) + drop_hint_fields (plan, maxp_prime); bool result = hb_subset_plan_add_table(plan, HB_OT_TAG_maxp, maxp_prime_blob); hb_blob_destroy (maxp_prime_blob); return result; } - /* We only implement version 0.5 as none of the extra fields in version 1.0 are useful. */ + static inline void drop_hint_fields (hb_subset_plan_t *plan, OT::maxp *maxp_prime) + { + if (maxp_prime->version.major == 1) + { + maxpV1Tail &v1 = StructAfter (*maxp_prime); + v1.maxZones.set (1); + v1.maxTwilightPoints.set (0); + v1.maxStorage.set (0); + v1.maxFunctionDefs.set (0); + v1.maxInstructionDefs.set (0); + v1.maxStackElements.set (0); + v1.maxSizeOfInstructions.set (0); + } + } + protected: FixedVersion<>version; /* Version of the maxp table (0.5 or 1.0), * 0x00005000u or 0x00010000u. */ HBUINT16 numGlyphs; /* The number of glyphs in the font. */ +/*maxpV1Tail v1Tail[VAR]; */ public: DEFINE_SIZE_STATIC (6); }; diff --git a/src/hb-ot-os2-table.hh b/src/hb-ot-os2-table.hh index 2d9d21495..6cb8d4949 100644 --- a/src/hb-ot-os2-table.hh +++ b/src/hb-ot-os2-table.hh @@ -28,7 +28,7 @@ #define HB_OT_OS2_TABLE_HH #include "hb-open-type-private.hh" - +#include "hb-ot-os2-unicode-ranges.hh" namespace OT { @@ -67,11 +67,40 @@ struct os2 os2_prime->usFirstCharIndex.set (min_cp); os2_prime->usLastCharIndex.set (max_cp); + _update_unicode_ranges (plan->codepoints, os2_prime->ulUnicodeRange); bool result = hb_subset_plan_add_table(plan, HB_OT_TAG_os2, os2_prime_blob); + hb_blob_destroy (os2_prime_blob); return result; } + inline void _update_unicode_ranges (const hb_prealloced_array_t &codepoints, + HBUINT32 ulUnicodeRange[4]) const + { + for (unsigned int i = 0; i < 4; i++) + ulUnicodeRange[i].set (0); + + for (unsigned int i = 0; i < codepoints.len; i++) + { + hb_codepoint_t cp = codepoints[i]; + unsigned int bit = hb_get_unicode_range_bit (cp); + if (bit < 128) + { + unsigned int block = bit / 32; + unsigned int bit_in_block = bit % 32; + unsigned int mask = 1 << bit_in_block; + ulUnicodeRange[block].set (ulUnicodeRange[block] | mask); + } + if (cp >= 0x10000 && cp <= 0x110000) + { + /* the spec says that bit 57 ("Non Plane 0") implies that there's + at least one codepoint beyond the BMP; so I also include all + the non-BMP codepoints here */ + ulUnicodeRange[1].set (ulUnicodeRange[1] | (1 << 25)); + } + } + } + static inline void find_min_and_max_codepoint (const hb_prealloced_array_t &codepoints, uint16_t *min_cp, /* OUT */ uint16_t *max_cp /* OUT */) diff --git a/src/hb-ot-os2-unicode-ranges.hh b/src/hb-ot-os2-unicode-ranges.hh new file mode 100644 index 000000000..2cf168f9c --- /dev/null +++ b/src/hb-ot-os2-unicode-ranges.hh @@ -0,0 +1,247 @@ +/* + * Copyright © 2018 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Garret Rieger + */ + +#ifndef HB_OT_OS2_UNICODE_RANGES_HH +#define HB_OT_OS2_UNICODE_RANGES_HH + +#include "hb-private.hh" +#include "hb-dsalgs.hh" + +namespace OT { + +struct Range { + hb_codepoint_t start; + hb_codepoint_t end; + unsigned int bit; +}; + +/* Note: The contents of this array was generated using src/gen-unicode-ranges.py. */ +static Range os2UnicodeRangesSorted[] = +{ + { 0x0, 0x7F, 0}, // Basic Latin + { 0x80, 0xFF, 1}, // Latin-1 Supplement + { 0x100, 0x17F, 2}, // Latin Extended-A + { 0x180, 0x24F, 3}, // Latin Extended-B + { 0x250, 0x2AF, 4}, // IPA Extensions + { 0x2B0, 0x2FF, 5}, // Spacing Modifier Letters + { 0x300, 0x36F, 6}, // Combining Diacritical Marks + { 0x370, 0x3FF, 7}, // Greek and Coptic + { 0x400, 0x4FF, 9}, // Cyrillic + { 0x500, 0x52F, 9}, // Cyrillic Supplement + { 0x530, 0x58F, 10}, // Armenian + { 0x590, 0x5FF, 11}, // Hebrew + { 0x600, 0x6FF, 13}, // Arabic + { 0x700, 0x74F, 71}, // Syriac + { 0x750, 0x77F, 13}, // Arabic Supplement + { 0x780, 0x7BF, 72}, // Thaana + { 0x7C0, 0x7FF, 14}, // NKo + { 0x900, 0x97F, 15}, // Devanagari + { 0x980, 0x9FF, 16}, // Bengali + { 0xA00, 0xA7F, 17}, // Gurmukhi + { 0xA80, 0xAFF, 18}, // Gujarati + { 0xB00, 0xB7F, 19}, // Oriya + { 0xB80, 0xBFF, 20}, // Tamil + { 0xC00, 0xC7F, 21}, // Telugu + { 0xC80, 0xCFF, 22}, // Kannada + { 0xD00, 0xD7F, 23}, // Malayalam + { 0xD80, 0xDFF, 73}, // Sinhala + { 0xE00, 0xE7F, 24}, // Thai + { 0xE80, 0xEFF, 25}, // Lao + { 0xF00, 0xFFF, 70}, // Tibetan + { 0x1000, 0x109F, 74}, // Myanmar + { 0x10A0, 0x10FF, 26}, // Georgian + { 0x1100, 0x11FF, 28}, // Hangul Jamo + { 0x1200, 0x137F, 75}, // Ethiopic + { 0x1380, 0x139F, 75}, // Ethiopic Supplement + { 0x13A0, 0x13FF, 76}, // Cherokee + { 0x1400, 0x167F, 77}, // Unified Canadian Aboriginal Syllabics + { 0x1680, 0x169F, 78}, // Ogham + { 0x16A0, 0x16FF, 79}, // Runic + { 0x1700, 0x171F, 84}, // Tagalog + { 0x1720, 0x173F, 84}, // Hanunoo + { 0x1740, 0x175F, 84}, // Buhid + { 0x1760, 0x177F, 84}, // Tagbanwa + { 0x1780, 0x17FF, 80}, // Khmer + { 0x1800, 0x18AF, 81}, // Mongolian + { 0x1900, 0x194F, 93}, // Limbu + { 0x1950, 0x197F, 94}, // Tai Le + { 0x1980, 0x19DF, 95}, // New Tai Lue + { 0x19E0, 0x19FF, 80}, // Khmer Symbols + { 0x1A00, 0x1A1F, 96}, // Buginese + { 0x1B00, 0x1B7F, 27}, // Balinese + { 0x1B80, 0x1BBF, 112}, // Sundanese + { 0x1C00, 0x1C4F, 113}, // Lepcha + { 0x1C50, 0x1C7F, 114}, // Ol Chiki + { 0x1D00, 0x1D7F, 4}, // Phonetic Extensions + { 0x1D80, 0x1DBF, 4}, // Phonetic Extensions Supplement + { 0x1DC0, 0x1DFF, 6}, // Combining Diacritical Marks Supplement + { 0x1E00, 0x1EFF, 29}, // Latin Extended Additional + { 0x1F00, 0x1FFF, 30}, // Greek Extended + { 0x2000, 0x206F, 31}, // General Punctuation + { 0x2070, 0x209F, 32}, // Superscripts And Subscripts + { 0x20A0, 0x20CF, 33}, // Currency Symbols + { 0x20D0, 0x20FF, 34}, // Combining Diacritical Marks For Symbols + { 0x2100, 0x214F, 35}, // Letterlike Symbols + { 0x2150, 0x218F, 36}, // Number Forms + { 0x2190, 0x21FF, 37}, // Arrows + { 0x2200, 0x22FF, 38}, // Mathematical Operators + { 0x2300, 0x23FF, 39}, // Miscellaneous Technical + { 0x2400, 0x243F, 40}, // Control Pictures + { 0x2440, 0x245F, 41}, // Optical Character Recognition + { 0x2460, 0x24FF, 42}, // Enclosed Alphanumerics + { 0x2500, 0x257F, 43}, // Box Drawing + { 0x2580, 0x259F, 44}, // Block Elements + { 0x25A0, 0x25FF, 45}, // Geometric Shapes + { 0x2600, 0x26FF, 46}, // Miscellaneous Symbols + { 0x2700, 0x27BF, 47}, // Dingbats + { 0x27C0, 0x27EF, 38}, // Miscellaneous Mathematical Symbols-A + { 0x27F0, 0x27FF, 37}, // Supplemental Arrows-A + { 0x2800, 0x28FF, 82}, // Braille Patterns + { 0x2900, 0x297F, 37}, // Supplemental Arrows-B + { 0x2980, 0x29FF, 38}, // Miscellaneous Mathematical Symbols-B + { 0x2A00, 0x2AFF, 38}, // Supplemental Mathematical Operators + { 0x2B00, 0x2BFF, 37}, // Miscellaneous Symbols and Arrows + { 0x2C00, 0x2C5F, 97}, // Glagolitic + { 0x2C60, 0x2C7F, 29}, // Latin Extended-C + { 0x2C80, 0x2CFF, 8}, // Coptic + { 0x2D00, 0x2D2F, 26}, // Georgian Supplement + { 0x2D30, 0x2D7F, 98}, // Tifinagh + { 0x2D80, 0x2DDF, 75}, // Ethiopic Extended + { 0x2DE0, 0x2DFF, 9}, // Cyrillic Extended-A + { 0x2E00, 0x2E7F, 31}, // Supplemental Punctuation + { 0x2E80, 0x2EFF, 59}, // CJK Radicals Supplement + { 0x2F00, 0x2FDF, 59}, // Kangxi Radicals + { 0x2FF0, 0x2FFF, 59}, // Ideographic Description Characters + { 0x3000, 0x303F, 48}, // CJK Symbols And Punctuation + { 0x3040, 0x309F, 49}, // Hiragana + { 0x30A0, 0x30FF, 50}, // Katakana + { 0x3100, 0x312F, 51}, // Bopomofo + { 0x3130, 0x318F, 52}, // Hangul Compatibility Jamo + { 0x3190, 0x319F, 59}, // Kanbun + { 0x31A0, 0x31BF, 51}, // Bopomofo Extended + { 0x31C0, 0x31EF, 61}, // CJK Strokes + { 0x31F0, 0x31FF, 50}, // Katakana Phonetic Extensions + { 0x3200, 0x32FF, 54}, // Enclosed CJK Letters And Months + { 0x3300, 0x33FF, 55}, // CJK Compatibility + { 0x3400, 0x4DBF, 59}, // CJK Unified Ideographs Extension A + { 0x4DC0, 0x4DFF, 99}, // Yijing Hexagram Symbols + { 0x4E00, 0x9FFF, 59}, // CJK Unified Ideographs + { 0xA000, 0xA48F, 83}, // Yi Syllables + { 0xA490, 0xA4CF, 83}, // Yi Radicals + { 0xA500, 0xA63F, 12}, // Vai + { 0xA640, 0xA69F, 9}, // Cyrillic Extended-B + { 0xA700, 0xA71F, 5}, // Modifier Tone Letters + { 0xA720, 0xA7FF, 29}, // Latin Extended-D + { 0xA800, 0xA82F, 100}, // Syloti Nagri + { 0xA840, 0xA87F, 53}, // Phags-pa + { 0xA880, 0xA8DF, 115}, // Saurashtra + { 0xA900, 0xA92F, 116}, // Kayah Li + { 0xA930, 0xA95F, 117}, // Rejang + { 0xAA00, 0xAA5F, 118}, // Cham + { 0xAC00, 0xD7AF, 56}, // Hangul Syllables + { 0xD800, 0xDFFF, 57}, // Non-Plane 0 * + { 0xE000, 0xF8FF, 60}, // Private Use Area (plane 0) + { 0xF900, 0xFAFF, 61}, // CJK Compatibility Ideographs + { 0xFB00, 0xFB4F, 62}, // Alphabetic Presentation Forms + { 0xFB50, 0xFDFF, 63}, // Arabic Presentation Forms-A + { 0xFE00, 0xFE0F, 91}, // Variation Selectors + { 0xFE10, 0xFE1F, 65}, // Vertical Forms + { 0xFE20, 0xFE2F, 64}, // Combining Half Marks + { 0xFE30, 0xFE4F, 65}, // CJK Compatibility Forms + { 0xFE50, 0xFE6F, 66}, // Small Form Variants + { 0xFE70, 0xFEFF, 67}, // Arabic Presentation Forms-B + { 0xFF00, 0xFFEF, 68}, // Halfwidth And Fullwidth Forms + { 0xFFF0, 0xFFFF, 69}, // Specials + { 0x10000, 0x1007F, 101}, // Linear B Syllabary + { 0x10080, 0x100FF, 101}, // Linear B Ideograms + { 0x10100, 0x1013F, 101}, // Aegean Numbers + { 0x10140, 0x1018F, 102}, // Ancient Greek Numbers + { 0x10190, 0x101CF, 119}, // Ancient Symbols + { 0x101D0, 0x101FF, 120}, // Phaistos Disc + { 0x10280, 0x1029F, 121}, // Lycian + { 0x102A0, 0x102DF, 121}, // Carian + { 0x10300, 0x1032F, 85}, // Old Italic + { 0x10330, 0x1034F, 86}, // Gothic + { 0x10380, 0x1039F, 103}, // Ugaritic + { 0x103A0, 0x103DF, 104}, // Old Persian + { 0x10400, 0x1044F, 87}, // Deseret + { 0x10450, 0x1047F, 105}, // Shavian + { 0x10480, 0x104AF, 106}, // Osmanya + { 0x10800, 0x1083F, 107}, // Cypriot Syllabary + { 0x10900, 0x1091F, 58}, // Phoenician + { 0x10920, 0x1093F, 121}, // Lydian + { 0x10A00, 0x10A5F, 108}, // Kharoshthi + { 0x12000, 0x123FF, 110}, // Cuneiform + { 0x12400, 0x1247F, 110}, // Cuneiform Numbers and Punctuation + { 0x1D000, 0x1D0FF, 88}, // Byzantine Musical Symbols + { 0x1D100, 0x1D1FF, 88}, // Musical Symbols + { 0x1D200, 0x1D24F, 88}, // Ancient Greek Musical Notation + { 0x1D300, 0x1D35F, 109}, // Tai Xuan Jing Symbols + { 0x1D360, 0x1D37F, 111}, // Counting Rod Numerals + { 0x1D400, 0x1D7FF, 89}, // Mathematical Alphanumeric Symbols + { 0x1F000, 0x1F02F, 122}, // Mahjong Tiles + { 0x1F030, 0x1F09F, 122}, // Domino Tiles + { 0x20000, 0x2A6DF, 59}, // CJK Unified Ideographs Extension B + { 0x2F800, 0x2FA1F, 61}, // CJK Compatibility Ideographs Supplement + { 0xE0000, 0xE007F, 92}, // Tags + { 0xE0100, 0xE01EF, 91}, // Variation Selectors Supplement + { 0xF0000, 0xFFFFD, 90}, // Private Use (plane 15) + {0x100000, 0x10FFFD, 90}, // Private Use (plane 16) +}; + +static int +_compare_range (const void *_key, const void *_item, void *_arg) +{ + hb_codepoint_t cp = *((hb_codepoint_t *) _key); + const Range *range = (Range *) _item; + + if (cp < range->start) + return -1; + else if (cp <= range->end) + return 0; + else + return 1; +} + +/** + * hb_get_unicode_range_bit: + * Returns the bit to be set in os/2 ulUnicodeRange for a given codepoint. + **/ +static unsigned int +hb_get_unicode_range_bit (hb_codepoint_t cp) +{ + Range *range = (Range*) hb_bsearch_r (&cp, os2UnicodeRangesSorted, + sizeof (os2UnicodeRangesSorted) / sizeof(Range), + sizeof(Range), + _compare_range, nullptr); + if (range != NULL) + return range->bit; + return -1; +} + +} /* namespace OT */ + +#endif /* HB_OT_OS2_UNICODE_RANGES_HH */ diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc index d9ba0f6b3..d2d8012d0 100644 --- a/src/hb-ot-shape.cc +++ b/src/hb-ot-shape.cc @@ -787,6 +787,8 @@ hb_ot_position (hb_ot_shape_context_t *c) _hb_ot_shape_fallback_kern (c->plan, c->font, c->buffer); _hb_buffer_deallocate_gsubgpos_vars (c->buffer); + + //hb_aat_layout_position (c->font, c->buffer); } static inline void diff --git a/src/hb-ot.h b/src/hb-ot.h index 2120a3efa..272208e38 100644 --- a/src/hb-ot.h +++ b/src/hb-ot.h @@ -33,6 +33,7 @@ #include "hb-ot-font.h" #include "hb-ot-layout.h" #include "hb-ot-math.h" +#include "hb-ot-base.h" #include "hb-ot-tag.h" #include "hb-ot-shape.h" #include "hb-ot-var.h" diff --git a/src/hb-subset.cc b/src/hb-subset.cc index cba05176d..9ebe5d31d 100644 --- a/src/hb-subset.cc +++ b/src/hb-subset.cc @@ -136,7 +136,7 @@ _hb_subset_face_data_destroy (void *user_data) { hb_subset_face_data_t *data = (hb_subset_face_data_t *) user_data; - for (int i = 0; i < data->tables.len; i++) + for (unsigned int i = 0; i < data->tables.len; i++) hb_blob_destroy (data->tables[i].blob); data->tables.finish (); diff --git a/src/hb-version.h b/src/hb-version.h new file mode 100644 index 000000000..f0f5a1814 --- /dev/null +++ b/src/hb-version.h @@ -0,0 +1,66 @@ +/* + * Copyright © 2011 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_H_IN +#error "Include instead." +#endif + +#ifndef HB_VERSION_H +#define HB_VERSION_H + +#include "hb-common.h" + +HB_BEGIN_DECLS + + +#define HB_VERSION_MAJOR 1 +#define HB_VERSION_MINOR 7 +#define HB_VERSION_MICRO 5 + +#define HB_VERSION_STRING "1.7.5" + +#define HB_VERSION_ATLEAST(major,minor,micro) \ + ((major)*10000+(minor)*100+(micro) <= \ + HB_VERSION_MAJOR*10000+HB_VERSION_MINOR*100+HB_VERSION_MICRO) + + +HB_EXTERN void +hb_version (unsigned int *major, + unsigned int *minor, + unsigned int *micro); + +HB_EXTERN const char * +hb_version_string (void); + +HB_EXTERN hb_bool_t +hb_version_atleast (unsigned int major, + unsigned int minor, + unsigned int micro); + + +HB_END_DECLS + +#endif /* HB_VERSION_H */ diff --git a/src/test-unicode-ranges.cc b/src/test-unicode-ranges.cc new file mode 100644 index 000000000..16d01ef20 --- /dev/null +++ b/src/test-unicode-ranges.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): Garret Rieger + */ + +#include "hb-private.hh" + +#include "hb-ot-os2-unicode-ranges.hh" + +void +test (hb_codepoint_t cp, int bit) +{ + if (OT::hb_get_unicode_range_bit (cp) != bit) + { + fprintf (stderr, "got incorrect bit (%d) for cp 0x%X. Should have been %d.", + OT::hb_get_unicode_range_bit (cp), + cp, + bit); + abort(); + } +} + +void +test_get_unicode_range_bit (void) +{ + test (0x0000, 0); + test (0x0042, 0); + test (0x007F, 0); + test (0x0080, 1); + + test (0x30A0, 50); + test (0x30B1, 50); + test (0x30FF, 50); + + test (0x10FFFD, 90); + + test (0x30000, -1); + test (0x110000, -1); +} + +int +main (void) +{ + test_get_unicode_range_bit (); + return 0; +} diff --git a/test/api/test-set.c b/test/api/test-set.c index 60e11d981..1c51e8469 100644 --- a/test/api/test-set.c +++ b/test/api/test-set.c @@ -121,15 +121,16 @@ test_set_basic (void) hb_set_destroy (s); } -static inline void -print_set (hb_set_t *s) -{ - hb_codepoint_t next; - printf ("{"); - for (next = HB_SET_VALUE_INVALID; hb_set_next (s, &next); ) - printf ("%d, ", next); - printf ("}\n"); -} + +// static inline void +// print_set (hb_set_t *s) +// { +// hb_codepoint_t next; +// printf ("{"); +// for (next = HB_SET_VALUE_INVALID; hb_set_next (s, &next); ) +// printf ("%d, ", next); +// printf ("}\n"); +// } static void test_set_algebra (void) diff --git a/test/api/test-subset-glyf.c b/test/api/test-subset-glyf.c index 54665162e..1caa52697 100644 --- a/test/api/test-subset-glyf.c +++ b/test/api/test-subset-glyf.c @@ -31,14 +31,30 @@ /* Unit tests for hb-subset-glyf.h */ -static void check_maxp_num_glyphs (hb_face_t *face, uint16_t expected_num_glyphs) +static void check_maxp_field (uint8_t *raw_maxp, unsigned int offset, uint16_t expected_value) +{ + uint16_t actual_value = (raw_maxp[offset] << 8) + raw_maxp[offset + 1]; + g_assert_cmpuint(expected_value, ==, actual_value); +} + +static void check_maxp_num_glyphs (hb_face_t *face, uint16_t expected_num_glyphs, bool hints) { hb_blob_t *maxp_blob = hb_face_reference_table (face, HB_TAG ('m','a','x', 'p')); unsigned int maxp_len; uint8_t *raw_maxp = (uint8_t *) hb_blob_get_data(maxp_blob, &maxp_len); - uint16_t num_glyphs = (raw_maxp[4] << 8) + raw_maxp[5]; - g_assert_cmpuint(expected_num_glyphs, ==, num_glyphs); + + check_maxp_field (raw_maxp, 4, expected_num_glyphs); // numGlyphs + if (!hints) + { + check_maxp_field (raw_maxp, 14, 1); // maxZones + check_maxp_field (raw_maxp, 16, 0); // maxTwilightPoints + check_maxp_field (raw_maxp, 18, 0); // maxStorage + check_maxp_field (raw_maxp, 20, 0); // maxFunctionDefs + check_maxp_field (raw_maxp, 22, 0); // maxInstructionDefs + check_maxp_field (raw_maxp, 24, 0); // maxStackElements + check_maxp_field (raw_maxp, 26, 0); // maxSizeOfInstructions + } hb_blob_destroy (maxp_blob); } @@ -57,7 +73,7 @@ test_subset_glyf (void) hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('g','l','y','f')); hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('l','o','c', 'a')); - check_maxp_num_glyphs(face_abc_subset, 3); + check_maxp_num_glyphs(face_abc_subset, 3, true); hb_face_destroy (face_abc_subset); hb_face_destroy (face_abc); @@ -77,7 +93,7 @@ test_subset_glyf_with_components (void) hb_subset_test_check (face_subset, face_generated_subset, HB_TAG ('g','l','y','f')); hb_subset_test_check (face_subset, face_generated_subset, HB_TAG ('l','o','c', 'a')); - check_maxp_num_glyphs(face_generated_subset, 4); + check_maxp_num_glyphs(face_generated_subset, 4, true); hb_face_destroy (face_generated_subset); hb_face_destroy (face_subset); @@ -98,7 +114,7 @@ test_subset_glyf_noop (void) hb_subset_test_check (face_abc, face_abc_subset, HB_TAG ('g','l','y','f')); hb_subset_test_check (face_abc, face_abc_subset, HB_TAG ('l','o','c', 'a')); - check_maxp_num_glyphs(face_abc_subset, 4); + check_maxp_num_glyphs(face_abc_subset, 4, true); hb_face_destroy (face_abc_subset); hb_face_destroy (face_abc); @@ -120,7 +136,7 @@ test_subset_glyf_strip_hints_simple (void) hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('l','o','c', 'a')); hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('g','l','y','f')); - check_maxp_num_glyphs(face_abc_subset, 3); + check_maxp_num_glyphs(face_abc_subset, 3, false); hb_face_destroy (face_abc_subset); hb_face_destroy (face_abc); diff --git a/test/subset/data/Makefile.am b/test/subset/data/Makefile.am index f1234db85..0b0013431 100644 --- a/test/subset/data/Makefile.am +++ b/test/subset/data/Makefile.am @@ -8,6 +8,7 @@ SUBDIRS = EXTRA_DIST = \ $(TESTS) \ expected/basics \ + expected/full-font \ fonts \ profiles \ $(NULL) diff --git a/test/subset/data/Makefile.sources b/test/subset/data/Makefile.sources index 37550b639..bc8139379 100644 --- a/test/subset/data/Makefile.sources +++ b/test/subset/data/Makefile.sources @@ -1,5 +1,6 @@ TESTS = \ tests/basics.tests \ + tests/full-font.tests \ $(NULL) XFAIL_TESTS = \ diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.default.61,62,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.default.61,62,63.ttf new file mode 100644 index 000000000..02cd7efb4 Binary files /dev/null and b/test/subset/data/expected/basics/Roboto-Regular.abc.default.61,62,63.ttf differ diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.default.61,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.default.61,63.ttf new file mode 100644 index 000000000..4942ad0cd Binary files /dev/null and b/test/subset/data/expected/basics/Roboto-Regular.abc.default.61,63.ttf differ diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.default.61.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.default.61.ttf new file mode 100644 index 000000000..08fe7718a Binary files /dev/null and b/test/subset/data/expected/basics/Roboto-Regular.abc.default.61.ttf differ diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.default.63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.default.63.ttf new file mode 100644 index 000000000..0f3a934ce Binary files /dev/null and b/test/subset/data/expected/basics/Roboto-Regular.abc.default.63.ttf differ diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.61,62,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.61,62,63.ttf new file mode 100644 index 000000000..70206add6 Binary files /dev/null and b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.61,62,63.ttf differ diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.61,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.61,63.ttf new file mode 100644 index 000000000..c74c02995 Binary files /dev/null and b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.61,63.ttf differ diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.61.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.61.ttf new file mode 100644 index 000000000..8ba816d77 Binary files /dev/null and b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.61.ttf differ diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.62.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.62.ttf new file mode 100644 index 000000000..837438a55 Binary files /dev/null and b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.62.ttf differ diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.63.ttf new file mode 100644 index 000000000..311737ab4 Binary files /dev/null and b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.63.ttf differ diff --git a/test/subset/data/expected/full-font/Roboto-Regular.default.1FC,21,41,20,62,63.ttf b/test/subset/data/expected/full-font/Roboto-Regular.default.1FC,21,41,20,62,63.ttf new file mode 100644 index 000000000..60e361d2c Binary files /dev/null and b/test/subset/data/expected/full-font/Roboto-Regular.default.1FC,21,41,20,62,63.ttf differ diff --git a/test/subset/data/expected/full-font/Roboto-Regular.default.61,62,63.ttf b/test/subset/data/expected/full-font/Roboto-Regular.default.61,62,63.ttf new file mode 100644 index 000000000..1fc430a4e Binary files /dev/null and b/test/subset/data/expected/full-font/Roboto-Regular.default.61,62,63.ttf differ diff --git a/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.1FC,21,41,20,62,63.ttf b/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.1FC,21,41,20,62,63.ttf new file mode 100644 index 000000000..98f01e19a Binary files /dev/null and b/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.1FC,21,41,20,62,63.ttf differ diff --git a/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.61,62,63.ttf b/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.61,62,63.ttf new file mode 100644 index 000000000..ea212f03d Binary files /dev/null and b/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.61,62,63.ttf differ diff --git a/test/subset/data/fonts/Roboto-Regular.ttf b/test/subset/data/fonts/Roboto-Regular.ttf new file mode 100644 index 000000000..2c97eeadf Binary files /dev/null and b/test/subset/data/fonts/Roboto-Regular.ttf differ diff --git a/test/subset/data/profiles/drop-hints.txt b/test/subset/data/profiles/drop-hints.txt new file mode 100644 index 000000000..e5cd9743f --- /dev/null +++ b/test/subset/data/profiles/drop-hints.txt @@ -0,0 +1 @@ +--no-hinting diff --git a/test/subset/data/tests/basics.tests b/test/subset/data/tests/basics.tests index 8a7246b98..972544540 100644 --- a/test/subset/data/tests/basics.tests +++ b/test/subset/data/tests/basics.tests @@ -3,6 +3,11 @@ Roboto-Regular.abc.ttf PROFILES: default.txt +drop-hints.txt SUBSETS: +abc b +c +ac +a diff --git a/test/subset/data/tests/full-font.tests b/test/subset/data/tests/full-font.tests new file mode 100644 index 000000000..f0a262bf7 --- /dev/null +++ b/test/subset/data/tests/full-font.tests @@ -0,0 +1,11 @@ +FONTS: +Roboto-Regular.ttf + +PROFILES: +default.txt +drop-hints.txt + +SUBSETS: +abc +Ǽ!A bc + diff --git a/test/subset/generate-expected-outputs.py b/test/subset/generate-expected-outputs.py index 6dac890ec..9ebf082f6 100755 --- a/test/subset/generate-expected-outputs.py +++ b/test/subset/generate-expected-outputs.py @@ -15,12 +15,17 @@ def usage(): print "Usage: generate-expected-outputs.py ..." -def generate_expected_output(input_file, unicodes, output_path): - check_call(["fonttools", "subset", - input_file, - "--drop-tables+=DSIG,GPOS,GSUB,GDEF", - "--unicodes=%s" % unicodes, - "--output-file=%s" % output_path]) +def generate_expected_output(input_file, unicodes, profile_flags, output_path): + args = ["fonttools", "subset", input_file] + args.extend(profile_flags) + args.extend(["--notdef-outline", + "--name-IDs=*", + "--name-languages=*", + "--name-legacy", + "--drop-tables+=DSIG,GPOS,GSUB,GDEF", + "--unicodes=%s" % unicodes, + "--output-file=%s" % output_path]) + check_call(args) args = sys.argv[1:] @@ -37,6 +42,6 @@ for path in args: unicodes = test.unicodes() font_name = test.get_font_name() print "Creating subset %s/%s" % (output_directory, font_name) - generate_expected_output(test.font_path, unicodes, - os.path.join(output_directory, - font_name)) + generate_expected_output(test.font_path, unicodes, test.get_profile_flags(), + os.path.join(output_directory, + font_name)) diff --git a/test/subset/run-tests.py b/test/subset/run-tests.py index 99f97826e..f1ef4614a 100755 --- a/test/subset/run-tests.py +++ b/test/subset/run-tests.py @@ -44,6 +44,7 @@ def run_test(test): "--font-file=" + test.font_path, "--output-file=" + out_file, "--unicodes=%s" % test.unicodes()] + cli_args.extend (test.get_profile_flags()) print (' '.join(cli_args)) _, return_code = cmd(cli_args) @@ -78,7 +79,7 @@ def run_ttx(file): def strip_check_sum (ttx_string): return re.sub ('checkSumAdjustment value=["]0x([0-9a-fA-F])+["]', - 'checkSumAdjustment value="0x00000000"', + 'checkSumAdjustment value="0x00000000"', ttx_string, count=1) args = sys.argv[1:] diff --git a/test/subset/subset_test_suite.py b/test/subset/subset_test_suite.py index 256e20713..35386508e 100644 --- a/test/subset/subset_test_suite.py +++ b/test/subset/subset_test_suite.py @@ -1,5 +1,6 @@ #!/usr/bin/env python +import io import os # A single test in a subset test suite. Identifies a font @@ -13,15 +14,19 @@ class Test: def unicodes(self): return ",".join("%X" % ord(c) for (i, c) in enumerate(self.subset)) + def get_profile_flags(self): + with io.open(self.profile_path, mode="r", encoding="utf-8") as f: + return f.read().splitlines(); + def get_font_name(self): font_base_name = os.path.basename(self.font_path) font_base_name_parts = os.path.splitext(font_base_name) profile_name = os.path.splitext(os.path.basename(self.profile_path))[0] return "%s.%s.%s%s" % (font_base_name_parts[0], - profile_name, - self.unicodes(), - font_base_name_parts[1]) + profile_name, + self.unicodes(), + font_base_name_parts[1]) # A group of tests to perform on the subsetter. Each test # Identifies a font a subsetting profile, and a subset to be cut. diff --git a/util/options.hh b/util/options.hh index f78156dbb..467350a92 100644 --- a/util/options.hh +++ b/util/options.hh @@ -454,7 +454,7 @@ struct font_options_t : option_group_t default_font_size = default_font_size_; x_ppem = 0; y_ppem = 0; - ptem = .0; + ptem = 0.; subpixel_bits = subpixel_bits_; font_file = nullptr; face_index = 0;