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