texlive[52883] Build/source/texk/dvisvgm: dvisvgm update to 2.8.1

commits+preining at tug.org commits+preining at tug.org
Fri Nov 22 03:37:37 CET 2019


Revision: 52883
          http://tug.org/svn/texlive?view=revision&revision=52883
Author:   preining
Date:     2019-11-22 03:37:37 +0100 (Fri, 22 Nov 2019)
Log Message:
-----------
dvisvgm update to 2.8.1 (from Martin Gieseking)

Modified Paths:
--------------
    trunk/Build/source/texk/dvisvgm/ChangeLog
    trunk/Build/source/texk/dvisvgm/Makefile.in
    trunk/Build/source/texk/dvisvgm/TLpatches/ChangeLog
    trunk/Build/source/texk/dvisvgm/TLpatches/patch-04-configure-upstream
    trunk/Build/source/texk/dvisvgm/TLpatches/patch-08-makefiles
    trunk/Build/source/texk/dvisvgm/configure
    trunk/Build/source/texk/dvisvgm/configure.ac
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/ChangeLog
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/Makefile.in
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/NEWS
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/README
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/configure.ac
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/doc/Makefile.am
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/doc/Makefile.in
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/doc/dvisvgm.1
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/doc/dvisvgm.txt.in
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/doc/tweak-db-refentry.xsl
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/auxiliary.h
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/bitmap.h
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/config.h
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/curve.c
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/curve.h
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/decompose.c
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/decompose.h
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/lists.h
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/potracelib.c
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/potracelib.h
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/progress.h
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/trace.c
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/trace.h
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/woff2/src/glyph.cc
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/woff2/src/normalize.cc
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/xxHash/Makefile.am
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/xxHash/Makefile.in
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/xxHash/xxhash.c
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/xxHash/xxhash.h
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/BasicDVIReader.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/BasicDVIReader.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Bezier.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Bezier.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/BgColorSpecialHandler.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Bitmap.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Bitmap.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/BoundingBox.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/BoundingBox.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/CLCommandLine.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/CLCommandLine.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/CMap.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/CMapManager.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/CMapReader.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/CMapReader.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Calculator.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/CharMapID.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Character.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Color.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Color.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/ColorSpecialHandler.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/CommandLine.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/DLLoader.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIActions.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIReader.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIToSVG.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIToSVG.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIToSVGActions.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIToSVGActions.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Directory.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Directory.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/DvisvgmSpecialHandler.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/DvisvgmSpecialHandler.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/EPSFile.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/EPSFile.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/EmSpecialHandler.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/EmSpecialHandler.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/EncFile.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/EncFile.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/FileFinder.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/FileFinder.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/FilePath.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/FilePath.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/FileSystem.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Font.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Font.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/FontCache.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/FontCache.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/FontEncoding.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/FontEncoding.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/FontEngine.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/FontEngine.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/FontManager.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/FontManager.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/FontMap.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/FontMetrics.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/FontWriter.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/FontWriter.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/GFGlyphTracer.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/GFGlyphTracer.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/GFReader.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/GFReader.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/GFTracer.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Ghostscript.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Ghostscript.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/GlyphTracerMessages.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/GraphicsPath.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/HashFunction.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/HashFunction.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/HtmlSpecialHandler.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/HyperlinkManager.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/ImageToSVG.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/ImageToSVG.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/InputBuffer.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/InputReader.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/InputReader.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/JFM.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/JFM.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Length.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Length.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/MD5HashFunction.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Makefile.am
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Makefile.in
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/MapLine.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/MapLine.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Matrix.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Matrix.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Message.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Message.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/MessageException.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/MetafontWrapper.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/MetafontWrapper.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/MiKTeXCom.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/NoPsSpecialHandler.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/PDFParser.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/PDFParser.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/PDFToSVG.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/PSInterpreter.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/PSInterpreter.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/PSPattern.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/PSPattern.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/PSPreviewFilter.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/PageRanges.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/PageSize.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/PageSize.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Pair.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/PathClipper.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/PdfSpecialHandler.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Process.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Process.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/PsSpecialHandler.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/PsSpecialHandler.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/RangeMap.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharHandler.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharHandler.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharPathHandler.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharPathHandler.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharTspanTextHandler.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharTspanTextHandler.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGOutput.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGOutput.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGSingleCharTextHandler.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGTree.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGTree.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/ShadingPatch.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/SignalHandler.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/SourceInput.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/SpecialActions.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/SpecialHandler.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/SpecialManager.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/SpecialManager.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/StreamReader.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/StreamReader.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/StreamWriter.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/StreamWriter.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Subfont.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Subfont.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/System.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/TFM.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/TensorProductPatch.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/TensorProductPatch.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/TpicSpecialHandler.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/TriangularPatch.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/TriangularPatch.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/TrueTypeFont.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/TrueTypeFont.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Unicode.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/VFReader.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/VFReader.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/VectorIterator.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/VectorStream.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLDocument.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLDocument.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLNode.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLNode.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLString.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLString.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/XXHashFunction.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/ZLibOutputStream.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/dvisvgm.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/options.xml
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/psdefs.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/utility.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/utility.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/version.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/BezierTest.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/BoundingBoxTest.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/CMapReaderTest.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/CommandLineTest.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/DVIReaderTest.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/DependencyGraphTest.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/DvisvgmSpecialTest.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/EmSpecialTest.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/FilePathTest.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/FontCacheTest.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/GFGlyphTracerTest.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/GraphicsPathTest.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/HashFunctionTest.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/Makefile.am
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/Makefile.in
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/MatrixTest.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/PSInterpreterTest.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/RangeMapTest.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/SVGOutputTest.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/StreamInputBufferTest.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/StreamReaderTest.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/StreamWriterTest.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/StringMatcherTest.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/TensorProductPatchTest.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/TpicSpecialTest.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/TriangularPatchTest.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/UtilityTest.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/XMLNodeTest.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/genhashcheck.py
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest-death-test.h
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest-message.h
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest-param-test.h
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest-printers.h
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest-spi.h
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest-test-part.h
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest-typed-test.h
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest.h
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest_pred_impl.h
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/internal/gtest-death-test-internal.h
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/internal/gtest-filepath.h
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/internal/gtest-internal.h
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/internal/gtest-param-util.h
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/internal/gtest-port-arch.h
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/internal/gtest-port.h
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/internal/gtest-string.h
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/internal/gtest-type-util.h
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/src/gtest-all.cc
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/src/gtest-death-test.cc
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/src/gtest-filepath.cc
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/src/gtest-internal-inl.h
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/src/gtest-port.cc
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/src/gtest-printers.cc
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/src/gtest-test-part.cc
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/src/gtest-typed-test.cc
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/src/gtest.cc
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/src/gtest_main.cc
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/testutil.hpp
    trunk/Build/source/texk/dvisvgm/version.ac

Added Paths:
-----------
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/doc/generate-dvisvgm-sty.xsl
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/xxHash/xxh3.h
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/EllipticalArc.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/EllipticalArc.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/AttributeExtractor.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/AttributeExtractor.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/DependencyGraph.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/GroupCollapser.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/GroupCollapser.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/Makefile.am
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/Makefile.in
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/OptimizerModule.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/RedundantElementRemover.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/RedundantElementRemover.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/SVGOptimizer.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/SVGOptimizer.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/TextSimplifier.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/TextSimplifier.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/TransformSimplifier.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/TransformSimplifier.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/WSNodeRemover.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/WSNodeRemover.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/EllipticalArcTest.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest-matchers.h

Removed Paths:
-------------
    trunk/Build/source/texk/dvisvgm/TLpatches/patch-10-psdefs
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/doc/dvisvgm.sty
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/CRC32.cpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/CRC32.hpp
    trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/DependencyGraph.hpp

Modified: trunk/Build/source/texk/dvisvgm/ChangeLog
===================================================================
--- trunk/Build/source/texk/dvisvgm/ChangeLog	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/ChangeLog	2019-11-22 02:37:37 UTC (rev 52883)
@@ -1,3 +1,7 @@
+2019-11-19  Martin Gieseking  <martin.gieseking at uos.de>
+
+	* version.ac: 2.8.1; update sources and patches.
+
 2019-05-07  Karl Berry  <karl at tug.org>
 
 	* configure.ac (HAVE_LIBGS): reinstate setting for non-TL builds.

Modified: trunk/Build/source/texk/dvisvgm/Makefile.in
===================================================================
--- trunk/Build/source/texk/dvisvgm/Makefile.in	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/Makefile.in	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 at tug.org>

Modified: trunk/Build/source/texk/dvisvgm/TLpatches/ChangeLog
===================================================================
--- trunk/Build/source/texk/dvisvgm/TLpatches/ChangeLog	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/TLpatches/ChangeLog	2019-11-22 02:37:37 UTC (rev 52883)
@@ -1,3 +1,9 @@
+2019-11-19  Martin Gieseking  <martin.gieseking at 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 at freefriends.org>
 
 	* patch-10-psdefs: from Akira.

