diff options
Diffstat (limited to 'Build/source')
286 files changed, 14854 insertions, 8023 deletions
diff --git a/Build/source/texk/dvisvgm/ChangeLog b/Build/source/texk/dvisvgm/ChangeLog index 42df6fc30f6..fcef5c522a2 100644 --- a/Build/source/texk/dvisvgm/ChangeLog +++ b/Build/source/texk/dvisvgm/ChangeLog @@ -1,3 +1,7 @@ +2019-11-19 Martin Gieseking <martin.gieseking@uos.de> + + * version.ac: 2.8.1; update sources and patches. + 2019-05-07 Karl Berry <karl@tug.org> * configure.ac (HAVE_LIBGS): reinstate setting for non-TL builds. diff --git a/Build/source/texk/dvisvgm/Makefile.in b/Build/source/texk/dvisvgm/Makefile.in index 1ba128a99f6..c53fb026a71 100644 --- a/Build/source/texk/dvisvgm/Makefile.in +++ b/Build/source/texk/dvisvgm/Makefile.in @@ -14,7 +14,7 @@ @SET_MAKE@ -# $Id: Makefile.am 49882 2019-01-31 18:21:25Z karl $ +# $Id$ # Makefile.am for the TeX Live subdirectory texk/dvisvgm/ # # Copyright 2015-2017 Karl Berry <tex-live@tug.org> diff --git a/Build/source/texk/dvisvgm/TLpatches/ChangeLog b/Build/source/texk/dvisvgm/TLpatches/ChangeLog index 682dfc104cf..5da373df2f7 100644 --- a/Build/source/texk/dvisvgm/TLpatches/ChangeLog +++ b/Build/source/texk/dvisvgm/TLpatches/ChangeLog @@ -1,3 +1,9 @@ +2019-11-19 Martin Gieseking <martin.gieseking@uos.de> + + * patch-04-configure-upstream, patch-08-makefiles, patch-09-woff-zlib: + adapt to 2.8.1. + * patch-10-psdefs: remove. + 2019-06-01 Karl Berry <karl@freefriends.org> * patch-10-psdefs: from Akira. diff --git a/Build/source/texk/dvisvgm/TLpatches/patch-04-configure-upstream b/Build/source/texk/dvisvgm/TLpatches/patch-04-configure-upstream index ea055633138..17909214244 100644 --- a/Build/source/texk/dvisvgm/TLpatches/patch-04-configure-upstream +++ b/Build/source/texk/dvisvgm/TLpatches/patch-04-configure-upstream @@ -1,15 +1,5 @@ - These are the (extensive) changes from the upstream - dvisvgm configure.ac to the current one in TL. For reference - only, won't apply to a new version as is. See also - patch-04-configure-tl. - - The general idea is that upstream needs to find and link against - various system libraries (kpathsea, freetype, zlib). For native - TL builds, we want to use the versions of those which are in the - TL source tree. - ---- dvisvgm-2.6.3/configure.ac 2019-03-09 04:13:38.000000000 -0800 -+++ configure.ac 2019-03-10 11:06:11.763261566 -0700 +--- dvisvgm-2.8.1/configure.ac ++++ configure.ac @@ -1,78 +1,63 @@ -# This file is part of dvisvgm -# Copyright (C) 2005-2019 Martin Gieseking <martin.gieseking@uos.de> @@ -17,7 +7,7 @@ -# Process this file with autoconf to produce a configure script. - -AC_PREREQ(2.59) --AC_INIT([dvisvgm],[2.6.3],[martin.gieseking@uos.de]) +-AC_INIT([dvisvgm],[2.8.1],[martin.gieseking@uos.de]) +# $Id: configure.ac 49819 2019-01-25 23:20:32Z karl $ +dnl Process this file with autoconf to produce a configure script +dnl for dvisvgm in TeX Live. @@ -35,7 +25,7 @@ +AC_PREREQ([2.65]) +m4_include([version.ac])[] dnl define dvisvgm_version +AC_INIT([dvisvgm (TeX Live)], dvisvgm_version, [tex-k@tug.org]) - DATE="March 2019" + DATE="November 2019" -AC_CONFIG_SRCDIR(src) +AC_CONFIG_SRCDIR([dvisvgm-src/src/dvisvgm.cpp]) AC_CONFIG_HEADERS([config.h]) @@ -131,28 +121,18 @@ have_libgs=yes AC_CHECK_HEADER([ghostscript/iapi.h], [AC_CHECK_LIB(gs, gsapi_revision,, [have_libgs=no])], -@@ -82,68 +67,87 @@ +@@ -82,12 +67,100 @@ [AC_CHECK_LIB(dl, dlopen,, [AC_DEFINE(DISABLE_GS, 1, [Set to 1 if PostScript support should be disabled])] [AC_MSG_WARN(PostScript support disabled)])]) -+fi - +- -# Check for pkg-config -PKG_PROG_PKG_CONFIG - -# Check for libraries. -PKG_CHECK_MODULES([FREETYPE], [freetype2]) -- --AC_ARG_ENABLE([woff], -- [AS_HELP_STRING([--disable-woff], [Disable WOFF support @<:@default=no@:>@])], -- [], -- [enable_woff=yes]) --AM_CONDITIONAL([ENABLE_WOFF], [test "x$enable_woff" = "xyes"]) -- --AC_ARG_WITH([ttfautohint], -- [AS_HELP_STRING([--with-ttfautohint@<:@=prefix@:>@], [enable ttfautohint support (disabled by default)])], -- [with_ttfautohint="$withval"], -- [with_ttfautohint=no]) ++fi ++ +if test -z "$HAVE_LIBGS" || test "$HAVE_LIBGS" -eq 0; then + AC_MSG_NOTICE([not linking to libgs, trying to arrange for dynamic loading]) + # Windows (native or MinGW32) has neither <dlfcn.h> nor dlopen(). @@ -215,11 +195,7 @@ +KPSE_ADD_FLAGS([kpathsea]) +AC_CHECK_FUNC([kpse_set_program_name], [], + [AC_MSG_ERROR([cannot find/use libkpathsea])]) - --# Add option to enable linking of bundled libraries (brotli, potrace, woff2, xxhash). --AC_ARG_ENABLE([bundled-libs], -- [AS_HELP_STRING([--enable-bundled-libs], [use bundled libraries instead of the system ones @<:@default=no@:>@])]) --AM_CONDITIONAL([USE_BUNDLED_LIBS], [test "x$enable_bundled_libs" = "xyes"]) ++ +# Check if the kpathsea headers are C++ safe. +AC_LANG_PUSH([C++]) +AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <kpathsea/kpathsea.h>]], @@ -229,7 +205,44 @@ + AC_DEFINE([KPSE_CXX_UNSAFE], 1, + [Define to 1 if the kpathsea headers are not C++ safe.])]) +AC_LANG_POP([C++]) ++ ++echo timestamp >config.force ++fi ++ ++KPSE_RESTORE_FLAGS ++ ++# emacs-page ++# Check for header files. ++AC_HEADER_DIRENT ++AC_HEADER_STDC ++AC_CHECK_HEADERS_ONCE([libintl.h stdlib.h string.h strings.h unistd.h]) ++ ++# Check for typedefs, structures, and compiler characteristics. ++AC_HEADER_STDBOOL ++AC_TYPE_SIZE_T ++AC_STRUCT_TM ++ ++# Check for library functions. ++AC_FUNC_STAT ++AC_CHECK_FUNCS_ONCE([ftime gettimeofday sigaction umask uselocale]) + + AC_ARG_ENABLE([woff], + [AS_HELP_STRING([--disable-woff], [Disable WOFF support @<:@default=no@:>@])], +@@ -95,124 +168,44 @@ + [enable_woff=yes]) + AM_CONDITIONAL([ENABLE_WOFF], [test "x$enable_woff" = "xyes"]) +-AC_ARG_WITH([ttfautohint], +- [AS_HELP_STRING([--with-ttfautohint@<:@=prefix@:>@], [enable ttfautohint support (disabled by default)])], +- [with_ttfautohint="$withval"], +- [with_ttfautohint=no]) +- ++# TL: skip ttfautohint? + # Add option to enable linking of bundled libraries (brotli, potrace, woff2, xxhash). + AC_ARG_ENABLE([bundled-libs], +- [AS_HELP_STRING([--enable-bundled-libs], [use bundled libraries instead of the system ones @<:@default=no@:>@])]) +-AM_CONDITIONAL([USE_BUNDLED_LIBS], [test "x$enable_bundled_libs" = "xyes"]) +- -# If option --enable-bundled-libs is not given, look for system libraries of brotli, potrace, woff2, and xxhash. -AS_IF([test "x$enable_bundled_libs" != "xyes"], - [AC_CHECK_HEADER(potracelib.h, @@ -266,20 +279,23 @@ -AC_CHECK_HEADERS([openssl/md5.h]) -PKG_CHECK_MODULES([LIBCRYPTO], [libcrypto], [HAVE_LIBCRYPTO=1], [HAVE_LIBCRYPTO=0]) -AM_CONDITIONAL([USE_BUNDLED_MD5], [test "$HAVE_LIBCRYPTO" -eq 0]) -+echo timestamp >config.force -+fi - +- -AC_CHECK_LIB(z, gzopen) -+KPSE_RESTORE_FLAGS - -+# emacs-page - # Check for header files. - AC_HEADER_DIRENT - AC_HEADER_STDC -@@ -158,79 +162,73 @@ - AC_FUNC_STAT - AC_CHECK_FUNCS_ONCE([ftime gettimeofday sigaction umask uselocale]) - +- +-# Check for header files. +-AC_HEADER_DIRENT +-AC_HEADER_STDC +-AC_CHECK_HEADERS_ONCE([libintl.h stdlib.h string.h strings.h unistd.h]) +- +-# Check for typedefs, structures, and compiler characteristics. +-AC_HEADER_STDBOOL +-AC_TYPE_SIZE_T +-AC_STRUCT_TM +- +-# Check for library functions. +-AC_FUNC_STAT +-AC_CHECK_FUNCS_ONCE([ftime gettimeofday sigaction umask uselocale]) +- -# add options for selection of "optional" library locations -# currently these libraries are mandatory; the --with-foo options -# are used to specify the locations explicitely @@ -291,23 +307,10 @@ - [AS_IF([test -n "$ZLIB_DIR"], - [ZLIB_CFLAGS="-I$ZLIB_DIR -I$ZLIB_DIR/include"] - [ZLIB_LIBS="-L$ZLIB_DIR/lib" -lz])])]) -+AC_ARG_ENABLE([woff], -+ [AS_HELP_STRING([--disable-woff], [Disable WOFF support @<:@default=no@:>@])], -+ [], -+ [enable_woff=yes]) -+AM_CONDITIONAL([ENABLE_WOFF], [test "x$enable_woff" = "xyes"]) -+ -+AC_DEFINE([HAVE_LIBKPATHSEA], 1, [Define to 1 if you have the `kpathsea' library (-lkpathsea).]) -+AC_DEFINE([HAVE_LIBFREETYPE], 1, [Define to 1 if you have the `freetype2' library (-lfreetype).]) -+AC_DEFINE([HAVE_LIBZ], 1, [Define to 1 if you have the `z' library (-lz).]) -+if false; then -+ AC_DEFINE([KPSE_CXX_UNSAFE], 1, [Define to 1 if the kpathsea headers are not C++ safe.]) -+fi - +- -AC_SUBST([ZLIB_CFLAGS]) -AC_SUBST([ZLIB_LIBS]) -+# TL: skip ttfautohint? - +- -# Check if the kpathsea headers are C++ safe -AC_MSG_CHECKING([if the kpathsea headers are C++ safe]) -AC_LANG_PUSH([C++]) @@ -318,8 +321,36 @@ - AC_DEFINE([KPSE_CXX_UNSAFE], 1, - [Define to 1 if the kpathsea headers are not C++ safe.])]) -AC_LANG_POP([C++]) -+# Add option to enable linking of bundled libraries (brotli, potrace, woff2, xxhash). -+AC_ARG_ENABLE([bundled-libs], +- +-CPPFLAGS="$CPPFLAGS_SAVE" +-CFLAGS="$CFLAGS_SAVE" +-LDFLAGS="$LDFLAGS_SAVE" +- +-AC_ARG_ENABLE([manpage], +- [AS_HELP_STRING([--disable-manpage], [disable generation of manual page @<:@default=no@:>@])]) +-AS_IF([test "x$enable_manpage" != "xno"],[ +- enable_manpage="no" +- # Check for utilities required to build the manpage +- AC_CHECK_PROG(ASCIIDOC, asciidoc, yes) +- AS_IF([test "x$ASCIIDOC" = "xyes"], [ +- AC_CHECK_PROG(XMLTO, xmlto, yes) +- AS_IF([test "x$XMLTO" = "xyes"], [ +- AC_CHECK_PROG(XSLTPROC, xsltproc, yes) +- AS_IF([test "x$XSLTPROC" = "xyes"],[enable_manpage="yes"])])])]) +-AS_IF([test "x$enable_manpage" != "xyes"], +- AC_MSG_NOTICE([generation of manual page has been disabled])) +-AM_CONDITIONAL([BUILD_MANPAGE], [test "x$enable_manpage" = "xyes"]) +- +-AX_CODE_COVERAGE +-AS_IF([ test "$enable_code_coverage" = "yes" ], [ +- # disable optimization +- changequote({,}) +- CFLAGS=`echo $CFLAGS | sed 's/-O[1-9s]//g'` +- CXXFLAGS=`echo $CXXFLAGS | sed 's/-O[1-9s]//g'` +- changequote([,]) +-]) +- +-AC_SUBST([dvisvgm_srcdir], ['$(top_srcdir)']) + [AS_HELP_STRING([--enable-bundled-libs], [use bundled libraries instead of the system ones @<:@default=no@:>@])], + [use_bundled_libs=yes]) +AM_CONDITIONAL([USE_BUNDLED_LIBS], [test "x$use_bundled_libs" = "xyes" dnl @@ -351,70 +382,11 @@ +# (init woff2) +AC_SUBST(WOFF2_CFLAGS) +AC_SUBST(WOFF2_LIBS) - --CPPFLAGS="$CPPFLAGS_SAVE" --CFLAGS="$CFLAGS_SAVE" --LDFLAGS="$LDFLAGS_SAVE" -- --AC_ARG_ENABLE([manpage], -- [AS_HELP_STRING([--disable-manpage], [disable generation of manual page @<:@default=no@:>@])]) --AS_IF([test "x$enable_manpage" != "xno"],[ -- enable_manpage="no" -- # Check for utilities required to build the manpage -- AC_CHECK_PROG(ASCIIDOC, asciidoc, yes) -- AS_IF([test "x$ASCIIDOC" = "xyes"], [ -- AC_CHECK_PROG(XMLTO, xmlto, yes) -- AS_IF([test "x$XMLTO" = "xyes"], [ -- AC_CHECK_PROG(XSLTPROC, xsltproc, yes) -- AS_IF([test "x$XSLTPROC" = "xyes"],[enable_manpage="yes"])])])]) --AS_IF([test "x$enable_manpage" != "xyes"], -- AC_MSG_NOTICE([generation of manual page has been disabled])) --AM_CONDITIONAL([BUILD_MANPAGE], [test "x$enable_manpage" = "xyes"]) -- --AX_CODE_COVERAGE --AS_IF([ test "$enable_code_coverage" = "yes" ], [ -- # disable optimization -- changequote({,}) -- CFLAGS=`echo $CFLAGS | sed 's/-O[1-9s]//g'` -- CXXFLAGS=`echo $CXXFLAGS | sed 's/-O[1-9s]//g'` -- changequote([,]) --]) ++ +AC_SUBST([DVISVGM_TREE], [dvisvgm-src]) - --AC_SUBST([dvisvgm_srcdir], ['$(top_srcdir)']) ++ +AC_SUBST([dvisvgm_srcdir], ['$(top_srcdir)/dvisvgm-src']) AC_SUBST(DATE) AC_SUBST(AM_CPPFLAGS) AC_SUBST(AM_LDFLAGS) --AC_CONFIG_FILES([ -- Makefile -- libs/Makefile -- libs/brotli/Makefile -- libs/clipper/Makefile -- libs/ff-woff/Makefile -- libs/md5/Makefile -- libs/potrace/Makefile -- libs/variant/Makefile -- libs/woff2/Makefile -- libs/xxHash/Makefile -- m4/Makefile -- src/Makefile -- src/version.hpp -- tests/Makefile -- tests/data/Makefile -- doc/Makefile]) -+AC_CONFIG_FILES([Makefile -+ dvisvgm-src/Makefile -+ dvisvgm-src/libs/Makefile -+ dvisvgm-src/libs/brotli/Makefile -+ dvisvgm-src/libs/clipper/Makefile -+ dvisvgm-src/libs/ff-woff/Makefile -+ dvisvgm-src/libs/md5/Makefile -+ dvisvgm-src/libs/potrace/Makefile -+ dvisvgm-src/libs/variant/Makefile -+ dvisvgm-src/libs/woff2/Makefile -+ dvisvgm-src/libs/xxHash/Makefile -+ dvisvgm-src/src/Makefile -+ dvisvgm-src/src/version.hpp -+])dnl TL: skipping tests/* and doc/* - AC_OUTPUT + diff --git a/Build/source/texk/dvisvgm/TLpatches/patch-08-makefiles b/Build/source/texk/dvisvgm/TLpatches/patch-08-makefiles index e5ce9d5ce3b..343678d2ac7 100644 --- a/Build/source/texk/dvisvgm/TLpatches/patch-08-makefiles +++ b/Build/source/texk/dvisvgm/TLpatches/patch-08-makefiles @@ -1,18 +1,34 @@ See ./TL-Changes. ---- dvisvgm-2.6.3/Makefile.am 2019-03-09 04:09:01.000000000 -0800 -+++ dvisvgm-src/Makefile.am 2019-03-10 11:06:34.614937057 -0700 -@@ -6,5 +6,5 @@ +--- dvisvgm-2.8.1/Makefile.am 2019-07-08 17:24:34.000000000 +0200 ++++ dvisvgm-src/Makefile.am 2019-11-16 13:57:04.091210187 +0100 +@@ -5,7 +5,7 @@ + AUTOMAKE_OPTIONS = foreign EXTRA_DIST = COPYING -SUBDIRS = libs m4 src tests doc -+SUBDIRS = libs src #not for TL: tests doc ++SUBDIRS = libs src #not for TL: m4 tests doc ACLOCAL_AMFLAGS = -I m4 ---- dvisvgm-2.6.3/src/Makefile.am 2019-03-09 04:09:01.000000000 -0800 -+++ dvisvgm-src/src/Makefile.am 2019-03-10 11:08:14.712515629 -0700 -@@ -16,9 +16,6 @@ - $(noinst_LIBRARIES) \ + if USE_BUNDLED_LIBS +--- dvisvgm-2.8.1/src/Makefile.am 2019-09-12 14:43:35.000000000 +0200 ++++ dvisvgm-src/src/Makefile.am 2019-11-16 15:54:55.820450555 +0100 +@@ -4,7 +4,7 @@ + ## Process this file with automake. + + bin_PROGRAMS = dvisvgm +-noinst_LTLIBRARIES = libdvisvgm.la ++noinst_LIBRARIES = libdvisvgm.a + SUBDIRS = optimizer + + dvisvgm_SOURCES = \ +@@ -14,13 +14,11 @@ + include ../libs/defs.am + + dvisvgm_LDADD = \ +- $(noinst_LTLIBRARIES) \ ++ $(noinst_LIBRARIES) \ ++ optimizer/liboptimizer.a \ ../libs/clipper/libclipper.a \ - $(FREETYPE_LIBS) \ - $(FONTFORGE_LIBS) \ @@ -22,21 +38,37 @@ + $(XXHASH_LIBS) if ENABLE_WOFF -@@ -35,5 +32,13 @@ + dvisvgm_LDADD += \ +@@ -35,9 +33,17 @@ + dvisvgm_LDADD += $(LIBCRYPTO_LIBS) endif +-dvisvgm_DEPENDENCIES = $(noinst_LTLIBRARIES) +dvisvgm_LDADD += \ + $(KPATHSEA_LIBS) \ + $(FREETYPE2_LIBS) \ + $(FONTFORGE_LIBS) \ + $(ZLIB_LIBS) \ + $(LIBGS_LIBS) -+ - dvisvgm_DEPENDENCIES = $(noinst_LIBRARIES) + +-libdvisvgm_la_SOURCES = \ ++dvisvgm_DEPENDENCIES = $(noinst_LIBRARIES) +dvisvgm_DEPENDENCIES += $(KPATHSEA_DEPEND) $(ZLIB_DEPEND) $(FREETYPE2_DEPEND) ++ ++libdvisvgm_a_SOURCES = \ + AGLTable.hpp \ + BasicDVIReader.hpp BasicDVIReader.cpp \ + Bezier.hpp Bezier.cpp \ +@@ -160,28 +166,31 @@ + ZLibOutputStream.hpp - libdvisvgm_a_SOURCES = \ -@@ -259,15 +264,11 @@ + if ENABLE_WOFF +-libdvisvgm_la_SOURCES += ffwrapper.c ffwrapper.h ++libdvisvgm_a_SOURCES += ffwrapper.c ffwrapper.h + endif + +-libdvisvgm_la_LIBADD = optimizer/liboptimizer.la +- EXTRA_DIST = options.xml options.dtd iapi.h ierrors.h MiKTeXCom.hpp MiKTeXCom.cpp -AM_CFLAGS = -Wall \ @@ -56,26 +88,44 @@ + -I$(dvisvgm_srcdir)/libs/variant/include AM_CXXFLAGS += \ -@@ -299,5 +300,18 @@ - endif - -+AM_CXXFLAGS += \ + $(POTRACE_CFLAGS) \ +- $(XXHASH_CFLAGS) ++ $(XXHASH_CFLAGS) \ + $(KPATHSEA_INCLUDES) \ + $(POTRACE_INCLUDES) \ + $(FREETYPE2_INCLUDES) \ -+ $(ZLIB_INCLUDES) \ + $(LIBGS_INCLUDES) \ + $(CODE_COVERAGE_CFLAGS) - ++ +if WIN32 +AM_CXXFLAGS += -DTEXLIVEWIN32 +endif WIN32 -+ -+if ! TEXLIVE_BUILD + + AM_LDFLAGS = \ + $(KPSE_LIBS) \ +@@ -192,8 +201,6 @@ + -I$(dvisvgm_srcdir)/libs/ff-woff/fontforge \ + -I$(dvisvgm_srcdir)/libs/ff-woff/inc + +-AM_CXXFLAGS += $(TTFAUTOHINT_CFLAGS) +- + AM_CXXFLAGS += \ + $(BROTLI_CFLAGS) \ + $(WOFF2_CFLAGS) +@@ -204,9 +211,10 @@ + AM_CXXFLAGS += $(LIBCRYPTO_CFLAGS) + endif + +-AM_LDFLAGS += $(TTFAUTOHINT_LIBS) + endif + +# TL: do not try to rebuild these source files. ++if ! TEXLIVE_BUILD + # the command-line parser class is generated from options.xml by opt2cpp $(srcdir)/CommandLine.hpp: options.xml -@@ -312,6 +326,14 @@ +@@ -220,7 +228,15 @@ + fi psdefs.ps: ; +endif ! TEXLIVE_BUILD @@ -90,3 +140,14 @@ +@FREETYPE2_RULE@ +# Rebuild libz: +@ZLIB_RULE@ +--- dvisvgm-2.8.1/src/optimizer/Makefile.am 2019-11-08 15:26:11.000000000 +0100 ++++ dvisvgm-src/src/optimizer/Makefile.am 2019-11-16 15:15:54.151760519 +0100 +@@ -1,6 +1,6 @@ +-noinst_LTLIBRARIES = liboptimizer.la ++noinst_LIBRARIES = liboptimizer.a + +-liboptimizer_la_SOURCES = \ ++liboptimizer_a_SOURCES = \ + AttributeExtractor.hpp AttributeExtractor.cpp \ + DependencyGraph.hpp \ + GroupCollapser.hpp GroupCollapser.cpp \ diff --git a/Build/source/texk/dvisvgm/TLpatches/patch-10-psdefs b/Build/source/texk/dvisvgm/TLpatches/patch-10-psdefs deleted file mode 100644 index 82690ddc352..00000000000 --- a/Build/source/texk/dvisvgm/TLpatches/patch-10-psdefs +++ /dev/null @@ -1,19 +0,0 @@ -dvisvgm does not work with gs-9.27 because GS_PDF_ProcSet was removed in -gs-9.27. - ---- psdefs.cpp.orig Mon Mar 11 03:21:29 2019 -+++ psdefs.cpp Thu May 30 08:06:00 2019 -@@ -107,8 +107,8 @@ - "dmode sysexec<</Normal 0/Compatible 0/Multiply 1/Screen 2/Overlay 3/SoftLight " - "4/HardLight 5/ColorDodge 6/ColorBurn 7/Darken 8/Lighten 9/Difference 10/Exclus" - "ion 11/Hue 12/Saturation 13/Color 14/Luminosity 15/CompatibleOverprint 16>>exc" --"h get 1(setblendmode)prcmd}def/@pdfpagecount{GS_PDF_ProcSet begin pdfdict begi" --"n(r)file pdfopen begin pdfpagecount currentdict pdfclose end end end}def/@pdfp" --"agebox{GS_PDF_ProcSet begin pdfdict begin(r)file pdfopen begin dup dup 1 lt ex" --"ch pdfpagecount gt or{pop}{pdfgetpage/MediaBox pget pop aload pop}ifelse curre" --"ntdict pdfclose end end end}def DELAYBIND{.bindnow}if "; -+"h get 1(setblendmode)prcmd}def/@pdfpagecount{(r)file runpdfbe" -+"gin pdfpagecount runpdfend}def/@pdfp" -+"agebox{(r)file runpdfbegin dup dup 1 lt ex" -+"ch pdfpagecount gt or{pop}{pdfgetpage/MediaBox pget pop aload pop}ifelse runpd" -+"fend}def DELAYBIND{.bindnow}if "; diff --git a/Build/source/texk/dvisvgm/configure b/Build/source/texk/dvisvgm/configure index e8bc774312d..4a2238b63a7 100755 --- a/Build/source/texk/dvisvgm/configure +++ b/Build/source/texk/dvisvgm/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for dvisvgm (TeX Live) 2.6.3. +# Generated by GNU Autoconf 2.69 for dvisvgm (TeX Live) 2.8.1. # # Report bugs to <tex-k@tug.org>. # @@ -590,8 +590,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='dvisvgm (TeX Live)' PACKAGE_TARNAME='dvisvgm--tex-live-' -PACKAGE_VERSION='2.6.3' -PACKAGE_STRING='dvisvgm (TeX Live) 2.6.3' +PACKAGE_VERSION='2.8.1' +PACKAGE_STRING='dvisvgm (TeX Live) 2.8.1' PACKAGE_BUGREPORT='tex-k@tug.org' PACKAGE_URL='' @@ -1391,7 +1391,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures dvisvgm (TeX Live) 2.6.3 to adapt to many kinds of systems. +\`configure' configures dvisvgm (TeX Live) 2.8.1 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1462,7 +1462,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of dvisvgm (TeX Live) 2.6.3:";; + short | recursive ) echo "Configuration of dvisvgm (TeX Live) 2.8.1:";; esac cat <<\_ACEOF @@ -1594,7 +1594,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -dvisvgm (TeX Live) configure 2.6.3 +dvisvgm (TeX Live) configure 2.8.1 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -2462,7 +2462,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by dvisvgm (TeX Live) $as_me 2.6.3, which was +It was created by dvisvgm (TeX Live) $as_me 2.8.1, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -2820,7 +2820,7 @@ ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $ ac_compiler_gnu=$ac_cv_c_compiler_gnu -DATE="March 2019" +DATE="November 2019" ac_config_headers="$ac_config_headers config.h" @@ -8214,7 +8214,7 @@ fi # Define the identity of the package. PACKAGE='dvisvgm--tex-live-' - VERSION='2.6.3' + VERSION='2.8.1' cat >>confdefs.h <<_ACEOF @@ -20212,7 +20212,7 @@ Usage: $0 [OPTIONS] Report bugs to <bug-libtool@gnu.org>." lt_cl_version="\ -dvisvgm (TeX Live) config.lt 2.6.3 +dvisvgm (TeX Live) config.lt 2.8.1 configured by $0, generated by GNU Autoconf 2.69. Copyright (C) 2011 Free Software Foundation, Inc. @@ -22938,7 +22938,7 @@ dvisvgm_srcdir='$(top_srcdir)/dvisvgm-src' -ac_config_files="$ac_config_files Makefile dvisvgm-src/Makefile dvisvgm-src/libs/Makefile dvisvgm-src/libs/brotli/Makefile dvisvgm-src/libs/clipper/Makefile dvisvgm-src/libs/ff-woff/Makefile dvisvgm-src/libs/md5/Makefile dvisvgm-src/libs/potrace/Makefile dvisvgm-src/libs/variant/Makefile dvisvgm-src/libs/woff2/Makefile dvisvgm-src/libs/xxHash/Makefile dvisvgm-src/src/Makefile dvisvgm-src/src/version.hpp" +ac_config_files="$ac_config_files Makefile dvisvgm-src/Makefile dvisvgm-src/libs/Makefile dvisvgm-src/libs/brotli/Makefile dvisvgm-src/libs/clipper/Makefile dvisvgm-src/libs/ff-woff/Makefile dvisvgm-src/libs/md5/Makefile dvisvgm-src/libs/potrace/Makefile dvisvgm-src/libs/variant/Makefile dvisvgm-src/libs/woff2/Makefile dvisvgm-src/libs/xxHash/Makefile dvisvgm-src/src/Makefile dvisvgm-src/src/version.hpp dvisvgm-src/src/optimizer/Makefile" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure @@ -23517,7 +23517,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by dvisvgm (TeX Live) $as_me 2.6.3, which was +This file was extended by dvisvgm (TeX Live) $as_me 2.8.1, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -23583,7 +23583,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -dvisvgm (TeX Live) config.status 2.6.3 +dvisvgm (TeX Live) config.status 2.8.1 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" @@ -24114,6 +24114,7 @@ do "dvisvgm-src/libs/xxHash/Makefile") CONFIG_FILES="$CONFIG_FILES dvisvgm-src/libs/xxHash/Makefile" ;; "dvisvgm-src/src/Makefile") CONFIG_FILES="$CONFIG_FILES dvisvgm-src/src/Makefile" ;; "dvisvgm-src/src/version.hpp") CONFIG_FILES="$CONFIG_FILES dvisvgm-src/src/version.hpp" ;; + "dvisvgm-src/src/optimizer/Makefile") CONFIG_FILES="$CONFIG_FILES dvisvgm-src/src/optimizer/Makefile" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac diff --git a/Build/source/texk/dvisvgm/configure.ac b/Build/source/texk/dvisvgm/configure.ac index 387fc501ab7..26cdef4ae9f 100644 --- a/Build/source/texk/dvisvgm/configure.ac +++ b/Build/source/texk/dvisvgm/configure.ac @@ -15,7 +15,7 @@ dnl AC_PREREQ([2.65]) m4_include([version.ac])[] dnl define dvisvgm_version AC_INIT([dvisvgm (TeX Live)], dvisvgm_version, [tex-k@tug.org]) -DATE="March 2019" +DATE="November 2019" AC_CONFIG_SRCDIR([dvisvgm-src/src/dvisvgm.cpp]) AC_CONFIG_HEADERS([config.h]) AC_CONFIG_MACRO_DIRS([../../m4])dnl not just _DIR @@ -233,5 +233,6 @@ AC_CONFIG_FILES([Makefile dvisvgm-src/libs/xxHash/Makefile dvisvgm-src/src/Makefile dvisvgm-src/src/version.hpp + dvisvgm-src/src/optimizer/Makefile ])dnl TL: skipping tests/* and doc/* AC_OUTPUT diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/ChangeLog b/Build/source/texk/dvisvgm/dvisvgm-src/ChangeLog index b082998a45e..e7761560f4b 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/ChangeLog +++ b/Build/source/texk/dvisvgm/dvisvgm-src/ChangeLog @@ -1,13 +1,881 @@ +2019-11-14 Martin Gieseking <martin.gieseking@uos.de> + + * NEWS, README.md: + updated NEWS and README + +2019-11-12 Martin Gieseking <martin.gieseking@uos.de> + + * .appveyor.yml, .travis.yml, configure.ac, src/Doxyfile, src/version.hpp: + set version to 2.8.1 + + * doc/dvisvgm.txt.in: + some minor changes of the manual page + +2019-11-11 Martin Gieseking <martin.gieseking@uos.de> + + * src/psdefs.cpp: + added newline at end of file + +2019-11-08 Martin Gieseking <martin.gieseking@uos.de> + + * src/optimizer/GroupCollapser.hpp: + made GroupCollapser::moveAttributes() static + + * doc/dvisvgm.txt.in, src/optimizer/Makefile.am, + src/optimizer/SVGOptimizer.cpp, src/optimizer/TextSimplifier.cpp, + src/optimizer/TextSimplifier.hpp: + added optimizer module TextSimplifier + + * doc/dvisvgm.txt.in, src/XMLNode.hpp, + src/optimizer/AttributeExtractor.hpp, src/optimizer/TextSimplifier.cpp: + extended functionality of optimizer module 'simplify-text' +- common + attributes of tspans are moved to the enclosing text element +- tspans + without attributes are unwrapped + +2019-11-05 Martin Gieseking <martin.gieseking@uos.de> + + * src/DVIToSVGActions.cpp, src/DVIToSVGActions.hpp, + src/EmSpecialHandler.cpp, src/EmSpecialHandler.hpp: + removed some constant initializers from constructors + + * src/DVIToSVGActions.cpp, src/DVIToSVGActions.hpp, + src/EmSpecialHandler.cpp, src/PSInterpreter.cpp, src/PSInterpreter.hpp, + src/PsSpecialHandler.cpp, src/PsSpecialHandler.hpp, + src/SpecialActions.hpp, src/TpicSpecialHandler.cpp, src/psdefs.cpp, + tests/PSInterpreterTest.cpp: + added support for PS operator 'nulldevice' + +2019-10-30 Martin Gieseking <martin.gieseking@uos.de> + + * src/FileFinder.cpp: + added PNG, JPEG, and SVG to supported formats of FileFinder + + * src/PsSpecialHandler.cpp, src/PsSpecialHandler.hpp: + psfile: create absolute or relative paths to reference images +depending + on the file location and the file path given by the user + +2019-10-29 Martin Gieseking <martin.gieseking@uos.de> + + * src/FilePath.cpp, src/FilePath.hpp: + added method to check if a path is absolute or relative + +2019-10-27 Martin Gieseking <martin.gieseking@uos.de> + + * src/CMapReader.cpp, src/CMapReader.hpp, tests/CMapReaderTest.cpp: + CMapReader: extracted common code; added test for 'begincidchar' + +2019-10-25 Martin Gieseking <martin.gieseking@uos.de> + + * tests/Makefile.am, tests/create-makefile: + added missing gtest file to distribution + + * tests/FontCacheTest.cpp: + remove temporary files created by FontCacheTest + + * .appveyor.yml, .travis.yml, configure.ac, src/Doxyfile, src/version.hpp: + set version to 2.8 + + * NEWS: + updated NEWS + +2019-10-23 Martin Gieseking <martin.gieseking@uos.de> + + * src/CMapReader.cpp, src/CMapReader.hpp: + CMapReader: added support for operator 'begincidchar' (patch by Akira + Kakuto) + +2019-10-20 Martin Gieseking <martin.gieseking@uos.de> + + * src/DVIToSVG.cpp, src/DVIToSVG.hpp, src/DVIToSVGActions.cpp, + src/DVIToSVGActions.hpp, src/FilePath.cpp, src/FilePath.hpp, + src/HyperlinkManager.cpp, src/ImageToSVG.cpp, src/ImageToSVG.hpp, + src/PDFToSVG.hpp, src/SVGOutput.cpp, src/SVGOutput.hpp, + src/SpecialActions.hpp, tests/FilePathTest.cpp, tests/SVGOutputTest.cpp: + SVGOutput: renamed 'filename' to 'filepath'; changed return type to + FilePath + +2019-10-18 Martin Gieseking <martin.gieseking@uos.de> + + * tests/gtest/include/gtest/gtest-death-test.h, + tests/gtest/include/gtest/gtest-matchers.h, + tests/gtest/include/gtest/gtest-message.h, + tests/gtest/include/gtest/gtest-param-test.h, + tests/gtest/include/gtest/gtest-printers.h, + tests/gtest/include/gtest/gtest-spi.h, + tests/gtest/include/gtest/gtest-test-part.h, + tests/gtest/include/gtest/gtest-typed-test.h, + tests/gtest/include/gtest/gtest.h, + tests/gtest/include/gtest/gtest_pred_impl.h, + tests/gtest/include/gtest/internal/gtest-death-test-internal.h, + tests/gtest/include/gtest/internal/gtest-filepath.h, + tests/gtest/include/gtest/internal/gtest-internal.h, + tests/gtest/include/gtest/internal/gtest-param-util.h, + tests/gtest/include/gtest/internal/gtest-port-arch.h, + tests/gtest/include/gtest/internal/gtest-port.h, + tests/gtest/include/gtest/internal/gtest-string.h, + tests/gtest/include/gtest/internal/gtest-type-util.h, + tests/gtest/src/gtest-all.cc, tests/gtest/src/gtest-death-test.cc, + tests/gtest/src/gtest-filepath.cc, tests/gtest/src/gtest-internal-inl.h, + tests/gtest/src/gtest-matchers.cc, tests/gtest/src/gtest-port.cc, + tests/gtest/src/gtest-printers.cc, tests/gtest/src/gtest-test-part.cc, + tests/gtest/src/gtest-typed-test.cc, tests/gtest/src/gtest.cc, + tests/gtest/src/gtest_main.cc, tests/testutil.hpp: + updated gtest to version 1.10 + + * src/PsSpecialHandler.cpp, src/PsSpecialHandler.hpp: + psfile: added support for PDF, JPG, PNG, and SVG files + + * src/optimizer/TransformSimplifier.cpp, + src/optimizer/TransformSimplifier.hpp: + try to incorporate transformations into positional and size attributes + + * src/PsSpecialHandler.cpp: + PS handler: minor code enhancements + +2019-10-17 Martin Gieseking <martin.gieseking@uos.de> + + * src/PSInterpreter.cpp: + call GS with -dDELAYSAFER if GS version >= 9.50 +Ghostscript 9.50 + introduced incompatible changes regarding SAFER which is now +active by + default. This conflicts with DELAYBIND and WRITESYSTEMDICT, which + are +necessary for dvisvgm to work + correctly. +https://www.ghostscript.com/doc/9.50/Use.htm#Safer + + * tests/HashFunctionTest.cpp: + adapted XXH128 tests to changes in xxhash 0.7.2 + +2019-10-08 Martin Gieseking <martin.gieseking@uos.de> + + * libs/xxHash/xxh3.h, libs/xxHash/xxhash.c, libs/xxHash/xxhash.h: + updated xxhash to version 0.7.2 + +2019-10-06 Martin Gieseking <martin.gieseking@uos.de> + + * src/EllipticalArc.cpp: + minor changes in EllipticalArc.cpp + +2019-09-19 Martin Gieseking <martin.gieseking@uos.de> + + * src/PathClipper.cpp: + prevent warnings about uninitialized variables + +2019-09-17 Martin Gieseking <martin.gieseking@uos.de> + + * libs/potrace/auxiliary.h, libs/potrace/bitmap.h, libs/potrace/config.h, + libs/potrace/curve.c, libs/potrace/curve.h, libs/potrace/decompose.c, + libs/potrace/decompose.h, libs/potrace/lists.h, + libs/potrace/potracelib.c, libs/potrace/potracelib.h, + libs/potrace/progress.h, libs/potrace/trace.c, libs/potrace/trace.h: + updated potrace to version 1.16 + + * src/Bitmap.cpp, src/Bitmap.hpp: + minor code cleanup of Bitmap class + +2019-09-12 Martin Gieseking <martin.gieseking@uos.de> + + * src/GraphicsPath.hpp: + renamed misspelled variables 'largeArgFlag' to 'largeArcFlag' + + * src/EllipticalArc.cpp: + removed #include "debug.h" + +2019-09-03 Martin Gieseking <martin.gieseking@uos.de> + + * libs/woff2/src/glyph.cc, libs/woff2/src/normalize.cc: + fixed two compiler warnings in libwoff2 +regarding signed/unsigned + comparison + +2019-08-27 Martin Gieseking <martin.gieseking@uos.de> + + * src/XXHashFunction.hpp, tests/HashFunctionTest.cpp: + simplified implementation of XXHashFunction::digestValue() and tests + +2019-08-26 Martin Gieseking <martin.gieseking@uos.de> + + * src/StreamReader.cpp, src/StreamReader.hpp, src/VFReader.cpp, + tests/StreamReaderTest.cpp: + removed vector reference from StreamReader::readBytes() + + * src/CRC32.cpp, src/CRC32.hpp, src/FontCache.cpp, src/FontCache.hpp, + src/HashFunction.cpp, src/HashFunction.hpp, src/Makefile.am, + src/StreamReader.cpp, src/StreamReader.hpp, src/StreamWriter.cpp, + src/StreamWriter.hpp, src/XXHashFunction.hpp, src/utility.hpp, + tests/CRC32Test.cpp, tests/FontCacheTest.cpp, tests/Makefile.am, + tests/StreamReaderTest.cpp, tests/StreamWriterTest.cpp: + replaced CRC32 cache checksums with XXH32 hashes + +2019-08-25 Martin Gieseking <martin.gieseking@uos.de> + + * doc/dvisvgm.txt.in, libs/xxHash/xxhash.h, src/HashFunction.cpp, + src/XXHashFunction.hpp, tests/HashFunctionTest.cpp: + added support for the experimental 128-bit XXH3 algorithm + +2019-08-24 Martin Gieseking <martin.gieseking@uos.de> + + * src/GraphicsPath.hpp: + avoid redundant sequences of closepath (z/Z) commands + +2019-08-19 Martin Gieseking <martin.gieseking@uos.de> + + * src/GraphicsPath.hpp, tests/GraphicsPathTest.cpp: + added short versions of 'quadto' and 'cubicto' to GraphicsPath + +2019-08-18 Martin Gieseking <martin.gieseking@uos.de> + + * src/TpicSpecialHandler.cpp, tests/TpicSpecialTest.cpp: + use class EllipticalArc to process arcs in tpic handler + +2019-08-15 Martin Gieseking <martin.gieseking@uos.de> + + * libs/xxHash/Makefile.am, libs/xxHash/xxh3.h, libs/xxHash/xxhash.c, + libs/xxHash/xxhash.h: + updated xxhash to version 0.7.1 + + * src/DVIToSVG.cpp: + print error message on wrong page hash arguments + +2019-08-14 Martin Gieseking <martin.gieseking@uos.de> + + * src/EllipticalArc.cpp, src/EllipticalArc.hpp, src/GraphicsPath.hpp, + tests/EllipticalArcTest.cpp, tests/GraphicsPathTest.cpp: + added GraphicsPath::approximateArcs() + +2019-08-13 Martin Gieseking <martin.gieseking@uos.de> + + * src/Bezier.cpp, src/Bezier.hpp, src/EllipticalArc.cpp, + src/EllipticalArc.hpp, src/GraphicsPath.hpp, src/Makefile.am, + src/Pair.hpp, src/utility.cpp, src/utility.hpp, + tests/EllipticalArcTest.cpp, tests/Makefile.am: + added support of 'arcto' command to class GraphicsPath + +2019-08-08 Martin Gieseking <martin.gieseking@uos.de> + + * src/Bezier.cpp, src/Bezier.hpp, src/PsSpecialHandler.cpp, + src/ShadingPatch.hpp, src/TensorProductPatch.cpp, + src/TensorProductPatch.hpp, src/TriangularPatch.cpp, + src/TriangularPatch.hpp, tests/BezierTest.cpp, + tests/TensorProductPatchTest.cpp, tests/TriangularPatchTest.cpp: + getBBox(): replaced reference parameter with return value + + * src/PsSpecialHandler.cpp, src/ShadingPatch.hpp, + src/TensorProductPatch.cpp, src/TensorProductPatch.hpp, + src/TriangularPatch.cpp, src/TriangularPatch.hpp, + tests/TensorProductPatchTest.cpp, tests/TriangularPatchTest.cpp: + getBoundaryPath(): replaced reference parameter with return value + +2019-08-04 Martin Gieseking <martin.gieseking@uos.de> + + * src/Color.cpp, src/Pair.hpp: + use std::hypot() to compute length of vector + +2019-08-01 Martin Gieseking <martin.gieseking@uos.de> + + * src/MD5HashFunction.hpp: + removed 'explicit' from default constructor +Work around for C++11 bug in + GCC 4.8: +https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58255 + + * src/FontCache.cpp, src/FontEngine.cpp, src/FontWriter.cpp, + src/GraphicsPath.hpp, src/Pair.hpp, src/PathClipper.cpp, + src/TpicSpecialHandler.cpp, src/optimizer/CMakeLists.txt, + src/optimizer/Makefile.am, tests/FontCacheTest.cpp, + tests/GraphicsPathTest.cpp: + redesigned implementation of class GraphicsPath +- use variant instances + to store path commands instead of plain structs +- process commands in + visitor objects +- removed GraphicsPath::Actions::draw() that exposed + implemenation details +- simplify iterate() method + +2019-07-29 Martin Gieseking <martin.gieseking@uos.de> + + * src/FontCache.cpp: + use direct string concatenation instead of temporary string stream + +2019-07-28 Martin Gieseking <martin.gieseking@uos.de> + + * doc/Makefile.am: + added missing dependency to Makefile rule + + * .appveyor.yml, .travis.yml, configure.ac, src/Doxyfile, src/version.hpp: + set version to 2.7.4 + + * NEWS: + updated NEWS + +2019-07-27 Martin Gieseking <martin.gieseking@uos.de> + + * doc/Makefile.am: + moved generation of dvisvgm.sty to separate rule + +2019-07-26 Martin Gieseking <martin.gieseking@uos.de> + + * src/Color.cpp: + use std::round to round color value (fixes #116) + + * doc/Makefile.am, doc/dvisvgm.sty, doc/dvisvgm.txt.in, + doc/generate-dvisvgm-sty.xsl, doc/tweak-db-article.xsl, + doc/tweak-db-refentry.xsl: + show revision date given in doc/dvisvgm.txt on manual page +rather than + the build date + +2019-07-25 Martin Gieseking <martin.gieseking@uos.de> + + * src/TrueTypeFont.cpp: + call ofstream constructor with std::string instead of C string + +2019-07-23 Martin Gieseking <martin.gieseking@uos.de> + + * src/MetafontWrapper.cpp: + replaced atoi() with stoi() + +2019-07-16 Martin Gieseking <martin.gieseking@uos.de> + + * src/MetafontWrapper.cpp: + don't access moved string + + * doc/dvisvgm.txt.in, src/dvisvgm.cpp: + changed cache location to $XDG_CACHE_HOME/dvisvgm +or ~/.cache/dvisvgm if + $XDG_CACHE_HOME is not set (closes #112) + +2019-07-12 Martin Gieseking <martin.gieseking@uos.de> + + * .appveyor.yml, .travis.yml, configure.ac, src/Doxyfile, src/version.hpp: + set version to 2.7.3 + + * NEWS: + updated NEWS + +2019-07-09 Martin Gieseking <martin.gieseking@uos.de> + + * src/XMLString.cpp, src/utility.cpp, src/utility.hpp, + tests/UtilityTest.cpp: + added util::to_string(double) that strips trailing zeros +(in contrast to + std::to_string) + + * src/CMapManager.cpp, src/CMapReader.cpp, src/DVIReader.cpp, + src/GFReader.cpp, src/JFM.cpp, src/Length.cpp, src/MapLine.cpp, + src/Matrix.cpp, src/PDFParser.cpp, src/SVGOutput.cpp, src/VFReader.cpp: + replaced some string streams with plain strings + +2019-07-08 Martin Gieseking <martin.gieseking@uos.de> + + * README.md: + updated badges in README + + * src/Font.cpp, src/Font.hpp, src/dvisvgm.cpp: + changed type of CACHE_PATH to std::string + +2019-07-07 Martin Gieseking <martin.gieseking@uos.de> + + * .github/FUNDING.yml: + added funding.yml + +2019-07-06 Martin Gieseking <martin.gieseking@uos.de> + + * src/DVIToSVG.cpp: + properly assign collected chars to unique fonts (fixes #110) + +2019-06-18 Martin Gieseking <martin.gieseking@uos.de> + + * doc/dvisvgm.txt.in: + manpage: updated \special example + +2019-06-17 Martin Gieseking <martin.gieseking@uos.de> + + * src/BasicDVIReader.cpp: + replaced string streams with plain strings + +2019-06-11 Martin Gieseking <martin.gieseking@uos.de> + + * tests/genhashcheck.py: + use range-based loop to iterate over C array + +2019-06-07 Martin Gieseking <martin.gieseking@uos.de> + + * .appveyor.yml, .travis.yml, configure.ac, src/Doxyfile, src/version.hpp: + set version to 2.7.2 + + * NEWS: + updated NEWS + +2019-05-29 Martin Gieseking <martin.gieseking@uos.de> + + * src/psdefs.cpp: + 'GS_PDF_ProcSet' and 'pdfdict' are private as of GS 9.27 +As a workaround + 'runpdfbegin' and 'runpdfend' can be used to enter/leave the + dictionaries. + +2019-05-20 Martin Gieseking <martin.gieseking@uos.de> + + * .appveyor.yml, .travis.yml, configure.ac, src/Doxyfile, src/version.hpp: + set version to 2.7.1 + + * NEWS: + updated NEWS + +2019-05-10 Martin Gieseking <martin.gieseking@uos.de> + + * .appveyor.yml, .gitignore, src/MiKTeXCom.hpp: + added files required to access the MiKTeX session object + +2019-05-06 Martin Gieseking <martin.gieseking@uos.de> + + * src/psdefs.cpp: + pop unused operand in PS operator 'setmatrix' (closes #106) + +2019-04-18 Martin Gieseking <martin.gieseking@uos.de> + + * src/optimizer/AttributeExtractor.cpp, src/optimizer/GroupCollapser.cpp, + src/utility.hpp: + removed util::make_array() due to compatibility + issues +https://trac.macports.org/ticket/58347 + +2019-04-17 Martin Gieseking <martin.gieseking@uos.de> + + * README, README.md: + updated URL of FontForge website + +2019-04-15 Martin Gieseking <martin.gieseking@uos.de> + + * README.md: + removed Coverity badge as the service seems to be dead + +2019-04-14 Martin Gieseking <martin.gieseking@uos.de> + + * src/Makefile.am: + add file windows.hpp to source tarball + +2019-04-13 Martin Gieseking <martin.gieseking@uos.de> + + * .appveyor.yml, .travis.yml, configure.ac, src/Doxyfile, src/version.hpp: + set version to 2.7 + + * NEWS: + updated NEWS + +2019-04-12 Martin Gieseking <martin.gieseking@uos.de> + + * doc/dvisvgm.txt.in, src/DvisvgmSpecialHandler.cpp: + added specials "bbox lock" and "bbox unlock" to lock/unlock the page + bbox +(closes #105) + + * doc/dvisvgm.txt.in, src/DvisvgmSpecialHandler.cpp: + added optional modifier 'transform' to the dvisvgm:bbox specials + + * doc/dvisvgm.txt.in, src/DvisvgmSpecialHandler.cpp: + added macro {?matrix} to raw specials + +2019-04-11 Martin Gieseking <martin.gieseking@uos.de> + + * src/Bezier.cpp, src/BoundingBox.hpp, src/CMap.hpp, src/CMapReader.hpp, + src/Character.hpp, src/Color.hpp, src/DLLoader.hpp, src/Directory.cpp, + src/Directory.hpp, src/DvisvgmSpecialHandler.cpp, src/EPSFile.hpp, + src/EncFile.hpp, src/FilePath.hpp, src/Font.hpp, src/FontEncoding.hpp, + src/FontMap.hpp, src/FontWriter.cpp, src/FontWriter.hpp, + src/GFTracer.hpp, src/GlyphTracerMessages.hpp, src/GraphicsPath.hpp, + src/InputBuffer.hpp, src/InputReader.hpp, src/JFM.hpp, src/Length.hpp, + src/MD5HashFunction.hpp, src/MapLine.hpp, src/Matrix.cpp, src/Matrix.hpp, + src/Message.hpp, src/PDFParser.cpp, src/PDFParser.hpp, src/PSPattern.hpp, + src/PSPreviewFilter.hpp, src/PageSize.hpp, src/Pair.hpp, + src/PsSpecialHandler.cpp, src/PsSpecialHandler.hpp, + src/SVGCharHandler.hpp, src/SVGCharTspanTextHandler.hpp, + src/SVGOutput.hpp, src/SVGSingleCharTextHandler.hpp, + src/ShadingPatch.hpp, src/SourceInput.hpp, src/StreamReader.hpp, + src/StreamWriter.hpp, src/TFM.hpp, src/TensorProductPatch.hpp, + src/TriangularPatch.hpp, src/TrueTypeFont.hpp, src/VFReader.cpp, + src/VFReader.hpp, src/VectorIterator.hpp, src/VectorStream.hpp, + src/XMLDocument.hpp, src/XMLString.hpp, src/XXHashFunction.hpp, + src/optimizer/DependencyGraph.hpp: + marked most constructors 'explicit' if they may be called with a single + parameter + + * src/DVIReader.cpp, src/DVIToSVG.cpp, src/DVIToSVGActions.cpp, + src/Font.cpp, src/FontEngine.cpp, src/FontManager.cpp, + src/HyperlinkManager.cpp, src/ImageToSVG.cpp, src/PDFParser.hpp, + src/PSInterpreter.cpp, src/PdfSpecialHandler.cpp, + src/PsSpecialHandler.cpp, src/SVGCharHandler.cpp, + src/SVGCharPathHandler.cpp, src/SVGCharTspanTextHandler.cpp, + src/SVGTree.cpp, src/TensorProductPatch.cpp, src/TriangularPatch.cpp, + src/TrueTypeFont.cpp: + use automatic type deduction in conjunction with casts + + * src/EPSFile.cpp, src/EmSpecialHandler.cpp, src/EncFile.cpp, + src/InputReader.cpp, src/PSInterpreter.cpp, src/PsSpecialHandler.cpp, + src/SpecialManager.cpp, src/StreamReader.cpp, src/Subfont.cpp, + src/Unicode.cpp, src/dvisvgm.cpp: + explicitly cast integers representing characeters to char + + * src/CLCommandLine.hpp, src/DvisvgmSpecialHandler.cpp, + src/DvisvgmSpecialHandler.hpp, src/EncFile.cpp, src/Font.cpp, + src/Font.hpp, src/MetafontWrapper.cpp, src/MetafontWrapper.hpp, + src/Process.cpp, src/Process.hpp, src/SVGOutput.cpp, src/SVGOutput.hpp, + src/Subfont.cpp, src/Subfont.hpp: + if possible, move string parameters instead of copying them + + * src/Color.cpp, src/FontEngine.cpp, src/PathClipper.cpp: + use std::lround() rather than truncation + + * src/DVIActions.hpp, src/DVIToSVGActions.hpp, src/Font.hpp, + src/PSInterpreter.cpp, src/SignalHandler.cpp, src/System.cpp: + replaced 0 and NULL with nullptr + + * src/Message.cpp, src/Message.hpp: + drop 'const' from char parameter + + * src/EPSFile.cpp: + replaced C array with std::array + + * src/SpecialManager.hpp, src/ZLibOutputStream.hpp: + made deleted constructor public; use 'default' with default constructor + + * src/PageSize.cpp: + removed redundant semicolons + +2019-04-10 Martin Gieseking <martin.gieseking@uos.de> + + * src/RangeMap.cpp, tests/RangeMapTest.cpp: + use std::accumulate() to compute the number of values mapped by a + RangeMap + +2019-04-09 Martin Gieseking <martin.gieseking@uos.de> + + * doc/dvisvgm.txt.in: + reworded some paragraphs on the manpage + +2019-04-05 Martin Gieseking <martin.gieseking@uos.de> + + * src/DvisvgmSpecialHandler.cpp, src/HtmlSpecialHandler.cpp, + src/InputReader.cpp, src/InputReader.hpp, src/PsSpecialHandler.cpp, + tests/StreamInputBufferTest.cpp: + optionally allow 'flags' (attributes w/o values) in attribute lists + + * src/PsSpecialHandler.cpp: + psfile/pdffile: evaluate boolean attribute 'clip' +If given, the drawing + region is clipped to the bounding box of the +EPS/PDF page being + processed. +(closes #104) + + * .appveyor.yml: + AppVeyor: switched build image to VS 2019 Preview + +2019-04-04 Martin Gieseking <martin.gieseking@uos.de> + + * .appveyor.yml: + AppVeyor: updated release number of ttfautohint-dll + + * m4/ax_cxx_compile_stdcxx.m4: + updated ax_cxx_compile_stdcxx.m4 to version 11 + +2019-04-03 Martin Gieseking <martin.gieseking@uos.de> + + * .appveyor.yml: + AppVeyor: set freetype version to 2.10.0; use current image of VS 2017 + again + + * src/SVGTree.cpp: + fixed gcc 5 failure regarding initializer lists + + * src/FileFinder.cpp: + pdffile special: look for pdf files in texmf tree too (closes #103) + +2019-04-01 Martin Gieseking <martin.gieseking@uos.de> + + * src/optimizer/GroupCollapser.cpp: + group collapser: unwrap groups without attributes + + * src/DVIToSVGActions.hpp, src/DvisvgmSpecialHandler.cpp, + src/DvisvgmSpecialHandler.hpp, src/EmSpecialHandler.cpp, + src/HyperlinkManager.cpp, src/ImageToSVG.hpp, src/PSPattern.cpp, + src/PsSpecialHandler.cpp, src/SpecialActions.hpp, + src/TpicSpecialHandler.cpp, tests/DvisvgmSpecialTest.cpp, + tests/EmSpecialTest.cpp, tests/TpicSpecialTest.cpp: + reduced interface of SpecialActions +- removed append/prepend and context + functions +- added direct access to the SVGTree object + +2019-03-31 Martin Gieseking <martin.gieseking@uos.de> + + * src/XMLNode.cpp, src/XMLNode.hpp, src/optimizer/AttributeExtractor.cpp, + src/optimizer/AttributeExtractor.hpp, src/optimizer/GroupCollapser.cpp, + src/optimizer/RedundantElementRemover.cpp, + src/optimizer/TransformSimplifier.cpp, src/optimizer/WSNodeRemover.cpp, + tests/BoundingBoxTest.cpp, tests/TpicSpecialTest.cpp, + tests/XMLNodeTest.cpp: + refactored the implementation of the XML node classes +for easier + modifications of the XML tree + +2019-03-30 Martin Gieseking <martin.gieseking@uos.de> + + * libs/ff-woff/Makefile.am: + added missing zlib include path to ff-woff + + * src/CMapReader.cpp: + properly release memory if CMap throws an exception + +2019-03-28 Martin Gieseking <martin.gieseking@uos.de> + + * src/GraphicsPath.hpp: + skip redundant line drawing commands in path elements + +2019-03-27 Martin Gieseking <martin.gieseking@uos.de> + + * src/XMLString.cpp, tests/DVIReaderTest.cpp, tests/GFGlyphTracerTest.cpp, + tests/MatrixTest.cpp: + replace "0." by "." in floating point numbers |x| < 1 + + * src/GraphicsPath.hpp, tests/GFGlyphTracerTest.cpp: + avoid redundant space characters in SVG paths + + * src/GraphicsPath.hpp, tests/TpicSpecialTest.cpp: + take precision into account when checking for reflection points + +2019-03-25 Martin Gieseking <martin.gieseking@uos.de> + + * src/Matrix.cpp, src/Matrix.hpp, tests/MatrixTest.cpp: + made Matrix::parse() a static member + + * configure.ac, doc/dvisvgm.txt.in, src/CommandLine.hpp, src/DVIToSVG.cpp, + src/DependencyGraph.hpp, src/ImageToSVG.cpp, src/Makefile.am, + src/SVGOptimizer.cpp, src/SVGOptimizer.hpp, src/SVGTree.cpp, + src/XMLNode.cpp, src/dvisvgm.cpp, src/optimizer/AttributeExtractor.cpp, + src/optimizer/AttributeExtractor.hpp, src/optimizer/CMakeLists.txt, + src/optimizer/DependencyGraph.hpp, src/optimizer/GroupCollapser.cpp, + src/optimizer/GroupCollapser.hpp, src/optimizer/Makefile.am, + src/optimizer/OptimizerModule.hpp, + src/optimizer/RedundantElementRemover.cpp, + src/optimizer/RedundantElementRemover.hpp, + src/optimizer/SVGOptimizer.cpp, src/optimizer/SVGOptimizer.hpp, + src/optimizer/TransformSimplifier.cpp, + src/optimizer/TransformSimplifier.hpp, src/optimizer/WSNodeRemover.cpp, + src/optimizer/WSNodeRemover.hpp, src/options.xml, + tests/DependencyGraphTest.cpp, tests/Makefile.am, tests/create-makefile: + moved optimizer classes to subdirectory + +2019-03-24 Martin Gieseking <martin.gieseking@uos.de> + + * src/Matrix.cpp, src/Matrix.hpp, src/PsSpecialHandler.cpp, + tests/MatrixTest.cpp: + swapped Matrix::lmultiply and Matrix::rmultiply + + * src/Matrix.cpp, src/Matrix.hpp, src/SVGOptimizer.cpp, + src/SVGOptimizer.hpp, src/utility.hpp, tests/MatrixTest.cpp: + added optimizer to simplify 'transform' attributes + +2019-03-23 Martin Gieseking <martin.gieseking@uos.de> + + * src/SVGOptimizer.cpp, src/SVGOptimizer.hpp, src/XMLNode.cpp, + src/XMLNode.hpp: + remove whitespace nodes before collapsing group elements + +2019-03-22 Martin Gieseking <martin.gieseking@uos.de> + + * src/InputBuffer.hpp: + added StringInputBuffer::assign() to assign a different string + + * src/InputReader.cpp, tests/StreamInputBufferTest.cpp: + replaced constraints for attribute names +- must start with a letter +- + may contain selected non-alphanumeric characters, like '-', '_', and '.' + + * doc/dvisvgm.txt.in, src/DvisvgmSpecialHandler.cpp, + src/DvisvgmSpecialHandler.hpp, src/SVGTree.cpp, src/XMLNode.cpp, + tests/DvisvgmSpecialTest.cpp: + allow split tags distributed over several dvisvgm:raw specials + +2019-03-21 Martin Gieseking <martin.gieseking@uos.de> + + * src/BgColorSpecialHandler.cpp, src/PSPattern.cpp, src/PageRanges.cpp, + src/PathClipper.cpp, src/RangeMap.cpp: + use type 'auto' for local iterator variables + + * src/FilePath.hpp, src/Font.hpp, src/ImageToSVG.hpp, src/PDFParser.hpp, + src/SVGOutput.hpp, src/Subfont.hpp, src/XMLNode.cpp, src/XMLNode.hpp: + use move semantics to initialize string members + +2019-03-20 Martin Gieseking <martin.gieseking@uos.de> + + * src/BasicDVIReader.hpp, src/DVIToSVG.hpp, src/Subfont.hpp: + deleted constructors should be public + + * src/Bezier.cpp, src/Bezier.hpp, src/CMap.hpp, src/CMapReader.cpp, + src/Color.cpp, src/DVIToSVG.hpp, src/DVIToSVGActions.cpp, + src/EmSpecialHandler.cpp, src/EncFile.cpp, src/FileFinder.cpp, + src/FileFinder.hpp, src/FileSystem.cpp, src/Font.cpp, src/FontCache.cpp, + src/FontEncoding.cpp, src/FontEncoding.hpp, src/FontEngine.cpp, + src/FontEngine.hpp, src/FontManager.cpp, src/FontManager.hpp, + src/FontWriter.hpp, src/GFGlyphTracer.cpp, src/GFGlyphTracer.hpp, + src/Ghostscript.cpp, src/Ghostscript.hpp, src/ImageToSVG.cpp, + src/MapLine.cpp, src/MapLine.hpp, src/Message.cpp, src/Message.hpp, + src/NoPsSpecialHandler.hpp, src/PDFParser.cpp, src/PSInterpreter.cpp, + src/PSInterpreter.hpp, src/PathClipper.cpp, src/Process.hpp, + src/SVGCharHandler.hpp, src/SVGCharPathHandler.cpp, + src/SVGCharPathHandler.hpp, src/SVGCharTspanTextHandler.cpp, + src/SVGTree.hpp, src/VFReader.cpp, src/VFReader.hpp, src/XMLNode.cpp, + src/dvisvgm.cpp: + use nullptr instead of 0 + + * src/BoundingBox.hpp, src/CLCommandLine.hpp, src/CMapReader.hpp, + src/Calculator.hpp, src/Font.hpp, src/FontMetrics.hpp, + src/FontWriter.hpp, src/GFReader.hpp, src/Length.hpp, src/MapLine.hpp, + src/Matrix.hpp, src/MessageException.hpp, src/PDFParser.hpp, + src/PSInterpreter.hpp, src/PageSize.hpp, src/ShadingPatch.hpp, + src/SpecialHandler.hpp, src/StreamReader.hpp, src/TrueTypeFont.hpp, + src/VFReader.hpp, src/VectorIterator.hpp, src/ZLibOutputStream.hpp: + made constructors of exception classes explicit + + * src/ZLibOutputStream.hpp: + few modifications of class ZLibOutputStream + + * src/CharMapID.hpp, src/Color.hpp, src/FontCache.hpp, src/Message.cpp, + src/Message.hpp: + ensure initializations of static members don't throw exceptions + + * src/BoundingBox.cpp, src/CMapManager.cpp, src/ColorSpecialHandler.cpp, + src/DvisvgmSpecialHandler.cpp, src/PathClipper.cpp, src/RangeMap.cpp: + replaced some index-based loops with range-based ones + + * src/FilePath.cpp, src/FilePath.hpp: + fixed type used to store directories in class FilePath + + * src/CLCommandLine.cpp: + use emplace_back() instead of push_back() + + * src/FileFinder.cpp, src/Font.hpp, src/TensorProductPatch.hpp, + src/dvisvgm.cpp: + removed redundant 'virtual' modifiers and calls of c_str() + + * src/FontManager.cpp, src/HyperlinkManager.cpp, src/PageSize.cpp: + use spezialized string::find() to look for single characters + + * doc/dvisvgm.txt.in, src/CommandLine.hpp, src/dvisvgm.cpp, + src/options.xml, tests/CommandLineTest.cpp: + renamed option --exact to --exact-bbox +This change is downward + compatible due to partial matching of long options. + + * src/DVIToSVGActions.cpp, src/DvisvgmSpecialHandler.cpp, src/Matrix.cpp, + src/Matrix.hpp, src/PSPattern.cpp, src/PsSpecialHandler.cpp, + src/SVGCharHandler.cpp, src/SVGCharPathHandler.cpp, src/SVGTree.cpp, + tests/MatrixTest.cpp: + renamed and slightly refactored Matrix::getSVG() + +2019-03-19 Martin Gieseking <martin.gieseking@uos.de> + + * doc/dvisvgm.txt.in, src/DVIToSVGActions.hpp, + src/DvisvgmSpecialHandler.cpp, src/DvisvgmSpecialHandler.hpp, + src/HyperlinkManager.cpp, src/ImageToSVG.hpp, src/SVGTree.cpp, + src/SVGTree.hpp, src/SpecialActions.hpp, tests/DvisvgmSpecialTest.cpp: + added context stack for SVG defs section + + * src/DVIToSVG.cpp, src/ImageToSVG.cpp, src/SVGOptimizer.cpp, + src/SVGOptimizer.hpp, src/SVGTree.cpp, src/SVGTree.hpp: + moved removal of redundant clipPath elements to SVGOptimizer + + * doc/dvisvgm.txt.in, src/CommandLine.hpp, src/SVGOptimizer.cpp, + src/SVGOptimizer.hpp, src/dvisvgm.cpp, src/options.xml: + added command-line option --group-attributes + +2019-03-18 Martin Gieseking <martin.gieseking@uos.de> + + * src/Makefile.am: + reformatted file list in Makefile + +2019-03-16 Martin Gieseking <martin.gieseking@uos.de> + + * src/psdefs.cpp: + added processing of PS operators xshow, yshow, and xyshow + +2019-03-15 Martin Gieseking <martin.gieseking@uos.de> + + * libs/xxHash/xxhash.c, libs/xxHash/xxhash.h: + updated xxhash to version 0.7.0 + +2019-03-14 Martin Gieseking <martin.gieseking@uos.de> + + * src/Makefile.am, src/SVGOptimizer.cpp, src/SVGOptimizer.hpp, + src/SVGTree.cpp, src/XMLNode.cpp, src/XMLNode.hpp, src/utility.hpp: + added algorithms to move common attributes to group elements + +2019-03-13 Martin Gieseking <martin.gieseking@uos.de> + + * src/DVIToSVGActions.hpp, src/ImageToSVG.hpp, src/PSPattern.cpp, + src/PSPattern.hpp, src/SVGCharHandler.cpp, src/SVGCharHandler.hpp, + src/SVGTree.cpp, src/SVGTree.hpp, src/SpecialActions.hpp, + src/SpecialManager.cpp, src/SpecialManager.hpp, src/XMLDocument.cpp, + src/XMLDocument.hpp, src/XMLNode.cpp, src/XMLNode.hpp, + tests/DvisvgmSpecialTest.cpp, tests/EmSpecialTest.cpp, + tests/TpicSpecialTest.cpp: + take unique_ptrs by value instead of rvalue reference + +2019-03-12 Martin Gieseking <martin.gieseking@uos.de> + + * src/BoundingBox.cpp, src/BoundingBox.hpp, src/DVIToSVG.cpp, + src/DVIToSVG.hpp, src/DVIToSVGActions.cpp, src/DVIToSVGActions.hpp, + src/DvisvgmSpecialHandler.cpp, src/EmSpecialHandler.cpp, + src/HyperlinkManager.cpp, src/ImageToSVG.cpp, src/ImageToSVG.hpp, + src/PSPattern.cpp, src/PSPattern.hpp, src/PsSpecialHandler.cpp, + src/PsSpecialHandler.hpp, src/SVGCharHandler.cpp, src/SVGCharHandler.hpp, + src/SVGCharPathHandler.cpp, src/SVGCharPathHandler.hpp, + src/SVGCharTspanTextHandler.cpp, src/SVGCharTspanTextHandler.hpp, + src/SVGTree.cpp, src/SVGTree.hpp, src/SpecialActions.hpp, + src/TpicSpecialHandler.cpp, src/XMLDocument.cpp, src/XMLDocument.hpp, + src/XMLNode.cpp, src/XMLNode.hpp, tests/DvisvgmSpecialTest.cpp, + tests/EmSpecialTest.cpp, tests/TpicSpecialTest.cpp, + tests/XMLNodeTest.cpp: + renamed XML node classes + + * src/XMLDocument.cpp, src/XMLNode.cpp, src/XMLNode.hpp, + tests/XMLNodeTest.cpp: + replaced dynamic casts of XML nodes with dedicated cast methods + +2019-03-11 Martin Gieseking <martin.gieseking@uos.de> + + * doc/Makefile.am: + rebuild manpage if configure.ac was updated +A potential change of the + version number should be propagated to the manpage. + + * doc/dvisvgm.txt.in: + manpage: added link to SVG color names + 2019-03-09 Martin Gieseking <martin.gieseking@uos.de> * src/PsSpecialHandler.cpp: imgfile: improved and simplifed code - - compute transformation matrix only once (for image and bbox) - - compute and update bbox only if necessary +- compute transformation matrix + only once (for image and bbox) +- compute and update bbox only if + necessary * .appveyor.yml, .travis.yml, configure.ac, src/Doxyfile, src/version.hpp: set version to 2.6.3 + * NEWS: + updated NEWS + 2019-03-07 Martin Gieseking <martin.gieseking@uos.de> * src/dvisvgm.cpp: @@ -17,7 +885,22 @@ ensure forward slashes in file paths passed to PS oparator 'run' * src/PsSpecialHandler.cpp, src/psdefs.cpp: - ensure forward slashes in file paths passed to PS oparator 'run' + psfile/pdffile: adapt opposite orientation of y-coordinates properly + +2019-02-28 Martin Gieseking <martin.gieseking@uos.de> + + * src/InputReader.cpp, src/InputReader.hpp, + tests/StreamInputBufferTest.cpp, tests/StringMatcherTest.cpp: + added StringMatcher::read() + + * src/DvisvgmSpecialHandler.cpp, src/DvisvgmSpecialHandler.hpp, + src/InputReader.cpp, tests/DvisvgmSpecialTest.cpp: + parse raw specials and create proper XML nodes + +2019-02-26 Martin Gieseking <martin.gieseking@uos.de> + + * src/DvisvgmSpecialHandler.cpp, src/FontWriter.cpp: + replaced lookup loops with std::find_if 2019-02-25 Martin Gieseking <martin.gieseking@uos.de> diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/Makefile.in b/Build/source/texk/dvisvgm/dvisvgm-src/Makefile.in index b92cc984869..447627d9fa7 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/Makefile.in +++ b/Build/source/texk/dvisvgm/dvisvgm-src/Makefile.in @@ -166,7 +166,8 @@ ETAGS = etags CTAGS = ctags DIST_SUBDIRS = $(SUBDIRS) am__DIST_COMMON = $(srcdir)/Makefile.in AUTHORS COPYING ChangeLog \ - INSTALL NEWS README + INSTALL NEWS README ar-lib compile config.guess config.sub \ + depcomp install-sh ltmain.sh missing DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/NEWS b/Build/source/texk/dvisvgm/dvisvgm-src/NEWS index 7c799314f37..301a2de7a65 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/NEWS +++ b/Build/source/texk/dvisvgm/dvisvgm-src/NEWS @@ -1,3 +1,68 @@ +dvisvgm-2.8.1 (2019-11-14) +- added SVG optimizer module 'simplify-text' +- added support for PS operator 'nulldevice' +- copy absolute paths from special 'psfile' unchanged to the SVG file +- some code refactorings + +dvisvgm-2.8 (2019-10-25) +- added support for JPEG, PNG, PDF, and SVG files to special 'psfile' +- added support for Ghostscript 9.50 +- added support for elliptical arc segments in graphics paths +- added support for CMap operator 'begincidchar' (patch by Akira Kakuto) +- added suport for experimental 128-bit XXH3 hashes +- extended optimizer module 'simplify-transform' to incorporate translation and + scaling components into positional and size attributes +- replaced CRC32 checksums used in cache files with XXH32 hashes +- updated potrace to version 1.16 +- updated xxHash to version 0.7.2 +- updated gtest to 1.10 +- lots of code refactorings + +dvisvgm-2.7.4 (2019-07-28) +- fixed memory issue occurred when calling Metafont +- fixed rounding issue in color conversion (GH #116) +- changed location of cache files from ~/.dvisvgm/cache to + $XDG_CACHE_HOME/dvisvgm which usually expands to ~/.cache/dvisvgm (GH #112) +- some minor refactorings + +dvisvgm-2.7.3 (2019-07-12) +- fixed randomly missing glyph paths referenced by 'use' elements (GH #110) +- minor update of the man page +- some code refactorings + +dvisvgm-2.7.2 (2019-06-07) +- adapted PostScript handler to incompatible changes introduced with + Ghostscript 9.27 (removal of GS_PDF_ProcSet and pdfdict) + +dvisvgm-2.7.1 (2019-05-20) +- fixed a bug in PS operator 'setmatrix' (GH #106) +- fixed build issue reported on MacPorts + (https://trac.macports.org/ticket/58347) +- added source files required to access the MIKTeX session object + (required due to deprecation of the MiKTeX SDK) + +dvisvgm-2.7 (2019-04-13) +- added option --optimize to perform several optimizations on the + generated SVG files (current optimizer modules: collapse-groups, + group-attributes, remove-clippath, simplify-transform) (GH #97) +- dvisvgm's "raw" specials are now parsed and converted to proper XML nodes +- several improvements to SVG graphics path descriptions: + * omit redundant spaces and leading zeros + * omit line commands representing zero-length lines + * improved detection of reflected control points in Bézier curve sequences +- added evaluation of PS operators xshow, yshow, and xyshow +- added evaluation of psfile/pdffile attribute 'clip' to clip the + drawing region to the bounding box of the image being processed (GH #104) +- added specials 'dvisvgm:bbox lock' and 'dvisvgm:bbox unlock' to disable and + enable updating the bounding box of the current page (GH #105) +- added optional modifier 'transform' to dvisvgm:bbox specials to allow for + applying the current transformation to the bounding box +- added macro '{?matrix}' to dvisvgm's 'raw' specials that expands to the + current transformation matrix +- renamed option --exact to --exact-bbox (backward compatible change) +- updated the bundled xxHash library to version 0.7.0 +- lots of code refactorings + dvisvgm-2.6.3 (2019-03-09) - create short RGB hex values for color attributes if possible - fixed rejection of paper formats, like A4, by option --bbox diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/README b/Build/source/texk/dvisvgm/dvisvgm-src/README index 7f0cd47de42..dd9513702ec 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/README +++ b/Build/source/texk/dvisvgm/dvisvgm-src/README @@ -14,7 +14,7 @@ DEPENDENCIES to polygons, intersects them using Clipper, and reconstructs the curves afterwards. - * FontForge library (https://www.fontforge.org) + * FontForge library (https://fontforge.github.io) dvisvgm can be built with optional WOFF support that allows to embed the font data in WOFF or TrueType format rather than as SVG. The FontForge library provides the required functions to create font files in these diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/configure.ac b/Build/source/texk/dvisvgm/dvisvgm-src/configure.ac index 306a2821464..9421ad61527 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/configure.ac +++ b/Build/source/texk/dvisvgm/dvisvgm-src/configure.ac @@ -1,78 +1,63 @@ -# This file is part of dvisvgm -# Copyright (C) 2005-2019 Martin Gieseking <martin.gieseking@uos.de> -# -# Process this file with autoconf to produce a configure script. - -AC_PREREQ(2.59) -AC_INIT([dvisvgm],[2.6.3],[martin.gieseking@uos.de]) -DATE="March 2019" -AC_CONFIG_SRCDIR(src) +# $Id: configure.ac 49819 2019-01-25 23:20:32Z karl $ +dnl Process this file with autoconf to produce a configure script +dnl for dvisvgm in TeX Live. +dnl +dnl Copyright 2015-2019 Karl Berry <tex-live@tug.org> +dnl Copyright 2009-2014 Peter Breitenlohner <tex-live@tug.org> +dnl +dnl This file is free software; the copyright holder +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. +dnl +dnl Adapted for TeX Live from original dvisvgm configure.ac +dnl Copyright 2005-2019 Martin Gieseking +dnl +AC_PREREQ([2.65]) +m4_include([version.ac])[] dnl define dvisvgm_version +AC_INIT([dvisvgm (TeX Live)], dvisvgm_version, [tex-k@tug.org]) +DATE="November 2019" +AC_CONFIG_SRCDIR([dvisvgm-src/src/dvisvgm.cpp]) AC_CONFIG_HEADERS([config.h]) -AC_CONFIG_MACRO_DIR([m4]) -AC_CANONICAL_HOST -AC_CANONICAL_TARGET -AM_INIT_AUTOMAKE([subdir-objects]) +AC_CONFIG_MACRO_DIRS([../../m4])dnl not just _DIR +AC_CONFIG_AUX_DIR([../../build-aux]) + +AM_CONDITIONAL([TEXLIVE_BUILD], [test "x$enable_texlive_build" = xyes]) + +# Common code for all programs using libkpathsea. +# PROG_AR must be run before KPSE_COMMON, since the latter calls LT_INIT. +AM_PROG_AR +KPSE_COMMON([dvisvgm]) AH_TEMPLATE([TARGET_SYSTEM], [The machine triplet of the target system]) AC_DEFINE_UNQUOTED([TARGET_SYSTEM], ["$target"]) -# Checks for programs. AC_PROG_CC AC_PROG_CC_C99 AC_PROG_CXX AX_CXX_COMPILE_STDCXX([11]) -AM_PROG_AR LT_INIT +KPSE_CXX_HACK AC_PROG_RANLIB AC_LANG(C) -AX_CHECK_COMPILE_FLAG([-Wmismatched-tags -Wno-mismatched-tags], [CXXFLAGS="$CXXFLAGS -Wno-mismatched-tags"]) AC_CHECK_HEADERS([sys/time.h sys/timeb.h xlocale.h]) AC_HEADER_TIOCGWINSZ -CPPFLAGS_SAVE="$CPPFLAGS" -CFLAGS_SAVE="$CFLAGS" -LDFLAGS_SAVE="$LDFLAGS" - -# Check availability and usability of the kpathsea library -AC_ARG_VAR(KPSE_CFLAGS, [C/C++ compiler flags for the kpathsea library]) -AC_ARG_VAR(KPSE_LIBS, [linker flags for the kpathsea library]) -AC_ARG_VAR(KPSE_LIBS, []) -AC_ARG_WITH([kpathsea], - [AS_HELP_STRING([--with-kpathsea=prefix], [set location of kpathsea library])], - [with_kpathsea="$withval"], - [with_kpathsea=yes]) - -AS_IF([test "x$with_kpathsea" != "xyes"], - [KPSE_CFLAGS="-I$with_kpathsea/include" KPSE_LIBS="-L$with_kpathsea/lib"] - [CPPFLAGS="$CPPFLAGS $KPSE_CFLAGS" CFLAGS="$CFLAGS $KPSE_CFLAGS" LDFLAGS="$LDFLAGS $KPSE_LIBS"]) - -AC_CHECK_HEADER([kpathsea/kpathsea.h],, - [AC_MSG_ERROR([please install the kpathsea development package])]) -AC_CHECK_LIB([kpathsea], [kpse_find_file],, - [AC_MSG_ERROR([libkpathsea not found, please install the corresponding package first])]) - -AC_MSG_CHECKING([kpathsea version]) -AC_RUN_IFELSE([AC_LANG_SOURCE([#include <stdio.h> - #include <kpathsea/kpathsea.h> - int main() { - FILE *f; - f = fopen("kpseversion", "w"); - if(!f) exit(1); - fprintf(f, "%s\n", KPSEVERSION); - fclose(f); - exit(0); - }])], - [kpseversion=`cat kpseversion|sed 's/kpathsea version //'`], [kpseversion=], [kpseversion=unknown]) -AC_MSG_RESULT("$kpseversion") -rm -f kpseversion -AS_IF([test -z "$kpseversion"], - [AC_MSG_ERROR([Could not compile a simple kpathsea program -- check your installation])]) -AC_SUBST(KPSE_CFLAGS) -AC_SUBST(KPSE_LIBS) - -# Check how to link Ghostscript +KPSE_COND_WIN32 +KPSE_KPATHSEA_FLAGS +KPSE_FREETYPE2_FLAGS +KPSE_ZLIB_FLAGS + +KPSE_SAVE_FLAGS + +# emacs-page Ghostscript complexities. +LIBGS_INCLUDES= +LIBGS_LIBS= +if test "x$enable_native_texlive_build" = xyes; then + # TL: always dlload libgs, must avoid shared lib ref in binary. + HAVE_LIBGS=0 +else have_libgs=yes AC_CHECK_HEADER([ghostscript/iapi.h], [AC_CHECK_LIB(gs, gsapi_revision,, [have_libgs=no])], @@ -82,68 +67,87 @@ AS_IF([test "x$have_libgs" = "xno"], [AC_CHECK_LIB(dl, dlopen,, [AC_DEFINE(DISABLE_GS, 1, [Set to 1 if PostScript support should be disabled])] [AC_MSG_WARN(PostScript support disabled)])]) +fi + +if test -z "$HAVE_LIBGS" || test "$HAVE_LIBGS" -eq 0; then + AC_MSG_NOTICE([not linking to libgs, trying to arrange for dynamic loading]) + # Windows (native or MinGW32) has neither <dlfcn.h> nor dlopen(). + if test "x$kpse_cv_have_win32" = xno; then + # FreeBSD neither has nor requires libdl. + AC_SEARCH_LIBS([dlopen], [dl]) + AS_CASE([$ac_cv_search_dlopen], + [no | "none required"], [], + [LIBGS_LIBS=$ac_cv_search_dlopen]) + AC_CHECK_HEADER([dlfcn.h]) + AC_CHECK_FUNC([dlopen]) + if test "x$ac_cv_header_dlfcn_h:$ac_cv_func_dlopen" != xyes:yes; then + AC_DEFINE(DISABLE_GS, 1, + [Set to 1 if PostScript support is to be disabled]) + LIBGS_LIBS= + fi + fi +else + # query Ghostscript version + AC_MSG_CHECKING([Ghostscript version]) + AC_RUN_IFELSE([AC_LANG_SOURCE([#include <stdio.h> + #include <ghostscript/iapi.h> + int main () { + gsapi_revision_t r; + if (gsapi_revision(&r, sizeof(gsapi_revision_t)) == 0) { + FILE *f; + f = fopen("gsversion", "w"); + if (!f) exit(1); + fprintf(f, "%ld\n", r.revision); + fclose(f); + exit(0); + } + }])], + [gsversion=`cat gsversion`], [gsversion=], [gsversion=unknown]) + AC_MSG_RESULT("$gsversion") + rm -f gsversion + if test -z "$gsversion" || test "$gsversion" -lt 831; then + # current Ghostscript API was introduced in version 8.31 + # older versions are not supported + AC_DEFINE(DISABLE_GS, 1, [Set to 1 if PostScript support should be disabled]) + AC_MSG_WARN([Ghostscript version < 8.31 found; PostScript support disabled]) + else + LIBGS_LIBS=-lgs + fi +fi +AC_SUBST([LIBGS_INCLUDES]) +AC_SUBST([LIBGS_LIBS]) + +if test "x$enable_build" != xno || test -f config.force; then + +# Checks for more libraries. +KPSE_ADD_FLAGS([zlib]) +AC_CHECK_FUNC([gzopen], [], + [AC_MSG_ERROR([cannot find/use zlib])]) + +KPSE_ADD_FLAGS([freetype2]) +AC_CHECK_FUNC([FT_Init_FreeType], [], + [AC_MSG_ERROR([cannot find/use libfreetype])]) + +KPSE_ADD_FLAGS([kpathsea]) +AC_CHECK_FUNC([kpse_set_program_name], [], + [AC_MSG_ERROR([cannot find/use libkpathsea])]) + +# Check if the kpathsea headers are C++ safe. +AC_LANG_PUSH([C++]) +AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <kpathsea/kpathsea.h>]], + [[printf("%s\n", concat("one", "two"))]])], + [], + [AC_MSG_ERROR([Sorry, your kpathsea headers are too old]) + AC_DEFINE([KPSE_CXX_UNSAFE], 1, + [Define to 1 if the kpathsea headers are not C++ safe.])]) +AC_LANG_POP([C++]) -# Check for pkg-config -PKG_PROG_PKG_CONFIG - -# Check for libraries. -PKG_CHECK_MODULES([FREETYPE], [freetype2]) - -AC_ARG_ENABLE([woff], - [AS_HELP_STRING([--disable-woff], [Disable WOFF support @<:@default=no@:>@])], - [], - [enable_woff=yes]) -AM_CONDITIONAL([ENABLE_WOFF], [test "x$enable_woff" = "xyes"]) - -AC_ARG_WITH([ttfautohint], - [AS_HELP_STRING([--with-ttfautohint@<:@=prefix@:>@], [enable ttfautohint support (disabled by default)])], - [with_ttfautohint="$withval"], - [with_ttfautohint=no]) +echo timestamp >config.force +fi -# Add option to enable linking of bundled libraries (brotli, potrace, woff2, xxhash). -AC_ARG_ENABLE([bundled-libs], - [AS_HELP_STRING([--enable-bundled-libs], [use bundled libraries instead of the system ones @<:@default=no@:>@])]) -AM_CONDITIONAL([USE_BUNDLED_LIBS], [test "x$enable_bundled_libs" = "xyes"]) - -# If option --enable-bundled-libs is not given, look for system libraries of brotli, potrace, woff2, and xxhash. -AS_IF([test "x$enable_bundled_libs" != "xyes"], - [AC_CHECK_HEADER(potracelib.h, - [AC_SEARCH_LIBS(potrace_trace, [potrace], [have_potrace=yes])])] - [AC_CHECK_HEADER([xxhash.h], - [AC_SEARCH_LIBS(XXH32, [xxhash], [have_xxhash=yes])])] - [AS_IF([test "x$enable_woff" = "xyes"], - [PKG_CHECK_MODULES(BROTLI, [libbrotlienc], [have_brotli=yes])] - [PKG_CHECK_MODULES(WOFF2, [libwoff2enc], [have_woff2=yes])])]) -AM_CONDITIONAL(HAVE_POTRACE, [test "x$have_potrace" = "xyes"]) -AM_CONDITIONAL(HAVE_BROTLI, [test "x$have_brotli" = "xyes"]) -AM_CONDITIONAL(HAVE_WOFF2, [test "x$have_woff2" = "xyes"]) -AM_CONDITIONAL(HAVE_XXHASH, [test "x$have_xxhash" = "xyes"]) - -AS_IF([test "x$enable_woff" != "xyes"], - [AC_DEFINE([DISABLE_WOFF], 1, [Define if WOFF support is disabled])], - [AS_IF([test "x$with_ttfautohint" != "xno"], - [AS_IF([test "x$with_ttfautohint" = "xyes"], - # --with-ttfautohint without path => check via pkg-config - [PKG_CHECK_MODULES([TTFAUTOHINT], [ttfautohint],, - [AC_MSG_ERROR([can't locate ttfautohint, use "--with-ttfautohint=path" to specify its location])])], - # --with-ttfautohint=/path/ttfautohint given - [TTFAUTOHINT_CFLAGS="-I$with_ttfautohint/include"] - [TTFAUTOHINT_LIBS="-L$with_ttfautohint/lib"])] - [CPPFLAGS="$CPPFLAGS $TTFAUTOHINT_CFLAGS" CFLAGS="$CFLAGS $TTFAUTOHINT_CFLAGS" LDFLAGS="$LDFLAGS $TTFAUTOHINT_LIBS"] - [AC_CHECK_HEADERS([ttfautohint.h],, [AC_MSG_WARN([ttfautohint.h not found])])] - [AC_CHECK_LIB([ttfautohint], [TTF_autohint],, - [AC_MSG_WARN([no working ttfautohint library found])] - [AC_CHECK_LIB(dl, dlopen, - [AC_MSG_NOTICE([enabled dynamic loading of ttfautohint])], - [AC_MSG_WARN([disabled ttfautohint support])])])] - [AC_SUBST(TTFAUTOHINT_CFLAGS) AC_SUBST(TTFAUTOHINT_LIBS)])]) - -AC_CHECK_HEADERS([openssl/md5.h]) -PKG_CHECK_MODULES([LIBCRYPTO], [libcrypto], [HAVE_LIBCRYPTO=1], [HAVE_LIBCRYPTO=0]) -AM_CONDITIONAL([USE_BUNDLED_MD5], [test "$HAVE_LIBCRYPTO" -eq 0]) - -AC_CHECK_LIB(z, gzopen) +KPSE_RESTORE_FLAGS +# emacs-page # Check for header files. AC_HEADER_DIRENT AC_HEADER_STDC @@ -158,61 +162,50 @@ AC_STRUCT_TM AC_FUNC_STAT AC_CHECK_FUNCS_ONCE([ftime gettimeofday sigaction umask uselocale]) -# add options for selection of "optional" library locations -# currently these libraries are mandatory; the --with-foo options -# are used to specify the locations explicitely - -AC_ARG_WITH(zlib, - [AS_HELP_STRING([--with-zlib=DIR], [set location of the zlib library])], - [AS_IF([test "x$withval" != "xno"], - [AS_IF([test "x$withval" != "xyes"], [ZLIB_DIR=$withval])] - [AS_IF([test -n "$ZLIB_DIR"], - [ZLIB_CFLAGS="-I$ZLIB_DIR -I$ZLIB_DIR/include"] - [ZLIB_LIBS="-L$ZLIB_DIR/lib" -lz])])]) - -AC_SUBST([ZLIB_CFLAGS]) -AC_SUBST([ZLIB_LIBS]) - -# Check if the kpathsea headers are C++ safe -AC_MSG_CHECKING([if the kpathsea headers are C++ safe]) -AC_LANG_PUSH([C++]) -AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <kpathsea/kpathsea.h>]], - [[printf("%s\n", concat("one", "two"))]])], - [AC_MSG_RESULT([yes])], - [AC_MSG_RESULT([no]) - AC_DEFINE([KPSE_CXX_UNSAFE], 1, - [Define to 1 if the kpathsea headers are not C++ safe.])]) -AC_LANG_POP([C++]) +AC_ARG_ENABLE([woff], + [AS_HELP_STRING([--disable-woff], [Disable WOFF support @<:@default=no@:>@])], + [], + [enable_woff=yes]) +AM_CONDITIONAL([ENABLE_WOFF], [test "x$enable_woff" = "xyes"]) -CPPFLAGS="$CPPFLAGS_SAVE" -CFLAGS="$CFLAGS_SAVE" -LDFLAGS="$LDFLAGS_SAVE" - -AC_ARG_ENABLE([manpage], - [AS_HELP_STRING([--disable-manpage], [disable generation of manual page @<:@default=no@:>@])]) -AS_IF([test "x$enable_manpage" != "xno"],[ - enable_manpage="no" - # Check for utilities required to build the manpage - AC_CHECK_PROG(ASCIIDOC, asciidoc, yes) - AS_IF([test "x$ASCIIDOC" = "xyes"], [ - AC_CHECK_PROG(XMLTO, xmlto, yes) - AS_IF([test "x$XMLTO" = "xyes"], [ - AC_CHECK_PROG(XSLTPROC, xsltproc, yes) - AS_IF([test "x$XSLTPROC" = "xyes"],[enable_manpage="yes"])])])]) -AS_IF([test "x$enable_manpage" != "xyes"], - AC_MSG_NOTICE([generation of manual page has been disabled])) -AM_CONDITIONAL([BUILD_MANPAGE], [test "x$enable_manpage" = "xyes"]) - -AX_CODE_COVERAGE -AS_IF([ test "$enable_code_coverage" = "yes" ], [ - # disable optimization - changequote({,}) - CFLAGS=`echo $CFLAGS | sed 's/-O[1-9s]//g'` - CXXFLAGS=`echo $CXXFLAGS | sed 's/-O[1-9s]//g'` - changequote([,]) -]) - -AC_SUBST([dvisvgm_srcdir], ['$(top_srcdir)']) +# TL: skip ttfautohint? +# Add option to enable linking of bundled libraries (brotli, potrace, woff2, xxhash). +AC_ARG_ENABLE([bundled-libs], + [AS_HELP_STRING([--enable-bundled-libs], [use bundled libraries instead of the system ones @<:@default=no@:>@])], + [use_bundled_libs=yes]) +AM_CONDITIONAL([USE_BUNDLED_LIBS], [test "x$use_bundled_libs" = "xyes" dnl + || test "x$enable_native_texlive_build" = xyes]) +# that is, force using bundled libs for native TL build. + +# TL: use bundled md5 too +AM_CONDITIONAL([USE_BUNDLED_MD5], true) + +# TL: these conditionals for system libraries are in the Makefile.am's. +AM_CONDITIONAL(HAVE_POTRACE, false) +AM_CONDITIONAL(HAVE_BROTLI, false) +AM_CONDITIONAL(HAVE_WOFF2, false) +AM_CONDITIONAL(HAVE_XXHASH, false) + +# TL: not going to build_manpage (which is the default). +# TL: not going to attempt code coverage; need to subst it away. +AM_CONDITIONAL([CODE_COVERAGE_ENABLED], false) +CODE_COVERAGE_RULES= +AC_SUBST([CODE_COVERAGE_RULES]) + +# TL: the original configure calls pkg_check_modules, +# which calls ac_arg_var on the _cflags and _libs for various libraries, +# which calls ac_subst. we'll just ac_subst them to get initial (empty) +# definitions, so we can retain the += used by the original lib/defs.am. +# (init brotli) +AC_SUBST(BROTLI_CFLAGS) +AC_SUBST(BROTLI_LIBS) +# (init woff2) +AC_SUBST(WOFF2_CFLAGS) +AC_SUBST(WOFF2_LIBS) + +AC_SUBST([DVISVGM_TREE], [dvisvgm-src]) + +AC_SUBST([dvisvgm_srcdir], ['$(top_srcdir)/dvisvgm-src']) AC_SUBST(DATE) AC_SUBST(AM_CPPFLAGS) AC_SUBST(AM_LDFLAGS) @@ -230,6 +223,7 @@ AC_CONFIG_FILES([ m4/Makefile src/Makefile src/version.hpp + src/optimizer/Makefile tests/Makefile tests/data/Makefile doc/Makefile]) diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/doc/Makefile.am b/Build/source/texk/dvisvgm/dvisvgm-src/doc/Makefile.am index d9a6037e937..a2bc63bd2e4 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/doc/Makefile.am +++ b/Build/source/texk/dvisvgm/dvisvgm-src/doc/Makefile.am @@ -10,20 +10,27 @@ if BUILD_MANPAGE man_MANS = dvisvgm.1 endif -EXTRA_DIST = $(man_MANS) conf-dblatex-man.xsl conf-dblatex-pdf.xsl dvisvgm.sty dvisvgm.txt.in tweak-dblatex-pdf.xsl tweak-db-refentry.xsl +EXTRA_DIST = $(man_MANS) \ + conf-dblatex-man.xsl \ + conf-dblatex-pdf.xsl \ + dvisvgm.txt.in \ + generate-dvisvgm-sty.xsl \ + tweak-dblatex-pdf.xsl \ + tweak-db-refentry.xsl CONF_DBLATEX_MAN = $(dvisvgm_srcdir)/doc/conf-dblatex-man.xsl CONF_DBLATEX_PDF = $(dvisvgm_srcdir)/doc/conf-dblatex-pdf.xsl TWEAK_DBLATEX_PDF = $(dvisvgm_srcdir)/doc/tweak-dblatex-pdf.xsl TWEAK_DB_ARTICLE = $(dvisvgm_srcdir)/doc/tweak-db-article.xsl TWEAK_DB_REFENTRY = $(dvisvgm_srcdir)/doc/tweak-db-refentry.xsl +GEN_DBLATEX_STY = $(dvisvgm_srcdir)/doc/generate-dvisvgm-sty.xsl DB_VARS = man.endnotes.list.enabled=0 man.endnotes.are.numbered=0 man.authors.section.enabled=0 dvisvgm.1: dvisvgm-man.xml $(CONF_DBLATEX_MAN) xmlto -m $(CONF_DBLATEX_MAN) $(addprefix --stringparam , $(DB_VARS)) man $< -dvisvgm.pdf: dvisvgm-man.xml $(CONF_DBLATEX_PDF) $(TWEAK_DBLATEX_PDF) +dvisvgm.pdf: dvisvgm-man.xml dvisvgm.sty $(CONF_DBLATEX_PDF) $(TWEAK_DBLATEX_PDF) mv $< $<.tmp xsltproc -o $< $(TWEAK_DBLATEX_PDF) $<.tmp dblatex -bxetex --texstyle=./dvisvgm.sty -p $(CONF_DBLATEX_PDF) $< @@ -44,22 +51,28 @@ dvisvgm.epub: dvisvgm-article.xml a2x -darticle -fepub -L --icons --icons-dir=. $< mv $(basename $<).epub $@ -.SECONDARY: dvisvgm-article.xml dvisvgm-man.xml +.SECONDARY: dvisvgm-article.xml dvisvgm-man.xml dvisvgm.sty dvisvgm-man.xml: dvisvgm.txt $(TWEAK_DB_REFENTRY) asciidoc -a icons -a 'iconsdir=.' -a badges -a 'revnumber=@VERSION@' --unsafe -bdocbook -dmanpage -o $@.tmp $< xsltproc -o $@ $(TWEAK_DB_REFENTRY) $@.tmp rm $@.tmp -dvisvgm-article.xml: dvisvgm.txt +dvisvgm-article.xml: dvisvgm.txt $(TWEAK_DB_ARTICLE) asciidoc -a icons -a 'iconsdir=.' -a badges -a 'revnumber=@VERSION@' --unsafe -bdocbook -darticle -o $@.tmp $< xsltproc -o $@ $(TWEAK_DB_ARTICLE) $@.tmp rm $@.tmp sed -i "s/{VERSION}/@VERSION@/" $@ -dvisvgm.txt: dvisvgm.txt.in +dvisvgm.sty: dvisvgm-man.xml $(GEN_DBLATEX_STY) + xsltproc -o dvisvgm.sty $(GEN_DBLATEX_STY) $< + +dvisvgm.txt: dvisvgm.txt.in ../configure.ac sed -e 's/@VERSION[@]/@VERSION@/g' -e 's/@PACKAGE_BUGREPORT[@]/@PACKAGE_BUGREPORT@/g' $< >$@ - touch -r $< $@ + if [ $< -nt ../configure.ac ]; \ + then touch -r $< $@; \ + else touch -r ../configure.ac $@; \ + fi epub: dvisvgm.epub html: dvisvgm.html @@ -67,10 +80,10 @@ man: dvisvgm.1 pdf: dvisvgm.pdf clean: - rm -f dvisvgm.pdf dvisvgm.html dvisvgm-man.xml dvisvgm-article.xml dvisvgm.txt dvisvgm.dvi dvisvgm.epub + rm -f dvisvgm.pdf dvisvgm.html dvisvgm-man.xml dvisvgm-article.xml dvisvgm.txt dvisvgm.sty dvisvgm.dvi dvisvgm.epub distclean-local: - rm -f dvisvgm.pdf dvisvgm.html dvisvgm-man.xml dvisvgm-article.xml dvisvgm.txt dvisvgm.dvi dvisvgm.epub dvisvgm.1 + rm -f dvisvgm.pdf dvisvgm.html dvisvgm-man.xml dvisvgm-article.xml dvisvgm.txt dvisvgm.sty dvisvgm.dvi dvisvgm.epub dvisvgm.1 # Ensure that distribution tarballs always contain a recent manpage, i.e. # let "make dist" and "make distcheck" fail if dvisvgm.1 can't be built. diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/doc/Makefile.in b/Build/source/texk/dvisvgm/dvisvgm-src/doc/Makefile.in index 971a1180a3a..b5bf93ce6b9 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/doc/Makefile.in +++ b/Build/source/texk/dvisvgm/dvisvgm-src/doc/Makefile.in @@ -319,12 +319,20 @@ top_srcdir = @top_srcdir@ # However, the distribution tarball should always contain a recent manpage. We ensure # this by adding a dist-hook rule below. @BUILD_MANPAGE_TRUE@man_MANS = dvisvgm.1 -EXTRA_DIST = $(man_MANS) conf-dblatex-man.xsl conf-dblatex-pdf.xsl dvisvgm.sty dvisvgm.txt.in tweak-dblatex-pdf.xsl tweak-db-refentry.xsl +EXTRA_DIST = $(man_MANS) \ + conf-dblatex-man.xsl \ + conf-dblatex-pdf.xsl \ + dvisvgm.txt.in \ + generate-dvisvgm-sty.xsl \ + tweak-dblatex-pdf.xsl \ + tweak-db-refentry.xsl + CONF_DBLATEX_MAN = $(dvisvgm_srcdir)/doc/conf-dblatex-man.xsl CONF_DBLATEX_PDF = $(dvisvgm_srcdir)/doc/conf-dblatex-pdf.xsl TWEAK_DBLATEX_PDF = $(dvisvgm_srcdir)/doc/tweak-dblatex-pdf.xsl TWEAK_DB_ARTICLE = $(dvisvgm_srcdir)/doc/tweak-db-article.xsl TWEAK_DB_REFENTRY = $(dvisvgm_srcdir)/doc/tweak-db-refentry.xsl +GEN_DBLATEX_STY = $(dvisvgm_srcdir)/doc/generate-dvisvgm-sty.xsl DB_VARS = man.endnotes.list.enabled=0 man.endnotes.are.numbered=0 man.authors.section.enabled=0 all: all-am @@ -570,7 +578,7 @@ uninstall-man: uninstall-man1 dvisvgm.1: dvisvgm-man.xml $(CONF_DBLATEX_MAN) xmlto -m $(CONF_DBLATEX_MAN) $(addprefix --stringparam , $(DB_VARS)) man $< -dvisvgm.pdf: dvisvgm-man.xml $(CONF_DBLATEX_PDF) $(TWEAK_DBLATEX_PDF) +dvisvgm.pdf: dvisvgm-man.xml dvisvgm.sty $(CONF_DBLATEX_PDF) $(TWEAK_DBLATEX_PDF) mv $< $<.tmp xsltproc -o $< $(TWEAK_DBLATEX_PDF) $<.tmp dblatex -bxetex --texstyle=./dvisvgm.sty -p $(CONF_DBLATEX_PDF) $< @@ -591,22 +599,28 @@ dvisvgm.epub: dvisvgm-article.xml a2x -darticle -fepub -L --icons --icons-dir=. $< mv $(basename $<).epub $@ -.SECONDARY: dvisvgm-article.xml dvisvgm-man.xml +.SECONDARY: dvisvgm-article.xml dvisvgm-man.xml dvisvgm.sty dvisvgm-man.xml: dvisvgm.txt $(TWEAK_DB_REFENTRY) asciidoc -a icons -a 'iconsdir=.' -a badges -a 'revnumber=@VERSION@' --unsafe -bdocbook -dmanpage -o $@.tmp $< xsltproc -o $@ $(TWEAK_DB_REFENTRY) $@.tmp rm $@.tmp -dvisvgm-article.xml: dvisvgm.txt +dvisvgm-article.xml: dvisvgm.txt $(TWEAK_DB_ARTICLE) asciidoc -a icons -a 'iconsdir=.' -a badges -a 'revnumber=@VERSION@' --unsafe -bdocbook -darticle -o $@.tmp $< xsltproc -o $@ $(TWEAK_DB_ARTICLE) $@.tmp rm $@.tmp sed -i "s/{VERSION}/@VERSION@/" $@ -dvisvgm.txt: dvisvgm.txt.in +dvisvgm.sty: dvisvgm-man.xml $(GEN_DBLATEX_STY) + xsltproc -o dvisvgm.sty $(GEN_DBLATEX_STY) $< + +dvisvgm.txt: dvisvgm.txt.in ../configure.ac sed -e 's/@VERSION[@]/@VERSION@/g' -e 's/@PACKAGE_BUGREPORT[@]/@PACKAGE_BUGREPORT@/g' $< >$@ - touch -r $< $@ + if [ $< -nt ../configure.ac ]; \ + then touch -r $< $@; \ + else touch -r ../configure.ac $@; \ + fi epub: dvisvgm.epub html: dvisvgm.html @@ -614,10 +628,10 @@ man: dvisvgm.1 pdf: dvisvgm.pdf clean: - rm -f dvisvgm.pdf dvisvgm.html dvisvgm-man.xml dvisvgm-article.xml dvisvgm.txt dvisvgm.dvi dvisvgm.epub + rm -f dvisvgm.pdf dvisvgm.html dvisvgm-man.xml dvisvgm-article.xml dvisvgm.txt dvisvgm.sty dvisvgm.dvi dvisvgm.epub distclean-local: - rm -f dvisvgm.pdf dvisvgm.html dvisvgm-man.xml dvisvgm-article.xml dvisvgm.txt dvisvgm.dvi dvisvgm.epub dvisvgm.1 + rm -f dvisvgm.pdf dvisvgm.html dvisvgm-man.xml dvisvgm-article.xml dvisvgm.txt dvisvgm.sty dvisvgm.dvi dvisvgm.epub dvisvgm.1 # Ensure that distribution tarballs always contain a recent manpage, i.e. # let "make dist" and "make distcheck" fail if dvisvgm.1 can't be built. diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/doc/dvisvgm.1 b/Build/source/texk/dvisvgm/dvisvgm-src/doc/dvisvgm.1 index e482b7bfa60..e6d6b8743f1 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/doc/dvisvgm.1 +++ b/Build/source/texk/dvisvgm/dvisvgm-src/doc/dvisvgm.1 @@ -2,12 +2,12 @@ .\" Title: dvisvgm .\" Author: Martin Gieseking <martin.gieseking@uos.de> .\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/> -.\" Date: 03/09/2019 +.\" Date: 2019-11-12 .\" Manual: dvisvgm Manual -.\" Source: dvisvgm 2.6.3 +.\" Source: dvisvgm 2.8.1 .\" Language: English .\" -.TH "DVISVGM" "1" "03/09/2019" "dvisvgm 2\&.6\&.3" "dvisvgm Manual" +.TH "DVISVGM" "1" "2019\-11\-12" "dvisvgm 2\&.8\&.1" "dvisvgm Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -164,7 +164,12 @@ only affects the bounding box and does not transform the page content\&. Hence, \fB\-C, \-\-cache\fR[=\fIdir\fR] .RS 4 To speed up the conversion process of bitmap fonts, dvisvgm saves intermediate conversion information in cache files\&. By default, these files are stored in -\fB$HOME/\&.dvisvgm/cache\fR\&. If you prefer a different location, use option +\fB$XDG_CACHE_HOME/dvisvgm/\fR +or +\fB$HOME/\&.cache/dvisvgm\fR +if +\fBXDG_CACHE_HOME\fR +is not set\&. If you prefer a different location, use option \fB\-\-cache\fR to overwrite the default\&. Furthermore, it is also possible to disable the font caching mechanism completely with option \fB\-\-cache=none\fR\&. If argument @@ -196,12 +201,13 @@ By default, dvisvgm exclusively uses RGB values of the form or \fI#RGB\fR to represent colors in the SVG file\&. The latter is a short form for colors whose RGB components each consist of two identical hex digits, e\&.g\&. -\fI#123\fR +\fB#123\fR equals -\fI#112233\fR\&. According to the SVG standard, it\(cqs also possible to use color names (like +\fB#112233\fR\&. According to the SVG standard, it\(cqs also possible to use color names (like \fBblack\fR and -\fBdarkblue\fR) for a limited number of predefined colors\&. In order to apply these color names rather than their RGB values, call dvisvgm with option +\fBdarkblue\fR) for a limited number of +predefined colors (\m[blue]https://www.w3.org/TR/SVG11/types.html#ColorKeywords\m[])\&. In order to apply these color names rather than their RGB values, call dvisvgm with option \fB\-\-colornames\fR\&. All colors without an SVG color name will still be represented by RGB values\&. .RE .PP @@ -219,10 +225,10 @@ special command is created and forwarded to the PostScript special handler\&. Th for further information\&. .RE .PP -\fB\-e, \-\-exact\fR +\fB\-e, \-\-exact\-bbox\fR .RS 4 This option tells dvisvgm to compute the precise bounding box of each character\&. By default, the values stored in a font\(cqs TFM file are used to determine a glyph\(cqs extent\&. As these values are intended to implement optimal character placements and are not designed to represent the exact dimensions, they don\(cqt necessarily correspond with the bounds of the visual glyphs\&. Thus, width and/or height of some glyphs may be larger (or smaller) than the respective TFM values\&. As a result, this can lead to clipped characters at the bounds of the SVG graphics\&. With option -\fB\-\-exact\fR +\fB\-\-exact\-bbox\fR given, dvisvgm analyzes the actual shape of each character and derives a usually tight bounding box\&. .RE .PP @@ -258,7 +264,9 @@ is omitted, dvisvgm looks for the default map files \fIpdftex\&.map\fR, \fIdvipdfm\&.map\fR, and \fIpsfonts\&.map\fR -(in this order)\&. Otherwise, the files as option arguments are evaluated in the given order\&. Multiple filenames must be separated by commas without leading and/or trailing whitespace\&. By default, redefined mappings do not replace previous ones\&. However, each filename can be preceded by an optional mode specifier (\fB+\fR, +(in this order)\&. Otherwise, the files given as option arguments are evaluated in the given order\&. Multiple filenames must be separated by commas without leading and/or trailing whitespace\&. +.sp +By default, redefined mappings do not replace previous ones\&. However, each filename can be preceded by an optional mode specifier (\fB+\fR, \fB\-\fR, or \fB=\fR) to change this behavior: .PP @@ -298,7 +306,10 @@ replace previous entries\&. Afterwards, all definitions for the fonts given in \fImyfile2\&.map\fR are removed from the font map tree\&. .sp -For further information about the map file formats and the mode specifiers, see the manuals of dvips and dvipdfm\&. +For further information about the map file formats and the mode specifiers, see the manuals of +dvips (\m[blue]https://tug.org/texinfohtml/dvips.html\m[]) +and +dvipdfm (\m[blue]https://ctan.org/tex-archive/dviware/dvipdfm\m[])\&. .RE .RE .PP @@ -337,7 +348,7 @@ parameter is an integer value between 0 and 2\&. It selects the display variant Disables the removal of temporary files as created by Metafont (usually \&.gf, \&.tfm, and \&.log files) or the TrueType/WOFF module\&. .RE .PP -\fB\-\-libgs\fR=\fIfilename\fR +\fB\-\-libgs\fR=\fIpath\fR .RS 4 This option is only available if the Ghostscript library is not directly linked to dvisvgm and if PostScript support was not completely disabled during compilation\&. In this case, dvisvgm tries to load the shared GS library dynamically during runtime\&. By default, it expects the library\(cqs name to be \fBlibgs\&.so\&.X\fR @@ -345,10 +356,20 @@ This option is only available if the Ghostscript library is not directly linked \fBX\fR is the ABI version of the library) or \fBgsdll32\&.dll\fR/\fBgsdll64\&.dll\fR -(Windows)\&. Option +(Windows)\&. If dvisvgm doesn\(cqt find the library, option \fB\-\-libgs\fR -can be used to give a different name\&. Alternatively, it\(cqs also possible to set the GS library name by the environment variable -\fBLIBGS\fR\&. The latter has less precedence than the command\-line option, i\&.e\&. dvisvgm ignores variable +can be used to specify the correct path and filename, e\&.g\&. +\fB\-\-libgs=/usr/local/lib/libgs\&.so\&.9\fR +or +\fB\-\-libgs=\egs\egs9\&.25\ebin\egsdll64\&.dll\fR\&. +.sp +Alternatively, it\(cqs also possible to assign the path to environment variable +\fBLIBGS\fR, e\&.g\&. +\fBexport LIBGS=/usr/local/lib/libgs\&.so\&.9\fR +or +\fBset LIBGS=\egs\egs9\&.25\ebin\egsdll63\&.dll\fR\&. +\fBLIBGS\fR +has less precedence than the command\-line option, i\&.e\&. dvisvgm ignores variable \fBLIBGS\fR if \fB\-\-libgs\fR @@ -432,7 +453,7 @@ If this option is given, dvisvgm doesn\(cqt create SVG \fIfont\fR elements but uses \fIpaths\fR -instead\&. The resulting SVG files tend to be larger but they are concurrently more compatible with most applications that don\(cqt support SVG fonts yet\&. The optional argument +instead\&. The resulting SVG files tend to be larger but are concurrently more compatible with most applications that don\(cqt support SVG fonts\&. The optional argument \fIvariant\fR selects the method how to substitute fonts by paths\&. Variant 0 creates \fIpath\fR @@ -469,6 +490,82 @@ By default, dvisvgm creates CSS styles and class attributes to reference fonts\& \fB\-\-no\-styles\fR\&. .RE .PP +\fB\-O, \-\-optimize\fR[=\fImodules\fR] +.RS 4 +Applies several optimizations on the generated SVG tree to reduce the file size\&. The optimizations are performed by running separate optimizer modules specified by optional argument +\fImodules\fR\&. It may consist of a single module name or a comma\-separated list of several module names\&. The corresponding modules are executed one by one in the given order and thus transform the XML tree gradually\&. +.sp +The following list describes the currently available optimizer modules\&. +.PP +\fBlist\fR +.RS 4 +Lists all available optimizer modules and exits\&. +.RE +.PP +\fBnone\fR +.RS 4 +If this argument is given, dvisvgm doesn\(cqt apply any optimization\&. +\fBnone\fR +can\(cqt be combined with other module names\&. +.RE +.PP +\fBall\fR +.RS 4 +Performs all optimizations listed below\&. This is also the default if option +\fB\-\-optimize\fR +is used without argument\&. The modules are executed in a predefined order that usually leads to the best results\&. +\fBall\fR +can\(cqt be combined with other module names\&. +.RE +.PP +\fBcollapse\-groups\fR +.RS 4 +Combines nested group elements (\fB<g>\fR\&...\fB</g>\fR) that contain only a single group each\&. If possible, the group attributes are moved to the outermost element of the processed subtree\&. This module also unwraps group elements that have no attributes at all\&. +.RE +.PP +\fBgroup\-attributes\fR +.RS 4 +Creates groups (\fB<g>\fR\&...\fB</g>\fR) for common attributes around adjacent elements\&. Each attribute is moved to a separate group so that multiple common attributes lead to nested groups\&. They can be combined by applying optimizer module +\fIcollapse\-groups\fR +afterwards\&. The algorithm only takes inheritable properties, such as +\fBfill\fR +or +\fBstroke\-width\fR, into account and only removes them from an element if none of the other attributes, like +\fBid\fR, prevents this\&. +.RE +.PP +\fBremove\-clippath\fR +.RS 4 +Removes all redundant +\fIclipPath\fR +elements\&. This optimization was already present in former versions of dvisvgm and was always applied by default\&. This behavior is retained, i\&.e\&. dvisvgm executes this module even if option +\fB\-\-optimize\fR +is not given\&. You can use argument +\fInone\fR +to prevent that\&. +.RE +.PP +\fBsimplify\-text\fR +.RS 4 +If a +\fBtext\fR +element only contains whitespace nodes and +\fBtspan\fR +elements, all common inheritable attributes of the latter are moved to the enclosing text element\&. All +\fBtspan\fR +elements without further attributes are unwrapped\&. +.RE +.PP +\fBsimplify\-transform\fR +.RS 4 +Tries to shorten all +\fItransform\fR +attributes\&. This module combines the transformation commands of each attribute and decomposes the resulting transformation matrix into a sequence of basic transformations, i\&.e\&. translation, scaling, rotation, and skewing\&. If this sequence is shorter than the equivalent +\fImatrix\fR +expression, it\(cqs assigned to the attribute\&. Otherwise, the matrix expression is used\&. +.RE +.RE +.PP \fB\-o, \-\-output\fR=\fIpattern\fR .RS 4 Sets the pattern specifying the names of the generated SVG files\&. Parameter @@ -578,17 +675,20 @@ provides a combined hash computed from the DVI data and the command\-line option Since the page number isn\(cqt part of the file name by default, different DVI pages with identical contents get the same file name\&. Therefore, only the first one is converted while the others are skipped\&. To create separate files for each page, you can add the page number to the output pattern, e\&.g\&. \fB\-\-output="%f\-%p\-%hc"\fR\&. .sp -By default, dvisvgm uses the XXH64 hash algorithm to compute the values provided through +By default, dvisvgm uses the fast XXH64 hash algorithm to compute the values provided through \fB%hd\fR and -\fB%hc\fR\&. It\(cqs extremely fast, and a 64\-bit hash should be sufficient for most documents with an average size of pages\&. Alternatively, XXH32 and MD5 can be used as well\&. The desired algorithm is specified by argument +\fB%hc\fR\&. 64\-bit hashes should be sufficient for most documents with an average size of pages\&. Alternatively, XXH32 and MD5 can be used as well\&. The desired algorithm is specified by argument \fIparams\fR of option \fB\-\-page\-hashes\fR\&. It takes one of the strings \fBMD5\fR, \fBXXH32\fR, and \fBXXH64\fR, where the names can be given in lower case too, like -\fB\-\-page\-hashes=md5\fR\&. +\fB\-\-page\-hashes=md5\fR\&. Since version 0\&.7\&.1, xxHash provides an experimental 128\-bit hash function, whose algorithm may still change with the next versions of the library\&. If the corresponding API is available, dvisvgm supports the new hash function and option +\fB\-\-page\-hashes\fR +additionally accepts the algorithm specifier +\fBXXH128\fR\&. .sp Finally, option \fB\-\-page\-hashes\fR @@ -986,17 +1086,22 @@ dvisvgm offers its own small set of specials\&. The following list gives a brief .PP \fBdvisvgm:raw\fR \fItext\fR .RS 4 -Adds an arbitrary sequence of characters to the page section of the SVG document\&. dvisvgm does not perform any validation here, thus the user has to ensure that the resulting SVG is still valid\&. Parameter +Adds an arbitrary sequence of XML nodes to the page section of the SVG document\&. dvisvgm checks syntax and proper nesting of the inserted elements but does not perform any validation, thus the user has to ensure that the resulting SVG is still valid\&. Opening and closing tags may be distributed among different +\fBraw\fR +specials\&. The tags themselves can also be split but must be continued with the immediatly following +\fBraw\fR +special\&. Both syntactically incorrect and wrongly nested tags lead to error messages\&. Parameter \fItext\fR -may contain the expressions +may also contain the expressions \fB{?x}\fR, -\fB{?y}\fR, and -\fB{?color}\fR +\fB{?y}\fR, +\fB{?color}\fR, and +\fB{?matrix}\fR that expand to the current \fIx\fR or \fIy\fR -coordinate and the current color, respectively\&. Furthermore, +coordinate, the current color, and current transformation matrix, respectively\&. Furthermore, \fB{?nl}\fR expands to a newline character\&. .RE @@ -1004,7 +1109,7 @@ expands to a newline character\&. \fBdvisvgm:rawdef\fR \fItext\fR .RS 4 This command is similar to -\fBdvisvgm:raw\fR, but puts the raw text into the <defs> section of the SVG document currently being generated\&. +\fBdvisvgm:raw\fR, but puts the XML nodes into the <defs> section of the SVG document currently being generated\&. .RE .PP \fBdvisvgm:rawset\fR \fIname\fR \&... \fBdvisvgm:endrawset\fR @@ -1017,7 +1122,7 @@ specials enclosed by \fBdvisvgm:rawset\fR and \fBdvisvgm:endrawset\fR -are not evaluated immediately but jointly stored under the given +are not evaluated immediately but stored together under the given \fIname\fR for later use\&. Once defined, the named fragment can be referenced throughout the DVI file by \fBdvisvgm:rawput\fR @@ -1065,6 +1170,16 @@ can be given together with a unit specifier (see option \fB\-\-bbox\fR) or as plain floating point numbers\&. In the latter case, TeX point units are assumed (1in = 72\&.27pt)\&. .RE .PP +\fBdvisvgm:bbox\fR lock +.RS 4 +Locks the bounding box of the current page and prevents it from further updating, i\&.e\&. graphics elements added after calling this special are not taken into account in determining the extent of the bounding box\&. +.RE +.PP +\fBdvisvgm:bbox\fR unlock +.RS 4 +Unlocks the previously locked bounding box of the current page so that it gets updated again when adding graphics elements to the page\&. +.RE +.PP \fBdvisvgm:bbox\fR n[ew] \fIname\fR .RS 4 Defines or resets a local bounding box called @@ -1082,7 +1197,7 @@ expands to the four values wasn\(cqt previously defined, all four values equal to zero\&. .RE .PP -\fBdvisvgm:bbox\fR \fIwidth\fR \fIheight\fR [\fIdepth\fR] +\fBdvisvgm:bbox\fR \fIwidth\fR \fIheight\fR [\fIdepth\fR] [\fBtransform\fR] .RS 4 Updates the bounding box of the current page by embedding a virtual rectangle (\fIx\fR, \fIy\fR, @@ -1098,17 +1213,23 @@ is specified, dvisvgm embeds a second rectangle (\fIx\fR, can be given together with a unit specifier (see option \fB\-\-bbox\fR) or as plain floating point numbers\&. In the latter case, TeX point units are assumed (1in = 72\&.27pt)\&. Depending on size and position of the virtual rectangle, this command either enlarges the overall bounding box or leaves it as is\&. It\(cqs not possible to reduce its extent\&. This special should be used together with \fBdvisvgm:raw\fR -in order to update the viewport of the page properly\&. +in order to update the viewport of the page properly\&. By default, the box extents are assigned unchanged and, in particular, are not altered by transformation commands\&. In order to apply the current transformation matrix, the optional modifier +\fBtransform\fR +can be added at the end of the special statement\&. .RE .PP -\fBdvisvgm:bbox\fR a[bs] \fIx1\fR \fIy1\fR \fIx2\fR \fIy2\fR +\fBdvisvgm:bbox\fR a[bs] \fIx1\fR \fIy1\fR \fIx2\fR \fIy2\fR [\fBtransform\fR] .RS 4 -This variant of the bbox special updates the bounding box by embedding a virtual rectangle (\fIx1\fR,\fIy1\fR,\fIx2\fR,\fIy2\fR)\&. The points (\fIx1\fR,\fIy1\fR) and (\fIx2\fR,\fIy2\fR) denote the absolute coordinates of two diagonal corners of the rectangle\&. +This variant of the bbox special updates the bounding box by embedding a virtual rectangle (\fIx1\fR,\fIy1\fR,\fIx2\fR,\fIy2\fR)\&. The points (\fIx1\fR,\fIy1\fR) and (\fIx2\fR,\fIy2\fR) denote the absolute coordinates of two diagonal corners of the rectangle\&. As with the relative special variant described above, the optional modifier +\fBtransform\fR +allows for applying the current transformation matrix to the bounding box\&. .RE .PP -\fBdvisvgm:bbox\fR f[ix] \fIx1\fR \fIy1\fR \fIx2\fR \fIy2\fR +\fBdvisvgm:bbox\fR f[ix] \fIx1\fR \fIy1\fR \fIx2\fR \fIy2\fR [\fBtransform\fR] .RS 4 -This variant of the bbox special assigns an absolute (final) bounding box to the resulting SVG\&. After executing this command, dvisvgm doesn\(cqt further alter the bounding box coordinates, except this special is called again later\&. The points (\fIx1\fR,\fIy1\fR) and (\fIx2\fR,\fIy2\fR) denote the absolute coordinates of two diagonal corners of the rectangle\&. +This variant of the bbox special assigns an absolute (final) bounding box to the resulting SVG\&. After executing this command, dvisvgm doesn\(cqt further alter the bounding box coordinates, except this special is called again later\&. The points (\fIx1\fR,\fIy1\fR) and (\fIx2\fR,\fIy2\fR) denote the absolute coordinates of two diagonal corners of the rectangle\&. As with the relative special variant described above, the optional modifier +\fBtransform\fR +allows for applying the current transformation matrix to the bounding box\&. .sp The following TeX snippet adds two raw SVG elements to the output and updates the bounding box accordingly: .sp @@ -1117,11 +1238,11 @@ The following TeX snippet adds two raw SVG elements to the output and updates th .\} .nf \especial{dvisvgm:raw <circle cx=\*(Aq{?x}\*(Aq cy=\*(Aq{?y}\*(Aq r=\*(Aq10\*(Aq stroke=\*(Aqblack\*(Aq fill=\*(Aqred\*(Aq/>}% -\especial{dvisvgm:bbox 10bp 10bp 10bp}% -\especial{dvisvgm:bbox \-10bp 10bp 10bp} +\especial{dvisvgm:bbox 10bp 10bp 10bp transform}% +\especial{dvisvgm:bbox \-10bp 10bp 10bp transform} -\especial{dvisvgm:raw <path d=\*(AqM50 200 L10 250 H100 Z\*(Aq stroke=\*(Aqblack\*(Aq fill=\*(Aqblue\*(Aq/>} -\especial{dvisvgm:bbox abs 10bp 200bp 100bp 250bp} +\especial{dvisvgm:raw <path d=\*(AqM50 200 L10 250 H100 Z\*(Aq stroke=\*(Aqblack\*(Aq fill=\*(Aqblue\*(Aq/>}% +\especial{dvisvgm:bbox abs 10bp 200bp 100bp 250bp transform} .fi .if n \{\ .RE @@ -1181,8 +1302,8 @@ pdfTeX user manual (\m[blue]https://ctan.org/pkg/pdftex\m[])\&. \fBps\fR .RS 4 The famous DVI driver -\fIdvips\fR -introduced its own set of specials in order to embed PostScript code into DVI files, which greatly improves the capabilities of DVI documents\&. One aim of dvisvgm is to completely evaluate all PostScript snippets and to convert as many of them as possible to SVG\&. In contrast to dvips, dvisvgm uses floating point arithmetics to compute the precise position of each graphic element, i\&.e\&. it doesn\(cqt round the coordinates\&. Therefore, the relative locations of the graphic elements may slightly differ from those computed by dvips\&. +\fIdvips\fR (\m[blue]https://www.tug.org/texinfohtml/dvips.html\m[]) +introduced its own set of specials in order to embed PostScript code into DVI files, which greatly improves the capabilities of DVI documents\&. One aim of dvisvgm is to completely evaluate all PostScript fragments and to convert as many of them as possible to SVG\&. In contrast to dvips, dvisvgm uses floating point arithmetics to compute the precise position of each graphic element, i\&.e\&. it doesn\(cqt round the coordinates\&. Therefore, the relative locations of the graphic elements may slightly differ from those computed by dvips\&. .sp Since PostScript is a rather complex language, dvisvgm does not implement its own PostScript interpreter but relies on Ghostscript (\m[blue]https://ghostscript.com\m[]) @@ -1219,66 +1340,75 @@ If you call dvisvgm with option The TPIC special set defines instructions for drawing simple geometric objects\&. Some LaTeX packages, like eepic and tplot, use these specials to describe graphics\&. .RE .SH "EXAMPLES" -.sp -.if n \{\ +.PP +\fBdvisvgm file\fR .RS 4 -.\} -.nf -dvisvgm file -.fi -.if n \{\ +Converts the first page of +\fIfile\&.dvi\fR +to +\fIfile\&.svg\fR\&. .RE -.\} -.sp -Converts the first page of \fIfile\&.dvi\fR to \fIfile\&.svg\fR\&. -.sp -.if n \{\ +.PP +\fBdvisvgm \-p1\-5 file\fR .RS 4 -.\} -.nf -dvisvgm \- < file\&.dvi -.fi -.if n \{\ +Converts the first five pages of +\fIfile\&.dvi\fR +to +\fIfile\-1\&.svg\fR,\&...,\fIfile\-5\&.svg\fR\&. .RE -.\} -.sp -Converts the first page of \fIfile\&.dvi\fR to \fIstdin\&.svg\fR where the contents of \fIfile\&.dvi\fR is read from \fBstdin\fR\&. -.sp -.if n \{\ +.PP +\fBdvisvgm \-p1\- file\fR .RS 4 -.\} -.nf -dvisvgm \-z file -.fi -.if n \{\ +Converts all pages of +\fIfile\&.dvi\fR +to separate SVG files\&. .RE -.\} -.sp -Converts the first page of \fIfile\&.dvi\fR to \fIfile\&.svgz\fR with default compression level 9\&. -.sp -.if n \{\ +.PP +\fBdvisvgm \-p1,3 \-O file\fR .RS 4 -.\} -.nf -dvisvgm \-p5 \-z3 \-ba4\-l \-onewfile file -.fi -.if n \{\ +Converts the first and third page of +\fIfile\&.dvi\fR +to optimized SVG files\&. .RE -.\} -.sp -Converts the fifth page of \fIfile\&.dvi\fR to \fInewfile\&.svgz\fR with compression level 3\&. The bounding box is set to DIN/ISO A4 in landscape format\&. -.sp -.if n \{\ +.PP +\fBdvisvgm \- < file\&.dvi\fR .RS 4 -.\} -.nf -dvisvgm \-\-transform="R20,w/3,2h/5 T1cm,1cm S2,3" file -.fi -.if n \{\ +Converts the first page of +\fIfile\&.dvi\fR +to +\fIstdin\&.svg\fR +where the contents of +\fIfile\&.dvi\fR +is read from +\fBstdin\fR\&. +.RE +.PP +\fBdvisvgm \-z file\fR +.RS 4 +Converts the first page of +\fIfile\&.dvi\fR +to +\fIfile\&.svgz\fR +with default compression level 9\&. +.RE +.PP +\fBdvisvgm \-p5 \-z3 \-ba4\-l \-o newfile file\fR +.RS 4 +Converts the fifth page of +\fIfile\&.dvi\fR +to +\fInewfile\&.svgz\fR +with compression level 3\&. The bounding box is set to DIN/ISO A4 in landscape format\&. +.RE +.PP +\fBdvisvgm \-\-transform="R20,w/3,2h/5 T1cm,1cm S2,3" file\fR +.RS 4 +Converts the first page of +\fIfile\&.dvi\fR +to +\fIfile\&.svg\fR +where three transformations are applied\&. .RE -.\} -.sp -Converts the first page of \fIfile\&.dvi\fR to \fIfile\&.svg\fR where three transformations are applied\&. .SH "ENVIRONMENT" .sp dvisvgm uses the \fBkpathsea\fR library for locating the files that it opens\&. Hence, the environment variables described in the library\(cqs documentation influence the converter\&. diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/doc/dvisvgm.sty b/Build/source/texk/dvisvgm/dvisvgm-src/doc/dvisvgm.sty deleted file mode 100644 index 26140e47ac2..00000000000 --- a/Build/source/texk/dvisvgm/dvisvgm-src/doc/dvisvgm.sty +++ /dev/null @@ -1,14 +0,0 @@ -\NeedsTeXFormat{LaTeX2e} -\ProvidesPackage{dvisvgm}[2015/02/04 dvisvgm DocBook style] -\RequirePackageWithOptions{docbook} -\RequirePackage[english]{babel} -\RequirePackage[yyyymmdd]{datetime} -\AtBeginDocument{% - \thispagestyle{empty} - \lhead[]{\refmiscinfomanual} - \rhead[]{\thepage} - \lfoot[]{\refmiscinfosource{} \refmiscinfoversion} - \rfoot[]{\today} - \def\tableofcontents{\stdtoc} % keep TOC on current page -} - diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/doc/dvisvgm.txt.in b/Build/source/texk/dvisvgm/dvisvgm-src/doc/dvisvgm.txt.in index 1535877586c..1b5c6692529 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/doc/dvisvgm.txt.in +++ b/Build/source/texk/dvisvgm/dvisvgm-src/doc/dvisvgm.txt.in @@ -22,6 +22,7 @@ Martin Gieseking <@PACKAGE_BUGREPORT@> :man source: dvisvgm :man version: @VERSION@ :man manual: dvisvgm Manual +:revdate: 2019-11-12 20:21 +0100 Name ---- @@ -129,7 +130,8 @@ Hence, if you choose a landscape format, the page won't be rotated. // *-C, --cache*[='dir']:: To speed up the conversion process of bitmap fonts, dvisvgm saves intermediate conversion -information in cache files. By default, these files are stored in +$HOME/.dvisvgm/cache+. +information in cache files. By default, these files are stored in +$XDG_CACHE_HOME/dvisvgm/+ +or +$HOME/.cache/dvisvgm+ if +XDG_CACHE_HOME+ is not set. If you prefer a different location, use option *--cache* to overwrite the default. Furthermore, it is also possible to disable the font caching mechanism completely with option *--cache=none*. If argument 'dir' is omitted, dvisvgm prints the path of the default cache directory together @@ -150,17 +152,16 @@ below for further information. *--colornames*:: By default, dvisvgm exclusively uses RGB values of the form '#RRGGBB' or '#RGB' to represent colors in the SVG file. The latter is a short form for colors whose RGB components each -consist of two identical hex digits, e.g. '#123' equals '#112233'. +consist of two identical hex digits, e.g. +#123+ equals +#112233+. According to the SVG standard, it's also possible to use color names (like +black+ and +darkblue+) -for a limited number of predefined colors. In order to apply these color names rather than their -RGB values, call dvisvgm with option *--colornames*. All colors without an SVG color name will -still be represented by RGB values. +for a limited number of https://www.w3.org/TR/SVG11/types.html#ColorKeywords[predefined colors]. +In order to apply these color names rather than their RGB values, call dvisvgm with option +*--colornames*. All colors without an SVG color name will still be represented by RGB values. *--comments*:: Adds comments with further information about selected data to the SVG file. Currently, only font elements and font CSS rules related to native fonts are annotated. - *-E, --eps*:: If this option is given, dvisvgm does not expect a DVI but an EPS input file, and tries to convert it to SVG. In order to do so, a single 'psfile' special command is created and forwarded to the @@ -168,14 +169,14 @@ PostScript special handler. This option is only available if dvisvgm was built with PostScript support enabled, and requires Ghostscript to be available. See option *--libgs* for further information. -*-e, --exact*:: +*-e, --exact-bbox*:: This option tells dvisvgm to compute the precise bounding box of each character. By default, the values stored in a font's TFM file are used to determine a glyph's extent. As these values are intended to implement optimal character placements and are not designed to represent the exact dimensions, they don't necessarily correspond with the bounds of the visual glyphs. Thus, width and/or height of some glyphs may be larger (or smaller) than the respective TFM values. As a result, -this can lead to clipped characters at the bounds of the SVG graphics. With option *--exact* given, -dvisvgm analyzes the actual shape of each character and derives a usually tight bounding box. +this can lead to clipped characters at the bounds of the SVG graphics. With option *--exact-bbox* +given, dvisvgm analyzes the actual shape of each character and derives a usually tight bounding box. *-f, --font-format*='format':: Selects the file format used to embed the font data into the SVG files. Following formats are @@ -193,8 +194,9 @@ Loads and evaluates a single font map file or a sequence of font map files. Thes to resolve font file names and encodings. dvisvgm does not provide its own map files but tries to read available ones coming with dvips or dvipdfm. If option *--fontmap* is omitted, dvisvgm looks for the default map files 'ps2pk.map', 'pdftex.map', 'dvipdfm.map', and 'psfonts.map' (in this order). -Otherwise, the files as option arguments are evaluated in the given order. Multiple filenames must be -separated by commas without leading and/or trailing whitespace. +Otherwise, the files given as option arguments are evaluated in the given order. Multiple filenames +must be separated by commas without leading and/or trailing whitespace. ++ By default, redefined mappings do not replace previous ones. However, each filename can be preceded by an optional mode specifier (*+*, *-*, or *=*) to change this behavior: @@ -221,7 +223,7 @@ where all redefinitions of 'myfile1.map' replace previous entries. Afterwards, a given in 'myfile2.map' are removed from the font map tree. + For further information about the map file formats and the mode specifiers, see the manuals of -dvips and dvipdfm. +https://tug.org/texinfohtml/dvips.html[dvips] and https://ctan.org/tex-archive/dviware/dvipdfm[dvipdfm]. *--grad-overlap*:: Tells dvisvgm to create overlapping grid segments when approximating color gradient fills (also see @@ -268,15 +270,19 @@ while mode 2 sorts the lines by the long option names. Disables the removal of temporary files as created by Metafont (usually .gf, .tfm, and .log files) or the TrueType/WOFF module. -*--libgs*='filename':: +*--libgs*='path':: This option is only available if the Ghostscript library is not directly linked to dvisvgm and if PostScript support was not completely disabled during compilation. In this case, dvisvgm tries to load the shared GS library dynamically during runtime. By default, it expects the library's name to be +libgs.so.X+ (on Unix-like systems, where +X+ is the ABI version of the library) or -+gsdll32.dll+/+gsdll64.dll+ (Windows). Option *--libgs* can be used to give a different name. -Alternatively, it's also possible to set the GS library name by the environment variable *LIBGS*. -The latter has less precedence than the command-line option, i.e. dvisvgm ignores variable *LIBGS* -if *--libgs* is given. ++gsdll32.dll+/+gsdll64.dll+ (Windows). If dvisvgm doesn't find the library, option *--libgs* can be +used to specify the correct path and filename, e.g. +--libgs=/usr/local/lib/libgs.so.9+ or ++--libgs=\gs\gs9.25\bin\gsdll64.dll+. ++ +Alternatively, it's also possible to assign the path to environment variable *LIBGS*, e.g. ++export LIBGS=/usr/local/lib/libgs.so.9+ or +set LIBGS=\gs\gs9.25\bin\gsdll63.dll+. *LIBGS* has +less precedence than the command-line option, i.e. dvisvgm ignores variable *LIBGS* if *--libgs* +is given. *-L, --linkmark*='style':: Selects the method how to mark hyperlinked areas. The 'style' argument can take one of the values @@ -322,8 +328,8 @@ This option disables these calls. *-n, --no-fonts*[='variant']:: If this option is given, dvisvgm doesn't create SVG 'font' elements but uses 'paths' instead. The -resulting SVG files tend to be larger but they are concurrently more compatible with most applications that -don't support SVG fonts yet. The optional argument 'variant' selects the method how to substitute fonts +resulting SVG files tend to be larger but are concurrently more compatible with most applications that +don't support SVG fonts. The optional argument 'variant' selects the method how to substitute fonts by paths. Variant 0 creates 'path' and 'use' elements in order to avoid lengthy duplicates. Variant 1 creates 'path' elements only. Option *--no-fonts* implies *--no-styles*. @@ -344,6 +350,56 @@ more compact than adding the complete font information to each text element over However, if you prefer direct font references, the default behavior can be disabled with option *--no-styles*. +*-O, --optimize*[='modules']:: +Applies several optimizations on the generated SVG tree to reduce the file size. The optimizations +are performed by running separate optimizer modules specified by optional argument 'modules'. +It may consist of a single module name or a comma-separated list of several module names. +The corresponding modules are executed one by one in the given order and thus transform the +XML tree gradually. ++ +The following list describes the currently available optimizer modules. + + *list*;; + Lists all available optimizer modules and exits. + + *none*;; + If this argument is given, dvisvgm doesn't apply any optimization. *none* can't be combined + with other module names. + + *all*;; + Performs all optimizations listed below. This is also the default if option *--optimize* is + used without argument. The modules are executed in a predefined order that usually leads to the + best results. *all* can't be combined with other module names. + + *collapse-groups*;; + Combines nested group elements (+<g>+...+</g>+) that contain only a single group each. If possible, + the group attributes are moved to the outermost element of the processed subtree. This module also + unwraps group elements that have no attributes at all. + + *group-attributes*;; + Creates groups (+<g>+...+</g>+) for common attributes around adjacent elements. Each attribute is + moved to a separate group so that multiple common attributes lead to nested groups. They can be + combined by applying optimizer module 'collapse-groups' afterwards. The algorithm only takes + inheritable properties, such as +fill+ or +stroke-width+, into account and only removes them from + an element if none of the other attributes, like +id+, prevents this. + + *remove-clippath*;; + Removes all redundant 'clipPath' elements. This optimization was already present in former versions + of dvisvgm and was always applied by default. This behavior is retained, i.e. dvisvgm executes + this module even if option *--optimize* is not given. You can use argument 'none' to prevent that. + + *simplify-text*;; + If a +text+ element only contains whitespace nodes and +tspan+ elements, all common inheritable + attributes of the latter are moved to the enclosing text element. All +tspan+ elements without + further attributes are unwrapped. + + *simplify-transform*;; + Tries to shorten all 'transform' attributes. This module combines the transformation commands of + each attribute and decomposes the resulting transformation matrix into a sequence of basic + transformations, i.e. translation, scaling, rotation, and skewing. If this sequence is shorter + than the equivalent 'matrix' expression, it's assigned to the attribute. Otherwise, the matrix + expression is used. + *-o, --output*='pattern':: Sets the pattern specifying the names of the generated SVG files. Parameter 'pattern' is a string that may contain static character sequences as well as the variables +%f+, +%p+, +%P+, +%hd+, @@ -412,11 +468,14 @@ contents get the same file name. Therefore, only the first one is converted whil skipped. To create separate files for each page, you can add the page number to the output pattern, e.g. +--output="%f-%p-%hc"+. + -By default, dvisvgm uses the XXH64 hash algorithm to compute the values provided through +%hd+ and -+%hc+. It's extremely fast, and a 64-bit hash should be sufficient for most documents with an average -size of pages. Alternatively, XXH32 and MD5 can be used as well. The desired algorithm is specified -by argument 'params' of option *--page-hashes*. It takes one of the strings +MD5+, +XXH32+, and +XXH64+, -where the names can be given in lower case too, like +--page-hashes=md5+. +By default, dvisvgm uses the fast XXH64 hash algorithm to compute the values provided through +%hd+ and ++%hc+. 64-bit hashes should be sufficient for most documents with an average size of pages. Alternatively, +XXH32 and MD5 can be used as well. The desired algorithm is specified by argument 'params' of option +*--page-hashes*. It takes one of the strings +MD5+, +XXH32+, and +XXH64+, where the names can be given +in lower case too, like +--page-hashes=md5+. Since version 0.7.1, xxHash provides an experimental 128-bit +hash function, whose algorithm may still change with the next versions of the library. If the +corresponding API is available, dvisvgm supports the new hash function and option *--page-hashes* +additionally accepts the algorithm specifier +XXH128+. + Finally, option *--page-hashes* can take a second argument that must be separated by a comma. Currently, only the two parameters 'list' and 'replace' are evaluated, e.g. +--page-hashes=md5,list+ @@ -616,19 +675,23 @@ exact syntax, see the documentation of dvips, for instance. *dvisvgm*:: dvisvgm offers its own small set of specials. The following list gives a brief overview. *dvisvgm:raw* 'text';; - Adds an arbitrary sequence of characters to the page section of the SVG document. dvisvgm does not perform - any validation here, thus the user has to ensure that the resulting SVG is still valid. Parameter 'text' - may contain the expressions *{?x}*, *{?y}*, and *{?color}* that expand to the current 'x' or 'y' coordinate - and the current color, respectively. Furthermore, *{?nl}* expands to a newline character. - + Adds an arbitrary sequence of XML nodes to the page section of the SVG document. dvisvgm checks syntax and + proper nesting of the inserted elements but does not perform any validation, thus the user has to ensure + that the resulting SVG is still valid. Opening and closing tags may be distributed among different +raw+ + specials. The tags themselves can also be split but must be continued with the immediatly following +raw+ + special. Both syntactically incorrect and wrongly nested tags lead to error messages. + Parameter 'text' may also contain the expressions *{?x}*, *{?y}*, *{?color}*, and *{?matrix}* that expand to + the current 'x' or 'y' coordinate, the current color, and current transformation matrix, respectively. + Furthermore, *{?nl}* expands to a newline character. + *dvisvgm:rawdef* 'text';; - This command is similar to *dvisvgm:raw*, but puts the raw text into the <defs> section of the SVG document + This command is similar to *dvisvgm:raw*, but puts the XML nodes into the <defs> section of the SVG document currently being generated. *dvisvgm:rawset* 'name' ... *dvisvgm:endrawset*;; This pair of specials marks the begin and end of a definition of a named raw SVG fragment. All *dvisvgm:raw* and *dvisvgm:rawdef* specials enclosed by *dvisvgm:rawset* and *dvisvgm:endrawset* are not evaluated - immediately but jointly stored under the given 'name' for later use. Once defined, the named fragment can be + immediately but stored together under the given 'name' for later use. Once defined, the named fragment can be referenced throughout the DVI file by *dvisvgm:rawput* (see below). The two commands *dvisvgm:rawset* and *dvisvgm:endrawset* must not be nested, i.e. each call of *dvisvgm:rawset* has to be followed by a corresponding call of *dvisvgm:endrawset* before another *dvisvgm:rawset* may occur. @@ -646,7 +709,15 @@ dvisvgm offers its own small set of specials. The following list gives a brief o can be used here. However, dvisvgm does not check the file format or the file name suffix. The lengths 'width' and 'height' can be given together with a unit specifier (see option *--bbox*) or as plain floating point numbers. In the latter case, TeX point units are assumed (1in = 72.27pt). - + + *dvisvgm:bbox* lock;; + Locks the bounding box of the current page and prevents it from further updating, i.e. graphics elements added + after calling this special are not taken into account in determining the extent of the bounding box. + + *dvisvgm:bbox* unlock;; + Unlocks the previously locked bounding box of the current page so that it gets updated again when adding + graphics elements to the page. + *dvisvgm:bbox* n[ew] 'name';; Defines or resets a local bounding box called 'name'. The name may consist of letters and digits. While processing a DVI page, dvisvgm continuously updates the (global) bounding box of the current page in order to @@ -658,8 +729,8 @@ dvisvgm offers its own small set of specials. The following list gives a brief o In conjunction with special *dvisvgm:raw*, the macro *{?bbox 'name'}* expands to the four values 'x', 'y', 'w', and 'h' (separated by spaces) specifying the coordinates of the upper left corner, width, and height of the local box 'name'. If box 'name' wasn't previously defined, all four values equal to zero. - - *dvisvgm:bbox* 'width' 'height' ['depth'];; + + *dvisvgm:bbox* 'width' 'height' ['depth'] [+transform+];; Updates the bounding box of the current page by embedding a virtual rectangle ('x', 'y', 'width', 'height') where the lower left corner is located at the current DVI drawing position ('x','y'). If the optional parameter 'depth' is specified, dvisvgm embeds a second rectangle ('x', 'y', 'width', -__depth__). The lengths 'width', 'height', and @@ -667,26 +738,33 @@ dvisvgm offers its own small set of specials. The following list gives a brief o In the latter case, TeX point units are assumed (1in = 72.27pt). Depending on size and position of the virtual rectangle, this command either enlarges the overall bounding box or leaves it as is. It's not possible to reduce its extent. This special should be used together with *dvisvgm:raw* in order to update the viewport of the page properly. - - *dvisvgm:bbox* a[bs] 'x1' 'y1' 'x2' 'y2';; + By default, the box extents are assigned unchanged and, in particular, are not altered by transformation commands. + In order to apply the current transformation matrix, the optional modifier +transform+ can be added at the end of + the special statement. + + *dvisvgm:bbox* a[bs] 'x1' 'y1' 'x2' 'y2' [+transform+];; This variant of the bbox special updates the bounding box by embedding a virtual rectangle ('x1','y1','x2','y2'). The points ('x1','y1') and ('x2','y2') denote the absolute coordinates of two diagonal corners of the rectangle. - - *dvisvgm:bbox* f[ix] 'x1' 'y1' 'x2' 'y2';; + As with the relative special variant described above, the optional modifier +transform+ allows for applying the + current transformation matrix to the bounding box. + + *dvisvgm:bbox* f[ix] 'x1' 'y1' 'x2' 'y2' [+transform+];; This variant of the bbox special assigns an absolute (final) bounding box to the resulting SVG. After executing this command, dvisvgm doesn't further alter the bounding box coordinates, except this special is called again later. The points ('x1','y1') and ('x2','y2') denote the absolute coordinates of two diagonal corners of the rectangle. + As with the relative special variant described above, the optional modifier +transform+ allows for applying the + current transformation matrix to the bounding box. + The following TeX snippet adds two raw SVG elements to the output and updates the bounding box accordingly: + [source,tex] ------------------------------------------------------------------------------------- \special{dvisvgm:raw <circle cx='{?x}' cy='{?y}' r='10' stroke='black' fill='red'/>}% -\special{dvisvgm:bbox 10bp 10bp 10bp}% -\special{dvisvgm:bbox -10bp 10bp 10bp} +\special{dvisvgm:bbox 10bp 10bp 10bp transform}% +\special{dvisvgm:bbox -10bp 10bp 10bp transform} -\special{dvisvgm:raw <path d='M50 200 L10 250 H100 Z' stroke='black' fill='blue'/>} -\special{dvisvgm:bbox abs 10bp 200bp 100bp 250bp} +\special{dvisvgm:raw <path d='M50 200 L10 250 H100 Z' stroke='black' fill='blue'/>}% +\special{dvisvgm:bbox abs 10bp 200bp 100bp 250bp transform} ------------------------------------------------------------------------------------- + @@ -727,12 +805,12 @@ information on the command syntax and semantics, see the documentation of +\pdfm https://ctan.org/pkg/pdftex[pdfTeX user manual]. *ps*:: -The famous DVI driver 'dvips' introduced its own set of specials in order to embed PostScript code into DVI files, -which greatly improves the capabilities of DVI documents. One aim of dvisvgm is to completely evaluate all -PostScript snippets and to convert as many of them as possible to SVG. In contrast to dvips, dvisvgm uses -floating point arithmetics to compute the precise position of each graphic element, i.e. it doesn't round the -coordinates. Therefore, the relative locations of the graphic elements may slightly differ from those computed -by dvips. +The famous DVI driver https://www.tug.org/texinfohtml/dvips.html['dvips'] introduced its own set of specials +in order to embed PostScript code into DVI files, which greatly improves the capabilities of DVI documents. +One aim of dvisvgm is to completely evaluate all PostScript fragments and to convert as many of them as possible +to SVG. In contrast to dvips, dvisvgm uses floating point arithmetics to compute the precise position of each +graphic element, i.e. it doesn't round the coordinates. Therefore, the relative locations of the graphic elements +may slightly differ from those computed by dvips. + Since PostScript is a rather complex language, dvisvgm does not implement its own PostScript interpreter but relies on https://ghostscript.com[Ghostscript] instead. If the Ghostscript library was not linked to the @@ -765,32 +843,29 @@ eepic and tplot, use these specials to describe graphics. Examples -------- ------------- -dvisvgm file ------------- -Converts the first page of 'file.dvi' to 'file.svg'. - --------------------- -dvisvgm - < file.dvi --------------------- -Converts the first page of 'file.dvi' to 'stdin.svg' where the contents of 'file.dvi' -is read from *stdin*. - ---------------- -dvisvgm -z file ---------------- -Converts the first page of 'file.dvi' to 'file.svgz' with default compression level 9. - -------------------------------------- -dvisvgm -p5 -z3 -ba4-l -onewfile file -------------------------------------- -Converts the fifth page of 'file.dvi' to 'newfile.svgz' with compression level 3. -The bounding box is set to DIN/ISO A4 in landscape format. - ------------------------------------------------------ -dvisvgm --transform="R20,w/3,2h/5 T1cm,1cm S2,3" file ------------------------------------------------------ -Converts the first page of 'file.dvi' to 'file.svg' where three transformations are applied. ++dvisvgm file+:: + Converts the first page of 'file.dvi' to 'file.svg'. + ++dvisvgm -p1-5 file+:: + Converts the first five pages of 'file.dvi' to 'file-1.svg',...,'file-5.svg'. + ++dvisvgm -p1- file+:: + Converts all pages of 'file.dvi' to separate SVG files. + ++dvisvgm -p1,3 -O file+:: + Converts the first and third page of 'file.dvi' to optimized SVG files. + ++dvisvgm - < file.dvi+:: + Converts the first page of 'file.dvi' to 'stdin.svg' where the contents of 'file.dvi' is read from *stdin*. + ++dvisvgm -z file+:: + Converts the first page of 'file.dvi' to 'file.svgz' with default compression level 9. + ++dvisvgm -p5 -z3 -ba4-l -o newfile file+:: + Converts the fifth page of 'file.dvi' to 'newfile.svgz' with compression level 3. The bounding box is set to DIN/ISO A4 in landscape format. + ++dvisvgm --transform="R20,w/3,2h/5 T1cm,1cm S2,3" file+:: + Converts the first page of 'file.dvi' to 'file.svg' where three transformations are applied. [[environment]] Environment diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/doc/generate-dvisvgm-sty.xsl b/Build/source/texk/dvisvgm/dvisvgm-src/doc/generate-dvisvgm-sty.xsl new file mode 100644 index 00000000000..9ce456d1b3a --- /dev/null +++ b/Build/source/texk/dvisvgm/dvisvgm-src/doc/generate-dvisvgm-sty.xsl @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="UTF-8"?> +<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> + <xsl:output method="text"/> + + <xsl:template match="/">% This is a generated file -- don't modify it manually. +\NeedsTeXFormat{LaTeX2e} +\ProvidesPackage{dvisvgm}[2015/02/04 dvisvgm DocBook style] +\RequirePackageWithOptions{docbook} +\RequirePackage[english]{babel} +\AtBeginDocument{% + \thispagestyle{empty} + \lhead[]{\refmiscinfomanual} + \rhead[]{\thepage} + \lfoot[]{\refmiscinfosource{} \refmiscinfoversion} + \rfoot[]{<xsl:value-of select="refentry/refentryinfo/date"/>} % revision date given in dvisvgm.txt.in + \def\tableofcontents{\stdtoc} % keep TOC on current page +} + </xsl:template> +</xsl:stylesheet>
\ No newline at end of file diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/doc/tweak-db-refentry.xsl b/Build/source/texk/dvisvgm/dvisvgm-src/doc/tweak-db-refentry.xsl index ef1752142ea..088e2ce4345 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/doc/tweak-db-refentry.xsl +++ b/Build/source/texk/dvisvgm/dvisvgm-src/doc/tweak-db-refentry.xsl @@ -4,23 +4,45 @@ <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:date="http://exslt.org/dates-and-times" - extension-element-prefixes="date"> + xmlns:func="http://exslt.org/functions" + xmlns:my="my-namespace" + exclude-result-prefixes="my" + extension-element-prefixes="date func"> <xsl:output doctype-public="-//OASIS//DTD DocBook XML V4.5//EN" doctype-system="http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd"/> + <!-- adapt ISO date created by keyword expansion --> + <xsl:template match="refentryinfo/date | revision[1]/date"> + <date> + <xsl:value-of select="my:extract-date(.)"/> + </date> + </xsl:template> + <!-- add date to refmeta element --> <xsl:template match="refmeta"> <xsl:copy> <xsl:copy-of select="*"/> - <xsl:variable name="date" select="date:date()"/> - <xsl:if test="$date"> - <refmiscinfo class="date"> - <xsl:value-of select="substring($date, 1, 10)"/> - </refmiscinfo> - </xsl:if> + <refmiscinfo class="date"> + <xsl:value-of select="my:extract-date(../refentryinfo/date)"/> + </refmiscinfo> </xsl:copy> </xsl:template> + <func:function name="my:extract-date"> + <xsl:param name="isodate"/> + <xsl:variable name="shortdate" select="substring($isodate, 1, 10)"/> + <xsl:choose> + <xsl:when test="translate($shortdate, '0123456789', '##########') = '####-##-##'"> + <!-- use date part of expanded keyword --> + <func:result select="$shortdate"/> + </xsl:when> + <xsl:otherwise> + <!-- use current date as fallback --> + <func:result select="substring(date:date(), 1, 10)"/> + </xsl:otherwise> + </xsl:choose> + </func:function> + <!-- copy everything else unchanged --> <xsl:template match="@*|node()"> <xsl:copy> diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/auxiliary.h b/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/auxiliary.h index bb0c6e03cb9..6ac2713a63e 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/auxiliary.h +++ b/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/auxiliary.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2001-2017 Peter Selinger. +/* Copyright (C) 2001-2019 Peter Selinger. This file is part of Potrace. It is free software and it is covered by the GNU General Public License. See the file COPYING for details. */ diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/bitmap.h b/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/bitmap.h index 2e91ab1e7d7..c5685746896 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/bitmap.h +++ b/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/bitmap.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2001-2017 Peter Selinger. +/* Copyright (C) 2001-2019 Peter Selinger. This file is part of Potrace. It is free software and it is covered by the GNU General Public License. See the file COPYING for details. */ @@ -108,7 +108,7 @@ static inline potrace_bitmap_t *bm_new(int w, int h) { return NULL; } if (size == 0) { - size = 1; /* make sure calloc() doesn't return NULL */ + size = BM_WORDSIZE; /* make sure calloc() doesn't return NULL */ } bm = (potrace_bitmap_t *) malloc(sizeof(potrace_bitmap_t)); @@ -203,7 +203,7 @@ static inline int bm_resize(potrace_bitmap_t *bm, int h) { goto error; } if (newsize == 0) { - newsize = 1; /* make sure realloc() doesn't return NULL */ + newsize = BM_WORDSIZE; /* make sure realloc() doesn't return NULL */ } newmap = (potrace_word *)realloc(bm->map, newsize); diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/config.h b/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/config.h index 2d3e609c137..24d8ea1bf0a 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/config.h +++ b/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/config.h @@ -1,5 +1,5 @@ #ifndef CONFIG_H #define CONFIG_H -#define VERSION "1.15" +#define VERSION "1.16" #define HAVE_INTTYPES_H 1 #endif diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/curve.c b/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/curve.c index 0f415559589..81e02bb7d2a 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/curve.c +++ b/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/curve.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2001-2017 Peter Selinger. +/* Copyright (C) 2001-2019 Peter Selinger. This file is part of Potrace. It is free software and it is covered by the GNU General Public License. See the file COPYING for details. */ diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/curve.h b/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/curve.h index 00f042cc228..fa18a93d216 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/curve.h +++ b/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/curve.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2001-2017 Peter Selinger. +/* Copyright (C) 2001-2019 Peter Selinger. This file is part of Potrace. It is free software and it is covered by the GNU General Public License. See the file COPYING for details. */ diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/decompose.c b/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/decompose.c index 5439ad51f3a..ae72850efb2 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/decompose.c +++ b/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/decompose.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2001-2017 Peter Selinger. +/* Copyright (C) 2001-2019 Peter Selinger. This file is part of Potrace. It is free software and it is covered by the GNU General Public License. See the file COPYING for details. */ diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/decompose.h b/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/decompose.h index a80a480ccbf..584b383ef90 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/decompose.h +++ b/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/decompose.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2001-2017 Peter Selinger. +/* Copyright (C) 2001-2019 Peter Selinger. This file is part of Potrace. It is free software and it is covered by the GNU General Public License. See the file COPYING for details. */ diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/lists.h b/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/lists.h index f76bdcde14b..507cf15bdfb 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/lists.h +++ b/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/lists.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2001-2017 Peter Selinger. +/* Copyright (C) 2001-2019 Peter Selinger. This file is part of Potrace. It is free software and it is covered by the GNU General Public License. See the file COPYING for details. */ diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/potracelib.c b/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/potracelib.c index 7dc9fe940ab..bf16e3f1747 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/potracelib.c +++ b/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/potracelib.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2001-2017 Peter Selinger. +/* Copyright (C) 2001-2019 Peter Selinger. This file is part of Potrace. It is free software and it is covered by the GNU General Public License. See the file COPYING for details. */ diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/potracelib.h b/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/potracelib.h index 003297740af..ae2f18c7ebc 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/potracelib.h +++ b/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/potracelib.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2001-2017 Peter Selinger. +/* Copyright (C) 2001-2019 Peter Selinger. This file is part of Potrace. It is free software and it is covered by the GNU General Public License. See the file COPYING for details. */ diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/progress.h b/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/progress.h index cdd637694c1..5123368a7e8 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/progress.h +++ b/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/progress.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2001-2017 Peter Selinger. +/* Copyright (C) 2001-2019 Peter Selinger. This file is part of Potrace. It is free software and it is covered by the GNU General Public License. See the file COPYING for details. */ diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/trace.c b/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/trace.c index b0b9944ae6a..b830764447b 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/trace.c +++ b/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/trace.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2001-2017 Peter Selinger. +/* Copyright (C) 2001-2019 Peter Selinger. This file is part of Potrace. It is free software and it is covered by the GNU General Public License. See the file COPYING for details. */ diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/trace.h b/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/trace.h index 5976453353b..7ddcb89c7bc 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/trace.h +++ b/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/trace.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2001-2017 Peter Selinger. +/* Copyright (C) 2001-2019 Peter Selinger. This file is part of Potrace. It is free software and it is covered by the GNU General Public License. See the file COPYING for details. */ diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/libs/woff2/src/glyph.cc b/Build/source/texk/dvisvgm/dvisvgm-src/libs/woff2/src/glyph.cc index 057174de219..1b4408b924c 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/libs/woff2/src/glyph.cc +++ b/Build/source/texk/dvisvgm/dvisvgm-src/libs/woff2/src/glyph.cc @@ -350,7 +350,7 @@ bool StoreGlyph(const Glyph& glyph, uint8_t* dst, size_t* dst_size) { } } else if (glyph.contours.size() > 0) { // Simple glyph. - if (glyph.contours.size() > std::numeric_limits<int16_t>::max()) { + if (glyph.contours.size() > size_t(std::numeric_limits<int16_t>::max())) { return FONT_COMPRESSION_FAILURE(); } if (*dst_size < ((12ULL + 2 * glyph.contours.size()) + diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/libs/woff2/src/normalize.cc b/Build/source/texk/dvisvgm/dvisvgm-src/libs/woff2/src/normalize.cc index 32a065975f0..dc4bfe6c5c7 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/libs/woff2/src/normalize.cc +++ b/Build/source/texk/dvisvgm/dvisvgm-src/libs/woff2/src/normalize.cc @@ -93,7 +93,7 @@ bool MakeEditableBuffer(Font* font, int tableTag) { if (table->IsReused()) { return true; } - int sz = Round4(table->length); + uint32_t sz = Round4(table->length); table->buffer.resize(sz); uint8_t* buf = &table->buffer[0]; memcpy(buf, table->data, table->length); diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/libs/xxHash/Makefile.am b/Build/source/texk/dvisvgm/dvisvgm-src/libs/xxHash/Makefile.am index e40f8a066ee..089c7aab718 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/libs/xxHash/Makefile.am +++ b/Build/source/texk/dvisvgm/dvisvgm-src/libs/xxHash/Makefile.am @@ -1,10 +1,10 @@ if !HAVE_XXHASH noinst_LIBRARIES = libxxhash.a -libxxhash_a_SOURCES = xxhash.c xxhash.h +libxxhash_a_SOURCES = xxhash.c xxhash.h xxh3.h AM_CXXFLAGS = -Wall -xxhash.c: xxhash.h +xxhash.c: xxhash.h xxh3.h @CODE_COVERAGE_RULES@ endif diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/libs/xxHash/Makefile.in b/Build/source/texk/dvisvgm/dvisvgm-src/libs/xxHash/Makefile.in index 363e13baad0..fdb5c76dd4c 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/libs/xxHash/Makefile.in +++ b/Build/source/texk/dvisvgm/dvisvgm-src/libs/xxHash/Makefile.in @@ -119,7 +119,7 @@ am__v_AR_0 = @echo " AR " $@; am__v_AR_1 = libxxhash_a_AR = $(AR) $(ARFLAGS) libxxhash_a_LIBADD = -am__libxxhash_a_SOURCES_DIST = xxhash.c xxhash.h +am__libxxhash_a_SOURCES_DIST = xxhash.c xxhash.h xxh3.h @HAVE_XXHASH_FALSE@am_libxxhash_a_OBJECTS = xxhash.$(OBJEXT) libxxhash_a_OBJECTS = $(am_libxxhash_a_OBJECTS) AM_V_P = $(am__v_P_@AM_V@) @@ -340,7 +340,7 @@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ @HAVE_XXHASH_FALSE@noinst_LIBRARIES = libxxhash.a -@HAVE_XXHASH_FALSE@libxxhash_a_SOURCES = xxhash.c xxhash.h +@HAVE_XXHASH_FALSE@libxxhash_a_SOURCES = xxhash.c xxhash.h xxh3.h @HAVE_XXHASH_FALSE@AM_CXXFLAGS = -Wall CLEANFILES = *.gcda *.gcno all: all-am @@ -639,7 +639,7 @@ uninstall-am: .PRECIOUS: Makefile -@HAVE_XXHASH_FALSE@xxhash.c: xxhash.h +@HAVE_XXHASH_FALSE@xxhash.c: xxhash.h xxh3.h @HAVE_XXHASH_FALSE@@CODE_COVERAGE_RULES@ diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/libs/xxHash/xxh3.h b/Build/source/texk/dvisvgm/dvisvgm-src/libs/xxHash/xxh3.h new file mode 100644 index 00000000000..b3a8295845e --- /dev/null +++ b/Build/source/texk/dvisvgm/dvisvgm-src/libs/xxHash/xxh3.h @@ -0,0 +1,1613 @@ +/* + xxHash - Extremely Fast Hash algorithm + Development source file for `xxh3` + Copyright (C) 2019-present, Yann Collet. + + BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the + distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + You can contact the author at : + - xxHash source repository : https://github.com/Cyan4973/xxHash +*/ + +/* Note : + This file is separated for development purposes. + It will be integrated into `xxhash.c` when development phase is complete. +*/ + +#ifndef XXH3_H +#define XXH3_H + + +/* === Dependencies === */ + +#undef XXH_INLINE_ALL /* in case it's already defined */ +#define XXH_INLINE_ALL +#include "xxhash.h" + + +/* === Compiler specifics === */ + +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* >= C99 */ +# define XXH_RESTRICT restrict +#else +/* note : it might be useful to define __restrict or __restrict__ for some C++ compilers */ +# define XXH_RESTRICT /* disable */ +#endif + +#if defined(__GNUC__) +# if defined(__AVX2__) +# include <immintrin.h> +# elif defined(__SSE2__) +# include <emmintrin.h> +# elif defined(__ARM_NEON__) || defined(__ARM_NEON) +# define inline __inline__ /* clang bug */ +# include <arm_neon.h> +# undef inline +# endif +#elif defined(_MSC_VER) +# include <intrin.h> +#endif + +/* + * Sanity check. + * + * XXH3 only requires these features to be efficient: + * + * - Usable unaligned access + * - A 32-bit or 64-bit ALU + * - If 32-bit, a decent ADC instruction + * - A 32 or 64-bit multiply with a 64-bit result + * + * Almost all 32-bit and 64-bit targets meet this, except for Thumb-1, the + * classic 16-bit only subset of ARM's instruction set. + * + * First of all, Thumb-1 lacks support for the UMULL instruction which + * performs the important long multiply. This means numerous __aeabi_lmul + * calls. + * + * Second of all, the 8 functional registers are just not enough. + * Setup for __aeabi_lmul, byteshift loads, pointers, and all arithmetic need + * Lo registers, and this shuffling results in thousands more MOVs than A32. + * + * A32 and T32 don't have this limitation. They can access all 14 registers, + * do a 32->64 multiply with UMULL, and the flexible operand is helpful too. + * + * If compiling Thumb-1 for a target which supports ARM instructions, we + * will give a warning. + * + * Usually, if this happens, it is because of an accident and you probably + * need to specify -march, as you probably meant to compileh for a newer + * architecture. + */ +#if defined(__thumb__) && !defined(__thumb2__) && defined(__ARM_ARCH_ISA_ARM) +# warning "XXH3 is highly inefficient without ARM or Thumb-2." +#endif + +/* ========================================== + * Vectorization detection + * ========================================== */ +#define XXH_SCALAR 0 +#define XXH_SSE2 1 +#define XXH_AVX2 2 +#define XXH_NEON 3 +#define XXH_VSX 4 + +#ifndef XXH_VECTOR /* can be defined on command line */ +# if defined(__AVX2__) +# define XXH_VECTOR XXH_AVX2 +# elif defined(__SSE2__) || defined(_M_AMD64) || defined(_M_X64) || (defined(_M_IX86_FP) && (_M_IX86_FP == 2)) +# define XXH_VECTOR XXH_SSE2 +# elif defined(__GNUC__) /* msvc support maybe later */ \ + && (defined(__ARM_NEON__) || defined(__ARM_NEON)) \ + && (defined(__LITTLE_ENDIAN__) /* We only support little endian NEON */ \ + || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) +# define XXH_VECTOR XXH_NEON +# elif defined(__PPC64__) && defined(__POWER8_VECTOR__) && defined(__GNUC__) +# define XXH_VECTOR XXH_VSX +# else +# define XXH_VECTOR XXH_SCALAR +# endif +#endif + +/* control alignment of accumulator, + * for compatibility with fast vector loads */ +#ifndef XXH_ACC_ALIGN +# if XXH_VECTOR == 0 /* scalar */ +# define XXH_ACC_ALIGN 8 +# elif XXH_VECTOR == 1 /* sse2 */ +# define XXH_ACC_ALIGN 16 +# elif XXH_VECTOR == 2 /* avx2 */ +# define XXH_ACC_ALIGN 32 +# elif XXH_VECTOR == 3 /* neon */ +# define XXH_ACC_ALIGN 16 +# elif XXH_VECTOR == 4 /* vsx */ +# define XXH_ACC_ALIGN 16 +# endif +#endif + +/* xxh_u64 XXH_mult32to64(xxh_u32 a, xxh_u64 b) { return (xxh_u64)a * (xxh_u64)b; } */ +#if defined(_MSC_VER) && defined(_M_IX86) +# include <intrin.h> +# define XXH_mult32to64(x, y) __emulu(x, y) +#else +# define XXH_mult32to64(x, y) ((xxh_u64)((x) & 0xFFFFFFFF) * (xxh_u64)((y) & 0xFFFFFFFF)) +#endif + +/* VSX stuff. It's a lot because VSX support is mediocre across compilers and + * there is a lot of mischief with endianness. */ +#if XXH_VECTOR == XXH_VSX +# include <altivec.h> +# undef vector +typedef __vector unsigned long long U64x2; +typedef __vector unsigned char U8x16; +typedef __vector unsigned U32x4; + +#ifndef XXH_VSX_BE +# if defined(__BIG_ENDIAN__) \ + || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) +# define XXH_VSX_BE 1 +# elif defined(__VEC_ELEMENT_REG_ORDER__) && __VEC_ELEMENT_REG_ORDER__ == __ORDER_BIG_ENDIAN__ +# warning "-maltivec=be is not recommended. Please use native endianness." +# define XXH_VSX_BE 1 +# else +# define XXH_VSX_BE 0 +# endif +#endif + +/* We need some helpers for big endian mode. */ +#if XXH_VSX_BE +/* A wrapper for POWER9's vec_revb. */ +# ifdef __POWER9_VECTOR__ +# define XXH_vec_revb vec_revb +# else +XXH_FORCE_INLINE U64x2 XXH_vec_revb(U64x2 val) +{ + U8x16 const vByteSwap = { 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, + 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08 }; + return vec_perm(val, val, vByteSwap); +} +# endif + +/* Power8 Crypto gives us vpermxor which is very handy for + * PPC64EB. + * + * U8x16 vpermxor(U8x16 a, U8x16 b, U8x16 mask) + * { + * U8x16 ret; + * for (int i = 0; i < 16; i++) { + * ret[i] = a[mask[i] & 0xF] ^ b[mask[i] >> 4]; + * } + * return ret; + * } + * + * Because both of the main loops load the key, swap, and xor it with input, + * we can combine the key swap into this instruction. + */ +# ifdef vec_permxor +# define XXH_vec_permxor vec_permxor +# else +# define XXH_vec_permxor __builtin_crypto_vpermxor +# endif +#endif +/* + * Because we reinterpret the multiply, there are endian memes: vec_mulo actually becomes + * vec_mule. + * + * Additionally, the intrinsic wasn't added until GCC 8, despite existing for a while. + * Clang has an easy way to control this, we can just use the builtin which doesn't swap. + * GCC needs inline assembly. */ +#if __has_builtin(__builtin_altivec_vmuleuw) +# define XXH_vec_mulo __builtin_altivec_vmulouw +# define XXH_vec_mule __builtin_altivec_vmuleuw +#else +/* Adapted from https://github.com/google/highwayhash/blob/master/highwayhash/hh_vsx.h. */ +XXH_FORCE_INLINE U64x2 XXH_vec_mulo(U32x4 a, U32x4 b) { + U64x2 result; + __asm__("vmulouw %0, %1, %2" : "=v" (result) : "v" (a), "v" (b)); + return result; +} +XXH_FORCE_INLINE U64x2 XXH_vec_mule(U32x4 a, U32x4 b) { + U64x2 result; + __asm__("vmuleuw %0, %1, %2" : "=v" (result) : "v" (a), "v" (b)); + return result; +} +#endif +#endif + + +/* ========================================== + * XXH3 default settings + * ========================================== */ + +#define XXH_SECRET_DEFAULT_SIZE 192 /* minimum XXH3_SECRET_SIZE_MIN */ + +#if (XXH_SECRET_DEFAULT_SIZE < XXH3_SECRET_SIZE_MIN) +# error "default keyset is not large enough" +#endif + +XXH_ALIGN(64) static const xxh_u8 kSecret[XXH_SECRET_DEFAULT_SIZE] = { + 0xb8, 0xfe, 0x6c, 0x39, 0x23, 0xa4, 0x4b, 0xbe, 0x7c, 0x01, 0x81, 0x2c, 0xf7, 0x21, 0xad, 0x1c, + 0xde, 0xd4, 0x6d, 0xe9, 0x83, 0x90, 0x97, 0xdb, 0x72, 0x40, 0xa4, 0xa4, 0xb7, 0xb3, 0x67, 0x1f, + 0xcb, 0x79, 0xe6, 0x4e, 0xcc, 0xc0, 0xe5, 0x78, 0x82, 0x5a, 0xd0, 0x7d, 0xcc, 0xff, 0x72, 0x21, + 0xb8, 0x08, 0x46, 0x74, 0xf7, 0x43, 0x24, 0x8e, 0xe0, 0x35, 0x90, 0xe6, 0x81, 0x3a, 0x26, 0x4c, + 0x3c, 0x28, 0x52, 0xbb, 0x91, 0xc3, 0x00, 0xcb, 0x88, 0xd0, 0x65, 0x8b, 0x1b, 0x53, 0x2e, 0xa3, + 0x71, 0x64, 0x48, 0x97, 0xa2, 0x0d, 0xf9, 0x4e, 0x38, 0x19, 0xef, 0x46, 0xa9, 0xde, 0xac, 0xd8, + 0xa8, 0xfa, 0x76, 0x3f, 0xe3, 0x9c, 0x34, 0x3f, 0xf9, 0xdc, 0xbb, 0xc7, 0xc7, 0x0b, 0x4f, 0x1d, + 0x8a, 0x51, 0xe0, 0x4b, 0xcd, 0xb4, 0x59, 0x31, 0xc8, 0x9f, 0x7e, 0xc9, 0xd9, 0x78, 0x73, 0x64, + + 0xea, 0xc5, 0xac, 0x83, 0x34, 0xd3, 0xeb, 0xc3, 0xc5, 0x81, 0xa0, 0xff, 0xfa, 0x13, 0x63, 0xeb, + 0x17, 0x0d, 0xdd, 0x51, 0xb7, 0xf0, 0xda, 0x49, 0xd3, 0x16, 0x55, 0x26, 0x29, 0xd4, 0x68, 0x9e, + 0x2b, 0x16, 0xbe, 0x58, 0x7d, 0x47, 0xa1, 0xfc, 0x8f, 0xf8, 0xb8, 0xd1, 0x7a, 0xd0, 0x31, 0xce, + 0x45, 0xcb, 0x3a, 0x8f, 0x95, 0x16, 0x04, 0x28, 0xaf, 0xd7, 0xfb, 0xca, 0xbb, 0x4b, 0x40, 0x7e, +}; + +/* + * GCC for x86 has a tendency to use SSE in this loop. While it + * successfully avoids swapping (as MUL overwrites EAX and EDX), it + * slows it down because instead of free register swap shifts, it + * must use pshufd and punpckl/hd. + * + * To prevent this, we use this attribute to shut off SSE. + */ +#if defined(__GNUC__) && !defined(__clang__) && defined(__i386__) +__attribute__((__target__("no-sse"))) +#endif +static XXH128_hash_t +XXH_mult64to128(xxh_u64 lhs, xxh_u64 rhs) +{ + /* + * GCC/Clang __uint128_t method. + * + * On most 64-bit targets, GCC and Clang define a __uint128_t type. + * This is usually the best way as it usually uses a native long 64-bit + * multiply, such as MULQ on x86_64 or MUL + UMULH on aarch64. + * + * Usually. + * + * Despite being a 32-bit platform, Clang (and emscripten) define this + * type despite not having the arithmetic for it. This results in a + * laggy compiler builtin call which calculates a full 128-bit multiply. + * In that case it is best to use the portable one. + * https://github.com/Cyan4973/xxHash/issues/211#issuecomment-515575677 + */ +#if defined(__GNUC__) && !defined(__wasm__) \ + && defined(__SIZEOF_INT128__) \ + || (defined(_INTEGRAL_MAX_BITS) && _INTEGRAL_MAX_BITS >= 128) + + __uint128_t product = (__uint128_t)lhs * (__uint128_t)rhs; + XXH128_hash_t const r128 = { (xxh_u64)(product), (xxh_u64)(product >> 64) }; + return r128; + + /* + * MSVC for x64's _umul128 method. + * + * xxh_u64 _umul128(xxh_u64 Multiplier, xxh_u64 Multiplicand, xxh_u64 *HighProduct); + * + * This compiles to single operand MUL on x64. + */ +#elif defined(_M_X64) || defined(_M_IA64) + +#ifndef _MSC_VER +# pragma intrinsic(_umul128) +#endif + xxh_u64 product_high; + xxh_u64 const product_low = _umul128(lhs, rhs, &product_high); + XXH128_hash_t const r128 = { product_low, product_high }; + return r128; + +#else + /* + * Portable scalar method. Optimized for 32-bit and 64-bit ALUs. + * + * This is a fast and simple grade school multiply, which is shown + * below with base 10 arithmetic instead of base 0x100000000. + * + * 9 3 // D2 lhs = 93 + * x 7 5 // D2 rhs = 75 + * ---------- + * 1 5 // D2 lo_lo = (93 % 10) * (75 % 10) + * 4 5 | // D2 hi_lo = (93 / 10) * (75 % 10) + * 2 1 | // D2 lo_hi = (93 % 10) * (75 / 10) + * + 6 3 | | // D2 hi_hi = (93 / 10) * (75 / 10) + * --------- + * 2 7 | // D2 cross = (15 / 10) + (45 % 10) + 21 + * + 6 7 | | // D2 upper = (27 / 10) + (45 / 10) + 63 + * --------- + * 6 9 7 5 + * + * The reasons for adding the products like this are: + * 1. It avoids manual carry tracking. Just like how + * (9 * 9) + 9 + 9 = 99, the same applies with this for + * UINT64_MAX. This avoids a lot of complexity. + * + * 2. It hints for, and on Clang, compiles to, the powerful UMAAL + * instruction available in ARMv6+ A32/T32, which is shown below: + * + * void UMAAL(xxh_u32 *RdLo, xxh_u32 *RdHi, xxh_u32 Rn, xxh_u32 Rm) + * { + * xxh_u64 product = (xxh_u64)*RdLo * (xxh_u64)*RdHi + Rn + Rm; + * *RdLo = (xxh_u32)(product & 0xFFFFFFFF); + * *RdHi = (xxh_u32)(product >> 32); + * } + * + * This instruction was designed for efficient long multiplication, + * and allows this to be calculated in only 4 instructions which + * is comparable to some 64-bit ALUs. + * + * 3. It isn't terrible on other platforms. Usually this will be + * a couple of 32-bit ADD/ADCs. + */ + + /* First calculate all of the cross products. */ + xxh_u64 const lo_lo = XXH_mult32to64(lhs & 0xFFFFFFFF, rhs & 0xFFFFFFFF); + xxh_u64 const hi_lo = XXH_mult32to64(lhs >> 32, rhs & 0xFFFFFFFF); + xxh_u64 const lo_hi = XXH_mult32to64(lhs & 0xFFFFFFFF, rhs >> 32); + xxh_u64 const hi_hi = XXH_mult32to64(lhs >> 32, rhs >> 32); + + /* Now add the products together. These will never overflow. */ + xxh_u64 const cross = (lo_lo >> 32) + (hi_lo & 0xFFFFFFFF) + lo_hi; + xxh_u64 const upper = (hi_lo >> 32) + (cross >> 32) + hi_hi; + xxh_u64 const lower = (cross << 32) | (lo_lo & 0xFFFFFFFF); + + XXH128_hash_t r128 = { lower, upper }; + return r128; +#endif +} + +/* + * We want to keep the attribute here because a target switch + * disables inlining. + * + * Does a 64-bit to 128-bit multiply, then XOR folds it. + * The reason for the separate function is to prevent passing + * too many structs around by value. This will hopefully inline + * the multiply, but we don't force it. + */ +#if defined(__GNUC__) && !defined(__clang__) && defined(__i386__) +__attribute__((__target__("no-sse"))) +#endif +static xxh_u64 +XXH3_mul128_fold64(xxh_u64 lhs, xxh_u64 rhs) +{ + XXH128_hash_t product = XXH_mult64to128(lhs, rhs); + return product.low64 ^ product.high64; +} + + +static XXH64_hash_t XXH3_avalanche(xxh_u64 h64) +{ + h64 ^= h64 >> 37; + h64 *= PRIME64_3; + h64 ^= h64 >> 32; + return h64; +} + + +/* ========================================== + * Short keys + * ========================================== */ + +XXH_FORCE_INLINE XXH64_hash_t +XXH3_len_1to3_64b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) +{ + XXH_ASSERT(input != NULL); + XXH_ASSERT(1 <= len && len <= 3); + XXH_ASSERT(secret != NULL); + { xxh_u8 const c1 = input[0]; + xxh_u8 const c2 = input[len >> 1]; + xxh_u8 const c3 = input[len - 1]; + xxh_u32 const combined = ((xxh_u32)c1) | (((xxh_u32)c2) << 8) | (((xxh_u32)c3) << 16) | (((xxh_u32)len) << 24); + xxh_u64 const keyed = (xxh_u64)combined ^ (XXH_readLE32(secret) + seed); + xxh_u64 const mixed = keyed * PRIME64_1; + return XXH3_avalanche(mixed); + } +} + +XXH_FORCE_INLINE XXH64_hash_t +XXH3_len_4to8_64b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) +{ + XXH_ASSERT(input != NULL); + XXH_ASSERT(secret != NULL); + XXH_ASSERT(4 <= len && len <= 8); + { xxh_u32 const input_lo = XXH_readLE32(input); + xxh_u32 const input_hi = XXH_readLE32(input + len - 4); + xxh_u64 const input_64 = input_lo | ((xxh_u64)input_hi << 32); + xxh_u64 const keyed = input_64 ^ (XXH_readLE64(secret) + seed); + xxh_u64 const mix64 = len + ((keyed ^ (keyed >> 51)) * PRIME32_1); + return XXH3_avalanche((mix64 ^ (mix64 >> 47)) * PRIME64_2); + } +} + +XXH_FORCE_INLINE XXH64_hash_t +XXH3_len_9to16_64b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) +{ + XXH_ASSERT(input != NULL); + XXH_ASSERT(secret != NULL); + XXH_ASSERT(9 <= len && len <= 16); + { xxh_u64 const input_lo = XXH_readLE64(input) ^ (XXH_readLE64(secret) + seed); + xxh_u64 const input_hi = XXH_readLE64(input + len - 8) ^ (XXH_readLE64(secret + 8) - seed); + xxh_u64 const acc = len + (input_lo + input_hi) + XXH3_mul128_fold64(input_lo, input_hi); + return XXH3_avalanche(acc); + } +} + +XXH_FORCE_INLINE XXH64_hash_t +XXH3_len_0to16_64b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) +{ + XXH_ASSERT(len <= 16); + { if (len > 8) return XXH3_len_9to16_64b(input, len, secret, seed); + if (len >= 4) return XXH3_len_4to8_64b(input, len, secret, seed); + if (len) return XXH3_len_1to3_64b(input, len, secret, seed); + return 0; + } +} + + +/* === Long Keys === */ + +#define STRIPE_LEN 64 +#define XXH_SECRET_CONSUME_RATE 8 /* nb of secret bytes consumed at each accumulation */ +#define ACC_NB (STRIPE_LEN / sizeof(xxh_u64)) + +typedef enum { XXH3_acc_64bits, XXH3_acc_128bits } XXH3_accWidth_e; + +XXH_FORCE_INLINE void +XXH3_accumulate_512( void* XXH_RESTRICT acc, + const void* XXH_RESTRICT input, + const void* XXH_RESTRICT secret, + XXH3_accWidth_e accWidth) +{ +#if (XXH_VECTOR == XXH_AVX2) + + XXH_ASSERT((((size_t)acc) & 31) == 0); + { XXH_ALIGN(32) __m256i* const xacc = (__m256i *) acc; + const __m256i* const xinput = (const __m256i *) input; /* not really aligned, just for ptr arithmetic, and because _mm256_loadu_si256() requires this type */ + const __m256i* const xsecret = (const __m256i *) secret; /* not really aligned, just for ptr arithmetic, and because _mm256_loadu_si256() requires this type */ + + size_t i; + for (i=0; i < STRIPE_LEN/sizeof(__m256i); i++) { + __m256i const data_vec = _mm256_loadu_si256 (xinput+i); + __m256i const key_vec = _mm256_loadu_si256 (xsecret+i); + __m256i const data_key = _mm256_xor_si256 (data_vec, key_vec); /* uint32 dk[8] = {d0+k0, d1+k1, d2+k2, d3+k3, ...} */ + __m256i const product = _mm256_mul_epu32 (data_key, _mm256_shuffle_epi32 (data_key, 0x31)); /* uint64 mul[4] = {dk0*dk1, dk2*dk3, ...} */ + if (accWidth == XXH3_acc_128bits) { + __m256i const data_swap = _mm256_shuffle_epi32(data_vec, _MM_SHUFFLE(1,0,3,2)); + __m256i const sum = _mm256_add_epi64(xacc[i], data_swap); + xacc[i] = _mm256_add_epi64(product, sum); + } else { /* XXH3_acc_64bits */ + __m256i const sum = _mm256_add_epi64(xacc[i], data_vec); + xacc[i] = _mm256_add_epi64(product, sum); + } + } } + +#elif (XXH_VECTOR == XXH_SSE2) + + XXH_ASSERT((((size_t)acc) & 15) == 0); + { XXH_ALIGN(16) __m128i* const xacc = (__m128i *) acc; + const __m128i* const xinput = (const __m128i *) input; /* not really aligned, just for ptr arithmetic, and because _mm_loadu_si128() requires this type */ + const __m128i* const xsecret = (const __m128i *) secret; /* not really aligned, just for ptr arithmetic, and because _mm_loadu_si128() requires this type */ + + size_t i; + for (i=0; i < STRIPE_LEN/sizeof(__m128i); i++) { + __m128i const data_vec = _mm_loadu_si128 (xinput+i); + __m128i const key_vec = _mm_loadu_si128 (xsecret+i); + __m128i const data_key = _mm_xor_si128 (data_vec, key_vec); /* uint32 dk[8] = {d0+k0, d1+k1, d2+k2, d3+k3, ...} */ + __m128i const product = _mm_mul_epu32 (data_key, _mm_shuffle_epi32 (data_key, 0x31)); /* uint64 mul[4] = {dk0*dk1, dk2*dk3, ...} */ + if (accWidth == XXH3_acc_128bits) { + __m128i const data_swap = _mm_shuffle_epi32(data_vec, _MM_SHUFFLE(1,0,3,2)); + __m128i const sum = _mm_add_epi64(xacc[i], data_swap); + xacc[i] = _mm_add_epi64(product, sum); + } else { /* XXH3_acc_64bits */ + __m128i const sum = _mm_add_epi64(xacc[i], data_vec); + xacc[i] = _mm_add_epi64(product, sum); + } + } } + +#elif (XXH_VECTOR == XXH_NEON) + + XXH_ASSERT((((size_t)acc) & 15) == 0); + { + XXH_ALIGN(16) uint64x2_t* const xacc = (uint64x2_t *) acc; + /* We don't use a uint32x4_t pointer because it causes bus errors on ARMv7. */ + uint8_t const* const xinput = (const uint8_t *) input; + uint8_t const* const xsecret = (const uint8_t *) secret; + + size_t i; + for (i=0; i < STRIPE_LEN / sizeof(uint64x2_t); i++) { +#if !defined(__aarch64__) && !defined(__arm64__) && defined(__GNUC__) /* ARM32-specific hack */ + /* vzip on ARMv7 Clang generates a lot of vmovs (technically vorrs) without this. + * vzip on 32-bit ARM NEON will overwrite the original register, and I think that Clang + * assumes I don't want to destroy it and tries to make a copy. This slows down the code + * a lot. + * aarch64 not only uses an entirely different syntax, but it requires three + * instructions... + * ext v1.16B, v0.16B, #8 // select high bits because aarch64 can't address them directly + * zip1 v3.2s, v0.2s, v1.2s // first zip + * zip2 v2.2s, v0.2s, v1.2s // second zip + * ...to do what ARM does in one: + * vzip.32 d0, d1 // Interleave high and low bits and overwrite. */ + + /* data_vec = xsecret[i]; */ + uint8x16_t const data_vec = vld1q_u8(xinput + (i * 16)); + /* key_vec = xsecret[i]; */ + uint8x16_t const key_vec = vld1q_u8(xsecret + (i * 16)); + /* data_key = data_vec ^ key_vec; */ + uint32x4_t data_key; + + if (accWidth == XXH3_acc_64bits) { + /* Add first to prevent register swaps */ + /* xacc[i] += data_vec; */ + xacc[i] = vaddq_u64 (xacc[i], vreinterpretq_u64_u8(data_vec)); + } else { /* XXH3_acc_128bits */ + /* xacc[i] += swap(data_vec); */ + /* can probably be optimized better */ + uint64x2_t const data64 = vreinterpretq_u64_u8(data_vec); + uint64x2_t const swapped= vextq_u64(data64, data64, 1); + xacc[i] = vaddq_u64 (xacc[i], swapped); + } + + data_key = vreinterpretq_u32_u8(veorq_u8(data_vec, key_vec)); + + /* Here's the magic. We use the quirkiness of vzip to shuffle data_key in place. + * shuffle: data_key[0, 1, 2, 3] = data_key[0, 2, 1, 3] */ + __asm__("vzip.32 %e0, %f0" : "+w" (data_key)); + /* xacc[i] += (uint64x2_t) data_key[0, 1] * (uint64x2_t) data_key[2, 3]; */ + xacc[i] = vmlal_u32(xacc[i], vget_low_u32(data_key), vget_high_u32(data_key)); + +#else + /* On aarch64, vshrn/vmovn seems to be equivalent to, if not faster than, the vzip method. */ + + /* data_vec = xsecret[i]; */ + uint8x16_t const data_vec = vld1q_u8(xinput + (i * 16)); + /* key_vec = xsecret[i]; */ + uint8x16_t const key_vec = vld1q_u8(xsecret + (i * 16)); + /* data_key = data_vec ^ key_vec; */ + uint64x2_t const data_key = vreinterpretq_u64_u8(veorq_u8(data_vec, key_vec)); + /* data_key_lo = (uint32x2_t) (data_key & 0xFFFFFFFF); */ + uint32x2_t const data_key_lo = vmovn_u64 (data_key); + /* data_key_hi = (uint32x2_t) (data_key >> 32); */ + uint32x2_t const data_key_hi = vshrn_n_u64 (data_key, 32); + if (accWidth == XXH3_acc_64bits) { + /* xacc[i] += data_vec; */ + xacc[i] = vaddq_u64 (xacc[i], vreinterpretq_u64_u8(data_vec)); + } else { /* XXH3_acc_128bits */ + /* xacc[i] += swap(data_vec); */ + uint64x2_t const data64 = vreinterpretq_u64_u8(data_vec); + uint64x2_t const swapped= vextq_u64(data64, data64, 1); + xacc[i] = vaddq_u64 (xacc[i], swapped); + } + /* xacc[i] += (uint64x2_t) data_key_lo * (uint64x2_t) data_key_hi; */ + xacc[i] = vmlal_u32 (xacc[i], data_key_lo, data_key_hi); + +#endif + } + } + +#elif (XXH_VECTOR == XXH_VSX) + U64x2* const xacc = (U64x2*) acc; /* presumed aligned */ + U64x2 const* const xinput = (U64x2 const*) input; /* no alignment restriction */ + U64x2 const* const xsecret = (U64x2 const*) secret; /* no alignment restriction */ + U64x2 const v32 = { 32, 32 }; +#if XXH_VSX_BE + U8x16 const vXorSwap = { 0x07, 0x16, 0x25, 0x34, 0x43, 0x52, 0x61, 0x70, + 0x8F, 0x9E, 0xAD, 0xBC, 0xCB, 0xDA, 0xE9, 0xF8 }; +#endif + size_t i; + for (i = 0; i < STRIPE_LEN / sizeof(U64x2); i++) { + /* data_vec = xinput[i]; */ + /* key_vec = xsecret[i]; */ +#if XXH_VSX_BE + /* byteswap */ + U64x2 const data_vec = XXH_vec_revb(vec_vsx_ld(0, xinput + i)); + U64x2 const key_raw = vec_vsx_ld(0, xsecret + i); + /* See comment above. data_key = data_vec ^ swap(xsecret[i]); */ + U64x2 const data_key = (U64x2)XXH_vec_permxor((U8x16)data_vec, (U8x16)key_raw, vXorSwap); +#else + U64x2 const data_vec = vec_vsx_ld(0, xinput + i); + U64x2 const key_vec = vec_vsx_ld(0, xsecret + i); + U64x2 const data_key = data_vec ^ key_vec; +#endif + /* shuffled = (data_key << 32) | (data_key >> 32); */ + U32x4 const shuffled = (U32x4)vec_rl(data_key, v32); + /* product = ((U64x2)data_key & 0xFFFFFFFF) * ((U64x2)shuffled & 0xFFFFFFFF); */ + U64x2 const product = XXH_vec_mulo((U32x4)data_key, shuffled); + xacc[i] += product; + + if (accWidth == XXH3_acc_64bits) { + xacc[i] += data_vec; + } else { /* XXH3_acc_128bits */ + /* swap high and low halves */ + U64x2 const data_swapped = vec_xxpermdi(data_vec, data_vec, 2); + xacc[i] += data_swapped; + } + } + +#else /* scalar variant of Accumulator - universal */ + + XXH_ALIGN(XXH_ACC_ALIGN) xxh_u64* const xacc = (xxh_u64*) acc; /* presumed aligned on 32-bytes boundaries, little hint for the auto-vectorizer */ + const xxh_u8* const xinput = (const xxh_u8*) input; /* no alignment restriction */ + const xxh_u8* const xsecret = (const xxh_u8*) secret; /* no alignment restriction */ + size_t i; + XXH_ASSERT(((size_t)acc & (XXH_ACC_ALIGN-1)) == 0); + for (i=0; i < ACC_NB; i++) { + xxh_u64 const data_val = XXH_readLE64(xinput + 8*i); + xxh_u64 const data_key = data_val ^ XXH_readLE64(xsecret + i*8); + + if (accWidth == XXH3_acc_64bits) { + xacc[i] += data_val; + } else { + xacc[i ^ 1] += data_val; /* swap adjacent lanes */ + } + xacc[i] += XXH_mult32to64(data_key & 0xFFFFFFFF, data_key >> 32); + } +#endif +} + +XXH_FORCE_INLINE void +XXH3_scrambleAcc(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) +{ +#if (XXH_VECTOR == XXH_AVX2) + + XXH_ASSERT((((size_t)acc) & 31) == 0); + { XXH_ALIGN(32) __m256i* const xacc = (__m256i*) acc; + const __m256i* const xsecret = (const __m256i *) secret; /* not really aligned, just for ptr arithmetic, and because _mm256_loadu_si256() requires this argument type */ + const __m256i prime32 = _mm256_set1_epi32((int)PRIME32_1); + + size_t i; + for (i=0; i < STRIPE_LEN/sizeof(__m256i); i++) { + /* xacc[i] ^= (xacc[i] >> 47) */ + __m256i const acc_vec = xacc[i]; + __m256i const shifted = _mm256_srli_epi64 (acc_vec, 47); + __m256i const data_vec = _mm256_xor_si256 (acc_vec, shifted); + /* xacc[i] ^= xsecret; */ + __m256i const key_vec = _mm256_loadu_si256 (xsecret+i); + __m256i const data_key = _mm256_xor_si256 (data_vec, key_vec); + + /* xacc[i] *= PRIME32_1; */ + __m256i const data_key_hi = _mm256_shuffle_epi32 (data_key, 0x31); + __m256i const prod_lo = _mm256_mul_epu32 (data_key, prime32); + __m256i const prod_hi = _mm256_mul_epu32 (data_key_hi, prime32); + xacc[i] = _mm256_add_epi64(prod_lo, _mm256_slli_epi64(prod_hi, 32)); + } + } + +#elif (XXH_VECTOR == XXH_SSE2) + + XXH_ASSERT((((size_t)acc) & 15) == 0); + { XXH_ALIGN(16) __m128i* const xacc = (__m128i*) acc; + const __m128i* const xsecret = (const __m128i *) secret; /* not really aligned, just for ptr arithmetic, and because _mm_loadu_si128() requires this argument type */ + const __m128i prime32 = _mm_set1_epi32((int)PRIME32_1); + + size_t i; + for (i=0; i < STRIPE_LEN/sizeof(__m128i); i++) { + /* xacc[i] ^= (xacc[i] >> 47) */ + __m128i const acc_vec = xacc[i]; + __m128i const shifted = _mm_srli_epi64 (acc_vec, 47); + __m128i const data_vec = _mm_xor_si128 (acc_vec, shifted); + /* xacc[i] ^= xsecret; */ + __m128i const key_vec = _mm_loadu_si128 (xsecret+i); + __m128i const data_key = _mm_xor_si128 (data_vec, key_vec); + + /* xacc[i] *= PRIME32_1; */ + __m128i const data_key_hi = _mm_shuffle_epi32 (data_key, 0x31); + __m128i const prod_lo = _mm_mul_epu32 (data_key, prime32); + __m128i const prod_hi = _mm_mul_epu32 (data_key_hi, prime32); + xacc[i] = _mm_add_epi64(prod_lo, _mm_slli_epi64(prod_hi, 32)); + } + } + +#elif (XXH_VECTOR == XXH_NEON) + + XXH_ASSERT((((size_t)acc) & 15) == 0); + + { uint64x2_t* const xacc = (uint64x2_t*) acc; + uint8_t const* const xsecret = (uint8_t const*) secret; + uint32x2_t const prime = vdup_n_u32 (PRIME32_1); + + size_t i; + for (i=0; i < STRIPE_LEN/sizeof(uint64x2_t); i++) { + /* data_vec = xacc[i] ^ (xacc[i] >> 47); */ + uint64x2_t const acc_vec = xacc[i]; + uint64x2_t const shifted = vshrq_n_u64 (acc_vec, 47); + uint64x2_t const data_vec = veorq_u64 (acc_vec, shifted); + + /* key_vec = xsecret[i]; */ + uint32x4_t const key_vec = vreinterpretq_u32_u8(vld1q_u8(xsecret + (i * 16))); + /* data_key = data_vec ^ key_vec; */ + uint32x4_t const data_key = veorq_u32 (vreinterpretq_u32_u64(data_vec), key_vec); + /* shuffled = { data_key[0, 2], data_key[1, 3] }; */ + uint32x2x2_t const shuffled = vzip_u32 (vget_low_u32(data_key), vget_high_u32(data_key)); + + /* data_key *= PRIME32_1 */ + + /* prod_hi = (data_key >> 32) * PRIME32_1; */ + uint64x2_t const prod_hi = vmull_u32 (shuffled.val[1], prime); + /* xacc[i] = prod_hi << 32; */ + xacc[i] = vshlq_n_u64(prod_hi, 32); + /* xacc[i] += (prod_hi & 0xFFFFFFFF) * PRIME32_1; */ + xacc[i] = vmlal_u32(xacc[i], shuffled.val[0], prime); + } } + +#elif (XXH_VECTOR == XXH_VSX) + + U64x2* const xacc = (U64x2*) acc; + const U64x2* const xsecret = (const U64x2*) secret; + /* constants */ + U64x2 const v32 = { 32, 32 }; + U64x2 const v47 = { 47, 47 }; + U32x4 const prime = { PRIME32_1, PRIME32_1, PRIME32_1, PRIME32_1 }; + size_t i; +#if XXH_VSX_BE + /* endian swap */ + U8x16 const vXorSwap = { 0x07, 0x16, 0x25, 0x34, 0x43, 0x52, 0x61, 0x70, + 0x8F, 0x9E, 0xAD, 0xBC, 0xCB, 0xDA, 0xE9, 0xF8 }; +#endif + for (i = 0; i < STRIPE_LEN / sizeof(U64x2); i++) { + U64x2 const acc_vec = xacc[i]; + U64x2 const data_vec = acc_vec ^ (acc_vec >> v47); + /* key_vec = xsecret[i]; */ +#if XXH_VSX_BE + /* swap bytes words */ + U64x2 const key_raw = vec_vsx_ld(0, xsecret + i); + U64x2 const data_key = (U64x2)XXH_vec_permxor((U8x16)data_vec, (U8x16)key_raw, vXorSwap); +#else + U64x2 const key_vec = vec_vsx_ld(0, xsecret + i); + U64x2 const data_key = data_vec ^ key_vec; +#endif + + /* data_key *= PRIME32_1 */ + + /* prod_lo = ((U64x2)data_key & 0xFFFFFFFF) * ((U64x2)prime & 0xFFFFFFFF); */ + U64x2 const prod_even = XXH_vec_mule((U32x4)data_key, prime); + /* prod_hi = ((U64x2)data_key >> 32) * ((U64x2)prime >> 32); */ + U64x2 const prod_odd = XXH_vec_mulo((U32x4)data_key, prime); + xacc[i] = prod_odd + (prod_even << v32); + } + +#else /* scalar variant of Scrambler - universal */ + + XXH_ALIGN(XXH_ACC_ALIGN) xxh_u64* const xacc = (xxh_u64*) acc; /* presumed aligned on 32-bytes boundaries, little hint for the auto-vectorizer */ + const xxh_u8* const xsecret = (const xxh_u8*) secret; /* no alignment restriction */ + size_t i; + XXH_ASSERT((((size_t)acc) & (XXH_ACC_ALIGN-1)) == 0); + for (i=0; i < ACC_NB; i++) { + xxh_u64 const key64 = XXH_readLE64(xsecret + 8*i); + xxh_u64 acc64 = xacc[i]; + acc64 ^= acc64 >> 47; + acc64 ^= key64; + acc64 *= PRIME32_1; + xacc[i] = acc64; + } + +#endif +} + +/* assumption : nbStripes will not overflow secret size */ +XXH_FORCE_INLINE void +XXH3_accumulate( xxh_u64* XXH_RESTRICT acc, + const xxh_u8* XXH_RESTRICT input, + const xxh_u8* XXH_RESTRICT secret, + size_t nbStripes, + XXH3_accWidth_e accWidth) +{ + size_t n; + for (n = 0; n < nbStripes; n++ ) { + XXH3_accumulate_512(acc, + input + n*STRIPE_LEN, + secret + n*XXH_SECRET_CONSUME_RATE, + accWidth); + } +} + +/* note : clang auto-vectorizes well in SS2 mode _if_ this function is `static`, + * and doesn't auto-vectorize it at all if it is `FORCE_INLINE`. + * However, it auto-vectorizes better AVX2 if it is `FORCE_INLINE` + * Pretty much every other modes and compilers prefer `FORCE_INLINE`. + */ + +#if defined(__clang__) && (XXH_VECTOR==0) && !defined(__AVX2__) && !defined(__arm__) && !defined(__thumb__) +static void +#else +XXH_FORCE_INLINE void +#endif +XXH3_hashLong_internal_loop( xxh_u64* XXH_RESTRICT acc, + const xxh_u8* XXH_RESTRICT input, size_t len, + const xxh_u8* XXH_RESTRICT secret, size_t secretSize, + XXH3_accWidth_e accWidth) +{ + size_t const nb_rounds = (secretSize - STRIPE_LEN) / XXH_SECRET_CONSUME_RATE; + size_t const block_len = STRIPE_LEN * nb_rounds; + size_t const nb_blocks = len / block_len; + + size_t n; + + XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); + + for (n = 0; n < nb_blocks; n++) { + XXH3_accumulate(acc, input + n*block_len, secret, nb_rounds, accWidth); + XXH3_scrambleAcc(acc, secret + secretSize - STRIPE_LEN); + } + + /* last partial block */ + XXH_ASSERT(len > STRIPE_LEN); + { size_t const nbStripes = (len - (block_len * nb_blocks)) / STRIPE_LEN; + XXH_ASSERT(nbStripes <= (secretSize / XXH_SECRET_CONSUME_RATE)); + XXH3_accumulate(acc, input + nb_blocks*block_len, secret, nbStripes, accWidth); + + /* last stripe */ + if (len & (STRIPE_LEN - 1)) { + const xxh_u8* const p = input + len - STRIPE_LEN; +#define XXH_SECRET_LASTACC_START 7 /* do not align on 8, so that secret is different from scrambler */ + XXH3_accumulate_512(acc, p, secret + secretSize - STRIPE_LEN - XXH_SECRET_LASTACC_START, accWidth); + } } +} + +XXH_FORCE_INLINE xxh_u64 +XXH3_mix2Accs(const xxh_u64* XXH_RESTRICT acc, const xxh_u8* XXH_RESTRICT secret) +{ + return XXH3_mul128_fold64( + acc[0] ^ XXH_readLE64(secret), + acc[1] ^ XXH_readLE64(secret+8) ); +} + +static XXH64_hash_t +XXH3_mergeAccs(const xxh_u64* XXH_RESTRICT acc, const xxh_u8* XXH_RESTRICT secret, xxh_u64 start) +{ + xxh_u64 result64 = start; + + result64 += XXH3_mix2Accs(acc+0, secret + 0); + result64 += XXH3_mix2Accs(acc+2, secret + 16); + result64 += XXH3_mix2Accs(acc+4, secret + 32); + result64 += XXH3_mix2Accs(acc+6, secret + 48); + + return XXH3_avalanche(result64); +} + +#define XXH3_INIT_ACC { PRIME32_3, PRIME64_1, PRIME64_2, PRIME64_3, \ + PRIME64_4, PRIME32_2, PRIME64_5, PRIME32_1 }; + +XXH_FORCE_INLINE XXH64_hash_t +XXH3_hashLong_internal(const xxh_u8* XXH_RESTRICT input, size_t len, + const xxh_u8* XXH_RESTRICT secret, size_t secretSize) +{ + XXH_ALIGN(XXH_ACC_ALIGN) xxh_u64 acc[ACC_NB] = XXH3_INIT_ACC; + + XXH3_hashLong_internal_loop(acc, input, len, secret, secretSize, XXH3_acc_64bits); + + /* converge into final hash */ + XXH_STATIC_ASSERT(sizeof(acc) == 64); +#define XXH_SECRET_MERGEACCS_START 11 /* do not align on 8, so that secret is different from accumulator */ + XXH_ASSERT(secretSize >= sizeof(acc) + XXH_SECRET_MERGEACCS_START); + return XXH3_mergeAccs(acc, secret + XXH_SECRET_MERGEACCS_START, (xxh_u64)len * PRIME64_1); +} + + +XXH_NO_INLINE XXH64_hash_t /* It's important for performance that XXH3_hashLong is not inlined. Not sure why (uop cache maybe ?), but difference is large and easily measurable */ +XXH3_hashLong_64b_defaultSecret(const xxh_u8* XXH_RESTRICT input, size_t len) +{ + return XXH3_hashLong_internal(input, len, kSecret, sizeof(kSecret)); +} + +XXH_NO_INLINE XXH64_hash_t /* It's important for performance that XXH3_hashLong is not inlined. Not sure why (uop cache maybe ?), but difference is large and easily measurable */ +XXH3_hashLong_64b_withSecret(const xxh_u8* XXH_RESTRICT input, size_t len, + const xxh_u8* XXH_RESTRICT secret, size_t secretSize) +{ + return XXH3_hashLong_internal(input, len, secret, secretSize); +} + + +XXH_FORCE_INLINE void XXH_writeLE64(void* dst, xxh_u64 v64) +{ + if (!XXH_CPU_LITTLE_ENDIAN) v64 = XXH_swap64(v64); + memcpy(dst, &v64, sizeof(v64)); +} + +/* XXH3_initCustomSecret() : + * destination `customSecret` is presumed allocated and same size as `kSecret`. + */ +XXH_FORCE_INLINE void XXH3_initCustomSecret(xxh_u8* customSecret, xxh_u64 seed64) +{ + int const nbRounds = XXH_SECRET_DEFAULT_SIZE / 16; + int i; + + XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE & 15) == 0); + + for (i=0; i < nbRounds; i++) { + XXH_writeLE64(customSecret + 16*i, XXH_readLE64(kSecret + 16*i) + seed64); + XXH_writeLE64(customSecret + 16*i + 8, XXH_readLE64(kSecret + 16*i + 8) - seed64); + } +} + + +/* XXH3_hashLong_64b_withSeed() : + * Generate a custom key, + * based on alteration of default kSecret with the seed, + * and then use this key for long mode hashing. + * This operation is decently fast but nonetheless costs a little bit of time. + * Try to avoid it whenever possible (typically when seed==0). + */ +XXH_NO_INLINE XXH64_hash_t /* It's important for performance that XXH3_hashLong is not inlined. Not sure why (uop cache maybe ?), but difference is large and easily measurable */ +XXH3_hashLong_64b_withSeed(const xxh_u8* input, size_t len, XXH64_hash_t seed) +{ + XXH_ALIGN(8) xxh_u8 secret[XXH_SECRET_DEFAULT_SIZE]; + if (seed==0) return XXH3_hashLong_64b_defaultSecret(input, len); + XXH3_initCustomSecret(secret, seed); + return XXH3_hashLong_internal(input, len, secret, sizeof(secret)); +} + + +XXH_FORCE_INLINE xxh_u64 XXH3_mix16B(const xxh_u8* XXH_RESTRICT input, + const xxh_u8* XXH_RESTRICT secret, xxh_u64 seed64) +{ + xxh_u64 const input_lo = XXH_readLE64(input); + xxh_u64 const input_hi = XXH_readLE64(input+8); + return XXH3_mul128_fold64( + input_lo ^ (XXH_readLE64(secret) + seed64), + input_hi ^ (XXH_readLE64(secret+8) - seed64) ); +} + + +XXH_FORCE_INLINE XXH64_hash_t +XXH3_len_17to128_64b(const xxh_u8* XXH_RESTRICT input, size_t len, + const xxh_u8* XXH_RESTRICT secret, size_t secretSize, + XXH64_hash_t seed) +{ + XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); (void)secretSize; + XXH_ASSERT(16 < len && len <= 128); + + { xxh_u64 acc = len * PRIME64_1; + if (len > 32) { + if (len > 64) { + if (len > 96) { + acc += XXH3_mix16B(input+48, secret+96, seed); + acc += XXH3_mix16B(input+len-64, secret+112, seed); + } + acc += XXH3_mix16B(input+32, secret+64, seed); + acc += XXH3_mix16B(input+len-48, secret+80, seed); + } + acc += XXH3_mix16B(input+16, secret+32, seed); + acc += XXH3_mix16B(input+len-32, secret+48, seed); + } + acc += XXH3_mix16B(input+0, secret+0, seed); + acc += XXH3_mix16B(input+len-16, secret+16, seed); + + return XXH3_avalanche(acc); + } +} + +#define XXH3_MIDSIZE_MAX 240 + +XXH_NO_INLINE XXH64_hash_t +XXH3_len_129to240_64b(const xxh_u8* XXH_RESTRICT input, size_t len, + const xxh_u8* XXH_RESTRICT secret, size_t secretSize, + XXH64_hash_t seed) +{ + XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); (void)secretSize; + XXH_ASSERT(128 < len && len <= XXH3_MIDSIZE_MAX); + + #define XXH3_MIDSIZE_STARTOFFSET 3 + #define XXH3_MIDSIZE_LASTOFFSET 17 + + { xxh_u64 acc = len * PRIME64_1; + int const nbRounds = (int)len / 16; + int i; + for (i=0; i<8; i++) { + acc += XXH3_mix16B(input+(16*i), secret+(16*i), seed); + } + acc = XXH3_avalanche(acc); + XXH_ASSERT(nbRounds >= 8); + for (i=8 ; i < nbRounds; i++) { + acc += XXH3_mix16B(input+(16*i), secret+(16*(i-8)) + XXH3_MIDSIZE_STARTOFFSET, seed); + } + /* last bytes */ + acc += XXH3_mix16B(input + len - 16, secret + XXH3_SECRET_SIZE_MIN - XXH3_MIDSIZE_LASTOFFSET, seed); + return XXH3_avalanche(acc); + } +} + +/* === Public entry point === */ + +XXH_PUBLIC_API XXH64_hash_t XXH3_64bits(const void* input, size_t len) +{ + if (len <= 16) return XXH3_len_0to16_64b((const xxh_u8*)input, len, kSecret, 0); + if (len <= 128) return XXH3_len_17to128_64b((const xxh_u8*)input, len, kSecret, sizeof(kSecret), 0); + if (len <= XXH3_MIDSIZE_MAX) return XXH3_len_129to240_64b((const xxh_u8*)input, len, kSecret, sizeof(kSecret), 0); + return XXH3_hashLong_64b_defaultSecret((const xxh_u8*)input, len); +} + +XXH_PUBLIC_API XXH64_hash_t +XXH3_64bits_withSecret(const void* input, size_t len, const void* secret, size_t secretSize) +{ + XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); + /* if an action must be taken should `secret` conditions not be respected, + * it should be done here. + * For now, it's a contract pre-condition. + * Adding a check and a branch here would cost performance at every hash */ + if (len <= 16) return XXH3_len_0to16_64b((const xxh_u8*)input, len, (const xxh_u8*)secret, 0); + if (len <= 128) return XXH3_len_17to128_64b((const xxh_u8*)input, len, (const xxh_u8*)secret, secretSize, 0); + if (len <= XXH3_MIDSIZE_MAX) return XXH3_len_129to240_64b((const xxh_u8*)input, len, (const xxh_u8*)secret, secretSize, 0); + return XXH3_hashLong_64b_withSecret((const xxh_u8*)input, len, (const xxh_u8*)secret, secretSize); +} + +XXH_PUBLIC_API XXH64_hash_t +XXH3_64bits_withSeed(const void* input, size_t len, XXH64_hash_t seed) +{ + if (len <= 16) return XXH3_len_0to16_64b((const xxh_u8*)input, len, kSecret, seed); + if (len <= 128) return XXH3_len_17to128_64b((const xxh_u8*)input, len, kSecret, sizeof(kSecret), seed); + if (len <= XXH3_MIDSIZE_MAX) return XXH3_len_129to240_64b((const xxh_u8*)input, len, kSecret, sizeof(kSecret), seed); + return XXH3_hashLong_64b_withSeed((const xxh_u8*)input, len, seed); +} + +/* === XXH3 streaming === */ + +XXH_PUBLIC_API XXH3_state_t* XXH3_createState(void) +{ + return (XXH3_state_t*)XXH_malloc(sizeof(XXH3_state_t)); +} + +XXH_PUBLIC_API XXH_errorcode XXH3_freeState(XXH3_state_t* statePtr) +{ + XXH_free(statePtr); + return XXH_OK; +} + +XXH_PUBLIC_API void +XXH3_copyState(XXH3_state_t* dst_state, const XXH3_state_t* src_state) +{ + memcpy(dst_state, src_state, sizeof(*dst_state)); +} + +static void +XXH3_64bits_reset_internal(XXH3_state_t* statePtr, + XXH64_hash_t seed, + const xxh_u8* secret, size_t secretSize) +{ + XXH_ASSERT(statePtr != NULL); + memset(statePtr, 0, sizeof(*statePtr)); + statePtr->acc[0] = PRIME32_3; + statePtr->acc[1] = PRIME64_1; + statePtr->acc[2] = PRIME64_2; + statePtr->acc[3] = PRIME64_3; + statePtr->acc[4] = PRIME64_4; + statePtr->acc[5] = PRIME32_2; + statePtr->acc[6] = PRIME64_5; + statePtr->acc[7] = PRIME32_1; + statePtr->seed = seed; + XXH_ASSERT(secret != NULL); + statePtr->secret = secret; + XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); + statePtr->secretLimit = (XXH32_hash_t)(secretSize - STRIPE_LEN); + statePtr->nbStripesPerBlock = statePtr->secretLimit / XXH_SECRET_CONSUME_RATE; +} + +XXH_PUBLIC_API XXH_errorcode +XXH3_64bits_reset(XXH3_state_t* statePtr) +{ + if (statePtr == NULL) return XXH_ERROR; + XXH3_64bits_reset_internal(statePtr, 0, kSecret, XXH_SECRET_DEFAULT_SIZE); + return XXH_OK; +} + +XXH_PUBLIC_API XXH_errorcode +XXH3_64bits_reset_withSecret(XXH3_state_t* statePtr, const void* secret, size_t secretSize) +{ + if (statePtr == NULL) return XXH_ERROR; + XXH3_64bits_reset_internal(statePtr, 0, (const xxh_u8*)secret, secretSize); + if (secret == NULL) return XXH_ERROR; + if (secretSize < XXH3_SECRET_SIZE_MIN) return XXH_ERROR; + return XXH_OK; +} + +XXH_PUBLIC_API XXH_errorcode +XXH3_64bits_reset_withSeed(XXH3_state_t* statePtr, XXH64_hash_t seed) +{ + if (statePtr == NULL) return XXH_ERROR; + XXH3_64bits_reset_internal(statePtr, seed, kSecret, XXH_SECRET_DEFAULT_SIZE); + XXH3_initCustomSecret(statePtr->customSecret, seed); + statePtr->secret = statePtr->customSecret; + return XXH_OK; +} + +XXH_FORCE_INLINE void +XXH3_consumeStripes( xxh_u64* acc, + XXH32_hash_t* nbStripesSoFarPtr, XXH32_hash_t nbStripesPerBlock, + const xxh_u8* input, size_t totalStripes, + const xxh_u8* secret, size_t secretLimit, + XXH3_accWidth_e accWidth) +{ + XXH_ASSERT(*nbStripesSoFarPtr < nbStripesPerBlock); + if (nbStripesPerBlock - *nbStripesSoFarPtr <= totalStripes) { + /* need a scrambling operation */ + size_t const nbStripes = nbStripesPerBlock - *nbStripesSoFarPtr; + XXH3_accumulate(acc, input, secret + nbStripesSoFarPtr[0] * XXH_SECRET_CONSUME_RATE, nbStripes, accWidth); + XXH3_scrambleAcc(acc, secret + secretLimit); + XXH3_accumulate(acc, input + nbStripes * STRIPE_LEN, secret, totalStripes - nbStripes, accWidth); + *nbStripesSoFarPtr = (XXH32_hash_t)(totalStripes - nbStripes); + } else { + XXH3_accumulate(acc, input, secret + nbStripesSoFarPtr[0] * XXH_SECRET_CONSUME_RATE, totalStripes, accWidth); + *nbStripesSoFarPtr += (XXH32_hash_t)totalStripes; + } +} + +XXH_FORCE_INLINE XXH_errorcode +XXH3_update(XXH3_state_t* state, const xxh_u8* input, size_t len, XXH3_accWidth_e accWidth) +{ + if (input==NULL) +#if defined(XXH_ACCEPT_NULL_INPUT_POINTER) && (XXH_ACCEPT_NULL_INPUT_POINTER>=1) + return XXH_OK; +#else + return XXH_ERROR; +#endif + + { const xxh_u8* const bEnd = input + len; + + state->totalLen += len; + + if (state->bufferedSize + len <= XXH3_INTERNALBUFFER_SIZE) { /* fill in tmp buffer */ + XXH_memcpy(state->buffer + state->bufferedSize, input, len); + state->bufferedSize += (XXH32_hash_t)len; + return XXH_OK; + } + /* input now > XXH3_INTERNALBUFFER_SIZE */ + + #define XXH3_INTERNALBUFFER_STRIPES (XXH3_INTERNALBUFFER_SIZE / STRIPE_LEN) + XXH_STATIC_ASSERT(XXH3_INTERNALBUFFER_SIZE % STRIPE_LEN == 0); /* clean multiple */ + + if (state->bufferedSize) { /* some input within internal buffer: fill then consume it */ + size_t const loadSize = XXH3_INTERNALBUFFER_SIZE - state->bufferedSize; + XXH_memcpy(state->buffer + state->bufferedSize, input, loadSize); + input += loadSize; + XXH3_consumeStripes(state->acc, + &state->nbStripesSoFar, state->nbStripesPerBlock, + state->buffer, XXH3_INTERNALBUFFER_STRIPES, + state->secret, state->secretLimit, + accWidth); + state->bufferedSize = 0; + } + + /* consume input by full buffer quantities */ + if (input+XXH3_INTERNALBUFFER_SIZE <= bEnd) { + const xxh_u8* const limit = bEnd - XXH3_INTERNALBUFFER_SIZE; + do { + XXH3_consumeStripes(state->acc, + &state->nbStripesSoFar, state->nbStripesPerBlock, + input, XXH3_INTERNALBUFFER_STRIPES, + state->secret, state->secretLimit, + accWidth); + input += XXH3_INTERNALBUFFER_SIZE; + } while (input<=limit); + } + + if (input < bEnd) { /* some remaining input input : buffer it */ + XXH_memcpy(state->buffer, input, (size_t)(bEnd-input)); + state->bufferedSize = (XXH32_hash_t)(bEnd-input); + } + } + + return XXH_OK; +} + +XXH_PUBLIC_API XXH_errorcode +XXH3_64bits_update(XXH3_state_t* state, const void* input, size_t len) +{ + return XXH3_update(state, (const xxh_u8*)input, len, XXH3_acc_64bits); +} + + +XXH_FORCE_INLINE void +XXH3_digest_long (XXH64_hash_t* acc, const XXH3_state_t* state, XXH3_accWidth_e accWidth) +{ + memcpy(acc, state->acc, sizeof(state->acc)); /* digest locally, state remains unaltered, and can continue ingesting more input afterwards */ + if (state->bufferedSize >= STRIPE_LEN) { + size_t const totalNbStripes = state->bufferedSize / STRIPE_LEN; + XXH32_hash_t nbStripesSoFar = state->nbStripesSoFar; + XXH3_consumeStripes(acc, + &nbStripesSoFar, state->nbStripesPerBlock, + state->buffer, totalNbStripes, + state->secret, state->secretLimit, + accWidth); + if (state->bufferedSize % STRIPE_LEN) { /* one last partial stripe */ + XXH3_accumulate_512(acc, + state->buffer + state->bufferedSize - STRIPE_LEN, + state->secret + state->secretLimit - XXH_SECRET_LASTACC_START, + accWidth); + } + } else { /* bufferedSize < STRIPE_LEN */ + if (state->bufferedSize) { /* one last stripe */ + xxh_u8 lastStripe[STRIPE_LEN]; + size_t const catchupSize = STRIPE_LEN - state->bufferedSize; + memcpy(lastStripe, state->buffer + sizeof(state->buffer) - catchupSize, catchupSize); + memcpy(lastStripe + catchupSize, state->buffer, state->bufferedSize); + XXH3_accumulate_512(acc, + lastStripe, + state->secret + state->secretLimit - XXH_SECRET_LASTACC_START, + accWidth); + } } +} + +XXH_PUBLIC_API XXH64_hash_t XXH3_64bits_digest (const XXH3_state_t* state) +{ + if (state->totalLen > XXH3_MIDSIZE_MAX) { + XXH_ALIGN(XXH_ACC_ALIGN) XXH64_hash_t acc[ACC_NB]; + XXH3_digest_long(acc, state, XXH3_acc_64bits); + return XXH3_mergeAccs(acc, state->secret + XXH_SECRET_MERGEACCS_START, (xxh_u64)state->totalLen * PRIME64_1); + } + /* len <= XXH3_MIDSIZE_MAX : short code */ + if (state->seed) + return XXH3_64bits_withSeed(state->buffer, (size_t)state->totalLen, state->seed); + return XXH3_64bits_withSecret(state->buffer, (size_t)(state->totalLen), state->secret, state->secretLimit + STRIPE_LEN); +} + +/* ========================================== + * XXH3 128 bits (=> XXH128) + * ========================================== */ + +XXH_FORCE_INLINE XXH128_hash_t +XXH3_len_1to3_128b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) +{ + XXH_ASSERT(input != NULL); + XXH_ASSERT(1 <= len && len <= 3); + XXH_ASSERT(secret != NULL); + { xxh_u8 const c1 = input[0]; + xxh_u8 const c2 = input[len >> 1]; + xxh_u8 const c3 = input[len - 1]; + xxh_u32 const combinedl = ((xxh_u32)c1) + (((xxh_u32)c2) << 8) + (((xxh_u32)c3) << 16) + (((xxh_u32)len) << 24); + xxh_u32 const combinedh = XXH_swap32(combinedl); + xxh_u64 const keyed_lo = (xxh_u64)combinedl ^ (XXH_readLE32(secret) + seed); + xxh_u64 const keyed_hi = (xxh_u64)combinedh ^ (XXH_readLE32(secret+4) - seed); + xxh_u64 const mixedl = keyed_lo * PRIME64_1; + xxh_u64 const mixedh = keyed_hi * PRIME64_5; + XXH128_hash_t const h128 = { XXH3_avalanche(mixedl) /*low64*/, XXH3_avalanche(mixedh) /*high64*/ }; + return h128; + } +} + + +XXH_FORCE_INLINE XXH128_hash_t +XXH3_len_4to8_128b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) +{ + XXH_ASSERT(input != NULL); + XXH_ASSERT(secret != NULL); + XXH_ASSERT(4 <= len && len <= 8); + { xxh_u32 const input_lo = XXH_readLE32(input); + xxh_u32 const input_hi = XXH_readLE32(input + len - 4); + xxh_u64 const input_64_lo = input_lo + ((xxh_u64)input_hi << 32); + xxh_u64 const input_64_hi = XXH_swap64(input_64_lo); + xxh_u64 const keyed_lo = input_64_lo ^ (XXH_readLE64(secret) + seed); + xxh_u64 const keyed_hi = input_64_hi ^ (XXH_readLE64(secret + 8) - seed); + xxh_u64 const mix64l1 = len + ((keyed_lo ^ (keyed_lo >> 51)) * PRIME32_1); + xxh_u64 const mix64l2 = (mix64l1 ^ (mix64l1 >> 47)) * PRIME64_2; + xxh_u64 const mix64h1 = ((keyed_hi ^ (keyed_hi >> 47)) * PRIME64_1) - len; + xxh_u64 const mix64h2 = (mix64h1 ^ (mix64h1 >> 43)) * PRIME64_4; + { XXH128_hash_t const h128 = { XXH3_avalanche(mix64l2) /*low64*/, XXH3_avalanche(mix64h2) /*high64*/ }; + return h128; + } } +} + +XXH_FORCE_INLINE XXH128_hash_t +XXH3_len_9to16_128b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) +{ + XXH_ASSERT(input != NULL); + XXH_ASSERT(secret != NULL); + XXH_ASSERT(9 <= len && len <= 16); + { xxh_u64 const input_lo = XXH_readLE64(input) ^ (XXH_readLE64(secret) + seed); + xxh_u64 const input_hi = XXH_readLE64(input + len - 8) ^ (XXH_readLE64(secret+8) - seed); + XXH128_hash_t m128 = XXH_mult64to128(input_lo ^ input_hi, PRIME64_1); + xxh_u64 const lenContrib = XXH_mult32to64(len, PRIME32_5); + m128.low64 += lenContrib; + m128.high64 += input_hi * PRIME64_1; + m128.low64 ^= (m128.high64 >> 32); + { XXH128_hash_t h128 = XXH_mult64to128(m128.low64, PRIME64_2); + h128.high64 += m128.high64 * PRIME64_2; + h128.low64 = XXH3_avalanche(h128.low64); + h128.high64 = XXH3_avalanche(h128.high64); + return h128; + } } +} + +/* Assumption : `secret` size is >= 16 + * Note : it should be >= XXH3_SECRET_SIZE_MIN anyway */ +XXH_FORCE_INLINE XXH128_hash_t +XXH3_len_0to16_128b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) +{ + XXH_ASSERT(len <= 16); + { if (len > 8) return XXH3_len_9to16_128b(input, len, secret, seed); + if (len >= 4) return XXH3_len_4to8_128b(input, len, secret, seed); + if (len) return XXH3_len_1to3_128b(input, len, secret, seed); + { XXH128_hash_t const h128 = { 0, 0 }; + return h128; + } } +} + +XXH_FORCE_INLINE XXH128_hash_t +XXH3_hashLong_128b_internal(const xxh_u8* XXH_RESTRICT input, size_t len, + const xxh_u8* XXH_RESTRICT secret, size_t secretSize) +{ + XXH_ALIGN(XXH_ACC_ALIGN) xxh_u64 acc[ACC_NB] = XXH3_INIT_ACC; + + XXH3_hashLong_internal_loop(acc, input, len, secret, secretSize, XXH3_acc_128bits); + + /* converge into final hash */ + XXH_STATIC_ASSERT(sizeof(acc) == 64); + XXH_ASSERT(secretSize >= sizeof(acc) + XXH_SECRET_MERGEACCS_START); + { xxh_u64 const low64 = XXH3_mergeAccs(acc, secret + XXH_SECRET_MERGEACCS_START, (xxh_u64)len * PRIME64_1); + xxh_u64 const high64 = XXH3_mergeAccs(acc, secret + secretSize - sizeof(acc) - XXH_SECRET_MERGEACCS_START, ~((xxh_u64)len * PRIME64_2)); + XXH128_hash_t const h128 = { low64, high64 }; + return h128; + } +} + +XXH_NO_INLINE XXH128_hash_t /* It's important for performance that XXH3_hashLong is not inlined. Not sure why (uop cache maybe ?), but difference is large and easily measurable */ +XXH3_hashLong_128b_defaultSecret(const xxh_u8* input, size_t len) +{ + return XXH3_hashLong_128b_internal(input, len, kSecret, sizeof(kSecret)); +} + +XXH_NO_INLINE XXH128_hash_t /* It's important for performance that XXH3_hashLong is not inlined. Not sure why (uop cache maybe ?), but difference is large and easily measurable */ +XXH3_hashLong_128b_withSecret(const xxh_u8* input, size_t len, + const xxh_u8* secret, size_t secretSize) +{ + return XXH3_hashLong_128b_internal(input, len, secret, secretSize); +} + +XXH_NO_INLINE XXH128_hash_t /* It's important for performance that XXH3_hashLong is not inlined. Not sure why (uop cache maybe ?), but difference is large and easily measurable */ +XXH3_hashLong_128b_withSeed(const xxh_u8* input, size_t len, XXH64_hash_t seed) +{ + XXH_ALIGN(8) xxh_u8 secret[XXH_SECRET_DEFAULT_SIZE]; + if (seed == 0) return XXH3_hashLong_128b_defaultSecret(input, len); + XXH3_initCustomSecret(secret, seed); + return XXH3_hashLong_128b_internal(input, len, secret, sizeof(secret)); +} + + +XXH_FORCE_INLINE XXH128_hash_t +XXH128_mix32B(XXH128_hash_t acc, const xxh_u8* input_1, const xxh_u8* input_2, const xxh_u8* secret, XXH64_hash_t seed) +{ + acc.low64 += XXH3_mix16B (input_1, secret+0, seed); + acc.low64 ^= XXH_readLE64(input_2) + XXH_readLE64(input_2 + 8); + acc.high64 += XXH3_mix16B (input_2, secret+16, seed); + acc.high64 ^= XXH_readLE64(input_1) + XXH_readLE64(input_1 + 8); + return acc; +} + +XXH_NO_INLINE XXH128_hash_t +XXH3_len_129to240_128b(const xxh_u8* XXH_RESTRICT input, size_t len, + const xxh_u8* XXH_RESTRICT secret, size_t secretSize, + XXH64_hash_t seed) +{ + XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); (void)secretSize; + XXH_ASSERT(128 < len && len <= XXH3_MIDSIZE_MAX); + + { XXH128_hash_t acc; + int const nbRounds = (int)len / 32; + int i; + acc.low64 = len * PRIME64_1; + acc.high64 = 0; + for (i=0; i<4; i++) { + acc = XXH128_mix32B(acc, input+(32*i), input+(32*i)+16, secret+(32*i), seed); + } + acc.low64 = XXH3_avalanche(acc.low64); + acc.high64 = XXH3_avalanche(acc.high64); + XXH_ASSERT(nbRounds >= 4); + for (i=4 ; i < nbRounds; i++) { + acc = XXH128_mix32B(acc, input+(32*i), input+(32*i)+16, secret+XXH3_MIDSIZE_STARTOFFSET+(32*(i-4)), seed); + } + /* last bytes */ + acc = XXH128_mix32B(acc, input + len - 16, input + len - 32, secret + XXH3_SECRET_SIZE_MIN - XXH3_MIDSIZE_LASTOFFSET - 16, 0ULL - seed); + + { xxh_u64 const low64 = acc.low64 + acc.high64; + xxh_u64 const high64 = (acc.low64 * PRIME64_1) + (acc.high64 * PRIME64_4) + ((len - seed) * PRIME64_2); + XXH128_hash_t const h128 = { XXH3_avalanche(low64), (XXH64_hash_t)0 - XXH3_avalanche(high64) }; + return h128; + } + } +} + + +XXH_FORCE_INLINE XXH128_hash_t +XXH3_len_17to128_128b(const xxh_u8* XXH_RESTRICT input, size_t len, + const xxh_u8* XXH_RESTRICT secret, size_t secretSize, + XXH64_hash_t seed) +{ + XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); (void)secretSize; + XXH_ASSERT(16 < len && len <= 128); + + { XXH128_hash_t acc; + acc.low64 = len * PRIME64_1; + acc.high64 = 0; + if (len > 32) { + if (len > 64) { + if (len > 96) { + acc = XXH128_mix32B(acc, input+48, input+len-64, secret+96, seed); + } + acc = XXH128_mix32B(acc, input+32, input+len-48, secret+64, seed); + } + acc = XXH128_mix32B(acc, input+16, input+len-32, secret+32, seed); + } + acc = XXH128_mix32B(acc, input, input+len-16, secret, seed); + { xxh_u64 const low64 = acc.low64 + acc.high64; + xxh_u64 const high64 = (acc.low64 * PRIME64_1) + (acc.high64 * PRIME64_4) + ((len - seed) * PRIME64_2); + XXH128_hash_t const h128 = { XXH3_avalanche(low64), (XXH64_hash_t)0 - XXH3_avalanche(high64) }; + return h128; + } + } +} + +XXH_PUBLIC_API XXH128_hash_t XXH3_128bits(const void* input, size_t len) +{ + if (len <= 16) return XXH3_len_0to16_128b((const xxh_u8*)input, len, kSecret, 0); + if (len <= 128) return XXH3_len_17to128_128b((const xxh_u8*)input, len, kSecret, sizeof(kSecret), 0); + if (len <= XXH3_MIDSIZE_MAX) return XXH3_len_129to240_128b((const xxh_u8*)input, len, kSecret, sizeof(kSecret), 0); + return XXH3_hashLong_128b_defaultSecret((const xxh_u8*)input, len); +} + +XXH_PUBLIC_API XXH128_hash_t +XXH3_128bits_withSecret(const void* input, size_t len, const void* secret, size_t secretSize) +{ + XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); + /* if an action must be taken should `secret` conditions not be respected, + * it should be done here. + * For now, it's a contract pre-condition. + * Adding a check and a branch here would cost performance at every hash */ + if (len <= 16) return XXH3_len_0to16_128b((const xxh_u8*)input, len, (const xxh_u8*)secret, 0); + if (len <= 128) return XXH3_len_17to128_128b((const xxh_u8*)input, len, (const xxh_u8*)secret, secretSize, 0); + if (len <= XXH3_MIDSIZE_MAX) return XXH3_len_129to240_128b((const xxh_u8*)input, len, (const xxh_u8*)secret, secretSize, 0); + return XXH3_hashLong_128b_withSecret((const xxh_u8*)input, len, (const xxh_u8*)secret, secretSize); +} + +XXH_PUBLIC_API XXH128_hash_t +XXH3_128bits_withSeed(const void* input, size_t len, XXH64_hash_t seed) +{ + if (len <= 16) return XXH3_len_0to16_128b((const xxh_u8*)input, len, kSecret, seed); + if (len <= 128) return XXH3_len_17to128_128b((const xxh_u8*)input, len, kSecret, sizeof(kSecret), seed); + if (len <= XXH3_MIDSIZE_MAX) return XXH3_len_129to240_128b((const xxh_u8*)input, len, kSecret, sizeof(kSecret), seed); + return XXH3_hashLong_128b_withSeed((const xxh_u8*)input, len, seed); +} + +XXH_PUBLIC_API XXH128_hash_t +XXH128(const void* input, size_t len, XXH64_hash_t seed) +{ + return XXH3_128bits_withSeed(input, len, seed); +} + + +/* === XXH3 128-bit streaming === */ + +/* all the functions are actually the same as for 64-bit streaming variant, + just the reset one is different (different initial acc values for 0,5,6,7), + and near the end of the digest function */ + +static void +XXH3_128bits_reset_internal(XXH3_state_t* statePtr, + XXH64_hash_t seed, + const xxh_u8* secret, size_t secretSize) +{ + XXH3_64bits_reset_internal(statePtr, seed, secret, secretSize); +} + +XXH_PUBLIC_API XXH_errorcode +XXH3_128bits_reset(XXH3_state_t* statePtr) +{ + if (statePtr == NULL) return XXH_ERROR; + XXH3_128bits_reset_internal(statePtr, 0, kSecret, XXH_SECRET_DEFAULT_SIZE); + return XXH_OK; +} + +XXH_PUBLIC_API XXH_errorcode +XXH3_128bits_reset_withSecret(XXH3_state_t* statePtr, const void* secret, size_t secretSize) +{ + if (statePtr == NULL) return XXH_ERROR; + XXH3_128bits_reset_internal(statePtr, 0, (const xxh_u8*)secret, secretSize); + if (secret == NULL) return XXH_ERROR; + if (secretSize < XXH3_SECRET_SIZE_MIN) return XXH_ERROR; + return XXH_OK; +} + +XXH_PUBLIC_API XXH_errorcode +XXH3_128bits_reset_withSeed(XXH3_state_t* statePtr, XXH64_hash_t seed) +{ + if (statePtr == NULL) return XXH_ERROR; + XXH3_128bits_reset_internal(statePtr, seed, kSecret, XXH_SECRET_DEFAULT_SIZE); + XXH3_initCustomSecret(statePtr->customSecret, seed); + statePtr->secret = statePtr->customSecret; + return XXH_OK; +} + +XXH_PUBLIC_API XXH_errorcode +XXH3_128bits_update(XXH3_state_t* state, const void* input, size_t len) +{ + return XXH3_update(state, (const xxh_u8*)input, len, XXH3_acc_128bits); +} + +XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_digest (const XXH3_state_t* state) +{ + if (state->totalLen > XXH3_MIDSIZE_MAX) { + XXH_ALIGN(XXH_ACC_ALIGN) XXH64_hash_t acc[ACC_NB]; + XXH3_digest_long(acc, state, XXH3_acc_128bits); + XXH_ASSERT(state->secretLimit + STRIPE_LEN >= sizeof(acc) + XXH_SECRET_MERGEACCS_START); + { xxh_u64 const low64 = XXH3_mergeAccs(acc, state->secret + XXH_SECRET_MERGEACCS_START, (xxh_u64)state->totalLen * PRIME64_1); + xxh_u64 const high64 = XXH3_mergeAccs(acc, state->secret + state->secretLimit + STRIPE_LEN - sizeof(acc) - XXH_SECRET_MERGEACCS_START, ~((xxh_u64)state->totalLen * PRIME64_2)); + XXH128_hash_t const h128 = { low64, high64 }; + return h128; + } + } + /* len <= XXH3_MIDSIZE_MAX : short code */ + if (state->seed) + return XXH3_128bits_withSeed(state->buffer, (size_t)state->totalLen, state->seed); + return XXH3_128bits_withSecret(state->buffer, (size_t)(state->totalLen), state->secret, state->secretLimit + STRIPE_LEN); +} + +/* 128-bit utility functions */ + +#include <string.h> /* memcmp */ + +/* return : 1 is equal, 0 if different */ +XXH_PUBLIC_API int XXH128_isEqual(XXH128_hash_t h1, XXH128_hash_t h2) +{ + /* note : XXH128_hash_t is compact, it has no padding byte */ + return !(memcmp(&h1, &h2, sizeof(h1))); +} + +/* This prototype is compatible with stdlib's qsort(). + * return : >0 if *h128_1 > *h128_2 + * <0 if *h128_1 < *h128_2 + * =0 if *h128_1 == *h128_2 */ +XXH_PUBLIC_API int XXH128_cmp(const void* h128_1, const void* h128_2) +{ + XXH128_hash_t const h1 = *(const XXH128_hash_t*)h128_1; + XXH128_hash_t const h2 = *(const XXH128_hash_t*)h128_2; + int const hcmp = (h1.high64 > h2.high64) - (h2.high64 > h1.high64); + /* note : bets that, in most cases, hash values are different */ + if (hcmp) return hcmp; + return (h1.low64 > h2.low64) - (h2.low64 > h1.low64); +} + + +/*====== Canonical representation ======*/ +XXH_PUBLIC_API void +XXH128_canonicalFromHash(XXH128_canonical_t* dst, XXH128_hash_t hash) +{ + XXH_STATIC_ASSERT(sizeof(XXH128_canonical_t) == sizeof(XXH128_hash_t)); + if (XXH_CPU_LITTLE_ENDIAN) { + hash.high64 = XXH_swap64(hash.high64); + hash.low64 = XXH_swap64(hash.low64); + } + memcpy(dst, &hash.high64, sizeof(hash.high64)); + memcpy((char*)dst + sizeof(hash.high64), &hash.low64, sizeof(hash.low64)); +} + +XXH_PUBLIC_API XXH128_hash_t +XXH128_hashFromCanonical(const XXH128_canonical_t* src) +{ + XXH128_hash_t h; + h.high64 = XXH_readBE64(src); + h.low64 = XXH_readBE64(src->digest + 8); + return h; +} + + + +#endif /* XXH3_H */ diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/libs/xxHash/xxhash.c b/Build/source/texk/dvisvgm/dvisvgm-src/libs/xxHash/xxhash.c index da06ea72bff..3f49b7d1d80 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/libs/xxHash/xxhash.c +++ b/Build/source/texk/dvisvgm/dvisvgm-src/libs/xxHash/xxhash.c @@ -33,6 +33,12 @@ */ +/* since xxhash.c can be included (via XXH_INLINE_ALL), + * it's good practice to protect it with guard + * in case of multiples inclusions */ +#ifndef XXHASH_C_01393879 +#define XXHASH_C_01393879 + /* ************************************* * Tuning parameters ***************************************/ @@ -50,14 +56,10 @@ * Prefer these methods in priority order (0 > 1 > 2) */ #ifndef XXH_FORCE_MEMORY_ACCESS /* can be defined externally, on command line for example */ -# if defined(__GNUC__) && ( defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) \ - || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) \ - || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) ) +# if !defined(__clang__) && defined(__GNUC__) && defined(__ARM_FEATURE_UNALIGNED) && defined(__ARM_ARCH) && (__ARM_ARCH == 6) # define XXH_FORCE_MEMORY_ACCESS 2 -# elif (defined(__INTEL_COMPILER) && !defined(_WIN32)) || \ - (defined(__GNUC__) && ( defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) \ - || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) \ - || defined(__ARM_ARCH_7S__) )) +# elif !defined(__clang__) && ((defined(__INTEL_COMPILER) && !defined(_WIN32)) || \ + (defined(__GNUC__) && (defined(__ARM_ARCH) && __ARM_ARCH >= 7))) # define XXH_FORCE_MEMORY_ACCESS 1 # endif #endif @@ -71,18 +73,6 @@ # define XXH_ACCEPT_NULL_INPUT_POINTER 0 #endif -/*!XXH_FORCE_NATIVE_FORMAT : - * By default, xxHash library provides endian-independent Hash values, based on little-endian convention. - * Results are therefore identical for little-endian and big-endian CPU. - * This comes at a performance cost for big-endian CPU, since some swapping is required to emulate little-endian format. - * Should endian-independence be of no importance for your application, you may set the #define below to 1, - * to improve speed for Big-endian CPU. - * This option has no impact on Little_Endian CPU. - */ -#ifndef XXH_FORCE_NATIVE_FORMAT /* can be defined externally */ -# define XXH_FORCE_NATIVE_FORMAT 0 -#endif - /*!XXH_FORCE_ALIGN_CHECK : * This is a minor performance trick, only useful with lots of very small keys. * It means : check for aligned/unaligned input. @@ -98,6 +88,18 @@ # endif #endif +/*!XXH_REROLL: + * Whether to reroll XXH32_finalize, and XXH64_finalize, + * instead of using an unrolled jump table/if statement loop. + * + * This is automatically defined on -Os/-Oz on GCC and Clang. */ +#ifndef XXH_REROLL +# if defined(__OPTIMIZE_SIZE__) +# define XXH_REROLL 1 +# else +# define XXH_REROLL 0 +# endif +#endif /* ************************************* * Includes & Memory related functions @@ -111,7 +113,7 @@ static void XXH_free (void* p) { free(p); } #include <string.h> static void* XXH_memcpy(void* dest, const void* src, size_t size) { return memcpy(dest,src,size); } -#include <assert.h> /* assert */ +#include <limits.h> /* ULLONG_MAX */ #define XXH_STATIC_LINKING_ONLY #include "xxhash.h" @@ -122,58 +124,82 @@ static void* XXH_memcpy(void* dest, const void* src, size_t size) { return memcp ***************************************/ #ifdef _MSC_VER /* Visual Studio */ # pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ -# define FORCE_INLINE static __forceinline +# define XXH_FORCE_INLINE static __forceinline +# define XXH_NO_INLINE static __declspec(noinline) #else # if defined (__cplusplus) || defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */ # ifdef __GNUC__ -# define FORCE_INLINE static inline __attribute__((always_inline)) +# define XXH_FORCE_INLINE static inline __attribute__((always_inline)) +# define XXH_NO_INLINE static __attribute__((noinline)) # else -# define FORCE_INLINE static inline +# define XXH_FORCE_INLINE static inline +# define XXH_NO_INLINE static # endif # else -# define FORCE_INLINE static +# define XXH_FORCE_INLINE static +# define XXH_NO_INLINE static # endif /* __STDC_VERSION__ */ #endif + +/* ************************************* +* Debug +***************************************/ +/* DEBUGLEVEL is expected to be defined externally, + * typically through compiler command line. + * Value must be a number. */ +#ifndef DEBUGLEVEL +# define DEBUGLEVEL 0 +#endif + +#if (DEBUGLEVEL>=1) +# include <assert.h> /* note : can still be disabled with NDEBUG */ +# define XXH_ASSERT(c) assert(c) +#else +# define XXH_ASSERT(c) ((void)0) +#endif + +/* note : use after variable declarations */ +#define XXH_STATIC_ASSERT(c) { enum { XXH_sa = 1/(int)(!!(c)) }; } + + /* ************************************* * Basic Types ***************************************/ -#ifndef MEM_MODULE -# if !defined (__VMS) \ - && (defined (__cplusplus) \ - || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) -# include <stdint.h> - typedef uint8_t BYTE; - typedef uint16_t U16; - typedef uint32_t U32; -# else - typedef unsigned char BYTE; - typedef unsigned short U16; - typedef unsigned int U32; -# endif +#if !defined (__VMS) \ + && (defined (__cplusplus) \ + || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) +# include <stdint.h> + typedef uint8_t xxh_u8; +#else + typedef unsigned char xxh_u8; #endif +typedef XXH32_hash_t xxh_u32; + + +/* === Memory access === */ #if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==2)) /* Force direct memory access. Only works on CPU which support unaligned memory access in hardware */ -static U32 XXH_read32(const void* memPtr) { return *(const U32*) memPtr; } +static xxh_u32 XXH_read32(const void* memPtr) { return *(const xxh_u32*) memPtr; } #elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==1)) /* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers */ /* currently only defined for gcc and icc */ -typedef union { U32 u32; } __attribute__((packed)) unalign; -static U32 XXH_read32(const void* ptr) { return ((const unalign*)ptr)->u32; } +typedef union { xxh_u32 u32; } __attribute__((packed)) unalign; +static xxh_u32 XXH_read32(const void* ptr) { return ((const unalign*)ptr)->u32; } #else /* portable and safe solution. Generally efficient. * see : http://stackoverflow.com/a/32095106/646947 */ -static U32 XXH_read32(const void* memPtr) +static xxh_u32 XXH_read32(const void* memPtr) { - U32 val; + xxh_u32 val; memcpy(&val, memPtr, sizeof(val)); return val; } @@ -181,18 +207,50 @@ static U32 XXH_read32(const void* memPtr) #endif /* XXH_FORCE_DIRECT_MEMORY_ACCESS */ +/* === Endianess === */ +typedef enum { XXH_bigEndian=0, XXH_littleEndian=1 } XXH_endianess; + +/* XXH_CPU_LITTLE_ENDIAN can be defined externally, for example on the compiler command line */ +#ifndef XXH_CPU_LITTLE_ENDIAN +# if defined(_WIN32) /* Windows is always little endian */ \ + || defined(__LITTLE_ENDIAN__) \ + || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) +# define XXH_CPU_LITTLE_ENDIAN 1 +# elif defined(__BIG_ENDIAN__) \ + || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) +# define XXH_CPU_LITTLE_ENDIAN 0 +# else +static int XXH_isLittleEndian(void) +{ + const union { xxh_u32 u; xxh_u8 c[4]; } one = { 1 }; /* don't use static : performance detrimental */ + return one.c[0]; +} +# define XXH_CPU_LITTLE_ENDIAN XXH_isLittleEndian() +# endif +#endif + + + + /* **************************************** * Compiler-specific Functions and Macros ******************************************/ #define XXH_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) +#ifndef __has_builtin +# define __has_builtin(x) 0 +#endif + +#if !defined(NO_CLANG_BUILTIN) && __has_builtin(__builtin_rotateleft32) && __has_builtin(__builtin_rotateleft64) +# define XXH_rotl32 __builtin_rotateleft32 +# define XXH_rotl64 __builtin_rotateleft64 /* Note : although _rotl exists for minGW (GCC under windows), performance seems poor */ -#if defined(_MSC_VER) +#elif defined(_MSC_VER) # define XXH_rotl32(x,r) _rotl(x,r) # define XXH_rotl64(x,r) _rotl64(x,r) #else -# define XXH_rotl32(x,r) ((x << r) | (x >> (32 - r))) -# define XXH_rotl64(x,r) ((x << r) | (x >> (64 - r))) +# define XXH_rotl32(x,r) (((x) << (r)) | ((x) >> (32 - (r)))) +# define XXH_rotl64(x,r) (((x) << (r)) | ((x) >> (64 - (r)))) #endif #if defined(_MSC_VER) /* Visual Studio */ @@ -200,7 +258,7 @@ static U32 XXH_read32(const void* memPtr) #elif XXH_GCC_VERSION >= 403 # define XXH_swap32 __builtin_bswap32 #else -static U32 XXH_swap32 (U32 x) +static xxh_u32 XXH_swap32 (xxh_u32 x) { return ((x << 24) & 0xff000000 ) | ((x << 8) & 0x00ff0000 ) | @@ -210,72 +268,101 @@ static U32 XXH_swap32 (U32 x) #endif -/* ************************************* -* Architecture Macros -***************************************/ -typedef enum { XXH_bigEndian=0, XXH_littleEndian=1 } XXH_endianess; - -/* XXH_CPU_LITTLE_ENDIAN can be defined externally, for example on the compiler command line */ -#ifndef XXH_CPU_LITTLE_ENDIAN -static int XXH_isLittleEndian(void) -{ - const union { U32 u; BYTE c[4]; } one = { 1 }; /* don't use static : performance detrimental */ - return one.c[0]; -} -# define XXH_CPU_LITTLE_ENDIAN XXH_isLittleEndian() -#endif - - /* *************************** * Memory reads *****************************/ typedef enum { XXH_aligned, XXH_unaligned } XXH_alignment; -FORCE_INLINE U32 XXH_readLE32_align(const void* ptr, XXH_endianess endian, XXH_alignment align) +XXH_FORCE_INLINE xxh_u32 XXH_readLE32(const void* ptr) { - if (align==XXH_unaligned) - return endian==XXH_littleEndian ? XXH_read32(ptr) : XXH_swap32(XXH_read32(ptr)); - else - return endian==XXH_littleEndian ? *(const U32*)ptr : XXH_swap32(*(const U32*)ptr); + return XXH_CPU_LITTLE_ENDIAN ? XXH_read32(ptr) : XXH_swap32(XXH_read32(ptr)); } -FORCE_INLINE U32 XXH_readLE32(const void* ptr, XXH_endianess endian) +static xxh_u32 XXH_readBE32(const void* ptr) { - return XXH_readLE32_align(ptr, endian, XXH_unaligned); + return XXH_CPU_LITTLE_ENDIAN ? XXH_swap32(XXH_read32(ptr)) : XXH_read32(ptr); } -static U32 XXH_readBE32(const void* ptr) +XXH_FORCE_INLINE xxh_u32 +XXH_readLE32_align(const void* ptr, XXH_alignment align) { - return XXH_CPU_LITTLE_ENDIAN ? XXH_swap32(XXH_read32(ptr)) : XXH_read32(ptr); + if (align==XXH_unaligned) { + return XXH_readLE32(ptr); + } else { + return XXH_CPU_LITTLE_ENDIAN ? *(const xxh_u32*)ptr : XXH_swap32(*(const xxh_u32*)ptr); + } } /* ************************************* -* Macros +* Misc ***************************************/ -#define XXH_STATIC_ASSERT(c) { enum { XXH_sa = 1/(int)(!!(c)) }; } /* use after variable declarations */ XXH_PUBLIC_API unsigned XXH_versionNumber (void) { return XXH_VERSION_NUMBER; } /* ******************************************************************* * 32-bit hash functions *********************************************************************/ -static const U32 PRIME32_1 = 2654435761U; -static const U32 PRIME32_2 = 2246822519U; -static const U32 PRIME32_3 = 3266489917U; -static const U32 PRIME32_4 = 668265263U; -static const U32 PRIME32_5 = 374761393U; +static const xxh_u32 PRIME32_1 = 0x9E3779B1U; /* 0b10011110001101110111100110110001 */ +static const xxh_u32 PRIME32_2 = 0x85EBCA77U; /* 0b10000101111010111100101001110111 */ +static const xxh_u32 PRIME32_3 = 0xC2B2AE3DU; /* 0b11000010101100101010111000111101 */ +static const xxh_u32 PRIME32_4 = 0x27D4EB2FU; /* 0b00100111110101001110101100101111 */ +static const xxh_u32 PRIME32_5 = 0x165667B1U; /* 0b00010110010101100110011110110001 */ -static U32 XXH32_round(U32 seed, U32 input) +static xxh_u32 XXH32_round(xxh_u32 acc, xxh_u32 input) { - seed += input * PRIME32_2; - seed = XXH_rotl32(seed, 13); - seed *= PRIME32_1; - return seed; + acc += input * PRIME32_2; + acc = XXH_rotl32(acc, 13); + acc *= PRIME32_1; +#if defined(__GNUC__) && defined(__SSE4_1__) && !defined(XXH_ENABLE_AUTOVECTORIZE) + /* UGLY HACK: + * This inline assembly hack forces acc into a normal register. This is the + * only thing that prevents GCC and Clang from autovectorizing the XXH32 loop + * (pragmas and attributes don't work for some resason) without globally + * disabling SSE4.1. + * + * The reason we want to avoid vectorization is because despite working on + * 4 integers at a time, there are multiple factors slowing XXH32 down on + * SSE4: + * - There's a ridiculous amount of lag from pmulld (10 cycles of latency on newer chips!) + * making it slightly slower to multiply four integers at once compared to four + * integers independently. Even when pmulld was fastest, Sandy/Ivy Bridge, it is + * still not worth it to go into SSE just to multiply unless doing a long operation. + * + * - Four instructions are required to rotate, + * movqda tmp, v // not required with VEX encoding + * pslld tmp, 13 // tmp <<= 13 + * psrld v, 19 // x >>= 19 + * por v, tmp // x |= tmp + * compared to one for scalar: + * roll v, 13 // reliably fast across the board + * shldl v, v, 13 // Sandy Bridge and later prefer this for some reason + * + * - Instruction level parallelism is actually more beneficial here because the + * SIMD actually serializes this operation: While v1 is rotating, v2 can load data, + * while v3 can multiply. SSE forces them to operate together. + * + * How this hack works: + * __asm__("" // Declare an assembly block but don't declare any instructions + * : // However, as an Input/Output Operand, + * "+r" // constrain a read/write operand (+) as a general purpose register (r). + * (acc) // and set acc as the operand + * ); + * + * Because of the 'r', the compiler has promised that seed will be in a + * general purpose register and the '+' says that it will be 'read/write', + * so it has to assume it has changed. It is like volatile without all the + * loads and stores. + * + * Since the argument has to be in a normal register (not an SSE register), + * each time XXH32_round is called, it is impossible to vectorize. */ + __asm__("" : "+r" (acc)); +#endif + return acc; } /* mix all bits */ -static U32 XXH32_avalanche(U32 h32) +static xxh_u32 XXH32_avalanche(xxh_u32 h32) { h32 ^= h32 >> 15; h32 *= PRIME32_2; @@ -285,97 +372,103 @@ static U32 XXH32_avalanche(U32 h32) return(h32); } -#define XXH_get32bits(p) XXH_readLE32_align(p, endian, align) - -static U32 -XXH32_finalize(U32 h32, const void* ptr, size_t len, - XXH_endianess endian, XXH_alignment align) +#define XXH_get32bits(p) XXH_readLE32_align(p, align) +static xxh_u32 +XXH32_finalize(xxh_u32 h32, const xxh_u8* ptr, size_t len, XXH_alignment align) { - const BYTE* p = (const BYTE*)ptr; -#define PROCESS1 \ - h32 += (*p) * PRIME32_5; \ - p++; \ +#define PROCESS1 \ + h32 += (*ptr++) * PRIME32_5; \ h32 = XXH_rotl32(h32, 11) * PRIME32_1 ; #define PROCESS4 \ - h32 += XXH_get32bits(p) * PRIME32_3; \ - p+=4; \ + h32 += XXH_get32bits(ptr) * PRIME32_3; \ + ptr+=4; \ h32 = XXH_rotl32(h32, 17) * PRIME32_4 ; - switch(len&15) /* or switch(bEnd - p) */ - { - case 12: PROCESS4; - /* fallthrough */ - case 8: PROCESS4; - /* fallthrough */ - case 4: PROCESS4; - return XXH32_avalanche(h32); - - case 13: PROCESS4; - /* fallthrough */ - case 9: PROCESS4; - /* fallthrough */ - case 5: PROCESS4; - PROCESS1; - return XXH32_avalanche(h32); - - case 14: PROCESS4; - /* fallthrough */ - case 10: PROCESS4; - /* fallthrough */ - case 6: PROCESS4; - PROCESS1; - PROCESS1; - return XXH32_avalanche(h32); - - case 15: PROCESS4; - /* fallthrough */ - case 11: PROCESS4; - /* fallthrough */ - case 7: PROCESS4; - /* fallthrough */ - case 3: PROCESS1; - /* fallthrough */ - case 2: PROCESS1; - /* fallthrough */ - case 1: PROCESS1; - /* fallthrough */ - case 0: return XXH32_avalanche(h32); + /* Compact rerolled version */ + if (XXH_REROLL) { + len &= 15; + while (len >= 4) { + PROCESS4; + len -= 4; + } + while (len > 0) { + PROCESS1; + --len; + } + return XXH32_avalanche(h32); + } else { + switch(len&15) /* or switch(bEnd - p) */ { + case 12: PROCESS4; + /* fallthrough */ + case 8: PROCESS4; + /* fallthrough */ + case 4: PROCESS4; + return XXH32_avalanche(h32); + + case 13: PROCESS4; + /* fallthrough */ + case 9: PROCESS4; + /* fallthrough */ + case 5: PROCESS4; + PROCESS1; + return XXH32_avalanche(h32); + + case 14: PROCESS4; + /* fallthrough */ + case 10: PROCESS4; + /* fallthrough */ + case 6: PROCESS4; + PROCESS1; + PROCESS1; + return XXH32_avalanche(h32); + + case 15: PROCESS4; + /* fallthrough */ + case 11: PROCESS4; + /* fallthrough */ + case 7: PROCESS4; + /* fallthrough */ + case 3: PROCESS1; + /* fallthrough */ + case 2: PROCESS1; + /* fallthrough */ + case 1: PROCESS1; + /* fallthrough */ + case 0: return XXH32_avalanche(h32); + } + XXH_ASSERT(0); + return h32; /* reaching this point is deemed impossible */ } - assert(0); - return h32; /* reaching this point is deemed impossible */ } - -FORCE_INLINE U32 -XXH32_endian_align(const void* input, size_t len, U32 seed, - XXH_endianess endian, XXH_alignment align) +XXH_FORCE_INLINE xxh_u32 +XXH32_endian_align(const xxh_u8* input, size_t len, xxh_u32 seed, XXH_alignment align) { - const BYTE* p = (const BYTE*)input; - const BYTE* bEnd = p + len; - U32 h32; + const xxh_u8* bEnd = input + len; + xxh_u32 h32; #if defined(XXH_ACCEPT_NULL_INPUT_POINTER) && (XXH_ACCEPT_NULL_INPUT_POINTER>=1) - if (p==NULL) { + if (input==NULL) { len=0; - bEnd=p=(const BYTE*)(size_t)16; + bEnd=input=(const xxh_u8*)(size_t)16; } #endif if (len>=16) { - const BYTE* const limit = bEnd - 15; - U32 v1 = seed + PRIME32_1 + PRIME32_2; - U32 v2 = seed + PRIME32_2; - U32 v3 = seed + 0; - U32 v4 = seed - PRIME32_1; + const xxh_u8* const limit = bEnd - 15; + xxh_u32 v1 = seed + PRIME32_1 + PRIME32_2; + xxh_u32 v2 = seed + PRIME32_2; + xxh_u32 v3 = seed + 0; + xxh_u32 v4 = seed - PRIME32_1; do { - v1 = XXH32_round(v1, XXH_get32bits(p)); p+=4; - v2 = XXH32_round(v2, XXH_get32bits(p)); p+=4; - v3 = XXH32_round(v3, XXH_get32bits(p)); p+=4; - v4 = XXH32_round(v4, XXH_get32bits(p)); p+=4; - } while (p < limit); + v1 = XXH32_round(v1, XXH_get32bits(input)); input += 4; + v2 = XXH32_round(v2, XXH_get32bits(input)); input += 4; + v3 = XXH32_round(v3, XXH_get32bits(input)); input += 4; + v4 = XXH32_round(v4, XXH_get32bits(input)); input += 4; + } while (input < limit); h32 = XXH_rotl32(v1, 1) + XXH_rotl32(v2, 7) + XXH_rotl32(v3, 12) + XXH_rotl32(v4, 18); @@ -383,35 +476,29 @@ XXH32_endian_align(const void* input, size_t len, U32 seed, h32 = seed + PRIME32_5; } - h32 += (U32)len; + h32 += (xxh_u32)len; - return XXH32_finalize(h32, p, len&15, endian, align); + return XXH32_finalize(h32, input, len&15, align); } -XXH_PUBLIC_API unsigned int XXH32 (const void* input, size_t len, unsigned int seed) +XXH_PUBLIC_API XXH32_hash_t XXH32 (const void* input, size_t len, XXH32_hash_t seed) { #if 0 /* Simple version, good for code maintenance, but unfortunately slow for small inputs */ XXH32_state_t state; XXH32_reset(&state, seed); - XXH32_update(&state, input, len); + XXH32_update(&state, (const xxh_u8*)input, len); return XXH32_digest(&state); + #else - XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN; if (XXH_FORCE_ALIGN_CHECK) { if ((((size_t)input) & 3) == 0) { /* Input is 4-bytes aligned, leverage the speed benefit */ - if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT) - return XXH32_endian_align(input, len, seed, XXH_littleEndian, XXH_aligned); - else - return XXH32_endian_align(input, len, seed, XXH_bigEndian, XXH_aligned); + return XXH32_endian_align((const xxh_u8*)input, len, seed, XXH_aligned); } } - if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT) - return XXH32_endian_align(input, len, seed, XXH_littleEndian, XXH_unaligned); - else - return XXH32_endian_align(input, len, seed, XXH_bigEndian, XXH_unaligned); + return XXH32_endian_align((const xxh_u8*)input, len, seed, XXH_unaligned); #endif } @@ -434,7 +521,7 @@ XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* dstState, const XXH32_state_t memcpy(dstState, srcState, sizeof(*dstState)); } -XXH_PUBLIC_API XXH_errorcode XXH32_reset(XXH32_state_t* statePtr, unsigned int seed) +XXH_PUBLIC_API XXH_errorcode XXH32_reset(XXH32_state_t* statePtr, XXH32_hash_t seed) { XXH32_state_t state; /* using a local state to memcpy() in order to avoid strict-aliasing warnings */ memset(&state, 0, sizeof(state)); @@ -448,12 +535,9 @@ XXH_PUBLIC_API XXH_errorcode XXH32_reset(XXH32_state_t* statePtr, unsigned int s } -FORCE_INLINE -XXH_errorcode XXH32_update_endian (XXH32_state_t* state, const void* input, size_t len, XXH_endianess endian) +XXH_PUBLIC_API XXH_errorcode +XXH32_update(XXH32_state_t* state, const void* input, size_t len) { - const BYTE* p = (const BYTE*)input; - const BYTE* const bEnd = p + len; - if (input==NULL) #if defined(XXH_ACCEPT_NULL_INPUT_POINTER) && (XXH_ACCEPT_NULL_INPUT_POINTER>=1) return XXH_OK; @@ -461,71 +545,63 @@ XXH_errorcode XXH32_update_endian (XXH32_state_t* state, const void* input, size return XXH_ERROR; #endif - state->total_len_32 += (unsigned)len; - state->large_len |= (len>=16) | (state->total_len_32>=16); + { const xxh_u8* p = (const xxh_u8*)input; + const xxh_u8* const bEnd = p + len; - if (state->memsize + len < 16) { /* fill in tmp buffer */ - XXH_memcpy((BYTE*)(state->mem32) + state->memsize, input, len); - state->memsize += (unsigned)len; - return XXH_OK; - } + state->total_len_32 += (XXH32_hash_t)len; + state->large_len |= (XXH32_hash_t)((len>=16) | (state->total_len_32>=16)); - if (state->memsize) { /* some data left from previous update */ - XXH_memcpy((BYTE*)(state->mem32) + state->memsize, input, 16-state->memsize); - { const U32* p32 = state->mem32; - state->v1 = XXH32_round(state->v1, XXH_readLE32(p32, endian)); p32++; - state->v2 = XXH32_round(state->v2, XXH_readLE32(p32, endian)); p32++; - state->v3 = XXH32_round(state->v3, XXH_readLE32(p32, endian)); p32++; - state->v4 = XXH32_round(state->v4, XXH_readLE32(p32, endian)); + if (state->memsize + len < 16) { /* fill in tmp buffer */ + XXH_memcpy((xxh_u8*)(state->mem32) + state->memsize, input, len); + state->memsize += (XXH32_hash_t)len; + return XXH_OK; } - p += 16-state->memsize; - state->memsize = 0; - } - if (p <= bEnd-16) { - const BYTE* const limit = bEnd - 16; - U32 v1 = state->v1; - U32 v2 = state->v2; - U32 v3 = state->v3; - U32 v4 = state->v4; + if (state->memsize) { /* some data left from previous update */ + XXH_memcpy((xxh_u8*)(state->mem32) + state->memsize, input, 16-state->memsize); + { const xxh_u32* p32 = state->mem32; + state->v1 = XXH32_round(state->v1, XXH_readLE32(p32)); p32++; + state->v2 = XXH32_round(state->v2, XXH_readLE32(p32)); p32++; + state->v3 = XXH32_round(state->v3, XXH_readLE32(p32)); p32++; + state->v4 = XXH32_round(state->v4, XXH_readLE32(p32)); + } + p += 16-state->memsize; + state->memsize = 0; + } - do { - v1 = XXH32_round(v1, XXH_readLE32(p, endian)); p+=4; - v2 = XXH32_round(v2, XXH_readLE32(p, endian)); p+=4; - v3 = XXH32_round(v3, XXH_readLE32(p, endian)); p+=4; - v4 = XXH32_round(v4, XXH_readLE32(p, endian)); p+=4; - } while (p<=limit); - - state->v1 = v1; - state->v2 = v2; - state->v3 = v3; - state->v4 = v4; - } + if (p <= bEnd-16) { + const xxh_u8* const limit = bEnd - 16; + xxh_u32 v1 = state->v1; + xxh_u32 v2 = state->v2; + xxh_u32 v3 = state->v3; + xxh_u32 v4 = state->v4; + + do { + v1 = XXH32_round(v1, XXH_readLE32(p)); p+=4; + v2 = XXH32_round(v2, XXH_readLE32(p)); p+=4; + v3 = XXH32_round(v3, XXH_readLE32(p)); p+=4; + v4 = XXH32_round(v4, XXH_readLE32(p)); p+=4; + } while (p<=limit); + + state->v1 = v1; + state->v2 = v2; + state->v3 = v3; + state->v4 = v4; + } - if (p < bEnd) { - XXH_memcpy(state->mem32, p, (size_t)(bEnd-p)); - state->memsize = (unsigned)(bEnd-p); + if (p < bEnd) { + XXH_memcpy(state->mem32, p, (size_t)(bEnd-p)); + state->memsize = (unsigned)(bEnd-p); + } } return XXH_OK; } -XXH_PUBLIC_API XXH_errorcode XXH32_update (XXH32_state_t* state_in, const void* input, size_t len) +XXH_PUBLIC_API XXH32_hash_t XXH32_digest (const XXH32_state_t* state) { - XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN; - - if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT) - return XXH32_update_endian(state_in, input, len, XXH_littleEndian); - else - return XXH32_update_endian(state_in, input, len, XXH_bigEndian); -} - - -FORCE_INLINE U32 -XXH32_digest_endian (const XXH32_state_t* state, XXH_endianess endian) -{ - U32 h32; + xxh_u32 h32; if (state->large_len) { h32 = XXH_rotl32(state->v1, 1) @@ -538,18 +614,7 @@ XXH32_digest_endian (const XXH32_state_t* state, XXH_endianess endian) h32 += state->total_len_32; - return XXH32_finalize(h32, state->mem32, state->memsize, endian, XXH_aligned); -} - - -XXH_PUBLIC_API unsigned int XXH32_digest (const XXH32_state_t* state_in) -{ - XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN; - - if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT) - return XXH32_digest_endian(state_in, XXH_littleEndian); - else - return XXH32_digest_endian(state_in, XXH_bigEndian); + return XXH32_finalize(h32, (const xxh_u8*)state->mem32, state->memsize, XXH_aligned); } @@ -582,31 +647,46 @@ XXH_PUBLIC_API XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src /*====== Memory access ======*/ -#ifndef MEM_MODULE -# define MEM_MODULE -# if !defined (__VMS) \ - && (defined (__cplusplus) \ - || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) -# include <stdint.h> - typedef uint64_t U64; -# else - /* if compiler doesn't support unsigned long long, replace by another 64-bit type */ - typedef unsigned long long U64; -# endif -#endif - +typedef XXH64_hash_t xxh_u64; + + +/*! XXH_REROLL_XXH64: + * Whether to reroll the XXH64_finalize() loop. + * + * Just like XXH32, we can unroll the XXH64_finalize() loop. This can be a performance gain + * on 64-bit hosts, as only one jump is required. + * + * However, on 32-bit hosts, because arithmetic needs to be done with two 32-bit registers, + * and 64-bit arithmetic needs to be simulated, it isn't beneficial to unroll. The code becomes + * ridiculously large (the largest function in the binary on i386!), and rerolling it saves + * anywhere from 3kB to 20kB. It is also slightly faster because it fits into cache better + * and is more likely to be inlined by the compiler. + * + * If XXH_REROLL is defined, this is ignored and the loop is always rerolled. */ +#ifndef XXH_REROLL_XXH64 +# if (defined(__ILP32__) || defined(_ILP32)) /* ILP32 is often defined on 32-bit GCC family */ \ + || !(defined(__x86_64__) || defined(_M_X64) || defined(_M_AMD64) /* x86-64 */ \ + || defined(_M_ARM64) || defined(__aarch64__) || defined(__arm64__) /* aarch64 */ \ + || defined(__PPC64__) || defined(__PPC64LE__) || defined(__ppc64__) || defined(__powerpc64__) /* ppc64 */ \ + || defined(__mips64__) || defined(__mips64)) /* mips64 */ \ + || (!defined(SIZE_MAX) || SIZE_MAX < ULLONG_MAX) /* check limits */ +# define XXH_REROLL_XXH64 1 +# else +# define XXH_REROLL_XXH64 0 +# endif +#endif /* !defined(XXH_REROLL_XXH64) */ #if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==2)) /* Force direct memory access. Only works on CPU which support unaligned memory access in hardware */ -static U64 XXH_read64(const void* memPtr) { return *(const U64*) memPtr; } +static xxh_u64 XXH_read64(const void* memPtr) { return *(const xxh_u64*) memPtr; } #elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==1)) /* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers */ /* currently only defined for gcc and icc */ -typedef union { U32 u32; U64 u64; } __attribute__((packed)) unalign64; -static U64 XXH_read64(const void* ptr) { return ((const unalign64*)ptr)->u64; } +typedef union { xxh_u32 u32; xxh_u64 u64; } __attribute__((packed)) unalign64; +static xxh_u64 XXH_read64(const void* ptr) { return ((const unalign64*)ptr)->u64; } #else @@ -614,9 +694,9 @@ static U64 XXH_read64(const void* ptr) { return ((const unalign64*)ptr)->u64; } * see : http://stackoverflow.com/a/32095106/646947 */ -static U64 XXH_read64(const void* memPtr) +static xxh_u64 XXH_read64(const void* memPtr) { - U64 val; + xxh_u64 val; memcpy(&val, memPtr, sizeof(val)); return val; } @@ -628,7 +708,7 @@ static U64 XXH_read64(const void* memPtr) #elif XXH_GCC_VERSION >= 403 # define XXH_swap64 __builtin_bswap64 #else -static U64 XXH_swap64 (U64 x) +static xxh_u64 XXH_swap64 (xxh_u64 x) { return ((x << 56) & 0xff00000000000000ULL) | ((x << 40) & 0x00ff000000000000ULL) | @@ -641,34 +721,35 @@ static U64 XXH_swap64 (U64 x) } #endif -FORCE_INLINE U64 XXH_readLE64_align(const void* ptr, XXH_endianess endian, XXH_alignment align) +XXH_FORCE_INLINE xxh_u64 XXH_readLE64(const void* ptr) { - if (align==XXH_unaligned) - return endian==XXH_littleEndian ? XXH_read64(ptr) : XXH_swap64(XXH_read64(ptr)); - else - return endian==XXH_littleEndian ? *(const U64*)ptr : XXH_swap64(*(const U64*)ptr); + return XXH_CPU_LITTLE_ENDIAN ? XXH_read64(ptr) : XXH_swap64(XXH_read64(ptr)); } -FORCE_INLINE U64 XXH_readLE64(const void* ptr, XXH_endianess endian) +static xxh_u64 XXH_readBE64(const void* ptr) { - return XXH_readLE64_align(ptr, endian, XXH_unaligned); + return XXH_CPU_LITTLE_ENDIAN ? XXH_swap64(XXH_read64(ptr)) : XXH_read64(ptr); } -static U64 XXH_readBE64(const void* ptr) +XXH_FORCE_INLINE xxh_u64 +XXH_readLE64_align(const void* ptr, XXH_alignment align) { - return XXH_CPU_LITTLE_ENDIAN ? XXH_swap64(XXH_read64(ptr)) : XXH_read64(ptr); + if (align==XXH_unaligned) + return XXH_readLE64(ptr); + else + return XXH_CPU_LITTLE_ENDIAN ? *(const xxh_u64*)ptr : XXH_swap64(*(const xxh_u64*)ptr); } /*====== xxh64 ======*/ -static const U64 PRIME64_1 = 11400714785074694791ULL; -static const U64 PRIME64_2 = 14029467366897019727ULL; -static const U64 PRIME64_3 = 1609587929392839161ULL; -static const U64 PRIME64_4 = 9650029242287828579ULL; -static const U64 PRIME64_5 = 2870177450012600261ULL; +static const xxh_u64 PRIME64_1 = 0x9E3779B185EBCA87ULL; /* 0b1001111000110111011110011011000110000101111010111100101010000111 */ +static const xxh_u64 PRIME64_2 = 0xC2B2AE3D27D4EB4FULL; /* 0b1100001010110010101011100011110100100111110101001110101101001111 */ +static const xxh_u64 PRIME64_3 = 0x165667B19E3779F9ULL; /* 0b0001011001010110011001111011000110011110001101110111100111111001 */ +static const xxh_u64 PRIME64_4 = 0x85EBCA77C2B2AE63ULL; /* 0b1000010111101011110010100111011111000010101100101010111001100011 */ +static const xxh_u64 PRIME64_5 = 0x27D4EB2F165667C5ULL; /* 0b0010011111010100111010110010111100010110010101100110011111000101 */ -static U64 XXH64_round(U64 acc, U64 input) +static xxh_u64 XXH64_round(xxh_u64 acc, xxh_u64 input) { acc += input * PRIME64_2; acc = XXH_rotl64(acc, 31); @@ -676,7 +757,7 @@ static U64 XXH64_round(U64 acc, U64 input) return acc; } -static U64 XXH64_mergeRound(U64 acc, U64 val) +static xxh_u64 XXH64_mergeRound(xxh_u64 acc, xxh_u64 val) { val = XXH64_round(0, val); acc ^= val; @@ -684,7 +765,7 @@ static U64 XXH64_mergeRound(U64 acc, U64 val) return acc; } -static U64 XXH64_avalanche(U64 h64) +static xxh_u64 XXH64_avalanche(xxh_u64 h64) { h64 ^= h64 >> 33; h64 *= PRIME64_2; @@ -695,146 +776,157 @@ static U64 XXH64_avalanche(U64 h64) } -#define XXH_get64bits(p) XXH_readLE64_align(p, endian, align) +#define XXH_get64bits(p) XXH_readLE64_align(p, align) -static U64 -XXH64_finalize(U64 h64, const void* ptr, size_t len, - XXH_endianess endian, XXH_alignment align) +static xxh_u64 +XXH64_finalize(xxh_u64 h64, const xxh_u8* ptr, size_t len, XXH_alignment align) { - const BYTE* p = (const BYTE*)ptr; - -#define PROCESS1_64 \ - h64 ^= (*p) * PRIME64_5; \ - p++; \ +#define PROCESS1_64 \ + h64 ^= (*ptr++) * PRIME64_5; \ h64 = XXH_rotl64(h64, 11) * PRIME64_1; #define PROCESS4_64 \ - h64 ^= (U64)(XXH_get32bits(p)) * PRIME64_1; \ - p+=4; \ + h64 ^= (xxh_u64)(XXH_get32bits(ptr)) * PRIME64_1; \ + ptr+=4; \ h64 = XXH_rotl64(h64, 23) * PRIME64_2 + PRIME64_3; #define PROCESS8_64 { \ - U64 const k1 = XXH64_round(0, XXH_get64bits(p)); \ - p+=8; \ + xxh_u64 const k1 = XXH64_round(0, XXH_get64bits(ptr)); \ + ptr+=8; \ h64 ^= k1; \ h64 = XXH_rotl64(h64,27) * PRIME64_1 + PRIME64_4; \ } - switch(len&31) { - case 24: PROCESS8_64; - /* fallthrough */ - case 16: PROCESS8_64; - /* fallthrough */ - case 8: PROCESS8_64; - return XXH64_avalanche(h64); - - case 28: PROCESS8_64; - /* fallthrough */ - case 20: PROCESS8_64; - /* fallthrough */ - case 12: PROCESS8_64; - /* fallthrough */ - case 4: PROCESS4_64; - return XXH64_avalanche(h64); - - case 25: PROCESS8_64; - /* fallthrough */ - case 17: PROCESS8_64; - /* fallthrough */ - case 9: PROCESS8_64; - PROCESS1_64; - return XXH64_avalanche(h64); - - case 29: PROCESS8_64; - /* fallthrough */ - case 21: PROCESS8_64; - /* fallthrough */ - case 13: PROCESS8_64; - /* fallthrough */ - case 5: PROCESS4_64; - PROCESS1_64; - return XXH64_avalanche(h64); - - case 26: PROCESS8_64; - /* fallthrough */ - case 18: PROCESS8_64; - /* fallthrough */ - case 10: PROCESS8_64; - PROCESS1_64; - PROCESS1_64; - return XXH64_avalanche(h64); - - case 30: PROCESS8_64; - /* fallthrough */ - case 22: PROCESS8_64; - /* fallthrough */ - case 14: PROCESS8_64; - /* fallthrough */ - case 6: PROCESS4_64; - PROCESS1_64; - PROCESS1_64; - return XXH64_avalanche(h64); - - case 27: PROCESS8_64; - /* fallthrough */ - case 19: PROCESS8_64; - /* fallthrough */ - case 11: PROCESS8_64; - PROCESS1_64; - PROCESS1_64; - PROCESS1_64; - return XXH64_avalanche(h64); - - case 31: PROCESS8_64; - /* fallthrough */ - case 23: PROCESS8_64; - /* fallthrough */ - case 15: PROCESS8_64; - /* fallthrough */ - case 7: PROCESS4_64; - /* fallthrough */ - case 3: PROCESS1_64; - /* fallthrough */ - case 2: PROCESS1_64; - /* fallthrough */ - case 1: PROCESS1_64; - /* fallthrough */ - case 0: return XXH64_avalanche(h64); + /* Rerolled version for 32-bit targets is faster and much smaller. */ + if (XXH_REROLL || XXH_REROLL_XXH64) { + len &= 31; + while (len >= 8) { + PROCESS8_64; + len -= 8; + } + if (len >= 4) { + PROCESS4_64; + len -= 4; + } + while (len > 0) { + PROCESS1_64; + --len; + } + return XXH64_avalanche(h64); + } else { + switch(len & 31) { + case 24: PROCESS8_64; + /* fallthrough */ + case 16: PROCESS8_64; + /* fallthrough */ + case 8: PROCESS8_64; + return XXH64_avalanche(h64); + + case 28: PROCESS8_64; + /* fallthrough */ + case 20: PROCESS8_64; + /* fallthrough */ + case 12: PROCESS8_64; + /* fallthrough */ + case 4: PROCESS4_64; + return XXH64_avalanche(h64); + + case 25: PROCESS8_64; + /* fallthrough */ + case 17: PROCESS8_64; + /* fallthrough */ + case 9: PROCESS8_64; + PROCESS1_64; + return XXH64_avalanche(h64); + + case 29: PROCESS8_64; + /* fallthrough */ + case 21: PROCESS8_64; + /* fallthrough */ + case 13: PROCESS8_64; + /* fallthrough */ + case 5: PROCESS4_64; + PROCESS1_64; + return XXH64_avalanche(h64); + + case 26: PROCESS8_64; + /* fallthrough */ + case 18: PROCESS8_64; + /* fallthrough */ + case 10: PROCESS8_64; + PROCESS1_64; + PROCESS1_64; + return XXH64_avalanche(h64); + + case 30: PROCESS8_64; + /* fallthrough */ + case 22: PROCESS8_64; + /* fallthrough */ + case 14: PROCESS8_64; + /* fallthrough */ + case 6: PROCESS4_64; + PROCESS1_64; + PROCESS1_64; + return XXH64_avalanche(h64); + + case 27: PROCESS8_64; + /* fallthrough */ + case 19: PROCESS8_64; + /* fallthrough */ + case 11: PROCESS8_64; + PROCESS1_64; + PROCESS1_64; + PROCESS1_64; + return XXH64_avalanche(h64); + + case 31: PROCESS8_64; + /* fallthrough */ + case 23: PROCESS8_64; + /* fallthrough */ + case 15: PROCESS8_64; + /* fallthrough */ + case 7: PROCESS4_64; + /* fallthrough */ + case 3: PROCESS1_64; + /* fallthrough */ + case 2: PROCESS1_64; + /* fallthrough */ + case 1: PROCESS1_64; + /* fallthrough */ + case 0: return XXH64_avalanche(h64); + } } - /* impossible to reach */ - assert(0); + XXH_ASSERT(0); return 0; /* unreachable, but some compilers complain without it */ } -FORCE_INLINE U64 -XXH64_endian_align(const void* input, size_t len, U64 seed, - XXH_endianess endian, XXH_alignment align) +XXH_FORCE_INLINE xxh_u64 +XXH64_endian_align(const xxh_u8* input, size_t len, xxh_u64 seed, XXH_alignment align) { - const BYTE* p = (const BYTE*)input; - const BYTE* bEnd = p + len; - U64 h64; + const xxh_u8* bEnd = input + len; + xxh_u64 h64; #if defined(XXH_ACCEPT_NULL_INPUT_POINTER) && (XXH_ACCEPT_NULL_INPUT_POINTER>=1) - if (p==NULL) { + if (input==NULL) { len=0; - bEnd=p=(const BYTE*)(size_t)32; + bEnd=input=(const xxh_u8*)(size_t)32; } #endif if (len>=32) { - const BYTE* const limit = bEnd - 32; - U64 v1 = seed + PRIME64_1 + PRIME64_2; - U64 v2 = seed + PRIME64_2; - U64 v3 = seed + 0; - U64 v4 = seed - PRIME64_1; + const xxh_u8* const limit = bEnd - 32; + xxh_u64 v1 = seed + PRIME64_1 + PRIME64_2; + xxh_u64 v2 = seed + PRIME64_2; + xxh_u64 v3 = seed + 0; + xxh_u64 v4 = seed - PRIME64_1; do { - v1 = XXH64_round(v1, XXH_get64bits(p)); p+=8; - v2 = XXH64_round(v2, XXH_get64bits(p)); p+=8; - v3 = XXH64_round(v3, XXH_get64bits(p)); p+=8; - v4 = XXH64_round(v4, XXH_get64bits(p)); p+=8; - } while (p<=limit); + v1 = XXH64_round(v1, XXH_get64bits(input)); input+=8; + v2 = XXH64_round(v2, XXH_get64bits(input)); input+=8; + v3 = XXH64_round(v3, XXH_get64bits(input)); input+=8; + v4 = XXH64_round(v4, XXH_get64bits(input)); input+=8; + } while (input<=limit); h64 = XXH_rotl64(v1, 1) + XXH_rotl64(v2, 7) + XXH_rotl64(v3, 12) + XXH_rotl64(v4, 18); h64 = XXH64_mergeRound(h64, v1); @@ -846,35 +938,30 @@ XXH64_endian_align(const void* input, size_t len, U64 seed, h64 = seed + PRIME64_5; } - h64 += (U64) len; + h64 += (xxh_u64) len; - return XXH64_finalize(h64, p, len, endian, align); + return XXH64_finalize(h64, input, len, align); } -XXH_PUBLIC_API unsigned long long XXH64 (const void* input, size_t len, unsigned long long seed) +XXH_PUBLIC_API XXH64_hash_t XXH64 (const void* input, size_t len, XXH64_hash_t seed) { #if 0 /* Simple version, good for code maintenance, but unfortunately slow for small inputs */ XXH64_state_t state; XXH64_reset(&state, seed); - XXH64_update(&state, input, len); + XXH64_update(&state, (const xxh_u8*)input, len); return XXH64_digest(&state); + #else - XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN; if (XXH_FORCE_ALIGN_CHECK) { if ((((size_t)input) & 7)==0) { /* Input is aligned, let's leverage the speed advantage */ - if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT) - return XXH64_endian_align(input, len, seed, XXH_littleEndian, XXH_aligned); - else - return XXH64_endian_align(input, len, seed, XXH_bigEndian, XXH_aligned); + return XXH64_endian_align((const xxh_u8*)input, len, seed, XXH_aligned); } } - if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT) - return XXH64_endian_align(input, len, seed, XXH_littleEndian, XXH_unaligned); - else - return XXH64_endian_align(input, len, seed, XXH_bigEndian, XXH_unaligned); + return XXH64_endian_align((const xxh_u8*)input, len, seed, XXH_unaligned); + #endif } @@ -895,7 +982,7 @@ XXH_PUBLIC_API void XXH64_copyState(XXH64_state_t* dstState, const XXH64_state_t memcpy(dstState, srcState, sizeof(*dstState)); } -XXH_PUBLIC_API XXH_errorcode XXH64_reset(XXH64_state_t* statePtr, unsigned long long seed) +XXH_PUBLIC_API XXH_errorcode XXH64_reset(XXH64_state_t* statePtr, XXH64_hash_t seed) { XXH64_state_t state; /* using a local state to memcpy() in order to avoid strict-aliasing warnings */ memset(&state, 0, sizeof(state)); @@ -903,17 +990,14 @@ XXH_PUBLIC_API XXH_errorcode XXH64_reset(XXH64_state_t* statePtr, unsigned long state.v2 = seed + PRIME64_2; state.v3 = seed + 0; state.v4 = seed - PRIME64_1; - /* do not write into reserved, planned to be removed in a future version */ - memcpy(statePtr, &state, sizeof(state) - sizeof(state.reserved)); + /* do not write into reserved64, might be removed in a future version */ + memcpy(statePtr, &state, sizeof(state) - sizeof(state.reserved64)); return XXH_OK; } -FORCE_INLINE -XXH_errorcode XXH64_update_endian (XXH64_state_t* state, const void* input, size_t len, XXH_endianess endian) +XXH_PUBLIC_API XXH_errorcode +XXH64_update (XXH64_state_t* state, const void* input, size_t len) { - const BYTE* p = (const BYTE*)input; - const BYTE* const bEnd = p + len; - if (input==NULL) #if defined(XXH_ACCEPT_NULL_INPUT_POINTER) && (XXH_ACCEPT_NULL_INPUT_POINTER>=1) return XXH_OK; @@ -921,71 +1005,66 @@ XXH_errorcode XXH64_update_endian (XXH64_state_t* state, const void* input, size return XXH_ERROR; #endif - state->total_len += len; + { const xxh_u8* p = (const xxh_u8*)input; + const xxh_u8* const bEnd = p + len; - if (state->memsize + len < 32) { /* fill in tmp buffer */ - XXH_memcpy(((BYTE*)state->mem64) + state->memsize, input, len); - state->memsize += (U32)len; - return XXH_OK; - } + state->total_len += len; - if (state->memsize) { /* tmp buffer is full */ - XXH_memcpy(((BYTE*)state->mem64) + state->memsize, input, 32-state->memsize); - state->v1 = XXH64_round(state->v1, XXH_readLE64(state->mem64+0, endian)); - state->v2 = XXH64_round(state->v2, XXH_readLE64(state->mem64+1, endian)); - state->v3 = XXH64_round(state->v3, XXH_readLE64(state->mem64+2, endian)); - state->v4 = XXH64_round(state->v4, XXH_readLE64(state->mem64+3, endian)); - p += 32-state->memsize; - state->memsize = 0; - } + if (state->memsize + len < 32) { /* fill in tmp buffer */ + XXH_memcpy(((xxh_u8*)state->mem64) + state->memsize, input, len); + state->memsize += (xxh_u32)len; + return XXH_OK; + } - if (p+32 <= bEnd) { - const BYTE* const limit = bEnd - 32; - U64 v1 = state->v1; - U64 v2 = state->v2; - U64 v3 = state->v3; - U64 v4 = state->v4; + if (state->memsize) { /* tmp buffer is full */ + XXH_memcpy(((xxh_u8*)state->mem64) + state->memsize, input, 32-state->memsize); + state->v1 = XXH64_round(state->v1, XXH_readLE64(state->mem64+0)); + state->v2 = XXH64_round(state->v2, XXH_readLE64(state->mem64+1)); + state->v3 = XXH64_round(state->v3, XXH_readLE64(state->mem64+2)); + state->v4 = XXH64_round(state->v4, XXH_readLE64(state->mem64+3)); + p += 32-state->memsize; + state->memsize = 0; + } - do { - v1 = XXH64_round(v1, XXH_readLE64(p, endian)); p+=8; - v2 = XXH64_round(v2, XXH_readLE64(p, endian)); p+=8; - v3 = XXH64_round(v3, XXH_readLE64(p, endian)); p+=8; - v4 = XXH64_round(v4, XXH_readLE64(p, endian)); p+=8; - } while (p<=limit); - - state->v1 = v1; - state->v2 = v2; - state->v3 = v3; - state->v4 = v4; - } + if (p+32 <= bEnd) { + const xxh_u8* const limit = bEnd - 32; + xxh_u64 v1 = state->v1; + xxh_u64 v2 = state->v2; + xxh_u64 v3 = state->v3; + xxh_u64 v4 = state->v4; + + do { + v1 = XXH64_round(v1, XXH_readLE64(p)); p+=8; + v2 = XXH64_round(v2, XXH_readLE64(p)); p+=8; + v3 = XXH64_round(v3, XXH_readLE64(p)); p+=8; + v4 = XXH64_round(v4, XXH_readLE64(p)); p+=8; + } while (p<=limit); + + state->v1 = v1; + state->v2 = v2; + state->v3 = v3; + state->v4 = v4; + } - if (p < bEnd) { - XXH_memcpy(state->mem64, p, (size_t)(bEnd-p)); - state->memsize = (unsigned)(bEnd-p); + if (p < bEnd) { + XXH_memcpy(state->mem64, p, (size_t)(bEnd-p)); + state->memsize = (unsigned)(bEnd-p); + } } return XXH_OK; } -XXH_PUBLIC_API XXH_errorcode XXH64_update (XXH64_state_t* state_in, const void* input, size_t len) -{ - XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN; - - if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT) - return XXH64_update_endian(state_in, input, len, XXH_littleEndian); - else - return XXH64_update_endian(state_in, input, len, XXH_bigEndian); -} -FORCE_INLINE U64 XXH64_digest_endian (const XXH64_state_t* state, XXH_endianess endian) +XXH_PUBLIC_API XXH64_hash_t XXH64_digest (const XXH64_state_t* state) { - U64 h64; + xxh_u64 h64; if (state->total_len >= 32) { - U64 const v1 = state->v1; - U64 const v2 = state->v2; - U64 const v3 = state->v3; - U64 const v4 = state->v4; + xxh_u64 const v1 = state->v1; + xxh_u64 const v2 = state->v2; + xxh_u64 const v3 = state->v3; + xxh_u64 const v4 = state->v4; h64 = XXH_rotl64(v1, 1) + XXH_rotl64(v2, 7) + XXH_rotl64(v3, 12) + XXH_rotl64(v4, 18); h64 = XXH64_mergeRound(h64, v1); @@ -996,19 +1075,9 @@ FORCE_INLINE U64 XXH64_digest_endian (const XXH64_state_t* state, XXH_endianess h64 = state->v3 /*seed*/ + PRIME64_5; } - h64 += (U64) state->total_len; - - return XXH64_finalize(h64, state->mem64, (size_t)state->total_len, endian, XXH_aligned); -} - -XXH_PUBLIC_API unsigned long long XXH64_digest (const XXH64_state_t* state_in) -{ - XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN; + h64 += (xxh_u64) state->total_len; - if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT) - return XXH64_digest_endian(state_in, XXH_littleEndian); - else - return XXH64_digest_endian(state_in, XXH_bigEndian); + return XXH64_finalize(h64, (const xxh_u8*)state->mem64, (size_t)state->total_len, XXH_aligned); } @@ -1026,4 +1095,16 @@ XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src return XXH_readBE64(src); } + + +/* ********************************************************************* +* XXH3 +* New generation hash designed for speed on small keys and vectorization +************************************************************************ */ + +#include "xxh3.h" + + #endif /* XXH_NO_LONG_LONG */ + +#endif /* XXHASH_C_01393879 */ diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/libs/xxHash/xxhash.h b/Build/source/texk/dvisvgm/dvisvgm-src/libs/xxHash/xxhash.h index d6bad943358..df1d08765dc 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/libs/xxHash/xxhash.h +++ b/Build/source/texk/dvisvgm/dvisvgm-src/libs/xxHash/xxhash.h @@ -49,10 +49,13 @@ Lookup3 1.2 GB/s 9 Bob Jenkins SuperFastHash 1.2 GB/s 1 Paul Hsieh CityHash64 1.05 GB/s 10 Pike & Alakuijala FNV 0.55 GB/s 5 Fowler, Noll, Vo -CRC32 0.43 GB/s 9 +CRC32 0.43 GB/s †9 MD5-32 0.33 GB/s 10 Ronald L. Rivest SHA1-32 0.28 GB/s 10 +Note †: other CRC32 implementations can be over 40x faster than SMHasher's: +http://fastcompression.blogspot.com/2019/03/presenting-xxh3.html?showComment=1552696407071#c3490092340461170735 + Q.Score is a measure of quality of the hash function. It depends on successfully passing SMHasher test set. 10 is a perfect score. @@ -77,20 +80,23 @@ extern "C" { ******************************/ #include <stddef.h> /* size_t */ typedef enum { XXH_OK=0, XXH_ERROR } XXH_errorcode; +#define XXH_STATIC_LINKING_ONLY /* **************************** * API modifier ******************************/ /** XXH_INLINE_ALL (and XXH_PRIVATE_API) - * This is useful to include xxhash functions in `static` mode + * This build macro includes xxhash functions in `static` mode * in order to inline them, and remove their symbol from the public list. - * Inlining can offer dramatic performance improvement on small keys. + * Inlining offers great performance improvement on small keys, + * and dramatic ones when length is expressed as a compile-time constant. + * See https://fastcompression.blogspot.com/2018/03/xxhash-for-small-keys-impressive-power.html . * Methodology : * #define XXH_INLINE_ALL * #include "xxhash.h" * `xxhash.c` is automatically included. - * It's not useful to compile and link it as a separate module. + * It's not useful to compile and link it as a separate object. */ #if defined(XXH_INLINE_ALL) || defined(XXH_PRIVATE_API) # ifndef XXH_STATIC_LINKING_ONLY @@ -107,7 +113,15 @@ typedef enum { XXH_OK=0, XXH_ERROR } XXH_errorcode; # define XXH_PUBLIC_API static # endif #else -# define XXH_PUBLIC_API /* do nothing */ +# if defined(WIN32) && defined(_MSC_VER) && (defined(XXH_IMPORT) || defined(XXH_EXPORT)) +# ifdef XXH_EXPORT +# define XXH_PUBLIC_API __declspec(dllexport) +# elif XXH_IMPORT +# define XXH_PUBLIC_API __declspec(dllimport) +# endif +# else +# define XXH_PUBLIC_API /* do nothing */ +# endif #endif /* XXH_INLINE_ALL || XXH_PRIVATE_API */ /*! XXH_NAMESPACE, aka Namespace Emulation : @@ -150,8 +164,8 @@ typedef enum { XXH_OK=0, XXH_ERROR } XXH_errorcode; * Version ***************************************/ #define XXH_VERSION_MAJOR 0 -#define XXH_VERSION_MINOR 6 -#define XXH_VERSION_RELEASE 5 +#define XXH_VERSION_MINOR 7 +#define XXH_VERSION_RELEASE 2 #define XXH_VERSION_NUMBER (XXH_VERSION_MAJOR *100*100 + XXH_VERSION_MINOR *100 + XXH_VERSION_RELEASE) XXH_PUBLIC_API unsigned XXH_versionNumber (void); @@ -159,28 +173,36 @@ XXH_PUBLIC_API unsigned XXH_versionNumber (void); /*-********************************************************************** * 32-bit hash ************************************************************************/ -typedef unsigned int XXH32_hash_t; +#if !defined (__VMS) \ + && (defined (__cplusplus) \ + || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) +# include <stdint.h> + typedef uint32_t XXH32_hash_t; +#else +# include <limits.h> +# if UINT_MAX == 0xFFFFFFFFUL + typedef unsigned int XXH32_hash_t; +# else +# if ULONG_MAX == 0xFFFFFFFFUL + typedef unsigned long XXH32_hash_t; +# else +# error "unsupported platform : need a 32-bit type" +# endif +# endif +#endif /*! XXH32() : Calculate the 32-bit hash of sequence "length" bytes stored at memory address "input". The memory between input & input+length must be valid (allocated and read-accessible). "seed" can be used to alter the result predictably. Speed on Core 2 Duo @ 3 GHz (single thread, SMHasher benchmark) : 5.4 GB/s */ -XXH_PUBLIC_API XXH32_hash_t XXH32 (const void* input, size_t length, unsigned int seed); +XXH_PUBLIC_API XXH32_hash_t XXH32 (const void* input, size_t length, XXH32_hash_t seed); /*====== Streaming ======*/ -typedef struct XXH32_state_s XXH32_state_t; /* incomplete type */ -XXH_PUBLIC_API XXH32_state_t* XXH32_createState(void); -XXH_PUBLIC_API XXH_errorcode XXH32_freeState(XXH32_state_t* statePtr); -XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* dst_state, const XXH32_state_t* src_state); - -XXH_PUBLIC_API XXH_errorcode XXH32_reset (XXH32_state_t* statePtr, unsigned int seed); -XXH_PUBLIC_API XXH_errorcode XXH32_update (XXH32_state_t* statePtr, const void* input, size_t length); -XXH_PUBLIC_API XXH32_hash_t XXH32_digest (const XXH32_state_t* statePtr); /* - * Streaming functions generate the xxHash of an input provided in multiple segments. - * Note that, for small input, they are slower than single-call functions, due to state management. + * Streaming functions generate the xxHash value from an incrememtal input. + * This method is slower than single-call functions, due to state management. * For small inputs, prefer `XXH32()` and `XXH64()`, which are better optimized. * * XXH state must first be allocated, using XXH*_createState() . @@ -194,36 +216,62 @@ XXH_PUBLIC_API XXH32_hash_t XXH32_digest (const XXH32_state_t* statePtr); * This function returns the nn-bits hash as an int or long long. * * It's still possible to continue inserting input into the hash state after a digest, - * and generate some new hashes later on, by calling again XXH*_digest(). + * and generate some new hash values later on, by invoking again XXH*_digest(). * - * When done, free XXH state space if it was allocated dynamically. + * When done, release the state, using XXH*_freeState(). */ +typedef struct XXH32_state_s XXH32_state_t; /* incomplete type */ +XXH_PUBLIC_API XXH32_state_t* XXH32_createState(void); +XXH_PUBLIC_API XXH_errorcode XXH32_freeState(XXH32_state_t* statePtr); +XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* dst_state, const XXH32_state_t* src_state); + +XXH_PUBLIC_API XXH_errorcode XXH32_reset (XXH32_state_t* statePtr, XXH32_hash_t seed); +XXH_PUBLIC_API XXH_errorcode XXH32_update (XXH32_state_t* statePtr, const void* input, size_t length); +XXH_PUBLIC_API XXH32_hash_t XXH32_digest (const XXH32_state_t* statePtr); + /*====== Canonical representation ======*/ +/* Default return values from XXH functions are basic unsigned 32 and 64 bits. + * This the simplest and fastest format for further post-processing. + * However, this leaves open the question of what is the order of bytes, + * since little and big endian conventions will write the same number differently. + * + * The canonical representation settles this issue, + * by mandating big-endian convention, + * aka, the same convention as human-readable numbers (large digits first). + * When writing hash values to storage, sending them over a network, or printing them, + * it's highly recommended to use the canonical representation, + * to ensure portability across a wider range of systems, present and future. + * + * The following functions allow transformation of hash values into and from canonical format. + */ + typedef struct { unsigned char digest[4]; } XXH32_canonical_t; XXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t hash); XXH_PUBLIC_API XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src); -/* Default result type for XXH functions are primitive unsigned 32 and 64 bits. - * The canonical representation uses human-readable write convention, aka big-endian (large digits first). - * These functions allow transformation of hash result into and from its canonical format. - * This way, hash values can be written into a file / memory, and remain comparable on different systems and programs. - */ - #ifndef XXH_NO_LONG_LONG /*-********************************************************************** * 64-bit hash ************************************************************************/ -typedef unsigned long long XXH64_hash_t; +#if !defined (__VMS) \ + && (defined (__cplusplus) \ + || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) +# include <stdint.h> + typedef uint64_t XXH64_hash_t; +#else + /* the following type must have a width of 64-bit */ + typedef unsigned long long XXH64_hash_t; +#endif /*! XXH64() : Calculate the 64-bit hash of sequence of length "len" stored at memory address "input". "seed" can be used to alter the result predictably. This function runs faster on 64-bit systems, but slower on 32-bit systems (see benchmark). */ -XXH_PUBLIC_API XXH64_hash_t XXH64 (const void* input, size_t length, unsigned long long seed); +XXH_PUBLIC_API XXH64_hash_t XXH64 (const void* input, size_t length, XXH64_hash_t seed); /*====== Streaming ======*/ typedef struct XXH64_state_s XXH64_state_t; /* incomplete type */ @@ -231,7 +279,7 @@ XXH_PUBLIC_API XXH64_state_t* XXH64_createState(void); XXH_PUBLIC_API XXH_errorcode XXH64_freeState(XXH64_state_t* statePtr); XXH_PUBLIC_API void XXH64_copyState(XXH64_state_t* dst_state, const XXH64_state_t* src_state); -XXH_PUBLIC_API XXH_errorcode XXH64_reset (XXH64_state_t* statePtr, unsigned long long seed); +XXH_PUBLIC_API XXH_errorcode XXH64_reset (XXH64_state_t* statePtr, XXH64_hash_t seed); XXH_PUBLIC_API XXH_errorcode XXH64_update (XXH64_state_t* statePtr, const void* input, size_t length); XXH_PUBLIC_API XXH64_hash_t XXH64_digest (const XXH64_state_t* statePtr); @@ -239,6 +287,8 @@ XXH_PUBLIC_API XXH64_hash_t XXH64_digest (const XXH64_state_t* statePtr); typedef struct { unsigned char digest[8]; } XXH64_canonical_t; XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH64_canonical_t* dst, XXH64_hash_t hash); XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src); + + #endif /* XXH_NO_LONG_LONG */ @@ -256,68 +306,278 @@ XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src * static allocation of XXH state, on stack or in a struct for example. * Never **ever** use members directly. */ -#if !defined (__VMS) \ - && (defined (__cplusplus) \ - || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) -# include <stdint.h> - struct XXH32_state_s { - uint32_t total_len_32; - uint32_t large_len; - uint32_t v1; - uint32_t v2; - uint32_t v3; - uint32_t v4; - uint32_t mem32[4]; - uint32_t memsize; - uint32_t reserved; /* never read nor write, might be removed in a future version */ + XXH32_hash_t total_len_32; + XXH32_hash_t large_len; + XXH32_hash_t v1; + XXH32_hash_t v2; + XXH32_hash_t v3; + XXH32_hash_t v4; + XXH32_hash_t mem32[4]; + XXH32_hash_t memsize; + XXH32_hash_t reserved; /* never read nor write, might be removed in a future version */ }; /* typedef'd to XXH32_state_t */ +#ifndef XXH_NO_LONG_LONG /* remove 64-bit support */ struct XXH64_state_s { - uint64_t total_len; - uint64_t v1; - uint64_t v2; - uint64_t v3; - uint64_t v4; - uint64_t mem64[4]; - uint32_t memsize; - uint32_t reserved[2]; /* never read nor write, might be removed in a future version */ + XXH64_hash_t total_len; + XXH64_hash_t v1; + XXH64_hash_t v2; + XXH64_hash_t v3; + XXH64_hash_t v4; + XXH64_hash_t mem64[4]; + XXH32_hash_t memsize; + XXH32_hash_t reserved32; /* required for padding anyway */ + XXH64_hash_t reserved64; /* never read nor write, might be removed in a future version */ }; /* typedef'd to XXH64_state_t */ +#endif /* XXH_NO_LONG_LONG */ -# else -struct XXH32_state_s { - unsigned total_len_32; - unsigned large_len; - unsigned v1; - unsigned v2; - unsigned v3; - unsigned v4; - unsigned mem32[4]; - unsigned memsize; - unsigned reserved; /* never read nor write, might be removed in a future version */ -}; /* typedef'd to XXH32_state_t */ +/*-********************************************************************** +* XXH3 +* New experimental hash +************************************************************************/ +#ifndef XXH_NO_LONG_LONG + + +/* ============================================ + * XXH3 is a new hash algorithm, + * featuring improved speed performance for both small and large inputs. + * See full speed analysis at : http://fastcompression.blogspot.com/2019/03/presenting-xxh3.html + * In general, expect XXH3 to run about ~2x faster on large inputs, + * and >3x faster on small ones, though exact differences depend on platform. + * + * The algorithm is portable, will generate the same hash on all platforms. + * It benefits greatly from vectorization units, but does not require it. + * + * XXH3 offers 2 variants, _64bits and _128bits. + * When only 64 bits are needed, prefer calling the _64bits variant : + * it reduces the amount of mixing, resulting in faster speed on small inputs. + * It's also generally simpler to manipulate a scalar return type than a struct. + * + * The XXH3 algorithm is still considered experimental. + * Produced results can still change between versions. + * Results produced by v0.7.x are not comparable with results from v0.7.y . + * It's nonetheless possible to use XXH3 for ephemeral data (local sessions), + * but avoid storing values in long-term storage for later reads. + * + * The API supports one-shot hashing, streaming mode, and custom secrets. + * + * There are still a number of opened questions that community can influence during the experimental period. + * I'm trying to list a few of them below, though don't consider this list as complete. + * + * - 128-bits output type : currently defined as a structure of two 64-bits fields. + * That's because 128-bit values do not exist in C standard. + * Note that it means that, at byte level, result is not identical depending on endianess. + * However, at field level, they are identical on all platforms. + * The canonical representation solves the issue of identical byte-level representation across platforms, + * which is necessary for serialization. + * Q1 : Would there be a better representation for a 128-bit hash result ? + * Q2 : Are the names of the inner 64-bit fields important ? Should they be changed ? + * + * - Prototype XXH128() : XXH128() uses the same arguments as XXH64(), for consistency. + * It means it maps to XXH3_128bits_withSeed(). + * This variant is slightly slower than XXH3_128bits(), + * because the seed is now part of the algorithm, and can't be simplified. + * Is that a good idea ? + * + * - Seed type for XXH128() : currently, it's a single 64-bit value, like the 64-bit variant. + * It could be argued that it's more logical to offer a 128-bit seed input parameter for a 128-bit hash. + * But 128-bit seed is more difficult to use, since it requires to pass a structure instead of a scalar value. + * Such a variant could either replace current one, or become an additional one. + * Farmhash, for example, offers both variants (the 128-bits seed variant is called `doubleSeed`). + * Follow up question : if both 64-bit and 128-bit seeds are allowed, which variant should be called XXH128 ? + * + * - Result for len==0 : Currently, the result of hashing a zero-length input is always `0`. + * It seems okay as a return value when using "default" secret and seed. + * But is it still fine to return `0` when secret or seed are non-default ? + * Are there use cases which could depend on generating a different hash result for zero-length input when the secret is different ? + * + * - Consistency (1) : Streaming XXH128 uses an XXH3 state, which is the same state as XXH3_64bits(). + * It means a 128bit streaming loop must invoke the following symbols : + * XXH3_createState(), XXH3_128bits_reset(), XXH3_128bits_update() (loop), XXH3_128bits_digest(), XXH3_freeState(). + * Is that consistent enough ? + * + * - Consistency (2) : The canonical representation of `XXH3_64bits` is provided by existing functions + * XXH64_canonicalFromHash(), and reverse operation XXH64_hashFromCanonical(). + * As a mirror, canonical functions for XXH128_hash_t results generated by `XXH3_128bits` + * are XXH128_canonicalFromHash() and XXH128_hashFromCanonical(). + * Which means, `XXH3` doesn't appear in the names, because canonical functions operate on a type, + * independently of which algorithm was used to generate that type. + * Is that consistent enough ? + */ + +#ifdef XXH_NAMESPACE +# define XXH3_64bits XXH_NAME2(XXH_NAMESPACE, XXH3_64bits) +# define XXH3_64bits_withSecret XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_withSecret) +# define XXH3_64bits_withSeed XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_withSeed) + +# define XXH3_createState XXH_NAME2(XXH_NAMESPACE, XXH3_createState) +# define XXH3_freeState XXH_NAME2(XXH_NAMESPACE, XXH3_freeState) +# define XXH3_copyState XXH_NAME2(XXH_NAMESPACE, XXH3_copyState) + +# define XXH3_64bits_reset XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_reset) +# define XXH3_64bits_reset_withSeed XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_reset_withSeed) +# define XXH3_64bits_reset_withSecret XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_reset_withSecret) +# define XXH3_64bits_update XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_update) +# define XXH3_64bits_digest XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_digest) +#endif + +/* XXH3_64bits() : + * default 64-bit variant, using default secret and default seed of 0. + * It's the fastest variant. */ +XXH_PUBLIC_API XXH64_hash_t XXH3_64bits(const void* data, size_t len); + +/* XXH3_64bits_withSecret() : + * It's possible to provide any blob of bytes as a "secret" to generate the hash. + * This makes it more difficult for an external actor to prepare an intentional collision. + * The secret *must* be large enough (>= XXH3_SECRET_SIZE_MIN). + * It should consist of random bytes. + * Avoid repeating same character, or sequences of bytes, + * and especially avoid swathes of \0. + * Failure to respect these conditions will result in a poor quality hash. + */ +#define XXH3_SECRET_SIZE_MIN 136 +XXH_PUBLIC_API XXH64_hash_t XXH3_64bits_withSecret(const void* data, size_t len, const void* secret, size_t secretSize); + +/* XXH3_64bits_withSeed() : + * This variant generates on the fly a custom secret, + * based on the default secret, altered using the `seed` value. + * While this operation is decently fast, note that it's not completely free. + * note : seed==0 produces same results as XXH3_64bits() */ +XXH_PUBLIC_API XXH64_hash_t XXH3_64bits_withSeed(const void* data, size_t len, XXH64_hash_t seed); + + +/* streaming 64-bit */ + +#if defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) /* C11+ */ +# include <stdalign.h> +# define XXH_ALIGN(n) alignas(n) +#elif defined(__GNUC__) +# define XXH_ALIGN(n) __attribute__ ((aligned(n))) +#elif defined(_MSC_VER) +# define XXH_ALIGN(n) __declspec(align(n)) +#else +# define XXH_ALIGN(n) /* disabled */ +#endif + +typedef struct XXH3_state_s XXH3_state_t; + +#define XXH3_SECRET_DEFAULT_SIZE 192 /* minimum XXH3_SECRET_SIZE_MIN */ +#define XXH3_INTERNALBUFFER_SIZE 256 +struct XXH3_state_s { + XXH_ALIGN(64) XXH64_hash_t acc[8]; + XXH_ALIGN(64) unsigned char customSecret[XXH3_SECRET_DEFAULT_SIZE]; /* used to store a custom secret generated from the seed. Makes state larger. Design might change */ + XXH_ALIGN(64) unsigned char buffer[XXH3_INTERNALBUFFER_SIZE]; + XXH32_hash_t bufferedSize; + XXH32_hash_t nbStripesPerBlock; + XXH32_hash_t nbStripesSoFar; + XXH32_hash_t secretLimit; + XXH32_hash_t reserved32; + XXH32_hash_t reserved32_2; + XXH64_hash_t totalLen; + XXH64_hash_t seed; + XXH64_hash_t reserved64; + const unsigned char* secret; /* note : there is some padding after, due to alignment on 64 bytes */ +}; /* typedef'd to XXH3_state_t */ + +/* Streaming requires state maintenance. + * This operation costs memory and cpu. + * As a consequence, streaming is slower than one-shot hashing. + * For better performance, prefer using one-shot functions whenever possible. */ + +XXH_PUBLIC_API XXH3_state_t* XXH3_createState(void); +XXH_PUBLIC_API XXH_errorcode XXH3_freeState(XXH3_state_t* statePtr); +XXH_PUBLIC_API void XXH3_copyState(XXH3_state_t* dst_state, const XXH3_state_t* src_state); + + +/* XXH3_64bits_reset() : + * initialize with default parameters. + * result will be equivalent to `XXH3_64bits()`. */ +XXH_PUBLIC_API XXH_errorcode XXH3_64bits_reset(XXH3_state_t* statePtr); +/* XXH3_64bits_reset_withSeed() : + * generate a custom secret from `seed`, and store it into state. + * digest will be equivalent to `XXH3_64bits_withSeed()`. */ +XXH_PUBLIC_API XXH_errorcode XXH3_64bits_reset_withSeed(XXH3_state_t* statePtr, XXH64_hash_t seed); +/* XXH3_64bits_reset_withSecret() : + * `secret` is referenced, and must outlive the hash streaming session. + * secretSize must be >= XXH3_SECRET_SIZE_MIN. + */ +XXH_PUBLIC_API XXH_errorcode XXH3_64bits_reset_withSecret(XXH3_state_t* statePtr, const void* secret, size_t secretSize); + +XXH_PUBLIC_API XXH_errorcode XXH3_64bits_update (XXH3_state_t* statePtr, const void* input, size_t length); +XXH_PUBLIC_API XXH64_hash_t XXH3_64bits_digest (const XXH3_state_t* statePtr); + + +/* 128-bit */ + +#ifdef XXH_NAMESPACE +# define XXH128 XXH_NAME2(XXH_NAMESPACE, XXH128) +# define XXH3_128bits XXH_NAME2(XXH_NAMESPACE, XXH3_128bits) +# define XXH3_128bits_withSeed XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_withSeed) +# define XXH3_128bits_withSecret XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_withSecret) + +# define XXH3_128bits_reset XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_reset) +# define XXH3_128bits_reset_withSeed XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_reset_withSeed) +# define XXH3_128bits_reset_withSecret XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_reset_withSecret) +# define XXH3_128bits_update XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_update) +# define XXH3_128bits_digest XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_digest) + +# define XXH128_isEqual XXH_NAME2(XXH_NAMESPACE, XXH128_isEqual) +# define XXH128_cmp XXH_NAME2(XXH_NAMESPACE, XXH128_cmp) +# define XXH128_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH128_canonicalFromHash) +# define XXH128_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH128_hashFromCanonical) +#endif + +typedef struct { + XXH64_hash_t low64; + XXH64_hash_t high64; +} XXH128_hash_t; + +XXH_PUBLIC_API XXH128_hash_t XXH128(const void* data, size_t len, XXH64_hash_t seed); +XXH_PUBLIC_API XXH128_hash_t XXH3_128bits(const void* data, size_t len); +XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_withSeed(const void* data, size_t len, XXH64_hash_t seed); /* == XXH128() */ +XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_withSecret(const void* data, size_t len, const void* secret, size_t secretSize); + +XXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset(XXH3_state_t* statePtr); +XXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset_withSeed(XXH3_state_t* statePtr, XXH64_hash_t seed); +XXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset_withSecret(XXH3_state_t* statePtr, const void* secret, size_t secretSize); + +XXH_PUBLIC_API XXH_errorcode XXH3_128bits_update (XXH3_state_t* statePtr, const void* input, size_t length); +XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_digest (const XXH3_state_t* statePtr); -# ifndef XXH_NO_LONG_LONG /* remove 64-bit support */ -struct XXH64_state_s { - unsigned long long total_len; - unsigned long long v1; - unsigned long long v2; - unsigned long long v3; - unsigned long long v4; - unsigned long long mem64[4]; - unsigned memsize; - unsigned reserved[2]; /* never read nor write, might be removed in a future version */ -}; /* typedef'd to XXH64_state_t */ -# endif -# endif +/* Note : for better performance, following functions can be inlined, + * using XXH_INLINE_ALL */ +/* return : 1 is equal, 0 if different */ +XXH_PUBLIC_API int XXH128_isEqual(XXH128_hash_t h1, XXH128_hash_t h2); +/* This comparator is compatible with stdlib's qsort(). + * return : >0 if *h128_1 > *h128_2 + * <0 if *h128_1 < *h128_2 + * =0 if *h128_1 == *h128_2 */ +XXH_PUBLIC_API int XXH128_cmp(const void* h128_1, const void* h128_2); + + +/*====== Canonical representation ======*/ +typedef struct { unsigned char digest[16]; } XXH128_canonical_t; +XXH_PUBLIC_API void XXH128_canonicalFromHash(XXH128_canonical_t* dst, XXH128_hash_t hash); +XXH_PUBLIC_API XXH128_hash_t XXH128_hashFromCanonical(const XXH128_canonical_t* src); + + +#endif /* XXH_NO_LONG_LONG */ + + +/*-********************************************************************** +* XXH_INLINE_ALL +************************************************************************/ #if defined(XXH_INLINE_ALL) || defined(XXH_PRIVATE_API) # include "xxhash.c" /* include xxhash function bodies as `static`, for inlining */ #endif + + #endif /* XXH_STATIC_LINKING_ONLY */ diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/BasicDVIReader.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/BasicDVIReader.cpp index 350e130166a..272c88c3ad1 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/BasicDVIReader.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/BasicDVIReader.cpp @@ -19,7 +19,6 @@ *************************************************************************/ #include <algorithm> -#include <sstream> #include "BasicDVIReader.hpp" using namespace std; @@ -100,11 +99,8 @@ int BasicDVIReader::evalCommand (CommandHandler &handler, int ¶m) { handler = &BasicDVIReader::cmdDir; num_param_bytes = 1; } - else if (opcode > OP_POSTPOST) { - ostringstream oss; - oss << "undefined DVI command (opcode " << opcode << ')'; - throw DVIException(oss.str()); - } + else if (opcode > OP_POSTPOST) + throw DVIException("undefined DVI command (opcode " + to_string(opcode) + ")"); else { const int offset = opcode < OP_FNTNUM0 ? OP_SET1 : (OP_FNTNUM63+1)-(OP_FNTNUM0-OP_SET1); handler = commands[opcode-offset].handler; @@ -194,9 +190,7 @@ void BasicDVIReader::setDVIVersion (DVIVersion version) { case DVI_XDV7: break; default: - ostringstream oss; - oss << "DVI version " << _dviVersion << " not supported"; - throw DVIException(oss.str()); + throw DVIException("DVI version " + to_string(_dviVersion) + " not supported"); } } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/BasicDVIReader.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/BasicDVIReader.hpp index ce3c0ac4061..14a1fb9858a 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/BasicDVIReader.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/BasicDVIReader.hpp @@ -51,7 +51,6 @@ class BasicDVIReader : public StreamReader { public: explicit BasicDVIReader (std::istream &is); - virtual ~BasicDVIReader () =default; virtual void executeAllPages (); virtual double getXPos () const {return 0;} virtual double getYPos () const {return 0;} diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/Bezier.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/Bezier.cpp index c98f6331930..d2077bcfebe 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/Bezier.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/Bezier.cpp @@ -21,11 +21,12 @@ #include <algorithm> #include <utility> #include "Bezier.hpp" +#include "Matrix.hpp" using namespace std; Bezier::Bezier () { - _points[0] = _points[1] = _points[2] = _points[3] = 0; + _points[0] = _points[1] = _points[2] = _points[3] = DPair(0); } @@ -51,13 +52,13 @@ Bezier::Bezier (const Bezier &source, double t0, double t1) { if (t0 > t1) swap(t0, t1); if (t0 == 0) - source.subdivide(t1, this, 0); + source.subdivide(t1, this, nullptr); else if (t1 == 1) - source.subdivide(t0, 0, this); + source.subdivide(t0, nullptr, this); else { Bezier subcurve; - source.subdivide(t0, 0, &subcurve); - subcurve.subdivide((t1-t0)/(1-t0), this, 0); + source.subdivide(t0, nullptr, &subcurve); + subcurve.subdivide((t1-t0)/(1-t0), this, nullptr); } } } @@ -230,8 +231,8 @@ static bool solve_quadratic_equation (double a, double b, double c, double &x1, /** Returns a tight bounding box parallel to the x- and y-axis. */ -void Bezier::getBBox (BoundingBox &bbox) const { - bbox.invalidate(); +BoundingBox Bezier::getBBox () const { + BoundingBox bbox; // coefficients of the derivative DPair pa = _points[3] - _points[2]*3.0 + _points[1]*3.0 - _points[0]; DPair pb = (_points[2]-_points[1]*2.0+_points[0])*2.0; @@ -253,4 +254,12 @@ void Bezier::getBBox (BoundingBox &bbox) const { } bbox.embed(_points[0]); bbox.embed(_points[3]); + return bbox; +} + + +Bezier& Bezier::transform (const Matrix &matrix) { + for (int i=0; i < 4; i++) + _points[i] = matrix*_points[i]; + return *this; } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/Bezier.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/Bezier.hpp index 7ba44418ea4..525ef23435b 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/Bezier.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/Bezier.hpp @@ -25,8 +25,9 @@ #include "BoundingBox.hpp" #include "Pair.hpp" -class Bezier -{ +class Matrix; + +class Bezier { public: Bezier (); Bezier (const DPair &p0, const DPair &p1, const DPair &p2); @@ -37,10 +38,11 @@ class Bezier DPair valueAt (double t) const; DPair blossomValue (double u, double v, double w) const; void subdivide (double t, Bezier *bezier1, Bezier *bezier2) const; - int approximate (double delta, std::vector<DPair> &p, std::vector<double> *t=0) const; + Bezier& transform (const Matrix &matrix); + int approximate (double delta, std::vector<DPair> &p, std::vector<double> *t=nullptr) const; const DPair& point (int i) const {return _points[i];} int reduceDegree (double delta, std::vector<DPair> &p) const; - void getBBox (BoundingBox &bbox) const; + BoundingBox getBBox () const; protected: int approximate (double delta, double t0, double t1, std::vector<DPair> &p, std::vector<double> *t) const; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/BgColorSpecialHandler.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/BgColorSpecialHandler.cpp index 1512e3fbe7c..10c05fca051 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/BgColorSpecialHandler.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/BgColorSpecialHandler.cpp @@ -54,7 +54,7 @@ void BgColorSpecialHandler::dviBeginPage (unsigned pageno, SpecialActions &actio if (_pageColors.empty()) return; // find number of page with bg color change not lower than the current one - vector<PageColor>::iterator it = lower_bound(_pageColors.begin(), _pageColors.end(), PageColor(pageno, Color::BLACK)); + auto it = lower_bound(_pageColors.begin(), _pageColors.end(), PageColor(pageno, Color::BLACK)); if (it != _pageColors.end() && it->first == pageno) actions.setBgColor(it->second); else if (it != _pageColors.begin()) diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/Bitmap.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/Bitmap.cpp index e39ad79c476..3fa554eed42 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/Bitmap.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/Bitmap.cpp @@ -25,10 +25,6 @@ using namespace std; -Bitmap::Bitmap () : _rows(0), _cols(0), _xshift(0), _yshift(0), _bpr(0), _bytes(0) -{ -} - /** Constructs a Bitmap */ Bitmap::Bitmap (int minx, int maxx, int miny , int maxy) { @@ -48,8 +44,7 @@ void Bitmap::resize (int minx, int maxx, int miny , int maxy) { _yshift = miny; _bpr = _cols/8 + (_cols % 8 ? 1 : 0); // bytes per row _bytes.resize(_rows*_bpr); - for (uint8_t &byte : _bytes) - byte = 0; + std::fill(_bytes.begin(), _bytes.end(), 0); } @@ -69,7 +64,7 @@ void Bitmap::setBits (int row, int col, int n) { int m = min(n, b+1); // number of bits to be set in current byte int bitseq = (1 << m)-1; // sequence of n set bits (bits 0..n-1 are set) bitseq <<= b-m+1; // move bit sequence so that bit b is the leftmost set bit - *byte |= uint8_t(bitseq); // apply bit sequence to current byte + *byte |= uint8_t(bitseq); // apply bit sequence to current byte byte++; n -= m; col += m; @@ -90,10 +85,8 @@ void Bitmap::forAllPixels (Callback &data) const { } -class BBoxCallback : public Bitmap::Callback -{ +class BBoxCallback : public Bitmap::Callback { public: - BBoxCallback () : _changed(false), _minx(numeric_limits<int>::max()), _miny(_minx), _maxx(0), _maxy(0) {} int minx () const {return _minx;} int miny () const {return _miny;} int maxx () const {return _maxx;} @@ -116,8 +109,9 @@ class BBoxCallback : public Bitmap::Callback } private: - bool _changed; - int _minx, _miny, _maxx, _maxy; + bool _changed = false; + int _minx = numeric_limits<int>::max(), _miny=_minx; + int _maxx = 0, _maxy = 0; }; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/Bitmap.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/Bitmap.hpp index fe9f31f0536..026edae9a21 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/Bitmap.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/Bitmap.hpp @@ -25,8 +25,7 @@ #include <vector> -class Bitmap -{ +class Bitmap { public: struct Callback { virtual ~Callback() =default; @@ -36,7 +35,7 @@ class Bitmap }; public: - Bitmap (); + Bitmap () =default; Bitmap (int minx, int maxx, int miny , int maxy); void resize (int minx, int maxx, int miny , int maxy); void setBits(int row, int col, int n); @@ -60,9 +59,9 @@ class Bitmap // std::ostream& write (std::ostream &os) const; private: - int _rows, _cols; ///< number of rows, columns - int _xshift, _yshift; ///< horizontal/vertical shift - int _bpr; ///< number of bytes per row + int _rows=0, _cols=0; ///< number of rows, columns + int _xshift=0, _yshift=0; ///< horizontal/vertical shift + int _bpr=0; ///< number of bytes per row std::vector<uint8_t> _bytes; }; @@ -81,7 +80,7 @@ int Bitmap::copy (std::vector<T> &target, bool vflip) const { int targetrow = vflip ? _rows-r-1 : r; for (int b=0; b < _bpr; b++) { T &t = target[targetrow*tpr + b/s]; - T chunk = (T)_bytes[r*_bpr+b] << (8*(s-1-b%s)); + T chunk = static_cast<T>(_bytes[r*_bpr+b]) << (8*(s-1-b%s)); if (b % s == 0) t = chunk; else @@ -107,5 +106,4 @@ void Bitmap::write (std::ostream &os, const std::vector<T> &v) const { } }*/ - #endif diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/BoundingBox.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/BoundingBox.cpp index 968a1517526..a076b523639 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/BoundingBox.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/BoundingBox.cpp @@ -74,7 +74,7 @@ vector<Length> BoundingBox::extractLengths (string boxstr) { boxstr = util::replace(boxstr, ",", " "); boxstr = util::normalize_space(boxstr); vector<string> lengthStrings = util::split(boxstr, " "); - for (string lenstr : lengthStrings) { + for (const string &lenstr : lengthStrings) { if (!lenstr.empty()) lengths.emplace_back(Length(lenstr)); } @@ -263,8 +263,8 @@ ostream& BoundingBox::write (ostream &os) const { } -unique_ptr<XMLElementNode> BoundingBox::createSVGRect () const { - auto rect = util::make_unique<XMLElementNode>("rect"); +unique_ptr<XMLElement> BoundingBox::createSVGRect () const { + auto rect = util::make_unique<XMLElement>("rect"); rect->addAttribute("x", minX()); rect->addAttribute("y", minY()); rect->addAttribute("width", width()); diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/BoundingBox.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/BoundingBox.hpp index 3ff775d02bf..8848f60f288 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/BoundingBox.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/BoundingBox.hpp @@ -31,11 +31,11 @@ class Matrix; -class XMLElementNode; +class XMLElement; struct BoundingBoxException : MessageException { - BoundingBoxException (const std::string &msg) : MessageException(msg) {} + explicit BoundingBoxException (const std::string &msg) : MessageException(msg) {} }; @@ -45,7 +45,7 @@ class BoundingBox { BoundingBox (double ulxx, double ulyy, double lrxx, double lryy); BoundingBox (const DPair &p1, const DPair &p2); BoundingBox (const Length &ulxx, const Length &ulyy, const Length &lrxx, const Length &lryy); - BoundingBox (const std::string &boxstr); + explicit BoundingBox (const std::string &boxstr); void set (const std::string &boxstr); void set (const std::vector<Length> &lengths); void embed (double x, double y); @@ -78,7 +78,7 @@ class BoundingBox { void transform (const Matrix &tm); std::string toSVGViewBox () const; std::ostream& write (std::ostream &os) const; - std::unique_ptr<XMLElementNode> createSVGRect () const; + std::unique_ptr<XMLElement> createSVGRect () const; private: double _ulx, _uly; ///< coordinates of upper left vertex (in PS point units) diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/CLCommandLine.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/CLCommandLine.cpp index 9b399a2b021..2b0c1b5359e 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/CLCommandLine.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/CLCommandLine.cpp @@ -39,7 +39,7 @@ void CommandLine::parse (int argc, char **argv) { for (int i=1; i < argc; i++) { istringstream iss(argv[i]); if (filesOnly || iss.peek() != '-') - _files.push_back(argv[i]); + _files.emplace_back(argv[i]); else { iss.get(); // skip dash if (iss.peek() < 0) diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/CLCommandLine.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/CLCommandLine.hpp index e012b21a4c9..a80d9b87d75 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/CLCommandLine.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/CLCommandLine.hpp @@ -37,7 +37,7 @@ class CommandLine { virtual ~CommandLine () =default; void parse (int argc, char **argv); void help (std::ostream &os, int mode=0) const; - void addFilename (std::string fname) {_files.emplace_back(fname);} + void addFilename (const std::string &fname) {_files.emplace_back(fname);} bool singleDashGiven () const {return _singleDashParsed;} const std::vector<std::string>& filenames () const {return _files;} @@ -60,7 +60,7 @@ class CommandLine { struct CommandLineException : public MessageException { - CommandLineException (const std::string &msg) : MessageException(msg) {} + explicit CommandLineException (const std::string &msg) : MessageException(msg) {} }; } // namespace CL diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/CMap.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/CMap.hpp index 22b16dced0a..0f0259e8538 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/CMap.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/CMap.hpp @@ -28,9 +28,7 @@ #include "RangeMap.hpp" -struct CMap : public NamedFontEncoding -{ - virtual ~CMap () =default; +struct CMap : public NamedFontEncoding { virtual bool vertical () const =0; virtual bool mapsToCID () const =0; virtual uint32_t cid (uint32_t c) const =0; @@ -48,8 +46,7 @@ struct CMap : public NamedFontEncoding }; -struct IdentityCMap : public CMap -{ +struct IdentityCMap : public CMap { uint32_t cid (uint32_t c) const override {return c;} uint32_t bfcode (uint32_t cid) const override {return 0;} std::string getROString () const override {return "Adobe-Identity";} @@ -57,38 +54,34 @@ struct IdentityCMap : public CMap }; -struct IdentityHCMap : public IdentityCMap -{ +struct IdentityHCMap : public IdentityCMap { bool vertical () const override {return false;} const char* name () const override {return "Identity-H";} }; -struct IdentityVCMap : public IdentityCMap -{ +struct IdentityVCMap : public IdentityCMap { bool vertical () const override {return true;} const char* name () const override {return "Identity-V";} }; -struct UnicodeCMap : public CMap -{ +struct UnicodeCMap : public CMap { bool vertical () const override {return false;} const char* name () const override {return "unicode";} bool mapsToCID () const override {return false;} - const char* path () const override {return 0;} + const char* path () const override {return nullptr;} uint32_t cid (uint32_t c) const override {return c;} uint32_t bfcode (uint32_t cid) const override {return cid;} std::string getROString () const override {return "";} }; -class SegmentedCMap : public CMap -{ +class SegmentedCMap : public CMap { friend class CMapReader; public: - SegmentedCMap (const std::string &fname) : _filename(fname), _basemap(0), _vertical(false), _mapsToCID(true) {} + explicit SegmentedCMap (std::string fname) : _filename(std::move(fname)) {} const char* name () const override {return _filename.c_str();} uint32_t cid (uint32_t c) const override; uint32_t bfcode (uint32_t cid) const override; @@ -105,9 +98,9 @@ class SegmentedCMap : public CMap std::string _filename; std::string _registry; std::string _ordering; - CMap *_basemap; - bool _vertical; - bool _mapsToCID; // true: chrcode->CID, false: CID->charcode + CMap *_basemap = nullptr; + bool _vertical = false; + bool _mapsToCID = true; // true: chrcode->CID, false: CID->charcode RangeMap _cidranges; RangeMap _bfranges; }; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/CMapManager.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/CMapManager.cpp index f033da7efc0..779c6ee3a83 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/CMapManager.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/CMapManager.cpp @@ -44,9 +44,7 @@ CMap* CMapManager::lookup (const string &name) { if (_includedCMaps.find(name) != _includedCMaps.end()) { _level = 0; - ostringstream oss; - oss << "circular reference of CMap " << name; - throw CMapReaderException(oss.str()); + throw CMapReaderException("circular reference of CMap " + name); } unique_ptr<CMap> cmap_ptr; @@ -124,8 +122,8 @@ const CMap* CMapManager::findCompatibleBaseFontMap (const PhysicalFont *font, co const bool is_unicode_map = bool(dynamic_cast<const UnicodeCMap*>(cmap)); const string ro = cmap->getROString(); for (const CharMapIDToEncName &enc : encodings) { - for (size_t i=0; i < charmapIDs.size(); i++) { - if (enc.id == charmapIDs[i]) { + for (const CharMapID &id : charmapIDs) { + if (enc.id == id) { string cmapname = ro+"-"+enc.encname; if (is_unicode_map || FileFinder::instance().lookup(cmapname, "cmap", false)) { charmapID = enc.id; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/CMapReader.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/CMapReader.cpp index 35f31d78d64..6661afbbb10 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/CMapReader.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/CMapReader.cpp @@ -32,10 +32,6 @@ using namespace std; -CMapReader::CMapReader () : _inCMap(false) { -} - - /** Reads a cmap file and returns the corresponding CMap object. * @param fname[in] name/path of cmap file * @return CMap object representing the read data, or 0 if file could not be read */ @@ -74,7 +70,7 @@ unique_ptr<CMap> CMapReader::read (std::istream& is, const string &name) { } } catch (CMapReaderException &e) { - _cmap.release(); + _cmap.reset(); throw; } return std::move(_cmap); @@ -89,9 +85,10 @@ void CMapReader::executeOperator (const string &opname, InputReader &ir) { const char *name; void (CMapReader::*handler)(InputReader&); }; - constexpr array<Operator, 6> operators {{ + constexpr array<Operator, 7> operators {{ {"beginbfchar", &CMapReader::op_beginbfchar}, {"beginbfrange", &CMapReader::op_beginbfrange}, + {"begincidchar", &CMapReader::op_begincidchar}, {"begincidrange", &CMapReader::op_begincidrange}, {"def", &CMapReader::op_def}, {"endcmap", &CMapReader::op_endcmap}, @@ -135,7 +132,7 @@ void CMapReader::op_usecmap (InputReader &) { throw CMapReaderException("stack underflow while processing usecmap"); else { const string name = popToken().strvalue(); - if ((_cmap->_basemap = CMapManager::instance().lookup(name)) == 0) + if ((_cmap->_basemap = CMapManager::instance().lookup(name)) == nullptr) throw CMapReaderException("CMap file '"+name+"' not found"); } } @@ -154,17 +151,19 @@ static uint32_t parse_hexentry (InputReader &ir) { } -void CMapReader::op_begincidrange (InputReader &ir) { +void CMapReader::parseCIDChars (InputReader &ir, bool isRange) { if (!_tokens.empty() && _tokens.back().type() == Token::Type::NUMBER) { ir.skipSpace(); int num_entries = static_cast<int>(popToken().numvalue()); while (num_entries > 0 && ir.peek() == '<') { uint32_t first = parse_hexentry(ir); - uint32_t last = parse_hexentry(ir); - uint32_t cid; + uint32_t last = first; + if (isRange) + last = parse_hexentry(ir); ir.skipSpace(); + uint32_t cid; if (!ir.parseUInt(cid)) - throw CMapReaderException("invalid range entry (decimal value expected)"); + throw CMapReaderException("invalid char entry (decimal value expected)"); _cmap->addCIDRange(first, last, cid); ir.skipSpace(); } @@ -172,6 +171,16 @@ void CMapReader::op_begincidrange (InputReader &ir) { } +void CMapReader::op_begincidchar (InputReader &ir) { + parseCIDChars(ir, false); +} + + +void CMapReader::op_begincidrange (InputReader &ir) { + parseCIDChars(ir, true); +} + + void CMapReader::op_beginbfrange (InputReader &ir) { if (!_tokens.empty() && _tokens.back().type() == Token::Type::NUMBER) { ir.skipSpace(); @@ -249,9 +258,7 @@ void CMapReader::Token::scan (InputReader &ir) { else if (isdigit(ir.peek())) { // number? double val; if (ir.parseDouble(val)) { - ostringstream oss; - oss << val; - _value = oss.str(); + _value = util::to_string(val); _type = Type::NUMBER; } } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/CMapReader.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/CMapReader.hpp index 4b04156d53d..3e5b841e0cf 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/CMapReader.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/CMapReader.hpp @@ -38,7 +38,7 @@ class CMapReader { enum class Type {UNKNOWN, END, DELIM, NUMBER, STRING, NAME, OPERATOR}; public: - Token (InputReader &ir); + explicit Token (InputReader &ir); void scan (InputReader &ir); Type type () const {return _type;} const std::string& strvalue () const {return _value;} @@ -50,15 +50,16 @@ class CMapReader { }; public: - CMapReader (); std::unique_ptr<CMap> read (const std::string &fname); std::unique_ptr<CMap> read (std::istream &is, const std::string &name); protected: Token popToken () {Token t=_tokens.back(); _tokens.pop_back(); return t;} void executeOperator (const std::string &op, InputReader &ir); + void parseCIDChars (InputReader &ir, bool isRange); void op_beginbfchar (InputReader &ir); void op_beginbfrange (InputReader &ir); + void op_begincidchar (InputReader &ir); void op_begincidrange (InputReader &ir); void op_def (InputReader &ir); void op_endcmap (InputReader &ir); @@ -67,13 +68,12 @@ class CMapReader { private: std::unique_ptr<SegmentedCMap> _cmap; ///< pointer to CMap being read std::vector<Token> _tokens; ///< stack of tokens to be processed - bool _inCMap; ///< operator begincmap has been executed + bool _inCMap=false; ///< true if operator begincmap has been executed }; - struct CMapReaderException : public MessageException { - CMapReaderException (const std::string &msg) : MessageException(msg) {} + explicit CMapReaderException (const std::string &msg) : MessageException(msg) {} }; #endif diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/CRC32.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/CRC32.cpp deleted file mode 100644 index 583b019324e..00000000000 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/CRC32.cpp +++ /dev/null @@ -1,112 +0,0 @@ -/************************************************************************* -** CRC32.cpp ** -** ** -** This file is part of dvisvgm -- a fast DVI to SVG converter ** -** Copyright (C) 2005-2019 Martin Gieseking <martin.gieseking@uos.de> ** -** ** -** 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 <http://www.gnu.org/licenses/>. ** -*************************************************************************/ - -#include <cstring> -#include "CRC32.hpp" - -using namespace std; - - -CRC32::CRC32 () : _crc32(0xFFFFFFFF) -{ - const uint32_t poly = 0xEDB88320; - for (int i = 0; i < 256; i++) { - uint32_t crc=i; - for (int j=8; j > 0; j--) { - if (crc & 1) - crc = (crc >> 1) ^ poly; - else - crc >>= 1; - } - _tab[i] = crc; - } -} - - -/** Resets CRC32 sum to 0. */ -void CRC32::reset () { - _crc32 = 0xFFFFFFFF; -} - - -/** Appends string bytes to the previous data and computes the resulting checksum. - * @param[in] data string to update the checksum with */ -void CRC32::update (const char *data) { - update((const uint8_t*)data, strlen(data)); -} - - -/** Appends a single value to the previous data and computes the resulting checksum. - * @param[in] n value to update the checksum with - * @param[in] bytes number of bytes to consider (0-4) */ -void CRC32::update (uint32_t n, int bytes) { - for (int i=bytes-1; i >= 0; --i) { - uint8_t byte = uint8_t((n >> (8*i)) & 0xff); - update(&byte, 1); - } -} - - -/** Appends a sequence of bytes to the previous data and computes the resulting checksum. - * @param[in] bytes pointer to array of bytes - * @param[in] len number of bytes in array */ -void CRC32::update (const uint8_t *bytes, size_t len) { - for (size_t i=0; i < len; ++i) - _crc32 = ((_crc32 >> 8) & 0x00FFFFFF) ^ _tab[(_crc32 ^ *bytes++) & 0xFF]; -} - - -void CRC32::update (istream &is) { - char buf [4096]; - while (is) { - is.read(buf, 4096); - update((uint8_t*)buf, is.gcount()); - } -} - - -/** Returns the checksum computed from values added with the update functions. */ -uint32_t CRC32::get () const { - return _crc32 ^ 0xFFFFFFFF; -} - - -/** Computes the CRC32 checksum of a sequence of bytes. - * @param[in] bytes pointer to array of bytes - * @param[in] len number of bytes in array - * @return CRC32 checksum */ -uint32_t CRC32::compute (const uint8_t *bytes, size_t len) { - CRC32 crc32; - crc32.update(bytes, len); - return crc32.get(); -} - - -/** Computes the CRC32 checksum of a string. */ -uint32_t CRC32::compute (const char *str) { - return compute((const uint8_t*)str, strlen(str)); -} - - -uint32_t CRC32::compute (istream &is) { - CRC32 crc32; - crc32.update(is); - return crc32.get(); -} diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/Calculator.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/Calculator.hpp index 876e5e07834..f498365e544 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/Calculator.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/Calculator.hpp @@ -28,7 +28,7 @@ struct CalculatorException : public MessageException { - CalculatorException (const std::string &msg) : MessageException(msg) {} + explicit CalculatorException (const std::string &msg) : MessageException(msg) {} }; class Calculator { diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/CharMapID.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/CharMapID.hpp index befd5ee2eac..e79c64b24fc 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/CharMapID.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/CharMapID.hpp @@ -25,8 +25,8 @@ /** Represents a character map of a font. */ struct CharMapID { - CharMapID () : platform_id(0), encoding_id(0) {} - CharMapID (uint8_t plf_id, uint8_t enc_id) : platform_id(plf_id), encoding_id(enc_id) {} + CharMapID () noexcept : platform_id(0), encoding_id(0) {} + CharMapID (uint8_t plf_id, uint8_t enc_id) noexcept : platform_id(plf_id), encoding_id(enc_id) {} bool operator == (const CharMapID &ids) const { return platform_id == ids.platform_id && encoding_id == ids.encoding_id; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/Character.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/Character.hpp index 338a0fb4982..e232401fb80 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/Character.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/Character.hpp @@ -22,11 +22,10 @@ #define CHARACTER_HPP -class Character -{ +class Character { public: enum Type {CHRCODE, INDEX, NAME}; - Character (const char *name) : _type(NAME), _name(name) {} + explicit Character (const char *name) : _type(NAME), _name(name) {} Character (Type type, uint32_t val) : _type(type), _number(val) {} Character (Type type, const Character &c) : _type(type), _number(c.type() != NAME ? c._number : 0) {} Type type () const {return _type;} diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/Color.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/Color.cpp index aa6b90b4063..de7e9074abf 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/Color.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/Color.cpp @@ -40,7 +40,7 @@ const Color Color::TRANSPARENT(uint32_t(0xff000000)); static inline uint8_t double_to_byte (double v) { v = max(0.0, min(1.0, v)); - return uint8_t(floor(255*v+0.5)); + return uint8_t(round(255.0*v)); } @@ -61,7 +61,7 @@ void Color::setRGB (double r, double g, double b) { * @return true if color name could be applied properly */ bool Color::setPSName (string name, bool case_sensitive) { if (name[0] == '#') { - char *p=0; + char *p=nullptr; _rgb = uint32_t(strtol(name.c_str()+1, &p, 16)); while (isspace(*p)) p++; @@ -213,7 +213,7 @@ Color Color::operator *= (double c) { else if (abs(c-trunc(c)) < 0.999) { uint32_t rgb=0; for (int i=0; i < 3; i++) { - rgb |= uint32_t((_rgb & 0xff)*c+0.5) << (8*i); + rgb |= lround((_rgb & 0xff)*c) << (8*i); _rgb >>= 8; } _rgb = rgb; @@ -394,7 +394,7 @@ string Color::svgColorString (bool rgbonly) const { {0xfffff0, "ivory"}, {0xffffff, "white"} }}; - ColorName cmppair = {_rgb, 0}; + ColorName cmppair = {_rgb, nullptr}; auto it = lower_bound(colornames.begin(), colornames.end(), cmppair, [](const ColorName &c1, const ColorName &c2) { return c1.rgb < c2.rgb; }); @@ -632,14 +632,14 @@ double Color::deltaE (const Color &c) const { c.getLab(l2, a2, b2); const double deltaL = l2-l1; const double lBar = (l1+l2)/2; - const double c1 = sqrt(a1*a1 + b1*b1); - const double c2 = sqrt(a2*a2 + b2*b2); + const double c1 = hypot(a1, b1); + const double c2 = hypot(a2, b2); const double cBar = (c1+c2)/2.0; const double g = (1.0-sqrt(pow(cBar, 7.0)/(pow(cBar, 7.0)+6103515625.0)))/2.0; const double aa1 = a1*(1.0+g); const double aa2 = a2*(1.0+g); - const double cc1 = sqrt(aa1*aa1 + b1*b1); - const double cc2 = sqrt(aa2*aa2 + b2*b2); + const double cc1 = hypot(aa1, b1); + const double cc2 = hypot(aa2, b2); const double ccBar = (cc1+cc2)/2.0; const double deltaCC = cc2-cc1; double hh1 = atan2(b1, aa1); diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/Color.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/Color.hpp index 27efa3a5988..f522bded55e 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/Color.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/Color.hpp @@ -30,8 +30,7 @@ #undef TRANSPARENT #endif -class Color -{ +class Color { public: static bool SUPPRESS_COLOR_NAMES; static const Color BLACK; @@ -41,12 +40,12 @@ class Color enum class ColorSpace {GRAY, RGB, CMYK, LAB}; public: - Color () : _rgb(0) {} - Color (uint32_t rgb) : _rgb(rgb) {} - Color (uint8_t r, uint8_t g, uint8_t b) {setRGB(r,g,b);} - Color (double r, double g, double b) {setRGB(r,g,b);} - Color (const std::valarray<double> &rgb) {setRGB(rgb);} - Color (const std::string &name); + Color () noexcept : _rgb(0) {} + explicit Color (uint32_t rgb) noexcept : _rgb(rgb) {} + Color (uint8_t r, uint8_t g, uint8_t b) noexcept {setRGB(r,g,b);} + Color (double r, double g, double b) noexcept {setRGB(r,g,b);} + explicit Color (const std::valarray<double> &rgb) noexcept {setRGB(rgb);} + explicit Color (const std::string &name); explicit operator uint32_t () const {return _rgb;} bool operator == (const Color &c) const {return _rgb == c._rgb;} bool operator != (const Color &c) const {return _rgb != c._rgb;} diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/ColorSpecialHandler.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/ColorSpecialHandler.cpp index c6a756be17e..4bfd4940039 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/ColorSpecialHandler.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/ColorSpecialHandler.cpp @@ -40,10 +40,10 @@ static double read_double (istream &is) { /** Reads multiple double values from a given stream. The number of * values read is determined by the size of the result vector. * @param[in] is stream to be read from - * @param[out] v the resulting values */ -static void read_doubles (istream &is, vector<double> &v) { - for (size_t i=0; i < v.size(); i++) - v[i] = read_double(is); + * @param[out] vec the resulting values */ +static void read_doubles (istream &is, vector<double> &vec) { + for (double &val : vec) + val = read_double(is); } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/CommandLine.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/CommandLine.hpp index d60ad44511f..b1f2636040f 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/CommandLine.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/CommandLine.hpp @@ -35,7 +35,7 @@ class CommandLine : public CL::CommandLine { Option colornamesOpt {"colornames", '\0', "prefer color names to RGB values if possible"}; Option commentsOpt {"comments", '\0', "add comments with additional information"}; Option epsOpt {"eps", 'E', "convert EPS file to SVG"}; - Option exactOpt {"exact", 'e', "compute exact glyph boxes"}; + Option exactBboxOpt {"exact-bbox", 'e', "compute exact glyph bounding boxes"}; TypedOption<std::string, Option::ArgMode::REQUIRED> fontFormatOpt {"font-format", 'f', "format", "svg", "select file format of embedded fonts"}; TypedOption<std::string, Option::ArgMode::REQUIRED> fontmapOpt {"fontmap", 'm', "filenames", "evaluate (additional) font map files"}; Option gradOverlapOpt {"grad-overlap", '\0', "create overlapping color gradient segments"}; @@ -52,6 +52,7 @@ class CommandLine : public CL::CommandLine { Option noMktexmfOpt {"no-mktexmf", '\0', "don't try to create missing fonts"}; TypedOption<std::string, Option::ArgMode::OPTIONAL> noSpecialsOpt {"no-specials", 'S', "prefixes", "don't process [selected] specials"}; Option noStylesOpt {"no-styles", '\0', "don't use CSS styles to reference fonts"}; + TypedOption<std::string, Option::ArgMode::OPTIONAL> optimizeOpt {"optimize", 'O', "modules", "all", "perform several SVG optimizations"}; TypedOption<std::string, Option::ArgMode::REQUIRED> outputOpt {"output", 'o', "pattern", "set name pattern of output files"}; TypedOption<std::string, Option::ArgMode::REQUIRED> pageOpt {"page", 'p', "ranges", "1", "choose page(s) to convert"}; TypedOption<std::string, Option::ArgMode::OPTIONAL> pageHashesOpt {"page-hashes", 'H', "params", "xxh64", "activate usage of page hashes"}; @@ -114,6 +115,7 @@ class CommandLine : public CL::CommandLine { {&gradSimplifyOpt, 1}, #endif {&linkmarkOpt, 1}, + {&optimizeOpt, 1}, {&outputOpt, 1}, {&precisionOpt, 1}, {&relativeOpt, 1}, @@ -129,7 +131,7 @@ class CommandLine : public CL::CommandLine { {&transformOpt, 2}, {&zoomOpt, 2}, {&cacheOpt, 3}, - {&exactOpt, 3}, + {&exactBboxOpt, 3}, {&keepOpt, 3}, #if !defined(HAVE_LIBGS) && !defined(DISABLE_GS) {&libgsOpt, 3}, diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/DLLoader.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/DLLoader.hpp index 47839216010..6bfff573e27 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/DLLoader.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/DLLoader.hpp @@ -33,7 +33,7 @@ class DLLoader { public: DLLoader () =delete; - DLLoader (const std::string &dlname); + explicit DLLoader (const std::string &dlname); DLLoader (DLLoader &&loader) =default; virtual ~DLLoader () {closeLibrary();} bool loaded () const {return _handle != nullptr;} diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIActions.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIActions.hpp index ac57eb25edc..c42f446d9ee 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIActions.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIActions.hpp @@ -40,7 +40,7 @@ struct DVIActions { virtual void beginPage (unsigned pageno, const std::vector<int32_t> &c) {} virtual void endPage (unsigned pageno) {} virtual BoundingBox& bbox () =0; - virtual void progress (size_t current, size_t total, const char *id=0) {} + virtual void progress (size_t current, size_t total, const char *id=nullptr) {} }; #endif diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIReader.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIReader.cpp index 415b97dc438..b0bbabee947 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIReader.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIReader.cpp @@ -277,7 +277,7 @@ void DVIReader::cmdPop (int) { * @param[in] font current font (corresponding to _currFontNum) * @param[in] c character to typeset */ void DVIReader::putVFChar (Font *font, uint32_t c) { - if (VirtualFont *vf = dynamic_cast<VirtualFont*>(font)) { // is current font a virtual font? + if (auto vf = dynamic_cast<VirtualFont*>(font)) { // is current font a virtual font? if (const vector<uint8_t> *dvi = vf->getDVI(c)) { // try to get DVI snippet that represents character c FontManager &fm = FontManager::instance(); DVIState savedState = _dviState; // save current cursor position @@ -457,11 +457,8 @@ void DVIReader::cmdDir (int) { uint8_t wmode = readUnsigned(1); if (wmode == 4) // yoko mode (4) equals default LR mode (0) wmode = 0; - if (wmode == 2 || wmode > 3) { - ostringstream oss; - oss << "invalid writing mode value " << wmode << " (0, 1, 3, or 4 expected)"; - throw DVIException(oss.str()); - } + if (wmode == 2 || wmode > 3) + throw DVIException("invalid writing mode value " + std::to_string(wmode) + " (0, 1, 3, or 4 expected)"); _dviState.d = (WritingMode)wmode; dviDir(_dviState.d); } @@ -485,11 +482,8 @@ void DVIReader::setFont (int fontnum, SetFontMode mode) { _currFontNum = fontnum; dviFontNum(uint32_t(fontnum), mode, font); } - else { - ostringstream oss; - oss << "undefined font number " << fontnum; - throw DVIException(oss.str()); - } + else + throw DVIException("undefined font number " + std::to_string(fontnum)); } @@ -522,7 +516,7 @@ const Font* DVIReader::defineFont (uint32_t fontnum, const string &name, uint32_ if (!font) { int id = fm.registerFont(fontnum, name, cs, ds, ss); font = fm.getFontById(id); - if (VirtualFont *vf = dynamic_cast<VirtualFont*>(font)) { + if (auto vf = dynamic_cast<VirtualFont*>(font)) { // read vf file, register its font and character definitions fm.enterVF(vf); ifstream ifs(vf->path(), ios::binary); diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIToSVG.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIToSVG.cpp index 82eeb8a7c9f..4801bd80a01 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIToSVG.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIToSVG.cpp @@ -38,6 +38,7 @@ #include "PageSize.hpp" #include "PreScanDVIReader.hpp" #include "SignalHandler.hpp" +#include "optimizer/SVGOptimizer.hpp" #include "SVGOutput.hpp" #include "utility.hpp" #include "version.hpp" @@ -110,18 +111,19 @@ void DVIToSVG::convert (unsigned first, unsigned last, HashFunction *hashFunc) { combinedHash = hashFunc->digestString(); } const SVGOutput::HashTriple hashTriple(dviHash, shortenedOptHash, combinedHash); - string fname = _out.filename(i, numberOfPages(), hashTriple); - if (!dviHash.empty() && !PAGE_HASH_SETTINGS.isSet(HashSettings::P_REPLACE) && FileSystem::exists(fname)) { + FilePath path = _out.filepath(i, numberOfPages(), hashTriple); + if (!dviHash.empty() && !PAGE_HASH_SETTINGS.isSet(HashSettings::P_REPLACE) && path.exists()) { Message::mstream(false, Message::MC_PAGE_NUMBER) << "skipping page " << i; Message::mstream().indent(1); - Message::mstream(false, Message::MC_PAGE_WRITTEN) << "\nfile " << fname << " exists\n"; + Message::mstream(false, Message::MC_PAGE_WRITTEN) << "\nfile " << path.shorterAbsoluteOrRelative() << " exists\n"; Message::mstream().indent(0); } else { executePage(i); - _svg.removeRedundantElements(); + SVGOptimizer(_svg).execute(); embedFonts(_svg.rootNode()); bool success = _svg.write(_out.getPageStream(currentPageNumber(), numberOfPages(), hashTriple)); + string fname = path.shorterAbsoluteOrRelative(); if (fname.empty()) fname = "<stdout>"; if (success) @@ -161,7 +163,7 @@ void DVIToSVG::convert (const string &rangestr, pair<int,int> *pageinfo) { throw MessageException("invalid page range format"); Message::mstream(false, Message::MC_PAGE_NUMBER) << "pre-processing DVI file (format version " << getDVIVersion() << ")\n"; - if (DVIToSVGActions *actions = dynamic_cast<DVIToSVGActions*>(_actions.get())) { + if (auto actions = dynamic_cast<DVIToSVGActions*>(_actions.get())) { PreScanDVIReader prescan(getInputStream(), actions); actions->setDVIReader(prescan); prescan.executeAllPages(); @@ -243,7 +245,7 @@ void DVIToSVG::enterBeginPage (unsigned pageno, const vector<int32_t> &c) { if (pageno != (unsigned)c[0]) // Does page number shown on page differ from physical page number? Message::mstream(false) << " [" << c[0] << ']'; Message::mstream().indent(1); - _svg.appendToDoc(util::make_unique<XMLCommentNode>(" This file was generated by dvisvgm " + string(PROGRAM_VERSION) + " ")); + _svg.appendToDoc(util::make_unique<XMLComment>(" This file was generated by dvisvgm " + string(PROGRAM_VERSION) + " ")); } } @@ -322,7 +324,7 @@ Matrix DVIToSVG::getPageTransformation () const { calc.setVariable("h", bbox.height()*bp2pt); } // add constants for length units to calculator - for (auto unit : Length::getUnits()) + for (const auto &unit : Length::getUnits()) calc.setVariable(unit.first, Length(1, unit.second).pt()); matrix.set(_transCmds, calc); } @@ -331,18 +333,22 @@ Matrix DVIToSVG::getPageTransformation () const { static void collect_chars (unordered_map<const Font*, set<int>> &fontmap) { + unordered_map<const Font*, set<int>> insertedChars; for (const auto &entry : fontmap) { - if (entry.first->uniqueFont() != entry.first) { + const Font *unique_font = entry.first->uniqueFont(); + if (unique_font != entry.first) { for (int c : entry.second) - fontmap[entry.first->uniqueFont()].insert(c); + insertedChars[unique_font].insert(c); } } + for (const auto &entry : insertedChars) + fontmap[entry.first].insert(entry.second.begin(), entry.second.end()); } /** Adds the font information to the SVG tree. * @param[in] svgElement the font nodes are added to this node */ -void DVIToSVG::embedFonts (XMLElementNode *svgElement) { +void DVIToSVG::embedFonts (XMLElement *svgElement) { if (!svgElement || !_actions) // no dvi actions => no chars written => no fonts to embed return; @@ -355,7 +361,7 @@ void DVIToSVG::embedFonts (XMLElementNode *svgElement) { unordered_set<const Font*> tracedFonts; // collect unique fonts already traced for (const auto &fontchar : usedCharsMap) { const Font *font = fontchar.first; - if (const PhysicalFont *ph_font = dynamic_cast<const PhysicalFont*>(font)) { + if (auto ph_font = dynamic_cast<const PhysicalFont*>(font)) { // Check if glyphs should be traced. Only trace the glyphs of unique fonts, i.e. // avoid retracing the same glyphs again if they are referenced in various sizes. if (TRACE_MODE != 0 && tracedFonts.find(ph_font->uniqueFont()) == tracedFonts.end()) { @@ -420,8 +426,8 @@ void DVIToSVG::setProcessSpecials (const char *ignorelist, bool pswarning) { } -string DVIToSVG::getSVGFilename (unsigned pageno) const { - return _out.filename(pageno, numberOfPages()); +FilePath DVIToSVG::getSVGFilePath (unsigned pageno) const { + return _out.filepath(pageno, numberOfPages()); } @@ -567,6 +573,15 @@ void DVIToSVG::HashSettings::setParameters (const string ¶mstr) { _params.insert(it->second); else if (_algo.empty() && HashFunction::isSupportedAlgorithm(name)) _algo = name; + else if (!name.empty()) { + string msg = "invalid hash parameter '"+name+"' (supported algorithms: "; + for (string str : HashFunction::supportedAlgorithms()) + msg += str + ", "; + msg.pop_back(); + msg.pop_back(); + msg += ')'; + throw MessageException(msg); + } } // set default hash algorithm if none is given if (_algo.empty()) diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIToSVG.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIToSVG.hpp index b738239408e..40dbdc884ff 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIToSVG.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIToSVG.hpp @@ -25,6 +25,7 @@ #include <string> #include <utility> #include "DVIReader.hpp" +#include "FilePath.hpp" #include "SVGTree.hpp" struct DVIActions; @@ -50,7 +51,8 @@ class DVIToSVG : public DVIReader { public: explicit DVIToSVG (std::istream &is, SVGOutputBase &out); - void convert (const std::string &range, std::pair<int,int> *pageinfo=0); + DVIToSVG (const DVIToSVG&) =delete; + void convert (const std::string &range, std::pair<int,int> *pageinfo=nullptr); void setPageSize (const std::string &format) {_bboxFormatString = format;} void setPageTransformation (const std::string &cmds) {_transCmds = cmds;} Matrix getPageTransformation () const override; @@ -61,9 +63,9 @@ class DVIToSVG : public DVIReader { void finishLine () override {_prevYPos = std::numeric_limits<double>::min();} void listHashes (const std::string &rangestr, std::ostream &os); - std::string getSVGFilename (unsigned pageno) const; + FilePath getSVGFilePath (unsigned pageno) const; std::string getUserBBoxString () const {return _bboxFormatString;} - static void setProcessSpecials (const char *ignorelist=0, bool pswarning=false); + static void setProcessSpecials (const char *ignorelist=nullptr, bool pswarning=false); public: static bool COMPUTE_PROGRESS; ///< if true, an action to handle the progress ratio of a page is triggered @@ -71,12 +73,11 @@ class DVIToSVG : public DVIReader { static HashSettings PAGE_HASH_SETTINGS; protected: - DVIToSVG (const DVIToSVG&) =delete; void convert (unsigned firstPage, unsigned lastPage, HashFunction *hashFunc); int executeCommand () override; void enterBeginPage (unsigned pageno, const std::vector<int32_t> &c); void leaveEndPage (unsigned pageno); - void embedFonts (XMLElementNode *svgElement); + void embedFonts (XMLElement *svgElement); void moveRight (double dx, MoveMode mode) override; void moveDown (double dy, MoveMode mode) override; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIToSVGActions.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIToSVGActions.cpp index 226d434bae5..bb8e4d6f845 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIToSVGActions.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIToSVGActions.cpp @@ -32,14 +32,6 @@ using namespace std; -DVIToSVGActions::DVIToSVGActions (DVIToSVG &dvisvg, SVGTree &svg) - : _svg(svg), _dvireader(&dvisvg), _bgcolor(Color::TRANSPARENT) -{ - _currentFontNum = -1; - _pageCount = 0; -} - - void DVIToSVGActions::reset() { _usedChars.clear(); _usedFonts.clear(); @@ -69,17 +61,19 @@ void DVIToSVGActions::moveToY (double y, bool forceSVGMove) { } -string DVIToSVGActions::getSVGFilename (unsigned pageno) const { - if (DVIToSVG *dvi2svg = dynamic_cast<DVIToSVG*>(_dvireader)) - return dvi2svg->getSVGFilename(pageno); - return ""; +FilePath DVIToSVGActions::getSVGFilePath (unsigned pageno) const { + FilePath path; + if (auto dvi2svg = dynamic_cast<DVIToSVG*>(_dvireader)) + path = dvi2svg->getSVGFilePath(pageno); + return path; } string DVIToSVGActions::getBBoxFormatString () const { - if (DVIToSVG *dvi2svg = dynamic_cast<DVIToSVG*>(_dvireader)) - return dvi2svg->getUserBBoxString(); - return ""; + string boxstr; + if (auto dvi2svg = dynamic_cast<DVIToSVG*>(_dvireader)) + boxstr = dvi2svg->getUserBBoxString(); + return boxstr; } @@ -91,6 +85,9 @@ string DVIToSVGActions::getBBoxFormatString () const { * @param[in] vertical true if we're in vertical mode * @param[in] font font to be used */ void DVIToSVGActions::setChar (double x, double y, unsigned c, bool vertical, const Font &font) { + if (_outputLocked) + return; + // If we use SVG fonts there is no need to record all font name/char/size combinations // because the SVG font mechanism handles this automatically. It's sufficient to // record font names and chars. The various font sizes can be ignored here. @@ -108,7 +105,7 @@ void DVIToSVGActions::setChar (double x, double y, unsigned c, bool vertical, co GlyphMetrics metrics; font.getGlyphMetrics(c, vertical, metrics); - const PhysicalFont* pf = dynamic_cast<const PhysicalFont*>(&font); + auto pf = dynamic_cast<const PhysicalFont*>(&font); if (PhysicalFont::EXACT_BBOX && pf) { GlyphMetrics exact_metrics; pf->getExactGlyphBox(c, exact_metrics, vertical, &callback); @@ -125,7 +122,7 @@ void DVIToSVGActions::setChar (double x, double y, unsigned c, bool vertical, co bbox.transform(getMatrix()); embed(bbox); #if 0 - XMLElementNode *rect = new XMLElementNode("rect"); + XMLElement *rect = new XMLElement("rect"); rect->addAttribute("x", x-metrics.wl); rect->addAttribute("y", y-metrics.h); rect->addAttribute("width", metrics.wl+metrics.wr); @@ -135,7 +132,7 @@ void DVIToSVGActions::setChar (double x, double y, unsigned c, bool vertical, co rect->addAttribute("stroke-width", "0.5"); _svg.appendToPage(rect); if (metrics.d > 0) { - XMLElementNode *line = new XMLElementNode("line"); + XMLElement *line = new XMLElement("line"); line->addAttribute("x1", x-metrics.wl); line->addAttribute("y1", y); line->addAttribute("x2", x+metrics.wr); @@ -145,7 +142,7 @@ void DVIToSVGActions::setChar (double x, double y, unsigned c, bool vertical, co _svg.appendToPage(line); } if (metrics.wl > 0) { - XMLElementNode *line = new XMLElementNode("line"); + XMLElement *line = new XMLElement("line"); line->addAttribute("x1", x); line->addAttribute("y1", y-metrics.h); line->addAttribute("x2", x); @@ -165,14 +162,17 @@ void DVIToSVGActions::setChar (double x, double y, unsigned c, bool vertical, co * @param[in] height length of the vertical edges * @param[in] width length of the horizontal edges */ void DVIToSVGActions::setRule (double x, double y, double height, double width) { + if (_outputLocked) + return; + // (x,y) is the lower left corner of the rectangle - auto rect = util::make_unique<XMLElementNode>("rect"); + auto rect = util::make_unique<XMLElement>("rect"); rect->addAttribute("x", x); rect->addAttribute("y", y-height); rect->addAttribute("height", height); rect->addAttribute("width", width); if (!getMatrix().isIdentity()) - rect->addAttribute("transform", getMatrix().getSVG()); + rect->addAttribute("transform", getMatrix().toSVG()); if (getColor() != Color::BLACK) rect->addAttribute("fill", _svg.getColor().svgColorString()); _svg.appendToPage(std::move(rect)); @@ -232,7 +232,7 @@ void DVIToSVGActions::endPage (unsigned pageno) { _svg.transformPage(matrix); if (_bgcolor != Color::TRANSPARENT) { // create a rectangle filled with the background color - auto rect = util::make_unique<XMLElementNode>("rect"); + auto rect = util::make_unique<XMLElement>("rect"); rect->addAttribute("x", _bbox.minX()); rect->addAttribute("y", _bbox.minY()); rect->addAttribute("width", _bbox.width()); @@ -306,7 +306,7 @@ static int digits (int n) { void DVIToSVGActions::progress (size_t current, size_t total, const char *id) { static double time=0; static bool draw=false; // show progress indicator? - static const char *prev_id=0; + static const char *prev_id=nullptr; if (current == 0 && total > 0) { time = System::time(); draw = false; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIToSVGActions.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIToSVGActions.hpp index 04a345865b9..e9adc63e38b 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIToSVGActions.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIToSVGActions.hpp @@ -42,7 +42,7 @@ class DVIToSVGActions : public DVIActions, public SpecialActions { using BoxMap = std::unordered_map<std::string,BoundingBox>; public: - DVIToSVGActions (DVIToSVG &dvisvg, SVGTree &svg); + DVIToSVGActions (DVIToSVG &dvisvg, SVGTree &svg) : _svg(svg), _dvireader(&dvisvg) {} void reset () override; void setChar (double x, double y, unsigned c, bool vertical, const Font &f) override; void setRule (double x, double y, double height, double width) override; @@ -52,32 +52,31 @@ class DVIToSVGActions : public DVIActions, public SpecialActions { const Matrix& getMatrix () const override {return _svg.getMatrix();} Matrix getPageTransformation () const override {return _dvireader->getPageTransformation();} Color getColor () const override {return _svg.getColor();} - int getDVIStackDepth() const override {return _dvireader->stackDepth();} - unsigned getCurrentPageNumber() const override {return _dvireader->currentPageNumber();} - void appendToPage(std::unique_ptr<XMLNode> &&node) override {_svg.appendToPage(std::move(node));} - void appendToDefs(std::unique_ptr<XMLNode> &&node) override {_svg.appendToDefs(std::move(node));} - void prependToPage(std::unique_ptr<XMLNode> &&node) override {_svg.prependToPage(std::move(node));} - void pushContextElement (std::unique_ptr<XMLElementNode> &&node) override {_svg.pushContextElement(std::move(node));} - void popContextElement () override {_svg.popContextElement();} - void setTextOrientation(bool vertical) override {_svg.setVertical(vertical);} + int getDVIStackDepth () const override {return _dvireader->stackDepth();} + unsigned getCurrentPageNumber () const override {return _dvireader->currentPageNumber();} + void setTextOrientation (bool vertical) override {_svg.setVertical(vertical);} void moveToX (double x, bool forceSVGMove) override; void moveToY (double y, bool forceSVGMove) override; void setFont (int num, const Font &font) override; void special (const std::string &spc, double dvi2bp, bool preprocessing=false) override; void beginPage (unsigned pageno, const std::vector<int32_t> &c) override; void endPage (unsigned pageno) override; - void progress (size_t current, size_t total, const char *id=0) override; + void progress (size_t current, size_t total, const char *id=nullptr) override; void progress (const char *id) override; double getX() const override {return _dvireader->getXPos();} double getY() const override {return _dvireader->getYPos();} void setX (double x) override {_dvireader->translateToX(x); _svg.setX(x);} void setY (double y) override {_dvireader->translateToY(y); _svg.setY(y);} void finishLine () override {_dvireader->finishLine();} + void lockOutput () override {_outputLocked = true;} + void unlockOutput () override {_outputLocked = false;} + bool outputLocked () const override {return _outputLocked;} + const SVGTree& svgTree () const override {return _svg;} BoundingBox& bbox () override {return _bbox;} BoundingBox& bbox (const std::string &name, bool reset=false) override; void embed (const BoundingBox &bbox) override; void embed (const DPair &p, double r=0) override; - std::string getSVGFilename (unsigned pageno) const override; + FilePath getSVGFilePath (unsigned pageno) const override; std::string getBBoxFormatString () const override; CharMap& getUsedChars () const {return _usedChars;} const FontSet& getUsedFonts () const {return _usedFonts;} @@ -87,12 +86,13 @@ class DVIToSVGActions : public DVIActions, public SpecialActions { SVGTree &_svg; BasicDVIReader *_dvireader; BoundingBox _bbox; - int _pageCount; - int _currentFontNum; + int _pageCount=0; + int _currentFontNum=-1; mutable CharMap _usedChars; FontSet _usedFonts; - Color _bgcolor; + Color _bgcolor=Color::TRANSPARENT; BoxMap _boxes; + bool _outputLocked=false; }; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/Directory.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/Directory.cpp index beb6f887da6..ccc05a2e92c 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/Directory.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/Directory.cpp @@ -25,7 +25,7 @@ using namespace std; #ifdef _WIN32 #include "windows.hpp" #else - #include <errno.h> + #include <cerrno> #include <sys/stat.h> #endif diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/Directory.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/Directory.hpp index ade36daf80d..a703c18977c 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/Directory.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/Directory.hpp @@ -34,7 +34,7 @@ class Directory { public: Directory (); - Directory (const std::string &path); + explicit Directory (const std::string &path); ~Directory (); bool open (std::string path); void close (); diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/DvisvgmSpecialHandler.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/DvisvgmSpecialHandler.cpp index 23e9b7107c7..dadf196f779 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/DvisvgmSpecialHandler.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/DvisvgmSpecialHandler.cpp @@ -26,6 +26,7 @@ #include "InputReader.hpp" #include "Length.hpp" #include "SpecialActions.hpp" +#include "SVGTree.hpp" #include "utility.hpp" #include "XMLNode.hpp" #include "XMLString.hpp" @@ -33,8 +34,10 @@ using namespace std; -DvisvgmSpecialHandler::DvisvgmSpecialHandler () - : _currentMacro(_macros.end()), _nestingLevel(0) +DvisvgmSpecialHandler::DvisvgmSpecialHandler () : + _currentMacro(_macros.end()), + _defsParser(&SVGTree::appendToDefs, &SVGTree::pushDefsContext, &SVGTree::popDefsContext), + _pageParser(&SVGTree::appendToPage, &SVGTree::pushPageContext, &SVGTree::popPageContext) { } @@ -54,12 +57,12 @@ void DvisvgmSpecialHandler::preprocess (const string&, istream &is, SpecialActio StreamInputReader ir(is); const string cmdstr = ir.getWord(); - for (const Command &command : commands) { - if (command.name == cmdstr) { - ir.skipSpace(); - (this->*command.handler)(ir); - return; - } + auto it = find_if(commands.begin(), commands.end(), [&](const Command &cmd) { + return cmd.name == cmdstr; + }); + if (it != commands.end()) { + ir.skipSpace(); + (this->*it->handler)(ir); } } @@ -133,12 +136,12 @@ bool DvisvgmSpecialHandler::process (const string &prefix, istream &is, SpecialA }}; StreamInputReader ir(is); const string cmdstr = ir.getWord(); - for (const Command &command : commands) { - if (command.name == cmdstr) { - ir.skipSpace(); - (this->*command.handler)(ir, actions); - return true; - } + auto it = find_if(commands.begin(), commands.end(), [&](const Command &cmd) { + return cmd.name == cmdstr; + }); + if (it != commands.end()) { + ir.skipSpace(); + (this->*it->handler)(ir, actions); } return true; } @@ -169,10 +172,11 @@ static void expand_constants (string &str, SpecialActions &actions) { const char *name; string val; }; - const array<Constant, 4> constants {{ - {"x", XMLString(actions.getX())}, - {"y", XMLString(actions.getY())}, - {"color", actions.getColor().svgColorString()}, + const array<Constant, 5> constants {{ + {"x", XMLString(actions.getX())}, + {"y", XMLString(actions.getY())}, + {"color", actions.getColor().svgColorString()}, + {"matrix", actions.getMatrix().toSVG()}, {"nl", "\n"}, }}; for (const Constant &constant : constants) { @@ -186,12 +190,17 @@ static void expand_constants (string &str, SpecialActions &actions) { } +/** Processes raw SVG fragments from the input stream. The SVG data must represent + * a single or multiple syntactically complete XML parts, like opening/closing tags, + * comments, or CDATA blocks. These must not be split and distributed over several + * 'raw' statements. Elements can be split but element tags can't. + * Example: "<g transform=" is invalid, "<g transform='scale(2,3)'>" is ok. */ void DvisvgmSpecialHandler::processRaw (InputReader &ir, SpecialActions &actions) { if (_nestingLevel == 0) { - string str = ir.getLine(); - if (!str.empty()) { - expand_constants(str, actions); - actions.appendToPage(util::make_unique<XMLTextNode>(str)); + string xml = ir.getLine(); + if (!xml.empty()) { + expand_constants(xml, actions); + _pageParser.parse(xml, actions); } } } @@ -199,10 +208,10 @@ void DvisvgmSpecialHandler::processRaw (InputReader &ir, SpecialActions &actions void DvisvgmSpecialHandler::processRawDef (InputReader &ir, SpecialActions &actions) { if (_nestingLevel == 0) { - string str = ir.getLine(); - if (!str.empty()) { - expand_constants(str, actions); - actions.appendToDefs(util::make_unique<XMLTextNode>(str)); + string xml = ir.getLine(); + if (!xml.empty()) { + expand_constants(xml, actions); + _defsParser.parse(xml, actions); } } } @@ -234,9 +243,9 @@ void DvisvgmSpecialHandler::processRawPut (InputReader &ir, SpecialActions &acti if ((type == 'P' || type == 'D') && !def.empty()) { expand_constants(def, actions); if (type == 'P') - actions.appendToPage(util::make_unique<XMLTextNode>(def)); + _pageParser.parse(def, actions); else { // type == 'D' - actions.appendToDefs(util::make_unique<XMLTextNode>(def)); + _defsParser.parse(def, actions); type = 'L'; // locked } } @@ -249,70 +258,92 @@ void DvisvgmSpecialHandler::processRawPut (InputReader &ir, SpecialActions &acti * @param[in] w width of the rectangle in PS point units * @param[in] h height of the rectangle in PS point units * @param[in] d depth of the rectangle in PS point units + * @param[in] transform if true, apply the current transformation matrix to the rectangle * @param[in] actions object providing the actions that can be performed by the SpecialHandler */ -static void update_bbox (Length w, Length h, Length d, SpecialActions &actions) { +static void update_bbox (Length w, Length h, Length d, bool transform, SpecialActions &actions) { double x = actions.getX(); double y = actions.getY(); - actions.embed(BoundingBox(x, y, x+w.bp(), y-h.bp())); - actions.embed(BoundingBox(x, y, x+w.bp(), y+d.bp())); + BoundingBox bbox1(x, y, x+w.bp(), y-h.bp()); + BoundingBox bbox2(x, y, x+w.bp(), y+d.bp()); + if (transform) { + bbox1.transform(actions.getMatrix()); + bbox2.transform(actions.getMatrix()); + } + actions.embed(bbox1); + actions.embed(bbox2); } /** Reads a length value including a trailing unit specifier and returns it. */ static Length read_length (InputReader &ir) { + Length length; ir.skipSpace(); - double val = ir.getDouble(); - string unit = isalpha(ir.peek()) ? ir.getString(2) : "pt"; - return Length(val, unit); + if (!isalpha(ir.peek())) { + double val = ir.getDouble(); + string unit = isalpha(ir.peek()) ? ir.getString(2) : "pt"; + length = Length(val, unit); + } + return length; } /** Evaluates the special dvisvgm:bbox. - * variant 1: dvisvgm:bbox [r[el]] <width> <height> [<depth>] - * variant 2: dvisvgm:bbox a[bs] <x1> <y1> <x2> <y2> - * variant 3: dvisvgm:bbox f[ix] <x1> <y1> <x2> <y2> - * variant 4: dvisvgm:bbox n[ew] <name> */ + * variant 1: dvisvgm:bbox [r[el]] <width> <height> [<depth>] [transform] + * variant 2: dvisvgm:bbox a[bs] <x1> <y1> <x2> <y2> [transform] + * variant 3: dvisvgm:bbox f[ix] <x1> <y1> <x2> <y2> [transform] + * variant 4: dvisvgm:bbox n[ew] <name> + * variant 5: dvisvgm:bbox lock | unlock */ void DvisvgmSpecialHandler::processBBox (InputReader &ir, SpecialActions &actions) { ir.skipSpace(); - int c = ir.peek(); - try { - if (!isalpha(c)) - c = 'r'; // no mode specifier => relative box parameters - else { - while (!isspace(ir.peek())) // skip trailing characters - ir.get(); - if (c == 'n') { // "new": create new local bounding box - ir.skipSpace(); - string name; - while (isalnum(ir.peek())) - name += char(ir.get()); - ir.skipSpace(); - if (!name.empty() && ir.eof()) - actions.bbox(name, true); // create new user box - } - else if (c == 'a' || c == 'f') { // "abs" or "fix" - Length lengths[4]; - for (int i=0; i < 4; i++) - lengths[i] = read_length(ir); - BoundingBox b(lengths[0], lengths[1], lengths[2], lengths[3]); - if (c == 'a') - actions.embed(b); - else { - actions.bbox() = b; - actions.bbox().lock(); + if (ir.check("lock")) + actions.bbox().lock(); + else if (ir.check("unlock")) + actions.bbox().unlock(); + else { + int c = ir.peek(); + try { + if (!isalpha(c)) + c = 'r'; // no mode specifier => relative box parameters + else { + while (!isspace(ir.peek())) // skip trailing characters + ir.get(); + if (c == 'n') { // "new": create new local bounding box + ir.skipSpace(); + string name; + while (isalnum(ir.peek())) + name += char(ir.get()); + ir.skipSpace(); + if (!name.empty() && ir.eof()) + actions.bbox(name, true); // create new user box } + else if (c == 'a' || c == 'f') { // "abs" or "fix" + Length lengths[4]; + for (Length &len : lengths) + len = read_length(ir); + BoundingBox b(lengths[0], lengths[1], lengths[2], lengths[3]); + ir.skipSpace(); + if (ir.check("transform")) + b.transform(actions.getMatrix()); + if (c == 'a') + actions.embed(b); + else { + actions.bbox() = b; + actions.bbox().lock(); + } + } + } + if (c == 'r') { + Length w = read_length(ir); + Length h = read_length(ir); + Length d = read_length(ir); + ir.skipSpace(); + update_bbox(w, h, d, ir.check("transform"), actions); } } - if (c == 'r') { - Length w = read_length(ir); - Length h = read_length(ir); - Length d = read_length(ir); - update_bbox(w, h, d, actions); + catch (const UnitException &e) { + throw SpecialException(string("dvisvgm:bbox: ") + e.what()); } } - catch (const UnitException &e) { - throw SpecialException(string("dvisvgm:bbox: ") + e.what()); - } } @@ -321,16 +352,16 @@ void DvisvgmSpecialHandler::processImg (InputReader &ir, SpecialActions &actions Length w = read_length(ir); Length h = read_length(ir); string f = ir.getString(); - update_bbox(w, h, 0, actions); - auto img = util::make_unique<XMLElementNode>("image"); + update_bbox(w, h, Length(0), false, actions); + auto img = util::make_unique<XMLElement>("image"); img->addAttribute("x", actions.getX()); img->addAttribute("y", actions.getY()); img->addAttribute("width", w.bp()); img->addAttribute("height", h.bp()); img->addAttribute("xlink:href", f); if (!actions.getMatrix().isIdentity()) - img->addAttribute("transform", actions.getMatrix().getSVG()); - actions.appendToPage(std::move(img)); + img->addAttribute("transform", actions.getMatrix().toSVG()); + actions.svgTree().appendToPage(std::move(img)); } catch (const UnitException &e) { throw SpecialException(string("dvisvgm:img: ") + e.what()); @@ -350,7 +381,10 @@ void DvisvgmSpecialHandler::dviPreprocessingFinished () { } -void DvisvgmSpecialHandler::dviEndPage (unsigned, SpecialActions&) { +void DvisvgmSpecialHandler::dviEndPage (unsigned, SpecialActions &actions) { + _defsParser.flush(actions); + _pageParser.flush(actions); + actions.bbox().unlock(); for (auto &strvecpair : _macros) { StringVector &vec = strvecpair.second; for (string &str : vec) { @@ -366,3 +400,140 @@ vector<const char*> DvisvgmSpecialHandler::prefixes() const { vector<const char*> pfx {"dvisvgm:"}; return pfx; } + +//////////////////////////////////////////////////////////////////////////////// + +/** Parses a fragment of XML code, creates corresponding XML nodes and adds them + * to the SVG tree. The code may be split and processed by several calls of this + * function. Incomplete chunks that can't be processed yet are stored and picked + * up again together with the next incoming XML fragment. If no further code should + * be appended, parameter 'finish' must be set. + * @param[in] xml XML fragment to parse + * @param[in] actions object providing the SVG tree functions + * @param[in] finish if true, no more XML is expected and parsing is finished */ +void DvisvgmSpecialHandler::XMLParser::parse (const string &xml, SpecialActions &actions, bool finish) { + // collect/extract an XML fragment that only contains complete tags + // incomplete tags are held back + _xmlbuf += xml; + size_t left=0, right; + while (left != string::npos) { + right = _xmlbuf.find('<', left); + if (left < right && left < _xmlbuf.length()) // plain text found? + (actions.svgTree().*_append)(util::make_unique<XMLText>(_xmlbuf.substr(left, right-left))); + if (right != string::npos) { + left = right; + if (_xmlbuf.compare(left, 9, "<![CDATA[") == 0) { + right = _xmlbuf.find("]]>", left+9); + if (right == string::npos) { + if (finish) throw SpecialException("expected ']]>' at end of CDATA block"); + break; + } + (actions.svgTree().*_append)(util::make_unique<XMLCData>(_xmlbuf.substr(left+9, right-left-9))); + right += 2; + } + else if (_xmlbuf.compare(left, 4, "<!--") == 0) { + right = _xmlbuf.find("-->", left+4); + if (right == string::npos) { + if (finish) throw SpecialException("expected '-->' at end of comment"); + break; + } + (actions.svgTree().*_append)(util::make_unique<XMLComment>(_xmlbuf.substr(left+4, right-left-4))); + right += 2; + } + else if (_xmlbuf.compare(left, 2, "<?") == 0) { + right = _xmlbuf.find("?>", left+2); + if (right == string::npos) { + if (finish) throw SpecialException("expected '?>' at end of processing instruction"); + break; + } + (actions.svgTree().*_append)(util::make_unique<XMLText>(_xmlbuf.substr(left, right-left+2))); + right++; + } + else if (_xmlbuf.compare(left, 2, "</") == 0) { + right = _xmlbuf.find('>', left+2); + if (right == string::npos) { + if (finish) throw SpecialException("missing '>' at end of closing XML tag"); + break; + } + closeElement(_xmlbuf.substr(left+2, right-left-2), actions); + } + else { + right = _xmlbuf.find('>', left+1); + if (right == string::npos) { + if (finish) throw SpecialException("missing '>' or '/>' at end of opening XML tag"); + break; + } + openElement(_xmlbuf.substr(left+1, right-left-1), actions); + } + } + left = right; + if (right != string::npos) + left++; + } + if (left == string::npos) + _xmlbuf.clear(); + else + _xmlbuf.erase(0, left); +} + + +/** Processes an opening element tag. + * @param[in] tag tag without leading and trailing angle brackets */ +void DvisvgmSpecialHandler::XMLParser::openElement (const string &tag, SpecialActions &actions) { + StringInputBuffer ib(tag); + BufferInputReader ir(ib); + string name = ir.getString("/ \t\n\r"); + ir.skipSpace(); + auto elemNode = util::make_unique<XMLElement>(name); + map<string, string> attribs; + if (ir.parseAttributes(attribs, true, "\"'")) { + for (const auto &attrpair : attribs) + elemNode->addAttribute(attrpair.first, attrpair.second); + } + ir.skipSpace(); + if (ir.peek() == '/') // end of empty element tag + (actions.svgTree().*_append)(std::move(elemNode)); + else if (ir.peek() < 0) { // end of opening tag + _nameStack.push_back(name); + (actions.svgTree().*_pushContext)(std::move(elemNode)); + } + else + throw SpecialException("'>' or '/>' expected at end of opening tag <"+name); +} + + +/** Processes a closing element tag. + * @param[in] tag tag without leading and trailing angle brackets */ +void DvisvgmSpecialHandler::XMLParser::closeElement (const string &tag, SpecialActions &actions) { + StringInputBuffer ib(tag); + BufferInputReader ir(ib); + string name = ir.getString(" \t\n\r"); + ir.skipSpace(); + if (ir.peek() >= 0) + throw SpecialException("'>' expected at end of closing tag </"+name); + if (_nameStack.empty()) + throw SpecialException("spurious closing tag </" + name + ">"); + if (_nameStack.back() != name) + throw SpecialException("expected </" + name + "> but found </" + _nameStack.back() + ">"); + (actions.svgTree().*_popContext)(); + _nameStack.pop_back(); +} + + +/** Processes any remaining XML fragments, checks for missing closing tags, + * and resets the parser state. */ +void DvisvgmSpecialHandler::XMLParser::flush (SpecialActions &actions) { + if (!_xmlbuf.empty()) { + parse("", actions, true); + _xmlbuf.clear(); + } + string tags; + while (!_nameStack.empty()) { + tags += "</"+_nameStack.back()+">, "; + _nameStack.pop_back(); + } + if (!tags.empty()) { + tags.resize(tags.length()-2); + throw SpecialException("missing closing tags: "+tags); + } +}
\ No newline at end of file diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/DvisvgmSpecialHandler.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/DvisvgmSpecialHandler.hpp index 3a72b04f931..a8bde952e6f 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/DvisvgmSpecialHandler.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/DvisvgmSpecialHandler.hpp @@ -21,6 +21,7 @@ #ifndef DVISVGMSPECIALHANDLER_HPP #define DVISVGMSPECIALHANDLER_HPP +#include <memory> #include <string> #include <unordered_map> #include <vector> @@ -28,8 +29,44 @@ class InputReader; class SpecialActions; +class SVGTree; +class XMLElement; +class XMLNode; + +#ifdef _MSC_VER +// MSVC: Prevent aggressive optimization of pointers to member functions. +// Instatiating class DvisvgmSpecialHandler without the following pragma +// leads to memory corruption. +// https://docs.microsoft.com/en-us/cpp/preprocessor/pointers-to-members +#pragma pointers_to_members(full_generality, single_inheritance) +#endif class DvisvgmSpecialHandler : public SpecialHandler { + class XMLParser { + using AppendFunc = void (SVGTree::*)(std::unique_ptr<XMLNode>); + using PushFunc = void (SVGTree::*)(std::unique_ptr<XMLElement>); + using PopFunc = void (SVGTree::*)(); + using NameStack = std::vector<std::string>; + + public: + XMLParser (AppendFunc append, PushFunc push, PopFunc pop) + : _append(append), _pushContext(push), _popContext(pop) {} + + void parse (const std::string &xml, SpecialActions &actions, bool finish=false); + void flush (SpecialActions &actions); + + protected: + void openElement (const std::string &tag, SpecialActions &actions); + void closeElement (const std::string &tag, SpecialActions &actions); + + private: + AppendFunc _append; + PushFunc _pushContext; + PopFunc _popContext; + std::string _xmlbuf; + NameStack _nameStack; ///< names of nested elements still missing a closing tag + }; + using StringVector = std::vector<std::string>; using MacroMap = std::unordered_map<std::string, StringVector>; @@ -60,7 +97,9 @@ class DvisvgmSpecialHandler : public SpecialHandler { private: MacroMap _macros; MacroMap::iterator _currentMacro; - int _nestingLevel; + int _nestingLevel=0; ///< nesting depth of rawset specials + XMLParser _defsParser; ///< parses XML added by 'rawdef' specials + XMLParser _pageParser; ///< parses XML added by 'raw' specials }; #endif diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/EPSFile.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/EPSFile.cpp index 21b1967fc6f..5a5fccc08f4 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/EPSFile.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/EPSFile.cpp @@ -18,6 +18,7 @@ ** along with this program; if not, see <http://www.gnu.org/licenses/>. ** *************************************************************************/ +#include <array> #include <cstring> #include <istream> #include <limits> @@ -66,8 +67,8 @@ EPSFile::EPSFile (const string &fname) : _ifs(fname, ios::binary) { _ifs.seekg(_offset); // continue reading at the beginning of the PS section } string str; - str += _ifs.get(); - str += _ifs.get(); + str += char(_ifs.get()); + str += char(_ifs.get()); _headerValid = (str == "%!"); _ifs.seekg(0); } @@ -98,12 +99,12 @@ BoundingBox EPSFile::bbox () const { ir.skip(14); ir.skipSpace(); if (!ir.check("(atend)", true)) { - int val[4]; - for (int i=0; i < 4; i++) { + array<int, 4> values; + for (int &v : values) { ir.skipSpace(); - ir.parseInt(val[i]); + ir.parseInt(v); } - box = BoundingBox(val[0], val[1], val[2], val[3]); + box = BoundingBox(values[0], values[1], values[2], values[3]); break; } } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/EPSFile.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/EPSFile.hpp index 713aecb2395..4fdd03ee1b3 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/EPSFile.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/EPSFile.hpp @@ -28,7 +28,7 @@ class EPSFile { public: - EPSFile (const std::string &fname); + explicit EPSFile (const std::string &fname); std::istream& istream () const; bool hasValidHeader () const {return _headerValid;} BoundingBox bbox () const; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/EllipticalArc.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/EllipticalArc.cpp new file mode 100644 index 00000000000..b820af00523 --- /dev/null +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/EllipticalArc.cpp @@ -0,0 +1,260 @@ +/************************************************************************* +** EllipticalArc.cpp ** +** ** +** This file is part of dvisvgm -- a fast DVI to SVG converter ** +** Copyright (C) 2005-2019 Martin Gieseking <martin.gieseking@uos.de> ** +** ** +** 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 <http://www.gnu.org/licenses/>. ** +*************************************************************************/ + +#include <cmath> +#include "EllipticalArc.hpp" +#include "utility.hpp" + +using namespace std; + + +/** Constructs an elliptical arc from end point parameterization. + * @param[in] start start point of arc + * @param[in] rx length of semi-major axis + * @param[in] ry length of semi-minor axis + * @param[in] angle rotation of ellipse around its center (in radians) + * @param[in] laf if true, choose the larger arc between start and end point + * @param[in] sweep if true, arc is drawn in the direction of increasing angles + * @param[in] end end point of the arc */ +EllipticalArc::EllipticalArc (const DPair &start, double rx, double ry, double angle, bool laf, bool sweep, const DPair &end) + : _rx(abs(rx)), _ry(abs(ry)), _rotationAngle(math::normalize_angle(angle, math::PI)), + _largeArc(laf), _sweepPositive(sweep), _startPoint(start), _endPoint(end) +{ + if (!isStraightLine()) { + // fix out-of-range radii according to section F.6.6.3 in + // https://www.w3.org/TR/SVG/implnote.html#ArcCorrectionOutOfRangeRadii + double c = cos(_rotationAngle); + double s = sin(_rotationAngle); + DPair p = (_startPoint-_endPoint)/2.0; + p = DPair(c*p.x()+s*p.y(), c*p.y()-s*p.x()); + double lambda = (p.x()*p.x())/(_rx*_rx) + (p.y()*p.y())/(_ry*_ry); + if (lambda > 1) { + lambda = sqrt(lambda); + _rx *= lambda; + _ry *= lambda; + } + } +} + + +/** Constructs an elliptical arc from center parameterization + * @param[in] center absolute coordinates of the center of the ellipse + * @param[in] rx length of semi-major axis + * @param[in] ry length of semi-minor axis + * @param[in] rot rotation of ellipse around its center (in radians) + * @param[in] startAngle angle between major axis and vector from center to start point + * @param[in] deltaAngle angle between the vectors from center to start and end point, respectively */ +EllipticalArc::EllipticalArc (const DPair ¢er, double rx, double ry, double rot, double startAngle, double deltaAngle) + : _rx(rx), _ry(ry), _rotationAngle(math::normalize_angle(rot, math::TWO_PI)), + _largeArc(abs(deltaAngle) > math::PI), _sweepPositive(deltaAngle > 0) +{ + // https://www.w3.org/TR/SVG/implnote.html#ArcConversionCenterToEndpoint + double c = cos(_rotationAngle); + double s = sin(_rotationAngle); + double c1 = cos(startAngle); + double s1 = sin(startAngle); + double c2 = cos(startAngle+deltaAngle); + double s2 = sin(startAngle+deltaAngle); + _startPoint = DPair(c*rx*c1*c - s*ry*s1, s*rx*c1 + c*ry*s1) + center; + _endPoint = DPair(c*rx*c2*c - s*ry*s2, s*rx*c2 + c*ry*s2) + center; +} + + +/** Returns the angle between (1, 0) and a given vector. + * The angle is normalized to the range [0, 2pi). */ +static inline double angle (const DPair &p) { + return math::normalize_0_2pi(atan2(p.y(), p.x())); +} + + +/** Computes the center parameterization of the arc. */ +EllipticalArc::CenterParams EllipticalArc::getCenterParams () const { + EllipticalArc::CenterParams params; + if (isStraightLine()) { + params.center = (_endPoint-_startPoint)/2.0; + params.startAngle = params.deltaAngle = 0; + } + else { + // https://www.w3.org/TR/SVG/implnote.html#ArcConversionEndpointToCenter + double c = cos(_rotationAngle); + double s = sin(_rotationAngle); + DPair p = (_startPoint-_endPoint)/2.0; + p = DPair(c*p.x()+s*p.y(), c*p.y()-s*p.x()); + double rx2 = _rx*_rx, ry2 = _ry*_ry; + double px2 = p.x()*p.x(), py2 = p.y()*p.y(); + double radicand = rx2*ry2 - rx2*py2 - ry2*px2; + if (radicand < 0) // should not happen if out-of-range radii were fixed correctly + radicand = 0; + else + radicand /= rx2*py2 + ry2*px2; + double root = sqrt(radicand) * (_largeArc == _sweepPositive ? -1 : 1); + DPair cp(root*p.y()*_rx/_ry, -root*p.x()*_ry/_rx); + DPair mid = (_startPoint+_endPoint)/2.0; + params.center = DPair(c*cp.x() - s*cp.y() + mid.x(), s*cp.x() + c*cp.y() + mid.y()); + DPair q1((p.x() - cp.x())/_rx, (p.y() - cp.y())/_ry); + DPair q2(-(p.x() + cp.x())/_rx, -(p.y() + cp.y())/_ry); + params.startAngle = angle(q1); + params.deltaAngle = angle(q2) - params.startAngle; + if (_sweepPositive && params.deltaAngle < 0) + params.deltaAngle += math::TWO_PI; + else if (!_sweepPositive && params.deltaAngle > 0) + params.deltaAngle -= math::TWO_PI; + } + return params; +} + + +/** Applies the affine transformation described by a given matrix to the arc. */ +void EllipticalArc::transform (const Matrix &matrix) { + double c = cos(_rotationAngle); + double s = sin(_rotationAngle); + Matrix ellipse({_rx*c, -_ry*s, 0, _rx*s, _ry*c}); // E := rotate(xrot)*scale(rx, ry) + ellipse.lmultiply(matrix); // E':= M*E + // Compute the singular value decomposition of the transformed ellipse shape: + // E' = rotate(phi)*scale(sx, sy)*rotate(theta) + // The initial, right-hand rotation can be ignored because it rotates the unit circle + // around the origin, i.e. rotate(theta) maps the circle to itself. + // The signs of sx and sy don't matter either. They just flip the yet unrotated + // ellipse on the x- and/or y-axis. Thus, |sx| and |sy| are the new radii, + // and phi the new rotation angle. + auto vec = math::svd({{ellipse.get(0,0), ellipse.get(0,1)}, {ellipse.get(1,0), ellipse.get(1,1)}}); + if (std::abs(vec[1]-vec[2]) < 1e-7) { // circle? + _rx = _ry = vec[1]; // always >= 0 + _rotationAngle = 0; + } + else { + _rx = vec[1]; // always >= 0 + _ry = abs(vec[2]); // ensure >= 0 + _rotationAngle = math::normalize_angle(vec[0], math::HALF_PI); + } + // change drawing direction (clockwise vs. counter-clockwise) if 'matrix' + // flipped the ellipse horizontally or vertically but not both + if ((matrix.get(0, 0) < 0) != (matrix.get(1, 1) < 0)) + _sweepPositive = !_sweepPositive; + _startPoint = matrix * _startPoint; + _endPoint = matrix * _endPoint; +} + + +/** Approximates an arc of the unit circle by a single cubic Bézier curve. + * @param[in] phi start angle of the arc in radians + * @param[in] delta length of the arc */ +static Bezier approx_unit_arc (double phi, double delta) { + double c = 0.551915024494; // see http://spencermortensen.com/articles/bezier-circle + if (abs(delta + math::HALF_PI) < 1e-7) + c = -c; + else + c = 4.0/3*tan(delta/4); + DPair p1(cos(phi), sin(phi)); + DPair p4(cos(phi+delta), sin(phi+delta)); + DPair p2(p1.x()-c*p1.y(), p1.y()+c*p1.x()); + DPair p3(p4.x()+c*p4.y(), p4.y()-c*p4.x()); + return Bezier(p1, p2, p3, p4); +} + + +/** Approximates the arc by a sequence of cubic Bézier curves. */ +vector<Bezier> EllipticalArc::approximate () const { + vector<Bezier> beziers; + if (_startPoint != _endPoint) { + if (isStraightLine()) { + DPair dir = (_endPoint - _startPoint); + dir /= dir.length()/3.0; + beziers.emplace_back(Bezier(_startPoint, _startPoint+dir, _endPoint-dir, _endPoint)); + } + else { + CenterParams cparams = getCenterParams(); + int numCurves = ceil(cparams.deltaAngle/math::HALF_PI); + double remainder = abs(fmod(cparams.deltaAngle, math::HALF_PI)); + if (remainder < 1e-7) + numCurves--; + else if (math::HALF_PI-remainder < 1e-7) + numCurves++; + if (numCurves > 0) { + double c = cos(_rotationAngle); + double s = sin(_rotationAngle); + Matrix ellipse = {_rx*c, -_ry*s, cparams.center.x(), _rx*s, _ry*c, cparams.center.y()}; + double angle = cparams.startAngle; + double diff = cparams.deltaAngle/numCurves; + while (numCurves-- > 0) { + beziers.emplace_back(approx_unit_arc(angle, diff).transform(ellipse)); + angle += diff; + } + } + } + } + return beziers; +} + + +static inline bool is_angle_between (double t, double angle1, double angle2) { + if (angle1 < angle2) + return angle1 < t && t < angle2; + return angle2 > t || t > angle1; +} + + +/** Returns the tight bounding box of the arc. */ +BoundingBox EllipticalArc::getBBox () const { + BoundingBox bbox; + bbox.embed(_startPoint); + bbox.embed(_endPoint); + if (!isStraightLine()) { + // compute extremes of ellipse centered at the origin + double c = cos(_rotationAngle); + double s = sin(_rotationAngle); + double tx1 = math::normalize_0_2pi(-atan2(_ry*s, _rx*c)); // position of vertical tangent, d/dt E(tx1)=(0, y) + double tx2 = math::normalize_0_2pi(math::PI+tx1); // position of second vertical tangent + double ct = cos(tx1); + double st = sin(tx1); + DPair pv1(_rx*c*ct - _ry*s*st, _rx*s*ct + _ry*c*st); // E(tx1), 1st point on ellipse with vertical tangent + DPair pv2 = -pv1; // E(tx2), 2nd point on ellipse with vertical tangent + + double ty1 = math::normalize_0_2pi(atan2(_ry*c, _rx*s)); // position of horizontal tangent, d/dt E(ty1)=(x, 0) + double ty2 = math::normalize_0_2pi(math::PI+ty1); // position of second horizontal tangent + ct = cos(ty1); + st = sin(ty1); + DPair ph1(_rx*c*ct - _ry*s*st, _rx*s*ct + _ry*c*st); // E(ty1), 1st point on ellipse with horizontal tangent + DPair ph2 = -ph1; // E(ty2), 2nd point on ellipse with horizontal tangent + + // translate extreme points to actual coordinates + CenterParams cparams = getCenterParams(); + pv1 += cparams.center; + pv2 += cparams.center; + ph1 += cparams.center; + ph2 += cparams.center; + + double angle1 = cparams.startAngle; + double angle2 = math::normalize_0_2pi(angle1+cparams.deltaAngle); + if (!_sweepPositive) + swap(angle1, angle2); + + // only consider extreme points located on the arc + if (is_angle_between(tx1, angle1, angle2)) + bbox.embed(pv1); + if (is_angle_between(tx2, angle1, angle2)) + bbox.embed(pv2); + if (is_angle_between(ty1, angle1, angle2)) + bbox.embed(ph1); + if (is_angle_between(ty2, angle1, angle2)) + bbox.embed(ph2); + } + return bbox; +} diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/EllipticalArc.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/EllipticalArc.hpp new file mode 100644 index 00000000000..5d205581967 --- /dev/null +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/EllipticalArc.hpp @@ -0,0 +1,59 @@ +/************************************************************************* +** EllipticalArc.hpp ** +** ** +** This file is part of dvisvgm -- a fast DVI to SVG converter ** +** Copyright (C) 2005-2019 Martin Gieseking <martin.gieseking@uos.de> ** +** ** +** 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 <http://www.gnu.org/licenses/>. ** +*************************************************************************/ + +#pragma once + +#include "Bezier.hpp" +#include "BoundingBox.hpp" +#include "Matrix.hpp" +#include "Pair.hpp" + +class EllipticalArc { + public: + struct CenterParams { + DPair center; ///< absolute coordinates of the center point + double startAngle; ///< angle of start point relative to semi-major axis (in radians) + double deltaAngle; ///< difference between angles of the start and end point (>0 if sweep flag is set) + }; + + public: + EllipticalArc (const DPair &start, double rx, double ry, double angle, bool laf, bool sweep, const DPair &end); + EllipticalArc (const DPair ¢er, double rx, double ry, double rot, double startAngle, double deltaAngle); + CenterParams getCenterParams () const; + double rx () const {return _rx;} + double ry () const {return _ry;} + bool largeArc () const {return _largeArc;} + bool sweepPositive () const {return _sweepPositive;} + double rotationAngle () const {return _rotationAngle;} + DPair startPoint () const {return _startPoint;} + DPair endPoint () const {return _endPoint;} + bool isStraightLine () const {return _rx < 1e-7 || _ry < 1e-7;} + BoundingBox getBBox () const; + void transform (const Matrix &matrix); + std::vector<Bezier> approximate () const; + + private: + double _rx, _ry; ///< length of semi-major and semi-minor axes + double _rotationAngle; ///< rotation angle around center (in radians) + bool _largeArc; ///< if true, the longer arc from start to end point is chosen, else the shorter one + bool _sweepPositive; ///< if true, arc is drawn in direction of positive angles, else the opposite direction + DPair _startPoint, _endPoint; ///< absolute coordinates of start and end point +}; + diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/EmSpecialHandler.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/EmSpecialHandler.cpp index f2725ad1fa2..c93a798fd74 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/EmSpecialHandler.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/EmSpecialHandler.cpp @@ -24,16 +24,13 @@ #include "InputReader.hpp" #include "Length.hpp" #include "SpecialActions.hpp" +#include "SVGTree.hpp" #include "XMLNode.hpp" #include "XMLString.hpp" using namespace std; -EmSpecialHandler::EmSpecialHandler () : _linewidth(0.4*72/72.27) { -} - - /** Computes the "cut vector" that is used to compute the line shape. * Because each line has a width > 0 the actual shape of the line is a tetragon. * The 4 vertices can be influenced by the cut parameter c that specifies @@ -78,11 +75,13 @@ static DPair cut_vector (char cuttype, const DPair &linedir, double linewidth) { * @param[in] lw line width in PS point units * @param[in] actions object providing the actions that can be performed by the SpecialHandler */ static void create_line (const DPair &p1, const DPair &p2, char c1, char c2, double lw, SpecialActions &actions) { - unique_ptr<XMLElementNode> node; + if (actions.outputLocked()) + return; + unique_ptr<XMLElement> node; DPair dir = p2-p1; if (dir.x() == 0 || dir.y() == 0 || (c1 == 'p' && c2 == 'p')) { // draw regular line - node = util::make_unique<XMLElementNode>("line"); + node = util::make_unique<XMLElement>("line"); node->addAttribute("x1", p1.x()); node->addAttribute("y1", p1.y()); node->addAttribute("x2", p2.x()); @@ -107,7 +106,7 @@ static void create_line (const DPair &p1, const DPair &p2, char c1, char c2, dou << XMLString(q12.x()) << ',' << XMLString(q12.y()) << ' ' << XMLString(q22.x()) << ',' << XMLString(q22.y()) << ' ' << XMLString(q21.x()) << ',' << XMLString(q21.y()); - node = util::make_unique<XMLElementNode>("polygon"); + node = util::make_unique<XMLElement>("polygon"); node->addAttribute("points", oss.str()); if (actions.getColor() != Color::BLACK) node->addAttribute("fill", actions.getColor().svgColorString()); @@ -117,7 +116,7 @@ static void create_line (const DPair &p1, const DPair &p2, char c1, char c2, dou actions.embed(q21); actions.embed(q22); } - actions.appendToPage(std::move(node)); + actions.svgTree().appendToPage(std::move(node)); } @@ -126,8 +125,8 @@ static void create_line (const DPair &p1, const DPair &p2, char c1, char c2, dou static double read_length (InputReader &in) { double val = in.getDouble(); string unitstr; - if (isalpha(in.peek())) unitstr += in.get(); - if (isalpha(in.peek())) unitstr += in.get(); + if (isalpha(in.peek())) unitstr += char(in.get()); + if (isalpha(in.peek())) unitstr += char(in.get()); Length::Unit unit = Length::Unit::PT; try { unit = Length::stringToUnit(unitstr); @@ -163,7 +162,7 @@ bool EmSpecialHandler::process (const string &prefix, istream &is, SpecialAction {"moveto", &EmSpecialHandler::moveto}, {"lineto", &EmSpecialHandler::lineto}, {"linewidth", &EmSpecialHandler::linewidth}, - {0, 0} + {nullptr, nullptr} }; StreamInputReader ir(is); diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/EmSpecialHandler.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/EmSpecialHandler.hpp index 546702c97ca..242ef248ef7 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/EmSpecialHandler.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/EmSpecialHandler.hpp @@ -38,7 +38,6 @@ class EmSpecialHandler : public SpecialHandler { }; public: - EmSpecialHandler (); const char* name () const override {return "em";} const char* info () const override {return "line drawing statements of the emTeX special set";} std::vector<const char*> prefixes() const override; @@ -54,9 +53,9 @@ class EmSpecialHandler : public SpecialHandler { private: std::unordered_map<int, DPair> _points; ///< points defined by special em:point - std::vector<Line> _lines; ///< list of lines with undefined end points - double _linewidth; ///< global line width - DPair _pos; ///< current position of "graphic cursor" + std::vector<Line> _lines; ///< list of lines with undefined end points + double _linewidth=0.4*72/72.27; ///< global line width + DPair _pos; ///< current position of "graphic cursor" }; #endif diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/EncFile.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/EncFile.cpp index 292ad722d7f..dba0a2544ab 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/EncFile.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/EncFile.cpp @@ -32,7 +32,7 @@ static string read_entry (InputReader &in); static bool valid_name_char (int c); -EncFile::EncFile (const string &encname) : _encname(encname) +EncFile::EncFile (string encname) : _encname(std::move(encname)) { read(); } @@ -101,7 +101,7 @@ static string read_entry (InputReader &in) { while (!in.eof() && ((in.peek() == '/' && accept_slashes) || valid_name_char(in.peek()))) { if (in.peek() != '/') accept_slashes = false; - entry += in.get(); + entry += char(in.get()); } if (entry.length() > 1) { // strip leading slashes @@ -127,6 +127,6 @@ static bool valid_name_char (int c) { * @return character name assigned to character code c*/ const char* EncFile::charName (uint32_t c) const { if (c < _table.size()) - return !_table[c].empty() ? _table[c].c_str() : 0; - return 0; + return !_table[c].empty() ? _table[c].c_str() : nullptr; + return nullptr; } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/EncFile.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/EncFile.hpp index 2eab020b655..fac26fd201f 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/EncFile.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/EncFile.hpp @@ -28,10 +28,9 @@ #include "FontEncoding.hpp" -class EncFile : public NamedFontEncoding -{ +class EncFile : public NamedFontEncoding { public: - EncFile (const std::string &name); + explicit EncFile (std::string encname); void read (); void read (std::istream &is); int size () const {return _table.size();} diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/FileFinder.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/FileFinder.cpp index a5b4ed2ef2e..dfd60412cb8 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/FileFinder.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/FileFinder.cpp @@ -69,7 +69,7 @@ FileFinder::FileFinder () { void FileFinder::init (const std::string &argv0, const std::string &progname, bool enable_mktexmf) { _argv0 = argv0; - _progname = progname.c_str(); + _progname = progname; _enableMktex = enable_mktexmf; } @@ -174,6 +174,11 @@ const char* FileFinder::findFile (const std::string &fname, const char *ftype) c {"pro", kpse_tex_ps_header_format}, {"sfd", kpse_sfd_format}, {"eps", kpse_pict_format}, + {"png", kpse_pict_format}, + {"jpg", kpse_pict_format}, + {"jpeg", kpse_pict_format}, + {"svg", kpse_pict_format}, + {"pdf", kpse_tex_format}, }; auto it = types.find(ext); if (it == types.end()) @@ -205,10 +210,10 @@ const char* FileFinder::findMappedFile (std::string fname) const { if (const FontMap::Entry *entry = FontMap::instance().lookup(base)) { const char *path=nullptr; if (entry->fontname.find('.') != std::string::npos) // does the mapped filename has an extension? - path = findFile(entry->fontname, 0); // look for that file + path = findFile(entry->fontname, nullptr); // look for that file else { // otherwise, use extension of unmapped file fname = entry->fontname + "." + ext; - (path = findFile(fname, 0)) || (path = mktex(fname)); + (path = findFile(fname, nullptr)) || (path = mktex(fname)); } return path; } @@ -233,7 +238,7 @@ const char* FileFinder::mktex (const std::string &fname) const { // maketfm and makemf are located in miktex/bin which is in the search PATH std::string toolname = (ext == "tfm" ? "miktex-maketfm" : "miktex-makemf"); system((toolname+".exe "+fname).c_str()); - path = findFile(fname, 0); + path = findFile(fname, nullptr); #else kpse_file_format_type type = (ext == "tfm" ? kpse_tfm_format : kpse_mf_format); path = kpse_make_tex(type, fname.c_str()); diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/FileFinder.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/FileFinder.hpp index f7f8f783d87..b01c26b10c0 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/FileFinder.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/FileFinder.hpp @@ -34,7 +34,7 @@ class FileFinder { std::string version () const; void addLookupDir (const std::string &path); const char* lookup (const std::string &fname, const char *ftype, bool extended=true) const; - const char* lookup (const std::string &fname, bool extended=true) const {return lookup(fname, 0, extended);} + const char* lookup (const std::string &fname, bool extended=true) const {return lookup(fname, nullptr, extended);} protected: FileFinder (); diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/FilePath.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/FilePath.cpp index d8834499d38..c859d30469d 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/FilePath.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/FilePath.cpp @@ -87,10 +87,28 @@ FilePath::FilePath (const string &path, bool isfile, const string ¤t_dir) } -/** Assigns a new path. Relative paths are relative to the current working directory. +/** Assigns a new path of a file or directory that already exists. + * Relative paths are relative to the current working directory. * @param[in] path absolute or relative path to a file or directory */ -void FilePath::set(const string &path) { - init(path, !FileSystem::isDirectory(path), FileSystem::getcwd()); +void FilePath::set (const string &path) { + set(path, !FileSystem::isDirectory(path)); +} + + +/** Assigns a new path. Relative paths are relative to the current working directory. + * @param[in] path absolute or relative path to a file or directory + * @param[in] isfile true if 'path' references a file, false if a directory is referenced */ +void FilePath::set (const string &path, bool isfile) { + init(path, isfile, FileSystem::getcwd()); +} + + +/** Assigns a new path. Relative paths are relative to the current working directory. + * @param[in] path absolute or relative path to a file or directory + * @param[in] isfile true if 'path' references a file, false if a directory is referenced + * @param[in] current_dir if 'path' is a relative path expression it will be related to 'current_dir' */ +void FilePath::set (const string &path, bool isfile, const string ¤t_dir) { + init(path, isfile, current_dir); } @@ -152,7 +170,7 @@ void FilePath::add (const string &dir) { if (dir == ".." && !_dirs.empty()) _dirs.pop_back(); else if (dir.length() > 0 && dir != ".") - _dirs.push_back(dir); + _dirs.emplace_back(dir); } @@ -257,3 +275,37 @@ string FilePath::relative (string reldir, bool with_filename) const { path = "."; return single_slashes(path); } + + +string FilePath::relative (const FilePath &filepath, bool with_filename) const { + return relative(filepath.absolute(false), with_filename); +} + + +/** Return the absolute or relative path whichever is shorter. +* @param[in] reldir absolute path to a directory +* @param[in] with_filename if false, the filename is omitted */ +string FilePath::shorterAbsoluteOrRelative (string reldir, bool with_filename) const { + string abs = absolute(with_filename); + string rel = relative(reldir, with_filename); + return abs.length() < rel.length() ? abs : rel; +} + + +bool FilePath::exists () const { + return empty() ? false : FileSystem::exists(absolute()); +} + + +/** Checks if a given path is absolute or relative. + * @param[in] path path string to check + * @return true if path is absolute */ +bool FilePath::isAbsolute (string path) { + path = util::trim(path); +#ifdef _WIN32 + path = FileSystem::adaptPathSeperators(path); + if (path.length() >= 2 && path[1] == ':' && isalpha(path[0])) + path.erase(0, 2); // remove drive letter and colon +#endif + return !path.empty() && path[0] == '/'; +} diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/FilePath.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/FilePath.hpp index f3efed020b0..32a9be68149 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/FilePath.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/FilePath.hpp @@ -28,8 +28,8 @@ class FilePath { class Directory { public: - Directory (const std::string &dir) : _dirstr(dir) {} - Directory (std::string &&dir) : _dirstr(std::move(dir)) {} + explicit Directory (std::string dir) : _dirstr(std::move(dir)) {} + explicit Directory (std::string &&dir) : _dirstr(std::move(dir)) {} bool operator == (const Directory &dir) const; bool operator != (const Directory &dir) const {return !(*this == dir);} explicit operator std::string () const {return _dirstr;} @@ -39,12 +39,17 @@ class FilePath { }; public: - FilePath (const std::string &path) {set(path);} + FilePath () =default; + explicit FilePath (const std::string &path) {set(path);} FilePath (const std::string &path, bool isfile) : FilePath(path, isfile, "") {} FilePath (const std::string &path, bool isfile, const std::string ¤t_dir); void set (const std::string &path); + void set (const std::string &path, bool isfile); + void set (const std::string &path, bool isfile, const std::string ¤t_dir); std::string absolute (bool with_filename=true) const; std::string relative (std::string reldir="", bool with_filename=true) const; + std::string relative (const FilePath &filepath, bool with_filename=true) const; + std::string shorterAbsoluteOrRelative (std::string reldir="", bool with_filename=true) const; std::string basename () const; std::string suffix () const; void suffix (const std::string &s); @@ -53,16 +58,18 @@ class FilePath { bool empty () const {return _dirs.empty() && _fname.empty();} const std::string& filename () const {return _fname;} void filename (const std::string &fname) {_fname = fname;} + bool exists () const; + static bool isAbsolute (std::string path); protected: void init (std::string path, bool isfile, std::string current_dir); void add (const std::string &elem); private: - std::vector<std::string> _dirs; + std::vector<Directory> _dirs; std::string _fname; #ifdef _WIN32 - char _drive; + char _drive=0; #endif }; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/FileSystem.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/FileSystem.cpp index 9540a5e9c7d..35621465a53 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/FileSystem.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/FileSystem.cpp @@ -175,7 +175,7 @@ const char* FileSystem::userdir () { if (!ret.empty()) return ret.c_str(); } - return 0; + return nullptr; #else const char *dir=getenv("HOME"); if (!dir) { diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/Font.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/Font.cpp index b83bb849a85..97520c59534 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/Font.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/Font.cpp @@ -99,8 +99,8 @@ const char* Font::filename () const { /////////////////////////////////////////////////////////////////////////////////////// -TFMFont::TFMFont (const string &name, uint32_t cs, double ds, double ss) - : _fontname(name), _checksum(cs), _dsize(ds), _ssize(ss) +TFMFont::TFMFont (string name, uint32_t cs, double ds, double ss) + : _fontname(std::move(name)), _checksum(cs), _dsize(ds), _ssize(ss) { } @@ -159,7 +159,7 @@ bool TFMFont::verifyChecksums () const { // static class variables bool PhysicalFont::EXACT_BBOX = false; bool PhysicalFont::KEEP_TEMP_FILES = false; -const char *PhysicalFont::CACHE_PATH = 0; +string PhysicalFont::CACHE_PATH; double PhysicalFont::METAFONT_MAG = 4; FontCache PhysicalFont::_cache; @@ -175,14 +175,14 @@ unique_ptr<Font> PhysicalFont::create (const string &name, int fontindex, uint32 const char* PhysicalFont::path () const { - const char *ext=0; + const char *ext=nullptr; switch (type()) { case Type::OTF: ext = "otf"; break; case Type::PFB: ext = "pfb"; break; case Type::TTC: ext = "ttc"; break; case Type::TTF: ext = "ttf"; break; case Type::MF : ext = "mf"; break; - default : ext = 0; + default : ext = nullptr; } if (ext) return FileFinder::instance().lookup(name()+"."+ext); @@ -323,8 +323,8 @@ std::string PhysicalFont::styleName () const { * @return true if outline could be computed */ bool PhysicalFont::getGlyph (int c, GraphicsPath<int32_t> &glyph, GFGlyphTracer::Callback *callback) const { if (type() == Type::MF) { - const Glyph *cached_glyph=0; - if (CACHE_PATH) { + const Glyph *cached_glyph=nullptr; + if (!CACHE_PATH.empty()) { _cache.write(CACHE_PATH); _cache.read(name(), CACHE_PATH); cached_glyph = _cache.getGlyph(c); @@ -342,7 +342,7 @@ bool PhysicalFont::getGlyph (int c, GraphicsPath<int32_t> &glyph, GFGlyphTracer: tracer.setGlyph(glyph); tracer.executeChar(c); glyph.closeOpenSubPaths(); - if (CACHE_PATH) + if (!CACHE_PATH.empty()) _cache.setGlyph(c, glyph); return true; } @@ -392,7 +392,7 @@ bool PhysicalFont::createGF (string &gfname) const { * @return number of glyphs traced */ int PhysicalFont::traceAllGlyphs (bool includeCached, GFGlyphTracer::Callback *cb) const { int count = 0; - if (type() == Type::MF && CACHE_PATH) { + if (type() == Type::MF && !CACHE_PATH.empty()) { if (const FontMetrics *metrics = getMetrics()) { int fchar = metrics->firstChar(); int lchar = metrics->lastChar(); @@ -479,7 +479,7 @@ PhysicalFontImpl::PhysicalFontImpl (const string &name, int fontindex, uint32_t PhysicalFontImpl::~PhysicalFontImpl () { - if (CACHE_PATH) + if (!CACHE_PATH.empty()) _cache.write(CACHE_PATH); if (!KEEP_TEMP_FILES) tidy(); @@ -548,7 +548,7 @@ uint32_t PhysicalFontImpl::unicode (uint32_t c) const { const FontStyle* PhysicalFontImpl::style () const { - if (auto *entry = fontMapEntry()) + if (auto entry = fontMapEntry()) return &entry->style; return nullptr; } @@ -671,6 +671,6 @@ void VirtualFontImpl::assignChar (uint32_t c, DVIVector &&dvi) { * @return pointer to vector of DVI commands, or 0 if character doesn't exist */ const vector<uint8_t>* VirtualFontImpl::getDVI (int c) const { auto it = _charDefs.find(c); - return (it == _charDefs.end() ? 0 : &it->second); + return (it == _charDefs.end() ? nullptr : &it->second); } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/Font.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/Font.hpp index 294ad4738ee..3273a0c14b8 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/Font.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/Font.hpp @@ -69,7 +69,7 @@ class Font { virtual const char* path () const =0; virtual const char* filename () const; virtual const FontEncoding* encoding () const; - virtual bool getGlyph (int c, Glyph &glyph, GFGlyphTracer::Callback *callback=0) const =0; + virtual bool getGlyph (int c, Glyph &glyph, GFGlyphTracer::Callback *callback=nullptr) const =0; virtual void getGlyphMetrics (int c, bool vertical, GlyphMetrics &metrics) const; virtual uint32_t unicode (uint32_t c) const; virtual void tidy () const {} @@ -88,7 +88,7 @@ class Font { * The metric values returned by the member functions are based on cmr10. */ class EmptyFont : public Font { public: - EmptyFont (const std::string &name) : _fontname(name) {} + explicit EmptyFont (std::string name) : _fontname(std::move(name)) {} std::unique_ptr<Font> clone (double ds, double sc) const override {return util::make_unique<EmptyFont>(*this);} const Font* uniqueFont () const override {return this;} std::string name () const override {return _fontname;} @@ -100,7 +100,7 @@ class EmptyFont : public Font { double italicCorr (int c) const override {return 0;} const FontMetrics* getMetrics () const override {return nullptr;} const char* path () const override {return nullptr;} - bool getGlyph (int c, Glyph &glyph, GFGlyphTracer::Callback *cb=0) const override {return false;} + bool getGlyph (int c, Glyph &glyph, GFGlyphTracer::Callback *cb=nullptr) const override {return false;} private: std::string _fontname; @@ -115,7 +115,7 @@ class PhysicalFont : public virtual Font { static std::unique_ptr<Font> create (const std::string &name, uint32_t checksum, double dsize, double ssize, PhysicalFont::Type type); static std::unique_ptr<Font> create (const std::string &name, int fontindex, uint32_t checksum, double dsize, double ssize); virtual Type type () const =0; - virtual bool getGlyph (int c, Glyph &glyph, GFGlyphTracer::Callback *cb=nullptr) const override; + bool getGlyph (int c, Glyph &glyph, GFGlyphTracer::Callback *cb=nullptr) const override; virtual bool getExactGlyphBox (int c, BoundingBox &bbox, GFGlyphTracer::Callback *cb=nullptr) const; virtual bool getExactGlyphBox (int c, GlyphMetrics &metrics, bool vertical, GFGlyphTracer::Callback *cb=nullptr) const; virtual bool isCIDFont () const; @@ -142,7 +142,7 @@ class PhysicalFont : public virtual Font { public: static bool EXACT_BBOX; static bool KEEP_TEMP_FILES; - static const char *CACHE_PATH; ///< path to cache directory (0 if caching is disabled) + static std::string CACHE_PATH; ///< path to cache directory ("" if caching is disabled) static double METAFONT_MAG; ///< magnification factor for Metafont calls protected: @@ -168,7 +168,7 @@ class VirtualFont : public virtual Font { class TFMFont : public virtual Font { public: - TFMFont (const std::string &name, uint32_t checksum, double dsize, double ssize); + TFMFont (std::string name, uint32_t cs, double ds, double ss); const FontMetrics* getMetrics () const override; std::string name () const override {return _fontname;} double designSize () const override {return _dsize;} @@ -227,7 +227,7 @@ class PhysicalFontProxy : public PhysicalFont { class PhysicalFontImpl : public PhysicalFont, public TFMFont { friend class PhysicalFont; public: - ~PhysicalFontImpl(); + ~PhysicalFontImpl () override; std::unique_ptr<Font> clone (double ds, double ss) const override { return std::unique_ptr<PhysicalFontProxy>(new PhysicalFontProxy(this, ds, ss)); @@ -258,7 +258,7 @@ class PhysicalFontImpl : public PhysicalFont, public TFMFont { class NativeFont : public PhysicalFont { public: virtual std::unique_ptr<NativeFont> clone (double ptsize, const FontStyle &style, Color color) const =0; - virtual std::unique_ptr<Font> clone (double ds, double sc) const override =0; + std::unique_ptr<Font> clone (double ds, double sc) const override =0; std::string name () const override; Type type () const override; double designSize () const override {return _ptsize;} @@ -312,8 +312,8 @@ class NativeFontProxy : public NativeFont { class NativeFontImpl : public NativeFont { public: - NativeFontImpl (const std::string &fname, int fontIndex, double ptsize, const FontStyle &style, Color color) - : NativeFont(ptsize, style, color), _path(fname), _fontIndex(fontIndex) {} + NativeFontImpl (std::string fname, int fontIndex, double ptsize, const FontStyle &style, Color color) + : NativeFont(ptsize, style, color), _path(std::move(fname)), _fontIndex(fontIndex) {} std::unique_ptr<NativeFont> clone (double ptsize, const FontStyle &style, Color color) const override { return std::unique_ptr<NativeFontProxy>(new NativeFontProxy(this, ptsize, style, color)); @@ -391,7 +391,7 @@ class VirtualFontImpl : public VirtualFont, public TFMFont { struct FontException : public MessageException { - FontException (const std::string &msg) : MessageException(msg) {} + explicit FontException (const std::string &msg) : MessageException(msg) {} }; #endif diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/FontCache.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/FontCache.cpp index 1e2f19a780b..34478542dfb 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/FontCache.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/FontCache.cpp @@ -23,13 +23,12 @@ #include <fstream> #include <iomanip> #include <sstream> -#include "CRC32.hpp" #include "FileSystem.hpp" #include "FontCache.hpp" -#include "Glyph.hpp" #include "Pair.hpp" #include "StreamReader.hpp" #include "StreamWriter.hpp" +#include "XXHashFunction.hpp" using namespace std; @@ -64,7 +63,7 @@ void FontCache::setGlyph (int c, const Glyph &glyph) { * @return font glyph data (0 if no matching data was found) */ const Glyph* FontCache::getGlyph (int c) const { auto it = _glyphs.find(c); - return (it != _glyphs.end()) ? &it->second : 0; + return (it != _glyphs.end()) ? &it->second : nullptr; } @@ -78,10 +77,9 @@ bool FontCache::write (const string &fontname, const string &dir) const { return true; if (!fontname.empty()) { - string dirstr = dir.empty() ? FileSystem::getcwd() : dir; - ostringstream oss; - oss << dirstr << '/' << fontname << ".fgd"; - ofstream ofs(oss.str(), ios::binary); + string pathstr = dir.empty() ? FileSystem::getcwd() : dir; + pathstr += "/" + fontname + ".fgd"; + ofstream ofs(pathstr, ios::binary); return write(fontname, ofs); } return false; @@ -94,7 +92,7 @@ bool FontCache::write (const string &dir) const { /** Returns the minimal number of bytes needed to store the given value. */ -static int max_int_size (int32_t value) { +static int max_number_of_bytes (int32_t value) { int32_t limit = 0x7f; for (int i=1; i <= 4; i++) { if ((value < 0 && -value <= limit+1) || (value >= 0 && value <= limit)) @@ -104,19 +102,49 @@ static int max_int_size (int32_t value) { return 4; } +static int max_int_size () { + return 0; +} -/** Returns the minimal number of bytes needed to store the biggest - * pair component of the given vector. */ -static int max_int_size (const Pair<int32_t> *pairs, size_t n) { - int ret=0; - for (size_t i=0; i < n; i++) { - ret = max(ret, max_int_size(pairs[i].x())); - ret = max(ret, max_int_size(pairs[i].y())); - } - return ret; +template <typename ...Args> +static int max_int_size (const Glyph::Point &p1, const Args& ...args) { + int max1 = max(max_number_of_bytes(p1.x()), max_number_of_bytes(p1.y())); + return max(max1, max_int_size(args...)); } +struct WriteActions : Glyph::IterationActions { + WriteActions (StreamWriter &sw, HashFunction &hashfunc) : _sw(sw), _hashfunc(hashfunc) {} + + using Point = Glyph::Point; + void moveto (const Point &p) override {write('M', p);} + void lineto (const Point &p) override {write('L', p);} + void quadto (const Point &p1, const Point &p2) override {write('Q', p1, p2);} + void cubicto (const Point &p1, const Point &p2, const Point &p3) override {write('C', p1, p2, p3); } + void closepath () override {write('Z');} + + template <typename ...Args> + void write (char cmd, Args ...args) { + int bytesPerValue = max_int_size(args...); + int cmdchar = (bytesPerValue << 5) | (cmd - 'A'); + _sw.writeUnsigned(cmdchar, 1, _hashfunc); + writeParams(bytesPerValue, args...); + } + + static void writeParams (int bytesPerValue) {} + + template <typename ...Args> + void writeParams (int bytesPerValue, const Point &p, const Args& ...args) { + _sw.writeSigned(p.x(), bytesPerValue, _hashfunc); + _sw.writeSigned(p.y(), bytesPerValue, _hashfunc); + writeParams(bytesPerValue, args...); + } + + StreamWriter &_sw; + HashFunction &_hashfunc; +}; + + /** Writes the current cache data to a stream (only if anything changed after * the last call of read()). * @param[in] fontname name of current font @@ -129,36 +157,22 @@ bool FontCache::write (const string &fontname, ostream &os) const { return false; StreamWriter sw(os); - CRC32 crc32; - - struct WriteActions : Glyph::Actions { - WriteActions (StreamWriter &sw, CRC32 &crc32) : _sw(sw), _crc32(crc32) {} - - void draw (char cmd, const Glyph::Point *points, int n) override { - int bytes = max_int_size(points, n); - int cmdchar = (bytes << 5) | (cmd - 'A'); - _sw.writeUnsigned(cmdchar, 1, _crc32); - for (int i=0; i < n; i++) { - _sw.writeSigned(points[i].x(), bytes, _crc32); - _sw.writeSigned(points[i].y(), bytes, _crc32); - } - } - StreamWriter &_sw; - CRC32 &_crc32; - } actions(sw, crc32); - - sw.writeUnsigned(FORMAT_VERSION, 1, crc32); - sw.writeUnsigned(0, 4); // space for checksum - sw.writeString(fontname, crc32, true); - sw.writeUnsigned(_glyphs.size(), 4, crc32); + XXH32HashFunction hashfunc; + + sw.writeUnsigned(FORMAT_VERSION, 1, hashfunc); + sw.writeBytes(hashfunc.digestValue()); // space for checksum + sw.writeString(fontname, hashfunc, true); + sw.writeUnsigned(_glyphs.size(), 4, hashfunc); + WriteActions actions(sw, hashfunc); for (const auto &charglyphpair : _glyphs) { const Glyph &glyph = charglyphpair.second; - sw.writeUnsigned(charglyphpair.first, 4, crc32); - sw.writeUnsigned(glyph.size(), 2, crc32); + sw.writeUnsigned(charglyphpair.first, 4, hashfunc); + sw.writeUnsigned(glyph.size(), 2, hashfunc); glyph.iterate(actions, false); } os.seekp(1); - sw.writeUnsigned(crc32.get(), 4); // insert CRC32 checksum + auto digest = hashfunc.digestValue(); + sw.writeBytes(digest); // insert checksum os.seekp(0, ios::end); return true; } @@ -195,17 +209,17 @@ bool FontCache::read (const string &fontname, istream &is) { return false; StreamReader sr(is); - CRC32 crc32; - if (sr.readUnsigned(1, crc32) != FORMAT_VERSION) + XXH32HashFunction hashfunc; + if (sr.readUnsigned(1, hashfunc) != FORMAT_VERSION) return false; - uint32_t crc32_cmp = sr.readUnsigned(4); - crc32.update(is); - if (crc32.get() != crc32_cmp) + auto hashcmp = sr.readBytes(hashfunc.digestSize()); + hashfunc.update(is); + if (hashfunc.digestValue() != hashcmp) return false; is.clear(); - is.seekg(5); // continue reading after checksum + is.seekg(hashfunc.digestSize()+1); // continue reading after checksum string fname = sr.readString(); if (fname != fontname) @@ -237,7 +251,7 @@ bool FontCache::read (const string &fontname, istream &is) { case 'Q': { Pair32 p1 = read_pair(bytes, sr); Pair32 p2 = read_pair(bytes, sr); - glyph.conicto(p1, p2); + glyph.quadto(p1, p2); break; } case 'Z': @@ -289,17 +303,17 @@ bool FontCache::fontinfo (std::istream &is, FontInfo &info) { is.seekg(0); try { StreamReader sr(is); - CRC32 crc32; - if ((info.version = sr.readUnsigned(1, crc32)) != FORMAT_VERSION) + XXH32HashFunction hashfunc; + if ((info.version = sr.readUnsigned(1, hashfunc)) != FORMAT_VERSION) return false; - info.checksum = sr.readUnsigned(4); - crc32.update(is); - if (crc32.get() != info.checksum) + info.checksum = sr.readBytes(hashfunc.digestSize()); + hashfunc.update(is); + if (hashfunc.digestValue() != info.checksum) return false; is.clear(); - is.seekg(5); // continue reading after checksum + is.seekg(hashfunc.digestSize()+1); // continue reading after checksum info.name = sr.readString(); info.numchars = sr.readUnsigned(4); @@ -361,8 +375,10 @@ void FontCache::fontinfo (const string &dirname, ostream &os, bool purge) { << setw(5) << right << strinfopair.second->numchars << " glyph" << (strinfopair.second->numchars == 1 ? ' ':'s') << setw(10) << right << strinfopair.second->numcmds << " cmd" << (strinfopair.second->numcmds == 1 ? ' ':'s') << setw(12) << right << strinfopair.second->numbytes << " byte" << (strinfopair.second->numbytes == 1 ? ' ':'s') - << setw(6) << "crc:" << setw(8) << hex << right << setfill('0') << strinfopair.second->checksum - << endl; + << " hash:" << hex; + for (int byte : strinfopair.second->checksum) + os << setw(2) << setfill('0') << byte; + os << '\n'; } } if (purge) { diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/FontCache.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/FontCache.hpp index 24c977818e7..0068b6c78bf 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/FontCache.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/FontCache.hpp @@ -30,16 +30,15 @@ class FontCache { public: struct FontInfo { - std::string name; // fontname - uint16_t version; // file format version - uint32_t checksum; // CRC32 checksum of file data - uint32_t numchars; // number of characters - uint32_t numbytes; // number of bytes - uint32_t numcmds; // number of path commands + std::string name; // fontname + uint16_t version; // file format version + std::vector<uint8_t> checksum; // checksum of file data + uint32_t numchars; // number of characters + uint32_t numbytes; // number of bytes + uint32_t numcmds; // number of path commands }; public: - FontCache () : _changed(false) {} ~FontCache () {clear();} bool read (const std::string &fontname, const std::string &dir); bool read (const std::string &fontname, std::istream &is); @@ -59,7 +58,7 @@ class FontCache { static const uint8_t FORMAT_VERSION; std::string _fontname; std::map<int, Glyph> _glyphs; - bool _changed; + bool _changed=false; }; #endif diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/FontEncoding.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/FontEncoding.cpp index add5cfc5ff6..3b038b63c6f 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/FontEncoding.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/FontEncoding.cpp @@ -32,7 +32,7 @@ using namespace std; * @return pointer to encoding object, or 0 if there is no encoding defined */ FontEncoding* FontEncoding::encoding (const string &encname) { if (encname.empty()) - return 0; + return nullptr; using EncodingMap = unordered_map<string, unique_ptr<EncFile>>; static EncodingMap encmap; @@ -77,7 +77,7 @@ const FontEncoding* FontEncodingPair::findCompatibleBaseFontMap (const PhysicalF return _enc2->findCompatibleBaseFontMap(font, charmapID); if (_enc1) return _enc1->findCompatibleBaseFontMap(font, charmapID); - return 0; + return nullptr; } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/FontEncoding.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/FontEncoding.hpp index de8ece6bb80..fffccd4224a 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/FontEncoding.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/FontEncoding.hpp @@ -32,7 +32,7 @@ struct FontEncoding { virtual ~FontEncoding () =default; virtual Character decode (uint32_t c) const =0; virtual bool mapsToCharIndex () const =0; - virtual const FontEncoding* findCompatibleBaseFontMap (const PhysicalFont *font, CharMapID &charmapID) const {return 0;} + virtual const FontEncoding* findCompatibleBaseFontMap (const PhysicalFont *font, CharMapID &charmapID) const {return nullptr;} static FontEncoding* encoding (const std::string &encname); }; @@ -45,7 +45,7 @@ struct NamedFontEncoding : public FontEncoding { class FontEncodingPair : public FontEncoding { public: - FontEncodingPair (const FontEncoding *enc1) : _enc1(enc1), _enc2(0) {} + explicit FontEncodingPair (const FontEncoding *enc1) : _enc1(enc1), _enc2(nullptr) {} FontEncodingPair (const FontEncoding *enc1, const FontEncoding *enc2) : _enc1(enc1), _enc2(enc2) {} Character decode (uint32_t c) const override; bool mapsToCharIndex () const override; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/FontEngine.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/FontEngine.cpp index 1bdcbcdbedb..61efd68916f 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/FontEngine.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/FontEngine.cpp @@ -18,6 +18,7 @@ ** along with this program; if not, see <http://www.gnu.org/licenses/>. ** *************************************************************************/ +#include <cmath> #include <sstream> #include <ft2build.h> #include FT_ADVANCES_H @@ -36,7 +37,7 @@ using namespace std; /** Converts a floating point value to a 16.16 fixed point value. */ static inline FT_Fixed to_16dot16 (double val) { - return static_cast<FT_Fixed>(val*65536.0 + 0.5); + return static_cast<FT_Fixed>(lround(val*65536.0)); } @@ -49,9 +50,7 @@ static inline FT_Fixed to_16dot16 (int val) { /////////////////////////////////////////////////////////////////////////// -FontEngine::FontEngine () : _currentFace(0), _currentFont(0) -{ - _currentChar = _currentGlyphIndex = 0; +FontEngine::FontEngine () { if (FT_Init_FreeType(&_library)) Message::estream(true) << "failed to initialize FreeType library\n"; } @@ -104,7 +103,7 @@ bool FontEngine::setFont (const Font &font) { return true; if (const char *path=font.path()) { - const PhysicalFont *pf = dynamic_cast<const PhysicalFont*>(&font); + auto pf = dynamic_cast<const PhysicalFont*>(&font); if (setFont(path, font.fontIndex(), pf ? pf->getCharMapID() : CharMapID())) { _currentFont = &font; return true; @@ -212,7 +211,7 @@ int FontEngine::getAdvance (int c) const { int FontEngine::getHAdvance () const { if (_currentFace) { - TT_OS2 *table = static_cast<TT_OS2*>(FT_Get_Sfnt_Table(_currentFace, ft_sfnt_os2)); + auto table = static_cast<TT_OS2*>(FT_Get_Sfnt_Table(_currentFace, ft_sfnt_os2)); return table ? table->xAvgCharWidth : 0; } return 0; @@ -294,7 +293,7 @@ string FontEngine::getGlyphName (const Character &c) const { vector<int> FontEngine::getPanose () const { vector<int> panose(10); if (_currentFace) { - TT_OS2 *table = static_cast<TT_OS2*>(FT_Get_Sfnt_Table(_currentFace, ft_sfnt_os2)); + auto table = static_cast<TT_OS2*>(FT_Get_Sfnt_Table(_currentFace, ft_sfnt_os2)); if (table) for (int i=0; i < 10; i++) panose[i] = table->panose[i]; @@ -339,35 +338,35 @@ CharMapID FontEngine::setCustomCharMap () { // Callback functions used by trace_outline/FT_Outline_Decompose static int moveto (FTVectorPtr to, void *user) { - Glyph *glyph = static_cast<Glyph*>(user); + auto glyph = static_cast<Glyph*>(user); glyph->moveto(to->x, to->y); return 0; } static int lineto (FTVectorPtr to, void *user) { - Glyph *glyph = static_cast<Glyph*>(user); + auto glyph = static_cast<Glyph*>(user); glyph->lineto(to->x, to->y); return 0; } -static int conicto (FTVectorPtr control, FTVectorPtr to, void *user) { - Glyph *glyph = static_cast<Glyph*>(user); - glyph->conicto(control->x, control->y, to->x, to->y); +static int quadto (FTVectorPtr control, FTVectorPtr to, void *user) { + auto glyph = static_cast<Glyph*>(user); + glyph->quadto(control->x, control->y, to->x, to->y); return 0; } static int cubicto (FTVectorPtr control1, FTVectorPtr control2, FTVectorPtr to, void *user) { - Glyph *glyph = static_cast<Glyph*>(user); + auto glyph = static_cast<Glyph*>(user); glyph->cubicto(control1->x, control1->y, control2->x, control2->y, to->x, to->y); return 0; } /** Traces the outline of a glyph by calling the corresponding "drawing" functions. - * Each glyph is composed of straight lines, quadratic (conic) or cubic B�zier curves. + * Each glyph is composed of straight lines, quadratic or cubic Bézier curves. * This function creates a Glyph object representing these graphics segments. * @param[in] face FreeType object representing the font to scan * @param[in] font corresponding Font object providing additional data @@ -393,7 +392,7 @@ static bool trace_outline (FT_Face face, const Font *font, int index, Glyph &gly if (style->bold != 0) FT_Outline_Embolden(&outline, style->bold/font->scaledSize()*face->units_per_EM); } - const FT_Outline_Funcs funcs = {moveto, lineto, conicto, cubicto, 0, 0}; + const FT_Outline_Funcs funcs = {moveto, lineto, quadto, cubicto, 0, 0}; FT_Outline_Decompose(&outline, &funcs, &glyph); return true; } @@ -403,7 +402,7 @@ static bool trace_outline (FT_Face face, const Font *font, int index, Glyph &gly /** Traces the outline of a glyph by calling the corresponding "drawing" functions. - * Each glyph is composed of straight lines, quadratic (conic) or cubic B�zier curves. + * Each glyph is composed of straight lines, quadratic or cubic Bézier curves. * This function creates a Glyph object representing these graphics segments. * @param[in] c the glyph of this character will be traced * @param[out] glyph resulting Glyph object containing the graphics segments diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/FontEngine.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/FontEngine.hpp index 071f7fcf4b5..33c9b96da2a 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/FontEngine.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/FontEngine.hpp @@ -73,10 +73,10 @@ class FontEngine { int charIndex (const Character &c) const; private: - mutable unsigned int _currentChar, _currentGlyphIndex; - FT_Face _currentFace; + mutable unsigned int _currentChar=0, _currentGlyphIndex=0; + FT_Face _currentFace = nullptr; FT_Library _library; - const Font *_currentFont; + const Font *_currentFont = nullptr; }; #endif diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/FontManager.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/FontManager.cpp index 7805cc1d53e..4f236b38664 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/FontManager.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/FontManager.cpp @@ -187,11 +187,11 @@ int FontManager::registerFont (uint32_t fontnum, const string &name, uint32_t ch fontindex = map_entry->fontindex; } // try to find font file with the exact given name - if (filename.rfind(".") != string::npos) + if (filename.rfind('.') != string::npos) newfont = create_font(filename, name, fontindex, checksum, dsize, ssize); else { // try various font file formats if the given file has no extension - const char *exts[] = {"pfb", "otf", "ttc", "ttf", "vf", "mf", 0}; + const char *exts[] = {"pfb", "otf", "ttc", "ttf", "vf", "mf", nullptr}; for (const char **p = exts; *p && !newfont; ++p) newfont = create_font(filename+"."+*p, name, fontindex, checksum, dsize, ssize); } @@ -204,7 +204,7 @@ int FontManager::registerFont (uint32_t fontnum, const string &name, uint32_t ch else { // create dummy font as a placeholder if the proper font is not available newfont = util::make_unique<EmptyFont>(name); - if (filename.rfind(".") == string::npos) + if (filename.rfind('.') == string::npos) filename += ".mf"; // print warning message about missing font file (only once for each filename) static set<string> missing_fonts; @@ -263,7 +263,7 @@ int FontManager::registerFont (uint32_t fontnum, string filename, int fontIndex, const int newid = _fonts.size(); // the new font gets this ID auto it = _name2id.find(fontname); if (it != _name2id.end()) { // font with same name already registered? - if (NativeFont *font = dynamic_cast<NativeFont*>(_fonts[it->second].get())) + if (auto font = dynamic_cast<NativeFont*>(_fonts[it->second].get())) newfont = font->clone(ptsize, style, color); } else { diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/FontManager.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/FontManager.hpp index 2228c0c46ae..4405f67ecde 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/FontManager.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/FontManager.hpp @@ -66,7 +66,7 @@ class FontManager void enterVF (VirtualFont *vf); void leaveVF (); void assignVFChar (int c, std::vector<uint8_t> &&dvi); - std::ostream& write (std::ostream &os, Font *font=0, int level=0); + std::ostream& write (std::ostream &os, Font *font=nullptr, int level=0); protected: FontManager () =default; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/FontMap.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/FontMap.hpp index ee64c335f71..cd109c1809b 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/FontMap.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/FontMap.hpp @@ -34,7 +34,7 @@ class Subfont; class FontMap { public: struct Entry { - Entry (const MapLine &mapline, Subfont *subfont=nullptr); + explicit Entry (const MapLine &mapline, Subfont *subfont=nullptr); Entry (const Entry &entry) =delete; Entry (Entry &&entry) =default; Entry& operator = (Entry &&entry) =default; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/FontMetrics.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/FontMetrics.hpp index 3f5296877b0..ccba26b727c 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/FontMetrics.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/FontMetrics.hpp @@ -67,7 +67,7 @@ struct NullFontMetric : public FontMetrics { struct FontMetricException : public MessageException { - FontMetricException (const std::string &msg) : MessageException(msg) {} + explicit FontMetricException (const std::string &msg) : MessageException(msg) {} }; #endif diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/FontWriter.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/FontWriter.cpp index 3c5173e5a85..d93402baf54 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/FontWriter.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/FontWriter.cpp @@ -39,21 +39,19 @@ const array<FontWriter::FontFormatInfo, 4> FontWriter::_formatInfos {{ /** Returns the corresponding FontFormat for a given format name (e.g. "svg", "woff" etc.). */ FontWriter::FontFormat FontWriter::toFontFormat (string formatstr) { formatstr = util::tolower(formatstr); - for (const FontFormatInfo &info : _formatInfos) { - if (formatstr == info.formatstr_short) - return info.format; - } - return FontFormat::UNKNOWN; + auto it = find_if(_formatInfos.begin(), _formatInfos.end(), [&](const FontFormatInfo &info) { + return info.formatstr_short == formatstr; + }); + return it != _formatInfos.end() ? it->format : FontFormat::UNKNOWN; } /** Returns the corresponding FontFormatInfo for a given FontFormat. */ const FontWriter::FontFormatInfo* FontWriter::fontFormatInfo (FontFormat format) { - for (const FontFormatInfo &info : _formatInfos) { - if (format == info.format) - return &info; - } - return nullptr; + auto it = find_if(_formatInfos.begin(), _formatInfos.end(), [&](const FontFormatInfo &info) { + return info.format == format; + }); + return it != _formatInfos.end() ? &(*it) : nullptr; } @@ -97,33 +95,38 @@ FontWriter::FontWriter (const PhysicalFont &font) : _font(font) { } -struct SFDActions : Glyph::Actions { - SFDActions (ostream &os) : _os(os) {} - void draw (char cmd, const Glyph::Point *points, int n) override { - if (cmd == 'Q') { - // convert quadratic Bézier curve to cubic one - DPair p0(_currentPoint.x(), _currentPoint.y()); - DPair p1(points[0].x(), points[0].y()); - DPair p2(points[1].x(), points[1].y()); - Bezier bezier(p0, p1, p2); - for (int i=1; i < 4; i++) - _os << lround(bezier.point(i).x()) << ' ' << lround(bezier.point(i).y()) << ' '; - _os << 'c'; - } - else { - for (int i=0; i < n; i++) - _os << points[i].x() << ' ' << points[i].y() << ' '; - switch (cmd) { - case 'M': _os << 'm'; _startPoint = points[0]; break; - case 'L': _os << 'l'; break; - case 'C': _os << 'c'; break; - case 'Z': _os << _startPoint.x() << ' ' << _startPoint.y() << " l"; _currentPoint = _startPoint; break; - } - } - if (n > 0) - _currentPoint = points[n-1]; - _os << " 0\n"; +struct SFDActions : Glyph::IterationActions { + explicit SFDActions (ostream &os) : _os(os) {} + + using Point = Glyph::Point; + void moveto (const Point &p) override {write('m', p);} + void lineto (const Point &p) override {write('l', p);} + void cubicto (const Point &p1, const Point &p2, const Point &p3) override {write('c', p1, p2, p3); } + void closepath () override {write('m', startPoint());} + + void quadto (const Point &p1, const Point &p2) override { + // convert quadratic Bézier curve to cubic one + DPair pt0(currentPoint().x(), currentPoint().y()); + DPair pt1(p1.x(), p1.y()); + DPair pt2(p2.x(), p2.y()); + Bezier b(pt0, pt1, pt2); + write('c', round(b.point(0)), round(b.point(1)), round(b.point(2)), round(b.point(3))); } + + template <typename ...Args> + void write (char cmd, const Args& ...args) { + writeParams(args...); + _os << cmd << " 0\n"; + } + + static void writeParams () {} + + template <typename Pt, typename ...Args> + void writeParams (const Pt &p, const Args& ...args) const { + _os << p.x() << ' ' << p.y() << ' '; + writeParams(args...); + } + ostream &_os; Glyph::Point _startPoint, _currentPoint; }; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/FontWriter.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/FontWriter.hpp index 3becdf2618d..458952cad9b 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/FontWriter.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/FontWriter.hpp @@ -36,9 +36,9 @@ class FontWriter { static bool AUTOHINT_FONTS; public: - FontWriter (const PhysicalFont &font); - std::string createFontFile (FontFormat format, const std::set<int> &charcodes, GFGlyphTracer::Callback *cb=0) const; - bool writeCSSFontFace (FontFormat format, const std::set<int> &charcodes, std::ostream &os, GFGlyphTracer::Callback *cb=0) const; + explicit FontWriter (const PhysicalFont &font); + std::string createFontFile (FontFormat format, const std::set<int> &charcodes, GFGlyphTracer::Callback *cb=nullptr) const; + bool writeCSSFontFace (FontFormat format, const std::set<int> &charcodes, std::ostream &os, GFGlyphTracer::Callback *cb=nullptr) const; static FontFormat toFontFormat (std::string formatstr); static std::vector<std::string> supportedFormats (); @@ -59,7 +59,7 @@ class FontWriter { struct FontWriterException : MessageException { - FontWriterException (const std::string &msg) : MessageException(msg) {} + explicit FontWriterException (const std::string &msg) : MessageException(msg) {} }; #endif diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/GFGlyphTracer.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/GFGlyphTracer.cpp index 0a3b653540d..85f7c2cab56 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/GFGlyphTracer.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/GFGlyphTracer.cpp @@ -22,7 +22,7 @@ using namespace std; -GFGlyphTracer::GFGlyphTracer () : GFTracer(_ifs, 0), _glyph(0), _callback(0) +GFGlyphTracer::GFGlyphTracer () : GFTracer(_ifs, 0) { } @@ -30,7 +30,7 @@ GFGlyphTracer::GFGlyphTracer () : GFTracer(_ifs, 0), _glyph(0), _callback(0) * @param[in] is GF input stream * @param[in] upp target units per PS point */ GFGlyphTracer::GFGlyphTracer (string &fname, double upp, Callback *cb) - : GFTracer(_ifs, upp), _glyph(0), _callback(cb) + : GFTracer(_ifs, upp), _callback(cb) { if (_callback) _callback->setFont(fname); diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/GFGlyphTracer.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/GFGlyphTracer.hpp index c6304c090b3..49f69b69ec7 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/GFGlyphTracer.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/GFGlyphTracer.hpp @@ -39,7 +39,7 @@ class GFGlyphTracer : public GFTracer public: GFGlyphTracer (); - GFGlyphTracer (std::string &fname, double upp, Callback *cb=0); + GFGlyphTracer (std::string &fname, double upp, Callback *cb=nullptr); void reset (std::string &fname, double upp); void setCallback (Callback *cb) {_callback = cb;} bool executeChar (uint8_t c) override; @@ -53,8 +53,8 @@ class GFGlyphTracer : public GFTracer private: std::ifstream _ifs; - Glyph *_glyph; - Callback *_callback; + Glyph *_glyph = nullptr; + Callback *_callback = nullptr; }; #endif diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/GFReader.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/GFReader.cpp index 3cba8e50691..32ba354443f 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/GFReader.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/GFReader.cpp @@ -106,11 +106,8 @@ int GFReader::executeCommand () { cmdPaint0(opcode); else if (opcode >= 74 && opcode <= 238) cmdNewRow(opcode-74); - else if (opcode >= 250) { - ostringstream oss; - oss << "undefined GF command (opcode " << opcode << ")"; - throw GFException(oss.str()); - } + else if (opcode >= 250) + throw GFException("undefined GF command (opcode " + std::to_string(opcode) + ")"); else { int offset = opcode <= 73 ? 64 : 239-(73-64+1); const GFCommand &cmd = commands[opcode-offset]; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/GFReader.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/GFReader.hpp index 87a9a75f5f2..3dfceb98cd6 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/GFReader.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/GFReader.hpp @@ -31,16 +31,13 @@ class CharInfo; -struct GFException : public MessageException -{ - GFException (const std::string &msg) : MessageException(msg) {} +struct GFException : public MessageException { + explicit GFException (const std::string &msg) : MessageException(msg) {} }; -class GFReader -{ - struct CharInfo - { +class GFReader { + struct CharInfo { CharInfo () : dx(0), dy(0), width(0), location(0) {} CharInfo (int32_t dxx, int32_t dyy, int32_t w, uint32_t p) : dx(dxx), dy(dyy), width(w), location(p) {} diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/GFTracer.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/GFTracer.hpp index 6e7875eba39..8fe746cc05d 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/GFTracer.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/GFTracer.hpp @@ -24,12 +24,10 @@ #include <istream> #include "GFReader.hpp" -class GFTracer : public GFReader -{ +class GFTracer : public GFReader { public: - GFTracer (std::istream &is); + explicit GFTracer (std::istream &is); GFTracer (std::istream &is, double upp); - virtual ~GFTracer () =default; virtual void moveTo (double x, double y) =0; virtual void lineTo (double x, double y) =0; virtual void curveTo (double c1x, double c1y, double c2x, double c2y, double x, double y) =0; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/Ghostscript.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/Ghostscript.cpp index ff57d213b1d..c097ace667a 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/Ghostscript.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/Ghostscript.cpp @@ -66,7 +66,7 @@ static string get_path_from_registry () { if (major_version >= 7) { char dll_path[512]; // path to Ghostscript DLL stored in the registry DWORD length = 512; - if (RegGetValueA(hkey, subkey, "GS_DLL", RRF_RT_REG_SZ, 0, dll_path, &length) == ERROR_SUCCESS) { + if (RegGetValueA(hkey, subkey, "GS_DLL", RRF_RT_REG_SZ, nullptr, dll_path, &length) == ERROR_SUCCESS) { RegCloseKey(hkey); return dll_path; } @@ -160,7 +160,6 @@ Ghostscript::Ghostscript () : DLLoader(get_libgs(LIBGS_NAME)) #endif { - _inst = 0; } @@ -173,7 +172,6 @@ Ghostscript::Ghostscript (int argc, const char **argv, void *caller) : DLLoader(get_libgs(LIBGS_NAME)) #endif { - _inst = 0; init(argc, argv, caller); } @@ -191,12 +189,12 @@ bool Ghostscript::init (int argc, const char **argv, void *caller) { if (!_inst) { int status = new_instance(&_inst, caller); if (status < 0) - _inst = 0; + _inst = nullptr; else { init_with_args(argc, const_cast<char**>(argv)); } } - return _inst != 0; + return _inst != nullptr; } @@ -257,7 +255,7 @@ int Ghostscript::new_instance (void **psinst, void *caller) { #else if (auto fn = LOAD_SYMBOL(gsapi_new_instance)) return fn(psinst, caller); - *psinst = 0; + *psinst = nullptr; return 0; #endif } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/Ghostscript.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/Ghostscript.hpp index 676da3909d8..4ea62f775f5 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/Ghostscript.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/Ghostscript.hpp @@ -73,10 +73,10 @@ class Ghostscript public: Ghostscript (); - Ghostscript (int argc, const char **argv, void *caller=0); + Ghostscript (int argc, const char **argv, void *caller=nullptr); Ghostscript (const Ghostscript &gs) =delete; ~Ghostscript (); - bool init (int argc, const char **argv, void *caller=0); + bool init (int argc, const char **argv, void *caller=nullptr); bool available (); bool revision (gsapi_revision_t *r); int revision (); @@ -96,7 +96,7 @@ class Ghostscript void delete_instance (); private: - void *_inst; ///< Ghostscript handle needed to call the gsapi_foo functions + void *_inst = nullptr; ///< Ghostscript handle needed to call the gsapi_foo functions }; #endif // DISABLE_GS diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/GlyphTracerMessages.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/GlyphTracerMessages.hpp index 579d6720b94..8a41b811d99 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/GlyphTracerMessages.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/GlyphTracerMessages.hpp @@ -25,12 +25,11 @@ #include "GFGlyphTracer.hpp" #include "Message.hpp" -class GlyphTracerMessages : public GFGlyphTracer::Callback -{ +class GlyphTracerMessages : public GFGlyphTracer::Callback { public: - GlyphTracerMessages (bool sfmsg=true, bool autonl=true) : _sfmsg(sfmsg), _autonl(autonl), _traced(false) {} + explicit GlyphTracerMessages (bool sfmsg=true, bool autonl=true) : _sfmsg(sfmsg), _autonl(autonl), _traced(false) {} - ~GlyphTracerMessages () { + ~GlyphTracerMessages () override { if (_autonl) Message::mstream() << '\n'; } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/GraphicsPath.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/GraphicsPath.hpp index 31e8e3521d1..78b29d46307 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/GraphicsPath.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/GraphicsPath.hpp @@ -18,17 +18,148 @@ ** along with this program; if not, see <http://www.gnu.org/licenses/>. ** *************************************************************************/ -#ifndef GRAPHICSPATH_HPP -#define GRAPHICSPATH_HPP +#pragma once +#include <array> #include <cctype> #include <deque> #include <ostream> +#include <type_traits> +#include <mpark/variant.hpp> #include "BoundingBox.hpp" +#include "EllipticalArc.hpp" #include "Matrix.hpp" #include "Pair.hpp" +#include "utility.hpp" #include "XMLString.hpp" +template <typename T> +class GraphicsPath; + +namespace gp { + +/// Base class for all path data commands, like moveto, lineto, curveto, etc. +struct CommandBase {}; + +/** Base class for all path data commands with NUM_POINTS point parameters + * @tparam NUM_POINTS number of parameter pairs representing points, e.g. 1 for moveto and lineto */ +template <typename T, int NUM_POINTS> +class Command : public CommandBase { + friend class GraphicsPath<T>; + public: + int numPoints () const {return NUM_POINTS;} + Pair<T>& point (int n) {return points[n];} + const Pair<T>& point (int n) const {return points[n];} + + /** Transforms the command by a given transformation matrix. + * @params[in] matrix describes the affine transformation to apply + * @params[in] currentPoint the untransformed end point of the preceding command */ + void transform (const Matrix &matrix, const Pair<T> ¤tPoint) { + for (Pair<T> &p : points) + p = matrix * p; + } + + /** Returns true if all points are identical to those of another command. */ + bool pointsEqual (const Command &cmd) const { + for (int i=0; i < NUM_POINTS; i++) + if (points[i] != cmd.points[i]) + return false; + return true; + } + + protected: + explicit Command () =default; + explicit Command (std::array<Pair<T>, NUM_POINTS> &&pts) : points(std::move(pts)) {} + + protected: + std::array<Pair<T>, NUM_POINTS> points; +}; + +template <typename T> +struct MoveTo : public Command<T, 1> { + explicit MoveTo (const Pair<T> &p) : Command<T, 1>({p}) {} +}; + +template <typename T> +struct LineTo : public Command<T, 1> { + explicit LineTo (const Pair<T> &p) : Command<T, 1>({p}) {} +}; + +template <typename T> +struct CubicTo : public Command<T, 3> { + explicit CubicTo (const Pair<T> &p1, const Pair<T> &p2, const Pair<T> &p3) : Command<T, 3>({p1, p2, p3}) {} +}; + +template <typename T> +struct QuadTo : public Command<T, 2> { + explicit QuadTo (const Pair<T> &p1, const Pair<T> &p2) : Command<T, 2>({p1, p2}) {} +}; + +template <typename T> +struct ClosePath : public Command<T, 0> { + ClosePath () : Command<T, 0>() {} +}; + +template <typename T> +struct ArcTo : Command<T, 1> { + ArcTo (T rxx, T ryy, double xrot, bool laf, bool sf, const Pair<T> &pp) + : Command<T, 1>({pp}), rx(rxx < 0 ? -rxx : rxx), ry(ryy < 0 ? -ryy : ryy), + xrotation(xrot), largeArcFlag(laf), sweepFlag(sf) {} + + bool operator == (const ArcTo &arc) const { + return rx == arc.rx + && ry == arc.ry + && xrotation == arc.xrotation + && largeArcFlag == arc.largeArcFlag + && sweepFlag == arc.sweepFlag + && this->points[0] == arc.points[0]; + } + + void transform (const Matrix &matrix, const Pair<T> ¤tPoint); + + bool operator != (const ArcTo &arc) const {return !(*this == arc);} + + T rx, ry; ///< length of the semi-major and semi-minor axes + double xrotation; ///< rotation of the semi-major axis in degrees + bool largeArcFlag; ///< if true, the longer arc from start to end point is chosen, else the shorter one + bool sweepFlag; ///< if true, arc is drawn in direction of positive angles, else the opposite direction +}; + +/** Applies an affine transformation described by a given matrix to the arc segment. + * @params[in] matrix describes the affine transformation to apply + * @params[in] currentPoint the untransformed end point of the preceding command */ +template <typename T> +void ArcTo<T>::transform (const Matrix &matrix, const Pair<T> ¤tPoint) { + EllipticalArc arc(currentPoint, rx, ry, math::deg2rad(xrotation), largeArcFlag, sweepFlag, this->points[0]); + arc.transform(matrix); + rx = arc.rx(); + ry = arc.ry(); + xrotation = math::rad2deg(arc.rotationAngle()); + largeArcFlag = arc.largeArc(); + sweepFlag = arc.sweepPositive(); + this->points[0] = Pair<T>(arc.endPoint()); +} + +/** Returns true if two path command objects are identical (same command and same parameters). */ +template <typename Cmd1, typename Cmd2> +inline typename std::enable_if<std::is_base_of<CommandBase, Cmd1>::value, bool>::type +operator == (const Cmd1 &cmd1, const Cmd2 &cmd2) { + if (std::is_convertible<Cmd1, Cmd2>::value && std::is_convertible<Cmd2, Cmd1>::value) + return cmd1.pointsEqual(cmd2); + return false; +} + +/** Returns true if two path command objects differ (different commands or different parameters). */ +template <typename Cmd1, typename Cmd2> +inline typename std::enable_if<std::is_base_of<CommandBase, Cmd1>::value, bool>::type +operator != (const Cmd1 &cmd1, const Cmd2 &cmd2) { + if (std::is_convertible<Cmd1, Cmd2>::value && std::is_convertible<Cmd2, Cmd1>::value) + return !cmd1.pointsEqual(cmd2); + return true; +} + +} // namespace gp + template <typename T> class GraphicsPath { @@ -37,78 +168,272 @@ class GraphicsPath { enum class WindingRule {EVEN_ODD, NON_ZERO}; using Point = Pair<T>; - struct Command { - enum class Type {MOVETO, LINETO, CONICTO, CUBICTO, CLOSEPATH}; + protected: - Command (Type t) : type(t) {} + static XMLString to_param_str (double v, double s, double d, bool leadingSpace) { + XMLString str(v*s + d); + if (leadingSpace && (str[0] != '-')) + str.insert(0, " "); + return str; + } - Command (Type t, const Point &p) : type(t) { - params[0] = p; - } + static XMLString to_param_str (double val, double prev, double s, double d, bool leadingSpace) { + XMLString str((val-prev)*s + d); + if (leadingSpace && (str[0] != '-')) + str.insert(0, " "); + return str; + } - Command (Type t, const Point &p1, const Point &p2) : type(t) { - params[0] = p1; - params[1] = p2; - } + static std::string to_param_str (const Point &p, double sx, double sy, double dx, double dy, bool leadingSpace) { + return to_param_str(p.x(), sx, dx, leadingSpace) + to_param_str(p.y(), sy, dy, true); + } - Command (Type t, const Point &p1, const Point &p2, const Point &p3) : type(t) { - params[0] = p1; - params[1] = p2; - params[2] = p3; - } + static std::string to_param_str (const Point &p, const Point &prev, double sx, double sy, double dx, double dy, bool leadingSpace) { + return to_param_str(p.x()-prev.x(), sx, dx, leadingSpace) + to_param_str(p.y()-prev.y(), sy, dy, true); + } + + using MoveTo = gp::MoveTo<T>; + using LineTo = gp::LineTo<T>; + using CubicTo = gp::CubicTo<T>; + using QuadTo = gp::QuadTo<T>; + using ArcTo = gp::ArcTo<T>; + using ClosePath = gp::ClosePath<T>; + + /// Variant representing a single path command + using CommandVariant = mpark::variant<MoveTo, LineTo, CubicTo, QuadTo, ArcTo, ClosePath>; + + class IterationVisitor; + + public: + /** Base class providing several template methods being called when executing + * GraphicsPath::iterate(). */ + class IterationActions { + friend class IterationVisitor; + public: + virtual ~IterationActions () =default; + virtual void moveto (const Point &p) {} + virtual void lineto (const Point &p) {} + virtual void hlineto (const T &x) {} + virtual void vlineto (const T &y) {} + virtual void quadto (const Point &p) {} + virtual void quadto (const Point &p1, const Point &p2) {} + virtual void cubicto (const Point &p1, const Point &p2) {} + virtual void cubicto (const Point &p1, const Point &p2, const Point &p3) {} + virtual void arcto (T rx, T ry, double angle, bool largeArcFlag, bool sweepFlag, const Point &p) {} + virtual void closepath () {} + virtual bool quit () {return false;} + virtual void finished () {} + const Point& startPoint () const {return _startPoint;} + const Point& currentPoint () const {return _currentPoint;} + + private: + Point _startPoint; ///< first point of the current sub-path + Point _currentPoint; ///< point reached by preceding path command, or (0,0) otherwise + }; + + protected: + class ModificationActions : public IterationActions { + friend class GraphicsPath; + public: + explicit ModificationActions (GraphicsPath &path) : _path(path) {} - int numParams () const { - switch (type) { - case Type::CLOSEPATH : return 0; - case Type::MOVETO : - case Type::LINETO : return 1; - case Type::CONICTO : return 2; - case Type::CUBICTO : return 3; + protected: + GraphicsPath& path () {return _path;} + int commandPos () const {return _commandPos;} + + private: + GraphicsPath &_path; + int _commandPos=0; ///< number of command in path being processed + }; + + class WriteActions : public IterationActions { + public: + WriteActions (std::ostream &os, bool rel, double sx, double sy, double dx, double dy) + : _os(os), _relative(rel), _sx(sx), _sy(sy), _dx(dx), _dy(dy) {} + + void moveto (const Point &p) override {write('M', {p});} + void lineto (const Point &p) override {write('L', {p});} + void hlineto (const T &x) override {write('H', x, this->currentPoint().x(), _sx, _dx);} + void vlineto (const T &y) override {write('V', y, this->currentPoint().y(), _sy, _dy);} + void quadto (const Point &p) override {write('T', {p});} + void quadto (const Point &p1, const Point &p2) override {write('Q', {p1, p2});} + void cubicto (const Point &p1, const Point &p2) override {write('S', {p1, p2});} + void cubicto (const Point &p1, const Point &p2, const Point &p3) override {write('C', {p1, p2, p3});} + void closepath () override {_os << (_relative ? 'z' : 'Z');} + + void arcto (T rx, T ry, double angle, bool largeArcFlag, bool sweepFlag, const Point &p) override { + Point diff = p-this->currentPoint(); + if (std::abs(diff.x()) < 1e-7 && std::abs(diff.y()) < 1e-7) + return; + if (std::abs(rx) < 1e-7 && std::abs(ry) < 1e-7) + lineto(p); + else { + if (std::abs(std::abs(_sx) - std::abs(_sy)) < 1e-7) { // symmetric scaling? + angle *= math::sgn(_sx) * math::sgn(_sy); + rx *= std::abs(_sx); + ry *= std::abs(_sx); + } + else { // asymmetric scaling => compute new shape parameters + EllipticalArc arc(this->currentPoint(), double(rx), double(ry), math::deg2rad(angle), largeArcFlag, sweepFlag, p); + arc.transform(ScalingMatrix(_sx, _sy)); + angle = math::rad2deg(arc.rotationAngle()); + rx = arc.rx(); + ry = arc.ry(); + } + _os << (_relative ? 'a' : 'A') + << to_param_str(rx, 1.0, 0, false) + << to_param_str(ry, 1.0, 0, true) + << to_param_str(angle, 1.0, 0, true) + << ' ' << (largeArcFlag ? 1 : 0) + << ' ' << (sweepFlag ? 1 : 0); + if (_relative) + _os << to_param_str(p, this->currentPoint(), _sx, _sy, _dx, _dy, true); + else + _os << to_param_str(p, _sx, _sy, _dx, _dy, true); + } } - return 0; - } - void transform (const Matrix &matrix) { - for (int i=0; i < numParams(); i++) - params[i] = matrix * params[i]; - } + protected: + void write (char cmdchar, std::initializer_list<Point> points) const { + int count=0; + if (_relative) { + _os << char(tolower(cmdchar)); + for (const Point &p : points) + _os << to_param_str(p, this->currentPoint(), _sx, _sy, _dx, _dy, count++ > 0); + } + else { + _os << cmdchar; + for (const Point &p : points) + _os << to_param_str(p, _sx, _sy, _dx, _dy, count++ > 0); + } + } - bool operator == (const Command &cmd) const { - bool ret = (type == cmd.type); - for (int i=0; ret && i < numParams(); i++) - ret &= (params[i] == cmd.params[i]); - return ret; - } + void write (char cmdchar, T val, T relval, double s, double d) const { + if (_relative) + _os << char(tolower(cmdchar)) << to_param_str(val, relval, s, d, false); + else + _os << cmdchar << to_param_str(val, s, d, false); + } - bool operator != (const Command &cmd) const { - bool ret = (type != cmd.type); - for (int i=0; !ret && i < numParams(); i++) - ret |= (params[i] != cmd.params[i]); - return ret; - } + private: + std::ostream &_os; ///< write output to this stream + bool _relative; ///< if true, use relative coordinates in path commands + double _sx, _sy; ///< horizontal and vertical scaling factors + double _dx, _dy; ///< horizontal and vertical translation values + }; + + /////////////////////////////////////////////////////////////////////////////// + + /** Calls the corresponding template method of an Action object for the current path command. + * If parameter 'useShortCmds' is true, the visitor operators check whether a command + * can be shortened due to special cases, e.g. horizontal or vertical lines, smooth + * curve connections etc. Otherwise, the full command templates are triggered. */ + class IterationVisitor { + public: + IterationVisitor (IterationActions &actions, bool useShortCmds, double eps=1e-7) + : _actions(actions), _shortCommandsActive(useShortCmds), _eps(eps) {} + + void setPrevCommand (const CommandVariant &prevCommand) { + _prevCommand = &prevCommand; + } + + void operator () (const MoveTo &cmd) { + _actions.moveto(cmd.points[0]); + _actions._startPoint = _actions._currentPoint = cmd.points[0]; + } + + void operator () (const LineTo &cmd) { + Point diff = abs(_actions._currentPoint-cmd.points[0]); + if (diff.x() >= _eps || diff.y() >= _eps) { + if (!_shortCommandsActive) + _actions.lineto(cmd.points[0]); + else { + if (diff.x() < _eps) + _actions.vlineto(cmd.points[0].y()); + else if (diff.y() < _eps) + _actions.hlineto(cmd.points[0].x()); + else + _actions.lineto(cmd.points[0]); + } + } + _actions._currentPoint = cmd.points[0]; + } + + void operator () (const CubicTo &cmd) { + bool smooth=false; + if (_shortCommandsActive) { + if (auto *prevCubic = mpark::get_if<CubicTo>(_prevCommand)) { + Point diff = abs(cmd.points[0] - prevCubic->points[2]*T(2) + prevCubic->points[1]); + if ((smooth = (diff.x() < _eps && diff.y() < _eps))) + _actions.cubicto(cmd.points[1], cmd.points[2]); + } + } + if (!smooth) + _actions.cubicto(cmd.points[0], cmd.points[1], cmd.points[2]); + _actions._currentPoint = cmd.points[2]; + } + + void operator () (const QuadTo &cmd) { + bool smooth=false; + if (_shortCommandsActive) { + if (auto *prevQuad = mpark::get_if<QuadTo>(_prevCommand)) { + Point diff = abs(cmd.points[0] - prevQuad->points[1] * T(2) + prevQuad->points[0]); + if ((smooth = (diff.x() < _eps && diff.y() < _eps))) // is reflection? + _actions.quadto(cmd.points[1]); + } + } + if (!smooth) + _actions.quadto(cmd.points[0], cmd.points[1]); + _actions._currentPoint = cmd.points[1]; + } + + void operator () (const ClosePath &cmd) { + _actions.closepath(); + _actions._currentPoint = _actions._startPoint; + } + + void operator () (const ArcTo &cmd) { + _actions.arcto(cmd.rx, cmd.ry, cmd.xrotation, cmd.largeArcFlag, cmd.sweepFlag, cmd.points[0]); + _actions._currentPoint = cmd.points[0]; + } - Type type; - Point params[3]; + private: + IterationActions &_actions; + bool _shortCommandsActive=false; + double _eps=1e-7; + const CommandVariant *_prevCommand=nullptr; }; - struct Actions { - virtual ~Actions () =default; - virtual void moveto (const Point &p) {} - virtual void lineto (const Point &p) {} - virtual void hlineto (const T &y) {} - virtual void vlineto (const T &x) {} - virtual void conicto (const Point &p) {} - virtual void conicto (const Point &p1, const Point &p2) {} - virtual void cubicto (const Point &p1, const Point &p2) {} - virtual void cubicto (const Point &p1, const Point &p2, const Point &p3) {} - virtual void closepath () {} - virtual void draw (char cmd, const Point *points, int n) {} - virtual bool quit () {return false;} - virtual void finished () {} + /////////////////////////////////////////////////////////////////////////////// + + /** Transforms all Point parameters of a path command. */ + class TransformVisior { + public: + explicit TransformVisior (const Matrix &m) : matrix(m) {} + + template <typename Cmd> void operator () (Cmd &cmd) { + Point cp = cmd.point(cmd.numPoints()-1); + cmd.transform(matrix, _currentPoint); + _currentPoint = cp; + } + + void operator () (MoveTo &cmd) { + Point cp = cmd.point(0); + cmd.transform(matrix, _currentPoint); + _startPoint = _currentPoint = cp; + } + + void operator () (ClosePath &cmd) { + _currentPoint = _startPoint; + } + + private: + const Matrix &matrix; + Point _startPoint, _currentPoint; ///< untransformed start end current point }; public: - GraphicsPath (WindingRule wr=WindingRule::NON_ZERO) : _windingRule(wr) {} + explicit GraphicsPath (WindingRule wr=WindingRule::NON_ZERO) : _windingRule(wr) {} void setWindingRule (WindingRule wr) {_windingRule = wr;} WindingRule windingRule () const {return _windingRule;} @@ -127,6 +452,9 @@ class GraphicsPath { return _commands.size(); } + const Point& startPoint () const {return _startPoint;} + const Point& finalPoint () const {return _finalPoint;} + /// Insert another path at the beginning of this one. void prepend (const GraphicsPath &path) { _commands.insert(_commands.begin(), path._commands.begin(), path._commands.end()); @@ -138,10 +466,11 @@ class GraphicsPath { void moveto (const Point &p) { // avoid sequences of several MOVETOs; always use latest - if (_commands.empty() || _commands.back().type != Command::Type::MOVETO) - _commands.emplace_back(Command(Command::Type::MOVETO, p)); + if (_commands.empty() || !mpark::get_if<MoveTo>(&_commands.back())) + _commands.emplace_back(MoveTo{p}); else - _commands.back().params[0] = p; + mpark::get<MoveTo>(_commands.back()).points[0] = p; + _startPoint = _finalPoint = p; } void lineto (const T &x, const T &y) { @@ -149,57 +478,94 @@ class GraphicsPath { } void lineto (const Point &p) { - _commands.emplace_back(Command(Command::Type::LINETO, p)); + _commands.emplace_back(LineTo{p}); + _finalPoint = p; } - void conicto (const T &x1, const T &y1, const T &x2, const T &y2) { - conicto(Point(x1, y1), Point(x2, y2)); + void quadto (const T &x1, const T &y1, const T &x2, const T &y2) { + quadto(Point(x1, y1), Point(x2, y2)); } - void conicto (const Point &p1, const Point &p2) { - _commands.emplace_back(Command(Command::Type::CONICTO, p1, p2)); + /** Creates a quadratic Bézier segment. */ + void quadto (const Point &p1, const Point &p2) { + _commands.emplace_back(QuadTo{p1, p2}); + _finalPoint = p2; + } + + /** Creates a quadratic Bézier segment smoothly extending a preceding one, i.e. the gradients + * of the two curves are identical at the connection point. The control point of the second + * curve is computed as the reflection of the preceding curve's control point at the connection + * point. */ + void quadto (const Point &p2) { + Point p1; + if (!_commands.empty()) { + if (auto qto = mpark::get_if<QuadTo>(&_commands.back())) + p1 = _finalPoint*T(2) - qto->point(0); // reflect previous control point at current point + else // previous command isn't a quadto? + p1 = _finalPoint; // => use current point as control point + } + quadto(p1, p2); } void cubicto (const T &x1, const T &y1, const T &x2, const T &y2, const T &x3, const T &y3) { cubicto(Point(x1, y1), Point(x2, y2), Point(x3, y3)); } + /** Creates a cubic Bézier segment. */ void cubicto (const Point &p1, const Point &p2, const Point &p3) { - _commands.emplace_back(Command(Command::Type::CUBICTO, p1, p2, p3)); + _commands.emplace_back(CubicTo{p1, p2, p3}); + _finalPoint = p3; } - void closepath () { - _commands.emplace_back(Command(Command::Type::CLOSEPATH)); + /** Creates a cubic Bézier segment smoothly extending a preceding one, i.e. the gradients + * of the two curves are identical at the connection point. The first control point of + * the second curve is computed as the reflection of the preceding curve's second control + * point at the connection point. */ + void cubicto (const Point &p2, const Point &p3) { + Point p1; + if (!_commands.empty()) { + if (auto cto = mpark::get_if<CubicTo>(&_commands.back())) + p1 = _finalPoint*T(2) - cto->point(1); // reflect previous control point at current point + else // previous command isn't a cubicto? + p1 = _finalPoint; // => use current point as control point + } + cubicto(p1, p2, p3); } - const std::vector<Command>& commands () const { - return _commands; + void closepath () { + if (!_commands.empty() && !mpark::get_if<ClosePath>(&_commands.back())) { + _commands.emplace_back(ClosePath{}); + _finalPoint = _startPoint; + } } + void arcto (double rx, double ry, double angle, bool laf, bool sweep, const Point &p) { + _commands.emplace_back(ArcTo{rx, ry, angle, laf, sweep, p}); + _finalPoint = p; + } /** Detects all open subpaths and closes them by adding a closePath command. * Most font formats only support closed outline paths so there are no explicit closePath statements * in the glyph's outline description. All open paths are automatically closed by the renderer. * This method detects all open paths and adds the missing closePath statement. */ void closeOpenSubPaths () { - Command *prevCommand=0; + CommandVariant *prevCmd = nullptr; for (auto it=_commands.begin(); it != _commands.end(); ++it) { - if (it->type == Command::Type::MOVETO && prevCommand && prevCommand->type != Command::Type::CLOSEPATH) { - prevCommand = &(*it); - it = _commands.insert(it, Command(Command::Type::CLOSEPATH))+1; + if (mpark::get_if<MoveTo>(&*it) && prevCmd && !mpark::get_if<ClosePath>(prevCmd)) { + prevCmd = &*it; + it = _commands.insert(it, ClosePath{})+1; } else - prevCommand = &(*it); + prevCmd = &*it; } - if (!_commands.empty() && _commands.back().type != Command::Type::CLOSEPATH) + if (!_commands.empty() && !mpark::get_if<ClosePath>(&_commands.back())) closepath(); } - - /** Removes redundant path commands commands. Currently, it only removes movetos. */ + /** Removes redundant path commands commands. Currently, only removes movetos. */ void removeRedundantCommands () { // remove trailing moveto commands - while (!_commands.empty() && _commands.back().type == Command::Type::MOVETO) + while (!_commands.empty() && mpark::get_if<MoveTo>(&_commands.back())) _commands.pop_back(); // resolve intermediate sequences of moveto commands auto it=_commands.begin(); @@ -207,7 +573,7 @@ class GraphicsPath { return; auto prev = it++; while (it != _commands.end()) { - if (prev->type != Command::Type::MOVETO || it->type != Command::Type::MOVETO) + if (!mpark::get_if<MoveTo>(&*prev) || !mpark::get_if<MoveTo>(&*it)) prev = it++; else { prev = _commands.erase(prev); // remove leading MOVETO and advance 'prev' to 'it' @@ -216,7 +582,6 @@ class GraphicsPath { } } - /** Writes the path data as SVG path drawing command to a given output stream. * @param[in] os output stream used to write the SVG commands to * @param[in] relative if true, create relative rather than absolute coordinate values @@ -225,94 +590,38 @@ class GraphicsPath { * @param[in] dx horizontal translation in PS point units * @param[in] dy vertical translation in PS point units */ void writeSVG (std::ostream &os, bool relative, double sx=1.0, double sy=1.0, double dx=0.0, double dy=0.0) const { - struct WriteActions : Actions { - WriteActions (std::ostream &os, bool relative, double sx, double sy, double dx, double dy) - : _os(os), _relative(relative), _sx(sx), _sy(sy), _dx(dx), _dy(dy) {} - - void draw (char cmd, const Point *points, int n) override { - if (_relative) - cmd = tolower(cmd); - _os << cmd; - switch (cmd) { - case 'h': _os << XMLString(_sx*(points->x()-_currentPoint.x())+_dx); break; - case 'v': _os << XMLString(_sy*(points->y()-_currentPoint.y())+_dy); break; - case 'z': _currentPoint = _startPoint; break; - case 'H': _os << XMLString(_sx*points->x()+_dx); break; - case 'V': _os << XMLString(_sy*points->y()+_dy); break; - default : - for (int i=0; i < n; i++) { - if (i > 0) - _os << ' '; - Point p = points[i]; - if (_relative) - p -= _currentPoint; - _os << XMLString(_sx*p.x()+_dx) << ' ' << XMLString(_sy*p.y()+_dy); - } - } - if (cmd == 'm') - _startPoint = points[0]; - if (islower(cmd) && n > 0) - _currentPoint = points[n-1]; - } - std::ostream &_os; - bool _relative; - double _sx, _sy, _dx, _dy; - Point _startPoint, _currentPoint; - } actions(os, relative, sx, sy, dx, dy); + WriteActions actions(os, relative, sx, sy, dx, dy); iterate(actions, true); } -#if 0 - void writePS (std::ostream &os, double sx=1.0, double sy=1.0, double dx=0.0, double dy=0.0) const { - struct WriteActions : Actions { - WriteActions (std::ostream &os, double sx, double sy, double dx, double dy) - : _os(os), _sx(sx), _sy(sy), _dx(dx), _dy(dy) {} - void draw (char cmd, const Point *points, int n) { - for (int i=0; i < n; i++) - _os << _sx*points[i].x()+_dx << ' ' << _sy*points[i].y()+_dy << ' '; - switch (cmd) { - case 'M': _os << "moveto"; break; - case 'L': _os << "lineto"; break; - case 'C': _os << "curveto"; break; - case 'Z': _os << "closepath"; break; - default: ; - } - _os << '\n'; - } - std::ostream &_os; - bool _relative; - double _sx, _sy, _dx, _dy; - } actions(os, sx, sy, dx, dy); - iterate(actions, false); - } -#endif - - /** Computes the bounding box of the current path. * @param[out] bbox the computed bounding box */ void computeBBox (BoundingBox &bbox) const { - struct BBoxActions : Actions { - BBoxActions (BoundingBox &bb) : bbox(bb) {} + struct BBoxActions : IterationActions { + explicit BBoxActions (BoundingBox &bb) : bbox(bb) {} void moveto (const Point &p) override {bbox.embed(p);} void lineto (const Point &p) override {bbox.embed(p);} - void conicto (const Point &p1, const Point &p2) override {bbox.embed(p1); bbox.embed(p2);} + void quadto (const Point &p1, const Point &p2) override {bbox.embed(p1); bbox.embed(p2);} void cubicto (const Point &p1, const Point &p2, const Point &p3) override {bbox.embed(p1); bbox.embed(p2); bbox.embed(p3);} + void arcto (T rx, T ry, double angle, bool laf, bool sweep, const Point &p) override { + bbox.embed(EllipticalArc(this->currentPoint(), double(rx), double(ry), angle, laf, sweep, p).getBBox()); + } BoundingBox &bbox; } actions(bbox); iterate(actions, false); } - /** Checks whether the current path describes a dot/point only (with no extent). * @param[out] p coordinates of the point if path describes a dot * @return true if path is a dot/point */ bool isDot (Point &p) const { - struct DotActions : Actions { + struct DotActions : IterationActions { DotActions () : differs(false) {} void moveto (const Point &p) override {point = p;} void lineto (const Point &p) override {differs = (p != point);} - void conicto (const Point &p1, const Point &p2) override {differs = (point != p1 || point != p2);} + void quadto (const Point &p1, const Point &p2) override { differs = (point != p1 || point != p2);} void cubicto (const Point &p1, const Point &p2, const Point &p3) override {differs = (point != p1 || point != p2 || point != p3);} + void arcto (T rx, T ry, double angle, bool largeArcFlag, bool sweepFlag, const Point &p) override { differs = (point != p);} bool quit () override {return differs;} Point point; bool differs; @@ -322,125 +631,105 @@ class GraphicsPath { return !actions.differs; } + /** Replaces all elliptic arcs with cubic Bézier curves. */ + void approximateArcs () { + struct ArcActions : ModificationActions { + explicit ArcActions (GraphicsPath &path) : ModificationActions(path) {} + void arcto (T rx, T ry, double angle, bool largeArcFlag, bool sweepFlag, const Point &p) override { + EllipticalArc arc(this->currentPoint(), rx, ry, angle, largeArcFlag, sweepFlag, p); + std::vector<CommandVariant> cmds; + for (const Bezier &bezier : arc.approximate()) + cmds.emplace_back(CubicTo{bezier.point(1), bezier.point(2), bezier.point(3)}); + this->path().replace(this->commandPos(), cmds); + } + } actions(*this); + iterate(actions); + } /** Transforms the path according to a given Matrix. * @param[in] matrix Matrix describing the affine transformation */ void transform (const Matrix &matrix) { - for (Command &command : _commands) - command.transform(matrix); + TransformVisior visior(matrix); + for (CommandVariant &command : _commands) + mpark::visit(visior, command); } - + /** Returns true if this path equals another one, i.e. it consists the same sequence + * of commands and coordinates. */ bool operator == (const GraphicsPath &path) const { if (size() != path.size()) return false; auto it = _commands.begin(); - for (const Command &cmd : path._commands) { + for (const auto &cmd : path._commands) { if (*it++ != cmd) return false; } return true; } - + /** Returns true if this path differs from another one (command-wise). */ bool operator != (const GraphicsPath &path) const { if (size() != path.size()) return true; auto it = _commands.begin(); - for (const Command &cmd : path._commands) { + for (const auto &cmd : path._commands) { if (*it++ != cmd) return true; } return false; } + /** Iterates over all commands defining this path and calls the corresponding template methods. + * In the case of successive bezier curve sequences, control points or tangent slopes are often + * identical so that the path description contains redundant information. SVG provides shorthand + * curve commands that require less parameters. If 'optimize' is true, this method detects such + * command sequences. + * @param[in] actions template methods called by each iteration step + * @param[in] optimize if true, shorthand drawing commands (hlineto, vlineto,...) are considered */ + void iterate (IterationActions &actions, bool optimize) const { + double eps = XMLString::DECIMAL_PLACES > 0 ? pow(10, -XMLString::DECIMAL_PLACES) : 1e-7; + IterationVisitor visitor(actions, optimize, eps); + for (const CommandVariant &cmd : _commands) { + if (actions.quit()) + break; + mpark::visit(visitor, cmd); + visitor.setPrevCommand(cmd); + } + actions.finished(); + } - void iterate (Actions &actions, bool optimize) const; + protected: + /** Replaces a command by a sequence of other ones. + * @param[in] pos position of command to replace (0-based) + * @param[in] cmds commands to insert */ + void replace (int pos, const std::vector<CommandVariant> &cmds) { + auto it = _commands.end(); + if (!_commands.empty()) { + it = _commands.begin()+pos; + it = _commands.erase(it); + } + _commands.insert(it, cmds.begin(), cmds.end()); + } + + /** Iterates over all commands of the path and calls the corresponding template methods. + * In contrast to the public iterate() method, this one allows to modify the command sequence. + * @param[in] actions template methods called by each iteration step */ + void iterate (ModificationActions &actions) { + IterationVisitor visitor(actions, false); + // no iterators here since they may be invalidated during path modifications + for (size_t i=0; i < _commands.size(); i++) { + if (actions.quit()) + break; + actions._commandPos = i; + mpark::visit(visitor, _commands[i]); + visitor.setPrevCommand(_commands[i]); + } + actions.finished(); + } private: - std::deque<Command> _commands; + std::deque<CommandVariant> _commands; ///< sequence of path commands WindingRule _windingRule; + Point _startPoint; ///< start point of final sub-path + Point _finalPoint; ///< final point reached by last command in path }; - - -/** Iterates over all commands defining this path and calls the corresponding template methods. - * In the case of successive bezier curve sequences, control points or tangent slopes are often - * identical so that the path description contains redundant information. SVG provides shorthand - * curve commands that require less parameters. If 'optimize' is true, this method detects such - * command sequences. - * @param[in] actions template methods called by each iteration step - * @param[in] optimize if true, shorthand drawing commands (hlineto, vlineto,...) are considered */ -template <typename T> -void GraphicsPath<T>::iterate (Actions &actions, bool optimize) const { - auto prev = _commands.end(); // pointer to preceding command - Point fp; // first point of current path - Point cp; // current point - Point pstore[2]; - for (auto it=_commands.begin(); it != _commands.end() && !actions.quit(); ++it) { - const Point *params = it->params; - switch (it->type) { - case Command::Type::MOVETO: - actions.moveto(params[0]); - actions.draw('M', params, 1); - fp = params[0]; - break; - case Command::Type::LINETO: - if (optimize) { - if (cp.x() == params[0].x()) { - actions.vlineto(params[0].y()); - actions.draw('V', params, 1); - } - else if (cp.y() == params[0].y()) { - actions.hlineto(params[0].x()); - actions.draw('H', params, 1); - } - else { - actions.lineto(params[0]); - actions.draw('L', params, 1); - } - } - else { - actions.lineto(params[0]); - actions.draw('L', params, 1); - } - break; - case Command::Type::CONICTO: - if (optimize && prev != _commands.end() && prev->type == Command::Type::CONICTO && params[0] == pstore[1]*T(2)-pstore[0]) { - actions.conicto(params[1]); - actions.draw('T', params+1, 1); - } - else { - actions.conicto(params[0], params[1]); - actions.draw('Q', params, 2); - } - pstore[0] = params[0]; // store control point and - pstore[1] = params[1]; // curve endpoint - break; - case Command::Type::CUBICTO: - // is first control point reflection of preceding second control point? - if (optimize && prev != _commands.end() && prev->type == Command::Type::CUBICTO && params[0] == pstore[1]*T(2)-pstore[0]) { - actions.cubicto(params[1], params[2]); - actions.draw('S', params+1, 2); - } - else { - actions.cubicto(params[0], params[1], params[2]); - actions.draw('C', params, 3); - } - pstore[0] = params[1]; // store second control point and - pstore[1] = params[2]; // curve endpoint - break; - case Command::Type::CLOSEPATH: - actions.closepath(); - actions.draw('Z', params, 0); - cp = fp; - } - // update current point - const int np = it->numParams(); - if (np > 0) - cp = it->params[np-1]; - prev = it; - } - actions.finished(); -} - -#endif diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/HashFunction.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/HashFunction.cpp index 7479fca604f..517cc8f3ccb 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/HashFunction.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/HashFunction.cpp @@ -31,7 +31,12 @@ using namespace std; /** Returns a vector containing the names of the currently supported hash algorithms. */ vector<string> HashFunction::supportedAlgorithms () { - return vector<string> {"md5", "xxh32", "xxh64"}; + return vector<string> { + "md5", "xxh32", "xxh64", +#ifdef ENABLE_XXH128 + "xxh128" +#endif + }; } @@ -52,6 +57,10 @@ unique_ptr<HashFunction> HashFunction::create (const string &name) { return util::make_unique<XXH32HashFunction>(); if (lowerName == "xxh64") return util::make_unique<XXH64HashFunction>(); +#ifdef ENABLE_XXH128 + if (lowerName == "xxh128") + return util::make_unique<XXH128HashFunction>(); +#endif return nullptr; } @@ -74,6 +83,15 @@ std::unique_ptr<HashFunction> HashFunction::create (const string &name, const ve } +void HashFunction::update (istream &is) { + char buf[4096]; + while (is) { + is.read(buf, 4096); + update(buf, is.gcount()); + } +} + + /** Returns the current digest as hexadecimal value. */ string HashFunction::digestString () const { ostringstream oss; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/HashFunction.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/HashFunction.hpp index 1b1259393fa..bba61918ed9 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/HashFunction.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/HashFunction.hpp @@ -21,6 +21,7 @@ #ifndef HASHFUNCTION_HPP #define HASHFUNCTION_HPP +#include <istream> #include <memory> #include <string> #include <vector> @@ -35,6 +36,7 @@ class HashFunction { virtual void update (const std::string &data) =0; virtual void update (const std::vector<uint8_t> &data) =0; virtual std::vector<uint8_t> digestValue () const =0; + void update (std::istream &is); std::string digestString () const; static std::vector<std::string> supportedAlgorithms (); static bool isSupportedAlgorithm (const std::string &algo); diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/HtmlSpecialHandler.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/HtmlSpecialHandler.cpp index b7f4e9664f6..43d3dbc2244 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/HtmlSpecialHandler.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/HtmlSpecialHandler.cpp @@ -31,7 +31,7 @@ void HtmlSpecialHandler::preprocess (const string&, istream &is, SpecialActions ir.skipSpace(); // collect page number and ID of named anchors map<string,string> attribs; - if (ir.check("<a ") && ir.parseAttributes(attribs, "\"") > 0) { + if (ir.check("<a ") && ir.parseAttributes(attribs, true, "\"") > 0) { map<string,string>::iterator it; if ((it = attribs.find("name")) != attribs.end()) HyperlinkManager::instance().addNameAchor(it->second, actions.getCurrentPageNumber()); @@ -47,7 +47,7 @@ bool HtmlSpecialHandler::process (const string&, istream &is, SpecialActions &ac ir.skipSpace(); map<string,string> attribs; map<string,string>::iterator it; - if (ir.check("<a ") && ir.parseAttributes(attribs, "\"") > 0) { + if (ir.check("<a ") && ir.parseAttributes(attribs, true, "\"") > 0) { if ((it = attribs.find("href")) != attribs.end()) // <a href="URI"> HyperlinkManager::instance().createLink(it->second, actions); else if ((it = attribs.find("name")) != attribs.end()) // <a name="ID"> @@ -59,7 +59,7 @@ bool HtmlSpecialHandler::process (const string&, istream &is, SpecialActions &ac HyperlinkManager::instance().closeAnchor(actions); else if (ir.check("<img src=")) { } - else if (ir.check("<base ") && ir.parseAttributes(attribs, "\"") > 0 && (it = attribs.find("href")) != attribs.end()) + else if (ir.check("<base ") && ir.parseAttributes(attribs, true, "\"") > 0 && (it = attribs.find("href")) != attribs.end()) HyperlinkManager::instance().setBaseUrl(it->second); return true; } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/HyperlinkManager.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/HyperlinkManager.cpp index 9d610426808..de412afcdc0 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/HyperlinkManager.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/HyperlinkManager.cpp @@ -88,7 +88,7 @@ void HyperlinkManager::createLink (string uri, SpecialActions &actions) { string name; if (uri[0] == '#') { // reference to named anchor? name = uri.substr(1); - NamedAnchors::iterator it = _namedAnchors.find(name); + auto it = _namedAnchors.find(name); if (it == _namedAnchors.end() || it->second.id < 0) Message::wstream(true) << "reference to undefined anchor '" << name << "'\n"; else { @@ -96,7 +96,7 @@ void HyperlinkManager::createLink (string uri, SpecialActions &actions) { uri = "#loc"+XMLString(id); if (actions.getCurrentPageNumber() != it->second.pageno) { ostringstream oss; - oss << actions.getSVGFilename(it->second.pageno) << uri; + oss << actions.getSVGFilePath(it->second.pageno).relative() << uri; uri = oss.str(); } } @@ -106,10 +106,10 @@ void HyperlinkManager::createLink (string uri, SpecialActions &actions) { uri = "/" + uri; uri = _base + uri; } - auto anchorNode = util::make_unique<XMLElementNode>("a"); + auto anchorNode = util::make_unique<XMLElement>("a"); anchorNode->addAttribute("xlink:href", uri); anchorNode->addAttribute("xlink:title", XMLString(name.empty() ? uri : name, false)); - actions.pushContextElement(std::move(anchorNode)); + actions.svgTree().pushPageContext(std::move(anchorNode)); actions.bbox("{anchor}", true); // start computing the bounding box of the linked area _depthThreshold = actions.getDVIStackDepth(); _anchorType = AnchorType::HREF; @@ -119,7 +119,7 @@ void HyperlinkManager::createLink (string uri, SpecialActions &actions) { void HyperlinkManager::closeAnchor (SpecialActions &actions) { if (_anchorType == AnchorType::HREF) { markLinkedBox(actions); - actions.popContextElement(); + actions.svgTree().popPageContext(); _depthThreshold = 0; } _anchorType = AnchorType::NONE; @@ -148,7 +148,7 @@ void HyperlinkManager::markLinkedBox (SpecialActions &actions) { if (bbox.width() > 0 && bbox.height() > 0) { // does the bounding box extend in both dimensions? if (MARKER_TYPE != MarkerType::NONE) { const double linewidth = _linewidth >= 0 ? _linewidth : min(0.5, bbox.height()/15); - auto rect = util::make_unique<XMLElementNode>("rect"); + auto rect = util::make_unique<XMLElement>("rect"); double x = bbox.minX(); double y = bbox.maxY()+linewidth; double w = bbox.width(); @@ -179,7 +179,7 @@ void HyperlinkManager::markLinkedBox (SpecialActions &actions) { rect->addAttribute("y", y); rect->addAttribute("width", w); rect->addAttribute("height", h); - actions.prependToPage(std::move(rect)); + actions.svgTree().prependToPage(std::move(rect)); if (MARKER_TYPE == MarkerType::BOX || MARKER_TYPE == MarkerType::BGCOLOR) { // slightly enlarge the boxed area x -= linewidth/2; @@ -192,14 +192,14 @@ void HyperlinkManager::markLinkedBox (SpecialActions &actions) { // Create an invisible rectangle around the linked area so that it's easier to access. // This is only necessary when using paths rather than real text elements together with fonts. if (!SVGTree::USE_FONTS) { - auto rect = util::make_unique<XMLElementNode>("rect"); + auto rect = util::make_unique<XMLElement>("rect"); rect->addAttribute("x", bbox.minX()); rect->addAttribute("y", bbox.minY()); rect->addAttribute("width", bbox.width()); rect->addAttribute("height", bbox.height()); rect->addAttribute("fill", "white"); rect->addAttribute("fill-opacity", 0); - actions.appendToPage(std::move(rect)); + actions.svgTree().appendToPage(std::move(rect)); } } } @@ -213,10 +213,10 @@ void HyperlinkManager::createViews (unsigned pageno, SpecialActions &actions) { ostringstream oss; oss << pagebox.minX() << ' ' << stranchorpair.second.pos << ' ' << pagebox.width() << ' ' << pagebox.height(); - auto view = util::make_unique<XMLElementNode>("view"); + auto view = util::make_unique<XMLElement>("view"); view->addAttribute("id", "loc"+XMLString(stranchorpair.second.id)); view->addAttribute("viewBox", oss.str()); - actions.appendToDefs(std::move(view)); + actions.svgTree().appendToDefs(std::move(view)); } } closeAnchor(actions); @@ -229,7 +229,7 @@ void HyperlinkManager::createViews (unsigned pageno, SpecialActions &actions) { bool HyperlinkManager::setLinkMarker (const string &marker) { string type; // "none", "box", "line", or a background color specifier string color; // optional line color specifier - size_t seppos = marker.find(":"); + size_t seppos = marker.find(':'); if (seppos == string::npos) type = marker; else { diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/ImageToSVG.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/ImageToSVG.cpp index 294b6adf951..26edb3c753c 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/ImageToSVG.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/ImageToSVG.cpp @@ -27,6 +27,7 @@ #include "MessageException.hpp" #include "PageRanges.hpp" #include "PsSpecialHandler.hpp" +#include "optimizer/SVGOptimizer.hpp" #include "SVGOutput.hpp" #include "System.hpp" #include "utility.hpp" @@ -72,19 +73,19 @@ void ImageToSVG::convert (int pageno) { _psHandler.process(psSpecialCmd(), ss, *this); } catch (...) { - progress(0); // remove progress message + progress(nullptr); // remove progress message throw; } - progress(0); + progress(nullptr); Matrix matrix = getUserMatrix(_bbox); // output SVG file - _svg.removeRedundantElements(); + SVGOptimizer(_svg).execute(); _svg.transformPage(matrix); _bbox.transform(matrix); _svg.setBBox(_bbox); - _svg.appendToDoc(util::make_unique<XMLCommentNode>(" This file was generated by dvisvgm " + string(PROGRAM_VERSION) + " ")); + _svg.appendToDoc(util::make_unique<XMLComment>(" This file was generated by dvisvgm " + string(PROGRAM_VERSION) + " ")); bool success = _svg.write(_out.getPageStream(pageno, totalPageCount())); - string svgfname = _out.filename(pageno, totalPageCount()); + string svgfname = _out.filepath(pageno, totalPageCount()).shorterAbsoluteOrRelative(); if (svgfname.empty()) svgfname = "<stdout>"; if (!success) @@ -144,10 +145,11 @@ void ImageToSVG::convert (const std::string &rangestr, pair<int,int> *pageinfo) } -string ImageToSVG::getSVGFilename (unsigned pageno) const { +FilePath ImageToSVG::getSVGFilePath (unsigned pageno) const { + FilePath path; if (pageno == 1) - return _out.filename(1, 1); - return ""; + path = _out.filepath(1, 1); + return path; } @@ -162,13 +164,13 @@ void ImageToSVG::progress (const char *id) { Terminal::cursor(false); Message::mstream(false) << "\n"; } - if (draw && ((System::time() - time > 0.05) || id == 0)) { + if (draw && ((System::time() - time > 0.05) || id == nullptr)) { const size_t DIGITS=6; Message::mstream(false, Message::MC_PROGRESS) << string(DIGITS-min(DIGITS, static_cast<size_t>(log10(count))), ' ') << count << " PostScript instructions processed\r"; // overprint indicator when finished - if (id == 0) { + if (id == nullptr) { Message::estream().clearline(); Terminal::cursor(true); } @@ -190,7 +192,7 @@ Matrix ImageToSVG::getUserMatrix (const BoundingBox &bbox) const { calc.setVariable("w", bbox.width()*bp2pt); calc.setVariable("h", bbox.height()*bp2pt); // add constants for length units to calculator - for (auto unit : Length::getUnits()) + for (const auto &unit : Length::getUnits()) calc.setVariable(unit.first, Length(1, unit.second).pt()); matrix.set(_transCmds, calc); } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/ImageToSVG.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/ImageToSVG.hpp index dcbce9b3242..a4e4de223f6 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/ImageToSVG.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/ImageToSVG.hpp @@ -32,8 +32,7 @@ struct SVGOutputBase; class ImageToSVG : protected SpecialActions { public: - ImageToSVG (const std::string &fname, SVGOutputBase &out) : _fname(fname), _out(out) {} - virtual ~ImageToSVG () =default; + ImageToSVG (std::string fname, SVGOutputBase &out) : _fname(std::move(fname)), _out(out) {} void convert (int pageno); void convert (int firstPage, int lastPage, std::pair<int,int> *pageinfo); void convert (const std::string &rangestr, std::pair<int,int> *pageinfo); @@ -61,19 +60,15 @@ class ImageToSVG : protected SpecialActions { Color getColor () const override {return _svg.getColor();} void setMatrix (const Matrix &m) override {_svg.setMatrix(m);} const Matrix& getMatrix () const override {return _svg.getMatrix();} + const SVGTree& svgTree () const override {return _svg;} void setBgColor (const Color &color) override {} - void appendToPage(std::unique_ptr<XMLNode> &&node) override {_svg.appendToPage(std::move(node));} - void appendToDefs(std::unique_ptr<XMLNode> &&node) override {_svg.appendToDefs(std::move(node));} - void prependToPage(std::unique_ptr<XMLNode> &&node) override {_svg.prependToPage(std::move(node));} - void pushContextElement (std::unique_ptr<XMLElementNode> &&node) override {_svg.pushContextElement(std::move(node));} - void popContextElement () override {_svg.popContextElement();} void embed (const BoundingBox &bbox) override {_bbox.embed(bbox);} void embed (const DPair &p, double r=0) override {if (r==0) _bbox.embed(p); else _bbox.embed(p, r);} void progress (const char *id) override; unsigned getCurrentPageNumber() const override {return 0;} BoundingBox& bbox () override {return _bbox;} BoundingBox& bbox (const std::string &name, bool reset=false) override {return _bbox;} - std::string getSVGFilename (unsigned pageno) const override; + FilePath getSVGFilePath (unsigned pageno) const override; std::string getBBoxFormatString () const override {return "";} private: diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/InputBuffer.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/InputBuffer.hpp index b144d34336d..8a62b6b0118 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/InputBuffer.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/InputBuffer.hpp @@ -27,8 +27,7 @@ #include <string> #include <ostream> -struct InputBuffer -{ +struct InputBuffer { virtual ~InputBuffer () =default; virtual int get () =0; virtual int peek () const =0; @@ -38,11 +37,10 @@ struct InputBuffer }; -class StreamInputBuffer : public InputBuffer -{ +class StreamInputBuffer : public InputBuffer { public: - StreamInputBuffer (std::istream &is, size_t bufsize=1024); - ~StreamInputBuffer (); + explicit StreamInputBuffer (std::istream &is, size_t bufsize=1024); + ~StreamInputBuffer () override; int get () override; int peek () const override; int peek (size_t n) const override; @@ -64,24 +62,23 @@ class StreamInputBuffer : public InputBuffer }; -class StringInputBuffer : public InputBuffer -{ +class StringInputBuffer : public InputBuffer { public: - StringInputBuffer (const std::string &str) : _str(str), _pos(0) {} - int get () override {return _pos < _str.length() ? _str[_pos++] : -1;} - int peek () const override {return _pos < _str.length() ? _str[_pos] : -1;} - int peek (size_t n) const override {return _pos+n < _str.length() ? _str[_pos+n] : -1;} - bool eof () const override {return _pos >= _str.length();} - void invalidate () override {_pos = _str.length();} + explicit StringInputBuffer (const std::string &str) : _str(&str) {} + void assign (const std::string &str) {_str = &str; _pos=0;} + int get () override {return _pos < _str->length() ? _str->at(_pos++) : -1;} + int peek () const override {return _pos < _str->length() ? _str->at(_pos) : -1;} + int peek (size_t n) const override {return _pos+n < _str->length() ? _str->at(_pos+n) : -1;} + bool eof () const override {return _pos >= _str->length();} + void invalidate () override {_pos = _str->length();} private: - const std::string &_str; - size_t _pos; + const std::string *_str; + size_t _pos=0; }; -class CharInputBuffer : public InputBuffer -{ +class CharInputBuffer : public InputBuffer { public: CharInputBuffer (const char *buf, size_t size) : _pos(buf), _size(buf ? size : 0) {} @@ -112,8 +109,7 @@ class CharInputBuffer : public InputBuffer }; -class SplittedCharInputBuffer : public InputBuffer -{ +class SplittedCharInputBuffer : public InputBuffer { public: SplittedCharInputBuffer (const char *buf1, size_t s1, const char *buf2, size_t s2); int get () override; @@ -129,16 +125,15 @@ class SplittedCharInputBuffer : public InputBuffer }; -class TextStreamInputBuffer : public StreamInputBuffer -{ +class TextStreamInputBuffer : public StreamInputBuffer { public: - TextStreamInputBuffer (std::istream &is) : StreamInputBuffer(is), _line(1), _col(1) {} + explicit TextStreamInputBuffer (std::istream &is) : StreamInputBuffer(is) {} int get () override; int line () const {return _line;} int col () const {return _col;} private: - int _line, _col; + int _line=1, _col=1; }; #endif diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/InputReader.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/InputReader.cpp index 9a317b4bf96..5c9b9f5c621 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/InputReader.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/InputReader.cpp @@ -19,6 +19,7 @@ *************************************************************************/ #include <cmath> +#include <cstring> #include <functional> #include "InputReader.hpp" @@ -41,11 +42,15 @@ void StringMatcher::setPattern (const string &pattern) { } +/** Reads characters from an input stream until the pattern string or EOF is reached. + * The matching string is read too if found. An empty pattern matches any character, i.e. + * reading stops after the first character. + * @return true if the pattern was found */ bool StringMatcher::match (InputReader &ir) { - _charsRead = 0; int c; int i=0; const int len = static_cast<int>(_pattern.length()); + _charsRead = 0; while ((c = ir.get()) >= 0) { _charsRead++; while (i >= 0 && c != _pattern[i]) @@ -56,6 +61,25 @@ bool StringMatcher::match (InputReader &ir) { return false; } + +/** Reads characters from an input stream until the pattern string or EOF is reached + * and returns them as a string. The matching string is also appended to the returned string. */ +string StringMatcher::read (InputReader &ir) { + string ret; + int c; + int i=0; + const int len = static_cast<int>(_pattern.length()); + while ((c = ir.get()) >= 0) { + ret += char(c); + while (i >= 0 && c != _pattern[i]) + i = _borders[i]; + if (++i == len) + break; + } + _charsRead = ret.length(); + return ret; +} + /////////////////////////////////////////////////////////////////////////// /** Skips n characters. */ @@ -73,15 +97,26 @@ void InputReader::skipSpace () { } -/** Tries to find a given string and skips all characters preceding that string. +/** Tries to find a given string and skips all characters preceding that string. If + * the string can't be found, all characters until EOF are skipped. * @param[in] str string to look for (must not be longer than the maximal buffer size) - * @return true if s was found */ + * @return true if str was found */ bool InputReader::skipUntil (const char *str) { StringMatcher matcher(str); return matcher.match(*this); } +/** Tries to find a given string and returns all characters including that string. If + * the string can't be found, all characters until EOF are read. + * @param[in] str string to look for (must not be longer than the maximal buffer size) + * @return the read characters */ +string InputReader::readUntil (const char *str) { + StringMatcher matcher(str); + return matcher.read(*this); +} + + /** Looks for the first occurrence of a given character. * @param[in] c character to lookup * @return position of character relative to current location, -1 if character was not found */ @@ -246,7 +281,7 @@ string InputReader::getWord () { string ret; skipSpace(); while (isalpha(peek())) - ret += get(); + ret += char(get()); return ret; } @@ -261,7 +296,7 @@ char InputReader::getPunct () { } -/** Reads a string optionally delimited by a given quotation character. +/** Reads a string optionally enclosed by a given quotation character. * Before reading the string, all leading whitespace is skipped. Then, the function checks * for one of the the given quotation characters. If it is found, all characters until the * second appearance of the same quotation char are appended to the result. Otherwise, an @@ -278,7 +313,7 @@ string InputReader::getQuotedString (const char *quotechars) { if (const char *quotechar = strchr(quotechars, peek())) { get(); while (!eof() && peek() != *quotechar) - ret += get(); + ret += char(get()); get(); } return ret; @@ -294,7 +329,7 @@ string InputReader::getString () { string ret; skipSpace(); while (!eof() && !isspace(peek()) && isprint(peek())) - ret += get(); + ret += char(get()); return ret; } @@ -305,7 +340,7 @@ string InputReader::getString () { string InputReader::getString (size_t n) { string ret; while (n-- > 0) - ret += get(); + ret += char(get()); return ret; } @@ -319,7 +354,7 @@ string InputReader::getString (const char *delim) { string ret; skipSpace(); while (!eof() && peek() > 0 && !strchr(delim, peek())) - ret += get(); + ret += char(get()); return ret; } @@ -328,33 +363,37 @@ string InputReader::getLine () { string ret; skipSpace(); while (!eof() && peek() > 0 && peek() != '\n') - ret += get(); + ret += char(get()); // trim trailing whitespace ret.erase(std::find_if(ret.rbegin(), ret.rend(), not1(ptr_fun<int, int>(isspace))).base(), ret.end()); return ret; } -/** Parses a sequence of key-value pairs of the form KEY=VALUE or KEY="VALUE" +/** Parses a sequence of key-value pairs of the form KEY=VALUE or KEY="VALUE". + * If parameter 'requireValues' is false, attributes may also consist of a key only. * @param[out] attr the scanned atributes + * @param[in] requireValues true if all attributes require a value * @param[in] quotechars recognized quote characters used to enclose the attribute values * @return number of attributes scanned */ -int InputReader::parseAttributes (map<string,string> &attr, const char *quotechars) { - bool ready=false; - while (!eof() && !ready) { +int InputReader::parseAttributes (map<string,string> &attr, bool requireValues, const char *quotechars) { + while (!eof()) { string key; skipSpace(); - while (isalnum(peek())) - key += get(); + if (!isalpha(peek())) // first character of attribute name must be a letter + break; + key += char(get()); + while (isalnum(peek()) || strchr("-:._", peek())) + key += char(get()); skipSpace(); if (peek() == '=') { get(); skipSpace(); string val = getQuotedString(quotechars); - attr[key] = val; + attr.emplace(std::move(key), std::move(val)); } - else - ready = true; + else if (!requireValues) + attr.emplace(std::move(key), ""); } return attr.size(); } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/InputReader.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/InputReader.hpp index 5523499f073..0ca4f107722 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/InputReader.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/InputReader.hpp @@ -37,7 +37,8 @@ class InputReader { virtual bool check (char c) const {return peek() == c;} virtual bool check (const char *s, bool consume=true); virtual void skip (size_t n); - virtual bool skipUntil (const char *s); + virtual bool skipUntil (const char *str); + virtual std::string readUntil (const char *str); virtual int find (char c) const; virtual void skipSpace (); virtual int getInt (); @@ -53,14 +54,14 @@ class InputReader { virtual std::string getString (size_t n); virtual std::string getString (const char *delim); virtual std::string getLine (); - virtual int parseAttributes (std::map<std::string,std::string> &attr, const char *quotechars=nullptr); + virtual int parseAttributes (std::map<std::string,std::string> &attr, bool requireValues, const char *quotechars=nullptr); virtual operator bool () const {return !eof();} }; class StreamInputReader : public InputReader { public: - StreamInputReader (std::istream &is) : _is(is) {} + explicit StreamInputReader (std::istream &is) : _is(is) {} int get () override {return _is.get();} int peek () const override {return _is.peek();} int peek (size_t n) const override; @@ -74,7 +75,7 @@ class StreamInputReader : public InputReader { class BufferInputReader : public InputReader { public: - BufferInputReader (InputBuffer &ib) : _ib(&ib) {} + explicit BufferInputReader (InputBuffer &ib) : _ib(&ib) {} void assign (InputBuffer &ib) {_ib = &ib;} int get () override {return _ib->get();} int peek () const override {return _ib->peek();} @@ -91,9 +92,10 @@ class BufferInputReader : public InputReader { class StringMatcher { public: StringMatcher () : _charsRead(0) {} - StringMatcher (const std::string &pattern) : _charsRead(0) {setPattern(pattern);} + explicit StringMatcher (const std::string &pattern) : _charsRead(0) {setPattern(pattern);} void setPattern (const std::string &pattern); bool match (InputReader &ir); + std::string read (InputReader &ir); size_t charsRead () const {return _charsRead;} private: diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/JFM.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/JFM.cpp index a1835f6732c..a79fdf0c03b 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/JFM.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/JFM.cpp @@ -32,11 +32,9 @@ JFM::JFM (istream &is) { is.seekg(0); StreamReader reader(is); uint16_t id = uint16_t(reader.readUnsigned(2)); // JFM ID (9 or 11) - if (id != 9 && id != 11) { - ostringstream oss; - oss << "invalid JFM identifier " << id << " (9 or 11 expected)"; - throw FontMetricException(oss.str()); - } + if (id != 9 && id != 11) + throw FontMetricException("invalid JFM identifier " + std::to_string(id) + " (9 or 11 expected)"); + _vertical = (id == 9); uint16_t nt = uint16_t(reader.readUnsigned(2)); // length of character type table uint16_t lf = uint16_t(reader.readUnsigned(2)); // length of entire file in 4 byte words diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/JFM.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/JFM.hpp index 5b5901ee61f..c51f371a5ec 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/JFM.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/JFM.hpp @@ -27,7 +27,7 @@ class JFM : public TFM { public: - JFM (std::istream &is); + explicit JFM (std::istream &is); bool verticalLayout () const override {return _vertical;} uint32_t minChar () const {return _minchar;} uint32_t maxChar () const {return static_cast<uint32_t>(_minchar+_charTypeTable.size()-1);} diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/Length.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/Length.cpp index ba7dd2a2252..cbee103d49b 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/Length.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/Length.cpp @@ -60,9 +60,7 @@ void Length::set (double val, Unit unit) { case Unit::SP: _pt = val/pt2sp; break; default: // this isn't supposed to happen - ostringstream oss; - oss << "invalid length unit: (" << static_cast<int>(unit) << ")"; - throw UnitException(oss.str()); + throw UnitException("invalid length unit: (" + std::to_string(static_cast<int>(unit)) + ")"); } } @@ -80,9 +78,7 @@ double Length::get (Unit unit) const { case Unit::SP: return sp(); } // this isn't supposed to happen - ostringstream oss; - oss << "invalid length unit: (" << static_cast<int>(unit) << ")"; - throw UnitException(oss.str()); + throw UnitException("invalid length unit: (" + std::to_string(static_cast<int>(unit)) + ")"); } @@ -111,7 +107,7 @@ Length::Unit Length::stringToUnit (const std::string &unitstr) { case unit_id('s','p'): return Unit::SP; } } - throw UnitException(string("invalid length unit: ")+unitstr); + throw UnitException(string("invalid length unit: ") + unitstr); } @@ -136,7 +132,7 @@ void Length::set (double val, string unitstr) { if (unitstr.empty()) unitstr = "pt"; else if (unitstr.length() != 2) - throw UnitException(string("invalid length unit: ")+unitstr); + throw UnitException(string("invalid length unit: ") + unitstr); set(val, stringToUnit(unitstr)); } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/Length.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/Length.hpp index 0c9aa6526bf..4454eec168e 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/Length.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/Length.hpp @@ -30,7 +30,7 @@ #endif struct UnitException : MessageException { - UnitException (const std::string &msg) : MessageException(msg) {} + explicit UnitException (const std::string &msg) : MessageException(msg) {} }; @@ -40,10 +40,10 @@ class Length { public: constexpr Length () : _pt(0) {} - constexpr Length (long double pt) : _pt(static_cast<double>(pt)) {} + explicit constexpr Length (long double pt) : _pt(static_cast<double>(pt)) {} Length (double val, Unit unit) {set(val, unit);} Length (double val, const std::string &unitstr) {set(val, unitstr);} - Length (const std::string &lenstr) {set(lenstr);} + explicit Length (const std::string &lenstr) {set(lenstr);} void set (double val, Unit unit); void set (double val, std::string unit); void set (const std::string &lenstr); diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/MD5HashFunction.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/MD5HashFunction.hpp index 3ccbdfe12c1..e233673d36d 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/MD5HashFunction.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/MD5HashFunction.hpp @@ -34,8 +34,8 @@ class MD5HashFunction : public HashFunction { public: MD5HashFunction () {MD5_Init(&_context);} MD5HashFunction (const char *data, size_t length) : MD5HashFunction() {update(data, length);} - MD5HashFunction (const std::string &data) : MD5HashFunction() {update(data);} - MD5HashFunction (const std::vector<uint8_t> &data) : MD5HashFunction() {update(data);} + explicit MD5HashFunction (const std::string &data) : MD5HashFunction() {update(data);} + explicit MD5HashFunction (const std::vector<uint8_t> &data) : MD5HashFunction() {update(data);} int digestSize () const override {return 16;} void reset () override {MD5_Init(&_context);} void update (const char *data, size_t length) override {MD5_Update(&_context, data, length);} diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/Makefile.am b/Build/source/texk/dvisvgm/dvisvgm-src/src/Makefile.am index 421ccd840e1..8c7786e9dd1 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/Makefile.am +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/Makefile.am @@ -5,6 +5,7 @@ bin_PROGRAMS = dvisvgm noinst_LIBRARIES = libdvisvgm.a +SUBDIRS = optimizer dvisvgm_SOURCES = \ CommandLine.hpp \ @@ -14,6 +15,7 @@ include ../libs/defs.am dvisvgm_LDADD = \ $(noinst_LIBRARIES) \ + optimizer/liboptimizer.a \ ../libs/clipper/libclipper.a \ $(POTRACE_LIBS) \ $(XXHASH_LIBS) @@ -43,217 +45,123 @@ dvisvgm_DEPENDENCIES += $(KPATHSEA_DEPEND) $(ZLIB_DEPEND) $(FREETYPE2_DEPEND) libdvisvgm_a_SOURCES = \ AGLTable.hpp \ - BasicDVIReader.cpp \ - BasicDVIReader.hpp \ - Bezier.cpp \ - Bezier.hpp \ - BgColorSpecialHandler.cpp \ - BgColorSpecialHandler.hpp \ - Bitmap.cpp \ - Bitmap.hpp \ - BoundingBox.cpp \ - BoundingBox.hpp \ - Calculator.cpp \ - Calculator.hpp \ + BasicDVIReader.hpp BasicDVIReader.cpp \ + Bezier.hpp Bezier.cpp \ + BgColorSpecialHandler.hpp BgColorSpecialHandler.cpp \ + Bitmap.hpp Bitmap.cpp \ + BoundingBox.hpp BoundingBox.cpp \ + Calculator.hpp Calculator.cpp \ Character.hpp \ - CharMapID.cpp \ - CharMapID.hpp \ - CLCommandLine.cpp \ - CLCommandLine.hpp \ + CharMapID.hpp CharMapID.cpp \ + CLCommandLine.hpp CLCommandLine.cpp \ + CMap.hpp CMap.cpp \ + CMapManager.hpp CMapManager.cpp \ + CMapReader.hpp CMapReader.cpp \ CLOption.hpp \ - CMap.cpp \ - CMap.hpp \ - CMapManager.cpp \ - CMapManager.hpp \ - CMapReader.cpp \ - CMapReader.hpp \ - Color.cpp \ - Color.hpp \ - ColorSpecialHandler.cpp \ - ColorSpecialHandler.hpp \ - CRC32.cpp \ - CRC32.hpp \ - DependencyGraph.hpp \ - Directory.cpp \ - Directory.hpp \ - DLLoader.cpp \ - DLLoader.hpp \ + Color.hpp Color.cpp \ + ColorSpecialHandler.hpp ColorSpecialHandler.cpp \ + CommandLine.hpp \ + Directory.hpp Directory.cpp \ DVIActions.hpp \ - DVIReader.cpp \ - DVIReader.hpp \ - DvisvgmSpecialHandler.cpp \ - DvisvgmSpecialHandler.hpp \ - DVIToSVG.cpp \ - DVIToSVG.hpp \ - DVIToSVGActions.cpp \ - DVIToSVGActions.hpp \ - EmSpecialHandler.cpp \ - EmSpecialHandler.hpp \ - EncFile.cpp \ - EncFile.hpp \ - EPSFile.cpp \ - EPSFile.hpp \ + DLLoader.hpp DLLoader.cpp \ + DVIReader.hpp DVIReader.cpp \ + DvisvgmSpecialHandler.hpp DvisvgmSpecialHandler.cpp \ + DVIToSVG.hpp DVIToSVG.cpp \ + DVIToSVGActions.hpp DVIToSVGActions.cpp \ + EllipticalArc.hpp EllipticalArc.cpp \ + EmSpecialHandler.hpp EmSpecialHandler.cpp \ + EncFile.hpp EncFile.cpp \ + EPSFile.hpp EPSFile.cpp \ EPSToSVG.hpp \ - FileFinder.cpp \ - FileFinder.hpp \ - FilePath.cpp \ - FilePath.hpp \ - FileSystem.cpp \ - FileSystem.hpp \ + FileFinder.hpp FileFinder.cpp \ + FilePath.hpp FilePath.cpp \ + FileSystem.hpp FileSystem.cpp \ FixWord.hpp \ - Font.cpp \ - Font.hpp \ - FontCache.cpp \ - FontCache.hpp \ - FontEncoding.cpp \ - FontEncoding.hpp \ - FontEngine.cpp \ - FontEngine.hpp \ - FontManager.cpp \ - FontManager.hpp \ - FontMap.cpp \ - FontMap.hpp \ - FontMetrics.cpp \ - FontMetrics.hpp \ + Font.hpp Font.cpp \ + FontCache.hpp FontCache.cpp \ + FontEncoding.hpp FontEncoding.cpp \ + FontEngine.hpp FontEngine.cpp \ + FontManager.hpp FontManager.cpp \ + FontMap.hpp FontMap.cpp \ + FontMetrics.hpp FontMetrics.cpp \ FontStyle.hpp \ - FontWriter.cpp \ - FontWriter.hpp \ - GFGlyphTracer.cpp \ - GFGlyphTracer.hpp \ - GFReader.cpp \ - GFReader.hpp \ - GFTracer.cpp \ - GFTracer.hpp \ - Ghostscript.cpp \ - Ghostscript.hpp \ + FontWriter.hpp FontWriter.cpp \ + GFGlyphTracer.hpp GFGlyphTracer.cpp \ + GFReader.hpp GFReader.cpp \ + GFTracer.hpp GFTracer.cpp \ + Ghostscript.hpp Ghostscript.cpp \ Glyph.hpp \ GlyphTracerMessages.hpp \ GraphicsPath.hpp \ - HashFunction.cpp \ - HashFunction.hpp \ - HtmlSpecialHandler.cpp \ - HtmlSpecialHandler.hpp \ - HyperlinkManager.cpp \ - HyperlinkManager.hpp \ - ImageToSVG.cpp \ - ImageToSVG.hpp \ - InputBuffer.cpp \ - InputBuffer.hpp \ - InputReader.cpp \ - InputReader.hpp \ - JFM.cpp \ - JFM.hpp \ - Length.cpp \ - Length.hpp \ + HashFunction.hpp HashFunction.cpp \ + HtmlSpecialHandler.hpp HtmlSpecialHandler.cpp \ + HyperlinkManager.hpp HyperlinkManager.cpp \ + ImageToSVG.hpp ImageToSVG.cpp \ + InputBuffer.hpp InputBuffer.cpp \ + InputReader.hpp InputReader.cpp \ + JFM.hpp JFM.cpp \ + Length.hpp Length.cpp \ macros.hpp \ - MapLine.cpp \ - MapLine.hpp \ - Matrix.cpp \ - Matrix.hpp \ + MapLine.hpp MapLine.cpp \ + Matrix.hpp Matrix.cpp \ MD5HashFunction.hpp \ - Message.cpp \ - Message.hpp \ + Message.hpp Message.cpp \ MessageException.hpp \ - MetafontWrapper.cpp \ - MetafontWrapper.hpp \ - NoPsSpecialHandler.cpp \ - NoPsSpecialHandler.hpp \ + MetafontWrapper.hpp MetafontWrapper.cpp \ + NoPsSpecialHandler.hpp NoPsSpecialHandler.cpp \ NumericRanges.hpp \ - PageRanges.cpp \ - PageRanges.hpp \ - PageSize.cpp \ - PageSize.hpp \ + PageRanges.hpp PageRanges.cpp \ + PageSize.hpp PageSize.cpp \ Pair.hpp \ - PapersizeSpecialHandler.cpp \ - PapersizeSpecialHandler.hpp \ - PathClipper.cpp \ - PathClipper.hpp \ - PDFParser.cpp \ - PDFParser.hpp \ + PapersizeSpecialHandler.hpp PapersizeSpecialHandler.cpp \ + PathClipper.hpp PathClipper.cpp \ + PDFParser.hpp PDFParser.cpp \ + PdfSpecialHandler.hpp PdfSpecialHandler.cpp \ PDFToSVG.hpp \ - PdfSpecialHandler.cpp \ - PdfSpecialHandler.hpp \ - PreScanDVIReader.cpp \ - PreScanDVIReader.hpp \ - Process.cpp \ - Process.hpp \ + PreScanDVIReader.hpp PreScanDVIReader.cpp \ + Process.hpp Process.cpp \ psdefs.cpp \ PSFilter.hpp \ - PSInterpreter.cpp \ - PSInterpreter.hpp \ - PSPattern.cpp \ - PSPattern.hpp \ - PSPreviewFilter.cpp \ - PSPreviewFilter.hpp \ - PsSpecialHandler.cpp \ - PsSpecialHandler.hpp \ - RangeMap.cpp \ - RangeMap.hpp \ - ShadingPatch.cpp \ - ShadingPatch.hpp \ - SignalHandler.cpp \ - SignalHandler.hpp \ - SourceInput.cpp \ - SourceInput.hpp \ + PSInterpreter.hpp PSInterpreter.cpp \ + PSPattern.hpp PSPattern.cpp \ + PSPreviewFilter.hpp PSPreviewFilter.cpp \ + PsSpecialHandler.hpp PsSpecialHandler.cpp \ + RangeMap.hpp RangeMap.cpp \ + ShadingPatch.hpp ShadingPatch.cpp \ + SignalHandler.hpp SignalHandler.cpp \ + SourceInput.hpp SourceInput.cpp \ SpecialActions.hpp \ SpecialHandler.hpp \ - SpecialManager.cpp \ - SpecialManager.hpp \ - StreamReader.cpp \ - StreamReader.hpp \ - StreamWriter.cpp \ - StreamWriter.hpp \ - Subfont.cpp \ - Subfont.hpp \ - SVGCharHandler.cpp \ - SVGCharHandler.hpp \ - SVGCharHandlerFactory.cpp \ - SVGCharHandlerFactory.hpp \ - SVGCharPathHandler.cpp \ - SVGCharPathHandler.hpp \ - SVGCharTspanTextHandler.cpp \ - SVGCharTspanTextHandler.hpp \ - SVGOutput.cpp \ - SVGOutput.hpp \ - SVGSingleCharTextHandler.cpp \ - SVGSingleCharTextHandler.hpp \ - SVGTree.cpp \ - SVGTree.hpp \ - System.cpp \ - System.hpp \ - TensorProductPatch.cpp \ - TensorProductPatch.hpp \ - Terminal.cpp \ - Terminal.hpp \ - TFM.cpp \ - TFM.hpp \ - ToUnicodeMap.cpp \ - ToUnicodeMap.hpp \ - TpicSpecialHandler.cpp \ - TpicSpecialHandler.hpp \ - TriangularPatch.cpp \ - TriangularPatch.hpp \ - TrueTypeFont.cpp \ - TrueTypeFont.hpp \ - TTFAutohint.cpp \ - TTFAutohint.hpp \ - Unicode.cpp \ - Unicode.hpp \ - utility.hpp \ - utility.cpp \ + SpecialManager.hpp SpecialManager.cpp \ + StreamReader.hpp StreamReader.cpp \ + StreamWriter.hpp StreamWriter.cpp \ + Subfont.hpp Subfont.cpp \ + SVGCharHandler.hpp SVGCharHandler.cpp \ + SVGCharHandlerFactory.hpp SVGCharHandlerFactory.cpp \ + SVGCharPathHandler.hpp SVGCharPathHandler.cpp \ + SVGCharTspanTextHandler.hpp SVGCharTspanTextHandler.cpp \ + SVGOutput.hpp SVGOutput.cpp \ + SVGSingleCharTextHandler.hpp SVGSingleCharTextHandler.cpp \ + SVGTree.hpp SVGTree.cpp \ + System.hpp System.cpp \ + TensorProductPatch.hpp TensorProductPatch.cpp \ + Terminal.hpp Terminal.cpp \ + TFM.hpp TFM.cpp \ + ToUnicodeMap.hpp ToUnicodeMap.cpp \ + TpicSpecialHandler.hpp TpicSpecialHandler.cpp \ + TriangularPatch.hpp TriangularPatch.cpp \ + TrueTypeFont.hpp TrueTypeFont.cpp \ + TTFAutohint.hpp TTFAutohint.cpp \ + Unicode.hpp Unicode.cpp \ + utility.hpp utility.cpp \ VectorIterator.hpp \ VectorStream.hpp \ - version.hpp \ VFActions.hpp \ - VFReader.cpp \ - VFReader.hpp \ + VFReader.hpp VFReader.cpp \ windows.hpp \ - XMLDocument.cpp \ - XMLDocument.hpp \ - XMLNode.cpp \ - XMLNode.hpp \ - XMLString.cpp \ - XMLString.hpp \ + XMLDocument.hpp XMLDocument.cpp \ + XMLNode.hpp XMLNode.cpp \ + XMLString.hpp XMLString.cpp \ XXHashFunction.hpp \ ZLibOutputStream.hpp @@ -273,7 +181,16 @@ AM_CXXFLAGS = $(WARNING_CXXFLAGS) -Wnon-virtual-dtor \ AM_CXXFLAGS += \ $(POTRACE_CFLAGS) \ - $(XXHASH_CFLAGS) + $(XXHASH_CFLAGS) \ + $(KPATHSEA_INCLUDES) \ + $(POTRACE_INCLUDES) \ + $(FREETYPE2_INCLUDES) \ + $(LIBGS_INCLUDES) \ + $(CODE_COVERAGE_CFLAGS) + +if WIN32 +AM_CXXFLAGS += -DTEXLIVEWIN32 +endif WIN32 AM_LDFLAGS = \ $(KPSE_LIBS) \ @@ -284,8 +201,6 @@ AM_CFLAGS += \ -I$(dvisvgm_srcdir)/libs/ff-woff/fontforge \ -I$(dvisvgm_srcdir)/libs/ff-woff/inc -AM_CXXFLAGS += $(TTFAUTOHINT_CFLAGS) - AM_CXXFLAGS += \ $(BROTLI_CFLAGS) \ $(WOFF2_CFLAGS) @@ -296,23 +211,11 @@ else AM_CXXFLAGS += $(LIBCRYPTO_CFLAGS) endif -AM_LDFLAGS += $(TTFAUTOHINT_LIBS) endif -AM_CXXFLAGS += \ - $(KPATHSEA_INCLUDES) \ - $(POTRACE_INCLUDES) \ - $(FREETYPE2_INCLUDES) \ - $(ZLIB_INCLUDES) \ - $(LIBGS_INCLUDES) \ - $(CODE_COVERAGE_CFLAGS) - -if WIN32 -AM_CXXFLAGS += -DTEXLIVEWIN32 -endif WIN32 - -if ! TEXLIVE_BUILD # TL: do not try to rebuild these source files. +if ! TEXLIVE_BUILD + # the command-line parser class is generated from options.xml by opt2cpp $(srcdir)/CommandLine.hpp: options.xml rm -f $@ diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/Makefile.in b/Build/source/texk/dvisvgm/dvisvgm-src/src/Makefile.in index 7da31007555..47584fce862 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/Makefile.in +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/Makefile.in @@ -102,16 +102,17 @@ bin_PROGRAMS = dvisvgm$(EXEEXT) @USE_BUNDLED_MD5_TRUE@am__append_6 = ../libs/md5/libmd5.a @USE_BUNDLED_MD5_FALSE@am__append_7 = $(LIBCRYPTO_LIBS) @ENABLE_WOFF_TRUE@am__append_8 = ffwrapper.c ffwrapper.h -@ENABLE_WOFF_TRUE@am__append_9 = \ +@WIN32_TRUE@am__append_9 = -DTEXLIVEWIN32 +@ENABLE_WOFF_TRUE@am__append_10 = \ @ENABLE_WOFF_TRUE@ -I$(dvisvgm_srcdir)/libs/ff-woff/fontforge \ @ENABLE_WOFF_TRUE@ -I$(dvisvgm_srcdir)/libs/ff-woff/inc -@ENABLE_WOFF_TRUE@am__append_10 = $(TTFAUTOHINT_CFLAGS) \ -@ENABLE_WOFF_TRUE@ $(BROTLI_CFLAGS) $(WOFF2_CFLAGS) -@ENABLE_WOFF_TRUE@@USE_BUNDLED_MD5_TRUE@am__append_11 = -I$(dvisvgm_srcdir)/libs/md5 -@ENABLE_WOFF_TRUE@@USE_BUNDLED_MD5_FALSE@am__append_12 = $(LIBCRYPTO_CFLAGS) -@ENABLE_WOFF_TRUE@am__append_13 = $(TTFAUTOHINT_LIBS) -@WIN32_TRUE@am__append_14 = -DTEXLIVEWIN32 +@ENABLE_WOFF_TRUE@am__append_11 = \ +@ENABLE_WOFF_TRUE@ $(BROTLI_CFLAGS) \ +@ENABLE_WOFF_TRUE@ $(WOFF2_CFLAGS) + +@ENABLE_WOFF_TRUE@@USE_BUNDLED_MD5_TRUE@am__append_12 = -I$(dvisvgm_srcdir)/libs/md5 +@ENABLE_WOFF_TRUE@@USE_BUNDLED_MD5_FALSE@am__append_13 = $(LIBCRYPTO_CFLAGS) subdir = dvisvgm-src/src ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/../../m4/ax_cxx_compile_stdcxx.m4 \ @@ -145,83 +146,82 @@ am__v_AR_0 = @echo " AR " $@; am__v_AR_1 = libdvisvgm_a_AR = $(AR) $(ARFLAGS) libdvisvgm_a_LIBADD = -am__libdvisvgm_a_SOURCES_DIST = AGLTable.hpp BasicDVIReader.cpp \ - BasicDVIReader.hpp Bezier.cpp Bezier.hpp \ - BgColorSpecialHandler.cpp BgColorSpecialHandler.hpp Bitmap.cpp \ - Bitmap.hpp BoundingBox.cpp BoundingBox.hpp Calculator.cpp \ - Calculator.hpp Character.hpp CharMapID.cpp CharMapID.hpp \ - CLCommandLine.cpp CLCommandLine.hpp CLOption.hpp CMap.cpp \ - CMap.hpp CMapManager.cpp CMapManager.hpp CMapReader.cpp \ - CMapReader.hpp Color.cpp Color.hpp ColorSpecialHandler.cpp \ - ColorSpecialHandler.hpp CRC32.cpp CRC32.hpp \ - DependencyGraph.hpp Directory.cpp Directory.hpp DLLoader.cpp \ - DLLoader.hpp DVIActions.hpp DVIReader.cpp DVIReader.hpp \ - DvisvgmSpecialHandler.cpp DvisvgmSpecialHandler.hpp \ - DVIToSVG.cpp DVIToSVG.hpp DVIToSVGActions.cpp \ - DVIToSVGActions.hpp EmSpecialHandler.cpp EmSpecialHandler.hpp \ - EncFile.cpp EncFile.hpp EPSFile.cpp EPSFile.hpp EPSToSVG.hpp \ - FileFinder.cpp FileFinder.hpp FilePath.cpp FilePath.hpp \ - FileSystem.cpp FileSystem.hpp FixWord.hpp Font.cpp Font.hpp \ - FontCache.cpp FontCache.hpp FontEncoding.cpp FontEncoding.hpp \ - FontEngine.cpp FontEngine.hpp FontManager.cpp FontManager.hpp \ - FontMap.cpp FontMap.hpp FontMetrics.cpp FontMetrics.hpp \ - FontStyle.hpp FontWriter.cpp FontWriter.hpp GFGlyphTracer.cpp \ - GFGlyphTracer.hpp GFReader.cpp GFReader.hpp GFTracer.cpp \ - GFTracer.hpp Ghostscript.cpp Ghostscript.hpp Glyph.hpp \ - GlyphTracerMessages.hpp GraphicsPath.hpp HashFunction.cpp \ - HashFunction.hpp HtmlSpecialHandler.cpp HtmlSpecialHandler.hpp \ - HyperlinkManager.cpp HyperlinkManager.hpp ImageToSVG.cpp \ - ImageToSVG.hpp InputBuffer.cpp InputBuffer.hpp InputReader.cpp \ - InputReader.hpp JFM.cpp JFM.hpp Length.cpp Length.hpp \ - macros.hpp MapLine.cpp MapLine.hpp Matrix.cpp Matrix.hpp \ - MD5HashFunction.hpp Message.cpp Message.hpp \ - MessageException.hpp MetafontWrapper.cpp MetafontWrapper.hpp \ - NoPsSpecialHandler.cpp NoPsSpecialHandler.hpp \ - NumericRanges.hpp PageRanges.cpp PageRanges.hpp PageSize.cpp \ - PageSize.hpp Pair.hpp PapersizeSpecialHandler.cpp \ - PapersizeSpecialHandler.hpp PathClipper.cpp PathClipper.hpp \ - PDFParser.cpp PDFParser.hpp PDFToSVG.hpp PdfSpecialHandler.cpp \ - PdfSpecialHandler.hpp PreScanDVIReader.cpp \ - PreScanDVIReader.hpp Process.cpp Process.hpp psdefs.cpp \ - PSFilter.hpp PSInterpreter.cpp PSInterpreter.hpp PSPattern.cpp \ - PSPattern.hpp PSPreviewFilter.cpp PSPreviewFilter.hpp \ - PsSpecialHandler.cpp PsSpecialHandler.hpp RangeMap.cpp \ - RangeMap.hpp ShadingPatch.cpp ShadingPatch.hpp \ - SignalHandler.cpp SignalHandler.hpp SourceInput.cpp \ - SourceInput.hpp SpecialActions.hpp SpecialHandler.hpp \ - SpecialManager.cpp SpecialManager.hpp StreamReader.cpp \ - StreamReader.hpp StreamWriter.cpp StreamWriter.hpp Subfont.cpp \ - Subfont.hpp SVGCharHandler.cpp SVGCharHandler.hpp \ - SVGCharHandlerFactory.cpp SVGCharHandlerFactory.hpp \ - SVGCharPathHandler.cpp SVGCharPathHandler.hpp \ - SVGCharTspanTextHandler.cpp SVGCharTspanTextHandler.hpp \ - SVGOutput.cpp SVGOutput.hpp SVGSingleCharTextHandler.cpp \ - SVGSingleCharTextHandler.hpp SVGTree.cpp SVGTree.hpp \ - System.cpp System.hpp TensorProductPatch.cpp \ - TensorProductPatch.hpp Terminal.cpp Terminal.hpp TFM.cpp \ - TFM.hpp ToUnicodeMap.cpp ToUnicodeMap.hpp \ - TpicSpecialHandler.cpp TpicSpecialHandler.hpp \ - TriangularPatch.cpp TriangularPatch.hpp TrueTypeFont.cpp \ - TrueTypeFont.hpp TTFAutohint.cpp TTFAutohint.hpp Unicode.cpp \ - Unicode.hpp utility.hpp utility.cpp VectorIterator.hpp \ - VectorStream.hpp version.hpp VFActions.hpp VFReader.cpp \ - VFReader.hpp windows.hpp XMLDocument.cpp XMLDocument.hpp \ - XMLNode.cpp XMLNode.hpp XMLString.cpp XMLString.hpp \ - XXHashFunction.hpp ZLibOutputStream.hpp ffwrapper.c \ - ffwrapper.h +am__libdvisvgm_a_SOURCES_DIST = AGLTable.hpp BasicDVIReader.hpp \ + BasicDVIReader.cpp Bezier.hpp Bezier.cpp \ + BgColorSpecialHandler.hpp BgColorSpecialHandler.cpp Bitmap.hpp \ + Bitmap.cpp BoundingBox.hpp BoundingBox.cpp Calculator.hpp \ + Calculator.cpp Character.hpp CharMapID.hpp CharMapID.cpp \ + CLCommandLine.hpp CLCommandLine.cpp CMap.hpp CMap.cpp \ + CMapManager.hpp CMapManager.cpp CMapReader.hpp CMapReader.cpp \ + CLOption.hpp Color.hpp Color.cpp ColorSpecialHandler.hpp \ + ColorSpecialHandler.cpp CommandLine.hpp Directory.hpp \ + Directory.cpp DVIActions.hpp DLLoader.hpp DLLoader.cpp \ + DVIReader.hpp DVIReader.cpp DvisvgmSpecialHandler.hpp \ + DvisvgmSpecialHandler.cpp DVIToSVG.hpp DVIToSVG.cpp \ + DVIToSVGActions.hpp DVIToSVGActions.cpp EllipticalArc.hpp \ + EllipticalArc.cpp EmSpecialHandler.hpp EmSpecialHandler.cpp \ + EncFile.hpp EncFile.cpp EPSFile.hpp EPSFile.cpp EPSToSVG.hpp \ + FileFinder.hpp FileFinder.cpp FilePath.hpp FilePath.cpp \ + FileSystem.hpp FileSystem.cpp FixWord.hpp Font.hpp Font.cpp \ + FontCache.hpp FontCache.cpp FontEncoding.hpp FontEncoding.cpp \ + FontEngine.hpp FontEngine.cpp FontManager.hpp FontManager.cpp \ + FontMap.hpp FontMap.cpp FontMetrics.hpp FontMetrics.cpp \ + FontStyle.hpp FontWriter.hpp FontWriter.cpp GFGlyphTracer.hpp \ + GFGlyphTracer.cpp GFReader.hpp GFReader.cpp GFTracer.hpp \ + GFTracer.cpp Ghostscript.hpp Ghostscript.cpp Glyph.hpp \ + GlyphTracerMessages.hpp GraphicsPath.hpp HashFunction.hpp \ + HashFunction.cpp HtmlSpecialHandler.hpp HtmlSpecialHandler.cpp \ + HyperlinkManager.hpp HyperlinkManager.cpp ImageToSVG.hpp \ + ImageToSVG.cpp InputBuffer.hpp InputBuffer.cpp InputReader.hpp \ + InputReader.cpp JFM.hpp JFM.cpp Length.hpp Length.cpp \ + macros.hpp MapLine.hpp MapLine.cpp Matrix.hpp Matrix.cpp \ + MD5HashFunction.hpp Message.hpp Message.cpp \ + MessageException.hpp MetafontWrapper.hpp MetafontWrapper.cpp \ + NoPsSpecialHandler.hpp NoPsSpecialHandler.cpp \ + NumericRanges.hpp PageRanges.hpp PageRanges.cpp PageSize.hpp \ + PageSize.cpp Pair.hpp PapersizeSpecialHandler.hpp \ + PapersizeSpecialHandler.cpp PathClipper.hpp PathClipper.cpp \ + PDFParser.hpp PDFParser.cpp PdfSpecialHandler.hpp \ + PdfSpecialHandler.cpp PDFToSVG.hpp PreScanDVIReader.hpp \ + PreScanDVIReader.cpp Process.hpp Process.cpp psdefs.cpp \ + PSFilter.hpp PSInterpreter.hpp PSInterpreter.cpp PSPattern.hpp \ + PSPattern.cpp PSPreviewFilter.hpp PSPreviewFilter.cpp \ + PsSpecialHandler.hpp PsSpecialHandler.cpp RangeMap.hpp \ + RangeMap.cpp ShadingPatch.hpp ShadingPatch.cpp \ + SignalHandler.hpp SignalHandler.cpp SourceInput.hpp \ + SourceInput.cpp SpecialActions.hpp SpecialHandler.hpp \ + SpecialManager.hpp SpecialManager.cpp StreamReader.hpp \ + StreamReader.cpp StreamWriter.hpp StreamWriter.cpp Subfont.hpp \ + Subfont.cpp SVGCharHandler.hpp SVGCharHandler.cpp \ + SVGCharHandlerFactory.hpp SVGCharHandlerFactory.cpp \ + SVGCharPathHandler.hpp SVGCharPathHandler.cpp \ + SVGCharTspanTextHandler.hpp SVGCharTspanTextHandler.cpp \ + SVGOutput.hpp SVGOutput.cpp SVGSingleCharTextHandler.hpp \ + SVGSingleCharTextHandler.cpp SVGTree.hpp SVGTree.cpp \ + System.hpp System.cpp TensorProductPatch.hpp \ + TensorProductPatch.cpp Terminal.hpp Terminal.cpp TFM.hpp \ + TFM.cpp ToUnicodeMap.hpp ToUnicodeMap.cpp \ + TpicSpecialHandler.hpp TpicSpecialHandler.cpp \ + TriangularPatch.hpp TriangularPatch.cpp TrueTypeFont.hpp \ + TrueTypeFont.cpp TTFAutohint.hpp TTFAutohint.cpp Unicode.hpp \ + Unicode.cpp utility.hpp utility.cpp VectorIterator.hpp \ + VectorStream.hpp VFActions.hpp VFReader.hpp VFReader.cpp \ + windows.hpp XMLDocument.hpp XMLDocument.cpp XMLNode.hpp \ + XMLNode.cpp XMLString.hpp XMLString.cpp XXHashFunction.hpp \ + ZLibOutputStream.hpp ffwrapper.c ffwrapper.h @ENABLE_WOFF_TRUE@am__objects_1 = ffwrapper.$(OBJEXT) am_libdvisvgm_a_OBJECTS = BasicDVIReader.$(OBJEXT) Bezier.$(OBJEXT) \ BgColorSpecialHandler.$(OBJEXT) Bitmap.$(OBJEXT) \ BoundingBox.$(OBJEXT) Calculator.$(OBJEXT) CharMapID.$(OBJEXT) \ CLCommandLine.$(OBJEXT) CMap.$(OBJEXT) CMapManager.$(OBJEXT) \ CMapReader.$(OBJEXT) Color.$(OBJEXT) \ - ColorSpecialHandler.$(OBJEXT) CRC32.$(OBJEXT) \ - Directory.$(OBJEXT) DLLoader.$(OBJEXT) DVIReader.$(OBJEXT) \ + ColorSpecialHandler.$(OBJEXT) Directory.$(OBJEXT) \ + DLLoader.$(OBJEXT) DVIReader.$(OBJEXT) \ DvisvgmSpecialHandler.$(OBJEXT) DVIToSVG.$(OBJEXT) \ - DVIToSVGActions.$(OBJEXT) EmSpecialHandler.$(OBJEXT) \ - EncFile.$(OBJEXT) EPSFile.$(OBJEXT) FileFinder.$(OBJEXT) \ - FilePath.$(OBJEXT) FileSystem.$(OBJEXT) Font.$(OBJEXT) \ - FontCache.$(OBJEXT) FontEncoding.$(OBJEXT) \ + DVIToSVGActions.$(OBJEXT) EllipticalArc.$(OBJEXT) \ + EmSpecialHandler.$(OBJEXT) EncFile.$(OBJEXT) EPSFile.$(OBJEXT) \ + FileFinder.$(OBJEXT) FilePath.$(OBJEXT) FileSystem.$(OBJEXT) \ + Font.$(OBJEXT) FontCache.$(OBJEXT) FontEncoding.$(OBJEXT) \ FontEngine.$(OBJEXT) FontManager.$(OBJEXT) FontMap.$(OBJEXT) \ FontMetrics.$(OBJEXT) FontWriter.$(OBJEXT) \ GFGlyphTracer.$(OBJEXT) GFReader.$(OBJEXT) GFTracer.$(OBJEXT) \ @@ -283,12 +283,12 @@ am__depfiles_remade = ./$(DEPDIR)/BasicDVIReader.Po \ ./$(DEPDIR)/Bitmap.Po ./$(DEPDIR)/BoundingBox.Po \ ./$(DEPDIR)/CLCommandLine.Po ./$(DEPDIR)/CMap.Po \ ./$(DEPDIR)/CMapManager.Po ./$(DEPDIR)/CMapReader.Po \ - ./$(DEPDIR)/CRC32.Po ./$(DEPDIR)/Calculator.Po \ - ./$(DEPDIR)/CharMapID.Po ./$(DEPDIR)/Color.Po \ - ./$(DEPDIR)/ColorSpecialHandler.Po ./$(DEPDIR)/DLLoader.Po \ - ./$(DEPDIR)/DVIReader.Po ./$(DEPDIR)/DVIToSVG.Po \ - ./$(DEPDIR)/DVIToSVGActions.Po ./$(DEPDIR)/Directory.Po \ - ./$(DEPDIR)/DvisvgmSpecialHandler.Po ./$(DEPDIR)/EPSFile.Po \ + ./$(DEPDIR)/Calculator.Po ./$(DEPDIR)/CharMapID.Po \ + ./$(DEPDIR)/Color.Po ./$(DEPDIR)/ColorSpecialHandler.Po \ + ./$(DEPDIR)/DLLoader.Po ./$(DEPDIR)/DVIReader.Po \ + ./$(DEPDIR)/DVIToSVG.Po ./$(DEPDIR)/DVIToSVGActions.Po \ + ./$(DEPDIR)/Directory.Po ./$(DEPDIR)/DvisvgmSpecialHandler.Po \ + ./$(DEPDIR)/EPSFile.Po ./$(DEPDIR)/EllipticalArc.Po \ ./$(DEPDIR)/EmSpecialHandler.Po ./$(DEPDIR)/EncFile.Po \ ./$(DEPDIR)/FileFinder.Po ./$(DEPDIR)/FilePath.Po \ ./$(DEPDIR)/FileSystem.Po ./$(DEPDIR)/Font.Po \ @@ -368,11 +368,27 @@ am__v_CXXLD_0 = @echo " CXXLD " $@; am__v_CXXLD_1 = SOURCES = $(libdvisvgm_a_SOURCES) $(dvisvgm_SOURCES) DIST_SOURCES = $(am__libdvisvgm_a_SOURCES_DIST) $(dvisvgm_SOURCES) +RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ + ctags-recursive dvi-recursive html-recursive info-recursive \ + install-data-recursive install-dvi-recursive \ + install-exec-recursive install-html-recursive \ + install-info-recursive install-pdf-recursive \ + install-ps-recursive install-recursive installcheck-recursive \ + installdirs-recursive pdf-recursive ps-recursive \ + tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +am__recursive_targets = \ + $(RECURSIVE_TARGETS) \ + $(RECURSIVE_CLEAN_TARGETS) \ + $(am__extra_recursive_targets) +AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ + distdir distdir-am am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is @@ -392,14 +408,43 @@ am__define_uniq_tagged_files = \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) am__DIST_COMMON = $(srcdir)/../libs/defs.am $(srcdir)/Makefile.in \ $(srcdir)/version.hpp.in $(top_srcdir)/../../build-aux/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_CPPFLAGS = @AM_CPPFLAGS@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ -AM_LDFLAGS = $(KPSE_LIBS) $(CODE_COVERAGE_LDFLAGS) $(am__append_13) +AM_LDFLAGS = \ + $(KPSE_LIBS) \ + $(CODE_COVERAGE_LDFLAGS) + AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ @@ -545,6 +590,7 @@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ noinst_LIBRARIES = libdvisvgm.a +SUBDIRS = optimizer dvisvgm_SOURCES = \ CommandLine.hpp \ dvisvgm.cpp @@ -553,87 +599,88 @@ dvisvgm_SOURCES = \ @HAVE_POTRACE_FALSE@POTRACE_LIBS = ../libs/potrace/libpotrace.a @HAVE_XXHASH_FALSE@XXHASH_CFLAGS = -I$(dvisvgm_srcdir)/libs/xxHash @HAVE_XXHASH_FALSE@XXHASH_LIBS = ../libs/xxHash/libxxhash.a -dvisvgm_LDADD = $(noinst_LIBRARIES) ../libs/clipper/libclipper.a \ - $(POTRACE_LIBS) $(XXHASH_LIBS) $(am__append_5) $(am__append_6) \ - $(am__append_7) $(KPATHSEA_LIBS) $(FREETYPE2_LIBS) \ - $(FONTFORGE_LIBS) $(ZLIB_LIBS) $(LIBGS_LIBS) +dvisvgm_LDADD = $(noinst_LIBRARIES) optimizer/liboptimizer.a \ + ../libs/clipper/libclipper.a $(POTRACE_LIBS) $(XXHASH_LIBS) \ + $(am__append_5) $(am__append_6) $(am__append_7) \ + $(KPATHSEA_LIBS) $(FREETYPE2_LIBS) $(FONTFORGE_LIBS) \ + $(ZLIB_LIBS) $(LIBGS_LIBS) dvisvgm_DEPENDENCIES = $(noinst_LIBRARIES) $(KPATHSEA_DEPEND) \ $(ZLIB_DEPEND) $(FREETYPE2_DEPEND) -libdvisvgm_a_SOURCES = AGLTable.hpp BasicDVIReader.cpp \ - BasicDVIReader.hpp Bezier.cpp Bezier.hpp \ - BgColorSpecialHandler.cpp BgColorSpecialHandler.hpp Bitmap.cpp \ - Bitmap.hpp BoundingBox.cpp BoundingBox.hpp Calculator.cpp \ - Calculator.hpp Character.hpp CharMapID.cpp CharMapID.hpp \ - CLCommandLine.cpp CLCommandLine.hpp CLOption.hpp CMap.cpp \ - CMap.hpp CMapManager.cpp CMapManager.hpp CMapReader.cpp \ - CMapReader.hpp Color.cpp Color.hpp ColorSpecialHandler.cpp \ - ColorSpecialHandler.hpp CRC32.cpp CRC32.hpp \ - DependencyGraph.hpp Directory.cpp Directory.hpp DLLoader.cpp \ - DLLoader.hpp DVIActions.hpp DVIReader.cpp DVIReader.hpp \ - DvisvgmSpecialHandler.cpp DvisvgmSpecialHandler.hpp \ - DVIToSVG.cpp DVIToSVG.hpp DVIToSVGActions.cpp \ - DVIToSVGActions.hpp EmSpecialHandler.cpp EmSpecialHandler.hpp \ - EncFile.cpp EncFile.hpp EPSFile.cpp EPSFile.hpp EPSToSVG.hpp \ - FileFinder.cpp FileFinder.hpp FilePath.cpp FilePath.hpp \ - FileSystem.cpp FileSystem.hpp FixWord.hpp Font.cpp Font.hpp \ - FontCache.cpp FontCache.hpp FontEncoding.cpp FontEncoding.hpp \ - FontEngine.cpp FontEngine.hpp FontManager.cpp FontManager.hpp \ - FontMap.cpp FontMap.hpp FontMetrics.cpp FontMetrics.hpp \ - FontStyle.hpp FontWriter.cpp FontWriter.hpp GFGlyphTracer.cpp \ - GFGlyphTracer.hpp GFReader.cpp GFReader.hpp GFTracer.cpp \ - GFTracer.hpp Ghostscript.cpp Ghostscript.hpp Glyph.hpp \ - GlyphTracerMessages.hpp GraphicsPath.hpp HashFunction.cpp \ - HashFunction.hpp HtmlSpecialHandler.cpp HtmlSpecialHandler.hpp \ - HyperlinkManager.cpp HyperlinkManager.hpp ImageToSVG.cpp \ - ImageToSVG.hpp InputBuffer.cpp InputBuffer.hpp InputReader.cpp \ - InputReader.hpp JFM.cpp JFM.hpp Length.cpp Length.hpp \ - macros.hpp MapLine.cpp MapLine.hpp Matrix.cpp Matrix.hpp \ - MD5HashFunction.hpp Message.cpp Message.hpp \ - MessageException.hpp MetafontWrapper.cpp MetafontWrapper.hpp \ - NoPsSpecialHandler.cpp NoPsSpecialHandler.hpp \ - NumericRanges.hpp PageRanges.cpp PageRanges.hpp PageSize.cpp \ - PageSize.hpp Pair.hpp PapersizeSpecialHandler.cpp \ - PapersizeSpecialHandler.hpp PathClipper.cpp PathClipper.hpp \ - PDFParser.cpp PDFParser.hpp PDFToSVG.hpp PdfSpecialHandler.cpp \ - PdfSpecialHandler.hpp PreScanDVIReader.cpp \ - PreScanDVIReader.hpp Process.cpp Process.hpp psdefs.cpp \ - PSFilter.hpp PSInterpreter.cpp PSInterpreter.hpp PSPattern.cpp \ - PSPattern.hpp PSPreviewFilter.cpp PSPreviewFilter.hpp \ - PsSpecialHandler.cpp PsSpecialHandler.hpp RangeMap.cpp \ - RangeMap.hpp ShadingPatch.cpp ShadingPatch.hpp \ - SignalHandler.cpp SignalHandler.hpp SourceInput.cpp \ - SourceInput.hpp SpecialActions.hpp SpecialHandler.hpp \ - SpecialManager.cpp SpecialManager.hpp StreamReader.cpp \ - StreamReader.hpp StreamWriter.cpp StreamWriter.hpp Subfont.cpp \ - Subfont.hpp SVGCharHandler.cpp SVGCharHandler.hpp \ - SVGCharHandlerFactory.cpp SVGCharHandlerFactory.hpp \ - SVGCharPathHandler.cpp SVGCharPathHandler.hpp \ - SVGCharTspanTextHandler.cpp SVGCharTspanTextHandler.hpp \ - SVGOutput.cpp SVGOutput.hpp SVGSingleCharTextHandler.cpp \ - SVGSingleCharTextHandler.hpp SVGTree.cpp SVGTree.hpp \ - System.cpp System.hpp TensorProductPatch.cpp \ - TensorProductPatch.hpp Terminal.cpp Terminal.hpp TFM.cpp \ - TFM.hpp ToUnicodeMap.cpp ToUnicodeMap.hpp \ - TpicSpecialHandler.cpp TpicSpecialHandler.hpp \ - TriangularPatch.cpp TriangularPatch.hpp TrueTypeFont.cpp \ - TrueTypeFont.hpp TTFAutohint.cpp TTFAutohint.hpp Unicode.cpp \ - Unicode.hpp utility.hpp utility.cpp VectorIterator.hpp \ - VectorStream.hpp version.hpp VFActions.hpp VFReader.cpp \ - VFReader.hpp windows.hpp XMLDocument.cpp XMLDocument.hpp \ - XMLNode.cpp XMLNode.hpp XMLString.cpp XMLString.hpp \ - XXHashFunction.hpp ZLibOutputStream.hpp $(am__append_8) +libdvisvgm_a_SOURCES = AGLTable.hpp BasicDVIReader.hpp \ + BasicDVIReader.cpp Bezier.hpp Bezier.cpp \ + BgColorSpecialHandler.hpp BgColorSpecialHandler.cpp Bitmap.hpp \ + Bitmap.cpp BoundingBox.hpp BoundingBox.cpp Calculator.hpp \ + Calculator.cpp Character.hpp CharMapID.hpp CharMapID.cpp \ + CLCommandLine.hpp CLCommandLine.cpp CMap.hpp CMap.cpp \ + CMapManager.hpp CMapManager.cpp CMapReader.hpp CMapReader.cpp \ + CLOption.hpp Color.hpp Color.cpp ColorSpecialHandler.hpp \ + ColorSpecialHandler.cpp CommandLine.hpp Directory.hpp \ + Directory.cpp DVIActions.hpp DLLoader.hpp DLLoader.cpp \ + DVIReader.hpp DVIReader.cpp DvisvgmSpecialHandler.hpp \ + DvisvgmSpecialHandler.cpp DVIToSVG.hpp DVIToSVG.cpp \ + DVIToSVGActions.hpp DVIToSVGActions.cpp EllipticalArc.hpp \ + EllipticalArc.cpp EmSpecialHandler.hpp EmSpecialHandler.cpp \ + EncFile.hpp EncFile.cpp EPSFile.hpp EPSFile.cpp EPSToSVG.hpp \ + FileFinder.hpp FileFinder.cpp FilePath.hpp FilePath.cpp \ + FileSystem.hpp FileSystem.cpp FixWord.hpp Font.hpp Font.cpp \ + FontCache.hpp FontCache.cpp FontEncoding.hpp FontEncoding.cpp \ + FontEngine.hpp FontEngine.cpp FontManager.hpp FontManager.cpp \ + FontMap.hpp FontMap.cpp FontMetrics.hpp FontMetrics.cpp \ + FontStyle.hpp FontWriter.hpp FontWriter.cpp GFGlyphTracer.hpp \ + GFGlyphTracer.cpp GFReader.hpp GFReader.cpp GFTracer.hpp \ + GFTracer.cpp Ghostscript.hpp Ghostscript.cpp Glyph.hpp \ + GlyphTracerMessages.hpp GraphicsPath.hpp HashFunction.hpp \ + HashFunction.cpp HtmlSpecialHandler.hpp HtmlSpecialHandler.cpp \ + HyperlinkManager.hpp HyperlinkManager.cpp ImageToSVG.hpp \ + ImageToSVG.cpp InputBuffer.hpp InputBuffer.cpp InputReader.hpp \ + InputReader.cpp JFM.hpp JFM.cpp Length.hpp Length.cpp \ + macros.hpp MapLine.hpp MapLine.cpp Matrix.hpp Matrix.cpp \ + MD5HashFunction.hpp Message.hpp Message.cpp \ + MessageException.hpp MetafontWrapper.hpp MetafontWrapper.cpp \ + NoPsSpecialHandler.hpp NoPsSpecialHandler.cpp \ + NumericRanges.hpp PageRanges.hpp PageRanges.cpp PageSize.hpp \ + PageSize.cpp Pair.hpp PapersizeSpecialHandler.hpp \ + PapersizeSpecialHandler.cpp PathClipper.hpp PathClipper.cpp \ + PDFParser.hpp PDFParser.cpp PdfSpecialHandler.hpp \ + PdfSpecialHandler.cpp PDFToSVG.hpp PreScanDVIReader.hpp \ + PreScanDVIReader.cpp Process.hpp Process.cpp psdefs.cpp \ + PSFilter.hpp PSInterpreter.hpp PSInterpreter.cpp PSPattern.hpp \ + PSPattern.cpp PSPreviewFilter.hpp PSPreviewFilter.cpp \ + PsSpecialHandler.hpp PsSpecialHandler.cpp RangeMap.hpp \ + RangeMap.cpp ShadingPatch.hpp ShadingPatch.cpp \ + SignalHandler.hpp SignalHandler.cpp SourceInput.hpp \ + SourceInput.cpp SpecialActions.hpp SpecialHandler.hpp \ + SpecialManager.hpp SpecialManager.cpp StreamReader.hpp \ + StreamReader.cpp StreamWriter.hpp StreamWriter.cpp Subfont.hpp \ + Subfont.cpp SVGCharHandler.hpp SVGCharHandler.cpp \ + SVGCharHandlerFactory.hpp SVGCharHandlerFactory.cpp \ + SVGCharPathHandler.hpp SVGCharPathHandler.cpp \ + SVGCharTspanTextHandler.hpp SVGCharTspanTextHandler.cpp \ + SVGOutput.hpp SVGOutput.cpp SVGSingleCharTextHandler.hpp \ + SVGSingleCharTextHandler.cpp SVGTree.hpp SVGTree.cpp \ + System.hpp System.cpp TensorProductPatch.hpp \ + TensorProductPatch.cpp Terminal.hpp Terminal.cpp TFM.hpp \ + TFM.cpp ToUnicodeMap.hpp ToUnicodeMap.cpp \ + TpicSpecialHandler.hpp TpicSpecialHandler.cpp \ + TriangularPatch.hpp TriangularPatch.cpp TrueTypeFont.hpp \ + TrueTypeFont.cpp TTFAutohint.hpp TTFAutohint.cpp Unicode.hpp \ + Unicode.cpp utility.hpp utility.cpp VectorIterator.hpp \ + VectorStream.hpp VFActions.hpp VFReader.hpp VFReader.cpp \ + windows.hpp XMLDocument.hpp XMLDocument.cpp XMLNode.hpp \ + XMLNode.cpp XMLString.hpp XMLString.cpp XXHashFunction.hpp \ + ZLibOutputStream.hpp $(am__append_8) EXTRA_DIST = options.xml options.dtd iapi.h ierrors.h MiKTeXCom.hpp MiKTeXCom.cpp AM_CFLAGS = $(WARNING_CFLAGS) $(ZLIB_INCLUDES) $(CODE_COVERAGE_CFLAGS) \ - $(am__append_9) + $(am__append_10) AM_CXXFLAGS = $(WARNING_CXXFLAGS) -Wnon-virtual-dtor \ -I$(dvisvgm_srcdir)/libs/clipper \ -I$(dvisvgm_srcdir)/libs/variant/include $(POTRACE_CFLAGS) \ - $(XXHASH_CFLAGS) $(am__append_10) $(am__append_11) \ - $(am__append_12) $(KPATHSEA_INCLUDES) $(POTRACE_INCLUDES) \ - $(FREETYPE2_INCLUDES) $(ZLIB_INCLUDES) $(LIBGS_INCLUDES) \ - $(CODE_COVERAGE_CFLAGS) $(am__append_14) + $(XXHASH_CFLAGS) $(KPATHSEA_INCLUDES) $(POTRACE_INCLUDES) \ + $(FREETYPE2_INCLUDES) $(LIBGS_INCLUDES) \ + $(CODE_COVERAGE_CFLAGS) $(am__append_9) $(am__append_11) \ + $(am__append_12) $(am__append_13) CLEANFILES = *.gcda *.gcno -all: all-am +all: all-recursive .SUFFIXES: .SUFFIXES: .c .cpp .lo .o .obj @@ -746,7 +793,6 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CMap.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CMapManager.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CMapReader.Po@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CRC32.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Calculator.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CharMapID.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Color.Po@am__quote@ # am--include-marker @@ -758,6 +804,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Directory.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DvisvgmSpecialHandler.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/EPSFile.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/EllipticalArc.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/EmSpecialHandler.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/EncFile.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FileFinder.Po@am__quote@ # am--include-marker @@ -894,14 +941,61 @@ mostlyclean-libtool: clean-libtool: -rm -rf .libs _libs +# This directory's subdirectories are mostly independent; you can cd +# into them and run 'make' without going through this Makefile. +# To change the values of 'make' variables: instead of editing Makefiles, +# (1) if the variable is set in 'config.status', edit 'config.status' +# (which will cause the Makefiles to be regenerated when you run 'make'); +# (2) otherwise, pass the desired values on the 'make' command line. +$(am__recursive_targets): + @fail=; \ + if $(am__make_keepgoing); then \ + failcom='fail=yes'; \ + else \ + failcom='exit 1'; \ + fi; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique -tags: tags-am +tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ @@ -914,7 +1008,7 @@ tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $$unique; \ fi; \ fi -ctags: ctags-am +ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) @@ -927,7 +1021,7 @@ GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" -cscopelist: cscopelist-am +cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ @@ -979,22 +1073,48 @@ distdir-am: $(DISTFILES) || exit 1; \ fi; \ done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + $(am__make_dryrun) \ + || test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done check-am: all-am -check: check-am +check: check-recursive all-am: Makefile $(PROGRAMS) $(LIBRARIES) -installdirs: +installdirs: installdirs-recursive +installdirs-am: for dir in "$(DESTDIR)$(bindir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done -install: install-am -install-exec: install-exec-am -install-data: install-data-am -uninstall: uninstall-am +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am -installcheck: installcheck-am +installcheck: installcheck-recursive install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ @@ -1017,12 +1137,12 @@ distclean-generic: maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -clean: clean-am +clean: clean-recursive clean-am: clean-binPROGRAMS clean-generic clean-libtool \ clean-noinstLIBRARIES mostlyclean-am -distclean: distclean-am +distclean: distclean-recursive -rm -f ./$(DEPDIR)/BasicDVIReader.Po -rm -f ./$(DEPDIR)/Bezier.Po -rm -f ./$(DEPDIR)/BgColorSpecialHandler.Po @@ -1032,7 +1152,6 @@ distclean: distclean-am -rm -f ./$(DEPDIR)/CMap.Po -rm -f ./$(DEPDIR)/CMapManager.Po -rm -f ./$(DEPDIR)/CMapReader.Po - -rm -f ./$(DEPDIR)/CRC32.Po -rm -f ./$(DEPDIR)/Calculator.Po -rm -f ./$(DEPDIR)/CharMapID.Po -rm -f ./$(DEPDIR)/Color.Po @@ -1044,6 +1163,7 @@ distclean: distclean-am -rm -f ./$(DEPDIR)/Directory.Po -rm -f ./$(DEPDIR)/DvisvgmSpecialHandler.Po -rm -f ./$(DEPDIR)/EPSFile.Po + -rm -f ./$(DEPDIR)/EllipticalArc.Po -rm -f ./$(DEPDIR)/EmSpecialHandler.Po -rm -f ./$(DEPDIR)/EncFile.Po -rm -f ./$(DEPDIR)/FileFinder.Po @@ -1123,47 +1243,47 @@ distclean: distclean-am distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags -dvi: dvi-am +dvi: dvi-recursive dvi-am: -html: html-am +html: html-recursive html-am: -info: info-am +info: info-recursive info-am: install-data-am: -install-dvi: install-dvi-am +install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-binPROGRAMS -install-html: install-html-am +install-html: install-html-recursive install-html-am: -install-info: install-info-am +install-info: install-info-recursive install-info-am: install-man: -install-pdf: install-pdf-am +install-pdf: install-pdf-recursive install-pdf-am: -install-ps: install-ps-am +install-ps: install-ps-recursive install-ps-am: installcheck-am: -maintainer-clean: maintainer-clean-am +maintainer-clean: maintainer-clean-recursive -rm -f ./$(DEPDIR)/BasicDVIReader.Po -rm -f ./$(DEPDIR)/Bezier.Po -rm -f ./$(DEPDIR)/BgColorSpecialHandler.Po @@ -1173,7 +1293,6 @@ maintainer-clean: maintainer-clean-am -rm -f ./$(DEPDIR)/CMap.Po -rm -f ./$(DEPDIR)/CMapManager.Po -rm -f ./$(DEPDIR)/CMapReader.Po - -rm -f ./$(DEPDIR)/CRC32.Po -rm -f ./$(DEPDIR)/Calculator.Po -rm -f ./$(DEPDIR)/CharMapID.Po -rm -f ./$(DEPDIR)/Color.Po @@ -1185,6 +1304,7 @@ maintainer-clean: maintainer-clean-am -rm -f ./$(DEPDIR)/Directory.Po -rm -f ./$(DEPDIR)/DvisvgmSpecialHandler.Po -rm -f ./$(DEPDIR)/EPSFile.Po + -rm -f ./$(DEPDIR)/EllipticalArc.Po -rm -f ./$(DEPDIR)/EmSpecialHandler.Po -rm -f ./$(DEPDIR)/EncFile.Po -rm -f ./$(DEPDIR)/FileFinder.Po @@ -1263,42 +1383,44 @@ maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic -mostlyclean: mostlyclean-am +mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool -pdf: pdf-am +pdf: pdf-recursive pdf-am: -ps: ps-am +ps: ps-recursive ps-am: uninstall-am: uninstall-binPROGRAMS -.MAKE: install-am install-strip - -.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ - clean-binPROGRAMS clean-generic clean-libtool \ - clean-noinstLIBRARIES cscopelist-am ctags ctags-am distclean \ - distclean-compile distclean-generic distclean-libtool \ - distclean-tags distdir dvi dvi-am html html-am info info-am \ - install install-am install-binPROGRAMS install-data \ - install-data-am install-dvi install-dvi-am install-exec \ - install-exec-am install-html install-html-am install-info \ - install-info-am install-man install-pdf install-pdf-am \ - install-ps install-ps-am install-strip installcheck \ - installcheck-am installdirs maintainer-clean \ - maintainer-clean-generic mostlyclean mostlyclean-compile \ - mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ - tags tags-am uninstall uninstall-am uninstall-binPROGRAMS +.MAKE: $(am__recursive_targets) install-am install-strip + +.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \ + am--depfiles check check-am clean clean-binPROGRAMS \ + clean-generic clean-libtool clean-noinstLIBRARIES \ + cscopelist-am ctags ctags-am distclean distclean-compile \ + distclean-generic distclean-libtool distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-binPROGRAMS install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + installdirs-am maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \ + uninstall-am uninstall-binPROGRAMS .PRECIOUS: Makefile # TL: do not try to rebuild these source files. + # the command-line parser class is generated from options.xml by opt2cpp @TEXLIVE_BUILD_FALSE@$(srcdir)/CommandLine.hpp: options.xml @TEXLIVE_BUILD_FALSE@ rm -f $@ diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/MapLine.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/MapLine.cpp index eb82372ce58..57aa116f028 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/MapLine.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/MapLine.cpp @@ -28,11 +28,6 @@ using namespace std; -MapLine::MapLine () : _sfd(0), _fontindex(0), _slant(0), _bold(0), _extend(1) -{ -} - - /** Constructs a MapLine object by parsing a single map line from the given stream. */ MapLine::MapLine (istream &is) : MapLine() { char buf[256]; @@ -226,9 +221,7 @@ void MapLine::parseDVIPDFMLine (InputReader &ir) { throw_number_expected('w', true); break; default: - ostringstream oss; - oss << "invalid option: -" << option; - throw MapLineException(oss.str()); + throw MapLineException("invalid option: -" + string(1, option)); } ir.skipSpace(); } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/MapLine.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/MapLine.hpp index 1620becd5e7..ea41fae0d02 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/MapLine.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/MapLine.hpp @@ -31,17 +31,15 @@ class InputReader; class SubfontDefinition; -struct MapLineException : MessageException -{ - MapLineException (const std::string &msg) : MessageException(msg) {} +struct MapLineException : MessageException { + explicit MapLineException (const std::string &msg) : MessageException(msg) {} }; -class MapLine -{ +class MapLine { public: - MapLine (std::istream &is); - MapLine (std::string str); + explicit MapLine (std::istream &is); + explicit MapLine (std::string str); const std::string& texname () const {return _texname;} const std::string& psname () const {return _psname;} const std::string& fontfname () const {return _fontfname;} @@ -53,8 +51,7 @@ class MapLine SubfontDefinition* sfd () const {return _sfd;} protected: - MapLine (); - void init (); + MapLine () =default; bool isDVIPSFormat (const char *line) const; void parse (const char *line); void parseDVIPSLine (InputReader &ir); @@ -62,13 +59,13 @@ class MapLine void parseFilenameOptions (std::string opt); private: - std::string _texname; ///< TeX font name - std::string _psname; ///< PS font name - std::string _fontfname; ///< name of fontfile - std::string _encname; ///< name of encoding (without file suffix ".enc") - SubfontDefinition *_sfd; ///< subfont definition to be used - int _fontindex; ///< font index of file with multiple fonts (e.g. ttc files) - double _slant, _bold, _extend; + std::string _texname; ///< TeX font name + std::string _psname; ///< PS font name + std::string _fontfname; ///< name of fontfile + std::string _encname; ///< name of encoding (without file suffix ".enc") + SubfontDefinition *_sfd=nullptr; ///< subfont definition to be used + int _fontindex=0; ///< font index of file with multiple fonts (e.g. ttc files) + double _slant=0, _bold=0, _extend=1; }; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/Matrix.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/Matrix.cpp index 1f9ff9ac0fa..f94e84809c1 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/Matrix.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/Matrix.cpp @@ -70,7 +70,7 @@ Matrix::Matrix (double d) { * remaining matrix components will be set to those of the identity matrix. * @param[in] v array containing the matrix components * @param[in] size size of array v */ -Matrix::Matrix (double v[], unsigned size) { +Matrix::Matrix (const double *v, unsigned size) { set(v, size); } @@ -86,7 +86,7 @@ Matrix::Matrix (const std::vector<double> &v, int start) { Matrix::Matrix (const string &cmds, Calculator &calc) { - parse(cmds, calc); + *this = parse(cmds, calc); } @@ -109,7 +109,7 @@ Matrix& Matrix::set (double d) { } -Matrix& Matrix::set (double v[], unsigned size) { +Matrix& Matrix::set (const double *v, unsigned size) { size = min(size, 9u); for (unsigned i=0; i < size; i++) _values[i/3][i%3] = v[i]; @@ -134,8 +134,8 @@ Matrix& Matrix::set (const vector<double> &v, int start) { } -Matrix& Matrix::set(const string &cmds, Calculator &calc) { - parse(cmds, calc); +Matrix& Matrix::set (const string &cmds, Calculator &calc) { + *this = parse(cmds, calc); return *this; } @@ -143,7 +143,7 @@ Matrix& Matrix::set(const string &cmds, Calculator &calc) { Matrix& Matrix::translate (double tx, double ty) { if (tx != 0 || ty != 0) { TranslationMatrix t(tx, ty); - rmultiply(t); + lmultiply(t); } return *this; } @@ -152,7 +152,7 @@ Matrix& Matrix::translate (double tx, double ty) { Matrix& Matrix::scale (double sx, double sy) { if (sx != 1 || sy != 1) { ScalingMatrix s(sx, sy); - rmultiply(s); + lmultiply(s); } return *this; } @@ -163,7 +163,7 @@ Matrix& Matrix::scale (double sx, double sy) { * @param[in] deg rotation angle in degrees */ Matrix& Matrix::rotate (double deg) { RotationMatrix r(deg); - rmultiply(r); + lmultiply(r); return *this; } @@ -179,7 +179,7 @@ Matrix& Matrix::xskewByRatio (double xyratio) { if (xyratio != 0) { double v[] = {1, xyratio}; Matrix t(v, 2); - rmultiply(t); + lmultiply(t); } return *this; } @@ -196,7 +196,7 @@ Matrix& Matrix::yskewByRatio (double xyratio) { if (xyratio != 0) { double v[] = {1, 0, 0, xyratio}; Matrix t(v, 4); - rmultiply(t); + lmultiply(t); } return *this; } @@ -208,7 +208,7 @@ Matrix& Matrix::flip (bool haxis, double a) { s = -1; double v[] = {-s, 0, (haxis ? 0 : 2*a), 0, s, (haxis ? 2*a : 0), 0, 0, 1}; Matrix t(v); - rmultiply(t); + lmultiply(t); return *this; } @@ -222,8 +222,8 @@ Matrix& Matrix::transpose () { } -/** Multiplies this matrix M with matrix tm (tm is the factor on the left side): M := tm * M */ -Matrix& Matrix::lmultiply (const Matrix &tm) { +/** Multiplies this matrix M with matrix tm (tm is the factor on the right side): M := M * tm */ +Matrix& Matrix::rmultiply (const Matrix &tm) { Matrix ret; for (int i=0; i < 3; i++) for (int j=0; j < 3; j++) @@ -233,8 +233,8 @@ Matrix& Matrix::lmultiply (const Matrix &tm) { } -/** Multiplies this matrix M with matrix tm (tm is the factor on the right side): M := M * tm */ -Matrix& Matrix::rmultiply (const Matrix &tm) { +/** Multiplies this matrix M with matrix tm (tm is the factor on the left side): M := tm * M */ +Matrix& Matrix::lmultiply (const Matrix &tm) { Matrix ret; for (int i=0; i < 3; i++) for (int j=0; j < 3; j++) @@ -356,8 +356,8 @@ static double getArgument (istream &is, Calculator &calc, double def, bool optio } -Matrix& Matrix::parse (istream &is, Calculator &calc) { - *this = Matrix(1); +Matrix Matrix::parse (istream &is, Calculator &calc) { + Matrix ret(1); while (is) { is >> ws; int cmd = is.get(); @@ -365,22 +365,22 @@ Matrix& Matrix::parse (istream &is, Calculator &calc) { case 'T': { double tx = getArgument(is, calc, 0, false, false); double ty = getArgument(is, calc, 0, true, true); - translate(tx, ty); + ret.translate(tx, ty); break; } case 'S': { double sx = getArgument(is, calc, 1, false, false); double sy = getArgument(is, calc, sx, true, true ); - scale(sx, sy); + ret.scale(sx, sy); break; } case 'R': { double a = getArgument(is, calc, 0, false, false); double x = getArgument(is, calc, calc.getVariable("ux")+calc.getVariable("w")/2, true, true); double y = getArgument(is, calc, calc.getVariable("uy")+calc.getVariable("h")/2, true, true); - translate(-x, -y); - rotate(a); - translate(x, y); + ret.translate(-x, -y); + ret.rotate(a); + ret.translate(x, y); break; } case 'F': { @@ -388,7 +388,7 @@ Matrix& Matrix::parse (istream &is, Calculator &calc) { if (c != 'H' && c != 'V') throw ParserException("'H' or 'V' expected"); double a = getArgument(is, calc, 0, false, false); - flip(c == 'H', a); + ret.flip(c == 'H', a); break; } case 'K': { @@ -396,15 +396,12 @@ Matrix& Matrix::parse (istream &is, Calculator &calc) { if (c != 'X' && c != 'Y') throw ParserException("transformation command 'K' must be followed by 'X' or 'Y'"); double a = getArgument(is, calc, 0, false, false); - if (std::abs(cos(deg2rad(a))) < numeric_limits<double>::epsilon()) { - ostringstream oss; - oss << "illegal skewing angle: " << a << " degrees"; - throw ParserException(oss.str()); - } + if (std::abs(cos(deg2rad(a))) < numeric_limits<double>::epsilon()) + throw ParserException("illegal skewing angle: " + util::to_string(a) + " degrees"); if (c == 'X') - xskewByAngle(a); + ret.xskewByAngle(a); else - yskewByAngle(a); + ret.yskewByAngle(a); break; } case 'M': { @@ -415,20 +412,18 @@ Matrix& Matrix::parse (istream &is, Calculator &calc) { v[6] = v[7] = 0; v[8] = 1; Matrix tm(v); - rmultiply(tm); + ret.lmultiply(tm); break; } default: - ostringstream oss; - oss << "transformation command expected (found '" << char(cmd) << "' instead)"; - throw ParserException(oss.str()); + throw ParserException("transformation command expected (found '" + string(1, cmd) + "' instead)"); } } - return *this; + return ret; } -Matrix& Matrix::parse (const string &cmds, Calculator &calc) { +Matrix Matrix::parse (const string &cmds, Calculator &calc) { istringstream iss; iss.str(cmds); return parse(iss, calc); @@ -437,17 +432,14 @@ Matrix& Matrix::parse (const string &cmds, Calculator &calc) { /** Returns an SVG matrix expression that can be used in transform attributes. * ((a,b,c),(d,e,f),(0,0,1)) => matrix(a d b e c f) */ -string Matrix::getSVG () const { +string Matrix::toSVG () const { ostringstream oss; oss << "matrix("; for (int i=0; i < 3; i++) { - for (int j=0; j < 2; j++) { - if (i > 0 || j > 0) - oss << ' '; - oss << XMLString(_values[j][i]); - } + for (int j=0; j < 2; j++) + oss << XMLString(_values[j][i]) << ' '; } - oss << ')'; + oss.seekp(-1, ios::cur) << ')'; // overwrite trailing space character return oss.str(); } @@ -467,9 +459,118 @@ ostream& Matrix::write (ostream &os) const { } -////////////////////////////////////////////////////////////////// +static const char* ord_suffix (int n) { + static const char *suffixes[] = {"th", "st", "nd", "rd"}; + if (abs(n) < 4) + return suffixes[n]; + return suffixes[0]; +} + + +static void skip_comma_wsp (istream &is) { + is >> ws; + if (is.peek() == ',') is.ignore(1); + is >> ws; +} + + +static size_t parse_transform_cmd (istream &is, string cmd, size_t minparams, size_t maxparams, vector<double> ¶ms) { + for (int i=0; i < int(cmd.length()); i++) { + if (is.get() != cmd[i]) { + is.seekg(-i-1, ios::cur); + return 0; + } + } + params.clear(); + is >> ws; + if (is.get() != '(') + throw ParserException("missing '(' after command '"+cmd+"'"); + for (size_t i=1; i <= maxparams; i++) { + is >> ws; + double val; + if (is.fail()) + throw ParserException(to_string(i)+ord_suffix(i)+" parameter of '"+cmd+"' must be a number"); + is >> val; + params.push_back(val); + is >> ws; + if (i == minparams && is.peek() == ')') { + is.ignore(1); + return i; + } + if (i == maxparams) { + if (is.peek() != ')') + throw ParserException("missing ')' at end of command '"+cmd+"'"); + is.ignore(1); + } + skip_comma_wsp(is); + } + return maxparams; +} +static bool ne (double x, double y) {return abs(x-y) >= 1e-6;} +static bool ne_angle (double x, double y) {return abs(x-y) >= 1e-3;} + + +Matrix Matrix::parseSVGTransform (const string &transform) { + istringstream iss(transform); + Matrix matrix(1); + iss >> ws; + while (iss) { + vector<double> params; + if (parse_transform_cmd(iss, "matrix", 6, 6, params)) { + if (ne(params[0], 1) || ne(params[1], 0) || ne(params[2], 0) || ne(params[3], 1) || ne(params[4], 0) || ne(params[5], 0)) + matrix.rmultiply({params[0], params[2], params[4], params[1], params[3], params[5]}); + } + else if (parse_transform_cmd(iss, "rotate", 1, 3, params)) { + if (params.size() == 1) { + params.push_back(0); + params.push_back(0); + } + if (ne_angle(fmod(params[0], 360), 0)) { + bool translate = ne(params[1], 0) || ne(params[2], 0); + if (translate) + matrix.rmultiply(TranslationMatrix(params[1], params[2])); + matrix.rmultiply(RotationMatrix(params[0])); + if (translate) + matrix.rmultiply(TranslationMatrix(-params[1], -params[2])); + } + } + else if (parse_transform_cmd(iss, "scale", 1, 2, params)) { + if (params.size() == 1) + params.push_back(1); + if (ne(params[0], 1) || ne(params[1], 1)) + matrix.rmultiply(ScalingMatrix(params[0], params[1])); + } + else if (parse_transform_cmd(iss, "skewX", 1, 1, params)) { + if (ne_angle(fmod(abs(params[0])-90, 180), 0)) + matrix.rmultiply(XSkewingMatrix(params[0])); + } + else if (parse_transform_cmd(iss, "skewY", 1, 1, params)) { + if (ne_angle(fmod(abs(params[0])-90, 180), 0)) + matrix.rmultiply(YSkewingMatrix(params[0])); + } + else if (parse_transform_cmd(iss, "translate", 1, 2, params)) { + if (params.size() == 1) + params.push_back(0); + if (ne(params[0], 0) || ne(params[1], 0)) + matrix.rmultiply(TranslationMatrix(params[0], params[1])); + } + else { // invalid command + string cmd; + while (isalpha(iss.peek())) + cmd += char(iss.get()); + if (cmd.empty()) + throw ParserException("unexpected character in transform attribute: "+to_string(char(iss.get()))); + throw ParserException("invalid command in transform attribute: "+cmd); + } + skip_comma_wsp(iss); + } + return matrix; +} + +////////////////////////////////////////////////////////////////// + TranslationMatrix::TranslationMatrix (double tx, double ty) { double v[] = {1, 0, tx, 0, 1, ty}; set(v, 6); @@ -490,3 +591,14 @@ RotationMatrix::RotationMatrix (double deg) { set(v, 5); } + +XSkewingMatrix::XSkewingMatrix (double deg) { + double xyratio = tan(deg2rad(deg)); + lmultiply(Matrix({1, xyratio})); +} + + +YSkewingMatrix::YSkewingMatrix (double deg) { + double xyratio = tan(deg2rad(deg)); + lmultiply(Matrix({1, 0, 0, xyratio})); +} diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/Matrix.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/Matrix.hpp index 73b443a619c..733ff71fad8 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/Matrix.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/Matrix.hpp @@ -30,7 +30,7 @@ struct ParserException : public MessageException { - ParserException (const std::string &msg) : MessageException(msg) {} + explicit ParserException (const std::string &msg) : MessageException(msg) {} }; class Calculator; @@ -42,20 +42,18 @@ class Matrix { public: Matrix (const std::string &cmds, Calculator &calc); Matrix (double d=0); - Matrix (double v[], unsigned size=9); - Matrix (const std::vector<double> &v, int start=0); + explicit Matrix (const double *v, unsigned size=9); + explicit Matrix (const std::vector<double> &v, int start=0); Matrix (std::initializer_list<double> initlist); Matrix& set (double d); - Matrix& set (double v[], unsigned size); + Matrix& set (const double *v, unsigned size); Matrix& set (const std::vector<double> &v, int start=0); Matrix& set (const std::string &cmds, Calculator &calc); double get (int row, int col) const {return _values[row][col];} Matrix& transpose (); Matrix& invert (); - Matrix& parse (std::istream &is, Calculator &c); - Matrix& parse (const std::string &cmds, Calculator &c); - Matrix& lmultiply (const Matrix &tm); Matrix& rmultiply (const Matrix &tm); + Matrix& lmultiply (const Matrix &tm); Matrix& translate (double tx, double ty); Matrix& translate (const DPair &p) {return translate(p.x(), p.y());} Matrix& scale (double sx, double sy); @@ -72,9 +70,13 @@ class Matrix { bool operator != (const Matrix &m) const; bool isIdentity() const; bool isTranslation (double &tx, double &ty) const; - std::string getSVG () const; + std::string toSVG () const; std::ostream& write (std::ostream &os) const; + static Matrix parse (std::istream &is, Calculator &c); + static Matrix parse (const std::string &cmds, Calculator &c); + static Matrix parseSVGTransform (const std::string &transform); + private: double _values[3][3]; // row x col }; @@ -91,7 +93,17 @@ struct ScalingMatrix : public Matrix { struct RotationMatrix : public Matrix { - RotationMatrix (double deg); + explicit RotationMatrix (double deg); +}; + + +struct XSkewingMatrix : public Matrix { + explicit XSkewingMatrix (double deg); +}; + + +struct YSkewingMatrix : public Matrix { + explicit YSkewingMatrix (double deg); }; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/Message.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/Message.cpp index 4ab9fc89a7d..85ed204cb43 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/Message.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/Message.cpp @@ -28,12 +28,8 @@ using namespace std; -MessageStream::MessageStream () : _os(0), _nl(false), _col(1), _indent(0) { -} - - -MessageStream::MessageStream (std::ostream &os) - : _os(&os), _nl(true), _col(1), _indent(0) +MessageStream::MessageStream (std::ostream &os) noexcept + : _os(&os), _nl(true) { Terminal::init(os); } @@ -45,7 +41,7 @@ MessageStream::~MessageStream () { } -void MessageStream::putChar (const char c, ostream &os) { +void MessageStream::putChar (char c, ostream &os) { switch (c) { case '\r': os << '\r'; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/Message.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/Message.hpp index 95a96555637..a7e60340218 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/Message.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/Message.hpp @@ -31,13 +31,12 @@ class Message; -class MessageStream -{ +class MessageStream { friend class Message; public: - MessageStream (); - MessageStream (std::ostream &os); + MessageStream () =default; + explicit MessageStream (std::ostream &os) noexcept; ~MessageStream (); template <typename T> @@ -58,26 +57,25 @@ class MessageStream void clearline (); protected: - void putChar (const char c, std::ostream &os); + void putChar (char c, std::ostream &os); std::ostream* os () {return _os;} private: - std::ostream *_os; - bool _nl; ///< true if previous character was a newline - int _col; ///< current terminal column - int _indent; ///< indentation width (number of columns/characters) + std::ostream *_os=nullptr; + bool _nl=false; ///< true if previous character was a newline + int _col=1; ///< current terminal column + int _indent=0; ///< indentation width (number of columns/characters) }; -class Message -{ +class Message { struct Color { - Color () : foreground(-1), background(-1) {} - Color (int8_t fgcolor) : foreground(fgcolor), background(-1) {} - Color (int8_t fgcolor, bool light) : foreground(fgcolor + (light ? 8 : 0)), background(-1) {} - Color (int8_t fgcolor, int8_t bgcolor) : foreground(fgcolor), background(bgcolor) {} - int8_t foreground; - int8_t background; + Color () =default; + explicit Color (int8_t fgcolor) noexcept : foreground(fgcolor) {} + Color (int8_t fgcolor, bool light) noexcept: foreground(fgcolor + (light ? 8 : 0)) {} + Color (int8_t fgcolor, int8_t bgcolor) noexcept : foreground(fgcolor), background(bgcolor) {} + int8_t foreground = -1; + int8_t background = -1; }; public: diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/MessageException.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/MessageException.hpp index ccd6567d3d2..c7aa342860e 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/MessageException.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/MessageException.hpp @@ -25,12 +25,10 @@ #include <string> -class MessageException : public std::exception -{ +class MessageException : public std::exception { public: - MessageException (const std::string &msg) : _message(msg) {} - virtual ~MessageException () throw() =default; - const char* what () const throw() override {return _message.c_str();} + explicit MessageException (std::string msg) : _message(std::move(msg)) {} + const char* what () const noexcept override {return _message.c_str();} private: std::string _message; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/MetafontWrapper.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/MetafontWrapper.cpp index a5f8538c319..5807d7254ef 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/MetafontWrapper.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/MetafontWrapper.cpp @@ -18,7 +18,6 @@ ** along with this program; if not, see <http://www.gnu.org/licenses/>. ** *************************************************************************/ -#include <cstdlib> #include <cctype> #include <fstream> #include <sstream> @@ -32,12 +31,13 @@ using namespace std; -MetafontWrapper::MetafontWrapper (const string &fname, const string &dir) : _fontname(fname), _dir(dir) +MetafontWrapper::MetafontWrapper (string fname, string dir) + : _fontname(std::move(fname)), _dir(std::move(dir)) { // ensure that folder paths ends with slash if (_dir.empty()) _dir = "./"; - else if (_dir != "/" && dir[dir.length()-1] != '/') + else if (_dir != "/" && _dir.back() != '/') _dir += '/'; } @@ -87,7 +87,7 @@ bool MetafontWrapper::call (const string &mode, double mag) { iss.getline(buf, sizeof(buf)); string line = buf; if (line.substr(0, 3) == ">> ") { - resolution = atoi(line.substr(3).c_str()); + resolution = stoi(line.substr(3)); break; } } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/MetafontWrapper.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/MetafontWrapper.hpp index e1107afe9ba..031eb01ebd1 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/MetafontWrapper.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/MetafontWrapper.hpp @@ -29,7 +29,7 @@ class FileFinder; class MetafontWrapper { public: - MetafontWrapper (const std::string &fontname, const std::string &dir); + MetafontWrapper (std::string fname, std::string dir); bool call (const std::string &mode, double mag); bool make (const std::string &mode, double mag); bool success () const; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/MiKTeXCom.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/MiKTeXCom.hpp index c87d0e3d862..5bf19811674 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/MiKTeXCom.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/MiKTeXCom.hpp @@ -25,10 +25,10 @@ #include "windows.hpp" #ifdef _MSC_VER -#import <MiKTeX209-session.tlb> +#import <miktex-session.tlb> using namespace MiKTeXSession2_9; #else -#include "miktex209-session.h" +#include "miktex-session.h" #endif class MiKTeXCom { diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/NoPsSpecialHandler.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/NoPsSpecialHandler.hpp index 5f97cfdb27a..f4f04218856 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/NoPsSpecialHandler.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/NoPsSpecialHandler.hpp @@ -27,8 +27,8 @@ class NoPsSpecialHandler : public SpecialHandler { public: NoPsSpecialHandler () : _count(0) {} bool process (const std::string &prefix, std::istream &is, SpecialActions &actions) override; - const char* name () const override {return 0;} - const char* info () const override {return 0;} + const char* name () const override {return nullptr;} + const char* info () const override {return nullptr;} std::vector<const char*> prefixes() const override; protected: diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/PDFParser.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/PDFParser.cpp index 10dd9b1577c..1ecd40cba82 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/PDFParser.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/PDFParser.cpp @@ -119,7 +119,7 @@ static pair<bool,int> parse_escape_seq (InputReader &ir) { string str; for (int i=0; i < 3 && isoctaldigit(ir.peek()); i++) str += static_cast<char>(ir.get()); - return pair<bool,int>{true, stoi(str, 0, 8)}; + return pair<bool,int>{true, stoi(str, nullptr, 8)}; } char c = static_cast<char>(ir.get()); switch (c) { @@ -168,10 +168,8 @@ static string parse_literal_string (InputReader &ir) { static char get_hex_digit (InputReader &ir) { int c = ir.get(); if (isxdigit(c)) - return static_cast<char>(c); - ostringstream oss; - oss << "invalid hexadecimal digit '" << static_cast<char>(c) << "'"; - throw PDFException(oss.str()); + return char(c); + throw PDFException("invalid hexadecimal digit '" + string(1, char(c)) + "'"); } @@ -190,7 +188,7 @@ static string parse_hex_string (InputReader &ir) { else if (ir.peek() == '>') hexpair += '0'; ir.skipSpace(); - str += static_cast<char>(stoi(hexpair, 0, 16)); + str += static_cast<char>(stoi(hexpair, nullptr, 16)); } if (ir.peek() != '>') throw PDFException("missing '>' at end of hexadecimal string"); @@ -316,7 +314,7 @@ static string& subst_numeric_chars (string &str) { if (pos > str.length()-3) throw PDFException("sign character # must be followed by two hexadecimal digits"); if (isxdigit(str[pos+1]) && isxdigit(str[pos+2])) { - int c = stoi(str.substr(pos+1, 2), 0, 16); + int c = stoi(str.substr(pos+1, 2), nullptr, 16); if (c == 0) throw PDFException("null character not permitted in name"); str.replace(pos, 3, 1, static_cast<char>(c)); @@ -458,7 +456,7 @@ static ostream& operator << (ostream &os, const unique_ptr<Dictionary<string,PDF struct WriteVisitor { - WriteVisitor (ostream &os) : _os(os) {} + explicit WriteVisitor (ostream &os) : _os(os) {} template <typename T> void operator () (const T &val) {_os << val;} ostream &_os; }; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/PDFParser.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/PDFParser.hpp index f4595ce4de0..64716683077 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/PDFParser.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/PDFParser.hpp @@ -79,12 +79,12 @@ struct PDFObjectRef { }; struct PDFOperator { - PDFOperator (const std::string &name) : opname(name) {} + explicit PDFOperator (std::string name) : opname(std::move(name)) {} std::string opname; }; struct PDFName { - PDFName (const std::string &val) : str(val) {} + explicit PDFName (std::string val) : str(std::move(val)) {} bool operator == (const PDFName &name) const {return str == name.str;} std::string str; }; @@ -134,14 +134,14 @@ class PDFObject { template<> inline const PDFArray* PDFObject::get() const { - if (auto *p = mpark::get_if<std::unique_ptr<PDFArray>>(&_value)) + if (auto p = mpark::get_if<std::unique_ptr<PDFArray>>(&_value)) return &(**p); return nullptr; } template<> inline const PDFDict* PDFObject::get() const { - if (auto *p = mpark::get_if<std::unique_ptr<PDFDict>>(&_value)) + if (auto p = mpark::get_if<std::unique_ptr<PDFDict>>(&_value)) return &(**p); return nullptr; } @@ -179,7 +179,7 @@ class PDFParser { /** If errors occur while parsing a sequence of PDF objects, an instance of this exception is thrown. */ struct PDFException : public MessageException { - PDFException (const std::string &msg) : MessageException(msg) {} + explicit PDFException (const std::string &msg) : MessageException(msg) {} }; #endif diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/PDFToSVG.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/PDFToSVG.hpp index f999de88e8d..d1871d0bb1e 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/PDFToSVG.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/PDFToSVG.hpp @@ -60,4 +60,3 @@ class PDFToSVG : public ImageToSVG { }; #endif - diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/PSInterpreter.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/PSInterpreter.cpp index c27dcfea4bb..aa9cab21077 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/PSInterpreter.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/PSInterpreter.cpp @@ -51,8 +51,15 @@ void PSInterpreter::init () { "-dWRITESYSTEMDICT", // leave systemdict writable as some operators must be replaced "-dNOPROMPT" }; - if (int gsrev = _gs.revision()) + if (int gsrev = _gs.revision()) { gsargs.emplace_back(gsrev == 922 ? "-dREALLYDELAYBIND" : "-dDELAYBIND"); + // As of GS 9.50, -dSAFER is active by default which leads to warnings + // in conjunction with -dDELAYBIND and -dWRITESYSTEMDICT. + // Thus, -dDELAYSAFER (or -dNOSAFER) must be added. + // https://www.ghostscript.com/doc/9.50/Use.htm#Safer + if (gsrev >= 950) + gsargs.emplace_back("-dDELAYSAFER"); + } _gs.init(gsargs.size(), gsargs.data(), this); _gs.set_stdio(input, output, error); _initialized = true; @@ -111,7 +118,7 @@ bool PSInterpreter::execute (const char *str, size_t len, bool flush) { if (_filter && _filter->active()) { PSFilter *filter = _filter; - _filter = 0; // prevent recursion when filter calls execute() + _filter = nullptr; // prevent recursion when filter calls execute() filter->execute(str, len); if (filter->active()) // filter still active after execution? _filter = filter; @@ -189,7 +196,7 @@ int GSDLLCALL PSInterpreter::input (void *inst, char *buf, int len) { * @param[in] len number of characters in buf * @return number of processed characters (equals 'len') */ int GSDLLCALL PSInterpreter::output (void *inst, const char *buf, int len) { - PSInterpreter *self = static_cast<PSInterpreter*>(inst); + auto self = static_cast<PSInterpreter*>(inst); if (self && self->_actions) { const size_t MAXLEN = 512; // maximal line length (longer lines are of no interest) const char *end = buf+len-1; // last position of buf @@ -204,7 +211,7 @@ int GSDLLCALL PSInterpreter::output (void *inst, const char *buf, int len) { vector<char> &linebuf = self->_linebuf; // just a shorter name... if ((*last == '\n' || !self->active()) || self->_inError) { if (linelength + linebuf.size() > 1) { // prefix "dvi." plus final newline - SplittedCharInputBuffer ib(linebuf.empty() ? 0 : &linebuf[0], linebuf.size(), first, linelength); + SplittedCharInputBuffer ib(linebuf.empty() ? nullptr : &linebuf[0], linebuf.size(), first, linelength); BufferInputReader in(ib); if (self->_inError) self->_errorMessage += string(first, linelength); @@ -213,7 +220,7 @@ int GSDLLCALL PSInterpreter::output (void *inst, const char *buf, int len) { if (in.check("Unrecoverable error: ")) { self->_errorMessage.clear(); while (!in.eof()) - self->_errorMessage += in.get(); + self->_errorMessage += char(in.get()); self->_inError = true; } else if (in.check("dvi.")) @@ -279,6 +286,7 @@ void PSInterpreter::callActions (InputReader &in) { {"setlinewidth", { 1, &PSActions::setlinewidth}}, {"setmatrix", { 6, &PSActions::setmatrix}}, {"setmiterlimit", { 1, &PSActions::setmiterlimit}}, + {"setnulldevice", { 1, &PSActions::setnulldevice}}, {"setopacityalpha",{ 1, &PSActions::setopacityalpha}}, {"setshapealpha", { 1, &PSActions::setshapealpha}}, {"setpagedevice", { 0, &PSActions::setpagedevice}}, diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/PSInterpreter.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/PSInterpreter.hpp index 6a64351889b..8e75e3c5f1a 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/PSInterpreter.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/PSInterpreter.hpp @@ -32,7 +32,7 @@ struct PSException : public MessageException { - PSException (const std::string &msg) : MessageException(msg) {} + explicit PSException (const std::string &msg) : MessageException(msg) {} }; @@ -71,6 +71,7 @@ struct PSActions { virtual void setlinewidth (std::vector<double> &p) =0; virtual void setmatrix (std::vector<double> &p) =0; virtual void setmiterlimit (std::vector<double> &p) =0; + virtual void setnulldevice (std::vector<double> &p) =0; virtual void setopacityalpha (std::vector<double> &p) =0; virtual void setshapealpha (std::vector<double> &p) =0; virtual void setpagedevice (std::vector<double> &p) =0; @@ -90,7 +91,7 @@ class PSInterpreter { enum Mode {PS_NONE, PS_RUNNING, PS_QUIT}; public: - explicit PSInterpreter (PSActions *actions=0); + explicit PSInterpreter (PSActions *actions=nullptr); PSInterpreter (const PSInterpreter &psi) =delete; bool execute (const char *str, size_t len, bool flush=true); bool execute (const char *str, bool flush=true) {return execute(str, std::strlen(str), flush);} diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/PSPattern.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/PSPattern.cpp index 43b45c56596..90ff6a56852 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/PSPattern.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/PSPattern.cpp @@ -39,7 +39,7 @@ string PSPattern::svgID () const { /** Appends the definition of this pattern to the "def" section of the SVG tree. */ void PSPattern::apply (SpecialActions &actions) { if (auto pattern = createPatternNode()) - actions.appendToDefs(std::move(pattern)); + actions.svgTree().appendToDefs(std::move(pattern)); } @@ -54,18 +54,18 @@ PSTilingPattern::PSTilingPattern (int id, BoundingBox &bbox, Matrix &matrix, dou /** Assigns a new group element. */ -void PSTilingPattern::setGroupNode (unique_ptr<XMLElementNode> &&node) { +void PSTilingPattern::setGroupNode (unique_ptr<XMLElement> node) { _groupNode = std::move(node); _groupNodePtr = _groupNode.get(); } /** Creates a new pattern element representing the pattern defined in the PS code. */ -unique_ptr<XMLElementNode> PSTilingPattern::createPatternNode () const { +unique_ptr<XMLElement> PSTilingPattern::createPatternNode () const { if (!_groupNode) return nullptr; BoundingBox box(_bbox.minX(), _bbox.minY(), _bbox.minX()+_xstep, _bbox.minY()+_ystep); - auto pattern = util::make_unique<XMLElementNode>("pattern"); + auto pattern = util::make_unique<XMLElement>("pattern"); pattern->addAttribute("id", svgID()); pattern->addAttribute("x", box.minX()); pattern->addAttribute("y", box.minY()); @@ -74,7 +74,7 @@ unique_ptr<XMLElementNode> PSTilingPattern::createPatternNode () const { pattern->addAttribute("viewBox", box.toSVGViewBox()); pattern->addAttribute("patternUnits", "userSpaceOnUse"); if (!_matrix.isIdentity()) - pattern->addAttribute("patternTransform", _matrix.getSVG()); + pattern->addAttribute("patternTransform", _matrix.toSVG()); if (_xstep < _bbox.width() || _ystep < _bbox.height()) { // overlapping tiles? // disable clipping at the tile borders => tiles become "transparent" pattern->addAttribute("overflow", "visible"); @@ -89,10 +89,10 @@ unique_ptr<XMLElementNode> PSTilingPattern::createPatternNode () const { /** Creates a new clip element restricting the drawing area to the * dimensions given in the definition of the pattern. */ -unique_ptr<XMLElementNode> PSTilingPattern::createClipNode() const { - auto clip = util::make_unique<XMLElementNode>("clipPath"); +unique_ptr<XMLElement> PSTilingPattern::createClipNode() const { + auto clip = util::make_unique<XMLElement>("clipPath"); clip->addAttribute("id", "pc"+XMLString(psID())); - auto rect = util::make_unique<XMLElementNode>("rect"); + auto rect = util::make_unique<XMLElement>("rect"); rect->addAttribute("x", _bbox.minX()); rect->addAttribute("y", _bbox.minY()); rect->addAttribute("width", _bbox.width()); @@ -104,9 +104,9 @@ unique_ptr<XMLElementNode> PSTilingPattern::createClipNode() const { /** Creates a new group element that contains all "drawing" elements that * define the pattern graphic. */ -unique_ptr<XMLElementNode> PSTilingPattern::createGroupNode () const { +unique_ptr<XMLElement> PSTilingPattern::createGroupNode () const { // add all succeeding path elements to this group - auto group = util::make_unique<XMLElementNode>("g"); + auto group = util::make_unique<XMLElement>("g"); group->addAttribute("clip-path", XMLString("url(#pc")+XMLString(psID())+")"); return group; } @@ -145,16 +145,16 @@ string PSUncoloredTilingPattern::svgID () const { /** Appends the definition of this pattern with the current color applied * to the "def" section of the SVG tree. */ void PSUncoloredTilingPattern::apply (SpecialActions &actions) { - set<Color>::iterator it=_colors.find(_currentColor); + auto it=_colors.find(_currentColor); if (it == _colors.end()) { if (_applied) - setGroupNode(util::static_unique_ptr_cast<XMLElementNode>(getGroupNode()->clone())); + setGroupNode(util::static_unique_ptr_cast<XMLElement>(getGroupNode()->clone())); // assign current color to the pattern graphic - vector<XMLElementNode*> colored_elems; + vector<XMLElement*> colored_elems; const array<const char*, 2> attribs = {{"fill", "stroke"}}; for (const char *attrib : attribs) { getGroupNode()->getDescendants(nullptr, attrib, colored_elems); - for (XMLElementNode *elem : colored_elems) { + for (XMLElement *elem : colored_elems) { if (string(elem->getAttributeValue(attrib)) != "none") elem->addAttribute(attrib, _currentColor.svgColorString()); } @@ -167,7 +167,7 @@ void PSUncoloredTilingPattern::apply (SpecialActions &actions) { } -unique_ptr<XMLElementNode> PSUncoloredTilingPattern::createClipNode() const { +unique_ptr<XMLElement> PSUncoloredTilingPattern::createClipNode() const { // only the first instance of this patterns get a clip element if (_colors.empty()) return PSTilingPattern::createClipNode(); diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/PSPattern.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/PSPattern.hpp index 818e08fc87b..7dde27827d6 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/PSPattern.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/PSPattern.hpp @@ -32,7 +32,7 @@ class SpecialActions; class SVGTree; -class XMLElementNode; +class XMLElement; class PSPattern { public: @@ -42,8 +42,8 @@ class PSPattern { virtual void apply (SpecialActions &actions); protected: - PSPattern (int id) : _id(id) {} - virtual std::unique_ptr<XMLElementNode> createPatternNode () const =0; + explicit PSPattern (int id) : _id(id) {} + virtual std::unique_ptr<XMLElement> createPatternNode () const =0; private: int _id; ///< PostSCript ID of this pattern @@ -52,23 +52,23 @@ class PSPattern { class PSTilingPattern : public PSPattern { public: - virtual XMLElementNode* getContainerNode () {return _groupNode.get();} + virtual XMLElement* getContainerNode () {return _groupNode.get();} void apply (SpecialActions &actions) override; protected: PSTilingPattern (int id, BoundingBox &bbox, Matrix &matrix, double xstep, double ystep); - std::unique_ptr<XMLElementNode> createPatternNode () const override; - virtual std::unique_ptr<XMLElementNode> createClipNode () const; - virtual std::unique_ptr<XMLElementNode> createGroupNode () const; - virtual XMLElementNode* getGroupNode () const {return _groupNodePtr;} - virtual void setGroupNode (std::unique_ptr<XMLElementNode> &&node); + std::unique_ptr<XMLElement> createPatternNode () const override; + virtual std::unique_ptr<XMLElement> createClipNode () const; + virtual std::unique_ptr<XMLElement> createGroupNode () const; + virtual XMLElement* getGroupNode () const {return _groupNodePtr;} + virtual void setGroupNode (std::unique_ptr<XMLElement> node); private: BoundingBox _bbox; ///< bounding box of the tile graphics Matrix _matrix; ///< tile transformation double _xstep, _ystep; ///< horizontal and vertical distance between neighboured tiles - mutable std::unique_ptr<XMLElementNode> _groupNode; ///< group containing the drawing elements - XMLElementNode *_groupNodePtr; ///< keeps a pointer to the group node even after moving _groupNode to the SVGTree + mutable std::unique_ptr<XMLElement> _groupNode; ///< group containing the drawing elements + XMLElement *_groupNodePtr; ///< keeps a pointer to the group node even after moving _groupNode to the SVGTree }; @@ -86,7 +86,7 @@ class PSUncoloredTilingPattern final : public PSTilingPattern { void apply (SpecialActions &actions) override; protected: - std::unique_ptr<XMLElementNode> createClipNode () const override; + std::unique_ptr<XMLElement> createClipNode () const override; private: std::set<Color> _colors; ///< colors this pattern has already been drawn with diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/PSPreviewFilter.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/PSPreviewFilter.hpp index 5f58d931d56..7de5a2e2a8b 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/PSPreviewFilter.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/PSPreviewFilter.hpp @@ -30,7 +30,7 @@ class SpecialActions; class PSPreviewFilter : public PSFilter { public: - PSPreviewFilter (PSInterpreter &psi); + explicit PSPreviewFilter (PSInterpreter &psi); void activate (); void execute (const char *code, size_t len) override; bool active () const override {return _active;} diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/PageRanges.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/PageRanges.cpp index dc82151fff9..e6c1a8287bd 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/PageRanges.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/PageRanges.cpp @@ -78,7 +78,7 @@ bool PageRanges::parse (const string &str, int max_page) { /** Returns the number of pages. */ size_t PageRanges::numberOfPages () const { size_t sum=0; - for (NumericRanges<int>::ConstIterator it=begin(); it != end(); ++it) - sum += it->second - it->first + 1; + for (const auto &entry : *this) + sum += entry.second - entry.first + 1; return sum; } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/PageSize.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/PageSize.cpp index 3831f5d49bc..2f0a48aeb94 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/PageSize.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/PageSize.cpp @@ -96,7 +96,7 @@ void PageSize::resize (string name) { name = util::tolower(name); // extract optional suffix - size_t pos = name.rfind("-"); + size_t pos = name.rfind('-'); bool landscape = false; if (pos != string::npos) { string suffix = name.substr(pos); @@ -117,14 +117,14 @@ void PageSize::resize (string name) { } else if (name == "legal") { _width = 216_mm; - _height = 356_mm;; + _height = 356_mm; } else if (name == "letter") { _width = 216_mm; _height = 279_mm; } else if (name == "ledger") { - _width = 279_mm;; + _width = 279_mm; _height = 432_mm; } else if (isdigit(name[1]) && name.length() < 5) { // limit length of number to prevent arithmetic errors diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/PageSize.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/PageSize.hpp index b5a0836162d..c785a89564e 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/PageSize.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/PageSize.hpp @@ -25,14 +25,14 @@ #include "MessageException.hpp" struct PageSizeException : public MessageException { - PageSizeException (const std::string &msg) : MessageException(msg) {} + explicit PageSizeException (const std::string &msg) : MessageException(msg) {} }; class PageSize { public: PageSize () =default; PageSize (Length w, Length h) : _width(w), _height(h) {} - PageSize (const std::string &name); + explicit PageSize (const std::string &name); void resize (std:: string name); void resize (Length w, Length h); Length width () const {return _width;} diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/Pair.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/Pair.hpp index 2ca2a9466d7..5dd7c68a932 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/Pair.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/Pair.hpp @@ -26,17 +26,21 @@ #include "macros.hpp" template <typename T> -class Pair -{ +class Pair { public: - Pair (T x=0, T y=0) : _x(x), _y(y) {} + explicit Pair (T x=0, T y=0) : _x(x), _y(y) {} + template <typename U> Pair (const Pair<U> &p) : _x(U(p.x())), _y(U(p.y())) {} + Pair (const Pair &p) =default; + Pair (Pair &&p) =default; + Pair& operator = (const Pair &p) =default; + Pair& operator = (Pair &&p) =default; Pair operator += (const Pair &p) {_x += p._x; _y += p._y; return *this;} Pair operator -= (const Pair &p) {_x -= p._x; _y -= p._y; return *this;} Pair operator *= (T c) {_x *= c; _y *= c; return *this;} Pair operator /= (T c) {_x /= c; _y /= c; return *this;} Pair operator - () const {return Pair(-_x, -_y);} Pair ortho () const {return Pair(-_y, _x);} - double length () const {return std::sqrt(_x*_x + _y*_y);} + double length () const {return std::hypot(_x, _y);} bool operator == (const Pair &p) const {return _x == p._x && _y == p._y;} bool operator != (const Pair &p) const {return _x != p._x || _y != p._y;} T x () const {return _x;} @@ -54,15 +58,30 @@ inline Pair<T> abs (const Pair<T> &p) { return Pair<T>(std::abs(p.x()), std::abs(p.y())); } -struct Pair32 : public Pair<int32_t> -{ - Pair32 (int32_t x=0, int32_t y=0) : Pair<int32_t>(x, y) {} - explicit Pair32 (double x, double y) : Pair<int32_t>(int32_t(x+0.5), int32_t(y+0.5)) {} +/** Returns the dot product of two 2D vectors. */ +template <typename T> +inline T dot (const Pair<T> &p1, const Pair<T> &p2) { + return p1.x()*p1.y() + p1.y()*p2.y(); +} + +/** Returns the determinant of two 2D vectors. */ +template <typename T> +inline T det (const Pair<T> &p1, const Pair<T> &p2) { + return p1.x()*p2.y() - p1.y()*p2.x(); +} + +struct Pair32 : public Pair<int32_t> { + explicit Pair32 (int32_t x=0, int32_t y=0) : Pair<int32_t>(x, y) {} + explicit Pair32 (double x, double y) : Pair<int32_t>(lround(x), lround(y)) {} Pair32 (const Pair<int32_t> &p) : Pair<int32_t>(p) {} }; typedef Pair<double> DPair; +inline DPair round (const DPair &p) { + return DPair(std::lround(p.x()), std::lround(p.y())); +} + template <typename T> IMPLEMENT_ARITHMETIC_OPERATOR(Pair<T>, +) diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/PathClipper.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/PathClipper.cpp index a08b74a1aad..f646289d25e 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/PathClipper.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/PathClipper.cpp @@ -18,6 +18,7 @@ ** along with this program; if not, see <http://www.gnu.org/licenses/>. ** *************************************************************************/ +#include <cmath> #include "Bezier.hpp" #include "PathClipper.hpp" @@ -31,9 +32,7 @@ using CurvedPath = PathClipper::CurvedPath; const int SCALE_FACTOR = 1000; inline cInt to_cInt (double x) { - if (x < 0) - return static_cast<cInt>(x*SCALE_FACTOR - 0.5); - return static_cast<cInt>(x*SCALE_FACTOR + 0.5); + return static_cast<cInt>(lround(x*SCALE_FACTOR)); } @@ -50,7 +49,7 @@ inline DPair to_DPair (const IntPoint &p) { /** In order to flatten a curved path, all path segements are processed sequentially. * Depending on the type of the segment, one of the methods provided by this class * is called. */ -class FlattenActions : public CurvedPath::Actions { +class FlattenActions : public CurvedPath::IterationActions { public: FlattenActions (vector<Bezier> &curves, Polygons &polygons, int &numLines) : _polygons(polygons), _curves(curves), _numLines(numLines) {} @@ -74,7 +73,7 @@ class FlattenActions : public CurvedPath::Actions { _currentPoint = p; } - void conicto (const CurvedPath::Point &p1, const CurvedPath::Point &p2) override { + void quadto (const CurvedPath::Point &p1, const CurvedPath::Point &p2) override { Bezier bezier(_currentPoint, p1, p2); addCurvePoints(bezier); } @@ -130,9 +129,9 @@ class FlattenActions : public CurvedPath::Actions { /** Removes adjacent polygon vertices that equal their predecessor. */ static void remove_redundant_vertices (Polygon &polygon) { - Polygon::iterator it1=polygon.begin(); + auto it1=polygon.begin(); while (it1 != polygon.end()) { - Polygon::iterator it2 = it1+1; + auto it2 = it1+1; if (it2 == polygon.end()) it2 = polygon.begin(); if (it1 == it2) @@ -159,8 +158,8 @@ static void remove_redundant_vertices (Polygon &polygon) { void PathClipper::flatten (const CurvedPath &curvedPath, Polygons &polygons) { FlattenActions flattenActions(_curves, polygons, _numLines); curvedPath.iterate(flattenActions, false); - for (size_t i=0; i < polygons.size(); i++) - remove_redundant_vertices(polygons[i]); + for (Polygon &poly : polygons) + remove_redundant_vertices(poly); } @@ -207,7 +206,7 @@ static double division_ratio (const IntPoint &p1, const IntPoint &p2, const IntP /** Returns the label of point q that lies on the line between points p1 and p2. */ inline ZLabel division_label (const IntPoint &p1, const IntPoint &p2, const IntPoint &q) { - double t1, t2; + double t1=0, t2=0; double s=0; int32_t id = segment_id(p1, p2, t1, t2); if (id > 0) @@ -237,7 +236,7 @@ void PathClipper::callback (IntPoint &e1bot, IntPoint &e1top, IntPoint &e2bot, I * @param[out] label if not 0, retrieves the label of the endpoint * @param[in] startLabel if true, the found endpoint is treated as start point and * parameter 'label' gets the corresponding value */ -static size_t find_segment_endpoint (const Polygon &polygon, size_t start, ZLabel *label=0, bool startLabel=false) { +static size_t find_segment_endpoint (const Polygon &polygon, size_t start, ZLabel *label=nullptr, bool startLabel=false) { if (polygon.empty()) return 0; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/PdfSpecialHandler.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/PdfSpecialHandler.cpp index 43edd96569e..70174b0fe10 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/PdfSpecialHandler.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/PdfSpecialHandler.cpp @@ -95,7 +95,7 @@ static char prepare_mode (InputReader &ir) { void PdfSpecialHandler::preprocessPagesize (StreamInputReader &ir, SpecialActions &actions) { // add page sizes to collection of paper sizes in order to handle them equally SpecialHandler *handler = SpecialManager::instance().findHandlerByName("papersize"); - if (auto *papersizeHandler = dynamic_cast<PapersizeSpecialHandler*>(handler)) { + if (auto papersizeHandler = dynamic_cast<PapersizeSpecialHandler*>(handler)) { try { Length width, height; // parse parameter sequence of the form (name length)+ @@ -152,8 +152,8 @@ void PdfSpecialHandler::preprocessDest (StreamInputReader &ir, SpecialActions &a }); if (objects.size() < 2) return; - auto *name = objects[0].get<string>(); - auto *dest = objects[1].get<PDFArray>(); + auto name = objects[0].get<string>(); + auto dest = objects[1].get<PDFArray>(); // get target info from array [pageno /XYZ xpos ypos zpos] if (name && dest && dest->size() >= 4 && dest->at(0).get<int>()) { int pageno = *dest->at(0).get<int>(); @@ -210,7 +210,7 @@ static Color to_color (const PDFObject &obj) { Color color; if (obj.get<int>() || obj.get<double>()) color.setGray(double(obj)); - else if (auto *colorArray = obj.get<PDFArray>()) { + else if (auto colorArray = obj.get<PDFArray>()) { size_t size = min(size_t(4), colorArray->size()); valarray<double> colorComps(size); for (size_t i=0; i < size; i++) @@ -262,7 +262,7 @@ void PdfSpecialHandler::processDest (StreamInputReader &ir, SpecialActions &acti PDFParser parser; vector<PDFObject> objects = parser.parse(ir); if (!objects.empty()) { - if (auto *name = objects[0].get<string>()) + if (auto name = objects[0].get<string>()) HyperlinkManager::instance().setActiveNameAnchor(*name, actions); } } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/Process.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/Process.cpp index f8ede292a2a..ff73cb53366 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/Process.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/Process.cpp @@ -21,9 +21,9 @@ #ifdef _WIN32 #include "windows.hpp" #else + #include <csignal> #include <fcntl.h> #include <sys/wait.h> - #include <signal.h> #include <unistd.h> #endif @@ -61,8 +61,8 @@ class Subprocess { }; -Process::Process (const string &cmd, const string ¶mstr) - : _cmd(cmd), _paramstr(paramstr) +Process::Process (string cmd, string paramstr) + : _cmd(std::move(cmd)), _paramstr(std::move(paramstr)) { } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/Process.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/Process.hpp index 3333e24df1d..70eeafb9d8b 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/Process.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/Process.hpp @@ -25,11 +25,11 @@ class Process { public: - Process (const std::string &cmd, const std::string ¶mstr); + Process (std::string cmd, std::string paramstr); Process (const Process &orig) =delete; Process (Process &&orig) =delete; - bool run (std::string *out=0); - bool run (const std::string &dir, std::string *out=0); + bool run (std::string *out=nullptr); + bool run (const std::string &dir, std::string *out=nullptr); private: std::string _cmd; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/PsSpecialHandler.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/PsSpecialHandler.cpp index 4b503d34bee..405da48434b 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/PsSpecialHandler.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/PsSpecialHandler.cpp @@ -25,6 +25,7 @@ #include <sstream> #include "EPSFile.hpp" #include "FileFinder.hpp" +#include "FilePath.hpp" #include "FileSystem.hpp" #include "Message.hpp" #include "PathClipper.hpp" @@ -183,6 +184,15 @@ void PsSpecialHandler::preprocess (const string &prefix, istream &is, SpecialAct } +static string filename_suffix (const string &fname) { + string ret; + size_t pos = fname.rfind('.'); + if (pos != string::npos) + ret = util::tolower(fname.substr(pos+1)); + return ret; +} + + bool PsSpecialHandler::process (const string &prefix, istream &is, SpecialActions &actions) { // process PS headers only once (in prescan) if (prefix == "!" || prefix == "header=") @@ -203,10 +213,24 @@ bool PsSpecialHandler::process (const string &prefix, istream &is, SpecialAction else if (prefix == "psfile=" || prefix == "PSfile=" || prefix == "pdffile=") { if (_actions) { StreamInputReader in(is); - const string fname = in.getQuotedString(in.peek() == '"' ? "\"" : nullptr); + string fname = in.getQuotedString(in.peek() == '"' ? "\"" : nullptr); + fname = FileSystem::adaptPathSeperators(fname); + FileType fileType = FileType::EPS; + if (prefix == "pdffile") + fileType = FileType::PDF; + else { + // accept selected non-PS files in psfile special + string ext = filename_suffix(fname); + if (ext == "pdf") + fileType = FileType::PDF; + else if (ext == "svg") + fileType = FileType::SVG; + else if (ext == "jpg" || ext == "jpeg" || ext == "png") + fileType = FileType::BITMAP; + } map<string,string> attr; - in.parseAttributes(attr); - imgfile(prefix == "pdffile=" ? FileType::PDF : FileType::EPS, fname, attr); + in.parseAttributes(attr, false); + imgfile(fileType, fname, attr); } } else if (prefix == "ps::") { @@ -216,9 +240,9 @@ bool PsSpecialHandler::process (const string &prefix, istream &is, SpecialAction // collect characters inside the brackets string code; for (int i=0; i < 9 && is.peek() != ']' && !is.eof(); ++i) - code += is.get(); + code += char(is.get()); if (is.peek() == ']') - code += is.get(); + code += char(is.get()); if (code == "[begin]" || code == "[nobreak]") { moveToDVIPos(); @@ -272,15 +296,6 @@ void PsSpecialHandler::imgfile (FileType filetype, const string &fname, const ma if (fname == "/dev/null") return; - string filepath; - if (const char *path = FileFinder::instance().lookup(fname, false)) - filepath = FileSystem::adaptPathSeperators(path); - if ((filepath.empty() || !FileSystem::exists(filepath)) && FileSystem::exists(fname)) - filepath = fname; - if (filepath.empty()) { - Message::wstream(true) << "file '" << fname << "' not found\n"; - return; - } map<string,string>::const_iterator it; // bounding box of EPS figure in PS point units (lower left and upper right corner) @@ -290,7 +305,9 @@ void PsSpecialHandler::imgfile (FileType filetype, const string &fname, const ma double ury = (it = attr.find("ury")) != attr.end() ? stod(it->second) : 0; int pageno = (it = attr.find("page")) != attr.end() ? stoi(it->second, nullptr, 10) : 1; - if (filetype == FileType::PDF && llx == 0 && lly == 0 && urx == 0 && ury == 0) { + if (filetype == FileType::BITMAP || filetype == FileType::SVG) + swap(lly, ury); + else if (filetype == FileType::PDF && llx == 0 && lly == 0 && urx == 0 && ury == 0) { BoundingBox pagebox = _psi.pdfPageBox(fname, pageno); if (pagebox.valid()) { llx = pagebox.minX(); @@ -316,6 +333,8 @@ void PsSpecialHandler::imgfile (FileType filetype, const string &fname, const ma double vscale = (it = attr.find("vscale")) != attr.end() ? stod(it->second) : 100; double angle = (it = attr.find("angle")) != attr.end() ? stod(it->second) : 0; + bool clipToBbox = (attr.find("clip") != attr.end()); + // compute factors to scale the bounding box to width rwi and height rhi double sx = rwi/abs(llx-urx); double sy = rhi/abs(lly-ury); @@ -335,36 +354,26 @@ void PsSpecialHandler::imgfile (FileType filetype, const string &fname, const ma _actions->setY(0); moveToDVIPos(); - auto groupNode = util::make_unique<XMLElementNode>("g"); // put SVG nodes created from the EPS/PDF file in this group - _xmlnode = groupNode.get(); - _psi.execute( - "\n@beginspecial @setspecial" // enter special environment - "/setpagedevice{@setpagedevice}def " // activate processing of operator "setpagedevice" - "matrix setmatrix" // don't apply outer PS transformations - "/FirstPage "+to_string(pageno)+" def" // set number of fisrt page to convert (PDF only) - "/LastPage "+to_string(pageno)+" def" // set number of last page to convert (PDF only) - "("+ filepath + ")run " // execute file content - "@endspecial " // leave special environment - ); - if (!groupNode->empty()) { // has anything been drawn? + auto imgNode = createImageNode(filetype, fname, pageno, BoundingBox(llx, lly, urx, ury), clipToBbox); + if (imgNode) { // has anything been drawn? Matrix matrix(1); - matrix.scale(sx, -sy).rotate(-angle).scale(hscale/100, vscale/100); // apply transformation attributes + if (filetype == FileType::EPS || filetype == FileType::PDF) + sy = -sy; // adapt orientation of y-coordinates + matrix.scale(sx, sy).rotate(-angle).scale(hscale/100, vscale/100); // apply transformation attributes matrix.translate(x+hoffset, y-voffset); // move image to current DVI position - matrix.rmultiply(_actions->getMatrix()); + matrix.lmultiply(_actions->getMatrix()); // update bounding box BoundingBox bbox(0, 0, urx-llx, ury-lly); bbox.transform(matrix); _actions->embed(bbox); - // insert group containing SVG nodes created from image - matrix.lmultiply(TranslationMatrix(-llx, -lly)); // move lower left corner of image to origin + // insert element containing the image data + matrix.rmultiply(TranslationMatrix(-llx, -lly)); // move lower left corner of image to origin if (!matrix.isIdentity()) - groupNode->addAttribute("transform", matrix.getSVG()); - _actions->appendToPage(std::move(groupNode)); + imgNode->addAttribute("transform", matrix.toSVG()); + _actions->svgTree().appendToPage(std::move(imgNode)); } - _xmlnode = nullptr; // append following elements to page group again - // restore DVI position _actions->setX(x); _actions->setY(y); @@ -372,6 +381,63 @@ void PsSpecialHandler::imgfile (FileType filetype, const string &fname, const ma } +/** Creates an XML element containing the image data depending on the file type. + * @param[in] type file type of the image + * @param[in] fname file name/path of image file + * @param[in] pageno number of page to process (PDF only) + * @param[in] bbox bounding box of the image + * @param[in] clip if true, the image is clipped to its bounding box + * @return pointer to the element or nullptr if there's no image data */ +unique_ptr<XMLElement> PsSpecialHandler::createImageNode (FileType type, const string &fname, int pageno, BoundingBox bbox, bool clip) { + unique_ptr<XMLElement> node; + string pathstr; + if (const char *path = FileFinder::instance().lookup(fname, false)) + pathstr = FileSystem::adaptPathSeperators(path); + if ((pathstr.empty() || !FileSystem::exists(pathstr)) && FileSystem::exists(fname)) + pathstr = fname; + if (pathstr.empty()) + Message::wstream(true) << "file '" << fname << "' not found\n"; + else if (type == FileType::BITMAP || type == FileType::SVG) { + node = util::make_unique<XMLElement>("image"); + node->addAttribute("x", 0); + node->addAttribute("y", 0); + node->addAttribute("width", bbox.width()); + node->addAttribute("height", bbox.height()); + + // Only reference the image with an absolute path if either an absolute path was given by the user + // or a given plain filename is not present in the current working directory but was found through + // the FileFinder, i.e. it's usually located somewhere in the texmf tree. + string href = pathstr; + if (!FilePath::isAbsolute(fname) && (fname.find('/') != string::npos || FilePath(fname).exists())) + href = FilePath(pathstr).relative(FilePath(_actions->getSVGFilePath(pageno))); + node->addAttribute("xlink:href", href); + } + else { // PostScript or PDF + // clip image to its bounding box if flag 'clip' is given + string rectclip; + if (clip) + rectclip = to_string(bbox.minX())+" "+to_string(bbox.minY())+" "+to_string(bbox.width())+" "+to_string(bbox.height())+" rectclip"; + + node = util::make_unique<XMLElement>("g"); // put SVG nodes created from the EPS/PDF file in this group + _xmlnode = node.get(); + _psi.execute( + "\n@beginspecial @setspecial" // enter special environment + "/setpagedevice{@setpagedevice}def " // activate processing of operator "setpagedevice" + "matrix setmatrix" // don't apply outer PS transformations + "/FirstPage "+to_string(pageno)+" def" // set number of first page to convert (PDF only) + "/LastPage "+to_string(pageno)+" def " // set number of last page to convert (PDF only) + +rectclip+ // clip to bounding box (if requexted by attribute 'clip') + "(" + pathstr + ")run " // execute file content + "@endspecial " // leave special environment + ); + if (node->empty()) + node.reset(nullptr); + _xmlnode = nullptr; // append following elements to page group again + } + return node; +} + + /** Apply transformation to width, height, and depth set by preview package. * @param[in] matrix transformation matrix to apply * @param[out] w width @@ -386,15 +452,17 @@ static bool transform_box_extents (const Matrix &matrix, double &w, double &h, d return false; // => non-horizontal baseline, can't compute meaningful extents if (ex.y() == 0) // horizontal scaling or skewing? - w *= fabs(ex.x()); + w *= abs(ex.x()); if (ey.x()==0 || ex.y()==0) { // vertical scaling? - if (ey.y() < 0) swap(h, d); - if (double sy = fabs(ey.y())/ey.length()) { - h *= fabs(ey.y()/sy); - d *= fabs(ey.y()/sy); - } - else + if (ey.y() < 0) + swap(h, d); + double sy = abs(ey.y())/ey.length(); + if (sy < 1e-8) h = d = 0; + else { + h *= abs(ey.y()/sy); + d *= abs(ey.y()/sy); + } } return true; } @@ -435,7 +503,7 @@ void PsSpecialHandler::dviEndPage (unsigned, SpecialActions &actions) { "depth=" << XMLString(d*bp2pt) << "pt\n"; } #if 0 - auto rect = util::make_unique<XMLElementNode>("rect"); + auto rect = util::make_unique<XMLElement>("rect"); rect->addAttribute("x", actions.bbox().minX()); rect->addAttribute("y", actions.bbox().minY()); rect->addAttribute("width", w); @@ -445,7 +513,7 @@ void PsSpecialHandler::dviEndPage (unsigned, SpecialActions &actions) { rect->addAttribute("stroke-width", "0.1"); actions.appendToPage(std::move(rect)); if (d > 0) { - auto line = util::make_unique<XMLElementNode>("line"); + auto line = util::make_unique<XMLElement>("line"); line->addAttribute("x1", actions.bbox().minX()); line->addAttribute("y1", actions.bbox().minY()+h); line->addAttribute("x2", actions.bbox().maxX()); @@ -553,14 +621,14 @@ void PsSpecialHandler::stroke (vector<double> &p) { } if (_clipStack.prependedPath()) _path.prepend(*_clipStack.prependedPath()); - unique_ptr<XMLElementNode> path; + unique_ptr<XMLElement> path; Pair<double> point; if (_path.isDot(point)) { // zero-length path? if (_linecap == 1) { // round line ends? => draw dot double x = point.x(); double y = point.y(); double r = _linewidth/2.0; - path = util::make_unique<XMLElementNode>("circle"); + path = util::make_unique<XMLElement>("circle"); path->addAttribute("cx", x); path->addAttribute("cy", y); path->addAttribute("r", r); @@ -575,7 +643,7 @@ void PsSpecialHandler::stroke (vector<double> &p) { ostringstream oss; _path.writeSVG(oss, SVGTree::RELATIVE_PATH_CMDS); - path = util::make_unique<XMLElementNode>("path"); + path = util::make_unique<XMLElement>("path"); path->addAttribute("d", oss.str()); path->addAttribute("stroke", _actions->getColor().svgColorString()); path->addAttribute("fill", "none"); @@ -592,13 +660,11 @@ void PsSpecialHandler::stroke (vector<double> &p) { if (_blendmode > 0 && _blendmode < 16) path->addAttribute("style", "mix-blend-mode:"+css_blendmode_name(_blendmode)); if (!_dashpattern.empty()) { - ostringstream oss; - for (size_t i=0; i < _dashpattern.size(); i++) { - if (i > 0) - oss << ','; - oss << XMLString(_dashpattern[i]); - } - path->addAttribute("stroke-dasharray", oss.str()); + string patternStr; + for (double dashValue : _dashpattern) + patternStr += XMLString(dashValue)+","; + patternStr.pop_back(); + path->addAttribute("stroke-dasharray", patternStr); if (_dashoffset != 0) path->addAttribute("stroke-dashoffset", _dashoffset); } @@ -614,7 +680,7 @@ void PsSpecialHandler::stroke (vector<double> &p) { if (_xmlnode) _xmlnode->append(std::move(path)); else { - _actions->appendToPage(std::move(path)); + _actions->svgTree().appendToPage(std::move(path)); _actions->embed(bbox); } _path.clear(); @@ -642,7 +708,7 @@ void PsSpecialHandler::fill (vector<double> &p, bool evenodd) { ostringstream oss; _path.writeSVG(oss, SVGTree::RELATIVE_PATH_CMDS); - unique_ptr<XMLElementNode> path = util::make_unique<XMLElementNode>("path"); + unique_ptr<XMLElement> path = util::make_unique<XMLElement>("path"); path->addAttribute("d", oss.str()); if (_pattern) path->addAttribute("fill", XMLString("url(#")+_pattern->svgID()+")"); @@ -665,7 +731,7 @@ void PsSpecialHandler::fill (vector<double> &p, bool evenodd) { if (_xmlnode) _xmlnode->append(std::move(path)); else { - _actions->appendToPage(std::move(path)); + _actions->svgTree().appendToPage(std::move(path)); _actions->embed(bbox); } _path.clear(); @@ -682,7 +748,7 @@ static void create_matrix (vector<double> &v, int startindex, Matrix &matrix) { // using corresponding values of the identity matrix. if (v.size()-startindex < 6) { v.resize(6+startindex); - for (int i=v.size()-startindex; i < 6; ++i) + for (size_t i=v.size()-startindex; i < 6; ++i) v[i+startindex] = (i%3 ? 0 : 1); } // PS matrix [a b c d e f] equals ((a,b,0),(c,d,0),(e,f,1)). @@ -724,7 +790,7 @@ void PsSpecialHandler::makepattern (vector<double> &p) { Matrix matrix; // transformation matrix given together with pattern definition create_matrix(p, 9, matrix); - matrix.rmultiply(_actions->getMatrix()); + matrix.lmultiply(_actions->getMatrix()); unique_ptr<PSTilingPattern> pattern; if (paint_type == 1) @@ -756,10 +822,10 @@ void PsSpecialHandler::setpattern (vector<double> &p) { if (it == _patterns.end()) _pattern = nullptr; else { - if (auto *pattern = dynamic_cast<PSUncoloredTilingPattern*>(it->second.get())) + if (auto pattern = dynamic_cast<PSUncoloredTilingPattern*>(it->second.get())) pattern->setColor(color); it->second->apply(*_actions); - if (auto *pattern = dynamic_cast<PSTilingPattern*>(it->second.get())) + if (auto pattern = dynamic_cast<PSTilingPattern*>(it->second.get())) _pattern = pattern; else _pattern = nullptr; @@ -828,19 +894,19 @@ void PsSpecialHandler::clip (Path path, bool evenodd) { intersectedPath.writeSVG(oss, SVGTree::RELATIVE_PATH_CMDS); } if (pathReplaced) { - auto pathElem = util::make_unique<XMLElementNode>("path"); + auto pathElem = util::make_unique<XMLElement>("path"); pathElem->addAttribute("d", oss.str()); if (evenodd) pathElem->addAttribute("clip-rule", "evenodd"); int newID = _clipStack.topID(); - auto clipElem = util::make_unique<XMLElementNode>("clipPath"); + auto clipElem = util::make_unique<XMLElement>("clipPath"); clipElem->addAttribute("id", XMLString("clip")+XMLString(newID)); if (!COMPUTE_CLIPPATHS_INTERSECTIONS && oldID) clipElem->addAttribute("clip-path", XMLString("url(#clip")+XMLString(oldID)+")"); clipElem->append(std::move(pathElem)); - _actions->appendToDefs(std::move(clipElem)); + _actions->svgTree().appendToDefs(std::move(clipElem)); } } @@ -864,7 +930,7 @@ void PsSpecialHandler::shfill (vector<double> ¶ms) { case 3: colorSpace = Color::ColorSpace::RGB; break; case 4: colorSpace = Color::ColorSpace::CMYK; break; } - VectorIterator<double> it = params; + VectorIterator<double> it(params); it += 2; // skip shading type and color space // Get color to fill the whole mesh area before drawing the gradient colors on top of that background. // This is an optional parameter to shfill. @@ -951,15 +1017,15 @@ static void read_patch_data (ShadingPatch &patch, int edgeflag, class ShadingCallback : public ShadingPatch::Callback { public: - ShadingCallback (SpecialActions &actions, XMLElementNode *parent, int clippathID) + ShadingCallback (SpecialActions &actions, XMLElement *parent, int clippathID) : _actions(actions) { - auto group = util::make_unique<XMLElementNode>("g"); + auto group = util::make_unique<XMLElement>("g"); _group = group.get(); if (parent) parent->append(std::move(group)); else - actions.appendToPage(std::move(group)); + actions.svgTree().appendToPage(std::move(group)); if (clippathID > 0) _group->addAttribute("clip-path", XMLString("url(#clip")+XMLString(clippathID)+")"); } @@ -971,7 +1037,7 @@ class ShadingCallback : public ShadingPatch::Callback { // draw a single patch segment ostringstream oss; path.writeSVG(oss, SVGTree::RELATIVE_PATH_CMDS); - auto pathElem = util::make_unique<XMLElementNode>("path"); + auto pathElem = util::make_unique<XMLElement>("path"); pathElem->addAttribute("d", oss.str()); pathElem->addAttribute("fill", color.svgColorString()); _group->append(std::move(pathElem)); @@ -979,7 +1045,7 @@ class ShadingCallback : public ShadingPatch::Callback { private: SpecialActions &_actions; - XMLElementNode *_group; + XMLElement *_group; }; @@ -999,16 +1065,14 @@ void PsSpecialHandler::processSequentialPatchMesh (int shadingTypeID, ColorSpace #if 0 if (bgcolorGiven) { // fill whole patch area with given background color - GraphicsPath<double> outline; - patch->getBoundaryPath(outline); + GraphicsPath<double> outline = patch->getBoundaryPath(); callback.patchSegment(outline, bgcolor); } #endif patch->approximate(SHADING_SEGMENT_SIZE, SHADING_SEGMENT_OVERLAP, SHADING_SIMPLIFY_DELTA, callback); if (!_xmlnode) { // update bounding box - BoundingBox bbox; - patch->getBBox(bbox); + BoundingBox bbox = patch->getBBox(); bbox.transform(_actions->getMatrix()); _actions->embed(bbox); } @@ -1093,7 +1157,7 @@ void PsSpecialHandler::scale (vector<double> &p) { if (_actions) { Matrix m = _actions->getMatrix(); ScalingMatrix s(p[0], p[1]); - m.lmultiply(s); + m.rmultiply(s); _actions->setMatrix(m); } } @@ -1103,7 +1167,7 @@ void PsSpecialHandler::translate (vector<double> &p) { if (_actions) { Matrix m = _actions->getMatrix(); TranslationMatrix t(p[0], p[1]); - m.lmultiply(t); + m.rmultiply(t); _actions->setMatrix(m); } } @@ -1113,7 +1177,7 @@ void PsSpecialHandler::rotate (vector<double> &p) { if (_actions) { Matrix m = _actions->getMatrix(); RotationMatrix r(p[0]); - m.lmultiply(r); + m.rmultiply(r); _actions->setMatrix(m); } } @@ -1167,6 +1231,18 @@ void PsSpecialHandler::executed () { _actions->progress("ps"); } + +/** This method is called by PSInterpreter if the status of the output devices has changed. + * @param[in] p 1 if output device is the nulldevice, 1 otherwise */ +void PsSpecialHandler::setnulldevice (vector<double> &p) { + if (_actions) { + if (p[0] != 0) + _actions->lockOutput(); // prevent further SVG output + else + _actions->unlockOutput(); // enable SVG output again + } +} + //////////////////////////////////////////// void PsSpecialHandler::ClippingStack::pushEmptyPath () { diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/PsSpecialHandler.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/PsSpecialHandler.hpp index 188c4527189..c7a8a978150 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/PsSpecialHandler.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/PsSpecialHandler.hpp @@ -34,7 +34,7 @@ class PSPattern; -class XMLElementNode; +class XMLElement; class PsSpecialHandler : public SpecialHandler, protected PSActions { using Path = GraphicsPath<double>; @@ -68,7 +68,7 @@ class PsSpecialHandler : public SpecialHandler, protected PSActions { int saveID; ///< if >=0, path was pushed by 'save', and saveID holds the ID of the PS memory object Entry () : Entry(-1) {} Entry (const Path &p, int pid, int sid) : path(std::make_shared<Path>(p)), pathID(pid), saveID(sid) {} - Entry (int sid) : path(nullptr), pathID(0), saveID(sid) {} + explicit Entry (int sid) : path(nullptr), pathID(0), saveID(sid) {} Entry (const Entry &entry) =default; Entry (Entry &&entry) =default; }; @@ -77,11 +77,11 @@ class PsSpecialHandler : public SpecialHandler, protected PSActions { }; enum PsSection {PS_NONE, PS_HEADERS, PS_BODY}; - enum class FileType {EPS, PDF}; + enum class FileType {EPS, PDF, SVG, BITMAP}; public: PsSpecialHandler (); - ~PsSpecialHandler (); + ~PsSpecialHandler () override; const char* name () const override {return "ps";} const char* info () const override {return "dvips PostScript specials";} std::vector<const char*> prefixes() const override; @@ -104,6 +104,7 @@ class PsSpecialHandler : public SpecialHandler, protected PSActions { void executeAndSync (std::istream &is, bool updatePos); void processHeaderFile (const char *fname); void imgfile (FileType type, const std::string &fname, const std::map<std::string,std::string> &attr); + std::unique_ptr<XMLElement> createImageNode (FileType type, const std::string &fname, int pageno, BoundingBox bbox, bool clip); void dviEndPage (unsigned pageno, SpecialActions &actions) override; void clip (Path path, bool evenodd); void processSequentialPatchMesh (int shadingTypeID, ColorSpace cspace, VectorIterator<double> &it); @@ -145,6 +146,7 @@ class PsSpecialHandler : public SpecialHandler, protected PSActions { void setlinewidth (std::vector<double> &p) override {_linewidth = scale(p[0] ? p[0] : 0.5);} void setmatrix (std::vector<double> &p) override; void setmiterlimit (std::vector<double> &p) override {_miterlimit = p[0];} + void setnulldevice (std::vector<double> &p) override; void setopacityalpha (std::vector<double> &p) override {_opacityalpha = p[0];} void setshapealpha (std::vector<double> &p) override {_shapealpha = p[0];} void setpagedevice (std::vector<double> &p) override; @@ -160,8 +162,8 @@ class PsSpecialHandler : public SpecialHandler, protected PSActions { SpecialActions *_actions; PSPreviewFilter _previewFilter; ///< filter to extract information generated by the preview package PsSection _psSection=PS_NONE; ///< current section processed (nothing yet, headers, or body specials) - XMLElementNode *_xmlnode; ///< if != 0, created SVG elements are appended to this node - XMLElementNode *_savenode; ///< pointer to temporaryly store _xmlnode + XMLElement *_xmlnode; ///< if != 0, created SVG elements are appended to this node + XMLElement *_savenode; ///< pointer to temporaryly store _xmlnode std::string _headerCode; ///< collected literal PS header code Path _path; DPair _currentpoint; ///< current PS position in bp units diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/RangeMap.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/RangeMap.cpp index dd9eb88462c..5fa2bb10ab1 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/RangeMap.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/RangeMap.cpp @@ -18,6 +18,7 @@ ** along with this program; if not, see <http://www.gnu.org/licenses/>. ** *************************************************************************/ +#include <numeric> #include "RangeMap.hpp" using namespace std; @@ -96,7 +97,7 @@ void RangeMap::addRange (uint32_t cmin, uint32_t cmax, uint32_t vmin) { } else { // ranges overlap and/or must be inserted somewhere inside the vector - Ranges::iterator it = lower_bound(_ranges.begin(), _ranges.end(), range); + auto it = lower_bound(_ranges.begin(), _ranges.end(), range); const bool at_end = (it == _ranges.end()); if (at_end) --it; @@ -125,16 +126,16 @@ void RangeMap::addRange (uint32_t cmin, uint32_t cmax, uint32_t vmin) { void RangeMap::adaptNeighbors (Ranges::iterator it) { if (it != _ranges.end()) { // adapt left neighbor - Ranges::iterator lit = it-1; // points to left neighbor - if (it != _ranges.begin() && it->min() <= lit->max()) { + if (it != _ranges.begin() && it->min() <= (it-1)->max()) { + auto lit = it-1; // points to left neighbor bool left_neighbor_valid = (it->min() > 0 && it->min()-1 >= lit->min()); - if (left_neighbor_valid) // is adapted left neighbor valid? - lit->max(it->min()-1); // => assign new max value + if (left_neighbor_valid) // is adapted left neighbor valid? + lit->max(it->min()-1); // => assign new max value if (!left_neighbor_valid || it->join(*lit)) it = _ranges.erase(lit); } // remove right neighbors completely overlapped by *it - Ranges::iterator rit = it+1; // points to right neighbor + auto rit = it+1; // points to right neighbor while (rit != _ranges.end() && it->max() >= rit->max()) { // complete overlap? _ranges.erase(rit); rit = it+1; @@ -178,10 +179,9 @@ uint32_t RangeMap::valueAt (uint32_t c) const { /** Returns the number of values mapped. */ size_t RangeMap::numValues () const { - size_t count=0; - for (const Range &range : _ranges) - count += range.max()-range.min()+1; - return count; + return std::accumulate(_ranges.begin(), _ranges.end(), 0, [](size_t sum, const Range &range) { + return sum+range.max()-range.min()+1; + }); } @@ -191,7 +191,7 @@ ostream& RangeMap::Range::write (ostream& os) const { ostream& RangeMap::write (ostream& os) const { - for (size_t i=0; i < _ranges.size(); i++) - _ranges[i].write(os) << '\n'; + for (const Range &range : _ranges) + range.write(os) << '\n'; return os; } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharHandler.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharHandler.cpp index 70fc6836e9c..3733053e4d0 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharHandler.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharHandler.cpp @@ -25,7 +25,7 @@ using namespace std; -void SVGCharHandler::setInitialContextNode (XMLElementNode *node) { +void SVGCharHandler::setInitialContextNode (XMLElement *node) { resetContextNode(); _initialContextNode = node; } @@ -34,9 +34,9 @@ void SVGCharHandler::setInitialContextNode (XMLElementNode *node) { /** Changes the context element. All following nodes will be appended to this node. * @param[in] node the new context node * @return bare pointer to the new context node or 0 if context hasn't changed */ -XMLElementNode* SVGCharHandler::pushContextNode (unique_ptr<XMLElementNode> &&node) { +XMLElement* SVGCharHandler::pushContextNode (unique_ptr<XMLElement> node) { if (node && (_contextNodeStack.empty() || node.get() != _contextNodeStack.top())) { - XMLElementNode *nodeptr = node.get(); + XMLElement *nodeptr = node.get(); contextNode()->append(std::move(node)); _contextNodeStack.push(nodeptr); return nodeptr; @@ -61,11 +61,11 @@ void SVGCharHandler::resetContextNode () { /** Creates and returns a new SVG text element. * @param[in] x current x coordinate * @param[in] y current y coordinate */ -unique_ptr<XMLElementNode> SVGCharTextHandler::createTextNode (double x, double y) const { +unique_ptr<XMLElement> SVGCharTextHandler::createTextNode (double x, double y) const { const Font *font = _font.get(); if (!font) return nullptr; - auto textNode = util::make_unique<XMLElementNode>("text"); + auto textNode = util::make_unique<XMLElement>("text"); if (_selectFontByClass) textNode->addAttribute("class", string("f")+XMLString(_fontnum)); else { @@ -77,7 +77,7 @@ unique_ptr<XMLElementNode> SVGCharTextHandler::createTextNode (double x, double if (_vertical) { textNode->addAttribute("writing-mode", "tb"); // align glyphs designed for horizontal layout properly - if (const PhysicalFont *pf = dynamic_cast<const PhysicalFont*>(font)) { + if (auto pf = dynamic_cast<const PhysicalFont*>(font)) { if (!pf->getMetrics()->verticalLayout()) { // alphabetic text designed for horizontal layout? x += pf->scaledAscent()/2.5; // move vertical baseline to the right by strikethrough offset textNode->addAttribute("glyph-orientation-vertical", 90); // ensure rotation @@ -87,6 +87,6 @@ unique_ptr<XMLElementNode> SVGCharTextHandler::createTextNode (double x, double textNode->addAttribute("x", x); textNode->addAttribute("y", y); if (!_matrix.get().isIdentity()) - textNode->addAttribute("transform", _matrix.get().getSVG()); + textNode->addAttribute("transform", _matrix.get().toSVG()); return textNode; } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharHandler.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharHandler.hpp index c527ee26655..48d24496fab 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharHandler.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharHandler.hpp @@ -31,7 +31,7 @@ template <typename T> class CharProperty { public: - CharProperty (const T &v) : _value(v), _changed(false) {} + CharProperty (const T &v) : _value(v) {} void set (const T &v) { if (v != _value) { @@ -47,20 +47,20 @@ class CharProperty { private: T _value; - bool _changed; + bool _changed=false; }; -class XMLElementNode; +class XMLElement; /** Base class for all character handlers. These handlers create SVG representations * for the added characters and append them to the SVG tree. */ class SVGCharHandler { public: - SVGCharHandler () : _color(Color::BLACK), _font(0), _fontnum(0), _matrix(1), _vertical(false), _initialContextNode(0) {} + SVGCharHandler () : _matrix(1) {} virtual ~SVGCharHandler() =default; - virtual void setInitialContextNode (XMLElementNode *node); + virtual void setInitialContextNode (XMLElement *node); virtual void appendChar (uint32_t c, double x, double y) =0; virtual void notifyXAdjusted () {} virtual void notifyYAdjusted () {} @@ -74,32 +74,32 @@ class SVGCharHandler { protected: virtual void resetContextNode (); - XMLElementNode* pushContextNode (std::unique_ptr<XMLElementNode> &&node); + XMLElement* pushContextNode (std::unique_ptr<XMLElement> node); void popContextNode (); - XMLElementNode* contextNode () const { + XMLElement* contextNode () const { return _contextNodeStack.empty() ? _initialContextNode : _contextNodeStack.top(); } - CharProperty<Color> _color; ///< current color - CharProperty<const Font*> _font; ///< current font - int _fontnum; ///< current font ID - CharProperty<Matrix> _matrix; ///< current transformation - CharProperty<bool> _vertical; ///< current writing mode + CharProperty<Color> _color=Color::BLACK; ///< current color + CharProperty<const Font*> _font=0; ///< current font + int _fontnum=0; ///< current font ID + CharProperty<Matrix> _matrix; ///< current transformation + CharProperty<bool> _vertical=false; ///< current writing mode private: - XMLElementNode *_initialContextNode; ///< SVG element the generated character nodes are attached to - std::stack<XMLElementNode*> _contextNodeStack; + XMLElement *_initialContextNode= nullptr; ///< SVG element the generated character nodes are attached to + std::stack<XMLElement*> _contextNodeStack; }; /** Base class for all character handlers that create SVG <text> elements. */ class SVGCharTextHandler : public SVGCharHandler { public: - SVGCharTextHandler (bool selectFontByClass) : _selectFontByClass(selectFontByClass) {} + explicit SVGCharTextHandler (bool selectFontByClass) : _selectFontByClass(selectFontByClass) {} protected: - std::unique_ptr<XMLElementNode> createTextNode (double x, double y) const; + std::unique_ptr<XMLElement> createTextNode (double x, double y) const; private: bool _selectFontByClass; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharPathHandler.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharPathHandler.cpp index 1b2316926d0..3962168ae2f 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharPathHandler.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharPathHandler.cpp @@ -31,7 +31,7 @@ using namespace std; * @param[in] createUseElements determines whether to create "use" elements to reference previous paths or not * @param[in] relativePathCommands determines whether to create relative or absolute SVG path commands */ SVGCharPathHandler::SVGCharPathHandler (bool createUseElements, bool relativePathCommands) - : _relativePathCommands(relativePathCommands), _groupNode(0), _fontColor(Color::BLACK) + : _relativePathCommands(relativePathCommands) { if (createUseElements) _appendChar = &SVGCharPathHandler::appendUseElement; @@ -42,7 +42,7 @@ SVGCharPathHandler::SVGCharPathHandler (bool createUseElements, bool relativePat void SVGCharPathHandler::resetContextNode () { SVGCharHandler::resetContextNode(); - _groupNode = 0; + _groupNode = nullptr; } @@ -69,11 +69,11 @@ void SVGCharPathHandler::appendChar (uint32_t c, double x, double y) { if (color.changed() || _matrix.changed()) { resetContextNode(); if (applyColor || applyMatrix) { - _groupNode = pushContextNode(util::make_unique<XMLElementNode>("g")); + _groupNode = pushContextNode(util::make_unique<XMLElement>("g")); if (applyColor) contextNode()->addAttribute("fill", color.get().svgColorString()); if (applyMatrix) - contextNode()->addAttribute("transform", _matrix.get().getSVG()); + contextNode()->addAttribute("transform", _matrix.get().toSVG()); } color.changed(false); _matrix.changed(false); @@ -84,7 +84,7 @@ void SVGCharPathHandler::appendChar (uint32_t c, double x, double y) { GlyphMetrics metrics; font->getGlyphMetrics(c, _vertical, metrics); x -= metrics.wl; - if (const PhysicalFont *pf = dynamic_cast<const PhysicalFont*>(font)) { + if (auto pf = dynamic_cast<const PhysicalFont*>(font)) { // Center glyph between top and bottom border of the TFM box. // This is just an approximation used until I find a way to compute // the exact location in vertical mode. @@ -109,28 +109,28 @@ void SVGCharPathHandler::appendChar (uint32_t c, double x, double y) { void SVGCharPathHandler::appendUseElement (uint32_t c, double x, double y, const Matrix &matrix) { string id = "#g" + to_string(FontManager::instance().fontID(_font)) + "-" + to_string(c); - auto useNode = util::make_unique<XMLElementNode>("use"); + auto useNode = util::make_unique<XMLElement>("use"); useNode->addAttribute("x", XMLString(x)); useNode->addAttribute("y", XMLString(y)); useNode->addAttribute("xlink:href", id); if (!matrix.isIdentity()) - useNode->addAttribute("transform", matrix.getSVG()); + useNode->addAttribute("transform", matrix.toSVG()); contextNode()->append(std::move(useNode)); } void SVGCharPathHandler::appendPathElement (uint32_t c, double x, double y, const Matrix &matrix) { Glyph glyph; - const PhysicalFont *pf = dynamic_cast<const PhysicalFont*>(_font.get()); + auto pf = dynamic_cast<const PhysicalFont*>(_font.get()); if (pf && pf->getGlyph(c, glyph)) { double sx = pf->scaledSize()/pf->unitsPerEm(); double sy = -sx; ostringstream oss; glyph.writeSVG(oss, _relativePathCommands, sx, sy, x, y); - auto glyphNode = util::make_unique<XMLElementNode>("path"); + auto glyphNode = util::make_unique<XMLElement>("path"); glyphNode->addAttribute("d", oss.str()); if (!matrix.isIdentity()) - glyphNode->addAttribute("transform", matrix.getSVG()); + glyphNode->addAttribute("transform", matrix.toSVG()); contextNode()->append(std::move(glyphNode)); } } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharPathHandler.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharPathHandler.hpp index 944e554a9e6..ba172de340d 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharPathHandler.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharPathHandler.hpp @@ -37,10 +37,10 @@ class SVGCharPathHandler : public SVGCharHandler { void resetContextNode () override; private: - AppendMethod _appendChar; ///< method called to append a single character - bool _relativePathCommands; ///< if true, create relative rather than absolute SVG path commands - XMLElementNode *_groupNode; ///< current group node taking the path elements - CharProperty<Color> _fontColor; ///< color of current font + AppendMethod _appendChar; ///< method called to append a single character + bool _relativePathCommands; ///< if true, create relative rather than absolute SVG path commands + XMLElement *_groupNode=nullptr; ///< current group node taking the path elements + CharProperty<Color> _fontColor=Color::BLACK; ///< color of current font }; #endif diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharTspanTextHandler.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharTspanTextHandler.cpp index eb47f493085..a48f5f9a931 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharTspanTextHandler.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharTspanTextHandler.cpp @@ -41,20 +41,20 @@ void SVGCharTspanTextHandler::appendChar (uint32_t c, double x, double y) { if (_tspanNode && (_xchanged || _ychanged || _color.changed())) { // if drawing position or color was explicitly changed, finish current tspan element popContextNode(); - _tspanNode = 0; + _tspanNode = nullptr; } // Apply text color changes only if the color of the entire font is black. // Glyphs of non-black fonts (e.g. defined in a XeTeX document) can't change their color. bool applyColor = _color.get() != Color::BLACK && _font.get()->color() == Color::BLACK; if (_xchanged || _ychanged || (_color.changed() && applyColor)) { - _tspanNode = pushContextNode(util::make_unique<XMLElementNode>("tspan")); + _tspanNode = pushContextNode(util::make_unique<XMLElement>("tspan")); if (applyColor) _tspanNode->addAttribute("fill", _color.get().svgColorString()); _color.changed(false); if (_xchanged) { if (_vertical) { // align glyphs designed for horizontal layout properly - if (const PhysicalFont *pf = dynamic_cast<const PhysicalFont*>(_font.get())) + if (auto pf = dynamic_cast<const PhysicalFont*>(_font.get())) if (!pf->getMetrics()->verticalLayout()) x += pf->scaledAscent()/2.5; // move vertical baseline to the right by strikethrough offset } @@ -70,16 +70,16 @@ void SVGCharTspanTextHandler::appendChar (uint32_t c, double x, double y) { } -void SVGCharTspanTextHandler::setInitialContextNode (XMLElementNode *node) { +void SVGCharTspanTextHandler::setInitialContextNode (XMLElement *node) { SVGCharHandler::setInitialContextNode(node); - _textNode = _tspanNode = 0; + _textNode = _tspanNode = nullptr; _xchanged = _ychanged = false; } void SVGCharTspanTextHandler::resetContextNode () { SVGCharHandler::resetContextNode(); - _textNode = _tspanNode = 0; + _textNode = _tspanNode = nullptr; _xchanged = _ychanged = false; _font.changed(false); _matrix.changed(false); diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharTspanTextHandler.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharTspanTextHandler.hpp index c88e97bfe52..01567997b63 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharTspanTextHandler.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharTspanTextHandler.hpp @@ -25,19 +25,19 @@ class SVGCharTspanTextHandler : public SVGCharTextHandler { public: - SVGCharTspanTextHandler (bool selectFontByClass); + explicit SVGCharTspanTextHandler (bool selectFontByClass); void notifyXAdjusted () override {_xchanged = true;} void notifyYAdjusted() override {_ychanged = true;} void appendChar (uint32_t c, double x, double y) override; - void setInitialContextNode (XMLElementNode *node) override; + void setInitialContextNode (XMLElement *node) override; protected: void resetContextNode () override; private: bool _xchanged, _ychanged; - XMLElementNode *_textNode; - XMLElementNode *_tspanNode; + XMLElement *_textNode; + XMLElement *_tspanNode; }; #endif diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGOutput.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGOutput.cpp index 6256acdeba1..7c4108c8769 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGOutput.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGOutput.cpp @@ -34,8 +34,8 @@ using namespace std; -SVGOutput::SVGOutput (const string &base, const string &pattern, int zipLevel) - : _path(base), _pattern(pattern), _stdout(base.empty()), _zipLevel(zipLevel), _page(-1) +SVGOutput::SVGOutput (const string &base, string pattern, int zipLevel) + : _path(base), _pattern(std::move(pattern)), _stdout(base.empty()), _zipLevel(zipLevel), _page(-1) { } @@ -46,8 +46,8 @@ SVGOutput::SVGOutput (const string &base, const string &pattern, int zipLevel) * @param[in] hash hash value of the current page * @return output stream for the given page */ ostream& SVGOutput::getPageStream (int page, int numPages, const HashTriple &hashes) const { - string fname = filename(page, numPages, hashes); - if (fname.empty()) { + FilePath path = filepath(page, numPages, hashes); + if (path.empty()) { if (_zipLevel == 0) { _osptr.reset(); return cout; @@ -63,52 +63,35 @@ ostream& SVGOutput::getPageStream (int page, int numPages, const HashTriple &has _page = page; if (_zipLevel > 0) - _osptr = util::make_unique<ZLibOutputFileStream>(fname, ZLIB_GZIP, _zipLevel); + _osptr = util::make_unique<ZLibOutputFileStream>(path.absolute(), ZLIB_GZIP, _zipLevel); else - _osptr = util::make_unique<ofstream>(fname); + _osptr = util::make_unique<ofstream>(path.absolute()); if (!_osptr) - throw MessageException("can't open file "+fname+" for writing"); + throw MessageException("can't open file "+path.shorterAbsoluteOrRelative()+" for writing"); return *_osptr; } -/** Returns the name of the SVG file containing the given page. +/** Returns the path of the SVG file containing the given page number. * @param[in] page number of current page * @param[in] numPages total number of pages * @param[in] hash hash value of current page */ -string SVGOutput::filename (int page, int numPages, const HashTriple &hashes) const { - if (_stdout) - return ""; - - string expanded_pattern = util::trim(expandFormatString(_pattern, page, numPages, hashes)); - // set and expand default pattern if necessary - if (expanded_pattern.empty()) { - string pattern = hashes.empty() ? (numPages > 1 ? "%f-%p" : "%f") : "%f-%hd"; - expanded_pattern = expandFormatString(pattern, page, numPages, hashes); +FilePath SVGOutput::filepath (int page, int numPages, const HashTriple &hashes) const { + FilePath outpath; + if (!_stdout) { + string expanded_pattern = util::trim(expandFormatString(_pattern, page, numPages, hashes)); + // set and expand default pattern if necessary + if (expanded_pattern.empty()) { + string pattern = hashes.empty() ? (numPages > 1 ? "%f-%p" : "%f") : "%f-%hd"; + expanded_pattern = expandFormatString(pattern, page, numPages, hashes); + } + // append suffix if necessary + outpath.set(expanded_pattern, true); + if (outpath.suffix().empty()) + outpath.suffix(_zipLevel > 0 ? "svgz" : "svg"); } - // append suffix if necessary - FilePath outpath(expanded_pattern, true); - if (outpath.suffix().empty()) - outpath.suffix(_zipLevel > 0 ? "svgz" : "svg"); - string abspath = outpath.absolute(); - string relpath = outpath.relative(); - return abspath.length() < relpath.length() ? abspath : relpath; -} - - -#if 0 -string SVGOutput::outpath (int page, int numPages) const { - string path = filename(page, numPages); - if (path.empty()) - return ""; - size_t pos = path.rfind('/'); - if (pos == string::npos) - return "."; - if (pos == 0) - return "/"; - return path.substr(0, pos); + return outpath; } -#endif /** Replaces expressions in a given string by the corresponding values and returns the result. @@ -174,9 +157,7 @@ string SVGOutput::expandFormatString (string str, int page, int numPages, const result += oss.str(); } catch (CalculatorException &e) { - oss.str(""); - oss << "error in filename pattern (" << e.what() << ")"; - throw MessageException(oss.str()); + throw MessageException("error in filename pattern (" + string(e.what()) + ")"); } pos = endpos; } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGOutput.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGOutput.hpp index 6fb4ee6abf1..3c382f0b7fe 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGOutput.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGOutput.hpp @@ -31,8 +31,8 @@ struct SVGOutputBase { class HashTriple { public: HashTriple () =default; - HashTriple (const std::string &dviHash, const std::string &optHash, const std::string &cmbHash) - : _dviHash(dviHash), _optHash(optHash), _cmbHash(cmbHash) {} + HashTriple (std::string dviHash, std::string optHash, std::string cmbHash) + : _dviHash(std::move(dviHash)), _optHash(std::move(optHash)), _cmbHash(std::move(cmbHash)) {} std::string dviHash () const {return _dviHash;} std::string optHash () const {return _optHash;} std::string cmbHash () const {return _cmbHash;} @@ -46,7 +46,7 @@ struct SVGOutputBase { virtual ~SVGOutputBase () =default; virtual std::ostream& getPageStream (int page, int numPages, const HashTriple &hashes=HashTriple()) const =0; - virtual std::string filename (int page, int numPages, const HashTriple &hashes=HashTriple()) const =0; + virtual FilePath filepath (int page, int numPages, const HashTriple &hashes= HashTriple()) const =0; virtual bool ignoresHashes () const {return true;} }; @@ -54,11 +54,11 @@ struct SVGOutputBase { class SVGOutput : public SVGOutputBase { public: SVGOutput () : SVGOutput("", "", 0) {} - SVGOutput (const std::string &base) : SVGOutput(base, "", 0) {} + explicit SVGOutput (const std::string &base) : SVGOutput(base, "", 0) {} SVGOutput (const std::string &base, const std::string &pattern) : SVGOutput(base, pattern, 0) {} - SVGOutput (const std::string &base, const std::string &pattern, int zipLevel); + SVGOutput (const std::string &base, std::string pattern, int zipLevel); std::ostream& getPageStream (int page, int numPages, const HashTriple &hash=HashTriple()) const override; - std::string filename (int page, int numPages, const HashTriple &hash=HashTriple()) const override; + FilePath filepath (int page, int numPages, const HashTriple &hash=HashTriple()) const override; bool ignoresHashes () const override; protected: diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGSingleCharTextHandler.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGSingleCharTextHandler.hpp index 9729bafabac..7fd2174f127 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGSingleCharTextHandler.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGSingleCharTextHandler.hpp @@ -26,7 +26,7 @@ class SVGSingleCharTextHandler : public SVGCharTextHandler { public: - SVGSingleCharTextHandler (bool createStyleElements) : SVGCharTextHandler(createStyleElements) {} + explicit SVGSingleCharTextHandler (bool createStyleElements) : SVGCharTextHandler(createStyleElements) {} void appendChar (uint32_t c, double x, double y) override; }; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGTree.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGTree.cpp index 3c891219e14..57b5fd5a4fa 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGTree.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGTree.cpp @@ -20,9 +20,9 @@ #include <algorithm> #include <array> +#include <cstring> #include <sstream> #include "BoundingBox.hpp" -#include "DependencyGraph.hpp" #include "DVIToSVG.hpp" #include "FileSystem.hpp" #include "Font.hpp" @@ -36,7 +36,6 @@ using namespace std; - // static class variables bool SVGTree::CREATE_CSS=true; bool SVGTree::USE_FONTS=true; @@ -56,7 +55,7 @@ SVGTree::SVGTree () : _charHandler(SVGCharHandlerFactory::createHandler()) { /** Clears the SVG tree and initializes the root element. */ void SVGTree::reset () { _doc.clear(); - auto rootNode = util::make_unique<XMLElementNode>("svg"); + auto rootNode = util::make_unique<XMLElement>("svg"); rootNode->addAttribute("version", "1.1"); rootNode->addAttribute("xmlns", "http://www.w3.org/2000/svg"); rootNode->addAttribute("xmlns:xlink", "http://www.w3.org/1999/xlink"); @@ -112,45 +111,46 @@ bool SVGTree::setFontFormat (string formatstr) { /** Starts a new page. * @param[in] pageno number of new page */ void SVGTree::newPage (int pageno) { - auto pageNode = util::make_unique<XMLElementNode>("g"); + auto pageNode = util::make_unique<XMLElement>("g"); if (pageno >= 0) pageNode->addAttribute("id", string("page")+XMLString(pageno)); _charHandler->setInitialContextNode(pageNode.get()); _page = pageNode.get(); _root->append(std::move(pageNode)); - while (!_contextElementStack.empty()) - _contextElementStack.pop(); + _defsContextStack = stack<XMLElement*>(); + _pageContextStack = stack<XMLElement*>(); } -void SVGTree::appendToDefs (unique_ptr<XMLNode> &&node) { +void SVGTree::appendToDefs (unique_ptr<XMLNode> node) { if (!_defs) { - auto defsNode = util::make_unique<XMLElementNode>("defs"); + auto defsNode = util::make_unique<XMLElement>("defs"); _defs = defsNode.get(); _root->prepend(std::move(defsNode)); } - _defs->append(std::move(node)); + XMLElement *parent = _defsContextStack.empty() ? _defs : _defsContextStack.top(); + parent->append(std::move(node)); } -void SVGTree::appendToPage (unique_ptr<XMLNode> &&node) { - XMLElementNode *parent = _contextElementStack.empty() ? _page : _contextElementStack.top(); +void SVGTree::appendToPage (unique_ptr<XMLNode> node) { + XMLElement *parent = _pageContextStack.empty() ? _page : _pageContextStack.top(); parent->append(std::move(node)); _charHandler->setInitialContextNode(parent); } -void SVGTree::prependToPage (unique_ptr<XMLNode> &&node) { - if (_contextElementStack.empty()) +void SVGTree::prependToPage (unique_ptr<XMLNode> node) { + if (_pageContextStack.empty()) _page->prepend(std::move(node)); else - _contextElementStack.top()->prepend(std::move(node)); + _pageContextStack.top()->prepend(std::move(node)); } void SVGTree::transformPage (const Matrix &usermatrix) { if (!usermatrix.isIdentity()) - _page->addAttribute("transform", usermatrix.getSVG()); + _page->addAttribute("transform", usermatrix.toSVG()); } @@ -159,17 +159,17 @@ void SVGTree::transformPage (const Matrix &usermatrix) { * @param[in] font font to extract the glyph from * @param[in] cb pointer to callback object for sending feedback to the glyph tracer (may be 0) * @return pointer to element node if glyph exists, 0 otherwise */ -static unique_ptr<XMLElementNode> createGlyphNode (int c, const PhysicalFont &font, GFGlyphTracer::Callback *cb) { +static unique_ptr<XMLElement> createGlyphNode (int c, const PhysicalFont &font, GFGlyphTracer::Callback *cb) { Glyph glyph; if (!font.getGlyph(c, glyph, cb) || (!SVGTree::USE_FONTS && !SVGTree::CREATE_USE_ELEMENTS)) return nullptr; double sx=1.0, sy=1.0; double upem = font.unitsPerEm(); - unique_ptr<XMLElementNode> glyphNode; + unique_ptr<XMLElement> glyphNode; if (SVGTree::USE_FONTS) { double extend = font.style() ? font.style()->extend : 1; - glyphNode = util::make_unique<XMLElementNode>("glyph"); + glyphNode = util::make_unique<XMLElement>("glyph"); glyphNode->addAttribute("unicode", XMLString(font.unicode(c), false)); glyphNode->addAttribute("horiz-adv-x", XMLString(font.hAdvance(c)*extend)); glyphNode->addAttribute("vert-adv-y", XMLString(font.vAdvance(c))); @@ -178,7 +178,7 @@ static unique_ptr<XMLElementNode> createGlyphNode (int c, const PhysicalFont &fo glyphNode->addAttribute("glyph-name", name); } else { - glyphNode = util::make_unique<XMLElementNode>("path"); + glyphNode = util::make_unique<XMLElement>("path"); glyphNode->addAttribute("id", "g"+to_string(FontManager::instance().fontID(&font))+"-"+to_string(c)); sx = font.scaledSize()/upem; sy = -sx; @@ -192,7 +192,7 @@ static unique_ptr<XMLElementNode> createGlyphNode (int c, const PhysicalFont &fo static string font_info (const Font &font) { ostringstream oss; - if (const NativeFont *nf = dynamic_cast<const NativeFont*>(&font)) { + if (auto nf = dynamic_cast<const NativeFont*>(&font)) { oss << nf->familyName() << ' ' << nf->styleName() << "; " << nf->filename(); if (nf->style()) { if (nf->style()->bold != 0) @@ -255,14 +255,14 @@ void SVGTree::append (const PhysicalFont &font, const set<int> &chars, GFGlyphTr if (ADD_COMMENTS) { string info = font_info(font); if (!info.empty()) - appendToDefs(util::make_unique<XMLCommentNode>(string(" font: ")+info+" ")); + appendToDefs(util::make_unique<XMLComment>(string(" font: ")+info+" ")); } - auto fontNode = util::make_unique<XMLElementNode>("font"); + auto fontNode = util::make_unique<XMLElement>("font"); string fontname = font.name(); fontNode->addAttribute("id", fontname); fontNode->addAttribute("horiz-adv-x", XMLString(font.hAdvance())); - auto faceNode = util::make_unique<XMLElementNode>("font-face"); + auto faceNode = util::make_unique<XMLElement>("font-face"); faceNode->addAttribute("font-family", fontname); faceNode->addAttribute("units-per-em", XMLString(font.unitsPerEm())); if (!font.verticalLayout()) { @@ -281,7 +281,7 @@ void SVGTree::append (const PhysicalFont &font, const set<int> &chars, GFGlyphTr // reference the already embedded path together with a transformation attribute and let the SVG renderer // scale the glyphs properly. This is only necessary if we don't want to use font but path elements. for (int c : chars) { - auto useNode = util::make_unique<XMLElementNode>("use"); + auto useNode = util::make_unique<XMLElement>("use"); useNode->addAttribute("id", "g"+to_string(FontManager::instance().fontID(&font))+"-"+to_string(c)); useNode->addAttribute("xlink:href", "#g"+to_string(FontManager::instance().fontID(font.uniqueFont()))+"-"+to_string(c)); double scale = font.scaledSize()/font.uniqueFont()->scaledSize(); @@ -297,70 +297,47 @@ void SVGTree::append (const PhysicalFont &font, const set<int> &chars, GFGlyphTr } -/** Pushes a new context element that will take all following nodes added to the page. */ -void SVGTree::pushContextElement (unique_ptr<XMLElementNode> &&node) { - XMLElementNode *nodePtr = node.get(); - if (_contextElementStack.empty()) - _page->append(std::move(node)); +void SVGTree::pushDefsContext (unique_ptr<XMLElement> node) { + XMLElement *nodePtr = node.get(); + if (_defsContextStack.empty()) + appendToDefs(std::move(node)); else - _contextElementStack.top()->append(std::move(node)); - _contextElementStack.push(nodePtr); - _charHandler->setInitialContextNode(nodePtr); + _defsContextStack.top()->append(std::move(node)); + _defsContextStack.push(nodePtr); } -/** Pops the current context element and restored the previous one. */ -void SVGTree::popContextElement () { - if (!_contextElementStack.empty()) - _contextElementStack.pop(); - _charHandler->setInitialContextNode(_page); +void SVGTree::popDefsContext () { + if (!_defsContextStack.empty()) + _defsContextStack.pop(); } -/** Extracts the ID from a local URL reference like url(#abcde) */ -static inline string extract_id_from_url (const string &url) { - return url.substr(5, url.length()-6); +/** Pushes a new context element that will take all following nodes added to the page. */ +void SVGTree::pushPageContext (unique_ptr<XMLElement> node) { + XMLElement *nodePtr = node.get(); + if (_pageContextStack.empty()) + _page->append(std::move(node)); + else + _pageContextStack.top()->append(std::move(node)); + _pageContextStack.push(nodePtr); + _charHandler->setInitialContextNode(nodePtr); } -/** Removes elements present in the SVG tree that are not required. - * For now, only clipPath elements are removed. */ -void SVGTree::removeRedundantElements () { - vector<XMLElementNode*> clipPathElements; - if (!_defs || !_defs->getDescendants("clipPath", nullptr, clipPathElements)) - return; - - // collect dependencies between clipPath elements in the defs section of the SVG tree - DependencyGraph<string> idTree; - for (const XMLElementNode *clip : clipPathElements) { - if (const char *id = clip->getAttributeValue("id")) { - if (const char *url = clip->getAttributeValue("clip-path")) - idTree.insert(extract_id_from_url(url), id); - else - idTree.insert(id); - } - } - // collect elements that reference a clipPath, i.e. have a clip-path attribute - vector<XMLElementNode*> descendants; - _page->getDescendants(nullptr, "clip-path", descendants); - // remove referenced IDs and their dependencies from the dependency graph - for (const XMLElementNode *elem : descendants) { - string idref = extract_id_from_url(elem->getAttributeValue("clip-path")); - idTree.removeDependencyPath(idref); - } - descendants.clear(); - for (const string &str : idTree.getKeys()) { - XMLElementNode *node = _defs->getFirstDescendant("clipPath", "id", str.c_str()); - _defs->remove(node); - } +/** Pops the current context element and restored the previous one. */ +void SVGTree::popPageContext () { + if (!_pageContextStack.empty()) + _pageContextStack.pop(); + _charHandler->setInitialContextNode(_page); } -XMLCDataNode* SVGTree::styleCDataNode () { +XMLCData* SVGTree::styleCDataNode () { if (!_styleCDataNode) { - auto styleNode = util::make_unique<XMLElementNode>("style"); + auto styleNode = util::make_unique<XMLElement>("style"); styleNode->addAttribute("type", "text/css"); - auto cdataNode = util::make_unique<XMLCDataNode>(); + auto cdataNode = util::make_unique<XMLCData>(); _styleCDataNode = cdataNode.get(); styleNode->append(std::move(cdataNode)); _root->insertBefore(std::move(styleNode), _page); diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGTree.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGTree.hpp index 62891e76fa3..d351ec97991 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGTree.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGTree.hpp @@ -46,17 +46,18 @@ class SVGTree { void reset (); bool write (std::ostream &os) const {return bool(_doc.write(os));} void newPage (int pageno); - void appendToDefs (std::unique_ptr<XMLNode> &&node); - void appendToPage (std::unique_ptr<XMLNode> &&node); - void prependToPage (std::unique_ptr<XMLNode> &&node); - void appendToDoc (std::unique_ptr<XMLNode> &&node) {_doc.append(std::move(node));} - void appendToRoot (std::unique_ptr<XMLNode> &&node) {_root->append(std::move(node));} + void appendToDefs (std::unique_ptr<XMLNode> node); + void appendToPage (std::unique_ptr<XMLNode> node); + void prependToPage (std::unique_ptr<XMLNode> node); + void appendToDoc (std::unique_ptr<XMLNode> node) {_doc.append(std::move(node));} + void appendToRoot (std::unique_ptr<XMLNode> node) {_root->append(std::move(node));} void appendChar (int c, double x, double y) {_charHandler->appendChar(c, x, y);} void appendFontStyles (const std::unordered_set<const Font*> &fonts); - void append (const PhysicalFont &font, const std::set<int> &chars, GFGlyphTracer::Callback *callback=0); - void pushContextElement (std::unique_ptr<XMLElementNode> &&node); - void popContextElement (); - void removeRedundantElements (); + void append (const PhysicalFont &font, const std::set<int> &chars, GFGlyphTracer::Callback *callback=nullptr); + void pushDefsContext (std::unique_ptr<XMLElement> node); + void popDefsContext (); + void pushPageContext (std::unique_ptr<XMLElement> node); + void popPageContext (); void setBBox (const BoundingBox &bbox); void setFont (int id, const Font &font); static bool setFontFormat (std::string formatstr); @@ -68,10 +69,12 @@ class SVGTree { void transformPage (const Matrix &m); Color getColor () const {return _charHandler->getColor();} const Matrix& getMatrix () const {return _charHandler->getMatrix();} - XMLElementNode* rootNode () const {return _root;} + XMLElement* rootNode () const {return _root;} + XMLElement* defsNode () const {return _defs;} + XMLElement* pageNode () const {return _page;} protected: - XMLCDataNode* styleCDataNode (); + XMLCData* styleCDataNode (); public: static bool USE_FONTS; ///< if true, create font references and don't draw paths directly @@ -85,10 +88,11 @@ class SVGTree { private: XMLDocument _doc; - XMLElementNode *_root, *_page, *_defs; - XMLCDataNode *_styleCDataNode; + XMLElement *_root, *_page, *_defs; + XMLCData *_styleCDataNode; std::unique_ptr<SVGCharHandler> _charHandler; - std::stack<XMLElementNode*> _contextElementStack; + std::stack<XMLElement*> _defsContextStack; + std::stack<XMLElement*> _pageContextStack; }; #endif diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/ShadingPatch.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/ShadingPatch.hpp index 2c430ac58bf..4346301e7bf 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/ShadingPatch.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/ShadingPatch.hpp @@ -38,12 +38,12 @@ class ShadingPatch { using ColorVec = std::vector<Color>; public: - ShadingPatch (Color::ColorSpace colorSpace) : _colorspace(colorSpace) {} + explicit ShadingPatch (Color::ColorSpace colorSpace) : _colorspace(colorSpace) {} virtual ~ShadingPatch () =default; virtual int psShadingType () const =0; virtual void approximate (int gridsize, bool overlap, double delta, Callback &callback) const =0; - virtual void getBBox (BoundingBox &bbox) const =0; - virtual void getBoundaryPath (GraphicsPath<double> &path) const =0; + virtual BoundingBox getBBox () const =0; + virtual GraphicsPath<double> getBoundaryPath () const =0; virtual void setPoints (const PointVec &points, int edgeflag, ShadingPatch *patch) =0; virtual void setColors (const ColorVec &colors, int edgeflag, ShadingPatch *patch) =0; virtual int numPoints (int edgeflag) const =0; @@ -63,7 +63,7 @@ class ShadingPatch { struct ShadingException : public MessageException { - ShadingException (const std::string &msg) : MessageException(msg) {} + explicit ShadingException (const std::string &msg) : MessageException(msg) {} }; #endif diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/SignalHandler.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/SignalHandler.cpp index aa2a5dde55e..886c9281bbc 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/SignalHandler.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/SignalHandler.cpp @@ -129,7 +129,7 @@ bool SignalHandler::Impl::setSigintHandler (HandlerFunc handler) { bool SignalHandler::Impl::restoreSigintHandler () { if (_origSigaction.sa_handler == nullptr) return false; - return (sigaction(SIGINT, &_origSigaction, 0) == 0); + return (sigaction(SIGINT, &_origSigaction, nullptr) == 0); } #else // !HAVE_SIGACTION diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/SourceInput.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/SourceInput.hpp index 05df49ee84a..3b0f7b3c62c 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/SourceInput.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/SourceInput.hpp @@ -43,7 +43,7 @@ class TemporaryFile { class SourceInput { public: - SourceInput (const std::string &fname) : _fname(fname) {} + explicit SourceInput (const std::string &fname) : _fname(fname) {} std::istream& getInputStream (bool showMessages=false); std::string getFileName () const; std::string getMessageFileName () const; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/SpecialActions.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/SpecialActions.hpp index 5e32f84413b..7e53303792b 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/SpecialActions.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/SpecialActions.hpp @@ -25,10 +25,12 @@ #include <memory> #include "BoundingBox.hpp" #include "Color.hpp" +#include "FilePath.hpp" #include "Matrix.hpp" +#include "SVGTree.hpp" +class XMLElement; class XMLNode; -class XMLElementNode; class SpecialActions { public: @@ -44,20 +46,20 @@ class SpecialActions { virtual const Matrix& getMatrix () const =0; virtual Matrix getPageTransformation () const {return Matrix(1);} virtual void setBgColor (const Color &color) =0; - virtual void appendToPage(std::unique_ptr<XMLNode> &&node) =0; - virtual void appendToDefs(std::unique_ptr<XMLNode> &&node) =0; - virtual void prependToPage(std::unique_ptr<XMLNode> &&node) =0; - virtual void pushContextElement (std::unique_ptr<XMLElementNode> &&node) =0; - virtual void popContextElement () =0; + virtual const SVGTree& svgTree () const =0; + SVGTree& svgTree () {return const_cast<SVGTree&>(const_cast<const SpecialActions*>(this)->svgTree());} virtual BoundingBox& bbox () =0; virtual BoundingBox& bbox (const std::string &name, bool reset=false) =0; virtual void embed (const BoundingBox &bbox) =0; virtual void embed (const DPair &p, double r=0) =0; virtual unsigned getCurrentPageNumber () const =0; - virtual std::string getSVGFilename (unsigned pageno) const =0; + virtual FilePath getSVGFilePath (unsigned pageno) const =0; virtual std::string getBBoxFormatString () const =0; virtual void progress (const char *id) {} virtual int getDVIStackDepth () const {return 0;} + virtual void lockOutput () {} + virtual void unlockOutput () {} + virtual bool outputLocked () const {return false;} static double PROGRESSBAR_DELAY; ///< progress bar doesn't appear before this time has elapsed (in sec) }; @@ -65,6 +67,7 @@ class SpecialActions { class EmptySpecialActions : public SpecialActions { public: + EmptySpecialActions () : _matrix(1) {_svg.newPage(1);} double getX () const override {return 0;} double getY () const override {return 0;} void setX (double x) override {} @@ -75,22 +78,19 @@ class EmptySpecialActions : public SpecialActions { Color getColor () const override {return Color::BLACK;} void setMatrix (const Matrix &m) override {} const Matrix& getMatrix () const override {return _matrix;} - void appendToPage(std::unique_ptr<XMLNode> &&node) override {} - void appendToDefs(std::unique_ptr<XMLNode> &&node) override {} - void prependToPage(std::unique_ptr<XMLNode> &&node) override {} - void pushContextElement (std::unique_ptr<XMLElementNode> &&node) override {} - void popContextElement () override {} + const SVGTree& svgTree () const override {return _svg;} BoundingBox& bbox () override {return _bbox;} BoundingBox& bbox (const std::string &name, bool reset=false) override {return _bbox;} void embed (const BoundingBox &bbox) override {} void embed (const DPair &p, double r=0) override {} unsigned getCurrentPageNumber() const override {return 0;} - std::string getSVGFilename (unsigned pageno) const override {return "";} + FilePath getSVGFilePath (unsigned pageno) const override {return FilePath();} std::string getBBoxFormatString () const override {return "";} private: BoundingBox _bbox; Matrix _matrix; + SVGTree _svg; }; #endif diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/SpecialHandler.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/SpecialHandler.hpp index 35b4caf44a0..4a3439bb246 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/SpecialHandler.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/SpecialHandler.hpp @@ -32,7 +32,7 @@ class SpecialManager; struct SpecialException : public MessageException { - SpecialException (const std::string &msg) : MessageException(msg) {} + explicit SpecialException (const std::string &msg) : MessageException(msg) {} }; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/SpecialManager.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/SpecialManager.cpp index 5b8646879f0..4838cbdf47b 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/SpecialManager.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/SpecialManager.cpp @@ -46,7 +46,7 @@ void SpecialManager::unregisterHandlers () { /** Registers a single special handler. This method doesn't check if a * handler of the same class is already registered. * @param[in] handler pointer to handler to be registered */ -void SpecialManager::registerHandler (unique_ptr<SpecialHandler> &&handler) { +void SpecialManager::registerHandler (unique_ptr<SpecialHandler> handler) { if (handler) { // get array of prefixes this handler is responsible for for (const char *prefix : handler->prefixes()) @@ -104,11 +104,11 @@ static string extract_prefix (istream &is) { int c; string prefix; while (isalnum(c=is.get())) - prefix += c; + prefix += char(c); if (ispunct(c)) // also add separation character to identifying prefix - prefix += c; + prefix += char(c); if (prefix == "ps:" && is.peek() == ':') - prefix += is.get(); + prefix += char(is.get()); return prefix; } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/SpecialManager.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/SpecialManager.hpp index 671078baa6b..fe88eaf58eb 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/SpecialManager.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/SpecialManager.hpp @@ -36,8 +36,9 @@ class SpecialManager { using HandlerMap = std::unordered_map<std::string,SpecialHandler*>; public: + SpecialManager (const SpecialManager &) =delete; static SpecialManager& instance (); - void registerHandler (std::unique_ptr<SpecialHandler> &&handler); + void registerHandler (std::unique_ptr<SpecialHandler> handler); void registerHandlers (std::vector<std::unique_ptr<SpecialHandler>> &handlers, const char *ignorelist); void unregisterHandlers (); void preprocess (const std::string &special, SpecialActions &actions) const; @@ -51,7 +52,6 @@ class SpecialManager { protected: SpecialManager () =default; - SpecialManager (const SpecialManager &) =delete; SpecialHandler* findHandlerByPrefix (const std::string &prefix) const; private: diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/StreamReader.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/StreamReader.cpp index 08067566075..ccfb176abee 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/StreamReader.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/StreamReader.cpp @@ -20,8 +20,9 @@ #include <algorithm> #include <vector> -#include "CRC32.hpp" +#include "HashFunction.hpp" #include "StreamReader.hpp" +#include "utility.hpp" using namespace std; @@ -46,13 +47,13 @@ uint32_t StreamReader::readUnsigned (int bytes) { } -/** Reads an unsigned integer from assigned input stream and updates the CRC32 checksum. - * @param[in] bytes number of bytes to read (max. 4) - * @param[in,out] crc32 checksum to be updated +/** Reads an unsigned integer from assigned input stream and updates the hash value. + * @param[in] n number of bytes to read (max. 4) + * @param[in,out] hashfunc hash to update * @return read integer */ -uint32_t StreamReader::readUnsigned (int bytes, CRC32 &crc32) { - uint32_t ret = readUnsigned(bytes); - crc32.update(ret, bytes); +uint32_t StreamReader::readUnsigned (int n, HashFunction &hashfunc) { + uint32_t ret = readUnsigned(n); + hashfunc.update(util::bytes(ret, n)); return ret; } @@ -70,13 +71,13 @@ int32_t StreamReader::readSigned (int bytes) { } -/** Reads an signed integer from assigned input stream and updates the CRC32 checksum. +/** Reads an signed integer from assigned input stream and updates the hash value. * @param[in] bytes number of bytes to read (max. 4) - * @param[in,out] crc32 checksum to be updated + * @param[in,out] hashfunc hash to update * @return read integer */ -int32_t StreamReader::readSigned (int bytes, CRC32 &crc32) { - int32_t ret = readSigned(bytes); - crc32.update(uint32_t(ret), bytes); +int32_t StreamReader::readSigned (int n, HashFunction &hashfunc) { + int32_t ret = readSigned(n); + hashfunc.update(util::bytes(ret, n)); return ret; } @@ -87,21 +88,21 @@ string StreamReader::readString () { throw StreamReaderException("no stream assigned"); string ret; while (!_is->eof() && _is->peek() > 0) - ret += _is->get(); + ret += char(_is->get()); _is->get(); // skip 0-byte return ret; } -/** Reads a string terminated by a 0-byte and updates the CRC32 checksum. - * @param[in,out] crc32 checksum to be updated +/** Reads a string terminated by a 0-byte and updates the hash value. + * @param[in,out] hashfunc hash to update * @param[in] finalZero consider final 0-byte in checksum * @return the string read */ -string StreamReader::readString (CRC32 &crc32, bool finalZero) { +string StreamReader::readString (HashFunction &hashfunc, bool finalZero) { string ret = readString(); - crc32.update(reinterpret_cast<const uint8_t*>(ret.data()), ret.length()); + hashfunc.update(ret.data(), ret.length()); if (finalZero) - crc32.update(0, 1); + hashfunc.update(0, 1); return ret; } @@ -119,36 +120,37 @@ string StreamReader::readString (int length) { } -/** Reads a string of a given length and updates the CRC32 checksum. +/** Reads a string of a given length and updates the hash value. * @param[in] length number of characters to read - * @param[in,out] crc32 checksum to be updated + * @param[in,out] hashfunc hash to update * @return the string read */ -string StreamReader::readString (int length, CRC32 &crc32) { +string StreamReader::readString (int length, HashFunction &hashfunc) { string ret = readString(length); - crc32.update(reinterpret_cast<const uint8_t*>(ret.data()), length); + hashfunc.update(ret.data(), length); return ret; } -vector<uint8_t>& StreamReader::readBytes (int n, vector<uint8_t> &bytes) { +vector<uint8_t> StreamReader::readBytes (int n) { + vector<uint8_t> bytes(n); if (n > 0) - _is->read((char*)&bytes[0], n); + _is->read(reinterpret_cast<char*>(bytes.data()), n); return bytes; } -vector<uint8_t>& StreamReader::readBytes (int n, vector<uint8_t> &bytes, CRC32 &crc32) { - readBytes(n, bytes); - crc32.update(&bytes[0], bytes.size()); +vector<uint8_t> StreamReader::readBytes (int n, HashFunction &hashfunc) { + vector<uint8_t> bytes = readBytes(n); + hashfunc.update(bytes); return bytes; } -int StreamReader::readByte (CRC32 &crc32) { +int StreamReader::readByte (HashFunction &hashfunc) { int ret = readByte(); if (ret >= 0) { - const uint8_t c = uint8_t(ret & 0xff); - crc32.update(&c, 1); + char c = ret & 0xff; + hashfunc.update(&c, 1); } return ret; } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/StreamReader.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/StreamReader.hpp index bf38b2cbf76..05c4e1e701b 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/StreamReader.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/StreamReader.hpp @@ -26,28 +26,28 @@ #include <vector> #include "MessageException.hpp" -class CRC32; +class HashFunction; class StreamReader { public: - StreamReader (std::istream &is) : _is(&is) {} + explicit StreamReader (std::istream &is) : _is(&is) {} virtual ~StreamReader () =default; bool isStreamValid () const {return _is;} bool eof () const {return _is->eof();} void clearStream () {_is->clear();} std::istream& replaceStream (std::istream &s); uint32_t readUnsigned (int n); - uint32_t readUnsigned (int n, CRC32 &crc32); + uint32_t readUnsigned (int n, HashFunction &hashfunc); int32_t readSigned (int n); - int32_t readSigned (int n, CRC32 &crc32); + int32_t readSigned (int n, HashFunction &hashfunc); std::string readString (); - std::string readString (CRC32 &crc32, bool finalZero=false); + std::string readString (HashFunction &hashfunc, bool finalZero=false); std::string readString (int length); - std::string readString (int length, CRC32 &crc32); - std::vector<uint8_t>& readBytes (int n, std::vector<uint8_t> &bytes); - std::vector<uint8_t>& readBytes (int n, std::vector<uint8_t> &bytes, CRC32 &crc32); + std::string readString (int length, HashFunction &hashfunc); + std::vector<uint8_t> readBytes (int n); + std::vector<uint8_t> readBytes (int n, HashFunction &hash); int readByte () {return _is->get();} - int readByte (CRC32 &crc32); + int readByte (HashFunction &hashfunc); void seek (std::streampos pos, std::ios::seekdir dir) {_is->seekg(pos, dir);} void seek (std::streampos pos) {_is->seekg(pos);} std::streampos tell () const {return _is->tellg();} @@ -62,7 +62,7 @@ class StreamReader { struct StreamReaderException : public MessageException { - StreamReaderException (const std::string &msg) : MessageException(msg) {} + explicit StreamReaderException (const std::string &msg) : MessageException(msg) {} }; #endif diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/StreamWriter.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/StreamWriter.cpp index c5630f56ba2..62164686952 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/StreamWriter.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/StreamWriter.cpp @@ -18,8 +18,9 @@ ** along with this program; if not, see <http://www.gnu.org/licenses/>. ** *************************************************************************/ -#include "CRC32.hpp" +#include "HashFunction.hpp" #include "StreamWriter.hpp" +#include "utility.hpp" using namespace std; @@ -37,7 +38,7 @@ void StreamWriter::writeUnsigned (uint32_t val, int n) { * @param[in] val the value to write * @param[in] n number of bytes to be considered */ void StreamWriter::writeSigned (int32_t val, int n) { - writeUnsigned((uint32_t)val, n); + writeUnsigned(uint32_t(val), n); } @@ -71,27 +72,27 @@ void StreamWriter::writeString (const string &str, bool finalZero) { /** Writes an unsigned integer to the output stream. * @param[in] val the value to write * @param[in] n number of bytes to be considered - * @param[in,out] crc32 checksum to be updated */ -void StreamWriter::writeUnsigned (uint32_t val, int n, CRC32 &crc32) { + * @param[in,out] hashfunc hash to update */ +void StreamWriter::writeUnsigned (uint32_t val, int n, HashFunction &hashfunc) { writeUnsigned(val, n); - crc32.update(val, n); + hashfunc.update(util::bytes(val, n)); } -/** Writes a signed integer to the output stream and updates the CRC32 checksum. +/** Writes a signed integer to the output stream and updates the hash value. * @param[in] val the value to write * @param[in] n number of bytes to be considered - * @param[in,out] crc32 checksum to be updated */ -void StreamWriter::writeSigned (int32_t val, int n, CRC32 &crc32) { - writeUnsigned((uint32_t)val, n, crc32); + * @param[in,out] hashfunc hash to update */ +void StreamWriter::writeSigned (int32_t val, int n, HashFunction &hashfunc) { + writeUnsigned(uint32_t(val), n, hashfunc); } -/** Writes a string to the output stream and updates the CRC32 checksum. +/** Writes a string to the output stream and updates the hash value. * @param[in] str the string to write - * @param[in,out] crc32 checksum to be updated + * @param[in,out] hashfunc hash to update * @param[in] finalZero if true, a final 0-byte is appended */ -void StreamWriter::writeString (const std::string &str, CRC32 &crc32, bool finalZero) { +void StreamWriter::writeString (const std::string &str, HashFunction &hashfunc, bool finalZero) { writeString(str, finalZero); - crc32.update((const uint8_t*)str.c_str(), str.length() + (finalZero ? 1 : 0)); + hashfunc.update(str.data(), str.length() + (finalZero ? 1 : 0)); } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/StreamWriter.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/StreamWriter.hpp index b60e61811e9..441a9a7e7ff 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/StreamWriter.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/StreamWriter.hpp @@ -24,21 +24,20 @@ #include <ostream> #include <vector> -class CRC32; +class HashFunction; class StreamWriter { public: - StreamWriter (std::ostream &os) : _os(os) {} - virtual ~StreamWriter () =default; + explicit StreamWriter (std::ostream &os) : _os(os) {} void writeUnsigned (uint32_t val, int n); void writeSigned (int32_t val, int n); void writeBytes (const std::vector<uint8_t> &bytes); void writeBytes (const uint8_t *buf, size_t bufsize); void writeBytes (int byte, size_t count); void writeString (const std::string &str, bool finalZero=false); - void writeUnsigned (uint32_t val, int n, CRC32 &crc32); - void writeSigned (int32_t val, int n, CRC32 &crc32); - void writeString (const std::string &str, CRC32 &crc32, bool finalZero=false); + void writeUnsigned (uint32_t val, int n, HashFunction &hashfunc); + void writeSigned (int32_t val, int n, HashFunction &hashfunc); + void writeString (const std::string &str, HashFunction &hashfunc, bool finalZero=false); private: std::ostream &_os; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/Subfont.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/Subfont.cpp index 3f246c0dd8d..e0b2570d8c7 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/Subfont.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/Subfont.cpp @@ -34,13 +34,13 @@ using namespace std; // helper functions static int skip_mapping_data (istream &is); -static bool scan_line (const char *line, int lineno, vector<uint16_t> &mapping, const string &fname, long &pos); +static bool scan_line (const char *line, int lineno, vector<uint16_t> &mapping, const string &fname, long &offset); /** Constructs a new SubfontDefinition object. * @param[in] name name of subfont definition * @param[in] fpath path to corresponding .sfd file*/ -SubfontDefinition::SubfontDefinition (const string &name, const char *fpath) : _sfname(name) { +SubfontDefinition::SubfontDefinition (string name, const char *fpath) : _sfname(std::move(name)) { // read all subfont IDs from the .sfd file but skip the mapping data ifstream is(fpath); while (is) { @@ -51,7 +51,7 @@ SubfontDefinition::SubfontDefinition (const string &name, const char *fpath) : _ else { string id; while (is && !isspace(is.peek())) - id += is.get(); + id += char(is.get()); if (!id.empty()) { auto state = _subfonts.emplace(pair<string,unique_ptr<Subfont>>(id, unique_ptr<Subfont>())); if (state.second) // id was not present in map already @@ -136,7 +136,7 @@ bool Subfont::read () { else { string id; while (is && !isspace(is.peek())) - id += is.get(); + id += char(is.get()); if (id != _id) lineno += skip_mapping_data(is); else { diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/Subfont.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/Subfont.hpp index c452aaeaccf..ca88520ea2f 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/Subfont.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/Subfont.hpp @@ -37,6 +37,7 @@ class Subfont; class SubfontDefinition { using Subfonts = std::map<std::string, std::unique_ptr<Subfont>>; public: + SubfontDefinition (const SubfontDefinition &sfd) =delete; static SubfontDefinition* lookup (const std::string &name); // int getIDs (std::vector<std::string> &ids) const; const std::string& name() const {return _sfname;} @@ -46,8 +47,7 @@ class SubfontDefinition { const char* path () const; protected: - SubfontDefinition (const std::string &name, const char *fpath); - SubfontDefinition (const SubfontDefinition &sfd) =delete; + SubfontDefinition (std::string name, const char *fpath); private: std::string _sfname; ///< name of subfont @@ -59,12 +59,12 @@ class SubfontDefinition { class Subfont { friend class SubfontDefinition; public: + Subfont (const Subfont &sf) =delete; const std::string& id () const {return _id;} uint16_t decode (unsigned char c); protected: Subfont (SubfontDefinition &sfd, const std::string &id) : _sfd(sfd), _id(id), _mapping(0) {} - Subfont (const Subfont &sf) =delete; bool read (); private: @@ -76,8 +76,8 @@ class Subfont { class SubfontException : public MessageException { public: - SubfontException (const std::string &msg, const std::string &fname, int lineno=0) - : MessageException(msg), _fname(fname), _lineno(lineno) {} + SubfontException (const std::string &msg, std::string fname, int lineno=0) + : MessageException(msg), _fname(std::move(fname)), _lineno(lineno) {} const char* filename () const {return _fname.c_str();} int lineno () const {return _lineno;} diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/System.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/System.cpp index c63e5e02dcd..b2724bdcab2 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/System.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/System.cpp @@ -36,7 +36,7 @@ using namespace std; double System::time () { #if defined (HAVE_SYS_TIME_H) struct timeval tv; - gettimeofday(&tv, NULL); + gettimeofday(&tv, nullptr); return tv.tv_sec + tv.tv_usec/1000000.0; #elif defined (HAVE_SYS_TIMEB_H) struct timeb tb; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/TFM.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/TFM.hpp index 36cb462b6f3..668ff390833 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/TFM.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/TFM.hpp @@ -33,7 +33,7 @@ class StreamReader; class TFM : public FontMetrics { public: - TFM (std::istream &is); + explicit TFM (std::istream &is); double getCharWidth (int c) const override; double getCharHeight (int c) const override; double getCharDepth (int c) const override; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/TensorProductPatch.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/TensorProductPatch.cpp index e9e0ef4b192..52acd63179a 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/TensorProductPatch.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/TensorProductPatch.cpp @@ -63,7 +63,7 @@ void TensorProductPatch::setFirstMatrixColumn (DPair source[4][4], int col, bool * @param[in] edgeflag defines how to connect this patch with another one * @param[in] patch reference patch required if edgeflag > 0 */ void TensorProductPatch::setPoints (const PointVec &points, int edgeflag, ShadingPatch *patch) { - TensorProductPatch *tpPatch = dynamic_cast<TensorProductPatch*>(patch); + auto tpPatch = dynamic_cast<TensorProductPatch*>(patch); if (edgeflag > 0 && !tpPatch) throw ShadingException("missing preceding data in definition of tensor-product patch"); if ((edgeflag == 0 && points.size() != 16) || (edgeflag > 0 && points.size() != 12)) @@ -107,7 +107,7 @@ void TensorProductPatch::setPoints (const PointVec &points, int edgeflag, Shadin * @param[in] edgeflag defines how to connect this patch with another one * @param[in] patch reference patch required if edgeflag > 0 */ void TensorProductPatch::setColors(const ColorVec &colors, int edgeflag, ShadingPatch* patch) { - TensorProductPatch *tpPatch = dynamic_cast<TensorProductPatch*>(patch); + auto tpPatch = dynamic_cast<TensorProductPatch*>(patch); if (edgeflag > 0 && !tpPatch) throw ShadingException("missing preceding data in definition of tensor-product patch"); if ((edgeflag == 0 && colors.size() != 4) || (edgeflag > 0 && colors.size() != 2)) @@ -201,16 +201,18 @@ Color TensorProductPatch::averageColor (const Color &c1, const Color &c2, const } -void TensorProductPatch::getBoundaryPath (GraphicsPath<double> &path) const { +GraphicsPath<double> TensorProductPatch::getBoundaryPath () const { // Simple approach: Use the outer curves as boundary path. This doesn't always lead // to correct results since, depending on the control points, P(u,v) might exceed // the simple boundary. + GraphicsPath<double> path; path.moveto(_points[0][0]); path.cubicto(_points[0][1], _points[0][2], _points[0][3]); path.cubicto(_points[1][3], _points[2][3], _points[3][3]); path.cubicto(_points[3][2], _points[3][1], _points[3][0]); path.cubicto(_points[2][0], _points[1][0], _points[0][0]); path.closepath(); + return path; } @@ -354,8 +356,7 @@ void TensorProductPatch::approximateRow (double v1, double inc, bool overlap, do void TensorProductPatch::approximate (int gridsize, bool overlap, double delta, Callback &callback) const { if (_colors[0] == _colors[1] && _colors[1] == _colors[2] && _colors[2] == _colors[3]) { // simple case: monochromatic patch - GraphicsPath<double> path; - getBoundaryPath(path); + GraphicsPath<double> path = getBoundaryPath(); callback.patchSegment(path, _colors[0]); } else { @@ -377,17 +378,16 @@ void TensorProductPatch::approximate (int gridsize, bool overlap, double delta, } -void TensorProductPatch::getBBox (BoundingBox &bbox) const { +BoundingBox TensorProductPatch::getBBox () const { + BoundingBox bbox; Bezier bezier; - BoundingBox bezierBox; for (int i=0; i <= 1; i++) { horizontalCurve(i, bezier); - bezier.getBBox(bezierBox); - bbox.embed(bezierBox); + bbox.embed(bezier.getBBox()); verticalCurve(i, bezier); - bezier.getBBox(bezierBox); - bbox.embed(bezierBox); + bbox.embed(bezier.getBBox()); } + return bbox; } @@ -492,7 +492,7 @@ DPair CoonsPatch::valueAt (double u, double v) const { * @param[in] edgeflag defines how to connect this patch to another one * @param[in] patch reference patch required if edgeflag > 0 */ void CoonsPatch::setPoints (const PointVec &points, int edgeflag, ShadingPatch *patch) { - CoonsPatch *coonsPatch = dynamic_cast<CoonsPatch*>(patch); + auto coonsPatch = dynamic_cast<CoonsPatch*>(patch); if (edgeflag > 0 && !coonsPatch) throw ShadingException("missing preceding data in definition of relative Coons patch"); if ((edgeflag == 0 && points.size() != 12) || (edgeflag > 0 && points.size() != 8)) @@ -529,7 +529,7 @@ void CoonsPatch::setPoints (const PointVec &points, int edgeflag, ShadingPatch * void CoonsPatch::setColors (const ColorVec &colors, int edgeflag, ShadingPatch *patch) { - CoonsPatch *coonsPatch = dynamic_cast<CoonsPatch*>(patch); + auto coonsPatch = dynamic_cast<CoonsPatch*>(patch); if (edgeflag > 0 && !coonsPatch) throw ShadingException("missing preceding data in definition of relative Coons patch"); if ((edgeflag == 0 && colors.size() != 4) || (edgeflag > 0 && colors.size() != 2)) diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/TensorProductPatch.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/TensorProductPatch.hpp index ca5071d2eb4..711feefc2d8 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/TensorProductPatch.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/TensorProductPatch.hpp @@ -36,13 +36,11 @@ * \f[P(u,v):=\sum_{i=0}^3\sum_{j=0}^3 p_{ij} B_i(u) B_j(v)\f] * where \f$B_k(t)={3\choose k}(1-t)^k t^k\f$ and \f$u,v \in [0,1]\f$. The four colors assigned * to the vertices are interpolated bilinearily over the unit square. */ -class TensorProductPatch : public ShadingPatch -{ +class TensorProductPatch : public ShadingPatch { friend class CoonsPatch; - public: TensorProductPatch () : ShadingPatch(Color::ColorSpace::RGB) {} - TensorProductPatch (Color::ColorSpace cspace) : ShadingPatch(cspace) {} + explicit TensorProductPatch (Color::ColorSpace cspace) : ShadingPatch(cspace) {} TensorProductPatch (const PointVec &points, const ColorVec &colors, Color::ColorSpace cspace, int edgeflag, TensorProductPatch *patch); int psShadingType() const override {return 7;} void setPoints (const DPair points[4][4], int edgeflag, TensorProductPatch *patch); @@ -53,12 +51,12 @@ class TensorProductPatch : public ShadingPatch Color averageColor () const override; void horizontalCurve (double v, Bezier &bezier) const; void verticalCurve (double u, Bezier &bezier) const; - void getBoundaryPath (GraphicsPath<double> &path) const override; + GraphicsPath<double> getBoundaryPath () const override; void subpatch (double u1, double u2, double v1, double v2, TensorProductPatch &patch) const; DPair blossomValue (double u1, double u2, double u3, double v1, double v2, double v3) const; DPair blossomValue (double u[3], double v[3]) const {return blossomValue(u[0], u[1], u[2], v[0], v[1], v[2]);} void approximate (int gridsize, bool overlap, double delta, Callback &callback) const override; - void getBBox (BoundingBox &bbox) const override; + BoundingBox getBBox () const override; int numPoints (int edgeflag) const override {return edgeflag == 0 ? 16 : 12;} int numColors (int edgeflag) const override {return edgeflag == 0 ? 4 : 2;} @@ -78,16 +76,15 @@ class TensorProductPatch : public ShadingPatch * depend on the outer ones, i.e. they are computed automatically and can't be set by the user. * Thus, a Coons patch is defined by 12 control points, 4 vertex colors and a corresponding * color space. */ -class CoonsPatch : public TensorProductPatch -{ +class CoonsPatch : public TensorProductPatch { public: - CoonsPatch () {} - CoonsPatch (Color::ColorSpace cspace) : TensorProductPatch(cspace) {} + CoonsPatch () =default; + explicit CoonsPatch (Color::ColorSpace cspace) : TensorProductPatch(cspace) {} CoonsPatch (const PointVec &points, const ColorVec &colors, Color::ColorSpace cspace, int edgeflag, CoonsPatch *patch); int psShadingType() const override {return 6;} - virtual void setPoints (const PointVec &points, int edgeflag, ShadingPatch *patch) override; - virtual void setColors (const ColorVec &colors, int edgeflag, ShadingPatch *patch) override; - virtual DPair valueAt (double u, double v) const override; + void setPoints (const PointVec &points, int edgeflag, ShadingPatch *patch) override; + void setColors (const ColorVec &colors, int edgeflag, ShadingPatch *patch) override; + DPair valueAt (double u, double v) const override; int numPoints (int edgeflag) const override {return edgeflag == 0 ? 12 : 8;} int numColors (int edgeflag) const override {return edgeflag == 0 ? 4 : 2;} }; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/TpicSpecialHandler.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/TpicSpecialHandler.cpp index ae940d2d8ea..b97fa439afe 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/TpicSpecialHandler.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/TpicSpecialHandler.cpp @@ -23,6 +23,7 @@ #include <sstream> #include <string> #include "Color.hpp" +#include "EllipticalArc.hpp" #include "InputBuffer.hpp" #include "InputReader.hpp" #include "GraphicsPath.hpp" @@ -69,7 +70,7 @@ Color TpicSpecialHandler::fillColor (bool grayOnly) const { * @param[in] penwidth pen with used to compute the stroke parameters * @param[in] pencolor the drawing color * @param[in] ddist dash/dot distance of line in PS point units (0:solid line, >0:dashed line, <0:dotted line) */ -static void add_stroke_attribs (XMLElementNode *elem, double penwidth, Color pencolor, double ddist) { +static void add_stroke_attribs (XMLElement *elem, double penwidth, Color pencolor, double ddist) { if (penwidth > 0) { // attributes actually required? elem->addAttribute("stroke", pencolor.svgColorString()); elem->addAttribute("stroke-width", XMLString(penwidth)); @@ -81,9 +82,9 @@ static void add_stroke_attribs (XMLElementNode *elem, double penwidth, Color pen } -static unique_ptr<XMLElementNode> create_ellipse_element (double cx, double cy, double rx, double ry) { +static unique_ptr<XMLElement> create_ellipse_element (double cx, double cy, double rx, double ry) { bool is_circle = (rx == ry); - auto elem = util::make_unique<XMLElementNode>(is_circle ? "circle" : "ellipse"); + auto elem = util::make_unique<XMLElement>(is_circle ? "circle" : "ellipse"); elem->addAttribute("cx", XMLString(cx)); elem->addAttribute("cy", XMLString(cy)); if (is_circle) @@ -100,8 +101,8 @@ static unique_ptr<XMLElementNode> create_ellipse_element (double cx, double cy, * @param[in] ddist dash/dot distance of line in PS point units (0:solid line, >0:dashed line, <0:dotted line) * @param[in] actions object providing the actions that can be performed by the SpecialHandler */ void TpicSpecialHandler::drawLines (double ddist, SpecialActions &actions) { - if (!_points.empty() && (_penwidth > 0 || _grayLevel >= 0)) { - unique_ptr<XMLElementNode> elem; + if (!_points.empty() && (_penwidth > 0 || _grayLevel >= 0) && !actions.outputLocked()) { + unique_ptr<XMLElement> elem; if (_points.size() == 1) { const DPair &p = _points.back(); elem = create_ellipse_element(p.x()+actions.getX(), p.y()+actions.getY(), _penwidth/2.0, _penwidth/2.0); @@ -109,14 +110,14 @@ void TpicSpecialHandler::drawLines (double ddist, SpecialActions &actions) { } else { if (_points.size() == 2 || (_grayLevel < 0 && _points.front() != _points.back())) { - elem = util::make_unique<XMLElementNode>("polyline"); + elem = util::make_unique<XMLElement>("polyline"); elem->addAttribute("fill", "none"); elem->addAttribute("stroke-linecap", "round"); } else { while (_points.front() == _points.back()) _points.pop_back(); - elem = util::make_unique<XMLElementNode>("polygon"); + elem = util::make_unique<XMLElement>("polygon"); elem->addAttribute("fill", _grayLevel < 0 ? "none" : fillColor(false).svgColorString()); } ostringstream oss; @@ -131,7 +132,7 @@ void TpicSpecialHandler::drawLines (double ddist, SpecialActions &actions) { elem->addAttribute("points", oss.str()); add_stroke_attribs(elem.get(), _penwidth, Color::BLACK, ddist); } - actions.appendToPage(std::move(elem)); + actions.svgTree().appendToPage(std::move(elem)); } reset(); } @@ -146,7 +147,7 @@ void TpicSpecialHandler::drawLines (double ddist, SpecialActions &actions) { * @param[in] ddist length of dashes and gaps * @param[in] actions object providing the actions that can be performed by the SpecialHandler */ void TpicSpecialHandler::drawSplines (double ddist, SpecialActions &actions) { - if (!_points.empty() && _penwidth > 0) { + if (!_points.empty() && _penwidth > 0 && !actions.outputLocked()) { const size_t numPoints = _points.size(); if (numPoints < 3) { _grayLevel = -1; @@ -164,7 +165,7 @@ void TpicSpecialHandler::drawSplines (double ddist, SpecialActions &actions) { const DPair p1 = p+_points[i]; const DPair p2 = p+_points[i+1]; mid = p1+(p2-p1)/2.0; - path.conicto(p1, mid); + path.quadto(p1, mid); actions.embed(mid); actions.embed((p0+p1*6.0+p2)/8.0, _penwidth); } @@ -174,27 +175,19 @@ void TpicSpecialHandler::drawSplines (double ddist, SpecialActions &actions) { path.lineto(p+_points[numPoints-1]); actions.embed(p+_points[numPoints-1]); } - auto pathElem = util::make_unique<XMLElementNode>("path"); + auto pathElem = util::make_unique<XMLElement>("path"); pathElem->addAttribute("fill", "none"); ostringstream oss; path.writeSVG(oss, SVGTree::RELATIVE_PATH_CMDS); pathElem->addAttribute("d", oss.str()); add_stroke_attribs(pathElem.get(), _penwidth, _dviColor, ddist); - actions.appendToPage(std::move(pathElem)); + actions.svgTree().appendToPage(std::move(pathElem)); } } reset(); } -static double normalized_angle (double rad) { - rad = fmod(rad, math::TWO_PI); - if (rad < 0) - rad += math::TWO_PI; - return rad; -} - - /** Draws an elliptical arc. * @param[in] cx x-coordinate of arc center relative to current DVI position * @param[in] cy y-coordinate of arc center relative to current DVI position @@ -204,31 +197,25 @@ static double normalized_angle (double rad) { * @param[in] angle2 ending angle (clockwise) relative to x-axis * @param[in] actions object providing the actions that can be performed by the SpecialHandler */ void TpicSpecialHandler::drawArc (double cx, double cy, double rx, double ry, double angle1, double angle2, SpecialActions &actions) { - if (_penwidth > 0 || _grayLevel >= 0) { - angle1 = -angle1; - angle2 = -angle2; + if ((_penwidth > 0 || _grayLevel >= 0) && !actions.outputLocked()) { cx += actions.getX(); cy += actions.getY(); - unique_ptr<XMLElementNode> elem; + unique_ptr<XMLElement> elem; bool closed=true; if (abs(angle2-angle1) >= math::TWO_PI) // closed ellipse? elem = create_ellipse_element(cx, cy, rx, ry); else { - angle1 = normalized_angle(angle1); - angle2 = normalized_angle(angle2); - double delta = normalized_angle(angle2-angle1); - int large_arg = (delta < math::PI) ? 1 : 0; - ostringstream oss; - oss << 'M' << XMLString(cx+rx*cos(angle1)) << ' ' << XMLString(cy+ry*sin(-angle1)) - << 'A' << XMLString(rx) << ' ' << XMLString(ry) - << " 0 " // no rotation of x-axis - << large_arg << " 1 " // always draw arc clockwise (sweep flag == 1) - << XMLString(cx+rx*cos(angle2)) << ' ' << XMLString(cy-ry*sin(angle2)); + EllipticalArc arc(DPair(cx, cy), rx, ry, 0, -angle1, math::normalize_0_2pi(angle2-angle1)); + GraphicsPath<double> path; + path.moveto(arc.startPoint()); + path.arcto(rx, ry, 0, arc.largeArc(), arc.sweepPositive(), arc.endPoint()); if (_grayLevel >= 0) - oss << 'Z'; + path.closepath(); else closed = false; - elem = util::make_unique<XMLElementNode>("path"); + elem = util::make_unique<XMLElement>("path"); + ostringstream oss; + path.writeSVG(oss, SVGTree::RELATIVE_PATH_CMDS); elem->addAttribute("d", oss.str()); } if (_penwidth > 0) { @@ -238,7 +225,7 @@ void TpicSpecialHandler::drawArc (double cx, double cy, double rx, double ry, do elem->addAttribute("stroke-linecap", "round"); } elem->addAttribute("fill", _grayLevel < 0 ? "none" : fillColor(true).svgColorString()); - actions.appendToPage(std::move(elem)); + actions.svgTree().appendToPage(std::move(elem)); double pw = _penwidth/2.0; actions.embed(BoundingBox(cx-rx-pw, cy-ry-pw, cx+rx+pw, cy+ry+pw)); } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/TriangularPatch.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/TriangularPatch.cpp index 4f9a4a1f58e..01efe2e8f0d 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/TriangularPatch.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/TriangularPatch.cpp @@ -31,7 +31,7 @@ TriangularPatch::TriangularPatch (const PointVec &points, const ColorVec &colors void TriangularPatch::setPoints (const PointVec &points, int edgeflag, ShadingPatch *patch) { - TriangularPatch *triangularPatch = dynamic_cast<TriangularPatch*>(patch); + auto triangularPatch = dynamic_cast<TriangularPatch*>(patch); if (edgeflag > 0 && !triangularPatch) throw ShadingException("missing preceding data in definition of triangular patch"); if ((edgeflag == 0 && points.size() != 3) || (edgeflag > 0 && points.size() != 1)) @@ -62,7 +62,7 @@ void TriangularPatch::setPoints (const DPair &p1, const DPair &p2, const DPair & void TriangularPatch::setColors (const ColorVec &colors, int edgeflag, ShadingPatch *patch) { - TriangularPatch *triangularPatch = dynamic_cast<TriangularPatch*>(patch); + auto triangularPatch = dynamic_cast<TriangularPatch*>(patch); if (edgeflag > 0 && !triangularPatch) throw ShadingException("missing preceding data in definition of triangular patch"); if ((edgeflag == 0 && colors.size() != 3) || (edgeflag > 0 && colors.size() != 1)) @@ -161,8 +161,7 @@ static inline double snap (double x) { * @param[in] callback object notified */ void TriangularPatch::approximate (int gridsize, bool overlap, double delta, Callback &callback) const { if (_colors[0] == _colors[1] && _colors[1] == _colors[2]) { - GraphicsPath<double> path; - getBoundaryPath(path); + GraphicsPath<double> path = getBoundaryPath(); callback.patchSegment(path, _colors[0]); } else { @@ -197,18 +196,21 @@ void TriangularPatch::approximate (int gridsize, bool overlap, double delta, Cal } -void TriangularPatch::getBoundaryPath(GraphicsPath<double> &path) const { +GraphicsPath<double> TriangularPatch::getBoundaryPath () const { + GraphicsPath<double> path; path.clear(); path.moveto(_points[0]); path.lineto(_points[1]); path.lineto(_points[2]); path.closepath(); + return path; } -void TriangularPatch::getBBox (BoundingBox &bbox) const { - bbox.invalidate(); +BoundingBox TriangularPatch::getBBox () const { + BoundingBox bbox; bbox.embed(_points[0]); bbox.embed(_points[1]); bbox.embed(_points[2]); + return bbox; } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/TriangularPatch.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/TriangularPatch.hpp index 3ad189aff88..d329e43fa1a 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/TriangularPatch.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/TriangularPatch.hpp @@ -25,11 +25,10 @@ #include "Pair.hpp" #include "ShadingPatch.hpp" -class TriangularPatch : public ShadingPatch -{ +class TriangularPatch : public ShadingPatch { public: TriangularPatch (); - TriangularPatch (Color::ColorSpace cspace) : ShadingPatch(cspace) {} + explicit TriangularPatch (Color::ColorSpace cspace) : ShadingPatch(cspace) {} TriangularPatch (const PointVec &points, const ColorVec &colors, Color::ColorSpace cspace, int edgeflag, TriangularPatch *patch); int psShadingType() const override {return 4;} DPair valueAt (double u, double v) const; @@ -40,8 +39,8 @@ class TriangularPatch : public ShadingPatch void setColors (const ColorVec &colors, int edgeflag, ShadingPatch *patch) override; void setColors (const Color &c1, const Color &c2, const Color &c3); void approximate (int gridsize, bool overlap, double delta, Callback &listener) const override; - void getBBox (BoundingBox &bbox) const override; - void getBoundaryPath(GraphicsPath<double> &path) const override; + BoundingBox getBBox () const override; + GraphicsPath<double> getBoundaryPath () const override; int numPoints (int edgeflag) const override {return edgeflag == 0 ? 3 : 1;} int numColors (int edgeflag) const override {return edgeflag == 0 ? 3 : 1;} @@ -54,10 +53,9 @@ class TriangularPatch : public ShadingPatch }; -class LatticeTriangularPatch : public TriangularPatch -{ +class LatticeTriangularPatch : public TriangularPatch { public: - LatticeTriangularPatch (Color::ColorSpace cspace) : TriangularPatch(cspace) {} + explicit LatticeTriangularPatch (Color::ColorSpace cspace) : TriangularPatch(cspace) {} int psShadingType() const override {return 5;} }; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/TrueTypeFont.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/TrueTypeFont.cpp index 2cbb77bac51..408a00eede2 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/TrueTypeFont.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/TrueTypeFont.cpp @@ -127,7 +127,7 @@ void TrueTypeFont::writeWOFF (ostream &os) const { void TrueTypeFont::writeWOFF (const string &fname) const { - ofstream ofs(fname.c_str(), ios::binary); + ofstream ofs(fname, ios::binary); writeWOFF(ofs); } @@ -136,10 +136,10 @@ void TrueTypeFont::writeWOFF (const string &fname) const { * @param[out] os stream to write the WOFF2 data to * @return true on success */ bool TrueTypeFont::writeWOFF2 (ostream &os) const { - const uint8_t* input_data = reinterpret_cast<const uint8_t*>(_buffer.data()); + auto input_data = reinterpret_cast<const uint8_t*>(_buffer.data()); size_t output_size = woff2::MaxWOFF2CompressedSize(input_data, _buffer.size()); string output(output_size, 0); - uint8_t* output_data = reinterpret_cast<uint8_t*>(&output[0]); + auto output_data = reinterpret_cast<uint8_t*>(&output[0]); woff2::WOFF2Params params; if (woff2::ConvertTTFToWOFF2(input_data, _buffer.size(), output_data, &output_size, params)) { output.resize(output_size); @@ -151,7 +151,7 @@ bool TrueTypeFont::writeWOFF2 (ostream &os) const { bool TrueTypeFont::writeWOFF2 (const string &fname) const { - ofstream ofs(fname.c_str(), ios::binary); + ofstream ofs(fname, ios::binary); return writeWOFF2(ofs); } @@ -167,9 +167,9 @@ string TrueTypeFont::TTFTableRecord::name () const { uint32_t TrueTypeFont::TTFTableRecord::computeChecksum () const { uint32_t sum=0; - const uint32_t *startptr = reinterpret_cast<const uint32_t*>(data); - const uint32_t *endptr = startptr + paddedSize()/sizeof(uint32_t); + auto startptr = reinterpret_cast<const uint32_t*>(data); + auto endptr = startptr + paddedSize()/sizeof(uint32_t); while (startptr < endptr) sum += *startptr++; return sum; -}
\ No newline at end of file +} diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/TrueTypeFont.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/TrueTypeFont.hpp index 67a90be3ffb..d2e5b6e98d4 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/TrueTypeFont.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/TrueTypeFont.hpp @@ -53,7 +53,7 @@ class TrueTypeFont { public: TrueTypeFont () : _version(0) {} - TrueTypeFont (const std::string &fname) {read(fname);} + explicit TrueTypeFont (const std::string &fname) {read(fname);} bool read (const std::string &fname); void writeWOFF (std::ostream &os) const; void writeWOFF (const std::string &fname) const; @@ -68,7 +68,7 @@ class TrueTypeFont { struct TrueTypeFontException : public MessageException { - TrueTypeFontException (const std::string &msg) : MessageException(msg) {} + explicit TrueTypeFontException (const std::string &msg) : MessageException(msg) {} }; #endif diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/Unicode.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/Unicode.cpp index ab17d48fa90..d4a18a7bb96 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/Unicode.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/Unicode.cpp @@ -92,21 +92,21 @@ string Unicode::utf8 (int32_t cp) { string utf8; if (cp >= 0) { if (cp < 0x80) - utf8 += cp; + utf8 += char(cp); else if (cp < 0x800) { - utf8 += 0xC0 + (cp >> 6); - utf8 += 0x80 + (cp & 0x3F); + utf8 += char(0xC0 + (cp >> 6)); + utf8 += char(0x80 + (cp & 0x3F)); } else if (cp < 0x10000) { - utf8 += 0xE0 + (cp >> 12); - utf8 += 0x80 + ((cp >> 6) & 0x3F); - utf8 += 0x80 + (cp & 0x3F); + utf8 += char(0xE0 + (cp >> 12)); + utf8 += char(0x80 + ((cp >> 6) & 0x3F)); + utf8 += char(0x80 + (cp & 0x3F)); } else if (cp < 0x110000) { - utf8 += 0xF0 + (cp >> 18); - utf8 += 0x80 + ((cp >> 12) & 0x3F); - utf8 += 0x80 + ((cp >> 6) & 0x3F); - utf8 += 0x80 + (cp & 0x3F); + utf8 += char(0xF0 + (cp >> 18)); + utf8 += char(0x80 + ((cp >> 12) & 0x3F)); + utf8 += char(0x80 + ((cp >> 6) & 0x3F)); + utf8 += char(0x80 + (cp & 0x3F)); } // UTF-8 does not support codepoints >= 0x110000 } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/VFReader.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/VFReader.cpp index df150d0a511..cff67c919c1 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/VFReader.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/VFReader.cpp @@ -28,12 +28,8 @@ using namespace std; -VFReader::VFReader (istream &is) - : StreamReader(is), _actions(0), _designSize(0) { -} - - -VFReader::~VFReader () { +VFReader::VFReader (istream &is) : StreamReader(is) +{ } @@ -57,7 +53,7 @@ int VFReader::executeCommand (ApproveAction approve) { bool approved = !approve || approve(opcode); VFActions *actions = _actions; if (!approved) - replaceActions(0); // disable actions + replaceActions(nullptr); // disable actions if (opcode <= 241) // short character definition? cmdShortChar(opcode); @@ -70,9 +66,7 @@ int VFReader::executeCommand (ApproveAction approve) { case 248: cmdPost(); break; // postamble default : { // invalid opcode replaceActions(actions); // reenable actions - ostringstream oss; - oss << "undefined VF command (opcode " << opcode << ')'; - throw VFException(oss.str()); + throw VFException("undefined VF command (opcode " + std::to_string(opcode) + ")"); } } } @@ -143,8 +137,7 @@ void VFReader::cmdLongChar () { else { uint32_t cc = readUnsigned(4); // character code readUnsigned(4); // equals character width from corresponding TFM file - vector<uint8_t> dvi(pl); // DVI subroutine - readBytes(pl, dvi); + auto dvi = readBytes(pl); // DVI subroutine _actions->defineVFChar(cc, std::move(dvi)); // call template method for user actions } } @@ -158,8 +151,7 @@ void VFReader::cmdShortChar (int pl) { else { uint32_t cc = readUnsigned(1); // character code readUnsigned(3); // character width from corresponding TFM file - vector<uint8_t> dvi(pl); // DVI subroutine - readBytes(pl, dvi); + auto dvi = readBytes(pl); // DVI subroutine _actions->defineVFChar(cc, std::move(dvi)); // call template method for user actions } } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/VFReader.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/VFReader.hpp index 00da32bbfdc..8ddba805e8f 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/VFReader.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/VFReader.hpp @@ -25,28 +25,23 @@ #include "StreamReader.hpp" -struct VFException : public MessageException -{ - VFException (const std::string &msg) : MessageException(msg) {} +struct VFException : public MessageException { + explicit VFException (const std::string &msg) : MessageException(msg) {} }; - struct VFActions; - -class VFReader : public StreamReader -{ +class VFReader : public StreamReader{ using ApproveAction = bool (*)(int); public: - VFReader (std::istream &is); - virtual ~VFReader (); + explicit VFReader (std::istream &is); VFActions* replaceActions (VFActions *a); bool executeAll (); bool executePreambleAndFontDefs (); bool executeCharDefs (); protected: - int executeCommand (ApproveAction approve=0); + int executeCommand (ApproveAction approve=nullptr); // the following methods represent the VF commands // they are called by executeCommand and should not be used directly @@ -57,8 +52,8 @@ class VFReader : public StreamReader void cmdFontDef (int len); private: - VFActions *_actions; ///< actions to execute when reading a VF command - double _designSize; ///< design size of currently read VF in PS points + VFActions *_actions=nullptr; ///< actions to execute when reading a VF command + double _designSize=0; ///< design size of currently read VF in PS points }; #endif diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/VectorIterator.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/VectorIterator.hpp index d5615eafb35..17707fbc965 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/VectorIterator.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/VectorIterator.hpp @@ -25,17 +25,15 @@ #include "MessageException.hpp" -struct IteratorException : public MessageException -{ - IteratorException (const std::string &msg) : MessageException(msg) {} +struct IteratorException : public MessageException { + explicit IteratorException (const std::string &msg) : MessageException(msg) {} }; template <typename T> -class VectorIterator -{ +class VectorIterator { public: - VectorIterator (std::vector<T> &vec) : _vector(vec), _pos(0) {} + explicit VectorIterator (std::vector<T> &vec) : _vector(vec), _pos(0) {} VectorIterator operator ++ () { _pos++; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/VectorStream.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/VectorStream.hpp index ddf9aa5985a..c74388e076b 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/VectorStream.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/VectorStream.hpp @@ -25,10 +25,9 @@ #include <vector> template <typename T> -class VectorStreamBuffer : public std::streambuf -{ +class VectorStreamBuffer : public std::streambuf { public: - VectorStreamBuffer (const std::vector<T> &v) { + explicit VectorStreamBuffer (const std::vector<T> &v) { if (v.empty()) _begin = _end = _curr = nullptr; else { @@ -76,10 +75,9 @@ class VectorStreamBuffer : public std::streambuf template <typename T> -class VectorInputStream : public std::istream -{ +class VectorInputStream : public std::istream { public: - VectorInputStream (const std::vector<T> &source) : std::istream(&_buf), _buf(source) {} + explicit VectorInputStream (const std::vector<T> &source) : std::istream(&_buf), _buf(source) {} private: VectorStreamBuffer<T> _buf; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLDocument.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLDocument.cpp index 66ef7e612c9..be14eaf6786 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLDocument.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLDocument.cpp @@ -22,7 +22,7 @@ using namespace std; -XMLDocument::XMLDocument (unique_ptr<XMLElementNode> &&root) +XMLDocument::XMLDocument (unique_ptr<XMLElement> root) : _rootElement(std::move(root)) { } @@ -34,17 +34,17 @@ void XMLDocument::clear () { } -void XMLDocument::append (unique_ptr<XMLNode> &&node) { +void XMLDocument::append (unique_ptr<XMLNode> node) { if (node) { - if (dynamic_cast<XMLElementNode*>(node.get())) - _rootElement = util::static_unique_ptr_cast<XMLElementNode>(std::move(node)); + if (node->toElement()) + _rootElement = util::static_unique_ptr_cast<XMLElement>(std::move(node)); else _nodes.emplace_back(std::move(node)); } } -void XMLDocument::setRootNode (unique_ptr<XMLElementNode> &&root) { +void XMLDocument::setRootNode (unique_ptr<XMLElement> root) { _rootElement = std::move(root); } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLDocument.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLDocument.hpp index 0e5dc6a6ee3..e9132c44d8f 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLDocument.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLDocument.hpp @@ -28,17 +28,17 @@ class XMLDocument { public: XMLDocument () =default; - XMLDocument (std::unique_ptr<XMLElementNode> &&root); + explicit XMLDocument(std::unique_ptr<XMLElement> root); void clear (); - void append (std::unique_ptr<XMLElementNode> &&node); - void append (std::unique_ptr<XMLNode> &&node); - void setRootNode (std::unique_ptr<XMLElementNode> &&root); - const XMLElementNode* getRootElement () const {return _rootElement.get();} + void append (std::unique_ptr<XMLElement> node); + void append (std::unique_ptr<XMLNode> node); + void setRootNode (std::unique_ptr<XMLElement> root); + const XMLElement* getRootElement () const {return _rootElement.get();} std::ostream& write (std::ostream &os) const; private: std::vector<std::unique_ptr<XMLNode>> _nodes; - std::unique_ptr<XMLElementNode> _rootElement; + std::unique_ptr<XMLElement> _rootElement; }; #endif diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLNode.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLNode.cpp index e0598c4956a..128be5b9e51 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLNode.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLNode.cpp @@ -28,32 +28,71 @@ using namespace std; +bool XMLElement::WRITE_NEWLINES=true; -XMLElementNode::XMLElementNode (const string &n) : _name(n) { + +/** Inserts a sibling node after this one. + * @param[in] node node to insert + * @return raw pointer to inserted node */ +XMLNode* XMLNode::insertNext (unique_ptr<XMLNode> node) { + if (_next) { + _next->_prev = node.get(); + node->_next = std::move(_next); + } + node->_prev = this; + node->_parent = _parent; + _next = std::move(node); + return _next.get(); } -XMLElementNode::XMLElementNode (const XMLElementNode &node) - : _name(node._name), _attributes(node._attributes) +/** Removes the following sibling node of this one. + * @return pointer to the removed node */ +unique_ptr<XMLNode> XMLNode::removeNext () { + unique_ptr<XMLNode> oldnext = std::move(_next); + if (oldnext) { + oldnext->_parent = oldnext->_prev = nullptr; + if ((_next = std::move(oldnext->_next))) { + _next->_prev = this; + oldnext->_next.reset(); + } + } + return oldnext; +} + +///////////////////////////////////////////////////////////////////// + +XMLElement::XMLElement (string name) : _name(std::move(name)) { +} + + +XMLElement::XMLElement (const XMLElement &node) + : XMLNode(node), _name(node._name), _attributes(node._attributes) { - for (const auto &child : node._children) - _children.emplace_back(unique_ptr<XMLNode>(child->clone())); + for (XMLNode *child=_firstChild.get(); child; child = child->next()) + insertLast(child->clone()); } -XMLElementNode::XMLElementNode (XMLElementNode &&node) - : _name(std::move(node._name)), _attributes(std::move(node._attributes)), _children(std::move(node._children)) +XMLElement::XMLElement (XMLElement &&node) noexcept + : XMLNode(std::move(node)), + _name(std::move(node._name)), + _attributes(std::move(node._attributes)), + _firstChild(std::move(node._firstChild)), + _lastChild(node._lastChild) { } -void XMLElementNode::clear () { +/** Removes all attributes and children. */ +void XMLElement::clear () { _attributes.clear(); - _children.clear(); + _firstChild.reset(); + _lastChild = nullptr; } -void XMLElementNode::addAttribute (const string &name, const string &value) { +void XMLElement::addAttribute (const string &name, const string &value) { if (Attribute *attr = getAttribute(name)) attr->value = value; else @@ -61,27 +100,66 @@ void XMLElementNode::addAttribute (const string &name, const string &value) { } -void XMLElementNode::addAttribute (const string &name, double value) { +void XMLElement::addAttribute (const string &name, double value) { addAttribute(name, XMLString(value)); } +void XMLElement::removeAttribute (const std::string &name) { + _attributes.erase(find_if(_attributes.begin(), _attributes.end(), [&](const Attribute &attr) { + return attr.name == name; + })); +} + + +/** Inserts a new last child node and returns a raw pointer to it. */ +XMLNode* XMLElement::insertLast (unique_ptr<XMLNode> child) { + if (!child) + return nullptr; + child->parent(this); + if (!empty()) + _lastChild = _lastChild->insertNext(std::move(child)); + else { + _firstChild = std::move(child); + _lastChild = _firstChild.get(); + } + return _lastChild; +} + + +/** Inserts a new first child node and returns a raw pointer to it. */ +XMLNode* XMLElement::insertFirst (unique_ptr<XMLNode> child) { + if (!child) + return nullptr; + child->parent(this); + if (empty()) { + _firstChild = std::move(child); + _lastChild = _firstChild.get(); + } + else { + child->insertNext(std::move(_firstChild)); + _firstChild = std::move(child); + } + return _firstChild.get(); +} + + /** Appends a child node to this element. The element also takes the ownership of the child. * @param[in] child node to be appended * @return raw pointer to the appended child node */ -XMLNode* XMLElementNode::append (unique_ptr<XMLNode> &&child) { +XMLNode* XMLElement::append (unique_ptr<XMLNode> child) { if (!child) return nullptr; - XMLTextNode *textNode1 = dynamic_cast<XMLTextNode*>(child.get()); - if (!textNode1 || _children.empty()) - _children.emplace_back(std::move(child)); + XMLText *textNode1 = child->toText(); + if (!textNode1 || empty()) + insertLast(std::move(child)); else { - if (XMLTextNode *textNode2 = dynamic_cast<XMLTextNode*>(_children.back().get())) - textNode2->append(util::static_unique_ptr_cast<XMLTextNode>(std::move(child))); // merge two consecutive text nodes + if (XMLText *textNode2 = _lastChild->toText()) + textNode2->append(util::static_unique_ptr_cast<XMLText>(std::move(child))); // merge two consecutive text nodes else - _children.emplace_back(std::move(child)); + insertLast(std::move(child)); } - return _children.back().get(); + return _lastChild; } @@ -89,30 +167,31 @@ XMLNode* XMLElementNode::append (unique_ptr<XMLNode> &&child) { * appended there, otherwise a new text node is created. * @param[in] str string to be appended * @return raw pointer to the text node the string was appended to */ -XMLNode* XMLElementNode::append (const string &str) { - if (_children.empty() || !dynamic_cast<XMLTextNode*>(_children.back().get())) - _children.emplace_back(util::make_unique<XMLTextNode>(str)); +XMLNode* XMLElement::append (const string &str) { + XMLText *last; + if (!empty() && (last = _lastChild->toText())) + last->append(str); else - static_cast<XMLTextNode*>(_children.back().get())->append(str); - return _children.back().get(); + insertLast(util::make_unique<XMLText>(str)); + return _lastChild; } /** Prepends a child node to this element. The element also takes the ownership of the child. * @param[in] child node to be prepended * @return raw pointer to the prepended child node */ -XMLNode* XMLElementNode::prepend (unique_ptr<XMLNode> &&child) { +XMLNode* XMLElement::prepend (unique_ptr<XMLNode> child) { if (!child) return nullptr; - XMLTextNode *textNode1 = dynamic_cast<XMLTextNode*>(child.get()); - if (textNode1 && !_children.empty()) { - if (XMLTextNode *textNode2 = dynamic_cast<XMLTextNode*>(_children.front().get())) { - textNode2->prepend(util::static_unique_ptr_cast<XMLTextNode>(std::move(child))); // merge two consecutive text nodes + XMLText *textNode1 = child->toText(); + if (textNode1 && !empty()) { + if (XMLText *textNode2 = _firstChild->toText()) { + textNode2->prepend(util::static_unique_ptr_cast<XMLText>(std::move(child))); // merge two consecutive text nodes return textNode2; } } - _children.emplace_front(std::move(child)); - return _children.front().get(); + insertFirst(std::move(child)); + return _firstChild.get(); } @@ -121,15 +200,15 @@ XMLNode* XMLElementNode::prepend (unique_ptr<XMLNode> &&child) { * node present, nothing is inserted. * @param[in] child node to be inserted * @param[in] sibling following sibling of 'child' - * @return true on success */ -bool XMLElementNode::insertBefore (unique_ptr<XMLNode> &&child, XMLNode *sibling) { - auto it = _children.begin(); - while (it != _children.end() && it->get() != sibling) - ++it; - if (it == _children.end()) - return false; - _children.emplace(it, std::move(child)); - return true; + * @return raw pointer to inserted node */ +XMLNode* XMLElement::insertBefore (unique_ptr<XMLNode> child, XMLNode *sibling) { + if (!child || (sibling && sibling->parent() != this)) + return nullptr; + if (!sibling) + return insertLast(std::move(child)); + if (sibling == _firstChild.get()) + return insertFirst(std::move(child)); + return sibling->prev()->insertNext(std::move(child)); } @@ -138,25 +217,93 @@ bool XMLElementNode::insertBefore (unique_ptr<XMLNode> &&child, XMLNode *sibling * node present, nothing is inserted. * @param[in] child node to be inserted * @param[in] sibling preceding sibling of 'child' - * @return true on success */ -bool XMLElementNode::insertAfter (unique_ptr<XMLNode> &&child, XMLNode *sibling) { - auto it = _children.begin(); - while (it != _children.end() && it->get() != sibling) - ++it; - if (it == _children.end()) - return false; - _children.emplace(++it, std::move(child)); - return true; -} - - -/** Removes a given child from the element. */ -void XMLElementNode::remove (const XMLNode *child) { - auto it = find_if(_children.begin(), _children.end(), [=](const unique_ptr<XMLNode> &ptr) { - return ptr.get() == child; - }); - if (it != _children.end()) - _children.erase(it); + * @return raw pointer to inserted node */ +XMLNode* XMLElement::insertAfter (unique_ptr<XMLNode> child, XMLNode *sibling) { + if (!child || (sibling && sibling->parent() != this)) + return nullptr; + if (!sibling) + return insertFirst(std::move(child)); + if (sibling == _lastChild) + return insertLast(std::move(child)); + return sibling->insertNext(std::move(child)); +} + + +/** Moves a sequence of child nodes to a new element of a given name and inserts + * this (wrapper) element at the former position of the first node of the sequence. + * Example: wrap 3 child nodes of element a with b: + * <a>text1<c/>text2<d/></a> => <a>text1<b><c/>text2<d/></b></a> + * @param[in] first first node to wrap + * @param[in] last last node to wrap (or nullptr if all following siblings of 'first' are to be wrapped) + * @param[in] name name of the wrapper element to be created + * @return raw pointer to the new wrapper element */ +XMLElement* XMLElement::wrap (XMLNode *first, XMLNode *last, const string &name) { + if (!first || !first->parent() || (last && first->parent() != last->parent())) + return nullptr; + XMLElement *parent = first->parent()->toElement(); + XMLNode *prev = first->prev(); + auto wrapper = util::make_unique<XMLElement>(name); + if (last) + last = last->next(); + XMLNode *child = first; + while (child && child != last) { + XMLNode *next = child->next(); + wrapper->insertLast(remove(child)); + child = next; + } + XMLElement *ret = wrapper.get(); + if (prev) + parent->insertAfter(std::move(wrapper), prev); + else + parent->insertFirst(std::move(wrapper)); + return ret; +} + + +/** Moves all child nodes C1,...,Cn of a given element E to its parent and + * removes E afterwards, so that C1 is located at the former position of E + * followed by C2,...,Cn. + * Example: unwrap a child element b of a: + * <a>text1<b><c/>text2<d/></b></a> => <a>text1<c/>text2<d/></a> + * @param[in] child child element to unwrap + * @return raw pointer to the first node C1 of the unwrapped sequence */ +XMLNode* XMLElement::unwrap (XMLElement *child) { + if (!child || !child->parent()) + return nullptr; + XMLElement *parent = child->parent()->toElement(); + auto removedChild = remove(child); + if (child->empty()) + return child->next(); + XMLNode *firstGrandchild = child->firstChild(); + XMLNode *prev = child->prev(); + unique_ptr<XMLNode> grandchild = std::move(child->_firstChild); + while (grandchild) { + prev = parent->insertAfter(std::move(grandchild), prev); + grandchild = std::move(prev->_next); + } + return firstGrandchild; +} + + +/** Removes a child node from the element. + * @param[in] child pointer to child to remove + * @return pointer to removed child or nullptr if given child doesn't belong to this element */ +unique_ptr<XMLNode> XMLElement::remove (XMLNode *child) { + unique_ptr<XMLNode> node; + if (child && child->parent()) { + XMLElement *parent = child->parent()->toElement(); + if (child == parent->_lastChild) + parent->_lastChild = child->prev(); + if (child != parent->firstChild()) + node = child->prev()->removeNext(); + else { + node = std::move(parent->_firstChild); + if ((parent->_firstChild = std::move(node->_next))) + parent->_firstChild->prev(nullptr); + } + child->parent(nullptr); + } + return node; } @@ -165,10 +312,10 @@ void XMLElementNode::remove (const XMLNode *child) { * @param[in] attrName name of attribute to find * @param[out] descendants all elements found * @return true if at least one element was found */ -bool XMLElementNode::getDescendants (const char *name, const char *attrName, vector<XMLElementNode*> &descendants) const { - for (auto &child : _children) { - if (XMLElementNode *elem = dynamic_cast<XMLElementNode*>(child.get())) { - if ((!name || elem->getName() == name) && (!attrName || elem->hasAttribute(attrName))) +bool XMLElement::getDescendants (const char *name, const char *attrName, vector<XMLElement*> &descendants) const { + for (XMLNode *child = _firstChild.get(); child; child = child->next()) { + if (XMLElement *elem = child->toElement()) { + if ((!name || elem->name() == name) && (!attrName || elem->hasAttribute(attrName))) descendants.push_back(elem); elem->getDescendants(name, attrName, descendants); } @@ -182,15 +329,15 @@ bool XMLElementNode::getDescendants (const char *name, const char *attrName, vec * @param[in] attrName if not 0, only elements with an attribute of this name are considered * @param[in] attrValue if not 0, only elements with attribute attrName="attrValue" are considered * @return pointer to the found element or 0 */ -XMLElementNode* XMLElementNode::getFirstDescendant (const char *name, const char *attrName, const char *attrValue) const { - for (auto &child : _children) { - if (XMLElementNode *elem = dynamic_cast<XMLElementNode*>(child.get())) { - if (!name || elem->getName() == name) { +XMLElement* XMLElement::getFirstDescendant (const char *name, const char *attrName, const char *attrValue) const { + for (XMLNode *child = _firstChild.get(); child; child = child->next()) { + if (XMLElement *elem = child->toElement()) { + if (!name || elem->name() == name) { const char *value; - if (!attrName || (((value = elem->getAttributeValue(attrName)) != 0) && (!attrValue || string(value) == attrValue))) + if (!attrName || (((value = elem->getAttributeValue(attrName)) != nullptr) && (!attrValue || string(value) == attrValue))) return elem; } - if (XMLElementNode *descendant = elem->getFirstDescendant(name, attrName, attrValue)) + if (XMLElement *descendant = elem->getFirstDescendant(name, attrName, attrValue)) return descendant; } } @@ -198,23 +345,22 @@ XMLElementNode* XMLElementNode::getFirstDescendant (const char *name, const char } -ostream& XMLElementNode::write (ostream &os) const { +ostream& XMLElement::write (ostream &os) const { os << '<' << _name; for (const auto &attrib : _attributes) os << ' ' << attrib.name << "='" << attrib.value << '\''; - if (_children.empty()) + if (empty()) os << "/>"; else { os << '>'; // Insert newlines around children except text nodes. According to the // SVG specification, pure whitespace nodes are ignored by the SVG renderer. - if (!dynamic_cast<XMLTextNode*>(_children.front().get())) + if (WRITE_NEWLINES && !_firstChild->toText()) os << '\n'; - for (auto it=_children.begin(); it != _children.end(); ++it) { - (*it)->write(os); - if (!dynamic_cast<XMLTextNode*>(it->get())) { - auto next=it; - if (++next == _children.end() || !dynamic_cast<XMLTextNode*>(next->get())) + for (XMLNode *child = _firstChild.get(); child; child = child->next()) { + child->write(os); + if (!child->toText()) { + if (WRITE_NEWLINES && (!child->next() || !child->next()->toText())) os << '\n'; } } @@ -225,7 +371,7 @@ ostream& XMLElementNode::write (ostream &os) const { /** Returns true if this element has an attribute of given name. */ -bool XMLElementNode::hasAttribute (const string &name) const { +bool XMLElement::hasAttribute (const string &name) const { return getAttribute(name) != nullptr; } @@ -233,14 +379,14 @@ bool XMLElementNode::hasAttribute (const string &name) const { /** Returns the value of an attribute. * @param[in] name name of attribute * @return attribute value or 0 if attribute doesn't exist */ -const char* XMLElementNode::getAttributeValue (const std::string& name) const { +const char* XMLElement::getAttributeValue (const std::string& name) const { if (const Attribute *attr = getAttribute(name)) return attr->value.c_str(); return nullptr; } -XMLElementNode::Attribute* XMLElementNode::getAttribute (const string &name) { +XMLElement::Attribute* XMLElement::getAttribute (const string &name) { auto it = find_if(_attributes.begin(), _attributes.end(), [&](const Attribute &attr) { return attr.name == name; }); @@ -248,7 +394,7 @@ XMLElementNode::Attribute* XMLElementNode::getAttribute (const string &name) { } -const XMLElementNode::Attribute* XMLElementNode::getAttribute (const string &name) const { +const XMLElement::Attribute* XMLElement::getAttribute (const string &name) const { auto it = find_if(_attributes.begin(), _attributes.end(), [&](const Attribute &attr) { return attr.name == name; }); @@ -258,11 +404,11 @@ const XMLElementNode::Attribute* XMLElementNode::getAttribute (const string &nam ////////////////////// -void XMLTextNode::append (unique_ptr<XMLNode> &&node) { +void XMLText::append (unique_ptr<XMLNode> node) { if (!node) return; - if (dynamic_cast<XMLTextNode*>(node.get())) - append(util::static_unique_ptr_cast<XMLTextNode>(std::move(node))); + if (node->toText()) + append(util::static_unique_ptr_cast<XMLText>(std::move(node))); else { // append text representation of the node ostringstream oss; @@ -272,32 +418,37 @@ void XMLTextNode::append (unique_ptr<XMLNode> &&node) { } -void XMLTextNode::append (unique_ptr<XMLTextNode> &&node) { +void XMLText::append (unique_ptr<XMLText> node) { if (node) _text += node->_text; } -void XMLTextNode::append (const string &str) { +void XMLText::append (const string &str) { _text += str; } -void XMLTextNode::prepend (unique_ptr<XMLNode> &&node) { - if (XMLTextNode *textNode = dynamic_cast<XMLTextNode*>(node.get())) +void XMLText::prepend (unique_ptr<XMLNode> node) { + if (XMLText *textNode = node->toText()) _text = textNode->_text + _text; } + +const XMLText* XMLText::toWSNode () const { + return _text.find_first_not_of(" \t\n\r") == string::npos ? this : nullptr; +} + ///////////////////////////////////////////////////////////////////// -ostream& XMLCDataNode::write (ostream &os) const { +ostream& XMLCData::write (ostream &os) const { if (!_data.empty()) - os << "<![CDATA[\n" << _data << "]]>"; + os << "<![CDATA[" << _data << "]]>"; return os; } -void XMLCDataNode::append (string &&str) { +void XMLCData::append (string &&str) { if (_data.empty()) _data = move(str); else diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLNode.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLNode.hpp index b9a75fa0588..b4e5ed6f2b4 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLNode.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLNode.hpp @@ -29,107 +29,198 @@ #include <vector> #include "utility.hpp" +class XMLCData; +class XMLComment; +class XMLElement; +class XMLText; class XMLNode { + friend class XMLElement; + + template <typename T> + T* cast (const T* (XMLNode::*func)() const) { + return const_cast<T*>((const_cast<const XMLNode*>(this)->*func)()); + } + public: + XMLNode () =default; + XMLNode (const XMLNode &node) : _next(nullptr) {} + XMLNode (XMLNode &&node) noexcept : _parent(node._parent), _prev(node._prev), _next(std::move(node._next)) {} virtual ~XMLNode () =default; virtual std::unique_ptr<XMLNode> clone () const =0; virtual void clear () =0; virtual std::ostream& write (std::ostream &os) const =0; + virtual const XMLElement* toElement () const {return nullptr;} + virtual const XMLText* toText () const {return nullptr;} + virtual const XMLText* toWSNode () const {return nullptr;} + virtual const XMLComment* toComment () const {return nullptr;} + virtual const XMLCData* toCData () const {return nullptr;} + XMLElement* toElement () {return cast<XMLElement>(&XMLNode::toElement);} + XMLText* toText () {return cast<XMLText>(&XMLNode::toText);} + XMLComment* toComment () {return cast<XMLComment>(&XMLNode::toComment);} + XMLCData* toCData () {return cast<XMLCData>(&XMLNode::toCData);} + XMLNode* parent () const {return _parent;} + XMLNode* prev () const {return _prev;} + XMLNode* next () const {return _next.get();} + + protected: + XMLNode* insertNext (std::unique_ptr<XMLNode> node); + std::unique_ptr<XMLNode> removeNext (); + void parent (XMLNode *p) {_parent = p;} + void prev (XMLNode *p) {_prev = p;} + + private: + XMLNode *_parent=nullptr; ///< pointer to parent node + XMLNode *_prev=nullptr; ///< pointer to preceding sibling + std::unique_ptr<XMLNode> _next; ///< pointer to next sibling (incl. ownership) +}; + + +class XMLNodeIterator { + public: + XMLNodeIterator () =default; + explicit XMLNodeIterator (XMLNode *curr) : _curr(curr) {} + XMLNodeIterator& operator ++ () {_curr = _curr->next(); return *this;} + XMLNodeIterator& operator -- () {_curr = _curr->prev(); return *this;} + XMLNodeIterator operator ++ (int) {auto p=_curr; _curr = _curr->next(); return XMLNodeIterator(p);} + XMLNodeIterator operator -- (int) {auto p=_curr; _curr = _curr->prev(); return XMLNodeIterator(p);} + XMLNode* operator * () {return _curr;} + XMLNode& operator -> () {return *_curr;} + bool operator == (const XMLNodeIterator &it) const {return _curr == it._curr;} + bool operator != (const XMLNodeIterator &it) const {return _curr != it._curr;} + + private: + XMLNode *_curr=nullptr; }; -class XMLElementNode : public XMLNode { +class ConstXMLNodeIterator { + public: + ConstXMLNodeIterator () =default; + explicit ConstXMLNodeIterator (const XMLNode *curr) : _curr(curr) {} + ConstXMLNodeIterator& operator ++ () {_curr = _curr->next(); return *this;} + ConstXMLNodeIterator& operator -- () {_curr = _curr->prev(); return *this;} + ConstXMLNodeIterator operator ++ (int) {auto p=_curr; _curr = _curr->next(); return ConstXMLNodeIterator(p);} + ConstXMLNodeIterator operator -- (int) {auto p=_curr; _curr = _curr->prev(); return ConstXMLNodeIterator(p);} + const XMLNode* operator * () {return _curr;} + const XMLNode& operator -> () {return *_curr;} + bool operator == (const ConstXMLNodeIterator &it) const {return _curr == it._curr;} + bool operator != (const ConstXMLNodeIterator &it) const {return _curr != it._curr;} + + private: + const XMLNode *_curr=nullptr; +}; + + +class XMLElement : public XMLNode { public: struct Attribute { - Attribute (const std::string &nam, const std::string &val) : name(nam), value(val) {} + Attribute (std::string nam, std::string val) : name(std::move(nam)), value(std::move(val)) {} std::string name; std::string value; }; - using ChildList = std::deque<std::unique_ptr<XMLNode>>; + using Attributes = std::vector<Attribute>; + static bool WRITE_NEWLINES; ///< insert line breaks after element tags? public: - XMLElementNode (const std::string &name); - XMLElementNode (const XMLElementNode &node); - XMLElementNode (XMLElementNode &&node); - std::unique_ptr<XMLNode> clone () const override {return util::make_unique<XMLElementNode>(*this);} + explicit XMLElement (std::string name); + XMLElement (const XMLElement &node); + XMLElement (XMLElement &&node) noexcept; + std::unique_ptr<XMLNode> clone () const override {return util::make_unique<XMLElement>(*this);} void clear () override; void addAttribute (const std::string &name, const std::string &value); void addAttribute (const std::string &name, double value); - XMLNode* append (std::unique_ptr<XMLNode> &&child); + void removeAttribute (const std::string &name); + XMLNode* append (std::unique_ptr<XMLNode> child); XMLNode* append (const std::string &str); - XMLNode* prepend (std::unique_ptr<XMLNode> &&child); - void remove (const XMLNode *child); - bool insertAfter (std::unique_ptr<XMLNode> &&child, XMLNode *sibling); - bool insertBefore (std::unique_ptr<XMLNode> &&child, XMLNode *sibling); + XMLNode* prepend (std::unique_ptr<XMLNode> child); + XMLNode* insertAfter (std::unique_ptr<XMLNode> child, XMLNode *sibling); + XMLNode* insertBefore (std::unique_ptr<XMLNode> child, XMLNode *sibling); bool hasAttribute (const std::string &name) const; const char* getAttributeValue (const std::string &name) const; - bool getDescendants (const char *name, const char *attrName, std::vector<XMLElementNode*> &descendants) const; - XMLElementNode* getFirstDescendant (const char *name, const char *attrName, const char *attrValue) const; + bool getDescendants (const char *name, const char *attrName, std::vector<XMLElement*> &descendants) const; + XMLElement* getFirstDescendant (const char *name, const char *attrName, const char *attrValue) const; + XMLNode* firstChild () const {return _firstChild.get();} + XMLNode* lastChild () const {return _lastChild;} std::ostream& write (std::ostream &os) const override; - bool empty () const {return _children.empty();} - const ChildList& children () const {return _children;} - const std::string& getName () const {return _name;} + bool empty () const {return !_firstChild;} + Attributes& attributes () {return _attributes;} + const Attributes& attributes () const {return _attributes;} + XMLNodeIterator begin () {return XMLNodeIterator(_firstChild.get());} + XMLNodeIterator end () {return XMLNodeIterator(nullptr);} + ConstXMLNodeIterator begin () const {return ConstXMLNodeIterator(_firstChild.get());} + ConstXMLNodeIterator end () const {return ConstXMLNodeIterator(nullptr);} + const std::string& name () const {return _name;} + const XMLElement* toElement () const override {return this;} + const Attribute* getAttribute (const std::string &name) const; + + static std::unique_ptr<XMLNode> remove (XMLNode *child); + static XMLElement* wrap (XMLNode *first, XMLNode *last, const std::string &name); + static XMLNode* unwrap (XMLElement *child); + protected: Attribute* getAttribute (const std::string &name); - const Attribute* getAttribute (const std::string &name) const; + XMLNode* insertFirst (std::unique_ptr<XMLNode> child); + XMLNode* insertLast (std::unique_ptr<XMLNode> child); private: std::string _name; // element name (<name a1="v1" .. an="vn">...</name>) std::vector<Attribute> _attributes; - ChildList _children; // child nodes + std::unique_ptr<XMLNode> _firstChild; ///< pointer to first child node (incl. ownership) + XMLNode *_lastChild=nullptr; ///< pointer to last child node }; -class XMLTextNode : public XMLNode { +class XMLText : public XMLNode { public: - XMLTextNode (const std::string &str) : _text(str) {} - XMLTextNode (std::string &&str) : _text(std::move(str)) {} - std::unique_ptr<XMLNode> clone () const override {return util::make_unique<XMLTextNode>(*this);} + explicit XMLText (std::string str) : _text(std::move(str)) {} + std::unique_ptr<XMLNode> clone () const override {return util::make_unique<XMLText>(*this);} void clear () override {_text.clear();} - void append (std::unique_ptr<XMLNode> &&node); - void append (std::unique_ptr<XMLTextNode> &&node); + void append (std::unique_ptr<XMLNode> node); + void append (std::unique_ptr<XMLText> node); void append (const std::string &str); - void prepend (std::unique_ptr<XMLNode> &&node); + void prepend (std::unique_ptr<XMLNode> node); std::ostream& write (std::ostream &os) const override {return os << _text;} const std::string& getText () const {return _text;} + const XMLText* toText () const override {return this;} + const XMLText* toWSNode () const override; private: std::string _text; }; -class XMLCommentNode : public XMLNode { +class XMLComment : public XMLNode { public: - XMLCommentNode (const std::string &str) : _text(str) {} - XMLCommentNode (std::string &&str) : _text(std::move(str)) {} - std::unique_ptr<XMLNode> clone () const override {return util::make_unique<XMLCommentNode>(*this);} + explicit XMLComment (std::string str) : _text(std::move(str)) {} + std::unique_ptr<XMLNode> clone () const override {return util::make_unique<XMLComment>(*this);} void clear () override {_text.clear();} std::ostream& write (std::ostream &os) const override {return os << "<!--" << _text << "-->";} + const XMLComment* toComment () const override {return this;} private: std::string _text; }; -class XMLCDataNode : public XMLNode { +class XMLCData : public XMLNode { public: - XMLCDataNode () =default; - XMLCDataNode (const std::string &d) : _data(d) {} - XMLCDataNode (std::string &&d) : _data(std::move(d)) {} - std::unique_ptr<XMLNode> clone () const override {return util::make_unique<XMLCDataNode>(*this);} + XMLCData () =default; + explicit XMLCData (std::string data) : _data(std::move(data)) {} + std::unique_ptr<XMLNode> clone () const override {return util::make_unique<XMLCData>(*this);} void clear () override {_data.clear();} void append (std::string &&str); std::ostream& write (std::ostream &os) const override; + const XMLCData* toCData () const override {return this;} private: std::string _data; }; -inline std::ostream& operator << (std::ostream &os, const XMLElementNode &node) {return node.write(os);} -inline std::ostream& operator << (std::ostream &os, const XMLTextNode &node) {return node.write(os);} -inline std::ostream& operator << (std::ostream &os, const XMLCommentNode &node) {return node.write(os);} -inline std::ostream& operator << (std::ostream &os, const XMLCDataNode &node) {return node.write(os);} +inline std::ostream& operator << (std::ostream &os, const XMLElement &node) {return node.write(os);} +inline std::ostream& operator << (std::ostream &os, const XMLText &node) {return node.write(os);} +inline std::ostream& operator << (std::ostream &os, const XMLComment &node) {return node.write(os);} +inline std::ostream& operator << (std::ostream &os, const XMLCData &node) {return node.write(os);} #endif diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLString.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLString.cpp index 734cc7ff8cd..fcafb8d1ee0 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLString.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLString.cpp @@ -21,6 +21,7 @@ #include <cmath> #include <cstdlib> #include "Unicode.hpp" +#include "utility.hpp" #include "XMLString.hpp" using namespace std; @@ -89,14 +90,8 @@ XMLString::XMLString (double x) { } if (std::abs(x) < 1e-6) x = 0; - assign(to_string(x)); - size_t pos = find('.'); - if (pos != string::npos) { - pos = find_last_not_of('0'); - if (pos != string::npos) { - erase(pos+1); // remove trailing zeros - if (at(length()-1) == '.') - pop_back(); // remove trailing dot - } - } + assign(util::to_string(x)); + size_t pos = find("0."); + if (pos != string::npos && (pos == 0 || at(pos-1) == '-')) + erase(pos, 1); } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLString.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLString.hpp index efc88d1a25a..fa9cf15f9ea 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLString.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLString.hpp @@ -24,14 +24,13 @@ #include <string> -class XMLString : public std::string -{ +class XMLString : public std::string { public: XMLString () : std::string() {} - XMLString (const char *str, bool plain=false); - XMLString (const std::string &str, bool plain=false); - XMLString (int n, bool cast=true); - XMLString (double x); + explicit XMLString (const char *str, bool plain=false); + explicit XMLString (const std::string &str, bool plain=false); + explicit XMLString (int n, bool cast=true); + explicit XMLString (double x); static int DECIMAL_PLACES; ///< number of decimal places applied to floating point values (0-6) }; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/XXHashFunction.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/XXHashFunction.hpp index 62f10db3792..f81deddbd46 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/XXHashFunction.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/XXHashFunction.hpp @@ -23,7 +23,11 @@ #include <xxhash.h> #include "HashFunction.hpp" +#include "utility.hpp" +#if (XXH_VERSION_NUMBER >= 701) && defined(XXH3_SECRET_SIZE_MIN) +#define ENABLE_XXH128 +#endif template <int HASH_SIZE> struct XXHInterface { @@ -49,6 +53,17 @@ struct XXHInterface<8> { static constexpr auto digest = &XXH64_digest; }; +#ifdef ENABLE_XXH128 +template<> +struct XXHInterface<16> { + using State = XXH3_state_t; + static constexpr auto createState = &XXH3_createState; + static constexpr auto freeState = &XXH3_freeState; + static constexpr auto reset = &XXH3_128bits_reset_withSeed; + static constexpr auto update = &XXH3_128bits_update; + static constexpr auto digest = &XXH3_128bits_digest; +}; +#endif /** Implements the HashFunction class for the xxHash algorithms. */ template <int HASH_BYTES> @@ -57,23 +72,19 @@ class XXHashFunction : public HashFunction { public: XXHashFunction () : _state(Interface::createState()) {Interface::reset(_state, 0);} XXHashFunction(const char *data, size_t length) : XXHashFunction() {update(data, length);} - XXHashFunction(const std::string &data) : XXHashFunction() {update(data);} - XXHashFunction(const std::vector<uint8_t> &data) : XXHashFunction() {update(data);} - ~XXHashFunction () {Interface::freeState(_state);} + explicit XXHashFunction(const std::string &data) : XXHashFunction() {update(data);} + explicit XXHashFunction(const std::vector<uint8_t> &data) : XXHashFunction() {update(data);} + ~XXHashFunction () override {Interface::freeState(_state);} int digestSize () const override {return HASH_BYTES;} void reset () override {Interface::reset(_state, 0);} void update (const char *data, size_t length) override {Interface::update(_state, data, length);} void update (const std::string &data) override {update(data.data(), data.length());} void update (const std::vector<uint8_t> &data) override {update(reinterpret_cast<const char*>(data.data()), data.size());} + using HashFunction::update; // unhide update(istream &is) defined in base class + std::vector<uint8_t> digestValue () const override { - std::vector<uint8_t> hash(HASH_BYTES); - auto digest = Interface::digest(_state); - for (int i=HASH_BYTES-1; i >= 0; i--) { - hash[i] = digest & 0xff; - digest >>= 8; - } - return hash; + return util::bytes(Interface::digest(_state), HASH_BYTES); } static unsigned version () {return XXH_versionNumber();} @@ -85,4 +96,19 @@ class XXHashFunction : public HashFunction { using XXH32HashFunction = XXHashFunction<4>; using XXH64HashFunction = XXHashFunction<8>; +#ifdef ENABLE_XXH128 +using XXH128HashFunction = XXHashFunction<16>; + +template<> +inline std::vector<uint8_t> XXHashFunction<16>::digestValue () const { + std::vector<uint8_t> hash; + auto digest = Interface::digest(_state); + for (auto chunk : {digest.high64, digest.low64}) { + auto bytes = util::bytes(chunk); + hash.insert(hash.end(), bytes.begin(), bytes.end()); + } + return hash; +} +#endif + #endif diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/ZLibOutputStream.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/ZLibOutputStream.hpp index 4e882813550..8331cb9eed3 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/ZLibOutputStream.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/ZLibOutputStream.hpp @@ -33,20 +33,20 @@ #endif struct ZLibException : public MessageException { - ZLibException (const std::string &msg) : MessageException(msg) {} + explicit ZLibException (const std::string &msg) : MessageException(msg) {} }; enum ZLibCompressionFormat {ZLIB_DEFLATE=0, ZLIB_GZIP=16}; class ZLibOutputBuffer : public std::streambuf { public: - ZLibOutputBuffer () {} + ZLibOutputBuffer () =default; ZLibOutputBuffer (std::streambuf *sbuf, ZLibCompressionFormat format, int zipLevel) { open(sbuf, format, zipLevel); } - ~ZLibOutputBuffer () { + ~ZLibOutputBuffer () override { close(); } @@ -84,7 +84,7 @@ class ZLibOutputBuffer : public std::streambuf { else { if (_inbuf.size() == _inbuf.capacity()) flush(Z_NO_FLUSH); - _inbuf.push_back(c); + _inbuf.push_back(static_cast<unsigned char>(c)); } return c; } @@ -101,10 +101,10 @@ class ZLibOutputBuffer : public std::streambuf { * @throws ZLibException if compression failed */ void flush (int flushmode) { if (_opened) { - _zstream.avail_in = _inbuf.size(); + _zstream.avail_in = static_cast<uInt>(_inbuf.size()); _zstream.next_in = _inbuf.data(); do { - _zstream.avail_out = _zbuf.size(); + _zstream.avail_out = static_cast<uInt>(_zbuf.size()); _zstream.next_out = _zbuf.data(); int ret = deflate(&_zstream, flushmode); if (ret == Z_STREAM_ERROR) { @@ -146,7 +146,7 @@ class ZLibOutputStream : private ZLibOutputBuffer, public std::ostream { ZLibOutputStream (std::ostream &os, ZLibCompressionFormat format, int zipLevel) : ZLibOutputBuffer(os.rdbuf(), format, zipLevel), std::ostream(this) {} - ~ZLibOutputStream () {close();} + ~ZLibOutputStream () override {close();} bool open (std::ostream &os, ZLibCompressionFormat format, int zipLevel) { ZLibOutputBuffer::close(); @@ -172,7 +172,7 @@ class ZLibOutputFileStream : public ZLibOutputStream { } } - ~ZLibOutputFileStream () {close();} + ~ZLibOutputFileStream () override {close();} private: std::ofstream _ofs; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/dvisvgm.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/dvisvgm.cpp index b82709f1f55..37584d5ddbd 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/dvisvgm.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/dvisvgm.cpp @@ -45,6 +45,7 @@ #include "PsSpecialHandler.hpp" #include "SignalHandler.hpp" #include "SourceInput.hpp" +#include "optimizer/SVGOptimizer.hpp" #include "SVGOutput.hpp" #include "System.hpp" #include "XXHashFunction.hpp" @@ -108,27 +109,36 @@ static void set_libgs (CommandLine &args) { static bool set_cache_dir (const CommandLine &args) { if (args.cacheOpt.given() && !args.cacheOpt.value().empty()) { if (args.cacheOpt.value() == "none") - PhysicalFont::CACHE_PATH = 0; + PhysicalFont::CACHE_PATH.clear(); else if (FileSystem::exists(args.cacheOpt.value())) - PhysicalFont::CACHE_PATH = args.cacheOpt.value().c_str(); + PhysicalFont::CACHE_PATH = args.cacheOpt.value(); else Message::wstream(true) << "cache directory '" << args.cacheOpt.value() << "' does not exist (caching disabled)\n"; } - else if (const char *userdir = FileSystem::userdir()) { + else { + string &cachepath = PhysicalFont::CACHE_PATH; + const char *cachehome = getenv("XDG_CACHE_HOME"); + if (!cachehome || util::trim(cachehome).empty()) { #ifdef _WIN32 - string cachedir = "\\.dvisvgm\\cache"; + cachehome = "~\\.cache"; #else - string cachedir = "/.dvisvgm/cache"; + cachehome = "~/.cache"; #endif - static string cachepath = userdir + cachedir; + } + cachepath = util::trim(cachehome) + FileSystem::PATHSEP + "dvisvgm"; + if (cachepath[0] == '~' && cachepath[1] == FileSystem::PATHSEP) { + if (FileSystem::userdir()) + cachepath.replace(0, 1, FileSystem::userdir()); + else + cachepath.erase(0, 2); // strip leading "~/" + } if (!FileSystem::exists(cachepath)) FileSystem::mkdir(cachepath); - PhysicalFont::CACHE_PATH = cachepath.c_str(); } if (args.cacheOpt.given() && args.cacheOpt.value().empty()) { - cout << "cache directory: " << (PhysicalFont::CACHE_PATH ? PhysicalFont::CACHE_PATH : "(none)") << '\n'; + cout << "cache directory: " << (PhysicalFont::CACHE_PATH.empty() ? "(none)" : PhysicalFont::CACHE_PATH) << '\n'; try { - if (PhysicalFont::CACHE_PATH) + if (!PhysicalFont::CACHE_PATH.empty()) FontCache::fontinfo(PhysicalFont::CACHE_PATH, cout, true); } catch (StreamReaderException &e) { @@ -143,7 +153,7 @@ static bool set_cache_dir (const CommandLine &args) { static bool set_temp_dir (const CommandLine &args) { if (args.tmpdirOpt.given()) { if (!args.tmpdirOpt.value().empty()) - FileSystem::TMPDIR = args.tmpdirOpt.value().c_str(); + FileSystem::TMPDIR = args.tmpdirOpt.value(); else { cout << "temporary folder: " << FileSystem::tmpdir() << '\n'; return false; @@ -299,14 +309,14 @@ static string svg_options_hash (const CommandLine &cmdline) { // options affecting the SVG output vector<const CL::Option*> svg_options = { &cmdline.bboxOpt, &cmdline.clipjoinOpt, &cmdline.colornamesOpt, &cmdline.commentsOpt, - &cmdline.exactOpt, &cmdline.fontFormatOpt, &cmdline.fontmapOpt, &cmdline.gradOverlapOpt, + &cmdline.exactBboxOpt, &cmdline.fontFormatOpt, &cmdline.fontmapOpt, &cmdline.gradOverlapOpt, &cmdline.gradSegmentsOpt, &cmdline.gradSimplifyOpt, &cmdline.linkmarkOpt, &cmdline.magOpt, - &cmdline.noFontsOpt, &cmdline.noMergeOpt, &cmdline.noSpecialsOpt, &cmdline.noStylesOpt, - &cmdline.precisionOpt, &cmdline.relativeOpt, &cmdline.zoomOpt + &cmdline.noFontsOpt, &cmdline.noMergeOpt, &cmdline.noSpecialsOpt, &cmdline.noStylesOpt, + &cmdline.optimizeOpt, &cmdline.precisionOpt, &cmdline.relativeOpt, &cmdline.zoomOpt }; string idString = get_transformation_string(cmdline); for (const CL::Option *opt : svg_options) { - idString += opt->given(); + idString += char(opt->given()); idString += opt->valueString(); } return XXH64HashFunction(idString).digestString(); @@ -337,10 +347,9 @@ static void set_variables (const CommandLine &cmdline) { SVGTree::USE_FONTS = !cmdline.noFontsOpt.given(); if (!SVGTree::setFontFormat(cmdline.fontFormatOpt.value())) { string msg = "unknown font format '"+cmdline.fontFormatOpt.value()+"' (supported formats: "; - ostringstream oss; for (const string &format : FontWriter::supportedFormats()) - oss << ", " << format; - msg += oss.str().substr(2) + ')'; + msg += format + ", "; + msg.erase(msg.end()-2); throw CL::CommandLineException(msg); } SVGTree::CREATE_USE_ELEMENTS = cmdline.noFontsOpt.value() < 1; @@ -350,7 +359,7 @@ static void set_variables (const CommandLine &cmdline) { SVGTree::ADD_COMMENTS = cmdline.commentsOpt.given(); DVIToSVG::TRACE_MODE = cmdline.traceAllOpt.given() ? (cmdline.traceAllOpt.value() ? 'a' : 'm') : 0; Message::LEVEL = cmdline.verbosityOpt.value(); - PhysicalFont::EXACT_BBOX = cmdline.exactOpt.given(); + PhysicalFont::EXACT_BBOX = cmdline.exactBboxOpt.given(); PhysicalFont::KEEP_TEMP_FILES = cmdline.keepOpt.given(); PhysicalFont::METAFONT_MAG = max(1.0, cmdline.magOpt.value()); XMLString::DECIMAL_PLACES = max(0, min(6, cmdline.precisionOpt.value())); @@ -358,6 +367,19 @@ static void set_variables (const CommandLine &cmdline) { PsSpecialHandler::SHADING_SEGMENT_OVERLAP = cmdline.gradOverlapOpt.given(); PsSpecialHandler::SHADING_SEGMENT_SIZE = max(1, cmdline.gradSegmentsOpt.value()); PsSpecialHandler::SHADING_SIMPLIFY_DELTA = cmdline.gradSimplifyOpt.value(); + if (cmdline.optimizeOpt.given()) { + SVGOptimizer::MODULE_SEQUENCE = cmdline.optimizeOpt.value(); + vector<string> modnames; + if (!SVGOptimizer().checkModuleString(SVGOptimizer::MODULE_SEQUENCE, modnames)) { + string msg = "invalid optimizer module"; + if (modnames.size() > 1) msg += 's'; + msg += ": "; + for (const string &modname : modnames) + msg += modname + ", "; + msg.erase(msg.end()-2); + throw CL::CommandLineException(msg); + } + } } @@ -393,6 +415,10 @@ int main (int argc, char *argv[]) { SpecialManager::instance().writeHandlerInfo(cout); return 0; } + if (cmdline.optimizeOpt.value() == "list") { + SVGOptimizer().listModules(cout); + return 0; + } if (!set_cache_dir(cmdline) || !set_temp_dir(cmdline)) return 0; check_bbox(cmdline.bboxOpt.value()); diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/AttributeExtractor.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/AttributeExtractor.cpp new file mode 100644 index 00000000000..e26018253d6 --- /dev/null +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/AttributeExtractor.cpp @@ -0,0 +1,176 @@ +/************************************************************************* +** AttributeExtractor.cpp ** +** ** +** This file is part of dvisvgm -- a fast DVI to SVG converter ** +** Copyright (C) 2005-2019 Martin Gieseking <martin.gieseking@uos.de> ** +** ** +** 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 <http://www.gnu.org/licenses/>. ** +*************************************************************************/ + +#include <algorithm> +#include <array> +#include "AttributeExtractor.hpp" + +using namespace std; + +/** Constructs a new run object for an attribute and a sequence of sibling nodes. + * @param[in] attr attribute to look for + * @param[in] first first element of node sequence to scan */ +AttributeExtractor::AttributeRun::AttributeRun (const Attribute &attr, XMLElement *first) { + _length = 1; + _first = first; + for (_last=_first->next(); _last; _last=_last->next()) { + if (_last->toText() || _last->toCData()) // don't include text/CDATA nodes + break; + if (XMLElement *childElem = _last->toElement()) { + if (!groupable(*childElem)) + break; + const char *val = childElem->getAttributeValue(attr.name); + if (val && val == attr.value) + ++_length; + else + break; + } + } + if (_first != _last && _last) + _last = _last->prev(); +} + + +const char* AttributeExtractor::info () const { + return "move common attributes from a sequence of elements to enclosing groups"; +} + + +/** Performs the attribute extraction on a given context node. Each extracted + * attribute gets its own group, i.e. the extraction of multiple attributes + * of the same elements leads to nested groups. + * @param[in] context attributes of all children in this element are extracted + * @param[in] recurse if true, the algorithm is recursively performed on all descendant elements */ +void AttributeExtractor::execute (XMLElement *context, bool recurse) { + if (!context || context->empty()) + return; + if (recurse) { + for (auto node : *context) { + if (XMLElement *elem = node->toElement()) + execute(elem, true); + } + } + for (XMLNode *child=context->firstChild(); child; child=child->next()) { + if (XMLElement *elem = child->toElement()) + child = extractAttribute(elem); + } +} + + +/** Looks for the first attribute not yet processed and tries to group it. If + * there is a sequence of adjacent sibling nodes N1,...,Nn with an identical inheritable + * attribute, the function creates a group element with this attribute and moves the + * nodes N1,...,Nn into that group. The group is inserted at the former position of N1. + * @param[in] elem first element of a node sequence with potentially identical attributes + * @return the new group element if attributes could be grouped, 'elem' otherwise */ +XMLNode* AttributeExtractor::extractAttribute (XMLElement *elem) { + for (const auto ¤tAttribute : elem->attributes()) { + if (!inheritable(currentAttribute) || extracted(currentAttribute)) + continue; + AttributeRun run(currentAttribute, elem); + if (run.length() >= MIN_RUN_LENGTH) { + XMLElement::Attribute attrib = currentAttribute; + XMLElement *group = XMLElement::wrap(run.first(), run.last(), "g"); + group->addAttribute(attrib.name, attrib.value); + // remove attribute from the grouped elements but keep it on elements with 'id' attribute + // since they can be referenced, and keep 'fill' attribute on animation elements + for (XMLNode *node : *group) { + XMLElement *elem = node->toElement(); + if (elem && extractable(attrib, *elem)) + elem->removeAttribute(attrib.name); + } + // continue with children of the new group but ignore the just extracted attribute + _extractedAttributes.insert(attrib.name); + execute(group, false); + _extractedAttributes.erase(attrib.name); + return group; + } + } + return elem; +} + + +/** Checks whether an element type is allowed to be put in a group element (<g>...</g>). + * For now we only consider a subset of the actually allowed set of elements. + * @param[in] elem name of element to check + * @return true if the element is groupable */ +bool AttributeExtractor::groupable (const XMLElement &elem) { + // https://www.w3.org/TR/SVG/struct.html#GElement + static const char *names[] = { + "a", "altGlyphDef", "animate", "animateColor", "animateMotion", "animateTransform", + "circle", "clipPath", "color-profile", "cursor", "defs", "desc", "ellipse", "filter", + "font", "font-face", "foreignObject", "g", "image", "line", "linearGradient", "marker", + "mask", "path", "pattern", "polygon", "polyline", "radialGradient", "rect", "set", + "style", "switch", "symbol", "text", "title", "use", "view" + }; + return binary_search(begin(names), end(names), elem.name(), [](const string &name1, const string &name2) { + return name1 < name2; + }); +} + + +/** Checks whether an SVG attribute A of an element E implicitly propagates its properties + * to all child elements of E that don't specify A. For now we only consider a subset of + * the inheritable properties. + * @param[in] attrib name of attribute to check + * @return true if the attribute is inheritable */ +bool AttributeExtractor::inheritable (const Attribute &attrib) { + // subset of inheritable properties listed on https://www.w3.org/TR/SVG11/propidx.html + // clip-path is not inheritable but can be moved to the parent element as long as + // no child gets an different clip-path attribute + // https://www.w3.org/TR/SVG11/styling.html#Inheritance + static const char *names[] = { + "clip-path", "clip-rule", "color", "color-interpolation", "color-interpolation-filters", "color-profile", + "color-rendering", "direction", "fill", "fill-opacity", "fill-rule", "font", "font-family", "font-size", + "font-size-adjust", "font-stretch", "font-style", "font-variant", "font-weight", "glyph-orientation-horizontal", + "glyph-orientation-vertical", "letter-spacing", "paint-order", "stroke", "stroke-dasharray", "stroke-dashoffset", + "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke-width", "transform", + "visibility", "word-spacing", "writing-mode" + }; + return binary_search(begin(names), end(names), attrib.name, [](const string &name1, const string &name2) { + return name1 < name2; + }); +} + + +/** Checks whether an attribute is allowed to be removed from a given element. */ +bool AttributeExtractor::extractable (const Attribute &attrib, XMLElement &element) { + if (element.hasAttribute("id")) + return false; + if (attrib.name != "fill") + return true; + // the 'fill' attribute of animation elements has different semantics than + // that of graphics elements => don't extract it from animation nodes + // https://www.w3.org/TR/SVG11/animate.html#TimingAttributes + static const char *names[] = { + "animate", "animateColor", "animateMotion", "animateTransform", "set" + }; + auto it = find_if(begin(names), end(names), [&](const string &name) { + return element.name() == name; + }); + return it == end(names); +} + + +/** Returns true if a given attribute was already extracted from the + * current run of elements. */ +bool AttributeExtractor::extracted (const Attribute &attr) const { + return _extractedAttributes.find(attr.name) != _extractedAttributes.end(); +} diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/AttributeExtractor.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/AttributeExtractor.hpp new file mode 100644 index 00000000000..c882e8b4c8f --- /dev/null +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/AttributeExtractor.hpp @@ -0,0 +1,61 @@ +/************************************************************************* +** AttributeExtractor.hpp ** +** ** +** This file is part of dvisvgm -- a fast DVI to SVG converter ** +** Copyright (C) 2005-2019 Martin Gieseking <martin.gieseking@uos.de> ** +** ** +** 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 <http://www.gnu.org/licenses/>. ** +*************************************************************************/ + +#pragma once + +#include <set> +#include <string> +#include "OptimizerModule.hpp" +#include "../XMLNode.hpp" + +/** Moves common attributes of adjacent elements to enclosing groups. */ +class AttributeExtractor : public OptimizerModule { + using Attribute = XMLElement::Attribute; + + /** Represents a range of adjacent nodes where all elements have a common attribute. */ + struct AttributeRun { + public: + AttributeRun (const Attribute &attr, XMLElement *first); + XMLNode* first () {return _first;} + XMLNode* last () {return _last;} + int length () const {return _length;} + + private: + int _length; ///< run length excluding non-element nodes + XMLNode *_first, *_last; ///< first and last node in run + }; + + public: + void execute (XMLElement*, XMLElement *context) override {execute(context, true);}; + const char* info () const override; + static bool groupable (const XMLElement &elem); + static bool inheritable (const Attribute &attrib); + static bool extractable (const Attribute &attr, XMLElement &element); + + protected: + void execute (XMLElement *context, bool recurse); + XMLNode* extractAttribute (XMLElement *elem); + bool extracted (const Attribute &attr) const; + + private: + std::set<std::string> _extractedAttributes; + static constexpr int MIN_RUN_LENGTH = 3; +}; + diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/DependencyGraph.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/DependencyGraph.hpp index c9738d3f030..c9111b43d56 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/DependencyGraph.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/DependencyGraph.hpp @@ -25,12 +25,12 @@ #include <memory> #include <set> #include <vector> -#include "utility.hpp" +#include "../utility.hpp" template <typename T> class DependencyGraph { struct GraphNode { - GraphNode (const T &k) : key(k), dependent() {} + explicit GraphNode (const T &k) : key(k), dependent() {} void addDependee (GraphNode *node) { if (node) { diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/GroupCollapser.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/GroupCollapser.cpp new file mode 100644 index 00000000000..36bf3a8cd5a --- /dev/null +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/GroupCollapser.cpp @@ -0,0 +1,165 @@ +/************************************************************************* +** GroupCollapser.cpp ** +** ** +** This file is part of dvisvgm -- a fast DVI to SVG converter ** +** Copyright (C) 2005-2019 Martin Gieseking <martin.gieseking@uos.de> ** +** ** +** 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 <http://www.gnu.org/licenses/>. ** +*************************************************************************/ + +#include <algorithm> +#include <array> +#include <string> +#include <vector> +#include "AttributeExtractor.hpp" +#include "GroupCollapser.hpp" +#include "../XMLNode.hpp" + +using namespace std; + + +const char* GroupCollapser::info () const { + return "join nested group elements"; +} + + +/** Checks if there's only a single child element and optional whitespace + * siblings in a given element. + * @param[in] elem element to check + * @return pointer to the only child element or nullptr */ +static XMLElement* only_child_element (XMLElement *elem) { + XMLElement *firstChildElement=nullptr; + for (XMLNode *child : *elem) { + if (XMLElement *childElement = child->toElement()) { + if (firstChildElement) + return nullptr; + firstChildElement = childElement; + } + else if (!child->toWSNode()) + return nullptr; + } + return firstChildElement; +} + + +/** Removes all whitespace child nodes from a given element. */ +static void remove_ws_nodes (XMLElement *elem) { + XMLNode *node = elem->firstChild(); + while (node) { + if (!node->toWSNode()) + node = node->next(); + else { + XMLNode *next = node->next(); + XMLElement::remove(node); + node = next; + } + } +} + + +/** Recursively removes all redundant group elements from the given context element + * and moves their attributes to the corresponding parent element. + * @param[in] context root of the subtree to process */ +void GroupCollapser::execute (XMLElement *context) { + if (!context) + return; + XMLNode *node=context->firstChild(); + while (node) { + XMLNode *next = node->next(); // keep safe pointer to next node + if (XMLElement *elem = node->toElement()) + execute(elem); + node = next; + } + if (context->name() == "g" && context->attributes().empty()) { + // unwrap group without attributes + remove_ws_nodes(context); + XMLElement::unwrap(context); + } + else { + XMLElement *child = only_child_element(context); + if (child && collapsible(*context)) { + if (child->name() == "g" && unwrappable(*child, *context) && moveAttributes(*child, *context)) { + remove_ws_nodes(context); + XMLElement::unwrap(child); + } + } + } +} + + +/** Moves all attributes from an element to another one. Attributes already + * present in the destination element are overwritten or combined. + * @param[in] source element the attributes are taken from + * @param[in] dest element that receives the attributes + * @return true if all attributes have been moved */ +bool GroupCollapser::moveAttributes (XMLElement &source, XMLElement &dest) { + vector<string> movedAttributes; + for (const XMLElement::Attribute &attr : source.attributes()) { + if (attr.name == "transform") { + string transform; + if (const char *destvalue = dest.getAttributeValue("transform")) + transform = destvalue+attr.value; + else + transform = attr.value; + dest.addAttribute("transform", transform); + movedAttributes.emplace_back("transform"); + } + else if (AttributeExtractor::inheritable(attr)) { + dest.addAttribute(attr.name, attr.value); + movedAttributes.emplace_back(attr.name); + } + } + for (const string &attrname : movedAttributes) + source.removeAttribute(attrname); + return source.attributes().empty(); +} + + +/** Returns true if a given element is allowed to take the inheritable attributes + * and children of a child group without changing the semantics. + * @param[in] element group element to check */ +bool GroupCollapser::collapsible (const XMLElement &element) { + // the 'fill' attribute of animation elements has different semantics than + // that of graphics elements => don't collapse them + static const char *names[] = { + "animate", "animateColor", "animateMotion", "animateTransform", "set" + }; + auto it = find_if(begin(names), end(names), [&](const string &name) { + return element.name() == name; + }); + return it == end(names); +} + + +/** Returns true if a given group element is allowed to be unwrapped, i.e. its + * attributes and children can be moved to the parent without changing the semantics. + * @param[in] source element whose children and attributes should be moved + * @param[in] dest element that should receive the children and attributes */ +bool GroupCollapser::unwrappable (const XMLElement &source, const XMLElement &dest) { + // check for colliding clip-path attributes + if (const char *cp1 = source.getAttributeValue("clip-path")) { + if (const char *cp2 = dest.getAttributeValue("clip-path")) { + if (string(cp1) != cp2) + return false; + } + } + // these attributes prevent a group from being unwrapped + static const char *attribs[] = { + "class", "id", "filter", "mask", "style" + }; + auto it = find_if(begin(attribs), end(attribs), [&](const string &name) { + return source.hasAttribute(name) || dest.hasAttribute(name); + }); + return it == end(attribs); +} diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/GroupCollapser.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/GroupCollapser.hpp new file mode 100644 index 00000000000..9b5eb018293 --- /dev/null +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/GroupCollapser.hpp @@ -0,0 +1,36 @@ +/************************************************************************* +** GroupCollapser.hpp ** +** ** +** This file is part of dvisvgm -- a fast DVI to SVG converter ** +** Copyright (C) 2005-2019 Martin Gieseking <martin.gieseking@uos.de> ** +** ** +** 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 <http://www.gnu.org/licenses/>. ** +*************************************************************************/ + +#pragma once + +#include "OptimizerModule.hpp" + +/** Joins the attributes of nested groups and removes groups without attributes. */ +class GroupCollapser : public OptimizerModule { + public: + void execute (XMLElement*, XMLElement *context) override {execute(context);}; + void execute (XMLElement *context); + const char* info () const override; + + protected: + static bool moveAttributes (XMLElement &source, XMLElement &dest); + static bool collapsible (const XMLElement &elem); + static bool unwrappable (const XMLElement &source, const XMLElement &dest); +}; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/Makefile.am b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/Makefile.am new file mode 100644 index 00000000000..10232c273d3 --- /dev/null +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/Makefile.am @@ -0,0 +1,14 @@ +noinst_LIBRARIES = liboptimizer.a + +liboptimizer_a_SOURCES = \ + AttributeExtractor.hpp AttributeExtractor.cpp \ + DependencyGraph.hpp \ + GroupCollapser.hpp GroupCollapser.cpp \ + OptimizerModule.hpp \ + RedundantElementRemover.hpp RedundantElementRemover.cpp \ + SVGOptimizer.hpp SVGOptimizer.cpp \ + TextSimplifier.hpp TextSimplifier.cpp \ + TransformSimplifier.hpp TransformSimplifier.cpp \ + WSNodeRemover.hpp WSNodeRemover.cpp + +AM_CXXFLAGS = -I$(dvisvgm_srcdir)/libs/variant/include diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/Makefile.in b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/Makefile.in new file mode 100644 index 00000000000..103e6bc0e36 --- /dev/null +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/Makefile.in @@ -0,0 +1,694 @@ +# Makefile.in generated by automake 1.16.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2018 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = dvisvgm-src/src/optimizer +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/../../m4/ax_cxx_compile_stdcxx.m4 \ + $(top_srcdir)/../../m4/kpse-common.m4 \ + $(top_srcdir)/../../m4/kpse-cxx-hack.m4 \ + $(top_srcdir)/../../m4/kpse-freetype2-flags.m4 \ + $(top_srcdir)/../../m4/kpse-kpathsea-flags.m4 \ + $(top_srcdir)/../../m4/kpse-warnings.m4 \ + $(top_srcdir)/../../m4/kpse-win32.m4 \ + $(top_srcdir)/../../m4/kpse-zlib-flags.m4 \ + $(top_srcdir)/../../m4/libtool.m4 \ + $(top_srcdir)/../../m4/ltoptions.m4 \ + $(top_srcdir)/../../m4/ltsugar.m4 \ + $(top_srcdir)/../../m4/ltversion.m4 \ + $(top_srcdir)/../../m4/lt~obsolete.m4 $(top_srcdir)/version.ac \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LIBRARIES = $(noinst_LIBRARIES) +ARFLAGS = cru +AM_V_AR = $(am__v_AR_@AM_V@) +am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@) +am__v_AR_0 = @echo " AR " $@; +am__v_AR_1 = +liboptimizer_a_AR = $(AR) $(ARFLAGS) +liboptimizer_a_LIBADD = +am_liboptimizer_a_OBJECTS = AttributeExtractor.$(OBJEXT) \ + GroupCollapser.$(OBJEXT) RedundantElementRemover.$(OBJEXT) \ + SVGOptimizer.$(OBJEXT) TextSimplifier.$(OBJEXT) \ + TransformSimplifier.$(OBJEXT) WSNodeRemover.$(OBJEXT) +liboptimizer_a_OBJECTS = $(am_liboptimizer_a_OBJECTS) +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/../../build-aux/depcomp +am__maybe_remake_depfiles = depfiles +am__depfiles_remade = ./$(DEPDIR)/AttributeExtractor.Po \ + ./$(DEPDIR)/GroupCollapser.Po \ + ./$(DEPDIR)/RedundantElementRemover.Po \ + ./$(DEPDIR)/SVGOptimizer.Po ./$(DEPDIR)/TextSimplifier.Po \ + ./$(DEPDIR)/TransformSimplifier.Po \ + ./$(DEPDIR)/WSNodeRemover.Po +am__mv = mv -f +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CXXFLAGS) $(CXXFLAGS) +AM_V_CXX = $(am__v_CXX_@AM_V@) +am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@) +am__v_CXX_0 = @echo " CXX " $@; +am__v_CXX_1 = +CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ + $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CXXLD = $(am__v_CXXLD_@AM_V@) +am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@) +am__v_CXXLD_0 = @echo " CXXLD " $@; +am__v_CXXLD_1 = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = +SOURCES = $(liboptimizer_a_SOURCES) +DIST_SOURCES = $(liboptimizer_a_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +am__DIST_COMMON = $(srcdir)/Makefile.in \ + $(top_srcdir)/../../build-aux/depcomp +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_CPPFLAGS = @AM_CPPFLAGS@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AM_LDFLAGS = @AM_LDFLAGS@ +AR = @AR@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BROTLI_CFLAGS = @BROTLI_CFLAGS@ +BROTLI_LIBS = @BROTLI_LIBS@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CODE_COVERAGE_RULES = @CODE_COVERAGE_RULES@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CXXLD = @CXXLD@ +CYGPATH_W = @CYGPATH_W@ +DATE = @DATE@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +DVISVGM_TREE = @DVISVGM_TREE@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +FREETYPE2_DEPEND = @FREETYPE2_DEPEND@ +FREETYPE2_INCLUDES = @FREETYPE2_INCLUDES@ +FREETYPE2_LIBS = @FREETYPE2_LIBS@ +FT2_CONFIG = @FT2_CONFIG@ +GREP = @GREP@ +HAVE_CXX11 = @HAVE_CXX11@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +KPATHSEA_DEPEND = @KPATHSEA_DEPEND@ +KPATHSEA_INCLUDES = @KPATHSEA_INCLUDES@ +KPATHSEA_LIBS = @KPATHSEA_LIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBGS_INCLUDES = @LIBGS_INCLUDES@ +LIBGS_LIBS = @LIBGS_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PKG_CONFIG = @PKG_CONFIG@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +WARNING_CFLAGS = @WARNING_CFLAGS@ +WARNING_CXXFLAGS = @WARNING_CXXFLAGS@ +WOFF2_CFLAGS = @WOFF2_CFLAGS@ +WOFF2_LIBS = @WOFF2_LIBS@ +ZLIB_DEPEND = @ZLIB_DEPEND@ +ZLIB_INCLUDES = @ZLIB_INCLUDES@ +ZLIB_LIBS = @ZLIB_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +dvisvgm_srcdir = @dvisvgm_srcdir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +noinst_LIBRARIES = liboptimizer.a +liboptimizer_a_SOURCES = \ + AttributeExtractor.hpp AttributeExtractor.cpp \ + DependencyGraph.hpp \ + GroupCollapser.hpp GroupCollapser.cpp \ + OptimizerModule.hpp \ + RedundantElementRemover.hpp RedundantElementRemover.cpp \ + SVGOptimizer.hpp SVGOptimizer.cpp \ + TextSimplifier.hpp TextSimplifier.cpp \ + TransformSimplifier.hpp TransformSimplifier.cpp \ + WSNodeRemover.hpp WSNodeRemover.cpp + +AM_CXXFLAGS = -I$(dvisvgm_srcdir)/libs/variant/include +all: all-am + +.SUFFIXES: +.SUFFIXES: .cpp .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign dvisvgm-src/src/optimizer/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign dvisvgm-src/src/optimizer/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) + +liboptimizer.a: $(liboptimizer_a_OBJECTS) $(liboptimizer_a_DEPENDENCIES) $(EXTRA_liboptimizer_a_DEPENDENCIES) + $(AM_V_at)-rm -f liboptimizer.a + $(AM_V_AR)$(liboptimizer_a_AR) liboptimizer.a $(liboptimizer_a_OBJECTS) $(liboptimizer_a_LIBADD) + $(AM_V_at)$(RANLIB) liboptimizer.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/AttributeExtractor.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/GroupCollapser.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RedundantElementRemover.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SVGOptimizer.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TextSimplifier.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TransformSimplifier.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/WSNodeRemover.Po@am__quote@ # am--include-marker + +$(am__depfiles_remade): + @$(MKDIR_P) $(@D) + @echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) + +.cpp.o: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $< + +.cpp.obj: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ +@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.cpp.lo: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ +@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -f ./$(DEPDIR)/AttributeExtractor.Po + -rm -f ./$(DEPDIR)/GroupCollapser.Po + -rm -f ./$(DEPDIR)/RedundantElementRemover.Po + -rm -f ./$(DEPDIR)/SVGOptimizer.Po + -rm -f ./$(DEPDIR)/TextSimplifier.Po + -rm -f ./$(DEPDIR)/TransformSimplifier.Po + -rm -f ./$(DEPDIR)/WSNodeRemover.Po + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f ./$(DEPDIR)/AttributeExtractor.Po + -rm -f ./$(DEPDIR)/GroupCollapser.Po + -rm -f ./$(DEPDIR)/RedundantElementRemover.Po + -rm -f ./$(DEPDIR)/SVGOptimizer.Po + -rm -f ./$(DEPDIR)/TextSimplifier.Po + -rm -f ./$(DEPDIR)/TransformSimplifier.Po + -rm -f ./$(DEPDIR)/WSNodeRemover.Po + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ + clean-generic clean-libtool clean-noinstLIBRARIES \ + cscopelist-am ctags ctags-am distclean distclean-compile \ + distclean-generic distclean-libtool distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/OptimizerModule.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/OptimizerModule.hpp new file mode 100644 index 00000000000..ff4fec1b4dc --- /dev/null +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/OptimizerModule.hpp @@ -0,0 +1,30 @@ +/************************************************************************* +** OptimizerModule.hpp ** +** ** +** This file is part of dvisvgm -- a fast DVI to SVG converter ** +** Copyright (C) 2005-2019 Martin Gieseking <martin.gieseking@uos.de> ** +** ** +** 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 <http://www.gnu.org/licenses/>. ** +*************************************************************************/ + +#pragma once + +class XMLElement; + +class OptimizerModule { + public: + virtual ~OptimizerModule () =default; + virtual void execute (XMLElement *defs, XMLElement *context) =0; + virtual const char* info () const =0; +}; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/RedundantElementRemover.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/RedundantElementRemover.cpp new file mode 100644 index 00000000000..85d8e5b1fa8 --- /dev/null +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/RedundantElementRemover.cpp @@ -0,0 +1,68 @@ +/************************************************************************* +** RedundantElementRemover.cpp ** +** ** +** This file is part of dvisvgm -- a fast DVI to SVG converter ** +** Copyright (C) 2005-2019 Martin Gieseking <martin.gieseking@uos.de> ** +** ** +** 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 <http://www.gnu.org/licenses/>. ** +*************************************************************************/ + +#include "DependencyGraph.hpp" +#include "RedundantElementRemover.hpp" +#include "../XMLNode.hpp" + +using namespace std; + +const char* RedundantElementRemover::info () const { + return "remove redundant 'clipPath' elements"; +} + + +/** Extracts the ID from a local URL reference like url(#abcde) */ +static inline string extract_id_from_url (const string &url) { + return url.substr(5, url.length()-6); +} + + +/** Removes elements present in the SVG tree that are not required. + * For now, only clipPath elements are removed. */ +void RedundantElementRemover::execute (XMLElement *defs, XMLElement *context) { + vector<XMLElement*> clipPathElements; + if (!defs || !context || !defs->getDescendants("clipPath", nullptr, clipPathElements)) + return; + + // collect dependencies between clipPath elements in the defs section of the SVG tree + DependencyGraph<string> idTree; + for (const XMLElement *clip : clipPathElements) { + if (const char *id = clip->getAttributeValue("id")) { + if (const char *url = clip->getAttributeValue("clip-path")) + idTree.insert(extract_id_from_url(url), id); + else + idTree.insert(id); + } + } + // collect elements that reference a clipPath, i.e. have a clip-path attribute + vector<XMLElement*> descendants; + context->getDescendants(nullptr, "clip-path", descendants); + // remove referenced IDs and their dependencies from the dependency graph + for (const XMLElement *elem : descendants) { + string idref = extract_id_from_url(elem->getAttributeValue("clip-path")); + idTree.removeDependencyPath(idref); + } + descendants.clear(); + for (const string &str : idTree.getKeys()) { + XMLElement *node = defs->getFirstDescendant("clipPath", "id", str.c_str()); + XMLElement::remove(node); + } +} diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/RedundantElementRemover.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/RedundantElementRemover.hpp new file mode 100644 index 00000000000..dd46cfeba5d --- /dev/null +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/RedundantElementRemover.hpp @@ -0,0 +1,29 @@ +/************************************************************************* +** RedundantElementRemover.hpp ** +** ** +** This file is part of dvisvgm -- a fast DVI to SVG converter ** +** Copyright (C) 2005-2019 Martin Gieseking <martin.gieseking@uos.de> ** +** ** +** 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 <http://www.gnu.org/licenses/>. ** +*************************************************************************/ + +#pragma once + +#include "OptimizerModule.hpp" + +class RedundantElementRemover : public OptimizerModule { + public: + void execute (XMLElement *defs, XMLElement *context) override; + const char* info () const override; +}; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/SVGOptimizer.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/SVGOptimizer.cpp new file mode 100644 index 00000000000..0320f8b565e --- /dev/null +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/SVGOptimizer.cpp @@ -0,0 +1,107 @@ +/************************************************************************* +** SVGOptimizer.cpp ** +** ** +** This file is part of dvisvgm -- a fast DVI to SVG converter ** +** Copyright (C) 2005-2019 Martin Gieseking <martin.gieseking@uos.de> ** +** ** +** 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 <http://www.gnu.org/licenses/>. ** +*************************************************************************/ + +#include <algorithm> +#include <array> +#include <map> +#include "SVGOptimizer.hpp" +#include "../SVGTree.hpp" + +#include "AttributeExtractor.hpp" +#include "GroupCollapser.hpp" +#include "RedundantElementRemover.hpp" +#include "TextSimplifier.hpp" +#include "TransformSimplifier.hpp" +#include "WSNodeRemover.hpp" + +using namespace std; + +string SVGOptimizer::MODULE_SEQUENCE; + +SVGOptimizer::SVGOptimizer (SVGTree *svg) : _svg(svg) { + // optimizer modules available to the user; must be listed in default order +// _moduleEntries.emplace_back(ModuleEntry("remove-ws", util::make_unique<WSNodeRemover>())); + _moduleEntries.emplace_back(ModuleEntry("simplify-text", util::make_unique<TextSimplifier>())); + _moduleEntries.emplace_back(ModuleEntry("group-attributes", util::make_unique<AttributeExtractor>())); + _moduleEntries.emplace_back(ModuleEntry("collapse-groups", util::make_unique<GroupCollapser>())); + _moduleEntries.emplace_back(ModuleEntry("simplify-transform", util::make_unique<TransformSimplifier>())); + _moduleEntries.emplace_back(ModuleEntry("remove-clippath", util::make_unique<RedundantElementRemover>())); +} + + +void SVGOptimizer::execute () { + if (!_svg || MODULE_SEQUENCE == "none") + return; + if (MODULE_SEQUENCE.empty()) + MODULE_SEQUENCE = "remove-clippath"; // default behaviour of previous dvisvgm releases + if (MODULE_SEQUENCE == "all") { + for (const auto &entry : _moduleEntries) + entry.module->execute(_svg->defsNode(), _svg->pageNode()); + } + else { + vector<string> names = util::split(MODULE_SEQUENCE, ","); + for (const string &name : names) { + if (OptimizerModule *module = getModule(name)) + module->execute(_svg->defsNode(), _svg->pageNode()); + } + } +} + + +void SVGOptimizer::listModules (ostream &os) const { + size_t maxlen=0; + map<string, const char*> infos; + for (const auto &entry : _moduleEntries) { + maxlen = max(maxlen, entry.modname.length()); + infos.emplace(entry.modname, entry.module->info()); + } + for (const auto &infopair : infos) { + os << setw(maxlen) << left << infopair.first; + os << " | " << infopair.second << '\n'; + } +} + + +/** Checks if all module names given in a comma-separated list are known. + * @param[in] namestr comma-separated list of module names + * @param[out] unknownNames names not recognized + * @return true if all names are known */ +bool SVGOptimizer::checkModuleString (string &namestr, vector<string> &unknownNames) const { + unknownNames.clear(); + if (namestr.empty() || namestr == "all" || namestr == "none") + return true; + vector<string> givenNames = util::split(namestr, ","); + for (const string &name : givenNames) { + if (!getModule(name)) + unknownNames.emplace_back(name); + } + return unknownNames.empty(); +} + + +OptimizerModule* SVGOptimizer::getModule (const string &name) const { + auto it = find_if(_moduleEntries.begin(), _moduleEntries.end(), [&](const ModuleEntry &entry) { + return entry.modname == name; + }); + if (it != _moduleEntries.end()) + return (*it).module.get(); + return nullptr; +} + diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/SVGOptimizer.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/SVGOptimizer.hpp new file mode 100644 index 00000000000..809f1f497c2 --- /dev/null +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/SVGOptimizer.hpp @@ -0,0 +1,59 @@ +/************************************************************************* +** SVGOptimizer.hpp ** +** ** +** This file is part of dvisvgm -- a fast DVI to SVG converter ** +** Copyright (C) 2005-2019 Martin Gieseking <martin.gieseking@uos.de> ** +** ** +** 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 <http://www.gnu.org/licenses/>. ** +*************************************************************************/ + +#pragma once + +#include <memory> +#include <ostream> +#include <set> +#include <vector> +#include "OptimizerModule.hpp" +#include "../XMLNode.hpp" + +class SVGTree; + +class SVGOptimizer { + struct ModuleEntry { + ModuleEntry (std::string name, std::unique_ptr<OptimizerModule> mod) + : modname(std::move(name)), module(std::move(mod)) {} + + std::string modname; + std::unique_ptr<OptimizerModule> module; + }; + public: + explicit SVGOptimizer (SVGTree *svg=nullptr); + explicit SVGOptimizer (SVGTree &svg) : SVGOptimizer(&svg) {} + void execute (); + void listModules (std::ostream &os) const; + bool checkModuleString (std::string &namestr, std::vector<std::string> &unknownNames) const; + + static std::string MODULE_SEQUENCE; + + protected: + OptimizerModule* getModule (const std::string &name) const; + + private: + SVGTree *_svg; + std::vector<ModuleEntry> _moduleEntries; +}; + + + + diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/TextSimplifier.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/TextSimplifier.cpp new file mode 100644 index 00000000000..23e0e386dfe --- /dev/null +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/TextSimplifier.cpp @@ -0,0 +1,118 @@ +/************************************************************************* +** TextSimplifier.cpp ** +** ** +** This file is part of dvisvgm -- a fast DVI to SVG converter ** +** Copyright (C) 2005-2019 Martin Gieseking <martin.gieseking@uos.de> ** +** ** +** 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 <http://www.gnu.org/licenses/>. ** +*************************************************************************/ + +#include <vector> +#include "AttributeExtractor.hpp" +#include "TextSimplifier.hpp" +#include "../XMLNode.hpp" + +using namespace std; + + +const char* TextSimplifier::info () const { + return "merge data of tspans into enclosing text elements"; +} + + +/** Returns all common inheritable attributes of multiple elements. */ +static XMLElement::Attributes common_inheritable_attributes (const vector<XMLElement*> &elements) { + bool intersected=false; + XMLElement::Attributes commonAttribs; + for (const XMLElement *elem : elements) { + if (commonAttribs.empty()) { + if (intersected) + break; + for (const auto attrib : elem->attributes()) { + if (AttributeExtractor::inheritable(attrib)) + commonAttribs.push_back(attrib); + } + } + else { + for (auto it = commonAttribs.begin(); it != commonAttribs.end();) { + auto *attrib = elem->getAttribute(it->name); + if (!attrib || attrib->value != it->value) + it = commonAttribs.erase(it); + else + ++it; + } + } + intersected = true; + } + return commonAttribs; +} + + +/** Returns all tspan elements of a text element if the latter doesn't contain + * any non-whitespace text nodes. Otherwise, the returned vector is empty. + * @param[in] textElement text element to check + * @return the tspan children of the text element */ +static vector<XMLElement*> get_tspans (XMLElement *textElement) { + vector<XMLElement*> tspans; + bool failed=false; + for (XMLNode *child : *textElement) { + if (child->toWSNode() || child->toComment()) + continue; + if (child->toText()) + failed = true; + else if (XMLElement *childElement = child->toElement()) { + if (childElement->name() != "tspan") + failed = true; + else + tspans.push_back(childElement); + } + if (failed) { + tspans.clear(); + break; + } + } + return tspans; +} + + +void TextSimplifier::execute (XMLElement *context) { + if (!context) + return; + if (context->name() == "text") { + vector<XMLElement*> tspans = get_tspans(context); + vector<XMLElement::Attribute> attribs = common_inheritable_attributes(tspans); + if (!tspans.empty() && !attribs.empty()) { + // move all common tspan attributes to the parent text element + for (const XMLElement::Attribute &attr : attribs) + context->addAttribute(attr.name, attr.value); + // remove all common attributes from the tspan elements + for (XMLElement *tspan : tspans) { + for (const XMLElement::Attribute &attr : attribs) + tspan->removeAttribute(attr.name); + // unwrap the tspan if there are no remaining attributes + if (tspan->attributes().empty()) + XMLElement::unwrap(tspan); + } + } + } + else { + XMLNode *node = context->firstChild(); + while (node) { + XMLNode *next = node->next(); // keep safe pointer to next node + if (XMLElement *elem = node->toElement()) + execute(elem); + node = next; + } + } +} diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/TextSimplifier.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/TextSimplifier.hpp new file mode 100644 index 00000000000..86f44e50518 --- /dev/null +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/TextSimplifier.hpp @@ -0,0 +1,30 @@ +/************************************************************************* +** TextSimplifier.hpp ** +** ** +** This file is part of dvisvgm -- a fast DVI to SVG converter ** +** Copyright (C) 2005-2019 Martin Gieseking <martin.gieseking@uos.de> ** +** ** +** 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 <http://www.gnu.org/licenses/>. ** +*************************************************************************/ + +#pragma once + +#include "OptimizerModule.hpp" + +class TextSimplifier : public OptimizerModule { + public: + void execute (XMLElement *defs, XMLElement *context) override {execute(context);} + static void execute (XMLElement *context); + const char *info () const override; +}; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/TransformSimplifier.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/TransformSimplifier.cpp new file mode 100644 index 00000000000..b9d4c3db596 --- /dev/null +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/TransformSimplifier.cpp @@ -0,0 +1,182 @@ +/************************************************************************* +** TransformSimplifier.cpp ** +** ** +** This file is part of dvisvgm -- a fast DVI to SVG converter ** +** Copyright (C) 2005-2019 Martin Gieseking <martin.gieseking@uos.de> ** +** ** +** 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 <http://www.gnu.org/licenses/>. ** +*************************************************************************/ + +#include <cmath> +#include <cstdlib> +#include "TransformSimplifier.hpp" +#include "../Matrix.hpp" +#include "../utility.hpp" +#include "../XMLNode.hpp" +#include "../XMLString.hpp" + +using namespace std; + +const char* TransformSimplifier::info () const { + return "try to simplify and shorten the values of 'transform' attributes"; +} + + +/** Tries to simplify the transform attributes of the context node and all its descendants. */ +void TransformSimplifier::execute (XMLElement *context) { + if (!context) + return; + if (const char *transform = context->getAttributeValue("transform")) { + Matrix matrix = Matrix::parseSVGTransform(transform); + if (!incorporateTransform(context, matrix)) { + string decomp = decompose(matrix); + if (decomp.length() > matrix.toSVG().length()) + context->addAttribute("transform", matrix.toSVG()); + else { + if (decomp.empty()) + context->removeAttribute("transform"); + else + context->addAttribute("transform", decomp); + } + } + } + // continue with child elements + for (XMLNode *child : *context) { + if (XMLElement *elem = child->toElement()) + execute(elem); + } +} + + +/** Tries to incorporate the translation and scaling components of the 'transform' attribute + * of a given element into the positional and/or size attributes of that element. If successful, + * the 'transform' attribute is removed. + * Currently, only 'image' and 'rect' elements are considered. + * @param[in] elem element to check + * @param[in] matrix matrix representing the 'transform' attribute of the element + * @return true on success */ +bool TransformSimplifier::incorporateTransform (XMLElement *elem, const Matrix &matrix) { + if ((elem->name() == "image" || elem->name() == "rect") && matrix.get(0, 1) == 0 && matrix.get(1, 0) == 0) { + double tx = matrix.get(0, 2); + double ty = matrix.get(1, 2); + double sx = matrix.get(0, 0); + double sy = matrix.get(1, 1); + if (const char *xstr = elem->getAttributeValue("x")) + tx += sx*strtod(xstr, nullptr); + if (const char *ystr = elem->getAttributeValue("y")) + ty += sy*strtod(ystr, nullptr); + if (const char *wstr = elem->getAttributeValue("width")) + elem->addAttribute("width", sx*strtod(wstr, nullptr)); + if (const char *hstr = elem->getAttributeValue("height")) + elem->addAttribute("height", sy*strtod(hstr, nullptr)); + elem->addAttribute("x", tx); // update x attribute + elem->addAttribute("y", ty); // update x attribute + elem->removeAttribute("transform"); + return true; + } + return false; +} + + +static string translate_cmd (double dx, double dy) { + string ret; + XMLString dxstr(dx), dystr(dy); + if (dxstr != "0" || dystr != "0") { + ret = "translate("+dxstr; + if (dystr != "0") + ret += " "+dystr; + ret += ')'; + } + return ret; +} + + +static string scale_cmd (double sx, double sy) { + string ret; + XMLString sxstr(sx), systr(sy); + if (sxstr != "1" || systr != "1") { + ret = "scale("+sxstr; + if (systr != "1") + ret += " "+systr; + ret += ')'; + } + return ret; +} + + +static string rotate_cmd (double rad) { + string ret; + XMLString degstr(math::rad2deg(fmod(rad, math::TWO_PI))); + if (degstr != "0") + ret = "rotate("+degstr+")"; + return ret; +} + + +static string skewx_cmd (double rad) { + string ret; + XMLString degstr(math::rad2deg(fmod(rad, math::PI))); + if (degstr != "0") + ret = "skewX("+degstr+")"; + return ret; +} + + +static string skewy_cmd (double rad) { + string ret; + XMLString degstr(math::rad2deg(fmod(rad, math::PI))); + if (degstr != "0") + ret = "skewY("+degstr+")"; + return ret; +} + + +static bool not_equal (double x, double y) { + return abs(x-y) >= 1e-6; +} + + +/** Decomposes a transformation matrix into a sequence of basic SVG transformations, i.e. + * translation, rotation, scaling, and skewing. The algorithm (QR-based decomposition) + * is taken from http://frederic-wang.fr/decomposition-of-2d-transform-matrices.html. + * @param[in] matrix matrix to decompose + * @return string containing the SVG transformation commands */ +string TransformSimplifier::decompose (const Matrix &matrix) { + // transformation matrix [a b c d e f] according to + // https://www.w3.org/TR/SVG11/coords.html#EstablishingANewUserSpace + double a = matrix.get(0, 0); + double b = matrix.get(1, 0); + double c = matrix.get(0, 1); + double d = matrix.get(1, 1); + double e = matrix.get(0, 2); + double f = matrix.get(1, 2); + string ret = translate_cmd(e, f); + double delta = a*d - b*c; + if (not_equal(a, 0) || not_equal(b, 0)) { + double r = sqrt(a*a + b*b); + ret += rotate_cmd(b > 0 ? acos(a/r) : -acos(a/r)); + ret += scale_cmd(r, delta/r); + ret += skewx_cmd(atan((a*c + b*d)/(r*r))); + } + else if (not_equal(c, 0) || not_equal(d, 0)) { + double s = sqrt(c*c + d*d); + ret += rotate_cmd(math::HALF_PI - (d > 0 ? acos(-c/s) : -acos(c/s))); + ret += scale_cmd(delta/s, s); + ret += skewy_cmd(atan((a*c + b*d)/(s*s))); + } + else + ret += scale_cmd(0, 0); + return ret; +} + diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/CRC32.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/TransformSimplifier.hpp index 880f8b737ef..c4b6d9ee16e 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/CRC32.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/TransformSimplifier.hpp @@ -1,5 +1,5 @@ /************************************************************************* -** CRC32.hpp ** +** TransformSimplifier.hpp ** ** ** ** This file is part of dvisvgm -- a fast DVI to SVG converter ** ** Copyright (C) 2005-2019 Martin Gieseking <martin.gieseking@uos.de> ** @@ -18,30 +18,20 @@ ** along with this program; if not, see <http://www.gnu.org/licenses/>. ** *************************************************************************/ -#ifndef CRC32_HPP -#define CRC32_HPP +#pragma once -#include <cstdlib> -#include <istream> +#include <string> +#include "OptimizerModule.hpp" -class CRC32 { +class Matrix; + +class TransformSimplifier : public OptimizerModule { public: - CRC32 (); - CRC32 (const CRC32 &crc32) =delete; - void update (const uint8_t *bytes, size_t len); - void update (uint32_t n, int bytes=4); - void update (const char *str); - void update (std::istream &is); - uint32_t get () const; - void reset (); - static uint32_t compute (const uint8_t *bytes, size_t len); - static uint32_t compute (const char *str); - static uint32_t compute (std::istream &is); + void execute (XMLElement*, XMLElement *context) override {execute(context);} + void execute (XMLElement *context); + const char* info () const override; - private: - uint32_t _crc32; - uint32_t _tab[256]; + protected: + bool incorporateTransform (XMLElement *elem, const Matrix &matrix); + std::string decompose (const Matrix &matrix); }; - - -#endif diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/WSNodeRemover.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/WSNodeRemover.cpp new file mode 100644 index 00000000000..2135e285bb6 --- /dev/null +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/WSNodeRemover.cpp @@ -0,0 +1,45 @@ +/************************************************************************* +** WSNodeRemover.cpp ** +** ** +** This file is part of dvisvgm -- a fast DVI to SVG converter ** +** Copyright (C) 2005-2019 Martin Gieseking <martin.gieseking@uos.de> ** +** ** +** 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 <http://www.gnu.org/licenses/>. ** +*************************************************************************/ + +#include "WSNodeRemover.hpp" +#include "../XMLNode.hpp" + +const char* WSNodeRemover::info () const { + return "remove redundant whitespace nodes"; +} + + +void WSNodeRemover::execute (XMLElement *context) { + if (!context) + return; + bool removeWS = context->name() != "text" && context->name() != "tspan"; + XMLNode *child = context->firstChild(); + while (child) { + if (removeWS && child->toWSNode()) { + XMLNode *next = child->next(); + XMLElement::remove(child); + child = next; + continue; + } + if (XMLElement *elem = child->toElement()) + execute(elem); + child = child->next(); + } +} diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/WSNodeRemover.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/WSNodeRemover.hpp new file mode 100644 index 00000000000..c4fe7f989e1 --- /dev/null +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/WSNodeRemover.hpp @@ -0,0 +1,30 @@ +/************************************************************************* +** WSNodeRemover.hpp ** +** ** +** This file is part of dvisvgm -- a fast DVI to SVG converter ** +** Copyright (C) 2005-2019 Martin Gieseking <martin.gieseking@uos.de> ** +** ** +** 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 <http://www.gnu.org/licenses/>. ** +*************************************************************************/ + +#pragma once + +#include "OptimizerModule.hpp" + +class WSNodeRemover : public OptimizerModule { + public: + void execute (XMLElement*, XMLElement *context) override {execute(context);}; + void execute (XMLElement *context); + const char* info () const override; +}; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/options.xml b/Build/source/texk/dvisvgm/dvisvgm-src/src/options.xml index 0764db3e5b8..27975f15910 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/options.xml +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/options.xml @@ -81,6 +81,10 @@ <arg type="string" name="style" default="box"/> <description>select how to mark hyperlinked areas</description> </option> + <option long="optimize" short="O"> + <arg name="modules" type="string" default="all" optional="yes"/> + <description>perform several SVG optimizations</description> + </option> <option long="output" short="o"> <arg type="string" name="pattern"/> <description>set name pattern of output files</description> @@ -141,8 +145,8 @@ <arg type="string" name="dir" optional="yes"/> <description>set/print path of cache directory</description> </option> - <option long="exact" short="e"> - <description>compute exact glyph boxes</description> + <option long="exact-bbox" short="e"> + <description>compute exact glyph bounding boxes</description> </option> <option long="keep"> <description>keep temporary files</description> diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/psdefs.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/psdefs.cpp index 5baf1a0bc0a..d38e2354e0a 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/psdefs.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/psdefs.cpp @@ -22,93 +22,103 @@ const char *PSInterpreter::PSDEFS = "<</Install{matrix setmatrix}/HWResolution[72 72]/PageSize[10000 10000]/Imaging" -"BBox null>>setpagedevice/@dodraw true store/@patcnt 0 store/@SD systemdict def" -"/@UD userdict def true setglobal @SD/:save @SD/save get put @SD/:restore @SD/r" -"estore get put @SD/:gsave @SD/gsave get put @SD/:grestore @SD/grestore get put" -" @SD/:grestoreall @SD/grestoreall get put @SD/:newpath @SD/newpath get put @SD" -"/:stroke @SD/stroke get put @SD/:fill @SD/fill get put @SD/:eofill @SD/eofill " -"get put @SD/:clip @SD/clip get put @SD/:eoclip @SD/eoclip get put @SD/:charpat" -"h @SD/charpath get put @SD/:show @SD/show get put @SD/:stringwidth @SD/stringw" -"idth get put @SD/.setopacityalpha known not{@SD/.setopacityalpha{pop}put}if @S" -"D/.setshapealpha known not{@SD/.setshapealpha{pop}put}if @SD/.setblendmode kno" -"wn not{@SD/.setblendmode{pop}put}if @SD/prseq{-1 1{-1 roll =only( )print}for(\\" -"n)print}put @SD/prcmd{( )exch(\\ndvi.)3{print}repeat prseq}put @SD/cvxall{{cvx" -"}forall}put @SD/defpr{[exch[/copy @SD]cvxall 5 -1 roll dup 6 1 roll[/get/exec]" -"cvxall 6 -1 roll dup 7 1 roll 4 -1 roll dup 5 1 roll dup length string cvs/prc" -"md cvx]cvx def}put @SD/querypos{{currentpoint}stopped{$error/newerror false pu" -"t}{2(querypos)prcmd}ifelse}put @SD/applyscalevals{1 0 dtransform exch dup mul " -"exch dup mul add sqrt 0 1 dtransform exch dup mul exch dup mul add sqrt 1 0 dt" -"ransform dup mul exch dup dup mul 3 -1 roll add dup 0 eq{pop}{sqrt div}ifelse " -"3(applyscalevals)prcmd}put @SD/prpath{{2(moveto)prcmd}{2(lineto)prcmd}{6(curve" -"to)prcmd}{0(closepath)prcmd}pathforall}put @SD/charpath{/@dodraw false store :" -"charpath/@dodraw true store}put @SD/stringwidth{/@dodraw false store :stringwi" -"dth/@dodraw true store}put @SD/show{@dodraw{dup :gsave currentpoint 2{50 mul e" -"xch}repeat :newpath moveto 50 50/scale sysexec true charpath fill :grestore/@d" -"odraw false store :show/@dodraw true store}{:show}ifelse}put @SD/awidthshow{{1" -" string dup 0 5 index put :gsave show :grestore pop 0 rmoveto 3 index eq{4 ind" -"ex 4 index rmoveto}if 1 index 1 index rmoveto}exch cshow 5{pop}repeat}put @SD/" -"widthshow{0 0 3 -1 roll pstack awidthshow}put @SD/ashow{0 0 0 6 3 roll awidths" -"how}put @SD/newpath{:newpath 1 1(newpath)prcmd}put @SD/stroke{@dodraw{prcolor " -"0 1(newpath)prcmd prpath 0(stroke)prcmd :newpath}{:stroke}ifelse}put @SD/fill{" -"@dodraw{prcolor 0 1(newpath)prcmd prpath 0(fill)prcmd :newpath}{:fill}ifelse}p" -"ut @SD/eofill{@dodraw{prcolor 0 1(newpath)prcmd prpath 0(eofill)prcmd :newpath" -"}{:eofill}ifelse}put @SD/clip{:clip 0 1(newpath)prcmd prpath 0(clip)prcmd}put " -"@SD/eoclip{:eoclip 0 1(newpath)prcmd prpath 0(eoclip)prcmd}put @SD/shfill{begi" -"n currentdict/ShadingType known currentdict/ColorSpace known and currentdict/D" -"ataSource known and currentdict/Function known not and ShadingType 4 ge and Da" -"taSource type/arraytype eq and{<</DeviceGray 1/DeviceRGB 3/DeviceCMYK 4/bgknow" -"n currentdict/Background known/bbknown currentdict/BBox known>>begin currentdi" -"ct ColorSpace known{ShadingType ColorSpace load bgknown{1 Background aload pop" -"}{0}ifelse bbknown{1 BBox aload pop}{0}ifelse ShadingType 5 eq{VerticesPerRow}" -"if DataSource aload length 4 add bgknown{ColorSpace load add}if bbknown{4 add}" -"if ShadingType 5 eq{1 add}if(shfill)prcmd}if end}if end}put/@rect{4 -2 roll mo" -"veto exch dup 0 rlineto exch 0 exch rlineto neg 0 rlineto closepath}bind def/@" -"rectcc{4 -2 roll moveto 2 copy 0 lt exch 0 lt xor{dup 0 exch rlineto exch 0 rl" -"ineto neg 0 exch rlineto}{exch dup 0 rlineto exch 0 exch rlineto neg 0 rlineto" -"}ifelse closepath}bind def @SD/rectclip{:newpath dup type/arraytype eq{aload l" -"ength 4 idiv{@rectcc}repeat}{@rectcc}ifelse clip :newpath}put @SD/rectfill{gsa" -"ve :newpath dup type/arraytype eq{aload length 4 idiv{@rectcc}repeat}{@rectcc}" -"ifelse fill grestore}put @SD/rectstroke{gsave :newpath dup type/arraytype eq{a" -"load length 4 idiv{@rect}repeat}{@rect}ifelse stroke grestore}put false setglo" -"bal @SD readonly pop/initclip 0 defpr/clippath 0 defpr/sysexec{@SD exch get ex" -"ec}def/adddot{dup length 1 add string dup 0 46 put dup 3 -1 roll 1 exch putint" -"erval}def/setlinewidth{dup/setlinewidth sysexec 1(setlinewidth)prcmd}def/setli" -"necap 1 defpr/setlinejoin 1 defpr/setmiterlimit 1 defpr/setdash{mark 3 1 roll " -"2 copy/setdash sysexec exch aload length 1 add -1 roll counttomark(setdash)prc" -"md pop}def/@setpagedevice{pop<<>>/setpagedevice sysexec matrix setmatrix newpa" -"th 0(setpagedevice)prcmd}def/prcolor{currentrgbcolor 3(setrgbcolor)prcmd}def/p" -"rintgstate{@dodraw{matrix currentmatrix aload pop 6(setmatrix)prcmd applyscale" -"vals currentlinewidth 1(setlinewidth)prcmd currentlinecap 1(setlinecap)prcmd c" -"urrentlinejoin 1(setlinejoin)prcmd currentmiterlimit 1(setmiterlimit)prcmd cur" -"rentrgbcolor 3(setrgbcolor)prcmd currentdash mark 3 1 roll exch aload length 1" -" add -1 roll counttomark(setdash)prcmd pop}if}def/setgstate{/setgstate sysexec" -" printgstate}def/save{@UD begin/@saveID vmstatus pop pop def end :save @saveID" -" 1(save)prcmd}def/restore{:restore printgstate @UD/@saveID known{@UD begin @sa" -"veID end}{0}ifelse 1(restore)prcmd}def/gsave 0 defpr/grestore{:grestore printg" -"state 0(grestore)prcmd}def/grestoreall{:grestoreall setstate 0(grestoreall)prc" -"md}def/rotate{dup type/arraytype ne @dodraw and{dup 1(rotate)prcmd}if/rotate s" -"ysexec applyscalevals}def/scale{dup type/arraytype ne @dodraw and{2 copy 2(sca" -"le)prcmd}if/scale sysexec applyscalevals}def/translate{dup type/arraytype ne @" -"dodraw and{2 copy 2(translate)prcmd}if/translate sysexec}def/setmatrix{dup/set" -"matrix sysexec @dodraw{aload pop 6(setmatrix)prcmd applyscalevals}if}def/initm" -"atrix{matrix setmatrix}def/concat{matrix currentmatrix matrix concatmatrix set" -"matrix}def/makepattern{gsave<</mx 3 -1 roll>>begin dup/XUID[1000000 @patcnt]pu" -"t mx/makepattern sysexec dup dup begin PatternType @patcnt BBox aload pop XSte" -"p YStep PaintType mx aload pop 15(makepattern)prcmd :newpath matrix setmatrix " -"PaintProc 0 1(makepattern)prcmd end/@patcnt @patcnt 1 add store end grestore}d" -"ef/setpattern{begin PatternType 1 eq{PaintType 1 eq{XUID aload pop exch pop 1}" -"{:gsave[currentcolorspace aload length -1 roll pop]setcolorspace/setcolor syse" -"xec XUID aload pop exch pop currentrgbcolor :grestore 4}ifelse(setpattern)prcm" -"d}{/setpattern sysexec}ifelse end}def/setcolor{dup type/dicttype eq{setpattern" -"}{/setcolor sysexec/currentrgbcolor sysexec setrgbcolor}ifelse}def/setgray 1 d" -"efpr/setcmykcolor 4 defpr/sethsbcolor 3 defpr/setrgbcolor 3 defpr/.setopacitya" -"lpha{dup/.setopacityalpha sysexec 1(setopacityalpha)prcmd}def/.setshapealpha{d" -"up/.setshapealpha sysexec 1(setshapealpha)prcmd}def/.setblendmode{dup/.setblen" -"dmode sysexec<</Normal 0/Compatible 0/Multiply 1/Screen 2/Overlay 3/SoftLight " -"4/HardLight 5/ColorDodge 6/ColorBurn 7/Darken 8/Lighten 9/Difference 10/Exclus" -"ion 11/Hue 12/Saturation 13/Color 14/Luminosity 15/CompatibleOverprint 16>>exc" -"h get 1(setblendmode)prcmd}def/@pdfpagecount{GS_PDF_ProcSet begin pdfdict begi" -"n(r)file pdfopen begin pdfpagecount currentdict pdfclose end end end}def/@pdfp" -"agebox{GS_PDF_ProcSet begin pdfdict begin(r)file pdfopen begin dup dup 1 lt ex" -"ch pdfpagecount gt or{pop}{pdfgetpage/MediaBox pget pop aload pop}ifelse curre" -"ntdict pdfclose end end end}def DELAYBIND{.bindnow}if "; +"BBox null>>setpagedevice/@dodraw true store/@nulldev false store/@patcnt 0 sto" +"re/@SD systemdict def/@UD userdict def true setglobal @SD/:save @SD/save get p" +"ut @SD/:restore @SD/restore get put @SD/:gsave @SD/gsave get put @SD/:grestore" +" @SD/grestore get put @SD/:grestoreall @SD/grestoreall get put @SD/:newpath @S" +"D/newpath get put @SD/:stroke @SD/stroke get put @SD/:fill @SD/fill get put @S" +"D/:eofill @SD/eofill get put @SD/:clip @SD/clip get put @SD/:eoclip @SD/eoclip" +" get put @SD/:charpath @SD/charpath get put @SD/:show @SD/show get put @SD/:st" +"ringwidth @SD/stringwidth get put @SD/:nulldevice @SD/nulldevice get put @SD/." +"setopacityalpha known not{@SD/.setopacityalpha{pop}put}if @SD/.setshapealpha k" +"nown not{@SD/.setshapealpha{pop}put}if @SD/.setblendmode known not{@SD/.setble" +"ndmode{pop}put}if @SD/prseq{-1 1{-1 roll =only( )print}for(\\n)print}put @SD/p" +"rcmd{( )exch(\\ndvi.)3{print}repeat prseq}put @SD/cvxall{{cvx}forall}put @SD/d" +"efpr{[exch[/copy @SD]cvxall 5 -1 roll dup 6 1 roll[/get/exec]cvxall 6 -1 roll " +"dup 7 1 roll 4 -1 roll dup 5 1 roll dup length string cvs/prcmd cvx]cvx def}pu" +"t @SD/querypos{{currentpoint}stopped{$error/newerror false put}{2(querypos)prc" +"md}ifelse}put @SD/applyscalevals{1 0 dtransform exch dup mul exch dup mul add " +"sqrt 0 1 dtransform exch dup mul exch dup mul add sqrt 1 0 dtransform dup mul " +"exch dup dup mul 3 -1 roll add dup 0 eq{pop}{sqrt div}ifelse 3(applyscalevals)" +"prcmd}put @SD/prpath{{2(moveto)prcmd}{2(lineto)prcmd}{6(curveto)prcmd}{0(close" +"path)prcmd}pathforall}put @SD/nulldevice{/@nulldev true store :nulldevice 1 1(" +"setnulldevice)prcmd}put @SD/charpath{/@dodraw false store :charpath/@dodraw tr" +"ue store}put @SD/stringwidth{/@dodraw false store :stringwidth/@dodraw true st" +"ore}put @SD/show{@dodraw @nulldev not and{dup :gsave currentpoint 2{50 mul exc" +"h}repeat :newpath moveto 50 50/scale sysexec true charpath fill :grestore/@dod" +"raw false store :show/@dodraw true store}{:show}ifelse}put @SD/varxyshow{exch " +"dup type/arraytype eq{<</arr 3 -1 roll/prc 5 -1 roll/chr 1 string/idx 0>>begin" +"{chr 0 3 -1 roll put :gsave chr show :grestore currentpoint prc moveto/idx idx" +" 1 add store}forall end}{pop show}ifelse}put @SD/xyshow{{exch arr idx 2 mul ge" +"t add exch arr idx 2 mul 1 add get add}varxyshow}put @SD/xshow{{exch arr idx g" +"et add exch}varxyshow}put @SD/yshow{{arr idx get add}varxyshow}put @SD/awidths" +"how{{1 string dup 0 5 index put :gsave show :grestore pop 0 rmoveto 3 index eq" +"{4 index 4 index rmoveto}if 1 index 1 index rmoveto}exch cshow 5{pop}repeat}pu" +"t @SD/widthshow{0 0 3 -1 roll pstack awidthshow}put @SD/ashow{0 0 0 6 3 roll a" +"widthshow}put @SD/newpath{:newpath 1 1(newpath)prcmd}put @SD/stroke{@dodraw @n" +"ulldev not and{prcolor 0 1(newpath)prcmd prpath 0(stroke)prcmd :newpath}{:stro" +"ke}ifelse}put @SD/fill{@dodraw @nulldev not and{prcolor 0 1(newpath)prcmd prpa" +"th 0(fill)prcmd :newpath}{:fill}ifelse}put @SD/eofill{@dodraw @nulldev not and" +"{prcolor 0 1(newpath)prcmd prpath 0(eofill)prcmd :newpath}{:eofill}ifelse}put " +"@SD/clip{:clip @nulldev not{0 1(newpath)prcmd prpath 0(clip)prcmd}if}put @SD/e" +"oclip{:eoclip @nulldev not{0 1(newpath)prcmd prpath 0(eoclip)prcmd}}put @SD/sh" +"fill{begin currentdict/ShadingType known currentdict/ColorSpace known and curr" +"entdict/DataSource known and currentdict/Function known not and ShadingType 4 " +"ge and DataSource type/arraytype eq and{<</DeviceGray 1/DeviceRGB 3/DeviceCMYK" +" 4/bgknown currentdict/Background known/bbknown currentdict/BBox known>>begin " +"currentdict ColorSpace known{ShadingType ColorSpace load bgknown{1 Background " +"aload pop}{0}ifelse bbknown{1 BBox aload pop}{0}ifelse ShadingType 5 eq{Vertic" +"esPerRow}if DataSource aload length 4 add bgknown{ColorSpace load add}if bbkno" +"wn{4 add}if ShadingType 5 eq{1 add}if(shfill)prcmd}if end}if end}put/@rect{4 -" +"2 roll moveto exch dup 0 rlineto exch 0 exch rlineto neg 0 rlineto closepath}b" +"ind def/@rectcc{4 -2 roll moveto 2 copy 0 lt exch 0 lt xor{dup 0 exch rlineto " +"exch 0 rlineto neg 0 exch rlineto}{exch dup 0 rlineto exch 0 exch rlineto neg " +"0 rlineto}ifelse closepath}bind def @SD/rectclip{:newpath dup type/arraytype e" +"q{aload length 4 idiv{@rectcc}repeat}{@rectcc}ifelse clip :newpath}put @SD/rec" +"tfill{gsave :newpath dup type/arraytype eq{aload length 4 idiv{@rectcc}repeat}" +"{@rectcc}ifelse fill grestore}put @SD/rectstroke{gsave :newpath dup type/array" +"type eq{aload length 4 idiv{@rect}repeat}{@rect}ifelse stroke grestore}put fal" +"se setglobal @SD readonly pop/initclip 0 defpr/clippath 0 defpr/sysexec{@SD ex" +"ch get exec}def/adddot{dup length 1 add string dup 0 46 put dup 3 -1 roll 1 ex" +"ch putinterval}def/setlinewidth{dup/setlinewidth sysexec 1(setlinewidth)prcmd}" +"def/setlinecap 1 defpr/setlinejoin 1 defpr/setmiterlimit 1 defpr/setdash{mark " +"3 1 roll 2 copy/setdash sysexec exch aload length 1 add -1 roll counttomark(se" +"tdash)prcmd pop}def/@setpagedevice{pop<<>>/setpagedevice sysexec matrix setmat" +"rix newpath 0(setpagedevice)prcmd}def/@checknulldev{@nulldev{currentpagedevice" +" maxlength 0 ne{/@nulldev false store 0 1(setnulldevice)prcmd}if}if}def/prcolo" +"r{currentrgbcolor 3(setrgbcolor)prcmd}def/printgstate{@dodraw @nulldev not and" +"{matrix currentmatrix aload pop 6(setmatrix)prcmd applyscalevals currentlinewi" +"dth 1(setlinewidth)prcmd currentlinecap 1(setlinecap)prcmd currentlinejoin 1(s" +"etlinejoin)prcmd currentmiterlimit 1(setmiterlimit)prcmd currentrgbcolor 3(set" +"rgbcolor)prcmd currentdash mark 3 1 roll exch aload length 1 add -1 roll count" +"tomark(setdash)prcmd pop}if}def/setgstate{/setgstate sysexec printgstate}def/s" +"ave{@UD begin/@saveID vmstatus pop pop def end :save @saveID 1(save)prcmd}def/" +"restore{:restore @checknulldev printgstate @UD/@saveID known{@UD begin @saveID" +" end}{0}ifelse 1(restore)prcmd}def/gsave 0 defpr/grestore{:grestore @checknull" +"dev printgstate 0(grestore)prcmd}def/grestoreall{:grestoreall @checknulldev se" +"tstate 0(grestoreall)prcmd}def/rotate{dup type/arraytype ne @dodraw and{dup 1(" +"rotate)prcmd}if/rotate sysexec applyscalevals}def/scale{dup type/arraytype ne " +"@dodraw and{2 copy 2(scale)prcmd}if/scale sysexec applyscalevals}def/translate" +"{dup type/arraytype ne @dodraw and{2 copy 2(translate)prcmd}if/translate sysex" +"ec}def/setmatrix{dup/setmatrix sysexec @dodraw{aload pop 6(setmatrix)prcmd app" +"lyscalevals}{pop}ifelse}def/initmatrix{matrix setmatrix}def/concat{matrix curr" +"entmatrix matrix concatmatrix setmatrix}def/makepattern{gsave<</mx 3 -1 roll>>" +"begin dup/XUID[1000000 @patcnt]put mx/makepattern sysexec dup dup begin Patter" +"nType @patcnt BBox aload pop XStep YStep PaintType mx aload pop 15(makepattern" +")prcmd :newpath matrix setmatrix PaintProc 0 1(makepattern)prcmd end/@patcnt @" +"patcnt 1 add store end grestore}def/setpattern{begin PatternType 1 eq{PaintTyp" +"e 1 eq{XUID aload pop exch pop 1}{:gsave[currentcolorspace aload length -1 rol" +"l pop]setcolorspace/setcolor sysexec XUID aload pop exch pop currentrgbcolor :" +"grestore 4}ifelse(setpattern)prcmd}{/setpattern sysexec}ifelse end}def/setcolo" +"r{dup type/dicttype eq{setpattern}{/setcolor sysexec/currentrgbcolor sysexec s" +"etrgbcolor}ifelse}def/setgray 1 defpr/setcmykcolor 4 defpr/sethsbcolor 3 defpr" +"/setrgbcolor 3 defpr/.setopacityalpha{dup/.setopacityalpha sysexec 1(setopacit" +"yalpha)prcmd}def/.setshapealpha{dup/.setshapealpha sysexec 1(setshapealpha)prc" +"md}def/.setblendmode{dup/.setblendmode sysexec<</Normal 0/Compatible 0/Multipl" +"y 1/Screen 2/Overlay 3/SoftLight 4/HardLight 5/ColorDodge 6/ColorBurn 7/Darken" +" 8/Lighten 9/Difference 10/Exclusion 11/Hue 12/Saturation 13/Color 14/Luminosi" +"ty 15/CompatibleOverprint 16>>exch get 1(setblendmode)prcmd}def/@pdfpagecount{" +"(r)file runpdfbegin pdfpagecount runpdfend}def/@pdfpagebox{(r)file runpdfbegin" +" dup dup 1 lt exch pdfpagecount gt or{pop}{pdfgetpage/MediaBox pget pop aload " +"pop}ifelse runpdfend}def DELAYBIND{.bindnow}if "; + diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/utility.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/utility.cpp index 99e8e194a02..f1ae59ec08e 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/utility.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/utility.cpp @@ -20,6 +20,7 @@ #include <algorithm> #include <cctype> +#include <cmath> #include <fstream> #include <functional> #include <iterator> @@ -27,6 +28,56 @@ using namespace std; +/** Computes the singular value decomposition of a given 2x2 matrix M + * so that M = rotate(phi)*scale(sx,sy)*rotate(theta), where + * rotate(t):={{cos t, -sin t}, {sin t, cos t}} and scale(sx, sy):={{sx, 0}, {0, sy}}. + * The corresponding math can be found in Jim Blinn: "Consider the Lowly 2x2 Matrix" + * https://ieeexplore.ieee.org/document/486688 + * Also published in "Jim Blinn's Corner: Notation, Notation, Notation", pp. 69--95. + * @param[in] m matrix {{m00, m01}, {m10, m11}} where the inner pairs denote the rows + * @return vector {phi, sx, sy, theta} */ +vector<double> math::svd (const double (&m)[2][2]) { + double phi=0, theta=0, sx=0, sy=0; + if (m[0][0] != 0 || m[0][1] != 0 || m[1][0] != 0 || m[1][1] != 0) { + double e = (m[0][0] + m[1][1])/2; // = cos(phi+theta)*(sx+sy)/2 + double f = (m[0][0] - m[1][1])/2; // = cos(phi-theta)*(sx-sy)/2 + double g = (m[1][0] + m[0][1])/2; // = sin(phi-theta)*(sx-sy)/2 + double h = (m[1][0] - m[0][1])/2; // = sin(phi+theta)*(sx+sy)/2 + double hyp1 = hypot(e, h); // = (sx+sy)/2 + double hyp2 = hypot(f, g); // = (sx-sy)/2 + sx = hyp1+hyp2; + sy = hyp1-hyp2; + if (hyp2 == 0) // uniformly scaled rotation? + theta = atan2(h, e); + else if (hyp1 == 0) // uniformly scaled reflection? + theta = -atan2(g, f); + else { + double a1 = atan2(g, f); // = phi-theta (g/f = tan(phi-theta)) + double a2 = atan2(h, e); // = phi+theta (h/e = tan(phi+theta)) + phi = (a2+a1)/2; + theta = (a2-a1)/2; + } + } + return vector<double>{phi, sx, sy, theta}; +} + + +/** Normalizes an angle to the interval [-mod, mod). */ +double math::normalize_angle (double angle, double mod) { + angle = fmod(angle+mod, 2.0*mod); + if (angle < 0) + angle += 2.0*mod; + return angle-mod; +} + + +double math::normalize_0_2pi (double rad) { + rad = fmod(rad, TWO_PI); + if (rad < 0) + rad += TWO_PI; + return rad; +} + /** Returns a given string with leading and trailing whitespace removed. * @param[in] str the string to process @@ -109,6 +160,20 @@ string util::tolower (const string &str) { } +/** Converts a double to a string and strips redundant trailing digits/dots. */ +string util::to_string (double val) { + string str = std::to_string(val); + if (str.find('.') != string::npos) { // double value and not an integer? + size_t pos = str.find_last_not_of('0'); + if (pos != string::npos) // trailing zeros + str.erase(pos+1, string::npos); + if (str.back() == '.') // trailing dot? + str.pop_back(); + } + return str; +} + + /** Returns the integer part of log10 of a given integer \f$n>0\f$. * If \f$n<0\f$, the result is 0. */ int util::ilog10 (int n) { diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/utility.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/utility.hpp index 905e4150dd5..7127280284a 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/utility.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/utility.hpp @@ -35,6 +35,14 @@ constexpr const double TWO_PI = 6.283185307179586476925286766559005768; constexpr const double SQRT2 = 1.414213562373095048801688724209698079; inline double deg2rad (double deg) {return PI*deg/180.0;} +inline double rad2deg (double rad) {return 180.0*rad/PI;} +double normalize_angle (double angle, double mod); +double normalize_0_2pi (double rad); +std::vector<double> svd (const double (&m)[2][2]); + +/** Signum function (returns x/abs(x) if x != 0, and 0 otherwise). */ +template <typename T> +inline int sgn (T x) {return (x > T(0)) - (x < T(0));} } // namespace math @@ -51,12 +59,31 @@ std::string trim (const std::string &str, const char *ws=" \t\n\r\f"); std::string normalize_space (std::string str, const char *ws=" \t\n\r\f"); std::string tolower (const std::string &str); std::string replace (std::string str, const std::string &find, const std::string &repl); +std::string to_string (double val); std::vector<std::string> split (const std::string &str, const std::string &sep); int ilog10 (int n); std::string read_file_contents (const std::string &fname); void write_file_contents (const std::string &fname, std::string::iterator start, std::string::iterator end); + +/** Returns a sequence of bytes of a given integral value. + * @param[in] val get bytes of this value + * @param[in] n number of bytes to extract (from LSB to MSB), all if n == 0 + * @return vector of bytes in big-endian order */ +template <typename T> +std::vector<uint8_t> bytes (T val, int n=0) { + if (n <= 0) + n = sizeof(T); + std::vector<uint8_t> ret(n); + for (int i=0; i < n; i++) { + ret[n-i-1] = val & 0xff; + val >>= 8; + } + return ret; +} + + /** Encodes the bytes in the half-open range [first,last) to Base64 and writes * the result to the range starting at 'dest'. * @param[in] first initial position of the range to be encoded diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/version.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/version.hpp index 22305f75f2b..59320fa6d2d 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/version.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/version.hpp @@ -22,7 +22,7 @@ #define VERSION_HPP constexpr const char *PROGRAM_NAME = "dvisvgm"; -constexpr const char *PROGRAM_VERSION = "2.6.3"; +constexpr const char *PROGRAM_VERSION = "2.8.1"; #endif diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/tests/BezierTest.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/tests/BezierTest.cpp index e657b9033cf..0c6ae700741 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/tests/BezierTest.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/tests/BezierTest.cpp @@ -108,9 +108,7 @@ TEST(BezierTest, reverse) { TEST(BezierTest, bbox) { Bezier bezier(DPair(0,0), DPair(12,12), DPair(24,6), DPair(30,-5)); - BoundingBox bbox; - bezier.getBBox(bbox); - EXPECT_BBOX_NEAR(bbox, BoundingBox(0, -5, 30, 6.598)); + EXPECT_BBOX_NEAR(bezier.getBBox(), BoundingBox(0, -5, 30, 6.598)); } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/tests/BoundingBoxTest.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/tests/BoundingBoxTest.cpp index 08e58f1b38e..31d23fe5717 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/tests/BoundingBoxTest.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/tests/BoundingBoxTest.cpp @@ -191,7 +191,7 @@ TEST(BoundingBoxTest, svgRectElement) { BoundingBox bbox(4, 5, 6, 7); auto rect = bbox.createSVGRect(); ASSERT_NE(rect, nullptr); - EXPECT_EQ(rect->getName(), "rect"); + EXPECT_EQ(rect->name(), "rect"); EXPECT_EQ(string(rect->getAttributeValue("x")), "4"); EXPECT_EQ(string(rect->getAttributeValue("y")), "5"); EXPECT_EQ(string(rect->getAttributeValue("width")), "2"); diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/tests/CMapReaderTest.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/tests/CMapReaderTest.cpp index 06836c4abc4..7e64d6d4e59 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/tests/CMapReaderTest.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/tests/CMapReaderTest.cpp @@ -73,6 +73,11 @@ const char *CMapReaderTest::cmapsrc = "<5833> <5834> <8c86>\n" "<5837> <5838> <8c9b>\n" "endbfrange\n" +"3 begincidchar\n" +"<1000> 50\n" +"<1005> 60\n" +"<1008> 70\n" +"endcidchar\n" "2 begincidrange\n" "<1234> <1240> 100\n" "<1300> <1302> 200\n" @@ -109,7 +114,11 @@ TEST_F(CMapReaderTest, cid) { const SegmentedCMap *seg_cmap = dynamic_cast<const SegmentedCMap*>(cmap.get()); ASSERT_NE(seg_cmap, nullptr); ASSERT_EQ(seg_cmap->numBFRanges(), 9u); - ASSERT_EQ(seg_cmap->numCIDRanges(), 2u); + ASSERT_EQ(seg_cmap->numCIDRanges(), 5u); + ASSERT_EQ(seg_cmap->cid(0x1000), 50u); + ASSERT_EQ(seg_cmap->cid(0x1005), 60u); + ASSERT_EQ(seg_cmap->cid(0x1008), 70u); + ASSERT_EQ(seg_cmap->cid(0x1233), 0u); ASSERT_EQ(seg_cmap->cid(0x1234), 100u); ASSERT_EQ(seg_cmap->cid(0x1240), 112u); diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/tests/CommandLineTest.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/tests/CommandLineTest.cpp index 710981309e9..5e10af84325 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/tests/CommandLineTest.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/tests/CommandLineTest.cpp @@ -95,7 +95,7 @@ TEST(CommandLineTest, arg_combined) { EXPECT_EQ(cmd.pageOpt.value(), "5"); EXPECT_TRUE(cmd.listSpecialsOpt.given()); EXPECT_TRUE(cmd.stdoutOpt.given()); - EXPECT_TRUE(cmd.exactOpt.given()); + EXPECT_TRUE(cmd.exactBboxOpt.given()); // can't combine short options that accept optional parameters const char *args2[] = {"progname", "-nls", "-p5", "-omyfile.xyz"}; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/tests/DVIReaderTest.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/tests/DVIReaderTest.cpp index 9eb2fd52818..572c1f8397c 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/tests/DVIReaderTest.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/tests/DVIReaderTest.cpp @@ -175,7 +175,7 @@ static void test_dvi_file (const char *fname, const vector<const char*> &expecte ASSERT_FALSE(ss.eof()); ss.getline(line, 512); lineno++; - ASSERT_EQ(line, expected_line) << "log line #" << lineno; + EXPECT_EQ(line, expected_line) << "log line #" << lineno; } ss.getline(line, 512); EXPECT_EQ(*line, '\0'); @@ -241,7 +241,7 @@ TEST(DVIReaderTest, dvi_v2) { "setchar0 103 [h=174.789, v=62.765, x=0, y=0, w=3.321, z=0, d=0]", "setchar0 101 [h=179.217, v=62.765, x=0, y=0, w=3.321, z=0, d=0]", "setchar0 110 [h=184.752, v=62.765, x=0, y=0, w=3.321, z=0, d=0]", - "right -0.277 [h=184.475, v=62.765, x=0, y=0, w=3.321, z=0, d=0]", + "right -.277 [h=184.475, v=62.765, x=0, y=0, w=3.321, z=0, d=0]", "setchar0 116 [h=188.35, v=62.765, x=0, y=0, w=3.321, z=0, d=0]", "setchar0 97 [h=193.331, v=62.765, x=0, y=0, w=3.321, z=0, d=0]", "xxx 'color pop' [h=193.331, v=62.765, x=0, y=0, w=3.321, z=0, d=0]", @@ -287,7 +287,7 @@ TEST(DVIReaderTest, dvi_v2) { "pop [h=143.822, v=107.402, x=0, y=0, w=3.321, z=0, d=0]", "right 37.446 [h=181.268, v=107.402, x=0, y=0, w=3.321, z=0, d=0]", "setchar0 119 [h=188.463, v=107.402, x=0, y=0, w=3.321, z=0, d=0]", - "right -0.277 [h=188.187, v=107.402, x=0, y=0, w=3.321, z=0, d=0]", + "right -.277 [h=188.187, v=107.402, x=0, y=0, w=3.321, z=0, d=0]", "setchar0 111 [h=193.168, v=107.402, x=0, y=0, w=3.321, z=0, d=0]", "setchar0 114 [h=197.07, v=107.402, x=0, y=0, w=3.321, z=0, d=0]", "setchar0 100 [h=202.605, v=107.402, x=0, y=0, w=3.321, z=0, d=0]", @@ -298,7 +298,7 @@ TEST(DVIReaderTest, dvi_v2) { "push [h=61.768, v=160.275, x=0, y=0, w=0, z=0, d=0]", "push [h=61.768, v=160.275, x=0, y=0, w=0, z=0, d=0]", "down -31.154 [h=61.768, v=129.121, x=0, y=0, w=0, z=0, d=0]", - "putrule 0.797, 220.922 [h=61.768, v=129.121, x=0, y=0, w=0, z=0, d=0]", + "putrule .797, 220.922 [h=61.768, v=129.121, x=0, y=0, w=0, z=0, d=0]", "y 11.157 [h=61.768, v=140.278, x=0, y=11.157, w=0, z=0, d=0]", "push [h=61.768, v=140.278, x=0, y=11.157, w=0, z=0, d=0]", "push [h=61.768, v=140.278, x=0, y=11.157, w=0, z=0, d=0]", @@ -333,7 +333,7 @@ TEST(DVIReaderTest, dvi_v2) { "pop [h=61.768, v=140.278, x=0, y=11.157, w=0, z=0, d=0]", "pop [h=61.768, v=140.278, x=0, y=11.157, w=0, z=0, d=0]", "down 5.8 [h=61.768, v=146.078, x=0, y=11.157, w=0, z=0, d=0]", - "putrule 0.498, 220.922 [h=61.768, v=146.078, x=0, y=11.157, w=0, z=0, d=0]", + "putrule .498, 220.922 [h=61.768, v=146.078, x=0, y=11.157, w=0, z=0, d=0]", "y0 [h=61.768, v=157.235, x=0, y=11.157, w=0, z=0, d=0]", "push [h=61.768, v=157.235, x=0, y=11.157, w=0, z=0, d=0]", "push [h=61.768, v=157.235, x=0, y=11.157, w=0, z=0, d=0]", @@ -419,11 +419,11 @@ TEST(DVIReaderTest, dvi_v2) { "setchar0 110 [h=115.401, v=181.145, x=0, y=11.955, w=3.321, z=0, d=0]", "setchar0 111 [h=120.382, v=181.145, x=0, y=11.955, w=3.321, z=0, d=0]", "setchar0 110 [h=125.917, v=181.145, x=0, y=11.955, w=3.321, z=0, d=0]", - "w -0.277 [h=125.64, v=181.145, x=0, y=11.955, w=-0.277, z=0, d=0]", - "setchar0 117 [h=131.175, v=181.145, x=0, y=11.955, w=-0.277, z=0, d=0]", - "setchar0 109 [h=139.477, v=181.145, x=0, y=11.955, w=-0.277, z=0, d=0]", - "w0 [h=139.2, v=181.145, x=0, y=11.955, w=-0.277, z=0, d=0]", - "setchar0 121 [h=144.458, v=181.145, x=0, y=11.955, w=-0.277, z=0, d=0]", + "w -.277 [h=125.64, v=181.145, x=0, y=11.955, w=-.277, z=0, d=0]", + "setchar0 117 [h=131.175, v=181.145, x=0, y=11.955, w=-.277, z=0, d=0]", + "setchar0 109 [h=139.477, v=181.145, x=0, y=11.955, w=-.277, z=0, d=0]", + "w0 [h=139.2, v=181.145, x=0, y=11.955, w=-.277, z=0, d=0]", + "setchar0 121 [h=144.458, v=181.145, x=0, y=11.955, w=-.277, z=0, d=0]", "pop [h=61.768, v=181.145, x=0, y=11.955, w=0, z=0, d=0]", "push [h=61.768, v=181.145, x=0, y=11.955, w=0, z=0, d=0]", "right 110.558 [h=172.326, v=181.145, x=0, y=11.955, w=0, z=0, d=0]", @@ -432,31 +432,31 @@ TEST(DVIReaderTest, dvi_v2) { "setchar0 114 [h=183.423, v=181.145, x=0, y=11.955, w=0, z=0, d=0]", "setchar0 109 [h=191.726, v=181.145, x=0, y=11.955, w=0, z=0, d=0]", "setchar0 111 [h=196.707, v=181.145, x=0, y=11.955, w=0, z=0, d=0]", - "w 0.277 [h=196.984, v=181.145, x=0, y=11.955, w=0.277, z=0, d=0]", - "setchar0 100 [h=202.519, v=181.145, x=0, y=11.955, w=0.277, z=0, d=0]", - "x 3.321 [h=205.84, v=181.145, x=3.321, y=11.955, w=0.277, z=0, d=0]", - "setchar0 116 [h=209.714, v=181.145, x=3.321, y=11.955, w=0.277, z=0, d=0]", - "setchar0 101 [h=214.142, v=181.145, x=3.321, y=11.955, w=0.277, z=0, d=0]", - "setchar0 109 [h=222.444, v=181.145, x=3.321, y=11.955, w=0.277, z=0, d=0]", - "setchar0 112 [h=227.979, v=181.145, x=3.321, y=11.955, w=0.277, z=0, d=0]", - "w0 [h=228.256, v=181.145, x=3.321, y=11.955, w=0.277, z=0, d=0]", - "setchar0 111 [h=233.237, v=181.145, x=3.321, y=11.955, w=0.277, z=0, d=0]", - "setchar0 114 [h=237.139, v=181.145, x=3.321, y=11.955, w=0.277, z=0, d=0]", - "x0 [h=240.46, v=181.145, x=3.321, y=11.955, w=0.277, z=0, d=0]", - "setchar0 105 [h=243.227, v=181.145, x=3.321, y=11.955, w=0.277, z=0, d=0]", - "setchar0 110 [h=248.762, v=181.145, x=3.321, y=11.955, w=0.277, z=0, d=0]", - "w -0.277 [h=248.485, v=181.145, x=3.321, y=11.955, w=-0.277, z=0, d=0]", - "setchar0 118 [h=253.743, v=181.145, x=3.321, y=11.955, w=-0.277, z=0, d=0]", - "setchar0 105 [h=256.511, v=181.145, x=3.321, y=11.955, w=-0.277, z=0, d=0]", - "setchar0 100 [h=262.046, v=181.145, x=3.321, y=11.955, w=-0.277, z=0, d=0]", - "setchar0 117 [h=267.58, v=181.145, x=3.321, y=11.955, w=-0.277, z=0, d=0]", - "setchar0 110 [h=273.115, v=181.145, x=3.321, y=11.955, w=-0.277, z=0, d=0]", - "w0 [h=272.838, v=181.145, x=3.321, y=11.955, w=-0.277, z=0, d=0]", - "setchar0 116 [h=276.713, v=181.145, x=3.321, y=11.955, w=-0.277, z=0, d=0]", + "w .277 [h=196.984, v=181.145, x=0, y=11.955, w=.277, z=0, d=0]", + "setchar0 100 [h=202.519, v=181.145, x=0, y=11.955, w=.277, z=0, d=0]", + "x 3.321 [h=205.84, v=181.145, x=3.321, y=11.955, w=.277, z=0, d=0]", + "setchar0 116 [h=209.714, v=181.145, x=3.321, y=11.955, w=.277, z=0, d=0]", + "setchar0 101 [h=214.142, v=181.145, x=3.321, y=11.955, w=.277, z=0, d=0]", + "setchar0 109 [h=222.444, v=181.145, x=3.321, y=11.955, w=.277, z=0, d=0]", + "setchar0 112 [h=227.979, v=181.145, x=3.321, y=11.955, w=.277, z=0, d=0]", + "w0 [h=228.256, v=181.145, x=3.321, y=11.955, w=.277, z=0, d=0]", + "setchar0 111 [h=233.237, v=181.145, x=3.321, y=11.955, w=.277, z=0, d=0]", + "setchar0 114 [h=237.139, v=181.145, x=3.321, y=11.955, w=.277, z=0, d=0]", + "x0 [h=240.46, v=181.145, x=3.321, y=11.955, w=.277, z=0, d=0]", + "setchar0 105 [h=243.227, v=181.145, x=3.321, y=11.955, w=.277, z=0, d=0]", + "setchar0 110 [h=248.762, v=181.145, x=3.321, y=11.955, w=.277, z=0, d=0]", + "w -.277 [h=248.485, v=181.145, x=3.321, y=11.955, w=-.277, z=0, d=0]", + "setchar0 118 [h=253.743, v=181.145, x=3.321, y=11.955, w=-.277, z=0, d=0]", + "setchar0 105 [h=256.511, v=181.145, x=3.321, y=11.955, w=-.277, z=0, d=0]", + "setchar0 100 [h=262.046, v=181.145, x=3.321, y=11.955, w=-.277, z=0, d=0]", + "setchar0 117 [h=267.58, v=181.145, x=3.321, y=11.955, w=-.277, z=0, d=0]", + "setchar0 110 [h=273.115, v=181.145, x=3.321, y=11.955, w=-.277, z=0, d=0]", + "w0 [h=272.838, v=181.145, x=3.321, y=11.955, w=-.277, z=0, d=0]", + "setchar0 116 [h=276.713, v=181.145, x=3.321, y=11.955, w=-.277, z=0, d=0]", "pop [h=61.768, v=181.145, x=0, y=11.955, w=0, z=0, d=0]", "pop [h=61.768, v=181.145, x=0, y=11.955, w=0, z=0, d=0]", "down 6.099 [h=61.768, v=187.245, x=0, y=11.955, w=0, z=0, d=0]", - "putrule 0.797, 220.922 [h=61.768, v=187.245, x=0, y=11.955, w=0, z=0, d=0]", + "putrule .797, 220.922 [h=61.768, v=187.245, x=0, y=11.955, w=0, z=0, d=0]", "pop [h=61.768, v=160.275, x=0, y=0, w=0, z=0, d=0]", "pop [h=61.768, v=160.275, x=0, y=0, w=0, z=0, d=0]", "pop [h=61.768, v=160.275, x=0, y=0, w=0, z=0, d=0]", @@ -473,9 +473,9 @@ TEST(DVIReaderTest, dvi_v2) { "push [h=61.768, v=218.472, x=0, y=0, w=0, z=0, d=0]", "right 3.387 [h=65.156, v=218.472, x=0, y=0, w=0, z=0, d=0]", "setchar0 98 [h=70.69, v=218.472, x=0, y=0, w=0, z=0, d=0]", - "right 0.277 [h=70.967, v=218.472, x=0, y=0, w=0, z=0, d=0]", + "right .277 [h=70.967, v=218.472, x=0, y=0, w=0, z=0, d=0]", "setchar0 111 [h=75.949, v=218.472, x=0, y=0, w=0, z=0, d=0]", - "right -0.277 [h=75.672, v=218.472, x=0, y=0, w=0, z=0, d=0]", + "right -.277 [h=75.672, v=218.472, x=0, y=0, w=0, z=0, d=0]", "setchar0 120 [h=80.93, v=218.472, x=0, y=0, w=0, z=0, d=0]", "setchar0 101 [h=85.358, v=218.472, x=0, y=0, w=0, z=0, d=0]", "setchar0 100 [h=90.893, v=218.472, x=0, y=0, w=0, z=0, d=0]", @@ -493,15 +493,15 @@ TEST(DVIReaderTest, dvi_v2) { "push [h=61.768, v=218.472, x=0, y=0, w=0, z=0, d=0]", "push [h=61.768, v=218.472, x=0, y=0, w=0, z=0, d=0]", "down -9.907 [h=61.768, v=208.565, x=0, y=0, w=0, z=0, d=0]", - "putrule 0.398, 53.267 [h=61.768, v=208.565, x=0, y=0, w=0, z=0, d=0]", + "putrule .398, 53.267 [h=61.768, v=208.565, x=0, y=0, w=0, z=0, d=0]", "down 13.095 [h=61.768, v=221.66, x=0, y=0, w=0, z=0, d=0]", "push [h=61.768, v=221.66, x=0, y=0, w=0, z=0, d=0]", - "setrule 13.295, 0.398 [h=62.167, v=221.66, x=0, y=0, w=0, z=0, d=0]", + "setrule 13.295, .398 [h=62.167, v=221.66, x=0, y=0, w=0, z=0, d=0]", "right 52.47 [h=114.637, v=221.66, x=0, y=0, w=0, z=0, d=0]", - "setrule 13.295, 0.398 [h=115.035, v=221.66, x=0, y=0, w=0, z=0, d=0]", + "setrule 13.295, .398 [h=115.035, v=221.66, x=0, y=0, w=0, z=0, d=0]", "pop [h=61.768, v=221.66, x=0, y=0, w=0, z=0, d=0]", - "down 0.199 [h=61.768, v=221.859, x=0, y=0, w=0, z=0, d=0]", - "putrule 0.398, 53.267 [h=61.768, v=221.859, x=0, y=0, w=0, z=0, d=0]", + "down .199 [h=61.768, v=221.859, x=0, y=0, w=0, z=0, d=0]", + "putrule .398, 53.267 [h=61.768, v=221.859, x=0, y=0, w=0, z=0, d=0]", "pop [h=61.768, v=218.472, x=0, y=0, w=0, z=0, d=0]", "pop [h=61.768, v=218.472, x=0, y=0, w=0, z=0, d=0]", "pop [h=61.768, v=218.472, x=0, y=0, w=0, z=0, d=0]", @@ -550,7 +550,7 @@ TEST(DVIReaderTest, dvi_v3) { "fontdef 7, 1274110073, cmr10 [h=25.088, v=43.042, x=0, y=0, w=0, z=0, d=1]", "fontnum 7, cmr10 [h=25.088, v=43.042, x=0, y=0, w=0, z=0, d=1]", "setchar0 118 [h=25.088, v=48.3, x=0, y=0, w=0, z=0, d=1]", - "right -0.277 [h=25.088, v=48.023, x=0, y=0, w=0, z=0, d=1]", + "right -.277 [h=25.088, v=48.023, x=0, y=0, w=0, z=0, d=1]", "setchar0 101 [h=25.088, v=52.451, x=0, y=0, w=0, z=0, d=1]", "setchar0 114 [h=25.088, v=56.353, x=0, y=0, w=0, z=0, d=1]", "setchar0 116 [h=25.088, v=60.228, x=0, y=0, w=0, z=0, d=1]", diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/tests/DependencyGraphTest.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/tests/DependencyGraphTest.cpp index 790361c46b4..fdf788e9d6e 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/tests/DependencyGraphTest.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/tests/DependencyGraphTest.cpp @@ -19,7 +19,7 @@ *************************************************************************/ #include <gtest/gtest.h> -#include "DependencyGraph.hpp" +#include "optimizer/DependencyGraph.hpp" using namespace std; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/tests/DvisvgmSpecialTest.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/tests/DvisvgmSpecialTest.cpp index 572ba6142be..4b4cdb6d424 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/tests/DvisvgmSpecialTest.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/tests/DvisvgmSpecialTest.cpp @@ -41,33 +41,37 @@ class DvisvgmSpecialTest : public ::testing::Test { protected: class ActionsRecorder : public EmptySpecialActions { public: - ActionsRecorder () : defs(""), page("") {} - void appendToDefs(unique_ptr<XMLNode> &&node) override {defs.append(std::move(node));} - void appendToPage(unique_ptr<XMLNode> &&node) override {page.append(std::move(node));} - void embed (const BoundingBox &bb) override {bbox.embed(bb);} - double getX () const override {return 0;} - double getY () const override {return 0;} - void clear () {defs.clear(); page.clear(); bbox=BoundingBox(0, 0, 0, 0);} - bool defsEquals (const string &str) const {return defs.getText() == str;} - bool pageEquals (const string &str) const {return page.getText() == str;} - bool bboxEquals (const string &str) const {return bbox.toSVGViewBox() == str;} - const Matrix& getMatrix () const override {static Matrix m(1); return m;} - string bboxString () const {return bbox.toSVGViewBox();} - string pageString () const {return page.getText();} - - void write (ostream &os) const { - os << "defs: " << defs.getText() << '\n' - << "page: " << page.getText() << '\n' - << "bbox: " << bbox.toSVGViewBox() << '\n'; + void embed (const BoundingBox &bb) override {bbox.embed(bb);} + double getX () const override {return 0;} + double getY () const override {return 0;} + bool defsEquals (const string &str) const {return defsString() == str;} + bool pageEquals (const string &str) const {return pageString() == str;} + bool bboxEquals (const string &str) const {return bbox.toSVGViewBox() == str;} + string bboxString () const {return bbox.toSVGViewBox();} + string defsString () const {return toString(svgTree().defsNode());} + string pageString () const {return toString(svgTree().pageNode());} + + void clear () { + SpecialActions::svgTree().reset(); + SpecialActions::svgTree().newPage(1); + bbox = BoundingBox(0, 0, 0, 0); + } + + protected: + string toString (const XMLNode *node) const { + ostringstream oss; + if (node) + node->write(oss); + return oss.str(); } private: - XMLTextNode defs, page; BoundingBox bbox; }; void SetUp () override { recorder.clear(); + XMLElement::WRITE_NEWLINES = false; } protected: @@ -81,29 +85,137 @@ TEST_F(DvisvgmSpecialTest, basic) { } -TEST_F(DvisvgmSpecialTest, raw) { +TEST_F(DvisvgmSpecialTest, rawText) { istringstream iss("raw first{?nl}"); handler.process("", iss, recorder); EXPECT_TRUE(recorder.defsEquals("")); - EXPECT_TRUE(recorder.pageEquals("first\n")); + EXPECT_TRUE(recorder.pageEquals("<g id='page1'>first\n</g>")) << recorder.pageString(); iss.clear(); iss.str("raw \t second {?bbox dummy} \t"); handler.process("", iss, recorder); EXPECT_TRUE(recorder.defsEquals("")); - EXPECT_TRUE(recorder.pageEquals("first\nsecond 0 0 0 0")); + EXPECT_TRUE(recorder.pageEquals("<g id='page1'>first\nsecond 0 0 0 0</g>")) << recorder.pageString(); +} + + +TEST_F(DvisvgmSpecialTest, rawPage1) { + istringstream iss("raw <elem attr1='1' attr2='20'>text1<inner><text2</inner>text3</elem>"); + handler.process("", iss, recorder); + EXPECT_TRUE(recorder.defsEquals("")); + EXPECT_TRUE(recorder.pageEquals("<g id='page1'><elem attr1='1' attr2='20'>text1<inner><text2</inner>text3</elem></g>")) << recorder.pageString(); +} + + +TEST_F(DvisvgmSpecialTest, rawPage2) { + istringstream iss("raw <elem attr1='1' attr2='20'>text1"); + handler.process("", iss, recorder); + iss.clear(); iss.str("raw text2<inner>text3</inner><my:empty-elem/>text4"); + handler.process("", iss, recorder); + iss.clear(); iss.str("raw </elem>"); + handler.process("", iss, recorder); + EXPECT_TRUE(recorder.defsEquals("")); + EXPECT_TRUE(recorder.pageEquals("<g id='page1'><elem attr1='1' attr2='20'>text1text2<inner>text3</inner><my:empty-elem/>text4</elem></g>")) << recorder.pageString(); +} + + +TEST_F(DvisvgmSpecialTest, rawPage3) { + istringstream iss("raw <elem attr1='1' attr2="); + handler.process("", iss, recorder); + iss.clear(); iss.str("raw '20'>text2<inner>text3</inner>text4</e"); + handler.process("", iss, recorder); + iss.clear(); iss.str("raw lem>"); + handler.process("", iss, recorder); + EXPECT_TRUE(recorder.defsEquals("")); + EXPECT_TRUE(recorder.pageEquals("<g id='page1'><elem attr1='1' attr2='20'>text2<inner>text3</inner>text4</elem></g>")) << recorder.pageString(); +} + + +TEST_F(DvisvgmSpecialTest, rawDefs1) { + istringstream iss("rawdef <elem attr1='1' attr2='20'>text1<inner><text2</inner>text3</elem>"); + handler.process("", iss, recorder); + EXPECT_TRUE(recorder.defsEquals("<defs><elem attr1='1' attr2='20'>text1<inner><text2</inner>text3</elem></defs>")) << recorder.defsString(); + EXPECT_TRUE(recorder.pageEquals("<g id='page1'/>")); +} + + +TEST_F(DvisvgmSpecialTest, rawDefs2) { + istringstream iss("rawdef <elem attr1='1' attr2='20'>text1"); + handler.process("", iss, recorder); + iss.clear(); iss.str("rawdef text2<inner>text3</inner>text4"); + handler.process("", iss, recorder); + iss.clear(); iss.str("rawdef </elem>"); + handler.process("", iss, recorder); + EXPECT_TRUE(recorder.defsEquals("<defs><elem attr1='1' attr2='20'>text1text2<inner>text3</inner>text4</elem></defs>")); + EXPECT_TRUE(recorder.pageEquals("<g id='page1'/>")); +} + + +TEST_F(DvisvgmSpecialTest, rawDefs3) { + istringstream iss("rawdef <elem attr1='1' a"); + handler.process("", iss, recorder); + iss.clear(); iss.str("rawdef ttr2='20'>text2<inner>text3</in"); + handler.process("", iss, recorder); + iss.clear(); iss.str("rawdef ner>text4</elem>"); + handler.process("", iss, recorder); + EXPECT_TRUE(recorder.defsEquals("<defs><elem attr1='1' attr2='20'>text2<inner>text3</inner>text4</elem></defs>")); + EXPECT_TRUE(recorder.pageEquals("<g id='page1'/>")); +} + + +TEST_F(DvisvgmSpecialTest, rawCDATA) { + istringstream iss("raw <outer>text1<![CDATA[1 < 2 <!--test-->]]>text2</outer>"); + handler.process("", iss, recorder); + EXPECT_TRUE(recorder.defsEquals("")); + EXPECT_TRUE(recorder.pageEquals("<g id='page1'><outer>text1<![CDATA[1 < 2 <!--test-->]]>text2</outer></g>")) << recorder.pageString(); +} + + +TEST_F(DvisvgmSpecialTest, rawComments) { + istringstream iss("raw <first/><second><!-- 1 < 2 ->--->text</second>"); + handler.process("", iss, recorder); + EXPECT_TRUE(recorder.defsEquals("")); + EXPECT_TRUE(recorder.pageEquals("<g id='page1'><first/><second><!-- 1 < 2 ->--->text</second></g>")) << recorder.pageString(); +} + + +TEST_F(DvisvgmSpecialTest, rawPI) { + istringstream iss("raw <first/><?pi1 whatever?><second><?pi2 whatever?></second>"); + handler.process("", iss, recorder); + EXPECT_TRUE(recorder.defsEquals("")); + EXPECT_TRUE(recorder.pageEquals("<g id='page1'><first/><?pi1 whatever?><second><?pi2 whatever?></second></g>")) << recorder.pageString(); +} + + +TEST_F(DvisvgmSpecialTest, rawPageFail) { + istringstream iss("raw <elem attr1='1' attr2='20'"); + EXPECT_THROW({handler.process("", iss, recorder); handler.finishPage();}, SpecialException); // incomplete opening tag + iss.clear(); iss.str("raw </elem>"); + EXPECT_THROW(handler.process("", iss, recorder), SpecialException); // spurious closing tag + iss.clear(); iss.str("raw <open>text</close>"); + EXPECT_THROW(handler.process("", iss, recorder), SpecialException); // mismatching tags +} + + +TEST_F(DvisvgmSpecialTest, rawDefsFail) { + istringstream iss("rawdef <elem attr1='1' attr2='20'"); + EXPECT_THROW({handler.process("", iss, recorder); handler.finishPage();}, SpecialException); // incomplete opening tag + iss.clear(); iss.str("rawdef </elem>"); + EXPECT_THROW(handler.process("", iss, recorder), SpecialException); // spurious closing tag + iss.clear(); iss.str("rawdef <open>text</close>"); + EXPECT_THROW(handler.process("", iss, recorder), SpecialException); // mismatching tags } TEST_F(DvisvgmSpecialTest, rawdef) { std::istringstream iss("rawdef first"); handler.process("", iss, recorder); - EXPECT_TRUE(recorder.defsEquals("first")); - EXPECT_TRUE(recorder.pageEquals("")); + EXPECT_TRUE(recorder.defsEquals("<defs>first</defs>")) << recorder.defsString(); + EXPECT_TRUE(recorder.pageEquals("<g id='page1'/>")); - iss.clear(); iss.str("rawdef \t second \t"); + iss.clear(); iss.str("rawdef \t <second></second> \t"); handler.process("", iss, recorder); - EXPECT_TRUE(recorder.defsEquals("firstsecond")); - EXPECT_TRUE(recorder.pageEquals("")); + EXPECT_TRUE(recorder.defsEquals("<defs>first<second/></defs>")); + EXPECT_TRUE(recorder.pageEquals("<g id='page1'/>")); } @@ -111,7 +223,7 @@ TEST_F(DvisvgmSpecialTest, pattern1) { const auto cmds = { "rawset pat1", "raw text1", - "raw text2", + "raw <elem>text2</elem>", "endrawset", "raw first", "rawput pat1", @@ -128,7 +240,7 @@ TEST_F(DvisvgmSpecialTest, pattern1) { } handler.finishPage(); EXPECT_TRUE(recorder.defsEquals("")); - EXPECT_TRUE(recorder.pageEquals("firsttext1text2text1text2")); + EXPECT_TRUE(recorder.pageEquals("<g id='page1'>firsttext1<elem>text2</elem>text1<elem>text2</elem></g>")) << recorder.pageString(); } @@ -136,7 +248,7 @@ TEST_F(DvisvgmSpecialTest, pattern2) { const auto cmds = { "rawset pat2", "rawdef text1", - "rawdef text2", + "rawdef <elem>text2</elem>", "endrawset", "rawdef first", "rawput pat2", @@ -152,16 +264,16 @@ TEST_F(DvisvgmSpecialTest, pattern2) { handler.process("", iss, recorder); } handler.finishPage(); - EXPECT_TRUE(recorder.defsEquals("firsttext1text2")); - EXPECT_TRUE(recorder.pageEquals("")); + EXPECT_TRUE(recorder.defsEquals("<defs>firsttext1<elem>text2</elem></defs>")) << recorder.defsString(); + EXPECT_TRUE(recorder.pageEquals("<g id='page1'/>")); } TEST_F(DvisvgmSpecialTest, pattern3) { const auto cmds = { "rawset pat3", - "raw text1", - "rawdef text2", + "raw <elem first='a' second='x\"y\"'>text<empty/></elem>", + "rawdef <a/>text2", "endrawset", "rawdef first", "raw second", @@ -177,8 +289,8 @@ TEST_F(DvisvgmSpecialTest, pattern3) { std::istringstream iss(cmd); handler.process("", iss, recorder); } - EXPECT_TRUE(recorder.defsEquals("firsttext2")); - EXPECT_TRUE(recorder.pageEquals("secondtext1text1")); + EXPECT_TRUE(recorder.defsEquals("<defs>first<a/>text2</defs>")); + EXPECT_TRUE(recorder.pageEquals("<g id='page1'>second<elem first='a' second='x\"y\"'>text<empty/></elem><elem first='a' second='x\"y\"'>text<empty/></elem></g>")) << recorder.pageString(); handler.finishPage(); } @@ -201,13 +313,13 @@ TEST_F(DvisvgmSpecialTest, processImg) { std::istringstream iss("img 72.27 72.27 test.png"); handler.process("", iss, recorder); EXPECT_TRUE(recorder.defsEquals("")); - EXPECT_TRUE(recorder.pageEquals("<image x='0' y='0' width='72' height='72' xlink:href='test.png'/>")); + EXPECT_TRUE(recorder.pageEquals("<g id='page1'><image x='0' y='0' width='72' height='72' xlink:href='test.png'/></g>")) << recorder.pageString(); recorder.clear(); iss.clear(); iss.str("img 10bp 20bp test2.png"); handler.process("", iss, recorder); - EXPECT_TRUE(recorder.pageEquals("<image x='0' y='0' width='10' height='20' xlink:href='test2.png'/>")); + EXPECT_TRUE(recorder.pageEquals("<g id='page1'><image x='0' y='0' width='10' height='20' xlink:href='test2.png'/></g>")) << recorder.pageString(); } @@ -221,7 +333,7 @@ TEST_F(DvisvgmSpecialTest, processBBox) { std::istringstream iss("bbox abs 0 0 72.27 72.27"); handler.process("", iss, recorder); EXPECT_TRUE(recorder.defsEquals("")); - EXPECT_TRUE(recorder.pageEquals("")); + EXPECT_TRUE(recorder.pageEquals("<g id='page1'/>")); EXPECT_TRUE(recorder.bboxEquals("0 0 72 72")); recorder.clear(); diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/tests/EllipticalArcTest.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/tests/EllipticalArcTest.cpp new file mode 100644 index 00000000000..127f7b08e3a --- /dev/null +++ b/Build/source/texk/dvisvgm/dvisvgm-src/tests/EllipticalArcTest.cpp @@ -0,0 +1,142 @@ +/************************************************************************* +** EllipticalArcTest.cpp ** +** ** +** This file is part of dvisvgm -- a fast DVI to SVG converter ** +** Copyright (C) 2005-2019 Martin Gieseking <martin.gieseking@uos.de> ** +** ** +** 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 <http://www.gnu.org/licenses/>. ** +*************************************************************************/ + +#include <gtest/gtest.h> +#include <sstream> +#include "EllipticalArc.hpp" +#include "utility.hpp" + +using namespace std; + +#define EXPECT_NEAR_PAIR(p1, p2, eps) \ + EXPECT_NEAR(p1.x(), p2.x(), eps); \ + EXPECT_NEAR(p1.y(), p2.y(), eps) + + +TEST(EllipticalArcTest, construct1) { + EllipticalArc arc(DPair(125,75), 100, 50, math::deg2rad(30), 1, 1, DPair(225, 125)); + EXPECT_FALSE(arc.isStraightLine()); + EXPECT_EQ(arc.startPoint(), DPair(125,75)); + EXPECT_EQ(arc.endPoint(), DPair(225,125)); + EXPECT_EQ(arc.rx(), 100); + EXPECT_EQ(arc.ry(), 50); + EXPECT_NEAR(math::rad2deg(arc.rotationAngle()), 30, 0.0001); + EXPECT_TRUE(arc.largeArc()); + EXPECT_TRUE(arc.sweepPositive()); +} + + +TEST(EllipticalArcTest, construct2) { + // radii two small, check automatic adaption + EllipticalArc arc(DPair(125,75), 20, 10, math::deg2rad(30), 1, 1, DPair(225, 125)); + EXPECT_FALSE(arc.isStraightLine()); + EXPECT_EQ(arc.startPoint(), DPair(125,75)); + EXPECT_EQ(arc.endPoint(), DPair(225,125)); + EXPECT_NEAR(arc.rx(), 56.2, 0.01); + EXPECT_NEAR(arc.ry(), 28.1, 0.01); + EXPECT_NEAR(math::rad2deg(arc.rotationAngle()), 30, 0.0001); + EXPECT_TRUE(arc.largeArc()); + EXPECT_TRUE(arc.sweepPositive()); +} + + +TEST(EllipticalArcTest, construct3) { + EXPECT_TRUE(EllipticalArc(DPair(125,75), 0, 10, math::deg2rad(30), 1, 1, DPair(225, 125)).isStraightLine()); + EXPECT_TRUE(EllipticalArc(DPair(125,75), 20, 0, math::deg2rad(30), 1, 1, DPair(225, 125)).isStraightLine()); + EXPECT_TRUE(EllipticalArc(DPair(125,75), 0, 0, math::deg2rad(30), 1, 1, DPair(225, 125)).isStraightLine()); +} + + +TEST(EllipticalArcTest, construct4) { + // center parameterization + EllipticalArc arc(DPair(100,100), 100, 50, math::deg2rad(30), math::deg2rad(30), math::deg2rad(80)); + EXPECT_FALSE(arc.isStraightLine()); + EXPECT_NEAR_PAIR(arc.startPoint(), DPair(152.452, 164.952), 0.001); + EXPECT_NEAR_PAIR(arc.endPoint(), DPair(50.856, 123.589), 0.001); + EXPECT_NEAR(arc.rx(), 100, 0.1); + EXPECT_NEAR(arc.ry(), 50, 0.1); + EXPECT_NEAR(math::rad2deg(arc.rotationAngle()), 30, 0.0001); + EXPECT_FALSE(arc.largeArc()); + EXPECT_TRUE(arc.sweepPositive()); +} + + +TEST(EllipticalArcTest, transform) { + EllipticalArc arc(DPair(125,75), 100, 50, math::deg2rad(30), 1, 1, DPair(225, 125)); + Matrix m(1); + m.scale(1,2).rotate(30).xskewByAngle(15).rotate(20).yskewByAngle(-20); + arc.transform(m); + EXPECT_NEAR_PAIR(arc.startPoint(), DPair(13.8871, 204.752), 0.001); + EXPECT_NEAR_PAIR(arc.endPoint(), DPair(35.957, 350.121), 0.001); + EXPECT_NEAR(arc.rx(), 154.73, 0.001); + EXPECT_NEAR(arc.ry(), 64.629, 0.001); + EXPECT_NEAR(math::rad2deg(arc.rotationAngle()), -81.748, 0.001); + EXPECT_TRUE(arc.largeArc()); + EXPECT_TRUE(arc.sweepPositive()); +} + + +TEST(EllipticalArcTest, bbox1) { + EllipticalArc arc(DPair(125,75), 100, 50, math::deg2rad(30), 1, 1, DPair(225, 125)); + BoundingBox bbox = arc.getBBox(); + EXPECT_NEAR(bbox.minX(), 96.854, 0.001); + EXPECT_NEAR(bbox.minY(), -6.633, 0.001); + EXPECT_NEAR(bbox.width(), 180.278, 0.001); + EXPECT_NEAR(bbox.height(), 132.288, 0.001); +} + + +TEST(EllipticalArcTest, bbox2) { + EllipticalArc arc(DPair(125,75), 100, 50, math::deg2rad(30), 0, 1, DPair(225, 125)); + BoundingBox bbox = arc.getBBox(); + EXPECT_NEAR(bbox.minX(), 125, 0.1); + EXPECT_NEAR(bbox.minY(), 75, 0.1); + EXPECT_NEAR(bbox.width(), 100, 0.1); + EXPECT_NEAR(bbox.height(), 50, 0.1); +} + + +TEST(EllipticalArcTest, approximate1) { + EllipticalArc arc(DPair(125,75), 100, 50, math::deg2rad(30), 1, 1, DPair(225, 125)); + auto beziers = arc.approximate(); + ASSERT_EQ(beziers.size(), 4u); + DPair data[4][4] = { + {DPair(125, 75), DPair(96.271, 46.768), DPair(88.655, 17.402), DPair(106.223, 2.602)}, + {DPair(106.223, 2.602), DPair(123.791, -12.198), DPair(162.434, -8.971), DPair(201.493, 10.558)}, + {DPair(201.493, 10.558), DPair(240.551, 30.088), DPair(270.89, 61.351), DPair(276.289, 87.635)}, + {DPair(276.289, 87.635), DPair(281.688, 113.919), DPair(260.884, 129.074), DPair(225, 125)} + }; + for (int i=0; i < 4; i++) { + for (int j=0; j < 4; j++) { + EXPECT_NEAR_PAIR(beziers[i].point(j), data[i][j], 0.001); + } + } +} + + +TEST(EllipticalArcTest, approximate2) { + EllipticalArc arc(DPair(125,75), 100, 50, math::deg2rad(30), 0, 1, DPair(225, 125)); + auto beziers = arc.approximate(); + ASSERT_EQ(beziers.size(), 1u); + DPair data[] = {DPair(125, 75), DPair(158.522, 78.806), DPair(198.163, 98.627), DPair(225, 125)}; + for (int j=0; j < 4; j++) { + EXPECT_NEAR_PAIR(beziers[0].point(j), data[j], 0.001); + } +} diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/tests/EmSpecialTest.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/tests/EmSpecialTest.cpp index 457338bc725..1a14e9e5f6c 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/tests/EmSpecialTest.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/tests/EmSpecialTest.cpp @@ -24,6 +24,7 @@ #include "SpecialActions.hpp" #include "XMLNode.hpp" #include "XMLString.hpp" +#include "SVGTree.hpp" using namespace std; @@ -32,35 +33,38 @@ class EmSpecialTest : public ::testing::Test { protected: class ActionsRecorder : public EmptySpecialActions { public: - ActionsRecorder () : x(), y(), page("page") {} - void appendToPage(unique_ptr<XMLNode> &&node) {page.append(std::move(node));} - void embed (const BoundingBox &bb) {bbox.embed(bb);} - void setX (double xx) {x = xx;} - void setY (double yy) {x = yy;} - double getX () const {return x;} - double getY () const {return y;} - Color getColor () const {return color;} - void setColor (const Color &c) {color = c;} - void clear () {page.clear(); bbox=BoundingBox(0, 0, 0, 0);} - string getPageXML () const {ostringstream oss; oss << page; return oss.str();} - const Matrix& getMatrix () const {static Matrix m(1); return m;} - - void write (ostream &os) const { + ActionsRecorder () : x(), y() {} + void embed (const BoundingBox &bb) override {bbox.embed(bb);} + void setX (double xx) override {x = xx;} + void setY (double yy) override {x = yy;} + double getX () const override {return x;} + double getY () const override {return y;} + Color getColor () const override {return color;} + void setColor (const Color &c) override {color = c;} + string getPageXML () const {ostringstream oss; oss << *svgTree().pageNode(); return oss.str();} + const Matrix& getMatrix () const override {static Matrix m(1); return m;} + + void clear () { + SpecialActions::svgTree().reset(); + SpecialActions::svgTree().newPage(1); + bbox = BoundingBox(0, 0, 0, 0); + } + +/* void write (ostream &os) const { os << "page: " << page << '\n' << "bbox: " << bbox.toSVGViewBox() << '\n'; - } + } */ private: double x, y; - Color color; - XMLElementNode page; BoundingBox bbox; + Color color; }; class MyEmSpecialHandler : public EmSpecialHandler { public: - MyEmSpecialHandler (SpecialActions &a) : actions(a) {} + explicit MyEmSpecialHandler (SpecialActions &a) : actions(a) {} void finishPage () {dviEndPage(0, actions);} void processSpecial (const string &str) {stringstream ss; ss << str; process("em", ss, actions);} @@ -96,17 +100,17 @@ TEST_F(EmSpecialTest, lines1) { recorder.setY(p[i].y()); handler.processSpecial(string("point ")+XMLString(i)); } - EXPECT_EQ(recorder.getPageXML(), "<page/>"); + EXPECT_EQ(recorder.getPageXML(), "<g id='page1'/>"); handler.processSpecial("linewidth 2bp"); for (int i=0; i < n; i++) handler.processSpecial(string("line ")+XMLString(i)+", "+XMLString((i+1)%n)); EXPECT_EQ(recorder.getPageXML(), - "<page>\n" + "<g id='page1'>\n" "<line x1='0' y1='0' x2='10' y2='0' stroke-width='2' stroke='#000'/>\n" "<line x1='10' y1='0' x2='10' y2='0' stroke-width='2' stroke='#000'/>\n" "<line x1='10' y1='0' x2='0' y2='0' stroke-width='2' stroke='#000'/>\n" "<line x1='0' y1='0' x2='0' y2='0' stroke-width='2' stroke='#000'/>\n" - "</page>" + "</g>" ); } @@ -126,12 +130,12 @@ TEST_F(EmSpecialTest, lines2) { } handler.finishPage(); EXPECT_EQ(recorder.getPageXML(), - "<page>\n" + "<g id='page1'>\n" "<line x1='0' y1='0' x2='10' y2='0' stroke-width='2' stroke='#000'/>\n" "<line x1='10' y1='0' x2='10' y2='0' stroke-width='2' stroke='#000'/>\n" "<line x1='10' y1='0' x2='0' y2='0' stroke-width='2' stroke='#000'/>\n" "<line x1='0' y1='0' x2='0' y2='0' stroke-width='2' stroke='#000'/>\n" - "</page>" + "</g>" ); } @@ -140,7 +144,7 @@ TEST_F(EmSpecialTest, pline) { handler.processSpecial("point 1, 10, 10"); handler.processSpecial("point 2, 100, 100"); handler.processSpecial("line 1, 2, 10bp"); - EXPECT_EQ(recorder.getPageXML(), "<page>\n<line x1='10' y1='10' x2='100' y2='100' stroke-width='10' stroke='#000'/>\n</page>"); + EXPECT_EQ(recorder.getPageXML(), "<g id='page1'>\n<line x1='10' y1='10' x2='100' y2='100' stroke-width='10' stroke='#000'/>\n</g>"); } @@ -148,7 +152,7 @@ TEST_F(EmSpecialTest, vline) { handler.processSpecial("point 1, 10, 10"); handler.processSpecial("point 2, 100, 100"); handler.processSpecial("line 1v, 2v, 10bp"); // cut line ends vertically - EXPECT_EQ(recorder.getPageXML(), "<page>\n<polygon points='10,17.07 10,2.93 100,92.93 100,107.07'/>\n</page>"); + EXPECT_EQ(recorder.getPageXML(), "<g id='page1'>\n<polygon points='10,17.07 10,2.93 100,92.93 100,107.07'/>\n</g>"); } @@ -156,7 +160,7 @@ TEST_F(EmSpecialTest, hline) { handler.processSpecial("point 1, 10, 10"); handler.processSpecial("point 2, 100, 100"); handler.processSpecial("line 1h, 2h, 10bp"); // cut line ends horizontally - EXPECT_EQ(recorder.getPageXML(), "<page>\n<polygon points='2.93,10 17.07,10 107.07,100 92.93,100'/>\n</page>"); + EXPECT_EQ(recorder.getPageXML(), "<g id='page1'>\n<polygon points='2.93,10 17.07,10 107.07,100 92.93,100'/>\n</g>"); } @@ -164,14 +168,14 @@ TEST_F(EmSpecialTest, hvline) { handler.processSpecial("point 1, 10, 10"); handler.processSpecial("point 2, 100, 100"); handler.processSpecial("line 1h, 2v, 10bp"); // cut line ends horizontally - EXPECT_EQ(recorder.getPageXML(), "<page>\n<polygon points='2.93,10 17.07,10 100,92.93 100,107.07'/>\n</page>"); + EXPECT_EQ(recorder.getPageXML(), "<g id='page1'>\n<polygon points='2.93,10 17.07,10 100,92.93 100,107.07'/>\n</g>"); recorder.clear(); recorder.setColor(Color(0.0, 0.0, 1.0)); handler.processSpecial("point 1, 10, 10"); handler.processSpecial("point 2, 100, 100"); handler.processSpecial("line 1v, 2h, 10bp"); // cut line ends horizontally - EXPECT_EQ(recorder.getPageXML(), "<page>\n<polygon points='10,17.07 10,2.93 107.07,100 92.93,100' fill='#00f'/>\n</page>"); + EXPECT_EQ(recorder.getPageXML(), "<g id='page1'>\n<polygon points='10,17.07 10,2.93 107.07,100 92.93,100' fill='#00f'/>\n</g>"); } @@ -186,12 +190,12 @@ TEST_F(EmSpecialTest, lineto) { handler.processSpecial(i == 0 ? "moveto" : "lineto"); } EXPECT_EQ(recorder.getPageXML(), - "<page>\n" + "<g id='page1'>\n" "<line x1='0' y1='0' x2='10' y2='0' stroke-width='2' stroke='#f00'/>\n" "<line x1='10' y1='0' x2='10' y2='0' stroke-width='4' stroke='#f00'/>\n" "<line x1='10' y1='0' x2='0' y2='0' stroke-width='6' stroke='#f00'/>\n" "<line x1='0' y1='0' x2='0' y2='0' stroke-width='8' stroke='#f00'/>\n" - "</page>" + "</g>" ); } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/tests/FilePathTest.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/tests/FilePathTest.cpp index 81cb55f3ba4..6cce81ef434 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/tests/FilePathTest.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/tests/FilePathTest.cpp @@ -30,6 +30,15 @@ using namespace std; +TEST(FilePathTest, empty) { + FilePath path; + ASSERT_TRUE(path.empty()); + path.set("/a/b/c/d", false, "/"); + ASSERT_FALSE(path.empty()); + ASSERT_EQ(path.absolute(), "/a/b/c/d"); +} + + TEST(FilePathTest, dir1) { FilePath fp("a/b/c/d", false, "/"); ASSERT_EQ(fp.absolute(), "/a/b/c/d"); @@ -91,4 +100,3 @@ TEST(FilePathTest, autodetect) { ASSERT_FALSE(fp2.empty()); ASSERT_EQ(fp2.absolute(), FileSystem::getcwd()); } - diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/tests/FontCacheTest.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/tests/FontCacheTest.cpp index 720db081152..d7928b5bb85 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/tests/FontCacheTest.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/tests/FontCacheTest.cpp @@ -66,11 +66,11 @@ class FontCacheTest : public testing::Test { glyph2.moveto(0, 0); glyph2.cubicto(10, 10, 20, 0, 50, 50); glyph2.lineto(30, 20); - glyph2.conicto(20, 40, 20, 20); + glyph2.quadto(20, 40, 20, 20); glyph2.closepath(); } - ~FontCacheTest () { + ~FontCacheTest () override { FileSystem::remove(cachedir+"/testfont.fgd"); } @@ -103,37 +103,37 @@ TEST_F(FontCacheTest, glyph) { TEST_F(FontCacheTest, write1) { cache.setGlyph(1, glyph1); ASSERT_TRUE(cache.fontname().empty()); - ASSERT_FALSE(cache.write(cachedir.c_str())); + ASSERT_FALSE(cache.write(cachedir)); } TEST_F(FontCacheTest, write2) { cache.setGlyph(1, glyph1); ASSERT_TRUE(FileSystem::exists(cachedir)); - ASSERT_TRUE(cache.write("testfont", cachedir.c_str())); + ASSERT_TRUE(cache.write("testfont", cachedir)); cache.setGlyph(10, glyph2); - ASSERT_TRUE(cache.write("testfont", cachedir.c_str())); - ASSERT_TRUE(cache.fontname().empty()); + EXPECT_TRUE(cache.write("testfont", cachedir)); + EXPECT_TRUE(cache.fontname().empty()); } TEST_F(FontCacheTest, read) { cache.setGlyph(1, glyph1); cache.setGlyph(10, glyph2); - ASSERT_TRUE(cache.write("testfont", cachedir.c_str())); + ASSERT_TRUE(cache.write("testfont", cachedir)); // clear cache object cache.clear(); - ASSERT_EQ(cache.getGlyph(1), nullptr); - ASSERT_EQ(cache.getGlyph(2), nullptr); - ASSERT_EQ(cache.getGlyph(10), nullptr); + EXPECT_EQ(cache.getGlyph(1), nullptr); + EXPECT_EQ(cache.getGlyph(2), nullptr); + EXPECT_EQ(cache.getGlyph(10), nullptr); // read glyph data from cache file - ASSERT_TRUE(cache.read("testfont", cachedir.c_str())); - ASSERT_EQ(cache.fontname(), "testfont"); + ASSERT_TRUE(cache.read("testfont", cachedir)); + EXPECT_EQ(cache.fontname(), "testfont"); ASSERT_NE(cache.getGlyph(1), nullptr); - ASSERT_EQ(cache.getGlyph(2), nullptr); + EXPECT_EQ(cache.getGlyph(2), nullptr); ASSERT_NE(cache.getGlyph(10), nullptr); - ASSERT_EQ(*cache.getGlyph(1), glyph1); - ASSERT_EQ(*cache.getGlyph(10), glyph2); + EXPECT_EQ(*cache.getGlyph(1), glyph1); + EXPECT_EQ(*cache.getGlyph(10), glyph2); } @@ -141,7 +141,7 @@ TEST_F(FontCacheTest, fontinfo1) { ostringstream oss; cache.clear(); FileSystem::remove(cachedir+"/testfont.fgd"); - cache.fontinfo(cachedir.c_str(), oss); + cache.fontinfo(cachedir, oss); ASSERT_EQ(oss.str(), "cache is empty\n"); // check removal of invalid cache files @@ -150,7 +150,7 @@ TEST_F(FontCacheTest, fontinfo1) { cachefile.close(); ASSERT_TRUE(FileSystem::exists(cachedir+"/invalid.fgd")); oss.str(""); - cache.fontinfo(cachedir.c_str(), oss, true); + cache.fontinfo(cachedir, oss, true); ASSERT_EQ(oss.str(), "cache is empty\n" "invalid cache file invalid.fgd removed\n" @@ -162,12 +162,12 @@ TEST_F(FontCacheTest, fontinfo1) { TEST_F(FontCacheTest, fontinfo2) { cache.setGlyph(1, glyph1); cache.setGlyph(10, glyph2); - ASSERT_TRUE(cache.write("testfont", cachedir.c_str())); + ASSERT_TRUE(cache.write("testfont", cachedir)); ostringstream oss; - cache.fontinfo(cachedir.c_str(), oss); + cache.fontinfo(cachedir, oss); ASSERT_EQ(oss.str(), "cache format version 5\n" - "testfont 2 glyphs 10 cmds 58 bytes crc:38cb5c67\n" + "testfont 2 glyphs 10 cmds 58 bytes hash:3cb32ab6\n" ); } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/tests/GFGlyphTracerTest.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/tests/GFGlyphTracerTest.cpp index b4ebb1b1acd..060e7cc8248 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/tests/GFGlyphTracerTest.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/tests/GFGlyphTracerTest.cpp @@ -75,13 +75,13 @@ TEST(GFGlyphTracerTest, executeChar) { ostringstream oss; glyph.closeOpenSubPaths(); EXPECT_EQ(scaled_pathstr(glyph), - "M3.5 4.3C3.2 4.1 3.1 4.1 2.9 4.3C1.9 4.8 0.6 4 0.6 3C0.6 2.8 0.7 2.4 0.8 2.3C0.9 2.1 1 2 0.9 1.7" - "C0.7 1.3 0.7 0.8 0.9 0.5C1 0.3 1 0.3 0.6 -0.1C0 -0.7 0.1 -1.4 1.1 -1.9C1.7 -2.2 3.3 -2.2 3.8 -1.9" - "C4.4 -1.6 4.7 -1.2 4.7 -0.8C4.7 0.2 3.9 0.7 2.4 0.7C1.3 0.7 1 0.9 1.1 1.4C1.1 1.7 1.2 1.7 1.4 1.7" + "M3.5 4.3C3.2 4.1 3.1 4.1 2.9 4.3C1.9 4.8 .6 4 .6 3C.6 2.8 .7 2.4 .8 2.3C.9 2.1 1 2 .9 1.7" + "C.7 1.3 .7 .8 .9 .5C1 .3 1 .3 .6-.1C0-.7 .1-1.4 1.1-1.9C1.7-2.2 3.3-2.2 3.8-1.9" + "C4.4-1.6 4.7-1.2 4.7-.8C4.7 .2 3.9 .7 2.4 .7C1.3 .7 1 .9 1.1 1.4C1.1 1.7 1.2 1.7 1.4 1.7" "C1.5 1.7 1.8 1.6 2 1.6C3.2 1.4 4.2 2.8 3.5 3.7C3.4 3.9 3.4 4 3.6 4.1C4 4.4 4.3 4.4 4.2 4.1" "C4.2 3.9 4.4 3.7 4.6 3.8C4.7 3.8 4.8 4 4.8 4.1C4.8 4.6 4.2 4.7 3.5 4.3Z" "M2.7 3.9C2.9 3.8 2.9 3.5 2.9 3C2.9 2.2 2.7 1.8 2.2 1.8C1.6 1.8 1.4 2.2 1.4 3C1.4 3.8 1.6 4.2 2.2 4.2C2.3 4.2 2.6 4.1 2.7 3.9Z" - "M3.5 -0.1C4 -0.2 4.2 -0.7 4 -1.1C3.6 -2 1.7 -2.2 1.1 -1.4C0.8 -1 0.8 -0.6 1.1 -0.2C1.3 0.1 1.4 0.1 2.2 0.1C2.7 0.1 3.3 0 3.5 -0.1Z"); + "M3.5-.1C4-.2 4.2-.7 4-1.1C3.6-2 1.7-2.2 1.1-1.4C.8-1 .8-.6 1.1-.2C1.3 .1 1.4 .1 2.2 .1C2.7 .1 3.3 0 3.5-.1Z"); EXPECT_EQ(callback.getLog(), "begin(103)end(103)"); tracer.reset(gfname, 1000); @@ -91,8 +91,8 @@ TEST(GFGlyphTracerTest, executeChar) { glyph.closeOpenSubPaths(); oss.str(""); EXPECT_EQ(scaled_pathstr(glyph), - "M0 0.7C0 0.7 0 0.6 0.1 0.6L0.1 0.6V0.3V0L0.1 0C0 0 0 0 0 0C0 0 0.1 0 0.2 0C0.3 0 0.3 0 0.3 0" - "C0.3 0 0.3 0 0.3 0L0.2 0V0.3V0.6L0.3 0.6C0.3 0.6 0.3 0.7 0.3 0.7C0.3 0.7 0.3 0.7 0.2 0.7C0.1 0.7 0 0.7 0 0.7Z"); + "M0 .7C0 .7 0 .6 .1 .6L.1 .6V.3V0L.1 0C0 0 0 0 0 0C0 0 .1 0 .2 0C.3 0 .3 0 .3 0" + "C.3 0 .3 0 .3 0L.2 0V.3V.6L.3 .6C.3 .6 .3 .7 .3 .7C.3 .7 .3 .7 .2 .7C.1 .7 0 .7 0 .7Z"); EXPECT_EQ(callback.getLog(), "begin(73)end(73)"); } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/tests/GraphicsPathTest.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/tests/GraphicsPathTest.cpp index ea06ec59cef..92420f653ed 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/tests/GraphicsPathTest.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/tests/GraphicsPathTest.cpp @@ -22,7 +22,7 @@ #include <sstream> #include "GraphicsPath.hpp" -using std::ostringstream; +using namespace std; TEST(GraphicsPathTest, svg) { GraphicsPath<int> path; @@ -92,7 +92,7 @@ TEST(GraphicsPathTest, relative1) { path.lineto(10,10); path.lineto(10,20); path.cubicto(20,20,30,30,40,40); - path.conicto(50, 50, 60, 60); + path.quadto(50, 50, 60, 60); path.lineto(100,60); path.closepath(); ostringstream oss; @@ -105,7 +105,7 @@ TEST(GraphicsPathTest, computeBBox) { GraphicsPath<int> path; path.moveto(10,10); path.lineto(100,10); - path.conicto(10,100,40,80); + path.quadto(10, 100, 40, 80); path.cubicto(5,5,30,10,90,70); path.lineto(20,30); path.closepath(); @@ -119,7 +119,7 @@ TEST(GraphicsPathTest, removeRedundantCommands) { GraphicsPath<int> path; path.moveto(10,10); path.lineto(100,10); - path.conicto(10,100,40,80); + path.quadto(10, 100, 40, 80); path.cubicto(5,5,30,10,90,70); path.moveto(10,10); path.moveto(15,10); @@ -133,13 +133,34 @@ TEST(GraphicsPathTest, removeRedundantCommands) { EXPECT_EQ(oss.str(), "M10 10H100Q10 100 40 80C5 5 30 10 90 70M20 20V30"); } +TEST(GraphicsPathTest, cmd_equals) { + using Point = Pair<int>; + gp::MoveTo<int> m1(Point(1, 2)); + gp::MoveTo<int> m2(Point(1, 2)); + gp::MoveTo<int> m3(Point(2, 1)); + EXPECT_EQ(m1, m2); + EXPECT_EQ(m2, m1); + EXPECT_NE(m1, m3); + EXPECT_NE(m3, m1); + gp::LineTo<int> l1(Point(1, 2)); + EXPECT_NE(l1, m1); + EXPECT_NE(m1, l1); + gp::CubicTo<int> c1(Point(1, 2), Point(3, 4), Point(5, 6)); + gp::CubicTo<int> c2(Point(1, 2), Point(3, 4), Point(5, 6)); + gp::CubicTo<int> c3(Point(1, 2), Point(0, 4), Point(5, 6)); + EXPECT_EQ(c1, c2); + EXPECT_EQ(c2, c1); + EXPECT_NE(c1, c3); + EXPECT_NE(c3, c1); +} + TEST(GraphicsPathTest, equals) { GraphicsPath<int> path1; EXPECT_TRUE(path1 == path1); path1.moveto(10,10); path1.lineto(100,10); - path1.conicto(10,100,40,80); + path1.quadto(10, 100, 40, 80); path1.cubicto(5,5,30,10,90,70); path1.lineto(20,30); path1.closepath(); @@ -149,7 +170,7 @@ TEST(GraphicsPathTest, equals) { EXPECT_FALSE(path1 == path2); path2.moveto(10,10); path2.lineto(100,10); - path2.conicto(10,100,40,80); + path2.quadto(10, 100, 40, 80); path2.cubicto(5,5,30,10,90,70); path2.lineto(20,30); EXPECT_FALSE(path1 == path2); @@ -161,7 +182,7 @@ TEST(GraphicsPathTest, equals) { path2.clear(); path2.moveto(10,10); path2.lineto(100,10); - path2.conicto(10,100,40,80); + path2.quadto(10, 100, 40, 80); path2.cubicto(5,5,10,10,90,70); path2.lineto(20,30); path2.closepath(); @@ -175,7 +196,7 @@ TEST(GraphicsPathTest, unequals) { EXPECT_FALSE(path1 != path1); path1.moveto(10,10); path1.lineto(100,10); - path1.conicto(10,100,40,80); + path1.quadto(10, 100, 40, 80); path1.cubicto(5,5,30,10,90,70); path1.lineto(20,30); path1.closepath(); @@ -185,7 +206,7 @@ TEST(GraphicsPathTest, unequals) { EXPECT_TRUE(path1 != path2); path2.moveto(10,10); path2.lineto(100,10); - path2.conicto(10,100,40,80); + path2.quadto(10, 100, 40, 80); path2.cubicto(5,5,30,10,90,70); path2.lineto(20,30); EXPECT_TRUE(path1 != path2); @@ -197,10 +218,48 @@ TEST(GraphicsPathTest, unequals) { path2.clear(); path2.moveto(10,10); path2.lineto(100,10); - path2.conicto(10,100,40,80); + path2.quadto(10, 100, 40, 80); path2.cubicto(5,5,10,10,90,70); path2.lineto(20,30); path2.closepath(); EXPECT_TRUE(path1 != path2); EXPECT_TRUE(path2 != path1); } + + +TEST(GraphicsPathTest, approximate_arcs) { + GraphicsPath<double> path; + XMLString::DECIMAL_PLACES = 2; + path.moveto(10, 10); + path.lineto(20, 0); + path.arcto(30, 20, 20, 1, 1, DPair(50, 50)); + ostringstream oss; + path.writeSVG(oss, false); + EXPECT_EQ(oss.str(), "M10 10L20 0A30 20 20 1 1 50 50"); + path.approximateArcs(); + oss.str(""); + path.writeSVG(oss, false); + EXPECT_EQ(oss.str(), "M10 10L20 0C25.05-7.15 34.02-8.12 42.72-2.44S58.14 14.42 59.73 25.91S57.48 46.9 50 50"); +} + + +TEST(GraphicsPathTest, smooth_quadto) { + GraphicsPath<int> path; + path.moveto(10, 10); + path.quadto(DPair(30, 20), DPair(40, 10)); + path.quadto(DPair(100, 30)); + ostringstream oss; + path.writeSVG(oss, false); + EXPECT_EQ(oss.str(), "M10 10Q30 20 40 10T100 30"); +} + + +TEST(GraphicsPathTest, smooth_cubicto) { + GraphicsPath<int> path; + path.moveto(10, 10); + path.cubicto(DPair(30, 20), DPair(40, 0), DPair(20, 50)); + path.cubicto(DPair(80, 100), DPair(100, 30)); + ostringstream oss; + path.writeSVG(oss, false); + EXPECT_EQ(oss.str(), "M10 10C30 20 40 0 20 50S80 100 100 30"); +} diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/tests/HashFunctionTest.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/tests/HashFunctionTest.cpp index dad7a6276c9..64559c5aab8 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/tests/HashFunctionTest.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/tests/HashFunctionTest.cpp @@ -35,10 +35,8 @@ TEST(HashFunctionTest, md5) { md5.reset(); md5.update("0123456789"); EXPECT_EQ(md5.digestString(), "781e5e245d69b566979b86e28d23f2c7"); - uint8_t bytes[] = {0x78, 0x1e, 0x5e, 0x24, 0x5d, 0x69, 0xb5, 0x66, 0x97, 0x9b, 0x86, 0xe2, 0x8d, 0x23, 0xf2, 0xc7}; - int i=0; - for (uint8_t byte : md5.digestValue()) - EXPECT_EQ(byte, bytes[i++]); + vector<uint8_t> bytes = {0x78, 0x1e, 0x5e, 0x24, 0x5d, 0x69, 0xb5, 0x66, 0x97, 0x9b, 0x86, 0xe2, 0x8d, 0x23, 0xf2, 0xc7}; + EXPECT_EQ(md5.digestValue(), bytes); } @@ -52,10 +50,8 @@ TEST(HashFunctionTest, xxh32) { xxh32.reset(); xxh32.update("0123456789"); EXPECT_EQ(xxh32.digestString(), "950c9c0a"); - uint8_t bytes[] = {0x95, 0x0c, 0x9c, 0x0a}; - int i=0; - for (uint8_t byte : xxh32.digestValue()) - EXPECT_EQ(byte, bytes[i++]); + vector<uint8_t> bytes = {0x95, 0x0c, 0x9c, 0x0a}; + EXPECT_EQ(xxh32.digestValue(), bytes); } @@ -69,13 +65,28 @@ TEST(HashFunctionTest, xxh64) { xxh64.reset(); xxh64.update("0123456789"); EXPECT_EQ(xxh64.digestString(), "3f5fc178a81867e7"); - uint8_t bytes[] = {0x3f, 0x5f, 0xc1, 0x78, 0xa8, 0x18, 0x67, 0xe7}; - int i=0; - for (uint8_t byte : xxh64.digestValue()) - EXPECT_EQ(byte, bytes[i++]); + vector<uint8_t> bytes = {0x3f, 0x5f, 0xc1, 0x78, 0xa8, 0x18, 0x67, 0xe7}; + EXPECT_EQ(xxh64.digestValue(), bytes); } +#ifdef ENABLE_XXH128 +TEST(HashFunctionTest, xxh128) { + XXH128HashFunction xxh128; + ASSERT_EQ(xxh128.digestSize(), 16); + xxh128.update("0123456789"); + EXPECT_EQ(xxh128.digestString(), "942eb242912d99ecb1844fcc57198e3a"); + xxh128.update("abcdefghij"); + EXPECT_EQ(xxh128.digestString(), "f37bc26b7087c656f0345fdf02a75bc4"); + xxh128.reset(); + xxh128.update("0123456789"); + EXPECT_EQ(xxh128.digestString(), "942eb242912d99ecb1844fcc57198e3a"); + vector<uint8_t> bytes = {0x94, 0x2e, 0xb2, 0x42, 0x91, 0x2d, 0x99, 0xec, 0xb1, 0x84, 0x4f, 0xcc, 0x57, 0x19, 0x8e, 0x3a}; + EXPECT_EQ(xxh128.digestValue(), bytes); +} +#endif + + TEST(HashFunctionTest, createMD5) { auto hashfunc = HashFunction::create("md5"); ASSERT_TRUE(dynamic_cast<MD5HashFunction*>(hashfunc.get()) != nullptr); @@ -112,6 +123,20 @@ TEST(HashFunctionTest, createXXH64) { } +#ifdef ENABLE_XXH128 +TEST(HashFunctionTest, createXXH128) { + auto hashfunc = HashFunction::create("xxh128"); + ASSERT_TRUE(dynamic_cast<XXH128HashFunction*>(hashfunc.get()) != nullptr); + hashfunc->update("0123456789"); + EXPECT_EQ(hashfunc->digestString(), "942eb242912d99ecb1844fcc57198e3a"); + + hashfunc = HashFunction::create("xxh128", "0123456789"); + ASSERT_TRUE(dynamic_cast<XXH128HashFunction*>(hashfunc.get()) != nullptr); + EXPECT_EQ(hashfunc->digestString(), "942eb242912d99ecb1844fcc57198e3a"); +} +#endif + + TEST(HashFunctionTest, createFail) { ASSERT_TRUE(HashFunction::create("not-available") == nullptr); -}
\ No newline at end of file +} diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/tests/Makefile.am b/Build/source/texk/dvisvgm/dvisvgm-src/tests/Makefile.am index 3f69fb42054..002e7e82bf4 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/tests/Makefile.am +++ b/Build/source/texk/dvisvgm/dvisvgm-src/tests/Makefile.am @@ -16,6 +16,7 @@ EXTRA_DIST = gtest/LICENSE \ gtest/src/gtest-filepath.cc \ gtest/src/gtest-internal-inl.h \ gtest/src/gtest_main.cc \ + gtest/src/gtest-matchers.cc \ gtest/src/gtest-port.cc \ gtest/src/gtest-printers.cc \ gtest/src/gtest-test-part.cc \ @@ -51,7 +52,7 @@ hashcheck_LDADD = $(LIBS_LIBS) hashcheck.cpp: genhashcheck.py $(dvisvgm_srcdir)/src/AGLTable.hpp $(dvisvgm_srcdir)/libs/xxHash/xxhash.h python $^ >$@ -TESTLIBS = libgtest.la ../src/libdvisvgm.a $(LIBS_LIBS) -lfreetype +TESTLIBS = libgtest.la ../src/libdvisvgm.la $(LIBS_LIBS) -lfreetype if ENABLE_WOFF TESTLIBS += ../libs/ff-woff/libfontforge.a endif @@ -117,12 +118,6 @@ CommandLineTest_SOURCES = CommandLineTest.cpp testutil.hpp CommandLineTest_CPPFLAGS = -I$(dvisvgm_srcdir)/tests/gtest/include $(LIBS_CFLAGS) CommandLineTest_LDADD = $(TESTLIBS) -TESTS += CRC32Test -check_PROGRAMS += CRC32Test -CRC32Test_SOURCES = CRC32Test.cpp testutil.hpp -CRC32Test_CPPFLAGS = -I$(dvisvgm_srcdir)/tests/gtest/include $(LIBS_CFLAGS) -CRC32Test_LDADD = $(TESTLIBS) - TESTS += DependencyGraphTest check_PROGRAMS += DependencyGraphTest DependencyGraphTest_SOURCES = DependencyGraphTest.cpp testutil.hpp @@ -147,6 +142,12 @@ DvisvgmSpecialTest_SOURCES = DvisvgmSpecialTest.cpp testutil.hpp DvisvgmSpecialTest_CPPFLAGS = -I$(dvisvgm_srcdir)/tests/gtest/include $(LIBS_CFLAGS) DvisvgmSpecialTest_LDADD = $(TESTLIBS) +TESTS += EllipticalArcTest +check_PROGRAMS += EllipticalArcTest +EllipticalArcTest_SOURCES = EllipticalArcTest.cpp testutil.hpp +EllipticalArcTest_CPPFLAGS = -I$(dvisvgm_srcdir)/tests/gtest/include $(LIBS_CFLAGS) +EllipticalArcTest_LDADD = $(TESTLIBS) + TESTS += EmSpecialTest check_PROGRAMS += EmSpecialTest EmSpecialTest_SOURCES = EmSpecialTest.cpp testutil.hpp diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/tests/Makefile.in b/Build/source/texk/dvisvgm/dvisvgm-src/tests/Makefile.in index 99cbdc24510..e6fd46d52aa 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/tests/Makefile.in +++ b/Build/source/texk/dvisvgm/dvisvgm-src/tests/Makefile.in @@ -101,9 +101,9 @@ TESTS = hashcheck$(EXEEXT) BezierTest$(EXEEXT) BitmapTest$(EXEEXT) \ BoundingBoxTest$(EXEEXT) CalculatorTest$(EXEEXT) \ CMapManagerTest$(EXEEXT) CMapReaderTest$(EXEEXT) \ CMapTest$(EXEEXT) ColorSpecialTest$(EXEEXT) ColorTest$(EXEEXT) \ - CommandLineTest$(EXEEXT) CRC32Test$(EXEEXT) \ - DependencyGraphTest$(EXEEXT) DirectoryTest$(EXEEXT) \ - DVIReaderTest$(EXEEXT) DvisvgmSpecialTest$(EXEEXT) \ + CommandLineTest$(EXEEXT) DependencyGraphTest$(EXEEXT) \ + DirectoryTest$(EXEEXT) DVIReaderTest$(EXEEXT) \ + DvisvgmSpecialTest$(EXEEXT) EllipticalArcTest$(EXEEXT) \ EmSpecialTest$(EXEEXT) FileFinderTest$(EXEEXT) \ FilePathTest$(EXEEXT) FileSystemTest$(EXEEXT) \ FontCacheTest$(EXEEXT) FontManagerTest$(EXEEXT) \ @@ -132,9 +132,9 @@ check_PROGRAMS = hashcheck$(EXEEXT) BezierTest$(EXEEXT) \ CalculatorTest$(EXEEXT) CMapManagerTest$(EXEEXT) \ CMapReaderTest$(EXEEXT) CMapTest$(EXEEXT) \ ColorSpecialTest$(EXEEXT) ColorTest$(EXEEXT) \ - CommandLineTest$(EXEEXT) CRC32Test$(EXEEXT) \ - DependencyGraphTest$(EXEEXT) DirectoryTest$(EXEEXT) \ - DVIReaderTest$(EXEEXT) DvisvgmSpecialTest$(EXEEXT) \ + CommandLineTest$(EXEEXT) DependencyGraphTest$(EXEEXT) \ + DirectoryTest$(EXEEXT) DVIReaderTest$(EXEEXT) \ + DvisvgmSpecialTest$(EXEEXT) EllipticalArcTest$(EXEEXT) \ EmSpecialTest$(EXEEXT) FileFinderTest$(EXEEXT) \ FilePathTest$(EXEEXT) FileSystemTest$(EXEEXT) \ FontCacheTest$(EXEEXT) FontManagerTest$(EXEEXT) \ @@ -196,7 +196,7 @@ am__DEPENDENCIES_4 = @USE_BUNDLED_MD5_FALSE@am__DEPENDENCIES_5 = $(am__DEPENDENCIES_4) am__DEPENDENCIES_6 = $(POTRACE_LIBS) $(XXHASH_LIBS) \ $(am__DEPENDENCIES_3) $(am__append_7) $(am__DEPENDENCIES_5) -am__DEPENDENCIES_7 = libgtest.la ../src/libdvisvgm.a \ +am__DEPENDENCIES_7 = libgtest.la ../src/libdvisvgm.la \ $(am__DEPENDENCIES_6) $(am__append_10) $(am__DEPENDENCIES_4) BezierTest_DEPENDENCIES = $(am__DEPENDENCIES_7) am_BitmapTest_OBJECTS = BitmapTest-BitmapTest.$(OBJEXT) @@ -216,9 +216,6 @@ CMapReaderTest_DEPENDENCIES = $(am__DEPENDENCIES_7) am_CMapTest_OBJECTS = CMapTest-CMapTest.$(OBJEXT) CMapTest_OBJECTS = $(am_CMapTest_OBJECTS) CMapTest_DEPENDENCIES = $(am__DEPENDENCIES_7) -am_CRC32Test_OBJECTS = CRC32Test-CRC32Test.$(OBJEXT) -CRC32Test_OBJECTS = $(am_CRC32Test_OBJECTS) -CRC32Test_DEPENDENCIES = $(am__DEPENDENCIES_7) am_CalculatorTest_OBJECTS = CalculatorTest-CalculatorTest.$(OBJEXT) CalculatorTest_OBJECTS = $(am_CalculatorTest_OBJECTS) CalculatorTest_DEPENDENCIES = $(am__DEPENDENCIES_7) @@ -247,6 +244,10 @@ am_DvisvgmSpecialTest_OBJECTS = \ DvisvgmSpecialTest-DvisvgmSpecialTest.$(OBJEXT) DvisvgmSpecialTest_OBJECTS = $(am_DvisvgmSpecialTest_OBJECTS) DvisvgmSpecialTest_DEPENDENCIES = $(am__DEPENDENCIES_7) +am_EllipticalArcTest_OBJECTS = \ + EllipticalArcTest-EllipticalArcTest.$(OBJEXT) +EllipticalArcTest_OBJECTS = $(am_EllipticalArcTest_OBJECTS) +EllipticalArcTest_DEPENDENCIES = $(am__DEPENDENCIES_7) am_EmSpecialTest_OBJECTS = EmSpecialTest-EmSpecialTest.$(OBJEXT) EmSpecialTest_OBJECTS = $(am_EmSpecialTest_OBJECTS) EmSpecialTest_DEPENDENCIES = $(am__DEPENDENCIES_7) @@ -424,7 +425,6 @@ am__depfiles_remade = ./$(DEPDIR)/BezierTest-BezierTest.Po \ ./$(DEPDIR)/CMapManagerTest-CMapManagerTest.Po \ ./$(DEPDIR)/CMapReaderTest-CMapReaderTest.Po \ ./$(DEPDIR)/CMapTest-CMapTest.Po \ - ./$(DEPDIR)/CRC32Test-CRC32Test.Po \ ./$(DEPDIR)/CalculatorTest-CalculatorTest.Po \ ./$(DEPDIR)/ColorSpecialTest-ColorSpecialTest.Po \ ./$(DEPDIR)/ColorTest-ColorTest.Po \ @@ -433,6 +433,7 @@ am__depfiles_remade = ./$(DEPDIR)/BezierTest-BezierTest.Po \ ./$(DEPDIR)/DependencyGraphTest-DependencyGraphTest.Po \ ./$(DEPDIR)/DirectoryTest-DirectoryTest.Po \ ./$(DEPDIR)/DvisvgmSpecialTest-DvisvgmSpecialTest.Po \ + ./$(DEPDIR)/EllipticalArcTest-EllipticalArcTest.Po \ ./$(DEPDIR)/EmSpecialTest-EmSpecialTest.Po \ ./$(DEPDIR)/FileFinderTest-FileFinderTest.Po \ ./$(DEPDIR)/FilePathTest-FilePathTest.Po \ @@ -520,11 +521,11 @@ am__v_CCLD_1 = SOURCES = $(libgtest_la_SOURCES) $(BezierTest_SOURCES) \ $(BitmapTest_SOURCES) $(BoundingBoxTest_SOURCES) \ $(CMapManagerTest_SOURCES) $(CMapReaderTest_SOURCES) \ - $(CMapTest_SOURCES) $(CRC32Test_SOURCES) \ - $(CalculatorTest_SOURCES) $(ColorSpecialTest_SOURCES) \ - $(ColorTest_SOURCES) $(CommandLineTest_SOURCES) \ - $(DVIReaderTest_SOURCES) $(DependencyGraphTest_SOURCES) \ - $(DirectoryTest_SOURCES) $(DvisvgmSpecialTest_SOURCES) \ + $(CMapTest_SOURCES) $(CalculatorTest_SOURCES) \ + $(ColorSpecialTest_SOURCES) $(ColorTest_SOURCES) \ + $(CommandLineTest_SOURCES) $(DVIReaderTest_SOURCES) \ + $(DependencyGraphTest_SOURCES) $(DirectoryTest_SOURCES) \ + $(DvisvgmSpecialTest_SOURCES) $(EllipticalArcTest_SOURCES) \ $(EmSpecialTest_SOURCES) $(FileFinderTest_SOURCES) \ $(FilePathTest_SOURCES) $(FileSystemTest_SOURCES) \ $(FontCacheTest_SOURCES) $(FontManagerTest_SOURCES) \ @@ -552,11 +553,11 @@ SOURCES = $(libgtest_la_SOURCES) $(BezierTest_SOURCES) \ DIST_SOURCES = $(libgtest_la_SOURCES) $(BezierTest_SOURCES) \ $(BitmapTest_SOURCES) $(BoundingBoxTest_SOURCES) \ $(CMapManagerTest_SOURCES) $(CMapReaderTest_SOURCES) \ - $(CMapTest_SOURCES) $(CRC32Test_SOURCES) \ - $(CalculatorTest_SOURCES) $(ColorSpecialTest_SOURCES) \ - $(ColorTest_SOURCES) $(CommandLineTest_SOURCES) \ - $(DVIReaderTest_SOURCES) $(DependencyGraphTest_SOURCES) \ - $(DirectoryTest_SOURCES) $(DvisvgmSpecialTest_SOURCES) \ + $(CMapTest_SOURCES) $(CalculatorTest_SOURCES) \ + $(ColorSpecialTest_SOURCES) $(ColorTest_SOURCES) \ + $(CommandLineTest_SOURCES) $(DVIReaderTest_SOURCES) \ + $(DependencyGraphTest_SOURCES) $(DirectoryTest_SOURCES) \ + $(DvisvgmSpecialTest_SOURCES) $(EllipticalArcTest_SOURCES) \ $(EmSpecialTest_SOURCES) $(FileFinderTest_SOURCES) \ $(FilePathTest_SOURCES) $(FileSystemTest_SOURCES) \ $(FontCacheTest_SOURCES) $(FontManagerTest_SOURCES) \ @@ -1018,9 +1019,10 @@ libgtest_la_LDFLAGS = -pthread EXTRA_DIST = gtest/LICENSE gtest/include gtest/src/gtest.cc \ gtest/src/gtest-death-test.cc gtest/src/gtest-filepath.cc \ gtest/src/gtest-internal-inl.h gtest/src/gtest_main.cc \ - gtest/src/gtest-port.cc gtest/src/gtest-printers.cc \ - gtest/src/gtest-test-part.cc gtest/src/gtest-typed-test.cc \ - check-conv genhashcheck.py normalize.xsl + gtest/src/gtest-matchers.cc gtest/src/gtest-port.cc \ + gtest/src/gtest-printers.cc gtest/src/gtest-test-part.cc \ + gtest/src/gtest-typed-test.cc check-conv genhashcheck.py \ + normalize.xsl @HAVE_POTRACE_FALSE@POTRACE_CFLAGS = -I$(dvisvgm_srcdir)/libs/potrace @HAVE_POTRACE_FALSE@POTRACE_LIBS = ../libs/potrace/libpotrace.a @HAVE_XXHASH_FALSE@XXHASH_CFLAGS = -I$(dvisvgm_srcdir)/libs/xxHash @@ -1036,7 +1038,7 @@ AM_CXXFLAGS = -I$(dvisvgm_srcdir)/src -I$(dvisvgm_srcdir)/libs/variant/include \ nodist_hashcheck_SOURCES = hashcheck.cpp hashcheck_CPPFLAGS = $(LIBS_CFLAGS) hashcheck_LDADD = $(LIBS_LIBS) -TESTLIBS = libgtest.la ../src/libdvisvgm.a $(LIBS_LIBS) -lfreetype \ +TESTLIBS = libgtest.la ../src/libdvisvgm.la $(LIBS_LIBS) -lfreetype \ $(am__append_10) $(CODE_COVERAGE_LDFLAGS) BezierTest_SOURCES = BezierTest.cpp testutil.hpp BezierTest_CPPFLAGS = -I$(dvisvgm_srcdir)/tests/gtest/include $(LIBS_CFLAGS) @@ -1068,9 +1070,6 @@ ColorTest_LDADD = $(TESTLIBS) CommandLineTest_SOURCES = CommandLineTest.cpp testutil.hpp CommandLineTest_CPPFLAGS = -I$(dvisvgm_srcdir)/tests/gtest/include $(LIBS_CFLAGS) CommandLineTest_LDADD = $(TESTLIBS) -CRC32Test_SOURCES = CRC32Test.cpp testutil.hpp -CRC32Test_CPPFLAGS = -I$(dvisvgm_srcdir)/tests/gtest/include $(LIBS_CFLAGS) -CRC32Test_LDADD = $(TESTLIBS) DependencyGraphTest_SOURCES = DependencyGraphTest.cpp testutil.hpp DependencyGraphTest_CPPFLAGS = -I$(dvisvgm_srcdir)/tests/gtest/include $(LIBS_CFLAGS) DependencyGraphTest_LDADD = $(TESTLIBS) @@ -1083,6 +1082,9 @@ DVIReaderTest_LDADD = $(TESTLIBS) DvisvgmSpecialTest_SOURCES = DvisvgmSpecialTest.cpp testutil.hpp DvisvgmSpecialTest_CPPFLAGS = -I$(dvisvgm_srcdir)/tests/gtest/include $(LIBS_CFLAGS) DvisvgmSpecialTest_LDADD = $(TESTLIBS) +EllipticalArcTest_SOURCES = EllipticalArcTest.cpp testutil.hpp +EllipticalArcTest_CPPFLAGS = -I$(dvisvgm_srcdir)/tests/gtest/include $(LIBS_CFLAGS) +EllipticalArcTest_LDADD = $(TESTLIBS) EmSpecialTest_SOURCES = EmSpecialTest.cpp testutil.hpp EmSpecialTest_CPPFLAGS = -I$(dvisvgm_srcdir)/tests/gtest/include $(LIBS_CFLAGS) EmSpecialTest_LDADD = $(TESTLIBS) @@ -1306,10 +1308,6 @@ CMapTest$(EXEEXT): $(CMapTest_OBJECTS) $(CMapTest_DEPENDENCIES) $(EXTRA_CMapTest @rm -f CMapTest$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(CMapTest_OBJECTS) $(CMapTest_LDADD) $(LIBS) -CRC32Test$(EXEEXT): $(CRC32Test_OBJECTS) $(CRC32Test_DEPENDENCIES) $(EXTRA_CRC32Test_DEPENDENCIES) - @rm -f CRC32Test$(EXEEXT) - $(AM_V_CXXLD)$(CXXLINK) $(CRC32Test_OBJECTS) $(CRC32Test_LDADD) $(LIBS) - CalculatorTest$(EXEEXT): $(CalculatorTest_OBJECTS) $(CalculatorTest_DEPENDENCIES) $(EXTRA_CalculatorTest_DEPENDENCIES) @rm -f CalculatorTest$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(CalculatorTest_OBJECTS) $(CalculatorTest_LDADD) $(LIBS) @@ -1342,6 +1340,10 @@ DvisvgmSpecialTest$(EXEEXT): $(DvisvgmSpecialTest_OBJECTS) $(DvisvgmSpecialTest_ @rm -f DvisvgmSpecialTest$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(DvisvgmSpecialTest_OBJECTS) $(DvisvgmSpecialTest_LDADD) $(LIBS) +EllipticalArcTest$(EXEEXT): $(EllipticalArcTest_OBJECTS) $(EllipticalArcTest_DEPENDENCIES) $(EXTRA_EllipticalArcTest_DEPENDENCIES) + @rm -f EllipticalArcTest$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(EllipticalArcTest_OBJECTS) $(EllipticalArcTest_LDADD) $(LIBS) + EmSpecialTest$(EXEEXT): $(EmSpecialTest_OBJECTS) $(EmSpecialTest_DEPENDENCIES) $(EXTRA_EmSpecialTest_DEPENDENCIES) @rm -f EmSpecialTest$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(EmSpecialTest_OBJECTS) $(EmSpecialTest_LDADD) $(LIBS) @@ -1536,7 +1538,6 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CMapManagerTest-CMapManagerTest.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CMapReaderTest-CMapReaderTest.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CMapTest-CMapTest.Po@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CRC32Test-CRC32Test.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CalculatorTest-CalculatorTest.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ColorSpecialTest-ColorSpecialTest.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ColorTest-ColorTest.Po@am__quote@ # am--include-marker @@ -1545,6 +1546,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DependencyGraphTest-DependencyGraphTest.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DirectoryTest-DirectoryTest.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DvisvgmSpecialTest-DvisvgmSpecialTest.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/EllipticalArcTest-EllipticalArcTest.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/EmSpecialTest-EmSpecialTest.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FileFinderTest-FileFinderTest.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FilePathTest-FilePathTest.Po@am__quote@ # am--include-marker @@ -1721,20 +1723,6 @@ CMapTest-CMapTest.obj: CMapTest.cpp @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(CMapTest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o CMapTest-CMapTest.obj `if test -f 'CMapTest.cpp'; then $(CYGPATH_W) 'CMapTest.cpp'; else $(CYGPATH_W) '$(srcdir)/CMapTest.cpp'; fi` -CRC32Test-CRC32Test.o: CRC32Test.cpp -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(CRC32Test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT CRC32Test-CRC32Test.o -MD -MP -MF $(DEPDIR)/CRC32Test-CRC32Test.Tpo -c -o CRC32Test-CRC32Test.o `test -f 'CRC32Test.cpp' || echo '$(srcdir)/'`CRC32Test.cpp -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/CRC32Test-CRC32Test.Tpo $(DEPDIR)/CRC32Test-CRC32Test.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='CRC32Test.cpp' object='CRC32Test-CRC32Test.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(CRC32Test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o CRC32Test-CRC32Test.o `test -f 'CRC32Test.cpp' || echo '$(srcdir)/'`CRC32Test.cpp - -CRC32Test-CRC32Test.obj: CRC32Test.cpp -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(CRC32Test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT CRC32Test-CRC32Test.obj -MD -MP -MF $(DEPDIR)/CRC32Test-CRC32Test.Tpo -c -o CRC32Test-CRC32Test.obj `if test -f 'CRC32Test.cpp'; then $(CYGPATH_W) 'CRC32Test.cpp'; else $(CYGPATH_W) '$(srcdir)/CRC32Test.cpp'; fi` -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/CRC32Test-CRC32Test.Tpo $(DEPDIR)/CRC32Test-CRC32Test.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='CRC32Test.cpp' object='CRC32Test-CRC32Test.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(CRC32Test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o CRC32Test-CRC32Test.obj `if test -f 'CRC32Test.cpp'; then $(CYGPATH_W) 'CRC32Test.cpp'; else $(CYGPATH_W) '$(srcdir)/CRC32Test.cpp'; fi` - CalculatorTest-CalculatorTest.o: CalculatorTest.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(CalculatorTest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT CalculatorTest-CalculatorTest.o -MD -MP -MF $(DEPDIR)/CalculatorTest-CalculatorTest.Tpo -c -o CalculatorTest-CalculatorTest.o `test -f 'CalculatorTest.cpp' || echo '$(srcdir)/'`CalculatorTest.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/CalculatorTest-CalculatorTest.Tpo $(DEPDIR)/CalculatorTest-CalculatorTest.Po @@ -1847,6 +1835,20 @@ DvisvgmSpecialTest-DvisvgmSpecialTest.obj: DvisvgmSpecialTest.cpp @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(DvisvgmSpecialTest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o DvisvgmSpecialTest-DvisvgmSpecialTest.obj `if test -f 'DvisvgmSpecialTest.cpp'; then $(CYGPATH_W) 'DvisvgmSpecialTest.cpp'; else $(CYGPATH_W) '$(srcdir)/DvisvgmSpecialTest.cpp'; fi` +EllipticalArcTest-EllipticalArcTest.o: EllipticalArcTest.cpp +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(EllipticalArcTest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT EllipticalArcTest-EllipticalArcTest.o -MD -MP -MF $(DEPDIR)/EllipticalArcTest-EllipticalArcTest.Tpo -c -o EllipticalArcTest-EllipticalArcTest.o `test -f 'EllipticalArcTest.cpp' || echo '$(srcdir)/'`EllipticalArcTest.cpp +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/EllipticalArcTest-EllipticalArcTest.Tpo $(DEPDIR)/EllipticalArcTest-EllipticalArcTest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='EllipticalArcTest.cpp' object='EllipticalArcTest-EllipticalArcTest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(EllipticalArcTest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o EllipticalArcTest-EllipticalArcTest.o `test -f 'EllipticalArcTest.cpp' || echo '$(srcdir)/'`EllipticalArcTest.cpp + +EllipticalArcTest-EllipticalArcTest.obj: EllipticalArcTest.cpp +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(EllipticalArcTest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT EllipticalArcTest-EllipticalArcTest.obj -MD -MP -MF $(DEPDIR)/EllipticalArcTest-EllipticalArcTest.Tpo -c -o EllipticalArcTest-EllipticalArcTest.obj `if test -f 'EllipticalArcTest.cpp'; then $(CYGPATH_W) 'EllipticalArcTest.cpp'; else $(CYGPATH_W) '$(srcdir)/EllipticalArcTest.cpp'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/EllipticalArcTest-EllipticalArcTest.Tpo $(DEPDIR)/EllipticalArcTest-EllipticalArcTest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='EllipticalArcTest.cpp' object='EllipticalArcTest-EllipticalArcTest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(EllipticalArcTest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o EllipticalArcTest-EllipticalArcTest.obj `if test -f 'EllipticalArcTest.cpp'; then $(CYGPATH_W) 'EllipticalArcTest.cpp'; else $(CYGPATH_W) '$(srcdir)/EllipticalArcTest.cpp'; fi` + EmSpecialTest-EmSpecialTest.o: EmSpecialTest.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(EmSpecialTest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT EmSpecialTest-EmSpecialTest.o -MD -MP -MF $(DEPDIR)/EmSpecialTest-EmSpecialTest.Tpo -c -o EmSpecialTest-EmSpecialTest.o `test -f 'EmSpecialTest.cpp' || echo '$(srcdir)/'`EmSpecialTest.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/EmSpecialTest-EmSpecialTest.Tpo $(DEPDIR)/EmSpecialTest-EmSpecialTest.Po @@ -2825,13 +2827,6 @@ CommandLineTest.log: CommandLineTest$(EXEEXT) --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) -CRC32Test.log: CRC32Test$(EXEEXT) - @p='CRC32Test$(EXEEXT)'; \ - b='CRC32Test'; \ - $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ - --log-file $$b.log --trs-file $$b.trs \ - $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ - "$$tst" $(AM_TESTS_FD_REDIRECT) DependencyGraphTest.log: DependencyGraphTest$(EXEEXT) @p='DependencyGraphTest$(EXEEXT)'; \ b='DependencyGraphTest'; \ @@ -2860,6 +2855,13 @@ DvisvgmSpecialTest.log: DvisvgmSpecialTest$(EXEEXT) --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) +EllipticalArcTest.log: EllipticalArcTest$(EXEEXT) + @p='EllipticalArcTest$(EXEEXT)'; \ + b='EllipticalArcTest'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) EmSpecialTest.log: EmSpecialTest$(EXEEXT) @p='EmSpecialTest$(EXEEXT)'; \ b='EmSpecialTest'; \ @@ -3303,7 +3305,6 @@ distclean: distclean-recursive -rm -f ./$(DEPDIR)/CMapManagerTest-CMapManagerTest.Po -rm -f ./$(DEPDIR)/CMapReaderTest-CMapReaderTest.Po -rm -f ./$(DEPDIR)/CMapTest-CMapTest.Po - -rm -f ./$(DEPDIR)/CRC32Test-CRC32Test.Po -rm -f ./$(DEPDIR)/CalculatorTest-CalculatorTest.Po -rm -f ./$(DEPDIR)/ColorSpecialTest-ColorSpecialTest.Po -rm -f ./$(DEPDIR)/ColorTest-ColorTest.Po @@ -3312,6 +3313,7 @@ distclean: distclean-recursive -rm -f ./$(DEPDIR)/DependencyGraphTest-DependencyGraphTest.Po -rm -f ./$(DEPDIR)/DirectoryTest-DirectoryTest.Po -rm -f ./$(DEPDIR)/DvisvgmSpecialTest-DvisvgmSpecialTest.Po + -rm -f ./$(DEPDIR)/EllipticalArcTest-EllipticalArcTest.Po -rm -f ./$(DEPDIR)/EmSpecialTest-EmSpecialTest.Po -rm -f ./$(DEPDIR)/FileFinderTest-FileFinderTest.Po -rm -f ./$(DEPDIR)/FilePathTest-FilePathTest.Po @@ -3410,7 +3412,6 @@ maintainer-clean: maintainer-clean-recursive -rm -f ./$(DEPDIR)/CMapManagerTest-CMapManagerTest.Po -rm -f ./$(DEPDIR)/CMapReaderTest-CMapReaderTest.Po -rm -f ./$(DEPDIR)/CMapTest-CMapTest.Po - -rm -f ./$(DEPDIR)/CRC32Test-CRC32Test.Po -rm -f ./$(DEPDIR)/CalculatorTest-CalculatorTest.Po -rm -f ./$(DEPDIR)/ColorSpecialTest-ColorSpecialTest.Po -rm -f ./$(DEPDIR)/ColorTest-ColorTest.Po @@ -3419,6 +3420,7 @@ maintainer-clean: maintainer-clean-recursive -rm -f ./$(DEPDIR)/DependencyGraphTest-DependencyGraphTest.Po -rm -f ./$(DEPDIR)/DirectoryTest-DirectoryTest.Po -rm -f ./$(DEPDIR)/DvisvgmSpecialTest-DvisvgmSpecialTest.Po + -rm -f ./$(DEPDIR)/EllipticalArcTest-EllipticalArcTest.Po -rm -f ./$(DEPDIR)/EmSpecialTest-EmSpecialTest.Po -rm -f ./$(DEPDIR)/FileFinderTest-FileFinderTest.Po -rm -f ./$(DEPDIR)/FilePathTest-FilePathTest.Po diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/tests/MatrixTest.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/tests/MatrixTest.cpp index bc568e09d13..62eb6a1805c 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/tests/MatrixTest.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/tests/MatrixTest.cpp @@ -21,6 +21,7 @@ #include <gtest/gtest.h> #include <sstream> #include <vector> +#include <XMLString.hpp> #include "Calculator.hpp" #include "Matrix.hpp" @@ -68,14 +69,14 @@ TEST(MatrixTest, svg) { ostringstream oss; m1.write(oss); EXPECT_EQ(oss.str(), "((1,2,3),(4,5,6),(7,8,9))"); - EXPECT_EQ(m1.getSVG(), "matrix(1 4 2 5 3 6)"); + EXPECT_EQ(m1.toSVG(), "matrix(1 4 2 5 3 6)"); double v2[] = {1,2}; Matrix m2(v2, 2); oss.str(""); m2.write(oss); EXPECT_EQ(oss.str(), "((1,2,0),(0,1,0),(0,0,1))"); - EXPECT_EQ(m2.getSVG(), "matrix(1 0 2 1 0 0)"); + EXPECT_EQ(m2.toSVG(), "matrix(1 0 2 1 0 0)"); } @@ -86,7 +87,7 @@ TEST(MatrixTest, transpose) { ostringstream oss; m.write(oss); EXPECT_EQ(oss.str(), "((1,4,7),(2,5,8),(3,6,9))"); - EXPECT_EQ(m.getSVG(), "matrix(1 2 4 5 7 8)"); + EXPECT_EQ(m.toSVG(), "matrix(1 2 4 5 7 8)"); } @@ -131,25 +132,25 @@ TEST(MatrixTest, isTranslation) { } -TEST(MatrixTest, lmultiply) { +TEST(MatrixTest, rmultiply) { const Matrix m1({1, 2, 3, 4, 5, 6, 7, 8, 9}); const Matrix m2({9, 8, 7, 6, 5, 4, 3, 2, 1}); EXPECT_NE(m1, m2); Matrix m3; - EXPECT_EQ((m3=m1).lmultiply(m2), Matrix({30, 24, 18, 84, 69, 54, 138, 114, 90})); - EXPECT_EQ((m3=m2).lmultiply(m1), Matrix({90, 114, 138, 54, 69, 84, 18, 24, 30})); - EXPECT_EQ((m3=m1).lmultiply(Matrix(1)), m1); + EXPECT_EQ((m3 = m1).rmultiply(m2), Matrix({30, 24, 18, 84, 69, 54, 138, 114, 90})); + EXPECT_EQ((m3 = m2).rmultiply(m1), Matrix({90, 114, 138, 54, 69, 84, 18, 24, 30})); + EXPECT_EQ((m3 = m1).rmultiply(Matrix(1)), m1); } -TEST(MatrixTest, rmultiply) { +TEST(MatrixTest, lmultiply) { const Matrix m1({1, 2, 3, 4, 5, 6, 7, 8, 9}); const Matrix m2({9, 8, 7, 6, 5, 4, 3, 2, 1}); EXPECT_NE(m1, m2); Matrix m3; - EXPECT_EQ((m3=m1).rmultiply(m2), Matrix({90, 114, 138, 54, 69, 84, 18, 24, 30})); - EXPECT_EQ((m3=m2).rmultiply(m1), Matrix({30, 24, 18, 84, 69, 54, 138, 114, 90})); - EXPECT_EQ((m3=m1).rmultiply(Matrix(1)), m1); + EXPECT_EQ((m3 = m1).lmultiply(m2), Matrix({90, 114, 138, 54, 69, 84, 18, 24, 30})); + EXPECT_EQ((m3 = m2).lmultiply(m1), Matrix({30, 24, 18, 84, 69, 54, 138, 114, 90})); + EXPECT_EQ((m3 = m1).lmultiply(Matrix(1)), m1); } @@ -254,3 +255,23 @@ TEST(MatrixTest, fail) { EXPECT_THROW(Matrix("KY270", calc), ParserException); // invalid argument (pole at 90+180k degrees) EXPECT_THROW(Matrix("S2,", calc), ParserException); // missing argument } + + +TEST(MatrixTest, parseSVGTransform) { + XMLString::DECIMAL_PLACES = 3; + EXPECT_EQ( + Matrix::parseSVGTransform("translate(50, 90)").toSVG(), + "matrix(1 0 0 1 50 90)"); + EXPECT_EQ( + Matrix::parseSVGTransform("scale(10 20)").toSVG(), + "matrix(10 0 0 20 0 0)"); + EXPECT_EQ( + Matrix::parseSVGTransform("rotate(-45)").toSVG(), + "matrix(.707 -.707 .707 .707 0 0)"); + EXPECT_EQ( + Matrix::parseSVGTransform("translate(50, 90) rotate(-45) ").toSVG(), + "matrix(.707 -.707 .707 .707 50 90)"); + EXPECT_EQ( + Matrix::parseSVGTransform("translate(50, 90) rotate(-45) , translate(130 160)").toSVG(), + "matrix(.707 -.707 .707 .707 255.061 111.213)"); +} diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/tests/PSInterpreterTest.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/tests/PSInterpreterTest.cpp index 4203830ebf6..629f8d753b1 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/tests/PSInterpreterTest.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/tests/PSInterpreterTest.cpp @@ -61,6 +61,7 @@ class PSTestActions : public PSActions { void setlinewidth (vector<double> &p) override {print("setlinewidth", p);} void setmatrix (vector<double> &p) override {print("setmatrix", p);} void setmiterlimit (vector<double> &p) override {print("setmiterlimit", p);} + void setnulldevice (vector<double> &p) override {print("setnulldevice", p);} void setopacityalpha (vector<double> &p) override {print("setopacityalpha", p);} void setshapealpha (vector<double> &p) override {print("setshapealpha", p);} void setrgbcolor (vector<double> &p) override {print("setrgbcolor", p);} diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/tests/RangeMapTest.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/tests/RangeMapTest.cpp index 960d4ee3628..63f31ff1bb5 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/tests/RangeMapTest.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/tests/RangeMapTest.cpp @@ -46,12 +46,14 @@ TEST(RangeMapTest, disjoint_ranges) { RangeMap rangemap; rangemap.addRange(5, 8, 1); ASSERT_EQ(rangemap.numRanges(), 1u); + EXPECT_EQ(rangemap.numValues(), 4u); CHECK_RANGE("A", rangemap, 5, 8, 1); CHECK_ZERO("B", rangemap, 0, 4); CHECK_ZERO("C", rangemap, 9, 20); rangemap.addRange(10, 15, 5); ASSERT_EQ(rangemap.numRanges(), 2u); + EXPECT_EQ(rangemap.numValues(), 10u); CHECK_RANGE("D", rangemap, 5, 8, 1); CHECK_RANGE("E", rangemap, 10, 15, 5); CHECK_ZERO("F", rangemap, 0, 4); @@ -60,6 +62,7 @@ TEST(RangeMapTest, disjoint_ranges) { rangemap.addRange(0, 3, 50); ASSERT_EQ(rangemap.numRanges(), 3u); + EXPECT_EQ(rangemap.numValues(), 14u); CHECK_RANGE("I", rangemap, 0, 3, 50); CHECK_RANGE("J", rangemap, 5, 8, 1); CHECK_RANGE("K", rangemap, 10, 15, 5); @@ -69,6 +72,7 @@ TEST(RangeMapTest, disjoint_ranges) { rangemap.addRange(16, 20, 1); ASSERT_EQ(rangemap.numRanges(), 4u); + EXPECT_EQ(rangemap.numValues(), 19u); CHECK_RANGE("O", rangemap, 5, 8, 1); CHECK_RANGE("P", rangemap, 10, 15, 5); CHECK_RANGE("Q", rangemap, 0, 3, 50); @@ -80,19 +84,23 @@ TEST(RangeMapTest, touching_ranges1) { RangeMap rangemap; rangemap.addRange(5, 8, 10); ASSERT_EQ(rangemap.numRanges(), 1u); + EXPECT_EQ(rangemap.numValues(), 4u); CHECK_RANGE("A", rangemap, 5, 8, 10); rangemap.addRange(9, 15, 14); ASSERT_EQ(rangemap.numRanges(), 1u); + EXPECT_EQ(rangemap.numValues(), 11u); CHECK_RANGE("B", rangemap, 5, 15, 10); rangemap.addRange(1, 4, 5); ASSERT_EQ(rangemap.numRanges(), 2u); + EXPECT_EQ(rangemap.numValues(), 15u); CHECK_RANGE("C", rangemap, 1, 4, 5); CHECK_RANGE("D", rangemap, 5, 15, 10); rangemap.addRange(1, 4, 6); ASSERT_EQ(rangemap.numRanges(), 1u); + EXPECT_EQ(rangemap.numValues(), 15u); CHECK_RANGE("E", rangemap, 1, 15, 6); } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/tests/SVGOutputTest.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/tests/SVGOutputTest.cpp index d7753e24f50..60e3beefd98 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/tests/SVGOutputTest.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/tests/SVGOutputTest.cpp @@ -38,34 +38,34 @@ struct SVGOutputTest : public ::testing::Test { TEST_F(SVGOutputTest, defaults) { SVGOutput out("SVGOutputTest.cpp", ""); - EXPECT_EQ(out.filename(1, 1), "SVGOutputTest.svg"); - EXPECT_EQ(out.filename(5, 9), "SVGOutputTest-5.svg"); - EXPECT_EQ(out.filename(5, 10), "SVGOutputTest-05.svg"); - EXPECT_EQ(out.filename(5, 256), "SVGOutputTest-005.svg"); + EXPECT_EQ(out.filepath(1, 1).relative(), "SVGOutputTest.svg"); + EXPECT_EQ(out.filepath(5, 9).relative(), "SVGOutputTest-5.svg"); + EXPECT_EQ(out.filepath(5, 10).relative(), "SVGOutputTest-05.svg"); + EXPECT_EQ(out.filepath(5, 256).relative(), "SVGOutputTest-005.svg"); } TEST_F(SVGOutputTest, widthSpecifier) { { SVGOutput out("SVGOutputTest.cpp", "%f--%3p"); - EXPECT_EQ(out.filename(5, 9), "SVGOutputTest--005.svg"); - EXPECT_EQ(out.filename(54, 65), "SVGOutputTest--054.svg"); - EXPECT_EQ(out.filename(543, 654), "SVGOutputTest--543.svg"); + EXPECT_EQ(out.filepath(5, 9).relative(), "SVGOutputTest--005.svg"); + EXPECT_EQ(out.filepath(54, 65).relative(), "SVGOutputTest--054.svg"); + EXPECT_EQ(out.filepath(543, 654).relative(), "SVGOutputTest--543.svg"); }{ SVGOutput out("SVGOutputTest.cpp", "%f--%3p--%P"); - EXPECT_EQ(out.filename(5, 9), "SVGOutputTest--005--9.svg"); - EXPECT_EQ(out.filename(54, 65), "SVGOutputTest--054--65.svg"); - EXPECT_EQ(out.filename(543, 654), "SVGOutputTest--543--654.svg"); + EXPECT_EQ(out.filepath(5, 9).relative(), "SVGOutputTest--005--9.svg"); + EXPECT_EQ(out.filepath(54, 65).relative(), "SVGOutputTest--054--65.svg"); + EXPECT_EQ(out.filepath(543, 654).relative(), "SVGOutputTest--543--654.svg"); }{ SVGOutput out("SVGOutputTest.cpp", "%f--%3p--%3P"); - EXPECT_EQ(out.filename(5, 9), "SVGOutputTest--005--009.svg"); - EXPECT_EQ(out.filename(54, 65), "SVGOutputTest--054--065.svg"); - EXPECT_EQ(out.filename(543, 654), "SVGOutputTest--543--654.svg"); + EXPECT_EQ(out.filepath(5, 9).relative(), "SVGOutputTest--005--009.svg"); + EXPECT_EQ(out.filepath(54, 65).relative(), "SVGOutputTest--054--065.svg"); + EXPECT_EQ(out.filepath(543, 654).relative(), "SVGOutputTest--543--654.svg"); }{ SVGOutput out("SVGOutputTest.cpp", "%5f--%3p--%3P"); - EXPECT_EQ(out.filename(5, 9), "SVGOutputTest--005--009.svg"); - EXPECT_EQ(out.filename(54, 65), "SVGOutputTest--054--065.svg"); - EXPECT_EQ(out.filename(543, 654), "SVGOutputTest--543--654.svg"); + EXPECT_EQ(out.filepath(5, 9).relative(), "SVGOutputTest--005--009.svg"); + EXPECT_EQ(out.filepath(54, 65).relative(), "SVGOutputTest--054--065.svg"); + EXPECT_EQ(out.filepath(543, 654).relative(), "SVGOutputTest--543--654.svg"); } } @@ -73,24 +73,24 @@ TEST_F(SVGOutputTest, widthSpecifier) { TEST_F(SVGOutputTest, expressions) { { SVGOutput out("SVGOutputTest.cpp", "no-macro"); - EXPECT_EQ(out.filename(5, 9), "no-macro.svg"); - EXPECT_EQ(out.filename(54, 65), "no-macro.svg"); - EXPECT_EQ(out.filename(543, 654), "no-macro.svg"); + EXPECT_EQ(out.filepath(5, 9).relative(), "no-macro.svg"); + EXPECT_EQ(out.filepath(54, 65).relative(), "no-macro.svg"); + EXPECT_EQ(out.filepath(543, 654).relative(), "no-macro.svg"); }{ SVGOutput out("SVGOutputTest.cpp", "%f--%(p-1)"); - EXPECT_EQ(out.filename(5, 9), "SVGOutputTest--4.svg"); - EXPECT_EQ(out.filename(54, 65), "SVGOutputTest--53.svg"); - EXPECT_EQ(out.filename(543, 654), "SVGOutputTest--542.svg"); + EXPECT_EQ(out.filepath(5, 9).relative(), "SVGOutputTest--4.svg"); + EXPECT_EQ(out.filepath(54, 65).relative(), "SVGOutputTest--53.svg"); + EXPECT_EQ(out.filepath(543, 654).relative(), "SVGOutputTest--542.svg"); }{ SVGOutput out("SVGOutputTest.cpp", "%f--%3(p-1)"); - EXPECT_EQ(out.filename(5, 9), "SVGOutputTest--004.svg"); - EXPECT_EQ(out.filename(54, 65), "SVGOutputTest--053.svg"); - EXPECT_EQ(out.filename(543, 654), "SVGOutputTest--542.svg"); + EXPECT_EQ(out.filepath(5, 9).relative(), "SVGOutputTest--004.svg"); + EXPECT_EQ(out.filepath(54, 65).relative(), "SVGOutputTest--053.svg"); + EXPECT_EQ(out.filepath(543, 654).relative(), "SVGOutputTest--542.svg"); }{ SVGOutput out("SVGOutputTest.cpp", "%f--%3(P+2p)"); - EXPECT_EQ(out.filename(5, 9), "SVGOutputTest--019.svg"); - EXPECT_EQ(out.filename(54, 65), "SVGOutputTest--173.svg"); - EXPECT_EQ(out.filename(543, 654), "SVGOutputTest--1740.svg"); + EXPECT_EQ(out.filepath(5, 9).relative(), "SVGOutputTest--019.svg"); + EXPECT_EQ(out.filepath(54, 65).relative(), "SVGOutputTest--173.svg"); + EXPECT_EQ(out.filepath(543, 654).relative(), "SVGOutputTest--1740.svg"); } } @@ -99,16 +99,16 @@ TEST_F(SVGOutputTest, hashes) { SVGOutput::HashTriple hashes("dvihash", "opthash", "cmbhash"); { SVGOutput out("SVGOutputTest.cpp", "%f-%hd-x"); - EXPECT_EQ(out.filename(1, 10), "SVGOutputTest--x.svg"); - EXPECT_EQ(out.filename(1, 10, hashes), "SVGOutputTest-dvihash-x.svg"); + EXPECT_EQ(out.filepath(1, 10).relative(), "SVGOutputTest--x.svg"); + EXPECT_EQ(out.filepath(1, 10, hashes).relative(), "SVGOutputTest-dvihash-x.svg"); }{ SVGOutput out("SVGOutputTest.cpp", "%f-%hd-x-%hc%ho"); - EXPECT_EQ(out.filename(1, 10), "SVGOutputTest--x-.svg"); - EXPECT_EQ(out.filename(1, 10, hashes), "SVGOutputTest-dvihash-x-cmbhashopthash.svg"); + EXPECT_EQ(out.filepath(1, 10).relative(), "SVGOutputTest--x-.svg"); + EXPECT_EQ(out.filepath(1, 10, hashes).relative(), "SVGOutputTest-dvihash-x-cmbhashopthash.svg"); }{ SVGOutput out("SVGOutputTest.cpp", "%f-%hd%p%ho"); - EXPECT_EQ(out.filename(1, 10), "SVGOutputTest-01.svg"); - EXPECT_EQ(out.filename(1, 10, hashes), "SVGOutputTest-dvihash01opthash.svg"); + EXPECT_EQ(out.filepath(1, 10).relative(), "SVGOutputTest-01.svg"); + EXPECT_EQ(out.filepath(1, 10, hashes).relative(), "SVGOutputTest-dvihash01opthash.svg"); } } @@ -117,12 +117,12 @@ TEST_F(SVGOutputTest, hashes_fail) { SVGOutput::HashTriple hashes("dvihash", "opthash", "cmbhash"); { SVGOutput out("SVGOutputTest.cpp", "%f-%h-x"); - EXPECT_THROW(out.filename(1, 10), MessageException); - EXPECT_THROW(out.filename(1, 10, hashes), MessageException); + EXPECT_THROW(out.filepath(1, 10).relative(), MessageException); + EXPECT_THROW(out.filepath(1, 10, hashes).relative(), MessageException); }{ SVGOutput out("SVGOutputTest.cpp", "%f-%hd-x-%ha%ho"); - EXPECT_THROW(out.filename(1, 10), MessageException); - EXPECT_THROW(out.filename(1, 10, hashes), MessageException); + EXPECT_THROW(out.filepath(1, 10).relative(), MessageException); + EXPECT_THROW(out.filepath(1, 10, hashes).relative(), MessageException); } } @@ -151,11 +151,11 @@ TEST_F(SVGOutputTest, getPageStream) { TEST_F(SVGOutputTest, ignore) { SVGOutput out("SVGOutputTest.cpp", "%x %y"); - EXPECT_EQ(out.filename(5, 9), "SVGOutputTest-5.svg"); + EXPECT_EQ(out.filepath(5, 9).relative(), "SVGOutputTest-5.svg"); } TEST_F(SVGOutputTest, error) { SVGOutput out("SVGOutputTest.cpp", "%(p/0)"); - EXPECT_THROW(out.filename(5, 9), MessageException); + EXPECT_THROW(out.filepath(5, 9).relative(), MessageException); } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/tests/StreamInputBufferTest.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/tests/StreamInputBufferTest.cpp index f1ebdc4d798..e5bf646ec90 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/tests/StreamInputBufferTest.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/tests/StreamInputBufferTest.cpp @@ -21,6 +21,7 @@ #include <gtest/gtest.h> #include <map> #include <sstream> +#include <stdexcept> #include <string> #include "InputBuffer.hpp" #include "InputReader.hpp" @@ -83,6 +84,20 @@ TEST(StreamInputBufferTest, skip) { } +TEST(StreamInputBufferTest, readUntil) { + istringstream iss("abcdefghijklmnopqrstuvwxyz"); + StreamInputBuffer buffer(iss, 10); + BufferInputReader in(buffer); + EXPECT_EQ(in.readUntil("ijk"), "abcdefghijk"); + EXPECT_EQ(in.peek(), 'l'); + EXPECT_EQ(in.readUntil("q"), "lmnopq"); + EXPECT_EQ(in.peek(), 'r'); + EXPECT_EQ(in.readUntil("X"), "rstuvwxyz"); + EXPECT_LT(in.peek(), 0); + EXPECT_TRUE(in.eof()); +} + + TEST(StreamInputBufferTest, parseInt) { istringstream iss("1234,-5,+6,10.-"); StreamInputBuffer buffer(iss, 10); @@ -180,16 +195,34 @@ TEST(StreamInputBufferTest, parseDouble) { } -TEST(StreamInputBufferTest, attribs) { - istringstream iss("aaa=1 bbb=2 ccc=3 d e"); +TEST(StreamInputBufferTest, attribs1) { + istringstream iss("aaa=1 bbb=2 c-c-c=3 3d=4 e"); StreamInputBuffer buffer(iss, 10); BufferInputReader in(buffer); map<string,string> attr; - int s = in.parseAttributes(attr); + int s = in.parseAttributes(attr, true); EXPECT_EQ(s, 3); EXPECT_EQ(attr["aaa"], "1"); EXPECT_EQ(attr["bbb"], "2"); - EXPECT_EQ(attr["ccc"], "3"); + EXPECT_EQ(attr["c-c-c"], "3"); + EXPECT_THROW(attr.at("3d"), std::out_of_range); + EXPECT_THROW(attr.at("e"), std::out_of_range); +} + + +TEST(StreamInputBufferTest, attribs2) { + istringstream iss("aaa='1' bbb='2' c-c-c='3' d e='value'"); + StreamInputBuffer buffer(iss, 10); + BufferInputReader in(buffer); + map<string,string> attr; + int s = in.parseAttributes(attr, false, "'"); + EXPECT_EQ(s, 5); + EXPECT_EQ(attr["aaa"], "1"); + EXPECT_EQ(attr["bbb"], "2"); + EXPECT_EQ(attr["c-c-c"], "3"); + EXPECT_EQ(attr["e"], "value"); + EXPECT_NO_THROW(attr.at("d")); + EXPECT_TRUE(attr.at("d").empty()); } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/tests/StreamReaderTest.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/tests/StreamReaderTest.cpp index 0f3b5b708f2..e769ab0f443 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/tests/StreamReaderTest.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/tests/StreamReaderTest.cpp @@ -22,8 +22,8 @@ #include <fstream> #include <sstream> #include <string> -#include "CRC32.hpp" #include "StreamReader.hpp" +#include "XXHashFunction.hpp" using namespace std; @@ -41,20 +41,20 @@ TEST(StreamReaderTest, readString) { } -TEST(StreamReaderTest, readStringCRC) { +TEST(StreamReaderTest, readString_hashed) { string str1 = "dvisvgm converts DVI files to SVG."; istringstream iss(str1); ASSERT_TRUE(bool(iss)); StreamReader reader(iss); - CRC32 crc; - string str2 = reader.readString(iss.str().length(), crc); + XXH32HashFunction hashfunc; + string str2 = reader.readString(iss.str().length(), hashfunc); EXPECT_EQ(str1, str2); - EXPECT_EQ(crc.get(), 0x7c4ef359u); + EXPECT_EQ(hashfunc.digestString(), "190cc9d2"); iss.clear(); iss.str(str1); - crc.reset(); - str2 = reader.readString(crc, false); - EXPECT_EQ(crc.get(), 0x7c4ef359u); + hashfunc.reset(); + str2 = reader.readString(hashfunc, false); + EXPECT_EQ(hashfunc.digestString(), "190cc9d2"); } @@ -67,14 +67,14 @@ TEST(StreamReaderTest, readUnsigned) { } -TEST(StreamReaderTest, readUnsignedCRC) { +TEST(StreamReaderTest, readUnsigned_hashed) { string str = "\x01\x02\x03\x04"; istringstream iss(str); StreamReader reader(iss); - CRC32 crc; - uint32_t val = reader.readUnsigned(4, crc); + XXH32HashFunction hashfunc; + uint32_t val = reader.readUnsigned(4, hashfunc); EXPECT_EQ(val, 0x01020304u); - EXPECT_EQ(crc.get(), 0xb63cfbcdu); + EXPECT_EQ(hashfunc.digestString(), "fe96d19c"); } @@ -87,14 +87,14 @@ TEST(StreamReaderTest, readSigned) { } -TEST(StreamReaderTest, readSignedCRC) { +TEST(StreamReaderTest, readSigned_hashed) { string str = "\xff\xee\xdd\xcc"; istringstream iss(str); StreamReader reader(iss); - CRC32 crc; - int32_t val = reader.readSigned(4, crc); + XXH32HashFunction hashfunc; + int32_t val = reader.readSigned(4, hashfunc); EXPECT_EQ(val, int32_t(0xffeeddcc)); - EXPECT_EQ(crc.get(), 0xfa79118eu); + EXPECT_EQ(hashfunc.digestString(), "8baa29bd"); } @@ -102,31 +102,27 @@ TEST(StreamReaderTest, readBytes) { string str = "\xff\xee\xdd\xcc"; istringstream iss(str); StreamReader reader(iss); - vector<uint8_t> bytes(4); - memset(&bytes[0], 0, 4); - reader.readBytes(3, bytes); + vector<uint8_t> bytes = reader.readBytes(3); + EXPECT_EQ(bytes.size(), 3u); EXPECT_EQ(bytes[0], 0xff); EXPECT_EQ(bytes[1], 0xee); EXPECT_EQ(bytes[2], 0xdd); - EXPECT_EQ(bytes[3], 0); } -TEST(StreamReaderTest, readBytesCRC) { +TEST(StreamReaderTest, readBytes_hashed) { string str = "\xff\xee\xdd\xcc"; istringstream iss(str); StreamReader reader(iss); - vector<uint8_t> bytes(4); - memset(&bytes[0], 0, 4); - CRC32 crc; - reader.readBytes(3, bytes, crc); + XXH32HashFunction hashfunc; + vector<uint8_t> bytes = reader.readBytes(3, hashfunc); + EXPECT_EQ(bytes.size(), 3u); EXPECT_EQ(bytes[0], 0xff); EXPECT_EQ(bytes[1], 0xee); EXPECT_EQ(bytes[2], 0xdd); - EXPECT_EQ(bytes[3], 0); - EXPECT_EQ(crc.get(), 0x68ab9f15u); - int byte = reader.readByte(crc); + EXPECT_EQ(hashfunc.digestString(), "5eda43a0"); + int byte = reader.readByte(hashfunc); EXPECT_EQ(byte, 0xcc); - EXPECT_EQ(crc.get(), 0x2d652e62u); + EXPECT_EQ(hashfunc.digestString(), "8baa29bd"); } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/tests/StreamWriterTest.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/tests/StreamWriterTest.cpp index b5e7f8fc89e..aa2cadb9c92 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/tests/StreamWriterTest.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/tests/StreamWriterTest.cpp @@ -21,8 +21,8 @@ #include <gtest/gtest.h> #include <sstream> #include <string> -#include "CRC32.hpp" #include "StreamWriter.hpp" +#include "XXHashFunction.hpp" using namespace std; @@ -40,21 +40,21 @@ TEST(StreamWriterTest, writeString) { } -TEST(StreamWriterTest, writeStringCRC) { +TEST(StreamWriterTest, writeString_hashed) { ostringstream oss; StreamWriter writer(oss); - CRC32 crc; + XXH32HashFunction hashfunc; string str = "dvisvgm converts DVI files to SVG."; - writer.writeString(str, crc); + writer.writeString(str, hashfunc); EXPECT_EQ(oss.str(), str); - EXPECT_EQ(crc.get(), 0x7C4EF359u); + EXPECT_EQ(hashfunc.digestString(), "190cc9d2"); oss.str(""); - crc.reset(); - writer.writeString(str, crc, true); + hashfunc.reset(); + writer.writeString(str, hashfunc, true); str.push_back('\0'); EXPECT_EQ(oss.str(), str); - EXPECT_EQ(crc.get(), 0xc0c9482e); + EXPECT_EQ(hashfunc.digestString(), "f82e1606"); } @@ -71,18 +71,18 @@ TEST(StreamWriterTest, writeUnsigned) { } -TEST(StreamWriterTest, writeUnsignedCRC) { +TEST(StreamWriterTest, writeUnsigned_hashed) { ostringstream oss; StreamWriter writer(oss); - CRC32 crc; - writer.writeUnsigned(0x00010203, 4, crc); + XXH32HashFunction hashfunc; + writer.writeUnsigned(0x00010203, 4, hashfunc); string str; str.push_back('\x00'); str.push_back('\x01'); str.push_back('\x02'); str.push_back('\x03'); EXPECT_EQ(oss.str(), str); - EXPECT_EQ(crc.get(), 0x8bb98613); + EXPECT_EQ(hashfunc.digestString(), "80691e66"); } @@ -95,12 +95,12 @@ TEST(StreamWriterTest, writeSigned) { } -TEST(StreamWriterTest, writeSignedCRC) { +TEST(StreamWriterTest, writeSigned_hashed) { ostringstream oss; StreamWriter writer(oss); - CRC32 crc; - writer.writeSigned(0xffeeddcc, 4, crc); + XXH32HashFunction hashfunc; + writer.writeSigned(0xffeeddcc, 4, hashfunc); string str = "\xff\xee\xdd\xcc"; EXPECT_EQ(oss.str(), str); - EXPECT_EQ(crc.get(), 0xfa79118e); + EXPECT_EQ(hashfunc.digestString(), "8baa29bd"); } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/tests/StringMatcherTest.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/tests/StringMatcherTest.cpp index 9945de25991..df2bb81cdb5 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/tests/StringMatcherTest.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/tests/StringMatcherTest.cpp @@ -30,6 +30,7 @@ TEST(StringMatcherTest, match1) { StreamInputReader ir(iss); EXPECT_FALSE(matcher.match(ir)); EXPECT_EQ(matcher.charsRead(), 0u); + EXPECT_LT(ir.peek(), 0); } @@ -39,6 +40,7 @@ TEST(StringMatcherTest, match2) { StreamInputReader ir(iss); EXPECT_TRUE(matcher.match(ir)); EXPECT_EQ(matcher.charsRead(), 1u); + EXPECT_EQ(ir.peek(), 'b'); } @@ -48,6 +50,7 @@ TEST(StringMatcherTest, match3) { StreamInputReader ir(iss); EXPECT_FALSE(matcher.match(ir)); EXPECT_EQ(matcher.charsRead(), 15u); + EXPECT_LT(ir.peek(), 0); } @@ -57,14 +60,17 @@ TEST(StringMatcherTest, match4) { StreamInputReader ir(iss); EXPECT_TRUE(matcher.match(ir)); EXPECT_EQ(matcher.charsRead(), 13u); + EXPECT_EQ(ir.peek(), 'x'); iss.clear(); iss.str("abcpatpattern"); EXPECT_TRUE(matcher.match(ir)); EXPECT_EQ(matcher.charsRead(), 13u); + EXPECT_LT(ir.peek(), 0); iss.clear(); iss.str("pattern"); EXPECT_TRUE(matcher.match(ir)); EXPECT_EQ(matcher.charsRead(), 7u); + EXPECT_LT(ir.peek(), 0); } @@ -74,4 +80,65 @@ TEST(StringMatcherTest, match5) { StreamInputReader ir(iss); EXPECT_TRUE(matcher.match(ir)); EXPECT_EQ(matcher.charsRead(), 13u); + EXPECT_EQ(ir.peek(), 'x'); +} + + +TEST(StringMatcherTest, read1) { + istringstream iss; + StringMatcher matcher("pattern"); + StreamInputReader ir(iss); + EXPECT_TRUE(matcher.read(ir).empty()); + EXPECT_EQ(matcher.charsRead(), 0u); + EXPECT_LT(ir.peek(), 0); +} + + +TEST(StringMatcherTest, read2) { + istringstream iss("abcpatpatternxyz"); + StringMatcher matcher(""); + StreamInputReader ir(iss); + EXPECT_EQ(matcher.read(ir), "a"); + EXPECT_EQ(matcher.charsRead(), 1u); + EXPECT_EQ(ir.peek(), 'b'); +} + + +TEST(StringMatcherTest, read3) { + istringstream iss("abcpatatternxyz"); + StringMatcher matcher("pattern"); + StreamInputReader ir(iss); + EXPECT_EQ(matcher.read(ir), "abcpatatternxyz"); + EXPECT_EQ(matcher.charsRead(), 15u); + EXPECT_LT(ir.peek(), 0); +} + + +TEST(StringMatcherTest, read4) { + istringstream iss("abcpatpatternxyz"); + StringMatcher matcher("pattern"); + StreamInputReader ir(iss); + EXPECT_EQ(matcher.read(ir), "abcpatpattern"); + EXPECT_EQ(matcher.charsRead(), 13u); + EXPECT_EQ(ir.peek(), 'x'); + iss.clear(); + iss.str("abcpatpattern"); + EXPECT_EQ(matcher.read(ir), "abcpatpattern"); + EXPECT_EQ(matcher.charsRead(), 13u); + EXPECT_LT(ir.peek(), 0); + iss.clear(); + iss.str("pattern"); + EXPECT_EQ(matcher.read(ir), "pattern"); + EXPECT_EQ(matcher.charsRead(), 7u); + EXPECT_LT(ir.peek(), 0); +} + + +TEST(StringMatcherTest, read5) { + istringstream iss("abcpatpatternxyz"); + StringMatcher matcher("pattern"); + StreamInputReader ir(iss); + EXPECT_EQ(matcher.read(ir), "abcpatpattern"); + EXPECT_EQ(matcher.charsRead(), 13u); + EXPECT_EQ(ir.peek(), 'x'); } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/tests/TensorProductPatchTest.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/tests/TensorProductPatchTest.cpp index 7a7c1da4100..a051f7d70dd 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/tests/TensorProductPatchTest.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/tests/TensorProductPatchTest.cpp @@ -235,8 +235,7 @@ TEST_F(TensorProductPatchTest, values) { TEST_F(TensorProductPatchTest, boundaryPath) { - GraphicsPath<double> path; - _patch.getBoundaryPath(path); + GraphicsPath<double> path = _patch.getBoundaryPath(); ostringstream oss; path.writeSVG(oss, false); EXPECT_EQ(oss.str(), "M10 10C20 0 50 30 70 20C80 50 90 60 100 70C70 100 20 100 10 70C20 40 0 30 10 10Z"); @@ -246,8 +245,7 @@ TEST_F(TensorProductPatchTest, boundaryPath) { TEST_F(TensorProductPatchTest, subpatch) { TensorProductPatch tpp; _patch.subpatch(0, 0.5, 0, 0.5, tpp); - GraphicsPath<double> path; - tpp.getBoundaryPath(path); + GraphicsPath<double> path = tpp.getBoundaryPath(); ostringstream oss; path.writeSVG(oss, false); EXPECT_EQ(oss.str(), "M10 10C5 20 7.5 27.5 10 36.25C20.625 46.875 31.25 52.1875 43.28125 54.21875C40 40.9375 36.25 27.5 36.25 15C25 10 15 5 10 10Z"); @@ -259,8 +257,7 @@ TEST_F(TensorProductPatchTest, subpatch) { TEST_F(TensorProductPatchTest, bbox) { - BoundingBox bbox; - _patch.getBBox(bbox); + BoundingBox bbox = _patch.getBBox(); EXPECT_NEAR(bbox.minX(), 7.1132, 0.0001); EXPECT_NEAR(bbox.minY(), 7.9289, 0.0001); EXPECT_DOUBLE_EQ(bbox.maxX(), 100.0); diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/tests/TpicSpecialTest.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/tests/TpicSpecialTest.cpp index 0f4d6546d63..afc92d54be9 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/tests/TpicSpecialTest.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/tests/TpicSpecialTest.cpp @@ -33,40 +33,39 @@ class TpicSpecialTest : public ::testing::Test { protected: class ActionsRecorder : public EmptySpecialActions { public: - ActionsRecorder () : x(), y(), page("page") {} - void appendToPage(unique_ptr<XMLNode> &&node) {page.append(std::move(node));} - void embed (const BoundingBox &bb) {bbox.embed(bb);} - void setX (double xx) {x = xx;} - void setY (double yy) {x = yy;} - double getX () const {return x;} - double getY () const {return y;} - Color getColor () const {return color;} - void setColor (const Color &c) {color = c;} - void clear () {page.clear(); bbox=BoundingBox(0, 0, 0, 0);} - const Matrix& getMatrix () const {static Matrix m(1); return m;} + ActionsRecorder () : x(), y() {} + void embed (const BoundingBox &bb) override {bbox.embed(bb);} + void setX (double xx) override {x = xx;} + void setY (double yy) override {x = yy;} + double getX () const override {return x;} + double getY () const override {return y;} + Color getColor () const override {return color;} + void setColor (const Color &c) override {color = c;} + const Matrix& getMatrix () const override {static Matrix m(1); return m;} + string getXMLSnippet () const { ostringstream oss; - for (const auto &child : page.children()) + for (XMLNode *child : *svgTree().pageNode()) child->write(oss); return oss.str(); } - void write (ostream &os) const { - os << "page: " << page << '\n' - << "bbox: " << bbox.toSVGViewBox() << '\n'; + void clear () { + SpecialActions::svgTree().reset(); + SpecialActions::svgTree().newPage(1); + bbox = BoundingBox(0, 0, 0, 0); } private: double x, y; Color color; - XMLElementNode page; BoundingBox bbox; }; class MyTpicSpecialHandler : public TpicSpecialHandler { public: - MyTpicSpecialHandler (SpecialActions &a) : actions(a) {} + explicit MyTpicSpecialHandler (SpecialActions &a) : actions(a) {} void finishPage () {dviEndPage(0, actions);} bool processSpecial (const string &cmd, string params="") { stringstream ss; @@ -251,7 +250,7 @@ TEST_F(TpicSpecialTest, stroke_spline) { handler.processSpecial("pa", "1000 500"); handler.processSpecial("sp"); EXPECT_EQ(recorder.getXMLSnippet(), - "<path fill='none' d='M0 0L36 36Q72 72 90 54Q108 36 126 54T180 108Q216 144 144 90L72 36' stroke='#000' stroke-width='1'/>" + "<path fill='none' d='M0 0L36 36Q72 72 90 54T126 54T180 108T144 90L72 36' stroke='#000' stroke-width='1'/>" ); EXPECT_DOUBLE_EQ(handler.penwidth(), 1.0); EXPECT_LT(handler.grayLevel(), 0); @@ -267,7 +266,7 @@ TEST_F(TpicSpecialTest, stroke_dashed_spline) { handler.processSpecial("pa", "0 0"); handler.processSpecial("sp", "1"); EXPECT_EQ(recorder.getXMLSnippet(), - "<path fill='none' d='M0 0L36 36Q72 72 90 54Q108 36 126 54T180 108Q216 144 108 72Z' stroke='#000' stroke-width='1' stroke-dasharray='72'/>" + "<path fill='none' d='M0 0L36 36Q72 72 90 54T126 54T180 108T108 72Z' stroke='#000' stroke-width='1' stroke-dasharray='72'/>" ); EXPECT_DOUBLE_EQ(handler.penwidth(), 1.0); EXPECT_LT(handler.grayLevel(), 0); @@ -283,7 +282,7 @@ TEST_F(TpicSpecialTest, stroke_dotted_spline) { handler.processSpecial("pa", "1000 500"); handler.processSpecial("sp", "-1"); EXPECT_EQ(recorder.getXMLSnippet(), - "<path fill='none' d='M0 0L36 36Q72 72 90 54Q108 36 126 54T180 108Q216 144 144 90L72 36' stroke='#000' stroke-width='1' stroke-dasharray='1 72'/>" + "<path fill='none' d='M0 0L36 36Q72 72 90 54T126 54T180 108T144 90L72 36' stroke='#000' stroke-width='1' stroke-dasharray='1 72'/>" ); EXPECT_DOUBLE_EQ(handler.penwidth(), 1.0); EXPECT_LT(handler.grayLevel(), 0); @@ -344,22 +343,22 @@ TEST_F(TpicSpecialTest, stroke_arc) { recorder.clear(); handler.processSpecial("ar", "0 0 1000 500 0 "+to_string(3*math::PI/4)); EXPECT_EQ(recorder.getXMLSnippet(), - "<path d='M72 0A72 36 0 0 1 -50.91 25.46' stroke-width='1' stroke='#000' stroke-linecap='round' fill='none'/>" + "<path d='M72 0A72 36 0 0 1-50.91 25.46' stroke-width='1' stroke='#000' stroke-linecap='round' fill='none'/>" ); recorder.clear(); handler.processSpecial("ar", "0 0 1000 500 0 "+to_string(math::PI)); EXPECT_EQ(recorder.getXMLSnippet(), - "<path d='M72 0A72 36 0 1 1 -72 0' stroke-width='1' stroke='#000' stroke-linecap='round' fill='none'/>" + "<path d='M72 0A72 36 0 1 1-72 0' stroke-width='1' stroke='#000' stroke-linecap='round' fill='none'/>" ); recorder.clear(); handler.processSpecial("ar", "0 0 1000 500 0 "+to_string(5*math::PI/4)); EXPECT_EQ(recorder.getXMLSnippet(), - "<path d='M72 0A72 36 0 1 1 -50.91 -25.46' stroke-width='1' stroke='#000' stroke-linecap='round' fill='none'/>" + "<path d='M72 0A72 36 0 1 1-50.91-25.46' stroke-width='1' stroke='#000' stroke-linecap='round' fill='none'/>" ); recorder.clear(); handler.processSpecial("ar", "0 0 1000 500 0 "+to_string(3*math::PI/2)); EXPECT_EQ(recorder.getXMLSnippet(), - "<path d='M72 0A72 36 0 1 1 0 -36' stroke-width='1' stroke='#000' stroke-linecap='round' fill='none'/>" + "<path d='M72 0A72 36 0 1 1 0-36' stroke-width='1' stroke='#000' stroke-linecap='round' fill='none'/>" ); recorder.clear(); handler.processSpecial("ar", "0 0 1000 500 0 "+to_string(-3*math::PI/2)); diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/tests/TriangularPatchTest.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/tests/TriangularPatchTest.cpp index 04ae3f01677..07c8819e2c6 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/tests/TriangularPatchTest.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/tests/TriangularPatchTest.cpp @@ -123,8 +123,7 @@ TEST(TriangularPatchTest, bbox) { points[2] = DPair(0, 10); vector<Color> colors(3); TriangularPatch tp(points, colors, Color::ColorSpace::RGB, 0, 0); - BoundingBox bbox; - tp.getBBox(bbox); + BoundingBox bbox = tp.getBBox(); EXPECT_EQ(bbox, BoundingBox(0, 0, 10, 10)); } @@ -136,8 +135,7 @@ TEST(TriangularPatchTest, boundaryPath) { points[2] = DPair(0, 10); vector<Color> colors(3); TriangularPatch tp(points, colors, Color::ColorSpace::RGB, 0, 0); - GraphicsPath<double> path; - tp.getBoundaryPath(path); + GraphicsPath<double> path = tp.getBoundaryPath(); ostringstream oss; path.writeSVG(oss, false); EXPECT_EQ(oss.str(), "M0 0H10L0 10Z"); diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/tests/UtilityTest.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/tests/UtilityTest.cpp index b2460d5017b..2faa4c2a964 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/tests/UtilityTest.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/tests/UtilityTest.cpp @@ -119,6 +119,17 @@ TEST(UtilityTest, ilog10) { } +TEST(UtilityTest, to_string) { + ASSERT_EQ(util::to_string(0), "0"); + ASSERT_EQ(util::to_string(1), "1"); + ASSERT_EQ(util::to_string(100), "100"); + ASSERT_EQ(util::to_string(-1), "-1"); + ASSERT_EQ(util::to_string(2.123), "2.123"); + ASSERT_EQ(util::to_string(-2.123), "-2.123"); + ASSERT_EQ(util::to_string(1.500e-5), "0.000015"); +} + + static string base64 (const string &str) { istringstream iss(str); ostringstream oss; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/tests/XMLNodeTest.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/tests/XMLNodeTest.cpp index b7a485ef527..eb3a37c4349 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/tests/XMLNodeTest.cpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/tests/XMLNodeTest.cpp @@ -28,66 +28,136 @@ using namespace std; +TEST(XMLNodeTest, downcast) { + unique_ptr<XMLNode> elem = util::make_unique<XMLElement>("element"); + EXPECT_EQ(elem->toElement(), elem.get()); + EXPECT_EQ(elem->toText(), nullptr); + EXPECT_EQ(elem->toCData(), nullptr); + EXPECT_EQ(elem->toComment(), nullptr); + + unique_ptr<XMLNode> text = util::make_unique<XMLText>("text"); + EXPECT_EQ(text->toElement(), nullptr); + EXPECT_EQ(text->toText(), text.get()); + EXPECT_EQ(text->toCData(), nullptr); + EXPECT_EQ(text->toComment(), nullptr); + + unique_ptr<XMLNode> cdata = util::make_unique<XMLCData>("cdata"); + EXPECT_EQ(cdata->toElement(), nullptr); + EXPECT_EQ(cdata->toText(), nullptr); + EXPECT_EQ(cdata->toCData(), cdata.get()); + EXPECT_EQ(cdata->toComment(), nullptr); + + unique_ptr<XMLNode> comment = util::make_unique<XMLComment>("comment"); + EXPECT_EQ(comment->toElement(), nullptr); + EXPECT_EQ(comment->toText(), nullptr); + EXPECT_EQ(comment->toCData(), nullptr); + EXPECT_EQ(comment->toComment(), comment.get()); +} + + +static int number_of_children (XMLElement &elem) { + int count=0; + for (XMLNode *node = elem.firstChild(); node; node=node->next()) + count++; + return count; +} + + TEST(XMLNodeTest, appendElement) { - XMLElementNode root("root"); - root.append(util::make_unique<XMLElementNode>("child1")); - root.append(util::make_unique<XMLElementNode>("child2")); - EXPECT_EQ(root.children().size(), 2u); + XMLElement root("root"); + root.append(util::make_unique<XMLElement>("child1")); + root.append(util::make_unique<XMLElement>("child2")); + EXPECT_EQ(number_of_children(root), 2); EXPECT_FALSE(root.empty()); - XMLElementNode *child1 = dynamic_cast<XMLElementNode*>(root.children().front().get()); - XMLElementNode *child2 = dynamic_cast<XMLElementNode*>(root.children().back().get()); + XMLElement *child1 = root.firstChild()->toElement(); + XMLElement *child2 = root.lastChild()->toElement(); ASSERT_NE(child1, nullptr); + EXPECT_EQ(child1->parent(), &root); + EXPECT_EQ(child1->prev(), nullptr); + EXPECT_EQ(child1->next(), child2); + EXPECT_EQ(child1->firstChild(), nullptr); + EXPECT_EQ(child1->lastChild(), nullptr); + EXPECT_EQ(child1->name(), "child1"); + ASSERT_NE(child2, nullptr); - EXPECT_EQ(child1->getName(), "child1"); - EXPECT_EQ(child2->getName(), "child2"); + EXPECT_EQ(child2->parent(), &root); + EXPECT_EQ(child2->prev(), child1); + EXPECT_EQ(child2->next(), nullptr); + EXPECT_EQ(child2->firstChild(), nullptr); + EXPECT_EQ(child2->lastChild(), nullptr); + EXPECT_EQ(child2->name(), "child2"); root.clear(); EXPECT_TRUE(root.empty()); } TEST(XMLNodeTest, prependElement) { - XMLElementNode root("root"); - root.prepend(util::make_unique<XMLElementNode>("child1")); - root.prepend(util::make_unique<XMLElementNode>("child2")); - EXPECT_EQ(root.children().size(), 2u); - XMLElementNode *child1 = dynamic_cast<XMLElementNode*>(root.children().front().get()); - XMLElementNode *child2 = dynamic_cast<XMLElementNode*>(root.children().back().get()); + XMLElement root("root"); + root.prepend(util::make_unique<XMLElement>("child1")); + root.prepend(util::make_unique<XMLElement>("child2")); + EXPECT_EQ(number_of_children(root), 2); + XMLElement *child1 = root.lastChild()->toElement(); + XMLElement *child2 = root.firstChild()->toElement(); ASSERT_NE(child1, nullptr); + EXPECT_EQ(child1->parent(), &root); + EXPECT_EQ(child1->prev(), child2); + EXPECT_EQ(child1->next(), nullptr); + EXPECT_EQ(child1->firstChild(), nullptr); + EXPECT_EQ(child1->lastChild(), nullptr); + EXPECT_EQ(child1->name(), "child1"); + ASSERT_NE(child2, nullptr); - EXPECT_EQ(child1->getName(), "child2"); - EXPECT_EQ(child2->getName(), "child1"); + EXPECT_EQ(child2->parent(), &root); + EXPECT_EQ(child2->prev(), nullptr); + EXPECT_EQ(child2->next(), child1); + EXPECT_EQ(child2->firstChild(), nullptr); + EXPECT_EQ(child2->lastChild(), nullptr); + EXPECT_EQ(child2->name(), "child2"); } TEST(XMLNodeTest, appendText) { - XMLElementNode root("root"); - root.append(util::make_unique<XMLTextNode>("first string")); - EXPECT_EQ(root.children().size(), 1u); - XMLTextNode *lastChild = dynamic_cast<XMLTextNode*>(root.children().back().get()); + XMLElement root("root"); + root.append(util::make_unique<XMLText>("first string")); + EXPECT_EQ(number_of_children(root), 1); + XMLText *lastChild = root.lastChild()->toText(); ASSERT_NE(lastChild, nullptr); EXPECT_EQ(lastChild->getText(), "first string"); - - root.append(util::make_unique<XMLTextNode>(",second string")); - EXPECT_EQ(root.children().size(), 1u); - lastChild = dynamic_cast<XMLTextNode*>(root.children().back().get()); + EXPECT_EQ(lastChild->parent(), &root); + EXPECT_EQ(lastChild->prev(), nullptr); + EXPECT_EQ(lastChild->next(), nullptr); + EXPECT_EQ(root.firstChild(), root.lastChild()); + + root.append(util::make_unique<XMLText>(",second string")); + EXPECT_EQ(number_of_children(root), 1); + lastChild = root.lastChild()->toText(); ASSERT_NE(lastChild, nullptr); EXPECT_EQ(lastChild->getText(), "first string,second string"); + EXPECT_EQ(lastChild->parent(), &root); + EXPECT_EQ(lastChild->prev(), nullptr); + EXPECT_EQ(lastChild->next(), nullptr); + EXPECT_EQ(root.firstChild(), root.lastChild()); root.append(",third string"); - EXPECT_EQ(root.children().size(), 1u); - lastChild = dynamic_cast<XMLTextNode*>(root.children().back().get()); + EXPECT_EQ(number_of_children(root), 1); + lastChild = root.lastChild()->toText(); ASSERT_NE(lastChild, nullptr); EXPECT_EQ(lastChild->getText(), "first string,second string,third string"); + EXPECT_EQ(lastChild->parent(), &root); + EXPECT_EQ(lastChild->prev(), nullptr); + EXPECT_EQ(lastChild->next(), nullptr); - root.append(util::make_unique<XMLElementNode>("separator")); + root.append(util::make_unique<XMLElement>("separator")); root.append(",fourth string"); - lastChild = dynamic_cast<XMLTextNode*>(root.children().back().get()); + EXPECT_EQ(number_of_children(root), 3); + lastChild = root.lastChild()->toText(); ASSERT_NE(lastChild, nullptr); EXPECT_EQ(lastChild->getText(), ",fourth string"); - root.append(util::make_unique<XMLElementNode>("separator")); - root.append(util::make_unique<XMLTextNode>(",fifth string")); - lastChild = dynamic_cast<XMLTextNode*>(root.children().back().get()); + root.append(util::make_unique<XMLElement>("separator")); + root.append(util::make_unique<XMLText>(",fifth string")); + EXPECT_EQ(number_of_children(root), 5); + lastChild = root.lastChild()->toText(); ASSERT_NE(lastChild, nullptr); EXPECT_EQ(lastChild->getText(), ",fifth string"); @@ -97,29 +167,40 @@ TEST(XMLNodeTest, appendText) { TEST(XMLNodeTest, prependText) { - XMLElementNode root("root"); - root.prepend(util::make_unique<XMLTextNode>("first string")); - EXPECT_EQ(root.children().size(), 1u); - XMLTextNode *firstChild = dynamic_cast<XMLTextNode*>(root.children().front().get()); + XMLElement root("root"); + root.prepend(util::make_unique<XMLText>("first string")); + EXPECT_EQ(number_of_children(root), 1); + XMLText *firstChild = root.firstChild()->toText(); ASSERT_NE(firstChild, nullptr); EXPECT_EQ(firstChild->getText(), "first string"); + EXPECT_EQ(firstChild->parent(), &root); + EXPECT_EQ(firstChild->prev(), nullptr); + EXPECT_EQ(firstChild->next(), nullptr); - root.prepend(util::make_unique<XMLTextNode>("second string,")); - EXPECT_EQ(root.children().size(), 1u); - firstChild = dynamic_cast<XMLTextNode*>(root.children().front().get()); + root.prepend(util::make_unique<XMLText>("second string,")); + EXPECT_EQ(number_of_children(root), 1); + firstChild = root.firstChild()->toText(); ASSERT_NE(firstChild, nullptr); EXPECT_EQ(firstChild->getText(), "second string,first string"); - - root.prepend(util::make_unique<XMLElementNode>("separator")); - root.prepend(util::make_unique<XMLTextNode>("third string,")); - firstChild = dynamic_cast<XMLTextNode*>(root.children().front().get()); + EXPECT_EQ(firstChild->parent(), &root); + EXPECT_EQ(firstChild->prev(), nullptr); + EXPECT_EQ(firstChild->next(), nullptr); + + root.prepend(util::make_unique<XMLElement>("separator")); + root.prepend(util::make_unique<XMLText>("third string,")); + EXPECT_EQ(number_of_children(root), 3); + firstChild = root.firstChild()->toText(); ASSERT_NE(firstChild, nullptr); EXPECT_EQ(firstChild->getText(), "third string,"); + EXPECT_EQ(firstChild->parent(), &root); + EXPECT_EQ(firstChild->prev(), nullptr); + EXPECT_EQ(firstChild->next()->next(), root.lastChild()); + EXPECT_EQ(root.lastChild()->prev()->prev(), root.firstChild()); } TEST(XMLNodeTest, attributes) { - XMLElementNode root("root"); + XMLElement root("root"); root.addAttribute("string", "text"); root.addAttribute("integer", 42); root.addAttribute("double", 42.24); @@ -136,13 +217,13 @@ TEST(XMLNodeTest, attributes) { TEST(XMLNodeTest, clone) { - XMLElementNode root ("root"); + XMLElement root ("root"); root.addAttribute("string", "text"); root.addAttribute("integer", 42); root.addAttribute("double", 42.24); root.append("text"); - unique_ptr<XMLElementNode> clone = util::static_unique_ptr_cast<XMLElementNode>(root.clone()); - EXPECT_EQ(clone->children().size(), 1u); + unique_ptr<XMLElement> clone = util::static_unique_ptr_cast<XMLElement>(root.clone()); + EXPECT_EQ(number_of_children(root), 1); EXPECT_STREQ(clone->getAttributeValue("string"), "text"); EXPECT_STREQ(clone->getAttributeValue("integer"), "42"); EXPECT_STREQ(clone->getAttributeValue("double"), "42.24"); @@ -150,99 +231,107 @@ TEST(XMLNodeTest, clone) { TEST(XMLNodeTest, insertBefore) { - XMLElementNode root("root"); - auto child1 = util::make_unique<XMLElementNode>("child1"); - auto child2 = util::make_unique<XMLElementNode>("child2"); + XMLElement root("root"); + auto child1 = util::make_unique<XMLElement>("child1"); + auto child2 = util::make_unique<XMLElement>("child2"); XMLNode* child1Ptr = root.append(std::move(child1)); XMLNode* child2Ptr = root.append(std::move(child2)); - auto node = util::make_unique<XMLElementNode>("node"); - EXPECT_FALSE(root.insertBefore(util::make_unique<XMLElementNode>("dummy"), node.get())); - EXPECT_EQ(root.children().size(), 2u); - EXPECT_TRUE(root.insertBefore(util::make_unique<XMLElementNode>("child3"), child1Ptr)); - EXPECT_EQ(root.children().size(), 3u); - XMLElementNode *child = dynamic_cast<XMLElementNode*>(root.children().front().get()); - EXPECT_EQ(child->getName(), "child3"); - EXPECT_TRUE(root.insertBefore(util::make_unique<XMLElementNode>("child4"), child2Ptr)); + auto node = util::make_unique<XMLElement>("node"); + EXPECT_FALSE(root.insertBefore(util::make_unique<XMLElement>("dummy"), node.get())); + EXPECT_EQ(number_of_children(root), 2); + EXPECT_TRUE(root.insertBefore(util::make_unique<XMLElement>("child3"), child1Ptr)); + EXPECT_EQ(number_of_children(root), 3); + XMLElement *child = root.firstChild()->toElement(); + EXPECT_EQ(child->name(), "child3"); + EXPECT_TRUE(root.insertBefore(util::make_unique<XMLElement>("child4"), child2Ptr)); const char *names[] = {"child3", "child1", "child4", "child2"}; const char **p = names; - for (const auto &node : root.children()) { - XMLElementNode *elem = dynamic_cast<XMLElementNode*>(node.get()); + for (XMLNode *node=root.firstChild(); node; node=node->next()) { + XMLElement *elem = node->toElement(); ASSERT_NE(elem, nullptr); - EXPECT_EQ(elem->getName(), *p++) << "name=" << elem->getName(); + EXPECT_EQ(elem->name(), *p++) << "name=" << elem->name(); + EXPECT_EQ(elem->parent(), &root); + if (elem->prev()) { + EXPECT_EQ(elem->prev()->next(), elem); + } } } TEST(XMLNodeTest, insertAfter) { - XMLElementNode root("root"); - auto child1 = util::make_unique<XMLElementNode>("child1"); - auto child2 = util::make_unique<XMLElementNode>("child2"); + XMLElement root("root"); + auto child1 = util::make_unique<XMLElement>("child1"); + auto child2 = util::make_unique<XMLElement>("child2"); XMLNode *child1Ptr = root.append(std::move(child1)); XMLNode *child2Ptr =root.append(std::move(child2)); - auto node = util::make_unique<XMLElementNode>("node"); - EXPECT_FALSE(root.insertAfter(util::make_unique<XMLElementNode>("dummy"), node.get())); - EXPECT_EQ(root.children().size(), 2u); - EXPECT_TRUE(root.insertAfter(util::make_unique<XMLElementNode>("child3"), child1Ptr)); - EXPECT_TRUE(root.insertAfter(util::make_unique<XMLElementNode>("child4"), child2Ptr)); - EXPECT_EQ(root.children().size(), 4u); + auto node = util::make_unique<XMLElement>("node"); + EXPECT_FALSE(root.insertAfter(util::make_unique<XMLElement>("dummy"), node.get())); + EXPECT_EQ(number_of_children(root), 2); + EXPECT_TRUE(root.insertAfter(util::make_unique<XMLElement>("child3"), child1Ptr)); + EXPECT_TRUE(root.insertAfter(util::make_unique<XMLElement>("child4"), child2Ptr)); + EXPECT_EQ(number_of_children(root), 4); const char *names[] = {"child1", "child3", "child2", "child4"}; const char **p = names; - for (const auto &node : root.children()) { - XMLElementNode *elem = dynamic_cast<XMLElementNode*>(node.get()); + for (XMLNode *node=root.firstChild(); node; node=node->next()) { + XMLElement *elem = node->toElement(); ASSERT_NE(elem, nullptr); - EXPECT_EQ(elem->getName(), *p++) << "name=" << elem->getName(); + EXPECT_EQ(elem->name(), *p++) << "name=" << elem->name(); + EXPECT_EQ(elem->parent(), &root); + if (elem->prev()) { + EXPECT_EQ(elem->prev()->next(), elem); + } } } TEST(XMLNodeTest, getDescendants) { - XMLElementNode root("root"); - auto child1 = util::make_unique<XMLElementNode>("child"); - auto child2 = util::make_unique<XMLElementNode>("childX"); - auto child3 = util::make_unique<XMLElementNode>("child"); - auto child4 = util::make_unique<XMLElementNode>("child"); + XMLElement root("root"); + auto child1 = util::make_unique<XMLElement>("child"); + auto child2 = util::make_unique<XMLElement>("childX"); + auto child3 = util::make_unique<XMLElement>("child"); + auto child4 = util::make_unique<XMLElement>("child"); child1->addAttribute("attr", "value"); child2->addAttribute("attr", "value"); child3->addAttribute("attr", "value"); child3->append("text"); - XMLElementNode *child3Ptr = static_cast<XMLElementNode*>(child2->append(std::move(child3))); - XMLElementNode *child2Ptr = static_cast<XMLElementNode*>(child1->append(std::move(child2))); - XMLElementNode *child1Ptr = static_cast<XMLElementNode*>(root.append(std::move(child1))); - XMLElementNode *child4Ptr = static_cast<XMLElementNode*>(root.append(std::move(child4))); - vector<XMLElementNode*> elements; + XMLElement *child3Ptr = static_cast<XMLElement*>(child2->append(std::move(child3))); + XMLElement *child2Ptr = static_cast<XMLElement*>(child1->append(std::move(child2))); + XMLElement *child1Ptr = static_cast<XMLElement*>(root.append(std::move(child1))); + XMLElement *child4Ptr = static_cast<XMLElement*>(root.append(std::move(child4))); + vector<XMLElement*> elements; root.getDescendants("child", nullptr, elements); EXPECT_EQ(elements.size(), 3u); { - XMLElementNode *nodes[] = {child1Ptr, child3Ptr, child4Ptr}; - XMLElementNode **p = nodes; - for (const XMLElementNode *elem : elements) + XMLElement *nodes[] = {child1Ptr, child3Ptr, child4Ptr}; + XMLElement **p = nodes; + for (const XMLElement *elem : elements) EXPECT_EQ(elem, *p++); }{ elements.clear(); root.getDescendants("child", "attr", elements); EXPECT_EQ(elements.size(), 2u); - XMLElementNode *nodes[] = {child1Ptr, child3Ptr}; - XMLElementNode **p = nodes; - for (const XMLElementNode *elem : elements) + XMLElement *nodes[] = {child1Ptr, child3Ptr}; + XMLElement **p = nodes; + for (const XMLElement *elem : elements) EXPECT_EQ(elem, *p++); }{ elements.clear(); root.getDescendants(nullptr, "attr", elements); EXPECT_EQ(elements.size(), 3u); - XMLElementNode *nodes[] = {child1Ptr, child2Ptr, child3Ptr}; - XMLElementNode **p = nodes; - for (const XMLElementNode *elem : elements) + XMLElement *nodes[] = {child1Ptr, child2Ptr, child3Ptr}; + XMLElement **p = nodes; + for (const XMLElement *elem : elements) EXPECT_EQ(elem, *p++); } } TEST(XMLNodeTest, getFirstDescendant) { - XMLElementNode root("root"); - auto child1 = util::make_unique<XMLElementNode>("child"); - auto child2 = util::make_unique<XMLElementNode>("childX"); - auto child3 = util::make_unique<XMLElementNode>("child"); - auto child4 = util::make_unique<XMLElementNode>("child"); + XMLElement root("root"); + auto child1 = util::make_unique<XMLElement>("child"); + auto child2 = util::make_unique<XMLElement>("childX"); + auto child3 = util::make_unique<XMLElement>("child"); + auto child4 = util::make_unique<XMLElement>("child"); child1->addAttribute("attr", "valueX"); child2->addAttribute("attr", "value"); child3->addAttribute("attrX", "value"); @@ -262,11 +351,11 @@ TEST(XMLNodeTest, getFirstDescendant) { TEST(XMLNodeTest, write) { - XMLElementNode root("root"); - auto child1 = util::make_unique<XMLElementNode>("child"); - auto child2 = util::make_unique<XMLElementNode>("childX"); - auto child3 = util::make_unique<XMLElementNode>("child"); - auto child4 = util::make_unique<XMLElementNode>("child"); + XMLElement root("root"); + auto child1 = util::make_unique<XMLElement>("child"); + auto child2 = util::make_unique<XMLElement>("childX"); + auto child3 = util::make_unique<XMLElement>("child"); + auto child4 = util::make_unique<XMLElement>("child"); child1->addAttribute("attr", "valueX"); child2->addAttribute("attr", "value"); child3->addAttribute("attrX", "value"); @@ -284,10 +373,10 @@ TEST(XMLNodeTest, write) { TEST(XMLNodeTest, cdata) { - XMLElementNode root("root"); - auto cdataNode = util::make_unique<XMLCDataNode>("text & <text>"); + XMLElement root("root"); + auto cdataNode = util::make_unique<XMLCData>("text & <text>"); XMLNode *cdataNodePtr = root.append(std::move(cdataNode)); - root.append(util::make_unique<XMLElementNode>("element")); + root.append(util::make_unique<XMLElement>("element")); root.append(cdataNodePtr->clone()); ostringstream oss; root.write(oss); @@ -302,4 +391,3 @@ TEST(XMLNodeTest, cdata) { str.erase(remove(str.begin(), str.end(), '\n'), str.end()); EXPECT_EQ(str, "<root><element/><![CDATA[text & <text>]]></root>"); } - diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/tests/genhashcheck.py b/Build/source/texk/dvisvgm/dvisvgm-src/tests/genhashcheck.py index 8f391fe7339..f7ac46c4885 100755 --- a/Build/source/texk/dvisvgm/dvisvgm-src/tests/genhashcheck.py +++ b/Build/source/texk/dvisvgm/dvisvgm-src/tests/genhashcheck.py @@ -29,6 +29,7 @@ if (len(sys.argv) < 2): print("""\ #include <xxhash.h> #include <cstdint> +#include <iterator> #include <iomanip> #include <iostream> #include <string> @@ -44,15 +45,14 @@ extract_hashes(sys.argv[1]) print(r"""}; int main () { - uint32_t prev_hash=0; - size_t size = sizeof(nameHashes)/sizeof(NameHash); - if (size == 0) { + if (distance(begin(nameHashes), end(nameHashes)) == 0) { cout << "hash table is empty\n"; return 1; } - for (size_t i=0; i < size; i++) { - const string &name = nameHashes[i].name; - const uint32_t hash = nameHashes[i].hash; + uint32_t prev_hash=0; + for (NameHash &nameHash : nameHashes) { + const string &name = nameHash.name; + const uint32_t hash = nameHash.hash; if (XXH32(&name[0], name.length(), 0) != hash) { cout << "hash of '" << name << "' doesn't match\n"; return 1; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest-death-test.h b/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest-death-test.h index 20c54d86951..dc878ffbb3a 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest-death-test.h +++ b/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest-death-test.h @@ -161,7 +161,6 @@ GTEST_API_ bool InDeathTestChild(); // is rarely a problem as people usually don't put the test binary // directory in PATH. // -// FIXME: make thread-safe death tests search the PATH. // Asserts that a given statement causes the program to exit, with an // integer exit status that satisfies predicate, and emitting error output @@ -170,7 +169,7 @@ GTEST_API_ bool InDeathTestChild(); GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_FATAL_FAILURE_) // Like ASSERT_EXIT, but continues on to successive tests in the -// test case, if any: +// test suite, if any: # define EXPECT_EXIT(statement, predicate, regex) \ GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_NONFATAL_FAILURE_) @@ -181,7 +180,7 @@ GTEST_API_ bool InDeathTestChild(); ASSERT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex) // Like ASSERT_DEATH, but continues on to successive tests in the -// test case, if any: +// test suite, if any: # define EXPECT_DEATH(statement, regex) \ EXPECT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex) @@ -228,7 +227,7 @@ class GTEST_API_ KilledBySignal { // return 12; // } // -// TEST(TestCase, TestDieOr12WorksInDgbAndOpt) { +// TEST(TestSuite, TestDieOr12WorksInDgbAndOpt) { // int sideeffect = 0; // // Only asserts in dbg. // EXPECT_DEBUG_DEATH(DieInDebugOr12(&sideeffect), "death"); @@ -277,20 +276,20 @@ class GTEST_API_ KilledBySignal { // This macro is used for implementing macros such as // EXPECT_DEATH_IF_SUPPORTED and ASSERT_DEATH_IF_SUPPORTED on systems where // death tests are not supported. Those macros must compile on such systems -// iff EXPECT_DEATH and ASSERT_DEATH compile with the same parameters on -// systems that support death tests. This allows one to write such a macro -// on a system that does not support death tests and be sure that it will -// compile on a death-test supporting system. It is exposed publicly so that -// systems that have death-tests with stricter requirements than -// GTEST_HAS_DEATH_TEST can write their own equivalent of -// EXPECT_DEATH_IF_SUPPORTED and ASSERT_DEATH_IF_SUPPORTED. +// if and only if EXPECT_DEATH and ASSERT_DEATH compile with the same parameters +// on systems that support death tests. This allows one to write such a macro on +// a system that does not support death tests and be sure that it will compile +// on a death-test supporting system. It is exposed publicly so that systems +// that have death-tests with stricter requirements than GTEST_HAS_DEATH_TEST +// can write their own equivalent of EXPECT_DEATH_IF_SUPPORTED and +// ASSERT_DEATH_IF_SUPPORTED. // // Parameters: // statement - A statement that a macro such as EXPECT_DEATH would test // for program termination. This macro has to make sure this // statement is compiled but not executed, to ensure that // EXPECT_DEATH_IF_SUPPORTED compiles with a certain -// parameter iff EXPECT_DEATH compiles with it. +// parameter if and only if EXPECT_DEATH compiles with it. // regex - A regex that a macro such as EXPECT_DEATH would use to test // the output of statement. This parameter has to be // compiled but not evaluated by this macro, to ensure that diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest-matchers.h b/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest-matchers.h new file mode 100644 index 00000000000..9de6c2e10a2 --- /dev/null +++ b/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest-matchers.h @@ -0,0 +1,750 @@ +// Copyright 2007, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// The Google C++ Testing and Mocking Framework (Google Test) +// +// This file implements just enough of the matcher interface to allow +// EXPECT_DEATH and friends to accept a matcher argument. + +// IWYU pragma: private, include "testing/base/public/gunit.h" +// IWYU pragma: friend third_party/googletest/googlemock/.* +// IWYU pragma: friend third_party/googletest/googletest/.* + +#ifndef GTEST_INCLUDE_GTEST_GTEST_MATCHERS_H_ +#define GTEST_INCLUDE_GTEST_GTEST_MATCHERS_H_ + +#include <memory> +#include <ostream> +#include <string> +#include <type_traits> + +#include "gtest/gtest-printers.h" +#include "gtest/internal/gtest-internal.h" +#include "gtest/internal/gtest-port.h" + +// MSVC warning C5046 is new as of VS2017 version 15.8. +#if defined(_MSC_VER) && _MSC_VER >= 1915 +#define GTEST_MAYBE_5046_ 5046 +#else +#define GTEST_MAYBE_5046_ +#endif + +GTEST_DISABLE_MSC_WARNINGS_PUSH_( + 4251 GTEST_MAYBE_5046_ /* class A needs to have dll-interface to be used by + clients of class B */ + /* Symbol involving type with internal linkage not defined */) + +namespace testing { + +// To implement a matcher Foo for type T, define: +// 1. a class FooMatcherImpl that implements the +// MatcherInterface<T> interface, and +// 2. a factory function that creates a Matcher<T> object from a +// FooMatcherImpl*. +// +// The two-level delegation design makes it possible to allow a user +// to write "v" instead of "Eq(v)" where a Matcher is expected, which +// is impossible if we pass matchers by pointers. It also eases +// ownership management as Matcher objects can now be copied like +// plain values. + +// MatchResultListener is an abstract class. Its << operator can be +// used by a matcher to explain why a value matches or doesn't match. +// +class MatchResultListener { + public: + // Creates a listener object with the given underlying ostream. The + // listener does not own the ostream, and does not dereference it + // in the constructor or destructor. + explicit MatchResultListener(::std::ostream* os) : stream_(os) {} + virtual ~MatchResultListener() = 0; // Makes this class abstract. + + // Streams x to the underlying ostream; does nothing if the ostream + // is NULL. + template <typename T> + MatchResultListener& operator<<(const T& x) { + if (stream_ != nullptr) *stream_ << x; + return *this; + } + + // Returns the underlying ostream. + ::std::ostream* stream() { return stream_; } + + // Returns true if and only if the listener is interested in an explanation + // of the match result. A matcher's MatchAndExplain() method can use + // this information to avoid generating the explanation when no one + // intends to hear it. + bool IsInterested() const { return stream_ != nullptr; } + + private: + ::std::ostream* const stream_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(MatchResultListener); +}; + +inline MatchResultListener::~MatchResultListener() { +} + +// An instance of a subclass of this knows how to describe itself as a +// matcher. +class MatcherDescriberInterface { + public: + virtual ~MatcherDescriberInterface() {} + + // Describes this matcher to an ostream. The function should print + // a verb phrase that describes the property a value matching this + // matcher should have. The subject of the verb phrase is the value + // being matched. For example, the DescribeTo() method of the Gt(7) + // matcher prints "is greater than 7". + virtual void DescribeTo(::std::ostream* os) const = 0; + + // Describes the negation of this matcher to an ostream. For + // example, if the description of this matcher is "is greater than + // 7", the negated description could be "is not greater than 7". + // You are not required to override this when implementing + // MatcherInterface, but it is highly advised so that your matcher + // can produce good error messages. + virtual void DescribeNegationTo(::std::ostream* os) const { + *os << "not ("; + DescribeTo(os); + *os << ")"; + } +}; + +// The implementation of a matcher. +template <typename T> +class MatcherInterface : public MatcherDescriberInterface { + public: + // Returns true if and only if the matcher matches x; also explains the + // match result to 'listener' if necessary (see the next paragraph), in + // the form of a non-restrictive relative clause ("which ...", + // "whose ...", etc) that describes x. For example, the + // MatchAndExplain() method of the Pointee(...) matcher should + // generate an explanation like "which points to ...". + // + // Implementations of MatchAndExplain() should add an explanation of + // the match result *if and only if* they can provide additional + // information that's not already present (or not obvious) in the + // print-out of x and the matcher's description. Whether the match + // succeeds is not a factor in deciding whether an explanation is + // needed, as sometimes the caller needs to print a failure message + // when the match succeeds (e.g. when the matcher is used inside + // Not()). + // + // For example, a "has at least 10 elements" matcher should explain + // what the actual element count is, regardless of the match result, + // as it is useful information to the reader; on the other hand, an + // "is empty" matcher probably only needs to explain what the actual + // size is when the match fails, as it's redundant to say that the + // size is 0 when the value is already known to be empty. + // + // You should override this method when defining a new matcher. + // + // It's the responsibility of the caller (Google Test) to guarantee + // that 'listener' is not NULL. This helps to simplify a matcher's + // implementation when it doesn't care about the performance, as it + // can talk to 'listener' without checking its validity first. + // However, in order to implement dummy listeners efficiently, + // listener->stream() may be NULL. + virtual bool MatchAndExplain(T x, MatchResultListener* listener) const = 0; + + // Inherits these methods from MatcherDescriberInterface: + // virtual void DescribeTo(::std::ostream* os) const = 0; + // virtual void DescribeNegationTo(::std::ostream* os) const; +}; + +namespace internal { + +// Converts a MatcherInterface<T> to a MatcherInterface<const T&>. +template <typename T> +class MatcherInterfaceAdapter : public MatcherInterface<const T&> { + public: + explicit MatcherInterfaceAdapter(const MatcherInterface<T>* impl) + : impl_(impl) {} + ~MatcherInterfaceAdapter() override { delete impl_; } + + void DescribeTo(::std::ostream* os) const override { impl_->DescribeTo(os); } + + void DescribeNegationTo(::std::ostream* os) const override { + impl_->DescribeNegationTo(os); + } + + bool MatchAndExplain(const T& x, + MatchResultListener* listener) const override { + return impl_->MatchAndExplain(x, listener); + } + + private: + const MatcherInterface<T>* const impl_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(MatcherInterfaceAdapter); +}; + +struct AnyEq { + template <typename A, typename B> + bool operator()(const A& a, const B& b) const { return a == b; } +}; +struct AnyNe { + template <typename A, typename B> + bool operator()(const A& a, const B& b) const { return a != b; } +}; +struct AnyLt { + template <typename A, typename B> + bool operator()(const A& a, const B& b) const { return a < b; } +}; +struct AnyGt { + template <typename A, typename B> + bool operator()(const A& a, const B& b) const { return a > b; } +}; +struct AnyLe { + template <typename A, typename B> + bool operator()(const A& a, const B& b) const { return a <= b; } +}; +struct AnyGe { + template <typename A, typename B> + bool operator()(const A& a, const B& b) const { return a >= b; } +}; + +// A match result listener that ignores the explanation. +class DummyMatchResultListener : public MatchResultListener { + public: + DummyMatchResultListener() : MatchResultListener(nullptr) {} + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(DummyMatchResultListener); +}; + +// A match result listener that forwards the explanation to a given +// ostream. The difference between this and MatchResultListener is +// that the former is concrete. +class StreamMatchResultListener : public MatchResultListener { + public: + explicit StreamMatchResultListener(::std::ostream* os) + : MatchResultListener(os) {} + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(StreamMatchResultListener); +}; + +// An internal class for implementing Matcher<T>, which will derive +// from it. We put functionalities common to all Matcher<T> +// specializations here to avoid code duplication. +template <typename T> +class MatcherBase { + public: + // Returns true if and only if the matcher matches x; also explains the + // match result to 'listener'. + bool MatchAndExplain(const T& x, MatchResultListener* listener) const { + return impl_->MatchAndExplain(x, listener); + } + + // Returns true if and only if this matcher matches x. + bool Matches(const T& x) const { + DummyMatchResultListener dummy; + return MatchAndExplain(x, &dummy); + } + + // Describes this matcher to an ostream. + void DescribeTo(::std::ostream* os) const { impl_->DescribeTo(os); } + + // Describes the negation of this matcher to an ostream. + void DescribeNegationTo(::std::ostream* os) const { + impl_->DescribeNegationTo(os); + } + + // Explains why x matches, or doesn't match, the matcher. + void ExplainMatchResultTo(const T& x, ::std::ostream* os) const { + StreamMatchResultListener listener(os); + MatchAndExplain(x, &listener); + } + + // Returns the describer for this matcher object; retains ownership + // of the describer, which is only guaranteed to be alive when + // this matcher object is alive. + const MatcherDescriberInterface* GetDescriber() const { + return impl_.get(); + } + + protected: + MatcherBase() {} + + // Constructs a matcher from its implementation. + explicit MatcherBase(const MatcherInterface<const T&>* impl) : impl_(impl) {} + + template <typename U> + explicit MatcherBase( + const MatcherInterface<U>* impl, + typename std::enable_if<!std::is_same<U, const U&>::value>::type* = + nullptr) + : impl_(new internal::MatcherInterfaceAdapter<U>(impl)) {} + + MatcherBase(const MatcherBase&) = default; + MatcherBase& operator=(const MatcherBase&) = default; + MatcherBase(MatcherBase&&) = default; + MatcherBase& operator=(MatcherBase&&) = default; + + virtual ~MatcherBase() {} + + private: + std::shared_ptr<const MatcherInterface<const T&>> impl_; +}; + +} // namespace internal + +// A Matcher<T> is a copyable and IMMUTABLE (except by assignment) +// object that can check whether a value of type T matches. The +// implementation of Matcher<T> is just a std::shared_ptr to const +// MatcherInterface<T>. Don't inherit from Matcher! +template <typename T> +class Matcher : public internal::MatcherBase<T> { + public: + // Constructs a null matcher. Needed for storing Matcher objects in STL + // containers. A default-constructed matcher is not yet initialized. You + // cannot use it until a valid value has been assigned to it. + explicit Matcher() {} // NOLINT + + // Constructs a matcher from its implementation. + explicit Matcher(const MatcherInterface<const T&>* impl) + : internal::MatcherBase<T>(impl) {} + + template <typename U> + explicit Matcher( + const MatcherInterface<U>* impl, + typename std::enable_if<!std::is_same<U, const U&>::value>::type* = + nullptr) + : internal::MatcherBase<T>(impl) {} + + // Implicit constructor here allows people to write + // EXPECT_CALL(foo, Bar(5)) instead of EXPECT_CALL(foo, Bar(Eq(5))) sometimes + Matcher(T value); // NOLINT +}; + +// The following two specializations allow the user to write str +// instead of Eq(str) and "foo" instead of Eq("foo") when a std::string +// matcher is expected. +template <> +class GTEST_API_ Matcher<const std::string&> + : public internal::MatcherBase<const std::string&> { + public: + Matcher() {} + + explicit Matcher(const MatcherInterface<const std::string&>* impl) + : internal::MatcherBase<const std::string&>(impl) {} + + // Allows the user to write str instead of Eq(str) sometimes, where + // str is a std::string object. + Matcher(const std::string& s); // NOLINT + + // Allows the user to write "foo" instead of Eq("foo") sometimes. + Matcher(const char* s); // NOLINT +}; + +template <> +class GTEST_API_ Matcher<std::string> + : public internal::MatcherBase<std::string> { + public: + Matcher() {} + + explicit Matcher(const MatcherInterface<const std::string&>* impl) + : internal::MatcherBase<std::string>(impl) {} + explicit Matcher(const MatcherInterface<std::string>* impl) + : internal::MatcherBase<std::string>(impl) {} + + // Allows the user to write str instead of Eq(str) sometimes, where + // str is a string object. + Matcher(const std::string& s); // NOLINT + + // Allows the user to write "foo" instead of Eq("foo") sometimes. + Matcher(const char* s); // NOLINT +}; + +#if GTEST_HAS_ABSL +// The following two specializations allow the user to write str +// instead of Eq(str) and "foo" instead of Eq("foo") when a absl::string_view +// matcher is expected. +template <> +class GTEST_API_ Matcher<const absl::string_view&> + : public internal::MatcherBase<const absl::string_view&> { + public: + Matcher() {} + + explicit Matcher(const MatcherInterface<const absl::string_view&>* impl) + : internal::MatcherBase<const absl::string_view&>(impl) {} + + // Allows the user to write str instead of Eq(str) sometimes, where + // str is a std::string object. + Matcher(const std::string& s); // NOLINT + + // Allows the user to write "foo" instead of Eq("foo") sometimes. + Matcher(const char* s); // NOLINT + + // Allows the user to pass absl::string_views directly. + Matcher(absl::string_view s); // NOLINT +}; + +template <> +class GTEST_API_ Matcher<absl::string_view> + : public internal::MatcherBase<absl::string_view> { + public: + Matcher() {} + + explicit Matcher(const MatcherInterface<const absl::string_view&>* impl) + : internal::MatcherBase<absl::string_view>(impl) {} + explicit Matcher(const MatcherInterface<absl::string_view>* impl) + : internal::MatcherBase<absl::string_view>(impl) {} + + // Allows the user to write str instead of Eq(str) sometimes, where + // str is a std::string object. + Matcher(const std::string& s); // NOLINT + + // Allows the user to write "foo" instead of Eq("foo") sometimes. + Matcher(const char* s); // NOLINT + + // Allows the user to pass absl::string_views directly. + Matcher(absl::string_view s); // NOLINT +}; +#endif // GTEST_HAS_ABSL + +// Prints a matcher in a human-readable format. +template <typename T> +std::ostream& operator<<(std::ostream& os, const Matcher<T>& matcher) { + matcher.DescribeTo(&os); + return os; +} + +// The PolymorphicMatcher class template makes it easy to implement a +// polymorphic matcher (i.e. a matcher that can match values of more +// than one type, e.g. Eq(n) and NotNull()). +// +// To define a polymorphic matcher, a user should provide an Impl +// class that has a DescribeTo() method and a DescribeNegationTo() +// method, and define a member function (or member function template) +// +// bool MatchAndExplain(const Value& value, +// MatchResultListener* listener) const; +// +// See the definition of NotNull() for a complete example. +template <class Impl> +class PolymorphicMatcher { + public: + explicit PolymorphicMatcher(const Impl& an_impl) : impl_(an_impl) {} + + // Returns a mutable reference to the underlying matcher + // implementation object. + Impl& mutable_impl() { return impl_; } + + // Returns an immutable reference to the underlying matcher + // implementation object. + const Impl& impl() const { return impl_; } + + template <typename T> + operator Matcher<T>() const { + return Matcher<T>(new MonomorphicImpl<const T&>(impl_)); + } + + private: + template <typename T> + class MonomorphicImpl : public MatcherInterface<T> { + public: + explicit MonomorphicImpl(const Impl& impl) : impl_(impl) {} + + virtual void DescribeTo(::std::ostream* os) const { impl_.DescribeTo(os); } + + virtual void DescribeNegationTo(::std::ostream* os) const { + impl_.DescribeNegationTo(os); + } + + virtual bool MatchAndExplain(T x, MatchResultListener* listener) const { + return impl_.MatchAndExplain(x, listener); + } + + private: + const Impl impl_; + }; + + Impl impl_; +}; + +// Creates a matcher from its implementation. +// DEPRECATED: Especially in the generic code, prefer: +// Matcher<T>(new MyMatcherImpl<const T&>(...)); +// +// MakeMatcher may create a Matcher that accepts its argument by value, which +// leads to unnecessary copies & lack of support for non-copyable types. +template <typename T> +inline Matcher<T> MakeMatcher(const MatcherInterface<T>* impl) { + return Matcher<T>(impl); +} + +// Creates a polymorphic matcher from its implementation. This is +// easier to use than the PolymorphicMatcher<Impl> constructor as it +// doesn't require you to explicitly write the template argument, e.g. +// +// MakePolymorphicMatcher(foo); +// vs +// PolymorphicMatcher<TypeOfFoo>(foo); +template <class Impl> +inline PolymorphicMatcher<Impl> MakePolymorphicMatcher(const Impl& impl) { + return PolymorphicMatcher<Impl>(impl); +} + +namespace internal { +// Implements a matcher that compares a given value with a +// pre-supplied value using one of the ==, <=, <, etc, operators. The +// two values being compared don't have to have the same type. +// +// The matcher defined here is polymorphic (for example, Eq(5) can be +// used to match an int, a short, a double, etc). Therefore we use +// a template type conversion operator in the implementation. +// +// The following template definition assumes that the Rhs parameter is +// a "bare" type (i.e. neither 'const T' nor 'T&'). +template <typename D, typename Rhs, typename Op> +class ComparisonBase { + public: + explicit ComparisonBase(const Rhs& rhs) : rhs_(rhs) {} + template <typename Lhs> + operator Matcher<Lhs>() const { + return Matcher<Lhs>(new Impl<const Lhs&>(rhs_)); + } + + private: + template <typename T> + static const T& Unwrap(const T& v) { return v; } + template <typename T> + static const T& Unwrap(std::reference_wrapper<T> v) { return v; } + + template <typename Lhs, typename = Rhs> + class Impl : public MatcherInterface<Lhs> { + public: + explicit Impl(const Rhs& rhs) : rhs_(rhs) {} + bool MatchAndExplain(Lhs lhs, + MatchResultListener* /* listener */) const override { + return Op()(lhs, Unwrap(rhs_)); + } + void DescribeTo(::std::ostream* os) const override { + *os << D::Desc() << " "; + UniversalPrint(Unwrap(rhs_), os); + } + void DescribeNegationTo(::std::ostream* os) const override { + *os << D::NegatedDesc() << " "; + UniversalPrint(Unwrap(rhs_), os); + } + + private: + Rhs rhs_; + }; + Rhs rhs_; +}; + +template <typename Rhs> +class EqMatcher : public ComparisonBase<EqMatcher<Rhs>, Rhs, AnyEq> { + public: + explicit EqMatcher(const Rhs& rhs) + : ComparisonBase<EqMatcher<Rhs>, Rhs, AnyEq>(rhs) { } + static const char* Desc() { return "is equal to"; } + static const char* NegatedDesc() { return "isn't equal to"; } +}; +template <typename Rhs> +class NeMatcher : public ComparisonBase<NeMatcher<Rhs>, Rhs, AnyNe> { + public: + explicit NeMatcher(const Rhs& rhs) + : ComparisonBase<NeMatcher<Rhs>, Rhs, AnyNe>(rhs) { } + static const char* Desc() { return "isn't equal to"; } + static const char* NegatedDesc() { return "is equal to"; } +}; +template <typename Rhs> +class LtMatcher : public ComparisonBase<LtMatcher<Rhs>, Rhs, AnyLt> { + public: + explicit LtMatcher(const Rhs& rhs) + : ComparisonBase<LtMatcher<Rhs>, Rhs, AnyLt>(rhs) { } + static const char* Desc() { return "is <"; } + static const char* NegatedDesc() { return "isn't <"; } +}; +template <typename Rhs> +class GtMatcher : public ComparisonBase<GtMatcher<Rhs>, Rhs, AnyGt> { + public: + explicit GtMatcher(const Rhs& rhs) + : ComparisonBase<GtMatcher<Rhs>, Rhs, AnyGt>(rhs) { } + static const char* Desc() { return "is >"; } + static const char* NegatedDesc() { return "isn't >"; } +}; +template <typename Rhs> +class LeMatcher : public ComparisonBase<LeMatcher<Rhs>, Rhs, AnyLe> { + public: + explicit LeMatcher(const Rhs& rhs) + : ComparisonBase<LeMatcher<Rhs>, Rhs, AnyLe>(rhs) { } + static const char* Desc() { return "is <="; } + static const char* NegatedDesc() { return "isn't <="; } +}; +template <typename Rhs> +class GeMatcher : public ComparisonBase<GeMatcher<Rhs>, Rhs, AnyGe> { + public: + explicit GeMatcher(const Rhs& rhs) + : ComparisonBase<GeMatcher<Rhs>, Rhs, AnyGe>(rhs) { } + static const char* Desc() { return "is >="; } + static const char* NegatedDesc() { return "isn't >="; } +}; + +// Implements polymorphic matchers MatchesRegex(regex) and +// ContainsRegex(regex), which can be used as a Matcher<T> as long as +// T can be converted to a string. +class MatchesRegexMatcher { + public: + MatchesRegexMatcher(const RE* regex, bool full_match) + : regex_(regex), full_match_(full_match) {} + +#if GTEST_HAS_ABSL + bool MatchAndExplain(const absl::string_view& s, + MatchResultListener* listener) const { + return MatchAndExplain(std::string(s), listener); + } +#endif // GTEST_HAS_ABSL + + // Accepts pointer types, particularly: + // const char* + // char* + // const wchar_t* + // wchar_t* + template <typename CharType> + bool MatchAndExplain(CharType* s, MatchResultListener* listener) const { + return s != nullptr && MatchAndExplain(std::string(s), listener); + } + + // Matches anything that can convert to std::string. + // + // This is a template, not just a plain function with const std::string&, + // because absl::string_view has some interfering non-explicit constructors. + template <class MatcheeStringType> + bool MatchAndExplain(const MatcheeStringType& s, + MatchResultListener* /* listener */) const { + const std::string& s2(s); + return full_match_ ? RE::FullMatch(s2, *regex_) + : RE::PartialMatch(s2, *regex_); + } + + void DescribeTo(::std::ostream* os) const { + *os << (full_match_ ? "matches" : "contains") << " regular expression "; + UniversalPrinter<std::string>::Print(regex_->pattern(), os); + } + + void DescribeNegationTo(::std::ostream* os) const { + *os << "doesn't " << (full_match_ ? "match" : "contain") + << " regular expression "; + UniversalPrinter<std::string>::Print(regex_->pattern(), os); + } + + private: + const std::shared_ptr<const RE> regex_; + const bool full_match_; +}; +} // namespace internal + +// Matches a string that fully matches regular expression 'regex'. +// The matcher takes ownership of 'regex'. +inline PolymorphicMatcher<internal::MatchesRegexMatcher> MatchesRegex( + const internal::RE* regex) { + return MakePolymorphicMatcher(internal::MatchesRegexMatcher(regex, true)); +} +inline PolymorphicMatcher<internal::MatchesRegexMatcher> MatchesRegex( + const std::string& regex) { + return MatchesRegex(new internal::RE(regex)); +} + +// Matches a string that contains regular expression 'regex'. +// The matcher takes ownership of 'regex'. +inline PolymorphicMatcher<internal::MatchesRegexMatcher> ContainsRegex( + const internal::RE* regex) { + return MakePolymorphicMatcher(internal::MatchesRegexMatcher(regex, false)); +} +inline PolymorphicMatcher<internal::MatchesRegexMatcher> ContainsRegex( + const std::string& regex) { + return ContainsRegex(new internal::RE(regex)); +} + +// Creates a polymorphic matcher that matches anything equal to x. +// Note: if the parameter of Eq() were declared as const T&, Eq("foo") +// wouldn't compile. +template <typename T> +inline internal::EqMatcher<T> Eq(T x) { return internal::EqMatcher<T>(x); } + +// Constructs a Matcher<T> from a 'value' of type T. The constructed +// matcher matches any value that's equal to 'value'. +template <typename T> +Matcher<T>::Matcher(T value) { *this = Eq(value); } + +// Creates a monomorphic matcher that matches anything with type Lhs +// and equal to rhs. A user may need to use this instead of Eq(...) +// in order to resolve an overloading ambiguity. +// +// TypedEq<T>(x) is just a convenient short-hand for Matcher<T>(Eq(x)) +// or Matcher<T>(x), but more readable than the latter. +// +// We could define similar monomorphic matchers for other comparison +// operations (e.g. TypedLt, TypedGe, and etc), but decided not to do +// it yet as those are used much less than Eq() in practice. A user +// can always write Matcher<T>(Lt(5)) to be explicit about the type, +// for example. +template <typename Lhs, typename Rhs> +inline Matcher<Lhs> TypedEq(const Rhs& rhs) { return Eq(rhs); } + +// Creates a polymorphic matcher that matches anything >= x. +template <typename Rhs> +inline internal::GeMatcher<Rhs> Ge(Rhs x) { + return internal::GeMatcher<Rhs>(x); +} + +// Creates a polymorphic matcher that matches anything > x. +template <typename Rhs> +inline internal::GtMatcher<Rhs> Gt(Rhs x) { + return internal::GtMatcher<Rhs>(x); +} + +// Creates a polymorphic matcher that matches anything <= x. +template <typename Rhs> +inline internal::LeMatcher<Rhs> Le(Rhs x) { + return internal::LeMatcher<Rhs>(x); +} + +// Creates a polymorphic matcher that matches anything < x. +template <typename Rhs> +inline internal::LtMatcher<Rhs> Lt(Rhs x) { + return internal::LtMatcher<Rhs>(x); +} + +// Creates a polymorphic matcher that matches anything != x. +template <typename Rhs> +inline internal::NeMatcher<Rhs> Ne(Rhs x) { + return internal::NeMatcher<Rhs>(x); +} +} // namespace testing + +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 5046 + +#endif // GTEST_INCLUDE_GTEST_GTEST_MATCHERS_H_ diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest-message.h b/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest-message.h index 5ca041614cb..4a80e11e6b2 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest-message.h +++ b/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest-message.h @@ -48,6 +48,7 @@ #define GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ #include <limits> +#include <memory> #include "gtest/internal/gtest-port.h" @@ -106,14 +107,6 @@ class GTEST_API_ Message { *ss_ << str; } -#if GTEST_OS_SYMBIAN - // Streams a value (either a pointer or not) to this object. - template <typename T> - inline Message& operator <<(const T& value) { - StreamHelper(typename internal::is_pointer<T>::type(), value); - return *this; - } -#else // Streams a non-pointer value to this object. template <typename T> inline Message& operator <<(const T& val) { @@ -151,14 +144,13 @@ class GTEST_API_ Message { // as "(null)". template <typename T> inline Message& operator <<(T* const& pointer) { // NOLINT - if (pointer == NULL) { + if (pointer == nullptr) { *ss_ << "(null)"; } else { *ss_ << pointer; } return *this; } -#endif // GTEST_OS_SYMBIAN // Since the basic IO manipulators are overloaded for both narrow // and wide streams, we have to provide this specialized definition @@ -187,12 +179,6 @@ class GTEST_API_ Message { Message& operator <<(const ::std::wstring& wstr); #endif // GTEST_HAS_STD_WSTRING -#if GTEST_HAS_GLOBAL_WSTRING - // Converts the given wide string to a narrow string using the UTF-8 - // encoding, and streams the result to this Message object. - Message& operator <<(const ::wstring& wstr); -#endif // GTEST_HAS_GLOBAL_WSTRING - // Gets the text streamed to this object so far as an std::string. // Each '\0' character in the buffer is replaced with "\\0". // @@ -200,31 +186,8 @@ class GTEST_API_ Message { std::string GetString() const; private: -#if GTEST_OS_SYMBIAN - // These are needed as the Nokia Symbian Compiler cannot decide between - // const T& and const T* in a function template. The Nokia compiler _can_ - // decide between class template specializations for T and T*, so a - // tr1::type_traits-like is_pointer works, and we can overload on that. - template <typename T> - inline void StreamHelper(internal::true_type /*is_pointer*/, T* pointer) { - if (pointer == NULL) { - *ss_ << "(null)"; - } else { - *ss_ << pointer; - } - } - template <typename T> - inline void StreamHelper(internal::false_type /*is_pointer*/, - const T& value) { - // See the comments in Message& operator <<(const T&) above for why - // we need this using statement. - using ::operator <<; - *ss_ << value; - } -#endif // GTEST_OS_SYMBIAN - // We'll hold the text streamed to this object here. - const internal::scoped_ptr< ::std::stringstream> ss_; + const std::unique_ptr< ::std::stringstream> ss_; // We declare (but don't implement) this to prevent the compiler // from implementing the assignment operator. diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest-param-test.h b/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest-param-test.h index 3e95e4390e0..c2e6eae3d83 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest-param-test.h +++ b/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest-param-test.h @@ -1,7 +1,3 @@ -// This file was GENERATED by command: -// pump.py gtest-param-test.h.pump -// DO NOT EDIT BY HAND!!! - // Copyright 2008, Google Inc. // All rights reserved. // @@ -75,7 +71,7 @@ TEST_P(FooTest, HasBlahBlah) { ... } -// Finally, you can use INSTANTIATE_TEST_CASE_P to instantiate the test +// Finally, you can use INSTANTIATE_TEST_SUITE_P to instantiate the test // case with any set of parameters you want. Google Test defines a number // of functions for generating test parameters. They return what we call // (surprise!) parameter generators. Here is a summary of them, which @@ -96,17 +92,17 @@ TEST_P(FooTest, HasBlahBlah) { // For more details, see comments at the definitions of these functions below // in this file. // -// The following statement will instantiate tests from the FooTest test case +// The following statement will instantiate tests from the FooTest test suite // each with parameter values "meeny", "miny", and "moe". -INSTANTIATE_TEST_CASE_P(InstantiationName, - FooTest, - Values("meeny", "miny", "moe")); +INSTANTIATE_TEST_SUITE_P(InstantiationName, + FooTest, + Values("meeny", "miny", "moe")); // To distinguish different instances of the pattern, (yes, you -// can instantiate it more then once) the first argument to the -// INSTANTIATE_TEST_CASE_P macro is a prefix that will be added to the -// actual test case name. Remember to pick unique prefixes for different +// can instantiate it more than once) the first argument to the +// INSTANTIATE_TEST_SUITE_P macro is a prefix that will be added to the +// actual test suite name. Remember to pick unique prefixes for different // instantiations. The tests from the instantiation above will have // these names: // @@ -123,7 +119,7 @@ INSTANTIATE_TEST_CASE_P(InstantiationName, // with parameter values "cat" and "dog": const char* pets[] = {"cat", "dog"}; -INSTANTIATE_TEST_CASE_P(AnotherInstantiationName, FooTest, ValuesIn(pets)); +INSTANTIATE_TEST_SUITE_P(AnotherInstantiationName, FooTest, ValuesIn(pets)); // The tests from the instantiation above will have these names: // @@ -132,9 +128,9 @@ INSTANTIATE_TEST_CASE_P(AnotherInstantiationName, FooTest, ValuesIn(pets)); // * AnotherInstantiationName/FooTest.HasBlahBlah/0 for "cat" // * AnotherInstantiationName/FooTest.HasBlahBlah/1 for "dog" // -// Please note that INSTANTIATE_TEST_CASE_P will instantiate all tests -// in the given test case, whether their definitions come before or -// AFTER the INSTANTIATE_TEST_CASE_P statement. +// Please note that INSTANTIATE_TEST_SUITE_P will instantiate all tests +// in the given test suite, whether their definitions come before or +// AFTER the INSTANTIATE_TEST_SUITE_P statement. // // Please also note that generator expressions (including parameters to the // generators) are evaluated in InitGoogleTest(), after main() has started. @@ -178,26 +174,23 @@ TEST_P(DerivedTest, DoesBlah) { #endif // 0 -#include "gtest/internal/gtest-port.h" - -#if !GTEST_OS_SYMBIAN -# include <utility> -#endif +#include <iterator> +#include <utility> #include "gtest/internal/gtest-internal.h" #include "gtest/internal/gtest-param-util.h" -#include "gtest/internal/gtest-param-util-generated.h" +#include "gtest/internal/gtest-port.h" namespace testing { // Functions producing parameter generators. // // Google Test uses these generators to produce parameters for value- -// parameterized tests. When a parameterized test case is instantiated +// parameterized tests. When a parameterized test suite is instantiated // with a particular generator, Google Test creates and runs tests // for each element in the sequence produced by the generator. // -// In the following sample, tests from test case FooTest are instantiated +// In the following sample, tests from test suite FooTest are instantiated // each three times with parameter values 3, 5, and 8: // // class FooTest : public TestWithParam<int> { ... }; @@ -206,7 +199,7 @@ namespace testing { // } // TEST_P(FooTest, TestThat) { // } -// INSTANTIATE_TEST_CASE_P(TestSequence, FooTest, Values(3, 5, 8)); +// INSTANTIATE_TEST_SUITE_P(TestSequence, FooTest, Values(3, 5, 8)); // // Range() returns generators providing sequences of values in a range. @@ -263,13 +256,13 @@ internal::ParamGenerator<T> Range(T start, T end) { // // Examples: // -// This instantiates tests from test case StringTest +// This instantiates tests from test suite StringTest // each with C-string values of "foo", "bar", and "baz": // // const char* strings[] = {"foo", "bar", "baz"}; -// INSTANTIATE_TEST_CASE_P(StringSequence, StringTest, ValuesIn(strings)); +// INSTANTIATE_TEST_SUITE_P(StringSequence, StringTest, ValuesIn(strings)); // -// This instantiates tests from test case StlStringTest +// This instantiates tests from test suite StlStringTest // each with STL strings with values "a" and "b": // // ::std::vector< ::std::string> GetParameterStrings() { @@ -279,9 +272,9 @@ internal::ParamGenerator<T> Range(T start, T end) { // return v; // } // -// INSTANTIATE_TEST_CASE_P(CharSequence, -// StlStringTest, -// ValuesIn(GetParameterStrings())); +// INSTANTIATE_TEST_SUITE_P(CharSequence, +// StlStringTest, +// ValuesIn(GetParameterStrings())); // // // This will also instantiate tests from CharTest @@ -294,16 +287,15 @@ internal::ParamGenerator<T> Range(T start, T end) { // return list; // } // ::std::list<char> l = GetParameterChars(); -// INSTANTIATE_TEST_CASE_P(CharSequence2, -// CharTest, -// ValuesIn(l.begin(), l.end())); +// INSTANTIATE_TEST_SUITE_P(CharSequence2, +// CharTest, +// ValuesIn(l.begin(), l.end())); // template <typename ForwardIterator> internal::ParamGenerator< - typename ::testing::internal::IteratorTraits<ForwardIterator>::value_type> + typename std::iterator_traits<ForwardIterator>::value_type> ValuesIn(ForwardIterator begin, ForwardIterator end) { - typedef typename ::testing::internal::IteratorTraits<ForwardIterator> - ::value_type ParamType; + typedef typename std::iterator_traits<ForwardIterator>::value_type ParamType; return internal::ParamGenerator<ParamType>( new internal::ValuesInIteratorRangeGenerator<ParamType>(begin, end)); } @@ -326,869 +318,22 @@ internal::ParamGenerator<typename Container::value_type> ValuesIn( // Values(T v1, T v2, ..., T vN) // - returns a generator producing sequences with elements v1, v2, ..., vN. // -// For example, this instantiates tests from test case BarTest each +// For example, this instantiates tests from test suite BarTest each // with values "one", "two", and "three": // -// INSTANTIATE_TEST_CASE_P(NumSequence, BarTest, Values("one", "two", "three")); +// INSTANTIATE_TEST_SUITE_P(NumSequence, +// BarTest, +// Values("one", "two", "three")); // -// This instantiates tests from test case BazTest each with values 1, 2, 3.5. +// This instantiates tests from test suite BazTest each with values 1, 2, 3.5. // The exact type of values will depend on the type of parameter in BazTest. // -// INSTANTIATE_TEST_CASE_P(FloatingNumbers, BazTest, Values(1, 2, 3.5)); +// INSTANTIATE_TEST_SUITE_P(FloatingNumbers, BazTest, Values(1, 2, 3.5)); // -// Currently, Values() supports from 1 to 50 parameters. // -template <typename T1> -internal::ValueArray1<T1> Values(T1 v1) { - return internal::ValueArray1<T1>(v1); -} - -template <typename T1, typename T2> -internal::ValueArray2<T1, T2> Values(T1 v1, T2 v2) { - return internal::ValueArray2<T1, T2>(v1, v2); -} - -template <typename T1, typename T2, typename T3> -internal::ValueArray3<T1, T2, T3> Values(T1 v1, T2 v2, T3 v3) { - return internal::ValueArray3<T1, T2, T3>(v1, v2, v3); -} - -template <typename T1, typename T2, typename T3, typename T4> -internal::ValueArray4<T1, T2, T3, T4> Values(T1 v1, T2 v2, T3 v3, T4 v4) { - return internal::ValueArray4<T1, T2, T3, T4>(v1, v2, v3, v4); -} - -template <typename T1, typename T2, typename T3, typename T4, typename T5> -internal::ValueArray5<T1, T2, T3, T4, T5> Values(T1 v1, T2 v2, T3 v3, T4 v4, - T5 v5) { - return internal::ValueArray5<T1, T2, T3, T4, T5>(v1, v2, v3, v4, v5); -} - -template <typename T1, typename T2, typename T3, typename T4, typename T5, - typename T6> -internal::ValueArray6<T1, T2, T3, T4, T5, T6> Values(T1 v1, T2 v2, T3 v3, - T4 v4, T5 v5, T6 v6) { - return internal::ValueArray6<T1, T2, T3, T4, T5, T6>(v1, v2, v3, v4, v5, v6); -} - -template <typename T1, typename T2, typename T3, typename T4, typename T5, - typename T6, typename T7> -internal::ValueArray7<T1, T2, T3, T4, T5, T6, T7> Values(T1 v1, T2 v2, T3 v3, - T4 v4, T5 v5, T6 v6, T7 v7) { - return internal::ValueArray7<T1, T2, T3, T4, T5, T6, T7>(v1, v2, v3, v4, v5, - v6, v7); -} - -template <typename T1, typename T2, typename T3, typename T4, typename T5, - typename T6, typename T7, typename T8> -internal::ValueArray8<T1, T2, T3, T4, T5, T6, T7, T8> Values(T1 v1, T2 v2, - T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8) { - return internal::ValueArray8<T1, T2, T3, T4, T5, T6, T7, T8>(v1, v2, v3, v4, - v5, v6, v7, v8); -} - -template <typename T1, typename T2, typename T3, typename T4, typename T5, - typename T6, typename T7, typename T8, typename T9> -internal::ValueArray9<T1, T2, T3, T4, T5, T6, T7, T8, T9> Values(T1 v1, T2 v2, - T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9) { - return internal::ValueArray9<T1, T2, T3, T4, T5, T6, T7, T8, T9>(v1, v2, v3, - v4, v5, v6, v7, v8, v9); -} - -template <typename T1, typename T2, typename T3, typename T4, typename T5, - typename T6, typename T7, typename T8, typename T9, typename T10> -internal::ValueArray10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> Values(T1 v1, - T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10) { - return internal::ValueArray10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(v1, - v2, v3, v4, v5, v6, v7, v8, v9, v10); -} - -template <typename T1, typename T2, typename T3, typename T4, typename T5, - typename T6, typename T7, typename T8, typename T9, typename T10, - typename T11> -internal::ValueArray11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, - T11> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11) { - return internal::ValueArray11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, - T11>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11); -} - -template <typename T1, typename T2, typename T3, typename T4, typename T5, - typename T6, typename T7, typename T8, typename T9, typename T10, - typename T11, typename T12> -internal::ValueArray12<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, - T12> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12) { - return internal::ValueArray12<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, - T12>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12); -} - -template <typename T1, typename T2, typename T3, typename T4, typename T5, - typename T6, typename T7, typename T8, typename T9, typename T10, - typename T11, typename T12, typename T13> -internal::ValueArray13<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, - T13> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13) { - return internal::ValueArray13<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, - T12, T13>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13); -} - -template <typename T1, typename T2, typename T3, typename T4, typename T5, - typename T6, typename T7, typename T8, typename T9, typename T10, - typename T11, typename T12, typename T13, typename T14> -internal::ValueArray14<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, - T14> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14) { - return internal::ValueArray14<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, - T12, T13, T14>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, - v14); -} - -template <typename T1, typename T2, typename T3, typename T4, typename T5, - typename T6, typename T7, typename T8, typename T9, typename T10, - typename T11, typename T12, typename T13, typename T14, typename T15> -internal::ValueArray15<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, - T14, T15> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, - T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15) { - return internal::ValueArray15<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, - T12, T13, T14, T15>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, - v13, v14, v15); -} - -template <typename T1, typename T2, typename T3, typename T4, typename T5, - typename T6, typename T7, typename T8, typename T9, typename T10, - typename T11, typename T12, typename T13, typename T14, typename T15, - typename T16> -internal::ValueArray16<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, - T14, T15, T16> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, - T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, - T16 v16) { - return internal::ValueArray16<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, - T12, T13, T14, T15, T16>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, - v12, v13, v14, v15, v16); -} - -template <typename T1, typename T2, typename T3, typename T4, typename T5, - typename T6, typename T7, typename T8, typename T9, typename T10, - typename T11, typename T12, typename T13, typename T14, typename T15, - typename T16, typename T17> -internal::ValueArray17<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, - T14, T15, T16, T17> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, - T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, - T16 v16, T17 v17) { - return internal::ValueArray17<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, - T12, T13, T14, T15, T16, T17>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, - v11, v12, v13, v14, v15, v16, v17); -} - -template <typename T1, typename T2, typename T3, typename T4, typename T5, - typename T6, typename T7, typename T8, typename T9, typename T10, - typename T11, typename T12, typename T13, typename T14, typename T15, - typename T16, typename T17, typename T18> -internal::ValueArray18<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, - T14, T15, T16, T17, T18> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, - T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, - T16 v16, T17 v17, T18 v18) { - return internal::ValueArray18<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, - T12, T13, T14, T15, T16, T17, T18>(v1, v2, v3, v4, v5, v6, v7, v8, v9, - v10, v11, v12, v13, v14, v15, v16, v17, v18); -} - -template <typename T1, typename T2, typename T3, typename T4, typename T5, - typename T6, typename T7, typename T8, typename T9, typename T10, - typename T11, typename T12, typename T13, typename T14, typename T15, - typename T16, typename T17, typename T18, typename T19> -internal::ValueArray19<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, - T14, T15, T16, T17, T18, T19> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, - T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, - T15 v15, T16 v16, T17 v17, T18 v18, T19 v19) { - return internal::ValueArray19<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, - T12, T13, T14, T15, T16, T17, T18, T19>(v1, v2, v3, v4, v5, v6, v7, v8, - v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19); -} - -template <typename T1, typename T2, typename T3, typename T4, typename T5, - typename T6, typename T7, typename T8, typename T9, typename T10, - typename T11, typename T12, typename T13, typename T14, typename T15, - typename T16, typename T17, typename T18, typename T19, typename T20> -internal::ValueArray20<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, - T14, T15, T16, T17, T18, T19, T20> Values(T1 v1, T2 v2, T3 v3, T4 v4, - T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, - T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20) { - return internal::ValueArray20<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, - T12, T13, T14, T15, T16, T17, T18, T19, T20>(v1, v2, v3, v4, v5, v6, v7, - v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20); -} - -template <typename T1, typename T2, typename T3, typename T4, typename T5, - typename T6, typename T7, typename T8, typename T9, typename T10, - typename T11, typename T12, typename T13, typename T14, typename T15, - typename T16, typename T17, typename T18, typename T19, typename T20, - typename T21> -internal::ValueArray21<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, - T14, T15, T16, T17, T18, T19, T20, T21> Values(T1 v1, T2 v2, T3 v3, T4 v4, - T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, - T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21) { - return internal::ValueArray21<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, - T12, T13, T14, T15, T16, T17, T18, T19, T20, T21>(v1, v2, v3, v4, v5, v6, - v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21); -} - -template <typename T1, typename T2, typename T3, typename T4, typename T5, - typename T6, typename T7, typename T8, typename T9, typename T10, - typename T11, typename T12, typename T13, typename T14, typename T15, - typename T16, typename T17, typename T18, typename T19, typename T20, - typename T21, typename T22> -internal::ValueArray22<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, - T14, T15, T16, T17, T18, T19, T20, T21, T22> Values(T1 v1, T2 v2, T3 v3, - T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, - T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, - T21 v21, T22 v22) { - return internal::ValueArray22<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, - T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22>(v1, v2, v3, v4, - v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, - v20, v21, v22); -} - -template <typename T1, typename T2, typename T3, typename T4, typename T5, - typename T6, typename T7, typename T8, typename T9, typename T10, - typename T11, typename T12, typename T13, typename T14, typename T15, - typename T16, typename T17, typename T18, typename T19, typename T20, - typename T21, typename T22, typename T23> -internal::ValueArray23<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, - T14, T15, T16, T17, T18, T19, T20, T21, T22, T23> Values(T1 v1, T2 v2, - T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, - T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, - T21 v21, T22 v22, T23 v23) { - return internal::ValueArray23<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, - T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23>(v1, v2, v3, - v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, - v20, v21, v22, v23); -} - -template <typename T1, typename T2, typename T3, typename T4, typename T5, - typename T6, typename T7, typename T8, typename T9, typename T10, - typename T11, typename T12, typename T13, typename T14, typename T15, - typename T16, typename T17, typename T18, typename T19, typename T20, - typename T21, typename T22, typename T23, typename T24> -internal::ValueArray24<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, - T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24> Values(T1 v1, T2 v2, - T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, - T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, - T21 v21, T22 v22, T23 v23, T24 v24) { - return internal::ValueArray24<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, - T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24>(v1, v2, - v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, - v19, v20, v21, v22, v23, v24); -} - -template <typename T1, typename T2, typename T3, typename T4, typename T5, - typename T6, typename T7, typename T8, typename T9, typename T10, - typename T11, typename T12, typename T13, typename T14, typename T15, - typename T16, typename T17, typename T18, typename T19, typename T20, - typename T21, typename T22, typename T23, typename T24, typename T25> -internal::ValueArray25<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, - T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25> Values(T1 v1, - T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, - T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, - T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25) { - return internal::ValueArray25<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, - T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25>(v1, - v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, - v18, v19, v20, v21, v22, v23, v24, v25); -} - -template <typename T1, typename T2, typename T3, typename T4, typename T5, - typename T6, typename T7, typename T8, typename T9, typename T10, - typename T11, typename T12, typename T13, typename T14, typename T15, - typename T16, typename T17, typename T18, typename T19, typename T20, - typename T21, typename T22, typename T23, typename T24, typename T25, - typename T26> -internal::ValueArray26<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, - T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, - T26> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26) { - return internal::ValueArray26<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, - T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, - T26>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, - v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26); -} - -template <typename T1, typename T2, typename T3, typename T4, typename T5, - typename T6, typename T7, typename T8, typename T9, typename T10, - typename T11, typename T12, typename T13, typename T14, typename T15, - typename T16, typename T17, typename T18, typename T19, typename T20, - typename T21, typename T22, typename T23, typename T24, typename T25, - typename T26, typename T27> -internal::ValueArray27<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, - T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, - T27> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27) { - return internal::ValueArray27<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, - T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, - T26, T27>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, - v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27); -} - -template <typename T1, typename T2, typename T3, typename T4, typename T5, - typename T6, typename T7, typename T8, typename T9, typename T10, - typename T11, typename T12, typename T13, typename T14, typename T15, - typename T16, typename T17, typename T18, typename T19, typename T20, - typename T21, typename T22, typename T23, typename T24, typename T25, - typename T26, typename T27, typename T28> -internal::ValueArray28<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, - T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, - T28> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28) { - return internal::ValueArray28<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, - T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, - T26, T27, T28>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, - v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, - v28); -} - -template <typename T1, typename T2, typename T3, typename T4, typename T5, - typename T6, typename T7, typename T8, typename T9, typename T10, - typename T11, typename T12, typename T13, typename T14, typename T15, - typename T16, typename T17, typename T18, typename T19, typename T20, - typename T21, typename T22, typename T23, typename T24, typename T25, - typename T26, typename T27, typename T28, typename T29> -internal::ValueArray29<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, - T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, - T29> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29) { - return internal::ValueArray29<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, - T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, - T26, T27, T28, T29>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, - v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, - v27, v28, v29); -} - -template <typename T1, typename T2, typename T3, typename T4, typename T5, - typename T6, typename T7, typename T8, typename T9, typename T10, - typename T11, typename T12, typename T13, typename T14, typename T15, - typename T16, typename T17, typename T18, typename T19, typename T20, - typename T21, typename T22, typename T23, typename T24, typename T25, - typename T26, typename T27, typename T28, typename T29, typename T30> -internal::ValueArray30<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, - T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, - T29, T30> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, - T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, - T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, - T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30) { - return internal::ValueArray30<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, - T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, - T26, T27, T28, T29, T30>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, - v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, - v26, v27, v28, v29, v30); -} - -template <typename T1, typename T2, typename T3, typename T4, typename T5, - typename T6, typename T7, typename T8, typename T9, typename T10, - typename T11, typename T12, typename T13, typename T14, typename T15, - typename T16, typename T17, typename T18, typename T19, typename T20, - typename T21, typename T22, typename T23, typename T24, typename T25, - typename T26, typename T27, typename T28, typename T29, typename T30, - typename T31> -internal::ValueArray31<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, - T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, - T29, T30, T31> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, - T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, - T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, - T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31) { - return internal::ValueArray31<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, - T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, - T26, T27, T28, T29, T30, T31>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, - v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, - v25, v26, v27, v28, v29, v30, v31); -} - -template <typename T1, typename T2, typename T3, typename T4, typename T5, - typename T6, typename T7, typename T8, typename T9, typename T10, - typename T11, typename T12, typename T13, typename T14, typename T15, - typename T16, typename T17, typename T18, typename T19, typename T20, - typename T21, typename T22, typename T23, typename T24, typename T25, - typename T26, typename T27, typename T28, typename T29, typename T30, - typename T31, typename T32> -internal::ValueArray32<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, - T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, - T29, T30, T31, T32> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, - T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, - T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, - T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, - T32 v32) { - return internal::ValueArray32<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, - T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, - T26, T27, T28, T29, T30, T31, T32>(v1, v2, v3, v4, v5, v6, v7, v8, v9, - v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, - v24, v25, v26, v27, v28, v29, v30, v31, v32); -} - -template <typename T1, typename T2, typename T3, typename T4, typename T5, - typename T6, typename T7, typename T8, typename T9, typename T10, - typename T11, typename T12, typename T13, typename T14, typename T15, - typename T16, typename T17, typename T18, typename T19, typename T20, - typename T21, typename T22, typename T23, typename T24, typename T25, - typename T26, typename T27, typename T28, typename T29, typename T30, - typename T31, typename T32, typename T33> -internal::ValueArray33<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, - T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, - T29, T30, T31, T32, T33> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, - T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, - T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, - T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, - T32 v32, T33 v33) { - return internal::ValueArray33<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, - T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, - T26, T27, T28, T29, T30, T31, T32, T33>(v1, v2, v3, v4, v5, v6, v7, v8, - v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, - v24, v25, v26, v27, v28, v29, v30, v31, v32, v33); -} - -template <typename T1, typename T2, typename T3, typename T4, typename T5, - typename T6, typename T7, typename T8, typename T9, typename T10, - typename T11, typename T12, typename T13, typename T14, typename T15, - typename T16, typename T17, typename T18, typename T19, typename T20, - typename T21, typename T22, typename T23, typename T24, typename T25, - typename T26, typename T27, typename T28, typename T29, typename T30, - typename T31, typename T32, typename T33, typename T34> -internal::ValueArray34<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, - T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, - T29, T30, T31, T32, T33, T34> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, - T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, - T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, - T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, - T31 v31, T32 v32, T33 v33, T34 v34) { - return internal::ValueArray34<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, - T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, - T26, T27, T28, T29, T30, T31, T32, T33, T34>(v1, v2, v3, v4, v5, v6, v7, - v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, - v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34); -} - -template <typename T1, typename T2, typename T3, typename T4, typename T5, - typename T6, typename T7, typename T8, typename T9, typename T10, - typename T11, typename T12, typename T13, typename T14, typename T15, - typename T16, typename T17, typename T18, typename T19, typename T20, - typename T21, typename T22, typename T23, typename T24, typename T25, - typename T26, typename T27, typename T28, typename T29, typename T30, - typename T31, typename T32, typename T33, typename T34, typename T35> -internal::ValueArray35<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, - T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, - T29, T30, T31, T32, T33, T34, T35> Values(T1 v1, T2 v2, T3 v3, T4 v4, - T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, - T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, - T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, - T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35) { - return internal::ValueArray35<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, - T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, - T26, T27, T28, T29, T30, T31, T32, T33, T34, T35>(v1, v2, v3, v4, v5, v6, - v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, - v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35); -} - -template <typename T1, typename T2, typename T3, typename T4, typename T5, - typename T6, typename T7, typename T8, typename T9, typename T10, - typename T11, typename T12, typename T13, typename T14, typename T15, - typename T16, typename T17, typename T18, typename T19, typename T20, - typename T21, typename T22, typename T23, typename T24, typename T25, - typename T26, typename T27, typename T28, typename T29, typename T30, - typename T31, typename T32, typename T33, typename T34, typename T35, - typename T36> -internal::ValueArray36<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, - T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, - T29, T30, T31, T32, T33, T34, T35, T36> Values(T1 v1, T2 v2, T3 v3, T4 v4, - T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, - T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, - T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, - T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36) { - return internal::ValueArray36<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, - T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, - T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36>(v1, v2, v3, v4, - v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, - v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, - v34, v35, v36); -} - -template <typename T1, typename T2, typename T3, typename T4, typename T5, - typename T6, typename T7, typename T8, typename T9, typename T10, - typename T11, typename T12, typename T13, typename T14, typename T15, - typename T16, typename T17, typename T18, typename T19, typename T20, - typename T21, typename T22, typename T23, typename T24, typename T25, - typename T26, typename T27, typename T28, typename T29, typename T30, - typename T31, typename T32, typename T33, typename T34, typename T35, - typename T36, typename T37> -internal::ValueArray37<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, - T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, - T29, T30, T31, T32, T33, T34, T35, T36, T37> Values(T1 v1, T2 v2, T3 v3, - T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, - T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, - T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, - T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, - T37 v37) { - return internal::ValueArray37<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, - T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, - T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37>(v1, v2, v3, - v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, - v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, - v34, v35, v36, v37); -} - -template <typename T1, typename T2, typename T3, typename T4, typename T5, - typename T6, typename T7, typename T8, typename T9, typename T10, - typename T11, typename T12, typename T13, typename T14, typename T15, - typename T16, typename T17, typename T18, typename T19, typename T20, - typename T21, typename T22, typename T23, typename T24, typename T25, - typename T26, typename T27, typename T28, typename T29, typename T30, - typename T31, typename T32, typename T33, typename T34, typename T35, - typename T36, typename T37, typename T38> -internal::ValueArray38<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, - T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, - T29, T30, T31, T32, T33, T34, T35, T36, T37, T38> Values(T1 v1, T2 v2, - T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, - T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, - T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, - T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, - T37 v37, T38 v38) { - return internal::ValueArray38<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, - T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, - T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38>(v1, v2, - v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, - v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, - v33, v34, v35, v36, v37, v38); -} - -template <typename T1, typename T2, typename T3, typename T4, typename T5, - typename T6, typename T7, typename T8, typename T9, typename T10, - typename T11, typename T12, typename T13, typename T14, typename T15, - typename T16, typename T17, typename T18, typename T19, typename T20, - typename T21, typename T22, typename T23, typename T24, typename T25, - typename T26, typename T27, typename T28, typename T29, typename T30, - typename T31, typename T32, typename T33, typename T34, typename T35, - typename T36, typename T37, typename T38, typename T39> -internal::ValueArray39<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, - T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, - T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39> Values(T1 v1, T2 v2, - T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, - T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, - T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, - T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, - T37 v37, T38 v38, T39 v39) { - return internal::ValueArray39<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, - T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, - T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39>(v1, - v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, - v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, - v32, v33, v34, v35, v36, v37, v38, v39); -} - -template <typename T1, typename T2, typename T3, typename T4, typename T5, - typename T6, typename T7, typename T8, typename T9, typename T10, - typename T11, typename T12, typename T13, typename T14, typename T15, - typename T16, typename T17, typename T18, typename T19, typename T20, - typename T21, typename T22, typename T23, typename T24, typename T25, - typename T26, typename T27, typename T28, typename T29, typename T30, - typename T31, typename T32, typename T33, typename T34, typename T35, - typename T36, typename T37, typename T38, typename T39, typename T40> -internal::ValueArray40<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, - T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, - T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40> Values(T1 v1, - T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, - T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, - T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, - T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, - T36 v36, T37 v37, T38 v38, T39 v39, T40 v40) { - return internal::ValueArray40<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, - T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, - T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, - T40>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, - v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, - v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40); -} - -template <typename T1, typename T2, typename T3, typename T4, typename T5, - typename T6, typename T7, typename T8, typename T9, typename T10, - typename T11, typename T12, typename T13, typename T14, typename T15, - typename T16, typename T17, typename T18, typename T19, typename T20, - typename T21, typename T22, typename T23, typename T24, typename T25, - typename T26, typename T27, typename T28, typename T29, typename T30, - typename T31, typename T32, typename T33, typename T34, typename T35, - typename T36, typename T37, typename T38, typename T39, typename T40, - typename T41> -internal::ValueArray41<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, - T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, - T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, - T41> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41) { - return internal::ValueArray41<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, - T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, - T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, - T40, T41>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, - v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, - v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41); -} - -template <typename T1, typename T2, typename T3, typename T4, typename T5, - typename T6, typename T7, typename T8, typename T9, typename T10, - typename T11, typename T12, typename T13, typename T14, typename T15, - typename T16, typename T17, typename T18, typename T19, typename T20, - typename T21, typename T22, typename T23, typename T24, typename T25, - typename T26, typename T27, typename T28, typename T29, typename T30, - typename T31, typename T32, typename T33, typename T34, typename T35, - typename T36, typename T37, typename T38, typename T39, typename T40, - typename T41, typename T42> -internal::ValueArray42<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, - T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, - T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, - T42> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, - T42 v42) { - return internal::ValueArray42<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, - T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, - T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, - T40, T41, T42>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, - v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, - v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, - v42); -} - -template <typename T1, typename T2, typename T3, typename T4, typename T5, - typename T6, typename T7, typename T8, typename T9, typename T10, - typename T11, typename T12, typename T13, typename T14, typename T15, - typename T16, typename T17, typename T18, typename T19, typename T20, - typename T21, typename T22, typename T23, typename T24, typename T25, - typename T26, typename T27, typename T28, typename T29, typename T30, - typename T31, typename T32, typename T33, typename T34, typename T35, - typename T36, typename T37, typename T38, typename T39, typename T40, - typename T41, typename T42, typename T43> -internal::ValueArray43<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, - T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, - T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, - T43> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, - T42 v42, T43 v43) { - return internal::ValueArray43<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, - T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, - T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, - T40, T41, T42, T43>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, - v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, - v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, - v41, v42, v43); -} - -template <typename T1, typename T2, typename T3, typename T4, typename T5, - typename T6, typename T7, typename T8, typename T9, typename T10, - typename T11, typename T12, typename T13, typename T14, typename T15, - typename T16, typename T17, typename T18, typename T19, typename T20, - typename T21, typename T22, typename T23, typename T24, typename T25, - typename T26, typename T27, typename T28, typename T29, typename T30, - typename T31, typename T32, typename T33, typename T34, typename T35, - typename T36, typename T37, typename T38, typename T39, typename T40, - typename T41, typename T42, typename T43, typename T44> -internal::ValueArray44<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, - T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, - T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, - T44> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, - T42 v42, T43 v43, T44 v44) { - return internal::ValueArray44<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, - T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, - T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, - T40, T41, T42, T43, T44>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, - v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, - v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, - v40, v41, v42, v43, v44); -} - -template <typename T1, typename T2, typename T3, typename T4, typename T5, - typename T6, typename T7, typename T8, typename T9, typename T10, - typename T11, typename T12, typename T13, typename T14, typename T15, - typename T16, typename T17, typename T18, typename T19, typename T20, - typename T21, typename T22, typename T23, typename T24, typename T25, - typename T26, typename T27, typename T28, typename T29, typename T30, - typename T31, typename T32, typename T33, typename T34, typename T35, - typename T36, typename T37, typename T38, typename T39, typename T40, - typename T41, typename T42, typename T43, typename T44, typename T45> -internal::ValueArray45<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, - T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, - T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, - T44, T45> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, - T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, - T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, - T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, - T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, - T41 v41, T42 v42, T43 v43, T44 v44, T45 v45) { - return internal::ValueArray45<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, - T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, - T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, - T40, T41, T42, T43, T44, T45>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, - v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, - v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, - v39, v40, v41, v42, v43, v44, v45); -} - -template <typename T1, typename T2, typename T3, typename T4, typename T5, - typename T6, typename T7, typename T8, typename T9, typename T10, - typename T11, typename T12, typename T13, typename T14, typename T15, - typename T16, typename T17, typename T18, typename T19, typename T20, - typename T21, typename T22, typename T23, typename T24, typename T25, - typename T26, typename T27, typename T28, typename T29, typename T30, - typename T31, typename T32, typename T33, typename T34, typename T35, - typename T36, typename T37, typename T38, typename T39, typename T40, - typename T41, typename T42, typename T43, typename T44, typename T45, - typename T46> -internal::ValueArray46<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, - T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, - T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, - T44, T45, T46> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, - T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, - T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, - T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, - T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, - T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46) { - return internal::ValueArray46<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, - T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, - T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, - T40, T41, T42, T43, T44, T45, T46>(v1, v2, v3, v4, v5, v6, v7, v8, v9, - v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, - v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, - v38, v39, v40, v41, v42, v43, v44, v45, v46); -} - -template <typename T1, typename T2, typename T3, typename T4, typename T5, - typename T6, typename T7, typename T8, typename T9, typename T10, - typename T11, typename T12, typename T13, typename T14, typename T15, - typename T16, typename T17, typename T18, typename T19, typename T20, - typename T21, typename T22, typename T23, typename T24, typename T25, - typename T26, typename T27, typename T28, typename T29, typename T30, - typename T31, typename T32, typename T33, typename T34, typename T35, - typename T36, typename T37, typename T38, typename T39, typename T40, - typename T41, typename T42, typename T43, typename T44, typename T45, - typename T46, typename T47> -internal::ValueArray47<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, - T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, - T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, - T44, T45, T46, T47> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, - T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, - T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, - T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, - T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, - T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47) { - return internal::ValueArray47<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, - T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, - T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, - T40, T41, T42, T43, T44, T45, T46, T47>(v1, v2, v3, v4, v5, v6, v7, v8, - v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, - v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, - v38, v39, v40, v41, v42, v43, v44, v45, v46, v47); -} - -template <typename T1, typename T2, typename T3, typename T4, typename T5, - typename T6, typename T7, typename T8, typename T9, typename T10, - typename T11, typename T12, typename T13, typename T14, typename T15, - typename T16, typename T17, typename T18, typename T19, typename T20, - typename T21, typename T22, typename T23, typename T24, typename T25, - typename T26, typename T27, typename T28, typename T29, typename T30, - typename T31, typename T32, typename T33, typename T34, typename T35, - typename T36, typename T37, typename T38, typename T39, typename T40, - typename T41, typename T42, typename T43, typename T44, typename T45, - typename T46, typename T47, typename T48> -internal::ValueArray48<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, - T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, - T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, - T44, T45, T46, T47, T48> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, - T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, - T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, - T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, - T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, - T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, - T48 v48) { - return internal::ValueArray48<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, - T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, - T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, - T40, T41, T42, T43, T44, T45, T46, T47, T48>(v1, v2, v3, v4, v5, v6, v7, - v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, - v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, - v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48); -} - -template <typename T1, typename T2, typename T3, typename T4, typename T5, - typename T6, typename T7, typename T8, typename T9, typename T10, - typename T11, typename T12, typename T13, typename T14, typename T15, - typename T16, typename T17, typename T18, typename T19, typename T20, - typename T21, typename T22, typename T23, typename T24, typename T25, - typename T26, typename T27, typename T28, typename T29, typename T30, - typename T31, typename T32, typename T33, typename T34, typename T35, - typename T36, typename T37, typename T38, typename T39, typename T40, - typename T41, typename T42, typename T43, typename T44, typename T45, - typename T46, typename T47, typename T48, typename T49> -internal::ValueArray49<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, - T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, - T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, - T44, T45, T46, T47, T48, T49> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, - T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, - T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, - T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, - T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, - T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, - T47 v47, T48 v48, T49 v49) { - return internal::ValueArray49<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, - T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, - T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, - T40, T41, T42, T43, T44, T45, T46, T47, T48, T49>(v1, v2, v3, v4, v5, v6, - v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, - v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, - v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49); -} - -template <typename T1, typename T2, typename T3, typename T4, typename T5, - typename T6, typename T7, typename T8, typename T9, typename T10, - typename T11, typename T12, typename T13, typename T14, typename T15, - typename T16, typename T17, typename T18, typename T19, typename T20, - typename T21, typename T22, typename T23, typename T24, typename T25, - typename T26, typename T27, typename T28, typename T29, typename T30, - typename T31, typename T32, typename T33, typename T34, typename T35, - typename T36, typename T37, typename T38, typename T39, typename T40, - typename T41, typename T42, typename T43, typename T44, typename T45, - typename T46, typename T47, typename T48, typename T49, typename T50> -internal::ValueArray50<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, - T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, - T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, - T44, T45, T46, T47, T48, T49, T50> Values(T1 v1, T2 v2, T3 v3, T4 v4, - T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, - T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, - T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, - T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, - T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, - T46 v46, T47 v47, T48 v48, T49 v49, T50 v50) { - return internal::ValueArray50<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, - T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, - T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, - T40, T41, T42, T43, T44, T45, T46, T47, T48, T49, T50>(v1, v2, v3, v4, - v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, - v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, - v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, - v48, v49, v50); +template <typename... T> +internal::ValueArray<T...> Values(T... v) { + return internal::ValueArray<T...>(std::move(v)...); } // Bool() allows generating tests with parameters in a set of (false, true). @@ -1201,7 +346,7 @@ internal::ValueArray50<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, // of multiple flags can be tested when several Bool()'s are combined using // Combine() function. // -// In the following example all tests in the test case FlagDependentTest +// In the following example all tests in the test suite FlagDependentTest // will be instantiated twice with parameters false and true. // // class FlagDependentTest : public testing::TestWithParam<bool> { @@ -1209,13 +354,12 @@ internal::ValueArray50<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, // external_flag = GetParam(); // } // } -// INSTANTIATE_TEST_CASE_P(BoolSequence, FlagDependentTest, Bool()); +// INSTANTIATE_TEST_SUITE_P(BoolSequence, FlagDependentTest, Bool()); // inline internal::ParamGenerator<bool> Bool() { return Values(false, true); } -# if GTEST_HAS_COMBINE // Combine() allows the user to combine two or more sequences to produce // values of a Cartesian product of those sequences' elements. // @@ -1224,184 +368,83 @@ inline internal::ParamGenerator<bool> Bool() { // - returns a generator producing sequences with elements coming from // the Cartesian product of elements from the sequences generated by // gen1, gen2, ..., genN. The sequence elements will have a type of -// tuple<T1, T2, ..., TN> where T1, T2, ..., TN are the types +// std::tuple<T1, T2, ..., TN> where T1, T2, ..., TN are the types // of elements from sequences produces by gen1, gen2, ..., genN. // -// Combine can have up to 10 arguments. This number is currently limited -// by the maximum number of elements in the tuple implementation used by Google -// Test. +// Combine can have up to 10 arguments. // // Example: // -// This will instantiate tests in test case AnimalTest each one with +// This will instantiate tests in test suite AnimalTest each one with // the parameter values tuple("cat", BLACK), tuple("cat", WHITE), // tuple("dog", BLACK), and tuple("dog", WHITE): // // enum Color { BLACK, GRAY, WHITE }; // class AnimalTest -// : public testing::TestWithParam<tuple<const char*, Color> > {...}; +// : public testing::TestWithParam<std::tuple<const char*, Color> > {...}; // // TEST_P(AnimalTest, AnimalLooksNice) {...} // -// INSTANTIATE_TEST_CASE_P(AnimalVariations, AnimalTest, -// Combine(Values("cat", "dog"), -// Values(BLACK, WHITE))); +// INSTANTIATE_TEST_SUITE_P(AnimalVariations, AnimalTest, +// Combine(Values("cat", "dog"), +// Values(BLACK, WHITE))); // // This will instantiate tests in FlagDependentTest with all variations of two // Boolean flags: // // class FlagDependentTest -// : public testing::TestWithParam<tuple<bool, bool> > { +// : public testing::TestWithParam<std::tuple<bool, bool> > { // virtual void SetUp() { // // Assigns external_flag_1 and external_flag_2 values from the tuple. -// tie(external_flag_1, external_flag_2) = GetParam(); +// std::tie(external_flag_1, external_flag_2) = GetParam(); // } // }; // // TEST_P(FlagDependentTest, TestFeature1) { // // Test your code using external_flag_1 and external_flag_2 here. // } -// INSTANTIATE_TEST_CASE_P(TwoBoolSequence, FlagDependentTest, -// Combine(Bool(), Bool())); -// -template <typename Generator1, typename Generator2> -internal::CartesianProductHolder2<Generator1, Generator2> Combine( - const Generator1& g1, const Generator2& g2) { - return internal::CartesianProductHolder2<Generator1, Generator2>( - g1, g2); -} - -template <typename Generator1, typename Generator2, typename Generator3> -internal::CartesianProductHolder3<Generator1, Generator2, Generator3> Combine( - const Generator1& g1, const Generator2& g2, const Generator3& g3) { - return internal::CartesianProductHolder3<Generator1, Generator2, Generator3>( - g1, g2, g3); -} - -template <typename Generator1, typename Generator2, typename Generator3, - typename Generator4> -internal::CartesianProductHolder4<Generator1, Generator2, Generator3, - Generator4> Combine( - const Generator1& g1, const Generator2& g2, const Generator3& g3, - const Generator4& g4) { - return internal::CartesianProductHolder4<Generator1, Generator2, Generator3, - Generator4>( - g1, g2, g3, g4); -} - -template <typename Generator1, typename Generator2, typename Generator3, - typename Generator4, typename Generator5> -internal::CartesianProductHolder5<Generator1, Generator2, Generator3, - Generator4, Generator5> Combine( - const Generator1& g1, const Generator2& g2, const Generator3& g3, - const Generator4& g4, const Generator5& g5) { - return internal::CartesianProductHolder5<Generator1, Generator2, Generator3, - Generator4, Generator5>( - g1, g2, g3, g4, g5); -} - -template <typename Generator1, typename Generator2, typename Generator3, - typename Generator4, typename Generator5, typename Generator6> -internal::CartesianProductHolder6<Generator1, Generator2, Generator3, - Generator4, Generator5, Generator6> Combine( - const Generator1& g1, const Generator2& g2, const Generator3& g3, - const Generator4& g4, const Generator5& g5, const Generator6& g6) { - return internal::CartesianProductHolder6<Generator1, Generator2, Generator3, - Generator4, Generator5, Generator6>( - g1, g2, g3, g4, g5, g6); -} - -template <typename Generator1, typename Generator2, typename Generator3, - typename Generator4, typename Generator5, typename Generator6, - typename Generator7> -internal::CartesianProductHolder7<Generator1, Generator2, Generator3, - Generator4, Generator5, Generator6, Generator7> Combine( - const Generator1& g1, const Generator2& g2, const Generator3& g3, - const Generator4& g4, const Generator5& g5, const Generator6& g6, - const Generator7& g7) { - return internal::CartesianProductHolder7<Generator1, Generator2, Generator3, - Generator4, Generator5, Generator6, Generator7>( - g1, g2, g3, g4, g5, g6, g7); -} - -template <typename Generator1, typename Generator2, typename Generator3, - typename Generator4, typename Generator5, typename Generator6, - typename Generator7, typename Generator8> -internal::CartesianProductHolder8<Generator1, Generator2, Generator3, - Generator4, Generator5, Generator6, Generator7, Generator8> Combine( - const Generator1& g1, const Generator2& g2, const Generator3& g3, - const Generator4& g4, const Generator5& g5, const Generator6& g6, - const Generator7& g7, const Generator8& g8) { - return internal::CartesianProductHolder8<Generator1, Generator2, Generator3, - Generator4, Generator5, Generator6, Generator7, Generator8>( - g1, g2, g3, g4, g5, g6, g7, g8); -} - -template <typename Generator1, typename Generator2, typename Generator3, - typename Generator4, typename Generator5, typename Generator6, - typename Generator7, typename Generator8, typename Generator9> -internal::CartesianProductHolder9<Generator1, Generator2, Generator3, - Generator4, Generator5, Generator6, Generator7, Generator8, - Generator9> Combine( - const Generator1& g1, const Generator2& g2, const Generator3& g3, - const Generator4& g4, const Generator5& g5, const Generator6& g6, - const Generator7& g7, const Generator8& g8, const Generator9& g9) { - return internal::CartesianProductHolder9<Generator1, Generator2, Generator3, - Generator4, Generator5, Generator6, Generator7, Generator8, Generator9>( - g1, g2, g3, g4, g5, g6, g7, g8, g9); -} - -template <typename Generator1, typename Generator2, typename Generator3, - typename Generator4, typename Generator5, typename Generator6, - typename Generator7, typename Generator8, typename Generator9, - typename Generator10> -internal::CartesianProductHolder10<Generator1, Generator2, Generator3, - Generator4, Generator5, Generator6, Generator7, Generator8, Generator9, - Generator10> Combine( - const Generator1& g1, const Generator2& g2, const Generator3& g3, - const Generator4& g4, const Generator5& g5, const Generator6& g6, - const Generator7& g7, const Generator8& g8, const Generator9& g9, - const Generator10& g10) { - return internal::CartesianProductHolder10<Generator1, Generator2, Generator3, - Generator4, Generator5, Generator6, Generator7, Generator8, Generator9, - Generator10>( - g1, g2, g3, g4, g5, g6, g7, g8, g9, g10); -} -# endif // GTEST_HAS_COMBINE - -# define TEST_P(test_case_name, test_name) \ - class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \ - : public test_case_name { \ - public: \ - GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {} \ - virtual void TestBody(); \ - private: \ - static int AddToRegistry() { \ - ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \ - GetTestCasePatternHolder<test_case_name>(\ - #test_case_name, \ - ::testing::internal::CodeLocation(\ - __FILE__, __LINE__))->AddTestPattern(\ - GTEST_STRINGIFY_(test_case_name), \ - GTEST_STRINGIFY_(test_name), \ - new ::testing::internal::TestMetaFactory< \ - GTEST_TEST_CLASS_NAME_(\ - test_case_name, test_name)>()); \ - return 0; \ - } \ - static int gtest_registering_dummy_ GTEST_ATTRIBUTE_UNUSED_; \ - GTEST_DISALLOW_COPY_AND_ASSIGN_(\ - GTEST_TEST_CLASS_NAME_(test_case_name, test_name)); \ - }; \ - int GTEST_TEST_CLASS_NAME_(test_case_name, \ - test_name)::gtest_registering_dummy_ = \ - GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::AddToRegistry(); \ - void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody() - -// The optional last argument to INSTANTIATE_TEST_CASE_P allows the user -// to specify a function or functor that generates custom test name suffixes -// based on the test parameters. The function should accept one argument of -// type testing::TestParamInfo<class ParamType>, and return std::string. +// INSTANTIATE_TEST_SUITE_P(TwoBoolSequence, FlagDependentTest, +// Combine(Bool(), Bool())); +// +template <typename... Generator> +internal::CartesianProductHolder<Generator...> Combine(const Generator&... g) { + return internal::CartesianProductHolder<Generator...>(g...); +} + +#define TEST_P(test_suite_name, test_name) \ + class GTEST_TEST_CLASS_NAME_(test_suite_name, test_name) \ + : public test_suite_name { \ + public: \ + GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)() {} \ + virtual void TestBody(); \ + \ + private: \ + static int AddToRegistry() { \ + ::testing::UnitTest::GetInstance() \ + ->parameterized_test_registry() \ + .GetTestSuitePatternHolder<test_suite_name>( \ + #test_suite_name, \ + ::testing::internal::CodeLocation(__FILE__, __LINE__)) \ + ->AddTestPattern( \ + GTEST_STRINGIFY_(test_suite_name), GTEST_STRINGIFY_(test_name), \ + new ::testing::internal::TestMetaFactory<GTEST_TEST_CLASS_NAME_( \ + test_suite_name, test_name)>()); \ + return 0; \ + } \ + static int gtest_registering_dummy_ GTEST_ATTRIBUTE_UNUSED_; \ + GTEST_DISALLOW_COPY_AND_ASSIGN_(GTEST_TEST_CLASS_NAME_(test_suite_name, \ + test_name)); \ + }; \ + int GTEST_TEST_CLASS_NAME_(test_suite_name, \ + test_name)::gtest_registering_dummy_ = \ + GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)::AddToRegistry(); \ + void GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)::TestBody() + +// The last argument to INSTANTIATE_TEST_SUITE_P allows the user to specify +// generator and an optional function or functor that generates custom test name +// suffixes based on the test parameters. Such a function or functor should +// accept one argument of type testing::TestParamInfo<class ParamType>, and +// return std::string. // // testing::PrintToStringParamName is a builtin test suffix generator that // returns the value of testing::PrintToString(GetParam()). @@ -1410,24 +453,50 @@ internal::CartesianProductHolder10<Generator1, Generator2, Generator3, // alphanumeric characters or underscore. Because PrintToString adds quotes // to std::string and C strings, it won't work for these types. -# define INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator, ...) \ - static ::testing::internal::ParamGenerator<test_case_name::ParamType> \ - gtest_##prefix##test_case_name##_EvalGenerator_() { return generator; } \ - static ::std::string gtest_##prefix##test_case_name##_EvalGenerateName_( \ - const ::testing::TestParamInfo<test_case_name::ParamType>& info) { \ - return ::testing::internal::GetParamNameGen<test_case_name::ParamType> \ - (__VA_ARGS__)(info); \ - } \ - static int gtest_##prefix##test_case_name##_dummy_ GTEST_ATTRIBUTE_UNUSED_ = \ - ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \ - GetTestCasePatternHolder<test_case_name>(\ - #test_case_name, \ - ::testing::internal::CodeLocation(\ - __FILE__, __LINE__))->AddTestCaseInstantiation(\ - #prefix, \ - >est_##prefix##test_case_name##_EvalGenerator_, \ - >est_##prefix##test_case_name##_EvalGenerateName_, \ - __FILE__, __LINE__) +#define GTEST_EXPAND_(arg) arg +#define GTEST_GET_FIRST_(first, ...) first +#define GTEST_GET_SECOND_(first, second, ...) second + +#define INSTANTIATE_TEST_SUITE_P(prefix, test_suite_name, ...) \ + static ::testing::internal::ParamGenerator<test_suite_name::ParamType> \ + gtest_##prefix##test_suite_name##_EvalGenerator_() { \ + return GTEST_EXPAND_(GTEST_GET_FIRST_(__VA_ARGS__, DUMMY_PARAM_)); \ + } \ + static ::std::string gtest_##prefix##test_suite_name##_EvalGenerateName_( \ + const ::testing::TestParamInfo<test_suite_name::ParamType>& info) { \ + if (::testing::internal::AlwaysFalse()) { \ + ::testing::internal::TestNotEmpty(GTEST_EXPAND_(GTEST_GET_SECOND_( \ + __VA_ARGS__, \ + ::testing::internal::DefaultParamName<test_suite_name::ParamType>, \ + DUMMY_PARAM_))); \ + auto t = std::make_tuple(__VA_ARGS__); \ + static_assert(std::tuple_size<decltype(t)>::value <= 2, \ + "Too Many Args!"); \ + } \ + return ((GTEST_EXPAND_(GTEST_GET_SECOND_( \ + __VA_ARGS__, \ + ::testing::internal::DefaultParamName<test_suite_name::ParamType>, \ + DUMMY_PARAM_))))(info); \ + } \ + static int gtest_##prefix##test_suite_name##_dummy_ \ + GTEST_ATTRIBUTE_UNUSED_ = \ + ::testing::UnitTest::GetInstance() \ + ->parameterized_test_registry() \ + .GetTestSuitePatternHolder<test_suite_name>( \ + #test_suite_name, \ + ::testing::internal::CodeLocation(__FILE__, __LINE__)) \ + ->AddTestSuiteInstantiation( \ + #prefix, >est_##prefix##test_suite_name##_EvalGenerator_, \ + >est_##prefix##test_suite_name##_EvalGenerateName_, \ + __FILE__, __LINE__) + +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +#define INSTANTIATE_TEST_CASE_P \ + static_assert(::testing::internal::InstantiateTestCase_P_IsDeprecated(), \ + ""); \ + INSTANTIATE_TEST_SUITE_P +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ } // namespace testing diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest-printers.h b/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest-printers.h index 51865f84e6f..56a05450ef5 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest-printers.h +++ b/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest-printers.h @@ -100,17 +100,16 @@ #ifndef GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ #define GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ +#include <functional> #include <ostream> // NOLINT #include <sstream> #include <string> +#include <tuple> +#include <type_traits> #include <utility> #include <vector> -#include "gtest/internal/gtest-port.h" #include "gtest/internal/gtest-internal.h" - -#if GTEST_HAS_STD_TUPLE_ -# include <tuple> -#endif +#include "gtest/internal/gtest-port.h" #if GTEST_HAS_ABSL #include "absl/strings/string_view.h" @@ -152,9 +151,10 @@ class TypeWithoutFormatter { public: // This default version is called when kTypeKind is kOtherType. static void PrintValue(const T& value, ::std::ostream* os) { - PrintBytesInObjectTo(static_cast<const unsigned char*>( - reinterpret_cast<const void*>(&value)), - sizeof(value), os); + PrintBytesInObjectTo( + static_cast<const unsigned char*>( + reinterpret_cast<const void*>(std::addressof(value))), + sizeof(value), os); } }; @@ -233,12 +233,12 @@ template <typename Char, typename CharTraits, typename T> ::std::basic_ostream<Char, CharTraits>& os, const T& x) { TypeWithoutFormatter<T, (internal::IsAProtocolMessage<T>::value ? kProtobuf - : internal::ImplicitlyConvertible< + : std::is_convertible< const T&, internal::BiggestInt>::value ? kConvertibleToInteger : #if GTEST_HAS_ABSL - internal::ImplicitlyConvertible< + std::is_convertible< const T&, absl::string_view>::value ? kConvertibleToStringView : @@ -358,16 +358,6 @@ GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const wchar_t); GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char, ::std::string); GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char, ::std::string); -#if GTEST_HAS_GLOBAL_STRING -GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char, ::string); -GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char, ::string); -#endif - -#if GTEST_HAS_GLOBAL_WSTRING -GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(wchar_t, ::wstring); -GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const wchar_t, ::wstring); -#endif - #if GTEST_HAS_STD_WSTRING GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(wchar_t, ::std::wstring); GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const wchar_t, ::std::wstring); @@ -448,7 +438,7 @@ void DefaultPrintTo(WrapPrinterType<kPrintContainer> /* dummy */, template <typename T> void DefaultPrintTo(WrapPrinterType<kPrintPointer> /* dummy */, T* p, ::std::ostream* os) { - if (p == NULL) { + if (p == nullptr) { *os << "NULL"; } else { // T is not a function type. We just call << to print p, @@ -460,7 +450,7 @@ void DefaultPrintTo(WrapPrinterType<kPrintPointer> /* dummy */, template <typename T> void DefaultPrintTo(WrapPrinterType<kPrintFunctionPointer> /* dummy */, T* p, ::std::ostream* os) { - if (p == NULL) { + if (p == nullptr) { *os << "NULL"; } else { // T is a function type, so '*os << p' doesn't do what we want @@ -515,13 +505,9 @@ void PrintTo(const T& value, ::std::ostream* os) { (sizeof(IsContainerTest<T>(0)) == sizeof(IsContainer)) && !IsRecursiveContainer<T>::value ? kPrintContainer - : !is_pointer<T>::value + : !std::is_pointer<T>::value ? kPrintOther -#if GTEST_LANG_CXX11 : std::is_function<typename std::remove_pointer<T>::type>::value -#else - : !internal::ImplicitlyConvertible<T, const void*>::value -#endif ? kPrintFunctionPointer : kPrintPointer > (), value, os); @@ -603,27 +589,13 @@ void PrintRawArrayTo(const T a[], size_t count, ::std::ostream* os) { } } -// Overloads for ::string and ::std::string. -#if GTEST_HAS_GLOBAL_STRING -GTEST_API_ void PrintStringTo(const ::string&s, ::std::ostream* os); -inline void PrintTo(const ::string& s, ::std::ostream* os) { - PrintStringTo(s, os); -} -#endif // GTEST_HAS_GLOBAL_STRING - +// Overloads for ::std::string. GTEST_API_ void PrintStringTo(const ::std::string&s, ::std::ostream* os); inline void PrintTo(const ::std::string& s, ::std::ostream* os) { PrintStringTo(s, os); } -// Overloads for ::wstring and ::std::wstring. -#if GTEST_HAS_GLOBAL_WSTRING -GTEST_API_ void PrintWideStringTo(const ::wstring&s, ::std::ostream* os); -inline void PrintTo(const ::wstring& s, ::std::ostream* os) { - PrintWideStringTo(s, os); -} -#endif // GTEST_HAS_GLOBAL_WSTRING - +// Overloads for ::std::wstring. #if GTEST_HAS_STD_WSTRING GTEST_API_ void PrintWideStringTo(const ::std::wstring&s, ::std::ostream* os); inline void PrintTo(const ::std::wstring& s, ::std::ostream* os) { @@ -638,99 +610,38 @@ inline void PrintTo(absl::string_view sp, ::std::ostream* os) { } #endif // GTEST_HAS_ABSL -#if GTEST_LANG_CXX11 inline void PrintTo(std::nullptr_t, ::std::ostream* os) { *os << "(nullptr)"; } -#endif // GTEST_LANG_CXX11 -#if GTEST_HAS_TR1_TUPLE || GTEST_HAS_STD_TUPLE_ -// Helper function for printing a tuple. T must be instantiated with -// a tuple type. template <typename T> -void PrintTupleTo(const T& t, ::std::ostream* os); -#endif // GTEST_HAS_TR1_TUPLE || GTEST_HAS_STD_TUPLE_ - -#if GTEST_HAS_TR1_TUPLE -// Overload for ::std::tr1::tuple. Needed for printing function arguments, -// which are packed as tuples. - -// Overloaded PrintTo() for tuples of various arities. We support -// tuples of up-to 10 fields. The following implementation works -// regardless of whether tr1::tuple is implemented using the -// non-standard variadic template feature or not. - -inline void PrintTo(const ::std::tr1::tuple<>& t, ::std::ostream* os) { - PrintTupleTo(t, os); -} - -template <typename T1> -void PrintTo(const ::std::tr1::tuple<T1>& t, ::std::ostream* os) { - PrintTupleTo(t, os); -} - -template <typename T1, typename T2> -void PrintTo(const ::std::tr1::tuple<T1, T2>& t, ::std::ostream* os) { - PrintTupleTo(t, os); -} - -template <typename T1, typename T2, typename T3> -void PrintTo(const ::std::tr1::tuple<T1, T2, T3>& t, ::std::ostream* os) { - PrintTupleTo(t, os); -} - -template <typename T1, typename T2, typename T3, typename T4> -void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4>& t, ::std::ostream* os) { - PrintTupleTo(t, os); -} - -template <typename T1, typename T2, typename T3, typename T4, typename T5> -void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4, T5>& t, - ::std::ostream* os) { - PrintTupleTo(t, os); -} - -template <typename T1, typename T2, typename T3, typename T4, typename T5, - typename T6> -void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4, T5, T6>& t, - ::std::ostream* os) { - PrintTupleTo(t, os); -} - -template <typename T1, typename T2, typename T3, typename T4, typename T5, - typename T6, typename T7> -void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7>& t, - ::std::ostream* os) { - PrintTupleTo(t, os); -} - -template <typename T1, typename T2, typename T3, typename T4, typename T5, - typename T6, typename T7, typename T8> -void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8>& t, - ::std::ostream* os) { - PrintTupleTo(t, os); +void PrintTo(std::reference_wrapper<T> ref, ::std::ostream* os) { + UniversalPrinter<T&>::Print(ref.get(), os); } -template <typename T1, typename T2, typename T3, typename T4, typename T5, - typename T6, typename T7, typename T8, typename T9> -void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9>& t, - ::std::ostream* os) { - PrintTupleTo(t, os); -} - -template <typename T1, typename T2, typename T3, typename T4, typename T5, - typename T6, typename T7, typename T8, typename T9, typename T10> -void PrintTo( - const ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>& t, - ::std::ostream* os) { - PrintTupleTo(t, os); +// Helper function for printing a tuple. T must be instantiated with +// a tuple type. +template <typename T> +void PrintTupleTo(const T&, std::integral_constant<size_t, 0>, + ::std::ostream*) {} + +template <typename T, size_t I> +void PrintTupleTo(const T& t, std::integral_constant<size_t, I>, + ::std::ostream* os) { + PrintTupleTo(t, std::integral_constant<size_t, I - 1>(), os); + GTEST_INTENTIONAL_CONST_COND_PUSH_() + if (I > 1) { + GTEST_INTENTIONAL_CONST_COND_POP_() + *os << ", "; + } + UniversalPrinter<typename std::tuple_element<I - 1, T>::type>::Print( + std::get<I - 1>(t), os); } -#endif // GTEST_HAS_TR1_TUPLE -#if GTEST_HAS_STD_TUPLE_ template <typename... Types> void PrintTo(const ::std::tuple<Types...>& t, ::std::ostream* os) { - PrintTupleTo(t, os); + *os << "("; + PrintTupleTo(t, std::integral_constant<size_t, sizeof...(Types)>(), os); + *os << ")"; } -#endif // GTEST_HAS_STD_TUPLE_ // Overload for std::pair. template <typename T1, typename T2> @@ -826,7 +737,6 @@ void UniversalPrintArray(const T* begin, size_t len, ::std::ostream* os) { // If the array has more than kThreshold elements, we'll have to // omit some details by printing only the first and the last // kChunkSize elements. - // FIXME: let the user control the threshold using a flag. if (len <= kThreshold) { PrintRawArrayTo(begin, len, os); } else { @@ -905,7 +815,7 @@ template <> class UniversalTersePrinter<const char*> { public: static void Print(const char* str, ::std::ostream* os) { - if (str == NULL) { + if (str == nullptr) { *os << "NULL"; } else { UniversalPrint(std::string(str), os); @@ -925,7 +835,7 @@ template <> class UniversalTersePrinter<const wchar_t*> { public: static void Print(const wchar_t* str, ::std::ostream* os) { - if (str == NULL) { + if (str == nullptr) { *os << "NULL"; } else { UniversalPrint(::std::wstring(str), os); @@ -961,109 +871,20 @@ void UniversalPrint(const T& value, ::std::ostream* os) { typedef ::std::vector< ::std::string> Strings; -// TuplePolicy<TupleT> must provide: -// - tuple_size -// size of tuple TupleT. -// - get<size_t I>(const TupleT& t) -// static function extracting element I of tuple TupleT. -// - tuple_element<size_t I>::type -// type of element I of tuple TupleT. -template <typename TupleT> -struct TuplePolicy; - -#if GTEST_HAS_TR1_TUPLE -template <typename TupleT> -struct TuplePolicy { - typedef TupleT Tuple; - static const size_t tuple_size = ::std::tr1::tuple_size<Tuple>::value; - - template <size_t I> - struct tuple_element : ::std::tr1::tuple_element<static_cast<int>(I), Tuple> { - }; - - template <size_t I> - static typename AddReference<const typename ::std::tr1::tuple_element< - static_cast<int>(I), Tuple>::type>::type - get(const Tuple& tuple) { - return ::std::tr1::get<I>(tuple); - } -}; -template <typename TupleT> -const size_t TuplePolicy<TupleT>::tuple_size; -#endif // GTEST_HAS_TR1_TUPLE - -#if GTEST_HAS_STD_TUPLE_ -template <typename... Types> -struct TuplePolicy< ::std::tuple<Types...> > { - typedef ::std::tuple<Types...> Tuple; - static const size_t tuple_size = ::std::tuple_size<Tuple>::value; - - template <size_t I> - struct tuple_element : ::std::tuple_element<I, Tuple> {}; - - template <size_t I> - static const typename ::std::tuple_element<I, Tuple>::type& get( - const Tuple& tuple) { - return ::std::get<I>(tuple); - } -}; -template <typename... Types> -const size_t TuplePolicy< ::std::tuple<Types...> >::tuple_size; -#endif // GTEST_HAS_STD_TUPLE_ - -#if GTEST_HAS_TR1_TUPLE || GTEST_HAS_STD_TUPLE_ -// This helper template allows PrintTo() for tuples and -// UniversalTersePrintTupleFieldsToStrings() to be defined by -// induction on the number of tuple fields. The idea is that -// TuplePrefixPrinter<N>::PrintPrefixTo(t, os) prints the first N -// fields in tuple t, and can be defined in terms of -// TuplePrefixPrinter<N - 1>. -// -// The inductive case. -template <size_t N> -struct TuplePrefixPrinter { - // Prints the first N fields of a tuple. - template <typename Tuple> - static void PrintPrefixTo(const Tuple& t, ::std::ostream* os) { - TuplePrefixPrinter<N - 1>::PrintPrefixTo(t, os); - GTEST_INTENTIONAL_CONST_COND_PUSH_() - if (N > 1) { - GTEST_INTENTIONAL_CONST_COND_POP_() - *os << ", "; - } - UniversalPrinter< - typename TuplePolicy<Tuple>::template tuple_element<N - 1>::type> - ::Print(TuplePolicy<Tuple>::template get<N - 1>(t), os); - } - // Tersely prints the first N fields of a tuple to a string vector, // one element for each field. - template <typename Tuple> - static void TersePrintPrefixToStrings(const Tuple& t, Strings* strings) { - TuplePrefixPrinter<N - 1>::TersePrintPrefixToStrings(t, strings); - ::std::stringstream ss; - UniversalTersePrint(TuplePolicy<Tuple>::template get<N - 1>(t), &ss); - strings->push_back(ss.str()); - } -}; - -// Base case. -template <> -struct TuplePrefixPrinter<0> { - template <typename Tuple> - static void PrintPrefixTo(const Tuple&, ::std::ostream*) {} - - template <typename Tuple> - static void TersePrintPrefixToStrings(const Tuple&, Strings*) {} -}; - -// Helper function for printing a tuple. -// Tuple must be either std::tr1::tuple or std::tuple type. template <typename Tuple> -void PrintTupleTo(const Tuple& t, ::std::ostream* os) { - *os << "("; - TuplePrefixPrinter<TuplePolicy<Tuple>::tuple_size>::PrintPrefixTo(t, os); - *os << ")"; +void TersePrintPrefixToStrings(const Tuple&, std::integral_constant<size_t, 0>, + Strings*) {} +template <typename Tuple, size_t I> +void TersePrintPrefixToStrings(const Tuple& t, + std::integral_constant<size_t, I>, + Strings* strings) { + TersePrintPrefixToStrings(t, std::integral_constant<size_t, I - 1>(), + strings); + ::std::stringstream ss; + UniversalTersePrint(std::get<I - 1>(t), &ss); + strings->push_back(ss.str()); } // Prints the fields of a tuple tersely to a string vector, one @@ -1072,11 +893,11 @@ void PrintTupleTo(const Tuple& t, ::std::ostream* os) { template <typename Tuple> Strings UniversalTersePrintTupleFieldsToStrings(const Tuple& value) { Strings result; - TuplePrefixPrinter<TuplePolicy<Tuple>::tuple_size>:: - TersePrintPrefixToStrings(value, &result); + TersePrintPrefixToStrings( + value, std::integral_constant<size_t, std::tuple_size<Tuple>::value>(), + &result); return result; } -#endif // GTEST_HAS_TR1_TUPLE || GTEST_HAS_STD_TUPLE_ } // namespace internal diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest-spi.h b/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest-spi.h index 1e8983938ea..aa38870e8e1 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest-spi.h +++ b/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest-spi.h @@ -72,14 +72,15 @@ class GTEST_API_ ScopedFakeTestPartResultReporter TestPartResultArray* result); // The d'tor restores the previous test part result reporter. - virtual ~ScopedFakeTestPartResultReporter(); + ~ScopedFakeTestPartResultReporter() override; // Appends the TestPartResult object to the TestPartResultArray // received in the constructor. // // This method is from the TestPartResultReporterInterface // interface. - virtual void ReportTestPartResult(const TestPartResult& result); + void ReportTestPartResult(const TestPartResult& result) override; + private: void Init(); diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest-test-part.h b/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest-test-part.h index 1c7b89e0879..05a79853586 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest-test-part.h +++ b/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest-test-part.h @@ -53,22 +53,20 @@ class GTEST_API_ TestPartResult { enum Type { kSuccess, // Succeeded. kNonFatalFailure, // Failed but the test can continue. - kFatalFailure // Failed and the test should be terminated. + kFatalFailure, // Failed and the test should be terminated. + kSkip // Skipped. }; // C'tor. TestPartResult does NOT have a default constructor. // Always use this constructor (with parameters) to create a // TestPartResult object. - TestPartResult(Type a_type, - const char* a_file_name, - int a_line_number, + TestPartResult(Type a_type, const char* a_file_name, int a_line_number, const char* a_message) : type_(a_type), - file_name_(a_file_name == NULL ? "" : a_file_name), + file_name_(a_file_name == nullptr ? "" : a_file_name), line_number_(a_line_number), summary_(ExtractSummary(a_message)), - message_(a_message) { - } + message_(a_message) {} // Gets the outcome of the test part. Type type() const { return type_; } @@ -76,7 +74,7 @@ class GTEST_API_ TestPartResult { // Gets the name of the source file where the test part took place, or // NULL if it's unknown. const char* file_name() const { - return file_name_.empty() ? NULL : file_name_.c_str(); + return file_name_.empty() ? nullptr : file_name_.c_str(); } // Gets the line in the source file where the test part took place, @@ -89,18 +87,21 @@ class GTEST_API_ TestPartResult { // Gets the message associated with the test part. const char* message() const { return message_.c_str(); } - // Returns true iff the test part passed. - bool passed() const { return type_ == kSuccess; } + // Returns true if and only if the test part was skipped. + bool skipped() const { return type_ == kSkip; } - // Returns true iff the test part failed. - bool failed() const { return type_ != kSuccess; } + // Returns true if and only if the test part passed. + bool passed() const { return type_ == kSuccess; } - // Returns true iff the test part non-fatally failed. + // Returns true if and only if the test part non-fatally failed. bool nonfatally_failed() const { return type_ == kNonFatalFailure; } - // Returns true iff the test part fatally failed. + // Returns true if and only if the test part fatally failed. bool fatally_failed() const { return type_ == kFatalFailure; } + // Returns true if and only if the test part failed. + bool failed() const { return fatally_failed() || nonfatally_failed(); } + private: Type type_; @@ -164,8 +165,8 @@ class GTEST_API_ HasNewFatalFailureHelper : public TestPartResultReporterInterface { public: HasNewFatalFailureHelper(); - virtual ~HasNewFatalFailureHelper(); - virtual void ReportTestPartResult(const TestPartResult& result); + ~HasNewFatalFailureHelper() override; + void ReportTestPartResult(const TestPartResult& result) override; bool has_new_fatal_failure() const { return has_new_fatal_failure_; } private: bool has_new_fatal_failure_; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest-typed-test.h b/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest-typed-test.h index 74bce46bdc5..095ce058022 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest-typed-test.h +++ b/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest-typed-test.h @@ -52,22 +52,22 @@ class FooTest : public testing::Test { T value_; }; -// Next, associate a list of types with the test case, which will be +// Next, associate a list of types with the test suite, which will be // repeated for each type in the list. The typedef is necessary for // the macro to parse correctly. typedef testing::Types<char, int, unsigned int> MyTypes; -TYPED_TEST_CASE(FooTest, MyTypes); +TYPED_TEST_SUITE(FooTest, MyTypes); // If the type list contains only one type, you can write that type // directly without Types<...>: -// TYPED_TEST_CASE(FooTest, int); +// TYPED_TEST_SUITE(FooTest, int); // Then, use TYPED_TEST() instead of TEST_F() to define as many typed -// tests for this test case as you want. +// tests for this test suite as you want. TYPED_TEST(FooTest, DoesBlah) { - // Inside a test, refer to TypeParam to get the type parameter. - // Since we are inside a derived class template, C++ requires use to - // visit the members of FooTest via 'this'. + // Inside a test, refer to the special name TypeParam to get the type + // parameter. Since we are inside a derived class template, C++ requires + // us to visit the members of FooTest via 'this'. TypeParam n = this->value_; // To visit static members of the fixture, add the TestFixture:: @@ -83,7 +83,7 @@ TYPED_TEST(FooTest, DoesBlah) { TYPED_TEST(FooTest, HasPropertyA) { ... } -// TYPED_TEST_CASE takes an optional third argument which allows to specify a +// TYPED_TEST_SUITE takes an optional third argument which allows to specify a // class that generates custom test name suffixes based on the type. This should // be a class which has a static template function GetName(int index) returning // a string for each type. The provided integer index equals the index of the @@ -99,7 +99,7 @@ TYPED_TEST(FooTest, HasPropertyA) { ... } // if (std::is_same<T, unsigned int>()) return "unsignedInt"; // } // }; -// TYPED_TEST_CASE(FooTest, MyTypes, MyTypeNames); +// TYPED_TEST_SUITE(FooTest, MyTypes, MyTypeNames); #endif // 0 @@ -126,13 +126,13 @@ class FooTest : public testing::Test { ... }; -// Next, declare that you will define a type-parameterized test case +// Next, declare that you will define a type-parameterized test suite // (the _P suffix is for "parameterized" or "pattern", whichever you // prefer): -TYPED_TEST_CASE_P(FooTest); +TYPED_TEST_SUITE_P(FooTest); // Then, use TYPED_TEST_P() to define as many type-parameterized tests -// for this type-parameterized test case as you want. +// for this type-parameterized test suite as you want. TYPED_TEST_P(FooTest, DoesBlah) { // Inside a test, refer to TypeParam to get the type parameter. TypeParam n = 0; @@ -143,10 +143,10 @@ TYPED_TEST_P(FooTest, HasPropertyA) { ... } // Now the tricky part: you need to register all test patterns before // you can instantiate them. The first argument of the macro is the -// test case name; the rest are the names of the tests in this test +// test suite name; the rest are the names of the tests in this test // case. -REGISTER_TYPED_TEST_CASE_P(FooTest, - DoesBlah, HasPropertyA); +REGISTER_TYPED_TEST_SUITE_P(FooTest, + DoesBlah, HasPropertyA); // Finally, you are free to instantiate the pattern with the types you // want. If you put the above code in a header file, you can #include @@ -154,19 +154,19 @@ REGISTER_TYPED_TEST_CASE_P(FooTest, // // To distinguish different instances of the pattern, the first // argument to the INSTANTIATE_* macro is a prefix that will be added -// to the actual test case name. Remember to pick unique prefixes for +// to the actual test suite name. Remember to pick unique prefixes for // different instances. typedef testing::Types<char, int, unsigned int> MyTypes; -INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes); +INSTANTIATE_TYPED_TEST_SUITE_P(My, FooTest, MyTypes); // If the type list contains only one type, you can write that type // directly without Types<...>: -// INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, int); +// INSTANTIATE_TYPED_TEST_SUITE_P(My, FooTest, int); // -// Similar to the optional argument of TYPED_TEST_CASE above, -// INSTANTIATE_TEST_CASE_P takes an optional fourth argument which allows to +// Similar to the optional argument of TYPED_TEST_SUITE above, +// INSTANTIATE_TEST_SUITE_P takes an optional fourth argument which allows to // generate custom names. -// INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes, MyTypeNames); +// INSTANTIATE_TYPED_TEST_SUITE_P(My, FooTest, MyTypes, MyTypeNames); #endif // 0 @@ -180,21 +180,18 @@ INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes); // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Expands to the name of the typedef for the type parameters of the -// given test case. -# define GTEST_TYPE_PARAMS_(TestCaseName) gtest_type_params_##TestCaseName##_ +// given test suite. +#define GTEST_TYPE_PARAMS_(TestSuiteName) gtest_type_params_##TestSuiteName##_ // Expands to the name of the typedef for the NameGenerator, responsible for // creating the suffixes of the name. -#define GTEST_NAME_GENERATOR_(TestCaseName) \ - gtest_type_params_##TestCaseName##_NameGenerator - -// The 'Types' template argument below must have spaces around it -// since some compilers may choke on '>>' when passing a template -// instance (e.g. Types<int>) -# define TYPED_TEST_CASE(CaseName, Types, ...) \ - typedef ::testing::internal::TypeList< Types >::type GTEST_TYPE_PARAMS_( \ - CaseName); \ - typedef ::testing::internal::NameGeneratorSelector<__VA_ARGS__>::type \ +#define GTEST_NAME_GENERATOR_(TestSuiteName) \ + gtest_type_params_##TestSuiteName##_NameGenerator + +#define TYPED_TEST_SUITE(CaseName, Types, ...) \ + typedef ::testing::internal::TypeList<Types>::type GTEST_TYPE_PARAMS_( \ + CaseName); \ + typedef ::testing::internal::NameGeneratorSelector<__VA_ARGS__>::type \ GTEST_NAME_GENERATOR_(CaseName) # define TYPED_TEST(CaseName, TestName) \ @@ -224,6 +221,13 @@ INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes); void GTEST_TEST_CLASS_NAME_(CaseName, \ TestName)<gtest_TypeParam_>::TestBody() +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +#define TYPED_TEST_CASE \ + static_assert(::testing::internal::TypedTestCaseIsDeprecated(), ""); \ + TYPED_TEST_SUITE +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + #endif // GTEST_HAS_TYPED_TEST // Implements type-parameterized tests. @@ -233,73 +237,93 @@ INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes); // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Expands to the namespace name that the type-parameterized tests for -// the given type-parameterized test case are defined in. The exact +// the given type-parameterized test suite are defined in. The exact // name of the namespace is subject to change without notice. -# define GTEST_CASE_NAMESPACE_(TestCaseName) \ - gtest_case_##TestCaseName##_ +#define GTEST_SUITE_NAMESPACE_(TestSuiteName) gtest_suite_##TestSuiteName##_ // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Expands to the name of the variable used to remember the names of -// the defined tests in the given test case. -# define GTEST_TYPED_TEST_CASE_P_STATE_(TestCaseName) \ - gtest_typed_test_case_p_state_##TestCaseName##_ +// the defined tests in the given test suite. +#define GTEST_TYPED_TEST_SUITE_P_STATE_(TestSuiteName) \ + gtest_typed_test_suite_p_state_##TestSuiteName##_ // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE DIRECTLY. // // Expands to the name of the variable used to remember the names of -// the registered tests in the given test case. -# define GTEST_REGISTERED_TEST_NAMES_(TestCaseName) \ - gtest_registered_test_names_##TestCaseName##_ +// the registered tests in the given test suite. +#define GTEST_REGISTERED_TEST_NAMES_(TestSuiteName) \ + gtest_registered_test_names_##TestSuiteName##_ // The variables defined in the type-parameterized test macros are // static as typically these macros are used in a .h file that can be // #included in multiple translation units linked together. -# define TYPED_TEST_CASE_P(CaseName) \ - static ::testing::internal::TypedTestCasePState \ - GTEST_TYPED_TEST_CASE_P_STATE_(CaseName) - -# define TYPED_TEST_P(CaseName, TestName) \ - namespace GTEST_CASE_NAMESPACE_(CaseName) { \ - template <typename gtest_TypeParam_> \ - class TestName : public CaseName<gtest_TypeParam_> { \ - private: \ - typedef CaseName<gtest_TypeParam_> TestFixture; \ - typedef gtest_TypeParam_ TypeParam; \ - virtual void TestBody(); \ - }; \ - static bool gtest_##TestName##_defined_ GTEST_ATTRIBUTE_UNUSED_ = \ - GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).AddTestName(\ - __FILE__, __LINE__, #CaseName, #TestName); \ - } \ - template <typename gtest_TypeParam_> \ - void GTEST_CASE_NAMESPACE_(CaseName)::TestName<gtest_TypeParam_>::TestBody() - -# define REGISTER_TYPED_TEST_CASE_P(CaseName, ...) \ - namespace GTEST_CASE_NAMESPACE_(CaseName) { \ - typedef ::testing::internal::Templates<__VA_ARGS__>::type gtest_AllTests_; \ - } \ - static const char* const GTEST_REGISTERED_TEST_NAMES_(CaseName) \ - GTEST_ATTRIBUTE_UNUSED_ = \ - GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).VerifyRegisteredTestNames( \ - __FILE__, __LINE__, #__VA_ARGS__) - -// The 'Types' template argument below must have spaces around it -// since some compilers may choke on '>>' when passing a template -// instance (e.g. Types<int>) -# define INSTANTIATE_TYPED_TEST_CASE_P(Prefix, CaseName, Types, ...) \ - static bool gtest_##Prefix##_##CaseName GTEST_ATTRIBUTE_UNUSED_ = \ - ::testing::internal::TypeParameterizedTestCase< \ - CaseName, GTEST_CASE_NAMESPACE_(CaseName)::gtest_AllTests_, \ - ::testing::internal::TypeList< Types >::type>:: \ - Register(#Prefix, \ - ::testing::internal::CodeLocation(__FILE__, __LINE__), \ - >EST_TYPED_TEST_CASE_P_STATE_(CaseName), #CaseName, \ - GTEST_REGISTERED_TEST_NAMES_(CaseName), \ - ::testing::internal::GenerateNames< \ - ::testing::internal::NameGeneratorSelector< \ - __VA_ARGS__>::type, \ - ::testing::internal::TypeList< Types >::type>()) +#define TYPED_TEST_SUITE_P(SuiteName) \ + static ::testing::internal::TypedTestSuitePState \ + GTEST_TYPED_TEST_SUITE_P_STATE_(SuiteName) + +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +#define TYPED_TEST_CASE_P \ + static_assert(::testing::internal::TypedTestCase_P_IsDeprecated(), ""); \ + TYPED_TEST_SUITE_P +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + +#define TYPED_TEST_P(SuiteName, TestName) \ + namespace GTEST_SUITE_NAMESPACE_(SuiteName) { \ + template <typename gtest_TypeParam_> \ + class TestName : public SuiteName<gtest_TypeParam_> { \ + private: \ + typedef SuiteName<gtest_TypeParam_> TestFixture; \ + typedef gtest_TypeParam_ TypeParam; \ + virtual void TestBody(); \ + }; \ + static bool gtest_##TestName##_defined_ GTEST_ATTRIBUTE_UNUSED_ = \ + GTEST_TYPED_TEST_SUITE_P_STATE_(SuiteName).AddTestName( \ + __FILE__, __LINE__, #SuiteName, #TestName); \ + } \ + template <typename gtest_TypeParam_> \ + void GTEST_SUITE_NAMESPACE_( \ + SuiteName)::TestName<gtest_TypeParam_>::TestBody() + +#define REGISTER_TYPED_TEST_SUITE_P(SuiteName, ...) \ + namespace GTEST_SUITE_NAMESPACE_(SuiteName) { \ + typedef ::testing::internal::Templates<__VA_ARGS__>::type gtest_AllTests_; \ + } \ + static const char* const GTEST_REGISTERED_TEST_NAMES_( \ + SuiteName) GTEST_ATTRIBUTE_UNUSED_ = \ + GTEST_TYPED_TEST_SUITE_P_STATE_(SuiteName).VerifyRegisteredTestNames( \ + __FILE__, __LINE__, #__VA_ARGS__) + +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +#define REGISTER_TYPED_TEST_CASE_P \ + static_assert(::testing::internal::RegisterTypedTestCase_P_IsDeprecated(), \ + ""); \ + REGISTER_TYPED_TEST_SUITE_P +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + +#define INSTANTIATE_TYPED_TEST_SUITE_P(Prefix, SuiteName, Types, ...) \ + static bool gtest_##Prefix##_##SuiteName GTEST_ATTRIBUTE_UNUSED_ = \ + ::testing::internal::TypeParameterizedTestSuite< \ + SuiteName, GTEST_SUITE_NAMESPACE_(SuiteName)::gtest_AllTests_, \ + ::testing::internal::TypeList<Types>::type>:: \ + Register(#Prefix, \ + ::testing::internal::CodeLocation(__FILE__, __LINE__), \ + >EST_TYPED_TEST_SUITE_P_STATE_(SuiteName), #SuiteName, \ + GTEST_REGISTERED_TEST_NAMES_(SuiteName), \ + ::testing::internal::GenerateNames< \ + ::testing::internal::NameGeneratorSelector< \ + __VA_ARGS__>::type, \ + ::testing::internal::TypeList<Types>::type>()) + +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +#define INSTANTIATE_TYPED_TEST_CASE_P \ + static_assert( \ + ::testing::internal::InstantiateTypedTestCase_P_IsDeprecated(), ""); \ + INSTANTIATE_TYPED_TEST_SUITE_P +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ #endif // GTEST_HAS_TYPED_TEST_P diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest.h b/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest.h index 5df4b0a3a71..dbe5b1c2c3f 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest.h +++ b/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest.h @@ -52,13 +52,17 @@ #ifndef GTEST_INCLUDE_GTEST_GTEST_H_ #define GTEST_INCLUDE_GTEST_GTEST_H_ +#include <cstddef> #include <limits> +#include <memory> #include <ostream> +#include <type_traits> #include <vector> #include "gtest/internal/gtest-internal.h" #include "gtest/internal/gtest-string.h" #include "gtest/gtest-death-test.h" +#include "gtest/gtest-matchers.h" #include "gtest/gtest-message.h" #include "gtest/gtest-param-test.h" #include "gtest/gtest-printers.h" @@ -69,21 +73,6 @@ GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ /* class A needs to have dll-interface to be used by clients of class B */) -// Depending on the platform, different string classes are available. -// On Linux, in addition to ::std::string, Google also makes use of -// class ::string, which has the same interface as ::std::string, but -// has a different implementation. -// -// You can define GTEST_HAS_GLOBAL_STRING to 1 to indicate that -// ::string is available AND is a distinct type to ::std::string, or -// define it to 0 to indicate otherwise. -// -// If ::std::string and ::string are the same class on your platform -// due to aliasing, you should define GTEST_HAS_GLOBAL_STRING to 0. -// -// If you do not define GTEST_HAS_GLOBAL_STRING, it is defined -// heuristically. - namespace testing { // Silence C4100 (unreferenced formal parameter) and 4805 @@ -195,7 +184,12 @@ void ReportFailureInUnknownLocation(TestPartResult::Type result_type, // If we don't forward declare them the compiler might confuse the classes // in friendship clauses with same named classes on the scope. class Test; -class TestCase; +class TestSuite; + +// Old API is still available but deprecated +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +using TestCase = TestSuite; +#endif class TestInfo; class UnitTest; @@ -298,9 +292,10 @@ class GTEST_API_ AssertionResult { template <typename T> explicit AssertionResult( const T& success, - typename internal::EnableIf< - !internal::ImplicitlyConvertible<T, AssertionResult>::value>::type* - /*enabler*/ = NULL) + typename std::enable_if< + !std::is_convertible<T, AssertionResult>::value>::type* + /*enabler*/ + = nullptr) : success_(success) {} #if defined(_MSC_VER) && _MSC_VER < 1910 @@ -313,7 +308,7 @@ class GTEST_API_ AssertionResult { return *this; } - // Returns true iff the assertion succeeded. + // Returns true if and only if the assertion succeeded. operator bool() const { return success_; } // NOLINT // Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE. @@ -324,9 +319,8 @@ class GTEST_API_ AssertionResult { // assertion's expectation). When nothing has been streamed into the // object, returns an empty string. const char* message() const { - return message_.get() != NULL ? message_->c_str() : ""; + return message_.get() != nullptr ? message_->c_str() : ""; } - // FIXME: Remove this after making sure no clients use it. // Deprecated; please use message() instead. const char* failure_message() const { return message(); } @@ -347,8 +341,7 @@ class GTEST_API_ AssertionResult { private: // Appends the contents of message to message_. void AppendMessage(const Message& a_message) { - if (message_.get() == NULL) - message_.reset(new ::std::string); + if (message_.get() == nullptr) message_.reset(new ::std::string); message_->append(a_message.GetString().c_str()); } @@ -361,7 +354,7 @@ class GTEST_API_ AssertionResult { // construct is not satisfied with the predicate's outcome. // Referenced via a pointer to avoid taking too much stack frame space // with test assertions. - internal::scoped_ptr< ::std::string> message_; + std::unique_ptr< ::std::string> message_; }; // Makes a successful assertion result. @@ -385,8 +378,8 @@ namespace testing { // The abstract class that all tests inherit from. // -// In Google Test, a unit test program contains one or many TestCases, and -// each TestCase contains one or many Tests. +// In Google Test, a unit test program contains one or many TestSuites, and +// each TestSuite contains one or many Tests. // // When you define a test using the TEST macro, you don't need to // explicitly derive from Test - the TEST macro automatically does @@ -410,49 +403,57 @@ class GTEST_API_ Test { public: friend class TestInfo; - // Defines types for pointers to functions that set up and tear down - // a test case. - typedef internal::SetUpTestCaseFunc SetUpTestCaseFunc; - typedef internal::TearDownTestCaseFunc TearDownTestCaseFunc; - // The d'tor is virtual as we intend to inherit from Test. virtual ~Test(); // Sets up the stuff shared by all tests in this test case. // - // Google Test will call Foo::SetUpTestCase() before running the first + // Google Test will call Foo::SetUpTestSuite() before running the first // test in test case Foo. Hence a sub-class can define its own - // SetUpTestCase() method to shadow the one defined in the super + // SetUpTestSuite() method to shadow the one defined in the super // class. - static void SetUpTestCase() {} + // Failures that happen during SetUpTestSuite are logged but otherwise + // ignored. + static void SetUpTestSuite() {} - // Tears down the stuff shared by all tests in this test case. + // Tears down the stuff shared by all tests in this test suite. // - // Google Test will call Foo::TearDownTestCase() after running the last + // Google Test will call Foo::TearDownTestSuite() after running the last // test in test case Foo. Hence a sub-class can define its own - // TearDownTestCase() method to shadow the one defined in the super + // TearDownTestSuite() method to shadow the one defined in the super // class. + // Failures that happen during TearDownTestSuite are logged but otherwise + // ignored. + static void TearDownTestSuite() {} + + // Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ static void TearDownTestCase() {} + static void SetUpTestCase() {} +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ - // Returns true iff the current test has a fatal failure. + // Returns true if and only if the current test has a fatal failure. static bool HasFatalFailure(); - // Returns true iff the current test has a non-fatal failure. + // Returns true if and only if the current test has a non-fatal failure. static bool HasNonfatalFailure(); - // Returns true iff the current test has a (either fatal or + // Returns true if and only if the current test was skipped. + static bool IsSkipped(); + + // Returns true if and only if the current test has a (either fatal or // non-fatal) failure. static bool HasFailure() { return HasFatalFailure() || HasNonfatalFailure(); } - // Logs a property for the current test, test case, or for the entire + // Logs a property for the current test, test suite, or for the entire // invocation of the test program when used outside of the context of a - // test case. Only the last value for a given key is remembered. These + // test suite. Only the last value for a given key is remembered. These // are public static so they can be called from utility functions that are // not members of the test fixture. Calls to RecordProperty made during // lifespan of the test (from the moment its constructor starts to the // moment its destructor finishes) will be output in XML as attributes of // the <testcase> element. Properties recorded from fixture's - // SetUpTestCase or TearDownTestCase are logged as attributes of the + // SetUpTestSuite or TearDownTestSuite are logged as attributes of the // corresponding <testsuite> element. Calls to RecordProperty made in the // global context (before or after invocation of RUN_ALL_TESTS and from // SetUp/TearDown method of Environment objects registered with Google @@ -471,8 +472,8 @@ class GTEST_API_ Test { virtual void TearDown(); private: - // Returns true iff the current test has the same fixture class as - // the first test in the current test case. + // Returns true if and only if the current test has the same fixture class + // as the first test in the current test suite. static bool HasSameFixtureClass(); // Runs the test after the test fixture has been set up. @@ -490,7 +491,7 @@ class GTEST_API_ Test { // internal method to avoid clashing with names used in user TESTs. void DeleteSelf_() { delete this; } - const internal::scoped_ptr< GTEST_FLAG_SAVER_ > gtest_flag_saver_; + const std::unique_ptr<GTEST_FLAG_SAVER_> gtest_flag_saver_; // Often a user misspells SetUp() as Setup() and spends a long time // wondering why it is never called by Google Test. The declaration of @@ -509,7 +510,7 @@ class GTEST_API_ Test { // If you see an error about overriding the following function or // about it being private, you have mis-spelled SetUp() as Setup(). struct Setup_should_be_spelled_SetUp {}; - virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; } + virtual Setup_should_be_spelled_SetUp* Setup() { return nullptr; } // We disallow copying Tests. GTEST_DISALLOW_COPY_AND_ASSIGN_(Test); @@ -573,21 +574,28 @@ class GTEST_API_ TestResult { // Returns the number of the test properties. int test_property_count() const; - // Returns true iff the test passed (i.e. no test part failed). - bool Passed() const { return !Failed(); } + // Returns true if and only if the test passed (i.e. no test part failed). + bool Passed() const { return !Skipped() && !Failed(); } + + // Returns true if and only if the test was skipped. + bool Skipped() const; - // Returns true iff the test failed. + // Returns true if and only if the test failed. bool Failed() const; - // Returns true iff the test fatally failed. + // Returns true if and only if the test fatally failed. bool HasFatalFailure() const; - // Returns true iff the test has a non-fatal failure. + // Returns true if and only if the test has a non-fatal failure. bool HasNonfatalFailure() const; // Returns the elapsed time, in milliseconds. TimeInMillis elapsed_time() const { return elapsed_time_; } + // Gets the time of the test case start, in ms from the start of the + // UNIX epoch. + TimeInMillis start_timestamp() const { return start_timestamp_; } + // Returns the i-th test part result among all the results. i can range from 0 // to total_part_count() - 1. If i is not in that range, aborts the program. const TestPartResult& GetTestPartResult(int i) const; @@ -599,7 +607,7 @@ class GTEST_API_ TestResult { private: friend class TestInfo; - friend class TestCase; + friend class TestSuite; friend class UnitTest; friend class internal::DefaultGlobalTestPartResultReporter; friend class internal::ExecDeathTest; @@ -618,6 +626,9 @@ class GTEST_API_ TestResult { return test_properties_; } + // Sets the start time. + void set_start_timestamp(TimeInMillis start) { start_timestamp_ = start; } + // Sets the elapsed time. void set_elapsed_time(TimeInMillis elapsed) { elapsed_time_ = elapsed; } @@ -631,7 +642,7 @@ class GTEST_API_ TestResult { const TestProperty& test_property); // Adds a failure if the key is a reserved attribute of Google Test - // testcase tags. Returns true if the property is valid. + // testsuite tags. Returns true if the property is valid. // FIXME: Validate attribute names are legal and human readable. static bool ValidateTestProperty(const std::string& xml_element, const TestProperty& test_property); @@ -661,6 +672,8 @@ class GTEST_API_ TestResult { std::vector<TestProperty> test_properties_; // Running count of death tests. int death_test_count_; + // The start time, in milliseconds since UNIX Epoch. + TimeInMillis start_timestamp_; // The elapsed time, in milliseconds. TimeInMillis elapsed_time_; @@ -670,7 +683,7 @@ class GTEST_API_ TestResult { // A TestInfo object stores the following information about a test: // -// Test case name +// Test suite name // Test name // Whether the test should be run // A function pointer that creates the test object when invoked @@ -685,8 +698,13 @@ class GTEST_API_ TestInfo { // don't inherit from TestInfo. ~TestInfo(); - // Returns the test case name. - const char* test_case_name() const { return test_case_name_.c_str(); } + // Returns the test suite name. + const char* test_suite_name() const { return test_suite_name_.c_str(); } + +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + const char* test_case_name() const { return test_suite_name(); } +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ // Returns the test name. const char* name() const { return name_.c_str(); } @@ -694,17 +712,15 @@ class GTEST_API_ TestInfo { // Returns the name of the parameter type, or NULL if this is not a typed // or a type-parameterized test. const char* type_param() const { - if (type_param_.get() != NULL) - return type_param_->c_str(); - return NULL; + if (type_param_.get() != nullptr) return type_param_->c_str(); + return nullptr; } // Returns the text representation of the value parameter, or NULL if this // is not a value-parameterized test. const char* value_param() const { - if (value_param_.get() != NULL) - return value_param_->c_str(); - return NULL; + if (value_param_.get() != nullptr) return value_param_->c_str(); + return nullptr; } // Returns the file name where this test is defined. @@ -721,7 +737,7 @@ class GTEST_API_ TestInfo { // been specified) and its full name matches the user-specified filter. // // Google Test allows the user to filter the tests by their full names. - // The full name of a test Bar in test case Foo is defined as + // The full name of a test Bar in test suite Foo is defined as // "Foo.Bar". Only the tests that match the filter will run. // // A filter is a colon-separated list of glob (not regex) patterns, @@ -734,7 +750,7 @@ class GTEST_API_ TestInfo { // contains the character 'A' or starts with "Foo.". bool should_run() const { return should_run_; } - // Returns true iff this test will appear in the XML report. + // Returns true if and only if this test will appear in the XML report. bool is_reportable() const { // The XML report includes tests matching the filter, excluding those // run in other shards. @@ -749,24 +765,19 @@ class GTEST_API_ TestInfo { friend class internal::DefaultDeathTestFactory; #endif // GTEST_HAS_DEATH_TEST friend class Test; - friend class TestCase; + friend class TestSuite; friend class internal::UnitTestImpl; friend class internal::StreamingListenerTest; friend TestInfo* internal::MakeAndRegisterTestInfo( - const char* test_case_name, - const char* name, - const char* type_param, - const char* value_param, - internal::CodeLocation code_location, - internal::TypeId fixture_class_id, - Test::SetUpTestCaseFunc set_up_tc, - Test::TearDownTestCaseFunc tear_down_tc, + const char* test_suite_name, const char* name, const char* type_param, + const char* value_param, internal::CodeLocation code_location, + internal::TypeId fixture_class_id, internal::SetUpTestSuiteFunc set_up_tc, + internal::TearDownTestSuiteFunc tear_down_tc, internal::TestFactoryBase* factory); // Constructs a TestInfo object. The newly constructed instance assumes // ownership of the factory object. - TestInfo(const std::string& test_case_name, - const std::string& name, + TestInfo(const std::string& test_suite_name, const std::string& name, const char* a_type_param, // NULL if not a type-parameterized test const char* a_value_param, // NULL if not a value-parameterized test internal::CodeLocation a_code_location, @@ -788,21 +799,21 @@ class GTEST_API_ TestInfo { } // These fields are immutable properties of the test. - const std::string test_case_name_; // Test case name + const std::string test_suite_name_; // test suite name const std::string name_; // Test name // Name of the parameter type, or NULL if this is not a typed or a // type-parameterized test. - const internal::scoped_ptr<const ::std::string> type_param_; + const std::unique_ptr<const ::std::string> type_param_; // Text representation of the value parameter, or NULL if this is not a // value-parameterized test. - const internal::scoped_ptr<const ::std::string> value_param_; + const std::unique_ptr<const ::std::string> value_param_; internal::CodeLocation location_; - const internal::TypeId fixture_class_id_; // ID of the test fixture class - bool should_run_; // True iff this test should run - bool is_disabled_; // True iff this test is disabled - bool matches_filter_; // True if this test matches the - // user-specified filter. - bool is_in_another_shard_; // Will be run in another shard. + const internal::TypeId fixture_class_id_; // ID of the test fixture class + bool should_run_; // True if and only if this test should run + bool is_disabled_; // True if and only if this test is disabled + bool matches_filter_; // True if this test matches the + // user-specified filter. + bool is_in_another_shard_; // Will be run in another shard. internal::TestFactoryBase* const factory_; // The factory that creates // the test object @@ -813,90 +824,96 @@ class GTEST_API_ TestInfo { GTEST_DISALLOW_COPY_AND_ASSIGN_(TestInfo); }; -// A test case, which consists of a vector of TestInfos. +// A test suite, which consists of a vector of TestInfos. // -// TestCase is not copyable. -class GTEST_API_ TestCase { +// TestSuite is not copyable. +class GTEST_API_ TestSuite { public: - // Creates a TestCase with the given name. + // Creates a TestSuite with the given name. // - // TestCase does NOT have a default constructor. Always use this - // constructor to create a TestCase object. + // TestSuite does NOT have a default constructor. Always use this + // constructor to create a TestSuite object. // // Arguments: // - // name: name of the test case + // name: name of the test suite // a_type_param: the name of the test's type parameter, or NULL if // this is not a type-parameterized test. - // set_up_tc: pointer to the function that sets up the test case - // tear_down_tc: pointer to the function that tears down the test case - TestCase(const char* name, const char* a_type_param, - Test::SetUpTestCaseFunc set_up_tc, - Test::TearDownTestCaseFunc tear_down_tc); + // set_up_tc: pointer to the function that sets up the test suite + // tear_down_tc: pointer to the function that tears down the test suite + TestSuite(const char* name, const char* a_type_param, + internal::SetUpTestSuiteFunc set_up_tc, + internal::TearDownTestSuiteFunc tear_down_tc); - // Destructor of TestCase. - virtual ~TestCase(); + // Destructor of TestSuite. + virtual ~TestSuite(); - // Gets the name of the TestCase. + // Gets the name of the TestSuite. const char* name() const { return name_.c_str(); } // Returns the name of the parameter type, or NULL if this is not a - // type-parameterized test case. + // type-parameterized test suite. const char* type_param() const { - if (type_param_.get() != NULL) - return type_param_->c_str(); - return NULL; + if (type_param_.get() != nullptr) return type_param_->c_str(); + return nullptr; } - // Returns true if any test in this test case should run. + // Returns true if any test in this test suite should run. bool should_run() const { return should_run_; } - // Gets the number of successful tests in this test case. + // Gets the number of successful tests in this test suite. int successful_test_count() const; - // Gets the number of failed tests in this test case. + // Gets the number of skipped tests in this test suite. + int skipped_test_count() const; + + // Gets the number of failed tests in this test suite. int failed_test_count() const; // Gets the number of disabled tests that will be reported in the XML report. int reportable_disabled_test_count() const; - // Gets the number of disabled tests in this test case. + // Gets the number of disabled tests in this test suite. int disabled_test_count() const; // Gets the number of tests to be printed in the XML report. int reportable_test_count() const; - // Get the number of tests in this test case that should run. + // Get the number of tests in this test suite that should run. int test_to_run_count() const; - // Gets the number of all tests in this test case. + // Gets the number of all tests in this test suite. int total_test_count() const; - // Returns true iff the test case passed. + // Returns true if and only if the test suite passed. bool Passed() const { return !Failed(); } - // Returns true iff the test case failed. + // Returns true if and only if the test suite failed. bool Failed() const { return failed_test_count() > 0; } // Returns the elapsed time, in milliseconds. TimeInMillis elapsed_time() const { return elapsed_time_; } + // Gets the time of the test suite start, in ms from the start of the + // UNIX epoch. + TimeInMillis start_timestamp() const { return start_timestamp_; } + // Returns the i-th test among all the tests. i can range from 0 to // total_test_count() - 1. If i is not in that range, returns NULL. const TestInfo* GetTestInfo(int i) const; // Returns the TestResult that holds test properties recorded during - // execution of SetUpTestCase and TearDownTestCase. + // execution of SetUpTestSuite and TearDownTestSuite. const TestResult& ad_hoc_test_result() const { return ad_hoc_test_result_; } private: friend class Test; friend class internal::UnitTestImpl; - // Gets the (mutable) vector of TestInfos in this TestCase. + // Gets the (mutable) vector of TestInfos in this TestSuite. std::vector<TestInfo*>& test_info_list() { return test_info_list_; } - // Gets the (immutable) vector of TestInfos in this TestCase. + // Gets the (immutable) vector of TestInfos in this TestSuite. const std::vector<TestInfo*>& test_info_list() const { return test_info_list_; } @@ -908,51 +925,64 @@ class GTEST_API_ TestCase { // Sets the should_run member. void set_should_run(bool should) { should_run_ = should; } - // Adds a TestInfo to this test case. Will delete the TestInfo upon - // destruction of the TestCase object. + // Adds a TestInfo to this test suite. Will delete the TestInfo upon + // destruction of the TestSuite object. void AddTestInfo(TestInfo * test_info); - // Clears the results of all tests in this test case. + // Clears the results of all tests in this test suite. void ClearResult(); - // Clears the results of all tests in the given test case. - static void ClearTestCaseResult(TestCase* test_case) { - test_case->ClearResult(); + // Clears the results of all tests in the given test suite. + static void ClearTestSuiteResult(TestSuite* test_suite) { + test_suite->ClearResult(); } - // Runs every test in this TestCase. + // Runs every test in this TestSuite. void Run(); - // Runs SetUpTestCase() for this TestCase. This wrapper is needed - // for catching exceptions thrown from SetUpTestCase(). - void RunSetUpTestCase() { (*set_up_tc_)(); } + // Runs SetUpTestSuite() for this TestSuite. This wrapper is needed + // for catching exceptions thrown from SetUpTestSuite(). + void RunSetUpTestSuite() { + if (set_up_tc_ != nullptr) { + (*set_up_tc_)(); + } + } - // Runs TearDownTestCase() for this TestCase. This wrapper is - // needed for catching exceptions thrown from TearDownTestCase(). - void RunTearDownTestCase() { (*tear_down_tc_)(); } + // Runs TearDownTestSuite() for this TestSuite. This wrapper is + // needed for catching exceptions thrown from TearDownTestSuite(). + void RunTearDownTestSuite() { + if (tear_down_tc_ != nullptr) { + (*tear_down_tc_)(); + } + } - // Returns true iff test passed. + // Returns true if and only if test passed. static bool TestPassed(const TestInfo* test_info) { return test_info->should_run() && test_info->result()->Passed(); } - // Returns true iff test failed. + // Returns true if and only if test skipped. + static bool TestSkipped(const TestInfo* test_info) { + return test_info->should_run() && test_info->result()->Skipped(); + } + + // Returns true if and only if test failed. static bool TestFailed(const TestInfo* test_info) { return test_info->should_run() && test_info->result()->Failed(); } - // Returns true iff the test is disabled and will be reported in the XML - // report. + // Returns true if and only if the test is disabled and will be reported in + // the XML report. static bool TestReportableDisabled(const TestInfo* test_info) { return test_info->is_reportable() && test_info->is_disabled_; } - // Returns true iff test is disabled. + // Returns true if and only if test is disabled. static bool TestDisabled(const TestInfo* test_info) { return test_info->is_disabled_; } - // Returns true iff this test will appear in the XML report. + // Returns true if and only if this test will appear in the XML report. static bool TestReportable(const TestInfo* test_info) { return test_info->is_reportable(); } @@ -962,17 +992,17 @@ class GTEST_API_ TestCase { return test_info->should_run(); } - // Shuffles the tests in this test case. + // Shuffles the tests in this test suite. void ShuffleTests(internal::Random* random); // Restores the test order to before the first shuffle. void UnshuffleTests(); - // Name of the test case. + // Name of the test suite. std::string name_; // Name of the parameter type, or NULL if this is not a typed or a // type-parameterized test. - const internal::scoped_ptr<const ::std::string> type_param_; + const std::unique_ptr<const ::std::string> type_param_; // The vector of TestInfos in their original order. It owns the // elements in the vector. std::vector<TestInfo*> test_info_list_; @@ -980,20 +1010,22 @@ class GTEST_API_ TestCase { // shuffling and restoring the test order. The i-th element in this // vector is the index of the i-th test in the shuffled test list. std::vector<int> test_indices_; - // Pointer to the function that sets up the test case. - Test::SetUpTestCaseFunc set_up_tc_; - // Pointer to the function that tears down the test case. - Test::TearDownTestCaseFunc tear_down_tc_; - // True iff any test in this test case should run. + // Pointer to the function that sets up the test suite. + internal::SetUpTestSuiteFunc set_up_tc_; + // Pointer to the function that tears down the test suite. + internal::TearDownTestSuiteFunc tear_down_tc_; + // True if and only if any test in this test suite should run. bool should_run_; + // The start time, in milliseconds since UNIX Epoch. + TimeInMillis start_timestamp_; // Elapsed time, in milliseconds. TimeInMillis elapsed_time_; - // Holds test properties recorded during execution of SetUpTestCase and - // TearDownTestCase. + // Holds test properties recorded during execution of SetUpTestSuite and + // TearDownTestSuite. TestResult ad_hoc_test_result_; - // We disallow copying TestCases. - GTEST_DISALLOW_COPY_AND_ASSIGN_(TestCase); + // We disallow copying TestSuites. + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestSuite); }; // An Environment object is capable of setting up and tearing down an @@ -1024,7 +1056,7 @@ class Environment { // If you see an error about overriding the following function or // about it being private, you have mis-spelled SetUp() as Setup(). struct Setup_should_be_spelled_SetUp {}; - virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; } + virtual Setup_should_be_spelled_SetUp* Setup() { return nullptr; } }; #if GTEST_HAS_EXCEPTIONS @@ -1060,8 +1092,13 @@ class TestEventListener { // Fired after environment set-up for each iteration of tests ends. virtual void OnEnvironmentsSetUpEnd(const UnitTest& unit_test) = 0; - // Fired before the test case starts. - virtual void OnTestCaseStart(const TestCase& test_case) = 0; + // Fired before the test suite starts. + virtual void OnTestSuiteStart(const TestSuite& /*test_suite*/) {} + + // Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + virtual void OnTestCaseStart(const TestCase& /*test_case*/) {} +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ // Fired before the test starts. virtual void OnTestStart(const TestInfo& test_info) = 0; @@ -1074,8 +1111,13 @@ class TestEventListener { // Fired after the test ends. virtual void OnTestEnd(const TestInfo& test_info) = 0; - // Fired after the test case ends. - virtual void OnTestCaseEnd(const TestCase& test_case) = 0; + // Fired after the test suite ends. + virtual void OnTestSuiteEnd(const TestSuite& /*test_suite*/) {} + +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + virtual void OnTestCaseEnd(const TestCase& /*test_case*/) {} +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ // Fired before environment tear-down for each iteration of tests starts. virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test) = 0; @@ -1098,21 +1140,30 @@ class TestEventListener { // above. class EmptyTestEventListener : public TestEventListener { public: - virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {} - virtual void OnTestIterationStart(const UnitTest& /*unit_test*/, - int /*iteration*/) {} - virtual void OnEnvironmentsSetUpStart(const UnitTest& /*unit_test*/) {} - virtual void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) {} - virtual void OnTestCaseStart(const TestCase& /*test_case*/) {} - virtual void OnTestStart(const TestInfo& /*test_info*/) {} - virtual void OnTestPartResult(const TestPartResult& /*test_part_result*/) {} - virtual void OnTestEnd(const TestInfo& /*test_info*/) {} - virtual void OnTestCaseEnd(const TestCase& /*test_case*/) {} - virtual void OnEnvironmentsTearDownStart(const UnitTest& /*unit_test*/) {} - virtual void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) {} - virtual void OnTestIterationEnd(const UnitTest& /*unit_test*/, - int /*iteration*/) {} - virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) {} + void OnTestProgramStart(const UnitTest& /*unit_test*/) override {} + void OnTestIterationStart(const UnitTest& /*unit_test*/, + int /*iteration*/) override {} + void OnEnvironmentsSetUpStart(const UnitTest& /*unit_test*/) override {} + void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) override {} + void OnTestSuiteStart(const TestSuite& /*test_suite*/) override {} +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + void OnTestCaseStart(const TestCase& /*test_case*/) override {} +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + + void OnTestStart(const TestInfo& /*test_info*/) override {} + void OnTestPartResult(const TestPartResult& /*test_part_result*/) override {} + void OnTestEnd(const TestInfo& /*test_info*/) override {} + void OnTestSuiteEnd(const TestSuite& /*test_suite*/) override {} +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + void OnTestCaseEnd(const TestCase& /*test_case*/) override {} +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + + void OnEnvironmentsTearDownStart(const UnitTest& /*unit_test*/) override {} + void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) override {} + void OnTestIterationEnd(const UnitTest& /*unit_test*/, + int /*iteration*/) override {} + void OnTestProgramEnd(const UnitTest& /*unit_test*/) override {} }; // TestEventListeners lets users add listeners to track events in Google Test. @@ -1152,7 +1203,7 @@ class GTEST_API_ TestEventListeners { } private: - friend class TestCase; + friend class TestSuite; friend class TestInfo; friend class internal::DefaultGlobalTestPartResultReporter; friend class internal::NoExecDeathTest; @@ -1193,7 +1244,7 @@ class GTEST_API_ TestEventListeners { GTEST_DISALLOW_COPY_AND_ASSIGN_(TestEventListeners); }; -// A UnitTest consists of a vector of TestCases. +// A UnitTest consists of a vector of TestSuites. // // This is a singleton class. The only instance of UnitTest is // created when UnitTest::GetInstance() is first called. This @@ -1222,10 +1273,14 @@ class GTEST_API_ UnitTest { // was executed. The UnitTest object owns the string. const char* original_working_dir() const; - // Returns the TestCase object for the test that's currently running, + // Returns the TestSuite object for the test that's currently running, // or NULL if no test is running. - const TestCase* current_test_case() const - GTEST_LOCK_EXCLUDED_(mutex_); + const TestSuite* current_test_suite() const GTEST_LOCK_EXCLUDED_(mutex_); + +// Legacy API is still available but deprecated +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + const TestCase* current_test_case() const GTEST_LOCK_EXCLUDED_(mutex_); +#endif // Returns the TestInfo object for the test that's currently running, // or NULL if no test is running. @@ -1235,29 +1290,40 @@ class GTEST_API_ UnitTest { // Returns the random seed used at the start of the current test run. int random_seed() const; - // Returns the ParameterizedTestCaseRegistry object used to keep track of + // Returns the ParameterizedTestSuiteRegistry object used to keep track of // value-parameterized tests and instantiate and register them. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. - internal::ParameterizedTestCaseRegistry& parameterized_test_registry() + internal::ParameterizedTestSuiteRegistry& parameterized_test_registry() GTEST_LOCK_EXCLUDED_(mutex_); - // Gets the number of successful test cases. - int successful_test_case_count() const; + // Gets the number of successful test suites. + int successful_test_suite_count() const; - // Gets the number of failed test cases. - int failed_test_case_count() const; + // Gets the number of failed test suites. + int failed_test_suite_count() const; - // Gets the number of all test cases. - int total_test_case_count() const; + // Gets the number of all test suites. + int total_test_suite_count() const; - // Gets the number of all test cases that contain at least one test + // Gets the number of all test suites that contain at least one test // that should run. + int test_suite_to_run_count() const; + + // Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + int successful_test_case_count() const; + int failed_test_case_count() const; + int total_test_case_count() const; int test_case_to_run_count() const; +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ // Gets the number of successful tests. int successful_test_count() const; + // Gets the number of skipped tests. + int skipped_test_count() const; + // Gets the number of failed tests. int failed_test_count() const; @@ -1283,19 +1349,25 @@ class GTEST_API_ UnitTest { // Gets the elapsed time, in milliseconds. TimeInMillis elapsed_time() const; - // Returns true iff the unit test passed (i.e. all test cases passed). + // Returns true if and only if the unit test passed (i.e. all test suites + // passed). bool Passed() const; - // Returns true iff the unit test failed (i.e. some test case failed - // or something outside of all tests failed). + // Returns true if and only if the unit test failed (i.e. some test suite + // failed or something outside of all tests failed). bool Failed() const; - // Gets the i-th test case among all the test cases. i can range from 0 to - // total_test_case_count() - 1. If i is not in that range, returns NULL. + // Gets the i-th test suite among all the test suites. i can range from 0 to + // total_test_suite_count() - 1. If i is not in that range, returns NULL. + const TestSuite* GetTestSuite(int i) const; + +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ const TestCase* GetTestCase(int i) const; +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ // Returns the TestResult containing information on test failures and - // properties logged outside of individual test cases. + // properties logged outside of individual test suites. const TestResult& ad_hoc_test_result() const; // Returns the list of event listeners that can be used to track events @@ -1326,15 +1398,15 @@ class GTEST_API_ UnitTest { GTEST_LOCK_EXCLUDED_(mutex_); // Adds a TestProperty to the current TestResult object when invoked from - // inside a test, to current TestCase's ad_hoc_test_result_ when invoked - // from SetUpTestCase or TearDownTestCase, or to the global property set + // inside a test, to current TestSuite's ad_hoc_test_result_ when invoked + // from SetUpTestSuite or TearDownTestSuite, or to the global property set // when invoked elsewhere. If the result already contains a property with // the same key, the value will be updated. void RecordProperty(const std::string& key, const std::string& value); - // Gets the i-th test case among all the test cases. i can range from 0 to - // total_test_case_count() - 1. If i is not in that range, returns NULL. - TestCase* GetMutableTestCase(int i); + // Gets the i-th test suite among all the test suites. i can range from 0 to + // total_test_suite_count() - 1. If i is not in that range, returns NULL. + TestSuite* GetMutableTestSuite(int i); // Accessors for the implementation object. internal::UnitTestImpl* impl() { return impl_; } @@ -1419,6 +1491,10 @@ GTEST_API_ void InitGoogleTest(int* argc, char** argv); // UNICODE mode. GTEST_API_ void InitGoogleTest(int* argc, wchar_t** argv); +// This overloaded version can be used on Arduino/embedded platforms where +// there is no argc/argv. +GTEST_API_ void InitGoogleTest(); + namespace internal { // Separate the error generating code from the code path to reduce the stack @@ -1435,6 +1511,13 @@ AssertionResult CmpHelperEQFailure(const char* lhs_expression, false); } +// This block of code defines operator==/!= +// to block lexical scope lookup. +// It prevents using invalid operator==/!= defined at namespace scope. +struct faketype {}; +inline bool operator==(faketype, faketype) { return true; } +inline bool operator!=(faketype, faketype) { return false; } + // The helper function for {ASSERT|EXPECT}_EQ. template <typename T1, typename T2> AssertionResult CmpHelperEQ(const char* lhs_expression, @@ -1456,18 +1539,17 @@ GTEST_API_ AssertionResult CmpHelperEQ(const char* lhs_expression, BiggestInt lhs, BiggestInt rhs); -// The helper class for {ASSERT|EXPECT}_EQ. The template argument -// lhs_is_null_literal is true iff the first argument to ASSERT_EQ() -// is a null pointer literal. The following default implementation is -// for lhs_is_null_literal being false. -template <bool lhs_is_null_literal> class EqHelper { public: // This templatized version is for the general case. - template <typename T1, typename T2> + template < + typename T1, typename T2, + // Disable this overload for cases where one argument is a pointer + // and the other is the null pointer constant. + typename std::enable_if<!std::is_integral<T1>::value || + !std::is_pointer<T2>::value>::type* = nullptr> static AssertionResult Compare(const char* lhs_expression, - const char* rhs_expression, - const T1& lhs, + const char* rhs_expression, const T1& lhs, const T2& rhs) { return CmpHelperEQ(lhs_expression, rhs_expression, lhs, rhs); } @@ -1484,49 +1566,15 @@ class EqHelper { BiggestInt rhs) { return CmpHelperEQ(lhs_expression, rhs_expression, lhs, rhs); } -}; -// This specialization is used when the first argument to ASSERT_EQ() -// is a null pointer literal, like NULL, false, or 0. -template <> -class EqHelper<true> { - public: - // We define two overloaded versions of Compare(). The first - // version will be picked when the second argument to ASSERT_EQ() is - // NOT a pointer, e.g. ASSERT_EQ(0, AnIntFunction()) or - // EXPECT_EQ(false, a_bool). - template <typename T1, typename T2> - static AssertionResult Compare( - const char* lhs_expression, - const char* rhs_expression, - const T1& lhs, - const T2& rhs, - // The following line prevents this overload from being considered if T2 - // is not a pointer type. We need this because ASSERT_EQ(NULL, my_ptr) - // expands to Compare("", "", NULL, my_ptr), which requires a conversion - // to match the Secret* in the other overload, which would otherwise make - // this template match better. - typename EnableIf<!is_pointer<T2>::value>::type* = 0) { - return CmpHelperEQ(lhs_expression, rhs_expression, lhs, rhs); - } - - // This version will be picked when the second argument to ASSERT_EQ() is a - // pointer, e.g. ASSERT_EQ(NULL, a_pointer). template <typename T> static AssertionResult Compare( - const char* lhs_expression, - const char* rhs_expression, - // We used to have a second template parameter instead of Secret*. That - // template parameter would deduce to 'long', making this a better match - // than the first overload even without the first overload's EnableIf. - // Unfortunately, gcc with -Wconversion-null warns when "passing NULL to - // non-pointer argument" (even a deduced integral argument), so the old - // implementation caused warnings in user code. - Secret* /* lhs (NULL) */, - T* rhs) { + const char* lhs_expression, const char* rhs_expression, + // Handle cases where '0' is used as a null pointer literal. + std::nullptr_t /* lhs */, T* rhs) { // We already know that 'lhs' is a null pointer. - return CmpHelperEQ(lhs_expression, rhs_expression, - static_cast<T*>(NULL), rhs); + return CmpHelperEQ(lhs_expression, rhs_expression, static_cast<T*>(nullptr), + rhs); } }; @@ -1755,6 +1803,12 @@ class GTEST_API_ AssertHelper { GTEST_DISALLOW_COPY_AND_ASSIGN_(AssertHelper); }; +enum GTestColor { COLOR_DEFAULT, COLOR_RED, COLOR_GREEN, COLOR_YELLOW }; + +GTEST_API_ GTEST_ATTRIBUTE_PRINTF_(2, 3) void ColoredPrintf(GTestColor color, + const char* fmt, + ...); + } // namespace internal // The pure interface class that all value-parameterized tests inherit from. @@ -1774,13 +1828,13 @@ class GTEST_API_ AssertHelper { // FooTest() { // // Can use GetParam() here. // } -// virtual ~FooTest() { +// ~FooTest() override { // // Can use GetParam() here. // } -// virtual void SetUp() { +// void SetUp() override { // // Can use GetParam() here. // } -// virtual void TearDown { +// void TearDown override { // // Can use GetParam() here. // } // }; @@ -1789,7 +1843,7 @@ class GTEST_API_ AssertHelper { // Foo foo; // ASSERT_TRUE(foo.DoesBar(GetParam())); // } -// INSTANTIATE_TEST_CASE_P(OneToTenRange, FooTest, ::testing::Range(1, 10)); +// INSTANTIATE_TEST_SUITE_P(OneToTenRange, FooTest, ::testing::Range(1, 10)); template <typename T> class WithParamInterface { @@ -1798,12 +1852,9 @@ class WithParamInterface { virtual ~WithParamInterface() {} // The current parameter value. Is also available in the test fixture's - // constructor. This member function is non-static, even though it only - // references static data, to reduce the opportunity for incorrect uses - // like writing 'WithParamInterface<bool>::GetParam()' for a test that - // uses a fixture whose parameter type is int. - const ParamType& GetParam() const { - GTEST_CHECK_(parameter_ != NULL) + // constructor. + static const ParamType& GetParam() { + GTEST_CHECK_(parameter_ != nullptr) << "GetParam() can only be called inside a value-parameterized test " << "-- did you intend to write TEST_P instead of TEST_F?"; return *parameter_; @@ -1824,7 +1875,7 @@ class WithParamInterface { }; template <typename T> -const T* WithParamInterface<T>::parameter_ = NULL; +const T* WithParamInterface<T>::parameter_ = nullptr; // Most value-parameterized classes can ignore the existence of // WithParamInterface, and can just inherit from ::testing::TestWithParam. @@ -1835,6 +1886,11 @@ class TestWithParam : public Test, public WithParamInterface<T> { // Macros for indicating success/failure in test code. +// Skips test in runtime. +// Skipping test aborts current function. +// Skipped tests are neither successful nor failed. +#define GTEST_SKIP() GTEST_SKIP_("Skipped") + // ADD_FAILURE unconditionally adds a failure to the current test. // SUCCEED generates a success - it doesn't automatically make the // current test successful, as a test is only successful when it has @@ -1864,6 +1920,11 @@ class TestWithParam : public Test, public WithParamInterface<T> { // Generates a fatal failure with a generic message. #define GTEST_FAIL() GTEST_FATAL_FAILURE_("Failed") +// Like GTEST_FAIL(), but at the given source file location. +#define GTEST_FAIL_AT(file, line) \ + GTEST_MESSAGE_AT_(file, line, "Failed", \ + ::testing::TestPartResult::kFatalFailure) + // Define this macro to 1 to omit the definition of FAIL(), which is a // generic name and clashes with some other libraries. #if !GTEST_DONT_DEFINE_FAIL @@ -1964,9 +2025,7 @@ class TestWithParam : public Test, public WithParamInterface<T> { // ASSERT_GT(records.size(), 0) << "There is no record left."; #define EXPECT_EQ(val1, val2) \ - EXPECT_PRED_FORMAT2(::testing::internal:: \ - EqHelper<GTEST_IS_NULL_LITERAL_(val1)>::Compare, \ - val1, val2) + EXPECT_PRED_FORMAT2(::testing::internal::EqHelper::Compare, val1, val2) #define EXPECT_NE(val1, val2) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperNE, val1, val2) #define EXPECT_LE(val1, val2) \ @@ -1979,9 +2038,7 @@ class TestWithParam : public Test, public WithParamInterface<T> { EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2) #define GTEST_ASSERT_EQ(val1, val2) \ - ASSERT_PRED_FORMAT2(::testing::internal:: \ - EqHelper<GTEST_IS_NULL_LITERAL_(val1)>::Compare, \ - val1, val2) + ASSERT_PRED_FORMAT2(::testing::internal::EqHelper::Compare, val1, val2) #define GTEST_ASSERT_NE(val1, val2) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperNE, val1, val2) #define GTEST_ASSERT_LE(val1, val2) \ @@ -2172,12 +2229,6 @@ class GTEST_API_ ScopedTrace { PushTrace(file, line, message ? message : "(null)"); } -#if GTEST_HAS_GLOBAL_STRING - ScopedTrace(const char* file, int line, const ::string& message) { - PushTrace(file, line, message); - } -#endif - ScopedTrace(const char* file, int line, const std::string& message) { PushTrace(file, line, message); } @@ -2215,10 +2266,9 @@ class GTEST_API_ ScopedTrace { ::testing::ScopedTrace GTEST_CONCAT_TOKEN_(gtest_trace_, __LINE__)(\ __FILE__, __LINE__, (message)) - // Compile-time assertion for type equality. -// StaticAssertTypeEq<type1, type2>() compiles iff type1 and type2 are -// the same type. The value it returns is not interesting. +// StaticAssertTypeEq<type1, type2>() compiles if and only if type1 and type2 +// are the same type. The value it returns is not interesting. // // Instead of making StaticAssertTypeEq a class template, we make it a // function template that invokes a helper class template. This @@ -2247,18 +2297,19 @@ class GTEST_API_ ScopedTrace { // // to cause a compiler error. template <typename T1, typename T2> -bool StaticAssertTypeEq() { - (void)internal::StaticAssertTypeEqHelper<T1, T2>(); +constexpr bool StaticAssertTypeEq() noexcept { + static_assert(std::is_same<T1, T2>::value, + "type1 and type2 are not the same type"); return true; } // Defines a test. // -// The first parameter is the name of the test case, and the second -// parameter is the name of the test within the test case. +// The first parameter is the name of the test suite, and the second +// parameter is the name of the test within the test suite. // -// The convention is to end the test case name with "Test". For -// example, a test case for the Foo class can be named FooTest. +// The convention is to end the test suite name with "Test". For +// example, a test suite for the Foo class can be named FooTest. // // Test code should appear between braces after an invocation of // this macro. Example: @@ -2277,28 +2328,28 @@ bool StaticAssertTypeEq() { // code. GetTestTypeId() is guaranteed to always return the same // value, as it always calls GetTypeId<>() from the Google Test // framework. -#define GTEST_TEST(test_case_name, test_name)\ - GTEST_TEST_(test_case_name, test_name, \ - ::testing::Test, ::testing::internal::GetTestTypeId()) +#define GTEST_TEST(test_suite_name, test_name) \ + GTEST_TEST_(test_suite_name, test_name, ::testing::Test, \ + ::testing::internal::GetTestTypeId()) // Define this macro to 1 to omit the definition of TEST(), which // is a generic name and clashes with some other libraries. #if !GTEST_DONT_DEFINE_TEST -# define TEST(test_case_name, test_name) GTEST_TEST(test_case_name, test_name) +#define TEST(test_suite_name, test_name) GTEST_TEST(test_suite_name, test_name) #endif // Defines a test that uses a test fixture. // // The first parameter is the name of the test fixture class, which -// also doubles as the test case name. The second parameter is the -// name of the test within the test case. +// also doubles as the test suite name. The second parameter is the +// name of the test within the test suite. // // A test fixture class must be declared earlier. The user should put // the test code between braces after using this macro. Example: // // class FooTest : public testing::Test { // protected: -// virtual void SetUp() { b_.AddElement(3); } +// void SetUp() override { b_.AddElement(3); } // // Foo a_; // Foo b_; @@ -2312,7 +2363,8 @@ bool StaticAssertTypeEq() { // EXPECT_EQ(a_.size(), 0); // EXPECT_EQ(b_.size(), 1); // } - +// +// GOOGLETEST_CM0011 DO NOT DELETE #define TEST_F(test_fixture, test_name)\ GTEST_TEST_(test_fixture, test_name, test_fixture, \ ::testing::internal::GetTypeId<test_fixture>()) @@ -2325,6 +2377,86 @@ GTEST_API_ std::string TempDir(); # pragma warning(pop) #endif +// Dynamically registers a test with the framework. +// +// This is an advanced API only to be used when the `TEST` macros are +// insufficient. The macros should be preferred when possible, as they avoid +// most of the complexity of calling this function. +// +// The `factory` argument is a factory callable (move-constructible) object or +// function pointer that creates a new instance of the Test object. It +// handles ownership to the caller. The signature of the callable is +// `Fixture*()`, where `Fixture` is the test fixture class for the test. All +// tests registered with the same `test_suite_name` must return the same +// fixture type. This is checked at runtime. +// +// The framework will infer the fixture class from the factory and will call +// the `SetUpTestSuite` and `TearDownTestSuite` for it. +// +// Must be called before `RUN_ALL_TESTS()` is invoked, otherwise behavior is +// undefined. +// +// Use case example: +// +// class MyFixture : public ::testing::Test { +// public: +// // All of these optional, just like in regular macro usage. +// static void SetUpTestSuite() { ... } +// static void TearDownTestSuite() { ... } +// void SetUp() override { ... } +// void TearDown() override { ... } +// }; +// +// class MyTest : public MyFixture { +// public: +// explicit MyTest(int data) : data_(data) {} +// void TestBody() override { ... } +// +// private: +// int data_; +// }; +// +// void RegisterMyTests(const std::vector<int>& values) { +// for (int v : values) { +// ::testing::RegisterTest( +// "MyFixture", ("Test" + std::to_string(v)).c_str(), nullptr, +// std::to_string(v).c_str(), +// __FILE__, __LINE__, +// // Important to use the fixture type as the return type here. +// [=]() -> MyFixture* { return new MyTest(v); }); +// } +// } +// ... +// int main(int argc, char** argv) { +// std::vector<int> values_to_test = LoadValuesFromConfig(); +// RegisterMyTests(values_to_test); +// ... +// return RUN_ALL_TESTS(); +// } +// +template <int&... ExplicitParameterBarrier, typename Factory> +TestInfo* RegisterTest(const char* test_suite_name, const char* test_name, + const char* type_param, const char* value_param, + const char* file, int line, Factory factory) { + using TestT = typename std::remove_pointer<decltype(factory())>::type; + + class FactoryImpl : public internal::TestFactoryBase { + public: + explicit FactoryImpl(Factory f) : factory_(std::move(f)) {} + Test* CreateTest() override { return factory_(); } + + private: + Factory factory_; + }; + + return internal::MakeAndRegisterTestInfo( + test_suite_name, test_name, type_param, value_param, + internal::CodeLocation(file, line), internal::GetTypeId<TestT>(), + internal::SuiteApiResolver<TestT>::GetSetUpCaseOrSuite(file, line), + internal::SuiteApiResolver<TestT>::GetTearDownCaseOrSuite(file, line), + new FactoryImpl{std::move(factory)}); +} + } // namespace testing // Use this function in main() to run all tests. It returns 0 if all diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest_pred_impl.h b/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest_pred_impl.h index 0c1105cb8eb..d514255c733 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest_pred_impl.h +++ b/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest_pred_impl.h @@ -27,11 +27,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// This file is AUTOMATICALLY GENERATED on 01/02/2018 by command +// This file is AUTOMATICALLY GENERATED on 01/02/2019 by command // 'gen_gtest_pred_impl.py 5'. DO NOT EDIT BY HAND! // // Implements a family of generic predicate assertion macros. - // GOOGLETEST_CM0001 DO NOT DELETE #ifndef GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ @@ -67,6 +66,8 @@ namespace testing { // We also define the EXPECT_* variations. // // For now we only support predicates whose arity is at most 5. +// Please email googletestframework@googlegroups.com if you need +// support for higher arities. // GTEST_ASSERT_ is the basic statement to which all of the assertions // in this file reduce. Don't use this in your code. @@ -89,9 +90,10 @@ AssertionResult AssertPred1Helper(const char* pred_text, const T1& v1) { if (pred(v1)) return AssertionSuccess(); - return AssertionFailure() << pred_text << "(" - << e1 << ") evaluates to false, where" - << "\n" << e1 << " evaluates to " << v1; + return AssertionFailure() + << pred_text << "(" << e1 << ") evaluates to false, where" + << "\n" + << e1 << " evaluates to " << ::testing::PrintToString(v1); } // Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT1. @@ -133,11 +135,12 @@ AssertionResult AssertPred2Helper(const char* pred_text, const T2& v2) { if (pred(v1, v2)) return AssertionSuccess(); - return AssertionFailure() << pred_text << "(" - << e1 << ", " - << e2 << ") evaluates to false, where" - << "\n" << e1 << " evaluates to " << v1 - << "\n" << e2 << " evaluates to " << v2; + return AssertionFailure() + << pred_text << "(" << e1 << ", " << e2 + << ") evaluates to false, where" + << "\n" + << e1 << " evaluates to " << ::testing::PrintToString(v1) << "\n" + << e2 << " evaluates to " << ::testing::PrintToString(v2); } // Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT2. @@ -184,13 +187,13 @@ AssertionResult AssertPred3Helper(const char* pred_text, const T3& v3) { if (pred(v1, v2, v3)) return AssertionSuccess(); - return AssertionFailure() << pred_text << "(" - << e1 << ", " - << e2 << ", " - << e3 << ") evaluates to false, where" - << "\n" << e1 << " evaluates to " << v1 - << "\n" << e2 << " evaluates to " << v2 - << "\n" << e3 << " evaluates to " << v3; + return AssertionFailure() + << pred_text << "(" << e1 << ", " << e2 << ", " << e3 + << ") evaluates to false, where" + << "\n" + << e1 << " evaluates to " << ::testing::PrintToString(v1) << "\n" + << e2 << " evaluates to " << ::testing::PrintToString(v2) << "\n" + << e3 << " evaluates to " << ::testing::PrintToString(v3); } // Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT3. @@ -242,15 +245,14 @@ AssertionResult AssertPred4Helper(const char* pred_text, const T4& v4) { if (pred(v1, v2, v3, v4)) return AssertionSuccess(); - return AssertionFailure() << pred_text << "(" - << e1 << ", " - << e2 << ", " - << e3 << ", " - << e4 << ") evaluates to false, where" - << "\n" << e1 << " evaluates to " << v1 - << "\n" << e2 << " evaluates to " << v2 - << "\n" << e3 << " evaluates to " << v3 - << "\n" << e4 << " evaluates to " << v4; + return AssertionFailure() + << pred_text << "(" << e1 << ", " << e2 << ", " << e3 << ", " << e4 + << ") evaluates to false, where" + << "\n" + << e1 << " evaluates to " << ::testing::PrintToString(v1) << "\n" + << e2 << " evaluates to " << ::testing::PrintToString(v2) << "\n" + << e3 << " evaluates to " << ::testing::PrintToString(v3) << "\n" + << e4 << " evaluates to " << ::testing::PrintToString(v4); } // Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT4. @@ -307,17 +309,15 @@ AssertionResult AssertPred5Helper(const char* pred_text, const T5& v5) { if (pred(v1, v2, v3, v4, v5)) return AssertionSuccess(); - return AssertionFailure() << pred_text << "(" - << e1 << ", " - << e2 << ", " - << e3 << ", " - << e4 << ", " - << e5 << ") evaluates to false, where" - << "\n" << e1 << " evaluates to " << v1 - << "\n" << e2 << " evaluates to " << v2 - << "\n" << e3 << " evaluates to " << v3 - << "\n" << e4 << " evaluates to " << v4 - << "\n" << e5 << " evaluates to " << v5; + return AssertionFailure() + << pred_text << "(" << e1 << ", " << e2 << ", " << e3 << ", " << e4 + << ", " << e5 << ") evaluates to false, where" + << "\n" + << e1 << " evaluates to " << ::testing::PrintToString(v1) << "\n" + << e2 << " evaluates to " << ::testing::PrintToString(v2) << "\n" + << e3 << " evaluates to " << ::testing::PrintToString(v3) << "\n" + << e4 << " evaluates to " << ::testing::PrintToString(v4) << "\n" + << e5 << " evaluates to " << ::testing::PrintToString(v5); } // Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT5. diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/internal/gtest-death-test-internal.h b/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/internal/gtest-death-test-internal.h index 0a9b42c8a57..68bd3530618 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/internal/gtest-death-test-internal.h +++ b/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/internal/gtest-death-test-internal.h @@ -36,9 +36,11 @@ #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ +#include "gtest/gtest-matchers.h" #include "gtest/internal/gtest-internal.h" #include <stdio.h> +#include <memory> namespace testing { namespace internal { @@ -78,7 +80,7 @@ class GTEST_API_ DeathTest { // argument is set. If the death test should be skipped, the pointer // is set to NULL; otherwise, it is set to the address of a new concrete // DeathTest object that controls the execution of the current test. - static bool Create(const char* statement, const RE* regex, + static bool Create(const char* statement, Matcher<const std::string&> matcher, const char* file, int line, DeathTest** test); DeathTest(); virtual ~DeathTest() { } @@ -144,21 +146,44 @@ GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 class DeathTestFactory { public: virtual ~DeathTestFactory() { } - virtual bool Create(const char* statement, const RE* regex, - const char* file, int line, DeathTest** test) = 0; + virtual bool Create(const char* statement, + Matcher<const std::string&> matcher, const char* file, + int line, DeathTest** test) = 0; }; // A concrete DeathTestFactory implementation for normal use. class DefaultDeathTestFactory : public DeathTestFactory { public: - virtual bool Create(const char* statement, const RE* regex, - const char* file, int line, DeathTest** test); + bool Create(const char* statement, Matcher<const std::string&> matcher, + const char* file, int line, DeathTest** test) override; }; // Returns true if exit_status describes a process that was terminated // by a signal, or exited normally with a nonzero exit code. GTEST_API_ bool ExitedUnsuccessfully(int exit_status); +// A string passed to EXPECT_DEATH (etc.) is caught by one of these overloads +// and interpreted as a regex (rather than an Eq matcher) for legacy +// compatibility. +inline Matcher<const ::std::string&> MakeDeathTestMatcher( + ::testing::internal::RE regex) { + return ContainsRegex(regex.pattern()); +} +inline Matcher<const ::std::string&> MakeDeathTestMatcher(const char* regex) { + return ContainsRegex(regex); +} +inline Matcher<const ::std::string&> MakeDeathTestMatcher( + const ::std::string& regex) { + return ContainsRegex(regex); +} + +// If a Matcher<const ::std::string&> is passed to EXPECT_DEATH (etc.), it's +// used directly. +inline Matcher<const ::std::string&> MakeDeathTestMatcher( + Matcher<const ::std::string&> matcher) { + return matcher; +} + // Traps C++ exceptions escaping statement and reports them as test // failures. Note that trapping SEH exceptions is not implemented here. # if GTEST_HAS_EXCEPTIONS @@ -186,38 +211,38 @@ GTEST_API_ bool ExitedUnsuccessfully(int exit_status); // This macro is for implementing ASSERT_DEATH*, EXPECT_DEATH*, // ASSERT_EXIT*, and EXPECT_EXIT*. -# define GTEST_DEATH_TEST_(statement, predicate, regex, fail) \ - GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ - if (::testing::internal::AlwaysTrue()) { \ - const ::testing::internal::RE& gtest_regex = (regex); \ - ::testing::internal::DeathTest* gtest_dt; \ - if (!::testing::internal::DeathTest::Create(#statement, >est_regex, \ - __FILE__, __LINE__, >est_dt)) { \ - goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \ - } \ - if (gtest_dt != NULL) { \ - ::testing::internal::scoped_ptr< ::testing::internal::DeathTest> \ - gtest_dt_ptr(gtest_dt); \ - switch (gtest_dt->AssumeRole()) { \ - case ::testing::internal::DeathTest::OVERSEE_TEST: \ - if (!gtest_dt->Passed(predicate(gtest_dt->Wait()))) { \ - goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \ - } \ - break; \ - case ::testing::internal::DeathTest::EXECUTE_TEST: { \ - ::testing::internal::DeathTest::ReturnSentinel \ - gtest_sentinel(gtest_dt); \ - GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, gtest_dt); \ - gtest_dt->Abort(::testing::internal::DeathTest::TEST_DID_NOT_DIE); \ - break; \ - } \ - default: \ - break; \ - } \ - } \ - } else \ - GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__): \ - fail(::testing::internal::DeathTest::LastMessage()) +#define GTEST_DEATH_TEST_(statement, predicate, regex_or_matcher, fail) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::AlwaysTrue()) { \ + ::testing::internal::DeathTest* gtest_dt; \ + if (!::testing::internal::DeathTest::Create( \ + #statement, \ + ::testing::internal::MakeDeathTestMatcher(regex_or_matcher), \ + __FILE__, __LINE__, >est_dt)) { \ + goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \ + } \ + if (gtest_dt != nullptr) { \ + std::unique_ptr< ::testing::internal::DeathTest> gtest_dt_ptr(gtest_dt); \ + switch (gtest_dt->AssumeRole()) { \ + case ::testing::internal::DeathTest::OVERSEE_TEST: \ + if (!gtest_dt->Passed(predicate(gtest_dt->Wait()))) { \ + goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \ + } \ + break; \ + case ::testing::internal::DeathTest::EXECUTE_TEST: { \ + ::testing::internal::DeathTest::ReturnSentinel gtest_sentinel( \ + gtest_dt); \ + GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, gtest_dt); \ + gtest_dt->Abort(::testing::internal::DeathTest::TEST_DID_NOT_DIE); \ + break; \ + } \ + default: \ + break; \ + } \ + } \ + } else \ + GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__) \ + : fail(::testing::internal::DeathTest::LastMessage()) // The symbol "fail" here expands to something into which a message // can be streamed. @@ -226,14 +251,13 @@ GTEST_API_ bool ExitedUnsuccessfully(int exit_status); // must accept a streamed message even though the message is never printed. // The regex object is not evaluated, but it is used to prevent "unused" // warnings and to avoid an expression that doesn't compile in debug mode. -#define GTEST_EXECUTE_STATEMENT_(statement, regex) \ - GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ - if (::testing::internal::AlwaysTrue()) { \ - GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ - } else if (!::testing::internal::AlwaysTrue()) { \ - const ::testing::internal::RE& gtest_regex = (regex); \ - static_cast<void>(gtest_regex); \ - } else \ +#define GTEST_EXECUTE_STATEMENT_(statement, regex_or_matcher) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::AlwaysTrue()) { \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + } else if (!::testing::internal::AlwaysTrue()) { \ + ::testing::internal::MakeDeathTestMatcher(regex_or_matcher); \ + } else \ ::testing::Message() // A class representing the parsed contents of the diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/internal/gtest-filepath.h b/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/internal/gtest-filepath.h index ae38d95bf84..c11b101516e 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/internal/gtest-filepath.h +++ b/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/internal/gtest-filepath.h @@ -110,7 +110,7 @@ class GTEST_API_ FilePath { const FilePath& base_name, const char* extension); - // Returns true iff the path is "". + // Returns true if and only if the path is "". bool IsEmpty() const { return pathname_.empty(); } // If input name has a trailing separator character, removes it and returns diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/internal/gtest-internal.h b/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/internal/gtest-internal.h index b762f61fc53..94c816a28bd 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/internal/gtest-internal.h +++ b/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/internal/gtest-internal.h @@ -58,6 +58,7 @@ #include <map> #include <set> #include <string> +#include <type_traits> #include <vector> #include "gtest/gtest-message.h" @@ -79,7 +80,6 @@ // Stringifies its argument. #define GTEST_STRINGIFY_(name) #name -class ProtocolMessage; namespace proto2 { class Message; } namespace testing { @@ -91,7 +91,7 @@ class Message; // Represents a failure message. class Test; // Represents a test. class TestInfo; // Information about a test. class TestPartResult; // Result of a test part. -class UnitTest; // A collection of test cases. +class UnitTest; // A collection of test suites. template <typename T> ::std::string PrintToString(const T& value); @@ -106,34 +106,22 @@ class UnitTestImpl; // Opaque implementation of UnitTest // stack trace. GTEST_API_ extern const char kStackTraceMarker[]; -// Two overloaded helpers for checking at compile time whether an -// expression is a null pointer literal (i.e. NULL or any 0-valued -// compile-time integral constant). Their return values have -// different sizes, so we can use sizeof() to test which version is -// picked by the compiler. These helpers have no implementations, as -// we only need their signatures. -// -// Given IsNullLiteralHelper(x), the compiler will pick the first -// version if x can be implicitly converted to Secret*, and pick the -// second version otherwise. Since Secret is a secret and incomplete -// type, the only expression a user can write that has type Secret* is -// a null pointer literal. Therefore, we know that x is a null -// pointer literal if and only if the first version is picked by the -// compiler. -char IsNullLiteralHelper(Secret* p); -char (&IsNullLiteralHelper(...))[2]; // NOLINT - -// A compile-time bool constant that is true if and only if x is a -// null pointer literal (i.e. NULL or any 0-valued compile-time -// integral constant). -#ifdef GTEST_ELLIPSIS_NEEDS_POD_ -// We lose support for NULL detection where the compiler doesn't like -// passing non-POD classes through ellipsis (...). -# define GTEST_IS_NULL_LITERAL_(x) false -#else -# define GTEST_IS_NULL_LITERAL_(x) \ - (sizeof(::testing::internal::IsNullLiteralHelper(x)) == 1) -#endif // GTEST_ELLIPSIS_NEEDS_POD_ +// An IgnoredValue object can be implicitly constructed from ANY value. +class IgnoredValue { + struct Sink {}; + public: + // This constructor template allows any value to be implicitly + // converted to IgnoredValue. The object has no data member and + // doesn't try to remember anything about the argument. We + // deliberately omit the 'explicit' keyword in order to allow the + // conversion to be implicit. + // Disable the conversion if T already has a magical conversion operator. + // Otherwise we get ambiguity. + template <typename T, + typename std::enable_if<!std::is_convertible<T, Sink>::value, + int>::type = 0> + IgnoredValue(const T& /* ignored */) {} // NOLINT(runtime/explicit) +}; // Appends the user-supplied message to the Google-Test-generated message. GTEST_API_ std::string AppendUserMessage( @@ -201,7 +189,7 @@ GTEST_API_ std::string DiffStrings(const std::string& left, // expected_value: "5" // actual_value: "6" // -// The ignoring_case parameter is true iff the assertion is a +// The ignoring_case parameter is true if and only if the assertion is a // *_STRCASEEQ*. When it's true, the string " (ignoring case)" will // be inserted into the message. GTEST_API_ AssertionResult EqFailure(const char* expected_expression, @@ -330,15 +318,15 @@ class FloatingPoint { // Returns the sign bit of this number. Bits sign_bit() const { return kSignBitMask & u_.bits_; } - // Returns true iff this is NAN (not a number). + // Returns true if and only if this is NAN (not a number). bool is_nan() const { // It's a NAN if the exponent bits are all ones and the fraction // bits are not entirely zeros. return (exponent_bits() == kExponentBitMask) && (fraction_bits() != 0); } - // Returns true iff this number is at most kMaxUlps ULP's away from - // rhs. In particular, this function: + // Returns true if and only if this number is at most kMaxUlps ULP's away + // from rhs. In particular, this function: // // - returns false if either number is (or both are) NAN. // - treats really large numbers as almost equal to infinity. @@ -409,7 +397,7 @@ typedef FloatingPoint<float> Float; typedef FloatingPoint<double> Double; // In order to catch the mistake of putting tests that use different -// test fixture classes in the same test case, we need to assign +// test fixture classes in the same test suite, we need to assign // unique IDs to fixture classes and compare them. The TypeId type is // used to hold such IDs. The user should treat TypeId as an opaque // type: the only operation allowed on TypeId values is to compare @@ -469,7 +457,7 @@ class TestFactoryBase { template <class TestClass> class TestFactoryImpl : public TestFactoryBase { public: - virtual Test* CreateTest() { return new TestClass; } + Test* CreateTest() override { return new TestClass; } }; #if GTEST_OS_WINDOWS @@ -485,9 +473,9 @@ GTEST_API_ AssertionResult IsHRESULTFailure(const char* expr, #endif // GTEST_OS_WINDOWS -// Types of SetUpTestCase() and TearDownTestCase() functions. -typedef void (*SetUpTestCaseFunc)(); -typedef void (*TearDownTestCaseFunc)(); +// Types of SetUpTestSuite() and TearDownTestSuite() functions. +using SetUpTestSuiteFunc = void (*)(); +using TearDownTestSuiteFunc = void (*)(); struct CodeLocation { CodeLocation(const std::string& a_file, int a_line) @@ -497,12 +485,64 @@ struct CodeLocation { int line; }; +// Helper to identify which setup function for TestCase / TestSuite to call. +// Only one function is allowed, either TestCase or TestSute but not both. + +// Utility functions to help SuiteApiResolver +using SetUpTearDownSuiteFuncType = void (*)(); + +inline SetUpTearDownSuiteFuncType GetNotDefaultOrNull( + SetUpTearDownSuiteFuncType a, SetUpTearDownSuiteFuncType def) { + return a == def ? nullptr : a; +} + +template <typename T> +// Note that SuiteApiResolver inherits from T because +// SetUpTestSuite()/TearDownTestSuite() could be protected. Ths way +// SuiteApiResolver can access them. +struct SuiteApiResolver : T { + // testing::Test is only forward declared at this point. So we make it a + // dependend class for the compiler to be OK with it. + using Test = + typename std::conditional<sizeof(T) != 0, ::testing::Test, void>::type; + + static SetUpTearDownSuiteFuncType GetSetUpCaseOrSuite(const char* filename, + int line_num) { + SetUpTearDownSuiteFuncType test_case_fp = + GetNotDefaultOrNull(&T::SetUpTestCase, &Test::SetUpTestCase); + SetUpTearDownSuiteFuncType test_suite_fp = + GetNotDefaultOrNull(&T::SetUpTestSuite, &Test::SetUpTestSuite); + + GTEST_CHECK_(!test_case_fp || !test_suite_fp) + << "Test can not provide both SetUpTestSuite and SetUpTestCase, please " + "make sure there is only one present at " + << filename << ":" << line_num; + + return test_case_fp != nullptr ? test_case_fp : test_suite_fp; + } + + static SetUpTearDownSuiteFuncType GetTearDownCaseOrSuite(const char* filename, + int line_num) { + SetUpTearDownSuiteFuncType test_case_fp = + GetNotDefaultOrNull(&T::TearDownTestCase, &Test::TearDownTestCase); + SetUpTearDownSuiteFuncType test_suite_fp = + GetNotDefaultOrNull(&T::TearDownTestSuite, &Test::TearDownTestSuite); + + GTEST_CHECK_(!test_case_fp || !test_suite_fp) + << "Test can not provide both TearDownTestSuite and TearDownTestCase," + " please make sure there is only one present at" + << filename << ":" << line_num; + + return test_case_fp != nullptr ? test_case_fp : test_suite_fp; + } +}; + // Creates a new TestInfo object and registers it with Google Test; // returns the created object. // // Arguments: // -// test_case_name: name of the test case +// test_suite_name: name of the test suite // name: name of the test // type_param the name of the test's type parameter, or NULL if // this is not a typed or a type-parameterized test. @@ -510,21 +550,16 @@ struct CodeLocation { // or NULL if this is not a type-parameterized test. // code_location: code location where the test is defined // fixture_class_id: ID of the test fixture class -// set_up_tc: pointer to the function that sets up the test case -// tear_down_tc: pointer to the function that tears down the test case +// set_up_tc: pointer to the function that sets up the test suite +// tear_down_tc: pointer to the function that tears down the test suite // factory: pointer to the factory that creates a test object. // The newly created TestInfo instance will assume // ownership of the factory object. GTEST_API_ TestInfo* MakeAndRegisterTestInfo( - const char* test_case_name, - const char* name, - const char* type_param, - const char* value_param, - CodeLocation code_location, - TypeId fixture_class_id, - SetUpTestCaseFunc set_up_tc, - TearDownTestCaseFunc tear_down_tc, - TestFactoryBase* factory); + const char* test_suite_name, const char* name, const char* type_param, + const char* value_param, CodeLocation code_location, + TypeId fixture_class_id, SetUpTestSuiteFunc set_up_tc, + TearDownTestSuiteFunc tear_down_tc, TestFactoryBase* factory); // If *pstr starts with the given prefix, modifies *pstr to be right // past the prefix and returns true; otherwise leaves *pstr unchanged @@ -536,19 +571,20 @@ GTEST_API_ bool SkipPrefix(const char* prefix, const char** pstr); GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ /* class A needs to have dll-interface to be used by clients of class B */) -// State of the definition of a type-parameterized test case. -class GTEST_API_ TypedTestCasePState { +// State of the definition of a type-parameterized test suite. +class GTEST_API_ TypedTestSuitePState { public: - TypedTestCasePState() : registered_(false) {} + TypedTestSuitePState() : registered_(false) {} // Adds the given test name to defined_test_names_ and return true - // if the test case hasn't been registered; otherwise aborts the + // if the test suite hasn't been registered; otherwise aborts the // program. bool AddTestName(const char* file, int line, const char* case_name, const char* test_name) { if (registered_) { - fprintf(stderr, "%s Test %s must be defined before " - "REGISTER_TYPED_TEST_CASE_P(%s, ...).\n", + fprintf(stderr, + "%s Test %s must be defined before " + "REGISTER_TYPED_TEST_SUITE_P(%s, ...).\n", FormatFileLocation(file, line).c_str(), test_name, case_name); fflush(stderr); posix::Abort(); @@ -581,14 +617,19 @@ class GTEST_API_ TypedTestCasePState { RegisteredTestsMap registered_tests_; }; +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +using TypedTestCasePState = TypedTestSuitePState; +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 // Skips to the first non-space char after the first comma in 'str'; // returns NULL if no comma is found in 'str'. inline const char* SkipComma(const char* str) { const char* comma = strchr(str, ','); - if (comma == NULL) { - return NULL; + if (comma == nullptr) { + return nullptr; } while (IsSpace(*(++comma))) {} return comma; @@ -598,7 +639,7 @@ inline const char* SkipComma(const char* str) { // the entire string if it contains no comma. inline std::string GetPrefixUntilComma(const char* str) { const char* comma = strchr(str, ','); - return comma == NULL ? str : std::string(str, comma); + return comma == nullptr ? str : std::string(str, comma); } // Splits a given string on a given delimiter, populating a given @@ -648,7 +689,7 @@ template <GTEST_TEMPLATE_ Fixture, class TestSel, typename Types> class TypeParameterizedTest { public: // 'index' is the index of the test in the type list 'Types' - // specified in INSTANTIATE_TYPED_TEST_CASE_P(Prefix, TestCase, + // specified in INSTANTIATE_TYPED_TEST_SUITE_P(Prefix, TestSuite, // Types). Valid values for 'index' are [0, N - 1] where N is the // length of Types. static bool Register(const char* prefix, const CodeLocation& code_location, @@ -663,13 +704,17 @@ class TypeParameterizedTest { // list. MakeAndRegisterTestInfo( (std::string(prefix) + (prefix[0] == '\0' ? "" : "/") + case_name + - "/" + type_names[index]) + "/" + type_names[static_cast<size_t>(index)]) .c_str(), StripTrailingSpaces(GetPrefixUntilComma(test_names)).c_str(), GetTypeName<Type>().c_str(), - NULL, // No value parameter. - code_location, GetTypeId<FixtureClass>(), TestClass::SetUpTestCase, - TestClass::TearDownTestCase, new TestFactoryImpl<TestClass>); + nullptr, // No value parameter. + code_location, GetTypeId<FixtureClass>(), + SuiteApiResolver<TestClass>::GetSetUpCaseOrSuite( + code_location.file.c_str(), code_location.line), + SuiteApiResolver<TestClass>::GetTearDownCaseOrSuite( + code_location.file.c_str(), code_location.line), + new TestFactoryImpl<TestClass>); // Next, recurses (at compile time) with the tail of the type list. return TypeParameterizedTest<Fixture, TestSel, @@ -695,15 +740,15 @@ class TypeParameterizedTest<Fixture, TestSel, Types0> { } }; -// TypeParameterizedTestCase<Fixture, Tests, Types>::Register() +// TypeParameterizedTestSuite<Fixture, Tests, Types>::Register() // registers *all combinations* of 'Tests' and 'Types' with Google // Test. The return value is insignificant - we just need to return // something such that we can call this function in a namespace scope. template <GTEST_TEMPLATE_ Fixture, typename Tests, typename Types> -class TypeParameterizedTestCase { +class TypeParameterizedTestSuite { public: static bool Register(const char* prefix, CodeLocation code_location, - const TypedTestCasePState* state, const char* case_name, + const TypedTestSuitePState* state, const char* case_name, const char* test_names, const std::vector<std::string>& type_names = GenerateNames<DefaultNameGenerator, Types>()) { @@ -726,20 +771,20 @@ class TypeParameterizedTestCase { prefix, test_location, case_name, test_names, 0, type_names); // Next, recurses (at compile time) with the tail of the test list. - return TypeParameterizedTestCase<Fixture, typename Tests::Tail, - Types>::Register(prefix, code_location, - state, case_name, - SkipComma(test_names), - type_names); + return TypeParameterizedTestSuite<Fixture, typename Tests::Tail, + Types>::Register(prefix, code_location, + state, case_name, + SkipComma(test_names), + type_names); } }; // The base case for the compile time recursion. template <GTEST_TEMPLATE_ Fixture, typename Types> -class TypeParameterizedTestCase<Fixture, Templates0, Types> { +class TypeParameterizedTestSuite<Fixture, Templates0, Types> { public: static bool Register(const char* /*prefix*/, const CodeLocation&, - const TypedTestCasePState* /*state*/, + const TypedTestSuitePState* /*state*/, const char* /*case_name*/, const char* /*test_names*/, const std::vector<std::string>& = std::vector<std::string>() /*type_names*/) { @@ -802,120 +847,16 @@ class GTEST_API_ Random { GTEST_DISALLOW_COPY_AND_ASSIGN_(Random); }; -// Defining a variable of type CompileAssertTypesEqual<T1, T2> will cause a -// compiler error iff T1 and T2 are different types. -template <typename T1, typename T2> -struct CompileAssertTypesEqual; - -template <typename T> -struct CompileAssertTypesEqual<T, T> { -}; - -// Removes the reference from a type if it is a reference type, -// otherwise leaves it unchanged. This is the same as -// tr1::remove_reference, which is not widely available yet. -template <typename T> -struct RemoveReference { typedef T type; }; // NOLINT -template <typename T> -struct RemoveReference<T&> { typedef T type; }; // NOLINT - -// A handy wrapper around RemoveReference that works when the argument -// T depends on template parameters. -#define GTEST_REMOVE_REFERENCE_(T) \ - typename ::testing::internal::RemoveReference<T>::type - -// Removes const from a type if it is a const type, otherwise leaves -// it unchanged. This is the same as tr1::remove_const, which is not -// widely available yet. -template <typename T> -struct RemoveConst { typedef T type; }; // NOLINT -template <typename T> -struct RemoveConst<const T> { typedef T type; }; // NOLINT - -// MSVC 8.0, Sun C++, and IBM XL C++ have a bug which causes the above -// definition to fail to remove the const in 'const int[3]' and 'const -// char[3][4]'. The following specialization works around the bug. -template <typename T, size_t N> -struct RemoveConst<const T[N]> { - typedef typename RemoveConst<T>::type type[N]; -}; - -#if defined(_MSC_VER) && _MSC_VER < 1400 -// This is the only specialization that allows VC++ 7.1 to remove const in -// 'const int[3] and 'const int[3][4]'. However, it causes trouble with GCC -// and thus needs to be conditionally compiled. -template <typename T, size_t N> -struct RemoveConst<T[N]> { - typedef typename RemoveConst<T>::type type[N]; -}; -#endif - -// A handy wrapper around RemoveConst that works when the argument -// T depends on template parameters. -#define GTEST_REMOVE_CONST_(T) \ - typename ::testing::internal::RemoveConst<T>::type - // Turns const U&, U&, const U, and U all into U. #define GTEST_REMOVE_REFERENCE_AND_CONST_(T) \ - GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(T)) - -// ImplicitlyConvertible<From, To>::value is a compile-time bool -// constant that's true iff type From can be implicitly converted to -// type To. -template <typename From, typename To> -class ImplicitlyConvertible { - private: - // We need the following helper functions only for their types. - // They have no implementations. - - // MakeFrom() is an expression whose type is From. We cannot simply - // use From(), as the type From may not have a public default - // constructor. - static typename AddReference<From>::type MakeFrom(); - - // These two functions are overloaded. Given an expression - // Helper(x), the compiler will pick the first version if x can be - // implicitly converted to type To; otherwise it will pick the - // second version. - // - // The first version returns a value of size 1, and the second - // version returns a value of size 2. Therefore, by checking the - // size of Helper(x), which can be done at compile time, we can tell - // which version of Helper() is used, and hence whether x can be - // implicitly converted to type To. - static char Helper(To); - static char (&Helper(...))[2]; // NOLINT - - // We have to put the 'public' section after the 'private' section, - // or MSVC refuses to compile the code. - public: -#if defined(__BORLANDC__) - // C++Builder cannot use member overload resolution during template - // instantiation. The simplest workaround is to use its C++0x type traits - // functions (C++Builder 2009 and above only). - static const bool value = __is_convertible(From, To); -#else - // MSVC warns about implicitly converting from double to int for - // possible loss of data, so we need to temporarily disable the - // warning. - GTEST_DISABLE_MSC_WARNINGS_PUSH_(4244) - static const bool value = - sizeof(Helper(ImplicitlyConvertible::MakeFrom())) == 1; - GTEST_DISABLE_MSC_WARNINGS_POP_() -#endif // __BORLANDC__ -}; -template <typename From, typename To> -const bool ImplicitlyConvertible<From, To>::value; + typename std::remove_const<typename std::remove_reference<T>::type>::type // IsAProtocolMessage<T>::value is a compile-time bool constant that's -// true iff T is type ProtocolMessage, proto2::Message, or a subclass -// of those. +// true if and only if T is type proto2::Message or a subclass of it. template <typename T> struct IsAProtocolMessage : public bool_constant< - ImplicitlyConvertible<const T*, const ::ProtocolMessage*>::value || - ImplicitlyConvertible<const T*, const ::proto2::Message*>::value> { -}; + std::is_convertible<const T*, const ::proto2::Message*>::value> {}; // When the compiler sees expression IsContainerTest<C>(0), if C is an // STL-style container class, the first overload of IsContainerTest @@ -942,7 +883,6 @@ struct IsAProtocolMessage // IsContainerTest(typename C::const_iterator*) and // IsContainerTest(...) doesn't work with Visual Age C++ and Sun C++. typedef int IsContainer; -#if GTEST_LANG_CXX11 template <class C, class Iterator = decltype(::std::declval<const C&>().begin()), class = decltype(::std::declval<const C&>().end()), @@ -952,14 +892,6 @@ template <class C, IsContainer IsContainerTest(int /* dummy */) { return 0; } -#else -template <class C> -IsContainer IsContainerTest(int /* dummy */, - typename C::iterator* /* it */ = NULL, - typename C::const_iterator* /* const_it */ = NULL) { - return 0; -} -#endif // GTEST_LANG_CXX11 typedef char IsNotContainer; template <class C> @@ -980,47 +912,30 @@ struct IsHashTable { static char test(...); public: - static const bool value = sizeof(test<T>(0, 0)) == sizeof(int); + static const bool value = sizeof(test<T>(nullptr, nullptr)) == sizeof(int); }; template <typename T> const bool IsHashTable<T>::value; -template<typename T> -struct VoidT { - typedef void value_type; -}; - -template <typename T, typename = void> -struct HasValueType : false_type {}; -template <typename T> -struct HasValueType<T, VoidT<typename T::value_type> > : true_type { -}; - template <typename C, - bool = sizeof(IsContainerTest<C>(0)) == sizeof(IsContainer), - bool = HasValueType<C>::value> + bool = sizeof(IsContainerTest<C>(0)) == sizeof(IsContainer)> struct IsRecursiveContainerImpl; -template <typename C, bool HV> -struct IsRecursiveContainerImpl<C, false, HV> : public false_type {}; +template <typename C> +struct IsRecursiveContainerImpl<C, false> : public std::false_type {}; // Since the IsRecursiveContainerImpl depends on the IsContainerTest we need to // obey the same inconsistencies as the IsContainerTest, namely check if // something is a container is relying on only const_iterator in C++11 and // is relying on both const_iterator and iterator otherwise template <typename C> -struct IsRecursiveContainerImpl<C, true, false> : public false_type {}; - -template <typename C> -struct IsRecursiveContainerImpl<C, true, true> { - #if GTEST_LANG_CXX11 - typedef typename IteratorTraits<typename C::const_iterator>::value_type - value_type; -#else - typedef typename IteratorTraits<typename C::iterator>::value_type value_type; -#endif - typedef is_same<value_type, C> type; +struct IsRecursiveContainerImpl<C, true> { + using value_type = decltype(*std::declval<typename C::const_iterator>()); + using type = + std::is_same<typename std::remove_const< + typename std::remove_reference<value_type>::type>::type, + C>; }; // IsRecursiveContainer<Type> is a unary compile-time predicate that @@ -1032,13 +947,6 @@ struct IsRecursiveContainerImpl<C, true, true> { template <typename C> struct IsRecursiveContainer : public IsRecursiveContainerImpl<C>::type {}; -// EnableIf<condition>::type is void when 'Cond' is true, and -// undefined when 'Cond' is false. To use SFINAE to make a function -// overload only apply when a particular expression is true, add -// "typename EnableIf<expression>::type* = 0" as the last parameter. -template<bool> struct EnableIf; -template<> struct EnableIf<true> { typedef void type; }; // NOLINT - // Utilities for native arrays. // ArrayEq() compares two k-dimensional native arrays using the @@ -1161,10 +1069,9 @@ class NativeArray { } private: - enum { - kCheckTypeIsNotConstOrAReference = StaticAssertTypeEqHelper< - Element, GTEST_REMOVE_REFERENCE_AND_CONST_(Element)>::value - }; + static_assert(!std::is_const<Element>::value, "Type must not be const"); + static_assert(!std::is_reference<Element>::value, + "Type must not be a reference"); // Initializes this object with a copy of the input. void InitCopy(const Element* array, size_t a_size) { @@ -1189,6 +1096,139 @@ class NativeArray { GTEST_DISALLOW_ASSIGN_(NativeArray); }; +// Backport of std::index_sequence. +template <size_t... Is> +struct IndexSequence { + using type = IndexSequence; +}; + +// Double the IndexSequence, and one if plus_one is true. +template <bool plus_one, typename T, size_t sizeofT> +struct DoubleSequence; +template <size_t... I, size_t sizeofT> +struct DoubleSequence<true, IndexSequence<I...>, sizeofT> { + using type = IndexSequence<I..., (sizeofT + I)..., 2 * sizeofT>; +}; +template <size_t... I, size_t sizeofT> +struct DoubleSequence<false, IndexSequence<I...>, sizeofT> { + using type = IndexSequence<I..., (sizeofT + I)...>; +}; + +// Backport of std::make_index_sequence. +// It uses O(ln(N)) instantiation depth. +template <size_t N> +struct MakeIndexSequence + : DoubleSequence<N % 2 == 1, typename MakeIndexSequence<N / 2>::type, + N / 2>::type {}; + +template <> +struct MakeIndexSequence<0> : IndexSequence<> {}; + +// FIXME: This implementation of ElemFromList is O(1) in instantiation depth, +// but it is O(N^2) in total instantiations. Not sure if this is the best +// tradeoff, as it will make it somewhat slow to compile. +template <typename T, size_t, size_t> +struct ElemFromListImpl {}; + +template <typename T, size_t I> +struct ElemFromListImpl<T, I, I> { + using type = T; +}; + +// Get the Nth element from T... +// It uses O(1) instantiation depth. +template <size_t N, typename I, typename... T> +struct ElemFromList; + +template <size_t N, size_t... I, typename... T> +struct ElemFromList<N, IndexSequence<I...>, T...> + : ElemFromListImpl<T, N, I>... {}; + +template <typename... T> +class FlatTuple; + +template <typename Derived, size_t I> +struct FlatTupleElemBase; + +template <typename... T, size_t I> +struct FlatTupleElemBase<FlatTuple<T...>, I> { + using value_type = + typename ElemFromList<I, typename MakeIndexSequence<sizeof...(T)>::type, + T...>::type; + FlatTupleElemBase() = default; + explicit FlatTupleElemBase(value_type t) : value(std::move(t)) {} + value_type value; +}; + +template <typename Derived, typename Idx> +struct FlatTupleBase; + +template <size_t... Idx, typename... T> +struct FlatTupleBase<FlatTuple<T...>, IndexSequence<Idx...>> + : FlatTupleElemBase<FlatTuple<T...>, Idx>... { + using Indices = IndexSequence<Idx...>; + FlatTupleBase() = default; + explicit FlatTupleBase(T... t) + : FlatTupleElemBase<FlatTuple<T...>, Idx>(std::move(t))... {} +}; + +// Analog to std::tuple but with different tradeoffs. +// This class minimizes the template instantiation depth, thus allowing more +// elements that std::tuple would. std::tuple has been seen to require an +// instantiation depth of more than 10x the number of elements in some +// implementations. +// FlatTuple and ElemFromList are not recursive and have a fixed depth +// regardless of T... +// MakeIndexSequence, on the other hand, it is recursive but with an +// instantiation depth of O(ln(N)). +template <typename... T> +class FlatTuple + : private FlatTupleBase<FlatTuple<T...>, + typename MakeIndexSequence<sizeof...(T)>::type> { + using Indices = typename FlatTuple::FlatTupleBase::Indices; + + public: + FlatTuple() = default; + explicit FlatTuple(T... t) : FlatTuple::FlatTupleBase(std::move(t)...) {} + + template <size_t I> + const typename ElemFromList<I, Indices, T...>::type& Get() const { + return static_cast<const FlatTupleElemBase<FlatTuple, I>*>(this)->value; + } + + template <size_t I> + typename ElemFromList<I, Indices, T...>::type& Get() { + return static_cast<FlatTupleElemBase<FlatTuple, I>*>(this)->value; + } +}; + +// Utility functions to be called with static_assert to induce deprecation +// warnings. +GTEST_INTERNAL_DEPRECATED( + "INSTANTIATE_TEST_CASE_P is deprecated, please use " + "INSTANTIATE_TEST_SUITE_P") +constexpr bool InstantiateTestCase_P_IsDeprecated() { return true; } + +GTEST_INTERNAL_DEPRECATED( + "TYPED_TEST_CASE_P is deprecated, please use " + "TYPED_TEST_SUITE_P") +constexpr bool TypedTestCase_P_IsDeprecated() { return true; } + +GTEST_INTERNAL_DEPRECATED( + "TYPED_TEST_CASE is deprecated, please use " + "TYPED_TEST_SUITE") +constexpr bool TypedTestCaseIsDeprecated() { return true; } + +GTEST_INTERNAL_DEPRECATED( + "REGISTER_TYPED_TEST_CASE_P is deprecated, please use " + "REGISTER_TYPED_TEST_SUITE_P") +constexpr bool RegisterTypedTestCase_P_IsDeprecated() { return true; } + +GTEST_INTERNAL_DEPRECATED( + "INSTANTIATE_TYPED_TEST_CASE_P is deprecated, please use " + "INSTANTIATE_TYPED_TEST_SUITE_P") +constexpr bool InstantiateTypedTestCase_P_IsDeprecated() { return true; } + } // namespace internal } // namespace testing @@ -1208,7 +1248,10 @@ class NativeArray { #define GTEST_SUCCESS_(message) \ GTEST_MESSAGE_(message, ::testing::TestPartResult::kSuccess) -// Suppress MSVC warning 4702 (unreachable code) for the code following +#define GTEST_SKIP_(message) \ + return GTEST_MESSAGE_(message, ::testing::TestPartResult::kSkip) + +// Suppress MSVC warning 4072 (unreachable code) for the code following // statement if it returns or throws (or doesn't return or throw in some // situations). #define GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) \ @@ -1300,31 +1343,38 @@ class NativeArray { " Actual: it does.") // Expands to the name of the class that implements the given test. -#define GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \ - test_case_name##_##test_name##_Test +#define GTEST_TEST_CLASS_NAME_(test_suite_name, test_name) \ + test_suite_name##_##test_name##_Test // Helper macro for defining tests. -#define GTEST_TEST_(test_case_name, test_name, parent_class, parent_id)\ -class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) : public parent_class {\ - public:\ - GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {}\ - private:\ - virtual void TestBody();\ - static ::testing::TestInfo* const test_info_ GTEST_ATTRIBUTE_UNUSED_;\ - GTEST_DISALLOW_COPY_AND_ASSIGN_(\ - GTEST_TEST_CLASS_NAME_(test_case_name, test_name));\ -};\ -\ -::testing::TestInfo* const GTEST_TEST_CLASS_NAME_(test_case_name, test_name)\ - ::test_info_ =\ - ::testing::internal::MakeAndRegisterTestInfo(\ - #test_case_name, #test_name, NULL, NULL, \ - ::testing::internal::CodeLocation(__FILE__, __LINE__), \ - (parent_id), \ - parent_class::SetUpTestCase, \ - parent_class::TearDownTestCase, \ - new ::testing::internal::TestFactoryImpl<\ - GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>);\ -void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody() +#define GTEST_TEST_(test_suite_name, test_name, parent_class, parent_id) \ + static_assert(sizeof(GTEST_STRINGIFY_(test_suite_name)) > 1, \ + "test_suite_name must not be empty"); \ + static_assert(sizeof(GTEST_STRINGIFY_(test_name)) > 1, \ + "test_name must not be empty"); \ + class GTEST_TEST_CLASS_NAME_(test_suite_name, test_name) \ + : public parent_class { \ + public: \ + GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)() {} \ + \ + private: \ + virtual void TestBody(); \ + static ::testing::TestInfo* const test_info_ GTEST_ATTRIBUTE_UNUSED_; \ + GTEST_DISALLOW_COPY_AND_ASSIGN_(GTEST_TEST_CLASS_NAME_(test_suite_name, \ + test_name)); \ + }; \ + \ + ::testing::TestInfo* const GTEST_TEST_CLASS_NAME_(test_suite_name, \ + test_name)::test_info_ = \ + ::testing::internal::MakeAndRegisterTestInfo( \ + #test_suite_name, #test_name, nullptr, nullptr, \ + ::testing::internal::CodeLocation(__FILE__, __LINE__), (parent_id), \ + ::testing::internal::SuiteApiResolver< \ + parent_class>::GetSetUpCaseOrSuite(__FILE__, __LINE__), \ + ::testing::internal::SuiteApiResolver< \ + parent_class>::GetTearDownCaseOrSuite(__FILE__, __LINE__), \ + new ::testing::internal::TestFactoryImpl<GTEST_TEST_CLASS_NAME_( \ + test_suite_name, test_name)>); \ + void GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)::TestBody() #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/internal/gtest-param-util.h b/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/internal/gtest-param-util.h index d64f620c4c6..97533993c0c 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/internal/gtest-param-util.h +++ b/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/internal/gtest-param-util.h @@ -37,18 +37,19 @@ #include <ctype.h> +#include <cassert> #include <iterator> +#include <memory> #include <set> +#include <tuple> #include <utility> #include <vector> #include "gtest/internal/gtest-internal.h" -#include "gtest/internal/gtest-linked_ptr.h" #include "gtest/internal/gtest-port.h" #include "gtest/gtest-printers.h" namespace testing { - // Input to a parameterized test name generator, describing a test parameter. // Consists of the parameter value and the integer parameter index. template <class ParamType> @@ -72,13 +73,14 @@ struct PrintToStringParamName { namespace internal { // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. -// +// Utility Functions + // Outputs a message explaining invalid registration of different -// fixture class for the same test case. This may happen when +// fixture class for the same test suite. This may happen when // TEST_P macro is used to define two tests with the same name // but in different namespaces. -GTEST_API_ void ReportInvalidTestCaseType(const char* test_case_name, - CodeLocation code_location); +GTEST_API_ void ReportInvalidTestSuiteType(const char* test_suite_name, + CodeLocation code_location); template <typename> class ParamGeneratorInterface; template <typename> class ParamGenerator; @@ -153,7 +155,7 @@ class ParamIterator { private: friend class ParamGenerator<T>; explicit ParamIterator(ParamIteratorInterface<T>* impl) : impl_(impl) {} - scoped_ptr<ParamIteratorInterface<T> > impl_; + std::unique_ptr<ParamIteratorInterface<T> > impl_; }; // ParamGeneratorInterface<T> is the binary interface to access generators @@ -192,7 +194,7 @@ class ParamGenerator { iterator end() const { return iterator(impl_->End()); } private: - linked_ptr<const ParamGeneratorInterface<T> > impl_; + std::shared_ptr<const ParamGeneratorInterface<T> > impl_; }; // Generates values from a range of two comparable values. Can be used to @@ -205,12 +207,12 @@ class RangeGenerator : public ParamGeneratorInterface<T> { RangeGenerator(T begin, T end, IncrementT step) : begin_(begin), end_(end), step_(step), end_index_(CalculateEndIndex(begin, end, step)) {} - virtual ~RangeGenerator() {} + ~RangeGenerator() override {} - virtual ParamIteratorInterface<T>* Begin() const { + ParamIteratorInterface<T>* Begin() const override { return new Iterator(this, begin_, 0, step_); } - virtual ParamIteratorInterface<T>* End() const { + ParamIteratorInterface<T>* End() const override { return new Iterator(this, end_, end_index_, step_); } @@ -220,20 +222,20 @@ class RangeGenerator : public ParamGeneratorInterface<T> { Iterator(const ParamGeneratorInterface<T>* base, T value, int index, IncrementT step) : base_(base), value_(value), index_(index), step_(step) {} - virtual ~Iterator() {} + ~Iterator() override {} - virtual const ParamGeneratorInterface<T>* BaseGenerator() const { + const ParamGeneratorInterface<T>* BaseGenerator() const override { return base_; } - virtual void Advance() { + void Advance() override { value_ = static_cast<T>(value_ + step_); index_++; } - virtual ParamIteratorInterface<T>* Clone() const { + ParamIteratorInterface<T>* Clone() const override { return new Iterator(*this); } - virtual const T* Current() const { return &value_; } - virtual bool Equals(const ParamIteratorInterface<T>& other) const { + const T* Current() const override { return &value_; } + bool Equals(const ParamIteratorInterface<T>& other) const override { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) @@ -290,12 +292,12 @@ class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface<T> { template <typename ForwardIterator> ValuesInIteratorRangeGenerator(ForwardIterator begin, ForwardIterator end) : container_(begin, end) {} - virtual ~ValuesInIteratorRangeGenerator() {} + ~ValuesInIteratorRangeGenerator() override {} - virtual ParamIteratorInterface<T>* Begin() const { + ParamIteratorInterface<T>* Begin() const override { return new Iterator(this, container_.begin()); } - virtual ParamIteratorInterface<T>* End() const { + ParamIteratorInterface<T>* End() const override { return new Iterator(this, container_.end()); } @@ -307,16 +309,16 @@ class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface<T> { Iterator(const ParamGeneratorInterface<T>* base, typename ContainerType::const_iterator iterator) : base_(base), iterator_(iterator) {} - virtual ~Iterator() {} + ~Iterator() override {} - virtual const ParamGeneratorInterface<T>* BaseGenerator() const { + const ParamGeneratorInterface<T>* BaseGenerator() const override { return base_; } - virtual void Advance() { + void Advance() override { ++iterator_; value_.reset(); } - virtual ParamIteratorInterface<T>* Clone() const { + ParamIteratorInterface<T>* Clone() const override { return new Iterator(*this); } // We need to use cached value referenced by iterator_ because *iterator_ @@ -326,12 +328,11 @@ class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface<T> { // can advance iterator_ beyond the end of the range, and we cannot // detect that fact. The client code, on the other hand, is // responsible for not calling Current() on an out-of-range iterator. - virtual const T* Current() const { - if (value_.get() == NULL) - value_.reset(new T(*iterator_)); + const T* Current() const override { + if (value_.get() == nullptr) value_.reset(new T(*iterator_)); return value_.get(); } - virtual bool Equals(const ParamIteratorInterface<T>& other) const { + bool Equals(const ParamIteratorInterface<T>& other) const override { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) @@ -354,9 +355,9 @@ class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface<T> { // A cached value of *iterator_. We keep it here to allow access by // pointer in the wrapping iterator's operator->(). // value_ needs to be mutable to be accessed in Current(). - // Use of scoped_ptr helps manage cached value's lifetime, + // Use of std::unique_ptr helps manage cached value's lifetime, // which is bound by the lifespan of the iterator itself. - mutable scoped_ptr<const T> value_; + mutable std::unique_ptr<const T> value_; }; // class ValuesInIteratorRangeGenerator::Iterator // No implementation - assignment is unsupported. @@ -376,25 +377,12 @@ std::string DefaultParamName(const TestParamInfo<ParamType>& info) { return name_stream.GetString(); } -// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. -// -// Parameterized test name overload helpers, which help the -// INSTANTIATE_TEST_CASE_P macro choose between the default parameterized -// test name generator and user param name generator. -template <class ParamType, class ParamNameGenFunctor> -ParamNameGenFunctor GetParamNameGen(ParamNameGenFunctor func) { - return func; -} - -template <class ParamType> -struct ParamNameGenFunc { - typedef std::string Type(const TestParamInfo<ParamType>&); -}; - -template <class ParamType> -typename ParamNameGenFunc<ParamType>::Type *GetParamNameGen() { - return DefaultParamName; +template <typename T = int> +void TestNotEmpty() { + static_assert(sizeof(T) == 0, "Empty arguments are not allowed."); } +template <typename T = int> +void TestNotEmpty(const T&) {} // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // @@ -406,7 +394,7 @@ class ParameterizedTestFactory : public TestFactoryBase { typedef typename TestClass::ParamType ParamType; explicit ParameterizedTestFactory(ParamType parameter) : parameter_(parameter) {} - virtual Test* CreateTest() { + Test* CreateTest() override { TestClass::SetParam(¶meter_); return new TestClass(); } @@ -434,19 +422,19 @@ class TestMetaFactoryBase { // TestMetaFactory creates test factories for passing into // MakeAndRegisterTestInfo function. Since MakeAndRegisterTestInfo receives // ownership of test factory pointer, same factory object cannot be passed -// into that method twice. But ParameterizedTestCaseInfo is going to call +// into that method twice. But ParameterizedTestSuiteInfo is going to call // it for each Test/Parameter value combination. Thus it needs meta factory // creator class. -template <class TestCase> +template <class TestSuite> class TestMetaFactory - : public TestMetaFactoryBase<typename TestCase::ParamType> { + : public TestMetaFactoryBase<typename TestSuite::ParamType> { public: - typedef typename TestCase::ParamType ParamType; + using ParamType = typename TestSuite::ParamType; TestMetaFactory() {} - virtual TestFactoryBase* CreateTestFactory(ParamType parameter) { - return new ParameterizedTestFactory<TestCase>(parameter); + TestFactoryBase* CreateTestFactory(ParamType parameter) override { + return new ParameterizedTestFactory<TestSuite>(parameter); } private: @@ -455,93 +443,93 @@ class TestMetaFactory // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // -// ParameterizedTestCaseInfoBase is a generic interface -// to ParameterizedTestCaseInfo classes. ParameterizedTestCaseInfoBase +// ParameterizedTestSuiteInfoBase is a generic interface +// to ParameterizedTestSuiteInfo classes. ParameterizedTestSuiteInfoBase // accumulates test information provided by TEST_P macro invocations -// and generators provided by INSTANTIATE_TEST_CASE_P macro invocations +// and generators provided by INSTANTIATE_TEST_SUITE_P macro invocations // and uses that information to register all resulting test instances -// in RegisterTests method. The ParameterizeTestCaseRegistry class holds -// a collection of pointers to the ParameterizedTestCaseInfo objects +// in RegisterTests method. The ParameterizeTestSuiteRegistry class holds +// a collection of pointers to the ParameterizedTestSuiteInfo objects // and calls RegisterTests() on each of them when asked. -class ParameterizedTestCaseInfoBase { +class ParameterizedTestSuiteInfoBase { public: - virtual ~ParameterizedTestCaseInfoBase() {} + virtual ~ParameterizedTestSuiteInfoBase() {} - // Base part of test case name for display purposes. - virtual const std::string& GetTestCaseName() const = 0; + // Base part of test suite name for display purposes. + virtual const std::string& GetTestSuiteName() const = 0; // Test case id to verify identity. - virtual TypeId GetTestCaseTypeId() const = 0; + virtual TypeId GetTestSuiteTypeId() const = 0; // UnitTest class invokes this method to register tests in this - // test case right before running them in RUN_ALL_TESTS macro. - // This method should not be called more then once on any single - // instance of a ParameterizedTestCaseInfoBase derived class. + // test suite right before running them in RUN_ALL_TESTS macro. + // This method should not be called more than once on any single + // instance of a ParameterizedTestSuiteInfoBase derived class. virtual void RegisterTests() = 0; protected: - ParameterizedTestCaseInfoBase() {} + ParameterizedTestSuiteInfoBase() {} private: - GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseInfoBase); + GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestSuiteInfoBase); }; // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // -// ParameterizedTestCaseInfo accumulates tests obtained from TEST_P -// macro invocations for a particular test case and generators -// obtained from INSTANTIATE_TEST_CASE_P macro invocations for that -// test case. It registers tests with all values generated by all +// ParameterizedTestSuiteInfo accumulates tests obtained from TEST_P +// macro invocations for a particular test suite and generators +// obtained from INSTANTIATE_TEST_SUITE_P macro invocations for that +// test suite. It registers tests with all values generated by all // generators when asked. -template <class TestCase> -class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase { +template <class TestSuite> +class ParameterizedTestSuiteInfo : public ParameterizedTestSuiteInfoBase { public: // ParamType and GeneratorCreationFunc are private types but are required // for declarations of public methods AddTestPattern() and - // AddTestCaseInstantiation(). - typedef typename TestCase::ParamType ParamType; + // AddTestSuiteInstantiation(). + using ParamType = typename TestSuite::ParamType; // A function that returns an instance of appropriate generator type. typedef ParamGenerator<ParamType>(GeneratorCreationFunc)(); - typedef typename ParamNameGenFunc<ParamType>::Type ParamNameGeneratorFunc; + using ParamNameGeneratorFunc = std::string(const TestParamInfo<ParamType>&); - explicit ParameterizedTestCaseInfo( - const char* name, CodeLocation code_location) - : test_case_name_(name), code_location_(code_location) {} + explicit ParameterizedTestSuiteInfo(const char* name, + CodeLocation code_location) + : test_suite_name_(name), code_location_(code_location) {} // Test case base name for display purposes. - virtual const std::string& GetTestCaseName() const { return test_case_name_; } + const std::string& GetTestSuiteName() const override { + return test_suite_name_; + } // Test case id to verify identity. - virtual TypeId GetTestCaseTypeId() const { return GetTypeId<TestCase>(); } + TypeId GetTestSuiteTypeId() const override { return GetTypeId<TestSuite>(); } // TEST_P macro uses AddTestPattern() to record information // about a single test in a LocalTestInfo structure. - // test_case_name is the base name of the test case (without invocation + // test_suite_name is the base name of the test suite (without invocation // prefix). test_base_name is the name of an individual test without // parameter index. For the test SequenceA/FooTest.DoBar/1 FooTest is - // test case base name and DoBar is test base name. - void AddTestPattern(const char* test_case_name, - const char* test_base_name, + // test suite base name and DoBar is test base name. + void AddTestPattern(const char* test_suite_name, const char* test_base_name, TestMetaFactoryBase<ParamType>* meta_factory) { - tests_.push_back(linked_ptr<TestInfo>(new TestInfo(test_case_name, - test_base_name, - meta_factory))); + tests_.push_back(std::shared_ptr<TestInfo>( + new TestInfo(test_suite_name, test_base_name, meta_factory))); } - // INSTANTIATE_TEST_CASE_P macro uses AddGenerator() to record information + // INSTANTIATE_TEST_SUITE_P macro uses AddGenerator() to record information // about a generator. - int AddTestCaseInstantiation(const std::string& instantiation_name, - GeneratorCreationFunc* func, - ParamNameGeneratorFunc* name_func, - const char* file, int line) { + int AddTestSuiteInstantiation(const std::string& instantiation_name, + GeneratorCreationFunc* func, + ParamNameGeneratorFunc* name_func, + const char* file, int line) { instantiations_.push_back( InstantiationInfo(instantiation_name, func, name_func, file, line)); return 0; // Return value used only to run this method in namespace scope. } - // UnitTest class invokes this method to register tests in this test case - // test cases right before running tests in RUN_ALL_TESTS macro. - // This method should not be called more then once on any single - // instance of a ParameterizedTestCaseInfoBase derived class. - // UnitTest has a guard to prevent from calling this method more then once. - virtual void RegisterTests() { + // UnitTest class invokes this method to register tests in this test suite + // test suites right before running tests in RUN_ALL_TESTS macro. + // This method should not be called more than once on any single + // instance of a ParameterizedTestSuiteInfoBase derived class. + // UnitTest has a guard to prevent from calling this method more than once. + void RegisterTests() override { for (typename TestInfoContainer::iterator test_it = tests_.begin(); test_it != tests_.end(); ++test_it) { - linked_ptr<TestInfo> test_info = *test_it; + std::shared_ptr<TestInfo> test_info = *test_it; for (typename InstantiationContainer::iterator gen_it = instantiations_.begin(); gen_it != instantiations_.end(); ++gen_it) { @@ -551,10 +539,10 @@ class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase { const char* file = gen_it->file; int line = gen_it->line; - std::string test_case_name; + std::string test_suite_name; if ( !instantiation_name.empty() ) - test_case_name = instantiation_name + "/"; - test_case_name += test_info->test_case_base_name; + test_suite_name = instantiation_name + "/"; + test_suite_name += test_info->test_suite_base_name; size_t i = 0; std::set<std::string> test_param_names; @@ -577,39 +565,39 @@ class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase { test_param_names.insert(param_name); - test_name_stream << test_info->test_base_name << "/" << param_name; + if (!test_info->test_base_name.empty()) { + test_name_stream << test_info->test_base_name << "/"; + } + test_name_stream << param_name; MakeAndRegisterTestInfo( - test_case_name.c_str(), - test_name_stream.GetString().c_str(), - NULL, // No type parameter. - PrintToString(*param_it).c_str(), - code_location_, - GetTestCaseTypeId(), - TestCase::SetUpTestCase, - TestCase::TearDownTestCase, + test_suite_name.c_str(), test_name_stream.GetString().c_str(), + nullptr, // No type parameter. + PrintToString(*param_it).c_str(), code_location_, + GetTestSuiteTypeId(), + SuiteApiResolver<TestSuite>::GetSetUpCaseOrSuite(file, line), + SuiteApiResolver<TestSuite>::GetTearDownCaseOrSuite(file, line), test_info->test_meta_factory->CreateTestFactory(*param_it)); } // for param_it } // for gen_it } // for test_it - } // RegisterTests + } // RegisterTests private: // LocalTestInfo structure keeps information about a single test registered // with TEST_P macro. struct TestInfo { - TestInfo(const char* a_test_case_base_name, - const char* a_test_base_name, - TestMetaFactoryBase<ParamType>* a_test_meta_factory) : - test_case_base_name(a_test_case_base_name), - test_base_name(a_test_base_name), - test_meta_factory(a_test_meta_factory) {} - - const std::string test_case_base_name; + TestInfo(const char* a_test_suite_base_name, const char* a_test_base_name, + TestMetaFactoryBase<ParamType>* a_test_meta_factory) + : test_suite_base_name(a_test_suite_base_name), + test_base_name(a_test_base_name), + test_meta_factory(a_test_meta_factory) {} + + const std::string test_suite_base_name; const std::string test_base_name; - const scoped_ptr<TestMetaFactoryBase<ParamType> > test_meta_factory; + const std::unique_ptr<TestMetaFactoryBase<ParamType> > test_meta_factory; }; - typedef ::std::vector<linked_ptr<TestInfo> > TestInfoContainer; - // Records data received from INSTANTIATE_TEST_CASE_P macros: + using TestInfoContainer = ::std::vector<std::shared_ptr<TestInfo> >; + // Records data received from INSTANTIATE_TEST_SUITE_P macros: // <Instantiation name, Sequence generator creation function, // Name generator function, Source file, Source line> struct InstantiationInfo { @@ -646,76 +634,247 @@ class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase { return true; } - const std::string test_case_name_; + const std::string test_suite_name_; CodeLocation code_location_; TestInfoContainer tests_; InstantiationContainer instantiations_; - GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseInfo); -}; // class ParameterizedTestCaseInfo + GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestSuiteInfo); +}; // class ParameterizedTestSuiteInfo + +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +template <class TestCase> +using ParameterizedTestCaseInfo = ParameterizedTestSuiteInfo<TestCase>; +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // -// ParameterizedTestCaseRegistry contains a map of ParameterizedTestCaseInfoBase -// classes accessed by test case names. TEST_P and INSTANTIATE_TEST_CASE_P -// macros use it to locate their corresponding ParameterizedTestCaseInfo -// descriptors. -class ParameterizedTestCaseRegistry { +// ParameterizedTestSuiteRegistry contains a map of +// ParameterizedTestSuiteInfoBase classes accessed by test suite names. TEST_P +// and INSTANTIATE_TEST_SUITE_P macros use it to locate their corresponding +// ParameterizedTestSuiteInfo descriptors. +class ParameterizedTestSuiteRegistry { public: - ParameterizedTestCaseRegistry() {} - ~ParameterizedTestCaseRegistry() { - for (TestCaseInfoContainer::iterator it = test_case_infos_.begin(); - it != test_case_infos_.end(); ++it) { - delete *it; + ParameterizedTestSuiteRegistry() {} + ~ParameterizedTestSuiteRegistry() { + for (auto& test_suite_info : test_suite_infos_) { + delete test_suite_info; } } // Looks up or creates and returns a structure containing information about - // tests and instantiations of a particular test case. - template <class TestCase> - ParameterizedTestCaseInfo<TestCase>* GetTestCasePatternHolder( - const char* test_case_name, - CodeLocation code_location) { - ParameterizedTestCaseInfo<TestCase>* typed_test_info = NULL; - for (TestCaseInfoContainer::iterator it = test_case_infos_.begin(); - it != test_case_infos_.end(); ++it) { - if ((*it)->GetTestCaseName() == test_case_name) { - if ((*it)->GetTestCaseTypeId() != GetTypeId<TestCase>()) { + // tests and instantiations of a particular test suite. + template <class TestSuite> + ParameterizedTestSuiteInfo<TestSuite>* GetTestSuitePatternHolder( + const char* test_suite_name, CodeLocation code_location) { + ParameterizedTestSuiteInfo<TestSuite>* typed_test_info = nullptr; + for (auto& test_suite_info : test_suite_infos_) { + if (test_suite_info->GetTestSuiteName() == test_suite_name) { + if (test_suite_info->GetTestSuiteTypeId() != GetTypeId<TestSuite>()) { // Complain about incorrect usage of Google Test facilities // and terminate the program since we cannot guaranty correct - // test case setup and tear-down in this case. - ReportInvalidTestCaseType(test_case_name, code_location); + // test suite setup and tear-down in this case. + ReportInvalidTestSuiteType(test_suite_name, code_location); posix::Abort(); } else { // At this point we are sure that the object we found is of the same // type we are looking for, so we downcast it to that type // without further checks. typed_test_info = CheckedDowncastToActualType< - ParameterizedTestCaseInfo<TestCase> >(*it); + ParameterizedTestSuiteInfo<TestSuite> >(test_suite_info); } break; } } - if (typed_test_info == NULL) { - typed_test_info = new ParameterizedTestCaseInfo<TestCase>( - test_case_name, code_location); - test_case_infos_.push_back(typed_test_info); + if (typed_test_info == nullptr) { + typed_test_info = new ParameterizedTestSuiteInfo<TestSuite>( + test_suite_name, code_location); + test_suite_infos_.push_back(typed_test_info); } return typed_test_info; } void RegisterTests() { - for (TestCaseInfoContainer::iterator it = test_case_infos_.begin(); - it != test_case_infos_.end(); ++it) { - (*it)->RegisterTests(); + for (auto& test_suite_info : test_suite_infos_) { + test_suite_info->RegisterTests(); } } +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + template <class TestCase> + ParameterizedTestCaseInfo<TestCase>* GetTestCasePatternHolder( + const char* test_case_name, CodeLocation code_location) { + return GetTestSuitePatternHolder<TestCase>(test_case_name, code_location); + } + +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + + private: + using TestSuiteInfoContainer = ::std::vector<ParameterizedTestSuiteInfoBase*>; + + TestSuiteInfoContainer test_suite_infos_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestSuiteRegistry); +}; + +} // namespace internal + +// Forward declarations of ValuesIn(), which is implemented in +// include/gtest/gtest-param-test.h. +template <class Container> +internal::ParamGenerator<typename Container::value_type> ValuesIn( + const Container& container); + +namespace internal { +// Used in the Values() function to provide polymorphic capabilities. + +template <typename... Ts> +class ValueArray { + public: + ValueArray(Ts... v) : v_{std::move(v)...} {} + + template <typename T> + operator ParamGenerator<T>() const { // NOLINT + return ValuesIn(MakeVector<T>(MakeIndexSequence<sizeof...(Ts)>())); + } private: - typedef ::std::vector<ParameterizedTestCaseInfoBase*> TestCaseInfoContainer; + template <typename T, size_t... I> + std::vector<T> MakeVector(IndexSequence<I...>) const { + return std::vector<T>{static_cast<T>(v_.template Get<I>())...}; + } - TestCaseInfoContainer test_case_infos_; + FlatTuple<Ts...> v_; +}; - GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseRegistry); +template <typename... T> +class CartesianProductGenerator + : public ParamGeneratorInterface<::std::tuple<T...>> { + public: + typedef ::std::tuple<T...> ParamType; + + CartesianProductGenerator(const std::tuple<ParamGenerator<T>...>& g) + : generators_(g) {} + ~CartesianProductGenerator() override {} + + ParamIteratorInterface<ParamType>* Begin() const override { + return new Iterator(this, generators_, false); + } + ParamIteratorInterface<ParamType>* End() const override { + return new Iterator(this, generators_, true); + } + + private: + template <class I> + class IteratorImpl; + template <size_t... I> + class IteratorImpl<IndexSequence<I...>> + : public ParamIteratorInterface<ParamType> { + public: + IteratorImpl(const ParamGeneratorInterface<ParamType>* base, + const std::tuple<ParamGenerator<T>...>& generators, bool is_end) + : base_(base), + begin_(std::get<I>(generators).begin()...), + end_(std::get<I>(generators).end()...), + current_(is_end ? end_ : begin_) { + ComputeCurrentValue(); + } + ~IteratorImpl() override {} + + const ParamGeneratorInterface<ParamType>* BaseGenerator() const override { + return base_; + } + // Advance should not be called on beyond-of-range iterators + // so no component iterators must be beyond end of range, either. + void Advance() override { + assert(!AtEnd()); + // Advance the last iterator. + ++std::get<sizeof...(T) - 1>(current_); + // if that reaches end, propagate that up. + AdvanceIfEnd<sizeof...(T) - 1>(); + ComputeCurrentValue(); + } + ParamIteratorInterface<ParamType>* Clone() const override { + return new IteratorImpl(*this); + } + + const ParamType* Current() const override { return current_value_.get(); } + + bool Equals(const ParamIteratorInterface<ParamType>& other) const override { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const IteratorImpl* typed_other = + CheckedDowncastToActualType<const IteratorImpl>(&other); + + // We must report iterators equal if they both point beyond their + // respective ranges. That can happen in a variety of fashions, + // so we have to consult AtEnd(). + if (AtEnd() && typed_other->AtEnd()) return true; + + bool same = true; + bool dummy[] = { + (same = same && std::get<I>(current_) == + std::get<I>(typed_other->current_))...}; + (void)dummy; + return same; + } + + private: + template <size_t ThisI> + void AdvanceIfEnd() { + if (std::get<ThisI>(current_) != std::get<ThisI>(end_)) return; + + bool last = ThisI == 0; + if (last) { + // We are done. Nothing else to propagate. + return; + } + + constexpr size_t NextI = ThisI - (ThisI != 0); + std::get<ThisI>(current_) = std::get<ThisI>(begin_); + ++std::get<NextI>(current_); + AdvanceIfEnd<NextI>(); + } + + void ComputeCurrentValue() { + if (!AtEnd()) + current_value_ = std::make_shared<ParamType>(*std::get<I>(current_)...); + } + bool AtEnd() const { + bool at_end = false; + bool dummy[] = { + (at_end = at_end || std::get<I>(current_) == std::get<I>(end_))...}; + (void)dummy; + return at_end; + } + + const ParamGeneratorInterface<ParamType>* const base_; + std::tuple<typename ParamGenerator<T>::iterator...> begin_; + std::tuple<typename ParamGenerator<T>::iterator...> end_; + std::tuple<typename ParamGenerator<T>::iterator...> current_; + std::shared_ptr<ParamType> current_value_; + }; + + using Iterator = IteratorImpl<typename MakeIndexSequence<sizeof...(T)>::type>; + + std::tuple<ParamGenerator<T>...> generators_; +}; + +template <class... Gen> +class CartesianProductHolder { + public: + CartesianProductHolder(const Gen&... g) : generators_(g...) {} + template <typename... T> + operator ParamGenerator<::std::tuple<T...>>() const { + return ParamGenerator<::std::tuple<T...>>( + new CartesianProductGenerator<T...>(generators_)); + } + + private: + std::tuple<Gen...> generators_; }; } // namespace internal diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/internal/gtest-port-arch.h b/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/internal/gtest-port-arch.h index f83700e06d9..cece93dba12 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/internal/gtest-port-arch.h +++ b/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/internal/gtest-port-arch.h @@ -38,14 +38,13 @@ // Determines the platform on which Google Test is compiled. #ifdef __CYGWIN__ # define GTEST_OS_CYGWIN 1 -#elif defined __SYMBIAN32__ -# define GTEST_OS_SYMBIAN 1 +# elif defined(__MINGW__) || defined(__MINGW32__) || defined(__MINGW64__) +# define GTEST_OS_WINDOWS_MINGW 1 +# define GTEST_OS_WINDOWS 1 #elif defined _WIN32 # define GTEST_OS_WINDOWS 1 # ifdef _WIN32_WCE # define GTEST_OS_WINDOWS_MOBILE 1 -# elif defined(__MINGW__) || defined(__MINGW32__) -# define GTEST_OS_WINDOWS_MINGW 1 # elif defined(WINAPI_FAMILY) # include <winapifamily.h> # if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) @@ -65,15 +64,21 @@ # else # define GTEST_OS_WINDOWS_DESKTOP 1 # endif // _WIN32_WCE +#elif defined __OS2__ +# define GTEST_OS_OS2 1 #elif defined __APPLE__ # define GTEST_OS_MAC 1 # if TARGET_OS_IPHONE # define GTEST_OS_IOS 1 # endif +#elif defined __DragonFly__ +# define GTEST_OS_DRAGONFLY 1 #elif defined __FreeBSD__ # define GTEST_OS_FREEBSD 1 #elif defined __Fuchsia__ # define GTEST_OS_FUCHSIA 1 +#elif defined(__GLIBC__) && defined(__FreeBSD_kernel__) +# define GTEST_OS_GNU_KFREEBSD 1 #elif defined __linux__ # define GTEST_OS_LINUX 1 # if defined __ANDROID__ @@ -95,6 +100,8 @@ # define GTEST_OS_OPENBSD 1 #elif defined __QNX__ # define GTEST_OS_QNX 1 +#elif defined(__HAIKU__) +#define GTEST_OS_HAIKU 1 #endif // __CYGWIN__ #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_ARCH_H_ diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/internal/gtest-port.h b/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/internal/gtest-port.h index 786497d854c..063fcb1083b 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/internal/gtest-port.h +++ b/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/internal/gtest-port.h @@ -72,10 +72,6 @@ // is/isn't available. // GTEST_HAS_EXCEPTIONS - Define it to 1/0 to indicate that exceptions // are enabled. -// GTEST_HAS_GLOBAL_STRING - Define it to 1/0 to indicate that ::string -// is/isn't available -// GTEST_HAS_GLOBAL_WSTRING - Define it to 1/0 to indicate that ::wstring -// is/isn't available // GTEST_HAS_POSIX_RE - Define it to 1/0 to indicate that POSIX regular // expressions are/aren't available. // GTEST_HAS_PTHREAD - Define it to 1/0 to indicate that <pthread.h> @@ -85,8 +81,6 @@ // GTEST_HAS_STD_WSTRING - Define it to 1/0 to indicate that // std::wstring does/doesn't work (Google Test can // be used where std::wstring is unavailable). -// GTEST_HAS_TR1_TUPLE - Define it to 1/0 to indicate tr1::tuple -// is/isn't available. // GTEST_HAS_SEH - Define it to 1/0 to indicate whether the // compiler supports Microsoft's "Structured // Exception Handling". @@ -94,12 +88,6 @@ // - Define it to 1/0 to indicate whether the // platform supports I/O stream redirection using // dup() and dup2(). -// GTEST_USE_OWN_TR1_TUPLE - Define it to 1/0 to indicate whether Google -// Test's own tr1 tuple implementation should be -// used. Unused when the user sets -// GTEST_HAS_TR1_TUPLE to 0. -// GTEST_LANG_CXX11 - Define it to 1/0 to indicate that Google Test -// is building in C++11/C++98 mode. // GTEST_LINKED_AS_SHARED_LIBRARY // - Define to 1 when compiling tests that use // Google Test as a shared library (known as @@ -125,8 +113,11 @@ // // GTEST_OS_AIX - IBM AIX // GTEST_OS_CYGWIN - Cygwin +// GTEST_OS_DRAGONFLY - DragonFlyBSD // GTEST_OS_FREEBSD - FreeBSD // GTEST_OS_FUCHSIA - Fuchsia +// GTEST_OS_GNU_KFREEBSD - GNU/kFreeBSD +// GTEST_OS_HAIKU - Haiku // GTEST_OS_HPUX - HP-UX // GTEST_OS_LINUX - Linux // GTEST_OS_LINUX_ANDROID - Google Android @@ -135,9 +126,9 @@ // GTEST_OS_NACL - Google Native Client (NaCl) // GTEST_OS_NETBSD - NetBSD // GTEST_OS_OPENBSD - OpenBSD +// GTEST_OS_OS2 - OS/2 // GTEST_OS_QNX - QNX // GTEST_OS_SOLARIS - Sun Solaris -// GTEST_OS_SYMBIAN - Symbian // GTEST_OS_WINDOWS - Windows (Desktop, MinGW, or Mobile) // GTEST_OS_WINDOWS_DESKTOP - Windows Desktop // GTEST_OS_WINDOWS_MINGW - MinGW @@ -146,7 +137,7 @@ // GTEST_OS_WINDOWS_RT - Windows Store App/WinRT // GTEST_OS_ZOS - z/OS // -// Among the platforms, Cygwin, Linux, Max OS X, and Windows have the +// Among the platforms, Cygwin, Linux, Mac OS X, and Windows have the // most stable support. Since core members of the Google Test project // don't have access to other platforms, support for them may be less // stable. If you notice any problems on your platform, please notify @@ -172,8 +163,6 @@ // EXPECT_DEATH(DoSomethingDeadly()); // #endif // -// GTEST_HAS_COMBINE - the Combine() function (for value-parameterized -// tests) // GTEST_HAS_DEATH_TEST - death tests // GTEST_HAS_TYPED_TEST - typed tests // GTEST_HAS_TYPED_TEST_P - type-parameterized tests @@ -184,7 +173,6 @@ // define themselves. // GTEST_USES_SIMPLE_RE - our own simple regex is used; // the above RE\b(s) are mutually exclusive. -// GTEST_CAN_COMPARE_NULL - accepts untyped NULL in EXPECT_EQ(). // Misc public macros // ------------------ @@ -210,23 +198,10 @@ // GTEST_INTENTIONAL_CONST_COND_POP_ - finish code section where MSVC C4127 // is suppressed. // -// C++11 feature wrappers: -// -// testing::internal::forward - portability wrapper for std::forward. -// testing::internal::move - portability wrapper for std::move. -// // Synchronization: // Mutex, MutexLock, ThreadLocal, GetThreadCount() // - synchronization primitives. // -// Template meta programming: -// is_pointer - as in TR1; needed on Symbian and IBM XL C/C++ only. -// IteratorTraits - partial implementation of std::iterator_traits, which -// is not available in libCstd when compiled with Sun C++. -// -// Smart pointers: -// scoped_ptr - as in TR2. -// // Regular expressions: // RE - a simple regular expression class using the POSIX // Extended Regular Expression syntax on UNIX-like platforms @@ -262,12 +237,20 @@ // BoolFromGTestEnv() - parses a bool environment variable. // Int32FromGTestEnv() - parses an Int32 environment variable. // StringFromGTestEnv() - parses a string environment variable. +// +// Deprecation warnings: +// GTEST_INTERNAL_DEPRECATED(message) - attribute marking a function as +// deprecated; calling a marked function +// should generate a compiler warning #include <ctype.h> // for isspace, etc #include <stddef.h> // for ptrdiff_t -#include <stdlib.h> #include <stdio.h> +#include <stdlib.h> #include <string.h> +#include <memory> +#include <type_traits> + #ifndef _WIN32_WCE # include <sys/types.h> # include <sys/stat.h> @@ -278,12 +261,11 @@ # include <TargetConditionals.h> #endif -// Brings in the definition of HAS_GLOBAL_STRING. This must be done -// BEFORE we test HAS_GLOBAL_STRING. -#include <string> // NOLINT #include <algorithm> // NOLINT -#include <iostream> // NOLINT -#include <sstream> // NOLINT +#include <iostream> // NOLINT +#include <sstream> // NOLINT +#include <string> // NOLINT +#include <tuple> #include <utility> #include <vector> // NOLINT @@ -315,14 +297,14 @@ // GTEST_DISABLE_MSC_WARNINGS_PUSH_(4800 4385) // /* code that triggers warnings C4800 and C4385 */ // GTEST_DISABLE_MSC_WARNINGS_POP_() -#if _MSC_VER >= 1400 +#if defined(_MSC_VER) # define GTEST_DISABLE_MSC_WARNINGS_PUSH_(warnings) \ __pragma(warning(push)) \ __pragma(warning(disable: warnings)) # define GTEST_DISABLE_MSC_WARNINGS_POP_() \ __pragma(warning(pop)) #else -// Older versions of MSVC don't have __pragma. +// Not all compilers are MSVC # define GTEST_DISABLE_MSC_WARNINGS_PUSH_(warnings) # define GTEST_DISABLE_MSC_WARNINGS_POP_() #endif @@ -343,80 +325,6 @@ GTEST_DISABLE_MSC_WARNINGS_POP_() #endif -#ifndef GTEST_LANG_CXX11 -// gcc and clang define __GXX_EXPERIMENTAL_CXX0X__ when -// -std={c,gnu}++{0x,11} is passed. The C++11 standard specifies a -// value for __cplusplus, and recent versions of clang, gcc, and -// probably other compilers set that too in C++11 mode. -# if __GXX_EXPERIMENTAL_CXX0X__ || __cplusplus >= 201103L || _MSC_VER >= 1900 -// Compiling in at least C++11 mode. -# define GTEST_LANG_CXX11 1 -# else -# define GTEST_LANG_CXX11 0 -# endif -#endif - -// Distinct from C++11 language support, some environments don't provide -// proper C++11 library support. Notably, it's possible to build in -// C++11 mode when targeting Mac OS X 10.6, which has an old libstdc++ -// with no C++11 support. -// -// libstdc++ has sufficient C++11 support as of GCC 4.6.0, __GLIBCXX__ -// 20110325, but maintenance releases in the 4.4 and 4.5 series followed -// this date, so check for those versions by their date stamps. -// https://gcc.gnu.org/onlinedocs/libstdc++/manual/abi.html#abi.versioning -#if GTEST_LANG_CXX11 && \ - (!defined(__GLIBCXX__) || ( \ - __GLIBCXX__ >= 20110325ul && /* GCC >= 4.6.0 */ \ - /* Blacklist of patch releases of older branches: */ \ - __GLIBCXX__ != 20110416ul && /* GCC 4.4.6 */ \ - __GLIBCXX__ != 20120313ul && /* GCC 4.4.7 */ \ - __GLIBCXX__ != 20110428ul && /* GCC 4.5.3 */ \ - __GLIBCXX__ != 20120702ul)) /* GCC 4.5.4 */ -# define GTEST_STDLIB_CXX11 1 -#endif - -// Only use C++11 library features if the library provides them. -#if GTEST_STDLIB_CXX11 -# define GTEST_HAS_STD_BEGIN_AND_END_ 1 -# define GTEST_HAS_STD_FORWARD_LIST_ 1 -# if !defined(_MSC_VER) || (_MSC_FULL_VER >= 190023824) -// works only with VS2015U2 and better -# define GTEST_HAS_STD_FUNCTION_ 1 -# endif -# define GTEST_HAS_STD_INITIALIZER_LIST_ 1 -# define GTEST_HAS_STD_MOVE_ 1 -# define GTEST_HAS_STD_UNIQUE_PTR_ 1 -# define GTEST_HAS_STD_SHARED_PTR_ 1 -# define GTEST_HAS_UNORDERED_MAP_ 1 -# define GTEST_HAS_UNORDERED_SET_ 1 -#endif - -// C++11 specifies that <tuple> provides std::tuple. -// Some platforms still might not have it, however. -#if GTEST_LANG_CXX11 -# define GTEST_HAS_STD_TUPLE_ 1 -# if defined(__clang__) -// Inspired by -// https://clang.llvm.org/docs/LanguageExtensions.html#include-file-checking-macros -# if defined(__has_include) && !__has_include(<tuple>) -# undef GTEST_HAS_STD_TUPLE_ -# endif -# elif defined(_MSC_VER) -// Inspired by boost/config/stdlib/dinkumware.hpp -# if defined(_CPPLIB_VER) && _CPPLIB_VER < 520 -# undef GTEST_HAS_STD_TUPLE_ -# endif -# elif defined(__GLIBCXX__) -// Inspired by boost/config/stdlib/libstdcpp3.hpp, -// http://gcc.gnu.org/gcc-4.2/changes.html and -// https://web.archive.org/web/20140227044429/gcc.gnu.org/onlinedocs/libstdc++/manual/bk01pt01ch01.html#manual.intro.status.standard.200x -# if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 2) -# undef GTEST_HAS_STD_TUPLE_ -# endif -# endif -#endif - // Brings in definitions for functions used in the testing::internal::posix // namespace (read, write, close, chdir, isatty, stat). We do not currently // use them on Windows Mobile. @@ -449,7 +357,8 @@ typedef struct _RTL_CRITICAL_SECTION GTEST_CRITICAL_SECTION; # include <android/api-level.h> // NOLINT #endif -// Defines this to true iff Google Test can use POSIX regular expressions. +// Defines this to true if and only if Google Test can use POSIX regular +// expressions. #ifndef GTEST_HAS_POSIX_RE # if GTEST_OS_LINUX_ANDROID // On Android, <regex.h> is only available starting with Gingerbread. @@ -490,7 +399,7 @@ typedef struct _RTL_CRITICAL_SECTION GTEST_CRITICAL_SECTION; // The user didn't tell us whether exceptions are enabled, so we need // to figure it out. # if defined(_MSC_VER) && defined(_CPPUNWIND) -// MSVC defines _CPPUNWIND to 1 iff exceptions are enabled. +// MSVC defines _CPPUNWIND to 1 if and only if exceptions are enabled. # define GTEST_HAS_EXCEPTIONS 1 # elif defined(__BORLANDC__) // C++Builder's implementation of the STL uses the _HAS_EXCEPTIONS @@ -501,16 +410,17 @@ typedef struct _RTL_CRITICAL_SECTION GTEST_CRITICAL_SECTION; # endif // _HAS_EXCEPTIONS # define GTEST_HAS_EXCEPTIONS _HAS_EXCEPTIONS # elif defined(__clang__) -// clang defines __EXCEPTIONS iff exceptions are enabled before clang 220714, -// but iff cleanups are enabled after that. In Obj-C++ files, there can be -// cleanups for ObjC exceptions which also need cleanups, even if C++ exceptions -// are disabled. clang has __has_feature(cxx_exceptions) which checks for C++ -// exceptions starting at clang r206352, but which checked for cleanups prior to -// that. To reliably check for C++ exception availability with clang, check for +// clang defines __EXCEPTIONS if and only if exceptions are enabled before clang +// 220714, but if and only if cleanups are enabled after that. In Obj-C++ files, +// there can be cleanups for ObjC exceptions which also need cleanups, even if +// C++ exceptions are disabled. clang has __has_feature(cxx_exceptions) which +// checks for C++ exceptions starting at clang r206352, but which checked for +// cleanups prior to that. To reliably check for C++ exception availability with +// clang, check for // __EXCEPTIONS && __has_feature(cxx_exceptions). # define GTEST_HAS_EXCEPTIONS (__EXCEPTIONS && __has_feature(cxx_exceptions)) # elif defined(__GNUC__) && __EXCEPTIONS -// gcc defines __EXCEPTIONS to 1 iff exceptions are enabled. +// gcc defines __EXCEPTIONS to 1 if and only if exceptions are enabled. # define GTEST_HAS_EXCEPTIONS 1 # elif defined(__SUNPRO_CC) // Sun Pro CC supports exceptions. However, there is no compile-time way of @@ -518,7 +428,7 @@ typedef struct _RTL_CRITICAL_SECTION GTEST_CRITICAL_SECTION; // they are enabled unless the user tells us otherwise. # define GTEST_HAS_EXCEPTIONS 1 # elif defined(__IBMCPP__) && __EXCEPTIONS -// xlC defines __EXCEPTIONS to 1 iff exceptions are enabled. +// xlC defines __EXCEPTIONS to 1 if and only if exceptions are enabled. # define GTEST_HAS_EXCEPTIONS 1 # elif defined(__HP_aCC) // Exception handling is in effect by default in HP aCC compiler. It has to @@ -540,31 +450,18 @@ typedef struct _RTL_CRITICAL_SECTION GTEST_CRITICAL_SECTION; # error "::std::string isn't available." #endif // !defined(GTEST_HAS_STD_STRING) -#ifndef GTEST_HAS_GLOBAL_STRING -# define GTEST_HAS_GLOBAL_STRING 0 -#endif // GTEST_HAS_GLOBAL_STRING - #ifndef GTEST_HAS_STD_WSTRING // The user didn't tell us whether ::std::wstring is available, so we need // to figure it out. -// FIXME: uses autoconf to detect whether ::std::wstring -// is available. - // Cygwin 1.7 and below doesn't support ::std::wstring. // Solaris' libc++ doesn't support it either. Android has // no support for it at least as recent as Froyo (2.2). -# define GTEST_HAS_STD_WSTRING \ - (!(GTEST_OS_LINUX_ANDROID || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS)) +#define GTEST_HAS_STD_WSTRING \ + (!(GTEST_OS_LINUX_ANDROID || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS || \ + GTEST_OS_HAIKU)) #endif // GTEST_HAS_STD_WSTRING -#ifndef GTEST_HAS_GLOBAL_WSTRING -// The user didn't tell us whether ::wstring is available, so we need -// to figure it out. -# define GTEST_HAS_GLOBAL_WSTRING \ - (GTEST_HAS_STD_WSTRING && GTEST_HAS_GLOBAL_STRING) -#endif // GTEST_HAS_GLOBAL_WSTRING - // Determines whether RTTI is available. #ifndef GTEST_HAS_RTTI // The user didn't tell us whether RTTI is enabled, so we need to @@ -572,14 +469,15 @@ typedef struct _RTL_CRITICAL_SECTION GTEST_CRITICAL_SECTION; # ifdef _MSC_VER -# ifdef _CPPRTTI // MSVC defines this macro iff RTTI is enabled. +#ifdef _CPPRTTI // MSVC defines this macro if and only if RTTI is enabled. # define GTEST_HAS_RTTI 1 # else # define GTEST_HAS_RTTI 0 # endif -// Starting with version 4.3.2, gcc defines __GXX_RTTI iff RTTI is enabled. -# elif defined(__GNUC__) && (GTEST_GCC_VER_ >= 40302) +// Starting with version 4.3.2, gcc defines __GXX_RTTI if and only if RTTI is +// enabled. +# elif defined(__GNUC__) # ifdef __GXX_RTTI // When building against STLport with the Android NDK and with @@ -635,9 +533,11 @@ typedef struct _RTL_CRITICAL_SECTION GTEST_CRITICAL_SECTION; // // To disable threading support in Google Test, add -DGTEST_HAS_PTHREAD=0 // to your compiler flags. -#define GTEST_HAS_PTHREAD \ - (GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_HPUX || GTEST_OS_QNX || \ - GTEST_OS_FREEBSD || GTEST_OS_NACL || GTEST_OS_NETBSD || GTEST_OS_FUCHSIA) +#define GTEST_HAS_PTHREAD \ + (GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_HPUX || GTEST_OS_QNX || \ + GTEST_OS_FREEBSD || GTEST_OS_NACL || GTEST_OS_NETBSD || GTEST_OS_FUCHSIA || \ + GTEST_OS_DRAGONFLY || GTEST_OS_GNU_KFREEBSD || GTEST_OS_OPENBSD || \ + GTEST_OS_HAIKU) #endif // GTEST_HAS_PTHREAD #if GTEST_HAS_PTHREAD @@ -649,136 +549,6 @@ typedef struct _RTL_CRITICAL_SECTION GTEST_CRITICAL_SECTION; # include <time.h> // NOLINT #endif -// Determines if hash_map/hash_set are available. -// Only used for testing against those containers. -#if !defined(GTEST_HAS_HASH_MAP_) -# if defined(_MSC_VER) && (_MSC_VER < 1900) -# define GTEST_HAS_HASH_MAP_ 1 // Indicates that hash_map is available. -# define GTEST_HAS_HASH_SET_ 1 // Indicates that hash_set is available. -# endif // _MSC_VER -#endif // !defined(GTEST_HAS_HASH_MAP_) - -// Determines whether Google Test can use tr1/tuple. You can define -// this macro to 0 to prevent Google Test from using tuple (any -// feature depending on tuple with be disabled in this mode). -#ifndef GTEST_HAS_TR1_TUPLE -# if GTEST_OS_LINUX_ANDROID && defined(_STLPORT_MAJOR) -// STLport, provided with the Android NDK, has neither <tr1/tuple> or <tuple>. -# define GTEST_HAS_TR1_TUPLE 0 -# elif defined(_MSC_VER) && (_MSC_VER >= 1910) -// Prevent `warning C4996: 'std::tr1': warning STL4002: -// The non-Standard std::tr1 namespace and TR1-only machinery -// are deprecated and will be REMOVED.` -# define GTEST_HAS_TR1_TUPLE 0 -# elif GTEST_LANG_CXX11 && defined(_LIBCPP_VERSION) -// libc++ doesn't support TR1. -# define GTEST_HAS_TR1_TUPLE 0 -# else -// The user didn't tell us not to do it, so we assume it's OK. -# define GTEST_HAS_TR1_TUPLE 1 -# endif -#endif // GTEST_HAS_TR1_TUPLE - -// Determines whether Google Test's own tr1 tuple implementation -// should be used. -#ifndef GTEST_USE_OWN_TR1_TUPLE -// We use our own tuple implementation on Symbian. -# if GTEST_OS_SYMBIAN -# define GTEST_USE_OWN_TR1_TUPLE 1 -# else -// The user didn't tell us, so we need to figure it out. - -// We use our own TR1 tuple if we aren't sure the user has an -// implementation of it already. At this time, libstdc++ 4.0.0+ and -// MSVC 2010 are the only mainstream standard libraries that come -// with a TR1 tuple implementation. NVIDIA's CUDA NVCC compiler -// pretends to be GCC by defining __GNUC__ and friends, but cannot -// compile GCC's tuple implementation. MSVC 2008 (9.0) provides TR1 -// tuple in a 323 MB Feature Pack download, which we cannot assume the -// user has. QNX's QCC compiler is a modified GCC but it doesn't -// support TR1 tuple. libc++ only provides std::tuple, in C++11 mode, -// and it can be used with some compilers that define __GNUC__. -# if (defined(__GNUC__) && !defined(__CUDACC__) && (GTEST_GCC_VER_ >= 40000) \ - && !GTEST_OS_QNX && !defined(_LIBCPP_VERSION)) \ - || (_MSC_VER >= 1600 && _MSC_VER < 1900) -# define GTEST_ENV_HAS_TR1_TUPLE_ 1 -# endif - -// C++11 specifies that <tuple> provides std::tuple. Use that if gtest is used -// in C++11 mode and libstdc++ isn't very old (binaries targeting OS X 10.6 -// can build with clang but need to use gcc4.2's libstdc++). -# if GTEST_LANG_CXX11 && (!defined(__GLIBCXX__) || __GLIBCXX__ > 20110325) -# define GTEST_ENV_HAS_STD_TUPLE_ 1 -# endif - -# if GTEST_ENV_HAS_TR1_TUPLE_ || GTEST_ENV_HAS_STD_TUPLE_ -# define GTEST_USE_OWN_TR1_TUPLE 0 -# else -# define GTEST_USE_OWN_TR1_TUPLE 1 -# endif -# endif // GTEST_OS_SYMBIAN -#endif // GTEST_USE_OWN_TR1_TUPLE - -// To avoid conditional compilation we make it gtest-port.h's responsibility -// to #include the header implementing tuple. -#if GTEST_HAS_STD_TUPLE_ -# include <tuple> // IWYU pragma: export -# define GTEST_TUPLE_NAMESPACE_ ::std -#endif // GTEST_HAS_STD_TUPLE_ - -// We include tr1::tuple even if std::tuple is available to define printers for -// them. -#if GTEST_HAS_TR1_TUPLE -# ifndef GTEST_TUPLE_NAMESPACE_ -# define GTEST_TUPLE_NAMESPACE_ ::std::tr1 -# endif // GTEST_TUPLE_NAMESPACE_ - -# if GTEST_USE_OWN_TR1_TUPLE -# include "gtest/internal/gtest-tuple.h" // IWYU pragma: export // NOLINT -# elif GTEST_OS_SYMBIAN - -// On Symbian, BOOST_HAS_TR1_TUPLE causes Boost's TR1 tuple library to -// use STLport's tuple implementation, which unfortunately doesn't -// work as the copy of STLport distributed with Symbian is incomplete. -// By making sure BOOST_HAS_TR1_TUPLE is undefined, we force Boost to -// use its own tuple implementation. -# ifdef BOOST_HAS_TR1_TUPLE -# undef BOOST_HAS_TR1_TUPLE -# endif // BOOST_HAS_TR1_TUPLE - -// This prevents <boost/tr1/detail/config.hpp>, which defines -// BOOST_HAS_TR1_TUPLE, from being #included by Boost's <tuple>. -# define BOOST_TR1_DETAIL_CONFIG_HPP_INCLUDED -# include <tuple> // IWYU pragma: export // NOLINT - -# elif defined(__GNUC__) && (GTEST_GCC_VER_ >= 40000) -// GCC 4.0+ implements tr1/tuple in the <tr1/tuple> header. This does -// not conform to the TR1 spec, which requires the header to be <tuple>. - -# if !GTEST_HAS_RTTI && GTEST_GCC_VER_ < 40302 -// Until version 4.3.2, gcc has a bug that causes <tr1/functional>, -// which is #included by <tr1/tuple>, to not compile when RTTI is -// disabled. _TR1_FUNCTIONAL is the header guard for -// <tr1/functional>. Hence the following #define is used to prevent -// <tr1/functional> from being included. -# define _TR1_FUNCTIONAL 1 -# include <tr1/tuple> -# undef _TR1_FUNCTIONAL // Allows the user to #include - // <tr1/functional> if they choose to. -# else -# include <tr1/tuple> // NOLINT -# endif // !GTEST_HAS_RTTI && GTEST_GCC_VER_ < 40302 - -// VS 2010 now has tr1 support. -# elif _MSC_VER >= 1600 -# include <tuple> // IWYU pragma: export // NOLINT - -# else // GTEST_USE_OWN_TR1_TUPLE -# include <tr1/tuple> // IWYU pragma: export // NOLINT -# endif // GTEST_USE_OWN_TR1_TUPLE - -#endif // GTEST_HAS_TR1_TUPLE - // Determines whether clone(2) is supported. // Usually it will only be available on Linux, excluding // Linux on the Itanium architecture. @@ -812,24 +582,21 @@ typedef struct _RTL_CRITICAL_SECTION GTEST_CRITICAL_SECTION; #ifndef GTEST_HAS_STREAM_REDIRECTION // By default, we assume that stream redirection is supported on all // platforms except known mobile ones. -# if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || \ - GTEST_OS_WINDOWS_PHONE || GTEST_OS_WINDOWS_RT +# if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_PHONE || GTEST_OS_WINDOWS_RT # define GTEST_HAS_STREAM_REDIRECTION 0 # else # define GTEST_HAS_STREAM_REDIRECTION 1 -# endif // !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_SYMBIAN +# endif // !GTEST_OS_WINDOWS_MOBILE #endif // GTEST_HAS_STREAM_REDIRECTION // Determines whether to support death tests. -// Google Test does not support death tests for VC 7.1 and earlier as -// abort() in a VC 7.1 application compiled as GUI in debug config // pops up a dialog window that cannot be suppressed programmatically. -#if (GTEST_OS_LINUX || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS || \ - (GTEST_OS_MAC && !GTEST_OS_IOS) || \ - (GTEST_OS_WINDOWS_DESKTOP && _MSC_VER >= 1400) || \ - GTEST_OS_WINDOWS_MINGW || GTEST_OS_AIX || GTEST_OS_HPUX || \ - GTEST_OS_OPENBSD || GTEST_OS_QNX || GTEST_OS_FREEBSD || \ - GTEST_OS_NETBSD || GTEST_OS_FUCHSIA) +#if (GTEST_OS_LINUX || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS || \ + (GTEST_OS_MAC && !GTEST_OS_IOS) || \ + (GTEST_OS_WINDOWS_DESKTOP && _MSC_VER) || GTEST_OS_WINDOWS_MINGW || \ + GTEST_OS_AIX || GTEST_OS_HPUX || GTEST_OS_OPENBSD || GTEST_OS_QNX || \ + GTEST_OS_FREEBSD || GTEST_OS_NETBSD || GTEST_OS_FUCHSIA || \ + GTEST_OS_DRAGONFLY || GTEST_OS_GNU_KFREEBSD || GTEST_OS_HAIKU) # define GTEST_HAS_DEATH_TEST 1 #endif @@ -837,26 +604,19 @@ typedef struct _RTL_CRITICAL_SECTION GTEST_CRITICAL_SECTION; // Typed tests need <typeinfo> and variadic macros, which GCC, VC++ 8.0, // Sun Pro CC, IBM Visual Age, and HP aCC support. -#if defined(__GNUC__) || (_MSC_VER >= 1400) || defined(__SUNPRO_CC) || \ +#if defined(__GNUC__) || defined(_MSC_VER) || defined(__SUNPRO_CC) || \ defined(__IBMCPP__) || defined(__HP_aCC) # define GTEST_HAS_TYPED_TEST 1 # define GTEST_HAS_TYPED_TEST_P 1 #endif -// Determines whether to support Combine(). This only makes sense when -// value-parameterized tests are enabled. The implementation doesn't -// work on Sun Studio since it doesn't understand templated conversion -// operators. -#if (GTEST_HAS_TR1_TUPLE || GTEST_HAS_STD_TUPLE_) && !defined(__SUNPRO_CC) -# define GTEST_HAS_COMBINE 1 -#endif - // Determines whether the system compiler uses UTF-16 for encoding wide strings. #define GTEST_WIDE_STRING_USES_UTF16_ \ - (GTEST_OS_WINDOWS || GTEST_OS_CYGWIN || GTEST_OS_SYMBIAN || GTEST_OS_AIX) + (GTEST_OS_WINDOWS || GTEST_OS_CYGWIN || GTEST_OS_AIX || GTEST_OS_OS2) // Determines whether test results can be streamed to a socket. -#if GTEST_OS_LINUX +#if GTEST_OS_LINUX || GTEST_OS_GNU_KFREEBSD || GTEST_OS_DRAGONFLY || \ + GTEST_OS_FREEBSD || GTEST_OS_NETBSD || GTEST_OS_OPENBSD # define GTEST_CAN_STREAM_RESULTS_ 1 #endif @@ -898,12 +658,6 @@ typedef struct _RTL_CRITICAL_SECTION GTEST_CRITICAL_SECTION; # define GTEST_ATTRIBUTE_UNUSED_ #endif -#if GTEST_LANG_CXX11 -# define GTEST_CXX11_EQUALS_DELETE_ = delete -#else // GTEST_LANG_CXX11 -# define GTEST_CXX11_EQUALS_DELETE_ -#endif // GTEST_LANG_CXX11 - // Use this annotation before a function that takes a printf format string. #if (defined(__GNUC__) || defined(__clang__)) && !defined(COMPILER_ICC) # if defined(__MINGW_PRINTF_FORMAT) @@ -925,12 +679,12 @@ typedef struct _RTL_CRITICAL_SECTION GTEST_CRITICAL_SECTION; // A macro to disallow operator= // This should be used in the private: declarations for a class. #define GTEST_DISALLOW_ASSIGN_(type) \ - void operator=(type const &) GTEST_CXX11_EQUALS_DELETE_ + void operator=(type const &) = delete // A macro to disallow copy constructor and operator= // This should be used in the private: declarations for a class. #define GTEST_DISALLOW_COPY_AND_ASSIGN_(type) \ - type(type const &) GTEST_CXX11_EQUALS_DELETE_; \ + type(type const &) = delete; \ GTEST_DISALLOW_ASSIGN_(type) // Tell the compiler to warn about unused return values for functions declared @@ -938,11 +692,11 @@ typedef struct _RTL_CRITICAL_SECTION GTEST_CRITICAL_SECTION; // following the argument list: // // Sprocket* AllocateSprocket() GTEST_MUST_USE_RESULT_; -#if defined(__GNUC__) && (GTEST_GCC_VER_ >= 30400) && !defined(COMPILER_ICC) +#if defined(__GNUC__) && !defined(COMPILER_ICC) # define GTEST_MUST_USE_RESULT_ __attribute__ ((warn_unused_result)) #else # define GTEST_MUST_USE_RESULT_ -#endif // __GNUC__ && (GTEST_GCC_VER_ >= 30400) && !COMPILER_ICC +#endif // __GNUC__ && !COMPILER_ICC // MS C++ compiler emits warning when a conditional expression is compile time // constant. In some contexts this warning is false positive and needs to be @@ -971,13 +725,17 @@ typedef struct _RTL_CRITICAL_SECTION GTEST_CRITICAL_SECTION; # define GTEST_HAS_SEH 0 # endif -#define GTEST_IS_THREADSAFE \ - (GTEST_HAS_MUTEX_AND_THREAD_LOCAL_ \ - || (GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT) \ - || GTEST_HAS_PTHREAD) - #endif // GTEST_HAS_SEH +#ifndef GTEST_IS_THREADSAFE + +#define GTEST_IS_THREADSAFE \ + (GTEST_HAS_MUTEX_AND_THREAD_LOCAL_ || \ + (GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT) || \ + GTEST_HAS_PTHREAD) + +#endif // GTEST_IS_THREADSAFE + // GTEST_API_ qualifies all symbols that must be exported. The definitions below // are guarded by #ifndef to give embedders a chance to define GTEST_API_ in // gtest/internal/custom/gtest-port.h @@ -1044,6 +802,18 @@ typedef struct _RTL_CRITICAL_SECTION GTEST_CRITICAL_SECTION; # define GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ #endif // __clang__ +// A function level attribute to disable HWAddressSanitizer instrumentation. +#if defined(__clang__) +# if __has_feature(hwaddress_sanitizer) +# define GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_ \ + __attribute__((no_sanitize("hwaddress"))) +# else +# define GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_ +# endif // __has_feature(hwaddress_sanitizer) +#else +# define GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_ +#endif // __clang__ + // A function level attribute to disable ThreadSanitizer instrumentation. #if defined(__clang__) # if __has_feature(thread_sanitizer) @@ -1060,16 +830,13 @@ namespace testing { class Message; -#if defined(GTEST_TUPLE_NAMESPACE_) -// Import tuple and friends into the ::testing namespace. -// It is part of our interface, having them in ::testing allows us to change -// their types as needed. -using GTEST_TUPLE_NAMESPACE_::get; -using GTEST_TUPLE_NAMESPACE_::make_tuple; -using GTEST_TUPLE_NAMESPACE_::tuple; -using GTEST_TUPLE_NAMESPACE_::tuple_size; -using GTEST_TUPLE_NAMESPACE_::tuple_element; -#endif // defined(GTEST_TUPLE_NAMESPACE_) +// Legacy imports for backwards compatibility. +// New code should use std:: names directly. +using std::get; +using std::make_tuple; +using std::tuple; +using std::tuple_element; +using std::tuple_size; namespace internal { @@ -1078,158 +845,24 @@ namespace internal { // Secret object, which is what we want. class Secret; -// The GTEST_COMPILE_ASSERT_ macro can be used to verify that a compile time -// expression is true. For example, you could use it to verify the -// size of a static array: +// The GTEST_COMPILE_ASSERT_ is a legacy macro used to verify that a compile +// time expression is true (in new code, use static_assert instead). For +// example, you could use it to verify the size of a static array: // // GTEST_COMPILE_ASSERT_(GTEST_ARRAY_SIZE_(names) == NUM_NAMES, // names_incorrect_size); // -// or to make sure a struct is smaller than a certain size: -// -// GTEST_COMPILE_ASSERT_(sizeof(foo) < 128, foo_too_large); -// -// The second argument to the macro is the name of the variable. If -// the expression is false, most compilers will issue a warning/error -// containing the name of the variable. - -#if GTEST_LANG_CXX11 -# define GTEST_COMPILE_ASSERT_(expr, msg) static_assert(expr, #msg) -#else // !GTEST_LANG_CXX11 -template <bool> - struct CompileAssert { -}; - -# define GTEST_COMPILE_ASSERT_(expr, msg) \ - typedef ::testing::internal::CompileAssert<(static_cast<bool>(expr))> \ - msg[static_cast<bool>(expr) ? 1 : -1] GTEST_ATTRIBUTE_UNUSED_ -#endif // !GTEST_LANG_CXX11 - -// Implementation details of GTEST_COMPILE_ASSERT_: -// -// (In C++11, we simply use static_assert instead of the following) -// -// - GTEST_COMPILE_ASSERT_ works by defining an array type that has -1 -// elements (and thus is invalid) when the expression is false. -// -// - The simpler definition -// -// #define GTEST_COMPILE_ASSERT_(expr, msg) typedef char msg[(expr) ? 1 : -1] -// -// does not work, as gcc supports variable-length arrays whose sizes -// are determined at run-time (this is gcc's extension and not part -// of the C++ standard). As a result, gcc fails to reject the -// following code with the simple definition: -// -// int foo; -// GTEST_COMPILE_ASSERT_(foo, msg); // not supposed to compile as foo is -// // not a compile-time constant. -// -// - By using the type CompileAssert<(bool(expr))>, we ensures that -// expr is a compile-time constant. (Template arguments must be -// determined at compile-time.) -// -// - The outter parentheses in CompileAssert<(bool(expr))> are necessary -// to work around a bug in gcc 3.4.4 and 4.0.1. If we had written -// -// CompileAssert<bool(expr)> -// -// instead, these compilers will refuse to compile -// -// GTEST_COMPILE_ASSERT_(5 > 0, some_message); -// -// (They seem to think the ">" in "5 > 0" marks the end of the -// template argument list.) -// -// - The array size is (bool(expr) ? 1 : -1), instead of simply -// -// ((expr) ? 1 : -1). -// -// This is to avoid running into a bug in MS VC 7.1, which -// causes ((0.0) ? 1 : -1) to incorrectly evaluate to 1. - -// StaticAssertTypeEqHelper is used by StaticAssertTypeEq defined in gtest.h. -// -// This template is declared, but intentionally undefined. -template <typename T1, typename T2> -struct StaticAssertTypeEqHelper; - -template <typename T> -struct StaticAssertTypeEqHelper<T, T> { - enum { value = true }; -}; - -// Same as std::is_same<>. -template <typename T, typename U> -struct IsSame { - enum { value = false }; -}; -template <typename T> -struct IsSame<T, T> { - enum { value = true }; -}; +// The second argument to the macro must be a valid C++ identifier. If the +// expression is false, compiler will issue an error containing this identifier. +#define GTEST_COMPILE_ASSERT_(expr, msg) static_assert(expr, #msg) // Evaluates to the number of elements in 'array'. #define GTEST_ARRAY_SIZE_(array) (sizeof(array) / sizeof(array[0])) -#if GTEST_HAS_GLOBAL_STRING -typedef ::string string; -#else -typedef ::std::string string; -#endif // GTEST_HAS_GLOBAL_STRING - -#if GTEST_HAS_GLOBAL_WSTRING -typedef ::wstring wstring; -#elif GTEST_HAS_STD_WSTRING -typedef ::std::wstring wstring; -#endif // GTEST_HAS_GLOBAL_WSTRING - // A helper for suppressing warnings on constant condition. It just // returns 'condition'. GTEST_API_ bool IsTrue(bool condition); -// Defines scoped_ptr. - -// This implementation of scoped_ptr is PARTIAL - it only contains -// enough stuff to satisfy Google Test's need. -template <typename T> -class scoped_ptr { - public: - typedef T element_type; - - explicit scoped_ptr(T* p = NULL) : ptr_(p) {} - ~scoped_ptr() { reset(); } - - T& operator*() const { return *ptr_; } - T* operator->() const { return ptr_; } - T* get() const { return ptr_; } - - T* release() { - T* const ptr = ptr_; - ptr_ = NULL; - return ptr; - } - - void reset(T* p = NULL) { - if (p != ptr_) { - if (IsTrue(sizeof(T) > 0)) { // Makes sure T is a complete type. - delete ptr_; - } - ptr_ = p; - } - } - - friend void swap(scoped_ptr& a, scoped_ptr& b) { - using std::swap; - swap(a.ptr_, b.ptr_); - } - - private: - T* ptr_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(scoped_ptr); -}; - // Defines RE. #if GTEST_USES_PCRE @@ -1247,25 +880,16 @@ class GTEST_API_ RE { // Constructs an RE from a string. RE(const ::std::string& regex) { Init(regex.c_str()); } // NOLINT -# if GTEST_HAS_GLOBAL_STRING - - RE(const ::string& regex) { Init(regex.c_str()); } // NOLINT - -# endif // GTEST_HAS_GLOBAL_STRING - RE(const char* regex) { Init(regex); } // NOLINT ~RE(); // Returns the string representation of the regex. const char* pattern() const { return pattern_; } - // FullMatch(str, re) returns true iff regular expression re matches - // the entire str. - // PartialMatch(str, re) returns true iff regular expression re + // FullMatch(str, re) returns true if and only if regular expression re + // matches the entire str. + // PartialMatch(str, re) returns true if and only if regular expression re // matches a substring of str (including str itself). - // - // FIXME: make FullMatch() and PartialMatch() work - // when str contains NUL characters. static bool FullMatch(const ::std::string& str, const RE& re) { return FullMatch(str.c_str(), re); } @@ -1273,26 +897,11 @@ class GTEST_API_ RE { return PartialMatch(str.c_str(), re); } -# if GTEST_HAS_GLOBAL_STRING - - static bool FullMatch(const ::string& str, const RE& re) { - return FullMatch(str.c_str(), re); - } - static bool PartialMatch(const ::string& str, const RE& re) { - return PartialMatch(str.c_str(), re); - } - -# endif // GTEST_HAS_GLOBAL_STRING - static bool FullMatch(const char* str, const RE& re); static bool PartialMatch(const char* str, const RE& re); private: void Init(const char* regex); - - // We use a const char* instead of an std::string, as Google Test used to be - // used where std::string is not available. FIXME: change to - // std::string. const char* pattern_; bool is_valid_; @@ -1360,7 +969,7 @@ class GTEST_API_ GTestLog { __FILE__, __LINE__).GetStream() inline void LogToStderr() {} -inline void FlushInfoLog() { fflush(NULL); } +inline void FlushInfoLog() { fflush(nullptr); } #endif // !defined(GTEST_LOG_) @@ -1397,19 +1006,6 @@ inline void FlushInfoLog() { fflush(NULL); } GTEST_LOG_(FATAL) << #posix_call << "failed with error " \ << gtest_error -// Adds reference to a type if it is not a reference type, -// otherwise leaves it unchanged. This is the same as -// tr1::add_reference, which is not widely available yet. -template <typename T> -struct AddReference { typedef T& type; }; // NOLINT -template <typename T> -struct AddReference<T&> { typedef T& type; }; // NOLINT - -// A handy wrapper around AddReference that works when the argument T -// depends on template parameters. -#define GTEST_ADD_REFERENCE_(T) \ - typename ::testing::internal::AddReference<T>::type - // Transforms "T" into "const T&" according to standard reference collapsing // rules (this is only needed as a backport for C++98 compilers that do not // support reference collapsing). Specifically, it transforms: @@ -1430,28 +1026,6 @@ struct ConstRef<T&> { typedef T& type; }; #define GTEST_REFERENCE_TO_CONST_(T) \ typename ::testing::internal::ConstRef<T>::type -#if GTEST_HAS_STD_MOVE_ -using std::forward; -using std::move; - -template <typename T> -struct RvalueRef { - typedef T&& type; -}; -#else // GTEST_HAS_STD_MOVE_ -template <typename T> -const T& move(const T& t) { - return t; -} -template <typename T> -GTEST_ADD_REFERENCE_(T) forward(GTEST_ADD_REFERENCE_(T) t) { return t; } - -template <typename T> -struct RvalueRef { - typedef const T& type; -}; -#endif // GTEST_HAS_STD_MOVE_ - // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Use ImplicitCast_ as a safe version of static_cast for upcasting in @@ -1505,13 +1079,13 @@ inline To DownCast_(From* f) { // so we only accept pointers GTEST_INTENTIONAL_CONST_COND_PUSH_() if (false) { GTEST_INTENTIONAL_CONST_COND_POP_() - const To to = NULL; - ::testing::internal::ImplicitCast_<From*>(to); + const To to = nullptr; + ::testing::internal::ImplicitCast_<From*>(to); } #if GTEST_HAS_RTTI // RTTI: debug mode only! - GTEST_CHECK_(f == NULL || dynamic_cast<To>(f) != NULL); + GTEST_CHECK_(f == nullptr || dynamic_cast<To>(f) != nullptr); #endif return static_cast<To>(f); } @@ -1565,9 +1139,6 @@ std::vector<std::string> GetInjectableArgvs(); // Deprecated: pass the args vector by value instead. void SetInjectableArgvs(const std::vector<std::string>* new_argvs); void SetInjectableArgvs(const std::vector<std::string>& new_argvs); -#if GTEST_HAS_GLOBAL_STRING -void SetInjectableArgvs(const std::vector< ::string>& new_argvs); -#endif // GTEST_HAS_GLOBAL_STRING void ClearInjectableArgvs(); #endif // GTEST_HAS_DEATH_TEST @@ -1583,7 +1154,7 @@ inline void SleepMilliseconds(int n) { 0, // 0 seconds. n * 1000L * 1000L, // And n ms. }; - nanosleep(&time, NULL); + nanosleep(&time, nullptr); } # endif // GTEST_HAS_PTHREAD @@ -1601,7 +1172,7 @@ inline void SleepMilliseconds(int n) { class Notification { public: Notification() : notified_(false) { - GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, NULL)); + GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, nullptr)); } ~Notification() { pthread_mutex_destroy(&mutex_); @@ -1659,7 +1230,8 @@ class GTEST_API_ AutoHandle { void Reset(Handle handle); private: - // Returns true iff the handle is a valid handle object that can be closed. + // Returns true if and only if the handle is a valid handle object that can be + // closed. bool IsCloseable() const; Handle handle_; @@ -1710,7 +1282,7 @@ class ThreadWithParamBase { // pass into pthread_create(). extern "C" inline void* ThreadFuncWithCLinkage(void* thread) { static_cast<ThreadWithParamBase*>(thread)->Run(); - return NULL; + return nullptr; } // Helper class for testing Google Test's multi-threading constructs. @@ -1739,20 +1311,19 @@ class ThreadWithParam : public ThreadWithParamBase { // The thread can be created only after all fields except thread_ // have been initialized. GTEST_CHECK_POSIX_SUCCESS_( - pthread_create(&thread_, 0, &ThreadFuncWithCLinkage, base)); + pthread_create(&thread_, nullptr, &ThreadFuncWithCLinkage, base)); } - ~ThreadWithParam() { Join(); } + ~ThreadWithParam() override { Join(); } void Join() { if (!finished_) { - GTEST_CHECK_POSIX_SUCCESS_(pthread_join(thread_, 0)); + GTEST_CHECK_POSIX_SUCCESS_(pthread_join(thread_, nullptr)); finished_ = true; } } - virtual void Run() { - if (thread_can_start_ != NULL) - thread_can_start_->WaitForNotification(); + void Run() override { + if (thread_can_start_ != nullptr) thread_can_start_->WaitForNotification(); func_(param_); } @@ -1762,7 +1333,8 @@ class ThreadWithParam : public ThreadWithParamBase { // When non-NULL, used to block execution until the controller thread // notifies. Notification* const thread_can_start_; - bool finished_; // true iff we know that the thread function has finished. + bool finished_; // true if and only if we know that the thread function has + // finished. pthread_t thread_; // The native thread object. GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadWithParam); @@ -2046,7 +1618,7 @@ class ThreadLocal : public ThreadLocalBase { GTEST_DISALLOW_COPY_AND_ASSIGN_(InstanceValueHolderFactory); }; - scoped_ptr<ValueHolderFactory> default_factory_; + std::unique_ptr<ValueHolderFactory> default_factory_; GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocal); }; @@ -2115,7 +1687,7 @@ class MutexBase { class Mutex : public MutexBase { public: Mutex() { - GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, NULL)); + GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, nullptr)); has_owner_ = false; } ~Mutex() { @@ -2213,7 +1785,7 @@ class GTEST_API_ ThreadLocal { T* GetOrCreateValue() const { ThreadLocalValueHolderBase* const holder = static_cast<ThreadLocalValueHolderBase*>(pthread_getspecific(key_)); - if (holder != NULL) { + if (holder != nullptr) { return CheckedDowncastToActualType<ValueHolder>(holder)->pointer(); } @@ -2257,7 +1829,7 @@ class GTEST_API_ ThreadLocal { // A key pthreads uses for looking up per-thread values. const pthread_key_t key_; - scoped_ptr<ValueHolderFactory> default_factory_; + std::unique_ptr<ValueHolderFactory> default_factory_; GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocal); }; @@ -2315,67 +1887,8 @@ class GTEST_API_ ThreadLocal { // we cannot detect it. GTEST_API_ size_t GetThreadCount(); -// Passing non-POD classes through ellipsis (...) crashes the ARM -// compiler and generates a warning in Sun Studio before 12u4. The Nokia Symbian -// and the IBM XL C/C++ compiler try to instantiate a copy constructor -// for objects passed through ellipsis (...), failing for uncopyable -// objects. We define this to ensure that only POD is passed through -// ellipsis on these systems. -#if defined(__SYMBIAN32__) || defined(__IBMCPP__) || \ - (defined(__SUNPRO_CC) && __SUNPRO_CC < 0x5130) -// We lose support for NULL detection where the compiler doesn't like -// passing non-POD classes through ellipsis (...). -# define GTEST_ELLIPSIS_NEEDS_POD_ 1 -#else -# define GTEST_CAN_COMPARE_NULL 1 -#endif - -// The Nokia Symbian and IBM XL C/C++ compilers cannot decide between -// const T& and const T* in a function template. These compilers -// _can_ decide between class template specializations for T and T*, -// so a tr1::type_traits-like is_pointer works. -#if defined(__SYMBIAN32__) || defined(__IBMCPP__) -# define GTEST_NEEDS_IS_POINTER_ 1 -#endif - -template <bool bool_value> -struct bool_constant { - typedef bool_constant<bool_value> type; - static const bool value = bool_value; -}; -template <bool bool_value> const bool bool_constant<bool_value>::value; - -typedef bool_constant<false> false_type; -typedef bool_constant<true> true_type; - -template <typename T, typename U> -struct is_same : public false_type {}; - -template <typename T> -struct is_same<T, T> : public true_type {}; - - -template <typename T> -struct is_pointer : public false_type {}; - -template <typename T> -struct is_pointer<T*> : public true_type {}; - -template <typename Iterator> -struct IteratorTraits { - typedef typename Iterator::value_type value_type; -}; - - -template <typename T> -struct IteratorTraits<T*> { - typedef T value_type; -}; - -template <typename T> -struct IteratorTraits<const T*> { - typedef T value_type; -}; +template <bool B> +using bool_constant = std::integral_constant<bool, B>; #if GTEST_OS_WINDOWS # define GTEST_PATH_SEP_ "\\" @@ -2535,12 +2048,12 @@ inline const char* GetEnv(const char* name) { #if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_PHONE || GTEST_OS_WINDOWS_RT // We are on Windows CE, which has no environment variables. static_cast<void>(name); // To prevent 'unused argument' warning. - return NULL; + return nullptr; #elif defined(__BORLANDC__) || defined(__SunOS_5_8) || defined(__SunOS_5_9) // Environment variables which we programmatically clear will be set to the // empty string rather than unset (NULL). Handle that case. const char* const env = getenv(name); - return (env != NULL && env[0] != '\0') ? env : NULL; + return (env != nullptr && env[0] != '\0') ? env : nullptr; #else return getenv(name); #endif @@ -2552,9 +2065,9 @@ GTEST_DISABLE_MSC_DEPRECATED_POP_() // Windows CE has no C library. The abort() function is used in // several places in Google Test. This implementation provides a reasonable // imitation of standard behaviour. -void Abort(); +[[noreturn]] void Abort(); #else -inline void Abort() { abort(); } +[[noreturn]] inline void Abort() { abort(); } #endif // GTEST_OS_WINDOWS_MOBILE } // namespace posix @@ -2564,13 +2077,12 @@ inline void Abort() { abort(); } // MSVC-based platforms. We map the GTEST_SNPRINTF_ macro to the appropriate // function in order to achieve that. We use macro definition here because // snprintf is a variadic function. -#if _MSC_VER >= 1400 && !GTEST_OS_WINDOWS_MOBILE +#if _MSC_VER && !GTEST_OS_WINDOWS_MOBILE // MSVC 2005 and above support variadic macros. # define GTEST_SNPRINTF_(buffer, size, format, ...) \ _snprintf_s(buffer, size, size, format, __VA_ARGS__) #elif defined(_MSC_VER) -// Windows CE does not define _snprintf_s and MSVC prior to 2005 doesn't -// complain about _snprintf. +// Windows CE does not define _snprintf_s # define GTEST_SNPRINTF_ _snprintf #else # define GTEST_SNPRINTF_ snprintf @@ -2684,9 +2196,6 @@ typedef TypeWithSize<8>::Int TimeInMillis; // Represents time in milliseconds. // Parses 'str' for a 32-bit signed integer. If successful, writes the result // to *value and returns true; otherwise leaves *value unchanged and returns // false. -// FIXME: Find a better way to refactor flag and environment parsing -// out of both gtest-port.cc and gtest.cc to avoid exporting this utility -// function. bool ParseInt32(const Message& src_text, const char* str, Int32* value); // Parses a bool/Int32/string from the environment variable @@ -2699,4 +2208,24 @@ const char* StringFromGTestEnv(const char* flag, const char* default_val); } // namespace internal } // namespace testing +#if !defined(GTEST_INTERNAL_DEPRECATED) + +// Internal Macro to mark an API deprecated, for googletest usage only +// Usage: class GTEST_INTERNAL_DEPRECATED(message) MyClass or +// GTEST_INTERNAL_DEPRECATED(message) <return_type> myFunction(); Every usage of +// a deprecated entity will trigger a warning when compiled with +// `-Wdeprecated-declarations` option (clang, gcc, any __GNUC__ compiler). +// For msvc /W3 option will need to be used +// Note that for 'other' compilers this macro evaluates to nothing to prevent +// compilations errors. +#if defined(_MSC_VER) +#define GTEST_INTERNAL_DEPRECATED(message) __declspec(deprecated(message)) +#elif defined(__GNUC__) +#define GTEST_INTERNAL_DEPRECATED(message) __attribute__((deprecated(message))) +#else +#define GTEST_INTERNAL_DEPRECATED(message) +#endif + +#endif // !defined(GTEST_INTERNAL_DEPRECATED) + #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/internal/gtest-string.h b/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/internal/gtest-string.h index 4c9b6262c3c..82aaa63bf46 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/internal/gtest-string.h +++ b/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/internal/gtest-string.h @@ -94,7 +94,8 @@ class GTEST_API_ String { static const char* Utf16ToAnsi(LPCWSTR utf16_str); #endif - // Compares two C strings. Returns true iff they have the same content. + // Compares two C strings. Returns true if and only if they have the same + // content. // // Unlike strcmp(), this function can handle NULL argument(s). A // NULL C string is considered different to any non-NULL C string, @@ -107,16 +108,16 @@ class GTEST_API_ String { // returned. static std::string ShowWideCString(const wchar_t* wide_c_str); - // Compares two wide C strings. Returns true iff they have the same - // content. + // Compares two wide C strings. Returns true if and only if they have the + // same content. // // Unlike wcscmp(), this function can handle NULL argument(s). A // NULL C string is considered different to any non-NULL C string, // including the empty string. static bool WideCStringEquals(const wchar_t* lhs, const wchar_t* rhs); - // Compares two C strings, ignoring case. Returns true iff they - // have the same content. + // Compares two C strings, ignoring case. Returns true if and only if + // they have the same content. // // Unlike strcasecmp(), this function can handle NULL argument(s). // A NULL C string is considered different to any non-NULL C string, @@ -124,8 +125,8 @@ class GTEST_API_ String { static bool CaseInsensitiveCStringEquals(const char* lhs, const char* rhs); - // Compares two wide C strings, ignoring case. Returns true iff they - // have the same content. + // Compares two wide C strings, ignoring case. Returns true if and only if + // they have the same content. // // Unlike wcscasecmp(), this function can handle NULL argument(s). // A NULL C string is considered different to any non-NULL wide C string, @@ -139,8 +140,8 @@ class GTEST_API_ String { static bool CaseInsensitiveWideCStringEquals(const wchar_t* lhs, const wchar_t* rhs); - // Returns true iff the given string ends with the given suffix, ignoring - // case. Any string is considered to end with an empty suffix. + // Returns true if and only if the given string ends with the given suffix, + // ignoring case. Any string is considered to end with an empty suffix. static bool EndsWithCaseInsensitive( const std::string& str, const std::string& suffix); @@ -150,6 +151,9 @@ class GTEST_API_ String { // Formats an int value as "%X". static std::string FormatHexInt(int value); + // Formats an int value as "%X". + static std::string FormatHexUInt32(UInt32 value); + // Formats a byte as "%02X". static std::string FormatByte(unsigned char value); diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/internal/gtest-type-util.h b/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/internal/gtest-type-util.h index 28e41124536..3d7542d1fb3 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/internal/gtest-type-util.h +++ b/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/internal/gtest-type-util.h @@ -31,12 +31,11 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - // Type utilities needed for implementing typed and type-parameterized // tests. This file is generated by a SCRIPT. DO NOT EDIT BY HAND! // // Currently we support at most 50 types in a list, and at most 50 -// type-parameterized tests in one type-parameterized test case. +// type-parameterized tests in one type-parameterized test suite. // Please contact googletestframework@googlegroups.com if you need // more. @@ -89,7 +88,7 @@ std::string GetTypeName() { # if GTEST_HAS_CXXABI_H_ using abi::__cxa_demangle; # endif // GTEST_HAS_CXXABI_H_ - char* const readable_name = __cxa_demangle(name, 0, 0, &status); + char* const readable_name = __cxa_demangle(name, nullptr, nullptr, &status); const std::string name_str(status == 0 ? readable_name : name); free(readable_name); return CanonicalizeForStdLibVersioning(name_str); @@ -106,18 +105,6 @@ std::string GetTypeName() { #if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P -// AssertyTypeEq<T1, T2>::type is defined iff T1 and T2 are the same -// type. This can be used as a compile-time assertion to ensure that -// two types are equal. - -template <typename T1, typename T2> -struct AssertTypeEq; - -template <typename T> -struct AssertTypeEq<T, T> { - typedef bool type; -}; - // A unique type used as the default value for the arguments of class // template Types. This allows us to simulate variadic templates // (e.g. Types<int>, Type<int, double>, and etc), which C++ doesn't @@ -3312,8 +3299,8 @@ struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, }; // The TypeList template makes it possible to use either a single type -// or a Types<...> list in TYPED_TEST_CASE() and -// INSTANTIATE_TYPED_TEST_CASE_P(). +// or a Types<...> list in TYPED_TEST_SUITE() and +// INSTANTIATE_TYPED_TEST_SUITE_P(). template <typename T> struct TypeList { diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/src/gtest-all.cc b/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/src/gtest-all.cc index b217a18006b..ad292905cf3 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/src/gtest-all.cc +++ b/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/src/gtest-all.cc @@ -41,6 +41,7 @@ #include "src/gtest.cc" #include "src/gtest-death-test.cc" #include "src/gtest-filepath.cc" +#include "src/gtest-matchers.cc" #include "src/gtest-port.cc" #include "src/gtest-printers.cc" #include "src/gtest-test-part.cc" diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/src/gtest-death-test.cc b/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/src/gtest-death-test.cc index 09083551612..da09a1cfc23 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/src/gtest-death-test.cc +++ b/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/src/gtest-death-test.cc @@ -31,6 +31,9 @@ // This file implements death tests. #include "gtest/gtest-death-test.h" + +#include <utility> + #include "gtest/internal/gtest-port.h" #include "gtest/internal/custom/gtest.h" @@ -62,10 +65,16 @@ # endif // GTEST_OS_QNX # if GTEST_OS_FUCHSIA +# include <lib/fdio/fd.h> # include <lib/fdio/io.h> # include <lib/fdio/spawn.h> +# include <lib/zx/channel.h> +# include <lib/zx/port.h> +# include <lib/zx/process.h> +# include <lib/zx/socket.h> # include <zircon/processargs.h> # include <zircon/syscalls.h> +# include <zircon/syscalls/policy.h> # include <zircon/syscalls/port.h> # endif // GTEST_OS_FUCHSIA @@ -113,8 +122,8 @@ GTEST_DEFINE_string_( "Indicates the file, line number, temporal index of " "the single death test to run, and a file descriptor to " "which a success code may be sent, all separated by " - "the '|' characters. This flag is specified if and only if the current " - "process is a sub-process launched for running a thread-safe " + "the '|' characters. This flag is specified if and only if the " + "current process is a sub-process launched for running a thread-safe " "death test. FOR INTERNAL USE ONLY."); } // namespace internal @@ -266,8 +275,6 @@ static const int kFuchsiaReadPipeFd = 3; // statement, which is not allowed; THREW means that the test statement // returned control by throwing an exception. IN_PROGRESS means the test // has not yet concluded. -// FIXME: Unify names and possibly values for -// AbortReason, DeathTestOutcome, and flag characters above. enum DeathTestOutcome { IN_PROGRESS, DIED, LIVED, RETURNED, THREW }; // Routine for aborting the program which is safe to call from an @@ -281,7 +288,7 @@ static void DeathTestAbort(const std::string& message) { // the heap for any additional non-minuscule memory requirements. const InternalRunDeathTestFlag* const flag = GetUnitTestImpl()->internal_run_death_test_flag(); - if (flag != NULL) { + if (flag != nullptr) { FILE* parent = posix::FDOpen(flag->write_fd(), "w"); fputc(kDeathTestInternalError, parent); fprintf(parent, "%s", message.c_str()); @@ -361,7 +368,7 @@ static void FailFromInternalError(int fd) { // for the current test. DeathTest::DeathTest() { TestInfo* const info = GetUnitTestImpl()->current_test_info(); - if (info == NULL) { + if (info == nullptr) { DeathTestAbort("Cannot run a death test outside of a TEST or " "TEST_F construct"); } @@ -369,10 +376,11 @@ DeathTest::DeathTest() { // Creates and returns a death test by dispatching to the current // death test factory. -bool DeathTest::Create(const char* statement, const RE* regex, - const char* file, int line, DeathTest** test) { +bool DeathTest::Create(const char* statement, + Matcher<const std::string&> matcher, const char* file, + int line, DeathTest** test) { return GetUnitTestImpl()->death_test_factory()->Create( - statement, regex, file, line, test); + statement, std::move(matcher), file, line, test); } const char* DeathTest::LastMessage() { @@ -388,9 +396,9 @@ std::string DeathTest::last_death_test_message_; // Provides cross platform implementation for some death functionality. class DeathTestImpl : public DeathTest { protected: - DeathTestImpl(const char* a_statement, const RE* a_regex) + DeathTestImpl(const char* a_statement, Matcher<const std::string&> matcher) : statement_(a_statement), - regex_(a_regex), + matcher_(std::move(matcher)), spawned_(false), status_(-1), outcome_(IN_PROGRESS), @@ -398,13 +406,12 @@ class DeathTestImpl : public DeathTest { write_fd_(-1) {} // read_fd_ is expected to be closed and cleared by a derived class. - ~DeathTestImpl() { GTEST_DEATH_TEST_CHECK_(read_fd_ == -1); } + ~DeathTestImpl() override { GTEST_DEATH_TEST_CHECK_(read_fd_ == -1); } - void Abort(AbortReason reason); - virtual bool Passed(bool status_ok); + void Abort(AbortReason reason) override; + bool Passed(bool status_ok) override; const char* statement() const { return statement_; } - const RE* regex() const { return regex_; } bool spawned() const { return spawned_; } void set_spawned(bool is_spawned) { spawned_ = is_spawned; } int status() const { return status_; } @@ -422,13 +429,15 @@ class DeathTestImpl : public DeathTest { // case of unexpected codes. void ReadAndInterpretStatusByte(); + // Returns stderr output from the child process. + virtual std::string GetErrorLogs(); + private: // The textual content of the code this object is testing. This class // doesn't own this string and should not attempt to delete it. const char* const statement_; - // The regular expression which test output must match. DeathTestImpl - // doesn't own this object and should not attempt to delete it. - const RE* const regex_; + // A matcher that's expected to match the stderr output by the child process. + Matcher<const std::string&> matcher_; // True if the death test child process has been successfully spawned. bool spawned_; // The exit status of the child process. @@ -490,6 +499,10 @@ void DeathTestImpl::ReadAndInterpretStatusByte() { set_read_fd(-1); } +std::string DeathTestImpl::GetErrorLogs() { + return GetCapturedStderr(); +} + // Signals that the death test code which should have exited, didn't. // Should be called only in a death test child process. // Writes a status byte to the child's status file descriptor, then @@ -543,22 +556,21 @@ static ::std::string FormatDeathTestOutput(const ::std::string& output) { // in the format specified by wait(2). On Windows, this is the // value supplied to the ExitProcess() API or a numeric code // of the exception that terminated the program. -// regex: A regular expression object to be applied to -// the test's captured standard error output; the death test -// fails if it does not match. +// matcher_: A matcher that's expected to match the stderr output by the child +// process. // // Argument: // status_ok: true if exit_status is acceptable in the context of // this particular death test, which fails if it is false // -// Returns true iff all of the above conditions are met. Otherwise, the -// first failing condition, in the order given above, is the one that is +// Returns true if and only if all of the above conditions are met. Otherwise, +// the first failing condition, in the order given above, is the one that is // reported. Also sets the last death test message string. bool DeathTestImpl::Passed(bool status_ok) { if (!spawned()) return false; - const std::string error_message = GetCapturedStderr(); + const std::string error_message = GetErrorLogs(); bool success = false; Message buffer; @@ -579,18 +591,15 @@ bool DeathTestImpl::Passed(bool status_ok) { break; case DIED: if (status_ok) { -# if GTEST_USES_PCRE - // PCRE regexes support embedded NULs. - const bool matched = RE::PartialMatch(error_message, *regex()); -# else - const bool matched = RE::PartialMatch(error_message.c_str(), *regex()); -# endif // GTEST_USES_PCRE - if (matched) { + if (matcher_.Matches(error_message)) { success = true; } else { + std::ostringstream stream; + matcher_.DescribeTo(&stream); buffer << " Result: died but not with expected error.\n" - << " Expected: " << regex()->pattern() << "\n" - << "Actual msg:\n" << FormatDeathTestOutput(error_message); + << " Expected: " << stream.str() << "\n" + << "Actual msg:\n" + << FormatDeathTestOutput(error_message); } } else { buffer << " Result: died but not with expected exit code:\n" @@ -639,11 +648,11 @@ bool DeathTestImpl::Passed(bool status_ok) { // class WindowsDeathTest : public DeathTestImpl { public: - WindowsDeathTest(const char* a_statement, - const RE* a_regex, - const char* file, - int line) - : DeathTestImpl(a_statement, a_regex), file_(file), line_(line) {} + WindowsDeathTest(const char* a_statement, Matcher<const std::string&> matcher, + const char* file, int line) + : DeathTestImpl(a_statement, std::move(matcher)), + file_(file), + line_(line) {} // All of these virtual functions are inherited from DeathTest. virtual int Wait(); @@ -720,7 +729,7 @@ DeathTest::TestRole WindowsDeathTest::AssumeRole() { const TestInfo* const info = impl->current_test_info(); const int death_test_index = info->result()->death_test_count(); - if (flag != NULL) { + if (flag != nullptr) { // ParseInternalRunDeathTestFlag() has performed all the necessary // processing. set_write_fd(flag->write_fd()); @@ -729,8 +738,8 @@ DeathTest::TestRole WindowsDeathTest::AssumeRole() { // WindowsDeathTest uses an anonymous pipe to communicate results of // a death test. - SECURITY_ATTRIBUTES handles_are_inheritable = { - sizeof(SECURITY_ATTRIBUTES), NULL, TRUE }; + SECURITY_ATTRIBUTES handles_are_inheritable = {sizeof(SECURITY_ATTRIBUTES), + nullptr, TRUE}; HANDLE read_handle, write_handle; GTEST_DEATH_TEST_CHECK_( ::CreatePipe(&read_handle, &write_handle, &handles_are_inheritable, @@ -741,13 +750,13 @@ DeathTest::TestRole WindowsDeathTest::AssumeRole() { write_handle_.Reset(write_handle); event_handle_.Reset(::CreateEvent( &handles_are_inheritable, - TRUE, // The event will automatically reset to non-signaled state. - FALSE, // The initial state is non-signalled. - NULL)); // The even is unnamed. - GTEST_DEATH_TEST_CHECK_(event_handle_.Get() != NULL); - const std::string filter_flag = - std::string("--") + GTEST_FLAG_PREFIX_ + kFilterFlag + "=" + - info->test_case_name() + "." + info->name(); + TRUE, // The event will automatically reset to non-signaled state. + FALSE, // The initial state is non-signalled. + nullptr)); // The even is unnamed. + GTEST_DEATH_TEST_CHECK_(event_handle_.Get() != nullptr); + const std::string filter_flag = std::string("--") + GTEST_FLAG_PREFIX_ + + kFilterFlag + "=" + info->test_suite_name() + + "." + info->name(); const std::string internal_flag = std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag + "=" + file_ + "|" + StreamableToString(line_) + "|" + @@ -760,10 +769,9 @@ DeathTest::TestRole WindowsDeathTest::AssumeRole() { "|" + StreamableToString(reinterpret_cast<size_t>(event_handle_.Get())); char executable_path[_MAX_PATH + 1]; // NOLINT - GTEST_DEATH_TEST_CHECK_( - _MAX_PATH + 1 != ::GetModuleFileNameA(NULL, - executable_path, - _MAX_PATH)); + GTEST_DEATH_TEST_CHECK_(_MAX_PATH + 1 != ::GetModuleFileNameA(nullptr, + executable_path, + _MAX_PATH)); std::string command_line = std::string(::GetCommandLineA()) + " " + filter_flag + " \"" + @@ -784,17 +792,16 @@ DeathTest::TestRole WindowsDeathTest::AssumeRole() { startup_info.hStdError = ::GetStdHandle(STD_ERROR_HANDLE); PROCESS_INFORMATION process_info; - GTEST_DEATH_TEST_CHECK_(::CreateProcessA( - executable_path, - const_cast<char*>(command_line.c_str()), - NULL, // Retuned process handle is not inheritable. - NULL, // Retuned thread handle is not inheritable. - TRUE, // Child inherits all inheritable handles (for write_handle_). - 0x0, // Default creation flags. - NULL, // Inherit the parent's environment. - UnitTest::GetInstance()->original_working_dir(), - &startup_info, - &process_info) != FALSE); + GTEST_DEATH_TEST_CHECK_( + ::CreateProcessA( + executable_path, const_cast<char*>(command_line.c_str()), + nullptr, // Retuned process handle is not inheritable. + nullptr, // Retuned thread handle is not inheritable. + TRUE, // Child inherits all inheritable handles (for write_handle_). + 0x0, // Default creation flags. + nullptr, // Inherit the parent's environment. + UnitTest::GetInstance()->original_working_dir(), &startup_info, + &process_info) != FALSE); child_handle_.Reset(process_info.hProcess); ::CloseHandle(process_info.hThread); set_spawned(true); @@ -805,38 +812,34 @@ DeathTest::TestRole WindowsDeathTest::AssumeRole() { class FuchsiaDeathTest : public DeathTestImpl { public: - FuchsiaDeathTest(const char* a_statement, - const RE* a_regex, - const char* file, - int line) - : DeathTestImpl(a_statement, a_regex), file_(file), line_(line) {} - virtual ~FuchsiaDeathTest() { - zx_status_t status = zx_handle_close(child_process_); - GTEST_DEATH_TEST_CHECK_(status == ZX_OK); - status = zx_handle_close(port_); - GTEST_DEATH_TEST_CHECK_(status == ZX_OK); - } + FuchsiaDeathTest(const char* a_statement, Matcher<const std::string&> matcher, + const char* file, int line) + : DeathTestImpl(a_statement, std::move(matcher)), + file_(file), + line_(line) {} // All of these virtual functions are inherited from DeathTest. - virtual int Wait(); - virtual TestRole AssumeRole(); + int Wait() override; + TestRole AssumeRole() override; + std::string GetErrorLogs() override; private: // The name of the file in which the death test is located. const char* const file_; // The line number on which the death test is located. const int line_; + // The stderr data captured by the child process. + std::string captured_stderr_; - zx_handle_t child_process_ = ZX_HANDLE_INVALID; - zx_handle_t port_ = ZX_HANDLE_INVALID; + zx::process child_process_; + zx::channel exception_channel_; + zx::socket stderr_socket_; }; // Utility class for accumulating command-line arguments. class Arguments { public: - Arguments() { - args_.push_back(NULL); - } + Arguments() { args_.push_back(nullptr); } ~Arguments() { for (std::vector<char*>::iterator i = args_.begin(); i != args_.end(); @@ -872,51 +875,88 @@ class Arguments { // status, or 0 if no child process exists. As a side effect, sets the // outcome data member. int FuchsiaDeathTest::Wait() { + const int kProcessKey = 0; + const int kSocketKey = 1; + const int kExceptionKey = 2; + if (!spawned()) return 0; - // Register to wait for the child process to terminate. + // Create a port to wait for socket/task/exception events. zx_status_t status_zx; - status_zx = zx_object_wait_async(child_process_, - port_, - 0 /* key */, - ZX_PROCESS_TERMINATED, - ZX_WAIT_ASYNC_ONCE); + zx::port port; + status_zx = zx::port::create(0, &port); GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); - // Wait for it to terminate, or an exception to be received. - zx_port_packet_t packet; - status_zx = zx_port_wait(port_, ZX_TIME_INFINITE, &packet); + // Register to wait for the child process to terminate. + status_zx = child_process_.wait_async( + port, kProcessKey, ZX_PROCESS_TERMINATED, ZX_WAIT_ASYNC_ONCE); GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); - if (ZX_PKT_IS_EXCEPTION(packet.type)) { - // Process encountered an exception. Kill it directly rather than letting - // other handlers process the event. - status_zx = zx_task_kill(child_process_); - GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); + // Register to wait for the socket to be readable or closed. + status_zx = stderr_socket_.wait_async( + port, kSocketKey, ZX_SOCKET_READABLE | ZX_SOCKET_PEER_CLOSED, + ZX_WAIT_ASYNC_ONCE); + GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); - // Now wait for |child_process_| to terminate. - zx_signals_t signals = 0; - status_zx = zx_object_wait_one( - child_process_, ZX_PROCESS_TERMINATED, ZX_TIME_INFINITE, &signals); + // Register to wait for an exception. + status_zx = exception_channel_.wait_async( + port, kExceptionKey, ZX_CHANNEL_READABLE, ZX_WAIT_ASYNC_ONCE); + GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); + + bool process_terminated = false; + bool socket_closed = false; + do { + zx_port_packet_t packet = {}; + status_zx = port.wait(zx::time::infinite(), &packet); GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); - GTEST_DEATH_TEST_CHECK_(signals & ZX_PROCESS_TERMINATED); - } else { - // Process terminated. - GTEST_DEATH_TEST_CHECK_(ZX_PKT_IS_SIGNAL_ONE(packet.type)); - GTEST_DEATH_TEST_CHECK_(packet.signal.observed & ZX_PROCESS_TERMINATED); - } + + if (packet.key == kExceptionKey) { + // Process encountered an exception. Kill it directly rather than + // letting other handlers process the event. We will get a kProcessKey + // event when the process actually terminates. + status_zx = child_process_.kill(); + GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); + } else if (packet.key == kProcessKey) { + // Process terminated. + GTEST_DEATH_TEST_CHECK_(ZX_PKT_IS_SIGNAL_ONE(packet.type)); + GTEST_DEATH_TEST_CHECK_(packet.signal.observed & ZX_PROCESS_TERMINATED); + process_terminated = true; + } else if (packet.key == kSocketKey) { + GTEST_DEATH_TEST_CHECK_(ZX_PKT_IS_SIGNAL_ONE(packet.type)); + if (packet.signal.observed & ZX_SOCKET_READABLE) { + // Read data from the socket. + constexpr size_t kBufferSize = 1024; + do { + size_t old_length = captured_stderr_.length(); + size_t bytes_read = 0; + captured_stderr_.resize(old_length + kBufferSize); + status_zx = stderr_socket_.read( + 0, &captured_stderr_.front() + old_length, kBufferSize, + &bytes_read); + captured_stderr_.resize(old_length + bytes_read); + } while (status_zx == ZX_OK); + if (status_zx == ZX_ERR_PEER_CLOSED) { + socket_closed = true; + } else { + GTEST_DEATH_TEST_CHECK_(status_zx == ZX_ERR_SHOULD_WAIT); + status_zx = stderr_socket_.wait_async( + port, kSocketKey, ZX_SOCKET_READABLE | ZX_SOCKET_PEER_CLOSED, + ZX_WAIT_ASYNC_ONCE); + GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); + } + } else { + GTEST_DEATH_TEST_CHECK_(packet.signal.observed & ZX_SOCKET_PEER_CLOSED); + socket_closed = true; + } + } + } while (!process_terminated && !socket_closed); ReadAndInterpretStatusByte(); zx_info_process_t buffer; - status_zx = zx_object_get_info( - child_process_, - ZX_INFO_PROCESS, - &buffer, - sizeof(buffer), - nullptr, - nullptr); + status_zx = child_process_.get_info( + ZX_INFO_PROCESS, &buffer, sizeof(buffer), nullptr, nullptr); GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); GTEST_DEATH_TEST_CHECK_(buffer.exited); @@ -936,21 +976,20 @@ DeathTest::TestRole FuchsiaDeathTest::AssumeRole() { const TestInfo* const info = impl->current_test_info(); const int death_test_index = info->result()->death_test_count(); - if (flag != NULL) { + if (flag != nullptr) { // ParseInternalRunDeathTestFlag() has performed all the necessary // processing. set_write_fd(kFuchsiaReadPipeFd); return EXECUTE_TEST; } - CaptureStderr(); // Flush the log buffers since the log streams are shared with the child. FlushInfoLog(); // Build the child process command line. - const std::string filter_flag = - std::string("--") + GTEST_FLAG_PREFIX_ + kFilterFlag + "=" - + info->test_case_name() + "." + info->name(); + const std::string filter_flag = std::string("--") + GTEST_FLAG_PREFIX_ + + kFilterFlag + "=" + info->test_suite_name() + + "." + info->name(); const std::string internal_flag = std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag + "=" + file_ + "|" @@ -964,35 +1003,68 @@ DeathTest::TestRole FuchsiaDeathTest::AssumeRole() { // Build the pipe for communication with the child. zx_status_t status; zx_handle_t child_pipe_handle; - uint32_t type; - status = fdio_pipe_half(&child_pipe_handle, &type); - GTEST_DEATH_TEST_CHECK_(status >= 0); - set_read_fd(status); + int child_pipe_fd; + status = fdio_pipe_half(&child_pipe_fd, &child_pipe_handle); + GTEST_DEATH_TEST_CHECK_(status == ZX_OK); + set_read_fd(child_pipe_fd); // Set the pipe handle for the child. - fdio_spawn_action_t add_handle_action = {}; - add_handle_action.action = FDIO_SPAWN_ACTION_ADD_HANDLE; - add_handle_action.h.id = PA_HND(type, kFuchsiaReadPipeFd); - add_handle_action.h.handle = child_pipe_handle; + fdio_spawn_action_t spawn_actions[2] = {}; + fdio_spawn_action_t* add_handle_action = &spawn_actions[0]; + add_handle_action->action = FDIO_SPAWN_ACTION_ADD_HANDLE; + add_handle_action->h.id = PA_HND(PA_FD, kFuchsiaReadPipeFd); + add_handle_action->h.handle = child_pipe_handle; + + // Create a socket pair will be used to receive the child process' stderr. + zx::socket stderr_producer_socket; + status = + zx::socket::create(0, &stderr_producer_socket, &stderr_socket_); + GTEST_DEATH_TEST_CHECK_(status >= 0); + int stderr_producer_fd = -1; + status = + fdio_fd_create(stderr_producer_socket.release(), &stderr_producer_fd); + GTEST_DEATH_TEST_CHECK_(status >= 0); - // Spawn the child process. - status = fdio_spawn_etc(ZX_HANDLE_INVALID, FDIO_SPAWN_CLONE_ALL, - args.Argv()[0], args.Argv(), nullptr, 1, - &add_handle_action, &child_process_, nullptr); + // Make the stderr socket nonblocking. + GTEST_DEATH_TEST_CHECK_(fcntl(stderr_producer_fd, F_SETFL, 0) == 0); + + fdio_spawn_action_t* add_stderr_action = &spawn_actions[1]; + add_stderr_action->action = FDIO_SPAWN_ACTION_CLONE_FD; + add_stderr_action->fd.local_fd = stderr_producer_fd; + add_stderr_action->fd.target_fd = STDERR_FILENO; + + // Create a child job. + zx_handle_t child_job = ZX_HANDLE_INVALID; + status = zx_job_create(zx_job_default(), 0, & child_job); + GTEST_DEATH_TEST_CHECK_(status == ZX_OK); + zx_policy_basic_t policy; + policy.condition = ZX_POL_NEW_ANY; + policy.policy = ZX_POL_ACTION_ALLOW; + status = zx_job_set_policy( + child_job, ZX_JOB_POL_RELATIVE, ZX_JOB_POL_BASIC, &policy, 1); GTEST_DEATH_TEST_CHECK_(status == ZX_OK); - // Create an exception port and attach it to the |child_process_|, to allow + // Create an exception channel attached to the |child_job|, to allow // us to suppress the system default exception handler from firing. - status = zx_port_create(0, &port_); + status = + zx_task_create_exception_channel( + child_job, 0, exception_channel_.reset_and_get_address()); GTEST_DEATH_TEST_CHECK_(status == ZX_OK); - status = zx_task_bind_exception_port( - child_process_, port_, 0 /* key */, 0 /*options */); + + // Spawn the child process. + status = fdio_spawn_etc( + child_job, FDIO_SPAWN_CLONE_ALL, args.Argv()[0], args.Argv(), nullptr, + 2, spawn_actions, child_process_.reset_and_get_address(), nullptr); GTEST_DEATH_TEST_CHECK_(status == ZX_OK); set_spawned(true); return OVERSEE_TEST; } +std::string FuchsiaDeathTest::GetErrorLogs() { + return captured_stderr_; +} + #else // We are neither on Windows, nor on Fuchsia. // ForkingDeathTest provides implementations for most of the abstract @@ -1000,10 +1072,10 @@ DeathTest::TestRole FuchsiaDeathTest::AssumeRole() { // left undefined. class ForkingDeathTest : public DeathTestImpl { public: - ForkingDeathTest(const char* statement, const RE* regex); + ForkingDeathTest(const char* statement, Matcher<const std::string&> matcher); // All of these virtual functions are inherited from DeathTest. - virtual int Wait(); + int Wait() override; protected: void set_child_pid(pid_t child_pid) { child_pid_ = child_pid; } @@ -1014,9 +1086,9 @@ class ForkingDeathTest : public DeathTestImpl { }; // Constructs a ForkingDeathTest. -ForkingDeathTest::ForkingDeathTest(const char* a_statement, const RE* a_regex) - : DeathTestImpl(a_statement, a_regex), - child_pid_(-1) {} +ForkingDeathTest::ForkingDeathTest(const char* a_statement, + Matcher<const std::string&> matcher) + : DeathTestImpl(a_statement, std::move(matcher)), child_pid_(-1) {} // Waits for the child in a death test to exit, returning its exit // status, or 0 if no child process exists. As a side effect, sets the @@ -1037,9 +1109,9 @@ int ForkingDeathTest::Wait() { // in the child process. class NoExecDeathTest : public ForkingDeathTest { public: - NoExecDeathTest(const char* a_statement, const RE* a_regex) : - ForkingDeathTest(a_statement, a_regex) { } - virtual TestRole AssumeRole(); + NoExecDeathTest(const char* a_statement, Matcher<const std::string&> matcher) + : ForkingDeathTest(a_statement, std::move(matcher)) {} + TestRole AssumeRole() override; }; // The AssumeRole process for a fork-and-run death test. It implements a @@ -1092,10 +1164,13 @@ DeathTest::TestRole NoExecDeathTest::AssumeRole() { // only this specific death test to be run. class ExecDeathTest : public ForkingDeathTest { public: - ExecDeathTest(const char* a_statement, const RE* a_regex, - const char* file, int line) : - ForkingDeathTest(a_statement, a_regex), file_(file), line_(line) { } - virtual TestRole AssumeRole(); + ExecDeathTest(const char* a_statement, Matcher<const std::string&> matcher, + const char* file, int line) + : ForkingDeathTest(a_statement, std::move(matcher)), + file_(file), + line_(line) {} + TestRole AssumeRole() override; + private: static ::std::vector<std::string> GetArgvsForDeathTestChildProcess() { ::std::vector<std::string> args = GetInjectableArgvs(); @@ -1115,9 +1190,7 @@ class ExecDeathTest : public ForkingDeathTest { // Utility class for accumulating command-line arguments. class Arguments { public: - Arguments() { - args_.push_back(NULL); - } + Arguments() { args_.push_back(nullptr); } ~Arguments() { for (std::vector<char*>::iterator i = args_.begin(); i != args_.end(); @@ -1211,6 +1284,9 @@ static int ExecDeathTestChildMain(void* child_arg) { // correct answer. static void StackLowerThanAddress(const void* ptr, bool* result) GTEST_NO_INLINE_; +// HWAddressSanitizer add a random tag to the MSB of the local variable address, +// making comparison result unpredictable. +GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_ static void StackLowerThanAddress(const void* ptr, bool* result) { int dummy; *result = (&dummy < ptr); @@ -1218,6 +1294,7 @@ static void StackLowerThanAddress(const void* ptr, bool* result) { // Make sure AddressSanitizer does not tamper with the stack here. GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ +GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_ static bool StackGrowsDown() { int dummy; bool result; @@ -1262,7 +1339,8 @@ static pid_t ExecDeathTestSpawnChild(char* const* argv, int close_fd) { fd_flags | FD_CLOEXEC)); struct inheritance inherit = {0}; // spawn is a system call. - child_pid = spawn(args.argv[0], 0, NULL, &inherit, args.argv, GetEnviron()); + child_pid = + spawn(args.argv[0], 0, nullptr, &inherit, args.argv, GetEnviron()); // Restores the current working directory. GTEST_DEATH_TEST_CHECK_(fchdir(cwd_fd) != -1); GTEST_DEATH_TEST_CHECK_SYSCALL_(close(cwd_fd)); @@ -1286,9 +1364,9 @@ static pid_t ExecDeathTestSpawnChild(char* const* argv, int close_fd) { if (!use_fork) { static const bool stack_grows_down = StackGrowsDown(); - const size_t stack_size = getpagesize(); + const auto stack_size = static_cast<size_t>(getpagesize()); // MMAP_ANONYMOUS is not defined on Mac, so we use MAP_ANON instead. - void* const stack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE, + void* const stack = mmap(nullptr, stack_size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); GTEST_DEATH_TEST_CHECK_(stack != MAP_FAILED); @@ -1302,8 +1380,9 @@ static pid_t ExecDeathTestSpawnChild(char* const* argv, int close_fd) { void* const stack_top = static_cast<char*>(stack) + (stack_grows_down ? stack_size - kMaxStackAlignment : 0); - GTEST_DEATH_TEST_CHECK_(stack_size > kMaxStackAlignment && - reinterpret_cast<intptr_t>(stack_top) % kMaxStackAlignment == 0); + GTEST_DEATH_TEST_CHECK_( + static_cast<size_t>(stack_size) > kMaxStackAlignment && + reinterpret_cast<uintptr_t>(stack_top) % kMaxStackAlignment == 0); child_pid = clone(&ExecDeathTestChildMain, stack_top, SIGCHLD, &args); @@ -1320,7 +1399,7 @@ static pid_t ExecDeathTestSpawnChild(char* const* argv, int close_fd) { # endif // GTEST_OS_QNX # if GTEST_OS_LINUX GTEST_DEATH_TEST_CHECK_SYSCALL_( - sigaction(SIGPROF, &saved_sigprof_action, NULL)); + sigaction(SIGPROF, &saved_sigprof_action, nullptr)); # endif // GTEST_OS_LINUX GTEST_DEATH_TEST_CHECK_(child_pid != -1); @@ -1338,7 +1417,7 @@ DeathTest::TestRole ExecDeathTest::AssumeRole() { const TestInfo* const info = impl->current_test_info(); const int death_test_index = info->result()->death_test_count(); - if (flag != NULL) { + if (flag != nullptr) { set_write_fd(flag->write_fd()); return EXECUTE_TEST; } @@ -1349,9 +1428,9 @@ DeathTest::TestRole ExecDeathTest::AssumeRole() { // it be closed when the child process does an exec: GTEST_DEATH_TEST_CHECK_(fcntl(pipe_fd[1], F_SETFD, 0) != -1); - const std::string filter_flag = - std::string("--") + GTEST_FLAG_PREFIX_ + kFilterFlag + "=" - + info->test_case_name() + "." + info->name(); + const std::string filter_flag = std::string("--") + GTEST_FLAG_PREFIX_ + + kFilterFlag + "=" + info->test_suite_name() + + "." + info->name(); const std::string internal_flag = std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag + "=" + file_ + "|" + StreamableToString(line_) + "|" @@ -1384,7 +1463,8 @@ DeathTest::TestRole ExecDeathTest::AssumeRole() { // by the "test" argument to its address. If the test should be // skipped, sets that pointer to NULL. Returns true, unless the // flag is set to an invalid value. -bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex, +bool DefaultDeathTestFactory::Create(const char* statement, + Matcher<const std::string&> matcher, const char* file, int line, DeathTest** test) { UnitTestImpl* const impl = GetUnitTestImpl(); @@ -1393,7 +1473,7 @@ bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex, const int death_test_index = impl->current_test_info() ->increment_death_test_count(); - if (flag != NULL) { + if (flag != nullptr) { if (death_test_index > flag->index()) { DeathTest::set_last_death_test_message( "Death test count (" + StreamableToString(death_test_index) @@ -1404,7 +1484,7 @@ bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex, if (!(flag->file() == file && flag->line() == line && flag->index() == death_test_index)) { - *test = NULL; + *test = nullptr; return true; } } @@ -1413,22 +1493,22 @@ bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex, if (GTEST_FLAG(death_test_style) == "threadsafe" || GTEST_FLAG(death_test_style) == "fast") { - *test = new WindowsDeathTest(statement, regex, file, line); + *test = new WindowsDeathTest(statement, std::move(matcher), file, line); } # elif GTEST_OS_FUCHSIA if (GTEST_FLAG(death_test_style) == "threadsafe" || GTEST_FLAG(death_test_style) == "fast") { - *test = new FuchsiaDeathTest(statement, regex, file, line); + *test = new FuchsiaDeathTest(statement, std::move(matcher), file, line); } # else if (GTEST_FLAG(death_test_style) == "threadsafe") { - *test = new ExecDeathTest(statement, regex, file, line); + *test = new ExecDeathTest(statement, std::move(matcher), file, line); } else if (GTEST_FLAG(death_test_style) == "fast") { - *test = new NoExecDeathTest(statement, regex); + *test = new NoExecDeathTest(statement, std::move(matcher)); } # endif // GTEST_OS_WINDOWS @@ -1458,8 +1538,6 @@ static int GetStatusFileDescriptor(unsigned int parent_process_id, StreamableToString(parent_process_id)); } - // FIXME: Replace the following check with a - // compile-time assertion when available. GTEST_CHECK_(sizeof(HANDLE) <= sizeof(size_t)); const HANDLE write_handle = @@ -1515,7 +1593,7 @@ static int GetStatusFileDescriptor(unsigned int parent_process_id, // initialized from the GTEST_FLAG(internal_run_death_test) flag if // the flag is specified; otherwise returns NULL. InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag() { - if (GTEST_FLAG(internal_run_death_test) == "") return NULL; + if (GTEST_FLAG(internal_run_death_test) == "") return nullptr; // GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we // can use it here. diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/src/gtest-filepath.cc b/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/src/gtest-filepath.cc index a7e65c082a7..bd7b99ff03e 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/src/gtest-filepath.cc +++ b/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/src/gtest-filepath.cc @@ -38,9 +38,6 @@ #elif GTEST_OS_WINDOWS # include <direct.h> # include <io.h> -#elif GTEST_OS_SYMBIAN -// Symbian OpenC has PATH_MAX in sys/syslimits.h -# include <sys/syslimits.h> #else # include <limits.h> # include <climits> // Some Linux distributions define PATH_MAX here. @@ -95,13 +92,14 @@ static bool IsPathSeparator(char c) { // Returns the current working directory, or "" if unsuccessful. FilePath FilePath::GetCurrentDir() { -#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_PHONE || GTEST_OS_WINDOWS_RT - // Windows CE doesn't have a current directory, so we just return +#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_PHONE || \ + GTEST_OS_WINDOWS_RT || ARDUINO || defined(ESP_PLATFORM) + // These platforms do not have a current directory, so we just return // something reasonable. return FilePath(kCurrentDirectoryString); #elif GTEST_OS_WINDOWS char cwd[GTEST_PATH_MAX_ + 1] = { '\0' }; - return FilePath(_getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd); + return FilePath(_getcwd(cwd, sizeof(cwd)) == nullptr ? "" : cwd); #else char cwd[GTEST_PATH_MAX_ + 1] = { '\0' }; char* result = getcwd(cwd, sizeof(cwd)); @@ -109,9 +107,9 @@ FilePath FilePath::GetCurrentDir() { // getcwd will likely fail in NaCl due to the sandbox, so return something // reasonable. The user may have provided a shim implementation for getcwd, // however, so fallback only when failure is detected. - return FilePath(result == NULL ? kCurrentDirectoryString : cwd); + return FilePath(result == nullptr ? kCurrentDirectoryString : cwd); # endif // GTEST_OS_NACL - return FilePath(result == NULL ? "" : cwd); + return FilePath(result == nullptr ? "" : cwd); #endif // GTEST_OS_WINDOWS_MOBILE } @@ -136,8 +134,8 @@ const char* FilePath::FindLastPathSeparator() const { #if GTEST_HAS_ALT_PATH_SEP_ const char* const last_alt_sep = strrchr(c_str(), kAlternatePathSeparator); // Comparing two pointers of which only one is NULL is undefined. - if (last_alt_sep != NULL && - (last_sep == NULL || last_alt_sep > last_sep)) { + if (last_alt_sep != nullptr && + (last_sep == nullptr || last_alt_sep > last_sep)) { return last_alt_sep; } #endif @@ -165,7 +163,7 @@ FilePath FilePath::RemoveFileName() const { const char* const last_sep = FindLastPathSeparator(); std::string dir; if (last_sep) { - dir = std::string(c_str(), last_sep + 1 - c_str()); + dir = std::string(c_str(), static_cast<size_t>(last_sep + 1 - c_str())); } else { dir = kCurrentDirectoryString; } @@ -250,9 +248,6 @@ bool FilePath::DirectoryExists() const { // root directory per disk drive.) bool FilePath::IsRootDirectory() const { #if GTEST_OS_WINDOWS - // FIXME: on Windows a network share like - // \\server\share can be a root directory, although it cannot be the - // current directory. Handle this properly. return pathname_.length() == 3 && IsAbsolutePath(); #else return pathname_.length() == 1 && IsPathSeparator(pathname_.c_str()[0]); @@ -324,7 +319,7 @@ bool FilePath::CreateFolder() const { #if GTEST_OS_WINDOWS_MOBILE FilePath removed_sep(this->RemoveTrailingPathSeparator()); LPCWSTR unicode = String::AnsiToUtf16(removed_sep.c_str()); - int result = CreateDirectory(unicode, NULL) ? 0 : -1; + int result = CreateDirectory(unicode, nullptr) ? 0 : -1; delete [] unicode; #elif GTEST_OS_WINDOWS int result = _mkdir(pathname_.c_str()); @@ -350,9 +345,8 @@ FilePath FilePath::RemoveTrailingPathSeparator() const { // Removes any redundant separators that might be in the pathname. // For example, "bar///foo" becomes "bar/foo". Does not eliminate other // redundancies that might be in a pathname involving "." or "..". -// FIXME: handle Windows network shares (e.g. \\server\share). void FilePath::Normalize() { - if (pathname_.c_str() == NULL) { + if (pathname_.c_str() == nullptr) { pathname_ = ""; return; } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/src/gtest-internal-inl.h b/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/src/gtest-internal-inl.h index 479004149b4..8ed70daab09 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/src/gtest-internal-inl.h +++ b/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/src/gtest-internal-inl.h @@ -42,6 +42,7 @@ #include <string.h> // For memmove. #include <algorithm> +#include <memory> #include <string> #include <vector> @@ -98,14 +99,14 @@ const char kFlagfileFlag[] = "flagfile"; // A valid random seed must be in [1, kMaxRandomSeed]. const int kMaxRandomSeed = 99999; -// g_help_flag is true iff the --help flag or an equivalent form is -// specified on the command line. +// g_help_flag is true if and only if the --help flag or an equivalent form +// is specified on the command line. GTEST_API_ extern bool g_help_flag; // Returns the current time in milliseconds. GTEST_API_ TimeInMillis GetTimeInMillis(); -// Returns true iff Google Test should use colors in the output. +// Returns true if and only if Google Test should use colors in the output. GTEST_API_ bool ShouldUseColor(bool stdout_is_tty); // Formats the given time in milliseconds as seconds. @@ -230,7 +231,7 @@ GTEST_API_ std::string CodePointToUtf8(UInt32 code_point); // Converts a wide string to a narrow string in UTF-8 encoding. // The wide string is assumed to have the following encoding: -// UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin, Symbian OS) +// UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin) // UTF-32 if sizeof(wchar_t) == 4 (on Linux) // Parameter str points to a null-terminated wide string. // Parameter num_chars may additionally limit the number @@ -265,8 +266,8 @@ GTEST_API_ bool ShouldShard(const char* total_shards_str, GTEST_API_ Int32 Int32FromEnvOrDie(const char* env_var, Int32 default_val); // Given the total number of shards, the shard index, and the test id, -// returns true iff the test should be run on this shard. The test id is -// some arbitrary but unique non-negative integer assigned to each test +// returns true if and only if the test should be run on this shard. The test id +// is some arbitrary but unique non-negative integer assigned to each test // method. Assumes that 0 <= shard_index < total_shards. GTEST_API_ bool ShouldRunTestOnShard( int total_shards, int shard_index, int test_id); @@ -297,7 +298,8 @@ void ForEach(const Container& c, Functor functor) { // in range [0, v.size()). template <typename E> inline E GetElementOr(const std::vector<E>& v, int i, E default_value) { - return (i < 0 || i >= static_cast<int>(v.size())) ? default_value : v[i]; + return (i < 0 || i >= static_cast<int>(v.size())) ? default_value + : v[static_cast<size_t>(i)]; } // Performs an in-place shuffle of a range of the vector's elements. @@ -319,8 +321,11 @@ void ShuffleRange(internal::Random* random, int begin, int end, // http://en.wikipedia.org/wiki/Fisher-Yates_shuffle for (int range_width = end - begin; range_width >= 2; range_width--) { const int last_in_range = begin + range_width - 1; - const int selected = begin + random->Generate(range_width); - std::swap((*v)[selected], (*v)[last_in_range]); + const int selected = + begin + + static_cast<int>(random->Generate(static_cast<UInt32>(range_width))); + std::swap((*v)[static_cast<size_t>(selected)], + (*v)[static_cast<size_t>(last_in_range)]); } } @@ -347,7 +352,7 @@ class TestPropertyKeyIs { // TestPropertyKeyIs has NO default constructor. explicit TestPropertyKeyIs(const std::string& key) : key_(key) {} - // Returns true iff the test name of test property matches on key_. + // Returns true if and only if the test name of test property matches on key_. bool operator()(const TestProperty& test_property) const { return test_property.key() == key_; } @@ -380,17 +385,17 @@ class GTEST_API_ UnitTestOptions { // Functions for processing the gtest_filter flag. - // Returns true iff the wildcard pattern matches the string. The - // first ':' or '\0' character in pattern marks the end of it. + // Returns true if and only if the wildcard pattern matches the string. + // The first ':' or '\0' character in pattern marks the end of it. // // This recursive algorithm isn't very efficient, but is clear and // works well enough for matching test names, which are short. static bool PatternMatchesString(const char *pattern, const char *str); - // Returns true iff the user-specified filter matches the test case - // name and the test name. - static bool FilterMatchesTest(const std::string &test_case_name, - const std::string &test_name); + // Returns true if and only if the user-specified filter matches the test + // suite name and the test name. + static bool FilterMatchesTest(const std::string& test_suite_name, + const std::string& test_name); #if GTEST_OS_WINDOWS // Function for supporting the gtest_catch_exception flag. @@ -442,8 +447,8 @@ class OsStackTraceGetter : public OsStackTraceGetterInterface { public: OsStackTraceGetter() {} - virtual std::string CurrentStackTrace(int max_depth, int skip_count); - virtual void UponLeavingGTest(); + std::string CurrentStackTrace(int max_depth, int skip_count) override; + void UponLeavingGTest() override; private: #if GTEST_HAS_ABSL @@ -474,7 +479,7 @@ class DefaultGlobalTestPartResultReporter explicit DefaultGlobalTestPartResultReporter(UnitTestImpl* unit_test); // Implements the TestPartResultReporterInterface. Reports the test part // result in the current test. - virtual void ReportTestPartResult(const TestPartResult& result); + void ReportTestPartResult(const TestPartResult& result) override; private: UnitTestImpl* const unit_test_; @@ -490,7 +495,7 @@ class DefaultPerThreadTestPartResultReporter explicit DefaultPerThreadTestPartResultReporter(UnitTestImpl* unit_test); // Implements the TestPartResultReporterInterface. The implementation just // delegates to the current global test part result reporter of *unit_test_. - virtual void ReportTestPartResult(const TestPartResult& result); + void ReportTestPartResult(const TestPartResult& result) override; private: UnitTestImpl* const unit_test_; @@ -528,22 +533,25 @@ class GTEST_API_ UnitTestImpl { void SetTestPartResultReporterForCurrentThread( TestPartResultReporterInterface* reporter); - // Gets the number of successful test cases. - int successful_test_case_count() const; + // Gets the number of successful test suites. + int successful_test_suite_count() const; - // Gets the number of failed test cases. - int failed_test_case_count() const; + // Gets the number of failed test suites. + int failed_test_suite_count() const; - // Gets the number of all test cases. - int total_test_case_count() const; + // Gets the number of all test suites. + int total_test_suite_count() const; - // Gets the number of all test cases that contain at least one test + // Gets the number of all test suites that contain at least one test // that should run. - int test_case_to_run_count() const; + int test_suite_to_run_count() const; // Gets the number of successful tests. int successful_test_count() const; + // Gets the number of skipped tests. + int skipped_test_count() const; + // Gets the number of failed tests. int failed_test_count() const; @@ -569,27 +577,33 @@ class GTEST_API_ UnitTestImpl { // Gets the elapsed time, in milliseconds. TimeInMillis elapsed_time() const { return elapsed_time_; } - // Returns true iff the unit test passed (i.e. all test cases passed). + // Returns true if and only if the unit test passed (i.e. all test suites + // passed). bool Passed() const { return !Failed(); } - // Returns true iff the unit test failed (i.e. some test case failed - // or something outside of all tests failed). + // Returns true if and only if the unit test failed (i.e. some test suite + // failed or something outside of all tests failed). bool Failed() const { - return failed_test_case_count() > 0 || ad_hoc_test_result()->Failed(); + return failed_test_suite_count() > 0 || ad_hoc_test_result()->Failed(); } - // Gets the i-th test case among all the test cases. i can range from 0 to - // total_test_case_count() - 1. If i is not in that range, returns NULL. - const TestCase* GetTestCase(int i) const { - const int index = GetElementOr(test_case_indices_, i, -1); - return index < 0 ? NULL : test_cases_[i]; + // Gets the i-th test suite among all the test suites. i can range from 0 to + // total_test_suite_count() - 1. If i is not in that range, returns NULL. + const TestSuite* GetTestSuite(int i) const { + const int index = GetElementOr(test_suite_indices_, i, -1); + return index < 0 ? nullptr : test_suites_[static_cast<size_t>(i)]; } - // Gets the i-th test case among all the test cases. i can range from 0 to - // total_test_case_count() - 1. If i is not in that range, returns NULL. - TestCase* GetMutableTestCase(int i) { - const int index = GetElementOr(test_case_indices_, i, -1); - return index < 0 ? NULL : test_cases_[index]; + // Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + const TestCase* GetTestCase(int i) const { return GetTestSuite(i); } +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + + // Gets the i-th test suite among all the test suites. i can range from 0 to + // total_test_suite_count() - 1. If i is not in that range, returns NULL. + TestSuite* GetMutableSuiteCase(int i) { + const int index = GetElementOr(test_suite_indices_, i, -1); + return index < 0 ? nullptr : test_suites_[static_cast<size_t>(index)]; } // Provides access to the event listener list. @@ -626,30 +640,38 @@ class GTEST_API_ UnitTestImpl { // trace but Bar() and CurrentOsStackTraceExceptTop() won't. std::string CurrentOsStackTraceExceptTop(int skip_count) GTEST_NO_INLINE_; - // Finds and returns a TestCase with the given name. If one doesn't + // Finds and returns a TestSuite with the given name. If one doesn't // exist, creates one and returns it. // // Arguments: // - // test_case_name: name of the test case + // test_suite_name: name of the test suite // type_param: the name of the test's type parameter, or NULL if // this is not a typed or a type-parameterized test. - // set_up_tc: pointer to the function that sets up the test case - // tear_down_tc: pointer to the function that tears down the test case - TestCase* GetTestCase(const char* test_case_name, - const char* type_param, - Test::SetUpTestCaseFunc set_up_tc, - Test::TearDownTestCaseFunc tear_down_tc); + // set_up_tc: pointer to the function that sets up the test suite + // tear_down_tc: pointer to the function that tears down the test suite + TestSuite* GetTestSuite(const char* test_suite_name, const char* type_param, + internal::SetUpTestSuiteFunc set_up_tc, + internal::TearDownTestSuiteFunc tear_down_tc); + +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + TestCase* GetTestCase(const char* test_case_name, const char* type_param, + internal::SetUpTestSuiteFunc set_up_tc, + internal::TearDownTestSuiteFunc tear_down_tc) { + return GetTestSuite(test_case_name, type_param, set_up_tc, tear_down_tc); + } +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ // Adds a TestInfo to the unit test. // // Arguments: // - // set_up_tc: pointer to the function that sets up the test case - // tear_down_tc: pointer to the function that tears down the test case + // set_up_tc: pointer to the function that sets up the test suite + // tear_down_tc: pointer to the function that tears down the test suite // test_info: the TestInfo object - void AddTestInfo(Test::SetUpTestCaseFunc set_up_tc, - Test::TearDownTestCaseFunc tear_down_tc, + void AddTestInfo(internal::SetUpTestSuiteFunc set_up_tc, + internal::TearDownTestSuiteFunc tear_down_tc, TestInfo* test_info) { // In order to support thread-safe death tests, we need to // remember the original working directory when the test program @@ -664,21 +686,20 @@ class GTEST_API_ UnitTestImpl { << "Failed to get the current working directory."; } - GetTestCase(test_info->test_case_name(), - test_info->type_param(), - set_up_tc, - tear_down_tc)->AddTestInfo(test_info); + GetTestSuite(test_info->test_suite_name(), test_info->type_param(), + set_up_tc, tear_down_tc) + ->AddTestInfo(test_info); } - // Returns ParameterizedTestCaseRegistry object used to keep track of + // Returns ParameterizedTestSuiteRegistry object used to keep track of // value-parameterized tests and instantiate and register them. - internal::ParameterizedTestCaseRegistry& parameterized_test_registry() { + internal::ParameterizedTestSuiteRegistry& parameterized_test_registry() { return parameterized_test_registry_; } - // Sets the TestCase object for the test that's currently running. - void set_current_test_case(TestCase* a_current_test_case) { - current_test_case_ = a_current_test_case; + // Sets the TestSuite object for the test that's currently running. + void set_current_test_suite(TestSuite* a_current_test_suite) { + current_test_suite_ = a_current_test_suite; } // Sets the TestInfo object for the test that's currently running. If @@ -689,7 +710,7 @@ class GTEST_API_ UnitTestImpl { } // Registers all parameterized tests defined using TEST_P and - // INSTANTIATE_TEST_CASE_P, creating regular tests for each test/parameter + // INSTANTIATE_TEST_SUITE_P, creating regular tests for each test/parameter // combination. This method can be called more then once; it has guards // protecting from registering the tests more then once. If // value-parameterized tests are disabled, RegisterParameterizedTests is @@ -704,7 +725,7 @@ class GTEST_API_ UnitTestImpl { // Clears the results of all tests, except the ad hoc tests. void ClearNonAdHocTestResult() { - ForEach(test_cases_, TestCase::ClearTestCaseResult); + ForEach(test_suites_, TestSuite::ClearTestSuiteResult); } // Clears the results of ad-hoc test assertions. @@ -713,7 +734,7 @@ class GTEST_API_ UnitTestImpl { } // Adds a TestProperty to the current TestResult object when invoked in a - // context of a test or a test case, or to the global property set. If the + // context of a test or a test suite, or to the global property set. If the // result already contains a property with the same key, the value will be // updated. void RecordProperty(const TestProperty& test_property); @@ -725,7 +746,7 @@ class GTEST_API_ UnitTestImpl { // Matches the full name of each test against the user-specified // filter to decide whether the test should run, then records the - // result in each TestCase and TestInfo object. + // result in each TestSuite and TestInfo object. // If shard_tests == HONOR_SHARDING_PROTOCOL, further filters tests // based on sharding variables in the environment. // Returns the number of tests that should run. @@ -734,7 +755,7 @@ class GTEST_API_ UnitTestImpl { // Prints the names of the tests matching the user-specified filter flag. void ListTestsMatchingFilter(); - const TestCase* current_test_case() const { return current_test_case_; } + const TestSuite* current_test_suite() const { return current_test_suite_; } TestInfo* current_test_info() { return current_test_info_; } const TestInfo* current_test_info() const { return current_test_info_; } @@ -795,11 +816,11 @@ class GTEST_API_ UnitTestImpl { // Gets the random number generator. internal::Random* random() { return &random_; } - // Shuffles all test cases, and the tests within each test case, + // Shuffles all test suites, and the tests within each test suite, // making sure that death tests are still run first. void ShuffleTests(); - // Restores the test cases and tests to their order before the first shuffle. + // Restores the test suites and tests to their order before the first shuffle. void UnshuffleTests(); // Returns the value of GTEST_FLAG(catch_exceptions) at the moment @@ -839,31 +860,31 @@ class GTEST_API_ UnitTestImpl { // before/after the tests are run. std::vector<Environment*> environments_; - // The vector of TestCases in their original order. It owns the + // The vector of TestSuites in their original order. It owns the // elements in the vector. - std::vector<TestCase*> test_cases_; + std::vector<TestSuite*> test_suites_; - // Provides a level of indirection for the test case list to allow - // easy shuffling and restoring the test case order. The i-th - // element of this vector is the index of the i-th test case in the + // Provides a level of indirection for the test suite list to allow + // easy shuffling and restoring the test suite order. The i-th + // element of this vector is the index of the i-th test suite in the // shuffled order. - std::vector<int> test_case_indices_; + std::vector<int> test_suite_indices_; // ParameterizedTestRegistry object used to register value-parameterized // tests. - internal::ParameterizedTestCaseRegistry parameterized_test_registry_; + internal::ParameterizedTestSuiteRegistry parameterized_test_registry_; // Indicates whether RegisterParameterizedTests() has been called already. bool parameterized_tests_registered_; - // Index of the last death test case registered. Initially -1. - int last_death_test_case_; + // Index of the last death test suite registered. Initially -1. + int last_death_test_suite_; - // This points to the TestCase for the currently running test. It - // changes as Google Test goes through one test case after another. + // This points to the TestSuite for the currently running test. It + // changes as Google Test goes through one test suite after another. // When no test is running, this is set to NULL and Google Test // stores assertion results in ad_hoc_test_result_. Initially NULL. - TestCase* current_test_case_; + TestSuite* current_test_suite_; // This points to the TestInfo for the currently running test. It // changes as Google Test goes through one test after another. When @@ -891,7 +912,7 @@ class GTEST_API_ UnitTestImpl { // desired. OsStackTraceGetterInterface* os_stack_trace_getter_; - // True iff PostFlagParsingInit() has been called. + // True if and only if PostFlagParsingInit() has been called. bool post_flag_parse_init_performed_; // The random number seed used at the beginning of the test run. @@ -910,8 +931,8 @@ class GTEST_API_ UnitTestImpl { #if GTEST_HAS_DEATH_TEST // The decomposed components of the gtest_internal_run_death_test flag, // parsed when RUN_ALL_TESTS is called. - internal::scoped_ptr<InternalRunDeathTestFlag> internal_run_death_test_flag_; - internal::scoped_ptr<internal::DeathTestFactory> death_test_factory_; + std::unique_ptr<InternalRunDeathTestFlag> internal_run_death_test_flag_; + std::unique_ptr<internal::DeathTestFactory> death_test_factory_; #endif // GTEST_HAS_DEATH_TEST // A per-thread stack of traces created by the SCOPED_TRACE() macro. @@ -994,8 +1015,6 @@ bool ParseNaturalNumber(const ::std::string& str, Integer* number) { const bool parse_success = *end == '\0' && errno == 0; - // FIXME: Convert this to compile time assertion when it is - // available. GTEST_CHECK_(sizeof(Integer) <= sizeof(parsed)); const Integer result = static_cast<Integer>(parsed); @@ -1059,18 +1078,18 @@ class StreamingListener : public EmptyTestEventListener { MakeConnection(); } - virtual ~SocketWriter() { + ~SocketWriter() override { if (sockfd_ != -1) CloseConnection(); } // Sends a string to the socket. - virtual void Send(const std::string& message) { + void Send(const std::string& message) override { GTEST_CHECK_(sockfd_ != -1) << "Send() can be called only when there is a connection."; - const int len = static_cast<int>(message.length()); - if (write(sockfd_, message.c_str(), len) != len) { + const auto len = static_cast<size_t>(message.length()); + if (write(sockfd_, message.c_str(), len) != static_cast<ssize_t>(len)) { GTEST_LOG_(WARNING) << "stream_result_to: failed to stream to " << host_name_ << ":" << port_num_; @@ -1082,7 +1101,7 @@ class StreamingListener : public EmptyTestEventListener { void MakeConnection(); // Closes the socket. - void CloseConnection() { + void CloseConnection() override { GTEST_CHECK_(sockfd_ != -1) << "CloseConnection() can be called only when there is a connection."; @@ -1108,11 +1127,11 @@ class StreamingListener : public EmptyTestEventListener { explicit StreamingListener(AbstractSocketWriter* socket_writer) : socket_writer_(socket_writer) { Start(); } - void OnTestProgramStart(const UnitTest& /* unit_test */) { + void OnTestProgramStart(const UnitTest& /* unit_test */) override { SendLn("event=TestProgramStart"); } - void OnTestProgramEnd(const UnitTest& unit_test) { + void OnTestProgramEnd(const UnitTest& unit_test) override { // Note that Google Test current only report elapsed time for each // test iteration, not for the entire test program. SendLn("event=TestProgramEnd&passed=" + FormatBool(unit_test.Passed())); @@ -1121,42 +1140,47 @@ class StreamingListener : public EmptyTestEventListener { socket_writer_->CloseConnection(); } - void OnTestIterationStart(const UnitTest& /* unit_test */, int iteration) { + void OnTestIterationStart(const UnitTest& /* unit_test */, + int iteration) override { SendLn("event=TestIterationStart&iteration=" + StreamableToString(iteration)); } - void OnTestIterationEnd(const UnitTest& unit_test, int /* iteration */) { + void OnTestIterationEnd(const UnitTest& unit_test, + int /* iteration */) override { SendLn("event=TestIterationEnd&passed=" + FormatBool(unit_test.Passed()) + "&elapsed_time=" + StreamableToString(unit_test.elapsed_time()) + "ms"); } - void OnTestCaseStart(const TestCase& test_case) { + // Note that "event=TestCaseStart" is a wire format and has to remain + // "case" for compatibilty + void OnTestCaseStart(const TestCase& test_case) override { SendLn(std::string("event=TestCaseStart&name=") + test_case.name()); } - void OnTestCaseEnd(const TestCase& test_case) { - SendLn("event=TestCaseEnd&passed=" + FormatBool(test_case.Passed()) - + "&elapsed_time=" + StreamableToString(test_case.elapsed_time()) - + "ms"); + // Note that "event=TestCaseEnd" is a wire format and has to remain + // "case" for compatibilty + void OnTestCaseEnd(const TestCase& test_case) override { + SendLn("event=TestCaseEnd&passed=" + FormatBool(test_case.Passed()) + + "&elapsed_time=" + StreamableToString(test_case.elapsed_time()) + + "ms"); } - void OnTestStart(const TestInfo& test_info) { + void OnTestStart(const TestInfo& test_info) override { SendLn(std::string("event=TestStart&name=") + test_info.name()); } - void OnTestEnd(const TestInfo& test_info) { + void OnTestEnd(const TestInfo& test_info) override { SendLn("event=TestEnd&passed=" + FormatBool((test_info.result())->Passed()) + "&elapsed_time=" + StreamableToString((test_info.result())->elapsed_time()) + "ms"); } - void OnTestPartResult(const TestPartResult& test_part_result) { + void OnTestPartResult(const TestPartResult& test_part_result) override { const char* file_name = test_part_result.file_name(); - if (file_name == NULL) - file_name = ""; + if (file_name == nullptr) file_name = ""; SendLn("event=TestPartResult&file=" + UrlEncode(file_name) + "&line=" + StreamableToString(test_part_result.line_number()) + "&message=" + UrlEncode(test_part_result.message())); @@ -1172,7 +1196,7 @@ class StreamingListener : public EmptyTestEventListener { std::string FormatBool(bool value) { return value ? "1" : "0"; } - const scoped_ptr<AbstractSocketWriter> socket_writer_; + const std::unique_ptr<AbstractSocketWriter> socket_writer_; GTEST_DISALLOW_COPY_AND_ASSIGN_(StreamingListener); }; // class StreamingListener diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/src/gtest-port.cc b/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/src/gtest-port.cc index fecb5d11c21..fc5ba6becc5 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/src/gtest-port.cc +++ b/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/src/gtest-port.cc @@ -31,16 +31,20 @@ #include "gtest/internal/gtest-port.h" #include <limits.h> -#include <stdlib.h> #include <stdio.h> +#include <stdlib.h> #include <string.h> #include <fstream> +#include <memory> #if GTEST_OS_WINDOWS # include <windows.h> # include <io.h> # include <sys/stat.h> # include <map> // Used in ThreadLocal. +# ifdef _MSC_VER +# include <crtdbg.h> +# endif // _MSC_VER #else # include <unistd.h> #endif // GTEST_OS_WINDOWS @@ -51,6 +55,14 @@ # include <mach/vm_map.h> #endif // GTEST_OS_MAC +#if GTEST_OS_DRAGONFLY || GTEST_OS_FREEBSD || GTEST_OS_GNU_KFREEBSD || \ + GTEST_OS_NETBSD || GTEST_OS_OPENBSD +# include <sys/sysctl.h> +# if GTEST_OS_DRAGONFLY || GTEST_OS_FREEBSD || GTEST_OS_GNU_KFREEBSD +# include <sys/user.h> +# endif +#endif + #if GTEST_OS_QNX # include <devctl.h> # include <fcntl.h> @@ -105,7 +117,7 @@ T ReadProcFileField(const std::string& filename, int field) { size_t GetThreadCount() { const std::string filename = (Message() << "/proc/" << getpid() << "/stat").GetString(); - return ReadProcFileField<int>(filename, 19); + return ReadProcFileField<size_t>(filename, 19); } #elif GTEST_OS_MAC @@ -127,6 +139,81 @@ size_t GetThreadCount() { } } +#elif GTEST_OS_DRAGONFLY || GTEST_OS_FREEBSD || GTEST_OS_GNU_KFREEBSD || \ + GTEST_OS_NETBSD + +#if GTEST_OS_NETBSD +#undef KERN_PROC +#define KERN_PROC KERN_PROC2 +#define kinfo_proc kinfo_proc2 +#endif + +#if GTEST_OS_DRAGONFLY +#define KP_NLWP(kp) (kp.kp_nthreads) +#elif GTEST_OS_FREEBSD || GTEST_OS_GNU_KFREEBSD +#define KP_NLWP(kp) (kp.ki_numthreads) +#elif GTEST_OS_NETBSD +#define KP_NLWP(kp) (kp.p_nlwps) +#endif + +// Returns the number of threads running in the process, or 0 to indicate that +// we cannot detect it. +size_t GetThreadCount() { + int mib[] = { + CTL_KERN, + KERN_PROC, + KERN_PROC_PID, + getpid(), +#if GTEST_OS_NETBSD + sizeof(struct kinfo_proc), + 1, +#endif + }; + u_int miblen = sizeof(mib) / sizeof(mib[0]); + struct kinfo_proc info; + size_t size = sizeof(info); + if (sysctl(mib, miblen, &info, &size, NULL, 0)) { + return 0; + } + return static_cast<size_t>(KP_NLWP(info)); +} +#elif GTEST_OS_OPENBSD + +// Returns the number of threads running in the process, or 0 to indicate that +// we cannot detect it. +size_t GetThreadCount() { + int mib[] = { + CTL_KERN, + KERN_PROC, + KERN_PROC_PID | KERN_PROC_SHOW_THREADS, + getpid(), + sizeof(struct kinfo_proc), + 0, + }; + u_int miblen = sizeof(mib) / sizeof(mib[0]); + + // get number of structs + size_t size; + if (sysctl(mib, miblen, NULL, &size, NULL, 0)) { + return 0; + } + mib[5] = size / mib[4]; + + // populate array of structs + struct kinfo_proc info[mib[5]]; + if (sysctl(mib, miblen, &info, &size, NULL, 0)) { + return 0; + } + + // exclude empty members + int nthreads = 0; + for (int i = 0; i < size / mib[4]; i++) { + if (info[i].p_tid != -1) + nthreads++; + } + return nthreads; +} + #elif GTEST_OS_QNX // Returns the number of threads running in the process, or 0 to indicate that @@ -138,7 +225,7 @@ size_t GetThreadCount() { } procfs_info process_info; const int status = - devctl(fd, DCMD_PROC_INFO, &process_info, sizeof(process_info), NULL); + devctl(fd, DCMD_PROC_INFO, &process_info, sizeof(process_info), nullptr); close(fd); if (status == EOK) { return static_cast<size_t>(process_info.num_threads); @@ -152,7 +239,7 @@ size_t GetThreadCount() { size_t GetThreadCount() { struct procentry64 entry; pid_t pid = getpid(); - int status = getprocs64(&entry, sizeof(entry), NULL, 0, &pid, 1); + int status = getprocs64(&entry, sizeof(entry), nullptr, 0, &pid, 1); if (status == 1) { return entry.pi_thcount; } else { @@ -192,7 +279,7 @@ size_t GetThreadCount() { #if GTEST_IS_THREADSAFE && GTEST_OS_WINDOWS void SleepMilliseconds(int n) { - ::Sleep(n); + ::Sleep(static_cast<DWORD>(n)); } AutoHandle::AutoHandle() @@ -230,15 +317,15 @@ void AutoHandle::Reset(HANDLE handle) { bool AutoHandle::IsCloseable() const { // Different Windows APIs may use either of these values to represent an // invalid handle. - return handle_ != NULL && handle_ != INVALID_HANDLE_VALUE; + return handle_ != nullptr && handle_ != INVALID_HANDLE_VALUE; } Notification::Notification() - : event_(::CreateEvent(NULL, // Default security attributes. - TRUE, // Do not reset automatically. - FALSE, // Initially unset. - NULL)) { // Anonymous event. - GTEST_CHECK_(event_.Get() != NULL); + : event_(::CreateEvent(nullptr, // Default security attributes. + TRUE, // Do not reset automatically. + FALSE, // Initially unset. + nullptr)) { // Anonymous event. + GTEST_CHECK_(event_.Get() != nullptr); } void Notification::Notify() { @@ -261,13 +348,10 @@ Mutex::Mutex() Mutex::~Mutex() { // Static mutexes are leaked intentionally. It is not thread-safe to try // to clean them up. - // FIXME: Switch to Slim Reader/Writer (SRW) Locks, which requires - // nothing to clean it up but is available only on Vista and later. - // https://docs.microsoft.com/en-us/windows/desktop/Sync/slim-reader-writer--srw--locks if (type_ == kDynamic) { ::DeleteCriticalSection(critical_section_); delete critical_section_; - critical_section_ = NULL; + critical_section_ = nullptr; } } @@ -296,6 +380,7 @@ void Mutex::AssertHeld() { namespace { +#ifdef _MSC_VER // Use the RAII idiom to flag mem allocs that are intentionally never // deallocated. The motivation is to silence the false positive mem leaks // that are reported by the debug version of MS's CRT which can only detect @@ -308,19 +393,15 @@ class MemoryIsNotDeallocated { public: MemoryIsNotDeallocated() : old_crtdbg_flag_(0) { -#ifdef _MSC_VER old_crtdbg_flag_ = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); // Set heap allocation block type to _IGNORE_BLOCK so that MS debug CRT // doesn't report mem leak if there's no matching deallocation. _CrtSetDbgFlag(old_crtdbg_flag_ & ~_CRTDBG_ALLOC_MEM_DF); -#endif // _MSC_VER } ~MemoryIsNotDeallocated() { -#ifdef _MSC_VER // Restore the original _CRTDBG_ALLOC_MEM_DF flag _CrtSetDbgFlag(old_crtdbg_flag_); -#endif // _MSC_VER } private: @@ -328,6 +409,7 @@ class MemoryIsNotDeallocated GTEST_DISALLOW_COPY_AND_ASSIGN_(MemoryIsNotDeallocated); }; +#endif // _MSC_VER } // namespace @@ -343,7 +425,9 @@ void Mutex::ThreadSafeLazyInit() { owner_thread_id_ = 0; { // Use RAII to flag that following mem alloc is never deallocated. +#ifdef _MSC_VER MemoryIsNotDeallocated memory_is_not_deallocated; +#endif // _MSC_VER critical_section_ = new CRITICAL_SECTION; } ::InitializeCriticalSection(critical_section_); @@ -384,17 +468,16 @@ class ThreadWithParamSupport : public ThreadWithParamBase { Notification* thread_can_start) { ThreadMainParam* param = new ThreadMainParam(runnable, thread_can_start); DWORD thread_id; - // FIXME: Consider to use _beginthreadex instead. HANDLE thread_handle = ::CreateThread( - NULL, // Default security. - 0, // Default stack size. + nullptr, // Default security. + 0, // Default stack size. &ThreadWithParamSupport::ThreadMain, - param, // Parameter to ThreadMainStatic - 0x0, // Default creation flags. + param, // Parameter to ThreadMainStatic + 0x0, // Default creation flags. &thread_id); // Need a valid pointer for the call to work under Win98. - GTEST_CHECK_(thread_handle != NULL) << "CreateThread failed with error " - << ::GetLastError() << "."; - if (thread_handle == NULL) { + GTEST_CHECK_(thread_handle != nullptr) + << "CreateThread failed with error " << ::GetLastError() << "."; + if (thread_handle == nullptr) { delete param; } return thread_handle; @@ -406,15 +489,15 @@ class ThreadWithParamSupport : public ThreadWithParamBase { : runnable_(runnable), thread_can_start_(thread_can_start) { } - scoped_ptr<Runnable> runnable_; + std::unique_ptr<Runnable> runnable_; // Does not own. Notification* thread_can_start_; }; static DWORD WINAPI ThreadMain(void* ptr) { // Transfers ownership. - scoped_ptr<ThreadMainParam> param(static_cast<ThreadMainParam*>(ptr)); - if (param->thread_can_start_ != NULL) + std::unique_ptr<ThreadMainParam> param(static_cast<ThreadMainParam*>(ptr)); + if (param->thread_can_start_ != nullptr) param->thread_can_start_->WaitForNotification(); param->runnable_->Run(); return 0; @@ -472,7 +555,7 @@ class ThreadLocalRegistryImpl { thread_local_values .insert(std::make_pair( thread_local_instance, - linked_ptr<ThreadLocalValueHolderBase>( + std::shared_ptr<ThreadLocalValueHolderBase>( thread_local_instance->NewValueForCurrentThread()))) .first; } @@ -481,7 +564,7 @@ class ThreadLocalRegistryImpl { static void OnThreadLocalDestroyed( const ThreadLocalBase* thread_local_instance) { - std::vector<linked_ptr<ThreadLocalValueHolderBase> > value_holders; + std::vector<std::shared_ptr<ThreadLocalValueHolderBase> > value_holders; // Clean up the ThreadLocalValues data structure while holding the lock, but // defer the destruction of the ThreadLocalValueHolderBases. { @@ -509,7 +592,7 @@ class ThreadLocalRegistryImpl { static void OnThreadExit(DWORD thread_id) { GTEST_CHECK_(thread_id != 0) << ::GetLastError(); - std::vector<linked_ptr<ThreadLocalValueHolderBase> > value_holders; + std::vector<std::shared_ptr<ThreadLocalValueHolderBase> > value_holders; // Clean up the ThreadIdToThreadLocals data structure while holding the // lock, but defer the destruction of the ThreadLocalValueHolderBases. { @@ -536,7 +619,8 @@ class ThreadLocalRegistryImpl { private: // In a particular thread, maps a ThreadLocal object to its value. typedef std::map<const ThreadLocalBase*, - linked_ptr<ThreadLocalValueHolderBase> > ThreadLocalValues; + std::shared_ptr<ThreadLocalValueHolderBase> > + ThreadLocalValues; // Stores all ThreadIdToThreadLocals having values in a thread, indexed by // thread's ID. typedef std::map<DWORD, ThreadLocalValues> ThreadIdToThreadLocals; @@ -551,18 +635,17 @@ class ThreadLocalRegistryImpl { HANDLE thread = ::OpenThread(SYNCHRONIZE | THREAD_QUERY_INFORMATION, FALSE, thread_id); - GTEST_CHECK_(thread != NULL); + GTEST_CHECK_(thread != nullptr); // We need to pass a valid thread ID pointer into CreateThread for it // to work correctly under Win98. DWORD watcher_thread_id; HANDLE watcher_thread = ::CreateThread( - NULL, // Default security. - 0, // Default stack size + nullptr, // Default security. + 0, // Default stack size &ThreadLocalRegistryImpl::WatcherThreadFunc, reinterpret_cast<LPVOID>(new ThreadIdAndHandle(thread_id, thread)), - CREATE_SUSPENDED, - &watcher_thread_id); - GTEST_CHECK_(watcher_thread != NULL); + CREATE_SUSPENDED, &watcher_thread_id); + GTEST_CHECK_(watcher_thread != nullptr); // Give the watcher thread the same priority as ours to avoid being // blocked by it. ::SetThreadPriority(watcher_thread, @@ -587,7 +670,9 @@ class ThreadLocalRegistryImpl { // Returns map of thread local instances. static ThreadIdToThreadLocals* GetThreadLocalsMapLocked() { mutex_.AssertHeld(); +#ifdef _MSC_VER MemoryIsNotDeallocated memory_is_not_deallocated; +#endif // _MSC_VER static ThreadIdToThreadLocals* map = new ThreadIdToThreadLocals(); return map; } @@ -630,7 +715,7 @@ RE::~RE() { free(const_cast<char*>(pattern_)); } -// Returns true iff regular expression re matches the entire str. +// Returns true if and only if regular expression re matches the entire str. bool RE::FullMatch(const char* str, const RE& re) { if (!re.is_valid_) return false; @@ -638,8 +723,8 @@ bool RE::FullMatch(const char* str, const RE& re) { return regexec(&re.full_regex_, str, 1, &match, 0) == 0; } -// Returns true iff regular expression re matches a substring of str -// (including str itself). +// Returns true if and only if regular expression re matches a substring of +// str (including str itself). bool RE::PartialMatch(const char* str, const RE& re) { if (!re.is_valid_) return false; @@ -679,14 +764,14 @@ void RE::Init(const char* regex) { #elif GTEST_USES_SIMPLE_RE -// Returns true iff ch appears anywhere in str (excluding the +// Returns true if and only if ch appears anywhere in str (excluding the // terminating '\0' character). bool IsInSet(char ch, const char* str) { - return ch != '\0' && strchr(str, ch) != NULL; + return ch != '\0' && strchr(str, ch) != nullptr; } -// Returns true iff ch belongs to the given classification. Unlike -// similar functions in <ctype.h>, these aren't affected by the +// Returns true if and only if ch belongs to the given classification. +// Unlike similar functions in <ctype.h>, these aren't affected by the // current locale. bool IsAsciiDigit(char ch) { return '0' <= ch && ch <= '9'; } bool IsAsciiPunct(char ch) { @@ -699,13 +784,13 @@ bool IsAsciiWordChar(char ch) { ('0' <= ch && ch <= '9') || ch == '_'; } -// Returns true iff "\\c" is a supported escape sequence. +// Returns true if and only if "\\c" is a supported escape sequence. bool IsValidEscape(char c) { return (IsAsciiPunct(c) || IsInSet(c, "dDfnrsStvwW")); } -// Returns true iff the given atom (specified by escaped and pattern) -// matches ch. The result is undefined if the atom is invalid. +// Returns true if and only if the given atom (specified by escaped and +// pattern) matches ch. The result is undefined if the atom is invalid. bool AtomMatchesChar(bool escaped, char pattern_char, char ch) { if (escaped) { // "\\p" where p is pattern_char. switch (pattern_char) { @@ -736,17 +821,14 @@ static std::string FormatRegexSyntaxError(const char* regex, int index) { // Generates non-fatal failures and returns false if regex is invalid; // otherwise returns true. bool ValidateRegex(const char* regex) { - if (regex == NULL) { - // FIXME: fix the source file location in the - // assertion failures to match where the regex is used in user - // code. + if (regex == nullptr) { ADD_FAILURE() << "NULL is not a valid simple regular expression."; return false; } bool is_valid = true; - // True iff ?, *, or + can follow the previous atom. + // True if and only if ?, *, or + can follow the previous atom. bool prev_repeatable = false; for (int i = 0; regex[i]; i++) { if (regex[i] == '\\') { // An escape sequence @@ -822,8 +904,8 @@ bool MatchRepetitionAndRegexAtHead( return false; } -// Returns true iff regex matches a prefix of str. regex must be a -// valid simple regular expression and not start with "^", or the +// Returns true if and only if regex matches a prefix of str. regex must +// be a valid simple regular expression and not start with "^", or the // result is undefined. bool MatchRegexAtHead(const char* regex, const char* str) { if (*regex == '\0') // An empty regex matches a prefix of anything. @@ -853,8 +935,8 @@ bool MatchRegexAtHead(const char* regex, const char* str) { } } -// Returns true iff regex matches any substring of str. regex must be -// a valid simple regular expression, or the result is undefined. +// Returns true if and only if regex matches any substring of str. regex must +// be a valid simple regular expression, or the result is undefined. // // The algorithm is recursive, but the recursion depth doesn't exceed // the regex length, so we won't need to worry about running out of @@ -862,8 +944,7 @@ bool MatchRegexAtHead(const char* regex, const char* str) { // exponential with respect to the regex length + the string length, // but usually it's must faster (often close to linear). bool MatchRegexAnywhere(const char* regex, const char* str) { - if (regex == NULL || str == NULL) - return false; + if (regex == nullptr || str == nullptr) return false; if (*regex == '^') return MatchRegexAtHead(regex + 1, str); @@ -883,21 +964,21 @@ RE::~RE() { free(const_cast<char*>(full_pattern_)); } -// Returns true iff regular expression re matches the entire str. +// Returns true if and only if regular expression re matches the entire str. bool RE::FullMatch(const char* str, const RE& re) { return re.is_valid_ && MatchRegexAnywhere(re.full_pattern_, str); } -// Returns true iff regular expression re matches a substring of str -// (including str itself). +// Returns true if and only if regular expression re matches a substring of +// str (including str itself). bool RE::PartialMatch(const char* str, const RE& re) { return re.is_valid_ && MatchRegexAnywhere(re.pattern_, str); } // Initializes an RE from its string representation. void RE::Init(const char* regex) { - pattern_ = full_pattern_ = NULL; - if (regex != NULL) { + pattern_ = full_pattern_ = nullptr; + if (regex != nullptr) { pattern_ = posix::StrDup(regex); } @@ -935,7 +1016,7 @@ const char kUnknownFile[] = "unknown file"; // Formats a source file path and a line number as they would appear // in an error message from the compiler used to compile this code. GTEST_API_ ::std::string FormatFileLocation(const char* file, int line) { - const std::string file_name(file == NULL ? kUnknownFile : file); + const std::string file_name(file == nullptr ? kUnknownFile : file); if (line < 0) { return file_name + ":"; @@ -954,7 +1035,7 @@ GTEST_API_ ::std::string FormatFileLocation(const char* file, int line) { // to the file location it produces, unlike FormatFileLocation(). GTEST_API_ ::std::string FormatCompilerIndependentFileLocation( const char* file, int line) { - const std::string file_name(file == NULL ? kUnknownFile : file); + const std::string file_name(file == nullptr ? kUnknownFile : file); if (line < 0) return file_name; @@ -1021,20 +1102,22 @@ class CapturedStream { // code as part of a regular standalone executable, which doesn't // run in a Dalvik process (e.g. when running it through 'adb shell'). // - // The location /sdcard is directly accessible from native code - // and is the only location (unofficially) supported by the Android - // team. It's generally a symlink to the real SD Card mount point - // which can be /mnt/sdcard, /mnt/sdcard0, /system/media/sdcard, or - // other OEM-customized locations. Never rely on these, and always - // use /sdcard. - char name_template[] = "/sdcard/gtest_captured_stream.XXXXXX"; + // The location /data/local/tmp is directly accessible from native code. + // '/sdcard' and other variants cannot be relied on, as they are not + // guaranteed to be mounted, or may have a delay in mounting. + char name_template[] = "/data/local/tmp/gtest_captured_stream.XXXXXX"; # else char name_template[] = "/tmp/captured_stream.XXXXXX"; # endif // GTEST_OS_LINUX_ANDROID const int captured_fd = mkstemp(name_template); + if (captured_fd == -1) { + GTEST_LOG_(WARNING) + << "Failed to create tmp file " << name_template + << " for test; does the test have access to the /tmp directory?"; + } filename_ = name_template; # endif // GTEST_OS_WINDOWS - fflush(NULL); + fflush(nullptr); dup2(captured_fd, fd_); close(captured_fd); } @@ -1046,13 +1129,17 @@ class CapturedStream { std::string GetCapturedString() { if (uncaptured_fd_ != -1) { // Restores the original stream. - fflush(NULL); + fflush(nullptr); dup2(uncaptured_fd_, fd_); close(uncaptured_fd_); uncaptured_fd_ = -1; } FILE* const file = posix::FOpen(filename_.c_str(), "r"); + if (file == nullptr) { + GTEST_LOG_(FATAL) << "Failed to open tmp file " << filename_ + << " for capturing stream."; + } const std::string content = ReadEntireFile(file); posix::FClose(file); return content; @@ -1069,13 +1156,13 @@ class CapturedStream { GTEST_DISABLE_MSC_DEPRECATED_POP_() -static CapturedStream* g_captured_stderr = NULL; -static CapturedStream* g_captured_stdout = NULL; +static CapturedStream* g_captured_stderr = nullptr; +static CapturedStream* g_captured_stdout = nullptr; // Starts capturing an output stream (stdout/stderr). static void CaptureStream(int fd, const char* stream_name, CapturedStream** stream) { - if (*stream != NULL) { + if (*stream != nullptr) { GTEST_LOG_(FATAL) << "Only one " << stream_name << " capturer can exist at a time."; } @@ -1087,7 +1174,7 @@ static std::string GetCapturedStream(CapturedStream** captured_stream) { const std::string content = (*captured_stream)->GetCapturedString(); delete *captured_stream; - *captured_stream = NULL; + *captured_stream = nullptr; return content; } @@ -1146,10 +1233,11 @@ std::string ReadEntireFile(FILE* file) { } #if GTEST_HAS_DEATH_TEST -static const std::vector<std::string>* g_injected_test_argvs = NULL; // Owned. +static const std::vector<std::string>* g_injected_test_argvs = + nullptr; // Owned. std::vector<std::string> GetInjectableArgvs() { - if (g_injected_test_argvs != NULL) { + if (g_injected_test_argvs != nullptr) { return *g_injected_test_argvs; } return GetArgvs(); @@ -1165,16 +1253,9 @@ void SetInjectableArgvs(const std::vector<std::string>& new_argvs) { new std::vector<std::string>(new_argvs.begin(), new_argvs.end())); } -#if GTEST_HAS_GLOBAL_STRING -void SetInjectableArgvs(const std::vector< ::string>& new_argvs) { - SetInjectableArgvs( - new std::vector<std::string>(new_argvs.begin(), new_argvs.end())); -} -#endif // GTEST_HAS_GLOBAL_STRING - void ClearInjectableArgvs() { delete g_injected_test_argvs; - g_injected_test_argvs = NULL; + g_injected_test_argvs = nullptr; } #endif // GTEST_HAS_DEATH_TEST @@ -1207,7 +1288,7 @@ static std::string FlagToEnvVar(const char* flag) { // unchanged and returns false. bool ParseInt32(const Message& src_text, const char* str, Int32* value) { // Parses the environment variable as a decimal integer. - char* end = NULL; + char* end = nullptr; const long long_value = strtol(str, &end, 10); // NOLINT // Has strtol() consumed all characters in the string? @@ -1246,15 +1327,15 @@ bool ParseInt32(const Message& src_text, const char* str, Int32* value) { // Reads and returns the Boolean environment variable corresponding to // the given flag; if it's not set, returns default_value. // -// The value is considered true iff it's not "0". +// The value is considered true if and only if it's not "0". bool BoolFromGTestEnv(const char* flag, bool default_value) { #if defined(GTEST_GET_BOOL_FROM_ENV_) return GTEST_GET_BOOL_FROM_ENV_(flag, default_value); #else const std::string env_var = FlagToEnvVar(flag); const char* const string_value = posix::GetEnv(env_var.c_str()); - return string_value == NULL ? - default_value : strcmp(string_value, "0") != 0; + return string_value == nullptr ? default_value + : strcmp(string_value, "0") != 0; #endif // defined(GTEST_GET_BOOL_FROM_ENV_) } @@ -1267,7 +1348,7 @@ Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) { #else const std::string env_var = FlagToEnvVar(flag); const char* const string_value = posix::GetEnv(env_var.c_str()); - if (string_value == NULL) { + if (string_value == nullptr) { // The environment variable is not set. return default_value; } @@ -1296,7 +1377,7 @@ Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) { std::string OutputFlagAlsoCheckEnvVar(){ std::string default_value_for_output_flag = ""; const char* xml_output_file_env = posix::GetEnv("XML_OUTPUT_FILE"); - if (NULL != xml_output_file_env) { + if (nullptr != xml_output_file_env) { default_value_for_output_flag = std::string("xml:") + xml_output_file_env; } return default_value_for_output_flag; @@ -1310,7 +1391,7 @@ const char* StringFromGTestEnv(const char* flag, const char* default_value) { #else const std::string env_var = FlagToEnvVar(flag); const char* const value = posix::GetEnv(env_var.c_str()); - return value == NULL ? default_value : value; + return value == nullptr ? default_value : value; #endif // defined(GTEST_GET_STRING_FROM_ENV_) } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/src/gtest-printers.cc b/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/src/gtest-printers.cc index de4d245e9fc..3337be312ea 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/src/gtest-printers.cc +++ b/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/src/gtest-printers.cc @@ -59,6 +59,7 @@ using ::std::ostream; // Prints a segment of bytes in the given object. GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ +GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_ GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ void PrintByteSegmentInObjectTo(const unsigned char* obj_bytes, size_t start, size_t count, ostream* os) { @@ -89,7 +90,6 @@ void PrintBytesInObjectToImpl(const unsigned char* obj_bytes, size_t count, // If the object size is bigger than kThreshold, we'll have to omit // some details by printing only the first and the last kChunkSize // bytes. - // FIXME: let the user control the threshold using a flag. if (count < kThreshold) { PrintByteSegmentInObjectTo(obj_bytes, 0, count, os); } else { @@ -144,7 +144,8 @@ inline bool IsPrintableAscii(wchar_t c) { // which is the type of c. template <typename UnsignedChar, typename Char> static CharFormat PrintAsCharLiteralTo(Char c, ostream* os) { - switch (static_cast<wchar_t>(c)) { + wchar_t w_c = static_cast<wchar_t>(c); + switch (w_c) { case L'\0': *os << "\\0"; break; @@ -176,7 +177,7 @@ static CharFormat PrintAsCharLiteralTo(Char c, ostream* os) { *os << "\\v"; break; default: - if (IsPrintableAscii(c)) { + if (IsPrintableAscii(w_c)) { *os << static_cast<char>(c); return kAsIs; } else { @@ -236,7 +237,7 @@ void PrintCharAndCodeTo(Char c, ostream* os) { if (format == kHexEscape || (1 <= c && c <= 9)) { // Do nothing. } else { - *os << ", 0x" << String::FormatHexInt(static_cast<UnsignedChar>(c)); + *os << ", 0x" << String::FormatHexInt(static_cast<int>(c)); } *os << ")"; } @@ -261,6 +262,7 @@ void PrintTo(wchar_t wc, ostream* os) { template <typename CharType> GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ +GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_ GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ static CharFormat PrintCharsAsStringTo( const CharType* begin, size_t len, ostream* os) { @@ -291,6 +293,7 @@ static CharFormat PrintCharsAsStringTo( template <typename CharType> GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ +GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_ GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ static void UniversalPrintCharArray( const CharType* begin, size_t len, ostream* os) { @@ -327,7 +330,7 @@ void UniversalPrintArray(const wchar_t* begin, size_t len, ostream* os) { // Prints the given C string to the ostream. void PrintTo(const char* s, ostream* os) { - if (s == NULL) { + if (s == nullptr) { *os << "NULL"; } else { *os << ImplicitCast_<const void*>(s) << " pointing to "; @@ -344,11 +347,11 @@ void PrintTo(const char* s, ostream* os) { #if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) // Prints the given wide C string to the ostream. void PrintTo(const wchar_t* s, ostream* os) { - if (s == NULL) { + if (s == nullptr) { *os << "NULL"; } else { *os << ImplicitCast_<const void*>(s) << " pointing to "; - PrintCharsAsStringTo(s, std::wcslen(s), os); + PrintCharsAsStringTo(s, wcslen(s), os); } } #endif // wchar_t is native @@ -420,17 +423,6 @@ void ConditionalPrintAsText(const char* str, size_t length, ostream* os) { } // anonymous namespace -// Prints a ::string object. -#if GTEST_HAS_GLOBAL_STRING -void PrintStringTo(const ::string& s, ostream* os) { - if (PrintCharsAsStringTo(s.data(), s.size(), os) == kHexEscape) { - if (GTEST_FLAG(print_utf8)) { - ConditionalPrintAsText(s.data(), s.size(), os); - } - } -} -#endif // GTEST_HAS_GLOBAL_STRING - void PrintStringTo(const ::std::string& s, ostream* os) { if (PrintCharsAsStringTo(s.data(), s.size(), os) == kHexEscape) { if (GTEST_FLAG(print_utf8)) { @@ -439,13 +431,6 @@ void PrintStringTo(const ::std::string& s, ostream* os) { } } -// Prints a ::wstring object. -#if GTEST_HAS_GLOBAL_WSTRING -void PrintWideStringTo(const ::wstring& s, ostream* os) { - PrintCharsAsStringTo(s.data(), s.size(), os); -} -#endif // GTEST_HAS_GLOBAL_WSTRING - #if GTEST_HAS_STD_WSTRING void PrintWideStringTo(const ::std::wstring& s, ostream* os) { PrintCharsAsStringTo(s.data(), s.size(), os); diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/src/gtest-test-part.cc b/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/src/gtest-test-part.cc index c88860d9238..178317a6bcd 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/src/gtest-test-part.cc +++ b/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/src/gtest-test-part.cc @@ -41,18 +41,21 @@ using internal::GetUnitTestImpl; // in it. std::string TestPartResult::ExtractSummary(const char* message) { const char* const stack_trace = strstr(message, internal::kStackTraceMarker); - return stack_trace == NULL ? message : - std::string(message, stack_trace); + return stack_trace == nullptr ? message : std::string(message, stack_trace); } // Prints a TestPartResult object. std::ostream& operator<<(std::ostream& os, const TestPartResult& result) { - return os - << result.file_name() << ":" << result.line_number() << ": " - << (result.type() == TestPartResult::kSuccess ? "Success" : - result.type() == TestPartResult::kFatalFailure ? "Fatal failure" : - "Non-fatal failure") << ":\n" - << result.message() << std::endl; + return os << result.file_name() << ":" << result.line_number() << ": " + << (result.type() == TestPartResult::kSuccess + ? "Success" + : result.type() == TestPartResult::kSkip + ? "Skipped" + : result.type() == TestPartResult::kFatalFailure + ? "Fatal failure" + : "Non-fatal failure") + << ":\n" + << result.message() << std::endl; } // Appends a TestPartResult to the array. @@ -67,7 +70,7 @@ const TestPartResult& TestPartResultArray::GetTestPartResult(int index) const { internal::posix::Abort(); } - return array_[index]; + return array_[static_cast<size_t>(index)]; } // Returns the number of TestPartResult objects in the array. diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/src/gtest-typed-test.cc b/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/src/gtest-typed-test.cc index 1dc2ad38bab..8677caf732b 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/src/gtest-typed-test.cc +++ b/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/src/gtest-typed-test.cc @@ -48,7 +48,7 @@ static const char* SkipSpaces(const char* str) { static std::vector<std::string> SplitIntoTestNames(const char* src) { std::vector<std::string> name_vec; src = SkipSpaces(src); - for (; src != NULL; src = SkipComma(src)) { + for (; src != nullptr; src = SkipComma(src)) { name_vec.push_back(StripTrailingSpaces(GetPrefixUntilComma(src))); } return name_vec; @@ -57,7 +57,7 @@ static std::vector<std::string> SplitIntoTestNames(const char* src) { // Verifies that registered_tests match the test names in // registered_tests_; returns registered_tests if successful, or // aborts the program otherwise. -const char* TypedTestCasePState::VerifyRegisteredTestNames( +const char* TypedTestSuitePState::VerifyRegisteredTestNames( const char* file, int line, const char* registered_tests) { typedef RegisteredTestsMap::const_iterator RegisteredTestIter; registered_ = true; @@ -89,7 +89,7 @@ const char* TypedTestCasePState::VerifyRegisteredTestNames( tests.insert(name); } else { errors << "No test named " << name - << " can be found in this test case.\n"; + << " can be found in this test suite.\n"; } } diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/src/gtest.cc b/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/src/gtest.cc index 6917b83c8ef..a5b4e5ac78c 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/src/gtest.cc +++ b/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/src/gtest.cc @@ -54,8 +54,6 @@ #if GTEST_OS_LINUX -// FIXME: Use autoconf to detect availability of -// gettimeofday(). # define GTEST_HAS_GETTIMEOFDAY_ 1 # include <fcntl.h> // NOLINT @@ -68,10 +66,6 @@ # include <unistd.h> // NOLINT # include <string> -#elif GTEST_OS_SYMBIAN -# define GTEST_HAS_GETTIMEOFDAY_ 1 -# include <sys/time.h> // NOLINT - #elif GTEST_OS_ZOS # define GTEST_HAS_GETTIMEOFDAY_ 1 # include <sys/time.h> // NOLINT @@ -86,6 +80,11 @@ #elif GTEST_OS_WINDOWS // We are on Windows proper. +# include <windows.h> // NOLINT +# undef min + +# include <crtdbg.h> // NOLINT +# include <debugapi.h> // NOLINT # include <io.h> // NOLINT # include <sys/timeb.h> // NOLINT # include <sys/types.h> // NOLINT @@ -93,25 +92,13 @@ # if GTEST_OS_WINDOWS_MINGW // MinGW has gettimeofday() but not _ftime64(). -// FIXME: Use autoconf to detect availability of -// gettimeofday(). -// FIXME: There are other ways to get the time on -// Windows, like GetTickCount() or GetSystemTimeAsFileTime(). MinGW -// supports these. consider using them instead. # define GTEST_HAS_GETTIMEOFDAY_ 1 # include <sys/time.h> // NOLINT # endif // GTEST_OS_WINDOWS_MINGW -// cpplint thinks that the header is already included, so we want to -// silence it. -# include <windows.h> // NOLINT -# undef min - #else // Assume other platforms have gettimeofday(). -// FIXME: Use autoconf to detect availability of -// gettimeofday(). # define GTEST_HAS_GETTIMEOFDAY_ 1 // cpplint thinks that the header is already included, so we want to @@ -160,14 +147,14 @@ using internal::Shuffle; // Constants. -// A test whose test case name or test name matches this filter is +// A test whose test suite name or test name matches this filter is // disabled and not run. static const char kDisableTestFilter[] = "DISABLED_*:*/DISABLED_*"; -// A test case whose name matches this filter is considered a death -// test case and will be run before test cases whose name doesn't +// A test suite whose name matches this filter is considered a death +// test suite and will be run before test suites whose name doesn't // match this filter. -static const char kDeathTestCaseFilter[] = "*DeathTest:*DeathTest/*"; +static const char kDeathTestSuiteFilter[] = "*DeathTest:*DeathTest/*"; // A test filter that matches everything. static const char kUniversalFilter[] = "*"; @@ -190,20 +177,20 @@ namespace internal { // stack trace. const char kStackTraceMarker[] = "\nStack trace:\n"; -// g_help_flag is true iff the --help flag or an equivalent form is -// specified on the command line. +// g_help_flag is true if and only if the --help flag or an equivalent form +// is specified on the command line. bool g_help_flag = false; // Utilty function to Open File for Writing static FILE* OpenFileForWriting(const std::string& output_file) { - FILE* fileout = NULL; + FILE* fileout = nullptr; FilePath output_file_path(output_file); FilePath output_dir(output_file_path.RemoveFileName()); if (output_dir.CreateDirectoriesRecursively()) { fileout = posix::FOpen(output_file.c_str(), "w"); } - if (fileout == NULL) { + if (fileout == nullptr) { GTEST_LOG_(FATAL) << "Unable to open file \"" << output_file << "\""; } return fileout; @@ -216,7 +203,7 @@ static FILE* OpenFileForWriting(const std::string& output_file) { static const char* GetDefaultFilter() { const char* const testbridge_test_only = internal::posix::GetEnv("TESTBRIDGE_TEST_ONLY"); - if (testbridge_test_only != NULL) { + if (testbridge_test_only != nullptr) { return testbridge_test_only; } return kUniversalFilter; @@ -228,15 +215,14 @@ GTEST_DEFINE_bool_( "Run disabled tests too, in addition to the tests normally being run."); GTEST_DEFINE_bool_( - break_on_failure, - internal::BoolFromGTestEnv("break_on_failure", false), - "True iff a failed assertion should be a debugger break-point."); + break_on_failure, internal::BoolFromGTestEnv("break_on_failure", false), + "True if and only if a failed assertion should be a debugger " + "break-point."); -GTEST_DEFINE_bool_( - catch_exceptions, - internal::BoolFromGTestEnv("catch_exceptions", true), - "True iff " GTEST_NAME_ - " should catch exceptions and treat them as test failures."); +GTEST_DEFINE_bool_(catch_exceptions, + internal::BoolFromGTestEnv("catch_exceptions", true), + "True if and only if " GTEST_NAME_ + " should catch exceptions and treat them as test failures."); GTEST_DEFINE_string_( color, @@ -283,17 +269,13 @@ GTEST_DEFINE_string_( "executable's name and, if necessary, made unique by adding " "digits."); -GTEST_DEFINE_bool_( - print_time, - internal::BoolFromGTestEnv("print_time", true), - "True iff " GTEST_NAME_ - " should display elapsed time in text output."); +GTEST_DEFINE_bool_(print_time, internal::BoolFromGTestEnv("print_time", true), + "True if and only if " GTEST_NAME_ + " should display elapsed time in text output."); -GTEST_DEFINE_bool_( - print_utf8, - internal::BoolFromGTestEnv("print_utf8", true), - "True iff " GTEST_NAME_ - " prints UTF8 characters as text."); +GTEST_DEFINE_bool_(print_utf8, internal::BoolFromGTestEnv("print_utf8", true), + "True if and only if " GTEST_NAME_ + " prints UTF8 characters as text."); GTEST_DEFINE_int32_( random_seed, @@ -307,16 +289,14 @@ GTEST_DEFINE_int32_( "How many times to repeat each test. Specify a negative number " "for repeating forever. Useful for shaking out flaky tests."); -GTEST_DEFINE_bool_( - show_internal_stack_frames, false, - "True iff " GTEST_NAME_ " should include internal stack frames when " - "printing test failure stack traces."); +GTEST_DEFINE_bool_(show_internal_stack_frames, false, + "True if and only if " GTEST_NAME_ + " should include internal stack frames when " + "printing test failure stack traces."); -GTEST_DEFINE_bool_( - shuffle, - internal::BoolFromGTestEnv("shuffle", false), - "True iff " GTEST_NAME_ - " should randomize tests' order on every run."); +GTEST_DEFINE_bool_(shuffle, internal::BoolFromGTestEnv("shuffle", false), + "True if and only if " GTEST_NAME_ + " should randomize tests' order on every run."); GTEST_DEFINE_int32_( stack_trace_depth, @@ -367,16 +347,16 @@ UInt32 Random::Generate(UInt32 range) { return state_ % range; } -// GTestIsInitialized() returns true iff the user has initialized +// GTestIsInitialized() returns true if and only if the user has initialized // Google Test. Useful for catching the user mistake of not initializing // Google Test before calling RUN_ALL_TESTS(). static bool GTestIsInitialized() { return GetArgvs().size() > 0; } -// Iterates over a vector of TestCases, keeping a running sum of the +// Iterates over a vector of TestSuites, keeping a running sum of the // results of calling a given int-returning method on each. // Returns the sum. -static int SumOverTestCaseList(const std::vector<TestCase*>& case_list, - int (TestCase::*method)() const) { +static int SumOverTestSuiteList(const std::vector<TestSuite*>& case_list, + int (TestSuite::*method)() const) { int sum = 0; for (size_t i = 0; i < case_list.size(); i++) { sum += (case_list[i]->*method)(); @@ -384,20 +364,20 @@ static int SumOverTestCaseList(const std::vector<TestCase*>& case_list, return sum; } -// Returns true iff the test case passed. -static bool TestCasePassed(const TestCase* test_case) { - return test_case->should_run() && test_case->Passed(); +// Returns true if and only if the test suite passed. +static bool TestSuitePassed(const TestSuite* test_suite) { + return test_suite->should_run() && test_suite->Passed(); } -// Returns true iff the test case failed. -static bool TestCaseFailed(const TestCase* test_case) { - return test_case->should_run() && test_case->Failed(); +// Returns true if and only if the test suite failed. +static bool TestSuiteFailed(const TestSuite* test_suite) { + return test_suite->should_run() && test_suite->Failed(); } -// Returns true iff test_case contains at least one test that should -// run. -static bool ShouldRunTestCase(const TestCase* test_case) { - return test_case->should_run(); +// Returns true if and only if test_suite contains at least one test that +// should run. +static bool ShouldRunTestSuite(const TestSuite* test_suite) { + return test_suite->should_run(); } // AssertHelper constructor. @@ -423,9 +403,6 @@ void AssertHelper::operator=(const Message& message) const { ); // NOLINT } -// Mutex for linked pointers. -GTEST_API_ GTEST_DEFINE_STATIC_MUTEX_(g_linked_ptr_mutex); - // A copy of all command line arguments. Set by InitGoogleTest(). static ::std::vector<std::string> g_argvs; @@ -445,7 +422,7 @@ static ::std::vector<std::string> g_argvs; FilePath GetCurrentExecutableName() { FilePath result; -#if GTEST_OS_WINDOWS +#if GTEST_OS_WINDOWS || GTEST_OS_OS2 result.Set(FilePath(GetArgvs()[0]).RemoveExtension("exe")); #else result.Set(FilePath(GetArgvs()[0])); @@ -460,9 +437,10 @@ FilePath GetCurrentExecutableName() { std::string UnitTestOptions::GetOutputFormat() { const char* const gtest_output_flag = GTEST_FLAG(output).c_str(); const char* const colon = strchr(gtest_output_flag, ':'); - return (colon == NULL) ? - std::string(gtest_output_flag) : - std::string(gtest_output_flag, colon - gtest_output_flag); + return (colon == nullptr) + ? std::string(gtest_output_flag) + : std::string(gtest_output_flag, + static_cast<size_t>(colon - gtest_output_flag)); } // Returns the name of the requested output file, or the default if none @@ -475,7 +453,7 @@ std::string UnitTestOptions::GetAbsolutePathToOutputFile() { format = std::string(kDefaultOutputFormat); const char* const colon = strchr(gtest_output_flag, ':'); - if (colon == NULL) + if (colon == nullptr) return internal::FilePath::MakeFileName( internal::FilePath( UnitTest::GetInstance()->original_working_dir()), @@ -484,10 +462,6 @@ std::string UnitTestOptions::GetAbsolutePathToOutputFile() { internal::FilePath output_name(colon + 1); if (!output_name.IsAbsolutePath()) - // FIXME: on Windows \some\path is not an absolute - // path (as its meaning depends on the current drive), yet the - // following logic for turning it into an absolute path is wrong. - // Fix it. output_name = internal::FilePath::ConcatPaths( internal::FilePath(UnitTest::GetInstance()->original_working_dir()), internal::FilePath(colon + 1)); @@ -501,8 +475,8 @@ std::string UnitTestOptions::GetAbsolutePathToOutputFile() { return result.string(); } -// Returns true iff the wildcard pattern matches the string. The -// first ':' or '\0' character in pattern marks the end of it. +// Returns true if and only if the wildcard pattern matches the string. +// The first ':' or '\0' character in pattern marks the end of it. // // This recursive algorithm isn't very efficient, but is clear and // works well enough for matching test names, which are short. @@ -535,7 +509,7 @@ bool UnitTestOptions::MatchesFilter( cur_pattern = strchr(cur_pattern, ':'); // Returns if no more pattern can be found. - if (cur_pattern == NULL) { + if (cur_pattern == nullptr) { return false; } @@ -544,11 +518,11 @@ bool UnitTestOptions::MatchesFilter( } } -// Returns true iff the user-specified filter matches the test case -// name and the test name. -bool UnitTestOptions::FilterMatchesTest(const std::string &test_case_name, - const std::string &test_name) { - const std::string& full_name = test_case_name + "." + test_name.c_str(); +// Returns true if and only if the user-specified filter matches the test +// suite name and the test name. +bool UnitTestOptions::FilterMatchesTest(const std::string& test_suite_name, + const std::string& test_name) { + const std::string& full_name = test_suite_name + "." + test_name.c_str(); // Split --gtest_filter at '-', if there is one, to separate into // positive filter and negative filter portions @@ -556,7 +530,7 @@ bool UnitTestOptions::FilterMatchesTest(const std::string &test_case_name, const char* const dash = strchr(p, '-'); std::string positive; std::string negative; - if (dash == NULL) { + if (dash == nullptr) { positive = GTEST_FLAG(filter).c_str(); // Whole string is a positive filter negative = ""; } else { @@ -701,7 +675,7 @@ static AssertionResult HasOneFailure(const char* /* results_expr */, << r; } - if (strstr(r.message(), substr.c_str()) == NULL) { + if (strstr(r.message(), substr.c_str()) == nullptr) { return AssertionFailure() << "Expected: " << expected << " containing \"" << substr << "\"\n" << " Actual:\n" @@ -770,61 +744,66 @@ void UnitTestImpl::SetTestPartResultReporterForCurrentThread( per_thread_test_part_result_reporter_.set(reporter); } -// Gets the number of successful test cases. -int UnitTestImpl::successful_test_case_count() const { - return CountIf(test_cases_, TestCasePassed); +// Gets the number of successful test suites. +int UnitTestImpl::successful_test_suite_count() const { + return CountIf(test_suites_, TestSuitePassed); } -// Gets the number of failed test cases. -int UnitTestImpl::failed_test_case_count() const { - return CountIf(test_cases_, TestCaseFailed); +// Gets the number of failed test suites. +int UnitTestImpl::failed_test_suite_count() const { + return CountIf(test_suites_, TestSuiteFailed); } -// Gets the number of all test cases. -int UnitTestImpl::total_test_case_count() const { - return static_cast<int>(test_cases_.size()); +// Gets the number of all test suites. +int UnitTestImpl::total_test_suite_count() const { + return static_cast<int>(test_suites_.size()); } -// Gets the number of all test cases that contain at least one test +// Gets the number of all test suites that contain at least one test // that should run. -int UnitTestImpl::test_case_to_run_count() const { - return CountIf(test_cases_, ShouldRunTestCase); +int UnitTestImpl::test_suite_to_run_count() const { + return CountIf(test_suites_, ShouldRunTestSuite); } // Gets the number of successful tests. int UnitTestImpl::successful_test_count() const { - return SumOverTestCaseList(test_cases_, &TestCase::successful_test_count); + return SumOverTestSuiteList(test_suites_, &TestSuite::successful_test_count); +} + +// Gets the number of skipped tests. +int UnitTestImpl::skipped_test_count() const { + return SumOverTestSuiteList(test_suites_, &TestSuite::skipped_test_count); } // Gets the number of failed tests. int UnitTestImpl::failed_test_count() const { - return SumOverTestCaseList(test_cases_, &TestCase::failed_test_count); + return SumOverTestSuiteList(test_suites_, &TestSuite::failed_test_count); } // Gets the number of disabled tests that will be reported in the XML report. int UnitTestImpl::reportable_disabled_test_count() const { - return SumOverTestCaseList(test_cases_, - &TestCase::reportable_disabled_test_count); + return SumOverTestSuiteList(test_suites_, + &TestSuite::reportable_disabled_test_count); } // Gets the number of disabled tests. int UnitTestImpl::disabled_test_count() const { - return SumOverTestCaseList(test_cases_, &TestCase::disabled_test_count); + return SumOverTestSuiteList(test_suites_, &TestSuite::disabled_test_count); } // Gets the number of tests to be printed in the XML report. int UnitTestImpl::reportable_test_count() const { - return SumOverTestCaseList(test_cases_, &TestCase::reportable_test_count); + return SumOverTestSuiteList(test_suites_, &TestSuite::reportable_test_count); } // Gets the number of all tests. int UnitTestImpl::total_test_count() const { - return SumOverTestCaseList(test_cases_, &TestCase::total_test_count); + return SumOverTestSuiteList(test_suites_, &TestSuite::total_test_count); } // Gets the number of tests that should run. int UnitTestImpl::test_to_run_count() const { - return SumOverTestCaseList(test_cases_, &TestCase::test_to_run_count); + return SumOverTestSuiteList(test_suites_, &TestSuite::test_to_run_count); } // Returns the current OS stack trace as an std::string. @@ -858,8 +837,6 @@ TimeInMillis GetTimeInMillis() { SYSTEMTIME now_systime; FILETIME now_filetime; ULARGE_INTEGER now_int64; - // FIXME: Shouldn't this just use - // GetSystemTimeAsFileTime()? GetSystemTime(&now_systime); if (SystemTimeToFileTime(&now_systime, &now_filetime)) { now_int64.LowPart = now_filetime.dwLowDateTime; @@ -874,8 +851,6 @@ TimeInMillis GetTimeInMillis() { // MSVC 8 deprecates _ftime64(), so we want to suppress warning 4996 // (deprecated function) there. - // FIXME: Use GetTickCount()? Or use - // SystemTimeToFileTime() GTEST_DISABLE_MSC_DEPRECATED_PUSH_() _ftime64(&now); GTEST_DISABLE_MSC_DEPRECATED_POP_() @@ -883,7 +858,7 @@ TimeInMillis GetTimeInMillis() { return static_cast<TimeInMillis>(now.time) * 1000 + now.millitm; #elif GTEST_HAS_GETTIMEOFDAY_ struct timeval now; - gettimeofday(&now, NULL); + gettimeofday(&now, nullptr); return static_cast<TimeInMillis>(now.tv_sec) * 1000 + now.tv_usec / 1000; #else # error "Don't know how to get the current time on your system." @@ -900,11 +875,10 @@ TimeInMillis GetTimeInMillis() { // value using delete[]. Returns the wide string, or NULL if the // input is NULL. LPCWSTR String::AnsiToUtf16(const char* ansi) { - if (!ansi) return NULL; + if (!ansi) return nullptr; const int length = strlen(ansi); const int unicode_length = - MultiByteToWideChar(CP_ACP, 0, ansi, length, - NULL, 0); + MultiByteToWideChar(CP_ACP, 0, ansi, length, nullptr, 0); WCHAR* unicode = new WCHAR[unicode_length + 1]; MultiByteToWideChar(CP_ACP, 0, ansi, length, unicode, unicode_length); @@ -917,33 +891,33 @@ LPCWSTR String::AnsiToUtf16(const char* ansi) { // value using delete[]. Returns the ANSI string, or NULL if the // input is NULL. const char* String::Utf16ToAnsi(LPCWSTR utf16_str) { - if (!utf16_str) return NULL; - const int ansi_length = - WideCharToMultiByte(CP_ACP, 0, utf16_str, -1, - NULL, 0, NULL, NULL); + if (!utf16_str) return nullptr; + const int ansi_length = WideCharToMultiByte(CP_ACP, 0, utf16_str, -1, nullptr, + 0, nullptr, nullptr); char* ansi = new char[ansi_length + 1]; - WideCharToMultiByte(CP_ACP, 0, utf16_str, -1, - ansi, ansi_length, NULL, NULL); + WideCharToMultiByte(CP_ACP, 0, utf16_str, -1, ansi, ansi_length, nullptr, + nullptr); ansi[ansi_length] = 0; return ansi; } #endif // GTEST_OS_WINDOWS_MOBILE -// Compares two C strings. Returns true iff they have the same content. +// Compares two C strings. Returns true if and only if they have the same +// content. // // Unlike strcmp(), this function can handle NULL argument(s). A NULL // C string is considered different to any non-NULL C string, // including the empty string. bool String::CStringEquals(const char * lhs, const char * rhs) { - if ( lhs == NULL ) return rhs == NULL; + if (lhs == nullptr) return rhs == nullptr; - if ( rhs == NULL ) return false; + if (rhs == nullptr) return false; return strcmp(lhs, rhs) == 0; } -#if GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING +#if GTEST_HAS_STD_WSTRING // Converts an array of wide chars to a narrow string using the UTF-8 // encoding, and streams the result to the given Message object. @@ -961,7 +935,7 @@ static void StreamWideCharsToMessage(const wchar_t* wstr, size_t length, } } -#endif // GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING +#endif // GTEST_HAS_STD_WSTRING void SplitString(const ::std::string& str, char delimiter, ::std::vector< ::std::string>* dest) { @@ -1011,15 +985,6 @@ Message& Message::operator <<(const ::std::wstring& wstr) { } #endif // GTEST_HAS_STD_WSTRING -#if GTEST_HAS_GLOBAL_WSTRING -// Converts the given wide string to a narrow string using the UTF-8 -// encoding, and streams the result to this Message object. -Message& Message::operator <<(const ::wstring& wstr) { - internal::StreamWideCharsToMessage(wstr.c_str(), wstr.length(), this); - return *this; -} -#endif // GTEST_HAS_GLOBAL_WSTRING - // Gets the text streamed to this object so far as an std::string. // Each '\0' character in the buffer is replaced with "\\0". std::string Message::GetString() const { @@ -1030,10 +995,9 @@ std::string Message::GetString() const { // Used in EXPECT_TRUE/FALSE(assertion_result). AssertionResult::AssertionResult(const AssertionResult& other) : success_(other.success_), - message_(other.message_.get() != NULL ? - new ::std::string(*other.message_) : - static_cast< ::std::string*>(NULL)) { -} + message_(other.message_.get() != nullptr + ? new ::std::string(*other.message_) + : static_cast< ::std::string*>(nullptr)) {} // Swaps two AssertionResults. void AssertionResult::swap(AssertionResult& other) { @@ -1045,8 +1009,7 @@ void AssertionResult::swap(AssertionResult& other) { // Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE. AssertionResult AssertionResult::operator!() const { AssertionResult negation(!success_); - if (message_.get() != NULL) - negation << *message_; + if (message_.get() != nullptr) negation << *message_; return negation; } @@ -1272,9 +1235,10 @@ std::string CreateUnifiedDiff(const std::vector<std::string>& left, for (; edit_i < edits.size(); ++edit_i) { if (n_suffix >= context) { // Continue only if the next hunk is very close. - std::vector<EditType>::const_iterator it = edits.begin() + edit_i; + auto it = edits.begin() + static_cast<int>(edit_i); while (it != edits.end() && *it == kMatch) ++it; - if (it == edits.end() || (it - edits.begin()) - edit_i >= context) { + if (it == edits.end() || + static_cast<size_t>(it - edits.begin()) - edit_i >= context) { // There is no next edit or it is too far away. break; } @@ -1350,7 +1314,7 @@ std::vector<std::string> SplitEscapedString(const std::string& str) { // lhs_value: "5" // rhs_value: "6" // -// The ignoring_case parameter is true iff the assertion is a +// The ignoring_case parameter is true if and only if the assertion is a // *_STRCASEEQ*. When it's true, the string "Ignoring case" will // be inserted into the message. AssertionResult EqFailure(const char* lhs_expression, @@ -1413,8 +1377,6 @@ AssertionResult DoubleNearPredFormat(const char* expr1, const double diff = fabs(val1 - val2); if (diff <= abs_error) return AssertionSuccess(); - // FIXME: do not print the value of an expression if it's - // already a literal. return AssertionFailure() << "The difference between " << expr1 << " and " << expr2 << " is " << diff << ", which exceeds " << abs_error_expr << ", where\n" @@ -1595,22 +1557,20 @@ namespace { // Helper functions for implementing IsSubString() and IsNotSubstring(). -// This group of overloaded functions return true iff needle is a -// substring of haystack. NULL is considered a substring of itself -// only. +// This group of overloaded functions return true if and only if needle +// is a substring of haystack. NULL is considered a substring of +// itself only. bool IsSubstringPred(const char* needle, const char* haystack) { - if (needle == NULL || haystack == NULL) - return needle == haystack; + if (needle == nullptr || haystack == nullptr) return needle == haystack; - return strstr(haystack, needle) != NULL; + return strstr(haystack, needle) != nullptr; } bool IsSubstringPred(const wchar_t* needle, const wchar_t* haystack) { - if (needle == NULL || haystack == NULL) - return needle == haystack; + if (needle == nullptr || haystack == nullptr) return needle == haystack; - return wcsstr(haystack, needle) != NULL; + return wcsstr(haystack, needle) != nullptr; } // StringType here can be either ::std::string or ::std::wstring. @@ -1724,12 +1684,12 @@ AssertionResult HRESULTFailureHelper(const char* expr, // Gets the system's human readable message string for this HRESULT. char error_text[kBufSize] = { '\0' }; DWORD message_length = ::FormatMessageA(kFlags, - 0, // no source, we're asking system - hr, // the error - 0, // no line width restrictions + 0, // no source, we're asking system + static_cast<DWORD>(hr), // the error + 0, // no line width restrictions error_text, // output buffer - kBufSize, // buf size - NULL); // no arguments for inserts + kBufSize, // buf size + nullptr); // no arguments for inserts // Trims tailing white space (FormatMessage leaves a trailing CR-LF) for (; message_length && IsSpace(error_text[message_length - 1]); --message_length) { @@ -1803,7 +1763,7 @@ inline UInt32 ChopLowBits(UInt32* bits, int n) { // to "(Invalid Unicode 0xXXXXXXXX)". std::string CodePointToUtf8(UInt32 code_point) { if (code_point > kMaxCodePoint4) { - return "(Invalid Unicode 0x" + String::FormatHexInt(code_point) + ")"; + return "(Invalid Unicode 0x" + String::FormatHexUInt32(code_point) + ")"; } char str[5]; // Big enough for the largest valid code point. @@ -1831,7 +1791,7 @@ std::string CodePointToUtf8(UInt32 code_point) { // The following two functions only make sense if the system // uses UTF-16 for wide string encoding. All supported systems -// with 16 bit wchar_t (Windows, Cygwin, Symbian OS) do use UTF-16. +// with 16 bit wchar_t (Windows, Cygwin) do use UTF-16. // Determines if the arguments constitute UTF-16 surrogate pair // and thus should be combined into a single Unicode code point @@ -1844,17 +1804,20 @@ inline bool IsUtf16SurrogatePair(wchar_t first, wchar_t second) { // Creates a Unicode code point from UTF16 surrogate pair. inline UInt32 CreateCodePointFromUtf16SurrogatePair(wchar_t first, wchar_t second) { + const auto first_u = static_cast<UInt32>(first); + const auto second_u = static_cast<UInt32>(second); const UInt32 mask = (1 << 10) - 1; - return (sizeof(wchar_t) == 2) ? - (((first & mask) << 10) | (second & mask)) + 0x10000 : - // This function should not be called when the condition is - // false, but we provide a sensible default in case it is. - static_cast<UInt32>(first); + return (sizeof(wchar_t) == 2) + ? (((first_u & mask) << 10) | (second_u & mask)) + 0x10000 + : + // This function should not be called when the condition is + // false, but we provide a sensible default in case it is. + first_u; } // Converts a wide string to a narrow string in UTF-8 encoding. // The wide string is assumed to have the following encoding: -// UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin, Symbian OS) +// UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin) // UTF-32 if sizeof(wchar_t) == 4 (on Linux) // Parameter str points to a null-terminated wide string. // Parameter num_chars may additionally limit the number @@ -1891,21 +1854,21 @@ std::string WideStringToUtf8(const wchar_t* str, int num_chars) { // Converts a wide C string to an std::string using the UTF-8 encoding. // NULL will be converted to "(null)". std::string String::ShowWideCString(const wchar_t * wide_c_str) { - if (wide_c_str == NULL) return "(null)"; + if (wide_c_str == nullptr) return "(null)"; return internal::WideStringToUtf8(wide_c_str, -1); } -// Compares two wide C strings. Returns true iff they have the same -// content. +// Compares two wide C strings. Returns true if and only if they have the +// same content. // // Unlike wcscmp(), this function can handle NULL argument(s). A NULL // C string is considered different to any non-NULL C string, // including the empty string. bool String::WideCStringEquals(const wchar_t * lhs, const wchar_t * rhs) { - if (lhs == NULL) return rhs == NULL; + if (lhs == nullptr) return rhs == nullptr; - if (rhs == NULL) return false; + if (rhs == nullptr) return false; return wcscmp(lhs, rhs) == 0; } @@ -1941,37 +1904,35 @@ AssertionResult CmpHelperSTRNE(const char* s1_expression, << " vs " << PrintToString(s2); } -// Compares two C strings, ignoring case. Returns true iff they have +// Compares two C strings, ignoring case. Returns true if and only if they have // the same content. // // Unlike strcasecmp(), this function can handle NULL argument(s). A // NULL C string is considered different to any non-NULL C string, // including the empty string. bool String::CaseInsensitiveCStringEquals(const char * lhs, const char * rhs) { - if (lhs == NULL) - return rhs == NULL; - if (rhs == NULL) - return false; + if (lhs == nullptr) return rhs == nullptr; + if (rhs == nullptr) return false; return posix::StrCaseCmp(lhs, rhs) == 0; } - // Compares two wide C strings, ignoring case. Returns true iff they - // have the same content. - // - // Unlike wcscasecmp(), this function can handle NULL argument(s). - // A NULL C string is considered different to any non-NULL wide C string, - // including the empty string. - // NB: The implementations on different platforms slightly differ. - // On windows, this method uses _wcsicmp which compares according to LC_CTYPE - // environment variable. On GNU platform this method uses wcscasecmp - // which compares according to LC_CTYPE category of the current locale. - // On MacOS X, it uses towlower, which also uses LC_CTYPE category of the - // current locale. +// Compares two wide C strings, ignoring case. Returns true if and only if they +// have the same content. +// +// Unlike wcscasecmp(), this function can handle NULL argument(s). +// A NULL C string is considered different to any non-NULL wide C string, +// including the empty string. +// NB: The implementations on different platforms slightly differ. +// On windows, this method uses _wcsicmp which compares according to LC_CTYPE +// environment variable. On GNU platform this method uses wcscasecmp +// which compares according to LC_CTYPE category of the current locale. +// On MacOS X, it uses towlower, which also uses LC_CTYPE category of the +// current locale. bool String::CaseInsensitiveWideCStringEquals(const wchar_t* lhs, const wchar_t* rhs) { - if (lhs == NULL) return rhs == NULL; + if (lhs == nullptr) return rhs == nullptr; - if (rhs == NULL) return false; + if (rhs == nullptr) return false; #if GTEST_OS_WINDOWS return _wcsicmp(lhs, rhs) == 0; @@ -1982,14 +1943,14 @@ bool String::CaseInsensitiveWideCStringEquals(const wchar_t* lhs, // Other unknown OSes may not define it either. wint_t left, right; do { - left = towlower(*lhs++); - right = towlower(*rhs++); + left = towlower(static_cast<wint_t>(*lhs++)); + right = towlower(static_cast<wint_t>(*rhs++)); } while (left && left == right); return left == right; #endif // OS selector } -// Returns true iff str ends with the given suffix, ignoring case. +// Returns true if and only if str ends with the given suffix, ignoring case. // Any string is considered to end with an empty suffix. bool String::EndsWithCaseInsensitive( const std::string& str, const std::string& suffix) { @@ -2008,12 +1969,17 @@ std::string String::FormatIntWidth2(int value) { } // Formats an int value as "%X". -std::string String::FormatHexInt(int value) { +std::string String::FormatHexUInt32(UInt32 value) { std::stringstream ss; ss << std::hex << std::uppercase << value; return ss.str(); } +// Formats an int value as "%X". +std::string String::FormatHexInt(int value) { + return FormatHexUInt32(static_cast<UInt32>(value)); +} + // Formats a byte as "%02X". std::string String::FormatByte(unsigned char value) { std::stringstream ss; @@ -2030,7 +1996,7 @@ std::string StringStreamToString(::std::stringstream* ss) { const char* const end = start + str.length(); std::string result; - result.reserve(2 * (end - start)); + result.reserve(static_cast<size_t>(2 * (end - start))); for (const char* ch = start; ch != end; ++ch) { if (*ch == '\0') { result += "\\0"; // Replaces NUL with "\\0"; @@ -2060,9 +2026,7 @@ std::string AppendUserMessage(const std::string& gtest_msg, // Creates an empty TestResult. TestResult::TestResult() - : death_test_count_(0), - elapsed_time_(0) { -} + : death_test_count_(0), start_timestamp_(0), elapsed_time_(0) {} // D'tor. TestResult::~TestResult() { @@ -2074,7 +2038,7 @@ TestResult::~TestResult() { const TestPartResult& TestResult::GetTestPartResult(int i) const { if (i < 0 || i >= total_part_count()) internal::posix::Abort(); - return test_part_results_.at(i); + return test_part_results_.at(static_cast<size_t>(i)); } // Returns the i-th test property. i can range from 0 to @@ -2083,7 +2047,7 @@ const TestPartResult& TestResult::GetTestPartResult(int i) const { const TestProperty& TestResult::GetTestProperty(int i) const { if (i < 0 || i >= test_property_count()) internal::posix::Abort(); - return test_properties_.at(i); + return test_properties_.at(static_cast<size_t>(i)); } // Clears the test part results. @@ -2131,18 +2095,18 @@ static const char* const kReservedTestSuitesAttributes[] = { // The list of reserved attributes used in the <testsuite> element of XML // output. static const char* const kReservedTestSuiteAttributes[] = { - "disabled", - "errors", - "failures", - "name", - "tests", - "time" -}; + "disabled", "errors", "failures", "name", "tests", "time", "timestamp"}; // The list of reserved attributes used in the <testcase> element of XML output. static const char* const kReservedTestCaseAttributes[] = { - "classname", "name", "status", "time", - "type_param", "value_param", "file", "line"}; + "classname", "name", "status", "time", "type_param", + "value_param", "file", "line"}; + +// Use a slightly different set for allowed output to ensure existing tests can +// still RecordProperty("result") or "RecordProperty(timestamp") +static const char* const kReservedOutputTestCaseAttributes[] = { + "classname", "name", "status", "time", "type_param", + "value_param", "file", "line", "result", "timestamp"}; template <int kSize> std::vector<std::string> ArrayAsVector(const char* const (&array)[kSize]) { @@ -2164,6 +2128,22 @@ static std::vector<std::string> GetReservedAttributesForElement( return std::vector<std::string>(); } +// TODO(jdesprez): Merge the two getReserved attributes once skip is improved +static std::vector<std::string> GetReservedOutputAttributesForElement( + const std::string& xml_element) { + if (xml_element == "testsuites") { + return ArrayAsVector(kReservedTestSuitesAttributes); + } else if (xml_element == "testsuite") { + return ArrayAsVector(kReservedTestSuiteAttributes); + } else if (xml_element == "testcase") { + return ArrayAsVector(kReservedOutputTestCaseAttributes); + } else { + GTEST_CHECK_(false) << "Unrecognized xml_element provided: " << xml_element; + } + // This code is unreachable but some compilers may not realizes that. + return std::vector<std::string>(); +} + static std::string FormatWordList(const std::vector<std::string>& words) { Message word_list; for (size_t i = 0; i < words.size(); ++i) { @@ -2207,7 +2187,17 @@ void TestResult::Clear() { elapsed_time_ = 0; } -// Returns true iff the test failed. +// Returns true off the test part was skipped. +static bool TestPartSkipped(const TestPartResult& result) { + return result.skipped(); +} + +// Returns true if and only if the test was skipped. +bool TestResult::Skipped() const { + return !Failed() && CountIf(test_part_results_, TestPartSkipped) > 0; +} + +// Returns true if and only if the test failed. bool TestResult::Failed() const { for (int i = 0; i < total_part_count(); ++i) { if (GetTestPartResult(i).failed()) @@ -2216,22 +2206,22 @@ bool TestResult::Failed() const { return false; } -// Returns true iff the test part fatally failed. +// Returns true if and only if the test part fatally failed. static bool TestPartFatallyFailed(const TestPartResult& result) { return result.fatally_failed(); } -// Returns true iff the test fatally failed. +// Returns true if and only if the test fatally failed. bool TestResult::HasFatalFailure() const { return CountIf(test_part_results_, TestPartFatallyFailed) > 0; } -// Returns true iff the test part non-fatally failed. +// Returns true if and only if the test part non-fatally failed. static bool TestPartNonfatallyFailed(const TestPartResult& result) { return result.nonfatally_failed(); } -// Returns true iff the test has a non-fatal failure. +// Returns true if and only if the test has a non-fatal failure. bool TestResult::HasNonfatalFailure() const { return CountIf(test_part_results_, TestPartNonfatallyFailed) > 0; } @@ -2294,25 +2284,25 @@ void ReportFailureInUnknownLocation(TestPartResult::Type result_type, // AddTestPartResult. UnitTest::GetInstance()->AddTestPartResult( result_type, - NULL, // No info about the source file where the exception occurred. - -1, // We have no info on which line caused the exception. + nullptr, // No info about the source file where the exception occurred. + -1, // We have no info on which line caused the exception. message, - ""); // No stack trace, either. + ""); // No stack trace, either. } } // namespace internal -// Google Test requires all tests in the same test case to use the same test +// Google Test requires all tests in the same test suite to use the same test // fixture class. This function checks if the current test has the -// same fixture class as the first test in the current test case. If +// same fixture class as the first test in the current test suite. If // yes, it returns true; otherwise it generates a Google Test failure and // returns false. bool Test::HasSameFixtureClass() { internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); - const TestCase* const test_case = impl->current_test_case(); + const TestSuite* const test_suite = impl->current_test_suite(); - // Info about the first test in the current test case. - const TestInfo* const first_test_info = test_case->test_info_list()[0]; + // Info about the first test in the current test suite. + const TestInfo* const first_test_info = test_suite->test_info_list()[0]; const internal::TypeId first_fixture_id = first_test_info->fixture_class_id_; const char* const first_test_name = first_test_info->name(); @@ -2328,7 +2318,7 @@ bool Test::HasSameFixtureClass() { const bool this_is_TEST = this_fixture_id == internal::GetTestTypeId(); if (first_is_TEST || this_is_TEST) { - // Both TEST and TEST_F appear in same test case, which is incorrect. + // Both TEST and TEST_F appear in same test suite, which is incorrect. // Tell the user how to fix this. // Gets the name of the TEST and the name of the TEST_F. Note @@ -2340,9 +2330,9 @@ bool Test::HasSameFixtureClass() { first_is_TEST ? this_test_name : first_test_name; ADD_FAILURE() - << "All tests in the same test case must use the same test fixture\n" - << "class, so mixing TEST_F and TEST in the same test case is\n" - << "illegal. In test case " << this_test_info->test_case_name() + << "All tests in the same test suite must use the same test fixture\n" + << "class, so mixing TEST_F and TEST in the same test suite is\n" + << "illegal. In test suite " << this_test_info->test_suite_name() << ",\n" << "test " << TEST_F_name << " is defined using TEST_F but\n" << "test " << TEST_name << " is defined using TEST. You probably\n" @@ -2352,15 +2342,15 @@ bool Test::HasSameFixtureClass() { // Two fixture classes with the same name appear in two different // namespaces, which is not allowed. Tell the user how to fix this. ADD_FAILURE() - << "All tests in the same test case must use the same test fixture\n" - << "class. However, in test case " - << this_test_info->test_case_name() << ",\n" - << "you defined test " << first_test_name - << " and test " << this_test_name << "\n" + << "All tests in the same test suite must use the same test fixture\n" + << "class. However, in test suite " + << this_test_info->test_suite_name() << ",\n" + << "you defined test " << first_test_name << " and test " + << this_test_name << "\n" << "using two different test fixture classes. This can happen if\n" << "the two classes are from different namespaces or translation\n" << "units and have the same name. You should probably rename one\n" - << "of the classes to put the tests into different test cases."; + << "of the classes to put the tests into different test suites."; } return false; } @@ -2393,7 +2383,7 @@ namespace internal { static std::string FormatCxxExceptionMessage(const char* description, const char* location) { Message message; - if (description != NULL) { + if (description != nullptr) { message << "C++ exception with description \"" << description << "\""; } else { message << "Unknown C++ exception"; @@ -2491,7 +2481,7 @@ Result HandleExceptionsInMethodIfSupported( } catch (...) { // NOLINT internal::ReportFailureInUnknownLocation( TestPartResult::kFatalFailure, - FormatCxxExceptionMessage(NULL, location)); + FormatCxxExceptionMessage(nullptr, location)); } return static_cast<Result>(0); #else @@ -2511,8 +2501,9 @@ void Test::Run() { internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); impl->os_stack_trace_getter()->UponLeavingGTest(); internal::HandleExceptionsInMethodIfSupported(this, &Test::SetUp, "SetUp()"); - // We will run the test only if SetUp() was successful. - if (!HasFatalFailure()) { + // We will run the test only if SetUp() was successful and didn't call + // GTEST_SKIP(). + if (!HasFatalFailure() && !IsSkipped()) { impl->os_stack_trace_getter()->UponLeavingGTest(); internal::HandleExceptionsInMethodIfSupported( this, &Test::TestBody, "the test body"); @@ -2526,32 +2517,36 @@ void Test::Run() { this, &Test::TearDown, "TearDown()"); } -// Returns true iff the current test has a fatal failure. +// Returns true if and only if the current test has a fatal failure. bool Test::HasFatalFailure() { return internal::GetUnitTestImpl()->current_test_result()->HasFatalFailure(); } -// Returns true iff the current test has a non-fatal failure. +// Returns true if and only if the current test has a non-fatal failure. bool Test::HasNonfatalFailure() { return internal::GetUnitTestImpl()->current_test_result()-> HasNonfatalFailure(); } +// Returns true if and only if the current test was skipped. +bool Test::IsSkipped() { + return internal::GetUnitTestImpl()->current_test_result()->Skipped(); +} + // class TestInfo // Constructs a TestInfo object. It assumes ownership of the test factory // object. -TestInfo::TestInfo(const std::string& a_test_case_name, - const std::string& a_name, - const char* a_type_param, +TestInfo::TestInfo(const std::string& a_test_suite_name, + const std::string& a_name, const char* a_type_param, const char* a_value_param, internal::CodeLocation a_code_location, internal::TypeId fixture_class_id, internal::TestFactoryBase* factory) - : test_case_name_(a_test_case_name), + : test_suite_name_(a_test_suite_name), name_(a_name), - type_param_(a_type_param ? new std::string(a_type_param) : NULL), - value_param_(a_value_param ? new std::string(a_value_param) : NULL), + type_param_(a_type_param ? new std::string(a_type_param) : nullptr), + value_param_(a_value_param ? new std::string(a_value_param) : nullptr), location_(a_code_location), fixture_class_id_(fixture_class_id), should_run_(false), @@ -2570,7 +2565,7 @@ namespace internal { // // Arguments: // -// test_case_name: name of the test case +// test_suite_name: name of the test suite // name: name of the test // type_param: the name of the test's type parameter, or NULL if // this is not a typed or a type-parameterized test. @@ -2578,40 +2573,35 @@ namespace internal { // or NULL if this is not a value-parameterized test. // code_location: code location where the test is defined // fixture_class_id: ID of the test fixture class -// set_up_tc: pointer to the function that sets up the test case -// tear_down_tc: pointer to the function that tears down the test case +// set_up_tc: pointer to the function that sets up the test suite +// tear_down_tc: pointer to the function that tears down the test suite // factory: pointer to the factory that creates a test object. // The newly created TestInfo instance will assume // ownership of the factory object. TestInfo* MakeAndRegisterTestInfo( - const char* test_case_name, - const char* name, - const char* type_param, - const char* value_param, - CodeLocation code_location, - TypeId fixture_class_id, - SetUpTestCaseFunc set_up_tc, - TearDownTestCaseFunc tear_down_tc, - TestFactoryBase* factory) { + const char* test_suite_name, const char* name, const char* type_param, + const char* value_param, CodeLocation code_location, + TypeId fixture_class_id, SetUpTestSuiteFunc set_up_tc, + TearDownTestSuiteFunc tear_down_tc, TestFactoryBase* factory) { TestInfo* const test_info = - new TestInfo(test_case_name, name, type_param, value_param, + new TestInfo(test_suite_name, name, type_param, value_param, code_location, fixture_class_id, factory); GetUnitTestImpl()->AddTestInfo(set_up_tc, tear_down_tc, test_info); return test_info; } -void ReportInvalidTestCaseType(const char* test_case_name, - CodeLocation code_location) { +void ReportInvalidTestSuiteType(const char* test_suite_name, + CodeLocation code_location) { Message errors; errors - << "Attempted redefinition of test case " << test_case_name << ".\n" - << "All tests in the same test case must use the same test fixture\n" - << "class. However, in test case " << test_case_name << ", you tried\n" + << "Attempted redefinition of test suite " << test_suite_name << ".\n" + << "All tests in the same test suite must use the same test fixture\n" + << "class. However, in test suite " << test_suite_name << ", you tried\n" << "to define a test using a fixture class different from the one\n" << "used earlier. This can happen if the two fixture classes are\n" << "from different namespaces and have the same name. You should\n" << "probably rename one of the classes to put the tests into different\n" - << "test cases."; + << "test suites."; GTEST_LOG_(ERROR) << FormatFileLocation(code_location.file.c_str(), code_location.line) @@ -2624,7 +2614,7 @@ namespace { // A predicate that checks the test name of a TestInfo against a known // value. // -// This is used for implementation of the TestCase class only. We put +// This is used for implementation of the TestSuite class only. We put // it in the anonymous namespace to prevent polluting the outer // namespace. // @@ -2637,7 +2627,7 @@ class TestNameIs { explicit TestNameIs(const char* name) : name_(name) {} - // Returns true iff the test name of test_info matches name_. + // Returns true if and only if the test name of test_info matches name_. bool operator()(const TestInfo * test_info) const { return test_info && test_info->name() == name_; } @@ -2651,7 +2641,7 @@ class TestNameIs { namespace internal { // This method expands all parameterized tests registered with macros TEST_P -// and INSTANTIATE_TEST_CASE_P into regular tests and registers those. +// and INSTANTIATE_TEST_SUITE_P into regular tests and registers those. // This will be done just once during the program runtime. void UnitTestImpl::RegisterParameterizedTests() { if (!parameterized_tests_registered_) { @@ -2685,19 +2675,23 @@ void TestInfo::Run() { factory_, &internal::TestFactoryBase::CreateTest, "the test fixture's constructor"); - // Runs the test if the constructor didn't generate a fatal failure. + // Runs the test if the constructor didn't generate a fatal failure or invoke + // GTEST_SKIP(). // Note that the object will not be null - if (!Test::HasFatalFailure()) { + if (!Test::HasFatalFailure() && !Test::IsSkipped()) { // This doesn't throw as all user code that can throw are wrapped into // exception handling code. test->Run(); } + if (test != nullptr) { // Deletes the test object. impl->os_stack_trace_getter()->UponLeavingGTest(); internal::HandleExceptionsInMethodIfSupported( test, &Test::DeleteSelf_, "the test fixture's destructor"); + } + result_.set_start_timestamp(start); result_.set_elapsed_time(internal::GetTimeInMillis() - start); // Notifies the unit test event listener that a test has just finished. @@ -2705,134 +2699,151 @@ void TestInfo::Run() { // Tells UnitTest to stop associating assertion results to this // test. - impl->set_current_test_info(NULL); + impl->set_current_test_info(nullptr); } -// class TestCase +// class TestSuite -// Gets the number of successful tests in this test case. -int TestCase::successful_test_count() const { +// Gets the number of successful tests in this test suite. +int TestSuite::successful_test_count() const { return CountIf(test_info_list_, TestPassed); } -// Gets the number of failed tests in this test case. -int TestCase::failed_test_count() const { +// Gets the number of successful tests in this test suite. +int TestSuite::skipped_test_count() const { + return CountIf(test_info_list_, TestSkipped); +} + +// Gets the number of failed tests in this test suite. +int TestSuite::failed_test_count() const { return CountIf(test_info_list_, TestFailed); } // Gets the number of disabled tests that will be reported in the XML report. -int TestCase::reportable_disabled_test_count() const { +int TestSuite::reportable_disabled_test_count() const { return CountIf(test_info_list_, TestReportableDisabled); } -// Gets the number of disabled tests in this test case. -int TestCase::disabled_test_count() const { +// Gets the number of disabled tests in this test suite. +int TestSuite::disabled_test_count() const { return CountIf(test_info_list_, TestDisabled); } // Gets the number of tests to be printed in the XML report. -int TestCase::reportable_test_count() const { +int TestSuite::reportable_test_count() const { return CountIf(test_info_list_, TestReportable); } -// Get the number of tests in this test case that should run. -int TestCase::test_to_run_count() const { +// Get the number of tests in this test suite that should run. +int TestSuite::test_to_run_count() const { return CountIf(test_info_list_, ShouldRunTest); } // Gets the number of all tests. -int TestCase::total_test_count() const { +int TestSuite::total_test_count() const { return static_cast<int>(test_info_list_.size()); } -// Creates a TestCase with the given name. +// Creates a TestSuite with the given name. // // Arguments: // -// name: name of the test case -// a_type_param: the name of the test case's type parameter, or NULL if -// this is not a typed or a type-parameterized test case. -// set_up_tc: pointer to the function that sets up the test case -// tear_down_tc: pointer to the function that tears down the test case -TestCase::TestCase(const char* a_name, const char* a_type_param, - Test::SetUpTestCaseFunc set_up_tc, - Test::TearDownTestCaseFunc tear_down_tc) +// name: name of the test suite +// a_type_param: the name of the test suite's type parameter, or NULL if +// this is not a typed or a type-parameterized test suite. +// set_up_tc: pointer to the function that sets up the test suite +// tear_down_tc: pointer to the function that tears down the test suite +TestSuite::TestSuite(const char* a_name, const char* a_type_param, + internal::SetUpTestSuiteFunc set_up_tc, + internal::TearDownTestSuiteFunc tear_down_tc) : name_(a_name), - type_param_(a_type_param ? new std::string(a_type_param) : NULL), + type_param_(a_type_param ? new std::string(a_type_param) : nullptr), set_up_tc_(set_up_tc), tear_down_tc_(tear_down_tc), should_run_(false), - elapsed_time_(0) { -} + start_timestamp_(0), + elapsed_time_(0) {} -// Destructor of TestCase. -TestCase::~TestCase() { +// Destructor of TestSuite. +TestSuite::~TestSuite() { // Deletes every Test in the collection. ForEach(test_info_list_, internal::Delete<TestInfo>); } // Returns the i-th test among all the tests. i can range from 0 to // total_test_count() - 1. If i is not in that range, returns NULL. -const TestInfo* TestCase::GetTestInfo(int i) const { +const TestInfo* TestSuite::GetTestInfo(int i) const { const int index = GetElementOr(test_indices_, i, -1); - return index < 0 ? NULL : test_info_list_[index]; + return index < 0 ? nullptr : test_info_list_[static_cast<size_t>(index)]; } // Returns the i-th test among all the tests. i can range from 0 to // total_test_count() - 1. If i is not in that range, returns NULL. -TestInfo* TestCase::GetMutableTestInfo(int i) { +TestInfo* TestSuite::GetMutableTestInfo(int i) { const int index = GetElementOr(test_indices_, i, -1); - return index < 0 ? NULL : test_info_list_[index]; + return index < 0 ? nullptr : test_info_list_[static_cast<size_t>(index)]; } -// Adds a test to this test case. Will delete the test upon -// destruction of the TestCase object. -void TestCase::AddTestInfo(TestInfo * test_info) { +// Adds a test to this test suite. Will delete the test upon +// destruction of the TestSuite object. +void TestSuite::AddTestInfo(TestInfo* test_info) { test_info_list_.push_back(test_info); test_indices_.push_back(static_cast<int>(test_indices_.size())); } -// Runs every test in this TestCase. -void TestCase::Run() { +// Runs every test in this TestSuite. +void TestSuite::Run() { if (!should_run_) return; internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); - impl->set_current_test_case(this); + impl->set_current_test_suite(this); TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater(); + // Call both legacy and the new API + repeater->OnTestSuiteStart(*this); +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI repeater->OnTestCaseStart(*this); +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI + impl->os_stack_trace_getter()->UponLeavingGTest(); internal::HandleExceptionsInMethodIfSupported( - this, &TestCase::RunSetUpTestCase, "SetUpTestCase()"); + this, &TestSuite::RunSetUpTestSuite, "SetUpTestSuite()"); - const internal::TimeInMillis start = internal::GetTimeInMillis(); + start_timestamp_ = internal::GetTimeInMillis(); for (int i = 0; i < total_test_count(); i++) { GetMutableTestInfo(i)->Run(); } - elapsed_time_ = internal::GetTimeInMillis() - start; + elapsed_time_ = internal::GetTimeInMillis() - start_timestamp_; impl->os_stack_trace_getter()->UponLeavingGTest(); internal::HandleExceptionsInMethodIfSupported( - this, &TestCase::RunTearDownTestCase, "TearDownTestCase()"); + this, &TestSuite::RunTearDownTestSuite, "TearDownTestSuite()"); + // Call both legacy and the new API + repeater->OnTestSuiteEnd(*this); +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI repeater->OnTestCaseEnd(*this); - impl->set_current_test_case(NULL); +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI + + impl->set_current_test_suite(nullptr); } -// Clears the results of all tests in this test case. -void TestCase::ClearResult() { +// Clears the results of all tests in this test suite. +void TestSuite::ClearResult() { ad_hoc_test_result_.Clear(); ForEach(test_info_list_, TestInfo::ClearTestResult); } -// Shuffles the tests in this test case. -void TestCase::ShuffleTests(internal::Random* random) { +// Shuffles the tests in this test suite. +void TestSuite::ShuffleTests(internal::Random* random) { Shuffle(random, &test_indices_); } // Restores the test order to before the first shuffle. -void TestCase::UnshuffleTests() { +void TestSuite::UnshuffleTests() { for (size_t i = 0; i < test_indices_.size(); i++) { test_indices_[i] = static_cast<int>(i); } @@ -2855,9 +2866,9 @@ static std::string FormatTestCount(int test_count) { return FormatCountableNoun(test_count, "test", "tests"); } -// Formats the count of test cases. -static std::string FormatTestCaseCount(int test_case_count) { - return FormatCountableNoun(test_case_count, "test case", "test cases"); +// Formats the count of test suites. +static std::string FormatTestSuiteCount(int test_suite_count) { + return FormatCountableNoun(test_suite_count, "test suite", "test suites"); } // Converts a TestPartResult::Type enum to human-friendly string @@ -2866,6 +2877,8 @@ static std::string FormatTestCaseCount(int test_case_count) { // between the two when viewing the test result. static const char * TestPartResultTypeToString(TestPartResult::Type type) { switch (type) { + case TestPartResult::kSkip: + return "Skipped"; case TestPartResult::kSuccess: return "Success"; @@ -2913,14 +2926,6 @@ static void PrintTestPartResult(const TestPartResult& test_part_result) { } // class PrettyUnitTestResultPrinter - -enum GTestColor { - COLOR_DEFAULT, - COLOR_RED, - COLOR_GREEN, - COLOR_YELLOW -}; - #if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE && \ !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT && !GTEST_OS_WINDOWS_MINGW @@ -2974,13 +2979,14 @@ static const char* GetAnsiColorCode(GTestColor color) { case COLOR_RED: return "1"; case COLOR_GREEN: return "2"; case COLOR_YELLOW: return "3"; - default: return NULL; - }; + default: + return nullptr; + } } #endif // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE -// Returns true iff Google Test should use colors in the output. +// Returns true if and only if Google Test should use colors in the output. bool ShouldUseColor(bool stdout_is_tty) { const char* const gtest_color = GTEST_FLAG(color).c_str(); @@ -3025,15 +3031,14 @@ void ColoredPrintf(GTestColor color, const char* fmt, ...) { va_list args; va_start(args, fmt); -#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS || \ - GTEST_OS_IOS || GTEST_OS_WINDOWS_PHONE || GTEST_OS_WINDOWS_RT +#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_ZOS || GTEST_OS_IOS || \ + GTEST_OS_WINDOWS_PHONE || GTEST_OS_WINDOWS_RT || defined(ESP_PLATFORM) const bool use_color = AlwaysFalse(); #else static const bool in_color_mode = ShouldUseColor(posix::IsATTY(posix::FileNo(stdout)) != 0); const bool use_color = in_color_mode && (color != COLOR_DEFAULT); -#endif // GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS - // The '!= 0' comparison is necessary to satisfy MSVC 7.1. +#endif // GTEST_OS_WINDOWS_MOBILE || GTEST_OS_ZOS if (!use_color) { vprintf(fmt, args); @@ -3079,14 +3084,13 @@ static void PrintFullTestCommentIfPresent(const TestInfo& test_info) { const char* const type_param = test_info.type_param(); const char* const value_param = test_info.value_param(); - if (type_param != NULL || value_param != NULL) { + if (type_param != nullptr || value_param != nullptr) { printf(", where "); - if (type_param != NULL) { + if (type_param != nullptr) { printf("%s = %s", kTypeParamLabel, type_param); - if (value_param != NULL) - printf(" and "); + if (value_param != nullptr) printf(" and "); } - if (value_param != NULL) { + if (value_param != nullptr) { printf("%s = %s", kValueParamLabel, value_param); } } @@ -3098,27 +3102,39 @@ static void PrintFullTestCommentIfPresent(const TestInfo& test_info) { class PrettyUnitTestResultPrinter : public TestEventListener { public: PrettyUnitTestResultPrinter() {} - static void PrintTestName(const char * test_case, const char * test) { - printf("%s.%s", test_case, test); + static void PrintTestName(const char* test_suite, const char* test) { + printf("%s.%s", test_suite, test); } // The following methods override what's in the TestEventListener class. - virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {} - virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration); - virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test); - virtual void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) {} - virtual void OnTestCaseStart(const TestCase& test_case); - virtual void OnTestStart(const TestInfo& test_info); - virtual void OnTestPartResult(const TestPartResult& result); - virtual void OnTestEnd(const TestInfo& test_info); - virtual void OnTestCaseEnd(const TestCase& test_case); - virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test); - virtual void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) {} - virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); - virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) {} + void OnTestProgramStart(const UnitTest& /*unit_test*/) override {} + void OnTestIterationStart(const UnitTest& unit_test, int iteration) override; + void OnEnvironmentsSetUpStart(const UnitTest& unit_test) override; + void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) override {} +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + void OnTestCaseStart(const TestCase& test_case) override; +#else + void OnTestSuiteStart(const TestSuite& test_suite) override; +#endif // OnTestCaseStart + + void OnTestStart(const TestInfo& test_info) override; + + void OnTestPartResult(const TestPartResult& result) override; + void OnTestEnd(const TestInfo& test_info) override; +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + void OnTestCaseEnd(const TestCase& test_case) override; +#else + void OnTestSuiteEnd(const TestSuite& test_suite) override; +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + + void OnEnvironmentsTearDownStart(const UnitTest& unit_test) override; + void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) override {} + void OnTestIterationEnd(const UnitTest& unit_test, int iteration) override; + void OnTestProgramEnd(const UnitTest& /*unit_test*/) override {} private: static void PrintFailedTests(const UnitTest& unit_test); + static void PrintSkippedTests(const UnitTest& unit_test); }; // Fired before each iteration of tests starts. @@ -3153,7 +3169,7 @@ void PrettyUnitTestResultPrinter::OnTestIterationStart( ColoredPrintf(COLOR_GREEN, "[==========] "); printf("Running %s from %s.\n", FormatTestCount(unit_test.test_to_run_count()).c_str(), - FormatTestCaseCount(unit_test.test_case_to_run_count()).c_str()); + FormatTestSuiteCount(unit_test.test_suite_to_run_count()).c_str()); fflush(stdout); } @@ -3164,22 +3180,38 @@ void PrettyUnitTestResultPrinter::OnEnvironmentsSetUpStart( fflush(stdout); } +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ void PrettyUnitTestResultPrinter::OnTestCaseStart(const TestCase& test_case) { const std::string counts = FormatCountableNoun(test_case.test_to_run_count(), "test", "tests"); ColoredPrintf(COLOR_GREEN, "[----------] "); printf("%s from %s", counts.c_str(), test_case.name()); - if (test_case.type_param() == NULL) { + if (test_case.type_param() == nullptr) { printf("\n"); } else { printf(", where %s = %s\n", kTypeParamLabel, test_case.type_param()); } fflush(stdout); } +#else +void PrettyUnitTestResultPrinter::OnTestSuiteStart( + const TestSuite& test_suite) { + const std::string counts = + FormatCountableNoun(test_suite.test_to_run_count(), "test", "tests"); + ColoredPrintf(COLOR_GREEN, "[----------] "); + printf("%s from %s", counts.c_str(), test_suite.name()); + if (test_suite.type_param() == nullptr) { + printf("\n"); + } else { + printf(", where %s = %s\n", kTypeParamLabel, test_suite.type_param()); + } + fflush(stdout); +} +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ void PrettyUnitTestResultPrinter::OnTestStart(const TestInfo& test_info) { ColoredPrintf(COLOR_GREEN, "[ RUN ] "); - PrintTestName(test_info.test_case_name(), test_info.name()); + PrintTestName(test_info.test_suite_name(), test_info.name()); printf("\n"); fflush(stdout); } @@ -3187,22 +3219,29 @@ void PrettyUnitTestResultPrinter::OnTestStart(const TestInfo& test_info) { // Called after an assertion failure. void PrettyUnitTestResultPrinter::OnTestPartResult( const TestPartResult& result) { - // If the test part succeeded, we don't need to do anything. - if (result.type() == TestPartResult::kSuccess) - return; - - // Print failure message from the assertion (e.g. expected this and got that). - PrintTestPartResult(result); - fflush(stdout); + switch (result.type()) { + // If the test part succeeded, or was skipped, + // we don't need to do anything. + case TestPartResult::kSkip: + case TestPartResult::kSuccess: + return; + default: + // Print failure message from the assertion + // (e.g. expected this and got that). + PrintTestPartResult(result); + fflush(stdout); + } } void PrettyUnitTestResultPrinter::OnTestEnd(const TestInfo& test_info) { if (test_info.result()->Passed()) { ColoredPrintf(COLOR_GREEN, "[ OK ] "); + } else if (test_info.result()->Skipped()) { + ColoredPrintf(COLOR_GREEN, "[ SKIPPED ] "); } else { ColoredPrintf(COLOR_RED, "[ FAILED ] "); } - PrintTestName(test_info.test_case_name(), test_info.name()); + PrintTestName(test_info.test_suite_name(), test_info.name()); if (test_info.result()->Failed()) PrintFullTestCommentIfPresent(test_info); @@ -3215,17 +3254,29 @@ void PrettyUnitTestResultPrinter::OnTestEnd(const TestInfo& test_info) { fflush(stdout); } +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ void PrettyUnitTestResultPrinter::OnTestCaseEnd(const TestCase& test_case) { if (!GTEST_FLAG(print_time)) return; const std::string counts = FormatCountableNoun(test_case.test_to_run_count(), "test", "tests"); ColoredPrintf(COLOR_GREEN, "[----------] "); - printf("%s from %s (%s ms total)\n\n", - counts.c_str(), test_case.name(), + printf("%s from %s (%s ms total)\n\n", counts.c_str(), test_case.name(), internal::StreamableToString(test_case.elapsed_time()).c_str()); fflush(stdout); } +#else +void PrettyUnitTestResultPrinter::OnTestSuiteEnd(const TestSuite& test_suite) { + if (!GTEST_FLAG(print_time)) return; + + const std::string counts = + FormatCountableNoun(test_suite.test_to_run_count(), "test", "tests"); + ColoredPrintf(COLOR_GREEN, "[----------] "); + printf("%s from %s (%s ms total)\n\n", counts.c_str(), test_suite.name(), + internal::StreamableToString(test_suite.elapsed_time()).c_str()); + fflush(stdout); +} +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ void PrettyUnitTestResultPrinter::OnEnvironmentsTearDownStart( const UnitTest& /*unit_test*/) { @@ -3241,30 +3292,54 @@ void PrettyUnitTestResultPrinter::PrintFailedTests(const UnitTest& unit_test) { return; } - for (int i = 0; i < unit_test.total_test_case_count(); ++i) { - const TestCase& test_case = *unit_test.GetTestCase(i); - if (!test_case.should_run() || (test_case.failed_test_count() == 0)) { + for (int i = 0; i < unit_test.total_test_suite_count(); ++i) { + const TestSuite& test_suite = *unit_test.GetTestSuite(i); + if (!test_suite.should_run() || (test_suite.failed_test_count() == 0)) { continue; } - for (int j = 0; j < test_case.total_test_count(); ++j) { - const TestInfo& test_info = *test_case.GetTestInfo(j); - if (!test_info.should_run() || test_info.result()->Passed()) { + for (int j = 0; j < test_suite.total_test_count(); ++j) { + const TestInfo& test_info = *test_suite.GetTestInfo(j); + if (!test_info.should_run() || !test_info.result()->Failed()) { continue; } ColoredPrintf(COLOR_RED, "[ FAILED ] "); - printf("%s.%s", test_case.name(), test_info.name()); + printf("%s.%s", test_suite.name(), test_info.name()); PrintFullTestCommentIfPresent(test_info); printf("\n"); } } } +// Internal helper for printing the list of skipped tests. +void PrettyUnitTestResultPrinter::PrintSkippedTests(const UnitTest& unit_test) { + const int skipped_test_count = unit_test.skipped_test_count(); + if (skipped_test_count == 0) { + return; + } + + for (int i = 0; i < unit_test.total_test_suite_count(); ++i) { + const TestSuite& test_suite = *unit_test.GetTestSuite(i); + if (!test_suite.should_run() || (test_suite.skipped_test_count() == 0)) { + continue; + } + for (int j = 0; j < test_suite.total_test_count(); ++j) { + const TestInfo& test_info = *test_suite.GetTestInfo(j); + if (!test_info.should_run() || !test_info.result()->Skipped()) { + continue; + } + ColoredPrintf(COLOR_GREEN, "[ SKIPPED ] "); + printf("%s.%s", test_suite.name(), test_info.name()); + printf("\n"); + } + } +} + void PrettyUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, int /*iteration*/) { ColoredPrintf(COLOR_GREEN, "[==========] "); printf("%s from %s ran.", FormatTestCount(unit_test.test_to_run_count()).c_str(), - FormatTestCaseCount(unit_test.test_case_to_run_count()).c_str()); + FormatTestSuiteCount(unit_test.test_suite_to_run_count()).c_str()); if (GTEST_FLAG(print_time)) { printf(" (%s ms total)", internal::StreamableToString(unit_test.elapsed_time()).c_str()); @@ -3273,6 +3348,13 @@ void PrettyUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, ColoredPrintf(COLOR_GREEN, "[ PASSED ] "); printf("%s.\n", FormatTestCount(unit_test.successful_test_count()).c_str()); + const int skipped_test_count = unit_test.skipped_test_count(); + if (skipped_test_count > 0) { + ColoredPrintf(COLOR_GREEN, "[ SKIPPED ] "); + printf("%s, listed below:\n", FormatTestCount(skipped_test_count).c_str()); + PrintSkippedTests(unit_test); + } + int num_failures = unit_test.failed_test_count(); if (!unit_test.Passed()) { const int failed_test_count = unit_test.failed_test_count(); @@ -3305,7 +3387,7 @@ void PrettyUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, class TestEventRepeater : public TestEventListener { public: TestEventRepeater() : forwarding_enabled_(true) {} - virtual ~TestEventRepeater(); + ~TestEventRepeater() override; void Append(TestEventListener *listener); TestEventListener* Release(TestEventListener* listener); @@ -3314,19 +3396,27 @@ class TestEventRepeater : public TestEventListener { bool forwarding_enabled() const { return forwarding_enabled_; } void set_forwarding_enabled(bool enable) { forwarding_enabled_ = enable; } - virtual void OnTestProgramStart(const UnitTest& unit_test); - virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration); - virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test); - virtual void OnEnvironmentsSetUpEnd(const UnitTest& unit_test); - virtual void OnTestCaseStart(const TestCase& test_case); - virtual void OnTestStart(const TestInfo& test_info); - virtual void OnTestPartResult(const TestPartResult& result); - virtual void OnTestEnd(const TestInfo& test_info); - virtual void OnTestCaseEnd(const TestCase& test_case); - virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test); - virtual void OnEnvironmentsTearDownEnd(const UnitTest& unit_test); - virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); - virtual void OnTestProgramEnd(const UnitTest& unit_test); + void OnTestProgramStart(const UnitTest& unit_test) override; + void OnTestIterationStart(const UnitTest& unit_test, int iteration) override; + void OnEnvironmentsSetUpStart(const UnitTest& unit_test) override; + void OnEnvironmentsSetUpEnd(const UnitTest& unit_test) override; +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + void OnTestCaseStart(const TestSuite& parameter) override; +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + void OnTestSuiteStart(const TestSuite& parameter) override; + void OnTestStart(const TestInfo& test_info) override; + void OnTestPartResult(const TestPartResult& result) override; + void OnTestEnd(const TestInfo& test_info) override; +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + void OnTestCaseEnd(const TestCase& parameter) override; +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + void OnTestSuiteEnd(const TestSuite& parameter) override; + void OnEnvironmentsTearDownStart(const UnitTest& unit_test) override; + void OnEnvironmentsTearDownEnd(const UnitTest& unit_test) override; + void OnTestIterationEnd(const UnitTest& unit_test, int iteration) override; + void OnTestProgramEnd(const UnitTest& unit_test) override; private: // Controls whether events will be forwarded to listeners_. Set to false @@ -3346,16 +3436,15 @@ void TestEventRepeater::Append(TestEventListener *listener) { listeners_.push_back(listener); } -// FIXME: Factor the search functionality into Vector::Find. TestEventListener* TestEventRepeater::Release(TestEventListener *listener) { for (size_t i = 0; i < listeners_.size(); ++i) { if (listeners_[i] == listener) { - listeners_.erase(listeners_.begin() + i); + listeners_.erase(listeners_.begin() + static_cast<int>(i)); return listener; } } - return NULL; + return nullptr; } // Since most methods are very similar, use macros to reduce boilerplate. @@ -3370,25 +3459,33 @@ void TestEventRepeater::Name(const Type& parameter) { \ } // This defines a member that forwards the call to all listeners in reverse // order. -#define GTEST_REVERSE_REPEATER_METHOD_(Name, Type) \ -void TestEventRepeater::Name(const Type& parameter) { \ - if (forwarding_enabled_) { \ - for (int i = static_cast<int>(listeners_.size()) - 1; i >= 0; i--) { \ - listeners_[i]->Name(parameter); \ - } \ - } \ -} +#define GTEST_REVERSE_REPEATER_METHOD_(Name, Type) \ + void TestEventRepeater::Name(const Type& parameter) { \ + if (forwarding_enabled_) { \ + for (size_t i = listeners_.size(); i != 0; i--) { \ + listeners_[i - 1]->Name(parameter); \ + } \ + } \ + } GTEST_REPEATER_METHOD_(OnTestProgramStart, UnitTest) GTEST_REPEATER_METHOD_(OnEnvironmentsSetUpStart, UnitTest) -GTEST_REPEATER_METHOD_(OnTestCaseStart, TestCase) +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +GTEST_REPEATER_METHOD_(OnTestCaseStart, TestSuite) +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +GTEST_REPEATER_METHOD_(OnTestSuiteStart, TestSuite) GTEST_REPEATER_METHOD_(OnTestStart, TestInfo) GTEST_REPEATER_METHOD_(OnTestPartResult, TestPartResult) GTEST_REPEATER_METHOD_(OnEnvironmentsTearDownStart, UnitTest) GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsSetUpEnd, UnitTest) GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsTearDownEnd, UnitTest) GTEST_REVERSE_REPEATER_METHOD_(OnTestEnd, TestInfo) -GTEST_REVERSE_REPEATER_METHOD_(OnTestCaseEnd, TestCase) +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +GTEST_REVERSE_REPEATER_METHOD_(OnTestCaseEnd, TestSuite) +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +GTEST_REVERSE_REPEATER_METHOD_(OnTestSuiteEnd, TestSuite) GTEST_REVERSE_REPEATER_METHOD_(OnTestProgramEnd, UnitTest) #undef GTEST_REPEATER_METHOD_ @@ -3406,8 +3503,8 @@ void TestEventRepeater::OnTestIterationStart(const UnitTest& unit_test, void TestEventRepeater::OnTestIterationEnd(const UnitTest& unit_test, int iteration) { if (forwarding_enabled_) { - for (int i = static_cast<int>(listeners_.size()) - 1; i >= 0; i--) { - listeners_[i]->OnTestIterationEnd(unit_test, iteration); + for (size_t i = listeners_.size(); i > 0; i--) { + listeners_[i - 1]->OnTestIterationEnd(unit_test, iteration); } } } @@ -3419,12 +3516,12 @@ class XmlUnitTestResultPrinter : public EmptyTestEventListener { public: explicit XmlUnitTestResultPrinter(const char* output_file); - virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); - void ListTestsMatchingFilter(const std::vector<TestCase*>& test_cases); + void OnTestIterationEnd(const UnitTest& unit_test, int iteration) override; + void ListTestsMatchingFilter(const std::vector<TestSuite*>& test_suites); // Prints an XML summary of all unit tests. static void PrintXmlTestsList(std::ostream* stream, - const std::vector<TestCase*>& test_cases); + const std::vector<TestSuite*>& test_suites); private: // Is c a whitespace character that is normalized to a space character @@ -3469,12 +3566,12 @@ class XmlUnitTestResultPrinter : public EmptyTestEventListener { // Streams an XML representation of a TestInfo object. static void OutputXmlTestInfo(::std::ostream* stream, - const char* test_case_name, + const char* test_suite_name, const TestInfo& test_info); - // Prints an XML representation of a TestCase object - static void PrintXmlTestCase(::std::ostream* stream, - const TestCase& test_case); + // Prints an XML representation of a TestSuite object + static void PrintXmlTestSuite(::std::ostream* stream, + const TestSuite& test_suite); // Prints an XML summary of unit_test to output stream out. static void PrintXmlUnitTest(::std::ostream* stream, @@ -3516,10 +3613,10 @@ void XmlUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, } void XmlUnitTestResultPrinter::ListTestsMatchingFilter( - const std::vector<TestCase*>& test_cases) { + const std::vector<TestSuite*>& test_suites) { FILE* xmlout = OpenFileForWriting(output_file_); std::stringstream stream; - PrintXmlTestsList(&stream, test_cases); + PrintXmlTestsList(&stream, test_suites); fprintf(xmlout, "%s", StringStreamToString(&stream).c_str()); fclose(xmlout); } @@ -3534,8 +3631,6 @@ void XmlUnitTestResultPrinter::ListTestsMatchingFilter( // module will consist of ordinary English text. // If this module is ever modified to produce version 1.1 XML output, // most invalid characters can be retained using character references. -// FIXME: It might be nice to have a minimally invasive, human-readable -// escaping scheme for invalid characters, rather than dropping them. std::string XmlUnitTestResultPrinter::EscapeXml( const std::string& str, bool is_attribute) { Message m; @@ -3600,7 +3695,7 @@ std::string XmlUnitTestResultPrinter::RemoveInvalidXmlCharacters( // This is how Google Test concepts map to the DTD: // // <testsuites name="AllTests"> <-- corresponds to a UnitTest object -// <testsuite name="testcase-name"> <-- corresponds to a TestCase object +// <testsuite name="testcase-name"> <-- corresponds to a TestSuite object // <testcase name="test-name"> <-- corresponds to a TestInfo object // <failure message="...">...</failure> // <failure message="...">...</failure> @@ -3624,12 +3719,11 @@ static bool PortableLocaltime(time_t seconds, struct tm* out) { // MINGW <time.h> provides neither localtime_r nor localtime_s, but uses // Windows' localtime(), which has a thread-local tm buffer. struct tm* tm_ptr = localtime(&seconds); // NOLINT - if (tm_ptr == NULL) - return false; + if (tm_ptr == nullptr) return false; *out = *tm_ptr; return true; #else - return localtime_r(&seconds, out) != NULL; + return localtime_r(&seconds, out) != nullptr; #endif } @@ -3655,7 +3749,7 @@ void XmlUnitTestResultPrinter::OutputXmlCDataSection(::std::ostream* stream, *stream << "<![CDATA["; for (;;) { const char* const next_segment = strstr(segment, "]]>"); - if (next_segment != NULL) { + if (next_segment != nullptr) { stream->write( segment, static_cast<std::streamsize>(next_segment - segment)); *stream << "]]>]]><![CDATA["; @@ -3674,7 +3768,7 @@ void XmlUnitTestResultPrinter::OutputXmlAttribute( const std::string& name, const std::string& value) { const std::vector<std::string>& allowed_names = - GetReservedAttributesForElement(element_name); + GetReservedOutputAttributesForElement(element_name); GTEST_CHECK_(std::find(allowed_names.begin(), allowed_names.end(), name) != allowed_names.end()) @@ -3685,40 +3779,47 @@ void XmlUnitTestResultPrinter::OutputXmlAttribute( } // Prints an XML representation of a TestInfo object. -// FIXME: There is also value in printing properties with the plain printer. void XmlUnitTestResultPrinter::OutputXmlTestInfo(::std::ostream* stream, - const char* test_case_name, + const char* test_suite_name, const TestInfo& test_info) { const TestResult& result = *test_info.result(); - const std::string kTestcase = "testcase"; + const std::string kTestsuite = "testcase"; if (test_info.is_in_another_shard()) { return; } *stream << " <testcase"; - OutputXmlAttribute(stream, kTestcase, "name", test_info.name()); + OutputXmlAttribute(stream, kTestsuite, "name", test_info.name()); - if (test_info.value_param() != NULL) { - OutputXmlAttribute(stream, kTestcase, "value_param", + if (test_info.value_param() != nullptr) { + OutputXmlAttribute(stream, kTestsuite, "value_param", test_info.value_param()); } - if (test_info.type_param() != NULL) { - OutputXmlAttribute(stream, kTestcase, "type_param", test_info.type_param()); + if (test_info.type_param() != nullptr) { + OutputXmlAttribute(stream, kTestsuite, "type_param", + test_info.type_param()); } if (GTEST_FLAG(list_tests)) { - OutputXmlAttribute(stream, kTestcase, "file", test_info.file()); - OutputXmlAttribute(stream, kTestcase, "line", + OutputXmlAttribute(stream, kTestsuite, "file", test_info.file()); + OutputXmlAttribute(stream, kTestsuite, "line", StreamableToString(test_info.line())); *stream << " />\n"; return; } - OutputXmlAttribute(stream, kTestcase, "status", + OutputXmlAttribute(stream, kTestsuite, "status", test_info.should_run() ? "run" : "notrun"); - OutputXmlAttribute(stream, kTestcase, "time", + OutputXmlAttribute(stream, kTestsuite, "result", + test_info.should_run() + ? (result.Skipped() ? "skipped" : "completed") + : "suppressed"); + OutputXmlAttribute(stream, kTestsuite, "time", FormatTimeInMillisAsSeconds(result.elapsed_time())); - OutputXmlAttribute(stream, kTestcase, "classname", test_case_name); + OutputXmlAttribute( + stream, kTestsuite, "timestamp", + FormatEpochTimeInMillisAsIso8601(result.start_timestamp())); + OutputXmlAttribute(stream, kTestsuite, "classname", test_suite_name); int failures = 0; for (int i = 0; i < result.total_part_count(); ++i) { @@ -3751,29 +3852,32 @@ void XmlUnitTestResultPrinter::OutputXmlTestInfo(::std::ostream* stream, } } -// Prints an XML representation of a TestCase object -void XmlUnitTestResultPrinter::PrintXmlTestCase(std::ostream* stream, - const TestCase& test_case) { +// Prints an XML representation of a TestSuite object +void XmlUnitTestResultPrinter::PrintXmlTestSuite(std::ostream* stream, + const TestSuite& test_suite) { const std::string kTestsuite = "testsuite"; *stream << " <" << kTestsuite; - OutputXmlAttribute(stream, kTestsuite, "name", test_case.name()); + OutputXmlAttribute(stream, kTestsuite, "name", test_suite.name()); OutputXmlAttribute(stream, kTestsuite, "tests", - StreamableToString(test_case.reportable_test_count())); + StreamableToString(test_suite.reportable_test_count())); if (!GTEST_FLAG(list_tests)) { OutputXmlAttribute(stream, kTestsuite, "failures", - StreamableToString(test_case.failed_test_count())); + StreamableToString(test_suite.failed_test_count())); OutputXmlAttribute( stream, kTestsuite, "disabled", - StreamableToString(test_case.reportable_disabled_test_count())); + StreamableToString(test_suite.reportable_disabled_test_count())); OutputXmlAttribute(stream, kTestsuite, "errors", "0"); OutputXmlAttribute(stream, kTestsuite, "time", - FormatTimeInMillisAsSeconds(test_case.elapsed_time())); - *stream << TestPropertiesAsXmlAttributes(test_case.ad_hoc_test_result()); + FormatTimeInMillisAsSeconds(test_suite.elapsed_time())); + OutputXmlAttribute( + stream, kTestsuite, "timestamp", + FormatEpochTimeInMillisAsIso8601(test_suite.start_timestamp())); + *stream << TestPropertiesAsXmlAttributes(test_suite.ad_hoc_test_result()); } *stream << ">\n"; - for (int i = 0; i < test_case.total_test_count(); ++i) { - if (test_case.GetTestInfo(i)->is_reportable()) - OutputXmlTestInfo(stream, test_case.name(), *test_case.GetTestInfo(i)); + for (int i = 0; i < test_suite.total_test_count(); ++i) { + if (test_suite.GetTestInfo(i)->is_reportable()) + OutputXmlTestInfo(stream, test_suite.name(), *test_suite.GetTestInfo(i)); } *stream << " </" << kTestsuite << ">\n"; } @@ -3794,11 +3898,11 @@ void XmlUnitTestResultPrinter::PrintXmlUnitTest(std::ostream* stream, stream, kTestsuites, "disabled", StreamableToString(unit_test.reportable_disabled_test_count())); OutputXmlAttribute(stream, kTestsuites, "errors", "0"); + OutputXmlAttribute(stream, kTestsuites, "time", + FormatTimeInMillisAsSeconds(unit_test.elapsed_time())); OutputXmlAttribute( stream, kTestsuites, "timestamp", FormatEpochTimeInMillisAsIso8601(unit_test.start_timestamp())); - OutputXmlAttribute(stream, kTestsuites, "time", - FormatTimeInMillisAsSeconds(unit_test.elapsed_time())); if (GTEST_FLAG(shuffle)) { OutputXmlAttribute(stream, kTestsuites, "random_seed", @@ -3809,31 +3913,31 @@ void XmlUnitTestResultPrinter::PrintXmlUnitTest(std::ostream* stream, OutputXmlAttribute(stream, kTestsuites, "name", "AllTests"); *stream << ">\n"; - for (int i = 0; i < unit_test.total_test_case_count(); ++i) { - if (unit_test.GetTestCase(i)->reportable_test_count() > 0) - PrintXmlTestCase(stream, *unit_test.GetTestCase(i)); + for (int i = 0; i < unit_test.total_test_suite_count(); ++i) { + if (unit_test.GetTestSuite(i)->reportable_test_count() > 0) + PrintXmlTestSuite(stream, *unit_test.GetTestSuite(i)); } *stream << "</" << kTestsuites << ">\n"; } void XmlUnitTestResultPrinter::PrintXmlTestsList( - std::ostream* stream, const std::vector<TestCase*>& test_cases) { + std::ostream* stream, const std::vector<TestSuite*>& test_suites) { const std::string kTestsuites = "testsuites"; *stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"; *stream << "<" << kTestsuites; int total_tests = 0; - for (size_t i = 0; i < test_cases.size(); ++i) { - total_tests += test_cases[i]->total_test_count(); + for (auto test_suite : test_suites) { + total_tests += test_suite->total_test_count(); } OutputXmlAttribute(stream, kTestsuites, "tests", StreamableToString(total_tests)); OutputXmlAttribute(stream, kTestsuites, "name", "AllTests"); *stream << ">\n"; - for (size_t i = 0; i < test_cases.size(); ++i) { - PrintXmlTestCase(stream, *test_cases[i]); + for (auto test_suite : test_suites) { + PrintXmlTestSuite(stream, *test_suite); } *stream << "</" << kTestsuites << ">\n"; } @@ -3878,11 +3982,11 @@ class JsonUnitTestResultPrinter : public EmptyTestEventListener { public: explicit JsonUnitTestResultPrinter(const char* output_file); - virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); + void OnTestIterationEnd(const UnitTest& unit_test, int iteration) override; // Prints an JSON summary of all unit tests. static void PrintJsonTestList(::std::ostream* stream, - const std::vector<TestCase*>& test_cases); + const std::vector<TestSuite*>& test_suites); private: // Returns an JSON-escaped copy of the input string str. @@ -3905,12 +4009,12 @@ class JsonUnitTestResultPrinter : public EmptyTestEventListener { // Streams a JSON representation of a TestInfo object. static void OutputJsonTestInfo(::std::ostream* stream, - const char* test_case_name, + const char* test_suite_name, const TestInfo& test_info); - // Prints a JSON representation of a TestCase object - static void PrintJsonTestCase(::std::ostream* stream, - const TestCase& test_case); + // Prints a JSON representation of a TestSuite object + static void PrintJsonTestSuite(::std::ostream* stream, + const TestSuite& test_suite); // Prints a JSON summary of unit_test to output stream out. static void PrintJsonUnitTest(::std::ostream* stream, @@ -4009,7 +4113,7 @@ static std::string FormatEpochTimeInMillisAsRFC3339(TimeInMillis ms) { String::FormatIntWidth2(time_struct.tm_sec) + "Z"; } -static inline std::string Indent(int width) { +static inline std::string Indent(size_t width) { return std::string(width, ' '); } @@ -4021,7 +4125,7 @@ void JsonUnitTestResultPrinter::OutputJsonKey( const std::string& indent, bool comma) { const std::vector<std::string>& allowed_names = - GetReservedAttributesForElement(element_name); + GetReservedOutputAttributesForElement(element_name); GTEST_CHECK_(std::find(allowed_names.begin(), allowed_names.end(), name) != allowed_names.end()) @@ -4041,7 +4145,7 @@ void JsonUnitTestResultPrinter::OutputJsonKey( const std::string& indent, bool comma) { const std::vector<std::string>& allowed_names = - GetReservedAttributesForElement(element_name); + GetReservedOutputAttributesForElement(element_name); GTEST_CHECK_(std::find(allowed_names.begin(), allowed_names.end(), name) != allowed_names.end()) @@ -4055,35 +4159,44 @@ void JsonUnitTestResultPrinter::OutputJsonKey( // Prints a JSON representation of a TestInfo object. void JsonUnitTestResultPrinter::OutputJsonTestInfo(::std::ostream* stream, - const char* test_case_name, + const char* test_suite_name, const TestInfo& test_info) { const TestResult& result = *test_info.result(); - const std::string kTestcase = "testcase"; + const std::string kTestsuite = "testcase"; const std::string kIndent = Indent(10); *stream << Indent(8) << "{\n"; - OutputJsonKey(stream, kTestcase, "name", test_info.name(), kIndent); + OutputJsonKey(stream, kTestsuite, "name", test_info.name(), kIndent); - if (test_info.value_param() != NULL) { - OutputJsonKey(stream, kTestcase, "value_param", - test_info.value_param(), kIndent); + if (test_info.value_param() != nullptr) { + OutputJsonKey(stream, kTestsuite, "value_param", test_info.value_param(), + kIndent); } - if (test_info.type_param() != NULL) { - OutputJsonKey(stream, kTestcase, "type_param", test_info.type_param(), + if (test_info.type_param() != nullptr) { + OutputJsonKey(stream, kTestsuite, "type_param", test_info.type_param(), kIndent); } if (GTEST_FLAG(list_tests)) { - OutputJsonKey(stream, kTestcase, "file", test_info.file(), kIndent); - OutputJsonKey(stream, kTestcase, "line", test_info.line(), kIndent, false); + OutputJsonKey(stream, kTestsuite, "file", test_info.file(), kIndent); + OutputJsonKey(stream, kTestsuite, "line", test_info.line(), kIndent, false); *stream << "\n" << Indent(8) << "}"; return; } - OutputJsonKey(stream, kTestcase, "status", + OutputJsonKey(stream, kTestsuite, "status", test_info.should_run() ? "RUN" : "NOTRUN", kIndent); - OutputJsonKey(stream, kTestcase, "time", + OutputJsonKey(stream, kTestsuite, "result", + test_info.should_run() + ? (result.Skipped() ? "SKIPPED" : "COMPLETED") + : "SUPPRESSED", + kIndent); + OutputJsonKey(stream, kTestsuite, "timestamp", + FormatEpochTimeInMillisAsRFC3339(result.start_timestamp()), + kIndent); + OutputJsonKey(stream, kTestsuite, "time", FormatTimeInMillisAsDuration(result.elapsed_time()), kIndent); - OutputJsonKey(stream, kTestcase, "classname", test_case_name, kIndent, false); + OutputJsonKey(stream, kTestsuite, "classname", test_suite_name, kIndent, + false); *stream << TestPropertiesAsJson(result, kIndent); int failures = 0; @@ -4110,40 +4223,44 @@ void JsonUnitTestResultPrinter::OutputJsonTestInfo(::std::ostream* stream, *stream << "\n" << Indent(8) << "}"; } -// Prints an JSON representation of a TestCase object -void JsonUnitTestResultPrinter::PrintJsonTestCase(std::ostream* stream, - const TestCase& test_case) { +// Prints an JSON representation of a TestSuite object +void JsonUnitTestResultPrinter::PrintJsonTestSuite( + std::ostream* stream, const TestSuite& test_suite) { const std::string kTestsuite = "testsuite"; const std::string kIndent = Indent(6); *stream << Indent(4) << "{\n"; - OutputJsonKey(stream, kTestsuite, "name", test_case.name(), kIndent); - OutputJsonKey(stream, kTestsuite, "tests", test_case.reportable_test_count(), + OutputJsonKey(stream, kTestsuite, "name", test_suite.name(), kIndent); + OutputJsonKey(stream, kTestsuite, "tests", test_suite.reportable_test_count(), kIndent); if (!GTEST_FLAG(list_tests)) { - OutputJsonKey(stream, kTestsuite, "failures", test_case.failed_test_count(), - kIndent); + OutputJsonKey(stream, kTestsuite, "failures", + test_suite.failed_test_count(), kIndent); OutputJsonKey(stream, kTestsuite, "disabled", - test_case.reportable_disabled_test_count(), kIndent); + test_suite.reportable_disabled_test_count(), kIndent); OutputJsonKey(stream, kTestsuite, "errors", 0, kIndent); + OutputJsonKey( + stream, kTestsuite, "timestamp", + FormatEpochTimeInMillisAsRFC3339(test_suite.start_timestamp()), + kIndent); OutputJsonKey(stream, kTestsuite, "time", - FormatTimeInMillisAsDuration(test_case.elapsed_time()), + FormatTimeInMillisAsDuration(test_suite.elapsed_time()), kIndent, false); - *stream << TestPropertiesAsJson(test_case.ad_hoc_test_result(), kIndent) + *stream << TestPropertiesAsJson(test_suite.ad_hoc_test_result(), kIndent) << ",\n"; } *stream << kIndent << "\"" << kTestsuite << "\": [\n"; bool comma = false; - for (int i = 0; i < test_case.total_test_count(); ++i) { - if (test_case.GetTestInfo(i)->is_reportable()) { + for (int i = 0; i < test_suite.total_test_count(); ++i) { + if (test_suite.GetTestInfo(i)->is_reportable()) { if (comma) { *stream << ",\n"; } else { comma = true; } - OutputJsonTestInfo(stream, test_case.name(), *test_case.GetTestInfo(i)); + OutputJsonTestInfo(stream, test_suite.name(), *test_suite.GetTestInfo(i)); } } *stream << "\n" << kIndent << "]\n" << Indent(4) << "}"; @@ -4181,14 +4298,14 @@ void JsonUnitTestResultPrinter::PrintJsonUnitTest(std::ostream* stream, *stream << kIndent << "\"" << kTestsuites << "\": [\n"; bool comma = false; - for (int i = 0; i < unit_test.total_test_case_count(); ++i) { - if (unit_test.GetTestCase(i)->reportable_test_count() > 0) { + for (int i = 0; i < unit_test.total_test_suite_count(); ++i) { + if (unit_test.GetTestSuite(i)->reportable_test_count() > 0) { if (comma) { *stream << ",\n"; } else { comma = true; } - PrintJsonTestCase(stream, *unit_test.GetTestCase(i)); + PrintJsonTestSuite(stream, *unit_test.GetTestSuite(i)); } } @@ -4196,24 +4313,24 @@ void JsonUnitTestResultPrinter::PrintJsonUnitTest(std::ostream* stream, } void JsonUnitTestResultPrinter::PrintJsonTestList( - std::ostream* stream, const std::vector<TestCase*>& test_cases) { + std::ostream* stream, const std::vector<TestSuite*>& test_suites) { const std::string kTestsuites = "testsuites"; const std::string kIndent = Indent(2); *stream << "{\n"; int total_tests = 0; - for (size_t i = 0; i < test_cases.size(); ++i) { - total_tests += test_cases[i]->total_test_count(); + for (auto test_suite : test_suites) { + total_tests += test_suite->total_test_count(); } OutputJsonKey(stream, kTestsuites, "tests", total_tests, kIndent); OutputJsonKey(stream, kTestsuites, "name", "AllTests", kIndent); *stream << kIndent << "\"" << kTestsuites << "\": [\n"; - for (size_t i = 0; i < test_cases.size(); ++i) { + for (size_t i = 0; i < test_suites.size(); ++i) { if (i != 0) { *stream << ",\n"; } - PrintJsonTestCase(stream, *test_cases[i]); + PrintJsonTestSuite(stream, *test_suites[i]); } *stream << "\n" @@ -4269,7 +4386,7 @@ void StreamingListener::SocketWriter::MakeConnection() { memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; // To allow both IPv4 and IPv6 addresses. hints.ai_socktype = SOCK_STREAM; - addrinfo* servinfo = NULL; + addrinfo* servinfo = nullptr; // Use the getaddrinfo() to get a linked list of IP addresses for // the given host name. @@ -4281,7 +4398,7 @@ void StreamingListener::SocketWriter::MakeConnection() { } // Loop through all the results and connect to the first we can. - for (addrinfo* cur_addr = servinfo; sockfd_ == -1 && cur_addr != NULL; + for (addrinfo* cur_addr = servinfo; sockfd_ == -1 && cur_addr != nullptr; cur_addr = cur_addr->ai_next) { sockfd_ = socket( cur_addr->ai_family, cur_addr->ai_socktype, cur_addr->ai_protocol); @@ -4413,9 +4530,8 @@ class ScopedPrematureExitFile { TestEventListeners::TestEventListeners() : repeater_(new internal::TestEventRepeater()), - default_result_printer_(NULL), - default_xml_generator_(NULL) { -} + default_result_printer_(nullptr), + default_xml_generator_(nullptr) {} TestEventListeners::~TestEventListeners() { delete repeater_; } @@ -4432,9 +4548,9 @@ void TestEventListeners::Append(TestEventListener* listener) { // NULL if the listener is not found in the list. TestEventListener* TestEventListeners::Release(TestEventListener* listener) { if (listener == default_result_printer_) - default_result_printer_ = NULL; + default_result_printer_ = nullptr; else if (listener == default_xml_generator_) - default_xml_generator_ = NULL; + default_xml_generator_ = nullptr; return repeater_->Release(listener); } @@ -4453,8 +4569,7 @@ void TestEventListeners::SetDefaultResultPrinter(TestEventListener* listener) { // list. delete Release(default_result_printer_); default_result_printer_ = listener; - if (listener != NULL) - Append(listener); + if (listener != nullptr) Append(listener); } } @@ -4469,8 +4584,7 @@ void TestEventListeners::SetDefaultXmlGenerator(TestEventListener* listener) { // list. delete Release(default_xml_generator_); default_xml_generator_ = listener; - if (listener != NULL) - Append(listener); + if (listener != nullptr) Append(listener); } } @@ -4494,52 +4608,66 @@ void TestEventListeners::SuppressEventForwarding() { // call this before main() starts, from which point on the return // value will never change. UnitTest* UnitTest::GetInstance() { - // When compiled with MSVC 7.1 in optimized mode, destroying the - // UnitTest object upon exiting the program messes up the exit code, - // causing successful tests to appear failed. We have to use a - // different implementation in this case to bypass the compiler bug. - // This implementation makes the compiler happy, at the cost of - // leaking the UnitTest object. - // CodeGear C++Builder insists on a public destructor for the // default implementation. Use this implementation to keep good OO // design with private destructor. -#if (_MSC_VER == 1310 && !defined(_DEBUG)) || defined(__BORLANDC__) +#if defined(__BORLANDC__) static UnitTest* const instance = new UnitTest; return instance; #else static UnitTest instance; return &instance; -#endif // (_MSC_VER == 1310 && !defined(_DEBUG)) || defined(__BORLANDC__) +#endif // defined(__BORLANDC__) } -// Gets the number of successful test cases. -int UnitTest::successful_test_case_count() const { - return impl()->successful_test_case_count(); +// Gets the number of successful test suites. +int UnitTest::successful_test_suite_count() const { + return impl()->successful_test_suite_count(); } -// Gets the number of failed test cases. -int UnitTest::failed_test_case_count() const { - return impl()->failed_test_case_count(); +// Gets the number of failed test suites. +int UnitTest::failed_test_suite_count() const { + return impl()->failed_test_suite_count(); } -// Gets the number of all test cases. -int UnitTest::total_test_case_count() const { - return impl()->total_test_case_count(); +// Gets the number of all test suites. +int UnitTest::total_test_suite_count() const { + return impl()->total_test_suite_count(); } -// Gets the number of all test cases that contain at least one test +// Gets the number of all test suites that contain at least one test // that should run. +int UnitTest::test_suite_to_run_count() const { + return impl()->test_suite_to_run_count(); +} + +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +int UnitTest::successful_test_case_count() const { + return impl()->successful_test_suite_count(); +} +int UnitTest::failed_test_case_count() const { + return impl()->failed_test_suite_count(); +} +int UnitTest::total_test_case_count() const { + return impl()->total_test_suite_count(); +} int UnitTest::test_case_to_run_count() const { - return impl()->test_case_to_run_count(); + return impl()->test_suite_to_run_count(); } +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ // Gets the number of successful tests. int UnitTest::successful_test_count() const { return impl()->successful_test_count(); } +// Gets the number of skipped tests. +int UnitTest::skipped_test_count() const { + return impl()->skipped_test_count(); +} + // Gets the number of failed tests. int UnitTest::failed_test_count() const { return impl()->failed_test_count(); } @@ -4575,29 +4703,37 @@ internal::TimeInMillis UnitTest::elapsed_time() const { return impl()->elapsed_time(); } -// Returns true iff the unit test passed (i.e. all test cases passed). +// Returns true if and only if the unit test passed (i.e. all test suites +// passed). bool UnitTest::Passed() const { return impl()->Passed(); } -// Returns true iff the unit test failed (i.e. some test case failed -// or something outside of all tests failed). +// Returns true if and only if the unit test failed (i.e. some test suite +// failed or something outside of all tests failed). bool UnitTest::Failed() const { return impl()->Failed(); } -// Gets the i-th test case among all the test cases. i can range from 0 to -// total_test_case_count() - 1. If i is not in that range, returns NULL. +// Gets the i-th test suite among all the test suites. i can range from 0 to +// total_test_suite_count() - 1. If i is not in that range, returns NULL. +const TestSuite* UnitTest::GetTestSuite(int i) const { + return impl()->GetTestSuite(i); +} + +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ const TestCase* UnitTest::GetTestCase(int i) const { return impl()->GetTestCase(i); } +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ // Returns the TestResult containing information on test failures and -// properties logged outside of individual test cases. +// properties logged outside of individual test suites. const TestResult& UnitTest::ad_hoc_test_result() const { return *impl()->ad_hoc_test_result(); } -// Gets the i-th test case among all the test cases. i can range from 0 to -// total_test_case_count() - 1. If i is not in that range, returns NULL. -TestCase* UnitTest::GetMutableTestCase(int i) { - return impl()->GetMutableTestCase(i); +// Gets the i-th test suite among all the test suites. i can range from 0 to +// total_test_suite_count() - 1. If i is not in that range, returns NULL. +TestSuite* UnitTest::GetMutableTestSuite(int i) { + return impl()->GetMutableSuiteCase(i); } // Returns the list of event listeners that can be used to track events @@ -4617,8 +4753,8 @@ TestEventListeners& UnitTest::listeners() { // We don't protect this under mutex_, as we only support calling it // from the main thread. Environment* UnitTest::AddEnvironment(Environment* env) { - if (env == NULL) { - return NULL; + if (env == nullptr) { + return nullptr; } impl_->environments().push_back(env); @@ -4642,25 +4778,24 @@ void UnitTest::AddTestPartResult( if (impl_->gtest_trace_stack().size() > 0) { msg << "\n" << GTEST_NAME_ << " trace:"; - for (int i = static_cast<int>(impl_->gtest_trace_stack().size()); - i > 0; --i) { + for (size_t i = impl_->gtest_trace_stack().size(); i > 0; --i) { const internal::TraceInfo& trace = impl_->gtest_trace_stack()[i - 1]; msg << "\n" << internal::FormatFileLocation(trace.file, trace.line) << " " << trace.message; } } - if (os_stack_trace.c_str() != NULL && !os_stack_trace.empty()) { + if (os_stack_trace.c_str() != nullptr && !os_stack_trace.empty()) { msg << internal::kStackTraceMarker << os_stack_trace; } - const TestPartResult result = - TestPartResult(result_type, file_name, line_number, - msg.GetString().c_str()); + const TestPartResult result = TestPartResult( + result_type, file_name, line_number, msg.GetString().c_str()); impl_->GetTestPartResultReporterForCurrentThread()-> ReportTestPartResult(result); - if (result_type != TestPartResult::kSuccess) { + if (result_type != TestPartResult::kSuccess && + result_type != TestPartResult::kSkip) { // gtest_break_on_failure takes precedence over // gtest_throw_on_failure. This allows a user to set the latter // in the code (perhaps in order to use Google Test assertions @@ -4678,11 +4813,10 @@ void UnitTest::AddTestPartResult( // with clang/gcc we can achieve the same effect on x86 by invoking int3 asm("int3"); #else - // Dereference NULL through a volatile pointer to prevent the compiler + // Dereference nullptr through a volatile pointer to prevent the compiler // from removing. We use this rather than abort() or __builtin_trap() for - // portability: Symbian doesn't implement abort() well, and some debuggers - // don't correctly trap abort(). - *static_cast<volatile int*>(NULL) = 1; + // portability: some debuggers don't correctly trap abort(). + *static_cast<volatile int*>(nullptr) = 1; #endif // GTEST_OS_WINDOWS } else if (GTEST_FLAG(throw_on_failure)) { #if GTEST_HAS_EXCEPTIONS @@ -4697,8 +4831,8 @@ void UnitTest::AddTestPartResult( } // Adds a TestProperty to the current TestResult object when invoked from -// inside a test, to current TestCase's ad_hoc_test_result_ when invoked -// from SetUpTestCase or TearDownTestCase, or to the global property set +// inside a test, to current TestSuite's ad_hoc_test_result_ when invoked +// from SetUpTestSuite or TearDownTestSuite, or to the global property set // when invoked elsewhere. If the result already contains a property with // the same key, the value will be updated. void UnitTest::RecordProperty(const std::string& key, @@ -4737,8 +4871,9 @@ int UnitTest::Run() { // that understands the premature-exit-file protocol to report the // test as having failed. const internal::ScopedPrematureExitFile premature_exit_file( - in_death_test_child_process ? - NULL : internal::posix::GetEnv("TEST_PREMATURE_EXIT_FILE")); + in_death_test_child_process + ? nullptr + : internal::posix::GetEnv("TEST_PREMATURE_EXIT_FILE")); // Captures the value of GTEST_FLAG(catch_exceptions). This value will be // used for the duration of the program. @@ -4763,23 +4898,27 @@ int UnitTest::Run() { _set_error_mode(_OUT_TO_STDERR); # endif -# if _MSC_VER >= 1400 && !GTEST_OS_WINDOWS_MOBILE +# if defined(_MSC_VER) && !GTEST_OS_WINDOWS_MOBILE // In the debug version, Visual Studio pops up a separate dialog // offering a choice to debug the aborted program. We need to suppress // this dialog or it will pop up for every EXPECT/ASSERT_DEATH statement // executed. Google Test will notify the user of any unexpected // failure via stderr. - // - // VC++ doesn't define _set_abort_behavior() prior to the version 8.0. - // Users of prior VC versions shall suffer the agony and pain of - // clicking through the countless debug dialogs. - // FIXME: find a way to suppress the abort dialog() in the - // debug mode when compiled with VC 7.1 or lower. if (!GTEST_FLAG(break_on_failure)) _set_abort_behavior( 0x0, // Clear the following flags: _WRITE_ABORT_MSG | _CALL_REPORTFAULT); // pop-up window, core dump. # endif + + // In debug mode, the Windows CRT can crash with an assertion over invalid + // input (e.g. passing an invalid file descriptor). The default handling + // for these assertions is to pop up a dialog and wait for user input. + // Instead ask the CRT to dump such assertions to stderr non-interactively. + if (!IsDebuggerPresent()) { + (void)_CrtSetReportMode(_CRT_ASSERT, + _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG); + (void)_CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR); + } } #endif // GTEST_OS_WINDOWS @@ -4795,13 +4934,22 @@ const char* UnitTest::original_working_dir() const { return impl_->original_working_dir_.c_str(); } -// Returns the TestCase object for the test that's currently running, +// Returns the TestSuite object for the test that's currently running, // or NULL if no test is running. +const TestSuite* UnitTest::current_test_suite() const + GTEST_LOCK_EXCLUDED_(mutex_) { + internal::MutexLock lock(&mutex_); + return impl_->current_test_suite(); +} + +// Legacy API is still available but deprecated +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ const TestCase* UnitTest::current_test_case() const GTEST_LOCK_EXCLUDED_(mutex_) { internal::MutexLock lock(&mutex_); - return impl_->current_test_case(); + return impl_->current_test_suite(); } +#endif // Returns the TestInfo object for the test that's currently running, // or NULL if no test is running. @@ -4814,11 +4962,10 @@ const TestInfo* UnitTest::current_test_info() const // Returns the random seed used at the start of the current test run. int UnitTest::random_seed() const { return impl_->random_seed(); } -// Returns ParameterizedTestCaseRegistry object used to keep track of +// Returns ParameterizedTestSuiteRegistry object used to keep track of // value-parameterized tests and instantiate and register them. -internal::ParameterizedTestCaseRegistry& - UnitTest::parameterized_test_registry() - GTEST_LOCK_EXCLUDED_(mutex_) { +internal::ParameterizedTestSuiteRegistry& +UnitTest::parameterized_test_registry() GTEST_LOCK_EXCLUDED_(mutex_) { return impl_->parameterized_test_registry(); } @@ -4852,23 +4999,22 @@ namespace internal { UnitTestImpl::UnitTestImpl(UnitTest* parent) : parent_(parent), GTEST_DISABLE_MSC_WARNINGS_PUSH_(4355 /* using this in initializer */) - default_global_test_part_result_reporter_(this), + default_global_test_part_result_reporter_(this), default_per_thread_test_part_result_reporter_(this), - GTEST_DISABLE_MSC_WARNINGS_POP_() - global_test_part_result_repoter_( + GTEST_DISABLE_MSC_WARNINGS_POP_() global_test_part_result_repoter_( &default_global_test_part_result_reporter_), per_thread_test_part_result_reporter_( &default_per_thread_test_part_result_reporter_), parameterized_test_registry_(), parameterized_tests_registered_(false), - last_death_test_case_(-1), - current_test_case_(NULL), - current_test_info_(NULL), + last_death_test_suite_(-1), + current_test_suite_(nullptr), + current_test_info_(nullptr), ad_hoc_test_result_(), - os_stack_trace_getter_(NULL), + os_stack_trace_getter_(nullptr), post_flag_parse_init_performed_(false), random_seed_(0), // Will be overridden by the flag before first use. - random_(0), // Will be reseeded before first use. + random_(0), // Will be reseeded before first use. start_timestamp_(0), elapsed_time_(0), #if GTEST_HAS_DEATH_TEST @@ -4880,8 +5026,8 @@ UnitTestImpl::UnitTestImpl(UnitTest* parent) } UnitTestImpl::~UnitTestImpl() { - // Deletes every TestCase. - ForEach(test_cases_, internal::Delete<TestCase>); + // Deletes every TestSuite. + ForEach(test_suites_, internal::Delete<TestSuite>); // Deletes every Environment. ForEach(environments_, internal::Delete<Environment>); @@ -4890,20 +5036,20 @@ UnitTestImpl::~UnitTestImpl() { } // Adds a TestProperty to the current TestResult object when invoked in a -// context of a test, to current test case's ad_hoc_test_result when invoke -// from SetUpTestCase/TearDownTestCase, or to the global property set +// context of a test, to current test suite's ad_hoc_test_result when invoke +// from SetUpTestSuite/TearDownTestSuite, or to the global property set // otherwise. If the result already contains a property with the same key, // the value will be updated. void UnitTestImpl::RecordProperty(const TestProperty& test_property) { std::string xml_element; TestResult* test_result; // TestResult appropriate for property recording. - if (current_test_info_ != NULL) { + if (current_test_info_ != nullptr) { xml_element = "testcase"; test_result = &(current_test_info_->result_); - } else if (current_test_case_ != NULL) { + } else if (current_test_suite_ != nullptr) { xml_element = "testsuite"; - test_result = &(current_test_case_->ad_hoc_test_result_); + test_result = &(current_test_suite_->ad_hoc_test_result_); } else { xml_element = "testsuites"; test_result = &ad_hoc_test_result_; @@ -4915,7 +5061,7 @@ void UnitTestImpl::RecordProperty(const TestProperty& test_property) { // Disables event forwarding if the control is currently in a death test // subprocess. Must not be called before InitGoogleTest. void UnitTestImpl::SuppressTestEventsIfInSubprocess() { - if (internal_run_death_test_flag_.get() != NULL) + if (internal_run_death_test_flag_.get() != nullptr) listeners()->SuppressEventForwarding(); } #endif // GTEST_HAS_DEATH_TEST @@ -4997,74 +5143,73 @@ void UnitTestImpl::PostFlagParsingInit() { } } -// A predicate that checks the name of a TestCase against a known +// A predicate that checks the name of a TestSuite against a known // value. // // This is used for implementation of the UnitTest class only. We put // it in the anonymous namespace to prevent polluting the outer // namespace. // -// TestCaseNameIs is copyable. -class TestCaseNameIs { +// TestSuiteNameIs is copyable. +class TestSuiteNameIs { public: // Constructor. - explicit TestCaseNameIs(const std::string& name) - : name_(name) {} + explicit TestSuiteNameIs(const std::string& name) : name_(name) {} - // Returns true iff the name of test_case matches name_. - bool operator()(const TestCase* test_case) const { - return test_case != NULL && strcmp(test_case->name(), name_.c_str()) == 0; + // Returns true if and only if the name of test_suite matches name_. + bool operator()(const TestSuite* test_suite) const { + return test_suite != nullptr && + strcmp(test_suite->name(), name_.c_str()) == 0; } private: std::string name_; }; -// Finds and returns a TestCase with the given name. If one doesn't +// Finds and returns a TestSuite with the given name. If one doesn't // exist, creates one and returns it. It's the CALLER'S // RESPONSIBILITY to ensure that this function is only called WHEN THE // TESTS ARE NOT SHUFFLED. // // Arguments: // -// test_case_name: name of the test case -// type_param: the name of the test case's type parameter, or NULL if -// this is not a typed or a type-parameterized test case. -// set_up_tc: pointer to the function that sets up the test case -// tear_down_tc: pointer to the function that tears down the test case -TestCase* UnitTestImpl::GetTestCase(const char* test_case_name, - const char* type_param, - Test::SetUpTestCaseFunc set_up_tc, - Test::TearDownTestCaseFunc tear_down_tc) { - // Can we find a TestCase with the given name? - const std::vector<TestCase*>::const_reverse_iterator test_case = - std::find_if(test_cases_.rbegin(), test_cases_.rend(), - TestCaseNameIs(test_case_name)); - - if (test_case != test_cases_.rend()) - return *test_case; +// test_suite_name: name of the test suite +// type_param: the name of the test suite's type parameter, or NULL if +// this is not a typed or a type-parameterized test suite. +// set_up_tc: pointer to the function that sets up the test suite +// tear_down_tc: pointer to the function that tears down the test suite +TestSuite* UnitTestImpl::GetTestSuite( + const char* test_suite_name, const char* type_param, + internal::SetUpTestSuiteFunc set_up_tc, + internal::TearDownTestSuiteFunc tear_down_tc) { + // Can we find a TestSuite with the given name? + const auto test_suite = + std::find_if(test_suites_.rbegin(), test_suites_.rend(), + TestSuiteNameIs(test_suite_name)); + + if (test_suite != test_suites_.rend()) return *test_suite; // No. Let's create one. - TestCase* const new_test_case = - new TestCase(test_case_name, type_param, set_up_tc, tear_down_tc); - - // Is this a death test case? - if (internal::UnitTestOptions::MatchesFilter(test_case_name, - kDeathTestCaseFilter)) { - // Yes. Inserts the test case after the last death test case - // defined so far. This only works when the test cases haven't + auto* const new_test_suite = + new TestSuite(test_suite_name, type_param, set_up_tc, tear_down_tc); + + // Is this a death test suite? + if (internal::UnitTestOptions::MatchesFilter(test_suite_name, + kDeathTestSuiteFilter)) { + // Yes. Inserts the test suite after the last death test suite + // defined so far. This only works when the test suites haven't // been shuffled. Otherwise we may end up running a death test // after a non-death test. - ++last_death_test_case_; - test_cases_.insert(test_cases_.begin() + last_death_test_case_, - new_test_case); + ++last_death_test_suite_; + test_suites_.insert(test_suites_.begin() + last_death_test_suite_, + new_test_suite); } else { // No. Appends to the end of the list. - test_cases_.push_back(new_test_case); + test_suites_.push_back(new_test_suite); } - test_case_indices_.push_back(static_cast<int>(test_case_indices_.size())); - return new_test_case; + test_suite_indices_.push_back(static_cast<int>(test_suite_indices_.size())); + return new_test_suite; } // Helpers for setting up / tearing down the given environment. They @@ -5082,7 +5227,8 @@ static void TearDownEnvironment(Environment* env) { env->TearDown(); } // All other functions called from RunAllTests() may safely assume that // parameterized tests are ready to be counted and run. bool UnitTestImpl::RunAllTests() { - // True iff Google Test is initialized before RUN_ALL_TESTS() is called. + // True if and only if Google Test is initialized before RUN_ALL_TESTS() is + // called. const bool gtest_is_initialized_before_run_all_tests = GTestIsInitialized(); // Do not run any test if the --help flag was specified. @@ -5098,12 +5244,13 @@ bool UnitTestImpl::RunAllTests() { // protocol. internal::WriteToShardStatusFileIfNeeded(); - // True iff we are in a subprocess for running a thread-safe-style + // True if and only if we are in a subprocess for running a thread-safe-style // death test. bool in_subprocess_for_death_test = false; #if GTEST_HAS_DEATH_TEST - in_subprocess_for_death_test = (internal_run_death_test_flag_.get() != NULL); + in_subprocess_for_death_test = + (internal_run_death_test_flag_.get() != nullptr); # if defined(GTEST_EXTRA_DEATH_TEST_CHILD_SETUP_) if (in_subprocess_for_death_test) { GTEST_EXTRA_DEATH_TEST_CHILD_SETUP_(); @@ -5130,7 +5277,7 @@ bool UnitTestImpl::RunAllTests() { random_seed_ = GTEST_FLAG(shuffle) ? GetRandomSeedFromFlag(GTEST_FLAG(random_seed)) : 0; - // True iff at least one test has failed. + // True if and only if at least one test has failed. bool failed = false; TestEventListener* repeater = listeners()->repeater(); @@ -5142,17 +5289,17 @@ bool UnitTestImpl::RunAllTests() { // when we are inside the subprocess of a death test. const int repeat = in_subprocess_for_death_test ? 1 : GTEST_FLAG(repeat); // Repeats forever if the repeat count is negative. - const bool forever = repeat < 0; - for (int i = 0; forever || i != repeat; i++) { + const bool gtest_repeat_forever = repeat < 0; + for (int i = 0; gtest_repeat_forever || i != repeat; i++) { // We want to preserve failures generated by ad-hoc test // assertions executed before RUN_ALL_TESTS(). ClearNonAdHocTestResult(); const TimeInMillis start = GetTimeInMillis(); - // Shuffles test cases and tests if requested. + // Shuffles test suites and tests if requested. if (has_tests_to_run && GTEST_FLAG(shuffle)) { - random()->Reseed(random_seed_); + random()->Reseed(static_cast<UInt32>(random_seed_)); // This should be done before calling OnTestIterationStart(), // such that a test event listener can see the actual test order // in the event. @@ -5162,19 +5309,33 @@ bool UnitTestImpl::RunAllTests() { // Tells the unit test event listeners that the tests are about to start. repeater->OnTestIterationStart(*parent_, i); - // Runs each test case if there is at least one test to run. + // Runs each test suite if there is at least one test to run. if (has_tests_to_run) { // Sets up all environments beforehand. repeater->OnEnvironmentsSetUpStart(*parent_); ForEach(environments_, SetUpEnvironment); repeater->OnEnvironmentsSetUpEnd(*parent_); - // Runs the tests only if there was no fatal failure during global - // set-up. - if (!Test::HasFatalFailure()) { - for (int test_index = 0; test_index < total_test_case_count(); + // Runs the tests only if there was no fatal failure or skip triggered + // during global set-up. + if (Test::IsSkipped()) { + // Emit diagnostics when global set-up calls skip, as it will not be + // emitted by default. + TestResult& test_result = + *internal::GetUnitTestImpl()->current_test_result(); + for (int j = 0; j < test_result.total_part_count(); ++j) { + const TestPartResult& test_part_result = + test_result.GetTestPartResult(j); + if (test_part_result.type() == TestPartResult::kSkip) { + const std::string& result = test_part_result.message(); + printf("%s\n", result.c_str()); + } + } + fflush(stdout); + } else if (!Test::HasFatalFailure()) { + for (int test_index = 0; test_index < total_test_suite_count(); test_index++) { - GetMutableTestCase(test_index)->Run(); + GetMutableSuiteCase(test_index)->Run(); } } @@ -5234,9 +5395,9 @@ bool UnitTestImpl::RunAllTests() { // be created, prints an error and exits. void WriteToShardStatusFileIfNeeded() { const char* const test_shard_file = posix::GetEnv(kTestShardStatusFile); - if (test_shard_file != NULL) { + if (test_shard_file != nullptr) { FILE* const file = posix::FOpen(test_shard_file, "w"); - if (file == NULL) { + if (file == nullptr) { ColoredPrintf(COLOR_RED, "Could not write to the test shard status file \"%s\" " "specified by the %s environment variable.\n", @@ -5271,7 +5432,7 @@ bool ShouldShard(const char* total_shards_env, << "Invalid environment variables: you have " << kTestShardIndex << " = " << shard_index << ", but have left " << kTestTotalShards << " unset.\n"; - ColoredPrintf(COLOR_RED, msg.GetString().c_str()); + ColoredPrintf(COLOR_RED, "%s", msg.GetString().c_str()); fflush(stdout); exit(EXIT_FAILURE); } else if (total_shards != -1 && shard_index == -1) { @@ -5279,7 +5440,7 @@ bool ShouldShard(const char* total_shards_env, << "Invalid environment variables: you have " << kTestTotalShards << " = " << total_shards << ", but have left " << kTestShardIndex << " unset.\n"; - ColoredPrintf(COLOR_RED, msg.GetString().c_str()); + ColoredPrintf(COLOR_RED, "%s", msg.GetString().c_str()); fflush(stdout); exit(EXIT_FAILURE); } else if (shard_index < 0 || shard_index >= total_shards) { @@ -5288,7 +5449,7 @@ bool ShouldShard(const char* total_shards_env, << kTestShardIndex << " < " << kTestTotalShards << ", but you have " << kTestShardIndex << "=" << shard_index << ", " << kTestTotalShards << "=" << total_shards << ".\n"; - ColoredPrintf(COLOR_RED, msg.GetString().c_str()); + ColoredPrintf(COLOR_RED, "%s", msg.GetString().c_str()); fflush(stdout); exit(EXIT_FAILURE); } @@ -5301,7 +5462,7 @@ bool ShouldShard(const char* total_shards_env, // and aborts. Int32 Int32FromEnvOrDie(const char* var, Int32 default_val) { const char* str_val = posix::GetEnv(var); - if (str_val == NULL) { + if (str_val == nullptr) { return default_val; } @@ -5314,8 +5475,8 @@ Int32 Int32FromEnvOrDie(const char* var, Int32 default_val) { } // Given the total number of shards, the shard index, and the test id, -// returns true iff the test should be run on this shard. The test id is -// some arbitrary but unique non-negative integer assigned to each test +// returns true if and only if the test should be run on this shard. The test id +// is some arbitrary but unique non-negative integer assigned to each test // method. Assumes that 0 <= shard_index < total_shards. bool ShouldRunTestOnShard(int total_shards, int shard_index, int test_id) { return (test_id % total_shards) == shard_index; @@ -5323,7 +5484,7 @@ bool ShouldRunTestOnShard(int total_shards, int shard_index, int test_id) { // Compares the name of each test with the user-specified filter to // decide whether the test should be run, then records the result in -// each TestCase and TestInfo object. +// each TestSuite and TestInfo object. // If shard_tests == true, further filters tests based on sharding // variables in the environment - see // https://github.com/google/googletest/blob/master/googletest/docs/advanced.md @@ -5340,26 +5501,23 @@ int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) { // this shard. int num_runnable_tests = 0; int num_selected_tests = 0; - for (size_t i = 0; i < test_cases_.size(); i++) { - TestCase* const test_case = test_cases_[i]; - const std::string &test_case_name = test_case->name(); - test_case->set_should_run(false); + for (auto* test_suite : test_suites_) { + const std::string& test_suite_name = test_suite->name(); + test_suite->set_should_run(false); - for (size_t j = 0; j < test_case->test_info_list().size(); j++) { - TestInfo* const test_info = test_case->test_info_list()[j]; + for (size_t j = 0; j < test_suite->test_info_list().size(); j++) { + TestInfo* const test_info = test_suite->test_info_list()[j]; const std::string test_name(test_info->name()); - // A test is disabled if test case name or test name matches + // A test is disabled if test suite name or test name matches // kDisableTestFilter. - const bool is_disabled = - internal::UnitTestOptions::MatchesFilter(test_case_name, - kDisableTestFilter) || - internal::UnitTestOptions::MatchesFilter(test_name, - kDisableTestFilter); + const bool is_disabled = internal::UnitTestOptions::MatchesFilter( + test_suite_name, kDisableTestFilter) || + internal::UnitTestOptions::MatchesFilter( + test_name, kDisableTestFilter); test_info->is_disabled_ = is_disabled; - const bool matches_filter = - internal::UnitTestOptions::FilterMatchesTest(test_case_name, - test_name); + const bool matches_filter = internal::UnitTestOptions::FilterMatchesTest( + test_suite_name, test_name); test_info->matches_filter_ = matches_filter; const bool is_runnable = @@ -5376,7 +5534,7 @@ int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) { num_selected_tests += is_selected; test_info->should_run_ = is_selected; - test_case->set_should_run(test_case->should_run() || is_selected); + test_suite->set_should_run(test_suite->should_run() || is_selected); } } return num_selected_tests; @@ -5387,7 +5545,7 @@ int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) { // max_length characters, only prints the first max_length characters // and "...". static void PrintOnOneLine(const char* str, int max_length) { - if (str != NULL) { + if (str != nullptr) { for (int i = 0; *str != '\0'; ++str) { if (i >= max_length) { printf("..."); @@ -5409,27 +5567,25 @@ void UnitTestImpl::ListTestsMatchingFilter() { // Print at most this many characters for each type/value parameter. const int kMaxParamLength = 250; - for (size_t i = 0; i < test_cases_.size(); i++) { - const TestCase* const test_case = test_cases_[i]; - bool printed_test_case_name = false; + for (auto* test_suite : test_suites_) { + bool printed_test_suite_name = false; - for (size_t j = 0; j < test_case->test_info_list().size(); j++) { - const TestInfo* const test_info = - test_case->test_info_list()[j]; + for (size_t j = 0; j < test_suite->test_info_list().size(); j++) { + const TestInfo* const test_info = test_suite->test_info_list()[j]; if (test_info->matches_filter_) { - if (!printed_test_case_name) { - printed_test_case_name = true; - printf("%s.", test_case->name()); - if (test_case->type_param() != NULL) { + if (!printed_test_suite_name) { + printed_test_suite_name = true; + printf("%s.", test_suite->name()); + if (test_suite->type_param() != nullptr) { printf(" # %s = ", kTypeParamLabel); // We print the type parameter on a single line to make // the output easy to parse by a program. - PrintOnOneLine(test_case->type_param(), kMaxParamLength); + PrintOnOneLine(test_suite->type_param(), kMaxParamLength); } printf("\n"); } printf(" %s", test_info->name()); - if (test_info->value_param() != NULL) { + if (test_info->value_param() != nullptr) { printf(" # %s = ", kValueParamLabel); // We print the value parameter on a single line to make the // output easy to parse by a program. @@ -5448,11 +5604,11 @@ void UnitTestImpl::ListTestsMatchingFilter() { if (output_format == "xml") { XmlUnitTestResultPrinter( UnitTestOptions::GetAbsolutePathToOutputFile().c_str()) - .PrintXmlTestsList(&stream, test_cases_); + .PrintXmlTestsList(&stream, test_suites_); } else if (output_format == "json") { JsonUnitTestResultPrinter( UnitTestOptions::GetAbsolutePathToOutputFile().c_str()) - .PrintJsonTestList(&stream, test_cases_); + .PrintJsonTestList(&stream, test_suites_); } fprintf(fileout, "%s", StringStreamToString(&stream).c_str()); fclose(fileout); @@ -5476,7 +5632,7 @@ void UnitTestImpl::set_os_stack_trace_getter( // otherwise, creates an OsStackTraceGetter, makes it the current // getter, and returns it. OsStackTraceGetterInterface* UnitTestImpl::os_stack_trace_getter() { - if (os_stack_trace_getter_ == NULL) { + if (os_stack_trace_getter_ == nullptr) { #ifdef GTEST_OS_STACK_TRACE_GETTER_ os_stack_trace_getter_ = new GTEST_OS_STACK_TRACE_GETTER_; #else @@ -5489,38 +5645,38 @@ OsStackTraceGetterInterface* UnitTestImpl::os_stack_trace_getter() { // Returns the most specific TestResult currently running. TestResult* UnitTestImpl::current_test_result() { - if (current_test_info_ != NULL) { + if (current_test_info_ != nullptr) { return ¤t_test_info_->result_; } - if (current_test_case_ != NULL) { - return ¤t_test_case_->ad_hoc_test_result_; + if (current_test_suite_ != nullptr) { + return ¤t_test_suite_->ad_hoc_test_result_; } return &ad_hoc_test_result_; } -// Shuffles all test cases, and the tests within each test case, +// Shuffles all test suites, and the tests within each test suite, // making sure that death tests are still run first. void UnitTestImpl::ShuffleTests() { - // Shuffles the death test cases. - ShuffleRange(random(), 0, last_death_test_case_ + 1, &test_case_indices_); + // Shuffles the death test suites. + ShuffleRange(random(), 0, last_death_test_suite_ + 1, &test_suite_indices_); - // Shuffles the non-death test cases. - ShuffleRange(random(), last_death_test_case_ + 1, - static_cast<int>(test_cases_.size()), &test_case_indices_); + // Shuffles the non-death test suites. + ShuffleRange(random(), last_death_test_suite_ + 1, + static_cast<int>(test_suites_.size()), &test_suite_indices_); - // Shuffles the tests inside each test case. - for (size_t i = 0; i < test_cases_.size(); i++) { - test_cases_[i]->ShuffleTests(random()); + // Shuffles the tests inside each test suite. + for (auto& test_suite : test_suites_) { + test_suite->ShuffleTests(random()); } } -// Restores the test cases and tests to their order before the first shuffle. +// Restores the test suites and tests to their order before the first shuffle. void UnitTestImpl::UnshuffleTests() { - for (size_t i = 0; i < test_cases_.size(); i++) { - // Unshuffles the tests in each test case. - test_cases_[i]->UnshuffleTests(); - // Resets the index of each test case. - test_case_indices_[i] = static_cast<int>(i); + for (size_t i = 0; i < test_suites_.size(); i++) { + // Unshuffles the tests in each test suite. + test_suites_[i]->UnshuffleTests(); + // Resets the index of each test suite. + test_suite_indices_[i] = static_cast<int>(i); } } @@ -5579,12 +5735,12 @@ bool SkipPrefix(const char* prefix, const char** pstr) { static const char* ParseFlagValue(const char* str, const char* flag, bool def_optional) { // str and flag must not be NULL. - if (str == NULL || flag == NULL) return NULL; + if (str == nullptr || flag == nullptr) return nullptr; // The flag must start with "--" followed by GTEST_FLAG_PREFIX_. const std::string flag_str = std::string("--") + GTEST_FLAG_PREFIX_ + flag; const size_t flag_len = flag_str.length(); - if (strncmp(str, flag_str.c_str(), flag_len) != 0) return NULL; + if (strncmp(str, flag_str.c_str(), flag_len) != 0) return nullptr; // Skips the flag name. const char* flag_end = str + flag_len; @@ -5597,7 +5753,7 @@ static const char* ParseFlagValue(const char* str, const char* flag, // If def_optional is true and there are more characters after the // flag name, or if def_optional is false, there must be a '=' after // the flag name. - if (flag_end[0] != '=') return NULL; + if (flag_end[0] != '=') return nullptr; // Returns the string after "=". return flag_end + 1; @@ -5618,7 +5774,7 @@ static bool ParseBoolFlag(const char* str, const char* flag, bool* value) { const char* const value_str = ParseFlagValue(str, flag, true); // Aborts if the parsing failed. - if (value_str == NULL) return false; + if (value_str == nullptr) return false; // Converts the string value to a bool. *value = !(*value_str == '0' || *value_str == 'f' || *value_str == 'F'); @@ -5635,7 +5791,7 @@ bool ParseInt32Flag(const char* str, const char* flag, Int32* value) { const char* const value_str = ParseFlagValue(str, flag, false); // Aborts if the parsing failed. - if (value_str == NULL) return false; + if (value_str == nullptr) return false; // Sets *value to the value of the flag. return ParseInt32(Message() << "The value of flag --" << flag, @@ -5653,7 +5809,7 @@ static bool ParseStringFlag(const char* str, const char* flag, String* value) { const char* const value_str = ParseFlagValue(str, flag, false); // Aborts if the parsing failed. - if (value_str == NULL) return false; + if (value_str == nullptr) return false; // Sets *value to the value of the flag. *value = value_str; @@ -5684,8 +5840,6 @@ static bool HasGoogleTestFlagPrefix(const char* str) { // @Y changes the color to yellow. // @D changes to the default terminal text color. // -// FIXME: Write tests for this once we add stdout -// capturing to Google Test. static void PrintColorEncoded(const char* str) { GTestColor color = COLOR_DEFAULT; // The current color. @@ -5695,7 +5849,7 @@ static void PrintColorEncoded(const char* str) { // next segment. for (;;) { const char* p = strchr(str, '@'); - if (p == NULL) { + if (p == nullptr) { ColoredPrintf(color, "%s", str); return; } @@ -5753,7 +5907,7 @@ static const char kColorEncodedHelpMessage[] = " @G--" GTEST_FLAG_PREFIX_ "output=@Y(@Gjson@Y|@Gxml@Y)[@G:@YDIRECTORY_PATH@G" GTEST_PATH_SEP_ "@Y|@G:@YFILE_PATH]@D\n" " Generate a JSON or XML report in the given directory or with the given\n" -" file name. @YFILE_PATH@D defaults to @Gtest_details.xml@D.\n" +" file name. @YFILE_PATH@D defaults to @Gtest_detail.xml@D.\n" # if GTEST_CAN_STREAM_RESULTS_ " @G--" GTEST_FLAG_PREFIX_ "stream_result_to=@YHOST@G:@YPORT@D\n" " Stream test results to the given server.\n" @@ -5895,7 +6049,7 @@ void ParseGoogleTestFlagsOnlyImpl(int* argc, CharType** argv) { void ParseGoogleTestFlagsOnly(int* argc, char** argv) { ParseGoogleTestFlagsOnlyImpl(argc, argv); - // Fix the value of *_NSGetArgc() on macOS, but iff + // Fix the value of *_NSGetArgc() on macOS, but if and only if // *_NSGetArgv() == argv // Only applicable to char** version of argv #if GTEST_OS_MAC @@ -5963,6 +6117,22 @@ void InitGoogleTest(int* argc, wchar_t** argv) { #endif // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_) } +// This overloaded version can be used on Arduino/embedded platforms where +// there is no argc/argv. +void InitGoogleTest() { + // Since Arduino doesn't have a command line, fake out the argc/argv arguments + int argc = 1; + const auto arg0 = "dummy"; + char* argv0 = const_cast<char*>(arg0); + char** argv = &argv0; + +#if defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_) + GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_(&argc, argv); +#else // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_) + internal::InitGoogleTestImpl(&argc, argv); +#endif // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_) +} + std::string TempDir() { #if defined(GTEST_CUSTOM_TEMPDIR_FUNCTION_) return GTEST_CUSTOM_TEMPDIR_FUNCTION_(); @@ -5972,7 +6142,7 @@ std::string TempDir() { return "\\temp\\"; #elif GTEST_OS_WINDOWS const char* temp_dir = internal::posix::GetEnv("TEMP"); - if (temp_dir == NULL || temp_dir[0] == '\0') + if (temp_dir == nullptr || temp_dir[0] == '\0') return "\\temp\\"; else if (temp_dir[strlen(temp_dir) - 1] == '\\') return temp_dir; diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/src/gtest_main.cc b/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/src/gtest_main.cc index 2113f621e65..f6e1dd96fb3 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/src/gtest_main.cc +++ b/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/src/gtest_main.cc @@ -27,11 +27,21 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include <stdio.h> +#include <cstdio> #include "gtest/gtest.h" +#ifdef ARDUINO +void setup() { + testing::InitGoogleTest(); +} + +void loop() { RUN_ALL_TESTS(); } + +#else + GTEST_API_ int main(int argc, char **argv) { printf("Running main() from %s\n", __FILE__); testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } +#endif diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/tests/testutil.hpp b/Build/source/texk/dvisvgm/dvisvgm-src/tests/testutil.hpp index 405b7d82396..b28542587ce 100644 --- a/Build/source/texk/dvisvgm/dvisvgm-src/tests/testutil.hpp +++ b/Build/source/texk/dvisvgm/dvisvgm-src/tests/testutil.hpp @@ -1,18 +1,5 @@ #pragma once -namespace testing { - namespace internal { - enum GTestColor { - COLOR_DEFAULT, - COLOR_RED, - COLOR_GREEN, - COLOR_YELLOW - }; - - void ColoredPrintf(GTestColor color, const char* fmt, ...); - } -} - #define WARNING(...) \ ColoredPrintf(testing::internal::COLOR_YELLOW, "[ WARNING ] "), \ ColoredPrintf(testing::internal::COLOR_YELLOW, __VA_ARGS__), \ diff --git a/Build/source/texk/dvisvgm/version.ac b/Build/source/texk/dvisvgm/version.ac index 6d7118b70e0..9a9881d8053 100644 --- a/Build/source/texk/dvisvgm/version.ac +++ b/Build/source/texk/dvisvgm/version.ac @@ -9,4 +9,4 @@ dnl dnl -------------------------------------------------------- dnl dnl m4-include this file to define the current dvisvgm version -m4_define([dvisvgm_version], [2.6.3]) +m4_define([dvisvgm_version], [2.8.1]) |