diff --git a/gtk-doc.make b/gtk-doc.make index d539a6ecd..f87eaab9c 100644 --- a/gtk-doc.make +++ b/gtk-doc.make @@ -1 +1,320 @@ -EXTRA_DIST = +# -*- mode: makefile -*- +# +# gtk-doc.make - make rules for gtk-doc +# Copyright (C) 2003 James Henstridge +# 2004-2007 Damon Chaplin +# 2007-2017 Stefan Sauer +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +#################################### +# Everything below here is generic # +#################################### + +if GTK_DOC_USE_LIBTOOL +GTKDOC_CC = $(LIBTOOL) --tag=CC --mode=compile $(CC) $(INCLUDES) $(GTKDOC_DEPS_CFLAGS) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +GTKDOC_LD = $(LIBTOOL) --tag=CC --mode=link $(CC) $(GTKDOC_DEPS_LIBS) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) +GTKDOC_RUN = $(LIBTOOL) --mode=execute +else +GTKDOC_CC = $(CC) $(INCLUDES) $(GTKDOC_DEPS_CFLAGS) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +GTKDOC_LD = $(CC) $(GTKDOC_DEPS_LIBS) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) +GTKDOC_RUN = +endif + +# We set GPATH here; this gives us semantics for GNU make +# which are more like other make's VPATH, when it comes to +# whether a source that is a target of one rule is then +# searched for in VPATH/GPATH. +# +GPATH = $(srcdir) + +TARGET_DIR=$(HTML_DIR)/$(DOC_MODULE) + +SETUP_FILES = \ + $(content_files) \ + $(expand_content_files) \ + $(DOC_MAIN_SGML_FILE) \ + $(DOC_MODULE)-sections.txt \ + $(DOC_MODULE)-overrides.txt + +EXTRA_DIST = \ + $(HTML_IMAGES) \ + $(SETUP_FILES) + +DOC_STAMPS=setup-build.stamp scan-build.stamp sgml-build.stamp \ + html-build.stamp pdf-build.stamp \ + sgml.stamp html.stamp pdf.stamp + +SCANOBJ_FILES = \ + $(DOC_MODULE).args \ + $(DOC_MODULE).hierarchy \ + $(DOC_MODULE).interfaces \ + $(DOC_MODULE).prerequisites \ + $(DOC_MODULE).signals + +REPORT_FILES = \ + $(DOC_MODULE)-undocumented.txt \ + $(DOC_MODULE)-undeclared.txt \ + $(DOC_MODULE)-unused.txt + +gtkdoc-check.test: Makefile + $(AM_V_GEN)echo "#!/bin/sh -e" > $@; \ + echo "$(GTKDOC_CHECK_PATH) || exit 1" >> $@; \ + chmod +x $@ + +CLEANFILES = $(SCANOBJ_FILES) $(REPORT_FILES) $(DOC_STAMPS) gtkdoc-check.test + +if GTK_DOC_BUILD_HTML +HTML_BUILD_STAMP=html-build.stamp +else +HTML_BUILD_STAMP= +endif +if GTK_DOC_BUILD_PDF +PDF_BUILD_STAMP=pdf-build.stamp +else +PDF_BUILD_STAMP= +endif + +all-gtk-doc: $(HTML_BUILD_STAMP) $(PDF_BUILD_STAMP) +.PHONY: all-gtk-doc + +if ENABLE_GTK_DOC +all-local: all-gtk-doc +endif + +docs: $(HTML_BUILD_STAMP) $(PDF_BUILD_STAMP) + +$(REPORT_FILES): sgml-build.stamp + +#### setup #### + +GTK_DOC_V_SETUP=$(GTK_DOC_V_SETUP_@AM_V@) +GTK_DOC_V_SETUP_=$(GTK_DOC_V_SETUP_@AM_DEFAULT_V@) +GTK_DOC_V_SETUP_0=@echo " DOC Preparing build"; + +setup-build.stamp: + -$(GTK_DOC_V_SETUP)if test "$(abs_srcdir)" != "$(abs_builddir)" ; then \ + files=`echo $(SETUP_FILES) $(DOC_MODULE).types`; \ + if test "x$$files" != "x" ; then \ + for file in $$files ; do \ + destdir=`dirname $(abs_builddir)/$$file`; \ + test -d "$$destdir" || mkdir -p "$$destdir"; \ + test -f $(abs_srcdir)/$$file && \ + cp -pf $(abs_srcdir)/$$file $(abs_builddir)/$$file || true; \ + done; \ + fi; \ + fi + $(AM_V_at)touch setup-build.stamp + +#### scan #### + +GTK_DOC_V_SCAN=$(GTK_DOC_V_SCAN_@AM_V@) +GTK_DOC_V_SCAN_=$(GTK_DOC_V_SCAN_@AM_DEFAULT_V@) +GTK_DOC_V_SCAN_0=@echo " DOC Scanning header files"; + +GTK_DOC_V_INTROSPECT=$(GTK_DOC_V_INTROSPECT_@AM_V@) +GTK_DOC_V_INTROSPECT_=$(GTK_DOC_V_INTROSPECT_@AM_DEFAULT_V@) +GTK_DOC_V_INTROSPECT_0=@echo " DOC Introspecting gobjects"; + +scan-build.stamp: setup-build.stamp $(HFILE_GLOB) $(CFILE_GLOB) + $(GTK_DOC_V_SCAN)_source_dir='' ; \ + for i in $(DOC_SOURCE_DIR) ; do \ + _source_dir="$${_source_dir} --source-dir=$$i" ; \ + done ; \ + gtkdoc-scan --module=$(DOC_MODULE) --ignore-headers="$(IGNORE_HFILES)" $${_source_dir} $(SCAN_OPTIONS) $(EXTRA_HFILES) + $(GTK_DOC_V_INTROSPECT)if grep -l '^..*$$' $(DOC_MODULE).types > /dev/null 2>&1 ; then \ + scanobj_options=""; \ + gtkdoc-scangobj 2>&1 --help | grep >/dev/null "\-\-verbose"; \ + if test "$$?" = "0"; then \ + if test "x$(V)" = "x1"; then \ + scanobj_options="--verbose"; \ + fi; \ + fi; \ + CC="$(GTKDOC_CC)" LD="$(GTKDOC_LD)" RUN="$(GTKDOC_RUN)" CFLAGS="$(GTKDOC_CFLAGS) $(CFLAGS)" LDFLAGS="$(GTKDOC_LIBS) $(LDFLAGS)" \ + gtkdoc-scangobj $(SCANGOBJ_OPTIONS) $$scanobj_options --module=$(DOC_MODULE); \ + else \ + for i in $(SCANOBJ_FILES) ; do \ + test -f $$i || touch $$i ; \ + done \ + fi + $(AM_V_at)touch scan-build.stamp + +$(DOC_MODULE)-decl.txt $(SCANOBJ_FILES) $(DOC_MODULE)-sections.txt $(DOC_MODULE)-overrides.txt: scan-build.stamp + @true + +#### xml #### + +GTK_DOC_V_XML=$(GTK_DOC_V_XML_@AM_V@) +GTK_DOC_V_XML_=$(GTK_DOC_V_XML_@AM_DEFAULT_V@) +GTK_DOC_V_XML_0=@echo " DOC Building XML"; + +sgml-build.stamp: setup-build.stamp $(DOC_MODULE)-decl.txt $(SCANOBJ_FILES) $(HFILE_GLOB) $(CFILE_GLOB) $(DOC_MODULE)-sections.txt $(DOC_MODULE)-overrides.txt $(expand_content_files) xml/gtkdocentities.ent + $(GTK_DOC_V_XML)_source_dir='' ; \ + for i in $(DOC_SOURCE_DIR) ; do \ + _source_dir="$${_source_dir} --source-dir=$$i" ; \ + done ; \ + gtkdoc-mkdb --module=$(DOC_MODULE) --output-format=xml --expand-content-files="$(expand_content_files)" --main-sgml-file=$(DOC_MAIN_SGML_FILE) $${_source_dir} $(MKDB_OPTIONS) + $(AM_V_at)touch sgml-build.stamp + +sgml.stamp: sgml-build.stamp + @true + +$(DOC_MAIN_SGML_FILE): sgml-build.stamp + @true + +xml/gtkdocentities.ent: Makefile + $(GTK_DOC_V_XML)$(MKDIR_P) $(@D) && ( \ + echo ""; \ + echo ""; \ + echo ""; \ + echo ""; \ + echo ""; \ + echo ""; \ + echo ""; \ + ) > $@ + +#### html #### + +GTK_DOC_V_HTML=$(GTK_DOC_V_HTML_@AM_V@) +GTK_DOC_V_HTML_=$(GTK_DOC_V_HTML_@AM_DEFAULT_V@) +GTK_DOC_V_HTML_0=@echo " DOC Building HTML"; + +GTK_DOC_V_XREF=$(GTK_DOC_V_XREF_@AM_V@) +GTK_DOC_V_XREF_=$(GTK_DOC_V_XREF_@AM_DEFAULT_V@) +GTK_DOC_V_XREF_0=@echo " DOC Fixing cross-references"; + +html-build.stamp: sgml.stamp $(DOC_MAIN_SGML_FILE) $(content_files) $(expand_content_files) + $(GTK_DOC_V_HTML)rm -rf html && mkdir html && \ + mkhtml_options=""; \ + gtkdoc-mkhtml 2>&1 --help | grep >/dev/null "\-\-verbose"; \ + if test "$$?" = "0"; then \ + if test "x$(V)" = "x1"; then \ + mkhtml_options="$$mkhtml_options --verbose"; \ + fi; \ + fi; \ + gtkdoc-mkhtml 2>&1 --help | grep >/dev/null "\-\-path"; \ + if test "$$?" = "0"; then \ + mkhtml_options="$$mkhtml_options --path=\"$(abs_srcdir)\""; \ + fi; \ + cd html && gtkdoc-mkhtml $$mkhtml_options $(MKHTML_OPTIONS) $(DOC_MODULE) ../$(DOC_MAIN_SGML_FILE) + -@test "x$(HTML_IMAGES)" = "x" || \ + for file in $(HTML_IMAGES) ; do \ + test -f $(abs_srcdir)/$$file && cp $(abs_srcdir)/$$file $(abs_builddir)/html; \ + test -f $(abs_builddir)/$$file && cp $(abs_builddir)/$$file $(abs_builddir)/html; \ + done; + $(GTK_DOC_V_XREF)gtkdoc-fixxref --module=$(DOC_MODULE) --module-dir=html --html-dir=$(HTML_DIR) $(FIXXREF_OPTIONS) + $(AM_V_at)touch html-build.stamp + +#### pdf #### + +GTK_DOC_V_PDF=$(GTK_DOC_V_PDF_@AM_V@) +GTK_DOC_V_PDF_=$(GTK_DOC_V_PDF_@AM_DEFAULT_V@) +GTK_DOC_V_PDF_0=@echo " DOC Building PDF"; + +pdf-build.stamp: sgml.stamp $(DOC_MAIN_SGML_FILE) $(content_files) $(expand_content_files) + $(GTK_DOC_V_PDF)rm -f $(DOC_MODULE).pdf && \ + mkpdf_options=""; \ + gtkdoc-mkpdf 2>&1 --help | grep >/dev/null "\-\-verbose"; \ + if test "$$?" = "0"; then \ + if test "x$(V)" = "x1"; then \ + mkpdf_options="$$mkpdf_options --verbose"; \ + fi; \ + fi; \ + if test "x$(HTML_IMAGES)" != "x"; then \ + for img in $(HTML_IMAGES); do \ + part=`dirname $$img`; \ + echo $$mkpdf_options | grep >/dev/null "\-\-imgdir=$$part "; \ + if test $$? != 0; then \ + mkpdf_options="$$mkpdf_options --imgdir=$$part"; \ + fi; \ + done; \ + fi; \ + gtkdoc-mkpdf --path="$(abs_srcdir)" $$mkpdf_options $(DOC_MODULE) $(DOC_MAIN_SGML_FILE) $(MKPDF_OPTIONS) + $(AM_V_at)touch pdf-build.stamp + +############## + +clean-local: + @rm -f *~ *.bak + @rm -rf .libs + @if echo $(SCAN_OPTIONS) | grep -q "\-\-rebuild-types" ; then \ + rm -f $(DOC_MODULE).types; \ + fi + @if echo $(SCAN_OPTIONS) | grep -q "\-\-rebuild-sections" ; then \ + rm -f $(DOC_MODULE)-sections.txt; \ + fi + +distclean-local: + @rm -rf xml html $(REPORT_FILES) $(DOC_MODULE).pdf \ + $(DOC_MODULE)-decl-list.txt $(DOC_MODULE)-decl.txt + @if test "$(abs_srcdir)" != "$(abs_builddir)" ; then \ + rm -f $(SETUP_FILES) $(DOC_MODULE).types; \ + fi + +maintainer-clean-local: + @rm -rf xml html + +install-data-local: + @installfiles=`echo $(builddir)/html/*`; \ + if test "$$installfiles" = '$(builddir)/html/*'; \ + then echo 1>&2 'Nothing to install' ; \ + else \ + if test -n "$(DOC_MODULE_VERSION)"; then \ + installdir="$(DESTDIR)$(TARGET_DIR)-$(DOC_MODULE_VERSION)"; \ + else \ + installdir="$(DESTDIR)$(TARGET_DIR)"; \ + fi; \ + $(mkinstalldirs) $${installdir} ; \ + for i in $$installfiles; do \ + echo ' $(INSTALL_DATA) '$$i ; \ + $(INSTALL_DATA) $$i $${installdir}; \ + done; \ + if test -n "$(DOC_MODULE_VERSION)"; then \ + mv -f $${installdir}/$(DOC_MODULE).devhelp2 \ + $${installdir}/$(DOC_MODULE)-$(DOC_MODULE_VERSION).devhelp2; \ + fi; \ + $(GTKDOC_REBASE) --relative --dest-dir=$(DESTDIR) --html-dir=$${installdir}; \ + fi + +uninstall-local: + @if test -n "$(DOC_MODULE_VERSION)"; then \ + installdir="$(DESTDIR)$(TARGET_DIR)-$(DOC_MODULE_VERSION)"; \ + else \ + installdir="$(DESTDIR)$(TARGET_DIR)"; \ + fi; \ + rm -rf $${installdir} + +# +# Require gtk-doc when making dist +# +if HAVE_GTK_DOC +dist-check-gtkdoc: docs +else +dist-check-gtkdoc: + @echo "*** gtk-doc is needed to run 'make dist'. ***" + @echo "*** gtk-doc was not found when 'configure' ran. ***" + @echo "*** please install gtk-doc and rerun 'configure'. ***" + @false +endif + +dist-hook: dist-check-gtkdoc all-gtk-doc dist-hook-local + @mkdir $(distdir)/html + @cp ./html/* $(distdir)/html + @-cp ./$(DOC_MODULE).pdf $(distdir)/ + @-cp ./$(DOC_MODULE).types $(distdir)/ + @-cp ./$(DOC_MODULE)-sections.txt $(distdir)/ + @cd $(distdir) && rm -f $(DISTCLEANFILES) + @$(GTKDOC_REBASE) --online --relative --html-dir=$(distdir)/html + +.PHONY : dist-hook-local docs diff --git a/src/hb-cff-interp-common.hh b/src/hb-cff-interp-common.hh index 432e6870b..a7206a787 100644 --- a/src/hb-cff-interp-common.hh +++ b/src/hb-cff-interp-common.hh @@ -169,7 +169,7 @@ inline unsigned int OpCode_Size (OpCode op) { return Is_OpCode_ESC (op)? 2: 1; } #define OpCode_fixedcs 255 /* 32-bit fixed */ /* Two byte escape operators 12, (0-41) */ -#define OpCode_ReservedESC0 Make_OpCode_ESC(0) +#define OpCode_dotsection Make_OpCode_ESC(0) /* CFF (obsoleted) */ #define OpCode_ReservedESC1 Make_OpCode_ESC(1) #define OpCode_ReservedESC2 Make_OpCode_ESC(2) #define OpCode_and Make_OpCode_ESC(3) /* CFF */ diff --git a/src/hb-cff-interp-cs-common.hh b/src/hb-cff-interp-cs-common.hh index 02216def2..4402539ed 100644 --- a/src/hb-cff-interp-cs-common.hh +++ b/src/hb-cff-interp-cs-common.hh @@ -88,9 +88,16 @@ struct Point y.init (); } + inline void set_int (int _x, int _y) + { + x.set_int (_x); + y.set_int (_y); + } + inline void move_x (const Number &dx) { x += dx; } inline void move_y (const Number &dy) { y += dy; } inline void move (const Number &dx, const Number &dy) { move_x (dx); move_y (dy); } + inline void move (const Point &d) { move_x (d.x); move_y (d.y); } Number x; Number y; diff --git a/src/hb-cff1-interp-cs.hh b/src/hb-cff1-interp-cs.hh index 4e4c26d7b..a74547980 100644 --- a/src/hb-cff1-interp-cs.hh +++ b/src/hb-cff1-interp-cs.hh @@ -84,6 +84,29 @@ template { /* PostScript-originated legacy opcodes (OpCode_add etc) are unsupported */ + /* Type 1-originated deprecated opcodes, seac behavior of endchar and dotsection are supported */ + + static inline void process_op (OpCode op, CFF1CSInterpEnv &env, PARAM& param) + { + switch (op) { + case OpCode_dotsection: + SUPER::flush_args_and_op (op, env, param); + break; + + case OpCode_endchar: + OPSET::check_width (op, env, param); + if (env.argStack.get_count () >= 4) + { + OPSET::process_seac (env, param); + } + OPSET::flush_args_and_op (op, env, param); + env.set_endchar (true); + break; + + default: + SUPER::process_op (op, env, param); + } + } static inline void check_width (OpCode op, CFF1CSInterpEnv &env, PARAM& param) { @@ -93,8 +116,6 @@ struct CFF1CSOpSet : CSOpSet switch (op) { case OpCode_endchar: - has_width = (env.argStack.get_count () > 0); - break; case OpCode_hstem: case OpCode_hstemhm: case OpCode_vstem: @@ -117,6 +138,10 @@ struct CFF1CSOpSet : CSOpSet } } + static inline void process_seac (CFF1CSInterpEnv &env, PARAM& param) + { + } + static inline void flush_args (CFF1CSInterpEnv &env, PARAM& param) { SUPER::flush_args (env, param); diff --git a/src/hb-ot-cff1-table.cc b/src/hb-ot-cff1-table.cc index 0bcbf6645..50f54c01c 100644 --- a/src/hb-ot-cff1-table.cc +++ b/src/hb-ot-cff1-table.cc @@ -30,7 +30,7 @@ using namespace CFF; /* SID to code */ -static const uint8_t standard_encoding [] = +static const uint8_t standard_encoding_to_code [] = { 0, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, @@ -45,7 +45,7 @@ static const uint8_t standard_encoding [] = }; /* SID to code */ -static const uint8_t expert_encoding [] = +static const uint8_t expert_encoding_to_code [] = { 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 45, 46, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 58, 59, 0, 0, 0, @@ -74,7 +74,7 @@ static const uint8_t expert_encoding [] = }; /* glyph ID to SID */ -static const uint16_t expert_charset [] = +static const uint16_t expert_charset_to_sid [] = { 0, 1, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 13, 14, 15, 99, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 27, 28, 249, 250, 251, 252, @@ -90,7 +90,7 @@ static const uint16_t expert_charset [] = }; /* glyph ID to SID */ -static const uint16_t expert_subset_charset [] = +static const uint16_t expert_subset_charset_to_sid [] = { 0, 1, 231, 232, 235, 236, 237, 238, 13, 14, 15, 99, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 27, 28, 249, 250, 251, 253, 254, 255, 256, 257, @@ -100,66 +100,131 @@ static const uint16_t expert_subset_charset [] = 340, 341, 342, 343, 344, 345, 346 }; -hb_codepoint_t OT::cff1::lookup_standard_encoding (hb_codepoint_t sid) +/* code to SID */ +static const uint8_t standard_encoding_to_sid [] = { - if (sid < ARRAY_LENGTH (standard_encoding)) - return (hb_codepoint_t)standard_encoding[sid]; + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, + 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, + 0, 111, 112, 113, 114, 0, 115, 116, 117, 118, 119, 120, 121, 122, 0, 123, + 0, 124, 125, 126, 127, 128, 129, 130, 131, 0, 132, 133, 0, 134, 135, 136, + 137, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 138, 0, 139, 0, 0, 0, 0, 140, 141, 142, 143, 0, 0, 0, 0, + 0, 144, 0, 0, 0, 145, 0, 0, 146, 147, 148, 149, 0, 0, 0, 0 +}; + +hb_codepoint_t OT::cff1::lookup_standard_encoding_for_code (hb_codepoint_t sid) +{ + if (sid < ARRAY_LENGTH (standard_encoding_to_code)) + return (hb_codepoint_t)standard_encoding_to_code[sid]; else return 0; } -hb_codepoint_t OT::cff1::lookup_expert_encoding (hb_codepoint_t sid) +hb_codepoint_t OT::cff1::lookup_expert_encoding_for_code (hb_codepoint_t sid) { - if (sid < ARRAY_LENGTH (expert_encoding)) - return (hb_codepoint_t)expert_encoding[sid]; + if (sid < ARRAY_LENGTH (expert_encoding_to_code)) + return (hb_codepoint_t)expert_encoding_to_code[sid]; else return 0; } -hb_codepoint_t OT::cff1::lookup_expert_charset (hb_codepoint_t glyph) +hb_codepoint_t OT::cff1::lookup_expert_charset_for_sid (hb_codepoint_t glyph) { - if (glyph < ARRAY_LENGTH (expert_charset)) - return (hb_codepoint_t)expert_charset[glyph]; + if (glyph < ARRAY_LENGTH (expert_charset_to_sid)) + return (hb_codepoint_t)expert_charset_to_sid[glyph]; else return 0; } -hb_codepoint_t OT::cff1::lookup_expert_subset_charset (hb_codepoint_t glyph) +hb_codepoint_t OT::cff1::lookup_expert_subset_charset_for_sid (hb_codepoint_t glyph) { - if (glyph < ARRAY_LENGTH (expert_subset_charset)) - return (hb_codepoint_t)expert_subset_charset[glyph]; + if (glyph < ARRAY_LENGTH (expert_subset_charset_to_sid)) + return (hb_codepoint_t)expert_subset_charset_to_sid[glyph]; else return 0; } -struct ExtentsParam +hb_codepoint_t OT::cff1::lookup_standard_encoding_for_sid (hb_codepoint_t code) +{ + if (code < ARRAY_LENGTH (standard_encoding_to_sid)) + return (hb_codepoint_t)standard_encoding_to_sid[code]; + else + return CFF_UNDEF_SID; +} + +struct Bounds { inline void init (void) + { + min.set_int (0x7FFFFFFF, 0x7FFFFFFF); + max.set_int (-0x80000000, -0x80000000); + } + + inline void update (const Point &pt) + { + if (pt.x < min.x) min.x = pt.x; + if (pt.x > max.x) max.x = pt.x; + if (pt.y < min.y) min.y = pt.y; + if (pt.y > max.y) max.y = pt.y; + } + + inline void merge (const Bounds &b) + { + if (empty ()) + *this = b; + else if (!b.empty ()) + { + if (b.min.x < min.x) min.x = b.min.x; + if (b.max.x > max.x) max.x = b.max.x; + if (b.min.y < min.y) min.y = b.min.y; + if (b.max.y > max.y) max.y = b.max.y; + } + } + + inline void offset (const Point &delta) + { + if (!empty ()) + { + min.move (delta); + max.move (delta); + } + } + + inline bool empty (void) const + { + return (min.x >= max.x) || (min.y >= max.y); + } + + Point min; + Point max; +}; + +struct ExtentsParam +{ + inline void init (const OT::cff1::accelerator_t *_cff) { path_open = false; - min_x.set_int (0x7FFFFFFF); - min_y.set_int (0x7FFFFFFF); - max_x.set_int (-0x80000000); - max_y.set_int (-0x80000000); + cff = _cff; + bounds.init (); } inline void start_path (void) { path_open = true; } inline void end_path (void) { path_open = false; } inline bool is_path_open (void) const { return path_open; } - inline void update_bounds (const Point &pt) - { - if (pt.x < min_x) min_x = pt.x; - if (pt.x > max_x) max_x = pt.x; - if (pt.y < min_y) min_y = pt.y; - if (pt.y > max_y) max_y = pt.y; - } + bool path_open; + Bounds bounds; - bool path_open; - Number min_x; - Number min_y; - Number max_x; - Number max_y; + const OT::cff1::accelerator_t *cff; }; struct CFF1PathProcs_Extents : PathProcs @@ -175,10 +240,10 @@ struct CFF1PathProcs_Extents : PathProcs {}; +static bool _get_bounds (const OT::cff1::accelerator_t *cff, hb_codepoint_t glyph, Bounds &bounds); + +struct CFF1CSOpSet_Extents : CFF1CSOpSet +{ + static inline void process_seac (CFF1CSInterpEnv &env, ExtentsParam& param) + { + unsigned int n = env.argStack.get_count (); + Point delta; + delta.x = env.argStack[n-4]; + delta.y = env.argStack[n-3]; + hb_codepoint_t base = param.cff->std_code_to_glyph (env.argStack[n-2].to_int ()); + hb_codepoint_t accent = param.cff->std_code_to_glyph (env.argStack[n-1].to_int ()); + + Bounds base_bounds, accent_bounds; + if (likely (base && accent + && _get_bounds (param.cff, base, base_bounds) + && _get_bounds (param.cff, accent, accent_bounds))) + { + param.bounds.merge (base_bounds); + accent_bounds.offset (delta); + param.bounds.merge (accent_bounds); + } + else + env.set_error (); + } +}; + +bool _get_bounds (const OT::cff1::accelerator_t *cff, hb_codepoint_t glyph, Bounds &bounds) +{ + bounds.init (); + if (unlikely (!cff->is_valid () || (glyph >= cff->num_glyphs))) return false; + + unsigned int fd = cff->fdSelect->get_fd (glyph); + CFF1CSInterpreter interp; + const ByteStr str = (*cff->charStrings)[glyph]; + interp.env.init (str, *cff, fd); + ExtentsParam param; + param.init (cff); + if (unlikely (!interp.interpret (param))) return false; + bounds = param.bounds; + return true; +} bool OT::cff1::accelerator_t::get_extents (hb_codepoint_t glyph, hb_glyph_extents_t *extents) const { - if (unlikely (!is_valid () || (glyph >= num_glyphs))) return false; + Bounds bounds; - unsigned int fd = fdSelect->get_fd (glyph); - CFF1CSInterpreter interp; - const ByteStr str = (*charStrings)[glyph]; - interp.env.init (str, *this, fd); - ExtentsParam param; - param.init (); - if (unlikely (!interp.interpret (param))) return false; + if (!_get_bounds (this, glyph, bounds)) + return false; - if (param.min_x >= param.max_x) + if (bounds.min.x >= bounds.max.x) { extents->width = 0; extents->x_bearing = 0; } else { - extents->x_bearing = (int32_t)param.min_x.floor (); - extents->width = (int32_t)param.max_x.ceil () - extents->x_bearing; + extents->x_bearing = (int32_t)bounds.min.x.floor (); + extents->width = (int32_t)bounds.max.x.ceil () - extents->x_bearing; } - if (param.min_y >= param.max_y) + if (bounds.min.y >= bounds.max.y) { extents->height = 0; extents->y_bearing = 0; } else { - extents->y_bearing = (int32_t)param.max_y.ceil (); - extents->height = (int32_t)param.min_y.floor () - extents->y_bearing; + extents->y_bearing = (int32_t)bounds.max.y.ceil (); + extents->height = (int32_t)bounds.min.y.floor () - extents->y_bearing; } return true; } + +struct GetSeacParam +{ + inline void init (const OT::cff1::accelerator_t *_cff) + { + cff = _cff; + base = 0; + accent = 0; + } + + inline bool has_seac (void) const + { return base && accent; } + + const OT::cff1::accelerator_t *cff; + hb_codepoint_t base; + hb_codepoint_t accent; +}; + +struct CFF1CSOpSet_Seac : CFF1CSOpSet +{ + static inline void process_seac (CFF1CSInterpEnv &env, GetSeacParam& param) + { + unsigned int n = env.argStack.get_count (); + hb_codepoint_t base_char = (hb_codepoint_t)env.argStack[n-2].to_int (); + hb_codepoint_t accent_char = (hb_codepoint_t)env.argStack[n-1].to_int (); + + param.base = param.cff->std_code_to_glyph (base_char); + param.accent = param.cff->std_code_to_glyph (accent_char); + } +}; + +bool OT::cff1::accelerator_t::get_seac_components (hb_codepoint_t glyph, hb_codepoint_t *base, hb_codepoint_t *accent) const +{ + if (unlikely (!is_valid () || (glyph >= num_glyphs))) return false; + + unsigned int fd = fdSelect->get_fd (glyph); + CFF1CSInterpreter interp; + const ByteStr str = (*charStrings)[glyph]; + interp.env.init (str, *this, fd); + GetSeacParam param; + param.init (this); + if (unlikely (!interp.interpret (param))) return false; + + if (param.has_seac ()) + { + *base = param.base; + *accent = param.accent; + return true; + } + return false; +} diff --git a/src/hb-ot-cff1-table.hh b/src/hb-ot-cff1-table.hh index 62e6b513c..c3b293c1b 100644 --- a/src/hb-ot-cff1-table.hh +++ b/src/hb-ot-cff1-table.hh @@ -323,6 +323,19 @@ struct Charset0 { return sids[glyph - 1]; } + inline hb_codepoint_t get_glyph (hb_codepoint_t sid, unsigned int num_glyphs) const + { + if (sid == 0) + return 0; + + for (unsigned int glyph = 1; glyph < num_glyphs; glyph++) + { + if (sids[glyph-1] == sid) + return glyph; + } + return 0; + } + inline unsigned int get_size (unsigned int num_glyphs) const { assert (num_glyphs > 0); @@ -379,6 +392,20 @@ struct Charset1_2 { return 0; } + inline hb_codepoint_t get_glyph (hb_codepoint_t sid) const + { + if (sid == 0) return 0; + hb_codepoint_t glyph = 1; + for (unsigned int i = 0;; i++) + { + if ((ranges[i].first <= sid) && sid <= ranges[i].first + ranges[i].nLeft) + return glyph + (sid - ranges[i].first); + glyph += (ranges[i].nLeft + 1); + } + + return 0; + } + inline unsigned int get_size (unsigned int num_glyphs) const { unsigned int size = HBUINT8::static_size; @@ -518,6 +545,16 @@ struct Charset { return u.format2.get_sid (glyph); } + inline hb_codepoint_t get_glyph (hb_codepoint_t sid, unsigned int num_glyphs) const + { + if (format == 0) + return u.format0.get_glyph (sid, num_glyphs); + else if (format == 1) + return u.format1.get_glyph (sid); + else + return u.format2.get_glyph (sid); + } + HBUINT8 format; union { Charset0 format0; @@ -997,6 +1034,14 @@ struct cff1 if (unlikely (!top_interp.interpret (topDict))) { fini (); return; } } + if (is_predef_charset ()) + charset = &Null(Charset); + else + { + charset = &StructAtOffsetOrNull (cff, topDict.CharsetOffset); + if (unlikely ((charset == &Null (Charset)) || !charset->sanitize (&sc))) { fini (); return; } + } + fdCount = 1; if (is_CID ()) { @@ -1094,11 +1139,27 @@ struct cff1 inline bool is_valid (void) const { return blob != nullptr; } inline bool is_CID (void) const { return topDict.is_CID (); } + inline bool is_predef_charset (void) const { return topDict.CharsetOffset <= ExpertSubsetCharset; } + + inline unsigned int std_code_to_glyph (hb_codepoint_t code) const + { + hb_codepoint_t sid = lookup_standard_encoding_for_sid (code); + if (unlikely (sid == CFF_UNDEF_SID)) + return 0; + + if (charset != &Null(Charset)) + return charset->get_glyph (sid, num_glyphs); + else if ((topDict.CharsetOffset == ISOAdobeCharset) + && (code <= 228 /*zcaron*/)) return sid; + return 0; + } + protected: hb_blob_t *blob; hb_sanitize_context_t sc; public: + const Charset *charset; const CFF1NameIndex *nameIndex; const CFF1TopDictIndex *topDictIndex; const CFF1StringIndex *stringIndex; @@ -1118,6 +1179,7 @@ struct cff1 struct accelerator_t : accelerator_templ_t { HB_INTERNAL bool get_extents (hb_codepoint_t glyph, hb_glyph_extents_t *extents) const; + HB_INTERNAL bool get_seac_components (hb_codepoint_t glyph, hb_codepoint_t *base, hb_codepoint_t *accent) const; }; struct accelerator_subset_t : accelerator_templ_t @@ -1129,13 +1191,6 @@ struct cff1 const OT::cff1 *cff = this->blob->as (); encoding = &Null(Encoding); - if (is_predef_charset ()) - charset = &Null(Charset); - else - { - charset = &StructAtOffsetOrNull (cff, topDict.CharsetOffset); - if (unlikely ((charset == &Null (Charset)) || !charset->sanitize (&sc))) { fini (); return; } - } if (is_CID ()) { if (unlikely (charset == &Null(Charset))) { fini (); return; } @@ -1151,7 +1206,6 @@ struct cff1 } inline bool is_predef_encoding (void) const { return topDict.EncodingOffset <= ExpertEncoding; } - inline bool is_predef_charset (void) const { return topDict.CharsetOffset <= ExpertSubsetCharset; } inline hb_codepoint_t glyph_to_code (hb_codepoint_t glyph) const { @@ -1165,10 +1219,10 @@ struct cff1 switch (topDict.EncodingOffset) { case StandardEncoding: - code = lookup_standard_encoding (sid); + code = lookup_standard_encoding_for_code (sid); break; case ExpertEncoding: - code = lookup_expert_encoding (sid); + code = lookup_expert_encoding_for_code (sid); break; default: break; @@ -1190,10 +1244,10 @@ struct cff1 if (glyph <= 228 /*zcaron*/) sid = glyph; break; case ExpertCharset: - sid = lookup_expert_charset (glyph); + sid = lookup_expert_charset_for_sid (glyph); break; case ExpertSubsetCharset: - sid = lookup_expert_subset_charset (glyph); + sid = lookup_expert_subset_charset_for_sid (glyph); break; default: break; @@ -1203,7 +1257,6 @@ struct cff1 } const Encoding *encoding; - const Charset *charset; private: typedef accelerator_templ_t SUPER; @@ -1228,10 +1281,11 @@ struct cff1 } protected: - HB_INTERNAL static hb_codepoint_t lookup_standard_encoding (hb_codepoint_t sid); - HB_INTERNAL static hb_codepoint_t lookup_expert_encoding (hb_codepoint_t sid); - HB_INTERNAL static hb_codepoint_t lookup_expert_charset (hb_codepoint_t glyph); - HB_INTERNAL static hb_codepoint_t lookup_expert_subset_charset (hb_codepoint_t glyph); + HB_INTERNAL static hb_codepoint_t lookup_standard_encoding_for_code (hb_codepoint_t sid); + HB_INTERNAL static hb_codepoint_t lookup_expert_encoding_for_code (hb_codepoint_t sid); + HB_INTERNAL static hb_codepoint_t lookup_expert_charset_for_sid (hb_codepoint_t glyph); + HB_INTERNAL static hb_codepoint_t lookup_expert_subset_charset_for_sid (hb_codepoint_t glyph); + HB_INTERNAL static hb_codepoint_t lookup_standard_encoding_for_sid (hb_codepoint_t code); public: FixedVersion version; /* Version of CFF table. set to 0x0100u */ diff --git a/src/hb-subset-plan.cc b/src/hb-subset-plan.cc index 115aa5871..2de08a71b 100644 --- a/src/hb-subset-plan.cc +++ b/src/hb-subset-plan.cc @@ -30,6 +30,7 @@ #include "hb-ot-cmap-table.hh" #include "hb-ot-glyf-table.hh" +#include "hb-ot-cff1-table.hh" static void _add_gid_and_children (const OT::glyf::accelerator_t &glyf, @@ -52,6 +53,19 @@ _add_gid_and_children (const OT::glyf::accelerator_t &glyf, } } +static void +_add_cff_seac_components (const OT::cff1::accelerator_t &cff, + hb_codepoint_t gid, + hb_set_t *gids_to_retain) +{ + hb_codepoint_t base_gid, accent_gid; + if (cff.get_seac_components (gid, &base_gid, &accent_gid)) + { + hb_set_add (gids_to_retain, base_gid); + hb_set_add (gids_to_retain, accent_gid); + } +} + static void _gsub_closure (hb_face_t *face, hb_set_t *gids_to_retain) { @@ -78,8 +92,10 @@ _populate_gids_to_retain (hb_face_t *face, { OT::cmap::accelerator_t cmap; OT::glyf::accelerator_t glyf; + OT::cff1::accelerator_t cff; cmap.init (face); glyf.init (face); + cff.init (face); hb_set_t *initial_gids_to_retain = hb_set_create (); initial_gids_to_retain->add (0); // Not-def @@ -109,6 +125,8 @@ _populate_gids_to_retain (hb_face_t *face, while (initial_gids_to_retain->next (&gid)) { _add_gid_and_children (glyf, gid, all_gids_to_retain); + if (cff.is_valid ()) + _add_cff_seac_components (cff, gid, all_gids_to_retain); } hb_set_destroy (initial_gids_to_retain); @@ -117,6 +135,7 @@ _populate_gids_to_retain (hb_face_t *face, while (all_gids_to_retain->next (&gid)) glyphs->push (gid); + cff.fini (); glyf.fini (); cmap.fini (); diff --git a/test/api/fonts/cff1_seac.C0.otf b/test/api/fonts/cff1_seac.C0.otf new file mode 100644 index 000000000..0b695135f Binary files /dev/null and b/test/api/fonts/cff1_seac.C0.otf differ diff --git a/test/api/fonts/cff1_seac.otf b/test/api/fonts/cff1_seac.otf new file mode 100644 index 000000000..bc7991c2d Binary files /dev/null and b/test/api/fonts/cff1_seac.otf differ diff --git a/test/api/test-ot-extents-cff.c b/test/api/test-ot-extents-cff.c index 3b0c04046..49b87997e 100644 --- a/test/api/test-ot-extents-cff.c +++ b/test/api/test-ot-extents-cff.c @@ -90,6 +90,36 @@ test_extents_cff1_flex (void) hb_font_destroy (font); } +static void +test_extents_cff1_seac (void) +{ + hb_face_t *face = hb_test_open_font_file ("fonts/cff1_seac.otf"); + g_assert (face); + hb_font_t *font = hb_font_create (face); + hb_face_destroy (face); + g_assert (font); + hb_ot_font_set_funcs (font); + + hb_glyph_extents_t extents; + hb_bool_t result = hb_font_get_glyph_extents (font, 3, &extents); /* Agrave */ + g_assert (result); + + g_assert_cmpint (extents.x_bearing, ==, 3); + g_assert_cmpint (extents.y_bearing, ==, 861); + g_assert_cmpint (extents.width, ==, 538); + g_assert_cmpint (extents.height, ==, -861); + + result = hb_font_get_glyph_extents (font, 4, &extents); /* Udieresis */ + g_assert (result); + + g_assert_cmpint (extents.x_bearing, ==, 87); + g_assert_cmpint (extents.y_bearing, ==, 827); + g_assert_cmpint (extents.width, ==, 471); + g_assert_cmpint (extents.height, ==, -839); + + hb_font_destroy (font); +} + static void test_extents_cff2 (void) { @@ -161,6 +191,7 @@ main (int argc, char **argv) hb_test_add (test_extents_cff1); hb_test_add (test_extents_cff1_flex); + hb_test_add (test_extents_cff1_seac); hb_test_add (test_extents_cff2); hb_test_add (test_extents_cff2_vsindex); diff --git a/test/api/test-subset-cff1.c b/test/api/test-subset-cff1.c index 3c18196b6..6ac57903d 100644 --- a/test/api/test-subset-cff1.c +++ b/test/api/test-subset-cff1.c @@ -248,6 +248,24 @@ test_subset_cff1_expert (void) hb_face_destroy (face); } +static void +test_subset_cff1_seac (void) +{ + hb_face_t *face = hb_test_open_font_file ("fonts/cff1_seac.otf"); + hb_face_t *face_subset = hb_test_open_font_file ("fonts/cff1_seac.C0.otf"); + + hb_set_t *codepoints = hb_set_create (); + hb_set_add (codepoints, 0xC0); /* Agrave */ + hb_face_t *face_test = hb_subset_test_create_subset (face, hb_subset_test_create_input (codepoints)); + hb_set_destroy (codepoints); + + hb_subset_test_check (face_subset, face_test, HB_TAG ('C','F','F',' ')); + + hb_face_destroy (face_test); + hb_face_destroy (face_subset); + hb_face_destroy (face); +} + int main (int argc, char **argv) { @@ -263,6 +281,7 @@ main (int argc, char **argv) hb_test_add (test_subset_cff1_j_desubr); hb_test_add (test_subset_cff1_j_desubr_strip_hints); hb_test_add (test_subset_cff1_expert); + hb_test_add (test_subset_cff1_seac); return hb_test_run (); }