Modified: trunk/Build/source/texk/dvisvgm/TLpatches/patch-04-configure-upstream
===================================================================
--- trunk/Build/source/texk/dvisvgm/TLpatches/patch-04-configure-upstream	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/TLpatches/patch-04-configure-upstream	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 at 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 at uos.de])
+-AC_INIT([dvisvgm],[2.8.1],[martin.gieseking at 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 at 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
+

Modified: trunk/Build/source/texk/dvisvgm/TLpatches/patch-08-makefiles
===================================================================
--- trunk/Build/source/texk/dvisvgm/TLpatches/patch-08-makefiles	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/TLpatches/patch-08-makefiles	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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,9 +38,12 @@
 +	$(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) \
@@ -31,12 +50,25 @@
 +	$(FONTFORGE_LIBS) \
 +	$(ZLIB_LIBS) \
 +	$(LIBGS_LIBS)
+ 
+-libdvisvgm_la_SOURCES = \
++dvisvgm_DEPENDENCIES = $(noinst_LIBRARIES)
++dvisvgm_DEPENDENCIES += $(KPATHSEA_DEPEND) $(ZLIB_DEPEND) $(FREETYPE2_DEPEND)
 +
- 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
-+
+ 
+ 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
-+# TL: do not try to rebuild these source files.
+ 
  # 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 @@
 + at FREETYPE2_RULE@
 +# Rebuild libz:
 + at 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  \

Deleted: trunk/Build/source/texk/dvisvgm/TLpatches/patch-10-psdefs
===================================================================
--- trunk/Build/source/texk/dvisvgm/TLpatches/patch-10-psdefs	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/TLpatches/patch-10-psdefs	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 ";

Modified: trunk/Build/source/texk/dvisvgm/configure
===================================================================
--- trunk/Build/source/texk/dvisvgm/configure	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/configure	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 at tug.org>.
 #
@@ -590,8 +590,8 @@
 # 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 at tug.org'
 PACKAGE_URL=''
 
@@ -1391,7 +1391,7 @@
   # 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 @@
 
 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 @@
 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 @@
 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_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 @@
 
 # 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 @@
 Report bugs to <bug-libtool at 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 @@
 
 
 
-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 @@
 # 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 @@
 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 @@
     "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

Modified: trunk/Build/source/texk/dvisvgm/configure.ac
===================================================================
--- trunk/Build/source/texk/dvisvgm/configure.ac	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/configure.ac	2019-11-22 02:37:37 UTC (rev 52883)
@@ -15,7 +15,7 @@
 AC_PREREQ([2.65])
 m4_include([version.ac])[] dnl define dvisvgm_version
 AC_INIT([dvisvgm (TeX Live)], dvisvgm_version, [tex-k at 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 @@
 	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

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/ChangeLog
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/ChangeLog	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/ChangeLog	2019-11-22 02:37:37 UTC (rev 52883)
@@ -1,13 +1,881 @@
+2019-11-14  Martin Gieseking  <martin.gieseking at uos.de>
+
+  * NEWS, README.md: 
+  updated NEWS and README 
+
+2019-11-12  Martin Gieseking  <martin.gieseking at 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 at uos.de>
+
+  * src/psdefs.cpp: 
+  added newline at end of file 
+
+2019-11-08  Martin Gieseking  <martin.gieseking at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at uos.de>
+
+  * src/EllipticalArc.cpp: 
+  minor changes in EllipticalArc.cpp 
+
+2019-09-19  Martin Gieseking  <martin.gieseking at uos.de>
+
+  * src/PathClipper.cpp: 
+  prevent warnings about uninitialized variables 
+
+2019-09-17  Martin Gieseking  <martin.gieseking at 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 at 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 at 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 at uos.de>
+
+  * src/XXHashFunction.hpp, tests/HashFunctionTest.cpp: 
+  simplified implementation of XXHashFunction::digestValue() and tests 
+
+2019-08-26  Martin Gieseking  <martin.gieseking at 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 at 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 at uos.de>
+
+  * src/GraphicsPath.hpp: 
+  avoid redundant sequences of closepath (z/Z) commands 
+
+2019-08-19  Martin Gieseking  <martin.gieseking at uos.de>
+
+  * src/GraphicsPath.hpp, tests/GraphicsPathTest.cpp: 
+  added short versions of 'quadto' and 'cubicto' to GraphicsPath 
+
+2019-08-18  Martin Gieseking  <martin.gieseking at uos.de>
+
+  * src/TpicSpecialHandler.cpp, tests/TpicSpecialTest.cpp: 
+  use class EllipticalArc to process arcs in tpic handler 
+
+2019-08-15  Martin Gieseking  <martin.gieseking at 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 at 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 at 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 at 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 at uos.de>
+
+  * src/Color.cpp, src/Pair.hpp: 
+  use std::hypot() to compute length of vector 
+
+2019-08-01  Martin Gieseking  <martin.gieseking at 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 at uos.de>
+
+  * src/FontCache.cpp: 
+  use direct string concatenation instead of temporary string stream 
+
+2019-07-28  Martin Gieseking  <martin.gieseking at 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 at uos.de>
+
+  * doc/Makefile.am: 
+  moved generation of dvisvgm.sty to separate rule 
+
+2019-07-26  Martin Gieseking  <martin.gieseking at 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 at uos.de>
+
+  * src/TrueTypeFont.cpp: 
+  call ofstream constructor with std::string instead of C string 
+
+2019-07-23  Martin Gieseking  <martin.gieseking at uos.de>
+
+  * src/MetafontWrapper.cpp: 
+  replaced atoi() with stoi() 
+
+2019-07-16  Martin Gieseking  <martin.gieseking at 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 at 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 at 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 at 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 at uos.de>
+
+  * .github/FUNDING.yml: 
+  added funding.yml 
+
+2019-07-06  Martin Gieseking  <martin.gieseking at uos.de>
+
+  * src/DVIToSVG.cpp: 
+  properly assign collected chars to unique fonts (fixes #110) 
+
+2019-06-18  Martin Gieseking  <martin.gieseking at uos.de>
+
+  * doc/dvisvgm.txt.in: 
+  manpage: updated \special example 
+
+2019-06-17  Martin Gieseking  <martin.gieseking at uos.de>
+
+  * src/BasicDVIReader.cpp: 
+  replaced string streams with plain strings 
+
+2019-06-11  Martin Gieseking  <martin.gieseking at uos.de>
+
+  * tests/genhashcheck.py: 
+  use range-based loop to iterate over C array 
+
+2019-06-07  Martin Gieseking  <martin.gieseking at 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 at 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 at 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 at uos.de>
+
+  * .appveyor.yml, .gitignore, src/MiKTeXCom.hpp: 
+  added files required to access the MiKTeX session object 
+
+2019-05-06  Martin Gieseking  <martin.gieseking at uos.de>
+
+  * src/psdefs.cpp: 
+  pop unused operand in PS operator 'setmatrix'  (closes #106) 
+
+2019-04-18  Martin Gieseking  <martin.gieseking at 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 at uos.de>
+
+  * README, README.md: 
+  updated URL of FontForge website 
+
+2019-04-15  Martin Gieseking  <martin.gieseking at uos.de>
+
+  * README.md: 
+  removed Coverity badge as the service seems to be dead 
+
+2019-04-14  Martin Gieseking  <martin.gieseking at uos.de>
+
+  * src/Makefile.am: 
+  add file windows.hpp to source tarball 
+
+2019-04-13  Martin Gieseking  <martin.gieseking at 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 at 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 at 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 at 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 at uos.de>
+
+  * doc/dvisvgm.txt.in: 
+  reworded some paragraphs on the manpage 
+
+2019-04-05  Martin Gieseking  <martin.gieseking at 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 at 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 at 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 at 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 at 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 at 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 at uos.de>
+
+  * src/GraphicsPath.hpp: 
+  skip redundant line drawing commands in path elements 
+
+2019-03-27  Martin Gieseking  <martin.gieseking at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at uos.de>
+
+  * src/Makefile.am: 
+  reformatted file list in Makefile 
+
+2019-03-16  Martin Gieseking  <martin.gieseking at uos.de>
+
+  * src/psdefs.cpp: 
+  added processing of PS operators xshow, yshow, and xyshow 
+
+2019-03-15  Martin Gieseking  <martin.gieseking at uos.de>
+
+  * libs/xxHash/xxhash.c, libs/xxHash/xxhash.h: 
+  updated xxhash to version 0.7.0 
+
+2019-03-14  Martin Gieseking  <martin.gieseking at 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 at 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 at 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 at 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 at 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 at uos.de>
 
   * src/dvisvgm.cpp: 
@@ -17,8 +885,23 @@
   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 at 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 at uos.de>
+
+  * src/DvisvgmSpecialHandler.cpp, src/FontWriter.cpp: 
+  replaced lookup loops with std::find_if 
+
 2019-02-25  Martin Gieseking  <martin.gieseking at uos.de>
 
   * m4/Makefile.am: 

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/Makefile.in
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/Makefile.in	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/Makefile.in	2019-11-22 02:37:37 UTC (rev 52883)
@@ -166,7 +166,8 @@
 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`; \

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/NEWS
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/NEWS	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/NEWS	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/README
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/README	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/README	2019-11-22 02:37:37 UTC (rev 52883)
@@ -14,7 +14,7 @@
    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

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/configure.ac
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/configure.ac	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/configure.ac	2019-11-22 02:37:37 UTC (rev 52883)
@@ -1,78 +1,63 @@
-# This file is part of dvisvgm
-# Copyright (C) 2005-2019 Martin Gieseking <martin.gieseking at uos.de>
-#
-# Process this file with autoconf to produce a configure script.
-
-AC_PREREQ(2.59)
-AC_INIT([dvisvgm],[2.6.3],[martin.gieseking at 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 at tug.org>
+dnl   Copyright 2009-2014 Peter Breitenlohner <tex-live at 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 at 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"
+KPSE_COND_WIN32
+KPSE_KPATHSEA_FLAGS
+KPSE_FREETYPE2_FLAGS
+KPSE_ZLIB_FLAGS
 
-# 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])
+KPSE_SAVE_FLAGS
 
-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
+# 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 @@
 	[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
+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])
 
-# Check for libraries.
-PKG_CHECK_MODULES([FREETYPE], [freetype2])
+if test "x$enable_build" != xno || test -f config.force; then
 
-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"])
+# Checks for more libraries.
+KPSE_ADD_FLAGS([zlib])
+AC_CHECK_FUNC([gzopen], [],
+              [AC_MSG_ERROR([cannot find/use zlib])])
 
-AC_ARG_WITH([ttfautohint],
-	[AS_HELP_STRING([--with-ttfautohint@<:@=prefix@:>@], [enable ttfautohint support (disabled by default)])],
-	[with_ttfautohint="$withval"],
-	[with_ttfautohint=no])
+KPSE_ADD_FLAGS([freetype2])
+AC_CHECK_FUNC([FT_Init_FreeType], [],
+              [AC_MSG_ERROR([cannot find/use libfreetype])])
 
-# 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"])
+KPSE_ADD_FLAGS([kpathsea])
+AC_CHECK_FUNC([kpse_set_program_name], [],
+              [AC_MSG_ERROR([cannot find/use libkpathsea])])
 
-# 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"])
+# 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++])
 
-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)])])
+echo timestamp >config.force
+fi
 
-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])
+KPSE_RESTORE_FLAGS
 
-AC_CHECK_LIB(z, gzopen)
-
+# emacs-page
 # Check for header files.
 AC_HEADER_DIRENT
 AC_HEADER_STDC
@@ -158,61 +162,50 @@
 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_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(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])])])
+# 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.
 
-AC_SUBST([ZLIB_CFLAGS])
-AC_SUBST([ZLIB_LIBS])
+# TL: use bundled md5 too
+AM_CONDITIONAL([USE_BUNDLED_MD5], true)
 
-# 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++])
+# 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)
 
-CPPFLAGS="$CPPFLAGS_SAVE"
-CFLAGS="$CFLAGS_SAVE"
-LDFLAGS="$LDFLAGS_SAVE"
+# 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])
 
-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"])
+# 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])
 
-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)'])
+AC_SUBST([dvisvgm_srcdir], ['$(top_srcdir)/dvisvgm-src'])
 AC_SUBST(DATE)
 AC_SUBST(AM_CPPFLAGS)
 AC_SUBST(AM_LDFLAGS)
@@ -230,6 +223,7 @@
 	m4/Makefile
 	src/Makefile
 	src/version.hpp
+	src/optimizer/Makefile
 	tests/Makefile
 	tests/data/Makefile
 	doc/Makefile])

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/doc/Makefile.am
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/doc/Makefile.am	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/doc/Makefile.am	2019-11-22 02:37:37 UTC (rev 52883)
@@ -10,7 +10,13 @@
 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
@@ -17,6 +23,7 @@
 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
 
@@ -23,7 +30,7 @@
 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,7 +51,7 @@
 	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 $<
@@ -51,15 +58,21 @@
 	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 @@
 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.

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/doc/Makefile.in
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/doc/Makefile.in	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/doc/Makefile.in	2019-11-22 02:37:37 UTC (rev 52883)
@@ -319,12 +319,20 @@
 # However, the distribution tarball should always contain a recent manpage. We ensure
 # this by adding a dist-hook rule below.
 @BUILD_MANPAGE_TRUE at 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 @@
 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,7 +599,7 @@
 	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 $<
@@ -598,15 +606,21 @@
 	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 @@
 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.

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/doc/dvisvgm.1
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/doc/dvisvgm.1	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/doc/dvisvgm.1	2019-11-22 02:37:37 UTC (rev 52883)
@@ -2,12 +2,12 @@
 .\"     Title: dvisvgm
 .\"    Author: Martin Gieseking <martin.gieseking at 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 @@
 \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 @@
 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 @@
 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 @@
 \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 @@
 \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 @@
 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,11 +356,21 @@
 \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
 is given\&.
@@ -432,7 +453,7 @@
 \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 @@
 \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,10 +675,10 @@
 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
@@ -588,7 +685,10 @@
 \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 @@
 .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 @@
 \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 @@
 \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 @@
 \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 @@
 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 @@
 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 @@
 .\}
 .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 @@
 \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 @@
 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
-.\}
-.sp
-Converts the first page of \fIfile\&.dvi\fR to \fIfile\&.svg\fR where three transformations are applied\&.
+.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
 .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\&.

Deleted: trunk/Build/source/texk/dvisvgm/dvisvgm-src/doc/dvisvgm.sty
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/doc/dvisvgm.sty	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/doc/dvisvgm.sty	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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
-}
-

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/doc/dvisvgm.txt.in
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/doc/dvisvgm.txt.in	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/doc/dvisvgm.txt.in	2019-11-22 02:37:37 UTC (rev 52883)
@@ -22,6 +22,7 @@
 :man source: dvisvgm
 :man version: @VERSION@
 :man manual: dvisvgm Manual
+:revdate: 2019-11-12 20:21 +0100
 
 Name
 ----
@@ -129,7 +130,8 @@
 //
 *-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 @@
 *--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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 
 *-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 @@
 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 @@
 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 @@
 *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 @@
   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 @@
   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,15 +738,22 @@
   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:
 +
@@ -682,11 +760,11 @@
 [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 @@
 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,33 +843,30 @@
 
 Examples
 --------
-------------
-dvisvgm file
-------------
-Converts the first page of 'file.dvi' to 'file.svg'.
++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 -p1-5 file+::
+	Converts the first five pages of 'file.dvi' to 'file-1.svg',...,'file-5.svg'.
 
----------------
-dvisvgm -z file
----------------
-Converts the first page of 'file.dvi' to 'file.svgz' with default compression level 9.
++dvisvgm -p1- file+::
+	Converts all pages of 'file.dvi' to separate SVG files.
 
--------------------------------------
-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 -p1,3 -O file+::
+	Converts the first and third page of 'file.dvi' to optimized SVG files.
 
------------------------------------------------------
-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.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
 -----------

Added: trunk/Build/source/texk/dvisvgm/dvisvgm-src/doc/generate-dvisvgm-sty.xsl
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/doc/generate-dvisvgm-sty.xsl	                        (rev 0)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/doc/generate-dvisvgm-sty.xsl	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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


Property changes on: trunk/Build/source/texk/dvisvgm/dvisvgm-src/doc/generate-dvisvgm-sty.xsl
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/doc/tweak-db-refentry.xsl
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/doc/tweak-db-refentry.xsl	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/doc/tweak-db-refentry.xsl	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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>

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/auxiliary.h
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/auxiliary.h	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/auxiliary.h	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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. */
 

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/bitmap.h
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/bitmap.h	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/bitmap.h	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 @@
     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 @@
     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);

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/config.h
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/config.h	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/config.h	2019-11-22 02:37:37 UTC (rev 52883)
@@ -1,5 +1,5 @@
 #ifndef CONFIG_H
 #define CONFIG_H
-#define VERSION "1.15"
+#define VERSION "1.16"
 #define HAVE_INTTYPES_H 1
 #endif

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/curve.c
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/curve.c	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/curve.c	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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. */
 

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/curve.h
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/curve.h	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/curve.h	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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. */
 

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/decompose.c
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/decompose.c	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/decompose.c	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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. */
 

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/decompose.h
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/decompose.h	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/decompose.h	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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. */
 

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/lists.h
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/lists.h	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/lists.h	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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. */
 

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/potracelib.c
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/potracelib.c	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/potracelib.c	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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. */
 

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/potracelib.h
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/potracelib.h	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/potracelib.h	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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. */
 

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/progress.h
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/progress.h	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/progress.h	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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. */
 

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/trace.c
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/trace.c	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/trace.c	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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. */
 

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/trace.h
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/trace.h	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/potrace/trace.h	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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. */
 

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/woff2/src/glyph.cc
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/woff2/src/glyph.cc	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/woff2/src/glyph.cc	2019-11-22 02:37:37 UTC (rev 52883)
@@ -350,7 +350,7 @@
     }
   } 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()) +

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/woff2/src/normalize.cc
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/woff2/src/normalize.cc	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/woff2/src/normalize.cc	2019-11-22 02:37:37 UTC (rev 52883)
@@ -93,7 +93,7 @@
   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);

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/xxHash/Makefile.am
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/xxHash/Makefile.am	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/xxHash/Makefile.am	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/xxHash/Makefile.in
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/xxHash/Makefile.in	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/xxHash/Makefile.in	2019-11-22 02:37:37 UTC (rev 52883)
@@ -119,7 +119,7 @@
 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 at am_libxxhash_a_OBJECTS = xxhash.$(OBJEXT)
 libxxhash_a_OBJECTS = $(am_libxxhash_a_OBJECTS)
 AM_V_P = $(am__v_P_ at AM_V@)
@@ -340,7 +340,7 @@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
 @HAVE_XXHASH_FALSE at noinst_LIBRARIES = libxxhash.a
- at HAVE_XXHASH_FALSE@libxxhash_a_SOURCES = xxhash.c xxhash.h
+ at HAVE_XXHASH_FALSE@libxxhash_a_SOURCES = xxhash.c xxhash.h xxh3.h
 @HAVE_XXHASH_FALSE at AM_CXXFLAGS = -Wall
 CLEANFILES = *.gcda *.gcno
 all: all-am
@@ -639,7 +639,7 @@
 .PRECIOUS: Makefile
 
 
- at HAVE_XXHASH_FALSE@xxhash.c: xxhash.h
+ at HAVE_XXHASH_FALSE@xxhash.c: xxhash.h xxh3.h
 
 @HAVE_XXHASH_FALSE@@CODE_COVERAGE_RULES@
 

Added: trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/xxHash/xxh3.h
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/xxHash/xxh3.h	                        (rev 0)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/xxHash/xxh3.h	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 */


Property changes on: trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/xxHash/xxh3.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/xxHash/xxhash.c
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/xxHash/xxhash.c	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/xxHash/xxhash.c	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 @@
 #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,49 +124,73 @@
 ***************************************/
 #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
 
@@ -171,9 +197,9 @@
 /* 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 @@
 #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 @@
 #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,50 +268,35 @@
 #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; }
 
 
@@ -260,22 +303,66 @@
 /* *******************************************************************
 *  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 @@
     return(h32);
 }
 
-#define XXH_get32bits(p) XXH_readLE32_align(p, endian, align)
+#define XXH_get32bits(p) XXH_readLE32_align(p, align)
 
-static U32
-XXH32_finalize(U32 h32, const void* ptr, size_t len,
-                XXH_endianess endian, XXH_alignment 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);
+    /* 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 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 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);
+           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 @@
         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 @@
     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 @@
 }
 
 
-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,50 +545,54 @@
         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);
+        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;
 
-        state->v1 = v1;
-        state->v2 = v2;
-        state->v3 = v3;
-        state->v4 = 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);
 
-    if (p < bEnd) {
-        XXH_memcpy(state->mem32, p, (size_t)(bEnd-p));
-        state->memsize = (unsigned)(bEnd-p);
+            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);
+        }
     }
 
     return XXH_OK;
@@ -511,22 +599,10 @@
 }
 
 
-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;
+    xxh_u32 h32;
 
-    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;
-
     if (state->large_len) {
         h32 = XXH_rotl32(state->v1, 1)
             + XXH_rotl32(state->v2, 7)
@@ -538,21 +614,10 @@
 
     h32 += state->total_len_32;
 
-    return XXH32_finalize(h32, state->mem32, state->memsize, endian, XXH_aligned);
+    return XXH32_finalize(h32, (const xxh_u8*)state->mem32, state->memsize, 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);
-}
-
-
 /*======   Canonical representation   ======*/
 
 /*! Default XXH result types are basic unsigned 32 and 64 bits.
@@ -582,31 +647,46 @@
 
 /*======   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 @@
  * 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 @@
 #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 @@
 }
 #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 @@
     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 @@
     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 @@
 }
 
 
-#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);
+    /* 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 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 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 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 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 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 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);
+           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 @@
         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 @@
     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 @@
     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 @@
         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);
+        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;
 
-        state->v1 = v1;
-        state->v2 = v2;
-        state->v3 = v3;
-        state->v4 = 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);
 
-    if (p < bEnd) {
-        XXH_memcpy(state->mem64, p, (size_t)(bEnd-p));
-        state->memsize = (unsigned)(bEnd-p);
+            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);
+        }
     }
 
     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,22 +1075,12 @@
         h64  = state->v3 /*seed*/ + PRIME64_5;
     }
 
-    h64 += (U64) state->total_len;
+    h64 += (xxh_u64) state->total_len;
 
-    return XXH64_finalize(h64, state->mem64, (size_t)state->total_len, endian, XXH_aligned);
+    return XXH64_finalize(h64, (const xxh_u8*)state->mem64, (size_t)state->total_len, 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;
 
-    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);
-}
-
-
 /*====== Canonical representation   ======*/
 
 XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH64_canonical_t* dst, XXH64_hash_t hash)
@@ -1026,4 +1095,16 @@
     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 */

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/xxHash/xxhash.h
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/xxHash/xxhash.h	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/xxHash/xxhash.h	2019-11-22 02:37:37 UTC (rev 52883)
@@ -49,10 +49,13 @@
 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,6 +80,7 @@
 ******************************/
 #include <stddef.h>   /* size_t */
 typedef enum { XXH_OK=0, XXH_ERROR } XXH_errorcode;
+#define XXH_STATIC_LINKING_ONLY
 
 
 /* ****************************
@@ -83,14 +87,16 @@
  *  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 @@
 #    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 @@
 *  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,7 +173,23 @@
 /*-**********************************************************************
 *  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".
@@ -166,21 +196,13 @@
     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,29 +216,55 @@
  * 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".
@@ -223,7 +271,7 @@
     "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 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 @@
 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 @@
  * 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
 
-#   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
+/* ============================================
+ * 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);
+
+
+/* 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 */
 
 

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/BasicDVIReader.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/BasicDVIReader.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/BasicDVIReader.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -19,7 +19,6 @@
 *************************************************************************/
 
 #include <algorithm>
-#include <sstream>
 #include "BasicDVIReader.hpp"
 
 using namespace std;
@@ -100,11 +99,8 @@
 		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 @@
 		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");
 	}
 }
 

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/BasicDVIReader.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/BasicDVIReader.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/BasicDVIReader.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -51,7 +51,6 @@
 
 	public:
 		explicit BasicDVIReader (std::istream &is);
-		virtual ~BasicDVIReader () =default;
 		virtual void executeAllPages ();
 		virtual double getXPos () const      {return 0;}
 		virtual double getYPos () const      {return 0;}

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Bezier.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Bezier.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Bezier.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 @@
 		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 @@
 
 
 /** 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 @@
 	}
 	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;
+}

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Bezier.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Bezier.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Bezier.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 @@
 		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;

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/BgColorSpecialHandler.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/BgColorSpecialHandler.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/BgColorSpecialHandler.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -54,7 +54,7 @@
 	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())

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Bitmap.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Bitmap.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Bitmap.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -25,11 +25,7 @@
 
 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) {
 	resize(minx, maxx, miny, maxy);
@@ -48,8 +44,7 @@
 	_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 @@
 		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 @@
 }
 
 
-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 @@
 		}
 
 	private:
-		bool _changed;
-		int _minx, _miny, _maxx, _maxy;
+		bool _changed = false;
+		int _minx = numeric_limits<int>::max(), _miny=_minx;
+		int _maxx = 0, _maxy = 0;
 };
 
 

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Bitmap.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Bitmap.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Bitmap.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -25,8 +25,7 @@
 #include <vector>
 
 
-class Bitmap
-{
+class Bitmap {
 	public:
 		struct Callback {
 			virtual ~Callback() =default;
@@ -36,7 +35,7 @@
 		};
 
 	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 @@
 //		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 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 @@
 	}
 }*/
 
-
 #endif

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/BoundingBox.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/BoundingBox.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/BoundingBox.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -74,7 +74,7 @@
 	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 @@
 }
 
 
-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());

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/BoundingBox.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/BoundingBox.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/BoundingBox.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 @@
 		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 @@
 		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)

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/CLCommandLine.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/CLCommandLine.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/CLCommandLine.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -39,7 +39,7 @@
 	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)

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/CLCommandLine.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/CLCommandLine.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/CLCommandLine.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -37,7 +37,7 @@
 		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 @@
 
 
 struct CommandLineException : public MessageException {
-	CommandLineException (const std::string &msg) : MessageException(msg) {}
+	explicit CommandLineException (const std::string &msg) : MessageException(msg) {}
 };
 
 } // namespace CL

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/CMap.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/CMap.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/CMap.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 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,26 +54,23 @@
 };
 
 
-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 "";}
@@ -83,12 +77,11 @@
 };
 
 
-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 @@
 		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;
 };

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/CMapManager.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/CMapManager.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/CMapManager.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -44,9 +44,7 @@
 
 	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 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;

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/CMapReader.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/CMapReader.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/CMapReader.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 @@
 		}
 	}
 	catch (CMapReaderException &e) {
-		_cmap.release();
+		_cmap.reset();
 		throw;
 	}
 	return std::move(_cmap);
@@ -89,9 +85,10 @@
 		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 @@
 		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 @@
 }
 
 
-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 last = first;
+			if (isRange)
+				last = parse_hexentry(ir);
+			ir.skipSpace();
 			uint32_t cid;
-			ir.skipSpace();
 			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_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 @@
 	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;
 		}
 	}

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/CMapReader.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/CMapReader.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/CMapReader.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -38,7 +38,7 @@
 			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,7 +50,6 @@
 	};
 
 	public:
-		CMapReader ();
 		std::unique_ptr<CMap> read (const std::string &fname);
 		std::unique_ptr<CMap> read (std::istream &is, const std::string &name);
 
@@ -57,8 +56,10 @@
 	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 @@
 	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

Deleted: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/CRC32.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/CRC32.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/CRC32.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 at 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();
-}

Deleted: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/CRC32.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/CRC32.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/CRC32.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -1,47 +0,0 @@
-/*************************************************************************
-** CRC32.hpp                                                            **
-**                                                                      **
-** This file is part of dvisvgm -- a fast DVI to SVG converter          **
-** Copyright (C) 2005-2019 Martin Gieseking <martin.gieseking at 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/>. **
-*************************************************************************/
-
-#ifndef CRC32_HPP
-#define CRC32_HPP
-
-#include <cstdlib>
-#include <istream>
-
-class CRC32 {
-	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);
-
-	private:
-		uint32_t _crc32;
-		uint32_t _tab[256];
-};
-
-
-#endif

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Calculator.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Calculator.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Calculator.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 {

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/CharMapID.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/CharMapID.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/CharMapID.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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;

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Character.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Character.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Character.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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;}

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Color.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Color.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Color.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -40,7 +40,7 @@
 
 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 @@
  *  @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 @@
 	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 @@
 			{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 @@
 	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);

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Color.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Color.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Color.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 @@
 		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;}

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/ColorSpecialHandler.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/ColorSpecialHandler.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/ColorSpecialHandler.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -40,10 +40,10 @@
 /** 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);
 }
 
 

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/CommandLine.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/CommandLine.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/CommandLine.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -35,7 +35,7 @@
 		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 @@
 		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 @@
 			{&gradSimplifyOpt, 1},
 #endif
 			{&linkmarkOpt, 1},
+			{&optimizeOpt, 1},
 			{&outputOpt, 1},
 			{&precisionOpt, 1},
 			{&relativeOpt, 1},
@@ -129,7 +131,7 @@
 			{&transformOpt, 2},
 			{&zoomOpt, 2},
 			{&cacheOpt, 3},
-			{&exactOpt, 3},
+			{&exactBboxOpt, 3},
 			{&keepOpt, 3},
 #if !defined(HAVE_LIBGS) && !defined(DISABLE_GS)
 			{&libgsOpt, 3},

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/DLLoader.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/DLLoader.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/DLLoader.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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;}

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIActions.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIActions.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIActions.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -40,7 +40,7 @@
 	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

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIReader.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIReader.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIReader.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -277,7 +277,7 @@
  *  @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 @@
 	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 @@
 		_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 @@
 	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);

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIToSVG.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIToSVG.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIToSVG.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 @@
 			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 @@
 		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 @@
 		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 @@
 			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 @@
 
 
 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 @@
 	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 @@
 }
 
 
-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 @@
 			_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())

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIToSVG.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIToSVG.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIToSVG.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -25,6 +25,7 @@
 #include <string>
 #include <utility>
 #include "DVIReader.hpp"
+#include "FilePath.hpp"
 #include "SVGTree.hpp"
 
 struct DVIActions;
@@ -50,7 +51,8 @@
 
 	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 @@
 		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 @@
 		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;
 

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIToSVGActions.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIToSVGActions.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIToSVGActions.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 @@
 }
 
 
-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 @@
  *  @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 @@
 
 	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 @@
 		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 @@
 	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 @@
 		_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 @@
  *  @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 @@
 	_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 @@
 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;

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIToSVGActions.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIToSVGActions.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/DVIToSVGActions.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -42,7 +42,7 @@
 	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,14 +52,9 @@
 		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;
@@ -66,7 +61,7 @@
 		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();}
@@ -73,11 +68,15 @@
 		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 @@
 		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;
 };
 
 

Deleted: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/DependencyGraph.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/DependencyGraph.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/DependencyGraph.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -1,133 +0,0 @@
-/*************************************************************************
-** DependencyGraph.hpp                                                  **
-**                                                                      **
-** This file is part of dvisvgm -- a fast DVI to SVG converter          **
-** Copyright (C) 2005-2019 Martin Gieseking <martin.gieseking at 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/>. **
-*************************************************************************/
-
-#ifndef DEPENDENCYGRAPH_HPP
-#define DEPENDENCYGRAPH_HPP
-
-#include <map>
-#include <memory>
-#include <set>
-#include <vector>
-#include "utility.hpp"
-
-template <typename T>
-class DependencyGraph {
-	struct GraphNode {
-		GraphNode (const T &k) : key(k), dependent() {}
-
-		void addDependee (GraphNode *node) {
-			if (node) {
-				node->dependent = this;
-				dependees.insert(node);
-			}
-		}
-
-		void unlinkDependees () {
-			for (GraphNode *dependee : dependees)
-				dependee->dependent = nullptr;
-			dependees.clear();
-		}
-
-		void unlinkDependee (GraphNode *dependee) {
-			auto it = dependees.find(dependee);
-			if (it != dependees.end()) {
-				(*it)->dependent = nullptr;
-				dependees.erase(it);
-			}
-		}
-
-		T key;
-		GraphNode *dependent;
-		std::set<GraphNode*> dependees;
-	};
-
-	using NodeMap = std::map<T, std::unique_ptr<GraphNode>>;
-
-	public:
-		/** Inserts a new isolated node into the dependency graph. */
-		void insert (const T &key) {
-			if (!contains(key))
-				_nodeMap.emplace(key, util::make_unique<GraphNode>(key));
-		}
-
-		/** Inserts a new node to the graph and adds a dependency on an existing one to it.
-		 *  @param[in] key ID of new node to insert
-		 *  @param[in] dependantKey ID of node the new node should depend on */
-		void insert (const T &dependentKey, const T &key) {
-			if (!contains(key)) {
-				auto dependentIter = _nodeMap.find(dependentKey);
-				if (dependentIter != _nodeMap.end()) {
-					auto node = util::make_unique<GraphNode>(key);
-					dependentIter->second->addDependee(node.get());
-					_nodeMap.emplace(key, std::move(node));
-				}
-			}
-		}
-
-		/** Removes a node and all its dependents from the graph. */
-		void removeDependencyPath (const T &key) {
-			auto it = _nodeMap.find(key);
-			if (it != _nodeMap.end()) {
-				for (GraphNode *node = it->second.get(); node;) {
-					GraphNode *dependent = node->dependent;
-					node->unlinkDependees();
-					if (dependent)
-						dependent->unlinkDependee(node);
-					_nodeMap.erase(node->key);
-					node = dependent;
-				}
-			}
-		}
-
-		/** Returns the IDs of all nodes present in the graph. */
-		std::vector<T> getKeys () const {
-			std::vector<T> keys;
-			for (auto &entry : _nodeMap)
-				keys.emplace_back(entry.first);
-			return keys;
-		}
-
-		bool contains (const T &value) const {
-			return _nodeMap.find(value) != _nodeMap.end();
-		}
-
-		bool empty () const {
-			return _nodeMap.empty();
-		}
-
-#if 0
-		void writeDOT (std::ostream &os) const {
-			os << "digraph {\n";
-			for (auto it=_nodeMap.begin(); it != _nodeMap.end(); ++it) {
-				GraphNode *node = it->second;
-				if (node->dependent)
-					os << (node->key) << " -> " << (node->dependent->key) << ";\n";
-				else if (node->dependees.empty())
-					os << (node->key) << ";\n";
-			}
-			os << "}\n";
-		}
-#endif
-
-	private:
-		NodeMap _nodeMap;
-};
-
-#endif

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Directory.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Directory.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Directory.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -25,7 +25,7 @@
 #ifdef _WIN32
 	#include "windows.hpp"
 #else
-	#include <errno.h>
+	#include <cerrno>
 	#include <sys/stat.h>
 #endif
 

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Directory.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Directory.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Directory.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -34,7 +34,7 @@
 
 	public:
 		Directory ();
-		Directory (const std::string &path);
+		explicit Directory (const std::string &path);
 		~Directory ();
 		bool open (std::string path);
 		void close ();

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/DvisvgmSpecialHandler.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/DvisvgmSpecialHandler.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/DvisvgmSpecialHandler.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 @@
 
 	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 @@
 	}};
 	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 @@
 		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 @@
 }
 
 
+/** 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::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 @@
 		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 @@
  *  @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
+	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();
-				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
+				update_bbox(w, h, d, ir.check("transform"), actions);
 			}
-			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 (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,8 +352,8 @@
 		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());
@@ -329,8 +360,8 @@
 		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::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*> 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

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/DvisvgmSpecialHandler.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/DvisvgmSpecialHandler.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/DvisvgmSpecialHandler.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 @@
 	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

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/EPSFile.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/EPSFile.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/EPSFile.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 @@
 			_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 @@
 				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;
 				}
 			}

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/EPSFile.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/EPSFile.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/EPSFile.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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;

Added: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/EllipticalArc.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/EllipticalArc.cpp	                        (rev 0)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/EllipticalArc.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 at 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 &center, 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;
+}


Property changes on: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/EllipticalArc.cpp
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/EllipticalArc.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/EllipticalArc.hpp	                        (rev 0)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/EllipticalArc.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 at 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 &center, 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
+};
+

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/EmSpecialHandler.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/EmSpecialHandler.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/EmSpecialHandler.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -24,6 +24,7 @@
 #include "InputReader.hpp"
 #include "Length.hpp"
 #include "SpecialActions.hpp"
+#include "SVGTree.hpp"
 #include "XMLNode.hpp"
 #include "XMLString.hpp"
 
@@ -30,10 +31,6 @@
 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 @@
  * @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 @@
 			 << 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 @@
 		actions.embed(q21);
 		actions.embed(q22);
 	}
-	actions.appendToPage(std::move(node));
+	actions.svgTree().appendToPage(std::move(node));
 }
 
 
@@ -126,8 +125,8 @@
 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 @@
 		{"moveto",    &EmSpecialHandler::moveto},
 		{"lineto",    &EmSpecialHandler::lineto},
 		{"linewidth", &EmSpecialHandler::linewidth},
-		{0, 0}
+		{nullptr, nullptr}
 	};
 
 	StreamInputReader ir(is);

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/EmSpecialHandler.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/EmSpecialHandler.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/EmSpecialHandler.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -38,7 +38,6 @@
 	};
 
 	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 @@
 
 	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

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/EncFile.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/EncFile.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/EncFile.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -32,7 +32,7 @@
 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 @@
 	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 @@
  * @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;
 }

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/EncFile.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/EncFile.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/EncFile.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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();}

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/FileFinder.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/FileFinder.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/FileFinder.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -69,7 +69,7 @@
 
 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 @@
 		{"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 @@
 	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 @@
 	// 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());

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/FileFinder.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/FileFinder.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/FileFinder.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -34,7 +34,7 @@
 		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 ();

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/FilePath.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/FilePath.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/FilePath.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -87,13 +87,31 @@
 }
 
 
-/** 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 &current_dir) {
+	init(path, isfile, current_dir);
+}
+
+
 /** Initializes a FilePath object. This method should be called by the constructors only.
  *  @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
@@ -152,7 +170,7 @@
 	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 @@
 		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] == '/';
+}

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/FilePath.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/FilePath.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/FilePath.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 @@
 	};
 
 	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 &current_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 &current_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,6 +58,8 @@
 		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);
@@ -59,10 +66,10 @@
 		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
 };
 

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/FileSystem.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/FileSystem.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/FileSystem.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -175,7 +175,7 @@
 		if (!ret.empty())
 			return ret.c_str();
 	}
-	return 0;
+	return nullptr;
 #else
 	const char *dir=getenv("HOME");
 	if (!dir) {

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Font.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Font.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Font.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -99,8 +99,8 @@
 
 ///////////////////////////////////////////////////////////////////////////////////////
 
-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 @@
 // 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,7 +175,7 @@
 
 
 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;
@@ -182,7 +182,7 @@
 		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 @@
  *  @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 @@
 					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 @@
  *  @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 () {
-	if (CACHE_PATH)
+	if (!CACHE_PATH.empty())
 		_cache.write(CACHE_PATH);
 	if (!KEEP_TEMP_FILES)
 		tidy();
@@ -548,7 +548,7 @@
 
 
 const FontStyle* PhysicalFontImpl::style () const {
-	if (auto *entry = fontMapEntry())
+	if (auto entry = fontMapEntry())
 		return &entry->style;
 	return nullptr;
 }
@@ -671,6 +671,6 @@
  *  @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);
 }
 

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Font.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Font.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Font.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -69,7 +69,7 @@
 		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 @@
  *  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 @@
 		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 @@
 		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 @@
 	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 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 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 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 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 @@
 
 
 struct FontException : public MessageException {
-	FontException (const std::string &msg) : MessageException(msg) {}
+	explicit FontException (const std::string &msg) : MessageException(msg) {}
 };
 
 #endif

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/FontCache.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/FontCache.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/FontCache.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 @@
  *  @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 @@
 		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 @@
 
 
 /** 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 @@
 	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 @@
 		return false;
 
 	StreamWriter sw(os);
-	CRC32 crc32;
+	XXH32HashFunction hashfunc;
 
-	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);
+	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 @@
 		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 @@
 				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 @@
 		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 @@
 					<< 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) {

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/FontCache.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/FontCache.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/FontCache.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 @@
 		static const uint8_t FORMAT_VERSION;
 		std::string _fontname;
 		std::map<int, Glyph> _glyphs;
-		bool _changed;
+		bool _changed=false;
 };
 
 #endif

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/FontEncoding.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/FontEncoding.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/FontEncoding.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -32,7 +32,7 @@
  * @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 @@
 		return _enc2->findCompatibleBaseFontMap(font, charmapID);
 	if (_enc1)
 		return _enc1->findCompatibleBaseFontMap(font, charmapID);
-	return 0;
+	return nullptr;
 }
 
 

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/FontEncoding.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/FontEncoding.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/FontEncoding.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -32,7 +32,7 @@
 	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 @@
 
 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;

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/FontEngine.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/FontEngine.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/FontEngine.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 @@
 
 /** 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 @@
 ///////////////////////////////////////////////////////////////////////////
 
 
-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 @@
 		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::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 @@
 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,7 +338,7 @@
 
 // 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;
 }
@@ -346,21 +345,21 @@
 
 
 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;
 }
@@ -367,7 +366,7 @@
 
 
 /** 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 @@
 			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 @@
 
 
 /** 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

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/FontEngine.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/FontEngine.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/FontEngine.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -73,10 +73,10 @@
 		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

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/FontManager.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/FontManager.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/FontManager.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -187,11 +187,11 @@
 			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 @@
 		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 @@
 	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 {

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/FontManager.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/FontManager.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/FontManager.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -66,7 +66,7 @@
 		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;

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/FontMap.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/FontMap.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/FontMap.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -34,7 +34,7 @@
 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;

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/FontMetrics.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/FontMetrics.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/FontMetrics.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -67,7 +67,7 @@
 
 
 struct FontMetricException : public MessageException {
-	FontMetricException (const std::string &msg) : MessageException(msg) {}
+	explicit FontMetricException (const std::string &msg) : MessageException(msg) {}
 };
 
 #endif

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/FontWriter.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/FontWriter.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/FontWriter.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -39,21 +39,19 @@
 /** 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 @@
 }
 
 
-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;
 };

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/FontWriter.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/FontWriter.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/FontWriter.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -36,9 +36,9 @@
 		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 @@
 
 
 struct FontWriterException : MessageException {
-	FontWriterException (const std::string &msg) : MessageException(msg) {}
+	explicit FontWriterException (const std::string &msg) : MessageException(msg) {}
 };
 
 #endif

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/GFGlyphTracer.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/GFGlyphTracer.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/GFGlyphTracer.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 @@
  *  @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);

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/GFGlyphTracer.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/GFGlyphTracer.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/GFGlyphTracer.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -39,7 +39,7 @@
 
 	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 @@
 
 	private:
 		std::ifstream _ifs;
-		Glyph *_glyph;
-		Callback *_callback;
+		Glyph *_glyph = nullptr;
+		Callback *_callback = nullptr;
 };
 
 #endif

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/GFReader.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/GFReader.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/GFReader.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -106,11 +106,8 @@
 		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];

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/GFReader.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/GFReader.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/GFReader.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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) {}
 

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/GFTracer.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/GFTracer.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/GFTracer.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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;

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Ghostscript.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Ghostscript.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Ghostscript.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -66,7 +66,7 @@
 					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 @@
 	: DLLoader(get_libgs(LIBGS_NAME))
 #endif
 {
-	_inst = 0;
 }
 
 
@@ -173,7 +172,6 @@
 	: DLLoader(get_libgs(LIBGS_NAME))
 #endif
 {
-	_inst = 0;
 	init(argc, argv, caller);
 }
 
@@ -191,12 +189,12 @@
 	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 @@
 #else
 	if (auto fn = LOAD_SYMBOL(gsapi_new_instance))
 		return fn(psinst, caller);
-	*psinst = 0;
+	*psinst = nullptr;
 	return 0;
 #endif
 }

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Ghostscript.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Ghostscript.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Ghostscript.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -73,10 +73,10 @@
 
 	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 @@
 		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

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/GlyphTracerMessages.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/GlyphTracerMessages.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/GlyphTracerMessages.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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';
 		}

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/GraphicsPath.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/GraphicsPath.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/GraphicsPath.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -18,19 +18,150 @@
 ** 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> &currentPoint) {
+			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> &currentPoint);
+
+	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> &currentPoint) {
+	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 {
 	friend class PathClipper;
 	public:
@@ -37,78 +168,272 @@
 		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);
+		}
 
-			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;
+		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) {}
+
+			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
+		};
 
-			Type type;
-			Point params[3];
+		///////////////////////////////////////////////////////////////////////////////
+
+		/** 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];
+				}
+
+			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 @@
 			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 @@
 
 		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 @@
 		}
 
 		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;
 		}
 
+		/** 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);
+		}
+
 		void closepath () {
-			_commands.emplace_back(Command(Command::Type::CLOSEPATH));
+			if (!_commands.empty() && !mpark::get_if<ClosePath>(&_commands.back())) {
+				_commands.emplace_back(ClosePath{});
+				_finalPoint = _startPoint;
+			}
 		}
 
-		const std::vector<Command>& commands () const {
-			return _commands;
+		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 @@
 				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 @@
 			}
 		}
 
-
 		/** 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 @@
 		 *  @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,20 +631,36 @@
 			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;
 			}
@@ -342,12 +667,12 @@
 			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;
 			}
@@ -354,93 +679,57 @@
 			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

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/HashFunction.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/HashFunction.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/HashFunction.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -31,7 +31,12 @@
 
 /** 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 @@
 		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 @@
 }
 
 
+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;

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/HashFunction.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/HashFunction.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/HashFunction.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -21,6 +21,7 @@
 #ifndef HASHFUNCTION_HPP
 #define HASHFUNCTION_HPP
 
+#include <istream>
 #include <memory>
 #include <string>
 #include <vector>
@@ -35,6 +36,7 @@
 		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);

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/HtmlSpecialHandler.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/HtmlSpecialHandler.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/HtmlSpecialHandler.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -31,7 +31,7 @@
 	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 @@
 	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 @@
 		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;
 }

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/HyperlinkManager.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/HyperlinkManager.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/HyperlinkManager.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -88,7 +88,7 @@
 	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 @@
 			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 @@
 			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::closeAnchor (SpecialActions &actions) {
 	if (_anchorType == AnchorType::HREF) {
 		markLinkedBox(actions);
-		actions.popContextElement();
+		actions.svgTree().popPageContext();
 		_depthThreshold = 0;
 	}
 	_anchorType = AnchorType::NONE;
@@ -148,7 +148,7 @@
 	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 @@
 			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,7 +192,7 @@
 		// 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());
@@ -199,7 +199,7 @@
 			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 @@
 			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 @@
 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 {

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/ImageToSVG.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/ImageToSVG.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/ImageToSVG.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 @@
 		_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 @@
 }
 
 
-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 @@
 		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 @@
 		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);
 	}

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/ImageToSVG.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/ImageToSVG.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/ImageToSVG.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -32,8 +32,7 @@
 
 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,12 +60,8 @@
 		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;
@@ -73,7 +68,7 @@
 		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:

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/InputBuffer.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/InputBuffer.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/InputBuffer.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 @@
 };
 
 
-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 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 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 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

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/InputReader.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/InputReader.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/InputReader.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -19,6 +19,7 @@
 *************************************************************************/
 
 #include <cmath>
+#include <cstring>
 #include <functional>
 #include "InputReader.hpp"
 
@@ -41,11 +42,15 @@
 }
 
 
+/** 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 @@
 	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,9 +97,10 @@
 }
 
 
-/** 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);
@@ -82,6 +107,16 @@
 }
 
 
+/** 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 ret;
 	skipSpace();
 	while (isalpha(peek()))
-		ret += get();
+		ret += char(get());
 	return ret;
 }
 
@@ -261,7 +296,7 @@
 }
 
 
-/** 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 @@
 	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 ret;
 	skipSpace();
 	while (!eof() && !isspace(peek()) && isprint(peek()))
-		ret += get();
+		ret += char(get());
 	return ret;
 }
 
@@ -305,7 +340,7 @@
 string InputReader::getString (size_t n) {
 	string ret;
 	while (n-- > 0)
-		ret += get();
+		ret += char(get());
 	return ret;
 }
 
@@ -319,7 +354,7 @@
 	string ret;
 	skipSpace();
 	while (!eof() && peek() > 0 && !strchr(delim, peek()))
-		ret += get();
+		ret += char(get());
 	return ret;
 }
 
@@ -328,7 +363,7 @@
 	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;
@@ -335,26 +370,30 @@
 }
 
 
-/** 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();
 }

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/InputReader.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/InputReader.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/InputReader.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -37,7 +37,8 @@
 		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,7 +54,7 @@
 		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();}
 };
 
@@ -60,7 +61,7 @@
 
 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 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 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:

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/JFM.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/JFM.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/JFM.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -32,11 +32,9 @@
 	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

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/JFM.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/JFM.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/JFM.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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);}

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Length.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Length.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Length.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -60,9 +60,7 @@
 		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 @@
 		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 @@
 			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 @@
 	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));
 }
 

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Length.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Length.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Length.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 @@
 
 	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);

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/MD5HashFunction.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/MD5HashFunction.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/MD5HashFunction.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -34,8 +34,8 @@
 	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);}

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Makefile.am
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Makefile.am	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Makefile.am	2019-11-22 02:37:37 UTC (rev 52883)
@@ -5,6 +5,7 @@
 
 bin_PROGRAMS     = dvisvgm
 noinst_LIBRARIES = libdvisvgm.a
+SUBDIRS = optimizer
 
 dvisvgm_SOURCES = \
 	CommandLine.hpp \
@@ -14,6 +15,7 @@
 
 dvisvgm_LDADD = \
 	$(noinst_LIBRARIES) \
+	optimizer/liboptimizer.a \
 	../libs/clipper/libclipper.a \
 	$(POTRACE_LIBS) \
 	$(XXHASH_LIBS)
@@ -43,217 +45,123 @@
 
 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,8 +181,17 @@
 
 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) \
 	$(CODE_COVERAGE_LDFLAGS)
@@ -284,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)
@@ -296,23 +211,11 @@
 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)
+# TL: do not try to rebuild these source files.
+if ! TEXLIVE_BUILD
 
-if WIN32
-AM_CXXFLAGS += -DTEXLIVEWIN32
-endif WIN32
-
-if ! TEXLIVE_BUILD
-# TL: do not try to rebuild these source files.
 # the command-line parser class is generated from options.xml by opt2cpp
 $(srcdir)/CommandLine.hpp: options.xml
 	rm -f $@

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Makefile.in
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Makefile.in	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Makefile.in	2019-11-22 02:37:37 UTC (rev 52883)
@@ -102,16 +102,17 @@
 @USE_BUNDLED_MD5_TRUE at am__append_6 = ../libs/md5/libmd5.a
 @USE_BUNDLED_MD5_FALSE at am__append_7 = $(LIBCRYPTO_LIBS)
 @ENABLE_WOFF_TRUE at am__append_8 = ffwrapper.c ffwrapper.h
- at ENABLE_WOFF_TRUE@am__append_9 = \
+ at WIN32_TRUE@am__append_9 = -DTEXLIVEWIN32
+ at 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
 
- at ENABLE_WOFF_TRUE@am__append_10 = $(TTFAUTOHINT_CFLAGS) \
- at ENABLE_WOFF_TRUE@	$(BROTLI_CFLAGS) $(WOFF2_CFLAGS)
- at ENABLE_WOFF_TRUE@@USE_BUNDLED_MD5_TRUE at am__append_11 = -I$(dvisvgm_srcdir)/libs/md5
- at ENABLE_WOFF_TRUE@@USE_BUNDLED_MD5_FALSE at am__append_12 = $(LIBCRYPTO_CFLAGS)
- at ENABLE_WOFF_TRUE@am__append_13 = $(TTFAUTOHINT_LIBS)
- at WIN32_TRUE@am__append_14 = -DTEXLIVEWIN32
+ at ENABLE_WOFF_TRUE@am__append_11 = \
+ at ENABLE_WOFF_TRUE@	$(BROTLI_CFLAGS) \
+ at ENABLE_WOFF_TRUE@	$(WOFF2_CFLAGS)
+
+ at ENABLE_WOFF_TRUE@@USE_BUNDLED_MD5_TRUE at am__append_12 = -I$(dvisvgm_srcdir)/libs/md5
+ at ENABLE_WOFF_TRUE@@USE_BUNDLED_MD5_FALSE at 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,70 +146,69 @@
 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 at am__objects_1 = ffwrapper.$(OBJEXT)
 am_libdvisvgm_a_OBJECTS = BasicDVIReader.$(OBJEXT) Bezier.$(OBJEXT) \
 	BgColorSpecialHandler.$(OBJEXT) Bitmap.$(OBJEXT) \
@@ -215,13 +215,13 @@
 	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 @@
 	./$(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_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 @@
   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_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
 noinst_LIBRARIES = libdvisvgm.a
+SUBDIRS = optimizer
 dvisvgm_SOURCES = \
 	CommandLine.hpp \
 	dvisvgm.cpp
@@ -553,87 +599,88 @@
 @HAVE_POTRACE_FALSE at POTRACE_LIBS = ../libs/potrace/libpotrace.a
 @HAVE_XXHASH_FALSE at XXHASH_CFLAGS = -I$(dvisvgm_srcdir)/libs/xxHash
 @HAVE_XXHASH_FALSE at 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 @@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/CMap.Po at am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/CMapManager.Po at am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/CMapReader.Po at am__quote@ # am--include-marker
- at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/CRC32.Po at am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/Calculator.Po at am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/CharMapID.Po at am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/Color.Po at am__quote@ # am--include-marker
@@ -758,6 +804,7 @@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/Directory.Po at am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/DvisvgmSpecialHandler.Po at am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/EPSFile.Po at am__quote@ # am--include-marker
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/EllipticalArc.Po at am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/EmSpecialHandler.Po at am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/EncFile.Po at am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/FileFinder.Po at am__quote@ # am--include-marker
@@ -894,14 +941,61 @@
 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 @@
 	      $$unique; \
 	  fi; \
 	fi
-ctags: ctags-am
+ctags: ctags-recursive
 
 CTAGS: ctags
 ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
@@ -927,7 +1021,7 @@
 	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 @@
 	    || 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 @@
 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 @@
 	-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 @@
 	-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-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 @@
 	-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 @@
 	-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 @@
 	-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
+.MAKE: $(am__recursive_targets) 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
+.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 $@

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/MapLine.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/MapLine.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/MapLine.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 @@
 					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();
 	}

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/MapLine.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/MapLine.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/MapLine.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -31,17 +31,15 @@
 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 @@
 		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 @@
 		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;
 };
 
 

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Matrix.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Matrix.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Matrix.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -70,7 +70,7 @@
  *  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 string &cmds, Calculator &calc) {
-	parse(cmds, calc);
+	*this = parse(cmds, calc);
 }
 
 
@@ -109,7 +109,7 @@
 }
 
 
-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 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::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::scale (double sx, double sy) {
 	if (sx != 1 || sy != 1) {
 		ScalingMatrix s(sx, sy);
-		rmultiply(s);
+		lmultiply(s);
 	}
 	return *this;
 }
@@ -163,7 +163,7 @@
  *  @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 @@
 	if (xyratio != 0) {
 		double v[] = {1, xyratio};
 		Matrix t(v, 2);
-		rmultiply(t);
+		lmultiply(t);
 	}
 	return *this;
 }
@@ -196,7 +196,7 @@
 	if (xyratio != 0) {
 		double v[] = {1, 0, 0, xyratio};
 		Matrix t(v, 4);
-		rmultiply(t);
+		lmultiply(t);
 	}
 	return *this;
 }
@@ -208,7 +208,7 @@
 		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 @@
 }
 
 
-/** 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 @@
 }
 
 
-/** 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 @@
 }
 
 
-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,13 +365,13 @@
 			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': {
@@ -378,9 +378,9 @@
 				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 @@
 				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 @@
 				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 @@
 				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 @@
 
 /** 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 @@
 }
 
 
+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> &params) {
+	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 @@
 	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}));
+}

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Matrix.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Matrix.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Matrix.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 @@
 	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& rmultiply (const Matrix &tm);
 		Matrix& lmultiply (const Matrix &tm);
-		Matrix& rmultiply (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 @@
 		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,10 +93,20 @@
 
 
 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);
+};
+
+
 inline std::ostream& operator << (std::ostream &os, const Matrix &m) {
 	return m.write(os);
 }

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Message.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Message.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Message.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 @@
 }
 
 
-void MessageStream::putChar (const char c, ostream &os) {
+void MessageStream::putChar (char c, ostream &os) {
 	switch (c) {
 		case '\r':
 			os << '\r';

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Message.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Message.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Message.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 @@
 		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:

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/MessageException.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/MessageException.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/MessageException.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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;

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/MetafontWrapper.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/MetafontWrapper.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/MetafontWrapper.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 @@
 		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;
 		}
 	}

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/MetafontWrapper.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/MetafontWrapper.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/MetafontWrapper.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -29,7 +29,7 @@
 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;

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/MiKTeXCom.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/MiKTeXCom.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/MiKTeXCom.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 {

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/NoPsSpecialHandler.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/NoPsSpecialHandler.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/NoPsSpecialHandler.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -27,8 +27,8 @@
 	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:

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/PDFParser.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/PDFParser.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/PDFParser.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -119,7 +119,7 @@
 		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 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 @@
 		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 @@
 		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 @@
 
 
 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;
 };

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/PDFParser.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/PDFParser.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/PDFParser.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -79,12 +79,12 @@
 };
 
 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,7 +134,7 @@
 
 
 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;
 }
@@ -141,7 +141,7 @@
 
 
 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 @@
 
 /** 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

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/PDFToSVG.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/PDFToSVG.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/PDFToSVG.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -60,4 +60,3 @@
 };
 
 #endif
-

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/PSInterpreter.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/PSInterpreter.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/PSInterpreter.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -51,8 +51,15 @@
 			"-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 @@
 
 	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 @@
  *  @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 @@
 			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 @@
 						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 @@
 		{"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}},

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/PSInterpreter.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/PSInterpreter.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/PSInterpreter.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 @@
 	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 @@
 	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);}

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/PSPattern.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/PSPattern.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/PSPattern.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -39,7 +39,7 @@
 /** 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,7 +54,7 @@
 
 
 /** 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();
 }
@@ -61,11 +61,11 @@
 
 
 /** 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 @@
 	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 @@
 
 /** 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 @@
 
 /** 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 @@
 /** 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 @@
 }
 
 
-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();

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/PSPattern.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/PSPattern.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/PSPattern.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -32,7 +32,7 @@
 
 class SpecialActions;
 class SVGTree;
-class XMLElementNode;
+class XMLElement;
 
 class PSPattern {
 	public:
@@ -42,8 +42,8 @@
 		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 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 @@
 		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

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/PSPreviewFilter.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/PSPreviewFilter.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/PSPreviewFilter.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -30,7 +30,7 @@
 
 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;}

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/PageRanges.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/PageRanges.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/PageRanges.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -78,7 +78,7 @@
 /** 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;
 }

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/PageSize.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/PageSize.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/PageSize.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -96,7 +96,7 @@
 
 	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,7 +117,7 @@
 	}
 	else if (name == "legal") {
 		_width = 216_mm;
-		_height = 356_mm;;
+		_height = 356_mm;
 	}
 	else if (name == "letter") {
 		_width = 216_mm;
@@ -124,7 +124,7 @@
 		_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

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/PageSize.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/PageSize.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/PageSize.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -25,7 +25,7 @@
 #include "MessageException.hpp"
 
 struct PageSizeException : public MessageException {
-	PageSizeException (const std::string &msg) : MessageException(msg) {}
+	explicit PageSizeException (const std::string &msg) : MessageException(msg) {}
 };
 
 class PageSize {
@@ -32,7 +32,7 @@
 	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;}

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Pair.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Pair.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Pair.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -26,10 +26,14 @@
 #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;}
@@ -36,7 +40,7 @@
 		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 @@
 	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>, +)
 

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/PathClipper.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/PathClipper.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/PathClipper.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 @@
 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 @@
 /** 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 @@
 			_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 @@
 
 /** 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 @@
 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 @@
 
 /** 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 @@
  *  @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;
 

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/PdfSpecialHandler.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/PdfSpecialHandler.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/PdfSpecialHandler.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -95,7 +95,7 @@
 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 @@
 	});
 	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 @@
 	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 @@
 	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);
 	}
 }

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Process.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Process.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Process.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 @@
 };
 
 
-Process::Process (const string &cmd, const string &paramstr)
-	: _cmd(cmd), _paramstr(paramstr)
+Process::Process (string cmd, string paramstr)
+	: _cmd(std::move(cmd)), _paramstr(std::move(paramstr))
 {
 }
 

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Process.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Process.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Process.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -25,11 +25,11 @@
 
 class Process {
 	public:
-		Process (const std::string &cmd, const std::string &paramstr);
+		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;

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/PsSpecialHandler.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/PsSpecialHandler.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/PsSpecialHandler.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 @@
 }
 
 
+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 @@
 	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 @@
 			// 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 @@
 	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 @@
 	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 @@
 	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,22 +354,14 @@
 	_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 at 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);
@@ -357,14 +368,12 @@
 		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 @@
 }
 
 
+/** 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 at 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 @@
 		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);
+		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);
 		}
-		else
-			h = d = 0;
 	}
 	return true;
 }
@@ -435,7 +503,7 @@
 					"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 @@
 			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,7 +621,7 @@
 	}
 	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
@@ -560,7 +628,7 @@
 			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 @@
 
 		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 @@
 		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 @@
 	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 @@
 
 	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 @@
 	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 @@
 	// 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 @@
 
 			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 @@
 	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 @@
 		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 @@
 		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 @@
 
 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 @@
 			// 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 @@
 
 	private:
 		SpecialActions &_actions;
-		XMLElementNode *_group;
+		XMLElement *_group;
 };
 
 
@@ -999,8 +1065,7 @@
 #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
@@ -1007,8 +1072,7 @@
 		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 @@
 	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 @@
 	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 @@
 	if (_actions) {
 		Matrix m = _actions->getMatrix();
 		RotationMatrix r(p[0]);
-		m.lmultiply(r);
+		m.rmultiply(r);
 		_actions->setMatrix(m);
 	}
 }
@@ -1167,6 +1231,18 @@
 		_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 () {

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/PsSpecialHandler.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/PsSpecialHandler.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/PsSpecialHandler.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -34,7 +34,7 @@
 
 
 class PSPattern;
-class XMLElementNode;
+class XMLElement;
 
 class PsSpecialHandler : public SpecialHandler, protected PSActions {
 	using Path = GraphicsPath<double>;
@@ -68,7 +68,7 @@
 				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 @@
 	};
 
 	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 @@
 		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 @@
 		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 @@
 		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

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/RangeMap.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/RangeMap.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/RangeMap.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 @@
 		}
 		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::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 @@
 
 /** 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::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;
 }

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharHandler.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharHandler.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharHandler.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -25,7 +25,7 @@
 using namespace std;
 
 
-void SVGCharHandler::setInitialContextNode (XMLElementNode *node) {
+void SVGCharHandler::setInitialContextNode (XMLElement *node) {
 	resetContextNode();
 	_initialContextNode = node;
 }
@@ -34,9 +34,9 @@
 /** 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 @@
 /** 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 @@
 	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 @@
 	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;
 }

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharHandler.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharHandler.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharHandler.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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,11 +47,11 @@
 
 	private:
 		T _value;
-		bool _changed;
+		bool _changed=false;
 };
 
 
-class XMLElementNode;
+class XMLElement;
 
 
 /** Base class for all character handlers. These handlers create SVG representations
@@ -58,9 +58,9 @@
  *  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,22 +74,22 @@
 
 	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;
 };
 
 
@@ -96,10 +96,10 @@
 /** 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;

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharPathHandler.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharPathHandler.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharPathHandler.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -31,7 +31,7 @@
  *  @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 @@
 
 void SVGCharPathHandler::resetContextNode () {
 	SVGCharHandler::resetContextNode();
-	_groupNode = 0;
+	_groupNode = nullptr;
 }
 
 
@@ -69,11 +69,11 @@
 	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 @@
 		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,12 +109,12 @@
 
 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));
 }
 
@@ -121,16 +121,16 @@
 
 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));
 	}
 }

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharPathHandler.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharPathHandler.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharPathHandler.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -37,10 +37,10 @@
 		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

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharTspanTextHandler.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharTspanTextHandler.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharTspanTextHandler.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -41,13 +41,13 @@
 	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);
@@ -54,7 +54,7 @@
 		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,9 +70,9 @@
 }
 
 
-void SVGCharTspanTextHandler::setInitialContextNode (XMLElementNode *node) {
+void SVGCharTspanTextHandler::setInitialContextNode (XMLElement *node) {
 	SVGCharHandler::setInitialContextNode(node);
-	_textNode = _tspanNode = 0;
+	_textNode = _tspanNode = nullptr;
 	_xchanged = _ychanged = false;
 }
 
@@ -79,7 +79,7 @@
 
 void SVGCharTspanTextHandler::resetContextNode () {
 	SVGCharHandler::resetContextNode();
-	_textNode = _tspanNode = 0;
+	_textNode = _tspanNode = nullptr;
 	_xchanged = _ychanged = false;
 	_font.changed(false);
 	_matrix.changed(false);

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharTspanTextHandler.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharTspanTextHandler.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGCharTspanTextHandler.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -25,11 +25,11 @@
 
 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;
@@ -36,8 +36,8 @@
 
 	private:
 		bool _xchanged, _ychanged;
-		XMLElementNode *_textNode;
-		XMLElementNode *_tspanNode;
+		XMLElement *_textNode;
+		XMLElement *_tspanNode;
 };
 
 #endif

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGOutput.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGOutput.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGOutput.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 @@
  *  @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,54 +63,37 @@
 
 	_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;
+	return outpath;
 }
 
 
-#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);
-}
-#endif
-
-
 /** Replaces expressions in a given string by the corresponding values and returns the result.
  *  Supported constructs:
  *  %f: basename of the current file (filename without suffix)
@@ -174,9 +157,7 @@
 							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;
 					}

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGOutput.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGOutput.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGOutput.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -31,8 +31,8 @@
 	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 @@
 
 	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 @@
 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:

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGSingleCharTextHandler.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGSingleCharTextHandler.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGSingleCharTextHandler.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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;
 };
 

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGTree.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGTree.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGTree.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 @@
 /** 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 @@
 /** 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,7 +159,7 @@
  *  @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;
@@ -166,10 +166,10 @@
 
 	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 @@
 			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 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 @@
 			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 @@
 		// 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 @@
 }
 
 
-/** 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);

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGTree.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGTree.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGTree.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -46,17 +46,18 @@
 		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 @@
 		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 @@
 
 	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

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/ShadingPatch.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/ShadingPatch.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/ShadingPatch.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -38,12 +38,12 @@
 		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 @@
 
 
 struct ShadingException : public MessageException {
-	ShadingException (const std::string &msg) : MessageException(msg) {}
+	explicit ShadingException (const std::string &msg) : MessageException(msg) {}
 };
 
 #endif

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/SignalHandler.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/SignalHandler.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/SignalHandler.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -129,7 +129,7 @@
 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

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/SourceInput.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/SourceInput.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/SourceInput.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -43,7 +43,7 @@
 
 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;

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/SpecialActions.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/SpecialActions.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/SpecialActions.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 @@
 		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 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 @@
 		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

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/SpecialHandler.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/SpecialHandler.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/SpecialHandler.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -32,7 +32,7 @@
 
 
 struct SpecialException : public MessageException {
-	SpecialException (const std::string &msg) : MessageException(msg) {}
+	explicit SpecialException (const std::string &msg) : MessageException(msg) {}
 };
 
 

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/SpecialManager.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/SpecialManager.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/SpecialManager.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -46,7 +46,7 @@
 /** 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 @@
 	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;
 }
 

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/SpecialManager.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/SpecialManager.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/SpecialManager.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -36,8 +36,9 @@
 		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 @@
 
 	protected:
 		SpecialManager () =default;
-		SpecialManager (const SpecialManager &) =delete;
 		SpecialHandler* findHandlerByPrefix (const std::string &prefix) const;
 
 	private:

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/StreamReader.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/StreamReader.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/StreamReader.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 @@
 }
 
 
-/** 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 @@
 }
 
 
-/** 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 @@
 		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 @@
 }
 
 
-/** 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;
 }

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/StreamReader.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/StreamReader.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/StreamReader.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -26,11 +26,11 @@
 #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();}
@@ -37,17 +37,17 @@
 		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 @@
 
 
 struct StreamReaderException : public MessageException {
-	StreamReaderException (const std::string &msg) : MessageException(msg) {}
+	explicit StreamReaderException (const std::string &msg) : MessageException(msg) {}
 };
 
 #endif

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/StreamWriter.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/StreamWriter.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/StreamWriter.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 @@
  *  @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 @@
 /** 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));
 }

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/StreamWriter.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/StreamWriter.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/StreamWriter.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -24,12 +24,11 @@
 #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);
@@ -36,9 +35,9 @@
 		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;

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Subfont.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Subfont.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Subfont.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -34,13 +34,13 @@
 // 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 @@
 		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 @@
 			else {
 				string id;
 				while (is && !isspace(is.peek()))
-					id += is.get();
+					id += char(is.get());
 				if (id != _id)
 					lineno += skip_mapping_data(is);
 				else {

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Subfont.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Subfont.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Subfont.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -37,6 +37,7 @@
 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 @@
 		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 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 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;}

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/System.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/System.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/System.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -36,7 +36,7 @@
 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;

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/TFM.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/TFM.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/TFM.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -33,7 +33,7 @@
 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;

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/TensorProductPatch.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/TensorProductPatch.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/TensorProductPatch.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -63,7 +63,7 @@
  *  @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 @@
  *  @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,10 +201,11 @@
 }
 
 
-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]);
@@ -211,6 +212,7 @@
 	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::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::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 @@
  *  @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::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))

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/TensorProductPatch.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/TensorProductPatch.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/TensorProductPatch.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 @@
 		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 @@
  *  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;}
 };

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/TpicSpecialHandler.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/TpicSpecialHandler.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/TpicSpecialHandler.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 @@
  *  @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 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 @@
  *  @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,7 +110,7 @@
 		}
 		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");
 			}
@@ -116,7 +117,7 @@
 			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 @@
 			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 @@
  *  @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 @@
 				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,13 +175,13 @@
 				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();
@@ -187,14 +188,6 @@
 }
 
 
-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 @@
  *  @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 @@
 				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));
 	}

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/TriangularPatch.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/TriangularPatch.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/TriangularPatch.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -31,7 +31,7 @@
 
 
 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::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 @@
  *  @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::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;
 }

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/TriangularPatch.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/TriangularPatch.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/TriangularPatch.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 @@
 		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 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;}
 };
 

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/TrueTypeFont.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/TrueTypeFont.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/TrueTypeFont.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -127,7 +127,7 @@
 
 
 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 @@
  *  @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 (const string &fname) const {
-	ofstream ofs(fname.c_str(), ios::binary);
+	ofstream ofs(fname, ios::binary);
 	return writeWOFF2(ofs);
 }
 
@@ -167,9 +167,9 @@
 
 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
+}

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/TrueTypeFont.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/TrueTypeFont.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/TrueTypeFont.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -53,7 +53,7 @@
 
 	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 @@
 
 
 struct TrueTypeFontException : public MessageException {
-	TrueTypeFontException (const std::string &msg) : MessageException(msg) {}
+	explicit TrueTypeFontException (const std::string &msg) : MessageException(msg) {}
 };
 
 #endif

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Unicode.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Unicode.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/Unicode.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -92,21 +92,21 @@
 	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
 	}

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/VFReader.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/VFReader.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/VFReader.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -28,15 +28,11 @@
 using namespace std;
 
 
-VFReader::VFReader (istream &is)
-	: StreamReader(is), _actions(0), _designSize(0) {
+VFReader::VFReader (istream &is) : StreamReader(is)
+{
 }
 
 
-VFReader::~VFReader () {
-}
-
-
 VFActions* VFReader::replaceActions (VFActions *a) {
 	VFActions *ret = _actions;
 	_actions = a;
@@ -57,7 +53,7 @@
 	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 @@
 			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 @@
 	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 @@
 	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
 	}
 }

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/VFReader.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/VFReader.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/VFReader.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -25,21 +25,16 @@
 #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 ();
@@ -46,7 +41,7 @@
 		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 @@
 		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

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/VectorIterator.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/VectorIterator.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/VectorIterator.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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++;

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/VectorStream.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/VectorStream.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/VectorStream.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 @@
 
 
 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;

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLDocument.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLDocument.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLDocument.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -22,7 +22,7 @@
 
 using namespace std;
 
-XMLDocument::XMLDocument (unique_ptr<XMLElementNode> &&root)
+XMLDocument::XMLDocument (unique_ptr<XMLElement> root)
 	: _rootElement(std::move(root))
 {
 }
@@ -34,10 +34,10 @@
 }
 
 
-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));
 	}
@@ -44,7 +44,7 @@
 }
 
 
-void XMLDocument::setRootNode (unique_ptr<XMLElementNode> &&root) {
+void XMLDocument::setRootNode (unique_ptr<XMLElement> root) {
 	_rootElement = std::move(root);
 }
 

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLDocument.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLDocument.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLDocument.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLNode.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLNode.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLNode.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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, 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,12 +167,13 @@
  *  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;
 }
 
 
@@ -101,18 +180,18 @@
 /** 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 @@
  *  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,37 +217,105 @@
  *  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;
+ *  @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));
 }
 
 
-/** 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);
+/** 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;
+}
+
+
 /** Gets all descendant elements with a given name and given attribute.
  *  @param[in] name name of elements to find
  *  @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 @@
  *  @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 @@
 }
 
 
-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 @@
 
 
 /** 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,7 +379,7 @@
 /** 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;
@@ -240,7 +386,7 @@
 }
 
 
-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 @@
 }
 
 
-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 @@
 
 //////////////////////
 
-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<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

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLNode.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLNode.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLNode.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -29,70 +29,161 @@
 #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 XMLElementNode : public XMLNode {
+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 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;
@@ -99,13 +190,13 @@
 };
 
 
-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;
@@ -112,15 +203,15 @@
 };
 
 
-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;
@@ -127,9 +218,9 @@
 };
 
 
-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

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLString.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLString.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLString.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -21,6 +21,7 @@
 #include <cmath>
 #include <cstdlib>
 #include "Unicode.hpp"
+#include "utility.hpp"
 #include "XMLString.hpp"
 
 using namespace std;
@@ -89,14 +90,8 @@
 	}
 	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);
 }

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLString.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLString.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/XMLString.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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)
 };

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/XXHashFunction.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/XXHashFunction.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/XXHashFunction.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 @@
 	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,9 +72,9 @@
 	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);}
@@ -66,14 +81,10 @@
 		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 @@
 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

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/ZLibOutputStream.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/ZLibOutputStream.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/ZLibOutputStream.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -33,7 +33,7 @@
 #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};
@@ -40,13 +40,13 @@
 
 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 @@
 			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 @@
 		 *  @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 @@
 		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 @@
 			}
 		}
 
-		~ZLibOutputFileStream () {close();}
+		~ZLibOutputFileStream () override {close();}
 
 	private:
 		std::ofstream _ofs;

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/dvisvgm.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/dvisvgm.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/dvisvgm.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 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_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 @@
 	// 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 @@
 	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 @@
 	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 @@
 	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 @@
 			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());

Added: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/AttributeExtractor.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/AttributeExtractor.cpp	                        (rev 0)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/AttributeExtractor.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 at 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 &currentAttribute : 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();
+}


Property changes on: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/AttributeExtractor.cpp
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Copied: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/AttributeExtractor.hpp (from rev 52882, trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/FontWriter.hpp)
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/AttributeExtractor.hpp	                        (rev 0)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/AttributeExtractor.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 at 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;
+};
+

Copied: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/DependencyGraph.hpp (from rev 52882, trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/DependencyGraph.hpp)
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/DependencyGraph.hpp	                        (rev 0)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/DependencyGraph.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -0,0 +1,133 @@
+/*************************************************************************
+** DependencyGraph.hpp                                                  **
+**                                                                      **
+** This file is part of dvisvgm -- a fast DVI to SVG converter          **
+** Copyright (C) 2005-2019 Martin Gieseking <martin.gieseking at 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/>. **
+*************************************************************************/
+
+#ifndef DEPENDENCYGRAPH_HPP
+#define DEPENDENCYGRAPH_HPP
+
+#include <map>
+#include <memory>
+#include <set>
+#include <vector>
+#include "../utility.hpp"
+
+template <typename T>
+class DependencyGraph {
+	struct GraphNode {
+		explicit GraphNode (const T &k) : key(k), dependent() {}
+
+		void addDependee (GraphNode *node) {
+			if (node) {
+				node->dependent = this;
+				dependees.insert(node);
+			}
+		}
+
+		void unlinkDependees () {
+			for (GraphNode *dependee : dependees)
+				dependee->dependent = nullptr;
+			dependees.clear();
+		}
+
+		void unlinkDependee (GraphNode *dependee) {
+			auto it = dependees.find(dependee);
+			if (it != dependees.end()) {
+				(*it)->dependent = nullptr;
+				dependees.erase(it);
+			}
+		}
+
+		T key;
+		GraphNode *dependent;
+		std::set<GraphNode*> dependees;
+	};
+
+	using NodeMap = std::map<T, std::unique_ptr<GraphNode>>;
+
+	public:
+		/** Inserts a new isolated node into the dependency graph. */
+		void insert (const T &key) {
+			if (!contains(key))
+				_nodeMap.emplace(key, util::make_unique<GraphNode>(key));
+		}
+
+		/** Inserts a new node to the graph and adds a dependency on an existing one to it.
+		 *  @param[in] key ID of new node to insert
+		 *  @param[in] dependantKey ID of node the new node should depend on */
+		void insert (const T &dependentKey, const T &key) {
+			if (!contains(key)) {
+				auto dependentIter = _nodeMap.find(dependentKey);
+				if (dependentIter != _nodeMap.end()) {
+					auto node = util::make_unique<GraphNode>(key);
+					dependentIter->second->addDependee(node.get());
+					_nodeMap.emplace(key, std::move(node));
+				}
+			}
+		}
+
+		/** Removes a node and all its dependents from the graph. */
+		void removeDependencyPath (const T &key) {
+			auto it = _nodeMap.find(key);
+			if (it != _nodeMap.end()) {
+				for (GraphNode *node = it->second.get(); node;) {
+					GraphNode *dependent = node->dependent;
+					node->unlinkDependees();
+					if (dependent)
+						dependent->unlinkDependee(node);
+					_nodeMap.erase(node->key);
+					node = dependent;
+				}
+			}
+		}
+
+		/** Returns the IDs of all nodes present in the graph. */
+		std::vector<T> getKeys () const {
+			std::vector<T> keys;
+			for (auto &entry : _nodeMap)
+				keys.emplace_back(entry.first);
+			return keys;
+		}
+
+		bool contains (const T &value) const {
+			return _nodeMap.find(value) != _nodeMap.end();
+		}
+
+		bool empty () const {
+			return _nodeMap.empty();
+		}
+
+#if 0
+		void writeDOT (std::ostream &os) const {
+			os << "digraph {\n";
+			for (auto it=_nodeMap.begin(); it != _nodeMap.end(); ++it) {
+				GraphNode *node = it->second;
+				if (node->dependent)
+					os << (node->key) << " -> " << (node->dependent->key) << ";\n";
+				else if (node->dependees.empty())
+					os << (node->key) << ";\n";
+			}
+			os << "}\n";
+		}
+#endif
+
+	private:
+		NodeMap _nodeMap;
+};
+
+#endif

Added: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/GroupCollapser.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/GroupCollapser.cpp	                        (rev 0)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/GroupCollapser.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 at 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);
+}


Property changes on: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/GroupCollapser.cpp
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Copied: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/GroupCollapser.hpp (from rev 52882, trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/MessageException.hpp)
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/GroupCollapser.hpp	                        (rev 0)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/GroupCollapser.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 at 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);
+};

Added: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/Makefile.am
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/Makefile.am	                        (rev 0)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/Makefile.am	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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


Property changes on: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/Makefile.am
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Copied: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/Makefile.in (from rev 52882, trunk/Build/source/texk/dvisvgm/dvisvgm-src/libs/xxHash/Makefile.in)
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/Makefile.in	                        (rev 0)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/Makefile.in	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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.
+
+ at 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_ at AM_V@)
+am__v_AR_ = $(am__v_AR_ at 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_ at AM_V@)
+am__v_P_ = $(am__v_P_ at AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_ at AM_V@)
+am__v_GEN_ = $(am__v_GEN_ at AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_ at AM_V@)
+am__v_at_ = $(am__v_at_ at AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+DEFAULT_INCLUDES = -I. at 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_ at AM_V@)
+am__v_lt_ = $(am__v_lt_ at 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_ at AM_V@)
+am__v_CXX_ = $(am__v_CXX_ at 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_ at AM_V@)
+am__v_CXXLD_ = $(am__v_CXXLD_ at 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_ at AM_V@)
+am__v_CC_ = $(am__v_CC_ at 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_ at AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_ at 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
+
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/AttributeExtractor.Po at am__quote@ # am--include-marker
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/GroupCollapser.Po at am__quote@ # am--include-marker
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/RedundantElementRemover.Po at am__quote@ # am--include-marker
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/SVGOptimizer.Po at am__quote@ # am--include-marker
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/TextSimplifier.Po at am__quote@ # am--include-marker
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/TransformSimplifier.Po at am__quote@ # am--include-marker
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/WSNodeRemover.Po at am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+	@$(MKDIR_P) $(@D)
+	@echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.cpp.o:
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+ at am__fastdepCXX_TRUE@	$(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+ at am__fastdepCXX_TRUE@	$(am__mv) $$depbase.Tpo $$depbase.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXXCOMPILE) -c -o $@ $<
+
+.cpp.obj:
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+ at am__fastdepCXX_TRUE@	$(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+ at am__fastdepCXX_TRUE@	$(am__mv) $$depbase.Tpo $$depbase.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.cpp.lo:
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+ at am__fastdepCXX_TRUE@	$(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+ at am__fastdepCXX_TRUE@	$(am__mv) $$depbase.Tpo $$depbase.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at 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:

Copied: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/OptimizerModule.hpp (from rev 52882, trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/version.hpp)
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/OptimizerModule.hpp	                        (rev 0)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/OptimizerModule.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 at 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;
+};

Added: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/RedundantElementRemover.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/RedundantElementRemover.cpp	                        (rev 0)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/RedundantElementRemover.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 at 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);
+	}
+}


Property changes on: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/RedundantElementRemover.cpp
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Copied: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/RedundantElementRemover.hpp (from rev 52882, trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/version.hpp)
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/RedundantElementRemover.hpp	                        (rev 0)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/RedundantElementRemover.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 at 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;
+};

Added: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/SVGOptimizer.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/SVGOptimizer.cpp	                        (rev 0)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/SVGOptimizer.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 at 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;
+}
+


Property changes on: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/SVGOptimizer.cpp
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Copied: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/SVGOptimizer.hpp (from rev 52882, trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/StreamWriter.hpp)
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/SVGOptimizer.hpp	                        (rev 0)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/SVGOptimizer.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 at 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;
+};
+
+
+
+

Added: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/TextSimplifier.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/TextSimplifier.cpp	                        (rev 0)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/TextSimplifier.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 at 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;
+		}
+	}
+}


Property changes on: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/TextSimplifier.cpp
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Copied: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/TextSimplifier.hpp (from rev 52882, trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/version.hpp)
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/TextSimplifier.hpp	                        (rev 0)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/TextSimplifier.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 at 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;
+};

Added: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/TransformSimplifier.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/TransformSimplifier.cpp	                        (rev 0)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/TransformSimplifier.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 at 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;
+}
+


Property changes on: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/TransformSimplifier.cpp
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Copied: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/TransformSimplifier.hpp (from rev 52882, trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/MessageException.hpp)
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/TransformSimplifier.hpp	                        (rev 0)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/TransformSimplifier.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -0,0 +1,37 @@
+/*************************************************************************
+** TransformSimplifier.hpp                                              **
+**                                                                      **
+** This file is part of dvisvgm -- a fast DVI to SVG converter          **
+** Copyright (C) 2005-2019 Martin Gieseking <martin.gieseking at 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 <string>
+#include "OptimizerModule.hpp"
+
+class Matrix;
+
+class TransformSimplifier : public OptimizerModule {
+	public:
+		void execute (XMLElement*, XMLElement *context) override {execute(context);}
+		void execute (XMLElement *context);
+		const char* info () const override;
+
+	protected:
+		bool incorporateTransform (XMLElement *elem, const Matrix &matrix);
+		std::string decompose (const Matrix &matrix);
+};

Copied: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/WSNodeRemover.cpp (from rev 52882, trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/System.cpp)
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/WSNodeRemover.cpp	                        (rev 0)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/WSNodeRemover.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 at 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();
+	}
+}

Copied: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/WSNodeRemover.hpp (from rev 52882, trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/version.hpp)
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/WSNodeRemover.hpp	                        (rev 0)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/optimizer/WSNodeRemover.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 at 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;
+};

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/options.xml
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/options.xml	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/options.xml	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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>

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/psdefs.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/psdefs.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/psdefs.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 ";
+

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/utility.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/utility.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/utility.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -20,6 +20,7 @@
 
 #include <algorithm>
 #include <cctype>
+#include <cmath>
 #include <fstream>
 #include <functional>
 #include <iterator>
@@ -27,7 +28,57 @@
 
 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
  *  @param[in] ws characters treated as whitespace
@@ -109,6 +160,20 @@
 }
 
 
+/** 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) {

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/utility.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/utility.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/utility.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -35,7 +35,15 @@
 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
 
 namespace util {
@@ -51,6 +59,7 @@
 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);
 
@@ -57,6 +66,24 @@
 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

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/version.hpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/version.hpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/src/version.hpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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
 

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/BezierTest.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/BezierTest.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/BezierTest.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -108,9 +108,7 @@
 
 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));
 }
 
 

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/BoundingBoxTest.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/BoundingBoxTest.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/BoundingBoxTest.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -191,7 +191,7 @@
 	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");

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/CMapReaderTest.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/CMapReaderTest.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/CMapReaderTest.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -73,6 +73,11 @@
 "<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 @@
 	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);

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/CommandLineTest.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/CommandLineTest.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/CommandLineTest.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -95,7 +95,7 @@
 	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"};

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/DVIReaderTest.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/DVIReaderTest.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/DVIReaderTest.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -175,7 +175,7 @@
 		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 @@
 		"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 @@
 		"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 @@
 		"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 @@
 		"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 @@
 		"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 @@
 		"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 @@
 		"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 @@
 		"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 @@
 		"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]",

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/DependencyGraphTest.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/DependencyGraphTest.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/DependencyGraphTest.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -19,7 +19,7 @@
 *************************************************************************/
 
 #include <gtest/gtest.h>
-#include "DependencyGraph.hpp"
+#include "optimizer/DependencyGraph.hpp"
 
 using namespace std;
 

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/DvisvgmSpecialTest.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/DvisvgmSpecialTest.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/DvisvgmSpecialTest.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -41,33 +41,37 @@
 	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 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 write (ostream &os) const {
-					os << "defs: " << defs.getText() << '\n'
-						<< "page: " << page.getText() << '\n'
-						<< "bbox: " << bbox.toSVGViewBox() << '\n';
+				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, 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 @@
 	const auto cmds = {
 		"rawset pat1",
 		"raw text1",
-		"raw text2",
+		"raw <elem>text2</elem>",
 		"endrawset",
 		"raw first",
 		"rawput pat1",
@@ -128,7 +240,7 @@
 	}
 	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 @@
 	const auto cmds = {
 		"rawset pat2",
 		"rawdef text1",
-		"rawdef text2",
+		"rawdef <elem>text2</elem>",
 		"endrawset",
 		"rawdef first",
 		"rawput pat2",
@@ -152,8 +264,8 @@
 		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'/>"));
 }
 
 
@@ -160,8 +272,8 @@
 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 @@
 		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 @@
 	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 @@
 	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();

Added: trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/EllipticalArcTest.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/EllipticalArcTest.cpp	                        (rev 0)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/EllipticalArcTest.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 at 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);
+	}
+}


Property changes on: trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/EllipticalArcTest.cpp
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/EmSpecialTest.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/EmSpecialTest.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/EmSpecialTest.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -24,6 +24,7 @@
 #include "SpecialActions.hpp"
 #include "XMLNode.hpp"
 #include "XMLString.hpp"
+#include "SVGTree.hpp"
 
 using namespace std;
 
@@ -32,35 +33,38 @@
 	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;}
+				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 write (ostream &os) const {
+				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;
+				BoundingBox bbox;
 				Color color;
-				XMLElementNode page;
-				BoundingBox bbox;
 		};
 
 
 		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 @@
 		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 @@
 	}
 	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 @@
 	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 @@
 	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 @@
 	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,7 +168,7 @@
 	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));
@@ -171,7 +175,7 @@
 	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 @@
 		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>"
 	);
 }
 

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/FilePathTest.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/FilePathTest.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/FilePathTest.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 @@
 	ASSERT_FALSE(fp2.empty());
 	ASSERT_EQ(fp2.absolute(), FileSystem::getcwd());
 }
-

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/FontCacheTest.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/FontCacheTest.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/FontCacheTest.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -66,11 +66,11 @@
 			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,7 +103,7 @@
 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));
 }
 
 
@@ -110,10 +110,10 @@
 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());
 }
 
 
@@ -120,20 +120,20 @@
 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 @@
 	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 @@
 	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, 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"
 	);
 }

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/GFGlyphTracerTest.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/GFGlyphTracerTest.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/GFGlyphTracerTest.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -75,13 +75,13 @@
 	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 @@
 	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)");
 }
 

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/GraphicsPathTest.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/GraphicsPathTest.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/GraphicsPathTest.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	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,7 +218,7 @@
 	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();
@@ -204,3 +225,41 @@
 	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");
+}

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/HashFunctionTest.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/HashFunctionTest.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/HashFunctionTest.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -35,10 +35,8 @@
 	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 @@
 	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 @@
 	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 @@
 }
 
 
+#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
+}

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/Makefile.am
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/Makefile.am	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/Makefile.am	2019-11-22 02:37:37 UTC (rev 52883)
@@ -16,6 +16,7 @@
 	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.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_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_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

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/Makefile.in
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/Makefile.in	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/Makefile.in	2019-11-22 02:37:37 UTC (rev 52883)
@@ -101,9 +101,9 @@
 	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 @@
 	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 @@
 @USE_BUNDLED_MD5_FALSE at 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 @@
 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 @@
 	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 @@
 	./$(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 @@
 	./$(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 @@
 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 @@
 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 @@
 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 at POTRACE_CFLAGS = -I$(dvisvgm_srcdir)/libs/potrace
 @HAVE_POTRACE_FALSE at POTRACE_LIBS = ../libs/potrace/libpotrace.a
 @HAVE_XXHASH_FALSE at XXHASH_CFLAGS = -I$(dvisvgm_srcdir)/libs/xxHash
@@ -1036,7 +1038,7 @@
 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 @@
 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 @@
 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 @@
 	@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 @@
 	@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 @@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/CMapManagerTest-CMapManagerTest.Po at am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/CMapReaderTest-CMapReaderTest.Po at am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/CMapTest-CMapTest.Po at am__quote@ # am--include-marker
- at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/CRC32Test-CRC32Test.Po at am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/CalculatorTest-CalculatorTest.Po at am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/ColorSpecialTest-ColorSpecialTest.Po at am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/ColorTest-ColorTest.Po at am__quote@ # am--include-marker
@@ -1545,6 +1546,7 @@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/DependencyGraphTest-DependencyGraphTest.Po at am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/DirectoryTest-DirectoryTest.Po at am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/DvisvgmSpecialTest-DvisvgmSpecialTest.Po at am__quote@ # am--include-marker
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/EllipticalArcTest-EllipticalArcTest.Po at am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/EmSpecialTest-EmSpecialTest.Po at am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/FileFinderTest-FileFinderTest.Po at am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/FilePathTest-FilePathTest.Po at am__quote@ # am--include-marker
@@ -1721,20 +1723,6 @@
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCXX_FALSE@	$(AM_V_CXX at 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
- at 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
- at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/CRC32Test-CRC32Test.Tpo $(DEPDIR)/CRC32Test-CRC32Test.Po
- at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='CRC32Test.cpp' object='CRC32Test-CRC32Test.o' libtool=no @AMDEPBACKSLASH@
- at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
- at am__fastdepCXX_FALSE@	$(AM_V_CXX at 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
- at 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`
- at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/CRC32Test-CRC32Test.Tpo $(DEPDIR)/CRC32Test-CRC32Test.Po
- at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='CRC32Test.cpp' object='CRC32Test-CRC32Test.obj' libtool=no @AMDEPBACKSLASH@
- at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
- at am__fastdepCXX_FALSE@	$(AM_V_CXX at 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 @@
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCXX_FALSE@	$(AM_V_CXX at 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
+ at 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
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/EllipticalArcTest-EllipticalArcTest.Tpo $(DEPDIR)/EllipticalArcTest-EllipticalArcTest.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='EllipticalArcTest.cpp' object='EllipticalArcTest-EllipticalArcTest.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at 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
+ at 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`
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/EllipticalArcTest-EllipticalArcTest.Tpo $(DEPDIR)/EllipticalArcTest-EllipticalArcTest.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='EllipticalArcTest.cpp' object='EllipticalArcTest-EllipticalArcTest.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at 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 @@
 	--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 @@
 	--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 @@
 	-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 @@
 	-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 @@
 	-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 @@
 	-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

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/MatrixTest.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/MatrixTest.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/MatrixTest.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -21,6 +21,7 @@
 #include <gtest/gtest.h>
 #include <sstream>
 #include <vector>
+#include <XMLString.hpp>
 #include "Calculator.hpp"
 #include "Matrix.hpp"
 
@@ -68,7 +69,7 @@
 	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);
@@ -75,7 +76,7 @@
 	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 @@
 	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, 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 @@
 	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)");
+}

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/PSInterpreterTest.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/PSInterpreterTest.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/PSInterpreterTest.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -61,6 +61,7 @@
 		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);}

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/RangeMapTest.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/RangeMapTest.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/RangeMapTest.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -46,6 +46,7 @@
 	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);
@@ -52,6 +53,7 @@
 
 	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 @@
 
 	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 @@
 
 	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 @@
 	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);
 }
 

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/SVGOutputTest.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/SVGOutputTest.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/SVGOutputTest.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -38,10 +38,10 @@
 
 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");
 }
 
 
@@ -48,24 +48,24 @@
 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, 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 @@
 	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 @@
 	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, 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);
 }

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/StreamInputBufferTest.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/StreamInputBufferTest.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/StreamInputBufferTest.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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, 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,19 +195,37 @@
 }
 
 
-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());
+}
+
+
 TEST(StreamInputBufferTest, invalidate) {
 	istringstream iss("aaa=1 bbb=2 ccc=3 d e");
 	StreamInputBuffer buffer(iss, 10);

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/StreamReaderTest.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/StreamReaderTest.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/StreamReaderTest.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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, 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, 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, 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 @@
 	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");
 }
 

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/StreamWriterTest.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/StreamWriterTest.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/StreamWriterTest.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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, 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,11 +71,11 @@
 }
 
 
-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');
@@ -82,7 +82,7 @@
 	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, 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");
 }

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/StringMatcherTest.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/StringMatcherTest.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/StringMatcherTest.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -30,6 +30,7 @@
 	StreamInputReader ir(iss);
 	EXPECT_FALSE(matcher.match(ir));
 	EXPECT_EQ(matcher.charsRead(), 0u);
+	EXPECT_LT(ir.peek(), 0);
 }
 
 
@@ -39,6 +40,7 @@
 	StreamInputReader ir(iss);
 	EXPECT_TRUE(matcher.match(ir));
 	EXPECT_EQ(matcher.charsRead(), 1u);
+	EXPECT_EQ(ir.peek(), 'b');
 }
 
 
@@ -48,6 +50,7 @@
 	StreamInputReader ir(iss);
 	EXPECT_FALSE(matcher.match(ir));
 	EXPECT_EQ(matcher.charsRead(), 15u);
+	EXPECT_LT(ir.peek(), 0);
 }
 
 
@@ -57,14 +60,17 @@
 	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 @@
 	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');
+}

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/TensorProductPatchTest.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/TensorProductPatchTest.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/TensorProductPatchTest.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -235,8 +235,7 @@
 
 
 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, 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, 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);

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/TpicSpecialTest.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/TpicSpecialTest.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/TpicSpecialTest.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -33,33 +33,32 @@
 	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;
 		};
 
@@ -66,7 +65,7 @@
 
 		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 @@
 	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 @@
 	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 @@
 	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 @@
 	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));

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/TriangularPatchTest.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/TriangularPatchTest.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/TriangularPatchTest.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -123,8 +123,7 @@
 	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 @@
 	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");

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/UtilityTest.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/UtilityTest.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/UtilityTest.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -119,6 +119,17 @@
 }
 
 
+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;

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/XMLNodeTest.cpp
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/XMLNodeTest.cpp	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/XMLNodeTest.cpp	2019-11-22 02:37:37 UTC (rev 52883)
@@ -28,18 +28,64 @@
 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());
 }
@@ -46,48 +92,72 @@
 
 
 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");
+	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<XMLTextNode>(",second string"));
-	EXPECT_EQ(root.children().size(), 1u);
-	lastChild = dynamic_cast<XMLTextNode*>(root.children().back().get());
+	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, 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");
+	EXPECT_EQ(firstChild->parent(), &root);
+	EXPECT_EQ(firstChild->prev(), nullptr);
+	EXPECT_EQ(firstChild->next(), nullptr);
 
-	root.prepend(util::make_unique<XMLElementNode>("separator"));
-	root.prepend(util::make_unique<XMLTextNode>("third string,"));
-	firstChild = dynamic_cast<XMLTextNode*>(root.children().front().get());
+	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, 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,88 +231,96 @@
 
 
 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++);
 	}
 }
@@ -238,11 +327,11 @@
 
 
 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, 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, 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 @@
 	str.erase(remove(str.begin(), str.end(), '\n'), str.end());
 	EXPECT_EQ(str, "<root><element/><![CDATA[text & <text>]]></root>");
 }
-

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/genhashcheck.py
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/genhashcheck.py	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/genhashcheck.py	2019-11-22 02:37:37 UTC (rev 52883)
@@ -29,6 +29,7 @@
 print("""\
 #include <xxhash.h>
 #include <cstdint>
+#include <iterator>
 #include <iomanip>
 #include <iostream>
 #include <string>
@@ -44,15 +45,14 @@
 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;

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest-death-test.h
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest-death-test.h	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest-death-test.h	2019-11-22 02:37:37 UTC (rev 52883)
@@ -161,7 +161,6 @@
 //   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_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 @@
     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 @@
 //   return 12;
 // }
 //
-// TEST(TestCase, TestDieOr12WorksInDgbAndOpt) {
+// TEST(TestSuite, TestDieOr12WorksInDgbAndOpt) {
 //   int sideeffect = 0;
 //   // Only asserts in dbg.
 //   EXPECT_DEBUG_DEATH(DieInDebugOr12(&sideeffect), "death");
@@ -277,13 +276,13 @@
 // 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
@@ -290,7 +289,7 @@
 //                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

Added: trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest-matchers.h
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest-matchers.h	                        (rev 0)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest-matchers.h	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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_


Property changes on: trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest-matchers.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest-message.h
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest-message.h	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest-message.h	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 @@
     *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,7 +144,7 @@
   // as "(null)".
   template <typename T>
   inline Message& operator <<(T* const& pointer) {  // NOLINT
-    if (pointer == NULL) {
+    if (pointer == nullptr) {
       *ss_ << "(null)";
     } else {
       *ss_ << pointer;
@@ -158,7 +151,6 @@
     }
     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 @@
   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 @@
   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.

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest-param-test.h
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest-param-test.h	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest-param-test.h	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 @@
   ...
 }
 
-// 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 @@
 // 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 @@
 // 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 @@
 //    * 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,15 +174,12 @@
 
 #endif  // 0
 
-#include "gtest/internal/gtest-port.h"
+#include <iterator>
+#include <utility>
 
-#if !GTEST_OS_SYMBIAN
-# include <utility>
-#endif
-
 #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 {
 
@@ -193,11 +186,11 @@
 // 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 @@
 // }
 // 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 @@
 //
 // 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 @@
 //   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 @@
 //   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,871 +318,24 @@
 // 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... T>
+internal::ValueArray<T...> Values(T... v) {
+  return internal::ValueArray<T...>(std::move(v)...);
 }
 
-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);
-}
-
 // Bool() allows generating tests with parameters in a set of (false, true).
 //
 // Synopsis:
@@ -1201,7 +346,7 @@
 // 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 @@
 //     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,37 +368,35 @@
 //   - 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();
 //   }
 // };
 //
@@ -1261,147 +403,48 @@
 // 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()));
+// INSTANTIATE_TEST_SUITE_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... Generator>
+internal::CartesianProductHolder<Generator...> Combine(const Generator&... g) {
+  return internal::CartesianProductHolder<Generator...>(g...);
 }
 
-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);
-}
+#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()
 
-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.
+// 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,25 +453,51 @@
 // 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, \
-                      &gtest_##prefix##test_case_name##_EvalGenerator_, \
-                      &gtest_##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, &gtest_##prefix##test_suite_name##_EvalGenerator_, \
+                  &gtest_##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
 
 #endif  // GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest-printers.h
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest-printers.h	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest-printers.h	2019-11-22 02:37:37 UTC (rev 52883)
@@ -100,18 +100,17 @@
 #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-internal.h"
 #include "gtest/internal/gtest-port.h"
-#include "gtest/internal/gtest-internal.h"
 
-#if GTEST_HAS_STD_TUPLE_
-# include <tuple>
-#endif
-
 #if GTEST_HAS_ABSL
 #include "absl/strings/string_view.h"
 #include "absl/types/optional.h"
@@ -152,9 +151,10 @@
  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 @@
     ::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_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 @@
 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 @@
 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 @@
                   (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 @@
   }
 }
 
-// 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 @@
 }
 #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_
+template <typename T>
+void PrintTo(std::reference_wrapper<T> ref, ::std::ostream* os) {
+  UniversalPrinter<T&>::Print(ref.get(), os);
+}
+
 // 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_
+void PrintTupleTo(const T&, std::integral_constant<size_t, 0>,
+                  ::std::ostream*) {}
 
-#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 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);
 }
 
-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);
-}
-
-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);
-}
-#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 @@
     // 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 @@
 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 @@
 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 @@
 
 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 @@
 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
 

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest-spi.h
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest-spi.h	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest-spi.h	2019-11-22 02:37:37 UTC (rev 52883)
@@ -72,7 +72,7 @@
                                    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.
@@ -79,7 +79,8 @@
   //
   // This method is from the TestPartResultReporterInterface
   // interface.
-  virtual void ReportTestPartResult(const TestPartResult& result);
+  void ReportTestPartResult(const TestPartResult& result) override;
+
  private:
   void Init();
 

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest-test-part.h
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest-test-part.h	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest-test-part.h	2019-11-22 02:37:37 UTC (rev 52883)
@@ -53,22 +53,20 @@
   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 @@
   // 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 @@
   // Gets the message associated with the test part.
   const char* message() const { return message_.c_str(); }
 
-  // Returns true iff the test part passed.
+  // Returns true if and only if the test part was skipped.
+  bool skipped() const { return type_ == kSkip; }
+
+  // Returns true if and only if the test part passed.
   bool passed() const { return type_ == kSuccess; }
 
-  // Returns true iff the test part failed.
-  bool failed() 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 @@
     : 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_;

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest-typed-test.h
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest-typed-test.h	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest-typed-test.h	2019-11-22 02:37:37 UTC (rev 52883)
@@ -52,22 +52,22 @@
   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, 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 @@
 //       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 @@
   ...
 };
 
-// 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 @@
 
 // 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 @@
 //
 // 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 @@
 // 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
+#define GTEST_NAME_GENERATOR_(TestSuiteName) \
+  gtest_type_params_##TestSuiteName##_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 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 @@
   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,74 +237,94 @@
 // 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_SUITE_P(SuiteName)              \
+  static ::testing::internal::TypedTestSuitePState \
+      GTEST_TYPED_TEST_SUITE_P_STATE_(SuiteName)
 
-# 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()
+// 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 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__)
+#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()
 
-// 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__), \
-                   &GTEST_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 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__),   \
+                   &GTEST_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
 
 #endif  // GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest.h
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest.h	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest.h	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 @@
 // 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 @@
   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 @@
     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 @@
   // 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 @@
  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 @@
   // 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 @@
 
 // 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 @@
  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 @@
   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 @@
   // 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 @@
   // 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 @@
   // 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 iff the test failed.
+  // Returns true if and only if the test was skipped.
+  bool Skipped() const;
+
+  // 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 @@
 
  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 @@
     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 @@
                       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 @@
   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 @@
 
 // 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,9 +698,14 @@
   // 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 @@
   // 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 @@
   // 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 @@
   // 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 @@
   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 @@
   }
 
   // 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,80 +824,86 @@
   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:
@@ -893,10 +910,10 @@
   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 @@
   // 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 @@
     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 @@
   // 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 @@
   // 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,9 +1092,14 @@
   // 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,9 +1111,14 @@
   // 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 @@
 // 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 @@
   }
 
  private:
-  friend class TestCase;
+  friend class TestSuite;
   friend class TestInfo;
   friend class internal::DefaultGlobalTestPartResultReporter;
   friend class internal::NoExecDeathTest;
@@ -1193,7 +1244,7 @@
   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,11 +1273,15 @@
   // 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.
   const TestInfo* current_test_info() const
@@ -1235,29 +1290,40 @@
   // 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 @@
   // 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 @@
       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 @@
 // 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 @@
                    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 @@
                                        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 @@
                                  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 @@
   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 @@
 //   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 @@
 //   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 @@
   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 @@
 };
 
 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 @@
 
 // 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 @@
 // 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 @@
 //   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 @@
   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 @@
     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 @@
   ::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 @@
 //
 // 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,21 +2328,21 @@
 // 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:
@@ -2298,7 +2349,7 @@
 //
 //   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 @@
 //     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 @@
 #  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

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest_pred_impl.h
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest_pred_impl.h	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/gtest_pred_impl.h	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 @@
 // We also define the EXPECT_* variations.
 //
 // For now we only support predicates whose arity is at most 5.
+// Please email googletestframework at 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 @@
                                   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 @@
                                   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 @@
                                   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 @@
                                   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 @@
                                   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.

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/internal/gtest-death-test-internal.h
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/internal/gtest-death-test-internal.h	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/internal/gtest-death-test-internal.h	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 @@
   // 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,15 +146,16 @@
 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
@@ -159,6 +162,28 @@
 // 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 @@
 
 // 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, &gtest_regex, \
-        __FILE__, __LINE__, &gtest_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__, &gtest_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 @@
 // 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

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/internal/gtest-filepath.h
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/internal/gtest-filepath.h	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/internal/gtest-filepath.h	2019-11-22 02:37:37 UTC (rev 52883)
@@ -110,7 +110,7 @@
                                          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

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/internal/gtest-internal.h
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/internal/gtest-internal.h	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/internal/gtest-internal.h	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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 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,35 +106,23 @@
 // 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
+// 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)
+};
 
-// 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_
-
 // Appends the user-supplied message to the Google-Test-generated message.
 GTEST_API_ std::string AppendUserMessage(
     const std::string& gtest_msg, const Message& user_msg);
@@ -201,7 +189,7 @@
 //   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,7 +318,7 @@
   // 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.
@@ -337,8 +325,8 @@
     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<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 @@
 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 @@
 
 #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 @@
   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 @@
 //                     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_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,6 +617,11 @@
   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';
@@ -587,8 +628,8 @@
 // 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 @@
 // 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 @@
 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 @@
     // 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 @@
   }
 };
 
-// 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 @@
         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 @@
   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))
+  typename std::remove_const<typename std::remove_reference<T>::type>::type
 
-// 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;
-
 // 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 @@
 // 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 @@
 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,30 +912,18 @@
   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
@@ -1010,17 +930,12 @@
 // 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 @@
 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 @@
   }
 
  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 @@
   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 @@
 #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 @@
            "  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_

Modified: trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/internal/gtest-param-util.h
===================================================================
--- trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/internal/gtest-param-util.h	2019-11-22 00:54:06 UTC (rev 52882)
+++ trunk/Build/source/texk/dvisvgm/dvisvgm-src/tests/gtest/include/gtest/internal/gtest-param-util.h	2019-11-22 02:37:37 UTC (rev 52883)
@@ -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"

@@ Diff output truncated at 1234567 characters. @@


More information about the tex-live-commits mailing list